@lucern/sdk 1.0.1 → 1.0.3

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 (176) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/accessControl.d.ts +1 -0
  3. package/dist/accessControl.js +213 -26
  4. package/dist/accessControl.js.map +1 -1
  5. package/dist/adminClient.d.ts +1 -0
  6. package/dist/adminClient.js +213 -26
  7. package/dist/adminClient.js.map +1 -1
  8. package/dist/answersClient.d.ts +1 -0
  9. package/dist/answersClient.js +213 -26
  10. package/dist/answersClient.js.map +1 -1
  11. package/dist/audiencesClient.d.ts +1 -0
  12. package/dist/audiencesClient.js +213 -26
  13. package/dist/audiencesClient.js.map +1 -1
  14. package/dist/auditClient.d.ts +1 -0
  15. package/dist/auditClient.js +213 -26
  16. package/dist/auditClient.js.map +1 -1
  17. package/dist/authDeviceClient.d.ts +1 -0
  18. package/dist/beliefs/index.d.ts +1 -0
  19. package/dist/beliefs/index.js +214 -27
  20. package/dist/beliefs/index.js.map +1 -1
  21. package/dist/beliefsClient.d.ts +1 -0
  22. package/dist/beliefsClient.js +213 -26
  23. package/dist/beliefsClient.js.map +1 -1
  24. package/dist/client.d.ts +1 -0
  25. package/dist/client.js +214 -27
  26. package/dist/client.js.map +1 -1
  27. package/dist/clientConfig.d.ts +1 -0
  28. package/dist/clientEvidenceCompat.d.ts +1 -0
  29. package/dist/clientKnowledgeNamespaces.d.ts +1 -0
  30. package/dist/clientLocalHelpers.d.ts +1 -0
  31. package/dist/clientLocalHelpers.js +2 -0
  32. package/dist/clientLocalHelpers.js.map +1 -1
  33. package/dist/clientPlatformNamespaces.d.ts +1 -0
  34. package/dist/clientRuntime.d.ts +1 -0
  35. package/dist/clientWorkflowNamespaces.d.ts +1 -0
  36. package/dist/contextClient.d.ts +1 -0
  37. package/dist/contextClient.js +213 -26
  38. package/dist/contextClient.js.map +1 -1
  39. package/dist/contradictions/index.d.ts +1 -0
  40. package/dist/contradictions/index.js +214 -27
  41. package/dist/contradictions/index.js.map +1 -1
  42. package/dist/control-plane.d.ts +1 -0
  43. package/dist/control-plane.js +213 -26
  44. package/dist/control-plane.js.map +1 -1
  45. package/dist/coreClient.d.ts +25 -1
  46. package/dist/coreClient.js +217 -27
  47. package/dist/coreClient.js.map +1 -1
  48. package/dist/decisions/index.d.ts +1 -0
  49. package/dist/decisions/index.js +214 -27
  50. package/dist/decisions/index.js.map +1 -1
  51. package/dist/decisionsClient.d.ts +1 -0
  52. package/dist/decisionsClient.js +213 -26
  53. package/dist/decisionsClient.js.map +1 -1
  54. package/dist/edges/index.d.ts +1 -0
  55. package/dist/edges/index.js +214 -27
  56. package/dist/edges/index.js.map +1 -1
  57. package/dist/embeddingsClient.d.ts +1 -0
  58. package/dist/embeddingsClient.js +213 -26
  59. package/dist/embeddingsClient.js.map +1 -1
  60. package/dist/eventingClient.d.ts +1 -0
  61. package/dist/eventingClient.js +213 -26
  62. package/dist/eventingClient.js.map +1 -1
  63. package/dist/eventsCore.d.ts +1 -0
  64. package/dist/eventsCore.js +213 -26
  65. package/dist/eventsCore.js.map +1 -1
  66. package/dist/evidence/index.d.ts +1 -0
  67. package/dist/evidence/index.js +214 -27
  68. package/dist/evidence/index.js.map +1 -1
  69. package/dist/evidenceClient.d.ts +1 -0
  70. package/dist/evidenceClient.js +213 -26
  71. package/dist/evidenceClient.js.map +1 -1
  72. package/dist/functionSurface.d.ts +1 -0
  73. package/dist/functionSurface.js +213 -26
  74. package/dist/functionSurface.js.map +1 -1
  75. package/dist/functionSurfaceClient.d.ts +1 -0
  76. package/dist/functionSurfaceClient.js +213 -26
  77. package/dist/functionSurfaceClient.js.map +1 -1
  78. package/dist/gatewayFacades.d.ts +1 -0
  79. package/dist/gatewayFacades.factories.d.ts +1 -0
  80. package/dist/gatewayFacades.factories.js +213 -26
  81. package/dist/gatewayFacades.factories.js.map +1 -1
  82. package/dist/gatewayFacades.js +213 -26
  83. package/dist/gatewayFacades.js.map +1 -1
  84. package/dist/graphAnalysisClient.d.ts +1 -0
  85. package/dist/graphAnalysisClient.js +213 -26
  86. package/dist/graphAnalysisClient.js.map +1 -1
  87. package/dist/graphClient.d.ts +1 -0
  88. package/dist/graphClient.js +213 -26
  89. package/dist/graphClient.js.map +1 -1
  90. package/dist/graphRecommendationsClient.d.ts +1 -0
  91. package/dist/graphRecommendationsClient.js +213 -26
  92. package/dist/graphRecommendationsClient.js.map +1 -1
  93. package/dist/graphStateClassifierClient.d.ts +1 -0
  94. package/dist/graphStateClassifierClient.js +213 -26
  95. package/dist/graphStateClassifierClient.js.map +1 -1
  96. package/dist/harnessClient.d.ts +1 -0
  97. package/dist/harnessClient.js +213 -26
  98. package/dist/harnessClient.js.map +1 -1
  99. package/dist/identityClient.d.ts +1 -0
  100. package/dist/identityClient.js +213 -26
  101. package/dist/identityClient.js.map +1 -1
  102. package/dist/index.d.ts +2 -1
  103. package/dist/index.js +237 -28
  104. package/dist/index.js.map +1 -1
  105. package/dist/jobsClient.d.ts +1 -0
  106. package/dist/jobsClient.js +213 -26
  107. package/dist/jobsClient.js.map +1 -1
  108. package/dist/learningClient.d.ts +1 -0
  109. package/dist/learningClient.js +213 -26
  110. package/dist/learningClient.js.map +1 -1
  111. package/dist/lenses/index.d.ts +1 -0
  112. package/dist/lenses/index.js +214 -27
  113. package/dist/lenses/index.js.map +1 -1
  114. package/dist/mcpClient.d.ts +1 -0
  115. package/dist/mcpClient.js +213 -26
  116. package/dist/mcpClient.js.map +1 -1
  117. package/dist/modelRuntimeClient.d.ts +1 -0
  118. package/dist/modelRuntimeClient.js +213 -26
  119. package/dist/modelRuntimeClient.js.map +1 -1
  120. package/dist/nodes/index.d.ts +1 -0
  121. package/dist/nodes/index.js +214 -27
  122. package/dist/nodes/index.js.map +1 -1
  123. package/dist/ontologies/index.d.ts +1 -0
  124. package/dist/ontologies/index.js +214 -27
  125. package/dist/ontologies/index.js.map +1 -1
  126. package/dist/ontologyClient.d.ts +1 -0
  127. package/dist/ontologyClient.js +213 -26
  128. package/dist/ontologyClient.js.map +1 -1
  129. package/dist/ontologyLinksClient.d.ts +1 -0
  130. package/dist/ontologyLinksClient.js +213 -26
  131. package/dist/ontologyLinksClient.js.map +1 -1
  132. package/dist/orgGraphSearchClient.d.ts +1 -0
  133. package/dist/orgGraphSearchClient.js +213 -26
  134. package/dist/orgGraphSearchClient.js.map +1 -1
  135. package/dist/packsClient.d.ts +1 -0
  136. package/dist/packsClient.js +213 -26
  137. package/dist/packsClient.js.map +1 -1
  138. package/dist/policyClient.d.ts +1 -0
  139. package/dist/policyClient.js +213 -26
  140. package/dist/policyClient.js.map +1 -1
  141. package/dist/proof-attestation.json +45 -0
  142. package/dist/questions/index.d.ts +1 -0
  143. package/dist/questions/index.js +214 -27
  144. package/dist/questions/index.js.map +1 -1
  145. package/dist/reportsClient.d.ts +1 -0
  146. package/dist/reportsClient.js +213 -26
  147. package/dist/reportsClient.js.map +1 -1
  148. package/dist/schemaClient.d.ts +1 -0
  149. package/dist/schemaClient.js +213 -26
  150. package/dist/schemaClient.js.map +1 -1
  151. package/dist/sdkSurface.d.ts +1 -0
  152. package/dist/sourcesClient.d.ts +1 -0
  153. package/dist/sourcesClient.js +213 -26
  154. package/dist/sourcesClient.js.map +1 -1
  155. package/dist/telemetryClient.d.ts +1 -0
  156. package/dist/telemetryClient.js +213 -26
  157. package/dist/telemetryClient.js.map +1 -1
  158. package/dist/toolRegistryClient.d.ts +1 -0
  159. package/dist/toolRegistryClient.js +213 -26
  160. package/dist/toolRegistryClient.js.map +1 -1
  161. package/dist/topics/index.d.ts +1 -0
  162. package/dist/topics/index.js +214 -27
  163. package/dist/topics/index.js.map +1 -1
  164. package/dist/topicsClient.d.ts +1 -0
  165. package/dist/topicsClient.js +213 -26
  166. package/dist/topicsClient.js.map +1 -1
  167. package/dist/version.d.ts +1 -1
  168. package/dist/version.js +1 -1
  169. package/dist/version.js.map +1 -1
  170. package/dist/workflowClient.d.ts +1 -0
  171. package/dist/workflowClient.js +213 -26
  172. package/dist/workflowClient.js.map +1 -1
  173. package/dist/worktrees/index.d.ts +1 -0
  174. package/dist/worktrees/index.js +214 -27
  175. package/dist/worktrees/index.js.map +1 -1
  176. package/package.json +6 -5
