movehat 0.2.6 → 0.2.8

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 (39) hide show
  1. package/dist/cli.js +1 -1
  2. package/dist/commands/fork/fund.js +3 -1
  3. package/dist/commands/fork/serve.js +10 -5
  4. package/dist/commands/test-move.js +6 -3
  5. package/dist/core/AccountManager.d.ts +121 -139
  6. package/dist/core/AccountManager.js +217 -158
  7. package/dist/fork/api.d.ts +1 -1
  8. package/dist/fork/api.js +9 -4
  9. package/dist/fork/manager.d.ts +2 -2
  10. package/dist/fork/manager.js +4 -8
  11. package/dist/fork/storage.js +5 -4
  12. package/dist/fork/test.d.ts +1 -1
  13. package/dist/fork/validation.d.ts +9 -0
  14. package/dist/fork/validation.js +88 -0
  15. package/dist/harness/Harness.d.ts +35 -6
  16. package/dist/harness/Harness.js +36 -5
  17. package/dist/helpers/index.d.ts +1 -0
  18. package/dist/helpers/index.js +1 -0
  19. package/dist/helpers/move-tests.js +8 -5
  20. package/dist/helpers/setup.js +6 -3
  21. package/dist/helpers/setupLocalTesting.d.ts +2 -2
  22. package/dist/helpers/setupLocalTesting.js +55 -24
  23. package/dist/helpers/testFixtures.d.ts +5 -4
  24. package/dist/helpers/testFixtures.js +4 -5
  25. package/dist/helpers/version-check.js +4 -2
  26. package/dist/index.d.ts +3 -1
  27. package/dist/node/MoveliteManager.d.ts +18 -0
  28. package/dist/node/MoveliteManager.js +152 -0
  29. package/dist/node/NodeProvider.d.ts +9 -0
  30. package/dist/node/NodeProvider.js +1 -0
  31. package/dist/runtime.d.ts +13 -0
  32. package/dist/runtime.js +8 -4
  33. package/dist/templates/.mocharc.json +1 -0
  34. package/dist/templates/tests/Counter.test.ts +12 -14
  35. package/dist/templates/tests/setup.ts +34 -0
  36. package/dist/types/config.d.ts +2 -0
  37. package/dist/types/fork.d.ts +24 -0
  38. package/dist/types/runtime.d.ts +2 -0
  39. package/package.json +4 -1
package/dist/cli.js CHANGED
@@ -66,7 +66,7 @@ program
66
66
  });
67
67
  program
68
68
  .command('compile')
69
- .description('Compile Move smart contracts using Movement CLI')
69
+ .description('Compile Move smart contracts (auto-detects named addresses and updates Move.toml)')
70
70
  .action(compileCommand);
71
71
  program
72
72
  .command('run <script>')
@@ -34,9 +34,11 @@ export default async function forkFundCommand(options) {
34
34
  // Verify
35
35
  const resourceType = `0x1::coin::CoinStore<${coinType}>`;
36
36
  const coinStore = await forkManager.getResource(options.account, resourceType);
37
+ const { assertCoinStore } = await import('../../fork/validation.js');
38
+ const validated = assertCoinStore(coinStore);
37
39
  logger.newline();
38
40
  logger.success("Account funded successfully!");
39
- logger.plain(` New balance: ${coinStore.coin.value}`);
41
+ logger.plain(` New balance: ${validated.coin.value}`);
40
42
  logger.newline();
41
43
  }
