@aithos/sdk 0.1.0-alpha.3 → 0.1.0-alpha.5

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 (46) hide show
  1. package/dist/src/auth-api.d.ts +41 -0
  2. package/dist/src/auth-api.js +82 -0
  3. package/dist/src/auth.d.ts +114 -75
  4. package/dist/src/auth.js +553 -73
  5. package/dist/src/compute.d.ts +8 -6
  6. package/dist/src/compute.js +19 -11
  7. package/dist/src/ethos.d.ts +117 -1
  8. package/dist/src/ethos.js +417 -16
  9. package/dist/src/index.d.ts +8 -4
  10. package/dist/src/index.js +26 -8
  11. package/dist/src/internal/delegate-bundle.d.ts +18 -0
  12. package/dist/src/internal/delegate-bundle.js +89 -0
  13. package/dist/src/internal/delegate-state.d.ts +45 -0
  14. package/dist/src/internal/delegate-state.js +120 -0
  15. package/dist/src/internal/owner-signers.d.ts +78 -0
  16. package/dist/src/internal/owner-signers.js +179 -0
  17. package/dist/src/internal/protocol-client-bridge.d.ts +8 -0
  18. package/dist/src/internal/protocol-client-bridge.js +20 -0
  19. package/dist/src/internal/recovery-file.d.ts +29 -0
  20. package/dist/src/internal/recovery-file.js +98 -0
  21. package/dist/src/internal/signer.d.ts +59 -0
  22. package/dist/src/internal/signer.js +86 -0
  23. package/dist/src/key-store.d.ts +128 -0
  24. package/dist/src/key-store.js +244 -0
  25. package/dist/src/mandates.d.ts +88 -1
  26. package/dist/src/mandates.js +185 -8
  27. package/dist/src/sdk.d.ts +36 -3
  28. package/dist/src/sdk.js +27 -23
  29. package/dist/src/session-store.d.ts +58 -0
  30. package/dist/src/session-store.js +158 -0
  31. package/dist/src/wallet.d.ts +4 -6
  32. package/dist/src/wallet.js +18 -8
  33. package/dist/test/auth-j3.test.d.ts +2 -0
  34. package/dist/test/auth-j3.test.js +360 -0
  35. package/dist/test/compute.test.js +22 -11
  36. package/dist/test/ethos.test.d.ts +2 -0
  37. package/dist/test/ethos.test.js +219 -0
  38. package/dist/test/key-store.test.d.ts +2 -0
  39. package/dist/test/key-store.test.js +161 -0
  40. package/dist/test/mandates.test.d.ts +2 -0
  41. package/dist/test/mandates.test.js +93 -0
  42. package/dist/test/sdk.test.js +64 -30
  43. package/dist/test/signer.test.d.ts +2 -0
  44. package/dist/test/signer.test.js +117 -0
  45. package/dist/test/wallet.test.js +20 -9
  46. package/package.json +4 -3
@@ -13,8 +13,9 @@
13
13
  // compute proxy at `${compute}/v1/invoke`. Read-only DDB GetItem on
14
14
  // the wallet table, gated by the same signed envelope verification
15
15
  // as compute_invoke. Returns the current balance + daily spent.
16
- import { buildSignedEnvelope, } from "@aithos/protocol-client";
16
+ import { buildSignedEnvelope } from "@aithos/protocol-client";
17
17
  import { computeInvokeUrl, walletTopupCheckoutUrl, } from "./endpoints.js";
18
+ import { ownerKeyPair } from "./internal/protocol-client-bridge.js";
18
19
  import { AithosSDKError } from "./types.js";
19
20
  /**
20
21
  * `sdk.wallet` namespace.
@@ -29,12 +30,16 @@ export class WalletNamespace {
29
30
  * hosted URL — the caller is responsible for redirecting the user (e.g.
30
31
  * `window.location.href = result.checkoutUrl`).
31
32
  *
32
- * On success, the Stripe webhook will credit `userDid`'s wallet once the
33
+ * On success, the Stripe webhook will credit the user's wallet once the
33
34
  * payment clears. Wallet balances are shared across all Aithos apps that
34
35
  * use the same DID.
35
36
  */
