@onmark/cli 0.4.0 → 0.5.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.
- package/onmark-release.json +47 -47
- package/package.json +4 -4
- package/packages/authoring/dist/src/presentation.js +127 -6
- package/packages/bundler/dist/src/authored_html.d.ts +2 -0
- package/packages/bundler/dist/src/authored_html.js +30 -0
- package/packages/bundler/dist/src/command.js +10 -6
- package/packages/bundler/dist/src/generated/bundle-manifest.d.ts +4 -5
- package/packages/bundler/dist/src/generated/bundle-manifest.js +1 -0
- package/packages/bundler/dist/src/presentation.d.ts +1 -1
- package/packages/bundler/dist/src/presentation.js +13 -2
- package/packages/runtime/dist/src/generated/browser-request.d.ts +5 -1
- package/packages/runtime/dist/src/generated/browser-response.d.ts +46 -1
- package/packages/runtime/dist/src/generated/bundle-layout.d.ts +1 -1
- package/packages/runtime/dist/src/generated/bundle-layout.js +1 -0
- package/packages/runtime/dist/src/generated/runtime-contract.d.ts +3 -1
- package/packages/runtime/dist/src/generated/runtime-contract.js +3 -1
- package/packages/runtime/dist/src/generated/validators.js +1172 -465
- package/packages/runtime/dist/src/index.d.ts +3 -3
- package/packages/runtime/dist/src/index.js +1 -1
- package/packages/runtime/dist/src/presentation.d.ts +8 -3
- package/packages/runtime/dist/src/presentation.js +97 -7
- package/packages/runtime/dist/src/session.d.ts +7 -3
- package/packages/runtime/dist/src/session.js +17 -9
- package/packages/runtime/dist/src/types.d.ts +2 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { ProtocolDecodeError, decodeBrowserRequest, decodeBrowserResponse, } from "./generated/codec.js";
|
|
2
2
|
export type { BrowserRequest } from "./generated/browser-request.js";
|
|
3
|
-
export type { BrowserResponse } from "./generated/browser-response.js";
|
|
3
|
+
export type { BrowserMediaLayout, BrowserMediaPlacement, BrowserResponse, } from "./generated/browser-response.js";
|
|
4
4
|
export type { BrowserPlan, BrowserVideo } from "./generated/browser-request.js";
|
|
5
5
|
export { runtimeFrameAt, type RuntimeFrame } from "./clock.js";
|
|
6
6
|
export { videoFrameSelection, type RuntimeVideo, type VideoFrameSelection, } from "./media.js";
|
|
@@ -8,6 +8,6 @@ export { DecodedVideo, materializedVideoSource, type BrowserVideoElement, type D
|
|
|
8
8
|
export { MAX_PRESENTATION_EFFECTS, PresentationRuntimeAdapter, type ContainerPresentation, type FrameEffect, type OverlayPresentation, type PresentationBindings, type PresentationExtensions, type RuntimeOverlay, type RuntimeNode, type RuntimeScene, type RuntimeShot, type RuntimeTransition, type TransitionPresentation, type VideoPresentation, } from "./presentation.js";
|
|
9
9
|
export { MAX_PRESENTATION_RESOURCES, PRESENTATION_RESOURCE_KINDS, type PresentationResource, type PresentationResourceKind, } from "./resource.js";
|
|
10
10
|
export { BUNDLE_ASSET_DIRECTORY, PRESENTATION_TEMPORAL_CAPABILITIES, type PresentationTemporalCapability, } from "./generated/bundle-layout.js";
|
|
11
|
-
export { BROWSER_PROTOCOL_VERSION, MAX_BROWSER_OVERLAYS, MAX_BROWSER_OVERLAY_TEXT_CHARACTERS, MAX_BROWSER_VIDEOS, MAX_BROWSER_TRANSITIONS, MAX_FAILURE_MESSAGE_CHARACTERS, MAX_PENDING_RESOURCE_CHARACTERS, MAX_PENDING_RESOURCES, } from "./generated/runtime-contract.js";
|
|
11
|
+
export { BROWSER_PROTOCOL_VERSION, BROWSER_OBJECT_POSITION_SCALE, MAX_BROWSER_MEDIA_LAYOUTS, MAX_BROWSER_OVERLAYS, MAX_BROWSER_OVERLAY_TEXT_CHARACTERS, MAX_BROWSER_VIDEOS, MAX_BROWSER_TRANSITIONS, MAX_FAILURE_MESSAGE_CHARACTERS, MAX_PENDING_RESOURCE_CHARACTERS, MAX_PENDING_RESOURCES, } from "./generated/runtime-contract.js";
|
|
12
12
|
export { RUNTIME_HOST_NAME, installRuntimeHost, type RuntimeHost, } from "./host.js";
|
|
13
|
-
export { RuntimeAdapterError, RuntimeSession, type RuntimeAdapter, type RuntimeAdapterFailureKind, type RuntimePlan, } from "./session.js";
|
|
13
|
+
export { RuntimeAdapterError, RuntimeSession, type RuntimeAdapter, type RuntimeAdapterFailureKind, type RuntimeMediaMode, type RuntimePlan, } from "./session.js";
|
|
@@ -7,6 +7,6 @@ export { DecodedVideo, materializedVideoSource, } from "./video.js";
|
|
|
7
7
|
export { MAX_PRESENTATION_EFFECTS, PresentationRuntimeAdapter, } from "./presentation.js";
|
|
8
8
|
export { MAX_PRESENTATION_RESOURCES, PRESENTATION_RESOURCE_KINDS, } from "./resource.js";
|
|
9
9
|
export { BUNDLE_ASSET_DIRECTORY, PRESENTATION_TEMPORAL_CAPABILITIES, } from "./generated/bundle-layout.js";
|
|
10
|
-
export { BROWSER_PROTOCOL_VERSION, MAX_BROWSER_OVERLAYS, MAX_BROWSER_OVERLAY_TEXT_CHARACTERS, MAX_BROWSER_VIDEOS, MAX_BROWSER_TRANSITIONS, MAX_FAILURE_MESSAGE_CHARACTERS, MAX_PENDING_RESOURCE_CHARACTERS, MAX_PENDING_RESOURCES, } from "./generated/runtime-contract.js";
|
|
10
|
+
export { BROWSER_PROTOCOL_VERSION, BROWSER_OBJECT_POSITION_SCALE, MAX_BROWSER_MEDIA_LAYOUTS, MAX_BROWSER_OVERLAYS, MAX_BROWSER_OVERLAY_TEXT_CHARACTERS, MAX_BROWSER_VIDEOS, MAX_BROWSER_TRANSITIONS, MAX_FAILURE_MESSAGE_CHARACTERS, MAX_PENDING_RESOURCE_CHARACTERS, MAX_PENDING_RESOURCES, } from "./generated/runtime-contract.js";
|
|
11
11
|
export { RUNTIME_HOST_NAME, installRuntimeHost, } from "./host.js";
|
|
12
12
|
export { RuntimeAdapterError, RuntimeSession, } from "./session.js";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { RuntimeFrame } from "./clock.js";
|
|
2
|
+
import type { BrowserMediaLayout, BrowserMediaPlacement } from "./generated/browser-response.js";
|
|
2
3
|
import { type RuntimeVideo } from "./media.js";
|
|
3
|
-
import { type RuntimeAdapter, type RuntimePlan } from "./session.js";
|
|
4
|
+
import { type RuntimeAdapter, type RuntimeMediaMode, type RuntimePlan } from "./session.js";
|
|
4
5
|
import { type BrowserVideoElement } from "./video.js";
|
|
5
6
|
import { type PresentationResource } from "./resource.js";
|
|
6
7
|
/** Maximum exact-frame effects retained by one presentation adapter. */
|
|
@@ -25,6 +26,10 @@ export interface ContainerPresentation {
|
|
|
25
26
|
export interface VideoPresentation {
|
|
26
27
|
readonly element: BrowserVideoElement;
|
|
27
28
|
readonly source: string;
|
|
29
|
+
/** Includes the media box in layout without exposing its pixels. */
|
|
30
|
+
setLayoutVisible(visible: boolean): void;
|
|
31
|
+
/** Measures one visible layout-only media box. */
|
|
32
|
+
measureLayout(): BrowserMediaPlacement;
|
|
28
33
|
setVisible(visible: boolean): void;
|
|
29
34
|
dispose(): void;
|
|
30
35
|
}
|
|
@@ -68,8 +73,8 @@ export interface PresentationBindings {
|
|
|
68
73
|
export declare class PresentationRuntimeAdapter implements RuntimeAdapter {
|
|
69
74
|
#private;
|
|
70
75
|
constructor(bindings: PresentationBindings, readinessTimeoutMilliseconds: number);
|
|
71
|
-
load(plan: RuntimePlan): Promise<void>;
|
|
72
|
-
prepare(_frame: RuntimeFrame): Promise<
|
|
76
|
+
load(plan: RuntimePlan, mediaMode?: RuntimeMediaMode): Promise<void>;
|
|
77
|
+
prepare(_frame: RuntimeFrame): Promise<BrowserMediaLayout>;
|
|
73
78
|
seek(frame: RuntimeFrame): Promise<void>;
|
|
74
79
|
confirm(frame: RuntimeFrame): Promise<void>;
|
|
75
80
|
dispose(): Promise<void>;
|
|
@@ -21,7 +21,7 @@ export class PresentationRuntimeAdapter {
|
|
|
21
21
|
this.#bindings = bindings;
|
|
22
22
|
this.#readinessTimeoutMilliseconds = readinessTimeoutMilliseconds;
|
|
23
23
|
}
|
|
24
|
-
async load(plan) {
|
|
24
|
+
async load(plan, mediaMode = "decoded") {
|
|
25
25
|
if (this.#state.kind !== "empty") {
|
|
26
26
|
throw new RuntimeAdapterError("operation", "presentation load requires the empty state");
|
|
27
27
|
}
|
|
@@ -34,12 +34,13 @@ export class PresentationRuntimeAdapter {
|
|
|
34
34
|
};
|
|
35
35
|
let boundStructure;
|
|
36
36
|
const videos = [];
|
|
37
|
+
const layoutVideos = [];
|
|
37
38
|
const overlays = [];
|
|
38
39
|
const transitions = [];
|
|
39
40
|
try {
|
|
40
41
|
boundStructure = this.#bindStructure(plan, structure);
|
|
41
42
|
this.#bindTransitions(plan, transitions);
|
|
42
|
-
this.#bindVideos(plan, videos);
|
|
43
|
+
this.#bindVideos(plan, mediaMode, videos, layoutVideos);
|
|
43
44
|
this.#bindOverlays(plan, overlays);
|
|
44
45
|
const extensions = await this.#bindings.bindExtensions(plan);
|
|
45
46
|
// Take both returned collections before either ownership projection or
|
|
@@ -53,7 +54,7 @@ export class PresentationRuntimeAdapter {
|
|
|
53
54
|
await loadVideos(videos);
|
|
54
55
|
}
|
|
55
56
|
catch (error) {
|
|
56
|
-
const cleanupFailure = await releasePresentation(effects, resources, structure, transitions, videos, overlays);
|
|
57
|
+
const cleanupFailure = await releasePresentation(effects, resources, structure, transitions, videos, layoutVideos, overlays);
|
|
57
58
|
// A binding attempt may mutate author-owned state that generic cleanup
|
|
58
59
|
// cannot prove reusable. A fresh page owns the only valid retry.
|
|
59
60
|
this.#state = { kind: "disposed" };
|
|
@@ -67,6 +68,7 @@ export class PresentationRuntimeAdapter {
|
|
|
67
68
|
structure: boundStructure,
|
|
68
69
|
transitions,
|
|
69
70
|
videos,
|
|
71
|
+
layoutVideos,
|
|
70
72
|
overlays,
|
|
71
73
|
};
|
|
72
74
|
}
|
|
@@ -74,10 +76,11 @@ export class PresentationRuntimeAdapter {
|
|
|
74
76
|
const state = this.#loadedState("prepare");
|
|
75
77
|
try {
|
|
76
78
|
await preparePresentationResources(state.resources, this.#readinessTimeoutMilliseconds);
|
|
79
|
+
return measureMediaLayout(state.layoutVideos, state.structure);
|
|
77
80
|
}
|
|
78
81
|
catch (error) {
|
|
79
82
|
this.#state = { ...state, kind: "failed" };
|
|
80
|
-
throw error;
|
|
83
|
+
throw RuntimeAdapterError.fromUnknown(error, "presentation preparation failed");
|
|
81
84
|
}
|
|
82
85
|
}
|
|
83
86
|
async seek(frame) {
|
|
@@ -125,7 +128,7 @@ export class PresentationRuntimeAdapter {
|
|
|
125
128
|
: undefined;
|
|
126
129
|
this.#state = { kind: "disposed" };
|
|
127
130
|
this.#staged = undefined;
|
|
128
|
-
const failure = await releasePresentation(loaded?.effects ?? [], loaded?.resources ?? [], loaded?.structure, loaded?.transitions ?? [], loaded?.videos ?? [], loaded?.overlays ?? []);
|
|
131
|
+
const failure = await releasePresentation(loaded?.effects ?? [], loaded?.resources ?? [], loaded?.structure, loaded?.transitions ?? [], loaded?.videos ?? [], loaded?.layoutVideos ?? [], loaded?.overlays ?? []);
|
|
129
132
|
if (failure !== undefined) {
|
|
130
133
|
throw RuntimeAdapterError.fromUnknown(failure, "presentation cleanup failed");
|
|
131
134
|
}
|
|
@@ -150,9 +153,17 @@ export class PresentationRuntimeAdapter {
|
|
|
150
153
|
shots: structure.shots,
|
|
151
154
|
};
|
|
152
155
|
}
|
|
153
|
-
#bindVideos(plan, videos) {
|
|
156
|
+
#bindVideos(plan, mediaMode, videos, layoutVideos) {
|
|
157
|
+
if (mediaMode === "omitted") {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
154
160
|
for (const placement of plan.videos) {
|
|
155
161
|
const presentation = this.#bindings.bindVideo(placement);
|
|
162
|
+
if (mediaMode === "layoutOnly") {
|
|
163
|
+
layoutVideos.push({ placement, presentation });
|
|
164
|
+
presentation.setVisible(false);
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
156
167
|
const resource = new DecodedVideo({
|
|
157
168
|
element: presentation.element,
|
|
158
169
|
nodeId: placement.node.nodeId,
|
|
@@ -301,7 +312,7 @@ function presentationLoadFailure(error, cleanupFailure) {
|
|
|
301
312
|
}
|
|
302
313
|
return RuntimeAdapterError.fromUnknown(error, "presentation failed to load");
|
|
303
314
|
}
|
|
304
|
-
async function releasePresentation(effects, resources, structure, transitions, videos, overlays) {
|
|
315
|
+
async function releasePresentation(effects, resources, structure, transitions, videos, layoutVideos, overlays) {
|
|
305
316
|
let failure = await releaseFrameEffects(effects);
|
|
306
317
|
const resourceFailure = await releasePresentationResources(resources);
|
|
307
318
|
failure ??= resourceFailure;
|
|
@@ -309,6 +320,10 @@ async function releasePresentation(effects, resources, structure, transitions, v
|
|
|
309
320
|
const releaseFailure = releaseVideo(video);
|
|
310
321
|
failure ??= releaseFailure;
|
|
311
322
|
}
|
|
323
|
+
for (const video of layoutVideos) {
|
|
324
|
+
const releaseFailure = releaseLayoutVideo(video);
|
|
325
|
+
failure ??= releaseFailure;
|
|
326
|
+
}
|
|
312
327
|
for (const overlay of overlays) {
|
|
313
328
|
const releaseFailure = releaseOverlay(overlay);
|
|
314
329
|
failure ??= releaseFailure;
|
|
@@ -321,6 +336,75 @@ async function releasePresentation(effects, resources, structure, transitions, v
|
|
|
321
336
|
failure ??= structureFailure;
|
|
322
337
|
return failure;
|
|
323
338
|
}
|
|
339
|
+
function measureMediaLayout(videos, structure) {
|
|
340
|
+
try {
|
|
341
|
+
return collectMediaLayout(videos, structure);
|
|
342
|
+
}
|
|
343
|
+
catch (error) {
|
|
344
|
+
throw mediaLayoutFailure(error);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
function collectMediaLayout(videos, structure) {
|
|
348
|
+
const byShot = groupLayoutVideos(videos);
|
|
349
|
+
const scenes = new Map(structure.scenes.map((scene) => [scene.placement.node.nodeId, scene]));
|
|
350
|
+
const placements = [];
|
|
351
|
+
for (const shot of structure.shots) {
|
|
352
|
+
const group = byShot.get(shot.placement.node.nodeId);
|
|
353
|
+
if (group === undefined) {
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
const scene = scenes.get(shot.placement.sceneId);
|
|
357
|
+
if (scene === undefined) {
|
|
358
|
+
throw new RuntimeAdapterError("operation", "layout-only video names an unbound scene");
|
|
359
|
+
}
|
|
360
|
+
scene.presentation.setVisible(true);
|
|
361
|
+
shot.presentation.setVisible(true);
|
|
362
|
+
for (const video of group) {
|
|
363
|
+
video.presentation.setLayoutVisible(true);
|
|
364
|
+
}
|
|
365
|
+
try {
|
|
366
|
+
for (const video of group) {
|
|
367
|
+
const placement = video.presentation.measureLayout();
|
|
368
|
+
if (placement.nodeId !== video.placement.node.nodeId) {
|
|
369
|
+
throw new RuntimeAdapterError("operation", "measured video layout names the wrong browser node");
|
|
370
|
+
}
|
|
371
|
+
placements.push(placement);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
finally {
|
|
375
|
+
for (const video of group) {
|
|
376
|
+
video.presentation.setLayoutVisible(false);
|
|
377
|
+
}
|
|
378
|
+
shot.presentation.setVisible(false);
|
|
379
|
+
scene.presentation.setVisible(false);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
// Freeze the owned array in place; generated JSON types remain mutable-shaped.
|
|
383
|
+
Object.freeze(placements);
|
|
384
|
+
return placements;
|
|
385
|
+
}
|
|
386
|
+
function mediaLayoutFailure(error) {
|
|
387
|
+
if (error instanceof RuntimeAdapterError) {
|
|
388
|
+
return error;
|
|
389
|
+
}
|
|
390
|
+
const message = error instanceof Error
|
|
391
|
+
? error.message
|
|
392
|
+
: "browser media layout measurement failed";
|
|
393
|
+
return new RuntimeAdapterError("operation", message);
|
|
394
|
+
}
|
|
395
|
+
function groupLayoutVideos(videos) {
|
|
396
|
+
const groups = new Map();
|
|
397
|
+
for (const video of videos) {
|
|
398
|
+
const group = groups.get(video.placement.shotId);
|
|
399
|
+
if (group === undefined) {
|
|
400
|
+
groups.set(video.placement.shotId, [video]);
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
group.push(video);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
return groups;
|
|
407
|
+
}
|
|
324
408
|
function releaseTransition(transition) {
|
|
325
409
|
return releaseAll([() => transition.dispose()]);
|
|
326
410
|
}
|
|
@@ -374,6 +458,12 @@ function releaseVideo(video) {
|
|
|
374
458
|
() => video.presentation.dispose(),
|
|
375
459
|
]);
|
|
376
460
|
}
|
|
461
|
+
function releaseLayoutVideo(video) {
|
|
462
|
+
return releaseAll([
|
|
463
|
+
() => video.presentation.setLayoutVisible(false),
|
|
464
|
+
() => video.presentation.dispose(),
|
|
465
|
+
]);
|
|
466
|
+
}
|
|
377
467
|
function releaseOverlay(overlay) {
|
|
378
468
|
return releaseAll([
|
|
379
469
|
() => overlay.presentation.setVisible(false),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BrowserPlan, BrowserRequest } from "./generated/browser-request.js";
|
|
2
|
-
import type { BrowserResponse } from "./generated/browser-response.js";
|
|
2
|
+
import type { BrowserMediaLayout, BrowserResponse } from "./generated/browser-response.js";
|
|
3
3
|
import { type RuntimeFrame } from "./clock.js";
|
|
4
4
|
type Immutable<T> = T extends object ? {
|
|
5
5
|
readonly [Key in keyof T]: Immutable<T[Key]>;
|
|
@@ -14,9 +14,9 @@ export type RuntimePlan = Immutable<BrowserPlan>;
|
|
|
14
14
|
*/
|
|
15
15
|
export interface RuntimeAdapter {
|
|
16
16
|
/** Installs one owned snapshot of the immutable browser plan. */
|
|
17
|
-
load(plan: RuntimePlan): Promise<void>;
|
|
17
|
+
load(plan: RuntimePlan, mediaMode: RuntimeMediaMode): Promise<void>;
|
|
18
18
|
/** Resolves only after resources at the evaluation start are stable. */
|
|
19
|
-
prepare(frame: RuntimeFrame): Promise<
|
|
19
|
+
prepare(frame: RuntimeFrame): Promise<BrowserMediaLayout>;
|
|
20
20
|
/** Stages one exact frame and registers media presentation observers. */
|
|
21
21
|
seek(frame: RuntimeFrame): Promise<void>;
|
|
22
22
|
/** Verifies media presentation after native compositor capture. */
|
|
@@ -24,6 +24,10 @@ export interface RuntimeAdapter {
|
|
|
24
24
|
/** Releases all resources owned by this adapter. */
|
|
25
25
|
dispose(): Promise<void>;
|
|
26
26
|
}
|
|
27
|
+
/** Browser responsibility selected before presentation loading begins. */
|
|
28
|
+
export type RuntimeMediaMode = Extract<BrowserRequest["command"], {
|
|
29
|
+
type: "load";
|
|
30
|
+
}>["mediaMode"];
|
|
27
31
|
export type RuntimeAdapterFailureKind = "operation" | "readinessTimeout";
|
|
28
32
|
/** Expected failure reported by a browser adapter. */
|
|
29
33
|
export declare class RuntimeAdapterError extends Error {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Owns command ordering and state while a narrow adapter owns browser effects;
|
|
3
3
|
// this split keeps protocol behavior deterministic and directly testable.
|
|
4
4
|
import { decodeBrowserResponse } from "./generated/codec.js";
|
|
5
|
-
import { BROWSER_PROTOCOL_VERSION, MAX_FAILURE_MESSAGE_CHARACTERS, MAX_PENDING_RESOURCE_CHARACTERS, MAX_PENDING_RESOURCES, } from "./generated/runtime-contract.js";
|
|
5
|
+
import { BROWSER_PROTOCOL_VERSION, MAX_BROWSER_MEDIA_LAYOUTS, MAX_FAILURE_MESSAGE_CHARACTERS, MAX_PENDING_RESOURCE_CHARACTERS, MAX_PENDING_RESOURCES, } from "./generated/runtime-contract.js";
|
|
6
6
|
import { runtimeFrameAt } from "./clock.js";
|
|
7
7
|
import { exactRatioIsCanonical, videoSourceMappingIsValid } from "./media.js";
|
|
8
8
|
/** Expected failure reported by a browser adapter. */
|
|
@@ -48,7 +48,7 @@ export class RuntimeSession {
|
|
|
48
48
|
#execute(request) {
|
|
49
49
|
switch (request.command.type) {
|
|
50
50
|
case "load":
|
|
51
|
-
return this.#load(request.requestId, request.command.plan);
|
|
51
|
+
return this.#load(request.requestId, request.command.plan, request.command.mediaMode);
|
|
52
52
|
case "prepare":
|
|
53
53
|
return this.#prepare(request.requestId, request.command.evaluationStart);
|
|
54
54
|
case "seek":
|
|
@@ -59,18 +59,18 @@ export class RuntimeSession {
|
|
|
59
59
|
return this.#dispose(request.requestId);
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
|
-
async #load(requestId, plan) {
|
|
62
|
+
async #load(requestId, plan, mediaMode) {
|
|
63
63
|
if (this.#state.kind !== "empty") {
|
|
64
64
|
return invalidRequest(requestId, "load requires an empty browser session");
|
|
65
65
|
}
|
|
66
|
-
const violation = planViolation(plan);
|
|
66
|
+
const violation = planViolation(plan, mediaMode);
|
|
67
67
|
if (violation !== undefined) {
|
|
68
68
|
return invalidRequest(requestId, violation);
|
|
69
69
|
}
|
|
70
70
|
const ownedPlan = snapshotPlan(plan);
|
|
71
71
|
const nextState = loadedState(ownedPlan);
|
|
72
72
|
try {
|
|
73
|
-
await this.#adapter.load(ownedPlan);
|
|
73
|
+
await this.#adapter.load(ownedPlan, mediaMode);
|
|
74
74
|
}
|
|
75
75
|
catch (error) {
|
|
76
76
|
// Loading may have entered author code and partially mutated its owned
|
|
@@ -89,7 +89,13 @@ export class RuntimeSession {
|
|
|
89
89
|
return invalidRequest(requestId, "prepare must use the plan evaluation start");
|
|
90
90
|
}
|
|
91
91
|
try {
|
|
92
|
-
await this.#adapter.prepare(runtimeFrameAt(evaluationStart, this.#state.frameRate));
|
|
92
|
+
const mediaLayout = await this.#adapter.prepare(runtimeFrameAt(evaluationStart, this.#state.frameRate));
|
|
93
|
+
this.#state = { ...this.#state, kind: "ready" };
|
|
94
|
+
return response(requestId, {
|
|
95
|
+
type: "prepared",
|
|
96
|
+
evaluationStart,
|
|
97
|
+
mediaLayout,
|
|
98
|
+
});
|
|
93
99
|
}
|
|
94
100
|
catch (error) {
|
|
95
101
|
// Preparation may have started author-owned asynchronous work that the
|
|
@@ -98,8 +104,6 @@ export class RuntimeSession {
|
|
|
98
104
|
this.#state = { kind: "failed" };
|
|
99
105
|
return readinessFailure(requestId, "prepareFailed", error);
|
|
100
106
|
}
|
|
101
|
-
this.#state = { ...this.#state, kind: "ready" };
|
|
102
|
-
return response(requestId, { type: "prepared", evaluationStart });
|
|
103
107
|
}
|
|
104
108
|
async #seek(requestId, frame) {
|
|
105
109
|
if (this.#state.kind !== "ready") {
|
|
@@ -199,7 +203,11 @@ function readinessFailure(requestId, operationCode, error) {
|
|
|
199
203
|
}
|
|
200
204
|
return operationFailure(requestId, operationCode, error);
|
|
201
205
|
}
|
|
202
|
-
function planViolation(plan) {
|
|
206
|
+
function planViolation(plan, mediaMode) {
|
|
207
|
+
if (mediaMode === "layoutOnly" &&
|
|
208
|
+
plan.videos.length > MAX_BROWSER_MEDIA_LAYOUTS) {
|
|
209
|
+
return "layout-only plan exceeds the browser media-layout limit";
|
|
210
|
+
}
|
|
203
211
|
if (!exactRatioIsCanonical(plan.frameRate)) {
|
|
204
212
|
return "plan frame rate is not canonical";
|
|
205
213
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export type { RuntimeFrame } from "./clock.js";
|
|
2
|
+
export type { BrowserMediaLayout, BrowserMediaPlacement, } from "./generated/browser-response.js";
|
|
2
3
|
export type { RuntimeVideo } from "./media.js";
|
|
3
4
|
export type { PresentationFrameBehavior, PresentationTemporalCapability, PresentationVisualCapability, } from "./generated/bundle-layout.js";
|
|
4
|
-
export type { RuntimePlan } from "./session.js";
|
|
5
|
+
export type { RuntimeMediaMode, RuntimePlan } from "./session.js";
|
|
5
6
|
export type { ContainerPresentation, FrameEffect, OverlayPresentation, PresentationBindings, PresentationExtensions, RuntimeOverlay, RuntimeNode, RuntimeScene, RuntimeShot, RuntimeTransition, TransitionPresentation, VideoPresentation, } from "./presentation.js";
|
|
6
7
|
export type { PresentationResource, PresentationResourceKind, } from "./resource.js";
|