@aithos/sdk 0.1.0-alpha.6 → 0.1.0-alpha.60

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 (105) hide show
  1. package/README.md +202 -7
  2. package/dist/src/agent-dispatch.d.ts +18 -0
  3. package/dist/src/agent-dispatch.js +178 -0
  4. package/dist/src/agent-loop.d.ts +94 -0
  5. package/dist/src/agent-loop.js +95 -0
  6. package/dist/src/agent-tools.d.ts +24 -0
  7. package/dist/src/agent-tools.js +147 -0
  8. package/dist/src/apps.d.ts +224 -0
  9. package/dist/src/apps.js +432 -0
  10. package/dist/src/assets.d.ts +225 -0
  11. package/dist/src/assets.js +534 -0
  12. package/dist/src/auth-api.d.ts +219 -0
  13. package/dist/src/auth-api.js +248 -0
  14. package/dist/src/auth.d.ts +591 -0
  15. package/dist/src/auth.js +947 -31
  16. package/dist/src/compute.d.ts +674 -6
  17. package/dist/src/compute.js +968 -20
  18. package/dist/src/data-schema-contacts-v1.d.ts +14 -0
  19. package/dist/src/data-schema-contacts-v1.js +28 -0
  20. package/dist/src/data.d.ts +368 -0
  21. package/dist/src/data.js +1124 -0
  22. package/dist/src/endpoints.d.ts +43 -0
  23. package/dist/src/endpoints.js +23 -0
  24. package/dist/src/ethos.d.ts +85 -0
  25. package/dist/src/ethos.js +463 -7
  26. package/dist/src/index.d.ts +22 -4
  27. package/dist/src/index.js +47 -2
  28. package/dist/src/internal/cmk-wrap.d.ts +41 -0
  29. package/dist/src/internal/cmk-wrap.js +132 -0
  30. package/dist/src/internal/delegate-bundle.js +7 -2
  31. package/dist/src/internal/envelope.d.ts +93 -0
  32. package/dist/src/internal/envelope.js +59 -0
  33. package/dist/src/internal/owner-signers.d.ts +5 -2
  34. package/dist/src/internal/owner-signers.js +22 -1
  35. package/dist/src/internal/recovery-file.d.ts +2 -0
  36. package/dist/src/internal/recovery-file.js +7 -0
  37. package/dist/src/key-store.d.ts +10 -0
  38. package/dist/src/key-store.js +6 -0
  39. package/dist/src/mandates.d.ts +58 -1
  40. package/dist/src/mandates.js +46 -3
  41. package/dist/src/migrate.d.ts +105 -0
  42. package/dist/src/migrate.js +367 -0
  43. package/dist/src/react/AithosAsset.d.ts +66 -0
  44. package/dist/src/react/AithosAsset.js +67 -0
  45. package/dist/src/react/context.d.ts +29 -0
  46. package/dist/src/react/context.js +31 -0
  47. package/dist/src/react/index.d.ts +29 -0
  48. package/dist/src/react/index.js +31 -0
  49. package/dist/src/react/use-aithos-asset.d.ts +39 -0
  50. package/dist/src/react/use-aithos-asset.js +118 -0
  51. package/dist/src/react/use-transcribe-pending.d.ts +21 -0
  52. package/dist/src/react/use-transcribe-pending.js +47 -0
  53. package/dist/src/rotate.d.ts +94 -0
  54. package/dist/src/rotate.js +298 -0
  55. package/dist/src/sdk.d.ts +36 -2
  56. package/dist/src/sdk.js +72 -1
  57. package/dist/src/transcribe-resilience.d.ts +57 -0
  58. package/dist/src/transcribe-resilience.js +203 -0
  59. package/dist/src/web.d.ts +279 -0
  60. package/dist/src/web.js +186 -0
  61. package/dist/test/agent-dispatch.test.d.ts +2 -0
  62. package/dist/test/agent-dispatch.test.js +222 -0
  63. package/dist/test/agent-loop.test.d.ts +2 -0
  64. package/dist/test/agent-loop.test.js +117 -0
  65. package/dist/test/agent-tools.test.d.ts +2 -0
  66. package/dist/test/agent-tools.test.js +50 -0
  67. package/dist/test/auth-j3.test.js +32 -1
  68. package/dist/test/canonical-conformance.test.d.ts +2 -0
  69. package/dist/test/canonical-conformance.test.js +86 -0
  70. package/dist/test/compute-delegate-path.test.d.ts +2 -0
  71. package/dist/test/compute-delegate-path.test.js +183 -0
  72. package/dist/test/compute.test.js +4 -0
  73. package/dist/test/converse.test.d.ts +2 -0
  74. package/dist/test/converse.test.js +162 -0
  75. package/dist/test/data-sphere.test.d.ts +2 -0
  76. package/dist/test/data-sphere.test.js +57 -0
  77. package/dist/test/endpoints.test.js +40 -1
  78. package/dist/test/envelope-core-conformance.test.d.ts +2 -0
  79. package/dist/test/envelope-core-conformance.test.js +75 -0
  80. package/dist/test/envelope.test.d.ts +2 -0
  81. package/dist/test/envelope.test.js +318 -0
  82. package/dist/test/ethos-first-edition.test.d.ts +2 -0
  83. package/dist/test/ethos-first-edition.test.js +371 -0
  84. package/dist/test/invoke-turn-sdk.test.d.ts +2 -0
  85. package/dist/test/invoke-turn-sdk.test.js +177 -0
  86. package/dist/test/migrate.test.d.ts +2 -0
  87. package/dist/test/migrate.test.js +340 -0
  88. package/dist/test/owner-data-client.test.d.ts +2 -0
  89. package/dist/test/owner-data-client.test.js +88 -0
  90. package/dist/test/rotate-ethos.test.d.ts +2 -0
  91. package/dist/test/rotate-ethos.test.js +151 -0
  92. package/dist/test/rotate.test.d.ts +2 -0
  93. package/dist/test/rotate.test.js +63 -0
  94. package/dist/test/schema-autoresolve.test.d.ts +2 -0
  95. package/dist/test/schema-autoresolve.test.js +146 -0
  96. package/dist/test/sdk.test.js +11 -2
  97. package/dist/test/signup-bootstrap.test.d.ts +2 -0
  98. package/dist/test/signup-bootstrap.test.js +311 -0
  99. package/dist/test/transcribe-invoke.test.d.ts +2 -0
  100. package/dist/test/transcribe-invoke.test.js +204 -0
  101. package/dist/test/transcribe.test.d.ts +2 -0
  102. package/dist/test/transcribe.test.js +186 -0
  103. package/dist/test/web.test.d.ts +2 -0
  104. package/dist/test/web.test.js +270 -0
  105. package/package.json +20 -3
