@drawnagency/primitives 0.1.114 → 0.1.115

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 (103) hide show
  1. package/dist/{chunk-OAGJBCSH.js → chunk-4WQ36ZP7.js} +19 -3
  2. package/dist/{chunk-PTY2RG2K.js → chunk-67P34WNW.js} +75 -130
  3. package/dist/chunk-APIJPTFG.js +64 -0
  4. package/dist/chunk-CDBURDPX.js +90 -0
  5. package/dist/chunk-DFKTF3CH.js +0 -0
  6. package/dist/chunk-DJABADOO.js +131 -0
  7. package/dist/{chunk-IP2SEBAJ.js → chunk-DJOGPSRU.js} +31 -72
  8. package/dist/{chunk-N3G7DOU3.js → chunk-FHTKSELX.js} +6 -6
  9. package/dist/chunk-GNF6KFQ7.js +18 -0
  10. package/dist/{chunk-QHMKIODQ.js → chunk-HHNPSKPT.js} +2 -89
  11. package/dist/{chunk-PZPGJZRG.js → chunk-JXATNKLV.js} +5 -5
  12. package/dist/{chunk-PLANHXS7.js → chunk-NX7TFHA4.js} +9 -9
  13. package/dist/{chunk-PNSCDBU7.js → chunk-O37AV27P.js} +6 -49
  14. package/dist/{chunk-5KSAS4VY.js → chunk-RIITGTV3.js} +1 -1
  15. package/dist/chunk-S7QRHUWO.js +8 -0
  16. package/dist/{chunk-7SAAJVDE.js → chunk-T26HAKW3.js} +37 -35
  17. package/dist/chunk-VY3IFGE3.js +70 -0
  18. package/dist/{chunk-VUYCRBJK.js → chunk-WYOFQHKI.js} +6 -4
  19. package/dist/{chunk-Y5QECJX7.js → chunk-YV3YSZEB.js} +5 -5
  20. package/dist/collab/rebase.d.ts.map +1 -1
  21. package/dist/collab/rebase.js +15 -15
  22. package/dist/components/editor/index.js +13 -13
  23. package/dist/components/primitives/index.js +16 -11
  24. package/dist/components/sections/brand-guide.js +13 -8
  25. package/dist/components/sections/register-schemas.js +20 -15
  26. package/dist/components/sections/register.js +20 -15
  27. package/dist/components/shell/EditorShell.d.ts.map +1 -1
  28. package/dist/deck-builder/index.js +9 -9
  29. package/dist/hooks/useEditorPublish.d.ts +4 -1
  30. package/dist/hooks/useEditorPublish.d.ts.map +1 -1
  31. package/dist/hooks/useMediaPipeline.d.ts.map +1 -1
  32. package/dist/index.js +85 -56
  33. package/dist/lib/dexie.d.ts +7 -1
  34. package/dist/lib/dexie.d.ts.map +1 -1
  35. package/dist/lib/dexie.js +3 -2
  36. package/dist/lib/image-variant-plan.d.ts +42 -0
  37. package/dist/lib/image-variant-plan.d.ts.map +1 -0
  38. package/dist/lib/image-variant-plan.js +53 -0
  39. package/dist/lib/index-ops.d.ts.map +1 -1
  40. package/dist/lib/index-ops.js +20 -16
  41. package/dist/lib/index.d.ts +2 -1
  42. package/dist/lib/index.d.ts.map +1 -1
  43. package/dist/lib/index.js +43 -22
  44. package/dist/lib/loader.d.ts +16 -17
  45. package/dist/lib/loader.d.ts.map +1 -1
  46. package/dist/lib/media-ops.d.ts +73 -0
  47. package/dist/lib/media-ops.d.ts.map +1 -0
  48. package/dist/lib/media-ops.js +60 -0
  49. package/dist/lib/nav-tree.d.ts +6 -0
  50. package/dist/lib/nav-tree.d.ts.map +1 -1
  51. package/dist/lib/pages.d.ts +2 -1
  52. package/dist/lib/pages.d.ts.map +1 -1
  53. package/dist/lib/sidecar-diagnostics.d.ts +20 -0
  54. package/dist/lib/sidecar-diagnostics.d.ts.map +1 -0
  55. package/dist/lib/sidecars.d.ts +118 -0
  56. package/dist/lib/sidecars.d.ts.map +1 -0
  57. package/dist/lib/sidecars.js +23 -0
  58. package/dist/lib/slug.d.ts +2 -0
  59. package/dist/lib/slug.d.ts.map +1 -0
  60. package/dist/lib/storage-tier.d.ts +17 -0
  61. package/dist/lib/storage-tier.d.ts.map +1 -0
  62. package/dist/lib/storage-tier.js +29 -0
  63. package/dist/lib/tags.d.ts +6 -0
  64. package/dist/lib/tags.d.ts.map +1 -1
  65. package/dist/media/index.js +15 -15
  66. package/dist/media/queue.d.ts +2 -0
  67. package/dist/media/queue.d.ts.map +1 -1
  68. package/dist/media/worker.d.ts +1 -35
  69. package/dist/media/worker.d.ts.map +1 -1
  70. package/dist/schemas/index.js +18 -12
  71. package/dist/schemas/media.d.ts +4 -0
  72. package/dist/schemas/media.d.ts.map +1 -1
  73. package/dist/storage/index.js +2 -1
  74. package/dist/storage/memory.d.ts +21 -0
  75. package/dist/storage/memory.d.ts.map +1 -0
  76. package/dist/storage/memory.js +129 -0
  77. package/dist/storage/types.d.ts +9 -0
  78. package/dist/storage/types.d.ts.map +1 -1
  79. package/package.json +21 -1
  80. package/src/collab/rebase.ts +12 -16
  81. package/src/components/shell/EditorShell.tsx +7 -4
  82. package/src/hooks/useEditorPublish.ts +9 -4
  83. package/src/hooks/useMediaPipeline.ts +29 -23
  84. package/src/lib/dexie.ts +9 -1
  85. package/src/lib/image-variant-plan.ts +92 -0
  86. package/src/lib/index-ops.ts +9 -18
  87. package/src/lib/index.ts +15 -0
  88. package/src/lib/loader.ts +18 -77
  89. package/src/lib/media-ops.ts +112 -0
  90. package/src/lib/nav-tree.ts +33 -4
  91. package/src/lib/pages.ts +2 -3
  92. package/src/lib/sidecar-diagnostics.ts +29 -0
  93. package/src/lib/sidecars.ts +221 -0
  94. package/src/lib/slug.ts +6 -0
  95. package/src/lib/storage-tier.ts +38 -0
  96. package/src/lib/tags.ts +20 -3
  97. package/src/media/queue.ts +3 -0
  98. package/src/media/utils.ts +1 -1
  99. package/src/media/worker.ts +17 -8
  100. package/src/schemas/media.ts +7 -2
  101. package/src/storage/memory.ts +178 -0
  102. package/src/storage/types.ts +15 -2
  103. /package/dist/{chunk-45FA7Z55.js → chunk-UUUSJDIG.js} +0 -0
