@hyperframes/inspector 0.0.0-stage → 0.8.152

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 (74) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +104 -2
  3. package/dist/inspection.js +2007 -0
  4. package/dist/live.js +1288 -0
  5. package/dist/service.js +63122 -0
  6. package/dist/types/core/src/audioAutomation.d.ts +202 -0
  7. package/dist/types/core/src/audioFx.d.ts +181 -0
  8. package/dist/types/core/src/audioGain.d.ts +44 -0
  9. package/dist/types/core/src/colorGrading.d.ts +1959 -0
  10. package/dist/types/core/src/colorGradingCurves.d.ts +8 -0
  11. package/dist/types/core/src/colorLuts.d.ts +24 -0
  12. package/dist/types/core/src/compiler/assetPaths.d.ts +1 -0
  13. package/dist/types/core/src/compiler/compositionAssembly.d.ts +144 -0
  14. package/dist/types/core/src/compiler/compositionScoping.d.ts +28 -0
  15. package/dist/types/core/src/compiler/externalScripts.d.ts +8 -0
  16. package/dist/types/core/src/compiler/htmlBundler.d.ts +74 -0
  17. package/dist/types/core/src/compiler/htmlCompiler.d.ts +18 -0
  18. package/dist/types/core/src/compiler/htmlDocument.d.ts +23 -0
  19. package/dist/types/core/src/compiler/importMaps.d.ts +18 -0
  20. package/dist/types/core/src/compiler/inlineSubCompositions.d.ts +151 -0
  21. package/dist/types/core/src/compiler/rewriteSubCompPaths.d.ts +1 -0
  22. package/dist/types/core/src/compiler/scriptRuns.d.ts +31 -0
  23. package/dist/types/core/src/compiler/selectorIdTokens.d.ts +70 -0
  24. package/dist/types/core/src/compiler/standaloneEntry.d.ts +2 -0
  25. package/dist/types/core/src/compiler/staticGuard.d.ts +7 -0
  26. package/dist/types/core/src/compiler/svgIdNamespacing.d.ts +80 -0
  27. package/dist/types/core/src/compiler/svgSelectorAliases.d.ts +30 -0
  28. package/dist/types/core/src/compiler/timingCompiler.d.ts +89 -0
  29. package/dist/types/core/src/generated/runtime-inline.d.ts +6 -0
  30. package/dist/types/core/src/generated/svg-selector-aliases-inline.d.ts +2 -0
  31. package/dist/types/core/src/inline-scripts/pickerApi.d.ts +32 -0
  32. package/dist/types/core/src/inline-scripts/runtimeContract.d.ts +13 -0
  33. package/dist/types/core/src/mediaTiming.d.ts +41 -0
  34. package/dist/types/core/src/playbackRateBounds.d.ts +1 -0
  35. package/dist/types/core/src/runtime/analytics.d.ts +18 -0
  36. package/dist/types/core/src/runtime/applyVariableBindings.d.ts +47 -0
  37. package/dist/types/core/src/runtime/audioAutomationVolume.d.ts +19 -0
  38. package/dist/types/core/src/runtime/authoredTiming.d.ts +16 -0
  39. package/dist/types/core/src/runtime/compositionDimension.d.ts +5 -0
  40. package/dist/types/core/src/runtime/diagnostics.d.ts +3 -0
  41. package/dist/types/core/src/runtime/domRealm.d.ts +67 -0
  42. package/dist/types/core/src/runtime/flattenedRoot.d.ts +9 -0
  43. package/dist/types/core/src/runtime/getVariables.d.ts +42 -0
  44. package/dist/types/core/src/runtime/globals.d.ts +11 -0
  45. package/dist/types/core/src/runtime/inspectionTypes.d.ts +68 -0
  46. package/dist/types/core/src/runtime/playbackRate.d.ts +26 -0
  47. package/dist/types/core/src/runtime/protocol.d.ts +30 -0
  48. package/dist/types/core/src/runtime/proxySrc.d.ts +3 -0
  49. package/dist/types/core/src/runtime/startExpression.d.ts +14 -0
  50. package/dist/types/core/src/runtime/startResolver.d.ts +21 -0
  51. package/dist/types/core/src/runtime/timelineDuration.d.ts +3 -0
  52. package/dist/types/core/src/runtime/timelineInspection.d.ts +46 -0
  53. package/dist/types/core/src/runtime/timelineValues.d.ts +15 -0
  54. package/dist/types/core/src/runtime/types.d.ts +335 -0
  55. package/dist/types/core/src/runtime/variableScope.d.ts +8 -0
  56. package/dist/types/core/src/safePath.d.ts +49 -0
  57. package/dist/types/core/src/sceneParts.d.ts +9 -0
  58. package/dist/types/core/src/speedRamp.d.ts +59 -0
  59. package/dist/types/core/src/tokenSlug.d.ts +12 -0
  60. package/dist/types/inspector/src/elementMap.d.ts +33 -0
  61. package/dist/types/inspector/src/engine.d.ts +35 -0
  62. package/dist/types/inspector/src/live.d.ts +18 -0
  63. package/dist/types/inspector/src/mapInspection.d.ts +76 -0
  64. package/dist/types/inspector/src/outputSchemas.d.ts +12 -0
  65. package/dist/types/inspector/src/pageQueries.d.ts +21 -0
  66. package/dist/types/inspector/src/pageServer.d.ts +2 -0
  67. package/dist/types/inspector/src/requests.d.ts +5 -0
  68. package/dist/types/inspector/src/service.d.ts +98 -0
  69. package/dist/types/inspector/src/sourceDependencies.d.ts +5 -0
  70. package/dist/types/inspector/src/sources.d.ts +49 -0
  71. package/dist/types/inspector/src/timelineReport.d.ts +28 -0
  72. package/dist/types/inspector/src/tools.d.ts +18 -0
  73. package/dist/types/inspector/src/types.d.ts +1 -0
  74. package/package.json +54 -3
