@qntx/nostr 0.12.1 → 0.14.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/dist/{builder-BrmLOVj_.d.mts → builder-C72nJITG.d.mts} +2 -2
- package/dist/{builder-Cf2N12CG.mjs → builder-CGgM_QHT.mjs} +5 -5
- package/dist/{builder-Cf2N12CG.mjs.map → builder-CGgM_QHT.mjs.map} +1 -1
- package/dist/{client-B3_vToDX.mjs → client-COkEihj_.mjs} +87 -79
- package/dist/client-COkEihj_.mjs.map +1 -0
- package/dist/client.d.mts +1 -1
- package/dist/client.mjs +1 -1
- package/dist/core.d.mts +7 -7
- package/dist/core.mjs +9 -9
- package/dist/{emitter-DkCY6NkU.mjs → emitter-u4kJqQDk.mjs} +2 -2
- package/dist/{emitter-DkCY6NkU.mjs.map → emitter-u4kJqQDk.mjs.map} +1 -1
- package/dist/{error-BquXDmIN.d.mts → error-BPqAU5RB.d.mts} +2 -6
- package/dist/{error-BD_0QFKT.d.mts → error-BjSUsx6M.d.mts} +2 -2
- package/dist/{error-D3VNRVhL.mjs → error-Dyb89ahb.mjs} +2 -2
- package/dist/{error-D3VNRVhL.mjs.map → error-Dyb89ahb.mjs.map} +1 -1
- package/dist/{error-DH4guike.mjs → error-QyECUDIp.mjs} +2 -2
- package/dist/{error-DH4guike.mjs.map → error-QyECUDIp.mjs.map} +1 -1
- package/dist/{event-B3ua2_oL.mjs → event-DvM1f03b.mjs} +7 -3
- package/dist/event-DvM1f03b.mjs.map +1 -0
- package/dist/{filter-B16P33dz.mjs → filter-3jOh4uLN.mjs} +50 -20
- package/dist/filter-3jOh4uLN.mjs.map +1 -0
- package/dist/{filter-PG7r79rt.d.mts → filter-oYG2zjJ3.d.mts} +6 -2
- package/dist/{gossip-u0iBlZ1U.d.mts → gossip-BvCItMVZ.d.mts} +3 -3
- package/dist/{gossip-K_JIexQs.mjs → gossip-CRyhK6E6.mjs} +4 -4
- package/dist/{gossip-K_JIexQs.mjs.map → gossip-CRyhK6E6.mjs.map} +1 -1
- package/dist/gossip.d.mts +1 -1
- package/dist/gossip.mjs +1 -1
- package/dist/http-CuazNRIP.mjs.map +1 -1
- package/dist/{index-DD0Ywpay.d.mts → index-B2JlP2Jf.d.mts} +9 -9
- package/dist/{index-SwMknboJ.d.mts → index-CcgmG3F6.d.mts} +19 -18
- package/dist/{index-yq9xkONo.d.mts → index-DCobP2Jj.d.mts} +10 -10
- package/dist/{index-Hp26bgYG.d.mts → index-Dpj_MUxb.d.mts} +8 -5
- package/dist/{index-rKcmI6ex.d.mts → index-DzHmhHqD.d.mts} +3 -3
- package/dist/{index-DxQO1eWA.d.mts → index-muydfuYD.d.mts} +21 -21
- package/dist/index.d.mts +19 -20
- package/dist/index.mjs +20 -20
- package/dist/{key-B218_SoL.mjs → key-D_oEutQ6.mjs} +5 -7
- package/dist/{key-B218_SoL.mjs.map → key-D_oEutQ6.mjs.map} +1 -1
- package/dist/{key-CwMVo14x.d.mts → key-DojW2QZl.d.mts} +3 -5
- package/dist/{kind-D8fENiiL.mjs → kind-I2Tvbe82.mjs} +6 -5
- package/dist/kind-I2Tvbe82.mjs.map +1 -0
- package/dist/{loaders-Xdbx-K61.mjs → loaders-BRh2riV9.mjs} +17 -16
- package/dist/loaders-BRh2riV9.mjs.map +1 -0
- package/dist/loaders.d.mts +2 -2
- package/dist/loaders.mjs +1 -1
- package/dist/{memory-VyPnOBU3.mjs → memory-D_GdEQYG.mjs} +2 -2
- package/dist/memory-D_GdEQYG.mjs.map +1 -0
- package/dist/memory-index-3GSrPIWj.mjs +671 -0
- package/dist/memory-index-3GSrPIWj.mjs.map +1 -0
- package/dist/{message-pYfVKxPn.mjs → message-BMfreCQc.mjs} +6 -6
- package/dist/message-BMfreCQc.mjs.map +1 -0
- package/dist/{nip17-BM4hJYBq.d.mts → nip17-BZvFQLcs.d.mts} +4 -4
- package/dist/{nip19-DpPN17bY.d.mts → nip19-D4RKn6GC.d.mts} +2 -2
- package/dist/{nip46-BHaxC9TZ.d.mts → nip46-i8L8_nIm.d.mts} +2 -2
- package/dist/{nip51-D_bu8Hph.d.mts → nip51-C_kTYcud.d.mts} +2 -2
- package/dist/{nip59-CGWfoItR.d.mts → nip59-DfJ6Moeu.d.mts} +2 -2
- package/dist/{nip65-DaWMg943.d.mts → nip65-CPNE0SV0.d.mts} +2 -2
- package/dist/{nip77-wHA_nEV5.d.mts → nip77-DhpoL7d8.d.mts} +2 -2
- package/dist/nips/blossom.d.mts +2 -2
- package/dist/nips/blossom.mjs +3 -3
- package/dist/nips/blossom.mjs.map +1 -1
- package/dist/nips/nip04.d.mts +9 -12
- package/dist/nips/nip04.mjs +38 -45
- package/dist/nips/nip04.mjs.map +1 -1
- package/dist/nips/nip05.d.mts +6 -3
- package/dist/nips/nip05.mjs +6 -3
- package/dist/nips/nip05.mjs.map +1 -1
- package/dist/nips/nip10.d.mts +2 -2
- package/dist/nips/nip10.mjs +4 -4
- package/dist/nips/nip11.d.mts +1 -1
- package/dist/nips/nip11.mjs +1 -1
- package/dist/nips/nip13.d.mts +1 -1
- package/dist/nips/nip13.mjs +1 -1
- package/dist/nips/nip13.mjs.map +1 -1
- package/dist/nips/nip17.d.mts +1 -1
- package/dist/nips/nip17.mjs +4 -4
- package/dist/nips/nip17.mjs.map +1 -1
- package/dist/nips/nip19.d.mts +1 -1
- package/dist/nips/nip19.mjs +2 -2
- package/dist/nips/nip19.mjs.map +1 -1
- package/dist/nips/nip21.d.mts +6 -3
- package/dist/nips/nip21.mjs +8 -5
- package/dist/nips/nip21.mjs.map +1 -1
- package/dist/nips/nip27.d.mts +1 -1
- package/dist/nips/nip27.mjs +15 -9
- package/dist/nips/nip27.mjs.map +1 -1
- package/dist/nips/nip42.mjs +2 -2
- package/dist/nips/nip44.mjs +1 -1
- package/dist/nips/nip46.d.mts +1 -1
- package/dist/nips/nip46.mjs +9 -7
- package/dist/nips/nip46.mjs.map +1 -1
- package/dist/nips/nip49.d.mts +1 -1
- package/dist/nips/nip49.mjs +1 -1
- package/dist/nips/nip51.d.mts +1 -1
- package/dist/nips/nip51.mjs +5 -5
- package/dist/nips/nip51.mjs.map +1 -1
- package/dist/nips/nip57.mjs +6 -5
- package/dist/nips/nip57.mjs.map +1 -1
- package/dist/nips/nip59.d.mts +1 -1
- package/dist/nips/nip59.mjs +5 -5
- package/dist/nips/nip59.mjs.map +1 -1
- package/dist/nips/nip65.d.mts +1 -1
- package/dist/nips/nip65.mjs +3 -3
- package/dist/nips/nip77.d.mts +1 -1
- package/dist/nips/nip77.mjs +1 -1
- package/dist/nips/nip77.mjs.map +1 -1
- package/dist/nips/nip98.d.mts +1 -1
- package/dist/nips/nip98.mjs +9 -6
- package/dist/nips/nip98.mjs.map +1 -1
- package/dist/{pool-DUuYJ0x4.d.mts → pool-MehgIIzm.d.mts} +20 -16
- package/dist/{pool-THuuOW4S.mjs → pool-lMT_mvzn.mjs} +25 -25
- package/dist/pool-lMT_mvzn.mjs.map +1 -0
- package/dist/{put-DRmV1wHD.mjs → put-BEM5j8xK.mjs} +5 -5
- package/dist/{put-DRmV1wHD.mjs.map → put-BEM5j8xK.mjs.map} +1 -1
- package/dist/{reactive-jyKrA9ej.d.mts → reactive-B7lPFgTS.d.mts} +3 -3
- package/dist/{reactive--pDpLt2H.mjs → reactive-DFHY-f00.mjs} +24 -9
- package/dist/reactive-DFHY-f00.mjs.map +1 -0
- package/dist/{relay-BGPqiGKF.mjs → relay-DIR77xQ2.mjs} +102 -89
- package/dist/relay-DIR77xQ2.mjs.map +1 -0
- package/dist/relay.d.mts +5 -5
- package/dist/relay.mjs +3 -3
- package/dist/{report-CHld4uWj.mjs → report-D2BM5dgn.mjs} +2 -2
- package/dist/{report-CHld4uWj.mjs.map → report-D2BM5dgn.mjs.map} +1 -1
- package/dist/{signer-CNTIeYH4.mjs → signer-Bha9gQy8.mjs} +109 -81
- package/dist/signer-Bha9gQy8.mjs.map +1 -0
- package/dist/signer.d.mts +1 -1
- package/dist/signer.mjs +2 -2
- package/dist/{storage-B5Wdt_Mn.mjs → storage-n2BE1bdY.mjs} +108 -179
- package/dist/storage-n2BE1bdY.mjs.map +1 -0
- package/dist/storage.d.mts +3 -3
- package/dist/storage.mjs +4 -4
- package/dist/store.d.mts +1 -1
- package/dist/store.mjs +1 -1
- package/dist/testing.d.mts +4 -4
- package/dist/testing.mjs +35 -10
- package/dist/testing.mjs.map +1 -1
- package/dist/{types-CqhnT-Mx.d.mts → types-DiVVyf1e.d.mts} +2 -2
- package/dist/{util-DDpPkiED.mjs → util-DfsyJ9nz.mjs} +30 -10
- package/dist/util-DfsyJ9nz.mjs.map +1 -0
- package/dist/{verifier-CjH1vnP2.mjs → verifier-DEHUy4AD.mjs} +3 -3
- package/dist/{verifier-CjH1vnP2.mjs.map → verifier-DEHUy4AD.mjs.map} +1 -1
- package/dist/{verifier-Cl24c9ph.d.mts → verifier-DhAbqVJF.d.mts} +2 -2
- package/dist/{websocket-CmeqvAkp.d.mts → websocket-DaCvJkF9.d.mts} +2 -5
- package/package.json +4 -3
- package/dist/client-B3_vToDX.mjs.map +0 -1
- package/dist/event-B3ua2_oL.mjs.map +0 -1
- package/dist/filter-B16P33dz.mjs.map +0 -1
- package/dist/kind-D8fENiiL.mjs.map +0 -1
- package/dist/loaders-Xdbx-K61.mjs.map +0 -1
- package/dist/memory-VyPnOBU3.mjs.map +0 -1
- package/dist/memory-index-Bhwe0ZdG.mjs +0 -374
- package/dist/memory-index-Bhwe0ZdG.mjs.map +0 -1
- package/dist/message-pYfVKxPn.mjs.map +0 -1
- package/dist/pool-THuuOW4S.mjs.map +0 -1
- package/dist/reactive--pDpLt2H.mjs.map +0 -1
- package/dist/relay-BGPqiGKF.mjs.map +0 -1
- package/dist/signer-CNTIeYH4.mjs.map +0 -1
- package/dist/storage-B5Wdt_Mn.mjs.map +0 -1
- package/dist/util-DDpPkiED.mjs.map +0 -1
|
@@ -0,0 +1,671 @@
|
|
|
1
|
+
import { S as parseEventAddress, _ as eventAddress, f as sortEvents, o as itemCompare, t as compareEventsDesc, y as formatEventAddress } from "./event-DvM1f03b.mjs";
|
|
2
|
+
import { i as filterTagConditions, o as matchFilter } from "./filter-3jOh4uLN.mjs";
|
|
3
|
+
import { i as trimOldest } from "./collections-DtwMc1NU.mjs";
|
|
4
|
+
import { i as DeletionState, n as decidePut, r as outboxBoundKey, t as applyPutMemory } from "./put-BEM5j8xK.mjs";
|
|
5
|
+
//#region src/storage/sorted-events.ts
|
|
6
|
+
/**
|
|
7
|
+
* Chunk bounds: a chunk splice moves at most `CHUNK_MAX` element refs and a chunk merge at
|
|
8
|
+
* `CHUNK_MIN` keeps chunk count proportional to `size` under removals.
|
|
9
|
+
*/
|
|
10
|
+
const CHUNK_MAX = 1024;
|
|
11
|
+
const CHUNK_MIN = 128;
|
|
12
|
+
/** Reverse of `compareEventsDesc`: `created_at` asc, `id` desc — the physical chunk order. */
|
|
13
|
+
function compareAsc(a, b) {
|
|
14
|
+
if (a.created_at !== b.created_at) return a.created_at - b.created_at;
|
|
15
|
+
if (a.id < b.id) return 1;
|
|
16
|
+
if (a.id > b.id) return -1;
|
|
17
|
+
return 0;
|
|
18
|
+
}
|
|
19
|
+
function mid(lo, hi) {
|
|
20
|
+
return lo + Math.floor((hi - lo) / 2);
|
|
21
|
+
}
|
|
22
|
+
/** A read cursor over a `SortedEvents` range in canonical order; `value` is the current event. */
|
|
23
|
+
var EventCursor = class {
|
|
24
|
+
#chunks;
|
|
25
|
+
#chunk;
|
|
26
|
+
#index;
|
|
27
|
+
#endChunk;
|
|
28
|
+
#endIndex;
|
|
29
|
+
constructor(chunks, chunk, index, endChunk, endIndex) {
|
|
30
|
+
this.#chunks = chunks;
|
|
31
|
+
this.#chunk = chunk;
|
|
32
|
+
this.#index = index;
|
|
33
|
+
this.#endChunk = endChunk;
|
|
34
|
+
this.#endIndex = endIndex;
|
|
35
|
+
}
|
|
36
|
+
get value() {
|
|
37
|
+
const chunk = this.#chunk;
|
|
38
|
+
const index = this.#index;
|
|
39
|
+
if (chunk < this.#endChunk || chunk === this.#endChunk && index <= this.#endIndex) return;
|
|
40
|
+
return this.#chunks[chunk]?.[index];
|
|
41
|
+
}
|
|
42
|
+
next() {
|
|
43
|
+
this.#index -= 1;
|
|
44
|
+
if (this.#index < 0) {
|
|
45
|
+
this.#chunk -= 1;
|
|
46
|
+
this.#index = (this.#chunks[this.#chunk]?.length ?? 1) - 1;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Event refs sorted in canonical order (`compareEventsDesc`: `created_at` desc, `id` asc) stored as
|
|
52
|
+
* chunks of ≤ `CHUNK_MAX` elements in ascending physical order so insertion and removal
|
|
53
|
+
* binary-search a chunk and then move a bounded number of refs — appending newer events (live
|
|
54
|
+
* ingest, ascending fills) pushes at the end, and appending older ones (relay backfill) moves at
|
|
55
|
+
* most one chunk's worth of refs. Internal to the memory index; not exported.
|
|
56
|
+
*/
|
|
57
|
+
var SortedEvents = class {
|
|
58
|
+
#chunks = [];
|
|
59
|
+
#size = 0;
|
|
60
|
+
get size() {
|
|
61
|
+
return this.#size;
|
|
62
|
+
}
|
|
63
|
+
clear() {
|
|
64
|
+
this.#chunks = [];
|
|
65
|
+
this.#size = 0;
|
|
66
|
+
}
|
|
67
|
+
/** Index of the chunk `event` belongs to: the last one whose first element is not newer. */
|
|
68
|
+
#chunkOf(event) {
|
|
69
|
+
const chunks = this.#chunks;
|
|
70
|
+
let lo = 0;
|
|
71
|
+
let hi = chunks.length;
|
|
72
|
+
while (lo < hi) {
|
|
73
|
+
const m = mid(lo, hi);
|
|
74
|
+
const first = chunks[m]?.[0];
|
|
75
|
+
if (first !== void 0 && compareAsc(first, event) <= 0) lo = m + 1;
|
|
76
|
+
else hi = m;
|
|
77
|
+
}
|
|
78
|
+
return lo - 1;
|
|
79
|
+
}
|
|
80
|
+
insert(event) {
|
|
81
|
+
const chunks = this.#chunks;
|
|
82
|
+
if (chunks.length === 0) {
|
|
83
|
+
chunks.push([event]);
|
|
84
|
+
this.#size = 1;
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const chunkIndex = Math.max(this.#chunkOf(event), 0);
|
|
88
|
+
const chunk = chunks[chunkIndex];
|
|
89
|
+
if (chunk === void 0) return;
|
|
90
|
+
let a = 0;
|
|
91
|
+
let b = chunk.length;
|
|
92
|
+
while (a < b) {
|
|
93
|
+
const m = mid(a, b);
|
|
94
|
+
const element = chunk[m];
|
|
95
|
+
if (element !== void 0 && compareAsc(element, event) <= 0) a = m + 1;
|
|
96
|
+
else b = m;
|
|
97
|
+
}
|
|
98
|
+
chunk.splice(a, 0, event);
|
|
99
|
+
this.#size += 1;
|
|
100
|
+
if (chunk.length > CHUNK_MAX) {
|
|
101
|
+
const half = chunk.splice(Math.floor(CHUNK_MAX / 2));
|
|
102
|
+
chunks.splice(chunkIndex + 1, 0, half);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
remove(event) {
|
|
106
|
+
const chunks = this.#chunks;
|
|
107
|
+
const chunkIndex = this.#chunkOf(event);
|
|
108
|
+
if (chunkIndex < 0) return false;
|
|
109
|
+
const chunk = chunks[chunkIndex];
|
|
110
|
+
if (chunk === void 0) return false;
|
|
111
|
+
let a = 0;
|
|
112
|
+
let b = chunk.length;
|
|
113
|
+
while (a < b) {
|
|
114
|
+
const m = mid(a, b);
|
|
115
|
+
const element = chunk[m];
|
|
116
|
+
if (element !== void 0 && compareAsc(element, event) < 0) a = m + 1;
|
|
117
|
+
else b = m;
|
|
118
|
+
}
|
|
119
|
+
const found = chunk[a];
|
|
120
|
+
if (found === void 0 || compareAsc(found, event) !== 0) return false;
|
|
121
|
+
chunk.splice(a, 1);
|
|
122
|
+
this.#size -= 1;
|
|
123
|
+
if (chunk.length === 0) chunks.splice(chunkIndex, 1);
|
|
124
|
+
else if (chunk.length < CHUNK_MIN) {
|
|
125
|
+
const next = chunks[chunkIndex + 1];
|
|
126
|
+
const prev = chunks[chunkIndex - 1];
|
|
127
|
+
if (next !== void 0 && chunk.length + next.length <= CHUNK_MAX) {
|
|
128
|
+
chunk.push(...next);
|
|
129
|
+
chunks.splice(chunkIndex + 1, 1);
|
|
130
|
+
} else if (prev !== void 0 && prev.length + chunk.length <= CHUNK_MAX) {
|
|
131
|
+
prev.push(...chunk);
|
|
132
|
+
chunks.splice(chunkIndex, 1);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Cursor over the [since, until] `created_at` window in canonical (desc) order: iteration starts
|
|
139
|
+
* at the newest element with `created_at <= until` and stops before the first with `created_at <
|
|
140
|
+
* since`. Chunks and their elements are stored ascending; the cursor walks back.
|
|
141
|
+
*/
|
|
142
|
+
cursor(since, until) {
|
|
143
|
+
const chunks = this.#chunks;
|
|
144
|
+
let chunk = chunks.length - 1;
|
|
145
|
+
let index = -1;
|
|
146
|
+
if (until === void 0) index = (chunks[chunk]?.length ?? 1) - 1;
|
|
147
|
+
else {
|
|
148
|
+
let lo = 0;
|
|
149
|
+
let hi = chunks.length;
|
|
150
|
+
while (lo < hi) {
|
|
151
|
+
const m = mid(lo, hi);
|
|
152
|
+
const first = chunks[m]?.[0];
|
|
153
|
+
if (first !== void 0 && first.created_at <= until) lo = m + 1;
|
|
154
|
+
else hi = m;
|
|
155
|
+
}
|
|
156
|
+
chunk = lo - 1;
|
|
157
|
+
if (chunk >= 0) {
|
|
158
|
+
const bucket = chunks[chunk];
|
|
159
|
+
let a = 0;
|
|
160
|
+
let b = bucket?.length ?? 0;
|
|
161
|
+
while (a < b) {
|
|
162
|
+
const m = mid(a, b);
|
|
163
|
+
const element = bucket?.[m];
|
|
164
|
+
if (element !== void 0 && element.created_at <= until) a = m + 1;
|
|
165
|
+
else b = m;
|
|
166
|
+
}
|
|
167
|
+
index = a - 1;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
let endChunk = -1;
|
|
171
|
+
let endIndex = -1;
|
|
172
|
+
if (since !== void 0) {
|
|
173
|
+
let lo = 0;
|
|
174
|
+
let hi = chunks.length;
|
|
175
|
+
while (lo < hi) {
|
|
176
|
+
const m = mid(lo, hi);
|
|
177
|
+
const last = chunks[m]?.at(-1);
|
|
178
|
+
if (last !== void 0 && last.created_at >= since) hi = m;
|
|
179
|
+
else lo = m + 1;
|
|
180
|
+
}
|
|
181
|
+
if (lo === chunks.length) endChunk = Number.MAX_SAFE_INTEGER;
|
|
182
|
+
else {
|
|
183
|
+
const bucket = chunks[lo];
|
|
184
|
+
let a = 0;
|
|
185
|
+
let b = bucket?.length ?? 0;
|
|
186
|
+
while (a < b) {
|
|
187
|
+
const m = mid(a, b);
|
|
188
|
+
const element = bucket?.[m];
|
|
189
|
+
if (element !== void 0 && element.created_at >= since) b = m;
|
|
190
|
+
else a = m + 1;
|
|
191
|
+
}
|
|
192
|
+
if (a === 0) {
|
|
193
|
+
endChunk = lo - 1;
|
|
194
|
+
endIndex = (chunks[endChunk]?.length ?? 1) - 1;
|
|
195
|
+
} else {
|
|
196
|
+
endChunk = lo;
|
|
197
|
+
endIndex = a - 1;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return new EventCursor(chunks, chunk, index, endChunk, endIndex);
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
//#endregion
|
|
205
|
+
//#region src/storage/memory-index.ts
|
|
206
|
+
/**
|
|
207
|
+
* NIP-01 only defines single-letter tag conditions; `#e`/`#p` hold hex ids (filter side
|
|
208
|
+
* lowercased).
|
|
209
|
+
*/
|
|
210
|
+
const SINGLE_ASCII_LETTER = /^[a-zA-Z]$/;
|
|
211
|
+
/**
|
|
212
|
+
* Synchronous in-memory event index with NIP-01 replaceable / addressable / ephemeral handling and
|
|
213
|
+
* NIP-09 deletion (kind 5) application. Shared by {@link MemoryEventStore} (async facade) and
|
|
214
|
+
* `ReactiveEventStore`.
|
|
215
|
+
*/
|
|
216
|
+
var MemoryIndex = class {
|
|
217
|
+
#byId = /* @__PURE__ */ new Map();
|
|
218
|
+
#all = new SortedEvents();
|
|
219
|
+
#byPubkey = /* @__PURE__ */ new Map();
|
|
220
|
+
#byKind = /* @__PURE__ */ new Map();
|
|
221
|
+
#byKindPubkey = /* @__PURE__ */ new Map();
|
|
222
|
+
#byTag = /* @__PURE__ */ new Map();
|
|
223
|
+
#replaceable = /* @__PURE__ */ new Map();
|
|
224
|
+
#watermarks = /* @__PURE__ */ new Map();
|
|
225
|
+
#watermarkIds = /* @__PURE__ */ new Map();
|
|
226
|
+
#deletion = new DeletionState();
|
|
227
|
+
#outboxBounds = /* @__PURE__ */ new Map();
|
|
228
|
+
#maxTombstones;
|
|
229
|
+
#maxWatermarks;
|
|
230
|
+
#onInsert;
|
|
231
|
+
#onRemove;
|
|
232
|
+
constructor(opts) {
|
|
233
|
+
this.#maxTombstones = opts?.maxTombstones;
|
|
234
|
+
this.#maxWatermarks = opts?.maxWatermarks ?? 0;
|
|
235
|
+
this.#onInsert = opts?.onInsert;
|
|
236
|
+
this.#onRemove = opts?.onRemove;
|
|
237
|
+
}
|
|
238
|
+
put(raw) {
|
|
239
|
+
const lookup = {
|
|
240
|
+
deletion: this.#deletion,
|
|
241
|
+
getById: (id) => this.#byId.get(id),
|
|
242
|
+
getReplaceable: (addr) => {
|
|
243
|
+
const id = this.#replaceable.get(addr);
|
|
244
|
+
const ev = id === void 0 ? void 0 : this.#byId.get(id);
|
|
245
|
+
if (ev) return {
|
|
246
|
+
id: ev.id,
|
|
247
|
+
created_at: ev.created_at
|
|
248
|
+
};
|
|
249
|
+
const watermark = this.#watermarks.get(addr);
|
|
250
|
+
return watermark === void 0 ? void 0 : {
|
|
251
|
+
...watermark,
|
|
252
|
+
evicted: true
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
const decision = decidePut(raw, lookup);
|
|
257
|
+
if (decision.action === "delete") {
|
|
258
|
+
for (const p of decision.plan.pendingIds) this.#dropWatermarkId(p.id);
|
|
259
|
+
for (const c of decision.plan.coordinates) this.#dropWatermark(c.key);
|
|
260
|
+
}
|
|
261
|
+
const result = applyPutMemory({
|
|
262
|
+
deletion: this.#deletion,
|
|
263
|
+
indexInsert: (e) => this.#indexInsert(e),
|
|
264
|
+
indexRemove: (id) => this.#indexRemove(id)
|
|
265
|
+
}, decision);
|
|
266
|
+
this.#trimTombstones();
|
|
267
|
+
return result;
|
|
268
|
+
}
|
|
269
|
+
/** Sequential `put` in input order. */
|
|
270
|
+
putMany(events) {
|
|
271
|
+
const results = [];
|
|
272
|
+
for (const event of events) results.push(this.put(event));
|
|
273
|
+
return results;
|
|
274
|
+
}
|
|
275
|
+
get(id) {
|
|
276
|
+
const key = id.toLowerCase();
|
|
277
|
+
if (this.#deletion.ids.has(key)) return;
|
|
278
|
+
return this.#byId.get(key);
|
|
279
|
+
}
|
|
280
|
+
/** Current event at a `kind:pubkey:d` coordinate (replaceable or addressable). */
|
|
281
|
+
getByAddress(address) {
|
|
282
|
+
const coord = parseEventAddress(address);
|
|
283
|
+
if (!coord) return;
|
|
284
|
+
const id = this.#replaceable.get(formatEventAddress(coord.kind, coord.pubkey, coord.identifier));
|
|
285
|
+
if (id === void 0) return;
|
|
286
|
+
if (this.#deletion.ids.has(id)) return;
|
|
287
|
+
return this.#byId.get(id);
|
|
288
|
+
}
|
|
289
|
+
query(filters) {
|
|
290
|
+
const seen = /* @__PURE__ */ new Set();
|
|
291
|
+
const events = [];
|
|
292
|
+
for (const filter of filters) for (const event of this.#matchedEvents(filter)) {
|
|
293
|
+
if (seen.has(event.id)) continue;
|
|
294
|
+
seen.add(event.id);
|
|
295
|
+
events.push(event);
|
|
296
|
+
}
|
|
297
|
+
sortEvents(events);
|
|
298
|
+
return events;
|
|
299
|
+
}
|
|
300
|
+
count(filters) {
|
|
301
|
+
const seen = /* @__PURE__ */ new Set();
|
|
302
|
+
for (const filter of filters) for (const event of this.#matchedEvents(filter)) seen.add(event.id);
|
|
303
|
+
return seen.size;
|
|
304
|
+
}
|
|
305
|
+
negentropyItems(filter) {
|
|
306
|
+
if (filter.limit === 0) return [];
|
|
307
|
+
const items = [];
|
|
308
|
+
const { limit } = filter;
|
|
309
|
+
if (filter.ids) {
|
|
310
|
+
const seen = /* @__PURE__ */ new Set();
|
|
311
|
+
for (const raw of filter.ids) {
|
|
312
|
+
const event = this.#byId.get(raw.toLowerCase());
|
|
313
|
+
if (!event || seen.has(event.id)) continue;
|
|
314
|
+
seen.add(event.id);
|
|
315
|
+
if (this.#deletion.covers(event) || !matchFilter(filter, event)) continue;
|
|
316
|
+
items.push({
|
|
317
|
+
id: event.id,
|
|
318
|
+
created_at: event.created_at
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
} else {
|
|
322
|
+
const cursor = this.#candidates(filter);
|
|
323
|
+
while (cursor.value !== void 0) {
|
|
324
|
+
const event = cursor.value;
|
|
325
|
+
cursor.next();
|
|
326
|
+
if (this.#deletion.covers(event) || !matchFilter(filter, event)) continue;
|
|
327
|
+
items.push({
|
|
328
|
+
id: event.id,
|
|
329
|
+
created_at: event.created_at
|
|
330
|
+
});
|
|
331
|
+
if (limit !== void 0 && items.length >= limit) break;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
if (filter.limit !== void 0) {
|
|
335
|
+
if (filter.ids) items.sort(compareEventsDesc);
|
|
336
|
+
if (items.length > filter.limit) items.length = filter.limit;
|
|
337
|
+
}
|
|
338
|
+
items.sort(itemCompare);
|
|
339
|
+
return items;
|
|
340
|
+
}
|
|
341
|
+
/** Remove by id and tombstone (like a local NIP-09). Returns removed count. */
|
|
342
|
+
remove(ids) {
|
|
343
|
+
let n = 0;
|
|
344
|
+
for (const raw of ids) {
|
|
345
|
+
const id = raw.toLowerCase();
|
|
346
|
+
if (this.#indexRemove(id)) n += 1;
|
|
347
|
+
this.#deletion.ids.add(id);
|
|
348
|
+
this.#deletion.pending.delete(id);
|
|
349
|
+
}
|
|
350
|
+
this.#trimTombstones();
|
|
351
|
+
return n;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Remove by id without writing a tombstone (LRU eviction). When the evicted event is the current
|
|
355
|
+
* winner of a replaceable/addressable address, a `{ id, created_at }` watermark is recorded so
|
|
356
|
+
* stale versions stay rejected while the body is gone; the watermarks are FIFO-bounded by
|
|
357
|
+
* `maxWatermarks`.
|
|
358
|
+
*/
|
|
359
|
+
evict(ids) {
|
|
360
|
+
let n = 0;
|
|
361
|
+
for (const raw of ids) {
|
|
362
|
+
const id = raw.toLowerCase();
|
|
363
|
+
const event = this.#byId.get(id);
|
|
364
|
+
if (event === void 0) continue;
|
|
365
|
+
const addr = eventAddress(event);
|
|
366
|
+
const winner = addr !== void 0 && this.#replaceable.get(addr) === id;
|
|
367
|
+
if (this.#indexRemove(id)) n += 1;
|
|
368
|
+
if (winner) this.#setWatermark(addr, {
|
|
369
|
+
id,
|
|
370
|
+
created_at: event.created_at
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
return n;
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* True when the id is tombstoned, or the coordinate has a deletion marker that still covers the
|
|
377
|
+
* current event at that address: a replacement published after the marker's `until` clears the
|
|
378
|
+
* deletion. Coordinates are matched on the canonical lowercase pubkey.
|
|
379
|
+
*/
|
|
380
|
+
isDeleted(idOrAddress) {
|
|
381
|
+
if (this.#deletion.ids.has(idOrAddress.toLowerCase())) return true;
|
|
382
|
+
const coord = parseEventAddress(idOrAddress);
|
|
383
|
+
if (!coord) return false;
|
|
384
|
+
const address = formatEventAddress(coord.kind, coord.pubkey, coord.identifier);
|
|
385
|
+
const until = this.#deletion.coordinates.get(address);
|
|
386
|
+
if (until === void 0) return false;
|
|
387
|
+
const id = this.#replaceable.get(address);
|
|
388
|
+
if (id === void 0) return true;
|
|
389
|
+
const event = this.#byId.get(id);
|
|
390
|
+
return event === void 0 || event.created_at <= until;
|
|
391
|
+
}
|
|
392
|
+
getOutboxBound(pubkey, kind) {
|
|
393
|
+
const persisted = this.#outboxBounds.get(outboxBoundKey(pubkey, kind));
|
|
394
|
+
if (persisted) return {
|
|
395
|
+
oldest: persisted.oldest,
|
|
396
|
+
newest: persisted.newest
|
|
397
|
+
};
|
|
398
|
+
return this.#deriveOutboxBound(pubkey, kind);
|
|
399
|
+
}
|
|
400
|
+
setOutboxBound(pubkey, kind, bound) {
|
|
401
|
+
this.#outboxBounds.set(outboxBoundKey(pubkey, kind), {
|
|
402
|
+
oldest: bound.oldest,
|
|
403
|
+
newest: bound.newest
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
clear() {
|
|
407
|
+
if (this.#onRemove) for (const event of this.#byId.values()) this.#onRemove(event);
|
|
408
|
+
this.#byId.clear();
|
|
409
|
+
this.#all.clear();
|
|
410
|
+
this.#byPubkey.clear();
|
|
411
|
+
this.#byKind.clear();
|
|
412
|
+
this.#byKindPubkey.clear();
|
|
413
|
+
this.#byTag.clear();
|
|
414
|
+
this.#replaceable.clear();
|
|
415
|
+
this.#watermarks.clear();
|
|
416
|
+
this.#watermarkIds.clear();
|
|
417
|
+
this.#deletion.clear();
|
|
418
|
+
this.#outboxBounds.clear();
|
|
419
|
+
}
|
|
420
|
+
get size() {
|
|
421
|
+
return this.#byId.size;
|
|
422
|
+
}
|
|
423
|
+
#indexInsert(event) {
|
|
424
|
+
this.#byId.set(event.id, event);
|
|
425
|
+
const { pubkey } = event;
|
|
426
|
+
this.#all.insert(event);
|
|
427
|
+
insertBucket(this.#byPubkey, pubkey, event);
|
|
428
|
+
insertBucket(this.#byKind, event.kind, event);
|
|
429
|
+
insertBucket(this.#byKindPubkey, `${event.kind}:${pubkey}`, event);
|
|
430
|
+
for (const key of tagKeys(event)) insertBucket(this.#byTag, key, event);
|
|
431
|
+
const addr = eventAddress(event);
|
|
432
|
+
if (addr !== void 0) {
|
|
433
|
+
this.#replaceable.set(addr, event.id);
|
|
434
|
+
this.#dropWatermark(addr);
|
|
435
|
+
}
|
|
436
|
+
this.#onInsert?.(event);
|
|
437
|
+
}
|
|
438
|
+
#indexRemove(id) {
|
|
439
|
+
this.#dropWatermarkId(id);
|
|
440
|
+
const event = this.#byId.get(id);
|
|
441
|
+
if (!event) return false;
|
|
442
|
+
this.#byId.delete(id);
|
|
443
|
+
const { pubkey } = event;
|
|
444
|
+
this.#all.remove(event);
|
|
445
|
+
removeBucket(this.#byPubkey, pubkey, event);
|
|
446
|
+
removeBucket(this.#byKind, event.kind, event);
|
|
447
|
+
removeBucket(this.#byKindPubkey, `${event.kind}:${pubkey}`, event);
|
|
448
|
+
for (const key of tagKeys(event)) removeBucket(this.#byTag, key, event);
|
|
449
|
+
const addr = eventAddress(event);
|
|
450
|
+
if (addr !== void 0 && this.#replaceable.get(addr) === id) this.#replaceable.delete(addr);
|
|
451
|
+
this.#onRemove?.(event);
|
|
452
|
+
return true;
|
|
453
|
+
}
|
|
454
|
+
#matchedEvents(filter) {
|
|
455
|
+
if (filter.limit === 0) return [];
|
|
456
|
+
const { limit } = filter;
|
|
457
|
+
const matched = [];
|
|
458
|
+
if (filter.ids) {
|
|
459
|
+
const seen = /* @__PURE__ */ new Set();
|
|
460
|
+
for (const raw of filter.ids) {
|
|
461
|
+
const event = this.#byId.get(raw.toLowerCase());
|
|
462
|
+
if (!event || seen.has(event.id)) continue;
|
|
463
|
+
seen.add(event.id);
|
|
464
|
+
if (this.#deletion.covers(event) || !matchFilter(filter, event)) continue;
|
|
465
|
+
matched.push(event);
|
|
466
|
+
}
|
|
467
|
+
sortEvents(matched);
|
|
468
|
+
return limit === void 0 ? matched : matched.slice(0, limit);
|
|
469
|
+
}
|
|
470
|
+
const cursor = this.#candidates(filter);
|
|
471
|
+
while (cursor.value !== void 0) {
|
|
472
|
+
const event = cursor.value;
|
|
473
|
+
cursor.next();
|
|
474
|
+
if (this.#deletion.covers(event) || !matchFilter(filter, event)) continue;
|
|
475
|
+
matched.push(event);
|
|
476
|
+
if (limit !== void 0 && matched.length >= limit) break;
|
|
477
|
+
}
|
|
478
|
+
return matched;
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Smallest-total bucket set for the filter's usable indexes: `authors`×`kinds` (both present),
|
|
482
|
+
* `authors`, `kinds`, each single-letter `#x` condition (a bucket per value; `#e`/`#p` filter
|
|
483
|
+
* values lowercased like `matchFilter`, others verbatim), or `all` as the fallback.
|
|
484
|
+
*/
|
|
485
|
+
#plan(filter) {
|
|
486
|
+
const { authors, kinds } = filter;
|
|
487
|
+
const tagConds = filterTagConditions(filter);
|
|
488
|
+
let best;
|
|
489
|
+
let bestTotal = Number.POSITIVE_INFINITY;
|
|
490
|
+
const consider = (buckets) => {
|
|
491
|
+
let total = 0;
|
|
492
|
+
const present = [];
|
|
493
|
+
for (const bucket of buckets) if (bucket !== void 0) {
|
|
494
|
+
present.push(bucket);
|
|
495
|
+
total += bucket.size;
|
|
496
|
+
}
|
|
497
|
+
if (total < bestTotal) {
|
|
498
|
+
bestTotal = total;
|
|
499
|
+
best = present;
|
|
500
|
+
}
|
|
501
|
+
};
|
|
502
|
+
if (authors !== void 0 && kinds !== void 0) {
|
|
503
|
+
const buckets = [];
|
|
504
|
+
for (const pk of authors) {
|
|
505
|
+
const pubkey = pk.toLowerCase();
|
|
506
|
+
for (const kind of kinds) buckets.push(this.#byKindPubkey.get(`${kind}:${pubkey}`));
|
|
507
|
+
}
|
|
508
|
+
consider(buckets);
|
|
509
|
+
}
|
|
510
|
+
if (authors !== void 0) consider(authors.map((pk) => this.#byPubkey.get(pk.toLowerCase())));
|
|
511
|
+
if (kinds !== void 0) consider(kinds.map((kind) => this.#byKind.get(kind)));
|
|
512
|
+
for (const { name, values } of tagConds) consider(values.map((v) => this.#byTag.get(`${name}:${v}`)));
|
|
513
|
+
if (best === void 0 || bestTotal > this.#all.size) return [this.#all];
|
|
514
|
+
return best;
|
|
515
|
+
}
|
|
516
|
+
/** Canonical-order candidates from the planned buckets, each clipped to `since`/`until`. */
|
|
517
|
+
#candidates(filter) {
|
|
518
|
+
const buckets = this.#plan(filter);
|
|
519
|
+
const cursors = [];
|
|
520
|
+
for (const bucket of buckets) {
|
|
521
|
+
const cursor = bucket.cursor(filter.since, filter.until);
|
|
522
|
+
if (cursor.value !== void 0) cursors.push(cursor);
|
|
523
|
+
}
|
|
524
|
+
if (cursors.length === 0) return EMPTY_CURSOR;
|
|
525
|
+
if (cursors.length === 1) return cursors[0] ?? EMPTY_CURSOR;
|
|
526
|
+
return new CursorHeap(cursors);
|
|
527
|
+
}
|
|
528
|
+
#deriveOutboxBound(pubkey, kind) {
|
|
529
|
+
const bucket = this.#byKindPubkey.get(`${kind}:${pubkey.toLowerCase()}`);
|
|
530
|
+
if (bucket === void 0) return;
|
|
531
|
+
let oldest;
|
|
532
|
+
let newest;
|
|
533
|
+
const cursor = bucket.cursor();
|
|
534
|
+
while (cursor.value !== void 0) {
|
|
535
|
+
const event = cursor.value;
|
|
536
|
+
cursor.next();
|
|
537
|
+
if (this.#deletion.covers(event)) continue;
|
|
538
|
+
newest ??= event.created_at;
|
|
539
|
+
oldest = event.created_at;
|
|
540
|
+
}
|
|
541
|
+
if (oldest === void 0 || newest === void 0) return;
|
|
542
|
+
return {
|
|
543
|
+
oldest,
|
|
544
|
+
newest
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
#setWatermark(addr, watermark) {
|
|
548
|
+
if (this.#maxWatermarks === 0) return;
|
|
549
|
+
this.#dropWatermark(addr);
|
|
550
|
+
this.#watermarks.set(addr, watermark);
|
|
551
|
+
this.#watermarkIds.set(watermark.id, addr);
|
|
552
|
+
trimOldest(this.#watermarks, this.#maxWatermarks, (a) => this.#dropWatermark(a));
|
|
553
|
+
}
|
|
554
|
+
#dropWatermark(addr) {
|
|
555
|
+
const watermark = this.#watermarks.get(addr);
|
|
556
|
+
if (watermark === void 0) return;
|
|
557
|
+
this.#watermarks.delete(addr);
|
|
558
|
+
this.#watermarkIds.delete(watermark.id);
|
|
559
|
+
}
|
|
560
|
+
#dropWatermarkId(id) {
|
|
561
|
+
const addr = this.#watermarkIds.get(id);
|
|
562
|
+
if (addr === void 0) return;
|
|
563
|
+
this.#watermarkIds.delete(id);
|
|
564
|
+
this.#watermarks.delete(addr);
|
|
565
|
+
}
|
|
566
|
+
#trimTombstones() {
|
|
567
|
+
const cap = this.#maxTombstones;
|
|
568
|
+
if (cap === void 0) return;
|
|
569
|
+
trimOldest(this.#deletion.ids, cap, (id) => {
|
|
570
|
+
this.#deletion.pending.delete(id);
|
|
571
|
+
});
|
|
572
|
+
trimOldest(this.#deletion.pending, cap);
|
|
573
|
+
trimOldest(this.#deletion.coordinates, cap);
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
const EMPTY_CURSOR = {
|
|
577
|
+
value: void 0,
|
|
578
|
+
next: () => void 0
|
|
579
|
+
};
|
|
580
|
+
/**
|
|
581
|
+
* Binary-heap k-way merge of sorted cursors. `next()` advances every cursor sitting on the emitted
|
|
582
|
+
* event, which dedupes an event present in several buckets (multi-value `#x` filters); copies
|
|
583
|
+
* compare equal so they always surface adjacent. Entries pair each cursor with its head event so
|
|
584
|
+
* heap comparisons never read `undefined`.
|
|
585
|
+
*/
|
|
586
|
+
var CursorHeap = class {
|
|
587
|
+
#heap;
|
|
588
|
+
constructor(cursors) {
|
|
589
|
+
const heap = [];
|
|
590
|
+
for (const cursor of cursors) {
|
|
591
|
+
const event = cursor.value;
|
|
592
|
+
if (event !== void 0) heap.push({
|
|
593
|
+
cursor,
|
|
594
|
+
event
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
this.#heap = heap;
|
|
598
|
+
for (let i = Math.floor(heap.length / 2) - 1; i >= 0; i--) this.#siftDown(i);
|
|
599
|
+
}
|
|
600
|
+
get value() {
|
|
601
|
+
return this.#heap[0]?.event;
|
|
602
|
+
}
|
|
603
|
+
next() {
|
|
604
|
+
const emitted = this.#heap[0]?.event;
|
|
605
|
+
if (emitted === void 0) return;
|
|
606
|
+
while (this.#heap[0]?.event === emitted) {
|
|
607
|
+
const [root] = this.#heap;
|
|
608
|
+
if (root === void 0) return;
|
|
609
|
+
root.cursor.next();
|
|
610
|
+
const nextEvent = root.cursor.value;
|
|
611
|
+
if (nextEvent === void 0) {
|
|
612
|
+
const last = this.#heap.pop();
|
|
613
|
+
if (this.#heap.length > 0 && last !== void 0) {
|
|
614
|
+
this.#heap[0] = last;
|
|
615
|
+
this.#siftDown(0);
|
|
616
|
+
}
|
|
617
|
+
} else {
|
|
618
|
+
root.event = nextEvent;
|
|
619
|
+
this.#siftDown(0);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
#less(a, b) {
|
|
624
|
+
const x = this.#heap[a];
|
|
625
|
+
const y = this.#heap[b];
|
|
626
|
+
return x !== void 0 && y !== void 0 && compareEventsDesc(x.event, y.event) < 0;
|
|
627
|
+
}
|
|
628
|
+
#siftDown(start) {
|
|
629
|
+
const heap = this.#heap;
|
|
630
|
+
let i = start;
|
|
631
|
+
for (;;) {
|
|
632
|
+
let min = i;
|
|
633
|
+
if (this.#less(2 * i + 1, min)) min = 2 * i + 1;
|
|
634
|
+
if (this.#less(2 * i + 2, min)) min = 2 * i + 2;
|
|
635
|
+
if (min === i) return;
|
|
636
|
+
const tmp = heap[i];
|
|
637
|
+
const swap = heap[min];
|
|
638
|
+
if (tmp === void 0 || swap === void 0) return;
|
|
639
|
+
heap[i] = swap;
|
|
640
|
+
heap[min] = tmp;
|
|
641
|
+
i = min;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
};
|
|
645
|
+
/** Distinct `${name}:${value}` bucket keys for every ASCII single-letter tag name on the event. */
|
|
646
|
+
function tagKeys(event) {
|
|
647
|
+
const keys = /* @__PURE__ */ new Set();
|
|
648
|
+
for (const tag of event.tags) {
|
|
649
|
+
const [name, value] = tag;
|
|
650
|
+
if (name === void 0 || value === void 0 || !SINGLE_ASCII_LETTER.test(name)) continue;
|
|
651
|
+
keys.add(`${name}:${value}`);
|
|
652
|
+
}
|
|
653
|
+
return [...keys];
|
|
654
|
+
}
|
|
655
|
+
function insertBucket(map, key, event) {
|
|
656
|
+
let bucket = map.get(key);
|
|
657
|
+
if (bucket === void 0) {
|
|
658
|
+
bucket = new SortedEvents();
|
|
659
|
+
map.set(key, bucket);
|
|
660
|
+
}
|
|
661
|
+
bucket.insert(event);
|
|
662
|
+
}
|
|
663
|
+
function removeBucket(map, key, event) {
|
|
664
|
+
const bucket = map.get(key);
|
|
665
|
+
if (bucket === void 0 || !bucket.remove(event)) return;
|
|
666
|
+
if (bucket.size === 0) map.delete(key);
|
|
667
|
+
}
|
|
668
|
+
//#endregion
|
|
669
|
+
export { MemoryIndex as t };
|
|
670
|
+
|
|
671
|
+
//# sourceMappingURL=memory-index-3GSrPIWj.mjs.map
|