@fortemi/core 2026.6.0 → 2026.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -150,6 +150,103 @@ async function createPGliteInstance(persistence, archiveName = "default") {
150
150
  return db;
151
151
  }
152
152
 
153
+ // src/worker/worker-client.ts
154
+ var PGliteWorkerClient = class {
155
+ constructor(worker) {
156
+ this.worker = worker;
157
+ this.readyPromise = new Promise((resolve) => {
158
+ this.resolveReady = resolve;
159
+ });
160
+ this.worker.addEventListener("message", (e) => {
161
+ const msg = e.data;
162
+ if (msg.type === "READY") {
163
+ this.resolveReady();
164
+ return;
165
+ }
166
+ if (!("id" in msg)) return;
167
+ const pending = this.pending.get(msg.id);
168
+ if (!pending) return;
169
+ this.pending.delete(msg.id);
170
+ if (msg.type === "ERROR") {
171
+ pending.reject(new Error(msg.error));
172
+ } else {
173
+ pending.resolve(msg);
174
+ }
175
+ });
176
+ }
177
+ pending = /* @__PURE__ */ new Map();
178
+ readyPromise;
179
+ resolveReady;
180
+ /** Resolves when the worker broadcasts READY after database initialisation. */
181
+ async waitReady() {
182
+ return this.readyPromise;
183
+ }
184
+ send(request) {
185
+ const id = generateId();
186
+ return new Promise((resolve, reject) => {
187
+ this.pending.set(id, {
188
+ resolve,
189
+ reject
190
+ });
191
+ this.worker.postMessage({ ...request, id });
192
+ });
193
+ }
194
+ async query(sql, params) {
195
+ const resp = await this.send({ type: "QUERY", sql, params });
196
+ return { rows: resp.rows, fields: resp.fields };
197
+ }
198
+ async exec(sql) {
199
+ await this.send({ type: "EXEC", sql });
200
+ }
201
+ async transaction(fn) {
202
+ const resp = await this.send({ type: "BEGIN" });
203
+ const txId = resp.txId;
204
+ const proxy = new TransactionProxy(this, txId);
205
+ try {
206
+ const result = await fn(proxy);
207
+ await this.send({ type: "COMMIT", txId });
208
+ return result;
209
+ } catch (err) {
210
+ await this.send({ type: "ROLLBACK", txId }).catch(() => {
211
+ });
212
+ throw err;
213
+ }
214
+ }
215
+ /** Forward TX_QUERY for TransactionProxy — not part of the public surface. */
216
+ async _txQuery(txId, sql, params) {
217
+ const resp = await this.send({
218
+ type: "TX_QUERY",
219
+ txId,
220
+ sql,
221
+ params
222
+ });
223
+ return { rows: resp.rows };
224
+ }
225
+ /** Forward TX_EXEC for TransactionProxy — not part of the public surface. */
226
+ async _txExec(txId, sql) {
227
+ await this.send({ type: "TX_EXEC", txId, sql });
228
+ }
229
+ async ping() {
230
+ await this.send({ type: "PING" });
231
+ }
232
+ async close() {
233
+ await this.send({ type: "CLOSE" });
234
+ this.worker.terminate();
235
+ }
236
+ };
237
+ var TransactionProxy = class {
238
+ constructor(client, txId) {
239
+ this.client = client;
240
+ this.txId = txId;
241
+ }
242
+ async query(sql, params) {
243
+ return this.client._txQuery(this.txId, sql, params);
244
+ }
245
+ async exec(sql) {
246
+ return this.client._txExec(this.txId, sql);
247
+ }
248
+ };
249
+
153
250
  // src/storage-backend.ts
