@semiont/core 0.5.8 → 0.5.10

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
@@ -1,4 +1,5 @@
1
- import { Subject, Observable } from 'rxjs';
1
+ import { Subject, Observable, merge, TimeoutError, throwError, firstValueFrom } from 'rxjs';
2
+ import { filter, map, take, timeout, catchError, defaultIfEmpty } from 'rxjs/operators';
2
3
  import { parse } from 'smol-toml';
3
4
 
4
5
  // src/branded-types.ts
@@ -138,8 +139,7 @@ var CHANNEL_SCHEMAS = {
138
139
  "yield:create-failed": "CommandError",
139
140
  "yield:update-ok": "YieldUpdateOk",
140
141
  "yield:update-failed": null,
141
- // YieldUpdateOk & CommandError
142
- "yield:move-ok": "YieldMoveOk",
142
+ // { correlationId } & CommandError
143
143
  "yield:move-failed": null,
144
144
  // { fromUri } & CommandError
145
145
  "yield:clone-token-generated": null,
@@ -177,8 +177,14 @@ var CHANNEL_SCHEMAS = {
177
177
  "mark:create-failed": "CommandError",
178
178
  "mark:delete-ok": "MarkDeleteOk",
179
179
  "mark:delete-failed": "CommandError",
180
+ "mark:archive-ok": null,
181
+ "mark:archive-failed": "CommandError",
182
+ "mark:unarchive-ok": null,
183
+ "mark:unarchive-failed": "CommandError",
180
184
  "mark:body-update-failed": "CommandError",
185
+ "frame:entity-type-add-ok": null,
181
186
  "frame:entity-type-add-failed": "CommandError",
187
+ "frame:tag-schema-add-ok": null,
182
188
  "frame:tag-schema-add-failed": "CommandError",
183
189
  "mark:select-comment": "SelectionData",
184
190
  "mark:select-tag": "SelectionData",
@@ -222,9 +228,6 @@ var CHANNEL_SCHEMAS = {
222
228
  "gather:summary-failed": null,
223
229
  // { correlationId } & CommandError
224
230
  "gather:annotation-progress": "GatherProgress",
225
- "gather:annotation-finished": "GatherAnnotationFinished",
226
- "gather:progress": "GatherProgress",
227
- "gather:finished": "GatherFinished",
228
231
  // ── BROWSE FLOW ─────────────────────────────────────────────────
229
232
  "browse:resource-requested": "BrowseResourceRequest",
230
233
  "browse:resource-result": "BrowseResourceResult",
@@ -305,6 +308,8 @@ var CHANNEL_SCHEMAS = {
305
308
  "job:claimed": null,
306
309
  // { correlationId; response: Record<string, unknown> }
307
310
  "job:claim-failed": null,
311
+ "job:cancel-ok": null,
312
+ "job:cancel-failed": "CommandError",
308
313
  // ── SETTINGS (frontend-only) ────────────────────────────────────
309
314
  "settings:theme-changed": "SettingsThemeChangedEvent",
310
315
  "settings:line-numbers-toggled": null,
@@ -347,8 +352,82 @@ function isStoredEvent(event) {
347
352
  return event && typeof event.id === "string" && typeof event.timestamp === "string" && typeof event.type === "string" && typeof event.metadata === "object" && typeof event.metadata.sequenceNumber === "number";
348
353
  }
349
354
 
355
+ // src/bus-operations.ts
356
+ var BUS_OPERATIONS = {
357
+ // ── BIND ────────────────────────────────────────────────────────
358
+ "bind:update-body": { result: "bind:body-updated", failure: "bind:body-update-failed" },
359
+ // ── BROWSE (reads) ──────────────────────────────────────────────
360
+ "browse:resource-requested": { result: "browse:resource-result", failure: "browse:resource-failed" },
361
+ "browse:resources-requested": { result: "browse:resources-result", failure: "browse:resources-failed" },
362
+ "browse:annotation-requested": { result: "browse:annotation-result", failure: "browse:annotation-failed" },
363
+ "browse:annotations-requested": { result: "browse:annotations-result", failure: "browse:annotations-failed" },
364
+ "browse:annotation-history-requested": { result: "browse:annotation-history-result", failure: "browse:annotation-history-failed" },
365
+ "browse:events-requested": { result: "browse:events-result", failure: "browse:events-failed" },
366
+ "browse:referenced-by-requested": { result: "browse:referenced-by-result", failure: "browse:referenced-by-failed" },
367
+ "browse:entity-types-requested": { result: "browse:entity-types-result", failure: "browse:entity-types-failed" },
368
+ "browse:tag-schemas-requested": { result: "browse:tag-schemas-result", failure: "browse:tag-schemas-failed" },
369
+ "browse:directory-requested": { result: "browse:directory-result", failure: "browse:directory-failed" },
370
+ // dormant — backend handler complete, no client caller yet (annotation-detail capability)
371
+ "browse:annotation-context-requested": { result: "browse:annotation-context-result", failure: "browse:annotation-context-failed" },
372
+ // ── FRAME (KB schema writes) ────────────────────────────────────
373
+ "frame:add-entity-type": { result: "frame:entity-type-add-ok", failure: "frame:entity-type-add-failed" },
374
+ "frame:add-tag-schema": { result: "frame:tag-schema-add-ok", failure: "frame:tag-schema-add-failed" },
375
+ // ── GATHER ──────────────────────────────────────────────────────
376
+ // streaming: take-1 result + failure plus an intermediate progress channel
377
+ "gather:requested": { result: "gather:complete", failure: "gather:failed", progress: "gather:annotation-progress" },
378
+ "gather:resource-requested": { result: "gather:resource-complete", failure: "gather:resource-failed" },
379
+ // dormant — backend handler complete, no client caller yet (annotation summary)
380
+ "gather:summary-requested": { result: "gather:summary-result", failure: "gather:summary-failed" },
381
+ // ── JOB ─────────────────────────────────────────────────────────
382
+ "job:create": { result: "job:created", failure: "job:create-failed" },
383
+ "job:status-requested": { result: "job:status-result", failure: "job:status-failed" },
384
+ "job:cancel-requested": { result: "job:cancel-ok", failure: "job:cancel-failed" },
385
+ // worker-side: the worker claims a queued job (not an SDK call)
386
+ "job:claim": { result: "job:claimed", failure: "job:claim-failed" },
387
+ // ── MARK ────────────────────────────────────────────────────────
388
+ "mark:create-request": { result: "mark:create-ok", failure: "mark:create-failed" },
389
+ "mark:delete": { result: "mark:delete-ok", failure: "mark:delete-failed" },
390
+ "mark:archive": { result: "mark:archive-ok", failure: "mark:archive-failed" },
391
+ "mark:unarchive": { result: "mark:unarchive-ok", failure: "mark:unarchive-failed" },
392
+ // ── MATCH ───────────────────────────────────────────────────────
393
+ // take-1 dressed as an Observable in the SDK; no progress channel
394
+ "match:search-requested": { result: "match:search-results", failure: "match:search-failed" },
395
+ // ── YIELD ───────────────────────────────────────────────────────
396
+ // live in-process (resource-operations.ts emits + awaits via race()); the
397
+ // client also .on()-subscribes -ok for cache invalidation
398
+ "yield:create": { result: "yield:create-ok", failure: "yield:create-failed" },
399
+ // dormant — handler in stower exists, no request emitter; client pre-subscribes -ok
400
+ "yield:update": { result: "yield:update-ok", failure: "yield:update-failed" },
401
+ "yield:clone-create": { result: "yield:clone-created", failure: "yield:clone-create-failed" },
402
+ "yield:clone-resource-requested": { result: "yield:clone-resource-result", failure: "yield:clone-resource-failed" },
403
+ "yield:clone-token-requested": { result: "yield:clone-token-generated", failure: "yield:clone-token-failed" }
404
+ };
405
+
406
+ // src/bridged-channels.ts
407
+ var BRIDGED_BROADCASTS = [
408
+ "job:report-progress",
409
+ "job:complete",
410
+ "job:fail",
411
+ "frame:entity-type-added",
412
+ "frame:tag-schema-added",
413
+ "beckon:focus",
414
+ "beckon:sparkle",
415
+ "bus:resume-gap"
416
+ ];
417
+ var REGISTRY_REPLIES = Object.keys(BUS_OPERATIONS).flatMap(
418
+ (key) => {
419
+ const op = BUS_OPERATIONS[key];
420
+ return "progress" in op ? [op.result, op.failure, op.progress] : [op.result, op.failure];
421
+ }
422
+ );
423
+ var BRIDGED_CHANNELS = [
424
+ ...REGISTRY_REPLIES,
425
+ ...BRIDGED_BROADCASTS
426
+ ];
427
+
350
428
  // src/bus-log.ts
351
429
  var NODE_BUS_LOG = typeof process !== "undefined" && !!process.env?.SEMIONT_BUS_LOG;
430
+ var IS_NODE = typeof process !== "undefined" && !!process.versions?.node;
352
431
  function busLogEnabled() {
353
432
  const g = globalThis;
354
433
  if (g.__SEMIONT_BUS_LOG__) return true;
@@ -372,6 +451,21 @@ function busLog(op, channel, payload, scope) {
372
451
  const tag = `[bus ${op}] ${channel}` + (scope ? ` scope=${scope}` : "") + (cid ? ` cid=${cid}` : "") + (traceId ? ` trace=${traceId.slice(0, 8)}` : "");
373
452
  console.debug(tag, payload);
374
453
  }
454
+ function warnUnobservedRepliesEnabled() {
455
+ return IS_NODE;
456
+ }
457
+ var unobservedReplyWarned = /* @__PURE__ */ new Set();
458
+ function warnIfUnobservedReply(channel, payload, observerCount) {
459
+ if (observerCount > 0) return;
460
+ const cidRaw = payload?.correlationId;
461
+ if (typeof cidRaw !== "string" || cidRaw.length === 0) return;
462
+ if (BRIDGED_CHANNELS.includes(channel)) return;
463
+ if (unobservedReplyWarned.has(channel)) return;
464
+ unobservedReplyWarned.add(channel);
465
+ console.warn(
466
+ `[bus DROP] ${channel} cid=${cidRaw.slice(0, 8)} emitted with 0 subscribers and not in BRIDGED_CHANNELS \u2014 a correlation reply with no forwarder is dropped, so the awaiting client times out (no error). Bridge it by declaring its operation in BUS_OPERATIONS (packages/core/src/bus-operations.ts) \u2014 or, if it is a non-reply broadcast, add it to BRIDGED_BROADCASTS (packages/core/src/bridged-channels.ts) \u2014 so transports subscribe to it.`
467
+ );
468
+ }
375
469
 
376
470
  // src/event-bus.ts
377
471
  var EventBus = class {
@@ -410,10 +504,14 @@ var EventBus = class {
410
504
  }
411
505
  if (!this.subjects.has(eventName)) {
412
506
  const subject = new Subject();
413
- if (busLogEnabled()) {
507
+ const wantBusLog = busLogEnabled();
508
+ const wantDropCheck = warnUnobservedRepliesEnabled();
509
+ if (wantBusLog || wantDropCheck) {
510
+ const wrapped = subject;
414
511
  const originalNext = subject.next.bind(subject);
415
512
  subject.next = (value) => {
416
- busLog("EMIT", String(eventName), value);
513
+ if (wantBusLog) busLog("EMIT", String(eventName), value);
514
+ if (wantDropCheck) warnIfUnobservedReply(String(eventName), value, wrapped.observers.length);
417
515
  originalNext(value);
418
516
  };
419
517
  }
@@ -704,12 +802,7 @@ function validateSvgMarkup(svg) {
704
802
  }
705
803
  function assembleAnnotation(request, creator) {
706
804
  const newAnnotationId = annotationId(generateUuid());
707
- const posSelector = getTextPositionSelector(request.target.selector);
708
805
  const svgSelector = getSvgSelector(request.target.selector);
709
- const fragmentSelector = getFragmentSelector(request.target.selector);
710
- if (!posSelector && !svgSelector && !fragmentSelector) {
711
- throw new Error("Either TextPositionSelector, SvgSelector, or FragmentSelector is required for creating annotations");
712
- }
713
806
  if (svgSelector) {
714
807
  const svgError = validateSvgMarkup(svgSelector.value);
715
808
  if (svgError) {
@@ -1004,69 +1097,116 @@ function decodeRepresentation(buffer, mediaType) {
1004
1097
  return buffer.toString(encoding);
1005
1098
  }
1006
1099
 
1007
- // src/bridged-channels.ts
1008
- var BRIDGED_CHANNELS = [
1009
- "browse:resources-result",
1010
- "browse:resources-failed",
1011
- "browse:resource-result",
1012
- "browse:resource-failed",
1013
- "browse:annotations-result",
1014
- "browse:annotations-failed",
1015
- "browse:annotation-result",
1016
- "browse:annotation-failed",
1017
- "browse:annotation-history-result",
1018
- "browse:annotation-history-failed",
1019
- "browse:events-result",
1020
- "browse:events-failed",
1021
- "browse:referenced-by-result",
1022
- "browse:referenced-by-failed",
1023
- "browse:entity-types-result",
1024
- "browse:entity-types-failed",
1025
- "browse:tag-schemas-result",
1026
- "browse:tag-schemas-failed",
1027
- "browse:directory-result",
1028
- "browse:directory-failed",
1029
- "browse:annotation-context-result",
1030
- "browse:annotation-context-failed",
1031
- "mark:delete-ok",
1032
- "mark:delete-failed",
1033
- "mark:create-ok",
1034
- "mark:create-failed",
1035
- "match:search-results",
1036
- "match:search-failed",
1037
- "gather:complete",
1038
- "gather:failed",
1039
- "gather:annotation-progress",
1040
- "gather:annotation-finished",
1041
- "gather:summary-result",
1042
- "gather:summary-failed",
1043
- "bind:body-updated",
1044
- "bind:body-update-failed",
1045
- "job:report-progress",
1046
- "job:complete",
1047
- "job:fail",
1048
- "job:status-result",
1049
- "job:status-failed",
1050
- "job:created",
1051
- "job:create-failed",
1052
- "job:claimed",
1053
- "job:claim-failed",
1054
- "yield:create-ok",
1055
- "yield:create-failed",
1056
- "yield:update-ok",
1057
- "yield:update-failed",
1058
- "yield:clone-token-generated",
1059
- "yield:clone-token-failed",
1060
- "yield:clone-resource-result",
1061
- "yield:clone-resource-failed",
1062
- "yield:clone-created",
1063
- "yield:clone-create-failed",
1064
- "frame:entity-type-added",
1065
- "frame:tag-schema-added",
1066
- "beckon:focus",
1067
- "beckon:sparkle",
1068
- "bus:resume-gap"
1069
- ];
1100
+ // src/errors.ts
1101
+ var SemiontError = class extends Error {
1102
+ constructor(message, code, details) {
1103
+ super(message);
1104
+ this.code = code;
1105
+ this.details = details;
1106
+ this.name = "SemiontError";
1107
+ Error.captureStackTrace(this, this.constructor);
1108
+ }
1109
+ code;
1110
+ details;
1111
+ };
1112
+ var ValidationError = class extends SemiontError {
1113
+ constructor(message, details) {
1114
+ super(message, "VALIDATION_ERROR", details);
1115
+ this.name = "ValidationError";
1116
+ }
1117
+ };
1118
+ var ScriptError = class extends SemiontError {
1119
+ constructor(message, code = "SCRIPT_ERROR", details) {
1120
+ super(message, code, details);
1121
+ this.name = "ScriptError";
1122
+ }
1123
+ };
1124
+ var NotFoundError = class extends SemiontError {
1125
+ constructor(resource, id) {
1126
+ const message = id ? `${resource} with id '${id}' not found` : `${resource} not found`;
1127
+ super(message, "NOT_FOUND", { resource, id });
1128
+ this.name = "NotFoundError";
1129
+ }
1130
+ };
1131
+ var UnauthorizedError = class extends SemiontError {
1132
+ constructor(message = "Unauthorized", details) {
1133
+ super(message, "UNAUTHORIZED", details);
1134
+ this.name = "UnauthorizedError";
1135
+ }
1136
+ };
1137
+ var ConflictError = class extends SemiontError {
1138
+ constructor(message, details) {
1139
+ super(message, "CONFLICT", details);
1140
+ this.name = "ConflictError";
1141
+ }
1142
+ };
1143
+
1144
+ // src/bus-request.ts
1145
+ var BusRequestError = class extends SemiontError {
1146
+ constructor(message, code, details) {
1147
+ super(message, code, details);
1148
+ this.name = "BusRequestError";
1149
+ }
1150
+ };
1151
+ async function busRequest(bus, operation, payload, timeoutMs = 3e4) {
1152
+ const correlationId = crypto.randomUUID();
1153
+ const fullPayload = { ...payload, correlationId };
1154
+ const { result: resultChannel, failure: failureChannel } = BUS_OPERATIONS[operation];
1155
+ const result$ = merge(
1156
+ bus.stream(resultChannel).pipe(
1157
+ filter((e) => e.correlationId === correlationId),
1158
+ map((e) => ({ ok: true, response: e.response }))
1159
+ ),
1160
+ bus.stream(failureChannel).pipe(
1161
+ filter((e) => e.correlationId === correlationId),
1162
+ map((e) => ({
1163
+ ok: false,
1164
+ error: new BusRequestError(e.message ?? "Bus request rejected", "bus.rejected", {
1165
+ channel: failureChannel,
1166
+ correlationId,
1167
+ payload: e
1168
+ })
1169
+ }))
1170
+ )
1171
+ ).pipe(
1172
+ take(1),
1173
+ timeout(timeoutMs),
1174
+ catchError((err) => {
1175
+ if (err instanceof TimeoutError) {
1176
+ return throwError(
1177
+ () => new BusRequestError(
1178
+ `Bus request timed out after ${timeoutMs}ms on ${resultChannel}`,
1179
+ "bus.timeout",
1180
+ { channel: operation, resultChannel, correlationId, timeoutMs }
1181
+ )
1182
+ );
1183
+ }
1184
+ return throwError(() => err);
1185
+ }),
1186
+ // If the stream completes with no value — the bus was disposed before a
1187
+ // reply (e.g. during `semiont.dispose()` with a request in flight) —
1188
+ // resolve to a typed `bus.closed` result instead of letting `firstValueFrom`
1189
+ // throw rxjs `EmptyError`. An awaited caller then gets a clean
1190
+ // BusRequestError; an in-flight promise nobody is awaiting simply resolves,
1191
+ // so it can't surface as an unhandled rejection on dispose.
1192
+ // See .plans/bugs/busrequest-emptyerror-on-dispose.md.
1193
+ defaultIfEmpty({
1194
+ ok: false,
1195
+ error: new BusRequestError(
1196
+ `Bus closed before a reply on ${resultChannel}`,
1197
+ "bus.closed",
1198
+ { channel: operation, resultChannel, correlationId }
1199
+ )
1200
+ })
1201
+ );
1202
+ const resultPromise = firstValueFrom(result$);
1203
+ await bus.emit(operation, fullPayload);
1204
+ const result = await resultPromise;
1205
+ if (!result.ok) {
1206
+ throw result.error;
1207
+ }
1208
+ return result.response;
1209
+ }
1070
1210
 
1071
1211
  // src/fuzzy-anchor.ts
1072
1212
  function normalizeText(text) {
@@ -1095,13 +1235,13 @@ function levenshteinDistance(str1, str2) {
1095
1235
  }
1096
1236
  function normalizeTextWithMap(input) {
1097
1237
  let normalized = "";
1098
- const map = [];
1238
+ const map2 = [];
1099
1239
  let pendingWhitespaceStart = -1;
1100
1240
  const flushWhitespace = () => {
1101
1241
  if (pendingWhitespaceStart !== -1) {
1102
1242
  if (normalized.length > 0) {
1103
1243
  normalized += " ";
1104
- map.push(pendingWhitespaceStart);
1244
+ map2.push(pendingWhitespaceStart);
1105
1245
  }
1106
1246
  pendingWhitespaceStart = -1;
1107
1247
  }
@@ -1115,30 +1255,30 @@ function normalizeTextWithMap(input) {
1115
1255
  flushWhitespace();
1116
1256
  if (ch === "\u2018" || ch === "\u2019") {
1117
1257
  normalized += "'";
1118
- map.push(i);
1258
+ map2.push(i);
1119
1259
  } else if (ch === "\u201C" || ch === "\u201D") {
1120
1260
  normalized += '"';
1121
- map.push(i);
1261
+ map2.push(i);
1122
1262
  } else if (ch === "\u2014") {
1123
1263
  normalized += "--";
1124
- map.push(i);
1125
- map.push(i);
1264
+ map2.push(i);
1265
+ map2.push(i);
1126
1266
  } else if (ch === "\u2013") {
1127
1267
  normalized += "-";
1128
- map.push(i);
1268
+ map2.push(i);
1129
1269
  } else {
1130
1270
  normalized += ch;
1131
- map.push(i);
1271
+ map2.push(i);
1132
1272
  }
1133
1273
  }
1134
- map.push(input.length);
1135
- return { normalized, map };
1274
+ map2.push(input.length);
1275
+ return { normalized, map: map2 };
1136
1276
  }
1137
1277
  function buildContentCache(content) {
1138
- const { normalized, map } = normalizeTextWithMap(content);
1278
+ const { normalized, map: map2 } = normalizeTextWithMap(content);
1139
1279
  return {
1140
1280
  normalizedContent: normalized,
1141
- normalizedMap: map,
1281
+ normalizedMap: map2,
1142
1282
  lowerContent: content.toLowerCase()
1143
1283
  };
1144
1284
  }
@@ -1769,12 +1909,12 @@ function extensionForMediaType(format) {
1769
1909
  return capabilitiesOf(format)?.extension ?? ".dat";
1770
1910
  }
1771
1911
  var EXTENSION_TO_MEDIA_TYPE = (() => {
1772
- const map = /* @__PURE__ */ new Map();
1912
+ const map2 = /* @__PURE__ */ new Map();
1773
1913
  for (const type of Object.keys(MEDIA_TYPES)) {
1774
1914
  const ext = MEDIA_TYPES[type].extension;
1775
- if (!map.has(ext)) map.set(ext, type);
1915
+ if (!map2.has(ext)) map2.set(ext, type);
1776
1916
  }
1777
- return map;
1917
+ return map2;
1778
1918
  })();
1779
1919
  var EXTENSION_ALIASES = {
1780
1920
  ".markdown": ".md",
@@ -1832,50 +1972,6 @@ function isDefined(value) {
1832
1972
  return value !== null && value !== void 0;
1833
1973
  }
1834
1974
 
1835
- // src/errors.ts
1836
- var SemiontError = class extends Error {
1837
- constructor(message, code, details) {
1838
- super(message);
1839
- this.code = code;
1840
- this.details = details;
1841
- this.name = "SemiontError";
1842
- Error.captureStackTrace(this, this.constructor);
1843
- }
1844
- code;
1845
- details;
1846
- };
1847
- var ValidationError = class extends SemiontError {
1848
- constructor(message, details) {
1849
- super(message, "VALIDATION_ERROR", details);
1850
- this.name = "ValidationError";
1851
- }
1852
- };
1853
- var ScriptError = class extends SemiontError {
1854
- constructor(message, code = "SCRIPT_ERROR", details) {
1855
- super(message, code, details);
1856
- this.name = "ScriptError";
1857
- }
1858
- };
1859
- var NotFoundError = class extends SemiontError {
1860
- constructor(resource, id) {
1861
- const message = id ? `${resource} with id '${id}' not found` : `${resource} not found`;
1862
- super(message, "NOT_FOUND", { resource, id });
1863
- this.name = "NotFoundError";
1864
- }
1865
- };
1866
- var UnauthorizedError = class extends SemiontError {
1867
- constructor(message = "Unauthorized", details) {
1868
- super(message, "UNAUTHORIZED", details);
1869
- this.name = "UnauthorizedError";
1870
- }
1871
- };
1872
- var ConflictError = class extends SemiontError {
1873
- constructor(message, details) {
1874
- super(message, "CONFLICT", details);
1875
- this.name = "ConflictError";
1876
- }
1877
- };
1878
-
1879
1975
  // src/did-utils.ts
1880
1976
  function userToDid(user) {
1881
1977
  return `did:web:${user.domain}:users:${encodeURIComponent(user.email)}`;
@@ -2125,8 +2221,7 @@ function loadTomlConfig(projectRoot, environment, globalConfigPath, reader, env)
2125
2221
  services.backend = {
2126
2222
  platform: { type: requirePlatform(backend.platform, "backend") },
2127
2223
  port: backend.port ?? 4e3,
2128
- publicURL: backend.publicURL ?? `http://localhost:${backend.port ?? 4e3}`,
2129
- corsOrigin: backend.corsOrigin ?? backend.frontendURL ?? "http://localhost:3000"
2224
+ publicURL: backend.publicURL ?? `http://localhost:${backend.port ?? 4e3}`
2130
2225
  };
2131
2226
  }
2132
2227
  if (frontend) {
@@ -2271,6 +2366,40 @@ function getAllPlatformTypes() {
2271
2366
  return ["aws", "container", "posix", "external"];
2272
2367
  }
2273
2368
 
2274
- export { AUTHORABLE_MEDIA_TYPES, BRIDGED_CHANNELS, CHANNEL_SCHEMAS, CONTEXT_FULL_WEIGHT, CONTEXT_PARTIAL_WEIGHT, ConfigurationError, ConflictError, EMBEDDABLE_MEDIA_TYPES, EventBus, JWTTokenSchema, LOCALES, MEDIA_TYPES, NotFoundError, PERSISTED_EVENT_TYPES, POSITION_WEIGHT_MAX, POSITION_WINDOW, RESOURCE_BROADCAST_TYPES, ScopedEventBus, ScriptError, SemiontError, UnauthorizedError, ValidationError, accessToken, agentToDid, anchorAnnotation, annotationId, annotationUri, applyBodyOperations, assembleAnnotation, authCode, baseMediaType, baseUrl, buildContentCache, burstBuffer, busLog, busLogEnabled, capabilitiesOf, cloneToken, createCircleSvg, createFragmentSelector, createPolygonSvg, createRectangleSvg, createTomlConfigLoader, decodeRepresentation, decodeWithCharset, didToAgent, email, entityType, errField, extensionForMediaType, extractBoundingBox, extractCharset, extractContext, findBestTextMatch, findBodyItem, formatLocaleDisplay, generateUuid, getAllLocaleCodes, getAllPlatformTypes, getAnnotationExactText, getAnnotationUriFromEvent, getBodySource, getBodyType, getChecksum, getCommentText, getCreator, getDerivedFrom, getExactText, getFragmentSelector, getLanguage, getLocaleEnglishName, getLocaleInfo, getLocaleNativeName, getNodeEncoding, getPageFromFragment, getPrimaryMediaType, getPrimaryRepresentation, getPrimarySelector, getResourceEntityTypes, getResourceId, getStorageUri, getSvgSelector, getTargetSelector, getTargetSource, getTextPositionSelector, getTextQuoteSelector, googleCredential, hasTargetSelector, isAnnotationId, isArchived, isArray, isAssessment, isBodyResolved, isBoolean, isComment, isDefined, isDraft, isEventRelatedToAnnotation, isFunction, isHighlight, isNull, isNullish, isNumber, isObject, isReference, isResolvedReference, isResourceId, isStoredEvent, isString, isStubReference, isSupportedMediaType, isTag, isUndefined, isValidEmail, isValidPlatformType, jobId, loadTomlConfig, mcpToken, mediaTypeForExtension, normalizeCoordinates, normalizeText, parseEnvironment, parseFragmentSelector, parseSvgSelector, reconcileSelector, refreshToken, resourceAnnotationUri, resourceId, resourceUri, scaleSvgToNative, searchQuery, serializePerKey, setBusLogTraceIdProvider, softwareToAgent, textExtractionOf, userDID, userId, userToAgent, userToDid, validateData, validateEnvironment, validateSvgMarkup, verifyPosition };
2369
+ // src/knowledge-graph-views.ts
2370
+ function deriveViews(graph, mainResourceId, focalAnnotationId) {
2371
+ const nodeById = new Map(graph.nodes.map((n) => [n.id, n]));
2372
+ const connections = [];
2373
+ const citedBy = [];
2374
+ for (const edge of graph.edges) {
2375
+ if (edge.type === "citation") {
2376
+ if (edge.target !== mainResourceId) continue;
2377
+ const node = nodeById.get(edge.source);
2378
+ citedBy.push({ resourceId: edge.source, resourceName: node?.label ?? edge.source });
2379
+ } else if (edge.source === mainResourceId) {
2380
+ const node = nodeById.get(edge.target);
2381
+ connections.push({
2382
+ resourceId: edge.target,
2383
+ resourceName: node?.label ?? edge.target,
2384
+ entityTypes: node?.entityTypes ?? [],
2385
+ bidirectional: edge.bidirectional ?? false
2386
+ });
2387
+ }
2388
+ }
2389
+ const siblingEntityTypes = /* @__PURE__ */ new Set();
2390
+ for (const node of graph.nodes) {
2391
+ if (node.type === "annotation" && node.id !== focalAnnotationId) {
2392
+ for (const et of node.entityTypes ?? []) siblingEntityTypes.add(et);
2393
+ }
2394
+ }
2395
+ return {
2396
+ connections,
2397
+ citedBy,
2398
+ citedByCount: citedBy.length,
2399
+ siblingEntityTypes: Array.from(siblingEntityTypes)
2400
+ };
2401
+ }
2402
+
2403
+ export { AUTHORABLE_MEDIA_TYPES, BRIDGED_CHANNELS, BusRequestError, CHANNEL_SCHEMAS, CONTEXT_FULL_WEIGHT, CONTEXT_PARTIAL_WEIGHT, ConfigurationError, ConflictError, EMBEDDABLE_MEDIA_TYPES, EventBus, JWTTokenSchema, LOCALES, MEDIA_TYPES, NotFoundError, PERSISTED_EVENT_TYPES, POSITION_WEIGHT_MAX, POSITION_WINDOW, RESOURCE_BROADCAST_TYPES, ScopedEventBus, ScriptError, SemiontError, UnauthorizedError, ValidationError, accessToken, agentToDid, anchorAnnotation, annotationId, annotationUri, applyBodyOperations, assembleAnnotation, authCode, baseMediaType, baseUrl, buildContentCache, burstBuffer, busLog, busLogEnabled, busRequest, capabilitiesOf, cloneToken, createCircleSvg, createFragmentSelector, createPolygonSvg, createRectangleSvg, createTomlConfigLoader, decodeRepresentation, decodeWithCharset, deriveViews, didToAgent, email, entityType, errField, extensionForMediaType, extractBoundingBox, extractCharset, extractContext, findBestTextMatch, findBodyItem, formatLocaleDisplay, generateUuid, getAllLocaleCodes, getAllPlatformTypes, getAnnotationExactText, getAnnotationUriFromEvent, getBodySource, getBodyType, getChecksum, getCommentText, getCreator, getDerivedFrom, getExactText, getFragmentSelector, getLanguage, getLocaleEnglishName, getLocaleInfo, getLocaleNativeName, getNodeEncoding, getPageFromFragment, getPrimaryMediaType, getPrimaryRepresentation, getPrimarySelector, getResourceEntityTypes, getResourceId, getStorageUri, getSvgSelector, getTargetSelector, getTargetSource, getTextPositionSelector, getTextQuoteSelector, googleCredential, hasTargetSelector, isAnnotationId, isArchived, isArray, isAssessment, isBodyResolved, isBoolean, isComment, isDefined, isDraft, isEventRelatedToAnnotation, isFunction, isHighlight, isNull, isNullish, isNumber, isObject, isReference, isResolvedReference, isResourceId, isStoredEvent, isString, isStubReference, isSupportedMediaType, isTag, isUndefined, isValidEmail, isValidPlatformType, jobId, loadTomlConfig, mcpToken, mediaTypeForExtension, normalizeCoordinates, normalizeText, parseEnvironment, parseFragmentSelector, parseSvgSelector, reconcileSelector, refreshToken, resourceAnnotationUri, resourceId, resourceUri, scaleSvgToNative, searchQuery, serializePerKey, setBusLogTraceIdProvider, softwareToAgent, textExtractionOf, userDID, userId, userToAgent, userToDid, validateData, validateEnvironment, validateSvgMarkup, verifyPosition };
2275
2404
  //# sourceMappingURL=index.js.map
2276
2405
  //# sourceMappingURL=index.js.map