@lucern/sdk 1.0.1 → 1.0.2

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 (175) hide show
  1. package/CHANGELOG.md +4 -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/questions/index.d.ts +1 -0
  142. package/dist/questions/index.js +214 -27
  143. package/dist/questions/index.js.map +1 -1
  144. package/dist/reportsClient.d.ts +1 -0
  145. package/dist/reportsClient.js +213 -26
  146. package/dist/reportsClient.js.map +1 -1
  147. package/dist/schemaClient.d.ts +1 -0
  148. package/dist/schemaClient.js +213 -26
  149. package/dist/schemaClient.js.map +1 -1
  150. package/dist/sdkSurface.d.ts +1 -0
  151. package/dist/sourcesClient.d.ts +1 -0
  152. package/dist/sourcesClient.js +213 -26
  153. package/dist/sourcesClient.js.map +1 -1
  154. package/dist/telemetryClient.d.ts +1 -0
  155. package/dist/telemetryClient.js +213 -26
  156. package/dist/telemetryClient.js.map +1 -1
  157. package/dist/toolRegistryClient.d.ts +1 -0
  158. package/dist/toolRegistryClient.js +213 -26
  159. package/dist/toolRegistryClient.js.map +1 -1
  160. package/dist/topics/index.d.ts +1 -0
  161. package/dist/topics/index.js +214 -27
  162. package/dist/topics/index.js.map +1 -1
  163. package/dist/topicsClient.d.ts +1 -0
  164. package/dist/topicsClient.js +213 -26
  165. package/dist/topicsClient.js.map +1 -1
  166. package/dist/version.d.ts +1 -1
  167. package/dist/version.js +1 -1
  168. package/dist/version.js.map +1 -1
  169. package/dist/workflowClient.d.ts +1 -0
  170. package/dist/workflowClient.js +213 -26
  171. package/dist/workflowClient.js.map +1 -1
  172. package/dist/worktrees/index.d.ts +1 -0
  173. package/dist/worktrees/index.js +214 -27
  174. package/dist/worktrees/index.js.map +1 -1
  175. package/package.json +6 -5
@@ -1,4 +1,5 @@
1
1
  import { GatewayClientConfig, PlatformGatewaySuccess } from './coreClient.js';
2
+ import '@lucern/transport-core';
2
3
  import './authContext.js';
3
4
  import './contracts/auth-session.contract.js';
4
5
  import './types.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
  var randomIdempotencyKey = generatePortableRequestId;
