@qlever-llc/trellis 0.10.11 → 0.10.12

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 (110) hide show
  1. package/esm/errors/TrellisError.d.ts +3 -3
  2. package/esm/errors/TrellisError.js +3 -3
  3. package/esm/server/internal_jobs/job-manager.d.ts.map +1 -1
  4. package/esm/server/internal_jobs/job-manager.js +32 -1
  5. package/esm/server/runtime.d.ts +3 -0
  6. package/esm/server/runtime.d.ts.map +1 -1
  7. package/esm/server/service.d.ts +15 -0
  8. package/esm/server/service.d.ts.map +1 -1
  9. package/esm/server/service.js +8 -0
  10. package/esm/server.d.ts.map +1 -1
  11. package/esm/server.js +54 -6
  12. package/esm/service/deno.d.ts +1 -1
  13. package/esm/service/deno.d.ts.map +1 -1
  14. package/esm/service/mod.d.ts +1 -1
  15. package/esm/service/mod.d.ts.map +1 -1
  16. package/esm/service/node.d.ts +1 -1
  17. package/esm/service/node.d.ts.map +1 -1
  18. package/esm/service/outbox_inbox.d.ts.map +1 -1
  19. package/esm/service/outbox_inbox.js +14 -0
  20. package/esm/telemetry/core.d.ts.map +1 -1
  21. package/esm/telemetry/core.js +1 -1
  22. package/esm/telemetry/env.d.ts.map +1 -1
  23. package/esm/telemetry/env.js +6 -1
  24. package/esm/telemetry/init.d.ts +3 -0
  25. package/esm/telemetry/init.d.ts.map +1 -0
  26. package/esm/telemetry/init.js +7 -0
  27. package/esm/telemetry/metrics.d.ts +34 -0
  28. package/esm/telemetry/metrics.d.ts.map +1 -0
  29. package/esm/telemetry/metrics.js +181 -0
  30. package/esm/telemetry/mod.d.ts +3 -0
  31. package/esm/telemetry/mod.d.ts.map +1 -1
  32. package/esm/telemetry/mod.js +2 -0
  33. package/esm/telemetry/runtime.d.ts +2 -0
  34. package/esm/telemetry/runtime.d.ts.map +1 -0
  35. package/esm/telemetry/runtime.js +134 -0
  36. package/esm/telemetry.d.ts +3 -0
  37. package/esm/telemetry.d.ts.map +1 -0
  38. package/esm/telemetry.js +2 -0
  39. package/esm/transfer.d.ts.map +1 -1
  40. package/esm/transfer.js +27 -16
  41. package/esm/trellis.d.ts.map +1 -1
  42. package/esm/trellis.js +460 -56
  43. package/package.json +7 -5
  44. package/script/errors/TrellisError.d.ts +3 -3
  45. package/script/errors/TrellisError.js +3 -3
  46. package/script/server/internal_jobs/job-manager.d.ts.map +1 -1
  47. package/script/server/internal_jobs/job-manager.js +32 -1
  48. package/script/server/runtime.d.ts +3 -0
  49. package/script/server/runtime.d.ts.map +1 -1
  50. package/script/server/service.d.ts +15 -0
  51. package/script/server/service.d.ts.map +1 -1
  52. package/script/server/service.js +8 -0
  53. package/script/server.d.ts.map +1 -1
  54. package/script/server.js +54 -6
  55. package/script/service/deno.d.ts +1 -1
  56. package/script/service/deno.d.ts.map +1 -1
  57. package/script/service/mod.d.ts +1 -1
  58. package/script/service/mod.d.ts.map +1 -1
  59. package/script/service/node.d.ts +1 -1
  60. package/script/service/node.d.ts.map +1 -1
  61. package/script/service/outbox_inbox.d.ts.map +1 -1
  62. package/script/service/outbox_inbox.js +14 -0
  63. package/script/telemetry/core.d.ts.map +1 -1
  64. package/script/telemetry/core.js +1 -1
  65. package/script/telemetry/env.d.ts.map +1 -1
  66. package/script/telemetry/env.js +6 -1
  67. package/script/telemetry/init.d.ts +3 -0
  68. package/script/telemetry/init.d.ts.map +1 -0
  69. package/script/telemetry/init.js +10 -0
  70. package/script/telemetry/metrics.d.ts +34 -0
  71. package/script/telemetry/metrics.d.ts.map +1 -0
  72. package/script/telemetry/metrics.js +186 -0
  73. package/script/telemetry/mod.d.ts +3 -0
  74. package/script/telemetry/mod.d.ts.map +1 -1
  75. package/script/telemetry/mod.js +7 -1
  76. package/script/telemetry/runtime.d.ts +2 -0
  77. package/script/telemetry/runtime.d.ts.map +1 -0
  78. package/script/telemetry/runtime.js +137 -0
  79. package/script/telemetry.d.ts +3 -0
  80. package/script/telemetry.d.ts.map +1 -0
  81. package/script/telemetry.js +18 -0
  82. package/script/transfer.d.ts.map +1 -1
  83. package/script/transfer.js +28 -17
  84. package/script/trellis.d.ts.map +1 -1
  85. package/script/trellis.js +490 -86
  86. package/src/errors/TrellisError.ts +4 -4
  87. package/src/server/internal_jobs/job-manager.ts +35 -5
  88. package/src/server/runtime.ts +4 -0
  89. package/src/server/service.ts +27 -0
  90. package/src/server.ts +66 -11
  91. package/src/service/deno.ts +1 -0
  92. package/src/service/mod.ts +1 -0
  93. package/src/service/node.ts +1 -0
  94. package/src/service/outbox_inbox.ts +14 -0
  95. package/src/telemetry/core.ts +1 -1
  96. package/src/telemetry/env.ts +5 -1
  97. package/src/telemetry/init.ts +8 -0
  98. package/src/telemetry/metrics.ts +294 -0
  99. package/src/telemetry/mod.ts +7 -0
  100. package/src/telemetry/runtime.ts +218 -0
  101. package/src/telemetry.ts +2 -0
  102. package/src/transfer.ts +69 -30
  103. package/src/trellis.ts +487 -88
  104. package/esm/tracing.d.ts +0 -5
  105. package/esm/tracing.d.ts.map +0 -1
  106. package/esm/tracing.js +0 -8
  107. package/script/tracing.d.ts +0 -5
  108. package/script/tracing.d.ts.map +0 -1
  109. package/script/tracing.js +0 -27
  110. package/src/tracing.ts +0 -28
