@norskvideo/ctl-test-harness 0.1.20 → 0.1.22

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/demo/run.d.ts CHANGED
@@ -1,8 +1,9 @@
1
+ import { type ManifestSeed } from "@norskvideo/ctl-sdk/manifest-seed";
1
2
  import { ensureRunnerOnNetwork } from "../container-net.js";
2
3
  import { type DaemonProcess, type StartDaemonOptions } from "../daemon.js";
3
4
  import { type BaseHarnessPorts } from "../harness-config.js";
4
5
  import { type SourceHandle, type SrtPumpTarget } from "../source-pump.js";
5
- import type { DemoIngest, DemoSpec } from "./spec.js";
6
+ import type { DemoDaemonPolicy, DemoIngest, DemoMode, DemoSpec, DemoTemplate } from "./spec.js";
6
7
  export interface CliResult {
7
8
  stdout: string;
8
9
  stderr: string;
@@ -16,20 +17,38 @@ export interface ProcessHandle {
16
17
  /** What `up` records so `down` (or a refused second `up`) can find the run. */
17
18
  export interface DemoState {
18
19
  product: string;
20
+ /** Absent on a demo's record; `dev-loop` on the standalone tier's, which
21
+ * lives beside it under its own file so the two never mistake each other. */
22
+ kind?: DemoStateKind;
19
23
  storeDir: string;
20
24
  daemonPort: number;
21
25
  instanceId?: string;
22
26
  devPid?: number;
27
+ /** Absent on records from before the policy existed: private. */
28
+ daemon?: DemoDaemonPolicy;
29
+ /** Extra containers `up` started, for `down` to remove. */
30
+ extras?: string[];
31
+ /** dev-loop: the exported workdir and the template it exported, for `refresh`. */
32
+ workdir?: string;
33
+ templateName?: string;
23
34
  }
35
+ export type DemoStateKind = "demo" | "dev-loop";
24
36
  export interface DemoStateStore {
25
- read(product: string): DemoState | null;
37
+ read(product: string, kind?: DemoStateKind): DemoState | null;
26
38
  write(state: DemoState): void;
27
- remove(product: string): void;
39
+ remove(product: string, kind?: DemoStateKind): void;
28
40
  }
29
41
  export interface DemoDeps {
30
42
  licenseFile(): string;
31
43
  storeDir(slug: string): string;
44
+ /** The developer's real store, for `--daemon reuse`. */
45
+ realStoreDir(): string;
32
46
  writeFile(path: string, contents: string): void;
47
+ /** Remove a file if present (the dev-loop's export stamp). */
48
+ removeFile(path: string): void;
49
+ /** File contents, or null when unreadable (compose.yml, manifest.seed.json,
50
+ * config.yaml, proxy-secret). */
51
+ readFile(path: string): string | null;
33
52
  fileExists(path: string): boolean;
34
53
  startDaemon(storeDir: string, options: StartDaemonOptions): {
35
54
  daemon: DaemonProcess;
@@ -42,11 +61,14 @@ export interface DemoDeps {
42
61
  cwd: string;
43
62
  env: Record<string, string>;
44
63
  }): ProcessHandle;
64
+ /** One `docker <argv>` invocation: extras, and the reuse policy's control-plane container sweep. */
65
+ docker(argv: string[]): CliResult;
45
66
  fetch(url: string, init?: RequestInit): Promise<Response>;
46
67
  startSources(opts: {
47
68
  daemonPort: number;
48
69
  instanceId: string;
49
70
  targets: readonly SrtPumpTarget[];
71
+ proxySecret?: string;
50
72
  timeoutMs?: number;
51
73
  }): Promise<SourceHandle[]>;
52
74
  stopSources(handles: SourceHandle[]): Promise<void>;
@@ -83,14 +105,21 @@ export interface DemoTimeouts {
83
105
  }
84
106
  export interface DemoRunOptions {
85
107
  action: "up" | "check";
86
- mode: "dev";
87
- /** The product repo root: dev command cwd, relative inputs and links. */
108
+ mode: DemoMode;
109
+ /** Default private. */
110
+ daemon?: DemoDaemonPolicy;
111
+ /** `reuse`: the daemon's port (default NORSK_CTL_PORT, else 8333). */
112
+ daemonPort?: number;
113
+ /** The product repo root: dev command cwd, relative inputs and links, manifest.seed.json. */
88
114
  cwd: string;
89
115
  /** Default: the product name without its `norsk-` prefix. */
90
116
  slug?: string;
91
117
  /** Releases an `up` hold. */
92
118
  abort?: AbortSignal;
93
119
  timeouts?: DemoTimeouts;
120
+ /** The hostname other machines reach this box by: every printed URL uses
121
+ * it, and a private daemon is initialised with it as its publicHost. */
122
+ publicHost?: string;
94
123
  }
95
124
  export interface DemoRunResult {
96
125
  instanceId: string;
@@ -134,6 +163,23 @@ export interface TemplateParams {
134
163
  * no parameter carries it and the instance offers it as the conventional
135
164
  * default, so the demo follows the template when the template moves. */
136
165
  export declare function resolveIngestPort(ingest: DemoIngest, rows: IngestPortRow[], t?: TemplateParams): number;
166
+ /** A stored template's `image:` ref that disagrees with the product's seed. */
167
+ export interface PinMismatch {
168
+ repo: string;
169
+ stored: string;
170
+ seed: string;
171
+ }
172
+ /** Image pins are read, never typed (05-demo s4): for every repo the seed's
173
+ * `latest` names (studio, media), the stored compose must pin the same ref.
174
+ * A repo the compose does not name is not a mismatch — the guard is about a
175
+ * stale snapshot, not template completeness. */
176
+ export declare function checkTemplatePins(composeText: string, seed: ManifestSeed): PinMismatch[];
177
+ /** The two config.yaml scalars the proxy URL needs; a regex, not a YAML
178
+ * parser, because that is all the driver reads from a store it does not own. */
179
+ export declare function parseProxyConfig(configText: string | null): {
180
+ scheme: "http" | "https";
181
+ port: number;
182
+ };
137
183
  export declare function findBrokenSymlinks(dir: string): string[];
138
184
  /** `<cwd>/test-temp/demo/<product>.json` — beside the store dirs, inside the
139
185
  * consumer's repo, where `down` from another shell can find it. */
@@ -142,6 +188,84 @@ export declare function fileStateStore(cwd: string): DemoStateStore;
142
188
  * own), falling back to the pid alone if it is not a group leader. */
143
189
  export declare function killGroup(pid: number): void;
144
190
  export declare function defaultDemoDeps(cwd: string): DemoDeps;
191
+ export interface SessionOptions {
192
+ mode: DemoMode;
193
+ daemon: DemoDaemonPolicy;
194
+ daemonPort?: number;
195
+ timeouts?: DemoTimeouts;
196
+ publicHost?: string;
197
+ /** Private: attach to an existing private store (a recorded run) instead of making one. */
198
+ storeDir?: string;
199
+ }
200
+ /** The pieces of a run that `runDemo`, `runExportCheck` and the dev-loop
201
+ * share: the daemon (private on its band, or the developer's), the dev
202
+ * backend on the driver's port, the registration, and the template (built
203
+ * or chosen). */
204
+ export declare class DemoSession {
205
+ readonly spec: DemoSpec;
206
+ readonly slug: string;
207
+ readonly cwd: string;
208
+ readonly deps: DemoDeps;
209
+ readonly mode: DemoMode;
210
+ readonly policy: DemoDaemonPolicy;
211
+ readonly ports: DemoPorts;
212
+ readonly storeDir: string;
213
+ /** The host every printed URL names. */
214
+ readonly host: string;
215
+ readonly publicHost: string | undefined;
216
+ /** Scheme + authority of the daemon's proxy, for `proxy` URLs. */
217
+ readonly proxyBase: string;
218
+ daemon: DaemonProcess | null;
219
+ dev: ProcessHandle | null;
220
+ extras: string[];
221
+ private readonly timeouts;
222
+ constructor(spec: DemoSpec, slug: string, cwd: string, deps: DemoDeps, opts: SessionOptions);
223
+ get devUrl(): string;
224
+ templateDir(name: string): string;
225
+ /** What the real daemon's proxy demands on `/api/*`; absent on a private daemon. */
226
+ proxySecret(): string | undefined;
227
+ cli: (argv: string[], opts?: {
228
+ output?: "json" | "yaml";
229
+ }) => Promise<CliResult>;
230
+ cliOk: (argv: string[], opts?: {
231
+ output?: "json" | "yaml";
232
+ }) => Promise<CliResult>;
233
+ /** Private: init a virgin store and start a daemon on the band. Reuse: the
234
+ * developer's daemon must already answer. */
235
+ attachDaemon(): Promise<void>;
236
+ startDev(): Promise<void>;
237
+ /** The reuse policy's mandatory sequence: `product add` refuses an existing
238
+ * name and stored templates are immutable, so the instance, every template
239
+ * the product publishes (plus the spec's built one), the product and its
240
+ * control-plane container all go first. Each step tolerates absence. */
241
+ resetRegistration(instanceId: string): Promise<void>;
242
+ register(opts: {
243
+ licence: boolean;
244
+ }): Promise<void>;
245
+ /** The template to launch: built from the spec's input, or a name the
246
+ * product publishes (its first default when the spec names none). */
247
+ resolveTemplate(t?: DemoTemplate | undefined): Promise<string>;
248
+ /** Funke's iterate.sh pin guard for every product: the stored compose must
249
+ * pin what manifest.seed.json declares. Image mode, and any reuse — a
250
+ * private dev-mode daemon renders the template fresh from source, so there
251
+ * is nothing stale to catch there. */
252
+ pinGuard(templateName: string): Promise<void>;
253
+ /** name -> stringified default, from `template show`. */
254
+ declaredParams(templateName: string): Promise<Map<string, string | undefined>>;
255
+ startExtras(instanceId: string): void;
256
+ stopExtras(): void;
257
+ waitRunning(instanceId: string): Promise<void>;
258
+ instanceListed(instanceId: string): Promise<boolean>;
259
+ ingestPorts(instanceId: string): Promise<IngestPortRow[]>;
260
+ gateTimeout(ms: number | undefined): number;
261
+ /** Tear down in reverse: sources, instance, then — private only — the
262
+ * daemon (with its proxy), the dev backend, the store. Reuse leaves the
263
+ * developer's daemon, store and registration as they are. */
264
+ teardown(opts: {
265
+ instances: string[];
266
+ handles: SourceHandle[];
267
+ }): Promise<void>;
268
+ }
145
269
  export declare function runDemo(spec: DemoSpec, opts: DemoRunOptions, deps?: DemoDeps): Promise<DemoRunResult>;
146
270
  export interface ExportCheckOptions {
147
271
  cwd: string;
@@ -156,5 +280,8 @@ export interface ExportCheckOptions {
156
280
  export declare function runExportCheck(spec: DemoSpec, opts: ExportCheckOptions, deps?: DemoDeps): Promise<{
157
281
  exportDir: string;
158
282
  }>;
283
+ /** `template export-workdir` with the spec's live-source links and params,
284
+ * then the check that rotted (05-demo s1): every symlink resolves. */
285
+ export declare function exportStandaloneWorkdir(s: DemoSession, templateName: string, to: string): Promise<void>;
159
286
  /** `demo down`: tear down the run `up` recorded, from any shell. */
160
287
  export declare function demoDown(product: string, deps?: DemoDeps): Promise<void>;