wative-core 2.4.1 → 2.4.3
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 +20 -0
- package/README.md +59 -55
- 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--npoeR2N.d.ts → container-provider-B8M0ylrK.d.ts} +1 -1
- package/dist/{container-provider-Ca_5z1uQ.d.cts → container-provider-YxyMpkhG.d.cts} +1 -1
- package/dist/{evm-EHpaW_sK.d.ts → evm-Bo3Dy492.d.ts} +1 -1
- package/dist/{evm-hSJJOVG3.d.cts → evm-DA6Sh6jv.d.cts} +1 -1
- package/dist/{file-sink-Bk5zYHw-.d.ts → file-sink-Be5iLbuT.d.ts} +2 -2
- package/dist/{file-sink-7ZAutH45.d.cts → file-sink-KCCpKHRj.d.cts} +2 -2
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +1 -1
- package/dist/index.node.cjs +1 -1
- package/dist/index.node.d.cts +5 -5
- package/dist/index.node.d.ts +5 -5
- 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-B5q8YaV9.d.ts → svm-B51NevS8.d.ts} +1 -1
- package/dist/{svm-CXFwmeMo.d.cts → svm-DswX6XRv.d.cts} +1 -1
- package/dist/{workspace-kq3QyAgm.d.cts → workspace-CBxKR80D.d.cts} +7 -43
- package/dist/{workspace-kq3QyAgm.d.ts → workspace-CBxKR80D.d.ts} +7 -43
- package/examples/01-quick-start.test.cjs +1 -2
- package/examples/02-hd-account.test.cjs +1 -2
- package/examples/03-pk-account.test.cjs +39 -1
- package/examples/04-network-management.test.cjs +1 -2
- package/examples/05-asset-management.test.cjs +1 -2
- package/examples/06-address-signing.test.cjs +1 -2
- package/examples/07-custom-provider.test.cjs +2 -8
- package/examples/08-persistence.test.cjs +1 -2
- package/examples/09-workspace-filter.test.cjs +1 -2
- package/examples/10-default-network.test.cjs +1 -3
- package/examples/11-subpath-imports.test.cjs +2 -6
- package/examples/12-logger.test.cjs +1 -3
- package/examples/13-workspace-config.test.cjs +1 -5
- package/examples/14-esm-runtime.test.mjs +0 -9
- package/examples/15-package-resolution.test.cjs +5 -83
- package/examples/16-known-answer-vectors.test.cjs +4 -22
- package/examples/17-locked-state.test.cjs +2 -23
- package/examples/18-envelope-v3.test.cjs +2 -21
- package/examples/19-simple-provider.test.cjs +1 -19
- package/examples/README.md +1 -1
- package/package.json +1 -1
|
@@ -1,12 +1,4 @@
|
|
|
1
|
-
// 17 —
|
|
2
|
-
// once locked, nothing that touches key material may succeed. The other
|
|
3
|
-
// examples lock at the end of a test but never assert what locking actually
|
|
4
|
-
// enforces, so a regression that left a decrypted key in memory would not fail
|
|
5
|
-
// any of them.
|
|
6
|
-
//
|
|
7
|
-
// This file pins the contract from the outside: which operations refuse, which
|
|
8
|
-
// error code they refuse with, that they hand back no secret material while
|
|
9
|
-
// refusing, and that unlocking restores exactly the previous behaviour.
|
|
1
|
+
// 17 — What locking enforces: which operations refuse, with which code, and unlock parity.
|
|
10
2
|
|
|
11
3
|
const test = require("node:test");
|
|
12
4
|
const assert = require("node:assert");
|
|
@@ -42,15 +34,7 @@ async function freshAccount(tag) {
|
|
|
42
34
|
return { ws, account, wallet, address };
|
|
43
35
|
}
|
|
44
36
|
|
|
45
|
-
/**
|
|
46
|
-
* Assert an operation refuses with the given code.
|
|
47
|
-
*
|
|
48
|
-
* The API deliberately mixes shapes: signing and key export are synchronous
|
|
49
|
-
* (they only touch already-decrypted material), while anything that persists or
|
|
50
|
-
* decrypts is async. Wrapping the call in an async function normalises a
|
|
51
|
-
* synchronous throw and a rejected promise into one thing, so these assertions
|
|
52
|
-
* describe the security contract rather than the call shape.
|
|
53
|
-
*/
|
|
37
|
+
/** Assert an operation refuses with the given code, sync throw or rejection alike. */
|
|
54
38
|
async function refuses(code, label, operation) {
|
|
55
39
|
await assert.rejects(
|
|
56
40
|
async () => operation(),
|
|
@@ -74,8 +58,6 @@ test("a locked account refuses every operation that needs key material", async (
|
|
|
74
58
|
await refuses("ACCOUNT_LOCKED", "signTypedData", () => address.signTypedData(TYPED_DATA));
|
|
75
59
|
await refuses("ACCOUNT_LOCKED", "deriveWallets", () => account.deriveWallets(1));
|
|
76
60
|
|
|
77
|
-
// Refusing with the correct password supplied is the point: possession of the
|
|
78
|
-
// password must not be enough to bypass the lock.
|
|
79
61
|
await ws.unlock("wsp-pwd").catch(() => {});
|
|
80
62
|
});
|
|
81
63
|
|
|
@@ -88,7 +70,6 @@ test("locking the workspace blocks workspace-level mutation too", async () => {
|
|
|
88
70
|
await refuses("WORKSPACE_LOCKED", "accounts.create", () =>
|
|
89
71
|
ws.accounts.create("Other", "wsp-pwd", MNEMONIC),
|
|
90
72
|
);
|
|
91
|
-
// Accounts held from before the lock must not keep signing.
|
|
92
73
|
await refuses("ACCOUNT_LOCKED", "signMessage on a stale handle", () =>
|
|
93
74
|
address.signMessage("hello"),
|
|
94
75
|
);
|
|
@@ -102,8 +83,6 @@ test("a locked account exposes no plaintext secret through its own surface", asy
|
|
|
102
83
|
|
|
103
84
|
await account.lock();
|
|
104
85
|
|
|
105
|
-
// Walk everything reachable from the locked account — the object graph is
|
|
106
|
-
// cyclic (workspace ⇄ account ⇄ wallet), so track visited objects.
|
|
107
86
|
const strings = [];
|
|
108
87
|
const seen = new Set();
|
|
109
88
|
const walk = (value) => {
|
|
@@ -1,15 +1,4 @@
|
|
|
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.
|
|
1
|
+
// 18 — HybridProviderV3 and the v3 envelope, exercised through the published package.
|
|
13
2
|
|
|
14
3
|
const test = require("node:test");
|
|
15
4
|
const assert = require("node:assert");
|
|
@@ -17,11 +6,7 @@ const { mkdtempSync, readFileSync, readdirSync, statSync } = require("node:fs");
|
|
|
17
6
|
const { tmpdir } = require("node:os");
|
|
18
7
|
const { join } = require("node:path");
|
|
19
8
|
|
|
20
|
-
// Both from the SAME entry point
|
|
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.
|
|
9
|
+
// Both from the SAME entry point — each entry is its own bundle with its own classes.
|
|
25
10
|
const { Workspace, HybridProviderV3 } = require("wative-core");
|
|
26
11
|
|
|
27
12
|
const MNEMONIC =
|
|
@@ -60,10 +45,6 @@ test("HybridProviderV3 writes v3 records, and they all share one salt", async ()
|
|
|
60
45
|
);
|
|
61
46
|
}
|
|
62
47
|
|
|
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
48
|
const saltOf = (rel) => readFileSync(join(root, rel)).subarray(1, 17).toString("hex");
|
|
68
49
|
const salts = new Set(names.map(saltOf));
|
|
69
50
|
assert.strictEqual(salts.size, 1, `expected one container salt, got ${salts.size}`);
|
|
@@ -1,14 +1,4 @@
|
|
|
1
|
-
// 19 — The
|
|
2
|
-
//
|
|
3
|
-
// Example 07 extends `Provider` and implements the record layer by hand, which
|
|
4
|
-
// is what you want when the storage system already has its own encryption or
|
|
5
|
-
// its own idea of a record. Most of the time you want this instead: extend
|
|
6
|
-
// `ContainerProvider` and implement six methods that move bytes around. It
|
|
7
|
-
// supplies the container session, the record API and all the encryption, so a
|
|
8
|
-
// working backend is about twenty lines.
|
|
9
|
-
//
|
|
10
|
-
// The store here is a plain Map with no persistence and no cleverness — the
|
|
11
|
-
// point is how little you have to write, not the store itself.
|
|
1
|
+
// 19 — The short way to write a backend: extend ContainerProvider, move bytes, done.
|
|
12
2
|
|
|
13
3
|
const test = require("node:test");
|
|
14
4
|
const assert = require("node:assert");
|
|
@@ -21,8 +11,6 @@ class MapProvider extends ContainerProvider {
|
|
|
21
11
|
#dirs = new Set([""]);
|
|
22
12
|
|
|
23
13
|
_exist(path) {
|
|
24
|
-
// A directory "exists" if anything sits under it — the library asks about
|
|
25
|
-
// both files and directories through this one method.
|
|
26
14
|
if (this.#store.has(path) || this.#dirs.has(path)) return true;
|
|
27
15
|
const prefix = path.endsWith("/") ? path : path + "/";
|
|
28
16
|
for (const k of this.#store.keys()) if (k.startsWith(prefix)) return true;
|
|
@@ -70,7 +58,6 @@ test("a twenty-line backend runs a whole workspace", async () => {
|
|
|
70
58
|
let ws = await Workspace.open({ provider, password: "wsp-pwd" });
|
|
71
59
|
assert.strictEqual(ws.locked, false);
|
|
72
60
|
|
|
73
|
-
// The built-in networks are there, exactly as with any other backend.
|
|
74
61
|
assert.ok(ws.networks.map((n) => n.slug).includes("ethereum"));
|
|
75
62
|
|
|
76
63
|
const acc = await ws.accounts.create(
|
|
@@ -81,7 +68,6 @@ test("a twenty-line backend runs a whole workspace", async () => {
|
|
|
81
68
|
await acc.deriveWallets(2);
|
|
82
69
|
assert.strictEqual(acc.wallets.length, 3);
|
|
83
70
|
|
|
84
|
-
// An address, and a signature from it — the full stack, on a Map.
|
|
85
71
|
const evm = acc.wallets[0].evm;
|
|
86
72
|
assert.match(evm.publicKey, /^0x[0-9a-fA-F]{40}$/);
|
|
87
73
|
const sig = await evm.signMessage("hello from a Map");
|
|
@@ -89,7 +75,6 @@ test("a twenty-line backend runs a whole workspace", async () => {
|
|
|
89
75
|
|
|
90
76
|
await ws.lock();
|
|
91
77
|
|
|
92
|
-
// Reopen from the same store: everything came back.
|
|
93
78
|
ws = await Workspace.open({ provider, password: "wsp-pwd" });
|
|
94
79
|
const again = ws.accounts.bySlug(acc.slug);
|
|
95
80
|
assert.ok(again);
|
|
@@ -101,9 +86,6 @@ test("a twenty-line backend runs a whole workspace", async () => {
|
|
|
101
86
|
});
|
|
102
87
|
|
|
103
88
|
test("the encryption comes with the base class, not with your code", async () => {
|
|
104
|
-
// Nothing above encrypts anything, yet nothing readable reaches the store.
|
|
105
|
-
// That is the reason to extend `ContainerProvider`: a backend cannot weaken
|
|
106
|
-
// the encryption because a backend never performs it.
|
|
107
89
|
const provider = new MapProvider("map://opaque");
|
|
108
90
|
const ws = await Workspace.open({ provider, password: "wsp-pwd" });
|
|
109
91
|
await ws.accounts.create(
|
package/examples/README.md
CHANGED
|
@@ -33,7 +33,7 @@ All tests work fully offline — no RPC calls, no real networks. Each test creat
|
|
|
33
33
|
|---|---|
|
|
34
34
|
| [01-quick-start.test.cjs](01-quick-start.test.cjs) | Open a workspace, create an HD account, derive 5 wallets, inspect EVM + Solana addresses, lock. |
|
|
35
35
|
| [02-hd-account.test.cjs](02-hd-account.test.cjs) | HD-specific flows — deriving / slicing wallets, dumping the mnemonic, account-level passwords with `resetPassword`, round-trip across lock + reopen. |
|
|
36
|
-
| [03-pk-account.test.cjs](03-pk-account.test.cjs) | PK accounts — creating from a private key, importing more keys (
|
|
36
|
+
| [03-pk-account.test.cjs](03-pk-account.test.cjs) | PK accounts — creating from a private key, importing more keys, and the three key formats accepted (EVM hex, Solana base58, `solana-keygen` JSON) with the chain inferred from the key. Also shows each import producing an address on both chains, duplicate-import rejection, and dropping wallets. |
|
|
37
37
|
| [04-network-management.test.cjs](04-network-management.test.cjs) | The 10 pre-loaded networks, adding a brand-new network, overriding a pre-loaded RPC URL via `update()`, dropping user networks, the built-in protection guard. |
|
|
38
38
|
| [05-asset-management.test.cjs](05-asset-management.test.cjs) | The 25 pre-loaded tokens, adding a custom user token, id collision rejection, contract-address collision rejection, dropping user tokens, `workspace.filter(q, "Asset")` search. |
|
|
39
39
|
| [06-address-signing.test.cjs](06-address-signing.test.cjs) | Personal-message signing on EVM and Solana, building a transaction fully offline (no RPC). |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wative-core",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.3",
|
|
4
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",
|