@powerhousedao/reactor-api 1.20.2 → 1.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,23 +1,3 @@
1
- ## 1.20.2 (2025-02-10)
2
-
3
- ### 🚀 Features
4
-
5
- - **design-system:** add danger zone settings page ([572345bc](https://github.com/powerhouse-inc/powerhouse/commit/572345bc))
6
-
7
- ### 🩹 Fixes
8
-
9
- - **reactor-api:** sanitize document model name before using it as __typename ([adcca457](https://github.com/powerhouse-inc/powerhouse/commit/adcca457))
10
-
11
- ### 🧱 Updated Dependencies
12
-
13
- - Updated document-model-libs to 1.131.2
14
- - Updated document-drive to 1.17.2
15
-
16
- ### ❤️ Thank You
17
-
18
- - ryanwolhuter @ryanwolhuter
19
- - Wouter Kampmann
20
-
21
1
  ## 1.2.0 (2024-10-29)
22
2
 
23
3
  ### 🚀 Features
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { PGlite } from '@electric-sql/pglite';
2
2
  import * as document_model_libs_document_drive from 'document-model-libs/document-drive';
3
- import { Trigger, PullResponderTriggerData, DocumentDriveDocument, ListenerFilter, DocumentDriveState, DocumentDriveLocalState, ListenerCallInfo, DocumentDriveAction } from 'document-model-libs/document-drive';
4
- import { Operation, Document, DocumentModel, Action, OperationScope, State, BaseAction, CreateChildDocumentInput, ActionContext, ReducerOptions, Signal } from 'document-model/document';
3
+ import { DocumentDriveDocument, ListenerFilter, Trigger, PullResponderTriggerData, DocumentDriveState, DocumentDriveLocalState, ListenerCallInfo, DocumentDriveAction } from 'document-model-libs/document-drive';
4
+ import { Operation, Document, DocumentModel, Action, OperationScope, State, BaseAction, ActionContext, ReducerOptions, Signal } from 'document-model/document';
5
5
  import { Unsubscribe } from 'nanoevents';
6
6
  import express, { Express } from 'express';
7
7
  import { Pool } from 'pg';
@@ -15,21 +15,6 @@ import { GraphQLResolverMap as GraphQLResolverMap$1 } from '@apollo/subgraph/dis
15
15
  import { AnalyticsModel } from '@powerhousedao/analytics-engine-graphql';
16
16
  import { GraphQLResolverMap } from '@apollo/subgraph/dist/schema-helper/resolverMap.js';
17
17
 
18
- type StrandUpdateSource = {
19
- type: "local";
20
- } | {
21
- type: "trigger";
22
- trigger: Trigger;
23
- };
24
- interface ITransmitter {
25
- transmit?(strands: StrandUpdate[], source: StrandUpdateSource): Promise<ListenerRevision[]>;
26
- disconnect?(): Promise<void>;
27
- }
28
- type PullResponderTrigger = Omit<Trigger, "data" | "type"> & {
29
- data: PullResponderTriggerData;
30
- type: "PullResponder";
31
- };
32
-
33
18
  declare class DocumentModelNotFoundError extends Error {
34
19
  id: string;
35
20
  constructor(id: string, cause?: unknown);
@@ -93,6 +78,28 @@ interface IReadModeDriveService {
93
78
  deleteReadDrive(id: string): Promise<ReadDriveNotFoundError | undefined>;
94
79
  }
95
80
 
81
+ interface IDefaultDrivesManager {
82
+ initializeDefaultRemoteDrives(): Promise<void>;
83
+ getDefaultRemoteDrives(): Map<string, DefaultRemoteDriveInfo>;
84
+ setDefaultDriveAccessLevel(url: string, level: RemoteDriveAccessLevel): Promise<void>;
85
+ setAllDefaultDrivesAccessLevel(level: RemoteDriveAccessLevel): Promise<void>;
86
+ }
87
+
88
+ type StrandUpdateSource = {
89
+ type: "local";
90
+ } | {
91
+ type: "trigger";
92
+ trigger: Trigger;
93
+ };
94
+ interface ITransmitter {
95
+ transmit?(strands: StrandUpdate[], source: StrandUpdateSource): Promise<ListenerRevision[]>;
96
+ disconnect?(): Promise<void>;
97
+ }
98
+ type PullResponderTrigger = Omit<Trigger, "data" | "type"> & {
99
+ data: PullResponderTriggerData;
100
+ type: "PullResponder";
101
+ };
102
+
96
103
  interface IReceiver<T extends Document = Document, S extends OperationScope = OperationScope> {
97
104
  onStrands: (strands: InternalTransmitterUpdate<T, S>[]) => Promise<void>;
98
105
  onDisconnect: () => Promise<void>;
@@ -113,13 +120,6 @@ interface IInternalTransmitter extends ITransmitter {
113
120
  setReceiver(receiver: IReceiver): void;
114
121
  }
115
122
 
116
- interface IDefaultDrivesManager {
117
- initializeDefaultRemoteDrives(): Promise<void>;
118
- getDefaultRemoteDrives(): Map<string, DefaultRemoteDriveInfo>;
119
- setDefaultDriveAccessLevel(url: string, level: RemoteDriveAccessLevel): Promise<void>;
120
- setAllDefaultDrivesAccessLevel(level: RemoteDriveAccessLevel): Promise<void>;
121
- }
122
-
123
123
  type DriveInput = State<Omit<DocumentDriveState, "__typename" | "id" | "nodes"> & {
124
124
  id?: string;
125
125
  }, DocumentDriveLocalState>;
@@ -130,7 +130,6 @@ type RemoteDriveOptions = DocumentDriveLocalState & {
130
130
  expectedDriveInfo?: DriveInfo;
131
131
  accessLevel?: RemoteDriveAccessLevel;
132
132
  };
133
- type CreateDocumentInput = CreateChildDocumentInput;
134
133
  type SignalResult = {
135
134
  signal: Signal;
136
135
  result: unknown;
@@ -161,6 +160,7 @@ type Listener = {
161
160
  system: boolean;
162
161
  filter: ListenerFilter;
163
162
  callInfo?: ListenerCallInfo;
163
+ transmitter?: ITransmitter;
164
164
  };
165
165
  type ListenerRevision = {
166
166
  driveId: string;
@@ -232,65 +232,52 @@ type GetStrandsOptions = {
232
232
  since?: string;
233
233
  fromRevision?: number;
234
234
  };
235
- declare abstract class AbstractDocumentDriveServer {
236
- /** Public methods **/
237
- abstract initialize(): Promise<Error[] | null>;
238
- abstract setDocumentModels(models: DocumentModel[]): void;
239
- abstract getDrives(): Promise<string[]>;
240
- abstract addDrive(drive: DriveInput): Promise<DocumentDriveDocument>;
241
- abstract addRemoteDrive(url: string, options: RemoteDriveOptions): Promise<DocumentDriveDocument>;
242
- abstract deleteDrive(id: string): Promise<void>;
243
- abstract getDrive(id: string, options?: GetDocumentOptions): Promise<DocumentDriveDocument>;
244
- abstract getDriveBySlug(slug: string): Promise<DocumentDriveDocument>;
245
- abstract getDocuments(drive: string): Promise<string[]>;
246
- abstract getDocument(drive: string, id: string, options?: GetDocumentOptions): Promise<Document>;
247
- abstract addOperation(drive: string, id: string, operation: Operation, options?: AddOperationOptions): Promise<IOperationResult>;
248
- abstract addOperations(drive: string, id: string, operations: Operation[], options?: AddOperationOptions): Promise<IOperationResult>;
249
- abstract queueOperation(drive: string, id: string, operation: Operation, options?: AddOperationOptions): Promise<IOperationResult>;
250
- abstract queueOperations(drive: string, id: string, operations: Operation[], options?: AddOperationOptions): Promise<IOperationResult>;
251
- abstract queueAction(drive: string, id: string, action: Action, options?: AddOperationOptions): Promise<IOperationResult>;
252
- abstract queueActions(drive: string, id: string, actions: Action[], options?: AddOperationOptions): Promise<IOperationResult>;
253
- abstract addDriveOperation(drive: string, operation: Operation<DocumentDriveAction | BaseAction>, options?: AddOperationOptions): Promise<IOperationResult<DocumentDriveDocument>>;
254
- abstract addDriveOperations(drive: string, operations: Operation<DocumentDriveAction | BaseAction>[], options?: AddOperationOptions): Promise<IOperationResult<DocumentDriveDocument>>;
255
- abstract queueDriveOperation(drive: string, operation: Operation<DocumentDriveAction | BaseAction>, options?: AddOperationOptions): Promise<IOperationResult<DocumentDriveDocument>>;
256
- abstract queueDriveOperations(drive: string, operations: Operation<DocumentDriveAction | BaseAction>[], options?: AddOperationOptions): Promise<IOperationResult<DocumentDriveDocument>>;
257
- abstract queueDriveAction(drive: string, action: DocumentDriveAction | BaseAction, options?: AddOperationOptions): Promise<IOperationResult<DocumentDriveDocument>>;
258
- abstract queueDriveActions(drive: string, actions: Array<DocumentDriveAction | BaseAction>, options?: AddOperationOptions): Promise<IOperationResult<DocumentDriveDocument>>;
259
- abstract addAction(drive: string, id: string, action: Action, options?: AddOperationOptions): Promise<IOperationResult>;
260
- abstract addActions(drive: string, id: string, actions: Action[], options?: AddOperationOptions): Promise<IOperationResult>;
261
- abstract addDriveAction(drive: string, action: DocumentDriveAction | BaseAction, options?: AddOperationOptions): Promise<IOperationResult<DocumentDriveDocument>>;
262
- abstract addDriveActions(drive: string, actions: (DocumentDriveAction | BaseAction)[], options?: AddOperationOptions): Promise<IOperationResult<DocumentDriveDocument>>;
263
- abstract getSyncStatus(syncUnitId: string): SyncStatus | SynchronizationUnitNotFoundError;
264
- abstract addInternalListener(driveId: string, receiver: IReceiver, options: {
235
+ interface IBaseDocumentDriveServer {
236
+ initialize(): Promise<Error[] | null>;
237
+ setDocumentModels(models: DocumentModel[]): void;
238
+ getDrives(): Promise<string[]>;
239
+ addDrive(input: DriveInput): Promise<DocumentDriveDocument>;
240
+ addRemoteDrive(url: string, options: RemoteDriveOptions): Promise<DocumentDriveDocument>;
241
+ deleteDrive(driveId: string): Promise<void>;
242
+ getDrive(driveId: string, options?: GetDocumentOptions): Promise<DocumentDriveDocument>;
243
+ getDriveBySlug(slug: string): Promise<DocumentDriveDocument>;
244
+ getDocuments(driveId: string): Promise<string[]>;
245
+ getDocument(driveId: string, documentId: string, options?: GetDocumentOptions): Promise<Document>;
246
+ addOperation(driveId: string, documentId: string, operation: Operation, options?: AddOperationOptions): Promise<IOperationResult>;
247
+ addOperations(driveId: string, documentId: string, operations: Operation[], options?: AddOperationOptions): Promise<IOperationResult>;
248
+ queueOperation(driveId: string, documentId: string, operation: Operation, options?: AddOperationOptions): Promise<IOperationResult>;
249
+ queueOperations(driveId: string, documentId: string, operations: Operation[], options?: AddOperationOptions): Promise<IOperationResult>;
250
+ queueAction(driveId: string, documentId: string, action: Action, options?: AddOperationOptions): Promise<IOperationResult>;
251
+ queueActions(driveId: string, documentId: string, actions: Action[], options?: AddOperationOptions): Promise<IOperationResult>;
252
+ addDriveOperation(driveId: string, operation: Operation<DocumentDriveAction | BaseAction>, options?: AddOperationOptions): Promise<IOperationResult<DocumentDriveDocument>>;
253
+ addDriveOperations(driveId: string, operations: Operation<DocumentDriveAction | BaseAction>[], options?: AddOperationOptions): Promise<IOperationResult<DocumentDriveDocument>>;
254
+ queueDriveOperation(driveId: string, operation: Operation<DocumentDriveAction | BaseAction>, options?: AddOperationOptions): Promise<IOperationResult<DocumentDriveDocument>>;
255
+ queueDriveOperations(driveId: string, operations: Operation<DocumentDriveAction | BaseAction>[], options?: AddOperationOptions): Promise<IOperationResult<DocumentDriveDocument>>;
256
+ queueDriveAction(driveId: string, action: DocumentDriveAction | BaseAction, options?: AddOperationOptions): Promise<IOperationResult<DocumentDriveDocument>>;
257
+ queueDriveActions(driveId: string, actions: Array<DocumentDriveAction | BaseAction>, options?: AddOperationOptions): Promise<IOperationResult<DocumentDriveDocument>>;
258
+ addAction(driveId: string, documentId: string, action: Action, options?: AddOperationOptions): Promise<IOperationResult>;
259
+ addActions(driveId: string, documentId: string, actions: Action[], options?: AddOperationOptions): Promise<IOperationResult>;
260
+ addDriveAction(driveId: string, action: DocumentDriveAction | BaseAction, options?: AddOperationOptions): Promise<IOperationResult<DocumentDriveDocument>>;
261
+ addDriveActions(driveId: string, actions: (DocumentDriveAction | BaseAction)[], options?: AddOperationOptions): Promise<IOperationResult<DocumentDriveDocument>>;
262
+ getSyncStatus(syncUnitId: string): SyncStatus | SynchronizationUnitNotFoundError;
263
+ addInternalListener(driveId: string, receiver: IReceiver, options: {
265
264
  listenerId: string;
266
265
  label: string;
267
266
  block: boolean;
268
267
  filter: ListenerFilter;
269
268
  }): Promise<IInternalTransmitter>;
270
269
  /** Synchronization methods */
271
- abstract getSynchronizationUnits(driveId: string, documentId?: string[], scope?: string[], branch?: string[], documentType?: string[], loadedDrive?: DocumentDriveDocument): Promise<SynchronizationUnit[]>;
272
- abstract getSynchronizationUnit(driveId: string, syncId: string, loadedDrive?: DocumentDriveDocument): Promise<SynchronizationUnit | undefined>;
273
- abstract getSynchronizationUnitsIds(driveId: string, documentId?: string[], scope?: string[], branch?: string[], documentType?: string[]): Promise<SynchronizationUnitQuery[]>;
274
- abstract getOperationData(driveId: string, syncId: string, filter: GetStrandsOptions, loadedDrive?: DocumentDriveDocument): Promise<OperationUpdate[]>;
270
+ getSynchronizationUnits(driveId: string, documentId?: string[], scope?: string[], branch?: string[], documentType?: string[], loadedDrive?: DocumentDriveDocument): Promise<SynchronizationUnit[]>;
271
+ getSynchronizationUnit(driveId: string, syncId: string, loadedDrive?: DocumentDriveDocument): Promise<SynchronizationUnit | undefined>;
272
+ getSynchronizationUnitsIds(driveId: string, documentId?: string[], scope?: string[], branch?: string[], documentType?: string[]): Promise<SynchronizationUnitQuery[]>;
273
+ getOperationData(driveId: string, syncId: string, filter: GetStrandsOptions, loadedDrive?: DocumentDriveDocument): Promise<OperationUpdate[]>;
275
274
  /** Internal methods **/
276
- protected abstract createDocument(drive: string, document: CreateDocumentInput): Promise<Document>;
277
- protected abstract deleteDocument(drive: string, id: string): Promise<void>;
278
- protected abstract getDocumentModel(documentType: string): DocumentModel;
279
- abstract getDocumentModels(): DocumentModel[];
280
- /** Event methods **/
281
- protected abstract emit<K extends keyof DriveEvents>(event: K, ...args: Parameters<DriveEvents[K]>): void;
282
- abstract on<K extends keyof DriveEvents>(event: K, cb: DriveEvents[K]): Unsubscribe;
283
- abstract getTransmitter(driveId: string, listenerId: string): Promise<ITransmitter | undefined>;
284
- abstract clearStorage(): Promise<void>;
285
- abstract registerPullResponderTrigger(id: string, url: string, options: Pick<RemoteDriveOptions, "pullFilter" | "pullInterval">): Promise<PullResponderTrigger>;
275
+ getDocumentModels(): DocumentModel[];
276
+ getTransmitter(driveId: string, listenerId: string): Promise<ITransmitter | undefined>;
277
+ clearStorage(): Promise<void>;
278
+ registerPullResponderTrigger(id: string, url: string, options: Pick<RemoteDriveOptions, "pullFilter" | "pullInterval">): Promise<PullResponderTrigger>;
279
+ on<K extends keyof DriveEvents>(event: K, cb: DriveEvents[K]): Unsubscribe;
286
280
  }
287
- type PublicKeys<T> = {
288
- [K in keyof T]: T extends {
289
- [P in K]: T[K];
290
- } ? K : never;
291
- }[keyof T];
292
- type PublicPart<T> = Pick<T, PublicKeys<T>>;
293
- type IBaseDocumentDriveServer = PublicPart<AbstractDocumentDriveServer>;
294
281
  type IDocumentDriveServer = IBaseDocumentDriveServer & IDefaultDrivesManager & IReadModeDriveServer;
295
282
 
296
283
  type ProcessorUpdate<D extends Document = Document, S extends OperationScope = OperationScope> = InternalTransmitterUpdate<D, S>;
package/dist/index.js CHANGED
@@ -25926,6 +25926,55 @@ index.documentHelpers;
25926
25926
 
25927
25927
  // ../document-drive/src/server/listener/transmitter/switchboard-push.ts
25928
25928
  __toESM(require_lib4());
25929
+
25930
+ // src/sync/utils.ts
25931
+ var processPushUpdate = async (reactor, strand) => {
25932
+ const result = await (strand.documentId !== undefined ? reactor.queueOperations(
25933
+ strand.driveId,
25934
+ strand.documentId,
25935
+ strand.operations
25936
+ ) : reactor.queueDriveOperations(
25937
+ strand.driveId,
25938
+ strand.operations
25939
+ ));
25940
+ const scopeOperations = result.document?.operations[strand.scope] ?? [];
25941
+ if (scopeOperations.length === 0) {
25942
+ return {
25943
+ revision: -1,
25944
+ branch: strand.branch,
25945
+ documentId: strand.documentId ?? "",
25946
+ driveId: strand.driveId,
25947
+ scope: strand.scope,
25948
+ status: result.status
25949
+ };
25950
+ }
25951
+ const revision = scopeOperations.slice().pop()?.index ?? -1;
25952
+ return {
25953
+ revision,
25954
+ branch: strand.branch,
25955
+ documentId: strand.documentId ?? "",
25956
+ driveId: strand.driveId,
25957
+ scope: strand.scope,
25958
+ status: result.status,
25959
+ error: result.error?.message || undefined
25960
+ };
25961
+ };
25962
+ var processAcknowledge = async (reactor, driveId, listenerId, revisions) => {
25963
+ const transmitter = await reactor.getTransmitter(
25964
+ driveId,
25965
+ listenerId
25966
+ );
25967
+ return transmitter.processAcknowledge(driveId, listenerId, revisions);
25968
+ };
25969
+ var processGetStrands = async (reactor, driveId, listenerId, since) => {
25970
+ const transmitter = await reactor.getTransmitter(
25971
+ driveId,
25972
+ listenerId
25973
+ );
25974
+ return transmitter.getStrands({ since });
25975
+ };
25976
+
25977
+ // src/subgraphs/drive/index.ts
25929
25978
  var DriveSubgraph = class extends Subgraph {
25930
25979
  name = "d/:drive";
25931
25980
  typeDefs = gql`
@@ -26159,49 +26208,26 @@ var DriveSubgraph = class extends Subgraph {
26159
26208
  }
26160
26209
  return listener;
26161
26210
  },
26162
- pushUpdates: async (_, { strands }, ctx) => {
26211
+ pushUpdates: async (_, { strands: strandsGql }, ctx) => {
26163
26212
  if (!ctx.driveId) throw new Error("Drive ID is required");
26164
- const listenerRevisions = await Promise.all(
26165
- strands.map(async (s2) => {
26166
- const operations = s2.operations.map((o) => ({
26167
- ...o,
26168
- input: JSON.parse(o.input),
26169
- skip: o.skip ?? 0,
26170
- scope: s2.scope,
26213
+ const strands = strandsGql.map((strandGql) => {
26214
+ return {
26215
+ operations: strandGql.operations.map((op) => ({
26216
+ ...op,
26217
+ input: JSON.parse(op.input),
26218
+ skip: op.skip ?? 0,
26219
+ scope: strandGql.scope,
26171
26220
  branch: "main"
26172
- })) ?? [];
26173
- const result = await (s2.documentId !== undefined ? this.reactor.queueOperations(
26174
- s2.driveId,
26175
- s2.documentId,
26176
- operations
26177
- ) : this.reactor.queueDriveOperations(
26178
- s2.driveId,
26179
- operations
26180
- ));
26181
- const scopeOperations = result.document?.operations[s2.scope] ?? [];
26182
- if (scopeOperations.length === 0) {
26183
- return {
26184
- revision: -1,
26185
- branch: s2.branch,
26186
- documentId: s2.documentId ?? "",
26187
- driveId: s2.driveId,
26188
- scope: s2.scope,
26189
- status: result.status
26190
- };
26191
- }
26192
- const revision = scopeOperations.slice().pop()?.index ?? -1;
26193
- return {
26194
- revision,
26195
- branch: s2.branch,
26196
- documentId: s2.documentId ?? "",
26197
- driveId: s2.driveId,
26198
- scope: s2.scope,
26199
- status: result.status,
26200
- error: result.error?.message || undefined
26201
- };
26202
- })
26221
+ })),
26222
+ documentId: strandGql.documentId,
26223
+ driveId: strandGql.driveId,
26224
+ scope: strandGql.scope,
26225
+ branch: strandGql.branch
26226
+ };
26227
+ });
26228
+ return await Promise.all(
26229
+ strands.map((strand) => processPushUpdate(this.reactor, strand))
26203
26230
  );
26204
- return listenerRevisions;
26205
26231
  },
26206
26232
  acknowledge: async (_, {
26207
26233
  listenerId,
@@ -26217,16 +26243,12 @@ var DriveSubgraph = class extends Subgraph {
26217
26243
  revision: e.revision,
26218
26244
  status: e.status
26219
26245
  }));
26220
- const transmitter = await this.reactor.getTransmitter(
26246
+ return await processAcknowledge(
26247
+ this.reactor,
26221
26248
  ctx.driveId,
26222
- listenerId
26223
- );
26224
- const result = await transmitter.processAcknowledge(
26225
- ctx.driveId ?? "1",
26226
26249
  listenerId,
26227
26250
  validEntries
26228
26251
  );
26229
- return result;
26230
26252
  }
26231
26253
  },
26232
26254
  System: {},
@@ -26236,26 +26258,27 @@ var DriveSubgraph = class extends Subgraph {
26236
26258
  since
26237
26259
  }, ctx) => {
26238
26260
  if (!ctx.driveId) throw new Error("Drive ID is required");
26239
- const listener = await this.reactor.getTransmitter(
26261
+ const strands = await processGetStrands(
26262
+ this.reactor,
26240
26263
  ctx.driveId,
26241
- listenerId
26264
+ listenerId,
26265
+ since
26242
26266
  );
26243
- const strands = await listener.getStrands({ since });
26244
- return strands.map((e) => ({
26245
- driveId: e.driveId,
26246
- documentId: e.documentId,
26247
- scope: e.scope,
26248
- branch: e.branch,
26249
- operations: e.operations.map((o) => ({
26250
- index: o.index,
26251
- skip: o.skip,
26252
- name: o.type,
26253
- input: JSON.stringify(o.input),
26254
- hash: o.hash,
26255
- timestamp: o.timestamp,
26256
- type: o.type,
26257
- context: o.context,
26258
- id: o.id
26267
+ return strands.map((update) => ({
26268
+ driveId: update.driveId,
26269
+ documentId: update.documentId,
26270
+ scope: update.scope,
26271
+ branch: update.branch,
26272
+ operations: update.operations.map((op) => ({
26273
+ index: op.index,
26274
+ skip: op.skip,
26275
+ name: op.type,
26276
+ input: JSON.stringify(op.input),
26277
+ hash: op.hash,
26278
+ timestamp: op.timestamp,
26279
+ type: op.type,
26280
+ context: op.context,
26281
+ id: op.id
26259
26282
  }))
26260
26283
  }));
26261
26284
  }