@unlink-xyz/core 0.1.3 → 0.1.4
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/README.md +9 -0
- package/dist/account/{zkAccount.d.ts → account.d.ts} +36 -5
- package/dist/account/account.d.ts.map +1 -0
- package/dist/account/accounts.d.ts +42 -0
- package/dist/account/accounts.d.ts.map +1 -0
- package/dist/account/seed.d.ts +45 -0
- package/dist/account/seed.d.ts.map +1 -0
- package/dist/account/serialization.d.ts +6 -0
- package/dist/account/serialization.d.ts.map +1 -0
- package/dist/browser/index.js +56221 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/wallet/index.js +55942 -0
- package/dist/browser/wallet/index.js.map +1 -0
- package/dist/clients/broadcaster.d.ts +8 -2
- package/dist/clients/broadcaster.d.ts.map +1 -1
- package/dist/clients/http.d.ts +6 -0
- package/dist/clients/http.d.ts.map +1 -1
- package/dist/clients/indexer.d.ts +16 -0
- package/dist/clients/indexer.d.ts.map +1 -1
- package/dist/config.d.ts +30 -9
- package/dist/config.d.ts.map +1 -1
- package/dist/constants.d.ts +6 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/core.d.ts.map +1 -1
- package/dist/crypto/adapters/index.d.ts +17 -0
- package/dist/crypto/adapters/index.d.ts.map +1 -0
- package/dist/crypto/adapters/polyfills.d.ts +5 -0
- package/dist/crypto/adapters/polyfills.d.ts.map +1 -0
- package/dist/crypto/encrypt.d.ts +33 -0
- package/dist/crypto/encrypt.d.ts.map +1 -0
- package/dist/crypto/secure-memory.d.ts +25 -0
- package/dist/crypto/secure-memory.d.ts.map +1 -0
- package/dist/errors.d.ts +17 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/history/index.d.ts +3 -0
- package/dist/history/index.d.ts.map +1 -0
- package/dist/history/service.d.ts +46 -0
- package/dist/history/service.d.ts.map +1 -0
- package/dist/history/types.d.ts +21 -0
- package/dist/history/types.d.ts.map +1 -0
- package/dist/index.d.ts +16 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6721 -19
- package/dist/index.js.map +1 -0
- package/dist/keys/address.d.ts +13 -0
- package/dist/keys/address.d.ts.map +1 -0
- package/dist/keys/derive.d.ts +37 -0
- package/dist/keys/derive.d.ts.map +1 -0
- package/dist/keys/hex.d.ts +14 -0
- package/dist/keys/hex.d.ts.map +1 -0
- package/dist/keys/index.d.ts +5 -0
- package/dist/keys/index.d.ts.map +1 -0
- package/dist/keys/mnemonic.d.ts +6 -0
- package/dist/keys/mnemonic.d.ts.map +1 -0
- package/dist/keys.d.ts +5 -1
- package/dist/keys.d.ts.map +1 -1
- package/dist/prover/config.d.ts +53 -22
- package/dist/prover/config.d.ts.map +1 -1
- package/dist/prover/integrity.d.ts +20 -0
- package/dist/prover/integrity.d.ts.map +1 -0
- package/dist/prover/prover.d.ts +16 -20
- package/dist/prover/prover.d.ts.map +1 -1
- package/dist/prover/registry.d.ts +3 -30
- package/dist/prover/registry.d.ts.map +1 -1
- package/dist/state/merkle/hydrator.d.ts +21 -19
- package/dist/state/merkle/hydrator.d.ts.map +1 -1
- package/dist/state/merkle/index.d.ts +2 -2
- package/dist/state/merkle/index.d.ts.map +1 -1
- package/dist/state/merkle/merkle-tree.d.ts +8 -0
- package/dist/state/merkle/merkle-tree.d.ts.map +1 -1
- package/dist/state/store/ciphertext-store.d.ts +11 -0
- package/dist/state/store/ciphertext-store.d.ts.map +1 -1
- package/dist/state/store/history-store.d.ts +24 -0
- package/dist/state/store/history-store.d.ts.map +1 -0
- package/dist/state/store/index.d.ts +3 -2
- package/dist/state/store/index.d.ts.map +1 -1
- package/dist/state/store/job-store.d.ts +7 -7
- package/dist/state/store/job-store.d.ts.map +1 -1
- package/dist/state/store/jobs.d.ts +70 -25
- package/dist/state/store/jobs.d.ts.map +1 -1
- package/dist/state/store/leaf-store.d.ts +4 -0
- package/dist/state/store/leaf-store.d.ts.map +1 -1
- package/dist/state/store/note-store.d.ts +7 -7
- package/dist/state/store/note-store.d.ts.map +1 -1
- package/dist/state/store/nullifier-store.d.ts +9 -0
- package/dist/state/store/nullifier-store.d.ts.map +1 -1
- package/dist/state/store/records.d.ts +39 -2
- package/dist/state/store/records.d.ts.map +1 -1
- package/dist/state/store/root-store.d.ts.map +1 -1
- package/dist/state/store/store.d.ts +79 -27
- package/dist/state/store/store.d.ts.map +1 -1
- package/dist/storage/indexeddb.d.ts.map +1 -1
- package/dist/storage/memory.d.ts.map +1 -1
- package/dist/transactions/adapter.d.ts +31 -0
- package/dist/transactions/adapter.d.ts.map +1 -0
- package/dist/transactions/deposit.d.ts +12 -15
- package/dist/transactions/deposit.d.ts.map +1 -1
- package/dist/transactions/index.d.ts +9 -4
- package/dist/transactions/index.d.ts.map +1 -1
- package/dist/transactions/note-selection.d.ts +17 -0
- package/dist/transactions/note-selection.d.ts.map +1 -0
- package/dist/transactions/note-sync.d.ts +5 -33
- package/dist/transactions/note-sync.d.ts.map +1 -1
- package/dist/transactions/reconcile.d.ts +9 -11
- package/dist/transactions/reconcile.d.ts.map +1 -1
- package/dist/transactions/transact.d.ts +30 -22
- package/dist/transactions/transact.d.ts.map +1 -1
- package/dist/transactions/transaction-planner.d.ts +34 -0
- package/dist/transactions/transaction-planner.d.ts.map +1 -0
- package/dist/transactions/transfer-planner.d.ts +37 -0
- package/dist/transactions/transfer-planner.d.ts.map +1 -0
- package/dist/transactions/types/deposit.d.ts +67 -0
- package/dist/transactions/types/deposit.d.ts.map +1 -0
- package/dist/transactions/types/domain.d.ts +70 -0
- package/dist/transactions/types/domain.d.ts.map +1 -0
- package/dist/transactions/types/index.d.ts +18 -0
- package/dist/transactions/types/index.d.ts.map +1 -0
- package/dist/transactions/types/options.d.ts +54 -0
- package/dist/transactions/types/options.d.ts.map +1 -0
- package/dist/transactions/types/planning.d.ts +82 -0
- package/dist/transactions/types/planning.d.ts.map +1 -0
- package/dist/transactions/types/state-stores.d.ts +151 -0
- package/dist/transactions/types/state-stores.d.ts.map +1 -0
- package/dist/transactions/types/transact.d.ts +83 -0
- package/dist/transactions/types/transact.d.ts.map +1 -0
- package/dist/transactions/withdrawal-planner.d.ts +58 -0
- package/dist/transactions/withdrawal-planner.d.ts.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/tsup.browser.config.d.ts +7 -0
- package/dist/tsup.browser.config.d.ts.map +1 -0
- package/dist/tsup.config.d.ts +8 -0
- package/dist/tsup.config.d.ts.map +1 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/amounts.d.ts +26 -0
- package/dist/utils/amounts.d.ts.map +1 -0
- package/dist/utils/async.d.ts +9 -0
- package/dist/utils/async.d.ts.map +1 -1
- package/dist/utils/async.js +38 -11
- package/dist/utils/async.js.map +1 -0
- package/dist/utils/bigint.d.ts +0 -2
- package/dist/utils/bigint.d.ts.map +1 -1
- package/dist/utils/format.d.ts +25 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/notes.d.ts +15 -0
- package/dist/utils/notes.d.ts.map +1 -0
- package/dist/utils/polling.d.ts +5 -0
- package/dist/utils/polling.d.ts.map +1 -1
- package/dist/utils/random.d.ts +18 -0
- package/dist/utils/random.d.ts.map +1 -0
- package/dist/utils/signature.d.ts +6 -0
- package/dist/utils/signature.d.ts.map +1 -1
- package/dist/utils/validators.d.ts +21 -10
- package/dist/utils/validators.d.ts.map +1 -1
- package/dist/vitest.config.d.ts +3 -0
- package/dist/vitest.config.d.ts.map +1 -0
- package/dist/wallet/adapter.d.ts +21 -0
- package/dist/wallet/adapter.d.ts.map +1 -0
- package/dist/wallet/burner/service.d.ts +32 -0
- package/dist/wallet/burner/service.d.ts.map +1 -0
- package/dist/wallet/burner/types.d.ts +47 -0
- package/dist/wallet/burner/types.d.ts.map +1 -0
- package/dist/wallet/index.d.ts +20 -0
- package/dist/wallet/index.d.ts.map +1 -0
- package/dist/wallet/index.js +6462 -0
- package/dist/wallet/index.js.map +1 -0
- package/dist/wallet/sdk.d.ts +48 -0
- package/dist/wallet/sdk.d.ts.map +1 -0
- package/dist/wallet/types.d.ts +457 -0
- package/dist/wallet/types.d.ts.map +1 -0
- package/dist/wallet/unlink-wallet.d.ts +187 -0
- package/dist/wallet/unlink-wallet.d.ts.map +1 -0
- package/package.json +38 -15
- package/.eslintrc.json +0 -4
- package/account/zkAccount.test.ts +0 -316
- package/account/zkAccount.ts +0 -222
- package/circuits.json +0 -26
- package/clients/broadcaster.ts +0 -67
- package/clients/http.ts +0 -94
- package/clients/indexer.ts +0 -150
- package/config.ts +0 -39
- package/core.ts +0 -17
- package/dist/account/railgun-imports-prototype.d.ts +0 -12
- package/dist/account/railgun-imports-prototype.d.ts.map +0 -1
- package/dist/account/railgun-imports-prototype.js +0 -30
- package/dist/account/zkAccount.d.ts.map +0 -1
- package/dist/account/zkAccount.js +0 -128
- package/dist/circuits.json +0 -26
- package/dist/clients/broadcaster.js +0 -23
- package/dist/clients/http.js +0 -57
- package/dist/clients/indexer.js +0 -67
- package/dist/config.js +0 -29
- package/dist/core.js +0 -12
- package/dist/errors.js +0 -18
- package/dist/key-derivation/babyjubjub.d.ts +0 -9
- package/dist/key-derivation/babyjubjub.d.ts.map +0 -1
- package/dist/key-derivation/babyjubjub.js +0 -9
- package/dist/key-derivation/bech32.d.ts +0 -22
- package/dist/key-derivation/bech32.d.ts.map +0 -1
- package/dist/key-derivation/bech32.js +0 -86
- package/dist/key-derivation/bip32.d.ts +0 -17
- package/dist/key-derivation/bip32.d.ts.map +0 -1
- package/dist/key-derivation/bip32.js +0 -41
- package/dist/key-derivation/bip39.d.ts +0 -22
- package/dist/key-derivation/bip39.d.ts.map +0 -1
- package/dist/key-derivation/bip39.js +0 -56
- package/dist/key-derivation/bytes.d.ts +0 -19
- package/dist/key-derivation/bytes.d.ts.map +0 -1
- package/dist/key-derivation/bytes.js +0 -92
- package/dist/key-derivation/hash.d.ts +0 -3
- package/dist/key-derivation/hash.d.ts.map +0 -1
- package/dist/key-derivation/hash.js +0 -10
- package/dist/key-derivation/index.d.ts +0 -8
- package/dist/key-derivation/index.d.ts.map +0 -1
- package/dist/key-derivation/index.js +0 -7
- package/dist/key-derivation/wallet-node.d.ts +0 -45
- package/dist/key-derivation/wallet-node.d.ts.map +0 -1
- package/dist/key-derivation/wallet-node.js +0 -109
- package/dist/keys.js +0 -41
- package/dist/prover/config.js +0 -80
- package/dist/prover/index.js +0 -1
- package/dist/prover/prover.js +0 -274
- package/dist/prover/registry.js +0 -57
- package/dist/schema.js +0 -14
- package/dist/state/ciphertext-store.d.ts +0 -12
- package/dist/state/ciphertext-store.d.ts.map +0 -1
- package/dist/state/ciphertext-store.js +0 -25
- package/dist/state/hydrator.d.ts +0 -16
- package/dist/state/hydrator.d.ts.map +0 -1
- package/dist/state/hydrator.js +0 -18
- package/dist/state/index.js +0 -2
- package/dist/state/job-store.d.ts +0 -12
- package/dist/state/job-store.d.ts.map +0 -1
- package/dist/state/job-store.js +0 -118
- package/dist/state/jobs.d.ts +0 -50
- package/dist/state/jobs.d.ts.map +0 -1
- package/dist/state/jobs.js +0 -1
- package/dist/state/leaf-store.d.ts +0 -17
- package/dist/state/leaf-store.d.ts.map +0 -1
- package/dist/state/leaf-store.js +0 -35
- package/dist/state/merkle/hydrator.js +0 -36
- package/dist/state/merkle/index.js +0 -2
- package/dist/state/merkle/merkle-tree.js +0 -104
- package/dist/state/merkle-tree.d.ts +0 -34
- package/dist/state/merkle-tree.d.ts.map +0 -1
- package/dist/state/merkle-tree.js +0 -104
- package/dist/state/note-store.d.ts +0 -37
- package/dist/state/note-store.d.ts.map +0 -1
- package/dist/state/note-store.js +0 -133
- package/dist/state/nullifier-store.d.ts +0 -13
- package/dist/state/nullifier-store.d.ts.map +0 -1
- package/dist/state/nullifier-store.js +0 -21
- package/dist/state/records.d.ts +0 -57
- package/dist/state/records.d.ts.map +0 -1
- package/dist/state/records.js +0 -1
- package/dist/state/root-store.d.ts +0 -13
- package/dist/state/root-store.d.ts.map +0 -1
- package/dist/state/root-store.js +0 -30
- package/dist/state/store/ciphertext-store.js +0 -25
- package/dist/state/store/index.js +0 -8
- package/dist/state/store/job-store.js +0 -118
- package/dist/state/store/jobs.js +0 -1
- package/dist/state/store/leaf-store.js +0 -35
- package/dist/state/store/note-store.js +0 -142
- package/dist/state/store/nullifier-store.js +0 -30
- package/dist/state/store/records.js +0 -1
- package/dist/state/store/root-store.js +0 -30
- package/dist/state/store/store.js +0 -22
- package/dist/state/store.d.ts +0 -26
- package/dist/state/store.d.ts.map +0 -1
- package/dist/state/store.js +0 -19
- package/dist/state.d.ts +0 -83
- package/dist/state.d.ts.map +0 -1
- package/dist/state.js +0 -171
- package/dist/storage/index.js +0 -2
- package/dist/storage/indexeddb.js +0 -205
- package/dist/storage/memory.js +0 -87
- package/dist/transactions/deposit.js +0 -169
- package/dist/transactions/index.js +0 -4
- package/dist/transactions/note-sync.js +0 -320
- package/dist/transactions/reconcile.js +0 -39
- package/dist/transactions/shield.d.ts +0 -5
- package/dist/transactions/shield.d.ts.map +0 -1
- package/dist/transactions/shield.js +0 -93
- package/dist/transactions/transact.js +0 -561
- package/dist/transactions/types.d.ts +0 -114
- package/dist/transactions/types.d.ts.map +0 -1
- package/dist/transactions/types.js +0 -1
- package/dist/transactions/utils.d.ts +0 -10
- package/dist/transactions/utils.d.ts.map +0 -1
- package/dist/transactions/utils.js +0 -17
- package/dist/types.js +0 -1
- package/dist/utils/bigint.js +0 -29
- package/dist/utils/crypto.d.ts +0 -12
- package/dist/utils/crypto.d.ts.map +0 -1
- package/dist/utils/crypto.js +0 -39
- package/dist/utils/json-codec.js +0 -25
- package/dist/utils/polling.js +0 -6
- package/dist/utils/signature.js +0 -12
- package/dist/utils/time.d.ts +0 -2
- package/dist/utils/time.d.ts.map +0 -1
- package/dist/utils/time.js +0 -3
- package/dist/utils/validators.js +0 -70
- package/dist/utils/witness.d.ts +0 -11
- package/dist/utils/witness.d.ts.map +0 -1
- package/dist/utils/witness.js +0 -19
- package/errors.ts +0 -20
- package/index.ts +0 -21
- package/key-derivation/babyjubjub.ts +0 -11
- package/key-derivation/bech32.test.ts +0 -90
- package/key-derivation/bech32.ts +0 -124
- package/key-derivation/bip32.ts +0 -56
- package/key-derivation/bip39.ts +0 -76
- package/key-derivation/bytes.ts +0 -118
- package/key-derivation/hash.ts +0 -13
- package/key-derivation/index.ts +0 -7
- package/key-derivation/wallet-node.ts +0 -155
- package/keys.ts +0 -47
- package/prover/config.ts +0 -104
- package/prover/index.ts +0 -1
- package/prover/prover.integration.test.ts +0 -162
- package/prover/prover.test.ts +0 -309
- package/prover/prover.ts +0 -405
- package/prover/registry.test.ts +0 -90
- package/prover/registry.ts +0 -82
- package/schema.ts +0 -17
- package/setup-artifacts.sh +0 -57
- package/state/index.ts +0 -2
- package/state/merkle/hydrator.ts +0 -69
- package/state/merkle/index.ts +0 -12
- package/state/merkle/merkle-tree.test.ts +0 -50
- package/state/merkle/merkle-tree.ts +0 -163
- package/state/store/ciphertext-store.ts +0 -28
- package/state/store/index.ts +0 -24
- package/state/store/job-store.ts +0 -162
- package/state/store/jobs.ts +0 -64
- package/state/store/leaf-store.ts +0 -39
- package/state/store/note-store.ts +0 -177
- package/state/store/nullifier-store.ts +0 -39
- package/state/store/records.ts +0 -61
- package/state/store/root-store.ts +0 -34
- package/state/store/store.ts +0 -25
- package/state.test.ts +0 -235
- package/storage/index.ts +0 -3
- package/storage/indexeddb.test.ts +0 -99
- package/storage/indexeddb.ts +0 -235
- package/storage/memory.test.ts +0 -59
- package/storage/memory.ts +0 -93
- package/transactions/deposit.test.ts +0 -160
- package/transactions/deposit.ts +0 -227
- package/transactions/index.ts +0 -20
- package/transactions/note-sync.test.ts +0 -155
- package/transactions/note-sync.ts +0 -452
- package/transactions/reconcile.ts +0 -73
- package/transactions/transact.test.ts +0 -451
- package/transactions/transact.ts +0 -811
- package/transactions/types.ts +0 -141
- package/tsconfig.json +0 -15
- package/types/global.d.ts +0 -15
- package/types.ts +0 -24
- package/utils/async.ts +0 -15
- package/utils/bigint.ts +0 -34
- package/utils/crypto.test.ts +0 -69
- package/utils/crypto.ts +0 -58
- package/utils/json-codec.ts +0 -38
- package/utils/polling.ts +0 -6
- package/utils/signature.ts +0 -16
- package/utils/validators.test.ts +0 -64
- package/utils/validators.ts +0 -86
package/state.test.ts
DELETED
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
import "fake-indexeddb/auto";
|
|
2
|
-
|
|
3
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
4
|
-
|
|
5
|
-
import { createStateStore } from "./state/index.js";
|
|
6
|
-
import {
|
|
7
|
-
createIndexedDbStorage,
|
|
8
|
-
createMemoryStorage,
|
|
9
|
-
} from "./storage/index.js";
|
|
10
|
-
import type { Storage } from "./types.js";
|
|
11
|
-
|
|
12
|
-
type StoreFactory = {
|
|
13
|
-
name: string;
|
|
14
|
-
setup(): Promise;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
async function deleteIndexeddbDatabase(name: string) {
|
|
18
|
-
await new Promise<void>((resolve, reject) => {
|
|
19
|
-
const request = indexedDB.deleteDatabase(name);
|
|
20
|
-
request.onsuccess = () => resolve();
|
|
21
|
-
request.onerror = () =>
|
|
22
|
-
reject(request.error ?? new Error("failed to delete indexedDB"));
|
|
23
|
-
request.onblocked = () =>
|
|
24
|
-
reject(new Error("indexedDB deletion was blocked"));
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const factories: StoreFactory[] = [
|
|
29
|
-
{
|
|
30
|
-
name: "memory",
|
|
31
|
-
async setup() {
|
|
32
|
-
const storage = createMemoryStorage();
|
|
33
|
-
await storage.open();
|
|
34
|
-
return { storage };
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
name: "indexeddb",
|
|
39
|
-
async setup() {
|
|
40
|
-
const dbName = `unlink-state-test-${Math.random().toString(6)}`;
|
|
41
|
-
await deleteIndexeddbDatabase(dbName).catch(() => {});
|
|
42
|
-
const storage = createIndexedDbStorage({ name: dbName });
|
|
43
|
-
await storage.open();
|
|
44
|
-
return {
|
|
45
|
-
storage,
|
|
46
|
-
cleanup: () => deleteIndexeddbDatabase(dbName).catch(() => {}),
|
|
47
|
-
};
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
|
-
];
|
|
51
|
-
|
|
52
|
-
describe.each(factories)("state store (%s)", ({ name, setup }) => {
|
|
53
|
-
let storage: Storage;
|
|
54
|
-
let cleanup: (() => Promise) | undefined;
|
|
55
|
-
let state: ReturnType;
|
|
56
|
-
|
|
57
|
-
beforeEach(async () => {
|
|
58
|
-
const prepared = await setup();
|
|
59
|
-
storage = prepared.storage;
|
|
60
|
-
cleanup = prepared.cleanup;
|
|
61
|
-
state = createStateStore(storage);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
afterEach(async () => {
|
|
65
|
-
await cleanup?.();
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it(`stores and loads note records [${name}]`, async () => {
|
|
69
|
-
const inserted = {
|
|
70
|
-
chainId: 1,
|
|
71
|
-
index: 5,
|
|
72
|
-
token: "0xToken",
|
|
73
|
-
value: "42",
|
|
74
|
-
commitment: "0xcommitment",
|
|
75
|
-
npk: "0xnpk",
|
|
76
|
-
mpk: "0xmpk",
|
|
77
|
-
random: "0xrandom",
|
|
78
|
-
nullifier: "0xnullifier",
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
await state.putNote(inserted);
|
|
82
|
-
|
|
83
|
-
const fetched = await state.getNote(1, 5);
|
|
84
|
-
expect(fetched).toEqual(inserted);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it(`stores and loads nullifier records [${name}]`, async () => {
|
|
88
|
-
const inserted = {
|
|
89
|
-
chainId: 1,
|
|
90
|
-
nullifier: "0xdeadbeef",
|
|
91
|
-
noteIndex: 12,
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
await state.putNullifier(inserted);
|
|
95
|
-
|
|
96
|
-
const fetched = await state.getNullifier(1, "0xdeadbeef");
|
|
97
|
-
expect(fetched).toEqual(inserted);
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it(`stores and loads leaf records [${name}]`, async () => {
|
|
101
|
-
const inserted = {
|
|
102
|
-
chainId: 137,
|
|
103
|
-
index: 2,
|
|
104
|
-
commitment: "0xleaf",
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
await state.putLeaf(inserted);
|
|
108
|
-
|
|
109
|
-
const fetched = await state.getLeaf(137, 2);
|
|
110
|
-
expect(fetched).toEqual(inserted);
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it(`stores and loads root records [${name}]`, async () => {
|
|
114
|
-
const inserted = {
|
|
115
|
-
chainId: 10,
|
|
116
|
-
root: "0xroot",
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
await state.putRoot(inserted);
|
|
120
|
-
|
|
121
|
-
const fetched = await state.getRoot(10, "0xroot");
|
|
122
|
-
expect(fetched).toEqual(inserted);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it(`stores ciphertext payloads [${name}]`, async () => {
|
|
126
|
-
const payload = new Uint8Array([1, 2, 3, 4]);
|
|
127
|
-
|
|
128
|
-
await state.putCiphertext(1, 7, payload);
|
|
129
|
-
|
|
130
|
-
const fetched = await state.getCiphertext(1, 7);
|
|
131
|
-
expect(fetched).not.toBeNull();
|
|
132
|
-
expect(fetched).toEqual(payload);
|
|
133
|
-
|
|
134
|
-
if (fetched) {
|
|
135
|
-
fetched[0] = 99;
|
|
136
|
-
const second = await state.getCiphertext(1, 7);
|
|
137
|
-
expect(second).toEqual(payload);
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
it(`lists notes by account and spent status [${name}]`, async () => {
|
|
142
|
-
const mpkA = "0xmpkA";
|
|
143
|
-
const mpkB = "0xmpkB";
|
|
144
|
-
|
|
145
|
-
const base = {
|
|
146
|
-
chainId: 1,
|
|
147
|
-
token: "0xToken",
|
|
148
|
-
value: "5",
|
|
149
|
-
commitment: "0xcommitment",
|
|
150
|
-
npk: "0xnpk",
|
|
151
|
-
random: "0xrandom",
|
|
152
|
-
} as const;
|
|
153
|
-
|
|
154
|
-
await state.putNote({
|
|
155
|
-
...base,
|
|
156
|
-
index: 1,
|
|
157
|
-
nullifier: "0xnullifier1",
|
|
158
|
-
mpk: mpkA,
|
|
159
|
-
});
|
|
160
|
-
await state.putNote({
|
|
161
|
-
...base,
|
|
162
|
-
index: 2,
|
|
163
|
-
nullifier: "0xnullifier2",
|
|
164
|
-
mpk: mpkA,
|
|
165
|
-
});
|
|
166
|
-
await state.putNote({
|
|
167
|
-
...base,
|
|
168
|
-
index: 3,
|
|
169
|
-
nullifier: "0xnullifier3",
|
|
170
|
-
mpk: mpkB,
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
await state.markNoteSpent(1, 2, 123);
|
|
174
|
-
|
|
175
|
-
const allForA = await state.listNotes({ mpk: mpkA });
|
|
176
|
-
expect(allForA.map((n) => n.index).sort((a, b) => a - b)).toEqual([1, 2]);
|
|
177
|
-
|
|
178
|
-
const activeForA = await state.listNotes({
|
|
179
|
-
mpk: mpkA,
|
|
180
|
-
includeSpent: false,
|
|
181
|
-
});
|
|
182
|
-
expect(activeForA.map((n) => n.index)).toEqual([1]);
|
|
183
|
-
|
|
184
|
-
const allForB = await state.listNotes({ mpk: mpkB });
|
|
185
|
-
expect(allForB).toHaveLength(1);
|
|
186
|
-
expect(allForB[0]?.index).toBe(3);
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
it(`aggregates zk balances per asset [${name}]`, async () => {
|
|
190
|
-
const mpk = "0xmpkBalance";
|
|
191
|
-
|
|
192
|
-
const note = (index: number, overrides: Partial = {}) => ({
|
|
193
|
-
chainId: 1,
|
|
194
|
-
index,
|
|
195
|
-
token: "0xTokenA",
|
|
196
|
-
value: `${index * 10}`,
|
|
197
|
-
commitment: `0xcommit-${index}`,
|
|
198
|
-
npk: `0xnpk-${index}`,
|
|
199
|
-
mpk,
|
|
200
|
-
random: `0xrandom-${index}`,
|
|
201
|
-
nullifier: `0xnullifier-${index}`,
|
|
202
|
-
...overrides,
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
await state.putNote(note(1, { value: "100" }));
|
|
206
|
-
await state.putNote(note(2, { value: "50" }));
|
|
207
|
-
await state.putNote(
|
|
208
|
-
note(3, { token: "0xTokenB", value: "5", nullifier: "0xnullifier-b" }),
|
|
209
|
-
);
|
|
210
|
-
await state.putNote(
|
|
211
|
-
note(4, {
|
|
212
|
-
mpk: "0xother",
|
|
213
|
-
nullifier: "0xnullifier-other",
|
|
214
|
-
value: "999",
|
|
215
|
-
}),
|
|
216
|
-
);
|
|
217
|
-
|
|
218
|
-
await state.markNoteSpent(1, 2, 456);
|
|
219
|
-
|
|
220
|
-
const balances = await state.getZkBalances(mpk, { chainId: 1 });
|
|
221
|
-
expect(balances).toEqual({
|
|
222
|
-
"0xTokenA": 100n,
|
|
223
|
-
"0xTokenB": 5n,
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
await state.markNoteUnspent(1, 2);
|
|
227
|
-
const balancesAfterReopen = await state.getZkBalances(mpk, {
|
|
228
|
-
chainId: 1,
|
|
229
|
-
});
|
|
230
|
-
expect(balancesAfterReopen).toEqual({
|
|
231
|
-
"0xTokenA": 150n,
|
|
232
|
-
"0xTokenB": 5n,
|
|
233
|
-
});
|
|
234
|
-
});
|
|
235
|
-
});
|
package/storage/index.ts
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import "fake-indexeddb/auto";
|
|
2
|
-
|
|
3
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
4
|
-
|
|
5
|
-
import { CoreError, KeyValidationError } from "../errors.js";
|
|
6
|
-
import { MAX_KEY_LEN } from "../keys.js";
|
|
7
|
-
import type { Storage } from "../types.js";
|
|
8
|
-
import { createIndexedDbStorage } from "./indexeddb.js";
|
|
9
|
-
|
|
10
|
-
const encoder = new TextEncoder();
|
|
11
|
-
let dbName = "unlink-core-test";
|
|
12
|
-
|
|
13
|
-
function deleteDatabase(name: string) {
|
|
14
|
-
return new Promise<void>((resolve, reject) => {
|
|
15
|
-
const request = indexedDB.deleteDatabase(name);
|
|
16
|
-
request.onsuccess = () => resolve();
|
|
17
|
-
request.onerror = () =>
|
|
18
|
-
reject(request.error ?? new Error("failed to delete indexedDB"));
|
|
19
|
-
request.onblocked = () =>
|
|
20
|
-
reject(new Error("indexedDB deletion was blocked"));
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
describe("createIndexedDbStorage", () => {
|
|
25
|
-
let storage: Storage;
|
|
26
|
-
|
|
27
|
-
beforeEach(async () => {
|
|
28
|
-
dbName = `unlink-core-test-${Math.random().toString(6)}`;
|
|
29
|
-
await deleteDatabase(dbName).catch(() => {});
|
|
30
|
-
storage = createIndexedDbStorage({ name: dbName });
|
|
31
|
-
await storage.open();
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
afterEach(async () => {
|
|
35
|
-
await deleteDatabase(dbName).catch(() => {});
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it("returns null when key is missing", async () => {
|
|
39
|
-
const value = await storage.get("meta:missing");
|
|
40
|
-
expect(value).toBeNull();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it("roundtrips put/get values", async () => {
|
|
44
|
-
await storage.put("meta:key", encoder.encode("value"));
|
|
45
|
-
const value = await storage.get("meta:key");
|
|
46
|
-
expect(value).toEqual(encoder.encode("value"));
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it("roundtrips schema version", async () => {
|
|
50
|
-
await storage.setSchemaVersion(3);
|
|
51
|
-
const version = await storage.getSchemaVersion();
|
|
52
|
-
expect(version).toBe(3);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it("rejects iter calls when start bound exceeds end bound", async () => {
|
|
56
|
-
await expect(
|
|
57
|
-
storage.iter({ start: "notes:z", end: "notes:a" }),
|
|
58
|
-
).rejects.toBeInstanceOf(CoreError);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it("supports prefix, limit, and reverse iteration", async () => {
|
|
62
|
-
await storage.put("notes:a", encoder.encode("1"));
|
|
63
|
-
await storage.put("notes:b", encoder.encode("2"));
|
|
64
|
-
await storage.put("notes:c", encoder.encode("3"));
|
|
65
|
-
await storage.put("meta:other", encoder.encode("x"));
|
|
66
|
-
|
|
67
|
-
const forward = await storage.iter({
|
|
68
|
-
prefix: "notes:",
|
|
69
|
-
limit: 2,
|
|
70
|
-
});
|
|
71
|
-
expect(forward.map((p) => p.key)).toEqual(["notes:a", "notes:b"]);
|
|
72
|
-
|
|
73
|
-
const reverse = await storage.iter({
|
|
74
|
-
prefix: "notes:",
|
|
75
|
-
reverse: true,
|
|
76
|
-
limit: 1,
|
|
77
|
-
});
|
|
78
|
-
expect(reverse.map((p) => p.key)).toEqual(["notes:c"]);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it("keeps batch atomic when validation fails", async () => {
|
|
82
|
-
await storage.put("meta:ok", encoder.encode("1"));
|
|
83
|
-
|
|
84
|
-
const oversizedKey = "a".repeat(MAX_KEY_LEN + 1);
|
|
85
|
-
await expect(
|
|
86
|
-
storage.batch([
|
|
87
|
-
{ del: "meta:ok" },
|
|
88
|
-
{ put: ["notes:new", encoder.encode("value")] },
|
|
89
|
-
{ put: [oversizedKey, encoder.encode("bad")] },
|
|
90
|
-
]),
|
|
91
|
-
).rejects.toBeInstanceOf(KeyValidationError);
|
|
92
|
-
|
|
93
|
-
const original = await storage.get("meta:ok");
|
|
94
|
-
expect(original).toEqual(encoder.encode("1"));
|
|
95
|
-
|
|
96
|
-
const missing = await storage.get("notes:new");
|
|
97
|
-
expect(missing).toBeNull();
|
|
98
|
-
});
|
|
99
|
-
});
|
package/storage/indexeddb.ts
DELETED
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* IndexedDB-backed key/value storage for Unlink Core.
|
|
3
|
-
*
|
|
4
|
-
* What this is
|
|
5
|
-
* - A durable, transactional KV store implemented on top of the browser's IndexedDB.
|
|
6
|
-
* - Two object stores: "kv" for app data, "meta" for schema/versioning.
|
|
7
|
-
*
|
|
8
|
-
* Why we implement it
|
|
9
|
-
* - We need persistent client-side state (notes, leaves, nullifiers, cfg, etc.) that survives reloads
|
|
10
|
-
* and works in both web apps and browser extensions without introducing a new backend.
|
|
11
|
-
*
|
|
12
|
-
* When to use
|
|
13
|
-
* - Browser UIs and extensions (MV2/MV3) where persistence is required.
|
|
14
|
-
* - Any environment with a real IndexedDB (tests use `fake-indexeddb`).
|
|
15
|
-
*
|
|
16
|
-
* Trade-offs
|
|
17
|
-
* - 👍 Durable, quota-managed, non-blocking, transactional writes (atomic batch).
|
|
18
|
-
* - 👍 Works offline; no server dependency.
|
|
19
|
-
* - ⚠️ Not natively available in Node/SSR; needs a polyfill for tests only.
|
|
20
|
-
*
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
import { CoreError } from "../errors.js";
|
|
24
|
-
import { validateKey } from "../keys.js";
|
|
25
|
-
import type { BatchOp, Bytes, IterOptions, KvPair, Storage } from "../types.js";
|
|
26
|
-
|
|
27
|
-
const DEFAULT_DB_NAME = "unlink-core";
|
|
28
|
-
const DB_VERSION = 1;
|
|
29
|
-
const KV_STORE = "kv";
|
|
30
|
-
const META_STORE = "meta";
|
|
31
|
-
const SCHEMA_KEY = "schema_version";
|
|
32
|
-
|
|
33
|
-
const copy = (value: Bytes) => new Uint8Array(value);
|
|
34
|
-
|
|
35
|
-
function assertIndexedDb(): IDBFactory {
|
|
36
|
-
if (typeof indexedDB === "undefined") {
|
|
37
|
-
throw new CoreError("indexedDB is not available in this environment");
|
|
38
|
-
}
|
|
39
|
-
return indexedDB;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export type IndexedDbOptions = {
|
|
43
|
-
name?: string;
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
// Translate IndexedDB's event-based transaction API into a promise that resolves
|
|
47
|
-
// when the transaction completes or rejects on failure/abort.
|
|
48
|
-
function txDone(tx: IDBTransaction): Promise<void> {
|
|
49
|
-
return new Promise<void>((resolve, reject) => {
|
|
50
|
-
tx.oncomplete = () => resolve();
|
|
51
|
-
tx.onerror = () =>
|
|
52
|
-
reject(tx.error ?? new CoreError("indexedDB transaction failed"));
|
|
53
|
-
tx.onabort = () =>
|
|
54
|
-
reject(tx.error ?? new CoreError("indexedDB transaction aborted"));
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function wrapRequest<T>(request: IDBRequest<T>): Promise<T> {
|
|
59
|
-
return new Promise<T>((resolve, reject) => {
|
|
60
|
-
request.onsuccess = () => resolve(request.result);
|
|
61
|
-
request.onerror = () =>
|
|
62
|
-
reject(request.error ?? new CoreError("indexedDB request failed"));
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Coerce whatever IndexedDB gives us back into our Bytes type.
|
|
67
|
-
function asBytes(raw: unknown): Bytes {
|
|
68
|
-
if (raw instanceof Uint8Array) return copy(raw);
|
|
69
|
-
if (raw instanceof ArrayBuffer) return copy(new Uint8Array(raw));
|
|
70
|
-
if (ArrayBuffer.isView(raw)) {
|
|
71
|
-
const view = raw as ArrayBufferView;
|
|
72
|
-
const buf = view.buffer.slice(
|
|
73
|
-
view.byteOffset,
|
|
74
|
-
view.byteOffset + view.byteLength,
|
|
75
|
-
);
|
|
76
|
-
return copy(new Uint8Array(buf));
|
|
77
|
-
}
|
|
78
|
-
throw new CoreError("indexedDB value is not binary data");
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// IndexedDB-backed implementation implementing the storage API.
|
|
82
|
-
export function createIndexedDbStorage(opts: IndexedDbOptions = {}): Storage {
|
|
83
|
-
const name = opts.name ?? DEFAULT_DB_NAME;
|
|
84
|
-
let db: IDBDatabase | null = null;
|
|
85
|
-
|
|
86
|
-
// Lazy-open the database so we only touch IndexedDB when needed.
|
|
87
|
-
async function ensureOpen(): Promise<IDBDatabase> {
|
|
88
|
-
if (db) return db;
|
|
89
|
-
|
|
90
|
-
// Guard for environments without IndexedDB (unit tests or SSR).
|
|
91
|
-
const idb: IDBFactory = assertIndexedDb();
|
|
92
|
-
|
|
93
|
-
const request = idb.open(name, DB_VERSION);
|
|
94
|
-
// Versioned schema: create one store for kv entries and one for metadata.
|
|
95
|
-
request.onupgradeneeded = () => {
|
|
96
|
-
const upgradeDb = request.result;
|
|
97
|
-
if (!upgradeDb.objectStoreNames.contains(KV_STORE)) {
|
|
98
|
-
upgradeDb.createObjectStore(KV_STORE);
|
|
99
|
-
}
|
|
100
|
-
if (!upgradeDb.objectStoreNames.contains(META_STORE)) {
|
|
101
|
-
upgradeDb.createObjectStore(META_STORE);
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
db = await new Promise<IDBDatabase>((resolve, reject) => {
|
|
105
|
-
request.onsuccess = () => resolve(request.result);
|
|
106
|
-
request.onerror = () =>
|
|
107
|
-
reject(request.error ?? new CoreError("indexedDB open failed"));
|
|
108
|
-
request.onblocked = () =>
|
|
109
|
-
reject(new CoreError("indexedDB open request was blocked"));
|
|
110
|
-
});
|
|
111
|
-
return db!;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Start a transaction and give callers both the store and a completion promise.
|
|
115
|
-
const getStore = async (
|
|
116
|
-
storeName: string,
|
|
117
|
-
mode: IDBTransactionMode,
|
|
118
|
-
): Promise<{ store: IDBObjectStore; done: Promise<void> }> => {
|
|
119
|
-
const database = await ensureOpen();
|
|
120
|
-
const tx = database.transaction(storeName, mode);
|
|
121
|
-
const done = txDone(tx);
|
|
122
|
-
return { store: tx.objectStore(storeName), done };
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
return {
|
|
126
|
-
async open() {
|
|
127
|
-
await ensureOpen();
|
|
128
|
-
},
|
|
129
|
-
|
|
130
|
-
async get(key: string) {
|
|
131
|
-
validateKey(key);
|
|
132
|
-
const { store, done } = await getStore(KV_STORE, "readonly");
|
|
133
|
-
const result = await wrapRequest(store.get(key));
|
|
134
|
-
await done;
|
|
135
|
-
if (result === undefined) return null;
|
|
136
|
-
return asBytes(result);
|
|
137
|
-
},
|
|
138
|
-
|
|
139
|
-
async put(key: string, value: Bytes) {
|
|
140
|
-
validateKey(key);
|
|
141
|
-
const { store, done } = await getStore(KV_STORE, "readwrite");
|
|
142
|
-
await wrapRequest(store.put(copy(value), key)); // copy avoids shared mutation; revisit if this becomes costly
|
|
143
|
-
await done;
|
|
144
|
-
},
|
|
145
|
-
|
|
146
|
-
async delete(key: string) {
|
|
147
|
-
validateKey(key);
|
|
148
|
-
const { store, done } = await getStore(KV_STORE, "readwrite");
|
|
149
|
-
await wrapRequest(store.delete(key));
|
|
150
|
-
await done;
|
|
151
|
-
},
|
|
152
|
-
|
|
153
|
-
async batch(ops: BatchOp[]) {
|
|
154
|
-
// Execute the batch within a single transaction to preserve atomicity.
|
|
155
|
-
const database = await ensureOpen();
|
|
156
|
-
const tx = database.transaction(KV_STORE, "readwrite");
|
|
157
|
-
const store = tx.objectStore(KV_STORE);
|
|
158
|
-
const done = txDone(tx);
|
|
159
|
-
try {
|
|
160
|
-
// Replay the batch within a single transaction; validation failure aborts everything.
|
|
161
|
-
for (const op of ops) {
|
|
162
|
-
if (op.put) {
|
|
163
|
-
const [key, value] = op.put;
|
|
164
|
-
validateKey(key);
|
|
165
|
-
store.put(copy(value), key); // copy avoids shared mutation; revisit if this becomes costly
|
|
166
|
-
}
|
|
167
|
-
if (op.del) {
|
|
168
|
-
validateKey(op.del);
|
|
169
|
-
store.delete(op.del);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
await done;
|
|
173
|
-
} catch (err) {
|
|
174
|
-
try {
|
|
175
|
-
tx.abort();
|
|
176
|
-
} catch (_) {
|
|
177
|
-
/* noop */
|
|
178
|
-
}
|
|
179
|
-
await done.catch(() => {});
|
|
180
|
-
throw err;
|
|
181
|
-
}
|
|
182
|
-
},
|
|
183
|
-
|
|
184
|
-
async iter(options: IterOptions = {}) {
|
|
185
|
-
if (options.start && options.end && options.start > options.end) {
|
|
186
|
-
throw new CoreError("iter start bound must not exceed end bound");
|
|
187
|
-
}
|
|
188
|
-
// Pull everything into memory for now. TODO: stream w/ cursor when needed for perf
|
|
189
|
-
const database = await ensureOpen();
|
|
190
|
-
const tx = database.transaction(KV_STORE, "readonly");
|
|
191
|
-
const store = tx.objectStore(KV_STORE);
|
|
192
|
-
const done = txDone(tx);
|
|
193
|
-
const [keys, values] = await Promise.all([
|
|
194
|
-
wrapRequest<IDBValidKey[]>(store.getAllKeys()),
|
|
195
|
-
wrapRequest<unknown[]>(store.getAll()),
|
|
196
|
-
]);
|
|
197
|
-
await done;
|
|
198
|
-
|
|
199
|
-
const pairs: KvPair[] = keys.map((key, idx) => {
|
|
200
|
-
if (typeof key !== "string") {
|
|
201
|
-
throw new CoreError("encountered non-string key in indexedDB");
|
|
202
|
-
}
|
|
203
|
-
const raw = values[idx];
|
|
204
|
-
return { key, value: asBytes(raw) };
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
let filtered = pairs.filter(({ key }) => {
|
|
208
|
-
if (options.prefix && !key.startsWith(options.prefix)) return false;
|
|
209
|
-
if (options.start && key < options.start) return false;
|
|
210
|
-
if (options.end && key > options.end) return false;
|
|
211
|
-
return true;
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
filtered.sort((a, b) => a.key.localeCompare(b.key));
|
|
215
|
-
if (options.reverse) filtered = filtered.reverse();
|
|
216
|
-
if (options.limit) filtered = filtered.slice(0, options.limit);
|
|
217
|
-
return filtered;
|
|
218
|
-
},
|
|
219
|
-
|
|
220
|
-
async getSchemaVersion() {
|
|
221
|
-
const { store, done } = await getStore(META_STORE, "readonly");
|
|
222
|
-
const value = await wrapRequest<number | undefined>(
|
|
223
|
-
store.get(SCHEMA_KEY),
|
|
224
|
-
);
|
|
225
|
-
await done;
|
|
226
|
-
return value ?? 0;
|
|
227
|
-
},
|
|
228
|
-
|
|
229
|
-
async setSchemaVersion(version) {
|
|
230
|
-
const { store, done } = await getStore(META_STORE, "readwrite");
|
|
231
|
-
await wrapRequest(store.put(version, SCHEMA_KEY));
|
|
232
|
-
await done;
|
|
233
|
-
},
|
|
234
|
-
};
|
|
235
|
-
}
|
package/storage/memory.test.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it } from "vitest";
|
|
2
|
-
|
|
3
|
-
import { CoreError, KeyValidationError } from "../errors.js";
|
|
4
|
-
import { MAX_KEY_LEN } from "../keys.js";
|
|
5
|
-
import type { Storage } from "../types.js";
|
|
6
|
-
import { createMemoryStorage } from "./memory.js";
|
|
7
|
-
|
|
8
|
-
const encoder = new TextEncoder();
|
|
9
|
-
|
|
10
|
-
describe("createMemoryStorage", () => {
|
|
11
|
-
let storage: Storage;
|
|
12
|
-
|
|
13
|
-
beforeEach(async () => {
|
|
14
|
-
storage = createMemoryStorage();
|
|
15
|
-
await storage.open();
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it("returns null when key is missing", async () => {
|
|
19
|
-
const value = await storage.get("meta:missing");
|
|
20
|
-
expect(value).toBeNull();
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it("roundtrips put/get values", async () => {
|
|
24
|
-
await storage.put("meta:key", encoder.encode("value"));
|
|
25
|
-
const value = await storage.get("meta:key");
|
|
26
|
-
expect(value).toEqual(encoder.encode("value"));
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it("roundtrips schema version", async () => {
|
|
30
|
-
await storage.setSchemaVersion(2);
|
|
31
|
-
const version = await storage.getSchemaVersion();
|
|
32
|
-
expect(version).toBe(2);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it("rejects iter calls when start bound exceeds end bound", async () => {
|
|
36
|
-
await expect(
|
|
37
|
-
storage.iter({ start: "notes:z", end: "notes:a" }),
|
|
38
|
-
).rejects.toBeInstanceOf(CoreError);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it("keeps batch atomic when validation fails", async () => {
|
|
42
|
-
await storage.put("meta:ok", encoder.encode("1"));
|
|
43
|
-
|
|
44
|
-
const oversizedKey = "a".repeat(MAX_KEY_LEN + 1);
|
|
45
|
-
await expect(
|
|
46
|
-
storage.batch([
|
|
47
|
-
{ del: "meta:ok" },
|
|
48
|
-
{ put: ["notes:new", encoder.encode("value")] },
|
|
49
|
-
{ put: [oversizedKey, encoder.encode("bad")] },
|
|
50
|
-
]),
|
|
51
|
-
).rejects.toBeInstanceOf(KeyValidationError);
|
|
52
|
-
|
|
53
|
-
const original = await storage.get("meta:ok");
|
|
54
|
-
expect(original).toEqual(encoder.encode("1"));
|
|
55
|
-
|
|
56
|
-
const missing = await storage.get("notes:new");
|
|
57
|
-
expect(missing).toBeNull();
|
|
58
|
-
});
|
|
59
|
-
});
|