@lucern/sdk 0.3.0-alpha.1 → 0.3.0-alpha.10

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 (214) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/README.md +51 -4
  3. package/dist/adminClient.d.ts +10 -8
  4. package/dist/adminClient.js +242 -39
  5. package/dist/adminClient.js.map +1 -1
  6. package/dist/answersClient.d.ts +2 -0
  7. package/dist/answersClient.js +221 -11
  8. package/dist/answersClient.js.map +1 -1
  9. package/dist/audience/index.d.ts +2 -1
  10. package/dist/audience/index.js +1 -3
  11. package/dist/audience/index.js.map +1 -1
  12. package/dist/audiencesClient.d.ts +18 -16
  13. package/dist/audiencesClient.js +297 -90
  14. package/dist/audiencesClient.js.map +1 -1
  15. package/dist/auditClient.d.ts +2 -0
  16. package/dist/auditClient.js +227 -15
  17. package/dist/auditClient.js.map +1 -1
  18. package/dist/authContext.d.ts +56 -0
  19. package/dist/authContext.js +170 -0
  20. package/dist/authContext.js.map +1 -0
  21. package/dist/authDeviceClient.d.ts +49 -0
  22. package/dist/authDeviceClient.js +121 -0
  23. package/dist/authDeviceClient.js.map +1 -0
  24. package/dist/beliefs/index.d.ts +25 -5
  25. package/dist/beliefs/index.js +3286 -1049
  26. package/dist/beliefs/index.js.map +1 -1
  27. package/dist/beliefsClient.d.ts +4 -2
  28. package/dist/beliefsClient.js +230 -26
  29. package/dist/beliefsClient.js.map +1 -1
  30. package/dist/boundaryClientSurface.d.ts +20 -0
  31. package/dist/boundaryClientSurface.js +73 -0
  32. package/dist/boundaryClientSurface.js.map +1 -0
  33. package/dist/client.d.ts +2969 -27
  34. package/dist/client.js +3286 -1049
  35. package/dist/client.js.map +1 -1
  36. package/dist/clientHelpers.d.ts +48 -0
  37. package/dist/clientHelpers.js +137 -0
  38. package/dist/clientHelpers.js.map +1 -0
  39. package/dist/contextClient.d.ts +6 -3
  40. package/dist/contextClient.js +252 -30
  41. package/dist/contextClient.js.map +1 -1
  42. package/dist/contextFacade.js +25 -16
  43. package/dist/contextFacade.js.map +1 -1
  44. package/dist/contextPackCompiler.js +19 -30
  45. package/dist/contextPackCompiler.js.map +1 -1
  46. package/dist/contextPackPolicy.js +7 -17
  47. package/dist/contextPackPolicy.js.map +1 -1
  48. package/dist/contextTypes.d.ts +2 -0
  49. package/dist/contracts/api-enums.contract.d.ts +1 -1
  50. package/dist/contracts/api-enums.contract.js.map +1 -1
  51. package/dist/contracts/index.d.ts +1 -0
  52. package/dist/contracts/index.js +108 -4
  53. package/dist/contracts/index.js.map +1 -1
  54. package/dist/contracts/lens-filter.contract.js +4 -3
  55. package/dist/contracts/lens-filter.contract.js.map +1 -1
  56. package/dist/contracts/lens-workflow.contract.js +4 -3
  57. package/dist/contracts/lens-workflow.contract.js.map +1 -1
  58. package/dist/contracts/lensFilter.js +4 -3
  59. package/dist/contracts/lensFilter.js.map +1 -1
  60. package/dist/contracts/lensWorkflow.js +4 -3
  61. package/dist/contracts/lensWorkflow.js.map +1 -1
  62. package/dist/contracts/mcpTools.d.ts +46 -1
  63. package/dist/contracts/mcpTools.js +102 -0
  64. package/dist/contracts/mcpTools.js.map +1 -1
  65. package/dist/contradictions/index.d.ts +24 -4
  66. package/dist/contradictions/index.js +3286 -1049
  67. package/dist/contradictions/index.js.map +1 -1
  68. package/dist/coreClient.d.ts +11 -1
  69. package/dist/coreClient.js +222 -14
  70. package/dist/coreClient.js.map +1 -1
  71. package/dist/decisions/index.d.ts +34 -14
  72. package/dist/decisions/index.js +3286 -1049
  73. package/dist/decisions/index.js.map +1 -1
  74. package/dist/decisionsClient.d.ts +6 -12
  75. package/dist/decisionsClient.js +235 -37
  76. package/dist/decisionsClient.js.map +1 -1
  77. package/dist/edges/index.d.ts +47 -87
  78. package/dist/edges/index.js +3286 -1049
  79. package/dist/edges/index.js.map +1 -1
  80. package/dist/embeddingsClient.d.ts +106 -0
  81. package/dist/embeddingsClient.js +731 -0
  82. package/dist/embeddingsClient.js.map +1 -0
  83. package/dist/eventingClient.d.ts +96 -0
  84. package/dist/eventingClient.js +728 -0
  85. package/dist/eventingClient.js.map +1 -0
  86. package/dist/events.js +6 -3
  87. package/dist/events.js.map +1 -1
  88. package/dist/eventsCore.d.ts +3 -1
  89. package/dist/eventsCore.js +222 -14
  90. package/dist/eventsCore.js.map +1 -1
  91. package/dist/evidence/index.d.ts +24 -4
  92. package/dist/evidence/index.js +3286 -1049
  93. package/dist/evidence/index.js.map +1 -1
  94. package/dist/evidenceClient.d.ts +2 -0
  95. package/dist/evidenceClient.js +222 -14
  96. package/dist/evidenceClient.js.map +1 -1
  97. package/dist/facade/context.d.ts +2 -1
  98. package/dist/facade/context.js +25 -16
  99. package/dist/facade/context.js.map +1 -1
  100. package/dist/functionSurface.d.ts +143 -0
  101. package/dist/functionSurface.js +1204 -0
  102. package/dist/functionSurface.js.map +1 -0
  103. package/dist/functionSurfaceClient.d.ts +8 -0
  104. package/dist/functionSurfaceClient.js +1204 -0
  105. package/dist/functionSurfaceClient.js.map +1 -0
  106. package/dist/gatewayFacades.d.ts +63 -46
  107. package/dist/gatewayFacades.js +461 -128
  108. package/dist/gatewayFacades.js.map +1 -1
  109. package/dist/graphAnalysisClient.d.ts +192 -0
  110. package/dist/graphAnalysisClient.js +799 -0
  111. package/dist/graphAnalysisClient.js.map +1 -0
  112. package/dist/graphClient.d.ts +7 -13
  113. package/dist/graphClient.js +244 -45
  114. package/dist/graphClient.js.map +1 -1
  115. package/dist/graphIntel.d.ts +3 -0
  116. package/dist/graphIntel.js +3 -0
  117. package/dist/graphIntel.js.map +1 -0
  118. package/dist/graphIntelligence.d.ts +2 -0
  119. package/dist/graphIntelligence.js +47 -0
  120. package/dist/graphIntelligence.js.map +1 -0
  121. package/dist/graphRecommendationsClient.d.ts +56 -0
  122. package/dist/graphRecommendationsClient.js +664 -0
  123. package/dist/graphRecommendationsClient.js.map +1 -0
  124. package/dist/graphStateClassifierClient.d.ts +73 -0
  125. package/dist/graphStateClassifierClient.js +716 -0
  126. package/dist/graphStateClassifierClient.js.map +1 -0
  127. package/dist/harnessClient.d.ts +15 -24
  128. package/dist/harnessClient.js +235 -42
  129. package/dist/harnessClient.js.map +1 -1
  130. package/dist/identityClient.d.ts +97 -11
  131. package/dist/identityClient.js +409 -33
  132. package/dist/identityClient.js.map +1 -1
  133. package/dist/index.d.ts +28 -5
  134. package/dist/index.js +3863 -1116
  135. package/dist/index.js.map +1 -1
  136. package/dist/infisicalRuntime.d.ts +42 -0
  137. package/dist/infisicalRuntime.js +314 -0
  138. package/dist/infisicalRuntime.js.map +1 -0
  139. package/dist/jobsClient.d.ts +98 -0
  140. package/dist/jobsClient.js +726 -0
  141. package/dist/jobsClient.js.map +1 -0
  142. package/dist/learningClient.d.ts +8 -6
  143. package/dist/learningClient.js +252 -44
  144. package/dist/learningClient.js.map +1 -1
  145. package/dist/lenses/index.d.ts +76 -38
  146. package/dist/lenses/index.js +3286 -1049
  147. package/dist/lenses/index.js.map +1 -1
  148. package/dist/mcpClient.d.ts +28 -0
  149. package/dist/mcpClient.js +668 -0
  150. package/dist/mcpClient.js.map +1 -0
  151. package/dist/modelRuntimeClient.d.ts +72 -0
  152. package/dist/modelRuntimeClient.js +704 -0
  153. package/dist/modelRuntimeClient.js.map +1 -0
  154. package/dist/nodes/index.d.ts +63 -21
  155. package/dist/nodes/index.js +3286 -1049
  156. package/dist/nodes/index.js.map +1 -1
  157. package/dist/ontologies/index.d.ts +53 -32
  158. package/dist/ontologies/index.js +3286 -1049
  159. package/dist/ontologies/index.js.map +1 -1
  160. package/dist/ontologyClient.d.ts +19 -25
  161. package/dist/ontologyClient.js +258 -40
  162. package/dist/ontologyClient.js.map +1 -1
  163. package/dist/ontologyLinksClient.d.ts +71 -0
  164. package/dist/ontologyLinksClient.js +697 -0
  165. package/dist/ontologyLinksClient.js.map +1 -0
  166. package/dist/orgGraphSearchClient.d.ts +85 -0
  167. package/dist/orgGraphSearchClient.js +672 -0
  168. package/dist/orgGraphSearchClient.js.map +1 -0
  169. package/dist/packsClient.d.ts +11 -23
  170. package/dist/packsClient.js +234 -46
  171. package/dist/packsClient.js.map +1 -1
  172. package/dist/policyClient.d.ts +13 -10
  173. package/dist/policyClient.js +243 -25
  174. package/dist/policyClient.js.map +1 -1
  175. package/dist/questions/index.d.ts +24 -4
  176. package/dist/questions/index.js +3286 -1049
  177. package/dist/questions/index.js.map +1 -1
  178. package/dist/realtime/index.d.ts +1 -1
  179. package/dist/reportsClient.d.ts +9 -7
  180. package/dist/reportsClient.js +281 -53
  181. package/dist/reportsClient.js.map +1 -1
  182. package/dist/schemaClient.d.ts +5 -3
  183. package/dist/schemaClient.js +235 -29
  184. package/dist/schemaClient.js.map +1 -1
  185. package/dist/sdkSurface.d.ts +8 -3
  186. package/dist/sdkSurface.js +10 -6
  187. package/dist/sdkSurface.js.map +1 -1
  188. package/dist/sourcesClient.d.ts +2 -0
  189. package/dist/sourcesClient.js +222 -14
  190. package/dist/sourcesClient.js.map +1 -1
  191. package/dist/telemetryClient.d.ts +94 -0
  192. package/dist/telemetryClient.js +741 -0
  193. package/dist/telemetryClient.js.map +1 -0
  194. package/dist/toolRegistryClient.d.ts +115 -0
  195. package/dist/toolRegistryClient.js +767 -0
  196. package/dist/toolRegistryClient.js.map +1 -0
  197. package/dist/topics/index.d.ts +35 -9
  198. package/dist/topics/index.js +3288 -1049
  199. package/dist/topics/index.js.map +1 -1
  200. package/dist/topicsClient.d.ts +4 -0
  201. package/dist/topicsClient.js +237 -24
  202. package/dist/topicsClient.js.map +1 -1
  203. package/dist/types.d.ts +5 -0
  204. package/dist/version.d.ts +1 -1
  205. package/dist/version.js +1 -1
  206. package/dist/version.js.map +1 -1
  207. package/dist/workflowClient.d.ts +58 -40
  208. package/dist/workflowClient.js +243 -58
  209. package/dist/workflowClient.js.map +1 -1
  210. package/dist/worktrees/index.d.ts +69 -33
  211. package/dist/worktrees/index.js +3286 -1049
  212. package/dist/worktrees/index.js.map +1 -1
  213. package/package.json +12 -3
  214. package/dist/client-B6aWUUwp.d.ts +0 -2552
