@qlever-llc/trellis 0.6.1 → 0.7.0-rc.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. package/README.md +6 -2
  2. package/esm/auth/device_activation.d.ts +194 -0
  3. package/esm/auth/device_activation.d.ts.map +1 -0
  4. package/esm/auth/{workload_activation.js → device_activation.js} +85 -60
  5. package/esm/auth/mod.d.ts +2 -2
  6. package/esm/auth/mod.d.ts.map +1 -1
  7. package/esm/auth/mod.js +2 -2
  8. package/esm/auth/protocol.d.ts +175 -72
  9. package/esm/auth/protocol.d.ts.map +1 -1
  10. package/esm/auth/protocol.js +126 -78
  11. package/esm/contracts/mod.d.ts +19 -3
  12. package/esm/contracts/mod.d.ts.map +1 -1
  13. package/esm/contracts/mod.js +28 -4
  14. package/esm/contracts/protocol.d.ts +34 -0
  15. package/esm/contracts/protocol.d.ts.map +1 -1
  16. package/esm/contracts/protocol.js +15 -0
  17. package/esm/server/deno.d.ts +1 -6
  18. package/esm/server/deno.d.ts.map +1 -1
  19. package/esm/server/deno.js +1 -16
  20. package/esm/server/mod.d.ts +3 -2
  21. package/esm/server/mod.d.ts.map +1 -1
  22. package/esm/server/mod.js +2 -2
  23. package/esm/server/node.d.ts +1 -6
  24. package/esm/server/node.d.ts.map +1 -1
  25. package/esm/server/node.js +1 -16
  26. package/esm/server/service.d.ts +32 -10
  27. package/esm/server/service.d.ts.map +1 -1
  28. package/esm/server/service.js +188 -41
  29. package/esm/server/transfer.d.ts +41 -0
  30. package/esm/server/transfer.d.ts.map +1 -0
  31. package/esm/server/transfer.js +418 -0
  32. package/esm/telemetry/init.d.ts +4 -0
  33. package/esm/telemetry/init.d.ts.map +1 -0
  34. package/esm/telemetry/init.js +7 -0
  35. package/esm/telemetry/mod.d.ts +1 -2
  36. package/esm/telemetry/mod.d.ts.map +1 -1
  37. package/esm/telemetry/mod.js +1 -2
  38. package/esm/telemetry/runtime.d.ts.map +1 -1
  39. package/esm/telemetry/runtime.js +9 -5
  40. package/esm/telemetry/trellis.d.ts +0 -1
  41. package/esm/telemetry/trellis.d.ts.map +1 -1
  42. package/esm/telemetry/trellis.js +0 -6
  43. package/esm/trellis/_sdk/auth/api.d.ts.map +1 -1
  44. package/esm/trellis/_sdk/auth/api.js +132 -110
  45. package/esm/trellis/_sdk/auth/contract.d.ts +1 -1
  46. package/esm/trellis/_sdk/auth/contract.d.ts.map +1 -1
  47. package/esm/trellis/_sdk/auth/contract.js +2 -2
  48. package/esm/trellis/_sdk/auth/schemas.d.ts +4212 -3069
  49. package/esm/trellis/_sdk/auth/schemas.d.ts.map +1 -1
  50. package/esm/trellis/_sdk/auth/schemas.js +144 -125
  51. package/esm/trellis/_sdk/auth/types.d.ts +417 -267
  52. package/esm/trellis/_sdk/auth/types.d.ts.map +1 -1
  53. package/esm/trellis/_sdk/auth/types.js +1 -1
  54. package/esm/trellis/_sdk/core/contract.d.ts +1 -1
  55. package/esm/trellis/_sdk/core/contract.d.ts.map +1 -1
  56. package/esm/trellis/_sdk/core/contract.js +2 -2
  57. package/esm/trellis/_sdk/core/schemas.d.ts +122 -0
  58. package/esm/trellis/_sdk/core/schemas.d.ts.map +1 -1
  59. package/esm/trellis/_sdk/core/schemas.js +4 -4
  60. package/esm/trellis/_sdk/core/types.d.ts +18 -1
  61. package/esm/trellis/_sdk/core/types.d.ts.map +1 -1
  62. package/esm/trellis/_sdk/core/types.js +1 -1
  63. package/esm/trellis/_sdk/state/_dnt.polyfills.d.ts +12 -0
  64. package/esm/trellis/_sdk/state/_dnt.polyfills.d.ts.map +1 -0
  65. package/esm/trellis/_sdk/state/_dnt.polyfills.js +15 -0
  66. package/esm/trellis/_sdk/state/api.d.ts +10 -0
  67. package/esm/trellis/_sdk/state/api.d.ts.map +1 -0
  68. package/esm/trellis/_sdk/state/api.js +71 -0
  69. package/esm/trellis/_sdk/state/contract.d.ts +8 -0
  70. package/esm/trellis/_sdk/state/contract.d.ts.map +1 -0
  71. package/esm/trellis/_sdk/state/contract.js +59 -0
  72. package/esm/trellis/_sdk/state/mod.d.ts +7 -0
  73. package/esm/trellis/_sdk/state/mod.d.ts.map +1 -0
  74. package/esm/trellis/_sdk/state/mod.js +5 -0
  75. package/esm/trellis/_sdk/state/package.json +3 -0
  76. package/esm/trellis/_sdk/state/schemas.d.ts +1437 -0
  77. package/esm/trellis/_sdk/state/schemas.d.ts.map +1 -0
  78. package/esm/trellis/_sdk/state/schemas.js +62 -0
  79. package/esm/trellis/_sdk/state/types.d.ts +206 -0
  80. package/esm/trellis/_sdk/state/types.d.ts.map +1 -0
  81. package/esm/trellis/_sdk/state/types.js +3 -0
  82. package/esm/trellis/client_connect.d.ts +53 -0
  83. package/esm/trellis/client_connect.d.ts.map +1 -0
  84. package/esm/trellis/client_connect.js +300 -0
  85. package/esm/trellis/contract.d.ts +1 -7
  86. package/esm/trellis/contract.d.ts.map +1 -1
  87. package/esm/trellis/contract.js +1 -12
  88. package/esm/trellis/device.d.ts +41 -0
  89. package/esm/trellis/device.d.ts.map +1 -0
  90. package/esm/trellis/device.js +209 -0
  91. package/esm/trellis/errors/AuthError.d.ts +1 -1
  92. package/esm/trellis/errors/AuthError.js +9 -9
  93. package/esm/trellis/errors/StoreError.d.ts +22 -0
  94. package/esm/trellis/errors/StoreError.d.ts.map +1 -0
  95. package/esm/trellis/errors/StoreError.js +41 -0
  96. package/esm/trellis/errors/TransferError.d.ts +22 -0
  97. package/esm/trellis/errors/TransferError.d.ts.map +1 -0
  98. package/esm/trellis/errors/TransferError.js +41 -0
  99. package/esm/trellis/errors/index.d.ts +8 -0
  100. package/esm/trellis/errors/index.d.ts.map +1 -1
  101. package/esm/trellis/errors/index.js +8 -0
  102. package/esm/trellis/index.d.ts +10 -4
  103. package/esm/trellis/index.d.ts.map +1 -1
  104. package/esm/trellis/index.js +6 -4
  105. package/esm/trellis/kv.d.ts +2 -0
  106. package/esm/trellis/kv.d.ts.map +1 -1
  107. package/esm/trellis/kv.js +6 -0
  108. package/esm/trellis/models/trellis/TrellisError.d.ts +15 -1
  109. package/esm/trellis/models/trellis/TrellisError.d.ts.map +1 -1
  110. package/esm/trellis/models/trellis/TrellisError.js +4 -0
  111. package/esm/trellis/runtime_transport.d.ts +12 -0
  112. package/esm/trellis/runtime_transport.d.ts.map +1 -0
  113. package/esm/trellis/runtime_transport.js +35 -0
  114. package/esm/trellis/sdk/state.d.ts +4 -0
  115. package/esm/trellis/sdk/state.d.ts.map +1 -0
  116. package/esm/trellis/sdk/state.js +3 -0
  117. package/esm/trellis/store.d.ts +51 -0
  118. package/esm/trellis/store.d.ts.map +1 -0
  119. package/esm/trellis/store.js +310 -0
  120. package/esm/trellis/tracing.js +1 -1
  121. package/esm/trellis/transfer.d.ts +118 -0
  122. package/esm/trellis/transfer.d.ts.map +1 -0
  123. package/esm/trellis/transfer.js +357 -0
  124. package/esm/trellis/trellis.d.ts +3 -0
  125. package/esm/trellis/trellis.d.ts.map +1 -1
  126. package/esm/trellis/trellis.js +48 -17
  127. package/package.json +7 -2
  128. package/script/auth/device_activation.d.ts +194 -0
  129. package/script/auth/device_activation.d.ts.map +1 -0
  130. package/script/auth/{workload_activation.js → device_activation.js} +99 -74
  131. package/script/auth/mod.d.ts +2 -2
  132. package/script/auth/mod.d.ts.map +1 -1
  133. package/script/auth/mod.js +84 -76
  134. package/script/auth/protocol.d.ts +175 -72
  135. package/script/auth/protocol.d.ts.map +1 -1
  136. package/script/auth/protocol.js +129 -81
  137. package/script/contracts/mod.d.ts +19 -3
  138. package/script/contracts/mod.d.ts.map +1 -1
  139. package/script/contracts/mod.js +30 -4
  140. package/script/contracts/protocol.d.ts +34 -0
  141. package/script/contracts/protocol.d.ts.map +1 -1
  142. package/script/contracts/protocol.js +16 -1
  143. package/script/telemetry/init.d.ts +4 -0
  144. package/script/telemetry/init.d.ts.map +1 -0
  145. package/script/telemetry/init.js +11 -0
  146. package/script/telemetry/mod.d.ts +1 -2
  147. package/script/telemetry/mod.d.ts.map +1 -1
  148. package/script/telemetry/mod.js +1 -4
  149. package/script/telemetry/runtime.d.ts.map +1 -1
  150. package/script/telemetry/runtime.js +9 -28
  151. package/script/telemetry/trellis.d.ts +0 -1
  152. package/script/telemetry/trellis.d.ts.map +1 -1
  153. package/script/telemetry/trellis.js +0 -7
  154. package/script/trellis/_sdk/auth/api.d.ts.map +1 -1
  155. package/script/trellis/_sdk/auth/api.js +132 -110
  156. package/script/trellis/_sdk/auth/contract.d.ts +1 -1
  157. package/script/trellis/_sdk/auth/contract.d.ts.map +1 -1
  158. package/script/trellis/_sdk/auth/contract.js +2 -2
  159. package/script/trellis/_sdk/auth/schemas.d.ts +4212 -3069
  160. package/script/trellis/_sdk/auth/schemas.d.ts.map +1 -1
  161. package/script/trellis/_sdk/auth/schemas.js +144 -125
  162. package/script/trellis/_sdk/auth/types.d.ts +417 -267
  163. package/script/trellis/_sdk/auth/types.d.ts.map +1 -1
  164. package/script/trellis/_sdk/auth/types.js +1 -1
  165. package/script/trellis/_sdk/core/contract.d.ts +1 -1
  166. package/script/trellis/_sdk/core/contract.d.ts.map +1 -1
  167. package/script/trellis/_sdk/core/contract.js +2 -2
  168. package/script/trellis/_sdk/core/schemas.d.ts +122 -0
  169. package/script/trellis/_sdk/core/schemas.d.ts.map +1 -1
  170. package/script/trellis/_sdk/core/schemas.js +4 -4
  171. package/script/trellis/_sdk/core/types.d.ts +18 -1
  172. package/script/trellis/_sdk/core/types.d.ts.map +1 -1
  173. package/script/trellis/_sdk/core/types.js +1 -1
  174. package/script/trellis/_sdk/state/_dnt.polyfills.d.ts +12 -0
  175. package/script/trellis/_sdk/state/_dnt.polyfills.d.ts.map +1 -0
  176. package/script/trellis/_sdk/state/_dnt.polyfills.js +16 -0
  177. package/script/trellis/_sdk/state/api.d.ts +10 -0
  178. package/script/trellis/_sdk/state/api.d.ts.map +1 -0
  179. package/script/trellis/_sdk/state/api.js +74 -0
  180. package/script/trellis/_sdk/state/contract.d.ts +8 -0
  181. package/script/trellis/_sdk/state/contract.d.ts.map +1 -0
  182. package/script/trellis/_sdk/state/contract.js +62 -0
  183. package/script/trellis/_sdk/state/mod.d.ts +7 -0
  184. package/script/trellis/_sdk/state/mod.d.ts.map +1 -0
  185. package/script/trellis/_sdk/state/mod.js +30 -0
  186. package/script/trellis/_sdk/state/package.json +3 -0
  187. package/script/trellis/_sdk/state/schemas.d.ts +1437 -0
  188. package/script/trellis/_sdk/state/schemas.d.ts.map +1 -0
  189. package/script/trellis/_sdk/state/schemas.js +65 -0
  190. package/script/trellis/_sdk/state/types.d.ts +206 -0
  191. package/script/trellis/_sdk/state/types.d.ts.map +1 -0
  192. package/script/trellis/_sdk/state/types.js +6 -0
  193. package/script/trellis/client_connect.d.ts +53 -0
  194. package/script/trellis/client_connect.d.ts.map +1 -0
  195. package/script/trellis/client_connect.js +304 -0
  196. package/script/trellis/contract.d.ts +1 -7
  197. package/script/trellis/contract.d.ts.map +1 -1
  198. package/script/trellis/contract.js +1 -12
  199. package/script/trellis/device.d.ts +41 -0
  200. package/script/trellis/device.d.ts.map +1 -0
  201. package/script/trellis/device.js +213 -0
  202. package/script/trellis/errors/AuthError.d.ts +1 -1
  203. package/script/trellis/errors/AuthError.js +9 -9
  204. package/script/trellis/errors/StoreError.d.ts +22 -0
  205. package/script/trellis/errors/StoreError.d.ts.map +1 -0
  206. package/script/trellis/errors/StoreError.js +48 -0
  207. package/script/trellis/errors/TransferError.d.ts +22 -0
  208. package/script/trellis/errors/TransferError.d.ts.map +1 -0
  209. package/script/trellis/errors/TransferError.js +48 -0
  210. package/script/trellis/errors/index.d.ts +8 -0
  211. package/script/trellis/errors/index.d.ts.map +1 -1
  212. package/script/trellis/errors/index.js +13 -1
  213. package/script/trellis/index.d.ts +10 -4
  214. package/script/trellis/index.d.ts.map +1 -1
  215. package/script/trellis/index.js +17 -6
  216. package/script/trellis/kv.d.ts +2 -0
  217. package/script/trellis/kv.d.ts.map +1 -1
  218. package/script/trellis/kv.js +6 -0
  219. package/script/trellis/models/trellis/TrellisError.d.ts +15 -1
  220. package/script/trellis/models/trellis/TrellisError.d.ts.map +1 -1
  221. package/script/trellis/models/trellis/TrellisError.js +4 -0
  222. package/script/trellis/runtime_transport.d.ts +12 -0
  223. package/script/trellis/runtime_transport.d.ts.map +1 -0
  224. package/script/trellis/runtime_transport.js +37 -0
  225. package/script/trellis/store.d.ts +51 -0
  226. package/script/trellis/store.d.ts.map +1 -0
  227. package/script/trellis/store.js +316 -0
  228. package/script/trellis/tracing.js +1 -1
  229. package/script/trellis/transfer.d.ts +118 -0
  230. package/script/trellis/transfer.d.ts.map +1 -0
  231. package/script/trellis/transfer.js +367 -0
  232. package/script/trellis/trellis.d.ts +3 -0
  233. package/script/trellis/trellis.d.ts.map +1 -1
  234. package/script/trellis/trellis.js +48 -17
  235. package/esm/auth/workload_activation.d.ts +0 -192
  236. package/esm/auth/workload_activation.d.ts.map +0 -1
  237. package/esm/trellis/workload.d.ts +0 -45
  238. package/esm/trellis/workload.d.ts.map +0 -1
  239. package/esm/trellis/workload.js +0 -144
  240. package/script/auth/workload_activation.d.ts +0 -192
  241. package/script/auth/workload_activation.d.ts.map +0 -1
  242. package/script/trellis/workload.d.ts +0 -45
  243. package/script/trellis/workload.d.ts.map +0 -1
  244. package/script/trellis/workload.js +0 -172
