@powerhousedao/reactor 6.0.0-dev.209 → 6.0.0-dev.210
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/index.d.ts +824 -722
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +279 -159
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { actions, actions as documentActions, createPresignedHeader, defaultBaseState, deriveOperationId, generateId, hashDocumentStateForScope, isUndoRedo } from "@powerhousedao/shared/document-model";
|
|
2
|
-
import { addFile, deleteNode } from "@powerhousedao/shared/document-drive";
|
|
1
|
+
import { actions, actions as documentActions, createPresignedHeader, defaultBaseState, deriveOperationId, generateId, hashDocumentStateForScope, isUndoRedo, replayDocument } from "@powerhousedao/shared/document-model";
|
|
2
|
+
import { addFile, addFolder, copyNode, deleteNode, driveCreateDocument, generateNodesCopy, getDescendants, handleTargetNameCollisions, isFileNode, isFolderNode, moveNode, updateNode } from "@powerhousedao/shared/document-drive";
|
|
3
3
|
import { v4 } from "uuid";
|
|
4
4
|
import { ConsoleLogger } from "document-model";
|
|
5
5
|
import { Migrator, sql } from "kysely";
|
|
@@ -257,33 +257,6 @@ function buildSingleJobMeta(jobId, callerMeta) {
|
|
|
257
257
|
};
|
|
258
258
|
}
|
|
259
259
|
//#endregion
|
|
260
|
-
//#region src/events/types.ts
|
|
261
|
-
/**
|
|
262
|
-
* Custom error class that aggregates multiple errors from event subscribers.
|
|
263
|
-
*/
|
|
264
|
-
var EventBusAggregateError = class extends Error {
|
|
265
|
-
errors;
|
|
266
|
-
constructor(errors) {
|
|
267
|
-
const message = `EventBus emit failed with ${errors.length} error(s): ${errors.map((e) => {
|
|
268
|
-
if (e && typeof e === "object" && "message" in e) return e.message;
|
|
269
|
-
return String(e);
|
|
270
|
-
}).join("; ")}`;
|
|
271
|
-
super(message);
|
|
272
|
-
this.name = "EventBusAggregateError";
|
|
273
|
-
this.errors = errors;
|
|
274
|
-
}
|
|
275
|
-
};
|
|
276
|
-
/**
|
|
277
|
-
* Event types for reactor lifecycle events.
|
|
278
|
-
*/
|
|
279
|
-
const ReactorEventTypes = {
|
|
280
|
-
JOB_PENDING: 10001,
|
|
281
|
-
JOB_RUNNING: 10002,
|
|
282
|
-
JOB_WRITE_READY: 10003,
|
|
283
|
-
JOB_READ_READY: 10004,
|
|
284
|
-
JOB_FAILED: 10005
|
|
285
|
-
};
|
|
286
|
-
//#endregion
|
|
287
260
|
//#region src/shared/types.ts
|
|
288
261
|
/**
|
|
289
262
|
* Enum that determines deletion propagation.
|
|
@@ -318,6 +291,230 @@ let JobStatus = /* @__PURE__ */ function(JobStatus) {
|
|
|
318
291
|
return JobStatus;
|
|
319
292
|
}({});
|
|
320
293
|
//#endregion
|
|
294
|
+
//#region src/client/drive-client.ts
|
|
295
|
+
/**
|
|
296
|
+
* Implementation of {@link IDriveClient}.
|
|
297
|
+
*
|
|
298
|
+
* Holds a back-reference to its parent {@link IReactorClient} for read and
|
|
299
|
+
* single-document write primitives, plus direct access to {@link IReactor}
|
|
300
|
+
* for batch execution. The back-reference is captured but never invoked
|
|
301
|
+
* during construction, so the partial-`this` hazard does not apply.
|
|
302
|
+
*/
|
|
303
|
+
var DriveClient = class {
|
|
304
|
+
constructor(client, logger, reactor, signer) {
|
|
305
|
+
this.client = client;
|
|
306
|
+
this.logger = logger;
|
|
307
|
+
this.reactor = reactor;
|
|
308
|
+
this.signer = signer;
|
|
309
|
+
}
|
|
310
|
+
async create(input, signal) {
|
|
311
|
+
this.logger.verbose("drives.create(@input)", input);
|
|
312
|
+
const driveDoc = driveCreateDocument({ global: {
|
|
313
|
+
name: input.global.name || "",
|
|
314
|
+
icon: input.global.icon ?? null,
|
|
315
|
+
nodes: []
|
|
316
|
+
} });
|
|
317
|
+
if (input.preferredEditor) driveDoc.header.meta = {
|
|
318
|
+
...driveDoc.header.meta,
|
|
319
|
+
preferredEditor: input.preferredEditor
|
|
320
|
+
};
|
|
321
|
+
return this.client.create(driveDoc, void 0, signal);
|
|
322
|
+
}
|
|
323
|
+
async addFile(driveIdentifier, document, parentFolder, signal) {
|
|
324
|
+
this.logger.verbose("drives.addFile(@driveIdentifier, @document, @parentFolder)", driveIdentifier, document.header.id, parentFolder);
|
|
325
|
+
const documentId = document.header.id;
|
|
326
|
+
const documentActions = await signActions([
|
|
327
|
+
createDocumentAction({
|
|
328
|
+
model: document.header.documentType,
|
|
329
|
+
version: 0,
|
|
330
|
+
documentId: document.header.id,
|
|
331
|
+
signing: {
|
|
332
|
+
signature: document.header.id,
|
|
333
|
+
publicKey: document.header.sig.publicKey,
|
|
334
|
+
nonce: document.header.sig.nonce,
|
|
335
|
+
createdAtUtcIso: document.header.createdAtUtcIso,
|
|
336
|
+
documentType: document.header.documentType
|
|
337
|
+
},
|
|
338
|
+
slug: document.header.slug,
|
|
339
|
+
name: document.header.name,
|
|
340
|
+
branch: document.header.branch,
|
|
341
|
+
meta: document.header.meta,
|
|
342
|
+
protocolVersions: document.header.protocolVersions ?? { "base-reducer": 2 }
|
|
343
|
+
}),
|
|
344
|
+
upgradeDocumentAction({
|
|
345
|
+
documentId: document.header.id,
|
|
346
|
+
model: document.header.documentType,
|
|
347
|
+
fromVersion: 0,
|
|
348
|
+
toVersion: 1,
|
|
349
|
+
initialState: document.state
|
|
350
|
+
}),
|
|
351
|
+
addRelationshipAction(driveIdentifier, documentId, "child")
|
|
352
|
+
], this.signer, signal);
|
|
353
|
+
const driveActions = await signActions([addFile({
|
|
354
|
+
id: documentId,
|
|
355
|
+
name: document.header.name || documentId,
|
|
356
|
+
documentType: document.header.documentType,
|
|
357
|
+
parentFolder
|
|
358
|
+
})], this.signer, signal);
|
|
359
|
+
const batchResult = await this.reactor.executeBatch({ jobs: [{
|
|
360
|
+
key: "document",
|
|
361
|
+
documentId,
|
|
362
|
+
scope: getSharedActionScope(documentActions),
|
|
363
|
+
branch: "main",
|
|
364
|
+
actions: documentActions,
|
|
365
|
+
dependsOn: []
|
|
366
|
+
}, {
|
|
367
|
+
key: "drive",
|
|
368
|
+
documentId: driveIdentifier,
|
|
369
|
+
scope: getSharedActionScope(driveActions),
|
|
370
|
+
branch: "main",
|
|
371
|
+
actions: driveActions,
|
|
372
|
+
dependsOn: ["document"]
|
|
373
|
+
}] }, signal);
|
|
374
|
+
const completedJobs = await Promise.all(Object.values(batchResult.jobs).map((job) => this.client.waitForJob(job, signal)));
|
|
375
|
+
for (const job of completedJobs) if (job.status === JobStatus.FAILED) throw new Error(job.error?.message);
|
|
376
|
+
return this.reactor.get(documentId);
|
|
377
|
+
}
|
|
378
|
+
async addFolder(driveIdentifier, name, parentFolder, signal) {
|
|
379
|
+
this.logger.verbose("drives.addFolder(@driveIdentifier, @name, @parentFolder)", driveIdentifier, name, parentFolder);
|
|
380
|
+
const folderId = generateId();
|
|
381
|
+
const node = (await this.client.execute(driveIdentifier, "main", [addFolder({
|
|
382
|
+
id: folderId,
|
|
383
|
+
name,
|
|
384
|
+
parentFolder
|
|
385
|
+
})], signal)).state.global.nodes.find((n) => n.id === folderId);
|
|
386
|
+
if (!node || !isFolderNode(node)) throw new Error("Folder creation failed");
|
|
387
|
+
return node;
|
|
388
|
+
}
|
|
389
|
+
async removeNode(driveIdentifier, nodeId, signal) {
|
|
390
|
+
this.logger.verbose("drives.removeNode(@driveIdentifier, @nodeId)", driveIdentifier, nodeId);
|
|
391
|
+
const drive = await this.client.get(driveIdentifier, void 0, signal);
|
|
392
|
+
const node = drive.state.global.nodes.find((n) => n.id === nodeId);
|
|
393
|
+
if (!node) throw new Error(`Node ${nodeId} not found in drive ${driveIdentifier}`);
|
|
394
|
+
if (isFolderNode(node)) {
|
|
395
|
+
const fileDescendants = getDescendants(node, drive.state.global.nodes).filter(isFileNode);
|
|
396
|
+
for (const file of fileDescendants) await this.removeFileNode(driveIdentifier, file.id, signal);
|
|
397
|
+
await this.client.execute(driveIdentifier, "main", [deleteNode({ id: nodeId })], signal);
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
await this.removeFileNode(driveIdentifier, nodeId, signal);
|
|
401
|
+
}
|
|
402
|
+
async renameNode(driveIdentifier, nodeId, name, signal) {
|
|
403
|
+
this.logger.verbose("drives.renameNode(@driveIdentifier, @nodeId, @name)", driveIdentifier, nodeId, name);
|
|
404
|
+
if ((await this.client.execute(nodeId, "main", [actions.setName({ name })], signal)).header.name !== name) throw new Error("Document rename did not apply");
|
|
405
|
+
const node = (await this.client.execute(driveIdentifier, "main", [updateNode({
|
|
406
|
+
id: nodeId,
|
|
407
|
+
name
|
|
408
|
+
})], signal)).state.global.nodes.find((n) => n.id === nodeId);
|
|
409
|
+
if (!node) throw new Error("Node missing from drive after rename");
|
|
410
|
+
return node;
|
|
411
|
+
}
|
|
412
|
+
async moveNode(driveIdentifier, srcNodeId, targetParentFolderId, signal) {
|
|
413
|
+
this.logger.verbose("drives.moveNode(@driveIdentifier, @srcNodeId, @targetParentFolderId)", driveIdentifier, srcNodeId, targetParentFolderId);
|
|
414
|
+
return this.client.execute(driveIdentifier, "main", [moveNode({
|
|
415
|
+
srcFolder: srcNodeId,
|
|
416
|
+
targetParentFolder: targetParentFolderId
|
|
417
|
+
})], signal);
|
|
418
|
+
}
|
|
419
|
+
async copyNode(driveIdentifier, srcNodeId, targetParentFolderId, signal) {
|
|
420
|
+
this.logger.verbose("drives.copyNode(@driveIdentifier, @srcNodeId, @targetParentFolderId)", driveIdentifier, srcNodeId, targetParentFolderId);
|
|
421
|
+
const drive = await this.client.get(driveIdentifier, void 0, signal);
|
|
422
|
+
const srcNode = drive.state.global.nodes.find((n) => n.id === srcNodeId);
|
|
423
|
+
if (!srcNode) throw new Error(`Node ${srcNodeId} not found in drive ${driveIdentifier}`);
|
|
424
|
+
const copyPlan = generateNodesCopy({
|
|
425
|
+
srcId: srcNodeId,
|
|
426
|
+
targetParentFolder: targetParentFolderId,
|
|
427
|
+
targetName: srcNode.name
|
|
428
|
+
}, () => generateId(), drive.state.global.nodes);
|
|
429
|
+
const resolvedNamesByTargetId = /* @__PURE__ */ new Map();
|
|
430
|
+
for (const entry of copyPlan) {
|
|
431
|
+
const node = drive.state.global.nodes.find((n) => n.id === entry.srcId);
|
|
432
|
+
if (!node) continue;
|
|
433
|
+
const resolved = handleTargetNameCollisions({
|
|
434
|
+
nodes: drive.state.global.nodes,
|
|
435
|
+
srcName: entry.targetName || node.name,
|
|
436
|
+
srcKind: isFileNode(node) ? "file" : "folder",
|
|
437
|
+
targetParentFolder: entry.targetParentFolder ?? null
|
|
438
|
+
});
|
|
439
|
+
resolvedNamesByTargetId.set(entry.targetId, resolved);
|
|
440
|
+
}
|
|
441
|
+
for (const entry of copyPlan) {
|
|
442
|
+
const node = drive.state.global.nodes.find((n) => n.id === entry.srcId);
|
|
443
|
+
if (!node || !isFileNode(node)) continue;
|
|
444
|
+
const srcDoc = await this.client.get(entry.srcId, void 0, signal);
|
|
445
|
+
const module = await this.client.getDocumentModelModule(srcDoc.header.documentType);
|
|
446
|
+
const duplicated = replayDocument(srcDoc.initialState, srcDoc.operations, module.reducer, createPresignedHeader(entry.targetId, srcDoc.header.documentType));
|
|
447
|
+
const resolvedName = resolvedNamesByTargetId.get(entry.targetId);
|
|
448
|
+
if (resolvedName) duplicated.header.name = resolvedName;
|
|
449
|
+
await this.addFile(driveIdentifier, duplicated, entry.targetParentFolder ?? void 0, signal);
|
|
450
|
+
}
|
|
451
|
+
return this.client.execute(driveIdentifier, "main", copyPlan.map((entry) => copyNode(entry)), signal);
|
|
452
|
+
}
|
|
453
|
+
async getNode(driveIdentifier, nodeId, signal) {
|
|
454
|
+
this.logger.verbose("drives.getNode(@driveIdentifier, @nodeId)", driveIdentifier, nodeId);
|
|
455
|
+
const node = (await this.client.get(driveIdentifier, void 0, signal)).state.global.nodes.find((n) => n.id === nodeId);
|
|
456
|
+
if (!node) throw new Error(`Node ${nodeId} not found in drive ${driveIdentifier}`);
|
|
457
|
+
return node;
|
|
458
|
+
}
|
|
459
|
+
async listNodes(driveIdentifier, parentFolder, signal) {
|
|
460
|
+
this.logger.verbose("drives.listNodes(@driveIdentifier, @parentFolder)", driveIdentifier, parentFolder);
|
|
461
|
+
const nodes = (await this.client.get(driveIdentifier, void 0, signal)).state.global.nodes;
|
|
462
|
+
if (parentFolder === void 0) return [...nodes];
|
|
463
|
+
return nodes.filter((n) => (n.parentFolder ?? null) === parentFolder);
|
|
464
|
+
}
|
|
465
|
+
async removeFileNode(driveId, fileId, signal) {
|
|
466
|
+
const relationshipActions = await signActions([removeRelationshipAction(driveId, fileId, "child")], this.signer, signal);
|
|
467
|
+
const driveActions = await signActions([deleteNode({ id: fileId })], this.signer, signal);
|
|
468
|
+
const batchResult = await this.reactor.executeBatch({ jobs: [{
|
|
469
|
+
key: "relationship",
|
|
470
|
+
documentId: driveId,
|
|
471
|
+
scope: getSharedActionScope(relationshipActions),
|
|
472
|
+
branch: "main",
|
|
473
|
+
actions: relationshipActions,
|
|
474
|
+
dependsOn: []
|
|
475
|
+
}, {
|
|
476
|
+
key: "drive",
|
|
477
|
+
documentId: driveId,
|
|
478
|
+
scope: getSharedActionScope(driveActions),
|
|
479
|
+
branch: "main",
|
|
480
|
+
actions: driveActions,
|
|
481
|
+
dependsOn: ["relationship"]
|
|
482
|
+
}] }, signal);
|
|
483
|
+
const completedJobs = await Promise.all(Object.values(batchResult.jobs).map((job) => this.client.waitForJob(job, signal)));
|
|
484
|
+
for (const job of completedJobs) if (job.status === JobStatus.FAILED) throw new Error(job.error?.message);
|
|
485
|
+
const deleteJob = await this.reactor.deleteDocument(fileId, this.signer, signal);
|
|
486
|
+
const deleteCompleted = await this.client.waitForJob(deleteJob, signal);
|
|
487
|
+
if (deleteCompleted.status === JobStatus.FAILED) throw new Error(deleteCompleted.error?.message);
|
|
488
|
+
}
|
|
489
|
+
};
|
|
490
|
+
//#endregion
|
|
491
|
+
//#region src/events/types.ts
|
|
492
|
+
/**
|
|
493
|
+
* Custom error class that aggregates multiple errors from event subscribers.
|
|
494
|
+
*/
|
|
495
|
+
var EventBusAggregateError = class extends Error {
|
|
496
|
+
errors;
|
|
497
|
+
constructor(errors) {
|
|
498
|
+
const message = `EventBus emit failed with ${errors.length} error(s): ${errors.map((e) => {
|
|
499
|
+
if (e && typeof e === "object" && "message" in e) return e.message;
|
|
500
|
+
return String(e);
|
|
501
|
+
}).join("; ")}`;
|
|
502
|
+
super(message);
|
|
503
|
+
this.name = "EventBusAggregateError";
|
|
504
|
+
this.errors = errors;
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
/**
|
|
508
|
+
* Event types for reactor lifecycle events.
|
|
509
|
+
*/
|
|
510
|
+
const ReactorEventTypes = {
|
|
511
|
+
JOB_PENDING: 10001,
|
|
512
|
+
JOB_RUNNING: 10002,
|
|
513
|
+
JOB_WRITE_READY: 10003,
|
|
514
|
+
JOB_READ_READY: 10004,
|
|
515
|
+
JOB_FAILED: 10005
|
|
516
|
+
};
|
|
517
|
+
//#endregion
|
|
321
518
|
//#region src/shared/awaiter.ts
|
|
322
519
|
/**
|
|
323
520
|
* Checks if a job status is terminal (job has finished).
|
|
@@ -484,6 +681,7 @@ var ReactorClient = class {
|
|
|
484
681
|
jobAwaiter;
|
|
485
682
|
documentIndexer;
|
|
486
683
|
documentView;
|
|
684
|
+
drives;
|
|
487
685
|
constructor(logger, reactor, signer, subscriptionManager, jobAwaiter, documentIndexer, documentView) {
|
|
488
686
|
this.logger = logger;
|
|
489
687
|
this.reactor = reactor;
|
|
@@ -492,6 +690,7 @@ var ReactorClient = class {
|
|
|
492
690
|
this.jobAwaiter = jobAwaiter;
|
|
493
691
|
this.documentIndexer = documentIndexer;
|
|
494
692
|
this.documentView = documentView;
|
|
693
|
+
this.drives = new DriveClient(this, logger, reactor, signer);
|
|
495
694
|
this.logger.verbose("ReactorClient initialized");
|
|
496
695
|
}
|
|
497
696
|
/**
|
|
@@ -579,36 +778,36 @@ var ReactorClient = class {
|
|
|
579
778
|
};
|
|
580
779
|
}
|
|
581
780
|
/**
|
|
582
|
-
* Retrieves
|
|
781
|
+
* Retrieves outgoing relationships of a given type from a source document.
|
|
583
782
|
*/
|
|
584
|
-
async
|
|
585
|
-
this.logger.verbose("
|
|
586
|
-
const
|
|
587
|
-
const
|
|
588
|
-
if (
|
|
783
|
+
async getOutgoingRelationships(sourceIdentifier, relationshipType, view, paging, signal) {
|
|
784
|
+
this.logger.verbose("getOutgoingRelationships(@sourceIdentifier, @relationshipType, @view, @paging)", sourceIdentifier, relationshipType, view, paging);
|
|
785
|
+
const sourceId = await this.documentView.resolveIdOrSlug(sourceIdentifier, view, void 0, signal);
|
|
786
|
+
const targetIds = (await this.documentIndexer.getOutgoing(sourceId, [relationshipType], void 0, void 0, signal)).results.map((rel) => rel.targetId);
|
|
787
|
+
if (targetIds.length === 0) return {
|
|
589
788
|
results: [],
|
|
590
789
|
options: paging || {
|
|
591
790
|
cursor: "0",
|
|
592
791
|
limit: 0
|
|
593
792
|
}
|
|
594
793
|
};
|
|
595
|
-
return this.reactor.find({ ids:
|
|
794
|
+
return this.reactor.find({ ids: targetIds }, view, paging, void 0, signal);
|
|
596
795
|
}
|
|
597
796
|
/**
|
|
598
|
-
* Retrieves
|
|
797
|
+
* Retrieves incoming relationships of a given type to a target document.
|
|
599
798
|
*/
|
|
600
|
-
async
|
|
601
|
-
this.logger.verbose("
|
|
602
|
-
const
|
|
603
|
-
const
|
|
604
|
-
if (
|
|
799
|
+
async getIncomingRelationships(targetIdentifier, relationshipType, view, paging, signal) {
|
|
800
|
+
this.logger.verbose("getIncomingRelationships(@targetIdentifier, @relationshipType, @view, @paging)", targetIdentifier, relationshipType, view, paging);
|
|
801
|
+
const targetId = await this.documentView.resolveIdOrSlug(targetIdentifier, view, void 0, signal);
|
|
802
|
+
const sourceIds = (await this.documentIndexer.getIncoming(targetId, [relationshipType], void 0, void 0, signal)).results.map((rel) => rel.sourceId);
|
|
803
|
+
if (sourceIds.length === 0) return {
|
|
605
804
|
results: [],
|
|
606
805
|
options: paging || {
|
|
607
806
|
cursor: "0",
|
|
608
807
|
limit: 0
|
|
609
808
|
}
|
|
610
809
|
};
|
|
611
|
-
return this.reactor.find({ ids:
|
|
810
|
+
return this.reactor.find({ ids: sourceIds }, view, paging, void 0, signal);
|
|
612
811
|
}
|
|
613
812
|
/**
|
|
614
813
|
* Filters documents by criteria and returns a list of them
|
|
@@ -693,61 +892,13 @@ var ReactorClient = class {
|
|
|
693
892
|
}
|
|
694
893
|
/**
|
|
695
894
|
* Creates an empty document in a drive as a single batched operation.
|
|
895
|
+
* Delegates to {@link IDriveClient.addFile}.
|
|
896
|
+
*
|
|
897
|
+
* @deprecated Use `client.drives.addFile` instead. This method will be
|
|
898
|
+
* removed in a future release.
|
|
696
899
|
*/
|
|
697
900
|
async createDocumentInDrive(driveId, document, parentFolder, signal) {
|
|
698
|
-
this.
|
|
699
|
-
const documentId = document.header.id;
|
|
700
|
-
const documentActions = await signActions([
|
|
701
|
-
createDocumentAction({
|
|
702
|
-
model: document.header.documentType,
|
|
703
|
-
version: 0,
|
|
704
|
-
documentId: document.header.id,
|
|
705
|
-
signing: {
|
|
706
|
-
signature: document.header.id,
|
|
707
|
-
publicKey: document.header.sig.publicKey,
|
|
708
|
-
nonce: document.header.sig.nonce,
|
|
709
|
-
createdAtUtcIso: document.header.createdAtUtcIso,
|
|
710
|
-
documentType: document.header.documentType
|
|
711
|
-
},
|
|
712
|
-
slug: document.header.slug,
|
|
713
|
-
name: document.header.name,
|
|
714
|
-
branch: document.header.branch,
|
|
715
|
-
meta: document.header.meta,
|
|
716
|
-
protocolVersions: document.header.protocolVersions ?? { "base-reducer": 2 }
|
|
717
|
-
}),
|
|
718
|
-
upgradeDocumentAction({
|
|
719
|
-
documentId: document.header.id,
|
|
720
|
-
model: document.header.documentType,
|
|
721
|
-
fromVersion: 0,
|
|
722
|
-
toVersion: 1,
|
|
723
|
-
initialState: document.state
|
|
724
|
-
}),
|
|
725
|
-
addRelationshipAction(driveId, documentId, "child")
|
|
726
|
-
], this.signer, signal);
|
|
727
|
-
const driveActions = await signActions([addFile({
|
|
728
|
-
id: documentId,
|
|
729
|
-
name: document.header.name || documentId,
|
|
730
|
-
documentType: document.header.documentType,
|
|
731
|
-
parentFolder
|
|
732
|
-
})], this.signer, signal);
|
|
733
|
-
const batchResult = await this.reactor.executeBatch({ jobs: [{
|
|
734
|
-
key: "document",
|
|
735
|
-
documentId,
|
|
736
|
-
scope: getSharedActionScope(documentActions),
|
|
737
|
-
branch: "main",
|
|
738
|
-
actions: documentActions,
|
|
739
|
-
dependsOn: []
|
|
740
|
-
}, {
|
|
741
|
-
key: "drive",
|
|
742
|
-
documentId: driveId,
|
|
743
|
-
scope: getSharedActionScope(driveActions),
|
|
744
|
-
branch: "main",
|
|
745
|
-
actions: driveActions,
|
|
746
|
-
dependsOn: ["document"]
|
|
747
|
-
}] }, signal);
|
|
748
|
-
const completedJobs = await Promise.all(Object.values(batchResult.jobs).map((job) => this.waitForJob(job, signal)));
|
|
749
|
-
for (const job of completedJobs) if (job.status === JobStatus.FAILED) throw new Error(job.error?.message);
|
|
750
|
-
return this.reactor.get(documentId);
|
|
901
|
+
return this.drives.addFile(driveId, document, parentFolder, signal);
|
|
751
902
|
}
|
|
752
903
|
/**
|
|
753
904
|
* Applies a list of actions to a document and waits for completion
|
|
@@ -779,32 +930,32 @@ var ReactorClient = class {
|
|
|
779
930
|
/**
|
|
780
931
|
* Adds multiple documents as children to another and waits for completion
|
|
781
932
|
*/
|
|
782
|
-
async
|
|
783
|
-
this.logger.verbose("
|
|
784
|
-
const jobInfo = await this.reactor.
|
|
933
|
+
async addRelationship(sourceIdentifier, targetIdentifier, relationshipType, branch = "main", signal) {
|
|
934
|
+
this.logger.verbose("addRelationship(@sourceIdentifier, @targetIdentifier, @relationshipType, @branch)", sourceIdentifier, targetIdentifier, relationshipType, branch);
|
|
935
|
+
const jobInfo = await this.reactor.addRelationship(sourceIdentifier, targetIdentifier, relationshipType, branch, this.signer, signal);
|
|
785
936
|
const completedJob = await this.waitForJob(jobInfo, signal);
|
|
786
937
|
if (completedJob.status === JobStatus.FAILED) throw new Error(completedJob.error?.message);
|
|
787
|
-
return await this.reactor.getByIdOrSlug(
|
|
938
|
+
return await this.reactor.getByIdOrSlug(sourceIdentifier, { branch }, completedJob.consistencyToken, signal);
|
|
788
939
|
}
|
|
789
940
|
/**
|
|
790
|
-
* Removes
|
|
941
|
+
* Removes a relationship between two documents and waits for completion.
|
|
791
942
|
*/
|
|
792
|
-
async
|
|
793
|
-
this.logger.verbose("
|
|
794
|
-
const jobInfo = await this.reactor.
|
|
943
|
+
async removeRelationship(sourceIdentifier, targetIdentifier, relationshipType, branch = "main", signal) {
|
|
944
|
+
this.logger.verbose("removeRelationship(@sourceIdentifier, @targetIdentifier, @relationshipType, @branch)", sourceIdentifier, targetIdentifier, relationshipType, branch);
|
|
945
|
+
const jobInfo = await this.reactor.removeRelationship(sourceIdentifier, targetIdentifier, relationshipType, branch, this.signer, signal);
|
|
795
946
|
const completedJob = await this.waitForJob(jobInfo, signal);
|
|
796
947
|
if (completedJob.status === JobStatus.FAILED) throw new Error(completedJob.error?.message);
|
|
797
|
-
return await this.reactor.getByIdOrSlug(
|
|
948
|
+
return await this.reactor.getByIdOrSlug(sourceIdentifier, { branch }, completedJob.consistencyToken, signal);
|
|
798
949
|
}
|
|
799
950
|
/**
|
|
800
|
-
* Moves
|
|
951
|
+
* Moves a relationship from one source document to another and waits for completion.
|
|
801
952
|
*/
|
|
802
|
-
async
|
|
803
|
-
this.logger.verbose("
|
|
804
|
-
const removeJobInfo = await this.reactor.
|
|
953
|
+
async moveRelationship(sourceParentIdentifier, targetParentIdentifier, targetIdentifier, relationshipType, branch = "main", signal) {
|
|
954
|
+
this.logger.verbose("moveRelationship(@sourceParentIdentifier, @targetParentIdentifier, @targetIdentifier, @relationshipType, @branch)", sourceParentIdentifier, targetParentIdentifier, targetIdentifier, relationshipType, branch);
|
|
955
|
+
const removeJobInfo = await this.reactor.removeRelationship(sourceParentIdentifier, targetIdentifier, relationshipType, branch, this.signer, signal);
|
|
805
956
|
const removeCompletedJob = await this.waitForJob(removeJobInfo, signal);
|
|
806
957
|
if (removeCompletedJob.status === JobStatus.FAILED) throw new Error(removeCompletedJob.error?.message);
|
|
807
|
-
const addJobInfo = await this.reactor.
|
|
958
|
+
const addJobInfo = await this.reactor.addRelationship(targetParentIdentifier, targetIdentifier, relationshipType, branch, this.signer, signal);
|
|
808
959
|
const addCompletedJob = await this.waitForJob(addJobInfo, signal);
|
|
809
960
|
if (addCompletedJob.status === JobStatus.FAILED) throw new Error(addCompletedJob.error?.message);
|
|
810
961
|
return {
|
|
@@ -841,13 +992,13 @@ var ReactorClient = class {
|
|
|
841
992
|
}
|
|
842
993
|
for (const descendantId of toDelete) {
|
|
843
994
|
if (descendantId === identifier) continue;
|
|
844
|
-
const removalJobs = await this.
|
|
995
|
+
const removalJobs = await this.removeAllIncomingRelationships(descendantId, signal);
|
|
845
996
|
jobs.push(...removalJobs);
|
|
846
997
|
const jobInfo = await this.reactor.deleteDocument(descendantId, this.signer, signal);
|
|
847
998
|
jobs.push(jobInfo);
|
|
848
999
|
}
|
|
849
1000
|
}
|
|
850
|
-
const removalJobs = await this.
|
|
1001
|
+
const removalJobs = await this.removeAllIncomingRelationships(identifier, signal);
|
|
851
1002
|
jobs.push(...removalJobs);
|
|
852
1003
|
const jobInfo = await this.reactor.deleteDocument(identifier, this.signer, signal);
|
|
853
1004
|
jobs.push(jobInfo);
|
|
@@ -923,46 +1074,15 @@ var ReactorClient = class {
|
|
|
923
1074
|
unsubscribeRelationship();
|
|
924
1075
|
};
|
|
925
1076
|
}
|
|
926
|
-
async
|
|
1077
|
+
async removeAllIncomingRelationships(documentId, signal) {
|
|
927
1078
|
const incoming = await this.documentIndexer.getIncoming(documentId, void 0, void 0, void 0, signal);
|
|
928
1079
|
const jobs = [];
|
|
929
1080
|
for (const rel of incoming.results) {
|
|
930
|
-
const
|
|
931
|
-
jobs.push(
|
|
1081
|
+
const jobInfo = await this.reactor.removeRelationship(rel.sourceId, documentId, rel.relationshipType, "main", this.signer, signal);
|
|
1082
|
+
jobs.push(jobInfo);
|
|
932
1083
|
}
|
|
933
1084
|
return jobs;
|
|
934
1085
|
}
|
|
935
|
-
async removeFromParent(documentId, rel, signal) {
|
|
936
|
-
const parentId = rel.sourceId;
|
|
937
|
-
let parentDoc;
|
|
938
|
-
try {
|
|
939
|
-
parentDoc = await this.reactor.get(parentId, void 0, void 0, signal);
|
|
940
|
-
} catch {
|
|
941
|
-
return [];
|
|
942
|
-
}
|
|
943
|
-
const isDrive = parentDoc.header.documentType === "powerhouse/document-drive";
|
|
944
|
-
const relationshipActions = await signActions([removeRelationshipAction(parentId, documentId, rel.relationshipType)], this.signer, signal);
|
|
945
|
-
if (isDrive) {
|
|
946
|
-
const driveActions = await signActions([deleteNode({ id: documentId })], this.signer, signal);
|
|
947
|
-
const batchResult = await this.reactor.executeBatch({ jobs: [{
|
|
948
|
-
key: "relationship",
|
|
949
|
-
documentId: parentId,
|
|
950
|
-
scope: getSharedActionScope(relationshipActions),
|
|
951
|
-
branch: "main",
|
|
952
|
-
actions: relationshipActions,
|
|
953
|
-
dependsOn: []
|
|
954
|
-
}, {
|
|
955
|
-
key: "drive",
|
|
956
|
-
documentId: parentId,
|
|
957
|
-
scope: getSharedActionScope(driveActions),
|
|
958
|
-
branch: "main",
|
|
959
|
-
actions: driveActions,
|
|
960
|
-
dependsOn: ["relationship"]
|
|
961
|
-
}] }, signal);
|
|
962
|
-
return [...Object.values(batchResult.jobs)];
|
|
963
|
-
}
|
|
964
|
-
return [await this.reactor.removeChildren(parentId, [documentId], "main", this.signer, signal)];
|
|
965
|
-
}
|
|
966
1086
|
};
|
|
967
1087
|
//#endregion
|
|
968
1088
|
//#region src/cache/collection-membership-cache.ts
|
|
@@ -8816,13 +8936,13 @@ var Reactor = class {
|
|
|
8816
8936
|
this.logger.verbose("getByIdOrSlug(@identifier, @view)", identifier, view);
|
|
8817
8937
|
return await this.documentView.getByIdOrSlug(identifier, view, consistencyToken, signal);
|
|
8818
8938
|
}
|
|
8819
|
-
async
|
|
8820
|
-
const relationships = await this.documentIndexer.getOutgoing(
|
|
8939
|
+
async getOutgoingRelationships(sourceId, relationshipType, consistencyToken, signal) {
|
|
8940
|
+
const relationships = await this.documentIndexer.getOutgoing(sourceId, [relationshipType], void 0, consistencyToken, signal);
|
|
8821
8941
|
if (signal?.aborted) throw new AbortError();
|
|
8822
8942
|
return relationships.results.map((rel) => rel.targetId);
|
|
8823
8943
|
}
|
|
8824
|
-
async
|
|
8825
|
-
const relationships = await this.documentIndexer.getIncoming(
|
|
8944
|
+
async getIncomingRelationships(targetId, relationshipType, consistencyToken, signal) {
|
|
8945
|
+
const relationships = await this.documentIndexer.getIncoming(targetId, [relationshipType], void 0, consistencyToken, signal);
|
|
8826
8946
|
if (signal?.aborted) throw new AbortError();
|
|
8827
8947
|
return relationships.results.map((rel) => rel.sourceId);
|
|
8828
8948
|
}
|
|
@@ -9182,19 +9302,19 @@ var Reactor = class {
|
|
|
9182
9302
|
}
|
|
9183
9303
|
return { jobs: Object.fromEntries(jobInfos) };
|
|
9184
9304
|
}
|
|
9185
|
-
async
|
|
9186
|
-
this.logger.verbose("
|
|
9305
|
+
async addRelationship(sourceId, targetId, relationshipType, branch = "main", signer, signal) {
|
|
9306
|
+
this.logger.verbose("addRelationship(@sourceId, @targetId, @relationshipType, @branch)", sourceId, targetId, relationshipType, branch);
|
|
9187
9307
|
if (signal?.aborted) throw new AbortError();
|
|
9188
|
-
let actions =
|
|
9308
|
+
let actions = [addRelationshipAction(sourceId, targetId, relationshipType)];
|
|
9189
9309
|
if (signer) actions = await signActions(actions, signer, signal);
|
|
9190
|
-
return await this.execute(
|
|
9310
|
+
return await this.execute(sourceId, branch, actions, signal);
|
|
9191
9311
|
}
|
|
9192
|
-
async
|
|
9193
|
-
this.logger.verbose("
|
|
9312
|
+
async removeRelationship(sourceId, targetId, relationshipType, branch = "main", signer, signal) {
|
|
9313
|
+
this.logger.verbose("removeRelationship(@sourceId, @targetId, @relationshipType, @branch)", sourceId, targetId, relationshipType, branch);
|
|
9194
9314
|
if (signal?.aborted) throw new AbortError();
|
|
9195
|
-
let actions =
|
|
9315
|
+
let actions = [removeRelationshipAction(sourceId, targetId, relationshipType)];
|
|
9196
9316
|
if (signer) actions = await signActions(actions, signer, signal);
|
|
9197
|
-
return await this.execute(
|
|
9317
|
+
return await this.execute(sourceId, branch, actions, signal);
|
|
9198
9318
|
}
|
|
9199
9319
|
getJobStatus(jobId, signal) {
|
|
9200
9320
|
this.logger.verbose("getJobStatus(@jobId)", jobId);
|
|
@@ -9772,6 +9892,6 @@ var DocumentIntegrityService = class {
|
|
|
9772
9892
|
}
|
|
9773
9893
|
};
|
|
9774
9894
|
//#endregion
|
|
9775
|
-
export { BaseReadModel, ChannelError, ChannelErrorSource, ChannelScheme, ConsistencyTracker, DefaultSubscriptionErrorHandler, DocumentChangeType, DocumentIntegrityService, DocumentModelRegistry, DuplicateManifestError, DuplicateModuleError, DuplicateOperationError, EventBus, EventBusAggregateError, GqlRequestChannel, GqlRequestChannelFactory, GqlResponseChannel, GqlResponseChannelFactory, SimpleJobExecutor as InMemoryJobExecutor, SimpleJobExecutor, InMemoryJobTracker, InMemoryQueue, IntervalPollTimer, InvalidModuleError, JobAwaiter, JobExecutorEventTypes, JobStatus, KyselyDocumentIndexer, KyselyDocumentView, KyselyKeyframeStore, KyselyOperationStore, KyselySyncCursorStorage, KyselySyncRemoteStorage, KyselyWriteCache, Mailbox, ModuleNotFoundError, NullDocumentModelResolver, OptimisticLockError, PollingChannelError, ProcessorManager, PropagationMode, QueueEventTypes, REACTOR_SCHEMA, Reactor, ReactorBuilder, ReactorClient, ReactorClientBuilder, ReactorEventTypes, ReactorSubscriptionManager, ReadModelCoordinator, RelationalDbProcessor, RelationshipChangeType, RevisionMismatchError, SimpleJobExecutorManager, SyncBuilder, SyncEventTypes, SyncOperation, SyncOperationAggregateError, SyncOperationStatus, SyncStatus, SyncStatusTracker, addRelationshipAction, batchOperationsByDocument, consolidateSyncOperations, createDocumentAction, createMutableShutdownStatus, createRelationalDb, deleteDocumentAction, documentActions, driveCollectionId, driveIdFromUrl, envelopesToSyncOperations, getMigrationStatus, makeConsistencyKey, parseDriveUrl, removeRelationshipAction, runMigrations, sortEnvelopesByFirstOperationTimestamp, trimMailboxFromAckOrdinal, upgradeDocumentAction };
|
|
9895
|
+
export { BaseReadModel, ChannelError, ChannelErrorSource, ChannelScheme, ConsistencyTracker, DefaultSubscriptionErrorHandler, DocumentChangeType, DocumentIntegrityService, DocumentModelRegistry, DriveClient, DuplicateManifestError, DuplicateModuleError, DuplicateOperationError, EventBus, EventBusAggregateError, GqlRequestChannel, GqlRequestChannelFactory, GqlResponseChannel, GqlResponseChannelFactory, SimpleJobExecutor as InMemoryJobExecutor, SimpleJobExecutor, InMemoryJobTracker, InMemoryQueue, IntervalPollTimer, InvalidModuleError, JobAwaiter, JobExecutorEventTypes, JobStatus, KyselyDocumentIndexer, KyselyDocumentView, KyselyKeyframeStore, KyselyOperationStore, KyselySyncCursorStorage, KyselySyncRemoteStorage, KyselyWriteCache, Mailbox, ModuleNotFoundError, NullDocumentModelResolver, OptimisticLockError, PollingChannelError, ProcessorManager, PropagationMode, QueueEventTypes, REACTOR_SCHEMA, Reactor, ReactorBuilder, ReactorClient, ReactorClientBuilder, ReactorEventTypes, ReactorSubscriptionManager, ReadModelCoordinator, RelationalDbProcessor, RelationshipChangeType, RevisionMismatchError, SimpleJobExecutorManager, SyncBuilder, SyncEventTypes, SyncOperation, SyncOperationAggregateError, SyncOperationStatus, SyncStatus, SyncStatusTracker, addRelationshipAction, batchOperationsByDocument, consolidateSyncOperations, createDocumentAction, createMutableShutdownStatus, createRelationalDb, deleteDocumentAction, documentActions, driveCollectionId, driveIdFromUrl, envelopesToSyncOperations, getMigrationStatus, makeConsistencyKey, parseDriveUrl, removeRelationshipAction, runMigrations, sortEnvelopesByFirstOperationTimestamp, trimMailboxFromAckOrdinal, upgradeDocumentAction };
|
|
9776
9896
|
|
|
9777
9897
|
//# sourceMappingURL=index.js.map
|