221
343
  function fallbackErrorCode(status) {
222
344
  if (status === 401) {
@@ -256,10 +378,8 @@ function computeRetryDelayMs(args) {
256
378
  const jitterWindow = Math.max(250, Math.round(baseDelay * 0.25));
257
379
  return baseDelay + Math.round(Math.random() * jitterWindow);
258
380
  }
259
- function timeoutError(timeoutMs) {
260
- const error = new Error(`Request timed out after ${timeoutMs}ms`);
261
- error.name = "AbortError";
262
- return error;
381
+ function classifyGatewayErrorForRetry(error) {
382
+ return isGatewayRetryableError(error) || classifyRetry({ error }).retryable;
263
383
  }
264
384
  function isRecord(value) {
265
385
  return value !== null && typeof value === "object" && !Array.isArray(value);
@@ -314,10 +434,18 @@ function cleanHeaderValue(value) {
314
434
  return normalized ? normalized : void 0;
315
435
  }
316
436
  function createGatewayRequestClient(config = {}) {
317
- const fetchImpl = config.fetchImpl ?? fetch;
318
- const baseUrl = config.baseUrl?.replace(/\/+$/, "") ?? "";
319
- const maxRetries = config.maxRetries ?? 2;
320
- const requestIdFactory = config.requestIdFactory ?? (() => generatePortableRequestId());
437
+ const env = resolveEnvironment();
438
+ const runtime = createGatewayRuntime(config, env);
439
+ const baseUrl = resolveGatewayBaseUrl(config.baseUrl, env);
440
+ const maxRetries = runtime.profile.maxRetries;
441
+ const requestIdFactory = runtime.profile.requestIdFactory;
442
+ const requestTimeoutByMethod = runtime.profile.timeoutMsByMethod;
443
+ const defaultRequestTimeoutMs = runtime.profile.timeoutMs;
444
+ const normalizedEnvironment = normalizeGatewayEnvironment(config.environment);
445
+ const telemetryExporter = config.telemetryEnabled === false ? null : config.telemetryExporter ?? createTelemetryExporterFromEnv(telemetryEnvironmentRecord(env), {
446
+ service: "lucern-sdk",
447
+ environment: normalizedEnvironment
448
+ });
321
449
  async function resolveAuthHeaders() {
322
450
  const provided = config.getAuthHeaders ? await config.getAuthHeaders() : {};
323
451
  const headers = new Headers(provided);
@@ -329,7 +457,7 @@ function createGatewayRequestClient(config = {}) {
329
457
  };
330
458
  setIfAbsent("x-lucern-key", config.apiKey);
331
459
  setIfAbsent("x-lucern-session-token", config.userToken);
332
- setIfAbsent("x-lucern-environment", config.environment);
460
+ setIfAbsent("x-lucern-environment", normalizedEnvironment);
333
461
  setIfAbsent("x-lucern-clerk-id", config.clerkId);
334
462
  setIfAbsent("x-lucern-user-id", config.userId ?? config.clerkId);
335
463
  setIfAbsent("x-lucern-deployment-host", config.deploymentHost);
@@ -344,19 +472,73 @@ function createGatewayRequestClient(config = {}) {
344
472
  return mergeHeaderRecord(base, createCanonicalAuthHeaders(authContext));
345
473
  }
346
474
  async function fetchWithTimeout(url, init, timeoutMs) {
475
+ const normalizeTransportError = (error, isTimeout) => {
476
+ if (isTimeout) {
477
+ return new GatewayTimeoutError(timeoutMs);
478
+ }
479
+ return error instanceof GatewayTimeoutError || error instanceof GatewayTransportError ? error : new GatewayTransportError(
480
+ error instanceof Error ? error.message : "Gateway transport error",
481
+ {
482
+ cause: error,
483
+ retryable: classifyGatewayErrorForRetry(error)
484
+ }
485
+ );
486
+ };
347
487
  const controller = new AbortController();
348
488
  const timer = setTimeout(() => controller.abort(), timeoutMs);
489
+ const requestEffect = Effect.tryPromise({
490
+ try: () => runtime.fetch(url, { ...init, signal: controller.signal }),
491
+ catch: (error) => normalizeTransportError(error, controller.signal.aborted)
492
+ });
349
493
  try {
350
- return await fetchImpl(url, { ...init, signal: controller.signal });
351
- } catch (error) {
352
- if (controller.signal.aborted) {
353
- throw timeoutError(timeoutMs);
494
+ const exit = await Effect.runPromiseExit(requestEffect);
495
+ if (Exit.isSuccess(exit)) {
496
+ return exit.value;
354
497
  }
355
- throw error;
498
+ const failure = Array.from(Cause.failures(exit.cause))[0];
499
+ if (failure !== void 0) {
500
+ throw failure;
501
+ }
502
+ throw Cause.squash(exit.cause);
356
503
  } finally {
357
504
  clearTimeout(timer);
358
505
  }
359
506
  }
507
+ async function emitSdkResponseTelemetry(context) {
508
+ const retry = classifyRetry({
509
+ status: context.status,
510
+ error: context.error,
511
+ retryAfter: context.retryAfterMs !== null && context.retryAfterMs !== void 0 ? String(context.retryAfterMs / 1e3) : void 0
512
+ });
513
+ await emitTelemetrySignal(telemetryExporter, {
514
+ signalType: "trace",
515
+ surface: "sdk-retry",
516
+ eventName: context.willRetry ? "sdk.retry" : context.error ? "sdk.request.error" : "sdk.request.complete",
517
+ severity: context.error ? context.willRetry ? "warn" : "error" : "info",
518
+ durationMs: context.durationMs,
519
+ metricName: "sdk.request.duration_ms",
520
+ metricValue: context.durationMs,
521
+ correlationId: context.correlationId ?? context.requestId,
522
+ policyTraceId: context.policyTraceId ?? null,
523
+ tenantId: context.headers.get("x-lucern-tenant-id") ?? context.headers.get("x-lucern-tenant") ?? void 0,
524
+ workspaceId: context.headers.get("x-lucern-workspace-id") ?? context.headers.get("x-lucern-workspace") ?? void 0,
525
+ attributes: {
526
+ service: "lucern-sdk",
527
+ operation: "gateway.request",
528
+ path: context.path,
529
+ httpMethod: context.method,
530
+ httpStatus: context.status,
531
+ attempt: context.attempt,
532
+ maxRetries: context.maxRetries,
533
+ retryReason: retry.reason,
534
+ retryAfterMs: context.retryAfterMs ?? retry.retryAfterMs,
535
+ willRetry: context.willRetry,
536
+ retryable: retry.retryable,
537
+ errorName: context.error instanceof Error ? context.error.name : void 0,
538
+ errorMessage: context.error instanceof Error ? context.error.message : void 0
539
+ }
540
+ });
541
+ }
360
542
  async function parsePayload(response) {
361
543
  const text = await response.text();
362
544
  if (!text) {
@@ -372,11 +554,11 @@ function createGatewayRequestClient(config = {}) {
372
554
  if (typeof requestTimeoutMs === "number") {
373
555
  return requestTimeoutMs;
374
556
  }
375
- const methodTimeoutMs = config.timeoutMsByMethod?.[method];
557
+ const methodTimeoutMs = requestTimeoutByMethod?.[method];
376
558
  if (typeof methodTimeoutMs === "number") {
377
559
  return methodTimeoutMs;
378
560
  }
379
- return config.timeoutMs ?? 15e3;
561
+ return defaultRequestTimeoutMs;
380
562
  }
381
563
  function tryParseGatewayEnvelopeJson(text) {
382
564
  const trimmed = text.trim();
@@ -397,8 +579,8 @@ function createGatewayRequestClient(config = {}) {
397
579
  const legacyError = failure && isRecord(failure.error) ? failure.error : failure?.legacyError;
398
580
  const correlationId = failure?.correlationId ?? args.response.headers.get("x-lucern-correlation-id")?.trim() ?? args.requestId;
399
581
  const policyTraceId = failure?.policyTraceId ?? args.response.headers.get("x-lucern-policy-trace-id")?.trim() ?? null;
400
- const details = redactJsonDiagnosticValue(
401
- failure?.details ?? legacyError?.details
582
+ const details = runtime.redaction(
583
+ redactJsonDiagnosticValue(failure?.details ?? legacyError?.details)
402
584
  );
403
585
  const policySummary = readPolicySummaryFromDetails(details);
404
586
  const failureMessage = typeof failure?.error === "string" ? failure.error : legacyError?.message;
@@ -468,7 +650,7 @@ function createGatewayRequestClient(config = {}) {
468
650
  failure
469
651
  });
470
652
  const willRetry = attempt < maxRetries && retry.retryable;
471
- await config.onResponse?.({
653
+ const responseContext2 = {
472
654
  ...hookRequestContext,
473
655
  durationMs: Date.now() - startedAt,
474
656
  status: response.status,
@@ -478,7 +660,9 @@ function createGatewayRequestClient(config = {}) {
478
660
  policyTraceId: apiError.policyTraceId ?? null,
479
661
  retryAfterMs,
480
662
  willRetry
481
- });
663
+ };
664
+ await config.onResponse?.(responseContext2);
665
+ await emitSdkResponseTelemetry(responseContext2);
482
666
  if (willRetry) {
483
667
  lastError = apiError;
484
668
  await delay(
@@ -493,7 +677,7 @@ function createGatewayRequestClient(config = {}) {
493
677
  throw apiError;
494
678
  }
495
679
  const successPayload = payload;
496
- await config.onResponse?.({
680
+ const responseContext = {
497
681
  ...hookRequestContext,
498
682
  durationMs: Date.now() - startedAt,
499
683
  status: response.status,
@@ -503,22 +687,25 @@ function createGatewayRequestClient(config = {}) {
503
687
  idempotentReplay: successPayload.idempotentReplay,
504
688
  retryAfterMs,
505
689
  willRetry: false
506
- });
690
+ };
691
+ await config.onResponse?.(responseContext);
692
+ await emitSdkResponseTelemetry(responseContext);
507
693
  return successPayload;
508
694
  } catch (fetchError) {
509
695
  if (fetchError instanceof LucernApiError) {
510
696
  throw fetchError;
511
697
  }
512
- const retry = classifyRetry({ error: fetchError });
513
- const willRetry = attempt < maxRetries && retry.retryable;
514
- await config.onResponse?.({
698
+ const willRetry = attempt < maxRetries && classifyGatewayErrorForRetry(fetchError);
699
+ const responseContext = {
515
700
  ...hookRequestContext,
516
701
  durationMs: Date.now() - startedAt,
517
702
  error: fetchError,
518
703
  correlationId: requestId,
519
704
  policyTraceId: null,
520
705
  willRetry
521
- });
706
+ };
707
+ await config.onResponse?.(responseContext);
708
+ await emitSdkResponseTelemetry(responseContext);
522
709
  lastError = fetchError;
523
710
  if (willRetry) {
524
711
  await delay(computeRetryDelayMs({ attempt }));