@agirails/sdk 2.5.3 → 2.5.4

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 (166) hide show
  1. package/dist/ACTPClient.d.ts +18 -0
  2. package/dist/ACTPClient.d.ts.map +1 -1
  3. package/dist/ACTPClient.js +67 -22
  4. package/dist/ACTPClient.js.map +1 -1
  5. package/dist/adapters/BasicAdapter.d.ts +12 -0
  6. package/dist/adapters/BasicAdapter.d.ts.map +1 -1
  7. package/dist/adapters/BasicAdapter.js +30 -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 +45 -11
  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 +2 -2
  20. package/dist/config/networks.d.ts.map +1 -1
  21. package/dist/config/networks.js +27 -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.map +1 -1
  34. package/dist/wallet/AutoWalletProvider.js +52 -18
  35. package/dist/wallet/AutoWalletProvider.js.map +1 -1
  36. package/dist/wallet/SmartWalletRouter.d.ts +116 -0
  37. package/dist/wallet/SmartWalletRouter.d.ts.map +1 -0
  38. package/dist/wallet/SmartWalletRouter.js +212 -0
  39. package/dist/wallet/SmartWalletRouter.js.map +1 -0
  40. package/dist/wallet/aa/DualNonceManager.d.ts +19 -0
  41. package/dist/wallet/aa/DualNonceManager.d.ts.map +1 -1
  42. package/dist/wallet/aa/DualNonceManager.js +100 -5
  43. package/dist/wallet/aa/DualNonceManager.js.map +1 -1
  44. package/package.json +3 -6
  45. package/src/ACTPClient.ts +0 -1579
  46. package/src/abi/ACTPKernel.json +0 -1356
  47. package/src/abi/AgentRegistry.json +0 -915
  48. package/src/abi/ERC20.json +0 -40
  49. package/src/abi/EscrowVault.json +0 -134
  50. package/src/abi/IdentityRegistry.json +0 -316
  51. package/src/adapters/AdapterRegistry.ts +0 -173
  52. package/src/adapters/AdapterRouter.ts +0 -416
  53. package/src/adapters/BaseAdapter.ts +0 -498
  54. package/src/adapters/BasicAdapter.ts +0 -514
  55. package/src/adapters/IAdapter.ts +0 -292
  56. package/src/adapters/StandardAdapter.ts +0 -555
  57. package/src/adapters/X402Adapter.ts +0 -731
  58. package/src/adapters/index.ts +0 -60
  59. package/src/builders/DeliveryProofBuilder.ts +0 -327
  60. package/src/builders/QuoteBuilder.ts +0 -483
  61. package/src/builders/index.ts +0 -17
  62. package/src/cli/commands/balance.ts +0 -110
  63. package/src/cli/commands/batch.ts +0 -487
  64. package/src/cli/commands/config.ts +0 -231
  65. package/src/cli/commands/deploy-check.ts +0 -364
  66. package/src/cli/commands/deploy-env.ts +0 -120
  67. package/src/cli/commands/diff.ts +0 -141
  68. package/src/cli/commands/init.ts +0 -469
  69. package/src/cli/commands/mint.ts +0 -116
  70. package/src/cli/commands/pay.ts +0 -113
  71. package/src/cli/commands/publish.ts +0 -475
  72. package/src/cli/commands/pull.ts +0 -124
  73. package/src/cli/commands/register.ts +0 -247
  74. package/src/cli/commands/simulate.ts +0 -345
  75. package/src/cli/commands/time.ts +0 -302
  76. package/src/cli/commands/tx.ts +0 -448
  77. package/src/cli/commands/watch.ts +0 -211
  78. package/src/cli/index.ts +0 -134
  79. package/src/cli/utils/client.ts +0 -252
  80. package/src/cli/utils/config.ts +0 -389
  81. package/src/cli/utils/output.ts +0 -465
  82. package/src/cli/utils/wallet.ts +0 -109
  83. package/src/config/agirailsmd.ts +0 -262
  84. package/src/config/networks.ts +0 -275
  85. package/src/config/pendingPublish.ts +0 -237
  86. package/src/config/publishPipeline.ts +0 -359
  87. package/src/config/syncOperations.ts +0 -279
  88. package/src/erc8004/ERC8004Bridge.ts +0 -462
  89. package/src/erc8004/ReputationReporter.ts +0 -468
  90. package/src/erc8004/index.ts +0 -61
  91. package/src/errors/index.ts +0 -427
  92. package/src/index.ts +0 -364
  93. package/src/level0/Provider.ts +0 -117
  94. package/src/level0/ServiceDirectory.ts +0 -131
  95. package/src/level0/index.ts +0 -10
  96. package/src/level0/provide.ts +0 -132
  97. package/src/level0/request.ts +0 -432
  98. package/src/level1/Agent.ts +0 -1426
  99. package/src/level1/index.ts +0 -10
  100. package/src/level1/pricing/PriceCalculator.ts +0 -255
  101. package/src/level1/pricing/PricingStrategy.ts +0 -198
  102. package/src/level1/types/Job.ts +0 -179
  103. package/src/level1/types/Options.ts +0 -291
  104. package/src/level1/types/index.ts +0 -8
  105. package/src/protocol/ACTPKernel.ts +0 -808
  106. package/src/protocol/AgentRegistry.ts +0 -559
  107. package/src/protocol/DIDManager.ts +0 -629
  108. package/src/protocol/DIDResolver.ts +0 -554
  109. package/src/protocol/EASHelper.ts +0 -378
  110. package/src/protocol/EscrowVault.ts +0 -255
  111. package/src/protocol/EventMonitor.ts +0 -204
  112. package/src/protocol/MessageSigner.ts +0 -510
  113. package/src/protocol/ProofGenerator.ts +0 -339
  114. package/src/protocol/QuoteBuilder.ts +0 -15
  115. package/src/registry/AgentRegistryClient.ts +0 -202
  116. package/src/runtime/BlockchainRuntime.ts +0 -1015
  117. package/src/runtime/IACTPRuntime.ts +0 -306
  118. package/src/runtime/MockRuntime.ts +0 -1298
  119. package/src/runtime/MockStateManager.ts +0 -577
  120. package/src/runtime/index.ts +0 -25
  121. package/src/runtime/types/MockState.ts +0 -237
  122. package/src/storage/ArchiveBundleBuilder.ts +0 -561
  123. package/src/storage/ArweaveClient.ts +0 -946
  124. package/src/storage/FilebaseClient.ts +0 -790
  125. package/src/storage/index.ts +0 -96
  126. package/src/storage/types.ts +0 -348
  127. package/src/types/adapter.ts +0 -310
  128. package/src/types/agent.ts +0 -79
  129. package/src/types/did.ts +0 -223
  130. package/src/types/eip712.ts +0 -175
  131. package/src/types/erc8004.ts +0 -293
  132. package/src/types/escrow.ts +0 -27
  133. package/src/types/index.ts +0 -17
  134. package/src/types/message.ts +0 -145
  135. package/src/types/state.ts +0 -87
  136. package/src/types/transaction.ts +0 -69
  137. package/src/types/x402.ts +0 -251
  138. package/src/utils/ErrorRecoveryGuide.ts +0 -676
  139. package/src/utils/Helpers.ts +0 -688
  140. package/src/utils/IPFSClient.ts +0 -368
  141. package/src/utils/Logger.ts +0 -484
  142. package/src/utils/NonceManager.ts +0 -591
  143. package/src/utils/RateLimiter.ts +0 -534
  144. package/src/utils/ReceivedNonceTracker.ts +0 -567
  145. package/src/utils/SDKLifecycle.ts +0 -416
  146. package/src/utils/SecureNonce.ts +0 -78
  147. package/src/utils/Semaphore.ts +0 -276
  148. package/src/utils/UsedAttestationTracker.ts +0 -385
  149. package/src/utils/canonicalJson.ts +0 -38
  150. package/src/utils/circuitBreaker.ts +0 -324
  151. package/src/utils/computeTypeHash.ts +0 -48
  152. package/src/utils/fsSafe.ts +0 -80
  153. package/src/utils/index.ts +0 -80
  154. package/src/utils/retry.ts +0 -364
  155. package/src/utils/security.ts +0 -418
  156. package/src/utils/validation.ts +0 -540
  157. package/src/wallet/AutoWalletProvider.ts +0 -299
  158. package/src/wallet/EOAWalletProvider.ts +0 -69
  159. package/src/wallet/IWalletProvider.ts +0 -135
  160. package/src/wallet/aa/BundlerClient.ts +0 -274
  161. package/src/wallet/aa/DualNonceManager.ts +0 -173
  162. package/src/wallet/aa/PaymasterClient.ts +0 -174
  163. package/src/wallet/aa/TransactionBatcher.ts +0 -353
  164. package/src/wallet/aa/UserOpBuilder.ts +0 -246
  165. package/src/wallet/aa/constants.ts +0 -60
  166. 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';