@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.
Files changed (119) hide show
  1. package/dist/chunk-26V4YNOR.js +108 -0
  2. package/dist/{chunk-OAGJBCSH.js → chunk-4WQ36ZP7.js} +19 -3
  3. package/dist/{chunk-PTY2RG2K.js → chunk-67P34WNW.js} +75 -130
  4. package/dist/chunk-APIJPTFG.js +64 -0
  5. package/dist/chunk-CDBURDPX.js +90 -0
  6. package/dist/{chunk-PLANHXS7.js → chunk-CEFFP3CH.js} +2 -2
  7. package/dist/chunk-DFKTF3CH.js +0 -0
  8. package/dist/chunk-DJABADOO.js +131 -0
  9. package/dist/{chunk-IP2SEBAJ.js → chunk-DJOGPSRU.js} +31 -72
  10. package/dist/chunk-DKZCHCV3.js +64 -0
  11. package/dist/chunk-FGQXHUAE.js +39 -0
  12. package/dist/chunk-GNF6KFQ7.js +18 -0
  13. package/dist/{chunk-QHMKIODQ.js → chunk-HHNPSKPT.js} +2 -89
  14. package/dist/{chunk-PZPGJZRG.js → chunk-HUOW3ZV2.js} +3 -3
  15. package/dist/{chunk-Y5QECJX7.js → chunk-L7WTERU5.js} +2 -2
  16. package/dist/{chunk-N3G7DOU3.js → chunk-LNQUUC2S.js} +2 -2
  17. package/dist/{chunk-7SAAJVDE.js → chunk-MSBHMY3C.js} +17 -15
  18. package/dist/{chunk-PNSCDBU7.js → chunk-O37AV27P.js} +6 -49
  19. package/dist/{chunk-5KSAS4VY.js → chunk-RIITGTV3.js} +1 -1
  20. package/dist/chunk-S7QRHUWO.js +8 -0
  21. package/dist/chunk-VY3IFGE3.js +70 -0
  22. package/dist/{chunk-VUYCRBJK.js → chunk-W72BPGR3.js} +7 -5
  23. package/dist/collab/rebase.d.ts.map +1 -1
  24. package/dist/collab/rebase.js +15 -15
  25. package/dist/components/editor/index.js +8 -8
  26. package/dist/components/primitives/index.js +14 -9
  27. package/dist/components/sections/brand-guide.js +12 -7
  28. package/dist/components/sections/register-schemas.js +17 -12
  29. package/dist/components/sections/register.js +17 -12
  30. package/dist/components/shell/EditorShell.d.ts.map +1 -1
  31. package/dist/deck-builder/index.js +6 -6
  32. package/dist/hooks/useEditorPublish.d.ts +4 -1
  33. package/dist/hooks/useEditorPublish.d.ts.map +1 -1
  34. package/dist/hooks/useMediaPipeline.d.ts.map +1 -1
  35. package/dist/index.js +78 -49
  36. package/dist/lib/dexie.d.ts +7 -1
  37. package/dist/lib/dexie.d.ts.map +1 -1
  38. package/dist/lib/dexie.js +3 -2
  39. package/dist/lib/document-refs.d.ts +8 -0
  40. package/dist/lib/document-refs.d.ts.map +1 -1
  41. package/dist/lib/document-refs.js +14 -0
  42. package/dist/lib/image-variant-plan.d.ts +42 -0
  43. package/dist/lib/image-variant-plan.d.ts.map +1 -0
  44. package/dist/lib/image-variant-plan.js +53 -0
  45. package/dist/lib/index-ops.d.ts.map +1 -1
  46. package/dist/lib/index-ops.js +20 -16
  47. package/dist/lib/index.d.ts +2 -1
  48. package/dist/lib/index.d.ts.map +1 -1
  49. package/dist/lib/index.js +36 -15
  50. package/dist/lib/loader.d.ts +16 -17
  51. package/dist/lib/loader.d.ts.map +1 -1
  52. package/dist/lib/media-ops.d.ts +73 -0
  53. package/dist/lib/media-ops.d.ts.map +1 -0
  54. package/dist/lib/media-ops.js +60 -0
  55. package/dist/lib/nav-tree.d.ts +6 -0
  56. package/dist/lib/nav-tree.d.ts.map +1 -1
  57. package/dist/lib/pages.d.ts +2 -1
  58. package/dist/lib/pages.d.ts.map +1 -1
  59. package/dist/lib/reference-validation.js +4 -33
  60. package/dist/lib/section-check.d.ts +49 -0
  61. package/dist/lib/section-check.d.ts.map +1 -0
  62. package/dist/lib/section-check.js +14 -0
  63. package/dist/lib/sidecar-diagnostics.d.ts +20 -0
  64. package/dist/lib/sidecar-diagnostics.d.ts.map +1 -0
  65. package/dist/lib/sidecars.d.ts +118 -0
  66. package/dist/lib/sidecars.d.ts.map +1 -0
  67. package/dist/lib/sidecars.js +23 -0
  68. package/dist/lib/site-validation.d.ts +123 -0
  69. package/dist/lib/site-validation.d.ts.map +1 -0
  70. package/dist/lib/site-validation.js +230 -0
  71. package/dist/lib/slug.d.ts +2 -0
  72. package/dist/lib/slug.d.ts.map +1 -0
  73. package/dist/lib/storage-tier.d.ts +17 -0
  74. package/dist/lib/storage-tier.d.ts.map +1 -0
  75. package/dist/lib/storage-tier.js +29 -0
  76. package/dist/lib/tags.d.ts +6 -0
  77. package/dist/lib/tags.d.ts.map +1 -1
  78. package/dist/media/index.js +15 -15
  79. package/dist/media/queue.d.ts +2 -0
  80. package/dist/media/queue.d.ts.map +1 -1
  81. package/dist/media/worker.d.ts +1 -35
  82. package/dist/media/worker.d.ts.map +1 -1
  83. package/dist/schemas/index.js +18 -12
  84. package/dist/schemas/media.d.ts +4 -0
  85. package/dist/schemas/media.d.ts.map +1 -1
  86. package/dist/storage/index.js +2 -1
  87. package/dist/storage/memory.d.ts +21 -0
  88. package/dist/storage/memory.d.ts.map +1 -0
  89. package/dist/storage/memory.js +129 -0
  90. package/dist/storage/types.d.ts +9 -0
  91. package/dist/storage/types.d.ts.map +1 -1
  92. package/package.json +34 -1
  93. package/src/collab/rebase.ts +12 -16
  94. package/src/components/shell/EditorShell.tsx +7 -4
  95. package/src/hooks/useEditorPublish.ts +9 -4
  96. package/src/hooks/useMediaPipeline.ts +29 -23
  97. package/src/lib/dexie.ts +9 -1
  98. package/src/lib/document-refs.ts +30 -0
  99. package/src/lib/image-variant-plan.ts +92 -0
  100. package/src/lib/index-ops.ts +9 -18
  101. package/src/lib/index.ts +15 -0
  102. package/src/lib/loader.ts +18 -77
  103. package/src/lib/media-ops.ts +112 -0
  104. package/src/lib/nav-tree.ts +33 -4
  105. package/src/lib/pages.ts +2 -3
  106. package/src/lib/section-check.ts +166 -0
  107. package/src/lib/sidecar-diagnostics.ts +29 -0
  108. package/src/lib/sidecars.ts +221 -0
  109. package/src/lib/site-validation.ts +269 -0
  110. package/src/lib/slug.ts +6 -0
  111. package/src/lib/storage-tier.ts +38 -0
  112. package/src/lib/tags.ts +20 -3
  113. package/src/media/queue.ts +3 -0
  114. package/src/media/utils.ts +1 -1
  115. package/src/media/worker.ts +17 -8
  116. package/src/schemas/media.ts +7 -2
  117. package/src/storage/memory.ts +178 -0
  118. package/src/storage/types.ts +15 -2
  119. /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-5KSAS4VY.js";
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-QHMKIODQ.js";
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
- RESERVED_SLUGS
3
- } from "./chunk-PTY2RG2K.js";
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) || placed.has(entry.pageId)) continue;
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)) continue;
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" || !validIds.has(id) || placed.has(id)) return false;
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-Y5QECJX7.js";
3
+ } from "./chunk-L7WTERU5.js";
4
4
  import {
5
5
  usePages
6
- } from "./chunk-5KSAS4VY.js";
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-VUYCRBJK.js";
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-5KSAS4VY.js";
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-QHMKIODQ.js";
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-Y5QECJX7.js";
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-5KSAS4VY.js";
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-N3G7DOU3.js";
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-PLANHXS7.js";
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-PZPGJZRG.js";
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-Y5QECJX7.js";
38
+ } from "./chunk-L7WTERU5.js";
39
39
  import {
40
40
  DropEdgeIndicator,
41
41
  useMediaLibrary,
42
42
  useResolvedMedia
43
- } from "./chunk-5KSAS4VY.js";
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-QHMKIODQ.js";
58
+ } from "./chunk-HHNPSKPT.js";
59
59
  import {
60
60
  referenceItems
61
- } from "./chunk-VUYCRBJK.js";
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
- cn
72
- } from "./chunk-7EOSDFS3.js";
78
+ pagesInNavOrder
79
+ } from "./chunk-DJOGPSRU.js";
73
80
  import {
74
81
  siteTags,
75
82
  tagDisplayLabel
76
- } from "./chunk-OAGJBCSH.js";
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";