@marver-design/marver 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +83 -5
- package/README.md +17 -4
- package/dist/auth-DdUKeVKt.mjs +1150 -0
- package/dist/{build-Cr_ZLMdq.mjs → build-DmfxJc6L.mjs} +188 -33
- package/dist/cli.mjs +16 -7
- package/dist/collab-BmaOjwP1.mjs +781 -0
- package/dist/{comments-CRqaO2MH.mjs → comments-pNxjTrGN.mjs} +3 -2
- package/dist/{daemon-DSmaS453.mjs → daemon-WjonKlPz.mjs} +3 -3
- package/dist/{dev-CLBjRs0J.mjs → dev-BXq7yE1p.mjs} +5 -5
- package/dist/events-C9k-ceOj.mjs +101 -0
- package/dist/{init-BSclDg4I.mjs → init-BpitOqRQ.mjs} +2 -3
- package/dist/{config-t9coJ-Pq.mjs → manifest-CS6krOTe.mjs} +236 -4
- package/dist/{marver-id-B8-3WiHk.mjs → marver-id-CVCoaMGI.mjs} +106 -1
- package/dist/{marver-id-gate-BDzW6ahN.mjs → marver-id-gate-DOjnZakC.mjs} +94 -6
- package/dist/{plugin-vE7sxEeT.mjs → plugin-Boy7I_JH.mjs} +82 -9
- package/dist/{profile-DcsJyppw.mjs → profile-ChpTPd-X.mjs} +1 -1
- package/dist/secure-cookie-_K1Hsx8H.mjs +26 -0
- package/dist/{serve-CZ1KEQxd.mjs → serve-BeLLizNg.mjs} +72 -18
- package/dist/share-C64b1tdN.mjs +159 -0
- package/dist/summary-Bf9tiGrE.mjs +211 -0
- package/dist/{sync-DELGomPk.mjs → sync-WYxDN9IT.mjs} +3 -102
- package/package.json +1 -1
- package/src/client/shell/App.tsx +43 -8
- package/src/client/shell/Comments.tsx +9 -5
- package/src/client/shell/LockedApp.tsx +113 -0
- package/src/client/shell/Play.tsx +97 -18
- package/src/client/shell/Toolbar.tsx +26 -2
- package/src/client/shell/canvas/Canvas.tsx +5 -15
- package/src/client/shell/canvas/ctl.ts +26 -0
- package/src/client/shell/comments-store.ts +39 -9
- package/src/client/shell/hash.ts +19 -0
- package/src/client/shell/icons.tsx +1 -0
- package/src/client/shell/store.ts +54 -3
- package/src/client/shell/styles.css +27 -0
- package/src/shared/events.ts +8 -3
- package/templates/instructions/publish.md +15 -1
- package/dist/auth-B5yuwnOq.mjs +0 -494
- package/dist/collab-C-n-uQdm.mjs +0 -364
- package/dist/manifest-C2tzkNaC.mjs +0 -233
- package/dist/update-DuWDj5nR.mjs +0 -77
- package/dist/utm-CxC3QN5X.mjs +0 -20
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { i as ROUTE, n as NAME } from "./cli.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { r as
|
|
4
|
-
import {
|
|
5
|
-
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { l as detectHost, r as scanFrames, s as loadConfig } from "./manifest-CS6krOTe.mjs";
|
|
3
|
+
import { n as tailwind3Css, r as tailwind4Plugin, t as marverPlugin } from "./plugin-Boy7I_JH.mjs";
|
|
4
|
+
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmSync, writeFileSync } from "node:fs";
|
|
6
5
|
import { basename, dirname, join, sep } from "node:path";
|
|
7
6
|
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
8
8
|
import { build } from "vite";
|
|
9
9
|
import react from "@vitejs/plugin-react";
|
|
10
10
|
//#region src/server/build.ts
|
|
@@ -44,19 +44,47 @@ function scanAssetRefs(src, moduleId) {
|
|
|
44
44
|
}
|
|
45
45
|
/** Same shape the client's assetUrl accepts: relative, inside design/assets/, no tricks. */
|
|
46
46
|
const isLocalAssetRef = (p) => !!p && !p.includes(":") && !p.startsWith("/") && !p.startsWith("\\") && !p.split("/").some((s) => s === ".." || s === "");
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
const ARTIFACT_TYPES = [
|
|
48
|
+
"doc",
|
|
49
|
+
"slides",
|
|
50
|
+
"design",
|
|
51
|
+
"sketch",
|
|
52
|
+
"refs",
|
|
53
|
+
"mix"
|
|
54
|
+
];
|
|
55
|
+
const VIEW_MODES = [
|
|
56
|
+
"canvas",
|
|
57
|
+
"board",
|
|
58
|
+
"present",
|
|
59
|
+
"focus",
|
|
60
|
+
"slides"
|
|
61
|
+
];
|
|
62
|
+
/** Publishing is default-CLOSED - no policy and no explicit flag = no build.
|
|
63
|
+
* Boards absent from the result do not ship. */
|
|
64
|
+
function resolvePolicy(root, allBoards, boardsFlag, allBoardsFlag) {
|
|
51
65
|
const known = (n) => n === "all-scenes" || !!allBoards[n];
|
|
66
|
+
const reveal = {
|
|
67
|
+
structure: true,
|
|
68
|
+
source: false
|
|
69
|
+
};
|
|
70
|
+
const row = (max) => ({
|
|
71
|
+
max,
|
|
72
|
+
type: "mix"
|
|
73
|
+
});
|
|
52
74
|
if (boardsFlag !== void 0) {
|
|
53
75
|
const names = boardsFlag.split(",").map((s) => s.trim()).filter(Boolean);
|
|
54
76
|
if (!names.length) throw new Error("--boards was given but named no boards");
|
|
55
77
|
const missing = names.filter((n) => !known(n));
|
|
56
78
|
if (missing.length) throw new Error(`--boards names not found in design/boards/: ${missing.join(", ")}`);
|
|
57
|
-
return
|
|
79
|
+
return {
|
|
80
|
+
boards: Object.fromEntries(names.map((n) => [n, row("comment")])),
|
|
81
|
+
reveal
|
|
82
|
+
};
|
|
58
83
|
}
|
|
59
|
-
if (allBoardsFlag) return
|
|
84
|
+
if (allBoardsFlag) return {
|
|
85
|
+
boards: Object.fromEntries(["all-scenes", ...Object.keys(allBoards).filter((n) => n !== "all-scenes")].map((n) => [n, row("comment")])),
|
|
86
|
+
reveal
|
|
87
|
+
};
|
|
60
88
|
const policyFile = join(root, "design", "publish.json");
|
|
61
89
|
if (!existsSync(policyFile)) throw new Error("publishing is default-closed and no publish policy exists.\n Either declare one in design/publish.json: { \"boards\": { \"<board>\": \"read\" | \"comment\" } }\n or be explicit: --boards a,b (publish just those) · --all-boards (publish everything)");
|
|
62
90
|
let policy;
|
|
@@ -70,10 +98,33 @@ function resolvePublish(root, allBoards, boardsFlag, allBoardsFlag) {
|
|
|
70
98
|
const out = {};
|
|
71
99
|
for (const [n, level] of entries) {
|
|
72
100
|
if (!known(n)) throw new Error(`design/publish.json names an unknown board: ${n}`);
|
|
73
|
-
if (level
|
|
74
|
-
|
|
101
|
+
if (level === "read" || level === "comment") {
|
|
102
|
+
out[n] = row(level);
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (typeof level !== "object" || level === null) throw new Error(`design/publish.json: board "${n}" has level "${level}" - use "read" or "comment", or a v2 object`);
|
|
106
|
+
const p = level;
|
|
107
|
+
if (p.max !== "read" && p.max !== "comment") throw new Error(`design/publish.json: board "${n}" needs "max": "read" | "comment"`);
|
|
108
|
+
const type = p.type ?? "mix";
|
|
109
|
+
if (!ARTIFACT_TYPES.includes(type)) throw new Error(`design/publish.json: board "${n}" has type "${type}" - use ${ARTIFACT_TYPES.join(" | ")}`);
|
|
110
|
+
if (p.open !== void 0 && !VIEW_MODES.includes(p.open)) throw new Error(`design/publish.json: board "${n}" has open "${p.open}" - use ${VIEW_MODES.join(" | ")}`);
|
|
111
|
+
if (p.lock && p.open === void 0) throw new Error(`design/publish.json: board "${n}" sets "lock" without "open" - name the mode the lock freezes`);
|
|
112
|
+
out[n] = {
|
|
113
|
+
max: p.max,
|
|
114
|
+
type,
|
|
115
|
+
...p.open ? { open: p.open } : {},
|
|
116
|
+
...p.lock ? { lock: true } : {}
|
|
117
|
+
};
|
|
75
118
|
}
|
|
76
|
-
|
|
119
|
+
if (policy.reveal !== void 0) {
|
|
120
|
+
if (typeof policy.reveal !== "object" || policy.reveal === null) throw new Error("design/publish.json: \"reveal\" must be an object");
|
|
121
|
+
if (policy.reveal.structure !== void 0) reveal.structure = policy.reveal.structure === true;
|
|
122
|
+
if (policy.reveal.source !== void 0) reveal.source = policy.reveal.source === true;
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
boards: out,
|
|
126
|
+
reveal
|
|
127
|
+
};
|
|
77
128
|
}
|
|
78
129
|
/** Read every board file; returns name -> parsed json. Bad JSON fails the build loudly. */
|
|
79
130
|
function readBoards(root) {
|
|
@@ -91,6 +142,58 @@ function readBoards(root) {
|
|
|
91
142
|
}
|
|
92
143
|
return out;
|
|
93
144
|
}
|
|
145
|
+
/**
|
|
146
|
+
* The generated registry with OPAQUE keys - the source strip's half of the
|
|
147
|
+
* bundle (01-sharing §6.2). Object keys are string literals that survive
|
|
148
|
+
* bundling verbatim, so with `reveal.source` off they must not be repo paths.
|
|
149
|
+
* The real paths appear only inside import() arguments, which rollup rewrites
|
|
150
|
+
* to chunk imports - they never reach the output. Layout chains are
|
|
151
|
+
* precomputed per key, because the path-walking logic needs the very strings
|
|
152
|
+
* being hidden.
|
|
153
|
+
*/
|
|
154
|
+
function registrySourceOpaque(root, frames, salt) {
|
|
155
|
+
const bases = ["/design/scenes", "/design/components"];
|
|
156
|
+
const opaque = (s) => "k" + createHash("sha256").update(salt).update(s).digest("hex").slice(0, 10);
|
|
157
|
+
const layoutFiles = /* @__PURE__ */ new Set();
|
|
158
|
+
const chainFor = (key) => {
|
|
159
|
+
const base = bases.find((b) => key.startsWith(b + "/")) ?? bases[0];
|
|
160
|
+
const chain = [];
|
|
161
|
+
let dir = key.slice(0, key.lastIndexOf("/"));
|
|
162
|
+
while (dir.length >= base.length) {
|
|
163
|
+
for (const ext of ["tsx", "jsx"]) {
|
|
164
|
+
const lk = `${dir}/_layout.${ext}`;
|
|
165
|
+
if (existsSync(join(root, lk.slice(1)))) {
|
|
166
|
+
chain.unshift(lk);
|
|
167
|
+
layoutFiles.add(lk);
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (dir === base) break;
|
|
172
|
+
dir = dir.slice(0, dir.lastIndexOf("/"));
|
|
173
|
+
}
|
|
174
|
+
return chain;
|
|
175
|
+
};
|
|
176
|
+
const rows = frames.map((f) => {
|
|
177
|
+
const key = "/" + posix(f.file);
|
|
178
|
+
return {
|
|
179
|
+
id: f.id,
|
|
180
|
+
key,
|
|
181
|
+
ok: opaque(key),
|
|
182
|
+
chain: []
|
|
183
|
+
};
|
|
184
|
+
});
|
|
185
|
+
for (const r of rows) r.chain = chainFor(r.key).map(opaque);
|
|
186
|
+
const providers = ["tsx", "jsx"].map((e) => `/design/providers.${e}`).filter((p) => existsSync(join(root, p.slice(1))));
|
|
187
|
+
return `// generated by \`${NAME} build\` - source paths are opaque (reveal.source is off)
|
|
188
|
+
export const frames = { ${rows.map((r) => `'${r.ok}': () => import('${r.key}')`).join(", ")} }
|
|
189
|
+
export const layouts = { ${[...layoutFiles].map((lk) => `'${opaque(lk)}': () => import('${lk}')`).join(", ")} }
|
|
190
|
+
export const providers = { ${providers.map((p, i) => `'p${i}': () => import('${p}')`).join(", ")} }
|
|
191
|
+
const idToKey = { ${rows.map((r) => `'${r.id}': '${r.ok}'`).join(", ")} }
|
|
192
|
+
export function frameFile(frameId) { return idToKey[frameId] ?? null }
|
|
193
|
+
const chains = { ${rows.map((r) => `'${r.ok}': ${JSON.stringify(r.chain)}`).join(", ")} }
|
|
194
|
+
export function layoutChain(fileKey) { return chains[fileKey] ?? [] }
|
|
195
|
+
`;
|
|
196
|
+
}
|
|
94
197
|
/** The generated registry for filtered builds: explicit imports only, same exports. */
|
|
95
198
|
function registrySource(root, frameKeys) {
|
|
96
199
|
const bases = ["/design/scenes", "/design/components"];
|
|
@@ -136,7 +239,7 @@ export function layoutChain(fileKey) {
|
|
|
136
239
|
}
|
|
137
240
|
`;
|
|
138
241
|
}
|
|
139
|
-
async function buildSite(root, boardsFlag, allBoardsFlag) {
|
|
242
|
+
async function buildSite(root, boardsFlag, allBoardsFlag, embedSeeds) {
|
|
140
243
|
const config = await loadConfig(root);
|
|
141
244
|
const host = detectHost(root);
|
|
142
245
|
const pkgDir = packageDir();
|
|
@@ -144,7 +247,11 @@ async function buildSite(root, boardsFlag, allBoardsFlag) {
|
|
|
144
247
|
const outDir = join(root, "design", ".dist");
|
|
145
248
|
const manifest = scanFrames(root);
|
|
146
249
|
const allBoards = readBoards(root);
|
|
147
|
-
const
|
|
250
|
+
const policy = resolvePolicy(root, allBoards, boardsFlag, allBoardsFlag);
|
|
251
|
+
const rights = Object.fromEntries(Object.entries(policy.boards).map(([n, p]) => [n, p.max]));
|
|
252
|
+
const strip = !policy.reveal.source;
|
|
253
|
+
const buildSalt = randomBytes(16).toString("hex");
|
|
254
|
+
const opaquePath = (id, ext) => `__mv/f/mv${createHash("sha256").update(buildSalt).update(id).digest("hex").slice(0, 12)}${ext}`;
|
|
148
255
|
const boardOrder = (n) => {
|
|
149
256
|
const o = allBoards[n]?.order;
|
|
150
257
|
return typeof o === "number" && Number.isFinite(o) ? o : Infinity;
|
|
@@ -159,29 +266,64 @@ async function buildSite(root, boardsFlag, allBoardsFlag) {
|
|
|
159
266
|
for (const b of Object.values(boards)) for (const node of Array.isArray(b?.nodes) ? b.nodes : []) if (typeof node?.frame === "string") wanted.add(node.frame);
|
|
160
267
|
frames = manifest.frames.filter((f) => wanted.has(f.id));
|
|
161
268
|
}
|
|
269
|
+
const pubFrames = strip ? frames.map((f) => ({
|
|
270
|
+
...f,
|
|
271
|
+
file: opaquePath(f.id, f.kind === "html" ? ".html" : "")
|
|
272
|
+
})) : frames;
|
|
273
|
+
const pubManifest = {
|
|
274
|
+
frames: pubFrames,
|
|
275
|
+
scenes: [...new Set(pubFrames.map((f) => f.scene))].sort().map((name) => ({
|
|
276
|
+
name,
|
|
277
|
+
frames: pubFrames.filter((f) => f.scene === name).length
|
|
278
|
+
}))
|
|
279
|
+
};
|
|
280
|
+
const boardsMeta = Object.fromEntries(publishedNames.filter((n) => policy.boards[n]).map((n) => {
|
|
281
|
+
const p = policy.boards[n];
|
|
282
|
+
return [n, {
|
|
283
|
+
type: p.type,
|
|
284
|
+
...p.open ? { open: p.open } : {},
|
|
285
|
+
...p.lock ? { lock: true } : {}
|
|
286
|
+
}];
|
|
287
|
+
}));
|
|
288
|
+
const lockedShell = publishedNames.length > 0 && publishedNames.every((n) => {
|
|
289
|
+
const p = policy.boards[n];
|
|
290
|
+
return !!p?.lock && !!p.open && [
|
|
291
|
+
"present",
|
|
292
|
+
"focus",
|
|
293
|
+
"slides"
|
|
294
|
+
].includes(p.open);
|
|
295
|
+
});
|
|
162
296
|
const data = {
|
|
163
|
-
manifest:
|
|
164
|
-
frames,
|
|
165
|
-
scenes: [...new Set(frames.map((f) => f.scene))].sort().map((name) => ({
|
|
166
|
-
name,
|
|
167
|
-
frames: frames.filter((f) => f.scene === name).length
|
|
168
|
-
}))
|
|
169
|
-
},
|
|
297
|
+
manifest: pubManifest,
|
|
170
298
|
boards,
|
|
171
299
|
names: publishedNames,
|
|
172
300
|
default: publishedNames.find((n) => n !== "all-scenes") ?? publishedNames[0],
|
|
173
|
-
rights
|
|
301
|
+
rights,
|
|
302
|
+
policy: {
|
|
303
|
+
boards: boardsMeta,
|
|
304
|
+
reveal: policy.reveal,
|
|
305
|
+
...lockedShell ? { lockedShell: true } : {}
|
|
306
|
+
}
|
|
174
307
|
};
|
|
175
308
|
const registryFile = posix(join(clientDir, "frame-host", "registry.ts"));
|
|
309
|
+
const lockedFile = posix(join(clientDir, "shell", "LockedApp.tsx"));
|
|
310
|
+
const tsxFrames = frames.filter((f) => f.kind === "tsx");
|
|
176
311
|
const plugins = [{
|
|
177
312
|
name: "marver-build",
|
|
178
313
|
enforce: "pre",
|
|
179
|
-
resolveId(id) {
|
|
314
|
+
resolveId(id, importer) {
|
|
180
315
|
if (id === "virtual:sh-data") return "\0sh-data-build";
|
|
316
|
+
if (lockedShell && (id === "./App.tsx" || id.endsWith("/shell/App.tsx")) && importer && posix(importer).endsWith("/shell/main.tsx")) return lockedFile;
|
|
181
317
|
},
|
|
182
318
|
load(id) {
|
|
183
319
|
if (id === "\0sh-data-build") return `export default ${JSON.stringify(data)}`;
|
|
184
|
-
if (
|
|
320
|
+
if (posix(id) === registryFile) {
|
|
321
|
+
if (strip) return registrySourceOpaque(root, tsxFrames.map((f) => ({
|
|
322
|
+
id: f.id,
|
|
323
|
+
file: posix(f.file)
|
|
324
|
+
})), buildSalt);
|
|
325
|
+
if (!includeAll) return registrySource(root, tsxFrames.map((f) => "/" + posix(f.file)));
|
|
326
|
+
}
|
|
185
327
|
}
|
|
186
328
|
}, react()];
|
|
187
329
|
if (host.tailwind === 4) {
|
|
@@ -196,8 +338,10 @@ async function buildSite(root, boardsFlag, allBoardsFlag) {
|
|
|
196
338
|
config,
|
|
197
339
|
detectedThemeCss: host.themeCss
|
|
198
340
|
}));
|
|
341
|
+
process.env.NODE_ENV = "production";
|
|
199
342
|
const result = await build({
|
|
200
343
|
configFile: false,
|
|
344
|
+
mode: "production",
|
|
201
345
|
root,
|
|
202
346
|
css,
|
|
203
347
|
plugins,
|
|
@@ -218,8 +362,8 @@ async function buildSite(root, boardsFlag, allBoardsFlag) {
|
|
|
218
362
|
},
|
|
219
363
|
output: {
|
|
220
364
|
entryFileNames: "assets/[name]-[hash].js",
|
|
221
|
-
chunkFileNames: "assets/[name]-[hash].js",
|
|
222
|
-
assetFileNames: "assets/[name]-[hash][extname]"
|
|
365
|
+
chunkFileNames: strip ? "assets/c-[hash].js" : "assets/[name]-[hash].js",
|
|
366
|
+
assetFileNames: strip ? "assets/a-[hash][extname]" : "assets/[name]-[hash][extname]"
|
|
223
367
|
}
|
|
224
368
|
}
|
|
225
369
|
},
|
|
@@ -258,8 +402,9 @@ async function buildSite(root, boardsFlag, allBoardsFlag) {
|
|
|
258
402
|
let html = src.includes("</head>") ? src.replace("</head>", `${inject}</head>`) : inject + src;
|
|
259
403
|
const shim = `<script>(function(){var a=Element.prototype.attachShadow;if(a)Element.prototype.attachShadow=function(i){if(i&&i.mode==='closed')window.__mvClosedShadow=1;return a.call(this,i)};})();<\/script>`;
|
|
260
404
|
html = /<head[^>]*>/i.test(html) ? html.replace(/<head[^>]*>/i, (m) => m + shim) : shim + html;
|
|
261
|
-
|
|
262
|
-
|
|
405
|
+
const dest = strip ? opaquePath(f.id, ".html") : f.file;
|
|
406
|
+
mkdirSync(dirname(join(outDir, dest)), { recursive: true });
|
|
407
|
+
writeFileSync(join(outDir, dest), html);
|
|
263
408
|
}
|
|
264
409
|
const assetsDir = join(root, "design", "assets");
|
|
265
410
|
const rootP = posix(root);
|
|
@@ -293,16 +438,22 @@ async function buildSite(root, boardsFlag, allBoardsFlag) {
|
|
|
293
438
|
copiedAssets++;
|
|
294
439
|
}
|
|
295
440
|
const commentsDir = join(root, "design", "comments");
|
|
441
|
+
const seedOut = embedSeeds ? join(outDir, "design", "comments") : join(root, "design", ".dist-seeds");
|
|
442
|
+
if (!embedSeeds) rmSync(seedOut, {
|
|
443
|
+
recursive: true,
|
|
444
|
+
force: true
|
|
445
|
+
});
|
|
296
446
|
if (existsSync(commentsDir)) {
|
|
297
447
|
let seeded = 0;
|
|
298
448
|
for (const n of publishedNames) {
|
|
299
449
|
const f = join(commentsDir, `${n}.jsonl`);
|
|
300
450
|
if (!existsSync(f)) continue;
|
|
301
|
-
mkdirSync(
|
|
302
|
-
cpSync(f, join(
|
|
451
|
+
mkdirSync(seedOut, { recursive: true });
|
|
452
|
+
cpSync(f, join(seedOut, `${n}.jsonl`));
|
|
303
453
|
seeded++;
|
|
304
454
|
}
|
|
305
|
-
if (seeded) console.log(` comments: ${seeded} board log${seeded === 1 ? "" : "s"} seeded`);
|
|
455
|
+
if (seeded) console.log(` comments: ${seeded} board log${seeded === 1 ? "" : "s"} seeded${embedSeeds ? "" : " (design/.dist-seeds, outside the web root)"}`);
|
|
456
|
+
if (seeded && embedSeeds) console.log(" WARNING: --embed-seeds put comment history in the web root - every event carries\n its author's email, readable by anyone who can reach the deployed files.");
|
|
306
457
|
}
|
|
307
458
|
let name = basename(root);
|
|
308
459
|
try {
|
|
@@ -329,7 +480,11 @@ async function buildSite(root, boardsFlag, allBoardsFlag) {
|
|
|
329
480
|
name,
|
|
330
481
|
branding: config.share.branding,
|
|
331
482
|
logo,
|
|
332
|
-
rights
|
|
483
|
+
rights,
|
|
484
|
+
boards: boardsMeta,
|
|
485
|
+
reveal: policy.reveal,
|
|
486
|
+
...config.share.frontDoor === false ? { frontDoor: false } : {},
|
|
487
|
+
...config.share.notify === false ? { notify: false } : {}
|
|
333
488
|
}));
|
|
334
489
|
console.log(`\n ${NAME} build → design/.dist`);
|
|
335
490
|
console.log(` boards: ${publishedNames.map((n) => `${n} (${rights[n]})`).join(", ")}`);
|
package/dist/cli.mjs
CHANGED
|
@@ -39,14 +39,14 @@ function version() {
|
|
|
39
39
|
}
|
|
40
40
|
const cli = cac(NAME);
|
|
41
41
|
cli.command("init", "Scaffold design/ in this repo").option("--mode <mode>", "studio | embedded", { default: "studio" }).option("--no-demo", "Skip the demo scene (the demo ships unless this flag is passed)").option("--root <dir>", "Host repo root", { default: "." }).action(async (opts) => {
|
|
42
|
-
const { init } = await import("./init-
|
|
42
|
+
const { init } = await import("./init-BpitOqRQ.mjs");
|
|
43
43
|
init(resolve(opts.root), {
|
|
44
44
|
mode: opts.mode === "embedded" ? "embedded" : "studio",
|
|
45
45
|
demo: opts.demo !== false
|
|
46
46
|
});
|
|
47
47
|
});
|
|
48
48
|
for (const [name, desc] of [["dev", "Start the local canvas (everything on: hot reload, comments, Live Jam)"], ["canvas", "Start the local canvas - same as dev"]]) cli.command(name, desc).option("--root <dir>", "Host repo root", { default: "." }).option("--port <port>", "Port (default 5199)").action(async (opts) => {
|
|
49
|
-
const { dev } = await import("./dev-
|
|
49
|
+
const { dev } = await import("./dev-BXq7yE1p.mjs");
|
|
50
50
|
let port;
|
|
51
51
|
if (opts.port !== void 0) {
|
|
52
52
|
const n = Number(opts.port);
|
|
@@ -55,18 +55,18 @@ for (const [name, desc] of [["dev", "Start the local canvas (everything on: hot
|
|
|
55
55
|
}
|
|
56
56
|
await dev(resolve(opts.root), port);
|
|
57
57
|
});
|
|
58
|
-
cli.command("build", "Static export → design/.dist (what ships comes from design/publish.json - publishing is default-closed)").option("--boards <names>", "Publish only these boards (comma-separated); overrides the publish policy").option("--all-boards", "Publish every board - the loud override for the default-closed policy").option("--root <dir>", "Host repo root", { default: "." }).action(async (opts) => {
|
|
59
|
-
const { buildSite } = await import("./build-
|
|
58
|
+
cli.command("build", "Static export → design/.dist (what ships comes from design/publish.json - publishing is default-closed)").option("--boards <names>", "Publish only these boards (comma-separated); overrides the publish policy").option("--all-boards", "Publish every board - the loud override for the default-closed policy").option("--embed-seeds", "Copy comment history INTO the web root (identifying - every event carries its author's email)").option("--root <dir>", "Host repo root", { default: "." }).action(async (opts) => {
|
|
59
|
+
const { buildSite } = await import("./build-DmfxJc6L.mjs");
|
|
60
60
|
try {
|
|
61
61
|
const boards = opts.boards === void 0 ? void 0 : typeof opts.boards === "string" ? opts.boards : "";
|
|
62
|
-
await buildSite(resolve(opts.root), boards, opts.allBoards === true);
|
|
62
|
+
await buildSite(resolve(opts.root), boards, opts.allBoards === true, opts.embedSeeds === true);
|
|
63
63
|
} catch (err) {
|
|
64
64
|
console.error(`[${NAME}] build failed: ${err.message}`);
|
|
65
65
|
process.exit(1);
|
|
66
66
|
}
|
|
67
67
|
});
|
|
68
68
|
cli.command("serve", "Serve design/.dist (set MARVER_PASSWORD to gate it)").option("--root <dir>", "Host repo root", { default: "." }).option("--port <port>", "Port (default $PORT or 4199)").action(async (opts) => {
|
|
69
|
-
const { serve } = await import("./serve-
|
|
69
|
+
const { serve } = await import("./serve-BeLLizNg.mjs");
|
|
70
70
|
let port;
|
|
71
71
|
if (opts.port !== void 0) {
|
|
72
72
|
const n = Number(opts.port);
|
|
@@ -75,7 +75,7 @@ cli.command("serve", "Serve design/.dist (set MARVER_PASSWORD to gate it)").opti
|
|
|
75
75
|
serve(resolve(opts.root), port);
|
|
76
76
|
});
|
|
77
77
|
cli.command("comments <action> [value]", "Comment collaboration: connect <url> · sync · list · reply <thread> · resolve <thread> · invite <email> · revoke <email>").option("--root <dir>", "Host repo root", { default: "." }).option("--token <token>", "connect: the canvas's MARVER_CLI_TOKEN (default $MARVER_CLI_TOKEN) - the identity-mode path").option("--invite <token>", "connect: claim this invite instead of signing in").option("--canvas-password <password>", "connect: the canvas gate password (default $MARVER_PASSWORD or prompt)").option("--email <email>", "connect: account email (skips the prompt)").option("--password <password>", "connect: account password (skips the prompt - mind your shell history)").option("--name <name>", "connect --invite: display name for the new account").option("--open", "list: only unresolved threads").option("--json", "list: machine-readable output").option("--board <board>", "scope to one board").option("--body <text>", "reply: the reply text").option("--addressed-in <frame>", "resolve: the variant frame that answered the feedback").action(async (action, value, opts) => {
|
|
78
|
-
const { commentsCommand } = await import("./comments-
|
|
78
|
+
const { commentsCommand } = await import("./comments-pNxjTrGN.mjs");
|
|
79
79
|
try {
|
|
80
80
|
await commentsCommand(resolve(opts.root), action, value, opts);
|
|
81
81
|
} catch (err) {
|
|
@@ -83,6 +83,15 @@ cli.command("comments <action> [value]", "Comment collaboration: connect <url>
|
|
|
83
83
|
process.exit(1);
|
|
84
84
|
}
|
|
85
85
|
});
|
|
86
|
+
cli.command("share <action> [value]", "Sharing roster (owner): add <who> · remove <who> · block/unblock <email> · general <mode> · list · requests · explain <who> · who").option("--root <dir>", "Host repo root", { default: "." }).option("--role <role>", "add / requests --approve: view (default) or comment").option("--expires <iso>", "add: expiry timestamp, e.g. 2026-12-31T00:00:00Z").option("--approve <email>", "requests: approve this pending request (canvas-wide in v1)").option("--decline <email>", "requests: decline this pending request (silent to the asker)").option("--json", "list: machine-readable output").action(async (action, value, opts) => {
|
|
87
|
+
const { shareCommand } = await import("./share-C64b1tdN.mjs");
|
|
88
|
+
try {
|
|
89
|
+
await shareCommand(resolve(opts.root), action, value, opts);
|
|
90
|
+
} catch (err) {
|
|
91
|
+
console.error(`[${NAME}] ${err.message}`);
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
86
95
|
cli.command("work <action> [...frames]", "Working state on the canvas: start <scene/frame ...> · done <scene/frame ...> | --all · list").option("--root <dir>", "Host repo root", { default: "." }).option("--ttl <minutes>", "start: minutes before the glow self-expires (default 10, max 30)").option("--all", "done: clear every working frame").action(async (action, frames, opts) => {
|
|
87
96
|
const { workCommand } = await import("./work-lzC-lPY0.mjs");
|
|
88
97
|
try {
|