@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,113 @@
1
+ import { HeartbeatClient } from './heartbeat/client.js';
2
+ import { PostMessageChannel } from './postMessageChannel.js';
3
+ const NON_CLICK_ESTABLISHMENT_LINK = 'https://github.com/slide-computer/signer-js/blob/main/packages/signer-web/README.md#channels-must-be-established-in-a-click-handler';
4
+ /** Error thrown by {@link PostMessageTransport} for transport-level failures. */
5
+ export class PostMessageTransportError extends Error {
6
+ }
7
+ // Tracks whether we're inside a click event handler.
8
+ // Capture phase sets true, bubble phase resets to false.
9
+ let withinClick = false;
10
+ if (globalThis.window) {
11
+ globalThis.window.addEventListener('click', () => (withinClick = true), true);
12
+ globalThis.window.addEventListener('click', () => (withinClick = false));
13
+ }
14
+ /**
15
+ * ICRC-29 post message transport for communicating with web-based signers.
16
+ *
17
+ * Opens a window to the signer's URL and establishes a communication channel
18
+ * using the ICRC-29 heartbeat protocol (`icrc29_status` polling). Messages
19
+ * are exchanged via `window.postMessage`.
20
+ * @see https://github.com/dfinity/wg-identity-authentication/blob/main/topics/icrc_29_window_post_message_transport.md
21
+ * @example
22
+ * ```ts
23
+ * const transport = new PostMessageTransport({ url: "https://oisy.com/sign" });
24
+ * const signer = new Signer({ transport });
25
+ * ```
26
+ */
27
+ export class PostMessageTransport {
28
+ #options;
29
+ constructor(options) {
30
+ const isSecureContext = (() => {
31
+ try {
32
+ const url = new URL(options.url);
33
+ return (url.protocol === 'https:' ||
34
+ url.hostname === '127.0.0.1' ||
35
+ url.hostname.split('.').slice(-1)[0] === 'localhost');
36
+ }
37
+ catch {
38
+ return false;
39
+ }
40
+ })();
41
+ if (!isSecureContext) {
42
+ throw new PostMessageTransportError('Invalid signer RPC url');
43
+ }
44
+ this.#options = {
45
+ windowOpenerFeatures: '',
46
+ window: globalThis.window,
47
+ establishTimeout: 120000,
48
+ pendingTimeout: 300000,
49
+ disconnectTimeout: 2000,
50
+ statusPollingRate: 300,
51
+ crypto: globalThis.crypto,
52
+ manageFocus: true,
53
+ closeOnEstablishTimeout: true,
54
+ closeOnPendingTimeout: true,
55
+ detectNonClickEstablishment: true,
56
+ ...options,
57
+ };
58
+ }
59
+ /**
60
+ * Opens the signer window and establishes a communication channel
61
+ * via the ICRC-29 heartbeat handshake.
62
+ * @throws {PostMessageTransportError} If called outside a click handler
63
+ * (when `detectNonClickEstablishment` is enabled), if the window
64
+ * cannot be opened, or if the handshake times out.
65
+ */
66
+ establishChannel() {
67
+ if (this.#options.detectNonClickEstablishment && !withinClick) {
68
+ return Promise.reject(new PostMessageTransportError(`Signer window should not be opened outside of click handler, see: ${NON_CLICK_ESTABLISHMENT_LINK}`));
69
+ }
70
+ let signerWindow;
71
+ try {
72
+ const result = this.#options.window.open(this.#options.url, `${new URL(this.#options.url).origin}-signer-window`, this.#options.windowOpenerFeatures);
73
+ if (!result) {
74
+ return Promise.reject(new PostMessageTransportError('Signer window could not be opened'));
75
+ }
76
+ signerWindow = result;
77
+ }
78
+ catch (error) {
79
+ return Promise.reject(new PostMessageTransportError(error instanceof Error ? error.message : 'Signer window could not be opened'));
80
+ }
81
+ return new Promise((resolve, reject) => {
82
+ let channel;
83
+ new HeartbeatClient({
84
+ ...this.#options,
85
+ signerWindow,
86
+ onEstablish: (origin, status) => {
87
+ channel = new PostMessageChannel({
88
+ ...this.#options,
89
+ signerOrigin: origin,
90
+ signerWindow,
91
+ signerStatus: status,
92
+ });
93
+ resolve(channel);
94
+ },
95
+ onEstablishTimeout: () => {
96
+ if (this.#options.closeOnEstablishTimeout) {
97
+ signerWindow.close();
98
+ }
99
+ reject(new PostMessageTransportError('Communication channel could not be established within a reasonable time'));
100
+ },
101
+ onPendingTimeout: () => {
102
+ if (this.#options.closeOnPendingTimeout) {
103
+ signerWindow.close();
104
+ }
105
+ reject(new PostMessageTransportError('Communication channel was pending for too long'));
106
+ },
107
+ onDisconnect: () => channel.close(),
108
+ onStatusChange: status => channel.changeStatus(status),
109
+ });
110
+ });
111
+ }
112
+ }
113
+ //# sourceMappingURL=postMessageTransport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postMessageTransport.js","sourceRoot":"","sources":["../../../src/web/postMessageTransport.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,122 @@
1
+ {
2
+ "name": "@icp-sdk/signer",
3
+ "version": "5.2.0",
4
+ "author": "DFINITY Stiftung <sdk@dfinity.org>",
5
+ "license": "Apache-2.0",
6
+ "description": "Library to interact with signers on the Internet Computer",
7
+ "homepage": "https://js.icp.build/signer/",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/dfinity/icp-js-signer.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/dfinity/icp-js-signer/issues"
14
+ },
15
+ "keywords": [
16
+ "internet computer",
17
+ "internet-computer",
18
+ "ic",
19
+ "dfinity",
20
+ "signer",
21
+ "wallet",
22
+ "actor",
23
+ "dfx",
24
+ "canister",
25
+ "candid",
26
+ "motoko",
27
+ "javascript",
28
+ "typescript",
29
+ "blockchain",
30
+ "crypto",
31
+ "distributed",
32
+ "api",
33
+ "sdk"
34
+ ],
35
+ "type": "module",
36
+ "types": "./lib/esm/index.d.ts",
37
+ "exports": {
38
+ ".": {
39
+ "types": "./lib/esm/index.d.ts",
40
+ "import": "./lib/esm/index.js",
41
+ "default": "./lib/esm/index.js"
42
+ },
43
+ "./agent": {
44
+ "types": "./lib/esm/agent/index.d.ts",
45
+ "import": "./lib/esm/agent/index.js",
46
+ "default": "./lib/esm/agent/index.js"
47
+ },
48
+ "./web": {
49
+ "types": "./lib/esm/web/index.d.ts",
50
+ "import": "./lib/esm/web/index.js",
51
+ "default": "./lib/esm/web/index.js"
52
+ },
53
+ "./extension": {
54
+ "types": "./lib/esm/extension/index.d.ts",
55
+ "import": "./lib/esm/extension/index.js",
56
+ "default": "./lib/esm/extension/index.js"
57
+ }
58
+ },
59
+ "scripts": {
60
+ "build": "tsc -p tsconfig.esm.json && npm run lint:package",
61
+ "test": "vitest run",
62
+ "test:e2e": "npm run build && npm run build:e2e && playwright test",
63
+ "build:e2e": "cd e2e/fixtures && esbuild relying-party.ts mock-wallet.ts mock-auth-provider.ts --bundle --format=iife --outdir=. --out-extension:.js=.bundle.js --alias:@icp-sdk/signer=../../lib/esm/index.js --alias:@icp-sdk/signer/web=../../lib/esm/web/index.js --alias:@icp-sdk/signer/extension=../../lib/esm/extension/index.js --alias:@icp-sdk/signer/agent=../../lib/esm/agent/index.js",
64
+ "lint": "eslint src/",
65
+ "lint:fix": "eslint --fix src/",
66
+ "lint:package": "publint --strict",
67
+ "attw": "attw --pack .",
68
+ "docs": "cd docs && npm run build",
69
+ "size": "size-limit --json",
70
+ "prettier:check": "npx -p prettier -p pretty-quick pretty-quick --check --branch main",
71
+ "prettier:format": "npx -p prettier -p pretty-quick pretty-quick --branch main",
72
+ "prepare": "husky"
73
+ },
74
+ "peerDependencies": {
75
+ "@icp-sdk/core": "^5"
76
+ },
77
+ "size-limit": [
78
+ {
79
+ "name": "@icp-sdk/signer",
80
+ "path": "./lib/esm/index.js",
81
+ "limit": "15 kb"
82
+ },
83
+ {
84
+ "name": "@icp-sdk/signer/agent",
85
+ "path": "./lib/esm/agent/index.js",
86
+ "limit": "15 kb"
87
+ },
88
+ {
89
+ "name": "@icp-sdk/signer/web",
90
+ "path": "./lib/esm/web/index.js",
91
+ "limit": "15 kb"
92
+ },
93
+ {
94
+ "name": "@icp-sdk/signer/extension",
95
+ "path": "./lib/esm/extension/index.js",
96
+ "limit": "15 kb"
97
+ }
98
+ ],
99
+ "devDependencies": {
100
+ "@arethetypeswrong/cli": "^0.18.2",
101
+ "@eslint/js": "^10.0.1",
102
+ "@playwright/test": "^1.58.2",
103
+ "@size-limit/esbuild": "^12.0.1",
104
+ "@size-limit/preset-small-lib": "^12.0.1",
105
+ "@tsconfig/node22": "^22.0.5",
106
+ "@types/node": "^25.5.0",
107
+ "@typescript-eslint/eslint-plugin": "^8.58.0",
108
+ "@typescript-eslint/parser": "^8.58.0",
109
+ "esbuild": "^0.27.4",
110
+ "eslint": "^10.1.0",
111
+ "eslint-plugin-jsdoc": "^62.8.1",
112
+ "globals": "^17.4.0",
113
+ "husky": "^9.1.7",
114
+ "prettier": "^3.8.1",
115
+ "pretty-quick": "^4.2.2",
116
+ "publint": "^0.3.18",
117
+ "serve": "^14.2.6",
118
+ "size-limit": "^12.0.1",
119
+ "typescript": "^5.9.3",
120
+ "vitest": "^4.1.1"
121
+ }
122
+ }