@@ -0,0 +1,304 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TrellisClient = void 0;
4
+ exports.connectClientWithDeps = connectClientWithDeps;
5
+ const nats_core_1 = require("@nats-io/nats-core");
6
+ const auth_ts_1 = require("./auth.ts");
7
+ const auth_ts_2 = require("./auth.ts");
8
+ const auth_ts_3 = require("./auth.ts");
9
+ const runtime_transport_ts_1 = require("./runtime_transport.ts");
10
+ const trellis_ts_1 = require("./trellis.ts");
11
+ const typebox_1 = require("typebox");
12
+ const value_1 = require("typebox/value");
13
+ const session_ts_1 = require("../auth/browser/session.ts");
14
+ const ClientBootstrapReadySchema = typebox_1.Type.Object({
15
+ status: typebox_1.Type.Literal("ready"),
16
+ connectInfo: typebox_1.Type.Object({
17
+ sessionKey: typebox_1.Type.String({ minLength: 1 }),
18
+ contractId: typebox_1.Type.String({ minLength: 1 }),
19
+ contractDigest: typebox_1.Type.String({ minLength: 1 }),
20
+ transport: typebox_1.Type.Object({
21
+ natsServers: typebox_1.Type.Array(typebox_1.Type.String({ minLength: 1 }), { minItems: 1 }),
22
+ inboxPrefix: typebox_1.Type.String({ minLength: 1 }),
23
+ sentinel: typebox_1.Type.Object({
24
+ jwt: typebox_1.Type.String({ minLength: 1 }),
25
+ seed: typebox_1.Type.String({ minLength: 1 }),
26
+ }, { additionalProperties: false }),
27
+ }, { additionalProperties: false }),
28
+ auth: typebox_1.Type.Object({
29
+ mode: typebox_1.Type.Literal("binding_token"),
30
+ bindingToken: typebox_1.Type.String({ minLength: 1 }),
31
+ expiresAt: typebox_1.Type.String({ format: "date-time" }),
32
+ }, { additionalProperties: false }),
33
+ }, { additionalProperties: false }),
34
+ }, { additionalProperties: true });
35
+ const ClientBootstrapAuthRequiredSchema = typebox_1.Type.Object({
36
+ status: typebox_1.Type.Literal("auth_required"),
37
+ }, { additionalProperties: true });
38
+ const ClientBootstrapNotReadySchema = typebox_1.Type.Object({
39
+ status: typebox_1.Type.Literal("not_ready"),
40
+ reason: typebox_1.Type.String({ minLength: 1 }),
41
+ }, { additionalProperties: true });
42
+ function isBrowserRuntime() {
43
+ return typeof window !== "undefined" && typeof document !== "undefined";
44
+ }
45
+ const defaultDeps = {
46
+ loadTransport: runtime_transport_ts_1.loadDefaultRuntimeTransport,
47
+ now: () => Date.now(),
48
+ };
49
+ function normalizeTrellisUrl(trellisUrl) {
50
+ return new URL(trellisUrl).toString().replace(/\/$/, "");
51
+ }
52
+ function resolveCurrentUrl(auth) {
53
+ if (auth?.currentUrl instanceof URL)
54
+ return auth.currentUrl;
55
+ if (typeof auth?.currentUrl === "string")
56
+ return new URL(auth.currentUrl);
57
+ if (isBrowserRuntime())
58
+ return new URL(window.location.href);
59
+ return null;
60
+ }
61
+ function resolveRedirectTo(auth, currentUrl) {
62
+ if (auth.redirectTo) {
63
+ return new URL(auth.redirectTo, currentUrl.origin).toString();
64
+ }
65
+ const queryRedirect = currentUrl.searchParams.get("redirectTo");
66
+ if (queryRedirect) {
67
+ return new URL(queryRedirect, currentUrl.origin).toString();
68
+ }
69
+ if (auth.landingPath) {
70
+ return new URL(auth.landingPath, currentUrl.origin).toString();
71
+ }
72
+ return currentUrl.toString();
73
+ }
74
+ function encodeJsonForQuery(value) {
75
+ const json = (0, auth_ts_3.canonicalizeJsonValue)(value);
76
+ const bytes = new TextEncoder().encode(json);
77
+ let binary = "";
78
+ for (const byte of bytes)
79
+ binary += String.fromCharCode(byte);
80
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
81
+ }
82
+ async function signDomainValue(sign, prefix, value) {
83
+ const digest = await (0, auth_ts_3.sha256)((0, auth_ts_3.utf8)(`${prefix}:${value}`));
84
+ const signature = await sign(digest);
85
+ const binary = String.fromCharCode(...signature);
86
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
87
+ }
88
+ async function resolveClientIdentity(auth) {
89
+ if (auth?.mode === "session_key") {
90
+ const sessionAuth = await (0, auth_ts_2.createAuth)({ sessionKeySeed: auth.sessionKeySeed });
91
+ return {
92
+ mode: "session_key",
93
+ sessionKey: sessionAuth.sessionKey,
94
+ sign: sessionAuth.sign,
95
+ oauthInitSig: sessionAuth.oauthInitSig,
96
+ bindingTokenSig: sessionAuth.natsConnectSigForBindingToken,
97
+ bootstrapSig: (iat) => signDomainValue(sessionAuth.sign, "bootstrap-client", String(iat)),
98
+ bindFlowSig: (flowId) => signDomainValue(sessionAuth.sign, "bind-flow", flowId),
99
+ };
100
+ }
101
+ const handle = auth?.handle ?? await (0, auth_ts_1.getOrCreateSessionKey)();
102
+ return {
103
+ mode: "browser",
104
+ sessionKey: (0, session_ts_1.getPublicSessionKey)(handle),
105
+ sign: (data) => (0, session_ts_1.signBytes)(handle, data),
106
+ oauthInitSig: (redirectTo, context) => (0, session_ts_1.oauthInitSig)(handle, redirectTo, context),
107
+ bindingTokenSig: (bindingToken) => signDomainValue((data) => (0, session_ts_1.signBytes)(handle, data), "nats-connect", bindingToken),
108
+ bootstrapSig: (iat) => signDomainValue((data) => (0, session_ts_1.signBytes)(handle, data), "bootstrap-client", String(iat)),
109
+ bindFlowSig: (flowId) => (0, session_ts_1.bindFlowSig)(handle, flowId),
110
+ };
111
+ }
112
+ async function bindClientFlow(args) {
113
+ const response = await fetch(`${args.trellisUrl}/auth/flow/${encodeURIComponent(args.flowId)}/bind`, {
114
+ method: "POST",
115
+ headers: { "Content-Type": "application/json" },
116
+ body: JSON.stringify({ sessionKey: args.sessionKey, sig: args.sig }),
117
+ });
118
+ if (!response.ok) {
119
+ throw new Error(`Client bind failed: ${response.status} ${await response.text()}`);
120
+ }
121
+ const payload = await response.json();
122
+ const parsed = value_1.Value.Parse(auth_ts_1.BindResponseSchema, payload);
123
+ if (parsed.status !== "bound") {
124
+ throw new Error(`Client bind did not complete: ${parsed.status}`);
125
+ }
126
+ }
127
+ async function fetchClientBootstrap(args) {
128
+ const response = await fetch(new URL("/bootstrap/client", args.trellisUrl), {
129
+ method: "POST",
130
+ headers: { "Content-Type": "application/json" },
131
+ body: JSON.stringify({
132
+ sessionKey: args.sessionKey,
133
+ iat: args.iat,
134
+ sig: args.bootstrapSig,
135
+ }),
136
+ });
137
+ const payload = await response.json();
138
+ if (!response.ok) {
139
+ const reason = typeof payload?.reason === "string"
140
+ ? payload.reason
141
+ : `http_${response.status}`;
142
+ throw new Error(`Client bootstrap failed: ${reason}`);
143
+ }
144
+ if (value_1.Value.Check(ClientBootstrapReadySchema, payload)) {
145
+ return payload;
146
+ }
147
+ if (value_1.Value.Check(ClientBootstrapAuthRequiredSchema, payload)) {
148
+ return payload;
149
+ }
150
+ if (value_1.Value.Check(ClientBootstrapNotReadySchema, payload)) {
151
+ return payload;
152
+ }
153
+ throw new Error("Client bootstrap returned an invalid response");
154
+ }
155
+ function cleanupBrowserCallbackUrl(currentUrl) {
156
+ if (!isBrowserRuntime())
157
+ return;
158
+ if (!currentUrl.searchParams.has("flowId") && !currentUrl.searchParams.has("authError")) {
159
+ return;
160
+ }
161
+ currentUrl.searchParams.delete("flowId");
162
+ currentUrl.searchParams.delete("authError");
163
+ window.history.replaceState({}, "", currentUrl.pathname + currentUrl.search);
164
+ }
165
+ async function buildSessionKeyLoginUrl(args) {
166
+ const url = new URL(`${args.trellisUrl}/auth/login`);
167
+ url.searchParams.set("redirectTo", args.redirectTo);
168
+ url.searchParams.set("sessionKey", args.sessionKey);
169
+ url.searchParams.set("sig", args.oauthInitSig);
170
+ url.searchParams.set("contract", encodeJsonForQuery(args.contract));
171
+ if (args.provider) {
172
+ url.searchParams.set("provider", args.provider);
173
+ }
174
+ if (args.context !== undefined) {
175
+ url.searchParams.set("context", encodeJsonForQuery(args.context));
176
+ }
177
+ return url.toString();
178
+ }
179
+ async function connectClientWithDeps(args, deps) {
180
+ const trellisUrl = normalizeTrellisUrl(args.trellisUrl);
181
+ const identity = await resolveClientIdentity(args.auth);
182
+ const currentUrl = args.auth?.mode === "session_key" ? null : resolveCurrentUrl(args.auth);
183
+ const callbackFlowId = args.auth?.mode === "session_key"
184
+ ? args.auth.flowId
185
+ : currentUrl?.searchParams.get("flowId") ?? undefined;
186
+ if (callbackFlowId) {
187
+ await bindClientFlow({
188
+ trellisUrl,
189
+ sessionKey: identity.sessionKey,
190
+ flowId: callbackFlowId,
191
+ sig: await identity.bindFlowSig(callbackFlowId),
192
+ });
193
+ if (currentUrl)
194
+ cleanupBrowserCallbackUrl(currentUrl);
195
+ }
196
+ const bootstrapIat = Math.floor(deps.now() / 1_000);
197
+ const initialBootstrap = await fetchClientBootstrap({
198
+ trellisUrl,
199
+ sessionKey: identity.sessionKey,
200
+ iat: bootstrapIat,
201
+ bootstrapSig: await identity.bootstrapSig(bootstrapIat),
202
+ });
203
+ const bootstrap = initialBootstrap.status === "auth_required"
204
+ ? await resolveAuthRequired(args, identity, currentUrl, deps)
205
+ : initialBootstrap;
206
+ if (bootstrap.status !== "ready") {
207
+ if (bootstrap.status === "not_ready") {
208
+ throw new Error(`Client bootstrap is not ready: ${bootstrap.reason}`);
209
+ }
210
+ throw new Error("Client bootstrap still requires authentication");
211
+ }
212
+ const transport = await deps.loadTransport();
213
+ const token = JSON.stringify({
214
+ v: 1,
215
+ sessionKey: identity.sessionKey,
216
+ bindingToken: bootstrap.connectInfo.auth.bindingToken,
217
+ sig: await identity.bindingTokenSig(bootstrap.connectInfo.auth.bindingToken),
218
+ });
219
+ const nc = await transport.connect({
220
+ servers: bootstrap.connectInfo.transport.natsServers,
221
+ token,
222
+ inboxPrefix: bootstrap.connectInfo.transport.inboxPrefix,
223
+ authenticator: (0, nats_core_1.jwtAuthenticator)(bootstrap.connectInfo.transport.sentinel.jwt, new TextEncoder().encode(bootstrap.connectInfo.transport.sentinel.seed)),
224
+ });
225
+ const clientOpts = {
226
+ ...(typeof args.name === "string" ? { name: args.name } : {}),
227
+ ...(args.log ? { log: args.log } : {}),
228
+ ...(typeof args.timeout === "number" ? { timeout: args.timeout } : {}),
229
+ ...(typeof args.stream === "string" ? { stream: args.stream } : {}),
230
+ ...(args.noResponderRetry ? { noResponderRetry: args.noResponderRetry } : {}),
231
+ };
232
+ return new trellis_ts_1.Trellis(clientOpts.name ?? "client", nc, {
233
+ sessionKey: identity.sessionKey,
234
+ sign: identity.sign,
235
+ }, {
236
+ log: clientOpts.log,
237
+ timeout: clientOpts.timeout,
238
+ stream: clientOpts.stream,
239
+ noResponderRetry: clientOpts.noResponderRetry,
240
+ api: args.contract.API.trellis,
241
+ });
242
+ }
243
+ async function resolveAuthRequired(args, identity, currentUrl, deps) {
244
+ const browserAuth = args.auth?.mode === "session_key"
245
+ ? {}
246
+ : args.auth ?? {};
247
+ const redirectTo = args.auth?.mode === "session_key"
248
+ ? args.auth.redirectTo
249
+ : currentUrl
250
+ ? resolveRedirectTo(browserAuth, currentUrl)
251
+ : undefined;
252
+ if (!redirectTo) {
253
+ throw new Error("Client authentication requires a redirectTo URL");
254
+ }
255
+ const loginUrl = args.auth?.mode === "session_key"
256
+ ? await buildSessionKeyLoginUrl({
257
+ trellisUrl: normalizeTrellisUrl(args.trellisUrl),
258
+ redirectTo,
259
+ sessionKey: identity.sessionKey,
260
+ contract: args.contract.CONTRACT,
261
+ provider: args.auth.provider,
262
+ context: args.auth.context,
263
+ oauthInitSig: await identity.oauthInitSig(redirectTo, args.auth.context),
264
+ })
265
+ : await (0, auth_ts_1.buildLoginUrl)({
266
+ authUrl: normalizeTrellisUrl(args.trellisUrl),
267
+ redirectTo,
268
+ handle: browserAuth.handle ?? await (0, auth_ts_1.getOrCreateSessionKey)(),
269
+ provider: browserAuth.provider,
270
+ contract: args.contract.CONTRACT,
271
+ context: browserAuth.context,
272
+ });
273
+ const continuation = await args.onAuthRequired?.({
274
+ loginUrl,
275
+ sessionKey: identity.sessionKey,
276
+ mode: identity.mode,
277
+ });
278
+ if (continuation && typeof continuation === "object" && "flowId" in continuation) {
279
+ await bindClientFlow({
280
+ trellisUrl: normalizeTrellisUrl(args.trellisUrl),
281
+ sessionKey: identity.sessionKey,
282
+ flowId: continuation.flowId,
283
+ sig: await identity.bindFlowSig(continuation.flowId),
284
+ });
285
+ const bootstrapIat = Math.floor(deps.now() / 1_000);
286
+ return await fetchClientBootstrap({
287
+ trellisUrl: normalizeTrellisUrl(args.trellisUrl),
288
+ sessionKey: identity.sessionKey,
289
+ iat: bootstrapIat,
290
+ bootstrapSig: await identity.bootstrapSig(bootstrapIat),
291
+ });
292
+ }
293
+ if (isBrowserRuntime()) {
294
+ window.location.href = loginUrl;
295
+ throw new Error("Redirecting to Trellis login");
296
+ }
297
+ throw new Error("Client authentication required and no auth continuation was provided");
298
+ }
299
+ class TrellisClient {
300
+ static connect(args) {
301
+ return connectClientWithDeps(args, defaultDeps);
302
+ }
303
+ }
304
+ exports.TrellisClient = TrellisClient;
@@ -1,11 +1,5 @@
1
- import type { NatsConnection } from "@nats-io/nats-core";
2
1
  import { type DefinedContract as BaseDefinedContract, type ContractApiViews, type ContractDependencyUse, type ContractModule, type ContractUseFn, type DefineContractInput, type EmptyApi, type MergeApis, type OwnedApiFromSource, type SdkContractModule, type TrellisApiLike, type TrellisContractV1, type UsedApiFromUses, type UseSpec } from "../contracts/mod.ts";
