@norskvideo/ctl-product-template-schema 0.1.52 → 0.1.54
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 +10 -1
- package/index.js +7 -1
- package/interfaces.d.ts +35 -24
- package/interfaces.js +52 -39
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -36,6 +36,9 @@ export declare const ProductTemplateAdvancedSchema: z.ZodObject<{
|
|
|
36
36
|
openFileLimit: z.ZodOptional<z.ZodObject<{
|
|
37
37
|
default: z.ZodOptional<z.ZodNumber>;
|
|
38
38
|
}, z.core.$strip>>;
|
|
39
|
+
memoryLimit: z.ZodOptional<z.ZodObject<{
|
|
40
|
+
default: z.ZodOptional<z.ZodString>;
|
|
41
|
+
}, z.core.$strip>>;
|
|
39
42
|
}, z.core.$strip>;
|
|
40
43
|
export declare const ProductTemplateAllocatedPortSchema: z.ZodObject<{
|
|
41
44
|
param: z.ZodString;
|
|
@@ -240,6 +243,9 @@ export declare const ProductTemplateManifestSchema: z.ZodObject<{
|
|
|
240
243
|
openFileLimit: z.ZodOptional<z.ZodObject<{
|
|
241
244
|
default: z.ZodOptional<z.ZodNumber>;
|
|
242
245
|
}, z.core.$strip>>;
|
|
246
|
+
memoryLimit: z.ZodOptional<z.ZodObject<{
|
|
247
|
+
default: z.ZodOptional<z.ZodString>;
|
|
248
|
+
}, z.core.$strip>>;
|
|
243
249
|
}, z.core.$strip>>;
|
|
244
250
|
requirements: z.ZodOptional<z.ZodObject<{
|
|
245
251
|
capacity: z.ZodOptional<z.ZodObject<{
|
|
@@ -501,6 +507,9 @@ export declare const ProductTemplateMaterialsSchema: z.ZodObject<{
|
|
|
501
507
|
openFileLimit: z.ZodOptional<z.ZodObject<{
|
|
502
508
|
default: z.ZodOptional<z.ZodNumber>;
|
|
503
509
|
}, z.core.$strip>>;
|
|
510
|
+
memoryLimit: z.ZodOptional<z.ZodObject<{
|
|
511
|
+
default: z.ZodOptional<z.ZodString>;
|
|
512
|
+
}, z.core.$strip>>;
|
|
504
513
|
}, z.core.$strip>>;
|
|
505
514
|
requirements: z.ZodOptional<z.ZodObject<{
|
|
506
515
|
capacity: z.ZodOptional<z.ZodObject<{
|
|
@@ -671,5 +680,5 @@ export declare const ProductTemplateMaterialsSchema: z.ZodObject<{
|
|
|
671
680
|
}, z.core.$strip>>>;
|
|
672
681
|
}, z.core.$strip>;
|
|
673
682
|
export type ProductTemplateMaterials = z.infer<typeof ProductTemplateMaterialsSchema>;
|
|
674
|
-
export { declareMediaConversion, interfaceDeclarationProblems, MEDIA_CONVERSION_INTERFACE, type
|
|
683
|
+
export { CONVERSION_TARGET_FORMAT, declareMediaConversion, interfaceDeclarationProblems, MEDIA_CONVERSION_INTERFACE, MEDIA_CONVERSION_VERSION, type MediaConversion, MediaConversionSchema, mediaConversionOf, type ProductTemplateInterface, ProductTemplateInterfaceSchema, } from "./interfaces.js";
|
|
675
684
|
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
|
@@ -146,6 +146,12 @@ export const ProductTemplateAdvancedSchema = z
|
|
|
146
146
|
// and not others) — so this is how a product that needs a HIGHER one says
|
|
147
147
|
// so, not how it gets a ceiling at all. Instance-wide, not per-service.
|
|
148
148
|
openFileLimit: z.object({ default: z.number().int().min(1024).max(1048576).optional() }).optional(),
|
|
149
|
+
// Memory ceiling for each of the instance's containers (docker `mem_limit`
|
|
150
|
+
// syntax, e.g. "24g"; swap is capped at the same value). The runner states
|
|
151
|
+
// one for every instance (16g) — an engine with none once drove a shared
|
|
152
|
+
// host into a global OOM kill — so this is how a product that needs MORE
|
|
153
|
+
// says so. "unlimited" opts the product out of a ceiling altogether.
|
|
154
|
+
memoryLimit: z.object({ default: z.string().optional() }).optional(),
|
|
149
155
|
})
|
|
150
156
|
.meta({ id: "ProductTemplateAdvanced", outputId: "ProductTemplateAdvanced" });
|
|
151
157
|
// A host-port binding whose value rides a product-template parameter, opted in per
|
|
@@ -524,5 +530,5 @@ export const ProductTemplateMaterialsSchema = z
|
|
|
524
530
|
}),
|
|
525
531
|
})
|
|
526
532
|
.meta({ id: "ProductTemplateMaterials" });
|
|
527
|
-
export { declareMediaConversion, interfaceDeclarationProblems, MEDIA_CONVERSION_INTERFACE,
|
|
533
|
+
export { CONVERSION_TARGET_FORMAT, declareMediaConversion, interfaceDeclarationProblems, MEDIA_CONVERSION_INTERFACE, MEDIA_CONVERSION_VERSION, MediaConversionSchema, mediaConversionOf, ProductTemplateInterfaceSchema, } from "./interfaces.js";
|
|
528
534
|
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
|
-
|
|
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<
|
|
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
|
-
|
|
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
|
|
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
|
|
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">):
|
|
54
|
-
type BindingRole = keyof
|
|
55
|
-
/** A norsk.io/media-conversion
|
|
56
|
-
*
|
|
57
|
-
*
|
|
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
|
-
*
|
|
61
|
-
|
|
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:
|
|
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
|
-
|
|
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(
|
|
40
|
-
// What the converter takes from the
|
|
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
|
|
46
|
-
//
|
|
47
|
-
|
|
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
|
-
|
|
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 !==
|
|
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
|
|
91
|
+
if (seen) {
|
|
79
92
|
problems.push(`${at}: declared more than once`);
|
|
80
93
|
return;
|
|
81
94
|
}
|
|
82
|
-
seen
|
|
83
|
-
const parsed =
|
|
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
|
|
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 !==
|
|
115
|
+
if (decl.name !== MEDIA_CONVERSION_INTERFACE || decl.version !== MEDIA_CONVERSION_VERSION)
|
|
112
116
|
continue;
|
|
113
|
-
const parsed =
|
|
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
|
|
147
|
-
*
|
|
148
|
-
*
|
|
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
|
-
*
|
|
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 =
|
|
182
|
+
const declaration = MediaConversionSchema.parse({
|
|
172
183
|
name: MEDIA_CONVERSION_INTERFACE,
|
|
173
|
-
version:
|
|
184
|
+
version: MEDIA_CONVERSION_VERSION,
|
|
185
|
+
returns: "programme",
|
|
186
|
+
target,
|
|
174
187
|
...rest,
|
|
175
188
|
bindings,
|
|
176
189
|
});
|