@aithos/sdk 0.1.0-alpha.4 → 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 (42) hide show
  1. package/dist/src/auth.d.ts +94 -136
  2. package/dist/src/auth.js +440 -159
  3. package/dist/src/compute.d.ts +8 -6
  4. package/dist/src/compute.js +19 -11
  5. package/dist/src/ethos.d.ts +117 -1
  6. package/dist/src/ethos.js +417 -16
  7. package/dist/src/index.d.ts +7 -4
  8. package/dist/src/index.js +17 -5
  9. package/dist/src/internal/delegate-bundle.d.ts +18 -0
  10. package/dist/src/internal/delegate-bundle.js +89 -0
  11. package/dist/src/internal/delegate-state.d.ts +45 -0
  12. package/dist/src/internal/delegate-state.js +120 -0
  13. package/dist/src/internal/owner-signers.d.ts +78 -0
  14. package/dist/src/internal/owner-signers.js +179 -0
  15. package/dist/src/internal/protocol-client-bridge.d.ts +8 -0
  16. package/dist/src/internal/protocol-client-bridge.js +20 -0
  17. package/dist/src/internal/recovery-file.d.ts +29 -0
  18. package/dist/src/internal/recovery-file.js +98 -0
  19. package/dist/src/internal/signer.d.ts +59 -0
  20. package/dist/src/internal/signer.js +86 -0
  21. package/dist/src/key-store.d.ts +128 -0
  22. package/dist/src/key-store.js +244 -0
  23. package/dist/src/mandates.d.ts +88 -1
  24. package/dist/src/mandates.js +185 -8
  25. package/dist/src/sdk.d.ts +36 -3
  26. package/dist/src/sdk.js +27 -23
  27. package/dist/src/wallet.d.ts +4 -6
  28. package/dist/src/wallet.js +18 -8
  29. package/dist/test/auth-j3.test.d.ts +2 -0
  30. package/dist/test/auth-j3.test.js +360 -0
  31. package/dist/test/compute.test.js +22 -11
  32. package/dist/test/ethos.test.d.ts +2 -0
  33. package/dist/test/ethos.test.js +219 -0
  34. package/dist/test/key-store.test.d.ts +2 -0
  35. package/dist/test/key-store.test.js +161 -0
  36. package/dist/test/mandates.test.d.ts +2 -0
  37. package/dist/test/mandates.test.js +93 -0
  38. package/dist/test/sdk.test.js +64 -30
  39. package/dist/test/signer.test.d.ts +2 -0
  40. package/dist/test/signer.test.js +117 -0
  41. package/dist/test/wallet.test.js +20 -9
  42. package/package.json +2 -1
@@ -1,197 +1,155 @@
1
1
  import { type AithosSessionStore } from "./session-store.js";
2
+ import { type AithosKeyStore } from "./key-store.js";
3
+ import { DelegateActor } from "./internal/delegate-state.js";
4
+ import { OwnerSigners } from "./internal/owner-signers.js";
2
5
  /** Default URL of the Aithos auth backend. */
3
6
  export declare const DEFAULT_AUTH_BASE_URL = "https://auth.aithos.be";
4
- /**
5
- * Construction options for {@link AithosAuth}.
6
- */
7
7
  export interface AithosAuthConfig {
8
- /**
9
- * Base URL of the Aithos auth backend. Defaults to
10
- * {@link DEFAULT_AUTH_BASE_URL}. Override for staging or self-hosted
11
- * deployments.
12
- */
13
8
  readonly authBaseUrl?: string;
14
- /**
15
- * Optional `fetch` implementation. Defaults to `globalThis.fetch`. Used
16
- * by tests to inject a mock without monkeypatching globals.
17
- */
18
9
  readonly fetch?: typeof fetch;
19
- /**
20
- * Optional `window`-like object. Defaults to `globalThis.window` when
21
- * available. Provided so node-side tests can assert redirect URLs without
22
- * shimming jsdom.
23
- */
24
10
  readonly window?: Pick<Window, "location" | "history">;
25
- /**
26
- * Pluggable session storage. Defaults to {@link sessionStorageStore}
27
- * in browser environments, {@link noopStore} elsewhere. See
28
- * `./session-store.ts` for built-in alternatives or to roll your own.
29
- */
11
+ /** Pluggable JWT-session storage. Defaults to {@link defaultSessionStore}. */
30
12
  readonly sessionStore?: AithosSessionStore;
13
+ /** Pluggable key persistence. Defaults to {@link defaultKeyStore}. */
14
+ readonly keyStore?: AithosKeyStore;
31
15
  }
