wative-core 2.2.1 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +634 -13
- package/LICENSE +114 -0
- package/README.md +144 -5
- package/dist/artifacts/evm/index.cjs +1 -1
- package/dist/artifacts/evm/index.d.cts +2 -2
- package/dist/artifacts/evm/index.d.ts +2 -2
- package/dist/artifacts/evm/index.js +1 -1
- package/dist/artifacts/svm/index.cjs +1 -1
- package/dist/artifacts/svm/index.d.cts +3 -3
- package/dist/artifacts/svm/index.d.ts +3 -3
- package/dist/artifacts/svm/index.js +1 -1
- package/dist/{container-provider-C59yqd5Z.d.ts → container-provider-D2QluIe_.d.ts} +10 -3
- package/dist/{container-provider-i614LDE1.d.cts → container-provider-DAUXclw_.d.cts} +10 -3
- package/dist/{evm-BLml33LX.d.cts → evm-GxBuNjq7.d.ts} +2 -2
- package/dist/{evm-DTzqGlL6.d.ts → evm-qXdZWugm.d.cts} +2 -2
- package/dist/{file-sink-B73MuigK.d.cts → file-sink-B0EjCBvG.d.ts} +8 -5
- package/dist/{file-sink-LS4hyXXi.d.ts → file-sink-DSOZbsJM.d.cts} +8 -5
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +25 -8
- package/dist/index.d.ts +25 -8
- package/dist/index.js +1 -1
- package/dist/index.node.cjs +1 -1
- package/dist/index.node.d.cts +6 -6
- package/dist/index.node.d.ts +6 -6
- package/dist/index.node.js +1 -1
- package/dist/node/index.cjs +1 -1
- package/dist/node/index.d.cts +3 -3
- package/dist/node/index.d.ts +3 -3
- package/dist/node/index.js +1 -1
- package/dist/{svm-DieFbh9k.d.ts → svm-B_c0L-rJ.d.cts} +2 -2
- package/dist/{svm-CCzqNAWM.d.cts → svm-Ca4Xyw0Y.d.ts} +2 -2
- package/dist/{workspace-CamTHxso.d.cts → workspace-DdaY7sWa.d.cts} +23 -4
- package/dist/{workspace-CamTHxso.d.ts → workspace-DdaY7sWa.d.ts} +23 -4
- package/examples/15-package-resolution.test.cjs +187 -1
- package/examples/18-envelope-v3.test.cjs +106 -0
- package/package.json +6 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as Address,
|
|
1
|
+
import { c as Address, G as SvmTxBuildParams, F as SvmTransaction } from './workspace-DdaY7sWa.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,
|
|
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,
|
|
1
|
+
import { c as Address, G as SvmTxBuildParams, F as SvmTransaction } from './workspace-DdaY7sWa.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,
|
|
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,13 @@ declare abstract class Provider {
|
|
|
163
165
|
|
|
164
166
|
initialize(): Promise<void>;
|
|
165
167
|
|
|
166
|
-
|
|
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" | "
|
|
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"
|
|
173
|
+
|
|
174
|
+
| "RPC_REJECTED" | "STORAGE_NOT_DURABLE" | "UNSUPPORTED_OP";
|
|
171
175
|
interface WativeErrorOpts {
|
|
172
176
|
readonly cause?: unknown;
|
|
173
177
|
readonly details?: Record<string, unknown>;
|
|
@@ -179,7 +183,7 @@ declare class WativeError extends Error {
|
|
|
179
183
|
constructor(code: WativeErrorCode, message: string, opts?: WativeErrorOpts);
|
|
180
184
|
}
|
|
181
185
|
|
|
182
|
-
type TransactionStatus = "draft" | "signed" | "submitted" | "pending" | "mined" | "confirmed" | "finalized" | "failed" | "dropped" | "timeout";
|
|
186
|
+
type TransactionStatus = "draft" | "signed" | "submitted" | "pending" | "mined" | "confirmed" | "finalized" | "failed" | "dropped" | "aborted" | "timeout";
|
|
183
187
|
|
|
184
188
|
declare const EvmTxType: {
|
|
185
189
|
readonly Legacy: 0;
|
|
@@ -592,9 +596,18 @@ declare class Account {
|
|
|
592
596
|
|
|
593
597
|
_persistInternal(): Promise<void>;
|
|
594
598
|
|
|
599
|
+
|
|
600
|
+
_isAttached(): boolean;
|
|
601
|
+
_setAttached(attached: boolean): void;
|
|
602
|
+
|
|
595
603
|
_dropWallet(wallet: Wallet): Promise<void>;
|
|
596
604
|
|
|
597
605
|
_enqueueMutation<T>(fn: () => Promise<T>): Promise<T>;
|
|
606
|
+
|
|
607
|
+
_restoreUnlockPassword(pwd: string | null): void;
|
|
608
|
+
|
|
609
|
+
|
|
610
|
+
_wipeWalletKeys(...wallets: Wallet[]): void;
|
|
598
611
|
}
|
|
599
612
|
interface AccountCollection extends ReadonlyArray<Account> {
|
|
600
613
|
create(displayName: string, password: string, secret: string, defaultNetwork?: NetworkLike, opts?: {
|
|
@@ -701,9 +714,15 @@ declare class Workspace {
|
|
|
701
714
|
accounts: AccountCollection;
|
|
702
715
|
networks: NetworkCollection;
|
|
703
716
|
|
|
717
|
+
_registerLiveAccount(account: Account): void;
|
|
718
|
+
|
|
719
|
+
_releaseAccount(account: Account): void;
|
|
720
|
+
|
|
704
721
|
_enqueueNetworkMutation<T>(fn: () => Promise<T>): Promise<T>;
|
|
705
722
|
private constructor();
|
|
706
723
|
get locked(): boolean;
|
|
724
|
+
|
|
725
|
+
get damagedAccountSlugs(): ReadonlyArray<string>;
|
|
707
726
|
get rootDescriptor(): string;
|
|
708
727
|
|
|
709
728
|
static open(providerOrRoot?: Provider | string | OpenOptions, password?: string, create?: boolean): Promise<Workspace>;
|
|
@@ -734,4 +753,4 @@ declare class Workspace {
|
|
|
734
753
|
} | null;
|
|
735
754
|
}
|
|
736
755
|
|
|
737
|
-
export { Account as A, type
|
|
756
|
+
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,13 @@ declare abstract class Provider {
|
|
|
163
165
|
|
|
164
166
|
initialize(): Promise<void>;
|
|
165
167
|
|
|
166
|
-
|
|
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" | "
|
|
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"
|
|
173
|
+
|
|
174
|
+
| "RPC_REJECTED" | "STORAGE_NOT_DURABLE" | "UNSUPPORTED_OP";
|
|
171
175
|
interface WativeErrorOpts {
|
|
172
176
|
readonly cause?: unknown;
|
|
173
177
|
readonly details?: Record<string, unknown>;
|
|
@@ -179,7 +183,7 @@ declare class WativeError extends Error {
|
|
|
179
183
|
constructor(code: WativeErrorCode, message: string, opts?: WativeErrorOpts);
|
|
180
184
|
}
|
|
181
185
|
|
|
182
|
-
type TransactionStatus = "draft" | "signed" | "submitted" | "pending" | "mined" | "confirmed" | "finalized" | "failed" | "dropped" | "timeout";
|
|
186
|
+
type TransactionStatus = "draft" | "signed" | "submitted" | "pending" | "mined" | "confirmed" | "finalized" | "failed" | "dropped" | "aborted" | "timeout";
|
|
183
187
|
|
|
184
188
|
declare const EvmTxType: {
|
|
185
189
|
readonly Legacy: 0;
|
|
@@ -592,9 +596,18 @@ declare class Account {
|
|
|
592
596
|
|
|
593
597
|
_persistInternal(): Promise<void>;
|
|
594
598
|
|
|
599
|
+
|
|
600
|
+
_isAttached(): boolean;
|
|
601
|
+
_setAttached(attached: boolean): void;
|
|
602
|
+
|
|
595
603
|
_dropWallet(wallet: Wallet): Promise<void>;
|
|
596
604
|
|
|
597
605
|
_enqueueMutation<T>(fn: () => Promise<T>): Promise<T>;
|
|
606
|
+
|
|
607
|
+
_restoreUnlockPassword(pwd: string | null): void;
|
|
608
|
+
|
|
609
|
+
|
|
610
|
+
_wipeWalletKeys(...wallets: Wallet[]): void;
|
|
598
611
|
}
|
|
599
612
|
interface AccountCollection extends ReadonlyArray<Account> {
|
|
600
613
|
create(displayName: string, password: string, secret: string, defaultNetwork?: NetworkLike, opts?: {
|
|
@@ -701,9 +714,15 @@ declare class Workspace {
|
|
|
701
714
|
accounts: AccountCollection;
|
|
702
715
|
networks: NetworkCollection;
|
|
703
716
|
|
|
717
|
+
_registerLiveAccount(account: Account): void;
|
|
718
|
+
|
|
719
|
+
_releaseAccount(account: Account): void;
|
|
720
|
+
|
|
704
721
|
_enqueueNetworkMutation<T>(fn: () => Promise<T>): Promise<T>;
|
|
705
722
|
private constructor();
|
|
706
723
|
get locked(): boolean;
|
|
724
|
+
|
|
725
|
+
get damagedAccountSlugs(): ReadonlyArray<string>;
|
|
707
726
|
get rootDescriptor(): string;
|
|
708
727
|
|
|
709
728
|
static open(providerOrRoot?: Provider | string | OpenOptions, password?: string, create?: boolean): Promise<Workspace>;
|
|
@@ -734,4 +753,4 @@ declare class Workspace {
|
|
|
734
753
|
} | null;
|
|
735
754
|
}
|
|
736
755
|
|
|
737
|
-
export { Account as A, type
|
|
756
|
+
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
|
-
|
|
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.
|
|
4
|
-
"description": "Hyperscale crypto wallet management library
|
|
3
|
+
"version": "2.4.0",
|
|
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
|
+
}
|