@drawnagency/primitives 0.1.114 → 0.1.116
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/dist/chunk-26V4YNOR.js +108 -0
- package/dist/{chunk-OAGJBCSH.js → chunk-4WQ36ZP7.js} +19 -3
- package/dist/{chunk-PTY2RG2K.js → chunk-67P34WNW.js} +75 -130
- package/dist/chunk-APIJPTFG.js +64 -0
- package/dist/chunk-CDBURDPX.js +90 -0
- package/dist/{chunk-PLANHXS7.js → chunk-CEFFP3CH.js} +2 -2
- package/dist/chunk-DFKTF3CH.js +0 -0
- package/dist/chunk-DJABADOO.js +131 -0
- package/dist/{chunk-IP2SEBAJ.js → chunk-DJOGPSRU.js} +31 -72
- package/dist/chunk-DKZCHCV3.js +64 -0
- package/dist/chunk-FGQXHUAE.js +39 -0
- package/dist/chunk-GNF6KFQ7.js +18 -0
- package/dist/{chunk-QHMKIODQ.js → chunk-HHNPSKPT.js} +2 -89
- package/dist/{chunk-PZPGJZRG.js → chunk-HUOW3ZV2.js} +3 -3
- package/dist/{chunk-Y5QECJX7.js → chunk-L7WTERU5.js} +2 -2
- package/dist/{chunk-N3G7DOU3.js → chunk-LNQUUC2S.js} +2 -2
- package/dist/{chunk-7SAAJVDE.js → chunk-MSBHMY3C.js} +17 -15
- package/dist/{chunk-PNSCDBU7.js → chunk-O37AV27P.js} +6 -49
- package/dist/{chunk-5KSAS4VY.js → chunk-RIITGTV3.js} +1 -1
- package/dist/chunk-S7QRHUWO.js +8 -0
- package/dist/chunk-VY3IFGE3.js +70 -0
- package/dist/{chunk-VUYCRBJK.js → chunk-W72BPGR3.js} +7 -5
- package/dist/collab/rebase.d.ts.map +1 -1
- package/dist/collab/rebase.js +15 -15
- package/dist/components/editor/index.js +8 -8
- package/dist/components/primitives/index.js +14 -9
- package/dist/components/sections/brand-guide.js +12 -7
- package/dist/components/sections/register-schemas.js +17 -12
- package/dist/components/sections/register.js +17 -12
- package/dist/components/shell/EditorShell.d.ts.map +1 -1
- package/dist/deck-builder/index.js +6 -6
- package/dist/hooks/useEditorPublish.d.ts +4 -1
- package/dist/hooks/useEditorPublish.d.ts.map +1 -1
- package/dist/hooks/useMediaPipeline.d.ts.map +1 -1
- package/dist/index.js +78 -49
- package/dist/lib/dexie.d.ts +7 -1
- package/dist/lib/dexie.d.ts.map +1 -1
- package/dist/lib/dexie.js +3 -2
- package/dist/lib/document-refs.d.ts +8 -0
- package/dist/lib/document-refs.d.ts.map +1 -1
- package/dist/lib/document-refs.js +14 -0
- package/dist/lib/image-variant-plan.d.ts +42 -0
- package/dist/lib/image-variant-plan.d.ts.map +1 -0
- package/dist/lib/image-variant-plan.js +53 -0
- package/dist/lib/index-ops.d.ts.map +1 -1
- package/dist/lib/index-ops.js +20 -16
- package/dist/lib/index.d.ts +2 -1
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +36 -15
- package/dist/lib/loader.d.ts +16 -17
- package/dist/lib/loader.d.ts.map +1 -1
- package/dist/lib/media-ops.d.ts +73 -0
- package/dist/lib/media-ops.d.ts.map +1 -0
- package/dist/lib/media-ops.js +60 -0
- package/dist/lib/nav-tree.d.ts +6 -0
- package/dist/lib/nav-tree.d.ts.map +1 -1
- package/dist/lib/pages.d.ts +2 -1
- package/dist/lib/pages.d.ts.map +1 -1
- package/dist/lib/reference-validation.js +4 -33
- package/dist/lib/section-check.d.ts +49 -0
- package/dist/lib/section-check.d.ts.map +1 -0
- package/dist/lib/section-check.js +14 -0
- package/dist/lib/sidecar-diagnostics.d.ts +20 -0
- package/dist/lib/sidecar-diagnostics.d.ts.map +1 -0
- package/dist/lib/sidecars.d.ts +118 -0
- package/dist/lib/sidecars.d.ts.map +1 -0
- package/dist/lib/sidecars.js +23 -0
- package/dist/lib/site-validation.d.ts +123 -0
- package/dist/lib/site-validation.d.ts.map +1 -0
- package/dist/lib/site-validation.js +230 -0
- package/dist/lib/slug.d.ts +2 -0
- package/dist/lib/slug.d.ts.map +1 -0
- package/dist/lib/storage-tier.d.ts +17 -0
- package/dist/lib/storage-tier.d.ts.map +1 -0
- package/dist/lib/storage-tier.js +29 -0
- package/dist/lib/tags.d.ts +6 -0
- package/dist/lib/tags.d.ts.map +1 -1
- package/dist/media/index.js +15 -15
- package/dist/media/queue.d.ts +2 -0
- package/dist/media/queue.d.ts.map +1 -1
- package/dist/media/worker.d.ts +1 -35
- package/dist/media/worker.d.ts.map +1 -1
- package/dist/schemas/index.js +18 -12
- package/dist/schemas/media.d.ts +4 -0
- package/dist/schemas/media.d.ts.map +1 -1
- package/dist/storage/index.js +2 -1
- package/dist/storage/memory.d.ts +21 -0
- package/dist/storage/memory.d.ts.map +1 -0
- package/dist/storage/memory.js +129 -0
- package/dist/storage/types.d.ts +9 -0
- package/dist/storage/types.d.ts.map +1 -1
- package/package.json +34 -1
- package/src/collab/rebase.ts +12 -16
- package/src/components/shell/EditorShell.tsx +7 -4
- package/src/hooks/useEditorPublish.ts +9 -4
- package/src/hooks/useMediaPipeline.ts +29 -23
- package/src/lib/dexie.ts +9 -1
- package/src/lib/document-refs.ts +30 -0
- package/src/lib/image-variant-plan.ts +92 -0
- package/src/lib/index-ops.ts +9 -18
- package/src/lib/index.ts +15 -0
- package/src/lib/loader.ts +18 -77
- package/src/lib/media-ops.ts +112 -0
- package/src/lib/nav-tree.ts +33 -4
- package/src/lib/pages.ts +2 -3
- package/src/lib/section-check.ts +166 -0
- package/src/lib/sidecar-diagnostics.ts +29 -0
- package/src/lib/sidecars.ts +221 -0
- package/src/lib/site-validation.ts +269 -0
- package/src/lib/slug.ts +6 -0
- package/src/lib/storage-tier.ts +38 -0
- package/src/lib/tags.ts +20 -3
- package/src/media/queue.ts +3 -0
- package/src/media/utils.ts +1 -1
- package/src/media/worker.ts +17 -8
- package/src/schemas/media.ts +7 -2
- package/src/storage/memory.ts +178 -0
- package/src/storage/types.ts +15 -2
- /package/dist/{chunk-45FA7Z55.js → chunk-UUUSJDIG.js} +0 -0
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
Select,
|
|
11
11
|
useMediaLibrary,
|
|
12
12
|
useResolvedMedia
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-RIITGTV3.js";
|
|
14
14
|
import {
|
|
15
15
|
Kbd,
|
|
16
16
|
Tooltip
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
} from "./chunk-IIDKW7AV.js";
|
|
24
24
|
import {
|
|
25
25
|
formatFileSize
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-CDBURDPX.js";
|
|
27
27
|
import {
|
|
28
28
|
cn
|
|
29
29
|
} from "./chunk-7EOSDFS3.js";
|
|
File without changes
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import {
|
|
2
|
+
reconcileNavReport
|
|
3
|
+
} from "./chunk-DJOGPSRU.js";
|
|
4
|
+
import {
|
|
5
|
+
mergeTags,
|
|
6
|
+
reconcileTagsReport
|
|
7
|
+
} from "./chunk-4WQ36ZP7.js";
|
|
8
|
+
import {
|
|
9
|
+
NavEntrySchema,
|
|
10
|
+
NavFileSchema,
|
|
11
|
+
TagEntrySchema,
|
|
12
|
+
TagsFileSchema
|
|
13
|
+
} from "./chunk-4Y2JQQZL.js";
|
|
14
|
+
|
|
15
|
+
// src/lib/sidecars.ts
|
|
16
|
+
var NAV = {
|
|
17
|
+
name: "nav",
|
|
18
|
+
path: "src/content/nav.json",
|
|
19
|
+
fileKey: "entries",
|
|
20
|
+
entrySchema: NavEntrySchema,
|
|
21
|
+
fileSchema: NavFileSchema,
|
|
22
|
+
reconcile: (entries, index) => reconcileNavReport(entries, index.pages),
|
|
23
|
+
// Grouping is edited rarely and has no dirty tracking, so persisted remote
|
|
24
|
+
// state beats unsaved local edits. A remote without the Sidecar (an older
|
|
25
|
+
// server) keeps ours rather than flattening it.
|
|
26
|
+
rebase: ({ local, remote }) => remote !== void 0 ? remote : local,
|
|
27
|
+
words: {
|
|
28
|
+
entries: "navigation entries",
|
|
29
|
+
changes: "Page grouping changes",
|
|
30
|
+
valid: "a valid navigation tree",
|
|
31
|
+
shape: 'an array of {kind:"page",pageId} / {kind:"group",id,label,startCollapsed,pageIds} entries'
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
var TAGS = {
|
|
35
|
+
name: "tags",
|
|
36
|
+
path: "src/content/tags.json",
|
|
37
|
+
fileKey: "tags",
|
|
38
|
+
entrySchema: TagEntrySchema,
|
|
39
|
+
fileSchema: TagsFileSchema,
|
|
40
|
+
reconcile: (entries, index) => reconcileTagsReport(entries, index.sections),
|
|
41
|
+
// Tagging is edited from every section's chrome, so remote-wins would drop
|
|
42
|
+
// unsaved tagging whenever a peer saved anything. See mergeTags.
|
|
43
|
+
rebase: mergeTags,
|
|
44
|
+
words: {
|
|
45
|
+
entries: "tag entries",
|
|
46
|
+
changes: "Tag changes",
|
|
47
|
+
valid: "a valid tag list",
|
|
48
|
+
shape: "an array of {id,label,sectionIds} entries"
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
var SIDECARS = [NAV, TAGS];
|
|
52
|
+
function readEntries(def, raw) {
|
|
53
|
+
if (!Array.isArray(raw)) {
|
|
54
|
+
console.warn(`[sidecars] ${def.name}: entry list is not a list; reading it as empty and degraded`);
|
|
55
|
+
return { entries: [], degraded: true };
|
|
56
|
+
}
|
|
57
|
+
const entries = [];
|
|
58
|
+
let dropped = 0;
|
|
59
|
+
for (const item of raw) {
|
|
60
|
+
const parsed = def.entrySchema.safeParse(item);
|
|
61
|
+
if (parsed.success) entries.push(parsed.data);
|
|
62
|
+
else dropped++;
|
|
63
|
+
}
|
|
64
|
+
if (dropped > 0) {
|
|
65
|
+
console.warn(`[sidecars] ${def.name}: dropped ${dropped} entr${dropped === 1 ? "y" : "ies"} this package version cannot represent; the read is degraded`);
|
|
66
|
+
}
|
|
67
|
+
return { entries, degraded: dropped > 0 };
|
|
68
|
+
}
|
|
69
|
+
function readSidecar(def, file) {
|
|
70
|
+
if (file === void 0 || file === null) return { entries: [], degraded: false };
|
|
71
|
+
return readEntries(def, file[def.fileKey]);
|
|
72
|
+
}
|
|
73
|
+
function readSidecarText(def, text) {
|
|
74
|
+
if (text === void 0) return { entries: [], degraded: false };
|
|
75
|
+
let file;
|
|
76
|
+
try {
|
|
77
|
+
file = JSON.parse(text);
|
|
78
|
+
} catch {
|
|
79
|
+
console.warn(`[sidecars] ${def.name}: ${def.path} is not valid JSON; the read is degraded`);
|
|
80
|
+
return { entries: [], degraded: true };
|
|
81
|
+
}
|
|
82
|
+
return readSidecar(def, file);
|
|
83
|
+
}
|
|
84
|
+
function liftSidecars(rawIndex) {
|
|
85
|
+
const raw = rawIndex !== null && typeof rawIndex === "object" ? rawIndex : {};
|
|
86
|
+
return {
|
|
87
|
+
...raw.nav !== void 0 ? { nav: readEntries(NAV, raw.nav) } : {},
|
|
88
|
+
...raw.tags !== void 0 ? { tags: readEntries(TAGS, raw.tags) } : {}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function planSidecarWrite(def, posted, branch, index) {
|
|
92
|
+
if (posted === void 0) return { action: "untouched" };
|
|
93
|
+
const skip = (reason) => ({
|
|
94
|
+
action: "skip",
|
|
95
|
+
warning: `${def.path} was left unchanged: ${reason} ${def.words.changes} from this save did not land. Upgrade the site's @drawnagency packages (or repair ${def.path} directly in the repo), then retry.`
|
|
96
|
+
});
|
|
97
|
+
if (posted.degraded) {
|
|
98
|
+
return {
|
|
99
|
+
action: "skip",
|
|
100
|
+
warning: `${def.name} was not ${def.words.valid}, so ${def.path} was left unchanged (it held entries this package version cannot read). Expected ${def.words.shape}.`
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
if (branch.kind === "unreadable") {
|
|
104
|
+
return skip("the current file could not be read to confirm the replacement loses nothing.");
|
|
105
|
+
}
|
|
106
|
+
if (branch.kind === "present") {
|
|
107
|
+
let existing;
|
|
108
|
+
try {
|
|
109
|
+
existing = JSON.parse(branch.text);
|
|
110
|
+
} catch {
|
|
111
|
+
return skip("the current file is not valid JSON, so this version cannot prove a replacement keeps its entries.");
|
|
112
|
+
}
|
|
113
|
+
if (!def.fileSchema.safeParse(existing).success) {
|
|
114
|
+
return skip(`the current file holds ${def.words.entries} this package version cannot represent (likely written by a newer version).`);
|
|
115
|
+
}
|
|
116
|
+
} else if (posted.entries.length === 0) {
|
|
117
|
+
return { action: "untouched" };
|
|
118
|
+
}
|
|
119
|
+
const { entries } = def.reconcile(posted.entries, index);
|
|
120
|
+
return { action: "write", path: def.path, content: JSON.stringify({ [def.fileKey]: entries }, null, 2) };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export {
|
|
124
|
+
NAV,
|
|
125
|
+
TAGS,
|
|
126
|
+
SIDECARS,
|
|
127
|
+
readSidecar,
|
|
128
|
+
readSidecarText,
|
|
129
|
+
liftSidecars,
|
|
130
|
+
planSidecarWrite
|
|
131
|
+
};
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
} from "./chunk-
|
|
2
|
+
diagnosticsCollector
|
|
3
|
+
} from "./chunk-GNF6KFQ7.js";
|
|
4
4
|
|
|
5
5
|
// src/lib/nav-tree.ts
|
|
6
6
|
function reconcileNav(entries, pages) {
|
|
7
|
+
return reconcileNavReport(entries, pages).entries;
|
|
8
|
+
}
|
|
9
|
+
function reconcileNavReport(entries, pages) {
|
|
10
|
+
const report = diagnosticsCollector();
|
|
7
11
|
const entryList = Array.isArray(entries) ? entries : [];
|
|
8
12
|
const pageList = Array.isArray(pages) ? pages : [];
|
|
9
13
|
const validIds = /* @__PURE__ */ new Set();
|
|
@@ -15,18 +19,36 @@ function reconcileNav(entries, pages) {
|
|
|
15
19
|
const result = [];
|
|
16
20
|
for (const entry of entryList) {
|
|
17
21
|
if (entry?.kind === "page") {
|
|
18
|
-
if (!validIds.has(entry.pageId)
|
|
22
|
+
if (!validIds.has(entry.pageId)) {
|
|
23
|
+
report.add("dangling", entry.pageId);
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (placed.has(entry.pageId)) {
|
|
27
|
+
report.add("duplicate-member", entry.pageId);
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
19
30
|
placed.add(entry.pageId);
|
|
20
31
|
result.push({ ...entry });
|
|
21
32
|
continue;
|
|
22
33
|
}
|
|
23
34
|
if (entry?.kind !== "group") continue;
|
|
24
35
|
if (typeof entry.id !== "string" || entry.id === "") continue;
|
|
25
|
-
if (seenGroupIds.has(entry.id))
|
|
36
|
+
if (seenGroupIds.has(entry.id)) {
|
|
37
|
+
report.add("duplicate-id", entry.id);
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
26
40
|
seenGroupIds.add(entry.id);
|
|
27
41
|
const claimed = Array.isArray(entry.pageIds) ? entry.pageIds : [];
|
|
28
42
|
const pageIds = claimed.filter((id) => {
|
|
29
|
-
if (typeof id !== "string"
|
|
43
|
+
if (typeof id !== "string") return false;
|
|
44
|
+
if (!validIds.has(id)) {
|
|
45
|
+
report.add("dangling", id);
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
if (placed.has(id)) {
|
|
49
|
+
report.add("duplicate-member", id);
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
30
52
|
placed.add(id);
|
|
31
53
|
return true;
|
|
32
54
|
});
|
|
@@ -42,9 +64,10 @@ function reconcileNav(entries, pages) {
|
|
|
42
64
|
for (const p of pageList) {
|
|
43
65
|
if (!p?.id || placed.has(p.id)) continue;
|
|
44
66
|
placed.add(p.id);
|
|
67
|
+
report.add("unlisted", p.id);
|
|
45
68
|
result.push({ kind: "page", pageId: p.id });
|
|
46
69
|
}
|
|
47
|
-
return result;
|
|
70
|
+
return { entries: result, diagnostics: report.list() };
|
|
48
71
|
}
|
|
49
72
|
function navEntries(index) {
|
|
50
73
|
return reconcileNav(index.nav ?? [], index.pages);
|
|
@@ -132,67 +155,9 @@ function moveNavEntry(index, from, to) {
|
|
|
132
155
|
return withNav(index, entries);
|
|
133
156
|
}
|
|
134
157
|
|
|
135
|
-
// src/lib/pages.ts
|
|
136
|
-
function pageDisplayTitle(title) {
|
|
137
|
-
return title || "Untitled";
|
|
138
|
-
}
|
|
139
|
-
function slugifyPageSlug(input) {
|
|
140
|
-
return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
141
|
-
}
|
|
142
|
-
function uniquePageSlug(base, existing) {
|
|
143
|
-
const taken = new Set(existing);
|
|
144
|
-
const reserved = new Set(RESERVED_SLUGS);
|
|
145
|
-
let candidate = base || "page";
|
|
146
|
-
if (!taken.has(candidate) && !reserved.has(candidate)) return candidate;
|
|
147
|
-
let n = 2;
|
|
148
|
-
while (taken.has(`${candidate}-${n}`) || reserved.has(`${candidate}-${n}`)) n++;
|
|
149
|
-
return `${candidate}-${n}`;
|
|
150
|
-
}
|
|
151
|
-
function pageById(index, id) {
|
|
152
|
-
return index.pages.find((p) => p.id === id);
|
|
153
|
-
}
|
|
154
|
-
function audiencePasses(access, audience) {
|
|
155
|
-
if (access.length === 0) return true;
|
|
156
|
-
if (!audience) return true;
|
|
157
|
-
return access.includes(audience);
|
|
158
|
-
}
|
|
159
|
-
function addPage(index, id) {
|
|
160
|
-
const slug = uniquePageSlug("new-page", index.pages.map((p) => p.slug));
|
|
161
|
-
const page = {
|
|
162
|
-
id,
|
|
163
|
-
title: "",
|
|
164
|
-
slug,
|
|
165
|
-
isHome: false,
|
|
166
|
-
showInNav: true,
|
|
167
|
-
status: "live",
|
|
168
|
-
access: [],
|
|
169
|
-
order: []
|
|
170
|
-
};
|
|
171
|
-
return {
|
|
172
|
-
...index,
|
|
173
|
-
pages: [...index.pages, page],
|
|
174
|
-
nav: [...navEntries(index), { kind: "page", pageId: id }]
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
function deletePage(index, pageId) {
|
|
178
|
-
const page = pageById(index, pageId);
|
|
179
|
-
if (!page || page.isHome) return { index, removedSectionIds: [] };
|
|
180
|
-
const removedSectionIds = [...page.order];
|
|
181
|
-
const nextSections = { ...index.sections };
|
|
182
|
-
for (const id of removedSectionIds) delete nextSections[id];
|
|
183
|
-
return {
|
|
184
|
-
index: {
|
|
185
|
-
...index,
|
|
186
|
-
pages: index.pages.filter((p) => p.id !== pageId),
|
|
187
|
-
sections: nextSections,
|
|
188
|
-
nav: navEntries(index).filter((e) => !(e.kind === "page" && e.pageId === pageId)).map((e) => e.kind === "group" ? { ...e, pageIds: e.pageIds.filter((id) => id !== pageId) } : e)
|
|
189
|
-
},
|
|
190
|
-
removedSectionIds
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
|
|
194
158
|
export {
|
|
195
159
|
reconcileNav,
|
|
160
|
+
reconcileNavReport,
|
|
196
161
|
navEntries,
|
|
197
162
|
pagesInNavOrder,
|
|
198
163
|
groupOfPage,
|
|
@@ -201,11 +166,5 @@ export {
|
|
|
201
166
|
renameGroup,
|
|
202
167
|
setGroupStartCollapsed,
|
|
203
168
|
deleteGroup,
|
|
204
|
-
moveNavEntry
|
|
205
|
-
pageDisplayTitle,
|
|
206
|
-
slugifyPageSlug,
|
|
207
|
-
uniquePageSlug,
|
|
208
|
-
audiencePasses,
|
|
209
|
-
addPage,
|
|
210
|
-
deletePage
|
|
169
|
+
moveNavEntry
|
|
211
170
|
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getContainerChildren
|
|
3
|
+
} from "./chunk-L45X7DKX.js";
|
|
4
|
+
|
|
5
|
+
// src/lib/document-refs.ts
|
|
6
|
+
function documentIdOf(section) {
|
|
7
|
+
if (section.type !== "document") return "";
|
|
8
|
+
return section.content.doc?.documentId ?? "";
|
|
9
|
+
}
|
|
10
|
+
function tallyDocumentIds(value, counts = /* @__PURE__ */ new Map()) {
|
|
11
|
+
if (Array.isArray(value)) {
|
|
12
|
+
for (const item of value) tallyDocumentIds(item, counts);
|
|
13
|
+
return counts;
|
|
14
|
+
}
|
|
15
|
+
const section = value;
|
|
16
|
+
const documentId = documentIdOf(section);
|
|
17
|
+
if (documentId) counts.set(documentId, (counts.get(documentId) ?? 0) + 1);
|
|
18
|
+
for (const child of getContainerChildren(section)) tallyDocumentIds(child, counts);
|
|
19
|
+
return counts;
|
|
20
|
+
}
|
|
21
|
+
function clearDocumentRefs(section, ids) {
|
|
22
|
+
const documentId = documentIdOf(section);
|
|
23
|
+
if (documentId && ids.has(documentId)) {
|
|
24
|
+
const content = section.content;
|
|
25
|
+
return {
|
|
26
|
+
changed: true,
|
|
27
|
+
section: { ...section, content: { ...section.content, doc: { ...content.doc, documentId: "" } } }
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const children = getContainerChildren(section);
|
|
31
|
+
if (children.length === 0) return { changed: false, section };
|
|
32
|
+
let changed = false;
|
|
33
|
+
const next = children.map((child) => {
|
|
34
|
+
const result = clearDocumentRefs(child, ids);
|
|
35
|
+
if (result.changed) changed = true;
|
|
36
|
+
return result.section;
|
|
37
|
+
});
|
|
38
|
+
if (!changed) return { changed: false, section };
|
|
39
|
+
return { changed: true, section: { ...section, content: { ...section.content, children: next } } };
|
|
40
|
+
}
|
|
41
|
+
function collectDocumentIds(value, out = /* @__PURE__ */ new Set()) {
|
|
42
|
+
if (Array.isArray(value)) {
|
|
43
|
+
for (const item of value) collectDocumentIds(item, out);
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
if (typeof value !== "object" || value === null) return out;
|
|
47
|
+
const node = value;
|
|
48
|
+
const content = node.content;
|
|
49
|
+
if (typeof content !== "object" || content === null || Array.isArray(content)) return out;
|
|
50
|
+
const record = content;
|
|
51
|
+
if (node.type === "document") {
|
|
52
|
+
const doc = record.doc;
|
|
53
|
+
const documentId = typeof doc === "object" && doc !== null ? doc.documentId : void 0;
|
|
54
|
+
if (typeof documentId === "string" && documentId !== "") out.add(documentId);
|
|
55
|
+
}
|
|
56
|
+
if (Array.isArray(record.children)) collectDocumentIds(record.children, out);
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export {
|
|
61
|
+
tallyDocumentIds,
|
|
62
|
+
clearDocumentRefs,
|
|
63
|
+
collectDocumentIds
|
|
64
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {
|
|
2
|
+
REFERENCE_TYPE
|
|
3
|
+
} from "./chunk-5GFACGSN.js";
|
|
4
|
+
|
|
5
|
+
// src/lib/reference-validation.ts
|
|
6
|
+
var strings = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string") : [];
|
|
7
|
+
function referenceProblems(sections, index, tagIds) {
|
|
8
|
+
const onPage = new Set(index.pages.flatMap((p) => p.order));
|
|
9
|
+
const problems = [];
|
|
10
|
+
for (const { id, content } of sections) {
|
|
11
|
+
const body = content;
|
|
12
|
+
if (body?.type !== REFERENCE_TYPE && index.sections[id]?.type !== REFERENCE_TYPE) continue;
|
|
13
|
+
const picks = strings(body?.content?.sectionIds).filter((pick) => pick !== id);
|
|
14
|
+
const problem = {
|
|
15
|
+
referenceId: id,
|
|
16
|
+
unknownTagIds: tagIds ? strings(body?.content?.tagIds).filter((tag) => !tagIds.has(tag)) : [],
|
|
17
|
+
unplacedSectionIds: picks.filter((pick) => !onPage.has(pick)),
|
|
18
|
+
referencePickIds: picks.filter((pick) => onPage.has(pick) && index.sections[pick]?.type === REFERENCE_TYPE),
|
|
19
|
+
picksItself: strings(body?.content?.sectionIds).includes(id)
|
|
20
|
+
};
|
|
21
|
+
if (problem.unknownTagIds.length || problem.unplacedSectionIds.length || problem.referencePickIds.length || problem.picksItself) problems.push(problem);
|
|
22
|
+
}
|
|
23
|
+
return problems;
|
|
24
|
+
}
|
|
25
|
+
function describeReferenceProblem(problem) {
|
|
26
|
+
const list = (ids) => ids.map((id) => `"${id}"`).join(", ");
|
|
27
|
+
const issues = [
|
|
28
|
+
...problem.unknownTagIds.length ? [`tagIds ${list(problem.unknownTagIds)} are not tags on this site`] : [],
|
|
29
|
+
...problem.unplacedSectionIds.length ? [`sectionIds ${list(problem.unplacedSectionIds)} are not top-level sections on any page (a container's child cannot be picked \u2014 pick the container)`] : [],
|
|
30
|
+
...problem.referencePickIds.length ? [`sectionIds ${list(problem.referencePickIds)} are References, which a Reference never shows`] : [],
|
|
31
|
+
...problem.picksItself ? ["sectionIds includes the Reference itself"] : []
|
|
32
|
+
];
|
|
33
|
+
return `Reference "${problem.referenceId}": ${issues.join("; ")}.`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export {
|
|
37
|
+
referenceProblems,
|
|
38
|
+
describeReferenceProblem
|
|
39
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// src/lib/sidecar-diagnostics.ts
|
|
2
|
+
function diagnosticsCollector() {
|
|
3
|
+
const byCode = /* @__PURE__ */ new Map();
|
|
4
|
+
return {
|
|
5
|
+
add(code, id) {
|
|
6
|
+
const ids = byCode.get(code) ?? /* @__PURE__ */ new Set();
|
|
7
|
+
ids.add(id);
|
|
8
|
+
byCode.set(code, ids);
|
|
9
|
+
},
|
|
10
|
+
list() {
|
|
11
|
+
return [...byCode].map(([code, ids]) => ({ code, ids: [...ids] }));
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
diagnosticsCollector
|
|
18
|
+
};
|
|
@@ -1,80 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
slugifyPageSlug
|
|
3
|
-
} from "./chunk-IP2SEBAJ.js";
|
|
4
|
-
|
|
5
|
-
// src/media/utils.ts
|
|
6
|
-
async function hashFileBuffer(buffer) {
|
|
7
|
-
if (typeof crypto !== "undefined" && crypto.subtle) {
|
|
8
|
-
const hashBuffer = await crypto.subtle.digest("SHA-256", buffer);
|
|
9
|
-
const hashArray = new Uint8Array(hashBuffer);
|
|
10
|
-
return Array.from(hashArray.slice(0, 8)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
11
|
-
}
|
|
12
|
-
const bytes = new Uint8Array(buffer);
|
|
13
|
-
const seeds = [2166136261, 84696351];
|
|
14
|
-
let result = "";
|
|
15
|
-
for (const seed of seeds) {
|
|
16
|
-
let h = seed;
|
|
17
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
18
|
-
h ^= bytes[i];
|
|
19
|
-
h = Math.imul(h, 16777619);
|
|
20
|
-
}
|
|
21
|
-
result += (h >>> 0).toString(16).padStart(8, "0");
|
|
22
|
-
}
|
|
23
|
-
return result;
|
|
24
|
-
}
|
|
25
|
-
function sanitizeMediaName(name) {
|
|
26
|
-
return slugifyPageSlug(name.replace(/\.[^.]+$/, ""));
|
|
27
|
-
}
|
|
28
|
-
var MIME_TO_EXT = {
|
|
29
|
-
"image/gif": "gif",
|
|
30
|
-
"image/apng": "apng",
|
|
31
|
-
"image/png": "png",
|
|
32
|
-
"image/jpeg": "jpg",
|
|
33
|
-
"image/webp": "webp",
|
|
34
|
-
"image/svg+xml": "svg",
|
|
35
|
-
"video/mp4": "mp4",
|
|
36
|
-
"video/webm": "webm"
|
|
37
|
-
};
|
|
38
|
-
var EXT_TO_MIME = {
|
|
39
|
-
...Object.fromEntries(
|
|
40
|
-
Object.entries(MIME_TO_EXT).map(([mime, ext]) => [`.${ext}`, mime])
|
|
41
|
-
),
|
|
42
|
-
".jpeg": "image/jpeg"
|
|
43
|
-
};
|
|
44
|
-
function mimeToExt(mime) {
|
|
45
|
-
return MIME_TO_EXT[mime] ?? "bin";
|
|
46
|
-
}
|
|
47
|
-
function mediaThumbnailUrl(item) {
|
|
48
|
-
if (item.mimeType === "image/svg+xml" || item.kind !== "image") {
|
|
49
|
-
return `/api/media/${item.id}/original.${mimeToExt(item.mimeType)}`;
|
|
50
|
-
}
|
|
51
|
-
if (item.variants.length === 0) return null;
|
|
52
|
-
const smallest = item.variants.reduce((a, b) => a.width < b.width ? a : b);
|
|
53
|
-
return `/api/media/${item.id}/${smallest.width}.webp`;
|
|
54
|
-
}
|
|
55
|
-
function imageThumbnailUrl(item) {
|
|
56
|
-
return item?.kind === "image" ? mediaThumbnailUrl(item) : null;
|
|
57
|
-
}
|
|
58
|
-
function displayFilenameExt(mime) {
|
|
59
|
-
const ext = MIME_TO_EXT[mime];
|
|
60
|
-
return ext ? `.${ext}` : "";
|
|
61
|
-
}
|
|
62
|
-
function displayFilename(originalName, mimeType) {
|
|
63
|
-
const ext = MIME_TO_EXT[mimeType];
|
|
64
|
-
if (!ext) return originalName;
|
|
65
|
-
const suffix = `.${ext}`;
|
|
66
|
-
if (originalName.toLowerCase().endsWith(suffix)) return originalName;
|
|
67
|
-
return `${originalName}${suffix}`;
|
|
68
|
-
}
|
|
69
|
-
function formatFileSize(bytes) {
|
|
70
|
-
if (bytes >= 1048576) return `${Math.round(bytes / 1048576)}MB`;
|
|
71
|
-
if (bytes >= 1024) return `${Math.round(bytes / 1024)}KB`;
|
|
72
|
-
return `${bytes}B`;
|
|
73
|
-
}
|
|
74
|
-
function displayName(item) {
|
|
75
|
-
return item.originalName;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
1
|
// src/media/queue.ts
|
|
79
2
|
var ProcessingQueue = class {
|
|
80
3
|
items = /* @__PURE__ */ new Map();
|
|
@@ -142,7 +65,8 @@ var ProcessingQueue = class {
|
|
|
142
65
|
primaryBlob: msg.primaryBlob,
|
|
143
66
|
posterBlob: msg.posterBlob,
|
|
144
67
|
width: msg.width,
|
|
145
|
-
height: msg.height
|
|
68
|
+
height: msg.height,
|
|
69
|
+
plan: msg.plan
|
|
146
70
|
};
|
|
147
71
|
this.options.onEvent({ type: "complete", item: { ...item } });
|
|
148
72
|
delete item.result;
|
|
@@ -432,17 +356,6 @@ function getMediaProvider() {
|
|
|
432
356
|
}
|
|
433
357
|
|
|
434
358
|
export {
|
|
435
|
-
hashFileBuffer,
|
|
436
|
-
sanitizeMediaName,
|
|
437
|
-
MIME_TO_EXT,
|
|
438
|
-
EXT_TO_MIME,
|
|
439
|
-
mimeToExt,
|
|
440
|
-
mediaThumbnailUrl,
|
|
441
|
-
imageThumbnailUrl,
|
|
442
|
-
displayFilenameExt,
|
|
443
|
-
displayFilename,
|
|
444
|
-
formatFileSize,
|
|
445
|
-
displayName,
|
|
446
359
|
ProcessingQueue,
|
|
447
360
|
resolveMedia,
|
|
448
361
|
resolveManifestReferences,
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
EditablePlainText
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-L7WTERU5.js";
|
|
4
4
|
import {
|
|
5
5
|
usePages
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-RIITGTV3.js";
|
|
7
7
|
import {
|
|
8
8
|
Button
|
|
9
9
|
} from "./chunk-GGYY3JQJ.js";
|
|
10
10
|
import {
|
|
11
11
|
toSectionId
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-W72BPGR3.js";
|
|
13
13
|
import {
|
|
14
14
|
ensureSanitizer,
|
|
15
15
|
isSanitizerReady,
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
DropEdgeIndicator,
|
|
4
4
|
useMediaLibrary,
|
|
5
5
|
useResolvedMedia
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-RIITGTV3.js";
|
|
7
7
|
import {
|
|
8
8
|
computeReorderTarget
|
|
9
9
|
} from "./chunk-DIMDRBFK.js";
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from "./chunk-IIDKW7AV.js";
|
|
13
13
|
import {
|
|
14
14
|
rebindImageRef
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-HHNPSKPT.js";
|
|
16
16
|
import {
|
|
17
17
|
cn
|
|
18
18
|
} from "./chunk-7EOSDFS3.js";
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
MediaBlock,
|
|
10
10
|
containerGridClass,
|
|
11
11
|
useEditableCollection
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-L7WTERU5.js";
|
|
13
13
|
import {
|
|
14
14
|
DragHandle,
|
|
15
15
|
DropEdgeIndicator,
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
Select,
|
|
20
20
|
useMediaLibrary,
|
|
21
21
|
usePages
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-RIITGTV3.js";
|
|
23
23
|
import {
|
|
24
24
|
IconButton
|
|
25
25
|
} from "./chunk-IIDKW7AV.js";
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
pluralize,
|
|
5
5
|
stripHtmlToPlainText,
|
|
6
6
|
truncate
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-LNQUUC2S.js";
|
|
8
8
|
import {
|
|
9
9
|
DeleteButton,
|
|
10
10
|
DragHandle,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
canDropBlock,
|
|
16
16
|
isBlockDragData,
|
|
17
17
|
useOptionalEditorContext
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-CEFFP3CH.js";
|
|
19
19
|
import {
|
|
20
20
|
Checkbox,
|
|
21
21
|
CheckboxBox,
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
EditableRichText,
|
|
26
26
|
defineHeadingSection,
|
|
27
27
|
useSanitizedHtml
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-HUOW3ZV2.js";
|
|
29
29
|
import {
|
|
30
30
|
EditablePlainText,
|
|
31
31
|
ImageDropZone,
|
|
@@ -35,12 +35,12 @@ import {
|
|
|
35
35
|
containerGridClass,
|
|
36
36
|
masonryColumnsClass,
|
|
37
37
|
spacerHiddenClass
|
|
38
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-L7WTERU5.js";
|
|
39
39
|
import {
|
|
40
40
|
DropEdgeIndicator,
|
|
41
41
|
useMediaLibrary,
|
|
42
42
|
useResolvedMedia
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-RIITGTV3.js";
|
|
44
44
|
import {
|
|
45
45
|
Kbd,
|
|
46
46
|
Popover,
|
|
@@ -55,10 +55,17 @@ import {
|
|
|
55
55
|
} from "./chunk-Y4JQGO6G.js";
|
|
56
56
|
import {
|
|
57
57
|
getMediaProvider
|
|
58
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-HHNPSKPT.js";
|
|
59
59
|
import {
|
|
60
60
|
referenceItems
|
|
61
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-W72BPGR3.js";
|
|
62
|
+
import {
|
|
63
|
+
cn
|
|
64
|
+
} from "./chunk-7EOSDFS3.js";
|
|
65
|
+
import {
|
|
66
|
+
audiencePasses,
|
|
67
|
+
pageDisplayTitle
|
|
68
|
+
} from "./chunk-VY3IFGE3.js";
|
|
62
69
|
import {
|
|
63
70
|
duplicateChildAt,
|
|
64
71
|
isSpacer,
|
|
@@ -68,17 +75,12 @@ import {
|
|
|
68
75
|
trimTrailingSpacers
|
|
69
76
|
} from "./chunk-L45X7DKX.js";
|
|
70
77
|
import {
|
|
71
|
-
|
|
72
|
-
} from "./chunk-
|
|
78
|
+
pagesInNavOrder
|
|
79
|
+
} from "./chunk-DJOGPSRU.js";
|
|
73
80
|
import {
|
|
74
81
|
siteTags,
|
|
75
82
|
tagDisplayLabel
|
|
76
|
-
} from "./chunk-
|
|
77
|
-
import {
|
|
78
|
-
audiencePasses,
|
|
79
|
-
pageDisplayTitle,
|
|
80
|
-
pagesInNavOrder
|
|
81
|
-
} from "./chunk-IP2SEBAJ.js";
|
|
83
|
+
} from "./chunk-4WQ36ZP7.js";
|
|
82
84
|
import {
|
|
83
85
|
REFERENCE_TYPE
|
|
84
86
|
} from "./chunk-5GFACGSN.js";
|