@peerbit/shared-log 9.2.13 → 10.0.0-05f4bef

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/dist/benchmark/get-samples.js +190 -64
  2. package/dist/benchmark/get-samples.js.map +1 -1
  3. package/dist/benchmark/index.js +16 -38
  4. package/dist/benchmark/index.js.map +1 -1
  5. package/dist/benchmark/memory/child.js.map +1 -1
  6. package/dist/benchmark/partial-sync.d.ts +3 -0
  7. package/dist/benchmark/partial-sync.d.ts.map +1 -0
  8. package/dist/benchmark/partial-sync.js +121 -0
  9. package/dist/benchmark/partial-sync.js.map +1 -0
  10. package/dist/benchmark/replication-prune.js.map +1 -1
  11. package/dist/benchmark/replication.js.map +1 -1
  12. package/dist/benchmark/to-rebalance.d.ts +2 -0
  13. package/dist/benchmark/to-rebalance.d.ts.map +1 -0
  14. package/dist/benchmark/to-rebalance.js +117 -0
  15. package/dist/benchmark/to-rebalance.js.map +1 -0
  16. package/dist/benchmark/utils.d.ts +24 -0
  17. package/dist/benchmark/utils.d.ts.map +1 -0
  18. package/dist/benchmark/utils.js +47 -0
  19. package/dist/benchmark/utils.js.map +1 -0
  20. package/dist/src/debounce.d.ts +2 -2
  21. package/dist/src/debounce.d.ts.map +1 -1
  22. package/dist/src/debounce.js +17 -47
  23. package/dist/src/debounce.js.map +1 -1
  24. package/dist/src/exchange-heads.d.ts +1 -13
  25. package/dist/src/exchange-heads.d.ts.map +1 -1
  26. package/dist/src/exchange-heads.js +0 -32
  27. package/dist/src/exchange-heads.js.map +1 -1
  28. package/dist/src/index.d.ts +119 -60
  29. package/dist/src/index.d.ts.map +1 -1
  30. package/dist/src/index.js +1116 -762
  31. package/dist/src/index.js.map +1 -1
  32. package/dist/src/integers.d.ts +22 -0
  33. package/dist/src/integers.d.ts.map +1 -0
  34. package/dist/src/integers.js +76 -0
  35. package/dist/src/integers.js.map +1 -0
  36. package/dist/src/pid.d.ts.map +1 -1
  37. package/dist/src/pid.js +22 -22
  38. package/dist/src/pid.js.map +1 -1
  39. package/dist/src/ranges.d.ts +168 -38
  40. package/dist/src/ranges.d.ts.map +1 -1
  41. package/dist/src/ranges.js +869 -272
  42. package/dist/src/ranges.js.map +1 -1
  43. package/dist/src/replication-domain-hash.d.ts +2 -3
  44. package/dist/src/replication-domain-hash.d.ts.map +1 -1
  45. package/dist/src/replication-domain-hash.js +40 -15
  46. package/dist/src/replication-domain-hash.js.map +1 -1
  47. package/dist/src/replication-domain-time.d.ts +5 -5
  48. package/dist/src/replication-domain-time.d.ts.map +1 -1
  49. package/dist/src/replication-domain-time.js +2 -0
  50. package/dist/src/replication-domain-time.js.map +1 -1
  51. package/dist/src/replication-domain.d.ts +17 -19
  52. package/dist/src/replication-domain.d.ts.map +1 -1
  53. package/dist/src/replication-domain.js +2 -6
  54. package/dist/src/replication-domain.js.map +1 -1
  55. package/dist/src/replication.d.ts +6 -6
  56. package/dist/src/replication.d.ts.map +1 -1
  57. package/dist/src/replication.js +4 -4
  58. package/dist/src/replication.js.map +1 -1
  59. package/dist/src/role.d.ts +3 -6
  60. package/dist/src/role.d.ts.map +1 -1
  61. package/dist/src/role.js +4 -5
  62. package/dist/src/role.js.map +1 -1
  63. package/dist/src/sync/index.d.ts +40 -0
  64. package/dist/src/sync/index.d.ts.map +1 -0
  65. package/dist/src/sync/index.js +2 -0
  66. package/dist/src/sync/index.js.map +1 -0
  67. package/dist/src/sync/rateless-iblt.d.ts +124 -0
  68. package/dist/src/sync/rateless-iblt.d.ts.map +1 -0
  69. package/dist/src/sync/rateless-iblt.js +495 -0
  70. package/dist/src/sync/rateless-iblt.js.map +1 -0
  71. package/dist/src/sync/simple.d.ts +69 -0
  72. package/dist/src/sync/simple.d.ts.map +1 -0
  73. package/dist/src/sync/simple.js +338 -0
  74. package/dist/src/sync/simple.js.map +1 -0
  75. package/dist/src/sync/wasm-init.browser.d.ts +1 -0
  76. package/dist/src/sync/wasm-init.browser.d.ts.map +1 -0
  77. package/dist/src/sync/wasm-init.browser.js +3 -0
  78. package/dist/src/sync/wasm-init.browser.js.map +1 -0
  79. package/dist/src/sync/wasm-init.d.ts +2 -0
  80. package/dist/src/sync/wasm-init.d.ts.map +1 -0
  81. package/dist/src/sync/wasm-init.js +13 -0
  82. package/dist/src/sync/wasm-init.js.map +1 -0
  83. package/dist/src/utils.d.ts +3 -3
  84. package/dist/src/utils.d.ts.map +1 -1
  85. package/dist/src/utils.js +2 -2
  86. package/dist/src/utils.js.map +1 -1
  87. package/package.json +73 -69
  88. package/src/debounce.ts +16 -51
  89. package/src/exchange-heads.ts +1 -23
  90. package/src/index.ts +1532 -1038
  91. package/src/integers.ts +102 -0
  92. package/src/pid.ts +23 -22
  93. package/src/ranges.ts +1204 -413
  94. package/src/replication-domain-hash.ts +43 -18
  95. package/src/replication-domain-time.ts +9 -9
  96. package/src/replication-domain.ts +21 -31
  97. package/src/replication.ts +10 -9
  98. package/src/role.ts +4 -6
  99. package/src/sync/index.ts +51 -0
  100. package/src/sync/rateless-iblt.ts +617 -0
  101. package/src/sync/simple.ts +403 -0
  102. package/src/sync/wasm-init.browser.ts +1 -0
  103. package/src/sync/wasm-init.ts +14 -0
  104. package/src/utils.ts +10 -4
@@ -7,35 +7,47 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __metadata = (this && this.__metadata) || function (k, v) {
8
8
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
9
  };
10
- import { deserialize, field, serialize, variant } from "@dao-xyz/borsh";
11
- import { PublicSignKey, equals, randomBytes, toBase64 } from "@peerbit/crypto";
12
- import { And, BoolQuery, ByteMatchQuery, Compare, IntegerCompare, Not, Or, Sort, SortDirection, StringMatch, iteratorInSeries, } from "@peerbit/indexer-interface";
10
+ import { deserialize, field, serialize, variant, vec } from "@dao-xyz/borsh";
11
+ import { PublicSignKey, equals, randomBytes, sha256Base64Sync, toBase64, } from "@peerbit/crypto";
12
+ import { And, BoolQuery, ByteMatchQuery, Compare, IntegerCompare, Not, Or, Sort, SortDirection, StringMatch,
13
+ /* iteratorInSeries, */
14
+ } from "@peerbit/indexer-interface";
13
15
  import { id } from "@peerbit/indexer-interface";
14
16
  import { Meta, ShallowMeta } from "@peerbit/log";
17
+ import { MAX_U32, MAX_U64, } from "./integers.js";
15
18
  import {} from "./replication-domain.js";
16
- import { MAX_U32, scaleToU32 } from "./role.js";
17
- import { groupByGidSync } from "./utils.js";
18
19
  export var ReplicationIntent;
19
20
  (function (ReplicationIntent) {
20
21
  ReplicationIntent[ReplicationIntent["NonStrict"] = 0] = "NonStrict";
21
22
  ReplicationIntent[ReplicationIntent["Strict"] = 1] = "Strict";
22
23
  })(ReplicationIntent || (ReplicationIntent = {}));
