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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/src/main.js CHANGED
@@ -7982,7 +7982,7 @@ var init_package = __esm(() => {
7982
7982
  package_default = {
7983
7983
  name: "@powerhousedao/connect",
7984
7984
  productName: "Powerhouse-Connect",
7985
- version: "6.0.0-dev.76",
7985
+ version: "6.0.0-dev.78",
7986
7986
  description: "Powerhouse Connect",
7987
7987
  main: "dist/index.html",
7988
7988
  type: "module",
@@ -17070,14 +17070,14 @@ class BaseReadModel {
17070
17070
  operationIndex;
17071
17071
  writeCache;
17072
17072
  consistencyTracker;
17073
- readModelId;
17073
+ config;
17074
17074
  lastOrdinal = 0;
17075
- constructor(db, operationIndex, writeCache, consistencyTracker, readModelId) {
17075
+ constructor(db, operationIndex, writeCache, consistencyTracker, config) {
17076
17076
  this.db = db;
17077
17077
  this.operationIndex = operationIndex;
17078
17078
  this.writeCache = writeCache;
17079
17079
  this.consistencyTracker = consistencyTracker;
17080
- this.readModelId = readModelId;
17080
+ this.config = config;
17081
17081
  }
17082
17082
  async init() {
17083
17083
  const viewState = await this.loadState();
@@ -17085,21 +17085,22 @@ class BaseReadModel {
17085
17085
  this.lastOrdinal = viewState;
17086
17086
  const missedOperations = await this.operationIndex.getSinceOrdinal(this.lastOrdinal);
17087
17087
  if (missedOperations.results.length > 0) {
17088
- const opsWithState = await this.rebuildStateForOperations(missedOperations.results);
17089
- await this.indexOperations(opsWithState);
17088
+ const ops = this.config.rebuildStateOnInit ? await this.rebuildStateForOperations(missedOperations.results) : missedOperations.results;
17089
+ await this.indexOperations(ops);
17090
17090
  }
17091
17091
  } else {
17092
17092
  await this.initializeState();
17093
17093
  const allOperations = await this.operationIndex.getSinceOrdinal(0);
17094
17094
  if (allOperations.results.length > 0) {
17095
- const opsWithState = await this.rebuildStateForOperations(allOperations.results);
17096
- await this.indexOperations(opsWithState);
17095
+ const ops = this.config.rebuildStateOnInit ? await this.rebuildStateForOperations(allOperations.results) : allOperations.results;
17096
+ await this.indexOperations(ops);
17097
17097
  }
17098
17098
  }
17099
17099
  }
17100
17100
  async indexOperations(items) {
17101
17101
  if (items.length === 0)
17102
17102
  return;
17103
+ await this.commitOperations(items);
17103
17104
  await this.db.transaction().execute(async (trx) => {
17104
17105
  await this.saveState(trx, items);
17105
17106
  });
@@ -17111,6 +17112,7 @@ class BaseReadModel {
17111
17112
  }
17112
17113
  await this.consistencyTracker.waitFor(token.coordinates, timeoutMs, signal);
17113
17114
  }
17115
+ async commitOperations(items) {}
17114
17116
  async rebuildStateForOperations(operations) {
17115
17117
  const result = [];
17116
17118
  for (const op of operations) {
@@ -17129,13 +17131,13 @@ class BaseReadModel {
17129
17131
  }
17130
17132
  async loadState() {
17131
17133
  const viewStateDb = this.db;
17132
- const row = await viewStateDb.selectFrom("ViewState").select("lastOrdinal").where("readModelId", "=", this.readModelId).executeTakeFirst();
17134
+ const row = await viewStateDb.selectFrom("ViewState").select("lastOrdinal").where("readModelId", "=", this.config.readModelId).executeTakeFirst();
17133
17135
  return row?.lastOrdinal;
17134
17136
  }
17135
17137
  async initializeState() {
17136
17138
  const viewStateDb = this.db;
17137
17139
  await viewStateDb.insertInto("ViewState").values({
17138
- readModelId: this.readModelId,
17140
+ readModelId: this.config.readModelId,
17139
17141
  lastOrdinal: 0
17140
17142
  }).execute();
17141
17143
  }
@@ -17145,7 +17147,7 @@ class BaseReadModel {
17145
17147
  await trx.updateTable("ViewState").set({
17146
17148
  lastOrdinal: maxOrdinal,
17147
17149
  lastOperationTimestamp: new Date
17148
- }).where("readModelId", "=", this.readModelId).execute();
17150
+ }).where("readModelId", "=", this.config.readModelId).execute();
17149
17151
  }
17150
17152
  updateConsistencyTracker(items) {
17151
17153
  const coordinates = [];
@@ -17870,6 +17872,661 @@ class ConsistencyTracker {
17870
17872
  }
17871
17873
  }
17872
17874
  }
17875
+ async function collectAllPages(firstPage, signal) {
17876
+ const allResults = [...firstPage.results];
17877
+ let currentPage = firstPage;
17878
+ while (currentPage.next) {
17879
+ if (signal?.aborted) {
17880
+ throw new Error("Operation aborted");
17881
+ }
17882
+ currentPage = await currentPage.next();
17883
+ allResults.push(...currentPage.results);
17884
+ }
17885
+ return allResults;
17886
+ }
17887
+
17888
+ class KyselyKeyframeStore {
17889
+ db;
17890
+ constructor(db) {
17891
+ this.db = db;
17892
+ }
17893
+ async putKeyframe(documentId, scope, branch, revision, document2, signal) {
17894
+ if (signal?.aborted) {
17895
+ throw new Error("Operation aborted");
17896
+ }
17897
+ await this.db.insertInto("Keyframe").values({
17898
+ documentId,
17899
+ documentType: document2.header.documentType,
17900
+ scope,
17901
+ branch,
17902
+ revision,
17903
+ document: document2
17904
+ }).onConflict((oc) => oc.columns(["documentId", "scope", "branch", "revision"]).doUpdateSet({ document: document2 })).execute();
17905
+ }
17906
+ async findNearestKeyframe(documentId, scope, branch, targetRevision, signal) {
17907
+ if (signal?.aborted) {
17908
+ throw new Error("Operation aborted");
17909
+ }
17910
+ 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();
17911
+ if (!row) {
17912
+ return;
17913
+ }
17914
+ return {
17915
+ revision: row.revision,
17916
+ document: row.document
17917
+ };
17918
+ }
17919
+ async deleteKeyframes(documentId, scope, branch, signal) {
17920
+ if (signal?.aborted) {
17921
+ throw new Error("Operation aborted");
17922
+ }
17923
+ let query = this.db.deleteFrom("Keyframe").where("documentId", "=", documentId);
17924
+ if (scope !== undefined && branch !== undefined) {
17925
+ query = query.where("scope", "=", scope).where("branch", "=", branch);
17926
+ } else if (scope !== undefined) {
17927
+ query = query.where("scope", "=", scope);
17928
+ }
17929
+ const result = await query.executeTakeFirst();
17930
+ return Number(result.numDeletedRows || 0n);
17931
+ }
17932
+ }
17933
+
17934
+ class AtomicTransaction {
17935
+ documentId;
17936
+ documentType;
17937
+ scope;
17938
+ branch;
17939
+ baseRevision;
17940
+ operations = [];
17941
+ constructor(documentId, documentType, scope, branch, baseRevision) {
17942
+ this.documentId = documentId;
17943
+ this.documentType = documentType;
17944
+ this.scope = scope;
17945
+ this.branch = branch;
17946
+ this.baseRevision = baseRevision;
17947
+ }
17948
+ addOperations(...operations) {
17949
+ for (const op of operations) {
17950
+ this.operations.push({
17951
+ jobId: v4_default(),
17952
+ opId: op.id,
17953
+ prevOpId: "",
17954
+ documentId: this.documentId,
17955
+ documentType: this.documentType,
17956
+ scope: this.scope,
17957
+ branch: this.branch,
17958
+ timestampUtcMs: new Date(op.timestampUtcMs),
17959
+ index: op.index,
17960
+ action: JSON.stringify(op.action),
17961
+ skip: op.skip,
17962
+ error: op.error || null,
17963
+ hash: op.hash
17964
+ });
17965
+ }
17966
+ }
17967
+ getOperations() {
17968
+ return this.operations;
17969
+ }
17970
+ }
17971
+
17972
+ class KyselyOperationStore {
17973
+ db;
17974
+ constructor(db) {
17975
+ this.db = db;
17976
+ }
17977
+ async apply(documentId, documentType, scope, branch, revision, fn, signal) {
17978
+ await this.db.transaction().execute(async (trx) => {
17979
+ if (signal?.aborted) {
17980
+ throw new Error("Operation aborted");
17981
+ }
17982
+ const latestOp = await trx.selectFrom("Operation").selectAll().where("documentId", "=", documentId).where("scope", "=", scope).where("branch", "=", branch).orderBy("index", "desc").limit(1).executeTakeFirst();
17983
+ const currentRevision = latestOp ? latestOp.index : -1;
17984
+ if (currentRevision !== revision - 1) {
17985
+ throw new RevisionMismatchError(currentRevision + 1, revision);
17986
+ }
17987
+ const atomicTxn = new AtomicTransaction(documentId, documentType, scope, branch, revision);
17988
+ await fn(atomicTxn);
17989
+ const operations = atomicTxn.getOperations();
17990
+ if (operations.length > 0) {
17991
+ let prevOpId = latestOp?.opId || "";
17992
+ for (const op of operations) {
17993
+ op.prevOpId = prevOpId;
17994
+ prevOpId = op.opId;
17995
+ }
17996
+ try {
17997
+ await trx.insertInto("Operation").values(operations).execute();
17998
+ } catch (error) {
17999
+ if (error instanceof Error) {
18000
+ if (error.message.includes("unique constraint")) {
18001
+ const op = operations[0];
18002
+ throw new DuplicateOperationError(`${op.opId} at index ${op.index} with skip ${op.skip}`);
18003
+ }
18004
+ throw error;
18005
+ }
18006
+ throw error;
18007
+ }
18008
+ }
18009
+ });
18010
+ }
18011
+ async getSince(documentId, scope, branch, revision, filter, paging, signal) {
18012
+ if (signal?.aborted) {
18013
+ throw new Error("Operation aborted");
18014
+ }
18015
+ let query = this.db.selectFrom("Operation").selectAll().where("documentId", "=", documentId).where("scope", "=", scope).where("branch", "=", branch).where("index", ">", revision).orderBy("index", "asc");
18016
+ if (filter) {
18017
+ if (filter.actionTypes && filter.actionTypes.length > 0) {
18018
+ const actionTypesArray = filter.actionTypes.map((t3) => `'${t3.replace(/'/g, "''")}'`).join(",");
18019
+ query = query.where(sql`action->>'type' = ANY(ARRAY[${sql.raw(actionTypesArray)}]::text[])`);
18020
+ }
18021
+ if (filter.timestampFrom) {
18022
+ query = query.where("timestampUtcMs", ">=", new Date(filter.timestampFrom));
18023
+ }
18024
+ if (filter.timestampTo) {
18025
+ query = query.where("timestampUtcMs", "<=", new Date(filter.timestampTo));
18026
+ }
18027
+ if (filter.sinceRevision !== undefined) {
18028
+ query = query.where("index", ">=", filter.sinceRevision);
18029
+ }
18030
+ }
18031
+ if (paging) {
18032
+ const cursorValue = Number.parseInt(paging.cursor, 10);
18033
+ if (cursorValue > 0) {
18034
+ query = query.where("index", ">", cursorValue);
18035
+ }
18036
+ if (paging.limit) {
18037
+ query = query.limit(paging.limit + 1);
18038
+ }
18039
+ }
18040
+ const rows = await query.execute();
18041
+ let hasMore = false;
18042
+ let items = rows;
18043
+ if (paging?.limit && rows.length > paging.limit) {
18044
+ hasMore = true;
18045
+ items = rows.slice(0, paging.limit);
18046
+ }
18047
+ const nextCursor = hasMore && items.length > 0 ? items[items.length - 1].index.toString() : undefined;
18048
+ const cursor = paging?.cursor || "0";
18049
+ const limit = paging?.limit || 100;
18050
+ const operations = items.map((row) => this.rowToOperation(row));
18051
+ return {
18052
+ results: operations,
18053
+ options: { cursor, limit },
18054
+ nextCursor,
18055
+ next: hasMore ? () => this.getSince(documentId, scope, branch, revision, filter, { cursor: nextCursor, limit }, signal) : undefined
18056
+ };
18057
+ }
18058
+ async getSinceId(id, paging, signal) {
18059
+ if (signal?.aborted) {
18060
+ throw new Error("Operation aborted");
18061
+ }
18062
+ let query = this.db.selectFrom("Operation").selectAll().where("id", ">", id).orderBy("id", "asc");
18063
+ if (paging) {
18064
+ const cursorValue = Number.parseInt(paging.cursor, 10);
18065
+ if (cursorValue > 0) {
18066
+ query = query.where("id", ">", cursorValue);
18067
+ }
18068
+ if (paging.limit) {
18069
+ query = query.limit(paging.limit + 1);
18070
+ }
18071
+ }
18072
+ const rows = await query.execute();
18073
+ let hasMore = false;
18074
+ let items = rows;
18075
+ if (paging?.limit && rows.length > paging.limit) {
18076
+ hasMore = true;
18077
+ items = rows.slice(0, paging.limit);
18078
+ }
18079
+ const nextCursor = hasMore && items.length > 0 ? items[items.length - 1].id.toString() : undefined;
18080
+ const cursor = paging?.cursor || "0";
18081
+ const limit = paging?.limit || 100;
18082
+ const operations = items.map((row) => this.rowToOperationWithContext(row));
18083
+ return {
18084
+ results: operations,
18085
+ options: { cursor, limit },
18086
+ nextCursor,
18087
+ next: hasMore ? () => this.getSinceId(id, { cursor: nextCursor, limit }, signal) : undefined
18088
+ };
18089
+ }
18090
+ async getConflicting(documentId, scope, branch, minTimestamp, paging, signal) {
18091
+ if (signal?.aborted) {
18092
+ throw new Error("Operation aborted");
18093
+ }
18094
+ let query = this.db.selectFrom("Operation").selectAll().where("documentId", "=", documentId).where("scope", "=", scope).where("branch", "=", branch).where("timestampUtcMs", ">=", new Date(minTimestamp)).orderBy("index", "asc");
18095
+ if (paging) {
18096
+ const cursorValue = Number.parseInt(paging.cursor, 10);
18097
+ if (cursorValue > 0) {
18098
+ query = query.where("index", ">", cursorValue);
18099
+ }
18100
+ if (paging.limit) {
18101
+ query = query.limit(paging.limit + 1);
18102
+ }
18103
+ }
18104
+ const rows = await query.execute();
18105
+ let hasMore = false;
18106
+ let items = rows;
18107
+ if (paging?.limit && rows.length > paging.limit) {
18108
+ hasMore = true;
18109
+ items = rows.slice(0, paging.limit);
18110
+ }
18111
+ const nextCursor = hasMore && items.length > 0 ? items[items.length - 1].index.toString() : undefined;
18112
+ const cursor = paging?.cursor || "0";
18113
+ const limit = paging?.limit || 100;
18114
+ const operations = items.map((row) => this.rowToOperation(row));
18115
+ return {
18116
+ results: operations,
18117
+ options: { cursor, limit },
18118
+ nextCursor,
18119
+ next: hasMore ? () => this.getConflicting(documentId, scope, branch, minTimestamp, { cursor: nextCursor, limit }, signal) : undefined
18120
+ };
18121
+ }
18122
+ async getRevisions(documentId, branch, signal) {
18123
+ if (signal?.aborted) {
18124
+ throw new Error("Operation aborted");
18125
+ }
18126
+ 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();
18127
+ const revision = {};
18128
+ let latestTimestamp = new Date(0).toISOString();
18129
+ for (const row of scopeRevisions) {
18130
+ revision[row.scope] = row.index + 1;
18131
+ const timestamp = row.timestampUtcMs.toISOString();
18132
+ if (timestamp > latestTimestamp) {
18133
+ latestTimestamp = timestamp;
18134
+ }
18135
+ }
18136
+ return {
18137
+ revision,
18138
+ latestTimestamp
18139
+ };
18140
+ }
18141
+ rowToOperation(row) {
18142
+ return {
18143
+ index: row.index,
18144
+ timestampUtcMs: row.timestampUtcMs.toISOString(),
18145
+ hash: row.hash,
18146
+ skip: row.skip,
18147
+ error: row.error || undefined,
18148
+ id: row.opId,
18149
+ action: row.action
18150
+ };
18151
+ }
18152
+ rowToOperationWithContext(row) {
18153
+ return {
18154
+ operation: this.rowToOperation(row),
18155
+ context: {
18156
+ documentId: row.documentId,
18157
+ documentType: row.documentType,
18158
+ scope: row.scope,
18159
+ branch: row.branch,
18160
+ ordinal: row.id
18161
+ }
18162
+ };
18163
+ }
18164
+ }
18165
+ async function up(db) {
18166
+ 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", [
18167
+ "documentId",
18168
+ "scope",
18169
+ "branch",
18170
+ "index"
18171
+ ]).addUniqueConstraint("unique_operation_instance", ["opId", "index", "skip"]).execute();
18172
+ await db.schema.createIndex("streamOperations").on("Operation").columns(["documentId", "scope", "branch", "id"]).execute();
18173
+ await db.schema.createIndex("branchlessStreamOperations").on("Operation").columns(["documentId", "scope", "id"]).execute();
18174
+ }
18175
+ async function up2(db) {
18176
+ 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", [
18177
+ "documentId",
18178
+ "scope",
18179
+ "branch",
18180
+ "revision"
18181
+ ]).execute();
18182
+ await db.schema.createIndex("keyframe_lookup").on("Keyframe").columns(["documentId", "scope", "branch", "revision"]).execute();
18183
+ }
18184
+ async function up3(db) {
18185
+ 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();
18186
+ }
18187
+ async function up4(db) {
18188
+ 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", [
18189
+ "sourceId",
18190
+ "targetId",
18191
+ "relationshipType"
18192
+ ]).execute();
18193
+ await db.schema.createIndex("idx_relationship_source").on("DocumentRelationship").column("sourceId").execute();
18194
+ await db.schema.createIndex("idx_relationship_target").on("DocumentRelationship").column("targetId").execute();
18195
+ await db.schema.createIndex("idx_relationship_type").on("DocumentRelationship").column("relationshipType").execute();
18196
+ }
18197
+ async function up5(db) {
18198
+ 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();
18199
+ }
18200
+ async function up6(db) {
18201
+ 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", [
18202
+ "documentId",
18203
+ "scope",
18204
+ "branch"
18205
+ ]).execute();
18206
+ await db.schema.createIndex("idx_slug_scope_branch").on("DocumentSnapshot").columns(["slug", "scope", "branch"]).execute();
18207
+ await db.schema.createIndex("idx_doctype_scope_branch").on("DocumentSnapshot").columns(["documentType", "scope", "branch"]).execute();
18208
+ await db.schema.createIndex("idx_last_updated").on("DocumentSnapshot").column("lastUpdatedAt").execute();
18209
+ await db.schema.createIndex("idx_is_deleted").on("DocumentSnapshot").column("isDeleted").execute();
18210
+ }
18211
+ async function up7(db) {
18212
+ 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", [
18213
+ "documentId",
18214
+ "scope",
18215
+ "branch"
18216
+ ]).execute();
18217
+ await db.schema.createIndex("idx_slug_documentid").on("SlugMapping").column("documentId").execute();
18218
+ }
18219
+ async function up8(db) {
18220
+ 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();
18221
+ }
18222
+ async function up9(db) {
18223
+ 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", [
18224
+ "documentId",
18225
+ "collectionId"
18226
+ ]).execute();
18227
+ await db.schema.createIndex("idx_document_collections_collectionId").on("document_collections").column("collectionId").execute();
18228
+ await db.schema.createIndex("idx_doc_collections_collection_range").on("document_collections").columns(["collectionId", "joinedOrdinal"]).execute();
18229
+ 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();
18230
+ await db.schema.createIndex("idx_operation_index_operations_document").on("operation_index_operations").columns(["documentId", "branch", "scope"]).execute();
18231
+ await db.schema.createIndex("idx_operation_index_operations_ordinal").on("operation_index_operations").column("ordinal").execute();
18232
+ }
18233
+ async function up10(db) {
18234
+ 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();
18235
+ await db.schema.createIndex("idx_sync_remotes_collection").on("sync_remotes").column("collection_id").execute();
18236
+ 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();
18237
+ await db.schema.createIndex("idx_sync_cursors_ordinal").on("sync_cursors").column("cursor_ordinal").execute();
18238
+ }
18239
+ async function up11(db) {
18240
+ await db.deleteFrom("sync_cursors").where("remote_name", "like", "outbox::%").execute();
18241
+ await db.deleteFrom("sync_remotes").where("name", "like", "outbox::%").execute();
18242
+ await db.schema.dropTable("sync_cursors").execute();
18243
+ 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();
18244
+ await db.schema.createIndex("idx_sync_cursors_ordinal").on("sync_cursors").column("cursor_ordinal").execute();
18245
+ }
18246
+ async function up12(db) {
18247
+ await db.schema.alterTable("operation_index_operations").addColumn("sourceRemote", "text", (col) => col.notNull().defaultTo("")).execute();
18248
+ }
18249
+ async function up13(db) {
18250
+ 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();
18251
+ await db.schema.createIndex("idx_sync_dead_letters_remote").on("sync_dead_letters").column("remote_name").execute();
18252
+ }
18253
+ async function up14(db) {
18254
+ 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();
18255
+ }
18256
+
18257
+ class ProgrammaticMigrationProvider {
18258
+ getMigrations() {
18259
+ return Promise.resolve(migrations);
18260
+ }
18261
+ }
18262
+ async function runMigrations(db, schema = REACTOR_SCHEMA) {
18263
+ try {
18264
+ await sql`CREATE SCHEMA IF NOT EXISTS ${sql.id(schema)}`.execute(db);
18265
+ } catch (error2) {
18266
+ return {
18267
+ success: false,
18268
+ migrationsExecuted: [],
18269
+ error: error2 instanceof Error ? error2 : new Error("Failed to create schema")
18270
+ };
18271
+ }
18272
+ const migrator = new Migrator({
18273
+ db: db.withSchema(schema),
18274
+ provider: new ProgrammaticMigrationProvider,
18275
+ migrationTableSchema: schema
18276
+ });
18277
+ let error;
18278
+ let results;
18279
+ try {
18280
+ const result = await migrator.migrateToLatest();
18281
+ error = result.error;
18282
+ results = result.results;
18283
+ } catch (e2) {
18284
+ error = e2;
18285
+ results = [];
18286
+ }
18287
+ const migrationsExecuted = results?.map((result) => result.migrationName) ?? [];
18288
+ if (error) {
18289
+ return {
18290
+ success: false,
18291
+ migrationsExecuted,
18292
+ error: error instanceof Error ? error : new Error("Unknown migration error")
18293
+ };
18294
+ }
18295
+ return {
18296
+ success: true,
18297
+ migrationsExecuted
18298
+ };
18299
+ }
18300
+
18301
+ class DefaultSubscriptionErrorHandler {
18302
+ handleError(error, context) {
18303
+ const errorMessage = `Subscription error in ${context.eventType} (${context.subscriptionId})`;
18304
+ if (error instanceof Error) {
18305
+ const enhancedError = new Error(`${errorMessage}: ${error.message}`);
18306
+ enhancedError.cause = error;
18307
+ enhancedError.stack = error.stack;
18308
+ throw enhancedError;
18309
+ } else {
18310
+ throw new Error(`${errorMessage}: ${String(error)}`);
18311
+ }
18312
+ }
18313
+ }
18314
+
18315
+ class ReactorSubscriptionManager {
18316
+ createdSubscriptions = new Map;
18317
+ deletedSubscriptions = new Map;
18318
+ updatedSubscriptions = new Map;
18319
+ relationshipSubscriptions = new Map;
18320
+ subscriptionCounter = 0;
18321
+ errorHandler;
18322
+ constructor(errorHandler) {
18323
+ this.errorHandler = errorHandler;
18324
+ }
18325
+ onDocumentCreated(callback, search) {
18326
+ const id = `created-${++this.subscriptionCounter}`;
18327
+ this.createdSubscriptions.set(id, { id, callback, search });
18328
+ return () => {
18329
+ this.createdSubscriptions.delete(id);
18330
+ };
18331
+ }
18332
+ onDocumentDeleted(callback, search) {
18333
+ const id = `deleted-${++this.subscriptionCounter}`;
18334
+ this.deletedSubscriptions.set(id, { id, callback, search });
18335
+ return () => {
18336
+ this.deletedSubscriptions.delete(id);
18337
+ };
18338
+ }
18339
+ onDocumentStateUpdated(callback, search, view) {
18340
+ const id = `updated-${++this.subscriptionCounter}`;
18341
+ this.updatedSubscriptions.set(id, { id, callback, search, view });
18342
+ return () => {
18343
+ this.updatedSubscriptions.delete(id);
18344
+ };
18345
+ }
18346
+ onRelationshipChanged(callback, search) {
18347
+ const id = `relationship-${++this.subscriptionCounter}`;
18348
+ this.relationshipSubscriptions.set(id, { id, callback, search });
18349
+ return () => {
18350
+ this.relationshipSubscriptions.delete(id);
18351
+ };
18352
+ }
18353
+ notifyDocumentsCreated(documentIds, documentTypes, parentIds) {
18354
+ const result = {
18355
+ results: documentIds,
18356
+ options: { cursor: "", limit: documentIds.length }
18357
+ };
18358
+ for (const subscription of this.createdSubscriptions.values()) {
18359
+ const filteredIds = this.filterDocumentIds(documentIds, subscription.search, documentTypes, parentIds);
18360
+ if (filteredIds.length > 0) {
18361
+ try {
18362
+ subscription.callback({
18363
+ ...result,
18364
+ results: filteredIds
18365
+ });
18366
+ } catch (error) {
18367
+ this.errorHandler.handleError(error, {
18368
+ eventType: "created",
18369
+ subscriptionId: subscription.id,
18370
+ eventData: filteredIds
18371
+ });
18372
+ }
18373
+ }
18374
+ }
18375
+ }
18376
+ notifyDocumentsDeleted(documentIds, documentTypes, parentIds) {
18377
+ for (const subscription of this.deletedSubscriptions.values()) {
18378
+ const filteredIds = this.filterDocumentIds(documentIds, subscription.search, documentTypes, parentIds);
18379
+ if (filteredIds.length > 0) {
18380
+ try {
18381
+ subscription.callback(filteredIds);
18382
+ } catch (error) {
18383
+ this.errorHandler.handleError(error, {
18384
+ eventType: "deleted",
18385
+ subscriptionId: subscription.id,
18386
+ eventData: filteredIds
18387
+ });
18388
+ }
18389
+ }
18390
+ }
18391
+ }
18392
+ notifyDocumentsUpdated(documents) {
18393
+ const result = {
18394
+ results: documents,
18395
+ options: { cursor: "", limit: documents.length }
18396
+ };
18397
+ for (const subscription of this.updatedSubscriptions.values()) {
18398
+ const filteredDocs = this.filterDocuments(documents, subscription.search);
18399
+ if (filteredDocs.length > 0) {
18400
+ try {
18401
+ subscription.callback({
18402
+ ...result,
18403
+ results: filteredDocs
18404
+ });
18405
+ } catch (error) {
18406
+ this.errorHandler.handleError(error, {
18407
+ eventType: "updated",
18408
+ subscriptionId: subscription.id,
18409
+ eventData: filteredDocs
18410
+ });
18411
+ }
18412
+ }
18413
+ }
18414
+ }
18415
+ notifyRelationshipChanged(parentId, childId, changeType, childType) {
18416
+ for (const subscription of this.relationshipSubscriptions.values()) {
18417
+ if (this.matchesRelationshipFilter(parentId, childId, childType, subscription.search)) {
18418
+ try {
18419
+ subscription.callback(parentId, childId, changeType);
18420
+ } catch (error) {
18421
+ this.errorHandler.handleError(error, {
18422
+ eventType: "relationshipChanged",
18423
+ subscriptionId: subscription.id,
18424
+ eventData: { parentId, childId, changeType }
18425
+ });
18426
+ }
18427
+ }
18428
+ }
18429
+ }
18430
+ clearAll() {
18431
+ this.createdSubscriptions.clear();
18432
+ this.deletedSubscriptions.clear();
18433
+ this.updatedSubscriptions.clear();
18434
+ this.relationshipSubscriptions.clear();
18435
+ }
18436
+ filterDocumentIds(documentIds, search, documentTypes, parentIds) {
18437
+ if (!search)
18438
+ return documentIds;
18439
+ return documentIds.filter((id) => {
18440
+ if (search.ids && !search.ids.includes(id))
18441
+ return false;
18442
+ if (search.type && documentTypes) {
18443
+ const docType = documentTypes.get(id);
18444
+ if (docType !== search.type)
18445
+ return false;
18446
+ }
18447
+ if (search.parentId && parentIds) {
18448
+ const parentId = parentIds.get(id);
18449
+ if (parentId !== search.parentId)
18450
+ return false;
18451
+ }
18452
+ return true;
18453
+ });
18454
+ }
18455
+ filterDocuments(documents, search) {
18456
+ if (!search)
18457
+ return documents;
18458
+ return documents.filter((doc) => {
18459
+ if (search.ids && !search.ids.includes(doc.header.id))
18460
+ return false;
18461
+ if (search.type && doc.header.documentType !== search.type)
18462
+ return false;
18463
+ if (search.slugs && !search.slugs.includes(doc.header.slug))
18464
+ return false;
18465
+ return true;
18466
+ });
18467
+ }
18468
+ matchesRelationshipFilter(parentId, childId, childType, search) {
18469
+ if (!search)
18470
+ return true;
18471
+ if (search.parentId && parentId !== search.parentId)
18472
+ return false;
18473
+ if (search.ids && !search.ids.includes(childId))
18474
+ return false;
18475
+ if (search.type && childType && childType !== search.type)
18476
+ return false;
18477
+ return true;
18478
+ }
18479
+ }
18480
+
18481
+ class SubscriptionNotificationReadModel {
18482
+ subscriptionManager;
18483
+ documentView;
18484
+ constructor(subscriptionManager, documentView) {
18485
+ this.subscriptionManager = subscriptionManager;
18486
+ this.documentView = documentView;
18487
+ }
18488
+ async indexOperations(operations) {
18489
+ if (operations.length === 0)
18490
+ return;
18491
+ const created = [];
18492
+ const deleted = [];
18493
+ const updatedIds = new Set;
18494
+ const documentTypes = new Map;
18495
+ const parentIds = new Map;
18496
+ for (const item of operations) {
18497
+ const { operation, context } = item;
18498
+ const actionType = operation.action.type;
18499
+ documentTypes.set(context.documentId, context.documentType);
18500
+ if (actionType === "CREATE_DOCUMENT") {
18501
+ created.push(context.documentId);
18502
+ } else if (actionType === "DELETE_DOCUMENT") {
18503
+ const input = operation.action.input;
18504
+ const deletedId = input.documentId ?? context.documentId;
18505
+ deleted.push(deletedId);
18506
+ } else if (actionType === "ADD_RELATIONSHIP") {
18507
+ const input = operation.action.input;
18508
+ this.subscriptionManager.notifyRelationshipChanged(input.sourceId, input.targetId, "added", input.childType);
18509
+ } else if (actionType === "REMOVE_RELATIONSHIP") {
18510
+ const input = operation.action.input;
18511
+ this.subscriptionManager.notifyRelationshipChanged(input.sourceId, input.targetId, "removed", input.childType);
18512
+ } else {
18513
+ if (!created.includes(context.documentId)) {
18514
+ updatedIds.add(context.documentId);
18515
+ }
18516
+ }
18517
+ }
18518
+ if (created.length > 0) {
18519
+ this.subscriptionManager.notifyDocumentsCreated(created, documentTypes, parentIds);
18520
+ }
18521
+ if (deleted.length > 0) {
18522
+ this.subscriptionManager.notifyDocumentsDeleted(deleted, documentTypes, parentIds);
18523
+ }
18524
+ if (updatedIds.size > 0 && this.documentView) {
18525
+ const documents = await Promise.all(Array.from(updatedIds).map((id) => this.documentView.get(id)));
18526
+ this.subscriptionManager.notifyDocumentsUpdated(documents);
18527
+ }
18528
+ }
18529
+ }
17873
18530
 
