sync:dropin never mirrors documentation into a served folder; protects nothing by default
This commit is contained in:
parent
f1575839af
commit
7b36255dc2
2 changed files with 19 additions and 9 deletions
|
|
@ -153,7 +153,7 @@ each bundle registers a **distinct** tag.
|
|||
| `bun run dev` | Vite dev server + HMR (default `http://localhost:5173`, or the next free port — read the terminal). `/` is the **auto-generated SPA** (playground) of every element, built from `internal/playground/{discover,render,dev-plugin}.mjs`; every bundle is also served at its own html path. Dev-only routes: `/__playground/registry.json` (the registry), `/assets/*` (served from `public/assets/`, else `app-profiles/*/data/`). **Writes nothing to `public/`** — no HMR across that boundary. |
|
||||
| `bun run smoke:playground` | Opens every element of the auto-generated SPA by deep link in Firefox and proves it boots: element defined, shadow DOM populated, no error card, a WebGL canvas for map profiles (checked through nested shadow roots), no HTML-for-JSON data responses. `--json <file>` writes the evidence; exit 1 on any failure. The pre-handoff gate. |
|
||||
| `bun run smoke:share` | The share round-trip gate (Firefox): opens a host page (`--playground` = every canvas element of the dev SPA; `--url <page> --tag <element>` = the website or any CDN page), clicks Share, reads the URL, fetches it, reopens it in a fresh page and asserts the SAME custom element mounts with a WebGL canvas. `--json <file>`; exit 1 on any failure — proves REQ-1 ("links work wherever the tree is hosted"). |
|
||||
| `bun run sync:dropin <dest>` | Mirrors the built web-root `public/` into a host checkout (e.g. the website's `public/js/doxa-maps-build/`): adds, updates and deletes to match; **never copies credentials** (`api/maps/token.json`, `token.local.js`); protects host-owned files (`README.md`); `--dry-run` first. The only sanctioned way a map changes on the site: change the bundler → `bun run build` → sync → commit in the host. |
|
||||
| `bun run sync:dropin <dest>` | Mirrors the built web-root `public/` into a host checkout (e.g. the website's `public/js/doxa-maps-build/`): adds, updates and deletes to match; **never copies credentials** (`api/maps/token.json`, `token.local.js`) **nor documentation** (`*.md`, `*.txt` — the README and docs stay private with the bundler; a stray doc in the destination is removed); `--protect a,b` keeps host-owned files; `--dry-run` first. The only sanctioned way a map changes on the site: change the bundler → `bun run build` → sync → commit in the host. |
|
||||
| `bun run build` | `clean` → one `vite build` per `app-profiles/*/` folder → `tree` → `check:drop` → `check:parse`. |
|
||||
| `bun run build:bundle` | Builds ONE bundle (needs `BUNDLE=<name>`). |
|
||||
| `bun run build:watch` | Rebuilds into `public/` on every change (integration loop). |
|
||||
|
|
|
|||
|
|
@ -11,11 +11,14 @@
|
|||
* files that no longer exist in the source. EXCEPT:
|
||||
* · credentials are NEVER copied — api/maps/token.json and token.local.js (the site serves
|
||||
* its own /api/maps/token; the leaf pages' token ladder falls through to it);
|
||||
* · host-owned files are PROTECTED (default: README.md at the drop-in root) — never
|
||||
* overwritten, never deleted.
|
||||
* · documentation is NEVER copied — *.md / *.markdown / *.txt: the served folder is product,
|
||||
* the README and docs stay private with the bundler (a stray doc already in <dest> is
|
||||
* removed like any other stale file);
|
||||
* · host-owned files can be PROTECTED with --protect (none by default) — never overwritten,
|
||||
* never deleted.
|
||||
* Refuses to CREATE <dest>: the drop-in folder is the host's decision, not this script's.
|
||||
*
|
||||
* Usage: node internal/sync-dropin.mjs <dest> [--from public] [--protect README.md,other]
|
||||
* Usage: node internal/sync-dropin.mjs <dest> [--from public] [--protect a.txt,other]
|
||||
* [--dry-run]
|
||||
* e.g. node internal/sync-dropin.mjs /home/qwerty/Workspace/doxa-life/public/js/doxa-maps-build
|
||||
* Exit: 0 synced (or dry-run printed) · 1 bad arguments / dest missing
|
||||
|
|
@ -32,9 +35,12 @@ const argOf = (k, d) => { const i = args.indexOf(k); return i >= 0 ? args[i + 1]
|
|||
const DEST = args.find(a => !a.startsWith('--') && a !== argOf('--from') && a !== argOf('--protect'))
|
||||
const FROM = resolve(ROOT, argOf('--from', 'public'))
|
||||
const DRY = args.includes('--dry-run')
|
||||
const PROTECT = new Set(String(argOf('--protect', 'README.md')).split(',').map(s => s.trim()).filter(Boolean))
|
||||
const PROTECT = new Set(String(argOf('--protect', '')).split(',').map(s => s.trim()).filter(Boolean))
|
||||
// Never ship a credential into a host repo — these are gitignored here for the same reason.
|
||||
const EXCLUDE = new Set(['api/maps/token.json', 'token.local.js'])
|
||||
// Never ship documentation into a served folder: the README/story stays private with the bundler.
|
||||
const isDoc = (f) => /\.(md|markdown|txt)$/i.test(f)
|
||||
const excluded = (f) => EXCLUDE.has(f) || isDoc(f)
|
||||
|
||||
if (!DEST) { console.error('[sync-dropin] usage: node internal/sync-dropin.mjs <dest> [--from public] [--protect a,b] [--dry-run]'); process.exit(1) }
|
||||
const dest = resolve(DEST)
|
||||
|
|
@ -51,9 +57,11 @@ function walk(dir, base = dir, out = []) {
|
|||
}
|
||||
const sha = p => createHash('sha1').update(readFileSync(p)).digest('hex')
|
||||
|
||||
const src = walk(FROM).filter(f => !EXCLUDE.has(f))
|
||||
const allSrc = walk(FROM)
|
||||
const src = allSrc.filter(f => !excluded(f))
|
||||
const have = new Set(walk(dest))
|
||||
let copied = 0, unchanged = 0, deleted = 0, protectedSkips = 0, excluded = walk(FROM).length - src.length
|
||||
let copied = 0, unchanged = 0, deleted = 0, protectedSkips = 0
|
||||
const excludedCount = allSrc.length - src.length
|
||||
for (const f of src) {
|
||||
if (PROTECT.has(f)) { protectedSkips++; continue }
|
||||
const s = join(FROM, f), d = join(dest, f)
|
||||
|
|
@ -63,7 +71,9 @@ for (const f of src) {
|
|||
}
|
||||
const srcSet = new Set(src)
|
||||
for (const f of have) {
|
||||
if (srcSet.has(f) || PROTECT.has(f) || EXCLUDE.has(f)) continue
|
||||
// stale = not in the source, not protected. Credentials and docs found in <dest> are stale too:
|
||||
// they must not sit in a served folder (a stray README, a token file).
|
||||
if (srcSet.has(f) || PROTECT.has(f)) continue
|
||||
if (!DRY) rmSync(join(dest, f))
|
||||
deleted++
|
||||
}
|
||||
|
|
@ -73,4 +83,4 @@ if (!DRY) {
|
|||
for (const d of dirs) if (readdirSync(d).length === 0) rmSync(d, { recursive: true })
|
||||
}
|
||||
console.log(`[sync-dropin] ${DRY ? 'DRY RUN — ' : ''}${norm(relative(ROOT, FROM))}/ → ${dest}`)
|
||||
console.log(`[sync-dropin] copied ${copied} · unchanged ${unchanged} · deleted ${deleted} · protected ${protectedSkips} (${[...PROTECT].join(', ')}) · credentials excluded ${excluded}`)
|
||||
console.log(`[sync-dropin] copied ${copied} · unchanged ${unchanged} · deleted ${deleted} · protected ${protectedSkips}${PROTECT.size ? ` (${[...PROTECT].join(', ')})` : ''} · credentials/docs excluded ${excludedCount}`)
|
||||
|
|
|
|||
Loading…
Reference in a new issue