@@ -1,7 +1,9 @@
1
1
  import { type AithosSessionStore } from "./session-store.js";
2
2
  import { type AithosKeyStore } from "./key-store.js";
3
3
  import { DelegateActor } from "./internal/delegate-state.js";
4
+ import { type SignedEnvelope } from "./internal/envelope.js";
4
5
  import { OwnerSigners } from "./internal/owner-signers.js";
6
+ import { type DataClient, type AithosSchemaLite } from "./data.js";
5
7
  /** Default URL of the Aithos auth backend. */
6
8
  export declare const DEFAULT_AUTH_BASE_URL = "https://auth.aithos.be";
7
9
  /** Default URL of the Aithos primitives API (publish_identity, publish_ethos_edition, etc.). */
@@ -22,6 +24,22 @@ export interface AithosAuthConfig {
22
24
  readonly sessionStore?: AithosSessionStore;
23
25
  /** Pluggable key persistence. Defaults to {@link defaultKeyStore}. */
24
26
  readonly keyStore?: AithosKeyStore;
27
+ /**
28
+ * Public client key issued by Aithos for browser callers
29
+ * (`pk_<env>_<…>`). When set, the custodial endpoints (`signUpCustodial`,
30
+ * `verifyEmail`, `resendVerificationEmail`) authenticate as this app
31
+ * by default — the caller no longer has to repeat the key on every
32
+ * call. The corresponding `allowed_origins` allowlist must include the
33
+ * current page's origin.
34
+ *
35
+ * Safe to ship in the browser bundle: it grants nothing beyond what
36
+ * a visitor of the app can already do, is gated by Origin on every
37
+ * call, and is rate-limited per IP by the backend.
38
+ *
39
+ * If your app authenticates with a SECRET Bearer API key from a
40
+ * backend instead, leave this unset and pass `apiKey` per call.
41
+ */
42
+ readonly publicKey?: string;
25
43
  }
26
44
  /**
27
45
  * Active Aithos session. Returned by JWT-backed entry points
@@ -64,7 +82,31 @@ export interface DelegateInfo {
64
82
  readonly label?: string;
65
83
  }
66
84
  export interface SignInWithGoogleOptions {
85
+ /**
86
+ * Opaque state the consumer app wants to recover after the OAuth
87
+ * round-trip (e.g. a deep-link to resume on). Echoed back as
88
+ * `?app_state=` on the final redirect.
89
+ */
67
90
  readonly appState?: string;
91
+ /**
92
+ * App id registered in the Aithos `aithos-auth-apps` table. When set
93
+ * together with {@link returnTo}, the auth backend redirects the
94
+ * browser to {@link returnTo} (post Google + Aithos sign-in) instead
95
+ * of the legacy hard-coded `app.aithos.be/auth/callback`.
96
+ *
97
+ * The pair is required together: the backend rejects half-presence
98
+ * with `sso_app_redirect_pair_required`. Use it for any consumer app
99
+ * other than the canonical `app.aithos.be` (typically your own
100
+ * domain in prod, `http://localhost:<port>/auth/callback` in dev).
101
+ */
102
+ readonly appId?: string;
103
+ /**
104
+ * Where the auth backend should 302 the browser back to after a
105
+ * successful Google sign-in. MUST be on the app's
106
+ * `allowed_redirect_uris` allowlist (registered with Aithos out of
107
+ * band; see {@link appId}). Exact-match — wildcards rejected.
108
+ */
109
+ readonly returnTo?: string;
68
110
  }
