@lucern/sdk 1.0.29 → 1.0.30

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 (191) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/accessControl.d.ts +31 -31
  3. package/dist/accessControl.js +1 -0
  4. package/dist/adminClient.d.ts +74 -74
  5. package/dist/adminClient.js +38 -30
  6. package/dist/{answersClient.d.ts → answers-client.d.ts} +1 -1
  7. package/dist/{answersClient.js → answers-client.js} +2 -2
  8. package/dist/audience/index.d.ts +12 -12
  9. package/dist/{audiencesClient.d.ts → audiences-client.d.ts} +1 -1
  10. package/dist/audiences-client.js +107 -0
  11. package/dist/{auditClient.d.ts → audit-client.d.ts} +2 -3
  12. package/dist/{auditClient.js → audit-client.js} +8 -7
  13. package/dist/authContext.d.ts +26 -26
  14. package/dist/authDeviceClient.d.ts +11 -11
  15. package/dist/authDeviceClient.js +4 -6
  16. package/dist/beliefs/index.d.ts +56 -28
  17. package/dist/beliefs/index.js +2 -1
  18. package/dist/beliefsClient.d.ts +71 -63
  19. package/dist/beliefsClient.js +90 -67
  20. package/dist/{boundaryClientSurface.d.ts → boundary-client-surface.d.ts} +4 -4
  21. package/dist/{boundaryClientSurface.js → boundary-client-surface.js} +9 -7
  22. package/dist/client-assembly-types.d.ts +219 -0
  23. package/dist/client-assembly-types.js +2 -0
  24. package/dist/{clientConfig.d.ts → client-config.d.ts} +16 -32
  25. package/dist/client-config.js +2 -0
  26. package/dist/{clientEvidenceCompat.d.ts → client-evidence-compat.d.ts} +24 -24
  27. package/dist/{clientEvidenceCompat.js → client-evidence-compat.js} +2 -2
  28. package/dist/client.d.ts +1906 -352
  29. package/dist/client.js +34 -30
  30. package/dist/clientGraphNamespaces.d.ts +35 -25
  31. package/dist/clientGraphNamespaces.js +11 -5
  32. package/dist/clientHelpers.js +8 -5
  33. package/dist/clientKnowledgeNamespaces.d.ts +124 -84
  34. package/dist/clientKnowledgeNamespaces.js +35 -34
  35. package/dist/clientLocalHelpers.d.ts +81 -52
  36. package/dist/clientLocalHelpers.js +193 -43
  37. package/dist/clientPlatformNamespaces.d.ts +1541 -150
  38. package/dist/clientPlatformNamespaces.js +10 -5
  39. package/dist/clientRuntime.d.ts +1 -1
  40. package/dist/clientRuntime.js +1 -1
  41. package/dist/clientWorkflowNamespaces.d.ts +211 -97
  42. package/dist/clientWorkflowNamespaces.js +22 -19
  43. package/dist/contextClient.d.ts +2 -2
  44. package/dist/contextClient.js +79 -50
  45. package/dist/contextFacade.d.ts +1 -1
  46. package/dist/contextFacade.js +2 -0
  47. package/dist/contextPackCompiler.d.ts +52 -52
  48. package/dist/contextPackCompiler.js +192 -122
  49. package/dist/contextPackPolicy.d.ts +22 -22
  50. package/dist/contextPackPolicy.js +21 -9
  51. package/dist/contextPackSchema.d.ts +3 -3
  52. package/dist/contextPackSchema.js +1 -0
  53. package/dist/contextTypes.d.ts +155 -155
  54. package/dist/contracts/api-enums.contract.js +2 -11
  55. package/dist/contracts/auth-session.contract.d.ts +16 -16
  56. package/dist/contracts/auth-session.contract.js +3 -2
  57. package/dist/contracts/context-pack.contract.d.ts +216 -216
  58. package/dist/contracts/contextPack.js +2 -0
  59. package/dist/contracts/index.d.ts +1 -1
  60. package/dist/contracts/index.js +2 -1
  61. package/dist/contracts/lens-filter.contract.d.ts +8 -8
  62. package/dist/contracts/lens-filter.contract.js +10 -10
  63. package/dist/contracts/lens-workflow.contract.d.ts +32 -32
  64. package/dist/contracts/lens-workflow.contract.js +2 -1
  65. package/dist/contracts/lensFilter.js +2 -0
  66. package/dist/contracts/lensWorkflow.js +2 -0
  67. package/dist/contracts/mcpTools.d.ts +19 -19
  68. package/dist/contracts/mcpTools.js +3 -1
  69. package/dist/contracts/prompt.contract.d.ts +12 -12
  70. package/dist/contracts/prompt.js +1 -0
  71. package/dist/contracts/sdk-tools.contract.js +1 -0
  72. package/dist/contracts/sdkTools.js +2 -0
  73. package/dist/contracts/tool-contracts.js +1 -0
  74. package/dist/contracts/workflow-runtime.contract.d.ts +45 -45
  75. package/dist/contracts/workflow-runtime.contract.js +1 -5
  76. package/dist/contracts/workflowRuntime.js +2 -0
  77. package/dist/contradictions/index.d.ts +8 -8
  78. package/dist/contradictions/index.js +1 -0
  79. package/dist/control-plane.d.ts +10 -10
  80. package/dist/control-plane.js +2 -2
  81. package/dist/controlObjectOwnership.d.ts +11 -11
  82. package/dist/controlObjectOwnership.js +1 -0
  83. package/dist/coreClient.d.ts +51 -51
  84. package/dist/coreClient.js +269 -101
  85. package/dist/customTools.d.ts +19 -19
  86. package/dist/customTools.js +4 -2
  87. package/dist/decisions/index.d.ts +18 -18
  88. package/dist/decisions/index.js +1 -0
  89. package/dist/decisionsClient.d.ts +4 -4
  90. package/dist/decisionsClient.js +36 -27
  91. package/dist/edges/index.d.ts +20 -18
  92. package/dist/edges/index.js +1 -0
  93. package/dist/embeddingsClient.d.ts +29 -29
  94. package/dist/embeddingsClient.js +15 -8
  95. package/dist/eventingClient.d.ts +27 -27
  96. package/dist/eventingClient.js +10 -5
  97. package/dist/events.d.ts +83 -83
  98. package/dist/events.js +19 -15
  99. package/dist/eventsCore.d.ts +7 -7
  100. package/dist/eventsCore.js +11 -10
  101. package/dist/evidence/index.d.ts +23 -21
  102. package/dist/evidence/index.js +1 -0
  103. package/dist/evidenceClient.d.ts +23 -23
  104. package/dist/evidenceClient.js +10 -6
  105. package/dist/facade/context.d.ts +9 -9
  106. package/dist/facade/context.js +67 -41
  107. package/dist/functionSurface.js +2 -0
  108. package/dist/functionSurfaceClient.js +2 -0
  109. package/dist/gatewayFacades.d.ts +215 -215
  110. package/dist/gatewayFacades.factories.d.ts +23 -44
  111. package/dist/gatewayFacades.factories.js +63 -62
  112. package/dist/gatewayFacades.js +31 -32
  113. package/dist/graphAnalysisClient.d.ts +60 -60
  114. package/dist/graphAnalysisClient.js +19 -18
  115. package/dist/graphClient.d.ts +34 -34
  116. package/dist/graphClient.js +56 -35
  117. package/dist/graphIntel.js +2 -0
  118. package/dist/graphIntelligence.d.ts +2 -2
  119. package/dist/graphIntelligence.js +1 -1
  120. package/dist/graphRecommendationsClient.d.ts +24 -24
  121. package/dist/graphRecommendationsClient.js +12 -7
  122. package/dist/graphStateClassifierClient.d.ts +13 -13
  123. package/dist/graphStateClassifierClient.js +10 -5
  124. package/dist/harnessClient.d.ts +61 -61
  125. package/dist/harnessClient.js +44 -31
  126. package/dist/identityClient.d.ts +33 -59
  127. package/dist/identityClient.js +126 -98
  128. package/dist/index.d.ts +20 -20
  129. package/dist/index.js +20 -19
  130. package/dist/infisicalRuntime.d.ts +11 -11
  131. package/dist/infisicalRuntime.js +20 -14
  132. package/dist/jobsClient.d.ts +28 -28
  133. package/dist/jobsClient.js +6 -3
  134. package/dist/learningClient.js +13 -8
  135. package/dist/lenses/index.d.ts +124 -28
  136. package/dist/lenses/index.js +1 -0
  137. package/dist/mcpClient.d.ts +1 -1
  138. package/dist/mcpClient.js +3 -3
  139. package/dist/modelRuntimeClient.d.ts +27 -27
  140. package/dist/modelRuntimeClient.js +10 -5
  141. package/dist/nodes/index.d.ts +9 -9
  142. package/dist/nodes/index.js +1 -0
  143. package/dist/ontologies/index.d.ts +68 -22
  144. package/dist/ontologies/index.js +1 -0
  145. package/dist/ontologyClient.js +24 -17
  146. package/dist/ontologyLinksClient.d.ts +35 -35
  147. package/dist/ontologyLinksClient.js +9 -6
  148. package/dist/opinion.d.ts +3 -3
  149. package/dist/opinion.js +12 -5
  150. package/dist/orgGraphSearchClient.d.ts +39 -39
  151. package/dist/orgGraphSearchClient.js +22 -13
  152. package/dist/packsClient.d.ts +1 -1
  153. package/dist/packsClient.js +28 -19
  154. package/dist/policyClient.d.ts +79 -68
  155. package/dist/policyClient.js +18 -12
  156. package/dist/proof-attestation.json +1 -1
  157. package/dist/questions/index.d.ts +38 -27
  158. package/dist/questions/index.js +1 -0
  159. package/dist/realtime/index.d.ts +3 -3
  160. package/dist/realtime/index.js +1 -0
  161. package/dist/realtime/refs.d.ts +2 -2
  162. package/dist/{reportsClient.d.ts → reports-client.d.ts} +2 -2
  163. package/dist/{reportsClient.js → reports-client.js} +19 -13
  164. package/dist/{schemaClient.d.ts → schema-client.d.ts} +2 -3
  165. package/dist/{schemaClient.js → schema-client.js} +14 -11
  166. package/dist/sdkSurface.d.ts +12 -12
  167. package/dist/sdkSurface.js +14 -10
  168. package/dist/secrets.d.ts +1 -1
  169. package/dist/secrets.js +2 -1
  170. package/dist/{sourcesClient.d.ts → sources-client.d.ts} +8 -9
  171. package/dist/{sourcesClient.js → sources-client.js} +4 -5
  172. package/dist/{telemetryClient.d.ts → telemetry-client.d.ts} +14 -14
  173. package/dist/{telemetryClient.js → telemetry-client.js} +6 -4
  174. package/dist/toolRegistryClient.d.ts +46 -46
  175. package/dist/toolRegistryClient.js +22 -11
  176. package/dist/topics/index.d.ts +23 -23
  177. package/dist/topics/index.js +2 -1
  178. package/dist/topicsClient.d.ts +6 -6
  179. package/dist/topicsClient.js +29 -18
  180. package/dist/types.d.ts +356 -355
  181. package/dist/version.d.ts +1 -1
  182. package/dist/version.js +1 -1
  183. package/dist/workflowClient.d.ts +36 -35
  184. package/dist/workflowClient.js +88 -60
  185. package/dist/worktrees/index.d.ts +118 -32
  186. package/dist/worktrees/index.js +2 -1
  187. package/package.json +45 -5
  188. package/dist/audiencesClient.js +0 -115
  189. package/dist/clientAssemblyTypes.d.ts +0 -33
  190. package/dist/clientAssemblyTypes.js +0 -2
  191. package/dist/clientConfig.js +0 -2