23
- export const getSegmentsFromOffsetAndRange = (offset, factor) => {
24
+ export var SyncStatus;
25
+ (function (SyncStatus) {
26
+ SyncStatus[SyncStatus["Unsynced"] = 0] = "Unsynced";
27
+ SyncStatus[SyncStatus["Synced"] = 1] = "Synced";
28
+ })(SyncStatus || (SyncStatus = {}));
29
+ const min = (a, b) => (a < b ? a : b);
30
+ const getSegmentsFromOffsetAndRange = (offset, factor, zero, max) => {
24
31
  let start1 = offset;
32
+ // @ts-ignore
25
33
  let end1Unscaled = offset + factor; // only add factor if it is not 1 to prevent numerical issues (like (0.9 + 1) % 1 => 0.8999999)
26
- let end1 = Math.min(end1Unscaled, MAX_U32);
34
+ let end1 = min(end1Unscaled, max);
27
35
  return [
28
36
  [start1, end1],
29
- end1Unscaled > MAX_U32
30
- ? [0, (factor !== MAX_U32 ? offset + factor : offset) % MAX_U32]
37
+ /* eslint-disable no-irregular-whitespace */
38
+ // @ts-ignore
39
+ end1Unscaled > max
40
+ ? /* eslint-disable no-irregular-whitespace */
41
+ // @ts-ignore
42
+ [zero, (factor !== max ? offset + factor : offset) % max]
31
43
  : [start1, end1],
32
44
  ];
33
45
  };
34
46
  export const shouldAssigneToRangeBoundary = (leaders, minReplicas) => {
35
47
  let assignedToRangeBoundary = leaders === false || leaders.size < minReplicas;
36
48
  if (!assignedToRangeBoundary && leaders) {
37
- for (const [_, { intersecting }] of leaders) {
38
- if (!intersecting) {
49
+ for (const [_, value] of leaders) {
50
+ if (!value.intersecting) {
39
51
  assignedToRangeBoundary = true;
40
52
  break;
41
53
  }
@@ -43,20 +55,21 @@ export const shouldAssigneToRangeBoundary = (leaders, minReplicas) => {
43
55
  }
44
56
  return assignedToRangeBoundary;
45
57
  };
46
- export class EntryReplicated {
47
- id; // hash + coordinate
58
+ export const isEntryReplicated = (x) => {
59
+ return x instanceof EntryReplicatedU32 || x instanceof EntryReplicatedU64;
60
+ };
61
+ export class EntryReplicatedU32 {
48
62
  hash;
49
63
  gid;
50
- coordinate;
64
+ coordinates;
51
65
  wallTime;
52
66
  assignedToRangeBoundary;
53
67
  _meta;
54
68
  _metaResolved;
55
69
  constructor(properties) {
56
- this.coordinate = properties.coordinate;
70
+ this.coordinates = properties.coordinates;
57
71
  this.hash = properties.hash;
58
72
  this.gid = properties.meta.gid;
59
- this.id = this.hash + "-" + this.coordinate;
60
73
  this.wallTime = properties.meta.clock.timestamp.wallTime;
61
74
  const shallow = properties.meta instanceof Meta
62
75
  ? new ShallowMeta(properties.meta)
@@ -76,38 +89,92 @@ export class EntryReplicated {
76
89
  __decorate([
77
90
  id({ type: "string" }),
78
91
  __metadata("design:type", String)
79
- ], EntryReplicated.prototype, "id", void 0);
92
+ ], EntryReplicatedU32.prototype, "hash", void 0);
80
93
  __decorate([
81
94
  field({ type: "string" }),
82
95
  __metadata("design:type", String)
83
- ], EntryReplicated.prototype, "hash", void 0);
96
+ ], EntryReplicatedU32.prototype, "gid", void 0);
97
+ __decorate([
98
+ field({ type: vec("u32") }),
99
+ __metadata("design:type", Array)
100
+ ], EntryReplicatedU32.prototype, "coordinates", void 0);
101
+ __decorate([
102
+ field({ type: "u64" }),
103
+ __metadata("design:type", BigInt)
104
+ ], EntryReplicatedU32.prototype, "wallTime", void 0);
105
+ __decorate([
106
+ field({ type: "bool" }),
107
+ __metadata("design:type", Boolean)
108
+ ], EntryReplicatedU32.prototype, "assignedToRangeBoundary", void 0);
109
+ __decorate([
110
+ field({ type: Uint8Array }),
111
+ __metadata("design:type", Uint8Array)
112
+ ], EntryReplicatedU32.prototype, "_meta", void 0);
113
+ export class EntryReplicatedU64 {
114
+ hash;
115
+ gid;
116
+ coordinates;
117
+ wallTime;
118
+ assignedToRangeBoundary;
119
+ _meta;
120
+ _metaResolved;
121
+ constructor(properties) {
122
+ this.coordinates = properties.coordinates;
123
+ this.hash = properties.hash;
124
+ this.gid = properties.meta.gid;
125
+ this.wallTime = properties.meta.clock.timestamp.wallTime;
126
+ const shallow = properties.meta instanceof Meta
127
+ ? new ShallowMeta(properties.meta)
128
+ : properties.meta;
129
+ this._meta = serialize(shallow);
130
+ this._metaResolved = deserialize(this._meta, ShallowMeta);
131
+ this._metaResolved = properties.meta;
132
+ this.assignedToRangeBoundary = properties.assignedToRangeBoundary;
133
+ }
134
+ get meta() {
135
+ if (!this._metaResolved) {
136
+ this._metaResolved = deserialize(this._meta, ShallowMeta);
137
+ }
138
+ return this._metaResolved;
139
+ }
140
+ }
141
+ __decorate([
142
+ id({ type: "string" }),
143
+ __metadata("design:type", String)
144
+ ], EntryReplicatedU64.prototype, "hash", void 0);
84
145
  __decorate([
85
146
  field({ type: "string" }),
86
147
  __metadata("design:type", String)
87
- ], EntryReplicated.prototype, "gid", void 0);
148
+ ], EntryReplicatedU64.prototype, "gid", void 0);
88
149
  __decorate([
89
- field({ type: "u32" }),
90
- __metadata("design:type", Number)
91
- ], EntryReplicated.prototype, "coordinate", void 0);
150
+ field({ type: vec("u64") }),
151
+ __metadata("design:type", Array)
152
+ ], EntryReplicatedU64.prototype, "coordinates", void 0);
92
153
  __decorate([
93
154
  field({ type: "u64" }),
94
155
  __metadata("design:type", BigInt)
95
- ], EntryReplicated.prototype, "wallTime", void 0);
156
+ ], EntryReplicatedU64.prototype, "wallTime", void 0);
96
157
  __decorate([
97
158
  field({ type: "bool" }),
98
159
  __metadata("design:type", Boolean)
99
- ], EntryReplicated.prototype, "assignedToRangeBoundary", void 0);
160
+ ], EntryReplicatedU64.prototype, "assignedToRangeBoundary", void 0);
100
161
  __decorate([
101
162
  field({ type: Uint8Array }),
102
163
  __metadata("design:type", Uint8Array)
103
- ], EntryReplicated.prototype, "_meta", void 0);
104
- let ReplicationRange = class ReplicationRange {
164
+ ], EntryReplicatedU64.prototype, "_meta", void 0);
165
+ export const isReplicationRangeMessage = (x) => {
166
+ return x instanceof ReplicationRangeMessage;
167
+ };
168
+ export class ReplicationRangeMessage {
169
+ }
170
+ let ReplicationRangeMessageU32 = class ReplicationRangeMessageU32 extends ReplicationRangeMessage {
105
171
  id;
106
172
  timestamp;
107
173
  _offset;
108
174
  _factor;
109
175
  mode;
110
176
  constructor(properties) {
177
+ super();
111
178
  const { id, offset, factor, timestamp, mode } = properties;
112
179
  this.id = id;
113
180
  this._offset = offset;
@@ -122,7 +189,7 @@ let ReplicationRange = class ReplicationRange {
122
189
  return this._offset;
123
190
  }
124
191
  toReplicationRangeIndexable(key) {
125
- return new ReplicationRangeIndexable({
192
+ return new ReplicationRangeIndexableU32({
126
193
  id: this.id,
127
194
  publicKeyHash: key.hashcode(),
128
195
  offset: this.offset,
@@ -135,29 +202,154 @@ let ReplicationRange = class ReplicationRange {
135
202
  __decorate([
136
203
  field({ type: Uint8Array }),
137
204
  __metadata("design:type", Uint8Array)
138
- ], ReplicationRange.prototype, "id", void 0);
205
+ ], ReplicationRangeMessageU32.prototype, "id", void 0);
139
206
  __decorate([
140
207
  field({ type: "u64" }),
141
208
  __metadata("design:type", BigInt)
142
- ], ReplicationRange.prototype, "timestamp", void 0);
209
+ ], ReplicationRangeMessageU32.prototype, "timestamp", void 0);
143
210
  __decorate([
144
211
  field({ type: "u32" }),
145
212
  __metadata("design:type", Number)
146
- ], ReplicationRange.prototype, "_offset", void 0);
213
+ ], ReplicationRangeMessageU32.prototype, "_offset", void 0);
147
214
  __decorate([
148
215
  field({ type: "u32" }),
149
216
  __metadata("design:type", Number)
150
- ], ReplicationRange.prototype, "_factor", void 0);
217
+ ], ReplicationRangeMessageU32.prototype, "_factor", void 0);
151
218
  __decorate([
152
219
  field({ type: "u8" }),
153
220
  __metadata("design:type", Number)
154
- ], ReplicationRange.prototype, "mode", void 0);
155
- ReplicationRange = __decorate([
221
+ ], ReplicationRangeMessageU32.prototype, "mode", void 0);
222
+ ReplicationRangeMessageU32 = __decorate([
156
223
  variant(0),
157
224
  __metadata("design:paramtypes", [Object])
158
- ], ReplicationRange);
159
- export { ReplicationRange };
160
- export class ReplicationRangeIndexable {
225
+ ], ReplicationRangeMessageU32);
226
+ export { ReplicationRangeMessageU32 };
227
+ let ReplicationRangeMessageU64 = class ReplicationRangeMessageU64 extends ReplicationRangeMessage {
228
+ id;
229
+ timestamp;
230
+ _offset;
231
+ _factor;
232
+ mode;
233
+ constructor(properties) {
234
+ super();
235
+ const { id, offset, factor, timestamp, mode } = properties;
236
+ this.id = id;
237
+ this._offset = offset;
238
+ this._factor = factor;
239
+ this.timestamp = timestamp;
240
+ this.mode = mode;
241
+ }
242
+ get factor() {
243
+ return this._factor;
244
+ }
245
+ get offset() {
246
+ return this._offset;
247
+ }
248
+ toReplicationRangeIndexable(key) {
249
+ return new ReplicationRangeIndexableU64({
250
+ id: this.id,
251
+ publicKeyHash: key.hashcode(),
252
+ offset: this.offset,
253
+ length: this.factor,
254
+ timestamp: this.timestamp,
255
+ mode: this.mode,
256
+ });
257
+ }
258
+ };
259
+ __decorate([
260
+ field({ type: Uint8Array }),
261
+ __metadata("design:type", Uint8Array)
262
+ ], ReplicationRangeMessageU64.prototype, "id", void 0);
263
+ __decorate([
264
+ field({ type: "u64" }),
265
+ __metadata("design:type", BigInt)
266
+ ], ReplicationRangeMessageU64.prototype, "timestamp", void 0);
267
+ __decorate([
268
+ field({ type: "u64" }),
269
+ __metadata("design:type", BigInt)
270
+ ], ReplicationRangeMessageU64.prototype, "_offset", void 0);
271
+ __decorate([
272
+ field({ type: "u64" }),
273
+ __metadata("design:type", BigInt)
274
+ ], ReplicationRangeMessageU64.prototype, "_factor", void 0);
275
+ __decorate([
276
+ field({ type: "u8" }),
277
+ __metadata("design:type", Number)
278
+ ], ReplicationRangeMessageU64.prototype, "mode", void 0);
279
+ ReplicationRangeMessageU64 = __decorate([
280
+ variant(1),
281
+ __metadata("design:paramtypes", [Object])
282
+ ], ReplicationRangeMessageU64);
283
+ export { ReplicationRangeMessageU64 };
284
+ class HashableSegmentU32 {
285
+ start1;
286
+ end1;
287
+ start2;
288
+ end2;
289
+ mode;
290
+ constructor(properties) {
291
+ this.start1 = properties.start1;
292
+ this.end1 = properties.end1;
293
+ this.start2 = properties.start2;
294
+ this.end2 = properties.end2;
295
+ this.mode = properties.mode;
296
+ }
297
+ }
298
+ __decorate([
299
+ field({ type: "u32" }),
300
+ __metadata("design:type", Number)
301
+ ], HashableSegmentU32.prototype, "start1", void 0);
302
+ __decorate([
303
+ field({ type: "u32" }),
304
+ __metadata("design:type", Number)
305
+ ], HashableSegmentU32.prototype, "end1", void 0);
306
+ __decorate([
307
+ field({ type: "u32" }),
308
+ __metadata("design:type", Number)
309
+ ], HashableSegmentU32.prototype, "start2", void 0);
310
+ __decorate([
311
+ field({ type: "u32" }),
312
+ __metadata("design:type", Number)
313
+ ], HashableSegmentU32.prototype, "end2", void 0);
314
+ __decorate([
315
+ field({ type: "u8" }),
316
+ __metadata("design:type", Number)
317
+ ], HashableSegmentU32.prototype, "mode", void 0);
318
+ class HashableSegmentU64 {
319
+ start1;
320
+ end1;
321
+ start2;
322
+ end2;
323
+ mode;
324
+ constructor(properties) {
325
+ this.start1 = properties.start1;
326
+ this.end1 = properties.end1;
327
+ this.start2 = properties.start2;
328
+ this.end2 = properties.end2;
329
+ this.mode = properties.mode;
330
+ }
331
+ }
332
+ __decorate([
333
+ field({ type: "u64" }),
334
+ __metadata("design:type", BigInt)
335
+ ], HashableSegmentU64.prototype, "start1", void 0);
336
+ __decorate([
337
+ field({ type: "u64" }),
338
+ __metadata("design:type", BigInt)
339
+ ], HashableSegmentU64.prototype, "end1", void 0);
340
+ __decorate([
341
+ field({ type: "u64" }),
342
+ __metadata("design:type", BigInt)
343
+ ], HashableSegmentU64.prototype, "start2", void 0);
344
+ __decorate([
345
+ field({ type: "u64" }),
346
+ __metadata("design:type", BigInt)
347
+ ], HashableSegmentU64.prototype, "end2", void 0);
348
+ __decorate([
349
+ field({ type: "u8" }),
350
+ __metadata("design:type", Number)
351
+ ], HashableSegmentU64.prototype, "mode", void 0);
352
+ export class ReplicationRangeIndexableU32 {
161
353
  id;
162
354
  hash;
163
355
  timestamp;
@@ -172,20 +364,12 @@ export class ReplicationRangeIndexable {
172
364
  this.hash =
173
365
  properties.publicKeyHash ||
174
366
  properties.publicKey.hashcode();
175
- if (!properties.normalized) {
176
- this.transform({ length: properties.length, offset: properties.offset });
177
- }
178
- else {
179
- this.transform({
180
- length: scaleToU32(properties.length),
181
- offset: scaleToU32(properties.offset),
182
- });
183
- }
367
+ this.transform({ length: properties.length, offset: properties.offset });
184
368
  this.mode = properties.mode ?? ReplicationIntent.NonStrict;
185
369
  this.timestamp = properties.timestamp || BigInt(0);
186
370
  }
187
371
  transform(properties) {
188
- const ranges = getSegmentsFromOffsetAndRange(properties.offset, properties.length);
372
+ const ranges = getSegmentsFromOffsetAndRange(properties.offset, properties.length, 0, MAX_U32);
189
373
  this.start1 = Math.round(ranges[0][0]);
190
374
  this.end1 = Math.round(ranges[0][1]);
191
375
  this.start2 = Math.round(ranges[1][0]);
@@ -194,11 +378,11 @@ export class ReplicationRangeIndexable {
194
378
  this.end1 -
195
379
  this.start1 +
196
380
  (this.end2 < this.end1 ? this.end2 - this.start2 : 0);
197
- if (this.start1 > 0xffffffff ||
198
- this.end1 > 0xffffffff ||
199
- this.start2 > 0xffffffff ||
200
- this.end2 > 0xffffffff ||
201
- this.width > 0xffffffff ||
381
+ if (this.start1 > MAX_U32 ||
382
+ this.end1 > MAX_U32 ||
383
+ this.start2 > MAX_U32 ||
384
+ this.end2 > MAX_U32 ||
385
+ this.width > MAX_U32 ||
202
386
  this.width < 0) {
203
387
  throw new Error("Segment coordinate out of bounds");
204
388
  }
@@ -223,7 +407,7 @@ export class ReplicationRangeIndexable {
223
407
  return false;
224
408
  }
225
409
  toReplicationRange() {
226
- return new ReplicationRange({
410
+ return new ReplicationRangeMessageU32({
227
411
  id: this.id,
228
412
  offset: this.start1,
229
413
  factor: this.width,
@@ -231,10 +415,6 @@ export class ReplicationRangeIndexable {
231
415
  mode: this.mode,
232
416
  });
233
417
  }
234
- distanceTo(point) {
235
- let wrappedPoint = MAX_U32 - point;
236
- return Math.min(Math.abs(this.start1 - point), Math.abs(this.end2 - point), Math.abs(this.start1 - wrappedPoint), Math.abs(this.end2 - wrappedPoint));
237
- }
238
418
  get wrapped() {
239
419
  return this.end2 < this.end1;
240
420
  }
@@ -271,84 +451,371 @@ export class ReplicationRangeIndexable {
271
451
  toStringDetailed() {
272
452
  return `(hash ${this.hash} range: ${this.toString()})`;
273
453
  }
454
+ toUniqueSegmentId() {
455
+ // return a unique id as a function of the segments location and the replication intent
456
+ const hashable = new HashableSegmentU32(this);
457
+ return sha256Base64Sync(serialize(hashable));
458
+ }
274
459
  }
275
460
  __decorate([
276
461
  id({ type: Uint8Array }),
277
462
  __metadata("design:type", Uint8Array)
278
- ], ReplicationRangeIndexable.prototype, "id", void 0);
463
+ ], ReplicationRangeIndexableU32.prototype, "id", void 0);
279
464
  __decorate([
280
465
  field({ type: "string" }),
281
466
  __metadata("design:type", String)
282
- ], ReplicationRangeIndexable.prototype, "hash", void 0);
467
+ ], ReplicationRangeIndexableU32.prototype, "hash", void 0);
283
468
  __decorate([
284
469
  field({ type: "u64" }),
285
470
  __metadata("design:type", BigInt)
286
- ], ReplicationRangeIndexable.prototype, "timestamp", void 0);
471
+ ], ReplicationRangeIndexableU32.prototype, "timestamp", void 0);
287
472
  __decorate([
288
473
  field({ type: "u32" }),
289
474
  __metadata("design:type", Number)
290
- ], ReplicationRangeIndexable.prototype, "start1", void 0);
475
+ ], ReplicationRangeIndexableU32.prototype, "start1", void 0);
291
476
  __decorate([
292
477
  field({ type: "u32" }),
293
478
  __metadata("design:type", Number)
294
- ], ReplicationRangeIndexable.prototype, "end1", void 0);
479
+ ], ReplicationRangeIndexableU32.prototype, "end1", void 0);
295
480
  __decorate([
296
481
  field({ type: "u32" }),
297
482
  __metadata("design:type", Number)
298
- ], ReplicationRangeIndexable.prototype, "start2", void 0);
483
+ ], ReplicationRangeIndexableU32.prototype, "start2", void 0);
299
484
  __decorate([
300
485
  field({ type: "u32" }),
301
486
  __metadata("design:type", Number)
302
- ], ReplicationRangeIndexable.prototype, "end2", void 0);
487
+ ], ReplicationRangeIndexableU32.prototype, "end2", void 0);
303
488
  __decorate([
304
489
  field({ type: "u32" }),
305
490
  __metadata("design:type", Number)
306
- ], ReplicationRangeIndexable.prototype, "width", void 0);
491
+ ], ReplicationRangeIndexableU32.prototype, "width", void 0);
307
492
  __decorate([
308
493
  field({ type: "u8" }),
309
494
  __metadata("design:type", Number)
310
- ], ReplicationRangeIndexable.prototype, "mode", void 0);
311
- const containingPoint = (rects, point, roleAgeLimit, matured, now, options) => {
312
- // point is between 0 and 1, and the range can start at any offset between 0 and 1 and have length between 0 and 1
313
- let queries = [
314
- new Or([
315
- new And([
316
- new IntegerCompare({
317
- key: "start1",
318
- compare: Compare.LessOrEqual,
319
- value: point,
320
- }),
321
- new IntegerCompare({
322
- key: "end1",
323
- compare: Compare.Greater,
324
- value: point,
325
- }),
326
- ]),
327
- new And([
328
- new IntegerCompare({
329
- key: "start2",
330
- compare: Compare.LessOrEqual,
331
- value: point,
332
- }),
333
- new IntegerCompare({
334
- key: "end2",
335
- compare: Compare.Greater,
336
- value: point,
337
- }),
338
- ]),
339
- ]),
340
- new IntegerCompare({
495
+ ], ReplicationRangeIndexableU32.prototype, "mode", void 0);
496
+ export class ReplicationRangeIndexableU64 {
497
+ id;
498
+ hash;
499
+ timestamp;
500
+ start1;
501
+ end1;
502
+ start2;
503
+ end2;
504
+ width;
505
+ mode;
506
+ constructor(properties) {
507
+ this.id = properties.id ?? randomBytes(32);
508
+ this.hash =
509
+ properties.publicKeyHash ||
510
+ properties.publicKey.hashcode();
511
+ this.transform({ length: properties.length, offset: properties.offset });
512
+ this.mode = properties.mode ?? ReplicationIntent.NonStrict;
513
+ this.timestamp = properties.timestamp || BigInt(0);
514
+ }
515
+ transform(properties) {
516
+ const ranges = getSegmentsFromOffsetAndRange(BigInt(properties.offset), BigInt(properties.length), 0n, MAX_U64);
517
+ this.start1 = ranges[0][0];
518
+ this.end1 = ranges[0][1];
519
+ this.start2 = ranges[1][0];
520
+ this.end2 = ranges[1][1];
521
+ this.width =
522
+ this.end1 -
523
+ this.start1 +
524
+ (this.end2 < this.end1 ? this.end2 - this.start2 : 0n);
525
+ if (this.start1 > MAX_U64 ||
526
+ this.end1 > MAX_U64 ||
527
+ this.start2 > MAX_U64 ||
528
+ this.end2 > MAX_U64 ||
529
+ this.width > MAX_U64 ||
530
+ this.width < 0n) {
531
+ throw new Error("Segment coordinate out of bounds");
532
+ }
533
+ }
534
+ get idString() {
535
+ return toBase64(this.id);
536
+ }
537
+ contains(point) {
538
+ return ((point >= this.start1 && point < this.end1) ||
539
+ (point >= this.start2 && point < this.end2));
540
+ }
541
+ overlaps(other, checkOther = true) {
542
+ if (this.contains(other.start1) ||
543
+ this.contains(other.start2) ||
544
+ this.contains(other.end1 - 1n) ||
545
+ this.contains(other.end2 - 1n)) {
546
+ return true;
547
+ }
548
+ if (checkOther) {
549
+ return other.overlaps(this, false);
550
+ }
551
+ return false;
552
+ }
553
+ toReplicationRange() {
554
+ return new ReplicationRangeMessageU64({
555
+ id: this.id,
556
+ offset: this.start1,
557
+ factor: this.width,
558
+ timestamp: this.timestamp,
559
+ mode: this.mode,
560
+ });
561
+ }
562
+ get wrapped() {
563
+ return this.end2 < this.end1;
564
+ }
565
+ get widthNormalized() {
566
+ return Number(this.width) / Number(MAX_U64);
567
+ }
568
+ equals(other) {
569
+ if (equals(this.id, other.id) &&
570
+ this.hash === other.hash &&
571
+ this.timestamp === other.timestamp &&
572
+ this.mode === other.mode &&
573
+ this.start1 === other.start1 &&
574
+ this.end1 === other.end1 &&
575
+ this.start2 === other.start2 &&
576
+ this.end2 === other.end2 &&
577
+ this.width === other.width) {
578
+ return true;
579
+ }
580
+ return false;
581
+ }
582
+ equalRange(other) {
583
+ return (this.start1 === other.start1 &&
584
+ this.end1 === other.end1 &&
585
+ this.start2 === other.start2 &&
586
+ this.end2 === other.end2);
587
+ }
588
+ toString() {
589
+ let roundToTwoDecimals = (num) => Math.round(num * 100) / 100;
590
+ if (Math.abs(Number(this.start1 - this.start2)) < 0.0001) {
591
+ return `([${roundToTwoDecimals(Number(this.start1) / Number(MAX_U64))}, ${roundToTwoDecimals(Number(this.start1) / Number(MAX_U64))}])`;
592
+ }
593
+ return `([${roundToTwoDecimals(Number(this.start1) / Number(MAX_U64))}, ${roundToTwoDecimals(Number(this.start1) / Number(MAX_U64))}] [${roundToTwoDecimals(Number(this.start2) / Number(MAX_U64))}, ${roundToTwoDecimals(Number(this.end2) / Number(MAX_U64))}])`;
594
+ }
595
+ toStringDetailed() {
596
+ return `(hash ${this.hash} range: ${this.toString()})`;
597
+ }
598
+ toUniqueSegmentId() {
599
+ // return a unique id as a function of the segments location and the replication intent
600
+ const hashable = new HashableSegmentU64(this);
601
+ return sha256Base64Sync(serialize(hashable));
602
+ }
603
+ }
604
+ __decorate([
605
+ id({ type: Uint8Array }),
606
+ __metadata("design:type", Uint8Array)
607
+ ], ReplicationRangeIndexableU64.prototype, "id", void 0);
608
+ __decorate([
609
+ field({ type: "string" }),
610
+ __metadata("design:type", String)
611
+ ], ReplicationRangeIndexableU64.prototype, "hash", void 0);
612
+ __decorate([
613
+ field({ type: "u64" }),
614
+ __metadata("design:type", BigInt)
615
+ ], ReplicationRangeIndexableU64.prototype, "timestamp", void 0);
616
+ __decorate([
617
+ field({ type: "u64" }),
618
+ __metadata("design:type", BigInt)
619
+ ], ReplicationRangeIndexableU64.prototype, "start1", void 0);
620
+ __decorate([
621
+ field({ type: "u64" }),
622
+ __metadata("design:type", BigInt)
623
+ ], ReplicationRangeIndexableU64.prototype, "end1", void 0);
624
+ __decorate([
625
+ field({ type: "u64" }),
626
+ __metadata("design:type", BigInt)
627
+ ], ReplicationRangeIndexableU64.prototype, "start2", void 0);
628
+ __decorate([
629
+ field({ type: "u64" }),
630
+ __metadata("design:type", BigInt)
631
+ ], ReplicationRangeIndexableU64.prototype, "end2", void 0);
632
+ __decorate([
633
+ field({ type: "u64" }),
634
+ __metadata("design:type", BigInt)
635
+ ], ReplicationRangeIndexableU64.prototype, "width", void 0);
636
+ __decorate([
637
+ field({ type: "u8" }),
638
+ __metadata("design:type", Number)
639
+ ], ReplicationRangeIndexableU64.prototype, "mode", void 0);
640
+ export const mergeRanges = (segments, numbers) => {
641
+ if (segments.length === 0) {
642
+ throw new Error("No segments to merge");
643
+ }
644
+ if (segments.length === 1) {
645
+ return segments[0];
646
+ }
647
+ // only allow merging from same publicKeyHash
648
+ const sameHash = segments.every((x) => x.hash === segments[0].hash);
649
+ if (!sameHash) {
650
+ throw new Error("Segments have different publicKeyHash");
651
+ }
652
+ // only allow merging segments with length 1 (trivial)
653
+ const sameLength = segments.every((x) => x.width === 1 || x.width === 1n);
654
+ if (!sameLength) {
655
+ throw new Error("Segments have different length, only merging of segments length 1 is supported");
656
+ }
657
+ const sorted = segments.sort((a, b) => Number(a.start1 - b.start1));
658
+ let calculateLargeGap = () => {
659
+ let last = sorted[sorted.length - 1];
660
+ let largestArc = numbers.zero;
661
+ let largestArcIndex = -1;
662
+ for (let i = 0; i < sorted.length; i++) {
663
+ const current = sorted[i];
664
+ if (current.start1 !== last.start1) {
665
+ let arc = numbers.zero;
666
+ if (current.start1 < last.end2) {
667
+ arc += (numbers.maxValue - last.end2);
668
+ arc += (current.start1 - numbers.zero);
669
+ }
670
+ else {
671
+ arc += (current.start1 - last.end2);
672
+ }
673
+ if (arc > largestArc) {
674
+ largestArc = arc;
675
+ largestArcIndex = i;
676
+ }
677
+ }
678
+ last = current;
679
+ }
680
+ return [largestArc, largestArcIndex];
681
+ };
682
+ const [largestArc, largestArcIndex] = calculateLargeGap();
683
+ let totalLengthFinal = numbers.maxValue - largestArc;
684
+ if (largestArcIndex === -1) {
685
+ return segments[0]; // all ranges are the same
686
+ }
687
+ // use segments[0] constructor to create a new object
688
+ const proto = segments[0].constructor;
689
+ return new proto({
690
+ length: totalLengthFinal,
691
+ offset: segments[largestArcIndex].start1,
692
+ publicKeyHash: segments[0].hash,
693
+ });
694
+ };
695
+ const createContainingPointQuery = (points, options) => {
696
+ const or = [];
697
+ for (const point of Array.isArray(points) ? points : [points]) {
698
+ or.push(new And([
699
+ new IntegerCompare({
700
+ key: "start1",
701
+ compare: Compare.LessOrEqual,
702
+ value: point,
703
+ }),
704
+ new IntegerCompare({
705
+ key: "end1",
706
+ compare: Compare.Greater,
707
+ value: point,
708
+ }),
709
+ ]));
710
+ or.push(new And([
711
+ new IntegerCompare({
712
+ key: "start2",
713
+ compare: Compare.LessOrEqual,
714
+ value: point,
715
+ }),
716
+ new IntegerCompare({
717
+ key: "end2",
718
+ compare: Compare.Greater,
719
+ value: point,
720
+ }),
721
+ ]));
722
+ }
723
+ if (options?.time) {
724
+ let queries = [
725
+ new Or(or),
726
+ new IntegerCompare({
727
+ key: "timestamp",
728
+ compare: options.time.matured ? Compare.LessOrEqual : Compare.Greater,
729
+ value: BigInt(options.time.now - options.time.roleAgeLimit),
730
+ }),
731
+ ];
732
+ return queries;
733
+ }
734
+ else {
735
+ return new Or(or);
736
+ }
737
+ };
738
+ const createContainingPartialPointQuery = (point, first, options) => {
739
+ let query;
740
+ if (first) {
741
+ query = [
742
+ new IntegerCompare({
743
+ key: "start1",
744
+ compare: Compare.LessOrEqual,
745
+ value: point,
746
+ }),
747
+ new IntegerCompare({
748
+ key: "end1",
749
+ compare: Compare.Greater,
750
+ value: point,
751
+ }),
752
+ ];
753
+ }
754
+ else {
755
+ query = [
756
+ new IntegerCompare({
757
+ key: "start2",
758
+ compare: Compare.LessOrEqual,
759
+ value: point,
760
+ }),
761
+ new IntegerCompare({
762
+ key: "end2",
763
+ compare: Compare.Greater,
764
+ value: point,
765
+ }),
766
+ ];
767
+ }
768
+ if (options?.time) {
769
+ query.push(new IntegerCompare({
341
770
  key: "timestamp",
342
- compare: matured ? Compare.LessOrEqual : Compare.Greater,
343
- value: BigInt(now - roleAgeLimit),
344
- }),
345
- ];
771
+ compare: options.time.matured ? Compare.LessOrEqual : Compare.Greater,
772
+ value: BigInt(options.time.now - options.time.roleAgeLimit),
773
+ }));
774
+ }
775
+ return query;
776
+ };
777
+ const iterateRangesContainingPoint = (rects, points, options) => {
778
+ // point is between 0 and 1, and the range can start at any offset between 0 and 1 and have length between 0 and 1
346
779
  return rects.iterate({
347
- query: queries,
780
+ query: createContainingPointQuery(points, {
781
+ time: options?.time,
782
+ }), // new Or(points.map(point => new And(createContainingPointQuery(point, roleAgeLimit, matured, now)))
348
783
  sort: options?.sort,
349
784
  }, options);
350
785
  };
