@onmark/cli 0.3.0 → 0.4.0

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 (34) hide show
  1. package/onmark-release.json +83 -53
  2. package/package.json +4 -4
  3. package/packages/authoring/dist/src/frame-motion.d.ts +10 -2
  4. package/packages/authoring/dist/src/frame-motion.js +29 -6
  5. package/packages/authoring/dist/src/index.d.ts +2 -2
  6. package/packages/authoring/dist/src/motion.d.ts +16 -4
  7. package/packages/authoring/dist/src/presentation.js +34 -1
  8. package/packages/authoring/dist/src/types.d.ts +1 -1
  9. package/packages/bundler/dist/src/authored_html.d.ts +17 -7
  10. package/packages/bundler/dist/src/authored_html.js +79 -21
  11. package/packages/bundler/dist/src/bundle_projection.d.ts +9 -0
  12. package/packages/bundler/dist/src/bundle_projection.js +66 -0
  13. package/packages/bundler/dist/src/command.js +28 -8
  14. package/packages/bundler/dist/src/generated/bundle-projection-validator.d.ts +7 -0
  15. package/packages/bundler/dist/src/generated/bundle-projection-validator.js +432 -0
  16. package/packages/bundler/dist/src/generated/bundle-projection.d.ts +25 -0
  17. package/packages/bundler/dist/src/generated/bundle-projection.js +2 -0
  18. package/packages/bundler/dist/src/index.d.ts +1 -1
  19. package/packages/bundler/dist/src/presentation.d.ts +13 -6
  20. package/packages/bundler/dist/src/presentation.js +58 -28
  21. package/packages/motion-gsap/dist/src/index.d.ts +10 -2
  22. package/packages/motion-gsap/dist/src/index.js +27 -5
  23. package/packages/runtime/dist/src/generated/browser-request.d.ts +15 -2
  24. package/packages/runtime/dist/src/generated/browser-response.d.ts +1 -1
  25. package/packages/runtime/dist/src/generated/runtime-contract.d.ts +2 -0
  26. package/packages/runtime/dist/src/generated/runtime-contract.js +2 -0
  27. package/packages/runtime/dist/src/generated/validators.d.ts +2 -2
  28. package/packages/runtime/dist/src/generated/validators.js +331 -128
  29. package/packages/runtime/dist/src/index.d.ts +2 -2
  30. package/packages/runtime/dist/src/index.js +1 -1
  31. package/packages/runtime/dist/src/presentation.d.ts +10 -0
  32. package/packages/runtime/dist/src/presentation.js +18 -3
  33. package/packages/runtime/dist/src/session.js +61 -12
  34. package/packages/runtime/dist/src/types.d.ts +1 -1