@@ -1,13 +1,15 @@
1
+ // biome-ignore-all lint/style/useFilenamingConvention: This file is an @lucern/sdk public import ABI / package subpath compatibility surface; the camelCase filename is intentional.
1
2
  import { createTelemetryExporterFromEnv, emitTelemetrySignal, } from "@lucern/transport-core";
2
3
  import { redactDiagnosticValue } from "@lucern/transport-core/redaction";
3
4
  import { classifyRetry } from "@lucern/transport-core/transport";
4
- import { Cause, Effect, Exit } from "effect";
5
+ import { Cause, Effect, Either, Exit, Schema } from "effect";
5
6
  import { createCanonicalAuthHeaders, LucernSdkAuthContextError, normalizeCanonicalLucernAuthContext, } from "./authContext.js";
6
7
  const DEFAULT_GATEWAY_TIMEOUT_MS = 15_000;
7
8
  const DEFAULT_GATEWAY_MAX_RETRIES = 2;
8
9
  const DEFAULT_ENV_TIMEOUT_MS = "LUCERN_REQUEST_TIMEOUT_MS";
9
10
  const DEFAULT_ENV_MAX_RETRIES = "LUCERN_GATEWAY_MAX_RETRIES";
10
11
  const ENV_TIMEOUT_BY_METHOD_PREFIX = "LUCERN_REQUEST_TIMEOUT_MS_";
