@scenar/cli 0.9.1 → 0.11.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 (175) hide show
  1. package/example-bundle/assets/index-DxmqjG-8.js +388 -0
  2. package/example-bundle/assets/style-B2sxnVVZ.css +1 -0
  3. package/example-bundle/embed.js +1 -1
  4. package/example-bundle/index.html +2 -2
  5. package/example-bundle/logo.png +0 -0
  6. package/example-bundle/pack-manifest.json +33 -9
  7. package/example-bundle/soundtrack/music.mp3 +0 -0
  8. package/example-bundle/soundtrack/sfx/click.mp3 +0 -0
  9. package/example-bundle/soundtrack/sfx/keystroke.mp3 +0 -0
  10. package/package.json +4 -4
  11. package/src/__tests__/collect-pack-shots.test.ts +27 -1
  12. package/src/__tests__/elevenlabs-provider.test.ts +187 -0
  13. package/src/__tests__/embed-snippet.test.ts +5 -0
  14. package/src/__tests__/find-authored-soundtrack.test.ts +54 -0
  15. package/src/__tests__/find-authored-title-cards.test.ts +65 -0
  16. package/src/__tests__/find-authored-viewport.test.ts +58 -0
  17. package/src/__tests__/load-bundle.test.ts +67 -0
  18. package/src/__tests__/narrate-command.test.ts +65 -1
  19. package/src/__tests__/narration-cache.test.ts +134 -0
  20. package/src/__tests__/pack-bundle-contract.test.ts +2 -0
  21. package/src/__tests__/pack-generate-embed-entry.test.ts +99 -16
  22. package/src/__tests__/presenter-command.test.ts +366 -0
  23. package/src/__tests__/render-command.test.ts +11 -0
  24. package/src/__tests__/render-generate-entry.test.ts +102 -0
  25. package/src/__tests__/resolve-pack-viewport.test.ts +46 -0
  26. package/src/__tests__/resolve-provider.test.ts +32 -3
  27. package/src/__tests__/scenario-validator.test.ts +174 -0
  28. package/src/__tests__/stage-assets.test.ts +269 -0
  29. package/src/commands/narrate.js +1 -1
  30. package/src/commands/narrate.js.map +1 -1
  31. package/src/commands/narrate.ts +1 -1
  32. package/src/commands/pack.d.ts.map +1 -1
  33. package/src/commands/pack.js +23 -4
  34. package/src/commands/pack.js.map +1 -1
  35. package/src/commands/pack.ts +26 -5
  36. package/src/commands/presenter.d.ts +3 -0
  37. package/src/commands/presenter.d.ts.map +1 -0
  38. package/src/commands/presenter.js +89 -0
  39. package/src/commands/presenter.js.map +1 -0
  40. package/src/commands/presenter.ts +107 -0
  41. package/src/commands/render.d.ts.map +1 -1
  42. package/src/commands/render.js +2 -0
  43. package/src/commands/render.js.map +1 -1
  44. package/src/commands/render.ts +6 -0
  45. package/src/embed/embed-snippet.d.ts +5 -0
  46. package/src/embed/embed-snippet.d.ts.map +1 -1
  47. package/src/embed/embed-snippet.js +6 -1
  48. package/src/embed/embed-snippet.js.map +1 -1
  49. package/src/embed/embed-snippet.ts +6 -1
  50. package/src/index.d.ts.map +1 -1
  51. package/src/index.js +2 -0
  52. package/src/index.js.map +1 -1
  53. package/src/index.ts +2 -0
  54. package/src/narrate/run-narrate.d.ts +15 -1
  55. package/src/narrate/run-narrate.d.ts.map +1 -1
  56. package/src/narrate/run-narrate.js +11 -4
  57. package/src/narrate/run-narrate.js.map +1 -1
  58. package/src/narrate/run-narrate.ts +15 -6
  59. package/src/pack/bundle-contract.d.ts +1 -0
  60. package/src/pack/bundle-contract.d.ts.map +1 -1
  61. package/src/pack/bundle-contract.js +3 -0
  62. package/src/pack/bundle-contract.js.map +1 -1
  63. package/src/pack/bundle-contract.ts +3 -0
  64. package/src/pack/collect-pack-shots.d.ts +16 -5
  65. package/src/pack/collect-pack-shots.d.ts.map +1 -1
  66. package/src/pack/collect-pack-shots.js +13 -4
  67. package/src/pack/collect-pack-shots.js.map +1 -1
  68. package/src/pack/collect-pack-shots.ts +35 -8
  69. package/src/pack/generate-embed-entry.d.ts +7 -0
  70. package/src/pack/generate-embed-entry.d.ts.map +1 -1
  71. package/src/pack/generate-embed-entry.js +105 -7
  72. package/src/pack/generate-embed-entry.js.map +1 -1
  73. package/src/pack/generate-embed-entry.ts +110 -7
  74. package/src/pack/run-pack.d.ts +8 -2
  75. package/src/pack/run-pack.d.ts.map +1 -1
  76. package/src/pack/run-pack.js +120 -17
  77. package/src/pack/run-pack.js.map +1 -1
  78. package/src/pack/run-pack.ts +164 -19
  79. package/src/pack/viewport.d.ts +17 -0
  80. package/src/pack/viewport.d.ts.map +1 -1
  81. package/src/pack/viewport.js +19 -0
  82. package/src/pack/viewport.js.map +1 -1
  83. package/src/pack/viewport.ts +29 -0
  84. package/src/presenter/heygen-client.d.ts +69 -0
  85. package/src/presenter/heygen-client.d.ts.map +1 -0
  86. package/src/presenter/heygen-client.js +154 -0
  87. package/src/presenter/heygen-client.js.map +1 -0
  88. package/src/presenter/heygen-client.ts +224 -0
  89. package/src/presenter/run-presenter.d.ts +67 -0
  90. package/src/presenter/run-presenter.d.ts.map +1 -0
  91. package/src/presenter/run-presenter.js +348 -0
  92. package/src/presenter/run-presenter.js.map +1 -0
  93. package/src/presenter/run-presenter.ts +536 -0
  94. package/src/render/generate-entry.d.ts +4 -0
  95. package/src/render/generate-entry.d.ts.map +1 -1
  96. package/src/render/generate-entry.js +75 -7
  97. package/src/render/generate-entry.js.map +1 -1
  98. package/src/render/generate-entry.ts +84 -7
  99. package/src/render/run-render.d.ts +6 -0
  100. package/src/render/run-render.d.ts.map +1 -1
  101. package/src/render/run-render.js +58 -0
  102. package/src/render/run-render.js.map +1 -1
  103. package/src/render/run-render.ts +72 -0
  104. package/src/render/stage-assets.d.ts +44 -0
  105. package/src/render/stage-assets.d.ts.map +1 -0
  106. package/src/render/stage-assets.js +91 -0
  107. package/src/render/stage-assets.js.map +1 -0
  108. package/src/render/stage-assets.ts +130 -0
  109. package/src/tts/echogarden.d.ts.map +1 -1
  110. package/src/tts/echogarden.js +4 -2
  111. package/src/tts/echogarden.js.map +1 -1
  112. package/src/tts/echogarden.ts +5 -2
  113. package/src/tts/edge-tts.d.ts.map +1 -1
  114. package/src/tts/edge-tts.js +2 -1
  115. package/src/tts/edge-tts.js.map +1 -1
  116. package/src/tts/edge-tts.ts +2 -1
  117. package/src/tts/elevenlabs.d.ts +15 -0
  118. package/src/tts/elevenlabs.d.ts.map +1 -0
  119. package/src/tts/elevenlabs.js +73 -0
  120. package/src/tts/elevenlabs.js.map +1 -0
  121. package/src/tts/elevenlabs.ts +105 -0
  122. package/src/tts/openai.d.ts.map +1 -1
  123. package/src/tts/openai.js +2 -1
  124. package/src/tts/openai.js.map +1 -1
  125. package/src/tts/openai.ts +2 -1
  126. package/src/tts/resolve-provider.d.ts +1 -1
  127. package/src/tts/resolve-provider.d.ts.map +1 -1
  128. package/src/tts/resolve-provider.js +10 -3
  129. package/src/tts/resolve-provider.js.map +1 -1
  130. package/src/tts/resolve-provider.ts +12 -4
  131. package/src/tts/types.d.ts +9 -0
  132. package/src/tts/types.d.ts.map +1 -1
  133. package/src/tts/types.ts +10 -0
  134. package/src/util/confirm.d.ts +11 -0
  135. package/src/util/confirm.d.ts.map +1 -0
  136. package/src/util/confirm.js +24 -0
  137. package/src/util/confirm.js.map +1 -0
  138. package/src/util/confirm.ts +23 -0
  139. package/src/util/load-bundle.d.ts +17 -1
  140. package/src/util/load-bundle.d.ts.map +1 -1
  141. package/src/util/load-bundle.js +19 -11
  142. package/src/util/load-bundle.js.map +1 -1
  143. package/src/util/load-bundle.ts +38 -12
  144. package/src/util/load-ts.d.ts +100 -0
  145. package/src/util/load-ts.d.ts.map +1 -1
  146. package/src/util/load-ts.js +176 -0
  147. package/src/util/load-ts.js.map +1 -1
  148. package/src/util/load-ts.ts +227 -0
  149. package/src/util/narration-cache.d.ts +13 -5
  150. package/src/util/narration-cache.d.ts.map +1 -1
  151. package/src/util/narration-cache.js +10 -8
  152. package/src/util/narration-cache.js.map +1 -1
  153. package/src/util/narration-cache.ts +22 -6
  154. package/src/util/presenter-cache.d.ts +44 -0
  155. package/src/util/presenter-cache.d.ts.map +1 -0
  156. package/src/util/presenter-cache.js +43 -0
  157. package/src/util/presenter-cache.js.map +1 -0
  158. package/src/util/presenter-cache.ts +101 -0
  159. package/src/util/scenario-assets.d.ts +47 -0
  160. package/src/util/scenario-assets.d.ts.map +1 -0
  161. package/src/util/scenario-assets.js +71 -0
  162. package/src/util/scenario-assets.js.map +1 -0
  163. package/src/util/scenario-assets.ts +111 -0
  164. package/src/util/soundtrack-assets.d.ts +34 -0
  165. package/src/util/soundtrack-assets.d.ts.map +1 -0
  166. package/src/util/soundtrack-assets.js +48 -0
  167. package/src/util/soundtrack-assets.js.map +1 -0
  168. package/src/util/soundtrack-assets.ts +69 -0
  169. package/src/validate/scenario-validator.d.ts.map +1 -1
  170. package/src/validate/scenario-validator.js +82 -0
  171. package/src/validate/scenario-validator.js.map +1 -1
  172. package/src/validate/scenario-validator.ts +110 -0
  173. package/tsconfig.tsbuildinfo +1 -1
  174. package/example-bundle/assets/index-DlmG1Uh7.js +0 -388
  175. package/example-bundle/assets/style-BjquDnTE.css +0 -1