17874
18531
  class Mailbox {
17875
18532
  itemsMap = new Map;
@@ -18630,6 +19287,8 @@ class GqlRequestChannel {
18630
19287
  pushFailureCount = 0;
18631
19288
  pushRetryTimer = null;
18632
19289
  pushBlocked = false;
19290
+ connectionState = "connecting";
19291
+ connectionStateCallbacks = new Set;
18633
19292
  constructor(logger2, channelId, remoteName, cursorStorage, config, operationIndex, pollTimer) {
18634
19293
  this.logger = logger2;
18635
19294
  this.channelId = channelId;
@@ -18658,6 +19317,7 @@ class GqlRequestChannel {
18658
19317
  clearTimeout(this.pushRetryTimer);
18659
19318
  this.pushRetryTimer = null;
18660
19319
  }
19320
+ this.transitionConnectionState("error");
18661
19321
  });
18662
19322
  this.outbox.onAdded((syncOps) => {
18663
19323
  if (this.isShutdown)
@@ -18705,8 +19365,25 @@ class GqlRequestChannel {
18705
19365
  clearTimeout(this.pushRetryTimer);
18706
19366
  this.pushRetryTimer = null;
18707
19367
  }
19368
+ this.transitionConnectionState("disconnected");
18708
19369
  return Promise.resolve();
18709
19370
  }
19371
+ getConnectionState() {
19372
+ return {
19373
+ state: this.connectionState,
19374
+ failureCount: this.failureCount,
19375
+ lastSuccessUtcMs: this.lastSuccessUtcMs ?? 0,
19376
+ lastFailureUtcMs: this.lastFailureUtcMs ?? 0,
19377
+ pushBlocked: this.pushBlocked,
19378
+ pushFailureCount: this.pushFailureCount
19379
+ };
19380
+ }
19381
+ onConnectionStateChange(callback) {
19382
+ this.connectionStateCallbacks.add(callback);
19383
+ return () => {
19384
+ this.connectionStateCallbacks.delete(callback);
19385
+ };
19386
+ }
18710
19387
  async init() {
18711
19388
  await this.touchRemoteChannel();
18712
19389
  const cursors = await this.cursorStorage.list(this.remoteName);
@@ -18718,6 +19395,20 @@ class GqlRequestChannel {
18718
19395
  this.lastPersistedOutboxOrdinal = outboxOrdinal;
18719
19396
  this.pollTimer.setDelegate(() => this.poll());
18720
19397
  this.pollTimer.start();
19398
+ this.transitionConnectionState("connected");
19399
+ }
19400
+ transitionConnectionState(next) {
19401
+ if (this.connectionState === next)
19402
+ return;
19403
+ this.connectionState = next;
19404
+ const snapshot = this.getConnectionState();
19405
+ for (const callback of this.connectionStateCallbacks) {
19406
+ try {
19407
+ callback(snapshot);
19408
+ } catch (error) {
19409
+ this.logger.error("Connection state change callback error: @Error", error);
19410
+ }
19411
+ }
18721
19412
  }
18722
19413
  async poll() {
18723
19414
  if (this.isShutdown) {
@@ -18756,6 +19447,7 @@ class GqlRequestChannel {
18756
19447
  }
18757
19448
  this.lastSuccessUtcMs = Date.now();
18758
19449
  this.failureCount = 0;
19450
+ this.transitionConnectionState("connected");
18759
19451
  }
18760
19452
  handleRemoteDeadLetters(deadLetters) {
18761
19453
  for (const dl of deadLetters) {
@@ -18772,11 +19464,13 @@ class GqlRequestChannel {
18772
19464
  handlePollError(error) {
18773
19465
  const err = error instanceof Error ? error : new Error(String(error));
18774
19466
  if (err.message.includes("Channel not found")) {
19467
+ this.transitionConnectionState("reconnecting");
18775
19468
  this.recoverFromChannelNotFound();
18776
19469
  return true;
18777
19470
  }
18778
19471
  this.failureCount++;
18779
19472
  this.lastFailureUtcMs = Date.now();
19473
+ this.transitionConnectionState("error");
18780
19474
  const channelError = new ChannelError("inbox", err);
18781
19475
  this.logger.error("GqlChannel poll error (@FailureCount): @Error", this.failureCount, channelError);
18782
19476
  return false;
@@ -18788,11 +19482,13 @@ class GqlRequestChannel {
18788
19482
  this.logger.info("GqlChannel @ChannelId re-registered successfully", this.channelId);
18789
19483
  this.failureCount = 0;
18790
19484
  this.pollTimer.start();
19485
+ this.transitionConnectionState("connected");
18791
19486
  }).catch((recoveryError) => {
18792
19487
  this.logger.error("GqlChannel @ChannelId failed to re-register: @Error", this.channelId, recoveryError);
18793
19488
  this.failureCount++;
18794
19489
  this.lastFailureUtcMs = Date.now();
18795
19490
  this.pollTimer.start();
19491
+ this.transitionConnectionState("error");
18796
19492
  });
18797
19493
  }
18798
19494
  async pollSyncEnvelopes(ackOrdinal, latestOrdinal) {
@@ -18913,12 +19609,16 @@ class GqlRequestChannel {
18913
19609
  this.pushSyncOperations(syncOps).then(() => {
18914
19610
  this.pushBlocked = false;
18915
19611
  this.pushFailureCount = 0;
19612
+ if (this.connectionState === "reconnecting" || this.connectionState === "error") {
19613
+ this.transitionConnectionState("connected");
19614
+ }
18916
19615
  }).catch((error) => {
18917
19616
  const err = error instanceof Error ? error : new Error(String(error));
18918
19617
  if (this.isRecoverablePushError(err)) {
18919
19618
  this.pushFailureCount++;
18920
19619
  this.pushBlocked = true;
18921
19620
  this.logger.error("GqlChannel push failed (attempt @FailureCount), will retry: @Error", this.pushFailureCount, err);
19621
+ this.transitionConnectionState("reconnecting");
18922
19622
  this.schedulePushRetry();
18923
19623
  } else {
18924
19624
  const channelError = new ChannelError("outbox", err);
@@ -18927,6 +19627,7 @@ class GqlRequestChannel {
18927
19627
  }
18928
19628
  this.deadLetter.add(...syncOps);
18929
19629
  this.outbox.remove(...syncOps);
19630
+ this.transitionConnectionState("error");
18930
19631
  }
18931
19632
  });
18932
19633
  }
@@ -19052,14 +19753,6 @@ class GqlRequestChannel {
19052
19753
  }
19053
19754
  return result.data;
19054
19755
  }
19055
- getHealth() {
19056
- return {
19057
- state: this.failureCount > 0 ? "error" : "idle",
19058
- lastSuccessUtcMs: this.lastSuccessUtcMs,
19059
- lastFailureUtcMs: this.lastFailureUtcMs,
19060
- failureCount: this.failureCount
19061
- };
19062
- }
19063
19756
  get poller() {
19064
19757
  return this.pollTimer;
19065
19758
  }
@@ -19158,6 +19851,8 @@ class GqlResponseChannel {
19158
19851
  isShutdown;
19159
19852
  lastPersistedInboxOrdinal = 0;
19160
19853
  lastPersistedOutboxOrdinal = 0;
19854
+ connectionState = "connecting";
19855
+ connectionStateCallbacks = new Set;
19161
19856
  constructor(logger2, channelId, remoteName, cursorStorage) {
19162
19857
  this.logger = logger2;
19163
19858
  this.channelId = channelId;
@@ -19198,8 +19893,38 @@ class GqlResponseChannel {
19198
19893
  }
19199
19894
  shutdown() {
19200
19895
  this.isShutdown = true;
19896
+ this.transitionConnectionState("disconnected");
19201
19897
  return Promise.resolve();
19202
19898
  }
19899
+ getConnectionState() {
19900
+ return {
19901
+ state: this.connectionState,
19902
+ failureCount: 0,
19903
+ lastSuccessUtcMs: 0,
19904
+ lastFailureUtcMs: 0,
19905
+ pushBlocked: false,
19906
+ pushFailureCount: 0
19907
+ };
19908
+ }
19909
+ onConnectionStateChange(callback) {
19910
+ this.connectionStateCallbacks.add(callback);
19911
+ return () => {
19912
+ this.connectionStateCallbacks.delete(callback);
19913
+ };
19914
+ }
19915
+ transitionConnectionState(next) {
19916
+ if (this.connectionState === next)
19917
+ return;
19918
+ this.connectionState = next;
19919
+ const snapshot = this.getConnectionState();
19920
+ for (const callback of this.connectionStateCallbacks) {
19921
+ try {
19922
+ callback(snapshot);
19923
+ } catch (error) {
19924
+ this.logger.error("Connection state change callback error: @Error", error);
19925
+ }
19926
+ }
19927
+ }
19203
19928
  async init() {
19204
19929
  const cursors = await this.cursorStorage.list(this.remoteName);
19205
19930
  const inboxOrdinal = cursors.find((c2) => c2.cursorType === "inbox")?.cursorOrdinal ?? 0;
@@ -19208,6 +19933,7 @@ class GqlResponseChannel {
19208
19933
  this.outbox.init(outboxOrdinal);
19209
19934
  this.lastPersistedInboxOrdinal = inboxOrdinal;
19210
19935
  this.lastPersistedOutboxOrdinal = outboxOrdinal;
19936
+ this.transitionConnectionState("connected");
19211
19937
  }
19212
19938
  }
19213
19939
 
@@ -19220,981 +19946,6 @@ class GqlResponseChannelFactory {
19220
19946
  return new GqlResponseChannel(this.logger, remoteId, remoteName, cursorStorage);
19221
19947
  }
19222
19948
  }
19223
- async function collectAllPages(firstPage, signal) {
19224
- const allResults = [...firstPage.results];
19225
- let currentPage = firstPage;
19226
- while (currentPage.next) {
19227
- if (signal?.aborted) {
19228
- throw new Error("Operation aborted");
19229
- }
19230
- currentPage = await currentPage.next();
19231
- allResults.push(...currentPage.results);
19232
- }
19233
- return allResults;
19234
- }
19235
-
19236
- class KyselyDocumentIndexer {
19237
- db;
19238
- operationStore;
19239
- consistencyTracker;
19240
- lastOperationId = 0;
19241
- constructor(db, operationStore, consistencyTracker) {
19242
- this.db = db;
19243
- this.operationStore = operationStore;
19244
- this.consistencyTracker = consistencyTracker;
19245
- }
19246
- async init() {
19247
- const indexerState = await this.db.selectFrom("IndexerState").selectAll().executeTakeFirst();
19248
- if (indexerState) {
19249
- this.lastOperationId = indexerState.lastOperationId;
19250
- const missedOperations = await this.operationStore.getSinceId(this.lastOperationId);
19251
- if (missedOperations.results.length > 0) {
19252
- await this.indexOperations(missedOperations.results);
19253
- }
19254
- } else {
19255
- await this.db.insertInto("IndexerState").values({
19256
- lastOperationId: 0
19257
- }).execute();
19258
- const allOperations = await this.operationStore.getSinceId(0);
19259
- if (allOperations.results.length > 0) {
19260
- await this.indexOperations(allOperations.results);
19261
- }
19262
- }
19263
- }
19264
- async indexOperations(items) {
19265
- if (items.length === 0)
19266
- return;
19267
- await this.db.transaction().execute(async (trx) => {
19268
- for (const item of items) {
19269
- const { operation } = item;
19270
- const actionType = operation.action.type;
19271
- if (actionType === "ADD_RELATIONSHIP") {
19272
- await this.handleAddRelationship(trx, operation);
19273
- } else if (actionType === "REMOVE_RELATIONSHIP") {
19274
- await this.handleRemoveRelationship(trx, operation);
19275
- }
19276
- }
19277
- const lastOpId = items[items.length - 1].operation.id;
19278
- if (lastOpId && typeof lastOpId === "number") {
19279
- this.lastOperationId = lastOpId;
19280
- await trx.updateTable("IndexerState").set({
19281
- lastOperationId: lastOpId,
19282
- lastOperationTimestamp: new Date
19283
- }).execute();
19284
- }
19285
- });
19286
- const coordinates = [];
19287
- for (let i2 = 0;i2 < items.length; i2++) {
19288
- const item = items[i2];
19289
- coordinates.push({
19290
- documentId: item.context.documentId,
19291
- scope: item.context.scope,
19292
- branch: item.context.branch,
19293
- operationIndex: item.operation.index
19294
- });
19295
- }
19296
- this.consistencyTracker.update(coordinates);
19297
- }
19298
- async waitForConsistency(token, timeoutMs, signal) {
19299
- if (token.coordinates.length === 0) {
19300
- return;
19301
- }
19302
- await this.consistencyTracker.waitFor(token.coordinates, timeoutMs, signal);
19303
- }
19304
- async getOutgoing(documentId, types2, paging, consistencyToken, signal) {
19305
- if (consistencyToken) {
19306
- await this.waitForConsistency(consistencyToken, undefined, signal);
19307
- }
19308
- if (signal?.aborted) {
19309
- throw new Error("Operation aborted");
19310
- }
19311
- const startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;
19312
- const limit = paging?.limit || 100;
19313
- let query = this.db.selectFrom("DocumentRelationship").selectAll().where("sourceId", "=", documentId);
19314
- if (types2 && types2.length > 0) {
19315
- query = query.where("relationshipType", "in", types2);
19316
- }
19317
- const rows = await query.orderBy("createdAt", "asc").orderBy("id", "asc").offset(startIndex).limit(limit + 1).execute();
19318
- const hasMore = rows.length > limit;
19319
- const results = hasMore ? rows.slice(0, limit) : rows;
19320
- const nextCursor = hasMore ? String(startIndex + limit) : undefined;
19321
- return {
19322
- results: results.map((row) => ({
19323
- sourceId: row.sourceId,
19324
- targetId: row.targetId,
19325
- relationshipType: row.relationshipType,
19326
- metadata: row.metadata ? row.metadata : undefined,
19327
- createdAt: row.createdAt,
19328
- updatedAt: row.updatedAt
19329
- })),
19330
- options: paging || { cursor: "0", limit: 100 },
19331
- nextCursor,
19332
- next: hasMore ? () => this.getOutgoing(documentId, types2, { cursor: nextCursor, limit }, consistencyToken, signal) : undefined
19333
- };
19334
- }
19335
- async getIncoming(documentId, types2, paging, consistencyToken, signal) {
19336
- if (consistencyToken) {
19337
- await this.waitForConsistency(consistencyToken, undefined, signal);
19338
- }
19339
- if (signal?.aborted) {
19340
- throw new Error("Operation aborted");
19341
- }
19342
- const startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;
19343
- const limit = paging?.limit || 100;
19344
- let query = this.db.selectFrom("DocumentRelationship").selectAll().where("targetId", "=", documentId);
19345
- if (types2 && types2.length > 0) {
19346
- query = query.where("relationshipType", "in", types2);
19347
- }
19348
- const rows = await query.orderBy("createdAt", "asc").orderBy("id", "asc").offset(startIndex).limit(limit + 1).execute();
19349
- const hasMore = rows.length > limit;
19350
- const results = hasMore ? rows.slice(0, limit) : rows;
19351
- const nextCursor = hasMore ? String(startIndex + limit) : undefined;
19352
- return {
19353
- results: results.map((row) => ({
19354
- sourceId: row.sourceId,
19355
- targetId: row.targetId,
19356
- relationshipType: row.relationshipType,
19357
- metadata: row.metadata ? row.metadata : undefined,
19358
- createdAt: row.createdAt,
19359
- updatedAt: row.updatedAt
19360
- })),
19361
- options: paging || { cursor: "0", limit: 100 },
19362
- nextCursor,
19363
- next: hasMore ? () => this.getIncoming(documentId, types2, { cursor: nextCursor, limit }, consistencyToken, signal) : undefined
19364
- };
19365
- }
19366
- async hasRelationship(sourceId, targetId, types2, consistencyToken, signal) {
19367
- if (consistencyToken) {
19368
- await this.waitForConsistency(consistencyToken, undefined, signal);
19369
- }
19370
- if (signal?.aborted) {
19371
- throw new Error("Operation aborted");
19372
- }
19373
- let query = this.db.selectFrom("DocumentRelationship").select("id").where("sourceId", "=", sourceId).where("targetId", "=", targetId);
19374
- if (types2 && types2.length > 0) {
19375
- query = query.where("relationshipType", "in", types2);
19376
- }
19377
- const result = await query.executeTakeFirst();
19378
- return result !== undefined;
19379
- }
19380
- async getUndirectedRelationships(a2, b, types2, paging, consistencyToken, signal) {
19381
- if (consistencyToken) {
19382
- await this.waitForConsistency(consistencyToken, undefined, signal);
19383
- }
19384
- if (signal?.aborted) {
19385
- throw new Error("Operation aborted");
19386
- }
19387
- const startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;
19388
- const limit = paging?.limit || 100;
19389
- let query = this.db.selectFrom("DocumentRelationship").selectAll().where((eb) => eb.or([
19390
- eb.and([eb("sourceId", "=", a2), eb("targetId", "=", b)]),
19391
- eb.and([eb("sourceId", "=", b), eb("targetId", "=", a2)])
19392
- ]));
19393
- if (types2 && types2.length > 0) {
19394
- query = query.where("relationshipType", "in", types2);
19395
- }
19396
- const rows = await query.orderBy("createdAt", "asc").orderBy("id", "asc").offset(startIndex).limit(limit + 1).execute();
19397
- const hasMore = rows.length > limit;
19398
- const results = hasMore ? rows.slice(0, limit) : rows;
19399
- const nextCursor = hasMore ? String(startIndex + limit) : undefined;
19400
- return {
19401
- results: results.map((row) => ({
19402
- sourceId: row.sourceId,
19403
- targetId: row.targetId,
19404
- relationshipType: row.relationshipType,
19405
- metadata: row.metadata ? row.metadata : undefined,
19406
- createdAt: row.createdAt,
19407
- updatedAt: row.updatedAt
19408
- })),
19409
- options: paging || { cursor: "0", limit: 100 },
19410
- nextCursor,
19411
- next: hasMore ? () => this.getUndirectedRelationships(a2, b, types2, { cursor: nextCursor, limit }, consistencyToken, signal) : undefined
19412
- };
19413
- }
19414
- async getDirectedRelationships(sourceId, targetId, types2, paging, consistencyToken, signal) {
19415
- if (consistencyToken) {
19416
- await this.waitForConsistency(consistencyToken, undefined, signal);
19417
- }
19418
- if (signal?.aborted) {
19419
- throw new Error("Operation aborted");
19420
- }
19421
- const startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;
19422
- const limit = paging?.limit || 100;
19423
- let query = this.db.selectFrom("DocumentRelationship").selectAll().where("sourceId", "=", sourceId).where("targetId", "=", targetId);
19424
- if (types2 && types2.length > 0) {
19425
- query = query.where("relationshipType", "in", types2);
19426
- }
19427
- const rows = await query.orderBy("createdAt", "asc").orderBy("id", "asc").offset(startIndex).limit(limit + 1).execute();
19428
- const hasMore = rows.length > limit;
19429
- const results = hasMore ? rows.slice(0, limit) : rows;
19430
- const nextCursor = hasMore ? String(startIndex + limit) : undefined;
19431
- return {
19432
- results: results.map((row) => ({
19433
- sourceId: row.sourceId,
19434
- targetId: row.targetId,
19435
- relationshipType: row.relationshipType,
19436
- metadata: row.metadata ? row.metadata : undefined,
19437
- createdAt: row.createdAt,
19438
- updatedAt: row.updatedAt
19439
- })),
19440
- options: paging || { cursor: "0", limit: 100 },
19441
- nextCursor,
19442
- next: hasMore ? () => this.getDirectedRelationships(sourceId, targetId, types2, { cursor: nextCursor, limit }, consistencyToken, signal) : undefined
19443
- };
19444
- }
19445
- async findPath(sourceId, targetId, types2, consistencyToken, signal) {
19446
- if (consistencyToken) {
19447
- await this.waitForConsistency(consistencyToken, undefined, signal);
19448
- }
19449
- if (signal?.aborted) {
19450
- throw new Error("Operation aborted");
19451
- }
19452
- if (sourceId === targetId) {
19453
- return [sourceId];
19454
- }
19455
- const visited = new Set;
19456
- const queue = [
19457
- { id: sourceId, path: [sourceId] }
19458
- ];
19459
- while (queue.length > 0) {
19460
- const current = queue.shift();
19461
- if (current.id === targetId) {
19462
- return current.path;
19463
- }
19464
- if (visited.has(current.id)) {
19465
- continue;
19466
- }
19467
- visited.add(current.id);
19468
- const outgoingPage = await this.getOutgoing(current.id, types2, undefined, consistencyToken, signal);
19469
- const outgoingRelationships = await collectAllPages(outgoingPage, signal);
19470
- for (const rel of outgoingRelationships) {
19471
- if (!visited.has(rel.targetId)) {
19472
- queue.push({
19473
- id: rel.targetId,
19474
- path: [...current.path, rel.targetId]
19475
- });
19476
- }
19477
- }
19478
- }
19479
- return null;
19480
- }
19481
- async findAncestors(documentId, types2, consistencyToken, signal) {
19482
- if (consistencyToken) {
19483
- await this.waitForConsistency(consistencyToken, undefined, signal);
19484
- }
19485
- if (signal?.aborted) {
19486
- throw new Error("Operation aborted");
19487
- }
19488
- const nodes = new Set([documentId]);
19489
- const edges = [];
19490
- const queue = [documentId];
19491
- const visited = new Set;
19492
- while (queue.length > 0) {
19493
- const currentId = queue.shift();
19494
- if (visited.has(currentId)) {
19495
- continue;
19496
- }
19497
- visited.add(currentId);
19498
- const incomingPage = await this.getIncoming(currentId, types2, undefined, consistencyToken, signal);
19499
- const incomingRelationships = await collectAllPages(incomingPage, signal);
19500
- for (const rel of incomingRelationships) {
19501
- nodes.add(rel.sourceId);
19502
- edges.push({
19503
- from: rel.sourceId,
19504
- to: rel.targetId,
19505
- type: rel.relationshipType
19506
- });
19507
- if (!visited.has(rel.sourceId)) {
19508
- queue.push(rel.sourceId);
19509
- }
19510
- }
19511
- }
19512
- return {
19513
- nodes: Array.from(nodes),
19514
- edges
19515
- };
19516
- }
19517
- async getRelationshipTypes(consistencyToken, signal) {
19518
- if (consistencyToken) {
19519
- await this.waitForConsistency(consistencyToken, undefined, signal);
19520
- }
19521
- if (signal?.aborted) {
19522
- throw new Error("Operation aborted");
19523
- }
19524
- const rows = await this.db.selectFrom("DocumentRelationship").select("relationshipType").distinct().execute();
19525
- return rows.map((row) => row.relationshipType);
19526
- }
19527
- async handleAddRelationship(trx, operation) {
19528
- const input = operation.action.input;
19529
- const existingDoc = await trx.selectFrom("Document").select("id").where("id", "=", input.sourceId).executeTakeFirst();
19530
- if (!existingDoc) {
19531
- await trx.insertInto("Document").values({
19532
- id: input.sourceId
19533
- }).execute();
19534
- }
19535
- const existingTargetDoc = await trx.selectFrom("Document").select("id").where("id", "=", input.targetId).executeTakeFirst();
19536
- if (!existingTargetDoc) {
19537
- await trx.insertInto("Document").values({
19538
- id: input.targetId
19539
- }).execute();
19540
- }
19541
- const existingRel = await trx.selectFrom("DocumentRelationship").select("id").where("sourceId", "=", input.sourceId).where("targetId", "=", input.targetId).where("relationshipType", "=", input.relationshipType).executeTakeFirst();
19542
- if (!existingRel) {
19543
- const relationship = {
19544
- id: v4_default(),
19545
- sourceId: input.sourceId,
19546
- targetId: input.targetId,
19547
- relationshipType: input.relationshipType,
19548
- metadata: input.metadata || null
19549
- };
19550
- await trx.insertInto("DocumentRelationship").values(relationship).execute();
19551
- }
19552
- }
19553
- async handleRemoveRelationship(trx, operation) {
19554
- const input = operation.action.input;
19555
- await trx.deleteFrom("DocumentRelationship").where("sourceId", "=", input.sourceId).where("targetId", "=", input.targetId).where("relationshipType", "=", input.relationshipType).execute();
19556
- }
19557
- }
19558
-
19559
- class KyselyKeyframeStore {
19560
- db;
19561
- constructor(db) {
19562
- this.db = db;
19563
- }
19564
- async putKeyframe(documentId, scope, branch, revision, document2, signal) {
19565
- if (signal?.aborted) {
19566
- throw new Error("Operation aborted");
19567
- }
19568
- await this.db.insertInto("Keyframe").values({
19569
- documentId,
19570
- documentType: document2.header.documentType,
19571
- scope,
19572
- branch,
19573
- revision,
19574
- document: document2
19575
- }).onConflict((oc) => oc.columns(["documentId", "scope", "branch", "revision"]).doUpdateSet({ document: document2 })).execute();
19576
- }
19577
- async findNearestKeyframe(documentId, scope, branch, targetRevision, signal) {
19578
- if (signal?.aborted) {
19579
- throw new Error("Operation aborted");
19580
- }
19581
- 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();
19582
- if (!row) {
19583
- return;
19584
- }
19585
- return {
19586
- revision: row.revision,
19587
- document: row.document
19588
- };
19589
- }
19590
- async deleteKeyframes(documentId, scope, branch, signal) {
19591
- if (signal?.aborted) {
19592
- throw new Error("Operation aborted");
19593
- }
19594
- let query = this.db.deleteFrom("Keyframe").where("documentId", "=", documentId);
19595
- if (scope !== undefined && branch !== undefined) {
19596
- query = query.where("scope", "=", scope).where("branch", "=", branch);
19597
- } else if (scope !== undefined) {
19598
- query = query.where("scope", "=", scope);
19599
- }
19600
- const result = await query.executeTakeFirst();
19601
- return Number(result.numDeletedRows || 0n);
19602
- }
19603
- }
19604
-
19605
- class AtomicTransaction {
19606
- documentId;
19607
- documentType;
19608
- scope;
19609
- branch;
19610
- baseRevision;
19611
- operations = [];
19612
- constructor(documentId, documentType, scope, branch, baseRevision) {
19613
- this.documentId = documentId;
19614
- this.documentType = documentType;
19615
- this.scope = scope;
19616
- this.branch = branch;
19617
- this.baseRevision = baseRevision;
19618
- }
19619
- addOperations(...operations) {
19620
- for (const op of operations) {
19621
- this.operations.push({
19622
- jobId: v4_default(),
19623
- opId: op.id,
19624
- prevOpId: "",
19625
- documentId: this.documentId,
19626
- documentType: this.documentType,
19627
- scope: this.scope,
19628
- branch: this.branch,
19629
- timestampUtcMs: new Date(op.timestampUtcMs),
19630
- index: op.index,
19631
- action: JSON.stringify(op.action),
19632
- skip: op.skip,
19633
- error: op.error || null,
19634
- hash: op.hash
19635
- });
19636
- }
19637
- }
19638
- getOperations() {
19639
- return this.operations;
19640
- }
19641
- }
19642
-
19643
- class KyselyOperationStore {
19644
- db;
19645
- constructor(db) {
19646
- this.db = db;
19647
- }
19648
- async apply(documentId, documentType, scope, branch, revision, fn, signal) {
19649
- await this.db.transaction().execute(async (trx) => {
19650
- if (signal?.aborted) {
19651
- throw new Error("Operation aborted");
19652
- }
19653
- const latestOp = await trx.selectFrom("Operation").selectAll().where("documentId", "=", documentId).where("scope", "=", scope).where("branch", "=", branch).orderBy("index", "desc").limit(1).executeTakeFirst();
19654
- const currentRevision = latestOp ? latestOp.index : -1;
19655
- if (currentRevision !== revision - 1) {
19656
- throw new RevisionMismatchError(currentRevision + 1, revision);
19657
- }
19658
- const atomicTxn = new AtomicTransaction(documentId, documentType, scope, branch, revision);
19659
- await fn(atomicTxn);
19660
- const operations = atomicTxn.getOperations();
19661
- if (operations.length > 0) {
19662
- let prevOpId = latestOp?.opId || "";
19663
- for (const op of operations) {
19664
- op.prevOpId = prevOpId;
19665
- prevOpId = op.opId;
19666
- }
19667
- try {
19668
- await trx.insertInto("Operation").values(operations).execute();
19669
- } catch (error) {
19670
- if (error instanceof Error) {
19671
- if (error.message.includes("unique constraint")) {
19672
- const op = operations[0];
19673
- throw new DuplicateOperationError(`${op.opId} at index ${op.index} with skip ${op.skip}`);
19674
- }
19675
- throw error;
19676
- }
19677
- throw error;
19678
- }
19679
- }
19680
- });
19681
- }
19682
- async getSince(documentId, scope, branch, revision, filter, paging, signal) {
19683
- if (signal?.aborted) {
19684
- throw new Error("Operation aborted");
19685
- }
19686
- let query = this.db.selectFrom("Operation").selectAll().where("documentId", "=", documentId).where("scope", "=", scope).where("branch", "=", branch).where("index", ">", revision).orderBy("index", "asc");
19687
- if (filter) {
19688
- if (filter.actionTypes && filter.actionTypes.length > 0) {
19689
- const actionTypesArray = filter.actionTypes.map((t3) => `'${t3.replace(/'/g, "''")}'`).join(",");
19690
- query = query.where(sql`action->>'type' = ANY(ARRAY[${sql.raw(actionTypesArray)}]::text[])`);
19691
- }
19692
- if (filter.timestampFrom) {
19693
- query = query.where("timestampUtcMs", ">=", new Date(filter.timestampFrom));
19694
- }
19695
- if (filter.timestampTo) {
19696
- query = query.where("timestampUtcMs", "<=", new Date(filter.timestampTo));
19697
- }
19698
- if (filter.sinceRevision !== undefined) {
19699
- query = query.where("index", ">=", filter.sinceRevision);
19700
- }
19701
- }
19702
- if (paging) {
19703
- const cursorValue = Number.parseInt(paging.cursor, 10);
19704
- if (cursorValue > 0) {
19705
- query = query.where("index", ">", cursorValue);
19706
- }
19707
- if (paging.limit) {
19708
- query = query.limit(paging.limit + 1);
19709
- }
19710
- }
19711
- const rows = await query.execute();
19712
- let hasMore = false;
19713
- let items = rows;
19714
- if (paging?.limit && rows.length > paging.limit) {
19715
- hasMore = true;
19716
- items = rows.slice(0, paging.limit);
19717
- }
19718
- const nextCursor = hasMore && items.length > 0 ? items[items.length - 1].index.toString() : undefined;
19719
- const cursor = paging?.cursor || "0";
19720
- const limit = paging?.limit || 100;
19721
- const operations = items.map((row) => this.rowToOperation(row));
19722
- return {
19723
- results: operations,
19724
- options: { cursor, limit },
19725
- nextCursor,
19726
- next: hasMore ? () => this.getSince(documentId, scope, branch, revision, filter, { cursor: nextCursor, limit }, signal) : undefined
19727
- };
19728
- }
19729
- async getSinceId(id, paging, signal) {
19730
- if (signal?.aborted) {
19731
- throw new Error("Operation aborted");
19732
- }
19733
- let query = this.db.selectFrom("Operation").selectAll().where("id", ">", id).orderBy("id", "asc");
19734
- if (paging) {
19735
- const cursorValue = Number.parseInt(paging.cursor, 10);
19736
- if (cursorValue > 0) {
19737
- query = query.where("id", ">", cursorValue);
19738
- }
19739
- if (paging.limit) {
19740
- query = query.limit(paging.limit + 1);
19741
- }
19742
- }
19743
- const rows = await query.execute();
19744
- let hasMore = false;
19745
- let items = rows;
19746
- if (paging?.limit && rows.length > paging.limit) {
19747
- hasMore = true;
19748
- items = rows.slice(0, paging.limit);
19749
- }
19750
- const nextCursor = hasMore && items.length > 0 ? items[items.length - 1].id.toString() : undefined;
19751
- const cursor = paging?.cursor || "0";
19752
- const limit = paging?.limit || 100;
19753
- const operations = items.map((row) => this.rowToOperationWithContext(row));
19754
- return {
19755
- results: operations,
19756
- options: { cursor, limit },
19757
- nextCursor,
19758
- next: hasMore ? () => this.getSinceId(id, { cursor: nextCursor, limit }, signal) : undefined
19759
- };
19760
- }
19761
- async getConflicting(documentId, scope, branch, minTimestamp, paging, signal) {
19762
- if (signal?.aborted) {
19763
- throw new Error("Operation aborted");
19764
- }
19765
- let query = this.db.selectFrom("Operation").selectAll().where("documentId", "=", documentId).where("scope", "=", scope).where("branch", "=", branch).where("timestampUtcMs", ">=", new Date(minTimestamp)).orderBy("index", "asc");
19766
- if (paging) {
19767
- const cursorValue = Number.parseInt(paging.cursor, 10);
19768
- if (cursorValue > 0) {
19769
- query = query.where("index", ">", cursorValue);
19770
- }
19771
- if (paging.limit) {
19772
- query = query.limit(paging.limit + 1);
19773
- }
19774
- }
19775
- const rows = await query.execute();
19776
- let hasMore = false;
19777
- let items = rows;
19778
- if (paging?.limit && rows.length > paging.limit) {
19779
- hasMore = true;
19780
- items = rows.slice(0, paging.limit);
19781
- }
19782
- const nextCursor = hasMore && items.length > 0 ? items[items.length - 1].index.toString() : undefined;
19783
- const cursor = paging?.cursor || "0";
19784
- const limit = paging?.limit || 100;
19785
- const operations = items.map((row) => this.rowToOperation(row));
19786
- return {
19787
- results: operations,
19788
- options: { cursor, limit },
19789
- nextCursor,
19790
- next: hasMore ? () => this.getConflicting(documentId, scope, branch, minTimestamp, { cursor: nextCursor, limit }, signal) : undefined
19791
- };
19792
- }
19793
- async getRevisions(documentId, branch, signal) {
19794
- if (signal?.aborted) {
19795
- throw new Error("Operation aborted");
19796
- }
19797
- 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();
19798
- const revision = {};
19799
- let latestTimestamp = new Date(0).toISOString();
19800
- for (const row of scopeRevisions) {
19801
- revision[row.scope] = row.index + 1;
19802
- const timestamp = row.timestampUtcMs.toISOString();
19803
- if (timestamp > latestTimestamp) {
19804
- latestTimestamp = timestamp;
19805
- }
19806
- }
19807
- return {
19808
- revision,
19809
- latestTimestamp
19810
- };
19811
- }
19812
- rowToOperation(row) {
19813
- return {
19814
- index: row.index,
19815
- timestampUtcMs: row.timestampUtcMs.toISOString(),
19816
- hash: row.hash,
19817
- skip: row.skip,
19818
- error: row.error || undefined,
19819
- id: row.opId,
19820
- action: row.action
19821
- };
19822
- }
19823
- rowToOperationWithContext(row) {
19824
- return {
19825
- operation: this.rowToOperation(row),
19826
- context: {
19827
- documentId: row.documentId,
19828
- documentType: row.documentType,
19829
- scope: row.scope,
19830
- branch: row.branch,
19831
- ordinal: row.id
19832
- }
19833
- };
19834
- }
19835
- }
19836
- async function up(db) {
19837
- 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", [
19838
- "documentId",
19839
- "scope",
19840
- "branch",
19841
- "index"
19842
- ]).addUniqueConstraint("unique_operation_instance", ["opId", "index", "skip"]).execute();
19843
- await db.schema.createIndex("streamOperations").on("Operation").columns(["documentId", "scope", "branch", "id"]).execute();
19844
- await db.schema.createIndex("branchlessStreamOperations").on("Operation").columns(["documentId", "scope", "id"]).execute();
19845
- }
19846
- async function up2(db) {
19847
- 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", [
19848
- "documentId",
19849
- "scope",
19850
- "branch",
19851
- "revision"
19852
- ]).execute();
19853
- await db.schema.createIndex("keyframe_lookup").on("Keyframe").columns(["documentId", "scope", "branch", "revision"]).execute();
19854
- }
19855
- async function up3(db) {
19856
- 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();
19857
- }
19858
- async function up4(db) {
19859
- 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", [
19860
- "sourceId",
19861
- "targetId",
19862
- "relationshipType"
19863
- ]).execute();
19864
- await db.schema.createIndex("idx_relationship_source").on("DocumentRelationship").column("sourceId").execute();
19865
- await db.schema.createIndex("idx_relationship_target").on("DocumentRelationship").column("targetId").execute();
19866
- await db.schema.createIndex("idx_relationship_type").on("DocumentRelationship").column("relationshipType").execute();
19867
- }
19868
- async function up5(db) {
19869
- 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();
19870
- }
19871
- async function up6(db) {
19872
- 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", [
19873
- "documentId",
19874
- "scope",
19875
- "branch"
19876
- ]).execute();
19877
- await db.schema.createIndex("idx_slug_scope_branch").on("DocumentSnapshot").columns(["slug", "scope", "branch"]).execute();
19878
- await db.schema.createIndex("idx_doctype_scope_branch").on("DocumentSnapshot").columns(["documentType", "scope", "branch"]).execute();
19879
- await db.schema.createIndex("idx_last_updated").on("DocumentSnapshot").column("lastUpdatedAt").execute();
19880
- await db.schema.createIndex("idx_is_deleted").on("DocumentSnapshot").column("isDeleted").execute();
19881
- }
19882
- async function up7(db) {
19883
- 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", [
19884
- "documentId",
19885
- "scope",
19886
- "branch"
19887
- ]).execute();
19888
- await db.schema.createIndex("idx_slug_documentid").on("SlugMapping").column("documentId").execute();
19889
- }
19890
- async function up8(db) {
19891
- 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();
19892
- }
19893
- async function up9(db) {
19894
- 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", [
19895
- "documentId",
19896
- "collectionId"
19897
- ]).execute();
19898
- await db.schema.createIndex("idx_document_collections_collectionId").on("document_collections").column("collectionId").execute();
19899
- await db.schema.createIndex("idx_doc_collections_collection_range").on("document_collections").columns(["collectionId", "joinedOrdinal"]).execute();
19900
- 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();
19901
- await db.schema.createIndex("idx_operation_index_operations_document").on("operation_index_operations").columns(["documentId", "branch", "scope"]).execute();
19902
- await db.schema.createIndex("idx_operation_index_operations_ordinal").on("operation_index_operations").column("ordinal").execute();
19903
- }
19904
- async function up10(db) {
19905
- 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();
19906
- await db.schema.createIndex("idx_sync_remotes_collection").on("sync_remotes").column("collection_id").execute();
19907
- 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();
19908
- await db.schema.createIndex("idx_sync_cursors_ordinal").on("sync_cursors").column("cursor_ordinal").execute();
19909
- }
19910
- async function up11(db) {
19911
- await db.deleteFrom("sync_cursors").where("remote_name", "like", "outbox::%").execute();
19912
- await db.deleteFrom("sync_remotes").where("name", "like", "outbox::%").execute();
19913
- await db.schema.dropTable("sync_cursors").execute();
19914
- 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();
19915
- await db.schema.createIndex("idx_sync_cursors_ordinal").on("sync_cursors").column("cursor_ordinal").execute();
19916
- }
19917
- async function up12(db) {
19918
- await db.schema.alterTable("operation_index_operations").addColumn("sourceRemote", "text", (col) => col.notNull().defaultTo("")).execute();
19919
- }
19920
- async function up13(db) {
19921
- 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();
19922
- await db.schema.createIndex("idx_sync_dead_letters_remote").on("sync_dead_letters").column("remote_name").execute();
19923
- }
19924
-
19925
- class ProgrammaticMigrationProvider {
19926
- getMigrations() {
19927
- return Promise.resolve(migrations);
19928
- }
19929
- }
19930
- async function runMigrations(db, schema = REACTOR_SCHEMA) {
19931
- try {
19932
- await sql`CREATE SCHEMA IF NOT EXISTS ${sql.id(schema)}`.execute(db);
19933
- } catch (error2) {
19934
- return {
19935
- success: false,
19936
- migrationsExecuted: [],
19937
- error: error2 instanceof Error ? error2 : new Error("Failed to create schema")
19938
- };
19939
- }
19940
- const migrator = new Migrator({
19941
- db: db.withSchema(schema),
19942
- provider: new ProgrammaticMigrationProvider,
19943
- migrationTableSchema: schema
19944
- });
19945
- let error;
19946
- let results;
19947
- try {
19948
- const result = await migrator.migrateToLatest();
19949
- error = result.error;
19950
- results = result.results;
19951
- } catch (e2) {
19952
- error = e2;
19953
- results = [];
19954
- }
19955
- const migrationsExecuted = results?.map((result) => result.migrationName) ?? [];
19956
- if (error) {
19957
- return {
19958
- success: false,
19959
- migrationsExecuted,
19960
- error: error instanceof Error ? error : new Error("Unknown migration error")
19961
- };
19962
- }
19963
- return {
19964
- success: true,
19965
- migrationsExecuted
19966
- };
19967
- }
19968
-
19969
- class DefaultSubscriptionErrorHandler {
19970
- handleError(error, context) {
19971
- const errorMessage = `Subscription error in ${context.eventType} (${context.subscriptionId})`;
19972
- if (error instanceof Error) {
19973
- const enhancedError = new Error(`${errorMessage}: ${error.message}`);
19974
- enhancedError.cause = error;
19975
- enhancedError.stack = error.stack;
19976
- throw enhancedError;
19977
- } else {
19978
- throw new Error(`${errorMessage}: ${String(error)}`);
19979
- }
19980
- }
19981
- }
19982
-
19983
- class ReactorSubscriptionManager {
19984
- createdSubscriptions = new Map;
19985
- deletedSubscriptions = new Map;
19986
- updatedSubscriptions = new Map;
19987
- relationshipSubscriptions = new Map;
19988
- subscriptionCounter = 0;
19989
- errorHandler;
19990
- constructor(errorHandler) {
19991
- this.errorHandler = errorHandler;
19992
- }
19993
- onDocumentCreated(callback, search) {
19994
- const id = `created-${++this.subscriptionCounter}`;
19995
- this.createdSubscriptions.set(id, { id, callback, search });
19996
- return () => {
19997
- this.createdSubscriptions.delete(id);
19998
- };
19999
- }
20000
- onDocumentDeleted(callback, search) {
20001
- const id = `deleted-${++this.subscriptionCounter}`;
20002
- this.deletedSubscriptions.set(id, { id, callback, search });
20003
- return () => {
20004
- this.deletedSubscriptions.delete(id);
20005
- };
20006
- }
20007
- onDocumentStateUpdated(callback, search, view) {
20008
- const id = `updated-${++this.subscriptionCounter}`;
20009
- this.updatedSubscriptions.set(id, { id, callback, search, view });
20010
- return () => {
20011
- this.updatedSubscriptions.delete(id);
20012
- };
20013
- }
20014
- onRelationshipChanged(callback, search) {
20015
- const id = `relationship-${++this.subscriptionCounter}`;
20016
- this.relationshipSubscriptions.set(id, { id, callback, search });
20017
- return () => {
20018
- this.relationshipSubscriptions.delete(id);
20019
- };
20020
- }
20021
- notifyDocumentsCreated(documentIds, documentTypes, parentIds) {
20022
- const result = {
20023
- results: documentIds,
20024
- options: { cursor: "", limit: documentIds.length }
20025
- };
20026
- for (const subscription of this.createdSubscriptions.values()) {
20027
- const filteredIds = this.filterDocumentIds(documentIds, subscription.search, documentTypes, parentIds);
20028
- if (filteredIds.length > 0) {
20029
- try {
20030
- subscription.callback({
20031
- ...result,
20032
- results: filteredIds
20033
- });
20034
- } catch (error) {
20035
- this.errorHandler.handleError(error, {
20036
- eventType: "created",
20037
- subscriptionId: subscription.id,
20038
- eventData: filteredIds
20039
- });
20040
- }
20041
- }
20042
- }
20043
- }
20044
- notifyDocumentsDeleted(documentIds, documentTypes, parentIds) {
20045
- for (const subscription of this.deletedSubscriptions.values()) {
20046
- const filteredIds = this.filterDocumentIds(documentIds, subscription.search, documentTypes, parentIds);
20047
- if (filteredIds.length > 0) {
20048
- try {
20049
- subscription.callback(filteredIds);
20050
- } catch (error) {
20051
- this.errorHandler.handleError(error, {
20052
- eventType: "deleted",
20053
- subscriptionId: subscription.id,
20054
- eventData: filteredIds
20055
- });
20056
- }
20057
- }
20058
- }
20059
- }
20060
- notifyDocumentsUpdated(documents) {
20061
- const result = {
20062
- results: documents,
20063
- options: { cursor: "", limit: documents.length }
20064
- };
20065
- for (const subscription of this.updatedSubscriptions.values()) {
20066
- const filteredDocs = this.filterDocuments(documents, subscription.search);
20067
- if (filteredDocs.length > 0) {
20068
- try {
20069
- subscription.callback({
20070
- ...result,
20071
- results: filteredDocs
20072
- });
20073
- } catch (error) {
20074
- this.errorHandler.handleError(error, {
20075
- eventType: "updated",
20076
- subscriptionId: subscription.id,
20077
- eventData: filteredDocs
20078
- });
20079
- }
20080
- }
20081
- }
20082
- }
20083
- notifyRelationshipChanged(parentId, childId, changeType, childType) {
20084
- for (const subscription of this.relationshipSubscriptions.values()) {
20085
- if (this.matchesRelationshipFilter(parentId, childId, childType, subscription.search)) {
20086
- try {
20087
- subscription.callback(parentId, childId, changeType);
20088
- } catch (error) {
20089
- this.errorHandler.handleError(error, {
20090
- eventType: "relationshipChanged",
20091
- subscriptionId: subscription.id,
20092
- eventData: { parentId, childId, changeType }
20093
- });
20094
- }
20095
- }
20096
- }
20097
- }
20098
- clearAll() {
20099
- this.createdSubscriptions.clear();
20100
- this.deletedSubscriptions.clear();
20101
- this.updatedSubscriptions.clear();
20102
- this.relationshipSubscriptions.clear();
20103
- }
20104
- filterDocumentIds(documentIds, search, documentTypes, parentIds) {
20105
- if (!search)
20106
- return documentIds;
20107
- return documentIds.filter((id) => {
20108
- if (search.ids && !search.ids.includes(id))
20109
- return false;
20110
- if (search.type && documentTypes) {
20111
- const docType = documentTypes.get(id);
20112
- if (docType !== search.type)
20113
- return false;
20114
- }
20115
- if (search.parentId && parentIds) {
20116
- const parentId = parentIds.get(id);
20117
- if (parentId !== search.parentId)
20118
- return false;
20119
- }
20120
- return true;
20121
- });
20122
- }
20123
- filterDocuments(documents, search) {
20124
- if (!search)
20125
- return documents;
20126
- return documents.filter((doc) => {
20127
- if (search.ids && !search.ids.includes(doc.header.id))
20128
- return false;
20129
- if (search.type && doc.header.documentType !== search.type)
20130
- return false;
20131
- if (search.slugs && !search.slugs.includes(doc.header.slug))
20132
- return false;
20133
- return true;
20134
- });
20135
- }
20136
- matchesRelationshipFilter(parentId, childId, childType, search) {
20137
- if (!search)
20138
- return true;
20139
- if (search.parentId && parentId !== search.parentId)
20140
- return false;
20141
- if (search.ids && !search.ids.includes(childId))
20142
- return false;
20143
- if (search.type && childType && childType !== search.type)
20144
- return false;
20145
- return true;
20146
- }
20147
- }
20148
-
20149
- class SubscriptionNotificationReadModel {
20150
- subscriptionManager;
20151
- documentView;
20152
- constructor(subscriptionManager, documentView) {
20153
- this.subscriptionManager = subscriptionManager;
20154
- this.documentView = documentView;
20155
- }
20156
- async indexOperations(operations) {
20157
- if (operations.length === 0)
20158
- return;
20159
- const created = [];
20160
- const deleted = [];
20161
- const updatedIds = new Set;
20162
- const documentTypes = new Map;
20163
- const parentIds = new Map;
20164
- for (const item of operations) {
20165
- const { operation, context } = item;
20166
- const actionType = operation.action.type;
20167
- documentTypes.set(context.documentId, context.documentType);
20168
- if (actionType === "CREATE_DOCUMENT") {
20169
- created.push(context.documentId);
20170
- } else if (actionType === "DELETE_DOCUMENT") {
20171
- const input = operation.action.input;
20172
- const deletedId = input.documentId ?? context.documentId;
20173
- deleted.push(deletedId);
20174
- } else if (actionType === "ADD_RELATIONSHIP") {
20175
- const input = operation.action.input;
20176
- this.subscriptionManager.notifyRelationshipChanged(input.sourceId, input.targetId, "added", input.childType);
20177
- } else if (actionType === "REMOVE_RELATIONSHIP") {
20178
- const input = operation.action.input;
20179
- this.subscriptionManager.notifyRelationshipChanged(input.sourceId, input.targetId, "removed", input.childType);
20180
- } else {
20181
- if (!created.includes(context.documentId)) {
20182
- updatedIds.add(context.documentId);
20183
- }
20184
- }
20185
- }
20186
- if (created.length > 0) {
20187
- this.subscriptionManager.notifyDocumentsCreated(created, documentTypes, parentIds);
20188
- }
20189
- if (deleted.length > 0) {
20190
- this.subscriptionManager.notifyDocumentsDeleted(deleted, documentTypes, parentIds);
20191
- }
20192
- if (updatedIds.size > 0 && this.documentView) {
20193
- const documents = await Promise.all(Array.from(updatedIds).map((id) => this.documentView.get(id)));
20194
- this.subscriptionManager.notifyDocumentsUpdated(documents);
20195
- }
20196
- }
20197
- }
20198
19949
  function rowToRemoteCursor(row) {
20199
19950
  return {
20200
19951
  remoteName: row.remote_name,
@@ -20924,6 +20675,7 @@ class SyncManager {
20924
20675
  batchAggregator;
20925
20676
  syncStatusTracker;
20926
20677
  maxDeadLettersPerRemote;
20678
+ connectionStateUnsubscribes = new Map;
20927
20679
  loadJobs = new Map;
20928
20680
  constructor(logger2, remoteStorage, cursorStorage, deadLetterStorage, channelFactory, operationIndex, reactor, eventBus, maxDeadLettersPerRemote = 100) {
20929
20681
  this.logger = logger2;
@@ -20989,6 +20741,10 @@ class SyncManager {
20989
20741
  this.awaiter.shutdown();
20990
20742
  this.syncAwaiter.shutdown();
20991
20743
  this.syncStatusTracker.clear();
20744
+ for (const unsub of this.connectionStateUnsubscribes.values()) {
20745
+ unsub();
20746
+ }
20747
+ this.connectionStateUnsubscribes.clear();
20992
20748
  const promises = [];
20993
20749
  for (const remote of this.remotes.values()) {
20994
20750
  promises.push(remote.channel.shutdown());
@@ -21070,6 +20826,11 @@ class SyncManager {
21070
20826
  await this.remoteStorage.remove(name);
21071
20827
  await this.cursorStorage.remove(name);
21072
20828
  this.syncStatusTracker.untrackRemote(name);
20829
+ const unsub = this.connectionStateUnsubscribes.get(name);
20830
+ if (unsub) {
20831
+ unsub();
20832
+ this.connectionStateUnsubscribes.delete(name);
20833
+ }
21073
20834
  this.remotes.delete(name);
21074
20835
  }
21075
20836
  list() {
@@ -21087,6 +20848,16 @@ class SyncManager {
21087
20848
  wireChannelCallbacks(remote) {
21088
20849
  remote.channel.inbox.onAdded((syncOps) => this.handleInboxAdded(remote, syncOps));
21089
20850
  this.syncStatusTracker.trackRemote(remote.name, remote.channel);
20851
+ const unsubscribe = remote.channel.onConnectionStateChange((snapshot) => {
20852
+ this.eventBus.emit(SyncEventTypes.CONNECTION_STATE_CHANGED, {
20853
+ remoteName: remote.name,
20854
+ remoteId: remote.id,
20855
+ previous: snapshot.state,
20856
+ current: snapshot.state,
20857
+ snapshot
20858
+ }).catch(() => {});
20859
+ });
20860
+ this.connectionStateUnsubscribes.set(remote.name, unsubscribe);
21090
20861
  remote.channel.deadLetter.onAdded((syncOps) => {
21091
20862
  for (const syncOp of syncOps) {
21092
20863
  this.logger.error("Dead letter (@remote, @documentId, @jobId, @error, @dependencies)", remote.name, syncOp.documentId, syncOp.jobId, syncOp.error?.message ?? "unknown", syncOp.jobDependencies);
@@ -22010,7 +21781,6 @@ class ReactorBuilder {
22010
21781
  logger;
22011
21782
  documentModels = [];
22012
21783
  upgradeManifests = [];
22013
- storage;
22014
21784
  features = { legacyStorageEnabled: false };
22015
21785
  readModels = [];
22016
21786
  executorManager;
@@ -22039,10 +21809,6 @@ class ReactorBuilder {
22039
21809
  this.upgradeManifests = manifests;
22040
21810
  return this;
22041
21811
  }
22042
- withLegacyStorage(storage) {
22043
- this.storage = storage;
22044
- return this;
22045
- }
22046
21812
  withFeatures(features) {
22047
21813
  this.features = { ...this.features, ...features };
22048
21814
  return this;
@@ -22166,7 +21932,7 @@ class ReactorBuilder {
22166
21932
  }
22167
21933
  readModelInstances.push(documentView);
22168
21934
  const documentIndexerConsistencyTracker = new ConsistencyTracker;
22169
- const documentIndexer = new KyselyDocumentIndexer(database, operationStore, documentIndexerConsistencyTracker);
21935
+ const documentIndexer = new KyselyDocumentIndexer(database, operationIndex, writeCache, documentIndexerConsistencyTracker);
22170
21936
  try {
22171
21937
  await documentIndexer.init();
22172
21938
  } catch (error) {
@@ -22176,7 +21942,7 @@ class ReactorBuilder {
22176
21942
  const subscriptionManager = new ReactorSubscriptionManager(new DefaultSubscriptionErrorHandler);
22177
21943
  const subscriptionNotificationReadModel = new SubscriptionNotificationReadModel(subscriptionManager, documentView);
22178
21944
  const processorManagerConsistencyTracker = new ConsistencyTracker;
22179
- const processorManager = new ProcessorManager(database, operationIndex, writeCache, processorManagerConsistencyTracker);
21945
+ const processorManager = new ProcessorManager(database, operationIndex, writeCache, processorManagerConsistencyTracker, this.logger);
22180
21946
  try {
22181
21947
  await processorManager.init();
22182
21948
  } catch (error) {
@@ -22520,7 +22286,7 @@ var __defProp2, __export2 = (target, all) => {
22520
22286
  }
22521
22287
  }, DocumentDeletedError, InvalidSignatureError, DowngradeNotSupportedError, DocumentNotFoundError, getNextIndexForScope = (document2, scope) => {
22522
22288
  return document2.header.revision[scope] || 0;
22523
- }, 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) => {
22289
+ }, 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) => {
22524
22290
  let maxOrdinal = 0;
22525
22291
  for (const syncOp of syncOps) {
22526
22292
  if (syncOp.status === 2) {
@@ -22530,7 +22296,7 @@ var __defProp2, __export2 = (target, all) => {
22530
22296
  }
22531
22297
  }
22532
22298
  return maxOrdinal;
22533
- }, 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;
22299
+ }, SyncStatus, cachedEncoder, LOG2_26, IS_RELATIONAL_DB_PROCESSOR, RelationalDbProcessor;
22534
22300
  var init_src = __esm(() => {
22535
22301
  __defProp2 = Object.defineProperty;
22536
22302
  byteToHex = [];
@@ -26672,19 +26438,24 @@ var init_src = __esm(() => {
26672
26438
  processorsByDrive = new Map;
26673
26439
  factoryToProcessors = new Map;
26674
26440
  knownDriveIds = new Set;
26675
- constructor(db, operationIndex, writeCache, consistencyTracker) {
26676
- super(db, operationIndex, writeCache, consistencyTracker, "processor-manager");
26441
+ cursorCache = new Map;
26442
+ logger;
26443
+ constructor(db, operationIndex, writeCache, consistencyTracker, logger2) {
26444
+ super(db, operationIndex, writeCache, consistencyTracker, {
26445
+ readModelId: "processor-manager",
26446
+ rebuildStateOnInit: true
26447
+ });
26448
+ this.logger = logger2;
26677
26449
  }
26678
- async indexOperations(items) {
26679
- if (items.length === 0)
26680
- return;
26450
+ async init() {
26451
+ await super.init();
26452
+ await this.loadAllCursors();
26453
+ await this.discoverExistingDrives();
26454
+ }
26455
+ async commitOperations(items) {
26681
26456
  await this.detectAndRegisterNewDrives(items);
26682
26457
  await this.detectAndCleanupDeletedDrives(items);
26683
26458
  await this.routeOperationsToProcessors(items);
26684
- await this.db.transaction().execute(async (trx) => {
26685
- await this.saveState(trx, items);
26686
- });
26687
- this.updateConsistencyTracker(items);
26688
26459
  }
26689
26460
  async registerFactory(identifier, factory) {
26690
26461
  if (this.factoryRegistry.has(identifier)) {
@@ -26701,13 +26472,13 @@ var init_src = __esm(() => {
26701
26472
  const factoryProcessors = this.factoryToProcessors.get(identifier);
26702
26473
  if (!factoryProcessors)
26703
26474
  return;
26704
- for (const [driveId, records] of factoryProcessors) {
26705
- for (const record of records) {
26706
- await this.safeDisconnect(record.processor);
26475
+ for (const [driveId, tracked] of factoryProcessors) {
26476
+ for (const t3 of tracked) {
26477
+ await this.safeDisconnect(t3.record.processor);
26707
26478
  }
26708
26479
  const driveProcessors = this.processorsByDrive.get(driveId);
26709
26480
  if (driveProcessors) {
26710
- const remaining = driveProcessors.filter((p) => !records.includes(p));
26481
+ const remaining = driveProcessors.filter((p) => !tracked.includes(p));
26711
26482
  if (remaining.length > 0) {
26712
26483
  this.processorsByDrive.set(driveId, remaining);
26713
26484
  } else {
@@ -26715,14 +26486,24 @@ var init_src = __esm(() => {
26715
26486
  }
26716
26487
  }
26717
26488
  }
26489
+ await this.deleteProcessorCursors({ factoryId: identifier });
26718
26490
  this.factoryToProcessors.delete(identifier);
26719
26491
  this.factoryRegistry.delete(identifier);
26720
26492
  }
26721
- getFactoryIdentifiers() {
26722
- return Array.from(this.factoryRegistry.keys());
26493
+ get(processorId) {
26494
+ for (const tracked of this.allTrackedProcessors()) {
26495
+ if (tracked.processorId === processorId)
26496
+ return tracked;
26497
+ }
26498
+ return;
26723
26499
  }
26724
- getProcessorsForDrive(driveId) {
26725
- return this.processorsByDrive.get(driveId) ?? [];
26500
+ getAll() {
26501
+ return Array.from(this.allTrackedProcessors());
26502
+ }
26503
+ *allTrackedProcessors() {
26504
+ for (const tracked of this.processorsByDrive.values()) {
26505
+ yield* tracked;
26506
+ }
26726
26507
  }
26727
26508
  async detectAndRegisterNewDrives(operations) {
26728
26509
  for (const op of operations) {
@@ -26753,6 +26534,12 @@ var init_src = __esm(() => {
26753
26534
  this.knownDriveIds.delete(driveId);
26754
26535
  }
26755
26536
  }
26537
+ async discoverExistingDrives() {
26538
+ const drives = await this.db.selectFrom("DocumentSnapshot").select("documentId").where("documentType", "=", DRIVE_DOCUMENT_TYPE).where("isDeleted", "=", false).execute();
26539
+ for (const drive of drives) {
26540
+ this.knownDriveIds.add(drive.documentId);
26541
+ }
26542
+ }
26756
26543
  isDeletedDocumentADrive(documentId) {
26757
26544
  return this.knownDriveIds.has(documentId);
26758
26545
  }
@@ -26761,71 +26548,214 @@ var init_src = __esm(() => {
26761
26548
  try {
26762
26549
  records = await factory(driveHeader);
26763
26550
  } catch (error) {
26764
- console.error(`ProcessorManager: Factory '${identifier}' failed for drive '${driveId}':`, error);
26551
+ this.logger.error("Factory '@FactoryId' failed for drive '@DriveId': @Error", identifier, driveId, error);
26765
26552
  return;
26766
26553
  }
26767
26554
  if (records.length === 0)
26768
26555
  return;
26556
+ const trackedList = [];
26557
+ for (let i2 = 0;i2 < records.length; i2++) {
26558
+ const record = records[i2];
26559
+ const processorId = `${identifier}:${driveId}:${i2}`;
26560
+ const cached = this.cursorCache.get(processorId);
26561
+ let lastOrdinal;
26562
+ let status;
26563
+ let lastError;
26564
+ let lastErrorTimestamp;
26565
+ if (cached) {
26566
+ lastOrdinal = cached.lastOrdinal;
26567
+ status = cached.status;
26568
+ lastError = cached.lastError ?? undefined;
26569
+ lastErrorTimestamp = cached.lastErrorTimestamp ?? undefined;
26570
+ } else {
26571
+ const startFrom = record.startFrom ?? "beginning";
26572
+ lastOrdinal = startFrom === "current" ? this.lastOrdinal : 0;
26573
+ status = "active";
26574
+ lastError = undefined;
26575
+ lastErrorTimestamp = undefined;
26576
+ }
26577
+ const tracked = {
26578
+ processorId,
26579
+ factoryId: identifier,
26580
+ driveId,
26581
+ processorIndex: i2,
26582
+ record,
26583
+ lastOrdinal,
26584
+ status,
26585
+ lastError,
26586
+ lastErrorTimestamp,
26587
+ retry: () => this.retryProcessor(tracked)
26588
+ };
26589
+ trackedList.push(tracked);
26590
+ await this.saveProcessorCursor(tracked);
26591
+ }
26592
+ await this.db.deleteFrom("ProcessorCursor").where("factoryId", "=", identifier).where("driveId", "=", driveId).where("processorIndex", ">=", records.length).execute();
26593
+ for (const [id, row] of this.cursorCache) {
26594
+ if (row.factoryId === identifier && row.driveId === driveId && row.processorIndex >= records.length) {
26595
+ this.cursorCache.delete(id);
26596
+ }
26597
+ }
26769
26598
  const factoryProcessors = this.factoryToProcessors.get(identifier);
26770
26599
  if (factoryProcessors) {
26771
- factoryProcessors.set(driveId, records);
26600
+ factoryProcessors.set(driveId, trackedList);
26772
26601
  }
26773
26602
  const existingDriveProcessors = this.processorsByDrive.get(driveId) ?? [];
26774
26603
  this.processorsByDrive.set(driveId, [
26775
26604
  ...existingDriveProcessors,
26776
- ...records
26605
+ ...trackedList
26777
26606
  ]);
26607
+ for (const tracked of trackedList) {
26608
+ if (tracked.status === "active" && tracked.lastOrdinal < this.lastOrdinal) {
26609
+ await this.backfillProcessor(tracked);
26610
+ }
26611
+ }
26612
+ }
26613
+ async backfillProcessor(tracked) {
26614
+ let page = await this.operationIndex.getSinceOrdinal(tracked.lastOrdinal);
26615
+ while (page.results.length > 0) {
26616
+ const matching = page.results.filter((op) => matchesFilter(op, tracked.record.filter));
26617
+ if (matching.length > 0) {
26618
+ try {
26619
+ await tracked.record.processor.onOperations(matching);
26620
+ } catch (error) {
26621
+ tracked.status = "errored";
26622
+ tracked.lastError = error instanceof Error ? error.message : String(error);
26623
+ tracked.lastErrorTimestamp = new Date;
26624
+ await this.safeSaveProcessorCursor(tracked);
26625
+ this.logger.error("Processor '@ProcessorId' failed during backfill at ordinal @Ordinal: @Error", tracked.processorId, tracked.lastOrdinal, error);
26626
+ return;
26627
+ }
26628
+ }
26629
+ const maxOrdinal = Math.max(...page.results.map((op) => op.context.ordinal));
26630
+ tracked.lastOrdinal = maxOrdinal;
26631
+ await this.safeSaveProcessorCursor(tracked);
26632
+ if (!page.next)
26633
+ break;
26634
+ page = await page.next();
26635
+ }
26636
+ }
26637
+ async retryProcessor(tracked) {
26638
+ if (tracked.status !== "errored")
26639
+ return;
26640
+ tracked.status = "active";
26641
+ tracked.lastError = undefined;
26642
+ tracked.lastErrorTimestamp = undefined;
26643
+ await this.saveProcessorCursor(tracked);
26644
+ await this.backfillProcessor(tracked);
26778
26645
  }
26779
26646
  async cleanupDriveProcessors(driveId) {
26780
26647
  const processors = this.processorsByDrive.get(driveId);
26781
26648
  if (!processors)
26782
26649
  return;
26783
- for (const record of processors) {
26784
- await this.safeDisconnect(record.processor);
26650
+ for (const tracked of processors) {
26651
+ await this.safeDisconnect(tracked.record.processor);
26785
26652
  }
26786
26653
  this.processorsByDrive.delete(driveId);
26787
26654
  for (const factoryProcessors of this.factoryToProcessors.values()) {
26788
26655
  factoryProcessors.delete(driveId);
26789
26656
  }
26657
+ await this.deleteProcessorCursors({ driveId });
26790
26658
  }
26791
26659
  async safeDisconnect(processor) {
26792
26660
  try {
26793
26661
  await processor.onDisconnect();
26794
26662
  } catch (error) {
26795
- console.error("ProcessorManager: Error disconnecting processor:", error);
26663
+ this.logger.error("Error disconnecting processor: @Error", error);
26796
26664
  }
26797
26665
  }
26798
26666
  async routeOperationsToProcessors(operations) {
26799
- const processorOperations = new Map;
26800
- for (const [, records] of this.processorsByDrive) {
26801
- for (const { processor, filter } of records) {
26802
- const matching = operations.filter((op) => matchesFilter(op, filter));
26803
- if (matching.length === 0)
26804
- continue;
26805
- const existing = processorOperations.get(processor) ?? [];
26806
- processorOperations.set(processor, [...existing, ...matching]);
26667
+ const maxOrdinal = Math.max(...operations.map((op) => op.context.ordinal));
26668
+ const allTracked = Array.from(this.allTrackedProcessors());
26669
+ await Promise.all(allTracked.map(async (tracked) => {
26670
+ if (tracked.status !== "active")
26671
+ return;
26672
+ const unseen = operations.filter((op) => op.context.ordinal > tracked.lastOrdinal);
26673
+ const matching = unseen.filter((op) => matchesFilter(op, tracked.record.filter));
26674
+ if (matching.length > 0) {
26675
+ try {
26676
+ await tracked.record.processor.onOperations(matching);
26677
+ } catch (error) {
26678
+ tracked.status = "errored";
26679
+ tracked.lastError = error instanceof Error ? error.message : String(error);
26680
+ tracked.lastErrorTimestamp = new Date;
26681
+ await this.safeSaveProcessorCursor(tracked);
26682
+ this.logger.error("Processor '@ProcessorId' failed at ordinal @Ordinal: @Error", tracked.processorId, tracked.lastOrdinal, error);
26683
+ return;
26684
+ }
26807
26685
  }
26686
+ tracked.lastOrdinal = maxOrdinal;
26687
+ await this.safeSaveProcessorCursor(tracked);
26688
+ }));
26689
+ }
26690
+ async loadAllCursors() {
26691
+ const rows = await this.db.selectFrom("ProcessorCursor").selectAll().execute();
26692
+ for (const row of rows) {
26693
+ this.cursorCache.set(row.processorId, row);
26808
26694
  }
26809
- await Promise.all(Array.from(processorOperations.entries()).map(async ([processor, ops]) => {
26810
- try {
26811
- await processor.onOperations(ops);
26812
- } catch (error) {
26813
- console.error("ProcessorManager: Error in processor.onOperations:", error);
26695
+ }
26696
+ async safeSaveProcessorCursor(tracked) {
26697
+ try {
26698
+ await this.saveProcessorCursor(tracked);
26699
+ } catch (error) {
26700
+ this.logger.error("Failed to persist cursor for '@ProcessorId': @Error", tracked.processorId, error);
26701
+ }
26702
+ }
26703
+ async saveProcessorCursor(tracked) {
26704
+ await this.db.insertInto("ProcessorCursor").values({
26705
+ processorId: tracked.processorId,
26706
+ factoryId: tracked.factoryId,
26707
+ driveId: tracked.driveId,
26708
+ processorIndex: tracked.processorIndex,
26709
+ lastOrdinal: tracked.lastOrdinal,
26710
+ status: tracked.status,
26711
+ lastError: tracked.lastError ?? null,
26712
+ lastErrorTimestamp: tracked.lastErrorTimestamp ?? null,
26713
+ updatedAt: new Date
26714
+ }).onConflict((oc) => oc.column("processorId").doUpdateSet({
26715
+ lastOrdinal: tracked.lastOrdinal,
26716
+ status: tracked.status,
26717
+ lastError: tracked.lastError ?? null,
26718
+ lastErrorTimestamp: tracked.lastErrorTimestamp ?? null,
26719
+ updatedAt: new Date
26720
+ })).execute();
26721
+ this.cursorCache.set(tracked.processorId, {
26722
+ processorId: tracked.processorId,
26723
+ factoryId: tracked.factoryId,
26724
+ driveId: tracked.driveId,
26725
+ processorIndex: tracked.processorIndex,
26726
+ lastOrdinal: tracked.lastOrdinal,
26727
+ status: tracked.status,
26728
+ lastError: tracked.lastError ?? null,
26729
+ lastErrorTimestamp: tracked.lastErrorTimestamp ?? null,
26730
+ createdAt: new Date,
26731
+ updatedAt: new Date
26732
+ });
26733
+ }
26734
+ async deleteProcessorCursors(filter) {
26735
+ if ("factoryId" in filter) {
26736
+ await this.db.deleteFrom("ProcessorCursor").where("factoryId", "=", filter.factoryId).execute();
26737
+ for (const [id, row] of this.cursorCache) {
26738
+ if (row.factoryId === filter.factoryId)
26739
+ this.cursorCache.delete(id);
26814
26740
  }
26815
- }));
26741
+ } else {
26742
+ await this.db.deleteFrom("ProcessorCursor").where("driveId", "=", filter.driveId).execute();
26743
+ for (const [id, row] of this.cursorCache) {
26744
+ if (row.driveId === filter.driveId)
26745
+ this.cursorCache.delete(id);
26746
+ }
26747
+ }
26816
26748
  }
26817
26749
  };
26818
26750
  KyselyDocumentView = class KyselyDocumentView extends BaseReadModel {
26819
26751
  operationStore;
26820
26752
  _db;
26821
26753
  constructor(db, operationStore, operationIndex, writeCache, consistencyTracker) {
26822
- super(db, operationIndex, writeCache, consistencyTracker, "document-view");
26754
+ super(db, operationIndex, writeCache, consistencyTracker, { readModelId: "document-view", rebuildStateOnInit: true });
26823
26755
  this.operationStore = operationStore;
26824
26756
  this._db = db;
26825
26757
  }
26826
- async indexOperations(items) {
26827
- if (items.length === 0)
26828
- return;
26758
+ async commitOperations(items) {
26829
26759
  await this._db.transaction().execute(async (trx) => {
26830
26760
  for (const item of items) {
26831
26761
  const { operation, context } = item;
@@ -26929,9 +26859,7 @@ var init_src = __esm(() => {
26929
26859
  }
26930
26860
  }
26931
26861
  }
26932
- await this.saveState(trx, items);
26933
26862
  });
26934
- this.updateConsistencyTracker(items);
26935
26863
  }
26936
26864
  async exists(documentIds, consistencyToken, signal) {
26937
26865
  if (consistencyToken) {
@@ -27176,6 +27104,363 @@ var init_src = __esm(() => {
27176
27104
  return resolvedDocumentId;
27177
27105
  }
27178
27106
  };
27107
+ KyselyDocumentIndexer = class KyselyDocumentIndexer extends BaseReadModel {
27108
+ _db;
27109
+ constructor(db, operationIndex, writeCache, consistencyTracker) {
27110
+ super(db, operationIndex, writeCache, consistencyTracker, { readModelId: "document-indexer", rebuildStateOnInit: false });
27111
+ this._db = db;
27112
+ }
27113
+ async commitOperations(items) {
27114
+ await this._db.transaction().execute(async (trx) => {
27115
+ for (const item of items) {
27116
+ const { operation } = item;
27117
+ const actionType = operation.action.type;
27118
+ if (actionType === "ADD_RELATIONSHIP") {
27119
+ await this.handleAddRelationship(trx, operation);
27120
+ } else if (actionType === "REMOVE_RELATIONSHIP") {
27121
+ await this.handleRemoveRelationship(trx, operation);
27122
+ }
27123
+ }
27124
+ });
27125
+ }
27126
+ async getOutgoing(documentId, types2, paging, consistencyToken, signal) {
27127
+ if (consistencyToken) {
27128
+ await this.waitForConsistency(consistencyToken, undefined, signal);
27129
+ }
27130
+ if (signal?.aborted) {
27131
+ throw new Error("Operation aborted");
27132
+ }
27133
+ const startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;
27134
+ const limit = paging?.limit || 100;
27135
+ let query = this._db.selectFrom("DocumentRelationship").selectAll().where("sourceId", "=", documentId);
27136
+ if (types2 && types2.length > 0) {
27137
+ query = query.where("relationshipType", "in", types2);
27138
+ }
27139
+ const rows = await query.orderBy("createdAt", "asc").orderBy("id", "asc").offset(startIndex).limit(limit + 1).execute();
27140
+ const hasMore = rows.length > limit;
27141
+ const results = hasMore ? rows.slice(0, limit) : rows;
27142
+ const nextCursor = hasMore ? String(startIndex + limit) : undefined;
27143
+ return {
27144
+ results: results.map((row) => ({
27145
+ sourceId: row.sourceId,
27146
+ targetId: row.targetId,
27147
+ relationshipType: row.relationshipType,
27148
+ metadata: row.metadata ? row.metadata : undefined,
27149
+ createdAt: row.createdAt,
27150
+ updatedAt: row.updatedAt
27151
+ })),
27152
+ options: paging || { cursor: "0", limit: 100 },
27153
+ nextCursor,
27154
+ next: hasMore ? () => this.getOutgoing(documentId, types2, { cursor: nextCursor, limit }, consistencyToken, signal) : undefined
27155
+ };
27156
+ }
27157
+ async getIncoming(documentId, types2, paging, consistencyToken, signal) {
27158
+ if (consistencyToken) {
27159
+ await this.waitForConsistency(consistencyToken, undefined, signal);
27160
+ }
27161
+ if (signal?.aborted) {
27162
+ throw new Error("Operation aborted");
27163
+ }
27164
+ const startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;
27165
+ const limit = paging?.limit || 100;
27166
+ let query = this._db.selectFrom("DocumentRelationship").selectAll().where("targetId", "=", documentId);
27167
+ if (types2 && types2.length > 0) {
27168
+ query = query.where("relationshipType", "in", types2);
27169
+ }
27170
+ const rows = await query.orderBy("createdAt", "asc").orderBy("id", "asc").offset(startIndex).limit(limit + 1).execute();
27171
+ const hasMore = rows.length > limit;
27172
+ const results = hasMore ? rows.slice(0, limit) : rows;
27173
+ const nextCursor = hasMore ? String(startIndex + limit) : undefined;
27174
+ return {
27175
+ results: results.map((row) => ({
27176
+ sourceId: row.sourceId,
27177
+ targetId: row.targetId,
27178
+ relationshipType: row.relationshipType,
27179
+ metadata: row.metadata ? row.metadata : undefined,
27180
+ createdAt: row.createdAt,
27181
+ updatedAt: row.updatedAt
27182
+ })),
27183
+ options: paging || { cursor: "0", limit: 100 },
27184
+ nextCursor,
27185
+ next: hasMore ? () => this.getIncoming(documentId, types2, { cursor: nextCursor, limit }, consistencyToken, signal) : undefined
27186
+ };
27187
+ }
27188
+ async hasRelationship(sourceId, targetId, types2, consistencyToken, signal) {
27189
+ if (consistencyToken) {
27190
+ await this.waitForConsistency(consistencyToken, undefined, signal);
27191
+ }
27192
+ if (signal?.aborted) {
27193
+ throw new Error("Operation aborted");
27194
+ }
27195
+ let query = this._db.selectFrom("DocumentRelationship").select("id").where("sourceId", "=", sourceId).where("targetId", "=", targetId);
27196
+ if (types2 && types2.length > 0) {
27197
+ query = query.where("relationshipType", "in", types2);
27198
+ }
27199
+ const result = await query.executeTakeFirst();
27200
+ return result !== undefined;
27201
+ }
27202
+ async getUndirectedRelationships(a2, b, types2, paging, consistencyToken, signal) {
27203
+ if (consistencyToken) {
27204
+ await this.waitForConsistency(consistencyToken, undefined, signal);
27205
+ }
27206
+ if (signal?.aborted) {
27207
+ throw new Error("Operation aborted");
27208
+ }
27209
+ const startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;
27210
+ const limit = paging?.limit || 100;
27211
+ let query = this._db.selectFrom("DocumentRelationship").selectAll().where((eb) => eb.or([
27212
+ eb.and([eb("sourceId", "=", a2), eb("targetId", "=", b)]),
27213
+ eb.and([eb("sourceId", "=", b), eb("targetId", "=", a2)])
27214
+ ]));
27215
+ if (types2 && types2.length > 0) {
27216
+ query = query.where("relationshipType", "in", types2);
27217
+ }
27218
+ const rows = await query.orderBy("createdAt", "asc").orderBy("id", "asc").offset(startIndex).limit(limit + 1).execute();
27219
+ const hasMore = rows.length > limit;
27220
+ const results = hasMore ? rows.slice(0, limit) : rows;
27221
+ const nextCursor = hasMore ? String(startIndex + limit) : undefined;
27222
+ return {
27223
+ results: results.map((row) => ({
27224
+ sourceId: row.sourceId,
27225
+ targetId: row.targetId,
27226
+ relationshipType: row.relationshipType,
27227
+ metadata: row.metadata ? row.metadata : undefined,
27228
+ createdAt: row.createdAt,
27229
+ updatedAt: row.updatedAt
27230
+ })),
27231
+ options: paging || { cursor: "0", limit: 100 },
27232
+ nextCursor,
27233
+ next: hasMore ? () => this.getUndirectedRelationships(a2, b, types2, { cursor: nextCursor, limit }, consistencyToken, signal) : undefined
27234
+ };
27235
+ }
27236
+ async getDirectedRelationships(sourceId, targetId, types2, paging, consistencyToken, signal) {
27237
+ if (consistencyToken) {
27238
+ await this.waitForConsistency(consistencyToken, undefined, signal);
27239
+ }
27240
+ if (signal?.aborted) {
27241
+ throw new Error("Operation aborted");
27242
+ }
27243
+ const startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;
27244
+ const limit = paging?.limit || 100;
27245
+ let query = this._db.selectFrom("DocumentRelationship").selectAll().where("sourceId", "=", sourceId).where("targetId", "=", targetId);
27246
+ if (types2 && types2.length > 0) {
27247
+ query = query.where("relationshipType", "in", types2);
27248
+ }
27249
+ const rows = await query.orderBy("createdAt", "asc").orderBy("id", "asc").offset(startIndex).limit(limit + 1).execute();
27250
+ const hasMore = rows.length > limit;
27251
+ const results = hasMore ? rows.slice(0, limit) : rows;
27252
+ const nextCursor = hasMore ? String(startIndex + limit) : undefined;
27253
+ return {
27254
+ results: results.map((row) => ({
27255
+ sourceId: row.sourceId,
27256
+ targetId: row.targetId,
27257
+ relationshipType: row.relationshipType,
27258
+ metadata: row.metadata ? row.metadata : undefined,
27259
+ createdAt: row.createdAt,
27260
+ updatedAt: row.updatedAt
27261
+ })),
27262
+ options: paging || { cursor: "0", limit: 100 },
27263
+ nextCursor,
27264
+ next: hasMore ? () => this.getDirectedRelationships(sourceId, targetId, types2, { cursor: nextCursor, limit }, consistencyToken, signal) : undefined
27265
+ };
27266
+ }
27267
+ async findPath(sourceId, targetId, types2, consistencyToken, signal) {
27268
+ if (consistencyToken) {
27269
+ await this.waitForConsistency(consistencyToken, undefined, signal);
27270
+ }
27271
+ if (signal?.aborted) {
27272
+ throw new Error("Operation aborted");
27273
+ }
27274
+ if (sourceId === targetId) {
27275
+ return [sourceId];
27276
+ }
27277
+ const visited = new Set;
27278
+ const queue = [
27279
+ { id: sourceId, path: [sourceId] }
27280
+ ];
27281
+ while (queue.length > 0) {
27282
+ const current = queue.shift();
27283
+ if (current.id === targetId) {
27284
+ return current.path;
27285
+ }
27286
+ if (visited.has(current.id)) {
27287
+ continue;
27288
+ }
27289
+ visited.add(current.id);
27290
+ const outgoingPage = await this.getOutgoing(current.id, types2, undefined, consistencyToken, signal);
27291
+ const outgoingRelationships = await collectAllPages(outgoingPage, signal);
27292
+ for (const rel of outgoingRelationships) {
27293
+ if (!visited.has(rel.targetId)) {
27294
+ queue.push({
27295
+ id: rel.targetId,
27296
+ path: [...current.path, rel.targetId]
27297
+ });
27298
+ }
27299
+ }
27300
+ }
27301
+ return null;
27302
+ }
27303
+ async findAncestors(documentId, types2, consistencyToken, signal) {
27304
+ if (consistencyToken) {
27305
+ await this.waitForConsistency(consistencyToken, undefined, signal);
27306
+ }
27307
+ if (signal?.aborted) {
27308
+ throw new Error("Operation aborted");
27309
+ }
27310
+ const nodes = new Set([documentId]);
27311
+ const edges = [];
27312
+ const queue = [documentId];
27313
+ const visited = new Set;
27314
+ while (queue.length > 0) {
27315
+ const currentId = queue.shift();
27316
+ if (visited.has(currentId)) {
27317
+ continue;
27318
+ }
27319
+ visited.add(currentId);
27320
+ const incomingPage = await this.getIncoming(currentId, types2, undefined, consistencyToken, signal);
27321
+ const incomingRelationships = await collectAllPages(incomingPage, signal);
27322
+ for (const rel of incomingRelationships) {
27323
+ nodes.add(rel.sourceId);
27324
+ edges.push({
27325
+ from: rel.sourceId,
27326
+ to: rel.targetId,
27327
+ type: rel.relationshipType
27328
+ });
27329
+ if (!visited.has(rel.sourceId)) {
27330
+ queue.push(rel.sourceId);
27331
+ }
27332
+ }
27333
+ }
27334
+ return {
27335
+ nodes: Array.from(nodes),
27336
+ edges
27337
+ };
27338
+ }
27339
+ async getRelationshipTypes(consistencyToken, signal) {
27340
+ if (consistencyToken) {
27341
+ await this.waitForConsistency(consistencyToken, undefined, signal);
27342
+ }
27343
+ if (signal?.aborted) {
27344
+ throw new Error("Operation aborted");
27345
+ }
27346
+ const rows = await this._db.selectFrom("DocumentRelationship").select("relationshipType").distinct().execute();
27347
+ return rows.map((row) => row.relationshipType);
27348
+ }
27349
+ async handleAddRelationship(trx, operation) {
27350
+ const input = operation.action.input;
27351
+ const existingDoc = await trx.selectFrom("Document").select("id").where("id", "=", input.sourceId).executeTakeFirst();
27352
+ if (!existingDoc) {
27353
+ await trx.insertInto("Document").values({
27354
+ id: input.sourceId
27355
+ }).execute();
27356
+ }
27357
+ const existingTargetDoc = await trx.selectFrom("Document").select("id").where("id", "=", input.targetId).executeTakeFirst();
27358
+ if (!existingTargetDoc) {
27359
+ await trx.insertInto("Document").values({
27360
+ id: input.targetId
27361
+ }).execute();
27362
+ }
27363
+ const existingRel = await trx.selectFrom("DocumentRelationship").select("id").where("sourceId", "=", input.sourceId).where("targetId", "=", input.targetId).where("relationshipType", "=", input.relationshipType).executeTakeFirst();
27364
+ if (!existingRel) {
27365
+ const relationship = {
27366
+ id: v4_default(),
27367
+ sourceId: input.sourceId,
27368
+ targetId: input.targetId,
27369
+ relationshipType: input.relationshipType,
27370
+ metadata: input.metadata || null
27371
+ };
27372
+ await trx.insertInto("DocumentRelationship").values(relationship).execute();
27373
+ }
27374
+ }
27375
+ async handleRemoveRelationship(trx, operation) {
27376
+ const input = operation.action.input;
27377
+ await trx.deleteFrom("DocumentRelationship").where("sourceId", "=", input.sourceId).where("targetId", "=", input.targetId).where("relationshipType", "=", input.relationshipType).execute();
27378
+ }
27379
+ };
27380
+ DuplicateOperationError = class DuplicateOperationError extends Error {
27381
+ constructor(description) {
27382
+ super(`Duplicate operation: ${description}`);
27383
+ this.name = "DuplicateOperationError";
27384
+ }
27385
+ };
27386
+ RevisionMismatchError = class RevisionMismatchError extends Error {
27387
+ constructor(expected, actual) {
27388
+ super(`Revision mismatch: expected ${expected}, got ${actual}`);
27389
+ this.name = "RevisionMismatchError";
27390
+ }
27391
+ };
27392
+ exports_001_create_operation_table = {};
27393
+ __export2(exports_001_create_operation_table, {
27394
+ up: () => up
27395
+ });
27396
+ exports_002_create_keyframe_table = {};
27397
+ __export2(exports_002_create_keyframe_table, {
27398
+ up: () => up2
27399
+ });
27400
+ exports_003_create_document_table = {};
27401
+ __export2(exports_003_create_document_table, {
27402
+ up: () => up3
27403
+ });
27404
+ exports_004_create_document_relationship_table = {};
27405
+ __export2(exports_004_create_document_relationship_table, {
27406
+ up: () => up4
27407
+ });
27408
+ exports_005_create_indexer_state_table = {};
27409
+ __export2(exports_005_create_indexer_state_table, {
27410
+ up: () => up5
27411
+ });
27412
+ exports_006_create_document_snapshot_table = {};
27413
+ __export2(exports_006_create_document_snapshot_table, {
27414
+ up: () => up6
27415
+ });
27416
+ exports_007_create_slug_mapping_table = {};
27417
+ __export2(exports_007_create_slug_mapping_table, {
27418
+ up: () => up7
27419
+ });
27420
+ exports_008_create_view_state_table = {};
27421
+ __export2(exports_008_create_view_state_table, {
27422
+ up: () => up8
27423
+ });
27424
+ exports_009_create_operation_index_tables = {};
27425
+ __export2(exports_009_create_operation_index_tables, {
27426
+ up: () => up9
27427
+ });
27428
+ exports_010_create_sync_tables = {};
27429
+ __export2(exports_010_create_sync_tables, {
27430
+ up: () => up10
27431
+ });
27432
+ exports_011_add_cursor_type_column = {};
27433
+ __export2(exports_011_add_cursor_type_column, {
27434
+ up: () => up11
27435
+ });
27436
+ exports_012_add_source_remote_column = {};
27437
+ __export2(exports_012_add_source_remote_column, {
27438
+ up: () => up12
27439
+ });
27440
+ exports_013_create_sync_dead_letters_table = {};
27441
+ __export2(exports_013_create_sync_dead_letters_table, {
27442
+ up: () => up13
27443
+ });
27444
+ exports_014_create_processor_cursor_table = {};
27445
+ __export2(exports_014_create_processor_cursor_table, {
27446
+ up: () => up14
27447
+ });
27448
+ migrations = {
27449
+ "001_create_operation_table": exports_001_create_operation_table,
27450
+ "002_create_keyframe_table": exports_002_create_keyframe_table,
27451
+ "003_create_document_table": exports_003_create_document_table,
27452
+ "004_create_document_relationship_table": exports_004_create_document_relationship_table,
27453
+ "005_create_indexer_state_table": exports_005_create_indexer_state_table,
27454
+ "006_create_document_snapshot_table": exports_006_create_document_snapshot_table,
27455
+ "007_create_slug_mapping_table": exports_007_create_slug_mapping_table,
27456
+ "008_create_view_state_table": exports_008_create_view_state_table,
27457
+ "009_create_operation_index_tables": exports_009_create_operation_index_tables,
27458
+ "010_create_sync_tables": exports_010_create_sync_tables,
27459
+ "011_add_cursor_type_column": exports_011_add_cursor_type_column,
27460
+ "012_add_source_remote_column": exports_012_add_source_remote_column,
27461
+ "013_create_sync_dead_letters_table": exports_013_create_sync_dead_letters_table,
27462
+ "014_create_processor_cursor_table": exports_014_create_processor_cursor_table
27463
+ };
27179
27464
  ((ChannelScheme2) => {
27180
27465
  ChannelScheme2["CONNECT"] = "connect";
27181
27466
  ChannelScheme2["SWITCHBOARD"] = "switchboard";
@@ -27197,7 +27482,8 @@ var init_src = __esm(() => {
27197
27482
  SYNC_PENDING: 20001,
27198
27483
  SYNC_SUCCEEDED: 20002,
27199
27484
  SYNC_FAILED: 20003,
27200
- DEAD_LETTER_ADDED: 20004
27485
+ DEAD_LETTER_ADDED: 20004,
27486
+ CONNECTION_STATE_CHANGED: 20005
27201
27487
  };
27202
27488
  MailboxAggregateError = class MailboxAggregateError extends Error {
27203
27489
  errors;
@@ -27234,85 +27520,6 @@ var init_src = __esm(() => {
27234
27520
  retryBaseDelayMs: 1000,
27235
27521
  retryMaxDelayMs: 300000
27236
27522
  };
27237
- DuplicateOperationError = class DuplicateOperationError extends Error {
27238
- constructor(description) {
27239
- super(`Duplicate operation: ${description}`);
27240
- this.name = "DuplicateOperationError";
27241
- }
27242
- };
27243
- RevisionMismatchError = class RevisionMismatchError extends Error {
27244
- constructor(expected, actual) {
27245
- super(`Revision mismatch: expected ${expected}, got ${actual}`);
27246
- this.name = "RevisionMismatchError";
27247
- }
27248
- };
27249
- exports_001_create_operation_table = {};
27250
- __export2(exports_001_create_operation_table, {
27251
- up: () => up
27252
- });
27253
- exports_002_create_keyframe_table = {};
27254
- __export2(exports_002_create_keyframe_table, {
27255
- up: () => up2
27256
- });
27257
- exports_003_create_document_table = {};
27258
- __export2(exports_003_create_document_table, {
27259
- up: () => up3
27260
- });
27261
- exports_004_create_document_relationship_table = {};
27262
- __export2(exports_004_create_document_relationship_table, {
27263
- up: () => up4
27264
- });
27265
- exports_005_create_indexer_state_table = {};
27266
- __export2(exports_005_create_indexer_state_table, {
27267
- up: () => up5
27268
- });
27269
- exports_006_create_document_snapshot_table = {};
27270
- __export2(exports_006_create_document_snapshot_table, {
27271
- up: () => up6
27272
- });
27273
- exports_007_create_slug_mapping_table = {};
27274
- __export2(exports_007_create_slug_mapping_table, {
27275
- up: () => up7
27276
- });
27277
- exports_008_create_view_state_table = {};
27278
- __export2(exports_008_create_view_state_table, {
27279
- up: () => up8
27280
- });
27281
- exports_009_create_operation_index_tables = {};
27282
- __export2(exports_009_create_operation_index_tables, {
27283
- up: () => up9
27284
- });
27285
- exports_010_create_sync_tables = {};
27286
- __export2(exports_010_create_sync_tables, {
27287
- up: () => up10
27288
- });
27289
- exports_011_add_cursor_type_column = {};
27290
- __export2(exports_011_add_cursor_type_column, {
27291
- up: () => up11
27292
- });
27293
- exports_012_add_source_remote_column = {};
27294
- __export2(exports_012_add_source_remote_column, {
27295
- up: () => up12
27296
- });
27297
- exports_013_create_sync_dead_letters_table = {};
27298
- __export2(exports_013_create_sync_dead_letters_table, {
27299
- up: () => up13
27300
- });
27301
- migrations = {
27302
- "001_create_operation_table": exports_001_create_operation_table,
27303
- "002_create_keyframe_table": exports_002_create_keyframe_table,
27304
- "003_create_document_table": exports_003_create_document_table,
27305
- "004_create_document_relationship_table": exports_004_create_document_relationship_table,
27306
- "005_create_indexer_state_table": exports_005_create_indexer_state_table,
27307
- "006_create_document_snapshot_table": exports_006_create_document_snapshot_table,
27308
- "007_create_slug_mapping_table": exports_007_create_slug_mapping_table,
27309
- "008_create_view_state_table": exports_008_create_view_state_table,
27310
- "009_create_operation_index_tables": exports_009_create_operation_index_tables,
27311
- "010_create_sync_tables": exports_010_create_sync_tables,
27312
- "011_add_cursor_type_column": exports_011_add_cursor_type_column,
27313
- "012_add_source_remote_column": exports_012_add_source_remote_column,
27314
- "013_create_sync_dead_letters_table": exports_013_create_sync_dead_letters_table
27315
- };
27316
27523
  ((SyncStatus2) => {
27317
27524
  SyncStatus2["Synced"] = "SYNCED";
27318
27525
  SyncStatus2["Outgoing"] = "OUTGOING";
@@ -27429,6 +27636,8 @@ __export(exports_src, {
27429
27636
  useDocumentById: () => useDocumentById,
27430
27637
  useDocument: () => useDocument,
27431
27638
  useDefaultDriveEditorModule: () => useDefaultDriveEditorModule,
27639
+ useConnectionStates: () => useConnectionStates,
27640
+ useConnectionState: () => useConnectionState,
27432
27641
  useAllowedDocumentTypes: () => useAllowedDocumentTypes,
27433
27642
  useAllowedDocumentModelModules: () => useAllowedDocumentModelModules,
27434
27643
  truncateAllTables: () => dropAllTables,
@@ -27535,6 +27744,7 @@ __export(exports_src, {
27535
27744
  RemoteDocumentController: () => RemoteDocumentController,
27536
27745
  RemoteClient: () => RemoteClient,
27537
27746
  RelationalDbProcessor: () => RelationalDbProcessor,
27747
+ RegistryClient: () => RegistryClient,
27538
27748
  ReactorClientDocumentCache: () => ReactorClientDocumentCache,
27539
27749
  ReactorClientBuilder: () => ReactorClientBuilder,
27540
27750
  ReactorBuilder: () => ReactorBuilder,
@@ -27598,14 +27808,15 @@ import {
27598
27808
  import { documentModelDocumentModelModule } from "document-model";
27599
27809
  import { useSyncExternalStore as useSyncExternalStore2 } from "react";
27600
27810
  import { useSyncExternalStore as useSyncExternalStore22 } from "react";
27811
+ import { useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
27601
27812
  import { logger as logger5 } from "document-drive";
27602
27813
  import { use as use2, useCallback as useCallback2, useSyncExternalStore as useSyncExternalStore3 } from "react";
27603
- import { useEffect as useEffect2, useState as useState2 } from "react";
27814
+ import { useEffect as useEffect22, useState as useState22 } from "react";
27604
27815
  import {
27605
27816
  DocumentModelNotFoundError,
27606
27817
  DocumentNotFoundError as DocumentNotFoundError2
27607
27818
  } from "document-drive";
27608
- import { useCallback as useCallback22, useEffect as useEffect22, useRef as useRef2, useState as useState22 } from "react";
27819
+ import { useCallback as useCallback3, useEffect as useEffect3, useRef as useRef22, useState as useState3 } from "react";
27609
27820
  import { isFileNode as isFileNode2 } from "document-drive";
27610
27821
  import { useMemo as useMemo2 } from "react";
27611
27822
  import {
@@ -27616,19 +27827,19 @@ import {
27616
27827
  import { createState } from "document-model";
27617
27828
  import { defaultBaseState as defaultBaseState2, generateId as generateId22 } from "document-model/core";
27618
27829
  import { logger as logger6 } from "document-drive";
27619
- import { useEffect as useEffect3, useState as useState3 } from "react";
27620
27830
  import { useEffect as useEffect4, useState as useState4 } from "react";
27831
+ import { useEffect as useEffect5, useState as useState5 } from "react";
27621
27832
  import { createRelationalDbLegacy } from "document-drive";
27622
27833
  import { useMemo as useMemo22 } from "react";
27623
- import { useEffect as useEffect5, useRef as useRef22, useState as useState5 } from "react";
27624
- import { useCallback as useCallback3, useMemo as useMemo3, useRef as useRef3 } from "react";
27625
- import { useCallback as useCallback4, useEffect as useEffect6, useRef as useRef4, useState as useState6 } from "react";
27834
+ import { useEffect as useEffect6, useRef as useRef3, useState as useState6 } from "react";
27835
+ import { useCallback as useCallback4, useMemo as useMemo3, useRef as useRef4 } from "react";
27836
+ import { useCallback as useCallback5, useEffect as useEffect7, useRef as useRef5, useState as useState7 } from "react";
27626
27837
  import { jsxDEV } from "react/jsx-dev-runtime";
27627
27838
  import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
27628
- import { useCallback as useCallback5, useEffect as useEffect7, useRef as useRef5, useState as useState7 } from "react";
27839
+ import { useCallback as useCallback6, useEffect as useEffect8, useRef as useRef6, useState as useState8 } from "react";
27629
27840
  import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
27630
27841
  import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
27631
- import { useEffect as useEffect8, useRef as useRef6 } from "react";
27842
+ import { useEffect as useEffect9, useRef as useRef7 } from "react";
27632
27843
  function asUint8Array(buf) {
27633
27844
  if (globalThis.Buffer != null) {
27634
27845
  return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
@@ -31060,6 +31271,52 @@ function useAllowedDocumentModelModules() {
31060
31271
  return documentModelModules;
31061
31272
  return documentModelModules?.filter((module) => allowedDocumentTypes.includes(module.documentModel.global.id));
31062
31273
  }
31274
+ function useConnectionStates() {
31275
+ const syncManager = useSync();
31276
+ const [states, setStates] = useState2(() => buildSnapshot(syncManager));
31277
+ const unsubscribesRef = useRef2([]);
31278
+ useEffect2(() => {
31279
+ if (!syncManager)
31280
+ return;
31281
+ function subscribe() {
31282
+ for (const unsub of unsubscribesRef.current) {
31283
+ unsub();
31284
+ }
31285
+ unsubscribesRef.current = [];
31286
+ const remotes = syncManager.list();
31287
+ for (const remote of remotes) {
31288
+ const unsub = remote.channel.onConnectionStateChange(() => {
31289
+ setStates(buildSnapshot(syncManager));
31290
+ });
31291
+ unsubscribesRef.current.push(unsub);
31292
+ }
31293
+ setStates(buildSnapshot(syncManager));
31294
+ }
31295
+ subscribe();
31296
+ const interval = setInterval(subscribe, 5000);
31297
+ return () => {
31298
+ clearInterval(interval);
31299
+ for (const unsub of unsubscribesRef.current) {
31300
+ unsub();
31301
+ }
31302
+ unsubscribesRef.current = [];
31303
+ };
31304
+ }, [syncManager]);
31305
+ return states;
31306
+ }
31307
+ function useConnectionState(remoteName) {
31308
+ const states = useConnectionStates();
31309
+ return states.get(remoteName);
31310
+ }
31311
+ function buildSnapshot(syncManager) {
31312
+ const map = new Map;
31313
+ if (!syncManager)
31314
+ return map;
31315
+ for (const remote of syncManager.list()) {
31316
+ map.set(remote.name, remote.channel.getConnectionState());
31317
+ }
31318
+ return map;
31319
+ }
31063
31320
  function sortNodesByName(nodes) {
31064
31321
  return nodes.toSorted((a2, b) => a2.name.localeCompare(b.name));
31065
31322
  }
@@ -31428,8 +31685,8 @@ function setPHDocumentEditorConfig(config) {
31428
31685
  }
31429
31686
  }
31430
31687
  function useSetPHDriveEditorConfig(config) {
31431
- const [isInitialized, setIsInitialized] = useState2(false);
31432
- useEffect2(() => {
31688
+ const [isInitialized, setIsInitialized] = useState22(false);
31689
+ useEffect22(() => {
31433
31690
  if (isInitialized)
31434
31691
  return;
31435
31692
  setPHDriveEditorConfig(config);
@@ -31437,8 +31694,8 @@ function useSetPHDriveEditorConfig(config) {
31437
31694
  }, [config, isInitialized]);
31438
31695
  }
31439
31696
  function useSetPHDocumentEditorConfig(config) {
31440
- const [isInitialized, setIsInitialized] = useState2(false);
31441
- useEffect2(() => {
31697
+ const [isInitialized, setIsInitialized] = useState22(false);
31698
+ useEffect22(() => {
31442
31699
  if (isInitialized)
31443
31700
  return;
31444
31701
  setPHDocumentEditorConfig(config);
@@ -31471,14 +31728,14 @@ function useDocumentOfType(documentId, documentType) {
31471
31728
  }
31472
31729
  function useDocumentOperations(documentId) {
31473
31730
  const reactorClient = useReactorClient();
31474
- const hasFetchedRef = useRef2(false);
31475
- const [state, setState] = useState22(() => ({
31731
+ const hasFetchedRef = useRef22(false);
31732
+ const [state, setState] = useState3(() => ({
31476
31733
  globalOperations: [],
31477
31734
  localOperations: [],
31478
31735
  isLoading: !!documentId,
31479
31736
  error: undefined
31480
31737
  }));
31481
- const fetchOperations = useCallback22(async (retryCount = 0) => {
31738
+ const fetchOperations = useCallback3(async (retryCount = 0) => {
31482
31739
  const MAX_RETRIES = 5;
31483
31740
  const RETRY_DELAY_MS = 500;
31484
31741
  if (!documentId || !reactorClient) {
@@ -31524,7 +31781,7 @@ function useDocumentOperations(documentId) {
31524
31781
  });
31525
31782
  hasFetchedRef.current = true;
31526
31783
  }, [documentId, reactorClient]);
31527
- useEffect22(() => {
31784
+ useEffect3(() => {
31528
31785
  if (documentId && reactorClient) {
31529
31786
  fetchOperations();
31530
31787
  } else if (!documentId) {
@@ -31537,7 +31794,7 @@ function useDocumentOperations(documentId) {
31537
31794
  hasFetchedRef.current = false;
31538
31795
  }
31539
31796
  }, [documentId, reactorClient, fetchOperations]);
31540
- const refetch = useCallback22(() => {
31797
+ const refetch = useCallback3(() => {
31541
31798
  fetchOperations(0);
31542
31799
  }, [fetchOperations]);
31543
31800
  return { ...state, refetch };
@@ -32039,8 +32296,8 @@ async function logout() {
32039
32296
  }
32040
32297
  function useUser() {
32041
32298
  const renown = useRenown();
32042
- const [user, setUser] = useState3(() => renown?.user);
32043
- useEffect3(() => {
32299
+ const [user, setUser] = useState4(() => renown?.user);
32300
+ useEffect4(() => {
32044
32301
  setUser(renown?.user);
32045
32302
  if (!renown)
32046
32303
  return;
@@ -32050,8 +32307,8 @@ function useUser() {
32050
32307
  }
32051
32308
  function useLoginStatus() {
32052
32309
  const renown = useRenown();
32053
- const [status, setStatus] = useState3(() => renown ? renown.status : "initializing");
32054
- useEffect3(() => {
32310
+ const [status, setStatus] = useState4(() => renown ? renown.status : "initializing");
32311
+ useEffect4(() => {
32055
32312
  setStatus(renown ? renown.status : "initializing");
32056
32313
  if (!renown)
32057
32314
  return;
@@ -32153,6 +32410,7 @@ async function loadExternalPackage(name4, registryUrl) {
32153
32410
  class BrowserPackageManager {
32154
32411
  #storage;
32155
32412
  #packages = new Map;
32413
+ #localPackageIds = new Set;
32156
32414
  #subscribers = new Set;
32157
32415
  #packagesMemo = [];
32158
32416
  constructor(namespace) {
@@ -32173,6 +32431,9 @@ class BrowserPackageManager {
32173
32431
  get packages() {
32174
32432
  return this.#packagesMemo;
32175
32433
  }
32434
+ get localPackageIds() {
32435
+ return new Set(this.#localPackageIds);
32436
+ }
32176
32437
  async addPackage(name4, registryUrl) {
32177
32438
  const module = await loadExternalPackage(name4, registryUrl);
32178
32439
  this.#packages.set(name4, module);
@@ -32189,6 +32450,7 @@ class BrowserPackageManager {
32189
32450
  }
32190
32451
  async addLocalPackage(name4, localPackage) {
32191
32452
  this.#packages.set(name4, localPackage);
32453
+ this.#localPackageIds.add(localPackage.id);
32192
32454
  this.#notifyPackagesChanged();
32193
32455
  }
32194
32456
  async removePackage(name4) {
@@ -32237,6 +32499,40 @@ async function dropAllReactorStorage(pg) {
32237
32499
  await dropTablesInSchema(pg, REACTOR_SCHEMA);
32238
32500
  await dropTablesInSchema(pg, "public");
32239
32501
  }
32502
+ function cdnUrlToApiUrl(cdnUrl) {
32503
+ return cdnUrl.replace(/\/-\/cdn\/?$/, "");
32504
+ }
32505
+ function mapPackageInfo(pkg) {
32506
+ return {
32507
+ name: pkg.name,
32508
+ description: pkg.manifest?.description,
32509
+ version: pkg.manifest?.version,
32510
+ category: pkg.manifest?.category,
32511
+ publisher: pkg.manifest?.publisher?.name,
32512
+ publisherUrl: pkg.manifest?.publisher?.url
32513
+ };
32514
+ }
32515
+
32516
+ class RegistryClient {
32517
+ apiUrl;
32518
+ constructor(cdnUrl) {
32519
+ this.apiUrl = cdnUrlToApiUrl(cdnUrl);
32520
+ }
32521
+ async getPackages() {
32522
+ const res = await fetch(`${this.apiUrl}/packages`);
32523
+ if (!res.ok)
32524
+ throw new Error(`Registry error: HTTP ${res.status}`);
32525
+ const data = await res.json();
32526
+ return data.map(mapPackageInfo);
32527
+ }
32528
+ async searchPackages(query) {
32529
+ const packages = await this.getPackages();
32530
+ if (!query)
32531
+ return packages;
32532
+ const lowerQuery = query.toLowerCase();
32533
+ return packages.filter((pkg) => pkg.name.toLowerCase().includes(lowerQuery) || pkg.description?.toLowerCase().includes(lowerQuery));
32534
+ }
32535
+ }
32240
32536
 
32241
32537
  class ReactorClientDocumentCache {
32242
32538
  client;
@@ -43674,11 +43970,11 @@ function createRelationalDbWithLive(pgliteInstance) {
43674
43970
  return relationalDBWithLive;
43675
43971
  }
43676
43972
  function useRelationalQuery(ProcessorClass, driveId, queryCallback, parameters, options) {
43677
- const [result, setResult] = useState5(null);
43678
- const [queryLoading, setQueryLoading] = useState5(true);
43679
- const [error, setError] = useState5(undefined);
43680
- const retryCount = useRef22(0);
43681
- const retryTimeoutRef = useRef22(null);
43973
+ const [result, setResult] = useState6(null);
43974
+ const [queryLoading, setQueryLoading] = useState6(true);
43975
+ const [error, setError] = useState6(undefined);
43976
+ const retryCount = useRef3(0);
43977
+ const retryTimeoutRef = useRef3(null);
43682
43978
  const relationalDb = useRelationalDb();
43683
43979
  const executeLiveQuery = async (sql22, queryParameters, retryAttempt = 0) => {
43684
43980
  if (!relationalDb.db) {
@@ -43704,7 +44000,7 @@ function useRelationalQuery(ProcessorClass, driveId, queryCallback, parameters,
43704
44000
  return null;
43705
44001
  }
43706
44002
  };
43707
- useEffect5(() => {
44003
+ useEffect6(() => {
43708
44004
  setError(undefined);
43709
44005
  setQueryLoading(true);
43710
44006
  retryCount.current = 0;
@@ -43734,7 +44030,7 @@ function useRelationalQuery(ProcessorClass, driveId, queryCallback, parameters,
43734
44030
  };
43735
44031
  }
43736
44032
  function useStableParams(params) {
43737
- const prevParamsRef = useRef3(null);
44033
+ const prevParamsRef = useRef4(null);
43738
44034
  return useMemo3(() => {
43739
44035
  if (!import_lodash.default(prevParamsRef.current, params)) {
43740
44036
  prevParamsRef.current = params;
@@ -43745,7 +44041,7 @@ function useStableParams(params) {
43745
44041
  function createProcessorQuery(ProcessorClass) {
43746
44042
  function useQuery(driveId, queryCallback, parameters, options) {
43747
44043
  const stableParams = useStableParams(parameters);
43748
- const memoizedCallback = useCallback3(queryCallback, [stableParams]);
44044
+ const memoizedCallback = useCallback4(queryCallback, [stableParams]);
43749
44045
  return useRelationalQuery(ProcessorClass, driveId, memoizedCallback, stableParams, options);
43750
44046
  }
43751
44047
  return useQuery;
@@ -44449,20 +44745,20 @@ function RenownLoginButton({
44449
44745
  showPopover = false
44450
44746
  }) {
44451
44747
  const onLogin = onLoginProp ?? (() => openRenown());
44452
- const [isOpen, setIsOpen] = useState6(false);
44453
- const [isLoading, setIsLoading] = useState6(false);
44454
- const [isHovered, setIsHovered] = useState6(false);
44455
- const [showAbove, setShowAbove] = useState6(true);
44456
- const wrapperRef = useRef4(null);
44457
- const closeTimeoutRef = useRef4(null);
44458
- const calculatePosition = useCallback4(() => {
44748
+ const [isOpen, setIsOpen] = useState7(false);
44749
+ const [isLoading, setIsLoading] = useState7(false);
44750
+ const [isHovered, setIsHovered] = useState7(false);
44751
+ const [showAbove, setShowAbove] = useState7(true);
44752
+ const wrapperRef = useRef5(null);
44753
+ const closeTimeoutRef = useRef5(null);
44754
+ const calculatePosition = useCallback5(() => {
44459
44755
  if (!wrapperRef.current)
44460
44756
  return;
44461
44757
  const rect = wrapperRef.current.getBoundingClientRect();
44462
44758
  const spaceAbove = rect.top;
44463
44759
  setShowAbove(spaceAbove >= POPOVER_HEIGHT + POPOVER_GAP);
44464
44760
  }, []);
44465
- const handleMouseEnter = useCallback4(() => {
44761
+ const handleMouseEnter = useCallback5(() => {
44466
44762
  setIsHovered(true);
44467
44763
  if (!showPopover)
44468
44764
  return;
@@ -44473,13 +44769,13 @@ function RenownLoginButton({
44473
44769
  calculatePosition();
44474
44770
  setIsOpen(true);
44475
44771
  }, [calculatePosition, showPopover]);
44476
- const handleMouseLeave = useCallback4(() => {
44772
+ const handleMouseLeave = useCallback5(() => {
44477
44773
  closeTimeoutRef.current = setTimeout(() => {
44478
44774
  setIsOpen(false);
44479
44775
  setIsHovered(false);
44480
44776
  }, 150);
44481
44777
  }, []);
44482
- useEffect6(() => {
44778
+ useEffect7(() => {
44483
44779
  return () => {
44484
44780
  if (closeTimeoutRef.current) {
44485
44781
  clearTimeout(closeTimeoutRef.current);
@@ -44588,19 +44884,19 @@ function RenownUserButton({
44588
44884
  const avatarUrl = avatarUrlProp ?? user?.ens?.avatarUrl;
44589
44885
  const userId = userIdProp ?? user?.profile?.documentId;
44590
44886
  const onDisconnect = onDisconnectProp ?? (() => void logout());
44591
- const [isOpen, setIsOpen] = useState7(false);
44592
- const [isCopied, setIsCopied] = useState7(false);
44593
- const [showAbove, setShowAbove] = useState7(true);
44594
- const wrapperRef = useRef5(null);
44595
- const closeTimeoutRef = useRef5(null);
44596
- const calculatePosition = useCallback5(() => {
44887
+ const [isOpen, setIsOpen] = useState8(false);
44888
+ const [isCopied, setIsCopied] = useState8(false);
44889
+ const [showAbove, setShowAbove] = useState8(true);
44890
+ const wrapperRef = useRef6(null);
44891
+ const closeTimeoutRef = useRef6(null);
44892
+ const calculatePosition = useCallback6(() => {
44597
44893
  if (!wrapperRef.current)
44598
44894
  return;
44599
44895
  const rect = wrapperRef.current.getBoundingClientRect();
44600
44896
  const spaceAbove = rect.top;
44601
44897
  setShowAbove(spaceAbove >= POPOVER_HEIGHT2 + POPOVER_GAP2);
44602
44898
  }, []);
44603
- const handleMouseEnter = useCallback5(() => {
44899
+ const handleMouseEnter = useCallback6(() => {
44604
44900
  if (closeTimeoutRef.current) {
44605
44901
  clearTimeout(closeTimeoutRef.current);
44606
44902
  closeTimeoutRef.current = null;
@@ -44608,19 +44904,19 @@ function RenownUserButton({
44608
44904
  calculatePosition();
44609
44905
  setIsOpen(true);
44610
44906
  }, [calculatePosition]);
44611
- const handleMouseLeave = useCallback5(() => {
44907
+ const handleMouseLeave = useCallback6(() => {
44612
44908
  closeTimeoutRef.current = setTimeout(() => {
44613
44909
  setIsOpen(false);
44614
44910
  }, 150);
44615
44911
  }, []);
44616
- useEffect7(() => {
44912
+ useEffect8(() => {
44617
44913
  return () => {
44618
44914
  if (closeTimeoutRef.current) {
44619
44915
  clearTimeout(closeTimeoutRef.current);
44620
44916
  }
44621
44917
  };
44622
44918
  }, []);
44623
- const copyToClipboard = useCallback5(async () => {
44919
+ const copyToClipboard = useCallback6(async () => {
44624
44920
  try {
44625
44921
  await navigator.clipboard.writeText(address);
44626
44922
  setIsCopied(true);
@@ -44813,8 +45109,8 @@ function RenownProvider({
44813
45109
  baseUrl,
44814
45110
  children
44815
45111
  }) {
44816
- const initRef = useRef6(false);
44817
- const initialPropsRef = useRef6({ appName, basename, baseUrl });
45112
+ const initRef = useRef7(false);
45113
+ const initialPropsRef = useRef7({ appName, basename, baseUrl });
44818
45114
  if (initRef.current) {
44819
45115
  const initial = initialPropsRef.current;
44820
45116
  if (appName !== initial.appName) {
@@ -44827,7 +45123,7 @@ function RenownProvider({
44827
45123
  console.warn("RenownProvider: 'baseUrl' changed after mount. This prop is only read once during initialization.");
44828
45124
  }
44829
45125
  }
44830
- useEffect8(() => {
45126
+ useEffect9(() => {
44831
45127
  if (initRef.current)
44832
45128
  return;
44833
45129
  initRef.current = true;
@@ -45412,10 +45708,10 @@ ${String(result)}`);
45412
45708
  }, 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 = () => {
45413
45709
  const packageManager = useVetraPackageManager();
45414
45710
  return useSyncExternalStore22((cb) => packageManager ? packageManager.subscribe(cb) : () => {}, () => packageManager?.packages ?? []);
45415
- }, 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 = () => {
45711
+ }, addVetraPackageManagerEventHandler, reactorClientModuleEventFunctions, reactorClientEventFunctions, useReactorClientModule, setReactorClientModule, addReactorClientModuleEventHandler, useReactorClient, setReactorClient, addReactorClientEventHandler, useSync = () => useReactorClientModule()?.reactorModule?.syncModule?.syncManager, useSyncList = () => {
45416
45712
  const sync = useSync();
45417
45713
  return sync?.list() ?? [];
45418
- }, 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) => {
45714
+ }, 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) => {
45419
45715
  const errors2 = [];
45420
45716
  if (document2.header.documentType !== "powerhouse/document-model") {
45421
45717
  return errors2;
@@ -45482,8 +45778,8 @@ ${String(result)}`);
45482
45778
  };
45483
45779
  return onDropFile;
45484
45780
  }, store, BrowserLocalStorage, PGLITE_UPDATE_EVENT = "ph:pglite-update", defaultPGliteState, usePGliteDB = () => {
45485
- const [state, setState] = useState4(() => window.powerhouse?.pglite ?? defaultPGliteState);
45486
- useEffect4(() => {
45781
+ const [state, setState] = useState5(() => window.powerhouse?.pglite ?? defaultPGliteState);
45782
+ useEffect5(() => {
45487
45783
  const handlePgliteUpdate = () => setState(window.powerhouse?.pglite ?? defaultPGliteState);
45488
45784
  window.addEventListener(PGLITE_UPDATE_EVENT, handlePgliteUpdate);
45489
45785
  return () => window.removeEventListener(PGLITE_UPDATE_EVENT, handlePgliteUpdate);
@@ -50667,6 +50963,14 @@ spurious results.`);
50667
50963
  vetraPackageManagerFunctions = makePHEventFunctions("vetraPackageManager");
50668
50964
  useVetraPackageManager = vetraPackageManagerFunctions.useValue;
50669
50965
  addVetraPackageManagerEventHandler = vetraPackageManagerFunctions.addEventHandler;
50966
+ reactorClientModuleEventFunctions = makePHEventFunctions("reactorClientModule");
50967
+ reactorClientEventFunctions = makePHEventFunctions("reactorClient");
50968
+ useReactorClientModule = reactorClientModuleEventFunctions.useValue;
50969
+ setReactorClientModule = reactorClientModuleEventFunctions.setValue;
50970
+ addReactorClientModuleEventHandler = reactorClientModuleEventFunctions.addEventHandler;
50971
+ useReactorClient = reactorClientEventFunctions.useValue;
50972
+ setReactorClient = reactorClientEventFunctions.setValue;
50973
+ addReactorClientEventHandler = reactorClientEventFunctions.addEventHandler;
50670
50974
  documentEventFunctions = makePHEventFunctions("documentCache");
50671
50975
  useDocumentCache = documentEventFunctions.useValue;
50672
50976
  setDocumentCache = documentEventFunctions.setValue;
@@ -51714,14 +52018,6 @@ spurious results.`);
51714
52018
  ...phDocumentEditorConfigHooks,
51715
52019
  ...nonUserConfigHooks
51716
52020
  };
51717
- reactorClientModuleEventFunctions = makePHEventFunctions("reactorClientModule");
51718
- reactorClientEventFunctions = makePHEventFunctions("reactorClient");
51719
- useReactorClientModule = reactorClientModuleEventFunctions.useValue;
51720
- setReactorClientModule = reactorClientModuleEventFunctions.setValue;
51721
- addReactorClientModuleEventHandler = reactorClientModuleEventFunctions.addEventHandler;
51722
- useReactorClient = reactorClientEventFunctions.useValue;
51723
- setReactorClient = reactorClientEventFunctions.setValue;
51724
- addReactorClientEventHandler = reactorClientEventFunctions.addEventHandler;
51725
52021
  featuresEventFunctions = makePHEventFunctions("features");
51726
52022
  useFeatures = featuresEventFunctions.useValue;
51727
52023
  setFeatures = featuresEventFunctions.setValue;
@@ -89759,21 +90055,21 @@ var init_extraerrordata = __esm(() => {
89759
90055
 
89760
90056
  // ../../node_modules/.pnpm/@sentry+core@10.40.0/node_modules/@sentry/core/build/esm/utils/path.js
89761
90057
  function normalizeArray(parts, allowAboveRoot) {
89762
- let up14 = 0;
90058
+ let up15 = 0;
89763
90059
  for (let i2 = parts.length - 1;i2 >= 0; i2--) {
89764
90060
  const last = parts[i2];
89765
90061
  if (last === ".") {
89766
90062
  parts.splice(i2, 1);
89767
90063
  } else if (last === "..") {
89768
90064
  parts.splice(i2, 1);
89769
- up14++;
89770
- } else if (up14) {
90065
+ up15++;
90066
+ } else if (up15) {
89771
90067
  parts.splice(i2, 1);
89772
- up14--;
90068
+ up15--;
89773
90069
  }
89774
90070
  }
89775
90071
  if (allowAboveRoot) {
89776
- for (;up14--; up14) {
90072
+ for (;up15--; up15) {
89777
90073
  parts.unshift("..");
89778
90074
  }
89779
90075
  }
@@ -111771,7 +112067,7 @@ function createV6CompatibleWrapCreateMemoryRouter(createRouterFunction, version5
111771
112067
  function createReactRouterV6CompatibleTracingIntegration(options, version5) {
111772
112068
  const integration = browserTracingIntegration({ ...options, instrumentPageLoad: false, instrumentNavigation: false });
111773
112069
  const {
111774
- useEffect: useEffect10,
112070
+ useEffect: useEffect11,
111775
112071
  useLocation,
111776
112072
  useNavigationType,
111777
112073
  createRoutesFromChildren,
@@ -111802,7 +112098,7 @@ function createReactRouterV6CompatibleTracingIntegration(options, version5) {
111802
112098
  } else {
111803
112099
  _lazyRouteTimeout = configuredMaxWait;
111804
112100
  }
111805
- _useEffect = useEffect10;
112101
+ _useEffect = useEffect11;
111806
112102
  _useLocation = useLocation;
111807
112103
  _useNavigationType = useNavigationType;
111808
112104
  _matchRoutes2 = matchRoutes2;
@@ -112529,7 +112825,7 @@ var init_reload_connect_toast = __esm(() => {
112529
112825
 
112530
112826
  // src/hooks/useCheckLatestVersion.ts
112531
112827
  import { logger as logger9 } from "document-drive";
112532
- import { createElement as createElement7, useEffect as useEffect11 } from "react";
112828
+ import { createElement as createElement7, useEffect as useEffect12 } from "react";
112533
112829
  var useCheckLatestVersion = () => {
112534
112830
  async function checkLatestVersion() {
112535
112831
  const result = await isLatestVersion();
@@ -112550,7 +112846,7 @@ Latest: @latestVersion`, result.currentVersion, result.latestVersion);
112550
112846
  });
112551
112847
  }
112552
112848
  }
112553
- useEffect11(() => {
112849
+ useEffect12(() => {
112554
112850
  checkLatestVersion().catch(console.error);
112555
112851
  }, []);
112556
112852
  };
@@ -112563,13 +112859,13 @@ var init_useCheckLatestVersion = __esm(() => {
112563
112859
 
112564
112860
  // src/hooks/useClientErrorHandler.ts
112565
112861
  import { logger as logger10 } from "document-drive";
112566
- import { useCallback as useCallback6, useMemo as useMemo4, useRef as useRef9, useState as useState10 } from "react";
112862
+ import { useCallback as useCallback7, useMemo as useMemo4, useRef as useRef10, useState as useState11 } from "react";
112567
112863
  var DELAY_LIMIT = 1e5, useClientErrorHandler = () => {
112568
- const [handlingInProgress, setHandlingInProgress] = useState10([]);
112569
- const [pullResponderTriggerMap, setPullResponderTriggerMap] = useState10(new Map);
112864
+ const [handlingInProgress, setHandlingInProgress] = useState11([]);
112865
+ const [pullResponderTriggerMap, setPullResponderTriggerMap] = useState11(new Map);
112570
112866
  const drives = useDrives();
112571
- const pullResponderRegisterDelay = useRef9(new Map);
112572
- const handleStrands400 = useCallback6(async (driveId, trigger, handlerCode) => {
112867
+ const pullResponderRegisterDelay = useRef10(new Map);
112868
+ const handleStrands400 = useCallback7(async (driveId, trigger, handlerCode) => {
112573
112869
  setHandlingInProgress((state) => [...state, handlerCode]);
112574
112870
  const triggerData = trigger.data;
112575
112871
  if (!triggerData)
@@ -112602,7 +112898,7 @@ var DELAY_LIMIT = 1e5, useClientErrorHandler = () => {
112602
112898
  pullResponderRegisterDelay,
112603
112899
  registerNewPullResponderTrigger
112604
112900
  ]);
112605
- const handleDriveNotFound = useCallback6(async (driveId, trigger, handlerCode) => {
112901
+ const handleDriveNotFound = useCallback7(async (driveId, trigger, handlerCode) => {
112606
112902
  setHandlingInProgress((state) => [...state, handlerCode]);
112607
112903
  try {
112608
112904
  const drive = drives?.find((drive2) => drive2.header.id === driveId);
@@ -112638,7 +112934,7 @@ var DELAY_LIMIT = 1e5, useClientErrorHandler = () => {
112638
112934
  getDriveIdBySlug,
112639
112935
  addRemoteDrive
112640
112936
  ]);
112641
- const strandsErrorHandler = useCallback6(async (driveId, trigger, status, errorMessage) => {}, [handleDriveNotFound, handleStrands400, handlingInProgress]);
112937
+ const strandsErrorHandler = useCallback7(async (driveId, trigger, status, errorMessage) => {}, [handleDriveNotFound, handleStrands400, handlingInProgress]);
112642
112938
  return useMemo4(() => ({ strandsErrorHandler }), [strandsErrorHandler]);
112643
112939
  };
112644
112940
  var init_useClientErrorHandler = __esm(() => {
@@ -117635,7 +117931,7 @@ var init_dist4 = __esm(() => {
117635
117931
 
117636
117932
  // src/hooks/useInitSentry.ts
117637
117933
  import { childLogger } from "document-drive";
117638
- import React8, { useEffect as useEffect14 } from "react";
117934
+ import React8, { useEffect as useEffect15 } from "react";
117639
117935
  async function getSentry() {
117640
117936
  return await Promise.resolve().then(() => (init_esm7(), exports_esm));
117641
117937
  }
@@ -117692,7 +117988,7 @@ async function closeClient() {
117692
117988
  function useInitSentry() {
117693
117989
  const [acceptedCookies] = useAcceptedCookies();
117694
117990
  const { analytics } = acceptedCookies;
117695
- useEffect14(() => {
117991
+ useEffect15(() => {
117696
117992
  if (!analytics) {
117697
117993
  closeClient().catch((error3) => logger11.error("@error", error3));
117698
117994
  return;
@@ -117712,22 +118008,22 @@ var init_useInitSentry = __esm(() => {
117712
118008
  });
117713
118009
 
117714
118010
  // src/hooks/useNodeActions.ts
117715
- import { useCallback as useCallback10 } from "react";
118011
+ import { useCallback as useCallback11 } from "react";
117716
118012
  function useDebugHandlers() {
117717
- const onAddTrigger = useCallback10(async (driveId) => {
118013
+ const onAddTrigger = useCallback11(async (driveId) => {
117718
118014
  const url = window.prompt("url") || "";
117719
118015
  const pullResponderTrigger = await registerNewPullResponderTrigger(driveId, url, { pullInterval: 6000 });
117720
118016
  if (!pullResponderTrigger)
117721
118017
  return;
117722
118018
  await addTrigger(driveId, pullResponderTrigger);
117723
118019
  }, [addTrigger, registerNewPullResponderTrigger]);
117724
- const onRemoveTrigger = useCallback10(async (driveId) => {
118020
+ const onRemoveTrigger = useCallback11(async (driveId) => {
117725
118021
  const triggerId = window.prompt("triggerId:");
117726
118022
  if (triggerId) {
117727
118023
  await removeTrigger(driveId, triggerId);
117728
118024
  }
117729
118025
  }, [removeTrigger]);
117730
- const onAddInvalidTrigger = useCallback10(async (driveId) => {
118026
+ const onAddInvalidTrigger = useCallback11(async (driveId) => {
117731
118027
  const url = window.prompt("url") || "";
117732
118028
  await addTrigger(driveId, {
117733
118029
  id: "some-invalid-id",
@@ -117750,7 +118046,7 @@ var init_useNodeActions = __esm(() => {
117750
118046
  });
117751
118047
 
117752
118048
  // ../../node_modules/.pnpm/react-hotkeys-hook@4.6.2_react-dom@19.2.4_react@19.2.4__react@19.2.4/node_modules/react-hotkeys-hook/dist/react-hotkeys-hook.esm.js
117753
- import { useContext as useContext5, createContext as createContext4, useState as useState13, useCallback as useCallback11, useRef as useRef12, useLayoutEffect as useLayoutEffect3, useEffect as useEffect15 } from "react";
118049
+ import { useContext as useContext5, createContext as createContext4, useState as useState14, useCallback as useCallback12, useRef as useRef13, useLayoutEffect as useLayoutEffect3, useEffect as useEffect16 } from "react";
117754
118050
  import { jsx } from "react/jsx-runtime";
117755
118051
  function _extends4() {
117756
118052
  return _extends4 = Object.assign ? Object.assign.bind() : function(n5) {
@@ -117884,20 +118180,20 @@ function deepEqual(x2, y2) {
117884
118180
  }, true) : x2 === y2;
117885
118181
  }
117886
118182
  function useDeepEqualMemo(value) {
117887
- var ref = useRef12(undefined);
118183
+ var ref = useRef13(undefined);
117888
118184
  if (!deepEqual(ref.current, value)) {
117889
118185
  ref.current = value;
117890
118186
  }
117891
118187
  return ref.current;
117892
118188
  }
117893
118189
  function useHotkeys(keys2, callback, options, dependencies) {
117894
- var _useState = useState13(null), ref = _useState[0], setRef = _useState[1];
117895
- var hasTriggeredRef = useRef12(false);
118190
+ var _useState = useState14(null), ref = _useState[0], setRef = _useState[1];
118191
+ var hasTriggeredRef = useRef13(false);
117896
118192
  var _options = !(options instanceof Array) ? options : !(dependencies instanceof Array) ? dependencies : undefined;
117897
118193
  var _keys = isReadonlyArray4(keys2) ? keys2.join(_options == null ? undefined : _options.splitKey) : keys2;
117898
118194
  var _deps = options instanceof Array ? options : dependencies instanceof Array ? dependencies : undefined;
117899
- var memoisedCB = useCallback11(callback, _deps != null ? _deps : []);
117900
- var cbRef = useRef12(memoisedCB);
118195
+ var memoisedCB = useCallback12(callback, _deps != null ? _deps : []);
118196
+ var cbRef = useRef13(memoisedCB);
117901
118197
  if (_deps) {
117902
118198
  cbRef.current = memoisedCB;
117903
118199
  } else {
@@ -118090,7 +118386,7 @@ var init_react_hotkeys_hook_esm = __esm(() => {
118090
118386
  enableScope: function enableScope() {},
118091
118387
  disableScope: function disableScope() {}
118092
118388
  });
118093
- useSafeLayoutEffect = typeof window !== "undefined" ? useLayoutEffect3 : useEffect15;
118389
+ useSafeLayoutEffect = typeof window !== "undefined" ? useLayoutEffect3 : useEffect16;
118094
118390
  });
118095
118391
 
118096
118392
  // src/hooks/useUndoRedoShortcuts.ts
@@ -118121,13 +118417,13 @@ var init_useUndoRedoShortcuts = __esm(() => {
118121
118417
  });
118122
118418
 
118123
118419
  // src/hooks/useWindowSize.ts
118124
- import { useEffect as useEffect16, useState as useState14 } from "react";
118420
+ import { useEffect as useEffect17, useState as useState15 } from "react";
118125
118421
  var useWindowSize = () => {
118126
- const [windowSize, setWindowSize] = useState14({
118422
+ const [windowSize, setWindowSize] = useState15({
118127
118423
  innerWidth: window.innerWidth,
118128
118424
  innerHeight: window.innerHeight
118129
118425
  });
118130
- useEffect16(() => {
118426
+ useEffect17(() => {
118131
118427
  const windowSizeHandler = () => {
118132
118428
  setWindowSize({
118133
118429
  innerWidth: window.innerWidth,
@@ -118205,8 +118501,8 @@ var init_hooks = __esm(() => {
118205
118501
  // ../../packages/reactor-browser/dist/src/connect.js
118206
118502
  import { logger as logger13 } from "document-drive";
118207
118503
  import { useSyncExternalStore as useSyncExternalStore7 } from "react";
118208
- import { use as use3, useCallback as useCallback12, useSyncExternalStore as useSyncExternalStore23 } from "react";
118209
- import { useEffect as useEffect19, useState as useState17 } from "react";
118504
+ import { use as use3, useCallback as useCallback13, useSyncExternalStore as useSyncExternalStore23 } from "react";
118505
+ import { useEffect as useEffect20, useState as useState18 } from "react";
118210
118506
  import { logger as logger52 } from "document-drive";
118211
118507
  import { logger as logger42 } from "document-drive";
118212
118508
  import { logger as logger23 } from "document-drive";
@@ -118214,6 +118510,7 @@ import { logger as logger32 } from "document-drive";
118214
118510
  import { buildSignedAction as buildSignedAction2 } from "document-model/core";
118215
118511
  import { useSyncExternalStore as useSyncExternalStore32 } from "react";
118216
118512
  import { useEffect as useEffect23, useState as useState23 } from "react";
118513
+ import { useEffect as useEffect32, useRef as useRef14, useState as useState32 } from "react";
118217
118514
  function consumeDidFromUrl2() {
118218
118515
  if (typeof window === "undefined")
118219
118516
  return;
@@ -118487,8 +118784,8 @@ class DocumentCache2 {
118487
118784
  }
118488
118785
  function useUser2() {
118489
118786
  const renown = useRenown2();
118490
- const [user, setUser2] = useState17(() => renown?.user);
118491
- useEffect19(() => {
118787
+ const [user, setUser2] = useState18(() => renown?.user);
118788
+ useEffect20(() => {
118492
118789
  setUser2(renown?.user);
118493
118790
  if (!renown)
118494
118791
  return;
@@ -118705,6 +119002,48 @@ function setDefaultPHGlobalConfig(config) {
118705
119002
  callGlobalSetterForKey2(key, config[key]);
118706
119003
  }
118707
119004
  }
119005
+ function useConnectionStates2() {
119006
+ const syncManager = useSync2();
119007
+ const [states, setStates] = useState32(() => buildSnapshot2(syncManager));
119008
+ const unsubscribesRef = useRef14([]);
119009
+ useEffect32(() => {
119010
+ if (!syncManager)
119011
+ return;
119012
+ function subscribe3() {
119013
+ for (const unsub of unsubscribesRef.current) {
119014
+ unsub();
119015
+ }
119016
+ unsubscribesRef.current = [];
119017
+ const remotes = syncManager.list();
119018
+ for (const remote of remotes) {
119019
+ const unsub = remote.channel.onConnectionStateChange(() => {
119020
+ setStates(buildSnapshot2(syncManager));
119021
+ });
119022
+ unsubscribesRef.current.push(unsub);
119023
+ }
119024
+ setStates(buildSnapshot2(syncManager));
119025
+ }
119026
+ subscribe3();
119027
+ const interval = setInterval(subscribe3, 5000);
119028
+ return () => {
119029
+ clearInterval(interval);
119030
+ for (const unsub of unsubscribesRef.current) {
119031
+ unsub();
119032
+ }
119033
+ unsubscribesRef.current = [];
119034
+ };
119035
+ }, [syncManager]);
119036
+ return states;
119037
+ }
119038
+ function buildSnapshot2(syncManager) {
119039
+ const map = new Map;
119040
+ if (!syncManager)
119041
+ return map;
119042
+ for (const remote of syncManager.list()) {
119043
+ map.set(remote.name, remote.channel.getConnectionState());
119044
+ }
119045
+ return map;
119046
+ }
118708
119047
  var SPLIT_LOWER_UPPER_RE2, SPLIT_UPPER_UPPER_RE2, SPLIT_SEPARATE_NUMBER_RE2, DEFAULT_STRIP_REGEXP2, SPLIT_REPLACE_VALUE2 = "$1\x00$2", DEFAULT_PREFIX_SUFFIX_CHARACTERS2 = "", 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 = () => {
118709
119048
  const sync = useSync2();
118710
119049
  return sync?.list() ?? [];
@@ -145342,7 +145681,7 @@ ${typeDefsDoc}`;
145342
145681
 
145343
145682
  // ../../packages/powerhouse-vetra-packages/dist/editors/document-model-editor/context/schema-context.js
145344
145683
  import { jsx as _jsx2 } from "react/jsx-runtime";
145345
- import { createContext as createContext6, useContext as useContext7, useEffect as useEffect20, useState as useState18 } from "react";
145684
+ import { createContext as createContext6, useContext as useContext7, useEffect as useEffect21, useState as useState19 } from "react";
145346
145685
  function makeSharedSchemaSdl(existingSchemaSdl, globalStateSchemaSdl, localStateSchemaSdl, operationSchemasSdl) {
145347
145686
  const existingSchema = buildSchema(existingSchemaSdl);
145348
145687
  const sdls = [
@@ -145415,8 +145754,8 @@ function parseSharedSchemaSdl(initialSchema2, globalStateSchemaSdl, localStateSc
145415
145754
  }
145416
145755
  function SchemaContextProvider(props) {
145417
145756
  const { children, globalStateSchemaSdl, localStateSchemaSdl, operationSchemasSdl } = props;
145418
- const [sharedSchemaSdl, setSharedSchemaSdl] = useState18(() => parseSharedSchemaSdl(printSchema(initialSchema), globalStateSchemaSdl, localStateSchemaSdl, operationSchemasSdl));
145419
- useEffect20(() => {
145757
+ const [sharedSchemaSdl, setSharedSchemaSdl] = useState19(() => parseSharedSchemaSdl(printSchema(initialSchema), globalStateSchemaSdl, localStateSchemaSdl, operationSchemasSdl));
145758
+ useEffect21(() => {
145420
145759
  setSharedSchemaSdl((prev) => parseSharedSchemaSdl(prev.sharedSchema, globalStateSchemaSdl, localStateSchemaSdl, operationSchemasSdl));
145421
145760
  }, [globalStateSchemaSdl, localStateSchemaSdl, operationSchemasSdl]);
145422
145761
  return _jsx2(SchemaContext.Provider, { value: sharedSchemaSdl, children });
@@ -156633,18 +156972,18 @@ var init_form = __esm(() => {
156633
156972
  // ../../packages/powerhouse-vetra-packages/dist/editors/document-model-editor/components/text-area.js
156634
156973
  import { jsx as _jsx5 } from "react/jsx-runtime";
156635
156974
  import * as React18 from "react";
156636
- import { forwardRef as forwardRef8, useImperativeHandle, useRef as useRef13, useCallback as useCallback14 } from "react";
156975
+ import { forwardRef as forwardRef8, useImperativeHandle, useRef as useRef15, useCallback as useCallback15 } from "react";
156637
156976
  var Textarea;
156638
156977
  var init_text_area = __esm(() => {
156639
156978
  init_style();
156640
156979
  Textarea = forwardRef8(({ className, ...props }, ref) => {
156641
- const textareaRef = useRef13(null);
156642
- const adjustHeight = useCallback14((textarea) => {
156980
+ const textareaRef = useRef15(null);
156981
+ const adjustHeight = useCallback15((textarea) => {
156643
156982
  textarea.style.height = "auto";
156644
156983
  const newHeight = Math.max(textarea.scrollHeight, textarea.offsetHeight);
156645
156984
  textarea.style.height = `${newHeight}px`;
156646
156985
  }, []);
156647
- const handleInput = useCallback14((e4) => {
156986
+ const handleInput = useCallback15((e4) => {
156648
156987
  adjustHeight(e4.currentTarget);
156649
156988
  }, [adjustHeight]);
156650
156989
  React18.useEffect(() => {
@@ -156663,7 +157002,7 @@ var init_text_area = __esm(() => {
156663
157002
 
156664
157003
  // ../../packages/powerhouse-vetra-packages/dist/editors/document-model-editor/components/text-field.js
156665
157004
  import { jsx as _jsx6, jsxs as _jsxs } from "react/jsx-runtime";
156666
- import { forwardRef as forwardRef9, useCallback as useCallback15, useEffect as useEffect24, useId as useId2, useImperativeHandle as useImperativeHandle2, useRef as useRef14 } from "react";
157005
+ import { forwardRef as forwardRef9, useCallback as useCallback16, useEffect as useEffect26, useId as useId2, useImperativeHandle as useImperativeHandle2, useRef as useRef16 } from "react";
156667
157006
  var TextField;
156668
157007
  var init_text_field = __esm(() => {
156669
157008
  init_zod2();
@@ -156674,9 +157013,9 @@ var init_text_field = __esm(() => {
156674
157013
  init_form();
156675
157014
  init_text_area();
156676
157015
  TextField = forwardRef9(({ name: name6, value, onSubmit, label, placeholder, unique, className = "", rows = 1, focusOnMount = false, required: required2 = false, allowEmpty = false, shouldReset = false, onChange }, ref) => {
156677
- const textareaRef = useRef14(null);
157016
+ const textareaRef = useRef16(null);
156678
157017
  const id = useId2();
156679
- useEffect24(() => {
157018
+ useEffect26(() => {
156680
157019
  if (focusOnMount && textareaRef.current) {
156681
157020
  textareaRef.current.focus();
156682
157021
  }
@@ -156690,7 +157029,7 @@ var init_text_field = __esm(() => {
156690
157029
  [name6]: value ?? ""
156691
157030
  }
156692
157031
  });
156693
- const handleSubmit = useCallback15((values) => {
157032
+ const handleSubmit = useCallback16((values) => {
156694
157033
  const newValue = values[name6];
156695
157034
  if (newValue === undefined || value === newValue)
156696
157035
  return;
@@ -156698,7 +157037,7 @@ var init_text_field = __esm(() => {
156698
157037
  if (shouldReset)
156699
157038
  form.reset({ [name6]: "" });
156700
157039
  }, [name6, value, onSubmit, form, shouldReset]);
156701
- const handleBlur = useCallback15(async () => {
157040
+ const handleBlur = useCallback16(async () => {
156702
157041
  const currentValue = form.getValues()[name6] ?? "";
156703
157042
  if (value === null || value === undefined) {
156704
157043
  if (!currentValue || currentValue.trim() === "")
@@ -156713,20 +157052,20 @@ var init_text_field = __esm(() => {
156713
157052
  }
156714
157053
  } catch (e4) {}
156715
157054
  }, [form, handleSubmit, name6, value]);
156716
- const onEnterKeyDown = useCallback15((e4) => {
157055
+ const onEnterKeyDown = useCallback16((e4) => {
156717
157056
  if (e4.key === "Enter") {
156718
157057
  e4.preventDefault();
156719
157058
  e4.target.blur();
156720
157059
  }
156721
157060
  }, []);
156722
- const handleChange = useCallback15((e4) => {
157061
+ const handleChange = useCallback16((e4) => {
156723
157062
  const newValue = e4.target.value;
156724
157063
  onChange?.(newValue);
156725
157064
  }, [onChange]);
156726
157065
  useImperativeHandle2(ref, () => ({
156727
157066
  focus: () => textareaRef.current?.focus()
156728
157067
  }));
156729
- useEffect24(() => {
157068
+ useEffect26(() => {
156730
157069
  form.reset({ [name6]: value ?? "" });
156731
157070
  }, [form, name6, value]);
156732
157071
  return _jsx6(Form3, { ...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) => {
@@ -156744,13 +157083,13 @@ var init_text_field = __esm(() => {
156744
157083
 
156745
157084
  // ../../packages/powerhouse-vetra-packages/dist/editors/document-model-editor/components/model-metadata-form.js
156746
157085
  import { jsx as _jsx7, jsxs as _jsxs2 } from "react/jsx-runtime";
156747
- import { useCallback as useCallback16 } from "react";
157086
+ import { useCallback as useCallback17 } from "react";
156748
157087
  function ModelMetadata(props) {
156749
157088
  return _jsxs2("div", { children: [_jsx7(ModelNameForm, { ...props }), _jsx7("div", { className: "flex h-full flex-col gap-4", children: _jsxs2("div", { className: "grid flex-1 grid-cols-3 items-start gap-4", children: [_jsxs2("div", { className: "col-span-2 flex h-full flex-col gap-4", children: [_jsx7("div", { className: "shrink-0", children: _jsx7(DocumentTypeForm, { ...props }) }), _jsx7("div", { className: "min-h-0 flex-1", children: _jsx7(DescriptionForm, { ...props }) })] }), _jsxs2("div", { className: "col-span-1 flex flex-col gap-4", children: [_jsx7(AuthorNameForm, { ...props }), _jsx7(AuthorWebsiteForm, { ...props }), _jsx7(ModelExtensionForm, { ...props })] })] }) })] });
156750
157089
  }
156751
157090
  function ModelNameForm(props) {
156752
157091
  const { name: name6, globalStateSchema, localStateSchema, setModelName, setStateSchema } = props;
156753
- const onSubmit = useCallback16((newName) => {
157092
+ const onSubmit = useCallback17((newName) => {
156754
157093
  if (name6 === newName) {
156755
157094
  return;
156756
157095
  }
@@ -156842,10 +157181,10 @@ var init_module_form = __esm(() => {
156842
157181
 
156843
157182
  // ../../packages/powerhouse-vetra-packages/dist/editors/document-model-editor/components/operation-form.js
156844
157183
  import { jsx as _jsx9 } from "react/jsx-runtime";
156845
- import { useCallback as useCallback17 } from "react";
157184
+ import { useCallback as useCallback18 } from "react";
156846
157185
  function OperationForm({ operation, module, focusOnMount, allOperationNames, onAddOperationAndInitialSchema, updateOperationName, deleteOperation }) {
156847
157186
  const isEdit = !!operation;
156848
- const handleSubmit = useCallback17(async (name6) => {
157187
+ const handleSubmit = useCallback18(async (name6) => {
156849
157188
  if (isEdit && name6 === "") {
156850
157189
  deleteOperation(operation.id);
156851
157190
  return;
@@ -156867,7 +157206,7 @@ function OperationForm({ operation, module, focusOnMount, allOperationNames, onA
156867
157206
  updateOperationName,
156868
157207
  onAddOperationAndInitialSchema
156869
157208
  ]);
156870
- const handleChange = useCallback17((value) => {
157209
+ const handleChange = useCallback18((value) => {
156871
157210
  if (isEdit && value === "") {
156872
157211
  deleteOperation(operation.id);
156873
157212
  }
@@ -156933,10 +157272,10 @@ var init_linting = __esm(() => {
156933
157272
 
156934
157273
  // ../../packages/powerhouse-vetra-packages/dist/editors/document-model-editor/components/operation-description-form.js
156935
157274
  import { jsx as _jsx10 } from "react/jsx-runtime";
156936
- import { useEffect as useEffect26, useRef as useRef15 } from "react";
157275
+ import { useEffect as useEffect27, useRef as useRef17 } from "react";
156937
157276
  function OperationDescriptionForm({ operation, focusOnMount, setOperationDescription }) {
156938
- const textFieldRef = useRef15(null);
156939
- useEffect26(() => {
157277
+ const textFieldRef = useRef17(null);
157278
+ useEffect27(() => {
156940
157279
  if (focusOnMount && textFieldRef.current) {
156941
157280
  textFieldRef.current.focus();
156942
157281
  }
@@ -156949,12 +157288,12 @@ var init_operation_description_form = __esm(() => {
156949
157288
 
156950
157289
  // ../../packages/powerhouse-vetra-packages/dist/editors/document-model-editor/components/operation-error-form.js
156951
157290
  import { jsx as _jsx11 } from "react/jsx-runtime";
156952
- import { useCallback as useCallback18, useRef as useRef16 } from "react";
157291
+ import { useCallback as useCallback19, useRef as useRef18 } from "react";
156953
157292
  function OperationErrorForm({ operation, error: error50, focusOnMount, onSubmit, onAddOperationError, deleteOperationError, setOperationErrorName }) {
156954
- const textFieldRef = useRef16(null);
157293
+ const textFieldRef = useRef18(null);
156955
157294
  const isEdit = !!error50;
156956
157295
  const allOperationErrorNames = operation.errors.map((o3) => o3.name).filter((n6) => n6 !== null);
156957
- const handleSubmit = useCallback18((name6) => {
157296
+ const handleSubmit = useCallback19((name6) => {
156958
157297
  if (isEdit && name6 === "") {
156959
157298
  deleteOperationError(error50.id);
156960
157299
  return;
@@ -156975,7 +157314,7 @@ function OperationErrorForm({ operation, error: error50, focusOnMount, onSubmit,
156975
157314
  onAddOperationError,
156976
157315
  onSubmit
156977
157316
  ]);
156978
- const handleChange = useCallback18((value) => {
157317
+ const handleChange = useCallback19((value) => {
156979
157318
  if (isEdit && value === "") {
156980
157319
  deleteOperationError(error50.id);
156981
157320
  }
@@ -156989,18 +157328,18 @@ var init_operation_error_form = __esm(() => {
156989
157328
 
156990
157329
  // ../../packages/powerhouse-vetra-packages/dist/editors/document-model-editor/components/operation-errors.js
156991
157330
  import { jsx as _jsx12, jsxs as _jsxs3 } from "react/jsx-runtime";
156992
- import { useCallback as useCallback19, useId as useId3, useState as useState19 } from "react";
157331
+ import { useCallback as useCallback20, useId as useId3, useState as useState20 } from "react";
156993
157332
  function OperationErrors({ operation, addOperationError, deleteOperationError, setOperationErrorName }) {
156994
157333
  const addErrorFormId = useId3();
156995
- const [shouldFocusAddForm, setShouldFocusAddForm] = useState19(false);
156996
- const onAddOperationError = useCallback19(async (operationId, error50) => {
157334
+ const [shouldFocusAddForm, setShouldFocusAddForm] = useState20(false);
157335
+ const onAddOperationError = useCallback20(async (operationId, error50) => {
156997
157336
  const errorId = await addOperationError(operationId, error50);
156998
157337
  if (errorId) {
156999
157338
  setShouldFocusAddForm(true);
157000
157339
  }
157001
157340
  return errorId;
157002
157341
  }, [addOperationError, setShouldFocusAddForm]);
157003
- const onAddOperationErrorSubmit = useCallback19(() => setShouldFocusAddForm(false), [setShouldFocusAddForm]);
157342
+ const onAddOperationErrorSubmit = useCallback20(() => setShouldFocusAddForm(false), [setShouldFocusAddForm]);
157004
157343
  return _jsxs3("ul", { className: "ml-4 list-disc", children: [operation.errors.map((error50) => _jsx12("li", { children: _jsx12(OperationErrorForm, { error: error50, operation, onAddOperationError, deleteOperationError, setOperationErrorName }) }, error50.id)), _jsx12("li", { children: _jsx12(OperationErrorForm, { operation, onAddOperationError, deleteOperationError, setOperationErrorName, focusOnMount: shouldFocusAddForm, onSubmit: onAddOperationErrorSubmit }, `${addErrorFormId}-${shouldFocusAddForm}`) })] });
157005
157344
  }
157006
157345
  var init_operation_errors = __esm(() => {
@@ -160300,10 +160639,10 @@ function dispatchKey(elt, name6, code6, mods) {
160300
160639
  let down = new KeyboardEvent("keydown", options);
160301
160640
  down.synthetic = true;
160302
160641
  elt.dispatchEvent(down);
160303
- let up14 = new KeyboardEvent("keyup", options);
160304
- up14.synthetic = true;
160305
- elt.dispatchEvent(up14);
160306
- return down.defaultPrevented || up14.defaultPrevented;
160642
+ let up15 = new KeyboardEvent("keyup", options);
160643
+ up15.synthetic = true;
160644
+ elt.dispatchEvent(up15);
160645
+ return down.defaultPrevented || up15.defaultPrevented;
160307
160646
  }
160308
160647
  function getRoot(node) {
160309
160648
  while (node) {
@@ -182631,14 +182970,14 @@ var init_factories = __esm(() => {
182631
182970
  });
182632
182971
 
182633
182972
  // ../../packages/powerhouse-vetra-packages/dist/editors/document-model-editor/components/code-editors/hooks.js
182634
- import { useEffect as useEffect27, useRef as useRef17 } from "react";
182973
+ import { useEffect as useEffect28, useRef as useRef19 } from "react";
182635
182974
  function useEditorRefs() {
182636
- const editorRef = useRef17(null);
182637
- const viewRef = useRef17(null);
182638
- const updateListenerCompartment = useRef17(new Compartment);
182639
- const focusHandlerCompartment = useRef17(new Compartment);
182640
- const pasteHandlerCompartment = useRef17(new Compartment);
182641
- const timeoutRef = useRef17(null);
182975
+ const editorRef = useRef19(null);
182976
+ const viewRef = useRef19(null);
182977
+ const updateListenerCompartment = useRef19(new Compartment);
182978
+ const focusHandlerCompartment = useRef19(new Compartment);
182979
+ const pasteHandlerCompartment = useRef19(new Compartment);
182980
+ const timeoutRef = useRef19(null);
182642
182981
  return {
182643
182982
  editorRef,
182644
182983
  viewRef,
@@ -182649,7 +182988,7 @@ function useEditorRefs() {
182649
182988
  };
182650
182989
  }
182651
182990
  function useEditorCleanup(viewRef) {
182652
- useEffect27(() => {
182991
+ useEffect28(() => {
182653
182992
  return () => {
182654
182993
  if (viewRef.current) {
182655
182994
  viewRef.current.destroy();
@@ -182659,7 +182998,7 @@ function useEditorCleanup(viewRef) {
182659
182998
  }, []);
182660
182999
  }
182661
183000
  function useHandlerReconfiguration(view, readonly4, timeoutRef, updateDocumentInModel, compartments) {
182662
- useEffect27(() => {
183001
+ useEffect28(() => {
182663
183002
  if (!view)
182664
183003
  return;
182665
183004
  view.dispatch({
@@ -182673,7 +183012,7 @@ function useHandlerReconfiguration(view, readonly4, timeoutRef, updateDocumentIn
182673
183012
  }, [readonly4, updateDocumentInModel]);
182674
183013
  }
182675
183014
  function useDocumentSync(view, doc3) {
182676
- useEffect27(() => {
183015
+ useEffect28(() => {
182677
183016
  if (!view)
182678
183017
  return;
182679
183018
  const currentDoc = view.state.doc.toString();
@@ -189989,7 +190328,7 @@ __export(exports_graphql_editor, {
189989
190328
  default: () => graphql_editor_default
189990
190329
  });
189991
190330
  import { jsx as _jsx13 } from "react/jsx-runtime";
189992
- import { memo as memo3, useEffect as useEffect28, useRef as useRef18 } from "react";
190331
+ import { memo as memo3, useEffect as useEffect29, useRef as useRef20 } from "react";
189993
190332
  var GraphqlEditor, graphql_editor_default;
189994
190333
  var init_graphql_editor = __esm(() => {
189995
190334
  init_dist13();
@@ -190006,10 +190345,10 @@ var init_graphql_editor = __esm(() => {
190006
190345
  GraphqlEditor = memo3(function GraphqlEditor2(props) {
190007
190346
  const { doc: doc3, readonly: readonly4 = false, updateDocumentInModel, customLinter } = props;
190008
190347
  const { editorRef, viewRef, updateListenerCompartment, focusHandlerCompartment, pasteHandlerCompartment, timeoutRef } = useEditorRefs();
190009
- const graphqlCompartment = useRef18(new Compartment);
190010
- const linterCompartment = useRef18(new Compartment);
190348
+ const graphqlCompartment = useRef20(new Compartment);
190349
+ const linterCompartment = useRef20(new Compartment);
190011
190350
  const { sharedSchema } = useSchemaContext();
190012
- useEffect28(() => {
190351
+ useEffect29(() => {
190013
190352
  if (!viewRef.current) {
190014
190353
  const schema18 = buildSchema(sharedSchema);
190015
190354
  viewRef.current = new EditorView({
@@ -190033,7 +190372,7 @@ var init_graphql_editor = __esm(() => {
190033
190372
  }
190034
190373
  }, []);
190035
190374
  useEditorCleanup(viewRef);
190036
- useEffect28(() => {
190375
+ useEffect29(() => {
190037
190376
  const view = viewRef.current;
190038
190377
  if (!view)
190039
190378
  return;
@@ -190063,13 +190402,13 @@ var init_graphql_editor = __esm(() => {
190063
190402
 
190064
190403
  // ../../packages/powerhouse-vetra-packages/dist/editors/document-model-editor/components/operation.js
190065
190404
  import { jsx as _jsx14, jsxs as _jsxs4 } from "react/jsx-runtime";
190066
- import { lazy as lazy2, Suspense, useCallback as useCallback20 } from "react";
190405
+ import { lazy as lazy2, Suspense, useCallback as useCallback21 } from "react";
190067
190406
  function Operation(props) {
190068
190407
  const { operation, module, allOperationNames, lastCreatedOperationId, onAddOperationAndInitialSchema, updateOperationName, deleteOperation, updateOperationSchema, setOperationDescription, addOperationError, deleteOperationError, setOperationErrorName, toggleNoInputRequired } = props;
190069
190408
  const noInputRequired = isEmptyOperationSchema(operation.schema);
190070
- const handleToggleNoInput = useCallback20((checked) => toggleNoInputRequired(operation.id, checked), [operation.id, toggleNoInputRequired]);
190071
- const handleUpdateDocument = useCallback20((newDoc) => updateOperationSchema(operation.id, newDoc), [operation.id, updateOperationSchema]);
190072
- const customLinter = useCallback20((doc3) => operation.name ? ensureValidOperationSchemaInputName(doc3, operation.name) : [], [operation.name]);
190409
+ const handleToggleNoInput = useCallback21((checked) => toggleNoInputRequired(operation.id, checked), [operation.id, toggleNoInputRequired]);
190410
+ const handleUpdateDocument = useCallback21((newDoc) => updateOperationSchema(operation.id, newDoc), [operation.id, updateOperationSchema]);
190411
+ const customLinter = useCallback21((doc3) => operation.name ? ensureValidOperationSchemaInputName(doc3, operation.name) : [], [operation.name]);
190073
190412
  return _jsxs4("div", { className: "mt-4 grid grid-cols-2 gap-x-12", style: {
190074
190413
  gridTemplateAreas: `
190075
190414
  "left editor"
@@ -190090,12 +190429,12 @@ var init_operation = __esm(() => {
190090
190429
 
190091
190430
  // ../../packages/powerhouse-vetra-packages/dist/editors/document-model-editor/components/operations.js
190092
190431
  import { jsx as _jsx15, jsxs as _jsxs5 } from "react/jsx-runtime";
190093
- import { useCallback as useCallback21, useId as useId4, useState as useState20 } from "react";
190432
+ import { useCallback as useCallback22, useId as useId4, useState as useState21 } from "react";
190094
190433
  function Operations({ module, allOperations, shouldFocusNewOperation, updateOperationName, deleteOperation, addOperationAndInitialSchema, addOperationError, deleteOperationError, setOperationErrorName, updateOperationSchema, setOperationDescription, toggleNoInputRequired }) {
190095
- const [lastCreatedOperationId, setLastCreatedOperationId] = useState20(null);
190434
+ const [lastCreatedOperationId, setLastCreatedOperationId] = useState21(null);
190096
190435
  const addOperationFormId = useId4();
190097
190436
  const allOperationNames = allOperations.map((o3) => o3.name).filter((n6) => n6 !== null);
190098
- const onAddOperationAndInitialSchema = useCallback21(async (moduleId, name6) => {
190437
+ const onAddOperationAndInitialSchema = useCallback22(async (moduleId, name6) => {
190099
190438
  const operationId = await addOperationAndInitialSchema(moduleId, name6);
190100
190439
  if (operationId) {
190101
190440
  setLastCreatedOperationId(operationId);
@@ -190124,10 +190463,10 @@ var init_module = __esm(() => {
190124
190463
 
190125
190464
  // ../../packages/powerhouse-vetra-packages/dist/editors/document-model-editor/components/modules.js
190126
190465
  import { jsx as _jsx17, jsxs as _jsxs7 } from "react/jsx-runtime";
190127
- import { useCallback as useCallback23, useRef as useRef19, useState as useState21 } from "react";
190466
+ import { useCallback as useCallback23, useRef as useRef21, useState as useState24 } from "react";
190128
190467
  function Modules({ modules, allOperations, addModule, updateModuleName, deleteModule, updateOperationName, deleteOperation, addOperationAndInitialSchema, updateOperationSchema, setOperationDescription, addOperationError, deleteOperationError, setOperationErrorName, toggleNoInputRequired }) {
190129
- const [lastCreatedModuleId, setLastCreatedModuleId] = useState21(null);
190130
- const focusTrapRef = useRef19(null);
190468
+ const [lastCreatedModuleId, setLastCreatedModuleId] = useState24(null);
190469
+ const focusTrapRef = useRef21(null);
190131
190470
  const onAddModule = useCallback23(async (name6) => {
190132
190471
  const moduleId = await addModule(name6);
190133
190472
  if (moduleId) {
@@ -191486,7 +191825,7 @@ __export(exports_json_editor, {
191486
191825
  default: () => json_editor_default
191487
191826
  });
191488
191827
  import { jsx as _jsx21 } from "react/jsx-runtime";
191489
- import { memo as memo4, useEffect as useEffect35 } from "react";
191828
+ import { memo as memo4, useEffect as useEffect38 } from "react";
191490
191829
  var JSONEditor, json_editor_default;
191491
191830
  var init_json_editor = __esm(() => {
191492
191831
  init_dist37();
@@ -191500,7 +191839,7 @@ var init_json_editor = __esm(() => {
191500
191839
  JSONEditor = memo4(function JSONEditor2(props) {
191501
191840
  const { doc: doc3, readonly: readonly4 = false, updateDocumentInModel } = props;
191502
191841
  const { editorRef, viewRef, updateListenerCompartment, focusHandlerCompartment, pasteHandlerCompartment, timeoutRef } = useEditorRefs();
191503
- useEffect35(() => {
191842
+ useEffect38(() => {
191504
191843
  if (!viewRef.current) {
191505
191844
  viewRef.current = new EditorView({
191506
191845
  state: EditorState.create({
@@ -191543,12 +191882,12 @@ __export(exports_state_schemas, {
191543
191882
  import { jsxs as _jsxs9, jsx as _jsx22 } from "react/jsx-runtime";
191544
191883
  import { cn as cn3 } from "@powerhousedao/design-system";
191545
191884
  import { Checkbox } from "@powerhousedao/design-system/ui/components/checkbox/checkbox.js";
191546
- import { lazy as lazy3, Suspense as Suspense2, useCallback as useCallback28, useEffect as useEffect36, useMemo as useMemo12, useRef as useRef28, useState as useState29 } from "react";
191885
+ import { lazy as lazy3, Suspense as Suspense2, useCallback as useCallback27, useEffect as useEffect39, useMemo as useMemo12, useRef as useRef30, useState as useState30 } from "react";
191547
191886
  function StateEditor({ modelName, stateSchema, initialValue, setStateSchema, setInitialState, scope }) {
191548
191887
  const { sharedSchema: sharedSchemaSdl, error: sharedSchemaError } = useSchemaContext();
191549
- const [showStandardLib, setShowStandardLib] = useState29(false);
191550
- const [syncWithSchema, setSyncWithSchema] = useState29(true);
191551
- const customLinter = useCallback28((doc3) => ensureValidStateSchemaName(doc3, modelName, scope), [modelName, scope]);
191888
+ const [showStandardLib, setShowStandardLib] = useState30(false);
191889
+ const [syncWithSchema, setSyncWithSchema] = useState30(true);
191890
+ const customLinter = useCallback27((doc3) => ensureValidStateSchemaName(doc3, modelName, scope), [modelName, scope]);
191552
191891
  const schemaErrors = useMemo12(() => {
191553
191892
  const errors5 = ensureValidStateSchemaName(stateSchema, modelName, scope);
191554
191893
  if (sharedSchemaError) {
@@ -191556,12 +191895,12 @@ function StateEditor({ modelName, stateSchema, initialValue, setStateSchema, set
191556
191895
  }
191557
191896
  return errors5;
191558
191897
  }, [stateSchema, modelName, scope, sharedSchemaError]);
191559
- const handleToggleStandardLib = useCallback28(() => {
191898
+ const handleToggleStandardLib = useCallback27(() => {
191560
191899
  setShowStandardLib((prev) => !prev);
191561
191900
  }, []);
191562
- const handleSchemaUpdate = useCallback28((newDoc) => setStateSchema(newDoc, scope), [setStateSchema, scope]);
191563
- const handleInitialStateUpdate = useCallback28((newDoc) => setInitialState(newDoc, scope), [setInitialState, scope]);
191564
- const hasSyncedRef = useRef28(false);
191901
+ const handleSchemaUpdate = useCallback27((newDoc) => setStateSchema(newDoc, scope), [setStateSchema, scope]);
191902
+ const handleInitialStateUpdate = useCallback27((newDoc) => setInitialState(newDoc, scope), [setInitialState, scope]);
191903
+ const hasSyncedRef = useRef30(false);
191565
191904
  const { initialValueErrors, fixedState } = useMemo12(() => {
191566
191905
  const existingValue = initialValue || "{}";
191567
191906
  const sharedSchemaDocumentNode = safeParseSdl(sharedSchemaSdl);
@@ -191586,7 +191925,7 @@ function StateEditor({ modelName, stateSchema, initialValue, setStateSchema, set
191586
191925
  }
191587
191926
  return { initialValueErrors: errors5, fixedState: null };
191588
191927
  }, [sharedSchemaSdl, initialValue, syncWithSchema, scope, modelName]);
191589
- useEffect36(() => {
191928
+ useEffect39(() => {
191590
191929
  if (fixedState && !hasSyncedRef.current) {
191591
191930
  hasSyncedRef.current = true;
191592
191931
  setInitialState(fixedState, scope);
@@ -191597,7 +191936,7 @@ function StateEditor({ modelName, stateSchema, initialValue, setStateSchema, set
191597
191936
  return _jsxs9("div", { className: "grid grid-cols-2 gap-4", children: [_jsxs9("div", { children: [_jsxs9("h3", { className: "mb-2 text-lg capitalize", children: [scope, " state schema *"] }), _jsxs9(Button, { onClick: handleToggleStandardLib, className: "mb-2 flex w-fit items-center gap-2", children: [showStandardLib ? "Hide" : "Show", " standard library", _jsx22("svg", { className: cn3("inline-block transition-transform", showStandardLib ? "rotate-180" : "rotate-0"), xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", children: _jsx22("path", { d: "M11.9883 6.01172C11.4363 6.01172 10.9883 6.45972 10.9883 7.01172V13.0117H6.98828L11.9883 18.0117L16.9883 13.0117H12.9883V7.01172C12.9883 6.45972 12.5403 6.01172 11.9883 6.01172Z", fill: "black" }) })] }), _jsxs9(Suspense2, { children: [showStandardLib && _jsx22(GraphqlEditor4, { doc: typeDefsDoc, readonly: true }), _jsx22(GraphqlEditor4, { doc: stateSchema, updateDocumentInModel: handleSchemaUpdate, customLinter }), schemaErrors.length > 0 && _jsx22("p", { className: "mt-2 text-sm text-red-600", children: schemaErrors[0].message })] })] }), _jsxs9("div", { children: [_jsxs9("div", { className: "flex flex-col items-end", children: [_jsxs9("h3", { className: "mb-2 text-right text-lg capitalize", children: [scope, " state initial value *"] }), _jsx22(Checkbox, { value: syncWithSchema, onChange: setSyncWithSchema, className: "mb-2 w-fit whitespace-nowrap rounded-md border border-gray-200 bg-gray-50 pl-2 text-sm font-medium text-gray-800 transition-colors hover:bg-gray-100 hover:text-gray-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2", label: _jsxs9("div", { className: "flex items-center gap-2 py-2 pr-2", children: ["Sync with schema", " ", _jsx22("svg", { className: "inline-block", xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: _jsx22("path", { d: "M8.00521 1.99219C6.63588 1.99219 5.32788 2.45152 4.27588 3.28419C3.98721 3.51219 3.94321 3.93285 4.17188 4.22151C4.40054 4.51018 4.82055 4.55418 5.10921 4.32552C5.92721 3.67819 6.93921 3.32552 8.00521 3.32552C10.5825 3.32552 12.6719 5.41485 12.6719 7.99218H11.3385L13.3385 10.6588L15.3385 7.99218H14.0052C14.0052 4.67818 11.3192 1.99219 8.00521 1.99219ZM2.67188 5.32552L0.671875 7.99218H2.00521C2.00521 11.3062 4.69121 13.9922 8.00521 13.9922C9.37521 13.9922 10.6825 13.5335 11.7345 12.7002C12.0232 12.4722 12.0672 12.0515 11.8385 11.7628C11.6099 11.4742 11.1899 11.4302 10.9012 11.6588C10.0825 12.3068 9.07188 12.6588 8.00521 12.6588C5.42788 12.6588 3.33854 10.5695 3.33854 7.99218H4.67188L2.67188 5.32552Z", fill: "#343839" }) })] }) })] }), _jsxs9(Suspense2, { children: [_jsx22(JSONEditor3, { doc: initialValue, updateDocumentInModel: handleInitialStateUpdate }), initialValueErrors.map((error50, index) => _jsx22("p", { className: "mt-2 text-sm text-red-600", children: error50 instanceof StateValidationError ? _jsx22(StateValidationErrorMessage, { error: error50 }) : error50.message }, index))] })] })] });
191598
191937
  }
191599
191938
  function StateSchemas({ modelName, globalStateSchema, localStateSchema, globalStateInitialValue, localStateInitialValue, setStateSchema, setInitialState, currentScope, onScopeChange }) {
191600
- const handleAddLocalState = useCallback28(() => {
191939
+ const handleAddLocalState = useCallback27(() => {
191601
191940
  const initialDoc = makeInitialSchemaDoc(modelName, "local");
191602
191941
  setStateSchema(initialDoc, "local");
191603
191942
  setInitialState("", "local");
@@ -191627,18 +191966,18 @@ import { jsx as _jsx23, jsxs as _jsxs10 } from "react/jsx-runtime";
191627
191966
  import { DocumentToolbar } from "@powerhousedao/design-system/connect";
191628
191967
  import { addModule, addOperation, addOperationError, deleteModule, deleteOperation, deleteOperationError, setAuthorName, setAuthorWebsite, setInitialState, setModelDescription, setModelExtension, setModelId, setModelName, setModuleName, setOperationDescription, setOperationErrorName, setOperationName, setOperationSchema, setStateSchema } from "document-model";
191629
191968
  import { generateId as generateId3 } from "document-model/core";
191630
- import { lazy as lazy4, Suspense as Suspense3, useEffect as useEffect37, useRef as useRef29, useState as useState30 } from "react";
191969
+ import { lazy as lazy4, Suspense as Suspense3, useEffect as useEffect40, useRef as useRef31, useState as useState31 } from "react";
191631
191970
  function Editor() {
191632
191971
  useSetPHDocumentEditorConfig(editorConfig);
191633
191972
  const toast3 = usePHToast();
191634
191973
  const [document2, dispatch] = useSelectedDocumentModelDocument();
191635
- const [scope, setScope] = useState30("global");
191974
+ const [scope, setScope] = useState31("global");
191636
191975
  const documentNodeName = document2.header.name;
191637
191976
  const { name: modelName, id: documentType, extension, description, author: { name: authorName, website: authorWebsite } } = document2.state.global;
191638
191977
  const { state: { global: { schema: globalStateSchema, initialValue: globalStateInitialValue }, local: { schema: localStateSchema, initialValue: localStateInitialValue } }, modules } = document2.state.global.specifications[0];
191639
191978
  const operations = modules.flatMap((module) => module.operations);
191640
- const shouldSetInitialName = useRef29(!modelName && !!documentNodeName && operations.length === 0);
191641
- useEffect37(() => {
191979
+ const shouldSetInitialName = useRef31(!modelName && !!documentNodeName && operations.length === 0);
191980
+ useEffect40(() => {
191642
191981
  if (!shouldSetInitialName.current || !documentNodeName)
191643
191982
  return;
191644
191983
  const initialSchemaDoc2 = initializeModelSchema(documentNodeName);
@@ -192735,9 +193074,9 @@ var init_esm12 = __esm(() => {
192735
193074
  import { jsx as _jsx25 } from "react/jsx-runtime";
192736
193075
  import { useWindowSize as useWindowSize3 } from "@powerhousedao/design-system";
192737
193076
  import { FileItem } from "@powerhousedao/design-system/connect";
192738
- import React35, { useRef as useRef30 } from "react";
193077
+ import React35, { useRef as useRef32 } from "react";
192739
193078
  function FileContentView() {
192740
- const parentRef = useRef30(null);
193079
+ const parentRef = useRef32(null);
192741
193080
  const windowSize = useWindowSize3();
192742
193081
  const availableWidth = windowSize.innerWidth - USED_SPACE;
192743
193082
  const nodes = useNodesInSelectedDriveOrFolder();
@@ -261542,10 +261881,10 @@ var init_reactor2 = __esm(() => {
261542
261881
  });
261543
261882
 
261544
261883
  // src/store/user.ts
261545
- import { useEffect as useEffect43 } from "react";
261884
+ import { useEffect as useEffect46 } from "react";
261546
261885
  function useSetSentryUser() {
261547
261886
  const user = useUser2();
261548
- useEffect43(() => {
261887
+ useEffect46(() => {
261549
261888
  let sentryUser = null;
261550
261889
  if (user) {
261551
261890
  const { credential, ...rest } = user;
@@ -261574,13 +261913,13 @@ __export(exports_ClearStorageModal, {
261574
261913
  });
261575
261914
  import { ConnectConfirmationModal } from "@powerhousedao/design-system/connect";
261576
261915
  import { childLogger as childLogger4 } from "document-drive";
261577
- import { useState as useState34 } from "react";
261916
+ import { useState as useState37 } from "react";
261578
261917
  import { jsxDEV as jsxDEV12 } from "react/jsx-dev-runtime";
261579
261918
  function ClearStorageModal() {
261580
261919
  const phModal = usePHModal();
261581
261920
  const open = phModal?.type === "clearStorage";
261582
261921
  const { t: t7 } = useTranslation();
261583
- const [loading, setLoading3] = useState34(false);
261922
+ const [loading, setLoading3] = useState37(false);
261584
261923
  function clearStorage() {
261585
261924
  setLoading3(true);
261586
261925
  clearReactorStorage().then(() => {
@@ -261702,26 +262041,26 @@ __export(exports_DebugSettingsModal, {
261702
262041
  import { Icon, Modal, PowerhouseButton as PowerhouseButton2 } from "@powerhousedao/design-system";
261703
262042
  import { Combobox, FormInput } from "@powerhousedao/design-system/connect";
261704
262043
  import { generateId as generateId4 } from "document-model/core";
261705
- import { useEffect as useEffect44, useState as useState35 } from "react";
262044
+ import { useEffect as useEffect47, useState as useState38 } from "react";
261706
262045
  import { jsxDEV as jsxDEV15 } from "react/jsx-dev-runtime";
261707
262046
  var DebugSettingsModal = () => {
261708
262047
  const phModal = usePHModal();
261709
262048
  const open = phModal?.type === "debugSettings";
261710
262049
  const autoRegisterPullResponder = localStorage.getItem("AUTO_REGISTER_PULL_RESPONDER") !== "false";
261711
- const [appVersion, setAppVersion] = useState35(connectConfig.appVersion);
261712
- const [serviceWorkerDebugMode, setServiceWorkerDebugMode] = useState35({
262050
+ const [appVersion, setAppVersion] = useState38(connectConfig.appVersion);
262051
+ const [serviceWorkerDebugMode, setServiceWorkerDebugMode] = useState38({
261713
262052
  label: serviceWorkerManager.debug ? "Enabled" : "Disabled",
261714
262053
  value: serviceWorkerManager.debug
261715
262054
  });
261716
- const [selectedDrive, setSelectedDrive3] = useState35();
261717
- const [selectedDriveTrigger, setSelectedDriveTrigger] = useState35(null);
261718
- const [driveUrl, setDriveUrl] = useState35("");
261719
- const [autoRegister, setAutoRegister] = useState35({
262055
+ const [selectedDrive, setSelectedDrive3] = useState38();
262056
+ const [selectedDriveTrigger, setSelectedDriveTrigger] = useState38(null);
262057
+ const [driveUrl, setDriveUrl] = useState38("");
262058
+ const [autoRegister, setAutoRegister] = useState38({
261720
262059
  label: autoRegisterPullResponder ? "Enabled" : "Disabled",
261721
262060
  value: autoRegisterPullResponder ? "true" : "false"
261722
262061
  });
261723
262062
  const drives = useDrives();
261724
- useEffect44(() => {
262063
+ useEffect47(() => {
261725
262064
  serviceWorkerManager.setDebug(serviceWorkerDebugMode.value);
261726
262065
  }, [serviceWorkerDebugMode]);
261727
262066
  const driveTriggers = drives?.find((drive) => drive.header.id === selectedDrive)?.state.local.triggers || [];
@@ -262301,11 +262640,11 @@ var init_danger_zone = __esm(() => {
262301
262640
 
262302
262641
  // src/components/modal/modals/settings/default-editor.tsx
262303
262642
  import { DefaultEditor as BaseDefaultEditor } from "@powerhousedao/design-system/connect";
262304
- import { useCallback as useCallback31, useState as useState36 } from "react";
262643
+ import { useCallback as useCallback30, useState as useState39 } from "react";
262305
262644
  import { jsxDEV as jsxDEV23 } from "react/jsx-dev-runtime";
262306
262645
  var documentModelEditorOptions, DefaultEditor = () => {
262307
- const [documentModelEditor, setDocumentModelEditor] = useState36(documentModelEditorOptions[1]);
262308
- const handleSetDocumentEditor = useCallback31((value) => {
262646
+ const [documentModelEditor, setDocumentModelEditor] = useState39(documentModelEditorOptions[1]);
262647
+ const handleSetDocumentEditor = useCallback30((value) => {
262309
262648
  const option = documentModelEditorOptions.find((dm) => dm.value == value);
262310
262649
  if (option) {
262311
262650
  setDocumentModelEditor(option);
@@ -262324,90 +262663,194 @@ var init_default_editor = __esm(() => {
262324
262663
  ];
262325
262664
  });
262326
262665
 
262666
+ // src/hooks/use-registry.ts
262667
+ import { useCallback as useCallback31, useEffect as useEffect48, useMemo as useMemo15, useState as useState40 } from "react";
262668
+ function loadPersistedState() {
262669
+ try {
262670
+ const raw = localStorage.getItem(STORAGE_KEY);
262671
+ if (raw)
262672
+ return JSON.parse(raw);
262673
+ } catch {}
262674
+ return null;
262675
+ }
262676
+ function persistState(state) {
262677
+ try {
262678
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
262679
+ } catch {}
262680
+ }
262681
+ function deriveLabelFromUrl(url2) {
262682
+ try {
262683
+ const parsed = new URL(url2);
262684
+ const host = parsed.hostname;
262685
+ if (host === "localhost" || host === "127.0.0.1") {
262686
+ return "Local";
262687
+ }
262688
+ return host;
262689
+ } catch {
262690
+ return url2;
262691
+ }
262692
+ }
262693
+ function buildRegistries(packagesRegistry) {
262694
+ const registries2 = [];
262695
+ if (packagesRegistry) {
262696
+ const urls = packagesRegistry.split(",").map((u2) => u2.trim()).filter(Boolean);
262697
+ urls.forEach((url2, index) => {
262698
+ registries2.push({
262699
+ id: `registry-${index}`,
262700
+ label: deriveLabelFromUrl(url2),
262701
+ url: url2
262702
+ });
262703
+ });
262704
+ }
262705
+ registries2.push({
262706
+ id: "custom",
262707
+ label: "Custom",
262708
+ url: "",
262709
+ editable: true
262710
+ });
262711
+ return registries2;
262712
+ }
262713
+ function useRegistry() {
262714
+ const registries2 = useMemo15(() => buildRegistries(connectConfig.packagesRegistry), []);
262715
+ const persisted = useMemo15(() => loadPersistedState(), []);
262716
+ const [selectedRegistryId, setSelectedRegistryId] = useState40(() => persisted?.selectedRegistryId ?? registries2[0]?.id ?? "custom");
262717
+ const [customRegistryUrl, setCustomRegistryUrl] = useState40(() => persisted?.customRegistryUrl ?? "");
262718
+ const [registryStatus, setRegistryStatus] = useState40("idle");
262719
+ const [availablePackages, setAvailablePackages] = useState40([]);
262720
+ const selectedRegistry = useMemo15(() => registries2.find((r7) => r7.id === selectedRegistryId), [registries2, selectedRegistryId]);
262721
+ const effectiveRegistryUrl = useMemo15(() => {
262722
+ if (!selectedRegistry)
262723
+ return "";
262724
+ if (selectedRegistry.editable)
262725
+ return customRegistryUrl;
262726
+ return selectedRegistry.url;
262727
+ }, [selectedRegistry, customRegistryUrl]);
262728
+ const client = useMemo15(() => effectiveRegistryUrl ? new RegistryClient(effectiveRegistryUrl) : null, [effectiveRegistryUrl]);
262729
+ useEffect48(() => {
262730
+ persistState({ selectedRegistryId, customRegistryUrl });
262731
+ }, [selectedRegistryId, customRegistryUrl]);
262732
+ useEffect48(() => {
262733
+ if (!client) {
262734
+ setRegistryStatus("idle");
262735
+ setAvailablePackages([]);
262736
+ return;
262737
+ }
262738
+ let cancelled = false;
262739
+ setRegistryStatus("connecting");
262740
+ client.getPackages().then((packages) => {
262741
+ if (cancelled)
262742
+ return;
262743
+ setAvailablePackages(packages);
262744
+ setRegistryStatus("connected");
262745
+ }).catch(() => {
262746
+ if (cancelled)
262747
+ return;
262748
+ setRegistryStatus("error");
262749
+ setAvailablePackages([]);
262750
+ });
262751
+ return () => {
262752
+ cancelled = true;
262753
+ };
262754
+ }, [client]);
262755
+ const fetchPackages = useCallback31(async (query) => {
262756
+ if (!client)
262757
+ return [];
262758
+ const lowerQuery = query.toLowerCase();
262759
+ return availablePackages.filter((pkg) => pkg.name.toLowerCase().includes(lowerQuery) || pkg.description?.toLowerCase().includes(lowerQuery));
262760
+ }, [client, availablePackages]);
262761
+ return {
262762
+ registries: registries2,
262763
+ selectedRegistryId,
262764
+ registryStatus,
262765
+ effectiveRegistryUrl,
262766
+ customRegistryUrl,
262767
+ availablePackages,
262768
+ setSelectedRegistryId,
262769
+ setCustomRegistryUrl,
262770
+ fetchPackages
262771
+ };
262772
+ }
262773
+ var STORAGE_KEY = "ph-connect-registry-selection";
262774
+ var init_use_registry = __esm(() => {
262775
+ init_connect_config();
262776
+ init_src2();
262777
+ });
262778
+
262327
262779
  // src/components/modal/modals/settings/package-manager.tsx
262328
- import { PH_PACKAGES } from "@powerhousedao/config";
262329
262780
  import { PackageManager } from "@powerhousedao/design-system/connect";
262330
- import { useCallback as useCallback33, useEffect as useEffect45, useMemo as useMemo15, useState as useState37 } from "react";
262781
+ import { useCallback as useCallback33, useMemo as useMemo16 } from "react";
262331
262782
  import { jsxDEV as jsxDEV24 } from "react/jsx-dev-runtime";
262332
- var LOCAL_REACTOR_VALUE = "local-reactor", LOCAL_REACTOR_LABEL = "Local Reactor", PH_PACKAGES_REGISTRY, ConnectPackageManager = () => {
262783
+ function toPackageDetails(pkg, removable) {
262784
+ return {
262785
+ id: pkg.id,
262786
+ name: pkg.name,
262787
+ description: pkg.description,
262788
+ category: pkg.category,
262789
+ publisher: pkg.author.name,
262790
+ publisherUrl: pkg.author.website ?? "",
262791
+ modules: Object.values(pkg.modules).flatMap((modules) => modules.map((module) => module.name)),
262792
+ removable
262793
+ };
262794
+ }
262795
+ var ConnectPackageManager = () => {
262333
262796
  const packageManager = useVetraPackageManager();
262334
262797
  const vetraPackages = useVetraPackages();
262335
- const drives = useDrives();
262336
- const [reactor3, setReactor] = useState37("");
262337
- const reactorOptions = useMemo15(() => {
262338
- return drives?.reduce((acc, drive) => {
262339
- const trigger = drive.state.local.triggers.find((trigger2) => trigger2.data?.url);
262340
- if (!trigger?.data?.url) {
262341
- return acc;
262342
- }
262343
- const value = trigger.data.url;
262344
- const label = drive.state.global.name;
262345
- acc.push({
262346
- value,
262347
- label,
262348
- disabled: true
262349
- });
262350
- return acc;
262351
- }, [
262352
- {
262353
- value: LOCAL_REACTOR_VALUE,
262354
- label: LOCAL_REACTOR_LABEL,
262355
- disabled: false
262356
- }
262357
- ]);
262358
- }, [drives]);
262359
- useEffect45(() => {
262360
- setReactor((reactor4) => {
262361
- const defaultOption = reactorOptions?.find((option) => !option.disabled);
262362
- if (reactor4 && reactorOptions?.find((option) => option.value === reactor4)) {
262363
- return reactor4;
262798
+ const {
262799
+ registries: registries2,
262800
+ selectedRegistryId,
262801
+ registryStatus,
262802
+ effectiveRegistryUrl,
262803
+ customRegistryUrl,
262804
+ setSelectedRegistryId,
262805
+ setCustomRegistryUrl,
262806
+ fetchPackages
262807
+ } = useRegistry();
262808
+ const packagesInfo = useMemo16(() => vetraPackages.map((pkg) => makeVetraPackageManifest(pkg)), [vetraPackages]);
262809
+ const { preInstalledPackages, installedPackages } = useMemo16(() => {
262810
+ const localIds = packageManager?.localPackageIds ?? new Set;
262811
+ const preInstalled = [];
262812
+ const installed = [];
262813
+ for (const pkg of packagesInfo) {
262814
+ const isLocal = localIds.has(pkg.id);
262815
+ if (isLocal) {
262816
+ preInstalled.push(toPackageDetails(pkg, false));
262364
262817
  } else {
262365
- return defaultOption?.value ?? "";
262818
+ installed.push(toPackageDetails(pkg, true));
262366
262819
  }
262367
- });
262368
- }, [reactor3, reactorOptions]);
262369
- const packagesInfo = useMemo15(() => vetraPackages.map((pkg) => makeVetraPackageManifest(pkg)), [vetraPackages]);
262370
- const handleReactorChange = useCallback33((reactor4) => setReactor(reactor4 ?? ""), []);
262820
+ }
262821
+ return { preInstalledPackages: preInstalled, installedPackages: installed };
262822
+ }, [packagesInfo, packageManager]);
262371
262823
  const handleInstall = useCallback33((packageName) => {
262372
- if (reactor3 !== LOCAL_REACTOR_VALUE) {
262373
- throw new Error("Cannot install external package on a remote reactor");
262824
+ if (!effectiveRegistryUrl) {
262825
+ throw new Error("No registry selected");
262374
262826
  }
262375
- return packageManager?.addPackage(packageName, PH_PACKAGES_REGISTRY);
262376
- }, [reactor3, packageManager]);
262827
+ return packageManager?.addPackage(packageName, effectiveRegistryUrl);
262828
+ }, [effectiveRegistryUrl, packageManager]);
262377
262829
  const handleUninstall = useCallback33((packageId) => {
262378
- if (reactor3 !== LOCAL_REACTOR_VALUE) {
262379
- throw new Error("Cannot delete external package on a remote reactor");
262380
- }
262381
262830
  const pkg = packagesInfo.find((p3) => p3.id === packageId);
262382
262831
  if (!pkg) {
262383
262832
  throw new Error(`Package with id ${packageId} not found`);
262384
262833
  }
262385
262834
  packageManager?.removePackage(pkg.name).catch(console.error);
262386
- }, [reactor3, packageManager, packagesInfo]);
262835
+ }, [packageManager, packagesInfo]);
262387
262836
  return /* @__PURE__ */ jsxDEV24(PackageManager, {
262388
262837
  mutable: true,
262389
- reactorOptions: reactorOptions ?? [],
262390
- reactor: reactor3,
262391
- packages: packagesInfo.map((pkg) => ({
262392
- id: pkg.id,
262393
- name: pkg.name,
262394
- description: pkg.description,
262395
- category: pkg.category,
262396
- publisher: pkg.author.name,
262397
- publisherUrl: pkg.author.website ?? "",
262398
- modules: Object.values(pkg.modules).flatMap((modules) => modules.map((module) => module.name)),
262399
- removable: true
262400
- })),
262401
- onReactorChange: handleReactorChange,
262838
+ registries: registries2,
262839
+ selectedRegistryId,
262840
+ onRegistryChange: setSelectedRegistryId,
262841
+ registryStatus,
262842
+ customRegistryUrl,
262843
+ onCustomRegistryUrlChange: setCustomRegistryUrl,
262844
+ packages: installedPackages,
262845
+ availablePackages: preInstalledPackages,
262402
262846
  onInstall: handleInstall,
262403
262847
  onUninstall: handleUninstall,
262404
- packageOptions: PH_PACKAGES
262848
+ fetchPackages
262405
262849
  }, undefined, false, undefined, this);
262406
262850
  };
262407
262851
  var init_package_manager = __esm(() => {
262408
- init_connect_config();
262409
262852
  init_src2();
262410
- PH_PACKAGES_REGISTRY = connectConfig.packagesRegistry ?? "http://localhost:8080/-/cdn/";
262853
+ init_use_registry();
262411
262854
  });
262412
262855
 
262413
262856
  // src/components/modal/modals/SettingsModal.tsx
@@ -262417,7 +262860,7 @@ __export(exports_SettingsModal, {
262417
262860
  });
262418
262861
  import { Icon as Icon2 } from "@powerhousedao/design-system";
262419
262862
  import { SettingsModal as SettingsModalV2 } from "@powerhousedao/design-system/connect";
262420
- import { useMemo as useMemo16 } from "react";
262863
+ import { useMemo as useMemo17 } from "react";
262421
262864
  import { jsxDEV as jsxDEV25 } from "react/jsx-dev-runtime";
262422
262865
  var SettingsModal = () => {
262423
262866
  const phModal = usePHModal();
@@ -262425,7 +262868,7 @@ var SettingsModal = () => {
262425
262868
  function onRefresh() {
262426
262869
  window.location.reload();
262427
262870
  }
262428
- const tabs = useMemo16(() => [
262871
+ const tabs = useMemo17(() => [
262429
262872
  {
262430
262873
  id: "package-manager",
262431
262874
  icon: /* @__PURE__ */ jsxDEV25(Icon2, {
@@ -262698,18 +263141,59 @@ var init_useDbExplorer = __esm(() => {
262698
263141
  ];
262699
263142
  });
262700
263143
 
263144
+ // src/components/modal/modals/InspectorModal/useProcessorsInspector.ts
263145
+ import { useCallback as useCallback36, useMemo as useMemo18 } from "react";
263146
+ function useProcessorsInspector() {
263147
+ const reactorClientModule = useReactorClientModule2();
263148
+ const processorManager = reactorClientModule?.reactorModule?.processorManager;
263149
+ const hasProcessorManager = useMemo18(() => processorManager != null, [processorManager]);
263150
+ const getProcessors = useCallback36(async () => {
263151
+ if (!processorManager) {
263152
+ return [];
263153
+ }
263154
+ return processorManager.getAll().map((tracked) => ({
263155
+ processorId: tracked.processorId,
263156
+ factoryId: tracked.factoryId,
263157
+ driveId: tracked.driveId,
263158
+ processorIndex: tracked.processorIndex,
263159
+ lastOrdinal: tracked.lastOrdinal,
263160
+ status: tracked.status,
263161
+ lastError: tracked.lastError,
263162
+ lastErrorTimestamp: tracked.lastErrorTimestamp
263163
+ }));
263164
+ }, [processorManager]);
263165
+ const onRetry = useCallback36(async (processorId) => {
263166
+ if (!processorManager)
263167
+ return;
263168
+ const tracked = processorManager.get(processorId);
263169
+ if (tracked) {
263170
+ await tracked.retry();
263171
+ }
263172
+ }, [processorManager]);
263173
+ if (!hasProcessorManager) {
263174
+ return;
263175
+ }
263176
+ return {
263177
+ getProcessors,
263178
+ onRetry
263179
+ };
263180
+ }
263181
+ var init_useProcessorsInspector = __esm(() => {
263182
+ init_connect2();
263183
+ });
263184
+
262701
263185
  // src/components/modal/modals/InspectorModal/useQueueInspector.ts
262702
- import { useCallback as useCallback36, useMemo as useMemo17 } from "react";
263186
+ import { useCallback as useCallback37, useMemo as useMemo19 } from "react";
262703
263187
  function useQueueInspector() {
262704
263188
  const reactorClientModule = useReactorClientModule2();
262705
263189
  const queue = reactorClientModule?.reactorModule?.queue;
262706
- const inMemoryQueue = useMemo17(() => {
263190
+ const inMemoryQueue = useMemo19(() => {
262707
263191
  if (queue instanceof InMemoryQueue) {
262708
263192
  return queue;
262709
263193
  }
262710
263194
  return;
262711
263195
  }, [queue]);
262712
- const getQueueState = useCallback36(async () => {
263196
+ const getQueueState = useCallback37(async () => {
262713
263197
  if (!inMemoryQueue) {
262714
263198
  return {
262715
263199
  isPaused: false,
@@ -262738,12 +263222,12 @@ function useQueueInspector() {
262738
263222
  totalExecuting: executingJobs.length
262739
263223
  };
262740
263224
  }, [inMemoryQueue]);
262741
- const onPause = useCallback36(async () => {
263225
+ const onPause = useCallback37(async () => {
262742
263226
  if (inMemoryQueue) {
262743
263227
  inMemoryQueue.pause();
262744
263228
  }
262745
263229
  }, [inMemoryQueue]);
262746
- const onResume = useCallback36(async () => {
263230
+ const onResume = useCallback37(async () => {
262747
263231
  if (inMemoryQueue) {
262748
263232
  await inMemoryQueue.resume();
262749
263233
  }
@@ -262763,19 +263247,21 @@ var init_useQueueInspector = __esm(() => {
262763
263247
  });
262764
263248
 
262765
263249
  // src/components/modal/modals/InspectorModal/useRemotesInspector.ts
262766
- import { useCallback as useCallback37 } from "react";
263250
+ import { useCallback as useCallback38 } from "react";
262767
263251
  function useRemotesInspector() {
262768
263252
  const syncManager = useSync2();
262769
263253
  if (!syncManager) {
262770
263254
  throw new Error("Sync manager not found");
262771
263255
  }
262772
- const getRemotes = useCallback37(() => {
263256
+ const connectionStates = useConnectionStates2();
263257
+ const getRemotes = useCallback38(() => {
262773
263258
  return Promise.resolve(syncManager.list());
262774
263259
  }, [syncManager]);
262775
- const removeRemote = useCallback37((name6) => syncManager.remove(name6), [syncManager]);
263260
+ const removeRemote = useCallback38((name6) => syncManager.remove(name6), [syncManager]);
262776
263261
  return {
262777
263262
  getRemotes,
262778
- removeRemote
263263
+ removeRemote,
263264
+ connectionStates
262779
263265
  };
262780
263266
  }
262781
263267
  var init_useRemotesInspector = __esm(() => {
@@ -262789,8 +263275,9 @@ var DEFAULT_PAGE_SIZE = 25, InspectorModal = () => {
262789
263275
  const phModal = usePHModal();
262790
263276
  const open = phModal?.type === "inspector";
262791
263277
  const { getTables, getTableRows, getDefaultSort, onExportDb, onImportDb } = useDbExplorer();
262792
- const { getRemotes, removeRemote } = useRemotesInspector();
263278
+ const { getRemotes, removeRemote, connectionStates } = useRemotesInspector();
262793
263279
  const queueInspectorProps = useQueueInspector();
263280
+ const processorsInspectorProps = useProcessorsInspector();
262794
263281
  return /* @__PURE__ */ jsxDEV27(ConnectInspectorModal, {
262795
263282
  open,
262796
263283
  onOpenChange: (status) => {
@@ -262808,15 +263295,18 @@ var DEFAULT_PAGE_SIZE = 25, InspectorModal = () => {
262808
263295
  },
262809
263296
  remotesInspectorProps: {
262810
263297
  getRemotes,
262811
- removeRemote
263298
+ removeRemote,
263299
+ connectionStates
262812
263300
  },
262813
- queueInspectorProps
263301
+ queueInspectorProps,
263302
+ processorsInspectorProps
262814
263303
  }, undefined, false, undefined, this);
262815
263304
  };
262816
263305
  var init_InspectorModal = __esm(() => {
262817
263306
  init_src2();
262818
263307
  init_src2();
262819
263308
  init_useDbExplorer();
263309
+ init_useProcessorsInspector();
262820
263310
  init_useQueueInspector();
262821
263311
  init_useRemotesInspector();
262822
263312
  });
@@ -262866,7 +263356,7 @@ var SentryProvider = ({ children }) => {
262866
263356
  // src/components/analytics.tsx
262867
263357
  init_connect_config();
262868
263358
  init_hooks();
262869
- import { useEffect as useEffect17 } from "react";
263359
+ import { useEffect as useEffect18 } from "react";
262870
263360
  function gtag(...args) {
262871
263361
  window.dataLayer?.push(...args);
262872
263362
  }
@@ -262874,7 +263364,7 @@ var Analytics = () => {
262874
263364
  const gaTrackingId = connectConfig.gaTrackingId;
262875
263365
  const [{ analytics }] = useAcceptedCookies();
262876
263366
  const useAnalytics = gaTrackingId && analytics;
262877
- useEffect17(() => {
263367
+ useEffect18(() => {
262878
263368
  if (useAnalytics) {
262879
263369
  const script = document.createElement("script");
262880
263370
  script.src = `https://www.googletagmanager.com/gtag/js?id=${gaTrackingId}`;
@@ -262900,14 +263390,14 @@ import {
262900
263390
  ConnectSidebar,
262901
263391
  HomeScreen
262902
263392
  } from "@powerhousedao/design-system/connect";
262903
- import { useEffect as useEffect18, useState as useState15 } from "react";
263393
+ import { useEffect as useEffect19, useState as useState16 } from "react";
262904
263394
  import { jsxDEV as jsxDEV8 } from "react/jsx-dev-runtime";
262905
263395
  var LOADER_DELAY = 250;
262906
263396
  var Loader = ({ delay = LOADER_DELAY }) => {
262907
263397
  const isSSR = typeof window === "undefined";
262908
263398
  const showInitialLoader = typeof document !== "undefined" && document.body.getAttribute("data-show-loader") === "true";
262909
- const [showLoading, setShowLoading] = useState15(!delay || showInitialLoader);
262910
- useEffect18(() => {
263399
+ const [showLoading, setShowLoading] = useState16(!delay || showInitialLoader);
263400
+ useEffect19(() => {
262911
263401
  const id = setTimeout(() => {
262912
263402
  setShowLoading(true);
262913
263403
  }, delay);
@@ -262972,7 +263462,7 @@ import { lazy as lazy7, Suspense as Suspense4 } from "react";
262972
263462
  import { childLogger as childLogger2 } from "document-drive";
262973
263463
 
262974
263464
  // ../../node_modules/.pnpm/react-error-boundary@4.1.2_react@19.2.4/node_modules/react-error-boundary/dist/react-error-boundary.development.esm.js
262975
- import { createContext as createContext5, Component as Component4, createElement as createElement10, useContext as useContext6, useState as useState16, useMemo as useMemo8, forwardRef as forwardRef2 } from "react";
263465
+ import { createContext as createContext5, Component as Component4, createElement as createElement10, useContext as useContext6, useState as useState17, useMemo as useMemo8, forwardRef as forwardRef2 } from "react";
262976
263466
  "use client";
262977
263467
  var ErrorBoundaryContext = createContext5(null);
262978
263468
  var initialState = {
@@ -263259,10 +263749,10 @@ import {
263259
263749
  ToastContainer as ToastContainer2,
263260
263750
  WagmiContext
263261
263751
  } from "@powerhousedao/design-system/connect";
263262
- import { useEffect as useEffect46 } from "react";
263752
+ import { useEffect as useEffect49 } from "react";
263263
263753
  import { jsxDEV as jsxDEV30 } from "react/jsx-dev-runtime";
263264
263754
  var App = () => {
263265
- useEffect46(() => {
263755
+ useEffect49(() => {
263266
263756
  const handlePreloadError = () => {
263267
263757
  console.log("Outdated chunks detected, reloading page...");
263268
263758
  window.location.reload();
@@ -263272,7 +263762,7 @@ var App = () => {
263272
263762
  window.removeEventListener("vite:preloadError", handlePreloadError);
263273
263763
  };
263274
263764
  }, []);
263275
- useEffect46(() => {
263765
+ useEffect49(() => {
263276
263766
  if (import.meta.env.MODE === "development") {
263277
263767
  window.documentEditorDebugTools = new DocumentEditorDebugTools;
263278
263768
  } else {
@@ -263373,12 +263863,12 @@ var CookieBanner = () => {
263373
263863
  // src/components/document-editor-container.tsx
263374
263864
  init_services();
263375
263865
  init_src2();
263376
- import { useCallback as useCallback38, useMemo as useMemo18 } from "react";
263866
+ import { useCallback as useCallback39, useMemo as useMemo20 } from "react";
263377
263867
  import { jsxDEV as jsxDEV32 } from "react/jsx-dev-runtime";
263378
263868
  function DocumentEditorContainer() {
263379
263869
  const [selectedDocument] = useSelectedDocument();
263380
263870
  const parentFolder = useNodeParentFolderById(selectedDocument.header.id);
263381
- const onExport = useCallback38(() => {
263871
+ const onExport = useCallback39(() => {
263382
263872
  const validationErrors = validateDocument(selectedDocument);
263383
263873
  if (validationErrors.length) {
263384
263874
  showPHModal({
@@ -263393,10 +263883,10 @@ function DocumentEditorContainer() {
263393
263883
  });
263394
263884
  }
263395
263885
  }, [selectedDocument]);
263396
- const onOpenSwitchboardLink = useMemo18(() => {
263886
+ const onOpenSwitchboardLink = useMemo20(() => {
263397
263887
  return async () => {};
263398
263888
  }, []);
263399
- const onClose = useCallback38(() => {
263889
+ const onClose = useCallback39(() => {
263400
263890
  setSelectedNode(parentFolder);
263401
263891
  }, [parentFolder, setSelectedNode]);
263402
263892
  return /* @__PURE__ */ jsxDEV32("div", {
@@ -263412,11 +263902,11 @@ function DocumentEditorContainer() {
263412
263902
  }, undefined, false, undefined, this);
263413
263903
  }
263414
263904
  // src/components/dots-loader.tsx
263415
- import { useEffect as useEffect47, useState as useState38 } from "react";
263905
+ import { useEffect as useEffect50, useState as useState41 } from "react";
263416
263906
  import { jsxDEV as jsxDEV33 } from "react/jsx-dev-runtime";
263417
263907
  var DotsLoader = () => {
263418
- const [dots, setDots] = useState38(0);
263419
- useEffect47(() => {
263908
+ const [dots, setDots] = useState41(0);
263909
+ useEffect50(() => {
263420
263910
  const id = setInterval(() => {
263421
263911
  setDots((dots2) => dots2 === 3 ? 0 : dots2 + 1);
263422
263912
  }, 200);
@@ -263436,11 +263926,11 @@ import { Suspense as Suspense6 } from "react";
263436
263926
 
263437
263927
  // src/components/editor-loader.tsx
263438
263928
  import { DefaultEditorLoader } from "@powerhousedao/design-system/connect";
263439
- import { useEffect as useEffect48, useState as useState39 } from "react";
263929
+ import { useEffect as useEffect51, useState as useState42 } from "react";
263440
263930
  import { jsxDEV as jsxDEV34, Fragment as Fragment7 } from "react/jsx-dev-runtime";
263441
263931
  function EditorLoader(props) {
263442
- const [showLoading, setShowLoading] = useState39(false);
263443
- useEffect48(() => {
263932
+ const [showLoading, setShowLoading] = useState42(false);
263933
+ useEffect51(() => {
263444
263934
  setTimeout(() => {
263445
263935
  setShowLoading(true);
263446
263936
  }, props.loadingTimeout ?? 200);
@@ -263487,13 +263977,13 @@ function DriveEditorContainer() {
263487
263977
  init_src2();
263488
263978
  init_connect2();
263489
263979
  import { Icon as Icon3 } from "@powerhousedao/design-system";
263490
- import { useMemo as useMemo19 } from "react";
263980
+ import { useMemo as useMemo21 } from "react";
263491
263981
  import { jsxDEV as jsxDEV36 } from "react/jsx-dev-runtime";
263492
263982
  function DriveIcon({
263493
263983
  drive
263494
263984
  }) {
263495
263985
  const remotes = useSyncList2();
263496
- const isRemoteDrive = useMemo19(() => {
263986
+ const isRemoteDrive = useMemo21(() => {
263497
263987
  if (!drive)
263498
263988
  return false;
263499
263989
  return remotes.some((remote) => remote.collectionId === driveCollectionId("main", drive.header.id));
@@ -263524,7 +264014,7 @@ init_services();
263524
264014
  init_src2();
263525
264015
  import { RevisionHistory } from "@powerhousedao/design-system/connect";
263526
264016
  import { redo as redo2, undo as undo2 } from "document-model/core";
263527
- import { Suspense as Suspense7, useEffect as useEffect49, useState as useState40 } from "react";
264017
+ import { Suspense as Suspense7, useEffect as useEffect53, useState as useState43 } from "react";
263528
264018
  import { jsxDEV as jsxDEV37 } from "react/jsx-dev-runtime";
263529
264019
  function EditorError({ message }) {
263530
264020
  return /* @__PURE__ */ jsxDEV37("div", {
@@ -263555,7 +264045,7 @@ var DocumentEditor = (props) => {
263555
264045
  isLoading: isLoadingOperations,
263556
264046
  refetch: refetchOperations
263557
264047
  } = useDocumentOperations(documentId);
263558
- useEffect49(() => {
264048
+ useEffect53(() => {
263559
264049
  if (revisionHistoryVisible) {
263560
264050
  refetchOperations();
263561
264051
  }
@@ -263578,13 +264068,13 @@ var DocumentEditor = (props) => {
263578
264068
  canUndo,
263579
264069
  canRedo
263580
264070
  });
263581
- useEffect49(() => {
264071
+ useEffect53(() => {
263582
264072
  return () => {
263583
264073
  window.documentEditorDebugTools?.clear();
263584
264074
  };
263585
264075
  }, []);
263586
- const [editorError, setEditorError] = useState40(undefined);
263587
- useEffect49(() => {
264076
+ const [editorError, setEditorError] = useState43(undefined);
264077
+ useEffect53(() => {
263588
264078
  if (editorError && editorError.documentId !== documentId) {
263589
264079
  setEditorError(undefined);
263590
264080
  }
@@ -263963,18 +264453,18 @@ import {
263963
264453
  HomeScreenAddDriveItem,
263964
264454
  HomeScreenItem
263965
264455
  } from "@powerhousedao/design-system/connect";
263966
- import { useEffect as useEffect50 } from "react";
264456
+ import { useEffect as useEffect55 } from "react";
263967
264457
  import { jsxDEV as jsxDEV43 } from "react/jsx-dev-runtime";
263968
264458
  function Content2() {
263969
264459
  const [selectedDrive] = useSelectedDriveSafe();
263970
264460
  const selectedFolder = useSelectedFolder();
263971
264461
  const selectedDocumentId = useSelectedDocumentId();
263972
- useEffect50(() => {
264462
+ useEffect55(() => {
263973
264463
  if (!selectedDocumentId) {
263974
264464
  setPHDocumentEditorConfig(defaultPHDocumentEditorConfig);
263975
264465
  }
263976
264466
  }, [selectedDocumentId]);
263977
- useEffect50(() => {
264467
+ useEffect55(() => {
263978
264468
  if (!selectedDrive) {
263979
264469
  setPHDriveEditorConfig(defaultPHDriveEditorConfig);
263980
264470
  }
@@ -264569,13 +265059,13 @@ var gql = (chunks, ...variables) => {
264569
265059
  };
264570
265060
  // src/pages/demo/atlas-import.tsx
264571
265061
  init_dist4();
264572
- import { useCallback as useCallback39, useEffect as useEffect51, useMemo as useMemo20, useRef as useRef31, useState as useState41 } from "react";
265062
+ import { useCallback as useCallback40, useEffect as useEffect56, useMemo as useMemo23, useRef as useRef33, useState as useState44 } from "react";
264573
265063
  import { jsxDEV as jsxDEV44, Fragment as Fragment8 } from "react/jsx-dev-runtime";
264574
265064
  var REACTOR_URL = "https://apps.powerhouse.io/sky-atlas/staging/switchboard";
264575
265065
  var MIN_LOADING_TIME = 2000;
264576
265066
  function useReactorUrl() {
264577
265067
  const { search } = useLocation();
264578
- return useMemo20(() => {
265068
+ return useMemo23(() => {
264579
265069
  const params = new URLSearchParams(search);
264580
265070
  const url2 = params.get("reactorUrl") ?? REACTOR_URL;
264581
265071
  return url2.endsWith("/") ? url2 : `${url2}/`;
@@ -264590,16 +265080,16 @@ async function forkAtlas(docId, reactorUrl) {
264590
265080
  return await request(`${reactorUrl}graphql`, document2, { docId });
264591
265081
  }
264592
265082
  function AtlasImport() {
264593
- const status = useRef31("initial");
265083
+ const status = useRef33("initial");
264594
265084
  const reactor3 = useReactorClient2();
264595
265085
  const { documentId } = useParams();
264596
265086
  const reactorUrl = useReactorUrl();
264597
265087
  const navigate = useNavigate();
264598
- const [driveId, setDriveId] = useState41(undefined);
264599
- const [error50, setError] = useState41(undefined);
264600
- const [loading, setLoading3] = useState41(true);
265088
+ const [driveId, setDriveId] = useState44(undefined);
265089
+ const [error50, setError] = useState44(undefined);
265090
+ const [loading, setLoading3] = useState44(true);
264601
265091
  const hasError = status.current === "error";
264602
- useEffect51(() => {
265092
+ useEffect56(() => {
264603
265093
  if (error50) {
264604
265094
  console.error("Error forking Atlas:", error50);
264605
265095
  toast("Error forking Atlas", { type: "error" });
@@ -264611,12 +265101,12 @@ function AtlasImport() {
264611
265101
  status.current = "forked";
264612
265102
  setDriveId(driveId2);
264613
265103
  }
264614
- const redirectToDrive = useCallback39(() => {
265104
+ const redirectToDrive = useCallback40(() => {
264615
265105
  if (driveId && !loading) {
264616
265106
  navigate(`/d/${driveId}`, { replace: true });
264617
265107
  }
264618
265108
  }, [driveId, navigate, loading]);
264619
- const addForkDrive = useCallback39(async (driveId2) => {
265109
+ const addForkDrive = useCallback40(async (driveId2) => {
264620
265110
  console.log("Adding remote drive:", driveId2);
264621
265111
  const driveUrl = `${reactorUrl}d/${driveId2}`;
264622
265112
  try {
@@ -264655,7 +265145,7 @@ function AtlasImport() {
264655
265145
  setError(error51);
264656
265146
  }
264657
265147
  }, [addRemoteDrive, navigate, reactorUrl]);
264658
- useEffect51(() => {
265148
+ useEffect56(() => {
264659
265149
  if (!documentId || status.current !== "initial")
264660
265150
  return;
264661
265151
  status.current = "forking";
@@ -264664,7 +265154,7 @@ function AtlasImport() {
264664
265154
  setError(error51);
264665
265155
  });
264666
265156
  }, [documentId, status]);
264667
- useEffect51(() => {
265157
+ useEffect56(() => {
264668
265158
  if (!driveId || !reactor3 || status.current !== "forked")
264669
265159
  return;
264670
265160
  status.current = "addingDrive";