@bendyline/squisq 2.11.16 → 2.11.18

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 (37) hide show
  1. package/dist/{Doc-Bd2kdzuy.d.ts → Doc-B6TYHYGc.d.ts} +41 -2
  2. package/dist/{ImageEditDoc-C3HOltpW.d.ts → ImageEditDoc-CN_3Ysj5.d.ts} +1 -1
  3. package/dist/chunk-3XEABCT3.js +114 -0
  4. package/dist/{chunk-WMXQDP2C.js → chunk-7IGKCHDP.js} +352 -17
  5. package/dist/{chunk-C3NAY5YP.js → chunk-A5QJJZ5S.js} +8 -5
  6. package/dist/{chunk-HVJ6VFDX.js → chunk-GB7OFYUK.js} +4 -0
  7. package/dist/{chunk-NC6LD6D3.js → chunk-J4ACZBO4.js} +50 -8
  8. package/dist/{chunk-ANH2OZ2M.js → chunk-LJZHC6GN.js} +146 -11
  9. package/dist/{chunk-IFJPPI63.js → chunk-NM747LUO.js} +829 -298
  10. package/dist/{chunk-GDHXT5Q7.js → chunk-PGWYC3S2.js} +2 -2
  11. package/dist/{chunk-X7BNDUNI.js → chunk-Q6ELOAOQ.js} +383 -1
  12. package/dist/{chunk-IRVXZUVU.js → chunk-RYO4QW6R.js} +2 -4
  13. package/dist/{chunk-TMOHAFYE.js → chunk-WSFXV5BT.js} +17 -0
  14. package/dist/doc/index.d.ts +35 -24
  15. package/dist/doc/index.js +13 -7
  16. package/dist/fence/index.d.ts +1 -1
  17. package/dist/generate/index.d.ts +1 -1
  18. package/dist/imageEdit/index.d.ts +3 -3
  19. package/dist/index.d.ts +7 -7
  20. package/dist/index.js +88 -34
  21. package/dist/jsonForm/index.d.ts +1 -1
  22. package/dist/jsonForm/index.js +1 -1
  23. package/dist/markdown/index.d.ts +170 -4
  24. package/dist/markdown/index.js +24 -4
  25. package/dist/{materializePageSection-FRv9whYy.d.ts → materializePageSection-IYXU3tDN.d.ts} +6 -1
  26. package/dist/mediaEdit/index.d.ts +2 -2
  27. package/dist/narration/index.d.ts +1 -1
  28. package/dist/narration/index.js +10 -9
  29. package/dist/recommend/index.js +2 -2
  30. package/dist/schemas/index.d.ts +4 -4
  31. package/dist/schemas/index.js +1 -1
  32. package/dist/{themeLibrary-BbF3EKWM.d.ts → themeLibrary-_46saKYO.d.ts} +1 -1
  33. package/dist/timing/index.d.ts +1 -1
  34. package/dist/transform/index.d.ts +84 -4
  35. package/dist/transform/index.js +38 -8
  36. package/package.json +1 -1
  37. package/dist/chunk-5W7F46OO.js +0 -337
