@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.
- package/dist/src/auth-api.d.ts +41 -0
- package/dist/src/auth-api.js +82 -0
- package/dist/src/auth.d.ts +114 -75
- package/dist/src/auth.js +553 -73
- package/dist/src/compute.d.ts +8 -6
- package/dist/src/compute.js +19 -11
- package/dist/src/ethos.d.ts +117 -1
- package/dist/src/ethos.js +417 -16
- package/dist/src/index.d.ts +8 -4
- package/dist/src/index.js +26 -8
- package/dist/src/internal/delegate-bundle.d.ts +18 -0
- package/dist/src/internal/delegate-bundle.js +89 -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 +88 -1
- package/dist/src/mandates.js +185 -8
- package/dist/src/sdk.d.ts +36 -3
- package/dist/src/sdk.js +27 -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/test/auth-j3.test.d.ts +2 -0
- package/dist/test/auth-j3.test.js +360 -0
- package/dist/test/compute.test.js +22 -11
- 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.test.d.ts +2 -0
- package/dist/test/mandates.test.js +93 -0
- package/dist/test/sdk.test.js +64 -30
- package/dist/test/signer.test.d.ts +2 -0
- package/dist/test/signer.test.js +117 -0
- package/dist/test/wallet.test.js +20 -9
- package/package.json +4 -3
|
@@ -0,0 +1,41 @@
|
|
|
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 LoginChallengeResponse {
|
|
25
|
+
readonly authSalt: Uint8Array;
|
|
26
|
+
readonly encSalt: Uint8Array;
|
|
27
|
+
readonly kdf: KdfParams;
|
|
28
|
+
}
|
|
29
|
+
export declare function loginChallenge(http: HttpClient, email: string): Promise<LoginChallengeResponse>;
|
|
30
|
+
export interface LoginVerifyResponse {
|
|
31
|
+
readonly session: string;
|
|
32
|
+
readonly exp: number;
|
|
33
|
+
readonly did: string;
|
|
34
|
+
readonly handle: string;
|
|
35
|
+
readonly blob: Uint8Array;
|
|
36
|
+
readonly blobNonce: Uint8Array;
|
|
37
|
+
readonly blobVersion: number;
|
|
38
|
+
}
|
|
39
|
+
export declare function loginVerify(http: HttpClient, email: string, authKey: Uint8Array): Promise<LoginVerifyResponse>;
|
|
40
|
+
export {};
|
|
41
|
+
//# sourceMappingURL=auth-api.d.ts.map
|
|
@@ -0,0 +1,82 @@
|
|
|
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
|
+
export async function registerAccount(http, input) {
|
|
45
|
+
return postJson(http, "/auth/register", {
|
|
46
|
+
email: input.email,
|
|
47
|
+
handle: input.handle,
|
|
48
|
+
display_name: input.displayName,
|
|
49
|
+
did: input.did,
|
|
50
|
+
auth_key_b64: bytesToB64(input.authKey),
|
|
51
|
+
auth_salt_b64: bytesToB64(input.authSalt),
|
|
52
|
+
enc_salt_b64: bytesToB64(input.encSalt),
|
|
53
|
+
kdf: input.kdf,
|
|
54
|
+
blob_b64: bytesToB64(input.blob),
|
|
55
|
+
blob_nonce_b64: bytesToB64(input.blobNonce),
|
|
56
|
+
blob_version: input.blobVersion,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
export async function loginChallenge(http, email) {
|
|
60
|
+
const wire = await postJson(http, "/auth/login/challenge", { email });
|
|
61
|
+
return {
|
|
62
|
+
authSalt: b64ToBytes(wire.auth_salt_b64),
|
|
63
|
+
encSalt: b64ToBytes(wire.enc_salt_b64),
|
|
64
|
+
kdf: wire.kdf,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export async function loginVerify(http, email, authKey) {
|
|
68
|
+
const wire = await postJson(http, "/auth/login/verify", {
|
|
69
|
+
email,
|
|
70
|
+
auth_key_b64: bytesToB64(authKey),
|
|
71
|
+
});
|
|
72
|
+
return {
|
|
73
|
+
session: wire.session,
|
|
74
|
+
exp: wire.exp,
|
|
75
|
+
did: wire.did,
|
|
76
|
+
handle: wire.handle,
|
|
77
|
+
blob: b64ToBytes(wire.blob_b64),
|
|
78
|
+
blobNonce: b64ToBytes(wire.blob_nonce_b64),
|
|
79
|
+
blobVersion: wire.blob_version,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=auth-api.js.map
|
package/dist/src/auth.d.ts
CHANGED
|
@@ -1,116 +1,155 @@
|
|
|
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";
|
|
1
5
|
/** Default URL of the Aithos auth backend. */
|
|
2
6
|
export declare const DEFAULT_AUTH_BASE_URL = "https://auth.aithos.be";
|
|
3
|
-
/**
|
|
4
|
-
* Construction options for {@link AithosAuth}.
|
|
5
|
-
*/
|
|
6
7
|
export interface AithosAuthConfig {
|
|
7
|
-
/**
|
|
8
|
-
* Base URL of the Aithos auth backend. Defaults to
|
|
9
|
-
* {@link DEFAULT_AUTH_BASE_URL}. Override for staging or self-hosted
|
|
10
|
-
* deployments.
|
|
11
|
-
*/
|
|
12
8
|
readonly authBaseUrl?: string;
|
|
13
|
-
/**
|
|
14
|
-
* Optional `fetch` implementation. Defaults to `globalThis.fetch`. Used
|
|
15
|
-
* by tests to inject a mock without monkeypatching globals.
|
|
16
|
-
*/
|
|
17
9
|
readonly fetch?: typeof fetch;
|
|
18
|
-
/**
|
|
19
|
-
* Optional `window`-like object. Defaults to `globalThis.window` when
|
|
20
|
-
* available. Provided so node-side tests can assert redirect URLs without
|
|
21
|
-
* shimming jsdom.
|
|
22
|
-
*/
|
|
23
10
|
readonly window?: Pick<Window, "location" | "history">;
|
|
11
|
+
/** Pluggable JWT-session storage. Defaults to {@link defaultSessionStore}. */
|
|
12
|
+
readonly sessionStore?: AithosSessionStore;
|
|
13
|
+
/** Pluggable key persistence. Defaults to {@link defaultKeyStore}. */
|
|
14
|
+
readonly keyStore?: AithosKeyStore;
|
|
24
15
|
}
|
|
25
16
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* mapping layer and keeps the SDK transparent if the user opens the
|
|
31
|
-
* Network panel.
|
|
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}.
|
|
32
21
|
*/
|
|
33
22
|
export interface AithosSession {
|
|
34
|
-
/** HS256 JWT — send in `Authorization: Bearer <session>` to auth/* and
|
|
35
|
-
* app endpoints that consume it. */
|
|
36
23
|
readonly session: string;
|
|
37
|
-
/** JWT expiry, Unix seconds. */
|
|
38
24
|
readonly exp: number;
|
|
39
|
-
/** Aithos DID — `did:aithos:z…`. Stable across all the user's devices. */
|
|
40
25
|
readonly did: string;
|
|
41
|
-
/** User-visible handle (rendered as `@handle`). */
|
|
42
26
|
readonly handle: string;
|
|
43
|
-
/** Encrypted vault, base64. Empty string + version 0 on first sign-in. */
|
|
44
27
|
readonly blob_b64: string;
|
|
45
|
-
/** AES-GCM nonce for the blob, base64 (12 bytes). Empty on first sign-in. */
|
|
46
28
|
readonly blob_nonce_b64: string;
|
|
47
|
-
/** Monotonic blob version. Bumped on every PUT /auth/blob. */
|
|
48
29
|
readonly blob_version: number;
|
|
49
|
-
/** 32-byte vault key, base64. Decrypts {@link blob_b64} via AES-GCM-256. */
|
|
50
30
|
readonly enc_key_b64: string;
|
|
51
|
-
/** True the first time this user signs in. The app should run its
|
|
52
|
-
* onboarding flow rather than mounting an empty blob. */
|
|
53
31
|
readonly is_first_login: boolean;
|
|
54
32
|
}
|
|
55
33
|
/**
|
|
56
|
-
*
|
|
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.
|
|
57
37
|
*/
|
|
58
|
-
export interface
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
* to remember "the user clicked sign-in from /settings/billing" so you
|
|
63
|
-
* can restore that route after the redirect chain.
|
|
64
|
-
*
|
|
65
|
-
* Maximum 1024 characters.
|
|
66
|
-
*/
|
|
67
|
-
readonly appState?: string;
|
|
38
|
+
export interface OwnerInfo {
|
|
39
|
+
readonly did: string;
|
|
40
|
+
readonly handle: string;
|
|
41
|
+
readonly displayName: string;
|
|
68
42
|
}
|
|
69
43
|
/**
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
* URL). All methods are pure — no module-global state.
|
|
44
|
+
* Public information about a delegate session held by the SDK. Returned
|
|
45
|
+
* by `importMandate` and `getDelegates`.
|
|
73
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
|
+
}
|
|
56
|
+
export interface SignInWithGoogleOptions {
|
|
57
|
+
readonly appState?: string;
|
|
58
|
+
}
|
|
59
|
+
export interface SignInInput {
|
|
60
|
+
readonly email: string;
|
|
61
|
+
readonly password: string;
|
|
62
|
+
}
|
|
63
|
+
export interface SignUpInput {
|
|
64
|
+
readonly email: string;
|
|
65
|
+
readonly password: string;
|
|
66
|
+
readonly handle: string;
|
|
67
|
+
readonly displayName?: string;
|
|
68
|
+
}
|
|
69
|
+
export interface SignUpResult {
|
|
70
|
+
readonly session: AithosSession;
|
|
71
|
+
readonly recoveryFile: Blob;
|
|
72
|
+
readonly recoveryFilename: string;
|
|
73
|
+
}
|
|
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
|
+
}
|
|
74
82
|
export declare class AithosAuth {
|
|
75
|
-
|
|
83
|
+
#private;
|
|
76
84
|
readonly authBaseUrl: string;
|
|
77
|
-
private readonly fetchImpl;
|
|
78
|
-
private readonly win;
|
|
79
85
|
constructor(config?: AithosAuthConfig);
|
|
80
86
|
/**
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
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.
|
|
84
92
|
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
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.
|
|
87
98
|
*/
|
|
88
|
-
|
|
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;
|
|
89
107
|
/**
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
* `history.replaceState` so a page refresh doesn't replay the redeem
|
|
94
|
-
* (which would 410 anyway).
|
|
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.
|
|
95
111
|
*
|
|
96
|
-
*
|
|
97
|
-
* page load. Throws {@link AithosSDKError} on backend errors or when
|
|
98
|
-
* the URL carries `aithos_error=…` (Google denial, token-exchange
|
|
99
|
-
* failure, etc.).
|
|
112
|
+
* @internal
|
|
100
113
|
*/
|
|
101
|
-
|
|
114
|
+
_getOwnerSigners(): OwnerSigners | null;
|
|
102
115
|
/**
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
* the code out of the URL via their own router.
|
|
116
|
+
* Internal accessor — looks up an active delegate by mandate id.
|
|
117
|
+
* @internal
|
|
106
118
|
*/
|
|
107
|
-
|
|
119
|
+
_getDelegateActor(mandateId: string): DelegateActor | undefined;
|
|
108
120
|
/**
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
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
|
|
113
125
|
*/
|
|
126
|
+
_findDelegateForSubject(did: string): DelegateActor | undefined;
|
|
127
|
+
signIn(input: SignInInput): Promise<AithosSession>;
|
|
128
|
+
signUp(input: SignUpInput): Promise<SignUpResult>;
|
|
129
|
+
/**
|
|
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.
|
|
136
|
+
*
|
|
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.
|
|
140
|
+
*/
|
|
141
|
+
signInWithRecovery(input: SignInWithRecoveryInput): Promise<OwnerInfo>;
|
|
142
|
+
/**
|
|
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).
|
|
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>;
|
|
114
153
|
signOut(): Promise<void>;
|
|
115
154
|
}
|
|
116
155
|
//# sourceMappingURL=auth.d.ts.map
|