@drawnagency/primitives 0.1.109 → 0.1.111
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/auth/cookies.d.ts +8 -0
- package/dist/auth/cookies.d.ts.map +1 -1
- package/dist/auth/index.d.ts +1 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +3 -1
- package/dist/auth/types.d.ts +11 -4
- package/dist/auth/types.d.ts.map +1 -1
- package/dist/{chunk-WXBHP4JY.js → chunk-3GAG6ZXB.js} +55 -46
- package/dist/{chunk-FM4M4Q2W.js → chunk-4TZJZU2T.js} +23 -3
- package/dist/{chunk-5PVRACZY.js → chunk-7MI3HCOF.js} +60 -23
- package/dist/{chunk-WBDPDGFA.js → chunk-7WQJ57XG.js} +6 -31
- package/dist/{chunk-LQHYVPBS.js → chunk-ALMEC3XN.js} +11 -12
- package/dist/{chunk-TZQPOR5A.js → chunk-DMCGN5AS.js} +10 -3
- package/dist/{chunk-ZKVKNUJC.js → chunk-ELQ4C677.js} +1 -1
- package/dist/{chunk-5BM2Y3NJ.js → chunk-FRVO75DK.js} +14 -2
- package/dist/{chunk-VKAGMEKE.js → chunk-FTPETWXE.js} +1 -0
- package/dist/{chunk-3TO4RRHY.js → chunk-GPPVYLEI.js} +7 -0
- package/dist/{chunk-NLQ5F3RQ.js → chunk-HBULBDGP.js} +1 -1
- package/dist/{chunk-67ZOQCUD.js → chunk-NXGIHSL5.js} +67 -50
- package/dist/{chunk-CPTFFLK2.js → chunk-OTDA6KWL.js} +10 -3
- package/dist/{chunk-XIDE4TDF.js → chunk-OUYB2GCW.js} +1 -1
- package/dist/{chunk-72CG6AA2.js → chunk-RA5IOFPY.js} +10 -2
- package/dist/{chunk-GEENI3OC.js → chunk-SW6PCQQD.js} +4 -0
- package/dist/{chunk-BOZUEKWL.js → chunk-UVIYI4J6.js} +1 -1
- package/dist/{chunk-AB3XVXI3.js → chunk-VCCNKTFD.js} +37 -29
- package/dist/{chunk-XBYJQ5RS.js → chunk-XQMDWXD6.js} +21 -6
- package/dist/collab/rebase.d.ts +6 -0
- package/dist/collab/rebase.d.ts.map +1 -1
- package/dist/collab/rebase.js +12 -3
- package/dist/collab/recovery.d.ts +0 -20
- package/dist/collab/recovery.d.ts.map +1 -1
- package/dist/components/brandguide/ColorSwatchSettings.d.ts.map +1 -1
- package/dist/components/brandguide/ColorsView.d.ts.map +1 -1
- package/dist/components/brandguide/colors-shared.d.ts +10 -1
- package/dist/components/brandguide/colors-shared.d.ts.map +1 -1
- package/dist/components/chat/ChatPanel.d.ts.map +1 -1
- package/dist/components/docfile/DocFilePane.d.ts.map +1 -1
- package/dist/components/docfile/PdfCanvasViewer.d.ts.map +1 -1
- package/dist/components/docfile/doc-file-state.d.ts.map +1 -1
- package/dist/components/editor/IndicatorPill.d.ts.map +1 -1
- package/dist/components/editor/NavGroupRow.d.ts +7 -2
- package/dist/components/editor/NavGroupRow.d.ts.map +1 -1
- package/dist/components/editor/PagesModal.d.ts.map +1 -1
- package/dist/components/editor/index.js +13 -12
- package/dist/components/primitives/EditableRichText.d.ts.map +1 -1
- package/dist/components/primitives/LinkPopover.d.ts.map +1 -1
- package/dist/components/primitives/index.js +14 -12
- package/dist/components/primitives/useEditableCollection.d.ts.map +1 -1
- package/dist/components/primitives/useEditablePlainText.d.ts.map +1 -1
- package/dist/components/sections/IconList/index.d.ts.map +1 -1
- package/dist/components/sections/Prose/Prose.d.ts.map +1 -1
- package/dist/components/sections/brand-guide.js +8 -8
- package/dist/components/sections/register-schemas.js +14 -14
- package/dist/components/sections/register.js +14 -14
- package/dist/components/shared/FontPicker.d.ts.map +1 -1
- package/dist/components/shared/HistoryChangesModal.d.ts.map +1 -1
- package/dist/components/shared/HistoryPopover.d.ts.map +1 -1
- package/dist/components/shared/Navigation.d.ts.map +1 -1
- package/dist/components/shared/Popover.d.ts.map +1 -1
- package/dist/components/shell/AudienceAddForm.d.ts +1 -5
- package/dist/components/shell/AudienceAddForm.d.ts.map +1 -1
- package/dist/components/shell/AudienceRow.d.ts +2 -3
- package/dist/components/shell/AudienceRow.d.ts.map +1 -1
- package/dist/components/shell/BugReportFAB.d.ts.map +1 -1
- package/dist/components/shell/EditorShell.d.ts.map +1 -1
- package/dist/components/shell/MediaLibraryModal.d.ts.map +1 -1
- package/dist/components/shell/SiteSettingsUsers.d.ts.map +1 -1
- package/dist/components/shell/SiteSettingsViewerAccess.d.ts.map +1 -1
- package/dist/components/shell/view-branch.d.ts.map +1 -1
- package/dist/document/components/DocRail.d.ts.map +1 -1
- package/dist/document/components/DocViewer.d.ts.map +1 -1
- package/dist/document/components/measure.d.ts.map +1 -1
- package/dist/document/components/useDocPages.d.ts.map +1 -1
- package/dist/document/engine/blocks.d.ts.map +1 -1
- package/dist/document/engine/masonry.d.ts.map +1 -1
- package/dist/document/engine/paginate.d.ts.map +1 -1
- package/dist/document/engine/settings.d.ts +3 -0
- package/dist/document/engine/settings.d.ts.map +1 -1
- package/dist/document/index.js +79 -28
- package/dist/hooks/useBuildStatus.d.ts.map +1 -1
- package/dist/hooks/useDocumentUploads.d.ts +1 -0
- package/dist/hooks/useDocumentUploads.d.ts.map +1 -1
- package/dist/hooks/useEditorPersistence.d.ts.map +1 -1
- package/dist/hooks/useEditorPublish.d.ts.map +1 -1
- package/dist/hooks/useFocusTrap.d.ts +6 -0
- package/dist/hooks/useFocusTrap.d.ts.map +1 -1
- package/dist/hooks/useMediaPipeline.d.ts +3 -2
- package/dist/hooks/useMediaPipeline.d.ts.map +1 -1
- package/dist/hooks/useSanitizedHtml.d.ts +12 -0
- package/dist/hooks/useSanitizedHtml.d.ts.map +1 -0
- package/dist/index.js +19 -13
- package/dist/lib/block-move.d.ts.map +1 -1
- package/dist/lib/contrast.d.ts.map +1 -1
- package/dist/lib/dexie.d.ts +2 -8
- package/dist/lib/dexie.d.ts.map +1 -1
- package/dist/lib/dexie.js +21 -49
- package/dist/lib/index-ops.d.ts.map +1 -1
- package/dist/lib/index-ops.js +43 -23
- package/dist/lib/index.js +8 -8
- package/dist/lib/loader.d.ts.map +1 -1
- package/dist/lib/media-folders.d.ts +12 -4
- package/dist/lib/media-folders.d.ts.map +1 -1
- package/dist/lib/media-folders.js +12 -2
- package/dist/lib/migrate-sections-transform.js +1 -1
- package/dist/lib/nav-progress.d.ts +14 -0
- package/dist/lib/nav-progress.d.ts.map +1 -0
- package/dist/lib/nav-tree.d.ts.map +1 -1
- package/dist/lib/nav.d.ts.map +1 -1
- package/dist/lib/pages.d.ts.map +1 -1
- package/dist/lib/registry.d.ts.map +1 -1
- package/dist/lib/registry.js +1 -1
- package/dist/lib/sanitize.d.ts +6 -0
- package/dist/lib/sanitize.d.ts.map +1 -1
- package/dist/lib/timestamp.d.ts.map +1 -1
- package/dist/media/index.js +4 -4
- package/dist/media/queue.d.ts.map +1 -1
- package/dist/media/resolve.d.ts.map +1 -1
- package/dist/media/utils.d.ts.map +1 -1
- package/dist/media/videoPoster.d.ts.map +1 -1
- package/dist/schemas/audience.d.ts +5 -1
- package/dist/schemas/audience.d.ts.map +1 -1
- package/dist/schemas/audience.js +1 -1
- package/dist/schemas/index.js +8 -6
- package/dist/schemas/sections.d.ts +12 -0
- package/dist/schemas/sections.d.ts.map +1 -1
- package/dist/storage/index.d.ts +1 -1
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +3 -1
- package/dist/storage/types.d.ts +9 -0
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/types/database.d.ts +0 -3
- package/dist/types/database.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/auth/cookies.ts +11 -0
- package/src/auth/index.ts +1 -1
- package/src/auth/types.ts +18 -4
- package/src/collab/rebase.ts +26 -1
- package/src/collab/recovery.ts +29 -3
- package/src/components/brandguide/ColorSwatchSettings.tsx +40 -13
- package/src/components/brandguide/ColorsEditable.tsx +7 -9
- package/src/components/brandguide/ColorsView.tsx +12 -11
- package/src/components/brandguide/colors-shared.ts +17 -1
- package/src/components/chat/ChatPanel.tsx +19 -0
- package/src/components/docfile/DocFilePane.tsx +11 -0
- package/src/components/docfile/PdfCanvasViewer.tsx +46 -5
- package/src/components/docfile/doc-file-state.ts +7 -0
- package/src/components/editor/IndicatorPill.tsx +5 -1
- package/src/components/editor/NavGroupRow.tsx +8 -3
- package/src/components/editor/PagesModal.tsx +10 -2
- package/src/components/primitives/EditableList.tsx +10 -2
- package/src/components/primitives/EditableRichText.tsx +4 -3
- package/src/components/primitives/LinkPopover.tsx +23 -1
- package/src/components/primitives/useEditableCollection.ts +61 -41
- package/src/components/primitives/useEditablePlainText.ts +24 -3
- package/src/components/sections/IconList/index.tsx +8 -1
- package/src/components/sections/Prose/Prose.tsx +4 -2
- package/src/components/shared/FontPicker.tsx +16 -4
- package/src/components/shared/HistoryChangesModal.tsx +12 -1
- package/src/components/shared/HistoryPopover.tsx +18 -4
- package/src/components/shared/Navigation.tsx +20 -2
- package/src/components/shared/Popover.tsx +9 -5
- package/src/components/shell/AudienceAddForm.tsx +6 -26
- package/src/components/shell/AudienceRow.tsx +29 -39
- package/src/components/shell/BugReportFAB.tsx +20 -2
- package/src/components/shell/EditorShell.tsx +200 -50
- package/src/components/shell/MediaLibraryModal.tsx +52 -10
- package/src/components/shell/SiteSettingsUsers.tsx +3 -0
- package/src/components/shell/SiteSettingsViewerAccess.tsx +21 -16
- package/src/components/shell/view-branch.ts +4 -1
- package/src/document/components/DocRail.tsx +27 -2
- package/src/document/components/DocViewer.tsx +5 -1
- package/src/document/components/measure.tsx +22 -6
- package/src/document/components/useDocPages.ts +13 -3
- package/src/document/engine/blocks.ts +33 -4
- package/src/document/engine/masonry.ts +8 -2
- package/src/document/engine/paginate.ts +4 -1
- package/src/document/engine/settings.ts +40 -3
- package/src/hooks/useBuildStatus.ts +6 -0
- package/src/hooks/useDocumentUploads.ts +46 -3
- package/src/hooks/useEditorPersistence.ts +33 -19
- package/src/hooks/useEditorPublish.ts +83 -34
- package/src/hooks/useFocusTrap.ts +18 -0
- package/src/hooks/useMediaPipeline.ts +111 -38
- package/src/hooks/useSanitizedHtml.ts +29 -0
- package/src/lib/audience-secret.ts +1 -0
- package/src/lib/block-move.ts +13 -2
- package/src/lib/contrast.ts +14 -14
- package/src/lib/dexie.ts +46 -49
- package/src/lib/index-ops.ts +63 -20
- package/src/lib/loader.ts +41 -12
- package/src/lib/media-folders.ts +31 -5
- package/src/lib/migrate-sections-transform.ts +22 -2
- package/src/lib/nav-progress.ts +108 -0
- package/src/lib/nav-tree.ts +16 -2
- package/src/lib/nav.ts +10 -1
- package/src/lib/pages.ts +24 -6
- package/src/lib/registry.ts +3 -0
- package/src/lib/sanitize.ts +9 -0
- package/src/lib/timestamp.ts +5 -0
- package/src/media/queue.ts +4 -0
- package/src/media/resolve.ts +14 -1
- package/src/media/utils.ts +3 -1
- package/src/media/videoPoster.ts +14 -3
- package/src/schemas/audience.ts +10 -2
- package/src/schemas/sections.ts +23 -1
- package/src/storage/index.ts +1 -1
- package/src/storage/types.ts +13 -0
- package/src/types/database.ts +0 -3
package/src/lib/pages.ts
CHANGED
|
@@ -71,8 +71,14 @@ export function setHomePage(index: SiteIndex, pageId: string): SiteIndex {
|
|
|
71
71
|
const current = homePage(index);
|
|
72
72
|
if (current.id === pageId) return index;
|
|
73
73
|
if (!pageById(index, pageId)) return index;
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
// Neither side of the swap counts against the other: the promoted page's slug
|
|
75
|
+
// is about to become "" and the demoted one's is about to be replaced, so
|
|
76
|
+
// leaving them in gave the demoted page a "-2" suffix it did not need.
|
|
77
|
+
const takenSlugs = index.pages
|
|
78
|
+
.filter((p) => p.id !== pageId && p.id !== current.id)
|
|
79
|
+
.map((p) => p.slug)
|
|
80
|
+
.filter((s) => s !== "");
|
|
81
|
+
const demotedSlug = uniquePageSlug(slugifyPageSlug(current.title) || "home", takenSlugs);
|
|
76
82
|
return mapPages(index, (p) => {
|
|
77
83
|
if (p.id === pageId) return { ...p, isHome: true, slug: "" };
|
|
78
84
|
if (p.id === current.id) return { ...p, isHome: false, slug: demotedSlug };
|
|
@@ -167,10 +173,15 @@ export function addSectionToPage(
|
|
|
167
173
|
meta: SectionMeta,
|
|
168
174
|
insertIndex: number,
|
|
169
175
|
): SiteIndex {
|
|
176
|
+
// Strip any existing occurrence first. page.order and sections{} must
|
|
177
|
+
// partition exactly, and re-adding an id that already sits in some page's
|
|
178
|
+
// order produced a duplicate that IndexSchema rejects at save time — far from
|
|
179
|
+
// the call that caused it.
|
|
170
180
|
const pages = index.pages.map((p) => {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
order
|
|
181
|
+
const without = p.order.includes(sectionId) ? p.order.filter((id) => id !== sectionId) : p.order;
|
|
182
|
+
if (p.id !== pageId) return without === p.order ? p : { ...p, order: without };
|
|
183
|
+
const order = [...without];
|
|
184
|
+
order.splice(Math.min(insertIndex, order.length), 0, sectionId);
|
|
174
185
|
return { ...p, order };
|
|
175
186
|
});
|
|
176
187
|
return { ...index, pages, sections: { ...index.sections, [sectionId]: meta } };
|
|
@@ -239,6 +250,7 @@ export function reorderVisibleSectionInPage(
|
|
|
239
250
|
const fromId = visibleIds[fromIndex];
|
|
240
251
|
if (fromId === undefined) return index;
|
|
241
252
|
const withoutFrom = visibleIds.filter((id) => id !== fromId);
|
|
253
|
+
let changed = false;
|
|
242
254
|
const pages = index.pages.map((p) => {
|
|
243
255
|
if (p.id !== pageId) return p;
|
|
244
256
|
const fromPos = p.order.indexOf(fromId);
|
|
@@ -246,9 +258,15 @@ export function reorderVisibleSectionInPage(
|
|
|
246
258
|
const order = [...p.order];
|
|
247
259
|
order.splice(fromPos, 1);
|
|
248
260
|
order.splice(visibleInsertPosition(order, withoutFrom, toIndex), 0, fromId);
|
|
261
|
+
// A drop back onto the section's own slot resolves to the position it
|
|
262
|
+
// already held. Handing back a fresh object anyway defeated the caller's
|
|
263
|
+
// reference-based no-op check (applyBlockMove), so an inert drop armed a
|
|
264
|
+
// dirty index and a save.
|
|
265
|
+
if (order.length === p.order.length && order.every((id, i) => id === p.order[i])) return p;
|
|
266
|
+
changed = true;
|
|
249
267
|
return { ...p, order };
|
|
250
268
|
});
|
|
251
|
-
return { ...index, pages };
|
|
269
|
+
return changed ? { ...index, pages } : index;
|
|
252
270
|
}
|
|
253
271
|
|
|
254
272
|
export function moveSection(
|
package/src/lib/registry.ts
CHANGED
|
@@ -260,7 +260,10 @@ export function createRegistry(): SectionRegistry {
|
|
|
260
260
|
return {
|
|
261
261
|
registerSection(def) {
|
|
262
262
|
sections.set(def.type, def);
|
|
263
|
+
// Clear on re-registration without the field: a stale entry would keep
|
|
264
|
+
// telling the server-side sanitizer to treat a plain field as rich text.
|
|
263
265
|
if (def.richTextFields) richText.set(def.type, def.richTextFields);
|
|
266
|
+
else richText.delete(def.type);
|
|
264
267
|
},
|
|
265
268
|
registerSchema(type, schema) {
|
|
266
269
|
schemas.set(type, schema);
|
package/src/lib/sanitize.ts
CHANGED
|
@@ -40,6 +40,15 @@ export function sanitizeHtml(html: string): string {
|
|
|
40
40
|
return clean;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
/**
|
|
44
|
+
* True when `sanitizeHtml` will actually sanitize. On the server DOMPurify never
|
|
45
|
+
* loads and never will, so callers there are on their own (core's sanitize-server
|
|
46
|
+
* covers the SSR viewer path); this reports ready so SSR output is unchanged.
|
|
47
|
+
*/
|
|
48
|
+
export function isSanitizerReady(): boolean {
|
|
49
|
+
return typeof window === "undefined" || purifier !== null;
|
|
50
|
+
}
|
|
51
|
+
|
|
43
52
|
/**
|
|
44
53
|
* Await this during component mount (e.g. useEffect) to guarantee
|
|
45
54
|
* DOMPurify is loaded before `sanitizeHtml` is called.
|
package/src/lib/timestamp.ts
CHANGED
|
@@ -12,15 +12,20 @@ export function formatDate(iso: string): string {
|
|
|
12
12
|
|
|
13
13
|
export function formatDateTime(iso: string): string {
|
|
14
14
|
const date = new Date(iso);
|
|
15
|
+
// UTC-pinned like its two siblings: without it the server (UTC) and the client
|
|
16
|
+
// (local) render different values for the same timestamp, which is a hydration
|
|
17
|
+
// mismatch wherever this reaches SSR output.
|
|
15
18
|
const datePart = date.toLocaleDateString("en-US", {
|
|
16
19
|
month: "short",
|
|
17
20
|
day: "numeric",
|
|
18
21
|
year: "numeric",
|
|
22
|
+
timeZone: "UTC",
|
|
19
23
|
});
|
|
20
24
|
const timePart = date.toLocaleTimeString("en-US", {
|
|
21
25
|
hour: "numeric",
|
|
22
26
|
minute: "2-digit",
|
|
23
27
|
hour12: true,
|
|
28
|
+
timeZone: "UTC",
|
|
24
29
|
});
|
|
25
30
|
return `${datePart} | ${timePart}`;
|
|
26
31
|
}
|
package/src/media/queue.ts
CHANGED
|
@@ -118,6 +118,10 @@ export class ProcessingQueue {
|
|
|
118
118
|
height: msg.height,
|
|
119
119
|
};
|
|
120
120
|
this.options.onEvent({ type: "complete", item: { ...item } });
|
|
121
|
+
// The event above carries the only reference anyone reads. Holding ours
|
|
122
|
+
// pinned every variant Blob of every completed upload — the full decoded
|
|
123
|
+
// output of the whole session — for the queue's lifetime.
|
|
124
|
+
delete item.result;
|
|
121
125
|
this.cleanupWorker(id, worker);
|
|
122
126
|
this.processNext();
|
|
123
127
|
} else if (msg.type === "error") {
|
package/src/media/resolve.ts
CHANGED
|
@@ -37,6 +37,19 @@ export function resolveManifestReferences(
|
|
|
37
37
|
if (typeof obj.imageId === "string") {
|
|
38
38
|
const manifestItem = manifest.images[obj.imageId];
|
|
39
39
|
const resolved = resolveMedia({ imageId: obj.imageId }, manifest, sizes, provider);
|
|
40
|
+
// Recurse into this object's own values first. Returning straight from
|
|
41
|
+
// here left any ref nested INSIDE a ref-carrying object unresolved.
|
|
42
|
+
const base: Record<string, unknown> = {};
|
|
43
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
44
|
+
base[key] = resolveManifestReferences(value, manifest, sizes, provider);
|
|
45
|
+
}
|
|
46
|
+
if (!resolved) {
|
|
47
|
+
// The item is gone from the manifest. Drop the baked fields instead of
|
|
48
|
+
// leaving the previous item's `src` pointing at an asset that no longer
|
|
49
|
+
// exists — a deleted image kept rendering until someone hit the 404.
|
|
50
|
+
for (const key of BAKED_MEDIA_KEYS) delete base[key];
|
|
51
|
+
return { ...base, alt: manifestItem?.alt ?? "" };
|
|
52
|
+
}
|
|
40
53
|
const patch: Record<string, unknown> = {
|
|
41
54
|
alt: manifestItem?.alt ?? "",
|
|
42
55
|
};
|
|
@@ -55,7 +68,7 @@ export function resolveManifestReferences(
|
|
|
55
68
|
patch.width = resolved.width;
|
|
56
69
|
patch.height = resolved.height;
|
|
57
70
|
}
|
|
58
|
-
return { ...
|
|
71
|
+
return { ...base, ...patch };
|
|
59
72
|
}
|
|
60
73
|
|
|
61
74
|
// Recurse into all values
|
package/src/media/utils.ts
CHANGED
|
@@ -57,7 +57,9 @@ export function displayFilename(originalName: string, mimeType: string): string
|
|
|
57
57
|
const ext = MIME_TO_EXT[mimeType];
|
|
58
58
|
if (!ext) return originalName;
|
|
59
59
|
const suffix = `.${ext}`;
|
|
60
|
-
|
|
60
|
+
// Case-insensitively: extensions come off the user's filesystem, so a
|
|
61
|
+
// case-sensitive check rendered "Logo.PNG" as "Logo.PNG.png".
|
|
62
|
+
if (originalName.toLowerCase().endsWith(suffix)) return originalName;
|
|
61
63
|
return `${originalName}${suffix}`;
|
|
62
64
|
}
|
|
63
65
|
|
package/src/media/videoPoster.ts
CHANGED
|
@@ -34,7 +34,7 @@ export function generateVideoPoster(
|
|
|
34
34
|
video.src = url;
|
|
35
35
|
|
|
36
36
|
video.addEventListener("loadeddata", () => {
|
|
37
|
-
|
|
37
|
+
const capture = () => {
|
|
38
38
|
if (settled) return;
|
|
39
39
|
try {
|
|
40
40
|
const w = video.videoWidth;
|
|
@@ -67,8 +67,19 @@ export function generateVideoPoster(
|
|
|
67
67
|
} catch (err) {
|
|
68
68
|
safeReject(err instanceof Error ? err : new Error(String(err)));
|
|
69
69
|
}
|
|
70
|
-
}
|
|
71
|
-
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const target = isFinite(video.duration) ? Math.min(0.1, video.duration / 2) : 0;
|
|
73
|
+
// Assigning currentTime a value it ALREADY holds fires no `seeked` — the
|
|
74
|
+
// common case for a 0-duration or already-at-0 decode. Waiting for the
|
|
75
|
+
// event then stalled the full 10s timeout, and the rejection that followed
|
|
76
|
+
// is what produced a 0x0 media item.
|
|
77
|
+
if (video.currentTime === target) {
|
|
78
|
+
capture();
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
video.addEventListener("seeked", capture, { once: true });
|
|
82
|
+
video.currentTime = target;
|
|
72
83
|
}, { once: true });
|
|
73
84
|
});
|
|
74
85
|
}
|
package/src/schemas/audience.ts
CHANGED
|
@@ -70,11 +70,19 @@ export type ViewerCredential = z.infer<typeof ViewerCredentialSchema>;
|
|
|
70
70
|
/**
|
|
71
71
|
* Convert a friendly display string into an audience slug.
|
|
72
72
|
* Lowercases, replaces non-alphanumeric runs with single dashes,
|
|
73
|
-
* strips leading/trailing dashes
|
|
73
|
+
* strips leading/trailing dashes, truncates to the schema's 32-char max.
|
|
74
|
+
* Result must pass AudienceNameSchema.
|
|
75
|
+
*
|
|
76
|
+
* Kept byte-for-byte equivalent to @drawnagency/platform's copy
|
|
77
|
+
* (src/slugify.ts) — change both together.
|
|
74
78
|
*/
|
|
75
79
|
export function slugifyAudienceName(input: string): string {
|
|
76
80
|
return input
|
|
77
81
|
.toLowerCase()
|
|
78
82
|
.replace(/[^a-z0-9]+/g, "-")
|
|
79
|
-
.replace(/^-+|-+$/g, "")
|
|
83
|
+
.replace(/^-+|-+$/g, "")
|
|
84
|
+
// Trim the trailing separator again: slicing can land mid-word and leave
|
|
85
|
+
// one, which AudienceNameSchema forbids as a final character.
|
|
86
|
+
.slice(0, 32)
|
|
87
|
+
.replace(/-+$/g, "");
|
|
80
88
|
}
|
package/src/schemas/sections.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { getAllSchemas } from "../lib/registry";
|
|
2
|
+
import { getAllSchemas, getSchema } from "../lib/registry";
|
|
3
3
|
import { LayoutEnvelopeSchema, type LayoutEnvelope } from "./block";
|
|
4
4
|
|
|
5
5
|
export interface SectionContent<C = Record<string, unknown>> {
|
|
@@ -26,3 +26,25 @@ export function getSectionSchema(): z.ZodType<Section> {
|
|
|
26
26
|
.object({ id: z.string(), layout: LayoutEnvelopeSchema.optional() })
|
|
27
27
|
.and(getSectionContentSchema()) as z.ZodType<Section>;
|
|
28
28
|
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The single-type equivalent of `getSectionSchema()`, for callers that already
|
|
32
|
+
* know a section's `type`. Returns null for an unregistered type — the same
|
|
33
|
+
* outcome the union produces, since no member would match.
|
|
34
|
+
*
|
|
35
|
+
* Prefer this in loops. The union in `getSectionContentSchema()` validates its
|
|
36
|
+
* members in order and fully validates every miss, so parsing N sections
|
|
37
|
+
* against M registered types costs O(N x M) object validations; every section
|
|
38
|
+
* schema pins `type: z.literal(...)`, so a registry lookup selects exactly the
|
|
39
|
+
* member the union would have matched.
|
|
40
|
+
*/
|
|
41
|
+
export function getSectionSchemaForType(type: string): z.ZodType<Section> | null {
|
|
42
|
+
const schema = getSchema(type);
|
|
43
|
+
if (!schema) return null;
|
|
44
|
+
// `getSchema` is typed as a bare ZodType, so the intersection doesn't overlap
|
|
45
|
+
// Section structurally — same widening `getSectionSchema` gets for free from
|
|
46
|
+
// getSectionContentSchema's annotated return.
|
|
47
|
+
return z
|
|
48
|
+
.object({ id: z.string(), layout: LayoutEnvelopeSchema.optional() })
|
|
49
|
+
.and(schema) as unknown as z.ZodType<Section>;
|
|
50
|
+
}
|
package/src/storage/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export type { StorageProvider, FileWrite, AssetStore, DocumentStore } from "./types";
|
|
2
|
-
export { StorageConflictError, IdempotencyLookupUnavailableError, ASSET_CACHE_CONTROL, DOCUMENT_CACHE_CONTROL, IDEMPOTENCY_TRAILER, IDEMPOTENCY_KEY_RE, withIdempotencyTrailer } from "./types";
|
|
2
|
+
export { StorageConflictError, NothingToPublishError, IdempotencyLookupUnavailableError, ASSET_CACHE_CONTROL, DOCUMENT_CACHE_CONTROL, IDEMPOTENCY_TRAILER, IDEMPOTENCY_KEY_RE, withIdempotencyTrailer } from "./types";
|
package/src/storage/types.ts
CHANGED
|
@@ -11,6 +11,19 @@ export class StorageConflictError extends Error {
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Thrown by `promoteDraft` when there is no draft to publish. Typed rather than
|
|
16
|
+
* a bare Error because it is the ordinary outcome of publishing twice, and a
|
|
17
|
+
* caller that cannot tell it apart from a real failure reports "publish failed"
|
|
18
|
+
* for a site that is already fully published.
|
|
19
|
+
*/
|
|
20
|
+
export class NothingToPublishError extends Error {
|
|
21
|
+
constructor() {
|
|
22
|
+
super("No saved branch to publish");
|
|
23
|
+
this.name = "NothingToPublishError";
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
14
27
|
export interface StorageProvider {
|
|
15
28
|
writeFiles(
|
|
16
29
|
files: FileWrite[],
|
package/src/types/database.ts
CHANGED
|
@@ -674,7 +674,6 @@ export type Database = {
|
|
|
674
674
|
id: string
|
|
675
675
|
is_default: boolean
|
|
676
676
|
name: string
|
|
677
|
-
password_hash: string
|
|
678
677
|
site_id: string
|
|
679
678
|
}
|
|
680
679
|
Insert: {
|
|
@@ -684,7 +683,6 @@ export type Database = {
|
|
|
684
683
|
id?: string
|
|
685
684
|
is_default?: boolean
|
|
686
685
|
name: string
|
|
687
|
-
password_hash: string
|
|
688
686
|
site_id: string
|
|
689
687
|
}
|
|
690
688
|
Update: {
|
|
@@ -694,7 +692,6 @@ export type Database = {
|
|
|
694
692
|
id?: string
|
|
695
693
|
is_default?: boolean
|
|
696
694
|
name?: string
|
|
697
|
-
password_hash?: string
|
|
698
695
|
site_id?: string
|
|
699
696
|
}
|
|
700
697
|
Relationships: [
|