@norskvideo/ctl-sdk 0.1.5 → 0.1.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@norskvideo/ctl-sdk",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -49,9 +49,11 @@ export type ImportProductTemplateBytesFn = (opts: {
49
49
  kind: "product-default";
50
50
  }>;
51
51
  }) => Promise<void>;
52
- /** The container operations stopAll/restoreAll depend on, behind an interface
53
- * so tests can drive them without shelling out to Docker. Defaults wire
54
- * straight to docker-runner + the readiness probe. */
52
+ /** Every container operation this service performs, behind an interface so
53
+ * tests can drive them without shelling out to Docker. Defaults wire straight
54
+ * to docker-runner + the readiness probe. Reach for these rather than the
55
+ * module functions: calling docker-runner directly re-creates the bypass that
56
+ * made an injected fake silently inert on add/remove. */
55
57
  export interface ProductContainerOps {
56
58
  run(image: string, hostPort: number): Promise<string>;
57
59
  remove(containerId: string): Promise<void>;
@@ -72,8 +74,8 @@ export interface ProductServiceOptions {
72
74
  /** Liveness probe for dev-mode products. Injectable for tests; defaults to a
73
75
  * fast timeout-bounded GET of the dev URL's `/manifest.json`. */
74
76
  isDevUrlAlive?: (baseUrl: string) => Promise<boolean>;
75
- /** Container lifecycle ops used by stopAll/restoreAll. Injectable for tests;
76
- * defaults to the real docker-runner functions. */
77
+ /** Container lifecycle ops used by add/remove/restart/stopAll/restoreAll.
78
+ * Injectable for tests; defaults to the real docker-runner functions. */
77
79
  containerOps?: ProductContainerOps;
78
80
  }
79
81
  export declare class ProductService {
@@ -76,25 +76,25 @@ export class ProductService {
76
76
  }
77
77
  port = allocated;
78
78
  logger.info(`Starting product container: ${spec.image} on host port ${port}`);
79
- containerId = await dockerRun(spec.image, port);
79
+ containerId = await this.containerOps.run(spec.image, port);
80
80
  baseUrl = specBaseUrl(spec, port);
81
81
  }
82
82
  try {
83
- await waitForReady(baseUrl);
83
+ await this.containerOps.waitForReady(baseUrl);
84
84
  }
85
85
  catch (e) {
86
86
  if (containerId)
87
- await dockerRm(containerId);
87
+ await this.containerOps.remove(containerId);
88
88
  throw e;
89
89
  }
90
90
  const manifest = await fetchManifest(baseUrl).catch(async (e) => {
91
91
  if (containerId)
92
- await dockerRm(containerId);
92
+ await this.containerOps.remove(containerId);
93
93
  throw e;
94
94
  });
95
95
  if (existing.some((p) => p.name === manifest.name)) {
96
96
  if (containerId)
97
- await dockerRm(containerId);
97
+ await this.containerOps.remove(containerId);
98
98
  throw new ProductError("NAME_CONFLICT", `product '${manifest.name}' already registered`);
99
99
  }
100
100
  const warnings = [];
@@ -111,7 +111,7 @@ export class ProductService {
111
111
  licenseFile = resolved.file;
112
112
  if (resolved.fatal) {
113
113
  if (containerId)
114
- await dockerRm(containerId);
114
+ await this.containerOps.remove(containerId);
115
115
  throw new ProductError("LICENSE_INVALID", resolved.fatal);
116
116
  }
117
117
  if (resolved.warning)
@@ -137,19 +137,19 @@ export class ProductService {
137
137
  const parsed = contents !== undefined ? parseLicenseContents(contents) : undefined;
138
138
  if (parsed?.kind === "invalid-v2") {
139
139
  if (containerId)
140
- await dockerRm(containerId);
140
+ await this.containerOps.remove(containerId);
141
141
  throw new ProductError("LICENSE_INVALID", parsed.reason);
142
142
  }
143
143
  if (parsed?.kind === "legacy") {
144
144
  if (containerId)
145
- await dockerRm(containerId);
145
+ await this.containerOps.remove(containerId);
146
146
  throw new ProductError("LICENSE_INVALID", notV2EnvelopeMessage("V1 licenses are no longer accepted at registration"));
147
147
  }
148
148
  if (parsed?.kind === "v2") {
149
149
  const check = checkProductEntitlement(parsed, manifest.name, spec.kind === "container" ? spec.image : undefined);
150
150
  if (!check.ok) {
151
151
  if (containerId)
152
- await dockerRm(containerId);
152
+ await this.containerOps.remove(containerId);
153
153
  throw new ProductError("LICENSE_INVALID", check.reason);
154
154
  }
155
155
  warnings.push(...check.warnings);
@@ -159,7 +159,7 @@ export class ProductService {
159
159
  // stable, human-readable name (replacing docker's random alias). Tracked
160
160
  // by id, so a rename failure is harmless — hence best-effort.
161
161
  if (containerId)
162
- await dockerRename(containerId, productContainerName(manifest.name));
162
+ await this.containerOps.rename(containerId, productContainerName(manifest.name));
163
163
  // Sanity-probe the config screen so we catch (a) URLs that don't
164
164
  // serve anything at the manifest-declared path, and (b) the common
165
165
  // "registered the vite dev port" mistake — both are hard rejections
@@ -170,7 +170,7 @@ export class ProductService {
170
170
  }
171
171
  catch (e) {
172
172
  if (containerId)
173
- await dockerRm(containerId);
173
+ await this.containerOps.remove(containerId);
174
174
  throw e;
175
175
  }
176
176
  }
@@ -227,7 +227,7 @@ export class ProductService {
227
227
  if (!target)
228
228
  throw new ProductError("NOT_FOUND", `product '${name}' not registered`);
229
229
  if (target.containerId)
230
- await dockerRm(target.containerId);
230
+ await this.containerOps.remove(target.containerId);
231
231
  await this.store.update((products) => products.filter((p) => p.name !== name));
232
232
  logger.info(`Product '${name}' removed`);
233
233
  }