@norskvideo/ctl-product-template-schema 0.1.52 → 0.1.53

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/index.d.ts CHANGED
@@ -671,5 +671,5 @@ export declare const ProductTemplateMaterialsSchema: z.ZodObject<{
671
671
  }, z.core.$strip>>>;
672
672
  }, z.core.$strip>;
673
673
  export type ProductTemplateMaterials = z.infer<typeof ProductTemplateMaterialsSchema>;
674
- export { declareMediaConversion, interfaceDeclarationProblems, MEDIA_CONVERSION_INTERFACE, type MediaConversionV1, MediaConversionV1Schema, mediaConversionOf, type ProductTemplateInterface, ProductTemplateInterfaceSchema, } from "./interfaces.js";
674
+ export { CONVERSION_TARGET_FORMAT, declareMediaConversion, interfaceDeclarationProblems, MEDIA_CONVERSION_INTERFACE, MEDIA_CONVERSION_VERSION, type MediaConversion, MediaConversionSchema, mediaConversionOf, type ProductTemplateInterface, ProductTemplateInterfaceSchema, } from "./interfaces.js";
675
675
  export { composeServiceNamesOf, logsDeclarationProblems, NORSK_MEDIA_SERVICE_LOGS, type ProductTemplateLogs, ProductTemplateLogsSchema, productTemplateLogsProblems, type ServiceLogs, ServiceLogsSchema, STANDARD_LOGS, STUDIO_SERVICE_LOGS, servicesWithoutLogs, } from "./logs.js";
package/index.js CHANGED
@@ -524,5 +524,5 @@ export const ProductTemplateMaterialsSchema = z
524
524
  }),
525
525
  })
526
526
  .meta({ id: "ProductTemplateMaterials" });
527
- export { declareMediaConversion, interfaceDeclarationProblems, MEDIA_CONVERSION_INTERFACE, MediaConversionV1Schema, mediaConversionOf, ProductTemplateInterfaceSchema, } from "./interfaces.js";
527
+ export { CONVERSION_TARGET_FORMAT, declareMediaConversion, interfaceDeclarationProblems, MEDIA_CONVERSION_INTERFACE, MEDIA_CONVERSION_VERSION, MediaConversionSchema, mediaConversionOf, ProductTemplateInterfaceSchema, } from "./interfaces.js";
528
528
  export { composeServiceNamesOf, logsDeclarationProblems, NORSK_MEDIA_SERVICE_LOGS, ProductTemplateLogsSchema, productTemplateLogsProblems, ServiceLogsSchema, STANDARD_LOGS, STUDIO_SERVICE_LOGS, servicesWithoutLogs, } from "./logs.js";
package/interfaces.d.ts CHANGED
@@ -6,9 +6,17 @@ export declare const ProductTemplateInterfaceSchema: z.ZodObject<{
6
6
  }, z.core.$catchall<z.ZodUnknown>>;
7
7
  export type ProductTemplateInterface = z.infer<typeof ProductTemplateInterfaceSchema>;
8
8
  export declare const MEDIA_CONVERSION_INTERFACE = "norsk.io/media-conversion";
