@dxos/echo-pipeline 0.8.4-main.ae835ea → 0.8.4-main.bc674ce
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/lib/browser/{chunk-WJJXJTNS.mjs → chunk-FJPXA75J.mjs} +7 -12
- package/dist/lib/browser/chunk-FJPXA75J.mjs.map +7 -0
- package/dist/lib/browser/{chunk-FR6GJ4S4.mjs → chunk-WIQUYO7H.mjs} +39 -29
- package/dist/lib/browser/chunk-WIQUYO7H.mjs.map +7 -0
- package/dist/lib/browser/filter/index.mjs +1 -2
- package/dist/lib/browser/index.mjs +1933 -620
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +28 -201
- package/dist/lib/browser/testing/index.mjs.map +4 -4
- package/dist/lib/node-esm/{chunk-JQCCVDLT.mjs → chunk-7PL6UK4B.mjs} +39 -29
- package/dist/lib/node-esm/chunk-7PL6UK4B.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-LEQ77KAT.mjs → chunk-S5KGVQFZ.mjs} +7 -12
- package/dist/lib/node-esm/chunk-S5KGVQFZ.mjs.map +7 -0
- package/dist/lib/node-esm/filter/index.mjs +1 -2
- package/dist/lib/node-esm/index.mjs +1933 -620
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +28 -201
- package/dist/lib/node-esm/testing/index.mjs.map +4 -4
- package/dist/types/src/automerge/automerge-host.d.ts +36 -9
- package/dist/types/src/automerge/automerge-host.d.ts.map +1 -1
- package/dist/types/src/automerge/automerge-repo.test.d.ts +1 -1
- package/dist/types/src/automerge/automerge-repo.test.d.ts.map +1 -1
- package/dist/types/src/automerge/collection-synchronizer.d.ts +3 -2
- package/dist/types/src/automerge/collection-synchronizer.d.ts.map +1 -1
- package/dist/types/src/automerge/echo-network-adapter.d.ts +11 -6
- package/dist/types/src/automerge/echo-network-adapter.d.ts.map +1 -1
- package/dist/types/src/automerge/echo-replicator.d.ts +9 -6
- package/dist/types/src/automerge/echo-replicator.d.ts.map +1 -1
- package/dist/types/src/automerge/heads-store.d.ts +9 -2
- package/dist/types/src/automerge/heads-store.d.ts.map +1 -1
- package/dist/types/src/automerge/leveldb-storage-adapter.d.ts +4 -4
- package/dist/types/src/automerge/leveldb-storage-adapter.d.ts.map +1 -1
- package/dist/types/src/automerge/mesh-echo-replicator-connection.d.ts +7 -7
- package/dist/types/src/automerge/mesh-echo-replicator-connection.d.ts.map +1 -1
- package/dist/types/src/automerge/mesh-echo-replicator.d.ts.map +1 -1
- package/dist/types/src/db-host/automerge-data-source.d.ts +34 -0
- package/dist/types/src/db-host/automerge-data-source.d.ts.map +1 -0
- package/dist/types/src/db-host/automerge-data-source.test.d.ts +2 -0
- package/dist/types/src/db-host/automerge-data-source.test.d.ts.map +1 -0
- package/dist/types/src/db-host/data-service.d.ts +4 -3
- package/dist/types/src/db-host/data-service.d.ts.map +1 -1
- package/dist/types/src/db-host/documents-iterator.d.ts.map +1 -1
- package/dist/types/src/db-host/documents-synchronizer.d.ts +6 -5
- package/dist/types/src/db-host/documents-synchronizer.d.ts.map +1 -1
- package/dist/types/src/db-host/echo-host.d.ts +43 -11
- package/dist/types/src/db-host/echo-host.d.ts.map +1 -1
- package/dist/types/src/db-host/index.d.ts +1 -0
- package/dist/types/src/db-host/index.d.ts.map +1 -1
- package/dist/types/src/db-host/local-queue-service.d.ts +15 -0
- package/dist/types/src/db-host/local-queue-service.d.ts.map +1 -0
- package/dist/types/src/db-host/query-service.d.ts +7 -2
- package/dist/types/src/db-host/query-service.d.ts.map +1 -1
- package/dist/types/src/db-host/queue-data-source.d.ts +28 -0
- package/dist/types/src/db-host/queue-data-source.d.ts.map +1 -0
- package/dist/types/src/db-host/queue-service.test.d.ts +2 -0
- package/dist/types/src/db-host/queue-service.test.d.ts.map +1 -0
- package/dist/types/src/db-host/space-state-manager.d.ts +1 -0
- package/dist/types/src/db-host/space-state-manager.d.ts.map +1 -1
- package/dist/types/src/db-host/stub.d.ts +10 -0
- package/dist/types/src/db-host/stub.d.ts.map +1 -0
- package/dist/types/src/edge/echo-edge-replicator.d.ts +2 -2
- package/dist/types/src/edge/echo-edge-replicator.d.ts.map +1 -1
- package/dist/types/src/filter/filter-match.d.ts.map +1 -1
- package/dist/types/src/metadata/metadata-store.d.ts.map +1 -1
- package/dist/types/src/pipeline/pipeline.d.ts +2 -2
- package/dist/types/src/pipeline/pipeline.d.ts.map +1 -1
- package/dist/types/src/query/errors.d.ts +11 -15
- package/dist/types/src/query/errors.d.ts.map +1 -1
- package/dist/types/src/query/plan.d.ts +37 -3
- package/dist/types/src/query/plan.d.ts.map +1 -1
- package/dist/types/src/query/query-executor.d.ts +39 -3
- package/dist/types/src/query/query-executor.d.ts.map +1 -1
- package/dist/types/src/query/query-planner.d.ts +6 -0
- package/dist/types/src/query/query-planner.d.ts.map +1 -1
- package/dist/types/src/space/auth.d.ts +3 -3
- package/dist/types/src/space/auth.d.ts.map +1 -1
- package/dist/types/src/space/control-pipeline.d.ts +2 -2
- package/dist/types/src/space/control-pipeline.d.ts.map +1 -1
- package/dist/types/src/space/space-manager.d.ts +6 -6
- package/dist/types/src/space/space-manager.d.ts.map +1 -1
- package/dist/types/src/space/space-protocol.d.ts +5 -5
- package/dist/types/src/space/space-protocol.d.ts.map +1 -1
- package/dist/types/src/space/space.d.ts +3 -3
- package/dist/types/src/space/space.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +0 -2
- package/dist/types/src/testing/index.d.ts.map +1 -1
- package/dist/types/src/testing/test-network-adapter.d.ts +1 -1
- package/dist/types/src/testing/test-network-adapter.d.ts.map +1 -1
- package/dist/types/src/testing/test-replicator.d.ts +6 -6
- package/dist/types/src/testing/test-replicator.d.ts.map +1 -1
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +48 -38
- package/src/automerge/automerge-host.test.ts +37 -14
- package/src/automerge/automerge-host.ts +130 -36
- package/src/automerge/automerge-repo.test.ts +147 -30
- package/src/automerge/collection-synchronizer.test.ts +16 -10
- package/src/automerge/collection-synchronizer.ts +41 -11
- package/src/automerge/echo-network-adapter.ts +23 -11
- package/src/automerge/echo-replicator.ts +10 -6
- package/src/automerge/heads-store.ts +14 -2
- package/src/automerge/leveldb-storage-adapter.ts +4 -4
- package/src/automerge/mesh-echo-replicator-connection.ts +7 -7
- package/src/automerge/mesh-echo-replicator.ts +2 -2
- package/src/db-host/automerge-data-source.test.ts +294 -0
- package/src/db-host/automerge-data-source.ts +144 -0
- package/src/db-host/data-service.ts +10 -3
- package/src/db-host/documents-iterator.ts +3 -1
- package/src/db-host/documents-synchronizer.test.ts +77 -13
- package/src/db-host/documents-synchronizer.ts +51 -50
- package/src/db-host/echo-host.ts +191 -28
- package/src/db-host/index.ts +1 -0
- package/src/db-host/local-queue-service.ts +127 -0
- package/src/db-host/query-service.ts +17 -4
- package/src/db-host/queue-data-source.ts +132 -0
- package/src/db-host/queue-service.test.ts +141 -0
- package/src/db-host/space-state-manager.ts +4 -0
- package/src/db-host/stub.ts +28 -0
- package/src/edge/echo-edge-replicator.ts +12 -8
- package/src/filter/filter-match.test.ts +31 -25
- package/src/filter/filter-match.ts +8 -14
- package/src/metadata/metadata-store.ts +5 -2
- package/src/pipeline/pipeline.ts +2 -2
- package/src/query/errors.ts +2 -2
- package/src/query/plan.ts +48 -3
- package/src/query/query-executor.ts +612 -131
- package/src/query/query-planner.test.ts +509 -35
- package/src/query/query-planner.ts +187 -13
- package/src/space/admission-discovery-extension.ts +1 -1
- package/src/space/auth.ts +6 -6
- package/src/space/control-pipeline.ts +2 -2
- package/src/space/space-manager.ts +6 -6
- package/src/space/space-protocol.ts +11 -11
- package/src/space/space.ts +3 -3
- package/src/testing/index.ts +0 -2
- package/src/testing/test-network-adapter.ts +16 -3
- package/src/testing/test-replicator.ts +8 -7
- package/src/util.ts +7 -3
- package/dist/lib/browser/chunk-CGS2ULMK.mjs +0 -11
- package/dist/lib/browser/chunk-CGS2ULMK.mjs.map +0 -7
- package/dist/lib/browser/chunk-FR6GJ4S4.mjs.map +0 -7
- package/dist/lib/browser/chunk-WJJXJTNS.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +0 -11
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-JQCCVDLT.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-LEQ77KAT.mjs.map +0 -7
- package/dist/types/src/testing/test-data.d.ts +0 -18
- package/dist/types/src/testing/test-data.d.ts.map +0 -1
- package/dist/types/src/testing/test-schema.d.ts +0 -37
- package/dist/types/src/testing/test-schema.d.ts.map +0 -1
- package/src/testing/test-data.ts +0 -127
- package/src/testing/test-schema.ts +0 -53
|
@@ -37,6 +37,7 @@ export class QueryPlanner {
|
|
|
37
37
|
plan = this._optimizeEmptyFilters(plan);
|
|
38
38
|
plan = this._optimizeSoloUnions(plan);
|
|
39
39
|
plan = this._ensureOrderStep(plan);
|
|
40
|
+
plan = this._optimizeLimits(plan);
|
|
40
41
|
return plan;
|
|
41
42
|
}
|
|
42
43
|
|
|
@@ -62,6 +63,8 @@ export class QueryPlanner {
|
|
|
62
63
|
return this._generateSetDifferenceClause(query, context);
|
|
63
64
|
case 'order':
|
|
64
65
|
return this._generateOrderClause(query, context);
|
|
66
|
+
case 'limit':
|
|
67
|
+
return this._generateLimitClause(query, context);
|
|
65
68
|
default:
|
|
66
69
|
throw new QueryError({
|
|
67
70
|
message: `Unsupported query type: ${(query as any).type}`,
|
|
@@ -77,6 +80,12 @@ export class QueryPlanner {
|
|
|
77
80
|
if (query.options.spaceIds) {
|
|
78
81
|
newContext.selectionSpaces = query.options.spaceIds as readonly SpaceId[];
|
|
79
82
|
}
|
|
83
|
+
if (query.options.allQueuesFromSpaces !== undefined) {
|
|
84
|
+
newContext.selectionAllQueuesFromSpaces = query.options.allQueuesFromSpaces;
|
|
85
|
+
}
|
|
86
|
+
if (query.options.queues) {
|
|
87
|
+
newContext.selectionQueues = query.options.queues as readonly DXN.String[];
|
|
88
|
+
}
|
|
80
89
|
if (query.options.deleted) {
|
|
81
90
|
newContext.deletedHandling = query.options.deleted;
|
|
82
91
|
}
|
|
@@ -121,6 +130,8 @@ export class QueryPlanner {
|
|
|
121
130
|
{
|
|
122
131
|
_tag: 'SelectStep',
|
|
123
132
|
spaces: context.selectionSpaces,
|
|
133
|
+
allQueuesFromSpaces: context.selectionAllQueuesFromSpaces,
|
|
134
|
+
queues: context.selectionQueues,
|
|
124
135
|
selector: {
|
|
125
136
|
_tag: 'IdSelector',
|
|
126
137
|
objectIds: filter.id,
|
|
@@ -137,6 +148,8 @@ export class QueryPlanner {
|
|
|
137
148
|
{
|
|
138
149
|
_tag: 'SelectStep',
|
|
139
150
|
spaces: context.selectionSpaces,
|
|
151
|
+
allQueuesFromSpaces: context.selectionAllQueuesFromSpaces,
|
|
152
|
+
queues: context.selectionQueues,
|
|
140
153
|
selector: {
|
|
141
154
|
_tag: 'TypeSelector',
|
|
142
155
|
typename: [filter.typename as DXN.String],
|
|
@@ -144,9 +157,10 @@ export class QueryPlanner {
|
|
|
144
157
|
},
|
|
145
158
|
},
|
|
146
159
|
...this._generateDeletedHandlingSteps(context),
|
|
160
|
+
// TODO(dmaretskyi): Normally we could skip filtering by typename here, but since the index does not separate schema versions, we need to do additional filter to only select the correct version.
|
|
147
161
|
{
|
|
148
162
|
_tag: 'FilterStep',
|
|
149
|
-
filter: { ...filter
|
|
163
|
+
filter: { ...filter },
|
|
150
164
|
},
|
|
151
165
|
]);
|
|
152
166
|
} else {
|
|
@@ -154,6 +168,8 @@ export class QueryPlanner {
|
|
|
154
168
|
{
|
|
155
169
|
_tag: 'SelectStep',
|
|
156
170
|
spaces: context.selectionSpaces,
|
|
171
|
+
allQueuesFromSpaces: context.selectionAllQueuesFromSpaces,
|
|
172
|
+
queues: context.selectionQueues,
|
|
157
173
|
selector: {
|
|
158
174
|
_tag: 'WildcardSelector',
|
|
159
175
|
},
|
|
@@ -173,6 +189,8 @@ export class QueryPlanner {
|
|
|
173
189
|
{
|
|
174
190
|
_tag: 'SelectStep',
|
|
175
191
|
spaces: context.selectionSpaces,
|
|
192
|
+
allQueuesFromSpaces: context.selectionAllQueuesFromSpaces,
|
|
193
|
+
queues: context.selectionQueues,
|
|
176
194
|
selector: {
|
|
177
195
|
_tag: 'WildcardSelector',
|
|
178
196
|
},
|
|
@@ -191,10 +209,13 @@ export class QueryPlanner {
|
|
|
191
209
|
{
|
|
192
210
|
_tag: 'SelectStep',
|
|
193
211
|
spaces: context.selectionSpaces,
|
|
212
|
+
allQueuesFromSpaces: context.selectionAllQueuesFromSpaces,
|
|
213
|
+
queues: context.selectionQueues,
|
|
194
214
|
selector: {
|
|
195
215
|
_tag: 'TextSelector',
|
|
196
216
|
text: filter.text,
|
|
197
217
|
searchKind: filter.searchKind ?? this._options.defaultTextSearchKind,
|
|
218
|
+
typename: null,
|
|
198
219
|
},
|
|
199
220
|
},
|
|
200
221
|
...this._generateDeletedHandlingSteps(context),
|
|
@@ -229,6 +250,8 @@ export class QueryPlanner {
|
|
|
229
250
|
{
|
|
230
251
|
_tag: 'SelectStep',
|
|
231
252
|
spaces: context.selectionSpaces,
|
|
253
|
+
allQueuesFromSpaces: context.selectionAllQueuesFromSpaces,
|
|
254
|
+
queues: context.selectionQueues,
|
|
232
255
|
selector: {
|
|
233
256
|
_tag: 'TypeSelector',
|
|
234
257
|
typename: typenames as DXN.String[],
|
|
@@ -236,6 +259,10 @@ export class QueryPlanner {
|
|
|
236
259
|
},
|
|
237
260
|
},
|
|
238
261
|
...this._generateDeletedHandlingSteps(context),
|
|
262
|
+
{
|
|
263
|
+
_tag: 'FilterStep',
|
|
264
|
+
filter: { ...filter },
|
|
265
|
+
},
|
|
239
266
|
]);
|
|
240
267
|
} else {
|
|
241
268
|
throw new QueryError({ message: 'Query too complex', context: { query: context.originalQuery } });
|
|
@@ -321,7 +348,7 @@ export class QueryPlanner {
|
|
|
321
348
|
traversal: {
|
|
322
349
|
_tag: 'ReferenceTraversal',
|
|
323
350
|
direction: 'incoming',
|
|
324
|
-
property: query.property,
|
|
351
|
+
property: query.property ?? null,
|
|
325
352
|
},
|
|
326
353
|
},
|
|
327
354
|
...this._generateDeletedHandlingSteps(context),
|
|
@@ -471,29 +498,164 @@ export class QueryPlanner {
|
|
|
471
498
|
]);
|
|
472
499
|
}
|
|
473
500
|
|
|
501
|
+
private _generateLimitClause(query: QueryAST.QueryLimitClause, context: GenerationContext): QueryPlan.Plan {
|
|
502
|
+
return QueryPlan.Plan.make([
|
|
503
|
+
...this._generate(query.query, context).steps,
|
|
504
|
+
{
|
|
505
|
+
_tag: 'LimitStep',
|
|
506
|
+
limit: query.limit,
|
|
507
|
+
},
|
|
508
|
+
]);
|
|
509
|
+
}
|
|
510
|
+
|
|
474
511
|
// After complete plan is built, inspect it from the end:
|
|
475
512
|
// - Walk backwards until hitting an object set changer.
|
|
476
513
|
// - If an order step is found, skip.
|
|
477
|
-
// - Otherwise
|
|
514
|
+
// - Otherwise insert natural order before any limit steps (since limit should be applied after ordering).
|
|
515
|
+
// This method is recursive and also processes sub-plans in unions and set differences.
|
|
478
516
|
private _ensureOrderStep(plan: QueryPlan.Plan): QueryPlan.Plan {
|
|
517
|
+
// First, recursively process any sub-plans.
|
|
518
|
+
const processedSteps = plan.steps.map((step): QueryPlan.Step => {
|
|
519
|
+
if (step._tag === 'UnionStep') {
|
|
520
|
+
return {
|
|
521
|
+
_tag: 'UnionStep',
|
|
522
|
+
plans: step.plans.map((subPlan) => this._ensureOrderStep(subPlan)),
|
|
523
|
+
};
|
|
524
|
+
} else if (step._tag === 'SetDifferenceStep') {
|
|
525
|
+
return {
|
|
526
|
+
_tag: 'SetDifferenceStep',
|
|
527
|
+
source: this._ensureOrderStep(step.source),
|
|
528
|
+
exclude: this._ensureOrderStep(step.exclude),
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
return step;
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
const processedPlan = QueryPlan.Plan.make(processedSteps);
|
|
535
|
+
|
|
479
536
|
const OBJECT_SET_CHANGERS = new Set(['SelectStep', 'TraverseStep', 'UnionStep', 'SetDifferenceStep']);
|
|
480
|
-
for (let i =
|
|
481
|
-
const step =
|
|
537
|
+
for (let i = processedPlan.steps.length - 1; i >= 0; i--) {
|
|
538
|
+
const step = processedPlan.steps[i];
|
|
482
539
|
if (step._tag === 'OrderStep') {
|
|
483
|
-
return
|
|
540
|
+
return processedPlan;
|
|
484
541
|
}
|
|
485
542
|
if (OBJECT_SET_CHANGERS.has(step._tag)) {
|
|
486
543
|
break;
|
|
487
544
|
}
|
|
488
545
|
}
|
|
489
546
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
}
|
|
496
|
-
|
|
547
|
+
// Find the position to insert the order step (before any limit steps).
|
|
548
|
+
let insertIndex = processedPlan.steps.length;
|
|
549
|
+
for (let i = processedPlan.steps.length - 1; i >= 0; i--) {
|
|
550
|
+
if (processedPlan.steps[i]._tag === 'LimitStep') {
|
|
551
|
+
insertIndex = i;
|
|
552
|
+
} else {
|
|
553
|
+
break;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
const newSteps = [...processedPlan.steps];
|
|
558
|
+
newSteps.splice(insertIndex, 0, {
|
|
559
|
+
_tag: 'OrderStep',
|
|
560
|
+
order: [Order.natural.ast],
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
return QueryPlan.Plan.make(newSteps);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* Propagates limits from LimitStep to SelectStep and OrderStep when possible.
|
|
568
|
+
* Limits can only be propagated if there are no unions or traversals between the LimitStep and SelectStep/OrderStep.
|
|
569
|
+
*/
|
|
570
|
+
private _optimizeLimits(plan: QueryPlan.Plan): QueryPlan.Plan {
|
|
571
|
+
// First, recursively process any sub-plans.
|
|
572
|
+
const processedSteps = plan.steps.map((step): QueryPlan.Step => {
|
|
573
|
+
if (step._tag === 'UnionStep') {
|
|
574
|
+
return {
|
|
575
|
+
_tag: 'UnionStep',
|
|
576
|
+
plans: step.plans.map((subPlan) => this._optimizeLimits(subPlan)),
|
|
577
|
+
};
|
|
578
|
+
} else if (step._tag === 'SetDifferenceStep') {
|
|
579
|
+
return {
|
|
580
|
+
_tag: 'SetDifferenceStep',
|
|
581
|
+
source: this._optimizeLimits(step.source),
|
|
582
|
+
exclude: this._optimizeLimits(step.exclude),
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
return step;
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
// Find if there's a LimitStep at the end (possibly after OrderStep).
|
|
589
|
+
let limitStepIndex = -1;
|
|
590
|
+
let limitValue: number | undefined;
|
|
591
|
+
|
|
592
|
+
for (let i = processedSteps.length - 1; i >= 0; i--) {
|
|
593
|
+
const step = processedSteps[i];
|
|
594
|
+
if (step._tag === 'LimitStep') {
|
|
595
|
+
limitStepIndex = i;
|
|
596
|
+
limitValue = step.limit;
|
|
597
|
+
break;
|
|
598
|
+
}
|
|
599
|
+
// Only allow OrderStep after LimitStep when looking backwards.
|
|
600
|
+
if (step._tag !== 'OrderStep') {
|
|
601
|
+
break;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
if (limitStepIndex === -1 || limitValue === undefined) {
|
|
606
|
+
return QueryPlan.Plan.make(processedSteps);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// Check if we can propagate the limit to a SelectStep and/or OrderStep.
|
|
610
|
+
// We can only do this if there are no unions, traversals, or set differences between them.
|
|
611
|
+
const BLOCKERS = new Set(['UnionStep', 'TraverseStep', 'SetDifferenceStep']);
|
|
612
|
+
|
|
613
|
+
let selectStepIndex = -1;
|
|
614
|
+
let orderStepIndex = -1;
|
|
615
|
+
for (let i = 0; i < limitStepIndex; i++) {
|
|
616
|
+
const step = processedSteps[i];
|
|
617
|
+
if (step._tag === 'SelectStep') {
|
|
618
|
+
selectStepIndex = i;
|
|
619
|
+
}
|
|
620
|
+
if (step._tag === 'OrderStep') {
|
|
621
|
+
orderStepIndex = i;
|
|
622
|
+
}
|
|
623
|
+
if (BLOCKERS.has(step._tag)) {
|
|
624
|
+
// Found a blocker after the select/order step - can't propagate.
|
|
625
|
+
selectStepIndex = -1;
|
|
626
|
+
orderStepIndex = -1;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
if (selectStepIndex === -1 && orderStepIndex === -1) {
|
|
631
|
+
return QueryPlan.Plan.make(processedSteps);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// Create a mutable copy of steps to modify.
|
|
635
|
+
const newSteps = [...processedSteps];
|
|
636
|
+
|
|
637
|
+
// Propagate the limit to the SelectStep if found.
|
|
638
|
+
if (selectStepIndex !== -1) {
|
|
639
|
+
const selectStep = newSteps[selectStepIndex] as QueryPlan.SelectStep;
|
|
640
|
+
newSteps[selectStepIndex] = {
|
|
641
|
+
...selectStep,
|
|
642
|
+
limit: limitValue,
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// Propagate the limit to the OrderStep if found.
|
|
647
|
+
if (orderStepIndex !== -1) {
|
|
648
|
+
const orderStep = newSteps[orderStepIndex] as QueryPlan.OrderStep;
|
|
649
|
+
newSteps[orderStepIndex] = {
|
|
650
|
+
...orderStep,
|
|
651
|
+
limit: limitValue,
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// Remove the LimitStep since limit is now propagated.
|
|
656
|
+
newSteps.splice(limitStepIndex, 1);
|
|
657
|
+
|
|
658
|
+
return QueryPlan.Plan.make(newSteps);
|
|
497
659
|
}
|
|
498
660
|
}
|
|
499
661
|
|
|
@@ -511,6 +673,16 @@ type GenerationContext = {
|
|
|
511
673
|
*/
|
|
512
674
|
selectionSpaces: readonly SpaceId[];
|
|
513
675
|
|
|
676
|
+
/**
|
|
677
|
+
* Whether to select from all queues in the spaces specified by selectionSpaces.
|
|
678
|
+
*/
|
|
679
|
+
selectionAllQueuesFromSpaces: boolean;
|
|
680
|
+
|
|
681
|
+
/**
|
|
682
|
+
* Which queues to select from.
|
|
683
|
+
*/
|
|
684
|
+
selectionQueues: readonly DXN.String[];
|
|
685
|
+
|
|
514
686
|
/**
|
|
515
687
|
* How to handle deleted objects.
|
|
516
688
|
*/
|
|
@@ -525,6 +697,8 @@ type GenerationContext = {
|
|
|
525
697
|
const DEFAULT_CONTEXT: GenerationContext = {
|
|
526
698
|
originalQuery: null,
|
|
527
699
|
selectionSpaces: [],
|
|
700
|
+
selectionAllQueuesFromSpaces: false,
|
|
701
|
+
selectionQueues: [],
|
|
528
702
|
deletedHandling: 'exclude',
|
|
529
703
|
selectionInverted: false,
|
|
530
704
|
};
|
|
@@ -81,7 +81,7 @@ export class CredentialServerExtension extends RpcExtension<
|
|
|
81
81
|
): Promise<GetAdmissionCredentialResponse> => {
|
|
82
82
|
const memberInfo = this._space.spaceState.members.get(request.memberKey);
|
|
83
83
|
if (!memberInfo?.credential) {
|
|
84
|
-
throw new ProtocolError('Space member not found.', request);
|
|
84
|
+
throw new ProtocolError({ message: 'Space member not found.', context: { ...request } });
|
|
85
85
|
}
|
|
86
86
|
return { admissionCredential: memberInfo.credential };
|
|
87
87
|
},
|
package/src/space/auth.ts
CHANGED
|
@@ -15,7 +15,7 @@ export type AuthProvider = (nonce: Uint8Array) => Promise<Uint8Array | undefined
|
|
|
15
15
|
|
|
16
16
|
export type AuthVerifier = (nonce: Uint8Array, credential: Uint8Array) => Promise<boolean>;
|
|
17
17
|
|
|
18
|
-
export type
|
|
18
|
+
export type AuthExtensionProps = {
|
|
19
19
|
provider: AuthProvider;
|
|
20
20
|
verifier: AuthVerifier;
|
|
21
21
|
onAuthSuccess: () => void;
|
|
@@ -29,7 +29,7 @@ export class AuthExtension extends RpcExtension<Services, Services> {
|
|
|
29
29
|
},
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
-
constructor(private readonly
|
|
32
|
+
constructor(private readonly _authProps: AuthExtensionProps) {
|
|
33
33
|
super({
|
|
34
34
|
requested: {
|
|
35
35
|
AuthService: schema.getService('dxos.mesh.teleport.auth.AuthService'),
|
|
@@ -46,7 +46,7 @@ export class AuthExtension extends RpcExtension<Services, Services> {
|
|
|
46
46
|
AuthService: {
|
|
47
47
|
authenticate: async ({ challenge }) => {
|
|
48
48
|
try {
|
|
49
|
-
const credential = await this.
|
|
49
|
+
const credential = await this._authProps.provider(challenge);
|
|
50
50
|
if (!credential) {
|
|
51
51
|
throw new Error('auth rejected');
|
|
52
52
|
}
|
|
@@ -67,13 +67,13 @@ export class AuthExtension extends RpcExtension<Services, Services> {
|
|
|
67
67
|
const challenge = randomBytes(32);
|
|
68
68
|
const { credential } = await this.rpc.AuthService.authenticate({ challenge });
|
|
69
69
|
invariant(credential?.length > 0, 'invalid credential');
|
|
70
|
-
const success = await this.
|
|
70
|
+
const success = await this._authProps.verifier(challenge, credential);
|
|
71
71
|
invariant(success, 'credential not verified');
|
|
72
|
-
runInContext(this._ctx, () => this.
|
|
72
|
+
runInContext(this._ctx, () => this._authProps.onAuthSuccess());
|
|
73
73
|
} catch (err) {
|
|
74
74
|
log('auth failed', err);
|
|
75
75
|
this.close();
|
|
76
|
-
this.
|
|
76
|
+
this._authProps.onAuthFailure();
|
|
77
77
|
}
|
|
78
78
|
});
|
|
79
79
|
}
|
|
@@ -25,7 +25,7 @@ import { type AsyncCallback, Callback, tracer } from '@dxos/util';
|
|
|
25
25
|
import { type MetadataStore } from '../metadata';
|
|
26
26
|
import { Pipeline, type PipelineAccessor } from '../pipeline';
|
|
27
27
|
|
|
28
|
-
export type
|
|
28
|
+
export type ControlPipelineProps = {
|
|
29
29
|
spaceKey: PublicKey;
|
|
30
30
|
genesisFeed: FeedWrapper<FeedMessage>;
|
|
31
31
|
feedProvider: (feedKey: PublicKey) => Promise<FeedWrapper<FeedMessage>>;
|
|
@@ -70,7 +70,7 @@ export class ControlPipeline {
|
|
|
70
70
|
await this._saveSnapshot();
|
|
71
71
|
});
|
|
72
72
|
|
|
73
|
-
constructor({ spaceKey, genesisFeed, feedProvider, metadataStore }:
|
|
73
|
+
constructor({ spaceKey, genesisFeed, feedProvider, metadataStore }: ControlPipelineProps) {
|
|
74
74
|
this._spaceKey = spaceKey;
|
|
75
75
|
this._metadata = metadataStore;
|
|
76
76
|
this._pipeline = new Pipeline();
|
|
@@ -26,7 +26,7 @@ import { CredentialRetrieverExtension } from './admission-discovery-extension';
|
|
|
26
26
|
import { Space } from './space';
|
|
27
27
|
import { SpaceProtocol, type SwarmIdentity } from './space-protocol';
|
|
28
28
|
|
|
29
|
-
export type
|
|
29
|
+
export type SpaceManagerProps = {
|
|
30
30
|
feedStore: FeedStore<FeedMessage>;
|
|
31
31
|
networkManager: SwarmNetworkManager;
|
|
32
32
|
metadataStore: MetadataStore;
|
|
@@ -36,7 +36,7 @@ export type SpaceManagerParams = {
|
|
|
36
36
|
disableP2pReplication?: boolean;
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
-
export type
|
|
39
|
+
export type ConstructSpaceProps = {
|
|
40
40
|
metadata: SpaceMetadata;
|
|
41
41
|
swarmIdentity: SwarmIdentity;
|
|
42
42
|
memberKey: PublicKey;
|
|
@@ -49,7 +49,7 @@ export type ConstructSpaceParams = {
|
|
|
49
49
|
onMemberRolesChanged: (member: MemberInfo[]) => Promise<void>;
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
-
export type
|
|
52
|
+
export type RequestSpaceAdmissionCredentialProps = {
|
|
53
53
|
spaceKey: PublicKey;
|
|
54
54
|
identityKey: PublicKey;
|
|
55
55
|
swarmIdentity: SwarmIdentity;
|
|
@@ -69,7 +69,7 @@ export class SpaceManager {
|
|
|
69
69
|
private readonly _instanceId = PublicKey.random().toHex();
|
|
70
70
|
private readonly _disableP2pReplication: boolean;
|
|
71
71
|
|
|
72
|
-
constructor({ feedStore, networkManager, metadataStore, blobStore, disableP2pReplication }:
|
|
72
|
+
constructor({ feedStore, networkManager, metadataStore, blobStore, disableP2pReplication }: SpaceManagerProps) {
|
|
73
73
|
// TODO(burdon): Assert.
|
|
74
74
|
this._feedStore = feedStore;
|
|
75
75
|
this._networkManager = networkManager;
|
|
@@ -99,7 +99,7 @@ export class SpaceManager {
|
|
|
99
99
|
onDelegatedInvitationStatusChange,
|
|
100
100
|
onMemberRolesChanged,
|
|
101
101
|
memberKey,
|
|
102
|
-
}:
|
|
102
|
+
}: ConstructSpaceProps): Promise<Space> {
|
|
103
103
|
log.trace('dxos.echo.space-manager.construct-space', trace.begin({ id: this._instanceId }));
|
|
104
104
|
log('constructing space...', { spaceKey: metadata.genesisFeedKey });
|
|
105
105
|
|
|
@@ -135,7 +135,7 @@ export class SpaceManager {
|
|
|
135
135
|
return space;
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
public async requestSpaceAdmissionCredential(params:
|
|
138
|
+
public async requestSpaceAdmissionCredential(params: RequestSpaceAdmissionCredentialProps): Promise<Credential> {
|
|
139
139
|
const traceKey = 'dxos.echo.space-manager.request-space-admission';
|
|
140
140
|
log.trace(traceKey, trace.begin({ id: this._instanceId }));
|
|
141
141
|
log('requesting space admission credential...', { spaceKey: params.spaceKey });
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
type SwarmConnection,
|
|
13
13
|
type SwarmNetworkManager,
|
|
14
14
|
type WireProtocol,
|
|
15
|
-
type
|
|
15
|
+
type WireProtocolProps,
|
|
16
16
|
type WireProtocolProvider,
|
|
17
17
|
} from '@dxos/network-manager';
|
|
18
18
|
import type { FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
@@ -176,16 +176,16 @@ export class SpaceProtocol {
|
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
private _createProtocolProvider(credentials: Uint8Array | undefined): WireProtocolProvider {
|
|
179
|
-
return (
|
|
179
|
+
return (wireProps) => {
|
|
180
180
|
const session = new SpaceProtocolSession({
|
|
181
|
-
|
|
181
|
+
wireProps,
|
|
182
182
|
swarmIdentity: this._swarmIdentity,
|
|
183
183
|
onSessionAuth: this._onSessionAuth,
|
|
184
184
|
onAuthFailure: this._onAuthFailure,
|
|
185
185
|
blobSync: this.blobSync,
|
|
186
186
|
disableP2pReplication: this._disableP2pReplication,
|
|
187
187
|
});
|
|
188
|
-
this._sessions.set(
|
|
188
|
+
this._sessions.set(wireProps.remotePeerId, session);
|
|
189
189
|
|
|
190
190
|
for (const feed of this._feeds) {
|
|
191
191
|
session.replicator.addFeed(feed);
|
|
@@ -196,8 +196,8 @@ export class SpaceProtocol {
|
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
-
export type
|
|
200
|
-
|
|
199
|
+
export type SpaceProtocolSessionProps = {
|
|
200
|
+
wireProps: WireProtocolProps;
|
|
201
201
|
swarmIdentity: SwarmIdentity;
|
|
202
202
|
|
|
203
203
|
blobSync: BlobSync;
|
|
@@ -225,7 +225,7 @@ export enum AuthStatus {
|
|
|
225
225
|
*/
|
|
226
226
|
export class SpaceProtocolSession implements WireProtocol {
|
|
227
227
|
@logInfo
|
|
228
|
-
private readonly
|
|
228
|
+
private readonly _wireProps: WireProtocolProps;
|
|
229
229
|
|
|
230
230
|
private readonly _disableP2pReplication: boolean;
|
|
231
231
|
|
|
@@ -252,20 +252,20 @@ export class SpaceProtocolSession implements WireProtocol {
|
|
|
252
252
|
|
|
253
253
|
// TODO(dmaretskyi): Allow to pass in extra extensions.
|
|
254
254
|
constructor({
|
|
255
|
-
|
|
255
|
+
wireProps,
|
|
256
256
|
swarmIdentity,
|
|
257
257
|
onSessionAuth,
|
|
258
258
|
onAuthFailure,
|
|
259
259
|
blobSync,
|
|
260
260
|
disableP2pReplication,
|
|
261
|
-
}:
|
|
262
|
-
this.
|
|
261
|
+
}: SpaceProtocolSessionProps) {
|
|
262
|
+
this._wireProps = wireProps;
|
|
263
263
|
this._swarmIdentity = swarmIdentity;
|
|
264
264
|
this._onSessionAuth = onSessionAuth;
|
|
265
265
|
this._onAuthFailure = onAuthFailure;
|
|
266
266
|
this._blobSync = blobSync;
|
|
267
267
|
|
|
268
|
-
this._teleport = new Teleport(
|
|
268
|
+
this._teleport = new Teleport(wireProps);
|
|
269
269
|
|
|
270
270
|
this._disableP2pReplication = disableP2pReplication ?? false;
|
|
271
271
|
}
|
package/src/space/space.ts
CHANGED
|
@@ -24,7 +24,7 @@ import { type SpaceProtocol } from './space-protocol';
|
|
|
24
24
|
// TODO(burdon): Factor out?
|
|
25
25
|
type FeedProvider = (feedKey: PublicKey, opts?: FeedOptions) => Promise<FeedWrapper<FeedMessage>>;
|
|
26
26
|
|
|
27
|
-
export type
|
|
27
|
+
export type SpaceProps = {
|
|
28
28
|
id: SpaceId;
|
|
29
29
|
spaceKey: PublicKey;
|
|
30
30
|
protocol: SpaceProtocol;
|
|
@@ -40,7 +40,7 @@ export type SpaceParams = {
|
|
|
40
40
|
onMemberRolesChanged: (member: MemberInfo[]) => Promise<void>;
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
-
export type
|
|
43
|
+
export type CreatePipelineProps = {
|
|
44
44
|
start: Timeframe;
|
|
45
45
|
// designation: AdmittedFeed.Designation;
|
|
46
46
|
};
|
|
@@ -68,7 +68,7 @@ export class Space extends Resource {
|
|
|
68
68
|
private _controlFeed?: FeedWrapper<FeedMessage>;
|
|
69
69
|
private _dataFeed?: FeedWrapper<FeedMessage>;
|
|
70
70
|
|
|
71
|
-
constructor(params:
|
|
71
|
+
constructor(params: SpaceProps) {
|
|
72
72
|
super();
|
|
73
73
|
invariant(params.spaceKey && params.feedProvider);
|
|
74
74
|
this._id = params.id;
|
package/src/testing/index.ts
CHANGED
|
@@ -11,12 +11,25 @@ import { log } from '@dxos/log';
|
|
|
11
11
|
export type TestConnectionStateProvider = () => 'on' | 'off';
|
|
12
12
|
|
|
13
13
|
export class TestAdapter extends NetworkAdapter {
|
|
14
|
-
static createPair(
|
|
14
|
+
static createPair(
|
|
15
|
+
connectionStateProvider: TestConnectionStateProvider = () => 'on',
|
|
16
|
+
onMessage?: (message: Message) => void,
|
|
17
|
+
): TestAdapter[] {
|
|
15
18
|
const adapter1: TestAdapter = new TestAdapter({
|
|
16
|
-
send: (message: Message) =>
|
|
19
|
+
send: (message: Message) => {
|
|
20
|
+
onMessage?.(message);
|
|
21
|
+
if (connectionStateProvider() === 'on') {
|
|
22
|
+
void sleep(10).then(() => adapter2.receive(message));
|
|
23
|
+
}
|
|
24
|
+
},
|
|
17
25
|
});
|
|
18
26
|
const adapter2: TestAdapter = new TestAdapter({
|
|
19
|
-
send: (message: Message) =>
|
|
27
|
+
send: (message: Message) => {
|
|
28
|
+
onMessage?.(message);
|
|
29
|
+
if (connectionStateProvider() === 'on') {
|
|
30
|
+
void sleep(10).then(() => adapter1.receive(message));
|
|
31
|
+
}
|
|
32
|
+
},
|
|
20
33
|
});
|
|
21
34
|
|
|
22
35
|
return [adapter1, adapter2];
|
|
@@ -13,8 +13,8 @@ import type {
|
|
|
13
13
|
EchoReplicator,
|
|
14
14
|
EchoReplicatorContext,
|
|
15
15
|
ReplicatorConnection,
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
ShouldAdvertiseProps,
|
|
17
|
+
ShouldSyncCollectionProps,
|
|
18
18
|
} from '../automerge';
|
|
19
19
|
|
|
20
20
|
export type TestReplicatorNetworkOptions = {
|
|
@@ -30,7 +30,7 @@ export class TestReplicationNetwork extends Resource {
|
|
|
30
30
|
this._latency = options.latency;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
protected override async _close(
|
|
33
|
+
protected override async _close(_ctx: Context): Promise<void> {
|
|
34
34
|
for (const replicator of this._replicators) {
|
|
35
35
|
for (const connection of replicator.connections) {
|
|
36
36
|
void connection.writable.abort();
|
|
@@ -115,13 +115,13 @@ export class TestReplicationNetwork extends Resource {
|
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
type
|
|
118
|
+
type TestReplicatorProps = {
|
|
119
119
|
onConnect: () => Promise<void>;
|
|
120
120
|
onDisconnect: () => Promise<void>;
|
|
121
121
|
};
|
|
122
122
|
|
|
123
123
|
export class TestReplicator implements EchoReplicator {
|
|
124
|
-
constructor(private readonly _params:
|
|
124
|
+
constructor(private readonly _params: TestReplicatorProps) {}
|
|
125
125
|
|
|
126
126
|
public connected = false;
|
|
127
127
|
public context: EchoReplicatorContext | undefined = undefined;
|
|
@@ -167,11 +167,11 @@ export class TestReplicatorConnection implements ReplicatorConnection {
|
|
|
167
167
|
return false;
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
-
async shouldAdvertise(
|
|
170
|
+
async shouldAdvertise(_params: ShouldAdvertiseProps): Promise<boolean> {
|
|
171
171
|
return true;
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
shouldSyncCollection(
|
|
174
|
+
shouldSyncCollection(_params: ShouldSyncCollectionProps): boolean {
|
|
175
175
|
return true;
|
|
176
176
|
}
|
|
177
177
|
}
|
|
@@ -194,5 +194,6 @@ export const brokenAutomergeReplicatorFactory: AutomergeReplicatorFactory = (par
|
|
|
194
194
|
params[1]!.onSyncMessage = () => {
|
|
195
195
|
throw new Error();
|
|
196
196
|
};
|
|
197
|
+
|
|
197
198
|
return testAutomergeReplicatorFactory(params);
|
|
198
199
|
};
|
package/src/util.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type DatabaseDirectory,
|
|
5
|
+
import { type DatabaseDirectory, EncodedReference, ObjectStructure } from '@dxos/echo-protocol';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Assumes properties are at root.
|
|
@@ -14,8 +14,12 @@ export const findInlineObjectOfType = (
|
|
|
14
14
|
for (const id in spaceDoc.objects ?? {}) {
|
|
15
15
|
const obj = spaceDoc.objects![id];
|
|
16
16
|
const objType = ObjectStructure.getTypeReference(obj);
|
|
17
|
-
if (objType
|
|
18
|
-
|
|
17
|
+
if (objType) {
|
|
18
|
+
const typeDXN = EncodedReference.toDXN(objType);
|
|
19
|
+
const typeDXNInfo = typeDXN.asTypeDXN();
|
|
20
|
+
if (typeDXNInfo?.type === typename) {
|
|
21
|
+
return [id, obj];
|
|
22
|
+
}
|
|
19
23
|
}
|
|
20
24
|
}
|
|
21
25
|
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import "@dxos/node-std/globals";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __export = (target, all) => {
|
|
4
|
-
for (var name in all)
|
|
5
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
export {
|
|
9
|
-
__export
|
|
10
|
-
};
|
|
11
|
-
//# sourceMappingURL=chunk-CGS2ULMK.mjs.map
|