near-kit 0.0.0 → 0.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 (132) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +473 -2
  3. package/dist/contracts/contract.d.ts +63 -0
  4. package/dist/contracts/contract.d.ts.map +1 -0
  5. package/dist/contracts/contract.js +42 -0
  6. package/dist/contracts/contract.js.map +1 -0
  7. package/dist/contracts/index.d.ts +5 -0
  8. package/dist/contracts/index.d.ts.map +1 -0
  9. package/dist/contracts/index.js +5 -0
  10. package/dist/contracts/index.js.map +1 -0
  11. package/dist/core/actions.d.ts +193 -0
  12. package/dist/core/actions.d.ts.map +1 -0
  13. package/dist/core/actions.js +195 -0
  14. package/dist/core/actions.js.map +1 -0
  15. package/dist/core/config-schemas.d.ts +179 -0
  16. package/dist/core/config-schemas.d.ts.map +1 -0
  17. package/dist/core/config-schemas.js +169 -0
  18. package/dist/core/config-schemas.js.map +1 -0
  19. package/dist/core/constants.d.ts +43 -0
  20. package/dist/core/constants.d.ts.map +1 -0
  21. package/dist/core/constants.js +49 -0
  22. package/dist/core/constants.js.map +1 -0
  23. package/dist/core/near.d.ts +301 -0
  24. package/dist/core/near.d.ts.map +1 -0
  25. package/dist/core/near.js +504 -0
  26. package/dist/core/near.js.map +1 -0
  27. package/dist/core/nonce-manager.d.ts +39 -0
  28. package/dist/core/nonce-manager.d.ts.map +1 -0
  29. package/dist/core/nonce-manager.js +73 -0
  30. package/dist/core/nonce-manager.js.map +1 -0
  31. package/dist/core/rpc/rpc-error-handler.d.ts +60 -0
  32. package/dist/core/rpc/rpc-error-handler.d.ts.map +1 -0
  33. package/dist/core/rpc/rpc-error-handler.js +324 -0
  34. package/dist/core/rpc/rpc-error-handler.js.map +1 -0
  35. package/dist/core/rpc/rpc-schemas.d.ts +1812 -0
  36. package/dist/core/rpc/rpc-schemas.d.ts.map +1 -0
  37. package/dist/core/rpc/rpc-schemas.js +424 -0
  38. package/dist/core/rpc/rpc-schemas.js.map +1 -0
  39. package/dist/core/rpc/rpc.d.ts +117 -0
  40. package/dist/core/rpc/rpc.d.ts.map +1 -0
  41. package/dist/core/rpc/rpc.js +325 -0
  42. package/dist/core/rpc/rpc.js.map +1 -0
  43. package/dist/core/schema.d.ts +1188 -0
  44. package/dist/core/schema.d.ts.map +1 -0
  45. package/dist/core/schema.js +396 -0
  46. package/dist/core/schema.js.map +1 -0
  47. package/dist/core/transaction.d.ts +390 -0
  48. package/dist/core/transaction.d.ts.map +1 -0
  49. package/dist/core/transaction.js +653 -0
  50. package/dist/core/transaction.js.map +1 -0
  51. package/dist/core/types.d.ts +271 -0
  52. package/dist/core/types.d.ts.map +1 -0
  53. package/dist/core/types.js +9 -0
  54. package/dist/core/types.js.map +1 -0
  55. package/dist/errors/index.d.ts +226 -0
  56. package/dist/errors/index.d.ts.map +1 -0
  57. package/dist/errors/index.js +366 -0
  58. package/dist/errors/index.js.map +1 -0
  59. package/dist/index.d.ts +16 -0
  60. package/dist/index.d.ts.map +1 -0
  61. package/dist/index.js +23 -0
  62. package/dist/index.js.map +1 -0
  63. package/dist/keys/credential-schemas.d.ts +98 -0
  64. package/dist/keys/credential-schemas.d.ts.map +1 -0
  65. package/dist/keys/credential-schemas.js +128 -0
  66. package/dist/keys/credential-schemas.js.map +1 -0
  67. package/dist/keys/file-keystore.d.ts +130 -0
  68. package/dist/keys/file-keystore.d.ts.map +1 -0
  69. package/dist/keys/file-keystore.js +266 -0
  70. package/dist/keys/file-keystore.js.map +1 -0
  71. package/dist/keys/in-memory-keystore.d.ts +71 -0
  72. package/dist/keys/in-memory-keystore.d.ts.map +1 -0
  73. package/dist/keys/in-memory-keystore.js +85 -0
  74. package/dist/keys/in-memory-keystore.js.map +1 -0
  75. package/dist/keys/index.d.ts +14 -0
  76. package/dist/keys/index.d.ts.map +1 -0
  77. package/dist/keys/index.js +20 -0
  78. package/dist/keys/index.js.map +1 -0
  79. package/dist/keys/native-keystore.d.ts +111 -0
  80. package/dist/keys/native-keystore.d.ts.map +1 -0
  81. package/dist/keys/native-keystore.js +167 -0
  82. package/dist/keys/native-keystore.js.map +1 -0
  83. package/dist/keys/rotating-keystore.d.ts +207 -0
  84. package/dist/keys/rotating-keystore.d.ts.map +1 -0
  85. package/dist/keys/rotating-keystore.js +240 -0
  86. package/dist/keys/rotating-keystore.js.map +1 -0
  87. package/dist/sandbox/index.d.ts +6 -0
  88. package/dist/sandbox/index.d.ts.map +1 -0
  89. package/dist/sandbox/index.js +5 -0
  90. package/dist/sandbox/index.js.map +1 -0
  91. package/dist/sandbox/sandbox.d.ts +55 -0
  92. package/dist/sandbox/sandbox.d.ts.map +1 -0
  93. package/dist/sandbox/sandbox.js +341 -0
  94. package/dist/sandbox/sandbox.js.map +1 -0
  95. package/dist/utils/amount.d.ts +76 -0
  96. package/dist/utils/amount.d.ts.map +1 -0
  97. package/dist/utils/amount.js +137 -0
  98. package/dist/utils/amount.js.map +1 -0
  99. package/dist/utils/gas.d.ts +69 -0
  100. package/dist/utils/gas.d.ts.map +1 -0
  101. package/dist/utils/gas.js +92 -0
  102. package/dist/utils/gas.js.map +1 -0
  103. package/dist/utils/index.d.ts +14 -0
  104. package/dist/utils/index.d.ts.map +1 -0
  105. package/dist/utils/index.js +14 -0
  106. package/dist/utils/index.js.map +1 -0
  107. package/dist/utils/key.d.ts +117 -0
  108. package/dist/utils/key.d.ts.map +1 -0
  109. package/dist/utils/key.js +270 -0
  110. package/dist/utils/key.js.map +1 -0
  111. package/dist/utils/nep413.d.ts +97 -0
  112. package/dist/utils/nep413.d.ts.map +1 -0
  113. package/dist/utils/nep413.js +154 -0
  114. package/dist/utils/nep413.js.map +1 -0
  115. package/dist/utils/validation.d.ts +114 -0
  116. package/dist/utils/validation.d.ts.map +1 -0
  117. package/dist/utils/validation.js +150 -0
  118. package/dist/utils/validation.js.map +1 -0
  119. package/dist/wallets/adapters.d.ts +119 -0
  120. package/dist/wallets/adapters.d.ts.map +1 -0
  121. package/dist/wallets/adapters.js +267 -0
  122. package/dist/wallets/adapters.js.map +1 -0
  123. package/dist/wallets/index.d.ts +11 -0
  124. package/dist/wallets/index.d.ts.map +1 -0
  125. package/dist/wallets/index.js +2 -0
  126. package/dist/wallets/index.js.map +1 -0
  127. package/dist/wallets/types.d.ts +99 -0
  128. package/dist/wallets/types.d.ts.map +1 -0
  129. package/dist/wallets/types.js +10 -0
  130. package/dist/wallets/types.js.map +1 -0
  131. package/package.json +78 -7
  132. package/index.js +0 -1