3
- import type { ClientOpts } from "./client.ts";
4
- import type { Trellis, TrellisAuth } from "./trellis.ts";
5
- type RuntimeContractMethods<TOwnedApi extends TrellisApiLike, TTrellisApi extends TrellisApiLike> = {
6
- createClient(nats: NatsConnection, auth: TrellisAuth, opts?: ClientOpts): Trellis<TTrellisApi>;
7
- };
8
- export type DefinedContract<TOwnedApi extends TrellisApiLike, TUsedApi extends TrellisApiLike, TTrellisApi extends TrellisApiLike, TContractId extends string = string> = BaseDefinedContract<TOwnedApi, TUsedApi, TTrellisApi, TContractId> & RuntimeContractMethods<TOwnedApi, TTrellisApi>;
2
+ export type DefinedContract<TOwnedApi extends TrellisApiLike, TUsedApi extends TrellisApiLike, TTrellisApi extends TrellisApiLike, TContractId extends string = string> = BaseDefinedContract<TOwnedApi, TUsedApi, TTrellisApi, TContractId>;
9
3
  export declare function defineContract<const T extends DefineContractInput<any, any, any, any, any, any>>(source: T): DefinedContract<OwnedApiFromSource<T> & TrellisApiLike, UsedApiFromUses<T["uses"]> & TrellisApiLike, MergeApis<OwnedApiFromSource<T>, UsedApiFromUses<T["uses"]>> & TrellisApiLike, T["id"]>;
