@norskvideo/ctl-test-harness 0.1.4 → 0.1.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@norskvideo/ctl-test-harness",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./daemon": {
@@ -18,6 +18,25 @@
18
18
  "./harness-config": {
19
19
  "types": "./harness-config.d.ts",
20
20
  "default": "./harness-config.js"
21
+ },
22
+ "./studio-load": {
23
+ "types": "./studio-load.d.ts",
24
+ "default": "./studio-load.js"
25
+ }
26
+ },
27
+ "dependencies": {
28
+ "@norskvideo/ctl-sdk": "^0.1.0"
29
+ },
30
+ "peerDependencies": {
31
+ "@norskvideo/norsk-studio": "*",
32
+ "@norskvideo/norsk-studio-built-ins": "*"
33
+ },
34
+ "peerDependenciesMeta": {
35
+ "@norskvideo/norsk-studio": {
36
+ "optional": true
37
+ },
38
+ "@norskvideo/norsk-studio-built-ins": {
39
+ "optional": true
21
40
  }
22
41
  },
23
42
  "publishConfig": {
@@ -0,0 +1,11 @@
1
+ import { load } from "@norskvideo/norsk-studio/lib/runtime/document";
2
+ import { RuntimeSystem } from "@norskvideo/norsk-studio/lib/runtime/system";
3
+ export type CompiledDocument = ReturnType<typeof load>;
4
+ export interface StudioLoadOptions {
5
+ stubs?: string[];
6
+ register?: (runtime: RuntimeSystem) => void | Promise<void>;
7
+ filename?: string;
8
+ loadOptions?: Parameters<typeof load>[3];
9
+ }
10
+ export declare function loadsInStudio(yamlText: string, opts?: StudioLoadOptions): Promise<CompiledDocument>;
11
+ export declare function assertLoadsInStudio(yamlText: string, opts?: StudioLoadOptions): Promise<CompiledDocument>;
package/studio-load.js ADDED
@@ -0,0 +1,70 @@
1
+ // The cheap Layer 4 tier, packaged: run an emitted workflow YAML through
2
+ // Studio's REAL document.load() so every built-ins component's zod schema
3
+ // validates what the composer actually emits — not just the local factory
4
+ // typing. Synchronous validation path only; no Norsk media engine, no Docker.
5
+ //
6
+ // This generalises probe's _util/studio-load.ts (11 scenarios) so no product
7
+ // has to re-derive the fiddly parts:
8
+ // - built-ins registerAll sits at .default.default when bundled and .default
9
+ // when externalised; callableDefault tolerates both.
10
+ // - document.load() records "Unknown node type" and STOPS at the first
11
+ // component it can't resolve, so one custom component would mask every
12
+ // error after it. Out-of-library components (a product's own, or alpha
13
+ // ones absent from @norskvideo/norsk-studio-built-ins) are stub-registered
14
+ // via `stubs` — permissive, config not validated (there is no schema to
15
+ // validate against), passing input streams through so downstream built-ins
16
+ // still resolve subscriptions.
17
+ //
18
+ // Lives in ctl-test-harness (not dev-kit: it needs the norsk-studio packages,
19
+ // which are optional peers here — the products that use it already pin them;
20
+ // dev-kit stays dependency-lean).
21
+ import { callableDefault } from "@norskvideo/ctl-sdk";
22
+ import { load } from "@norskvideo/norsk-studio/lib/runtime/document";
23
+ import { RuntimeSystem } from "@norskvideo/norsk-studio/lib/runtime/system";
24
+ import * as builtInsModule from "@norskvideo/norsk-studio-built-ins";
25
+ const registerAll = callableDefault(builtInsModule, "@norskvideo/norsk-studio-built-ins");
26
+ function registerStub(runtime, identifier) {
27
+ const info = {
28
+ identifier,
29
+ name: identifier,
30
+ category: "Output",
31
+ // load() reads info.configForm.global (global-config map) and iterates
32
+ // info.configForm.form (per-field config patching); an empty non-global
33
+ // form is all a stub needs.
34
+ configForm: { global: false, form: {} },
35
+ subscription: {
36
+ accepts: {
37
+ type: "simple-stream",
38
+ video: true,
39
+ audio: true,
40
+ subtitle: true,
41
+ ancillary: true,
42
+ playlist: true,
43
+ acceptsTransient: true,
44
+ },
45
+ produces: { type: "dynamic-streams", streams: (_cfg, inputs) => inputs },
46
+ },
47
+ };
48
+ const definition = {
49
+ create: async () => { },
50
+ schemas: async () => ({ config: { type: "object", additionalProperties: true } }),
51
+ };
52
+ runtime.registerComponent(definition, info, "", undefined, "studio-load-stubs");
53
+ }
54
+ export async function loadsInStudio(yamlText, opts = {}) {
55
+ const runtime = new RuntimeSystem();
56
+ await registerAll(runtime);
57
+ for (const id of opts.stubs ?? [])
58
+ registerStub(runtime, id);
59
+ await opts.register?.(runtime);
60
+ return load(opts.filename ?? "workflow.yml", runtime, yamlText, { resolveConfig: true, ...opts.loadOptions });
61
+ }
62
+ // Throwing form for tests: one assertion per scenario, every load error listed.
63
+ export async function assertLoadsInStudio(yamlText, opts = {}) {
64
+ const compiled = await loadsInStudio(yamlText, opts);
65
+ if (compiled.errors.length > 0) {
66
+ const listed = compiled.errors.map((e, i) => ` [${i}] ${e.message}`).join("\n");
67
+ throw new Error(`${opts.filename ?? "workflow.yml"} failed Studio document.load():\n${listed}`);
68
+ }
69
+ return compiled;
70
+ }