@@ -1,20 +1,20 @@
1
1
  /**
2
2
  * Base class for all Trellis-specific errors.
3
- * Extends BaseError and relies on the traceId getter being configured via initTracing.
3
+ * Extends BaseError and relies on the traceId getter being configured via initTelemetry.
4
4
  */
5
5
  import { BaseError, type BaseErrorSchema } from "@qlever-llc/result";
6
6
 
7
7
  /**
8
8
  * Abstract base class for Trellis errors.
9
- * Trellis errors automatically include traceId when initTracing() has been called
9
+ * Trellis errors automatically include traceId when initTelemetry() has been called
10
10
  * and a span is active in the current context.
11
11
  *
12
- * The traceId integration is configured by the tracing module's initTracing() function,
12
+ * The traceId integration is configured by the telemetry module's initTelemetry() function,
13
13
  * which sets up BaseError.traceIdGetter to retrieve the traceId from the active span.
14
14
  */
15
15
  export abstract class TrellisError<
16
16
  TData extends BaseErrorSchema = BaseErrorSchema,
17
17
  > extends BaseError<TData> {
18
18
  // TrellisError inherits getTraceId() from BaseError which uses the static traceIdGetter.
19
- // The traceIdGetter is configured by initTracing() in the tracing module.
19
+ // The traceIdGetter is configured by initTelemetry() in the telemetry module.
20
20
  }
@@ -4,6 +4,7 @@ import {
4
4
  createMapCarrier,
5
5
  injectTraceContext,
6
6
  } from "../../telemetry/carrier.js";
7
+ import { recordTrellisError } from "../../telemetry/mod.js";
7
8
 
8
9
  import {
9
10
  ActiveJob,
@@ -103,11 +104,22 @@ export class JobManager<TPayload = unknown, TResult = unknown> {
103
104
  ): Promise<void> {
104
105
  const binding = this.#getQueueBinding(type);
105
106
  const headers = headersFromJobContext(event.context);
106
- await this.#context.nc.publish(
107
- `${binding.publishPrefix}.${jobId}.${event.eventType}`,
108
- new TextEncoder().encode(JSON.stringify(event)),
109
- { headers },
110
- );
107
+ try {
108
+ await this.#context.nc.publish(
109
+ `${binding.publishPrefix}.${jobId}.${event.eventType}`,
110
+ new TextEncoder().encode(JSON.stringify(event)),
111
+ { headers },
112
+ );
113
+ } catch (error) {
114
+ recordTrellisError(error, {
115
+ surface: "job",
116
+ direction: "worker",
117
+ operation: type,
118
+ phase: "publish",
119
+ messagingSystem: "nats",
120
+ });
121
+ throw error;
122
+ }
111
123
  }