10
4
  export type { ContractApiViews, ContractDependencyUse, ContractModule, ContractUseFn, DefineContractInput, EmptyApi, SdkContractModule, TrellisApiLike, TrellisContractV1, UseSpec, };
11
5
  //# sourceMappingURL=contract.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../../contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD,OAAO,EACL,KAAK,eAAe,IAAI,mBAAmB,EAC3C,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EAExB,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,OAAO,EACb,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AASzD,KAAK,sBAAsB,CACzB,SAAS,SAAS,cAAc,EAChC,WAAW,SAAS,cAAc,IAChC;IACF,YAAY,CACV,IAAI,EAAE,cAAc,EACpB,IAAI,EAAE,WAAW,EACjB,IAAI,CAAC,EAAE,UAAU,GAChB,OAAO,CAAC,WAAW,CAAC,CAAC;CACzB,CAAC;AAOF,MAAM,MAAM,eAAe,CACzB,SAAS,SAAS,cAAc,EAChC,QAAQ,SAAS,cAAc,EAC/B,WAAW,SAAS,cAAc,EAClC,WAAW,SAAS,MAAM,GAAG,MAAM,IACjC,mBAAmB,CAAC,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,CAAC,GAAG,sBAAsB,CAC7F,SAAS,EACT,WAAW,CACZ,CAAC;AAwBF,wBAAgB,cAAc,CAAC,KAAK,CAAC,CAAC,SAAS,mBAAmB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAC9F,MAAM,EAAE,CAAC,GACR,eAAe,CAChB,kBAAkB,CAAC,CAAC,CAAC,GAAG,cAAc,EACtC,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,cAAc,EAC3C,SAAS,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,cAAc,EAC7E,CAAC,CAAC,IAAI,CAAC,CACR,CAWA;AAED,YAAY,EACV,gBAAgB,EAChB,qBAAqB,EACrB,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,QAAQ,EACR,iBAAiB,EACjB,cAAc,EACd,iBAAiB,EACjB,OAAO,GACR,CAAC"}
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../../contract.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,eAAe,IAAI,mBAAmB,EAC3C,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EAExB,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,OAAO,EACb,MAAM,qBAAqB,CAAC;AAS7B,MAAM,MAAM,eAAe,CACzB,SAAS,SAAS,cAAc,EAChC,QAAQ,SAAS,cAAc,EAC/B,WAAW,SAAS,cAAc,EAClC,WAAW,SAAS,MAAM,GAAG,MAAM,IACjC,mBAAmB,CAAC,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;AAEvE,wBAAgB,cAAc,CAAC,KAAK,CAAC,CAAC,SAAS,mBAAmB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAC9F,MAAM,EAAE,CAAC,GACR,eAAe,CAChB,kBAAkB,CAAC,CAAC,CAAC,GAAG,cAAc,EACtC,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,cAAc,EAC3C,SAAS,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,cAAc,EAC7E,CAAC,CAAC,IAAI,CAAC,CACR,CAOA;AAED,YAAY,EACV,gBAAgB,EAChB,qBAAqB,EACrB,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,QAAQ,EACR,iBAAiB,EACjB,cAAc,EACd,iBAAiB,EACjB,OAAO,GACR,CAAC"}
@@ -2,17 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.defineContract = defineContract;
4
4
  const mod_ts_1 = require("../contracts/mod.ts");
