@agirails/sdk 2.5.3 → 2.5.5

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 (169) hide show
  1. package/dist/ACTPClient.d.ts +18 -0
  2. package/dist/ACTPClient.d.ts.map +1 -1
  3. package/dist/ACTPClient.js +72 -23
  4. package/dist/ACTPClient.js.map +1 -1
  5. package/dist/adapters/BasicAdapter.d.ts +15 -0
  6. package/dist/adapters/BasicAdapter.d.ts.map +1 -1
  7. package/dist/adapters/BasicAdapter.js +33 -4
  8. package/dist/adapters/BasicAdapter.js.map +1 -1
  9. package/dist/adapters/StandardAdapter.d.ts +20 -3
  10. package/dist/adapters/StandardAdapter.d.ts.map +1 -1
  11. package/dist/adapters/StandardAdapter.js +90 -12
  12. package/dist/adapters/StandardAdapter.js.map +1 -1
  13. package/dist/cli/commands/publish.js +16 -4
  14. package/dist/cli/commands/publish.js.map +1 -1
  15. package/dist/cli/commands/register.js +16 -4
  16. package/dist/cli/commands/register.js.map +1 -1
  17. package/dist/cli/commands/tx.js +31 -3
  18. package/dist/cli/commands/tx.js.map +1 -1
  19. package/dist/config/networks.d.ts +10 -2
  20. package/dist/config/networks.d.ts.map +1 -1
  21. package/dist/config/networks.js +31 -22
  22. package/dist/config/networks.js.map +1 -1
  23. package/dist/level0/request.d.ts.map +1 -1
  24. package/dist/level0/request.js +2 -1
  25. package/dist/level0/request.js.map +1 -1
  26. package/dist/runtime/BlockchainRuntime.d.ts.map +1 -1
  27. package/dist/runtime/BlockchainRuntime.js +11 -5
  28. package/dist/runtime/BlockchainRuntime.js.map +1 -1
  29. package/dist/utils/IPFSClient.d.ts +3 -1
  30. package/dist/utils/IPFSClient.d.ts.map +1 -1
  31. package/dist/utils/IPFSClient.js +27 -7
  32. package/dist/utils/IPFSClient.js.map +1 -1
  33. package/dist/wallet/AutoWalletProvider.d.ts +11 -1
  34. package/dist/wallet/AutoWalletProvider.d.ts.map +1 -1
  35. package/dist/wallet/AutoWalletProvider.js +84 -19
  36. package/dist/wallet/AutoWalletProvider.js.map +1 -1
  37. package/dist/wallet/IWalletProvider.d.ts +34 -0
  38. package/dist/wallet/IWalletProvider.d.ts.map +1 -1
  39. package/dist/wallet/SmartWalletRouter.d.ts +128 -0
  40. package/dist/wallet/SmartWalletRouter.d.ts.map +1 -0
  41. package/dist/wallet/SmartWalletRouter.js +248 -0
  42. package/dist/wallet/SmartWalletRouter.js.map +1 -0
  43. package/dist/wallet/aa/DualNonceManager.d.ts +26 -1
  44. package/dist/wallet/aa/DualNonceManager.d.ts.map +1 -1
  45. package/dist/wallet/aa/DualNonceManager.js +140 -6
  46. package/dist/wallet/aa/DualNonceManager.js.map +1 -1
  47. package/package.json +3 -6
  48. package/src/ACTPClient.ts +0 -1579
  49. package/src/abi/ACTPKernel.json +0 -1356
  50. package/src/abi/AgentRegistry.json +0 -915
  51. package/src/abi/ERC20.json +0 -40
  52. package/src/abi/EscrowVault.json +0 -134
  53. package/src/abi/IdentityRegistry.json +0 -316
  54. package/src/adapters/AdapterRegistry.ts +0 -173
  55. package/src/adapters/AdapterRouter.ts +0 -416
  56. package/src/adapters/BaseAdapter.ts +0 -498
  57. package/src/adapters/BasicAdapter.ts +0 -514
  58. package/src/adapters/IAdapter.ts +0 -292
  59. package/src/adapters/StandardAdapter.ts +0 -555
  60. package/src/adapters/X402Adapter.ts +0 -731
  61. package/src/adapters/index.ts +0 -60
  62. package/src/builders/DeliveryProofBuilder.ts +0 -327
  63. package/src/builders/QuoteBuilder.ts +0 -483
  64. package/src/builders/index.ts +0 -17
  65. package/src/cli/commands/balance.ts +0 -110
  66. package/src/cli/commands/batch.ts +0 -487
  67. package/src/cli/commands/config.ts +0 -231
  68. package/src/cli/commands/deploy-check.ts +0 -364
  69. package/src/cli/commands/deploy-env.ts +0 -120
  70. package/src/cli/commands/diff.ts +0 -141
  71. package/src/cli/commands/init.ts +0 -469
  72. package/src/cli/commands/mint.ts +0 -116
  73. package/src/cli/commands/pay.ts +0 -113
  74. package/src/cli/commands/publish.ts +0 -475
  75. package/src/cli/commands/pull.ts +0 -124
  76. package/src/cli/commands/register.ts +0 -247
  77. package/src/cli/commands/simulate.ts +0 -345
  78. package/src/cli/commands/time.ts +0 -302
  79. package/src/cli/commands/tx.ts +0 -448
  80. package/src/cli/commands/watch.ts +0 -211
  81. package/src/cli/index.ts +0 -134
  82. package/src/cli/utils/client.ts +0 -252
  83. package/src/cli/utils/config.ts +0 -389
  84. package/src/cli/utils/output.ts +0 -465
  85. package/src/cli/utils/wallet.ts +0 -109
  86. package/src/config/agirailsmd.ts +0 -262
  87. package/src/config/networks.ts +0 -275
  88. package/src/config/pendingPublish.ts +0 -237
  89. package/src/config/publishPipeline.ts +0 -359
  90. package/src/config/syncOperations.ts +0 -279
  91. package/src/erc8004/ERC8004Bridge.ts +0 -462
  92. package/src/erc8004/ReputationReporter.ts +0 -468
  93. package/src/erc8004/index.ts +0 -61
  94. package/src/errors/index.ts +0 -427
  95. package/src/index.ts +0 -364
  96. package/src/level0/Provider.ts +0 -117
  97. package/src/level0/ServiceDirectory.ts +0 -131
  98. package/src/level0/index.ts +0 -10
  99. package/src/level0/provide.ts +0 -132
  100. package/src/level0/request.ts +0 -432
  101. package/src/level1/Agent.ts +0 -1426
  102. package/src/level1/index.ts +0 -10
  103. package/src/level1/pricing/PriceCalculator.ts +0 -255
  104. package/src/level1/pricing/PricingStrategy.ts +0 -198
  105. package/src/level1/types/Job.ts +0 -179
  106. package/src/level1/types/Options.ts +0 -291
  107. package/src/level1/types/index.ts +0 -8
  108. package/src/protocol/ACTPKernel.ts +0 -808
  109. package/src/protocol/AgentRegistry.ts +0 -559
  110. package/src/protocol/DIDManager.ts +0 -629
  111. package/src/protocol/DIDResolver.ts +0 -554
  112. package/src/protocol/EASHelper.ts +0 -378
  113. package/src/protocol/EscrowVault.ts +0 -255
  114. package/src/protocol/EventMonitor.ts +0 -204
  115. package/src/protocol/MessageSigner.ts +0 -510
  116. package/src/protocol/ProofGenerator.ts +0 -339
  117. package/src/protocol/QuoteBuilder.ts +0 -15
  118. package/src/registry/AgentRegistryClient.ts +0 -202
  119. package/src/runtime/BlockchainRuntime.ts +0 -1015
  120. package/src/runtime/IACTPRuntime.ts +0 -306
  121. package/src/runtime/MockRuntime.ts +0 -1298
  122. package/src/runtime/MockStateManager.ts +0 -577
  123. package/src/runtime/index.ts +0 -25
  124. package/src/runtime/types/MockState.ts +0 -237
  125. package/src/storage/ArchiveBundleBuilder.ts +0 -561
  126. package/src/storage/ArweaveClient.ts +0 -946
  127. package/src/storage/FilebaseClient.ts +0 -790
  128. package/src/storage/index.ts +0 -96
  129. package/src/storage/types.ts +0 -348
  130. package/src/types/adapter.ts +0 -310
  131. package/src/types/agent.ts +0 -79
  132. package/src/types/did.ts +0 -223
  133. package/src/types/eip712.ts +0 -175
  134. package/src/types/erc8004.ts +0 -293
  135. package/src/types/escrow.ts +0 -27
  136. package/src/types/index.ts +0 -17
  137. package/src/types/message.ts +0 -145
  138. package/src/types/state.ts +0 -87
  139. package/src/types/transaction.ts +0 -69
  140. package/src/types/x402.ts +0 -251
  141. package/src/utils/ErrorRecoveryGuide.ts +0 -676
  142. package/src/utils/Helpers.ts +0 -688
  143. package/src/utils/IPFSClient.ts +0 -368
  144. package/src/utils/Logger.ts +0 -484
  145. package/src/utils/NonceManager.ts +0 -591
  146. package/src/utils/RateLimiter.ts +0 -534
  147. package/src/utils/ReceivedNonceTracker.ts +0 -567
  148. package/src/utils/SDKLifecycle.ts +0 -416
  149. package/src/utils/SecureNonce.ts +0 -78
  150. package/src/utils/Semaphore.ts +0 -276
  151. package/src/utils/UsedAttestationTracker.ts +0 -385
  152. package/src/utils/canonicalJson.ts +0 -38
  153. package/src/utils/circuitBreaker.ts +0 -324
  154. package/src/utils/computeTypeHash.ts +0 -48
  155. package/src/utils/fsSafe.ts +0 -80
  156. package/src/utils/index.ts +0 -80
  157. package/src/utils/retry.ts +0 -364
  158. package/src/utils/security.ts +0 -418
  159. package/src/utils/validation.ts +0 -540
  160. package/src/wallet/AutoWalletProvider.ts +0 -299
  161. package/src/wallet/EOAWalletProvider.ts +0 -69
  162. package/src/wallet/IWalletProvider.ts +0 -135
  163. package/src/wallet/aa/BundlerClient.ts +0 -274
  164. package/src/wallet/aa/DualNonceManager.ts +0 -173
  165. package/src/wallet/aa/PaymasterClient.ts +0 -174
  166. package/src/wallet/aa/TransactionBatcher.ts +0 -353
  167. package/src/wallet/aa/UserOpBuilder.ts +0 -246
  168. package/src/wallet/aa/constants.ts +0 -60
  169. package/src/wallet/keystore.ts +0 -240
