@waiaas/wallet-sdk 2.4.0-rc.3

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 ADDED
@@ -0,0 +1,215 @@
1
+ # @waiaas/wallet-sdk
2
+
3
+ SDK for external wallet apps to integrate with the WAIaaS Signing Protocol. Enables wallet applications (D'CENT, Phantom, MetaMask, etc.) to receive, display, and respond to transaction approval requests from WAIaaS daemon.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @waiaas/wallet-sdk
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import {
15
+ subscribeToRequests,
16
+ parseSignRequest,
17
+ buildSignResponse,
18
+ formatDisplayMessage,
19
+ sendViaNtfy,
20
+ } from '@waiaas/wallet-sdk';
21
+
22
+ // Subscribe to incoming sign requests via ntfy SSE
23
+ const sub = subscribeToRequests('my-topic', async (request) => {
24
+ // Display to user
25
+ console.log(formatDisplayMessage(request));
26
+
27
+ // Sign the transaction (your wallet's signing logic)
28
+ const signature = await myWallet.sign(request.message);
29
+
30
+ // Build and send response
31
+ const response = buildSignResponse(
32
+ request.requestId,
33
+ 'approve',
34
+ signature,
35
+ myWallet.address,
36
+ );
37
+
38
+ if (request.responseChannel.type === 'ntfy') {
39
+ await sendViaNtfy(
40
+ response,
41
+ request.responseChannel.responseTopic,
42
+ request.responseChannel.serverUrl,
43
+ );
44
+ }
45
+ });
46
+
47
+ // Stop listening
48
+ sub.unsubscribe();
49
+ ```
50
+
51
+ ## API Reference
52
+
53
+ ### Core Functions
54
+
55
+ #### `parseSignRequest(url: string): SignRequest | Promise<SignRequest>`
56
+
57
+ Extract a SignRequest from a universal link URL.
58
+
59
+ | Parameter | Type | Description |
60
+ |-----------|------|-------------|
61
+ | `url` | `string` | Universal link URL with query parameters |
62
+
63
+ **Supported URL modes:**
64
+
65
+ - **Inline:** `?data={base64url-encoded-SignRequest}` -- synchronous, returns `SignRequest`
66
+ - **Remote:** `?requestId={uuid}&topic={topic}&serverUrl={url}` -- asynchronous, fetches from ntfy
67
+
68
+ ```typescript
69
+ // Inline mode (sync)
70
+ const request = parseSignRequest('https://wallet.app/sign?data=eyJ...');
71
+
72
+ // Remote mode (async)
73
+ const request = await parseSignRequest(
74
+ 'https://wallet.app/sign?requestId=550e8400-...&topic=my-topic'
75
+ );
76
+ ```
77
+
78
+ **Throws:** `InvalidSignRequestUrlError`, `SignRequestExpiredError`, `SignRequestValidationError`
79
+
80
+ ---
81
+
82
+ #### `buildSignResponse(requestId, action, signature, signerAddress): SignResponse`
83
+
84
+ Create a validated SignResponse.
85
+
86
+ | Parameter | Type | Description |
87
+ |-----------|------|-------------|
88
+ | `requestId` | `string` | UUID from the original SignRequest |
89
+ | `action` | `'approve' \| 'reject'` | User's decision |
90
+ | `signature` | `string \| undefined` | Hex-encoded signature (required for `'approve'`) |
91
+ | `signerAddress` | `string` | Wallet address of the signer |
92
+
93
+ ```typescript
94
+ // Approve
95
+ const response = buildSignResponse(requestId, 'approve', '0xabcd...', address);
96
+
97
+ // Reject
98
+ const response = buildSignResponse(requestId, 'reject', undefined, address);
99
+ ```
100
+
101
+ ---
102
+
103
+ #### `formatDisplayMessage(request: SignRequest): string`
104
+
105
+ Create a human-readable transaction summary for display to the user.
106
+
107
+ ```typescript
108
+ const text = formatDisplayMessage(request);
109
+ // Transaction Approval Request
110
+ //
111
+ // Type: TOKEN_TRANSFER
112
+ // From: 0xAbcDef...
113
+ // To: 0x123456...
114
+ // Amount: 100 USDC
115
+ // Network: ethereum
116
+ // Policy: APPROVAL
117
+ // Expires: 2026-02-20T10:30:00.000Z
118
+ ```
119
+
120
+ ### Channel Functions
121
+
122
+ #### `sendViaNtfy(response, responseTopic, serverUrl?): Promise<void>`
123
+
124
+ Publish a SignResponse to an ntfy topic.
125
+
126
+ | Parameter | Type | Default | Description |
127
+ |-----------|------|---------|-------------|
128
+ | `response` | `SignResponse` | | Validated response |
129
+ | `responseTopic` | `string` | | ntfy topic for responses |
130
+ | `serverUrl` | `string` | `'https://ntfy.sh'` | ntfy server URL |
131
+
132
+ ---
133
+
134
+ #### `subscribeToRequests(topic, callback, serverUrl?): { unsubscribe: () => void }`
135
+
136
+ Subscribe to incoming sign requests via ntfy SSE stream.
137
+
138
+ | Parameter | Type | Default | Description |
139
+ |-----------|------|---------|-------------|
140
+ | `topic` | `string` | | ntfy topic for requests |
141
+ | `callback` | `(request: SignRequest) => void` | | Called for each valid request |
142
+ | `serverUrl` | `string` | `'https://ntfy.sh'` | ntfy server URL |
143
+
144
+ Auto-reconnects up to 3 times with 5-second delays. Expired requests are silently skipped.
145
+
146
+ ---
147
+
148
+ #### `sendViaTelegram(response, botUsername): string`
149
+
150
+ Generate a Telegram deeplink URL for sending a SignResponse.
151
+
152
+ | Parameter | Type | Description |
153
+ |-----------|------|-------------|
154
+ | `response` | `SignResponse` | Validated response |
155
+ | `botUsername` | `string` | Telegram bot username (without `@`) |
156
+
157
+ Returns a `https://t.me/{botUsername}?text=...` URL.
158
+
159
+ ### Error Classes
160
+
161
+ | Error | When Thrown |
162
+ |-------|------------|
163
+ | `InvalidSignRequestUrlError` | URL missing required parameters |
164
+ | `SignRequestExpiredError` | Request has expired (`expiresAt < now`) |
165
+ | `SignRequestValidationError` | Decoded data fails schema validation |
166
+
167
+ ### Types
168
+
169
+ All types are re-exported from `@waiaas/core`:
170
+
171
+ ```typescript
172
+ import type { SignRequest, SignResponse, WalletLinkConfig } from '@waiaas/wallet-sdk';
173
+ ```
174
+
175
+ ## Channels
176
+
177
+ WAIaaS supports two response channels:
178
+
179
+ ### ntfy (Direct Push)
180
+
181
+ No messenger required. Wallet app subscribes to an ntfy topic for requests and publishes responses to a separate topic.
182
+
183
+ ```
184
+ WAIaaS Daemon → ntfy server → Wallet App → ntfy server → WAIaaS Daemon
185
+ ```
186
+
187
+ ### Telegram (Messenger Relay)
188
+
189
+ Uses a Telegram bot as relay. Wallet app receives requests via Telegram and sends responses as deeplinks.
190
+
191
+ ```
192
+ WAIaaS Daemon → Telegram Bot → User → Wallet App → Telegram Bot → WAIaaS Daemon
193
+ ```
194
+
195
+ ## Universal Link Format
196
+
197
+ Wallet apps must handle URLs in this format:
198
+
199
+ ```
200
+ https://{wallet-host}/sign?data={base64url-encoded-SignRequest}
201
+ ```
202
+
203
+ Or remote fetch format:
204
+
205
+ ```
206
+ https://{wallet-host}/sign?requestId={uuid}&topic={topic}&serverUrl={ntfy-server}
207
+ ```
208
+
209
+ ## Integration Guide
210
+
211
+ For a complete integration walkthrough including architecture diagrams, security considerations, and testing guide, see the [Wallet SDK Integration Guide](https://github.com/minhoyooDEV/WAIaaS/blob/main/docs/wallet-sdk-integration.md).
212
+
213
+ ## License
214
+
215
+ [MIT](../../LICENSE)
@@ -0,0 +1,18 @@
1
+ /**
2
+ * buildSignResponse - Create a SignResponse object.
3
+ *
4
+ * @see internal/design/74-wallet-sdk-daemon-components.md Section 2.2
5
+ */
6
+ import type { SignResponse } from '@waiaas/core';
7
+ /**
8
+ * Build a validated SignResponse.
9
+ *
10
+ * @param requestId - UUID of the original SignRequest
11
+ * @param action - 'approve' or 'reject'
12
+ * @param signature - Hex-encoded signature (required for 'approve')
13
+ * @param signerAddress - Address of the signer
14
+ * @returns Validated SignResponse
15
+ * @throws Error if action is 'approve' but signature is missing
16
+ */
17
+ export declare function buildSignResponse(requestId: string, action: 'approve' | 'reject', signature: string | undefined, signerAddress: string): SignResponse;
18
+ //# sourceMappingURL=build-response.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-response.d.ts","sourceRoot":"","sources":["../src/build-response.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAGjD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,SAAS,GAAG,QAAQ,EAC5B,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,aAAa,EAAE,MAAM,GACpB,YAAY,CAed"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * buildSignResponse - Create a SignResponse object.
3
+ *
4
+ * @see internal/design/74-wallet-sdk-daemon-components.md Section 2.2
5
+ */
6
+ import { SignResponseSchema } from '@waiaas/core';
7
+ /**
8
+ * Build a validated SignResponse.
9
+ *
10
+ * @param requestId - UUID of the original SignRequest
11
+ * @param action - 'approve' or 'reject'
12
+ * @param signature - Hex-encoded signature (required for 'approve')
13
+ * @param signerAddress - Address of the signer
14
+ * @returns Validated SignResponse
15
+ * @throws Error if action is 'approve' but signature is missing
16
+ */
17
+ export function buildSignResponse(requestId, action, signature, signerAddress) {
18
+ if (action === 'approve' && !signature) {
19
+ throw new Error('signature required for approve action');
20
+ }
21
+ const response = {
22
+ version: '1',
23
+ requestId,
24
+ action,
25
+ ...(signature !== undefined ? { signature } : {}),
26
+ signerAddress,
27
+ signedAt: new Date().toISOString(),
28
+ };
29
+ return SignResponseSchema.parse(response);
30
+ }
31
+ //# sourceMappingURL=build-response.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-response.js","sourceRoot":"","sources":["../src/build-response.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAElD;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAC/B,SAAiB,EACjB,MAA4B,EAC5B,SAA6B,EAC7B,aAAqB;IAErB,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,SAAS,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IAED,MAAM,QAAQ,GAAG;QACf,OAAO,EAAE,GAAY;QACrB,SAAS;QACT,MAAM;QACN,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,aAAa;QACb,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACnC,CAAC;IAEF,OAAO,kBAAkB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Channel exports for @waiaas/wallet-sdk.
3
+ */
4
+ export { sendViaNtfy, subscribeToRequests } from './ntfy.js';
5
+ export { sendViaTelegram } from './telegram.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/channels/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Channel exports for @waiaas/wallet-sdk.
3
+ */
4
+ export { sendViaNtfy, subscribeToRequests } from './ntfy.js';
5
+ export { sendViaTelegram } from './telegram.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/channels/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * ntfy channel functions for the WAIaaS Signing Protocol.
3
+ *
4
+ * sendViaNtfy - Publish a SignResponse to an ntfy response topic.
5
+ * subscribeToRequests - SSE subscription for incoming sign requests.
6
+ *
7
+ * @see internal/design/73-signing-protocol-v1.md Section 7.4
8
+ * @see internal/design/74-wallet-sdk-daemon-components.md Section 2.6
9
+ */
10
+ import type { SignRequest, SignResponse } from '@waiaas/core';
11
+ /**
12
+ * Publish a SignResponse to an ntfy response topic.
13
+ *
14
+ * Encodes the response as base64url and POSTs it to the ntfy server.
15
+ *
16
+ * @param response - Validated SignResponse object
17
+ * @param responseTopic - ntfy topic name for responses
18
+ * @param serverUrl - ntfy server URL (defaults to https://ntfy.sh)
19
+ */
20
+ export declare function sendViaNtfy(response: SignResponse, responseTopic: string, serverUrl?: string): Promise<void>;
21
+ /**
22
+ * Subscribe to sign requests via ntfy SSE stream.
23
+ *
24
+ * Listens for new messages on the specified ntfy topic and parses them
25
+ * as SignRequest objects. Valid, non-expired requests trigger the callback.
26
+ *
27
+ * @param topic - ntfy topic name for incoming sign requests
28
+ * @param callback - Function called for each valid SignRequest received
29
+ * @param serverUrl - ntfy server URL (defaults to https://ntfy.sh)
30
+ * @returns Object with unsubscribe() method to close the SSE connection
31
+ */
32
+ export declare function subscribeToRequests(topic: string, callback: (request: SignRequest) => void, serverUrl?: string): {
33
+ unsubscribe: () => void;
34
+ };
35
+ //# sourceMappingURL=ntfy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ntfy.d.ts","sourceRoot":"","sources":["../../src/channels/ntfy.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAO9D;;;;;;;;GAQG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,YAAY,EACtB,aAAa,EAAE,MAAM,EACrB,SAAS,GAAE,MAA2B,GACrC,OAAO,CAAC,IAAI,CAAC,CAef;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,EACxC,SAAS,GAAE,MAA2B,GACrC;IAAE,WAAW,EAAE,MAAM,IAAI,CAAA;CAAE,CAkF7B"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * ntfy channel functions for the WAIaaS Signing Protocol.
3
+ *
4
+ * sendViaNtfy - Publish a SignResponse to an ntfy response topic.
5
+ * subscribeToRequests - SSE subscription for incoming sign requests.
6
+ *
7
+ * @see internal/design/73-signing-protocol-v1.md Section 7.4
8
+ * @see internal/design/74-wallet-sdk-daemon-components.md Section 2.6
9
+ */
10
+ import { SignRequestSchema } from '@waiaas/core';
11
+ const DEFAULT_SERVER_URL = 'https://ntfy.sh';
12
+ const MAX_RECONNECT_ATTEMPTS = 3;
13
+ const RECONNECT_DELAY_MS = 5_000;
14
+ /**
15
+ * Publish a SignResponse to an ntfy response topic.
16
+ *
17
+ * Encodes the response as base64url and POSTs it to the ntfy server.
18
+ *
19
+ * @param response - Validated SignResponse object
20
+ * @param responseTopic - ntfy topic name for responses
21
+ * @param serverUrl - ntfy server URL (defaults to https://ntfy.sh)
22
+ */
23
+ export async function sendViaNtfy(response, responseTopic, serverUrl = DEFAULT_SERVER_URL) {
24
+ const json = JSON.stringify(response);
25
+ const encoded = Buffer.from(json, 'utf-8').toString('base64url');
26
+ const url = `${serverUrl}/${responseTopic}`;
27
+ const res = await fetch(url, {
28
+ method: 'POST',
29
+ body: encoded,
30
+ });
31
+ if (!res.ok) {
32
+ throw new Error(`Failed to send response to ntfy: HTTP ${String(res.status)}`);
33
+ }
34
+ }
35
+ /**
36
+ * Subscribe to sign requests via ntfy SSE stream.
37
+ *
38
+ * Listens for new messages on the specified ntfy topic and parses them
39
+ * as SignRequest objects. Valid, non-expired requests trigger the callback.
40
+ *
41
+ * @param topic - ntfy topic name for incoming sign requests
42
+ * @param callback - Function called for each valid SignRequest received
43
+ * @param serverUrl - ntfy server URL (defaults to https://ntfy.sh)
44
+ * @returns Object with unsubscribe() method to close the SSE connection
45
+ */
46
+ export function subscribeToRequests(topic, callback, serverUrl = DEFAULT_SERVER_URL) {
47
+ const abortController = new AbortController();
48
+ let reconnectAttempts = 0;
49
+ async function connect() {
50
+ if (abortController.signal.aborted)
51
+ return;
52
+ try {
53
+ const url = `${serverUrl}/${topic}/sse`;
54
+ const res = await fetch(url, {
55
+ signal: abortController.signal,
56
+ });
57
+ if (!res.ok || !res.body) {
58
+ throw new Error(`SSE connection failed: HTTP ${String(res.status)}`);
59
+ }
60
+ // Reset reconnect counter on successful connection
61
+ reconnectAttempts = 0;
62
+ const reader = res.body.getReader();
63
+ const decoder = new TextDecoder();
64
+ let buffer = '';
65
+ while (!abortController.signal.aborted) {
66
+ const { done, value } = await reader.read();
67
+ if (done)
68
+ break;
69
+ buffer += decoder.decode(value, { stream: true });
70
+ const lines = buffer.split('\n');
71
+ // Keep the last incomplete line in buffer
72
+ buffer = lines.pop() ?? '';
73
+ for (const line of lines) {
74
+ if (!line.startsWith('data: '))
75
+ continue;
76
+ const dataStr = line.slice(6).trim();
77
+ if (!dataStr)
78
+ continue;
79
+ try {
80
+ const event = JSON.parse(dataStr);
81
+ if (!event.message)
82
+ continue;
83
+ const json = Buffer.from(event.message, 'base64url').toString('utf-8');
84
+ const parsed = JSON.parse(json);
85
+ const request = SignRequestSchema.parse(parsed);
86
+ // Skip expired requests
87
+ const expiresAt = new Date(request.expiresAt).getTime();
88
+ if (expiresAt < Date.now()) {
89
+ continue;
90
+ }
91
+ callback(request);
92
+ }
93
+ catch {
94
+ // Ignore malformed messages
95
+ }
96
+ }
97
+ }
98
+ }
99
+ catch (_err) {
100
+ // Don't reconnect if explicitly aborted
101
+ if (abortController.signal.aborted)
102
+ return;
103
+ reconnectAttempts++;
104
+ if (reconnectAttempts <= MAX_RECONNECT_ATTEMPTS) {
105
+ await new Promise((resolve) => setTimeout(resolve, RECONNECT_DELAY_MS));
106
+ void connect();
107
+ }
108
+ }
109
+ }
110
+ void connect();
111
+ return {
112
+ unsubscribe() {
113
+ abortController.abort();
114
+ },
115
+ };
116
+ }
117
+ //# sourceMappingURL=ntfy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ntfy.js","sourceRoot":"","sources":["../../src/channels/ntfy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Telegram channel function for the WAIaaS Signing Protocol.
3
+ *
4
+ * Generates a Telegram deeplink URL for sending a SignResponse to a bot.
5
+ * The actual Telegram app opening is the wallet app's responsibility.
6
+ *
7
+ * @see internal/design/73-signing-protocol-v1.md Section 8.5
8
+ */
9
+ import type { SignResponse } from '@waiaas/core';
10
+ /**
11
+ * Generate a Telegram deeplink URL for sending a SignResponse to a bot.
12
+ *
13
+ * Creates a https://t.me/{botUsername}?text={encoded} URL.
14
+ * Platform-specific scheme handling (tg:// vs https://t.me) is left to the wallet app.
15
+ *
16
+ * @param response - Validated SignResponse object
17
+ * @param botUsername - Telegram bot username (without @)
18
+ * @returns Telegram deeplink URL string
19
+ */
20
+ export declare function sendViaTelegram(response: SignResponse, botUsername: string): string;
21
+ //# sourceMappingURL=telegram.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telegram.d.ts","sourceRoot":"","sources":["../../src/channels/telegram.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,YAAY,EACtB,WAAW,EAAE,MAAM,GAClB,MAAM,CAKR"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Telegram channel function for the WAIaaS Signing Protocol.
3
+ *
4
+ * Generates a Telegram deeplink URL for sending a SignResponse to a bot.
5
+ * The actual Telegram app opening is the wallet app's responsibility.
6
+ *
7
+ * @see internal/design/73-signing-protocol-v1.md Section 8.5
8
+ */
9
+ /**
10
+ * Generate a Telegram deeplink URL for sending a SignResponse to a bot.
11
+ *
12
+ * Creates a https://t.me/{botUsername}?text={encoded} URL.
13
+ * Platform-specific scheme handling (tg:// vs https://t.me) is left to the wallet app.
14
+ *
15
+ * @param response - Validated SignResponse object
16
+ * @param botUsername - Telegram bot username (without @)
17
+ * @returns Telegram deeplink URL string
18
+ */
19
+ export function sendViaTelegram(response, botUsername) {
20
+ const json = JSON.stringify(response);
21
+ const encoded = Buffer.from(json, 'utf-8').toString('base64url');
22
+ const text = `/sign_response ${encoded}`;
23
+ return `https://t.me/${botUsername}?text=${encodeURIComponent(text)}`;
24
+ }
25
+ //# sourceMappingURL=telegram.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telegram.js","sourceRoot":"","sources":["../../src/channels/telegram.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAC7B,QAAsB,EACtB,WAAmB;IAEnB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IACjE,MAAM,IAAI,GAAG,kBAAkB,OAAO,EAAE,CAAC;IACzC,OAAO,gBAAgB,WAAW,SAAS,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;AACxE,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * formatDisplayMessage - Create a human-readable transaction summary.
3
+ *
4
+ * @see internal/design/74-wallet-sdk-daemon-components.md Section 2.4
5
+ */
6
+ import type { SignRequest } from '@waiaas/core';
7
+ /**
8
+ * Format a SignRequest into a human-readable display message.
9
+ *
10
+ * @param request - Validated SignRequest
11
+ * @returns Multi-line string summary of the transaction
12
+ */
13
+ export declare function formatDisplayMessage(request: SignRequest): string;
14
+ //# sourceMappingURL=display.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display.d.ts","sourceRoot":"","sources":["../src/display.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAkBjE"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * formatDisplayMessage - Create a human-readable transaction summary.
3
+ *
4
+ * @see internal/design/74-wallet-sdk-daemon-components.md Section 2.4
5
+ */
6
+ /**
7
+ * Format a SignRequest into a human-readable display message.
8
+ *
9
+ * @param request - Validated SignRequest
10
+ * @returns Multi-line string summary of the transaction
11
+ */
12
+ export function formatDisplayMessage(request) {
13
+ const lines = [
14
+ 'Transaction Approval Request',
15
+ '',
16
+ `Type: ${request.metadata.type}`,
17
+ `From: ${request.metadata.from}`,
18
+ `To: ${request.metadata.to}`,
19
+ ];
20
+ if (request.metadata.amount && request.metadata.symbol) {
21
+ lines.push(`Amount: ${request.metadata.amount} ${request.metadata.symbol}`);
22
+ }
23
+ lines.push(`Network: ${request.network}`);
24
+ lines.push(`Policy: ${request.metadata.policyTier}`);
25
+ lines.push(`Expires: ${request.expiresAt}`);
26
+ return lines.join('\n');
27
+ }
28
+ //# sourceMappingURL=display.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display.js","sourceRoot":"","sources":["../src/display.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAoB;IACvD,MAAM,KAAK,GAAa;QACtB,8BAA8B;QAC9B,EAAE;QACF,SAAS,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE;QAChC,SAAS,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE;QAChC,OAAO,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE;KAC7B,CAAC;IAEF,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QACvD,KAAK,CAAC,IAAI,CAAC,WAAW,OAAO,CAAC,QAAQ,CAAC,MAAM,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,YAAY,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAC1C,KAAK,CAAC,IAAI,CAAC,WAAW,OAAO,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IACrD,KAAK,CAAC,IAAI,CAAC,YAAY,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAE5C,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Custom error classes for @waiaas/wallet-sdk.
3
+ *
4
+ * These errors are thrown by SDK functions to indicate specific failure modes
5
+ * when parsing, validating, or processing signing protocol data.
6
+ */
7
+ /**
8
+ * Thrown when the URL passed to parseSignRequest is invalid or missing
9
+ * required parameters (neither 'data' nor 'requestId' found).
10
+ */
11
+ export declare class InvalidSignRequestUrlError extends Error {
12
+ readonly name = "InvalidSignRequestUrlError";
13
+ constructor(message: string);
14
+ }
15
+ /**
16
+ * Thrown when a SignRequest has expired (expiresAt < now).
17
+ */
18
+ export declare class SignRequestExpiredError extends Error {
19
+ readonly name = "SignRequestExpiredError";
20
+ readonly expiresAt: string;
21
+ constructor(expiresAt: string);
22
+ }
23
+ /**
24
+ * Thrown when the decoded data fails Zod schema validation.
25
+ */
26
+ export declare class SignRequestValidationError extends Error {
27
+ readonly name = "SignRequestValidationError";
28
+ constructor(zodMessage: string);
29
+ }
30
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH,qBAAa,0BAA2B,SAAQ,KAAK;IACnD,SAAkB,IAAI,gCAAgC;gBAE1C,OAAO,EAAE,MAAM;CAG5B;AAED;;GAEG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,SAAkB,IAAI,6BAA6B;IACnD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAEf,SAAS,EAAE,MAAM;CAI9B;AAED;;GAEG;AACH,qBAAa,0BAA2B,SAAQ,KAAK;IACnD,SAAkB,IAAI,gCAAgC;gBAE1C,UAAU,EAAE,MAAM;CAG/B"}
package/dist/errors.js ADDED
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Custom error classes for @waiaas/wallet-sdk.
3
+ *
4
+ * These errors are thrown by SDK functions to indicate specific failure modes
5
+ * when parsing, validating, or processing signing protocol data.
6
+ */
7
+ /**
8
+ * Thrown when the URL passed to parseSignRequest is invalid or missing
9
+ * required parameters (neither 'data' nor 'requestId' found).
10
+ */
11
+ export class InvalidSignRequestUrlError extends Error {
12
+ name = 'InvalidSignRequestUrlError';
13
+ constructor(message) {
14
+ super(message);
15
+ }
16
+ }
17
+ /**
18
+ * Thrown when a SignRequest has expired (expiresAt < now).
19
+ */
20
+ export class SignRequestExpiredError extends Error {
21
+ name = 'SignRequestExpiredError';
22
+ expiresAt;
23
+ constructor(expiresAt) {
24
+ super(`Sign request expired at ${expiresAt}`);
25
+ this.expiresAt = expiresAt;
26
+ }
27
+ }
28
+ /**
29
+ * Thrown when the decoded data fails Zod schema validation.
30
+ */
31
+ export class SignRequestValidationError extends Error {
32
+ name = 'SignRequestValidationError';
33
+ constructor(zodMessage) {
34
+ super(`Sign request validation failed: ${zodMessage}`);
35
+ }
36
+ }
37
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH,MAAM,OAAO,0BAA2B,SAAQ,KAAK;IACjC,IAAI,GAAG,4BAA4B,CAAC;IAEtD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;IACjB,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IAC9B,IAAI,GAAG,yBAAyB,CAAC;IAC1C,SAAS,CAAS;IAE3B,YAAY,SAAiB;QAC3B,KAAK,CAAC,2BAA2B,SAAS,EAAE,CAAC,CAAC;QAC9C,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,0BAA2B,SAAQ,KAAK;IACjC,IAAI,GAAG,4BAA4B,CAAC;IAEtD,YAAY,UAAkB;QAC5B,KAAK,CAAC,mCAAmC,UAAU,EAAE,CAAC,CAAC;IACzD,CAAC;CACF"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @waiaas/wallet-sdk - WAIaaS Wallet Signing SDK
3
+ *
4
+ * Provides wallet apps with tools to integrate the WAIaaS Signing Protocol v1.
5
+ *
6
+ * Public API:
7
+ * - parseSignRequest(url) - Extract SignRequest from universal link URL
8
+ * - buildSignResponse(requestId, action, signature?, signerAddress) - Create SignResponse
9
+ * - formatDisplayMessage(request) - Human-readable transaction summary
10
+ * - sendViaNtfy(response, topic, serverUrl?) - Publish to ntfy response topic
11
+ * - sendViaTelegram(response, botUsername) - Generate Telegram deeplink URL
12
+ * - subscribeToRequests(topic, callback, serverUrl?) - SSE subscription for sign requests
13
+ *
14
+ * @see internal/design/73-signing-protocol-v1.md
15
+ * @see internal/design/74-wallet-sdk-daemon-components.md
16
+ */
17
+ export { parseSignRequest } from './parse-request.js';
18
+ export { buildSignResponse } from './build-response.js';
19
+ export { formatDisplayMessage } from './display.js';
20
+ export { sendViaNtfy, subscribeToRequests, sendViaTelegram, } from './channels/index.js';
21
+ export { InvalidSignRequestUrlError, SignRequestExpiredError, SignRequestValidationError, } from './errors.js';
22
+ export type { SignRequest, SignResponse, WalletLinkConfig, } from '@waiaas/core';
23
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAGpD,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,0BAA0B,EAC1B,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,aAAa,CAAC;AAGrB,YAAY,EACV,WAAW,EACX,YAAY,EACZ,gBAAgB,GACjB,MAAM,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @waiaas/wallet-sdk - WAIaaS Wallet Signing SDK
3
+ *
4
+ * Provides wallet apps with tools to integrate the WAIaaS Signing Protocol v1.
5
+ *
6
+ * Public API:
7
+ * - parseSignRequest(url) - Extract SignRequest from universal link URL
8
+ * - buildSignResponse(requestId, action, signature?, signerAddress) - Create SignResponse
9
+ * - formatDisplayMessage(request) - Human-readable transaction summary
10
+ * - sendViaNtfy(response, topic, serverUrl?) - Publish to ntfy response topic
11
+ * - sendViaTelegram(response, botUsername) - Generate Telegram deeplink URL
12
+ * - subscribeToRequests(topic, callback, serverUrl?) - SSE subscription for sign requests
13
+ *
14
+ * @see internal/design/73-signing-protocol-v1.md
15
+ * @see internal/design/74-wallet-sdk-daemon-components.md
16
+ */
17
+ // Core functions
18
+ export { parseSignRequest } from './parse-request.js';
19
+ export { buildSignResponse } from './build-response.js';
20
+ export { formatDisplayMessage } from './display.js';
21
+ // Channel functions
22
+ export { sendViaNtfy, subscribeToRequests, sendViaTelegram, } from './channels/index.js';
23
+ // Error classes
24
+ export { InvalidSignRequestUrlError, SignRequestExpiredError, SignRequestValidationError, } from './errors.js';
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,iBAAiB;AACjB,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEpD,oBAAoB;AACpB,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAE7B,gBAAgB;AAChB,OAAO,EACL,0BAA0B,EAC1B,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,aAAa,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * parseSignRequest - Extract SignRequest from a universal link URL.
3
+ *
4
+ * Supports two modes:
5
+ * 1. Inline data: URL contains ?data={base64url-encoded-SignRequest}
6
+ * 2. Remote fetch: URL contains ?requestId={uuid}&topic={topic}&serverUrl={url}
7
+ * (fetches from ntfy topic)
8
+ *
9
+ * @see internal/design/74-wallet-sdk-daemon-components.md Section 2.1
10
+ */
11
+ import type { SignRequest } from '@waiaas/core';
12
+ /**
13
+ * Parse a SignRequest from a universal link URL.
14
+ *
15
+ * @param url - Universal link URL with ?data= or ?requestId= parameters
16
+ * @returns SignRequest (sync for inline data, async for ntfy fetch)
17
+ * @throws InvalidSignRequestUrlError - URL is invalid or missing parameters
18
+ * @throws SignRequestExpiredError - Request has expired
19
+ * @throws SignRequestValidationError - Decoded data fails Zod validation
20
+ */
21
+ export declare function parseSignRequest(url: string): SignRequest | Promise<SignRequest>;
22
+ //# sourceMappingURL=parse-request.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-request.d.ts","sourceRoot":"","sources":["../src/parse-request.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAoHhD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,GACV,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAyBpC"}
@@ -0,0 +1,135 @@
1
+ /**
2
+ * parseSignRequest - Extract SignRequest from a universal link URL.
3
+ *
4
+ * Supports two modes:
5
+ * 1. Inline data: URL contains ?data={base64url-encoded-SignRequest}
6
+ * 2. Remote fetch: URL contains ?requestId={uuid}&topic={topic}&serverUrl={url}
7
+ * (fetches from ntfy topic)
8
+ *
9
+ * @see internal/design/74-wallet-sdk-daemon-components.md Section 2.1
10
+ */
11
+ import { SignRequestSchema } from '@waiaas/core';
12
+ import { ZodError } from 'zod';
13
+ import { InvalidSignRequestUrlError, SignRequestExpiredError, SignRequestValidationError, } from './errors.js';
14
+ /**
15
+ * Check if a SignRequest has expired.
16
+ */
17
+ function assertNotExpired(request) {
18
+ const expiresAt = new Date(request.expiresAt).getTime();
19
+ if (expiresAt < Date.now()) {
20
+ throw new SignRequestExpiredError(request.expiresAt);
21
+ }
22
+ }
23
+ /**
24
+ * Decode inline data parameter (base64url -> JSON -> Zod validated SignRequest).
25
+ */
26
+ function decodeInlineData(data) {
27
+ let json;
28
+ try {
29
+ json = Buffer.from(data, 'base64url').toString('utf-8');
30
+ }
31
+ catch {
32
+ throw new InvalidSignRequestUrlError('Invalid base64url data parameter');
33
+ }
34
+ let parsed;
35
+ try {
36
+ parsed = JSON.parse(json);
37
+ }
38
+ catch {
39
+ throw new InvalidSignRequestUrlError('Invalid JSON in data parameter');
40
+ }
41
+ let request;
42
+ try {
43
+ request = SignRequestSchema.parse(parsed);
44
+ }
45
+ catch (err) {
46
+ if (err instanceof ZodError) {
47
+ throw new SignRequestValidationError(err.message);
48
+ }
49
+ throw err;
50
+ }
51
+ assertNotExpired(request);
52
+ return request;
53
+ }
54
+ /**
55
+ * Fetch a SignRequest from an ntfy topic by requestId.
56
+ */
57
+ async function fetchSignRequestFromNtfy(requestId, topic, serverUrl) {
58
+ const url = `${serverUrl}/${topic}/json?poll=1&since=all`;
59
+ const res = await fetch(url);
60
+ if (!res.ok) {
61
+ throw new InvalidSignRequestUrlError(`Failed to fetch from ntfy: HTTP ${String(res.status)}`);
62
+ }
63
+ const text = await res.text();
64
+ // ntfy returns newline-delimited JSON messages
65
+ const lines = text.trim().split('\n');
66
+ for (const line of lines) {
67
+ if (!line.trim())
68
+ continue;
69
+ let msg;
70
+ try {
71
+ msg = JSON.parse(line);
72
+ }
73
+ catch {
74
+ continue;
75
+ }
76
+ if (!msg.message)
77
+ continue;
78
+ let json;
79
+ try {
80
+ json = Buffer.from(msg.message, 'base64url').toString('utf-8');
81
+ }
82
+ catch {
83
+ continue;
84
+ }
85
+ let parsed;
86
+ try {
87
+ parsed = JSON.parse(json);
88
+ }
89
+ catch {
90
+ continue;
91
+ }
92
+ let request;
93
+ try {
94
+ request = SignRequestSchema.parse(parsed);
95
+ }
96
+ catch {
97
+ continue;
98
+ }
99
+ if (request.requestId === requestId) {
100
+ assertNotExpired(request);
101
+ return request;
102
+ }
103
+ }
104
+ throw new InvalidSignRequestUrlError(`Sign request ${requestId} not found in ntfy topic ${topic}`);
105
+ }
106
+ /**
107
+ * Parse a SignRequest from a universal link URL.
108
+ *
109
+ * @param url - Universal link URL with ?data= or ?requestId= parameters
110
+ * @returns SignRequest (sync for inline data, async for ntfy fetch)
111
+ * @throws InvalidSignRequestUrlError - URL is invalid or missing parameters
112
+ * @throws SignRequestExpiredError - Request has expired
113
+ * @throws SignRequestValidationError - Decoded data fails Zod validation
114
+ */
115
+ export function parseSignRequest(url) {
116
+ let parsed;
117
+ try {
118
+ parsed = new URL(url);
119
+ }
120
+ catch {
121
+ throw new InvalidSignRequestUrlError(`Invalid URL: ${url}`);
122
+ }
123
+ const data = parsed.searchParams.get('data');
124
+ if (data) {
125
+ return decodeInlineData(data);
126
+ }
127
+ const requestId = parsed.searchParams.get('requestId');
128
+ if (requestId) {
129
+ const topic = parsed.searchParams.get('topic') ?? 'waiaas-sign-requests';
130
+ const serverUrl = parsed.searchParams.get('serverUrl') ?? 'https://ntfy.sh';
131
+ return fetchSignRequestFromNtfy(requestId, topic, serverUrl);
132
+ }
133
+ throw new InvalidSignRequestUrlError('URL must contain either "data" or "requestId" parameter');
134
+ }
135
+ //# sourceMappingURL=parse-request.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-request.js","sourceRoot":"","sources":["../src/parse-request.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@waiaas/wallet-sdk",
3
+ "version": "2.4.0-rc.3",
4
+ "description": "WAIaaS Wallet Signing SDK - integrate wallet apps with WAIaaS signing protocol",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/minhoyoo-iotrust/WAIaaS.git",
10
+ "directory": "packages/wallet-sdk"
11
+ },
12
+ "homepage": "https://github.com/minhoyoo-iotrust/WAIaaS#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/minhoyoo-iotrust/WAIaaS/issues"
15
+ },
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
19
+ "main": "dist/index.js",
20
+ "types": "dist/index.d.ts",
21
+ "exports": {
22
+ ".": {
23
+ "import": "./dist/index.js",
24
+ "types": "./dist/index.d.ts"
25
+ }
26
+ },
27
+ "files": [
28
+ "dist",
29
+ "README.md"
30
+ ],
31
+ "scripts": {
32
+ "build": "tsc -p tsconfig.build.json",
33
+ "test": "vitest run",
34
+ "test:unit": "vitest run",
35
+ "lint": "eslint src/",
36
+ "typecheck": "tsc --noEmit",
37
+ "clean": "rm -rf dist"
38
+ },
39
+ "engines": {
40
+ "node": ">=18.0.0"
41
+ },
42
+ "dependencies": {
43
+ "@waiaas/core": "workspace:*",
44
+ "zod": "^3.24.0"
45
+ },
46
+ "devDependencies": {
47
+ "@types/node": "^25.2.3",
48
+ "vitest": "^3.0.0"
49
+ }
50
+ }