package/CHANGELOG.md CHANGED
@@ -5,6 +5,9 @@ All notable changes to `@lucern/sdk` will be documented in this file.
5
5
  ## [Unreleased]
6
6
  - No unreleased changes yet.
7
7
 
8
+ ## [0.3.0-alpha.7] - 2026-05-03
9
+ - Rebuild the coherent Lucern package line after Campaign 1 SDK hardening fixes.
10
+
8
11
  ## [0.2.0-alpha.5] - 2026-04-18
9
12
  - Refresh publish from current stackos source under EK-16 T4.
10
13
  - Version-numbering note: 0.2.0-alpha.2 through 0.2.0-alpha.5 were published from earlier stackos source on 2026-04-12 by pete_c. This release (alpha.5) is the first to ship the current April 18 source — 56 commits of accumulated changes from the code-separation track.
package/README.md CHANGED
@@ -10,6 +10,31 @@ Lucern gives your agents a reasoning graph that accumulates understanding across
10
10
  npm install @lucern/sdk
11
11
  ```
12
12
 
13
+ ## Install Model
14
+
15
+ `@lucern/sdk` is the primary TypeScript app dependency. Installing it also
16
+ installs its internal runtime dependencies, including Lucern contracts and
17
+ reasoning-kernel helpers, but a tenant should still list any `@lucern/*`
18
+ package that its own code or scripts import or execute.
19
+
20
+ Common direct installs:
21
+
22
+ | Need | Install |
23
+ | --- | --- |
24
+ | Programmatic Lucern API calls | `@lucern/sdk` |
25
+ | Tool access checks | `@lucern/access-control` |
26
+ | React hooks/components | `@lucern/react @lucern/sdk` |
27
+ | Convex component binding | `@lucern/identity @lucern/reasoning-kernel` |
28
+ | Bootstrap, auth, doctor, and operator commands | `@lucern/cli` |
29
+ | Agent-facing MCP server/runtime | `@lucern/mcp` |
30
+ | Full design-partner/package-suite pin | all packages from `TENANT_CLIENT_INSTALLABLE_PACKAGES` in `@lucern/contracts` |
31
+
32
+ The difference matters: `@lucern/cli` is a direct install because it provides
33
+ the `lucern` binary, but tenant app source should not import it. The Convex
34
+ component packages are direct installs for `convex.config.ts`, while application
35
+ code should stay on `@lucern/sdk`, `@lucern/react`, `@lucern/mcp`,
36
+ `@lucern/access-control`, `@lucern/contracts`, and `@lucern/types`.
37
+
13
38
  ## Canonical Interface
14
39
 
15
40
  `@lucern/sdk` is the canonical public interface for Lucern.
@@ -301,7 +326,7 @@ await lucern.graph.createEdge({
301
326
  Before your agent starts its next session, it reads the graph:
302
327
 
303
328
  ```typescript
304
- const context = await lucern.context.compile(topicId, {
329
+ const context = await lucern.context.compile({
305
330
  query: "code review strategy and static analysis coverage",
306
331
  ranking: "weighted_v1",
307
332
  tokenBudget: 2000,
@@ -363,6 +388,28 @@ lucern.identity // API keys and sessions
363
388
 
364
389
  The graph doesn't just store knowledge — it analyzes itself.
365
390
 
391
+ ### Query Suite
392
+
393
+ ```typescript
394
+ // Discover the prompt-backed Graph Intelligence recipes tenants can expose in
395
+ // their own UI or model workflows.
396
+ const catalog = await lucern.graphAnalysis.listGraphIntelligenceQueries();
397
+
398
+ // Run a named recipe. Lucern returns the resolved prompt, deterministic graph
399
+ // analysis bundle, sampled graph context, and public tool plan for LLM synthesis.
400
+ const preMortem = await lucern.graphAnalysis.runGraphIntelligenceQuery({
401
+ topicId,
402
+ queryId: "pre-mortem",
403
+ limit: 25,
404
+ });
405
+
406
+ await modelMachine.run({
407
+ prompt: preMortem.data.prompt,
408
+ context: preMortem.data.analysis,
409
+ tools: preMortem.data.toolPlan,
410
+ });
411
+ ```
412
+
366
413
  ### Structural Analysis
367
414
 
368
415
  ```typescript
@@ -445,7 +492,7 @@ traversal.data.nodes.forEach(node => {
445
492
  ### Inject Reasoning Context Into Any LLM Call
446
493
 
447
494
  ```typescript
448
- const context = await lucern.context.compile(topicId, {
495
+ const context = await lucern.context.compile({
449
496
  query: "security review priorities",
450
497
  ranking: "weighted_v1",
451
498
  tokenBudget: 3000,
@@ -556,7 +603,7 @@ architectural decisions, check the reasoning graph:
556
603
 
557
604
  - Read current beliefs: `lucern.beliefs.list({ topicId: "..." })`
558
605
  - Check for contradictions: `lucern.contradictions.list({ topicId: "..." })`
559
- - Compile context before analysis: `lucern.context.compile(topicId, { query: "..." })`
606
+ - Compile context before analysis: `lucern.context.compile({ query: "..." })`
560
607
 
561
608
  After making decisions, write them back:
562
609
  - Create beliefs for architectural decisions
@@ -587,7 +634,7 @@ contradictions, or knowledge state.
587
634
  Compile the current context to understand what the graph knows:
588
635
 
589
636
  \`\`\`typescript
590
- const context = await lucern.context.compile(topicId, {
637
+ const context = await lucern.context.compile({
591
638
  query: "<what you're working on>",
592
639
  tokenBudget: 2000,
593
640
  });
@@ -2,6 +2,8 @@ import { GatewayClientConfig, PlatformGatewaySuccess, GatewayScope } from './cor
2
2
  export { LucernApiError } from './coreClient.js';
3
3
  import { ListResult, JsonObject } from './types.js';
4
4
  import { ControlObjectOwnershipContract } from './controlObjectOwnership.js';
5
+ import './authContext.js';
6
+ import './contracts/auth-session.contract.js';
5
7
  import './contracts/workflow-runtime.contract.js';
6
8
  import './contracts/lens-workflow.contract.js';
7
9
  import './contracts/lens-filter.contract.js';
@@ -151,11 +153,11 @@ declare function createAdminClient(config?: AdminClientConfig): {
151
153
  /**
152
154
  * Get the control-object ownership contract.
153
155
  */