9
- export declare const MediaConversionV1Schema: z.ZodObject<{
9
+ /** The version of norsk.io/media-conversion this package knows. Version 1 (a
10
+ * fixed list of outputs, flat parameters) was retired before any caller used
11
+ * it; its number is not reused, so a reader of the old v1 never misreads this. */
12
+ export declare const MEDIA_CONVERSION_VERSION = 2;
13
+ /** The format a conversion's target follows: the conversion core's
14
+ * ConversionTarget (@norskvideo/norsk-studio-standards-conversion). Naming it
15
+ * tells a caller it can plan the conversion itself, with the same core. */
16
+ export declare const CONVERSION_TARGET_FORMAT = "norsk.io/conversion-target";
17
+ export declare const MediaConversionSchema: z.ZodObject<{
10
18
  name: z.ZodLiteral<"norsk.io/media-conversion">;
11
- version: z.ZodLiteral<1>;
19
+ version: z.ZodLiteral<2>;
12
20
  inputs: z.ZodArray<z.ZodObject<{
13
21
  name: z.ZodString;
14
22
  kinds: z.ZodRecord<z.ZodEnum<{
@@ -21,47 +29,50 @@ export declare const MediaConversionV1Schema: z.ZodObject<{
21
29
  max: z.ZodNumber;
22
30
  }, z.core.$strip>]>>;
23
31
  }, z.core.$strip>>;
24
- outputs: z.ZodArray<z.ZodObject<{
25
- name: z.ZodString;
26
- kind: z.ZodEnum<{
27
- video: "video";
28
- audio: "audio";
29
- subtitle: "subtitle";
30
- ancillary: "ancillary";
31
- }>;
32
- count: z.ZodOptional<z.ZodNumber>;
33
- format: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
34
- }, z.core.$strip>>;
32
+ returns: z.ZodLiteral<"programme">;
35
33
  transports: z.ZodArray<z.ZodString>;
36
34
  timeline: z.ZodString;
35
+ target: z.ZodObject<{
36
+ format: z.ZodString;
37
+ version: z.ZodNumber;
38
+ }, z.core.$strip>;
39
+ profiles: z.ZodOptional<z.ZodArray<z.ZodObject<{
40
+ name: z.ZodString;
41
+ label: z.ZodString;
42
+ description: z.ZodOptional<z.ZodString>;
43
+ target: z.ZodRecord<z.ZodString, z.ZodUnknown>;
44
+ }, z.core.$strip>>>;
37
45
  bindings: z.ZodObject<{
38
46
  sourceUrl: z.ZodString;
39
47
  returnName: z.ZodString;
48
+ target: z.ZodString;
40
49
  engineVersion: z.ZodOptional<z.ZodString>;
41
50
  conversionId: z.ZodOptional<z.ZodString>;
42
51
  }, z.core.$strip>;
43
52
  }, z.core.$strip>;
44
- export type MediaConversionV1 = z.infer<typeof MediaConversionV1Schema>;
53
+ export type MediaConversion = z.infer<typeof MediaConversionSchema>;
45
54
  /** Everything wrong with a template's interface declarations, given the
46
55
  * parameters it declares. Only known interfaces are checked. Empty = fine. */
47
56
  export declare function interfaceDeclarationProblems(template: {
48
57
  manifest: Pick<ProductTemplateManifest, "interfaces">;
49
58
  parameters: Pick<ProductTemplateParameter, "name">[];
50
59
  }): string[];
51
- /** The template's norsk.io/media-conversion v1 declaration, typed, if it
60
+ /** The template's norsk.io/media-conversion declaration, typed, if it
52
61
  * declares a valid one. */
53
- export declare function mediaConversionOf(manifest: Pick<ProductTemplateManifest, "interfaces">): MediaConversionV1 | undefined;
54
- type BindingRole = keyof MediaConversionV1["bindings"];
55
- /** A norsk.io/media-conversion v1 declaration and the parameters its
56
- * bindings name, built together so a template cannot bind a parameter it
57
- * never declared. Spread `parameters` into the template's parameters.yaml and
62
+ export declare function mediaConversionOf(manifest: Pick<ProductTemplateManifest, "interfaces">): MediaConversion | undefined;
63
+ type BindingRole = keyof MediaConversion["bindings"];
64
+ /** A norsk.io/media-conversion declaration and the parameters its bindings
65
+ * name, built together so a template cannot bind a parameter it never
66
+ * declared. Spread `parameters` into the template's parameters.yaml and
58
67
  * `interface` into its manifest's `interfaces`. Each binding defaults to a
59
- * conventional parameter name; pass a name to use the template's own, or
60
- * null to leave an optional role out. */
61
- export declare function declareMediaConversion(shape: Omit<MediaConversionV1, "name" | "version" | "bindings"> & {
68
+ * conventional parameter name; pass a name to use the template's own, or null
69
+ * to leave an optional role out. The target format defaults to the
70
+ * conversion core's. */
71
+ export declare function declareMediaConversion(shape: Omit<MediaConversion, "name" | "version" | "bindings" | "returns" | "target"> & {
72
+ target?: MediaConversion["target"];
62
73
  bindings?: Partial<Record<BindingRole, string | null>>;
63
74
  }): {
64
- interface: MediaConversionV1;
75
+ interface: MediaConversion;
65
76
  parameters: ProductTemplateParameter[];
66
77
  };
67
78
  export {};
package/interfaces.js CHANGED
@@ -25,6 +25,10 @@ export const ProductTemplateInterfaceSchema = z
25
25
  description: "A contract the template implements: its name and version, and the body that contract defines. Carried verbatim; a runner checks only the contracts it knows.",
26
26
  });
27
27
  export const MEDIA_CONVERSION_INTERFACE = "norsk.io/media-conversion";
28
+ /** The version of norsk.io/media-conversion this package knows. Version 1 (a
29
+ * fixed list of outputs, flat parameters) was retired before any caller used
30
+ * it; its number is not reused, so a reader of the old v1 never misreads this. */
31
+ export const MEDIA_CONVERSION_VERSION = 2;
28
32
  const PARAMETER_NAME = /^[A-Z][A-Z0-9_]*$/;
29
33
  const parameterName = z.string().regex(PARAMETER_NAME, "a parameter name");
30
34
  const MediaKindSchema = z.enum(["video", "audio", "subtitle", "ancillary"]);
@@ -34,53 +38,62 @@ const KindCountSchema = z.union([
34
38
  .object({ min: z.number().int().min(0), max: z.number().int().min(0) })
35
39
  .refine((r) => r.min <= r.max, { message: "min must be <= max" }),
36
40
  ]);
37
- export const MediaConversionV1Schema = z.object({
41
+ /** The format a conversion's target follows: the conversion core's
42
+ * ConversionTarget (@norskvideo/norsk-studio-standards-conversion). Naming it
43
+ * tells a caller it can plan the conversion itself, with the same core. */
44
+ export const CONVERSION_TARGET_FORMAT = "norsk.io/conversion-target";
45
+ export const MediaConversionSchema = z.object({
38
46
  name: z.literal(MEDIA_CONVERSION_INTERFACE),
39
- version: z.literal(1),
40
- // What the converter takes from the relay: per named input, how many tracks
47
+ version: z.literal(MEDIA_CONVERSION_VERSION),
48
+ // What the converter takes from the caller: per named input, how many tracks
41
49
  // of each kind (a count, or a range).
42
50
  inputs: z
43
51
  .array(z.object({ name: z.string().min(1), kinds: z.partialRecord(MediaKindSchema, KindCountSchema) }))
44
52
  .min(1),
45
- // What it hands back. A format value may refer to a parameter as ${NAME}, so
46
- // a client can show the result of a launch before it happens.
47
- outputs: z
48
- .array(z.object({
49
- name: z.string().min(1),
50
- kind: MediaKindSchema,
51
- count: z.number().int().min(1).optional(),
52
- format: z.record(z.string(), z.string()).optional(),
53
- }))
54
- .min(1),
53
+ // What comes back: the input programme, each track converted as the target
54
+ // says or passed, under its own stream key.
55
+ returns: z.literal("programme"),
55
56
  // Free strings rather than an enum: a template offering a transport this ctl
56
57
  // does not know (srt, moq) must still validate; the client picks one it speaks.
57
58
  transports: z.array(z.string().min(1)).min(1),
58
59
  timeline: z.string().min(1),
60
+ // The format of the value the target binding carries, and its version.
61
+ target: z.object({ format: z.string().min(1), version: z.number().int().min(1) }),
62
+ // Named targets for the common jobs, which a client offers before the
63
+ // target's own fields. A profile's target is in the target's format.
64
+ profiles: z
65
+ .array(z.object({
66
+ name: z.string().regex(/^[a-z0-9]+(-[a-z0-9]+)*$/, "a lower-case slug"),
67
+ label: z.string().min(1),
68
+ description: z.string().optional(),
69
+ target: z.record(z.string(), z.unknown()),
70
+ }))
71
+ .optional(),
59
72
  // The template's own parameters the client fills, by role.
60
73
  bindings: z.object({
61
74
  sourceUrl: parameterName,
62
75
  returnName: parameterName,
76
+ target: parameterName,
63
77
  engineVersion: parameterName.optional(),
64
78
  conversionId: parameterName.optional(),
65
79
  }),
66
80
  });
67
- const PARAMETER_REFERENCE = /\$\{([^}]*)\}/g;
68
81
  /** Everything wrong with a template's interface declarations, given the
69
82
  * parameters it declares. Only known interfaces are checked. Empty = fine. */
70
83
  export function interfaceDeclarationProblems(template) {
71
84
  const declared = new Set(template.parameters.map((p) => p.name));
72
- const seen = new Set();
85
+ let seen = false;
73
86
  const problems = [];
74
87
  (template.manifest.interfaces ?? []).forEach((decl, i) => {
75
- if (decl.name !== MEDIA_CONVERSION_INTERFACE || decl.version !== 1)
88
+ if (decl.name !== MEDIA_CONVERSION_INTERFACE || decl.version !== MEDIA_CONVERSION_VERSION)
76
89
  return;
77
90
  const at = `interfaces[${i}] (${decl.name} v${decl.version})`;
78
- if (seen.has(`${decl.name}@${decl.version}`)) {
91
+ if (seen) {
79
92
  problems.push(`${at}: declared more than once`);
80
93
  return;
81
94
  }
82
- seen.add(`${decl.name}@${decl.version}`);
83
- const parsed = MediaConversionV1Schema.safeParse(decl);
95
+ seen = true;
96
+ const parsed = MediaConversionSchema.safeParse(decl);
84
97
  if (!parsed.success) {
85
98
  for (const issue of parsed.error.issues) {
86
99
  problems.push(`${at}: ${issue.path.join(".") || "(declaration)"}: ${issue.message}`);
@@ -92,25 +105,16 @@ export function interfaceDeclarationProblems(template) {
92
105
  problems.push(`${at}: binding ${role} names ${param}, which is not a declared parameter`);
93
106
  }
94
107
  }
95
- parsed.data.outputs.forEach((output, o) => {
96
- for (const [key, value] of Object.entries(output.format ?? {})) {
97
- for (const [, ref] of value.matchAll(PARAMETER_REFERENCE)) {
98
- if (!declared.has(ref)) {
99
- problems.push(`${at}: outputs[${o}].format.${key} refers to ${ref}, which is not a declared parameter`);
100
- }
101
- }
102
- }
103
- });
104
108
  });
105
109
  return problems;
106
110
  }
107
- /** The template's norsk.io/media-conversion v1 declaration, typed, if it
111
+ /** The template's norsk.io/media-conversion declaration, typed, if it
108
112
  * declares a valid one. */
109
113
  export function mediaConversionOf(manifest) {
110
114
  for (const decl of manifest.interfaces ?? []) {
111
- if (decl.name !== MEDIA_CONVERSION_INTERFACE || decl.version !== 1)
115
+ if (decl.name !== MEDIA_CONVERSION_INTERFACE || decl.version !== MEDIA_CONVERSION_VERSION)
112
116
  continue;
113
- const parsed = MediaConversionV1Schema.safeParse(decl);
117
+ const parsed = MediaConversionSchema.safeParse(decl);
114
118
  if (parsed.success)
115
119
  return parsed.data;
116
120
  }
@@ -129,6 +133,12 @@ const BINDING_DEFAULTS = {
129
133
  purpose: "The name to publish the converted media under, for the caller to take it back. Filled by the caller.",
130
134
  required: true,
131
135
  },
136
+ target: {
137
+ name: "CONVERSION_TARGET",
138
+ label: "Conversion target",
139
+ purpose: "What the converted programme should be, as JSON in the declared target format. Filled by the caller.",
140
+ required: true,
141
+ },
132
142
  engineVersion: {
133
143
  name: "ENGINE_VERSION",
134
144
  label: "Engine version",
@@ -143,14 +153,15 @@ const BINDING_DEFAULTS = {
143
153
  },
144
154
  };
145
155
  const BINDING_GROUP = "Conversion link";
146
- /** A norsk.io/media-conversion v1 declaration and the parameters its
147
- * bindings name, built together so a template cannot bind a parameter it
148
- * never declared. Spread `parameters` into the template's parameters.yaml and
156
+ /** A norsk.io/media-conversion declaration and the parameters its bindings
157
+ * name, built together so a template cannot bind a parameter it never
158
+ * declared. Spread `parameters` into the template's parameters.yaml and
149
159
  * `interface` into its manifest's `interfaces`. Each binding defaults to a
150
- * conventional parameter name; pass a name to use the template's own, or
151
- * null to leave an optional role out. */
160
+ * conventional parameter name; pass a name to use the template's own, or null
161
+ * to leave an optional role out. The target format defaults to the
162
+ * conversion core's. */
152
163
  export function declareMediaConversion(shape) {
153
- const { bindings: chosen = {}, ...rest } = shape;
164
+ const { bindings: chosen = {}, target = { format: CONVERSION_TARGET_FORMAT, version: 1 }, ...rest } = shape;
154
165
  const bindings = {};
155
166
  const parameters = [];
156
167
  for (const role of Object.keys(BINDING_DEFAULTS)) {
@@ -168,9 +179,11 @@ export function declareMediaConversion(shape) {
168
179
  ...(fallback.required ? { required: true } : {}),
169
180
  });
170
181
  }
171
- const declaration = MediaConversionV1Schema.parse({
182
+ const declaration = MediaConversionSchema.parse({
172
183
  name: MEDIA_CONVERSION_INTERFACE,
173
- version: 1,
184
+ version: MEDIA_CONVERSION_VERSION,
185
+ returns: "programme",
186
+ target,
174
187
  ...rest,
175
188
  bindings,
176
189
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@norskvideo/ctl-product-template-schema",
3
- "version": "0.1.52",
3
+ "version": "0.1.53",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {