@icp-sdk/signer 5.2.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.
Files changed (45) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +165 -0
  3. package/lib/esm/agent/agent.d.ts +112 -0
  4. package/lib/esm/agent/agent.js +288 -0
  5. package/lib/esm/agent/agent.js.map +1 -0
  6. package/lib/esm/agent/index.d.ts +1 -0
  7. package/lib/esm/agent/index.js +2 -0
  8. package/lib/esm/agent/index.js.map +1 -0
  9. package/lib/esm/extension/browserExtensionChannel.d.ts +37 -0
  10. package/lib/esm/extension/browserExtensionChannel.js +80 -0
  11. package/lib/esm/extension/browserExtensionChannel.js.map +1 -0
  12. package/lib/esm/extension/browserExtensionTransport.d.ts +67 -0
  13. package/lib/esm/extension/browserExtensionTransport.js +70 -0
  14. package/lib/esm/extension/browserExtensionTransport.js.map +1 -0
  15. package/lib/esm/extension/index.d.ts +3 -0
  16. package/lib/esm/extension/index.js +3 -0
  17. package/lib/esm/extension/index.js.map +1 -0
  18. package/lib/esm/extension/types.d.ts +32 -0
  19. package/lib/esm/extension/types.js +2 -0
  20. package/lib/esm/extension/types.js.map +1 -0
  21. package/lib/esm/index.d.ts +2 -0
  22. package/lib/esm/index.js +2 -0
  23. package/lib/esm/index.js.map +1 -0
  24. package/lib/esm/signer.d.ts +180 -0
  25. package/lib/esm/signer.js +427 -0
  26. package/lib/esm/signer.js.map +1 -0
  27. package/lib/esm/transport.d.ts +32 -0
  28. package/lib/esm/transport.js +11 -0
  29. package/lib/esm/transport.js.map +1 -0
  30. package/lib/esm/web/heartbeat/client.d.ts +60 -0
  31. package/lib/esm/web/heartbeat/client.js +112 -0
  32. package/lib/esm/web/heartbeat/client.js.map +1 -0
  33. package/lib/esm/web/heartbeat/server.d.ts +43 -0
  34. package/lib/esm/web/heartbeat/server.js +82 -0
  35. package/lib/esm/web/heartbeat/server.js.map +1 -0
  36. package/lib/esm/web/index.d.ts +4 -0
  37. package/lib/esm/web/index.js +5 -0
  38. package/lib/esm/web/index.js.map +1 -0
  39. package/lib/esm/web/postMessageChannel.d.ts +55 -0
  40. package/lib/esm/web/postMessageChannel.js +109 -0
  41. package/lib/esm/web/postMessageChannel.js.map +1 -0
  42. package/lib/esm/web/postMessageTransport.d.ts +96 -0
  43. package/lib/esm/web/postMessageTransport.js +113 -0
  44. package/lib/esm/web/postMessageTransport.js.map +1 -0
  45. package/package.json +122 -0
