@seams/wallet 0.22.0 → 0.23.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 (54) hide show
  1. package/THIRD_PARTY_NOTICES.md +5 -2
  2. package/dist/.build-inputs.sha256 +1 -1
  3. package/dist/esm/externalNear/actions.js +26 -0
  4. package/dist/esm/externalNear/boundary.js +53 -0
  5. package/dist/esm/externalNear/controller.js +187 -0
  6. package/dist/esm/externalNear/hot.js +40 -0
  7. package/dist/esm/externalNear/index.js +3 -0
  8. package/dist/esm/externalNear/intear.js +109 -0
  9. package/dist/esm/externalNear/intearPopup.js +83 -0
  10. package/dist/esm/externalNear/meteor.js +121 -0
  11. package/dist/esm/externalNear/meteorRequest.js +117 -0
  12. package/dist/esm/externalNear/types.js +17 -0
  13. package/dist/esm/externalNear/wallets.js +33 -0
  14. package/dist/esm/node_modules/borsh/lib/esm/buffer.js +67 -0
  15. package/dist/esm/node_modules/borsh/lib/esm/deserialize.js +94 -0
  16. package/dist/esm/node_modules/borsh/lib/esm/index.js +13 -0
  17. package/dist/esm/node_modules/borsh/lib/esm/serialize.js +127 -0
  18. package/dist/esm/node_modules/borsh/lib/esm/types.js +19 -0
  19. package/dist/esm/node_modules/borsh/lib/esm/utils.js +104 -0
  20. package/dist/esm/plugins/plugin-utils.js +2 -5
  21. package/dist/esm/react/externalNear.css +90 -0
  22. package/dist/esm/react/externalNear.js +104 -0
  23. package/dist/esm/sdk/host-C5KYWEcs.js +1 -0
  24. package/dist/esm/sdk/wallet-iframe-host-ecdsa.js +1 -1
  25. package/dist/esm/sdk/wallet-iframe-host-full.js +1 -1
  26. package/dist/esm/sdk/wallet-iframe-host-near.js +1 -1
  27. package/dist/esm/sdk/wallet-iframe-host-runtime.js +1 -1
  28. package/dist/esm/sdk/wallet-ui.css +1 -1
  29. package/dist/public/headers.manifest.json +1 -1
  30. package/dist/public/sdk/host-C5KYWEcs.js +1 -0
  31. package/dist/public/sdk/wallet-iframe-host-ecdsa.js +1 -1
  32. package/dist/public/sdk/wallet-iframe-host-full.js +1 -1
  33. package/dist/public/sdk/wallet-iframe-host-near.js +1 -1
  34. package/dist/public/sdk/wallet-iframe-host-runtime.js +1 -1
  35. package/dist/public/sdk/wallet-ui.css +1 -1
  36. package/dist/public/wallet-assets.manifest.json +4 -5
  37. package/dist/public/wallet-service/index.html +4 -4
  38. package/dist/types/wallet/src/externalNear/actions.d.ts +20 -0
  39. package/dist/types/wallet/src/externalNear/boundary.d.ts +7 -0
  40. package/dist/types/wallet/src/externalNear/controller.d.ts +23 -0
  41. package/dist/types/wallet/src/externalNear/hot.d.ts +13 -0
  42. package/dist/types/wallet/src/externalNear/index.d.ts +4 -0
  43. package/dist/types/wallet/src/externalNear/intear.d.ts +12 -0
  44. package/dist/types/wallet/src/externalNear/intearPopup.d.ts +25 -0
  45. package/dist/types/wallet/src/externalNear/meteor.d.ts +16 -0
  46. package/dist/types/wallet/src/externalNear/meteorRequest.d.ts +29 -0
  47. package/dist/types/wallet/src/externalNear/types.d.ts +67 -0
  48. package/dist/types/wallet/src/externalNear/wallets.d.ts +4 -0
  49. package/dist/types/wallet/src/plugins/plugin-utils.d.ts +1 -1
  50. package/dist/types/wallet/src/react/externalNear.d.ts +26 -0
  51. package/package.json +18 -1
  52. package/dist/esm/plugins/SeamsWeb/walletIframe/sanitization.js +0 -18
  53. package/dist/esm/sdk/host-DoftJdVQ.js +0 -1
  54. package/dist/public/sdk/host-DoftJdVQ.js +0 -1
