wative-core 2.2.1 → 2.3.9

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 (36) hide show
  1. package/CHANGELOG.md +486 -13
  2. package/LICENSE +114 -0
  3. package/README.md +144 -5
  4. package/dist/artifacts/evm/index.cjs +1 -1
  5. package/dist/artifacts/evm/index.d.cts +2 -2
  6. package/dist/artifacts/evm/index.d.ts +2 -2
  7. package/dist/artifacts/evm/index.js +1 -1
  8. package/dist/artifacts/svm/index.cjs +1 -1
  9. package/dist/artifacts/svm/index.d.cts +3 -3
  10. package/dist/artifacts/svm/index.d.ts +3 -3
  11. package/dist/artifacts/svm/index.js +1 -1
  12. package/dist/{container-provider-i614LDE1.d.cts → container-provider-CkKGyHis.d.cts} +10 -3
  13. package/dist/{container-provider-C59yqd5Z.d.ts → container-provider-D_557LVN.d.ts} +10 -3
  14. package/dist/{evm-BLml33LX.d.cts → evm-Xw4zBLUH.d.ts} +2 -2
  15. package/dist/{evm-DTzqGlL6.d.ts → evm-gsdoVj16.d.cts} +2 -2
  16. package/dist/{file-sink-LS4hyXXi.d.ts → file-sink-C_SlT9IC.d.cts} +8 -5
  17. package/dist/{file-sink-B73MuigK.d.cts → file-sink-D33jvque.d.ts} +8 -5
  18. package/dist/index.cjs +1 -1
  19. package/dist/index.d.cts +20 -7
  20. package/dist/index.d.ts +20 -7
  21. package/dist/index.js +1 -1
  22. package/dist/index.node.cjs +1 -1
  23. package/dist/index.node.d.cts +6 -6
  24. package/dist/index.node.d.ts +6 -6
  25. package/dist/index.node.js +1 -1
  26. package/dist/node/index.cjs +1 -1
  27. package/dist/node/index.d.cts +3 -3
  28. package/dist/node/index.d.ts +3 -3
  29. package/dist/node/index.js +1 -1
  30. package/dist/{svm-DieFbh9k.d.ts → svm-CTCJsYri.d.cts} +2 -2
  31. package/dist/{svm-CCzqNAWM.d.cts → svm-CUuqpl1h.d.ts} +2 -2
  32. package/dist/{workspace-CamTHxso.d.cts → workspace-Du_jy51u.d.cts} +19 -4
  33. package/dist/{workspace-CamTHxso.d.ts → workspace-Du_jy51u.d.ts} +19 -4
  34. package/examples/15-package-resolution.test.cjs +187 -1
  35. package/examples/18-envelope-v3.test.cjs +106 -0
  36. package/package.json +6 -3
@@ -1,4 +1,4 @@
1
- import { c as Address, F as SvmTxBuildParams, D as SvmTransaction } from './workspace-CamTHxso.js';
1
+ import { c as Address, G as SvmTxBuildParams, F as SvmTransaction } from './workspace-Du_jy51u.cjs';
2
2
 
