@aithos/sdk 0.1.0-alpha.3 → 0.1.0-alpha.30
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.
- package/README.md +159 -0
- package/dist/src/auth-api.d.ts +105 -0
- package/dist/src/auth-api.js +178 -0
- package/dist/src/auth.d.ts +359 -68
- package/dist/src/auth.js +1035 -69
- package/dist/src/compute.d.ts +221 -9
- package/dist/src/compute.js +293 -16
- package/dist/src/data-schema-contacts-v1.d.ts +14 -0
- package/dist/src/data-schema-contacts-v1.js +28 -0
- package/dist/src/data.d.ts +97 -0
- package/dist/src/data.js +634 -0
- package/dist/src/endpoints.d.ts +9 -0
- package/dist/src/endpoints.js +5 -0
- package/dist/src/ethos.d.ts +202 -1
- package/dist/src/ethos.js +821 -16
- package/dist/src/index.d.ts +15 -6
- package/dist/src/index.js +36 -9
- package/dist/src/internal/delegate-bundle.d.ts +18 -0
- package/dist/src/internal/delegate-bundle.js +94 -0
- package/dist/src/internal/delegate-state.d.ts +45 -0
- package/dist/src/internal/delegate-state.js +120 -0
- package/dist/src/internal/owner-signers.d.ts +78 -0
- package/dist/src/internal/owner-signers.js +179 -0
- package/dist/src/internal/protocol-client-bridge.d.ts +8 -0
- package/dist/src/internal/protocol-client-bridge.js +20 -0
- package/dist/src/internal/recovery-file.d.ts +29 -0
- package/dist/src/internal/recovery-file.js +98 -0
- package/dist/src/internal/signer.d.ts +59 -0
- package/dist/src/internal/signer.js +86 -0
- package/dist/src/key-store.d.ts +128 -0
- package/dist/src/key-store.js +244 -0
- package/dist/src/mandates.d.ts +163 -1
- package/dist/src/mandates.js +286 -8
- package/dist/src/sdk.d.ts +39 -3
- package/dist/src/sdk.js +36 -23
- package/dist/src/session-store.d.ts +58 -0
- package/dist/src/session-store.js +158 -0
- package/dist/src/wallet.d.ts +4 -6
- package/dist/src/wallet.js +18 -8
- package/dist/src/web.d.ts +279 -0
- package/dist/src/web.js +186 -0
- package/dist/test/auth-j3.test.d.ts +2 -0
- package/dist/test/auth-j3.test.js +391 -0
- package/dist/test/compute-delegate-path.test.d.ts +2 -0
- package/dist/test/compute-delegate-path.test.js +183 -0
- package/dist/test/compute.test.js +26 -11
- package/dist/test/endpoints.test.js +20 -1
- package/dist/test/ethos-first-edition.test.d.ts +2 -0
- package/dist/test/ethos-first-edition.test.js +248 -0
- package/dist/test/ethos.test.d.ts +2 -0
- package/dist/test/ethos.test.js +219 -0
- package/dist/test/key-store.test.d.ts +2 -0
- package/dist/test/key-store.test.js +161 -0
- package/dist/test/mandates-compute.test.d.ts +2 -0
- package/dist/test/mandates-compute.test.js +256 -0
- package/dist/test/mandates.test.d.ts +2 -0
- package/dist/test/mandates.test.js +93 -0
- package/dist/test/sdk.test.js +70 -30
- package/dist/test/signer.test.d.ts +2 -0
- package/dist/test/signer.test.js +117 -0
- package/dist/test/signup-bootstrap.test.d.ts +2 -0
- package/dist/test/signup-bootstrap.test.js +222 -0
- package/dist/test/wallet.test.js +20 -9
- package/dist/test/web.test.d.ts +2 -0
- package/dist/test/web.test.js +270 -0
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -55,11 +55,170 @@ const reply = await sdk.compute.invokeBedrock({
|
|
|
55
55
|
console.log(reply.content);
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
+
## Delegating compute to an agent — opt-in token spending
|
|
59
|
+
|
|
60
|
+
To let an agent (or another user, or a third-party app) invoke Bedrock
|
|
61
|
+
**in your name**, with **your credits**, you mint a mandate. Token
|
|
62
|
+
spending is its own opt-in capability — passing it is a separate,
|
|
63
|
+
named, validated input that a consent UI can review. It is NEVER an
|
|
64
|
+
implicit side-effect of an ethos read/write scope.
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
// Mint a mandate that lets agent Bob read your public ethos AND
|
|
68
|
+
// spend up to 5 000 microcredits/day on Haiku, capped at 100 000
|
|
69
|
+
// microcredits over the whole mandate lifetime.
|
|
70
|
+
const mandate = await sdk.mandates.create({
|
|
71
|
+
granteeId: "urn:agent:bob",
|
|
72
|
+
scopes: ["ethos.read.public"],
|
|
73
|
+
ttlSeconds: 86_400,
|
|
74
|
+
compute: {
|
|
75
|
+
dailyCapMicrocredits: 5_000,
|
|
76
|
+
totalCapMicrocredits: 100_000,
|
|
77
|
+
maxCreditsPerCall: 500,
|
|
78
|
+
allowedModels: ["claude-haiku-4-5"],
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Hand `mandate.bundle` (a `.aithos-delegate.json` Blob) to Bob.
|
|
83
|
+
// He imports it, then signs his own envelopes and calls
|
|
84
|
+
// sdk.compute.invokeBedrock({ mandateId: mandate.mandateId, … })
|
|
85
|
+
// — every invocation debits *your* wallet, capped per the budget
|
|
86
|
+
// you set.
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Three invariants the SDK enforces synchronously, before reaching the
|
|
90
|
+
network — they fail fast with a precise `AithosSDKError`:
|
|
91
|
+
|
|
92
|
+
- **No smuggling.** Adding `"compute.invoke"` directly to `scopes[]`
|
|
93
|
+
throws `mandates_invalid_scopes`. The `compute` namespace is the
|
|
94
|
+
only path, so a UI reviewing `compute` can never be bypassed.
|
|
95
|
+
- **No bearer compute.** A `compute` namespace without at least one
|
|
96
|
+
of `dailyCapMicrocredits` or `totalCapMicrocredits` throws
|
|
97
|
+
`mandates_invalid_compute`. Unbounded compute mandates are forbidden
|
|
98
|
+
by construction.
|
|
99
|
+
- **Compute-only is fine.** `scopes: []` is allowed when `compute` is
|
|
100
|
+
set — useful for agents that only consume tokens (e.g. creative
|
|
101
|
+
assistants) without seeing any of your data.
|
|
102
|
+
|
|
103
|
+
## Custodial auth — onboarding users without a recovery file
|
|
104
|
+
|
|
105
|
+
Three new methods on `AithosAuth` let an app create and authenticate
|
|
106
|
+
its end-users via a server-managed custody flow — the user only needs
|
|
107
|
+
an email address and a password sent by mail. No recovery file, no
|
|
108
|
+
Google account, no client-side cryptography to handle.
|
|
109
|
+
|
|
110
|
+
The model is honest custody: Aithos KMS-wraps the user's Ed25519
|
|
111
|
+
identity seeds, and unwraps them on every sign-in after password
|
|
112
|
+
verification. Equivalent to how Coinbase or any hosted SaaS keeps your
|
|
113
|
+
private key. Annunciated to the user in the welcome email.
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
import { AithosSDK } from "@aithos/sdk";
|
|
117
|
+
|
|
118
|
+
// ─── Server-side: sign-up ───────────────────────────────────────────
|
|
119
|
+
// MUST run on your backend. The API key is a server secret —
|
|
120
|
+
// provisioned by Aithos via the operator runbook.
|
|
121
|
+
const sdk = new AithosSDK({ identity });
|
|
122
|
+
const result = await sdk.auth.signUpCustodial({
|
|
123
|
+
apiKey: process.env.AITHOS_API_KEY!,
|
|
124
|
+
email: "alice@example.com",
|
|
125
|
+
displayName: "Alice",
|
|
126
|
+
});
|
|
127
|
+
// → { userId, did, handle, email, mailSent }
|
|
128
|
+
// The user receives an email with their password and a sign-in link.
|
|
129
|
+
|
|
130
|
+
// ─── Browser-side: sign-in ──────────────────────────────────────────
|
|
131
|
+
// User pastes the password from their mail into your sign-in form,
|
|
132
|
+
// then your frontend calls this. No API key needed — the password
|
|
133
|
+
// is the credential.
|
|
134
|
+
const { session, passwordMustChange } = await sdk.auth.signInCustodial({
|
|
135
|
+
email: "alice@example.com",
|
|
136
|
+
password: "MyTempPass32chars",
|
|
137
|
+
});
|
|
138
|
+
// Local KeyStore is now hydrated with the 4 Ed25519 sphere seeds —
|
|
139
|
+
// the user can publish ethos editions, mint mandates, invoke compute,
|
|
140
|
+
// exactly as if they had signed in via a recovery file or Google SSO.
|
|
141
|
+
if (passwordMustChange) {
|
|
142
|
+
// Optional: nudge the user to set their own password via the
|
|
143
|
+
// standard reset flow.
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ─── Browser-side: request password reset ───────────────────────────
|
|
147
|
+
// The backend always returns silently (anti-enumeration). If the email
|
|
148
|
+
// is registered AND in custodial mode AND not in cooldown AND under the
|
|
149
|
+
// daily cap, a magic-link email is sent to the address.
|
|
150
|
+
await sdk.auth.requestPasswordReset({ email: "alice@example.com" });
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
The reset finalization (collecting the new password from the user) is
|
|
154
|
+
done on a small web page hosted by Aithos at `https://app.aithos.be/reset`
|
|
155
|
+
(or your app's own `reset_base_url` if you've registered one — see the
|
|
156
|
+
operator runbook). The page POSTs to `/auth/custodial/reset/finalize`
|
|
157
|
+
and returns the user to your sign-in page on success.
|
|
158
|
+
|
|
159
|
+
### Getting an API key
|
|
160
|
+
|
|
161
|
+
API keys are provisioned out-of-band by Aithos. Contact the maintainer
|
|
162
|
+
(or use the self-service console at `aithos.be/console` when it ships
|
|
163
|
+
in V2). The pattern is `aithos_<env>_<32 chars b58>`. Keep it in your
|
|
164
|
+
backend's secrets manager — never in browser code.
|
|
165
|
+
|
|
166
|
+
### Trade-offs vs. the zk and Google SSO flows
|
|
167
|
+
|
|
168
|
+
| | zk (recovery file) | Google SSO (KMS) | **Custodial** |
|
|
169
|
+
|----------------|----------------------------|----------------------|---------------|
|
|
170
|
+
| User burden | downloads `recovery.json` | Google consent | email only |
|
|
171
|
+
| Password reset | requires recovery file | re-auth via Google | magic-link mail |
|
|
172
|
+
| Trust model | zero-knowledge (you only) | Aithos + Google | Aithos only |
|
|
173
|
+
| Multi-device | re-import recovery | re-Google | email + password |
|
|
174
|
+
| SDK signing capability | full | full | full |
|
|
175
|
+
|
|
176
|
+
Custodial is the right default for SDK-integrated apps that want
|
|
177
|
+
SaaS-grade UX. zk is the right default for power users who want
|
|
178
|
+
sovereign custody. SSO is the right default for users already invested
|
|
179
|
+
in the Google ecosystem.
|
|
180
|
+
|
|
181
|
+
## Extracting webpages without an LLM
|
|
182
|
+
|
|
183
|
+
`sdk.web` is a token-priced primitive that lets your agent read a
|
|
184
|
+
public webpage and get back cleaned HTML, purged CSS and a
|
|
185
|
+
deterministic visual signature — all computed server-side without an
|
|
186
|
+
LLM in the loop. Pricing is a flat **1 microcredit** per successful
|
|
187
|
+
extraction (refunded on failure), versus ~30 mc for a comparable
|
|
188
|
+
LLM-based extraction.
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
import { AithosSDK } from "@aithos/sdk";
|
|
192
|
+
|
|
193
|
+
const sdk = new AithosSDK({ auth, appDid });
|
|
194
|
+
|
|
195
|
+
const { data, creditsCharged } = await sdk.web.extract({
|
|
196
|
+
url: "https://example.com",
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
console.log(data.meta.title); // "Example Domain"
|
|
200
|
+
console.log(data.visual_signature.colors.primary); // "#0078d4"
|
|
201
|
+
console.log(data.styles.css.length); // purged + minified CSS
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Owners can mint a mandate for delegate-only extraction:
|
|
205
|
+
|
|
206
|
+
```ts
|
|
207
|
+
import { WEB_EXTRACT_SCOPE } from "@aithos/sdk";
|
|
208
|
+
|
|
209
|
+
await sdk.mandates.create({
|
|
210
|
+
appDid: "did:aithos:app:my-agent",
|
|
211
|
+
scopes: [WEB_EXTRACT_SCOPE],
|
|
212
|
+
// ...
|
|
213
|
+
});
|
|
214
|
+
```
|
|
215
|
+
|
|
58
216
|
## What lives where
|
|
59
217
|
|
|
60
218
|
| Namespace | Purpose |
|
|
61
219
|
| ---------------- | ------------------------------------------------------------------------------------------ |
|
|
62
220
|
| `sdk.compute` | Bedrock invocation through the Aithos compute proxy (signed envelope, wallet enforcement). |
|
|
221
|
+
| `sdk.web` | Webpage extraction without an LLM through the web extractor proxy (1 mc / call). |
|
|
63
222
|
| `sdk.wallet` | Stripe Checkout sessions for credit-pack top-ups, balance helpers. |
|
|
64
223
|
| `sdk.ethos` | Ethos-zone composition / parsing — re-exported from `@aithos/protocol-client`. |
|
|
65
224
|
| `sdk.onboarding` | First-run identity / DID flows — re-exported. |
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { type KdfParams } from "@aithos/protocol-client";
|
|
2
|
+
interface HttpClient {
|
|
3
|
+
readonly fetchImpl: typeof fetch;
|
|
4
|
+
readonly authBaseUrl: string;
|
|
5
|
+
}
|
|
6
|
+
export interface RegisterApiInput {
|
|
7
|
+
readonly email: string;
|
|
8
|
+
readonly handle: string;
|
|
9
|
+
readonly displayName: string;
|
|
10
|
+
readonly did: string;
|
|
11
|
+
readonly authKey: Uint8Array;
|
|
12
|
+
readonly authSalt: Uint8Array;
|
|
13
|
+
readonly encSalt: Uint8Array;
|
|
14
|
+
readonly kdf: KdfParams;
|
|
15
|
+
readonly blob: Uint8Array;
|
|
16
|
+
readonly blobNonce: Uint8Array;
|
|
17
|
+
readonly blobVersion: number;
|
|
18
|
+
}
|
|
19
|
+
export interface RegisterApiResponse {
|
|
20
|
+
readonly session: string;
|
|
21
|
+
readonly exp: number;
|
|
22
|
+
}
|
|
23
|
+
export declare function registerAccount(http: HttpClient, input: RegisterApiInput): Promise<RegisterApiResponse>;
|
|
24
|
+
export interface PutBlobApiInput {
|
|
25
|
+
readonly jwt: string;
|
|
26
|
+
readonly blob: Uint8Array;
|
|
27
|
+
readonly blobNonce: Uint8Array;
|
|
28
|
+
readonly blobVersion: number;
|
|
29
|
+
}
|
|
30
|
+
export declare function putBlob(http: HttpClient, input: PutBlobApiInput): Promise<{
|
|
31
|
+
ok: true;
|
|
32
|
+
}>;
|
|
33
|
+
export interface LoginChallengeResponse {
|
|
34
|
+
readonly authSalt: Uint8Array;
|
|
35
|
+
readonly encSalt: Uint8Array;
|
|
36
|
+
readonly kdf: KdfParams;
|
|
37
|
+
}
|
|
38
|
+
export declare function loginChallenge(http: HttpClient, email: string): Promise<LoginChallengeResponse>;
|
|
39
|
+
export interface LoginVerifyResponse {
|
|
40
|
+
readonly session: string;
|
|
41
|
+
readonly exp: number;
|
|
42
|
+
readonly did: string;
|
|
43
|
+
readonly handle: string;
|
|
44
|
+
readonly blob: Uint8Array;
|
|
45
|
+
readonly blobNonce: Uint8Array;
|
|
46
|
+
readonly blobVersion: number;
|
|
47
|
+
}
|
|
48
|
+
export declare function loginVerify(http: HttpClient, email: string, authKey: Uint8Array): Promise<LoginVerifyResponse>;
|
|
49
|
+
export interface CustodialSignUpApiInput {
|
|
50
|
+
readonly apiKey: string;
|
|
51
|
+
readonly email: string;
|
|
52
|
+
readonly displayName?: string;
|
|
53
|
+
readonly handleHint?: string;
|
|
54
|
+
}
|
|
55
|
+
export interface CustodialSignUpApiResponse {
|
|
56
|
+
readonly userId: string;
|
|
57
|
+
readonly did: string;
|
|
58
|
+
readonly handle: string;
|
|
59
|
+
readonly email: string;
|
|
60
|
+
readonly mailSent: boolean;
|
|
61
|
+
readonly mailMessageId?: string;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Provision a custodial-mode account on behalf of a registered app.
|
|
65
|
+
* Server-only — the API key MUST be kept off the browser (it grants the
|
|
66
|
+
* ability to create accounts under your app's name). Typical use site is
|
|
67
|
+
* the app's backend in response to a sign-up form submission.
|
|
68
|
+
*/
|
|
69
|
+
export declare function custodialSignUp(http: HttpClient, input: CustodialSignUpApiInput): Promise<CustodialSignUpApiResponse>;
|
|
70
|
+
export interface CustodialSignInApiInput {
|
|
71
|
+
readonly email: string;
|
|
72
|
+
readonly password: string;
|
|
73
|
+
}
|
|
74
|
+
export interface CustodialSignInApiResponse {
|
|
75
|
+
readonly session: string;
|
|
76
|
+
readonly exp: number;
|
|
77
|
+
readonly did: string;
|
|
78
|
+
readonly handle: string;
|
|
79
|
+
readonly displayName: string;
|
|
80
|
+
/** Raw 32-byte Ed25519 seed — caller MUST hydrate its keystore and
|
|
81
|
+
* zeroize this buffer. */
|
|
82
|
+
readonly seed: Uint8Array;
|
|
83
|
+
/** Raw 32-byte vault encryption key — same lifecycle. */
|
|
84
|
+
readonly encKey: Uint8Array;
|
|
85
|
+
readonly blob: Uint8Array;
|
|
86
|
+
readonly blobNonce: Uint8Array;
|
|
87
|
+
readonly blobVersion: number;
|
|
88
|
+
readonly passwordMustChange: boolean;
|
|
89
|
+
}
|
|
90
|
+
export declare function custodialSignIn(http: HttpClient, input: CustodialSignInApiInput): Promise<CustodialSignInApiResponse>;
|
|
91
|
+
export declare function custodialResetRequest(http: HttpClient, email: string): Promise<void>;
|
|
92
|
+
export interface CustodialResetFinalizeApiInput {
|
|
93
|
+
readonly email: string;
|
|
94
|
+
readonly token: string;
|
|
95
|
+
readonly newPassword: string;
|
|
96
|
+
}
|
|
97
|
+
export interface CustodialResetFinalizeApiResponse {
|
|
98
|
+
readonly session: string;
|
|
99
|
+
readonly exp: number;
|
|
100
|
+
readonly did: string;
|
|
101
|
+
readonly handle: string;
|
|
102
|
+
}
|
|
103
|
+
export declare function custodialResetFinalize(http: HttpClient, input: CustodialResetFinalizeApiInput): Promise<CustodialResetFinalizeApiResponse>;
|
|
104
|
+
export {};
|
|
105
|
+
//# sourceMappingURL=auth-api.d.ts.map
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright 2026 Mathieu Colla
|
|
3
|
+
// Thin HTTP client over the Aithos auth Lambda.
|
|
4
|
+
//
|
|
5
|
+
// Internal — not exported from the package's public surface. The
|
|
6
|
+
// {@link AithosAuth} class composes these calls with the crypto
|
|
7
|
+
// primitives in `@aithos/protocol-client` and the session store in
|
|
8
|
+
// {@link ./session-store.ts} to expose a high-level
|
|
9
|
+
// signIn / signUp / signInWithGoogle API.
|
|
10
|
+
//
|
|
11
|
+
// Wire format mirrors `aithos/auth/API.md` exactly. All `*_b64` fields
|
|
12
|
+
// are standard-base64 (not URL-safe), padding stripped — see
|
|
13
|
+
// `bytesToB64` / `b64ToBytes` in `@aithos/protocol-client`.
|
|
14
|
+
import { bytesToB64, b64ToBytes, } from "@aithos/protocol-client";
|
|
15
|
+
import { AithosSDKError } from "./types.js";
|
|
16
|
+
async function readError(res, defaultCode) {
|
|
17
|
+
let body = null;
|
|
18
|
+
try {
|
|
19
|
+
body = (await res.json());
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
/* body not JSON */
|
|
23
|
+
}
|
|
24
|
+
const code = typeof body?.code === "string" ? `auth_${body.code}` : `auth_${defaultCode}`;
|
|
25
|
+
const message = body?.error ?? `${res.status} ${res.statusText || "request failed"}`;
|
|
26
|
+
return new AithosSDKError(code, message, {
|
|
27
|
+
status: res.status,
|
|
28
|
+
...(body !== null ? { data: body } : {}),
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
async function postJson(http, path, body, jwt) {
|
|
32
|
+
const res = await http.fetchImpl(`${http.authBaseUrl}${path}`, {
|
|
33
|
+
method: "POST",
|
|
34
|
+
headers: {
|
|
35
|
+
"content-type": "application/json",
|
|
36
|
+
...(jwt ? { authorization: `Bearer ${jwt}` } : {}),
|
|
37
|
+
},
|
|
38
|
+
body: JSON.stringify(body),
|
|
39
|
+
});
|
|
40
|
+
if (!res.ok)
|
|
41
|
+
throw await readError(res, "request_failed");
|
|
42
|
+
return (await res.json());
|
|
43
|
+
}
|
|
44
|
+
async function putJson(http, path, body, jwt) {
|
|
45
|
+
const res = await http.fetchImpl(`${http.authBaseUrl}${path}`, {
|
|
46
|
+
method: "PUT",
|
|
47
|
+
headers: {
|
|
48
|
+
"content-type": "application/json",
|
|
49
|
+
authorization: `Bearer ${jwt}`,
|
|
50
|
+
},
|
|
51
|
+
body: JSON.stringify(body),
|
|
52
|
+
});
|
|
53
|
+
if (!res.ok)
|
|
54
|
+
throw await readError(res, "request_failed");
|
|
55
|
+
return (await res.json());
|
|
56
|
+
}
|
|
57
|
+
export async function registerAccount(http, input) {
|
|
58
|
+
return postJson(http, "/auth/register", {
|
|
59
|
+
email: input.email,
|
|
60
|
+
handle: input.handle,
|
|
61
|
+
display_name: input.displayName,
|
|
62
|
+
did: input.did,
|
|
63
|
+
auth_key_b64: bytesToB64(input.authKey),
|
|
64
|
+
auth_salt_b64: bytesToB64(input.authSalt),
|
|
65
|
+
enc_salt_b64: bytesToB64(input.encSalt),
|
|
66
|
+
kdf: input.kdf,
|
|
67
|
+
blob_b64: bytesToB64(input.blob),
|
|
68
|
+
blob_nonce_b64: bytesToB64(input.blobNonce),
|
|
69
|
+
blob_version: input.blobVersion,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
export async function putBlob(http, input) {
|
|
73
|
+
return putJson(http, "/auth/blob", {
|
|
74
|
+
blob_b64: bytesToB64(input.blob),
|
|
75
|
+
blob_nonce_b64: bytesToB64(input.blobNonce),
|
|
76
|
+
blob_version: input.blobVersion,
|
|
77
|
+
}, input.jwt);
|
|
78
|
+
}
|
|
79
|
+
export async function loginChallenge(http, email) {
|
|
80
|
+
const wire = await postJson(http, "/auth/login/challenge", { email });
|
|
81
|
+
return {
|
|
82
|
+
authSalt: b64ToBytes(wire.auth_salt_b64),
|
|
83
|
+
encSalt: b64ToBytes(wire.enc_salt_b64),
|
|
84
|
+
kdf: wire.kdf,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
export async function loginVerify(http, email, authKey) {
|
|
88
|
+
const wire = await postJson(http, "/auth/login/verify", {
|
|
89
|
+
email,
|
|
90
|
+
auth_key_b64: bytesToB64(authKey),
|
|
91
|
+
});
|
|
92
|
+
return {
|
|
93
|
+
session: wire.session,
|
|
94
|
+
exp: wire.exp,
|
|
95
|
+
did: wire.did,
|
|
96
|
+
handle: wire.handle,
|
|
97
|
+
blob: b64ToBytes(wire.blob_b64),
|
|
98
|
+
blobNonce: b64ToBytes(wire.blob_nonce_b64),
|
|
99
|
+
blobVersion: wire.blob_version,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Provision a custodial-mode account on behalf of a registered app.
|
|
104
|
+
* Server-only — the API key MUST be kept off the browser (it grants the
|
|
105
|
+
* ability to create accounts under your app's name). Typical use site is
|
|
106
|
+
* the app's backend in response to a sign-up form submission.
|
|
107
|
+
*/
|
|
108
|
+
export async function custodialSignUp(http, input) {
|
|
109
|
+
const res = await http.fetchImpl(`${http.authBaseUrl}/auth/custodial/sign-up`, {
|
|
110
|
+
method: "POST",
|
|
111
|
+
headers: {
|
|
112
|
+
"content-type": "application/json",
|
|
113
|
+
authorization: `Bearer ${input.apiKey}`,
|
|
114
|
+
},
|
|
115
|
+
body: JSON.stringify({
|
|
116
|
+
email: input.email,
|
|
117
|
+
...(input.displayName ? { display_name: input.displayName } : {}),
|
|
118
|
+
...(input.handleHint ? { handle_hint: input.handleHint } : {}),
|
|
119
|
+
}),
|
|
120
|
+
});
|
|
121
|
+
if (!res.ok)
|
|
122
|
+
throw await readError(res, "custodial_signup_failed");
|
|
123
|
+
const wire = (await res.json());
|
|
124
|
+
return {
|
|
125
|
+
userId: wire.user_id,
|
|
126
|
+
did: wire.did,
|
|
127
|
+
handle: wire.handle,
|
|
128
|
+
email: wire.email,
|
|
129
|
+
mailSent: wire.mail_sent,
|
|
130
|
+
...(wire.mail_message_id !== undefined
|
|
131
|
+
? { mailMessageId: wire.mail_message_id }
|
|
132
|
+
: {}),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
export async function custodialSignIn(http, input) {
|
|
136
|
+
const wire = await postJson(http, "/auth/custodial/sign-in", { email: input.email, password: input.password });
|
|
137
|
+
return {
|
|
138
|
+
session: wire.session,
|
|
139
|
+
exp: wire.exp,
|
|
140
|
+
did: wire.did,
|
|
141
|
+
handle: wire.handle,
|
|
142
|
+
displayName: wire.display_name,
|
|
143
|
+
seed: b64ToBytes(wire.seed_b64),
|
|
144
|
+
encKey: b64ToBytes(wire.enc_key_b64),
|
|
145
|
+
blob: wire.blob_b64 ? b64ToBytes(wire.blob_b64) : new Uint8Array(0),
|
|
146
|
+
blobNonce: wire.blob_nonce_b64
|
|
147
|
+
? b64ToBytes(wire.blob_nonce_b64)
|
|
148
|
+
: new Uint8Array(0),
|
|
149
|
+
blobVersion: wire.blob_version,
|
|
150
|
+
passwordMustChange: wire.password_must_change,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/* ---- POST /auth/custodial/reset/request --------------------------------- */
|
|
154
|
+
export async function custodialResetRequest(http, email) {
|
|
155
|
+
// Backend always returns 200 { ok: true } regardless. We accept any
|
|
156
|
+
// 2xx body, even non-JSON, to be defensive.
|
|
157
|
+
const res = await http.fetchImpl(`${http.authBaseUrl}/auth/custodial/reset/request`, {
|
|
158
|
+
method: "POST",
|
|
159
|
+
headers: { "content-type": "application/json" },
|
|
160
|
+
body: JSON.stringify({ email }),
|
|
161
|
+
});
|
|
162
|
+
if (!res.ok)
|
|
163
|
+
throw await readError(res, "custodial_reset_request_failed");
|
|
164
|
+
}
|
|
165
|
+
export async function custodialResetFinalize(http, input) {
|
|
166
|
+
const wire = await postJson(http, "/auth/custodial/reset/finalize", {
|
|
167
|
+
email: input.email,
|
|
168
|
+
token: input.token,
|
|
169
|
+
new_password: input.newPassword,
|
|
170
|
+
});
|
|
171
|
+
return {
|
|
172
|
+
session: wire.session,
|
|
173
|
+
exp: wire.exp,
|
|
174
|
+
did: wire.did,
|
|
175
|
+
handle: wire.handle,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=auth-api.js.map
|