@norskvideo/ctl-dev-kit 0.2.95 → 0.2.97

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.
Files changed (2) hide show
  1. package/dashboard/uses.ts +53 -16
  2. package/package.json +5 -5
package/dashboard/uses.ts CHANGED
@@ -1,16 +1,21 @@
1
1
  // What a fleet dashboard uses, derived from its own code when it is built
2
- // (RFC 0006 registration-names-what-it-uses, task 122 K): every kind its
3
- // `fleet.query` and `fleet.watch` calls name, read as literals. A call the
4
- // build cannot read, or any other use of the client, fails the build rather
5
- // than leave `dashboard.json` short of what the code reads.
2
+ // (RFC 0006 registration-names-what-it-uses, task 122 K, task 123 K): every
3
+ // kind its `fleet.query` and `fleet.watch` calls name, and every operationId
4
+ // its `fleet.call` and `fleet.live` calls name, read as literals.
5
+ // `fleet.state.get`/`put` use nothing a registration lists. A call the build
6
+ // cannot read, or any other use of the client, fails the build rather than
7
+ // leave `dashboard.json` short of what the code reaches.
6
8
 
7
9
  import ts from "typescript";
8
10
 
9
11
  export const FLEET_MODULE = "@norskvideo/ctl-sdk/fleet";
10
- const CALLS = new Set(["query", "watch"]);
12
+ const KIND_CALLS = new Set(["query", "watch"]);
13
+ const OPERATION_CALLS = new Set(["call", "live"]);
14
+ const STATE_CALLS = new Set(["get", "put"]);
11
15
 
12
16
  export interface DashboardUses {
13
17
  kinds: string[];
18
+ operations: string[];
14
19
  }
15
20
 
16
21
  export type UsesResult = { status: "ok"; value: DashboardUses } | { status: "error"; error: string[] };
@@ -38,6 +43,7 @@ function kindsOfSelection(arg: ts.Expression | undefined): string[] | undefined
38
43
 
39
44
  export function dashboardUses(files: readonly { path: string; source: string }[]): UsesResult {
40
45
  const kinds = new Set<string>();
46
+ const operations = new Set<string>();
41
47
  const problems: string[] = [];
42
48
  for (const { path, source } of files) {
43
49
  const sf = ts.createSourceFile(path, source, ts.ScriptTarget.Latest, true);
@@ -82,17 +88,48 @@ export function dashboardUses(files: readonly { path: string; source: string }[]
82
88
  ts.isCallExpression(node) &&
83
89
  ts.isPropertyAccessExpression(node.expression) &&
84
90
  ts.isIdentifier(node.expression.expression) &&
85
- clients.has(node.expression.expression.text) &&
86
- CALLS.has(node.expression.name.text)
91
+ clients.has(node.expression.expression.text)
87
92
  ) {
88
- const found = kindsOfSelection(node.arguments[0]);
89
- if (found === undefined) {
90
- problems.push(
91
- `${where(node)}: ${node.expression.getText()} must name its kind as a literal, or a list of literals, in the selection it is passed, so the dashboard's uses can be derived`,
92
- );
93
- } else {
94
- for (const kind of found) kinds.add(kind);
93
+ const method = node.expression.name.text;
94
+ if (KIND_CALLS.has(method)) {
95
+ const found = kindsOfSelection(node.arguments[0]);
96
+ if (found === undefined) {
97
+ problems.push(
98
+ `${where(node)}: ${node.expression.getText()} must name its kind as a literal, or a list of literals, in the selection it is passed, so the dashboard's uses can be derived`,
99
+ );
100
+ } else {
101
+ for (const kind of found) kinds.add(kind);
102
+ }
103
+ for (const arg of node.arguments) visit(arg);
104
+ return;
95
105
  }
106
+ if (OPERATION_CALLS.has(method)) {
107
+ const operation = node.arguments[1];
108
+ if (
109
+ operation !== undefined &&
110
+ (ts.isStringLiteral(operation) || ts.isNoSubstitutionTemplateLiteral(operation))
111
+ ) {
112
+ operations.add(operation.text);
113
+ } else {
114
+ problems.push(
115
+ `${where(node)}: ${node.expression.getText()} must name its operationId as a literal, so the dashboard's uses can be derived`,
116
+ );
117
+ }
118
+ for (const arg of node.arguments) visit(arg);
119
+ return;
120
+ }
121
+ }
122
+ // fleet.state.get(...) / .put(...): the host's shared state, which a
123
+ // registration does not list.
124
+ if (
125
+ ts.isCallExpression(node) &&
126
+ ts.isPropertyAccessExpression(node.expression) &&
127
+ STATE_CALLS.has(node.expression.name.text) &&
128
+ ts.isPropertyAccessExpression(node.expression.expression) &&
129
+ node.expression.expression.name.text === "state" &&
130
+ ts.isIdentifier(node.expression.expression.expression) &&
131
+ clients.has(node.expression.expression.expression.text)
132
+ ) {
96
133
  for (const arg of node.arguments) visit(arg);
97
134
  return;
98
135
  }
@@ -101,7 +138,7 @@ export function dashboardUses(files: readonly { path: string; source: string }[]
101
138
  const declaring = ts.isImportSpecifier(parent) || (ts.isVariableDeclaration(parent) && parent.name === node);
102
139
  if (!declaring) {
103
140
  problems.push(
104
- `${where(node)}: ${node.text} is used other than by calling its query or watch, so the build cannot see what it reads`,
141
+ `${where(node)}: ${node.text} is used other than by calling its query, watch, call, live or state.get/put, so the build cannot see what it reaches`,
105
142
  );
106
143
  }
107
144
  }
@@ -111,5 +148,5 @@ export function dashboardUses(files: readonly { path: string; source: string }[]
111
148
  }
112
149
  return problems.length > 0
113
150
  ? { status: "error", error: problems }
114
- : { status: "ok", value: { kinds: [...kinds].sort() } };
151
+ : { status: "ok", value: { kinds: [...kinds].sort(), operations: [...operations].sort() } };
115
152
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@norskvideo/ctl-dev-kit",
3
- "version": "0.2.95",
3
+ "version": "0.2.97",
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-16-e43e0f90",
43
- "@norskvideo/norsk-studio": "1.30.0-2026-10-17-4468cc12",
44
- "@norskvideo/norsk-studio-builder": "1.30.0-2026-10-17-4468cc12",
45
- "@norskvideo/norsk-studio-built-ins": "1.30.0-2026-10-17-4468cc12",
42
+ "@norskvideo/norsk-sdk": "1.3.1-2026-10-21-c97178c2",
43
+ "@norskvideo/norsk-studio": "1.30.0-2026-10-20-6fb182ff",
44
+ "@norskvideo/norsk-studio-builder": "1.30.0-2026-10-20-6fb182ff",
45
+ "@norskvideo/norsk-studio-built-ins": "1.30.0-2026-10-20-6fb182ff",
46
46
  "@playwright/test": "^1.59.0",
47
47
  "@testing-library/jest-dom": "^6.9.1",
48
48
  "@testing-library/react": "^16.3.2",