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.
Files changed (53) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +59 -55
  3. package/dist/artifacts/evm/index.cjs +1 -1
  4. package/dist/artifacts/evm/index.d.cts +2 -2
  5. package/dist/artifacts/evm/index.d.ts +2 -2
  6. package/dist/artifacts/evm/index.js +1 -1
  7. package/dist/artifacts/svm/index.cjs +1 -1
  8. package/dist/artifacts/svm/index.d.cts +3 -3
  9. package/dist/artifacts/svm/index.d.ts +3 -3
  10. package/dist/artifacts/svm/index.js +1 -1
  11. package/dist/{container-provider--npoeR2N.d.ts → container-provider-B8M0ylrK.d.ts} +1 -1
  12. package/dist/{container-provider-Ca_5z1uQ.d.cts → container-provider-YxyMpkhG.d.cts} +1 -1
  13. package/dist/{evm-EHpaW_sK.d.ts → evm-Bo3Dy492.d.ts} +1 -1
  14. package/dist/{evm-hSJJOVG3.d.cts → evm-DA6Sh6jv.d.cts} +1 -1
  15. package/dist/{file-sink-Bk5zYHw-.d.ts → file-sink-Be5iLbuT.d.ts} +2 -2
  16. package/dist/{file-sink-7ZAutH45.d.cts → file-sink-KCCpKHRj.d.cts} +2 -2
  17. package/dist/index.cjs +1 -1
  18. package/dist/index.d.cts +6 -6
  19. package/dist/index.d.ts +6 -6
  20. package/dist/index.js +1 -1
  21. package/dist/index.node.cjs +1 -1
  22. package/dist/index.node.d.cts +5 -5
  23. package/dist/index.node.d.ts +5 -5
  24. package/dist/index.node.js +1 -1
  25. package/dist/node/index.cjs +1 -1
  26. package/dist/node/index.d.cts +3 -3
  27. package/dist/node/index.d.ts +3 -3
  28. package/dist/node/index.js +1 -1
  29. package/dist/{svm-B5q8YaV9.d.ts → svm-B51NevS8.d.ts} +1 -1
  30. package/dist/{svm-CXFwmeMo.d.cts → svm-DswX6XRv.d.cts} +1 -1
  31. package/dist/{workspace-kq3QyAgm.d.cts → workspace-CBxKR80D.d.cts} +7 -43
  32. package/dist/{workspace-kq3QyAgm.d.ts → workspace-CBxKR80D.d.ts} +7 -43
  33. package/examples/01-quick-start.test.cjs +1 -2
  34. package/examples/02-hd-account.test.cjs +1 -2
  35. package/examples/03-pk-account.test.cjs +39 -1
  36. package/examples/04-network-management.test.cjs +1 -2
  37. package/examples/05-asset-management.test.cjs +1 -2
  38. package/examples/06-address-signing.test.cjs +1 -2
  39. package/examples/07-custom-provider.test.cjs +2 -8
  40. package/examples/08-persistence.test.cjs +1 -2
  41. package/examples/09-workspace-filter.test.cjs +1 -2
  42. package/examples/10-default-network.test.cjs +1 -3
  43. package/examples/11-subpath-imports.test.cjs +2 -6
  44. package/examples/12-logger.test.cjs +1 -3
  45. package/examples/13-workspace-config.test.cjs +1 -5
  46. package/examples/14-esm-runtime.test.mjs +0 -9
  47. package/examples/15-package-resolution.test.cjs +5 -83
  48. package/examples/16-known-answer-vectors.test.cjs +4 -22
  49. package/examples/17-locked-state.test.cjs +2 -23
  50. package/examples/18-envelope-v3.test.cjs +2 -21
  51. package/examples/19-simple-provider.test.cjs +1 -19
  52. package/examples/README.md +1 -1
  53. package/package.json +1 -1
@@ -1,12 +1,4 @@
1
- // 17 — Locked-state contract. Locking is the library's core safety promise:
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, 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.
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 SHORT way to write a storage backend.
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(
@@ -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 (mix EVM + Solana under one account), duplicate-import rejection, dropping wallets. |
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.1",
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",