112
124
 
113
125
  async create(
@@ -247,6 +259,12 @@ export class JobManager<TPayload = unknown, TResult = unknown> {
247
259
  if (error instanceof JobProcessError) {
248
260
  const detail = error.message;
249
261
  if (error.kind === "retryable") {
262
+ recordTrellisError(error, {
263
+ surface: "job",
264
+ direction: "worker",
265
+ operation: job.type,
266
+ phase: "handler_result",
267
+ });
250
268
  await this.#publishJobEvent(job.type, job.id, {
251
269
  jobId: job.id,
252
270
  service: job.service,
@@ -262,6 +280,12 @@ export class JobManager<TPayload = unknown, TResult = unknown> {
262
280
  return { outcome: "retry", tries, error: detail };
263
281
  }
264
282
 
283
+ recordTrellisError(error, {
284
+ surface: "job",
285
+ direction: "worker",
286
+ operation: job.type,
287
+ phase: "handler_result",
288
+ });
265
289
  await this.#publishJobEvent(job.type, job.id, {
266
290
  jobId: job.id,
267
291
  service: job.service,
@@ -277,6 +301,12 @@ export class JobManager<TPayload = unknown, TResult = unknown> {
277
301
  return { outcome: "failed", tries, error: detail };
278
302
  }
279
303
 
304
+ recordTrellisError(error, {
305
+ surface: "job",
306
+ direction: "worker",
307
+ operation: job.type,
308
+ phase: "runtime",
309
+ });
280
310
  throw error;
281
311
  }
282
312
  }
@@ -20,8 +20,12 @@ export type NatsCredsAuthenticatorFn = (creds: Uint8Array) => unknown;
20
20
 
21
21
  export type ReadFileSyncFn = (path: string) => Uint8Array;
22
22
 
23
+ /** Initializes telemetry for a service runtime. */
24
+ export type InitTelemetryFn = (serviceName: string) => void;
25
+
23
26
  export type TrellisServiceRuntimeDeps = {
24
27
  connect: NatsConnectFn;
25
28
  credsAuthenticator?: NatsCredsAuthenticatorFn;
26
29
  readFileSync?: ReadFileSyncFn;
30
+ initTelemetry?: InitTelemetryFn;
27
31
  };
@@ -128,6 +128,7 @@ import {
128
128
  observeNatsTrellisConnection,
129
129
  type TrellisConnection,
130
130
  } from "../connection.js";
131
+ import { initTelemetry } from "../telemetry/init.js";
131
132
 
132
133
  type ExtraNatsConnectOpts = Omit<
133
134
  NatsConnectOpts,
@@ -431,6 +432,7 @@ async function loadDefaultServiceRuntimeDeps(): Promise<
431
432
  > {
432
433
  const transport = await loadDefaultRuntimeTransport();
433
434
  return {
435
+ initTelemetry,
434
436
  connect: (
435
437
  { servers, token, authenticator, inboxPrefix, ...extraOptions },
436
438
  ) =>
@@ -444,6 +446,12 @@ async function loadDefaultServiceRuntimeDeps(): Promise<
444
446
  };
445
447
  }
446
448
 
449
+ function automaticTelemetryEnabled(
450
+ telemetry: TrellisServiceConnectTelemetryOpts | undefined,
451
+ ): boolean {
452
+ return telemetry !== false && telemetry?.enabled !== false;
453
+ }
454
+
447
455
  const ServiceBootstrapReadySchema = Type.Object({
448
456
  status: Type.Literal("ready"),
449
457
  serverNow: Type.Integer(),
@@ -871,9 +879,20 @@ export type TrellisServiceConnectOpts<
871
879
  contract: ServiceContract<TOwnedApi, TTrellisApi>;
872
880
  name: string;
873
881
  sessionKeySeed: string;
882
+ /**
883
+ * Controls automatic telemetry initialization for this service connection.
884
+ * Enabled by default; pass `false` or `{ enabled: false }` to disable it.
885
+ */
886
+ telemetry?: TrellisServiceConnectTelemetryOpts;
874
887
  server?: TrellisServiceServerOpts;
875
888
  };
876
889
 
890
+ /** Controls automatic telemetry initialization for `TrellisService.connect()`. */
891
+ export type TrellisServiceConnectTelemetryOpts = false | {
892
+ /** Whether automatic telemetry initialization is enabled. Defaults to `true`. */
893
+ enabled?: boolean;
894
+ };
895
+
877
896
  type ServiceKvFacade<TKv extends ContractKvMetadata> = {
878
897
  [K in keyof TKv]: TKv[K]["required"] extends false
879
898
  ? TypedKV<TKv[K]["schema"]> | undefined
@@ -1760,6 +1779,11 @@ export type TrellisServiceConnectArgs<
1760
1779
  contract: TContract;
1761
1780
  name: string;
1762
1781
  sessionKeySeed: string;
1782
+ /**
1783
+ * Controls automatic telemetry initialization for this service connection.
1784
+ * Enabled by default; pass `false` or `{ enabled: false }` to disable it.
1785
+ */
1786
+ telemetry?: TrellisServiceConnectTelemetryOpts;
1763
1787
  server?: TrellisServiceServerOpts;
1764
1788
  };
1765
1789
 
@@ -3142,6 +3166,9 @@ export class TrellisService<
3142
3166
  ...(await loadDefaultServiceRuntimeDeps()),
3143
3167
  ...deps,
3144
3168
  } satisfies TrellisServiceRuntimeDeps;
3169
+ if (automaticTelemetryEnabled(args.telemetry)) {
3170
+ runtimeDeps.initTelemetry?.(args.name);
3171
+ }
3145
3172
  const auth = await createAuth({ sessionKeySeed: args.sessionKeySeed });
3146
3173
  const bootstrapLog = resolveServiceLogger(args.server?.log);
3147
3174
  const bootstrap = await fetchServiceBootstrapInfo({
package/src/server.ts CHANGED
@@ -25,6 +25,10 @@ import {
25
25
  import { RemoteError } from "./errors/RemoteError.js";
26
26
  import type { LoggerLike } from "./globals.js";
27
27
  import { serverLogger } from "./server_logger.js";
28
+ import {
29
+ recordTrellisError,
30
+ type TrellisErrorMetricAttributes,
31
+ } from "./telemetry/mod.js";
28
32
  import {
29
33
  type AcceptedOperation,
30
34
  annotateHandlerBoundaryError,
@@ -220,6 +224,18 @@ function traceIdFromTraceparent(
220
224
  return traceId;
221
225
  }
222
226
 
227
+ function recordOperationServerError(
228
+ error: unknown,
229
+ attributes: TrellisErrorMetricAttributes,
230
+ ): void {
231
+ recordTrellisError(error, {
232
+ messagingSystem: "nats",
233
+ surface: "operation",
234
+ direction: "server",
235
+ ...attributes,
236
+ });
237
+ }
238
+
223
239
  export class TrellisServiceRuntime extends Trellis<TrellisAPI, TrellisMode> {
224
240
  #version?: string;
225
241
  #log: LoggerLike;
@@ -937,6 +953,10 @@ export class TrellisServiceRuntime extends Trellis<TrellisAPI, TrellisMode> {
937
953
  const trellisError = error instanceof BaseError
938
954
  ? error
939
955
  : new UnexpectedError({ cause: error });
956
+ recordOperationServerError(trellisError, {
957
+ operation,
958
+ phase: "control",
959
+ });
940
960
  msg.respond(JSON.stringify({
941
961
  kind: "error",
942
962
  error: trellisError.toSerializable(),
@@ -1539,6 +1559,10 @@ export class TrellisServiceRuntime extends Trellis<TrellisAPI, TrellisMode> {
1539
1559
  const validated = await authenticate(msg, true);
1540
1560
  const value = validated.take();
1541
1561
  if (isErr(value)) {
1562
+ recordOperationServerError(value.error, {
1563
+ operation: String(operation),
1564
+ phase: "start",
1565
+ });
1542
1566
  this.respondWithError(msg, value.error);
1543
1567
  continue;
1544
1568
  }
@@ -1546,15 +1570,20 @@ export class TrellisServiceRuntime extends Trellis<TrellisAPI, TrellisMode> {
1546
1570
  let transferSession: RuntimeOperationTransferSession | undefined;
1547
1571
  if (ctx.transfer) {
1548
1572
  if (!this.#transferSupport) {
1573
+ const error = new UnexpectedError({
1574
+ cause: new Error(
1575
+ `Operation '${
1576
+ String(operation)
1577
+ }' declared transfer support but no runtime transfer support is configured`,
1578
+ ),
1579
+ });
1580
+ recordOperationServerError(error, {
1581
+ operation: String(operation),
1582
+ phase: "start",
1583
+ });
1549
1584
  this.respondWithError(
1550
1585
  msg,
1551
- new UnexpectedError({
1552
- cause: new Error(
1553
- `Operation '${
1554
- String(operation)
1555
- }' declared transfer support but no runtime transfer support is configured`,
1556
- ),
1557
- }),
1586
+ error,
1558
1587
  );
1559
1588
  continue;
1560
1589
  }
@@ -1566,6 +1595,10 @@ export class TrellisServiceRuntime extends Trellis<TrellisAPI, TrellisMode> {
1566
1595
  "key",
1567
1596
  ).take();
1568
1597
  if (isErr(key)) {
1598
+ recordOperationServerError(key.error, {
1599
+ operation: String(operation),
1600
+ phase: "start",
1601
+ });
1569
1602
  this.respondWithError(msg, key.error);
1570
1603
  continue;
1571
1604
  }
@@ -1575,6 +1608,10 @@ export class TrellisServiceRuntime extends Trellis<TrellisAPI, TrellisMode> {
1575
1608
  ctx.transfer.contentType,
1576
1609
  ).take();
1577
1610
  if (isErr(contentType)) {
1611
+ recordOperationServerError(contentType.error, {
1612
+ operation: String(operation),
1613
+ phase: "start",
1614
+ });
1578
1615
  this.respondWithError(msg, contentType.error);
1579
1616
  continue;
1580
1617
  }
@@ -1584,6 +1621,10 @@ export class TrellisServiceRuntime extends Trellis<TrellisAPI, TrellisMode> {
1584
1621
  ctx.transfer.metadata,
1585
1622
  ).take();
1586
1623
  if (isErr(metadata)) {
1624
+ recordOperationServerError(metadata.error, {
1625
+ operation: String(operation),
1626
+ phase: "start",
1627
+ });
1587
1628
  this.respondWithError(msg, metadata.error);
1588
1629
  continue;
1589
1630
  }
@@ -1601,6 +1642,10 @@ export class TrellisServiceRuntime extends Trellis<TrellisAPI, TrellisMode> {
1601
1642
  ...(metadata !== undefined ? { metadata } : {}),
1602
1643
  }).take();
1603
1644
  if (isErr(openedTransferValue)) {
1645
+ recordOperationServerError(openedTransferValue.error, {
1646
+ operation: String(operation),
1647
+ phase: "start",
1648
+ });
1604
1649
  this.respondWithError(msg, openedTransferValue.error);
1605
1650
  continue;
1606
1651
  }
@@ -1694,7 +1739,7 @@ export class TrellisServiceRuntime extends Trellis<TrellisAPI, TrellisMode> {
1694
1739
  ? handlerResult.take()
1695
1740
  : handlerResult;
1696
1741
  if (isErr(handlerOutcome)) {
1697
- await op.fail(annotateHandlerBoundaryError(
1742
+ const error = annotateHandlerBoundaryError(
1698
1743
  handlerOutcome.error,
1699
1744
  {
1700
1745
  operation: String(operation),
@@ -1704,7 +1749,12 @@ export class TrellisServiceRuntime extends Trellis<TrellisAPI, TrellisMode> {
1704
1749
  contractDigest: this.contractDigest,
1705
1750
  traceId: operationContext.traceId,
1706
1751
  },
1707
- ));
1752
+ );
1753
+ recordOperationServerError(error, {
1754
+ operation: String(operation),
1755
+ phase: "handler_result",
1756
+ });
1757
+ await op.fail(error);
1708
1758
  return;
1709
1759
  }
1710
1760
 
@@ -1724,14 +1774,19 @@ export class TrellisServiceRuntime extends Trellis<TrellisAPI, TrellisMode> {
1724
1774
  await op.complete(handlerOutcome);
1725
1775
  }
1726
1776
  } catch (cause) {
1727
- await op.fail(annotateHandlerBoundaryError(cause, {
1777
+ const error = annotateHandlerBoundaryError(cause, {
1728
1778
  operation: String(operation),
1729
1779
  requestId: operationContext.requestId,
1730
1780
  service: this.name,
1731
1781
  contractId: this.contractId,
1732
1782
  contractDigest: this.contractDigest,
1733
1783
  traceId: operationContext.traceId,
1734
- }));
1784
+ });
1785
+ recordOperationServerError(error, {
1786
+ operation: String(operation),
1787
+ phase: "handler_throw",
1788
+ });
1789
+ await op.fail(error);
1735
1790
  }
1736
1791
  })();
1737
1792
  }
@@ -17,4 +17,5 @@ export {
17
17
  type Trellis,
18
18
  TrellisService,
19
19
  type TrellisServiceConnectOpts,
20
+ type TrellisServiceConnectTelemetryOpts,
20
21
  } from "../server/service.js";
@@ -54,6 +54,7 @@ export {
54
54
  type Trellis,
55
55
  TrellisService,
56
56
  type TrellisServiceConnectOpts,
57
+ type TrellisServiceConnectTelemetryOpts,
57
58
  } from "../server/service.js";
58
59
  export {
59
60
  createPostgresOutboxSchema,
@@ -17,4 +17,5 @@ export {
17
17
  type Trellis,
18
18
  TrellisService,
19
19
  type TrellisServiceConnectOpts,
20
+ type TrellisServiceConnectTelemetryOpts,
20
21
  } from "../server/service.js";
@@ -3,6 +3,7 @@ import { type AsyncResult, type BaseError, isErr } from "@qlever-llc/result";
3
3
  import { type StaticDecode, Type } from "typebox";
4
4
  import type { PreparedTrellisEvent, Trellis } from "../trellis.js";
5
5
  import { TypedKV } from "../kv.js";
6
+ import { recordTrellisError } from "../telemetry/mod.js";
6
7
 
7
8
  export type OutboxMessageState = "pending" | "dispatched" | "failed";
8
9
 
@@ -646,6 +647,12 @@ export class OutboxDispatcher {
646
647
  retryDelayMs: this.#retryDelayMs(),
647
648
  });
648
649
  } catch (error) {
650
+ recordTrellisError(error, {
651
+ surface: "outbox",
652
+ direction: "dispatcher",
653
+ operation: "batch",
654
+ phase: "dispatch",
655
+ });
649
656
  this.#scheduleRetryWakeup();
650
657
  try {
651
658
  this.#options.onError?.(error);
@@ -693,6 +700,13 @@ export async function dispatchOutbox(
693
700
  );
694
701
  const value = result.take();
695
702
  if (isErr(value)) {
703
+ recordTrellisError(value.error, {
704
+ surface: "outbox",
705
+ direction: "dispatcher",
706
+ operation: message.event,
707
+ phase: "publish",
708
+ messagingSystem: "nats",
709
+ });
696
710
  failed += 1;
697
711
  await repository.markFailed(message.id, {
698
712
  error: value.error.message,
@@ -8,7 +8,7 @@ import {
8
8
  type Tracer,
9
9
  } from "@opentelemetry/api";
10
10
 
11
- export function getTracer(scope = "@qlever-llc/trellis/tracing"): Tracer {
11
+ export function getTracer(scope = "@qlever-llc/trellis/telemetry"): Tracer {
12
12
  return trace.getTracer(scope);
13
13
  }
14
14
 
@@ -13,7 +13,11 @@ type ProcessLike = {
13
13
  export function getEnv(key: string): string | undefined {
14
14
  const deno = dntShim.dntGlobalThis as typeof dntShim.dntGlobalThis & { Deno?: DenoLike };
15
15
  if (deno.Deno?.env?.get) {
16
- return deno.Deno.env.get(key);
16
+ try {
17
+ return deno.Deno.env.get(key);
18
+ } catch {
19
+ return undefined;
20
+ }
17
21
  }
18
22
 
19
23
  const processGlobal = dntShim.dntGlobalThis as typeof dntShim.dntGlobalThis & {
@@ -0,0 +1,8 @@
1
+ import { configureErrorTraceId } from "./result.js";
2
+ import { initTelemetryRuntime } from "./runtime.js";
3
+
4
+ /** Initializes Trellis telemetry for a service runtime. */
5
+ export function initTelemetry(serviceName: string): void {
6
+ configureErrorTraceId();
7
+ initTelemetryRuntime(serviceName);
8
+ }