@@ -0,0 +1,240 @@
1
+ import { parseKey } from "../utils/key.js";
2
+ /**
3
+ * Rotating key store that cycles through multiple keys per account.
4
+ *
5
+ * This keystore enables high-throughput concurrent transactions by rotating
6
+ * through multiple access keys for a single account. Each transaction uses
7
+ * a different key in round-robin fashion, eliminating nonce collisions.
8
+ *
9
+ * ## Use Cases
10
+ * - **High-throughput applications**: Send many concurrent transactions without nonce collisions
11
+ * - **Load balancing**: Distribute transaction load across multiple access keys
12
+ * - **Key rotation**: Seamlessly rotate keys without downtime
13
+ *
14
+ * ## How It Works
15
+ * - Each account can have multiple keys registered
16
+ * - `get()` returns the next key in round-robin order
17
+ * - Each key has independent nonce tracking via NonceManager
18
+ * - No nonce collisions between concurrent transactions
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * // Create keystore with multiple keys for one account
23
+ * const keyStore = new RotatingKeyStore()
24
+ * await keyStore.add("alice.near", parseKey("ed25519:key1..."))
25
+ * await keyStore.add("alice.near", parseKey("ed25519:key2..."))
26
+ * await keyStore.add("alice.near", parseKey("ed25519:key3..."))
27
+ *
28
+ * const near = new Near({ network: "testnet", keyStore })
29
+ *
30
+ * // Send 100 concurrent transactions - no nonce collisions!
31
+ * await Promise.all(
32
+ * Array(100).fill(0).map(() =>
33
+ * near.transaction("alice.near")
34
+ * .transfer("bob.near", "0.1")
35
+ * .send()
36
+ * )
37
+ * )
38
+ * ```
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * // Initialize with keys
43
+ * const keyStore = new RotatingKeyStore({
44
+ * "alice.near": [
45
+ * "ed25519:key1...",
46
+ * "ed25519:key2...",
47
+ * "ed25519:key3..."
48
+ * ]
49
+ * })
50
+ * ```
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * // Query rotation state
55
+ * const keys = await keyStore.getAll("alice.near")
56
+ * console.log(`Account has ${keys.length} keys`)
57
+ *
58
+ * const index = keyStore.getCurrentIndex("alice.near")
59
+ * console.log(`Currently at key index ${index}`)
60
+ * ```
61
+ */
62
+ export class RotatingKeyStore {
63
+ /**
64
+ * Create a new rotating keystore.
65
+ *
66
+ * @param initialKeys - Optional initial keys to populate the store.
67
+ * Maps account IDs to arrays of private key strings.
68
+ *
69
+ * @example
70
+ * ```typescript
71
+ * const keyStore = new RotatingKeyStore({
72
+ * "alice.near": ["ed25519:key1...", "ed25519:key2..."],
73
+ * "bob.near": ["ed25519:key3..."]
74
+ * })
75
+ * ```
76
+ */
77
+ constructor(initialKeys) {
78
+ this.keys = new Map();
79
+ this.counters = new Map();
80
+ if (initialKeys) {
81
+ for (const [accountId, keyStrings] of Object.entries(initialKeys)) {
82
+ for (const keyString of keyStrings) {
83
+ const keyPair = parseKey(keyString);
84
+ const existing = this.keys.get(accountId) ?? [];
85
+ existing.push(keyPair);
86
+ this.keys.set(accountId, existing);
87
+ }
88
+ }
89
+ }
90
+ }
91
+ /**
92
+ * Get the next key for an account using round-robin rotation.
93
+ *
94
+ * Each call to `get()` advances to the next key in the rotation.
95
+ * This is the core mechanism that enables concurrent transactions
96
+ * without nonce collisions.
97
+ *
98
+ * @param accountId - NEAR account ID
99
+ * @returns Next key in rotation, or null if no keys exist for account
100
+ *
101
+ * @example
102
+ * ```typescript
103
+ * // First call returns key1, second returns key2, third returns key3, fourth returns key1...
104
+ * const key1 = await keyStore.get("alice.near")
105
+ * const key2 = await keyStore.get("alice.near")
106
+ * const key3 = await keyStore.get("alice.near")
107
+ * const key4 = await keyStore.get("alice.near") // Back to key1
108
+ * ```
109
+ */
110
+ async get(accountId) {
111
+ const accountKeys = this.keys.get(accountId);
112
+ if (!accountKeys || accountKeys.length === 0) {
113
+ return null;
114
+ }
115
+ // Get current counter and increment for next call
116
+ const counter = this.counters.get(accountId) ?? 0;
117
+ const key = accountKeys[counter % accountKeys.length];
118
+ this.counters.set(accountId, counter + 1);
119
+ // We know key exists because we checked accountKeys.length > 0 above
120
+ return key ?? null;
121
+ }
122
+ /**
123
+ * Add a key to an account's rotation pool.
124
+ *
125
+ * If the account already has keys, the new key is appended to the rotation.
126
+ * If this is the first key for the account, it becomes the starting key.
127
+ *
128
+ * @param accountId - NEAR account ID
129
+ * @param key - Key pair to add to rotation
130
+ * @param options - Optional metadata (preserved but not used for rotation)
131
+ *
132
+ * @example
133
+ * ```typescript
134
+ * await keyStore.add("alice.near", keyPair1)
135
+ * await keyStore.add("alice.near", keyPair2) // Now rotates between both
136
+ * ```
137
+ */
138
+ async add(accountId, key, _options) {
139
+ const existing = this.keys.get(accountId) ?? [];
140
+ existing.push(key);
141
+ this.keys.set(accountId, existing);
142
+ }
143
+ /**
144
+ * Remove all keys for an account from the rotation pool.
145
+ *
146
+ * This also resets the rotation counter for the account.
147
+ *
148
+ * @param accountId - NEAR account ID
149
+ *
150
+ * @example
151
+ * ```typescript
152
+ * await keyStore.remove("alice.near")
153
+ * ```
154
+ */
155
+ async remove(accountId) {
156
+ this.keys.delete(accountId);
157
+ this.counters.delete(accountId);
158
+ }
159
+ /**
160
+ * List all account IDs in the keystore.
161
+ *
162
+ * @returns Array of account IDs that have at least one key
163
+ *
164
+ * @example
165
+ * ```typescript
166
+ * const accounts = await keyStore.list()
167
+ * console.log(`Managing keys for: ${accounts.join(", ")}`)
168
+ * ```
169
+ */
170
+ async list() {
171
+ return Array.from(this.keys.keys());
172
+ }
173
+ /**
174
+ * Get all keys for an account (non-rotating).
175
+ *
176
+ * Returns all keys in the rotation pool without advancing the counter.
177
+ * Useful for inspecting or managing the key pool.
178
+ *
179
+ * @param accountId - NEAR account ID
180
+ * @returns Array of all key pairs for the account, or empty array if none exist
181
+ *
182
+ * @example
183
+ * ```typescript
184
+ * const keys = await keyStore.getAll("alice.near")
185
+ * console.log(`Account has ${keys.length} keys in rotation`)
186
+ * ```
187
+ */
188
+ async getAll(accountId) {
189
+ return this.keys.get(accountId) ?? [];
190
+ }
191
+ /**
192
+ * Get the current rotation index for an account.
193
+ *
194
+ * The index indicates which key will be returned on the next `get()` call.
195
+ *
196
+ * @param accountId - NEAR account ID
197
+ * @returns Current counter value (0-based index into key array)
198
+ *
199
+ * @example
200
+ * ```typescript
201
+ * const index = keyStore.getCurrentIndex("alice.near")
202
+ * const totalKeys = (await keyStore.getAll("alice.near")).length
203
+ * console.log(`Next key: ${index % totalKeys}`)
204
+ * ```
205
+ */
206
+ getCurrentIndex(accountId) {
207
+ return this.counters.get(accountId) ?? 0;
208
+ }
209
+ /**
210
+ * Reset the rotation counter for an account.
211
+ *
212
+ * The next `get()` call will return the first key in the rotation.
213
+ *
214
+ * @param accountId - NEAR account ID
215
+ *
216
+ * @example
217
+ * ```typescript
218
+ * keyStore.resetCounter("alice.near")
219
+ * const key = await keyStore.get("alice.near") // Returns first key
220
+ * ```
221
+ */
222
+ resetCounter(accountId) {
223
+ this.counters.set(accountId, 0);
224
+ }
225
+ /**
226
+ * Clear all keys and counters from the keystore.
227
+ *
228
+ * Useful for testing cleanup or resetting state.
229
+ *
230
+ * @example
231
+ * ```typescript
232
+ * keyStore.clear()
233
+ * ```
234
+ */
235
+ clear() {
236
+ this.keys.clear();
237
+ this.counters.clear();
238
+ }
239
+ }
240
+ //# sourceMappingURL=rotating-keystore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rotating-keystore.js","sourceRoot":"","sources":["../../src/keys/rotating-keystore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Sandbox exports
3
+ */
4
+ export type { SandboxOptions } from "./sandbox.js";
5
+ export { Sandbox } from "./sandbox.js";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sandbox/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Sandbox exports
3
+ */
4
+ export { Sandbox } from "./sandbox.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sandbox/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * NEAR Sandbox - Local testing environment
3
+ *
4
+ * Simple, explicit API for running a local NEAR node for testing.
5
+ */
6
+ export interface SandboxOptions {
7
+ version?: string;
8
+ /**
9
+ * Whether to spawn the sandbox process as detached.
10
+ * Default: true
11
+ * Set to false in test environments to prevent the process from being killed by test runners.
12
+ */
13
+ detached?: boolean;
14
+ }
15
+ /**
16
+ * NEAR Sandbox instance
17
+ *
18
+ * Manages a local NEAR node for testing. Automatically cleans up on stop().
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * const sandbox = await Sandbox.start();
23
+ * const near = new Near({ network: sandbox });
24
+ * // ... run tests
25
+ * await sandbox.stop();
26
+ * ```
27
+ */
28
+ export declare class Sandbox {
29
+ readonly rpcUrl: string;
30
+ readonly networkId: string;
31
+ readonly rootAccount: {
32
+ id: string;
33
+ secretKey: string;
34
+ };
35
+ private process;
36
+ private homeDir;
37
+ private constructor();
38
+ /**
39
+ * Start a new sandbox instance
40
+ *
41
+ * Downloads the sandbox binary if needed, initializes a temporary directory,
42
+ * and starts the sandbox process.
43
+ *
44
+ * @param options - Optional configuration
45
+ * @returns Promise resolving to a running Sandbox instance
46
+ */
47
+ static start(options?: SandboxOptions): Promise<Sandbox>;
48
+ /**
49
+ * Stop the sandbox and clean up
50
+ *
51
+ * Kills the sandbox process and removes temporary files.
52
+ */
53
+ stop(): Promise<void>;
54
+ }
55
+ //# sourceMappingURL=sandbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../../src/sandbox/sandbox.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAkCH,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,OAAO;IAClB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,WAAW,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IAEvD,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,OAAO,CAAQ;IAEvB,OAAO;IAcP;;;;;;;;OAQG;WACU,KAAK,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,OAAO,CAAC;IAuDlE;;;;OAIG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAiC5B"}
@@ -0,0 +1,341 @@
1
+ /**
2
+ * NEAR Sandbox - Local testing environment
3
+ *
4
+ * Simple, explicit API for running a local NEAR node for testing.
5
+ */
6
+ import { spawn } from "node:child_process";
7
+ import fs from "node:fs";
8
+ import { mkdir, mkdtemp, readFile, rm } from "node:fs/promises";
9
+ import { createServer } from "node:net";
10
+ import os from "node:os";
11
+ import path from "node:path";
12
+ import { Readable } from "node:stream";
13
+ import { pipeline } from "node:stream/promises";
14
+ import * as tar from "tar";
15
+ const DEFAULT_VERSION = "2.9.0";
16
+ const BINARY_NAME = "near-sandbox";
17
+ const ARCHIVE_NAME = "near-sandbox.tar.gz";
18
+ const DOWNLOAD_BASE = "https://s3-us-west-1.amazonaws.com/build.nearprotocol.com/nearcore";
19
+ const STARTUP_TIMEOUT = 60000;
20
+ const DOWNLOAD_TIMEOUT = 120000;
21
+ /**
22
+ * NEAR Sandbox instance
23
+ *
24
+ * Manages a local NEAR node for testing. Automatically cleans up on stop().
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * const sandbox = await Sandbox.start();
29
+ * const near = new Near({ network: sandbox });
30
+ * // ... run tests
31
+ * await sandbox.stop();
32
+ * ```
33
+ */
34
+ export class Sandbox {
35
+ constructor(rpcUrl, networkId, rootAccount, homeDir, childProcess) {
36
+ this.rpcUrl = rpcUrl;
37
+ this.networkId = networkId;
38
+ this.rootAccount = rootAccount;
39
+ this.homeDir = homeDir;
40
+ this.process = childProcess;
41
+ }
42
+ /**
43
+ * Start a new sandbox instance
44
+ *
45
+ * Downloads the sandbox binary if needed, initializes a temporary directory,
46
+ * and starts the sandbox process.
47
+ *
48
+ * @param options - Optional configuration
49
+ * @returns Promise resolving to a running Sandbox instance
50
+ */
51
+ static async start(options = {}) {
52
+ const version = options.version ?? DEFAULT_VERSION;
53
+ const detached = options.detached ?? true;
54
+ // 1. Ensure binary is available
55
+ const binaryPath = await ensureBinary(version);
56
+ // 2. Create temporary home directory
57
+ const homeDir = await mkdtemp(path.join(os.tmpdir(), "near-sandbox-"));
58
+ // 3. Initialize sandbox
59
+ await runInit(binaryPath, homeDir);
60
+ // 4. Read validator key
61
+ const validatorKey = await loadValidatorKey(homeDir);
62
+ const rootAccount = {
63
+ id: validatorKey.account_id,
64
+ secretKey: validatorKey.secret_key ?? validatorKey.private_key ?? "",
65
+ };
66
+ // 5. Start sandbox process
67
+ const port = await findAvailablePort();
68
+ const networkPort = port + 1;
69
+ const childProcess = spawn(binaryPath, [
70
+ "--home",
71
+ homeDir,
72
+ "run",
73
+ "--rpc-addr",
74
+ `0.0.0.0:${port}`,
75
+ "--network-addr",
76
+ `0.0.0.0:${networkPort}`,
77
+ ], {
78
+ detached,
79
+ stdio: detached ? "ignore" : "pipe",
80
+ });
81
+ if (!childProcess.pid) {
82
+ throw new Error("Failed to start sandbox: no PID");
83
+ }
84
+ if (detached) {
85
+ childProcess.unref();
86
+ }
87
+ const rpcUrl = `http://127.0.0.1:${port}`;
88
+ // 6. Wait for RPC to be ready
89
+ await waitForReady(rpcUrl);
90
+ return new Sandbox(rpcUrl, "localnet", rootAccount, homeDir, childProcess);
91
+ }
92
+ /**
93
+ * Stop the sandbox and clean up
94
+ *
95
+ * Kills the sandbox process and removes temporary files.
96
+ */
97
+ async stop() {
98
+ if (this.process?.pid) {
99
+ const pid = this.process.pid;
100
+ try {
101
+ // Try to kill process group first (for detached processes)
102
+ process.kill(-pid, "SIGTERM");
103
+ await sleep(100);
104
+ }
105
+ catch {
106
+ // Try direct kill
107
+ try {
108
+ process.kill(pid, "SIGTERM");
109
+ await sleep(100);
110
+ }
111
+ catch {
112
+ // Try SIGKILL as last resort
113
+ try {
114
+ process.kill(pid, "SIGKILL");
115
+ }
116
+ catch {
117
+ // Process already dead
118
+ }
119
+ }
120
+ }
121
+ this.process = undefined;
122
+ }
123
+ // Clean up temporary directory
124
+ try {
125
+ await rm(this.homeDir, { recursive: true, force: true });
126
+ }
127
+ catch {
128
+ // Ignore cleanup errors
129
+ }
130
+ }
131
+ }
132
+ // ==================== Helper Functions ====================
133
+ /**
134
+ * Get platform identifier for downloading correct binary.
135
+ * @internal
136
+ */
137
+ function getPlatformId() {
138
+ const system = os.platform();
139
+ const arch = os.arch();
140
+ const platform = system === "darwin" ? "Darwin" : "Linux";
141
+ const normalizedArch = arch === "x64" ? "x86_64" : arch;
142
+ if (!["x86_64", "arm64"].includes(normalizedArch)) {
143
+ throw new Error(`Unsupported architecture: ${arch}`);
144
+ }
145
+ if (system !== "darwin" && system !== "linux") {
146
+ throw new Error(`Unsupported platform: ${system}`);
147
+ }
148
+ return { system: platform, arch: normalizedArch };
149
+ }
150
+ /**
151
+ * Get directory for storing sandbox binaries.
152
+ * @internal
153
+ */
154
+ function getBinaryDir() {
155
+ const dir = path.join(os.homedir(), ".near-kit", "sandbox", "bin");
156
+ return dir;
157
+ }
158
+ /**
159
+ * Download and extract sandbox binary.
160
+ * @internal
161
+ */
162
+ async function downloadBinary(version) {
163
+ const { system, arch } = getPlatformId();
164
+ const destDir = getBinaryDir();
165
+ const filename = `${BINARY_NAME}-${version}`;
166
+ const dest = path.join(destDir, filename);
167
+ // Return if already exists
168
+ if (fs.existsSync(dest)) {
169
+ return dest;
170
+ }
171
+ const url = `${DOWNLOAD_BASE}/${system}-${arch}/${version}/${ARCHIVE_NAME}`;
172
+ const tmpDir = await mkdtemp(path.join(os.tmpdir(), "near-sandbox-download-"));
173
+ try {
174
+ const archivePath = path.join(tmpDir, ARCHIVE_NAME);
175
+ // Download with timeout
176
+ const controller = new AbortController();
177
+ const timeout = setTimeout(() => controller.abort(), DOWNLOAD_TIMEOUT);
178
+ try {
179
+ const response = await fetch(url, { signal: controller.signal });
180
+ if (!response.ok) {
181
+ throw new Error(`Download failed: ${response.status} ${response.statusText}`);
182
+ }
183
+ if (!response.body) {
184
+ throw new Error("Response body is null");
185
+ }
186
+ const stream = fs.createWriteStream(archivePath);
187
+ // Convert DOM ReadableStream to Node.js ReadableStream
188
+ await pipeline(Readable.fromWeb(response.body), stream);
189
+ }
190
+ finally {
191
+ clearTimeout(timeout);
192
+ }
193
+ // Extract archive (strip=1 removes top-level directory)
194
+ await tar.x({ file: archivePath, cwd: tmpDir, strip: 1 });
195
+ const extracted = path.join(tmpDir, BINARY_NAME);
196
+ if (!fs.existsSync(extracted)) {
197
+ throw new Error(`Binary ${BINARY_NAME} not found in archive`);
198
+ }
199
+ // Move to final location and make executable
200
+ await mkdir(path.dirname(dest), { recursive: true });
201
+ await fs.promises.rename(extracted, dest);
202
+ await fs.promises.chmod(dest, 0o755);
203
+ return dest;
204
+ }
205
+ catch (error) {
206
+ throw new Error(`Failed to download binary from ${url}: ${error}`);
207
+ }
208
+ finally {
209
+ await rm(tmpDir, { recursive: true, force: true });
210
+ }
211
+ }
212
+ /**
213
+ * Ensure binary is available and return its path.
214
+ * @internal
215
+ */
216
+ async function ensureBinary(version) {
217
+ return await downloadBinary(version);
218
+ }
219
+ /**
220
+ * Run sandbox init command.
221
+ * @internal
222
+ */
223
+ async function runInit(binaryPath, homeDir) {
224
+ const args = ["--home", homeDir, "init", "--chain-id", "localnet"];
225
+ return new Promise((resolve, reject) => {
226
+ const child = spawn(binaryPath, args, { stdio: "pipe" });
227
+ let stderr = "";
228
+ child.stderr?.on("data", (data) => {
229
+ stderr += data.toString();
230
+ });
231
+ child.on("exit", (code) => {
232
+ if (code === 0) {
233
+ resolve();
234
+ }
235
+ else {
236
+ // Provide helpful error message for common issues
237
+ let errorMsg = `Sandbox init failed with code ${code}: ${stderr}`;
238
+ if (stderr.includes("file descriptor limit")) {
239
+ errorMsg +=
240
+ "\n\n" +
241
+ "The sandbox requires at least 65,535 file descriptors.\n" +
242
+ "Current limit can be checked with: ulimit -n\n\n" +
243
+ "To fix on Linux, add to /etc/security/limits.conf:\n" +
244
+ " * soft nofile 65535\n" +
245
+ " * hard nofile 65535\n\n" +
246
+ "To fix on macOS:\n" +
247
+ " sudo launchctl limit maxfiles 65536 200000\n\n" +
248
+ "For Docker, add: --ulimit nofile=65535:65535\n\n" +
249
+ "See: https://github.com/r-near/near-kit/blob/main/src/sandbox/README.md";
250
+ }
251
+ reject(new Error(errorMsg));
252
+ }
253
+ });
254
+ child.on("error", reject);
255
+ });
256
+ }
257
+ /**
258
+ * Load validator key from sandbox home directory.
259
+ * @internal
260
+ */
261
+ async function loadValidatorKey(homeDir) {
262
+ const keyPath = path.join(homeDir, "validator_key.json");
263
+ try {
264
+ const data = await readFile(keyPath, "utf8");
265
+ return JSON.parse(data);
266
+ }
267
+ catch (error) {
268
+ throw new Error(`Failed to read validator key from ${keyPath}: ${error}`);
269
+ }
270
+ }
271
+ /**
272
+ * Find an available port by letting the OS choose.
273
+ * @internal
274
+ */
275
+ async function findAvailablePort() {
276
+ return new Promise((resolve, reject) => {
277
+ const server = createServer();
278
+ server.on("error", reject);
279
+ server.listen(0, "127.0.0.1", () => {
280
+ const address = server.address();
281
+ if (!address || typeof address === "string") {
282
+ reject(new Error("Failed to get port"));
283
+ return;
284
+ }
285
+ const port = address.port;
286
+ server.close(() => {
287
+ resolve(port);
288
+ });
289
+ });
290
+ });
291
+ }
292
+ /**
293
+ * Ping sandbox RPC endpoint to check if it's ready.
294
+ * @internal
295
+ */
296
+ async function pingRpc(url, timeoutMs = 1000) {
297
+ const controller = new AbortController();
298
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
299
+ try {
300
+ const response = await fetch(url, {
301
+ method: "POST",
302
+ headers: { "Content-Type": "application/json" },
303
+ body: JSON.stringify({
304
+ jsonrpc: "2.0",
305
+ id: "status",
306
+ method: "status",
307
+ params: [],
308
+ }),
309
+ signal: controller.signal,
310
+ });
311
+ return response.ok;
312
+ }
313
+ catch {
314
+ return false;
315
+ }
316
+ finally {
317
+ clearTimeout(timeout);
318
+ }
319
+ }
320
+ /**
321
+ * Wait for sandbox to be ready.
322
+ * @internal
323
+ */
324
+ async function waitForReady(rpcUrl, timeout = STARTUP_TIMEOUT) {
325
+ const start = Date.now();
326
+ while (Date.now() - start < timeout) {
327
+ if (await pingRpc(rpcUrl)) {
328
+ return;
329
+ }
330
+ await sleep(500);
331
+ }
332
+ throw new Error(`Sandbox failed to start within ${timeout}ms`);
333
+ }
334
+ /**
335
+ * Sleep helper.
336
+ * @internal
337
+ */
338
+ function sleep(ms) {
339
+ return new Promise((resolve) => setTimeout(resolve, ms));
340
+ }
341
+ //# sourceMappingURL=sandbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../../src/sandbox/sandbox.ts"],"names":[],"mappings":"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"}