12
+ const TRAILING_SLASHES_PATTERN = /\/+$/u;
11
13
  export class GatewayTimeoutError extends Error {
12
14
  retryable = true;
13
15
  timeoutMs;
@@ -28,12 +30,12 @@ export class GatewayTransportError extends Error {
28
30
  }
29
31
  }
30
32
  export function isGatewayRecoverableError(error) {
31
- return error instanceof GatewayTimeoutError || error instanceof GatewayTransportError;
33
+ return (error instanceof GatewayTimeoutError ||
34
+ error instanceof GatewayTransportError);
32
35
  }
33
36
  export function isGatewayRetryableError(error) {
34
37
  return ((error instanceof GatewayTimeoutError && error.retryable) ||
35
- (error instanceof GatewayTransportError && error.retryable) ||
36
- false);
38
+ (error instanceof GatewayTransportError && error.retryable));
37
39
  }
38
40
  /**
39
41
  * Structured error thrown when a platform API request fails.
@@ -63,29 +65,85 @@ export class LucernApiError extends Error {
63
65
  this.policyTraceId = args.policyTraceId;
64
66
  }
65
67
  }
68
+ const JsonValueSchema = Schema.Unknown.pipe(Schema.filter((value) => isJsonValue(value), {
69
+ message: () => "Expected a JSON-serializable value",
70
+ }));
71
+ const GatewayLegacyErrorSchema = Schema.Struct({
72
+ code: Schema.String,
73
+ message: Schema.String,
74
+ details: Schema.optional(JsonValueSchema),
75
+ });
76
+ const GatewaySuccessDataSchema = Schema.Unknown.pipe(Schema.filter((value) => value !== undefined, {
77
+ message: () => "Expected gateway success data to be present",
78
+ }));
79
+ const GatewaySuccessEnvelopeSchema = Schema.Struct({
80
+ success: Schema.Literal(true),
81
+ data: GatewaySuccessDataSchema,
82
+ correlationId: Schema.String,
83
+ idempotentReplay: Schema.Boolean,
84
+ policyTraceId: Schema.NullOr(Schema.String),
85
+ });
86
+ const GatewayFailureEnvelopeSchema = Schema.Struct({
87
+ success: Schema.Literal(false),
88
+ error: Schema.Union(Schema.String, GatewayLegacyErrorSchema),
89
+ code: Schema.optional(Schema.String),
90
+ correlationId: Schema.String,
91
+ details: Schema.optional(JsonValueSchema),
92
+ invariant: Schema.optional(Schema.NullOr(Schema.String)),
93
+ legacyError: Schema.optional(GatewayLegacyErrorSchema),
94
+ policyTraceId: Schema.NullOr(Schema.String),
95
+ suggestion: Schema.optional(Schema.NullOr(Schema.String)),
96
+ });
97
+ const GatewayEnvelopeSchema = Schema.Union(GatewaySuccessEnvelopeSchema, GatewayFailureEnvelopeSchema);
98
+ const GatewayJsonBodySchema = Schema.Unknown.pipe(Schema.filter((value) => value === undefined || isJsonValue(value, { allowUndefined: true }), {
99
+ message: () => "Expected a JSON-serializable request body",
100
+ }));
66
101
  /**
67
102
  * Serialize a gateway query object into a URL query string.
68
103
  */