@@ -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
  };
@@ -1,7 +1,3 @@
1
- import {
2
- Checkbox,
3
- Tabs
4
- } from "./chunk-JR24U7FJ.js";
5
1
  import {
6
2
  EditableGrid,
7
3
  EditableList,
@@ -9,7 +5,11 @@ import {
9
5
  MediaBlock,
10
6
  containerGridClass,
11
7
  useEditableCollection
12
- } from "./chunk-Y5QECJX7.js";
8
+ } from "./chunk-YV3YSZEB.js";
9
+ import {
10
+ Checkbox,
11
+ Tabs
12
+ } from "./chunk-JR24U7FJ.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";
@@ -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";
4
- import {
5
- usePages
6
- } from "./chunk-5KSAS4VY.js";
3
+ } from "./chunk-YV3YSZEB.js";
7
4
  import {
8
5
  Button
9
6
  } from "./chunk-GGYY3JQJ.js";
7
+ import {
8
+ usePages
9
+ } from "./chunk-RIITGTV3.js";
10
10
  import {
11
11
  toSectionId
12
- } from "./chunk-VUYCRBJK.js";
12
+ } from "./chunk-WYOFQHKI.js";
13
13
  import {
14
14
  ensureSanitizer,
15
15
  isSanitizerReady,
@@ -1,3 +1,10 @@
1
+ import {
2
+ Kbd,
3
+ Tooltip
4
+ } from "./chunk-JCDZAFX2.js";
5
+ import {
6
+ Button
7
+ } from "./chunk-GGYY3JQJ.js";
1
8
  import {
2
9
  Checkbox,
3
10
  Tabs
@@ -10,20 +17,13 @@ import {
10
17
  Select,
11
18
  useMediaLibrary,
12
19
  useResolvedMedia
13
- } from "./chunk-5KSAS4VY.js";
14
- import {
15
- Kbd,
16
- Tooltip
17
- } from "./chunk-JCDZAFX2.js";
18
- import {
19
- Button
20
- } from "./chunk-GGYY3JQJ.js";
20
+ } from "./chunk-RIITGTV3.js";
21
21
  import {
22
22
  IconButton
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";
@@ -7,10 +7,6 @@ import {
7
7
  import {
8
8
  getSectionSchemaForType
9
9
  } from "./chunk-DMCGN5AS.js";
10
- import {
11
- NavEntrySchema,
12
- TagEntrySchema
13
- } from "./chunk-4Y2JQQZL.js";
14
10
  import {
15
11
  getAllSchemas
16
12
  } from "./chunk-FTPETWXE.js";
@@ -111,45 +107,7 @@ function safeRedirect(url, fallback) {
111
107
  }
112
108
 
113
109
  // src/lib/loader.ts
114
- function parseNavFile(navFile) {
115
- if (!navFile) return { entries: [], degraded: false };
116
- const rawEntries = navFile.entries;
117
- if (!Array.isArray(rawEntries)) {
118
- console.warn("[loader] Invalid nav.json, falling back to a flat navigation");
119
- return { entries: [], degraded: true };
120
- }
121
- const entries = [];
122
- let dropped = 0;
123
- for (const raw of rawEntries) {
124
- const result = NavEntrySchema.safeParse(raw);
125
- if (result.success) entries.push(result.data);
126
- else dropped++;
127
- }
128
- if (dropped > 0) {
129
- console.warn(`[loader] nav.json: dropped ${dropped} entr${dropped === 1 ? "y" : "ies"} this package version cannot represent; navigation is degraded`);
130
- }
131
- return { entries, degraded: dropped > 0 };
132
- }
133
- function parseTagsFile(tagsFile) {
134
- if (!tagsFile) return { tags: [], degraded: false };
135
- const rawTags = tagsFile.tags;
136
- if (!Array.isArray(rawTags)) {
137
- console.warn("[loader] Invalid tags.json, falling back to no tags");
138
- return { tags: [], degraded: true };
139
- }
140
- const tags = [];
141
- let dropped = 0;
142
- for (const raw of rawTags) {
143
- const result = TagEntrySchema.safeParse(raw);
144
- if (result.success) tags.push(result.data);
145
- else dropped++;
146
- }
147
- if (dropped > 0) {
148
- console.warn(`[loader] tags.json: dropped ${dropped} entr${dropped === 1 ? "y" : "ies"} this package version cannot represent; tags are degraded`);
149
- }
150
- return { tags, degraded: dropped > 0 };
151
- }
152
- function mergeSiteContent(index, sectionFiles, navFile, tagsSidecar = { loaded: false }) {
110
+ function mergeSiteContent(index, sectionFiles, sidecars = {}) {
153
111
  const sections = [];
154
112
  const canValidate = getAllSchemas().length >= 2;
155
113
  const orderedIds = index.pages.flatMap((p) => p.order);
@@ -180,23 +138,22 @@ function mergeSiteContent(index, sectionFiles, navFile, tagsSidecar = { loaded:
180
138
  sections.push({ section: raw, meta });
181
139
  }
182
140
  }
183
- const nav = parseNavFile(navFile);
184
- const tags = tagsSidecar.loaded ? parseTagsFile(tagsSidecar.file) : null;
141
+ const { nav, tags } = sidecars;
185
142
  return {
186
143
  sections,
187
- index: { ...index, nav: nav.entries, ...tags ? { tags: tags.tags } : {} },
188
- navDegraded: nav.degraded,
144
+ index: { ...index, nav: nav?.entries ?? [], ...tags ? { tags: tags.entries } : {} },
145
+ navDegraded: nav?.degraded ?? false,
189
146
  tagsDegraded: tags?.degraded ?? false
190
147
  };
191
148
  }
192
- function loadStaticSiteContent(index, sectionGlob, navFile, tagsSidecar = { loaded: false }) {
149
+ function loadStaticSiteContent(index, sectionGlob, sidecars = {}) {
193
150
  const sectionFiles = {};
194
151
  for (const [path, data] of Object.entries(sectionGlob)) {
195
152
  const filename = path.split("/").pop();
196
153
  const id = filename.replace(".json", "");
197
154
  sectionFiles[id] = data;
198
155
  }
199
- return mergeSiteContent(index, sectionFiles, navFile, tagsSidecar);
156
+ return mergeSiteContent(index, sectionFiles, sidecars);
200
157
  }
201
158
 
202
159
  export {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getMediaProvider
3
- } from "./chunk-QHMKIODQ.js";
3
+ } from "./chunk-HHNPSKPT.js";
4
4
  import {
5
5
  cn
6
6
  } from "./chunk-7EOSDFS3.js";
@@ -0,0 +1,8 @@
1
+ // src/lib/slug.ts
2
+ function slugifyPageSlug(input) {
3
+ return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
4
+ }
5
+
6
+ export {
7
+ slugifyPageSlug
8
+ };