@norskvideo/ctl-product-template-schema 0.1.54 → 0.1.56
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 +25 -0
- package/index.js +41 -2
- package/pack.js +3 -0
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -4,6 +4,11 @@ export declare const ProductTemplateTargetSchema: z.ZodEnum<{
|
|
|
4
4
|
}>;
|
|
5
5
|
export type ProductTemplateTarget = z.infer<typeof ProductTemplateTargetSchema>;
|
|
6
6
|
export declare const RESERVED_INSTANCE_ROUTE_SEGMENTS: readonly ["studio", "media", "visualiser", "uvis", "status", "metrics"];
|
|
7
|
+
/** How a template's runtimes appear on fleet dashboards (RFC 0006 §4.1). */
|
|
8
|
+
export declare const ProductTemplateDashboardSchema: z.ZodObject<{
|
|
9
|
+
kind: z.ZodString;
|
|
10
|
+
previews: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
11
|
+
}, z.core.$strip>;
|
|
7
12
|
export declare const PRODUCT_TEMPLATE_ADVANCED_NETWORK_MODES: readonly ["docker", "hybrid"];
|
|
8
13
|
export declare const ProductTemplateAdvancedSchema: z.ZodObject<{
|
|
9
14
|
networkMode: z.ZodOptional<z.ZodObject<{
|
|
@@ -200,6 +205,14 @@ export declare const ProductTemplateManifestSchema: z.ZodObject<{
|
|
|
200
205
|
websocket: z.ZodOptional<z.ZodBoolean>;
|
|
201
206
|
auth: z.ZodOptional<z.ZodBoolean>;
|
|
202
207
|
}, z.core.$strip>>>;
|
|
208
|
+
operations: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
209
|
+
path: z.ZodString;
|
|
210
|
+
openapi: z.ZodString;
|
|
211
|
+
}, z.core.$strip>>>;
|
|
212
|
+
}, z.core.$strip>>;
|
|
213
|
+
dashboard: z.ZodOptional<z.ZodObject<{
|
|
214
|
+
kind: z.ZodString;
|
|
215
|
+
previews: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
203
216
|
}, z.core.$strip>>;
|
|
204
217
|
allowWorkflowUploads: z.ZodOptional<z.ZodBoolean>;
|
|
205
218
|
isStudio: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -464,6 +477,14 @@ export declare const ProductTemplateMaterialsSchema: z.ZodObject<{
|
|
|
464
477
|
websocket: z.ZodOptional<z.ZodBoolean>;
|
|
465
478
|
auth: z.ZodOptional<z.ZodBoolean>;
|
|
466
479
|
}, z.core.$strip>>>;
|
|
480
|
+
operations: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
481
|
+
path: z.ZodString;
|
|
482
|
+
openapi: z.ZodString;
|
|
483
|
+
}, z.core.$strip>>>;
|
|
484
|
+
}, z.core.$strip>>;
|
|
485
|
+
dashboard: z.ZodOptional<z.ZodObject<{
|
|
486
|
+
kind: z.ZodString;
|
|
487
|
+
previews: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
467
488
|
}, z.core.$strip>>;
|
|
468
489
|
allowWorkflowUploads: z.ZodOptional<z.ZodBoolean>;
|
|
469
490
|
isStudio: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -674,6 +695,10 @@ export declare const ProductTemplateMaterialsSchema: z.ZodObject<{
|
|
|
674
695
|
path: z.ZodString;
|
|
675
696
|
content: z.ZodUnion<readonly [z.ZodString, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>]>;
|
|
676
697
|
}, z.core.$strip>>>;
|
|
698
|
+
openapi: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
699
|
+
path: z.ZodString;
|
|
700
|
+
content: z.ZodUnion<readonly [z.ZodString, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>]>;
|
|
701
|
+
}, z.core.$strip>>>;
|
|
677
702
|
workdirSeed: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
678
703
|
path: z.ZodString;
|
|
679
704
|
content: z.ZodUnion<readonly [z.ZodString, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>]>;
|
package/index.js
CHANGED
|
@@ -87,6 +87,36 @@ const ProductTemplateRouteSchema = z.object({
|
|
|
87
87
|
description: "Whether the route sits behind the runner's oauth2 auth_request. Omit for the default `true`. Set false only for a surface that must be reachable unauthenticated, as the media route is.",
|
|
88
88
|
}),
|
|
89
89
|
});
|
|
90
|
+
// The operations a template serves, each described by an OpenAPI document it
|
|
91
|
+
// carries under openapi/ (RFC 0006 §4.1, norsk-ctl task 123). Keyed by the
|
|
92
|
+
// instance path the document describes, so it covers the runtime-screen
|
|
93
|
+
// catch-all as well as declared routes. An operation is reachable from a
|
|
94
|
+
// dashboard only when marked `x-norsk-dashboard: true`, and needs the
|
|
95
|
+
// platform rung its `x-norsk-role` names on the runtime.
|
|
96
|
+
const SAFE_SEGMENTS = (value) => !value.split("/").some((s) => s === ".." || s === ".");
|
|
97
|
+
const ProductTemplateOperationsSchema = z.object({
|
|
98
|
+
path: z
|
|
99
|
+
.string()
|
|
100
|
+
.regex(/^\/[A-Za-z0-9._~-]+(\/[A-Za-z0-9._~-]+)*$/, "an absolute path under the instance, no trailing slash")
|
|
101
|
+
.refine(SAFE_SEGMENTS, { message: "no . or .. segments" })
|
|
102
|
+
.meta({
|
|
103
|
+
description: "The path under /instance/<id>/ the document's paths are relative to, e.g. /live/api/probe-api.",
|
|
104
|
+
}),
|
|
105
|
+
openapi: z
|
|
106
|
+
.string()
|
|
107
|
+
.regex(/^openapi\/[A-Za-z0-9._-]+(\/[A-Za-z0-9._-]+)*\.(ya?ml|json)$/, "a YAML or JSON file under openapi/")
|
|
108
|
+
.refine(SAFE_SEGMENTS, { message: "no . or .. segments" })
|
|
109
|
+
.meta({ description: "The OpenAPI 3 document in the template tar, e.g. openapi/probe-api.yaml." }),
|
|
110
|
+
});
|
|
111
|
+
/** How a template's runtimes appear on fleet dashboards (RFC 0006 §4.1). */
|
|
112
|
+
export const ProductTemplateDashboardSchema = z.object({
|
|
113
|
+
kind: z.string().min(1).meta({
|
|
114
|
+
description: "The discovery kind a runtime of this template announces itself as, e.g. norsk-probe.monitor.",
|
|
115
|
+
}),
|
|
116
|
+
previews: z.array(z.string().min(1)).optional().meta({
|
|
117
|
+
description: "The roles of the MoQ previews it offers, e.g. main.",
|
|
118
|
+
}),
|
|
119
|
+
});
|
|
90
120
|
const ProductTemplateProxySchema = z.object({
|
|
91
121
|
expose: z.array(z.string()).default([]).meta({
|
|
92
122
|
description: "Paths (or globs) the runner's nginx routes through to this instance. Anything not in the list returns 404 from the proxy. Glob-shaped strings (`/static/*`) are accepted as hints — current implementation treats the whole set as a signal to mount a catch-all on the instance root; per-path filtering can come later.",
|
|
@@ -94,6 +124,9 @@ const ProductTemplateProxySchema = z.object({
|
|
|
94
124
|
routes: z.array(ProductTemplateRouteSchema).optional().meta({
|
|
95
125
|
description: "Extra named services to route under the instance root, beside the runtime-screen catch-all. Additive and optional: a template that omits it routes exactly as before, so an older runner ignoring the field still launches the product.",
|
|
96
126
|
}),
|
|
127
|
+
operations: z.array(ProductTemplateOperationsSchema).optional().meta({
|
|
128
|
+
description: "The operations this template's runtimes serve, each set described by an OpenAPI document in the tar; the ones marked x-norsk-dashboard are what fleet dashboards may call, each decided per user by the platform. Additive: a runner that predates it ignores it.",
|
|
129
|
+
}),
|
|
97
130
|
});
|
|
98
131
|
// product-template-schema cannot import @norsk-ctl/shared (dependency direction), so
|
|
99
132
|
// this is a literal copy of the runner's network-mode enum — and the runner
|
|
@@ -207,7 +240,7 @@ export const ProductTemplateSideloadSchema = z
|
|
|
207
240
|
export const ProductTemplateHostTlsSchema = z
|
|
208
241
|
.object({
|
|
209
242
|
services: z.array(z.string().min(1)).min(1).meta({
|
|
210
|
-
description: "Compose services that get the host certificate. Each must be a service in the template's own compose.yml. The runner mounts the certificate and key read-only at /etc/norsk-host-tls (cert.pem, key.pem) and sets NORSK_HOST_TLS_DIR=/etc/norsk-host-tls
|
|
243
|
+
description: "Compose services that get the host certificate. Each must be a service in the template's own compose.yml. The runner mounts the certificate and key read-only at /etc/norsk-host-tls (cert.pem, key.pem) and sets NORSK_HOST_TLS_DIR=/etc/norsk-host-tls. A host with no certificate mounts nothing and sets no variable; the launch still goes ahead.",
|
|
211
244
|
}),
|
|
212
245
|
})
|
|
213
246
|
.meta({ id: "ProductTemplateHostTls", outputId: "ProductTemplateHostTls" });
|
|
@@ -222,7 +255,7 @@ export const ProductTemplateHostTlsSchema = z
|
|
|
222
255
|
export const ProductTemplateWorkdirSchema = z
|
|
223
256
|
.object({
|
|
224
257
|
services: z.array(z.string().min(1)).min(1).meta({
|
|
225
|
-
description: "Compose services that get the instance working directory, read-write at /data -- the same directory, at the same path, that media and studio have
|
|
258
|
+
description: "Compose services that get the instance working directory, read-write at /data -- the same directory, at the same path, that media and studio have. Each must be a service in the template's own compose.yml. It survives relaunch, restart and runner upgrade; only `instance delete --purge` removes it.",
|
|
226
259
|
}),
|
|
227
260
|
})
|
|
228
261
|
.meta({ id: "ProductTemplateWorkdir", outputId: "ProductTemplateWorkdir" });
|
|
@@ -368,6 +401,9 @@ export const ProductTemplateManifestSchema = z
|
|
|
368
401
|
description: "Per-instance Debug menu toggles. Each of `studio`/`visualiser` defaults to shown; set false to hide a redundant link (e.g. Studio hides its own 'Open Studio').",
|
|
369
402
|
}),
|
|
370
403
|
proxy: ProductTemplateProxySchema.optional(),
|
|
404
|
+
dashboard: ProductTemplateDashboardSchema.optional().meta({
|
|
405
|
+
description: "How this template's runtimes appear on fleet dashboards: the kind they announce, and their previews. Absent = not on dashboards.",
|
|
406
|
+
}),
|
|
371
407
|
allowWorkflowUploads: z.boolean().optional().meta({
|
|
372
408
|
description: "Whether the operator may upload workflow documents for this product. They land in the working directory's studio-save-files/, where Studio lists them for the operator to open — so this is for Norsk Studio itself (the editor), not for appliances built on it: an appliance (probe, playout) generates its one workflow from its config screen and has nothing to select. Absent = false. Assets are governed separately by `supportsCustomAssets`.",
|
|
373
409
|
}),
|
|
@@ -525,6 +561,9 @@ export const ProductTemplateMaterialsSchema = z
|
|
|
525
561
|
.array(ProductTemplateFileSchema)
|
|
526
562
|
.default([])
|
|
527
563
|
.meta({ description: "Free-form product files — packed under assets/ in the tar" }),
|
|
564
|
+
openapi: z.array(ProductTemplateFileSchema).optional().meta({
|
|
565
|
+
description: "The OpenAPI documents proxy.operations names, packed under openapi/ in the tar. Optional so materials built before it still typecheck.",
|
|
566
|
+
}),
|
|
528
567
|
workdirSeed: z.array(ProductTemplateFileSchema).default([]).meta({
|
|
529
568
|
description: "Files copied recursively into the launch workdir at launch time. Packed under workdir-seed/ in the tar. Existing files in the launch workdir win on conflict (the seed only fills gaps), so re-launches and operator-edits-in-place are non-destructive. Lets a product template ship a 'starter pack' of demo workflows / dashboards / components that the runtime sees in /data on first launch.",
|
|
530
569
|
}),
|
package/pack.js
CHANGED
|
@@ -33,6 +33,9 @@ export function productTemplateTarEntries(materials) {
|
|
|
33
33
|
for (const a of materials.assets) {
|
|
34
34
|
entries.push({ name: `assets/${a.path}`, content: a.content });
|
|
35
35
|
}
|
|
36
|
+
for (const o of materials.openapi ?? []) {
|
|
37
|
+
entries.push({ name: `openapi/${o.path}`, content: o.content });
|
|
38
|
+
}
|
|
36
39
|
for (const s of materials.workdirSeed) {
|
|
37
40
|
entries.push({ name: `workdir-seed/${s.path}`, content: s.content });
|
|
38
41
|
}
|