42
44
  catch (error) {
@@ -2,6 +2,7 @@ import { join } from 'path';
2
2
  import { existsSync } from 'fs';
3
3
  import { loadUserConfig } from '../../core/config.js';
4
4
  import { ForkServer } from '../../fork/server.js';
5
+ import { logger } from '../../ui/index.js';
5
6
  /**
6
7
  * Fork serve command: Start a local RPC server serving the fork
7
8
  */
@@ -26,9 +27,11 @@ export default async function forkServeCommand(options) {
26
27
  }
27
28
  // Verify fork exists
28
29
  if (!existsSync(join(forkPath, 'metadata.json'))) {
29
- console.error(`\nError: Fork not found at ${forkPath}`);
30
- console.error(`\nCreate a fork first with:`);
31
- console.error(` movehat fork create --network <network> --name <name>`);
30
+ logger.newline();
31
+ logger.error(`Fork not found at ${forkPath}`);
32
+ logger.newline();
33
+ logger.error("Create a fork first with:");
34
+ logger.error(" movehat fork create --network <network> --name <name>");
32
35
  process.exit(1);
33
36
  }
34
37
  // Get port (already validated by Commander's parsePort in cli.ts)
@@ -38,7 +41,8 @@ export default async function forkServeCommand(options) {
38
41
  const server = new ForkServer(forkPath, port, host);
39
42
  // Handle graceful shutdown (use 'once' to prevent duplicate shutdowns)
40
43
  const shutdown = async () => {
41
- console.log('\n\nShutting down...');
44
+ logger.newline();
45
+ logger.step("Shutting down...");
42
46
  await server.stop();
43
47
  process.exit(0);
44
48
  };
@@ -59,7 +63,8 @@ export default async function forkServeCommand(options) {
59
63
  }
60
64
  catch (error) {
61
65
  const msg = error instanceof Error ? error.message : String(error);
62
- console.error(`\nError starting fork server:`, msg);
66
+ logger.newline();
67
+ logger.error(`Error starting fork server: ${msg}`);
63
68
  process.exit(1);
64
69
  }
65
70
  }
@@ -1,7 +1,9 @@
1
1
  import { runMoveTests } from "../helpers/move-tests.js";
2
+ import { logger } from "../ui/index.js";
2
3
  export default async function testMoveCommand(options = {}) {
3
4
  try {
4
- console.log("Running Move unit tests...\n");
5
+ logger.step("Running Move unit tests...");
6
+ logger.newline();
5
7
  await runMoveTests({
6
8
  filter: options.filter,
7
9
  ignoreWarnings: options.ignoreWarnings,
@@ -10,10 +12,11 @@ export default async function testMoveCommand(options = {}) {
10
12
  process.exit(0);
11
13
  }
12
14
  catch (err) {
13
- console.error("\n✗ Move tests failed");
15
+ logger.newline();
16
+ logger.error("Move tests failed");
14
17
  const msg = err instanceof Error ? err.message : String(err);
15
18
  if (msg) {
16
- console.error(` ${msg}`);
19
+ logger.error(` ${msg}`);
17
20
  }
18
21
  process.exit(1);
19
22
  }
@@ -14,183 +14,165 @@ export interface SaveAccountPoolOptions {
14
14
  */
15
15
  includeImported?: boolean | undefined;
16
16
  }
17
+ export interface AccountManagerOptions {
18
+ /**
19
+ * Filesystem location where `saveAccountPool` writes `test-pool.json`
20
+ * and `loadAccountPool` reads from. When omitted, the path is computed
21
+ * LAZILY on each call from `join(process.cwd(), ".movehat", "accounts")`
22
+ * — so `process.chdir()` between construction and pool I/O is respected.
23
+ *
24
+ * Pass an explicit value when per-instance isolation matters (parallel
25
+ * test files, harness pools that must not collide with another suite's).
26
+ *
27
+ * The process-wide static facade exposed on the `AccountManager` class
28
+ * itself uses a separate singleton whose `poolPath` is EAGERLY captured
29
+ * at module-import time. That preserves the legacy F8(b) behavior for
30
+ * any code still on the static API during the 0.2.7 deprecation window;
31
+ * the static facade is removed in 0.3.0.
32
+ */
33
+ poolPath?: string | undefined;
34
+ }
17
35
  /**
18
36
  * Centralized Account Manager for movehat
19
37
  *
20
38
  * Manages all account creation, loading, and lifecycle operations.
21
- * Provides a pool of reusable test accounts with labels for better test readability.
39
+ * Provides a pool of reusable test accounts with labels for better test
40
+ * readability.
41
+ *
42
+ * Two API surfaces are exposed:
43
+ *
44
+ * **Instance API (recommended; M9.1+)** — `new AccountManager(options?)`
45
+ * gives a fully isolated pool. Two instances in the same process have
46
+ * independent labelMaps, private-key maps, and account pools. Each
47
+ * `Harness` constructed in 0.3.0+ will own one of these; user code
48
+ * accesses labeled accounts via `harness.accounts.<label>` (Harness
49
+ * snapshots them at construction time).
50
+ *
51
+ * **Static facade (deprecated; will be removed in 0.3.0)** — every
52
+ * former static method (`AccountManager.createAccount(...)`, etc.) still
53
+ * works and forwards to a single process-wide singleton. This preserves
54
+ * the existing label-sharing behavior across calls during the
55
+ * deprecation window. Migration target is the instance API; see M9 meta
56
+ * (#270) and migration guide at `/docs/upgrading/0.3.0` (published in
57
+ * M9.4).
22
58
  */
23
59
  export declare class AccountManager {
24
- private static pool;
25
- private static privateKeys;
26
- private static labelMap;
27
- private static generatedAccountAddresses;
28
- private static poolLoaded;
29
- private static defaultPoolPath;
30
- /**
31
- * Get a test account from the pool. If label is provided and exists, returns that account.
32
- * Otherwise creates a new account with the optional label.
33
- *
34
- * @param label Optional label for the account (e.g., "alice", "bob", "deployer")
60
+ private readonly pool;
61
+ private readonly privateKeys;
62
+ private readonly labelMap;
63
+ private readonly generatedAccountAddresses;
64
+ private poolLoaded;
65
+ private readonly poolPathOverride;
66
+ constructor(options?: AccountManagerOptions);
67
+ /**
68
+ * Resolved pool directory. When the caller supplied an explicit
69
+ * `poolPath` to the constructor, that value is returned verbatim.
70
+ * Otherwise the path is computed LAZILY from the current
71
+ * `process.cwd()` on each access — so `process.chdir()` performed
72
+ * between construction and pool I/O takes effect, unlike the legacy
73
+ * static-only API which captured cwd at module import time
74
+ * (audit finding F8(b)).
75
+ */
76
+ private get poolPath();
77
+ /**
78
+ * Get a test account from the pool. If label is provided and exists,
79
+ * returns that account. Otherwise creates a new account with the
80
+ * optional label.
81
+ *
82
+ * @param label Optional label for the account (e.g., "alice", "bob")
35
83
  * @returns An Account instance
36
- *
37
- * @example
38
- * const alice = AccountManager.getTestAccount("alice");
39
- * const randomAccount = AccountManager.getTestAccount();
40
84
  */
41
- static getTestAccount(label?: string): Account;
85
+ getTestAccount(label?: string): Account;
42
86
  /**
43
- * Create a new account and optionally add it to the pool with a label
44
- *
45
- * @param label Optional label for the account
46
- * @param fund Whether to fund the account (handled externally)
47
- * @returns A new Account instance
48
- *
49
- * @example
50
- * const deployer = AccountManager.createAccount("deployer");
51
- * const bob = AccountManager.createAccount("bob", true);
87
+ * Create a new account and optionally add it to the pool with a
88
+ * label. The `fund` parameter is accepted for API symmetry; actual
89
+ * funding is the caller's responsibility.
52
90
  */
53
- static createAccount(label?: string, fund?: boolean): Account;
91
+ createAccount(label?: string, _fund?: boolean): Account;
54
92
  /**
55
- * Get an account by its label
56
- *
57
- * @param label The label to look up
58
- * @returns The Account if found, undefined otherwise
59
- *
60
- * @example
61
- * const alice = AccountManager.getAccountByLabel("alice");
62
- * if (alice) {
63
- * console.log(`Alice's address: ${alice.accountAddress.toString()}`);
64
- * }
93
+ * Get an account by its label, or undefined if not present.
65
94
  */
66
- static getAccountByLabel(label: string): Account | undefined;
95
+ getAccountByLabel(label: string): Account | undefined;
67
96
  /**
68
- * Load account from environment variable
69
- *
70
- * @param envVar The environment variable name (defaults to "PRIVATE_KEY")
71
- * @returns Account instance
72
- * @throws Error if environment variable is not set
97
+ * Load account from environment variable.
73
98
  *
74
- * @example
75
- * const account = AccountManager.loadAccountFromEnv("MH_PRIVATE_KEY");
99
+ * @throws Error if the environment variable is not set
76
100
  */
77
- static loadAccountFromEnv(envVar?: string): Account;
101
+ loadAccountFromEnv(envVar?: string): Account;
78
102
  /**
79
- * Load account from a private key hex string
80
- *
81
- * @param privateKeyHex The private key as a hex string (with or without 0x prefix)
82
- * @returns Account instance
83
- *
84
- * @example
85
- * const account = AccountManager.loadAccountFromPrivateKey("0xabc123...");
103
+ * Load account from a private key hex string (with or without 0x prefix).
86
104
  */
87
- static loadAccountFromPrivateKey(privateKeyHex: string): Account;
105
+ loadAccountFromPrivateKey(privateKeyHex: string): Account;
88
106
  /**
89
- * Load all accounts from movehat config
90
- *
91
- * @param config The resolved MovehatConfig
92
- * @returns Array of Account instances
93
- *
94
- * @example
95
- * const config = await resolveNetworkConfig(userConfig);
96
- * const accounts = AccountManager.loadAccountsFromConfig(config);
107
+ * Load all accounts from movehat config.
97
108
  */
98
- static loadAccountsFromConfig(config: MovehatConfig): Account[];
109
+ loadAccountsFromConfig(config: MovehatConfig): Account[];
99
110
  /**
100
- * Get all labeled accounts in the pool
101
- *
102
- * @returns Record of label to Account mappings
103
- *
104
- * @example
105
- * const labeled = AccountManager.getLabeledAccounts();
106
- * console.log(`Deployer: ${labeled.deployer?.accountAddress.toString()}`);
111
+ * Get all labeled accounts in the pool.
107
112
  */
108
- static getLabeledAccounts(): Record<string, Account>;
113
+ getLabeledAccounts(): Record<string, Account>;
109
114
  /**
110
- * Save the current account pool to disk for persistence
111
- *
112
- * @param poolPath Optional custom path (defaults to .movehat/accounts)
113
- *
114
- * @example
115
- * AccountManager.saveAccountPool();
115
+ * Save the current account pool to disk for persistence.
116
116
  */
117
- static saveAccountPool(): void;
118
- static saveAccountPool(poolPath: string): void;
119
- static saveAccountPool(options: SaveAccountPoolOptions): void;
120
- static saveAccountPool(poolPath: string, options: SaveAccountPoolOptions): void;
117
+ saveAccountPool(): void;
118
+ saveAccountPool(poolPath: string): void;
119
+ saveAccountPool(options: SaveAccountPoolOptions): void;
120
+ saveAccountPool(poolPath: string, options: SaveAccountPoolOptions): void;
121
121
  /**
122
- * Load account pool from disk
123
- *
124
- * @param poolPath Optional custom path (defaults to .movehat/accounts)
125
- * @returns true if pool was loaded, false if file doesn't exist
126
- *
127
- * @example
128
- * if (AccountManager.loadAccountPool()) {
129
- * console.log("Pool loaded successfully");
130
- * }
122
+ * Load account pool from disk. Returns true if a pool file was found
123
+ * and parsed, false if the file does not exist or parsing failed.
131
124
  */
132
- static loadAccountPool(poolPath?: string): boolean;
125
+ loadAccountPool(poolPath?: string): boolean;
133
126
  /**
134
- * Clear the entire account pool
135
- * Useful for test isolation
136
- *
137
- * @example
138
- * after(() => {
139
- * AccountManager.clearPool();
140
- * });
127
+ * Clear the entire account pool. Useful for test isolation.
141
128
  */
142
- static clearPool(): void;
129
+ clearPool(): void;
143
130
  /**
144
- * Get the current size of the account pool
145
- *
146
- * @returns Number of accounts in the pool
131
+ * Number of accounts in the pool.
147
132
  */
148
- static getPoolSize(): number;
133
+ getPoolSize(): number;
149
134
  /**
150
- * Get all accounts in the pool
151
- *
152
- * @returns Array of all Account instances
135
+ * All accounts in the pool.
153
136
  */
154
- static getAllAccounts(): Account[];
137
+ getAllAccounts(): Account[];
155
138
  /**
156
- * Check if a label is already in use
157
- *
158
- * @param label The label to check
159
- * @returns true if label exists, false otherwise
139
+ * Whether a label is currently bound to an account in this pool.
160
140
  */
161
- static hasLabel(label: string): boolean;
141
+ hasLabel(label: string): boolean;
162
142
  /**
163
- * Get or create an account with a specific label
164
- * If the label exists, returns the existing account
165
- * Otherwise creates a new account with that label
166
- *
167
- * @param label The label for the account
168
- * @returns Account instance
169
- *
170
- * @example
171
- * const alice = AccountManager.getOrCreateLabeled("alice");
172
- * const aliceAgain = AccountManager.getOrCreateLabeled("alice"); // Same account
143
+ * Get or create an account with a specific label.
173
144
  */
174
- static getOrCreateLabeled(label: string): Account;
145
+ getOrCreateLabeled(label: string): Account;
175
146
  /**
176
- * Batch create multiple labeled accounts
177
- *
178
- * @param labels Array of labels to create
179
- * @returns Record of label to Account mappings
180
- *
181
- * @example
182
- * const accounts = AccountManager.createBatch(["alice", "bob", "charlie"]);
183
- * console.log(accounts.alice.accountAddress.toString());
147
+ * Batch create multiple labeled accounts.
184
148
  */
185
- static createBatch(labels: readonly string[]): Record<string, Account>;
149
+ createBatch(labels: readonly string[]): Record<string, Account>;
186
150
  /**
187
- * Export account private keys for backup/sharing
188
- * WARNING: Only use this for test accounts, never production keys
189
- *
190
- * @param labels Optional array of labels to export (exports all if not provided)
191
- * @returns Record of label/address to private key hex string
151
+ * Export account private keys for backup/sharing.
152
+ * WARNING: Only use this for test accounts, never production keys.
192
153
  */
154
+ exportPrivateKeys(labels?: string[]): Record<string, string>;
155
+ private accountFromPrivateKey;
156
+ private trackAccount;
157
+ static getTestAccount(label?: string): Account;
158
+ static createAccount(label?: string, fund?: boolean): Account;
159
+ static getAccountByLabel(label: string): Account | undefined;
160
+ static loadAccountFromEnv(envVar?: string): Account;
161
+ static loadAccountFromPrivateKey(privateKeyHex: string): Account;
162
+ static loadAccountsFromConfig(config: MovehatConfig): Account[];
163
+ static getLabeledAccounts(): Record<string, Account>;
164
+ static saveAccountPool(): void;
165
+ static saveAccountPool(poolPath: string): void;
166
+ static saveAccountPool(options: SaveAccountPoolOptions): void;
167
+ static saveAccountPool(poolPath: string, options: SaveAccountPoolOptions): void;
168
+ static loadAccountPool(poolPath?: string): boolean;
169
+ static clearPool(): void;
170
+ static getPoolSize(): number;
171
+ static getAllAccounts(): Account[];
172
+ static hasLabel(label: string): boolean;
173
+ static getOrCreateLabeled(label: string): Account;
174
+ static createBatch(labels: readonly string[]): Record<string, Account>;
193
175
  static exportPrivateKeys(labels?: string[]): Record<string, string>;
194
- private static accountFromPrivateKey;
195
- private static trackAccount;
196
176
  }
177
+ /** @internal — test-only. Resets the once-per-method dedup Set. */
178
+ export declare function _resetDeprecationWarnings(): void;