@@ -1,5 +1,6 @@
1
1
  import { GatewayClientConfig, PlatformGatewaySuccess } from './coreClient.js';
2
2
  import { JsonObject, SdkPrincipalContext } from './types.js';
3
+ import '@lucern/transport-core';
3
4
  import './authContext.js';
4
5
  import './contracts/auth-session.contract.js';
5
6
  import './contracts/workflow-runtime.contract.js';
@@ -1,5 +1,7 @@
1
+ import { createTelemetryExporterFromEnv, emitTelemetrySignal } from '@lucern/transport-core';
1
2
  import { redactDiagnosticValue } from '@lucern/transport-core/redaction';
2
3
  import { classifyRetry } from '@lucern/transport-core/transport';
4
+ import { Effect, Exit, Cause } from 'effect';
3
5
 
4
6
  // src/coreClient.ts
5
7
 
@@ -171,6 +173,33 @@ function createCanonicalAuthHeaders(authContext) {
171
173
  }
172
174
 
173
175
  // src/coreClient.ts
176
+ var DEFAULT_GATEWAY_TIMEOUT_MS = 15e3;
177
+ var DEFAULT_GATEWAY_MAX_RETRIES = 2;
178
+ var DEFAULT_ENV_TIMEOUT_MS = "LUCERN_REQUEST_TIMEOUT_MS";
179
+ var DEFAULT_ENV_MAX_RETRIES = "LUCERN_GATEWAY_MAX_RETRIES";
180
+ var ENV_TIMEOUT_BY_METHOD_PREFIX = "LUCERN_REQUEST_TIMEOUT_MS_";
181
+ var GatewayTimeoutError = class extends Error {
182
+ retryable = true;
183
+ timeoutMs;
184
+ constructor(timeoutMs) {
185
+ super(`Request timed out after ${timeoutMs}ms`);
186
+ this.name = "AbortError";
187
+ this.timeoutMs = timeoutMs;
188
+ }
189
+ };
190
+ var GatewayTransportError = class extends Error {
191
+ retryable;
192
+ cause;
193
+ constructor(message, options) {
194
+ super(message);
195
+ this.name = "GatewayTransportError";
196
+ this.retryable = options?.retryable ?? true;
197
+ this.cause = options?.cause;
198
+ }
199
+ };
200
+ function isGatewayRetryableError(error) {
201
+ return error instanceof GatewayTimeoutError && error.retryable || error instanceof GatewayTransportError && error.retryable || false;
202
+ }
174
203
  var LucernApiError = class extends Error {
175
204
  code;
176
205
  status;
@@ -217,6 +246,99 @@ function generatePortableRequestId() {
217
246
  8
218
247
  ).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10).join("")}`;
219
248
  }
249
+ function resolveEnvironment() {
250
+ const processEnv = typeof globalThis === "object" && globalThis !== null && "process" in globalThis ? globalThis.process : void 0;
251
+ const env = processEnv !== void 0 && typeof processEnv === "object" && processEnv !== null && typeof processEnv.env === "object" ? processEnv.env : void 0;
252
+ return {
253
+ get: (name) => {
254
+ const value = env?.[name];
255
+ return typeof value === "string" && value.length > 0 ? value : void 0;
256
+ }
257
+ };
258
+ }
259
+ function telemetryEnvironmentRecord(environment) {
260
+ const names = [
261
+ "LUCERN_TELEMETRY_ENABLED",
262
+ "AXIOM_TELEMETRY_ENABLED",
263
+ "LUCERN_AXIOM_TOKEN",
264
+ "AXIOM_TOKEN",
265
+ "LUCERN_AXIOM_EVENTS_DATASET",
266
+ "LUCERN_AXIOM_DATASET",
267
+ "AXIOM_EVENTS_DATASET",
268
+ "AXIOM_DATASET",
269
+ "LUCERN_AXIOM_API_URL",
270
+ "AXIOM_URL",
271
+ "LUCERN_ENVIRONMENT",
272
+ "NODE_ENV",
273
+ "LUCERN_RELEASE",
274
+ "SENTRY_RELEASE",
275
+ "VERCEL_GIT_COMMIT_SHA"
276
+ ];
277
+ return Object.fromEntries(
278
+ names.map((name) => [name, environment.get(name)])
279
+ );
280
+ }
281
+ function resolveRequestProfile(config, environment) {
282
+ const requestIdFactory = config.requestIdFactory ?? (() => generatePortableRequestId());
283
+ const parsedMaxRetries = parseIntegerFromString(
284
+ config.maxRetries,
285
+ environment.get(DEFAULT_ENV_MAX_RETRIES)
286
+ );
287
+ const parsedTimeoutMs = parseIntegerFromString(
288
+ config.timeoutMs,
289
+ environment.get(DEFAULT_ENV_TIMEOUT_MS)
290
+ );
291
+ const methodTimeouts = {
292
+ ...config.timeoutMsByMethod
293
+ };
294
+ for (const method of ["GET", "POST", "PUT", "PATCH", "DELETE"]) {
295
+ const envKey = `${ENV_TIMEOUT_BY_METHOD_PREFIX}${method}`;
296
+ const raw = environment.get(envKey);
297
+ if (!raw || methodTimeouts[method] !== void 0) {
298
+ continue;
299
+ }
300
+ const parsed = parseIntegerFromString(void 0, raw);
301
+ if (typeof parsed === "number") {
302
+ methodTimeouts[method] = parsed;
303
+ }
304
+ }
305
+ return {
306
+ maxRetries: parsedMaxRetries ?? DEFAULT_GATEWAY_MAX_RETRIES,
307
+ timeoutMs: parsedTimeoutMs ?? DEFAULT_GATEWAY_TIMEOUT_MS,
308
+ timeoutMsByMethod: methodTimeouts,
309
+ requestIdFactory
310
+ };
311
+ }
312
+ function createGatewayRuntime(config, environment) {
313
+ return {
314
+ fetch: config.fetchImpl ?? fetch,
315
+ now: () => Date.now(),
316
+ sleep: (ms) => delay(ms),
317
+ env: environment,
318
+ redaction: resolveRequestRedactionValue,
319
+ profile: resolveRequestProfile(config, environment)
320
+ };
321
+ }
322
+ function parseIntegerFromString(value, rawValue) {
323
+ if (typeof value === "number" && Number.isInteger(value) && value >= 0) {
324
+ return value;
325
+ }
326
+ if (typeof rawValue !== "string" || !rawValue.trim()) {
327
+ return void 0;
328
+ }
329
+ const parsed = Number.parseInt(rawValue, 10);
330
+ return Number.isInteger(parsed) && parsed >= 0 ? parsed : void 0;
331
+ }
332
+ function resolveRequestRedactionValue(value) {
333
+ return redactDiagnosticValue(value);
334
+ }
335
+ function resolveGatewayBaseUrl(configBaseUrl, environment) {
336
+ const envBaseUrl = environment.get("LUCERN_API_URL") ?? environment.get("LUCERN_BASE_URL") ?? environment.get("LUCERN_GATEWAY_BASE_URL");
337
+ return (configBaseUrl ?? envBaseUrl ?? "").replace(/\/+$/, "");
338
+ }
339
+ function normalizeGatewayEnvironment(value) {
340
+ return value === "sandbox" || value === "production" ? value : void 0;
341
+ }
220
342
  function fallbackErrorCode(status) {
221
343
  if (status === 401) {
222
344
  return "AUTHENTICATION_REQUIRED";
@@ -255,10 +377,8 @@ function computeRetryDelayMs(args) {
255
377
  const jitterWindow = Math.max(250, Math.round(baseDelay * 0.25));
256
378
  return baseDelay + Math.round(Math.random() * jitterWindow);
257
379
  }
258
- function timeoutError(timeoutMs) {
259
- const error = new Error(`Request timed out after ${timeoutMs}ms`);
260
- error.name = "AbortError";
261
- return error;
380
+ function classifyGatewayErrorForRetry(error) {
381
+ return isGatewayRetryableError(error) || classifyRetry({ error }).retryable;
262
382
  }
263
383
  function isRecord(value) {
264
384
  return value !== null && typeof value === "object" && !Array.isArray(value);
@@ -313,10 +433,18 @@ function cleanHeaderValue(value) {
313
433
  return normalized ? normalized : void 0;
314
434
  }
315
435
  function createGatewayRequestClient(config = {}) {
316
- const fetchImpl = config.fetchImpl ?? fetch;
317
- const baseUrl = config.baseUrl?.replace(/\/+$/, "") ?? "";
318
- const maxRetries = config.maxRetries ?? 2;
319
- const requestIdFactory = config.requestIdFactory ?? (() => generatePortableRequestId());
436
+ const env = resolveEnvironment();
437
+ const runtime = createGatewayRuntime(config, env);
438
+ const baseUrl = resolveGatewayBaseUrl(config.baseUrl, env);
439
+ const maxRetries = runtime.profile.maxRetries;
440
+ const requestIdFactory = runtime.profile.requestIdFactory;
441
+ const requestTimeoutByMethod = runtime.profile.timeoutMsByMethod;
442
+ const defaultRequestTimeoutMs = runtime.profile.timeoutMs;
443
+ const normalizedEnvironment = normalizeGatewayEnvironment(config.environment);
444
+ const telemetryExporter = config.telemetryEnabled === false ? null : config.telemetryExporter ?? createTelemetryExporterFromEnv(telemetryEnvironmentRecord(env), {
445
+ service: "lucern-sdk",
446
+ environment: normalizedEnvironment
447
+ });
320
448
  async function resolveAuthHeaders() {
321
449
  const provided = config.getAuthHeaders ? await config.getAuthHeaders() : {};
322
450
  const headers = new Headers(provided);
@@ -328,7 +456,7 @@ function createGatewayRequestClient(config = {}) {
328
456
  };
329
457
  setIfAbsent("x-lucern-key", config.apiKey);
330
458
  setIfAbsent("x-lucern-session-token", config.userToken);
331
- setIfAbsent("x-lucern-environment", config.environment);
459
+ setIfAbsent("x-lucern-environment", normalizedEnvironment);
332
460
  setIfAbsent("x-lucern-clerk-id", config.clerkId);
333
461
  setIfAbsent("x-lucern-user-id", config.userId ?? config.clerkId);
334
462
  setIfAbsent("x-lucern-deployment-host", config.deploymentHost);
@@ -343,19 +471,73 @@ function createGatewayRequestClient(config = {}) {
343
471
  return mergeHeaderRecord(base, createCanonicalAuthHeaders(authContext));
344
472
  }
345
473
  async function fetchWithTimeout(url, init, timeoutMs) {
474
+ const normalizeTransportError = (error, isTimeout) => {
475
+ if (isTimeout) {
476
+ return new GatewayTimeoutError(timeoutMs);
477
+ }
478
+ return error instanceof GatewayTimeoutError || error instanceof GatewayTransportError ? error : new GatewayTransportError(
479
+ error instanceof Error ? error.message : "Gateway transport error",
480
+ {
481
+ cause: error,
482
+ retryable: classifyGatewayErrorForRetry(error)
483
+ }
484
+ );
485
+ };
346
486
  const controller = new AbortController();
347
487
  const timer = setTimeout(() => controller.abort(), timeoutMs);
488
+ const requestEffect = Effect.tryPromise({
489
+ try: () => runtime.fetch(url, { ...init, signal: controller.signal }),
490
+ catch: (error) => normalizeTransportError(error, controller.signal.aborted)
491
+ });
348
492
  try {
349
- return await fetchImpl(url, { ...init, signal: controller.signal });
350
- } catch (error) {
351
- if (controller.signal.aborted) {
352
- throw timeoutError(timeoutMs);
493
+ const exit = await Effect.runPromiseExit(requestEffect);
494
+ if (Exit.isSuccess(exit)) {
495
+ return exit.value;
353
496
  }
354
- throw error;
497
+ const failure = Array.from(Cause.failures(exit.cause))[0];
498
+ if (failure !== void 0) {
499
+ throw failure;
500
+ }
501
+ throw Cause.squash(exit.cause);
355
502
  } finally {
356
503
  clearTimeout(timer);
357
504
  }
358
505
  }
506
+ async function emitSdkResponseTelemetry(context) {
507
+ const retry = classifyRetry({
508
+ status: context.status,
509
+ error: context.error,
510
+ retryAfter: context.retryAfterMs !== null && context.retryAfterMs !== void 0 ? String(context.retryAfterMs / 1e3) : void 0
511
+ });
512
+ await emitTelemetrySignal(telemetryExporter, {
513
+ signalType: "trace",
514
+ surface: "sdk-retry",
515
+ eventName: context.willRetry ? "sdk.retry" : context.error ? "sdk.request.error" : "sdk.request.complete",
516
+ severity: context.error ? context.willRetry ? "warn" : "error" : "info",
517
+ durationMs: context.durationMs,
518
+ metricName: "sdk.request.duration_ms",
519
+ metricValue: context.durationMs,
520
+ correlationId: context.correlationId ?? context.requestId,
521
+ policyTraceId: context.policyTraceId ?? null,
522
+ tenantId: context.headers.get("x-lucern-tenant-id") ?? context.headers.get("x-lucern-tenant") ?? void 0,
523
+ workspaceId: context.headers.get("x-lucern-workspace-id") ?? context.headers.get("x-lucern-workspace") ?? void 0,
524
+ attributes: {
525
+ service: "lucern-sdk",
526
+ operation: "gateway.request",
527
+ path: context.path,
528
+ httpMethod: context.method,
529
+ httpStatus: context.status,
530
+ attempt: context.attempt,
531
+ maxRetries: context.maxRetries,
532
+ retryReason: retry.reason,
533
+ retryAfterMs: context.retryAfterMs ?? retry.retryAfterMs,
534
+ willRetry: context.willRetry,
535
+ retryable: retry.retryable,
536
+ errorName: context.error instanceof Error ? context.error.name : void 0,
537
+ errorMessage: context.error instanceof Error ? context.error.message : void 0
538
+ }
539
+ });
540
+ }
359
541
  async function parsePayload(response) {
360
542
  const text = await response.text();
361
543
  if (!text) {
@@ -371,11 +553,11 @@ function createGatewayRequestClient(config = {}) {
371
553
  if (typeof requestTimeoutMs === "number") {
372
554
  return requestTimeoutMs;
373
555
  }
374
- const methodTimeoutMs = config.timeoutMsByMethod?.[method];
556
+ const methodTimeoutMs = requestTimeoutByMethod?.[method];
375
557
  if (typeof methodTimeoutMs === "number") {
376
558
  return methodTimeoutMs;
377
559
  }
378
- return config.timeoutMs ?? 15e3;
560
+ return defaultRequestTimeoutMs;
379
561
  }
380
562
  function tryParseGatewayEnvelopeJson(text) {
381
563
  const trimmed = text.trim();
@@ -396,8 +578,8 @@ function createGatewayRequestClient(config = {}) {
396
578
  const legacyError = failure && isRecord(failure.error) ? failure.error : failure?.legacyError;
397
579
  const correlationId = failure?.correlationId ?? args.response.headers.get("x-lucern-correlation-id")?.trim() ?? args.requestId;
398
580
  const policyTraceId = failure?.policyTraceId ?? args.response.headers.get("x-lucern-policy-trace-id")?.trim() ?? null;
399
- const details = redactJsonDiagnosticValue(
400
- failure?.details ?? legacyError?.details
581
+ const details = runtime.redaction(
582
+ redactJsonDiagnosticValue(failure?.details ?? legacyError?.details)
401
583
  );
402
584
  const policySummary = readPolicySummaryFromDetails(details);
403
585
  const failureMessage = typeof failure?.error === "string" ? failure.error : legacyError?.message;
@@ -467,7 +649,7 @@ function createGatewayRequestClient(config = {}) {
467
649
  failure
468
650
  });
469
651
  const willRetry = attempt < maxRetries && retry.retryable;
470
- await config.onResponse?.({
652
+ const responseContext2 = {
471
653
  ...hookRequestContext,
472
654
  durationMs: Date.now() - startedAt,
473
655
  status: response.status,
@@ -477,7 +659,9 @@ function createGatewayRequestClient(config = {}) {
477
659
  policyTraceId: apiError.policyTraceId ?? null,
478
660
  retryAfterMs,
479
661
  willRetry
480
- });
662
+ };
663
+ await config.onResponse?.(responseContext2);
664
+ await emitSdkResponseTelemetry(responseContext2);
481
665
  if (willRetry) {
482
666
  lastError = apiError;
483
667
  await delay(
@@ -492,7 +676,7 @@ function createGatewayRequestClient(config = {}) {
492
676
  throw apiError;
493
677
  }
494
678
  const successPayload = payload;
495
- await config.onResponse?.({
679
+ const responseContext = {
496
680
  ...hookRequestContext,
497
681
  durationMs: Date.now() - startedAt,
498
682
  status: response.status,
@@ -502,22 +686,25 @@ function createGatewayRequestClient(config = {}) {
502
686
  idempotentReplay: successPayload.idempotentReplay,
503
687
  retryAfterMs,
504
688
  willRetry: false
505
- });
689
+ };
690
+ await config.onResponse?.(responseContext);
691
+ await emitSdkResponseTelemetry(responseContext);
506
692
  return successPayload;
507
693
  } catch (fetchError) {
508
694
  if (fetchError instanceof LucernApiError) {
509
695
  throw fetchError;
510
696
  }
511
- const retry = classifyRetry({ error: fetchError });
512
- const willRetry = attempt < maxRetries && retry.retryable;
513
- await config.onResponse?.({
697
+ const willRetry = attempt < maxRetries && classifyGatewayErrorForRetry(fetchError);
698
+ const responseContext = {
514
699
  ...hookRequestContext,
515
700
  durationMs: Date.now() - startedAt,
516
701
  error: fetchError,
517
702
  correlationId: requestId,
518
703
  policyTraceId: null,
519
704
  willRetry
520
- });
705
+ };
706
+ await config.onResponse?.(responseContext);
707
+ await emitSdkResponseTelemetry(responseContext);
521
708
  lastError = fetchError;
522
709
  if (willRetry) {
523
710
  await delay(computeRetryDelayMs({ attempt }));