@powerhousedao/connect 6.0.0-dev.77 → 6.0.0-dev.78

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.
@@ -4499,7 +4499,7 @@ var init_package = __esm(() => {
4499
4499
  package_default = {
4500
4500
  name: "@powerhousedao/connect",
4501
4501
  productName: "Powerhouse-Connect",
4502
- version: "6.0.0-dev.76",
4502
+ version: "6.0.0-dev.77",
4503
4503
  description: "Powerhouse Connect",
4504
4504
  main: "dist/index.html",
4505
4505
  type: "module",
@@ -13587,14 +13587,14 @@ class BaseReadModel {
13587
13587
  operationIndex;
13588
13588
  writeCache;
13589
13589
  consistencyTracker;
13590
- readModelId;
13590
+ config;
13591
13591
  lastOrdinal = 0;
13592
- constructor(db, operationIndex, writeCache, consistencyTracker, readModelId) {
13592
+ constructor(db, operationIndex, writeCache, consistencyTracker, config) {
13593
13593
  this.db = db;
13594
13594
  this.operationIndex = operationIndex;
13595
13595
  this.writeCache = writeCache;
13596
13596
  this.consistencyTracker = consistencyTracker;
13597
- this.readModelId = readModelId;
13597
+ this.config = config;
13598
13598
  }
13599
13599
  async init() {
13600
13600
  const viewState = await this.loadState();
@@ -13602,21 +13602,22 @@ class BaseReadModel {
13602
13602
  this.lastOrdinal = viewState;
13603
13603
  const missedOperations = await this.operationIndex.getSinceOrdinal(this.lastOrdinal);
13604
13604
  if (missedOperations.results.length > 0) {
13605
- const opsWithState = await this.rebuildStateForOperations(missedOperations.results);
13606
- await this.indexOperations(opsWithState);
13605
+ const ops = this.config.rebuildStateOnInit ? await this.rebuildStateForOperations(missedOperations.results) : missedOperations.results;
13606
+ await this.indexOperations(ops);
13607
13607
  }
13608
13608
  } else {
13609
13609
  await this.initializeState();
13610
13610
  const allOperations = await this.operationIndex.getSinceOrdinal(0);
13611
13611
  if (allOperations.results.length > 0) {
13612
- const opsWithState = await this.rebuildStateForOperations(allOperations.results);
13613
- await this.indexOperations(opsWithState);
13612
+ const ops = this.config.rebuildStateOnInit ? await this.rebuildStateForOperations(allOperations.results) : allOperations.results;
13613
+ await this.indexOperations(ops);
13614
13614
  }
13615
13615
  }
13616
13616
  }
13617
13617
  async indexOperations(items) {
13618
13618
  if (items.length === 0)
13619
13619
  return;
13620
+ await this.commitOperations(items);
13620
13621
  await this.db.transaction().execute(async (trx) => {
13621
13622
  await this.saveState(trx, items);
13622
13623
  });
@@ -13628,6 +13629,7 @@ class BaseReadModel {
13628
13629
  }
13629
13630
  await this.consistencyTracker.waitFor(token.coordinates, timeoutMs, signal);
13630
13631
  }
13632
+ async commitOperations(items) {}
13631
13633
  async rebuildStateForOperations(operations) {
13632
13634
  const result = [];
13633
13635
  for (const op of operations) {
@@ -13646,13 +13648,13 @@ class BaseReadModel {
13646
13648
  }
13647
13649
  async loadState() {
13648
13650
  const viewStateDb = this.db;
13649
- const row = await viewStateDb.selectFrom("ViewState").select("lastOrdinal").where("readModelId", "=", this.readModelId).executeTakeFirst();
13651
+ const row = await viewStateDb.selectFrom("ViewState").select("lastOrdinal").where("readModelId", "=", this.config.readModelId).executeTakeFirst();
13650
13652
  return row?.lastOrdinal;
13651
13653
  }
13652
13654
  async initializeState() {
13653
13655
  const viewStateDb = this.db;
13654
13656
  await viewStateDb.insertInto("ViewState").values({
13655
- readModelId: this.readModelId,
13657
+ readModelId: this.config.readModelId,
13656
13658
  lastOrdinal: 0
13657
13659
  }).execute();
13658
13660
  }
@@ -13662,7 +13664,7 @@ class BaseReadModel {
13662
13664
  await trx.updateTable("ViewState").set({
13663
13665
  lastOrdinal: maxOrdinal,
13664
13666
  lastOperationTimestamp: new Date
13665
- }).where("readModelId", "=", this.readModelId).execute();
13667
+ }).where("readModelId", "=", this.config.readModelId).execute();
13666
13668
  }
13667
13669
  updateConsistencyTracker(items) {
13668
13670
  const coordinates = [];
@@ -14387,6 +14389,661 @@ class ConsistencyTracker {
14387
14389
  }
14388
14390
  }
14389
14391
  }
14392
+ async function collectAllPages(firstPage, signal) {
14393
+ const allResults = [...firstPage.results];
14394
+ let currentPage = firstPage;
14395
+ while (currentPage.next) {
14396
+ if (signal?.aborted) {
14397
+ throw new Error("Operation aborted");
14398
+ }
14399
+ currentPage = await currentPage.next();
14400
+ allResults.push(...currentPage.results);
14401
+ }
14402
+ return allResults;
14403
+ }
14404
+
14405
+ class KyselyKeyframeStore {
14406
+ db;
14407
+ constructor(db) {
14408
+ this.db = db;
14409
+ }
14410
+ async putKeyframe(documentId, scope, branch, revision, document2, signal) {
14411
+ if (signal?.aborted) {
14412
+ throw new Error("Operation aborted");
14413
+ }
14414
+ await this.db.insertInto("Keyframe").values({
14415
+ documentId,
14416
+ documentType: document2.header.documentType,
14417
+ scope,
14418
+ branch,
14419
+ revision,
14420
+ document: document2
14421
+ }).onConflict((oc) => oc.columns(["documentId", "scope", "branch", "revision"]).doUpdateSet({ document: document2 })).execute();
14422
+ }
14423
+ async findNearestKeyframe(documentId, scope, branch, targetRevision, signal) {
14424
+ if (signal?.aborted) {
14425
+ throw new Error("Operation aborted");
14426
+ }
14427
+ const row = await this.db.selectFrom("Keyframe").selectAll().where("documentId", "=", documentId).where("scope", "=", scope).where("branch", "=", branch).where("revision", "<=", targetRevision).orderBy("revision", "desc").limit(1).executeTakeFirst();
14428
+ if (!row) {
14429
+ return;
14430
+ }
14431
+ return {
14432
+ revision: row.revision,
14433
+ document: row.document
14434
+ };
14435
+ }
14436
+ async deleteKeyframes(documentId, scope, branch, signal) {
14437
+ if (signal?.aborted) {
14438
+ throw new Error("Operation aborted");
14439
+ }
14440
+ let query = this.db.deleteFrom("Keyframe").where("documentId", "=", documentId);
14441
+ if (scope !== undefined && branch !== undefined) {
14442
+ query = query.where("scope", "=", scope).where("branch", "=", branch);
14443
+ } else if (scope !== undefined) {
14444
+ query = query.where("scope", "=", scope);
14445
+ }
14446
+ const result = await query.executeTakeFirst();
14447
+ return Number(result.numDeletedRows || 0n);
14448
+ }
14449
+ }
14450
+
14451
+ class AtomicTransaction {
14452
+ documentId;
14453
+ documentType;
14454
+ scope;
14455
+ branch;
14456
+ baseRevision;
14457
+ operations = [];
14458
+ constructor(documentId, documentType, scope, branch, baseRevision) {
14459
+ this.documentId = documentId;
14460
+ this.documentType = documentType;
14461
+ this.scope = scope;
14462
+ this.branch = branch;
14463
+ this.baseRevision = baseRevision;
14464
+ }
14465
+ addOperations(...operations) {
14466
+ for (const op of operations) {
14467
+ this.operations.push({
14468
+ jobId: v4_default(),
14469
+ opId: op.id,
14470
+ prevOpId: "",
14471
+ documentId: this.documentId,
14472
+ documentType: this.documentType,
14473
+ scope: this.scope,
14474
+ branch: this.branch,
14475
+ timestampUtcMs: new Date(op.timestampUtcMs),
14476
+ index: op.index,
14477
+ action: JSON.stringify(op.action),
14478
+ skip: op.skip,
14479
+ error: op.error || null,
14480
+ hash: op.hash
14481
+ });
14482
+ }
14483
+ }
14484
+ getOperations() {
14485
+ return this.operations;
14486
+ }
14487
+ }
14488
+
14489
+ class KyselyOperationStore {
14490
+ db;
14491
+ constructor(db) {
14492
+ this.db = db;
14493
+ }
14494
+ async apply(documentId, documentType, scope, branch, revision, fn, signal) {
14495
+ await this.db.transaction().execute(async (trx) => {
14496
+ if (signal?.aborted) {
14497
+ throw new Error("Operation aborted");
14498
+ }
14499
+ const latestOp = await trx.selectFrom("Operation").selectAll().where("documentId", "=", documentId).where("scope", "=", scope).where("branch", "=", branch).orderBy("index", "desc").limit(1).executeTakeFirst();
14500
+ const currentRevision = latestOp ? latestOp.index : -1;
14501
+ if (currentRevision !== revision - 1) {
14502
+ throw new RevisionMismatchError(currentRevision + 1, revision);
14503
+ }
14504
+ const atomicTxn = new AtomicTransaction(documentId, documentType, scope, branch, revision);
14505
+ await fn(atomicTxn);
14506
+ const operations = atomicTxn.getOperations();
14507
+ if (operations.length > 0) {
14508
+ let prevOpId = latestOp?.opId || "";
14509
+ for (const op of operations) {
14510
+ op.prevOpId = prevOpId;
14511
+ prevOpId = op.opId;
14512
+ }
14513
+ try {
14514
+ await trx.insertInto("Operation").values(operations).execute();
14515
+ } catch (error) {
14516
+ if (error instanceof Error) {
14517
+ if (error.message.includes("unique constraint")) {
14518
+ const op = operations[0];
14519
+ throw new DuplicateOperationError(`${op.opId} at index ${op.index} with skip ${op.skip}`);
14520
+ }
14521
+ throw error;
14522
+ }
14523
+ throw error;
14524
+ }
14525
+ }
14526
+ });
14527
+ }
14528
+ async getSince(documentId, scope, branch, revision, filter, paging, signal) {
14529
+ if (signal?.aborted) {
14530
+ throw new Error("Operation aborted");
14531
+ }
14532
+ let query = this.db.selectFrom("Operation").selectAll().where("documentId", "=", documentId).where("scope", "=", scope).where("branch", "=", branch).where("index", ">", revision).orderBy("index", "asc");
14533
+ if (filter) {
14534
+ if (filter.actionTypes && filter.actionTypes.length > 0) {
14535
+ const actionTypesArray = filter.actionTypes.map((t) => `'${t.replace(/'/g, "''")}'`).join(",");
14536
+ query = query.where(sql`action->>'type' = ANY(ARRAY[${sql.raw(actionTypesArray)}]::text[])`);
14537
+ }
14538
+ if (filter.timestampFrom) {
14539
+ query = query.where("timestampUtcMs", ">=", new Date(filter.timestampFrom));
14540
+ }
14541
+ if (filter.timestampTo) {
14542
+ query = query.where("timestampUtcMs", "<=", new Date(filter.timestampTo));
14543
+ }
14544
+ if (filter.sinceRevision !== undefined) {
14545
+ query = query.where("index", ">=", filter.sinceRevision);
14546
+ }
14547
+ }
14548
+ if (paging) {
14549
+ const cursorValue = Number.parseInt(paging.cursor, 10);
14550
+ if (cursorValue > 0) {
14551
+ query = query.where("index", ">", cursorValue);
14552
+ }
14553
+ if (paging.limit) {
14554
+ query = query.limit(paging.limit + 1);
14555
+ }
14556
+ }
14557
+ const rows = await query.execute();
14558
+ let hasMore = false;
14559
+ let items = rows;
14560
+ if (paging?.limit && rows.length > paging.limit) {
14561
+ hasMore = true;
14562
+ items = rows.slice(0, paging.limit);
14563
+ }
14564
+ const nextCursor = hasMore && items.length > 0 ? items[items.length - 1].index.toString() : undefined;
14565
+ const cursor = paging?.cursor || "0";
14566
+ const limit = paging?.limit || 100;
14567
+ const operations = items.map((row) => this.rowToOperation(row));
14568
+ return {
14569
+ results: operations,
14570
+ options: { cursor, limit },
14571
+ nextCursor,
14572
+ next: hasMore ? () => this.getSince(documentId, scope, branch, revision, filter, { cursor: nextCursor, limit }, signal) : undefined
14573
+ };
14574
+ }
14575
+ async getSinceId(id, paging, signal) {
14576
+ if (signal?.aborted) {
14577
+ throw new Error("Operation aborted");
14578
+ }
14579
+ let query = this.db.selectFrom("Operation").selectAll().where("id", ">", id).orderBy("id", "asc");
14580
+ if (paging) {
14581
+ const cursorValue = Number.parseInt(paging.cursor, 10);
14582
+ if (cursorValue > 0) {
14583
+ query = query.where("id", ">", cursorValue);
14584
+ }
14585
+ if (paging.limit) {
14586
+ query = query.limit(paging.limit + 1);
14587
+ }
14588
+ }
14589
+ const rows = await query.execute();
14590
+ let hasMore = false;
14591
+ let items = rows;
14592
+ if (paging?.limit && rows.length > paging.limit) {
14593
+ hasMore = true;
14594
+ items = rows.slice(0, paging.limit);
14595
+ }
14596
+ const nextCursor = hasMore && items.length > 0 ? items[items.length - 1].id.toString() : undefined;
14597
+ const cursor = paging?.cursor || "0";
14598
+ const limit = paging?.limit || 100;
14599
+ const operations = items.map((row) => this.rowToOperationWithContext(row));
14600
+ return {
14601
+ results: operations,
14602
+ options: { cursor, limit },
14603
+ nextCursor,
14604
+ next: hasMore ? () => this.getSinceId(id, { cursor: nextCursor, limit }, signal) : undefined
14605
+ };
14606
+ }
14607
+ async getConflicting(documentId, scope, branch, minTimestamp, paging, signal) {
14608
+ if (signal?.aborted) {
14609
+ throw new Error("Operation aborted");
14610
+ }
14611
+ let query = this.db.selectFrom("Operation").selectAll().where("documentId", "=", documentId).where("scope", "=", scope).where("branch", "=", branch).where("timestampUtcMs", ">=", new Date(minTimestamp)).orderBy("index", "asc");
14612
+ if (paging) {
14613
+ const cursorValue = Number.parseInt(paging.cursor, 10);
14614
+ if (cursorValue > 0) {
14615
+ query = query.where("index", ">", cursorValue);
14616
+ }
14617
+ if (paging.limit) {
14618
+ query = query.limit(paging.limit + 1);
14619
+ }
14620
+ }
14621
+ const rows = await query.execute();
14622
+ let hasMore = false;
14623
+ let items = rows;
14624
+ if (paging?.limit && rows.length > paging.limit) {
14625
+ hasMore = true;
14626
+ items = rows.slice(0, paging.limit);
14627
+ }
14628
+ const nextCursor = hasMore && items.length > 0 ? items[items.length - 1].index.toString() : undefined;
14629
+ const cursor = paging?.cursor || "0";
14630
+ const limit = paging?.limit || 100;
14631
+ const operations = items.map((row) => this.rowToOperation(row));
14632
+ return {
14633
+ results: operations,
14634
+ options: { cursor, limit },
14635
+ nextCursor,
14636
+ next: hasMore ? () => this.getConflicting(documentId, scope, branch, minTimestamp, { cursor: nextCursor, limit }, signal) : undefined
14637
+ };
14638
+ }
14639
+ async getRevisions(documentId, branch, signal) {
14640
+ if (signal?.aborted) {
14641
+ throw new Error("Operation aborted");
14642
+ }
14643
+ const scopeRevisions = await this.db.selectFrom("Operation as o1").select(["o1.scope", "o1.index", "o1.timestampUtcMs"]).where("o1.documentId", "=", documentId).where("o1.branch", "=", branch).where((eb) => eb("o1.index", "=", eb.selectFrom("Operation as o2").select((eb2) => eb2.fn.max("o2.index").as("maxIndex")).where("o2.documentId", "=", eb.ref("o1.documentId")).where("o2.branch", "=", eb.ref("o1.branch")).where("o2.scope", "=", eb.ref("o1.scope")))).execute();
14644
+ const revision = {};
14645
+ let latestTimestamp = new Date(0).toISOString();
14646
+ for (const row of scopeRevisions) {
14647
+ revision[row.scope] = row.index + 1;
14648
+ const timestamp = row.timestampUtcMs.toISOString();
14649
+ if (timestamp > latestTimestamp) {
14650
+ latestTimestamp = timestamp;
14651
+ }
14652
+ }
14653
+ return {
14654
+ revision,
14655
+ latestTimestamp
14656
+ };
14657
+ }
14658
+ rowToOperation(row) {
14659
+ return {
14660
+ index: row.index,
14661
+ timestampUtcMs: row.timestampUtcMs.toISOString(),
14662
+ hash: row.hash,
14663
+ skip: row.skip,
14664
+ error: row.error || undefined,
14665
+ id: row.opId,
14666
+ action: row.action
14667
+ };
14668
+ }
14669
+ rowToOperationWithContext(row) {
14670
+ return {
14671
+ operation: this.rowToOperation(row),
14672
+ context: {
14673
+ documentId: row.documentId,
14674
+ documentType: row.documentType,
14675
+ scope: row.scope,
14676
+ branch: row.branch,
14677
+ ordinal: row.id
14678
+ }
14679
+ };
14680
+ }
14681
+ }
14682
+ async function up(db) {
14683
+ await db.schema.createTable("Operation").addColumn("id", "serial", (col) => col.primaryKey()).addColumn("jobId", "text", (col) => col.notNull()).addColumn("opId", "text", (col) => col.notNull()).addColumn("prevOpId", "text", (col) => col.notNull()).addColumn("writeTimestampUtcMs", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn("documentId", "text", (col) => col.notNull()).addColumn("documentType", "text", (col) => col.notNull()).addColumn("scope", "text", (col) => col.notNull()).addColumn("branch", "text", (col) => col.notNull()).addColumn("timestampUtcMs", "timestamptz", (col) => col.notNull()).addColumn("index", "integer", (col) => col.notNull()).addColumn("action", "jsonb", (col) => col.notNull()).addColumn("skip", "integer", (col) => col.notNull()).addColumn("error", "text").addColumn("hash", "text", (col) => col.notNull()).addUniqueConstraint("unique_revision", [
14684
+ "documentId",
14685
+ "scope",
14686
+ "branch",
14687
+ "index"
14688
+ ]).addUniqueConstraint("unique_operation_instance", ["opId", "index", "skip"]).execute();
14689
+ await db.schema.createIndex("streamOperations").on("Operation").columns(["documentId", "scope", "branch", "id"]).execute();
14690
+ await db.schema.createIndex("branchlessStreamOperations").on("Operation").columns(["documentId", "scope", "id"]).execute();
14691
+ }
14692
+ async function up2(db) {
14693
+ await db.schema.createTable("Keyframe").addColumn("id", "serial", (col) => col.primaryKey()).addColumn("documentId", "text", (col) => col.notNull()).addColumn("documentType", "text", (col) => col.notNull()).addColumn("scope", "text", (col) => col.notNull()).addColumn("branch", "text", (col) => col.notNull()).addColumn("revision", "integer", (col) => col.notNull()).addColumn("document", "jsonb", (col) => col.notNull()).addColumn("createdAt", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).addUniqueConstraint("unique_keyframe", [
14694
+ "documentId",
14695
+ "scope",
14696
+ "branch",
14697
+ "revision"
14698
+ ]).execute();
14699
+ await db.schema.createIndex("keyframe_lookup").on("Keyframe").columns(["documentId", "scope", "branch", "revision"]).execute();
14700
+ }
14701
+ async function up3(db) {
14702
+ await db.schema.createTable("Document").addColumn("id", "text", (col) => col.primaryKey()).addColumn("createdAt", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn("updatedAt", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();
14703
+ }
14704
+ async function up4(db) {
14705
+ await db.schema.createTable("DocumentRelationship").addColumn("id", "text", (col) => col.primaryKey()).addColumn("sourceId", "text", (col) => col.notNull().references("Document.id").onDelete("cascade")).addColumn("targetId", "text", (col) => col.notNull().references("Document.id").onDelete("cascade")).addColumn("relationshipType", "text", (col) => col.notNull()).addColumn("metadata", "jsonb").addColumn("createdAt", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn("updatedAt", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).addUniqueConstraint("unique_source_target_type", [
14706
+ "sourceId",
14707
+ "targetId",
14708
+ "relationshipType"
14709
+ ]).execute();
14710
+ await db.schema.createIndex("idx_relationship_source").on("DocumentRelationship").column("sourceId").execute();
14711
+ await db.schema.createIndex("idx_relationship_target").on("DocumentRelationship").column("targetId").execute();
14712
+ await db.schema.createIndex("idx_relationship_type").on("DocumentRelationship").column("relationshipType").execute();
14713
+ }
14714
+ async function up5(db) {
14715
+ await db.schema.createTable("IndexerState").addColumn("id", "integer", (col) => col.primaryKey().generatedAlwaysAsIdentity()).addColumn("lastOperationId", "integer", (col) => col.notNull()).addColumn("lastOperationTimestamp", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();
14716
+ }
14717
+ async function up6(db) {
14718
+ await db.schema.createTable("DocumentSnapshot").addColumn("id", "text", (col) => col.primaryKey()).addColumn("documentId", "text", (col) => col.notNull()).addColumn("slug", "text").addColumn("name", "text").addColumn("scope", "text", (col) => col.notNull()).addColumn("branch", "text", (col) => col.notNull()).addColumn("content", "jsonb", (col) => col.notNull()).addColumn("documentType", "text", (col) => col.notNull()).addColumn("lastOperationIndex", "integer", (col) => col.notNull()).addColumn("lastOperationHash", "text", (col) => col.notNull()).addColumn("lastUpdatedAt", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn("snapshotVersion", "integer", (col) => col.notNull().defaultTo(1)).addColumn("identifiers", "jsonb").addColumn("metadata", "jsonb").addColumn("isDeleted", "boolean", (col) => col.notNull().defaultTo(false)).addColumn("deletedAt", "timestamptz").addUniqueConstraint("unique_doc_scope_branch", [
14719
+ "documentId",
14720
+ "scope",
14721
+ "branch"
14722
+ ]).execute();
14723
+ await db.schema.createIndex("idx_slug_scope_branch").on("DocumentSnapshot").columns(["slug", "scope", "branch"]).execute();
14724
+ await db.schema.createIndex("idx_doctype_scope_branch").on("DocumentSnapshot").columns(["documentType", "scope", "branch"]).execute();
14725
+ await db.schema.createIndex("idx_last_updated").on("DocumentSnapshot").column("lastUpdatedAt").execute();
14726
+ await db.schema.createIndex("idx_is_deleted").on("DocumentSnapshot").column("isDeleted").execute();
14727
+ }
14728
+ async function up7(db) {
14729
+ await db.schema.createTable("SlugMapping").addColumn("slug", "text", (col) => col.primaryKey()).addColumn("documentId", "text", (col) => col.notNull()).addColumn("scope", "text", (col) => col.notNull()).addColumn("branch", "text", (col) => col.notNull()).addColumn("createdAt", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn("updatedAt", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).addUniqueConstraint("unique_docid_scope_branch", [
14730
+ "documentId",
14731
+ "scope",
14732
+ "branch"
14733
+ ]).execute();
14734
+ await db.schema.createIndex("idx_slug_documentid").on("SlugMapping").column("documentId").execute();
14735
+ }
14736
+ async function up8(db) {
14737
+ await db.schema.createTable("ViewState").addColumn("readModelId", "text", (col) => col.primaryKey()).addColumn("lastOrdinal", "integer", (col) => col.notNull().defaultTo(0)).addColumn("lastOperationTimestamp", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();
14738
+ }
14739
+ async function up9(db) {
14740
+ await db.schema.createTable("document_collections").addColumn("documentId", "text", (col) => col.notNull()).addColumn("collectionId", "text", (col) => col.notNull()).addColumn("joinedOrdinal", "bigint", (col) => col.notNull().defaultTo(0)).addColumn("leftOrdinal", "bigint").addPrimaryKeyConstraint("document_collections_pkey", [
14741
+ "documentId",
14742
+ "collectionId"
14743
+ ]).execute();
14744
+ await db.schema.createIndex("idx_document_collections_collectionId").on("document_collections").column("collectionId").execute();
14745
+ await db.schema.createIndex("idx_doc_collections_collection_range").on("document_collections").columns(["collectionId", "joinedOrdinal"]).execute();
14746
+ await db.schema.createTable("operation_index_operations").addColumn("ordinal", "serial", (col) => col.primaryKey()).addColumn("opId", "text", (col) => col.notNull()).addColumn("documentId", "text", (col) => col.notNull()).addColumn("documentType", "text", (col) => col.notNull()).addColumn("scope", "text", (col) => col.notNull()).addColumn("branch", "text", (col) => col.notNull()).addColumn("timestampUtcMs", "text", (col) => col.notNull()).addColumn("writeTimestampUtcMs", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn("index", "integer", (col) => col.notNull()).addColumn("skip", "integer", (col) => col.notNull()).addColumn("hash", "text", (col) => col.notNull()).addColumn("action", "jsonb", (col) => col.notNull()).execute();
14747
+ await db.schema.createIndex("idx_operation_index_operations_document").on("operation_index_operations").columns(["documentId", "branch", "scope"]).execute();
14748
+ await db.schema.createIndex("idx_operation_index_operations_ordinal").on("operation_index_operations").column("ordinal").execute();
14749
+ }
14750
+ async function up10(db) {
14751
+ await db.schema.createTable("sync_remotes").addColumn("name", "text", (col) => col.primaryKey()).addColumn("collection_id", "text", (col) => col.notNull()).addColumn("channel_type", "text", (col) => col.notNull()).addColumn("channel_id", "text", (col) => col.notNull().defaultTo("")).addColumn("remote_name", "text", (col) => col.notNull().defaultTo("")).addColumn("channel_parameters", "jsonb", (col) => col.notNull().defaultTo(sql`'{}'::jsonb`)).addColumn("filter_document_ids", "jsonb").addColumn("filter_scopes", "jsonb").addColumn("filter_branch", "text", (col) => col.notNull().defaultTo("main")).addColumn("push_state", "text", (col) => col.notNull().defaultTo("idle")).addColumn("push_last_success_utc_ms", "text").addColumn("push_last_failure_utc_ms", "text").addColumn("push_failure_count", "integer", (col) => col.notNull().defaultTo(0)).addColumn("pull_state", "text", (col) => col.notNull().defaultTo("idle")).addColumn("pull_last_success_utc_ms", "text").addColumn("pull_last_failure_utc_ms", "text").addColumn("pull_failure_count", "integer", (col) => col.notNull().defaultTo(0)).addColumn("created_at", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn("updated_at", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();
14752
+ await db.schema.createIndex("idx_sync_remotes_collection").on("sync_remotes").column("collection_id").execute();
14753
+ await db.schema.createTable("sync_cursors").addColumn("remote_name", "text", (col) => col.primaryKey().references("sync_remotes.name").onDelete("cascade")).addColumn("cursor_ordinal", "bigint", (col) => col.notNull().defaultTo(0)).addColumn("last_synced_at_utc_ms", "text").addColumn("updated_at", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();
14754
+ await db.schema.createIndex("idx_sync_cursors_ordinal").on("sync_cursors").column("cursor_ordinal").execute();
14755
+ }
14756
+ async function up11(db) {
14757
+ await db.deleteFrom("sync_cursors").where("remote_name", "like", "outbox::%").execute();
14758
+ await db.deleteFrom("sync_remotes").where("name", "like", "outbox::%").execute();
14759
+ await db.schema.dropTable("sync_cursors").execute();
14760
+ await db.schema.createTable("sync_cursors").addColumn("remote_name", "text", (col) => col.notNull()).addColumn("cursor_type", "text", (col) => col.notNull().defaultTo("inbox")).addColumn("cursor_ordinal", "bigint", (col) => col.notNull().defaultTo(0)).addColumn("last_synced_at_utc_ms", "text").addColumn("updated_at", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).addPrimaryKeyConstraint("sync_cursors_pk", ["remote_name", "cursor_type"]).execute();
14761
+ await db.schema.createIndex("idx_sync_cursors_ordinal").on("sync_cursors").column("cursor_ordinal").execute();
14762
+ }
14763
+ async function up12(db) {
14764
+ await db.schema.alterTable("operation_index_operations").addColumn("sourceRemote", "text", (col) => col.notNull().defaultTo("")).execute();
14765
+ }
14766
+ async function up13(db) {
14767
+ await db.schema.createTable("sync_dead_letters").addColumn("ordinal", "serial", (col) => col.primaryKey()).addColumn("id", "text", (col) => col.unique().notNull()).addColumn("job_id", "text", (col) => col.notNull()).addColumn("job_dependencies", "jsonb", (col) => col.notNull().defaultTo(sql`'[]'::jsonb`)).addColumn("remote_name", "text", (col) => col.notNull().references("sync_remotes.name").onDelete("cascade")).addColumn("document_id", "text", (col) => col.notNull()).addColumn("scopes", "jsonb", (col) => col.notNull().defaultTo(sql`'[]'::jsonb`)).addColumn("branch", "text", (col) => col.notNull()).addColumn("operations", "jsonb", (col) => col.notNull().defaultTo(sql`'[]'::jsonb`)).addColumn("error_source", "text", (col) => col.notNull()).addColumn("error_message", "text", (col) => col.notNull()).addColumn("created_at", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();
14768
+ await db.schema.createIndex("idx_sync_dead_letters_remote").on("sync_dead_letters").column("remote_name").execute();
14769
+ }
14770
+ async function up14(db) {
14771
+ await db.schema.createTable("ProcessorCursor").addColumn("processorId", "text", (col) => col.primaryKey()).addColumn("factoryId", "text", (col) => col.notNull()).addColumn("driveId", "text", (col) => col.notNull()).addColumn("processorIndex", "integer", (col) => col.notNull()).addColumn("lastOrdinal", "integer", (col) => col.notNull().defaultTo(sql`0`)).addColumn("status", "text", (col) => col.notNull().defaultTo(sql`'active'`)).addColumn("lastError", "text").addColumn("lastErrorTimestamp", "timestamptz").addColumn("createdAt", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn("updatedAt", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();
14772
+ }
14773
+
14774
+ class ProgrammaticMigrationProvider {
14775
+ getMigrations() {
14776
+ return Promise.resolve(migrations);
14777
+ }
14778
+ }
14779
+ async function runMigrations(db, schema = REACTOR_SCHEMA) {
14780
+ try {
14781
+ await sql`CREATE SCHEMA IF NOT EXISTS ${sql.id(schema)}`.execute(db);
14782
+ } catch (error2) {
14783
+ return {
14784
+ success: false,
14785
+ migrationsExecuted: [],
14786
+ error: error2 instanceof Error ? error2 : new Error("Failed to create schema")
14787
+ };
14788
+ }
14789
+ const migrator = new Migrator({
14790
+ db: db.withSchema(schema),
14791
+ provider: new ProgrammaticMigrationProvider,
14792
+ migrationTableSchema: schema
14793
+ });
14794
+ let error;
14795
+ let results;
14796
+ try {
14797
+ const result = await migrator.migrateToLatest();
14798
+ error = result.error;
14799
+ results = result.results;
14800
+ } catch (e) {
14801
+ error = e;
14802
+ results = [];
14803
+ }
14804
+ const migrationsExecuted = results?.map((result) => result.migrationName) ?? [];
14805
+ if (error) {
14806
+ return {
14807
+ success: false,
14808
+ migrationsExecuted,
14809
+ error: error instanceof Error ? error : new Error("Unknown migration error")
14810
+ };
14811
+ }
14812
+ return {
14813
+ success: true,
14814
+ migrationsExecuted
14815
+ };
14816
+ }
14817
+
14818
+ class DefaultSubscriptionErrorHandler {
14819
+ handleError(error, context) {
14820
+ const errorMessage = `Subscription error in ${context.eventType} (${context.subscriptionId})`;
14821
+ if (error instanceof Error) {
14822
+ const enhancedError = new Error(`${errorMessage}: ${error.message}`);
14823
+ enhancedError.cause = error;
14824
+ enhancedError.stack = error.stack;
14825
+ throw enhancedError;
14826
+ } else {
14827
+ throw new Error(`${errorMessage}: ${String(error)}`);
14828
+ }
14829
+ }
14830
+ }
14831
+
14832
+ class ReactorSubscriptionManager {
14833
+ createdSubscriptions = new Map;
14834
+ deletedSubscriptions = new Map;
14835
+ updatedSubscriptions = new Map;
14836
+ relationshipSubscriptions = new Map;
14837
+ subscriptionCounter = 0;
14838
+ errorHandler;
14839
+ constructor(errorHandler) {
14840
+ this.errorHandler = errorHandler;
14841
+ }
14842
+ onDocumentCreated(callback, search) {
14843
+ const id = `created-${++this.subscriptionCounter}`;
14844
+ this.createdSubscriptions.set(id, { id, callback, search });
14845
+ return () => {
14846
+ this.createdSubscriptions.delete(id);
14847
+ };
14848
+ }
14849
+ onDocumentDeleted(callback, search) {
14850
+ const id = `deleted-${++this.subscriptionCounter}`;
14851
+ this.deletedSubscriptions.set(id, { id, callback, search });
14852
+ return () => {
14853
+ this.deletedSubscriptions.delete(id);
14854
+ };
14855
+ }
14856
+ onDocumentStateUpdated(callback, search, view) {
14857
+ const id = `updated-${++this.subscriptionCounter}`;
14858
+ this.updatedSubscriptions.set(id, { id, callback, search, view });
14859
+ return () => {
14860
+ this.updatedSubscriptions.delete(id);
14861
+ };
14862
+ }
14863
+ onRelationshipChanged(callback, search) {
14864
+ const id = `relationship-${++this.subscriptionCounter}`;
14865
+ this.relationshipSubscriptions.set(id, { id, callback, search });
14866
+ return () => {
14867
+ this.relationshipSubscriptions.delete(id);
14868
+ };
14869
+ }
14870
+ notifyDocumentsCreated(documentIds, documentTypes, parentIds) {
14871
+ const result = {
14872
+ results: documentIds,
14873
+ options: { cursor: "", limit: documentIds.length }
14874
+ };
14875
+ for (const subscription of this.createdSubscriptions.values()) {
14876
+ const filteredIds = this.filterDocumentIds(documentIds, subscription.search, documentTypes, parentIds);
14877
+ if (filteredIds.length > 0) {
14878
+ try {
14879
+ subscription.callback({
14880
+ ...result,
14881
+ results: filteredIds
14882
+ });
14883
+ } catch (error) {
14884
+ this.errorHandler.handleError(error, {
14885
+ eventType: "created",
14886
+ subscriptionId: subscription.id,
14887
+ eventData: filteredIds
14888
+ });
14889
+ }
14890
+ }
14891
+ }
14892
+ }
14893
+ notifyDocumentsDeleted(documentIds, documentTypes, parentIds) {
14894
+ for (const subscription of this.deletedSubscriptions.values()) {
14895
+ const filteredIds = this.filterDocumentIds(documentIds, subscription.search, documentTypes, parentIds);
14896
+ if (filteredIds.length > 0) {
14897
+ try {
14898
+ subscription.callback(filteredIds);
14899
+ } catch (error) {
14900
+ this.errorHandler.handleError(error, {
14901
+ eventType: "deleted",
14902
+ subscriptionId: subscription.id,
14903
+ eventData: filteredIds
14904
+ });
14905
+ }
14906
+ }
14907
+ }
14908
+ }
14909
+ notifyDocumentsUpdated(documents) {
14910
+ const result = {
14911
+ results: documents,
14912
+ options: { cursor: "", limit: documents.length }
14913
+ };
14914
+ for (const subscription of this.updatedSubscriptions.values()) {
14915
+ const filteredDocs = this.filterDocuments(documents, subscription.search);
14916
+ if (filteredDocs.length > 0) {
14917
+ try {
14918
+ subscription.callback({
14919
+ ...result,
14920
+ results: filteredDocs
14921
+ });
14922
+ } catch (error) {
14923
+ this.errorHandler.handleError(error, {
14924
+ eventType: "updated",
14925
+ subscriptionId: subscription.id,
14926
+ eventData: filteredDocs
14927
+ });
14928
+ }
14929
+ }
14930
+ }
14931
+ }
14932
+ notifyRelationshipChanged(parentId, childId, changeType, childType) {
14933
+ for (const subscription of this.relationshipSubscriptions.values()) {
14934
+ if (this.matchesRelationshipFilter(parentId, childId, childType, subscription.search)) {
14935
+ try {
14936
+ subscription.callback(parentId, childId, changeType);
14937
+ } catch (error) {
14938
+ this.errorHandler.handleError(error, {
14939
+ eventType: "relationshipChanged",
14940
+ subscriptionId: subscription.id,
14941
+ eventData: { parentId, childId, changeType }
14942
+ });
14943
+ }
14944
+ }
14945
+ }
14946
+ }
14947
+ clearAll() {
14948
+ this.createdSubscriptions.clear();
14949
+ this.deletedSubscriptions.clear();
14950
+ this.updatedSubscriptions.clear();
14951
+ this.relationshipSubscriptions.clear();
14952
+ }
14953
+ filterDocumentIds(documentIds, search, documentTypes, parentIds) {
14954
+ if (!search)
14955
+ return documentIds;
14956
+ return documentIds.filter((id) => {
14957
+ if (search.ids && !search.ids.includes(id))
14958
+ return false;
14959
+ if (search.type && documentTypes) {
14960
+ const docType = documentTypes.get(id);
14961
+ if (docType !== search.type)
14962
+ return false;
14963
+ }
14964
+ if (search.parentId && parentIds) {
14965
+ const parentId = parentIds.get(id);
14966
+ if (parentId !== search.parentId)
14967
+ return false;
14968
+ }
14969
+ return true;
14970
+ });
14971
+ }
14972
+ filterDocuments(documents, search) {
14973
+ if (!search)
14974
+ return documents;
14975
+ return documents.filter((doc) => {
14976
+ if (search.ids && !search.ids.includes(doc.header.id))
14977
+ return false;
14978
+ if (search.type && doc.header.documentType !== search.type)
14979
+ return false;
14980
+ if (search.slugs && !search.slugs.includes(doc.header.slug))
14981
+ return false;
14982
+ return true;
14983
+ });
14984
+ }
14985
+ matchesRelationshipFilter(parentId, childId, childType, search) {
14986
+ if (!search)
14987
+ return true;
14988
+ if (search.parentId && parentId !== search.parentId)
14989
+ return false;
14990
+ if (search.ids && !search.ids.includes(childId))
14991
+ return false;
14992
+ if (search.type && childType && childType !== search.type)
14993
+ return false;
14994
+ return true;
14995
+ }
14996
+ }
14997
+
14998
+ class SubscriptionNotificationReadModel {
14999
+ subscriptionManager;
15000
+ documentView;
15001
+ constructor(subscriptionManager, documentView) {
15002
+ this.subscriptionManager = subscriptionManager;
15003
+ this.documentView = documentView;
15004
+ }
15005
+ async indexOperations(operations) {
15006
+ if (operations.length === 0)
15007
+ return;
15008
+ const created = [];
15009
+ const deleted = [];
15010
+ const updatedIds = new Set;
15011
+ const documentTypes = new Map;
15012
+ const parentIds = new Map;
15013
+ for (const item of operations) {
15014
+ const { operation, context } = item;
15015
+ const actionType = operation.action.type;
15016
+ documentTypes.set(context.documentId, context.documentType);
15017
+ if (actionType === "CREATE_DOCUMENT") {
15018
+ created.push(context.documentId);
15019
+ } else if (actionType === "DELETE_DOCUMENT") {
15020
+ const input = operation.action.input;
15021
+ const deletedId = input.documentId ?? context.documentId;
15022
+ deleted.push(deletedId);
15023
+ } else if (actionType === "ADD_RELATIONSHIP") {
15024
+ const input = operation.action.input;
15025
+ this.subscriptionManager.notifyRelationshipChanged(input.sourceId, input.targetId, "added", input.childType);
15026
+ } else if (actionType === "REMOVE_RELATIONSHIP") {
15027
+ const input = operation.action.input;
15028
+ this.subscriptionManager.notifyRelationshipChanged(input.sourceId, input.targetId, "removed", input.childType);
15029
+ } else {
15030
+ if (!created.includes(context.documentId)) {
15031
+ updatedIds.add(context.documentId);
15032
+ }
15033
+ }
15034
+ }
15035
+ if (created.length > 0) {
15036
+ this.subscriptionManager.notifyDocumentsCreated(created, documentTypes, parentIds);
15037
+ }
15038
+ if (deleted.length > 0) {
15039
+ this.subscriptionManager.notifyDocumentsDeleted(deleted, documentTypes, parentIds);
15040
+ }
15041
+ if (updatedIds.size > 0 && this.documentView) {
15042
+ const documents = await Promise.all(Array.from(updatedIds).map((id) => this.documentView.get(id)));
15043
+ this.subscriptionManager.notifyDocumentsUpdated(documents);
15044
+ }
15045
+ }
15046
+ }
14390
15047
 
14391
15048
  class Mailbox {
14392
15049
  itemsMap = new Map;
@@ -15147,6 +15804,8 @@ class GqlRequestChannel {
15147
15804
  pushFailureCount = 0;
15148
15805
  pushRetryTimer = null;
15149
15806
  pushBlocked = false;
15807
+ connectionState = "connecting";
15808
+ connectionStateCallbacks = new Set;
15150
15809
  constructor(logger2, channelId, remoteName, cursorStorage, config, operationIndex, pollTimer) {
15151
15810
  this.logger = logger2;
15152
15811
  this.channelId = channelId;
@@ -15175,6 +15834,7 @@ class GqlRequestChannel {
15175
15834
  clearTimeout(this.pushRetryTimer);
15176
15835
  this.pushRetryTimer = null;
15177
15836
  }
15837
+ this.transitionConnectionState("error");
15178
15838
  });
15179
15839
  this.outbox.onAdded((syncOps) => {
15180
15840
  if (this.isShutdown)
@@ -15222,8 +15882,25 @@ class GqlRequestChannel {
15222
15882
  clearTimeout(this.pushRetryTimer);
15223
15883
  this.pushRetryTimer = null;
15224
15884
  }
15885
+ this.transitionConnectionState("disconnected");
15225
15886
  return Promise.resolve();
15226
15887
  }
15888
+ getConnectionState() {
15889
+ return {
15890
+ state: this.connectionState,
15891
+ failureCount: this.failureCount,
15892
+ lastSuccessUtcMs: this.lastSuccessUtcMs ?? 0,
15893
+ lastFailureUtcMs: this.lastFailureUtcMs ?? 0,
15894
+ pushBlocked: this.pushBlocked,
15895
+ pushFailureCount: this.pushFailureCount
15896
+ };
15897
+ }
15898
+ onConnectionStateChange(callback) {
15899
+ this.connectionStateCallbacks.add(callback);
15900
+ return () => {
15901
+ this.connectionStateCallbacks.delete(callback);
15902
+ };
15903
+ }
15227
15904
  async init() {
15228
15905
  await this.touchRemoteChannel();
15229
15906
  const cursors = await this.cursorStorage.list(this.remoteName);
@@ -15235,6 +15912,20 @@ class GqlRequestChannel {
15235
15912
  this.lastPersistedOutboxOrdinal = outboxOrdinal;
15236
15913
  this.pollTimer.setDelegate(() => this.poll());
15237
15914
  this.pollTimer.start();
15915
+ this.transitionConnectionState("connected");
15916
+ }
15917
+ transitionConnectionState(next) {
15918
+ if (this.connectionState === next)
15919
+ return;
15920
+ this.connectionState = next;
15921
+ const snapshot = this.getConnectionState();
15922
+ for (const callback of this.connectionStateCallbacks) {
15923
+ try {
15924
+ callback(snapshot);
15925
+ } catch (error) {
15926
+ this.logger.error("Connection state change callback error: @Error", error);
15927
+ }
15928
+ }
15238
15929
  }
15239
15930
  async poll() {
15240
15931
  if (this.isShutdown) {
@@ -15273,6 +15964,7 @@ class GqlRequestChannel {
15273
15964
  }
15274
15965
  this.lastSuccessUtcMs = Date.now();
15275
15966
  this.failureCount = 0;
15967
+ this.transitionConnectionState("connected");
15276
15968
  }
15277
15969
  handleRemoteDeadLetters(deadLetters) {
15278
15970
  for (const dl of deadLetters) {
@@ -15289,11 +15981,13 @@ class GqlRequestChannel {
15289
15981
  handlePollError(error) {
15290
15982
  const err = error instanceof Error ? error : new Error(String(error));
15291
15983
  if (err.message.includes("Channel not found")) {
15984
+ this.transitionConnectionState("reconnecting");
15292
15985
  this.recoverFromChannelNotFound();
15293
15986
  return true;
15294
15987
  }
15295
15988
  this.failureCount++;
15296
15989
  this.lastFailureUtcMs = Date.now();
15990
+ this.transitionConnectionState("error");
15297
15991
  const channelError = new ChannelError("inbox", err);
15298
15992
  this.logger.error("GqlChannel poll error (@FailureCount): @Error", this.failureCount, channelError);
15299
15993
  return false;
@@ -15305,11 +15999,13 @@ class GqlRequestChannel {
15305
15999
  this.logger.info("GqlChannel @ChannelId re-registered successfully", this.channelId);
15306
16000
  this.failureCount = 0;
15307
16001
  this.pollTimer.start();
16002
+ this.transitionConnectionState("connected");
15308
16003
  }).catch((recoveryError) => {
15309
16004
  this.logger.error("GqlChannel @ChannelId failed to re-register: @Error", this.channelId, recoveryError);
15310
16005
  this.failureCount++;
15311
16006
  this.lastFailureUtcMs = Date.now();
15312
16007
  this.pollTimer.start();
16008
+ this.transitionConnectionState("error");
15313
16009
  });
15314
16010
  }
15315
16011
  async pollSyncEnvelopes(ackOrdinal, latestOrdinal) {
@@ -15430,12 +16126,16 @@ class GqlRequestChannel {
15430
16126
  this.pushSyncOperations(syncOps).then(() => {
15431
16127
  this.pushBlocked = false;
15432
16128
  this.pushFailureCount = 0;
16129
+ if (this.connectionState === "reconnecting" || this.connectionState === "error") {
16130
+ this.transitionConnectionState("connected");
16131
+ }
15433
16132
  }).catch((error) => {
15434
16133
  const err = error instanceof Error ? error : new Error(String(error));
15435
16134
  if (this.isRecoverablePushError(err)) {
15436
16135
  this.pushFailureCount++;
15437
16136
  this.pushBlocked = true;
15438
16137
  this.logger.error("GqlChannel push failed (attempt @FailureCount), will retry: @Error", this.pushFailureCount, err);
16138
+ this.transitionConnectionState("reconnecting");
15439
16139
  this.schedulePushRetry();
15440
16140
  } else {
15441
16141
  const channelError = new ChannelError("outbox", err);
@@ -15444,6 +16144,7 @@ class GqlRequestChannel {
15444
16144
  }
15445
16145
  this.deadLetter.add(...syncOps);
15446
16146
  this.outbox.remove(...syncOps);
16147
+ this.transitionConnectionState("error");
15447
16148
  }
15448
16149
  });
15449
16150
  }
@@ -15569,14 +16270,6 @@ class GqlRequestChannel {
15569
16270
  }
15570
16271
  return result.data;
15571
16272
  }
15572
- getHealth() {
15573
- return {
15574
- state: this.failureCount > 0 ? "error" : "idle",
15575
- lastSuccessUtcMs: this.lastSuccessUtcMs,
15576
- lastFailureUtcMs: this.lastFailureUtcMs,
15577
- failureCount: this.failureCount
15578
- };
15579
- }
15580
16273
  get poller() {
15581
16274
  return this.pollTimer;
15582
16275
  }
@@ -15675,6 +16368,8 @@ class GqlResponseChannel {
15675
16368
  isShutdown;
15676
16369
  lastPersistedInboxOrdinal = 0;
15677
16370
  lastPersistedOutboxOrdinal = 0;
16371
+ connectionState = "connecting";
16372
+ connectionStateCallbacks = new Set;
15678
16373
  constructor(logger2, channelId, remoteName, cursorStorage) {
15679
16374
  this.logger = logger2;
15680
16375
  this.channelId = channelId;
@@ -15715,8 +16410,38 @@ class GqlResponseChannel {
15715
16410
  }
15716
16411
  shutdown() {
15717
16412
  this.isShutdown = true;
16413
+ this.transitionConnectionState("disconnected");
15718
16414
  return Promise.resolve();
15719
16415
  }
16416
+ getConnectionState() {
16417
+ return {
16418
+ state: this.connectionState,
16419
+ failureCount: 0,
16420
+ lastSuccessUtcMs: 0,
16421
+ lastFailureUtcMs: 0,
16422
+ pushBlocked: false,
16423
+ pushFailureCount: 0
16424
+ };
16425
+ }
16426
+ onConnectionStateChange(callback) {
16427
+ this.connectionStateCallbacks.add(callback);
16428
+ return () => {
16429
+ this.connectionStateCallbacks.delete(callback);
16430
+ };
16431
+ }
16432
+ transitionConnectionState(next) {
16433
+ if (this.connectionState === next)
16434
+ return;
16435
+ this.connectionState = next;
16436
+ const snapshot = this.getConnectionState();
16437
+ for (const callback of this.connectionStateCallbacks) {
16438
+ try {
16439
+ callback(snapshot);
16440
+ } catch (error) {
16441
+ this.logger.error("Connection state change callback error: @Error", error);
16442
+ }
16443
+ }
16444
+ }
15720
16445
  async init() {
15721
16446
  const cursors = await this.cursorStorage.list(this.remoteName);
15722
16447
  const inboxOrdinal = cursors.find((c) => c.cursorType === "inbox")?.cursorOrdinal ?? 0;
@@ -15725,6 +16450,7 @@ class GqlResponseChannel {
15725
16450
  this.outbox.init(outboxOrdinal);
15726
16451
  this.lastPersistedInboxOrdinal = inboxOrdinal;
15727
16452
  this.lastPersistedOutboxOrdinal = outboxOrdinal;
16453
+ this.transitionConnectionState("connected");
15728
16454
  }
15729
16455
  }
15730
16456
 
@@ -15737,981 +16463,6 @@ class GqlResponseChannelFactory {
15737
16463
  return new GqlResponseChannel(this.logger, remoteId, remoteName, cursorStorage);
15738
16464
  }
15739
16465
  }
15740
- async function collectAllPages(firstPage, signal) {
15741
- const allResults = [...firstPage.results];
15742
- let currentPage = firstPage;
15743
- while (currentPage.next) {
15744
- if (signal?.aborted) {
15745
- throw new Error("Operation aborted");
15746
- }
15747
- currentPage = await currentPage.next();
15748
- allResults.push(...currentPage.results);
15749
- }
15750
- return allResults;
15751
- }
15752
-
15753
- class KyselyDocumentIndexer {
15754
- db;
15755
- operationStore;
15756
- consistencyTracker;
15757
- lastOperationId = 0;
15758
- constructor(db, operationStore, consistencyTracker) {
15759
- this.db = db;
15760
- this.operationStore = operationStore;
15761
- this.consistencyTracker = consistencyTracker;
15762
- }
15763
- async init() {
15764
- const indexerState = await this.db.selectFrom("IndexerState").selectAll().executeTakeFirst();
15765
- if (indexerState) {
15766
- this.lastOperationId = indexerState.lastOperationId;
15767
- const missedOperations = await this.operationStore.getSinceId(this.lastOperationId);
15768
- if (missedOperations.results.length > 0) {
15769
- await this.indexOperations(missedOperations.results);
15770
- }
15771
- } else {
15772
- await this.db.insertInto("IndexerState").values({
15773
- lastOperationId: 0
15774
- }).execute();
15775
- const allOperations = await this.operationStore.getSinceId(0);
15776
- if (allOperations.results.length > 0) {
15777
- await this.indexOperations(allOperations.results);
15778
- }
15779
- }
15780
- }
15781
- async indexOperations(items) {
15782
- if (items.length === 0)
15783
- return;
15784
- await this.db.transaction().execute(async (trx) => {
15785
- for (const item of items) {
15786
- const { operation } = item;
15787
- const actionType = operation.action.type;
15788
- if (actionType === "ADD_RELATIONSHIP") {
15789
- await this.handleAddRelationship(trx, operation);
15790
- } else if (actionType === "REMOVE_RELATIONSHIP") {
15791
- await this.handleRemoveRelationship(trx, operation);
15792
- }
15793
- }
15794
- const lastOpId = items[items.length - 1].operation.id;
15795
- if (lastOpId && typeof lastOpId === "number") {
15796
- this.lastOperationId = lastOpId;
15797
- await trx.updateTable("IndexerState").set({
15798
- lastOperationId: lastOpId,
15799
- lastOperationTimestamp: new Date
15800
- }).execute();
15801
- }
15802
- });
15803
- const coordinates = [];
15804
- for (let i = 0;i < items.length; i++) {
15805
- const item = items[i];
15806
- coordinates.push({
15807
- documentId: item.context.documentId,
15808
- scope: item.context.scope,
15809
- branch: item.context.branch,
15810
- operationIndex: item.operation.index
15811
- });
15812
- }
15813
- this.consistencyTracker.update(coordinates);
15814
- }
15815
- async waitForConsistency(token, timeoutMs, signal) {
15816
- if (token.coordinates.length === 0) {
15817
- return;
15818
- }
15819
- await this.consistencyTracker.waitFor(token.coordinates, timeoutMs, signal);
15820
- }
15821
- async getOutgoing(documentId, types2, paging, consistencyToken, signal) {
15822
- if (consistencyToken) {
15823
- await this.waitForConsistency(consistencyToken, undefined, signal);
15824
- }
15825
- if (signal?.aborted) {
15826
- throw new Error("Operation aborted");
15827
- }
15828
- const startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;
15829
- const limit = paging?.limit || 100;
15830
- let query = this.db.selectFrom("DocumentRelationship").selectAll().where("sourceId", "=", documentId);
15831
- if (types2 && types2.length > 0) {
15832
- query = query.where("relationshipType", "in", types2);
15833
- }
15834
- const rows = await query.orderBy("createdAt", "asc").orderBy("id", "asc").offset(startIndex).limit(limit + 1).execute();
15835
- const hasMore = rows.length > limit;
15836
- const results = hasMore ? rows.slice(0, limit) : rows;
15837
- const nextCursor = hasMore ? String(startIndex + limit) : undefined;
15838
- return {
15839
- results: results.map((row) => ({
15840
- sourceId: row.sourceId,
15841
- targetId: row.targetId,
15842
- relationshipType: row.relationshipType,
15843
- metadata: row.metadata ? row.metadata : undefined,
15844
- createdAt: row.createdAt,
15845
- updatedAt: row.updatedAt
15846
- })),
15847
- options: paging || { cursor: "0", limit: 100 },
15848
- nextCursor,
15849
- next: hasMore ? () => this.getOutgoing(documentId, types2, { cursor: nextCursor, limit }, consistencyToken, signal) : undefined
15850
- };
15851
- }
15852
- async getIncoming(documentId, types2, paging, consistencyToken, signal) {
15853
- if (consistencyToken) {
15854
- await this.waitForConsistency(consistencyToken, undefined, signal);
15855
- }
15856
- if (signal?.aborted) {
15857
- throw new Error("Operation aborted");
15858
- }
15859
- const startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;
15860
- const limit = paging?.limit || 100;
15861
- let query = this.db.selectFrom("DocumentRelationship").selectAll().where("targetId", "=", documentId);
15862
- if (types2 && types2.length > 0) {
15863
- query = query.where("relationshipType", "in", types2);
15864
- }
15865
- const rows = await query.orderBy("createdAt", "asc").orderBy("id", "asc").offset(startIndex).limit(limit + 1).execute();
15866
- const hasMore = rows.length > limit;
15867
- const results = hasMore ? rows.slice(0, limit) : rows;
15868
- const nextCursor = hasMore ? String(startIndex + limit) : undefined;
15869
- return {
15870
- results: results.map((row) => ({
15871
- sourceId: row.sourceId,
15872
- targetId: row.targetId,
15873
- relationshipType: row.relationshipType,
15874
- metadata: row.metadata ? row.metadata : undefined,
15875
- createdAt: row.createdAt,
15876
- updatedAt: row.updatedAt
15877
- })),
15878
- options: paging || { cursor: "0", limit: 100 },
15879
- nextCursor,
15880
- next: hasMore ? () => this.getIncoming(documentId, types2, { cursor: nextCursor, limit }, consistencyToken, signal) : undefined
15881
- };
15882
- }
15883
- async hasRelationship(sourceId, targetId, types2, consistencyToken, signal) {
15884
- if (consistencyToken) {
15885
- await this.waitForConsistency(consistencyToken, undefined, signal);
15886
- }
15887
- if (signal?.aborted) {
15888
- throw new Error("Operation aborted");
15889
- }
15890
- let query = this.db.selectFrom("DocumentRelationship").select("id").where("sourceId", "=", sourceId).where("targetId", "=", targetId);
15891
- if (types2 && types2.length > 0) {
15892
- query = query.where("relationshipType", "in", types2);
15893
- }
15894
- const result = await query.executeTakeFirst();
15895
- return result !== undefined;
15896
- }
15897
- async getUndirectedRelationships(a, b, types2, paging, consistencyToken, signal) {
15898
- if (consistencyToken) {
15899
- await this.waitForConsistency(consistencyToken, undefined, signal);
15900
- }
15901
- if (signal?.aborted) {
15902
- throw new Error("Operation aborted");
15903
- }
15904
- const startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;
15905
- const limit = paging?.limit || 100;
15906
- let query = this.db.selectFrom("DocumentRelationship").selectAll().where((eb) => eb.or([
15907
- eb.and([eb("sourceId", "=", a), eb("targetId", "=", b)]),
15908
- eb.and([eb("sourceId", "=", b), eb("targetId", "=", a)])
15909
- ]));
15910
- if (types2 && types2.length > 0) {
15911
- query = query.where("relationshipType", "in", types2);
15912
- }
15913
- const rows = await query.orderBy("createdAt", "asc").orderBy("id", "asc").offset(startIndex).limit(limit + 1).execute();
15914
- const hasMore = rows.length > limit;
15915
- const results = hasMore ? rows.slice(0, limit) : rows;
15916
- const nextCursor = hasMore ? String(startIndex + limit) : undefined;
15917
- return {
15918
- results: results.map((row) => ({
15919
- sourceId: row.sourceId,
15920
- targetId: row.targetId,
15921
- relationshipType: row.relationshipType,
15922
- metadata: row.metadata ? row.metadata : undefined,
15923
- createdAt: row.createdAt,
15924
- updatedAt: row.updatedAt
15925
- })),
15926
- options: paging || { cursor: "0", limit: 100 },
15927
- nextCursor,
15928
- next: hasMore ? () => this.getUndirectedRelationships(a, b, types2, { cursor: nextCursor, limit }, consistencyToken, signal) : undefined
15929
- };
15930
- }
15931
- async getDirectedRelationships(sourceId, targetId, types2, paging, consistencyToken, signal) {
15932
- if (consistencyToken) {
15933
- await this.waitForConsistency(consistencyToken, undefined, signal);
15934
- }
15935
- if (signal?.aborted) {
15936
- throw new Error("Operation aborted");
15937
- }
15938
- const startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;
15939
- const limit = paging?.limit || 100;
15940
- let query = this.db.selectFrom("DocumentRelationship").selectAll().where("sourceId", "=", sourceId).where("targetId", "=", targetId);
15941
- if (types2 && types2.length > 0) {
15942
- query = query.where("relationshipType", "in", types2);
15943
- }
15944
- const rows = await query.orderBy("createdAt", "asc").orderBy("id", "asc").offset(startIndex).limit(limit + 1).execute();
15945
- const hasMore = rows.length > limit;
15946
- const results = hasMore ? rows.slice(0, limit) : rows;
15947
- const nextCursor = hasMore ? String(startIndex + limit) : undefined;
15948
- return {
15949
- results: results.map((row) => ({
15950
- sourceId: row.sourceId,
15951
- targetId: row.targetId,
15952
- relationshipType: row.relationshipType,
15953
- metadata: row.metadata ? row.metadata : undefined,
15954
- createdAt: row.createdAt,
15955
- updatedAt: row.updatedAt
15956
- })),
15957
- options: paging || { cursor: "0", limit: 100 },
15958
- nextCursor,
15959
- next: hasMore ? () => this.getDirectedRelationships(sourceId, targetId, types2, { cursor: nextCursor, limit }, consistencyToken, signal) : undefined
15960
- };
15961
- }
15962
- async findPath(sourceId, targetId, types2, consistencyToken, signal) {
15963
- if (consistencyToken) {
15964
- await this.waitForConsistency(consistencyToken, undefined, signal);
15965
- }
15966
- if (signal?.aborted) {
15967
- throw new Error("Operation aborted");
15968
- }
15969
- if (sourceId === targetId) {
15970
- return [sourceId];
15971
- }
15972
- const visited = new Set;
15973
- const queue = [
15974
- { id: sourceId, path: [sourceId] }
15975
- ];
15976
- while (queue.length > 0) {
15977
- const current = queue.shift();
15978
- if (current.id === targetId) {
15979
- return current.path;
15980
- }
15981
- if (visited.has(current.id)) {
15982
- continue;
15983
- }
15984
- visited.add(current.id);
15985
- const outgoingPage = await this.getOutgoing(current.id, types2, undefined, consistencyToken, signal);
15986
- const outgoingRelationships = await collectAllPages(outgoingPage, signal);
15987
- for (const rel of outgoingRelationships) {
15988
- if (!visited.has(rel.targetId)) {
15989
- queue.push({
15990
- id: rel.targetId,
15991
- path: [...current.path, rel.targetId]
15992
- });
15993
- }
15994
- }
15995
- }
15996
- return null;
15997
- }
15998
- async findAncestors(documentId, types2, consistencyToken, signal) {
15999
- if (consistencyToken) {
16000
- await this.waitForConsistency(consistencyToken, undefined, signal);
16001
- }
16002
- if (signal?.aborted) {
16003
- throw new Error("Operation aborted");
16004
- }
16005
- const nodes = new Set([documentId]);
16006
- const edges = [];
16007
- const queue = [documentId];
16008
- const visited = new Set;
16009
- while (queue.length > 0) {
16010
- const currentId = queue.shift();
16011
- if (visited.has(currentId)) {
16012
- continue;
16013
- }
16014
- visited.add(currentId);
16015
- const incomingPage = await this.getIncoming(currentId, types2, undefined, consistencyToken, signal);
16016
- const incomingRelationships = await collectAllPages(incomingPage, signal);
16017
- for (const rel of incomingRelationships) {
16018
- nodes.add(rel.sourceId);
16019
- edges.push({
16020
- from: rel.sourceId,
16021
- to: rel.targetId,
16022
- type: rel.relationshipType
16023
- });
16024
- if (!visited.has(rel.sourceId)) {
16025
- queue.push(rel.sourceId);
16026
- }
16027
- }
16028
- }
16029
- return {
16030
- nodes: Array.from(nodes),
16031
- edges
16032
- };
16033
- }
16034
- async getRelationshipTypes(consistencyToken, signal) {
16035
- if (consistencyToken) {
16036
- await this.waitForConsistency(consistencyToken, undefined, signal);
16037
- }
16038
- if (signal?.aborted) {
16039
- throw new Error("Operation aborted");
16040
- }
16041
- const rows = await this.db.selectFrom("DocumentRelationship").select("relationshipType").distinct().execute();
16042
- return rows.map((row) => row.relationshipType);
16043
- }
16044
- async handleAddRelationship(trx, operation) {
16045
- const input = operation.action.input;
16046
- const existingDoc = await trx.selectFrom("Document").select("id").where("id", "=", input.sourceId).executeTakeFirst();
16047
- if (!existingDoc) {
16048
- await trx.insertInto("Document").values({
16049
- id: input.sourceId
16050
- }).execute();
16051
- }
16052
- const existingTargetDoc = await trx.selectFrom("Document").select("id").where("id", "=", input.targetId).executeTakeFirst();
16053
- if (!existingTargetDoc) {
16054
- await trx.insertInto("Document").values({
16055
- id: input.targetId
16056
- }).execute();
16057
- }
16058
- const existingRel = await trx.selectFrom("DocumentRelationship").select("id").where("sourceId", "=", input.sourceId).where("targetId", "=", input.targetId).where("relationshipType", "=", input.relationshipType).executeTakeFirst();
16059
- if (!existingRel) {
16060
- const relationship = {
16061
- id: v4_default(),
16062
- sourceId: input.sourceId,
16063
- targetId: input.targetId,
16064
- relationshipType: input.relationshipType,
16065
- metadata: input.metadata || null
16066
- };
16067
- await trx.insertInto("DocumentRelationship").values(relationship).execute();
16068
- }
16069
- }
16070
- async handleRemoveRelationship(trx, operation) {
16071
- const input = operation.action.input;
16072
- await trx.deleteFrom("DocumentRelationship").where("sourceId", "=", input.sourceId).where("targetId", "=", input.targetId).where("relationshipType", "=", input.relationshipType).execute();
16073
- }
16074
- }
16075
-
16076
- class KyselyKeyframeStore {
16077
- db;
16078
- constructor(db) {
16079
- this.db = db;
16080
- }
16081
- async putKeyframe(documentId, scope, branch, revision, document2, signal) {
16082
- if (signal?.aborted) {
16083
- throw new Error("Operation aborted");
16084
- }
16085
- await this.db.insertInto("Keyframe").values({
16086
- documentId,
16087
- documentType: document2.header.documentType,
16088
- scope,
16089
- branch,
16090
- revision,
16091
- document: document2
16092
- }).onConflict((oc) => oc.columns(["documentId", "scope", "branch", "revision"]).doUpdateSet({ document: document2 })).execute();
16093
- }
16094
- async findNearestKeyframe(documentId, scope, branch, targetRevision, signal) {
16095
- if (signal?.aborted) {
16096
- throw new Error("Operation aborted");
16097
- }
16098
- const row = await this.db.selectFrom("Keyframe").selectAll().where("documentId", "=", documentId).where("scope", "=", scope).where("branch", "=", branch).where("revision", "<=", targetRevision).orderBy("revision", "desc").limit(1).executeTakeFirst();
16099
- if (!row) {
16100
- return;
16101
- }
16102
- return {
16103
- revision: row.revision,
16104
- document: row.document
16105
- };
16106
- }
16107
- async deleteKeyframes(documentId, scope, branch, signal) {
16108
- if (signal?.aborted) {
16109
- throw new Error("Operation aborted");
16110
- }
16111
- let query = this.db.deleteFrom("Keyframe").where("documentId", "=", documentId);
16112
- if (scope !== undefined && branch !== undefined) {
16113
- query = query.where("scope", "=", scope).where("branch", "=", branch);
16114
- } else if (scope !== undefined) {
16115
- query = query.where("scope", "=", scope);
16116
- }
16117
- const result = await query.executeTakeFirst();
16118
- return Number(result.numDeletedRows || 0n);
16119
- }
16120
- }
16121
-
16122
- class AtomicTransaction {
16123
- documentId;
16124
- documentType;
16125
- scope;
16126
- branch;
16127
- baseRevision;
16128
- operations = [];
16129
- constructor(documentId, documentType, scope, branch, baseRevision) {
16130
- this.documentId = documentId;
16131
- this.documentType = documentType;
16132
- this.scope = scope;
16133
- this.branch = branch;
16134
- this.baseRevision = baseRevision;
16135
- }
16136
- addOperations(...operations) {
16137
- for (const op of operations) {
16138
- this.operations.push({
16139
- jobId: v4_default(),
16140
- opId: op.id,
16141
- prevOpId: "",
16142
- documentId: this.documentId,
16143
- documentType: this.documentType,
16144
- scope: this.scope,
16145
- branch: this.branch,
16146
- timestampUtcMs: new Date(op.timestampUtcMs),
16147
- index: op.index,
16148
- action: JSON.stringify(op.action),
16149
- skip: op.skip,
16150
- error: op.error || null,
16151
- hash: op.hash
16152
- });
16153
- }
16154
- }
16155
- getOperations() {
16156
- return this.operations;
16157
- }
16158
- }
16159
-
16160
- class KyselyOperationStore {
16161
- db;
16162
- constructor(db) {
16163
- this.db = db;
16164
- }
16165
- async apply(documentId, documentType, scope, branch, revision, fn, signal) {
16166
- await this.db.transaction().execute(async (trx) => {
16167
- if (signal?.aborted) {
16168
- throw new Error("Operation aborted");
16169
- }
16170
- const latestOp = await trx.selectFrom("Operation").selectAll().where("documentId", "=", documentId).where("scope", "=", scope).where("branch", "=", branch).orderBy("index", "desc").limit(1).executeTakeFirst();
16171
- const currentRevision = latestOp ? latestOp.index : -1;
16172
- if (currentRevision !== revision - 1) {
16173
- throw new RevisionMismatchError(currentRevision + 1, revision);
16174
- }
16175
- const atomicTxn = new AtomicTransaction(documentId, documentType, scope, branch, revision);
16176
- await fn(atomicTxn);
16177
- const operations = atomicTxn.getOperations();
16178
- if (operations.length > 0) {
16179
- let prevOpId = latestOp?.opId || "";
16180
- for (const op of operations) {
16181
- op.prevOpId = prevOpId;
16182
- prevOpId = op.opId;
16183
- }
16184
- try {
16185
- await trx.insertInto("Operation").values(operations).execute();
16186
- } catch (error) {
16187
- if (error instanceof Error) {
16188
- if (error.message.includes("unique constraint")) {
16189
- const op = operations[0];
16190
- throw new DuplicateOperationError(`${op.opId} at index ${op.index} with skip ${op.skip}`);
16191
- }
16192
- throw error;
16193
- }
16194
- throw error;
16195
- }
16196
- }
16197
- });
16198
- }
16199
- async getSince(documentId, scope, branch, revision, filter, paging, signal) {
16200
- if (signal?.aborted) {
16201
- throw new Error("Operation aborted");
16202
- }
16203
- let query = this.db.selectFrom("Operation").selectAll().where("documentId", "=", documentId).where("scope", "=", scope).where("branch", "=", branch).where("index", ">", revision).orderBy("index", "asc");
16204
- if (filter) {
16205
- if (filter.actionTypes && filter.actionTypes.length > 0) {
16206
- const actionTypesArray = filter.actionTypes.map((t) => `'${t.replace(/'/g, "''")}'`).join(",");
16207
- query = query.where(sql`action->>'type' = ANY(ARRAY[${sql.raw(actionTypesArray)}]::text[])`);
16208
- }
16209
- if (filter.timestampFrom) {
16210
- query = query.where("timestampUtcMs", ">=", new Date(filter.timestampFrom));
16211
- }
16212
- if (filter.timestampTo) {
16213
- query = query.where("timestampUtcMs", "<=", new Date(filter.timestampTo));
16214
- }
16215
- if (filter.sinceRevision !== undefined) {
16216
- query = query.where("index", ">=", filter.sinceRevision);
16217
- }
16218
- }
16219
- if (paging) {
16220
- const cursorValue = Number.parseInt(paging.cursor, 10);
16221
- if (cursorValue > 0) {
16222
- query = query.where("index", ">", cursorValue);
16223
- }
16224
- if (paging.limit) {
16225
- query = query.limit(paging.limit + 1);
16226
- }
16227
- }
16228
- const rows = await query.execute();
16229
- let hasMore = false;
16230
- let items = rows;
16231
- if (paging?.limit && rows.length > paging.limit) {
16232
- hasMore = true;
16233
- items = rows.slice(0, paging.limit);
16234
- }
16235
- const nextCursor = hasMore && items.length > 0 ? items[items.length - 1].index.toString() : undefined;
16236
- const cursor = paging?.cursor || "0";
16237
- const limit = paging?.limit || 100;
16238
- const operations = items.map((row) => this.rowToOperation(row));
16239
- return {
16240
- results: operations,
16241
- options: { cursor, limit },
16242
- nextCursor,
16243
- next: hasMore ? () => this.getSince(documentId, scope, branch, revision, filter, { cursor: nextCursor, limit }, signal) : undefined
16244
- };
16245
- }
16246
- async getSinceId(id, paging, signal) {
16247
- if (signal?.aborted) {
16248
- throw new Error("Operation aborted");
16249
- }
16250
- let query = this.db.selectFrom("Operation").selectAll().where("id", ">", id).orderBy("id", "asc");
16251
- if (paging) {
16252
- const cursorValue = Number.parseInt(paging.cursor, 10);
16253
- if (cursorValue > 0) {
16254
- query = query.where("id", ">", cursorValue);
16255
- }
16256
- if (paging.limit) {
16257
- query = query.limit(paging.limit + 1);
16258
- }
16259
- }
16260
- const rows = await query.execute();
16261
- let hasMore = false;
16262
- let items = rows;
16263
- if (paging?.limit && rows.length > paging.limit) {
16264
- hasMore = true;
16265
- items = rows.slice(0, paging.limit);
16266
- }
16267
- const nextCursor = hasMore && items.length > 0 ? items[items.length - 1].id.toString() : undefined;
16268
- const cursor = paging?.cursor || "0";
16269
- const limit = paging?.limit || 100;
16270
- const operations = items.map((row) => this.rowToOperationWithContext(row));
16271
- return {
16272
- results: operations,
16273
- options: { cursor, limit },
16274
- nextCursor,
16275
- next: hasMore ? () => this.getSinceId(id, { cursor: nextCursor, limit }, signal) : undefined
16276
- };
16277
- }
16278
- async getConflicting(documentId, scope, branch, minTimestamp, paging, signal) {
16279
- if (signal?.aborted) {
16280
- throw new Error("Operation aborted");
16281
- }
16282
- let query = this.db.selectFrom("Operation").selectAll().where("documentId", "=", documentId).where("scope", "=", scope).where("branch", "=", branch).where("timestampUtcMs", ">=", new Date(minTimestamp)).orderBy("index", "asc");
16283
- if (paging) {
16284
- const cursorValue = Number.parseInt(paging.cursor, 10);
16285
- if (cursorValue > 0) {
16286
- query = query.where("index", ">", cursorValue);
16287
- }
16288
- if (paging.limit) {
16289
- query = query.limit(paging.limit + 1);
16290
- }
16291
- }
16292
- const rows = await query.execute();
16293
- let hasMore = false;
16294
- let items = rows;
16295
- if (paging?.limit && rows.length > paging.limit) {
16296
- hasMore = true;
16297
- items = rows.slice(0, paging.limit);
16298
- }
16299
- const nextCursor = hasMore && items.length > 0 ? items[items.length - 1].index.toString() : undefined;
16300
- const cursor = paging?.cursor || "0";
16301
- const limit = paging?.limit || 100;
16302
- const operations = items.map((row) => this.rowToOperation(row));
16303
- return {
16304
- results: operations,
16305
- options: { cursor, limit },
16306
- nextCursor,
16307
- next: hasMore ? () => this.getConflicting(documentId, scope, branch, minTimestamp, { cursor: nextCursor, limit }, signal) : undefined
16308
- };
16309
- }
16310
- async getRevisions(documentId, branch, signal) {
16311
- if (signal?.aborted) {
16312
- throw new Error("Operation aborted");
16313
- }
16314
- const scopeRevisions = await this.db.selectFrom("Operation as o1").select(["o1.scope", "o1.index", "o1.timestampUtcMs"]).where("o1.documentId", "=", documentId).where("o1.branch", "=", branch).where((eb) => eb("o1.index", "=", eb.selectFrom("Operation as o2").select((eb2) => eb2.fn.max("o2.index").as("maxIndex")).where("o2.documentId", "=", eb.ref("o1.documentId")).where("o2.branch", "=", eb.ref("o1.branch")).where("o2.scope", "=", eb.ref("o1.scope")))).execute();
16315
- const revision = {};
16316
- let latestTimestamp = new Date(0).toISOString();
16317
- for (const row of scopeRevisions) {
16318
- revision[row.scope] = row.index + 1;
16319
- const timestamp = row.timestampUtcMs.toISOString();
16320
- if (timestamp > latestTimestamp) {
16321
- latestTimestamp = timestamp;
16322
- }
16323
- }
16324
- return {
16325
- revision,
16326
- latestTimestamp
16327
- };
16328
- }
16329
- rowToOperation(row) {
16330
- return {
16331
- index: row.index,
16332
- timestampUtcMs: row.timestampUtcMs.toISOString(),
16333
- hash: row.hash,
16334
- skip: row.skip,
16335
- error: row.error || undefined,
16336
- id: row.opId,
16337
- action: row.action
16338
- };
16339
- }
16340
- rowToOperationWithContext(row) {
16341
- return {
16342
- operation: this.rowToOperation(row),
16343
- context: {
16344
- documentId: row.documentId,
16345
- documentType: row.documentType,
16346
- scope: row.scope,
16347
- branch: row.branch,
16348
- ordinal: row.id
16349
- }
16350
- };
16351
- }
16352
- }
16353
- async function up(db) {
16354
- await db.schema.createTable("Operation").addColumn("id", "serial", (col) => col.primaryKey()).addColumn("jobId", "text", (col) => col.notNull()).addColumn("opId", "text", (col) => col.notNull()).addColumn("prevOpId", "text", (col) => col.notNull()).addColumn("writeTimestampUtcMs", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn("documentId", "text", (col) => col.notNull()).addColumn("documentType", "text", (col) => col.notNull()).addColumn("scope", "text", (col) => col.notNull()).addColumn("branch", "text", (col) => col.notNull()).addColumn("timestampUtcMs", "timestamptz", (col) => col.notNull()).addColumn("index", "integer", (col) => col.notNull()).addColumn("action", "jsonb", (col) => col.notNull()).addColumn("skip", "integer", (col) => col.notNull()).addColumn("error", "text").addColumn("hash", "text", (col) => col.notNull()).addUniqueConstraint("unique_revision", [
16355
- "documentId",
16356
- "scope",
16357
- "branch",
16358
- "index"
16359
- ]).addUniqueConstraint("unique_operation_instance", ["opId", "index", "skip"]).execute();
16360
- await db.schema.createIndex("streamOperations").on("Operation").columns(["documentId", "scope", "branch", "id"]).execute();
16361
- await db.schema.createIndex("branchlessStreamOperations").on("Operation").columns(["documentId", "scope", "id"]).execute();
16362
- }
16363
- async function up2(db) {
16364
- await db.schema.createTable("Keyframe").addColumn("id", "serial", (col) => col.primaryKey()).addColumn("documentId", "text", (col) => col.notNull()).addColumn("documentType", "text", (col) => col.notNull()).addColumn("scope", "text", (col) => col.notNull()).addColumn("branch", "text", (col) => col.notNull()).addColumn("revision", "integer", (col) => col.notNull()).addColumn("document", "jsonb", (col) => col.notNull()).addColumn("createdAt", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).addUniqueConstraint("unique_keyframe", [
16365
- "documentId",
16366
- "scope",
16367
- "branch",
16368
- "revision"
16369
- ]).execute();
16370
- await db.schema.createIndex("keyframe_lookup").on("Keyframe").columns(["documentId", "scope", "branch", "revision"]).execute();
16371
- }
16372
- async function up3(db) {
16373
- await db.schema.createTable("Document").addColumn("id", "text", (col) => col.primaryKey()).addColumn("createdAt", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn("updatedAt", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();
16374
- }
16375
- async function up4(db) {
16376
- await db.schema.createTable("DocumentRelationship").addColumn("id", "text", (col) => col.primaryKey()).addColumn("sourceId", "text", (col) => col.notNull().references("Document.id").onDelete("cascade")).addColumn("targetId", "text", (col) => col.notNull().references("Document.id").onDelete("cascade")).addColumn("relationshipType", "text", (col) => col.notNull()).addColumn("metadata", "jsonb").addColumn("createdAt", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn("updatedAt", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).addUniqueConstraint("unique_source_target_type", [
16377
- "sourceId",
16378
- "targetId",
16379
- "relationshipType"
16380
- ]).execute();
16381
- await db.schema.createIndex("idx_relationship_source").on("DocumentRelationship").column("sourceId").execute();
16382
- await db.schema.createIndex("idx_relationship_target").on("DocumentRelationship").column("targetId").execute();
16383
- await db.schema.createIndex("idx_relationship_type").on("DocumentRelationship").column("relationshipType").execute();
16384
- }
16385
- async function up5(db) {
16386
- await db.schema.createTable("IndexerState").addColumn("id", "integer", (col) => col.primaryKey().generatedAlwaysAsIdentity()).addColumn("lastOperationId", "integer", (col) => col.notNull()).addColumn("lastOperationTimestamp", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();
16387
- }
16388
- async function up6(db) {
16389
- await db.schema.createTable("DocumentSnapshot").addColumn("id", "text", (col) => col.primaryKey()).addColumn("documentId", "text", (col) => col.notNull()).addColumn("slug", "text").addColumn("name", "text").addColumn("scope", "text", (col) => col.notNull()).addColumn("branch", "text", (col) => col.notNull()).addColumn("content", "jsonb", (col) => col.notNull()).addColumn("documentType", "text", (col) => col.notNull()).addColumn("lastOperationIndex", "integer", (col) => col.notNull()).addColumn("lastOperationHash", "text", (col) => col.notNull()).addColumn("lastUpdatedAt", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn("snapshotVersion", "integer", (col) => col.notNull().defaultTo(1)).addColumn("identifiers", "jsonb").addColumn("metadata", "jsonb").addColumn("isDeleted", "boolean", (col) => col.notNull().defaultTo(false)).addColumn("deletedAt", "timestamptz").addUniqueConstraint("unique_doc_scope_branch", [
16390
- "documentId",
16391
- "scope",
16392
- "branch"
16393
- ]).execute();
16394
- await db.schema.createIndex("idx_slug_scope_branch").on("DocumentSnapshot").columns(["slug", "scope", "branch"]).execute();
16395
- await db.schema.createIndex("idx_doctype_scope_branch").on("DocumentSnapshot").columns(["documentType", "scope", "branch"]).execute();
16396
- await db.schema.createIndex("idx_last_updated").on("DocumentSnapshot").column("lastUpdatedAt").execute();
16397
- await db.schema.createIndex("idx_is_deleted").on("DocumentSnapshot").column("isDeleted").execute();
16398
- }
16399
- async function up7(db) {
16400
- await db.schema.createTable("SlugMapping").addColumn("slug", "text", (col) => col.primaryKey()).addColumn("documentId", "text", (col) => col.notNull()).addColumn("scope", "text", (col) => col.notNull()).addColumn("branch", "text", (col) => col.notNull()).addColumn("createdAt", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn("updatedAt", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).addUniqueConstraint("unique_docid_scope_branch", [
16401
- "documentId",
16402
- "scope",
16403
- "branch"
16404
- ]).execute();
16405
- await db.schema.createIndex("idx_slug_documentid").on("SlugMapping").column("documentId").execute();
16406
- }
16407
- async function up8(db) {
16408
- await db.schema.createTable("ViewState").addColumn("readModelId", "text", (col) => col.primaryKey()).addColumn("lastOrdinal", "integer", (col) => col.notNull().defaultTo(0)).addColumn("lastOperationTimestamp", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();
16409
- }
16410
- async function up9(db) {
16411
- await db.schema.createTable("document_collections").addColumn("documentId", "text", (col) => col.notNull()).addColumn("collectionId", "text", (col) => col.notNull()).addColumn("joinedOrdinal", "bigint", (col) => col.notNull().defaultTo(0)).addColumn("leftOrdinal", "bigint").addPrimaryKeyConstraint("document_collections_pkey", [
16412
- "documentId",
16413
- "collectionId"
16414
- ]).execute();
16415
- await db.schema.createIndex("idx_document_collections_collectionId").on("document_collections").column("collectionId").execute();
16416
- await db.schema.createIndex("idx_doc_collections_collection_range").on("document_collections").columns(["collectionId", "joinedOrdinal"]).execute();
16417
- await db.schema.createTable("operation_index_operations").addColumn("ordinal", "serial", (col) => col.primaryKey()).addColumn("opId", "text", (col) => col.notNull()).addColumn("documentId", "text", (col) => col.notNull()).addColumn("documentType", "text", (col) => col.notNull()).addColumn("scope", "text", (col) => col.notNull()).addColumn("branch", "text", (col) => col.notNull()).addColumn("timestampUtcMs", "text", (col) => col.notNull()).addColumn("writeTimestampUtcMs", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn("index", "integer", (col) => col.notNull()).addColumn("skip", "integer", (col) => col.notNull()).addColumn("hash", "text", (col) => col.notNull()).addColumn("action", "jsonb", (col) => col.notNull()).execute();
16418
- await db.schema.createIndex("idx_operation_index_operations_document").on("operation_index_operations").columns(["documentId", "branch", "scope"]).execute();
16419
- await db.schema.createIndex("idx_operation_index_operations_ordinal").on("operation_index_operations").column("ordinal").execute();
16420
- }
16421
- async function up10(db) {
16422
- await db.schema.createTable("sync_remotes").addColumn("name", "text", (col) => col.primaryKey()).addColumn("collection_id", "text", (col) => col.notNull()).addColumn("channel_type", "text", (col) => col.notNull()).addColumn("channel_id", "text", (col) => col.notNull().defaultTo("")).addColumn("remote_name", "text", (col) => col.notNull().defaultTo("")).addColumn("channel_parameters", "jsonb", (col) => col.notNull().defaultTo(sql`'{}'::jsonb`)).addColumn("filter_document_ids", "jsonb").addColumn("filter_scopes", "jsonb").addColumn("filter_branch", "text", (col) => col.notNull().defaultTo("main")).addColumn("push_state", "text", (col) => col.notNull().defaultTo("idle")).addColumn("push_last_success_utc_ms", "text").addColumn("push_last_failure_utc_ms", "text").addColumn("push_failure_count", "integer", (col) => col.notNull().defaultTo(0)).addColumn("pull_state", "text", (col) => col.notNull().defaultTo("idle")).addColumn("pull_last_success_utc_ms", "text").addColumn("pull_last_failure_utc_ms", "text").addColumn("pull_failure_count", "integer", (col) => col.notNull().defaultTo(0)).addColumn("created_at", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn("updated_at", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();
16423
- await db.schema.createIndex("idx_sync_remotes_collection").on("sync_remotes").column("collection_id").execute();
16424
- await db.schema.createTable("sync_cursors").addColumn("remote_name", "text", (col) => col.primaryKey().references("sync_remotes.name").onDelete("cascade")).addColumn("cursor_ordinal", "bigint", (col) => col.notNull().defaultTo(0)).addColumn("last_synced_at_utc_ms", "text").addColumn("updated_at", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();
16425
- await db.schema.createIndex("idx_sync_cursors_ordinal").on("sync_cursors").column("cursor_ordinal").execute();
16426
- }
16427
- async function up11(db) {
16428
- await db.deleteFrom("sync_cursors").where("remote_name", "like", "outbox::%").execute();
16429
- await db.deleteFrom("sync_remotes").where("name", "like", "outbox::%").execute();
16430
- await db.schema.dropTable("sync_cursors").execute();
16431
- await db.schema.createTable("sync_cursors").addColumn("remote_name", "text", (col) => col.notNull()).addColumn("cursor_type", "text", (col) => col.notNull().defaultTo("inbox")).addColumn("cursor_ordinal", "bigint", (col) => col.notNull().defaultTo(0)).addColumn("last_synced_at_utc_ms", "text").addColumn("updated_at", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).addPrimaryKeyConstraint("sync_cursors_pk", ["remote_name", "cursor_type"]).execute();
16432
- await db.schema.createIndex("idx_sync_cursors_ordinal").on("sync_cursors").column("cursor_ordinal").execute();
16433
- }
16434
- async function up12(db) {
16435
- await db.schema.alterTable("operation_index_operations").addColumn("sourceRemote", "text", (col) => col.notNull().defaultTo("")).execute();
16436
- }
16437
- async function up13(db) {
16438
- await db.schema.createTable("sync_dead_letters").addColumn("ordinal", "serial", (col) => col.primaryKey()).addColumn("id", "text", (col) => col.unique().notNull()).addColumn("job_id", "text", (col) => col.notNull()).addColumn("job_dependencies", "jsonb", (col) => col.notNull().defaultTo(sql`'[]'::jsonb`)).addColumn("remote_name", "text", (col) => col.notNull().references("sync_remotes.name").onDelete("cascade")).addColumn("document_id", "text", (col) => col.notNull()).addColumn("scopes", "jsonb", (col) => col.notNull().defaultTo(sql`'[]'::jsonb`)).addColumn("branch", "text", (col) => col.notNull()).addColumn("operations", "jsonb", (col) => col.notNull().defaultTo(sql`'[]'::jsonb`)).addColumn("error_source", "text", (col) => col.notNull()).addColumn("error_message", "text", (col) => col.notNull()).addColumn("created_at", "timestamptz", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();
16439
- await db.schema.createIndex("idx_sync_dead_letters_remote").on("sync_dead_letters").column("remote_name").execute();
16440
- }
16441
-
16442
- class ProgrammaticMigrationProvider {
16443
- getMigrations() {
16444
- return Promise.resolve(migrations);
16445
- }
16446
- }
16447
- async function runMigrations(db, schema = REACTOR_SCHEMA) {
16448
- try {
16449
- await sql`CREATE SCHEMA IF NOT EXISTS ${sql.id(schema)}`.execute(db);
16450
- } catch (error2) {
16451
- return {
16452
- success: false,
16453
- migrationsExecuted: [],
16454
- error: error2 instanceof Error ? error2 : new Error("Failed to create schema")
16455
- };
16456
- }
16457
- const migrator = new Migrator({
16458
- db: db.withSchema(schema),
16459
- provider: new ProgrammaticMigrationProvider,
16460
- migrationTableSchema: schema
16461
- });
16462
- let error;
16463
- let results;
16464
- try {
16465
- const result = await migrator.migrateToLatest();
16466
- error = result.error;
16467
- results = result.results;
16468
- } catch (e) {
16469
- error = e;
16470
- results = [];
16471
- }
16472
- const migrationsExecuted = results?.map((result) => result.migrationName) ?? [];
16473
- if (error) {
16474
- return {
16475
- success: false,
16476
- migrationsExecuted,
16477
- error: error instanceof Error ? error : new Error("Unknown migration error")
16478
- };
16479
- }
16480
- return {
16481
- success: true,
16482
- migrationsExecuted
16483
- };
16484
- }
16485
-
16486
- class DefaultSubscriptionErrorHandler {
16487
- handleError(error, context) {
16488
- const errorMessage = `Subscription error in ${context.eventType} (${context.subscriptionId})`;
16489
- if (error instanceof Error) {
16490
- const enhancedError = new Error(`${errorMessage}: ${error.message}`);
16491
- enhancedError.cause = error;
16492
- enhancedError.stack = error.stack;
16493
- throw enhancedError;
16494
- } else {
16495
- throw new Error(`${errorMessage}: ${String(error)}`);
16496
- }
16497
- }
16498
- }
16499
-
16500
- class ReactorSubscriptionManager {
16501
- createdSubscriptions = new Map;
16502
- deletedSubscriptions = new Map;
16503
- updatedSubscriptions = new Map;
16504
- relationshipSubscriptions = new Map;
16505
- subscriptionCounter = 0;
16506
- errorHandler;
16507
- constructor(errorHandler) {
16508
- this.errorHandler = errorHandler;
16509
- }
16510
- onDocumentCreated(callback, search) {
16511
- const id = `created-${++this.subscriptionCounter}`;
16512
- this.createdSubscriptions.set(id, { id, callback, search });
16513
- return () => {
16514
- this.createdSubscriptions.delete(id);
16515
- };
16516
- }
16517
- onDocumentDeleted(callback, search) {
16518
- const id = `deleted-${++this.subscriptionCounter}`;
16519
- this.deletedSubscriptions.set(id, { id, callback, search });
16520
- return () => {
16521
- this.deletedSubscriptions.delete(id);
16522
- };
16523
- }
16524
- onDocumentStateUpdated(callback, search, view) {
16525
- const id = `updated-${++this.subscriptionCounter}`;
16526
- this.updatedSubscriptions.set(id, { id, callback, search, view });
16527
- return () => {
16528
- this.updatedSubscriptions.delete(id);
16529
- };
16530
- }
16531
- onRelationshipChanged(callback, search) {
16532
- const id = `relationship-${++this.subscriptionCounter}`;
16533
- this.relationshipSubscriptions.set(id, { id, callback, search });
16534
- return () => {
16535
- this.relationshipSubscriptions.delete(id);
16536
- };
16537
- }
16538
- notifyDocumentsCreated(documentIds, documentTypes, parentIds) {
16539
- const result = {
16540
- results: documentIds,
16541
- options: { cursor: "", limit: documentIds.length }
16542
- };
16543
- for (const subscription of this.createdSubscriptions.values()) {
16544
- const filteredIds = this.filterDocumentIds(documentIds, subscription.search, documentTypes, parentIds);
16545
- if (filteredIds.length > 0) {
16546
- try {
16547
- subscription.callback({
16548
- ...result,
16549
- results: filteredIds
16550
- });
16551
- } catch (error) {
16552
- this.errorHandler.handleError(error, {
16553
- eventType: "created",
16554
- subscriptionId: subscription.id,
16555
- eventData: filteredIds
16556
- });
16557
- }
16558
- }
16559
- }
16560
- }
16561
- notifyDocumentsDeleted(documentIds, documentTypes, parentIds) {
16562
- for (const subscription of this.deletedSubscriptions.values()) {
16563
- const filteredIds = this.filterDocumentIds(documentIds, subscription.search, documentTypes, parentIds);
16564
- if (filteredIds.length > 0) {
16565
- try {
16566
- subscription.callback(filteredIds);
16567
- } catch (error) {
16568
- this.errorHandler.handleError(error, {
16569
- eventType: "deleted",
16570
- subscriptionId: subscription.id,
16571
- eventData: filteredIds
16572
- });
16573
- }
16574
- }
16575
- }
16576
- }
16577
- notifyDocumentsUpdated(documents) {
16578
- const result = {
16579
- results: documents,
16580
- options: { cursor: "", limit: documents.length }
16581
- };
16582
- for (const subscription of this.updatedSubscriptions.values()) {
16583
- const filteredDocs = this.filterDocuments(documents, subscription.search);
16584
- if (filteredDocs.length > 0) {
16585
- try {
16586
- subscription.callback({
16587
- ...result,
16588
- results: filteredDocs
16589
- });
16590
- } catch (error) {
16591
- this.errorHandler.handleError(error, {
16592
- eventType: "updated",
16593
- subscriptionId: subscription.id,
16594
- eventData: filteredDocs
16595
- });
16596
- }
16597
- }
16598
- }
16599
- }
16600
- notifyRelationshipChanged(parentId, childId, changeType, childType) {
16601
- for (const subscription of this.relationshipSubscriptions.values()) {
16602
- if (this.matchesRelationshipFilter(parentId, childId, childType, subscription.search)) {
16603
- try {
16604
- subscription.callback(parentId, childId, changeType);
16605
- } catch (error) {
16606
- this.errorHandler.handleError(error, {
16607
- eventType: "relationshipChanged",
16608
- subscriptionId: subscription.id,
16609
- eventData: { parentId, childId, changeType }
16610
- });
16611
- }
16612
- }
16613
- }
16614
- }
16615
- clearAll() {
16616
- this.createdSubscriptions.clear();
16617
- this.deletedSubscriptions.clear();
16618
- this.updatedSubscriptions.clear();
16619
- this.relationshipSubscriptions.clear();
16620
- }
16621
- filterDocumentIds(documentIds, search, documentTypes, parentIds) {
16622
- if (!search)
16623
- return documentIds;
16624
- return documentIds.filter((id) => {
16625
- if (search.ids && !search.ids.includes(id))
16626
- return false;
16627
- if (search.type && documentTypes) {
16628
- const docType = documentTypes.get(id);
16629
- if (docType !== search.type)
16630
- return false;
16631
- }
16632
- if (search.parentId && parentIds) {
16633
- const parentId = parentIds.get(id);
16634
- if (parentId !== search.parentId)
16635
- return false;
16636
- }
16637
- return true;
16638
- });
16639
- }
16640
- filterDocuments(documents, search) {
16641
- if (!search)
16642
- return documents;
16643
- return documents.filter((doc) => {
16644
- if (search.ids && !search.ids.includes(doc.header.id))
16645
- return false;
16646
- if (search.type && doc.header.documentType !== search.type)
16647
- return false;
16648
- if (search.slugs && !search.slugs.includes(doc.header.slug))
16649
- return false;
16650
- return true;
16651
- });
16652
- }
16653
- matchesRelationshipFilter(parentId, childId, childType, search) {
16654
- if (!search)
16655
- return true;
16656
- if (search.parentId && parentId !== search.parentId)
16657
- return false;
16658
- if (search.ids && !search.ids.includes(childId))
16659
- return false;
16660
- if (search.type && childType && childType !== search.type)
16661
- return false;
16662
- return true;
16663
- }
16664
- }
16665
-
16666
- class SubscriptionNotificationReadModel {
16667
- subscriptionManager;
16668
- documentView;
16669
- constructor(subscriptionManager, documentView) {
16670
- this.subscriptionManager = subscriptionManager;
16671
- this.documentView = documentView;
16672
- }
16673
- async indexOperations(operations) {
16674
- if (operations.length === 0)
16675
- return;
16676
- const created = [];
16677
- const deleted = [];
16678
- const updatedIds = new Set;
16679
- const documentTypes = new Map;
16680
- const parentIds = new Map;
16681
- for (const item of operations) {
16682
- const { operation, context } = item;
16683
- const actionType = operation.action.type;
16684
- documentTypes.set(context.documentId, context.documentType);
16685
- if (actionType === "CREATE_DOCUMENT") {
16686
- created.push(context.documentId);
16687
- } else if (actionType === "DELETE_DOCUMENT") {
16688
- const input = operation.action.input;
16689
- const deletedId = input.documentId ?? context.documentId;
16690
- deleted.push(deletedId);
16691
- } else if (actionType === "ADD_RELATIONSHIP") {
16692
- const input = operation.action.input;
16693
- this.subscriptionManager.notifyRelationshipChanged(input.sourceId, input.targetId, "added", input.childType);
16694
- } else if (actionType === "REMOVE_RELATIONSHIP") {
16695
- const input = operation.action.input;
16696
- this.subscriptionManager.notifyRelationshipChanged(input.sourceId, input.targetId, "removed", input.childType);
16697
- } else {
16698
- if (!created.includes(context.documentId)) {
16699
- updatedIds.add(context.documentId);
16700
- }
16701
- }
16702
- }
16703
- if (created.length > 0) {
16704
- this.subscriptionManager.notifyDocumentsCreated(created, documentTypes, parentIds);
16705
- }
16706
- if (deleted.length > 0) {
16707
- this.subscriptionManager.notifyDocumentsDeleted(deleted, documentTypes, parentIds);
16708
- }
16709
- if (updatedIds.size > 0 && this.documentView) {
16710
- const documents = await Promise.all(Array.from(updatedIds).map((id) => this.documentView.get(id)));
16711
- this.subscriptionManager.notifyDocumentsUpdated(documents);
16712
- }
16713
- }
16714
- }
16715
16466
  function rowToRemoteCursor(row) {
16716
16467
  return {
16717
16468
  remoteName: row.remote_name,
@@ -17441,6 +17192,7 @@ class SyncManager {
17441
17192
  batchAggregator;
17442
17193
  syncStatusTracker;
17443
17194
  maxDeadLettersPerRemote;
17195
+ connectionStateUnsubscribes = new Map;
17444
17196
  loadJobs = new Map;
17445
17197
  constructor(logger2, remoteStorage, cursorStorage, deadLetterStorage, channelFactory, operationIndex, reactor, eventBus, maxDeadLettersPerRemote = 100) {
17446
17198
  this.logger = logger2;
@@ -17506,6 +17258,10 @@ class SyncManager {
17506
17258
  this.awaiter.shutdown();
17507
17259
  this.syncAwaiter.shutdown();
17508
17260
  this.syncStatusTracker.clear();
17261
+ for (const unsub of this.connectionStateUnsubscribes.values()) {
17262
+ unsub();
17263
+ }
17264
+ this.connectionStateUnsubscribes.clear();
17509
17265
  const promises = [];
17510
17266
  for (const remote of this.remotes.values()) {
17511
17267
  promises.push(remote.channel.shutdown());
@@ -17587,6 +17343,11 @@ class SyncManager {
17587
17343
  await this.remoteStorage.remove(name);
17588
17344
  await this.cursorStorage.remove(name);
17589
17345
  this.syncStatusTracker.untrackRemote(name);
17346
+ const unsub = this.connectionStateUnsubscribes.get(name);
17347
+ if (unsub) {
17348
+ unsub();
17349
+ this.connectionStateUnsubscribes.delete(name);
17350
+ }
17590
17351
  this.remotes.delete(name);
17591
17352
  }
17592
17353
  list() {
@@ -17604,6 +17365,16 @@ class SyncManager {
17604
17365
  wireChannelCallbacks(remote) {
17605
17366
  remote.channel.inbox.onAdded((syncOps) => this.handleInboxAdded(remote, syncOps));
17606
17367
  this.syncStatusTracker.trackRemote(remote.name, remote.channel);
17368
+ const unsubscribe = remote.channel.onConnectionStateChange((snapshot) => {
17369
+ this.eventBus.emit(SyncEventTypes.CONNECTION_STATE_CHANGED, {
17370
+ remoteName: remote.name,
17371
+ remoteId: remote.id,
17372
+ previous: snapshot.state,
17373
+ current: snapshot.state,
17374
+ snapshot
17375
+ }).catch(() => {});
17376
+ });
17377
+ this.connectionStateUnsubscribes.set(remote.name, unsubscribe);
17607
17378
  remote.channel.deadLetter.onAdded((syncOps) => {
17608
17379
  for (const syncOp of syncOps) {
17609
17380
  this.logger.error("Dead letter (@remote, @documentId, @jobId, @error, @dependencies)", remote.name, syncOp.documentId, syncOp.jobId, syncOp.error?.message ?? "unknown", syncOp.jobDependencies);
@@ -18527,7 +18298,6 @@ class ReactorBuilder {
18527
18298
  logger;
18528
18299
  documentModels = [];
18529
18300
  upgradeManifests = [];
18530
- storage;
18531
18301
  features = { legacyStorageEnabled: false };
18532
18302
  readModels = [];
18533
18303
  executorManager;
@@ -18556,10 +18326,6 @@ class ReactorBuilder {
18556
18326
  this.upgradeManifests = manifests;
18557
18327
  return this;
18558
18328
  }
18559
- withLegacyStorage(storage) {
18560
- this.storage = storage;
18561
- return this;
18562
- }
18563
18329
  withFeatures(features) {
18564
18330
  this.features = { ...this.features, ...features };
18565
18331
  return this;
@@ -18683,7 +18449,7 @@ class ReactorBuilder {
18683
18449
  }
18684
18450
  readModelInstances.push(documentView);
18685
18451
  const documentIndexerConsistencyTracker = new ConsistencyTracker;
18686
- const documentIndexer = new KyselyDocumentIndexer(database, operationStore, documentIndexerConsistencyTracker);
18452
+ const documentIndexer = new KyselyDocumentIndexer(database, operationIndex, writeCache, documentIndexerConsistencyTracker);
18687
18453
  try {
18688
18454
  await documentIndexer.init();
18689
18455
  } catch (error) {
@@ -18693,7 +18459,7 @@ class ReactorBuilder {
18693
18459
  const subscriptionManager = new ReactorSubscriptionManager(new DefaultSubscriptionErrorHandler);
18694
18460
  const subscriptionNotificationReadModel = new SubscriptionNotificationReadModel(subscriptionManager, documentView);
18695
18461
  const processorManagerConsistencyTracker = new ConsistencyTracker;
18696
- const processorManager = new ProcessorManager(database, operationIndex, writeCache, processorManagerConsistencyTracker);
18462
+ const processorManager = new ProcessorManager(database, operationIndex, writeCache, processorManagerConsistencyTracker, this.logger);
18697
18463
  try {
18698
18464
  await processorManager.init();
18699
18465
  } catch (error) {
@@ -19037,7 +18803,7 @@ var __defProp2, __export2 = (target, all) => {
19037
18803
  }
19038
18804
  }, DocumentDeletedError, InvalidSignatureError, DowngradeNotSupportedError, DocumentNotFoundError, getNextIndexForScope = (document2, scope) => {
19039
18805
  return document2.header.revision[scope] || 0;
19040
- }, EventBusAggregateError, ReactorEventTypes, QueueEventTypes, ModuleNotFoundError, DuplicateModuleError, DuplicateManifestError, ManifestNotFoundError, DowngradeNotSupportedError2, MissingUpgradeTransitionError, InvalidUpgradeStepError, STRICT_ORDER_ACTION_TYPES, MAX_SKIP_THRESHOLD = 1000, documentScopeActions, DRIVE_DOCUMENT_TYPE = "powerhouse/document-drive", ProcessorManager, KyselyDocumentView, ChannelScheme, SyncOperationStatus, ChannelErrorSource, SyncEventTypes, MailboxAggregateError, ChannelError, SyncOperationAggregateError, DEFAULT_CONFIG, syncOpCounter = 0, getLatestAppliedOrdinal = (syncOps) => {
18806
+ }, EventBusAggregateError, ReactorEventTypes, QueueEventTypes, ModuleNotFoundError, DuplicateModuleError, DuplicateManifestError, ManifestNotFoundError, DowngradeNotSupportedError2, MissingUpgradeTransitionError, InvalidUpgradeStepError, STRICT_ORDER_ACTION_TYPES, MAX_SKIP_THRESHOLD = 1000, documentScopeActions, DRIVE_DOCUMENT_TYPE = "powerhouse/document-drive", ProcessorManager, KyselyDocumentView, KyselyDocumentIndexer, DuplicateOperationError, RevisionMismatchError, exports_001_create_operation_table, exports_002_create_keyframe_table, exports_003_create_document_table, exports_004_create_document_relationship_table, exports_005_create_indexer_state_table, exports_006_create_document_snapshot_table, exports_007_create_slug_mapping_table, exports_008_create_view_state_table, exports_009_create_operation_index_tables, exports_010_create_sync_tables, exports_011_add_cursor_type_column, exports_012_add_source_remote_column, exports_013_create_sync_dead_letters_table, exports_014_create_processor_cursor_table, REACTOR_SCHEMA = "reactor", migrations, ChannelScheme, SyncOperationStatus, ChannelErrorSource, SyncEventTypes, MailboxAggregateError, ChannelError, SyncOperationAggregateError, DEFAULT_CONFIG, syncOpCounter = 0, getLatestAppliedOrdinal = (syncOps) => {
19041
18807
  let maxOrdinal = 0;
19042
18808
  for (const syncOp of syncOps) {
19043
18809
  if (syncOp.status === 2) {
@@ -19047,7 +18813,7 @@ var __defProp2, __export2 = (target, all) => {
19047
18813
  }
19048
18814
  }
19049
18815
  return maxOrdinal;
19050
- }, DuplicateOperationError, RevisionMismatchError, exports_001_create_operation_table, exports_002_create_keyframe_table, exports_003_create_document_table, exports_004_create_document_relationship_table, exports_005_create_indexer_state_table, exports_006_create_document_snapshot_table, exports_007_create_slug_mapping_table, exports_008_create_view_state_table, exports_009_create_operation_index_tables, exports_010_create_sync_tables, exports_011_add_cursor_type_column, exports_012_add_source_remote_column, exports_013_create_sync_dead_letters_table, REACTOR_SCHEMA = "reactor", migrations, SyncStatus, cachedEncoder, LOG2_26, IS_RELATIONAL_DB_PROCESSOR, RelationalDbProcessor;
18816
+ }, SyncStatus, cachedEncoder, LOG2_26, IS_RELATIONAL_DB_PROCESSOR, RelationalDbProcessor;
19051
18817
  var init_src = __esm(() => {
19052
18818
  __defProp2 = Object.defineProperty;
19053
18819
  byteToHex = [];
@@ -23189,19 +22955,24 @@ var init_src = __esm(() => {
23189
22955
  processorsByDrive = new Map;
23190
22956
  factoryToProcessors = new Map;
23191
22957
  knownDriveIds = new Set;
23192
- constructor(db, operationIndex, writeCache, consistencyTracker) {
23193
- super(db, operationIndex, writeCache, consistencyTracker, "processor-manager");
22958
+ cursorCache = new Map;
22959
+ logger;
22960
+ constructor(db, operationIndex, writeCache, consistencyTracker, logger2) {
22961
+ super(db, operationIndex, writeCache, consistencyTracker, {
22962
+ readModelId: "processor-manager",
22963
+ rebuildStateOnInit: true
22964
+ });
22965
+ this.logger = logger2;
23194
22966
  }
23195
- async indexOperations(items) {
23196
- if (items.length === 0)
23197
- return;
22967
+ async init() {
22968
+ await super.init();
22969
+ await this.loadAllCursors();
22970
+ await this.discoverExistingDrives();
22971
+ }
22972
+ async commitOperations(items) {
23198
22973
  await this.detectAndRegisterNewDrives(items);
23199
22974
  await this.detectAndCleanupDeletedDrives(items);
23200
22975
  await this.routeOperationsToProcessors(items);
23201
- await this.db.transaction().execute(async (trx) => {
23202
- await this.saveState(trx, items);
23203
- });
23204
- this.updateConsistencyTracker(items);
23205
22976
  }
23206
22977
  async registerFactory(identifier, factory) {
23207
22978
  if (this.factoryRegistry.has(identifier)) {
@@ -23218,13 +22989,13 @@ var init_src = __esm(() => {
23218
22989
  const factoryProcessors = this.factoryToProcessors.get(identifier);
23219
22990
  if (!factoryProcessors)
23220
22991
  return;
23221
- for (const [driveId, records] of factoryProcessors) {
23222
- for (const record of records) {
23223
- await this.safeDisconnect(record.processor);
22992
+ for (const [driveId, tracked] of factoryProcessors) {
22993
+ for (const t of tracked) {
22994
+ await this.safeDisconnect(t.record.processor);
23224
22995
  }
23225
22996
  const driveProcessors = this.processorsByDrive.get(driveId);
23226
22997
  if (driveProcessors) {
23227
- const remaining = driveProcessors.filter((p) => !records.includes(p));
22998
+ const remaining = driveProcessors.filter((p) => !tracked.includes(p));
23228
22999
  if (remaining.length > 0) {
23229
23000
  this.processorsByDrive.set(driveId, remaining);
23230
23001
  } else {
@@ -23232,14 +23003,24 @@ var init_src = __esm(() => {
23232
23003
  }
23233
23004
  }
23234
23005
  }
23006
+ await this.deleteProcessorCursors({ factoryId: identifier });
23235
23007
  this.factoryToProcessors.delete(identifier);
23236
23008
  this.factoryRegistry.delete(identifier);
23237
23009
  }
23238
- getFactoryIdentifiers() {
23239
- return Array.from(this.factoryRegistry.keys());
23010
+ get(processorId) {
23011
+ for (const tracked of this.allTrackedProcessors()) {
23012
+ if (tracked.processorId === processorId)
23013
+ return tracked;
23014
+ }
23015
+ return;
23240
23016
  }
23241
- getProcessorsForDrive(driveId) {
23242
- return this.processorsByDrive.get(driveId) ?? [];
23017
+ getAll() {
23018
+ return Array.from(this.allTrackedProcessors());
23019
+ }
23020
+ *allTrackedProcessors() {
23021
+ for (const tracked of this.processorsByDrive.values()) {
23022
+ yield* tracked;
23023
+ }
23243
23024
  }
23244
23025
  async detectAndRegisterNewDrives(operations) {
23245
23026
  for (const op of operations) {
@@ -23270,6 +23051,12 @@ var init_src = __esm(() => {
23270
23051
  this.knownDriveIds.delete(driveId);
23271
23052
  }
23272
23053
  }
23054
+ async discoverExistingDrives() {
23055
+ const drives = await this.db.selectFrom("DocumentSnapshot").select("documentId").where("documentType", "=", DRIVE_DOCUMENT_TYPE).where("isDeleted", "=", false).execute();
23056
+ for (const drive of drives) {
23057
+ this.knownDriveIds.add(drive.documentId);
23058
+ }
23059
+ }
23273
23060
  isDeletedDocumentADrive(documentId) {
23274
23061
  return this.knownDriveIds.has(documentId);
23275
23062
  }
@@ -23278,71 +23065,214 @@ var init_src = __esm(() => {
23278
23065
  try {
23279
23066
  records = await factory(driveHeader);
23280
23067
  } catch (error) {
23281
- console.error(`ProcessorManager: Factory '${identifier}' failed for drive '${driveId}':`, error);
23068
+ this.logger.error("Factory '@FactoryId' failed for drive '@DriveId': @Error", identifier, driveId, error);
23282
23069
  return;
23283
23070
  }
23284
23071
  if (records.length === 0)
23285
23072
  return;
23073
+ const trackedList = [];
23074
+ for (let i = 0;i < records.length; i++) {
23075
+ const record = records[i];
23076
+ const processorId = `${identifier}:${driveId}:${i}`;
23077
+ const cached = this.cursorCache.get(processorId);
23078
+ let lastOrdinal;
23079
+ let status;
23080
+ let lastError;
23081
+ let lastErrorTimestamp;
23082
+ if (cached) {
23083
+ lastOrdinal = cached.lastOrdinal;
23084
+ status = cached.status;
23085
+ lastError = cached.lastError ?? undefined;
23086
+ lastErrorTimestamp = cached.lastErrorTimestamp ?? undefined;
23087
+ } else {
23088
+ const startFrom = record.startFrom ?? "beginning";
23089
+ lastOrdinal = startFrom === "current" ? this.lastOrdinal : 0;
23090
+ status = "active";
23091
+ lastError = undefined;
23092
+ lastErrorTimestamp = undefined;
23093
+ }
23094
+ const tracked = {
23095
+ processorId,
23096
+ factoryId: identifier,
23097
+ driveId,
23098
+ processorIndex: i,
23099
+ record,
23100
+ lastOrdinal,
23101
+ status,
23102
+ lastError,
23103
+ lastErrorTimestamp,
23104
+ retry: () => this.retryProcessor(tracked)
23105
+ };
23106
+ trackedList.push(tracked);
23107
+ await this.saveProcessorCursor(tracked);
23108
+ }
23109
+ await this.db.deleteFrom("ProcessorCursor").where("factoryId", "=", identifier).where("driveId", "=", driveId).where("processorIndex", ">=", records.length).execute();
23110
+ for (const [id, row] of this.cursorCache) {
23111
+ if (row.factoryId === identifier && row.driveId === driveId && row.processorIndex >= records.length) {
23112
+ this.cursorCache.delete(id);
23113
+ }
23114
+ }
23286
23115
  const factoryProcessors = this.factoryToProcessors.get(identifier);
23287
23116
  if (factoryProcessors) {
23288
- factoryProcessors.set(driveId, records);
23117
+ factoryProcessors.set(driveId, trackedList);
23289
23118
  }
23290
23119
  const existingDriveProcessors = this.processorsByDrive.get(driveId) ?? [];
23291
23120
  this.processorsByDrive.set(driveId, [
23292
23121
  ...existingDriveProcessors,
23293
- ...records
23122
+ ...trackedList
23294
23123
  ]);
23124
+ for (const tracked of trackedList) {
23125
+ if (tracked.status === "active" && tracked.lastOrdinal < this.lastOrdinal) {
23126
+ await this.backfillProcessor(tracked);
23127
+ }
23128
+ }
23129
+ }
23130
+ async backfillProcessor(tracked) {
23131
+ let page = await this.operationIndex.getSinceOrdinal(tracked.lastOrdinal);
23132
+ while (page.results.length > 0) {
23133
+ const matching = page.results.filter((op) => matchesFilter(op, tracked.record.filter));
23134
+ if (matching.length > 0) {
23135
+ try {
23136
+ await tracked.record.processor.onOperations(matching);
23137
+ } catch (error) {
23138
+ tracked.status = "errored";
23139
+ tracked.lastError = error instanceof Error ? error.message : String(error);
23140
+ tracked.lastErrorTimestamp = new Date;
23141
+ await this.safeSaveProcessorCursor(tracked);
23142
+ this.logger.error("Processor '@ProcessorId' failed during backfill at ordinal @Ordinal: @Error", tracked.processorId, tracked.lastOrdinal, error);
23143
+ return;
23144
+ }
23145
+ }
23146
+ const maxOrdinal = Math.max(...page.results.map((op) => op.context.ordinal));
23147
+ tracked.lastOrdinal = maxOrdinal;
23148
+ await this.safeSaveProcessorCursor(tracked);
23149
+ if (!page.next)
23150
+ break;
23151
+ page = await page.next();
23152
+ }
23153
+ }
23154
+ async retryProcessor(tracked) {
23155
+ if (tracked.status !== "errored")
23156
+ return;
23157
+ tracked.status = "active";
23158
+ tracked.lastError = undefined;
23159
+ tracked.lastErrorTimestamp = undefined;
23160
+ await this.saveProcessorCursor(tracked);
23161
+ await this.backfillProcessor(tracked);
23295
23162
  }
23296
23163
  async cleanupDriveProcessors(driveId) {
23297
23164
  const processors = this.processorsByDrive.get(driveId);
23298
23165
  if (!processors)
23299
23166
  return;
23300
- for (const record of processors) {
23301
- await this.safeDisconnect(record.processor);
23167
+ for (const tracked of processors) {
23168
+ await this.safeDisconnect(tracked.record.processor);
23302
23169
  }
23303
23170
  this.processorsByDrive.delete(driveId);
23304
23171
  for (const factoryProcessors of this.factoryToProcessors.values()) {
23305
23172
  factoryProcessors.delete(driveId);
23306
23173
  }
23174
+ await this.deleteProcessorCursors({ driveId });
23307
23175
  }
23308
23176
  async safeDisconnect(processor) {
23309
23177
  try {
23310
23178
  await processor.onDisconnect();
23311
23179
  } catch (error) {
23312
- console.error("ProcessorManager: Error disconnecting processor:", error);
23180
+ this.logger.error("Error disconnecting processor: @Error", error);
23313
23181
  }
23314
23182
  }
23315
23183
  async routeOperationsToProcessors(operations) {
23316
- const processorOperations = new Map;
23317
- for (const [, records] of this.processorsByDrive) {
23318
- for (const { processor, filter } of records) {
23319
- const matching = operations.filter((op) => matchesFilter(op, filter));
23320
- if (matching.length === 0)
23321
- continue;
23322
- const existing = processorOperations.get(processor) ?? [];
23323
- processorOperations.set(processor, [...existing, ...matching]);
23184
+ const maxOrdinal = Math.max(...operations.map((op) => op.context.ordinal));
23185
+ const allTracked = Array.from(this.allTrackedProcessors());
23186
+ await Promise.all(allTracked.map(async (tracked) => {
23187
+ if (tracked.status !== "active")
23188
+ return;
23189
+ const unseen = operations.filter((op) => op.context.ordinal > tracked.lastOrdinal);
23190
+ const matching = unseen.filter((op) => matchesFilter(op, tracked.record.filter));
23191
+ if (matching.length > 0) {
23192
+ try {
23193
+ await tracked.record.processor.onOperations(matching);
23194
+ } catch (error) {
23195
+ tracked.status = "errored";
23196
+ tracked.lastError = error instanceof Error ? error.message : String(error);
23197
+ tracked.lastErrorTimestamp = new Date;
23198
+ await this.safeSaveProcessorCursor(tracked);
23199
+ this.logger.error("Processor '@ProcessorId' failed at ordinal @Ordinal: @Error", tracked.processorId, tracked.lastOrdinal, error);
23200
+ return;
23201
+ }
23324
23202
  }
23203
+ tracked.lastOrdinal = maxOrdinal;
23204
+ await this.safeSaveProcessorCursor(tracked);
23205
+ }));
23206
+ }
23207
+ async loadAllCursors() {
23208
+ const rows = await this.db.selectFrom("ProcessorCursor").selectAll().execute();
23209
+ for (const row of rows) {
23210
+ this.cursorCache.set(row.processorId, row);
23325
23211
  }
23326
- await Promise.all(Array.from(processorOperations.entries()).map(async ([processor, ops]) => {
23327
- try {
23328
- await processor.onOperations(ops);
23329
- } catch (error) {
23330
- console.error("ProcessorManager: Error in processor.onOperations:", error);
23212
+ }
23213
+ async safeSaveProcessorCursor(tracked) {
23214
+ try {
23215
+ await this.saveProcessorCursor(tracked);
23216
+ } catch (error) {
23217
+ this.logger.error("Failed to persist cursor for '@ProcessorId': @Error", tracked.processorId, error);
23218
+ }
23219
+ }
23220
+ async saveProcessorCursor(tracked) {
23221
+ await this.db.insertInto("ProcessorCursor").values({
23222
+ processorId: tracked.processorId,
23223
+ factoryId: tracked.factoryId,
23224
+ driveId: tracked.driveId,
23225
+ processorIndex: tracked.processorIndex,
23226
+ lastOrdinal: tracked.lastOrdinal,
23227
+ status: tracked.status,
23228
+ lastError: tracked.lastError ?? null,
23229
+ lastErrorTimestamp: tracked.lastErrorTimestamp ?? null,
23230
+ updatedAt: new Date
23231
+ }).onConflict((oc) => oc.column("processorId").doUpdateSet({
23232
+ lastOrdinal: tracked.lastOrdinal,
23233
+ status: tracked.status,
23234
+ lastError: tracked.lastError ?? null,
23235
+ lastErrorTimestamp: tracked.lastErrorTimestamp ?? null,
23236
+ updatedAt: new Date
23237
+ })).execute();
23238
+ this.cursorCache.set(tracked.processorId, {
23239
+ processorId: tracked.processorId,
23240
+ factoryId: tracked.factoryId,
23241
+ driveId: tracked.driveId,
23242
+ processorIndex: tracked.processorIndex,
23243
+ lastOrdinal: tracked.lastOrdinal,
23244
+ status: tracked.status,
23245
+ lastError: tracked.lastError ?? null,
23246
+ lastErrorTimestamp: tracked.lastErrorTimestamp ?? null,
23247
+ createdAt: new Date,
23248
+ updatedAt: new Date
23249
+ });
23250
+ }
23251
+ async deleteProcessorCursors(filter) {
23252
+ if ("factoryId" in filter) {
23253
+ await this.db.deleteFrom("ProcessorCursor").where("factoryId", "=", filter.factoryId).execute();
23254
+ for (const [id, row] of this.cursorCache) {
23255
+ if (row.factoryId === filter.factoryId)
23256
+ this.cursorCache.delete(id);
23331
23257
  }
23332
- }));
23258
+ } else {
23259
+ await this.db.deleteFrom("ProcessorCursor").where("driveId", "=", filter.driveId).execute();
23260
+ for (const [id, row] of this.cursorCache) {
23261
+ if (row.driveId === filter.driveId)
23262
+ this.cursorCache.delete(id);
23263
+ }
23264
+ }
23333
23265
  }
23334
23266
  };
23335
23267
  KyselyDocumentView = class KyselyDocumentView extends BaseReadModel {
23336
23268
  operationStore;
23337
23269
  _db;
23338
23270
  constructor(db, operationStore, operationIndex, writeCache, consistencyTracker) {
23339
- super(db, operationIndex, writeCache, consistencyTracker, "document-view");
23271
+ super(db, operationIndex, writeCache, consistencyTracker, { readModelId: "document-view", rebuildStateOnInit: true });
23340
23272
  this.operationStore = operationStore;
23341
23273
  this._db = db;
23342
23274
  }
23343
- async indexOperations(items) {
23344
- if (items.length === 0)
23345
- return;
23275
+ async commitOperations(items) {
23346
23276
  await this._db.transaction().execute(async (trx) => {
23347
23277
  for (const item of items) {
23348
23278
  const { operation, context } = item;
@@ -23446,9 +23376,7 @@ var init_src = __esm(() => {
23446
23376
  }
23447
23377
  }
23448
23378
  }
23449
- await this.saveState(trx, items);
23450
23379
  });
23451
- this.updateConsistencyTracker(items);
23452
23380
  }
23453
23381
  async exists(documentIds, consistencyToken, signal) {
23454
23382
  if (consistencyToken) {
@@ -23693,63 +23621,278 @@ var init_src = __esm(() => {
23693
23621
  return resolvedDocumentId;
23694
23622
  }
23695
23623
  };
23696
- ((ChannelScheme2) => {
23697
- ChannelScheme2["CONNECT"] = "connect";
23698
- ChannelScheme2["SWITCHBOARD"] = "switchboard";
23699
- })(ChannelScheme ||= {});
23700
- ((SyncOperationStatus2) => {
23701
- SyncOperationStatus2[SyncOperationStatus2["Unknown"] = -1] = "Unknown";
23702
- SyncOperationStatus2[SyncOperationStatus2["TransportPending"] = 0] = "TransportPending";
23703
- SyncOperationStatus2[SyncOperationStatus2["ExecutionPending"] = 1] = "ExecutionPending";
23704
- SyncOperationStatus2[SyncOperationStatus2["Applied"] = 2] = "Applied";
23705
- SyncOperationStatus2[SyncOperationStatus2["Error"] = 3] = "Error";
23706
- })(SyncOperationStatus ||= {});
23707
- ((ChannelErrorSource2) => {
23708
- ChannelErrorSource2["None"] = "none";
23709
- ChannelErrorSource2["Channel"] = "channel";
23710
- ChannelErrorSource2["Inbox"] = "inbox";
23711
- ChannelErrorSource2["Outbox"] = "outbox";
23712
- })(ChannelErrorSource ||= {});
23713
- SyncEventTypes = {
23714
- SYNC_PENDING: 20001,
23715
- SYNC_SUCCEEDED: 20002,
23716
- SYNC_FAILED: 20003,
23717
- DEAD_LETTER_ADDED: 20004
23718
- };
23719
- MailboxAggregateError = class MailboxAggregateError extends Error {
23720
- errors;
23721
- constructor(errors2) {
23722
- const messages = errors2.map((e) => e.message).join("; ");
23723
- super(`Mailbox callback failed with ${errors2.length} error(s): ${messages}`);
23724
- this.name = "MailboxAggregateError";
23725
- this.errors = errors2;
23624
+ KyselyDocumentIndexer = class KyselyDocumentIndexer extends BaseReadModel {
23625
+ _db;
23626
+ constructor(db, operationIndex, writeCache, consistencyTracker) {
23627
+ super(db, operationIndex, writeCache, consistencyTracker, { readModelId: "document-indexer", rebuildStateOnInit: false });
23628
+ this._db = db;
23726
23629
  }
23727
- };
23728
- ChannelError = class ChannelError extends Error {
23729
- source;
23730
- error;
23731
- constructor(source, error) {
23732
- super(`ChannelError[${source}]: ${error.message}`);
23733
- this.name = "ChannelError";
23734
- this.source = source;
23735
- this.error = error;
23630
+ async commitOperations(items) {
23631
+ await this._db.transaction().execute(async (trx) => {
23632
+ for (const item of items) {
23633
+ const { operation } = item;
23634
+ const actionType = operation.action.type;
23635
+ if (actionType === "ADD_RELATIONSHIP") {
23636
+ await this.handleAddRelationship(trx, operation);
23637
+ } else if (actionType === "REMOVE_RELATIONSHIP") {
23638
+ await this.handleRemoveRelationship(trx, operation);
23639
+ }
23640
+ }
23641
+ });
23736
23642
  }
23737
- };
23738
- SyncOperationAggregateError = class SyncOperationAggregateError extends Error {
23739
- errors;
23740
- constructor(errors2) {
23741
- const messages = errors2.map((e) => e.message).join("; ");
23742
- super(`SyncOperation callback failed with ${errors2.length} error(s): ${messages}`);
23743
- this.name = "SyncOperationAggregateError";
23744
- this.errors = errors2;
23643
+ async getOutgoing(documentId, types2, paging, consistencyToken, signal) {
23644
+ if (consistencyToken) {
23645
+ await this.waitForConsistency(consistencyToken, undefined, signal);
23646
+ }
23647
+ if (signal?.aborted) {
23648
+ throw new Error("Operation aborted");
23649
+ }
23650
+ const startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;
23651
+ const limit = paging?.limit || 100;
23652
+ let query = this._db.selectFrom("DocumentRelationship").selectAll().where("sourceId", "=", documentId);
23653
+ if (types2 && types2.length > 0) {
23654
+ query = query.where("relationshipType", "in", types2);
23655
+ }
23656
+ const rows = await query.orderBy("createdAt", "asc").orderBy("id", "asc").offset(startIndex).limit(limit + 1).execute();
23657
+ const hasMore = rows.length > limit;
23658
+ const results = hasMore ? rows.slice(0, limit) : rows;
23659
+ const nextCursor = hasMore ? String(startIndex + limit) : undefined;
23660
+ return {
23661
+ results: results.map((row) => ({
23662
+ sourceId: row.sourceId,
23663
+ targetId: row.targetId,
23664
+ relationshipType: row.relationshipType,
23665
+ metadata: row.metadata ? row.metadata : undefined,
23666
+ createdAt: row.createdAt,
23667
+ updatedAt: row.updatedAt
23668
+ })),
23669
+ options: paging || { cursor: "0", limit: 100 },
23670
+ nextCursor,
23671
+ next: hasMore ? () => this.getOutgoing(documentId, types2, { cursor: nextCursor, limit }, consistencyToken, signal) : undefined
23672
+ };
23673
+ }
23674
+ async getIncoming(documentId, types2, paging, consistencyToken, signal) {
23675
+ if (consistencyToken) {
23676
+ await this.waitForConsistency(consistencyToken, undefined, signal);
23677
+ }
23678
+ if (signal?.aborted) {
23679
+ throw new Error("Operation aborted");
23680
+ }
23681
+ const startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;
23682
+ const limit = paging?.limit || 100;
23683
+ let query = this._db.selectFrom("DocumentRelationship").selectAll().where("targetId", "=", documentId);
23684
+ if (types2 && types2.length > 0) {
23685
+ query = query.where("relationshipType", "in", types2);
23686
+ }
23687
+ const rows = await query.orderBy("createdAt", "asc").orderBy("id", "asc").offset(startIndex).limit(limit + 1).execute();
23688
+ const hasMore = rows.length > limit;
23689
+ const results = hasMore ? rows.slice(0, limit) : rows;
23690
+ const nextCursor = hasMore ? String(startIndex + limit) : undefined;
23691
+ return {
23692
+ results: results.map((row) => ({
23693
+ sourceId: row.sourceId,
23694
+ targetId: row.targetId,
23695
+ relationshipType: row.relationshipType,
23696
+ metadata: row.metadata ? row.metadata : undefined,
23697
+ createdAt: row.createdAt,
23698
+ updatedAt: row.updatedAt
23699
+ })),
23700
+ options: paging || { cursor: "0", limit: 100 },
23701
+ nextCursor,
23702
+ next: hasMore ? () => this.getIncoming(documentId, types2, { cursor: nextCursor, limit }, consistencyToken, signal) : undefined
23703
+ };
23704
+ }
23705
+ async hasRelationship(sourceId, targetId, types2, consistencyToken, signal) {
23706
+ if (consistencyToken) {
23707
+ await this.waitForConsistency(consistencyToken, undefined, signal);
23708
+ }
23709
+ if (signal?.aborted) {
23710
+ throw new Error("Operation aborted");
23711
+ }
23712
+ let query = this._db.selectFrom("DocumentRelationship").select("id").where("sourceId", "=", sourceId).where("targetId", "=", targetId);
23713
+ if (types2 && types2.length > 0) {
23714
+ query = query.where("relationshipType", "in", types2);
23715
+ }
23716
+ const result = await query.executeTakeFirst();
23717
+ return result !== undefined;
23718
+ }
23719
+ async getUndirectedRelationships(a, b, types2, paging, consistencyToken, signal) {
23720
+ if (consistencyToken) {
23721
+ await this.waitForConsistency(consistencyToken, undefined, signal);
23722
+ }
23723
+ if (signal?.aborted) {
23724
+ throw new Error("Operation aborted");
23725
+ }
23726
+ const startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;
23727
+ const limit = paging?.limit || 100;
23728
+ let query = this._db.selectFrom("DocumentRelationship").selectAll().where((eb) => eb.or([
23729
+ eb.and([eb("sourceId", "=", a), eb("targetId", "=", b)]),
23730
+ eb.and([eb("sourceId", "=", b), eb("targetId", "=", a)])
23731
+ ]));
23732
+ if (types2 && types2.length > 0) {
23733
+ query = query.where("relationshipType", "in", types2);
23734
+ }
23735
+ const rows = await query.orderBy("createdAt", "asc").orderBy("id", "asc").offset(startIndex).limit(limit + 1).execute();
23736
+ const hasMore = rows.length > limit;
23737
+ const results = hasMore ? rows.slice(0, limit) : rows;
23738
+ const nextCursor = hasMore ? String(startIndex + limit) : undefined;
23739
+ return {
23740
+ results: results.map((row) => ({
23741
+ sourceId: row.sourceId,
23742
+ targetId: row.targetId,
23743
+ relationshipType: row.relationshipType,
23744
+ metadata: row.metadata ? row.metadata : undefined,
23745
+ createdAt: row.createdAt,
23746
+ updatedAt: row.updatedAt
23747
+ })),
23748
+ options: paging || { cursor: "0", limit: 100 },
23749
+ nextCursor,
23750
+ next: hasMore ? () => this.getUndirectedRelationships(a, b, types2, { cursor: nextCursor, limit }, consistencyToken, signal) : undefined
23751
+ };
23752
+ }
23753
+ async getDirectedRelationships(sourceId, targetId, types2, paging, consistencyToken, signal) {
23754
+ if (consistencyToken) {
23755
+ await this.waitForConsistency(consistencyToken, undefined, signal);
23756
+ }
23757
+ if (signal?.aborted) {
23758
+ throw new Error("Operation aborted");
23759
+ }
23760
+ const startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;
23761
+ const limit = paging?.limit || 100;
23762
+ let query = this._db.selectFrom("DocumentRelationship").selectAll().where("sourceId", "=", sourceId).where("targetId", "=", targetId);
23763
+ if (types2 && types2.length > 0) {
23764
+ query = query.where("relationshipType", "in", types2);
23765
+ }
23766
+ const rows = await query.orderBy("createdAt", "asc").orderBy("id", "asc").offset(startIndex).limit(limit + 1).execute();
23767
+ const hasMore = rows.length > limit;
23768
+ const results = hasMore ? rows.slice(0, limit) : rows;
23769
+ const nextCursor = hasMore ? String(startIndex + limit) : undefined;
23770
+ return {
23771
+ results: results.map((row) => ({
23772
+ sourceId: row.sourceId,
23773
+ targetId: row.targetId,
23774
+ relationshipType: row.relationshipType,
23775
+ metadata: row.metadata ? row.metadata : undefined,
23776
+ createdAt: row.createdAt,
23777
+ updatedAt: row.updatedAt
23778
+ })),
23779
+ options: paging || { cursor: "0", limit: 100 },
23780
+ nextCursor,
23781
+ next: hasMore ? () => this.getDirectedRelationships(sourceId, targetId, types2, { cursor: nextCursor, limit }, consistencyToken, signal) : undefined
23782
+ };
23783
+ }
23784
+ async findPath(sourceId, targetId, types2, consistencyToken, signal) {
23785
+ if (consistencyToken) {
23786
+ await this.waitForConsistency(consistencyToken, undefined, signal);
23787
+ }
23788
+ if (signal?.aborted) {
23789
+ throw new Error("Operation aborted");
23790
+ }
23791
+ if (sourceId === targetId) {
23792
+ return [sourceId];
23793
+ }
23794
+ const visited = new Set;
23795
+ const queue = [
23796
+ { id: sourceId, path: [sourceId] }
23797
+ ];
23798
+ while (queue.length > 0) {
23799
+ const current = queue.shift();
23800
+ if (current.id === targetId) {
23801
+ return current.path;
23802
+ }
23803
+ if (visited.has(current.id)) {
23804
+ continue;
23805
+ }
23806
+ visited.add(current.id);
23807
+ const outgoingPage = await this.getOutgoing(current.id, types2, undefined, consistencyToken, signal);
23808
+ const outgoingRelationships = await collectAllPages(outgoingPage, signal);
23809
+ for (const rel of outgoingRelationships) {
23810
+ if (!visited.has(rel.targetId)) {
23811
+ queue.push({
23812
+ id: rel.targetId,
23813
+ path: [...current.path, rel.targetId]
23814
+ });
23815
+ }
23816
+ }
23817
+ }
23818
+ return null;
23819
+ }
23820
+ async findAncestors(documentId, types2, consistencyToken, signal) {
23821
+ if (consistencyToken) {
23822
+ await this.waitForConsistency(consistencyToken, undefined, signal);
23823
+ }
23824
+ if (signal?.aborted) {
23825
+ throw new Error("Operation aborted");
23826
+ }
23827
+ const nodes = new Set([documentId]);
23828
+ const edges = [];
23829
+ const queue = [documentId];
23830
+ const visited = new Set;
23831
+ while (queue.length > 0) {
23832
+ const currentId = queue.shift();
23833
+ if (visited.has(currentId)) {
23834
+ continue;
23835
+ }
23836
+ visited.add(currentId);
23837
+ const incomingPage = await this.getIncoming(currentId, types2, undefined, consistencyToken, signal);
23838
+ const incomingRelationships = await collectAllPages(incomingPage, signal);
23839
+ for (const rel of incomingRelationships) {
23840
+ nodes.add(rel.sourceId);
23841
+ edges.push({
23842
+ from: rel.sourceId,
23843
+ to: rel.targetId,
23844
+ type: rel.relationshipType
23845
+ });
23846
+ if (!visited.has(rel.sourceId)) {
23847
+ queue.push(rel.sourceId);
23848
+ }
23849
+ }
23850
+ }
23851
+ return {
23852
+ nodes: Array.from(nodes),
23853
+ edges
23854
+ };
23855
+ }
23856
+ async getRelationshipTypes(consistencyToken, signal) {
23857
+ if (consistencyToken) {
23858
+ await this.waitForConsistency(consistencyToken, undefined, signal);
23859
+ }
23860
+ if (signal?.aborted) {
23861
+ throw new Error("Operation aborted");
23862
+ }
23863
+ const rows = await this._db.selectFrom("DocumentRelationship").select("relationshipType").distinct().execute();
23864
+ return rows.map((row) => row.relationshipType);
23865
+ }
23866
+ async handleAddRelationship(trx, operation) {
23867
+ const input = operation.action.input;
23868
+ const existingDoc = await trx.selectFrom("Document").select("id").where("id", "=", input.sourceId).executeTakeFirst();
23869
+ if (!existingDoc) {
23870
+ await trx.insertInto("Document").values({
23871
+ id: input.sourceId
23872
+ }).execute();
23873
+ }
23874
+ const existingTargetDoc = await trx.selectFrom("Document").select("id").where("id", "=", input.targetId).executeTakeFirst();
23875
+ if (!existingTargetDoc) {
23876
+ await trx.insertInto("Document").values({
23877
+ id: input.targetId
23878
+ }).execute();
23879
+ }
23880
+ const existingRel = await trx.selectFrom("DocumentRelationship").select("id").where("sourceId", "=", input.sourceId).where("targetId", "=", input.targetId).where("relationshipType", "=", input.relationshipType).executeTakeFirst();
23881
+ if (!existingRel) {
23882
+ const relationship = {
23883
+ id: v4_default(),
23884
+ sourceId: input.sourceId,
23885
+ targetId: input.targetId,
23886
+ relationshipType: input.relationshipType,
23887
+ metadata: input.metadata || null
23888
+ };
23889
+ await trx.insertInto("DocumentRelationship").values(relationship).execute();
23890
+ }
23891
+ }
23892
+ async handleRemoveRelationship(trx, operation) {
23893
+ const input = operation.action.input;
23894
+ await trx.deleteFrom("DocumentRelationship").where("sourceId", "=", input.sourceId).where("targetId", "=", input.targetId).where("relationshipType", "=", input.relationshipType).execute();
23745
23895
  }
23746
- };
23747
- DEFAULT_CONFIG = {
23748
- intervalMs: 2000,
23749
- maxQueueDepth: 100,
23750
- backpressureCheckIntervalMs: 500,
23751
- retryBaseDelayMs: 1000,
23752
- retryMaxDelayMs: 300000
23753
23896
  };
23754
23897
  DuplicateOperationError = class DuplicateOperationError extends Error {
23755
23898
  constructor(description) {
@@ -23815,6 +23958,10 @@ var init_src = __esm(() => {
23815
23958
  __export2(exports_013_create_sync_dead_letters_table, {
23816
23959
  up: () => up13
23817
23960
  });
23961
+ exports_014_create_processor_cursor_table = {};
23962
+ __export2(exports_014_create_processor_cursor_table, {
23963
+ up: () => up14
23964
+ });
23818
23965
  migrations = {
23819
23966
  "001_create_operation_table": exports_001_create_operation_table,
23820
23967
  "002_create_keyframe_table": exports_002_create_keyframe_table,
@@ -23828,7 +23975,67 @@ var init_src = __esm(() => {
23828
23975
  "010_create_sync_tables": exports_010_create_sync_tables,
23829
23976
  "011_add_cursor_type_column": exports_011_add_cursor_type_column,
23830
23977
  "012_add_source_remote_column": exports_012_add_source_remote_column,
23831
- "013_create_sync_dead_letters_table": exports_013_create_sync_dead_letters_table
23978
+ "013_create_sync_dead_letters_table": exports_013_create_sync_dead_letters_table,
23979
+ "014_create_processor_cursor_table": exports_014_create_processor_cursor_table
23980
+ };
23981
+ ((ChannelScheme2) => {
23982
+ ChannelScheme2["CONNECT"] = "connect";
23983
+ ChannelScheme2["SWITCHBOARD"] = "switchboard";
23984
+ })(ChannelScheme ||= {});
23985
+ ((SyncOperationStatus2) => {
23986
+ SyncOperationStatus2[SyncOperationStatus2["Unknown"] = -1] = "Unknown";
23987
+ SyncOperationStatus2[SyncOperationStatus2["TransportPending"] = 0] = "TransportPending";
23988
+ SyncOperationStatus2[SyncOperationStatus2["ExecutionPending"] = 1] = "ExecutionPending";
23989
+ SyncOperationStatus2[SyncOperationStatus2["Applied"] = 2] = "Applied";
23990
+ SyncOperationStatus2[SyncOperationStatus2["Error"] = 3] = "Error";
23991
+ })(SyncOperationStatus ||= {});
23992
+ ((ChannelErrorSource2) => {
23993
+ ChannelErrorSource2["None"] = "none";
23994
+ ChannelErrorSource2["Channel"] = "channel";
23995
+ ChannelErrorSource2["Inbox"] = "inbox";
23996
+ ChannelErrorSource2["Outbox"] = "outbox";
23997
+ })(ChannelErrorSource ||= {});
23998
+ SyncEventTypes = {
23999
+ SYNC_PENDING: 20001,
24000
+ SYNC_SUCCEEDED: 20002,
24001
+ SYNC_FAILED: 20003,
24002
+ DEAD_LETTER_ADDED: 20004,
24003
+ CONNECTION_STATE_CHANGED: 20005
24004
+ };
24005
+ MailboxAggregateError = class MailboxAggregateError extends Error {
24006
+ errors;
24007
+ constructor(errors2) {
24008
+ const messages = errors2.map((e) => e.message).join("; ");
24009
+ super(`Mailbox callback failed with ${errors2.length} error(s): ${messages}`);
24010
+ this.name = "MailboxAggregateError";
24011
+ this.errors = errors2;
24012
+ }
24013
+ };
24014
+ ChannelError = class ChannelError extends Error {
24015
+ source;
24016
+ error;
24017
+ constructor(source, error) {
24018
+ super(`ChannelError[${source}]: ${error.message}`);
24019
+ this.name = "ChannelError";
24020
+ this.source = source;
24021
+ this.error = error;
24022
+ }
24023
+ };
24024
+ SyncOperationAggregateError = class SyncOperationAggregateError extends Error {
24025
+ errors;
24026
+ constructor(errors2) {
24027
+ const messages = errors2.map((e) => e.message).join("; ");
24028
+ super(`SyncOperation callback failed with ${errors2.length} error(s): ${messages}`);
24029
+ this.name = "SyncOperationAggregateError";
24030
+ this.errors = errors2;
24031
+ }
24032
+ };
24033
+ DEFAULT_CONFIG = {
24034
+ intervalMs: 2000,
24035
+ maxQueueDepth: 100,
24036
+ backpressureCheckIntervalMs: 500,
24037
+ retryBaseDelayMs: 1000,
24038
+ retryMaxDelayMs: 300000
23832
24039
  };
23833
24040
  ((SyncStatus2) => {
23834
24041
  SyncStatus2["Synced"] = "SYNCED";
@@ -23946,6 +24153,8 @@ __export(exports_src, {
23946
24153
  useDocumentById: () => useDocumentById,
23947
24154
  useDocument: () => useDocument,
23948
24155
  useDefaultDriveEditorModule: () => useDefaultDriveEditorModule,
24156
+ useConnectionStates: () => useConnectionStates,
24157
+ useConnectionState: () => useConnectionState,
23949
24158
  useAllowedDocumentTypes: () => useAllowedDocumentTypes,
23950
24159
  useAllowedDocumentModelModules: () => useAllowedDocumentModelModules,
23951
24160
  truncateAllTables: () => dropAllTables,
@@ -24052,6 +24261,7 @@ __export(exports_src, {
24052
24261
  RemoteDocumentController: () => RemoteDocumentController,
24053
24262
  RemoteClient: () => RemoteClient,
24054
24263
  RelationalDbProcessor: () => RelationalDbProcessor,
24264
+ RegistryClient: () => RegistryClient,
24055
24265
  ReactorClientDocumentCache: () => ReactorClientDocumentCache,
24056
24266
  ReactorClientBuilder: () => ReactorClientBuilder,
24057
24267
  ReactorBuilder: () => ReactorBuilder,
@@ -24115,14 +24325,15 @@ import {
24115
24325
  import { documentModelDocumentModelModule } from "document-model";
24116
24326
  import { useSyncExternalStore } from "react";
24117
24327
  import { useSyncExternalStore as useSyncExternalStore2 } from "react";
24328
+ import { useEffect, useRef, useState } from "react";
24118
24329
  import { logger as logger5 } from "document-drive";
24119
- import { use, useCallback, useSyncExternalStore as useSyncExternalStore3 } from "react";
24120
- import { useEffect, useState } from "react";
24330
+ import { use, useCallback as useCallback2, useSyncExternalStore as useSyncExternalStore3 } from "react";
24331
+ import { useEffect as useEffect2, useState as useState2 } from "react";
24121
24332
  import {
24122
24333
  DocumentModelNotFoundError,
24123
24334
  DocumentNotFoundError as DocumentNotFoundError2
24124
24335
  } from "document-drive";
24125
- import { useCallback as useCallback2, useEffect as useEffect2, useRef, useState as useState2 } from "react";
24336
+ import { useCallback as useCallback3, useEffect as useEffect3, useRef as useRef2, useState as useState3 } from "react";
24126
24337
  import { isFileNode as isFileNode2 } from "document-drive";
24127
24338
  import { useMemo } from "react";
24128
24339
  import {
@@ -24133,19 +24344,19 @@ import {
24133
24344
  import { createState } from "document-model";
24134
24345
  import { defaultBaseState as defaultBaseState2, generateId as generateId22 } from "document-model/core";
24135
24346
  import { logger as logger6 } from "document-drive";
24136
- import { useEffect as useEffect3, useState as useState3 } from "react";
24137
24347
  import { useEffect as useEffect4, useState as useState4 } from "react";
24348
+ import { useEffect as useEffect5, useState as useState5 } from "react";
24138
24349
  import { createRelationalDbLegacy } from "document-drive";
24139
24350
  import { useMemo as useMemo2 } from "react";
24140
- import { useEffect as useEffect5, useRef as useRef2, useState as useState5 } from "react";
24141
- import { useCallback as useCallback3, useMemo as useMemo3, useRef as useRef3 } from "react";
24142
- import { useCallback as useCallback4, useEffect as useEffect6, useRef as useRef4, useState as useState6 } from "react";
24351
+ import { useEffect as useEffect6, useRef as useRef3, useState as useState6 } from "react";
24352
+ import { useCallback as useCallback4, useMemo as useMemo3, useRef as useRef4 } from "react";
24353
+ import { useCallback as useCallback5, useEffect as useEffect7, useRef as useRef5, useState as useState7 } from "react";
24143
24354
  import { jsxDEV } from "react/jsx-dev-runtime";
24144
24355
  import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
24145
- import { useCallback as useCallback5, useEffect as useEffect7, useRef as useRef5, useState as useState7 } from "react";
24356
+ import { useCallback as useCallback6, useEffect as useEffect8, useRef as useRef6, useState as useState8 } from "react";
24146
24357
  import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
24147
24358
  import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
24148
- import { useEffect as useEffect8, useRef as useRef6 } from "react";
24359
+ import { useEffect as useEffect9, useRef as useRef7 } from "react";
24149
24360
  function asUint8Array(buf) {
24150
24361
  if (globalThis.Buffer != null) {
24151
24362
  return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
@@ -27577,6 +27788,52 @@ function useAllowedDocumentModelModules() {
27577
27788
  return documentModelModules;
27578
27789
  return documentModelModules?.filter((module) => allowedDocumentTypes.includes(module.documentModel.global.id));
27579
27790
  }
27791
+ function useConnectionStates() {
27792
+ const syncManager = useSync();
27793
+ const [states, setStates] = useState(() => buildSnapshot(syncManager));
27794
+ const unsubscribesRef = useRef([]);
27795
+ useEffect(() => {
27796
+ if (!syncManager)
27797
+ return;
27798
+ function subscribe() {
27799
+ for (const unsub of unsubscribesRef.current) {
27800
+ unsub();
27801
+ }
27802
+ unsubscribesRef.current = [];
27803
+ const remotes = syncManager.list();
27804
+ for (const remote of remotes) {
27805
+ const unsub = remote.channel.onConnectionStateChange(() => {
27806
+ setStates(buildSnapshot(syncManager));
27807
+ });
27808
+ unsubscribesRef.current.push(unsub);
27809
+ }
27810
+ setStates(buildSnapshot(syncManager));
27811
+ }
27812
+ subscribe();
27813
+ const interval = setInterval(subscribe, 5000);
27814
+ return () => {
27815
+ clearInterval(interval);
27816
+ for (const unsub of unsubscribesRef.current) {
27817
+ unsub();
27818
+ }
27819
+ unsubscribesRef.current = [];
27820
+ };
27821
+ }, [syncManager]);
27822
+ return states;
27823
+ }
27824
+ function useConnectionState(remoteName) {
27825
+ const states = useConnectionStates();
27826
+ return states.get(remoteName);
27827
+ }
27828
+ function buildSnapshot(syncManager) {
27829
+ const map = new Map;
27830
+ if (!syncManager)
27831
+ return map;
27832
+ for (const remote of syncManager.list()) {
27833
+ map.set(remote.name, remote.channel.getConnectionState());
27834
+ }
27835
+ return map;
27836
+ }
27580
27837
  function sortNodesByName(nodes) {
27581
27838
  return nodes.toSorted((a, b) => a.name.localeCompare(b.name));
27582
27839
  }
@@ -27634,7 +27891,7 @@ function useDocuments(ids) {
27634
27891
  }
27635
27892
  function useGetDocument() {
27636
27893
  const documentCache = useDocumentCache();
27637
- return useCallback((id) => {
27894
+ return useCallback2((id) => {
27638
27895
  if (!documentCache) {
27639
27896
  return Promise.reject(new Error("Document cache not initialized"));
27640
27897
  }
@@ -27643,7 +27900,7 @@ function useGetDocument() {
27643
27900
  }
27644
27901
  function useGetDocuments() {
27645
27902
  const documentCache = useDocumentCache();
27646
- return useCallback((ids) => {
27903
+ return useCallback2((ids) => {
27647
27904
  if (!documentCache) {
27648
27905
  return Promise.reject(new Error("Document cache not initialized"));
27649
27906
  }
@@ -27945,8 +28202,8 @@ function setPHDocumentEditorConfig(config) {
27945
28202
  }
27946
28203
  }
27947
28204
  function useSetPHDriveEditorConfig(config) {
27948
- const [isInitialized, setIsInitialized] = useState(false);
27949
- useEffect(() => {
28205
+ const [isInitialized, setIsInitialized] = useState2(false);
28206
+ useEffect2(() => {
27950
28207
  if (isInitialized)
27951
28208
  return;
27952
28209
  setPHDriveEditorConfig(config);
@@ -27954,8 +28211,8 @@ function useSetPHDriveEditorConfig(config) {
27954
28211
  }, [config, isInitialized]);
27955
28212
  }
27956
28213
  function useSetPHDocumentEditorConfig(config) {
27957
- const [isInitialized, setIsInitialized] = useState(false);
27958
- useEffect(() => {
28214
+ const [isInitialized, setIsInitialized] = useState2(false);
28215
+ useEffect2(() => {
27959
28216
  if (isInitialized)
27960
28217
  return;
27961
28218
  setPHDocumentEditorConfig(config);
@@ -27988,14 +28245,14 @@ function useDocumentOfType(documentId, documentType) {
27988
28245
  }
27989
28246
  function useDocumentOperations(documentId) {
27990
28247
  const reactorClient = useReactorClient();
27991
- const hasFetchedRef = useRef(false);
27992
- const [state, setState] = useState2(() => ({
28248
+ const hasFetchedRef = useRef2(false);
28249
+ const [state, setState] = useState3(() => ({
27993
28250
  globalOperations: [],
27994
28251
  localOperations: [],
27995
28252
  isLoading: !!documentId,
27996
28253
  error: undefined
27997
28254
  }));
27998
- const fetchOperations = useCallback2(async (retryCount = 0) => {
28255
+ const fetchOperations = useCallback3(async (retryCount = 0) => {
27999
28256
  const MAX_RETRIES = 5;
28000
28257
  const RETRY_DELAY_MS = 500;
28001
28258
  if (!documentId || !reactorClient) {
@@ -28041,7 +28298,7 @@ function useDocumentOperations(documentId) {
28041
28298
  });
28042
28299
  hasFetchedRef.current = true;
28043
28300
  }, [documentId, reactorClient]);
28044
- useEffect2(() => {
28301
+ useEffect3(() => {
28045
28302
  if (documentId && reactorClient) {
28046
28303
  fetchOperations();
28047
28304
  } else if (!documentId) {
@@ -28054,7 +28311,7 @@ function useDocumentOperations(documentId) {
28054
28311
  hasFetchedRef.current = false;
28055
28312
  }
28056
28313
  }, [documentId, reactorClient, fetchOperations]);
28057
- const refetch = useCallback2(() => {
28314
+ const refetch = useCallback3(() => {
28058
28315
  fetchOperations(0);
28059
28316
  }, [fetchOperations]);
28060
28317
  return { ...state, refetch };
@@ -28556,8 +28813,8 @@ async function logout() {
28556
28813
  }
28557
28814
  function useUser() {
28558
28815
  const renown = useRenown();
28559
- const [user, setUser] = useState3(() => renown?.user);
28560
- useEffect3(() => {
28816
+ const [user, setUser] = useState4(() => renown?.user);
28817
+ useEffect4(() => {
28561
28818
  setUser(renown?.user);
28562
28819
  if (!renown)
28563
28820
  return;
@@ -28567,8 +28824,8 @@ function useUser() {
28567
28824
  }
28568
28825
  function useLoginStatus() {
28569
28826
  const renown = useRenown();
28570
- const [status, setStatus] = useState3(() => renown ? renown.status : "initializing");
28571
- useEffect3(() => {
28827
+ const [status, setStatus] = useState4(() => renown ? renown.status : "initializing");
28828
+ useEffect4(() => {
28572
28829
  setStatus(renown ? renown.status : "initializing");
28573
28830
  if (!renown)
28574
28831
  return;
@@ -28670,6 +28927,7 @@ async function loadExternalPackage(name4, registryUrl) {
28670
28927
  class BrowserPackageManager {
28671
28928
  #storage;
28672
28929
  #packages = new Map;
28930
+ #localPackageIds = new Set;
28673
28931
  #subscribers = new Set;
28674
28932
  #packagesMemo = [];
28675
28933
  constructor(namespace) {
@@ -28690,6 +28948,9 @@ class BrowserPackageManager {
28690
28948
  get packages() {
28691
28949
  return this.#packagesMemo;
28692
28950
  }
28951
+ get localPackageIds() {
28952
+ return new Set(this.#localPackageIds);
28953
+ }
28693
28954
  async addPackage(name4, registryUrl) {
28694
28955
  const module = await loadExternalPackage(name4, registryUrl);
28695
28956
  this.#packages.set(name4, module);
@@ -28706,6 +28967,7 @@ class BrowserPackageManager {
28706
28967
  }
28707
28968
  async addLocalPackage(name4, localPackage) {
28708
28969
  this.#packages.set(name4, localPackage);
28970
+ this.#localPackageIds.add(localPackage.id);
28709
28971
  this.#notifyPackagesChanged();
28710
28972
  }
28711
28973
  async removePackage(name4) {
@@ -28754,6 +29016,40 @@ async function dropAllReactorStorage(pg) {
28754
29016
  await dropTablesInSchema(pg, REACTOR_SCHEMA);
28755
29017
  await dropTablesInSchema(pg, "public");
28756
29018
  }
29019
+ function cdnUrlToApiUrl(cdnUrl) {
29020
+ return cdnUrl.replace(/\/-\/cdn\/?$/, "");
29021
+ }
29022
+ function mapPackageInfo(pkg) {
29023
+ return {
29024
+ name: pkg.name,
29025
+ description: pkg.manifest?.description,
29026
+ version: pkg.manifest?.version,
29027
+ category: pkg.manifest?.category,
29028
+ publisher: pkg.manifest?.publisher?.name,
29029
+ publisherUrl: pkg.manifest?.publisher?.url
29030
+ };
29031
+ }
29032
+
29033
+ class RegistryClient {
29034
+ apiUrl;
29035
+ constructor(cdnUrl) {
29036
+ this.apiUrl = cdnUrlToApiUrl(cdnUrl);
29037
+ }
29038
+ async getPackages() {
29039
+ const res = await fetch(`${this.apiUrl}/packages`);
29040
+ if (!res.ok)
29041
+ throw new Error(`Registry error: HTTP ${res.status}`);
29042
+ const data = await res.json();
29043
+ return data.map(mapPackageInfo);
29044
+ }
29045
+ async searchPackages(query) {
29046
+ const packages = await this.getPackages();
29047
+ if (!query)
29048
+ return packages;
29049
+ const lowerQuery = query.toLowerCase();
29050
+ return packages.filter((pkg) => pkg.name.toLowerCase().includes(lowerQuery) || pkg.description?.toLowerCase().includes(lowerQuery));
29051
+ }
29052
+ }
28757
29053
 
28758
29054
  class ReactorClientDocumentCache {
28759
29055
  client;
@@ -40191,11 +40487,11 @@ function createRelationalDbWithLive(pgliteInstance) {
40191
40487
  return relationalDBWithLive;
40192
40488
  }
40193
40489
  function useRelationalQuery(ProcessorClass, driveId, queryCallback, parameters, options) {
40194
- const [result, setResult] = useState5(null);
40195
- const [queryLoading, setQueryLoading] = useState5(true);
40196
- const [error, setError] = useState5(undefined);
40197
- const retryCount = useRef2(0);
40198
- const retryTimeoutRef = useRef2(null);
40490
+ const [result, setResult] = useState6(null);
40491
+ const [queryLoading, setQueryLoading] = useState6(true);
40492
+ const [error, setError] = useState6(undefined);
40493
+ const retryCount = useRef3(0);
40494
+ const retryTimeoutRef = useRef3(null);
40199
40495
  const relationalDb = useRelationalDb();
40200
40496
  const executeLiveQuery = async (sql22, queryParameters, retryAttempt = 0) => {
40201
40497
  if (!relationalDb.db) {
@@ -40221,7 +40517,7 @@ function useRelationalQuery(ProcessorClass, driveId, queryCallback, parameters,
40221
40517
  return null;
40222
40518
  }
40223
40519
  };
40224
- useEffect5(() => {
40520
+ useEffect6(() => {
40225
40521
  setError(undefined);
40226
40522
  setQueryLoading(true);
40227
40523
  retryCount.current = 0;
@@ -40251,7 +40547,7 @@ function useRelationalQuery(ProcessorClass, driveId, queryCallback, parameters,
40251
40547
  };
40252
40548
  }
40253
40549
  function useStableParams(params) {
40254
- const prevParamsRef = useRef3(null);
40550
+ const prevParamsRef = useRef4(null);
40255
40551
  return useMemo3(() => {
40256
40552
  if (!import_lodash.default(prevParamsRef.current, params)) {
40257
40553
  prevParamsRef.current = params;
@@ -40262,7 +40558,7 @@ function useStableParams(params) {
40262
40558
  function createProcessorQuery(ProcessorClass) {
40263
40559
  function useQuery(driveId, queryCallback, parameters, options) {
40264
40560
  const stableParams = useStableParams(parameters);
40265
- const memoizedCallback = useCallback3(queryCallback, [stableParams]);
40561
+ const memoizedCallback = useCallback4(queryCallback, [stableParams]);
40266
40562
  return useRelationalQuery(ProcessorClass, driveId, memoizedCallback, stableParams, options);
40267
40563
  }
40268
40564
  return useQuery;
@@ -40966,20 +41262,20 @@ function RenownLoginButton({
40966
41262
  showPopover = false
40967
41263
  }) {
40968
41264
  const onLogin = onLoginProp ?? (() => openRenown());
40969
- const [isOpen, setIsOpen] = useState6(false);
40970
- const [isLoading, setIsLoading] = useState6(false);
40971
- const [isHovered, setIsHovered] = useState6(false);
40972
- const [showAbove, setShowAbove] = useState6(true);
40973
- const wrapperRef = useRef4(null);
40974
- const closeTimeoutRef = useRef4(null);
40975
- const calculatePosition = useCallback4(() => {
41265
+ const [isOpen, setIsOpen] = useState7(false);
41266
+ const [isLoading, setIsLoading] = useState7(false);
41267
+ const [isHovered, setIsHovered] = useState7(false);
41268
+ const [showAbove, setShowAbove] = useState7(true);
41269
+ const wrapperRef = useRef5(null);
41270
+ const closeTimeoutRef = useRef5(null);
41271
+ const calculatePosition = useCallback5(() => {
40976
41272
  if (!wrapperRef.current)
40977
41273
  return;
40978
41274
  const rect = wrapperRef.current.getBoundingClientRect();
40979
41275
  const spaceAbove = rect.top;
40980
41276
  setShowAbove(spaceAbove >= POPOVER_HEIGHT + POPOVER_GAP);
40981
41277
  }, []);
40982
- const handleMouseEnter = useCallback4(() => {
41278
+ const handleMouseEnter = useCallback5(() => {
40983
41279
  setIsHovered(true);
40984
41280
  if (!showPopover)
40985
41281
  return;
@@ -40990,13 +41286,13 @@ function RenownLoginButton({
40990
41286
  calculatePosition();
40991
41287
  setIsOpen(true);
40992
41288
  }, [calculatePosition, showPopover]);
40993
- const handleMouseLeave = useCallback4(() => {
41289
+ const handleMouseLeave = useCallback5(() => {
40994
41290
  closeTimeoutRef.current = setTimeout(() => {
40995
41291
  setIsOpen(false);
40996
41292
  setIsHovered(false);
40997
41293
  }, 150);
40998
41294
  }, []);
40999
- useEffect6(() => {
41295
+ useEffect7(() => {
41000
41296
  return () => {
41001
41297
  if (closeTimeoutRef.current) {
41002
41298
  clearTimeout(closeTimeoutRef.current);
@@ -41105,19 +41401,19 @@ function RenownUserButton({
41105
41401
  const avatarUrl = avatarUrlProp ?? user?.ens?.avatarUrl;
41106
41402
  const userId = userIdProp ?? user?.profile?.documentId;
41107
41403
  const onDisconnect = onDisconnectProp ?? (() => void logout());
41108
- const [isOpen, setIsOpen] = useState7(false);
41109
- const [isCopied, setIsCopied] = useState7(false);
41110
- const [showAbove, setShowAbove] = useState7(true);
41111
- const wrapperRef = useRef5(null);
41112
- const closeTimeoutRef = useRef5(null);
41113
- const calculatePosition = useCallback5(() => {
41404
+ const [isOpen, setIsOpen] = useState8(false);
41405
+ const [isCopied, setIsCopied] = useState8(false);
41406
+ const [showAbove, setShowAbove] = useState8(true);
41407
+ const wrapperRef = useRef6(null);
41408
+ const closeTimeoutRef = useRef6(null);
41409
+ const calculatePosition = useCallback6(() => {
41114
41410
  if (!wrapperRef.current)
41115
41411
  return;
41116
41412
  const rect = wrapperRef.current.getBoundingClientRect();
41117
41413
  const spaceAbove = rect.top;
41118
41414
  setShowAbove(spaceAbove >= POPOVER_HEIGHT2 + POPOVER_GAP2);
41119
41415
  }, []);
41120
- const handleMouseEnter = useCallback5(() => {
41416
+ const handleMouseEnter = useCallback6(() => {
41121
41417
  if (closeTimeoutRef.current) {
41122
41418
  clearTimeout(closeTimeoutRef.current);
41123
41419
  closeTimeoutRef.current = null;
@@ -41125,19 +41421,19 @@ function RenownUserButton({
41125
41421
  calculatePosition();
41126
41422
  setIsOpen(true);
41127
41423
  }, [calculatePosition]);
41128
- const handleMouseLeave = useCallback5(() => {
41424
+ const handleMouseLeave = useCallback6(() => {
41129
41425
  closeTimeoutRef.current = setTimeout(() => {
41130
41426
  setIsOpen(false);
41131
41427
  }, 150);
41132
41428
  }, []);
41133
- useEffect7(() => {
41429
+ useEffect8(() => {
41134
41430
  return () => {
41135
41431
  if (closeTimeoutRef.current) {
41136
41432
  clearTimeout(closeTimeoutRef.current);
41137
41433
  }
41138
41434
  };
41139
41435
  }, []);
41140
- const copyToClipboard = useCallback5(async () => {
41436
+ const copyToClipboard = useCallback6(async () => {
41141
41437
  try {
41142
41438
  await navigator.clipboard.writeText(address);
41143
41439
  setIsCopied(true);
@@ -41330,8 +41626,8 @@ function RenownProvider({
41330
41626
  baseUrl,
41331
41627
  children
41332
41628
  }) {
41333
- const initRef = useRef6(false);
41334
- const initialPropsRef = useRef6({ appName, basename, baseUrl });
41629
+ const initRef = useRef7(false);
41630
+ const initialPropsRef = useRef7({ appName, basename, baseUrl });
41335
41631
  if (initRef.current) {
41336
41632
  const initial = initialPropsRef.current;
41337
41633
  if (appName !== initial.appName) {
@@ -41344,7 +41640,7 @@ function RenownProvider({
41344
41640
  console.warn("RenownProvider: 'baseUrl' changed after mount. This prop is only read once during initialization.");
41345
41641
  }
41346
41642
  }
41347
- useEffect8(() => {
41643
+ useEffect9(() => {
41348
41644
  if (initRef.current)
41349
41645
  return;
41350
41646
  initRef.current = true;
@@ -41929,10 +42225,10 @@ ${String(result)}`);
41929
42225
  }, docCache, fragmentSourceMap, printFragmentWarnings = true, experimentalFragmentVariables = false, extras, PropagationMode2, PhDocumentFieldsFragmentDoc, GetDocumentModelsDocument, GetDocumentDocument, GetDocumentChildrenDocument, GetDocumentParentsDocument, FindDocumentsDocument, GetDocumentOperationsDocument, GetJobStatusDocument, CreateDocumentDocument, CreateEmptyDocumentDocument, MutateDocumentDocument, MutateDocumentAsyncDocument, RenameDocumentDocument, AddChildrenDocument, RemoveChildrenDocument, MoveChildrenDocument, DeleteDocumentDocument, DeleteDocumentsDocument, DocumentChangesDocument, JobChangesDocument, PollSyncEnvelopesDocument, TouchChannelDocument, PushSyncEnvelopesDocument, defaultWrapper = (action, _operationName, _operationType, _variables) => action(), SPLIT_LOWER_UPPER_RE, SPLIT_UPPER_UPPER_RE, SPLIT_SEPARATE_NUMBER_RE, DEFAULT_STRIP_REGEXP, SPLIT_REPLACE_VALUE = "$1\x00$2", DEFAULT_PREFIX_SUFFIX_CHARACTERS = "", isExternalControlsEnabledEventFunctions, setIsExternalControlsEnabled, useIsExternalControlsEnabled, addIsExternalControlsEnabledEventHandler, isDragAndDropEnabledEventFunctions, setIsDragAndDropEnabled, useIsDragAndDropEnabled, addIsDragAndDropEnabledEventHandler, allowedDocumentTypesEventFunctions, setAllowedDocumentTypes, addAllowedDocumentTypesEventHandler, phDriveEditorConfigSetters, phDocumentEditorConfigSetters, phDriveEditorConfigHooks, phDocumentEditorConfigHooks, vetraPackageManagerFunctions, useVetraPackageManager, useVetraPackages = () => {
41930
42226
  const packageManager = useVetraPackageManager();
41931
42227
  return useSyncExternalStore2((cb) => packageManager ? packageManager.subscribe(cb) : () => {}, () => packageManager?.packages ?? []);
41932
- }, addVetraPackageManagerEventHandler, documentEventFunctions, useDocumentCache, setDocumentCache, addDocumentCacheEventHandler, base64, locales, defaultLocale, initialMulticharmap, initialCharmap, slug_default, drivesEventFunctions, useDrives, setDrives, addDrivesEventHandler, selectedDriveIdEventFunctions, useSelectedDriveId, setSelectedDriveId, addSelectedDriveIdEventHandler, selectedNodeIdEventFunctions, useSelectedNodeId, setSelectedNodeId, addSelectedNodeIdEventHandler, useRouterBasename, setRouterBasename, addRouterBasenameEventHandler, useVersion, setVersion, addVersionEventHandler, useRequiresHardRefresh, setRequiresHardRefresh, addRequiresHardRefreshEventHandler, useWarnOutdatedApp, setWarnOutdatedApp, addWarnOutdatedAppEventHandler, useStudioMode, setStudioMode, addStudioModeEventHandler, useBasePath, setBasePath, addBasePathEventHandler, useVersionCheckInterval, setVersionCheckInterval, addVersionCheckIntervalEventHandler, useCliVersion, setCliVersion, addCliVersionEventHandler, useFileUploadOperationsChunkSize, setFileUploadOperationsChunkSize, addFileUploadOperationsChunkSizeEventHandler, useIsDocumentModelSelectionSettingsEnabled, setIsDocumentModelSelectionSettingsEnabled, addIsDocumentModelSelectionSettingsEnabledEventHandler, useGaTrackingId, setGaTrackingId, addGaTrackingIdEventHandler, useDefaultDrivesUrl, setDefaultDrivesUrl, addDefaultDrivesUrlEventHandler, useDrivesPreserveStrategy, setDrivesPreserveStrategy, addDrivesPreserveStrategyEventHandler, useIsLocalDrivesEnabled, setIsLocalDrivesEnabled, addIsLocalDrivesEnabledEventHandler, useIsAddDriveEnabled, setIsAddDriveEnabled, addIsAddDriveEnabledEventHandler, useIsPublicDrivesEnabled, setIsPublicDrivesEnabled, addIsPublicDrivesEnabledEventHandler, useIsAddPublicDrivesEnabled, setIsAddPublicDrivesEnabled, addIsAddPublicDrivesEnabledEventHandler, useIsDeletePublicDrivesEnabled, setIsDeletePublicDrivesEnabled, addIsDeletePublicDrivesEnabledEventHandler, useIsCloudDrivesEnabled, setIsCloudDrivesEnabled, addIsCloudDrivesEnabledEventHandler, useIsAddCloudDrivesEnabled, setIsAddCloudDrivesEnabled, addIsAddCloudDrivesEnabledEventHandler, useIsDeleteCloudDrivesEnabled, setIsDeleteCloudDrivesEnabled, addIsDeleteCloudDrivesEnabledEventHandler, useLocalDrivesEnabled, setLocalDrivesEnabled, addLocalDrivesEnabledEventHandler, useIsAddLocalDrivesEnabled, setIsAddLocalDrivesEnabled, addIsAddLocalDrivesEnabledEventHandler, useIsDeleteLocalDrivesEnabled, setIsDeleteLocalDrivesEnabled, addIsDeleteLocalDrivesEnabledEventHandler, useIsEditorDebugModeEnabled, setIsEditorDebugModeEnabled, addIsEditorDebugModeEnabledEventHandler, useIsEditorReadModeEnabled, setIsEditorReadModeEnabled, addIsEditorReadModeEnabledEventHandler, useIsAnalyticsDatabaseWorkerEnabled, setIsAnalyticsDatabaseWorkerEnabled, addIsAnalyticsDatabaseWorkerEnabledEventHandler, useIsDiffAnalyticsEnabled, setIsDiffAnalyticsEnabled, addIsDiffAnalyticsEnabledEventHandler, useIsDriveAnalyticsEnabled, setIsDriveAnalyticsEnabled, addIsDriveAnalyticsEnabledEventHandler, useRenownUrl, setRenownUrl, addRenownUrlEventHandler, useRenownNetworkId, setRenownNetworkId, addRenownNetworkIdEventHandler, useRenownChainId, setRenownChainId, addRenownChainIdEventHandler, useSentryRelease, setSentryRelease, addSentryReleaseEventHandler, useSentryDsn, setSentryDsn, addSentryDsnEventHandler, useSentryEnv, setSentryEnv, addSentryEnvEventHandler, useIsSentryTracingEnabled, setIsSentryTracingEnabled, addIsSentryTracingEnabledEventHandler, useIsExternalProcessorsEnabled, setIsExternalProcessorsEnabled, addIsExternalProcessorsEnabledEventHandler, useIsExternalPackagesEnabled, setIsExternalPackagesEnabled, addIsExternalPackagesEnabledEventHandler, enabledEditorsEventFunctions, setEnabledEditors, useEnabledEditors, addEnabledEditorsEventHandler, disabledEditorsEventFunctions, setDisabledEditors, useDisabledEditors, addDisabledEditorsEventHandler, isRelationalProcessorsEnabled, setIsRelationalProcessorsEnabled, useIsRelationalProcessorsEnabled, addIsRelationalProcessorsEnabledEventHandler, isExternalRelationalProcessorsEnabled, setIsExternalRelationalProcessorsEnabled, useIsExternalRelationalProcessorsEnabled, addIsExternalRelationalProcessorsEnabledEventHandler, isAnalyticsEnabledEventFunctions, setIsAnalyticsEnabled, useIsAnalyticsEnabled, addIsAnalyticsEnabledEventHandler, isAnalyticsExternalProcessorsEnabled, setIsAnalyticsExternalProcessorsEnabled, useIsAnalyticsExternalProcessorsEnabled, addIsAnalyticsExternalProcessorsEnabledEventHandler, analyticsDatabaseNameEventFunctions, setAnalyticsDatabaseName, useAnalyticsDatabaseName, addAnalyticsDatabaseNameEventHandler, logLevelEventFunctions, setLogLevel2, useLogLevel, addLogLevelEventHandler, allowListEventFunctions, setAllowList, useAllowList, addAllowListEventHandler, nonUserConfigSetters, phGlobalConfigSetters, nonUserConfigHooks, phGlobalConfigHooks, reactorClientModuleEventFunctions, reactorClientEventFunctions, useReactorClientModule, setReactorClientModule, addReactorClientModuleEventHandler, useReactorClient, setReactorClient, addReactorClientEventHandler, useSync = () => useReactorClientModule()?.reactorModule?.syncModule?.syncManager, useSyncList = () => {
42228
+ }, addVetraPackageManagerEventHandler, reactorClientModuleEventFunctions, reactorClientEventFunctions, useReactorClientModule, setReactorClientModule, addReactorClientModuleEventHandler, useReactorClient, setReactorClient, addReactorClientEventHandler, useSync = () => useReactorClientModule()?.reactorModule?.syncModule?.syncManager, useSyncList = () => {
41933
42229
  const sync = useSync();
41934
42230
  return sync?.list() ?? [];
41935
- }, featuresEventFunctions, useFeatures, setFeatures, addFeaturesEventHandler, modalEventFunctions, usePHModal, setPHModal, addModalEventHandler, revisionHistoryEventFunctions, useRevisionHistoryVisible, setRevisionHistoryVisible, addRevisionHistoryVisibleEventHandler, selectedTimelineItemEventFunctions, useSelectedTimelineItem, setSelectedTimelineItem, addSelectedTimelineItemEventHandler, selectedTimelineRevisionEventFunctions, useSelectedTimelineRevision, setSelectedTimelineRevision, addSelectedTimelineRevisionEventHandler, toastEventFunctions, usePHToast, setPHToast, addToastEventHandler, FEATURE_INSPECTOR_ENABLED = "FEATURE_INSPECTOR_ENABLED", FEATURE_INSPECTOR_ENABLED_DEFAULT = false, syncStatusToUI, validateDocument = (document2) => {
42231
+ }, documentEventFunctions, useDocumentCache, setDocumentCache, addDocumentCacheEventHandler, base64, locales, defaultLocale, initialMulticharmap, initialCharmap, slug_default, drivesEventFunctions, useDrives, setDrives, addDrivesEventHandler, selectedDriveIdEventFunctions, useSelectedDriveId, setSelectedDriveId, addSelectedDriveIdEventHandler, selectedNodeIdEventFunctions, useSelectedNodeId, setSelectedNodeId, addSelectedNodeIdEventHandler, useRouterBasename, setRouterBasename, addRouterBasenameEventHandler, useVersion, setVersion, addVersionEventHandler, useRequiresHardRefresh, setRequiresHardRefresh, addRequiresHardRefreshEventHandler, useWarnOutdatedApp, setWarnOutdatedApp, addWarnOutdatedAppEventHandler, useStudioMode, setStudioMode, addStudioModeEventHandler, useBasePath, setBasePath, addBasePathEventHandler, useVersionCheckInterval, setVersionCheckInterval, addVersionCheckIntervalEventHandler, useCliVersion, setCliVersion, addCliVersionEventHandler, useFileUploadOperationsChunkSize, setFileUploadOperationsChunkSize, addFileUploadOperationsChunkSizeEventHandler, useIsDocumentModelSelectionSettingsEnabled, setIsDocumentModelSelectionSettingsEnabled, addIsDocumentModelSelectionSettingsEnabledEventHandler, useGaTrackingId, setGaTrackingId, addGaTrackingIdEventHandler, useDefaultDrivesUrl, setDefaultDrivesUrl, addDefaultDrivesUrlEventHandler, useDrivesPreserveStrategy, setDrivesPreserveStrategy, addDrivesPreserveStrategyEventHandler, useIsLocalDrivesEnabled, setIsLocalDrivesEnabled, addIsLocalDrivesEnabledEventHandler, useIsAddDriveEnabled, setIsAddDriveEnabled, addIsAddDriveEnabledEventHandler, useIsPublicDrivesEnabled, setIsPublicDrivesEnabled, addIsPublicDrivesEnabledEventHandler, useIsAddPublicDrivesEnabled, setIsAddPublicDrivesEnabled, addIsAddPublicDrivesEnabledEventHandler, useIsDeletePublicDrivesEnabled, setIsDeletePublicDrivesEnabled, addIsDeletePublicDrivesEnabledEventHandler, useIsCloudDrivesEnabled, setIsCloudDrivesEnabled, addIsCloudDrivesEnabledEventHandler, useIsAddCloudDrivesEnabled, setIsAddCloudDrivesEnabled, addIsAddCloudDrivesEnabledEventHandler, useIsDeleteCloudDrivesEnabled, setIsDeleteCloudDrivesEnabled, addIsDeleteCloudDrivesEnabledEventHandler, useLocalDrivesEnabled, setLocalDrivesEnabled, addLocalDrivesEnabledEventHandler, useIsAddLocalDrivesEnabled, setIsAddLocalDrivesEnabled, addIsAddLocalDrivesEnabledEventHandler, useIsDeleteLocalDrivesEnabled, setIsDeleteLocalDrivesEnabled, addIsDeleteLocalDrivesEnabledEventHandler, useIsEditorDebugModeEnabled, setIsEditorDebugModeEnabled, addIsEditorDebugModeEnabledEventHandler, useIsEditorReadModeEnabled, setIsEditorReadModeEnabled, addIsEditorReadModeEnabledEventHandler, useIsAnalyticsDatabaseWorkerEnabled, setIsAnalyticsDatabaseWorkerEnabled, addIsAnalyticsDatabaseWorkerEnabledEventHandler, useIsDiffAnalyticsEnabled, setIsDiffAnalyticsEnabled, addIsDiffAnalyticsEnabledEventHandler, useIsDriveAnalyticsEnabled, setIsDriveAnalyticsEnabled, addIsDriveAnalyticsEnabledEventHandler, useRenownUrl, setRenownUrl, addRenownUrlEventHandler, useRenownNetworkId, setRenownNetworkId, addRenownNetworkIdEventHandler, useRenownChainId, setRenownChainId, addRenownChainIdEventHandler, useSentryRelease, setSentryRelease, addSentryReleaseEventHandler, useSentryDsn, setSentryDsn, addSentryDsnEventHandler, useSentryEnv, setSentryEnv, addSentryEnvEventHandler, useIsSentryTracingEnabled, setIsSentryTracingEnabled, addIsSentryTracingEnabledEventHandler, useIsExternalProcessorsEnabled, setIsExternalProcessorsEnabled, addIsExternalProcessorsEnabledEventHandler, useIsExternalPackagesEnabled, setIsExternalPackagesEnabled, addIsExternalPackagesEnabledEventHandler, enabledEditorsEventFunctions, setEnabledEditors, useEnabledEditors, addEnabledEditorsEventHandler, disabledEditorsEventFunctions, setDisabledEditors, useDisabledEditors, addDisabledEditorsEventHandler, isRelationalProcessorsEnabled, setIsRelationalProcessorsEnabled, useIsRelationalProcessorsEnabled, addIsRelationalProcessorsEnabledEventHandler, isExternalRelationalProcessorsEnabled, setIsExternalRelationalProcessorsEnabled, useIsExternalRelationalProcessorsEnabled, addIsExternalRelationalProcessorsEnabledEventHandler, isAnalyticsEnabledEventFunctions, setIsAnalyticsEnabled, useIsAnalyticsEnabled, addIsAnalyticsEnabledEventHandler, isAnalyticsExternalProcessorsEnabled, setIsAnalyticsExternalProcessorsEnabled, useIsAnalyticsExternalProcessorsEnabled, addIsAnalyticsExternalProcessorsEnabledEventHandler, analyticsDatabaseNameEventFunctions, setAnalyticsDatabaseName, useAnalyticsDatabaseName, addAnalyticsDatabaseNameEventHandler, logLevelEventFunctions, setLogLevel2, useLogLevel, addLogLevelEventHandler, allowListEventFunctions, setAllowList, useAllowList, addAllowListEventHandler, nonUserConfigSetters, phGlobalConfigSetters, nonUserConfigHooks, phGlobalConfigHooks, featuresEventFunctions, useFeatures, setFeatures, addFeaturesEventHandler, modalEventFunctions, usePHModal, setPHModal, addModalEventHandler, revisionHistoryEventFunctions, useRevisionHistoryVisible, setRevisionHistoryVisible, addRevisionHistoryVisibleEventHandler, selectedTimelineItemEventFunctions, useSelectedTimelineItem, setSelectedTimelineItem, addSelectedTimelineItemEventHandler, selectedTimelineRevisionEventFunctions, useSelectedTimelineRevision, setSelectedTimelineRevision, addSelectedTimelineRevisionEventHandler, toastEventFunctions, usePHToast, setPHToast, addToastEventHandler, FEATURE_INSPECTOR_ENABLED = "FEATURE_INSPECTOR_ENABLED", FEATURE_INSPECTOR_ENABLED_DEFAULT = false, syncStatusToUI, validateDocument = (document2) => {
41936
42232
  const errors2 = [];
41937
42233
  if (document2.header.documentType !== "powerhouse/document-model") {
41938
42234
  return errors2;
@@ -41999,8 +42295,8 @@ ${String(result)}`);
41999
42295
  };
42000
42296
  return onDropFile;
42001
42297
  }, store, BrowserLocalStorage, PGLITE_UPDATE_EVENT = "ph:pglite-update", defaultPGliteState, usePGliteDB = () => {
42002
- const [state, setState] = useState4(() => window.powerhouse?.pglite ?? defaultPGliteState);
42003
- useEffect4(() => {
42298
+ const [state, setState] = useState5(() => window.powerhouse?.pglite ?? defaultPGliteState);
42299
+ useEffect5(() => {
42004
42300
  const handlePgliteUpdate = () => setState(window.powerhouse?.pglite ?? defaultPGliteState);
42005
42301
  window.addEventListener(PGLITE_UPDATE_EVENT, handlePgliteUpdate);
42006
42302
  return () => window.removeEventListener(PGLITE_UPDATE_EVENT, handlePgliteUpdate);
@@ -47184,6 +47480,14 @@ spurious results.`);
47184
47480
  vetraPackageManagerFunctions = makePHEventFunctions("vetraPackageManager");
47185
47481
  useVetraPackageManager = vetraPackageManagerFunctions.useValue;
47186
47482
  addVetraPackageManagerEventHandler = vetraPackageManagerFunctions.addEventHandler;
47483
+ reactorClientModuleEventFunctions = makePHEventFunctions("reactorClientModule");
47484
+ reactorClientEventFunctions = makePHEventFunctions("reactorClient");
47485
+ useReactorClientModule = reactorClientModuleEventFunctions.useValue;
47486
+ setReactorClientModule = reactorClientModuleEventFunctions.setValue;
47487
+ addReactorClientModuleEventHandler = reactorClientModuleEventFunctions.addEventHandler;
47488
+ useReactorClient = reactorClientEventFunctions.useValue;
47489
+ setReactorClient = reactorClientEventFunctions.setValue;
47490
+ addReactorClientEventHandler = reactorClientEventFunctions.addEventHandler;
47187
47491
  documentEventFunctions = makePHEventFunctions("documentCache");
47188
47492
  useDocumentCache = documentEventFunctions.useValue;
47189
47493
  setDocumentCache = documentEventFunctions.setValue;
@@ -48231,14 +48535,6 @@ spurious results.`);
48231
48535
  ...phDocumentEditorConfigHooks,
48232
48536
  ...nonUserConfigHooks
48233
48537
  };
48234
- reactorClientModuleEventFunctions = makePHEventFunctions("reactorClientModule");
48235
- reactorClientEventFunctions = makePHEventFunctions("reactorClient");
48236
- useReactorClientModule = reactorClientModuleEventFunctions.useValue;
48237
- setReactorClientModule = reactorClientModuleEventFunctions.setValue;
48238
- addReactorClientModuleEventHandler = reactorClientModuleEventFunctions.addEventHandler;
48239
- useReactorClient = reactorClientEventFunctions.useValue;
48240
- setReactorClient = reactorClientEventFunctions.setValue;
48241
- addReactorClientEventHandler = reactorClientEventFunctions.addEventHandler;
48242
48538
  featuresEventFunctions = makePHEventFunctions("features");
48243
48539
  useFeatures = featuresEventFunctions.useValue;
48244
48540
  setFeatures = featuresEventFunctions.setValue;
@@ -86276,21 +86572,21 @@ var init_extraerrordata = __esm(() => {
86276
86572
 
86277
86573
  // ../../node_modules/.pnpm/@sentry+core@10.40.0/node_modules/@sentry/core/build/esm/utils/path.js
86278
86574
  function normalizeArray(parts, allowAboveRoot) {
86279
- let up14 = 0;
86575
+ let up15 = 0;
86280
86576
  for (let i = parts.length - 1;i >= 0; i--) {
86281
86577
  const last = parts[i];
86282
86578
  if (last === ".") {
86283
86579
  parts.splice(i, 1);
86284
86580
  } else if (last === "..") {
86285
86581
  parts.splice(i, 1);
86286
- up14++;
86287
- } else if (up14) {
86582
+ up15++;
86583
+ } else if (up15) {
86288
86584
  parts.splice(i, 1);
86289
- up14--;
86585
+ up15--;
86290
86586
  }
86291
86587
  }
86292
86588
  if (allowAboveRoot) {
86293
- for (;up14--; up14) {
86589
+ for (;up15--; up15) {
86294
86590
  parts.unshift("..");
86295
86591
  }
86296
86592
  }
@@ -108288,7 +108584,7 @@ function createV6CompatibleWrapCreateMemoryRouter(createRouterFunction, version5
108288
108584
  function createReactRouterV6CompatibleTracingIntegration(options, version5) {
108289
108585
  const integration = browserTracingIntegration({ ...options, instrumentPageLoad: false, instrumentNavigation: false });
108290
108586
  const {
108291
- useEffect: useEffect10,
108587
+ useEffect: useEffect11,
108292
108588
  useLocation,
108293
108589
  useNavigationType,
108294
108590
  createRoutesFromChildren,
@@ -108319,7 +108615,7 @@ function createReactRouterV6CompatibleTracingIntegration(options, version5) {
108319
108615
  } else {
108320
108616
  _lazyRouteTimeout = configuredMaxWait;
108321
108617
  }
108322
- _useEffect = useEffect10;
108618
+ _useEffect = useEffect11;
108323
108619
  _useLocation = useLocation;
108324
108620
  _useNavigationType = useNavigationType;
108325
108621
  _matchRoutes2 = matchRoutes2;
@@ -135962,7 +136258,7 @@ ${typeDefsDoc}`;
135962
136258
 
135963
136259
  // ../../packages/powerhouse-vetra-packages/dist/editors/document-model-editor/context/schema-context.js
135964
136260
  import { jsx as _jsx2 } from "react/jsx-runtime";
135965
- import { createContext, useContext, useEffect as useEffect11, useState as useState10 } from "react";
136261
+ import { createContext, useContext, useEffect as useEffect12, useState as useState11 } from "react";
135966
136262
  function makeSharedSchemaSdl(existingSchemaSdl, globalStateSchemaSdl, localStateSchemaSdl, operationSchemasSdl) {
135967
136263
  const existingSchema = buildSchema(existingSchemaSdl);
135968
136264
  const sdls = [
@@ -136035,8 +136331,8 @@ function parseSharedSchemaSdl(initialSchema2, globalStateSchemaSdl, localStateSc
136035
136331
  }
136036
136332
  function SchemaContextProvider(props) {
136037
136333
  const { children, globalStateSchemaSdl, localStateSchemaSdl, operationSchemasSdl } = props;
136038
- const [sharedSchemaSdl, setSharedSchemaSdl] = useState10(() => parseSharedSchemaSdl(printSchema(initialSchema), globalStateSchemaSdl, localStateSchemaSdl, operationSchemasSdl));
136039
- useEffect11(() => {
136334
+ const [sharedSchemaSdl, setSharedSchemaSdl] = useState11(() => parseSharedSchemaSdl(printSchema(initialSchema), globalStateSchemaSdl, localStateSchemaSdl, operationSchemasSdl));
136335
+ useEffect12(() => {
136040
136336
  setSharedSchemaSdl((prev) => parseSharedSchemaSdl(prev.sharedSchema, globalStateSchemaSdl, localStateSchemaSdl, operationSchemasSdl));
136041
136337
  }, [globalStateSchemaSdl, localStateSchemaSdl, operationSchemasSdl]);
136042
136338
  return _jsx2(SchemaContext.Provider, { value: sharedSchemaSdl, children });
@@ -145611,18 +145907,18 @@ var init_form = __esm(() => {
145611
145907
  // ../../packages/powerhouse-vetra-packages/dist/editors/document-model-editor/components/text-area.js
145612
145908
  import { jsx as _jsx5 } from "react/jsx-runtime";
145613
145909
  import * as React14 from "react";
145614
- import { forwardRef as forwardRef6, useImperativeHandle, useRef as useRef9, useCallback as useCallback8 } from "react";
145910
+ import { forwardRef as forwardRef6, useImperativeHandle, useRef as useRef10, useCallback as useCallback7 } from "react";
145615
145911
  var Textarea;
145616
145912
  var init_text_area = __esm(() => {
145617
145913
  init_style();
145618
145914
  Textarea = forwardRef6(({ className, ...props }, ref) => {
145619
- const textareaRef = useRef9(null);
145620
- const adjustHeight = useCallback8((textarea) => {
145915
+ const textareaRef = useRef10(null);
145916
+ const adjustHeight = useCallback7((textarea) => {
145621
145917
  textarea.style.height = "auto";
145622
145918
  const newHeight = Math.max(textarea.scrollHeight, textarea.offsetHeight);
145623
145919
  textarea.style.height = `${newHeight}px`;
145624
145920
  }, []);
145625
- const handleInput = useCallback8((e3) => {
145921
+ const handleInput = useCallback7((e3) => {
145626
145922
  adjustHeight(e3.currentTarget);
145627
145923
  }, [adjustHeight]);
145628
145924
  React14.useEffect(() => {
@@ -145641,7 +145937,7 @@ var init_text_area = __esm(() => {
145641
145937
 
145642
145938
  // ../../packages/powerhouse-vetra-packages/dist/editors/document-model-editor/components/text-field.js
145643
145939
  import { jsx as _jsx6, jsxs as _jsxs } from "react/jsx-runtime";
145644
- import { forwardRef as forwardRef7, useCallback as useCallback9, useEffect as useEffect13, useId as useId2, useImperativeHandle as useImperativeHandle2, useRef as useRef10 } from "react";
145940
+ import { forwardRef as forwardRef7, useCallback as useCallback9, useEffect as useEffect14, useId as useId2, useImperativeHandle as useImperativeHandle2, useRef as useRef11 } from "react";
145645
145941
  var TextField;
145646
145942
  var init_text_field = __esm(() => {
145647
145943
  init_zod2();
@@ -145652,9 +145948,9 @@ var init_text_field = __esm(() => {
145652
145948
  init_form();
145653
145949
  init_text_area();
145654
145950
  TextField = forwardRef7(({ name: name6, value, onSubmit, label, placeholder, unique, className = "", rows = 1, focusOnMount = false, required: required2 = false, allowEmpty = false, shouldReset = false, onChange }, ref) => {
145655
- const textareaRef = useRef10(null);
145951
+ const textareaRef = useRef11(null);
145656
145952
  const id = useId2();
145657
- useEffect13(() => {
145953
+ useEffect14(() => {
145658
145954
  if (focusOnMount && textareaRef.current) {
145659
145955
  textareaRef.current.focus();
145660
145956
  }
@@ -145704,7 +146000,7 @@ var init_text_field = __esm(() => {
145704
146000
  useImperativeHandle2(ref, () => ({
145705
146001
  focus: () => textareaRef.current?.focus()
145706
146002
  }));
145707
- useEffect13(() => {
146003
+ useEffect14(() => {
145708
146004
  form.reset({ [name6]: value ?? "" });
145709
146005
  }, [form, name6, value]);
145710
146006
  return _jsx6(Form2, { ...form, children: _jsx6(FormField, { control: form.control, name: name6, render: ({ field }) => _jsxs(FormItem, { className: "grid h-full grid-rows-[auto,1fr] gap-2 overflow-visible", children: [!!label && _jsx6(FormLabel, { htmlFor: name6, className: "text-sm font-medium text-gray-700", children: label }), _jsx6(FormControl, { children: _jsx6(Textarea, { ...field, id, name: name6, ref: (node) => {
@@ -145911,10 +146207,10 @@ var init_linting = __esm(() => {
145911
146207
 
145912
146208
  // ../../packages/powerhouse-vetra-packages/dist/editors/document-model-editor/components/operation-description-form.js
145913
146209
  import { jsx as _jsx10 } from "react/jsx-runtime";
145914
- import { useEffect as useEffect14, useRef as useRef11 } from "react";
146210
+ import { useEffect as useEffect15, useRef as useRef12 } from "react";
145915
146211
  function OperationDescriptionForm({ operation, focusOnMount, setOperationDescription }) {
145916
- const textFieldRef = useRef11(null);
145917
- useEffect14(() => {
146212
+ const textFieldRef = useRef12(null);
146213
+ useEffect15(() => {
145918
146214
  if (focusOnMount && textFieldRef.current) {
145919
146215
  textFieldRef.current.focus();
145920
146216
  }
@@ -145927,9 +146223,9 @@ var init_operation_description_form = __esm(() => {
145927
146223
 
145928
146224
  // ../../packages/powerhouse-vetra-packages/dist/editors/document-model-editor/components/operation-error-form.js
145929
146225
  import { jsx as _jsx11 } from "react/jsx-runtime";
145930
- import { useCallback as useCallback12, useRef as useRef12 } from "react";
146226
+ import { useCallback as useCallback12, useRef as useRef13 } from "react";
145931
146227
  function OperationErrorForm({ operation, error: error50, focusOnMount, onSubmit, onAddOperationError, deleteOperationError, setOperationErrorName }) {
145932
- const textFieldRef = useRef12(null);
146228
+ const textFieldRef = useRef13(null);
145933
146229
  const isEdit = !!error50;
145934
146230
  const allOperationErrorNames = operation.errors.map((o3) => o3.name).filter((n5) => n5 !== null);
145935
146231
  const handleSubmit = useCallback12((name6) => {
@@ -145967,10 +146263,10 @@ var init_operation_error_form = __esm(() => {
145967
146263
 
145968
146264
  // ../../packages/powerhouse-vetra-packages/dist/editors/document-model-editor/components/operation-errors.js
145969
146265
  import { jsx as _jsx12, jsxs as _jsxs3 } from "react/jsx-runtime";
145970
- import { useCallback as useCallback13, useId as useId3, useState as useState11 } from "react";
146266
+ import { useCallback as useCallback13, useId as useId3, useState as useState12 } from "react";
145971
146267
  function OperationErrors({ operation, addOperationError, deleteOperationError, setOperationErrorName }) {
145972
146268
  const addErrorFormId = useId3();
145973
- const [shouldFocusAddForm, setShouldFocusAddForm] = useState11(false);
146269
+ const [shouldFocusAddForm, setShouldFocusAddForm] = useState12(false);
145974
146270
  const onAddOperationError = useCallback13(async (operationId, error50) => {
145975
146271
  const errorId = await addOperationError(operationId, error50);
145976
146272
  if (errorId) {
@@ -149278,10 +149574,10 @@ function dispatchKey(elt, name6, code6, mods) {
149278
149574
  let down = new KeyboardEvent("keydown", options);
149279
149575
  down.synthetic = true;
149280
149576
  elt.dispatchEvent(down);
149281
- let up14 = new KeyboardEvent("keyup", options);
149282
- up14.synthetic = true;
149283
- elt.dispatchEvent(up14);
149284
- return down.defaultPrevented || up14.defaultPrevented;
149577
+ let up15 = new KeyboardEvent("keyup", options);
149578
+ up15.synthetic = true;
149579
+ elt.dispatchEvent(up15);
149580
+ return down.defaultPrevented || up15.defaultPrevented;
149285
149581
  }
149286
149582
  function getRoot(node) {
149287
149583
  while (node) {
@@ -171609,14 +171905,14 @@ var init_factories = __esm(() => {
171609
171905
  });
171610
171906
 
171611
171907
  // ../../packages/powerhouse-vetra-packages/dist/editors/document-model-editor/components/code-editors/hooks.js
171612
- import { useEffect as useEffect15, useRef as useRef13 } from "react";
171908
+ import { useEffect as useEffect16, useRef as useRef14 } from "react";
171613
171909
  function useEditorRefs() {
171614
- const editorRef = useRef13(null);
171615
- const viewRef = useRef13(null);
171616
- const updateListenerCompartment = useRef13(new Compartment);
171617
- const focusHandlerCompartment = useRef13(new Compartment);
171618
- const pasteHandlerCompartment = useRef13(new Compartment);
171619
- const timeoutRef = useRef13(null);
171910
+ const editorRef = useRef14(null);
171911
+ const viewRef = useRef14(null);
171912
+ const updateListenerCompartment = useRef14(new Compartment);
171913
+ const focusHandlerCompartment = useRef14(new Compartment);
171914
+ const pasteHandlerCompartment = useRef14(new Compartment);
171915
+ const timeoutRef = useRef14(null);
171620
171916
  return {
171621
171917
  editorRef,
171622
171918
  viewRef,
@@ -171627,7 +171923,7 @@ function useEditorRefs() {
171627
171923
  };
171628
171924
  }
171629
171925
  function useEditorCleanup(viewRef) {
171630
- useEffect15(() => {
171926
+ useEffect16(() => {
171631
171927
  return () => {
171632
171928
  if (viewRef.current) {
171633
171929
  viewRef.current.destroy();
@@ -171637,7 +171933,7 @@ function useEditorCleanup(viewRef) {
171637
171933
  }, []);
171638
171934
  }
171639
171935
  function useHandlerReconfiguration(view, readonly4, timeoutRef, updateDocumentInModel, compartments) {
171640
- useEffect15(() => {
171936
+ useEffect16(() => {
171641
171937
  if (!view)
171642
171938
  return;
171643
171939
  view.dispatch({
@@ -171651,7 +171947,7 @@ function useHandlerReconfiguration(view, readonly4, timeoutRef, updateDocumentIn
171651
171947
  }, [readonly4, updateDocumentInModel]);
171652
171948
  }
171653
171949
  function useDocumentSync(view, doc3) {
171654
- useEffect15(() => {
171950
+ useEffect16(() => {
171655
171951
  if (!view)
171656
171952
  return;
171657
171953
  const currentDoc = view.state.doc.toString();
@@ -178967,7 +179263,7 @@ __export(exports_graphql_editor, {
178967
179263
  default: () => graphql_editor_default
178968
179264
  });
178969
179265
  import { jsx as _jsx13 } from "react/jsx-runtime";
178970
- import { memo as memo2, useEffect as useEffect16, useRef as useRef14 } from "react";
179266
+ import { memo as memo2, useEffect as useEffect17, useRef as useRef15 } from "react";
178971
179267
  var GraphqlEditor, graphql_editor_default;
178972
179268
  var init_graphql_editor = __esm(() => {
178973
179269
  init_dist11();
@@ -178984,10 +179280,10 @@ var init_graphql_editor = __esm(() => {
178984
179280
  GraphqlEditor = memo2(function GraphqlEditor2(props) {
178985
179281
  const { doc: doc3, readonly: readonly4 = false, updateDocumentInModel, customLinter } = props;
178986
179282
  const { editorRef, viewRef, updateListenerCompartment, focusHandlerCompartment, pasteHandlerCompartment, timeoutRef } = useEditorRefs();
178987
- const graphqlCompartment = useRef14(new Compartment);
178988
- const linterCompartment = useRef14(new Compartment);
179283
+ const graphqlCompartment = useRef15(new Compartment);
179284
+ const linterCompartment = useRef15(new Compartment);
178989
179285
  const { sharedSchema } = useSchemaContext();
178990
- useEffect16(() => {
179286
+ useEffect17(() => {
178991
179287
  if (!viewRef.current) {
178992
179288
  const schema18 = buildSchema(sharedSchema);
178993
179289
  viewRef.current = new EditorView({
@@ -179011,7 +179307,7 @@ var init_graphql_editor = __esm(() => {
179011
179307
  }
179012
179308
  }, []);
179013
179309
  useEditorCleanup(viewRef);
179014
- useEffect16(() => {
179310
+ useEffect17(() => {
179015
179311
  const view = viewRef.current;
179016
179312
  if (!view)
179017
179313
  return;
@@ -179068,9 +179364,9 @@ var init_operation = __esm(() => {
179068
179364
 
179069
179365
  // ../../packages/powerhouse-vetra-packages/dist/editors/document-model-editor/components/operations.js
179070
179366
  import { jsx as _jsx15, jsxs as _jsxs5 } from "react/jsx-runtime";
179071
- import { useCallback as useCallback15, useId as useId4, useState as useState12 } from "react";
179367
+ import { useCallback as useCallback15, useId as useId4, useState as useState13 } from "react";
179072
179368
  function Operations({ module, allOperations, shouldFocusNewOperation, updateOperationName, deleteOperation, addOperationAndInitialSchema, addOperationError, deleteOperationError, setOperationErrorName, updateOperationSchema, setOperationDescription, toggleNoInputRequired }) {
179073
- const [lastCreatedOperationId, setLastCreatedOperationId] = useState12(null);
179369
+ const [lastCreatedOperationId, setLastCreatedOperationId] = useState13(null);
179074
179370
  const addOperationFormId = useId4();
179075
179371
  const allOperationNames = allOperations.map((o3) => o3.name).filter((n5) => n5 !== null);
179076
179372
  const onAddOperationAndInitialSchema = useCallback15(async (moduleId, name6) => {
@@ -179102,10 +179398,10 @@ var init_module = __esm(() => {
179102
179398
 
179103
179399
  // ../../packages/powerhouse-vetra-packages/dist/editors/document-model-editor/components/modules.js
179104
179400
  import { jsx as _jsx17, jsxs as _jsxs7 } from "react/jsx-runtime";
179105
- import { useCallback as useCallback16, useRef as useRef15, useState as useState13 } from "react";
179401
+ import { useCallback as useCallback16, useRef as useRef16, useState as useState14 } from "react";
179106
179402
  function Modules({ modules, allOperations, addModule, updateModuleName, deleteModule, updateOperationName, deleteOperation, addOperationAndInitialSchema, updateOperationSchema, setOperationDescription, addOperationError, deleteOperationError, setOperationErrorName, toggleNoInputRequired }) {
179107
- const [lastCreatedModuleId, setLastCreatedModuleId] = useState13(null);
179108
- const focusTrapRef = useRef15(null);
179403
+ const [lastCreatedModuleId, setLastCreatedModuleId] = useState14(null);
179404
+ const focusTrapRef = useRef16(null);
179109
179405
  const onAddModule = useCallback16(async (name6) => {
179110
179406
  const moduleId = await addModule(name6);
179111
179407
  if (moduleId) {
@@ -180464,7 +180760,7 @@ __export(exports_json_editor, {
180464
180760
  default: () => json_editor_default
180465
180761
  });
180466
180762
  import { jsx as _jsx21 } from "react/jsx-runtime";
180467
- import { memo as memo3, useEffect as useEffect23 } from "react";
180763
+ import { memo as memo3, useEffect as useEffect24 } from "react";
180468
180764
  var JSONEditor, json_editor_default;
180469
180765
  var init_json_editor = __esm(() => {
180470
180766
  init_dist35();
@@ -180478,7 +180774,7 @@ var init_json_editor = __esm(() => {
180478
180774
  JSONEditor = memo3(function JSONEditor2(props) {
180479
180775
  const { doc: doc3, readonly: readonly4 = false, updateDocumentInModel } = props;
180480
180776
  const { editorRef, viewRef, updateListenerCompartment, focusHandlerCompartment, pasteHandlerCompartment, timeoutRef } = useEditorRefs();
180481
- useEffect23(() => {
180777
+ useEffect24(() => {
180482
180778
  if (!viewRef.current) {
180483
180779
  viewRef.current = new EditorView({
180484
180780
  state: EditorState.create({
@@ -180521,11 +180817,11 @@ __export(exports_state_schemas, {
180521
180817
  import { jsxs as _jsxs9, jsx as _jsx22 } from "react/jsx-runtime";
180522
180818
  import { cn as cn3 } from "@powerhousedao/design-system";
180523
180819
  import { Checkbox } from "@powerhousedao/design-system/ui/components/checkbox/checkbox.js";
180524
- import { lazy as lazy3, Suspense as Suspense2, useCallback as useCallback20, useEffect as useEffect24, useMemo as useMemo8, useRef as useRef22, useState as useState18 } from "react";
180820
+ import { lazy as lazy3, Suspense as Suspense2, useCallback as useCallback20, useEffect as useEffect25, useMemo as useMemo8, useRef as useRef23, useState as useState19 } from "react";
180525
180821
  function StateEditor({ modelName, stateSchema, initialValue, setStateSchema, setInitialState, scope }) {
180526
180822
  const { sharedSchema: sharedSchemaSdl, error: sharedSchemaError } = useSchemaContext();
180527
- const [showStandardLib, setShowStandardLib] = useState18(false);
180528
- const [syncWithSchema, setSyncWithSchema] = useState18(true);
180823
+ const [showStandardLib, setShowStandardLib] = useState19(false);
180824
+ const [syncWithSchema, setSyncWithSchema] = useState19(true);
180529
180825
  const customLinter = useCallback20((doc3) => ensureValidStateSchemaName(doc3, modelName, scope), [modelName, scope]);
180530
180826
  const schemaErrors = useMemo8(() => {
180531
180827
  const errors5 = ensureValidStateSchemaName(stateSchema, modelName, scope);
@@ -180539,7 +180835,7 @@ function StateEditor({ modelName, stateSchema, initialValue, setStateSchema, set
180539
180835
  }, []);
180540
180836
  const handleSchemaUpdate = useCallback20((newDoc) => setStateSchema(newDoc, scope), [setStateSchema, scope]);
180541
180837
  const handleInitialStateUpdate = useCallback20((newDoc) => setInitialState(newDoc, scope), [setInitialState, scope]);
180542
- const hasSyncedRef = useRef22(false);
180838
+ const hasSyncedRef = useRef23(false);
180543
180839
  const { initialValueErrors, fixedState } = useMemo8(() => {
180544
180840
  const existingValue = initialValue || "{}";
180545
180841
  const sharedSchemaDocumentNode = safeParseSdl(sharedSchemaSdl);
@@ -180564,7 +180860,7 @@ function StateEditor({ modelName, stateSchema, initialValue, setStateSchema, set
180564
180860
  }
180565
180861
  return { initialValueErrors: errors5, fixedState: null };
180566
180862
  }, [sharedSchemaSdl, initialValue, syncWithSchema, scope, modelName]);
180567
- useEffect24(() => {
180863
+ useEffect25(() => {
180568
180864
  if (fixedState && !hasSyncedRef.current) {
180569
180865
  hasSyncedRef.current = true;
180570
180866
  setInitialState(fixedState, scope);
@@ -180605,18 +180901,18 @@ import { jsx as _jsx23, jsxs as _jsxs10 } from "react/jsx-runtime";
180605
180901
  import { DocumentToolbar } from "@powerhousedao/design-system/connect";
180606
180902
  import { addModule, addOperation, addOperationError, deleteModule, deleteOperation, deleteOperationError, setAuthorName, setAuthorWebsite, setInitialState, setModelDescription, setModelExtension, setModelId, setModelName, setModuleName, setOperationDescription, setOperationErrorName, setOperationName, setOperationSchema, setStateSchema } from "document-model";
180607
180903
  import { generateId as generateId3 } from "document-model/core";
180608
- import { lazy as lazy4, Suspense as Suspense3, useEffect as useEffect25, useRef as useRef23, useState as useState19 } from "react";
180904
+ import { lazy as lazy4, Suspense as Suspense3, useEffect as useEffect26, useRef as useRef24, useState as useState20 } from "react";
180609
180905
  function Editor() {
180610
180906
  useSetPHDocumentEditorConfig(editorConfig);
180611
180907
  const toast3 = usePHToast();
180612
180908
  const [document2, dispatch] = useSelectedDocumentModelDocument();
180613
- const [scope, setScope] = useState19("global");
180909
+ const [scope, setScope] = useState20("global");
180614
180910
  const documentNodeName = document2.header.name;
180615
180911
  const { name: modelName, id: documentType, extension, description, author: { name: authorName, website: authorWebsite } } = document2.state.global;
180616
180912
  const { state: { global: { schema: globalStateSchema, initialValue: globalStateInitialValue }, local: { schema: localStateSchema, initialValue: localStateInitialValue } }, modules } = document2.state.global.specifications[0];
180617
180913
  const operations = modules.flatMap((module) => module.operations);
180618
- const shouldSetInitialName = useRef23(!modelName && !!documentNodeName && operations.length === 0);
180619
- useEffect25(() => {
180914
+ const shouldSetInitialName = useRef24(!modelName && !!documentNodeName && operations.length === 0);
180915
+ useEffect26(() => {
180620
180916
  if (!shouldSetInitialName.current || !documentNodeName)
180621
180917
  return;
180622
180918
  const initialSchemaDoc2 = initializeModelSchema(documentNodeName);
@@ -181713,9 +182009,9 @@ var init_esm12 = __esm(() => {
181713
182009
  import { jsx as _jsx25 } from "react/jsx-runtime";
181714
182010
  import { useWindowSize } from "@powerhousedao/design-system";
181715
182011
  import { FileItem } from "@powerhousedao/design-system/connect";
181716
- import React33, { useRef as useRef24 } from "react";
182012
+ import React33, { useRef as useRef25 } from "react";
181717
182013
  function FileContentView() {
181718
- const parentRef = useRef24(null);
182014
+ const parentRef = useRef25(null);
181719
182015
  const windowSize = useWindowSize();
181720
182016
  const availableWidth = windowSize.innerWidth - USED_SPACE;
181721
182017
  const nodes = useNodesInSelectedDriveOrFolder();
@@ -181889,14 +182185,15 @@ var init_editors = __esm(() => {
181889
182185
  import { logger as logger9 } from "document-drive";
181890
182186
  import { useSyncExternalStore as useSyncExternalStore4 } from "react";
181891
182187
  import { use as use3, useCallback as useCallback21, useSyncExternalStore as useSyncExternalStore22 } from "react";
181892
- import { useEffect as useEffect27, useState as useState21 } from "react";
182188
+ import { useEffect as useEffect28, useState as useState22 } from "react";
181893
182189
  import { logger as logger52 } from "document-drive";
181894
182190
  import { logger as logger42 } from "document-drive";
181895
182191
  import { logger as logger23 } from "document-drive";
181896
182192
  import { logger as logger32 } from "document-drive";
181897
182193
  import { buildSignedAction as buildSignedAction2 } from "document-model/core";
181898
182194
  import { useSyncExternalStore as useSyncExternalStore32 } from "react";
181899
- import { useEffect as useEffect28, useState as useState22 } from "react";
182195
+ import { useEffect as useEffect29, useState as useState23 } from "react";
182196
+ import { useEffect as useEffect32, useRef as useRef26, useState as useState32 } from "react";
181900
182197
  function consumeDidFromUrl2() {
181901
182198
  if (typeof window === "undefined")
181902
182199
  return;
@@ -182170,8 +182467,8 @@ class DocumentCache2 {
182170
182467
  }
182171
182468
  function useUser2() {
182172
182469
  const renown = useRenown2();
182173
- const [user, setUser2] = useState21(() => renown?.user);
182174
- useEffect27(() => {
182470
+ const [user, setUser2] = useState22(() => renown?.user);
182471
+ useEffect28(() => {
182175
182472
  setUser2(renown?.user);
182176
182473
  if (!renown)
182177
182474
  return;
@@ -182388,6 +182685,48 @@ function setDefaultPHGlobalConfig(config20) {
182388
182685
  callGlobalSetterForKey2(key, config20[key]);
182389
182686
  }
182390
182687
  }
182688
+ function useConnectionStates2() {
182689
+ const syncManager = useSync2();
182690
+ const [states, setStates] = useState32(() => buildSnapshot2(syncManager));
182691
+ const unsubscribesRef = useRef26([]);
182692
+ useEffect32(() => {
182693
+ if (!syncManager)
182694
+ return;
182695
+ function subscribe2() {
182696
+ for (const unsub of unsubscribesRef.current) {
182697
+ unsub();
182698
+ }
182699
+ unsubscribesRef.current = [];
182700
+ const remotes = syncManager.list();
182701
+ for (const remote of remotes) {
182702
+ const unsub = remote.channel.onConnectionStateChange(() => {
182703
+ setStates(buildSnapshot2(syncManager));
182704
+ });
182705
+ unsubscribesRef.current.push(unsub);
182706
+ }
182707
+ setStates(buildSnapshot2(syncManager));
182708
+ }
182709
+ subscribe2();
182710
+ const interval = setInterval(subscribe2, 5000);
182711
+ return () => {
182712
+ clearInterval(interval);
182713
+ for (const unsub of unsubscribesRef.current) {
182714
+ unsub();
182715
+ }
182716
+ unsubscribesRef.current = [];
182717
+ };
182718
+ }, [syncManager]);
182719
+ return states;
182720
+ }
182721
+ function buildSnapshot2(syncManager) {
182722
+ const map2 = new Map;
182723
+ if (!syncManager)
182724
+ return map2;
182725
+ for (const remote of syncManager.list()) {
182726
+ map2.set(remote.name, remote.channel.getConnectionState());
182727
+ }
182728
+ return map2;
182729
+ }
182391
182730
  var SPLIT_LOWER_UPPER_RE3, SPLIT_UPPER_UPPER_RE3, SPLIT_SEPARATE_NUMBER_RE3, DEFAULT_STRIP_REGEXP3, SPLIT_REPLACE_VALUE3 = "$1\x00$2", DEFAULT_PREFIX_SUFFIX_CHARACTERS3 = "", isExternalControlsEnabledEventFunctions2, setIsExternalControlsEnabled2, useIsExternalControlsEnabled2, addIsExternalControlsEnabledEventHandler2, isDragAndDropEnabledEventFunctions2, setIsDragAndDropEnabled2, useIsDragAndDropEnabled2, addIsDragAndDropEnabledEventHandler2, allowedDocumentTypesEventFunctions2, setAllowedDocumentTypes2, addAllowedDocumentTypesEventHandler2, phDriveEditorConfigSetters2, phDocumentEditorConfigSetters2, phDriveEditorConfigHooks2, phDocumentEditorConfigHooks2, useRouterBasename2, setRouterBasename2, addRouterBasenameEventHandler2, useVersion2, setVersion2, addVersionEventHandler2, useRequiresHardRefresh2, setRequiresHardRefresh2, addRequiresHardRefreshEventHandler2, useWarnOutdatedApp2, setWarnOutdatedApp2, addWarnOutdatedAppEventHandler2, useStudioMode2, setStudioMode2, addStudioModeEventHandler2, useBasePath2, setBasePath2, addBasePathEventHandler2, useVersionCheckInterval2, setVersionCheckInterval2, addVersionCheckIntervalEventHandler2, useCliVersion2, setCliVersion2, addCliVersionEventHandler2, useFileUploadOperationsChunkSize2, setFileUploadOperationsChunkSize2, addFileUploadOperationsChunkSizeEventHandler2, useIsDocumentModelSelectionSettingsEnabled2, setIsDocumentModelSelectionSettingsEnabled2, addIsDocumentModelSelectionSettingsEnabledEventHandler2, useGaTrackingId2, setGaTrackingId2, addGaTrackingIdEventHandler2, useDefaultDrivesUrl2, setDefaultDrivesUrl2, addDefaultDrivesUrlEventHandler2, useDrivesPreserveStrategy2, setDrivesPreserveStrategy2, addDrivesPreserveStrategyEventHandler2, useIsLocalDrivesEnabled2, setIsLocalDrivesEnabled2, addIsLocalDrivesEnabledEventHandler2, useIsAddDriveEnabled2, setIsAddDriveEnabled2, addIsAddDriveEnabledEventHandler2, useIsPublicDrivesEnabled2, setIsPublicDrivesEnabled2, addIsPublicDrivesEnabledEventHandler2, useIsAddPublicDrivesEnabled2, setIsAddPublicDrivesEnabled2, addIsAddPublicDrivesEnabledEventHandler2, useIsDeletePublicDrivesEnabled2, setIsDeletePublicDrivesEnabled2, addIsDeletePublicDrivesEnabledEventHandler2, useIsCloudDrivesEnabled2, setIsCloudDrivesEnabled2, addIsCloudDrivesEnabledEventHandler2, useIsAddCloudDrivesEnabled2, setIsAddCloudDrivesEnabled2, addIsAddCloudDrivesEnabledEventHandler2, useIsDeleteCloudDrivesEnabled2, setIsDeleteCloudDrivesEnabled2, addIsDeleteCloudDrivesEnabledEventHandler2, useLocalDrivesEnabled2, setLocalDrivesEnabled2, addLocalDrivesEnabledEventHandler2, useIsAddLocalDrivesEnabled2, setIsAddLocalDrivesEnabled2, addIsAddLocalDrivesEnabledEventHandler2, useIsDeleteLocalDrivesEnabled2, setIsDeleteLocalDrivesEnabled2, addIsDeleteLocalDrivesEnabledEventHandler2, useIsEditorDebugModeEnabled2, setIsEditorDebugModeEnabled2, addIsEditorDebugModeEnabledEventHandler2, useIsEditorReadModeEnabled2, setIsEditorReadModeEnabled2, addIsEditorReadModeEnabledEventHandler2, useIsAnalyticsDatabaseWorkerEnabled2, setIsAnalyticsDatabaseWorkerEnabled2, addIsAnalyticsDatabaseWorkerEnabledEventHandler2, useIsDiffAnalyticsEnabled2, setIsDiffAnalyticsEnabled2, addIsDiffAnalyticsEnabledEventHandler2, useIsDriveAnalyticsEnabled2, setIsDriveAnalyticsEnabled2, addIsDriveAnalyticsEnabledEventHandler2, useRenownUrl2, setRenownUrl2, addRenownUrlEventHandler2, useRenownNetworkId2, setRenownNetworkId2, addRenownNetworkIdEventHandler2, useRenownChainId2, setRenownChainId2, addRenownChainIdEventHandler2, useSentryRelease2, setSentryRelease2, addSentryReleaseEventHandler2, useSentryDsn2, setSentryDsn2, addSentryDsnEventHandler2, useSentryEnv2, setSentryEnv2, addSentryEnvEventHandler2, useIsSentryTracingEnabled2, setIsSentryTracingEnabled2, addIsSentryTracingEnabledEventHandler2, useIsExternalProcessorsEnabled2, setIsExternalProcessorsEnabled2, addIsExternalProcessorsEnabledEventHandler2, useIsExternalPackagesEnabled2, setIsExternalPackagesEnabled2, addIsExternalPackagesEnabledEventHandler2, enabledEditorsEventFunctions2, setEnabledEditors2, useEnabledEditors2, addEnabledEditorsEventHandler2, disabledEditorsEventFunctions2, setDisabledEditors2, useDisabledEditors2, addDisabledEditorsEventHandler2, isRelationalProcessorsEnabled2, setIsRelationalProcessorsEnabled2, useIsRelationalProcessorsEnabled2, addIsRelationalProcessorsEnabledEventHandler2, isExternalRelationalProcessorsEnabled2, setIsExternalRelationalProcessorsEnabled2, useIsExternalRelationalProcessorsEnabled2, addIsExternalRelationalProcessorsEnabledEventHandler2, isAnalyticsEnabledEventFunctions2, setIsAnalyticsEnabled2, useIsAnalyticsEnabled2, addIsAnalyticsEnabledEventHandler2, isAnalyticsExternalProcessorsEnabled2, setIsAnalyticsExternalProcessorsEnabled2, useIsAnalyticsExternalProcessorsEnabled2, addIsAnalyticsExternalProcessorsEnabledEventHandler2, analyticsDatabaseNameEventFunctions2, setAnalyticsDatabaseName2, useAnalyticsDatabaseName2, addAnalyticsDatabaseNameEventHandler2, logLevelEventFunctions2, setLogLevel3, useLogLevel2, addLogLevelEventHandler2, allowListEventFunctions2, setAllowList2, useAllowList2, addAllowListEventHandler2, nonUserConfigSetters2, phGlobalConfigSetters2, nonUserConfigHooks2, phGlobalConfigHooks2, featuresEventFunctions2, useFeatures2, setFeatures2, addFeaturesEventHandler2, documentEventFunctions2, useDocumentCache2, setDocumentCache2, addDocumentCacheEventHandler2, drivesEventFunctions2, useDrives2, setDrives2, addDrivesEventHandler2, useLoading2, setLoading2, addLoadingEventHandler2, modalEventFunctions2, usePHModal2, setPHModal2, addModalEventHandler2, reactorClientModuleEventFunctions2, reactorClientEventFunctions2, useReactorClientModule2, setReactorClientModule2, addReactorClientModuleEventHandler2, useReactorClient2, setReactorClient2, addReactorClientEventHandler2, useSync2 = () => useReactorClientModule2()?.reactorModule?.syncModule?.syncManager, useSyncList2 = () => {
182392
182731
  const sync = useSync2();
182393
182732
  return sync?.list() ?? [];
@@ -252224,10 +252563,10 @@ var init_reactor2 = __esm(() => {
252224
252563
  });
252225
252564
 
252226
252565
  // src/store/user.ts
252227
- import { useEffect as useEffect34 } from "react";
252566
+ import { useEffect as useEffect37 } from "react";
252228
252567
  function useSetSentryUser() {
252229
252568
  const user = useUser2();
252230
- useEffect34(() => {
252569
+ useEffect37(() => {
252231
252570
  let sentryUser = null;
252232
252571
  if (user) {
252233
252572
  const { credential, ...rest } = user;