@waaskey/sdk 0.0.1

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Waaskey
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,54 @@
1
+ # @waaskey/sdk
2
+
3
+ Official TypeScript SDK for [Waaskey](https://waaskey.com) — embedded, non-custodial
4
+ **MPC wallets** for your app. Create wallets and sign transactions where the private
5
+ key is never assembled in one place (2-of-3 threshold ECDSA, no seed phrase).
6
+
7
+ > **Early access (v0.0.x).** The public API is taking shape and may change before
8
+ > `1.0.0`. Pin an exact version.
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ pnpm add @waaskey/sdk
14
+ ```
15
+
16
+ ## Quickstart
17
+
18
+ ```ts
19
+ import { Waaskey } from '@waaskey/sdk';
20
+
21
+ const waaskey = new Waaskey({ apiKey: process.env.WAASKEY_PUBLISHABLE_KEY! });
22
+
23
+ // Create an MPC wallet
24
+ const wallet = await waaskey.wallets.create({ userId: user.id, chain: 'ethereum' });
25
+ // → { id: 'wlt_…', address: '0xabc…' }
26
+
27
+ // Sign a message (interactive threshold-MPC, one awaited call)
28
+ const signature = await wallet.signMessage('Hello Waaskey');
29
+ ```
30
+
31
+ ## API
32
+
33
+ | Method | Description |
34
+ | -------------------------------------------- | ----------------------------------------- |
35
+ | `new Waaskey({ apiKey, baseUrl?, fetch? })` | Create a client. |
36
+ | `waaskey.wallets.create({ chain, userId? })` | Create a new wallet. Returns a `Wallet`. |
37
+ | `waaskey.wallets.get(id)` | Load an existing wallet. |
38
+ | `wallet.signMessage(message)` | Sign a message with the wallet's MPC key. |
39
+
40
+ Errors are thrown as `WaaskeyError` (`{ message, status, code }`).
41
+
42
+ ## Development
43
+
44
+ ```bash
45
+ pnpm install
46
+ pnpm test:unit # vitest
47
+ pnpm types # tsc --noEmit
48
+ pnpm lint
49
+ pnpm build # tsup → dist (esm + cjs + d.ts)
50
+ ```
51
+
52
+ ## License
53
+
54
+ [MIT](./LICENSE) © Waaskey
package/dist/index.cjs ADDED
@@ -0,0 +1,104 @@
1
+ 'use strict';
2
+
3
+ // src/types.ts
4
+ var WaaskeyError = class extends Error {
5
+ constructor(message, status, code) {
6
+ super(message);
7
+ this.status = status;
8
+ this.code = code;
9
+ this.name = "WaaskeyError";
10
+ }
11
+ status;
12
+ code;
13
+ };
14
+
15
+ // src/http.ts
16
+ var HttpClient = class {
17
+ apiKey;
18
+ baseUrl;
19
+ fetchImpl;
20
+ constructor(apiKey, baseUrl, fetchImpl) {
21
+ this.apiKey = apiKey;
22
+ this.baseUrl = baseUrl.replace(/\/$/, "");
23
+ const resolved = fetchImpl ?? globalThis.fetch;
24
+ if (!resolved) {
25
+ throw new Error("No fetch implementation available \u2014 pass `fetch` in WaaskeyOptions.");
26
+ }
27
+ this.fetchImpl = resolved.bind(globalThis);
28
+ }
29
+ async request(method, path, body) {
30
+ const res = await this.fetchImpl(`${this.baseUrl}${path}`, {
31
+ method,
32
+ headers: {
33
+ authorization: `Bearer ${this.apiKey}`,
34
+ "content-type": "application/json"
35
+ },
36
+ body: body === void 0 ? void 0 : JSON.stringify(body)
37
+ });
38
+ if (!res.ok) {
39
+ const detail = await res.json().catch(() => ({}));
40
+ const message = typeof detail.message === "string" ? detail.message : res.statusText;
41
+ const code = typeof detail.code === "string" ? detail.code : void 0;
42
+ throw new WaaskeyError(message, res.status, code);
43
+ }
44
+ return await res.json();
45
+ }
46
+ };
47
+
48
+ // src/wallet.ts
49
+ var Wallet = class {
50
+ constructor(http, data) {
51
+ this.http = http;
52
+ this.id = data.id;
53
+ this.address = data.address;
54
+ this.chain = data.chain;
55
+ }
56
+ http;
57
+ id;
58
+ address;
59
+ chain;
60
+ /** Sign an arbitrary message with this wallet's key (2-of-3 threshold MPC). */
61
+ async signMessage(message) {
62
+ const { signature } = await this.http.request("POST", `/v1/wallets/${this.id}/sign-message`, { message });
63
+ return signature;
64
+ }
65
+ };
66
+
67
+ // src/wallets.ts
68
+ var Wallets = class {
69
+ constructor(http) {
70
+ this.http = http;
71
+ }
72
+ http;
73
+ /** Create a new MPC wallet on the given chain. */
74
+ async create(params) {
75
+ const data = await this.http.request("POST", "/v1/wallets", params);
76
+ return new Wallet(this.http, data);
77
+ }
78
+ /** Load an existing wallet by id. */
79
+ async get(id) {
80
+ const data = await this.http.request("GET", `/v1/wallets/${id}`);
81
+ return new Wallet(this.http, data);
82
+ }
83
+ };
84
+
85
+ // src/client.ts
86
+ var DEFAULT_BASE_URL = "https://api.waaskey.com";
87
+ var Waaskey = class {
88
+ /** The `wallets` resource. */
89
+ wallets;
90
+ constructor(options) {
91
+ if (!options?.apiKey) {
92
+ throw new Error("Waaskey: `apiKey` is required.");
93
+ }
94
+ const http = new HttpClient(options.apiKey, options.baseUrl ?? DEFAULT_BASE_URL, options.fetch);
95
+ this.wallets = new Wallets(http);
96
+ }
97
+ };
98
+
99
+ exports.Waaskey = Waaskey;
100
+ exports.WaaskeyError = WaaskeyError;
101
+ exports.Wallet = Wallet;
102
+ exports.Wallets = Wallets;
103
+ //# sourceMappingURL=index.cjs.map
104
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts","../src/http.ts","../src/wallet.ts","../src/wallets.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Public contract for the Waaskey SDK.\n *\n * These types describe the wire shapes the SDK exchanges with the Waaskey API.\n * They will be replaced by types generated from the backend OpenAPI spec once the\n * API contract is stable; until then this file is the single source of truth.\n */\n\n/** Chains a wallet can be created on. */\nexport type Chain = 'ethereum' | 'polygon' | 'arbitrum' | 'base' | 'optimism' | 'bitcoin' | 'solana';\n\n/** Options accepted by `new Waaskey(...)`. */\nexport interface WaaskeyOptions {\n /** Publishable API key issued from the Waaskey dashboard. */\n apiKey: string;\n /** API base URL. Defaults to the Waaskey production API. */\n baseUrl?: string;\n /** Custom fetch implementation (e.g. for non-browser runtimes). Defaults to global `fetch`. */\n fetch?: typeof fetch;\n}\n\n/** Parameters for creating a wallet. */\nexport interface CreateWalletParams {\n /** Your end-user's id in your own system; binds the wallet to that user. */\n userId?: string;\n /** Chain the wallet is created on. */\n chain: Chain;\n}\n\n/** A wallet as returned by the API. */\nexport interface WalletData {\n /** Waaskey wallet id, e.g. `wlt_...`. */\n id: string;\n /** On-chain address. */\n address: string;\n /** Chain the wallet belongs to. */\n chain: Chain;\n}\n\n/** Error thrown for any non-2xx API response. */\nexport class WaaskeyError extends Error {\n constructor(\n message: string,\n readonly status: number,\n readonly code?: string,\n ) {\n super(message);\n this.name = 'WaaskeyError';\n }\n}\n","import { WaaskeyError } from './types';\n\n/** Thin typed HTTP client over fetch — the single place requests are issued. */\nexport class HttpClient {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private readonly fetchImpl: typeof fetch;\n\n constructor(apiKey: string, baseUrl: string, fetchImpl?: typeof fetch) {\n this.apiKey = apiKey;\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n const resolved = fetchImpl ?? globalThis.fetch;\n if (!resolved) {\n throw new Error('No fetch implementation available — pass `fetch` in WaaskeyOptions.');\n }\n this.fetchImpl = resolved.bind(globalThis);\n }\n\n async request<T>(method: string, path: string, body?: unknown): Promise<T> {\n const res = await this.fetchImpl(`${this.baseUrl}${path}`, {\n method,\n headers: {\n authorization: `Bearer ${this.apiKey}`,\n 'content-type': 'application/json',\n },\n body: body === undefined ? undefined : JSON.stringify(body),\n });\n\n if (!res.ok) {\n const detail = await res.json().catch(() => ({}) as Record<string, unknown>);\n const message = typeof detail.message === 'string' ? detail.message : res.statusText;\n const code = typeof detail.code === 'string' ? detail.code : undefined;\n throw new WaaskeyError(message, res.status, code);\n }\n\n return (await res.json()) as T;\n }\n}\n","import type { HttpClient } from './http';\nimport type { Chain, WalletData } from './types';\n\n/**\n * A handle to a single wallet. Returned by `waaskey.wallets.create(...)`.\n *\n * Signing is an interactive threshold-MPC protocol; from the caller's point of\n * view it is a single awaited call that returns the signature.\n */\nexport class Wallet implements WalletData {\n readonly id: string;\n readonly address: string;\n readonly chain: Chain;\n\n constructor(\n private readonly http: HttpClient,\n data: WalletData,\n ) {\n this.id = data.id;\n this.address = data.address;\n this.chain = data.chain;\n }\n\n /** Sign an arbitrary message with this wallet's key (2-of-3 threshold MPC). */\n async signMessage(message: string): Promise<string> {\n const { signature } = await this.http.request<{ signature: string }>('POST', `/v1/wallets/${this.id}/sign-message`, { message });\n return signature;\n }\n}\n","import type { HttpClient } from './http';\nimport type { CreateWalletParams, WalletData } from './types';\nimport { Wallet } from './wallet';\n\n/** The `wallets` resource: create and load wallets. */\nexport class Wallets {\n constructor(private readonly http: HttpClient) {}\n\n /** Create a new MPC wallet on the given chain. */\n async create(params: CreateWalletParams): Promise<Wallet> {\n const data = await this.http.request<WalletData>('POST', '/v1/wallets', params);\n return new Wallet(this.http, data);\n }\n\n /** Load an existing wallet by id. */\n async get(id: string): Promise<Wallet> {\n const data = await this.http.request<WalletData>('GET', `/v1/wallets/${id}`);\n return new Wallet(this.http, data);\n }\n}\n","import { HttpClient } from './http';\nimport type { WaaskeyOptions } from './types';\nimport { Wallets } from './wallets';\n\nconst DEFAULT_BASE_URL = 'https://api.waaskey.com';\n\n/**\n * The Waaskey client — entry point of the SDK.\n *\n * @example\n * ```ts\n * import { Waaskey } from '@waaskey/sdk';\n *\n * const waaskey = new Waaskey({ apiKey: process.env.WAASKEY_PUBLISHABLE_KEY! });\n * const wallet = await waaskey.wallets.create({ userId: user.id, chain: 'ethereum' });\n * const signature = await wallet.signMessage('Hello Waaskey');\n * ```\n */\nexport class Waaskey {\n /** The `wallets` resource. */\n readonly wallets: Wallets;\n\n constructor(options: WaaskeyOptions) {\n if (!options?.apiKey) {\n throw new Error('Waaskey: `apiKey` is required.');\n }\n const http = new HttpClient(options.apiKey, options.baseUrl ?? DEFAULT_BASE_URL, options.fetch);\n this.wallets = new Wallets(http);\n }\n}\n"]}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Public contract for the Waaskey SDK.
3
+ *
4
+ * These types describe the wire shapes the SDK exchanges with the Waaskey API.
5
+ * They will be replaced by types generated from the backend OpenAPI spec once the
6
+ * API contract is stable; until then this file is the single source of truth.
7
+ */
8
+ /** Chains a wallet can be created on. */
9
+ type Chain = 'ethereum' | 'polygon' | 'arbitrum' | 'base' | 'optimism' | 'bitcoin' | 'solana';
10
+ /** Options accepted by `new Waaskey(...)`. */
11
+ interface WaaskeyOptions {
12
+ /** Publishable API key issued from the Waaskey dashboard. */
13
+ apiKey: string;
14
+ /** API base URL. Defaults to the Waaskey production API. */
15
+ baseUrl?: string;
16
+ /** Custom fetch implementation (e.g. for non-browser runtimes). Defaults to global `fetch`. */
17
+ fetch?: typeof fetch;
18
+ }
19
+ /** Parameters for creating a wallet. */
20
+ interface CreateWalletParams {
21
+ /** Your end-user's id in your own system; binds the wallet to that user. */
22
+ userId?: string;
23
+ /** Chain the wallet is created on. */
24
+ chain: Chain;
25
+ }
26
+ /** A wallet as returned by the API. */
27
+ interface WalletData {
28
+ /** Waaskey wallet id, e.g. `wlt_...`. */
29
+ id: string;
30
+ /** On-chain address. */
31
+ address: string;
32
+ /** Chain the wallet belongs to. */
33
+ chain: Chain;
34
+ }
35
+ /** Error thrown for any non-2xx API response. */
36
+ declare class WaaskeyError extends Error {
37
+ readonly status: number;
38
+ readonly code?: string | undefined;
39
+ constructor(message: string, status: number, code?: string | undefined);
40
+ }
41
+
42
+ /** Thin typed HTTP client over fetch — the single place requests are issued. */
43
+ declare class HttpClient {
44
+ private readonly apiKey;
45
+ private readonly baseUrl;
46
+ private readonly fetchImpl;
47
+ constructor(apiKey: string, baseUrl: string, fetchImpl?: typeof fetch);
48
+ request<T>(method: string, path: string, body?: unknown): Promise<T>;
49
+ }
50
+
51
+ /**
52
+ * A handle to a single wallet. Returned by `waaskey.wallets.create(...)`.
53
+ *
54
+ * Signing is an interactive threshold-MPC protocol; from the caller's point of
55
+ * view it is a single awaited call that returns the signature.
56
+ */
57
+ declare class Wallet implements WalletData {
58
+ private readonly http;
59
+ readonly id: string;
60
+ readonly address: string;
61
+ readonly chain: Chain;
62
+ constructor(http: HttpClient, data: WalletData);
63
+ /** Sign an arbitrary message with this wallet's key (2-of-3 threshold MPC). */
64
+ signMessage(message: string): Promise<string>;
65
+ }
66
+
67
+ /** The `wallets` resource: create and load wallets. */
68
+ declare class Wallets {
69
+ private readonly http;
70
+ constructor(http: HttpClient);
71
+ /** Create a new MPC wallet on the given chain. */
72
+ create(params: CreateWalletParams): Promise<Wallet>;
73
+ /** Load an existing wallet by id. */
74
+ get(id: string): Promise<Wallet>;
75
+ }
76
+
77
+ /**
78
+ * The Waaskey client — entry point of the SDK.
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * import { Waaskey } from '@waaskey/sdk';
83
+ *
84
+ * const waaskey = new Waaskey({ apiKey: process.env.WAASKEY_PUBLISHABLE_KEY! });
85
+ * const wallet = await waaskey.wallets.create({ userId: user.id, chain: 'ethereum' });
86
+ * const signature = await wallet.signMessage('Hello Waaskey');
87
+ * ```
88
+ */
89
+ declare class Waaskey {
90
+ /** The `wallets` resource. */
91
+ readonly wallets: Wallets;
92
+ constructor(options: WaaskeyOptions);
93
+ }
94
+
95
+ export { type Chain, type CreateWalletParams, Waaskey, WaaskeyError, type WaaskeyOptions, Wallet, type WalletData, Wallets };
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Public contract for the Waaskey SDK.
3
+ *
4
+ * These types describe the wire shapes the SDK exchanges with the Waaskey API.
5
+ * They will be replaced by types generated from the backend OpenAPI spec once the
6
+ * API contract is stable; until then this file is the single source of truth.
7
+ */
8
+ /** Chains a wallet can be created on. */
9
+ type Chain = 'ethereum' | 'polygon' | 'arbitrum' | 'base' | 'optimism' | 'bitcoin' | 'solana';
10
+ /** Options accepted by `new Waaskey(...)`. */
11
+ interface WaaskeyOptions {
12
+ /** Publishable API key issued from the Waaskey dashboard. */
13
+ apiKey: string;
14
+ /** API base URL. Defaults to the Waaskey production API. */
15
+ baseUrl?: string;
16
+ /** Custom fetch implementation (e.g. for non-browser runtimes). Defaults to global `fetch`. */
17
+ fetch?: typeof fetch;
18
+ }
19
+ /** Parameters for creating a wallet. */
20
+ interface CreateWalletParams {
21
+ /** Your end-user's id in your own system; binds the wallet to that user. */
22
+ userId?: string;
23
+ /** Chain the wallet is created on. */
24
+ chain: Chain;
25
+ }
26
+ /** A wallet as returned by the API. */
27
+ interface WalletData {
28
+ /** Waaskey wallet id, e.g. `wlt_...`. */
29
+ id: string;
30
+ /** On-chain address. */
31
+ address: string;
32
+ /** Chain the wallet belongs to. */
33
+ chain: Chain;
34
+ }
35
+ /** Error thrown for any non-2xx API response. */
36
+ declare class WaaskeyError extends Error {
37
+ readonly status: number;
38
+ readonly code?: string | undefined;
39
+ constructor(message: string, status: number, code?: string | undefined);
40
+ }
41
+
42
+ /** Thin typed HTTP client over fetch — the single place requests are issued. */
43
+ declare class HttpClient {
44
+ private readonly apiKey;
45
+ private readonly baseUrl;
46
+ private readonly fetchImpl;
47
+ constructor(apiKey: string, baseUrl: string, fetchImpl?: typeof fetch);
48
+ request<T>(method: string, path: string, body?: unknown): Promise<T>;
49
+ }
50
+
51
+ /**
52
+ * A handle to a single wallet. Returned by `waaskey.wallets.create(...)`.
53
+ *
54
+ * Signing is an interactive threshold-MPC protocol; from the caller's point of
55
+ * view it is a single awaited call that returns the signature.
56
+ */
57
+ declare class Wallet implements WalletData {
58
+ private readonly http;
59
+ readonly id: string;
60
+ readonly address: string;
61
+ readonly chain: Chain;
62
+ constructor(http: HttpClient, data: WalletData);
63
+ /** Sign an arbitrary message with this wallet's key (2-of-3 threshold MPC). */
64
+ signMessage(message: string): Promise<string>;
65
+ }
66
+
67
+ /** The `wallets` resource: create and load wallets. */
68
+ declare class Wallets {
69
+ private readonly http;
70
+ constructor(http: HttpClient);
71
+ /** Create a new MPC wallet on the given chain. */
72
+ create(params: CreateWalletParams): Promise<Wallet>;
73
+ /** Load an existing wallet by id. */
74
+ get(id: string): Promise<Wallet>;
75
+ }
76
+
77
+ /**
78
+ * The Waaskey client — entry point of the SDK.
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * import { Waaskey } from '@waaskey/sdk';
83
+ *
84
+ * const waaskey = new Waaskey({ apiKey: process.env.WAASKEY_PUBLISHABLE_KEY! });
85
+ * const wallet = await waaskey.wallets.create({ userId: user.id, chain: 'ethereum' });
86
+ * const signature = await wallet.signMessage('Hello Waaskey');
87
+ * ```
88
+ */
89
+ declare class Waaskey {
90
+ /** The `wallets` resource. */
91
+ readonly wallets: Wallets;
92
+ constructor(options: WaaskeyOptions);
93
+ }
94
+
95
+ export { type Chain, type CreateWalletParams, Waaskey, WaaskeyError, type WaaskeyOptions, Wallet, type WalletData, Wallets };
package/dist/index.js ADDED
@@ -0,0 +1,99 @@
1
+ // src/types.ts
2
+ var WaaskeyError = class extends Error {
3
+ constructor(message, status, code) {
4
+ super(message);
5
+ this.status = status;
6
+ this.code = code;
7
+ this.name = "WaaskeyError";
8
+ }
9
+ status;
10
+ code;
11
+ };
12
+
13
+ // src/http.ts
14
+ var HttpClient = class {
15
+ apiKey;
16
+ baseUrl;
17
+ fetchImpl;
18
+ constructor(apiKey, baseUrl, fetchImpl) {
19
+ this.apiKey = apiKey;
20
+ this.baseUrl = baseUrl.replace(/\/$/, "");
21
+ const resolved = fetchImpl ?? globalThis.fetch;
22
+ if (!resolved) {
23
+ throw new Error("No fetch implementation available \u2014 pass `fetch` in WaaskeyOptions.");
24
+ }
25
+ this.fetchImpl = resolved.bind(globalThis);
26
+ }
27
+ async request(method, path, body) {
28
+ const res = await this.fetchImpl(`${this.baseUrl}${path}`, {
29
+ method,
30
+ headers: {
31
+ authorization: `Bearer ${this.apiKey}`,
32
+ "content-type": "application/json"
33
+ },
34
+ body: body === void 0 ? void 0 : JSON.stringify(body)
35
+ });
36
+ if (!res.ok) {
37
+ const detail = await res.json().catch(() => ({}));
38
+ const message = typeof detail.message === "string" ? detail.message : res.statusText;
39
+ const code = typeof detail.code === "string" ? detail.code : void 0;
40
+ throw new WaaskeyError(message, res.status, code);
41
+ }
42
+ return await res.json();
43
+ }
44
+ };
45
+
46
+ // src/wallet.ts
47
+ var Wallet = class {
48
+ constructor(http, data) {
49
+ this.http = http;
50
+ this.id = data.id;
51
+ this.address = data.address;
52
+ this.chain = data.chain;
53
+ }
54
+ http;
55
+ id;
56
+ address;
57
+ chain;
58
+ /** Sign an arbitrary message with this wallet's key (2-of-3 threshold MPC). */
59
+ async signMessage(message) {
60
+ const { signature } = await this.http.request("POST", `/v1/wallets/${this.id}/sign-message`, { message });
61
+ return signature;
62
+ }
63
+ };
64
+
65
+ // src/wallets.ts
66
+ var Wallets = class {
67
+ constructor(http) {
68
+ this.http = http;
69
+ }
70
+ http;
71
+ /** Create a new MPC wallet on the given chain. */
72
+ async create(params) {
73
+ const data = await this.http.request("POST", "/v1/wallets", params);
74
+ return new Wallet(this.http, data);
75
+ }
76
+ /** Load an existing wallet by id. */
77
+ async get(id) {
78
+ const data = await this.http.request("GET", `/v1/wallets/${id}`);
79
+ return new Wallet(this.http, data);
80
+ }
81
+ };
82
+
83
+ // src/client.ts
84
+ var DEFAULT_BASE_URL = "https://api.waaskey.com";
85
+ var Waaskey = class {
86
+ /** The `wallets` resource. */
87
+ wallets;
88
+ constructor(options) {
89
+ if (!options?.apiKey) {
90
+ throw new Error("Waaskey: `apiKey` is required.");
91
+ }
92
+ const http = new HttpClient(options.apiKey, options.baseUrl ?? DEFAULT_BASE_URL, options.fetch);
93
+ this.wallets = new Wallets(http);
94
+ }
95
+ };
96
+
97
+ export { Waaskey, WaaskeyError, Wallet, Wallets };
98
+ //# sourceMappingURL=index.js.map
99
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts","../src/http.ts","../src/wallet.ts","../src/wallets.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Public contract for the Waaskey SDK.\n *\n * These types describe the wire shapes the SDK exchanges with the Waaskey API.\n * They will be replaced by types generated from the backend OpenAPI spec once the\n * API contract is stable; until then this file is the single source of truth.\n */\n\n/** Chains a wallet can be created on. */\nexport type Chain = 'ethereum' | 'polygon' | 'arbitrum' | 'base' | 'optimism' | 'bitcoin' | 'solana';\n\n/** Options accepted by `new Waaskey(...)`. */\nexport interface WaaskeyOptions {\n /** Publishable API key issued from the Waaskey dashboard. */\n apiKey: string;\n /** API base URL. Defaults to the Waaskey production API. */\n baseUrl?: string;\n /** Custom fetch implementation (e.g. for non-browser runtimes). Defaults to global `fetch`. */\n fetch?: typeof fetch;\n}\n\n/** Parameters for creating a wallet. */\nexport interface CreateWalletParams {\n /** Your end-user's id in your own system; binds the wallet to that user. */\n userId?: string;\n /** Chain the wallet is created on. */\n chain: Chain;\n}\n\n/** A wallet as returned by the API. */\nexport interface WalletData {\n /** Waaskey wallet id, e.g. `wlt_...`. */\n id: string;\n /** On-chain address. */\n address: string;\n /** Chain the wallet belongs to. */\n chain: Chain;\n}\n\n/** Error thrown for any non-2xx API response. */\nexport class WaaskeyError extends Error {\n constructor(\n message: string,\n readonly status: number,\n readonly code?: string,\n ) {\n super(message);\n this.name = 'WaaskeyError';\n }\n}\n","import { WaaskeyError } from './types';\n\n/** Thin typed HTTP client over fetch — the single place requests are issued. */\nexport class HttpClient {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private readonly fetchImpl: typeof fetch;\n\n constructor(apiKey: string, baseUrl: string, fetchImpl?: typeof fetch) {\n this.apiKey = apiKey;\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n const resolved = fetchImpl ?? globalThis.fetch;\n if (!resolved) {\n throw new Error('No fetch implementation available — pass `fetch` in WaaskeyOptions.');\n }\n this.fetchImpl = resolved.bind(globalThis);\n }\n\n async request<T>(method: string, path: string, body?: unknown): Promise<T> {\n const res = await this.fetchImpl(`${this.baseUrl}${path}`, {\n method,\n headers: {\n authorization: `Bearer ${this.apiKey}`,\n 'content-type': 'application/json',\n },\n body: body === undefined ? undefined : JSON.stringify(body),\n });\n\n if (!res.ok) {\n const detail = await res.json().catch(() => ({}) as Record<string, unknown>);\n const message = typeof detail.message === 'string' ? detail.message : res.statusText;\n const code = typeof detail.code === 'string' ? detail.code : undefined;\n throw new WaaskeyError(message, res.status, code);\n }\n\n return (await res.json()) as T;\n }\n}\n","import type { HttpClient } from './http';\nimport type { Chain, WalletData } from './types';\n\n/**\n * A handle to a single wallet. Returned by `waaskey.wallets.create(...)`.\n *\n * Signing is an interactive threshold-MPC protocol; from the caller's point of\n * view it is a single awaited call that returns the signature.\n */\nexport class Wallet implements WalletData {\n readonly id: string;\n readonly address: string;\n readonly chain: Chain;\n\n constructor(\n private readonly http: HttpClient,\n data: WalletData,\n ) {\n this.id = data.id;\n this.address = data.address;\n this.chain = data.chain;\n }\n\n /** Sign an arbitrary message with this wallet's key (2-of-3 threshold MPC). */\n async signMessage(message: string): Promise<string> {\n const { signature } = await this.http.request<{ signature: string }>('POST', `/v1/wallets/${this.id}/sign-message`, { message });\n return signature;\n }\n}\n","import type { HttpClient } from './http';\nimport type { CreateWalletParams, WalletData } from './types';\nimport { Wallet } from './wallet';\n\n/** The `wallets` resource: create and load wallets. */\nexport class Wallets {\n constructor(private readonly http: HttpClient) {}\n\n /** Create a new MPC wallet on the given chain. */\n async create(params: CreateWalletParams): Promise<Wallet> {\n const data = await this.http.request<WalletData>('POST', '/v1/wallets', params);\n return new Wallet(this.http, data);\n }\n\n /** Load an existing wallet by id. */\n async get(id: string): Promise<Wallet> {\n const data = await this.http.request<WalletData>('GET', `/v1/wallets/${id}`);\n return new Wallet(this.http, data);\n }\n}\n","import { HttpClient } from './http';\nimport type { WaaskeyOptions } from './types';\nimport { Wallets } from './wallets';\n\nconst DEFAULT_BASE_URL = 'https://api.waaskey.com';\n\n/**\n * The Waaskey client — entry point of the SDK.\n *\n * @example\n * ```ts\n * import { Waaskey } from '@waaskey/sdk';\n *\n * const waaskey = new Waaskey({ apiKey: process.env.WAASKEY_PUBLISHABLE_KEY! });\n * const wallet = await waaskey.wallets.create({ userId: user.id, chain: 'ethereum' });\n * const signature = await wallet.signMessage('Hello Waaskey');\n * ```\n */\nexport class Waaskey {\n /** The `wallets` resource. */\n readonly wallets: Wallets;\n\n constructor(options: WaaskeyOptions) {\n if (!options?.apiKey) {\n throw new Error('Waaskey: `apiKey` is required.');\n }\n const http = new HttpClient(options.apiKey, options.baseUrl ?? DEFAULT_BASE_URL, options.fetch);\n this.wallets = new Wallets(http);\n }\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "@waaskey/sdk",
3
+ "version": "0.0.1",
4
+ "description": "Waaskey — embedded, non-custodial MPC wallets for your app. Official TypeScript SDK.",
5
+ "license": "MIT",
6
+ "author": "Waaskey",
7
+ "homepage": "https://waaskey.com",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/Next-Vector/waas-sdk.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/Next-Vector/waas-sdk/issues"
14
+ },
15
+ "keywords": [
16
+ "waaskey",
17
+ "wallet",
18
+ "mpc",
19
+ "web3",
20
+ "ethereum",
21
+ "non-custodial",
22
+ "embedded-wallet"
23
+ ],
24
+ "type": "module",
25
+ "main": "./dist/index.cjs",
26
+ "module": "./dist/index.js",
27
+ "types": "./dist/index.d.ts",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "import": "./dist/index.js",
32
+ "require": "./dist/index.cjs"
33
+ }
34
+ },
35
+ "files": [
36
+ "dist",
37
+ "README.md",
38
+ "LICENSE"
39
+ ],
40
+ "sideEffects": false,
41
+ "engines": {
42
+ "node": ">=22"
43
+ },
44
+ "packageManager": "pnpm@10.28.2",
45
+ "publishConfig": {
46
+ "access": "public"
47
+ },
48
+ "scripts": {
49
+ "build": "tsup",
50
+ "start": "tsup --watch",
51
+ "types": "tsc --noEmit",
52
+ "lint": "eslint .",
53
+ "lint:fix": "eslint . --fix",
54
+ "format": "prettier . --write",
55
+ "format:check": "prettier . --check",
56
+ "test:unit": "vitest run",
57
+ "prepublishOnly": "pnpm build"
58
+ },
59
+ "devDependencies": {
60
+ "@eslint/js": "^10.0.1",
61
+ "@types/node": "^22.10.0",
62
+ "eslint": "^10.5.0",
63
+ "eslint-config-prettier": "^10.1.8",
64
+ "prettier": "^3.8.4",
65
+ "tsup": "^8.5.1",
66
+ "typescript": "^5.9.3",
67
+ "typescript-eslint": "^8.61.1",
68
+ "vitest": "^4.1.9"
69
+ }
70
+ }