3
3
  interface SvmInstruction {
4
4
  readonly programId: string;
@@ -56,4 +56,4 @@ declare class Program {
56
56
  call(from: Address, instructionName: string, args: Readonly<Record<string, unknown>>, accounts: Readonly<Record<string, string>>, opts?: Partial<SvmTxBuildParams>): SvmTransaction;
57
57
  }
58
58
 
59
- export { ASSOCIATED_TOKEN_PROGRAM_ID as A, NATIVE_SOL_MINT as N, Program as P, type SvmInstruction as S, TOKEN_2022_PROGRAM_ID as T, TOKEN_PROGRAM_ID as a, splTokenEncodeInstruction as s };
59
+ export { ASSOCIATED_TOKEN_PROGRAM_ID as A, NATIVE_SOL_MINT as N, Program as P, type SvmInstruction as S, TOKEN_2022_PROGRAM_ID as T, type SplTokenAccountSet as a, type SplTokenArgs as b, TOKEN_PROGRAM_ID as c, splTokenEncodeInstruction as s };
@@ -1,4 +1,4 @@
1
- import { c as Address, F as SvmTxBuildParams, D as SvmTransaction } from './workspace-CamTHxso.cjs';
1
+ import { c as Address, G as SvmTxBuildParams, F as SvmTransaction } from './workspace-Du_jy51u.js';
2
2
 
3
3
  interface SvmInstruction {
4
4
  readonly programId: string;
@@ -56,4 +56,4 @@ declare class Program {
56
56
  call(from: Address, instructionName: string, args: Readonly<Record<string, unknown>>, accounts: Readonly<Record<string, string>>, opts?: Partial<SvmTxBuildParams>): SvmTransaction;
57
57
  }
58
58
 
59
- export { ASSOCIATED_TOKEN_PROGRAM_ID as A, NATIVE_SOL_MINT as N, Program as P, type SvmInstruction as S, TOKEN_2022_PROGRAM_ID as T, TOKEN_PROGRAM_ID as a, splTokenEncodeInstruction as s };
59
+ export { ASSOCIATED_TOKEN_PROGRAM_ID as A, NATIVE_SOL_MINT as N, Program as P, type SvmInstruction as S, TOKEN_2022_PROGRAM_ID as T, type SplTokenAccountSet as a, type SplTokenArgs as b, TOKEN_PROGRAM_ID as c, splTokenEncodeInstruction as s };
@@ -128,6 +128,8 @@ interface RecordInit<T> {
128
128
  readonly password?: string;
129
129
  readonly decrypt?: (ciphertext: Uint8Array, password: string) => Uint8Array;
130
130
  readonly persist?: (value: T, password: string) => Promise<void>;
131
+
132
+ readonly requireLiveSession?: () => void;
131
133
  }
132
134
  declare class Record$1<T> {
133
135
  #private;
@@ -163,11 +165,11 @@ declare abstract class Provider {
163
165
 
164
166
  initialize(): Promise<void>;
165
167
 
166
- passwordTanren(userInputPassword: string, salt: Uint8Array): Uint8Array;
168
+ protected _hasRawAccountData(): Promise<boolean>;
167
169
  abstract close(): Promise<void>;
168
170
  }
169
171
 
170
- type WativeErrorCode = "WORKSPACE_LOCKED" | "ACCOUNT_LOCKED" | "RECORD_LOCKED" | "BAD_PASSWORD" | "WEAK_PASSWORD" | "RECORD_NOT_FOUND" | "PROVIDER_IO" | "PERMISSION_DENIED" | "DISK_FULL" | "PARAMETER_ERROR" | "DECRYPT_FAILED" | "ENCRYPT_FAILED" | "ALGORITHM_IRREVERSIBLE" | "INVALID_MNEMONIC" | "INVALID_PRIVATE_KEY" | "UNSUPPORTED_NETWORK" | "TX_BUILD_FAILED" | "TX_SIGN_FAILED" | "TX_SUBMIT_FAILED" | "TX_TIMEOUT" | "TX_DROPPED" | "RPC_UNREACHABLE" | "STORAGE_NOT_DURABLE" | "UNSUPPORTED_OP";
172
+ type WativeErrorCode = "WORKSPACE_LOCKED" | "ACCOUNT_LOCKED" | "RECORD_LOCKED" | "BAD_PASSWORD" | "WEAK_PASSWORD" | "RECORD_NOT_FOUND" | "PROVIDER_IO" | "PERMISSION_DENIED" | "DISK_FULL" | "PARAMETER_ERROR" | "DECRYPT_FAILED" | "ENCRYPT_FAILED" | "ALGORITHM_IRREVERSIBLE" | "INVALID_MNEMONIC" | "INVALID_PRIVATE_KEY" | "UNSUPPORTED_NETWORK" | "TX_BUILD_FAILED" | "TX_SIGN_FAILED" | "TX_SUBMIT_FAILED" | "TX_TIMEOUT" | "TX_DROPPED" | "TX_ABORTED" | "RPC_UNREACHABLE" | "STORAGE_NOT_DURABLE" | "UNSUPPORTED_OP";
171
173
  interface WativeErrorOpts {
172
174
  readonly cause?: unknown;
173
175
  readonly details?: Record<string, unknown>;
@@ -179,7 +181,7 @@ declare class WativeError extends Error {
179
181
  constructor(code: WativeErrorCode, message: string, opts?: WativeErrorOpts);
180
182
  }
181
183
 
182
- type TransactionStatus = "draft" | "signed" | "submitted" | "pending" | "mined" | "confirmed" | "finalized" | "failed" | "dropped" | "timeout";
184
+ type TransactionStatus = "draft" | "signed" | "submitted" | "pending" | "mined" | "confirmed" | "finalized" | "failed" | "dropped" | "aborted" | "timeout";
183
185
 
184
186
  declare const EvmTxType: {
185
187
  readonly Legacy: 0;
@@ -592,9 +594,18 @@ declare class Account {
592
594
 
593
595
  _persistInternal(): Promise<void>;
594
596
 
597
+
598
+ _isAttached(): boolean;
599
+ _setAttached(attached: boolean): void;
600
+
595
601
  _dropWallet(wallet: Wallet): Promise<void>;
596
602
 
597
603
  _enqueueMutation<T>(fn: () => Promise<T>): Promise<T>;
604
+
605
+ _restoreUnlockPassword(pwd: string | null): void;
606
+
607
+
608
+ _wipeWalletKeys(...wallets: Wallet[]): void;
598
609
  }
599
610
  interface AccountCollection extends ReadonlyArray<Account> {
600
611
  create(displayName: string, password: string, secret: string, defaultNetwork?: NetworkLike, opts?: {
@@ -701,9 +712,13 @@ declare class Workspace {
701
712
  accounts: AccountCollection;
702
713
  networks: NetworkCollection;
703
714
 
715
+ _registerLiveAccount(account: Account): void;
716
+
704
717
  _enqueueNetworkMutation<T>(fn: () => Promise<T>): Promise<T>;
705
718
  private constructor();
706
719
  get locked(): boolean;
720
+
721
+ get damagedAccountSlugs(): ReadonlyArray<string>;
707
722
  get rootDescriptor(): string;
708
723
 
709
724
  static open(providerOrRoot?: Provider | string | OpenOptions, password?: string, create?: boolean): Promise<Workspace>;
@@ -734,4 +749,4 @@ declare class Workspace {
734
749
  } | null;
735
750
  }
736
751
 
737
- export { Account as A, type SvmAddress as B, type ChainId as C, SvmTransaction as D, type EvmAddress as E, type SvmTxBuildParams as F, type TransactionReceipt as G, type TransactionStateChange as H, type TransactionStatus as I, type TransactionTracker as J, type WalletCollection as K, type LogLevel as L, WativeError as M, Network as N, type WativeErrorCode as O, Provider as P, type WativeErrorOpts as Q, Record$1 as R, type Settling as S, type Transaction as T, Workspace as U, type WorkspaceConfig as V, Wallet as W, newMnemonic as X, type ContainerState as Y, type AccountCollection as a, type AccountOrgType as b, Address as c, Asset as d, type AssetBalance as e, type AssetCollection as f, type AssetId as g, type AssetInitObject as h, type ChainVM as i, ConsoleSink as j, type EvmRawTx as k, EvmTransaction as l, type EvmTxBuildParams as m, EvmTxType as n, type LogRecord as o, type LogSink as p, Logger as q, type LoggerConfig as r, type NetworkCollection as s, type NetworkInit as t, type NetworkLike as u, type RecordInit as v, type RecordType as w, type SimulationResult as x, type SinkConfig as y, type Slug as z };
752
+ export { Account as A, type Slug as B, type ChainId as C, type SvmAddress as D, type EvmAddress as E, SvmTransaction as F, type SvmTxBuildParams as G, type TransactionReceipt as H, type TransactionStateChange as I, type TransactionStatus as J, type TransactionTracker as K, type LogLevel as L, type WalletCollection as M, Network as N, type OpenOptions as O, Provider as P, WativeError as Q, Record$1 as R, type Settling as S, type Transaction as T, type WativeErrorCode as U, type WativeErrorOpts as V, Wallet as W, Workspace as X, type WorkspaceConfig as Y, newMnemonic as Z, type AccountCollection as a, type AccountOrgType as b, Address as c, Asset as d, type AssetBalance as e, type AssetCollection as f, type AssetId as g, type AssetInitObject as h, type ChainVM as i, ConsoleSink as j, type ContainerState as k, type EvmRawTx as l, EvmTransaction as m, type EvmTxBuildParams as n, EvmTxType as o, type LogRecord as p, type LogSink as q, Logger as r, type LoggerConfig as s, type NetworkCollection as t, type NetworkInit as u, type NetworkLike as v, type RecordInit as w, type RecordType as x, type SimulationResult as y, type SinkConfig as z };
@@ -128,6 +128,8 @@ interface RecordInit<T> {
128
128
  readonly password?: string;
129
129
  readonly decrypt?: (ciphertext: Uint8Array, password: string) => Uint8Array;
130
130
  readonly persist?: (value: T, password: string) => Promise<void>;
131
+
132
+ readonly requireLiveSession?: () => void;
131
133
  }
132
134
  declare class Record$1<T> {
133
135
  #private;
@@ -163,11 +165,11 @@ declare abstract class Provider {
163
165
 
164
166
  initialize(): Promise<void>;
165
167
 
166
- passwordTanren(userInputPassword: string, salt: Uint8Array): Uint8Array;
168
+ protected _hasRawAccountData(): Promise<boolean>;
167
169
  abstract close(): Promise<void>;
168
170
  }
169
171
 
170
- type WativeErrorCode = "WORKSPACE_LOCKED" | "ACCOUNT_LOCKED" | "RECORD_LOCKED" | "BAD_PASSWORD" | "WEAK_PASSWORD" | "RECORD_NOT_FOUND" | "PROVIDER_IO" | "PERMISSION_DENIED" | "DISK_FULL" | "PARAMETER_ERROR" | "DECRYPT_FAILED" | "ENCRYPT_FAILED" | "ALGORITHM_IRREVERSIBLE" | "INVALID_MNEMONIC" | "INVALID_PRIVATE_KEY" | "UNSUPPORTED_NETWORK" | "TX_BUILD_FAILED" | "TX_SIGN_FAILED" | "TX_SUBMIT_FAILED" | "TX_TIMEOUT" | "TX_DROPPED" | "RPC_UNREACHABLE" | "STORAGE_NOT_DURABLE" | "UNSUPPORTED_OP";
172
+ type WativeErrorCode = "WORKSPACE_LOCKED" | "ACCOUNT_LOCKED" | "RECORD_LOCKED" | "BAD_PASSWORD" | "WEAK_PASSWORD" | "RECORD_NOT_FOUND" | "PROVIDER_IO" | "PERMISSION_DENIED" | "DISK_FULL" | "PARAMETER_ERROR" | "DECRYPT_FAILED" | "ENCRYPT_FAILED" | "ALGORITHM_IRREVERSIBLE" | "INVALID_MNEMONIC" | "INVALID_PRIVATE_KEY" | "UNSUPPORTED_NETWORK" | "TX_BUILD_FAILED" | "TX_SIGN_FAILED" | "TX_SUBMIT_FAILED" | "TX_TIMEOUT" | "TX_DROPPED" | "TX_ABORTED" | "RPC_UNREACHABLE" | "STORAGE_NOT_DURABLE" | "UNSUPPORTED_OP";
171
173
  interface WativeErrorOpts {
172
174
  readonly cause?: unknown;
173
175
  readonly details?: Record<string, unknown>;
@@ -179,7 +181,7 @@ declare class WativeError extends Error {
179
181
  constructor(code: WativeErrorCode, message: string, opts?: WativeErrorOpts);
180
182
  }
181
183
 
182
- type TransactionStatus = "draft" | "signed" | "submitted" | "pending" | "mined" | "confirmed" | "finalized" | "failed" | "dropped" | "timeout";
184
+ type TransactionStatus = "draft" | "signed" | "submitted" | "pending" | "mined" | "confirmed" | "finalized" | "failed" | "dropped" | "aborted" | "timeout";
183
185
 
184
186
  declare const EvmTxType: {
185
187
  readonly Legacy: 0;
@@ -592,9 +594,18 @@ declare class Account {
592
594
 
593
595
  _persistInternal(): Promise<void>;
594
596
 
597
+
598
+ _isAttached(): boolean;
599
+ _setAttached(attached: boolean): void;
600
+
595
601
  _dropWallet(wallet: Wallet): Promise<void>;
596
602
 
597
603
  _enqueueMutation<T>(fn: () => Promise<T>): Promise<T>;
604
+
605
+ _restoreUnlockPassword(pwd: string | null): void;
606
+
607
+
608
+ _wipeWalletKeys(...wallets: Wallet[]): void;
598
609
  }
599
610
  interface AccountCollection extends ReadonlyArray<Account> {
600
611
  create(displayName: string, password: string, secret: string, defaultNetwork?: NetworkLike, opts?: {
@@ -701,9 +712,13 @@ declare class Workspace {
701
712
  accounts: AccountCollection;
702
713
  networks: NetworkCollection;
703
714
 
715
+ _registerLiveAccount(account: Account): void;
716
+
704
717
  _enqueueNetworkMutation<T>(fn: () => Promise<T>): Promise<T>;
705
718
  private constructor();
706
719
  get locked(): boolean;
720
+
721
+ get damagedAccountSlugs(): ReadonlyArray<string>;
707
722
  get rootDescriptor(): string;
708
723
 
709
724
  static open(providerOrRoot?: Provider | string | OpenOptions, password?: string, create?: boolean): Promise<Workspace>;
@@ -734,4 +749,4 @@ declare class Workspace {
734
749
  } | null;
735
750
  }
736
751
 
737
- export { Account as A, type SvmAddress as B, type ChainId as C, SvmTransaction as D, type EvmAddress as E, type SvmTxBuildParams as F, type TransactionReceipt as G, type TransactionStateChange as H, type TransactionStatus as I, type TransactionTracker as J, type WalletCollection as K, type LogLevel as L, WativeError as M, Network as N, type WativeErrorCode as O, Provider as P, type WativeErrorOpts as Q, Record$1 as R, type Settling as S, type Transaction as T, Workspace as U, type WorkspaceConfig as V, Wallet as W, newMnemonic as X, type ContainerState as Y, type AccountCollection as a, type AccountOrgType as b, Address as c, Asset as d, type AssetBalance as e, type AssetCollection as f, type AssetId as g, type AssetInitObject as h, type ChainVM as i, ConsoleSink as j, type EvmRawTx as k, EvmTransaction as l, type EvmTxBuildParams as m, EvmTxType as n, type LogRecord as o, type LogSink as p, Logger as q, type LoggerConfig as r, type NetworkCollection as s, type NetworkInit as t, type NetworkLike as u, type RecordInit as v, type RecordType as w, type SimulationResult as x, type SinkConfig as y, type Slug as z };
752
+ export { Account as A, type Slug as B, type ChainId as C, type SvmAddress as D, type EvmAddress as E, SvmTransaction as F, type SvmTxBuildParams as G, type TransactionReceipt as H, type TransactionStateChange as I, type TransactionStatus as J, type TransactionTracker as K, type LogLevel as L, type WalletCollection as M, Network as N, type OpenOptions as O, Provider as P, WativeError as Q, Record$1 as R, type Settling as S, type Transaction as T, type WativeErrorCode as U, type WativeErrorOpts as V, Wallet as W, Workspace as X, type WorkspaceConfig as Y, newMnemonic as Z, type AccountCollection as a, type AccountOrgType as b, Address as c, Asset as d, type AssetBalance as e, type AssetCollection as f, type AssetId as g, type AssetInitObject as h, type ChainVM as i, ConsoleSink as j, type ContainerState as k, type EvmRawTx as l, EvmTransaction as m, type EvmTxBuildParams as n, EvmTxType as o, type LogRecord as p, type LogSink as q, Logger as r, type LoggerConfig as s, type NetworkCollection as t, type NetworkInit as u, type NetworkLike as v, type RecordInit as w, type RecordType as x, type SimulationResult as y, type SinkConfig as z };
@@ -11,7 +11,16 @@
11
11
  const test = require("node:test");
12
12
  const assert = require("node:assert");
13
13
 
14
- const SUBPATHS = ["wative-core", "wative-core/artifacts/evm", "wative-core/artifacts/svm"];
14
+ // "wative-core/node" is where HybridProviderV3 lives after the breaking
15
+ // refactor that folded NodeHybridProvider into it. It was missing here, so the
16
+ // subpath carrying the release's headline feature was the one subpath nothing
17
+ // resolved.
18
+ const SUBPATHS = [
19
+ "wative-core",
20
+ "wative-core/node",
21
+ "wative-core/artifacts/evm",
22
+ "wative-core/artifacts/svm",
23
+ ];
15
24
 
16
25
  test("every declared subpath resolves by bare name under require(), to the CJS build", () => {
17
26
  for (const specifier of SUBPATHS) {
@@ -25,6 +34,183 @@ test("every declared subpath resolves by bare name under require(), to the CJS b
25
34
  }
26
35
  });
27
36
 
37
+ // A type used in a public signature but not exported is invisible to a
38
+ // TypeScript consumer, who then cannot name what the method returns. That is not
39
+ // visible from JavaScript, so it is asserted against the emitted declarations.
40
+ //
41
+ // Two things this used to get wrong, both of which let a real regression ship:
42
+ //
43
+ // 1. It opened ONLY `dist/index.node.d.cts` — the node+require artifact. The
44
+ // root subpath emits THREE declaration files (browser/default, node+import,
45
+ // node+require), and `ContainerState` is the return type of the universal
46
+ // `Provider.inspectContainer()`. Deleting its export from the browser
47
+ // artifact alone left this green while every bundler consumer got TS2305.
48
+ // The artifact list is now derived from the `exports` map itself, so a new
49
+ // subpath or condition is covered the day it is added rather than the day
50
+ // someone remembers.
51
+ //
52
+ // 2. It asserted `\bName\b` — bare presence anywhere in the file. A name also
53
+ // appears in an import specifier, in another type's signature, or in a
54
+ // comment, so the assertion held whether or not the name was EXPORTED. It
55
+ // now parses the export clauses and checks membership in the exported set.
56
+ // Keyed by ARTIFACT, not by subpath: the browser and node root builds export
57
+ // legitimately different sets (the node one adds the filesystem provider), so a
58
+ // per-subpath map cannot express "required here, absent there" and would either
59
+ // under-check the node build or falsely fail the browser one.
60
+ //
61
+ // ⚠️ This list is HAND-MAINTAINED, and that is the remaining weakness. The
62
+ // checks below make the ORACLE strong — every declared artifact, and exported
63
+ // rather than merely mentioned — but the INPUT is still a list someone has to
64
+ // remember to extend. `OpenOptions` and `PasswordCheckContext` were both TS2305
65
+ // in a shipped release precisely because nothing derived this list from the
66
+ // public signatures. Deriving it (a referenced-but-not-exported set difference
67
+ // over the emitted declarations) is the real fix and is not done here.
68
+ const EXPECTED_EXPORTS = {
69
+ "./dist/index.d.ts": ["ContainerState", "Argon2BackendInfo", "OpenOptions", "PasswordCheckContext"],
70
+ "./dist/index.node.d.ts": [
71
+ "ContainerState",
72
+ "Argon2BackendInfo",
73
+ "OpenOptions",
74
+ "PasswordCheckContext",
75
+ // The node root re-exports the filesystem provider surface. `exports.test.ts`
76
+ // pins this as a deliberate contract, and `18-envelope-v3.test.cjs` reaches
77
+ // `HybridProviderV3` through the ROOT specifier, not the ./node subpath.
78
+ "HybridProviderV3",
79
+ "HybridProvider",
80
+ "FileSink",
81
+ "FileSinkOptions",
82
+ ],
83
+ "./dist/index.node.d.cts": [
84
+ "ContainerState",
85
+ "Argon2BackendInfo",
86
+ "OpenOptions",
87
+ "PasswordCheckContext",
88
+ "HybridProviderV3",
89
+ "HybridProvider",
90
+ "FileSink",
91
+ "FileSinkOptions",
92
+ ],
93
+ "./dist/node/index.d.ts": ["HybridProviderV3", "HybridProvider", "FileSink", "FileSinkOptions"],
94
+ "./dist/node/index.d.cts": ["HybridProviderV3", "HybridProvider", "FileSink", "FileSinkOptions"],
95
+ };
96
+
97
+ // The `exports` map declares 10 `types` entries across 9 distinct files
98
+ // (`./dist/index.d.ts` is reached by both the `browser` and `default`
99
+ // conditions). Both totals are asserted EXACTLY rather than as floors: a floor
100
+ // tolerates a gap, so deleting `exports["./node"].require.types` would drop the
101
+ // CJS declarations for the subpath carrying the headline feature and still pass.
102
+ // 32 = 4 (index.d.ts, counted twice — browser and default both resolve to it)
103
+ // + 8 + 8 (the two node root artifacts) + 4 + 4 (the ./node subpath pair).
104
+ // The artifacts/{evm,svm} pairs contribute none; they are checked for existence
105
+ // and non-emptiness only.
106
+ const EXPECTED_ARTIFACTS = 10;
107
+ const EXPECTED_ASSERTIONS = 32;
108
+
109
+ // tsup re-exports rather than re-declares: `export { k as ContainerState } from
110
+ // './chunk.cjs'`. The public name is what follows `as`, or the whole entry when
111
+ // there is no alias. Direct `export declare class X` forms are collected too.
112
+ //
113
+ // Two shapes the two builds do NOT agree on, both of which must be handled or
114
+ // the check reports a false regression: the browser artifact writes inline type
115
+ // modifiers (`type Argon2BackendInfo`) where the node artifact writes the bare
116
+ // name, and a name colliding with a lib type is emitted aliased (`Record$1 as
117
+ // Record`). Strip the modifier first, then resolve the alias.
118
+ function exportedNames(dts) {
119
+ const names = new Set();
120
+ for (const m of dts.matchAll(/export\s*(?:type\s*)?\{([^}]*)\}/g)) {
121
+ for (const entry of m[1].split(",")) {
122
+ const trimmed = entry.trim().replace(/^type\s+/, "");
123
+ if (!trimmed) continue;
124
+ const parts = trimmed.split(/\s+as\s+/);
125
+ names.add(parts[parts.length - 1].trim());
126
+ }
127
+ }
128
+ for (const m of dts.matchAll(
129
+ /export\s+(?:declare\s+)?(?:abstract\s+)?(?:class|interface|type|const|function|enum)\s+([A-Za-z_$][\w$]*)/g,
130
+ )) {
131
+ names.add(m[1]);
132
+ }
133
+ return names;
134
+ }
135
+
136
+ // Every `types` file the exports map can resolve, as [subpath, condition, file].
137
+ function declaredTypeArtifacts(exportsMap) {
138
+ const out = [];
139
+ const walk = (subpath, node, condition) => {
140
+ if (typeof node === "string") return;
141
+ for (const [key, value] of Object.entries(node)) {
142
+ if (key === "types" && typeof value === "string") {
143
+ out.push({ subpath, condition: condition || "default", file: value });
144
+ } else if (value && typeof value === "object") {
145
+ walk(subpath, value, condition ? `${condition}.${key}` : key);
146
+ }
147
+ }
148
+ };
149
+ for (const [subpath, node] of Object.entries(exportsMap)) walk(subpath, node, "");
150
+ return out;
151
+ }
152
+
153
+ test("every type named by a public signature is exported from every artifact that declares it", () => {
154
+ const fs = require("node:fs");
155
+ const path = require("node:path");
156
+ // Resolve the package under test by NAME, not by `__dirname/..`. This file
157
+ // runs in two layouts: in the release checkout (examples/ beside dist/, where
158
+ // `..` is the package root) and copied FLAT into a scratch consumer dir that
159
+ // installed the tarball (where `..` is the scratch dir's parent and holds no
160
+ // package.json at all). The second layout is what CI's "published" job uses,
161
+ // and `__dirname/..` made this test throw ENOENT there — so that job has
162
+ // never been able to pass. The exports map declares "./package.json", so this
163
+ // resolves in both.
164
+ const root = path.dirname(require.resolve("wative-core/package.json"));
165
+ const pkg = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8"));
166
+ const artifacts = declaredTypeArtifacts(pkg.exports);
167
+
168
+ // If the exports map stops declaring types, this test would otherwise pass by
169
+ // checking nothing at all — the same vacuity it exists to prevent.
170
+ assert.strictEqual(
171
+ artifacts.length,
172
+ EXPECTED_ARTIFACTS,
173
+ `the exports map declares ${artifacts.length} types entries, expected exactly ${EXPECTED_ARTIFACTS}. ` +
174
+ `A condition lost its "types" (consumers fall back to "could not find a declaration file"), ` +
175
+ `or a subpath was added and needs an entry in EXPECTED_EXPORTS.`,
176
+ );
177
+
178
+ // Counting `types` entries alone cannot see a subpath that declares NONE: the
179
+ // total is unchanged, so the exact-count assertion above passes while the new
180
+ // subpath ships with no declarations at all and its consumers get "could not
181
+ // find a declaration file". Every subpath with conditions must produce at
182
+ // least one.
183
+ for (const [subpath, node] of Object.entries(pkg.exports)) {
184
+ if (typeof node === "string") continue; // "./package.json" — a file, not a type surface
185
+ assert.ok(
186
+ artifacts.some((a) => a.subpath === subpath),
187
+ `subpath "${subpath}" declares no "types" under any condition — TypeScript consumers get no declarations for it`,
188
+ );
189
+ }
190
+
191
+ let checked = 0;
192
+ for (const { subpath, condition, file } of artifacts) {
193
+ const abs = path.join(root, file);
194
+ assert.ok(fs.existsSync(abs), `${subpath} (${condition}) declares types "${file}", which does not exist`);
195
+ const names = exportedNames(fs.readFileSync(abs, "utf8"));
196
+ assert.ok(names.size > 0, `${file} exports nothing — the declaration emit is empty or malformed`);
197
+ for (const name of EXPECTED_EXPORTS[file] || []) {
198
+ assert.ok(
199
+ names.has(name),
200
+ `${name} appears in a public signature of "${subpath}" but is not exported from ${file}`,
201
+ );
202
+ checked++;
203
+ }
204
+ }
205
+ // Exact, for the same reason as the artifact count: a floor here would let a
206
+ // whole artifact's expectations be deleted without the suite noticing.
207
+ assert.strictEqual(
208
+ checked,
209
+ EXPECTED_ASSERTIONS,
210
+ `made ${checked} name/artifact assertions, expected exactly ${EXPECTED_ASSERTIONS}`,
211
+ );
212
+ });
213
+
28
214
  test("bare-name require() exposes the documented entry points", () => {
29
215
  const core = require("wative-core");
30
216
  for (const name of ["Workspace", "Network", "Asset", "Provider", "WativeError"]) {
@@ -0,0 +1,106 @@
1
+ // 18 — HybridProviderV3 and the v3 envelope, through the published package.
2
+ //
3
+ // This file exists because the publish gate could not see the release's
4
+ // headline feature at all. Every other example opens a workspace with
5
+ // `Workspace.open({ path })`, which uses the default provider and writes v2, so
6
+ // disabling v3 in all four built bundles — making `HybridProviderV3` silently
7
+ // write v2 records — passed the entire 54-test suite. The same mutation fails
8
+ // the source suite loudly, so the gap was exactly at the packaging boundary,
9
+ // which is the one thing this gate exists to cover.
10
+ //
11
+ // The subpath `wative-core/node` also re-exports the class; that resolution is
12
+ // covered by example 15.
13
+
14
+ const test = require("node:test");
15
+ const assert = require("node:assert");
16
+ const { mkdtempSync, readFileSync, readdirSync, statSync } = require("node:fs");
17
+ const { tmpdir } = require("node:os");
18
+ const { join } = require("node:path");
19
+
20
+ // Both from the SAME entry point, which is what the README documents and what
21
+ // the cross-entry-point guard enforces: each entry is its own bundle with its
22
+ // own class identities, so a Workspace from one cannot accept a provider from
23
+ // the other. `wative-core/node` re-exports the provider classes but not
24
+ // Workspace, so pairing them comes from here.
25
+ const { Workspace, HybridProviderV3 } = require("wative-core");
26
+
27
+ const MNEMONIC =
28
+ "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
29
+ const PW = "v3-example-password";
30
+
31
+ /** Envelope version byte of every record under `root`. */
32
+ function versions(root) {
33
+ const out = {};
34
+ const walk = (dir, prefix) => {
35
+ for (const name of readdirSync(dir)) {
36
+ const p = join(dir, name);
37
+ if (statSync(p).isDirectory()) walk(p, `${prefix}${name}/`);
38
+ else out[`${prefix}${name}`] = readFileSync(p)[0];
39
+ }
40
+ };
41
+ walk(root, "");
42
+ return out;
43
+ }
44
+
45
+ test("HybridProviderV3 writes v3 records, and they all share one salt", async () => {
46
+ const root = mkdtempSync(join(tmpdir(), "wative-v3-example-"));
47
+ const ws = await Workspace.open(new HybridProviderV3(root), PW, true);
48
+ const acc = await ws.accounts.create("V3 Desk", PW, MNEMONIC);
49
+ await acc.deriveWallets(3);
50
+ await ws.lock();
51
+
52
+ const byFile = versions(root);
53
+ const names = Object.keys(byFile);
54
+ assert.ok(names.length >= 5, `expected several records, got ${names.length}`);
55
+ for (const name of names) {
56
+ assert.strictEqual(
57
+ byFile[name],
58
+ 3,
59
+ `${name} is a v${byFile[name]} envelope — HybridProviderV3 silently degraded to v2`,
60
+ );
61
+ }
62
+
63
+ // The container salt is the 16 bytes after the version byte. v3's whole point
64
+ // is that every record shares it, which is what collapses N derivations into
65
+ // one; v2 mints a fresh salt per record, so this is also what distinguishes
66
+ // the two formats beyond the version byte alone.
67
+ const saltOf = (rel) => readFileSync(join(root, rel)).subarray(1, 17).toString("hex");
68
+ const salts = new Set(names.map(saltOf));
69
+ assert.strictEqual(salts.size, 1, `expected one container salt, got ${salts.size}`);
70
+ });
71
+
72
+ test("a v3 container reopens and yields the original secrets", async () => {
73
+ const root = mkdtempSync(join(tmpdir(), "wative-v3-example-"));
74
+ let ws = await Workspace.open(new HybridProviderV3(root), PW, true);
75
+ const created = await ws.accounts.create("V3 Desk", PW, MNEMONIC);
76
+ await created.deriveWallets(2);
77
+ const expected = created.wallets.map((w) => w.addresses.map((a) => a.publicKey).join(","));
78
+ await ws.lock();
79
+
80
+ ws = await Workspace.open(new HybridProviderV3(root), PW);
81
+ const acc = ws.accounts.bySlug(created.slug);
82
+ assert.ok(acc, "account did not survive the reopen");
83
+ await acc.tryUnlock(PW);
84
+ assert.strictEqual(acc.dumpMnemonic(), MNEMONIC);
85
+ assert.deepStrictEqual(
86
+ acc.wallets.map((w) => w.addresses.map((a) => a.publicKey).join(",")),
87
+ expected,
88
+ );
89
+ await ws.lock();
90
+ });
91
+
92
+ test("a wrong password is rejected, and does not damage the container", async () => {
93
+ const root = mkdtempSync(join(tmpdir(), "wative-v3-example-"));
94
+ let ws = await Workspace.open(new HybridProviderV3(root), PW, true);
95
+ await ws.accounts.create("V3 Desk", PW, MNEMONIC);
96
+ await ws.lock();
97
+
98
+ await assert.rejects(
99
+ () => Workspace.open(new HybridProviderV3(root), "not-the-password"),
100
+ (e) => e.code === "BAD_PASSWORD",
101
+ );
102
+
103
+ ws = await Workspace.open(new HybridProviderV3(root), PW);
104
+ assert.strictEqual(ws.accounts.length, 1);
105
+ await ws.lock();
106
+ });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "wative-core",
3
- "version": "2.2.1",
4
- "description": "Hyperscale crypto wallet management library \u2014 multi-workspace, multi-chain, originally designed for on-chain market makers",
3
+ "version": "2.3.9",
4
+ "description": "Hyperscale crypto wallet management library — multi-workspace, multi-chain, originally designed for on-chain market makers",
5
5
  "type": "module",
6
6
  "main": "./dist/index.node.cjs",
7
7
  "module": "./dist/index.node.js",
@@ -100,5 +100,8 @@
100
100
  "micro-ed25519-hdkey": "0.1.2",
101
101
  "tslib": "2.6.2",
102
102
  "tweetnacl": "1.0.3"
103
+ },
104
+ "optionalDependencies": {
105
+ "@node-rs/argon2": "^2.0.2"
103
106
  }
104
- }
107
+ }