@@ -5,7 +5,7 @@ distributed Seams Wallet SDK, server runtime, Wasm, strict Workers, and CLI.
5
5
  Dependency license expressions come from their package metadata. Packaged
6
6
  license and notice wording is reproduced below with normalized whitespace.
7
7
 
8
- Inventory: 450 dependency records (41 npm, 409 Cargo).
8
+ Inventory: 451 dependency records (42 npm, 409 Cargo).
9
9
 
10
10
  ## Dependency inventory
11
11
 
@@ -446,6 +446,7 @@ Inventory: 450 dependency records (41 npm, 409 Cargo).
446
446
  | npm | abitype | 1.2.3 | MIT | awkweb.eth <t@wevm.dev>; jxom.eth <j@wevm.dev> |
447
447
  | npm | asn1js | 3.0.7 | BSD-3-Clause | Ryan Hurst rmh@unmitigatedrisk.com; Yury Strozhevsky yury@strozhevsky.com |
448
448
  | npm | base-x | 5.0.1 | MIT | Daniel Cousens |
449
+ | npm | borsh | 1.0.0 | Apache-2.0 | Near Inc |
449
450
  | npm | bs58 | 6.0.0 | MIT | |
450
451
  | npm | eventemitter3 | 5.0.1 | MIT | Arnout Kazemier |
451
452
  | npm | idb | 8.0.3 | ISC | Jake Archibald |
@@ -2767,7 +2768,7 @@ Applies to:
2767
2768
 
2768
2769
  ### 23f18e03dc49df91
2769
2770
 
2770
- Packaged as: LICENSE, LICENSE-MIT
2771
+ Packaged as: LICENSE, LICENSE-MIT, LICENSE-MIT.txt
2771
2772
 
2772
2773
  Applies to:
2773
2774
 
@@ -2837,6 +2838,7 @@ Applies to:
2837
2838
  - cargo:zmij@1.0.21
2838
2839
  - cargo:zmij@1.0.23
2839
2840
  - npm:@near-js/types@2.4.0
2841
+ - npm:borsh@1.0.0
2840
2842
 
2841
2843
  Permission is hereby granted, free of charge, to any
2842
2844
  person obtaining a copy of this software and associated
@@ -7353,6 +7355,7 @@ Applies to:
7353
7355
  - cargo:borsh@1.6.1
7354
7356
  - cargo:borsh@1.8.0
7355
7357
  - cargo:borsh@1.8.1
7358
+ - npm:borsh@1.0.0
7356
7359
 
7357
7360
  Apache License
7358
7361
  Version 2.0, January 2004