@@ -0,0 +1,432 @@
1
+ // Generated by `cargo xtask schema`; do not edit.
2
+ "use strict";
3
+ export const validateBundleProjection = validate20;
4
+ const schema31 = {
5
+ $defs: {
6
+ BundleProjectionRegion: {
7
+ additionalProperties: false,
8
+ description: "Dense screenplay-order shots retained by one render region.",
9
+ properties: {
10
+ shotIndices: {
11
+ items: { format: "uint32", minimum: 0, type: "integer" },
12
+ maxItems: 10000,
13
+ minItems: 1,
14
+ type: "array",
15
+ },
16
+ },
17
+ required: ["shotIndices"],
18
+ type: "object",
19
+ },
20
+ BundleProjectionVersion: {
21
+ const: 1,
22
+ description: "Current immutable projection-plan version.",
23
+ format: "uint16",
24
+ maximum: 65535,
25
+ minimum: 0,
26
+ type: "integer",
27
+ },
28
+ },
29
+ $id: "https://onmark.dev/schemas/bundle-projection-v1.schema.json",
30
+ $schema: "https://json-schema.org/draft/2020-12/schema",
31
+ additionalProperties: false,
32
+ description: "Exact shot dependencies for every render region in output order.",
33
+ properties: {
34
+ regions: {
35
+ items: { $ref: "#/$defs/BundleProjectionRegion" },
36
+ maxItems: 10000,
37
+ minItems: 1,
38
+ type: "array",
39
+ },
40
+ version: { $ref: "#/$defs/BundleProjectionVersion" },
41
+ },
42
+ required: ["version", "regions"],
43
+ title: "BundleProjection",
44
+ type: "object",
45
+ };
46
+ const schema32 = {
47
+ additionalProperties: false,
48
+ description: "Dense screenplay-order shots retained by one render region.",
49
+ properties: {
50
+ shotIndices: {
51
+ items: { format: "uint32", minimum: 0, type: "integer" },
52
+ maxItems: 10000,
53
+ minItems: 1,
54
+ type: "array",
55
+ },
56
+ },
57
+ required: ["shotIndices"],
58
+ type: "object",
59
+ };
60
+ const schema33 = {
61
+ const: 1,
62
+ description: "Current immutable projection-plan version.",
63
+ format: "uint16",
64
+ maximum: 65535,
65
+ minimum: 0,
66
+ type: "integer",
67
+ };
68
+ function validate20(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {}, } = {}) {
69
+ /*# sourceURL="https://onmark.dev/schemas/bundle-projection-v1.schema.json" */ let vErrors = null;
70
+ let errors = 0;
71
+ const evaluated0 = validate20.evaluated;
72
+ if (evaluated0.dynamicProps) {
73
+ evaluated0.props = undefined;
74
+ }
75
+ if (evaluated0.dynamicItems) {
76
+ evaluated0.items = undefined;
77
+ }
78
+ if (data && typeof data == "object" && !Array.isArray(data)) {
79
+ if (data.version === undefined) {
80
+ const err0 = {
81
+ instancePath,
82
+ schemaPath: "#/required",
83
+ keyword: "required",
84
+ params: { missingProperty: "version" },
85
+ message: "must have required property '" + "version" + "'",
86
+ };
87
+ if (vErrors === null) {
88
+ vErrors = [err0];
89
+ }
90
+ else {
91
+ vErrors.push(err0);
92
+ }
93
+ errors++;
94
+ }
95
+ if (data.regions === undefined) {
96
+ const err1 = {
97
+ instancePath,
98
+ schemaPath: "#/required",
99
+ keyword: "required",
100
+ params: { missingProperty: "regions" },
101
+ message: "must have required property '" + "regions" + "'",
102
+ };
103
+ if (vErrors === null) {
104
+ vErrors = [err1];
105
+ }
106
+ else {
107
+ vErrors.push(err1);
108
+ }
109
+ errors++;
110
+ }
111
+ for (const key0 in data) {
112
+ if (!(key0 === "regions" || key0 === "version")) {
113
+ const err2 = {
114
+ instancePath,
115
+ schemaPath: "#/additionalProperties",
116
+ keyword: "additionalProperties",
117
+ params: { additionalProperty: key0 },
118
+ message: "must NOT have additional properties",
119
+ };
120
+ if (vErrors === null) {
121
+ vErrors = [err2];
122
+ }
123
+ else {
124
+ vErrors.push(err2);
125
+ }
126
+ errors++;
127
+ }
128
+ }
129
+ if (data.regions !== undefined) {
130
+ let data0 = data.regions;
131
+ if (Array.isArray(data0)) {
132
+ if (data0.length > 10000) {
133
+ const err3 = {
134
+ instancePath: instancePath + "/regions",
135
+ schemaPath: "#/properties/regions/maxItems",
136
+ keyword: "maxItems",
137
+ params: { limit: 10000 },
138
+ message: "must NOT have more than 10000 items",
139
+ };
140
+ if (vErrors === null) {
141
+ vErrors = [err3];
142
+ }
143
+ else {
144
+ vErrors.push(err3);
145
+ }
146
+ errors++;
147
+ }
148
+ if (data0.length < 1) {
149
+ const err4 = {
150
+ instancePath: instancePath + "/regions",
151
+ schemaPath: "#/properties/regions/minItems",
152
+ keyword: "minItems",
153
+ params: { limit: 1 },
154
+ message: "must NOT have fewer than 1 items",
155
+ };
156
+ if (vErrors === null) {
157
+ vErrors = [err4];
158
+ }
159
+ else {
160
+ vErrors.push(err4);
161
+ }
162
+ errors++;
163
+ }
164
+ const len0 = data0.length;
165
+ for (let i0 = 0; i0 < len0; i0++) {
166
+ let data1 = data0[i0];
167
+ if (data1 && typeof data1 == "object" && !Array.isArray(data1)) {
168
+ if (data1.shotIndices === undefined) {
169
+ const err5 = {
170
+ instancePath: instancePath + "/regions/" + i0,
171
+ schemaPath: "#/$defs/BundleProjectionRegion/required",
172
+ keyword: "required",
173
+ params: { missingProperty: "shotIndices" },
174
+ message: "must have required property '" + "shotIndices" + "'",
175
+ };
176
+ if (vErrors === null) {
177
+ vErrors = [err5];
178
+ }
179
+ else {
180
+ vErrors.push(err5);
181
+ }
182
+ errors++;
183
+ }
184
+ for (const key1 in data1) {
185
+ if (!(key1 === "shotIndices")) {
186
+ const err6 = {
187
+ instancePath: instancePath + "/regions/" + i0,
188
+ schemaPath: "#/$defs/BundleProjectionRegion/additionalProperties",
189
+ keyword: "additionalProperties",
190
+ params: { additionalProperty: key1 },
191
+ message: "must NOT have additional properties",
192
+ };
193
+ if (vErrors === null) {
194
+ vErrors = [err6];
195
+ }
196
+ else {
197
+ vErrors.push(err6);
198
+ }
199
+ errors++;
200
+ }
201
+ }
202
+ if (data1.shotIndices !== undefined) {
203
+ let data2 = data1.shotIndices;
204
+ if (Array.isArray(data2)) {
205
+ if (data2.length > 10000) {
206
+ const err7 = {
207
+ instancePath: instancePath + "/regions/" + i0 + "/shotIndices",
208
+ schemaPath: "#/$defs/BundleProjectionRegion/properties/shotIndices/maxItems",
209
+ keyword: "maxItems",
210
+ params: { limit: 10000 },
211
+ message: "must NOT have more than 10000 items",
212
+ };
213
+ if (vErrors === null) {
214
+ vErrors = [err7];
215
+ }
216
+ else {
217
+ vErrors.push(err7);
218
+ }
219
+ errors++;
220
+ }
221
+ if (data2.length < 1) {
222
+ const err8 = {
223
+ instancePath: instancePath + "/regions/" + i0 + "/shotIndices",
224
+ schemaPath: "#/$defs/BundleProjectionRegion/properties/shotIndices/minItems",
225
+ keyword: "minItems",
226
+ params: { limit: 1 },
227
+ message: "must NOT have fewer than 1 items",
228
+ };
229
+ if (vErrors === null) {
230
+ vErrors = [err8];
231
+ }
232
+ else {
233
+ vErrors.push(err8);
234
+ }
235
+ errors++;
236
+ }
237
+ const len1 = data2.length;
238
+ for (let i1 = 0; i1 < len1; i1++) {
239
+ let data3 = data2[i1];
240
+ if (!(typeof data3 == "number" &&
241
+ !(data3 % 1) &&
242
+ !isNaN(data3) &&
243
+ isFinite(data3))) {
244
+ const err9 = {
245
+ instancePath: instancePath + "/regions/" + i0 + "/shotIndices/" + i1,
246
+ schemaPath: "#/$defs/BundleProjectionRegion/properties/shotIndices/items/type",
247
+ keyword: "type",
248
+ params: { type: "integer" },
249
+ message: "must be integer",
250
+ };
251
+ if (vErrors === null) {
252
+ vErrors = [err9];
253
+ }
254
+ else {
255
+ vErrors.push(err9);
256
+ }
257
+ errors++;
258
+ }
259
+ if (typeof data3 == "number" && isFinite(data3)) {
260
+ if (data3 < 0 || isNaN(data3)) {
261
+ const err10 = {
262
+ instancePath: instancePath +
263
+ "/regions/" +
264
+ i0 +
265
+ "/shotIndices/" +
266
+ i1,
267
+ schemaPath: "#/$defs/BundleProjectionRegion/properties/shotIndices/items/minimum",
268
+ keyword: "minimum",
269
+ params: { comparison: ">=", limit: 0 },
270
+ message: "must be >= 0",
271
+ };
272
+ if (vErrors === null) {
273
+ vErrors = [err10];
274
+ }
275
+ else {
276
+ vErrors.push(err10);
277
+ }
278
+ errors++;
279
+ }
280
+ }
281
+ }
282
+ }
283
+ else {
284
+ const err11 = {
285
+ instancePath: instancePath + "/regions/" + i0 + "/shotIndices",
286
+ schemaPath: "#/$defs/BundleProjectionRegion/properties/shotIndices/type",
287
+ keyword: "type",
288
+ params: { type: "array" },
289
+ message: "must be array",
290
+ };
291
+ if (vErrors === null) {
292
+ vErrors = [err11];
293
+ }
294
+ else {
295
+ vErrors.push(err11);
296
+ }
297
+ errors++;
298
+ }
299
+ }
300
+ }
301
+ else {
302
+ const err12 = {
303
+ instancePath: instancePath + "/regions/" + i0,
304
+ schemaPath: "#/$defs/BundleProjectionRegion/type",
305
+ keyword: "type",
306
+ params: { type: "object" },
307
+ message: "must be object",
308
+ };
309
+ if (vErrors === null) {
310
+ vErrors = [err12];
311
+ }
312
+ else {
313
+ vErrors.push(err12);
314
+ }
315
+ errors++;
316
+ }
317
+ }
318
+ }
319
+ else {
320
+ const err13 = {
321
+ instancePath: instancePath + "/regions",
322
+ schemaPath: "#/properties/regions/type",
323
+ keyword: "type",
324
+ params: { type: "array" },
325
+ message: "must be array",
326
+ };
327
+ if (vErrors === null) {
328
+ vErrors = [err13];
329
+ }
330
+ else {
331
+ vErrors.push(err13);
332
+ }
333
+ errors++;
334
+ }
335
+ }
336
+ if (data.version !== undefined) {
337
+ let data4 = data.version;
338
+ if (!(typeof data4 == "number" &&
339
+ !(data4 % 1) &&
340
+ !isNaN(data4) &&
341
+ isFinite(data4))) {
342
+ const err14 = {
343
+ instancePath: instancePath + "/version",
344
+ schemaPath: "#/$defs/BundleProjectionVersion/type",
345
+ keyword: "type",
346
+ params: { type: "integer" },
347
+ message: "must be integer",
348
+ };
349
+ if (vErrors === null) {
350
+ vErrors = [err14];
351
+ }
352
+ else {
353
+ vErrors.push(err14);
354
+ }
355
+ errors++;
356
+ }
357
+ if (1 !== data4) {
358
+ const err15 = {
359
+ instancePath: instancePath + "/version",
360
+ schemaPath: "#/$defs/BundleProjectionVersion/const",
361
+ keyword: "const",
362
+ params: { allowedValue: 1 },
363
+ message: "must be equal to constant",
364
+ };
365
+ if (vErrors === null) {
366
+ vErrors = [err15];
367
+ }
368
+ else {
369
+ vErrors.push(err15);
370
+ }
371
+ errors++;
372
+ }
373
+ if (typeof data4 == "number" && isFinite(data4)) {
374
+ if (data4 > 65535 || isNaN(data4)) {
375
+ const err16 = {
376
+ instancePath: instancePath + "/version",
377
+ schemaPath: "#/$defs/BundleProjectionVersion/maximum",
378
+ keyword: "maximum",
379
+ params: { comparison: "<=", limit: 65535 },
380
+ message: "must be <= 65535",
381
+ };
382
+ if (vErrors === null) {
383
+ vErrors = [err16];
384
+ }
385
+ else {
386
+ vErrors.push(err16);
387
+ }
388
+ errors++;
389
+ }
390
+ if (data4 < 0 || isNaN(data4)) {
391
+ const err17 = {
392
+ instancePath: instancePath + "/version",
393
+ schemaPath: "#/$defs/BundleProjectionVersion/minimum",
394
+ keyword: "minimum",
395
+ params: { comparison: ">=", limit: 0 },
396
+ message: "must be >= 0",
397
+ };
398
+ if (vErrors === null) {
399
+ vErrors = [err17];
400
+ }
401
+ else {
402
+ vErrors.push(err17);
403
+ }
404
+ errors++;
405
+ }
406
+ }
407
+ }
408
+ }
409
+ else {
410
+ const err18 = {
411
+ instancePath,
412
+ schemaPath: "#/type",
413
+ keyword: "type",
414
+ params: { type: "object" },
415
+ message: "must be object",
416
+ };
417
+ if (vErrors === null) {
418
+ vErrors = [err18];
419
+ }
420
+ else {
421
+ vErrors.push(err18);
422
+ }
423
+ errors++;
424
+ }
425
+ validate20.errors = vErrors;
426
+ return errors === 0;
427
+ }
428
+ validate20.evaluated = {
429
+ props: true,
430
+ dynamicProps: false,
431
+ dynamicItems: false,
432
+ };
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Current immutable projection-plan version.
3
+ */
4
+ export type BundleProjectionVersion = 1;
5
+ /**
6
+ * Exact shot dependencies for every render region in output order.
7
+ */
8
+ export interface BundleProjection {
9
+ /**
10
+ * @minItems 1
11
+ * @maxItems 10000
12
+ */
13
+ regions: [BundleProjectionRegion, ...BundleProjectionRegion[]];
14
+ version: BundleProjectionVersion;
15
+ }
16
+ /**
17
+ * Dense screenplay-order shots retained by one render region.
18
+ */
19
+ export interface BundleProjectionRegion {
20
+ /**
21
+ * @minItems 1
22
+ * @maxItems 10000
23
+ */
24
+ shotIndices: [number, ...number[]];
25
+ }
@@ -0,0 +1,2 @@
1
+ // Generated by `cargo xtask schema`; edit Rust protocol types instead.
2
+ export {};
@@ -1,2 +1,2 @@
1
- export { BundleError, bundlePresentation, type BundleArtifact, type BundleErrorKind, type BundleFile, type BundleManifest, type BundleOptions, } from "./presentation.js";
1
+ export { BundleError, bundlePresentation, type BundleArtifact, type BundleErrorKind, type BundleFile, type BundleManifest, type BundleOptions, type BundleProjection, } from "./presentation.js";
2
2
  export { BUNDLE_ASSET_DIRECTORY, BUNDLE_ENTRY_POINT, BUNDLE_MANIFEST_FILE, BUNDLE_REGION_DIRECTORY, BUNDLE_TEMPORAL_CAPABILITIES, BUNDLE_VERSION, } from "./generated/bundle-manifest.js";
