@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.
- 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-DFKTF3CH.js +0 -0
- package/dist/chunk-DJABADOO.js +131 -0
- package/dist/{chunk-IP2SEBAJ.js → chunk-DJOGPSRU.js} +31 -72
- package/dist/{chunk-N3G7DOU3.js → chunk-FHTKSELX.js} +6 -6
- package/dist/chunk-GNF6KFQ7.js +18 -0
- package/dist/{chunk-QHMKIODQ.js → chunk-HHNPSKPT.js} +2 -89
- package/dist/{chunk-PZPGJZRG.js → chunk-JXATNKLV.js} +5 -5
- package/dist/{chunk-PLANHXS7.js → chunk-NX7TFHA4.js} +9 -9
- 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-7SAAJVDE.js → chunk-T26HAKW3.js} +37 -35
- package/dist/chunk-VY3IFGE3.js +70 -0
- package/dist/{chunk-VUYCRBJK.js → chunk-WYOFQHKI.js} +6 -4
- package/dist/{chunk-Y5QECJX7.js → chunk-YV3YSZEB.js} +5 -5
- package/dist/collab/rebase.d.ts.map +1 -1
- package/dist/collab/rebase.js +15 -15
- package/dist/components/editor/index.js +13 -13
- package/dist/components/primitives/index.js +16 -11
- package/dist/components/sections/brand-guide.js +13 -8
- package/dist/components/sections/register-schemas.js +20 -15
- package/dist/components/sections/register.js +20 -15
- package/dist/components/shell/EditorShell.d.ts.map +1 -1
- package/dist/deck-builder/index.js +9 -9
- 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 +85 -56
- 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/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 +43 -22
- 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/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/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 +21 -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/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/sidecar-diagnostics.ts +29 -0
- package/src/lib/sidecars.ts +221 -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
|
@@ -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
|
};
|
|
@@ -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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
|
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 =
|
|
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
|
|
188
|
-
navDegraded: nav
|
|
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,
|
|
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,
|
|
156
|
+
return mergeSiteContent(index, sectionFiles, sidecars);
|
|
200
157
|
}
|
|
201
158
|
|
|
202
159
|
export {
|