@oatscenter/trellis 0.100.0-rc.1

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 (264) hide show
  1. package/README.md +59 -0
  2. package/auth/authorization/client_context.d.ts +61 -0
  3. package/auth/authorization/client_context.js +266 -0
  4. package/auth/authorization/nats_registry.d.ts +41 -0
  5. package/auth/authorization/nats_registry.js +283 -0
  6. package/auth/authorization/provider_cache.d.ts +90 -0
  7. package/auth/authorization/provider_cache.js +783 -0
  8. package/auth/authorization/refresh.d.ts +46 -0
  9. package/auth/authorization/refresh.js +246 -0
  10. package/auth/authorization/types.d.ts +207 -0
  11. package/auth/authorization/types.js +60 -0
  12. package/auth/authorization_context.d.ts +11 -0
  13. package/auth/authorization_context.js +10 -0
  14. package/auth/browser/flow_types.d.ts +84 -0
  15. package/auth/browser/flow_types.js +70 -0
  16. package/auth/browser/portal.d.ts +21 -0
  17. package/auth/browser/portal.js +307 -0
  18. package/auth/browser/storage.d.ts +26 -0
  19. package/auth/browser/storage.js +224 -0
  20. package/auth/browser.d.ts +11 -0
  21. package/auth/browser.js +10 -0
  22. package/auth/browser_recovery.d.ts +13 -0
  23. package/auth/browser_recovery.js +38 -0
  24. package/auth/device_activation.d.ts +134 -0
  25. package/auth/device_activation.js +376 -0
  26. package/auth/http_error.d.ts +12 -0
  27. package/auth/http_error.js +32 -0
  28. package/auth/keys.d.ts +5 -0
  29. package/auth/keys.js +63 -0
  30. package/auth/mod.d.ts +16 -0
  31. package/auth/mod.js +16 -0
  32. package/auth/proof.d.ts +31 -0
  33. package/auth/proof.js +95 -0
  34. package/auth/protocol_wasm/trellis_protocol_wasm.d.ts +138 -0
  35. package/auth/protocol_wasm/trellis_protocol_wasm.js +605 -0
  36. package/auth/protocol_wasm/trellis_protocol_wasm_bg.wasm +0 -0
  37. package/auth/protocol_wasm/trellis_protocol_wasm_bytes.d.ts +1 -0
  38. package/auth/protocol_wasm/trellis_protocol_wasm_bytes.js +2 -0
  39. package/auth/protocol_wasm.d.ts +179 -0
  40. package/auth/protocol_wasm.js +133 -0
  41. package/auth/session_auth.d.ts +30 -0
  42. package/auth/session_auth.js +77 -0
  43. package/auth/session_proof.d.ts +53 -0
  44. package/auth/session_proof.js +43 -0
  45. package/auth/time.d.ts +6 -0
  46. package/auth/time.js +7 -0
  47. package/auth/trellis_id.d.ts +1 -0
  48. package/auth/trellis_id.js +5 -0
  49. package/auth/utils.d.ts +10 -0
  50. package/auth/utils.js +69 -0
  51. package/auth.d.ts +1 -0
  52. package/auth.js +1 -0
  53. package/caller.d.ts +111 -0
  54. package/caller.js +85 -0
  55. package/client.d.ts +14 -0
  56. package/client.js +1 -0
  57. package/client_connect.d.ts +143 -0
  58. package/client_connect.js +1097 -0
  59. package/codec.d.ts +13 -0
  60. package/codec.js +192 -0
  61. package/connection.d.ts +107 -0
  62. package/connection.js +396 -0
  63. package/device/activation.d.ts +42 -0
  64. package/device/activation.js +319 -0
  65. package/device.d.ts +80 -0
  66. package/device.js +687 -0
  67. package/env.d.ts +2 -0
  68. package/env.js +10 -0
  69. package/errors/AuthError.d.ts +30 -0
  70. package/errors/AuthError.js +34 -0
  71. package/errors/KVError.d.ts +30 -0
  72. package/errors/KVError.js +36 -0
  73. package/errors/OperationLifecycleError.d.ts +110 -0
  74. package/errors/OperationLifecycleError.js +142 -0
  75. package/errors/RemoteError.d.ts +61 -0
  76. package/errors/RemoteError.js +72 -0
  77. package/errors/SchemaValidationError.d.ts +48 -0
  78. package/errors/SchemaValidationError.js +49 -0
  79. package/errors/StoreError.d.ts +21 -0
  80. package/errors/StoreError.js +31 -0
  81. package/errors/TransferError.d.ts +21 -0
  82. package/errors/TransferError.js +31 -0
  83. package/errors/TransportError.d.ts +29 -0
  84. package/errors/TransportError.js +33 -0
  85. package/errors/TrellisError.d.ts +15 -0
  86. package/errors/TrellisError.js +15 -0
  87. package/errors/ValidationError.d.ts +50 -0
  88. package/errors/ValidationError.js +59 -0
  89. package/errors/index.d.ts +254 -0
  90. package/errors/index.js +238 -0
  91. package/generated.d.ts +4 -0
  92. package/generated.js +3 -0
  93. package/generated_support.d.ts +120 -0
  94. package/generated_support.js +359 -0
  95. package/globals.d.ts +9 -0
  96. package/globals.js +16 -0
  97. package/health_transport.d.ts +18 -0
  98. package/health_transport.js +32 -0
  99. package/helpers.d.ts +11 -0
  100. package/helpers.js +53 -0
  101. package/index.d.ts +2 -0
  102. package/index.js +2 -0
  103. package/internal_sdk/generated/apis/auth/mod.d.ts +805 -0
  104. package/internal_sdk/generated/apis/auth/mod.js +958 -0
  105. package/internal_sdk/generated/apis/core/mod.d.ts +79 -0
  106. package/internal_sdk/generated/apis/core/mod.js +93 -0
  107. package/internal_sdk/generated/apis/events/mod.d.ts +224 -0
  108. package/internal_sdk/generated/apis/events/mod.js +313 -0
  109. package/internal_sdk/generated/apis/health/mod.d.ts +106 -0
  110. package/internal_sdk/generated/apis/health/mod.js +132 -0
  111. package/internal_sdk/generated/apis/index.d.ts +7 -0
  112. package/internal_sdk/generated/apis/index.js +8 -0
  113. package/internal_sdk/generated/apis/jobs/mod.d.ts +176 -0
  114. package/internal_sdk/generated/apis/jobs/mod.js +209 -0
  115. package/internal_sdk/generated/apis/state/mod.d.ts +104 -0
  116. package/internal_sdk/generated/apis/state/mod.js +139 -0
  117. package/internal_sdk/generated/index.d.ts +4 -0
  118. package/internal_sdk/generated/index.js +5 -0
  119. package/internal_sdk/generated/package.json +18 -0
  120. package/internal_sdk/generated/participants/cli/mod.d.ts +402 -0
  121. package/internal_sdk/generated/participants/cli/mod.js +460 -0
  122. package/internal_sdk/generated/participants/cli/types.d.ts +2 -0
  123. package/internal_sdk/generated/participants/cli/types.js +3 -0
  124. package/internal_sdk/generated/participants/console/mod.d.ts +489 -0
  125. package/internal_sdk/generated/participants/console/mod.js +579 -0
  126. package/internal_sdk/generated/participants/console/types.d.ts +2 -0
  127. package/internal_sdk/generated/participants/console/types.js +3 -0
  128. package/internal_sdk/generated/participants/eventsRuntime/mod.d.ts +64 -0
  129. package/internal_sdk/generated/participants/eventsRuntime/mod.js +42 -0
  130. package/internal_sdk/generated/participants/eventsRuntime/types.d.ts +2 -0
  131. package/internal_sdk/generated/participants/eventsRuntime/types.js +3 -0
  132. package/internal_sdk/generated/participants/healthRuntime/mod.d.ts +58 -0
  133. package/internal_sdk/generated/participants/healthRuntime/mod.js +36 -0
  134. package/internal_sdk/generated/participants/healthRuntime/types.d.ts +2 -0
  135. package/internal_sdk/generated/participants/healthRuntime/types.js +3 -0
  136. package/internal_sdk/generated/participants/index.d.ts +8 -0
  137. package/internal_sdk/generated/participants/index.js +9 -0
  138. package/internal_sdk/generated/participants/jobsRuntime/mod.d.ts +64 -0
  139. package/internal_sdk/generated/participants/jobsRuntime/mod.js +42 -0
  140. package/internal_sdk/generated/participants/jobsRuntime/types.d.ts +2 -0
  141. package/internal_sdk/generated/participants/jobsRuntime/types.js +3 -0
  142. package/internal_sdk/generated/participants/platform/mod.d.ts +164 -0
  143. package/internal_sdk/generated/participants/platform/mod.js +149 -0
  144. package/internal_sdk/generated/participants/platform/types.d.ts +7 -0
  145. package/internal_sdk/generated/participants/platform/types.js +5 -0
  146. package/internal_sdk/generated/participants/portal/mod.d.ts +131 -0
  147. package/internal_sdk/generated/participants/portal/mod.js +109 -0
  148. package/internal_sdk/generated/participants/portal/types.d.ts +2 -0
  149. package/internal_sdk/generated/participants/portal/types.js +3 -0
  150. package/internal_sdk/generated/types/_internal/p0.d.ts +13511 -0
  151. package/internal_sdk/generated/types/_internal/p0.js +6105 -0
  152. package/internal_sdk/generated/types/index.d.ts +2951 -0
  153. package/internal_sdk/generated/types/index.js +1477 -0
  154. package/jobs.d.ts +309 -0
  155. package/jobs.js +389 -0
  156. package/kv.d.ts +85 -0
  157. package/kv.js +330 -0
  158. package/operations.d.ts +189 -0
  159. package/operations.js +847 -0
  160. package/package.json +73 -0
  161. package/pagination.d.ts +25 -0
  162. package/pagination.js +117 -0
  163. package/participant.d.ts +6 -0
  164. package/participant.js +6 -0
  165. package/participant_runtime/api.d.ts +131 -0
  166. package/participant_runtime/api.js +42 -0
  167. package/participant_runtime/json.d.ts +16 -0
  168. package/participant_runtime/json.js +193 -0
  169. package/participant_runtime/metadata.d.ts +34 -0
  170. package/participant_runtime/metadata.js +4 -0
  171. package/participant_runtime/participant.d.ts +200 -0
  172. package/participant_runtime/participant.js +330 -0
  173. package/participant_runtime/schemas.d.ts +347 -0
  174. package/participant_runtime/schemas.js +211 -0
  175. package/participant_runtime/surface_names.d.ts +16 -0
  176. package/participant_runtime/surface_names.js +34 -0
  177. package/portable.d.ts +30 -0
  178. package/portable.js +14 -0
  179. package/provider.d.ts +69 -0
  180. package/provider.js +68 -0
  181. package/runtime_transport.d.ts +25 -0
  182. package/runtime_transport.js +48 -0
  183. package/service/mod.d.ts +14 -0
  184. package/service/mod.js +13 -0
  185. package/service/outbox_inbox.d.ts +259 -0
  186. package/service/outbox_inbox.js +908 -0
  187. package/service/runtime/bootstrap.d.ts +56 -0
  188. package/service/runtime/bootstrap.js +226 -0
  189. package/service/runtime/core.d.ts +46 -0
  190. package/service/runtime/core.js +1747 -0
  191. package/service/runtime/health.d.ts +97 -0
  192. package/service/runtime/health.js +153 -0
  193. package/service/runtime/health_schemas.d.ts +23 -0
  194. package/service/runtime/health_schemas.js +20 -0
  195. package/service/runtime/internal_jobs/active-job.d.ts +40 -0
  196. package/service/runtime/internal_jobs/active-job.js +91 -0
  197. package/service/runtime/internal_jobs/bindings.d.ts +40 -0
  198. package/service/runtime/internal_jobs/bindings.js +1 -0
  199. package/service/runtime/internal_jobs/cancellation-registry.d.ts +13 -0
  200. package/service/runtime/internal_jobs/cancellation-registry.js +55 -0
  201. package/service/runtime/internal_jobs/heartbeat.d.ts +33 -0
  202. package/service/runtime/internal_jobs/heartbeat.js +65 -0
  203. package/service/runtime/internal_jobs/job-manager.d.ts +126 -0
  204. package/service/runtime/internal_jobs/job-manager.js +821 -0
  205. package/service/runtime/internal_jobs/key-coordinator.d.ts +280 -0
  206. package/service/runtime/internal_jobs/key-coordinator.js +747 -0
  207. package/service/runtime/internal_jobs/projection.d.ts +3 -0
  208. package/service/runtime/internal_jobs/projection.js +42 -0
  209. package/service/runtime/internal_jobs/runtime-worker.d.ts +126 -0
  210. package/service/runtime/internal_jobs/runtime-worker.js +454 -0
  211. package/service/runtime/internal_jobs/types.d.ts +246 -0
  212. package/service/runtime/internal_jobs/types.js +163 -0
  213. package/service/runtime/logger.d.ts +2 -0
  214. package/service/runtime/logger.js +7 -0
  215. package/service/runtime/runtime.d.ts +16 -0
  216. package/service/runtime/runtime.js +1 -0
  217. package/service/runtime/service.d.ts +372 -0
  218. package/service/runtime/service.js +1896 -0
  219. package/service/runtime/transfer/download.d.ts +27 -0
  220. package/service/runtime/transfer/download.js +1 -0
  221. package/service/runtime/transfer/protocol.d.ts +15 -0
  222. package/service/runtime/transfer/protocol.js +46 -0
  223. package/service/runtime/transfer/queue.d.ts +18 -0
  224. package/service/runtime/transfer/queue.js +136 -0
  225. package/service/runtime/transfer/upload.d.ts +40 -0
  226. package/service/runtime/transfer/upload.js +27 -0
  227. package/service/runtime/transfer.d.ts +62 -0
  228. package/service/runtime/transfer.js +763 -0
  229. package/session.d.ts +862 -0
  230. package/session.js +3407 -0
  231. package/store.d.ts +71 -0
  232. package/store.js +412 -0
  233. package/store_entry.d.ts +20 -0
  234. package/store_entry.js +75 -0
  235. package/tasks.d.ts +10 -0
  236. package/tasks.js +28 -0
  237. package/telemetry/carrier.d.ts +8 -0
  238. package/telemetry/carrier.js +20 -0
  239. package/telemetry/core.d.ts +7 -0
  240. package/telemetry/core.js +14 -0
  241. package/telemetry/env.d.ts +2 -0
  242. package/telemetry/env.js +10 -0
  243. package/telemetry/init.d.ts +2 -0
  244. package/telemetry/init.js +7 -0
  245. package/telemetry/metrics.d.ts +81 -0
  246. package/telemetry/metrics.js +267 -0
  247. package/telemetry/mod.d.ts +13 -0
  248. package/telemetry/mod.js +8 -0
  249. package/telemetry/nats.d.ts +6 -0
  250. package/telemetry/nats.js +6 -0
  251. package/telemetry/result.d.ts +1 -0
  252. package/telemetry/result.js +18 -0
  253. package/telemetry/runtime.d.ts +1 -0
  254. package/telemetry/runtime.js +141 -0
  255. package/telemetry/trace.d.ts +4 -0
  256. package/telemetry/trace.js +26 -0
  257. package/telemetry/trellis.d.ts +1 -0
  258. package/telemetry/trellis.js +1 -0
  259. package/telemetry.d.ts +1 -0
  260. package/telemetry.js +1 -0
  261. package/transfer.d.ts +112 -0
  262. package/transfer.js +525 -0
  263. package/transfer_protocol.d.ts +1 -0
  264. package/transfer_protocol.js +13 -0