154
- getControlObjectOwnership(): Promise<PlatformGatewaySuccess<ControlObjectOwnershipContract>>;
156
+ getControlObjectOwnership: () => Promise<PlatformGatewaySuccess<ControlObjectOwnershipContract>>;
155
157
  /**
156
158
  * @deprecated Use getControlObjectOwnership.
157
159
  */
158
- getControlObjectOwnershipContract(): Promise<PlatformGatewaySuccess<ControlObjectOwnershipContract>>;
160
+ getControlObjectOwnershipContract: () => Promise<PlatformGatewaySuccess<ControlObjectOwnershipContract>>;
159
161
  /**
160
162
  * List workspaces for the current admin scope.
161
163
  */
@@ -188,33 +190,33 @@ declare function createAdminClient(config?: AdminClientConfig): {
188
190
  /**
189
191
  * Create a membership.
190
192
  */
191
- createMembership(input: GatewayScope & {
193
+ createMembership: (input: GatewayScope & {
192
194
  membershipId?: string;
193
195
  principalId: string;
194
196
  role: "platform_admin" | "tenant_admin" | "workspace_admin" | "editor" | "viewer" | "auditor" | "service_agent";
195
197
  status?: "active" | "invited" | "revoked" | "expired";
196
198
  source?: "bootstrap" | "manual" | "sync" | "sso" | "api" | "scim" | "invitation";
197
- }, idempotencyKey?: string): Promise<PlatformGatewaySuccess<unknown>>;
199
+ }, idempotencyKey?: string) => Promise<PlatformGatewaySuccess<unknown>>;
198
200
  /**
199
201
  * Update a membership.
200
202
  */
201
- updateMembership(input: GatewayScope & {
203
+ updateMembership: (input: GatewayScope & {
202
204
  membershipId?: string;
203
205
  principalId: string;
204
206
  role: "platform_admin" | "tenant_admin" | "workspace_admin" | "editor" | "viewer" | "auditor" | "service_agent";
205
207
  status?: "active" | "invited" | "revoked" | "expired";
206
208
  source?: "bootstrap" | "manual" | "sync" | "sso" | "api" | "scim" | "invitation";
207
- }, idempotencyKey?: string): Promise<PlatformGatewaySuccess<unknown>>;
209
+ }, idempotencyKey?: string) => Promise<PlatformGatewaySuccess<unknown>>;
208
210
  /**
209
211
  * @deprecated Use createMembership or updateMembership.
210
212
  */
211
- upsertMembership(input: GatewayScope & {
213
+ upsertMembership: (input: GatewayScope & {
212
214
  membershipId?: string;
213
215
  principalId: string;
214
216
  role: "platform_admin" | "tenant_admin" | "workspace_admin" | "editor" | "viewer" | "auditor" | "service_agent";
215
217
  status?: "active" | "invited" | "revoked" | "expired";
216
218
  source?: "bootstrap" | "manual" | "sync" | "sso" | "api" | "scim" | "invitation";
217
- }, idempotencyKey?: string): Promise<PlatformGatewaySuccess<unknown>>;
219
+ }, idempotencyKey?: string) => Promise<PlatformGatewaySuccess<unknown>>;
218
220
  /**
219
221
  * List tenant API keys in the current admin scope.
220
222
  */
@@ -1,3 +1,170 @@
1
+ // src/authContext.ts
2
+ var LucernSdkAuthContextError = class extends Error {
3
+ reason;
4
+ constructor(reason, message) {
5
+ super(message);
6
+ this.name = "LucernSdkAuthContextError";
7
+ this.reason = reason;
8
+ }
9
+ };
10
+ function cleanString(value) {
11
+ const normalized = value?.trim();
12
+ return normalized ? normalized : void 0;
13
+ }
14
+ function cleanStringList(values) {
15
+ if (!values) {
16
+ return [];
17
+ }
18
+ return values.map((value) => value.trim()).filter(
19
+ (value, index, list) => value.length > 0 && list.indexOf(value) === index
20
+ );
21
+ }
22
+ function requireString(value, reason, label) {
23
+ const normalized = cleanString(value);
24
+ if (!normalized) {
25
+ throw new LucernSdkAuthContextError(
26
+ reason,
27
+ `Canonical Lucern SDK auth context is missing ${label}.`
28
+ );
29
+ }
30
+ return normalized;
31
+ }
32
+ function requirePrincipalType(principalType) {
33
+ if (!principalType) {
34
+ throw new LucernSdkAuthContextError(
35
+ "principal_missing",
36
+ "Canonical Lucern SDK auth context is missing principalType."
37
+ );
38
+ }
39
+ return principalType;
40
+ }
41
+ function requireAuthMode(authMode) {
42
+ if (!authMode) {
43
+ throw new LucernSdkAuthContextError(
44
+ "principal_missing",
45
+ "Canonical Lucern SDK auth context is missing authMode."
46
+ );
47
+ }
48
+ return authMode;
49
+ }
50
+ function ensurePermitMatch(args) {
51
+ const actual = cleanString(args.actual);
52
+ if (actual && actual !== args.expected) {
53
+ throw new LucernSdkAuthContextError(
54
+ "policy_denied",
55
+ `Canonical Lucern SDK auth context has conflicting Permit ${args.field}.`
56
+ );
57
+ }
58
+ }
59
+ function normalizeCanonicalLucernAuthContext(input) {
60
+ if (!input) {
61
+ throw new LucernSdkAuthContextError(
62
+ "principal_missing",
63
+ "Canonical Lucern SDK auth context is required."
64
+ );
65
+ }
66
+ if (input.policyDecision === "deny") {
67
+ throw new LucernSdkAuthContextError(
68
+ "policy_denied",
69
+ "Canonical Lucern SDK auth context carries a denied policy decision."
70
+ );
71
+ }
72
+ const principalId = requireString(
73
+ input.principalId,
74
+ "principal_missing",
75
+ "principalId"
76
+ );
77
+ const tenantId = requireString(input.tenantId, "tenant_missing", "tenantId");
78
+ const workspaceId = requireString(
79
+ input.workspaceId,
80
+ "workspace_missing",
81
+ "workspaceId"
82
+ );
83
+ const roles = cleanStringList(input.roles);
84
+ const scopes = cleanStringList(input.scopes);
85
+ const principalType = requirePrincipalType(input.principalType);
86
+ const authMode = requireAuthMode(input.authMode);
87
+ const roleBasedInteractiveAuth = authMode === "interactive_user" && roles.length > 0;
88
+ if (roles.length === 0 || scopes.length === 0 && !roleBasedInteractiveAuth) {
89
+ throw new LucernSdkAuthContextError(
90
+ "membership_missing",
91
+ "Canonical Lucern SDK auth context requires non-empty roles and scopes."
92
+ );
93
+ }
94
+ const subject = cleanString(input.permit?.subject) ?? principalId;
95
+ const tenant = cleanString(input.permit?.tenant) ?? tenantId;
96
+ const workspace = cleanString(input.permit?.workspace) ?? workspaceId;
97
+ ensurePermitMatch({
98
+ field: "subject",
99
+ expected: principalId,
100
+ actual: subject
101
+ });
102
+ ensurePermitMatch({ field: "tenant", expected: tenantId, actual: tenant });
103
+ ensurePermitMatch({
104
+ field: "workspace",
105
+ expected: workspaceId,
106
+ actual: workspace
107
+ });
108
+ const context = input.permit?.context ? { ...input.permit.context } : void 0;
109
+ return {
110
+ clerkId: cleanString(input.clerkId),
111
+ principalId,
112
+ tenantId,
113
+ workspaceId,
114
+ principalType,
115
+ authMode,
116
+ roles,
117
+ scopes,
118
+ delegationChain: input.delegationChain ? [...input.delegationChain] : [],
119
+ policyTraceId: cleanString(input.policyTraceId),
120
+ correlationId: cleanString(input.correlationId),
121
+ membershipId: cleanString(input.membershipId),
122
+ permit: {
123
+ subject,
124
+ tenant,
125
+ workspace,
126
+ resource: cleanString(input.permit?.resource),
127
+ action: cleanString(input.permit?.action),
128
+ relation: cleanString(input.permit?.relation),
129
+ context
130
+ }
131
+ };
132
+ }
133
+ function createCanonicalAuthHeaders(authContext) {
134
+ const headers = {
135
+ "x-lucern-principal-id": authContext.principalId,
136
+ "x-lucern-principal-type": authContext.principalType,
137
+ "x-lucern-tenant": authContext.tenantId,
138
+ "x-lucern-tenant-id": authContext.tenantId,
139
+ "x-lucern-workspace": authContext.workspaceId,
140
+ "x-lucern-workspace-id": authContext.workspaceId,
141
+ "x-lucern-auth-mode": authContext.authMode,
142
+ "x-lucern-roles": authContext.roles.join(","),
143
+ "x-lucern-scopes": authContext.scopes.join(","),
144
+ "x-lucern-permit-context": JSON.stringify(authContext.permit)
145
+ };
146
+ if (authContext.clerkId) {
147
+ headers["x-lucern-clerk-id"] = authContext.clerkId;
148
+ headers["x-lucern-user-id"] = authContext.clerkId;
149
+ }
150
+ if (authContext.delegationChain.length > 0) {
151
+ headers["x-lucern-delegation-chain"] = JSON.stringify(
152
+ authContext.delegationChain
153
+ );
154
+ }
155
+ if (authContext.policyTraceId) {
156
+ headers["x-lucern-policy-trace-id"] = authContext.policyTraceId;
157
+ }
158
+ if (authContext.correlationId) {
159
+ headers["x-correlation-id"] = authContext.correlationId;
160
+ headers["x-lucern-correlation-id"] = authContext.correlationId;
161
+ }
162
+ if (authContext.membershipId) {
163
+ headers["x-lucern-membership-id"] = authContext.membershipId;
164
+ }
165
+ return headers;
166
+ }
167
+
1
168
  // src/coreClient.ts
2
169
  var LucernApiError = class extends Error {
3
170
  code;
@@ -65,9 +232,7 @@ function generatePortableRequestId() {
65
232
  8
66
233
  ).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10).join("")}`;
67
234
  }
68
- function randomIdempotencyKey() {
69
- return generatePortableRequestId();
70
- }
235
+ var randomIdempotencyKey = generatePortableRequestId;
71
236
  function isRetryableStatus(status) {
72
237
  return status >= 500 || status === 408 || status === 429;
73
238
  }
@@ -132,8 +297,11 @@ function timeoutError(timeoutMs) {
132
297
  error.name = "AbortError";
133
298
  return error;
134
299
  }
300
+ function isRecord(value) {
301
+ return value !== null && typeof value === "object" && !Array.isArray(value);
302
+ }
135
303
  function readPolicySummaryFromDetails(details) {
136
- if (!details || typeof details !== "object" || Array.isArray(details)) {
304
+ if (!isRecord(details)) {
137
305
  return null;
138
306
  }
139
307
  const directSummary = details.summary;
@@ -141,11 +309,11 @@ function readPolicySummaryFromDetails(details) {
141
309
  return directSummary.trim();
142
310
  }
143
311
  const policy = details.policy;
144
- if (!policy || typeof policy !== "object" || Array.isArray(policy)) {
312
+ if (!isRecord(policy)) {
145
313
  return null;
146
314
  }
147
315
  const explanation = policy.explanation;
148
- if (!explanation || typeof explanation !== "object" || Array.isArray(explanation)) {
316
+ if (!isRecord(explanation)) {
149
317
  return null;
150
318
  }
151
319
  const nestedSummary = explanation.summary;
@@ -154,16 +322,41 @@ function readPolicySummaryFromDetails(details) {
154
322
  }
155
323
  return null;
156
324
  }
325
+ async function resolveConfiguredAuthContext(authContext) {
326
+ if (typeof authContext === "function") {
327
+ return await authContext();
328
+ }
329
+ return authContext;
330
+ }
331
+ function mergeHeaderRecord(base, addition) {
332
+ const headers = new Headers(base);
333
+ for (const [key, value] of Object.entries(addition)) {
334
+ const existing = headers.get(key);
335
+ if (existing !== null && existing !== value) {
336
+ throw new LucernSdkAuthContextError(
337
+ "policy_denied",
338
+ `Canonical Lucern SDK auth context conflicts with existing ${key} header.`
339
+ );
340
+ }
341
+ headers.set(key, value);
342
+ }
343
+ return Object.fromEntries(headers.entries());
344
+ }
157
345
  function createGatewayRequestClient(config = {}) {
158
346
  const fetchImpl = config.fetchImpl ?? fetch;
159
347
  const baseUrl = config.baseUrl?.replace(/\/+$/, "") ?? "";
160
348
  const maxRetries = config.maxRetries ?? 2;
161
349
  const requestIdFactory = config.requestIdFactory ?? (() => generatePortableRequestId());
162
350
  async function resolveAuthHeaders() {
163
- if (!config.getAuthHeaders) {
164
- return {};
351
+ const base = config.getAuthHeaders ? await config.getAuthHeaders() : {};
352
+ const authContextInput = await resolveConfiguredAuthContext(
353
+ config.authContext
354
+ );
355
+ if (!authContextInput && !config.requireCanonicalAuthContext) {
356
+ return base;
165
357
  }
166
- return await config.getAuthHeaders();
358
+ const authContext = normalizeCanonicalLucernAuthContext(authContextInput);
359
+ return mergeHeaderRecord(base, createCanonicalAuthHeaders(authContext));
167
360
  }
168
361
  async function fetchWithTimeout(url, init, timeoutMs) {
169
362
  const controller = new AbortController();
@@ -184,11 +377,11 @@ function createGatewayRequestClient(config = {}) {
184
377
  if (!text) {
185
378
  return null;
186
379
  }
187
- try {
188
- return JSON.parse(text);
189
- } catch {
380
+ const parsed = tryParseGatewayEnvelopeJson(text);
381
+ if (!parsed.ok) {
190
382
  return null;
191
383
  }
384
+ return isRecord(parsed.value) ? parsed.value : null;
192
385
  }
193
386
  function resolveTimeoutMs(method, requestTimeoutMs) {
194
387
  if (typeof requestTimeoutMs === "number") {
@@ -200,16 +393,31 @@ function createGatewayRequestClient(config = {}) {
200
393
  }
201
394
  return config.timeoutMs ?? 15e3;
202
395
  }
396
+ function tryParseGatewayEnvelopeJson(text) {
397
+ const trimmed = text.trim();
398
+ if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) {
399
+ return { ok: false, reason: "non-json" };
400
+ }
401
+ try {
402
+ return { ok: true, value: JSON.parse(trimmed) };
403
+ } catch (error) {
404
+ if (error instanceof SyntaxError) {
405
+ return { ok: false, reason: "invalid-json", error };
406
+ }
407
+ throw error;
408
+ }
409
+ }
203
410
  function buildApiError(args) {
204
411
  const failure = args.failure;
205
- const legacyError = failure && typeof failure.error === "object" && failure.error !== null ? failure.error : failure?.legacyError;
412
+ const legacyError = failure && isRecord(failure.error) ? failure.error : failure?.legacyError;
206
413
  const correlationId = failure?.correlationId ?? args.response.headers.get("x-lucern-correlation-id")?.trim() ?? args.requestId;
207
414
  const policyTraceId = failure?.policyTraceId ?? args.response.headers.get("x-lucern-policy-trace-id")?.trim() ?? null;
208
415
  const details = failure?.details ?? legacyError?.details;
209
416
  const policySummary = readPolicySummaryFromDetails(details);
417
+ const failureMessage = typeof failure?.error === "string" ? failure.error : legacyError?.message;
210
418
  return new LucernApiError({
211
419
  code: failure?.code ?? legacyError?.code ?? fallbackErrorCode(args.response.status),
212
- message: policySummary ?? (typeof failure?.error === "string" ? failure.error : legacyError?.message ?? (args.response.ok ? "Platform API returned an invalid success payload." : "Platform API request failed.")),
420
+ message: policySummary ?? failureMessage ?? (args.response.ok ? "Platform API returned an invalid success payload." : "Platform API request failed."),
213
421
  status: args.response.status,
214
422
  invariant: failure?.invariant,
215
423
  suggestion: failure?.suggestion,
@@ -341,7 +549,10 @@ function createListResult(items, legacyKey) {
341
549
  total: items.length
342
550
  };
343
551
  if (legacyKey) {
344
- result[legacyKey] = items;
552
+ return {
553
+ ...result,
554
+ [legacyKey]: items
555
+ };
345
556
  }
346
557
  return result;
347
558
  }
@@ -379,6 +590,17 @@ function asTenantVaultSecretArray(data) {
379
590
  }
380
591
  function createAdminClient(config = {}) {
381
592
  const gateway = createGatewayRequestClient(config);
593
+ const getControlObjectOwnership = async () => gateway.request({
594
+ path: "/api/platform/v1/admin/control-ownership"
595
+ });
596
+ const createMembership = async (input, idempotencyKey) => gateway.request({
597
+ path: "/api/platform/v1/memberships",
598
+ method: "POST",
599
+ body: input,
600
+ idempotencyKey: idempotencyKey ?? randomIdempotencyKey()
601
+ });
602
+ const updateMembership = createMembership;
603
+ const upsertMembership = createMembership;
382
604
  return {
383
605
  /**
384
606
  * List tenants visible to the current principal.
@@ -410,19 +632,11 @@ function createAdminClient(config = {}) {
410
632
  /**
411
633
  * Get the control-object ownership contract.
412
634
  */
413
- async getControlObjectOwnership() {
414
- return gateway.request({
415
- path: "/api/platform/v1/admin/control-ownership"
416
- });
417
- },
635
+ getControlObjectOwnership,
418
636
  /**
419
637
  * @deprecated Use getControlObjectOwnership.
420
638
  */
421
- async getControlObjectOwnershipContract() {
422
- return gateway.request({
423
- path: "/api/platform/v1/admin/control-ownership"
424
- });
425
- },
639
+ getControlObjectOwnershipContract: getControlObjectOwnership,
426
640
  /**
427
641
  * List workspaces for the current admin scope.
428
642
  */
@@ -469,26 +683,15 @@ function createAdminClient(config = {}) {
469
683
  /**
470
684
  * Create a membership.
471
685
  */
472
- async createMembership(input, idempotencyKey) {
473
- return gateway.request({
474
- path: "/api/platform/v1/memberships",
475
- method: "POST",
476
- body: input,
477
- idempotencyKey: idempotencyKey ?? randomIdempotencyKey()
478
- });
479
- },
686
+ createMembership,
480
687
  /**
481
688
  * Update a membership.
482
689
  */
483
- async updateMembership(input, idempotencyKey) {
484
- return this.createMembership(input, idempotencyKey);
485
- },
690
+ updateMembership,
486
691
  /**
487
692
  * @deprecated Use createMembership or updateMembership.
488
693
  */
489
- async upsertMembership(input, idempotencyKey) {
490
- return this.createMembership(input, idempotencyKey);
491
- },
694
+ upsertMembership,
492
695
  /**
493
696
  * List tenant API keys in the current admin scope.
494
697
  */