@semiont/core 0.5.9 → 0.5.11

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,16 @@ 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",
184
+ "mark:update-entity-types-ok": null,
185
+ "mark:update-entity-types-failed": "CommandError",
180
186
  "mark:body-update-failed": "CommandError",
187
+ "frame:entity-type-add-ok": null,
181
188
  "frame:entity-type-add-failed": "CommandError",
189
+ "frame:tag-schema-add-ok": null,
182
190
  "frame:tag-schema-add-failed": "CommandError",
183
191
  "mark:select-comment": "SelectionData",
184
192
  "mark:select-tag": "SelectionData",
@@ -193,11 +201,6 @@ var CHANNEL_SCHEMAS = {
193
201
  // void
194
202
  "mark:progress-dismiss": null,
195
203
  // void
196
- "mark:mode-toggled": null,
197
- // void
198
- "mark:selection-changed": "MarkSelectionChangedEvent",
199
- "mark:click-changed": "MarkClickChangedEvent",
200
- "mark:shape-changed": "MarkShapeChangedEvent",
201
204
  // ── BIND FLOW ───────────────────────────────────────────────────
202
205
  "bind:initiate": "BindInitiateCommand",
203
206
  "bind:update-body": "BindUpdateBodyCommand",
@@ -222,9 +225,6 @@ var CHANNEL_SCHEMAS = {
222
225
  "gather:summary-failed": null,
223
226
  // { correlationId } & CommandError
224
227
  "gather:annotation-progress": "GatherProgress",
225
- "gather:annotation-finished": "GatherAnnotationFinished",
226
- "gather:progress": "GatherProgress",
227
- "gather:finished": "GatherFinished",
228
228
  // ── BROWSE FLOW ─────────────────────────────────────────────────
229
229
  "browse:resource-requested": "BrowseResourceRequest",
230
230
  "browse:resource-result": "BrowseResourceResult",
@@ -258,6 +258,9 @@ var CHANNEL_SCHEMAS = {
258
258
  "browse:tag-schemas-requested": "BrowseTagSchemasRequest",
259
259
  "browse:tag-schemas-result": "BrowseTagSchemasResult",
260
260
  "browse:tag-schemas-failed": null,
261
+ "browse:agents-requested": "BrowseAgentsRequest",
262
+ "browse:agents-result": "BrowseAgentsResult",
263
+ "browse:agents-failed": null,
261
264
  "browse:directory-requested": "BrowseDirectoryRequest",
262
265
  "browse:directory-result": "BrowseDirectoryResult",
263
266
  "browse:directory-failed": null,
@@ -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,84 @@ 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:agents-requested": { result: "browse:agents-result", failure: "browse:agents-failed" },
370
+ "browse:directory-requested": { result: "browse:directory-result", failure: "browse:directory-failed" },
371
+ // dormant — backend handler complete, no client caller yet (annotation-detail capability)
372
+ "browse:annotation-context-requested": { result: "browse:annotation-context-result", failure: "browse:annotation-context-failed" },
373
+ // ── FRAME (KB schema writes) ────────────────────────────────────
374
+ "frame:add-entity-type": { result: "frame:entity-type-add-ok", failure: "frame:entity-type-add-failed" },
375
+ "frame:add-tag-schema": { result: "frame:tag-schema-add-ok", failure: "frame:tag-schema-add-failed" },
376
+ // ── GATHER ──────────────────────────────────────────────────────
377
+ // streaming: take-1 result + failure plus an intermediate progress channel
378
+ "gather:requested": { result: "gather:complete", failure: "gather:failed", progress: "gather:annotation-progress" },
379
+ "gather:resource-requested": { result: "gather:resource-complete", failure: "gather:resource-failed" },
380
+ // dormant — backend handler complete, no client caller yet (annotation summary)
381
+ "gather:summary-requested": { result: "gather:summary-result", failure: "gather:summary-failed" },
382
+ // ── JOB ─────────────────────────────────────────────────────────
383
+ "job:create": { result: "job:created", failure: "job:create-failed" },
384
+ "job:status-requested": { result: "job:status-result", failure: "job:status-failed" },
385
+ "job:cancel-requested": { result: "job:cancel-ok", failure: "job:cancel-failed" },
386
+ // worker-side: the worker claims a queued job (not an SDK call)
387
+ "job:claim": { result: "job:claimed", failure: "job:claim-failed" },
388
+ // ── MARK ────────────────────────────────────────────────────────
389
+ "mark:create-request": { result: "mark:create-ok", failure: "mark:create-failed" },
390
+ "mark:delete": { result: "mark:delete-ok", failure: "mark:delete-failed" },
391
+ "mark:archive": { result: "mark:archive-ok", failure: "mark:archive-failed" },
392
+ "mark:unarchive": { result: "mark:unarchive-ok", failure: "mark:unarchive-failed" },
393
+ "mark:update-entity-types": { result: "mark:update-entity-types-ok", failure: "mark:update-entity-types-failed" },
394
+ // ── MATCH ───────────────────────────────────────────────────────
395
+ // take-1 dressed as an Observable in the SDK; no progress channel
396
+ "match:search-requested": { result: "match:search-results", failure: "match:search-failed" },
397
+ // ── YIELD ───────────────────────────────────────────────────────
398
+ // live in-process (resource-operations.ts emits + awaits via race()); the
399
+ // client also .on()-subscribes -ok for cache invalidation
400
+ "yield:create": { result: "yield:create-ok", failure: "yield:create-failed" },
401
+ // dormant — handler in stower exists, no request emitter; client pre-subscribes -ok
402
+ "yield:update": { result: "yield:update-ok", failure: "yield:update-failed" },
403
+ "yield:clone-create": { result: "yield:clone-created", failure: "yield:clone-create-failed" },
404
+ "yield:clone-resource-requested": { result: "yield:clone-resource-result", failure: "yield:clone-resource-failed" },
405
+ "yield:clone-token-requested": { result: "yield:clone-token-generated", failure: "yield:clone-token-failed" }
406
+ };
407
+
408
+ // src/bridged-channels.ts
409
+ var BRIDGED_BROADCASTS = [
410
+ "job:report-progress",
411
+ "job:complete",
412
+ "job:fail",
413
+ "frame:entity-type-added",
414
+ "frame:tag-schema-added",
415
+ "beckon:focus",
416
+ "beckon:sparkle",
417
+ "bus:resume-gap"
418
+ ];
419
+ var REGISTRY_REPLIES = Object.keys(BUS_OPERATIONS).flatMap(
420
+ (key) => {
421
+ const op = BUS_OPERATIONS[key];
422
+ return "progress" in op ? [op.result, op.failure, op.progress] : [op.result, op.failure];
423
+ }
424
+ );
425
+ var BRIDGED_CHANNELS = [
426
+ ...REGISTRY_REPLIES,
427
+ ...BRIDGED_BROADCASTS
428
+ ];
429
+
350
430
  // src/bus-log.ts
351
431
  var NODE_BUS_LOG = typeof process !== "undefined" && !!process.env?.SEMIONT_BUS_LOG;
432
+ var IS_NODE = typeof process !== "undefined" && !!process.versions?.node;
352
433
  function busLogEnabled() {
353
434
  const g = globalThis;
354
435
  if (g.__SEMIONT_BUS_LOG__) return true;
@@ -372,6 +453,21 @@ function busLog(op, channel, payload, scope) {
372
453
  const tag = `[bus ${op}] ${channel}` + (scope ? ` scope=${scope}` : "") + (cid ? ` cid=${cid}` : "") + (traceId ? ` trace=${traceId.slice(0, 8)}` : "");
373
454
  console.debug(tag, payload);
374
455
  }
456
+ function warnUnobservedRepliesEnabled() {
457
+ return IS_NODE;
458
+ }
459
+ var unobservedReplyWarned = /* @__PURE__ */ new Set();
460
+ function warnIfUnobservedReply(channel, payload, observerCount) {
461
+ if (observerCount > 0) return;
462
+ const cidRaw = payload?.correlationId;
463
+ if (typeof cidRaw !== "string" || cidRaw.length === 0) return;
464
+ if (BRIDGED_CHANNELS.includes(channel)) return;
465
+ if (unobservedReplyWarned.has(channel)) return;
466
+ unobservedReplyWarned.add(channel);
467
+ console.warn(
468
+ `[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.`
469
+ );
470
+ }
375
471
 
376
472
  // src/event-bus.ts
377
473
  var EventBus = class {
@@ -410,10 +506,14 @@ var EventBus = class {
410
506
  }
411
507
  if (!this.subjects.has(eventName)) {
412
508
  const subject = new Subject();
413
- if (busLogEnabled()) {
509
+ const wantBusLog = busLogEnabled();
510
+ const wantDropCheck = warnUnobservedRepliesEnabled();
511
+ if (wantBusLog || wantDropCheck) {
512
+ const wrapped = subject;
414
513
  const originalNext = subject.next.bind(subject);
415
514
  subject.next = (value) => {
416
- busLog("EMIT", String(eventName), value);
515
+ if (wantBusLog) busLog("EMIT", String(eventName), value);
516
+ if (wantDropCheck) warnIfUnobservedReply(String(eventName), value, wrapped.observers.length);
417
517
  originalNext(value);
418
518
  };
419
519
  }
@@ -704,12 +804,7 @@ function validateSvgMarkup(svg) {
704
804
  }
705
805
  function assembleAnnotation(request, creator) {
706
806
  const newAnnotationId = annotationId(generateUuid());
707
- const posSelector = getTextPositionSelector(request.target.selector);
708
807
  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
808
  if (svgSelector) {
714
809
  const svgError = validateSvgMarkup(svgSelector.value);
715
810
  if (svgError) {
@@ -1004,69 +1099,122 @@ function decodeRepresentation(buffer, mediaType) {
1004
1099
  return buffer.toString(encoding);
1005
1100
  }
1006
1101
 
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
- ];
1102
+ // src/errors.ts
1103
+ var SemiontError = class extends Error {
1104
+ constructor(message, code, details) {
1105
+ super(message);
1106
+ this.code = code;
1107
+ this.details = details;
1108
+ this.name = "SemiontError";
1109
+ Error.captureStackTrace(this, this.constructor);
1110
+ }
1111
+ code;
1112
+ details;
1113
+ };
1114
+ var ValidationError = class extends SemiontError {
1115
+ constructor(message, details) {
1116
+ super(message, "VALIDATION_ERROR", details);
1117
+ this.name = "ValidationError";
1118
+ }
1119
+ };
1120
+ var ScriptError = class extends SemiontError {
1121
+ constructor(message, code = "SCRIPT_ERROR", details) {
1122
+ super(message, code, details);
1123
+ this.name = "ScriptError";
1124
+ }
1125
+ };
1126
+ var NotFoundError = class extends SemiontError {
1127
+ constructor(resource, id) {
1128
+ const message = id ? `${resource} with id '${id}' not found` : `${resource} not found`;
1129
+ super(message, "NOT_FOUND", { resource, id });
1130
+ this.name = "NotFoundError";
1131
+ }
1132
+ };
1133
+ var UnauthorizedError = class extends SemiontError {
1134
+ constructor(message = "Unauthorized", details) {
1135
+ super(message, "UNAUTHORIZED", details);
1136
+ this.name = "UnauthorizedError";
1137
+ }
1138
+ };
1139
+ var ConflictError = class extends SemiontError {
1140
+ constructor(message, details) {
1141
+ super(message, "CONFLICT", details);
1142
+ this.name = "ConflictError";
1143
+ }
1144
+ };
1145
+
1146
+ // src/bus-request.ts
1147
+ var BusRequestError = class extends SemiontError {
1148
+ constructor(message, code, details) {
1149
+ super(message, code, details);
1150
+ this.name = "BusRequestError";
1151
+ }
1152
+ };
1153
+ async function busRequest(bus, operation, payload, timeoutMs = 3e4) {
1154
+ const correlationId = crypto.randomUUID();
1155
+ const fullPayload = { ...payload, correlationId };
1156
+ const { result: resultChannel, failure: failureChannel } = BUS_OPERATIONS[operation];
1157
+ const result$ = merge(
1158
+ bus.stream(resultChannel).pipe(
1159
+ filter((e) => e.correlationId === correlationId),
1160
+ map((e) => ({ ok: true, response: e.response }))
1161
+ ),
1162
+ bus.stream(failureChannel).pipe(
1163
+ filter((e) => e.correlationId === correlationId),
1164
+ map((e) => ({
1165
+ ok: false,
1166
+ error: new BusRequestError(e.message ?? "Bus request rejected", "bus.rejected", {
1167
+ channel: failureChannel,
1168
+ correlationId,
1169
+ payload: e
1170
+ })
1171
+ }))
1172
+ )
1173
+ ).pipe(
1174
+ take(1),
1175
+ timeout(timeoutMs),
1176
+ catchError((err) => {
1177
+ if (err instanceof TimeoutError) {
1178
+ return throwError(
1179
+ () => new BusRequestError(
1180
+ `Bus request timed out after ${timeoutMs}ms on ${resultChannel}`,
1181
+ "bus.timeout",
1182
+ { channel: operation, resultChannel, correlationId, timeoutMs }
1183
+ )
1184
+ );
1185
+ }
1186
+ return throwError(() => err);
1187
+ }),
1188
+ // If the stream completes with no value — the bus was disposed before a
1189
+ // reply (e.g. during `semiont.dispose()` with a request in flight) —
1190
+ // resolve to a typed `bus.closed` result instead of letting `firstValueFrom`
1191
+ // throw rxjs `EmptyError`. An awaited caller then gets a clean
1192
+ // BusRequestError; an in-flight promise nobody is awaiting simply resolves,
1193
+ // so it can't surface as an unhandled rejection on dispose.
1194
+ // See .plans/bugs/busrequest-emptyerror-on-dispose.md.
1195
+ defaultIfEmpty({
1196
+ ok: false,
1197
+ error: new BusRequestError(
1198
+ `Bus closed before a reply on ${resultChannel}`,
1199
+ "bus.closed",
1200
+ { channel: operation, resultChannel, correlationId }
1201
+ )
1202
+ })
1203
+ );
1204
+ const resultPromise = firstValueFrom(result$);
1205
+ try {
1206
+ await bus.emit(operation, fullPayload);
1207
+ } catch (emitError) {
1208
+ resultPromise.catch(() => {
1209
+ });
1210
+ throw emitError;
1211
+ }
1212
+ const result = await resultPromise;
1213
+ if (!result.ok) {
1214
+ throw result.error;
1215
+ }
1216
+ return result.response;
1217
+ }
1070
1218
 
1071
1219
  // src/fuzzy-anchor.ts
1072
1220
  function normalizeText(text) {
@@ -1095,13 +1243,13 @@ function levenshteinDistance(str1, str2) {
1095
1243
  }
1096
1244
  function normalizeTextWithMap(input) {
1097
1245
  let normalized = "";
1098
- const map = [];
1246
+ const map2 = [];
1099
1247
  let pendingWhitespaceStart = -1;
1100
1248
  const flushWhitespace = () => {
1101
1249
  if (pendingWhitespaceStart !== -1) {
1102
1250
  if (normalized.length > 0) {
1103
1251
  normalized += " ";
1104
- map.push(pendingWhitespaceStart);
1252
+ map2.push(pendingWhitespaceStart);
1105
1253
  }
1106
1254
  pendingWhitespaceStart = -1;
1107
1255
  }
@@ -1115,30 +1263,30 @@ function normalizeTextWithMap(input) {
1115
1263
  flushWhitespace();
1116
1264
  if (ch === "\u2018" || ch === "\u2019") {
1117
1265
  normalized += "'";
1118
- map.push(i);
1266
+ map2.push(i);
1119
1267
  } else if (ch === "\u201C" || ch === "\u201D") {
1120
1268
  normalized += '"';
1121
- map.push(i);
1269
+ map2.push(i);
1122
1270
  } else if (ch === "\u2014") {
1123
1271
  normalized += "--";
1124
- map.push(i);
1125
- map.push(i);
1272
+ map2.push(i);
1273
+ map2.push(i);
1126
1274
  } else if (ch === "\u2013") {
1127
1275
  normalized += "-";
1128
- map.push(i);
1276
+ map2.push(i);
1129
1277
  } else {
1130
1278
  normalized += ch;
1131
- map.push(i);
1279
+ map2.push(i);
1132
1280
  }
1133
1281
  }
1134
- map.push(input.length);
1135
- return { normalized, map };
1282
+ map2.push(input.length);
1283
+ return { normalized, map: map2 };
1136
1284
  }
1137
1285
  function buildContentCache(content) {
1138
- const { normalized, map } = normalizeTextWithMap(content);
1286
+ const { normalized, map: map2 } = normalizeTextWithMap(content);
1139
1287
  return {
1140
1288
  normalizedContent: normalized,
1141
- normalizedMap: map,
1289
+ normalizedMap: map2,
1142
1290
  lowerContent: content.toLowerCase()
1143
1291
  };
1144
1292
  }
@@ -1769,12 +1917,12 @@ function extensionForMediaType(format) {
1769
1917
  return capabilitiesOf(format)?.extension ?? ".dat";
1770
1918
  }
1771
1919
  var EXTENSION_TO_MEDIA_TYPE = (() => {
1772
- const map = /* @__PURE__ */ new Map();
1920
+ const map2 = /* @__PURE__ */ new Map();
1773
1921
  for (const type of Object.keys(MEDIA_TYPES)) {
1774
1922
  const ext = MEDIA_TYPES[type].extension;
1775
- if (!map.has(ext)) map.set(ext, type);
1923
+ if (!map2.has(ext)) map2.set(ext, type);
1776
1924
  }
1777
- return map;
1925
+ return map2;
1778
1926
  })();
1779
1927
  var EXTENSION_ALIASES = {
1780
1928
  ".markdown": ".md",
@@ -1832,50 +1980,6 @@ function isDefined(value) {
1832
1980
  return value !== null && value !== void 0;
1833
1981
  }
1834
1982
 
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
1983
  // src/did-utils.ts
1880
1984
  function userToDid(user) {
1881
1985
  return `did:web:${user.domain}:users:${encodeURIComponent(user.email)}`;
@@ -2270,6 +2374,40 @@ function getAllPlatformTypes() {
2270
2374
  return ["aws", "container", "posix", "external"];
2271
2375
  }
2272
2376
 
2273
- 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 };
2377
+ // src/knowledge-graph-views.ts
2378
+ function deriveViews(graph, mainResourceId, focalAnnotationId) {
2379
+ const nodeById = new Map(graph.nodes.map((n) => [n.id, n]));
2380
+ const connections = [];
2381
+ const citedBy = [];
2382
+ for (const edge of graph.edges) {
2383
+ if (edge.type === "citation") {
2384
+ if (edge.target !== mainResourceId) continue;
2385
+ const node = nodeById.get(edge.source);
2386
+ citedBy.push({ resourceId: edge.source, resourceName: node?.label ?? edge.source });
2387
+ } else if (edge.source === mainResourceId) {
2388
+ const node = nodeById.get(edge.target);
2389
+ connections.push({
2390
+ resourceId: edge.target,
2391
+ resourceName: node?.label ?? edge.target,
2392
+ entityTypes: node?.entityTypes ?? [],
2393
+ bidirectional: edge.bidirectional ?? false
2394
+ });
2395
+ }
2396
+ }
2397
+ const siblingEntityTypes = /* @__PURE__ */ new Set();
2398
+ for (const node of graph.nodes) {
2399
+ if (node.type === "annotation" && node.id !== focalAnnotationId) {
2400
+ for (const et of node.entityTypes ?? []) siblingEntityTypes.add(et);
2401
+ }
2402
+ }
2403
+ return {
2404
+ connections,
2405
+ citedBy,
2406
+ citedByCount: citedBy.length,
2407
+ siblingEntityTypes: Array.from(siblingEntityTypes)
2408
+ };
2409
+ }
2410
+
2411
+ 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 };
2274
2412
  //# sourceMappingURL=index.js.map
2275
2413
  //# sourceMappingURL=index.js.map