@semiont/api-client 0.2.45 → 0.2.46

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,8 @@
1
1
  import ky from 'ky';
2
+ import { merge, firstValueFrom } from 'rxjs';
3
+ import { filter, map, take, timeout } from 'rxjs/operators';
2
4
  import { resourceUri } from '@semiont/core';
5
+ export { getFragmentSelector, getSvgSelector, getTextPositionSelector, validateSvgMarkup } from '@semiont/core';
3
6
 
4
7
  // src/client.ts
5
8
 
@@ -580,6 +583,54 @@ var SSEClient = class {
580
583
  }
581
584
  return stream;
582
585
  }
586
+ /**
587
+ * Subscribe to global system events (long-lived stream)
588
+ *
589
+ * Opens a long-lived SSE connection to receive system-level domain events
590
+ * (entity type additions, etc.) that are not scoped to a specific resource.
591
+ *
592
+ * @param options - Request options (auth token, eventBus)
593
+ * @returns SSE stream controller
594
+ *
595
+ * @example
596
+ * ```typescript
597
+ * const stream = sseClient.globalEvents({ auth: 'your-token', eventBus });
598
+ *
599
+ * // Events auto-emit to EventBus — subscribe there
600
+ * eventBus.get('make-meaning:event').subscribe((event) => {
601
+ * if (event.type === 'entitytype.added') {
602
+ * // Invalidate entity types query
603
+ * }
604
+ * });
605
+ *
606
+ * // Close when no longer needed
607
+ * stream.close();
608
+ * ```
609
+ */
610
+ globalEvents(options) {
611
+ const url = `${this.baseUrl}/api/events/stream`;
612
+ const stream = createSSEStream(
613
+ url,
614
+ {
615
+ method: "GET",
616
+ headers: this.getHeaders(options.auth)
617
+ },
618
+ {
619
+ progressEvents: ["*"],
620
+ completeEvent: null,
621
+ errorEvent: null,
622
+ eventBus: options.eventBus
623
+ },
624
+ this.logger
625
+ );
626
+ if (options.onConnected) {
627
+ const sub = options.eventBus.get(SSE_STREAM_CONNECTED).subscribe(() => {
628
+ options.onConnected();
629
+ sub.unsubscribe();
630
+ });
631
+ }
632
+ return stream;
633
+ }
583
634
  };
584
635
 
585
636
  // src/client.ts
