@semiont/api-client 0.2.45 → 0.3.0

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,5 +1,7 @@
1
1
  import ky from 'ky';
2
- import { resourceUri } from '@semiont/core';
2
+ import { merge, firstValueFrom } from 'rxjs';
3
+ import { filter, map, take, timeout } from 'rxjs/operators';
4
+ export { getFragmentSelector, getSvgSelector, getTextPositionSelector, validateSvgMarkup } from '@semiont/core';
3
5
 
4
6
  // src/client.ts
5
7
 
@@ -165,17 +167,6 @@ var SSEClient = class {
165
167
  }
166
168
  return headers;
167
169
  }
168
- /**
169
- * Extract resource ID from URI
170
- *
171
- * Handles both full URIs and plain IDs:
172
- * - 'http://localhost:4000/resources/doc-123' -> 'doc-123'
173
- * - 'doc-123' -> 'doc-123'
174
- */
175
- extractId(uri) {
176
- const parts = uri.split("/");
177
- return parts[parts.length - 1];
178
- }
179
170
  /**
180
171
  * Detect annotations in a resource (streaming)
181
172
  *
@@ -212,8 +203,7 @@ var SSEClient = class {
212
203
  * ```
213
204
  */
214
205
  annotateReferences(resourceId, request, options) {
215
- const id = this.extractId(resourceId);
216
- const url = `${this.baseUrl}/resources/${id}/annotate-references-stream`;
206
+ const url = `${this.baseUrl}/resources/${resourceId}/annotate-references-stream`;
217
207
  return createSSEStream(
218
208
  url,
219
209
  {
@@ -269,9 +259,7 @@ var SSEClient = class {
269
259
  * ```
270
260
  */
271
261
  yieldResourceFromAnnotation(resourceId, annotationId, request, options) {
272
- const resId = this.extractId(resourceId);
273
- const annId = this.extractId(annotationId);
274
- const url = `${this.baseUrl}/resources/${resId}/annotations/${annId}/yield-resource-stream`;
262
+ const url = `${this.baseUrl}/resources/${resourceId}/annotations/${annotationId}/yield-resource-stream`;
275
263
  return createSSEStream(
276
264
  url,
277
265
  {
@@ -325,8 +313,7 @@ var SSEClient = class {
325
313
  * ```
326
314
  */
327
315
  annotateHighlights(resourceId, request = {}, options) {
328
- const id = this.extractId(resourceId);
329
- const url = `${this.baseUrl}/resources/${id}/annotate-highlights-stream`;
316
+ const url = `${this.baseUrl}/resources/${resourceId}/annotate-highlights-stream`;
330
317
  return createSSEStream(
331
318
  url,
332
319
  {
@@ -380,8 +367,7 @@ var SSEClient = class {
380
367
  * ```
381
368
  */
382
369
  annotateAssessments(resourceId, request = {}, options) {
383
- const id = this.extractId(resourceId);
384
- const url = `${this.baseUrl}/resources/${id}/annotate-assessments-stream`;
370
+ const url = `${this.baseUrl}/resources/${resourceId}/annotate-assessments-stream`;
385
371
  return createSSEStream(
386
372
  url,
387
373
  {
@@ -439,8 +425,7 @@ var SSEClient = class {
439
425
  * ```
440
426
  */
441
427
  annotateComments(resourceId, request = {}, options) {
442
- const id = this.extractId(resourceId);
443
- const url = `${this.baseUrl}/resources/${id}/annotate-comments-stream`;
428
+ const url = `${this.baseUrl}/resources/${resourceId}/annotate-comments-stream`;
444
429
  return createSSEStream(
445
430
  url,
446
431
  {
@@ -499,8 +484,7 @@ var SSEClient = class {
499
484
  * ```
500
485
  */
501
486
  annotateTags(resourceId, request, options) {
502
- const id = this.extractId(resourceId);
503
- const url = `${this.baseUrl}/resources/${id}/annotate-tags-stream`;
487
+ const url = `${this.baseUrl}/resources/${resourceId}/annotate-tags-stream`;
504
488
  return createSSEStream(
505
489
  url,
506
490
  {
@@ -518,6 +502,35 @@ var SSEClient = class {
518
502
  this.logger
519
503
  );
520
504
  }
505
+ /**
506
+ * Search for binding candidates (streaming)
507
+ *
508
+ * Bridges bind:search-requested to the backend Binder actor via SSE.
509
+ * Results emit as bind:search-results on the browser EventBus.
510
+ *
511
+ * @param resourceId - Resource the annotation belongs to
512
+ * @param request - Search configuration (referenceId, context, limit)
513
+ * @param options - Request options (auth token, eventBus)
514
+ * @returns SSE stream controller
515
+ */
516
+ bindSearch(resourceId, request, options) {
517
+ const url = `${this.baseUrl}/resources/${resourceId}/bind-search-stream`;
518
+ return createSSEStream(
519
+ url,
520
+ {
521
+ method: "POST",
522
+ headers: this.getHeaders(options.auth),
523
+ body: JSON.stringify(request)
524
+ },
525
+ {
526
+ progressEvents: [],
527
+ completeEvent: "bind:search-results",
528
+ errorEvent: "bind:search-failed",
529
+ eventBus: options.eventBus
530
+ },
531
+ this.logger
532
+ );
533
+ }
521
534
  /**
522
535
  * Subscribe to resource events (long-lived stream)
523
536
  *
@@ -553,8 +566,7 @@ var SSEClient = class {
553
566
  * ```
554
567
  */
555
568
  resourceEvents(resourceId, options) {
556
- const id = this.extractId(resourceId);
557
- const url = `${this.baseUrl}/resources/${id}/events/stream`;
569
+ const url = `${this.baseUrl}/resources/${resourceId}/events/stream`;
558
570
  const stream = createSSEStream(
559
571
  url,
560
572
  {
@@ -580,6 +592,54 @@ var SSEClient = class {
580
592
  }
581
593
  return stream;
582
594
  }
595
+ /**
596
+ * Subscribe to global system events (long-lived stream)
597
+ *
598
+ * Opens a long-lived SSE connection to receive system-level domain events
599
+ * (entity type additions, etc.) that are not scoped to a specific resource.
600
+ *
601
+ * @param options - Request options (auth token, eventBus)
602
+ * @returns SSE stream controller
603
+ *
604
+ * @example
605
+ * ```typescript
606
+ * const stream = sseClient.globalEvents({ auth: 'your-token', eventBus });
607
+ *
608
+ * // Events auto-emit to EventBus — subscribe there
609
+ * eventBus.get('make-meaning:event').subscribe((event) => {
610
+ * if (event.type === 'entitytype.added') {
611
+ * // Invalidate entity types query
612
+ * }
613
+ * });
614
+ *
615
+ * // Close when no longer needed
616
+ * stream.close();
617
+ * ```
618
+ */
619
+ globalEvents(options) {
620
+ const url = `${this.baseUrl}/api/events/stream`;
621
+ const stream = createSSEStream(
622
+ url,
623
+ {
624
+ method: "GET",
625
+ headers: this.getHeaders(options.auth)
626
+ },
627
+ {
628
+ progressEvents: ["*"],
629
+ completeEvent: null,
630
+ errorEvent: null,
631
+ eventBus: options.eventBus
632
+ },
633
+ this.logger
634
+ );
635
+ if (options.onConnected) {
636
+ const sub = options.eventBus.get(SSE_STREAM_CONNECTED).subscribe(() => {
637
+ options.onConnected();
638
+ sub.unsubscribe();
639
+ });
640
+ }
641
+ return stream;
642
+ }
583
643
  };
584
644
 
585
645
  // src/client.ts
@@ -617,11 +677,11 @@ var SemiontApiClient = class {
617
677
  */
618
678
  sse;
619
679
  constructor(config) {
620
- const { baseUrl, timeout = 3e4, retry = 2, logger } = config;
680
+ const { baseUrl, timeout: timeout2 = 3e4, retry = 2, logger } = config;
621
681
  this.logger = logger;
622
682
  this.baseUrl = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
623
683
  this.http = ky.create({
624
- timeout,
684
+ timeout: timeout2,
625
685
  retry,
626
686
  hooks: {
627
687
  beforeRequest: [
@@ -788,8 +848,8 @@ var SemiontApiClient = class {
788
848
  auth: options?.auth
789
849
  }).json();
790
850
  }
791
- async getResource(resourceUri2, options) {
792
- return this.http.get(resourceUri2, {
851
+ async getResource(id, options) {
852
+ return this.http.get(`${this.baseUrl}/resources/${id}`, {
793
853
  ...options,
794
854
  auth: options?.auth
795
855
  }).json();
@@ -816,8 +876,8 @@ var SemiontApiClient = class {
816
876
  * const { data, contentType } = await client.getResourceRepresentation(rUri, { accept: 'application/pdf', auth: token });
817
877
  * ```
818
878
  */
819
- async getResourceRepresentation(resourceUri2, options) {
820
- const response = await this.http.get(resourceUri2, {
879
+ async getResourceRepresentation(id, options) {
880
+ const response = await this.http.get(`${this.baseUrl}/resources/${id}`, {
821
881
  headers: {
822
882
  Accept: options?.accept || "text/plain"
823
883
  },
@@ -863,8 +923,8 @@ var SemiontApiClient = class {
863
923
  * }
864
924
  * ```
865
925
  */
866
- async getResourceRepresentationStream(resourceUri2, options) {
867
- const response = await this.http.get(resourceUri2, {
926
+ async getResourceRepresentationStream(id, options) {
927
+ const response = await this.http.get(`${this.baseUrl}/resources/${id}`, {
868
928
  headers: {
869
929
  Accept: options?.accept || "text/plain"
870
930
  },
@@ -887,46 +947,45 @@ var SemiontApiClient = class {
887
947
  auth: options?.auth
888
948
  }).json();
889
949
  }
890
- async updateResource(resourceUri2, data, options) {
891
- return this.http.patch(resourceUri2, {
950
+ async updateResource(id, data, options) {
951
+ await this.http.patch(`${this.baseUrl}/resources/${id}`, {
892
952
  json: data,
893
953
  ...options,
894
954
  auth: options?.auth
895
- }).json();
955
+ }).text();
896
956
  }
897
- async getResourceEvents(resourceUri2, options) {
898
- return this.http.get(`${resourceUri2}/events`, {
957
+ async getResourceEvents(id, options) {
958
+ return this.http.get(`${this.baseUrl}/resources/${id}/events`, {
899
959
  ...options,
900
960
  auth: options?.auth
901
961
  }).json();
902
962
  }
903
- async getResourceAnnotations(resourceUri2, options) {
904
- return this.http.get(`${resourceUri2}/annotations`, {
963
+ async getResourceAnnotations(id, options) {
964
+ return this.http.get(`${this.baseUrl}/resources/${id}/annotations`, {
905
965
  ...options,
906
966
  auth: options?.auth
907
967
  }).json();
908
968
  }
909
- async getAnnotationLLMContext(resourceUri2, annotationId, options) {
969
+ async getAnnotationLLMContext(resourceId, annotationId, options) {
910
970
  const searchParams = new URLSearchParams();
911
971
  if (options?.contextWindow) {
912
972
  searchParams.append("contextWindow", options.contextWindow.toString());
913
973
  }
914
974
  return this.http.get(
915
- `${resourceUri2}/annotations/${annotationId}/llm-context`,
975
+ `${this.baseUrl}/resources/${resourceId}/annotations/${annotationId}/llm-context`,
916
976
  {
917
977
  searchParams,
918
978
  auth: options?.auth
919
979
  }
920
980
  ).json();
921
981
  }
922
- async getResourceReferencedBy(resourceUri2, options) {
923
- return this.http.get(`${resourceUri2}/referenced-by`, {
982
+ async getResourceReferencedBy(id, options) {
983
+ return this.http.get(`${this.baseUrl}/resources/${id}/referenced-by`, {
924
984
  ...options,
925
985
  auth: options?.auth
926
986
  }).json();
927
987
  }
928
- async generateCloneToken(resourceUri2, options) {
929
- const id = resourceUri2.split("/").pop();
988
+ async generateCloneToken(id, options) {
930
989
  return this.http.post(`${this.baseUrl}/resources/${id}/clone-with-token`, {
931
990
  ...options,
932
991
  auth: options?.auth
@@ -948,69 +1007,70 @@ var SemiontApiClient = class {
948
1007
  // ============================================================================
949
1008
  // ANNOTATIONS
950
1009
  // ============================================================================
951
- async createAnnotation(resourceUri2, data, options) {
952
- return this.http.post(`${resourceUri2}/annotations`, {
1010
+ async createAnnotation(id, data, options) {
1011
+ return this.http.post(`${this.baseUrl}/resources/${id}/annotations`, {
953
1012
  json: data,
954
1013
  ...options,
955
1014
  auth: options?.auth
956
1015
  }).json();
957
1016
  }
958
- async getAnnotation(annotationUri, options) {
959
- return this.http.get(annotationUri, {
1017
+ async getAnnotation(id, options) {
1018
+ return this.http.get(`${this.baseUrl}/annotations/${id}`, {
960
1019
  ...options,
961
1020
  auth: options?.auth
962
1021
  }).json();
963
1022
  }
964
- async getResourceAnnotation(annotationUri, options) {
965
- return this.http.get(annotationUri, {
1023
+ async getResourceAnnotation(resourceId, annotationId, options) {
1024
+ return this.http.get(`${this.baseUrl}/resources/${resourceId}/annotations/${annotationId}`, {
966
1025
  ...options,
967
1026
  auth: options?.auth
968
1027
  }).json();
969
1028
  }
970
- async listAnnotations(resourceUri2, motivation, options) {
1029
+ async listAnnotations(id, motivation, options) {
971
1030
  const searchParams = new URLSearchParams();
972
1031
  if (motivation) searchParams.append("motivation", motivation);
973
- return this.http.get(`${resourceUri2}/annotations`, {
1032
+ return this.http.get(`${this.baseUrl}/resources/${id}/annotations`, {
974
1033
  searchParams,
975
1034
  ...options,
976
1035
  auth: options?.auth
977
1036
  }).json();
978
1037
  }
979
- async deleteAnnotation(annotationUri, options) {
980
- await this.http.delete(annotationUri, {
1038
+ async deleteAnnotation(resourceId, annotationId, options) {
1039
+ await this.http.delete(`${this.baseUrl}/resources/${resourceId}/annotations/${annotationId}`, {
981
1040
  ...options,
982
1041
  auth: options?.auth
983
1042
  });
984
1043
  }
985
- async updateAnnotationBody(annotationUri, data, options) {
986
- return this.http.put(`${annotationUri}/body`, {
1044
+ async updateAnnotationBody(resourceId, annotationId, data, options) {
1045
+ await this.http.put(`${this.baseUrl}/resources/${resourceId}/annotations/${annotationId}/body`, {
987
1046
  json: data,
988
1047
  ...options,
989
1048
  auth: options?.auth
990
- }).json();
1049
+ });
991
1050
  }
992
- async getAnnotationHistory(annotationUri, options) {
1051
+ async getAnnotationHistory(resourceId, annotationId, options) {
1052
+ const url = `${this.baseUrl}/resources/${resourceId}/annotations/${annotationId}/history`;
993
1053
  if (options) {
994
- return this.http.get(`${annotationUri}/history`, options).json();
1054
+ return this.http.get(url, options).json();
995
1055
  }
996
- return this.http.get(`${annotationUri}/history`).json();
1056
+ return this.http.get(url).json();
997
1057
  }
998
1058
  // ============================================================================
999
1059
  // ENTITY TYPES
1000
1060
  // ============================================================================
1001
1061
  async addEntityType(type, options) {
1002
- return this.http.post(`${this.baseUrl}/api/entity-types`, {
1003
- json: { type },
1062
+ await this.http.post(`${this.baseUrl}/api/entity-types`, {
1063
+ json: { tag: type },
1004
1064
  ...options,
1005
1065
  auth: options?.auth
1006
- }).json();
1066
+ });
1007
1067
  }
1008
1068
  async addEntityTypesBulk(types, options) {
1009
- return this.http.post(`${this.baseUrl}/api/entity-types/bulk`, {
1069
+ await this.http.post(`${this.baseUrl}/api/entity-types/bulk`, {
1010
1070
  json: { tags: types },
1011
1071
  ...options,
1012
1072
  auth: options?.auth
1013
- }).json();
1073
+ });
1014
1074
  }
1015
1075
  async listEntityTypes(options) {
1016
1076
  return this.http.get(`${this.baseUrl}/api/entity-types`, {
@@ -1051,6 +1111,113 @@ var SemiontApiClient = class {
1051
1111
  }).json();
1052
1112
  }
1053
1113
  // ============================================================================
1114
+ // ADMIN — EXCHANGE (Backup/Restore)
1115
+ // ============================================================================
1116
+ /**
1117
+ * Create a backup of the knowledge base. Returns raw Response for streaming download.
1118
+ * Caller should use response.blob() to trigger a file download.
1119
+ */
1120
+ async backupKnowledgeBase(options) {
1121
+ return fetch(`${this.baseUrl}/api/admin/exchange/backup`, {
1122
+ method: "POST",
1123
+ headers: {
1124
+ "Content-Type": "application/json",
1125
+ ...options?.auth ? { Authorization: `Bearer ${options.auth}` } : {}
1126
+ }
1127
+ });
1128
+ }
1129
+ /**
1130
+ * Restore knowledge base from a backup file. Parses SSE progress events and calls onProgress.
1131
+ * Returns the final SSE event (phase: 'complete' or 'error').
1132
+ */
1133
+ async restoreKnowledgeBase(file, options) {
1134
+ const formData = new FormData();
1135
+ formData.append("file", file);
1136
+ const response = await fetch(`${this.baseUrl}/api/admin/exchange/restore`, {
1137
+ method: "POST",
1138
+ headers: {
1139
+ ...options?.auth ? { Authorization: `Bearer ${options.auth}` } : {}
1140
+ },
1141
+ body: formData
1142
+ });
1143
+ if (!response.ok) {
1144
+ throw new Error(`Restore failed: ${response.status} ${response.statusText}`);
1145
+ }
1146
+ const reader = response.body.getReader();
1147
+ const decoder = new TextDecoder();
1148
+ let buffer = "";
1149
+ let finalResult = { phase: "unknown" };
1150
+ while (true) {
1151
+ const { done, value } = await reader.read();
1152
+ if (done) break;
1153
+ buffer += decoder.decode(value, { stream: true });
1154
+ const lines = buffer.split("\n");
1155
+ buffer = lines.pop();
1156
+ for (const line of lines) {
1157
+ if (line.startsWith("data: ")) {
1158
+ const event = JSON.parse(line.slice(6));
1159
+ options?.onProgress?.(event);
1160
+ finalResult = event;
1161
+ }
1162
+ }
1163
+ }
1164
+ return finalResult;
1165
+ }
1166
+ // ============================================================================
1167
+ // ADMIN — EXCHANGE (Linked Data Export/Import)
1168
+ // ============================================================================
1169
+ /**
1170
+ * Export the knowledge base as a JSON-LD Linked Data archive. Returns raw Response for streaming download.
1171
+ * Caller should use response.blob() to trigger a file download.
1172
+ */
1173
+ async exportKnowledgeBase(params, options) {
1174
+ const query = params?.includeArchived ? "?includeArchived=true" : "";
1175
+ return fetch(`${this.baseUrl}/api/moderate/exchange/export${query}`, {
1176
+ method: "POST",
1177
+ headers: {
1178
+ "Content-Type": "application/json",
1179
+ ...options?.auth ? { Authorization: `Bearer ${options.auth}` } : {}
1180
+ }
1181
+ });
1182
+ }
1183
+ /**
1184
+ * Import a JSON-LD Linked Data archive into the knowledge base. Parses SSE progress events and calls onProgress.
1185
+ * Returns the final SSE event (phase: 'complete' or 'error').
1186
+ */
1187
+ async importKnowledgeBase(file, options) {
1188
+ const formData = new FormData();
1189
+ formData.append("file", file);
1190
+ const response = await fetch(`${this.baseUrl}/api/moderate/exchange/import`, {
1191
+ method: "POST",
1192
+ headers: {
1193
+ ...options?.auth ? { Authorization: `Bearer ${options.auth}` } : {}
1194
+ },
1195
+ body: formData
1196
+ });
1197
+ if (!response.ok) {
1198
+ throw new Error(`Import failed: ${response.status} ${response.statusText}`);
1199
+ }
1200
+ const reader = response.body.getReader();
1201
+ const decoder = new TextDecoder();
1202
+ let buffer = "";
1203
+ let finalResult = { phase: "unknown" };
1204
+ while (true) {
1205
+ const { done, value } = await reader.read();
1206
+ if (done) break;
1207
+ buffer += decoder.decode(value, { stream: true });
1208
+ const lines = buffer.split("\n");
1209
+ buffer = lines.pop();
1210
+ for (const line of lines) {
1211
+ if (line.startsWith("data: ")) {
1212
+ const event = JSON.parse(line.slice(6));
1213
+ options?.onProgress?.(event);
1214
+ finalResult = event;
1215
+ }
1216
+ }
1217
+ }
1218
+ return finalResult;
1219
+ }
1220
+ // ============================================================================
1054
1221
  // JOB STATUS
1055
1222
  // ============================================================================
1056
1223
  async getJobStatus(id, options) {
@@ -1067,7 +1234,7 @@ var SemiontApiClient = class {
1067
1234
  */
1068
1235
  async pollJobUntilComplete(id, options) {
1069
1236
  const interval = options?.interval ?? 1e3;
1070
- const timeout = options?.timeout ?? 6e4;
1237
+ const timeout2 = options?.timeout ?? 6e4;
1071
1238
  const startTime = Date.now();
1072
1239
  while (true) {
1073
1240
  const status = await this.getJobStatus(id, { auth: options?.auth });
@@ -1077,8 +1244,8 @@ var SemiontApiClient = class {
1077
1244
  if (status.status === "complete" || status.status === "failed" || status.status === "cancelled") {
1078
1245
  return status;
1079
1246
  }
1080
- if (Date.now() - startTime > timeout) {
1081
- throw new Error(`Job polling timeout after ${timeout}ms`);
1247
+ if (Date.now() - startTime > timeout2) {
1248
+ throw new Error(`Job polling timeout after ${timeout2}ms`);
1082
1249
  }
1083
1250
  await new Promise((resolve) => setTimeout(resolve, interval));
1084
1251
  }
@@ -1086,13 +1253,13 @@ var SemiontApiClient = class {
1086
1253
  // ============================================================================
1087
1254
  // LLM CONTEXT
1088
1255
  // ============================================================================
1089
- async getResourceLLMContext(resourceUri2, options) {
1256
+ async getResourceLLMContext(id, options) {
1090
1257
  const searchParams = new URLSearchParams();
1091
1258
  if (options?.depth !== void 0) searchParams.append("depth", options.depth.toString());
1092
1259
  if (options?.maxResources !== void 0) searchParams.append("maxResources", options.maxResources.toString());
1093
1260
  if (options?.includeContent !== void 0) searchParams.append("includeContent", options.includeContent.toString());
1094
1261
  if (options?.includeSummary !== void 0) searchParams.append("includeSummary", options.includeSummary.toString());
1095
- return this.http.get(`${resourceUri2}/llm-context`, {
1262
+ return this.http.get(`${this.baseUrl}/resources/${id}/llm-context`, {
1096
1263
  searchParams,
1097
1264
  auth: options?.auth
1098
1265
  }).json();
@@ -1113,6 +1280,273 @@ var SemiontApiClient = class {
1113
1280
  return this.http.get(`${this.baseUrl}/api/status`).json();
1114
1281
  }
1115
1282
  };
1283
+ async function eventBusRequest(eventBus, requestEvent, payload, successEvent, failureEvent, timeoutMs = 3e4) {
1284
+ const correlationId = payload.correlationId;
1285
+ const result$ = merge(
1286
+ eventBus.get(successEvent).pipe(
1287
+ filter((e) => e.correlationId === correlationId),
1288
+ map((e) => ({ ok: true, response: e.response }))
1289
+ ),
1290
+ eventBus.get(failureEvent).pipe(
1291
+ filter((e) => e.correlationId === correlationId),
1292
+ map((e) => ({ ok: false, error: e.error }))
1293
+ )
1294
+ ).pipe(take(1), timeout(timeoutMs));
1295
+ const resultPromise = firstValueFrom(result$);
1296
+ eventBus.get(requestEvent).next(payload);
1297
+ const result = await resultPromise;
1298
+ if (!result.ok) {
1299
+ throw result.error;
1300
+ }
1301
+ return result.response;
1302
+ }
1303
+ var EventBusClient = class {
1304
+ constructor(eventBus, timeoutMs = 3e4) {
1305
+ this.eventBus = eventBus;
1306
+ this.timeoutMs = timeoutMs;
1307
+ }
1308
+ // ========================================================================
1309
+ // Browse Flow — Resource reads
1310
+ // ========================================================================
1311
+ async getResource(resourceId) {
1312
+ return eventBusRequest(
1313
+ this.eventBus,
1314
+ "browse:resource-requested",
1315
+ { correlationId: crypto.randomUUID(), resourceId },
1316
+ "browse:resource-result",
1317
+ "browse:resource-failed",
1318
+ this.timeoutMs
1319
+ );
1320
+ }
1321
+ async listResources(options) {
1322
+ return eventBusRequest(
1323
+ this.eventBus,
1324
+ "browse:resources-requested",
1325
+ { correlationId: crypto.randomUUID(), ...options },
1326
+ "browse:resources-result",
1327
+ "browse:resources-failed",
1328
+ this.timeoutMs
1329
+ );
1330
+ }
1331
+ // ========================================================================
1332
+ // Browse Flow — Annotation reads
1333
+ // ========================================================================
1334
+ async getAnnotations(resourceId) {
1335
+ return eventBusRequest(
1336
+ this.eventBus,
1337
+ "browse:annotations-requested",
1338
+ { correlationId: crypto.randomUUID(), resourceId },
1339
+ "browse:annotations-result",
1340
+ "browse:annotations-failed",
1341
+ this.timeoutMs
1342
+ );
1343
+ }
1344
+ async getAnnotation(resourceId, annotationId) {
1345
+ return eventBusRequest(
1346
+ this.eventBus,
1347
+ "browse:annotation-requested",
1348
+ { correlationId: crypto.randomUUID(), resourceId, annotationId },
1349
+ "browse:annotation-result",
1350
+ "browse:annotation-failed",
1351
+ this.timeoutMs
1352
+ );
1353
+ }
1354
+ // ========================================================================
1355
+ // Browse Flow — Event history
1356
+ // ========================================================================
1357
+ async getEvents(resourceId, options) {
1358
+ return eventBusRequest(
1359
+ this.eventBus,
1360
+ "browse:events-requested",
1361
+ { correlationId: crypto.randomUUID(), resourceId, ...options },
1362
+ "browse:events-result",
1363
+ "browse:events-failed",
1364
+ this.timeoutMs
1365
+ );
1366
+ }
1367
+ async getAnnotationHistory(resourceId, annotationId) {
1368
+ return eventBusRequest(
1369
+ this.eventBus,
1370
+ "browse:annotation-history-requested",
1371
+ { correlationId: crypto.randomUUID(), resourceId, annotationId },
1372
+ "browse:annotation-history-result",
1373
+ "browse:annotation-history-failed",
1374
+ this.timeoutMs
1375
+ );
1376
+ }
1377
+ // ========================================================================
1378
+ // Bind Flow — Graph queries
1379
+ // ========================================================================
1380
+ async getReferencedBy(resourceId, motivation) {
1381
+ return eventBusRequest(
1382
+ this.eventBus,
1383
+ "bind:referenced-by-requested",
1384
+ { correlationId: crypto.randomUUID(), resourceId, motivation },
1385
+ "bind:referenced-by-result",
1386
+ "bind:referenced-by-failed",
1387
+ this.timeoutMs
1388
+ );
1389
+ }
1390
+ // ========================================================================
1391
+ // Mark Flow — Entity types
1392
+ // ========================================================================
1393
+ async listEntityTypes() {
1394
+ return eventBusRequest(
1395
+ this.eventBus,
1396
+ "mark:entity-types-requested",
1397
+ { correlationId: crypto.randomUUID() },
1398
+ "mark:entity-types-result",
1399
+ "mark:entity-types-failed",
1400
+ this.timeoutMs
1401
+ );
1402
+ }
1403
+ addEntityType(tag, userId) {
1404
+ this.eventBus.get("mark:add-entity-type").next({ tag, userId });
1405
+ }
1406
+ // ========================================================================
1407
+ // Yield Flow — Clone tokens
1408
+ // ========================================================================
1409
+ async generateCloneToken(resourceId) {
1410
+ return eventBusRequest(
1411
+ this.eventBus,
1412
+ "yield:clone-token-requested",
1413
+ { correlationId: crypto.randomUUID(), resourceId },
1414
+ "yield:clone-token-generated",
1415
+ "yield:clone-token-failed",
1416
+ this.timeoutMs
1417
+ );
1418
+ }
1419
+ async getResourceByToken(token) {
1420
+ return eventBusRequest(
1421
+ this.eventBus,
1422
+ "yield:clone-resource-requested",
1423
+ { correlationId: crypto.randomUUID(), token },
1424
+ "yield:clone-resource-result",
1425
+ "yield:clone-resource-failed",
1426
+ this.timeoutMs
1427
+ );
1428
+ }
1429
+ async createResourceFromToken(options) {
1430
+ return eventBusRequest(
1431
+ this.eventBus,
1432
+ "yield:clone-create",
1433
+ { correlationId: crypto.randomUUID(), ...options },
1434
+ "yield:clone-created",
1435
+ "yield:clone-create-failed",
1436
+ this.timeoutMs
1437
+ );
1438
+ }
1439
+ // ========================================================================
1440
+ // Job Control
1441
+ // ========================================================================
1442
+ async getJobStatus(jobId) {
1443
+ return eventBusRequest(
1444
+ this.eventBus,
1445
+ "job:status-requested",
1446
+ { correlationId: crypto.randomUUID(), jobId },
1447
+ "job:status-result",
1448
+ "job:status-failed",
1449
+ this.timeoutMs
1450
+ );
1451
+ }
1452
+ // ========================================================================
1453
+ // Gather Flow — LLM context
1454
+ // ========================================================================
1455
+ async getAnnotationLLMContext(annotationId, resourceId, options) {
1456
+ const correlationId = crypto.randomUUID();
1457
+ const result$ = merge(
1458
+ this.eventBus.get("gather:complete").pipe(
1459
+ filter((e) => e.correlationId === correlationId),
1460
+ map((e) => ({ ok: true, response: e.response }))
1461
+ ),
1462
+ this.eventBus.get("gather:failed").pipe(
1463
+ filter((e) => e.correlationId === correlationId),
1464
+ map((e) => ({ ok: false, error: e.error }))
1465
+ )
1466
+ ).pipe(take(1), timeout(this.timeoutMs));
1467
+ const resultPromise = firstValueFrom(result$);
1468
+ this.eventBus.get("gather:requested").next({
1469
+ correlationId,
1470
+ annotationId,
1471
+ resourceId,
1472
+ options
1473
+ });
1474
+ const result = await resultPromise;
1475
+ if (!result.ok) {
1476
+ throw result.error;
1477
+ }
1478
+ return result.response;
1479
+ }
1480
+ async getResourceLLMContext(resourceId, options) {
1481
+ const correlationId = crypto.randomUUID();
1482
+ const result$ = merge(
1483
+ this.eventBus.get("gather:resource-complete").pipe(
1484
+ filter((e) => e.correlationId === correlationId),
1485
+ map((e) => ({ ok: true, response: e.context }))
1486
+ ),
1487
+ this.eventBus.get("gather:resource-failed").pipe(
1488
+ filter((e) => e.correlationId === correlationId),
1489
+ map((e) => ({ ok: false, error: e.error }))
1490
+ )
1491
+ ).pipe(take(1), timeout(this.timeoutMs));
1492
+ const resultPromise = firstValueFrom(result$);
1493
+ this.eventBus.get("gather:resource-requested").next({
1494
+ correlationId,
1495
+ resourceId,
1496
+ options
1497
+ });
1498
+ const result = await resultPromise;
1499
+ if (!result.ok) {
1500
+ throw result.error;
1501
+ }
1502
+ return result.response;
1503
+ }
1504
+ // ========================================================================
1505
+ // Bind Flow — Search
1506
+ // ========================================================================
1507
+ async searchResources(searchTerm) {
1508
+ const correlationId = crypto.randomUUID();
1509
+ const referenceId = correlationId;
1510
+ const result$ = merge(
1511
+ this.eventBus.get("bind:search-results").pipe(
1512
+ filter((e) => e.correlationId === correlationId),
1513
+ map((e) => ({ ok: true, results: e.results }))
1514
+ ),
1515
+ this.eventBus.get("bind:search-failed").pipe(
1516
+ filter((e) => e.correlationId === correlationId),
1517
+ map((e) => ({ ok: false, error: e.error }))
1518
+ )
1519
+ ).pipe(take(1), timeout(this.timeoutMs));
1520
+ const resultPromise = firstValueFrom(result$);
1521
+ this.eventBus.get("bind:search-requested").next({
1522
+ correlationId,
1523
+ referenceId,
1524
+ context: {
1525
+ annotation: {
1526
+ "@context": "http://www.w3.org/ns/anno.jsonld",
1527
+ type: "Annotation",
1528
+ id: referenceId,
1529
+ motivation: "linking",
1530
+ target: referenceId,
1531
+ body: []
1532
+ },
1533
+ sourceResource: {
1534
+ "@context": "https://schema.org",
1535
+ "@id": referenceId,
1536
+ name: searchTerm,
1537
+ format: "text/plain",
1538
+ representations: []
1539
+ },
1540
+ sourceContext: { selected: searchTerm }
1541
+ }
1542
+ });
1543
+ const result = await resultPromise;
1544
+ if (!result.ok) {
1545
+ throw result.error;
1546
+ }
1547
+ return result.results;
1548
+ }
1549
+ };
1116
1550
  function getBodySource(body) {
1117
1551
  if (Array.isArray(body)) {
1118
1552
  for (const item of body) {
@@ -1120,7 +1554,7 @@ function getBodySource(body) {
1120
1554
  const itemType = item.type;
1121
1555
  const itemSource = item.source;
1122
1556
  if (itemType === "SpecificResource" && typeof itemSource === "string") {
1123
- return resourceUri(itemSource);
1557
+ return itemSource;
1124
1558
  }
1125
1559
  }
1126
1560
  }
@@ -1130,7 +1564,7 @@ function getBodySource(body) {
1130
1564
  const bodyType = body.type;
1131
1565
  const bodySource = body.source;
1132
1566
  if (bodyType === "SpecificResource" && typeof bodySource === "string") {
1133
- return resourceUri(bodySource);
1567
+ return bodySource;
1134
1568
  }
1135
1569
  }
1136
1570
  return null;
@@ -1161,9 +1595,9 @@ function isBodyResolved(body) {
1161
1595
  }
1162
1596
  function getTargetSource(target) {
1163
1597
  if (typeof target === "string") {
1164
- return resourceUri(target);
1598
+ return target;
1165
1599
  }
1166
- return resourceUri(target.source);
1600
+ return target.source;
1167
1601
  }
1168
1602
  function getTargetSelector(target) {
1169
1603
  if (typeof target === "string") {
@@ -1231,49 +1665,12 @@ function getPrimarySelector(selector) {
1231
1665
  }
1232
1666
  return selector;
1233
1667
  }
1234
- function getTextPositionSelector(selector) {
1235
- if (!selector) return null;
1236
- const selectors = Array.isArray(selector) ? selector : [selector];
1237
- const found = selectors.find((s) => s.type === "TextPositionSelector");
1238
- if (!found) return null;
1239
- return found.type === "TextPositionSelector" ? found : null;
1240
- }
1241
1668
  function getTextQuoteSelector(selector) {
1242
1669
  const selectors = Array.isArray(selector) ? selector : [selector];
1243
1670
  const found = selectors.find((s) => s.type === "TextQuoteSelector");
1244
1671
  if (!found) return null;
1245
1672
  return found.type === "TextQuoteSelector" ? found : null;
1246
1673
  }
1247
- function getSvgSelector(selector) {
1248
- if (!selector) return null;
1249
- const selectors = Array.isArray(selector) ? selector : [selector];
1250
- const found = selectors.find((s) => s.type === "SvgSelector");
1251
- if (!found) return null;
1252
- return found.type === "SvgSelector" ? found : null;
1253
- }
1254
- function getFragmentSelector(selector) {
1255
- if (!selector) return null;
1256
- const selectors = Array.isArray(selector) ? selector : [selector];
1257
- const found = selectors.find((s) => s.type === "FragmentSelector");
1258
- if (!found) return null;
1259
- return found.type === "FragmentSelector" ? found : null;
1260
- }
1261
- function validateSvgMarkup(svg) {
1262
- if (!svg.includes('xmlns="http://www.w3.org/2000/svg"')) {
1263
- return 'SVG must include xmlns="http://www.w3.org/2000/svg" attribute';
1264
- }
1265
- if (!svg.includes("<svg") || !svg.includes("</svg>")) {
1266
- return "SVG must have opening and closing tags";
1267
- }
1268
- const shapeElements = ["rect", "circle", "ellipse", "polygon", "polyline", "path", "line"];
1269
- const hasShape = shapeElements.some(
1270
- (shape) => svg.includes(`<${shape}`) || svg.includes(`<${shape} `)
1271
- );
1272
- if (!hasShape) {
1273
- return "SVG must contain at least one shape element (rect, circle, ellipse, polygon, polyline, path, or line)";
1274
- }
1275
- return null;
1276
- }
1277
1674
  function extractBoundingBox(svg) {
1278
1675
  const viewBoxMatch = svg.match(/<svg[^>]*viewBox="([^"]+)"/);
1279
1676
  if (viewBoxMatch) {
@@ -1507,13 +1904,7 @@ function getAllLocaleCodes() {
1507
1904
  // src/utils/resources.ts
1508
1905
  function getResourceId(resource) {
1509
1906
  if (!resource) return void 0;
1510
- const fullId = resource["@id"];
1511
- if (fullId.includes("/resources/")) {
1512
- const parts = fullId.split("/resources/");
1513
- const lastPart = parts[parts.length - 1];
1514
- return lastPart || void 0;
1515
- }
1516
- return void 0;
1907
+ return resource["@id"] || void 0;
1517
1908
  }
1518
1909
  function getPrimaryRepresentation(resource) {
1519
1910
  if (!resource?.representations) return void 0;
@@ -1798,14 +2189,14 @@ function isValidEmail(email) {
1798
2189
 
1799
2190
  // src/mime-utils.ts
1800
2191
  function getExtensionForMimeType(mimeType) {
1801
- const map = {
2192
+ const map2 = {
1802
2193
  "text/plain": "txt",
1803
2194
  "text/markdown": "md",
1804
2195
  "image/png": "png",
1805
2196
  "image/jpeg": "jpg",
1806
2197
  "application/pdf": "pdf"
1807
2198
  };
1808
- return map[mimeType] || "dat";
2199
+ return map2[mimeType] || "dat";
1809
2200
  }
1810
2201
  function isImageMimeType(mimeType) {
1811
2202
  return mimeType === "image/png" || mimeType === "image/jpeg";
@@ -1826,6 +2217,6 @@ function getMimeCategory(mimeType) {
1826
2217
  return "unsupported";
1827
2218
  }
1828
2219
 
1829
- export { APIError, JWTTokenSchema, LOCALES, SSEClient, SSE_STREAM_CONNECTED, SemiontApiClient, buildContentCache, createCircleSvg, createPolygonSvg, createRectangleSvg, decodeRepresentation, decodeWithCharset, extractBoundingBox, extractCharset, extractContext, findBestTextMatch, findTextWithContext, formatLocaleDisplay, getAllLocaleCodes, getAnnotationExactText, getBodySource, getBodyType, getChecksum, getCommentText, getCreator, getDerivedFrom, getExactText, getExtensionForMimeType, getFragmentSelector, getLanguage, getLocaleEnglishName, getLocaleInfo, getLocaleNativeName, getMimeCategory, getNodeEncoding, getPrimaryMediaType, getPrimaryRepresentation, getPrimarySelector, getResourceEntityTypes, getResourceId, getStorageUri, getSvgSelector, getTargetSelector, getTargetSource, getTextPositionSelector, getTextQuoteSelector, hasTargetSelector, isArchived, isAssessment, isBodyResolved, isComment, isDraft, isHighlight, isImageMimeType, isPdfMimeType, isReference, isResolvedReference, isStubReference, isTag, isTextMimeType, isValidEmail, normalizeCoordinates, normalizeText, parseSvgSelector, scaleSvgToNative, validateAndCorrectOffsets, validateData, validateSvgMarkup, verifyPosition };
2220
+ export { APIError, EventBusClient, JWTTokenSchema, LOCALES, SSEClient, SSE_STREAM_CONNECTED, SemiontApiClient, buildContentCache, createCircleSvg, createPolygonSvg, createRectangleSvg, decodeRepresentation, decodeWithCharset, extractBoundingBox, extractCharset, extractContext, findBestTextMatch, findTextWithContext, formatLocaleDisplay, getAllLocaleCodes, getAnnotationExactText, getBodySource, getBodyType, getChecksum, getCommentText, getCreator, getDerivedFrom, getExactText, getExtensionForMimeType, getLanguage, getLocaleEnglishName, getLocaleInfo, getLocaleNativeName, getMimeCategory, getNodeEncoding, getPrimaryMediaType, getPrimaryRepresentation, getPrimarySelector, getResourceEntityTypes, getResourceId, getStorageUri, getTargetSelector, getTargetSource, getTextQuoteSelector, hasTargetSelector, isArchived, isAssessment, isBodyResolved, isComment, isDraft, isHighlight, isImageMimeType, isPdfMimeType, isReference, isResolvedReference, isStubReference, isTag, isTextMimeType, isValidEmail, normalizeCoordinates, normalizeText, parseSvgSelector, scaleSvgToNative, validateAndCorrectOffsets, validateData, verifyPosition };
1830
2221
  //# sourceMappingURL=index.js.map
1831
2222
  //# sourceMappingURL=index.js.map