@@ -1,577 +0,0 @@
1
- /**
2
- * MockStateManager - Persistent state management for Mock Mode
3
- *
4
- * Responsible for persisting mock blockchain state to disk, enabling
5
- * state sharing across CLI commands, SDK library usage, and Dashboard.
6
- *
7
- * Features:
8
- * - File-based JSON persistence in `.actp/mock-state.json`
9
- * - Atomic file operations (write to temp file, then rename)
10
- * - File locking to prevent concurrent access corruption
11
- * - Error recovery for corrupted state files
12
- *
13
- * @module runtime/MockStateManager
14
- * @see ADR-001 (Mock State Persistence Strategy)
15
- * @see MOCK_STATE_MANAGER_SPEC.md
16
- */
17
-
18
- import * as fs from 'fs';
19
- import * as path from 'path';
20
- import lockfile from 'proper-lockfile';
21
- import { MockState, MOCK_STATE_DEFAULTS } from './types/MockState';
22
- import { assertSafeFileForRead, ensureSafeDir } from '../utils/fsSafe';
23
-
24
- /**
25
- * Error thrown when mock state file is corrupted.
26
- */
27
- export class MockStateCorruptedError extends Error {
28
- public readonly statePath: string;
29
-
30
- constructor(statePath: string, cause?: Error) {
31
- super(
32
- `Mock state file corrupted: ${statePath}\n` +
33
- `Delete it manually or run: actp mock reset\n` +
34
- (cause ? `Cause: ${cause.message}` : '')
35
- );
36
- this.name = 'MockStateCorruptedError';
37
- this.statePath = statePath;
38
- }
39
- }
40
-
41
- /**
42
- * Error thrown when state version is unsupported.
43
- */
44
- export class MockStateVersionError extends Error {
45
- public readonly version: string;
46
- public readonly supportedVersion: string;
47
-
48
- constructor(version: string, supportedVersion: string = MOCK_STATE_DEFAULTS.VERSION) {
49
- super(
50
- `Unsupported state version: ${version}\n` +
51
- `Supported version: ${supportedVersion}\n` +
52
- `Run: actp mock reset to create new state file`
53
- );
54
- this.name = 'MockStateVersionError';
55
- this.version = version;
56
- this.supportedVersion = supportedVersion;
57
- }
58
- }
59
-
60
- /**
61
- * Error thrown when lock cannot be acquired.
62
- */
63
- export class MockStateLockError extends Error {
64
- public readonly statePath: string;
65
- public readonly cause?: Error;
66
-
67
- constructor(statePath: string, cause?: Error) {
68
- super(
69
- `Could not acquire lock on mock state: ${statePath}\n` +
70
- `Another ACTP process may be running.\n` +
71
- `Please wait a moment and try again.` +
72
- (cause ? `\nCause: ${cause.message}` : '')
73
- );
74
- this.name = 'MockStateLockError';
75
- this.statePath = statePath;
76
- this.cause = cause;
77
- }
78
- }
79
-
80
- /**
81
- * Lock options for proper-lockfile.
82
- * - 5 retries with exponential backoff (100ms -> 1000ms)
83
- * - 10 second stale lock detection (handles process crashes)
84
- */
85
- const LOCK_OPTIONS: lockfile.LockOptions = {
86
- retries: {
87
- retries: 5,
88
- minTimeout: 100,
89
- maxTimeout: 1000,
90
- },
91
- stale: 10000, // 10 seconds
92
- };
93
-
94
- /**
95
- * Maximum allowed state file size (10 MB).
96
- * Prevents disk exhaustion from runaway state growth.
97
- *
98
- * Note: For states approaching this limit, JSON.stringify/parse may
99
- * temporarily use ~3x the file size in memory (~30 MB for 10 MB state).
100
- * This is acceptable for a local development tool with <1000 transactions.
101
- */
102
- const MAX_STATE_FILE_SIZE = 10 * 1024 * 1024;
103
-
104
- /**
105
- * Maximum nesting depth for JSON parsing.
106
- * Prevents DoS attacks via deeply nested JSON structures.
107
- *
108
- * SECURITY: Deeply nested JSON can cause:
109
- * - Stack overflow during parsing
110
- * - Excessive CPU usage during traversal
111
- * - Memory exhaustion from recursion
112
- */
113
- const MAX_NESTING_DEPTH = 100;
114
-
115
- // ============================================================================
116
- // Security: Path Sanitization and JSON Depth Check
117
- // ============================================================================
118
-
119
- /**
120
- * Sanitize a file path for safe display in error messages.
121
- *
122
- * SECURITY: Replaces home directory with ~ to prevent information disclosure.
123
- *
124
- * @param fullPath - The full file path to sanitize
125
- * @returns Sanitized path safe for display
126
- */
127
- function sanitizePath(fullPath: string): string {
128
- // Import os dynamically to get home directory
129
- const home = process.env.HOME || process.env.USERPROFILE || '/';
130
- return fullPath.replace(home, '~');
131
- }
132
-
133
- /**
134
- * Check the nesting depth of a parsed JSON object.
135
- *
136
- * SECURITY: Prevents DoS via deeply nested JSON structures that can cause:
137
- * - Stack overflow
138
- * - Excessive CPU usage
139
- * - Memory exhaustion
140
- *
141
- * @param obj - The object to check
142
- * @param maxDepth - Maximum allowed nesting depth
143
- * @param currentDepth - Current depth (used for recursion)
144
- * @throws Error if object exceeds maximum nesting depth
145
- */
146
- function checkNestingDepth(
147
- obj: unknown,
148
- maxDepth: number = MAX_NESTING_DEPTH,
149
- currentDepth: number = 0
150
- ): void {
151
- if (currentDepth > maxDepth) {
152
- throw new Error(
153
- `State file exceeds maximum nesting depth of ${maxDepth}. ` +
154
- 'This may indicate a corrupted or malicious state file.'
155
- );
156
- }
157
-
158
- if (obj !== null && typeof obj === 'object') {
159
- // Check arrays and objects
160
- const values = Array.isArray(obj) ? obj : Object.values(obj);
161
- for (const value of values) {
162
- checkNestingDepth(value, maxDepth, currentDepth + 1);
163
- }
164
- }
165
- }
166
-
167
- /**
168
- * MockStateManager handles persistence of mock blockchain state.
169
- *
170
- * State is stored in `.actp/mock-state.json` within the project root.
171
- * Uses file locking to prevent corruption from concurrent access.
172
- *
173
- * @example
174
- * ```typescript
175
- * const manager = new MockStateManager();
176
- *
177
- * // Read-only access (no lock)
178
- * const state = manager.loadState();
179
- * console.log('Transactions:', Object.keys(state.transactions).length);
180
- *
181
- * // Read-modify-write with lock
182
- * const txId = await manager.withLock(async (state) => {
183
- * const txId = generateId();
184
- * state.transactions[txId] = { ... };
185
- * return txId;
186
- * });
187
- * ```
188
- */
189
- export class MockStateManager {
190
- /** Path to the state JSON file */
191
- private readonly statePath: string;
192
-
193
- /** Path to the .actp directory */
194
- private readonly actpDir: string;
195
-
196
- /**
197
- * Creates a new MockStateManager instance.
198
- *
199
- * @param projectRoot - Root directory for `.actp/` folder.
200
- * Defaults to current working directory.
201
- *
202
- * @example
203
- * ```typescript
204
- * // Use current directory
205
- * const manager = new MockStateManager();
206
- *
207
- * // Use specific project root
208
- * const manager = new MockStateManager('/path/to/project');
209
- * ```
210
- */
211
- constructor(projectRoot: string = process.cwd()) {
212
- this.actpDir = path.join(projectRoot, '.actp');
213
- this.statePath = path.join(this.actpDir, 'mock-state.json');
214
-
215
- // Ensure .actp directory exists
216
- this.ensureDirectory();
217
- }
218
-
219
- /**
220
- * Ensures the .actp directory exists.
221
- * Creates it with secure permissions if missing.
222
- */
223
- private ensureDirectory(): void {
224
- ensureSafeDir(this.actpDir, 0o755);
225
- }
226
-
227
- /**
228
- * Loads state from disk.
229
- *
230
- * Returns default state if file doesn't exist (first run).
231
- * Validates version compatibility and file size limits.
232
- *
233
- * SECURITY: Validates nesting depth to prevent DoS attacks.
234
- *
235
- * @returns The current mock state
236
- *
237
- * @throws {MockStateCorruptedError} If state file contains invalid JSON
238
- * @throws {MockStateVersionError} If state version is not supported
239
- * @throws {Error} If file exceeds size limit or other I/O errors
240
- *
241
- * @example
242
- * ```typescript
243
- * const state = manager.loadState();
244
- * console.log('Current time:', state.blockchain.currentTime);
245
- * ```
246
- */
247
- loadState(): MockState {
248
- // If file doesn't exist, return default state
249
- if (!fs.existsSync(this.statePath)) {
250
- return this.getDefaultState();
251
- }
252
-
253
- // SECURITY: Refuse to read from symlinked state files
254
- assertSafeFileForRead(this.statePath);
255
-
256
- // Check file size limit
257
- const stats = fs.statSync(this.statePath);
258
- if (stats.size > MAX_STATE_FILE_SIZE) {
259
- throw new Error(
260
- `Mock state file exceeds ${MAX_STATE_FILE_SIZE / 1024 / 1024} MB limit.\n` +
261
- `Run: actp mock compact or actp mock reset`
262
- );
263
- }
264
-
265
- // Read and parse file
266
- let raw: string;
267
- try {
268
- raw = fs.readFileSync(this.statePath, 'utf-8');
269
- } catch (error) {
270
- // SECURITY: Sanitize path in error message
271
- throw new Error(
272
- `Failed to read mock state file: ${sanitizePath(this.statePath)}\n` +
273
- `Error: ${(error as Error).message}`
274
- );
275
- }
276
-
277
- // Parse JSON
278
- let state: MockState;
279
- try {
280
- state = JSON.parse(raw);
281
- } catch (error) {
282
- // SECURITY: Sanitize path in error message
283
- throw new MockStateCorruptedError(sanitizePath(this.statePath), error as Error);
284
- }
285
-
286
- // SECURITY FIX: Check nesting depth to prevent DoS via deeply nested JSON
287
- try {
288
- checkNestingDepth(state);
289
- } catch (error) {
290
- throw new MockStateCorruptedError(
291
- sanitizePath(this.statePath),
292
- error as Error
293
- );
294
- }
295
-
296
- // Validate version
297
- if (state.version !== MOCK_STATE_DEFAULTS.VERSION) {
298
- throw new MockStateVersionError(state.version);
299
- }
300
-
301
- // Basic schema validation
302
- if (
303
- typeof state.mode !== 'string' ||
304
- typeof state.blockchain !== 'object' ||
305
- typeof state.transactions !== 'object' ||
306
- typeof state.escrows !== 'object' ||
307
- typeof state.accounts !== 'object'
308
- ) {
309
- throw new MockStateCorruptedError(sanitizePath(this.statePath));
310
- }
311
-
312
- return state;
313
- }
314
-
315
- /**
316
- * Saves state to disk atomically.
317
- *
318
- * Uses write-to-temp-then-rename pattern to ensure atomicity:
319
- * 1. Write state to `.tmp` file
320
- * 2. Rename `.tmp` to final path (atomic on POSIX)
321
- *
322
- * This prevents corruption if process crashes during write.
323
- *
324
- * @param state - The state to save
325
- *
326
- * @throws {Error} If write fails (disk full, permissions, etc.)
327
- *
328
- * @example
329
- * ```typescript
330
- * const state = manager.loadState();
331
- * state.blockchain.currentTime += 3600; // Advance 1 hour
332
- * manager.saveState(state);
333
- * ```
334
- */
335
- saveState(state: MockState): void {
336
- // Ensure directory exists (may have been deleted)
337
- this.ensureDirectory();
338
-
339
- const tempPath = `${this.statePath}.tmp`;
340
-
341
- try {
342
- // Prevent clobbering via pre-created temp symlink/file
343
- if (fs.existsSync(tempPath)) {
344
- fs.unlinkSync(tempPath);
345
- }
346
-
347
- // Write to temp file first (pretty-printed for human readability)
348
- // BigInt replacer: ethers v6 returns BigInt from contracts; JSON.stringify can't handle them natively
349
- const json = JSON.stringify(state, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2);
350
- fs.writeFileSync(tempPath, json, {
351
- encoding: 'utf-8',
352
- mode: 0o644,
353
- flag: 'wx', // exclusive create: do not follow existing symlink
354
- });
355
-
356
- // Rename atomically (POSIX rename is atomic)
357
- fs.renameSync(tempPath, this.statePath);
358
- } catch (error) {
359
- // Clean up temp file if it exists
360
- if (fs.existsSync(tempPath)) {
361
- try {
362
- fs.unlinkSync(tempPath);
363
- } catch {
364
- // Ignore cleanup errors
365
- }
366
- }
367
-
368
- throw new Error(
369
- `Failed to save mock state: ${(error as Error).message}\n` +
370
- `Path: ${sanitizePath(this.statePath)}`
371
- );
372
- }
373
- }
374
-
375
- /**
376
- * Executes an operation with exclusive file lock.
377
- *
378
- * Provides read-modify-write semantics with concurrency protection:
379
- * 1. Acquires exclusive lock on state file
380
- * 2. Loads current state
381
- * 3. Executes operation (may modify state)
382
- * 4. Saves updated state
383
- * 5. Releases lock
384
- *
385
- * Lock is always released, even if operation throws.
386
- *
387
- * @typeParam T - Return type of the operation
388
- * @param operation - Function that receives state and returns result.
389
- * Can be sync or async. May modify state object.
390
- *
391
- * @returns Promise resolving to operation's return value
392
- *
393
- * @throws {MockStateLockError} If lock cannot be acquired after retries
394
- * @throws {Error} If operation throws or save fails
395
- *
396
- * @example
397
- * ```typescript
398
- * // Create transaction with lock
399
- * const txId = await manager.withLock(async (state) => {
400
- * const txId = '0x' + crypto.randomBytes(32).toString('hex');
401
- * state.transactions[txId] = {
402
- * id: txId,
403
- * state: 'INITIATED',
404
- * // ...
405
- * };
406
- * return txId;
407
- * });
408
- * ```
409
- */
410
- async withLock<T>(operation: (state: MockState) => T | Promise<T>): Promise<T> {
411
- // Ensure state file exists before locking
412
- // (proper-lockfile requires the file to exist)
413
- if (!fs.existsSync(this.statePath)) {
414
- this.saveState(this.getDefaultState());
415
- }
416
-
417
- // SECURITY: Refuse to lock/use symlinked state files
418
- assertSafeFileForRead(this.statePath);
419
-
420
- let release: (() => Promise<void>) | null = null;
421
-
422
- try {
423
- // Acquire exclusive lock
424
- release = await lockfile.lock(this.statePath, LOCK_OPTIONS);
425
-
426
- // Load current state
427
- const state = this.loadState();
428
-
429
- // Execute operation (may be async)
430
- const result = await operation(state);
431
-
432
- // Save modified state
433
- this.saveState(state);
434
-
435
- return result;
436
- } catch (error) {
437
- // Transform lock errors into friendlier messages
438
- if (
439
- error instanceof Error &&
440
- (error.message.includes('ELOCKED') || error.message.includes('lock'))
441
- ) {
442
- throw new MockStateLockError(this.statePath, error);
443
- }
444
- throw error;
445
- } finally {
446
- // Always release lock
447
- if (release) {
448
- try {
449
- await release();
450
- } catch {
451
- // Ignore release errors (lock may have expired)
452
- }
453
- }
454
- }
455
- }
456
-
457
- /**
458
- * Resets state to default (fresh blockchain).
459
- *
460
- * Useful for starting fresh during testing or after corruption.
461
- * Does not require lock (overwrites entire file).
462
- *
463
- * @example
464
- * ```typescript
465
- * // Reset to clean state
466
- * manager.reset();
467
- *
468
- * // Verify reset
469
- * const state = manager.loadState();
470
- * console.log('Transactions:', Object.keys(state.transactions).length); // 0
471
- * ```
472
- */
473
- reset(): void {
474
- const defaultState = this.getDefaultState();
475
- this.saveState(defaultState);
476
- }
477
-
478
- /**
479
- * Checks if mock mode is initialized (state file exists).
480
- *
481
- * @returns true if state file exists, false otherwise
482
- *
483
- * @example
484
- * ```typescript
485
- * if (!manager.exists()) {
486
- * console.log('Run: actp init to initialize mock mode');
487
- * }
488
- * ```
489
- */
490
- exists(): boolean {
491
- return fs.existsSync(this.statePath);
492
- }
493
-
494
- /**
495
- * Gets the path to the state file.
496
- *
497
- * @returns Absolute path to mock-state.json
498
- */
499
- getStatePath(): string {
500
- return this.statePath;
501
- }
502
-
503
- /**
504
- * Gets the path to the .actp directory.
505
- *
506
- * @returns Absolute path to .actp directory
507
- */
508
- getActpDir(): string {
509
- return this.actpDir;
510
- }
511
-
512
- /**
513
- * Creates default/initial mock state.
514
- *
515
- * Used when state file doesn't exist or after reset.
516
- * Initializes blockchain with current timestamp.
517
- *
518
- * @returns Fresh mock state with empty transactions/escrows/accounts
519
- */
520
- getDefaultState(): MockState {
521
- return {
522
- version: MOCK_STATE_DEFAULTS.VERSION,
523
- mode: 'mock',
524
- blockchain: {
525
- currentTime: Math.floor(Date.now() / 1000),
526
- blockNumber: MOCK_STATE_DEFAULTS.INITIAL_BLOCK_NUMBER,
527
- chainId: MOCK_STATE_DEFAULTS.CHAIN_ID,
528
- blockTime: MOCK_STATE_DEFAULTS.BLOCK_TIME,
529
- },
530
- transactions: {},
531
- escrows: {},
532
- accounts: {},
533
- // SECURITY FIX (L-4): Initialize events array for persistence
534
- events: [],
535
- };
536
- }
537
-
538
- /**
539
- * Deletes the state file and .actp directory if empty.
540
- *
541
- * Used for cleanup during tests or uninitialization.
542
- *
543
- * @param force - If true, delete .actp directory even if not empty
544
- *
545
- * @example
546
- * ```typescript
547
- * // Clean up after tests
548
- * manager.destroy();
549
- * ```
550
- */
551
- destroy(force: boolean = false): void {
552
- // Remove state file
553
- if (fs.existsSync(this.statePath)) {
554
- fs.unlinkSync(this.statePath);
555
- }
556
-
557
- // Remove temp file if exists
558
- const tempPath = `${this.statePath}.tmp`;
559
- if (fs.existsSync(tempPath)) {
560
- fs.unlinkSync(tempPath);
561
- }
562
-
563
- // Remove lock file if exists (created by proper-lockfile)
564
- const lockPath = `${this.statePath}.lock`;
565
- if (fs.existsSync(lockPath)) {
566
- fs.unlinkSync(lockPath);
567
- }
568
-
569
- // Remove .actp directory if empty or forced
570
- if (fs.existsSync(this.actpDir)) {
571
- const files = fs.readdirSync(this.actpDir);
572
- if (files.length === 0 || force) {
573
- fs.rmSync(this.actpDir, { recursive: true, force: true });
574
- }
575
- }
576
- }
577
- }
@@ -1,25 +0,0 @@
1
- /**
2
- * Runtime module exports.
3
- *
4
- * Provides both the runtime interface and concrete implementations.
5
- *
6
- * @module runtime
7
- */
8
-
9
- export { IACTPRuntime, IMockRuntime, CreateTransactionParams } from './IACTPRuntime';
10
- export { MockRuntime } from './MockRuntime';
11
- export { MockStateManager } from './MockStateManager';
12
- export { BlockchainRuntime, BlockchainRuntimeConfig } from './BlockchainRuntime';
13
- export * from './types/MockState';
14
-
15
- // Re-export all custom errors from MockRuntime
16
- export {
17
- TransactionNotFoundError,
18
- InvalidStateTransitionError,
19
- InsufficientBalanceError,
20
- EscrowNotFoundError,
21
- DeadlinePassedError,
22
- ContractPausedError,
23
- InvalidAmountError,
24
- DisputeWindowActiveError,
25
- } from './MockRuntime';