@@ -0,0 +1,71 @@
1
+ import { access } from "node:fs/promises";
2
+ import { isAbsolute, join, normalize } from "node:path";
3
+ import { CONTENT_TYPE_BY_EXTENSION, finalExtension } from "../pack/bundle-contract.js";
4
+ /**
5
+ * True when an asset src is a remote URL (has a scheme) rather than a
6
+ * scenario-relative path. Remote assets are referenced, never copied.
7
+ */
8
+ export function isRemoteUrl(src) {
9
+ return /^[a-z][a-z0-9+.-]*:\/\//i.test(src);
10
+ }
11
+ /**
12
+ * Resolve a scenario-relative asset reference against its scenario
13
+ * directory — the shared containment-and-existence contract behind
14
+ * every shipped asset (soundtrack music, title-card logos).
15
+ *
16
+ * Returns `null` for remote URLs (used from where they live). Throws
17
+ * with an actionable message when the path escapes the scenario
18
+ * directory or the file does not exist — both would otherwise surface
19
+ * as a broken reference in the packed embed or the rendered video.
20
+ *
21
+ * @param configPath - The authored field, for error messages
22
+ * (e.g. "soundtrack.musicSrc").
23
+ * @param expectation - What a valid reference looks like, appended to
24
+ * the error (e.g. 'an MP3 inside the scenario directory').
25
+ */
26
+ export async function resolveScenarioAsset(scenarioDir, src, configPath, expectation) {
27
+ if (isRemoteUrl(src))
28
+ return null;
29
+ const destRelPath = normalize(src).replace(/^\.\//, "");
30
+ if (isAbsolute(destRelPath) || destRelPath === ".." || destRelPath.startsWith("../")) {
31
+ throw new Error(`${configPath} "${src}" points outside the scenario directory.\n` +
32
+ `The reference must be ${expectation} so it can ship with the bundle,\n` +
33
+ "or an absolute URL.");
34
+ }
35
+ const sourcePath = join(scenarioDir, destRelPath);
36
+ try {
37
+ await access(sourcePath);
38
+ }
39
+ catch {
40
+ throw new Error(`${configPath} "${src}" not found at ${sourcePath}.\n` +
41
+ `Add the file (${expectation}), or fix the path in the config.`);
42
+ }
43
+ return { sourcePath, destRelPath };
44
+ }
45
+ /**
46
+ * The image extensions the packed-embed deploy contract serves —
47
+ * derived from the canonical extension table so this can never drift
48
+ * from the server's allowlist. Notably NO svg (active content).
49
+ */
50
+ export const IMAGE_EXTENSIONS = Object.entries(CONTENT_TYPE_BY_EXTENSION)
51
+ .filter(([, contentType]) => contentType.startsWith("image/"))
52
+ .map(([extension]) => extension);
53
+ /**
54
+ * Resolve a title card's `logo_src` against its scenario directory,
55
+ * additionally enforcing the deploy contract's image formats — an
56
+ * unservable extension must fail at build time, not as a 404 (or a
57
+ * rejected deploy) later.
58
+ */
59
+ export async function resolveLogoAsset(scenarioDir, logoSrc, configPath) {
60
+ const asset = await resolveScenarioAsset(scenarioDir, logoSrc, configPath, "an image inside the scenario directory (e.g. ./logo.png)");
61
+ if (asset === null)
62
+ return null;
63
+ const extension = finalExtension(asset.destRelPath);
64
+ if (!IMAGE_EXTENSIONS.includes(extension)) {
65
+ throw new Error(`${configPath} "${logoSrc}" is not a supported image format.\n` +
66
+ `The deploy contract serves: ${IMAGE_EXTENSIONS.join(", ")}. ` +
67
+ "SVG is deliberately excluded (active content) — inline it in a view instead.");
68
+ }
69
+ return asset;
70
+ }
71
+ //# sourceMappingURL=scenario-assets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scenario-assets.js","sourceRoot":"","sources":["../../../src/util/scenario-assets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACxD,OAAO,EAAE,yBAAyB,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAevF;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,OAAO,0BAA0B,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,WAAmB,EACnB,GAAW,EACX,UAAkB,EAClB,WAAmB;IAEnB,IAAI,WAAW,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAElC,MAAM,WAAW,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IACxD,IAAI,UAAU,CAAC,WAAW,CAAC,IAAI,WAAW,KAAK,IAAI,IAAI,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QACrF,MAAM,IAAI,KAAK,CACb,GAAG,UAAU,KAAK,GAAG,4CAA4C;YAC/D,yBAAyB,WAAW,oCAAoC;YACxE,qBAAqB,CACxB,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IAClD,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,GAAG,UAAU,KAAK,GAAG,kBAAkB,UAAU,KAAK;YACpD,iBAAiB,WAAW,mCAAmC,CAClE,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC;AACrC,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAsB,MAAM,CAAC,OAAO,CAC/D,yBAAyB,CAC1B;KACE,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;KAC7D,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC;AAEnC;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,WAAmB,EACnB,OAAe,EACf,UAAkB;IAElB,MAAM,KAAK,GAAG,MAAM,oBAAoB,CACtC,WAAW,EACX,OAAO,EACP,UAAU,EACV,0DAA0D,CAC3D,CAAC;IACF,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAEhC,MAAM,SAAS,GAAG,cAAc,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACpD,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CACb,GAAG,UAAU,KAAK,OAAO,sCAAsC;YAC7D,+BAA+B,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;YAC9D,8EAA8E,CACjF,CAAC;IACJ,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,111 @@
1
+ import { access } from "node:fs/promises";
2
+ import { isAbsolute, join, normalize } from "node:path";
3
+ import { CONTENT_TYPE_BY_EXTENSION, finalExtension } from "../pack/bundle-contract.js";
4
+
5
+ /**
6
+ * A scenario-local asset reference resolved for shipping: where the
7
+ * authored file is, and where it lands in a staged public dir or packed
8
+ * bundle (the authored path with its leading `./` removed, so the
9
+ * runtime reference resolves onto the shipped file in both outputs).
10
+ */
11
+ export interface ScenarioAsset {
12
+ /** Absolute path of the authored file. */
13
+ readonly sourcePath: string;
14
+ /** Destination path relative to the public dir / bundle root. */
15
+ readonly destRelPath: string;
16
+ }
17
+
18
+ /**
19
+ * True when an asset src is a remote URL (has a scheme) rather than a
20
+ * scenario-relative path. Remote assets are referenced, never copied.
21
+ */
22
+ export function isRemoteUrl(src: string): boolean {
23
+ return /^[a-z][a-z0-9+.-]*:\/\//i.test(src);
24
+ }
25
+
26
+ /**
27
+ * Resolve a scenario-relative asset reference against its scenario
28
+ * directory — the shared containment-and-existence contract behind
29
+ * every shipped asset (soundtrack music, title-card logos).
30
+ *
31
+ * Returns `null` for remote URLs (used from where they live). Throws
32
+ * with an actionable message when the path escapes the scenario
33
+ * directory or the file does not exist — both would otherwise surface
34
+ * as a broken reference in the packed embed or the rendered video.
35
+ *
36
+ * @param configPath - The authored field, for error messages
37
+ * (e.g. "soundtrack.musicSrc").
38
+ * @param expectation - What a valid reference looks like, appended to
39
+ * the error (e.g. 'an MP3 inside the scenario directory').
40
+ */
41
+ export async function resolveScenarioAsset(
42
+ scenarioDir: string,
43
+ src: string,
44
+ configPath: string,
45
+ expectation: string,
46
+ ): Promise<ScenarioAsset | null> {
47
+ if (isRemoteUrl(src)) return null;
48
+
49
+ const destRelPath = normalize(src).replace(/^\.\//, "");
50
+ if (isAbsolute(destRelPath) || destRelPath === ".." || destRelPath.startsWith("../")) {
51
+ throw new Error(
52
+ `${configPath} "${src}" points outside the scenario directory.\n` +
53
+ `The reference must be ${expectation} so it can ship with the bundle,\n` +
54
+ "or an absolute URL.",
55
+ );
56
+ }
57
+
58
+ const sourcePath = join(scenarioDir, destRelPath);
59
+ try {
60
+ await access(sourcePath);
61
+ } catch {
62
+ throw new Error(
63
+ `${configPath} "${src}" not found at ${sourcePath}.\n` +
64
+ `Add the file (${expectation}), or fix the path in the config.`,
65
+ );
66
+ }
67
+
68
+ return { sourcePath, destRelPath };
69
+ }
70
+
71
+ /**
72
+ * The image extensions the packed-embed deploy contract serves —
73
+ * derived from the canonical extension table so this can never drift
74
+ * from the server's allowlist. Notably NO svg (active content).
75
+ */
76
+ export const IMAGE_EXTENSIONS: readonly string[] = Object.entries(
77
+ CONTENT_TYPE_BY_EXTENSION,
78
+ )
79
+ .filter(([, contentType]) => contentType.startsWith("image/"))
80
+ .map(([extension]) => extension);
81
+
82
+ /**
83
+ * Resolve a title card's `logo_src` against its scenario directory,
84
+ * additionally enforcing the deploy contract's image formats — an
85
+ * unservable extension must fail at build time, not as a 404 (or a
86
+ * rejected deploy) later.
87
+ */
88
+ export async function resolveLogoAsset(
89
+ scenarioDir: string,
90
+ logoSrc: string,
91
+ configPath: string,
92
+ ): Promise<ScenarioAsset | null> {
93
+ const asset = await resolveScenarioAsset(
94
+ scenarioDir,
95
+ logoSrc,
96
+ configPath,
97
+ "an image inside the scenario directory (e.g. ./logo.png)",
98
+ );
99
+ if (asset === null) return null;
100
+
101
+ const extension = finalExtension(asset.destRelPath);
102
+ if (!IMAGE_EXTENSIONS.includes(extension)) {
103
+ throw new Error(
104
+ `${configPath} "${logoSrc}" is not a supported image format.\n` +
105
+ `The deploy contract serves: ${IMAGE_EXTENSIONS.join(", ")}. ` +
106
+ "SVG is deliberately excluded (active content) — inline it in a view instead.",
107
+ );
108
+ }
109
+
110
+ return asset;
111
+ }
@@ -0,0 +1,34 @@
1
+ import { type ScenarioAsset } from "./scenario-assets.js";
2
+ export { isRemoteUrl } from "./scenario-assets.js";
3
+ /** Absolute filesystem locations of the built-in SFX asset files. */
4
+ export interface SfxAssetPaths {
5
+ readonly click: string;
6
+ readonly keystroke: string;
7
+ }
8
+ /**
9
+ * Where the built-in SFX set lives inside a staged render public dir and
10
+ * inside a packed bundle — one convention, shared with the composition's
11
+ * `sfxSrcs` default and the embed entry's `soundtrackSources`, so every
12
+ * consumer looks in the same place.
13
+ */
14
+ export declare const SFX_DEST_PATHS: SfxAssetPaths;
15
+ /**
16
+ * Resolve the built-in SFX asset files from `@scenar/react`, using the
17
+ * given directory as the resolution context — the scenario directory, so
18
+ * the assets come from the same installed `@scenar/react` the generated
19
+ * entry imports.
20
+ */
21
+ export declare function resolveSfxAssetPaths(fromDir: string): SfxAssetPaths;
22
+ /** A scenario-local music asset: where it is, and where it ships. */
23
+ export type MusicAsset = ScenarioAsset;
24
+ /**
25
+ * Resolve a soundtrack's `music_src` against its scenario directory —
26
+ * the shared {@link resolveScenarioAsset} contract with music wording.
27
+ *
28
+ * Returns `null` for remote URLs (played from where they live). Throws
29
+ * with an actionable message when the referenced file does not exist or
30
+ * the path escapes the scenario directory — both would otherwise surface
31
+ * as a silently music-less video or a 404 in the packed embed.
32
+ */
33
+ export declare function resolveMusicAsset(scenarioDir: string, musicSrc: string): Promise<MusicAsset | null>;
34
+ //# sourceMappingURL=soundtrack-assets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"soundtrack-assets.d.ts","sourceRoot":"","sources":["../../../src/util/soundtrack-assets.ts"],"names":[],"mappings":"AAEA,OAAO,EAAwB,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAEhF,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,qEAAqE;AACrE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;GAKG;AACH,eAAO,MAAM,cAAc,EAAE,aAG5B,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAenE;AAED,qEAAqE;AACrE,MAAM,MAAM,UAAU,GAAG,aAAa,CAAC;AAEvC;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAO5B"}
@@ -0,0 +1,48 @@
1
+ import { createRequire } from "node:module";
2
+ import { join } from "node:path";
3
+ import { resolveScenarioAsset } from "./scenario-assets.js";
4
+ export { isRemoteUrl } from "./scenario-assets.js";
5
+ /**
6
+ * Where the built-in SFX set lives inside a staged render public dir and
7
+ * inside a packed bundle — one convention, shared with the composition's
8
+ * `sfxSrcs` default and the embed entry's `soundtrackSources`, so every
9
+ * consumer looks in the same place.
10
+ */
11
+ export const SFX_DEST_PATHS = {
12
+ click: "soundtrack/sfx/click.mp3",
13
+ keystroke: "soundtrack/sfx/keystroke.mp3",
14
+ };
15
+ /**
16
+ * Resolve the built-in SFX asset files from `@scenar/react`, using the
17
+ * given directory as the resolution context — the scenario directory, so
18
+ * the assets come from the same installed `@scenar/react` the generated
19
+ * entry imports.
20
+ */
21
+ export function resolveSfxAssetPaths(fromDir) {
22
+ const require = createRequire(join(fromDir, "__scenar_resolver__.js"));
23
+ try {
24
+ return {
25
+ click: require.resolve("@scenar/react/assets/sfx/click.mp3"),
26
+ keystroke: require.resolve("@scenar/react/assets/sfx/keystroke.mp3"),
27
+ };
28
+ }
29
+ catch {
30
+ throw new Error("soundtrack.sfx is enabled, but @scenar/react's sound-effect assets could not be\n" +
31
+ `resolved from ${fromDir}.\n\n` +
32
+ "The default SFX set ships inside @scenar/react (assets/sfx/). Install or update\n" +
33
+ "it in this project: pnpm add @scenar/react");
34
+ }
35
+ }
36
+ /**
37
+ * Resolve a soundtrack's `music_src` against its scenario directory —
38
+ * the shared {@link resolveScenarioAsset} contract with music wording.
39
+ *
40
+ * Returns `null` for remote URLs (played from where they live). Throws
41
+ * with an actionable message when the referenced file does not exist or
42
+ * the path escapes the scenario directory — both would otherwise surface
43
+ * as a silently music-less video or a 404 in the packed embed.
44
+ */
45
+ export async function resolveMusicAsset(scenarioDir, musicSrc) {
46
+ return resolveScenarioAsset(scenarioDir, musicSrc, "soundtrack.musicSrc", "an MP3 inside the scenario directory (e.g. ./soundtrack/music.mp3)");
47
+ }
48
+ //# sourceMappingURL=soundtrack-assets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"soundtrack-assets.js","sourceRoot":"","sources":["../../../src/util/soundtrack-assets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,oBAAoB,EAAsB,MAAM,sBAAsB,CAAC;AAEhF,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAQnD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GAAkB;IAC3C,KAAK,EAAE,0BAA0B;IACjC,SAAS,EAAE,8BAA8B;CAC1C,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAe;IAClD,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,OAAO,EAAE,wBAAwB,CAAC,CAAC,CAAC;IACvE,IAAI,CAAC;QACH,OAAO;YACL,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,oCAAoC,CAAC;YAC5D,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,wCAAwC,CAAC;SACrE,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,mFAAmF;YACjF,iBAAiB,OAAO,OAAO;YAC/B,mFAAmF;YACnF,4CAA4C,CAC/C,CAAC;IACJ,CAAC;AACH,CAAC;AAKD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,WAAmB,EACnB,QAAgB;IAEhB,OAAO,oBAAoB,CACzB,WAAW,EACX,QAAQ,EACR,qBAAqB,EACrB,oEAAoE,CACrE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,69 @@
1
+ import { createRequire } from "node:module";
2
+ import { join } from "node:path";
3
+ import { resolveScenarioAsset, type ScenarioAsset } from "./scenario-assets.js";
4
+
5
+ export { isRemoteUrl } from "./scenario-assets.js";
6
+
7
+ /** Absolute filesystem locations of the built-in SFX asset files. */
8
+ export interface SfxAssetPaths {
9
+ readonly click: string;
10
+ readonly keystroke: string;
11
+ }
12
+
13
+ /**
14
+ * Where the built-in SFX set lives inside a staged render public dir and
15
+ * inside a packed bundle — one convention, shared with the composition's
16
+ * `sfxSrcs` default and the embed entry's `soundtrackSources`, so every
17
+ * consumer looks in the same place.
18
+ */
19
+ export const SFX_DEST_PATHS: SfxAssetPaths = {
20
+ click: "soundtrack/sfx/click.mp3",
21
+ keystroke: "soundtrack/sfx/keystroke.mp3",
22
+ };
23
+
24
+ /**
25
+ * Resolve the built-in SFX asset files from `@scenar/react`, using the
26
+ * given directory as the resolution context — the scenario directory, so
27
+ * the assets come from the same installed `@scenar/react` the generated
28
+ * entry imports.
29
+ */
30
+ export function resolveSfxAssetPaths(fromDir: string): SfxAssetPaths {
31
+ const require = createRequire(join(fromDir, "__scenar_resolver__.js"));
32
+ try {
33
+ return {
34
+ click: require.resolve("@scenar/react/assets/sfx/click.mp3"),
35
+ keystroke: require.resolve("@scenar/react/assets/sfx/keystroke.mp3"),
36
+ };
37
+ } catch {
38
+ throw new Error(
39
+ "soundtrack.sfx is enabled, but @scenar/react's sound-effect assets could not be\n" +
40
+ `resolved from ${fromDir}.\n\n` +
41
+ "The default SFX set ships inside @scenar/react (assets/sfx/). Install or update\n" +
42
+ "it in this project: pnpm add @scenar/react",
43
+ );
44
+ }
45
+ }
46
+
47
+ /** A scenario-local music asset: where it is, and where it ships. */
48
+ export type MusicAsset = ScenarioAsset;
49
+
50
+ /**
51
+ * Resolve a soundtrack's `music_src` against its scenario directory —
52
+ * the shared {@link resolveScenarioAsset} contract with music wording.
53
+ *
54
+ * Returns `null` for remote URLs (played from where they live). Throws
55
+ * with an actionable message when the referenced file does not exist or
56
+ * the path escapes the scenario directory — both would otherwise surface
57
+ * as a silently music-less video or a 404 in the packed embed.
58
+ */
59
+ export async function resolveMusicAsset(
60
+ scenarioDir: string,
61
+ musicSrc: string,
62
+ ): Promise<MusicAsset | null> {
63
+ return resolveScenarioAsset(
64
+ scenarioDir,
65
+ musicSrc,
66
+ "soundtrack.musicSrc",
67
+ "an MP3 inside the scenario directory (e.g. ./soundtrack/music.mp3)",
68
+ );
69
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"scenario-validator.d.ts","sourceRoot":"","sources":["../../../src/validate/scenario-validator.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,CAAC;CAC7C;AAgBD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,OAAO,GAAG,gBAAgB,CAcpE"}
1
+ {"version":3,"file":"scenario-validator.d.ts","sourceRoot":"","sources":["../../../src/validate/scenario-validator.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,CAAC;CAC7C;AAgBD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,OAAO,GAAG,gBAAgB,CAgBpE"}
@@ -25,6 +25,8 @@ export function validateScenario(scenario) {
25
25
  const obj = scenario;
26
26
  validateViewport(obj["viewport"], errors);
27
27
  validateSteps(obj["steps"], errors);
28
+ validateSoundtrack(obj["soundtrack"], errors);
29
+ validateTitleCards(obj["titleCards"], errors);
28
30
  return { valid: errors.length === 0, errors };
29
31
  }
30
32
  function validateViewport(viewport, errors) {
@@ -42,6 +44,71 @@ function validateViewport(viewport, errors) {
42
44
  errors.push({ path: "viewport.height", reason: "height must be a positive integer." });
43
45
  }
44
46
  }
47
+ function validateSoundtrack(soundtrack, errors) {
48
+ if (soundtrack === undefined || soundtrack === null)
49
+ return;
50
+ if (typeof soundtrack !== "object" || Array.isArray(soundtrack)) {
51
+ errors.push({ path: "soundtrack", reason: "soundtrack must be an object." });
52
+ return;
53
+ }
54
+ const st = soundtrack;
55
+ if (st["musicSrc"] !== undefined) {
56
+ if (typeof st["musicSrc"] !== "string" || st["musicSrc"].length === 0) {
57
+ errors.push({
58
+ path: "soundtrack.musicSrc",
59
+ reason: "musicSrc must be a non-empty asset reference (e.g. \"./soundtrack/music.mp3\").",
60
+ });
61
+ }
62
+ }
63
+ validateVolume(st["musicVolume"], "soundtrack.musicVolume", errors);
64
+ validateVolume(st["duckingVolume"], "soundtrack.duckingVolume", errors);
65
+ if (st["sfx"] !== undefined && typeof st["sfx"] !== "boolean") {
66
+ errors.push({ path: "soundtrack.sfx", reason: "sfx must be a boolean." });
67
+ }
68
+ }
69
+ function validateVolume(value, path, errors) {
70
+ if (value === undefined)
71
+ return;
72
+ if (typeof value !== "number" || value < 0 || value > 1) {
73
+ errors.push({ path, reason: "must be a number between 0.0 and 1.0." });
74
+ }
75
+ }
76
+ function validateTitleCards(titleCards, errors) {
77
+ if (titleCards === undefined || titleCards === null)
78
+ return;
79
+ if (typeof titleCards !== "object" || Array.isArray(titleCards)) {
80
+ errors.push({ path: "titleCards", reason: "titleCards must be an object." });
81
+ return;
82
+ }
83
+ const cards = titleCards;
84
+ for (const side of ["intro", "outro"]) {
85
+ if (cards[side] !== undefined) {
86
+ validateTitleCard(cards[side], `titleCards.${side}`, errors);
87
+ }
88
+ }
89
+ }
90
+ function validateTitleCard(card, path, errors) {
91
+ if (card === null || typeof card !== "object" || Array.isArray(card)) {
92
+ errors.push({ path, reason: "card must be an object." });
93
+ return;
94
+ }
95
+ const c = card;
96
+ if (typeof c["title"] !== "string" || c["title"].length === 0) {
97
+ errors.push({ path: `${path}.title`, reason: "title is required and must be a non-empty string." });
98
+ }
99
+ for (const field of ["subtitle", "logoSrc", "ctaText"]) {
100
+ if (c[field] !== undefined) {
101
+ if (typeof c[field] !== "string" || c[field].length === 0) {
102
+ errors.push({ path: `${path}.${field}`, reason: `${field} must be a non-empty string when present.` });
103
+ }
104
+ }
105
+ }
106
+ if (c["durationMs"] !== undefined) {
107
+ if (typeof c["durationMs"] !== "number" || c["durationMs"] <= 0) {
108
+ errors.push({ path: `${path}.durationMs`, reason: "durationMs must be a positive integer." });
109
+ }
110
+ }
111
+ }
45
112
  function validateSteps(steps, errors) {
46
113
  if (!Array.isArray(steps)) {
47
114
  errors.push({ path: "steps", reason: "steps must be an array." });
@@ -69,6 +136,21 @@ function validateStep(step, path, errors) {
69
136
  errors.push({ path: `${path}.delayMs`, reason: "delayMs must be a non-negative integer." });
70
137
  }
71
138
  }
139
+ if (s["presenter"] !== undefined) {
140
+ if (typeof s["presenter"] !== "boolean") {
141
+ errors.push({ path: `${path}.presenter`, reason: "presenter must be a boolean." });
142
+ }
143
+ else if (s["presenter"] === true &&
144
+ (typeof s["narrationText"] !== "string" || s["narrationText"].length === 0)) {
145
+ // Cross-field rule (see the Step.presenter proto doc comment):
146
+ // caught here so `scenar validate` flags the contradiction before
147
+ // the paid `scenar presenter` command runs.
148
+ errors.push({
149
+ path: `${path}.presenter`,
150
+ reason: "presenter requires narration_text — a presenter clip is derived from the step's narration audio.",
151
+ });
152
+ }
153
+ }
72
154
  if (s["interactions"] !== undefined) {
73
155
  if (!Array.isArray(s["interactions"])) {
74
156
  errors.push({ path: `${path}.interactions`, reason: "interactions must be an array." });
@@ -1 +1 @@
1
- {"version":3,"file":"scenario-validator.js","sourceRoot":"","sources":["../../../src/validate/scenario-validator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scenario-validator.js","sourceRoot":"","sources":["../../../src/validate/scenario-validator.ts"],"names":[],"mappings":"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"}
@@ -44,6 +44,8 @@ export function validateScenario(scenario: unknown): ValidationResult {
44
44
 
45
45
  validateViewport(obj["viewport"], errors);
46
46
  validateSteps(obj["steps"], errors);
47
+ validateSoundtrack(obj["soundtrack"], errors);
48
+ validateTitleCards(obj["titleCards"], errors);
47
49
 
48
50
  return { valid: errors.length === 0, errors };
49
51
  }
@@ -69,6 +71,97 @@ function validateViewport(
69
71
  }
70
72
  }
71
73
 
74
+ function validateSoundtrack(
75
+ soundtrack: unknown,
76
+ errors: ValidationError[],
77
+ ): void {
78
+ if (soundtrack === undefined || soundtrack === null) return;
79
+
80
+ if (typeof soundtrack !== "object" || Array.isArray(soundtrack)) {
81
+ errors.push({ path: "soundtrack", reason: "soundtrack must be an object." });
82
+ return;
83
+ }
84
+
85
+ const st = soundtrack as Record<string, unknown>;
86
+
87
+ if (st["musicSrc"] !== undefined) {
88
+ if (typeof st["musicSrc"] !== "string" || st["musicSrc"].length === 0) {
89
+ errors.push({
90
+ path: "soundtrack.musicSrc",
91
+ reason: "musicSrc must be a non-empty asset reference (e.g. \"./soundtrack/music.mp3\").",
92
+ });
93
+ }
94
+ }
95
+
96
+ validateVolume(st["musicVolume"], "soundtrack.musicVolume", errors);
97
+ validateVolume(st["duckingVolume"], "soundtrack.duckingVolume", errors);
98
+
99
+ if (st["sfx"] !== undefined && typeof st["sfx"] !== "boolean") {
100
+ errors.push({ path: "soundtrack.sfx", reason: "sfx must be a boolean." });
101
+ }
102
+ }
103
+
104
+ function validateVolume(
105
+ value: unknown,
106
+ path: string,
107
+ errors: ValidationError[],
108
+ ): void {
109
+ if (value === undefined) return;
110
+ if (typeof value !== "number" || value < 0 || value > 1) {
111
+ errors.push({ path, reason: "must be a number between 0.0 and 1.0." });
112
+ }
113
+ }
114
+
115
+ function validateTitleCards(
116
+ titleCards: unknown,
117
+ errors: ValidationError[],
118
+ ): void {
119
+ if (titleCards === undefined || titleCards === null) return;
120
+
121
+ if (typeof titleCards !== "object" || Array.isArray(titleCards)) {
122
+ errors.push({ path: "titleCards", reason: "titleCards must be an object." });
123
+ return;
124
+ }
125
+
126
+ const cards = titleCards as Record<string, unknown>;
127
+ for (const side of ["intro", "outro"] as const) {
128
+ if (cards[side] !== undefined) {
129
+ validateTitleCard(cards[side], `titleCards.${side}`, errors);
130
+ }
131
+ }
132
+ }
133
+
134
+ function validateTitleCard(
135
+ card: unknown,
136
+ path: string,
137
+ errors: ValidationError[],
138
+ ): void {
139
+ if (card === null || typeof card !== "object" || Array.isArray(card)) {
140
+ errors.push({ path, reason: "card must be an object." });
141
+ return;
142
+ }
143
+
144
+ const c = card as Record<string, unknown>;
145
+
146
+ if (typeof c["title"] !== "string" || c["title"].length === 0) {
147
+ errors.push({ path: `${path}.title`, reason: "title is required and must be a non-empty string." });
148
+ }
149
+
150
+ for (const field of ["subtitle", "logoSrc", "ctaText"] as const) {
151
+ if (c[field] !== undefined) {
152
+ if (typeof c[field] !== "string" || (c[field] as string).length === 0) {
153
+ errors.push({ path: `${path}.${field}`, reason: `${field} must be a non-empty string when present.` });
154
+ }
155
+ }
156
+ }
157
+
158
+ if (c["durationMs"] !== undefined) {
159
+ if (typeof c["durationMs"] !== "number" || c["durationMs"] <= 0) {
160
+ errors.push({ path: `${path}.durationMs`, reason: "durationMs must be a positive integer." });
161
+ }
162
+ }
163
+ }
164
+
72
165
  function validateSteps(
73
166
  steps: unknown,
74
167
  errors: ValidationError[],
@@ -110,6 +203,23 @@ function validateStep(
110
203
  }
111
204
  }
112
205
 
206
+ if (s["presenter"] !== undefined) {
207
+ if (typeof s["presenter"] !== "boolean") {
208
+ errors.push({ path: `${path}.presenter`, reason: "presenter must be a boolean." });
209
+ } else if (
210
+ s["presenter"] === true &&
211
+ (typeof s["narrationText"] !== "string" || s["narrationText"].length === 0)
212
+ ) {
213
+ // Cross-field rule (see the Step.presenter proto doc comment):
214
+ // caught here so `scenar validate` flags the contradiction before
215
+ // the paid `scenar presenter` command runs.
216
+ errors.push({
217
+ path: `${path}.presenter`,
218
+ reason: "presenter requires narration_text — a presenter clip is derived from the step's narration audio.",
219
+ });
220
+ }
221
+ }
222
+
113
223
  if (s["interactions"] !== undefined) {
114
224
  if (!Array.isArray(s["interactions"])) {
115
225
  errors.push({ path: `${path}.interactions`, reason: "interactions must be an array." });