@norskvideo/ctl-dev-kit 0.2.96 → 0.2.98

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.
@@ -47,6 +47,7 @@ COPY backend/dist ./backend/dist
47
47
  COPY native/ ./backend/dist/
48
48
  COPY frontend/dist ./frontend/dist
49
49
  COPY dashboards /usr/src/dashboards
50
+ COPY fleet-dashboards /usr/src/fleet-dashboards
50
51
  COPY components/lib /usr/src/components/lib
51
52
  # Optional product-template assets (funke's slate/black PNGs). Empty otherwise.
52
53
  COPY assets /usr/src/assets
@@ -20,6 +20,8 @@
20
20
  # having the directory/script — no per-product flag to keep in sync:
21
21
  # frontend/dist the frontend workspace's build output
22
22
  # dashboards/ the dashboard workspace's build output
23
+ # fleet-dashboards/ fleet dashboard bundles the product brings
24
+ # (its manifest's defaultDashboards)
23
25
  # components/lib the components workspace's build output
24
26
  # native/ native addon(s) (probe's signer) -> beside bundle
25
27
  # assets/ product-template assets (funke's PNGs)
@@ -52,7 +54,7 @@ trap 'rm -rf "${stage}"' EXIT
52
54
 
53
55
  echo "==> staging artifacts"
54
56
  mkdir -p "${stage}/backend" "${stage}/frontend/dist" "${stage}/components/lib" \
55
- "${stage}/dashboards" "${stage}/native" "${stage}/assets" "${stage}/docs"
57
+ "${stage}/dashboards" "${stage}/fleet-dashboards" "${stage}/native" "${stage}/assets" "${stage}/docs"
56
58
  # The backend bundle is the one non-negotiable payload — every bundle product has
57
59
  # one, so a missing dist is a broken build, not an absent workspace.
58
60
  cp -R "${PRODUCT_DIR}/backend/dist" "${stage}/backend/dist"
@@ -60,7 +62,7 @@ cp -R "${PRODUCT_DIR}/backend/dist" "${stage}/backend/dist"
60
62
  # Frontend / dashboards / components are produced by the workspaces of the same
61
63
  # name, so a product that has no such workspace never produces them (reuters:
62
64
  # backend-only). Staged empty in that case, exactly as native/ and assets/ below
63
- # — Dockerfile.bundle COPYs all six unconditionally, so the path must exist even
65
+ # — Dockerfile.bundle COPYs every one unconditionally, so the path must exist even
64
66
  # when there is nothing to put in it.
65
67
  if [ -d "${PRODUCT_DIR}/frontend/dist" ]; then
66
68
  cp -R "${PRODUCT_DIR}/frontend/dist/." "${stage}/frontend/dist/"
@@ -68,6 +70,12 @@ fi
68
70
  if [ -d "${PRODUCT_DIR}/dashboards" ]; then
69
71
  cp -R "${PRODUCT_DIR}/dashboards/." "${stage}/dashboards/"
70
72
  fi
73
+ # Fleet dashboards (norsk-ctl task 123): served by the control plane as the
74
+ # bundles its manifest's defaultDashboards name. Not under dashboards/, whose
75
+ # every directory is packed into each product template for Studio to serve.
76
+ if [ -d "${PRODUCT_DIR}/fleet-dashboards" ]; then
77
+ cp -R "${PRODUCT_DIR}/fleet-dashboards/." "${stage}/fleet-dashboards/"
78
+ fi
71
79
  if [ -d "${PRODUCT_DIR}/components/lib" ]; then
72
80
  cp -R "${PRODUCT_DIR}/components/lib/." "${stage}/components/lib/"
73
81
  fi
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.96",
3
+ "version": "0.2.98",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./create-product": "./create-product/create-product.ts",