69
104
  export function toQueryString(scope) {
70
105
  const params = new URLSearchParams();
71
- if (scope.tenantId) {
72
- params.set("tenantId", scope.tenantId);
73
- }
74
- if (scope.workspaceId) {
75
- params.set("workspaceId", scope.workspaceId);
106
+ for (const preferredKey of ["tenantId", "workspaceId"]) {
107
+ const preferredValue = Object.entries(scope).find(([key]) => key === preferredKey)?.[1];
108
+ const serialized = serializeGatewayQueryValue(preferredValue);
109
+ if (serialized !== undefined) {
110
+ params.set(preferredKey, serialized);
111
+ }
76
112
  }
77
113
  for (const [key, value] of Object.entries(scope)) {
78
114
  if (key === "tenantId" || key === "workspaceId") {
79
115
  continue;
80
116
  }
81
- if (value === undefined) {
82
- continue;
117
+ const serialized = serializeGatewayQueryValue(value);
118
+ if (serialized !== undefined) {
119
+ params.set(key, serialized);
83
120
  }
84
- params.set(key, String(value));
85
121
  }
86
122
  const serialized = params.toString();
87
123
  return serialized.length > 0 ? `?${serialized}` : "";
88
124
  }
125
+ function serializeGatewayQueryValue(value) {
126
+ const decoded = Schema.decodeUnknownEither(GatewayJsonBodySchema)(value);
127
+ if (Either.isLeft(decoded)) {
128
+ throw new TypeError("Gateway query values must be JSON-serializable.");
129
+ }
130
+ const queryValue = decoded.right;
131
+ if (queryValue === undefined || queryValue === null) {
132
+ return;
133
+ }
134
+ if (Array.isArray(queryValue)) {
135
+ return queryValue
136
+ .filter((item) => item !== undefined && item !== null)
137
+ .map((item) => String(item))
138
+ .join(",");
139
+ }
140
+ if (typeof queryValue === "string" ||
141
+ typeof queryValue === "number" ||
142
+ typeof queryValue === "boolean") {
143
+ return String(queryValue);
144
+ }
145
+ throw new TypeError("Gateway query values must be scalar or arrays.");
146
+ }
89
147
  function fillRandomBytes(length) {
90
148
  const bytes = new Uint8Array(length);
91
149
  if (typeof globalThis.crypto?.getRandomValues === "function") {
@@ -102,10 +160,14 @@ function generatePortableRequestId() {
102
160
  return globalThis.crypto.randomUUID();
103
161
  }
104
162
  const bytes = fillRandomBytes(16);
163
+ // biome-ignore lint/suspicious/noBitwiseOperators: UUID v4 fallback must set version bits.
105
164
  bytes[6] = (bytes[6] & 0x0f) | 0x40;
165
+ // biome-ignore lint/suspicious/noBitwiseOperators: UUID v4 fallback must set variant bits.
106
166
  bytes[8] = (bytes[8] & 0x3f) | 0x80;
107
167
  const hex = Array.from(bytes, (value) => value.toString(16).padStart(2, "0"));
108
- return `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex.slice(6, 8).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10).join("")}`;
168
+ return `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex
169
+ .slice(6, 8)
170
+ .join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10).join("")}`;
109
171
  }
110
172
  function resolveEnvironment() {
111
173
  const processEnv = typeof globalThis === "object" &&
@@ -186,7 +248,7 @@ function parseIntegerFromString(value, rawValue) {
186
248
  return value;
187
249
  }
188
250
  if (typeof rawValue !== "string" || !rawValue.trim()) {
189
- return undefined;
251
+ return;
190
252
  }
191
253
  const parsed = Number.parseInt(rawValue, 10);
192
254
  return Number.isInteger(parsed) && parsed >= 0 ? parsed : undefined;
@@ -198,7 +260,7 @@ function resolveGatewayBaseUrl(configBaseUrl, environment) {
198
260
  const envBaseUrl = environment.get("LUCERN_API_URL") ??
199
261
  environment.get("LUCERN_BASE_URL") ??
200
262
  environment.get("LUCERN_GATEWAY_BASE_URL");
201
- return (configBaseUrl ?? envBaseUrl ?? "").replace(/\/+$/, "");
263
+ return (configBaseUrl ?? envBaseUrl ?? "").replace(TRAILING_SLASHES_PATTERN, "");
202
264
  }
203
265
  function normalizeGatewayEnvironment(value) {
204
266
  return value === "sandbox" || value === "production" ? value : undefined;
@@ -250,6 +312,34 @@ function classifyGatewayErrorForRetry(error) {
250
312
  function isRecord(value) {
251
313
  return value !== null && typeof value === "object" && !Array.isArray(value);
252
314
  }
315
+ function isPlainObject(value) {
316
+ if (!isRecord(value)) {
317
+ return false;
318
+ }
319
+ const prototype = Object.getPrototypeOf(value);
320
+ return prototype === Object.prototype || prototype === null;
321
+ }
322
+ function isJsonValue(value, options = {}) {
323
+ if (value === undefined) {
324
+ return options.allowUndefined === true;
325
+ }
326
+ if (value === null) {
327
+ return true;
328
+ }
329
+ if (typeof value === "string" || typeof value === "boolean") {
330
+ return true;
331
+ }
332
+ if (typeof value === "number") {
333
+ return Number.isFinite(value);
334
+ }
335
+ if (Array.isArray(value)) {
336
+ return value.every((item) => isJsonValue(item, options));
337
+ }
338
+ if (!isPlainObject(value)) {
339
+ return false;
340
+ }
341
+ return Object.values(value).every((entry) => isJsonValue(entry, options));
342
+ }
253
343
  function readPolicySummaryFromDetails(details) {
254
344
  if (!isRecord(details)) {
255
345
  return null;
@@ -298,6 +388,21 @@ function cleanHeaderValue(value) {
298
388
  const normalized = value?.trim();
299
389
  return normalized ? normalized : undefined;
300
390
  }
391
+ function sdkTelemetryEventName(context) {
392
+ if (context.willRetry) {
393
+ return "sdk.retry";
394
+ }
395
+ if (context.error) {
396
+ return "sdk.request.error";
397
+ }
398
+ return "sdk.request.complete";
399
+ }
400
+ function sdkTelemetrySeverity(context) {
401
+ if (!context.error) {
402
+ return "info";
403
+ }
404
+ return context.willRetry ? "warn" : "error";
405
+ }
301
406
  /**
302
407
  * Create the transport client used by all SDK modules.
303
408
  */
@@ -334,7 +439,7 @@ export function createGatewayRequestClient(config = {}) {
334
439
  setIfAbsent("x-lucern-deployment-host", config.deploymentHost);
335
440
  const base = Object.fromEntries(headers.entries());
336
441
  const authContextInput = await resolveConfiguredAuthContext(config.authContext);
337
- if (!authContextInput && !config.requireCanonicalAuthContext) {
442
+ if (!(authContextInput || config.requireCanonicalAuthContext)) {
338
443
  return base;
339
444
  }
340
445
  const authContext = normalizeCanonicalLucernAuthContext(authContextInput);
@@ -385,12 +490,8 @@ export function createGatewayRequestClient(config = {}) {
385
490
  await emitTelemetrySignal(telemetryExporter, {
386
491
  signalType: "trace",
387
492
  surface: "sdk-retry",
388
- eventName: context.willRetry
389
- ? "sdk.retry"
390
- : context.error
391
- ? "sdk.request.error"
392
- : "sdk.request.complete",
393
- severity: context.error ? (context.willRetry ? "warn" : "error") : "info",
493
+ eventName: sdkTelemetryEventName(context),
494
+ severity: sdkTelemetrySeverity(context),
394
495
  durationMs: context.durationMs,
395
496
  metricName: "sdk.request.duration_ms",
396
497
  metricValue: context.durationMs,
@@ -428,9 +529,21 @@ export function createGatewayRequestClient(config = {}) {
428
529
  if (!parsed.ok) {
429
530
  return null;
430
531
  }
431
- return isRecord(parsed.value)
432
- ? parsed.value
433
- : null;
532
+ return decodeGatewayEnvelope(parsed.value);
533
+ }
534
+ function decodeGatewayEnvelope(value) {
535
+ const decoded = Schema.decodeUnknownEither(GatewayEnvelopeSchema)(value);
536
+ if (Either.isLeft(decoded)) {
537
+ return null;
538
+ }
539
+ const envelope = decoded.right;
540
+ if (envelope.success) {
541
+ return {
542
+ ...envelope,
543
+ data: envelope.data,
544
+ };
545
+ }
546
+ return envelope;
434
547
  }
435
548
  function resolveTimeoutMs(method, requestTimeoutMs) {
436
549
  if (typeof requestTimeoutMs === "number") {
@@ -444,7 +557,7 @@ export function createGatewayRequestClient(config = {}) {
444
557
  }
445
558
  function tryParseGatewayEnvelopeJson(text) {
446
559
  const trimmed = text.trim();
447
- if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) {
560
+ if (!(trimmed.startsWith("{") || trimmed.startsWith("["))) {
448
561
  return { ok: false, reason: "non-json" };
449
562
  }
450
563
  try {
@@ -468,9 +581,7 @@ export function createGatewayRequestClient(config = {}) {
468
581
  null;
469
582
  const details = runtime.redaction(redactJsonDiagnosticValue(failure?.details ?? legacyError?.details));
470
583
  const policySummary = readPolicySummaryFromDetails(details);
471
- const failureMessage = typeof failure?.error === "string"
472
- ? failure.error
473
- : legacyError?.message;
584
+ const failureMessage = typeof failure?.error === "string" ? failure.error : legacyError?.message;
474
585
  return new LucernApiError({
475
586
  code: failure?.code ??
476
587
  legacyError?.code ??
@@ -489,6 +600,97 @@ export function createGatewayRequestClient(config = {}) {
489
600
  policyTraceId,
490
601
  });
491
602
  }
603
+ async function emitGatewayResponseContext(context) {
604
+ await config.onResponse?.(context);
605
+ await emitSdkResponseTelemetry(context);
606
+ }
607
+ function buildGatewayRequestHookContext(args) {
608
+ return {
609
+ requestId: args.requestId,
610
+ attempt: args.attempt,
611
+ maxRetries: args.maxRetries,
612
+ method: args.method,
613
+ path: args.path,
614
+ url: args.url,
615
+ headers: new Headers(args.headers),
616
+ body: args.body,
617
+ timeoutMs: args.timeoutMs,
618
+ };
619
+ }
620
+ async function handleGatewayHttpResponse(args) {
621
+ if (!(args.response.ok && args.payload?.success)) {
622
+ const failure = args.payload && !args.payload.success
623
+ ? args.payload
624
+ : null;
625
+ const apiError = buildApiError({
626
+ requestId: args.requestId,
627
+ response: args.response,
628
+ failure,
629
+ });
630
+ const willRetry = args.attempt < args.maxRetries && args.retryable;
631
+ await emitGatewayResponseContext({
632
+ ...args.hookRequestContext,
633
+ durationMs: Date.now() - args.startedAt,
634
+ status: args.response.status,
635
+ response: args.responseClone,
636
+ error: apiError,
637
+ correlationId: apiError.correlationId ?? args.requestId,
638
+ policyTraceId: apiError.policyTraceId ?? null,
639
+ retryAfterMs: args.retryAfterMs,
640
+ willRetry,
641
+ });
642
+ if (willRetry) {
643
+ return {
644
+ retryError: apiError,
645
+ retryDelayMs: computeRetryDelayMs({
646
+ attempt: args.attempt,
647
+ status: args.response.status,
648
+ retryAfterMs: args.retryAfterMs,
649
+ }),
650
+ };
651
+ }
652
+ throw apiError;
653
+ }
654
+ const successPayload = args.payload;
655
+ await emitGatewayResponseContext({
656
+ ...args.hookRequestContext,
657
+ durationMs: Date.now() - args.startedAt,
658
+ status: args.response.status,
659
+ response: args.responseClone,
660
+ correlationId: successPayload.correlationId ??
661
+ args.response.headers.get("x-lucern-correlation-id")?.trim() ??
662
+ args.requestId,
663
+ policyTraceId: successPayload.policyTraceId ??
664
+ args.response.headers.get("x-lucern-policy-trace-id")?.trim() ??
665
+ null,
666
+ idempotentReplay: successPayload.idempotentReplay,
667
+ retryAfterMs: args.retryAfterMs,
668
+ willRetry: false,
669
+ });
670
+ return { success: successPayload };
671
+ }
672
+ async function handleGatewayFetchError(args) {
673
+ if (args.error instanceof LucernApiError) {
674
+ throw args.error;
675
+ }
676
+ const willRetry = args.attempt < args.maxRetries &&
677
+ classifyGatewayErrorForRetry(args.error);
678
+ await emitGatewayResponseContext({
679
+ ...args.hookRequestContext,
680
+ durationMs: Date.now() - args.startedAt,
681
+ error: args.error,
682
+ correlationId: args.requestId,
683
+ policyTraceId: null,
684
+ willRetry,
685
+ });
686
+ if (willRetry) {
687
+ return {
688
+ retryError: args.error,
689
+ retryDelayMs: computeRetryDelayMs({ attempt: args.attempt }),
690
+ };
691
+ }
692
+ throw args.error;
693
+ }
492
694
  async function request(args) {
493
695
  const authHeaders = await resolveAuthHeaders();
494
696
  const method = args.method ?? "GET";
@@ -504,11 +706,11 @@ export function createGatewayRequestClient(config = {}) {
504
706
  headers.get("x-request-id")?.trim() ||
505
707
  args.requestId ||
506
708
  requestIdFactory();
507
- if (!headers.has("x-correlation-id") && !headers.has("x-request-id")) {
709
+ if (!(headers.has("x-correlation-id") || headers.has("x-request-id"))) {
508
710
  headers.set("x-correlation-id", requestId);
509
711
  }
510
712
  const url = `${baseUrl}${args.path}`;
511
- const serializedBody = args.body ? JSON.stringify(args.body) : undefined;
713
+ const serializedBody = args.body === undefined ? undefined : stringifyGatewayJsonBody(args.body);
512
714
  const init = {
513
715
  method,
514
716
  headers,
@@ -516,17 +718,17 @@ export function createGatewayRequestClient(config = {}) {
516
718
  };
517
719
  let lastError;
518
720
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
519
- const hookRequestContext = {
721
+ const hookRequestContext = buildGatewayRequestHookContext({
520
722
  requestId,
521
723
  attempt,
522
724
  maxRetries,
523
725
  method,
524
726
  path: args.path,
525
727
  url,
526
- headers: new Headers(headers),
728
+ headers,
527
729
  body: serializedBody,
528
730
  timeoutMs,
529
- };
731
+ });
530
732
  await config.onRequest?.(hookRequestContext);
531
733
  const startedAt = Date.now();
532
734
  try {
@@ -538,77 +740,36 @@ export function createGatewayRequestClient(config = {}) {
538
740
  retryAfter: response.headers.get("Retry-After"),
539
741
  });
540
742
  const retryAfterMs = retry.retryAfterMs ?? null;
541
- if (!response.ok || !payload?.success) {
542
- const failure = payload && !payload.success ? payload : null;
543
- const apiError = buildApiError({
544
- requestId,
545
- response,
546
- failure,
547
- });
548
- const willRetry = attempt < maxRetries && retry.retryable;
549
- const responseContext = {
550
- ...hookRequestContext,
551
- durationMs: Date.now() - startedAt,
552
- status: response.status,
553
- response: responseClone,
554
- error: apiError,
555
- correlationId: apiError.correlationId ?? requestId,
556
- policyTraceId: apiError.policyTraceId ?? null,
557
- retryAfterMs,
558
- willRetry,
559
- };
560
- await config.onResponse?.(responseContext);
561
- await emitSdkResponseTelemetry(responseContext);
562
- if (willRetry) {
563
- lastError = apiError;
564
- await delay(computeRetryDelayMs({
565
- attempt,
566
- status: response.status,
567
- retryAfterMs,
568
- }));
569
- continue;
570
- }
571
- throw apiError;
572
- }
573
- const successPayload = payload;
574
- const responseContext = {
575
- ...hookRequestContext,
576
- durationMs: Date.now() - startedAt,
577
- status: response.status,
578
- response: responseClone,
579
- correlationId: successPayload.correlationId ??
580
- response.headers.get("x-lucern-correlation-id")?.trim() ??
581
- requestId,
582
- policyTraceId: successPayload.policyTraceId ??
583
- response.headers.get("x-lucern-policy-trace-id")?.trim() ??
584
- null,
585
- idempotentReplay: successPayload.idempotentReplay,
743
+ const attemptResult = await handleGatewayHttpResponse({
744
+ attempt,
745
+ hookRequestContext,
746
+ maxRetries,
747
+ payload,
748
+ requestId,
749
+ response,
750
+ responseClone,
586
751
  retryAfterMs,
587
- willRetry: false,
588
- };
589
- await config.onResponse?.(responseContext);
590
- await emitSdkResponseTelemetry(responseContext);
591
- return successPayload;
752
+ retryable: retry.retryable,
753
+ startedAt,
754
+ });
755
+ if ("retryError" in attemptResult) {
756
+ lastError = attemptResult.retryError;
757
+ await delay(attemptResult.retryDelayMs);
758
+ continue;
759
+ }
760
+ return attemptResult.success;
592
761
  }
593
762
  catch (fetchError) {
594
- if (fetchError instanceof LucernApiError) {
595
- throw fetchError;
596
- }
597
- const willRetry = attempt < maxRetries && classifyGatewayErrorForRetry(fetchError);
598
- const responseContext = {
599
- ...hookRequestContext,
600
- durationMs: Date.now() - startedAt,
763
+ const attemptResult = await handleGatewayFetchError({
764
+ attempt,
601
765
  error: fetchError,
602
- correlationId: requestId,
603
- policyTraceId: null,
604
- willRetry,
605
- };
606
- await config.onResponse?.(responseContext);
607
- await emitSdkResponseTelemetry(responseContext);
608
- lastError = fetchError;
609
- if (willRetry) {
610
- await delay(computeRetryDelayMs({ attempt }));
611
- }
766
+ hookRequestContext,
767
+ maxRetries,
768
+ requestId,
769
+ startedAt,
770
+ });
771
+ lastError = attemptResult.retryError;
772
+ await delay(attemptResult.retryDelayMs);
612
773
  }
613
774
  }
614
775
  throw lastError instanceof Error
@@ -619,4 +780,11 @@ export function createGatewayRequestClient(config = {}) {
619
780
  request,
620
781
  };
621
782
  }
783
+ function stringifyGatewayJsonBody(body) {
784
+ const decoded = Schema.decodeUnknownEither(GatewayJsonBodySchema)(body);
785
+ if (Either.isLeft(decoded)) {
786
+ throw new GatewayTransportError("Gateway request body must be JSON-serializable.", { retryable: false });
787
+ }
788
+ return JSON.stringify(decoded.right);
789
+ }
622
790
  //# sourceMappingURL=coreClient.js.map
@@ -5,39 +5,39 @@ type AnyZodObject = z.ZodObject<z.ZodRawShape>;
5
5
  /** Origin of a custom tool invocation (SDK call or MCP request). */
6
6
  export type CustomToolInvocationSource = "sdk" | "mcp";
7
7
  /** Runtime context passed to a custom tool handler during invocation. */
8
- export type CustomToolInvocationContext = {
8
+ export interface CustomToolInvocationContext {
9
9
  source: CustomToolInvocationSource;
10
- };
10
+ }
11
11
  /** Optional metadata attached to a custom tool registration. */
12
- export type CustomToolMetadata = {
12
+ export interface CustomToolMetadata {
13
13
  category?: string;
14
- tags?: string[];
15
14
  requiredScopes?: string[];
16
- };
15
+ tags?: string[];
16
+ }
17
17
  /** Input descriptor for registering a custom tool with its schemas and handler. */
18
- export type CustomToolRegistration<TInput extends AnyZodObject = AnyZodObject, TOutput extends z.ZodTypeAny = z.ZodTypeAny> = {
19
- namespace?: string;
20
- name: string;
18
+ export interface CustomToolRegistration<TInput extends AnyZodObject = AnyZodObject, TOutput extends z.ZodTypeAny = z.ZodTypeAny> {
21
19
  description: string;
22
- inputSchema: TInput;
23
- outputSchema: TOutput;
24
20
  handler: (input: z.infer<TInput>, context: CustomToolInvocationContext) => Promise<z.infer<TOutput>> | z.infer<TOutput>;
21
+ inputSchema: TInput;
25
22
  metadata?: CustomToolMetadata;
26
- ownerModule?: string;
23
+ name: string;
24
+ namespace?: string;
27
25
  ontologyPrimitive?: McpToolContract["ontologyPrimitive"];
26
+ outputSchema: TOutput;
27
+ ownerModule?: string;
28
28
  tier?: McpToolContract["tier"];
29
- };
29
+ }
30
30
  /** A fully resolved custom tool entry stored in the in-memory registry. */
31
- export type RegisteredCustomTool = {
32
- fullName: string;
33
- namespace: string;
34
- shortName: string;
35
- metadata: CustomToolMetadata;
31
+ export interface RegisteredCustomTool {
36
32
  contract: McpToolContract;
33
+ fullName: string;
37
34
  inputSchema: AnyZodObject;
38
- outputSchema: z.ZodTypeAny;
39
35
  invoke: (input: JsonObject, context: CustomToolInvocationContext) => Promise<unknown>;
40
- };
36
+ metadata: CustomToolMetadata;
37
+ namespace: string;
38
+ outputSchema: z.ZodTypeAny;
39
+ shortName: string;
40
+ }
41
41
  /** Error thrown when custom tool registration or invocation fails validation. */
42
42
  export declare class CustomToolRegistryError extends Error {
43
43
  constructor(message: string);
@@ -1,8 +1,10 @@
1
+ // biome-ignore-all lint/style/useFilenamingConvention: This file is an @lucern/sdk public import ABI / package subpath compatibility surface; the camelCase filename is intentional.
1
2
  import { z } from "zod";
2
3
  /** Default namespace assigned to custom tools when none is specified. */
3
4
  const DEFAULT_CUSTOM_NAMESPACE = "custom";
4
5
  /** Namespace strings reserved for platform-internal tools. */
5
6
  const RESERVED_NAMESPACES = new Set(["lucern"]);
7
+ const CUSTOM_TOOL_SEGMENT_PATTERN = /^[a-zA-Z][a-zA-Z0-9_-]*$/;
6
8
  /** Error thrown when custom tool registration or invocation fails validation. */
7
9
  export class CustomToolRegistryError extends Error {
8
10
  constructor(message) {
@@ -16,7 +18,7 @@ function normalizeSegment(value, field) {
16
18
  if (!normalized) {
17
19
  throw new CustomToolRegistryError(`Custom tool ${field} is required.`);
18
20
  }
19
- if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(normalized)) {
21
+ if (!CUSTOM_TOOL_SEGMENT_PATTERN.test(normalized)) {
20
22
  throw new CustomToolRegistryError(`Invalid custom tool ${field}: "${value}". Use letters, numbers, "_" or "-".`);
21
23
  }
22
24
  return normalized;
@@ -238,7 +240,7 @@ export function clearRegisteredCustomTools() {
238
240
  * @param context - Invocation context indicating the call source.
239
241
  * @returns The validated output from the tool handler.
240
242
  */
241
- export async function invokeRegisteredCustomTool(fullName, params, context) {
243
+ export function invokeRegisteredCustomTool(fullName, params, context) {
242
244
  const registered = getRegisteredCustomTool(fullName);
243
245
  if (!registered) {
244
246
  throw new CustomToolRegistryError(`Custom tool "${fullName}" is not registered.`);
@@ -4,29 +4,29 @@ export * as toolSchemas from "@lucern/contracts/tool-contracts";
4
4
  export type DecisionsClientConfig = LucernClientConfig;
5
5
  export type DecisionsClient = ReturnType<typeof createDecisionsClient>;
6
6
  export declare function createDecisionsClient(config?: DecisionsClientConfig): {
7
- createDecision: any;
8
- getDecision: any;
9
- listDecisions: any;
10
- recordDecisionOutcome: any;
11
- updateDecisionOutcome: any;
12
- getDecisionReadiness: (topicId: string) => any;
13
- getDecisionCalibration: (topicId: string) => any;
14
- listPendingDecisionOutcomeReviews: (topicId: string) => any;
7
+ createDecision: (input: import("..").RecordJudgmentInput, idempotencyKey?: string) => Promise<import("..").PlatformGatewaySuccess<import("..").RecordJudgmentResponse>>;
8
+ getDecision: (judgmentId: string) => Promise<import("..").PlatformGatewaySuccess<import("..").GetJudgmentResponse>>;
9
+ listDecisions: (query: import("..").ListJudgmentsInput) => Promise<import("..").PlatformGatewaySuccess<import("..").ListJudgmentsResponse>>;
10
+ recordDecisionOutcome: (judgmentId: string, input: import("..").RecordJudgmentOutcomeInput, idempotencyKey?: string) => Promise<import("..").PlatformGatewaySuccess<import("..").RecordJudgmentOutcomeResponse>>;
11
+ updateDecisionOutcome: (judgmentId: string, input: import("..").RecordJudgmentOutcomeInput, idempotencyKey?: string) => Promise<import("..").PlatformGatewaySuccess<import("..").RecordJudgmentOutcomeResponse>>;
12
+ getDecisionReadiness: (topicId: string) => Promise<import("..").PlatformGatewaySuccess<import("..").JudgmentReadinessResponse>>;
13
+ getDecisionCalibration: (topicId: string) => Promise<import("..").PlatformGatewaySuccess<import("..").JudgmentCalibrationResponse>>;
14
+ listPendingDecisionOutcomeReviews: (topicId: string) => Promise<import("..").PlatformGatewaySuccess<import("..").ListResult<import("..").PendingJudgmentOutcomeRecord, "reviews">>>;
15
15
  raw: {
16
- create: any;
17
- record: any;
18
- list: any;
19
- get: any;
20
- recordOutcome: any;
21
- updateOutcome: any;
22
- readiness(topicId: string): any;
23
- calibration(topicId: string): any;
24
- pendingOutcomeReview(topicId: string): any;
16
+ create: (input: import("..").RecordJudgmentInput, idempotencyKey?: string) => Promise<import("..").PlatformGatewaySuccess<import("..").RecordJudgmentResponse>>;
17
+ record: (input: import("..").RecordJudgmentInput, idempotencyKey?: string) => Promise<import("..").PlatformGatewaySuccess<import("..").RecordJudgmentResponse>>;
18
+ list: (query: import("..").ListJudgmentsInput) => Promise<import("..").PlatformGatewaySuccess<import("..").ListJudgmentsResponse>>;
19
+ get: (judgmentId: string) => Promise<import("..").PlatformGatewaySuccess<import("..").GetJudgmentResponse>>;
20
+ recordOutcome: (judgmentId: string, input: import("..").RecordJudgmentOutcomeInput, idempotencyKey?: string) => Promise<import("..").PlatformGatewaySuccess<import("..").RecordJudgmentOutcomeResponse>>;
21
+ updateOutcome: (judgmentId: string, input: import("..").RecordJudgmentOutcomeInput, idempotencyKey?: string) => Promise<import("..").PlatformGatewaySuccess<import("..").RecordJudgmentOutcomeResponse>>;
22
+ readiness(topicId: string): Promise<import("..").PlatformGatewaySuccess<import("..").JudgmentReadinessResponse>>;
23
+ calibration(topicId: string): Promise<import("..").PlatformGatewaySuccess<import("..").JudgmentCalibrationResponse>>;
24
+ pendingOutcomeReview(topicId: string): Promise<import("..").PlatformGatewaySuccess<import("..").ListResult<import("..").PendingJudgmentOutcomeRecord, "reviews">>>;
25
25
  transitionAuditIntegrity(args: {
26
26
  topicId?: string;
27
27
  judgmentId?: string;
28
28
  includePassing?: boolean;
29
- }): any;
29
+ }): Promise<import("..").PlatformGatewaySuccess<import("..").JudgmentTransitionAuditIntegrityResponse>>;
30
30
  };
31
31
  };
32
32
  //# sourceMappingURL=index.d.ts.map