@norskvideo/ctl-dev-kit 0.2.8 → 0.2.9

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.
@@ -18,7 +18,7 @@
18
18
  // (conventions/* + build/*), resolved package-relative so they work both
19
19
  // workspace-symlinked and installed from the published tarball.
20
20
  import { execFileSync } from "node:child_process";
21
- import { existsSync, readFileSync, statSync } from "node:fs";
21
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
22
22
  import { join } from "node:path";
23
23
  import { parseManifestSeed } from "@norskvideo/ctl-sdk/manifest-seed";
24
24
  import { checkTheme } from "../docs-theme/sync.ts";
@@ -340,6 +340,49 @@ export function demoProblems(repoRoot: string, canonicalShim: string): string[]
340
340
  return problems;
341
341
  }
342
342
 
343
+ // Product logs (norsk-mgr docs/internal/design/product-logs.md): every compose
344
+ // service a product template declares must say how it logs, or the node's log
345
+ // agent ships nothing (or garbage) for it. The schema's
346
+ // productTemplateLogsProblems says what is wrong with one template; what this
347
+ // gate pins is that the repo asks it. A repo that packs a product template
348
+ // must have a test that calls it — the packer itself cannot refuse, since
349
+ // products also pack at runtime and a missed entry must not become a 500.
350
+ const PACKS_TEMPLATE = /\bpackProductTemplate\b/;
351
+ const CHECKS_LOGS = /\bproductTemplateLogsProblems\b/;
352
+ const SKIP_DIRS = new Set(["node_modules", ".git", "dist", "build", "lib", "coverage", ".wireit"]);
353
+
354
+ function sourceFiles(dir: string, out: string[] = []): string[] {
355
+ let names: string[];
356
+ try {
357
+ names = readdirSync(dir);
358
+ } catch {
359
+ return out;
360
+ }
361
+ for (const name of names) {
362
+ if (SKIP_DIRS.has(name)) continue;
363
+ const path = join(dir, name);
364
+ const st = statSync(path);
365
+ if (st.isDirectory()) sourceFiles(path, out);
366
+ else if (/\.(ts|tsx)$/.test(name)) out.push(path);
367
+ }
368
+ return out;
369
+ }
370
+
371
+ export function productLogsProblems(repoRoot: string): string[] {
372
+ const files = sourceFiles(repoRoot);
373
+ const read = (f: string) => readFileSync(f, "utf8");
374
+ if (!files.some((f) => PACKS_TEMPLATE.test(read(f)))) return [];
375
+ const tested = files.some((f) => /\.test\.tsx?$/.test(f) && CHECKS_LOGS.test(read(f)));
376
+ return tested
377
+ ? []
378
+ : [
379
+ "this repo packs a product template but no test calls productTemplateLogsProblems " +
380
+ "(@norskvideo/ctl-product-template-schema). Add one asserting it returns [] for every template " +
381
+ "the product builds, and give the manifest a `logs:` entry per compose service " +
382
+ "(norsk-mgr docs/internal/design/product-logs.md).",
383
+ ];
384
+ }
385
+
343
386
  // A file that must be a verbatim, byte-for-byte copy of its dev-kit canonical.
344
387
  function verbatimProblem(
345
388
  repoRoot: string,
@@ -737,6 +780,7 @@ export function checkDrift(repoRoot: string, canonical: CanonicalBytes, opts: Ch
737
780
  for (const p of docsThemeProblems(repoRoot, opts.themeCanonical)) push(p);
738
781
 
739
782
  for (const p of demoProblems(repoRoot, canonical.demoShim)) push(p);
783
+ for (const p of productLogsProblems(repoRoot)) push(p);
740
784
 
741
785
  return { ok: problems.length === 0, problems };
742
786
  }
@@ -1104,6 +1104,7 @@ import {
1104
1104
  type ProductTemplateMaterials,
1105
1105
  type ProductTemplateParameter,
1106
1106
  STANDARD_ADVANCED_OVERRIDES,
1107
+ STANDARD_LOGS,
1107
1108
  } from "@norskvideo/ctl-product-template-schema";
1108
1109
  import type { ComponentLibrary } from "@norskvideo/norsk-studio-builder";
1109
1110
  import { stringify as yamlStringify } from "yaml";
@@ -1155,6 +1156,10 @@ ${runtimeScreen} proxy: {
1155
1156
  expose: [${proxyExpose}],
1156
1157
  },
1157
1158
  advanced: { ...STANDARD_ADVANCED_OVERRIDES, ...opts.advanced },
1159
+ // How each compose service logs, for the node's log agent. A service
1160
+ // added to renderCompose needs its own entry here — the drift gate
1161
+ // requires a test (product-template.test.ts) that says so.
1162
+ logs: STANDARD_LOGS,
1158
1163
  };
1159
1164
 
1160
1165
  return {
@@ -1256,6 +1261,7 @@ import {
1256
1261
  ParametersFileSchema,
1257
1262
  ProductTemplateManifestSchema,
1258
1263
  ProductTemplateMaterialsSchema,
1264
+ productTemplateLogsProblems,
1259
1265
  } from "@norskvideo/ctl-product-template-schema";
1260
1266
  import { packProductTemplate } from "@norskvideo/ctl-product-template-schema/pack";
1261
1267
  import type { ComponentLibrary } from "@norskvideo/norsk-studio-builder";
@@ -1277,6 +1283,11 @@ describe("product-template materials", () => {
1277
1283
  expect(ProductTemplateMaterialsSchema.safeParse(materials).success).toBe(true);
1278
1284
  });
1279
1285
 
1286
+ it("declare how every compose service logs", () => {
1287
+ const materials = buildProductTemplateMaterials(ProductConfigSchema.parse(example), { library });
1288
+ expect(productTemplateLogsProblems(materials)).toEqual([]);
1289
+ });
1290
+
1280
1291
  it("pack to a tar whose entries round-trip through the schema package", () => {
1281
1292
  const materials = buildProductTemplateMaterials(ProductConfigSchema.parse(example), { library });
1282
1293
  const tar = packProductTemplate(materials);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@norskvideo/ctl-dev-kit",
3
- "version": "0.2.8",
3
+ "version": "0.2.9",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./create-product": "./create-product/create-product.ts",