@@ -0,0 +1,8 @@
1
+ export type HfColorCurvePoint = readonly [input: number, output: number];
2
+ export type HfHueCurvePoint = readonly [hueDegrees: number, delta: number];
3
+ export declare const HF_COLOR_CURVE_LUT_SIZE = 1024;
4
+ export declare const HF_COLOR_CURVE_MAX_POINTS = 16;
5
+ /** Samples a shape-preserving cubic curve into a GPU-ready 1D lookup table. */
6
+ export declare function compileHfColorCurve(points: readonly HfColorCurvePoint[], size?: number): Float32Array;
7
+ /** Samples a periodic hue curve without duplicating the 0/360-degree texel. */
8
+ export declare function compileHfHueCurve(points: readonly HfHueCurvePoint[], outputMin: number, outputMax: number, size?: number): Float32Array;
@@ -0,0 +1,24 @@
1
+ export type CubeLutVec3 = readonly [number, number, number];
2
+ export interface CubeLut3D {
3
+ title: string | null;
4
+ size: number;
5
+ domainMin: CubeLutVec3;
6
+ domainMax: CubeLutVec3;
7
+ data: Float32Array;
8
+ }
9
+ export interface PackedCubeLut2D {
10
+ width: number;
11
+ height: number;
12
+ data: Uint8Array;
13
+ }
14
+ export interface ParseCubeLutOptions {
15
+ maxSize?: number;
16
+ }
17
+ export declare class CubeLutParseError extends Error {
18
+ readonly lineNumber: number | null;
19
+ constructor(message: string, lineNumber?: number | null);
20
+ }
21
+ export declare const DEFAULT_MAX_CUBE_LUT_SIZE = 64;
22
+ export declare function parseCubeLut(input: string, options?: ParseCubeLutOptions): CubeLut3D;
23
+ export declare function unitFloatToByte(value: number): number;
24
+ export declare function packCubeLutToRgba8(lut: CubeLut3D): PackedCubeLut2D;
@@ -0,0 +1 @@
1
+ export { CSS_URL_RE, PATH_ATTRS, isNonRelativeUrl, isPathInside, } from "@hyperframes/parsers/asset-paths";
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Composition assembly decisions — the questions both assembly paths answer.
3
+ *
4
+ * A composition is assembled twice in this repo: `compiler/inlineSubCompositions.ts`
5
+ * assembles it for rendering (Node, linkedom, synchronous, emits strings) and
6
+ * `runtime/compositionLoader.ts` assembles it for mounting (browser, fetch, live
7
+ * DOM, executes scripts). Their I/O is genuinely different; their *decisions* are
8
+ * not. This module owns the decisions:
9
+ *
10
+ * - which nodes are a composition's asset sources, and in what order
11
+ * - which `<head>` elements hoist into the host document
12
+ * - the composition's scope identity (CSS scope, script scope, authored root id)
13
+ * - which nodes carry the composition's declared variable defaults
14
+ * - how nested `data-composition-src` hosts are enumerated
15
+ *
16
+ * It is deliberately DOM-free, filesystem-free and network-free: the runtime is
17
+ * bundled by esbuild into the IIFE published to a CDN, so anything reachable
18
+ * from `runtime/entry.ts` ships to every viewer. It takes narrow structural
19
+ * types instead of `Document`/`Element` for the same reason `compositionScoping.ts`
20
+ * takes strings — so both a linkedom document and a live browser document
21
+ * satisfy it without an `as T` cast at either call site.
22
+ */
23
+ export declare function isJavaScriptType(el: AssemblyAttributed): boolean;
24
+ export declare function executableScripts<TElement extends AssemblyAttributed>(node: AssemblyQueryable<TElement> | null | undefined): TElement[];
25
+ /** The styles, scripts and links both paths extract, so the mounted copy must drop them. */
26
+ export declare function extractedCompositionAssets<TElement extends AssemblyAttributed>(node: AssemblyQueryable<TElement>): TElement[];
27
+ /**
28
+ * The compiler's nesting cap, enforced against the ancestry chain rather than a
29
+ * counter so a wide tree is not penalised for a deep sibling.
30
+ */
31
+ export declare const MAX_SUB_COMPOSITION_DEPTH = 20;
32
+ /** An element this module only ever reads attributes from. */
33
+ export interface AssemblyAttributed {
34
+ getAttribute(name: string): string | null;
35
+ }
36
+ /** A node this module only ever searches with a CSS selector. */
37
+ export interface AssemblyQueryable<TElement> {
38
+ querySelectorAll(selectors: string): Iterable<TElement>;
39
+ }
40
+ export interface CompositionAssemblyInput<TElement extends AssemblyAttributed> {
41
+ /**
42
+ * The composition's content: a `<template>`'s content when the composition is
43
+ * templated, the parsed document's `<body>` otherwise.
44
+ *
45
+ * Asset sources are collected from the WHOLE content node, never from the
46
+ * composition root alone. The canonical authored shape puts `<style>`/`<script>`
47
+ * as SIBLINGS of the root inside `<template>`; scanning only the root dropped a
48
+ * composition's entire stylesheet on mount while its render stayed correct.
49
+ */
50
+ contentNode: AssemblyQueryable<TElement>;
51
+ /**
52
+ * The parsed document's `<head>`, when the composition was loaded as a full
53
+ * HTML document. Omit it for an inline `<template>`, which has no head of its
54
+ * own.
55
+ */
56
+ head?: AssemblyQueryable<TElement> | null;
57
+ /**
58
+ * The parsed document's `<html>` element, when there is one. It is the first
59
+ * variable-default carrier; see `variableDefaultCarriers`.
60
+ */
61
+ documentElement?: TElement | null;
62
+ /**
63
+ * True when `contentNode` came from a `<template>`. A templated composition's
64
+ * `<head>` styles and scripts are not part of the composition — the template
65
+ * already carries everything it needs — so they are not collected.
66
+ */
67
+ hasTemplate: boolean;
68
+ /**
69
+ * The composition id the host asks this composition to mount as, or `null` for
70
+ * an anonymous host.
71
+ */
72
+ compositionId: string | null;
73
+ }
74
+ export interface CompositionAssemblyPlan<TElement extends AssemblyAttributed> {
75
+ /**
76
+ * The composition root inside `contentNode`. Matched on an EXACT id when the
77
+ * host names one — a template may intentionally use a different local id (a
78
+ * `captions-comp` host mounting a `captions` template), and flattening that
79
+ * fallback root changes the assembled DOM. Anonymous hosts fall back to the
80
+ * first root in the content.
81
+ */
82
+ innerRoot: TElement | null;
83
+ /**
84
+ * The id CSS is scoped to: the host's id when it names one, otherwise the id
85
+ * declared inside the content.
86
+ */
87
+ authoredCompositionId: string | null;
88
+ /**
89
+ * The id composition scripts are scoped to. It differs from
90
+ * `authoredCompositionId` only when a host names an id that no root inside the
91
+ * content declares: CSS stays on the host's id while scripts follow the id the
92
+ * content actually declares, so a script's self-referencing
93
+ * `querySelector('[data-composition-id="X"]')` still resolves.
94
+ */
95
+ scriptCompositionId: string | null;
96
+ /** The `id` attribute authored on the composition root, if any. */
97
+ authoredRootId: string | null;
98
+ /** `<style>` sources in injection order: head-sourced first, then content. */
99
+ styleSources: TElement[];
100
+ /**
101
+ * `<script>` sources in execution order: head-sourced first, then content. A
102
+ * head script (a GSAP CDN tag in a non-templated composition) has to run
103
+ * before the content scripts that call into it.
104
+ */
105
+ scriptSources: TElement[];
106
+ /** Head and content links to hoist into the host document. */
107
+ linkSources: TElement[];
108
+ /** Inert scripts the mounted root would leave behind; both paths mount them next to it. */
109
+ inertScriptsOutsideRoot: TElement[];
110
+ /**
111
+ * Nodes that may declare the composition's variable defaults, in precedence
112
+ * order — later wins. Full-document compositions declare on `<html>`;
113
+ * template/fragment compositions declare on the `[data-composition-id]` root
114
+ * div, because they have no `<html>` of their own. Callers read the declared
115
+ * defaults off each carrier and merge left to right.
116
+ */
117
+ variableDefaultCarriers: TElement[];
118
+ }
119
+ /**
120
+ * Answer, for one composition, where its assets come from, in what order, and
121
+ * how it is identified. Pure: it reads attributes and runs selectors, and does
122
+ * not mutate, fetch, or touch a filesystem.
123
+ */
124
+ export declare function planCompositionAssembly<TElement extends AssemblyAttributed & AssemblyQueryable<TElement>>(input: CompositionAssemblyInput<TElement>): CompositionAssemblyPlan<TElement>;
125
+ export type NestedHostSkipReason = "circular composition reference" | "nesting depth exceeded";
126
+ export interface NestedCompositionHost<TElement> {
127
+ host: TElement;
128
+ src: string;
129
+ }
130
+ export interface NestedCompositionHosts<TElement> {
131
+ hosts: NestedCompositionHost<TElement>[];
132
+ skipped: {
133
+ src: string;
134
+ reason: NestedHostSkipReason;
135
+ }[];
136
+ }
137
+ /**
138
+ * Enumerate the sub-composition hosts nested inside a composition that has just
139
+ * been assembled, refusing the two shapes that do not terminate.
140
+ *
141
+ * `ancestry` is the chain down to and including the assembled composition's own
142
+ * `src`, so a top-level host is enumerated with `[itsOwnSrc]`.
143
+ */
144
+ export declare function enumerateNestedCompositionHosts<TElement extends AssemblyAttributed>(assembledHost: AssemblyQueryable<TElement>, ancestry: readonly string[]): NestedCompositionHosts<TElement>;
@@ -0,0 +1,28 @@
1
+ export declare function scopeCssToComposition(css: string, compositionId: string, scopeSelectorOverride?: string, authoredRootId?: string | null, options?: {
2
+ compoundAuthoredRoot?: boolean;
3
+ scopeRootSelectors?: boolean;
4
+ }): string;
5
+ /** Drops repeats of an identical `@font-face` across the given style texts, keeping the last copy:
6
+ * the last matching rule is the one the browser uses, so a rule in between never gains precedence. */
7
+ export declare function dedupeFontFaceRules(styleTexts: string[]): string[];
8
+ export declare function scopedModulePrelude(timelineCompositionId: string, compositionSrc?: string | null): string;
9
+ export declare function wrapScopedCompositionScript(source: string, compositionId: string, errorLabel?: string, scopeSelectorOverride?: string, timelineCompositionId?: string, authoredRootId?: string | null, compositionSrc?: string | null): string;
10
+ export declare function wrapInlineScriptWithErrorBoundary(source: string, errorLabel: string): string;
11
+ /**
12
+ * Build the statement that populates `window.__hfVariablesByComp` — the table
13
+ * the scoped `getVariables` above reads. Returns `null` when there are no
14
+ * per-instance values.
15
+ *
16
+ * The WRITER lives next to the READER (the scoped `getVariables` in
17
+ * `wrapScopedCompositionScript`) on purpose: every compile path that wraps the
18
+ * reader MUST also emit this writer before the sub-comp scripts run. The
19
+ * render compiler (`htmlCompiler`) inlined the reader scripts but never emitted
20
+ * the writer while the preview bundler (`htmlBundler`) did, so
21
+ * `getVariables()` returned `{}` only during render — parametrized sub-comps
22
+ * silently shipped blank/default text in the final MP4 while snapshot QA passed
23
+ * (issue #2064). Both callers now share this one builder so they can't drift.
24
+ *
25
+ * Values, keys and composition ids are all attacker-reachable, so the whole
26
+ * table goes through `jsonScriptLiteral` — see there for why.
27
+ */
28
+ export declare function buildVariablesByCompScript(variablesByComp: Record<string, Record<string, unknown>>): string | null;
@@ -0,0 +1,8 @@
1
+ export interface ExternalScriptAttributes {
2
+ integrity?: string;
3
+ crossorigin?: string;
4
+ type?: "module";
5
+ }
6
+ export declare function readExternalScriptAttributes(el: Element): ExternalScriptAttributes;
7
+ /** Deduplicate scripts without discarding a nested composition's integrity requirement. */
8
+ export declare function ensureExternalScriptTag(doc: Document, src: string, attributes?: ExternalScriptAttributes): void;
@@ -0,0 +1,74 @@
1
+ export { FLATTENED_INNER_ROOT_STRIP_ATTRS } from "../runtime/flattenedRoot.js";
2
+ import { type MediaDurationProber } from "./htmlCompiler.js";
3
+ export type BundledHostCompositionIdentity = {
4
+ authoredCompositionId: string | null;
5
+ runtimeCompositionId: string | null;
6
+ };
7
+ export declare function assignBundledRuntimeCompositionIds(hosts: Element[], counts?: Map<string, number>): Map<Element, BundledHostCompositionIdentity>;
8
+ export declare function prepareFlattenedInnerRoot(innerRoot: Element): Element;
9
+ export declare function parsesAsScript(source: string): boolean;
10
+ export interface BundleScriptProvenance {
11
+ input: string;
12
+ output: string;
13
+ sourceMap: string;
14
+ sourceURL?: string;
15
+ }
16
+ export interface BundleOptions {
17
+ /** Optional source mapping for inspection; does not alter bundled HTML. */
18
+ scriptProvenance?: (script: BundleScriptProvenance) => void;
19
+ /** Project-relative HTML entry to bundle. Defaults to `index.html`. */
20
+ entryFile?: string;
21
+ stampHfIds?: boolean;
22
+ /** Optional media duration prober (e.g., ffprobe). If omitted, media durations are not resolved. */
23
+ probeMediaDuration?: MediaDurationProber;
24
+ /**
25
+ * How to handle the HyperFrames runtime <script> tag. Default: `"inline"`.
26
+ *
27
+ * - `"inline"` — embed the runtime IIFE body directly into the bundle. Produces
28
+ * genuinely self-contained HTML. Right for CLI render output, validate,
29
+ * snapshot, and any "ship a single .html file" use case.
30
+ * - `"placeholder"` — emit `<script ... src=""></script>` so the caller can
31
+ * substitute it with a real URL via string replace. Used by the dev studio
32
+ * server and vite preview to point at a local runtime endpoint, which keeps
33
+ * the runtime cacheable across hot-reloads instead of re-inlining ~150 KB
34
+ * on every change.
35
+ *
36
+ * The `HYPERFRAME_RUNTIME_URL` env var, when set, takes precedence over both
37
+ * modes and emits `<script ... src="<URL>">` directly.
38
+ */
39
+ runtime?: "inline" | "placeholder";
40
+ /**
41
+ * Inline .cube LUTs referenced from data-color-grading. Default: true for
42
+ * self-contained renders/exports. Studio preview disables this so the editor
43
+ * keeps showing project asset paths instead of giant data URLs.
44
+ */
45
+ inlineColorGradingLuts?: boolean;
46
+ /**
47
+ * Inline fonts, raster images (img/href/poster/srcset/CSS url()) and color grading LUTs as data
48
+ * URLs, up to the per-asset size ceiling. Default: true, for a genuinely self-contained bundle. Set
49
+ * false when the caller serves the project's own files alongside the bundle (e.g. a same-origin
50
+ * asset route): assets then keep their authored relative URL, which the caller resolves.
51
+ * `inlineColorGradingLuts` narrows LUTs further; it cannot inline a LUT this option excluded.
52
+ */
53
+ inlineAssets?: boolean;
54
+ /** Preview only: tag each scene's host, styles and scripts (`data-hf-scene`) so one can be swapped. */
55
+ sceneParts?: boolean;
56
+ /** Warn when the compiled HTML breaks the HyperFrames contract (default true). */
57
+ staticGuard?: boolean;
58
+ onRead?: (filePath: string) => void;
59
+ }
60
+ export declare function bundleToSingleHtml(projectDir: string, options?: BundleOptions): Promise<string>;
61
+ /**
62
+ * Compile-time counterpart of the runtime's injectCompositionCssVariables:
63
+ * every element declaring data-composition-variables gets a scoped stylesheet
64
+ * rule so var(--slug, literal) references resolve during body parse. The
65
+ * runtime injection remains define-if-absent, so it won't double-apply.
66
+ *
67
+ * `variablesByComp` (host-merged sub-composition values, keyed by runtime
68
+ * composition id) adds one rule per scope — the flattened inner root loses
69
+ * its data-composition-id, so the host selector is the only stable anchor.
70
+ * Exported for the producer's render compiler, which inlines sub-compositions
71
+ * through the shared module rather than this bundler.
72
+ * Returns whether a style element was appended.
73
+ */
74
+ export declare function emitRootCompositionVariableStyles(document: Document, variablesByComp?: Record<string, Record<string, unknown>>, overrides?: Record<string, unknown>): boolean;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Callback to probe media duration. If not provided, media duration resolution is skipped.
3
+ * Return duration in seconds, or 0 if unknown.
4
+ */
5
+ export type MediaDurationProber = (src: string) => Promise<number>;
6
+ /**
7
+ * Compile HTML with full duration resolution.
8
+ *
9
+ * 1. Static pass: compileTimingAttrs() adds data-end where data-duration exists
10
+ * 2. For unresolved video/audio (no data-duration): probe via probeMediaDuration, inject durations
11
+ * 3. For pre-resolved audio: clamp data-duration to playable source when needed.
12
+ * Explicit video slots are preserved and hold their final frame.
13
+ *
14
+ * @param rawHtml - The raw HTML string
15
+ * @param projectDir - The project directory for resolving relative paths
16
+ * @param probeMediaDuration - Optional callback to probe media duration (e.g., via ffprobe)
17
+ */
18
+ export declare function compileHtml(rawHtml: string, projectDir: string, probeMediaDuration?: MediaDurationProber): Promise<string>;
@@ -0,0 +1,23 @@
1
+ export declare const RUNTIME_BOOTSTRAP_ATTR = "data-hyperframes-preview-runtime";
2
+ export declare function isFullHtmlDocument(html: string): boolean;
3
+ /**
4
+ * Parse a full HTML document or wrap a fragment so linkedom consistently puts
5
+ * fragment content under document.body.
6
+ */
7
+ export declare function parseHTMLContent(html: string): Document;
8
+ export declare function stripEmbeddedRuntimeScripts(html: string): string;
9
+ export declare function isRuntimeFileUrl(src: string | null | undefined): boolean;
10
+ export declare function escapeInlineScriptSource(source: string): string;
11
+ export declare function findStartTags(html: string, name: string): number[];
12
+ export declare function hasCompositionOutsideTemplates(html: string): boolean;
13
+ /** Insert markup before the document's own `</head>`, `</body>` or `</template>`; null if it has none. */
14
+ export declare function insertBeforeCloseTag(html: string, name: "head" | "body" | "template", markup: string): string | null;
15
+ export declare function insertRuntimeTag(html: string, tag: string): string;
16
+ /**
17
+ * Insert raw tag markup at the very start of `<head>`, ahead of every author
18
+ * script (inline or external). Falls back to just before `<body>`, then to the
19
+ * top of the document, for fragments that carry neither.
20
+ */
21
+ export declare function injectTagsAtHeadStart(html: string, tags: string): string;
22
+ export declare function injectScriptsAtHeadStart(html: string, scripts: readonly string[]): string;
23
+ export declare function injectScriptsIntoHtml(html: string, headScripts: readonly string[], bodyScripts: readonly string[], stripEmbeddedRuntime?: boolean): string;
@@ -0,0 +1,18 @@
1
+ /** The subset of an import map a composition can declare. */
2
+ export interface ImportMap {
3
+ imports?: Record<string, string>;
4
+ scopes?: Record<string, Record<string, string>>;
5
+ }
6
+ /**
7
+ * Parses a mounted composition's import map, rebasing each address the way its `src`/`href`
8
+ * attributes are rebased. Returns null for a map the browser would reject too.
9
+ */
10
+ export declare function parseImportMap(json: string, rebase: (url: string) => string): ImportMap | null;
11
+ /**
12
+ * A page has one import map, and it must precede every module script. Mounted compositions'
13
+ * maps merge into the page's own (created at the top of <head> if absent); the first mapping
14
+ * of a specifier wins and a conflicting later one is dropped with a warning.
15
+ */
16
+ export declare function mergeImportMapsIntoDocument(doc: Document, maps: ImportMap[]): void;
17
+ /** Emits what inlineSubCompositions collected from mounted files' module and import-map scripts. */
18
+ export declare function emitMountedModuleScripts(doc: Document, importMaps: ImportMap[], moduleScripts: string[]): void;
@@ -0,0 +1,151 @@
1
+ import { type ExternalScriptAttributes } from "./externalScripts.js";
2
+ import { type ImportMap } from "./importMaps.js";
3
+ import { type CompositionStyle } from "./scriptRuns.js";
4
+ /**
5
+ * Shared sub-composition inlining logic.
6
+ *
7
+ * Both the core bundler (preview) and the producer compiler (render) need to
8
+ * inline sub-composition HTML referenced via `data-composition-src`. This
9
+ * module is the single source of truth for that transformation, eliminating
10
+ * divergence that previously caused bugs (e.g. producer not setting
11
+ * `data-composition-file`).
12
+ */
13
+ import { type AssetExists } from "./rewriteSubCompPaths.js";
14
+ /** Marks each scene whose nodes a script outside it names by selector, id or class: a swap would strand it. */
15
+ export declare function refuseSwapsReachedByRootScripts(document: Document, rootScripts: string[]): void;
16
+ export interface InlineSubCompositionsOptions {
17
+ /**
18
+ * Resolve the HTML content for a sub-composition given its `data-composition-src` value.
19
+ * Return `null` when the file cannot be found.
20
+ */
21
+ resolveHtml: (srcPath: string) => string | null;
22
+ /**
23
+ * Parse an HTML string into a Document. The returned object must expose
24
+ * standard DOM APIs (querySelector, querySelectorAll, body, head, etc.).
25
+ * Both linkedom's `parseHTML(...).document` and the core bundler's
26
+ * `parseHTMLContent(...)` satisfy this contract.
27
+ */
28
+ parseHtml: (html: string) => Document;
29
+ /**
30
+ * Identity map produced by `assignBundledRuntimeCompositionIds`.
31
+ * When provided, authoredCompositionId and runtimeCompositionId are read
32
+ * from this map instead of from the host element's attributes directly.
33
+ * The bundler uses this; the producer can omit it.
34
+ */
35
+ hostIdentityMap?: Map<Element, {
36
+ authoredCompositionId: string | null;
37
+ runtimeCompositionId: string | null;
38
+ }>;
39
+ /**
40
+ * When true, rewrite `url(...)` references in inline `style` attributes
41
+ * on sub-composition elements. The bundler enables this; the producer
42
+ * can skip it.
43
+ */
44
+ rewriteInlineStyles?: boolean;
45
+ /**
46
+ * Prepare the inner root element before injecting it into the host.
47
+ * The bundler's `prepareFlattenedInnerRoot` clones the element, strips
48
+ * timing attributes, and adds `data-hf-inner-root`. When omitted, the
49
+ * inner root's outerHTML is injected as-is.
50
+ */
51
+ flattenInnerRoot?: (innerRoot: Element) => Element;
52
+ /**
53
+ * When true, CSS selectors targeting the authored root use a compound
54
+ * selector (`[scope][root]`) instead of a descendant (`[scope] [root]`).
55
+ * Enable this in the producer path where the inner root merges onto
56
+ * the host element via innerHTML — both attributes end up on the same
57
+ * element and a descendant selector won't match.
58
+ */
59
+ compoundAuthoredRoot?: boolean;
60
+ /**
61
+ * Read declared variable defaults from a sub-composition's `<html>` element.
62
+ * The bundler passes `readDeclaredDefaults`; the producer can omit this.
63
+ */
64
+ readVariableDefaults?: (docElement: Element) => Record<string, unknown>;
65
+ /**
66
+ * Parse host-level variable overrides from `data-variable-values`.
67
+ * The bundler passes `parseHostVariableValues`; the producer can omit this.
68
+ */
69
+ parseHostVariables?: (host: Element) => Record<string, unknown>;
70
+ /**
71
+ * Build a CSS attribute selector for scoping, e.g.
72
+ * `[data-composition-id="my-comp"]`. Defaults to a simple implementation
73
+ * when not provided. The bundler passes `cssAttributeSelector` which
74
+ * handles escaping.
75
+ */
76
+ buildScopeSelector?: (compId: string) => string;
77
+ /**
78
+ * Error label prefix used in wrapped composition scripts.
79
+ * Defaults to `"[HyperFrames] composition script error:"`.
80
+ */
81
+ scriptErrorLabel?: string;
82
+ /**
83
+ * Probe for "does this project-root-relative path exist?". Supplied by
84
+ * callers that can see the filesystem so a sub-composition's SIBLING asset
85
+ * refs (`<link href="_shared.css">` next to the composition) resolve against
86
+ * its own directory instead of 404ing at the project root. Omit it and plain
87
+ * relative paths pass through unchanged. See `AssetExists`.
88
+ */
89
+ assetExists?: AssetExists;
90
+ /**
91
+ * Log a warning when a composition file cannot be resolved. `reason` is a
92
+ * short, human-readable explanation (e.g. "the file is empty (0 bytes or
93
+ * whitespace-only)") from `checkSubCompositionUsability` — present for
94
+ * every skip except when `resolveHtml` returns `null` (file not found,
95
+ * which callers detect themselves before calling `resolveHtml`).
96
+ * Defaults to `console.warn`.
97
+ */
98
+ onMissingComposition?: (srcPath: string, reason?: string) => void;
99
+ /** Tag each top-level host with `data-hf-scene` and report every part's scene, for preview swaps. */
100
+ tagScenes?: boolean;
101
+ }
102
+ export interface ExternalLink {
103
+ href: string;
104
+ rel: string;
105
+ crossorigin?: string;
106
+ media?: string;
107
+ title?: string;
108
+ type?: string;
109
+ disabled?: true;
110
+ }
111
+ /** Appends a hoisted link unless the document already has a live one it would duplicate. */
112
+ export declare function ensureExternalLinkTag(doc: Document, link: ExternalLink): void;
113
+ export interface InlineSubCompositionsResult {
114
+ styles: CompositionStyle[];
115
+ /** With `tagScenes`: the scene each entry of `styles` belongs to. */
116
+ styleScenes: string[];
117
+ scripts: string[];
118
+ externalScriptSrcs: string[];
119
+ scriptItems: Array<{
120
+ kind: "inline";
121
+ content: string;
122
+ scene?: string;
123
+ } | ({
124
+ kind: "external";
125
+ src: string;
126
+ scene?: string;
127
+ } & ExternalScriptAttributes)>;
128
+ /** May list one link more than once; `ensureExternalLinkTag` dedupes. */
129
+ externalLinks: ExternalLink[];
130
+ variablesByComp: Record<string, Record<string, unknown>>;
131
+ /** Mounted files' import maps, addresses rebased; emit with `emitMountedModuleScripts`. */
132
+ importMaps: ImportMap[];
133
+ /** Mounted files' inline module scripts, each already carrying its scoped `__hyperframes`. */
134
+ moduleScripts: string[];
135
+ }
136
+ /**
137
+ * Inline sub-compositions into a document. For each host element in `hosts`:
138
+ *
139
+ * 1. Resolve the sub-composition HTML via `options.resolveHtml`
140
+ * 2. Parse it, resolve template, body, or bare-fragment content
141
+ * 3. Find the inner `[data-composition-id]` root
142
+ * 4. Extract `<style>` elements, scope CSS, collect them
143
+ * 5. Extract `<script>` elements, wrap inline scripts, collect them
144
+ * 6. Collect external script `src` URLs for deduplication
145
+ * 7. Rewrite asset paths (and optionally inline-style asset URLs)
146
+ * 8. Copy dimension attrs from inner root to host if missing
147
+ * 9. Set `data-composition-file` on host
148
+ * 10. Remove `data-composition-src` from host
149
+ * 11. Inject the content into the host element
150
+ */
151
+ export declare function inlineSubCompositions(document: Document, hosts: Element[], options: InlineSubCompositionsOptions): InlineSubCompositionsResult;
@@ -0,0 +1 @@
1
+ export { rewriteAssetPath, rewriteAssetPaths, rewriteInlineStyleAssetUrls, rewriteCssAssetUrls, type AssetExists, } from "@hyperframes/parsers/asset-paths";
@@ -0,0 +1,31 @@
1
+ export interface InlineScriptRun {
2
+ members: Element[];
3
+ /** First later script that executes on its own; the merged run must stay before it. Null: end of body. */
4
+ anchor: Element | null;
5
+ }
6
+ /** Groups body scripts into runs of classic inline scripts split by any script that executes
7
+ * separately (src, module, or one the caller pins in place), so merging a run never reorders it past one. */
8
+ export declare function inlineScriptRuns(scripts: readonly Element[], isPinned?: (el: Element) => boolean): InlineScriptRun[];
9
+ export declare const AFTER_FONTS_SCRIPT_TYPE = "text/hf-after-fonts";
10
+ export declare const AFTER_FONTS_SCRIPTS = "script[type=\"text/hf-after-fonts\"], script[type=\"text/hf-after-fonts+module\"]";
11
+ export declare const AFTER_FONTS_CLAIM = "__hfAfterFontsClaimed";
12
+ export declare const INLINED_FILE_ATTR = "data-hf-inlined-src";
13
+ export declare const COMPOSITION_SOURCE_URL = "hyperframes-composition://body";
14
+ export declare const DEFERRED_FILE = "[defer][src], [defer][data-hf-inlined-src]";
15
+ /** Gives each body script a type the browser does not run, so the runtime can run it once web fonts are ready. */
16
+ export declare function deferScriptsUntilFonts(document: Document, isFramework?: (el: Element) => boolean): void;
17
+ export declare function typeAfterFonts(el: Element): string | null;
18
+ /** Undefined for a type the browser never applies as CSS; `media="all"` and an empty title count as none. */
19
+ export declare function cssStyleMergeKey(el: Element): string | undefined;
20
+ export declare const UNCONDITIONAL_CSS_KEY: string;
21
+ export declare function hasSameLink(scope: ParentNode, link: Element): boolean;
22
+ /** Groups head styles into runs of adjacent styles with one merge key, so merging a run never reorders rules. */
23
+ export declare function headStyleRuns(styles: readonly Element[], isPinned?: (el: Element) => boolean): Element[][];
24
+ export interface CompositionStyle {
25
+ css: string;
26
+ media: string | null;
27
+ title: string | null;
28
+ }
29
+ export declare function compositionStyle(el: Element, css: string): CompositionStyle;
30
+ /** One `<style>` per adjacent run of same-condition sheets, keeping each run's media and title. */
31
+ export declare function styleElementsFor(document: Document, sheets: readonly CompositionStyle[], join: (css: string[]) => string): Element[];
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Shared low-level scanner: walk a CSS selector and replace whole-token
3
+ * `#id` occurrences that sit outside quotes and attribute-selector brackets.
4
+ *
5
+ * Extracted from `compositionScoping.ts`'s authored-root-id rewrite (the
6
+ * original, single-id version of this scan) so `svgIdNamespacing.ts` can
7
+ * reuse the exact same quote/bracket-tracking logic for its many-id rewrite
8
+ * instead of a second, drifting copy of the same state machine.
9
+ *
10
+ * Split into two small passes rather than one branch-heavy loop: first mark
11
+ * which offsets are outside a quoted string or an attribute-selector
12
+ * bracket (`markUnguardedOffsets`), then walk the selector once more,
13
+ * consulting that mask, to actually splice in replacements
14
+ * (`replaceSelectorIdTokens`). Each pass stays simple enough to read at a
15
+ * glance instead of one function juggling both jobs.
16
+ *
17
+ * The `#id` token is read as a CSS identifier per CSS Syntax Level 3
18
+ * (`decodeCssIdentifierAt`): `\.`-style and `\HEX `-style escapes are
19
+ * decoded before the id is compared against the candidate list, so a
20
+ * stylesheet spelling `#fx\.1` matches the element whose raw `id` attribute
21
+ * is `fx.1`. Callers emit replacement selectors through
22
+ * `escapeCssIdentifier`, the inverse operation.
23
+ */
24
+ /**
25
+ * Read one CSS identifier starting at `start` and return its decoded value
26
+ * plus the offset just past it, or `null` when no identifier starts there.
27
+ * Follows the "consume an ident sequence" algorithm of CSS Syntax Level 3.
28
+ */
29
+ export declare function decodeCssIdentifierAt(text: string, start: number): {
30
+ value: string;
31
+ end: number;
32
+ } | null;
33
+ /**
34
+ * Serialize `value` as a CSS identifier — the `CSS.escape()` algorithm from
35
+ * CSSOM, implemented here because Node has no `CSS` global. Every output is
36
+ * a valid `#ident` selector body that `decodeCssIdentifierAt` round-trips
37
+ * back to `value`.
38
+ */
39
+ export declare function escapeCssIdentifier(value: string): string;
40
+ /**
41
+ * Replace every whole-token `#id` in `selector` whose DECODED identifier is
42
+ * in `candidateIds`, skipping occurrences inside a quoted string or an
43
+ * attribute-selector bracket.
44
+ *
45
+ * Because the whole identifier is consumed before comparing, `#clip2` is
46
+ * never mistaken for `#clip`, and `#fx\.1` matches the candidate `fx.1`.
47
+ * `resolveReplacement` receives the matched (decoded) id and returns the
48
+ * full replacement text (including its own leading `#`, if any) to splice
49
+ * in.
50
+ */
51
+ export declare function replaceSelectorIdTokens(selector: string, candidateIds: readonly string[], resolveReplacement: (matchedId: string) => string): string;
52
+ export declare function escapeCssAttributeValue(value: string): string;
53
+ type AttributeNamespace = {
54
+ kind: "any";
55
+ } | {
56
+ kind: "none";
57
+ } | {
58
+ kind: "named";
59
+ prefix: string;
60
+ };
61
+ export declare function parseAttributeSelector(predicate: string): {
62
+ name: string;
63
+ rawName: string;
64
+ namespace: AttributeNamespace;
65
+ operator: "=" | "~=" | "|=" | "^=" | "$=" | "*=";
66
+ value: string;
67
+ flag: string | undefined;
68
+ } | null;
69
+ export declare function replaceSelectorAttributeTokens(selector: string, rewrite: (predicate: string) => string): string;
70
+ export {};
@@ -0,0 +1,2 @@
1
+ export declare function isTemplateEntry(html: string): boolean;
2
+ export declare function extractStandaloneEntryFromIndex(indexHtml: string, entryFile: string, entryHtml?: string): string | null;
@@ -0,0 +1,7 @@
1
+ export type HyperframeStaticFailureReason = "missing_composition_id" | "missing_composition_dimensions" | "missing_timeline_registry" | "invalid_script_syntax" | "invalid_static_hyperframe_contract";
2
+ export type HyperframeStaticGuardResult = {
3
+ isValid: boolean;
4
+ missingKeys: string[];
5
+ failureReason: HyperframeStaticFailureReason | null;
6
+ };
7
+ export declare function validateHyperframeHtmlContract(html: string): Promise<HyperframeStaticGuardResult>;