5
- const client_ts_1 = require("./client.ts");
6
- function withRuntimeHelpers(contract) {
7
- const runtimeContract = contract;
8
- const createRuntimeClient = client_ts_1.createClient;
9
- runtimeContract.createClient = (nats, auth, opts) => createRuntimeClient(runtimeContract, nats, auth, opts);
10
- return runtimeContract;
11
- }
12
5
  function defineContract(source) {
13
- const contract = (0, mod_ts_1.defineContract)(source);
14
- // TypeScript's recursion limit trips over this cast in Svelte/tsserver, but
15
- // the runtime helper augmentation preserves the underlying contract shape.
16
- // @ts-ignore TS2589
17
- return withRuntimeHelpers(contract);
6
+ return (0, mod_ts_1.defineContract)(source);
18
7
  }
@@ -0,0 +1,41 @@
1
+ import { type NatsConnection } from "@nats-io/nats-core";
2
+ import type { TrellisAPI } from "./contracts.ts";
3
+ import { Trellis } from "./trellis.ts";
4
+ type DeviceContract<TApi extends TrellisAPI = TrellisAPI> = {
5
+ CONTRACT_ID: string;
6
+ CONTRACT_DIGEST: string;
7
+ API: {
8
+ trellis: TApi;
9
+ };
10
+ };
11
+ type DeviceConnectTransport = {
12
+ connect(options: {
13
+ servers: string | string[];
14
+ token?: string;
15
+ authenticator?: unknown;
16
+ inboxPrefix?: string;
17
+ }): Promise<NatsConnection>;
18
+ };
19
+ type DeviceConnectDeps = {
20
+ loadTransport(): Promise<DeviceConnectTransport>;
21
+ now(): number;
22
+ };
23
+ export type DeviceActivationController = {
24
+ url: string;
25
+ waitForOnlineApproval(opts?: {
26
+ signal?: AbortSignal;
27
+ }): Promise<void>;
28
+ acceptConfirmationCode(code: string): Promise<void>;
29
+ };
30
+ export type TrellisDeviceConnectArgs<TApi extends TrellisAPI = TrellisAPI> = {
31
+ trellisUrl: string;
32
+ contract: DeviceContract<TApi>;
33
+ rootSecret: Uint8Array | string;
34
+ onActivationRequired?(activation: DeviceActivationController): Promise<void>;
35
+ };
36
+ export declare function connectDeviceWithDeps<TApi extends TrellisAPI>(args: TrellisDeviceConnectArgs<TApi>, deps: DeviceConnectDeps): Promise<Trellis<TApi>>;
37
+ export declare const TrellisDevice: {
38
+ connect<TApi extends TrellisAPI>(args: TrellisDeviceConnectArgs<TApi>): Promise<Trellis<TApi>>;
39
+ };
40
+ export {};
41
+ //# sourceMappingURL=device.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../../../device.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAa3E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAIvC,KAAK,cAAc,CAAC,IAAI,SAAS,UAAU,GAAG,UAAU,IAAI;IAC1D,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,GAAG,EAAE;QACH,OAAO,EAAE,IAAI,CAAC;KACf,CAAC;CACH,CAAC;AAEF,KAAK,sBAAsB,GAAG;IAC5B,OAAO,CAAC,OAAO,EAAE;QACf,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,aAAa,CAAC,EAAE,OAAO,CAAC;QACxB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CAC7B,CAAC;AAEF,KAAK,iBAAiB,GAAG;IACvB,aAAa,IAAI,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACjD,GAAG,IAAI,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,qBAAqB,CAAC,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtE,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrD,CAAC;AAEF,MAAM,MAAM,wBAAwB,CAAC,IAAI,SAAS,UAAU,GAAG,UAAU,IAAI;IAC3E,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,cAAc,CAAC,IAAI,CAAC,CAAC;IAC/B,UAAU,EAAE,UAAU,GAAG,MAAM,CAAC;IAChC,oBAAoB,CAAC,CAAC,UAAU,EAAE,0BAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9E,CAAC;AA0GF,wBAAsB,qBAAqB,CAAC,IAAI,SAAS,UAAU,EACjE,IAAI,EAAE,wBAAwB,CAAC,IAAI,CAAC,EACpC,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CA2HxB;AAED,eAAO,MAAM,aAAa;YAChB,IAAI,SAAS,UAAU,QACvB,wBAAwB,CAAC,IAAI,CAAC,GACnC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;CAG1B,CAAC"}
@@ -0,0 +1,213 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TrellisDevice = void 0;
4
+ exports.connectDeviceWithDeps = connectDeviceWithDeps;
5
+ const nats_core_1 = require("@nats-io/nats-core");
6
+ const device_activation_ts_1 = require("../auth/device_activation.ts");
7
+ const keys_ts_1 = require("../auth/keys.ts");
8
+ const utils_ts_1 = require("../auth/utils.ts");
9
+ const runtime_transport_ts_1 = require("./runtime_transport.ts");
10
+ const trellis_ts_1 = require("./trellis.ts");
11
+ const typebox_1 = require("typebox");
12
+ const value_1 = require("typebox/value");
13
+ const DeviceBootstrapReadySchema = typebox_1.Type.Object({
14
+ status: typebox_1.Type.Literal("ready"),
15
+ connectInfo: typebox_1.Type.Object({
16
+ instanceId: typebox_1.Type.String({ minLength: 1 }),
17
+ profileId: typebox_1.Type.String({ minLength: 1 }),
18
+ contractId: typebox_1.Type.String({ minLength: 1 }),
19
+ contractDigest: typebox_1.Type.String({ minLength: 1 }),
20
+ transport: typebox_1.Type.Object({
21
+ natsServers: typebox_1.Type.Array(typebox_1.Type.String({ minLength: 1 }), { minItems: 1 }),
22
+ sentinel: typebox_1.Type.Object({
23
+ jwt: typebox_1.Type.String({ minLength: 1 }),
24
+ seed: typebox_1.Type.String({ minLength: 1 }),
25
+ }, { additionalProperties: false }),
26
+ }, { additionalProperties: false }),
27
+ auth: typebox_1.Type.Object({
28
+ mode: typebox_1.Type.Literal("device_identity"),
29
+ iatSkewSeconds: typebox_1.Type.Integer({ minimum: 1 }),
30
+ }, { additionalProperties: false }),
31
+ }, { additionalProperties: false }),
32
+ }, { additionalProperties: false });
33
+ const DeviceBootstrapActivationRequiredSchema = typebox_1.Type.Object({
34
+ status: typebox_1.Type.Literal("activation_required"),
35
+ }, { additionalProperties: false });
36
+ const DeviceBootstrapNotReadySchema = typebox_1.Type.Object({
37
+ status: typebox_1.Type.Literal("not_ready"),
38
+ reason: typebox_1.Type.String({ minLength: 1 }),
39
+ }, { additionalProperties: false });
40
+ function normalizeRootSecret(rootSecret) {
41
+ if (typeof rootSecret === "string") {
42
+ const decoded = (0, utils_ts_1.base64urlDecode)(rootSecret.trim());
43
+ if (decoded.length === 0)
44
+ throw new Error("rootSecret must not be empty");
45
+ return decoded;
46
+ }
47
+ if (rootSecret.length === 0)
48
+ throw new Error("rootSecret must not be empty");
49
+ return rootSecret;
50
+ }
51
+ async function signIdentityBytes(identitySeed, data) {
52
+ const privateKey = await (0, keys_ts_1.importEd25519PrivateKeyFromSeedBase64url)((0, utils_ts_1.base64urlEncode)(identitySeed));
53
+ return new Uint8Array(await crypto.subtle.sign("Ed25519", privateKey, (0, utils_ts_1.toArrayBuffer)(data)));
54
+ }
55
+ const defaultDeps = {
56
+ loadTransport: runtime_transport_ts_1.loadDefaultRuntimeTransport,
57
+ now: () => Date.now(),
58
+ };
59
+ function activationRequiredError() {
60
+ return new Error("Device activation required but no activation handler was provided");
61
+ }
62
+ function isConnectInfoUnavailable(error) {
63
+ const message = error instanceof Error ? error.message : String(error);
64
+ return message.includes("404") || message.includes("unknown_device") || message.includes("activation_required");
65
+ }
66
+ async function fetchDeviceBootstrap(args) {
67
+ const request = await (0, device_activation_ts_1.signDeviceWaitRequest)({
68
+ publicIdentityKey: args.publicIdentityKey,
69
+ nonce: "connect-info",
70
+ identitySeed: args.identitySeed,
71
+ contractDigest: args.contractDigest,
72
+ iat: args.iat,
73
+ });
74
+ const bootstrapRequest = {
75
+ publicIdentityKey: request.publicIdentityKey,
76
+ contractDigest: request.contractDigest,
77
+ iat: request.iat,
78
+ sig: request.sig,
79
+ };
80
+ const response = await fetch(new URL("/bootstrap/device", args.trellisUrl), {
81
+ method: "POST",
82
+ headers: { "Content-Type": "application/json" },
83
+ body: JSON.stringify(bootstrapRequest),
84
+ });
85
+ if (!response.ok) {
86
+ throw new Error(`Device bootstrap failed: ${response.status} ${await response.text()}`);
87
+ }
88
+ const payload = await response.json();
89
+ if (value_1.Value.Check(DeviceBootstrapReadySchema, payload))
90
+ return payload;
91
+ if (value_1.Value.Check(DeviceBootstrapActivationRequiredSchema, payload))
92
+ return payload;
93
+ if (value_1.Value.Check(DeviceBootstrapNotReadySchema, payload))
94
+ return payload;
95
+ throw new Error("Device bootstrap returned an invalid response");
96
+ }
97
+ async function connectDeviceWithDeps(args, deps) {
98
+ const rootSecret = normalizeRootSecret(args.rootSecret);
99
+ const identity = await (0, device_activation_ts_1.deriveDeviceIdentity)(rootSecret);
100
+ const contractDigest = args.contract.CONTRACT_DIGEST;
101
+ let connectInfo = null;
102
+ try {
103
+ const bootstrap = await fetchDeviceBootstrap({
104
+ trellisUrl: args.trellisUrl,
105
+ publicIdentityKey: identity.publicIdentityKey,
106
+ identitySeed: identity.identitySeed,
107
+ contractDigest,
108
+ });
109
+ if (bootstrap.status === "ready") {
110
+ connectInfo = bootstrap.connectInfo;
111
+ }
112
+ else if (bootstrap.status === "not_ready") {
113
+ throw new Error(bootstrap.reason);
114
+ }
115
+ }
116
+ catch (error) {
117
+ if (!isConnectInfoUnavailable(error))
118
+ throw error;
119
+ }
120
+ if (!connectInfo) {
121
+ if (!args.onActivationRequired)
122
+ throw activationRequiredError();
123
+ const nonce = crypto.randomUUID();
124
+ const payload = await (0, device_activation_ts_1.buildDeviceActivationPayload)({
125
+ activationKey: identity.activationKey,
126
+ publicIdentityKey: identity.publicIdentityKey,
127
+ nonce,
128
+ });
129
+ const activationUrl = (0, device_activation_ts_1.buildDeviceActivationUrl)({
130
+ trellisUrl: args.trellisUrl,
131
+ payload,
132
+ });
133
+ let activationCompleted = false;
134
+ let onlineConnectInfo = null;
135
+ await args.onActivationRequired({
136
+ url: activationUrl,
137
+ waitForOnlineApproval: async (opts) => {
138
+ if (activationCompleted)
139
+ return;
140
+ const activation = await (0, device_activation_ts_1.waitForDeviceActivation)({
141
+ trellisUrl: args.trellisUrl,
142
+ publicIdentityKey: identity.publicIdentityKey,
143
+ nonce,
144
+ identitySeed: identity.identitySeed,
145
+ contractDigest,
146
+ signal: opts?.signal,
147
+ });
148
+ onlineConnectInfo = activation.connectInfo;
149
+ activationCompleted = true;
150
+ },
151
+ acceptConfirmationCode: async (code) => {
152
+ if (activationCompleted)
153
+ return;
154
+ const ok = await (0, device_activation_ts_1.verifyDeviceConfirmationCode)({
155
+ activationKey: identity.activationKey,
156
+ publicIdentityKey: identity.publicIdentityKey,
157
+ nonce,
158
+ confirmationCode: code,
159
+ });
160
+ if (!ok) {
161
+ throw new Error("Invalid device confirmation code");
162
+ }
163
+ activationCompleted = true;
164
+ },
165
+ });
166
+ if (!activationCompleted) {
167
+ throw new Error("Device activation did not complete");
168
+ }
169
+ if (onlineConnectInfo) {
170
+ connectInfo = onlineConnectInfo;
171
+ }
172
+ else {
173
+ const bootstrap = await fetchDeviceBootstrap({
174
+ trellisUrl: args.trellisUrl,
175
+ publicIdentityKey: identity.publicIdentityKey,
176
+ identitySeed: identity.identitySeed,
177
+ contractDigest,
178
+ });
179
+ if (bootstrap.status !== "ready") {
180
+ throw new Error(`Device bootstrap is not ready: ${bootstrap.status}`);
181
+ }
182
+ connectInfo = bootstrap.connectInfo;
183
+ }
184
+ }
185
+ if (!connectInfo) {
186
+ throw new Error("Device bootstrap did not return runtime connect info");
187
+ }
188
+ const transport = await deps.loadTransport();
189
+ const iat = Math.floor(deps.now() / 1_000);
190
+ const authToken = await (0, device_activation_ts_1.createDeviceNatsAuthToken)({
191
+ publicIdentityKey: identity.publicIdentityKey,
192
+ identitySeed: identity.identitySeed,
193
+ contractDigest,
194
+ iat,
195
+ });
196
+ const nc = await transport.connect({
197
+ servers: connectInfo.transport.natsServers,
198
+ token: JSON.stringify(authToken),
199
+ inboxPrefix: `_INBOX.${identity.publicIdentityKey.slice(0, 16)}`,
200
+ authenticator: (0, nats_core_1.jwtAuthenticator)(connectInfo.transport.sentinel.jwt, new TextEncoder().encode(connectInfo.transport.sentinel.seed)),
201
+ });
202
+ return new trellis_ts_1.Trellis(args.contract.CONTRACT_ID, nc, {
203
+ sessionKey: identity.publicIdentityKey,
204
+ sign: (data) => signIdentityBytes(identity.identitySeed, data),
205
+ }, {
206
+ api: args.contract.API.trellis,
207
+ });
208
+ }
209
+ exports.TrellisDevice = {
210
+ connect(args) {
211
+ return connectDeviceWithDeps(args, defaultDeps);
212
+ },
213
+ };
@@ -4,7 +4,7 @@ export declare const AuthErrorDataSchema: Type.TObject<{
4
4
  id: Type.TString;
5
5
  type: Type.TLiteral<"AuthError">;
6
6
  message: Type.TString;
7
- reason: Type.TUnion<[Type.TLiteral<"invalid_request">, Type.TLiteral<"missing_session_key">, Type.TLiteral<"missing_proof">, Type.TLiteral<"session_not_found">, Type.TLiteral<"session_expired">, Type.TLiteral<"invalid_signature">, Type.TLiteral<"user_not_found">, Type.TLiteral<"user_inactive">, Type.TLiteral<"unknown_workload">, Type.TLiteral<"workload_profile_not_found">, Type.TLiteral<"workload_profile_disabled">, Type.TLiteral<"workload_activation_revoked">, Type.TLiteral<"unknown_service">, Type.TLiteral<"service_disabled">, Type.TLiteral<"iat_out_of_range">, Type.TLiteral<"invalid_binding_token">, Type.TLiteral<"session_corrupted">, Type.TLiteral<"session_already_bound">, Type.TLiteral<"authtoken_already_used">, Type.TLiteral<"oauth_session_key_mismatch">, Type.TLiteral<"service_role_on_user">, Type.TLiteral<"reply_subject_mismatch">, Type.TLiteral<"insufficient_permissions">, Type.TLiteral<"forbidden">, Type.TLiteral<"missing_handoff_id">, Type.TLiteral<"missing_profile_id">, Type.TLiteral<"workload_activation_handoff_not_found">, Type.TLiteral<"workload_activation_handoff_expired">, Type.TLiteral<"workload_activation_rejected">, Type.TLiteral<"workload_identity_key_mismatch">, Type.TLiteral<"invalid_workload_qr_mac">]>;
7
+ reason: Type.TUnion<[Type.TLiteral<"invalid_request">, Type.TLiteral<"missing_session_key">, Type.TLiteral<"missing_proof">, Type.TLiteral<"session_not_found">, Type.TLiteral<"session_expired">, Type.TLiteral<"invalid_signature">, Type.TLiteral<"user_not_found">, Type.TLiteral<"user_inactive">, Type.TLiteral<"unknown_device">, Type.TLiteral<"device_profile_not_found">, Type.TLiteral<"device_profile_disabled">, Type.TLiteral<"device_activation_revoked">, Type.TLiteral<"unknown_service">, Type.TLiteral<"service_disabled">, Type.TLiteral<"iat_out_of_range">, Type.TLiteral<"invalid_binding_token">, Type.TLiteral<"session_corrupted">, Type.TLiteral<"session_already_bound">, Type.TLiteral<"authtoken_already_used">, Type.TLiteral<"oauth_session_key_mismatch">, Type.TLiteral<"service_role_on_user">, Type.TLiteral<"reply_subject_mismatch">, Type.TLiteral<"insufficient_permissions">, Type.TLiteral<"forbidden">, Type.TLiteral<"missing_handoff_id">, Type.TLiteral<"missing_profile_id">, Type.TLiteral<"device_activation_handoff_not_found">, Type.TLiteral<"device_activation_handoff_expired">, Type.TLiteral<"device_activation_rejected">, Type.TLiteral<"device_identity_key_mismatch">, Type.TLiteral<"invalid_device_qr_mac">]>;
8
8
  context: Type.TOptional<Type.TRecord<"^.*$", Type.TUnknown>>;
9
9
  traceId: Type.TOptional<Type.TString>;
10
10
  }>;