@@ -703,6 +703,8 @@ interface AccentImage {
703
703
  * Base properties shared by all template blocks.
704
704
  */
705
705
  interface BaseTemplateBlock {
706
+ /** Compiled presentation timing is authoritative; pacing must not merge or split it. */
707
+ timelineLocked?: boolean;
706
708
  /** Unique block ID */
707
709
  id: string;
708
710
  /** Block duration in seconds */
@@ -1310,6 +1312,8 @@ interface DiagramTemplateEdge {
1310
1312
  */
1311
1313
  interface DiagramBlockInput extends BaseTemplateBlock {
1312
1314
  template: 'diagram';
1315
+ /** Paint an opaque themed surface for standalone slides; omitted stays transparent. */
1316
+ background?: 'surface';
1313
1317
  /** Optional diagram title displayed above the canvas. */
1314
1318
  title?: string;
1315
1319
  /** Color scheme for nodes and edges. */
@@ -2330,6 +2334,16 @@ interface DocDiagnostic {
2330
2334
  * A complete visual doc for an article.
2331
2335
  */
2332
2336
  interface Doc {
2337
+ /** Projection-only source/timing metadata from the document narration take. */
2338
+ presentationNarration?: {
2339
+ sourceText: string;
2340
+ src: string;
2341
+ startTime: number;
2342
+ duration: number;
2343
+ bookmarks: AudioBookmark[];
2344
+ };
2345
+ /** Projection-only guard: never compile an accepted plan twice. */
2346
+ presentationApplied?: boolean;
2333
2347
  /** Article ID this doc belongs to */
2334
2348
  articleId: string;
2335
2349
  /** Total duration in seconds (sum of all audio segments) */
@@ -2620,7 +2634,7 @@ interface Block {
2620
2634
  * A visual element within a block.
2621
2635
  * Layers are composited back-to-front (first layer is background).
2622
2636
  */
2623
- type Layer = ImageLayer | TextLayer | ShapeLayer | PathLayer | MapLayer | VideoLayer | TableLayer | TreeLayer | MermaidLayer;
2637
+ type Layer = ImageLayer | TextLayer | ShapeLayer | PathLayer | MapLayer | VideoLayer | VideoEmbedLayer | TableLayer | TreeLayer | MermaidLayer;
2624
2638
  interface BaseLayer {
2625
2639
  /** Unique identifier for this layer */
2626
2640
  id: string;
@@ -2885,6 +2899,31 @@ interface VideoLayer extends BaseLayer {
2885
2899
  license?: string;
2886
2900
  };
2887
2901
  }
2902
+ /**
2903
+ * Hosted video layer — the YouTube / Vimeo / Loom / Dailymotion / Wistia
2904
+ * player for a paragraph that is only a link to the video's page.
2905
+ *
2906
+ * Carries the page URL, never a player URL: renderers re-derive the iframe
2907
+ * `src` with `parseVideoEmbedUrl` (`@bendyline/squisq/markdown`), so an
2908
+ * authored layer cannot smuggle in an arbitrary frame, and a URL that is not a
2909
+ * supported video renders nothing. The player keeps the video's aspect ratio
2910
+ * (16:9, or 9:16 for Shorts), letterboxed within the layer's bounds.
2911
+ *
2912
+ * Unlike {@link VideoLayer} this is not a clip on the document timeline: it
2913
+ * does not follow play/pause, is never sought by frame capture, and adds no
2914
+ * audio to exports. Live players appear only where a viewer can use them (the
2915
+ * player's current slide); thumbnails, exports and frame capture draw a
2916
+ * poster instead.
2917
+ */
2918
+ interface VideoEmbedLayer extends BaseLayer {
2919
+ type: 'videoEmbed';
2920
+ content: {
2921
+ /** The video's page URL — any form `parseVideoEmbedUrl` recognizes. */
2922
+ url: string;
2923
+ /** Names the player for assistive tech and labels the poster. */
2924
+ title?: string;
2925
+ };
2926
+ }
2888
2927
  /**
2889
2928
  * Table layer - renders a data table with themed styling.
2890
2929
  * Uses foreignObject inside SVG for HTML-based table layout.
@@ -3277,4 +3316,4 @@ declare function getBlockAtTime(blocks: Block[], time: number): Block | null;
3277
3316
  */
3278
3317
  declare function getCaptionAtTime(captions: CaptionTrack | undefined, time: number): CaptionPhrase | null;
3279
3318
 
3280
- export { type FullBleedQuoteInput as $, type AccentImage as A, type BarChartInput as B, type CaptionPhrase as C, type CustomTemplateValidationError as D, type CustomTemplateValidationResult as E, DARK_SURFACE as F, DEFAULT_DOC_FONT as G, DEFAULT_TITLE_FONT as H, type DataTableInput as I, type DateEventInput as J, type DeepPartial as K, type DefinitionCardInput as L, type DiagramBlockInput as M, type DiagramEdgeAnchor as N, type DiagramTemplateEdge as O, type DiagramTemplateNode as P, type Doc as Q, type DocBlock as R, type DocDiagnostic as S, type DonutChartInput as T, type DrawingBlockInput as U, FRONTMATTER_CUSTOM_TEMPLATES_KEY as V, FRONTMATTER_CUSTOM_THEMES_KEY as W, FRONTMATTER_MOTION_KEY as X, type FactCardInput as Y, type FontFamily as Z, type FontFamilyKind as _, type AccentPosition as a, type PersistentLayerTemplate as a$, type GradientBackgroundConfig as a0, type ImageBackgroundConfig as a1, type ImageLayer as a2, type ImageTreatment as a3, type ImageWithCaptionInput as a4, LIGHT_SURFACE as a5, type Layer as a6, type LayerRepeat as a7, type LayoutHints as a8, type LeftFeatureInput as a9, PAGE_EMPHASES as aA, PAGE_EYEBROWS as aB, PAGE_HEADING_CASES as aC, PAGE_HEADING_SCALES as aD, PAGE_HEADING_UNDERLINES as aE, PAGE_HERO_STYLES as aF, PAGE_IMAGE_FRAMINGS as aG, PAGE_NUMERAL_STYLES as aH, PAGE_PATTERNS as aI, PAGE_QUOTE_MARKS as aJ, PAGE_SECTION_KINDS as aK, PAGE_SECTION_SPACINGS as aL, PAGE_SHADOWS as aM, PAGE_VARIANTS as aN, type PageAccentRotation as aO, type PageBackground as aP, type PageDesignFamily as aQ, type PageEmphasis as aR, type PageHeadingTreatment as aS, type PageSectionKind as aT, type PageSectionOverride as aU, type PageTokens as aV, type PageVariant as aW, type PathLayer as aX, type PatternBackgroundConfig as aY, type PersistentLayer as aZ, type PersistentLayerConfig as a_, type LineChartInput as aa, type LinearGradient as ab, type ListBlockInput as ac, MOTION_PROFILES as ad, type MapBlockInput as ae, type MapLayer as af, type MapMarker as ag, type MapTileStyle as ah, type MarkerStyle as ai, type MediaClip as aj, type MediaCrop as ak, type MediaCut as al, type MediaEdits as am, type MediaScheduleOptions as an, type MermaidLayer as ao, type MotionEntrance as ap, type MotionOrigin as aq, type MotionProfile as ar, type MotionProfileName as as, type MotionSpec as at, type MotionState as au, PAGE_ACCENT_STRATEGIES as av, PAGE_BACKGROUNDS as aw, PAGE_BACKGROUND_RHYTHMS as ax, PAGE_DESIGN_FAMILIES as ay, PAGE_DIVIDERS as az, type AmbientGradientConfig as b, type ViewportConfig as b$, type PersistentLayerTemplateConfig as b0, type PersistentLayerTemplateType as b1, type PhotoGridInput as b2, type PieChartInput as b3, type PipStyle as b4, type Position as b5, type ProgressIndicatorConfig as b6, type PromotedBodyAnnotation as b7, type PullQuoteInput as b8, type QuoteBlockInput as b9, type ThemeRegistry as bA, type ThemeSchemaVersion as bB, type ThemeSeedColors as bC, type ThemeStyle as bD, type ThemeTypography as bE, type TimelineBlockInput as bF, type TimelineTemplateEvent as bG, type TimelineTemplateLink as bH, type TimelineTemplateTrack as bI, type TitleBlockInput as bJ, type TitleCaptionConfig as bK, type TranscriptBlockInput as bL, type TreeBlockInput as bM, type TreeLayer as bN, type TreeLayerItem as bO, type TreeLayerStyle as bP, type TreeTemplateItem as bQ, type TwoColumnInput as bR, VIEWPORT_PRESETS as bS, type VideoLayer as bT, type VideoPipPosition as bU, type VideoPipShape as bV, type VideoPipSize as bW, type VideoPlacement as bX, type VideoPresentation as bY, type VideoPullQuoteInput as bZ, type VideoWithCaptionInput as b_, type RawLayersInput as ba, type RenderStyle as bb, type RightFeatureInput as bc, type ScatterChartInput as bd, type ScheduledClip as be, type SectionHeaderInput as bf, type ShapeFilter as bg, type ShapeLayer as bh, type ShapePattern as bi, type SolidBackgroundConfig as bj, type StartBlockConfig as bk, type StatHighlightInput as bl, type SurfaceScheme as bm, THEME_SCHEMA_VERSION as bn, type TableLayer as bo, type TableLayerStyle as bp, type TemplateBlock as bq, type TemplateContext as br, type TemplateFunction as bs, type TemplateRegistry as bt, type TextLayer as bu, type TextStyle as bv, type Theme as bw, type ThemeColorPalette as bx, type ThemeColorScheme as by, type ThemePageStyle as bz, type Animation as c, type ViewportOrientation as c0, type ViewportPreset as c1, type VignetteConfig as c2, applySurface as c3, calculateDuration as c4, calculateFontScale as c5, createTemplateContext as c6, createTheme as c7, createThemeRegistry as c8, getAspectRatioString as c9, type MediaEditParamKey as cA, type MediaEditParamValues as cB, type MediaFxOp as cC, formatMediaNumber as cD, hasRenderableFx as cE, mediaEditHtmlAttribute as cF, mediaEditValuesFromAttributes as cG, mediaEditValuesFromParams as cH, mediaRenderKey as cI, normalizeMediaCrop as cJ, normalizeMediaCuts as cK, parseMediaCrop as cL, parseMediaCuts as cM, parseMediaEdits as cN, parseMediaFx as cO, serializeMediaCrop as cP, serializeMediaCuts as cQ, serializeMediaEdits as cR, serializeMediaFx as cS, getBlockAtTime as ca, getCaptionAtTime as cb, getDocPlaybackDuration as cc, getLayoutHints as cd, getSafeTextBounds as ce, getSegmentAtTime as cf, getTwoColumnPositions as cg, getViewport as ch, getViewportOrientation as ci, isCustomTemplateDefinition as cj, isMotionProfileName as ck, isPersistentLayerTemplate as cl, isTemplateBlock as cm, scaledFontSize$1 as cn, readFrontmatterMotion as co, resolveMediaSchedule as cp, resolveMotionForDoc as cq, resolveMotionProfile as cr, scaledFontSize as cs, scheduleMediaClip as ct, validateCustomTemplateDefinition as cu, type MediaFxOpId as cv, type MediaFxChain as cw, MEDIA_EDIT_PARAMS as cx, MEDIA_FX_ORDER as cy, MEDIA_FX_SPECS as cz, type AnimationType as d, type AreaChartInput as e, type AudioBookmark as f, type AudioSegment as g, type AudioTimingData as h, type AudioTrack as i, type BigTextInput as j, type Block as k, type BlockConnection as l, type BorderStyle as m, type CaptionTrack as n, type CaptionWord as o, type ChartBaseFields as p, type ChartTemplateInput as q, type ColorScheme as r, type ColumnChartInput as s, type ComparisonBarInput as t, type ContentBlockInput as u, type CornerBrandingConfig as v, type CountUpSpec as w, type CreateTemplateContextOptions as x, type CustomTemplateDefinition as y, type CustomTemplateLayer as z };
3319
+ export { type FullBleedQuoteInput as $, type AccentImage as A, type BarChartInput as B, type CaptionPhrase as C, type CustomTemplateValidationError as D, type CustomTemplateValidationResult as E, DARK_SURFACE as F, DEFAULT_DOC_FONT as G, DEFAULT_TITLE_FONT as H, type DataTableInput as I, type DateEventInput as J, type DeepPartial as K, type DefinitionCardInput as L, type DiagramBlockInput as M, type DiagramEdgeAnchor as N, type DiagramTemplateEdge as O, type DiagramTemplateNode as P, type Doc as Q, type DocBlock as R, type DocDiagnostic as S, type DonutChartInput as T, type DrawingBlockInput as U, FRONTMATTER_CUSTOM_TEMPLATES_KEY as V, FRONTMATTER_CUSTOM_THEMES_KEY as W, FRONTMATTER_MOTION_KEY as X, type FactCardInput as Y, type FontFamily as Z, type FontFamilyKind as _, type AccentPosition as a, type PersistentLayerTemplate as a$, type GradientBackgroundConfig as a0, type ImageBackgroundConfig as a1, type ImageLayer as a2, type ImageTreatment as a3, type ImageWithCaptionInput as a4, LIGHT_SURFACE as a5, type Layer as a6, type LayerRepeat as a7, type LayoutHints as a8, type LeftFeatureInput as a9, PAGE_EMPHASES as aA, PAGE_EYEBROWS as aB, PAGE_HEADING_CASES as aC, PAGE_HEADING_SCALES as aD, PAGE_HEADING_UNDERLINES as aE, PAGE_HERO_STYLES as aF, PAGE_IMAGE_FRAMINGS as aG, PAGE_NUMERAL_STYLES as aH, PAGE_PATTERNS as aI, PAGE_QUOTE_MARKS as aJ, PAGE_SECTION_KINDS as aK, PAGE_SECTION_SPACINGS as aL, PAGE_SHADOWS as aM, PAGE_VARIANTS as aN, type PageAccentRotation as aO, type PageBackground as aP, type PageDesignFamily as aQ, type PageEmphasis as aR, type PageHeadingTreatment as aS, type PageSectionKind as aT, type PageSectionOverride as aU, type PageTokens as aV, type PageVariant as aW, type PathLayer as aX, type PatternBackgroundConfig as aY, type PersistentLayer as aZ, type PersistentLayerConfig as a_, type LineChartInput as aa, type LinearGradient as ab, type ListBlockInput as ac, MOTION_PROFILES as ad, type MapBlockInput as ae, type MapLayer as af, type MapMarker as ag, type MapTileStyle as ah, type MarkerStyle as ai, type MediaClip as aj, type MediaCrop as ak, type MediaCut as al, type MediaEdits as am, type MediaScheduleOptions as an, type MermaidLayer as ao, type MotionEntrance as ap, type MotionOrigin as aq, type MotionProfile as ar, type MotionProfileName as as, type MotionSpec as at, type MotionState as au, PAGE_ACCENT_STRATEGIES as av, PAGE_BACKGROUNDS as aw, PAGE_BACKGROUND_RHYTHMS as ax, PAGE_DESIGN_FAMILIES as ay, PAGE_DIVIDERS as az, type AmbientGradientConfig as b, type VideoWithCaptionInput as b$, type PersistentLayerTemplateConfig as b0, type PersistentLayerTemplateType as b1, type PhotoGridInput as b2, type PieChartInput as b3, type PipStyle as b4, type Position as b5, type ProgressIndicatorConfig as b6, type PromotedBodyAnnotation as b7, type PullQuoteInput as b8, type QuoteBlockInput as b9, type ThemeRegistry as bA, type ThemeSchemaVersion as bB, type ThemeSeedColors as bC, type ThemeStyle as bD, type ThemeTypography as bE, type TimelineBlockInput as bF, type TimelineTemplateEvent as bG, type TimelineTemplateLink as bH, type TimelineTemplateTrack as bI, type TitleBlockInput as bJ, type TitleCaptionConfig as bK, type TranscriptBlockInput as bL, type TreeBlockInput as bM, type TreeLayer as bN, type TreeLayerItem as bO, type TreeLayerStyle as bP, type TreeTemplateItem as bQ, type TwoColumnInput as bR, VIEWPORT_PRESETS as bS, type VideoEmbedLayer as bT, type VideoLayer as bU, type VideoPipPosition as bV, type VideoPipShape as bW, type VideoPipSize as bX, type VideoPlacement as bY, type VideoPresentation as bZ, type VideoPullQuoteInput as b_, type RawLayersInput as ba, type RenderStyle as bb, type RightFeatureInput as bc, type ScatterChartInput as bd, type ScheduledClip as be, type SectionHeaderInput as bf, type ShapeFilter as bg, type ShapeLayer as bh, type ShapePattern as bi, type SolidBackgroundConfig as bj, type StartBlockConfig as bk, type StatHighlightInput as bl, type SurfaceScheme as bm, THEME_SCHEMA_VERSION as bn, type TableLayer as bo, type TableLayerStyle as bp, type TemplateBlock as bq, type TemplateContext as br, type TemplateFunction as bs, type TemplateRegistry as bt, type TextLayer as bu, type TextStyle as bv, type Theme as bw, type ThemeColorPalette as bx, type ThemeColorScheme as by, type ThemePageStyle as bz, type Animation as c, type ViewportConfig as c0, type ViewportOrientation as c1, type ViewportPreset as c2, type VignetteConfig as c3, applySurface as c4, calculateDuration as c5, calculateFontScale as c6, createTemplateContext as c7, createTheme as c8, createThemeRegistry as c9, MEDIA_FX_SPECS as cA, type MediaEditParamKey as cB, type MediaEditParamValues as cC, type MediaFxOp as cD, formatMediaNumber as cE, hasRenderableFx as cF, mediaEditHtmlAttribute as cG, mediaEditValuesFromAttributes as cH, mediaEditValuesFromParams as cI, mediaRenderKey as cJ, normalizeMediaCrop as cK, normalizeMediaCuts as cL, parseMediaCrop as cM, parseMediaCuts as cN, parseMediaEdits as cO, parseMediaFx as cP, serializeMediaCrop as cQ, serializeMediaCuts as cR, serializeMediaEdits as cS, serializeMediaFx as cT, getAspectRatioString as ca, getBlockAtTime as cb, getCaptionAtTime as cc, getDocPlaybackDuration as cd, getLayoutHints as ce, getSafeTextBounds as cf, getSegmentAtTime as cg, getTwoColumnPositions as ch, getViewport as ci, getViewportOrientation as cj, isCustomTemplateDefinition as ck, isMotionProfileName as cl, isPersistentLayerTemplate as cm, isTemplateBlock as cn, scaledFontSize$1 as co, readFrontmatterMotion as cp, resolveMediaSchedule as cq, resolveMotionForDoc as cr, resolveMotionProfile as cs, scaledFontSize as ct, scheduleMediaClip as cu, validateCustomTemplateDefinition as cv, type MediaFxOpId as cw, type MediaFxChain as cx, MEDIA_EDIT_PARAMS as cy, MEDIA_FX_ORDER as cz, type AnimationType as d, type AreaChartInput as e, type AudioBookmark as f, type AudioSegment as g, type AudioTimingData as h, type AudioTrack as i, type BigTextInput as j, type Block as k, type BlockConnection as l, type BorderStyle as m, type CaptionTrack as n, type CaptionWord as o, type ChartBaseFields as p, type ChartTemplateInput as q, type ColorScheme as r, type ColumnChartInput as s, type ComparisonBarInput as t, type ContentBlockInput as u, type CornerBrandingConfig as v, type CountUpSpec as w, type CreateTemplateContextOptions as x, type CustomTemplateDefinition as y, type CustomTemplateLayer as z };
@@ -1,4 +1,4 @@
1
- import { a2 as ImageLayer, bu as TextLayer, bh as ShapeLayer, aX as PathLayer } from './Doc-Bd2kdzuy.js';
1
+ import { a2 as ImageLayer, bu as TextLayer, bh as ShapeLayer, aX as PathLayer } from './Doc-B6TYHYGc.js';
2
2
 
3
3
  /**
4
4
  * ImageEditDoc — JSON document describing a layered, editable image.
@@ -0,0 +1,114 @@
1
+ // src/narration/sidecar.ts
2
+ function resolveNarrationTimingGenerator(options) {
3
+ const baseWpm = options?.generator?.baseWpm ?? options?.baseWpm;
4
+ return {
5
+ name: options?.generator?.name ?? "squisq-teleprompter",
6
+ method: options?.generator?.method ?? "dsp-align",
7
+ ...baseWpm !== void 0 ? { baseWpm } : {}
8
+ };
9
+ }
10
+ function buildNarrationTimingJson(script, alignment, durationSec, options) {
11
+ const bookmarks = alignment.words.map((word) => {
12
+ const token = script.tokens[word.tokenIndex];
13
+ return {
14
+ id: `word-${word.tokenIndex}`,
15
+ time: word.tSec,
16
+ charOffset: token?.charOffset ?? 0,
17
+ textFragment: token?.text ?? ""
18
+ };
19
+ });
20
+ const blocks = alignment.blocks.map((range) => ({
21
+ ...range.blockId ? { blockId: range.blockId } : {},
22
+ ...range.heading !== void 0 ? { heading: range.heading } : {},
23
+ blockIndex: range.blockIndex,
24
+ charStart: range.charStart,
25
+ charEnd: range.charEnd,
26
+ startSec: range.startSec,
27
+ endSec: range.endSec
28
+ }));
29
+ return {
30
+ version: 3,
31
+ sourceText: script.sourceText,
32
+ duration: Number.isFinite(durationSec) && durationSec >= 0 ? durationSec : 0,
33
+ bookmarks,
34
+ blocks,
35
+ // Write only what `parseNarrationTimingJson` will read back, so the codec
36
+ // is a round-trip pair. A non-finite value would serialize to `null`
37
+ // (JSON has no NaN) and be dropped on parse anyway — omitting it here
38
+ // keeps the emitted sidecar honest rather than carrying a dead field.
39
+ ...finiteNumber(options?.cameraOffsetSec) ? { cameraOffsetSec: options.cameraOffsetSec } : {},
40
+ generator: resolveNarrationTimingGenerator(options)
41
+ };
42
+ }
43
+ function finiteNonNegative(value) {
44
+ return typeof value === "number" && Number.isFinite(value) && value >= 0;
45
+ }
46
+ function finiteNumber(value) {
47
+ return typeof value === "number" && Number.isFinite(value);
48
+ }
49
+ function parseNarrationTimingJson(data) {
50
+ try {
51
+ const text = typeof data === "string" ? data : new TextDecoder().decode(data instanceof Uint8Array ? data : new Uint8Array(data));
52
+ const parsed = JSON.parse(text);
53
+ if (typeof parsed !== "object" || parsed === null) return null;
54
+ const raw = parsed;
55
+ if (typeof raw.sourceText !== "string" || !finiteNonNegative(raw.duration)) return null;
56
+ const bookmarks = Array.isArray(raw.bookmarks) ? raw.bookmarks.flatMap((b) => {
57
+ if (typeof b !== "object" || b === null) return [];
58
+ const bookmark = b;
59
+ if (!finiteNonNegative(bookmark.time) || !finiteNonNegative(bookmark.charOffset)) {
60
+ return [];
61
+ }
62
+ return [
63
+ {
64
+ id: typeof bookmark.id === "string" ? bookmark.id : `bookmark-${bookmark.charOffset}`,
65
+ time: bookmark.time,
66
+ charOffset: bookmark.charOffset,
67
+ ...typeof bookmark.textFragment === "string" ? { textFragment: bookmark.textFragment } : {}
68
+ }
69
+ ];
70
+ }) : [];
71
+ let blocks = Array.isArray(raw.blocks) ? raw.blocks.flatMap((b) => {
72
+ if (typeof b !== "object" || b === null) return [];
73
+ const block = b;
74
+ if (!finiteNonNegative(block.startSec) || !finiteNonNegative(block.endSec) || !finiteNonNegative(block.charStart) || !finiteNonNegative(block.charEnd)) {
75
+ return [];
76
+ }
77
+ return [
78
+ {
79
+ ...typeof block.blockId === "string" ? { blockId: block.blockId } : {},
80
+ ...typeof block.heading === "string" ? { heading: block.heading } : {},
81
+ blockIndex: finiteNonNegative(block.blockIndex) ? block.blockIndex : 0,
82
+ charStart: block.charStart,
83
+ charEnd: block.charEnd,
84
+ startSec: block.startSec,
85
+ endSec: Math.max(block.startSec, block.endSec)
86
+ }
87
+ ];
88
+ }) : [];
89
+ blocks = blocks.sort((a, b) => a.startSec - b.startSec);
90
+ let cursor = 0;
91
+ for (const block of blocks) {
92
+ if (block.startSec < cursor) block.startSec = cursor;
93
+ if (block.endSec < block.startSec) block.endSec = block.startSec;
94
+ cursor = block.startSec;
95
+ }
96
+ return {
97
+ version: 3,
98
+ sourceText: raw.sourceText,
99
+ duration: raw.duration,
100
+ bookmarks,
101
+ blocks,
102
+ ...finiteNumber(raw.cameraOffsetSec) ? { cameraOffsetSec: raw.cameraOffsetSec } : {},
103
+ ...typeof raw.generator === "object" && raw.generator !== null ? { generator: raw.generator } : {}
104
+ };
105
+ } catch {
106
+ return null;
107
+ }
108
+ }
109
+
110
+ export {
111
+ resolveNarrationTimingGenerator,
112
+ buildNarrationTimingJson,
113
+ parseNarrationTimingJson
114
+ };