@@ -0,0 +1,288 @@
1
+ import { Cbor, Certificate, Expiry, HttpAgent, IC_ROOT_KEY, JSON_KEY_EXPIRY, LookupPathStatus, requestIdOf, SubmitRequestType, } from '@icp-sdk/core/agent';
2
+ import { uint8Equals } from '@icp-sdk/core/candid';
3
+ import { Principal } from '@icp-sdk/core/principal';
4
+ // Hex helpers — use native Uint8Array methods when available
5
+ const fromHex = (hex) => {
6
+ if ('fromHex' in Uint8Array && typeof Uint8Array.fromHex === 'function') {
7
+ return Uint8Array.fromHex(hex);
8
+ }
9
+ const bytes = new Uint8Array(hex.length / 2);
10
+ for (let i = 0; i < bytes.length; i++) {
11
+ bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
12
+ }
13
+ return bytes;
14
+ };
15
+ const toHex = (bytes) => {
16
+ if ('toHex' in bytes && typeof bytes.toHex === 'function') {
17
+ return bytes.toHex();
18
+ }
19
+ let hex = '';
20
+ for (let i = 0; i < bytes.byteLength; i++) {
21
+ hex += bytes[i].toString(16).padStart(2, '0');
22
+ }
23
+ return hex;
24
+ };
25
+ // IC root key as bytes, used as fallback when agent has no root key
26
+ const ROOT_KEY = fromHex(IC_ROOT_KEY);
27
+ const MAX_AGE_IN_MINUTES = 5;
28
+ const INVALID_RESPONSE_MESSAGE = 'Received invalid response from signer';
29
+ /**
30
+ * Error thrown by {@link SignerAgent} when a signer returns an invalid
31
+ * response or certificate validation fails.
32
+ */
33
+ export class SignerAgentError extends Error {
34
+ }
35
+ /**
36
+ * An {@link Agent} implementation that routes canister calls through a
37
+ * {@link Signer} for user approval. Drop-in replacement for {@link HttpAgent}
38
+ * when canister calls need to be signed by an external signer.
39
+ *
40
+ * Calls are sent to the signer via ICRC-49, and the returned content map
41
+ * and certificate are validated before being returned to the caller.
42
+ *
43
+ * Use {@link SignerAgent.create} or {@link SignerAgent.createSync} to
44
+ * construct an instance — the constructor is private.
45
+ * @example
46
+ * ```ts
47
+ * const agent = await SignerAgent.create({ signer, account });
48
+ * const result = await agent.update(canisterId, { methodName: "transfer", arg, effectiveCanisterId: canisterId });
49
+ * ```
50
+ */
51
+ export class SignerAgent {
52
+ static #isInternalConstructing = false;
53
+ #options;
54
+ #certificates = new Map();
55
+ #pending = Promise.resolve();
56
+ constructor(options) {
57
+ const throwError = !SignerAgent.#isInternalConstructing;
58
+ SignerAgent.#isInternalConstructing = false;
59
+ if (throwError) {
60
+ throw new SignerAgentError('SignerAgent is not constructable');
61
+ }
62
+ this.#options = options;
63
+ }
64
+ /** The root key used for certificate verification. */
65
+ get rootKey() {
66
+ return this.#options.agent.rootKey ?? ROOT_KEY;
67
+ }
68
+ /** The signer this agent routes calls through. */
69
+ get signer() {
70
+ return this.#options.signer;
71
+ }
72
+ /**
73
+ * Creates a new SignerAgent, asynchronously initializing the
74
+ * underlying HttpAgent if one is not provided.
75
+ * @param options - The signer agent options.
76
+ */
77
+ static async create(options) {
78
+ SignerAgent.#isInternalConstructing = true;
79
+ return new SignerAgent({
80
+ ...options,
81
+ agent: options.agent ?? (await HttpAgent.create()),
82
+ });
83
+ }
84
+ /**
85
+ * Creates a new SignerAgent synchronously.
86
+ * Use this when you already have an HttpAgent or don't need async initialization.
87
+ * @param options - The signer agent options.
88
+ */
89
+ static createSync(options) {
90
+ SignerAgent.#isInternalConstructing = true;
91
+ return new SignerAgent({
92
+ ...options,
93
+ agent: options.agent ?? HttpAgent.createSync(),
94
+ });
95
+ }
96
+ /**
97
+ * Sends a canister call through the signer, validates the content map
98
+ * and certificate, and returns the verified result.
99
+ *
100
+ * Calls are queued to ensure sequential execution — the signer's
101
+ * transport channel is opened first to avoid blocking popups.
102
+ * @param canisterId - The target canister principal.
103
+ * @param fields - The call options including method name and arguments.
104
+ */
105
+ async #sendAndVerify(canisterId, fields) {
106
+ await this.#options.signer.openChannel();
107
+ // Queue calls to ensure sequential execution through the signer
108
+ const response = await new Promise((resolve, reject) => {
109
+ this.#pending = this.#pending.finally(() => this.signer
110
+ .callCanister({
111
+ canisterId,
112
+ sender: this.#options.account,
113
+ method: fields.methodName,
114
+ arg: fields.arg,
115
+ nonce: fields.nonce,
116
+ })
117
+ .then(resolve, reject));
118
+ });
119
+ // Decode CBOR content map and reconstruct the Expiry
120
+ // (Expiry has a private constructor, so we use the JSON round-trip)
121
+ const decoded = Cbor.decode(response.contentMap);
122
+ const requestBody = {
123
+ ...decoded,
124
+ canister_id: Principal.from(decoded.canister_id),
125
+ ingress_expiry: Expiry.fromJSON(JSON.stringify({ [JSON_KEY_EXPIRY]: String(decoded.ingress_expiry) })),
126
+ };
127
+ // Verify the content map matches what we requested
128
+ const contentMapMatchesRequest = SubmitRequestType.Call === requestBody.request_type &&
129
+ canisterId.toText() === requestBody.canister_id.toText() &&
130
+ fields.methodName === requestBody.method_name &&
131
+ uint8Equals(fields.arg, requestBody.arg) &&
132
+ this.#options.account.toText() === Principal.from(requestBody.sender).toText();
133
+ if (!contentMapMatchesRequest) {
134
+ throw new SignerAgentError(INVALID_RESPONSE_MESSAGE);
135
+ }
136
+ // Validate the certificate against the IC root key
137
+ const requestId = requestIdOf(requestBody);
138
+ const certificate = await Certificate.create({
139
+ certificate: response.certificate,
140
+ rootKey: this.rootKey,
141
+ principal: { canisterId },
142
+ maxAgeInMinutes: MAX_AGE_IN_MINUTES,
143
+ }).catch(cause => {
144
+ throw new SignerAgentError(INVALID_RESPONSE_MESSAGE, { cause });
145
+ });
146
+ // Extract the reply from the certified state tree
147
+ const replyLookup = certificate.lookup_path(['request_status', requestId, 'reply']);
148
+ if (replyLookup.status !== LookupPathStatus.Found) {
149
+ throw new SignerAgentError(INVALID_RESPONSE_MESSAGE);
150
+ }
151
+ // Store raw certificate for readState lookups, deleted on first read
152
+ this.#certificates.set(toHex(requestId), response.certificate);
153
+ return {
154
+ requestId,
155
+ requestBody,
156
+ certificate,
157
+ rawCertificate: response.certificate,
158
+ reply: replyLookup.value,
159
+ };
160
+ }
161
+ /**
162
+ * Sends a canister call through the signer.
163
+ * Returns the request ID and a synthetic HTTP response.
164
+ * @param canisterId - The target canister principal or its text representation.
165
+ * @param fields - The call options including method name and arguments.
166
+ */
167
+ async call(canisterId, fields) {
168
+ canisterId = Principal.from(canisterId);
169
+ const { requestId, requestBody } = await this.#sendAndVerify(canisterId, fields);
170
+ return {
171
+ requestId,
172
+ response: {
173
+ ok: true,
174
+ status: 202,
175
+ statusText: 'Call has been sent over ICRC-25 JSON-RPC',
176
+ body: null,
177
+ headers: [],
178
+ },
179
+ requestDetails: requestBody,
180
+ };
181
+ }
182
+ /**
183
+ * Executes a canister update call and returns the certified result.
184
+ * Combines {@link call} with certificate validation and reply extraction.
185
+ * @param canisterId - The target canister principal or its text representation.
186
+ * @param fields - The call options including method name and arguments.
187
+ * @param _pollingOptions - Ignored. The signer already returns the
188
+ * certificate with the reply in a single round-trip.
189
+ */
190
+ async update(canisterId, fields, _pollingOptions) {
191
+ canisterId = Principal.from(canisterId);
192
+ const { requestBody, certificate, rawCertificate, reply } = await this.#sendAndVerify(canisterId, fields);
193
+ return {
194
+ certificate,
195
+ reply,
196
+ rawCertificate,
197
+ requestDetails: requestBody,
198
+ callResponse: {
199
+ ok: true,
200
+ status: 202,
201
+ statusText: 'Call has been sent over ICRC-25 JSON-RPC',
202
+ body: null,
203
+ headers: [],
204
+ },
205
+ };
206
+ }
207
+ /**
208
+ * Executes a query by upgrading it to a canister call through the signer.
209
+ * The signer signs and submits the call, and the reply is extracted
210
+ * from the certified response.
211
+ * @param canisterId - The target canister principal or its text representation.
212
+ * @param options - The query fields including method name and arguments.
213
+ * @param _identity - Ignored. The signer manages identity internally.
214
+ */
215
+ async query(canisterId, options, _identity) {
216
+ canisterId = Principal.from(canisterId);
217
+ const { requestId, reply } = await this.#sendAndVerify(canisterId, {
218
+ methodName: options.methodName,
219
+ arg: options.arg,
220
+ effectiveCanisterId: canisterId,
221
+ });
222
+ return {
223
+ requestId,
224
+ status: 'replied',
225
+ reply: { arg: reply },
226
+ httpDetails: {
227
+ ok: true,
228
+ status: 202,
229
+ statusText: 'Certificate with reply has been received over ICRC-25 JSON-RPC',
230
+ headers: [],
231
+ },
232
+ };
233
+ }
234
+ /** Fetches the IC root key via the underlying HttpAgent. */
235
+ async fetchRootKey() {
236
+ return await this.#options.agent.fetchRootKey();
237
+ }
238
+ /** Returns the account principal this agent makes calls on behalf of. */
239
+ getPrincipal() {
240
+ return Promise.resolve(this.#options.account);
241
+ }
242
+ /**
243
+ * @internal
244
+ * @param _options - The read state options.
245
+ * @param _identity - The identity to use for the request.
246
+ */
247
+ createReadStateRequest(_options, _identity) {
248
+ return Promise.resolve({ body: { content: {} } });
249
+ }
250
+ /**
251
+ * Returns the raw certificate for a previously completed call.
252
+ * The certificate is deleted after being read (single-use).
253
+ *
254
+ * Only supports `request_status` paths for request IDs that were
255
+ * returned by a prior {@link call}, {@link update}, or {@link query}.
256
+ * @param _canisterId - The target canister principal (unused).
257
+ * @param options - The read state options containing paths to look up.
258
+ * @param _identity - The identity to use (unused).
259
+ * @param _request - The request object (unused).
260
+ */
261
+ readState(_canisterId, options, _identity, _request) {
262
+ if (options.paths.length !== 1 ||
263
+ options.paths[0].length !== 2 ||
264
+ new TextDecoder().decode(options.paths[0][0]) !== 'request_status') {
265
+ return Promise.reject(new SignerAgentError('Given paths are not supported'));
266
+ }
267
+ const requestId = options.paths[0][1];
268
+ const key = toHex(requestId);
269
+ const certificate = this.#certificates.get(key);
270
+ if (!certificate) {
271
+ return Promise.reject(new SignerAgentError('Certificate could not be found'));
272
+ }
273
+ this.#certificates.delete(key);
274
+ return Promise.resolve({ certificate });
275
+ }
276
+ /** Queries the IC replica status via the underlying HttpAgent. */
277
+ async status() {
278
+ return await this.#options.agent.status();
279
+ }
280
+ /**
281
+ * Replaces the account principal used for subsequent calls.
282
+ * @param account - The new account principal to use for subsequent calls.
283
+ */
284
+ replaceAccount(account) {
285
+ this.#options.account = account;
286
+ }
287
+ }
288
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../../src/agent/agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export { SignerAgent, SignerAgentError, type SignerAgentOptions } from './agent.js';
@@ -0,0 +1,2 @@
1
+ export { SignerAgent, SignerAgentError } from './agent.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/agent/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAA2B,MAAM,YAAY,CAAC"}
@@ -0,0 +1,37 @@
1
+ import { type Channel, type JsonRpcRequest, type JsonRpcResponse } from '../transport.js';
2
+ import type { ProviderDetail } from './types.js';
3
+ /** Options for creating a {@link BrowserExtensionChannel}. */
4
+ export interface BrowserExtensionChannelOptions {
5
+ /** The provider details obtained during extension discovery. */
6
+ providerDetail: ProviderDetail;
7
+ /**
8
+ * The window to listen for extension events on.
9
+ * @default globalThis.window
10
+ */
11
+ window?: Window;
12
+ }
13
+ /**
14
+ * A {@link Channel} implementation that communicates with a browser
15
+ * extension signer via the ICRC-94 provider API.
16
+ *
17
+ * Messages are sent through `providerDetail.sendMessage` and responses
18
+ * are validated as JSON-RPC before being dispatched to listeners.
19
+ * The channel is automatically closed if the extension fires an
20
+ * `icrc94:unexpectedlyClosed` event.
21
+ */
22
+ export declare class BrowserExtensionChannel implements Channel {
23
+ #private;
24
+ constructor(options: BrowserExtensionChannelOptions);
25
+ /** Whether this channel has been closed. */
26
+ get closed(): boolean;
27
+ addEventListener(...[event, listener]: [event: 'close', listener: () => void] | [event: 'response', listener: (response: JsonRpcResponse) => void]): () => void;
28
+ /**
29
+ * Sends a JSON-RPC request to the extension via `providerDetail.sendMessage`.
30
+ * The response is validated as JSON-RPC before being dispatched.
31
+ * Non-JSON-RPC responses are silently ignored.
32
+ * @param request - The JSON-RPC request to send to the extension.
33
+ */
34
+ send(request: JsonRpcRequest): Promise<void>;
35
+ /** Dismisses the extension and notifies all close listeners. */
36
+ close(): Promise<void>;
37
+ }
@@ -0,0 +1,80 @@
1
+ import { isJsonRpcResponse, } from '../transport.js';
2
+ import { BrowserExtensionTransportError } from './browserExtensionTransport.js';
3
+ /**
4
+ * A {@link Channel} implementation that communicates with a browser
5
+ * extension signer via the ICRC-94 provider API.
6
+ *
7
+ * Messages are sent through `providerDetail.sendMessage` and responses
8
+ * are validated as JSON-RPC before being dispatched to listeners.
9
+ * The channel is automatically closed if the extension fires an
10
+ * `icrc94:unexpectedlyClosed` event.
11
+ */
12
+ export class BrowserExtensionChannel {
13
+ #closeListeners = new Set();
14
+ #responseListeners = new Set();
15
+ #options;
16
+ #closed = false;
17
+ constructor(options) {
18
+ this.#options = {
19
+ window: globalThis.window,
20
+ ...options,
21
+ };
22
+ // Listen for unexpected extension closure
23
+ const closeListener = () => {
24
+ this.#options.window.removeEventListener('icrc94:unexpectedlyClosed', closeListener);
25
+ this.#closed = true;
26
+ for (const listener of this.#closeListeners) {
27
+ listener();
28
+ }
29
+ };
30
+ this.#options.window.addEventListener('icrc94:unexpectedlyClosed', closeListener);
31
+ }
32
+ /** Whether this channel has been closed. */
33
+ get closed() {
34
+ return this.#closed;
35
+ }
36
+ addEventListener(...[event, listener]) {
37
+ switch (event) {
38
+ case 'close':
39
+ this.#closeListeners.add(listener);
40
+ return () => {
41
+ this.#closeListeners.delete(listener);
42
+ };
43
+ case 'response':
44
+ this.#responseListeners.add(listener);
45
+ return () => {
46
+ this.#responseListeners.delete(listener);
47
+ };
48
+ }
49
+ }
50
+ /**
51
+ * Sends a JSON-RPC request to the extension via `providerDetail.sendMessage`.
52
+ * The response is validated as JSON-RPC before being dispatched.
53
+ * Non-JSON-RPC responses are silently ignored.
54
+ * @param request - The JSON-RPC request to send to the extension.
55
+ */
56
+ async send(request) {
57
+ if (this.#closed) {
58
+ throw new BrowserExtensionTransportError('Communication channel is closed');
59
+ }
60
+ const response = await this.#options.providerDetail.sendMessage(request);
61
+ if (!isJsonRpcResponse(response)) {
62
+ return;
63
+ }
64
+ for (const listener of this.#responseListeners) {
65
+ listener(response);
66
+ }
67
+ }
68
+ /** Dismisses the extension and notifies all close listeners. */
69
+ async close() {
70
+ if (this.#closed) {
71
+ return;
72
+ }
73
+ this.#closed = true;
74
+ await this.#options.providerDetail.dismiss();
75
+ for (const listener of this.#closeListeners) {
76
+ listener();
77
+ }
78
+ }
79
+ }
80
+ //# sourceMappingURL=browserExtensionChannel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browserExtensionChannel.js","sourceRoot":"","sources":["../../../src/extension/browserExtensionChannel.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,iBAAiB,GAGlB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,8BAA8B,EAAE,MAAM,gCAAgC,CAAC;AAchF;;;;;;;;GAQG;AACH,MAAM,OAAO,uBAAuB;IACzB,eAAe,GAAG,IAAI,GAAG,EAAc,CAAC;IACxC,kBAAkB,GAAG,IAAI,GAAG,EAAuC,CAAC;IACpE,QAAQ,CAA2C;IAC5D,OAAO,GAAG,KAAK,CAAC;IAEhB,YAAY,OAAuC;QACjD,IAAI,CAAC,QAAQ,GAAG;YACd,MAAM,EAAE,UAAU,CAAC,MAAM;YACzB,GAAG,OAAO;SACX,CAAC;QAEF,0CAA0C;QAC1C,MAAM,aAAa,GAAG,GAAG,EAAE;YACzB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,mBAAmB,CAAC,2BAA2B,EAAE,aAAa,CAAC,CAAC;YACrF,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;gBAC5C,QAAQ,EAAE,CAAC;YACb,CAAC;QACH,CAAC,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,gBAAgB,CAAC,2BAA2B,EAAE,aAAa,CAAC,CAAC;IACpF,CAAC;IAED,4CAA4C;IAC5C,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,gBAAgB,CACd,GAAG,CAAC,KAAK,EAAE,QAAQ,CAEmD;QAEtE,QAAQ,KAAK,EAAE,CAAC;YACd,KAAK,OAAO;gBACV,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBACnC,OAAO,GAAG,EAAE;oBACV,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;gBACxC,CAAC,CAAC;YACJ,KAAK,UAAU;gBACb,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBACtC,OAAO,GAAG,EAAE;oBACV,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;gBAC3C,CAAC,CAAC;QACN,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,IAAI,CAAC,OAAuB;QAChC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,IAAI,8BAA8B,CAAC,iCAAiC,CAAC,CAAC;QAC9E,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QACzE,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,EAAE,CAAC;YACjC,OAAO;QACT,CAAC;QACD,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC/C,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAED,gEAAgE;IAChE,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,MAAM,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC;QAC7C,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YAC5C,QAAQ,EAAE,CAAC;QACb,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,67 @@
1
+ import type { Transport } from '../transport.js';
2
+ import { BrowserExtensionChannel, type BrowserExtensionChannelOptions } from './browserExtensionChannel.js';
3
+ import type { ProviderDetail } from './types.js';
4
+ /** Error thrown by {@link BrowserExtensionTransport} for transport-level failures. */
5
+ export declare class BrowserExtensionTransportError extends Error {
6
+ }
7
+ /** Options for creating a {@link BrowserExtensionTransport}. */
8
+ export type BrowserExtensionTransportOptions = BrowserExtensionChannelOptions;
9
+ /** Options for {@link BrowserExtensionTransport.discover}. */
10
+ export interface DiscoverBrowserExtensionOptions {
11
+ /**
12
+ * Time in milliseconds to wait for browser extensions to announce themselves
13
+ * via `icrc94:announceProvider` events.
14
+ * @default 100
15
+ */
16
+ discoveryDuration?: number;
17
+ /**
18
+ * The window to listen for extension events on.
19
+ * @default globalThis.window
20
+ */
21
+ window?: Window;
22
+ }
23
+ /** Options for {@link BrowserExtensionTransport.findTransport}. */
24
+ export interface EstablishBrowserExtensionTransportOptions extends DiscoverBrowserExtensionOptions, Omit<BrowserExtensionTransportOptions, 'providerDetail'> {
25
+ /** The UUID of the browser extension to connect to. */
26
+ uuid: string;
27
+ }
28
+ /**
29
+ * ICRC-94 transport for communicating with browser extension signers.
30
+ *
31
+ * Browser extensions announce themselves via `icrc94:announceProvider`
32
+ * window events. Use {@link BrowserExtensionTransport.discover} to find installed extensions, or
33
+ * {@link BrowserExtensionTransport.findTransport} to connect to a specific one by UUID.
34
+ * @see https://github.com/dfinity/wg-identity-authentication/blob/main/topics/icrc_94_multi_injected_provider_discovery.md
35
+ * @example
36
+ * ```ts
37
+ * // Discover all installed extensions
38
+ * const providers = await BrowserExtensionTransport.discover();
39
+ *
40
+ * // Or connect to a specific extension by UUID
41
+ * const transport = await BrowserExtensionTransport.findTransport({ uuid: "..." });
42
+ * const signer = new Signer({ transport });
43
+ * ```
44
+ */
45
+ export declare class BrowserExtensionTransport implements Transport {
46
+ #private;
47
+ constructor(options: BrowserExtensionTransportOptions);
48
+ /**
49
+ * Discovers all installed browser extension signers by dispatching
50
+ * an `icrc94:requestProvider` event and collecting `icrc94:announceProvider`
51
+ * responses. Waits for `discoveryDuration` ms before returning.
52
+ * @param root0 - The discovery options.
53
+ * @param root0.discoveryDuration - Time in milliseconds to wait for announcements.
54
+ * @param root0.window - The window to listen for extension events on.
55
+ * @returns The discovered extension providers, deduplicated by UUID.
56
+ */
57
+ static discover({ discoveryDuration, window, }?: DiscoverBrowserExtensionOptions): Promise<ProviderDetail[]>;
58
+ /**
59
+ * Discovers extensions and connects to the one matching the given UUID.
60
+ * @param options - The options including UUID and discovery settings.
61
+ * @throws {BrowserExtensionTransportError} If no extension with the given
62
+ * UUID is found.
63
+ */
64
+ static findTransport(options: EstablishBrowserExtensionTransportOptions): Promise<BrowserExtensionTransport>;
65
+ /** Creates a new {@link BrowserExtensionChannel} for this extension. */
66
+ establishChannel(): Promise<BrowserExtensionChannel>;
67
+ }
@@ -0,0 +1,70 @@
1
+ import { BrowserExtensionChannel, } from './browserExtensionChannel.js';
2
+ /** Error thrown by {@link BrowserExtensionTransport} for transport-level failures. */
3
+ export class BrowserExtensionTransportError extends Error {
4
+ }
5
+ /**
6
+ * ICRC-94 transport for communicating with browser extension signers.
7
+ *
8
+ * Browser extensions announce themselves via `icrc94:announceProvider`
9
+ * window events. Use {@link BrowserExtensionTransport.discover} to find installed extensions, or
10
+ * {@link BrowserExtensionTransport.findTransport} to connect to a specific one by UUID.
11
+ * @see https://github.com/dfinity/wg-identity-authentication/blob/main/topics/icrc_94_multi_injected_provider_discovery.md
12
+ * @example
13
+ * ```ts
14
+ * // Discover all installed extensions
15
+ * const providers = await BrowserExtensionTransport.discover();
16
+ *
17
+ * // Or connect to a specific extension by UUID
18
+ * const transport = await BrowserExtensionTransport.findTransport({ uuid: "..." });
19
+ * const signer = new Signer({ transport });
20
+ * ```
21
+ */
22
+ export class BrowserExtensionTransport {
23
+ #options;
24
+ constructor(options) {
25
+ this.#options = {
26
+ window: globalThis.window,
27
+ ...options,
28
+ };
29
+ }
30
+ /**
31
+ * Discovers all installed browser extension signers by dispatching
32
+ * an `icrc94:requestProvider` event and collecting `icrc94:announceProvider`
33
+ * responses. Waits for `discoveryDuration` ms before returning.
34
+ * @param root0 - The discovery options.
35
+ * @param root0.discoveryDuration - Time in milliseconds to wait for announcements.
36
+ * @param root0.window - The window to listen for extension events on.
37
+ * @returns The discovered extension providers, deduplicated by UUID.
38
+ */
39
+ static async discover({ discoveryDuration = 100, window = globalThis.window, } = {}) {
40
+ const providerDetails = [];
41
+ window.addEventListener('icrc94:announceProvider', ((event) => {
42
+ if (providerDetails.find(providerDetail => providerDetail.uuid === event.detail.uuid)) {
43
+ return;
44
+ }
45
+ providerDetails.push(event.detail);
46
+ }));
47
+ window.dispatchEvent(new CustomEvent('icrc94:requestProvider'));
48
+ await new Promise(resolve => setTimeout(resolve, discoveryDuration));
49
+ return providerDetails;
50
+ }
51
+ /**
52
+ * Discovers extensions and connects to the one matching the given UUID.
53
+ * @param options - The options including UUID and discovery settings.
54
+ * @throws {BrowserExtensionTransportError} If no extension with the given
55
+ * UUID is found.
56
+ */
57
+ static async findTransport(options) {
58
+ const providerDetails = await BrowserExtensionTransport.discover(options);
59
+ const providerDetail = providerDetails.find(({ uuid }) => uuid === options.uuid);
60
+ if (!providerDetail) {
61
+ throw new BrowserExtensionTransportError("Browser extension couldn't be found, make sure it's installed and enabled for this page.");
62
+ }
63
+ return new BrowserExtensionTransport({ ...options, providerDetail });
64
+ }
65
+ /** Creates a new {@link BrowserExtensionChannel} for this extension. */
66
+ establishChannel() {
67
+ return Promise.resolve(new BrowserExtensionChannel(this.#options));
68
+ }
69
+ }
70
+ //# sourceMappingURL=browserExtensionTransport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browserExtensionTransport.js","sourceRoot":"","sources":["../../../src/extension/browserExtensionTransport.ts"],"names":[],"mappings":"AACA,OAAO,EACL,uBAAuB,GAExB,MAAM,8BAA8B,CAAC;AAGtC,sFAAsF;AACtF,MAAM,OAAO,8BAA+B,SAAQ,KAAK;CAAG;AA6B5D;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,yBAAyB;IAC3B,QAAQ,CAA6C;IAE9D,YAAY,OAAyC;QACnD,IAAI,CAAC,QAAQ,GAAG;YACd,MAAM,EAAE,UAAU,CAAC,MAAM;YACzB,GAAG,OAAO;SACX,CAAC;IACJ,CAAC;IAED;;;;;;;;OAQG;IACH,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,EACpB,iBAAiB,GAAG,GAAG,EACvB,MAAM,GAAG,UAAU,CAAC,MAAM,MACS,EAAE;QACrC,MAAM,eAAe,GAAqB,EAAE,CAAC;QAC7C,MAAM,CAAC,gBAAgB,CAAC,yBAAyB,EAAE,CAAC,CAAC,KAAkC,EAAE,EAAE;YACzF,IAAI,eAAe,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,cAAc,CAAC,IAAI,KAAK,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;gBACtF,OAAO;YACT,CAAC;YACD,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACrC,CAAC,CAAkB,CAAC,CAAC;QACrB,MAAM,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,wBAAwB,CAAC,CAAC,CAAC;QAChE,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC;QACrE,OAAO,eAAe,CAAC;IACzB,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,KAAK,CAAC,aAAa,CACxB,OAAkD;QAElD,MAAM,eAAe,GAAG,MAAM,yBAAyB,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC1E,MAAM,cAAc,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QACjF,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,MAAM,IAAI,8BAA8B,CACtC,0FAA0F,CAC3F,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,yBAAyB,CAAC,EAAE,GAAG,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;IACvE,CAAC;IAED,wEAAwE;IACxE,gBAAgB;QACd,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,uBAAuB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;IACrE,CAAC;CACF"}
@@ -0,0 +1,3 @@
1
+ export { BrowserExtensionChannel, type BrowserExtensionChannelOptions, } from './browserExtensionChannel.js';
2
+ export { BrowserExtensionTransport, BrowserExtensionTransportError, type BrowserExtensionTransportOptions, type DiscoverBrowserExtensionOptions, type EstablishBrowserExtensionTransportOptions, } from './browserExtensionTransport.js';
3
+ export type { ProviderDetail } from './types.js';
@@ -0,0 +1,3 @@
1
+ export { BrowserExtensionChannel, } from './browserExtensionChannel.js';
2
+ export { BrowserExtensionTransport, BrowserExtensionTransportError, } from './browserExtensionTransport.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/extension/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,GAExB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,yBAAyB,EACzB,8BAA8B,GAI/B,MAAM,gCAAgC,CAAC"}
@@ -0,0 +1,32 @@
1
+ import type { JsonRpcRequest } from '../transport.js';
2
+ /**
3
+ * Details about a browser extension signer, as announced via the
4
+ * ICRC-94 `icrc94:announceProvider` event.
5
+ * @see https://github.com/dfinity/wg-identity-authentication/blob/main/topics/icrc_94_multi_injected_provider_discovery.md
6
+ */
7
+ export interface ProviderDetail {
8
+ /** Globally unique identifier (UUIDv4) for this extension. */
9
+ uuid: string;
10
+ /** Human-readable name of the signer. */
11
+ name: string;
12
+ /** Icon as a data URI (e.g. `data:image/svg+xml,...`). */
13
+ icon: `data:image/${string}`;
14
+ /** Reverse domain name identifier (e.g. `com.example.wallet`). */
15
+ rdns: string;
16
+ /** Sends a JSON-RPC request to the extension and returns the response. */
17
+ sendMessage: (message: JsonRpcRequest) => Promise<unknown>;
18
+ /** Dismisses the extension's UI. */
19
+ dismiss: () => Promise<void>;
20
+ }
21
+ /** Fired by extensions to announce their presence. */
22
+ export interface AnnounceProviderEvent extends CustomEvent<ProviderDetail> {
23
+ type: 'icrc94:announceProvider';
24
+ }
25
+ /** Dispatched by relying parties to trigger extension announcements. */
26
+ export interface RequestProviderEvent extends Event {
27
+ type: 'icrc94:requestProvider';
28
+ }
29
+ /** Fired by extensions when they close unexpectedly. */
30
+ export interface UnexpectedlyClosedEvent extends Event {
31
+ type: 'icrc94:unexpectedlyClosed';
32
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/extension/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export { type PermissionScope, type PermissionState, Signer, SignerError, type SignerOptions, type SupportedStandard, } from './signer.js';
2
+ export type { Channel, Transport } from './transport.js';
@@ -0,0 +1,2 @@
1
+ export { Signer, SignerError, } from './signer.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,MAAM,EACN,WAAW,GAGZ,MAAM,aAAa,CAAC"}