32
16
  /**
33
- * Active Aithos session. Persisted in the configured session store and
34
- * surfaced by {@link AithosAuth.getCurrentSession}.
35
- *
36
- * Wire-compatible with the auth Lambda's `SsoExchangeResponse` and
37
- * register/verify payloads ; field names are kept snake_case to match
38
- * the backend.
17
+ * Active Aithos session. Returned by JWT-backed entry points
18
+ * (`signIn`, `signUp`, `handleCallback`). Recovery-file and mandate
19
+ * sign-ins do NOT return an `AithosSession` — they yield the lighter
20
+ * {@link OwnerInfo} / {@link DelegateInfo}.
39
21
  */
40
22
  export interface AithosSession {
41
- /** HS256 JWT — send in `Authorization: Bearer <session>` to auth/* and
42
- * app endpoints that consume it. */
43
23
  readonly session: string;
44
- /** JWT expiry, Unix seconds. */
45
24
  readonly exp: number;
46
- /** Aithos DID — `did:aithos:z…`. Stable across all the user's devices. */
47
25
  readonly did: string;
48
- /** User-visible handle (rendered as `@handle`). */
49
26
  readonly handle: string;
50
- /** Encrypted vault blob, base64. Empty string on first Google sign-in. */
51
27
  readonly blob_b64: string;
52
- /** AES-GCM nonce for the blob, base64 (12 bytes). Empty on first Google sign-in. */
53
28
  readonly blob_nonce_b64: string;
54
- /** Monotonic blob version. 0 on first Google sign-in. */
55
29
  readonly blob_version: number;
56
- /** 32-byte vault key, base64. Decrypts {@link blob_b64} via AES-GCM-256.
57
- * Returned by Google SSO ; absent (empty string) for password sign-in
58
- * where the key stays in browser memory only. */
59
30
  readonly enc_key_b64: string;
60
- /** True the first time this user signs in (Google flow only). */
61
31
  readonly is_first_login: boolean;
62
32
  }
63
- /** Options for {@link AithosAuth.signInWithGoogle}. */
33
+ /**
34
+ * Public information about the loaded owner identity. Available after
35
+ * any owner-side sign-in (password, Google, recovery), regardless of
36
+ * whether a JWT is also present.
37
+ */
38
+ export interface OwnerInfo {
39
+ readonly did: string;
40
+ readonly handle: string;
41
+ readonly displayName: string;
42
+ }
43
+ /**
44
+ * Public information about a delegate session held by the SDK. Returned
45
+ * by `importMandate` and `getDelegates`.
46
+ */
47
+ export interface DelegateInfo {
48
+ readonly mandateId: string;
49
+ readonly subjectDid: string;
50
+ readonly granteeId: string;
51
+ readonly scopes: readonly string[];
52
+ /** ISO-8601, or null when the mandate has no `not_after`. */
53
+ readonly expiresAt: string | null;
54
+ readonly label?: string;
55
+ }
64
56
  export interface SignInWithGoogleOptions {
65
- /**
66
- * Opaque deep-link state preserved across the OAuth round-trip and
67
- * surfaced back to the app via `?app_state=…` on the callback URL. Use
68
- * to remember "the user clicked sign-in from /settings/billing" so you
69
- * can restore that route after the redirect chain.
70
- *
71
- * Maximum 1024 characters.
72
- */
73
57
  readonly appState?: string;
74
58
  }
75
- /** Options for {@link AithosAuth.signIn}. */
76
59
  export interface SignInInput {
77
60
  readonly email: string;
78
61
  readonly password: string;
79
62
  }
80
- /** Options for {@link AithosAuth.signUp}. */
81
63
  export interface SignUpInput {
82
64
  readonly email: string;
83
65
  readonly password: string;
84
- /** Aithos handle (the @-name). 1–63 alphanumeric chars + `_`/`-`. */
85
66
  readonly handle: string;
86
- /** Optional human-readable name. Defaults to the handle. */
87
67
  readonly displayName?: string;
88
68
  }