@@ -19,10 +19,10 @@ exports.AuthErrorDataSchema = typebox_1.default.Object({
19
19
  typebox_1.default.Literal("invalid_signature"),
20
20
  typebox_1.default.Literal("user_not_found"),
21
21
  typebox_1.default.Literal("user_inactive"),
22
- typebox_1.default.Literal("unknown_workload"),
23
- typebox_1.default.Literal("workload_profile_not_found"),
24
- typebox_1.default.Literal("workload_profile_disabled"),
25
- typebox_1.default.Literal("workload_activation_revoked"),
22
+ typebox_1.default.Literal("unknown_device"),
23
+ typebox_1.default.Literal("device_profile_not_found"),
24
+ typebox_1.default.Literal("device_profile_disabled"),
25
+ typebox_1.default.Literal("device_activation_revoked"),
26
26
  typebox_1.default.Literal("unknown_service"),
27
27
  typebox_1.default.Literal("service_disabled"),
28
28
  typebox_1.default.Literal("iat_out_of_range"),
@@ -37,11 +37,11 @@ exports.AuthErrorDataSchema = typebox_1.default.Object({
37
37
  typebox_1.default.Literal("forbidden"),
38
38
  typebox_1.default.Literal("missing_handoff_id"),
39
39
  typebox_1.default.Literal("missing_profile_id"),
40
- typebox_1.default.Literal("workload_activation_handoff_not_found"),
41
- typebox_1.default.Literal("workload_activation_handoff_expired"),
42
- typebox_1.default.Literal("workload_activation_rejected"),
43
- typebox_1.default.Literal("workload_identity_key_mismatch"),
44
- typebox_1.default.Literal("invalid_workload_qr_mac"),
40
+ typebox_1.default.Literal("device_activation_handoff_not_found"),
41
+ typebox_1.default.Literal("device_activation_handoff_expired"),
42
+ typebox_1.default.Literal("device_activation_rejected"),
43
+ typebox_1.default.Literal("device_identity_key_mismatch"),
44
+ typebox_1.default.Literal("invalid_device_qr_mac"),
45
45
  ]),
46
46
  context: typebox_1.default.Optional(typebox_1.default.Record(typebox_1.default.String(), typebox_1.default.Unknown())),
47
47
  traceId: typebox_1.default.Optional(typebox_1.default.String()),