@norskvideo/ctl-dev-kit 0.2.71 → 0.2.74

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.
@@ -26,6 +26,7 @@ export interface Canon {
26
26
  dprint: string;
27
27
  buildImageBootstrap: string;
28
28
  buildImage: string;
29
+ smoke: string;
29
30
  /** conventions/build-docs.yml — the embedded docs workflow a turnkey carries. */
30
31
  buildDocs: string;
31
32
  gitignoreCore: string;
@@ -53,6 +54,7 @@ export function loadCanon(): Canon {
53
54
  dprint: readFileSync(join(conventionsDir, "dprint.base.jsonc"), "utf8"),
54
55
  buildImageBootstrap: readFileSync(join(buildDir, "build-image.bootstrap.sh"), "utf8"),
55
56
  buildImage: readFileSync(join(conventionsDir, "build-image.yml"), "utf8"),
57
+ smoke: readFileSync(join(conventionsDir, "smoke.yml"), "utf8"),
56
58
  gitignoreCore: readFileSync(join(conventionsDir, "gitignore.core"), "utf8"),
57
59
  invariantsTemplate: readFileSync(join(import.meta.dir, "..", "testing", "INVARIANTS.template.md"), "utf8"),
58
60
  demoShim: readFileSync(join(conventionsDir, "demo.sh"), "utf8"),
@@ -223,6 +223,7 @@ function conventionFiles(ctx: ShapeContext, shape: ShapeModule): GeneratedFile[]
223
223
  { path: ".github/workflows/bump.yml", content: fillProduct(canon.bump) },
224
224
  { path: ".github/workflows/bot-prs.yml", content: canon.botPrs },
225
225
  { path: ".github/workflows/build-image.yml", content: fillProduct(canon.buildImage) },
226
+ { path: ".github/workflows/smoke.yml", content: fillProduct(canon.smoke) },
226
227
  { path: ".github/actions/ci-status-dispatch/action.yml", content: loadAsset("ci-status-dispatch.yml") },
227
228
  { path: "manifest.seed.json", content: seedJson(ctx) },
228
229
  { path: "licenseTemplate.json", content: licenseTemplateJson(ctx) },
@@ -257,9 +257,15 @@ refreshed \`~/.norsk-ctl/product-templates/<name>/compose.yml\` carries the pins
257
257
  so table and tests cannot drift apart.
258
258
  - **Layer 4 — studio-load round-trip** (\`tests/unit/loads-in-studio.test.ts\`):
259
259
  emitted YAML through Studio's real \`document.load()\`.
260
- - **Layer 5 — integration**: not scaffolded. Decide + record here whether this
261
- product carries one (unattended nightly bumps need it; see
260
+ - **Layer 5 — integration**: the smoke tier (\`tests/smoke.spec.ts\`, run by
261
+ the convention \`smoke.yml\` on PRs, main and the nightly bump). It launches
262
+ the built image, sends the camera1 sample to the SRT ingest and checks the
263
+ graph is up and the ingest connected. Grow its observations as the product
264
+ takes shape; add an \`integration.yml\` when a regression needs more than
265
+ one journey (see
262
266
  \`node_modules/@norskvideo/ctl-dev-kit/conventions/integration-testing.md\`).
267
+ Locally: \`bun run build:image && bun run test:smoke\` with
268
+ \`NORSK_LICENSE_FILE\` set.
263
269
 
264
270
  Byte-snapshots (\`tests/unit/workflow-snapshot.test.ts\`) pin the emitted wire
265
271
  bytes; \`UPDATE_SNAPSHOTS=1\` refreshes deliberately.
@@ -303,6 +309,7 @@ function rootPackageJson(ctx: ShapeContext): string {
303
309
  test: "bun run test:unit",
304
310
  "test:unit": `bun test shared/src/ backend/src/ ${hasComponents ? "components/src/ " : ""}tests/unit/`,
305
311
  "test:image": "bun test tests/image/",
312
+ "test:smoke": "NORSK_CTL_ENV=test bun test tests/smoke.spec.ts",
306
313
  "check:drift": "bun run node_modules/@norskvideo/ctl-dev-kit/conventions/check-drift.ts",
307
314
  "docs:check":
308
315
  "bun run node_modules/@norskvideo/ctl-dev-kit/docs/path-existence.ts && bun run node_modules/@norskvideo/ctl-dev-kit/docs/light-pages.ts && bun run node_modules/@norskvideo/ctl-dev-kit/docs/journeys.ts",
@@ -1210,9 +1217,10 @@ ${studioLibraries}
1210
1217
  // SRT-listener ingests bind inside the media engine and must be published as
1211
1218
  // UDP (without /udp docker publishes TCP and the host can't reach Norsk's
1212
1219
  // listener). srt-caller ingests dial out — no published port.
1220
+ // INGEST_PORT is the host side only: the listener inside the engine binds the
1221
+ // configured port whatever INGEST_PORT says.
1213
1222
  if (config.input.transport === "srt-listener") {
1214
- // biome-ignore lint/suspicious/noTemplateCurlyInString: docker-compose variable reference, not a TS template literal
1215
- mediaPorts.push("\${INGEST_PORT}:\${INGEST_PORT}/udp");
1223
+ mediaPorts.push(\`\\\${INGEST_PORT}:\${config.input.port}/udp\`);
1216
1224
  }
1217
1225
 
1218
1226
  const compose = {
@@ -1824,6 +1832,49 @@ exec bun run demo -- up --mode image --daemon reuse
1824
1832
  `;
1825
1833
  }
1826
1834
 
1835
+ function smokeSpecTs(ctx: ShapeContext): string {
1836
+ return `// The smoke tier: one journey through the built image, run by
1837
+ // @norskvideo/ctl-test-harness/smoke on PRs, main and the nightly bump.
1838
+ // smoke.yml builds the image and sets SMOKE_IMAGE_TAG; locally,
1839
+ // \`bun run build:image && bun run test:smoke\` with NORSK_LICENSE_FILE set.
1840
+ // The tag must be one the licence names (licenseTemplate.json).
1841
+ //
1842
+ // The camera1 sample goes to the SRT ingest. What it proves: the graph is up
1843
+ // and the ingest takes the feed. Grow the observations as the product takes
1844
+ // shape: they are what an unattended nightly bump is trusted on.
1845
+ import { test } from "bun:test";
1846
+ import { hashSlot } from "@norskvideo/ctl-test-harness/harness-config";
1847
+ import { runProductSmoke } from "@norskvideo/ctl-test-harness/smoke";
1848
+
1849
+ // The listener inside the media container (the configured default), which the
1850
+ // pump dials on the docker network.
1851
+ const LISTENER_PORT = 5001;
1852
+ // The host side of that publish, moved off 5001: other products' smokes (and a
1853
+ // running demo) hold it on a shared runner.
1854
+ const INGEST_HOST_PORT = 27001 + hashSlot("${ctx.name}", 40) * 4;
1855
+
1856
+ test(
1857
+ "${ctx.name}: the graph comes up and takes the SRT feed",
1858
+ () =>
1859
+ runProductSmoke("${ctx.name}", {
1860
+ product: {
1861
+ name: "${ctx.name}",
1862
+ register: { image: process.env.SMOKE_IMAGE_TAG ?? "${ctx.name}:dev" },
1863
+ },
1864
+ template: { name: "default" },
1865
+ params: [\`INGEST_PORT=\${INGEST_HOST_PORT}\`],
1866
+ hardware: "none",
1867
+ sources: [{ port: LISTENER_PORT, name: "input", streamId: "input", preset: "camera1" }],
1868
+ observe: [
1869
+ { kind: "components", ids: ["ingest", "egest"] },
1870
+ { kind: "srt-connected", componentId: "ingest" },
1871
+ ],
1872
+ }),
1873
+ 600_000,
1874
+ );
1875
+ `;
1876
+ }
1877
+
1827
1878
  function demoSpecTs(ctx: ShapeContext): string {
1828
1879
  return `// The ${ctx.name} demo (fleet review 05-demo): the manifest's default
1829
1880
  // template with the daemon's camera1 sample pumped into the SRT ingest. Run by
@@ -2221,6 +2272,7 @@ export const turnkey: ShapeModule = {
2221
2272
  { path: "scripts/with-display.sh", content: ctx.canon.withDisplay, executable: true },
2222
2273
  { path: "scripts/docs-handover.sh", content: DOCS_HANDOVER_SH, executable: true },
2223
2274
  { path: "tests/demo.spec.ts", content: demoSpecTs(ctx) },
2275
+ { path: "tests/smoke.spec.ts", content: smokeSpecTs(ctx) },
2224
2276
  { path: "tests/unit/demo-spec.test.ts", content: DEMO_SPEC_TEST_TS },
2225
2277
  { path: "shared/package.json", content: sharedPackageJson(ctx) },
2226
2278
  { path: "shared/tsconfig.json", content: WORKSPACE_TSCONFIG },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@norskvideo/ctl-dev-kit",
3
- "version": "0.2.71",
3
+ "version": "0.2.74",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./create-product": "./create-product/create-product.ts",
@@ -39,10 +39,10 @@
39
39
  },
40
40
  "devDependencies": {
41
41
  "@norskvideo/ctl-oas-to-ts": "^0.1.0",
42
- "@norskvideo/norsk-sdk": "1.3.1-2026-10-10-c587f1cc",
43
- "@norskvideo/norsk-studio": "1.30.0-2026-10-11-3deeff4c",
44
- "@norskvideo/norsk-studio-builder": "1.30.0-2026-10-11-3deeff4c",
45
- "@norskvideo/norsk-studio-built-ins": "1.30.0-2026-10-11-3deeff4c",
42
+ "@norskvideo/norsk-sdk": "1.3.1-2026-10-11-6f132471",
43
+ "@norskvideo/norsk-studio": "1.30.0-2026-10-12-34c09bda",
44
+ "@norskvideo/norsk-studio-builder": "1.30.0-2026-10-12-34c09bda",
45
+ "@norskvideo/norsk-studio-built-ins": "1.30.0-2026-10-12-34c09bda",
46
46
  "@playwright/test": "^1.59.0",
47
47
  "@types/bun": "latest",
48
48
  "@types/cors": "^2.8.17",