154
251
  var PGliteStorageBackend = class {
155
252
  constructor(id, db) {
@@ -177,6 +274,41 @@ var PGliteStorageBackendFactory = class {
177
274
  }
178
275
  };
179
276
  var defaultStorageBackendFactory = new PGliteStorageBackendFactory();
277
+ var PGliteWorkerStorageBackend = class {
278
+ constructor(id, client) {
279
+ this.id = id;
280
+ this.client = client;
281
+ }
282
+ mode = "readwrite";
283
+ query(sql, params) {
284
+ return this.client.query(sql, params);
285
+ }
286
+ exec(sql) {
287
+ return this.client.exec(sql);
288
+ }
289
+ transaction(fn) {
290
+ return this.client.transaction(fn);
291
+ }
292
+ close() {
293
+ return this.client.close();
294
+ }
295
+ };
296
+ var PGliteWorkerStorageBackendFactory = class {
297
+ constructor(options) {
298
+ this.options = options;
299
+ }
300
+ async open(input) {
301
+ const worker = this.options.createWorker();
302
+ const client = new PGliteWorkerClient(worker);
303
+ worker.postMessage({
304
+ type: "INIT",
305
+ persistence: input.persistence,
306
+ archiveName: input.archiveName
307
+ });
308
+ await client.waitReady();
309
+ return new PGliteWorkerStorageBackend(`pglite-worker:${input.persistence}:${input.archiveName}`, client);
310
+ }
311
+ };
180
312
 
181
313
  // src/capability-manager.ts
182
314
  var VALID_TRANSITIONS = {
@@ -799,13 +931,13 @@ var allMigrations = [
799
931
 
800
932
  // src/archive-manager.ts
801
933
  var ArchiveManager = class {
802
- constructor(persistenceOrFactory, events) {
934
+ constructor(persistenceOrFactory, events, persistenceOverride) {
803
935
  this.events = events;
804
936
  if (typeof persistenceOrFactory === "string") {
805
937
  this.persistence = persistenceOrFactory;
806
938
  this.backendFactory = defaultStorageBackendFactory;
807
939
  } else {
808
- this.persistence = "memory";
940
+ this.persistence = persistenceOverride ?? "memory";
809
941
  this.backendFactory = persistenceOrFactory;
810
942
  }
811
943
  this.archives.set("default", {
@@ -1170,103 +1302,6 @@ function createBlobStore(archiveName) {
1170
1302
  return new IdbBlobStore(archiveName);
1171
1303
  }
1172
1304
 
1173
- // src/worker/worker-client.ts
1174
- var PGliteWorkerClient = class {
1175
- constructor(worker) {
1176
- this.worker = worker;
1177
- this.readyPromise = new Promise((resolve) => {
1178
- this.resolveReady = resolve;
1179
- });
1180
- this.worker.addEventListener("message", (e) => {
1181
- const msg = e.data;
1182
- if (msg.type === "READY") {
1183
- this.resolveReady();
1184
- return;
1185
- }
1186
- if (!("id" in msg)) return;
1187
- const pending = this.pending.get(msg.id);
1188
- if (!pending) return;
1189
- this.pending.delete(msg.id);
1190
- if (msg.type === "ERROR") {
1191
- pending.reject(new Error(msg.error));
1192
- } else {
1193
- pending.resolve(msg);
1194
- }
1195
- });
1196
- }
1197
- pending = /* @__PURE__ */ new Map();
1198
- readyPromise;
1199
- resolveReady;
1200
- /** Resolves when the worker broadcasts READY after database initialisation. */
1201
- async waitReady() {
1202
- return this.readyPromise;
1203
- }
1204
- send(request) {
1205
- const id = generateId();
1206
- return new Promise((resolve, reject) => {
1207
- this.pending.set(id, {
1208
- resolve,
1209
- reject
1210
- });
1211
- this.worker.postMessage({ ...request, id });
1212
- });
1213
- }
1214
- async query(sql, params) {
1215
- const resp = await this.send({ type: "QUERY", sql, params });
1216
- return { rows: resp.rows, fields: resp.fields };
1217
- }
1218
- async exec(sql) {
1219
- await this.send({ type: "EXEC", sql });
1220
- }
1221
- async transaction(fn) {
1222
- const resp = await this.send({ type: "BEGIN" });
1223
- const txId = resp.txId;
1224
- const proxy = new TransactionProxy(this, txId);
1225
- try {
1226
- const result = await fn(proxy);
1227
- await this.send({ type: "COMMIT", txId });
1228
- return result;
1229
- } catch (err) {
1230
- await this.send({ type: "ROLLBACK", txId }).catch(() => {
1231
- });
1232
- throw err;
1233
- }
1234
- }
1235
- /** Forward TX_QUERY for TransactionProxy — not part of the public surface. */
1236
- async _txQuery(txId, sql, params) {
1237
- const resp = await this.send({
1238
- type: "TX_QUERY",
1239
- txId,
1240
- sql,
1241
- params
1242
- });
1243
- return { rows: resp.rows };
1244
- }
1245
- /** Forward TX_EXEC for TransactionProxy — not part of the public surface. */
1246
- async _txExec(txId, sql) {
1247
- await this.send({ type: "TX_EXEC", txId, sql });
1248
- }
1249
- async ping() {
1250
- await this.send({ type: "PING" });
1251
- }
1252
- async close() {
1253
- await this.send({ type: "CLOSE" });
1254
- this.worker.terminate();
1255
- }
1256
- };
1257
- var TransactionProxy = class {
1258
- constructor(client, txId) {
1259
- this.client = client;
1260
- this.txId = txId;
1261
- }
1262
- async query(sql, params) {
1263
- return this.client._txQuery(this.txId, sql, params);
1264
- }
1265
- async exec(sql) {
1266
- return this.client._txExec(this.txId, sql);
1267
- }
1268
- };
1269
-
1270
1305
  // src/repositories/notes-repository.ts
1271
1306
  var NotesRepository = class {
1272
1307
  constructor(db, events) {
@@ -5171,6 +5206,33 @@ var FallbackRouter = class {
5171
5206
  }
5172
5207
  };
5173
5208
 
5209
+ // src/fortemi-bridge.ts
5210
+ function getFortemiBridge(host = globalThis) {
5211
+ return host?.fortemiBridge ?? null;
5212
+ }
5213
+ function getFortemiSecretStore(host = globalThis) {
5214
+ return host?.fortemiBridge?.secrets ?? host?.fortemiSecureStorage ?? null;
5215
+ }
5216
+ async function hasFortemiSecureSecrets(host = globalThis) {
5217
+ const bridge = getFortemiBridge(host);
5218
+ if (bridge) {
5219
+ try {
5220
+ const capabilities = await bridge.capabilities();
5221
+ if (!capabilities.secureSecrets) return false;
5222
+ return Boolean(await bridge.secrets.isAvailable());
5223
+ } catch {
5224
+ return false;
5225
+ }
5226
+ }
5227
+ const legacySecrets = host?.fortemiSecureStorage;
5228
+ if (!legacySecrets) return false;
5229
+ try {
5230
+ return Boolean(await legacySecrets.isAvailable());
5231
+ } catch {
5232
+ return false;
5233
+ }
5234
+ }
5235
+
5174
5236
  // src/security/plugin-content.ts
5175
5237
  var DEFAULT_DIRECTIVES = {
5176
5238
  "default-src": ["'self'"],
@@ -5827,25 +5889,52 @@ async function exportShard(db, options) {
5827
5889
  components.push("provenance_edges");
5828
5890
  counts.provenance_edges = filteredProvenanceRows.length;
5829
5891
  if (options?.includeEmbeddings) {
5830
- const embSetRows = await db.query(`SELECT * FROM embedding_set ORDER BY created_at`);
5892
+ const embeddingSetIds = options.embeddingSetIds?.filter(Boolean) ?? [];
5893
+ const setScoped = embeddingSetIds.length > 0;
5894
+ const embSetRows = await db.query(
5895
+ `SELECT * FROM embedding_set
5896
+ ${setScoped ? "WHERE id = ANY($1)" : ""}
5897
+ ORDER BY created_at`,
5898
+ setScoped ? [embeddingSetIds] : []
5899
+ );
5900
+ const exportedSetIds = new Set(embSetRows.rows.map((row) => row.id));
5831
5901
  const shardEmbSets = embSetRows.rows.map(embeddingSetToShard);
5832
5902
  files.set("embedding_sets.json", encoder.encode(JSON.stringify(shardEmbSets)));
5833
5903
  components.push("embedding_sets");
5834
5904
  counts.embedding_sets = shardEmbSets.length;
5835
- const embMemberRows = await db.query(`SELECT * FROM embedding_set_member`);
5836
- const membersJsonl = embMemberRows.rows.map((m) => JSON.stringify(embeddingSetMemberToShard(m))).join("\n");
5905
+ const embMemberRows = await db.query(
5906
+ `SELECT * FROM embedding_set_member
5907
+ ${setScoped ? "WHERE embedding_set_id = ANY($1)" : ""}`,
5908
+ setScoped ? [embeddingSetIds] : []
5909
+ );
5910
+ const scopedEmbMemberRows = embMemberRows.rows.filter(
5911
+ (member) => exportedSetIds.has(member.embedding_set_id) && exportedNoteIds.has(member.note_id)
5912
+ );
5913
+ const membersJsonl = scopedEmbMemberRows.map((m) => JSON.stringify(embeddingSetMemberToShard(m))).join("\n");
5837
5914
  files.set("embedding_set_members.jsonl", encoder.encode(membersJsonl));
5838
5915
  components.push("embedding_set_members");
5839
- counts.embedding_set_members = embMemberRows.rows.length;
5840
- const embRows = await db.query(`SELECT * FROM embedding ORDER BY created_at`);
5841
- const embJsonl = embRows.rows.map((e) => JSON.stringify(embeddingToShard(e))).join("\n");
5916
+ counts.embedding_set_members = scopedEmbMemberRows.length;
5917
+ const embRows = await db.query(
5918
+ `SELECT * FROM embedding
5919
+ ${setScoped ? "WHERE embedding_set_id = ANY($1)" : ""}
5920
+ ORDER BY created_at`,
5921
+ setScoped ? [embeddingSetIds] : []
5922
+ );
5923
+ const memberEmbeddingIds = new Set(scopedEmbMemberRows.map((member) => member.embedding_id));
5924
+ const scopedEmbRows = embRows.rows.filter(
5925
+ (embedding) => exportedSetIds.has(embedding.embedding_set_id) && exportedNoteIds.has(embedding.note_id) && (memberEmbeddingIds.size === 0 || memberEmbeddingIds.has(embedding.id))
5926
+ );
5927
+ const embJsonl = scopedEmbRows.map((e) => JSON.stringify(embeddingToShard(e))).join("\n");
5842
5928
  files.set("embeddings.jsonl", encoder.encode(embJsonl));
5843
5929
  components.push("embeddings");
5844
- counts.embeddings = embRows.rows.length;
5930
+ counts.embeddings = scopedEmbRows.length;
5845
5931
  }
5846
5932
  const graphSourceRows = await db.query(`SELECT * FROM graph_source ORDER BY created_at, id`);
5847
- if (graphSourceRows.rows.length > 0) {
5848
- const shardGraphSources = graphSourceRows.rows.map((row) => ({
5933
+ const graphScoped = !!options?.embeddingSetIds?.length;
5934
+ const scopedGraphSourceRows = graphScoped ? graphSourceRows.rows.filter((row) => !row.embedding_set_id || options.embeddingSetIds?.includes(row.embedding_set_id)) : graphSourceRows.rows;
5935
+ const exportedGraphSourceIds = new Set(scopedGraphSourceRows.map((row) => row.id));
5936
+ if (scopedGraphSourceRows.length > 0) {
5937
+ const shardGraphSources = scopedGraphSourceRows.map((row) => ({
5849
5938
  id: row.id,
5850
5939
  name: row.name,
5851
5940
  kind: row.kind,
@@ -5867,8 +5956,9 @@ async function exportShard(db, options) {
5867
5956
  counts.graph_sources = shardGraphSources.length;
5868
5957
  }
5869
5958
  const graphEdgeRows = await db.query(`SELECT * FROM graph_edge_artifact ORDER BY graph_source_id, from_note_id, to_note_id, kind`);
5870
- if (graphEdgeRows.rows.length > 0) {
5871
- const graphEdgesJsonl = graphEdgeRows.rows.map((row) => JSON.stringify({
5959
+ const scopedGraphEdgeRows = graphScoped ? graphEdgeRows.rows.filter((row) => exportedGraphSourceIds.has(row.graph_source_id)) : graphEdgeRows.rows;
5960
+ if (scopedGraphEdgeRows.length > 0) {
5961
+ const graphEdgesJsonl = scopedGraphEdgeRows.map((row) => JSON.stringify({
5872
5962
  graph_source_id: row.graph_source_id,
5873
5963
  from_note_id: row.from_note_id,
5874
5964
  to_note_id: row.to_note_id,
@@ -5879,18 +5969,21 @@ async function exportShard(db, options) {
5879
5969
  })).join("\n");
5880
5970
  files.set("graph_edges.jsonl", encoder.encode(graphEdgesJsonl));
5881
5971
  components.push("graph_edges");
5882
- counts.graph_edges = graphEdgeRows.rows.length;
5972
+ counts.graph_edges = scopedGraphEdgeRows.length;
5883
5973
  }
5884
5974
  const communitySetRows = await db.query(`SELECT * FROM community_set ORDER BY created_at, id`);
5885
5975
  const communityRows = await db.query(`SELECT * FROM community ORDER BY community_set_id, rank NULLS LAST, id`);
5886
- if (communitySetRows.rows.length > 0) {
5976
+ const scopedCommunitySetRows = graphScoped ? communitySetRows.rows.filter((row) => exportedGraphSourceIds.has(row.graph_source_id)) : communitySetRows.rows;
5977
+ const exportedCommunitySetIds = new Set(scopedCommunitySetRows.map((row) => row.id));
5978
+ const scopedCommunityRows = graphScoped ? communityRows.rows.filter((row) => exportedCommunitySetIds.has(row.community_set_id)) : communityRows.rows;
5979
+ if (scopedCommunitySetRows.length > 0) {
5887
5980
  const communitiesBySet = /* @__PURE__ */ new Map();
5888
- for (const row of communityRows.rows) {
5981
+ for (const row of scopedCommunityRows) {
5889
5982
  const rows = communitiesBySet.get(row.community_set_id) ?? [];
5890
5983
  rows.push(row);
5891
5984
  communitiesBySet.set(row.community_set_id, rows);
5892
5985
  }
5893
- const shardCommunitySets = communitySetRows.rows.map((row) => ({
5986
+ const shardCommunitySets = scopedCommunitySetRows.map((row) => ({
5894
5987
  id: row.id,
5895
5988
  graph_source_id: row.graph_source_id,
5896
5989
  name: row.name,
@@ -5913,11 +6006,12 @@ async function exportShard(db, options) {
5913
6006
  files.set("communities.json", encoder.encode(JSON.stringify(shardCommunitySets)));
5914
6007
  components.push("communities");
5915
6008
  counts.community_sets = shardCommunitySets.length;
5916
- counts.communities = communityRows.rows.length;
6009
+ counts.communities = scopedCommunityRows.length;
5917
6010
  }
5918
6011
  const assignmentRows = await db.query(`SELECT * FROM community_assignment ORDER BY community_set_id, community_id, note_id`);
5919
- if (assignmentRows.rows.length > 0) {
5920
- const assignmentsJsonl = assignmentRows.rows.map((row) => JSON.stringify({
6012
+ const scopedAssignmentRows = graphScoped ? assignmentRows.rows.filter((row) => exportedCommunitySetIds.has(row.community_set_id)) : assignmentRows.rows;
6013
+ if (scopedAssignmentRows.length > 0) {
6014
+ const assignmentsJsonl = scopedAssignmentRows.map((row) => JSON.stringify({
5921
6015
  community_set_id: row.community_set_id,
5922
6016
  community_id: row.community_id,
5923
6017
  note_id: row.note_id,
@@ -5927,7 +6021,7 @@ async function exportShard(db, options) {
5927
6021
  })).join("\n");
5928
6022
  files.set("community_assignments.jsonl", encoder.encode(assignmentsJsonl));
5929
6023
  components.push("community_assignments");
5930
- counts.community_assignments = assignmentRows.rows.length;
6024
+ counts.community_assignments = scopedAssignmentRows.length;
5931
6025
  }
5932
6026
  const checksums = {};
5933
6027
  for (const [filename, data] of files) {
@@ -5949,9 +6043,25 @@ async function exportShard(db, options) {
5949
6043
 
5950
6044
  // src/shard/shard-import.ts
5951
6045
  var decoder = new TextDecoder();
6046
+ var DEFAULT_BATCH_SIZE = 250;
6047
+ async function yieldToEventLoop() {
6048
+ const scheduler = globalThis.scheduler;
6049
+ if (scheduler?.yield) {
6050
+ await scheduler.yield();
6051
+ return;
6052
+ }
6053
+ await new Promise((resolve) => setTimeout(resolve, 0));
6054
+ }
6055
+ async function maybeYield(done, batchSize) {
6056
+ if (batchSize > 0 && done > 0 && done % batchSize === 0) {
6057
+ await yieldToEventLoop();
6058
+ }
6059
+ }
5952
6060
  async function importShard(db, data, options) {
5953
6061
  const start = performance.now();
5954
6062
  const strategy = options?.conflictStrategy ?? "skip";
6063
+ const batchSize = options?.batchSize ?? DEFAULT_BATCH_SIZE;
6064
+ const report = options?.onProgress;
5955
6065
  const warnings = [];
5956
6066
  const errors = [];
5957
6067
  const counts = {
@@ -5975,9 +6085,11 @@ async function importShard(db, data, options) {
5975
6085
  };
5976
6086
  const skipped = {};
5977
6087
  const inputData = data instanceof ArrayBuffer ? new Uint8Array(data) : data;
6088
+ report?.({ phase: "unpack", done: 0, total: 1 });
5978
6089
  let files;
5979
6090
  try {
5980
6091
  files = unpackTarGz(inputData);
6092
+ report?.({ phase: "unpack", done: 1, total: 1 });
5981
6093
  } catch (err) {
5982
6094
  return {
5983
6095
  success: false,
@@ -6024,6 +6136,7 @@ async function importShard(db, data, options) {
6024
6136
  duration_ms: performance.now() - start
6025
6137
  };
6026
6138
  }
6139
+ report?.({ phase: "validate", done: 0, total: 1 });
6027
6140
  const checksumResult = await validateChecksums(manifest.checksums, files);
6028
6141
  if (!checksumResult.valid) {
6029
6142
  return {
@@ -6035,6 +6148,7 @@ async function importShard(db, data, options) {
6035
6148
  duration_ms: performance.now() - start
6036
6149
  };
6037
6150
  }
6151
+ report?.({ phase: "validate", done: 1, total: 1 });
6038
6152
  const parsedNotes = parseJsonl(files.get("notes.jsonl"));
6039
6153
  const parsedCollections = parseJsonArray(files.get("collections.json"));
6040
6154
  parseJsonArray(files.get("tags.json"));
@@ -6085,7 +6199,8 @@ async function importShard(db, data, options) {
6085
6199
  const conflictClause = strategy === "skip" ? "ON CONFLICT DO NOTHING" : "";
6086
6200
  try {
6087
6201
  await db.transaction(async (tx) => {
6088
- for (const shardCol of parsedCollections) {
6202
+ report?.({ phase: "collections", done: 0, total: parsedCollections.length });
6203
+ for (const [index, shardCol] of parsedCollections.entries()) {
6089
6204
  const col = collectionFromShard(shardCol);
6090
6205
  if (strategy === "replace") {
6091
6206
  await tx.query(
@@ -6102,8 +6217,11 @@ async function importShard(db, data, options) {
6102
6217
  );
6103
6218
  }
6104
6219
  counts.collections++;
6220
+ report?.({ phase: "collections", done: index + 1, total: parsedCollections.length });
6221
+ await maybeYield(index + 1, batchSize);
6105
6222
  }
6106
- for (const shardNote of parsedNotes) {
6223
+ report?.({ phase: "notes", done: 0, total: parsedNotes.length });
6224
+ for (const [index, shardNote] of parsedNotes.entries()) {
6107
6225
  const note = noteFromShard(shardNote);
6108
6226
  const contentHash = computeHash(new TextEncoder().encode(note.original_content));
6109
6227
  if (strategy === "replace") {
@@ -6180,7 +6298,12 @@ async function importShard(db, data, options) {
6180
6298
  );
6181
6299
  }
6182
6300
  counts.notes++;
6301
+ report?.({ phase: "notes", done: index + 1, total: parsedNotes.length });
6302
+ await maybeYield(index + 1, batchSize);
6183
6303
  }
6304
+ const totalSkos = parsedSkosSchemes.length + parsedSkosConcepts.length + parsedSkosRelations.length + parsedNoteSkosTags.length;
6305
+ let doneSkos = 0;
6306
+ report?.({ phase: "skos", done: doneSkos, total: totalSkos });
6184
6307
  for (const scheme of parsedSkosSchemes) {
6185
6308
  if (strategy === "replace") {
6186
6309
  await tx.query(
@@ -6197,6 +6320,8 @@ async function importShard(db, data, options) {
6197
6320
  );
6198
6321
  }
6199
6322
  counts.skos_schemes++;
6323
+ report?.({ phase: "skos", done: ++doneSkos, total: totalSkos });
6324
+ await maybeYield(doneSkos, batchSize);
6200
6325
  }
6201
6326
  for (const concept of parsedSkosConcepts) {
6202
6327
  const altLabels = JSON.stringify(concept.alt_labels ?? []);
@@ -6215,8 +6340,11 @@ async function importShard(db, data, options) {
6215
6340
  );
6216
6341
  }
6217
6342
  counts.skos_concepts++;
6343
+ report?.({ phase: "skos", done: ++doneSkos, total: totalSkos });
6344
+ await maybeYield(doneSkos, batchSize);
6218
6345
  }
6219
- for (const shardLink of parsedLinks) {
6346
+ report?.({ phase: "links", done: 0, total: parsedLinks.length });
6347
+ for (const [index, shardLink] of parsedLinks.entries()) {
6220
6348
  const link = linkFromShard(shardLink);
6221
6349
  if (strategy === "replace") {
6222
6350
  await tx.query(
@@ -6233,6 +6361,8 @@ async function importShard(db, data, options) {
6233
6361
  );
6234
6362
  }
6235
6363
  counts.links++;
6364
+ report?.({ phase: "links", done: index + 1, total: parsedLinks.length });
6365
+ await maybeYield(index + 1, batchSize);
6236
6366
  }
6237
6367
  for (const relation of parsedSkosRelations) {
6238
6368
  if (strategy === "replace") {
@@ -6250,6 +6380,8 @@ async function importShard(db, data, options) {
6250
6380
  );
6251
6381
  }
6252
6382
  counts.skos_relations++;
6383
+ report?.({ phase: "skos", done: ++doneSkos, total: totalSkos });
6384
+ await maybeYield(doneSkos, batchSize);
6253
6385
  }
6254
6386
  for (const tag of parsedNoteSkosTags) {
6255
6387
  await tx.query(
@@ -6259,8 +6391,11 @@ async function importShard(db, data, options) {
6259
6391
  [tag.id, tag.note_id, tag.concept_id, tag.created_at]
6260
6392
  );
6261
6393
  counts.note_skos_tags++;
6394
+ report?.({ phase: "skos", done: ++doneSkos, total: totalSkos });
6395
+ await maybeYield(doneSkos, batchSize);
6262
6396
  }
6263
- for (const edge of parsedProvenanceEdges) {
6397
+ report?.({ phase: "provenance", done: 0, total: parsedProvenanceEdges.length });
6398
+ for (const [index, edge] of parsedProvenanceEdges.entries()) {
6264
6399
  const attributes = edge.attributes === null ? null : JSON.stringify(edge.attributes);
6265
6400
  if (strategy === "replace") {
6266
6401
  await tx.query(
@@ -6277,8 +6412,11 @@ async function importShard(db, data, options) {
6277
6412
  );
6278
6413
  }
6279
6414
  counts.provenance_edges++;
6415
+ report?.({ phase: "provenance", done: index + 1, total: parsedProvenanceEdges.length });
6416
+ await maybeYield(index + 1, batchSize);
6280
6417
  }
6281
- for (const shardSet of parsedEmbSets) {
6418
+ report?.({ phase: "embedding_sets", done: 0, total: parsedEmbSets.length });
6419
+ for (const [index, shardSet] of parsedEmbSets.entries()) {
6282
6420
  const set = embeddingSetFromShard(shardSet);
6283
6421
  if (strategy === "replace") {
6284
6422
  await tx.query(
@@ -6301,8 +6439,11 @@ async function importShard(db, data, options) {
6301
6439
  );
6302
6440
  }
6303
6441
  counts.embedding_sets++;
6442
+ report?.({ phase: "embedding_sets", done: index + 1, total: parsedEmbSets.length });
6443
+ await maybeYield(index + 1, batchSize);
6304
6444
  }
6305
- for (const shardEmb of parsedEmbeddings) {
6445
+ report?.({ phase: "embeddings", done: 0, total: parsedEmbeddings.length });
6446
+ for (const [index, shardEmb] of parsedEmbeddings.entries()) {
6306
6447
  const emb = embeddingFromShard(shardEmb);
6307
6448
  if (strategy === "replace") {
6308
6449
  await tx.query(
@@ -6319,7 +6460,12 @@ async function importShard(db, data, options) {
6319
6460
  );
6320
6461
  }
6321
6462
  counts.embeddings++;
6463
+ report?.({ phase: "embeddings", done: index + 1, total: parsedEmbeddings.length });
6464
+ await maybeYield(index + 1, batchSize);
6322
6465
  }
6466
+ const totalGraph = parsedGraphSources.length + parsedGraphEdges.length;
6467
+ let doneGraph = 0;
6468
+ report?.({ phase: "graph", done: doneGraph, total: totalGraph });
6323
6469
  for (const source of parsedGraphSources) {
6324
6470
  const parameters = source.parameters == null ? null : JSON.stringify(source.parameters);
6325
6471
  const freshness = JSON.stringify({ ...source.freshness ?? {}, status: "unknown" });
@@ -6332,6 +6478,8 @@ async function importShard(db, data, options) {
6332
6478
  [source.id, source.name, source.kind, source.source_table ?? null, source.embedding_set_id ?? null, source.virtual_set_id ?? null, source.model ?? null, source.dimension ?? null, source.truncate_dimension ?? null, source.metric ?? null, source.algorithm ?? null, parameters, source.input_hash, freshness, source.created_at]
6333
6479
  );
6334
6480
  counts.graph_sources++;
6481
+ report?.({ phase: "graph", done: ++doneGraph, total: totalGraph });
6482
+ await maybeYield(doneGraph, batchSize);
6335
6483
  }
6336
6484
  for (const edge of parsedGraphEdges) {
6337
6485
  const metadata = edge.metadata == null ? null : JSON.stringify(edge.metadata);
@@ -6342,7 +6490,12 @@ async function importShard(db, data, options) {
6342
6490
  [edge.graph_source_id, edge.from_note_id, edge.to_note_id, edge.weight, edge.kind, edge.rank ?? null, metadata]
6343
6491
  );
6344
6492
  counts.graph_edges++;
6493
+ report?.({ phase: "graph", done: ++doneGraph, total: totalGraph });
6494
+ await maybeYield(doneGraph, batchSize);
6345
6495
  }
6496
+ const totalCommunities = parsedCommunitySets.length + parsedCommunitySets.reduce((sum, set) => sum + (set.communities?.length ?? 0), 0) + parsedCommunityAssignments.length;
6497
+ let doneCommunities = 0;
6498
+ report?.({ phase: "communities", done: doneCommunities, total: totalCommunities });
6346
6499
  for (const set of parsedCommunitySets) {
6347
6500
  const parameters = set.parameters == null ? null : JSON.stringify(set.parameters);
6348
6501
  const freshness = JSON.stringify({ ...set.freshness ?? {}, status: "unknown" });
@@ -6353,6 +6506,8 @@ async function importShard(db, data, options) {
6353
6506
  [set.id, set.graph_source_id, set.name, set.source_type, set.algorithm ?? null, parameters, set.input_hash, freshness, set.created_at]
6354
6507
  );
6355
6508
  counts.community_sets++;
6509
+ report?.({ phase: "communities", done: ++doneCommunities, total: totalCommunities });
6510
+ await maybeYield(doneCommunities, batchSize);
6356
6511
  for (const community of set.communities ?? []) {
6357
6512
  const metadata = community.metadata == null ? null : JSON.stringify(community.metadata);
6358
6513
  await tx.query(
@@ -6362,6 +6517,8 @@ async function importShard(db, data, options) {
6362
6517
  [set.id, community.id, community.label ?? null, community.rank ?? null, community.size ?? null, community.confidence ?? null, community.representative_note_ids ?? [], metadata]
6363
6518
  );
6364
6519
  counts.communities++;
6520
+ report?.({ phase: "communities", done: ++doneCommunities, total: totalCommunities });
6521
+ await maybeYield(doneCommunities, batchSize);
6365
6522
  }
6366
6523
  }
6367
6524
  for (const assignment of parsedCommunityAssignments) {
@@ -6373,16 +6530,22 @@ async function importShard(db, data, options) {
6373
6530
  [assignment.community_set_id, assignment.community_id, assignment.note_id, assignment.confidence ?? null, assignment.source_type, metadata]
6374
6531
  );
6375
6532
  counts.community_assignments++;
6533
+ report?.({ phase: "communities", done: ++doneCommunities, total: totalCommunities });
6534
+ await maybeYield(doneCommunities, batchSize);
6376
6535
  }
6377
- for (const member of parsedEmbMembers) {
6536
+ report?.({ phase: "embedding_set_members", done: 0, total: parsedEmbMembers.length });
6537
+ for (const [index, member] of parsedEmbMembers.entries()) {
6378
6538
  await tx.query(
6379
6539
  `INSERT INTO embedding_set_member (embedding_set_id, note_id, embedding_id)
6380
6540
  VALUES ($1, $2, $3) ON CONFLICT DO NOTHING`,
6381
6541
  [member.embedding_set_id, member.note_id, member.embedding_id]
6382
6542
  );
6383
6543
  counts.embedding_set_members++;
6544
+ report?.({ phase: "embedding_set_members", done: index + 1, total: parsedEmbMembers.length });
6545
+ await maybeYield(index + 1, batchSize);
6384
6546
  }
6385
6547
  });
6548
+ report?.({ phase: "index", done: 1, total: 1 });
6386
6549
  } catch (err) {
6387
6550
  return {
6388
6551
  success: false,
@@ -6546,10 +6709,53 @@ function createAiwgReviewDecisionExport(source, decisions, generatedAt = (/* @__
6546
6709
  decisions: [...decisions].sort((left, right) => left.item_id.localeCompare(right.item_id))
6547
6710
  };
6548
6711
  }
6712
+ function aiwgFortemiIndexToCommunityGraph(index, options = {}) {
6713
+ const ids = new Set(index.items.map((item) => item.id));
6714
+ const relationshipWeights = options.relationshipWeights ?? {};
6715
+ const edgeCounts = /* @__PURE__ */ new Map();
6716
+ for (const item of index.items) {
6717
+ for (const relationship of item.relationships) {
6718
+ if (!ids.has(relationship.target_id) && !options.includeDanglingRelationships) continue;
6719
+ const kind = relationship.type;
6720
+ const baseWeight = relationshipWeights[kind] ?? 1;
6721
+ const key = `${item.id}\0${relationship.target_id}\0${kind}`;
6722
+ const existing = edgeCounts.get(key);
6723
+ if (existing) existing.weight += baseWeight;
6724
+ else edgeCounts.set(key, { source: item.id, target: relationship.target_id, kind, weight: baseWeight });
6725
+ }
6726
+ }
6727
+ const communities = /* @__PURE__ */ new Map();
6728
+ for (const item of index.items) {
6729
+ const communityIds = communityIdsFor(item, options);
6730
+ for (const communityId of communityIds) {
6731
+ const nodes = communities.get(communityId) ?? [];
6732
+ nodes.push(item.id);
6733
+ communities.set(communityId, nodes);
6734
+ }
6735
+ }
6736
+ return {
6737
+ nodes: index.items.map((item) => ({ id: item.id })),
6738
+ edges: Array.from(edgeCounts.values()).sort((left, right) => left.source.localeCompare(right.source) || left.target.localeCompare(right.target) || left.kind.localeCompare(right.kind)),
6739
+ communities: Array.from(communities.entries()).map(([id, nodes]) => ({ id, nodes: [...new Set(nodes)].sort() })).sort((left, right) => left.id.localeCompare(right.id))
6740
+ };
6741
+ }
6742
+ function communityIdsFor(item, options) {
6743
+ if (options.communityFacet) {
6744
+ const values = item.facets[options.communityFacet] ?? [];
6745
+ if (values.length > 0) return values.map((value) => `${options.communityFacet}:${value}`);
6746
+ }
6747
+ if (options.communityTagPrefix) {
6748
+ const prefix = options.communityTagPrefix;
6749
+ const tags = item.tags.filter((tag) => tag.startsWith(prefix));
6750
+ if (tags.length > 0) return tags;
6751
+ }
6752
+ if (item.concepts.length > 0) return item.concepts.map((concept) => `concept:${concept}`);
6753
+ return [`type:${item.type}`];
6754
+ }
6549
6755
 
6550
6756
  // src/index.ts
6551
- var VERSION = "2026.6.0";
6757
+ var VERSION = "2026.6.1";
6552
6758
 
6553
- export { ArchiveManager, AttachmentsRepository, CURRENT_SHARD_VERSION, CapabilityManager, CaptureKnowledgeInputSchema, CollectionsRepository, CommunitiesRepository, EmbeddingSetsRepository, FallbackRouter, FortemiToolManifest, GetNoteInputSchema, GraphRepository, JOB_CAPABILITIES, JOB_PRIORITIES, JobQueueWorker, LOCAL_ENDPOINTS, LinksRepository, ListNotesInputSchema, ManageArchiveInputSchema, ManageAttachmentsInputSchema, ManageCapabilitiesInputSchema, ManageCollectionsInputSchema, ManageLinksInputSchema, ManageNoteInputSchema, ManageTagsInputSchema, MemoryBlobStore, MigrationRunner, NotesRepository, OpenAICompatibleProvider, PGliteStorageBackend, PGliteStorageBackendFactory, PGliteWorkerClient, ProviderRegistry, SHARD_FORMAT, SearchInputSchema, SearchRepository, SkosRepository, TagsRepository, TransactionProxy, TypedEventBus, VERSION, aiRevisionHandler, allMigrations, appendPluginScript, assertAiwgFortemiIndexExport, buildNoteConditions, buildPluginCsp, captureKnowledge, chunkText, classifyError, classifyModel, collectionFromShard, collectionToShard, computeHash, computeSri, conceptTaggingHandler, cosineSimilarity, createAiwgReviewDecisionExport, createBlobStore, createCspReportHandler, createFortemi, createLegacyProvider, createPGliteInstance, createRoutes, defaultStorageBackendFactory, detectCommunities, detectGpuCapabilities, detectInferenceCapabilities, discoverLocalProviders, embeddingFromShard, embeddingGenerationHandler, embeddingSetFromShard, embeddingSetMemberToShard, embeddingSetToShard, embeddingToShard, enqueueFullWorkflow, enqueueJob, enqueueNoteCreationJobs, estimateModelFit, estimateVramMB, estimateVramTier, exportShard, fetchPluginScript, fortemiManifest, generateId, getAiwgFortemiFacets, getEmbedFunction, getJobQueueStatus, getLlmFunction, getNote, importShard, isPluginScriptAllowed, linkFromShard, linkToShard, linkingHandler, listNotes, manageArchive, manageAttachments, manageCapabilities, manageCollections, manageLinks, manageNote, manageTags, matchRoute, noteFromShard, noteSkosTagToShard, noteToShard, packTarGz, parseCspReport, provenanceEdgeToShard, queryAiwgFortemiIndex, registerLlmCapability, registerSemanticCapability, registerServiceWorker, searchTool, selectLlmModel, setEmbedFunction, setLlmFunction, sha256Hex, skosConceptToShard, skosRelationToShard, skosSchemeToShard, suggestTags, tagsFromShard, tagsToShard, titleGenerationHandler, unpackTarGz, unregisterLlmCapability, unregisterSemanticCapability, validateAiwgFortemiIndexExport, validateChecksums, verifySri };
6759
+ export { ArchiveManager, AttachmentsRepository, CURRENT_SHARD_VERSION, CapabilityManager, CaptureKnowledgeInputSchema, CollectionsRepository, CommunitiesRepository, EmbeddingSetsRepository, FallbackRouter, FortemiToolManifest, GetNoteInputSchema, GraphRepository, JOB_CAPABILITIES, JOB_PRIORITIES, JobQueueWorker, LOCAL_ENDPOINTS, LinksRepository, ListNotesInputSchema, ManageArchiveInputSchema, ManageAttachmentsInputSchema, ManageCapabilitiesInputSchema, ManageCollectionsInputSchema, ManageLinksInputSchema, ManageNoteInputSchema, ManageTagsInputSchema, MemoryBlobStore, MigrationRunner, NotesRepository, OpenAICompatibleProvider, PGliteStorageBackend, PGliteStorageBackendFactory, PGliteWorkerClient, PGliteWorkerStorageBackend, PGliteWorkerStorageBackendFactory, ProviderRegistry, SHARD_FORMAT, SearchInputSchema, SearchRepository, SkosRepository, TagsRepository, TransactionProxy, TypedEventBus, VERSION, aiRevisionHandler, aiwgFortemiIndexToCommunityGraph, allMigrations, appendPluginScript, assertAiwgFortemiIndexExport, buildNoteConditions, buildPluginCsp, captureKnowledge, chunkText, classifyError, classifyModel, collectionFromShard, collectionToShard, computeHash, computeSri, conceptTaggingHandler, cosineSimilarity, createAiwgReviewDecisionExport, createBlobStore, createCspReportHandler, createFortemi, createLegacyProvider, createPGliteInstance, createRoutes, defaultStorageBackendFactory, detectCommunities, detectGpuCapabilities, detectInferenceCapabilities, discoverLocalProviders, embeddingFromShard, embeddingGenerationHandler, embeddingSetFromShard, embeddingSetMemberToShard, embeddingSetToShard, embeddingToShard, enqueueFullWorkflow, enqueueJob, enqueueNoteCreationJobs, estimateModelFit, estimateVramMB, estimateVramTier, exportShard, fetchPluginScript, fortemiManifest, generateId, getAiwgFortemiFacets, getEmbedFunction, getFortemiBridge, getFortemiSecretStore, getJobQueueStatus, getLlmFunction, getNote, hasFortemiSecureSecrets, importShard, isPluginScriptAllowed, linkFromShard, linkToShard, linkingHandler, listNotes, manageArchive, manageAttachments, manageCapabilities, manageCollections, manageLinks, manageNote, manageTags, matchRoute, noteFromShard, noteSkosTagToShard, noteToShard, packTarGz, parseCspReport, provenanceEdgeToShard, queryAiwgFortemiIndex, registerLlmCapability, registerSemanticCapability, registerServiceWorker, searchTool, selectLlmModel, setEmbedFunction, setLlmFunction, sha256Hex, skosConceptToShard, skosRelationToShard, skosSchemeToShard, suggestTags, tagsFromShard, tagsToShard, titleGenerationHandler, unpackTarGz, unregisterLlmCapability, unregisterSemanticCapability, validateAiwgFortemiIndexExport, validateChecksums, verifySri };
6554
6760
  //# sourceMappingURL=index.js.map
6555
6761
  //# sourceMappingURL=index.js.map