@theoo/sdk 0.1.0
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/LICENSE +21 -0
- package/README.md +81 -0
- package/dist/assurance.d.ts +14 -0
- package/dist/assurance.d.ts.map +1 -0
- package/dist/assurance.js +20 -0
- package/dist/assurance.js.map +1 -0
- package/dist/base64url.d.ts +4 -0
- package/dist/base64url.d.ts.map +1 -0
- package/dist/base64url.js +45 -0
- package/dist/base64url.js.map +1 -0
- package/dist/browser.d.ts +18 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +72 -0
- package/dist/browser.js.map +1 -0
- package/dist/client.d.ts +331 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +321 -0
- package/dist/client.js.map +1 -0
- package/dist/errors.d.ts +12 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +18 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/tokens.d.ts +21 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +12 -0
- package/dist/tokens.js.map +1 -0
- package/dist/transport.d.ts +45 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +170 -0
- package/dist/transport.js.map +1 -0
- package/dist/types.d.ts +453 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/dist/webauthn.d.ts +34 -0
- package/dist/webauthn.d.ts.map +1 -0
- package/dist/webauthn.js +62 -0
- package/dist/webauthn.js.map +1 -0
- package/package.json +37 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Theoo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# @theoo/sdk
|
|
2
|
+
|
|
3
|
+
The client for [Theoo](https://github.com/) — smart accounts owned by a
|
|
4
|
+
passkey that never leaves the user's device. No seed phrase, no extension, and
|
|
5
|
+
no key on a server.
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install @theoo/sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { Theoo } from "@theoo/sdk";
|
|
13
|
+
import { browserPasskeys, LocalStorageTokenStore } from "@theoo/sdk/browser";
|
|
14
|
+
|
|
15
|
+
const theoo = new Theoo({
|
|
16
|
+
baseUrl: "https://theoo.example.com",
|
|
17
|
+
apiKey: "theoo_pub_…", // publishable: safe in a page
|
|
18
|
+
passkeys: browserPasskeys,
|
|
19
|
+
tokens: new LocalStorageTokenStore(),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
await theoo.auth.begin({ provider: "email", destination: "you@example.com" });
|
|
23
|
+
await theoo.auth.complete({ kind: "code", challengeId, code });
|
|
24
|
+
await theoo.auth.enrolPasskey(); // this passkey now owns the account
|
|
25
|
+
|
|
26
|
+
await theoo.me.operations.run({
|
|
27
|
+
kind: "call",
|
|
28
|
+
call: { to: "0x…", value: "0", data: "0x" },
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Works in browsers and on servers. React bindings are in
|
|
33
|
+
[`@theoo/react`](https://www.npmjs.com/package/@theoo/react); native
|
|
34
|
+
ones in
|
|
35
|
+
[`@theoo/react-native`](https://www.npmjs.com/package/@theoo/react-native).
|
|
36
|
+
|
|
37
|
+
Theoo is self-hosted: this package talks to a service you run. See the
|
|
38
|
+
`docs/` directory of the repository for running one, the HTTP API, and the
|
|
39
|
+
full SDK reference.
|
|
40
|
+
|
|
41
|
+
## Security
|
|
42
|
+
|
|
43
|
+
**Which key goes where.** A **publishable** key (`theoo_pub_…`) is meant to
|
|
44
|
+
ship in a page: it reaches only the sign-in routes and the routes an end
|
|
45
|
+
user's own bearer token already scopes to that user, and only from the origins
|
|
46
|
+
its tenant registered. A **secret** key (`theoo_…`) can act for *any* of your
|
|
47
|
+
users and must never reach a browser.
|
|
48
|
+
|
|
49
|
+
**Where sessions are stored.** `LocalStorageTokenStore` keeps the access and
|
|
50
|
+
refresh tokens in `localStorage`, which any script running on your page can
|
|
51
|
+
read. If your app has an XSS hole, that hole reaches the session.
|
|
52
|
+
|
|
53
|
+
It is worth being precise about what that does and does not mean. A stolen
|
|
54
|
+
session can act as the user *within what a session is allowed to do* — read
|
|
55
|
+
their account, start operations that then need a passkey. It **cannot** move
|
|
56
|
+
funds or take the account: every operation is signed on the user's device by
|
|
57
|
+
a passkey this package never sees and the server never holds. There is no
|
|
58
|
+
seed phrase to steal and nothing to export.
|
|
59
|
+
|
|
60
|
+
Choose accordingly:
|
|
61
|
+
|
|
62
|
+
| Store | Use it when |
|
|
63
|
+
| :--- | :--- |
|
|
64
|
+
| `LocalStorageTokenStore` | The session should survive a reload. The usual choice. |
|
|
65
|
+
| `MemoryTokenStore` | You would rather a reload sign the user out than leave a token readable by script. |
|
|
66
|
+
| Your own `TokenStore` | You want the tokens somewhere else — a worker, an encrypted store, your own backend. |
|
|
67
|
+
|
|
68
|
+
**Transport.** Every request sends the API key and, when acting for a user,
|
|
69
|
+
a bearer token. So the client:
|
|
70
|
+
|
|
71
|
+
* **refuses a plaintext `http://` base URL** unless it is loopback. Pass
|
|
72
|
+
`allowInsecureHttp: true` only for a server crossing a network you control.
|
|
73
|
+
* **does not follow redirects** (`redirect: "error"`). The API never issues
|
|
74
|
+
one, and a redirect would hand `x-api-key` to whatever host it named.
|
|
75
|
+
* **sends no cookies** (`credentials: "omit"`), so nothing here is a CSRF
|
|
76
|
+
target.
|
|
77
|
+
* **logs nothing.** There are no `console` calls in this package, so no token
|
|
78
|
+
reaches a log by accident.
|
|
79
|
+
|
|
80
|
+
**Dependencies.** This package has none. `@theoo/react` depends only on this
|
|
81
|
+
one. Nothing third-party enters your bundle through Theoo.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AssuranceLevel, Caller } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* How strongly a caller is authenticated *right now*.
|
|
4
|
+
*
|
|
5
|
+
* A step-up — proving possession again on the strongest factor the account
|
|
6
|
+
* has — raises a caller to `verified`, and that elevation decays. Reading
|
|
7
|
+
* `subject.aal` gives the base level and silently ignores whether the
|
|
8
|
+
* elevation has since gone stale, which is the wrong answer for anything
|
|
9
|
+
* worth gating.
|
|
10
|
+
*
|
|
11
|
+
* @param now Unix seconds. Defaults to this machine's clock.
|
|
12
|
+
*/
|
|
13
|
+
export declare function effectiveAssurance(caller: Caller, now?: number): AssuranceLevel;
|
|
14
|
+
//# sourceMappingURL=assurance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assurance.d.ts","sourceRoot":"","sources":["../src/assurance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzD;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,SAAgC,GAAG,cAAc,CAMtG"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How strongly a caller is authenticated *right now*.
|
|
3
|
+
*
|
|
4
|
+
* A step-up — proving possession again on the strongest factor the account
|
|
5
|
+
* has — raises a caller to `verified`, and that elevation decays. Reading
|
|
6
|
+
* `subject.aal` gives the base level and silently ignores whether the
|
|
7
|
+
* elevation has since gone stale, which is the wrong answer for anything
|
|
8
|
+
* worth gating.
|
|
9
|
+
*
|
|
10
|
+
* @param now Unix seconds. Defaults to this machine's clock.
|
|
11
|
+
*/
|
|
12
|
+
export function effectiveAssurance(caller, now = Math.floor(Date.now() / 1000)) {
|
|
13
|
+
const fresh = caller.subject.stepUpFreshUntil;
|
|
14
|
+
if (fresh !== null && fresh > now)
|
|
15
|
+
return "verified";
|
|
16
|
+
// A subject whose base level is already `verified` was elevated at some
|
|
17
|
+
// point and has no live step-up now, so it falls back to possession.
|
|
18
|
+
return caller.subject.aal === "verified" ? "possession" : caller.subject.aal;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=assurance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assurance.js","sourceRoot":"","sources":["../src/assurance.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAc,EAAE,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;IACpF,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC;IAC9C,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,GAAG,GAAG;QAAE,OAAO,UAAU,CAAC;IACrD,wEAAwE;IACxE,qEAAqE;IACrE,OAAO,MAAM,CAAC,OAAO,CAAC,GAAG,KAAK,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC;AAC/E,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** base64url without padding, the WebAuthn JSON encoding. Works in browsers, Node and React Native. */
|
|
2
|
+
export declare function encode(input: ArrayBuffer | Uint8Array): string;
|
|
3
|
+
export declare function decode(input: string): Uint8Array;
|
|
4
|
+
//# sourceMappingURL=base64url.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base64url.d.ts","sourceRoot":"","sources":["../src/base64url.ts"],"names":[],"mappings":"AAAA,uGAAuG;AAMvG,wBAAgB,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,UAAU,GAAG,MAAM,CAa9D;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAchD"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** base64url without padding, the WebAuthn JSON encoding. Works in browsers, Node and React Native. */
|
|
2
|
+
const ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
3
|
+
const LOOKUP = {};
|
|
4
|
+
for (let i = 0; i < ALPHABET.length; i++)
|
|
5
|
+
LOOKUP[ALPHABET[i]] = i;
|
|
6
|
+
export function encode(input) {
|
|
7
|
+
const bytes = input instanceof Uint8Array ? input : new Uint8Array(input);
|
|
8
|
+
let out = "";
|
|
9
|
+
for (let i = 0; i < bytes.length; i += 3) {
|
|
10
|
+
const a = bytes[i];
|
|
11
|
+
const b = i + 1 < bytes.length ? bytes[i + 1] : 0;
|
|
12
|
+
const c = i + 2 < bytes.length ? bytes[i + 2] : 0;
|
|
13
|
+
out += ALPHABET[a >> 2];
|
|
14
|
+
out += ALPHABET[((a & 3) << 4) | (b >> 4)];
|
|
15
|
+
if (i + 1 < bytes.length)
|
|
16
|
+
out += ALPHABET[((b & 15) << 2) | (c >> 6)];
|
|
17
|
+
if (i + 2 < bytes.length)
|
|
18
|
+
out += ALPHABET[c & 63];
|
|
19
|
+
}
|
|
20
|
+
return out;
|
|
21
|
+
}
|
|
22
|
+
export function decode(input) {
|
|
23
|
+
const s = input.replace(/=+$/, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
24
|
+
const out = new Uint8Array(Math.floor((s.length * 3) / 4));
|
|
25
|
+
let o = 0;
|
|
26
|
+
for (let i = 0; i < s.length; i += 4) {
|
|
27
|
+
const a = at(s, i);
|
|
28
|
+
const b = at(s, i + 1);
|
|
29
|
+
const c = i + 2 < s.length ? at(s, i + 2) : 0;
|
|
30
|
+
const d = i + 3 < s.length ? at(s, i + 3) : 0;
|
|
31
|
+
out[o++] = (a << 2) | (b >> 4);
|
|
32
|
+
if (i + 2 < s.length)
|
|
33
|
+
out[o++] = ((b & 15) << 4) | (c >> 2);
|
|
34
|
+
if (i + 3 < s.length)
|
|
35
|
+
out[o++] = ((c & 3) << 6) | d;
|
|
36
|
+
}
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
function at(s, i) {
|
|
40
|
+
const v = LOOKUP[s[i] ?? ""];
|
|
41
|
+
if (v === undefined)
|
|
42
|
+
throw new Error(`base64url: bad character at ${i}`);
|
|
43
|
+
return v;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=base64url.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base64url.js","sourceRoot":"","sources":["../src/base64url.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The browser's passkey API, as a `PasskeyProvider`. Import from
|
|
3
|
+
* `@theoo/sdk/browser`; the main entry stays free of DOM assumptions so
|
|
4
|
+
* servers and React Native can use it.
|
|
5
|
+
*/
|
|
6
|
+
import { type PasskeyProvider } from "./webauthn.js";
|
|
7
|
+
import type { TokenStore, StoredTokens } from "./tokens.js";
|
|
8
|
+
export declare const browserPasskeys: PasskeyProvider;
|
|
9
|
+
/** Whether this browser can do a passkey ceremony at all. */
|
|
10
|
+
export declare function passkeysAvailable(): Promise<boolean>;
|
|
11
|
+
/** Tokens in `localStorage`, under one key. Survives reloads; cleared on sign-out. */
|
|
12
|
+
export declare class LocalStorageTokenStore implements TokenStore {
|
|
13
|
+
private readonly key;
|
|
14
|
+
constructor(key?: string);
|
|
15
|
+
load(): Promise<StoredTokens | null>;
|
|
16
|
+
save(tokens: StoredTokens | null): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=browser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAyD,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAE5G,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAoB5D,eAAO,MAAM,eAAe,EAAE,eAe7B,CAAC;AAEF,6DAA6D;AAC7D,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC,CAO1D;AAED,sFAAsF;AACtF,qBAAa,sBAAuB,YAAW,UAAU;IAC3C,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAAH,GAAG,SAAkB;IAC5C,IAAI,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAQpC,IAAI,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;CAQvD"}
|
package/dist/browser.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The browser's passkey API, as a `PasskeyProvider`. Import from
|
|
3
|
+
* `@theoo/sdk/browser`; the main entry stays free of DOM assumptions so
|
|
4
|
+
* servers and React Native can use it.
|
|
5
|
+
*/
|
|
6
|
+
import { credentialToJSON, toCreationOptions, toRequestOptions } from "./webauthn.js";
|
|
7
|
+
function pkc() {
|
|
8
|
+
if (typeof PublicKeyCredential === "undefined") {
|
|
9
|
+
throw new Error("Passkeys are not available in this browser.");
|
|
10
|
+
}
|
|
11
|
+
return PublicKeyCredential;
|
|
12
|
+
}
|
|
13
|
+
function toJSON(cred) {
|
|
14
|
+
if (!cred)
|
|
15
|
+
throw new Error("The passkey ceremony was cancelled.");
|
|
16
|
+
const c = cred;
|
|
17
|
+
return typeof c.toJSON === "function" ? c.toJSON() : credentialToJSON(c);
|
|
18
|
+
}
|
|
19
|
+
export const browserPasskeys = {
|
|
20
|
+
async create(options) {
|
|
21
|
+
const P = pkc();
|
|
22
|
+
const publicKey = P.parseCreationOptionsFromJSON
|
|
23
|
+
? P.parseCreationOptionsFromJSON(options.publicKey ?? options)
|
|
24
|
+
: toCreationOptions(options);
|
|
25
|
+
return toJSON(await navigator.credentials.create({ publicKey }));
|
|
26
|
+
},
|
|
27
|
+
async get(options) {
|
|
28
|
+
const P = pkc();
|
|
29
|
+
const publicKey = P.parseRequestOptionsFromJSON
|
|
30
|
+
? P.parseRequestOptionsFromJSON(options.publicKey ?? options)
|
|
31
|
+
: toRequestOptions(options);
|
|
32
|
+
return toJSON(await navigator.credentials.get({ publicKey }));
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
/** Whether this browser can do a passkey ceremony at all. */
|
|
36
|
+
export async function passkeysAvailable() {
|
|
37
|
+
if (typeof PublicKeyCredential === "undefined")
|
|
38
|
+
return false;
|
|
39
|
+
try {
|
|
40
|
+
return await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** Tokens in `localStorage`, under one key. Survives reloads; cleared on sign-out. */
|
|
47
|
+
export class LocalStorageTokenStore {
|
|
48
|
+
constructor(key = "theoo.session") {
|
|
49
|
+
this.key = key;
|
|
50
|
+
}
|
|
51
|
+
async load() {
|
|
52
|
+
try {
|
|
53
|
+
const raw = localStorage.getItem(this.key);
|
|
54
|
+
return raw ? JSON.parse(raw) : null;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async save(tokens) {
|
|
61
|
+
try {
|
|
62
|
+
if (tokens)
|
|
63
|
+
localStorage.setItem(this.key, JSON.stringify(tokens));
|
|
64
|
+
else
|
|
65
|
+
localStorage.removeItem(this.key);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
/* private mode, quota: the session simply does not persist */
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,EAAwB,MAAM,eAAe,CAAC;AAS5G,SAAS,GAAG;IACV,IAAI,OAAO,mBAAmB,KAAK,WAAW,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,CAAC;IACD,OAAO,mBAA0B,CAAC;AACpC,CAAC;AAED,SAAS,MAAM,CAAC,IAAuB;IACrC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IAClE,MAAM,CAAC,GAAG,IAAwD,CAAC;IACnE,OAAO,OAAO,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAU,CAAC,CAAC;AACpF,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAoB;IAC9C,KAAK,CAAC,MAAM,CAAC,OAAwB;QACnC,MAAM,CAAC,GAAG,GAAG,EAAE,CAAC;QAChB,MAAM,SAAS,GAAG,CAAC,CAAC,4BAA4B;YAC9C,CAAC,CAAC,CAAC,CAAC,4BAA4B,CAAC,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC;YAC9D,CAAC,CAAE,iBAAiB,CAAC,OAAO,CAAmD,CAAC;QAClF,OAAO,MAAM,CAAC,MAAM,SAAS,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;IACnE,CAAC;IACD,KAAK,CAAC,GAAG,CAAC,OAAwB;QAChC,MAAM,CAAC,GAAG,GAAG,EAAE,CAAC;QAChB,MAAM,SAAS,GAAG,CAAC,CAAC,2BAA2B;YAC7C,CAAC,CAAC,CAAC,CAAC,2BAA2B,CAAC,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC;YAC7D,CAAC,CAAE,gBAAgB,CAAC,OAAO,CAAkD,CAAC;QAChF,OAAO,MAAM,CAAC,MAAM,SAAS,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;IAChE,CAAC;CACF,CAAC;AAEF,6DAA6D;AAC7D,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,IAAI,OAAO,mBAAmB,KAAK,WAAW;QAAE,OAAO,KAAK,CAAC;IAC7D,IAAI,CAAC;QACH,OAAO,MAAM,mBAAmB,CAAC,6CAA6C,EAAE,CAAC;IACnF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,sFAAsF;AACtF,MAAM,OAAO,sBAAsB;IACjC,YAA6B,MAAM,eAAe;QAArB,QAAG,GAAH,GAAG,CAAkB;IAAG,CAAC;IACtD,KAAK,CAAC,IAAI;QACR,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC3C,OAAO,GAAG,CAAC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAkB,CAAC,CAAC,CAAC,IAAI,CAAC;QACxD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,MAA2B;QACpC,IAAI,CAAC;YACH,IAAI,MAAM;gBAAE,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;;gBAC9D,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzC,CAAC;QAAC,MAAM,CAAC;YACP,8DAA8D;QAChE,CAAC;IACH,CAAC;CACF"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
import type { StoredTokens, TokenStore } from "./tokens.js";
|
|
2
|
+
import { Transport, type FetchLike } from "./transport.js";
|
|
3
|
+
import type { AuthChallenge, AuthOutcome, AvailableChain, BeginAuthRequest, ChainCall, ClientInfo, CompleteAuthRequest, Elevation, IdentitySummary, Me, OperationKind, OperationStatus, PreparedOperation, RecoveryStatus, ApiKeySummary, Caller, ChainOption, IssuedKey, NewProject, NewProjectKey, Project, SessionGrant, SessionRenewal, SessionKey, SmartAccount, SolanaAccount, SolanaAction, SolanaOperationStatus, SolanaRecoveryStatus, SolanaSessionGrant, SolanaSessionKey, PreparedSolanaOperation } from "./types.js";
|
|
4
|
+
import type { PasskeyProvider } from "./webauthn.js";
|
|
5
|
+
export interface TheooOptions {
|
|
6
|
+
/** Where Theoo is served, e.g. `https://theoo.example.com`. */
|
|
7
|
+
baseUrl: string;
|
|
8
|
+
/** A publishable key in an app; a secret key on your server. */
|
|
9
|
+
apiKey: string;
|
|
10
|
+
/** How passkey ceremonies run here. `browserPasskeys` from `@theoo/sdk/browser`, or the React Native provider. */
|
|
11
|
+
passkeys?: PasskeyProvider;
|
|
12
|
+
tokens?: TokenStore;
|
|
13
|
+
fetch?: FetchLike;
|
|
14
|
+
/** What the end user's client looks like, sent with every request that acts for them. */
|
|
15
|
+
client?: ClientInfo;
|
|
16
|
+
onSession?: (tokens: StoredTokens | null) => void;
|
|
17
|
+
}
|
|
18
|
+
export interface WaitOptions {
|
|
19
|
+
intervalMs?: number;
|
|
20
|
+
timeoutMs?: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The Theoo client.
|
|
24
|
+
*
|
|
25
|
+
* With a publishable key it is an end user's client: `auth`, then everything
|
|
26
|
+
* under `me`. With a secret key it is the tenant's server: `users(id)` to act
|
|
27
|
+
* for any user.
|
|
28
|
+
*/
|
|
29
|
+
export declare class Theoo {
|
|
30
|
+
readonly transport: Transport;
|
|
31
|
+
private readonly passkeys?;
|
|
32
|
+
private readonly client;
|
|
33
|
+
constructor(opts: TheooOptions);
|
|
34
|
+
private ceremony;
|
|
35
|
+
readonly auth: {
|
|
36
|
+
/** Start a sign-in (or, with a signed-in user, an add-this-factor). */
|
|
37
|
+
begin: (req: BeginAuthRequest) => Promise<AuthChallenge>;
|
|
38
|
+
/** Finish a sign-in. Stores the session. */
|
|
39
|
+
complete: (req: CompleteAuthRequest) => Promise<AuthOutcome>;
|
|
40
|
+
/** Email or phone: send a code, then `submit(code)`. */
|
|
41
|
+
withCode: (provider: "email" | "phone", destination: string, purpose?: BeginAuthRequest["purpose"]) => Promise<{
|
|
42
|
+
challenge: {
|
|
43
|
+
kind: "code";
|
|
44
|
+
challengeId: string;
|
|
45
|
+
destinationMasked: string;
|
|
46
|
+
expiresAt: number;
|
|
47
|
+
devCode?: string | null;
|
|
48
|
+
};
|
|
49
|
+
submit: (code: string) => Promise<AuthOutcome>;
|
|
50
|
+
}>;
|
|
51
|
+
/** Google or KingsChat: where to send the user, then `submit` with what comes back. */
|
|
52
|
+
withProvider: (provider: "google" | "kingschat") => Promise<{
|
|
53
|
+
challenge: {
|
|
54
|
+
kind: "redirect";
|
|
55
|
+
state: string;
|
|
56
|
+
url: string;
|
|
57
|
+
} | {
|
|
58
|
+
kind: "popup";
|
|
59
|
+
state: string;
|
|
60
|
+
url: string;
|
|
61
|
+
expectsPostMessage: boolean;
|
|
62
|
+
};
|
|
63
|
+
/** After the provider's callback: the `code` it returned. */
|
|
64
|
+
submitCode: (code: string) => Promise<AuthOutcome>;
|
|
65
|
+
/** A token the provider's own SDK already produced. */
|
|
66
|
+
submitToken: (accessToken: string) => Promise<AuthOutcome>;
|
|
67
|
+
}>;
|
|
68
|
+
/** A passkey the user already has. One ceremony, no typing. */
|
|
69
|
+
withPasskey: () => Promise<AuthOutcome>;
|
|
70
|
+
/** Enrol a passkey on the signed-in user. The account on chain is owned by the first one. */
|
|
71
|
+
enrolPasskey: (label?: string) => Promise<AuthOutcome>;
|
|
72
|
+
refresh: () => Promise<StoredTokens | null>;
|
|
73
|
+
signOut: () => Promise<void>;
|
|
74
|
+
session: () => Promise<StoredTokens | null>;
|
|
75
|
+
};
|
|
76
|
+
readonly me: {
|
|
77
|
+
get: () => Promise<Me>;
|
|
78
|
+
account: (chain?: number) => Promise<SmartAccount | null>;
|
|
79
|
+
identities: () => Promise<IdentitySummary[]>;
|
|
80
|
+
unlinkIdentity: (provider: IdentitySummary["provider"], subject: string) => Promise<void>;
|
|
81
|
+
signOutEverywhere: () => Promise<void>;
|
|
82
|
+
/** Prove presence again with a passkey, for actions that demand freshness. */
|
|
83
|
+
stepUp: () => Promise<Elevation>;
|
|
84
|
+
operations: {
|
|
85
|
+
prepare: (kind: OperationKind, chain?: number) => Promise<PreparedOperation>;
|
|
86
|
+
submit: (id: string, assertion: unknown) => Promise<OperationStatus>;
|
|
87
|
+
get: (id: string) => Promise<OperationStatus>;
|
|
88
|
+
list: () => Promise<OperationStatus[]>;
|
|
89
|
+
/** Prepare, have the passkey sign, submit, and wait for inclusion. */
|
|
90
|
+
run: (kind: OperationKind, o?: {
|
|
91
|
+
chain?: number;
|
|
92
|
+
wait?: WaitOptions | false;
|
|
93
|
+
}) => Promise<OperationStatus>;
|
|
94
|
+
wait: (id: string, w?: WaitOptions) => Promise<OperationStatus>;
|
|
95
|
+
};
|
|
96
|
+
recovery: {
|
|
97
|
+
status: (chain?: number) => Promise<RecoveryStatus>;
|
|
98
|
+
/** Start moving the account to the newest passkey. Needs a fresh step-up on `/me`. */
|
|
99
|
+
begin: (chain?: number) => Promise<RecoveryStatus>;
|
|
100
|
+
complete: (chain?: number) => Promise<RecoveryStatus>;
|
|
101
|
+
};
|
|
102
|
+
sessions: {
|
|
103
|
+
list: () => Promise<SessionKey[]>;
|
|
104
|
+
get: (id: string) => Promise<SessionKey>;
|
|
105
|
+
/** Act under a session key: no passkey, within the grant. */
|
|
106
|
+
execute: (id: string, call: ChainCall) => Promise<OperationStatus>;
|
|
107
|
+
/** Grant a session: a passkey-signed operation. Returns the session once the grant is on chain. */
|
|
108
|
+
grant: (session: SessionGrant, o?: {
|
|
109
|
+
chain?: number;
|
|
110
|
+
wait?: WaitOptions;
|
|
111
|
+
}) => Promise<{
|
|
112
|
+
session: SessionKey;
|
|
113
|
+
operation: OperationStatus;
|
|
114
|
+
}>;
|
|
115
|
+
/**
|
|
116
|
+
* Extend a key that already exists, keeping its address. One passkey
|
|
117
|
+
* ceremony and no new key to distribute — and the spent counter
|
|
118
|
+
* restarts, because that is what the account does with a fresh grant.
|
|
119
|
+
*/
|
|
120
|
+
renew: (session: SessionRenewal, o?: {
|
|
121
|
+
chain?: number;
|
|
122
|
+
wait?: WaitOptions;
|
|
123
|
+
}) => Promise<{
|
|
124
|
+
session: SessionKey;
|
|
125
|
+
operation: OperationStatus;
|
|
126
|
+
}>;
|
|
127
|
+
revoke: (id: string, o?: {
|
|
128
|
+
chain?: number;
|
|
129
|
+
wait?: WaitOptions;
|
|
130
|
+
}) => Promise<OperationStatus>;
|
|
131
|
+
};
|
|
132
|
+
solana: {
|
|
133
|
+
account: (cluster?: string) => Promise<SolanaAccount | null>;
|
|
134
|
+
operations: {
|
|
135
|
+
prepare: (action: SolanaAction, cluster?: string) => Promise<PreparedSolanaOperation>;
|
|
136
|
+
submit: (id: string, assertion: unknown) => Promise<SolanaOperationStatus>;
|
|
137
|
+
get: (id: string) => Promise<SolanaOperationStatus>;
|
|
138
|
+
list: () => Promise<SolanaOperationStatus[]>;
|
|
139
|
+
run: (action: SolanaAction, cluster?: string) => Promise<SolanaOperationStatus>;
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* Session keys on Solana. The key signs the transaction itself, so
|
|
143
|
+
* `execute` is one call: no ceremony, no confirmation to wait for.
|
|
144
|
+
*/
|
|
145
|
+
sessions: {
|
|
146
|
+
list: () => Promise<SolanaSessionKey[]>;
|
|
147
|
+
get: (id: string) => Promise<SolanaSessionKey>;
|
|
148
|
+
/** Act under a session key: no passkey, within the grant. */
|
|
149
|
+
execute: (id: string, action: SolanaAction) => Promise<SolanaOperationStatus>;
|
|
150
|
+
/** Grant a session: a passkey-signed operation, as every grant is. */
|
|
151
|
+
grant: (session: SolanaSessionGrant, cluster?: string) => Promise<{
|
|
152
|
+
session: SolanaSessionKey;
|
|
153
|
+
operation: SolanaOperationStatus;
|
|
154
|
+
}>;
|
|
155
|
+
/** The same, on Solana: one ceremony, the same key, the tally reset. */
|
|
156
|
+
renew: (session: SessionRenewal, cluster?: string) => Promise<{
|
|
157
|
+
session: SolanaSessionKey;
|
|
158
|
+
operation: SolanaOperationStatus;
|
|
159
|
+
}>;
|
|
160
|
+
revoke: (id: string, cluster?: string) => Promise<SolanaOperationStatus>;
|
|
161
|
+
};
|
|
162
|
+
/** Guardian recovery on Solana: the same shape as the EVM side. */
|
|
163
|
+
recovery: {
|
|
164
|
+
status: (cluster?: string) => Promise<SolanaRecoveryStatus>;
|
|
165
|
+
/** Needs a fresh step-up on `/me`. */
|
|
166
|
+
begin: (cluster?: string) => Promise<SolanaRecoveryStatus>;
|
|
167
|
+
complete: (cluster?: string) => Promise<SolanaRecoveryStatus>;
|
|
168
|
+
};
|
|
169
|
+
};
|
|
170
|
+
};
|
|
171
|
+
/**
|
|
172
|
+
* Self-serve projects, for a console app.
|
|
173
|
+
*
|
|
174
|
+
* These act as the signed-in *developer* — a user of the console tenant —
|
|
175
|
+
* so they need that tenant's publishable key and the developer's own bearer
|
|
176
|
+
* token, exactly like any other `/v1/me` call. A developer can only ever
|
|
177
|
+
* reach projects they created.
|
|
178
|
+
*/
|
|
179
|
+
console: {
|
|
180
|
+
/**
|
|
181
|
+
* Every chain a project could be pointed at, across both account models.
|
|
182
|
+
*
|
|
183
|
+
* Not the same as {@link chains}, which answers for the calling tenant.
|
|
184
|
+
* A project does not exist yet when this is asked.
|
|
185
|
+
*/
|
|
186
|
+
chains: () => Promise<AvailableChain[]>;
|
|
187
|
+
projects: () => Promise<Project[]>;
|
|
188
|
+
create: (project: NewProject) => Promise<Project>;
|
|
189
|
+
keys: (slug: string) => Promise<ApiKeySummary[]>;
|
|
190
|
+
/** The key is in the response and never again. Show it once, then store it. */
|
|
191
|
+
issueKey: (slug: string, key: NewProjectKey) => Promise<IssuedKey>;
|
|
192
|
+
revokeKey: (slug: string, prefix: string) => Promise<{
|
|
193
|
+
revoked: boolean;
|
|
194
|
+
}>;
|
|
195
|
+
/** Rename a project. Cosmetic — the slug does not move. */
|
|
196
|
+
rename: (slug: string, name: string) => Promise<Project>;
|
|
197
|
+
/**
|
|
198
|
+
* Change which chain a call that names none gets. Safe at any time: it
|
|
199
|
+
* moves no address. Refused if the chain is not registered for the
|
|
200
|
+
* project's account model.
|
|
201
|
+
*/
|
|
202
|
+
setDefaultChain: (slug: string, chain: number) => Promise<Project>;
|
|
203
|
+
/**
|
|
204
|
+
* Put a project away, or take it back out. Not a delete: the accounts it
|
|
205
|
+
* owns exist on a chain and archiving does not touch them. An archived
|
|
206
|
+
* project's keys stop working and it stops counting against the project
|
|
207
|
+
* limit.
|
|
208
|
+
*/
|
|
209
|
+
setArchived: (slug: string, archived: boolean) => Promise<Project>;
|
|
210
|
+
setOrigins: (slug: string, origins: string[]) => Promise<Project>;
|
|
211
|
+
/** Lowering is always allowed; raising is capped at the operator's ceiling. */
|
|
212
|
+
setBudget: (slug: string, dailyWei: string | null) => Promise<Project>;
|
|
213
|
+
};
|
|
214
|
+
/**
|
|
215
|
+
* The chains this tenant's users can hold accounts on.
|
|
216
|
+
*
|
|
217
|
+
* Readable with a publishable key, so an app can offer a choice rather
|
|
218
|
+
* than hardcoding what an operator may change. Pass `chain` to any
|
|
219
|
+
* account or operation call to use one.
|
|
220
|
+
*/
|
|
221
|
+
chains(): Promise<ChainOption[]>;
|
|
222
|
+
/**
|
|
223
|
+
* Resolve an end user's access token into who they are.
|
|
224
|
+
*
|
|
225
|
+
* For a server holding a token its front end sent: it says which user, in
|
|
226
|
+
* which session, and how strongly they are authenticated. Needs a secret
|
|
227
|
+
* key, because it speaks for the tenant rather than for a user.
|
|
228
|
+
*
|
|
229
|
+
* Use {@link effectiveAssurance} on the result rather than reading
|
|
230
|
+
* `subject.aal`, which is the base level and ignores a step-up that has
|
|
231
|
+
* since gone stale.
|
|
232
|
+
*/
|
|
233
|
+
authenticate(accessToken: string): Promise<Caller>;
|
|
234
|
+
users(userId: string): {
|
|
235
|
+
account: (chain?: number) => Promise<SmartAccount | null>;
|
|
236
|
+
identities: () => Promise<IdentitySummary[]>;
|
|
237
|
+
signOutEverywhere: (reason?: string) => Promise<void>;
|
|
238
|
+
operations: {
|
|
239
|
+
prepare: (kind: OperationKind, chain?: number) => Promise<PreparedOperation>;
|
|
240
|
+
submit: (id: string, assertion: unknown) => Promise<OperationStatus>;
|
|
241
|
+
get: (id: string) => Promise<OperationStatus>;
|
|
242
|
+
list: () => Promise<OperationStatus[]>;
|
|
243
|
+
/** Prepare, have the passkey sign, submit, and wait for inclusion. */
|
|
244
|
+
run: (kind: OperationKind, o?: {
|
|
245
|
+
chain?: number;
|
|
246
|
+
wait?: WaitOptions | false;
|
|
247
|
+
}) => Promise<OperationStatus>;
|
|
248
|
+
wait: (id: string, w?: WaitOptions) => Promise<OperationStatus>;
|
|
249
|
+
};
|
|
250
|
+
recovery: {
|
|
251
|
+
status: (chain?: number) => Promise<RecoveryStatus>;
|
|
252
|
+
/** Start moving the account to the newest passkey. Needs a fresh step-up on `/me`. */
|
|
253
|
+
begin: (chain?: number) => Promise<RecoveryStatus>;
|
|
254
|
+
complete: (chain?: number) => Promise<RecoveryStatus>;
|
|
255
|
+
};
|
|
256
|
+
sessions: {
|
|
257
|
+
list: () => Promise<SessionKey[]>;
|
|
258
|
+
get: (id: string) => Promise<SessionKey>;
|
|
259
|
+
/** Act under a session key: no passkey, within the grant. */
|
|
260
|
+
execute: (id: string, call: ChainCall) => Promise<OperationStatus>;
|
|
261
|
+
/** Grant a session: a passkey-signed operation. Returns the session once the grant is on chain. */
|
|
262
|
+
grant: (session: SessionGrant, o?: {
|
|
263
|
+
chain?: number;
|
|
264
|
+
wait?: WaitOptions;
|
|
265
|
+
}) => Promise<{
|
|
266
|
+
session: SessionKey;
|
|
267
|
+
operation: OperationStatus;
|
|
268
|
+
}>;
|
|
269
|
+
/**
|
|
270
|
+
* Extend a key that already exists, keeping its address. One passkey
|
|
271
|
+
* ceremony and no new key to distribute — and the spent counter
|
|
272
|
+
* restarts, because that is what the account does with a fresh grant.
|
|
273
|
+
*/
|
|
274
|
+
renew: (session: SessionRenewal, o?: {
|
|
275
|
+
chain?: number;
|
|
276
|
+
wait?: WaitOptions;
|
|
277
|
+
}) => Promise<{
|
|
278
|
+
session: SessionKey;
|
|
279
|
+
operation: OperationStatus;
|
|
280
|
+
}>;
|
|
281
|
+
revoke: (id: string, o?: {
|
|
282
|
+
chain?: number;
|
|
283
|
+
wait?: WaitOptions;
|
|
284
|
+
}) => Promise<OperationStatus>;
|
|
285
|
+
};
|
|
286
|
+
solana: {
|
|
287
|
+
account: (cluster?: string) => Promise<SolanaAccount | null>;
|
|
288
|
+
operations: {
|
|
289
|
+
prepare: (action: SolanaAction, cluster?: string) => Promise<PreparedSolanaOperation>;
|
|
290
|
+
submit: (id: string, assertion: unknown) => Promise<SolanaOperationStatus>;
|
|
291
|
+
get: (id: string) => Promise<SolanaOperationStatus>;
|
|
292
|
+
list: () => Promise<SolanaOperationStatus[]>;
|
|
293
|
+
run: (action: SolanaAction, cluster?: string) => Promise<SolanaOperationStatus>;
|
|
294
|
+
};
|
|
295
|
+
/**
|
|
296
|
+
* Session keys on Solana. The key signs the transaction itself, so
|
|
297
|
+
* `execute` is one call: no ceremony, no confirmation to wait for.
|
|
298
|
+
*/
|
|
299
|
+
sessions: {
|
|
300
|
+
list: () => Promise<SolanaSessionKey[]>;
|
|
301
|
+
get: (id: string) => Promise<SolanaSessionKey>;
|
|
302
|
+
/** Act under a session key: no passkey, within the grant. */
|
|
303
|
+
execute: (id: string, action: SolanaAction) => Promise<SolanaOperationStatus>;
|
|
304
|
+
/** Grant a session: a passkey-signed operation, as every grant is. */
|
|
305
|
+
grant: (session: SolanaSessionGrant, cluster?: string) => Promise<{
|
|
306
|
+
session: SolanaSessionKey;
|
|
307
|
+
operation: SolanaOperationStatus;
|
|
308
|
+
}>;
|
|
309
|
+
/** The same, on Solana: one ceremony, the same key, the tally reset. */
|
|
310
|
+
renew: (session: SessionRenewal, cluster?: string) => Promise<{
|
|
311
|
+
session: SolanaSessionKey;
|
|
312
|
+
operation: SolanaOperationStatus;
|
|
313
|
+
}>;
|
|
314
|
+
revoke: (id: string, cluster?: string) => Promise<SolanaOperationStatus>;
|
|
315
|
+
};
|
|
316
|
+
/** Guardian recovery on Solana: the same shape as the EVM side. */
|
|
317
|
+
recovery: {
|
|
318
|
+
status: (cluster?: string) => Promise<SolanaRecoveryStatus>;
|
|
319
|
+
/** Needs a fresh step-up on `/me`. */
|
|
320
|
+
begin: (cluster?: string) => Promise<SolanaRecoveryStatus>;
|
|
321
|
+
complete: (cluster?: string) => Promise<SolanaRecoveryStatus>;
|
|
322
|
+
};
|
|
323
|
+
};
|
|
324
|
+
};
|
|
325
|
+
/** The user's Solana account and operations: the same passkey, a second ledger. */
|
|
326
|
+
private solanaAt;
|
|
327
|
+
private operationsAt;
|
|
328
|
+
private recoveryAt;
|
|
329
|
+
private sessionsAt;
|
|
330
|
+
}
|
|
331
|
+
//# sourceMappingURL=client.d.ts.map
|