@@ -1 +1 @@
1
- 457a3a44df7bb82ea046daa003a51f06837f317a1ab7bbe92293931ea7e74773
1
+ 1338f3f6f35ca0a9209fea6d25a3fa10bac28bba32ba928546abfac7a06b84a3
@@ -0,0 +1,26 @@
1
+ import { ActionType, toActionArgsWasm } from "../shared-ts/src/near/actions.js";
2
+ //#region src/externalNear/actions.ts
3
+ /** Wallet Selector's JSON action format, shared by HOT and Intear. */
4
+ function externalNearAction(action) {
5
+ const normalized = toActionArgsWasm(action);
6
+ switch (normalized.action_type) {
7
+ case ActionType.Transfer: return {
8
+ type: "Transfer",
9
+ params: { deposit: normalized.deposit }
10
+ };
11
+ case ActionType.FunctionCall: return {
12
+ type: "FunctionCall",
13
+ params: {
14
+ methodName: normalized.method_name,
15
+ args: JSON.parse(normalized.args),
16
+ gas: normalized.gas,
17
+ deposit: normalized.deposit
18
+ }
19
+ };
20
+ default: throw new Error("Unsupported external NEAR action.");
21
+ }
22
+ }
23
+ //#endregion
24
+ export { externalNearAction };
25
+
26
+ //# sourceMappingURL=actions.js.map
@@ -0,0 +1,53 @@
1
+ import { isPlainObject } from "../shared-ts/src/utils/validation.js";
2
+ import { isValidAccountId } from "../shared-ts/src/utils/near.js";
3
+ import { ActionType, toActionArgsWasm } from "../shared-ts/src/near/actions.js";
4
+ import bs58 from "bs58";
5
+ //#region src/externalNear/boundary.ts
6
+ function parseAccounts(raw) {
7
+ if (!Array.isArray(raw) || raw.length === 0) throw new Error("The wallet has no connected accounts.");
8
+ const accounts = [];
9
+ for (const account of raw) {
10
+ if (!isValidAccountId(account)) throw new Error("The wallet returned an invalid account.");
11
+ accounts.push(account);
12
+ }
13
+ return Object.freeze(accounts);
14
+ }
15
+ function validateTransaction(input) {
16
+ if (!isValidAccountId(input.receiverId) || input.actions.length === 0) throw new Error("Provide a receiver and at least one action.");
17
+ for (const action of input.actions) {
18
+ const normalized = toActionArgsWasm(action);
19
+ if (normalized.action_type !== ActionType.FunctionCall && normalized.action_type !== ActionType.Transfer) throw new Error("External NEAR supports function calls and transfers.");
20
+ if (!/^\d+$/.test(normalized.deposit)) throw new Error("Deposit must be an unsigned integer.");
21
+ if (normalized.action_type === ActionType.FunctionCall && (!/^\d+$/.test(normalized.gas) || BigInt(normalized.gas) === 0n || !normalized.method_name)) throw new Error("Provide a method and positive gas amount.");
22
+ }
23
+ return structuredClone(input);
24
+ }
25
+ function parseSubmission(raw, connection) {
26
+ if (!Array.isArray(raw) || raw.length !== 1) throw new Error("Missing transaction outcome.");
27
+ const outcome = raw[0];
28
+ if (!isPlainObject(outcome) || !isPlainObject(outcome.transaction)) throw new Error("Invalid transaction outcome.");
29
+ const { hash, signer_id } = outcome.transaction;
30
+ if (typeof hash !== "string" || bs58.decode(hash).length !== 32 || signer_id !== connection.accountId) throw new Error("Transaction identity does not match the request.");
31
+ return Object.freeze({
32
+ hash,
33
+ accountId: connection.accountId,
34
+ network: connection.network
35
+ });
36
+ }
37
+ function executionStatus(raw, submission) {
38
+ if (!isPlainObject(raw) || !isPlainObject(raw.result)) return "unresolved";
39
+ const result = raw.result;
40
+ if (!isPlainObject(result.transaction) || result.transaction.hash !== submission.hash || result.transaction.signer_id !== submission.accountId || result.final_execution_status !== "FINAL") return "unresolved";
41
+ if (!isPlainObject(result.status)) return "unresolved";
42
+ if ("Failure" in result.status) return "failed";
43
+ if (!("SuccessValue" in result.status) || !Array.isArray(result.receipts_outcome)) return "unresolved";
44
+ for (const receipt of result.receipts_outcome) {
45
+ if (!isPlainObject(receipt) || !isPlainObject(receipt.outcome) || !isPlainObject(receipt.outcome.status)) return "unresolved";
46
+ if ("Failure" in receipt.outcome.status) return "failed";
47
+ }
48
+ return "confirmed";
49
+ }
50
+ //#endregion
51
+ export { executionStatus, parseAccounts, parseSubmission, validateTransaction };
52
+
53
+ //# sourceMappingURL=boundary.js.map
@@ -0,0 +1,187 @@
1
+ import { createNearWalletProvider, nearWalletName } from "./wallets.js";
2
+ import { connectedNear } from "./types.js";
3
+ import { executionStatus, parseAccounts, parseSubmission, validateTransaction } from "./boundary.js";
4
+ //#region src/externalNear/controller.ts
5
+ function failure(code, message) {
6
+ return {
7
+ ok: false,
8
+ code,
9
+ message
10
+ };
11
+ }
12
+ var ExternalNearController = class {
13
+ snapshot;
14
+ enabledWallets;
15
+ network;
16
+ rpcUrl;
17
+ listeners = /* @__PURE__ */ new Set();
18
+ generation = 0;
19
+ provider = null;
20
+ pending = false;
21
+ constructor(config) {
22
+ if (config.network !== "mainnet" && config.network !== "testnet") throw new Error("Use mainnet or testnet for the NEAR network.");
23
+ const url = new URL(config.rpcUrl);
24
+ if (url.protocol !== "https:" && url.protocol !== "http:") throw new Error("Use an HTTP NEAR RPC URL.");
25
+ this.network = config.network;
26
+ this.rpcUrl = config.rpcUrl;
27
+ this.enabledWallets = normalizeWallets(config.wallets);
28
+ this.snapshot = Object.freeze({
29
+ connection: { kind: "disconnected" },
30
+ busy: false,
31
+ wallets: this.enabledWallets
32
+ });
33
+ }
34
+ setWallets(wallets) {
35
+ this.enabledWallets = normalizeWallets(wallets);
36
+ const connection = this.snapshot.connection;
37
+ if (connection.kind !== "disconnected" && !this.enabledWallets.includes(connection.wallet)) {
38
+ this.disconnect();
39
+ return;
40
+ }
41
+ this.publish(connection);
42
+ }
43
+ getSnapshot = () => this.snapshot;
44
+ subscribe = (listener) => {
45
+ this.listeners.add(listener);
46
+ return this.unsubscribe.bind(this, listener);
47
+ };
48
+ unsubscribe(listener) {
49
+ this.listeners.delete(listener);
50
+ }
51
+ publish(connection) {
52
+ this.snapshot = Object.freeze({
53
+ connection,
54
+ busy: this.pending,
55
+ wallets: this.enabledWallets
56
+ });
57
+ for (const listener of this.listeners) listener();
58
+ }
59
+ async connect(wallet) {
60
+ if (!this.enabledWallets.includes(wallet)) return failure("unavailable", "This wallet is disabled for this application.");
61
+ if (this.pending) return failure("pending_request", "Complete the pending wallet request.");
62
+ if (wallet === "hot" && this.network !== "mainnet") return failure("unavailable", "HOT Wallet is available on mainnet only.");
63
+ this.disconnect();
64
+ this.pending = true;
65
+ const generation = ++this.generation;
66
+ this.publish({
67
+ kind: "connecting",
68
+ wallet
69
+ });
70
+ try {
71
+ if (generation !== this.generation) return failure("connection_changed", "Wallet selection changed.");
72
+ const provider = await createNearWalletProvider(wallet, this.rpcUrl);
73
+ if (generation !== this.generation) {
74
+ provider.dispose();
75
+ return failure("connection_changed", "Wallet selection changed.");
76
+ }
77
+ this.provider = provider;
78
+ const accounts = parseAccounts(await provider.connect(this.network));
79
+ if (generation !== this.generation) return failure("connection_changed", "Wallet selection changed.");
80
+ const accountId = accounts[0];
81
+ if (!accountId) return failure("unavailable", "No wallet account is available.");
82
+ const connection = connectedNear(wallet, accountId, this.network, generation);
83
+ this.publish(connection);
84
+ return {
85
+ ok: true,
86
+ value: connection
87
+ };
88
+ } catch {
89
+ if (generation !== this.generation) return failure("connection_changed", "Wallet selection changed.");
90
+ this.disconnect();
91
+ return failure("unavailable", `${nearWalletName(wallet)} did not connect. Check the wallet and network, then try again.`);
92
+ } finally {
93
+ if (generation === this.generation) {
94
+ this.pending = false;
95
+ this.publish(this.snapshot.connection);
96
+ }
97
+ }
98
+ }
99
+ disconnect() {
100
+ ++this.generation;
101
+ const provider = this.provider;
102
+ this.provider = null;
103
+ this.pending = false;
104
+ provider?.dispose();
105
+ this.publish({ kind: "disconnected" });
106
+ }
107
+ async sendTransaction(connection, input) {
108
+ if (this.pending) return failure("pending_request", "Complete the pending wallet request.");
109
+ if (connection !== this.snapshot.connection || !this.provider) return failure("connection_changed", "Reconnect the wallet before signing.");
110
+ const provider = this.provider;
111
+ const generation = this.generation;
112
+ let transaction;
113
+ try {
114
+ transaction = validateTransaction(input);
115
+ } catch {
116
+ return failure("invalid_input", "Provide a valid transfer or function call.");
117
+ }
118
+ this.pending = true;
119
+ this.publish(connection);
120
+ let dispatched = false;
121
+ try {
122
+ const accounts = parseAccounts(await provider.accounts(this.network));
123
+ if (connection !== this.snapshot.connection || !accounts.includes(connection.accountId)) return failure("connection_changed", "Wallet account changed. Reconnect before signing.");
124
+ dispatched = true;
125
+ return {
126
+ ok: true,
127
+ value: parseSubmission(await provider.send(connection, transaction), connection)
128
+ };
129
+ } catch {
130
+ return dispatched ? failure("submission_unknown", "Submission is unknown. Check wallet activity before sending again.") : failure("unavailable", "Wallet account is unavailable.");
131
+ } finally {
132
+ if (generation === this.generation) {
133
+ this.pending = false;
134
+ this.publish(this.snapshot.connection);
135
+ }
136
+ }
137
+ }
138
+ async checkOutcome(submission) {
139
+ if (submission.network !== this.network) return {
140
+ kind: "unresolved",
141
+ submission
142
+ };
143
+ try {
144
+ const response = await fetch(this.rpcUrl, {
145
+ method: "POST",
146
+ headers: { "Content-Type": "application/json" },
147
+ signal: AbortSignal.timeout(15e3),
148
+ body: JSON.stringify({
149
+ jsonrpc: "2.0",
150
+ id: "external-near",
151
+ method: "tx",
152
+ params: {
153
+ tx_hash: submission.hash,
154
+ sender_account_id: submission.accountId,
155
+ wait_until: "FINAL"
156
+ }
157
+ })
158
+ });
159
+ if (!response.ok) return {
160
+ kind: "unresolved",
161
+ submission
162
+ };
163
+ return {
164
+ kind: executionStatus(await response.json(), submission),
165
+ submission
166
+ };
167
+ } catch {
168
+ return {
169
+ kind: "unresolved",
170
+ submission
171
+ };
172
+ }
173
+ }
174
+ };
175
+ function normalizeWallets(wallets) {
176
+ if (!Array.isArray(wallets)) throw new Error("Provide an explicit wallet list.");
177
+ const enabled = [];
178
+ for (const wallet of wallets) {
179
+ nearWalletName(wallet);
180
+ if (!enabled.includes(wallet)) enabled.push(wallet);
181
+ }
182
+ return Object.freeze(enabled);
183
+ }
184
+ //#endregion
185
+ export { ExternalNearController };
186
+
187
+ //# sourceMappingURL=controller.js.map
@@ -0,0 +1,40 @@
1
+ import { isObject } from "../shared-ts/src/utils/validation.js";
2
+ import { externalNearAction } from "./actions.js";
3
+ //#region src/externalNear/hot.ts
4
+ /** Direct extension API documented by hot-dao/hot-sdk-js. No iframe fallback. */
5
+ var HotExtensionProvider = class {
6
+ lifecycle = "active";
7
+ transport = Reflect.get(window, "hotExtension");
8
+ async request(method, params) {
9
+ if (this.lifecycle !== "active" || !isObject(this.transport) || Reflect.get(window, "hotExtension") !== this.transport) throw new Error("Install HOT Wallet or reconnect after the extension changes.");
10
+ const request = this.transport.request;
11
+ if (typeof request !== "function") throw new Error("HOT extension API is unavailable.");
12
+ return Reflect.apply(request, this.transport, [method, params]);
13
+ }
14
+ async connect(network) {
15
+ if (network !== "mainnet") throw new Error("HOT testnet support is not qualified.");
16
+ const response = await this.request("near:signIn", {});
17
+ if (!isObject(response)) throw new Error("Invalid HOT account response.");
18
+ return [response.accountId];
19
+ }
20
+ async accounts(network) {
21
+ return this.connect(network);
22
+ }
23
+ async send(connection, transaction) {
24
+ if (connection.network !== "mainnet") throw new Error("HOT requires mainnet.");
25
+ const response = await this.request("near:signAndSendTransactions", { transactions: [{
26
+ signerId: connection.accountId,
27
+ receiverId: transaction.receiverId,
28
+ actions: transaction.actions.map(externalNearAction)
29
+ }] });
30
+ if (!isObject(response)) throw new Error("Invalid HOT transaction response.");
31
+ return response.transactions;
32
+ }
33
+ dispose() {
34
+ this.lifecycle = "disposed";
35
+ }
36
+ };
37
+ //#endregion
38
+ export { HotExtensionProvider };
39
+
40
+ //# sourceMappingURL=hot.js.map
@@ -0,0 +1,3 @@
1
+ import { nearWalletName } from "./wallets.js";
2
+ import { ExternalNearController } from "./controller.js";
3
+ export { ExternalNearController, nearWalletName };
@@ -0,0 +1,109 @@
1
+ import { isPlainObject } from "../shared-ts/src/utils/validation.js";
2
+ import { base58Encode } from "../shared-ts/src/utils/base58.js";
3
+ import { isValidAccountId } from "../shared-ts/src/utils/near.js";
4
+ import { externalNearAction } from "./actions.js";
5
+ import { IntearPopup } from "./intearPopup.js";
6
+ //#region src/externalNear/intear.ts
7
+ /** The ephemeral key authenticates requests only. It is never installed on chain. */
8
+ async function authenticate(key, payload) {
9
+ const nonce = Date.now();
10
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(`${nonce}|${payload}`));
11
+ return {
12
+ nonce,
13
+ signature: `ed25519:${base58Encode(await crypto.subtle.sign("Ed25519", key.privateKey, digest))}`
14
+ };
15
+ }
16
+ var IntearWalletProvider = class {
17
+ lifecycle = "active";
18
+ popup = null;
19
+ session = null;
20
+ async connect(network) {
21
+ if (this.lifecycle !== "active") throw new Error("Intear connection disposed.");
22
+ const popup = new IntearPopup("/connect", "connected");
23
+ this.popup = popup;
24
+ const response = popup.result;
25
+ response.catch(ignorePopupFailure);
26
+ try {
27
+ const key = await crypto.subtle.generateKey({ name: "Ed25519" }, false, ["sign", "verify"]);
28
+ const publicKey = `ed25519:${base58Encode(await crypto.subtle.exportKey("raw", key.publicKey))}`;
29
+ const message = "{}";
30
+ const proof = await authenticate(key, message);
31
+ popup.send({
32
+ type: "signIn",
33
+ data: {
34
+ publicKey,
35
+ networkId: network,
36
+ message,
37
+ nonce: proof.nonce,
38
+ signature: proof.signature,
39
+ version: "V3",
40
+ actualOrigin: location.origin
41
+ }
42
+ });
43
+ const result = await response;
44
+ if (!isPlainObject(result) || !isValidAccountId(result.accountId) || result.functionCallKeyAdded !== false || result.useBridge !== false || result.walletUrl !== "https://wallet.intear.tech") throw new Error("Unsupported Intear connection response.");
45
+ this.session = {
46
+ accountId: result.accountId,
47
+ network,
48
+ key,
49
+ publicKey
50
+ };
51
+ return [result.accountId];
52
+ } catch (error) {
53
+ popup.fail(/* @__PURE__ */ new Error("Intear connection failed."));
54
+ throw error;
55
+ } finally {
56
+ if (this.popup === popup) this.popup = null;
57
+ }
58
+ }
59
+ async accounts(network) {
60
+ return this.session?.network === network ? [this.session.accountId] : [];
61
+ }
62
+ async send(connection, transaction) {
63
+ const session = this.session;
64
+ if (!session || session.network !== connection.network || session.accountId !== connection.accountId) throw new Error("Reconnect Intear.");
65
+ if (this.lifecycle !== "active") throw new Error("Intear connection disposed.");
66
+ const popup = new IntearPopup("/send-transactions", "sent");
67
+ this.popup = popup;
68
+ const response = popup.result;
69
+ response.catch(ignorePopupFailure);
70
+ try {
71
+ const transactions = JSON.stringify([{
72
+ signerId: session.accountId,
73
+ receiverId: transaction.receiverId,
74
+ actions: transaction.actions.map(externalNearAction)
75
+ }]);
76
+ const proof = await authenticate(session.key, transactions);
77
+ popup.send({
78
+ type: "signAndSendTransactions",
79
+ data: {
80
+ accountId: session.accountId,
81
+ publicKey: session.publicKey,
82
+ nonce: proof.nonce,
83
+ signature: proof.signature,
84
+ transactions,
85
+ mode: "Send"
86
+ }
87
+ });
88
+ const result = await response;
89
+ if (!isPlainObject(result)) throw new Error("Invalid Intear outcome.");
90
+ return result.outcomes;
91
+ } catch (error) {
92
+ popup.fail(/* @__PURE__ */ new Error("Intear transaction outcome is unknown."));
93
+ throw error;
94
+ } finally {
95
+ if (this.popup === popup) this.popup = null;
96
+ }
97
+ }
98
+ dispose() {
99
+ this.lifecycle = "disposed";
100
+ this.popup?.fail(/* @__PURE__ */ new Error("Intear disconnected. Check wallet activity for pending submissions."));
101
+ this.popup = null;
102
+ this.session = null;
103
+ }
104
+ };
105
+ function ignorePopupFailure() {}
106
+ //#endregion
107
+ export { IntearWalletProvider };
108
+
109
+ //# sourceMappingURL=intear.js.map
@@ -0,0 +1,83 @@
1
+ import { isPlainObject } from "../shared-ts/src/utils/validation.js";
2
+ //#region src/externalNear/intearPopup.ts
3
+ const INTEAR_ORIGIN = "https://wallet.intear.tech";
4
+ /** One popup per request; origin and WindowProxy together bind every response. */
5
+ var IntearPopup = class {
6
+ popup;
7
+ sent = false;
8
+ settled = false;
9
+ ready = false;
10
+ payload = null;
11
+ resolveResult = ignoreResult;
12
+ rejectResult = ignoreError;
13
+ interval;
14
+ timeout;
15
+ result;
16
+ constructor(path, successType) {
17
+ this.successType = successType;
18
+ this.popup = window.open(`${INTEAR_ORIGIN}${path}`, "_blank", "popup,width=420,height=720");
19
+ this.result = new Promise(this.captureResolvers);
20
+ window.addEventListener("message", this.receive);
21
+ this.interval = setInterval(this.checkClosed, 250);
22
+ this.timeout = setTimeout(this.expire, 12e4);
23
+ if (!this.popup) this.fail(/* @__PURE__ */ new Error("Allow popups to connect Intear Wallet."));
24
+ }
25
+ captureResolvers = (resolve, reject) => {
26
+ this.resolveResult = resolve;
27
+ this.rejectResult = reject;
28
+ };
29
+ send(payload) {
30
+ this.payload = payload;
31
+ this.dispatch();
32
+ }
33
+ dispatch() {
34
+ if (!this.settled && this.ready && !this.sent && this.payload && this.popup) {
35
+ this.sent = true;
36
+ this.popup.postMessage(this.payload, INTEAR_ORIGIN);
37
+ }
38
+ }
39
+ receive = (event) => {
40
+ if (this.settled || event.origin !== "https://wallet.intear.tech" || event.source !== this.popup || !isPlainObject(event.data)) return;
41
+ if (event.data.type === "ready") {
42
+ this.ready = true;
43
+ this.dispatch();
44
+ return;
45
+ }
46
+ if (!this.sent) return;
47
+ if (event.data.type === "error") {
48
+ this.fail(/* @__PURE__ */ new Error("Intear declined the request."));
49
+ return;
50
+ }
51
+ if (event.data.type === this.successType) {
52
+ this.cleanup();
53
+ this.resolveResult(event.data);
54
+ }
55
+ };
56
+ checkClosed = () => {
57
+ if (this.popup?.closed) this.fail(/* @__PURE__ */ new Error("Intear popup closed."));
58
+ };
59
+ expire = () => {
60
+ this.fail(/* @__PURE__ */ new Error("Intear request timed out."));
61
+ };
62
+ fail(error) {
63
+ if (!this.settled) {
64
+ this.cleanup();
65
+ this.rejectResult(error);
66
+ }
67
+ }
68
+ cleanup() {
69
+ this.settled = true;
70
+ clearInterval(this.interval);
71
+ clearTimeout(this.timeout);
72
+ window.removeEventListener("message", this.receive);
73
+ this.popup?.close();
74
+ this.popup = null;
75
+ this.payload = null;
76
+ }
77
+ };
78
+ function ignoreResult(_value) {}
79
+ function ignoreError(_error) {}
80
+ //#endregion
81
+ export { INTEAR_ORIGIN, IntearPopup };
82
+
83
+ //# sourceMappingURL=intearPopup.js.map
@@ -0,0 +1,121 @@
1
+ import { isPlainObject } from "../shared-ts/src/utils/validation.js";
2
+ import { base64Encode } from "../shared-ts/src/utils/base64.js";
3
+ import { base58Decode } from "../shared-ts/src/utils/base58.js";
4
+ import { isValidAccountId } from "../shared-ts/src/utils/near.js";
5
+ import { ActionType, toActionArgsWasm } from "../shared-ts/src/near/actions.js";
6
+ import { serialize } from "../node_modules/borsh/lib/esm/index.js";
7
+ import { MeteorRequest, meteorTransportFromWindow } from "./meteorRequest.js";
8
+ //#region src/externalNear/meteor.ts
9
+ const transactionSchema = { struct: {
10
+ signerId: "string",
11
+ publicKey: { struct: {
12
+ keyType: "u8",
13
+ data: { array: {
14
+ type: "u8",
15
+ len: 32
16
+ } }
17
+ } },
18
+ nonce: "u64",
19
+ receiverId: "string",
20
+ blockHash: { array: {
21
+ type: "u8",
22
+ len: 32
23
+ } },
24
+ actions: { array: { type: { enum: [
25
+ { struct: { createAccount: { struct: {} } } },
26
+ { struct: { deployContract: { struct: { code: { array: { type: "u8" } } } } } },
27
+ { struct: { functionCall: { struct: {
28
+ methodName: "string",
29
+ args: { array: { type: "u8" } },
30
+ gas: "u64",
31
+ deposit: "u128"
32
+ } } } },
33
+ { struct: { transfer: { struct: { deposit: "u128" } } } }
34
+ ] } } }
35
+ } };
36
+ function meteorAction(action) {
37
+ const value = toActionArgsWasm(action);
38
+ switch (value.action_type) {
39
+ case ActionType.Transfer: return { transfer: { deposit: BigInt(value.deposit) } };
40
+ case ActionType.FunctionCall: return { functionCall: {
41
+ methodName: value.method_name,
42
+ args: new TextEncoder().encode(value.args),
43
+ gas: BigInt(value.gas),
44
+ deposit: BigInt(value.deposit)
45
+ } };
46
+ default: throw new Error("Unsupported external NEAR action.");
47
+ }
48
+ }
49
+ var MeteorExtensionProvider = class {
50
+ lifecycle = "active";
51
+ transport = meteorTransportFromWindow();
52
+ request = null;
53
+ account = null;
54
+ constructor(rpcUrl) {
55
+ this.rpcUrl = rpcUrl;
56
+ }
57
+ async execute(network, action, inputs) {
58
+ if (this.lifecycle !== "active") throw new Error("Meteor connection disposed.");
59
+ const request = new MeteorRequest(this.transport, network, action, inputs);
60
+ this.request = request;
61
+ try {
62
+ return await request.result;
63
+ } finally {
64
+ if (this.request === request) this.request = null;
65
+ }
66
+ }
67
+ async connect(network) {
68
+ const response = await this.execute(network, "login", { methods: [] });
69
+ if (!isPlainObject(response) || !isValidAccountId(response.accountId)) throw new Error("Invalid Meteor account.");
70
+ this.account = {
71
+ accountId: response.accountId,
72
+ network
73
+ };
74
+ return [response.accountId];
75
+ }
76
+ async accounts(network) {
77
+ return this.account?.network === network ? [this.account.accountId] : [];
78
+ }
79
+ async send(connection, transaction) {
80
+ if (this.account?.accountId !== connection.accountId || this.account.network !== connection.network) throw new Error("Meteor account changed.");
81
+ const response = await fetch(this.rpcUrl, {
82
+ method: "POST",
83
+ headers: { "Content-Type": "application/json" },
84
+ signal: AbortSignal.timeout(15e3),
85
+ body: JSON.stringify({
86
+ jsonrpc: "2.0",
87
+ id: "meteor-block",
88
+ method: "block",
89
+ params: { finality: "final" }
90
+ })
91
+ });
92
+ const block = await response.json();
93
+ if (!response.ok || !isPlainObject(block) || !isPlainObject(block.result) || !isPlainObject(block.result.header) || typeof block.result.header.hash !== "string") throw new Error("Cannot read NEAR block.");
94
+ const blockHash = base58Decode(block.result.header.hash);
95
+ if (blockHash.length !== 32) throw new Error("Invalid NEAR block hash.");
96
+ const encoded = serialize(transactionSchema, {
97
+ signerId: connection.accountId,
98
+ publicKey: {
99
+ keyType: 0,
100
+ data: new Uint8Array(32)
101
+ },
102
+ nonce: 0n,
103
+ receiverId: transaction.receiverId,
104
+ blockHash,
105
+ actions: transaction.actions.map(meteorAction)
106
+ });
107
+ const outcome = await this.execute(connection.network, "sign", { transactions: base64Encode(encoded) });
108
+ if (!isPlainObject(outcome)) throw new Error("Invalid Meteor response.");
109
+ return outcome.executionOutcomes;
110
+ }
111
+ dispose() {
112
+ this.lifecycle = "disposed";
113
+ this.request?.cancel();
114
+ this.request = null;
115
+ this.account = null;
116
+ }
117
+ };
118
+ //#endregion
119
+ export { MeteorExtensionProvider };
120
+
121
+ //# sourceMappingURL=meteor.js.map