@@ -617,11 +668,11 @@ var SemiontApiClient = class {
617
668
  */
618
669
  sse;
619
670
  constructor(config) {
620
- const { baseUrl, timeout = 3e4, retry = 2, logger } = config;
671
+ const { baseUrl, timeout: timeout2 = 3e4, retry = 2, logger } = config;
621
672
  this.logger = logger;
622
673
  this.baseUrl = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
623
674
  this.http = ky.create({
624
- timeout,
675
+ timeout: timeout2,
625
676
  retry,
626
677
  hooks: {
627
678
  beforeRequest: [
@@ -888,11 +939,11 @@ var SemiontApiClient = class {
888
939
  }).json();
889
940
  }
890
941
  async updateResource(resourceUri2, data, options) {
891
- return this.http.patch(resourceUri2, {
942
+ await this.http.patch(resourceUri2, {
892
943
  json: data,
893
944
  ...options,
894
945
  auth: options?.auth
895
- }).json();
946
+ }).text();
896
947
  }
897
948
  async getResourceEvents(resourceUri2, options) {
898
949
  return this.http.get(`${resourceUri2}/events`, {
@@ -983,11 +1034,11 @@ var SemiontApiClient = class {
983
1034
  });
984
1035
  }
985
1036
  async updateAnnotationBody(annotationUri, data, options) {
986
- return this.http.put(`${annotationUri}/body`, {
1037
+ await this.http.put(`${annotationUri}/body`, {
987
1038
  json: data,
988
1039
  ...options,
989
1040
  auth: options?.auth
990
- }).json();
1041
+ });
991
1042
  }
992
1043
  async getAnnotationHistory(annotationUri, options) {
993
1044
  if (options) {
@@ -999,18 +1050,18 @@ var SemiontApiClient = class {
999
1050
  // ENTITY TYPES
1000
1051
  // ============================================================================
1001
1052
  async addEntityType(type, options) {
1002
- return this.http.post(`${this.baseUrl}/api/entity-types`, {
1003
- json: { type },
1053
+ await this.http.post(`${this.baseUrl}/api/entity-types`, {
1054
+ json: { tag: type },
1004
1055
  ...options,
1005
1056
  auth: options?.auth
1006
- }).json();
1057
+ });
1007
1058
  }
1008
1059
  async addEntityTypesBulk(types, options) {
1009
- return this.http.post(`${this.baseUrl}/api/entity-types/bulk`, {
1060
+ await this.http.post(`${this.baseUrl}/api/entity-types/bulk`, {
1010
1061
  json: { tags: types },
1011
1062
  ...options,
1012
1063
  auth: options?.auth
1013
- }).json();
1064
+ });
1014
1065
  }
1015
1066
  async listEntityTypes(options) {
1016
1067
  return this.http.get(`${this.baseUrl}/api/entity-types`, {
@@ -1067,7 +1118,7 @@ var SemiontApiClient = class {
1067
1118
  */
1068
1119
  async pollJobUntilComplete(id, options) {
1069
1120
  const interval = options?.interval ?? 1e3;
1070
- const timeout = options?.timeout ?? 6e4;
1121
+ const timeout2 = options?.timeout ?? 6e4;
1071
1122
  const startTime = Date.now();
1072
1123
  while (true) {
1073
1124
  const status = await this.getJobStatus(id, { auth: options?.auth });
@@ -1077,8 +1128,8 @@ var SemiontApiClient = class {
1077
1128
  if (status.status === "complete" || status.status === "failed" || status.status === "cancelled") {
1078
1129
  return status;
1079
1130
  }
1080
- if (Date.now() - startTime > timeout) {
1081
- throw new Error(`Job polling timeout after ${timeout}ms`);
1131
+ if (Date.now() - startTime > timeout2) {
1132
+ throw new Error(`Job polling timeout after ${timeout2}ms`);
1082
1133
  }
1083
1134
  await new Promise((resolve) => setTimeout(resolve, interval));
1084
1135
  }
@@ -1113,6 +1164,256 @@ var SemiontApiClient = class {
1113
1164
  return this.http.get(`${this.baseUrl}/api/status`).json();
1114
1165
  }
1115
1166
  };
1167
+ async function eventBusRequest(eventBus, requestEvent, payload, successEvent, failureEvent, timeoutMs = 3e4) {
1168
+ const correlationId = payload.correlationId;
1169
+ const result$ = merge(
1170
+ eventBus.get(successEvent).pipe(
1171
+ filter((e) => e.correlationId === correlationId),
1172
+ map((e) => ({ ok: true, response: e.response }))
1173
+ ),
1174
+ eventBus.get(failureEvent).pipe(
1175
+ filter((e) => e.correlationId === correlationId),
1176
+ map((e) => ({ ok: false, error: e.error }))
1177
+ )
1178
+ ).pipe(take(1), timeout(timeoutMs));
1179
+ const resultPromise = firstValueFrom(result$);
1180
+ eventBus.get(requestEvent).next(payload);
1181
+ const result = await resultPromise;
1182
+ if (!result.ok) {
1183
+ throw result.error;
1184
+ }
1185
+ return result.response;
1186
+ }
1187
+ var EventBusClient = class {
1188
+ constructor(eventBus, timeoutMs = 3e4) {
1189
+ this.eventBus = eventBus;
1190
+ this.timeoutMs = timeoutMs;
1191
+ }
1192
+ // ========================================================================
1193
+ // Browse Flow — Resource reads
1194
+ // ========================================================================
1195
+ async getResource(resourceId) {
1196
+ return eventBusRequest(
1197
+ this.eventBus,
1198
+ "browse:resource-requested",
1199
+ { correlationId: crypto.randomUUID(), resourceId },
1200
+ "browse:resource-result",
1201
+ "browse:resource-failed",
1202
+ this.timeoutMs
1203
+ );
1204
+ }
1205
+ async listResources(options) {
1206
+ return eventBusRequest(
1207
+ this.eventBus,
1208
+ "browse:resources-requested",
1209
+ { correlationId: crypto.randomUUID(), ...options },
1210
+ "browse:resources-result",
1211
+ "browse:resources-failed",
1212
+ this.timeoutMs
1213
+ );
1214
+ }
1215
+ // ========================================================================
1216
+ // Browse Flow — Annotation reads
1217
+ // ========================================================================
1218
+ async getAnnotations(resourceId) {
1219
+ return eventBusRequest(
1220
+ this.eventBus,
1221
+ "browse:annotations-requested",
1222
+ { correlationId: crypto.randomUUID(), resourceId },
1223
+ "browse:annotations-result",
1224
+ "browse:annotations-failed",
1225
+ this.timeoutMs
1226
+ );
1227
+ }
1228
+ async getAnnotation(resourceId, annotationId) {
1229
+ return eventBusRequest(
1230
+ this.eventBus,
1231
+ "browse:annotation-requested",
1232
+ { correlationId: crypto.randomUUID(), resourceId, annotationId },
1233
+ "browse:annotation-result",
1234
+ "browse:annotation-failed",
1235
+ this.timeoutMs
1236
+ );
1237
+ }
1238
+ // ========================================================================
1239
+ // Browse Flow — Event history
1240
+ // ========================================================================
1241
+ async getEvents(resourceId, options) {
1242
+ return eventBusRequest(
1243
+ this.eventBus,
1244
+ "browse:events-requested",
1245
+ { correlationId: crypto.randomUUID(), resourceId, ...options },
1246
+ "browse:events-result",
1247
+ "browse:events-failed",
1248
+ this.timeoutMs
1249
+ );
1250
+ }
1251
+ async getAnnotationHistory(resourceId, annotationId) {
1252
+ return eventBusRequest(
1253
+ this.eventBus,
1254
+ "browse:annotation-history-requested",
1255
+ { correlationId: crypto.randomUUID(), resourceId, annotationId },
1256
+ "browse:annotation-history-result",
1257
+ "browse:annotation-history-failed",
1258
+ this.timeoutMs
1259
+ );
1260
+ }
1261
+ // ========================================================================
1262
+ // Bind Flow — Graph queries
1263
+ // ========================================================================
1264
+ async getReferencedBy(resourceId, motivation) {
1265
+ return eventBusRequest(
1266
+ this.eventBus,
1267
+ "bind:referenced-by-requested",
1268
+ { correlationId: crypto.randomUUID(), resourceId, motivation },
1269
+ "bind:referenced-by-result",
1270
+ "bind:referenced-by-failed",
1271
+ this.timeoutMs
1272
+ );
1273
+ }
1274
+ // ========================================================================
1275
+ // Mark Flow — Entity types
1276
+ // ========================================================================
1277
+ async listEntityTypes() {
1278
+ return eventBusRequest(
1279
+ this.eventBus,
1280
+ "mark:entity-types-requested",
1281
+ { correlationId: crypto.randomUUID() },
1282
+ "mark:entity-types-result",
1283
+ "mark:entity-types-failed",
1284
+ this.timeoutMs
1285
+ );
1286
+ }
1287
+ addEntityType(tag, userId) {
1288
+ this.eventBus.get("mark:add-entity-type").next({ tag, userId });
1289
+ }
1290
+ // ========================================================================
1291
+ // Yield Flow — Clone tokens
1292
+ // ========================================================================
1293
+ async generateCloneToken(resourceId) {
1294
+ return eventBusRequest(
1295
+ this.eventBus,
1296
+ "yield:clone-token-requested",
1297
+ { correlationId: crypto.randomUUID(), resourceId },
1298
+ "yield:clone-token-generated",
1299
+ "yield:clone-token-failed",
1300
+ this.timeoutMs
1301
+ );
1302
+ }
1303
+ async getResourceByToken(token) {
1304
+ return eventBusRequest(
1305
+ this.eventBus,
1306
+ "yield:clone-resource-requested",
1307
+ { correlationId: crypto.randomUUID(), token },
1308
+ "yield:clone-resource-result",
1309
+ "yield:clone-resource-failed",
1310
+ this.timeoutMs
1311
+ );
1312
+ }
1313
+ async createResourceFromToken(options) {
1314
+ return eventBusRequest(
1315
+ this.eventBus,
1316
+ "yield:clone-create",
1317
+ { correlationId: crypto.randomUUID(), ...options },
1318
+ "yield:clone-created",
1319
+ "yield:clone-create-failed",
1320
+ this.timeoutMs
1321
+ );
1322
+ }
1323
+ // ========================================================================
1324
+ // Job Control
1325
+ // ========================================================================
1326
+ async getJobStatus(jobId) {
1327
+ return eventBusRequest(
1328
+ this.eventBus,
1329
+ "job:status-requested",
1330
+ { correlationId: crypto.randomUUID(), jobId },
1331
+ "job:status-result",
1332
+ "job:status-failed",
1333
+ this.timeoutMs
1334
+ );
1335
+ }
1336
+ // ========================================================================
1337
+ // Gather Flow — LLM context
1338
+ // ========================================================================
1339
+ async getAnnotationLLMContext(annotationUri, resourceUri2, options) {
1340
+ const correlationId = crypto.randomUUID();
1341
+ const result$ = merge(
1342
+ this.eventBus.get("gather:complete").pipe(
1343
+ filter((e) => e.correlationId === correlationId),
1344
+ map((e) => ({ ok: true, response: e.response }))
1345
+ ),
1346
+ this.eventBus.get("gather:failed").pipe(
1347
+ filter((e) => e.correlationId === correlationId),
1348
+ map((e) => ({ ok: false, error: e.error }))
1349
+ )
1350
+ ).pipe(take(1), timeout(this.timeoutMs));
1351
+ const resultPromise = firstValueFrom(result$);
1352
+ this.eventBus.get("gather:requested").next({
1353
+ correlationId,
1354
+ annotationUri,
1355
+ resourceUri: resourceUri2,
1356
+ options
1357
+ });
1358
+ const result = await resultPromise;
1359
+ if (!result.ok) {
1360
+ throw result.error;
1361
+ }
1362
+ return result.response;
1363
+ }
1364
+ async getResourceLLMContext(resourceUri2, options) {
1365
+ const correlationId = crypto.randomUUID();
1366
+ const result$ = merge(
1367
+ this.eventBus.get("gather:resource-complete").pipe(
1368
+ filter((e) => e.correlationId === correlationId),
1369
+ map((e) => ({ ok: true, response: e.context }))
1370
+ ),
1371
+ this.eventBus.get("gather:resource-failed").pipe(
1372
+ filter((e) => e.correlationId === correlationId),
1373
+ map((e) => ({ ok: false, error: e.error }))
1374
+ )
1375
+ ).pipe(take(1), timeout(this.timeoutMs));
1376
+ const resultPromise = firstValueFrom(result$);
1377
+ this.eventBus.get("gather:resource-requested").next({
1378
+ correlationId,
1379
+ resourceUri: resourceUri2,
1380
+ options
1381
+ });
1382
+ const result = await resultPromise;
1383
+ if (!result.ok) {
1384
+ throw result.error;
1385
+ }
1386
+ return result.response;
1387
+ }
1388
+ // ========================================================================
1389
+ // Bind Flow — Search
1390
+ // ========================================================================
1391
+ async searchResources(searchTerm) {
1392
+ const correlationId = crypto.randomUUID();
1393
+ const referenceId = correlationId;
1394
+ const result$ = merge(
1395
+ this.eventBus.get("bind:search-results").pipe(
1396
+ filter((e) => e.correlationId === correlationId),
1397
+ map((e) => ({ ok: true, results: e.results }))
1398
+ ),
1399
+ this.eventBus.get("bind:search-failed").pipe(
1400
+ filter((e) => e.correlationId === correlationId),
1401
+ map((e) => ({ ok: false, error: e.error }))
1402
+ )
1403
+ ).pipe(take(1), timeout(this.timeoutMs));
1404
+ const resultPromise = firstValueFrom(result$);
1405
+ this.eventBus.get("bind:search-requested").next({
1406
+ correlationId,
1407
+ referenceId,
1408
+ searchTerm
1409
+ });
1410
+ const result = await resultPromise;
1411
+ if (!result.ok) {
1412
+ throw result.error;
1413
+ }
1414
+ return result.results;
1415
+ }
1416
+ };
1116
1417
  function getBodySource(body) {
1117
1418
  if (Array.isArray(body)) {
1118
1419
  for (const item of body) {
@@ -1231,49 +1532,12 @@ function getPrimarySelector(selector) {
1231
1532
  }
1232
1533
  return selector;
1233
1534
  }
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
1535
  function getTextQuoteSelector(selector) {
1242
1536
  const selectors = Array.isArray(selector) ? selector : [selector];
1243
1537
  const found = selectors.find((s) => s.type === "TextQuoteSelector");
1244
1538
  if (!found) return null;
1245
1539
  return found.type === "TextQuoteSelector" ? found : null;
1246
1540
  }
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
1541
  function extractBoundingBox(svg) {
1278
1542
  const viewBoxMatch = svg.match(/<svg[^>]*viewBox="([^"]+)"/);
1279
1543
  if (viewBoxMatch) {
@@ -1798,14 +2062,14 @@ function isValidEmail(email) {
1798
2062
 
1799
2063
  // src/mime-utils.ts
1800
2064
  function getExtensionForMimeType(mimeType) {
1801
- const map = {
2065
+ const map2 = {
1802
2066
  "text/plain": "txt",
1803
2067
  "text/markdown": "md",
1804
2068
  "image/png": "png",
1805
2069
  "image/jpeg": "jpg",
1806
2070
  "application/pdf": "pdf"
1807
2071
  };
1808
- return map[mimeType] || "dat";
2072
+ return map2[mimeType] || "dat";
1809
2073
  }
1810
2074
  function isImageMimeType(mimeType) {
1811
2075
  return mimeType === "image/png" || mimeType === "image/jpeg";
@@ -1826,6 +2090,6 @@ function getMimeCategory(mimeType) {
1826
2090
  return "unsupported";
1827
2091
  }
1828
2092
 
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 };
2093
+ 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
2094
  //# sourceMappingURL=index.js.map
1831
2095
  //# sourceMappingURL=index.js.map