@@ -1,5 +1,6 @@
1
- import type { PresentationFrameBehavior, PresentationTemporalCapability, PresentationVisualCapability } from "../../../runtime/dist/src/index.js";
1
+ import type { PresentationFrameBehavior, PresentationVisualCapability } from "../../../runtime/dist/src/index.js";
2
2
  import { type BundleFile as WireBundleFile, type BundleManifest as WireBundleManifest } from "./generated/bundle-manifest.js";
3
+ import type { BundleProjection as WireBundleProjection } from "./generated/bundle-projection.js";
3
4
  type Immutable<T> = T extends object ? {
4
5
  readonly [Key in keyof T]: Immutable<T[Key]>;
5
6
  } : T;
@@ -7,18 +8,24 @@ type Immutable<T> = T extends object ? {
7
8
  export type BundleFile = Immutable<WireBundleFile>;
8
9
  /** Immutable view of the versioned Rust-owned bundle manifest. */
9
10
  export type BundleManifest = Immutable<WireBundleManifest>;
10
- /** Explicit inputs for one authored HTML document. */
11
- export interface BundleOptions {
12
- /** Authored document or a private snapshot containing its exact bytes. */
11
+ /** Immutable view of Rust-owned render-region shot selection. */
12
+ export type BundleProjection = Immutable<WireBundleProjection>;
13
+ interface BundleControls {
13
14
  readonly document: string;
14
- /** Base for inline-module imports when `document` is a private snapshot. */
15
15
  readonly resolveDirectory?: string;
16
16
  readonly outputDirectory: string;
17
17
  readonly maxOutputBytes: number;
18
- readonly temporalCapability: PresentationTemporalCapability;
19
18
  readonly visualCapability: PresentationVisualCapability;
20
19
  readonly frameBehavior: PresentationFrameBehavior;
21
20
  }
21
+ /** Explicit inputs for one authored HTML document. */
22
+ export type BundleOptions = BundleControls & ({
23
+ readonly temporalCapability: "sequential";
24
+ readonly projection?: never;
25
+ } | {
26
+ readonly temporalCapability: "randomAccess";
27
+ readonly projection: BundleProjection;
28
+ });
22
29
  /** Published directory and its owned immutable manifest snapshot. */
23
30
  export interface BundleArtifact {
24
31
  readonly directory: string;
@@ -6,7 +6,8 @@ import { createRequire } from "node:module";
6
6
  import { dirname, extname, isAbsolute, join, relative, resolve, sep, } from "node:path";
7
7
  import { build, } from "esbuild";
8
8
  import { BUNDLE_ENTRY_POINT, BUNDLE_FRAME_BEHAVIORS, BUNDLE_MANIFEST_FILE, BUNDLE_REGION_DIRECTORY, BUNDLE_TEMPORAL_CAPABILITIES, BUNDLE_VISUAL_CAPABILITIES, BUNDLE_VERSION, } from "./generated/bundle-manifest.js";
9
- import { AuthoredHtmlError, projectShotDocument, readAuthoredHtml, } from "./authored_html.js";
9
+ import { AuthoredHtmlError, projectRegionDocument, readAuthoredHtml, } from "./authored_html.js";
10
+ import { BundleProjectionError, decodeBundleProjection, } from "./bundle_projection.js";
10
11
  import { HtmlImageError, HtmlImageLimitError, projectedImageResources, } from "./html_image.js";
11
12
  import { hasAmbientImageAnimation } from "./image_admission.js";
12
13
  // Authored files live outside the package tree, so public facades resolve from
@@ -46,10 +47,10 @@ export class BundleError extends Error {
46
47
  // ── Build pipeline
47
48
  /** Builds one HTML-authored presentation without a parallel entry file. */
48
49
  export async function bundlePresentation(options) {
49
- const maxOutputBytes = validateOutputByteLimit(options.maxOutputBytes);
50
+ const controls = snapshotControls(options);
50
51
  let html;
51
52
  try {
52
- html = await readAuthoredHtml(options.document, maxOutputBytes, options.resolveDirectory);
53
+ html = await readAuthoredHtml(options.document, controls.maxOutputBytes, options.resolveDirectory);
53
54
  }
54
55
  catch (error) {
55
56
  if (error instanceof HtmlImageLimitError) {
@@ -60,17 +61,12 @@ export async function bundlePresentation(options) {
60
61
  }
61
62
  throw error;
62
63
  }
63
- return bundle({
64
- html,
65
- maxOutputBytes,
66
- outputDirectory: options.outputDirectory,
67
- temporalCapability: options.temporalCapability,
68
- visualCapability: options.visualCapability,
69
- frameBehavior: options.frameBehavior,
70
- });
64
+ return bundle(Object.freeze({
65
+ ...controls,
66
+ html: Object.freeze({ ...html }),
67
+ }));
71
68
  }
72
- async function bundle(options) {
73
- const input = validateInput(options);
69
+ async function bundle(input) {
74
70
  await requireAbsent(input.outputDirectory);
75
71
  await mkdir(dirname(input.outputDirectory), { recursive: true });
76
72
  const staging = await mkdtemp(join(dirname(input.outputDirectory), ".onmark-bundle-"));
@@ -105,7 +101,7 @@ async function buildArtifact(input, staging) {
105
101
  }))),
106
102
  });
107
103
  }
108
- function validateInput(options) {
104
+ function snapshotControls(options) {
109
105
  if (options.outputDirectory.length === 0) {
110
106
  throw new BundleError("configuration", "output directory cannot be empty");
111
107
  }
@@ -120,20 +116,54 @@ function validateInput(options) {
120
116
  temporalCapability !== "randomAccess") {
121
117
  throw new BundleError("configuration", "placement-bounded frames require random-access presentation timing");
122
118
  }
123
- return Object.freeze({
119
+ const input = {
124
120
  outputDirectory: resolve(options.outputDirectory),
125
121
  maxOutputBytes: options.maxOutputBytes,
126
- html: Object.freeze({ ...options.html }),
127
- temporalCapability,
128
122
  visualCapability,
129
123
  frameBehavior,
130
- });
124
+ };
125
+ return temporalCapability === "randomAccess"
126
+ ? Object.freeze({
127
+ ...input,
128
+ projection: snapshotProjection(requireProjection(options.projection)),
129
+ temporalCapability,
130
+ })
131
+ : Object.freeze({ ...input, temporalCapability });
131
132
  }
132
- function validateOutputByteLimit(value) {
133
- if (!Number.isSafeInteger(value) || value <= 0) {
134
- throw new BundleError("configuration", "maximum output bytes must be a positive safe integer");
133
+ function requireProjection(projection) {
134
+ if (projection === undefined) {
135
+ throw new BundleError("configuration", "random-access presentation requires a bundle projection");
136
+ }
137
+ return projection;
138
+ }
139
+ function snapshotProjection(projection) {
140
+ try {
141
+ projection = decodeBundleProjection(projection);
135
142
  }
136
- return value;
143
+ catch (error) {
144
+ if (error instanceof BundleProjectionError) {
145
+ throw new BundleError("configuration", error.message, error);
146
+ }
147
+ throw error;
148
+ }
149
+ const [first, ...rest] = projection.regions;
150
+ const regions = [
151
+ snapshotProjectionRegion(first),
152
+ ...rest.map(snapshotProjectionRegion),
153
+ ];
154
+ return Object.freeze({
155
+ version: projection.version,
156
+ regions: Object.freeze(regions),
157
+ });
158
+ }
159
+ function snapshotProjectionRegion(region) {
160
+ return Object.freeze({
161
+ shotIndices: snapshotShotIndices(region.shotIndices),
162
+ });
163
+ }
164
+ function snapshotShotIndices(indices) {
165
+ const [first, ...rest] = indices;
166
+ return Object.freeze([first, ...rest]);
137
167
  }
138
168
  function validateTemporalCapability(capability) {
139
169
  const admitted = BUNDLE_TEMPORAL_CAPABILITIES.find((candidate) => candidate === capability);
@@ -373,11 +403,11 @@ async function writeRegionArtifacts(staging, input, generated, resources, initia
373
403
  if (input.temporalCapability !== "randomAccess") {
374
404
  return [];
375
405
  }
376
- validateRegionCount(input.html.regions.length, generated.length + resources.length);
406
+ validateRegionCount(input.projection.regions.length, generated.length + resources.length);
377
407
  let remaining = initialBudget;
378
408
  const regions = [];
379
- for (const [index, region] of input.html.regions.entries()) {
380
- const document = projectShotDocument(input.html, region);
409
+ for (const [index, region] of input.projection.regions.entries()) {
410
+ const document = projectRegionDocument(input.html, region.shotIndices);
381
411
  const files = presentationFiles([
382
412
  ...generated,
383
413
  ...authoredResourceFiles(projectedImageResources(document.document, resources)),
@@ -386,7 +416,7 @@ async function writeRegionArtifacts(staging, input, generated, resources, initia
386
416
  const manifestBytes = encodeManifest(manifest);
387
417
  const entry = files.find((file) => file.path === BUNDLE_ENTRY_POINT);
388
418
  if (entry === undefined) {
389
- throw new BundleError("build", "shot-scoped bundle has no entry point");
419
+ throw new BundleError("build", "render-region bundle has no entry point");
390
420
  }
391
421
  remaining = consumeOutputBudget(remaining, entry.contents.byteLength);
392
422
  remaining = consumeOutputBudget(remaining, manifestBytes.byteLength);
@@ -411,11 +441,11 @@ async function writeRegionFiles(staging, directory, files) {
411
441
  }
412
442
  function validateRegionCount(regions, generated) {
413
443
  if (regions > MAX_REGION_ARTIFACTS) {
414
- throw new BundleError("outputLimit", "presentation exceeds the shot-scoped bundle limit");
444
+ throw new BundleError("outputLimit", "presentation exceeds the render-region bundle limit");
415
445
  }
416
446
  const links = regions * generated;
417
447
  if (!Number.isSafeInteger(links) || links > MAX_REGION_LINKS) {
418
- throw new BundleError("outputLimit", "presentation exceeds the shot-scoped bundle file limit");
448
+ throw new BundleError("outputLimit", "presentation exceeds the render-region bundle file limit");
419
449
  }
420
450
  }
421
451
  async function requireAbsent(outputDirectory) {