36
37
  async createTopupSession(args) {
37
- const { userDid, endpoints, fetch: fetchImpl } = this.#deps;
38
+ const { auth, endpoints, fetch: fetchImpl } = this.#deps;
39
+ const owner = auth._getOwnerSigners();
40
+ if (!owner || owner.destroyed) {
41
+ throw new AithosSDKError("sdk_no_owner", "no owner signed in; sign in first");
42
+ }
38
43
  const url = walletTopupCheckoutUrl(endpoints);
39
44
  let res;
40
45
  try {
@@ -42,7 +47,7 @@ export class WalletNamespace {
42
47
  method: "POST",
43
48
  headers: { "content-type": "application/json" },
44
49
  body: JSON.stringify({
45
- user_did: userDid,
50
+ user_did: owner.did,
46
51
  pack_id: args.packId,
47
52
  success_url: args.successUrl,
48
53
  cancel_url: args.cancelUrl,
@@ -88,16 +93,21 @@ export class WalletNamespace {
88
93
  * envelope-verify failures from the proxy).
89
94
  */
90
95
  async getBalance(args = {}) {
91
- const { identity, appDid, endpoints, fetch: fetchImpl } = this.#deps;
96
+ const { auth, appDid, endpoints, fetch: fetchImpl } = this.#deps;
97
+ const owner = auth._getOwnerSigners();
98
+ if (!owner || owner.destroyed) {
99
+ throw new AithosSDKError("sdk_no_owner", "no owner signed in; sign in first");
100
+ }
101
+ const publicKp = ownerKeyPair(owner, "public");
92
102
  const url = computeInvokeUrl(endpoints);
93
103
  const params = { app_did: appDid };
94
104
  const envelope = buildSignedEnvelope({
95
- iss: identity.did,
105
+ iss: owner.did,
96
106
  aud: url,
97
107
  method: "aithos.wallet_get_balance",
98
- verificationMethod: `${identity.did}#public`,
108
+ verificationMethod: `${owner.did}#public`,
99
109
  params,
100
- signer: identity.public,
110
+ signer: publicKp,
101
111
  });
102
112
  let res;
103
113
  try {
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=auth-j3.test.d.ts.map
@@ -0,0 +1,360 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright 2026 Mathieu Colla
3
+ // Tests for J3 — KeyStore integration, signInWithRecovery,
4
+ // importMandate, resume(), signOut(), state accessors.
5
+ import { strict as assert } from "node:assert";
6
+ import { describe, it } from "node:test";
7
+ import { createBrowserIdentity } from "@aithos/protocol-client";
8
+ import { AithosAuth, AithosSDKError, memoryKeyStore, noopStore, } from "../src/index.js";
9
+ import { parseDelegateBundle, readDelegateBundleText, } from "../src/internal/delegate-bundle.js";
10
+ import { parseRecoveryFile, serializeRecoveryFile, } from "../src/internal/recovery-file.js";
11
+ /* -------------------------------------------------------------------------- */
12
+ /* Test helpers */
13
+ /* -------------------------------------------------------------------------- */
14
+ function makeAuth(opts = {}) {
15
+ return new AithosAuth({
16
+ authBaseUrl: "https://auth.test",
17
+ fetch: (() => {
18
+ throw new Error("network not expected in this test");
19
+ }),
20
+ sessionStore: opts.sessionStore ?? noopStore(),
21
+ keyStore: opts.keyStore ?? memoryKeyStore(),
22
+ });
23
+ }
24
+ /** Build a recovery-file JSON string from a fresh BrowserIdentity. */
25
+ function recoveryTextFor(handle, displayName) {
26
+ const id = createBrowserIdentity(handle, displayName);
27
+ const { text } = serializeRecoveryFile(id);
28
+ return { text, did: id.did };
29
+ }
30
+ function delegateBundleText(args) {
31
+ return JSON.stringify({
32
+ aithos_delegate_version: "0.1.0",
33
+ mandate: {
34
+ id: args.mandateId,
35
+ subject_did: args.subjectDid,
36
+ grantee: {
37
+ id: args.granteeId,
38
+ pubkey: args.granteePubkeyMultibase ?? "z6MkqGenericPubKey",
39
+ },
40
+ scopes: args.scopes ?? ["ethos.read.public"],
41
+ },
42
+ delegate_seed_hex: "11".repeat(32),
43
+ });
44
+ }
45
+ /* -------------------------------------------------------------------------- */
46
+ /* parseRecoveryFile / serializeRecoveryFile */
47
+ /* -------------------------------------------------------------------------- */
48
+ describe("recovery file: parse + serialize", () => {
49
+ it("round-trips a fresh identity", () => {
50
+ const id = createBrowserIdentity("alice", "Alice");
51
+ const { text } = serializeRecoveryFile(id);
52
+ const parsed = parseRecoveryFile(text);
53
+ assert.equal(parsed.did, id.did);
54
+ assert.equal(parsed.handle, id.handle);
55
+ assert.equal(parsed.displayName, id.displayName);
56
+ assert.equal(parsed.seedsHex.root.length, 64);
57
+ });
58
+ it("accepts the runOnboarding shape (warning + created_at)", () => {
59
+ const id = createBrowserIdentity("bob", "Bob");
60
+ const text = JSON.stringify({
61
+ aithos_recovery_version: "0.1.0-plaintext",
62
+ warning: "this is plaintext, store offline",
63
+ handle: id.handle,
64
+ display_name: id.displayName,
65
+ did: id.did,
66
+ created_at: new Date().toISOString(),
67
+ seeds_hex: {
68
+ root: bytesToHex(id.root.seed),
69
+ public: bytesToHex(id.public.seed),
70
+ circle: bytesToHex(id.circle.seed),
71
+ self: bytesToHex(id.self.seed),
72
+ },
73
+ public_keys_multibase: {},
74
+ });
75
+ const parsed = parseRecoveryFile(text);
76
+ assert.equal(parsed.did, id.did);
77
+ });
78
+ it("rejects unsupported versions", () => {
79
+ assert.throws(() => parseRecoveryFile(JSON.stringify({ aithos_recovery_version: "9.9.9" })), (e) => e instanceof AithosSDKError && e.code === "auth_invalid_recovery_file");
80
+ });
81
+ it("rejects malformed seeds", () => {
82
+ const id = createBrowserIdentity("alice", "Alice");
83
+ const { text } = serializeRecoveryFile(id);
84
+ const obj = JSON.parse(text);
85
+ obj.seeds_hex.root = "not hex";
86
+ assert.throws(() => parseRecoveryFile(JSON.stringify(obj)), AithosSDKError);
87
+ });
88
+ });
89
+ /* -------------------------------------------------------------------------- */
90
+ /* parseDelegateBundle */
91
+ /* -------------------------------------------------------------------------- */
92
+ describe("delegate bundle: parse", () => {
93
+ it("parses a well-formed bundle", () => {
94
+ const text = delegateBundleText({
95
+ mandateId: "mandate:01H8XYZ",
96
+ subjectDid: "did:aithos:zCarol",
97
+ granteeId: "urn:aithos:agent:bob1",
98
+ scopes: ["ethos.read.public", "ethos.write.public"],
99
+ });
100
+ const parsed = parseDelegateBundle(text);
101
+ assert.equal(parsed.mandateId, "mandate:01H8XYZ");
102
+ assert.equal(parsed.subjectDid, "did:aithos:zCarol");
103
+ assert.equal(parsed.granteeId, "urn:aithos:agent:bob1");
104
+ assert.equal(parsed.delegateSeedHex.length, 64);
105
+ });
106
+ it("readDelegateBundleText accepts string passthrough", async () => {
107
+ const text = delegateBundleText({
108
+ mandateId: "m",
109
+ subjectDid: "did:aithos:z",
110
+ granteeId: "urn:x",
111
+ });
112
+ assert.equal(await readDelegateBundleText(text), text);
113
+ });
114
+ it("rejects missing mandate", () => {
115
+ assert.throws(() => parseDelegateBundle(JSON.stringify({
116
+ aithos_delegate_version: "0.1.0",
117
+ delegate_seed_hex: "11".repeat(32),
118
+ })), AithosSDKError);
119
+ });
120
+ it("rejects malformed delegate seed", () => {
121
+ assert.throws(() => parseDelegateBundle(JSON.stringify({
122
+ aithos_delegate_version: "0.1.0",
123
+ mandate: {
124
+ id: "m",
125
+ subject_did: "did:aithos:z",
126
+ grantee: { id: "u", pubkey: "z6MkXYZ" },
127
+ },
128
+ delegate_seed_hex: "not hex",
129
+ })), AithosSDKError);
130
+ });
131
+ });
132
+ /* -------------------------------------------------------------------------- */
133
+ /* AithosAuth — recovery sign-in */
134
+ /* -------------------------------------------------------------------------- */
135
+ describe("AithosAuth.signInWithRecovery", () => {
136
+ it("hydrates owner signers + persists to keyStore (no JWT)", async () => {
137
+ const keyStore = memoryKeyStore();
138
+ const sessionStore = noopStore();
139
+ const auth = makeAuth({ sessionStore, keyStore });
140
+ assert.equal(auth.canSignAsOwner(), false);
141
+ assert.equal(auth.getOwnerInfo(), null);
142
+ const { text } = recoveryTextFor("alice", "Alice");
143
+ const info = await auth.signInWithRecovery({ file: text });
144
+ assert.equal(info.handle, "alice");
145
+ assert.equal(auth.canSignAsOwner(), true);
146
+ assert.equal(auth.getOwnerInfo()?.did, info.did);
147
+ assert.equal(auth.getCurrentSession(), null, "no JWT for recovery flow");
148
+ const persisted = await keyStore.loadOwner();
149
+ assert.equal(persisted?.did, info.did);
150
+ });
151
+ it("rejects loading a different owner without signOut first", async () => {
152
+ const auth = makeAuth();
153
+ const a = recoveryTextFor("alice", "Alice");
154
+ await auth.signInWithRecovery({ file: a.text });
155
+ const b = recoveryTextFor("bob", "Bob");
156
+ await assert.rejects(() => auth.signInWithRecovery({ file: b.text }), (e) => e instanceof AithosSDKError && e.code === "auth_owner_already_loaded");
157
+ });
158
+ it("clears any stale JWT to keep stores in sync", async () => {
159
+ const keyStore = memoryKeyStore();
160
+ let stored = {
161
+ session: "stale-jwt",
162
+ exp: Math.floor(Date.now() / 1000) + 3600,
163
+ did: "did:aithos:zStale",
164
+ handle: "stale",
165
+ blob_b64: "",
166
+ blob_nonce_b64: "",
167
+ blob_version: 0,
168
+ enc_key_b64: "",
169
+ is_first_login: false,
170
+ };
171
+ const sessionStore = {
172
+ get: () => stored,
173
+ set: (s) => {
174
+ stored = s;
175
+ },
176
+ clear: () => {
177
+ stored = null;
178
+ },
179
+ };
180
+ const auth = makeAuth({ sessionStore, keyStore });
181
+ const { text } = recoveryTextFor("alice", "Alice");
182
+ await auth.signInWithRecovery({ file: text });
183
+ assert.equal(stored, null, "stale JWT must be wiped");
184
+ });
185
+ });
186
+ /* -------------------------------------------------------------------------- */
187
+ /* AithosAuth — importMandate */
188
+ /* -------------------------------------------------------------------------- */
189
+ describe("AithosAuth.importMandate", () => {
190
+ it("registers a delegate, lists it, removes it", async () => {
191
+ const keyStore = memoryKeyStore();
192
+ const auth = makeAuth({ keyStore });
193
+ const text = delegateBundleText({
194
+ mandateId: "mandate:A",
195
+ subjectDid: "did:aithos:zCarol",
196
+ granteeId: "urn:aithos:agent:bob1",
197
+ scopes: ["ethos.read.circle"],
198
+ });
199
+ const info = await auth.importMandate({ bundle: text });
200
+ assert.equal(info.mandateId, "mandate:A");
201
+ assert.equal(info.subjectDid, "did:aithos:zCarol");
202
+ assert.deepEqual(info.scopes, ["ethos.read.circle"]);
203
+ const list = auth.getDelegates();
204
+ assert.equal(list.length, 1);
205
+ assert.equal(list[0]?.mandateId, "mandate:A");
206
+ assert.equal(auth.canSignAsDelegateFor("did:aithos:zCarol"), true);
207
+ assert.equal(auth.canSignAsDelegateFor("did:aithos:zNobody"), false);
208
+ await auth.removeMandate("mandate:A");
209
+ assert.equal(auth.getDelegates().length, 0);
210
+ assert.equal((await keyStore.listDelegates()).length, 0);
211
+ });
212
+ it("works without an owner loaded (delegate-only session)", async () => {
213
+ const auth = makeAuth();
214
+ assert.equal(auth.canSignAsOwner(), false);
215
+ const text = delegateBundleText({
216
+ mandateId: "mandate:Solo",
217
+ subjectDid: "did:aithos:zCarol",
218
+ granteeId: "urn:aithos:agent:solo1",
219
+ });
220
+ await auth.importMandate({ bundle: text });
221
+ assert.equal(auth.canSignAsOwner(), false);
222
+ assert.equal(auth.canSignAsDelegateFor("did:aithos:zCarol"), true);
223
+ });
224
+ it("re-importing the same mandate replaces the prior actor", async () => {
225
+ const auth = makeAuth();
226
+ const text = delegateBundleText({
227
+ mandateId: "mandate:R",
228
+ subjectDid: "did:aithos:zCarol",
229
+ granteeId: "urn:aithos:agent:r",
230
+ });
231
+ await auth.importMandate({ bundle: text });
232
+ await auth.importMandate({ bundle: text });
233
+ assert.equal(auth.getDelegates().length, 1);
234
+ });
235
+ });
236
+ /* -------------------------------------------------------------------------- */
237
+ /* AithosAuth — resume() */
238
+ /* -------------------------------------------------------------------------- */
239
+ describe("AithosAuth.resume", () => {
240
+ it("rehydrates owner + delegates from keyStore on a fresh instance", async () => {
241
+ const keyStore = memoryKeyStore();
242
+ const sessionStore = noopStore();
243
+ // Seed the stores via a first auth instance.
244
+ {
245
+ const auth1 = makeAuth({ keyStore, sessionStore });
246
+ const { text: rt } = recoveryTextFor("alice", "Alice");
247
+ await auth1.signInWithRecovery({ file: rt });
248
+ const dt = delegateBundleText({
249
+ mandateId: "mandate:M1",
250
+ subjectDid: "did:aithos:zCarol",
251
+ granteeId: "urn:x",
252
+ });
253
+ await auth1.importMandate({ bundle: dt });
254
+ }
255
+ // Fresh instance, same stores → resume() must reload everything.
256
+ const auth2 = makeAuth({ keyStore, sessionStore });
257
+ assert.equal(auth2.canSignAsOwner(), false, "before resume, in-memory only");
258
+ await auth2.resume();
259
+ assert.equal(auth2.canSignAsOwner(), true);
260
+ assert.equal(auth2.getOwnerInfo()?.handle, "alice");
261
+ assert.equal(auth2.getDelegates().length, 1);
262
+ assert.equal(auth2.canSignAsDelegateFor("did:aithos:zCarol"), true);
263
+ });
264
+ it("strict mode: JWT in sessionStore but no owner in keyStore → wipes JWT", async () => {
265
+ let jwt = {
266
+ session: "j",
267
+ exp: Math.floor(Date.now() / 1000) + 3600,
268
+ did: "did:aithos:zGhost",
269
+ handle: "ghost",
270
+ blob_b64: "",
271
+ blob_nonce_b64: "",
272
+ blob_version: 0,
273
+ enc_key_b64: "",
274
+ is_first_login: false,
275
+ };
276
+ const sessionStore = {
277
+ get: () => jwt,
278
+ set: (s) => {
279
+ jwt = s;
280
+ },
281
+ clear: () => {
282
+ jwt = null;
283
+ },
284
+ };
285
+ const keyStore = memoryKeyStore();
286
+ const auth = makeAuth({ keyStore, sessionStore });
287
+ await auth.resume();
288
+ assert.equal(jwt, null, "out-of-sync JWT must be cleared");
289
+ assert.equal(auth.canSignAsOwner(), false);
290
+ });
291
+ it("strict mode: JWT and owner disagree on DID → wipes JWT only", async () => {
292
+ const keyStore = memoryKeyStore();
293
+ const { text } = recoveryTextFor("alice", "Alice");
294
+ // Seed the keystore with alice via one instance.
295
+ {
296
+ const auth1 = makeAuth({ keyStore });
297
+ await auth1.signInWithRecovery({ file: text });
298
+ }
299
+ // Now plant a JWT for a DIFFERENT DID in the session store.
300
+ let jwt = {
301
+ session: "j",
302
+ exp: Math.floor(Date.now() / 1000) + 3600,
303
+ did: "did:aithos:zSomeoneElse",
304
+ handle: "someone",
305
+ blob_b64: "",
306
+ blob_nonce_b64: "",
307
+ blob_version: 0,
308
+ enc_key_b64: "",
309
+ is_first_login: false,
310
+ };
311
+ const sessionStore = {
312
+ get: () => jwt,
313
+ set: (s) => {
314
+ jwt = s;
315
+ },
316
+ clear: () => {
317
+ jwt = null;
318
+ },
319
+ };
320
+ const auth2 = makeAuth({ keyStore, sessionStore });
321
+ await auth2.resume();
322
+ assert.equal(jwt, null, "mismatched JWT must be wiped");
323
+ // Owner is preserved (it's the source of truth in strict mode).
324
+ assert.equal(auth2.canSignAsOwner(), true);
325
+ assert.equal(auth2.getOwnerInfo()?.handle, "alice");
326
+ });
327
+ });
328
+ /* -------------------------------------------------------------------------- */
329
+ /* AithosAuth — signOut */
330
+ /* -------------------------------------------------------------------------- */
331
+ describe("AithosAuth.signOut", () => {
332
+ it("wipes both stores and in-memory state", async () => {
333
+ const keyStore = memoryKeyStore();
334
+ const auth = makeAuth({ keyStore });
335
+ const { text } = recoveryTextFor("alice", "Alice");
336
+ await auth.signInWithRecovery({ file: text });
337
+ const dt = delegateBundleText({
338
+ mandateId: "mandate:X",
339
+ subjectDid: "did:aithos:zCarol",
340
+ granteeId: "urn:x",
341
+ });
342
+ await auth.importMandate({ bundle: dt });
343
+ await auth.signOut();
344
+ assert.equal(auth.canSignAsOwner(), false);
345
+ assert.equal(auth.getOwnerInfo(), null);
346
+ assert.equal(auth.getDelegates().length, 0);
347
+ assert.equal(await keyStore.loadOwner(), null);
348
+ assert.equal((await keyStore.listDelegates()).length, 0);
349
+ });
350
+ });
351
+ /* -------------------------------------------------------------------------- */
352
+ /* Helpers */
353
+ /* -------------------------------------------------------------------------- */
354
+ function bytesToHex(b) {
355
+ let out = "";
356
+ for (let i = 0; i < b.length; i++)
357
+ out += b[i].toString(16).padStart(2, "0");
358
+ return out;
359
+ }
360
+ //# sourceMappingURL=auth-j3.test.js.map
@@ -9,12 +9,23 @@
9
9
  import { strict as assert } from "node:assert";
10
10
  import { describe, it } from "node:test";
11
11
  import { createBrowserIdentity } from "@aithos/protocol-client";
12
- import { AithosSDK, AithosSDKError } from "../src/index.js";
12
+ import { AithosAuth, AithosSDK, AithosSDKError, memoryKeyStore, noopStore, } from "../src/index.js";
13
+ import { serializeRecoveryFile } from "../src/internal/recovery-file.js";
13
14
  const APP_DID = "did:aithos:app:test";
14
- function makeSdk(fetchImpl) {
15
- const identity = createBrowserIdentity("test-handle", "Test User");
15
+ async function makeSdk(fetchImpl) {
16
+ const id = createBrowserIdentity("test-handle", "Test User");
17
+ const auth = new AithosAuth({
18
+ authBaseUrl: "https://auth.test",
19
+ fetch: (() => {
20
+ throw new Error("auth not used in compute tests");
21
+ }),
22
+ sessionStore: noopStore(),
23
+ keyStore: memoryKeyStore(),
24
+ });
25
+ const { text } = serializeRecoveryFile(id);
26
+ await auth.signInWithRecovery({ file: text });
16
27
  return new AithosSDK({
17
- identity,
28
+ auth,
18
29
  appDid: APP_DID,
19
30
  endpoints: { compute: "https://compute.example.test" },
20
31
  fetch: fetchImpl,
@@ -40,7 +51,7 @@ describe("compute.invokeBedrock — happy path", () => {
40
51
  headers: { "content-type": "application/json" },
41
52
  });
42
53
  };
43
- const sdk = makeSdk(fakeFetch);
54
+ const sdk = await makeSdk(fakeFetch);
44
55
  const out = await sdk.compute.invokeBedrock({
45
56
  mandateId: "mandate:abc",
46
57
  model: "claude-sonnet-4-6",
@@ -71,7 +82,7 @@ describe("compute.invokeBedrock — happy path", () => {
71
82
  headers: { "content-type": "application/json" },
72
83
  });
73
84
  };
74
- const sdk = makeSdk(fakeFetch);
85
+ const sdk = await makeSdk(fakeFetch);
75
86
  await sdk.compute.invokeBedrock({
76
87
  mandateId: "mandate:abc",
77
88
  model: "claude-sonnet-4-6",
@@ -92,7 +103,7 @@ describe("compute.invokeBedrock — errors", () => {
92
103
  const fakeFetch = async () => {
93
104
  throw new Error("fetch failed: ECONNREFUSED");
94
105
  };
95
- const sdk = makeSdk(fakeFetch);
106
+ const sdk = await makeSdk(fakeFetch);
96
107
  await assert.rejects(sdk.compute.invokeBedrock({
97
108
  mandateId: "mandate:abc",
98
109
  model: "claude-sonnet-4-6",
@@ -106,7 +117,7 @@ describe("compute.invokeBedrock — errors", () => {
106
117
  });
107
118
  it("wraps an HTTP non-2xx as AithosSDKError(code='http')", async () => {
108
119
  const fakeFetch = async () => new Response("nope", { status: 503, statusText: "Service Unavailable" });
109
- const sdk = makeSdk(fakeFetch);
120
+ const sdk = await makeSdk(fakeFetch);
110
121
  await assert.rejects(sdk.compute.invokeBedrock({
111
122
  mandateId: "mandate:abc",
112
123
  model: "claude-sonnet-4-6",
@@ -126,7 +137,7 @@ describe("compute.invokeBedrock — errors", () => {
126
137
  data: { balance: 0, required: 1 },
127
138
  },
128
139
  }), { status: 200, headers: { "content-type": "application/json" } });
129
- const sdk = makeSdk(fakeFetch);
140
+ const sdk = await makeSdk(fakeFetch);
130
141
  await assert.rejects(sdk.compute.invokeBedrock({
131
142
  mandateId: "mandate:abc",
132
143
  model: "claude-sonnet-4-6",
@@ -143,7 +154,7 @@ describe("compute.invokeBedrock — errors", () => {
143
154
  status: 200,
144
155
  headers: { "content-type": "application/json" },
145
156
  });
146
- const sdk = makeSdk(fakeFetch);
157
+ const sdk = await makeSdk(fakeFetch);
147
158
  await assert.rejects(sdk.compute.invokeBedrock({
148
159
  mandateId: "mandate:abc",
149
160
  model: "claude-sonnet-4-6",
@@ -165,7 +176,7 @@ describe("compute.invokeBedrock — abort", () => {
165
176
  headers: { "content-type": "application/json" },
166
177
  });
167
178
  };
168
- const sdk = makeSdk(fakeFetch);
179
+ const sdk = await makeSdk(fakeFetch);
169
180
  const ac = new AbortController();
170
181
  await sdk.compute.invokeBedrock({
171
182
  mandateId: "mandate:abc",
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ethos.test.d.ts.map