@optimystic/db-p2p-storage-rn 1.15.0 → 1.16.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/README.md +110 -0
- package/dist/src/identity.d.ts +3 -1
- package/dist/src/identity.d.ts.map +1 -1
- package/dist/src/identity.js +4 -2
- package/dist/src/identity.js.map +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/keys.d.ts +22 -0
- package/dist/src/keys.d.ts.map +1 -1
- package/dist/src/keys.js +47 -0
- package/dist/src/keys.js.map +1 -1
- package/dist/src/leveldb-kv-store.d.ts +24 -2
- package/dist/src/leveldb-kv-store.d.ts.map +1 -1
- package/dist/src/leveldb-kv-store.js +61 -3
- package/dist/src/leveldb-kv-store.js.map +1 -1
- package/dist/src/leveldb-like.d.ts +23 -4
- package/dist/src/leveldb-like.d.ts.map +1 -1
- package/dist/src/leveldb-like.js +6 -0
- package/dist/src/leveldb-like.js.map +1 -1
- package/dist/src/leveldb-storage.d.ts +70 -40
- package/dist/src/leveldb-storage.d.ts.map +1 -1
- package/dist/src/leveldb-storage.js +164 -103
- package/dist/src/leveldb-storage.js.map +1 -1
- package/dist/src/rn-opener.d.ts.map +1 -1
- package/dist/src/rn-opener.js +9 -7
- package/dist/src/rn-opener.js.map +1 -1
- package/package.json +3 -3
- package/src/identity.ts +4 -2
- package/src/index.ts +2 -2
- package/src/keys.ts +57 -0
- package/src/leveldb-kv-store.ts +67 -6
- package/src/leveldb-like.ts +24 -4
- package/src/leveldb-storage.ts +192 -127
- package/src/rn-opener.ts +11 -9
package/README.md
CHANGED
|
@@ -56,6 +56,107 @@ const libp2p = await createLibp2pNode({
|
|
|
56
56
|
Use the Node-free `/rn` entry point of `@optimystic/db-p2p` so the Node-only
|
|
57
57
|
TCP transport doesn't get bundled into the React Native app.
|
|
58
58
|
|
|
59
|
+
The same handle is shared by all three consumers. Close the storage and the
|
|
60
|
+
key-value store before the handle, and the handle last:
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
await rawStorage.close(); // applies what it still holds, disarms its timers
|
|
64
|
+
await kvStore.close(); // commits what it still holds, disarms its timer
|
|
65
|
+
await db.close();
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Neither `close()` closes the shared handle. A write a store still holds when the
|
|
69
|
+
handle is closed under it is lost, and a timer it still has armed would fire on
|
|
70
|
+
a closed handle.
|
|
71
|
+
|
|
72
|
+
## Persistence semantics
|
|
73
|
+
|
|
74
|
+
Everything lives in one LevelDB database (`optimystic` by default), one
|
|
75
|
+
ordered byte keyspace partitioned by a leading tag byte (`src/keys.ts`).
|
|
76
|
+
`LevelDBRawStorage` is the shared `KvRawStorage` kernel over a
|
|
77
|
+
`WriteGroupDriver` over a `JournalBatchBackend` over a `LevelDBJournalStore`:
|
|
78
|
+
the kernel owns all JSON/UTF-8 serialization, so the six block-storage stores
|
|
79
|
+
hold opaque kernel-encoded bytes. The keys and the logical types the kernel
|
|
80
|
+
decodes them back into are unchanged from earlier builds, so data written by
|
|
81
|
+
one reads unchanged, and a database an earlier build wrote has no journal, so
|
|
82
|
+
the first open over it applies nothing.
|
|
83
|
+
|
|
84
|
+
| Tag | Store | Key suffix | Decoded (logical) type |
|
|
85
|
+
|-----|-------|------------|------------------------|
|
|
86
|
+
| `0x01` | `metadata` | `blockId` | `BlockMetadata` |
|
|
87
|
+
| `0x02` | `revisions` | `blockId`, rev (8 bytes big-endian) | `ActionId` |
|
|
88
|
+
| `0x03` | `pending` | `blockId`, `actionId` | `Transform` |
|
|
89
|
+
| `0x04` | `transactions` | `blockId`, `actionId` | `Transform` |
|
|
90
|
+
| `0x05` | `materialized` | `blockId`, `actionId` | `IBlock` |
|
|
91
|
+
| `0x06` | `proofs` | `blockId`, rev (8 bytes big-endian) | `BlockCommitProof` |
|
|
92
|
+
| `0x07` | `journal` | the record's sequence (8 bytes big-endian), or nothing for the applied-through mark | a journal record as bytes, or the number of the last record applied — owned by `LevelDBJournalStore` |
|
|
93
|
+
| `0x10` | `kv` | the key, UTF-8 | a string (not kernel-backed) |
|
|
94
|
+
| `0x20` | `identity` | the key name, UTF-8 | raw protobuf bytes of the private key |
|
|
95
|
+
|
|
96
|
+
`listRevisions` and `listPendingTransactions` are range-bounded native scans,
|
|
97
|
+
drained before any result is yielded so a native iterator never stays open
|
|
98
|
+
across a consumer's `await`. `promotePendingTransaction` records two entries of
|
|
99
|
+
one write group — the committed row's put and the pending row's delete — applied
|
|
100
|
+
in that group's batch, so the move is atomic across crashes.
|
|
101
|
+
|
|
102
|
+
## Durability
|
|
103
|
+
|
|
104
|
+
A write resolves into memory and is served from there; `flush()` hands every
|
|
105
|
+
write made since the last flush to the journal backend as **one group**, and
|
|
106
|
+
every write this package makes to LevelDB is one `WriteBatch` — the handle
|
|
107
|
+
surface has no single put or delete — so a group lands whole or not at all.
|
|
108
|
+
|
|
109
|
+
What a crash loses today, with `rn-leveldb` 3.11:
|
|
110
|
+
|
|
111
|
+
| Crash | Lost |
|
|
112
|
+
|---|---|
|
|
113
|
+
| the app's process | a group not yet flushed, still in memory, whole; nothing a flush has resolved for |
|
|
114
|
+
| a power cut or operating-system crash | any write the operating system has not yet written out, whatever the window; a later group may survive while an earlier one is lost |
|
|
115
|
+
|
|
116
|
+
The second row is the binding's: `rn-leveldb` writes every batch with LevelDB's
|
|
117
|
+
default options, which hand the bytes to the operating system without syncing,
|
|
118
|
+
and offers no way to ask for a sync. So `LevelDBRawStorage` reports
|
|
119
|
+
`durability: 'process-crash'`, the backend applies each group at once as one
|
|
120
|
+
unsynced batch and journals nothing, every `flush({ withinMs })` is treated as
|
|
121
|
+
strict, and the node's start-up line says such a store cannot keep the window.
|
|
122
|
+
|
|
123
|
+
The synced path is built, and it runs in this package's suite over
|
|
124
|
+
`classic-level`, which can sync. On a handle whose `canSync` is true the
|
|
125
|
+
backend journals: a relaxed `flush({ withinMs })` — what a node uses for a write
|
|
126
|
+
its cohort also holds, see [storage.md §How long a write may wait for its sync](../db-p2p/docs/storage.md#how-long-a-write-may-wait-for-its-sync) —
|
|
127
|
+
appends the group as one journal record in one unsynced batch and resolves,
|
|
128
|
+
and one synced batch by the earliest deadline, or a strict flush before then,
|
|
129
|
+
applies every record appended since the last apply, in order, sets the
|
|
130
|
+
applied-through mark and deletes them. Every apply carries every byte it
|
|
131
|
+
applies, so what a power cut leaves is a prefix of the groups: a journal record
|
|
132
|
+
LevelDB lost is a missing number, and recovery at the next open applies the
|
|
133
|
+
consecutive run before it and discards everything after it (details in
|
|
134
|
+
[storage.md §6, *The journal backend*](../db-p2p/docs/storage.md#6-a-write-survives-a-crash-once-a-flush-called-after-it-has-resolved)).
|
|
135
|
+
The step that turns it on for phones is upstream: a release of `rn-leveldb`
|
|
136
|
+
whose batch write accepts a sync flag (the blocked ticket
|
|
137
|
+
`react-native-storage-syncs-once-rn-leveldb-can`). The adapter in this package
|
|
138
|
+
then reports `canSync: true`, the storage reports `'power-loss'`, and nothing
|
|
139
|
+
above it changes.
|
|
140
|
+
|
|
141
|
+
A failed batch latches the storage: every later write, flush and
|
|
142
|
+
`whenDurable()` rejects with `StoreFailedError` until the app reopens the store
|
|
143
|
+
(rule 5 of the flush contract,
|
|
144
|
+
[storage.md §6](../db-p2p/docs/storage.md#6-a-write-survives-a-crash-once-a-flush-called-after-it-has-resolved)).
|
|
145
|
+
|
|
146
|
+
`LevelDBKVStore` writes through a `WriteGroup` over its keys the same way:
|
|
147
|
+
`set` and `delete` resolve into memory, and `flush()` commits everything since
|
|
148
|
+
the last flush as one batch, synced where the handle can — every flush of this
|
|
149
|
+
store is strict, so nothing of it is ever journaled. `whenDurable()` and
|
|
150
|
+
`close()` are the group's.
|
|
151
|
+
|
|
152
|
+
## Identity
|
|
153
|
+
|
|
154
|
+
`loadOrCreateRNPeerKey(db, keyName?)` writes the libp2p private key as raw
|
|
155
|
+
protobuf bytes under `keyName` (default `peer-private-key`) in one batch,
|
|
156
|
+
synced where the handle can, so a power cut right after first start cannot give
|
|
157
|
+
the node a different peer id next time. LevelDB stores bytes natively, so no
|
|
158
|
+
base64 round-trip is needed.
|
|
159
|
+
|
|
59
160
|
## Debug logging
|
|
60
161
|
|
|
61
162
|
`DEBUG=` does not work in React Native, and without it every `optimystic:*`
|
|
@@ -72,6 +173,15 @@ It prints one `optimystic logging on: …` confirmation line; look for that
|
|
|
72
173
|
first. See `docs/debugging.md` § "Turning logging on" in the repository for
|
|
73
174
|
the `log` option, libp2p's separate switch, and the cost on device.
|
|
74
175
|
|
|
176
|
+
## Tests
|
|
177
|
+
|
|
178
|
+
`yarn test` runs the spec suite under `classic-level` in Node, so CI needs no
|
|
179
|
+
device. `classic-level` honours LevelDB's `sync` option, so the suite
|
|
180
|
+
exercises the journaled, synced path a phone will take once its binding can
|
|
181
|
+
sync, and checks which batches were written and whether each asked to sync;
|
|
182
|
+
nothing here cuts the power. The phone case is covered by presenting the same
|
|
183
|
+
binding as unable to sync.
|
|
184
|
+
|
|
75
185
|
## Related packages
|
|
76
186
|
|
|
77
187
|
- **[@optimystic/db-p2p](../db-p2p)** — the distributed layer this backend
|
package/dist/src/identity.d.ts
CHANGED
|
@@ -3,7 +3,9 @@ import type { LevelDBLike } from './leveldb-like.js';
|
|
|
3
3
|
export declare const DEFAULT_PEER_KEY_NAME = "peer-private-key";
|
|
4
4
|
/**
|
|
5
5
|
* Loads the persisted React Native peer's libp2p private key, or generates a
|
|
6
|
-
* fresh Ed25519 key on first call and persists it
|
|
6
|
+
* fresh Ed25519 key on first call and persists it in one batch, synced where
|
|
7
|
+
* the handle can sync, so a power cut right after first start cannot give the
|
|
8
|
+
* node a different peer id next time. An existing key is read as it is.
|
|
7
9
|
*
|
|
8
10
|
* The key is stored as raw protobuf bytes under a dedicated identity tag —
|
|
9
11
|
* LevelDB stores arbitrary byte sequences natively, so there is no base64
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/identity.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,qBAAqB,qBAAqB,CAAC;AAExD
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/identity.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,qBAAqB,qBAAqB,CAAC;AAExD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,qBAAqB,CAC1C,EAAE,EAAE,WAAW,EACf,OAAO,GAAE,MAA8B,GACrC,OAAO,CAAC,UAAU,CAAC,CASrB"}
|
package/dist/src/identity.js
CHANGED
|
@@ -3,7 +3,9 @@ import { identityKey } from './keys.js';
|
|
|
3
3
|
export const DEFAULT_PEER_KEY_NAME = 'peer-private-key';
|
|
4
4
|
/**
|
|
5
5
|
* Loads the persisted React Native peer's libp2p private key, or generates a
|
|
6
|
-
* fresh Ed25519 key on first call and persists it
|
|
6
|
+
* fresh Ed25519 key on first call and persists it in one batch, synced where
|
|
7
|
+
* the handle can sync, so a power cut right after first start cannot give the
|
|
8
|
+
* node a different peer id next time. An existing key is read as it is.
|
|
7
9
|
*
|
|
8
10
|
* The key is stored as raw protobuf bytes under a dedicated identity tag —
|
|
9
11
|
* LevelDB stores arbitrary byte sequences natively, so there is no base64
|
|
@@ -21,7 +23,7 @@ export async function loadOrCreateRNPeerKey(db, keyName = DEFAULT_PEER_KEY_NAME)
|
|
|
21
23
|
}
|
|
22
24
|
const key = await generateKeyPair('Ed25519');
|
|
23
25
|
const bytes = privateKeyToProtobuf(key);
|
|
24
|
-
await db.put(identityKey(keyName), bytes);
|
|
26
|
+
await db.batch().put(identityKey(keyName), bytes).write({ sync: db.canSync });
|
|
25
27
|
return key;
|
|
26
28
|
}
|
|
27
29
|
//# sourceMappingURL=identity.js.map
|
package/dist/src/identity.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAGpG,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,MAAM,CAAC,MAAM,qBAAqB,GAAG,kBAAkB,CAAC;AAExD
|
|
1
|
+
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAGpG,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,MAAM,CAAC,MAAM,qBAAqB,GAAG,kBAAkB,CAAC;AAExD;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAC1C,EAAe,EACf,UAAkB,qBAAqB;IAEvC,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;IAClD,IAAI,MAAM,IAAI,MAAM,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;QACrC,OAAO,sBAAsB,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,eAAe,CAAC,SAAS,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;IACxC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;IAC9E,OAAO,GAAG,CAAC;AACZ,CAAC"}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { LevelDBRawStorage,
|
|
2
|
-
export { LevelDBKVStore } from './leveldb-kv-store.js';
|
|
1
|
+
export { LevelDBRawStorage, LevelDBJournalStore, type LevelDBRawStorageOptions } from './leveldb-storage.js';
|
|
2
|
+
export { LevelDBKVStore, type LevelDBKVStoreOptions } from './leveldb-kv-store.js';
|
|
3
3
|
export { loadOrCreateRNPeerKey, DEFAULT_PEER_KEY_NAME } from './identity.js';
|
|
4
4
|
export { openOptimysticRNDb, wrapRNLevelDB, DEFAULT_DB_NAME, type OpenOptimysticRNDbOptions, type RNLevelDBNative, type RNLevelDBWriteBatchNative, type RNLevelDBIteratorNative, type RNLevelDBWriteBatchCtor, type RNLevelDBOpenFn, } from './rn-opener.js';
|
|
5
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,KAAK,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAC7G,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACnF,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC7E,OAAO,EACN,kBAAkB,EAClB,aAAa,EACb,eAAe,EACf,KAAK,yBAAyB,EAC9B,KAAK,eAAe,EACpB,KAAK,yBAAyB,EAC9B,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,eAAe,GACpB,MAAM,gBAAgB,CAAC"}
|
package/dist/src/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { LevelDBRawStorage,
|
|
1
|
+
export { LevelDBRawStorage, LevelDBJournalStore } from './leveldb-storage.js';
|
|
2
2
|
export { LevelDBKVStore } from './leveldb-kv-store.js';
|
|
3
3
|
export { loadOrCreateRNPeerKey, DEFAULT_PEER_KEY_NAME } from './identity.js';
|
|
4
4
|
export { openOptimysticRNDb, wrapRNLevelDB, DEFAULT_DB_NAME, } from './rn-opener.js';
|
package/dist/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAiC,MAAM,sBAAsB,CAAC;AAC7G,OAAO,EAAE,cAAc,EAA8B,MAAM,uBAAuB,CAAC;AACnF,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC7E,OAAO,EACN,kBAAkB,EAClB,aAAa,EACb,eAAe,GAOf,MAAM,gBAAgB,CAAC"}
|
package/dist/src/keys.d.ts
CHANGED
|
@@ -16,6 +16,10 @@
|
|
|
16
16
|
* - proofs: rev (8-byte big-endian unsigned, same as revisions)
|
|
17
17
|
* - materialized: actionId UTF-8 (terminal)
|
|
18
18
|
*
|
|
19
|
+
* The journal (`TAG_JOURNAL`) has no `blockId` envelope: a record key is the
|
|
20
|
+
* tag then its `seq` as 8 bytes big-endian, and the applied-through mark is the
|
|
21
|
+
* bare tag, which sorts before every numbered key.
|
|
22
|
+
*
|
|
19
23
|
* `kv` and `identity` keys are flat — no `blockId` envelope — under their
|
|
20
24
|
* own tag bytes (`TAG_KV`, `TAG_IDENTITY`) and use UTF-8 of the full key.
|
|
21
25
|
*
|
|
@@ -29,6 +33,7 @@ export declare const TAG_PENDING = 3;
|
|
|
29
33
|
export declare const TAG_TRANSACTIONS = 4;
|
|
30
34
|
export declare const TAG_MATERIALIZED = 5;
|
|
31
35
|
export declare const TAG_PROOFS = 6;
|
|
36
|
+
export declare const TAG_JOURNAL = 7;
|
|
32
37
|
export declare const TAG_KV = 16;
|
|
33
38
|
export declare const TAG_IDENTITY = 32;
|
|
34
39
|
export declare function metadataKey(blockId: string): Uint8Array;
|
|
@@ -65,6 +70,23 @@ export declare function blockEnvelopeRange(tag: number, blockId: string): {
|
|
|
65
70
|
};
|
|
66
71
|
/** Decode the `actionId` suffix from a `pendingKey` / `transactionKey` / `materializedKey`. */
|
|
67
72
|
export declare function actionIdFromKey(key: Uint8Array, blockId: string): string;
|
|
73
|
+
/** `TAG_JOURNAL || seq (8 BE)`: the key of the journal record numbered `seq`. */
|
|
74
|
+
export declare function journalRecordKey(seq: number): Uint8Array;
|
|
75
|
+
/** The bare tag: the key of the applied-through mark, which sorts before every record key. */
|
|
76
|
+
export declare function journalMarkKey(): Uint8Array;
|
|
77
|
+
/** The mark's value: the number of the last record applied, as 8 bytes big-endian. */
|
|
78
|
+
export declare function encodeJournalMark(appliedThrough: number): Uint8Array;
|
|
79
|
+
/** The number a mark value holds, or `undefined` when it is not 8 bytes. */
|
|
80
|
+
export declare function decodeJournalMark(value: Uint8Array): number | undefined;
|
|
81
|
+
/** Returns the inclusive lower / exclusive upper range covering the mark and every record key. */
|
|
82
|
+
export declare function journalRange(): {
|
|
83
|
+
gte: Uint8Array;
|
|
84
|
+
lt: Uint8Array;
|
|
85
|
+
};
|
|
86
|
+
/** Whether a key inside `journalRange` is the mark's (the bare tag) rather than a record's. */
|
|
87
|
+
export declare function isJournalMarkKey(key: Uint8Array): boolean;
|
|
88
|
+
/** The `seq` a record key names, or `undefined` for a key of another shape. */
|
|
89
|
+
export declare function seqFromJournalKey(key: Uint8Array): number | undefined;
|
|
68
90
|
export declare function kvKey(key: string): Uint8Array;
|
|
69
91
|
/** Returns the inclusive lower / exclusive upper range covering every kv key starting with `prefix`. */
|
|
70
92
|
export declare function kvPrefixRange(prefix: string): {
|
package/dist/src/keys.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/keys.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/keys.ts"],"names":[],"mappings":"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"}
|
package/dist/src/keys.js
CHANGED
|
@@ -16,6 +16,10 @@
|
|
|
16
16
|
* - proofs: rev (8-byte big-endian unsigned, same as revisions)
|
|
17
17
|
* - materialized: actionId UTF-8 (terminal)
|
|
18
18
|
*
|
|
19
|
+
* The journal (`TAG_JOURNAL`) has no `blockId` envelope: a record key is the
|
|
20
|
+
* tag then its `seq` as 8 bytes big-endian, and the applied-through mark is the
|
|
21
|
+
* bare tag, which sorts before every numbered key.
|
|
22
|
+
*
|
|
19
23
|
* `kv` and `identity` keys are flat — no `blockId` envelope — under their
|
|
20
24
|
* own tag bytes (`TAG_KV`, `TAG_IDENTITY`) and use UTF-8 of the full key.
|
|
21
25
|
*
|
|
@@ -29,6 +33,7 @@ export const TAG_PENDING = 0x03;
|
|
|
29
33
|
export const TAG_TRANSACTIONS = 0x04;
|
|
30
34
|
export const TAG_MATERIALIZED = 0x05;
|
|
31
35
|
export const TAG_PROOFS = 0x06;
|
|
36
|
+
export const TAG_JOURNAL = 0x07;
|
|
32
37
|
export const TAG_KV = 0x10;
|
|
33
38
|
export const TAG_IDENTITY = 0x20;
|
|
34
39
|
const textEncoder = new TextEncoder();
|
|
@@ -135,6 +140,48 @@ export function actionIdFromKey(key, blockId) {
|
|
|
135
140
|
const suffixOffset = 1 + 4 + blockIdLen;
|
|
136
141
|
return textDecoder().decode(key.subarray(suffixOffset));
|
|
137
142
|
}
|
|
143
|
+
// --- the journal ---
|
|
144
|
+
const SEQ_BYTES = 8;
|
|
145
|
+
/** `seq` as 8 bytes big-endian, the suffix of a record key and the value of the mark. */
|
|
146
|
+
function encodeSeq(seq) {
|
|
147
|
+
const out = new Uint8Array(SEQ_BYTES);
|
|
148
|
+
new DataView(out.buffer).setBigUint64(0, BigInt(seq), false);
|
|
149
|
+
return out;
|
|
150
|
+
}
|
|
151
|
+
/** The number 8 bytes big-endian hold, or `undefined` for any other length. */
|
|
152
|
+
function decodeSeq(bytes) {
|
|
153
|
+
if (bytes.byteLength !== SEQ_BYTES)
|
|
154
|
+
return undefined;
|
|
155
|
+
return Number(new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getBigUint64(0, false));
|
|
156
|
+
}
|
|
157
|
+
/** `TAG_JOURNAL || seq (8 BE)`: the key of the journal record numbered `seq`. */
|
|
158
|
+
export function journalRecordKey(seq) {
|
|
159
|
+
return concat(Uint8Array.of(TAG_JOURNAL), encodeSeq(seq));
|
|
160
|
+
}
|
|
161
|
+
/** The bare tag: the key of the applied-through mark, which sorts before every record key. */
|
|
162
|
+
export function journalMarkKey() {
|
|
163
|
+
return Uint8Array.of(TAG_JOURNAL);
|
|
164
|
+
}
|
|
165
|
+
/** The mark's value: the number of the last record applied, as 8 bytes big-endian. */
|
|
166
|
+
export function encodeJournalMark(appliedThrough) {
|
|
167
|
+
return encodeSeq(appliedThrough);
|
|
168
|
+
}
|
|
169
|
+
/** The number a mark value holds, or `undefined` when it is not 8 bytes. */
|
|
170
|
+
export function decodeJournalMark(value) {
|
|
171
|
+
return decodeSeq(value);
|
|
172
|
+
}
|
|
173
|
+
/** Returns the inclusive lower / exclusive upper range covering the mark and every record key. */
|
|
174
|
+
export function journalRange() {
|
|
175
|
+
return { gte: Uint8Array.of(TAG_JOURNAL), lt: Uint8Array.of(TAG_JOURNAL + 1) };
|
|
176
|
+
}
|
|
177
|
+
/** Whether a key inside `journalRange` is the mark's (the bare tag) rather than a record's. */
|
|
178
|
+
export function isJournalMarkKey(key) {
|
|
179
|
+
return key.byteLength === 1;
|
|
180
|
+
}
|
|
181
|
+
/** The `seq` a record key names, or `undefined` for a key of another shape. */
|
|
182
|
+
export function seqFromJournalKey(key) {
|
|
183
|
+
return decodeSeq(key.subarray(1));
|
|
184
|
+
}
|
|
138
185
|
export function kvKey(key) {
|
|
139
186
|
return concat(Uint8Array.of(TAG_KV), textEncoder.encode(key));
|
|
140
187
|
}
|
package/dist/src/keys.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/keys.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/keys.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type FlushOptions, type IKVStore, type WriteGroupOptions } from '@optimystic/db-p2p';
|
|
2
2
|
import { type LevelDBLike } from './leveldb-like.js';
|
|
3
|
+
/** The write group's options (`idleFlushMs`, `maxUnsyncedBytes`, the test-only `setTimer`). */
|
|
4
|
+
export type LevelDBKVStoreOptions = WriteGroupOptions;
|
|
3
5
|
/**
|
|
4
6
|
* LevelDB-backed `IKVStore` adapter for React Native peers.
|
|
5
7
|
*
|
|
@@ -8,14 +10,34 @@ import { type LevelDBLike } from './leveldb-like.js';
|
|
|
8
10
|
* so the three subsystems can't collide regardless of the user-chosen
|
|
9
11
|
* `prefix`. `list(prefix)` is a range-bounded scan — never a full-database
|
|
10
12
|
* iteration plus JS-side filter — so listing latency stays bounded.
|
|
13
|
+
*
|
|
14
|
+
* Writes go through a {@link WriteGroup} over the plain keys, as `FileKVStore` does: a `set` or
|
|
15
|
+
* `delete` resolves into memory, served from there to `get` and `list`, and `flush()` commits
|
|
16
|
+
* everything written since the last flush as ONE LevelDB batch, synced wherever the handle can
|
|
17
|
+
* sync (`canSync`), so the writes are on the disk before the flush resolves. Every flush the node
|
|
18
|
+
* makes of this store is strict, and so is the group's own idle flush, so there is no relaxed path
|
|
19
|
+
* to journal: a flush given a window is treated as strict, as a store that cannot defer a sync
|
|
20
|
+
* treats every window, and each batch carries its own data. A failed batch latches the store, after
|
|
21
|
+
* which every write and flush throws `StoreFailedError` (rule 5 of the flush contract on
|
|
22
|
+
* `RawStoreDriver.flush`); reads keep serving the overlay.
|
|
11
23
|
*/
|
|
12
24
|
export declare class LevelDBKVStore implements IKVStore {
|
|
13
25
|
private readonly db;
|
|
14
26
|
private readonly prefix;
|
|
15
|
-
|
|
27
|
+
private readonly group;
|
|
28
|
+
constructor(db: LevelDBLike, prefix?: string, options?: LevelDBKVStoreOptions);
|
|
16
29
|
get(key: string): Promise<string | undefined>;
|
|
17
30
|
set(key: string, value: string): Promise<void>;
|
|
18
31
|
delete(key: string): Promise<void>;
|
|
32
|
+
/** Every key under `prefix`: the store's, plus those written and not yet flushed, less those deleted and not yet flushed. */
|
|
19
33
|
list(prefix: string): Promise<string[]>;
|
|
34
|
+
/** Make every write resolved before this call durable: one batch, synced where the handle can, whatever `options.withinMs` says. The contract is `RawStoreDriver.flush`'s. */
|
|
35
|
+
flush(options?: FlushOptions): Promise<void>;
|
|
36
|
+
/** Resolves once every write covered by a flush that resolved before this call is durable; `RawStoreDriver.whenDurable`'s contract. */
|
|
37
|
+
whenDurable(): Promise<void>;
|
|
38
|
+
/** Flush what is still held and disarm the idle timer. The host closes the shared handle after this resolves. */
|
|
39
|
+
close(): Promise<void>;
|
|
40
|
+
private commit;
|
|
41
|
+
private listStored;
|
|
20
42
|
}
|
|
21
43
|
//# sourceMappingURL=leveldb-kv-store.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"leveldb-kv-store.d.ts","sourceRoot":"","sources":["../../src/leveldb-kv-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"leveldb-kv-store.d.ts","sourceRoot":"","sources":["../../src/leveldb-kv-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmC,KAAK,YAAY,EAAE,KAAK,QAAQ,EAAwB,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACrJ,OAAO,EAAS,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAG5D,+FAA+F;AAC/F,MAAM,MAAM,qBAAqB,GAAG,iBAAiB,CAAC;AAQtD;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,cAAe,YAAW,QAAQ;IAI7C,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJxB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqB;gBAGzB,EAAE,EAAE,WAAW,EACf,MAAM,GAAE,MAA0B,EACnD,OAAO,GAAE,qBAA0B;IAS9B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAQ7C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxC,6HAA6H;IACvH,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAY7C,8KAA8K;IAC9K,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5C,uIAAuI;IACvI,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B,iHAAiH;IACjH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAIR,MAAM;YAUN,UAAU;CAKxB"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { WriteGroup } from '@optimystic/db-p2p';
|
|
1
2
|
import { drain } from './leveldb-like.js';
|
|
2
3
|
import { kvKey, kvKeyToString, kvPrefixRange } from './keys.js';
|
|
3
4
|
const textEncoder = new TextEncoder();
|
|
@@ -13,27 +14,84 @@ const textDecoder = () => textDecoderInstance ??= new TextDecoder();
|
|
|
13
14
|
* so the three subsystems can't collide regardless of the user-chosen
|
|
14
15
|
* `prefix`. `list(prefix)` is a range-bounded scan — never a full-database
|
|
15
16
|
* iteration plus JS-side filter — so listing latency stays bounded.
|
|
17
|
+
*
|
|
18
|
+
* Writes go through a {@link WriteGroup} over the plain keys, as `FileKVStore` does: a `set` or
|
|
19
|
+
* `delete` resolves into memory, served from there to `get` and `list`, and `flush()` commits
|
|
20
|
+
* everything written since the last flush as ONE LevelDB batch, synced wherever the handle can
|
|
21
|
+
* sync (`canSync`), so the writes are on the disk before the flush resolves. Every flush the node
|
|
22
|
+
* makes of this store is strict, and so is the group's own idle flush, so there is no relaxed path
|
|
23
|
+
* to journal: a flush given a window is treated as strict, as a store that cannot defer a sync
|
|
24
|
+
* treats every window, and each batch carries its own data. A failed batch latches the store, after
|
|
25
|
+
* which every write and flush throws `StoreFailedError` (rule 5 of the flush contract on
|
|
26
|
+
* `RawStoreDriver.flush`); reads keep serving the overlay.
|
|
16
27
|
*/
|
|
17
28
|
export class LevelDBKVStore {
|
|
18
29
|
db;
|
|
19
30
|
prefix;
|
|
20
|
-
|
|
31
|
+
group;
|
|
32
|
+
constructor(db, prefix = 'optimystic:txn:', options = {}) {
|
|
21
33
|
this.db = db;
|
|
22
34
|
this.prefix = prefix;
|
|
35
|
+
this.group = new WriteGroup(key => key, {
|
|
36
|
+
commit: entries => this.commit(entries),
|
|
37
|
+
// Every commit is as durable as this store can make it when it resolves, so nothing is ever owed a sync.
|
|
38
|
+
sync: () => Promise.resolve(),
|
|
39
|
+
}, options);
|
|
23
40
|
}
|
|
24
41
|
async get(key) {
|
|
42
|
+
const held = this.group.lookup(key);
|
|
43
|
+
if (held !== undefined)
|
|
44
|
+
return held === null ? undefined : textDecoder().decode(held);
|
|
25
45
|
const bytes = await this.db.get(kvKey(this.prefix + key));
|
|
26
46
|
if (!bytes)
|
|
27
47
|
return undefined;
|
|
28
48
|
return textDecoder().decode(bytes);
|
|
29
49
|
}
|
|
30
50
|
async set(key, value) {
|
|
31
|
-
|
|
51
|
+
this.group.put(key, textEncoder.encode(value));
|
|
32
52
|
}
|
|
33
53
|
async delete(key) {
|
|
34
|
-
|
|
54
|
+
this.group.delete(key);
|
|
35
55
|
}
|
|
56
|
+
/** Every key under `prefix`: the store's, plus those written and not yet flushed, less those deleted and not yet flushed. */
|
|
36
57
|
async list(prefix) {
|
|
58
|
+
// Taken before awaiting the store: a commit resolving meanwhile drops entries from the overlay
|
|
59
|
+
// that the listing below may have been taken without.
|
|
60
|
+
const held = [...this.group.entries()].filter(([key]) => key.startsWith(prefix));
|
|
61
|
+
const keys = new Set(await this.listStored(prefix));
|
|
62
|
+
for (const [key, value] of held) {
|
|
63
|
+
if (value === null)
|
|
64
|
+
keys.delete(key);
|
|
65
|
+
else
|
|
66
|
+
keys.add(key);
|
|
67
|
+
}
|
|
68
|
+
return [...keys];
|
|
69
|
+
}
|
|
70
|
+
/** Make every write resolved before this call durable: one batch, synced where the handle can, whatever `options.withinMs` says. The contract is `RawStoreDriver.flush`'s. */
|
|
71
|
+
flush(options) {
|
|
72
|
+
return this.group.flush(options);
|
|
73
|
+
}
|
|
74
|
+
/** Resolves once every write covered by a flush that resolved before this call is durable; `RawStoreDriver.whenDurable`'s contract. */
|
|
75
|
+
whenDurable() {
|
|
76
|
+
return this.group.whenDurable();
|
|
77
|
+
}
|
|
78
|
+
/** Flush what is still held and disarm the idle timer. The host closes the shared handle after this resolves. */
|
|
79
|
+
close() {
|
|
80
|
+
return this.group.close();
|
|
81
|
+
}
|
|
82
|
+
async commit(entries) {
|
|
83
|
+
const batch = this.db.batch();
|
|
84
|
+
for (const { key, value } of entries) {
|
|
85
|
+
const encoded = kvKey(this.prefix + key);
|
|
86
|
+
if (value === undefined)
|
|
87
|
+
batch.delete(encoded);
|
|
88
|
+
else
|
|
89
|
+
batch.put(encoded, value);
|
|
90
|
+
}
|
|
91
|
+
await batch.write({ sync: this.db.canSync });
|
|
92
|
+
return { durable: Promise.resolve() };
|
|
93
|
+
}
|
|
94
|
+
async listStored(prefix) {
|
|
37
95
|
const range = kvPrefixRange(this.prefix + prefix);
|
|
38
96
|
const entries = await drain(this.db.iterator({ gte: range.gte, lt: range.lt, keys: true }));
|
|
39
97
|
return entries.map(([rawKey]) => kvKeyToString(rawKey).slice(this.prefix.length));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"leveldb-kv-store.js","sourceRoot":"","sources":["../../src/leveldb-kv-store.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"leveldb-kv-store.js","sourceRoot":"","sources":["../../src/leveldb-kv-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,6 +10,12 @@
|
|
|
10
10
|
* Only `openOptimysticRNDb`, the user-facing constructors, and the identity
|
|
11
11
|
* helper are exported from `index.ts`; the interfaces in this file are
|
|
12
12
|
* internal — consumers never see them.
|
|
13
|
+
*
|
|
14
|
+
* Every write this package makes is a `batch().write(...)`: the surface has no
|
|
15
|
+
* single `put` or `delete`, on purpose. A direct write lands unsynced in
|
|
16
|
+
* LevelDB's current log file, which LevelDB closes unsynced when it switches to
|
|
17
|
+
* a new one, so a later synced write does not cover it — exactly the write the
|
|
18
|
+
* journal under `LevelDBRawStorage` exists to keep out of the store.
|
|
13
19
|
*/
|
|
14
20
|
/** Range options for a `LevelDBLike.iterator` scan. */
|
|
15
21
|
export interface LevelDBIteratorOptions {
|
|
@@ -35,12 +41,21 @@ export interface LevelDBIteratorLike {
|
|
|
35
41
|
/** Release any native resources held by the iterator. */
|
|
36
42
|
close(): Promise<void>;
|
|
37
43
|
}
|
|
44
|
+
/** How a batch is written. */
|
|
45
|
+
export interface LevelDBWriteOptions {
|
|
46
|
+
/**
|
|
47
|
+
* Write with LevelDB's `WriteOptions.sync`: the batch is on the disk before the write resolves.
|
|
48
|
+
* Only valid on a handle whose `canSync` is true; asking a handle that cannot is a caller bug,
|
|
49
|
+
* and the adapter throws rather than write unsynced and report otherwise.
|
|
50
|
+
*/
|
|
51
|
+
readonly sync?: boolean;
|
|
52
|
+
}
|
|
38
53
|
/** Atomic batch of `put` / `delete` operations against a single database. */
|
|
39
54
|
export interface LevelDBWriteBatchLike {
|
|
40
55
|
put(key: Uint8Array, value: Uint8Array): this;
|
|
41
56
|
delete(key: Uint8Array): this;
|
|
42
|
-
/** Commit the batch atomically. */
|
|
43
|
-
write(): Promise<void>;
|
|
57
|
+
/** Commit the batch atomically; unsynced unless `options.sync`. The batch is consumed either way. */
|
|
58
|
+
write(options?: LevelDBWriteOptions): Promise<void>;
|
|
44
59
|
}
|
|
45
60
|
/**
|
|
46
61
|
* Minimal LevelDB driver surface used by this package.
|
|
@@ -51,9 +66,13 @@ export interface LevelDBWriteBatchLike {
|
|
|
51
66
|
* uniform with `classic-level`'s native async API.
|
|
52
67
|
*/
|
|
53
68
|
export interface LevelDBLike {
|
|
69
|
+
/**
|
|
70
|
+
* Whether `batch().write({ sync: true })` is honoured. Fixed for the life of the handle; it is
|
|
71
|
+
* what `LevelDBRawStorage` reports its `durability` from. `rn-leveldb` cannot sync today
|
|
72
|
+
* (`react-native-storage-syncs-once-rn-leveldb-can`); `classic-level` can.
|
|
73
|
+
*/
|
|
74
|
+
readonly canSync: boolean;
|
|
54
75
|
get(key: Uint8Array): Promise<Uint8Array | undefined>;
|
|
55
|
-
put(key: Uint8Array, value: Uint8Array): Promise<void>;
|
|
56
|
-
delete(key: Uint8Array): Promise<void>;
|
|
57
76
|
batch(): LevelDBWriteBatchLike;
|
|
58
77
|
iterator(options?: LevelDBIteratorOptions): LevelDBIteratorLike;
|
|
59
78
|
/** Release the underlying database handle. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"leveldb-like.d.ts","sourceRoot":"","sources":["../../src/leveldb-like.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"leveldb-like.d.ts","sourceRoot":"","sources":["../../src/leveldb-like.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,uDAAuD;AACvD,MAAM,WAAW,sBAAsB;IACtC,6BAA6B;IAC7B,GAAG,CAAC,EAAE,UAAU,CAAC;IACjB,6BAA6B;IAC7B,EAAE,CAAC,EAAE,UAAU,CAAC;IAChB,6BAA6B;IAC7B,GAAG,CAAC,EAAE,UAAU,CAAC;IACjB,6BAA6B;IAC7B,EAAE,CAAC,EAAE,UAAU,CAAC;IAChB,+BAA+B;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gGAAgG;IAChG,IAAI,CAAC,EAAE,OAAO,CAAC;CACf;AAED,kFAAkF;AAClF,MAAM,WAAW,mBAAmB;IACnC,yEAAyE;IACzE,IAAI,IAAI,OAAO,CAAC,CAAC,UAAU,EAAE,UAAU,CAAC,GAAG,SAAS,CAAC,CAAC;IACtD,yDAAyD;IACzD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,8BAA8B;AAC9B,MAAM,WAAW,mBAAmB;IACnC;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,6EAA6E;AAC7E,MAAM,WAAW,qBAAqB;IACrC,GAAG,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9C,MAAM,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,qGAAqG;IACrG,KAAK,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpD;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,WAAW;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,GAAG,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;IACtD,KAAK,IAAI,qBAAqB,CAAC;IAC/B,QAAQ,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,mBAAmB,CAAC;IAChE,8CAA8C;IAC9C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAsB,KAAK,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,CAY/F"}
|
package/dist/src/leveldb-like.js
CHANGED
|
@@ -10,6 +10,12 @@
|
|
|
10
10
|
* Only `openOptimysticRNDb`, the user-facing constructors, and the identity
|
|
11
11
|
* helper are exported from `index.ts`; the interfaces in this file are
|
|
12
12
|
* internal — consumers never see them.
|
|
13
|
+
*
|
|
14
|
+
* Every write this package makes is a `batch().write(...)`: the surface has no
|
|
15
|
+
* single `put` or `delete`, on purpose. A direct write lands unsynced in
|
|
16
|
+
* LevelDB's current log file, which LevelDB closes unsynced when it switches to
|
|
17
|
+
* a new one, so a later synced write does not cover it — exactly the write the
|
|
18
|
+
* journal under `LevelDBRawStorage` exists to keep out of the store.
|
|
13
19
|
*/
|
|
14
20
|
/**
|
|
15
21
|
* Drain an iterator into an array. Used by storage classes so a native
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"leveldb-like.js","sourceRoot":"","sources":["../../src/leveldb-like.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"leveldb-like.js","sourceRoot":"","sources":["../../src/leveldb-like.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAoEH;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,IAAyB;IACpD,MAAM,GAAG,GAAoC,EAAE,CAAC;IAChD,IAAI,CAAC;QACJ,OAAO,IAAI,EAAE,CAAC;YACb,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;YAChC,IAAI,CAAC,KAAK;gBAAE,MAAM;YAClB,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC;IACF,CAAC;YAAS,CAAC;QACV,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC"}
|