69
111
  export interface SignInInput {
70
112
  readonly email: string;
@@ -81,6 +123,28 @@ export interface SignUpResult {
81
123
  readonly recoveryFile: Blob;
82
124
  readonly recoveryFilename: string;
83
125
  }
126
+ /**
127
+ * Input to {@link AithosAuth.completeSsoFirstLogin}. The handle is
128
+ * required (the auth backend pre-generated one from the user's email
129
+ * local-part, available on the session payload — we re-confirm it
130
+ * here so the user can edit before commit).
131
+ */
132
+ export interface CompleteSsoFirstLoginInput {
133
+ readonly handle: string;
134
+ readonly displayName?: string;
135
+ }
136
+ /**
137
+ * Result of {@link AithosAuth.completeSsoFirstLogin}. Returns a recovery
138
+ * file just like signUp — even though the user authenticated via Google,
139
+ * the freshly-generated Ed25519 seeds are the only material that can
140
+ * sign Aithos artifacts; without the recovery file, losing access to
141
+ * the Google account means losing the ethos forever.
142
+ */
143
+ export interface CompleteSsoFirstLoginResult {
144
+ readonly session: AithosSession;
145
+ readonly recoveryFile: Blob;
146
+ readonly recoveryFilename: string;
147
+ }
84
148
  export interface SignInWithRecoveryInput {
85
149
  /** Recovery file as a Blob (browser File input) or already-decoded JSON string. */
86
150
  readonly file: Blob | string;
@@ -89,6 +153,192 @@ export interface ImportMandateInput {
89
153
  /** Delegate bundle as a Blob or already-decoded JSON string. */
90
154
  readonly bundle: Blob | string;
91
155
  }
156
+ /**
157
+ * Input to {@link AithosAuth.inviteCustodial}. Sends an invitation magic link
158
+ * that carries an opaque payload (typically a delegate bundle) to deliver to
159
+ * the invitee on accept. Mandate-agnostic: `mandateBundle` may be ANY mandate
160
+ * (read/write/append/ethos/compute…) — the auth backend stores it verbatim,
161
+ * bound to a single-use token, and never parses it.
162
+ *
163
+ * The app authenticates via `apiKey` (server-only secret) or `publicKey`
164
+ * (browser-safe, Origin-gated), or the constructor's default `publicKey`.
165
+ * No user password here — the invitee chooses it when they accept.
166
+ */
167
+ export interface InviteCustodialInput {
168
+ readonly apiKey?: string;
169
+ readonly publicKey?: string;
170
+ /** Invitee email — receives the magic link. */
171
+ readonly email: string;
172
+ /**
173
+ * The mandate to deliver. Accept the SDK's `MintedMandate.bundle` (Blob),
174
+ * a JSON string, or a plain bundle object — all normalized to a JSON string.
175
+ */
176
+ readonly mandateBundle: Blob | string | Record<string, unknown>;
177
+ /** Token TTL in seconds (backend clamps to its policy). */
178
+ readonly ttlSeconds?: number;
179
+ /** Optional display name pre-filled on the pending account. */
180
+ readonly displayName?: string;
181
+ }
182
+ /** Result of {@link AithosAuth.inviteCustodial}. */
183
+ export interface InviteCustodialResult {
184
+ readonly status: "invited";
185
+ readonly email: string;
186
+ readonly mailSent: boolean;
187
+ readonly mailMessageId?: string;
188
+ }
189
+ /**
190
+ * Input to {@link AithosAuth.acceptInvite}. `email` and `token` come from the
191
+ * `?email=&token=` query string of the invitation link. `password` is set by
192
+ * the invitee for a NEW account, or used to authenticate an EXISTING one — so
193
+ * it's required whenever the user isn't already signed in.
194
+ */
195
+ export interface AcceptInviteInput {
196
+ readonly email: string;
197
+ readonly token: string;
198
+ readonly password?: string;
199
+ }
200
+ /**
201
+ * Result of {@link AithosAuth.acceptInvite}. The token is consumed, the
202
+ * session is hydrated (account created or existing one signed in), and the
203
+ * invited mandate has been imported into the keystore — `delegate` describes
204
+ * it. Read `delegate.subjectDid` to identify the issuer (e.g. resolve their
205
+ * public Ethos via `sdk.ethos.of(delegate.subjectDid)`).
206
+ */
207
+ export interface AcceptInviteResult {
208
+ readonly status: "signed_in";
209
+ readonly session: AithosSession;
210
+ readonly delegate: DelegateInfo;
211
+ /** True when a new account was provisioned; false when an existing one signed in. */
212
+ readonly accountCreated: boolean;
213
+ }
214
+ /**
215
+ * Input to {@link AithosAuth.signUpCustodial}.
216
+ *
217
+ * The caller authenticates as an app via ONE of:
218
+ * - `apiKey` : server-only secret Bearer. Pass from your backend
219
+ * only — never ship it in browser code.
220
+ * - `publicKey` : browser-safe public client key. Safe to embed in
221
+ * the bundle; the backend gates it by Origin and
222
+ * rate-limits by IP.
223
+ *
224
+ * If you set `publicKey` on the {@link AithosAuth} constructor, omit
225
+ * both fields here — the default credential is used.
226
+ *
227
+ * The `password` is always required and is chosen by the user (sign-up
228
+ * no longer auto-generates one). The created account starts as
229
+ * **pending** (`email_verified=false`); the user must click the
230
+ * confirmation link sent by SES before {@link signInCustodial} works.
231
+ */
232
+ export interface CustodialSignUpInput {
233
+ /** Server-only Bearer secret. Mutually exclusive with `publicKey`. */
234
+ readonly apiKey?: string;
235
+ /** Browser-safe public client key. Mutually exclusive with `apiKey`.
236
+ * Overrides the constructor's default `publicKey` when provided. */
237
+ readonly publicKey?: string;
238
+ /** Email address of the new user. Will receive the verification mail. */
239
+ readonly email: string;
240
+ /** Raw password the user chose. ≥ 10 chars, mix of letters with
241
+ * ≥ 1 digit or symbol. Enforced server-side. */
242
+ readonly password: string;
243
+ /** Optional display name. Capped at 200 chars by the backend. */
244
+ readonly displayName?: string;
245
+ /** Optional handle hint. Backend may sanitise or replace. */
246
+ readonly handleHint?: string;
247
+ }
248
+ /**
249
+ * Result of {@link AithosAuth.signUpCustodial}. Always carries
250
+ * `status: "pending_verification"` — the user must click the link in
251
+ * their inbox before sign-in works. If `mailSent` is false the row
252
+ * exists in DDB anyway; trigger {@link AithosAuth.resendVerificationEmail}
253
+ * to retry the SES send.
254
+ */
255
+ export interface CustodialSignUpResult {
256
+ readonly status: "pending_verification";
257
+ readonly email: string;
258
+ readonly mailSent: boolean;
259
+ readonly mailMessageId?: string;
260
+ }
261
+ /** Input to {@link AithosAuth.verifyEmail}. Both fields come straight
262
+ * out of the `?email=&token=` query string of the confirmation URL. */
263
+ export interface VerifyEmailInput {
264
+ readonly email: string;
265
+ readonly token: string;
266
+ }
267
+ /**
268
+ * Result of {@link AithosAuth.verifyEmail}. Discriminated by `status`.
269
+ *
270
+ * - `"signed_in"` (magic-link mode): the user has been authenticated
271
+ * in this call. A JWT session is persisted to the session store and
272
+ * the local keystore is hydrated with the unwrapped seed bundle.
273
+ * The caller can navigate the user straight to a logged-in area.
274
+ * - `"already_verified"`: the verification link had already been
275
+ * consumed on a previous click. No session is minted (the token is
276
+ * spent). The caller should route the user to the sign-in form.
277
+ */
278
+ export type VerifyEmailResult = {
279
+ readonly status: "signed_in";
280
+ readonly session: AithosSession;
281
+ readonly passwordMustChange: false;
282
+ } | {
283
+ readonly status: "already_verified";
284
+ readonly email: string;
285
+ };
286
+ /** Input to {@link AithosAuth.resendVerificationEmail}. The `email` is
287
+ * required; credential overrides follow the same rules as
288
+ * {@link CustodialSignUpInput}. */
289
+ export interface ResendVerificationInput {
290
+ readonly email: string;
291
+ readonly apiKey?: string;
292
+ readonly publicKey?: string;
293
+ }
294
+ export interface CustodialSignInInput {
295
+ readonly email: string;
296
+ readonly password: string;
297
+ }
298
+ /**
299
+ * Active custodial session. Same JWT-backed shape as {@link AithosSession}
300
+ * but adds a `passwordMustChange` flag the UI can honour to nudge the
301
+ * user toward a `requestPasswordReset` on first login.
302
+ */
303
+ export interface CustodialSignInResult {
304
+ readonly session: AithosSession;
305
+ readonly passwordMustChange: boolean;
306
+ }
307
+ export interface RequestPasswordResetInput {
308
+ readonly email: string;
309
+ }
310
+ /**
311
+ * Input to {@link AithosAuth.applyPasswordReset}. Finalises a password
312
+ * reset started by {@link AithosAuth.requestPasswordReset}. The `email`
313
+ * and `token` come straight from the magic-link URL that landed in the
314
+ * user's inbox (`?email=…&token=…`); the `newPassword` is what the user
315
+ * just typed in the reset page.
316
+ */
317
+ export interface ApplyPasswordResetInput {
318
+ /** Email address whose password is being reset. */
319
+ readonly email: string;
320
+ /** Raw reset token extracted from the magic-link URL query string. */
321
+ readonly token: string;
322
+ /** New password — must satisfy the backend's policy (≥ 10 chars). */
323
+ readonly newPassword: string;
324
+ }
325
+ /**
326
+ * Result of {@link AithosAuth.applyPasswordReset}. Carries a fresh JWT
327
+ * session so the UI can either redirect to a "you're now signed in"
328
+ * landing or prompt the user to sign in explicitly with their new
329
+ * credentials — same {@link CustodialSignInResult} shape as a normal
330
+ * sign-in.
331
+ *
332
+ * Note: unlike {@link signInCustodial}, this DOES NOT hydrate the local
333
+ * keystore. The reset path on the auth Lambda re-wraps the seed bundle
334
+ * with KMS but doesn't return it (the user just typed a password — they
335
+ * still need to sign in once to materialise the seeds locally). The
336
+ * {@link AithosSession} returned here lets the app store the JWT and
337
+ * call {@link signInCustodial} to complete hydration.
338
+ */
339
+ export interface ApplyPasswordResetResult {
340
+ readonly session: AithosSession;
341
+ }
92
342
  export declare class AithosAuth {
93
343
  #private;
94
344
  readonly authBaseUrl: string;
@@ -114,6 +364,70 @@ export declare class AithosAuth {
114
364
  getOwnerInfo(): OwnerInfo | null;
115
365
  getDelegates(): readonly DelegateInfo[];
116
366
  canSignAsOwner(): boolean;
367
+ /**
368
+ * Sign an envelope (spec §11.2) as the active owner, to authenticate
369
+ * a call to a third-party Aithos-aware backend.
370
+ *
371
+ * Same primitive that SDK namespaces (`sdk.data`, `sdk.ethos`,
372
+ * `sdk.mandates`, ...) use internally to sign their own writes to
373
+ * `api.aithos.be`. Exposed here so apps can sign envelopes for their
374
+ * own backends — any service that verifies a `SignedEnvelope` per
375
+ * spec §11.2 (typically using `@aithos/protocol-core/envelope`'s
376
+ * `verifyEnvelope`) accepts the resulting object.
377
+ *
378
+ * The envelope binds the signature to `(iss, aud, method,
379
+ * params_hash, nonce, iat, exp)`, so it cannot be replayed against a
380
+ * different endpoint, method, or payload, and expires after
381
+ * `ttlSeconds` (default 60s, server-side typically caps at 300s).
382
+ *
383
+ * Usage:
384
+ *
385
+ * ```ts
386
+ * const envelope = await sdk.auth.signEnvelope({
387
+ * aud: "https://api.example.com/v1/widgets",
388
+ * method: "myapp.widgets.create",
389
+ * params: { name: "Widget #1" },
390
+ * });
391
+ * await fetch("https://api.example.com/v1/widgets", {
392
+ * method: "POST",
393
+ * headers: { "content-type": "application/json" },
394
+ * body: JSON.stringify({ ...payload, _envelope: envelope }),
395
+ * });
396
+ * ```
397
+ *
398
+ * @throws {AithosSDKError} `auth_not_signed_in` if no owner identity
399
+ * is loaded (call `signIn` / `signUp` / `signInCustodial` first).
400
+ * @throws {AithosSDKError} `auth_invalid_sphere` if `sphere` is not
401
+ * one of `"root" | "public" | "circle" | "self"`.
402
+ */
403
+ signEnvelope(args: {
404
+ /**
405
+ * Absolute URL of the target endpoint (scheme + host + path, no
406
+ * query, no fragment). The receiving server rejects the envelope if
407
+ * `aud` does not match the actual request URL.
408
+ */
409
+ readonly aud: string;
410
+ /** Fully-qualified JSON-RPC method name. */
411
+ readonly method: string;
412
+ /**
413
+ * Tool payload — what `params_hash` commits to. Will be
414
+ * JCS-canonicalized (RFC 8785 subset) before hashing, so JS object
415
+ * key order does not affect the result.
416
+ */
417
+ readonly params: unknown;
418
+ /**
419
+ * Which of the owner's four sphere keys signs. Default: `"public"`,
420
+ * which matches what SDK namespaces use for everyday writes.
421
+ * Choose `"root"`, `"circle"`, or `"self"` only if the receiving
422
+ * server specifically expects one of those (rare).
423
+ */
424
+ readonly sphere?: "root" | "public" | "circle" | "self" | "data";
425
+ /**
426
+ * Envelope lifetime in seconds. Default 60. Aithos servers cap
427
+ * at 300; third-party servers may apply their own cap.
428
+ */
429
+ readonly ttlSeconds?: number;
430
+ }): Promise<SignedEnvelope>;
117
431
  canSignAsDelegateFor(did: string): boolean;
118
432
  /**
119
433
  * Internal accessor used by sibling SDK namespaces (compute, wallet,
@@ -123,6 +437,64 @@ export declare class AithosAuth {
123
437
  * @internal
124
438
  */
125
439
  _getOwnerSigners(): OwnerSigners | null;
440
+ /**
441
+ * Ready-made owner data client bound to the signed-in account, signing +
442
+ * sealing under the dedicated **`#data`** sphere (the protocol-intended owner
443
+ * data key). This is the one-liner apps should use instead of hand-rolling
444
+ * `createDataClient` with a raw seed — hand-rolling with `#root` is exactly
445
+ * what left legacy collections sealed to the wrong key.
446
+ *
447
+ * const data = auth.ownerDataClient({ schemas: [myVendorLite] });
448
+ * await data.collection("notes").insert({ ... }); // owned under #data
449
+ *
450
+ * Throws when no owner is signed in, or when the account has no `#data`
451
+ * sphere (legacy accounts created before #data, or imported from a 4-seed
452
+ * recovery). Add one first with `rotateEthos` / the migration scripts, then
453
+ * re-import the resulting recovery — the error message says so.
454
+ *
455
+ * @param args.pdsUrl PDS base URL. Defaults to the SDK default (pds.aithos.be).
456
+ * @param args.schemas Vendor `AithosSchemaLite` definitions to register for
457
+ * WRITES (reads auto-resolve published schemas from the PDS).
458
+ */
459
+ ownerDataClient(args?: {
460
+ readonly pdsUrl?: string;
461
+ readonly schemas?: readonly AithosSchemaLite[];
462
+ }): DataClient;
463
+ /**
464
+ * Ready-made DELEGATE data client, bound to a mandate held in this session
465
+ * (imported via `importMandate` / an accepted invite). Same record-CRUD
466
+ * surface as the owner client, bounded by the mandate's scope — you never
467
+ * pass a key, a sphere, or the mandate itself to the data calls.
468
+ *
469
+ * const db = auth.delegateDataClient(); // single active mandate
470
+ * await db.collection("prospects").insert({ ... }); // needs data.prospects.write
471
+ *
472
+ * With several active mandates, pass `{ subjectDid }` or `{ mandateId }`.
473
+ * Owner-only ops (createCollection, authorizeDelegate, …) throw -32042 — the
474
+ * owner does those once, at onboarding.
475
+ */
476
+ delegateDataClient(args?: {
477
+ readonly subjectDid?: string;
478
+ readonly mandateId?: string;
479
+ readonly pdsUrl?: string;
480
+ readonly schemas?: readonly AithosSchemaLite[];
481
+ }): DataClient;
482
+ /**
483
+ * Unified data accessor — the database for "however you connected":
484
+ * - signed in as owner → your own collections under `#data`;
485
+ * - acting under an imported mandate → the subject's collections (per scope).
486
+ *
487
+ * Identical CRUD surface either way; the developer never sees a sphere, a
488
+ * key, or the mandate. The mode follows how you authenticated, not a flag on
489
+ * the data calls.
490
+ *
491
+ * const db = auth.data;
492
+ * await db.collection("prospects").insert({ ... });
493
+ *
494
+ * Only ambiguous when you are BOTH signed in as owner AND holding mandates;
495
+ * then call `ownerDataClient()` / `delegateDataClient({ … })` explicitly.
496
+ */
497
+ get data(): DataClient;
126
498
  /**
127
499
  * Internal accessor — looks up an active delegate by mandate id.
128
500
  * @internal
@@ -135,6 +507,42 @@ export declare class AithosAuth {
135
507
  * @internal
136
508
  */
137
509
  _findDelegateForSubject(did: string): DelegateActor | undefined;
510
+ /**
511
+ * Sign in with email + password, dispatching automatically between
512
+ * the legacy zero-knowledge flow ({@link signIn}) and the custodial
513
+ * flow ({@link signInCustodial}) based on which mode the account
514
+ * was provisioned with.
515
+ *
516
+ * Use this in apps that want a single sign-in form for users who
517
+ * may have been created under either mode (e.g. an app that's
518
+ * migrating from zk to custodial — pre-existing users stay zk
519
+ * forever, new ones go custodial, the SDK figures it out).
520
+ *
521
+ * Strategy: try {@link signInCustodial} first (the modern path).
522
+ * If the backend reports `auth_invalid_credentials` — which it
523
+ * uniformly returns for "wrong password", "unknown user", AND
524
+ * "user exists but not in custodial mode" (anti-enum) — fall
525
+ * back to {@link signIn} (zk).
526
+ *
527
+ * Other failure modes from the custodial path are NOT swallowed:
528
+ * - `auth_email_not_verified` → propagate (user is custodial but
529
+ * hasn't clicked the confirmation link yet; the app should
530
+ * surface a "resend mail" CTA rather than retrying as zk,
531
+ * which would also fail and mask the real cause)
532
+ * - server / network errors → propagate (don't double the
533
+ * incident by retrying through the other flow)
534
+ *
535
+ * Latency profile:
536
+ * - Pure custodial (success or wrong pwd) : 1 round-trip
537
+ * - Pure zk (any outcome) : 1 custodial probe + 2 zk
538
+ * - Unknown email : same as zk worst case
539
+ *
540
+ * Anti-enum note: timing slightly leaks the mode (custodial path is
541
+ * faster than zk). Acceptable for V1 — rate limiting + strong
542
+ * passwords are the real defenses. A future strict-anti-enum mode
543
+ * could race both paths in parallel and accept the 2x backend load.
544
+ */
545
+ signInAuto(input: SignInInput): Promise<AithosSession>;
138
546
  signIn(input: SignInInput): Promise<AithosSession>;
139
547
  signUp(input: SignUpInput): Promise<SignUpResult>;
140
548
  /**
@@ -159,8 +567,191 @@ export declare class AithosAuth {
159
567
  importMandate(input: ImportMandateInput): Promise<DelegateInfo>;
160
568
  removeMandate(mandateId: string): Promise<void>;
161
569
  signInWithGoogle(opts?: SignInWithGoogleOptions): never;
570
+ /**
571
+ * Public entrypoint — dedupes concurrent calls (React StrictMode).
572
+ * The first call kicks off the actual exchange; subsequent calls
573
+ * before that promise resolves return the SAME promise so they all
574
+ * receive the same `AithosSession | null`. Otherwise StrictMode's
575
+ * second invocation would race against the URL clean done by the
576
+ * first call and resolve to `null`, robbing the AuthCallback page
577
+ * of the session it actually obtained.
578
+ */
162
579
  handleCallback(): Promise<AithosSession | null>;
163
580
  exchange(aithosCode: string): Promise<AithosSession>;
581
+ /**
582
+ * Finish the first-time Google SSO bootstrap. After
583
+ * `signInWithGoogle()` + `handleCallback()`, a brand-new SSO user has
584
+ * a session JWT and an `enc_key` released by the auth backend, but
585
+ * NO Aithos identity yet (no Ed25519 seeds, no published did.json,
586
+ * no blob in the auth vault). This method closes that gap:
587
+ *
588
+ * 1. Generates a fresh {@link BrowserIdentity} client-side (4
589
+ * Ed25519 keypairs, derived DID).
590
+ * 2. Calls `aithos.publish_identity` on api.aithos.be so reads
591
+ * and writes against the Aithos primitives have an ethos to
592
+ * anchor to.
593
+ * 3. AES-GCM-encrypts the seeds with the session's `enc_key`,
594
+ * PUTs the result to `/auth/blob`. From now on, every Google
595
+ * sign-in for this user will receive the encrypted blob and
596
+ * hydrate locally.
597
+ * 4. Hydrates `ownerSigners` + `keyStore` so `canSignAsOwner()`
598
+ * flips to true.
599
+ * 5. Returns a recovery-file Blob — the only material that can
600
+ * restore this ethos if Google access is lost.
601
+ *
602
+ * Preconditions:
603
+ * - `getCurrentSession()` returns a non-null session (caller went
604
+ * through `handleCallback()` already).
605
+ * - The session's `blob_version` is 0 (i.e. no blob yet).
606
+ * - The session's `enc_key_b64` is non-empty.
607
+ *
608
+ * Throws `AithosSDKError("auth_sso_no_pending_first_login", …)` if
609
+ * preconditions don't hold (e.g. blob_version > 0 means the user has
610
+ * already completed setup; nothing to do).
611
+ */
612
+ completeSsoFirstLogin(input: CompleteSsoFirstLoginInput): Promise<CompleteSsoFirstLoginResult>;
613
+ /**
614
+ * Provision a custodial-mode account on behalf of a registered app.
615
+ *
616
+ * Two integration patterns:
617
+ * - **Frontend-only** apps : set `publicKey` on the constructor
618
+ * (or on this call). Safe to ship in browser bundles — the
619
+ * backend gates each request by Origin + IP rate limit.
620
+ * - **Backend-fronted** apps : the backend passes `apiKey` (secret
621
+ * Bearer); the browser never sees the credential.
622
+ *
623
+ * The created account is in a *pending* state — sign-in stays blocked
624
+ * until the user clicks the confirmation link sent to their inbox.
625
+ * Call {@link verifyEmail} from the page mounted on
626
+ * `app.verify_base_url` to consume the token; afterwards
627
+ * {@link signInCustodial} works.
628
+ *
629
+ * Errors map to `AithosSDKError` codes:
630
+ * - `auth_missing_api_key` (no credential provided)
631
+ * - `auth_invalid_api_key` (Bearer rejected by backend)
632
+ * - `auth_invalid_public_key` (public key rejected by backend)
633
+ * - `auth_api_key_revoked` / `auth_public_key_revoked`
634
+ * - `auth_origin_not_allowed` (public key + Origin not in allowlist)
635
+ * - `auth_password_too_weak` (400 — server-side strength check)
636
+ * - `auth_email_exists` (409 — email already registered)
637
+ * - `auth_email_invalid` (400 — bad email format)
638
+ * - `auth_mail_send_failed` (502 — DDB row exists but SES failed)
639
+ * - `auth_custodial_signup_failed` (catch-all)
640
+ */
641
+ signUpCustodial(input: CustodialSignUpInput): Promise<CustodialSignUpResult>;
642
+ /**
643
+ * Magic-link auto-signin: consume the verification token from the
644
+ * confirmation link, KMS-unwrap the seed bundle server-side, and
645
+ * hydrate the local session + keystore in one round-trip.
646
+ *
647
+ * Outcome depends on the link's state:
648
+ * - First click on a fresh link → returns
649
+ * `{ status: "signed_in", session, … }`. The session store is
650
+ * populated, the owner signers are loaded — the user is signed
651
+ * in. The caller should navigate them to a logged-in route.
652
+ * - Click of an already-consumed link → returns
653
+ * `{ status: "already_verified", email }`. No session is minted;
654
+ * the user must sign in via {@link signInCustodial}.
655
+ *
656
+ * Mount this on the page declared as `verify_base_url` in your app's
657
+ * registration. Read `email` + `token` from `window.location.search`,
658
+ * call this, branch on `result.status`.
659
+ *
660
+ * Throws `auth_token_invalid_or_expired` if the token is wrong or
661
+ * past its 1h TTL — surface a "request a fresh link" CTA in that case.
662
+ */
663
+ verifyEmail(input: VerifyEmailInput): Promise<VerifyEmailResult>;
664
+ /**
665
+ * Send an invitation magic link carrying a mandate. The issuer (owner)
666
+ * mints any mandate via {@link AithosSDK.mandates} (read/write/append/…),
667
+ * then calls this with the bundle: the auth backend stores it bound to a
668
+ * single-use token and emails the magic link. The mandate (and its delegate
669
+ * seed) never ride the email URL. The invitee redeems it via
670
+ * {@link acceptInvite}.
671
+ *
672
+ * Generic — knows nothing about the mandate's scope. Authenticate with
673
+ * `apiKey` (server) or `publicKey` (browser, Origin-gated).
674
+ */
675
+ inviteCustodial(input: InviteCustodialInput): Promise<InviteCustodialResult>;
676
+ /**
677
+ * Redeem an invitation from the magic link: consume the token, sign in
678
+ * (create the account with `password`, or authenticate an existing one),
679
+ * and AUTO-IMPORT the mandate the inviter attached. Returns the session and
680
+ * the imported {@link DelegateInfo}.
681
+ *
682
+ * Mount this on the page declared as the invitation's verify/redirect URL;
683
+ * read `email` + `token` from `window.location.search`, collect the
684
+ * `password`, call this.
685
+ *
686
+ * Throws `auth_token_invalid_or_expired` (bad/consumed/expired token) or an
687
+ * auth error if an existing account's password is wrong / a new one is weak.
688
+ */
689
+ acceptInvite(input: AcceptInviteInput): Promise<AcceptInviteResult>;
690
+ /**
691
+ * Re-send the verification mail for a pending account. Use when the
692
+ * user reports never having received the welcome mail, or when their
693
+ * verification token expired (24h TTL).
694
+ *
695
+ * The backend is anti-enumeration (always 200) and rate-limited
696
+ * 1/h/account, so it's safe to call even when the state of `email`
697
+ * is unknown. Accepts the same credential families as
698
+ * {@link signUpCustodial}; falls back to the constructor's
699
+ * `publicKey` when neither override is set.
700
+ */
701
+ resendVerificationEmail(input: ResendVerificationInput): Promise<void>;
702
+ /**
703
+ * Authenticate a custodial-mode user with email + password. Single
704
+ * round-trip: returns a fresh JWT session AND hydrates the local
705
+ * KeyStore with the user's 4 Ed25519 seeds (KMS-unwrapped server-side
706
+ * after Argon2id verify).
707
+ *
708
+ * After this returns, the SDK is ready to publish ethos editions,
709
+ * invoke compute, mint mandates, etc. — exactly as if the user had
710
+ * signed in via {@link signIn} (zk) or {@link handleCallback} (SSO).
711
+ *
712
+ * Errors map to `AithosSDKError` codes:
713
+ * - `auth_invalid_input` (your code passed empty fields)
714
+ * - `auth_invalid_credentials` (401 — wrong email / wrong password)
715
+ * - `auth_wrong_auth_mode` (403 — user exists in another flow)
716
+ */
717
+ signInCustodial(input: CustodialSignInInput): Promise<CustodialSignInResult>;
718
+ /**
719
+ * Trigger a password-reset email to the given address. Backend ALWAYS
720
+ * resolves silently (no enumeration) — caller cannot tell whether the
721
+ * email is registered or not. The mail itself, if sent, contains a
722
+ * magic-link URL of shape `<resetBaseUrl>?token=<raw>&email=<email>`.
723
+ *
724
+ * Per-email rate limits apply server-side (5 mails/day, 5 min cooldown
725
+ * between consecutive requests). Calls during cooldown silently no-op
726
+ * the mail send while still returning success here.
727
+ */
728
+ requestPasswordReset(input: RequestPasswordResetInput): Promise<void>;
729
+ /**
730
+ * Finalise a password reset using the magic-link token sent to the
731
+ * user's inbox by {@link requestPasswordReset}.
732
+ *
733
+ * Typical use site: the page mounted on the reset URL declared in
734
+ * `aithos-auth-apps.reset_base_url`. The page reads `email` and
735
+ * `token` from `window.location.search`, prompts the user for a new
736
+ * password, then calls this method.
737
+ *
738
+ * On success, the returned {@link AithosSession} is persisted to the
739
+ * session store but the local keystore is NOT hydrated — the backend
740
+ * does not return the seed bundle on this endpoint. To get a fully
741
+ * usable session (one that can sign envelopes), follow up with
742
+ * {@link signInCustodial} using the email + new password. The two
743
+ * round-trips can be hidden inside a single UI action: reset → auto
744
+ * sign-in → redirect to dashboard.
745
+ *
746
+ * Errors map to `AithosSDKError` codes:
747
+ * - `auth_invalid_input` (your code passed empty fields)
748
+ * - `auth_reset_token_invalid` (400 — token forged / wrong email)
749
+ * - `auth_reset_token_expired` (410 — token TTL elapsed)
750
+ * - `auth_reset_token_consumed` (409 — already used)
751
+ * - `auth_password_too_short` (400 — < 10 chars)
752
+ * - `auth_custodial_reset_failed` (catch-all)
753
+ */
754
+ applyPasswordReset(input: ApplyPasswordResetInput): Promise<ApplyPasswordResetResult>;
164
755
  signOut(): Promise<void>;
165
756
  }
166
757
  //# sourceMappingURL=auth.d.ts.map