89
- /** Result of {@link AithosAuth.signUp}. */
90
69
  export interface SignUpResult {
91
70
  readonly session: AithosSession;
92
- /**
93
- * Recovery file containing the user's seed material, plaintext at the
94
- * V1 spec ; the app should offer this to the user as a download. Lose
95
- * this file AND forget the password = lose the ethos.
96
- *
97
- * Format : JSON, content-type `application/json`. Filename suggestion
98
- * exposed as {@link recoveryFilename} for direct use with `<a download>`.
99
- */
100
71
  readonly recoveryFile: Blob;
101
- /** Suggested filename for {@link recoveryFile}. */
102
72
  readonly recoveryFilename: string;
103
73
  }
104
- /**
105
- * Authenticator for the Aithos identity service. One instance per app
106
- * is the recommended pattern (the constructor is cheap).
107
- *
108
- * The class is **stateful** in one specific way : it owns a session store
109
- * that gets written on every successful auth call and read by
110
- * {@link getCurrentSession}. Pass a custom store at construction time
111
- * if you need different persistence (localStorage, IndexedDB, no-op).
112
- */
74
+ export interface SignInWithRecoveryInput {
75
+ /** Recovery file as a Blob (browser File input) or already-decoded JSON string. */
76
+ readonly file: Blob | string;
77
+ }
78
+ export interface ImportMandateInput {
79
+ /** Delegate bundle as a Blob or already-decoded JSON string. */
80
+ readonly bundle: Blob | string;
81
+ }
113
82
  export declare class AithosAuth {
114
- /** Resolved auth base URL with a trailing slash trimmed. */
83
+ #private;
115
84
  readonly authBaseUrl: string;
116
- private readonly fetchImpl;
117
- private readonly win;
118
- private readonly store;
119
85
  constructor(config?: AithosAuthConfig);
120
86
  /**
121
- * Sign in to an existing Aithos account. Two-round-trip flow under the
122
- * hood :
123
- *
124
- * 1. POST /auth/login/challenge server returns the salts + KDF params
125
- * 2. derive auth_key from password + salt (Argon2id)
126
- * 3. POST /auth/login/verify → server checks auth_key, returns JWT + blob
127
- *
128
- * The returned `enc_key_b64` is empty by design : password sign-in
129
- * doesn't release the vault key over the wire (it's derived locally
130
- * but discarded after the call). Apps that need the seeds — most
131
- * apps don't — should use the (forthcoming) `loadEthos` helper
132
- * separately with the password still in hand.
87
+ * Reload signing material and JWT session from the configured stores.
88
+ * Must be called once at app boot before relying on
89
+ * {@link getCurrentSession} / {@link getOwnerInfo} / {@link canSignAsOwner}
90
+ * until then they reflect only what's been done in-memory in the
91
+ * current tab.
133
92
  *
134
- * Persists the session in the configured store before returning.
93
+ * Strict consistency: if the JWT and the stored owner disagree about
94
+ * who's signed in, both are wiped and the user re-auths. JWT-less
95
+ * owner state (loaded from keyStore but no JWT) is a valid resumed
96
+ * state — the user signed in via recovery or imported a mandate at
97
+ * some earlier moment and never went through the JWT flow.
135
98
  */
136
- signIn(input: SignInInput): Promise<AithosSession>;
99
+ resume(): Promise<void>;
100
+ /** JWT-backed session. Null when signed in via recovery / mandate / not at all. */
101
+ getCurrentSession(): AithosSession | null;
102
+ /** Loaded owner identity. Independent of JWT presence. */
103
+ getOwnerInfo(): OwnerInfo | null;
104
+ getDelegates(): readonly DelegateInfo[];
105
+ canSignAsOwner(): boolean;
106
+ canSignAsDelegateFor(did: string): boolean;
137
107
  /**
138
- * Create a new Aithos account end-to-end :
139
- *
140
- * 1. Generate a fresh `BrowserIdentity` (4 Ed25519/X25519 seeds)
141
- * 2. Build the recovery file (plaintext JSON, the user must save it)
142
- * 3. Derive auth_key + enc_key from the password (Argon2id, fresh salts)
143
- * 4. Encrypt the seeds in a vault blob (AES-GCM-256)
144
- * 5. POST /auth/register with everything → JWT
145
- * 6. Persist the session and return it + the recovery Blob
108
+ * Internal accessor used by sibling SDK namespaces (compute, wallet,
109
+ * ethos) when they need to sign on behalf of the owner. Returns null
110
+ * if no owner is loaded.
146
111
  *
147
- * The seeds are NOT published as an Aithos ethos here : the user's
148
- * profile on `app.aithos.be` won't appear until they (or another app)
149
- * publishes their first edition. This matches `aithos/app`'s design,
150
- * where the vault is the source of truth for keys and the published
151
- * edition is a separate concern.
112
+ * @internal
152
113
  */
153
- signUp(input: SignUpInput): Promise<SignUpResult>;
114
+ _getOwnerSigners(): OwnerSigners | null;
154
115
  /**
155
- * Redirect the browser to Google's OAuth consent screen. Must be called
156
- * synchronously in response to a user gesture (button click) — most
157
- * browsers block top-level navigation triggered from idle code.
158
- *
159
- * Does not return : navigation tears the JS context down. The `never`
160
- * return type tells callers any code after the call is unreachable.
116
+ * Internal accessor looks up an active delegate by mandate id.
117
+ * @internal
161
118
  */
162
- signInWithGoogle(opts?: SignInWithGoogleOptions): never;
119
+ _getDelegateActor(mandateId: string): DelegateActor | undefined;
163
120
  /**
164
- * Inspect the current URL for an `aithos_code` query parameter. If it's
165
- * present, exchange it at the backend, persist the session, and return
166
- * it. The query params are stripped from the URL via
167
- * `history.replaceState` so a page refresh doesn't replay the redeem
168
- * (which would 410 anyway).
169
- *
170
- * Returns `null` when there's no code in the URL — safe to call on every
171
- * page load. Throws {@link AithosSDKError} on backend errors or when
172
- * the URL carries `aithos_error=…`.
121
+ * Internal accessor finds the first active delegate whose subject
122
+ * matches `did`. Used by `sdk.ethos.of(did)` when the user holds a
123
+ * mandate for that subject.
124
+ * @internal
173
125
  */
174
- handleCallback(): Promise<AithosSession | null>;
126
+ _findDelegateForSubject(did: string): DelegateActor | undefined;
127
+ signIn(input: SignInInput): Promise<AithosSession>;
128
+ signUp(input: SignUpInput): Promise<SignUpResult>;
175
129
  /**
176
- * Programmatically redeem an `aithos_code` for a session. `handleCallback`
177
- * calls this for you ; expose it directly for callers that already pulled
178
- * the code out of the URL via their own router.
130
+ * Sign in by uploading a recovery file. Hydrates the owner signers
131
+ * locally no JWT is obtained on this path because the recovery
132
+ * file alone doesn't authenticate against the auth backend (no
133
+ * password, no Google session). Apps that need compute/wallet
134
+ * access should follow up with an email+password sign-in or with
135
+ * Google SSO.
179
136
  *
180
- * Note : this method does NOT persist the session it's the lower-level
181
- * primitive. Use `handleCallback` for the full pipe.
137
+ * The recovery file is ALWAYS the file produced by `signUp` (or the
138
+ * equivalent one emitted by `protocol-client`'s `runOnboarding`).
139
+ * Both shapes are accepted.
182
140
  */
183
- exchange(aithosCode: string): Promise<AithosSession>;
141
+ signInWithRecovery(input: SignInWithRecoveryInput): Promise<OwnerInfo>;
184
142
  /**
185
- * Read the active session from the configured store. Returns null if
186
- * the user is signed out, or if the JWT has expired (the store
187
- * auto-evicts expired entries see ./session-store.ts).
188
- */
189
- getCurrentSession(): AithosSession | null;
190
- /**
191
- * Stateless sign-out — the Aithos backend doesn't track sessions, so
192
- * there's nothing to revoke server-side ; this method clears the
193
- * configured session store and resolves.
143
+ * Import a delegate bundle (`.aithos-delegate.json`). Works in any
144
+ * state: with no owner loaded (delegate-only session), or alongside
145
+ * an existing owner (the user holds mandates for other people's
146
+ * ethoses while also being an owner themselves).
194
147
  */
148
+ importMandate(input: ImportMandateInput): Promise<DelegateInfo>;
149
+ removeMandate(mandateId: string): Promise<void>;
150
+ signInWithGoogle(opts?: SignInWithGoogleOptions): never;
151
+ handleCallback(): Promise<AithosSession | null>;
152
+ exchange(aithosCode: string): Promise<AithosSession>;
195
153
  signOut(): Promise<void>;
196
154
  }
197
155
  //# sourceMappingURL=auth.d.ts.map