351
- const getClosest = (direction, rects, point, roleAgeLimit, matured, now, includeStrict, options) => {
786
+ const allRangesContainingPoint = async (rects, points, options) => {
787
+ // point is between 0 and 1, and the range can start at any offset between 0 and 1 and have length between 0 and 1
788
+ let allResults = [];
789
+ for (const point of Array.isArray(points) ? points : [points]) {
790
+ const firstIterator = rects.iterate({
791
+ query: createContainingPartialPointQuery(point, false, options),
792
+ sort: options?.sort,
793
+ }, options);
794
+ const secondIterator = rects.iterate({
795
+ query: createContainingPartialPointQuery(point, true, options),
796
+ sort: options?.sort,
797
+ }, options);
798
+ [...(await firstIterator.all()), ...(await secondIterator.all())].forEach((x) => allResults.push(x));
799
+ }
800
+ return allResults;
801
+ /* return [...await iterateRangesContainingPoint(rects, points, options).all()]; */
802
+ };
803
+ const countRangesContainingPoint = async (rects, point, options) => {
804
+ return rects.count({
805
+ query: createContainingPointQuery(point, options),
806
+ });
807
+ };
808
+ export const appromixateCoverage = async (properties) => {
809
+ const grid = properties.numbers.getGrid(properties.numbers.zero, properties.samples);
810
+ /* const now = +new Date(); */
811
+ let hits = 0;
812
+ for (const point of grid) {
813
+ const count = await countRangesContainingPoint(properties.peers, point);
814
+ hits += properties.normalized ? (count > 0 ? 1 : 0) : count;
815
+ }
816
+ return hits / properties.samples;
817
+ };
818
+ const getClosest = (direction, rects, point, roleAgeLimit, matured, now, includeStrict, numbers, options) => {
352
819
  const createQueries = (p, equality) => {
353
820
  let queries;
354
821
  if (direction === "below") {
@@ -402,7 +869,7 @@ const getClosest = (direction, rects, point, roleAgeLimit, matured, now, include
402
869
  ],
403
870
  }, options);
404
871
  const iteratorWrapped = rects.iterate({
405
- query: createQueries(direction === "below" ? MAX_U32 : 0, true),
872
+ query: createQueries(direction === "below" ? numbers.maxValue : numbers.zero, true),
406
873
  sort: [
407
874
  direction === "below"
408
875
  ? new Sort({ key: ["end2"], direction: "desc" })
@@ -411,63 +878,68 @@ const getClosest = (direction, rects, point, roleAgeLimit, matured, now, include
411
878
  sortByHash,
412
879
  ],
413
880
  }, options);
414
- return joinIterator([iterator, iteratorWrapped], point, direction);
881
+ return joinIterator([iterator, iteratorWrapped], point, direction, numbers);
415
882
  };
416
- export const hasCoveringRange = async (rects, range) => {
417
- return ((await rects.count({
418
- query: [
419
- new Or([
420
- new And([
421
- new IntegerCompare({
422
- key: "start1",
423
- compare: Compare.LessOrEqual,
424
- value: range.start1,
425
- }),
426
- new IntegerCompare({
427
- key: "end1",
428
- compare: Compare.GreaterOrEqual,
429
- value: range.end1,
430
- }),
431
- ]),
432
- new And([
433
- new IntegerCompare({
434
- key: "start2",
435
- compare: Compare.LessOrEqual,
436
- value: range.start1,
437
- }),
438
- new IntegerCompare({
439
- key: "end2",
440
- compare: Compare.GreaterOrEqual,
441
- value: range.end1,
442
- }),
443
- ]),
883
+ export const getCoveringRangeQuery = (range) => {
884
+ return [
885
+ new Or([
886
+ new And([
887
+ new IntegerCompare({
888
+ key: "start1",
889
+ compare: Compare.LessOrEqual,
890
+ value: range.start1,
891
+ }),
892
+ new IntegerCompare({
893
+ key: "end1",
894
+ compare: Compare.GreaterOrEqual,
895
+ value: range.end1,
896
+ }),
897
+ ]),
898
+ new And([
899
+ new IntegerCompare({
900
+ key: "start2",
901
+ compare: Compare.LessOrEqual,
902
+ value: range.start1,
903
+ }),
904
+ new IntegerCompare({
905
+ key: "end2",
906
+ compare: Compare.GreaterOrEqual,
907
+ value: range.end1,
908
+ }),
909
+ ]),
910
+ ]),
911
+ new Or([
912
+ new And([
913
+ new IntegerCompare({
914
+ key: "start1",
915
+ compare: Compare.LessOrEqual,
916
+ value: range.start2,
917
+ }),
918
+ new IntegerCompare({
919
+ key: "end1",
920
+ compare: Compare.GreaterOrEqual,
921
+ value: range.end2,
922
+ }),
444
923
  ]),
445
- new Or([
446
- new And([
447
- new IntegerCompare({
448
- key: "start1",
449
- compare: Compare.LessOrEqual,
450
- value: range.start2,
451
- }),
452
- new IntegerCompare({
453
- key: "end1",
454
- compare: Compare.GreaterOrEqual,
455
- value: range.end2,
456
- }),
457
- ]),
458
- new And([
459
- new IntegerCompare({
460
- key: "start2",
461
- compare: Compare.LessOrEqual,
462
- value: range.start2,
463
- }),
464
- new IntegerCompare({
465
- key: "end2",
466
- compare: Compare.GreaterOrEqual,
467
- value: range.end2,
468
- }),
469
- ]),
924
+ new And([
925
+ new IntegerCompare({
926
+ key: "start2",
927
+ compare: Compare.LessOrEqual,
928
+ value: range.start2,
929
+ }),
930
+ new IntegerCompare({
931
+ key: "end2",
932
+ compare: Compare.GreaterOrEqual,
933
+ value: range.end2,
934
+ }),
470
935
  ]),
936
+ ]),
937
+ ];
938
+ };
939
+ export const iHaveCoveringRange = async (rects, range) => {
940
+ return ((await rects.count({
941
+ query: [
942
+ ...getCoveringRangeQuery(range),
471
943
  new StringMatch({
472
944
  key: "hash",
473
945
  value: range.hash,
@@ -480,34 +952,33 @@ export const hasCoveringRange = async (rects, range) => {
480
952
  ],
481
953
  })) > 0);
482
954
  };
483
- export const getDistance = (from, to, direction, end = MAX_U32) => {
484
- // if direction is 'above' only measure distance from 'from to 'to' from above.
485
- // i.e if from < to, then from needs to wrap around 0 to 1 and then to to
486
- // if direction is 'below' and from > to, then from needs to wrap around 1 to 0 and then to to
487
- // if direction is 'closest' then the shortest distance is the distance
488
- // also from is 0.1 and to is 0.9, then distance should be 0.2 not 0.8
489
- // same as for if from is 0.9 and to is 0.1, then distance should be 0.2 not 0.8
955
+ // TODO
956
+ export function getDistance(from, to, direction, end) {
957
+ const abs = (value) => value < 0 ? -value : value;
958
+ const diff = (a, b) => abs(a - b);
490
959
  if (direction === "closest") {
491
960
  if (from === to) {
492
- return 0;
961
+ return typeof from === "number" ? 0 : 0n; // returns 0 of the correct type
493
962
  }
494
- return Math.min(Math.abs(from - to), Math.abs(end - Math.abs(from - to)));
963
+ return diff(from, to) < diff(end, diff(from, to))
964
+ ? diff(from, to)
965
+ : diff(end, diff(from, to));
495
966
  }
496
967
  if (direction === "above") {
497
968
  if (from <= to) {
498
- return Math.abs(end - to) + from;
969
+ return end - to + from;
499
970
  }
500
971
  return from - to;
501
972
  }
502
973
  if (direction === "below") {
503
974
  if (from >= to) {
504
- return Math.abs(end - from) + to;
975
+ return end - from + to;
505
976
  }
506
977
  return to - from;
507
978
  }
508
979
  throw new Error("Invalid direction");
509
- };
510
- const joinIterator = (iterators, point, direction) => {
980
+ }
981
+ const joinIterator = (iterators, point, direction, numbers) => {
511
982
  let queues = [];
512
983
  return {
513
984
  next: async (count) => {
@@ -525,13 +996,13 @@ const joinIterator = (iterators, point, direction) => {
525
996
  const closest = el.value;
526
997
  let dist;
527
998
  if (direction === "closest") {
528
- dist = Math.min(getDistance(closest.start1, point, direction), getDistance(closest.end2, point, direction));
999
+ dist = numbers.min(getDistance(closest.start1, point, direction, numbers.maxValue), getDistance(closest.end2, point, direction, numbers.maxValue));
529
1000
  }
530
1001
  else if (direction === "above") {
531
- dist = getDistance(closest.start1, point, direction);
1002
+ dist = getDistance(closest.start1, point, direction, numbers.maxValue);
532
1003
  }
533
1004
  else if (direction === "below") {
534
- dist = getDistance(closest.end2, point, direction);
1005
+ dist = getDistance(closest.end2, point, direction, numbers.maxValue);
535
1006
  }
536
1007
  else {
537
1008
  throw new Error("Invalid direction");
@@ -543,7 +1014,7 @@ const joinIterator = (iterators, point, direction) => {
543
1014
  // pull the 'count' the closest element from one of the queue
544
1015
  for (let i = 0; i < count; i++) {
545
1016
  let closestQueue = -1;
546
- let closestDist = Number.MAX_SAFE_INTEGER;
1017
+ let closestDist = Number.MAX_VALUE;
547
1018
  for (let j = 0; j < queues.length; j++) {
548
1019
  let queue = queues[j];
549
1020
  if (queue && queue.elements.length > 0) {
@@ -584,25 +1055,84 @@ const joinIterator = (iterators, point, direction) => {
584
1055
  },
585
1056
  };
586
1057
  };
587
- const getClosestAround = (peers, point, roleAge, now, includeStrictBelow, includeStrictAbove, options) => {
588
- const closestBelow = getClosest("below", peers, point, roleAge, true, now, includeStrictBelow, options);
589
- const closestAbove = getClosest("above", peers, point, roleAge, true, now, includeStrictAbove, options);
590
- const containing = containingPoint(peers, point, roleAge, true, now, options);
591
- return iteratorInSeries(containing, joinIterator([closestBelow, closestAbove], point, "closest"));
1058
+ const getClosestAround = (peers, point, roleAge, now, includeStrictBelow, includeStrictAbove, numbers, options) => {
1059
+ const closestBelow = getClosest("below", peers, point, roleAge, true, now, includeStrictBelow, numbers, options);
1060
+ const closestAbove = getClosest("above", peers, point, roleAge, true, now, includeStrictAbove, numbers, options);
1061
+ /* const containing = iterateRangesContainingPoint<S, R>(
1062
+ peers,
1063
+ point,
1064
+ {
1065
+ time: {
1066
+ roleAgeLimit: roleAge,
1067
+ matured: true,
1068
+ now,
1069
+ }
1070
+ }
1071
+ );
1072
+
1073
+ return iteratorInSeries(
1074
+ containing,
1075
+ joinIterator<S, R>([closestBelow, closestAbove], point, "closest", numbers),
1076
+ ); */
1077
+ return joinIterator([closestBelow, closestAbove], point, "closest", numbers);
1078
+ };
1079
+ export const isMatured = (segment, now, minAge) => {
1080
+ return now - Number(segment.timestamp) >= minAge;
592
1081
  };
593
- const collectNodesAroundPoint = async (roleAge, peers, collector, point, now, done = () => true) => {
594
- /* let shape = { timestamp: true, hash: true } as const */
595
- const containing = containingPoint(peers, point, 0, true, now /* , { shape } */);
1082
+ /*
1083
+
1084
+ const collectNodesAroundPoint = async <R extends "u32" | "u64">(
1085
+ roleAge: number,
1086
+ peers: Index<ReplicationRangeIndexable<R>>,
1087
+ collector: (
1088
+ rect: { hash: string },
1089
+ matured: boolean,
1090
+ intersecting: boolean,
1091
+ ) => void,
1092
+ point: NumberFromType<R>,
1093
+ now: number,
1094
+ numbers: Numbers<R>,
1095
+ done: () => boolean = () => true,
1096
+ ) => {
1097
+ const containing = iterateRangesContainingPoint<
1098
+ { timestamp: true, hash: true },
1099
+ R
1100
+ >(peers, point, 0, true, now, { shape: { timestamp: true, hash: true } as const });
596
1101
  const allContaining = await containing.all();
597
1102
  for (const rect of allContaining) {
598
1103
  collector(rect.value, isMatured(rect.value, now, roleAge), true);
599
1104
  }
1105
+
600
1106
  if (done()) {
601
1107
  return;
602
1108
  }
603
- const closestBelow = getClosest("below", peers, point, 0, true, now, false /* , { shape } */);
604
- const closestAbove = getClosest("above", peers, point, 0, true, now, false /* , { shape } */);
605
- const aroundIterator = joinIterator([closestBelow, closestAbove], point, "closest");
1109
+
1110
+ const closestBelow = getClosest<undefined, R>(
1111
+ "below",
1112
+ peers,
1113
+ point,
1114
+ 0,
1115
+ true,
1116
+ now,
1117
+ false,
1118
+ numbers
1119
+ );
1120
+ const closestAbove = getClosest<undefined, R>(
1121
+ "above",
1122
+ peers,
1123
+ point,
1124
+ 0,
1125
+ true,
1126
+ now,
1127
+ false,
1128
+ numbers
1129
+ );
1130
+ const aroundIterator = joinIterator<undefined, R>(
1131
+ [closestBelow, closestAbove],
1132
+ point,
1133
+ "closest",
1134
+ numbers,
1135
+ );
606
1136
  while (aroundIterator.done() !== true && done() !== true) {
607
1137
  const res = await aroundIterator.next(1);
608
1138
  for (const rect of res) {
@@ -613,45 +1143,87 @@ const collectNodesAroundPoint = async (roleAge, peers, collector, point, now, do
613
1143
  }
614
1144
  }
615
1145
  };
616
- export const getEvenlySpacedU32 = (from, count) => {
617
- let ret = new Array(count);
618
- for (let i = 0; i < count; i++) {
619
- ret[i] = Math.round(from + (i * MAX_U32) / count) % MAX_U32;
1146
+ */
1147
+ const collectClosestAround = async (roleAge, peers, collector, point, now, numbers, done = () => true) => {
1148
+ const closestBelow = getClosest("below", peers, point, 0, true, now, false, numbers);
1149
+ const closestAbove = getClosest("above", peers, point, 0, true, now, false, numbers);
1150
+ /* const containingIterator = iterateRangesContainingPoint<undefined, R>(
1151
+ peers,
1152
+ point,
1153
+ );
1154
+ */
1155
+ const aroundIterator = joinIterator([/* containingIterator, */ closestBelow, closestAbove], point, "closest", numbers);
1156
+ let visited = new Set();
1157
+ while (aroundIterator.done() !== true && done() !== true) {
1158
+ const res = await aroundIterator.next(100);
1159
+ for (const rect of res) {
1160
+ visited.add(rect.value.idString);
1161
+ collector(rect.value, isMatured(rect.value, now, roleAge));
1162
+ if (done()) {
1163
+ return;
1164
+ }
1165
+ }
620
1166
  }
621
- return ret;
622
- };
623
- export const isMatured = (segment, now, minAge) => {
624
- return now - Number(segment.timestamp) >= minAge;
625
1167
  };
626
1168
  // get peer sample that are responsible for the cursor point
627
1169
  // will return a list of peers that want to replicate the data,
628
1170
  // but also if necessary a list of peers that are responsible for the data
629
1171
  // but have not explicitly replicating a range that cover the cursor point
630
- export const getSamples = async (cursor, peers, roleAge) => {
1172
+ export const getSamples = async (cursor, peers, roleAge, numbers, options) => {
631
1173
  const leaders = new Map();
632
1174
  if (!peers) {
633
1175
  return new Map();
634
1176
  }
635
1177
  const now = +new Date();
636
- const maturedLeaders = new Set();
1178
+ let matured = 0;
1179
+ /* let missingForCursors: NumberFromType<R>[] = [] */
1180
+ let uniqueVisited = new Set();
637
1181
  for (let i = 0; i < cursor.length; i++) {
638
- // evenly distributed
639
- // aquire at least one unique node for each point
640
- await collectNodesAroundPoint(roleAge, peers, (rect, m, intersecting) => {
641
- if (m) {
642
- maturedLeaders.add(rect.hash);
1182
+ let point = cursor[i];
1183
+ const allContaining = await allRangesContainingPoint(peers, point);
1184
+ for (const rect of allContaining) {
1185
+ uniqueVisited.add(rect.value.hash);
1186
+ let prev = leaders.get(rect.value.hash);
1187
+ if (!prev) {
1188
+ if (isMatured(rect.value, now, roleAge)) {
1189
+ matured++;
1190
+ }
1191
+ leaders.set(rect.value.hash, { intersecting: true });
643
1192
  }
644
- const prev = leaders.get(rect.hash);
645
- if (!prev || (intersecting && !prev.intersecting)) {
646
- leaders.set(rect.hash, { intersecting });
1193
+ else {
1194
+ prev.intersecting = true;
647
1195
  }
648
- }, cursor[i], now, () => {
649
- if (maturedLeaders.size > i) {
650
- return true;
1196
+ }
1197
+ if (options?.uniqueReplicators) {
1198
+ if (options.uniqueReplicators.size === leaders.size ||
1199
+ options.uniqueReplicators.size === uniqueVisited.size) {
1200
+ break; // nothing more to find
651
1201
  }
652
- return false;
653
- });
1202
+ }
1203
+ if (options?.onlyIntersecting || matured > i) {
1204
+ continue;
1205
+ }
1206
+ let foundOneUniqueMatured = false;
1207
+ await collectClosestAround(roleAge, peers, (rect, m) => {
1208
+ uniqueVisited.add(rect.hash);
1209
+ const prev = leaders.get(rect.hash);
1210
+ if (m) {
1211
+ if (!prev) {
1212
+ matured++;
1213
+ leaders.set(rect.hash, { intersecting: false });
1214
+ }
1215
+ if (matured > i) {
1216
+ foundOneUniqueMatured = true;
1217
+ }
1218
+ }
1219
+ }, point, now, numbers, () => foundOneUniqueMatured);
1220
+ /* if (!foundOneUniqueMatured) {
1221
+ missingForCursors.push(point);
1222
+ } */
654
1223
  }
1224
+ /* if (leaders.size < cursor.length) {
1225
+ throw new Error("Missing leaders got: " + leaders.size + " -- expected -- " + cursor.length + " role age " + roleAge + " missing " + missingForCursors.length + " replication index size: " + (await peers.count()));
1226
+ } */
655
1227
  return leaders;
656
1228
  };
657
1229
  const fetchOne = async (iterator) => {
@@ -659,20 +1231,19 @@ const fetchOne = async (iterator) => {
659
1231
  await iterator.close();
660
1232
  return value[0]?.value;
661
1233
  };
662
- export const minimumWidthToCover = async (minReplicas /* , replicatorCount: number */) => {
1234
+ export const minimumWidthToCover = async (minReplicas /* , replicatorCount: number */, numbers) => {
663
1235
  /* minReplicas = Math.min(minReplicas, replicatorCount); */ // TODO do we need this?
664
1236
  // If min replicas = 2
665
1237
  // then we need to make sure we cover 0.5 of the total 'width' of the replication space
666
1238
  // to make sure we reach sufficient amount of nodes such that at least one one has
667
1239
  // the entry we are looking for
668
- let widthToCoverScaled = Math.round(MAX_U32 / minReplicas);
1240
+ let widthToCoverScaled = numbers.divRound(numbers.maxValue, minReplicas);
669
1241
  return widthToCoverScaled;
670
1242
  };
671
1243
  export const getCoverSet = async (properties) => {
672
- let intervalWidth = properties.intervalWidth ?? MAX_U32;
673
1244
  const { peers, start, widthToCoverScaled, roleAge } = properties;
674
1245
  const now = Date.now();
675
- const { startNode, startLocation, endLocation } = await getStartAndEnd(peers, start, widthToCoverScaled, roleAge, now, intervalWidth);
1246
+ const { startNode, startLocation, endLocation } = await getStartAndEnd(peers, start, widthToCoverScaled, roleAge, now, properties.numbers);
676
1247
  let ret = new Set();
677
1248
  // if start node (assume is self) and not mature, ask all known remotes if limited
678
1249
  // TODO consider a more robust stragety here in a scenario where there are many nodes, lets say
@@ -705,14 +1276,19 @@ export const getCoverSet = async (properties) => {
705
1276
  // push edges
706
1277
  ret.add(current.hash);
707
1278
  const resolveNextContaining = async (nextLocation, roleAge) => {
708
- let next = await fetchOne(containingPoint(peers, nextLocation, roleAge, true, now, {
1279
+ let next = await fetchOne(iterateRangesContainingPoint(peers, nextLocation, {
709
1280
  sort: [new Sort({ key: "end2", direction: SortDirection.DESC })],
1281
+ time: {
1282
+ matured: true,
1283
+ roleAgeLimit: roleAge,
1284
+ now,
1285
+ },
710
1286
  })); // get entersecting sort by largest end2
711
1287
  return next;
712
1288
  };
713
1289
  const resolveNextAbove = async (nextLocation, roleAge) => {
714
1290
  // if not get closest from above
715
- let next = await fetchOne(getClosest("above", peers, nextLocation, roleAge, true, now, true));
1291
+ let next = await fetchOne(getClosest("above", peers, nextLocation, roleAge, true, now, true, properties.numbers));
716
1292
  return next;
717
1293
  };
718
1294
  const resolveNext = async (nextLocation, roleAge) => {
@@ -724,14 +1300,17 @@ export const getCoverSet = async (properties) => {
724
1300
  };
725
1301
  // fill the middle
726
1302
  let wrappedOnce = current.end2 < current.end1;
727
- let coveredLength = 0;
1303
+ let coveredLength = properties.numbers.zero;
728
1304
  const addLength = (from) => {
729
1305
  if (current.end2 < from || current.wrapped) {
730
1306
  wrappedOnce = true;
731
- coveredLength += MAX_U32 - from;
1307
+ // @ts-ignore
1308
+ coveredLength += properties.numbers.maxValue - from;
1309
+ // @ts-ignore
732
1310
  coveredLength += current.end2;
733
1311
  }
734
1312
  else {
1313
+ // @ts-ignore
735
1314
  coveredLength += current.end1 - from;
736
1315
  }
737
1316
  };
@@ -739,7 +1318,7 @@ export const getCoverSet = async (properties) => {
739
1318
  let maturedCoveredLength = coveredLength; /* TODO only increase matured length when startNode is matured? i.e. do isMatured(startNode, now, roleAge) ? coveredLength : 0; */
740
1319
  let nextLocation = current.end2;
741
1320
  while (maturedCoveredLength < widthToCoverScaled && // eslint-disable-line no-unmodified-loop-condition
742
- coveredLength <= MAX_U32 // eslint-disable-line no-unmodified-loop-condition
1321
+ coveredLength <= properties.numbers.maxValue // eslint-disable-line no-unmodified-loop-condition
743
1322
  ) {
744
1323
  let nextCandidate = await resolveNext(nextLocation, roleAge);
745
1324
  /* let fromAbove = false; */
@@ -764,8 +1343,8 @@ export const getCoverSet = async (properties) => {
764
1343
  coveredLength >= widthToCoverScaled;
765
1344
  if (!isLast ||
766
1345
  nextCandidate[1] ||
767
- Math.min(getDistance(last.start1, endLocation, "closest"), getDistance(last.end2, endLocation, "closest")) >
768
- Math.min(getDistance(current.start1, endLocation, "closest"), getDistance(current.end2, endLocation, "closest"))) {
1346
+ properties.numbers.min(getDistance(last.start1, endLocation, "closest", properties.numbers.maxValue), getDistance(last.end2, endLocation, "closest", properties.numbers.maxValue)) >
1347
+ properties.numbers.min(getDistance(current.start1, endLocation, "closest", properties.numbers.maxValue), getDistance(current.end2, endLocation, "closest", properties.numbers.maxValue))) {
769
1348
  ret.add(current.hash);
770
1349
  }
771
1350
  if (isLast && !nextCandidate[1] /* || equals(endRect.id, current.id) */) {
@@ -776,9 +1355,9 @@ export const getCoverSet = async (properties) => {
776
1355
  }
777
1356
  nextLocation = endIsWrapped
778
1357
  ? wrappedOnce
779
- ? Math.min(current.end2, endLocation)
1358
+ ? properties.numbers.min(current.end2, endLocation)
780
1359
  : current.end2
781
- : Math.min(current.end2, endLocation);
1360
+ : properties.numbers.min(current.end2, endLocation);
782
1361
  }
783
1362
  start instanceof PublicSignKey && ret.add(start.hashcode());
784
1363
  return ret;
@@ -787,53 +1366,58 @@ export const getCoverSet = async (properties) => {
787
1366
  // reduce the change set to only regions that are changed for each peer
788
1367
  // i.e. subtract removed regions from added regions, and vice versa
789
1368
  const result = new Map<string, { range: ReplicationRangeIndexable, added: boolean }[]>();
790
-
1369
+
791
1370
  for (const addedChange of changes.added ?? []) {
792
1371
  let prev = result.get(addedChange.hash) ?? [];
793
1372
  for (const [_hash, ranges] of result.entries()) {
794
1373
  for (const r of ranges) {
795
-
1374
+
796
1375
  }
797
1376
  }
798
1377
  }
799
1378
  }
800
1379
  */
801
- const matchRangeQuery = (range) => {
802
- let ors = [];
803
- ors.push(new And([
1380
+ export const matchEntriesInRangeQuery = (range) => {
1381
+ const c1 = new And([
804
1382
  new IntegerCompare({
805
- key: "coordinate",
1383
+ key: "coordinates",
806
1384
  compare: "gte",
807
1385
  value: range.start1,
808
1386
  }),
809
1387
  new IntegerCompare({
810
- key: "coordinate",
1388
+ key: "coordinates",
811
1389
  compare: "lt",
812
1390
  value: range.end1,
813
1391
  }),
814
- ]));
815
- ors.push(new And([
816
- new IntegerCompare({
817
- key: "coordinate",
818
- compare: "gte",
819
- value: range.start2,
820
- }),
821
- new IntegerCompare({
822
- key: "coordinate",
823
- compare: "lt",
824
- value: range.end2,
825
- }),
826
- ]));
1392
+ ]);
1393
+ if (range.start2 === range.end2) {
1394
+ return c1;
1395
+ }
1396
+ let ors = [
1397
+ c1,
1398
+ new And([
1399
+ new IntegerCompare({
1400
+ key: "coordinates",
1401
+ compare: "gte",
1402
+ value: range.start2,
1403
+ }),
1404
+ new IntegerCompare({
1405
+ key: "coordinates",
1406
+ compare: "lt",
1407
+ value: range.end2,
1408
+ }),
1409
+ ]),
1410
+ ];
827
1411
  return new Or(ors);
828
1412
  };
829
1413
  export const toRebalance = (changes, index) => {
830
1414
  const assignedRangesQuery = (changes) => {
831
1415
  let ors = [];
832
1416
  for (const change of changes) {
833
- const matchRange = matchRangeQuery(change.range);
1417
+ const matchRange = matchEntriesInRangeQuery(change.range);
834
1418
  if (change.type === "updated") {
835
1419
  // assuming a range is to be removed, is this entry still enoughly replicated
836
- const prevMatchRange = matchRangeQuery(change.prev);
1420
+ const prevMatchRange = matchEntriesInRangeQuery(change.prev);
837
1421
  ors.push(prevMatchRange);
838
1422
  ors.push(matchRange);
839
1423
  }
@@ -855,17 +1439,19 @@ export const toRebalance = (changes, index) => {
855
1439
  query: assignedRangesQuery(changes),
856
1440
  });
857
1441
  while (iterator.done() !== true) {
858
- const entries = await iterator.next(1000); // TODO choose right batch sizes here for optimal memory usage / speed
859
- // TODO do we need this
860
- const grouped = await groupByGidSync(entries.map((x) => x.value));
1442
+ const entries = await iterator.all(); // TODO choose right batch sizes here for optimal memory usage / speed
1443
+ /* const grouped = await groupByGidSync(entries.map((x) => x.value));
861
1444
  for (const [gid, entries] of grouped.entries()) {
862
1445
  yield { gid, entries };
1446
+ } */
1447
+ for (const entry of entries) {
1448
+ yield entry.value;
863
1449
  }
864
1450
  }
865
1451
  },
866
1452
  };
867
1453
  };
868
- export const fetchOneFromPublicKey = async (publicKey, index, roleAge, now, options) => {
1454
+ export const fetchOneFromPublicKey = async (publicKey, index, roleAge, now, numbers, options) => {
869
1455
  let iterator = index.iterate({
870
1456
  query: [new StringMatch({ key: "hash", value: publicKey.hashcode() })],
871
1457
  }, options);
@@ -874,7 +1460,7 @@ export const fetchOneFromPublicKey = async (publicKey, index, roleAge, now, opti
874
1460
  let node = result[0]?.value;
875
1461
  if (node) {
876
1462
  if (!isMatured(node, now, roleAge)) {
877
- const matured = await fetchOne(getClosestAround(index, node.start1, roleAge, now, false, false, options));
1463
+ const matured = await fetchOne(getClosestAround(index, node.start1, roleAge, now, false, false, numbers, options));
878
1464
  if (matured) {
879
1465
  node = matured;
880
1466
  }
@@ -882,17 +1468,17 @@ export const fetchOneFromPublicKey = async (publicKey, index, roleAge, now, opti
882
1468
  }
883
1469
  return node;
884
1470
  };
885
- export const getStartAndEnd = async (peers, start, widthToCoverScaled, roleAge, now, intervalWidth, options) => {
1471
+ export const getStartAndEnd = async (peers, start, widthToCoverScaled, roleAge, now, numbers, options) => {
886
1472
  // find a good starting point
887
1473
  let startNode = undefined;
888
1474
  let startLocation = undefined;
889
- const nodeFromPoint = async (point = scaleToU32(Math.random())) => {
1475
+ const nodeFromPoint = async (point = numbers.random()) => {
890
1476
  startLocation = point;
891
- startNode = await fetchOneClosest(peers, startLocation, roleAge, now, false, true, options);
1477
+ startNode = await fetchOneClosest(peers, startLocation, roleAge, now, false, true, numbers, options);
892
1478
  };
893
1479
  if (start instanceof PublicSignKey) {
894
1480
  // start at our node (local first)
895
- startNode = await fetchOneFromPublicKey(start, peers, roleAge, now, options);
1481
+ startNode = await fetchOneFromPublicKey(start, peers, roleAge, now, numbers, options);
896
1482
  if (!startNode) {
897
1483
  // fetch randomly
898
1484
  await nodeFromPoint();
@@ -901,38 +1487,49 @@ export const getStartAndEnd = async (peers, start, widthToCoverScaled, roleAge,
901
1487
  startLocation = startNode.start1;
902
1488
  }
903
1489
  }
904
- else if (typeof start === "number") {
1490
+ else if (typeof start === "number" || typeof start === "bigint") {
905
1491
  await nodeFromPoint(start);
906
1492
  }
907
1493
  else {
908
1494
  await nodeFromPoint();
909
1495
  }
910
1496
  if (!startNode || startLocation == null) {
911
- return { startNode: undefined, startLocation: 0, endLocation: 0 };
912
- }
913
- let endLocation = startLocation + widthToCoverScaled;
914
- if (intervalWidth != null) {
915
- endLocation = endLocation % intervalWidth;
916
- }
917
- // if start location is after endLocation and startNode is strict then return undefined because this is not a node we want to choose
918
- let coveredDistanceToStart = 0;
919
- if (startNode.start1 < startLocation) {
920
- coveredDistanceToStart += intervalWidth - startLocation + startNode.start1;
1497
+ return {
1498
+ startNode: undefined,
1499
+ startLocation: numbers.zero,
1500
+ endLocation: numbers.zero,
1501
+ };
921
1502
  }
922
- else {
923
- coveredDistanceToStart += startNode.start1 - startLocation;
924
- }
925
- if (startNode.mode === ReplicationIntent.Strict &&
926
- coveredDistanceToStart > widthToCoverScaled) {
927
- return { startNode: undefined, startLocation: 0, endLocation: 0 };
1503
+ // @ts-ignore
1504
+ let endLocation = (startLocation + widthToCoverScaled) % numbers.maxValue;
1505
+ // if the start node range is not containing the start point, then figure out if the startNode is ideal
1506
+ if (!startNode.contains(startLocation)) {
1507
+ let coveredDistanceToStart = numbers.zero;
1508
+ if (startNode.start1 < startLocation) {
1509
+ coveredDistanceToStart +=
1510
+ numbers.maxValue - startLocation + startNode.start1;
1511
+ }
1512
+ else {
1513
+ coveredDistanceToStart += (startNode.start1 -
1514
+ startLocation);
1515
+ }
1516
+ // in this case, the gap to the start point is larger than the width we want to cover. Assume there are no good points
1517
+ if (startNode.mode === ReplicationIntent.Strict &&
1518
+ coveredDistanceToStart > widthToCoverScaled) {
1519
+ return {
1520
+ startNode: undefined,
1521
+ startLocation: numbers.zero,
1522
+ endLocation: numbers.zero,
1523
+ };
1524
+ }
928
1525
  }
929
1526
  return {
930
1527
  startNode,
931
- startLocation: Math.round(startLocation),
932
- endLocation: Math.round(endLocation),
1528
+ startLocation,
1529
+ endLocation,
933
1530
  };
934
1531
  };
935
- export const fetchOneClosest = (peers, point, roleAge, now, includeStrictBelow, includeStrictAbove, options) => {
936
- return fetchOne(getClosestAround(peers, point, roleAge, now, includeStrictBelow, includeStrictAbove, options));
1532
+ export const fetchOneClosest = (peers, point, roleAge, now, includeStrictBelow, includeStrictAbove, numbers, options) => {
1533
+ return fetchOne(getClosestAround(peers, point, roleAge, now, includeStrictBelow, includeStrictAbove, numbers, options));
937
1534
  };
938
1535
  //# sourceMappingURL=ranges.js.map