@telorun/kernel 0.48.0 → 0.50.0

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 (194) hide show
  1. package/dist/controller-loader.d.ts +6 -1
  2. package/dist/controller-loader.d.ts.map +1 -1
  3. package/dist/controller-loader.js +2 -0
  4. package/dist/controller-loader.js.map +1 -1
  5. package/dist/controller-loaders/bundle-builder.d.ts +2 -1
  6. package/dist/controller-loaders/bundle-builder.d.ts.map +1 -1
  7. package/dist/controller-loaders/bundle-builder.js +14 -9
  8. package/dist/controller-loaders/bundle-builder.js.map +1 -1
  9. package/dist/controller-loaders/npm-loader.d.ts +8 -2
  10. package/dist/controller-loaders/npm-loader.d.ts.map +1 -1
  11. package/dist/controller-loaders/npm-loader.js +19 -10
  12. package/dist/controller-loaders/npm-loader.js.map +1 -1
  13. package/dist/controllers/logging/console-sink-controller.d.ts +15 -0
  14. package/dist/controllers/logging/console-sink-controller.d.ts.map +1 -0
  15. package/dist/controllers/logging/console-sink-controller.js +40 -0
  16. package/dist/controllers/logging/console-sink-controller.js.map +1 -0
  17. package/dist/controllers/logging/file-sink-controller.d.ts +11 -0
  18. package/dist/controllers/logging/file-sink-controller.d.ts.map +1 -0
  19. package/dist/controllers/logging/file-sink-controller.js +33 -0
  20. package/dist/controllers/logging/file-sink-controller.js.map +1 -0
  21. package/dist/controllers/logging/sink-identity.d.ts +37 -0
  22. package/dist/controllers/logging/sink-identity.d.ts.map +1 -0
  23. package/dist/controllers/logging/sink-identity.js +40 -0
  24. package/dist/controllers/logging/sink-identity.js.map +1 -0
  25. package/dist/controllers/module/import-controller.d.ts.map +1 -1
  26. package/dist/controllers/module/import-controller.js +25 -0
  27. package/dist/controllers/module/import-controller.js.map +1 -1
  28. package/dist/controllers/resource-definition/resource-definition-controller.d.ts.map +1 -1
  29. package/dist/controllers/resource-definition/resource-definition-controller.js +1 -0
  30. package/dist/controllers/resource-definition/resource-definition-controller.js.map +1 -1
  31. package/dist/evaluation-context.d.ts +27 -1
  32. package/dist/evaluation-context.d.ts.map +1 -1
  33. package/dist/evaluation-context.js +84 -16
  34. package/dist/evaluation-context.js.map +1 -1
  35. package/dist/index.d.ts +4 -0
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +5 -0
  38. package/dist/index.js.map +1 -1
  39. package/dist/internal-context.d.ts +4 -0
  40. package/dist/internal-context.d.ts.map +1 -1
  41. package/dist/kernel.d.ts +26 -0
  42. package/dist/kernel.d.ts.map +1 -1
  43. package/dist/kernel.js +78 -5
  44. package/dist/kernel.js.map +1 -1
  45. package/dist/logging/bootstrap-writer.d.ts +23 -0
  46. package/dist/logging/bootstrap-writer.d.ts.map +1 -0
  47. package/dist/logging/bootstrap-writer.js +31 -0
  48. package/dist/logging/bootstrap-writer.js.map +1 -0
  49. package/dist/logging/color-precedence.d.ts +27 -0
  50. package/dist/logging/color-precedence.d.ts.map +1 -0
  51. package/dist/logging/color-precedence.js +47 -0
  52. package/dist/logging/color-precedence.js.map +1 -0
  53. package/dist/logging/console-sink.d.ts +45 -0
  54. package/dist/logging/console-sink.d.ts.map +1 -0
  55. package/dist/logging/console-sink.js +56 -0
  56. package/dist/logging/console-sink.js.map +1 -0
  57. package/dist/logging/debug-wire-sink.d.ts +38 -0
  58. package/dist/logging/debug-wire-sink.d.ts.map +1 -0
  59. package/dist/logging/debug-wire-sink.js +85 -0
  60. package/dist/logging/debug-wire-sink.js.map +1 -0
  61. package/dist/logging/drop-accounting.d.ts +34 -0
  62. package/dist/logging/drop-accounting.d.ts.map +1 -0
  63. package/dist/logging/drop-accounting.js +98 -0
  64. package/dist/logging/drop-accounting.js.map +1 -0
  65. package/dist/logging/encode-json.d.ts +28 -0
  66. package/dist/logging/encode-json.d.ts.map +1 -0
  67. package/dist/logging/encode-json.js +86 -0
  68. package/dist/logging/encode-json.js.map +1 -0
  69. package/dist/logging/encode-pretty.d.ts +7 -0
  70. package/dist/logging/encode-pretty.d.ts.map +1 -0
  71. package/dist/logging/encode-pretty.js +104 -0
  72. package/dist/logging/encode-pretty.js.map +1 -0
  73. package/dist/logging/file-sink.d.ts +33 -0
  74. package/dist/logging/file-sink.d.ts.map +1 -0
  75. package/dist/logging/file-sink.js +72 -0
  76. package/dist/logging/file-sink.js.map +1 -0
  77. package/dist/logging/index.d.ts +39 -0
  78. package/dist/logging/index.d.ts.map +1 -0
  79. package/dist/logging/index.js +27 -0
  80. package/dist/logging/index.js.map +1 -0
  81. package/dist/logging/kernel-logging.d.ts +110 -0
  82. package/dist/logging/kernel-logging.d.ts.map +1 -0
  83. package/dist/logging/kernel-logging.js +199 -0
  84. package/dist/logging/kernel-logging.js.map +1 -0
  85. package/dist/logging/log-sink.d.ts +9 -0
  86. package/dist/logging/log-sink.d.ts.map +1 -0
  87. package/dist/logging/log-sink.js +8 -0
  88. package/dist/logging/log-sink.js.map +1 -0
  89. package/dist/logging/logging-host.d.ts +14 -0
  90. package/dist/logging/logging-host.d.ts.map +1 -0
  91. package/dist/logging/logging-host.js +27 -0
  92. package/dist/logging/logging-host.js.map +1 -0
  93. package/dist/logging/logging-pipeline.d.ts +89 -0
  94. package/dist/logging/logging-pipeline.d.ts.map +1 -0
  95. package/dist/logging/logging-pipeline.js +349 -0
  96. package/dist/logging/logging-pipeline.js.map +1 -0
  97. package/dist/logging/normalize-attributes.d.ts +48 -0
  98. package/dist/logging/normalize-attributes.d.ts.map +1 -0
  99. package/dist/logging/normalize-attributes.js +140 -0
  100. package/dist/logging/normalize-attributes.js.map +1 -0
  101. package/dist/logging/record-buffer.d.ts +24 -0
  102. package/dist/logging/record-buffer.d.ts.map +1 -0
  103. package/dist/logging/record-buffer.js +78 -0
  104. package/dist/logging/record-buffer.js.map +1 -0
  105. package/dist/logging/redact-attributes.d.ts +45 -0
  106. package/dist/logging/redact-attributes.d.ts.map +1 -0
  107. package/dist/logging/redact-attributes.js +152 -0
  108. package/dist/logging/redact-attributes.js.map +1 -0
  109. package/dist/logging/sampler.d.ts +34 -0
  110. package/dist/logging/sampler.d.ts.map +1 -0
  111. package/dist/logging/sampler.js +52 -0
  112. package/dist/logging/sampler.js.map +1 -0
  113. package/dist/logging/scope-config.d.ts +32 -0
  114. package/dist/logging/scope-config.d.ts.map +1 -0
  115. package/dist/logging/scope-config.js +2 -0
  116. package/dist/logging/scope-config.js.map +1 -0
  117. package/dist/logging/span-id.d.ts +24 -0
  118. package/dist/logging/span-id.d.ts.map +1 -0
  119. package/dist/logging/span-id.js +85 -0
  120. package/dist/logging/span-id.js.map +1 -0
  121. package/dist/logging/to-error-value.d.ts +3 -0
  122. package/dist/logging/to-error-value.d.ts.map +1 -0
  123. package/dist/logging/to-error-value.js +79 -0
  124. package/dist/logging/to-error-value.js.map +1 -0
  125. package/dist/logging/trace-parent.d.ts +54 -0
  126. package/dist/logging/trace-parent.d.ts.map +1 -0
  127. package/dist/logging/trace-parent.js +92 -0
  128. package/dist/logging/trace-parent.js.map +1 -0
  129. package/dist/manifest-schemas.d.ts +1 -1
  130. package/dist/manifest-schemas.d.ts.map +1 -1
  131. package/dist/manifest-schemas.js +12 -0
  132. package/dist/manifest-schemas.js.map +1 -1
  133. package/dist/module-context.d.ts +16 -0
  134. package/dist/module-context.d.ts.map +1 -1
  135. package/dist/module-context.js +6 -0
  136. package/dist/module-context.js.map +1 -1
  137. package/dist/resource-context.d.ts +15 -1
  138. package/dist/resource-context.d.ts.map +1 -1
  139. package/dist/resource-context.js +45 -0
  140. package/dist/resource-context.js.map +1 -1
  141. package/dist/schema-compiled-values.d.ts.map +1 -1
  142. package/dist/schema-compiled-values.js +7 -0
  143. package/dist/schema-compiled-values.js.map +1 -1
  144. package/dist/schema-validator.d.ts +8 -1
  145. package/dist/schema-validator.d.ts.map +1 -1
  146. package/dist/schema-validator.js +13 -3
  147. package/dist/schema-validator.js.map +1 -1
  148. package/dist/transports/oci/oci-client.d.ts.map +1 -1
  149. package/dist/transports/oci/oci-client.js +13 -3
  150. package/dist/transports/oci/oci-client.js.map +1 -1
  151. package/dist/transports/registry-transport.d.ts.map +1 -1
  152. package/dist/transports/registry-transport.js +15 -5
  153. package/dist/transports/registry-transport.js.map +1 -1
  154. package/package.json +3 -3
  155. package/src/controller-loader.ts +7 -1
  156. package/src/controller-loaders/bundle-builder.ts +18 -10
  157. package/src/controller-loaders/npm-loader.ts +32 -11
  158. package/src/controllers/logging/console-sink-controller.ts +46 -0
  159. package/src/controllers/logging/file-sink-controller.ts +40 -0
  160. package/src/controllers/logging/sink-identity.ts +53 -0
  161. package/src/controllers/module/import-controller.ts +27 -0
  162. package/src/controllers/resource-definition/resource-definition-controller.ts +1 -0
  163. package/src/evaluation-context.ts +93 -15
  164. package/src/index.ts +54 -0
  165. package/src/internal-context.ts +4 -0
  166. package/src/kernel.ts +98 -8
  167. package/src/logging/bootstrap-writer.ts +38 -0
  168. package/src/logging/color-precedence.ts +62 -0
  169. package/src/logging/console-sink.ts +86 -0
  170. package/src/logging/debug-wire-sink.ts +85 -0
  171. package/src/logging/drop-accounting.ts +108 -0
  172. package/src/logging/encode-json.ts +98 -0
  173. package/src/logging/encode-pretty.ts +117 -0
  174. package/src/logging/file-sink.ts +87 -0
  175. package/src/logging/index.ts +65 -0
  176. package/src/logging/kernel-logging.ts +266 -0
  177. package/src/logging/log-sink.ts +18 -0
  178. package/src/logging/logging-host.ts +33 -0
  179. package/src/logging/logging-pipeline.ts +465 -0
  180. package/src/logging/normalize-attributes.ts +228 -0
  181. package/src/logging/record-buffer.ts +72 -0
  182. package/src/logging/redact-attributes.ts +168 -0
  183. package/src/logging/sampler.ts +76 -0
  184. package/src/logging/scope-config.ts +32 -0
  185. package/src/logging/span-id.ts +84 -0
  186. package/src/logging/to-error-value.ts +89 -0
  187. package/src/logging/trace-parent.ts +110 -0
  188. package/src/manifest-schemas.ts +12 -0
  189. package/src/module-context.ts +23 -0
  190. package/src/resource-context.ts +48 -0
  191. package/src/schema-compiled-values.ts +6 -0
  192. package/src/schema-validator.ts +20 -5
  193. package/src/transports/oci/oci-client.ts +13 -3
  194. package/src/transports/registry-transport.ts +23 -5