package/README.md ADDED
@@ -0,0 +1,59 @@
1
+ # @oatscenter/trellis
2
+
3
+ JavaScript Trellis client runtime. Provides generated-participant client helpers
4
+ and runtime error types.
5
+
6
+ The npm package contains ESM JavaScript and TypeScript declarations. Use
7
+ `import`; CommonJS output and `require()` support have intentionally been
8
+ removed. Node and Deno adapters remain available as ESM subpaths. JSR
9
+ publication remains supported.
10
+
11
+ For AI-agent context, start with the generated package `TRELLIS.md` files and
12
+ the raw docs index:
13
+
14
+ - https://raw.githubusercontent.com/oats-center/trellis/main/docs/static/llms.txt
15
+ - https://raw.githubusercontent.com/oats-center/trellis/main/docs/static/llms-full.txt
16
+
17
+ ```typescript
18
+ import { TrellisClient } from "@oatscenter/trellis";
19
+ import { participants } from "example-trellis";
20
+
21
+ const client = await TrellisClient.connect({
22
+ trellisUrl: "https://trellis.example.com",
23
+ participant: participants.exampleApp.participant,
24
+ }).orThrow();
25
+ ```
26
+
27
+ The local package name comes from `trellis.toml`. Generation emits one ordinary
28
+ ESM package with `apis` and `participants` namespaces, executable JavaScript and
29
+ declarations, and the matching published runtime dependency. Commit that package
30
+ when ordinary builds should not require the Trellis CLI or API cache.
31
+
32
+ Connected API facades group actions by surface: `.rpc.<group>.<leaf>(input)`,
33
+ `.event.<group>.<leaf>.listen(handler)` or `.publish(event)`,
34
+ `.feed.<group>.<leaf>(input)`, and `.operation.<group>.<leaf>.start(input)`.
35
+ Inspect generated declarations for the exact selected APIs and action names. Do
36
+ not reconstruct transport subjects or use handwritten contract metadata.
37
+
38
+ Prepared events support durable publish flows. `prepare(...)` returns a
39
+ `PreparedTrellisEvent`; services can persist prepared events in SQL or NATS KV
40
+ outbox repositories and later publish them with `client.publishPrepared(...)`,
41
+ dispatch them with `dispatchOutbox`, or run an `OutboxDispatcher` and call
42
+ `notify()` after an outbox transaction commits.
43
+
44
+ Durable service event consumption is contract-declared. Add an event consumer
45
+ group to the service contract and call the generated listener with
46
+ `{ group: "groupName" }`. Do not pass `durableName`; Trellis provisions the
47
+ physical JetStream consumer and grants only the bound consumer subjects to the
48
+ service token. Use `{ mode: "ephemeral", replay: "new" }` for live-only
49
+ listeners.
50
+
51
+ Service connection helpers live in `@oatscenter/trellis/service*` to keep the
52
+ root package browser-safe. Browser login and portal-flow helpers live on
53
+ `@oatscenter/trellis/auth` and `@oatscenter/trellis/auth/browser`.
54
+
55
+ Service authors should not use the core package to recreate service bootstrap or
56
+ fetch resource bindings. Connect with `TrellisService.connect(...)` from
57
+ `@oatscenter/trellis/service` and use the returned resource handles instead of
58
+ calling `Trellis.Bindings.Get`, constructing `TrellisService` or `StoreHandle`,
59
+ or passing binding/resource data into `Trellis` constructors.
@@ -0,0 +1,61 @@
1
+ import type { AuthorizationContextVerificationPolicy } from "../protocol_wasm.ts";
2
+ import type { AuthorizationContextBundle, AuthorizationContextVerificationMaterial, AuthorizationRoutingMaterial, AuthorizationRuntimeBinding, VerifiedAuthorizationContext } from "./types.ts";
3
+ /** Verifies and exposes the current in-memory authorization context. */
4
+ export declare class AuthorizationContextCache {
5
+ #private;
6
+ readonly trellisUrl: string;
7
+ readonly fetch: typeof globalThis.fetch;
8
+ readonly now: () => number;
9
+ constructor(trellisUrl: string, fetch?: typeof globalThis.fetch, now?: () => number);
10
+ install(bundle: AuthorizationContextBundle, routing: AuthorizationRoutingMaterial, nowUnixSeconds?: number, shouldInstall?: () => boolean, runtime?: AuthorizationRuntimeBinding, installAdditional?: (verified: VerifiedAuthorizationContext) => void | (() => void) | Promise<void | (() => void)>): Promise<VerifiedAuthorizationContext>;
11
+ /** Verify and retain one private refresh candidate without exposing it to application use. */
12
+ prepare(bundle: AuthorizationContextBundle, routing: AuthorizationRoutingMaterial, nowUnixSeconds?: number, shouldInstall?: () => boolean, runtime?: AuthorizationRuntimeBinding, installAdditional?: (verified: VerifiedAuthorizationContext) => void | (() => void) | Promise<void | (() => void)>): Promise<VerifiedAuthorizationContext>;
13
+ /** Promote only the exact prepared candidate after transport admission and own coverage. */
14
+ promote(expectedDigest: string, shouldInstall?: () => boolean): VerifiedAuthorizationContext;
15
+ /** Return the installed context identity without time or usability checks. */
16
+ storedContextDigest(): string | undefined;
17
+ /** Drop a private candidate that became unusable before promotion. */
18
+ invalidateCandidate(digest: string): boolean;
19
+ /** Return the verified candidate used only for transport reauthorization. */
20
+ transportCurrent(): VerifiedAuthorizationContext;
21
+ hasCandidate(): boolean;
22
+ transportRuntimeBinding(): AuthorizationRuntimeBinding;
23
+ transportRoutingJwt(): string;
24
+ /** Returns the number of successfully installed authorization contexts. */
25
+ generation(): number;
26
+ current(nowUnixSeconds?: number): VerifiedAuthorizationContext;
27
+ bundle(): AuthorizationContextBundle;
28
+ /** Return the current compact verifier policy without cloning the context bundle. */
29
+ verificationPolicy(nowUnixSeconds?: number): AuthorizationContextVerificationPolicy;
30
+ shouldRefresh(nowUnixSeconds?: number): boolean;
31
+ clear(): Promise<void>;
32
+ /** Capture the exact material owned by an in-flight refresh. */
33
+ clearGuard(): readonly [string | null, string | null, number];
34
+ /** Clear terminal state only if no newer context or route JWT replaced it. */
35
+ clearIfCurrent(guard: readonly [string | null, string | null, number]): Promise<boolean>;
36
+ /** Return reconnect metadata retained with the signed context. */
37
+ runtimeBinding(): AuthorizationRuntimeBinding;
38
+ routingJwt(): string;
39
+ routingRefreshAt(): number;
40
+ setServerClockOffsetMs(offsetMs: number): void;
41
+ serverClockOffsetMs(): number;
42
+ correctedNowSeconds(): number;
43
+ nowMilliseconds(): number;
44
+ /**
45
+ * Return the installed chain material for a provider-side local verifier.
46
+ *
47
+ * This is an in-process handoff; it performs no registry I/O.
48
+ */
49
+ installedVerificationMaterial(): AuthorizationContextVerificationMaterial;
50
+ /** Register the single existing refresh task wake callback. */
51
+ registerRefreshRequest(callback: () => void): () => void;
52
+ /** Wake the existing refresh task after trust-floor advance. */
53
+ requestRefresh(): void;
54
+ }
55
+ /** Build the exact policy passed to the Rust/WASM verifier. */
56
+ export declare function authorizationContextVerificationPolicy(policy: AuthorizationContextBundle["policy"], nowUnixSeconds: number): AuthorizationContextVerificationPolicy;
57
+ /** Verify a complete authorization context chain through Rust/WASM. */
58
+ export declare function verifyAuthorizationContext(args: {
59
+ bundle: AuthorizationContextBundle;
60
+ policy: AuthorizationContextVerificationPolicy;
61
+ }): Promise<VerifiedAuthorizationContext>;
@@ -0,0 +1,266 @@
1
+ /** Verifies and exposes the current in-memory authorization context. */
2
+ export class AuthorizationContextCache {
3
+ trellisUrl;
4
+ fetch;
5
+ now;
6
+ #bundle;
7
+ #verified;
8
+ #runtime;
9
+ #routing;
10
+ #clockOffsetMs = 0;
11
+ #operation = 0;
12
+ #generation = 0;
13
+ #refreshRequest;
14
+ #refreshRequestPending = false;
15
+ #candidate;
16
+ constructor(trellisUrl, fetch = globalThis.fetch, now = Date.now) {
17
+ this.trellisUrl = trellisUrl;
18
+ this.fetch = fetch;
19
+ this.now = now;
20
+ }
21
+ async install(bundle, routing, nowUnixSeconds = this.correctedNowSeconds(), shouldInstall = () => true, runtime, installAdditional = () => { }) {
22
+ const verified = await this.prepare(bundle, routing, nowUnixSeconds, shouldInstall, runtime, installAdditional);
23
+ return this.promote(verified.contextDigest, shouldInstall);
24
+ }
25
+ /** Verify and retain one private refresh candidate without exposing it to application use. */
26
+ async prepare(bundle, routing, nowUnixSeconds = this.correctedNowSeconds(), shouldInstall = () => true, runtime, installAdditional = () => { }) {
27
+ const operation = ++this.#operation;
28
+ const verificationPolicy = authorizationContextVerificationPolicy(bundle.policy, nowUnixSeconds);
29
+ const verified = await verifyAuthorizationContext({
30
+ bundle,
31
+ policy: verificationPolicy,
32
+ });
33
+ const nextRuntime = runtime ?? this.#runtime;
34
+ if (nextRuntime &&
35
+ (nextRuntime.connectionId !== verified.context.connectionId ||
36
+ nextRuntime.loginSessionId !== verified.context.loginSessionId ||
37
+ nextRuntime.participantId !== verified.context.participantId ||
38
+ nextRuntime.inboxPrefix !== verified.context.inboxPrefix ||
39
+ !Object.values(nextRuntime.transports).some((transport) => transport.natsServers.length > 0))) {
40
+ throw new Error("authorization runtime binding does not match signed context");
41
+ }
42
+ if (!shouldInstall() || operation !== this.#operation) {
43
+ throw new Error("authorization context installation stopped");
44
+ }
45
+ const nextBundle = structuredClone(bundle);
46
+ const installedRuntime = nextRuntime
47
+ ? structuredClone(nextRuntime)
48
+ : undefined;
49
+ const nextRouting = structuredClone(routing);
50
+ const commitAdditional = await installAdditional(verified);
51
+ if (!shouldInstall() || operation !== this.#operation) {
52
+ throw new Error("authorization context installation stopped");
53
+ }
54
+ this.#candidate = {
55
+ operation,
56
+ bundle: nextBundle,
57
+ verified,
58
+ runtime: installedRuntime,
59
+ routing: nextRouting,
60
+ commitAdditional: typeof commitAdditional === "function"
61
+ ? commitAdditional
62
+ : undefined,
63
+ };
64
+ return verified;
65
+ }
66
+ /** Promote only the exact prepared candidate after transport admission and own coverage. */
67
+ promote(expectedDigest, shouldInstall = () => true) {
68
+ const candidate = this.#candidate;
69
+ if (!candidate || candidate.operation !== this.#operation ||
70
+ candidate.verified.contextDigest !== expectedDigest || !shouldInstall()) {
71
+ throw new Error("authorization candidate changed before promotion");
72
+ }
73
+ candidate.commitAdditional?.();
74
+ this.#bundle = candidate.bundle;
75
+ this.#verified = candidate.verified;
76
+ this.#runtime = candidate.runtime;
77
+ this.#routing = candidate.routing;
78
+ this.#candidate = undefined;
79
+ this.#generation += 1;
80
+ return candidate.verified;
81
+ }
82
+ /** Return the installed context identity without time or usability checks. */
83
+ storedContextDigest() {
84
+ return this.#verified?.contextDigest;
85
+ }
86
+ /** Drop a private candidate that became unusable before promotion. */
87
+ invalidateCandidate(digest) {
88
+ if (this.#candidate?.verified.contextDigest === digest) {
89
+ this.#candidate = undefined;
90
+ return true;
91
+ }
92
+ return false;
93
+ }
94
+ /** Return the verified candidate used only for transport reauthorization. */
95
+ transportCurrent() {
96
+ return this.#candidate?.verified ?? this.current();
97
+ }
98
+ hasCandidate() {
99
+ return this.#candidate !== undefined;
100
+ }
101
+ transportRuntimeBinding() {
102
+ const runtime = this.#candidate?.runtime ?? this.#runtime;
103
+ if (!runtime) {
104
+ throw new Error("no authorization runtime metadata is installed");
105
+ }
106
+ return structuredClone(runtime);
107
+ }
108
+ transportRoutingJwt() {
109
+ const routing = this.#candidate?.routing ?? this.#routing;
110
+ if (!routing || routing.bootstrapJwtExpiresAt <= this.correctedNowSeconds())
111
+ throw new Error("authorization routing JWT expired");
112
+ return routing.bootstrapJwt;
113
+ }
114
+ /** Returns the number of successfully installed authorization contexts. */
115
+ generation() {
116
+ return this.#generation;
117
+ }
118
+ current(nowUnixSeconds = this.correctedNowSeconds()) {
119
+ const verified = this.#verified;
120
+ if (!verified || verified.context.notBefore > nowUnixSeconds ||
121
+ verified.context.expiresAt <= nowUnixSeconds) {
122
+ throw new Error("no current authorization context");
123
+ }
124
+ return verified;
125
+ }
126
+ bundle() {
127
+ if (!this.#bundle)
128
+ throw new Error("no authorization context is installed");
129
+ return structuredClone(this.#bundle);
130
+ }
131
+ /** Return the current compact verifier policy without cloning the context bundle. */
132
+ verificationPolicy(nowUnixSeconds = this.correctedNowSeconds()) {
133
+ if (!this.#bundle)
134
+ throw new Error("no authorization context is installed");
135
+ return authorizationContextVerificationPolicy(this.#bundle.policy, nowUnixSeconds);
136
+ }
137
+ shouldRefresh(nowUnixSeconds = this.correctedNowSeconds()) {
138
+ this.current(nowUnixSeconds);
139
+ return nowUnixSeconds >= this.routingRefreshAt();
140
+ }
141
+ async clear() {
142
+ this.#operation += 1;
143
+ this.#bundle = undefined;
144
+ this.#verified = undefined;
145
+ this.#routing = undefined;
146
+ this.#candidate = undefined;
147
+ }
148
+ /** Capture the exact material owned by an in-flight refresh. */
149
+ clearGuard() {
150
+ return [
151
+ this.#verified?.contextDigest ?? null,
152
+ this.#routing?.bootstrapJwt ?? null,
153
+ this.#operation,
154
+ ];
155
+ }
156
+ /** Clear terminal state only if no newer context or route JWT replaced it. */
157
+ async clearIfCurrent(guard) {
158
+ if ((this.#verified?.contextDigest ?? null) !== guard[0] ||
159
+ (this.#routing?.bootstrapJwt ?? null) !== guard[1] ||
160
+ this.#operation !== guard[2])
161
+ return false;
162
+ this.#operation += 1;
163
+ this.#bundle = undefined;
164
+ this.#verified = undefined;
165
+ this.#routing = undefined;
166
+ this.#candidate = undefined;
167
+ return true;
168
+ }
169
+ /** Return reconnect metadata retained with the signed context. */
170
+ runtimeBinding() {
171
+ if (!this.#runtime) {
172
+ throw new Error("no authorization runtime metadata is installed");
173
+ }
174
+ return structuredClone(this.#runtime);
175
+ }
176
+ routingJwt() {
177
+ if (!this.#routing ||
178
+ this.#routing.bootstrapJwtExpiresAt <= this.correctedNowSeconds()) {
179
+ throw new Error("authorization routing JWT expired");
180
+ }
181
+ return this.#routing.bootstrapJwt;
182
+ }
183
+ routingRefreshAt() {
184
+ const context = this.current();
185
+ if (!this.#routing || !this.#bundle)
186
+ return this.correctedNowSeconds();
187
+ return Math.min(context.refreshAt, this.#routing.bootstrapJwtExpiresAt -
188
+ this.#bundle.policy.refreshLeadSeconds);
189
+ }
190
+ setServerClockOffsetMs(offsetMs) {
191
+ this.#clockOffsetMs = offsetMs;
192
+ }
193
+ serverClockOffsetMs() {
194
+ return this.#clockOffsetMs;
195
+ }
196
+ correctedNowSeconds() {
197
+ return Math.floor((this.now() + this.#clockOffsetMs) / 1_000);
198
+ }
199
+ nowMilliseconds() {
200
+ return this.now();
201
+ }
202
+ /**
203
+ * Return the installed chain material for a provider-side local verifier.
204
+ *
205
+ * This is an in-process handoff; it performs no registry I/O.
206
+ */
207
+ installedVerificationMaterial() {
208
+ if (!this.#bundle || !this.#verified) {
209
+ throw new Error("no authorization verification material is installed");
210
+ }
211
+ return {
212
+ issuer: structuredClone(this.#bundle.issuer),
213
+ context: structuredClone(this.#bundle.context),
214
+ contextDigest: this.#verified.contextDigest,
215
+ policy: authorizationContextVerificationPolicy(this.#bundle.policy, this.correctedNowSeconds()),
216
+ verified: structuredClone(this.#verified),
217
+ };
218
+ }
219
+ /** Register the single existing refresh task wake callback. */
220
+ registerRefreshRequest(callback) {
221
+ if (this.#refreshRequest) {
222
+ throw new Error("authorization refresh callback is already registered");
223
+ }
224
+ this.#refreshRequest = callback;
225
+ if (this.#refreshRequestPending) {
226
+ this.#refreshRequestPending = false;
227
+ callback();
228
+ }
229
+ return () => {
230
+ if (this.#refreshRequest === callback)
231
+ this.#refreshRequest = undefined;
232
+ };
233
+ }
234
+ /** Wake the existing refresh task after trust-floor advance. */
235
+ requestRefresh() {
236
+ const callback = this.#refreshRequest;
237
+ if (callback) {
238
+ callback();
239
+ }
240
+ else {
241
+ this.#refreshRequestPending = true;
242
+ }
243
+ }
244
+ }
245
+ /** Build the exact policy passed to the Rust/WASM verifier. */
246
+ export function authorizationContextVerificationPolicy(policy, nowUnixSeconds) {
247
+ return {
248
+ nowUnixSeconds,
249
+ allowedClockSkewSeconds: policy.allowedClockSkewSeconds,
250
+ maximumContextLifetimeSeconds: policy.maximumContextLifetimeSeconds,
251
+ maximumContextBytes: policy.maximumContextBytes,
252
+ maximumPermissions: policy.maximumPermissions,
253
+ refreshLeadSeconds: policy.refreshLeadSeconds,
254
+ refreshJitterSeconds: policy.refreshJitterSeconds,
255
+ };
256
+ }
257
+ /** Verify a complete authorization context chain through Rust/WASM. */
258
+ export async function verifyAuthorizationContext(args) {
259
+ const { verifyAuthorizationContextWasm } = await import("../protocol_wasm.js");
260
+ const result = await verifyAuthorizationContextWasm({
261
+ issuer: args.bundle.issuer,
262
+ context: args.bundle.context,
263
+ policy: args.policy,
264
+ });
265
+ return result;
266
+ }
@@ -0,0 +1,41 @@
1
+ import { type NatsConnection } from "@nats-io/nats-core";
2
+ import type { AuthorizationRegistryBinding } from "./types.ts";
3
+ /** Registry I/O counters observed since provider-cache start. */
4
+ export type AuthorizationRegistryIoCounters = {
5
+ contextGets: number;
6
+ watchStarts: number;
7
+ };
8
+ export type RegistryEntry = {
9
+ value: Uint8Array;
10
+ revision: number;
11
+ operation: string;
12
+ };
13
+ /** One exact revocation-key update observed after subscription flush. */
14
+ export type RegistryWatchEntry = {
15
+ operation: "put";
16
+ key: string;
17
+ value: Uint8Array;
18
+ revision: number;
19
+ } | {
20
+ operation: "delete";
21
+ key: string;
22
+ revision: number;
23
+ } | {
24
+ operation: "initialized";
25
+ };
26
+ /** Connected NATS KV reader for authorization evidence. */
27
+ export declare class AuthorizationRegistryReader {
28
+ #private;
29
+ private constructor();
30
+ /** Open the exact registry buckets from bootstrap-owned internal metadata. */
31
+ static open(nats: NatsConnection, binding: AuthorizationRegistryBinding, inboxPrefix: string): Promise<AuthorizationRegistryReader>;
32
+ /** Return a copy of internal registry counters. */
33
+ ioCounters(): AuthorizationRegistryIoCounters;
34
+ /** Read one immutable context by its exact digest key. */
35
+ getContext(digest: string): Promise<RegistryEntry | null>;
36
+ /** Subscribe only to the active context's revocation key. */
37
+ watchRevocation(contextDigest: string): Promise<{
38
+ iterator: AsyncIterator<RegistryWatchEntry>;
39
+ close: () => Promise<void>;
40
+ }>;
41
+ }