@@ -1,4 +1,5 @@
1
1
  import { executeInvokeStep, getRefIdentity, RuntimeError } from "@telorun/sdk";
2
+ import type { ScopeConfig } from "./logging/scope-config.js";
2
3
  import type {
3
4
  BootTarget,
4
5
  ControllerPolicy,
@@ -128,6 +129,20 @@ export class ModuleContext extends EvaluationContext implements IModuleContext {
128
129
  */
129
130
  private _controllerPolicy: ControllerPolicy | undefined;
130
131
 
132
+ /**
133
+ * The effective logging configuration for this module context — threshold,
134
+ * redaction, sampling, and the dotted import-alias path that identifies it.
135
+ *
136
+ * Stamped by the parent `Telo.Import` controller, which merges the import's
137
+ * own `logging:` block over its parent's *once*, when the import graph is
138
+ * built. Resolution therefore happens at load and the result is a plain value:
139
+ * there is no per-record lookup and no walk up the import chain at emit time,
140
+ * and it is the same scalar a guest runtime caches across an FFI boundary, so
141
+ * scoping and the FFI threshold cache are one mechanism rather than two.
142
+ * See kernel/specs/logging.md §12.2 and §9.
143
+ */
144
+ private _loggingConfig: ScopeConfig | undefined;
145
+
131
146
  constructor(
132
147
  source: string,
133
148
  variables: Record<string, unknown> = {},
@@ -192,6 +207,14 @@ export class ModuleContext extends EvaluationContext implements IModuleContext {
192
207
  return this._controllerPolicy;
193
208
  }
194
209
 
210
+ setLoggingConfig(config: ScopeConfig | undefined): void {
211
+ this._loggingConfig = config;
212
+ }
213
+
214
+ getLoggingConfig(): ScopeConfig | undefined {
215
+ return this._loggingConfig;
216
+ }
217
+
195
218
  protected override onResourceSnapshotted(name: string, snap: Record<string, unknown>): void {
196
219
  this.setResource(name, snap);
197
220
  }
@@ -12,6 +12,7 @@ import {
12
12
  type InvokeContext,
13
13
  type LoadOptions,
14
14
  type ModuleContext,
15
+ type Logger,
15
16
  type OpenSpan,
16
17
  type OpenSpanOptions,
17
18
  type ParsedArgs,
@@ -19,6 +20,14 @@ import {
19
20
  } from "@telorun/sdk";
20
21
  import { isRefSentinel } from "@telorun/templating";
21
22
  import { hostEnv } from "./host-env.js";
23
+ import type { LoggingHost } from "./logging/logging-host.js";
24
+ import type { ScopeConfig } from "./logging/scope-config.js";
25
+
26
+ /** The kernel's `ModuleContext` as far as logging is concerned. Declared
27
+ * structurally rather than imported to avoid a module cycle. */
28
+ interface KernelModuleContext {
29
+ getLoggingConfig?(): ScopeConfig | undefined;
30
+ }
22
31
  import { stripCompiledValues } from "./schema-compiled-values.js";
23
32
  import AjvModule from "ajv";
24
33
  import addFormats from "ajv-formats";
@@ -44,6 +53,45 @@ export class ResourceContextImpl implements ResourceContext {
44
53
  * and stamps the owner on the child context it registers them into. */
45
54
  readonly ownerPrefix: string;
46
55
 
56
+ /** Built lazily: most resources never log, and constructing the scoped logger
57
+ * eagerly for every context would allocate per resource for nothing. */
58
+ #log: Logger | undefined;
59
+
60
+ /**
61
+ * The resource's structured logger, stamped with its identity, module, and
62
+ * import-alias scope so a record identifies *which instance* emitted it — the
63
+ * distinction `module` alone cannot make when the same library is imported
64
+ * twice (§7.3).
65
+ */
66
+ get log(): Logger {
67
+ if (!this.#log) {
68
+ const kind = this.metadata?.kind as string | undefined;
69
+ const name = this.metadata?.metadata?.name as string | undefined;
70
+ const resource =
71
+ kind && name
72
+ ? { kind, name, id: `${this.ownerPrefix}${kind}.${name}` }
73
+ : undefined;
74
+ // The runtime value is always the kernel's `ModuleContext`, which carries
75
+ // the resolved per-scope config; the field is typed as the SDK's narrower
76
+ // interface, which deliberately does not expose kernel-internal state.
77
+ const scope = (
78
+ this.moduleContext as unknown as KernelModuleContext
79
+ ).getLoggingConfig?.();
80
+ this.#log = this.kernel.logging.createLogger(scope, resource);
81
+ }
82
+ return this.#log;
83
+ }
84
+
85
+ /** The sink-facing half of the pipeline. Only the built-in sink controllers
86
+ * reach for it; every other controller uses {@link log}. */
87
+ get logging(): LoggingHost {
88
+ return this.kernel.logging.host;
89
+ }
90
+
91
+ kernelLoggingRootScope(): ScopeConfig {
92
+ return this.kernel.logging.rootScope;
93
+ }
94
+
47
95
  constructor(
48
96
  readonly kernel: Kernel,
49
97
  readonly moduleContext: ModuleContext,
@@ -3,6 +3,12 @@ import { isCompiledValue } from "@telorun/sdk";
3
3
  /** Returns a schema-appropriate placeholder value for a CompiledValue field. */
4
4
  function placeholderForSchema(schema: Record<string, unknown>): unknown {
5
5
  if (schema.default !== undefined) return schema.default;
6
+ // An enum-constrained field needs a placeholder drawn from the enum: the
7
+ // type-based fallbacks below satisfy `type` but violate `enum`, so any CEL
8
+ // expression feeding an enum field would fail validation against a value the
9
+ // author never wrote. Mirrors `celPlaceholderForSchema` in the analyzer, which
10
+ // performs the same substitution for the static half.
11
+ if (Array.isArray(schema.enum) && schema.enum.length > 0) return schema.enum[0];
6
12
  switch (schema.type) {
7
13
  case "integer":
8
14
  case "number":
@@ -1,5 +1,5 @@
1
1
  import { evaluate } from "@marcbachmann/cel-js";
2
- import { DataValidator, isCompiledValue, RuntimeError, TypeRule } from "@telorun/sdk";
2
+ import { DataValidator, isCompiledValue, NOOP_LOGGER, RuntimeError, TypeRule, type Logger } from "@telorun/sdk";
3
3
  import AjvModule, { type ValidateFunction } from "ajv";
4
4
  import standaloneCodeMod from "ajv/dist/standalone/index.js";
5
5
  import addFormats from "ajv-formats";
@@ -148,6 +148,16 @@ export class SchemaValidator {
148
148
  * process — `compiledValidators` is keyed by object identity and would
149
149
  * miss those cases. */
150
150
  private hashCache = new Map<string, DataValidator>();
151
+ /** Where cache-failure diagnostics go. Injected rather than reached for
152
+ * globally: this class is constructed outside the kernel's stdio scope, and
153
+ * §13.1 forbids the kernel writing to `process.stderr` directly. Defaults to
154
+ * a no-op so a standalone construction (tests, tooling) stays silent. */
155
+ private log: Logger = NOOP_LOGGER;
156
+
157
+ /** Route cache diagnostics through the kernel's logger. */
158
+ setLogger(log: Logger): void {
159
+ this.log = log;
160
+ }
151
161
 
152
162
  constructor() {
153
163
  this.ajv = new Ajv({
@@ -172,6 +182,7 @@ export class SchemaValidator {
172
182
  "x-telo-step-context",
173
183
  "x-telo-widget",
174
184
  "x-telo-type",
185
+ "x-telo-inline",
175
186
  ]) {
176
187
  this.ajv.addKeyword(kw);
177
188
  }
@@ -342,8 +353,10 @@ export class SchemaValidator {
342
353
  // stale file with a fresh hash header.
343
354
  } catch (err) {
344
355
  if ((err as NodeJS.ErrnoException)?.code !== "ENOENT") {
345
- process.stderr.write(
346
- `[telo:kernel] validator cache load failed (${hash}): ${err instanceof Error ? err.message : String(err)}\n`,
356
+ this.log.warn(
357
+ "validator cache load failed",
358
+ { "telo.validator.hash": hash },
359
+ { error: err },
347
360
  );
348
361
  }
349
362
  }
@@ -358,8 +371,10 @@ export class SchemaValidator {
358
371
  fs.mkdirSync(cacheDir, { recursive: true });
359
372
  fs.writeFileSync(path.join(cacheDir, `${hash}.cjs`), payload, "utf-8");
360
373
  } catch (err) {
361
- process.stderr.write(
362
- `[telo:kernel] validator cache write failed (${hash}): ${err instanceof Error ? err.message : String(err)}\n`,
374
+ this.log.warn(
375
+ "validator cache write failed",
376
+ { "telo.validator.hash": hash },
377
+ { error: err },
363
378
  );
364
379
  }
365
380
  }
@@ -1,3 +1,4 @@
1
+ import { fetchOrThrow } from "@telorun/sdk";
1
2
  import { createHash } from "node:crypto";
2
3
 
3
4
  import { assertPublicEgress } from "../egress-guard.js";
@@ -109,7 +110,10 @@ export class OciClient {
109
110
  };
110
111
 
111
112
  const cached = this.tokenByScope.get(scope);
112
- let res = await fetch(url, withToken(cached));
113
+ let res = await fetchOrThrow(url, withToken(cached), {
114
+ operation: "OCI registry request",
115
+ setting: "the oci:// ref host",
116
+ });
113
117
  if (res.status !== 401) return res;
114
118
 
115
119
  const challenge = res.headers.get("www-authenticate");
@@ -119,7 +123,10 @@ export class OciClient {
119
123
  this.tokenByScope.set(scope, token);
120
124
  // Drain the 401 body so the connection can be reused.
121
125
  await res.text().catch(() => {});
122
- return fetch(url, withToken(token));
126
+ return fetchOrThrow(url, withToken(token), {
127
+ operation: "OCI registry request",
128
+ setting: "the oci:// ref host",
129
+ });
123
130
  }
124
131
 
125
132
  /** Exchange a bearer challenge for a token, authenticating to the token
@@ -141,7 +148,10 @@ export class OciClient {
141
148
  const basic = Buffer.from(`${cred.username}:${cred.password}`).toString("base64");
142
149
  headers.set("authorization", `Basic ${basic}`);
143
150
  }
144
- const res = await fetch(tokenUrl.href, { headers });
151
+ const res = await fetchOrThrow(tokenUrl.href, { headers }, {
152
+ operation: "OCI registry auth",
153
+ setting: "the oci:// ref host",
154
+ });
145
155
  if (!res.ok) return null;
146
156
  const body = (await res.json()) as { token?: string; access_token?: string };
147
157
  return body.token ?? body.access_token ?? null;
@@ -9,6 +9,7 @@ import {
9
9
  splitIntegrity,
10
10
  type ManifestSource,
11
11
  } from "@telorun/analyzer";
12
+ import { fetchOrThrow } from "@telorun/sdk";
12
13
  import { createHash } from "crypto";
13
14
 
14
15
  import { computeFilesIntegrity, injectFilesIntegrity } from "../bundle/files-integrity.js";
@@ -159,7 +160,11 @@ export class RegistryTransport implements Transport {
159
160
  const { modulePath } = parseModuleRef(ref);
160
161
  const url = `${this.registryUrl.replace(/\/+$/, "")}/${modulePath}`;
161
162
  await assertPublicEgress(url);
162
- const res = await fetch(url, { headers: { accept: "application/json" } });
163
+ const res = await fetchOrThrow(
164
+ url,
165
+ { headers: { accept: "application/json" } },
166
+ { operation: "Registry version list", setting: "--registry / TELO_REGISTRY" },
167
+ );
163
168
  if (res.status === 404) return null;
164
169
  if (!res.ok) {
165
170
  throw new Error(`Registry returned ${res.status} ${res.statusText} for ${modulePath}`);
@@ -189,7 +194,10 @@ export class RegistryTransport implements Transport {
189
194
  const fetchUrl = this.manifestUrl(ref);
190
195
  if (!fetchUrl) return null;
191
196
  await assertPublicEgress(fetchUrl);
192
- const res = await fetch(fetchUrl);
197
+ const res = await fetchOrThrow(fetchUrl, undefined, {
198
+ operation: "Registry manifest read",
199
+ setting: "--registry / TELO_REGISTRY",
200
+ });
193
201
  if (res.status === 404) return null;
194
202
  if (!res.ok) {
195
203
  throw new Error(`Registry returned ${res.status} ${res.statusText} for ${fetchUrl}`);
@@ -206,7 +214,10 @@ export class RegistryTransport implements Transport {
206
214
  throw new Error(`cannot hash non-remote import '${ref}'`);
207
215
  }
208
216
  await assertPublicEgress(fetchUrl);
209
- const res = await fetch(fetchUrl);
217
+ const res = await fetchOrThrow(fetchUrl, undefined, {
218
+ operation: "Registry manifest hash",
219
+ setting: "--registry / TELO_REGISTRY",
220
+ });
210
221
  if (!res.ok) {
211
222
  throw new Error(`fetch ${fetchUrl}: ${res.status} ${res.statusText}`);
212
223
  }
@@ -223,7 +234,10 @@ export class RegistryTransport implements Transport {
223
234
  // The payload rides beside the manifest as `module.tar.gz`.
224
235
  const tarUrl = source.replace(/\/telo\.yaml$/, "/module.tar.gz");
225
236
  await assertPublicEgress(tarUrl);
226
- const res = await fetch(tarUrl);
237
+ const res = await fetchOrThrow(tarUrl, undefined, {
238
+ operation: "Module payload download",
239
+ setting: "--registry / TELO_REGISTRY",
240
+ });
227
241
  if (!res.ok) {
228
242
  throw new Error(`could not fetch bundle ${tarUrl}: ${res.status} ${res.statusText}`);
229
243
  }
@@ -285,7 +299,11 @@ export class RegistryTransport implements Transport {
285
299
  for (let attempt = 1; attempt <= MAX_PUSH_ATTEMPTS; attempt++) {
286
300
  networkErr = null;
287
301
  try {
288
- res = await fetch(url, { method: "PUT", headers, body });
302
+ res = await fetchOrThrow(
303
+ url,
304
+ { method: "PUT", headers, body },
305
+ { operation: "Registry publish", setting: "--registry / TELO_REGISTRY" },
306
+ );
289
307
  } catch (err) {
290
308
  networkErr = err;
291
309
  res = null;