@semiont/api-client 0.4.7 → 0.4.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/README.md +2 -0
- package/dist/index.d.ts +234 -30
- package/dist/index.js +604 -171
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import ky from 'ky';
|
|
2
|
-
import { merge, firstValueFrom } from 'rxjs';
|
|
3
|
-
import {
|
|
2
|
+
import { Subscription, BehaviorSubject, merge, firstValueFrom } from 'rxjs';
|
|
3
|
+
import { resourceId, annotationId } from '@semiont/core';
|
|
4
4
|
export { getFragmentSelector, getSvgSelector, getTextPositionSelector, validateSvgMarkup } from '@semiont/core';
|
|
5
|
+
import { map, distinctUntilChanged, filter, take, timeout } from 'rxjs/operators';
|
|
5
6
|
|
|
6
7
|
// src/client.ts
|
|
7
8
|
|
|
@@ -133,9 +134,7 @@ function createSSEStream(url, fetchOptions, config, logger) {
|
|
|
133
134
|
abortController.abort();
|
|
134
135
|
}
|
|
135
136
|
} catch (error) {
|
|
136
|
-
|
|
137
|
-
console.error("[SSE] Event type:", eventType);
|
|
138
|
-
console.error("[SSE] Data:", data);
|
|
137
|
+
logger?.error("SSE Failed to parse event data", { error, eventType, data });
|
|
139
138
|
}
|
|
140
139
|
};
|
|
141
140
|
connect();
|
|
@@ -602,8 +601,8 @@ var SSEClient = class {
|
|
|
602
601
|
* @param options - Request options (auth token, eventBus)
|
|
603
602
|
* @returns SSE stream controller
|
|
604
603
|
*/
|
|
605
|
-
|
|
606
|
-
const url = `${this.baseUrl}/resources/${resourceId}/
|
|
604
|
+
matchSearch(resourceId, request, options) {
|
|
605
|
+
const url = `${this.baseUrl}/resources/${resourceId}/match-search-stream`;
|
|
607
606
|
return createSSEStream(
|
|
608
607
|
url,
|
|
609
608
|
{
|
|
@@ -766,6 +765,499 @@ var SSEClient = class {
|
|
|
766
765
|
return stream;
|
|
767
766
|
}
|
|
768
767
|
};
|
|
768
|
+
var FlowEngine = class {
|
|
769
|
+
constructor(eventBus, sse, http) {
|
|
770
|
+
this.eventBus = eventBus;
|
|
771
|
+
this.sse = sse;
|
|
772
|
+
this.http = http;
|
|
773
|
+
}
|
|
774
|
+
// ─── bind flow ─────────────────────────────────────────────────────────────
|
|
775
|
+
/**
|
|
776
|
+
* Activate the bind flow for a resource.
|
|
777
|
+
*
|
|
778
|
+
* @subscribes bind:update-body — calls SSE bindAnnotation
|
|
779
|
+
* @subscribes match:search-requested — calls SSE bindSearch
|
|
780
|
+
* @emits bind:body-updated, bind:body-update-failed
|
|
781
|
+
*/
|
|
782
|
+
bind(rUri, getToken) {
|
|
783
|
+
const sub = new Subscription();
|
|
784
|
+
sub.add(
|
|
785
|
+
this.eventBus.get("bind:update-body").subscribe((event) => {
|
|
786
|
+
const annotationId = event.annotationId;
|
|
787
|
+
const finishedSub = this.eventBus.get("bind:finished").subscribe((finishedEvent) => {
|
|
788
|
+
if (finishedEvent.annotationId !== annotationId) return;
|
|
789
|
+
finishedSub.unsubscribe();
|
|
790
|
+
failedSub.unsubscribe();
|
|
791
|
+
this.eventBus.get("bind:body-updated").next({ annotationId });
|
|
792
|
+
});
|
|
793
|
+
const failedSub = this.eventBus.get("bind:failed").subscribe(() => {
|
|
794
|
+
finishedSub.unsubscribe();
|
|
795
|
+
failedSub.unsubscribe();
|
|
796
|
+
this.eventBus.get("bind:body-update-failed").next({ error: new Error("Bind failed") });
|
|
797
|
+
});
|
|
798
|
+
this.sse.bindAnnotation(
|
|
799
|
+
rUri,
|
|
800
|
+
annotationId,
|
|
801
|
+
{ resourceId: event.resourceId, operations: event.operations },
|
|
802
|
+
{ auth: getToken(), eventBus: this.eventBus }
|
|
803
|
+
);
|
|
804
|
+
})
|
|
805
|
+
);
|
|
806
|
+
sub.add(
|
|
807
|
+
this.eventBus.get("match:search-requested").subscribe((event) => {
|
|
808
|
+
this.sse.matchSearch(rUri, {
|
|
809
|
+
correlationId: event.correlationId,
|
|
810
|
+
referenceId: event.referenceId,
|
|
811
|
+
context: event.context,
|
|
812
|
+
limit: event.limit,
|
|
813
|
+
useSemanticScoring: event.useSemanticScoring
|
|
814
|
+
}, { auth: getToken(), eventBus: this.eventBus });
|
|
815
|
+
})
|
|
816
|
+
);
|
|
817
|
+
return sub;
|
|
818
|
+
}
|
|
819
|
+
// ─── yield flow ────────────────────────────────────────────────────────────
|
|
820
|
+
/**
|
|
821
|
+
* Activate the yield (generation) flow for a resource.
|
|
822
|
+
*
|
|
823
|
+
* @subscribes yield:request — calls SSE yieldResource
|
|
824
|
+
* @subscribes yield:finished — links generated resource back to the reference annotation via bind:update-body
|
|
825
|
+
* @subscribes job:cancel-requested (generation) — aborts in-flight stream
|
|
826
|
+
*/
|
|
827
|
+
yield(_rUri, getToken) {
|
|
828
|
+
const sub = new Subscription();
|
|
829
|
+
let abortController = null;
|
|
830
|
+
sub.add(
|
|
831
|
+
this.eventBus.get("yield:request").subscribe((event) => {
|
|
832
|
+
abortController?.abort();
|
|
833
|
+
abortController = new AbortController();
|
|
834
|
+
this.sse.yieldResource(
|
|
835
|
+
event.resourceId,
|
|
836
|
+
event.annotationId,
|
|
837
|
+
event.options,
|
|
838
|
+
{ auth: getToken(), eventBus: this.eventBus }
|
|
839
|
+
);
|
|
840
|
+
})
|
|
841
|
+
);
|
|
842
|
+
sub.add(
|
|
843
|
+
this.eventBus.get("yield:finished").subscribe((event) => {
|
|
844
|
+
if (!event.resourceId || !event.referenceId || !event.sourceResourceId) return;
|
|
845
|
+
this.eventBus.get("bind:update-body").next({
|
|
846
|
+
annotationId: annotationId(event.referenceId),
|
|
847
|
+
resourceId: resourceId(event.sourceResourceId),
|
|
848
|
+
operations: [{ op: "add", item: { type: "SpecificResource", source: event.resourceId } }]
|
|
849
|
+
});
|
|
850
|
+
})
|
|
851
|
+
);
|
|
852
|
+
sub.add(
|
|
853
|
+
this.eventBus.get("job:cancel-requested").subscribe((event) => {
|
|
854
|
+
if (event.jobType === "generation") {
|
|
855
|
+
abortController?.abort();
|
|
856
|
+
abortController = null;
|
|
857
|
+
}
|
|
858
|
+
})
|
|
859
|
+
);
|
|
860
|
+
sub.add(new Subscription(() => {
|
|
861
|
+
abortController?.abort();
|
|
862
|
+
}));
|
|
863
|
+
return sub;
|
|
864
|
+
}
|
|
865
|
+
// ─── mark flow ─────────────────────────────────────────────────────────────
|
|
866
|
+
/**
|
|
867
|
+
* Activate the mark (annotation CRUD + assist) flow for a resource.
|
|
868
|
+
*
|
|
869
|
+
* @subscribes mark:submit — HTTP markAnnotation
|
|
870
|
+
* @subscribes mark:delete — HTTP deleteAnnotation
|
|
871
|
+
* @subscribes mark:assist-request — SSE mark* (by motivation)
|
|
872
|
+
* @subscribes job:cancel-requested (annotation) — aborts in-flight assist
|
|
873
|
+
* @emits mark:created, mark:create-failed, mark:deleted, mark:delete-failed
|
|
874
|
+
*/
|
|
875
|
+
mark(rUri, getToken) {
|
|
876
|
+
const sub = new Subscription();
|
|
877
|
+
let assistAbort = null;
|
|
878
|
+
sub.add(
|
|
879
|
+
this.eventBus.get("mark:submit").subscribe(async (event) => {
|
|
880
|
+
try {
|
|
881
|
+
const result = await this.http.markAnnotation(rUri, {
|
|
882
|
+
motivation: event.motivation,
|
|
883
|
+
target: { source: rUri, selector: event.selector },
|
|
884
|
+
body: event.body
|
|
885
|
+
}, { auth: getToken() });
|
|
886
|
+
this.eventBus.get("mark:created").next({ annotationId: annotationId(result.annotationId) });
|
|
887
|
+
} catch (error) {
|
|
888
|
+
this.eventBus.get("mark:create-failed").next({ error });
|
|
889
|
+
}
|
|
890
|
+
})
|
|
891
|
+
);
|
|
892
|
+
sub.add(
|
|
893
|
+
this.eventBus.get("mark:delete").subscribe(async (event) => {
|
|
894
|
+
try {
|
|
895
|
+
await this.http.deleteAnnotation(rUri, event.annotationId, { auth: getToken() });
|
|
896
|
+
this.eventBus.get("mark:deleted").next({ annotationId: event.annotationId });
|
|
897
|
+
} catch (error) {
|
|
898
|
+
this.eventBus.get("mark:delete-failed").next({ error });
|
|
899
|
+
}
|
|
900
|
+
})
|
|
901
|
+
);
|
|
902
|
+
sub.add(
|
|
903
|
+
this.eventBus.get("mark:assist-request").subscribe(async (event) => {
|
|
904
|
+
assistAbort?.abort();
|
|
905
|
+
assistAbort = new AbortController();
|
|
906
|
+
const opts = { auth: getToken(), eventBus: this.eventBus };
|
|
907
|
+
const { motivation, options } = event;
|
|
908
|
+
try {
|
|
909
|
+
if (motivation === "tagging") {
|
|
910
|
+
const { schemaId, categories } = options;
|
|
911
|
+
if (!schemaId || !categories?.length) throw new Error("Tag assist requires schemaId and categories");
|
|
912
|
+
this.sse.markTags(rUri, { schemaId, categories }, opts);
|
|
913
|
+
} else if (motivation === "linking") {
|
|
914
|
+
const { entityTypes, includeDescriptiveReferences } = options;
|
|
915
|
+
if (!entityTypes?.length) throw new Error("Reference assist requires entityTypes");
|
|
916
|
+
this.sse.markReferences(rUri, {
|
|
917
|
+
entityTypes,
|
|
918
|
+
includeDescriptiveReferences: includeDescriptiveReferences ?? false
|
|
919
|
+
}, opts);
|
|
920
|
+
} else if (motivation === "highlighting") {
|
|
921
|
+
this.sse.markHighlights(rUri, { instructions: options.instructions, density: options.density }, opts);
|
|
922
|
+
} else if (motivation === "assessing") {
|
|
923
|
+
this.sse.markAssessments(rUri, {
|
|
924
|
+
instructions: options.instructions,
|
|
925
|
+
tone: options.tone,
|
|
926
|
+
density: options.density,
|
|
927
|
+
language: options.language
|
|
928
|
+
}, opts);
|
|
929
|
+
} else if (motivation === "commenting") {
|
|
930
|
+
this.sse.markComments(rUri, {
|
|
931
|
+
instructions: options.instructions,
|
|
932
|
+
tone: options.tone,
|
|
933
|
+
density: options.density,
|
|
934
|
+
language: options.language
|
|
935
|
+
}, opts);
|
|
936
|
+
}
|
|
937
|
+
} catch (error) {
|
|
938
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
939
|
+
this.eventBus.get("mark:assist-cancelled").next(void 0);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
})
|
|
943
|
+
);
|
|
944
|
+
sub.add(
|
|
945
|
+
this.eventBus.get("job:cancel-requested").subscribe((event) => {
|
|
946
|
+
if (event.jobType === "annotation") {
|
|
947
|
+
assistAbort?.abort();
|
|
948
|
+
assistAbort = null;
|
|
949
|
+
}
|
|
950
|
+
})
|
|
951
|
+
);
|
|
952
|
+
sub.add(new Subscription(() => {
|
|
953
|
+
assistAbort?.abort();
|
|
954
|
+
}));
|
|
955
|
+
return sub;
|
|
956
|
+
}
|
|
957
|
+
// ─── gatherContext flow ─────────────────────────────────────────────────────
|
|
958
|
+
/**
|
|
959
|
+
* Activate the gather-context flow for a resource.
|
|
960
|
+
*
|
|
961
|
+
* @subscribes gather:requested — calls SSE gatherAnnotation, threads correlationId
|
|
962
|
+
* @emits gather:complete (re-emitted from SSE gather:annotation-finished)
|
|
963
|
+
*/
|
|
964
|
+
gatherContext(rUri, getToken) {
|
|
965
|
+
return this.eventBus.get("gather:requested").subscribe((event) => {
|
|
966
|
+
const { correlationId } = event;
|
|
967
|
+
const contextWindow = event.options?.contextWindow ?? 2e3;
|
|
968
|
+
const finishedSub = this.eventBus.get("gather:annotation-finished").subscribe((finishedEvent) => {
|
|
969
|
+
if (finishedEvent.correlationId !== correlationId) return;
|
|
970
|
+
finishedSub.unsubscribe();
|
|
971
|
+
failedSub.unsubscribe();
|
|
972
|
+
this.eventBus.get("gather:complete").next({
|
|
973
|
+
correlationId,
|
|
974
|
+
annotationId: finishedEvent.annotationId,
|
|
975
|
+
response: finishedEvent.response
|
|
976
|
+
});
|
|
977
|
+
});
|
|
978
|
+
const failedSub = this.eventBus.get("gather:failed").subscribe((failedEvent) => {
|
|
979
|
+
if (failedEvent.correlationId !== correlationId) return;
|
|
980
|
+
finishedSub.unsubscribe();
|
|
981
|
+
failedSub.unsubscribe();
|
|
982
|
+
});
|
|
983
|
+
this.sse.gatherAnnotation(
|
|
984
|
+
rUri,
|
|
985
|
+
event.annotationId,
|
|
986
|
+
{ contextWindow, correlationId },
|
|
987
|
+
{ auth: getToken(), eventBus: this.eventBus }
|
|
988
|
+
);
|
|
989
|
+
});
|
|
990
|
+
}
|
|
991
|
+
// ─── resourceEvents flow ───────────────────────────────────────────────────
|
|
992
|
+
/**
|
|
993
|
+
* Open the long-lived resource-events SSE stream.
|
|
994
|
+
* Returns a Subscription whose teardown closes the stream.
|
|
995
|
+
*/
|
|
996
|
+
resourceEvents(rUri, getToken) {
|
|
997
|
+
const stream = this.sse.resourceEvents(rUri, {
|
|
998
|
+
auth: getToken(),
|
|
999
|
+
eventBus: this.eventBus
|
|
1000
|
+
});
|
|
1001
|
+
return new Subscription(() => stream.close());
|
|
1002
|
+
}
|
|
1003
|
+
// ─── attentionStream flow ──────────────────────────────────────────────────
|
|
1004
|
+
/**
|
|
1005
|
+
* Open the long-lived participant attention SSE stream.
|
|
1006
|
+
* Returns a Subscription whose teardown closes the stream.
|
|
1007
|
+
*/
|
|
1008
|
+
attentionStream(getToken) {
|
|
1009
|
+
const stream = this.sse.attentionStream({
|
|
1010
|
+
auth: getToken(),
|
|
1011
|
+
eventBus: this.eventBus
|
|
1012
|
+
});
|
|
1013
|
+
return new Subscription(() => stream.close());
|
|
1014
|
+
}
|
|
1015
|
+
};
|
|
1016
|
+
var ResourceStore = class {
|
|
1017
|
+
constructor(http, eventBus) {
|
|
1018
|
+
this.http = http;
|
|
1019
|
+
eventBus.get("yield:created").subscribe((event) => {
|
|
1020
|
+
this.fetchDetail(event.resourceId);
|
|
1021
|
+
this.invalidateLists();
|
|
1022
|
+
});
|
|
1023
|
+
eventBus.get("yield:updated").subscribe((event) => {
|
|
1024
|
+
this.invalidateDetail(event.resourceId);
|
|
1025
|
+
this.invalidateLists();
|
|
1026
|
+
});
|
|
1027
|
+
eventBus.get("mark:archived").subscribe((event) => {
|
|
1028
|
+
if (event.resourceId) {
|
|
1029
|
+
this.invalidateDetail(event.resourceId);
|
|
1030
|
+
this.invalidateLists();
|
|
1031
|
+
}
|
|
1032
|
+
});
|
|
1033
|
+
eventBus.get("mark:unarchived").subscribe((event) => {
|
|
1034
|
+
if (event.resourceId) {
|
|
1035
|
+
this.invalidateDetail(event.resourceId);
|
|
1036
|
+
this.invalidateLists();
|
|
1037
|
+
}
|
|
1038
|
+
});
|
|
1039
|
+
eventBus.get("mark:entity-tag-added").subscribe((event) => {
|
|
1040
|
+
if (event.resourceId) {
|
|
1041
|
+
this.invalidateDetail(event.resourceId);
|
|
1042
|
+
}
|
|
1043
|
+
});
|
|
1044
|
+
eventBus.get("mark:entity-tag-removed").subscribe((event) => {
|
|
1045
|
+
if (event.resourceId) {
|
|
1046
|
+
this.invalidateDetail(event.resourceId);
|
|
1047
|
+
}
|
|
1048
|
+
});
|
|
1049
|
+
}
|
|
1050
|
+
/** Cache of individual resource details, keyed by ResourceId */
|
|
1051
|
+
detail$ = new BehaviorSubject(/* @__PURE__ */ new Map());
|
|
1052
|
+
/** Cache of list responses, keyed by a serialized options string */
|
|
1053
|
+
list$ = new BehaviorSubject(/* @__PURE__ */ new Map());
|
|
1054
|
+
/** Track in-flight fetches to avoid duplicate requests */
|
|
1055
|
+
fetchingDetail = /* @__PURE__ */ new Set();
|
|
1056
|
+
fetchingList = /* @__PURE__ */ new Set();
|
|
1057
|
+
/** Memoized Observables — same instance returned for the same key */
|
|
1058
|
+
detailObs$ = /* @__PURE__ */ new Map();
|
|
1059
|
+
listObs$ = /* @__PURE__ */ new Map();
|
|
1060
|
+
/** Mutable token getter — updated from the React layer when auth changes */
|
|
1061
|
+
getToken = () => void 0;
|
|
1062
|
+
/** Update the token getter (called from React when auth token changes) */
|
|
1063
|
+
setTokenGetter(getter) {
|
|
1064
|
+
this.getToken = getter;
|
|
1065
|
+
}
|
|
1066
|
+
/**
|
|
1067
|
+
* Get a single resource by ID as an Observable.
|
|
1068
|
+
* Triggers a fetch if not cached.
|
|
1069
|
+
*/
|
|
1070
|
+
get(id) {
|
|
1071
|
+
if (!this.detail$.value.has(id) && !this.fetchingDetail.has(id)) {
|
|
1072
|
+
this.fetchDetail(id);
|
|
1073
|
+
}
|
|
1074
|
+
let obs = this.detailObs$.get(id);
|
|
1075
|
+
if (!obs) {
|
|
1076
|
+
obs = this.detail$.pipe(map((m) => m.get(id)), distinctUntilChanged());
|
|
1077
|
+
this.detailObs$.set(id, obs);
|
|
1078
|
+
}
|
|
1079
|
+
return obs;
|
|
1080
|
+
}
|
|
1081
|
+
/**
|
|
1082
|
+
* List resources as an Observable.
|
|
1083
|
+
* Triggers a fetch if not cached.
|
|
1084
|
+
*/
|
|
1085
|
+
list(options) {
|
|
1086
|
+
const key = JSON.stringify(options ?? {});
|
|
1087
|
+
if (!this.list$.value.has(key) && !this.fetchingList.has(key)) {
|
|
1088
|
+
this.fetchList(key, options);
|
|
1089
|
+
}
|
|
1090
|
+
let obs = this.listObs$.get(key);
|
|
1091
|
+
if (!obs) {
|
|
1092
|
+
obs = this.list$.pipe(map((m) => m.get(key)), distinctUntilChanged());
|
|
1093
|
+
this.listObs$.set(key, obs);
|
|
1094
|
+
}
|
|
1095
|
+
return obs;
|
|
1096
|
+
}
|
|
1097
|
+
/** Invalidate and re-fetch a specific resource detail */
|
|
1098
|
+
invalidateDetail(id) {
|
|
1099
|
+
const next = new Map(this.detail$.value);
|
|
1100
|
+
next.delete(id);
|
|
1101
|
+
this.detail$.next(next);
|
|
1102
|
+
this.fetchDetail(id);
|
|
1103
|
+
}
|
|
1104
|
+
/** Remove all list caches (triggers re-fetch on next subscribe) */
|
|
1105
|
+
invalidateLists() {
|
|
1106
|
+
this.list$.next(/* @__PURE__ */ new Map());
|
|
1107
|
+
}
|
|
1108
|
+
async fetchDetail(id) {
|
|
1109
|
+
if (this.fetchingDetail.has(id)) return;
|
|
1110
|
+
this.fetchingDetail.add(id);
|
|
1111
|
+
try {
|
|
1112
|
+
const resource = await this.http.browseResource(id, { auth: this.getToken() });
|
|
1113
|
+
const next = new Map(this.detail$.value);
|
|
1114
|
+
next.set(id, resource);
|
|
1115
|
+
this.detail$.next(next);
|
|
1116
|
+
} catch {
|
|
1117
|
+
} finally {
|
|
1118
|
+
this.fetchingDetail.delete(id);
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
async fetchList(key, options) {
|
|
1122
|
+
if (this.fetchingList.has(key)) return;
|
|
1123
|
+
this.fetchingList.add(key);
|
|
1124
|
+
try {
|
|
1125
|
+
const result = await this.http.browseResources(options?.limit, options?.archived, void 0, { auth: this.getToken() });
|
|
1126
|
+
const next = new Map(this.list$.value);
|
|
1127
|
+
next.set(key, result);
|
|
1128
|
+
this.list$.next(next);
|
|
1129
|
+
} catch {
|
|
1130
|
+
} finally {
|
|
1131
|
+
this.fetchingList.delete(key);
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
};
|
|
1135
|
+
var AnnotationStore = class {
|
|
1136
|
+
constructor(http, eventBus) {
|
|
1137
|
+
this.http = http;
|
|
1138
|
+
eventBus.get("mark:deleted").subscribe((event) => {
|
|
1139
|
+
this.removeFromDetailCache(event.annotationId);
|
|
1140
|
+
});
|
|
1141
|
+
eventBus.get("mark:added").subscribe((event) => {
|
|
1142
|
+
if (event.resourceId) {
|
|
1143
|
+
this.invalidateList(event.resourceId);
|
|
1144
|
+
}
|
|
1145
|
+
});
|
|
1146
|
+
eventBus.get("mark:removed").subscribe((event) => {
|
|
1147
|
+
if (event.resourceId) {
|
|
1148
|
+
this.invalidateList(event.resourceId);
|
|
1149
|
+
}
|
|
1150
|
+
this.invalidateDetail(event.payload.annotationId);
|
|
1151
|
+
});
|
|
1152
|
+
eventBus.get("mark:body-updated").subscribe((event) => {
|
|
1153
|
+
if (event.resourceId) {
|
|
1154
|
+
this.invalidateList(event.resourceId);
|
|
1155
|
+
}
|
|
1156
|
+
this.invalidateDetail(event.payload.annotationId);
|
|
1157
|
+
});
|
|
1158
|
+
eventBus.get("mark:entity-tag-added").subscribe((event) => {
|
|
1159
|
+
if (event.resourceId) {
|
|
1160
|
+
this.invalidateList(event.resourceId);
|
|
1161
|
+
}
|
|
1162
|
+
});
|
|
1163
|
+
eventBus.get("mark:entity-tag-removed").subscribe((event) => {
|
|
1164
|
+
if (event.resourceId) {
|
|
1165
|
+
this.invalidateList(event.resourceId);
|
|
1166
|
+
}
|
|
1167
|
+
});
|
|
1168
|
+
}
|
|
1169
|
+
/** Annotation list responses keyed by ResourceId */
|
|
1170
|
+
list$ = new BehaviorSubject(/* @__PURE__ */ new Map());
|
|
1171
|
+
/** Individual annotation details keyed by AnnotationId */
|
|
1172
|
+
detail$ = new BehaviorSubject(/* @__PURE__ */ new Map());
|
|
1173
|
+
/** Track in-flight fetches */
|
|
1174
|
+
fetchingList = /* @__PURE__ */ new Set();
|
|
1175
|
+
fetchingDetail = /* @__PURE__ */ new Set();
|
|
1176
|
+
/** Memoized Observables — same instance returned for the same key */
|
|
1177
|
+
listObs$ = /* @__PURE__ */ new Map();
|
|
1178
|
+
detailObs$ = /* @__PURE__ */ new Map();
|
|
1179
|
+
/** Mutable token getter — updated from the React layer when auth changes */
|
|
1180
|
+
getToken = () => void 0;
|
|
1181
|
+
/** Update the token getter (called from React when auth token changes) */
|
|
1182
|
+
setTokenGetter(getter) {
|
|
1183
|
+
this.getToken = getter;
|
|
1184
|
+
}
|
|
1185
|
+
/**
|
|
1186
|
+
* Get annotations for a resource as an Observable.
|
|
1187
|
+
* Triggers a fetch if not cached.
|
|
1188
|
+
*/
|
|
1189
|
+
listForResource(resourceId) {
|
|
1190
|
+
if (!this.list$.value.has(resourceId) && !this.fetchingList.has(resourceId)) {
|
|
1191
|
+
this.fetchList(resourceId);
|
|
1192
|
+
}
|
|
1193
|
+
let obs = this.listObs$.get(resourceId);
|
|
1194
|
+
if (!obs) {
|
|
1195
|
+
obs = this.list$.pipe(map((m) => m.get(resourceId)), distinctUntilChanged());
|
|
1196
|
+
this.listObs$.set(resourceId, obs);
|
|
1197
|
+
}
|
|
1198
|
+
return obs;
|
|
1199
|
+
}
|
|
1200
|
+
/**
|
|
1201
|
+
* Get a single annotation detail as an Observable.
|
|
1202
|
+
* Triggers a fetch if not cached.
|
|
1203
|
+
*/
|
|
1204
|
+
get(resourceId, annotationId) {
|
|
1205
|
+
if (!this.detail$.value.has(annotationId) && !this.fetchingDetail.has(annotationId)) {
|
|
1206
|
+
this.fetchDetail(resourceId, annotationId);
|
|
1207
|
+
}
|
|
1208
|
+
let obs = this.detailObs$.get(annotationId);
|
|
1209
|
+
if (!obs) {
|
|
1210
|
+
obs = this.detail$.pipe(map((m) => m.get(annotationId)), distinctUntilChanged());
|
|
1211
|
+
this.detailObs$.set(annotationId, obs);
|
|
1212
|
+
}
|
|
1213
|
+
return obs;
|
|
1214
|
+
}
|
|
1215
|
+
/** Invalidate and re-fetch a resource's annotation list */
|
|
1216
|
+
invalidateList(resourceId) {
|
|
1217
|
+
const next = new Map(this.list$.value);
|
|
1218
|
+
next.delete(resourceId);
|
|
1219
|
+
this.list$.next(next);
|
|
1220
|
+
this.fetchList(resourceId);
|
|
1221
|
+
}
|
|
1222
|
+
/** Invalidate a single annotation detail (re-fetched on next subscribe) */
|
|
1223
|
+
invalidateDetail(annotationId) {
|
|
1224
|
+
const next = new Map(this.detail$.value);
|
|
1225
|
+
next.delete(annotationId);
|
|
1226
|
+
this.detail$.next(next);
|
|
1227
|
+
}
|
|
1228
|
+
/** Remove an annotation from the detail cache without re-fetching */
|
|
1229
|
+
removeFromDetailCache(annotationId) {
|
|
1230
|
+
const next = new Map(this.detail$.value);
|
|
1231
|
+
next.delete(annotationId);
|
|
1232
|
+
this.detail$.next(next);
|
|
1233
|
+
}
|
|
1234
|
+
async fetchList(resourceId) {
|
|
1235
|
+
if (this.fetchingList.has(resourceId)) return;
|
|
1236
|
+
this.fetchingList.add(resourceId);
|
|
1237
|
+
try {
|
|
1238
|
+
const result = await this.http.browseAnnotations(resourceId, void 0, { auth: this.getToken() });
|
|
1239
|
+
const next = new Map(this.list$.value);
|
|
1240
|
+
next.set(resourceId, result);
|
|
1241
|
+
this.list$.next(next);
|
|
1242
|
+
} catch {
|
|
1243
|
+
} finally {
|
|
1244
|
+
this.fetchingList.delete(resourceId);
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
async fetchDetail(resourceId, annotationId) {
|
|
1248
|
+
if (this.fetchingDetail.has(annotationId)) return;
|
|
1249
|
+
this.fetchingDetail.add(annotationId);
|
|
1250
|
+
try {
|
|
1251
|
+
const result = await this.http.browseAnnotation(resourceId, annotationId, { auth: this.getToken() });
|
|
1252
|
+
const next = new Map(this.detail$.value);
|
|
1253
|
+
next.set(annotationId, result);
|
|
1254
|
+
this.detail$.next(next);
|
|
1255
|
+
} catch {
|
|
1256
|
+
} finally {
|
|
1257
|
+
this.fetchingDetail.delete(annotationId);
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
};
|
|
769
1261
|
|
|
770
1262
|
// src/client.ts
|
|
771
1263
|
var APIError = class extends Error {
|
|
@@ -780,29 +1272,30 @@ var APIError = class extends Error {
|
|
|
780
1272
|
var SemiontApiClient = class {
|
|
781
1273
|
http;
|
|
782
1274
|
baseUrl;
|
|
1275
|
+
/** The workspace-scoped EventBus this client was constructed with. */
|
|
1276
|
+
eventBus;
|
|
783
1277
|
logger;
|
|
784
1278
|
/**
|
|
785
1279
|
* SSE streaming client for real-time operations
|
|
786
1280
|
*
|
|
787
1281
|
* Separate from the main HTTP client to clearly mark streaming endpoints.
|
|
788
1282
|
* Uses native fetch() instead of ky for SSE support.
|
|
789
|
-
*
|
|
790
|
-
* @example
|
|
791
|
-
* ```typescript
|
|
792
|
-
* const stream = client.sse.detectAnnotations(
|
|
793
|
-
* resourceId,
|
|
794
|
-
* { entityTypes: ['Person', 'Organization'] },
|
|
795
|
-
* { auth: accessToken }
|
|
796
|
-
* );
|
|
797
|
-
*
|
|
798
|
-
* stream.onProgress((p) => console.log(p.message));
|
|
799
|
-
* stream.onComplete((r) => console.log(`Found ${r.foundCount} entities`));
|
|
800
|
-
* stream.close();
|
|
801
|
-
* ```
|
|
802
1283
|
*/
|
|
803
1284
|
sse;
|
|
1285
|
+
/**
|
|
1286
|
+
* Framework-agnostic flow orchestration.
|
|
1287
|
+
* Each method returns a Subscription; call .unsubscribe() to tear down.
|
|
1288
|
+
*/
|
|
1289
|
+
flows;
|
|
1290
|
+
/**
|
|
1291
|
+
* Per-workspace observable stores for entity data.
|
|
1292
|
+
* Call stores.resources.setTokenGetter() / stores.annotations.setTokenGetter()
|
|
1293
|
+
* from the React layer when the auth token changes.
|
|
1294
|
+
*/
|
|
1295
|
+
stores;
|
|
804
1296
|
constructor(config) {
|
|
805
|
-
const { baseUrl, timeout: timeout2 = 3e4, retry = 2, logger } = config;
|
|
1297
|
+
const { baseUrl, eventBus, timeout: timeout2 = 3e4, retry = 2, logger } = config;
|
|
1298
|
+
this.eventBus = eventBus;
|
|
806
1299
|
this.logger = logger;
|
|
807
1300
|
this.baseUrl = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
808
1301
|
this.http = ky.create({
|
|
@@ -811,18 +1304,14 @@ var SemiontApiClient = class {
|
|
|
811
1304
|
credentials: "include",
|
|
812
1305
|
hooks: {
|
|
813
1306
|
beforeRequest: [
|
|
814
|
-
(request
|
|
815
|
-
const auth = options.auth;
|
|
816
|
-
if (auth) {
|
|
817
|
-
request.headers.set("Authorization", `Bearer ${auth}`);
|
|
818
|
-
}
|
|
1307
|
+
(request) => {
|
|
819
1308
|
if (this.logger) {
|
|
820
1309
|
this.logger.debug("HTTP Request", {
|
|
821
1310
|
type: "http_request",
|
|
822
1311
|
url: request.url,
|
|
823
1312
|
method: request.method,
|
|
824
1313
|
timestamp: Date.now(),
|
|
825
|
-
hasAuth:
|
|
1314
|
+
hasAuth: request.headers.has("Authorization")
|
|
826
1315
|
});
|
|
827
1316
|
}
|
|
828
1317
|
}
|
|
@@ -872,6 +1361,14 @@ var SemiontApiClient = class {
|
|
|
872
1361
|
baseUrl: this.baseUrl,
|
|
873
1362
|
logger: this.logger
|
|
874
1363
|
});
|
|
1364
|
+
this.flows = new FlowEngine(this.eventBus, this.sse, this);
|
|
1365
|
+
this.stores = {
|
|
1366
|
+
resources: new ResourceStore(this, this.eventBus),
|
|
1367
|
+
annotations: new AnnotationStore(this, this.eventBus)
|
|
1368
|
+
};
|
|
1369
|
+
}
|
|
1370
|
+
authHeaders(options) {
|
|
1371
|
+
return options?.auth ? { Authorization: `Bearer ${options.auth}` } : {};
|
|
875
1372
|
}
|
|
876
1373
|
// ============================================================================
|
|
877
1374
|
// AUTHENTICATION
|
|
@@ -879,28 +1376,30 @@ var SemiontApiClient = class {
|
|
|
879
1376
|
async authenticatePassword(email, password, options) {
|
|
880
1377
|
return this.http.post(`${this.baseUrl}/api/tokens/password`, {
|
|
881
1378
|
json: { email, password },
|
|
882
|
-
|
|
883
|
-
auth: options?.auth
|
|
1379
|
+
headers: this.authHeaders(options)
|
|
884
1380
|
}).json();
|
|
885
1381
|
}
|
|
886
1382
|
async refreshToken(token, options) {
|
|
887
1383
|
return this.http.post(`${this.baseUrl}/api/tokens/refresh`, {
|
|
888
1384
|
json: { refreshToken: token },
|
|
889
|
-
|
|
890
|
-
auth: options?.auth
|
|
1385
|
+
headers: this.authHeaders(options)
|
|
891
1386
|
}).json();
|
|
892
1387
|
}
|
|
893
1388
|
async authenticateGoogle(credential, options) {
|
|
894
1389
|
return this.http.post(`${this.baseUrl}/api/tokens/google`, {
|
|
895
1390
|
json: { credential },
|
|
896
|
-
|
|
897
|
-
auth: options?.auth
|
|
1391
|
+
headers: this.authHeaders(options)
|
|
898
1392
|
}).json();
|
|
899
1393
|
}
|
|
900
1394
|
async generateMCPToken(options) {
|
|
901
1395
|
return this.http.post(`${this.baseUrl}/api/tokens/mcp-generate`, {
|
|
902
|
-
|
|
903
|
-
|
|
1396
|
+
headers: this.authHeaders(options)
|
|
1397
|
+
}).json();
|
|
1398
|
+
}
|
|
1399
|
+
async getMediaToken(resourceId, options) {
|
|
1400
|
+
return this.http.post(`${this.baseUrl}/api/tokens/media`, {
|
|
1401
|
+
json: { resourceId },
|
|
1402
|
+
headers: this.authHeaders(options)
|
|
904
1403
|
}).json();
|
|
905
1404
|
}
|
|
906
1405
|
// ============================================================================
|
|
@@ -908,21 +1407,18 @@ var SemiontApiClient = class {
|
|
|
908
1407
|
// ============================================================================
|
|
909
1408
|
async getMe(options) {
|
|
910
1409
|
return this.http.get(`${this.baseUrl}/api/users/me`, {
|
|
911
|
-
|
|
912
|
-
auth: options?.auth
|
|
1410
|
+
headers: this.authHeaders(options)
|
|
913
1411
|
}).json();
|
|
914
1412
|
}
|
|
915
1413
|
async acceptTerms(options) {
|
|
916
1414
|
return this.http.post(`${this.baseUrl}/api/users/accept-terms`, {
|
|
917
|
-
|
|
918
|
-
auth: options?.auth
|
|
1415
|
+
headers: this.authHeaders(options)
|
|
919
1416
|
}).json();
|
|
920
1417
|
}
|
|
921
1418
|
async logout(options) {
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
}
|
|
925
|
-
return this.http.post(`${this.baseUrl}/api/users/logout`).json();
|
|
1419
|
+
return this.http.post(`${this.baseUrl}/api/users/logout`, {
|
|
1420
|
+
headers: this.authHeaders(options)
|
|
1421
|
+
}).json();
|
|
926
1422
|
}
|
|
927
1423
|
// ============================================================================
|
|
928
1424
|
// RESOURCES
|
|
@@ -971,14 +1467,12 @@ var SemiontApiClient = class {
|
|
|
971
1467
|
}
|
|
972
1468
|
return this.http.post(`${this.baseUrl}/resources`, {
|
|
973
1469
|
body: formData,
|
|
974
|
-
|
|
975
|
-
auth: options?.auth
|
|
1470
|
+
headers: this.authHeaders(options)
|
|
976
1471
|
}).json();
|
|
977
1472
|
}
|
|
978
1473
|
async browseResource(id, options) {
|
|
979
1474
|
return this.http.get(`${this.baseUrl}/resources/${id}`, {
|
|
980
|
-
|
|
981
|
-
auth: options?.auth
|
|
1475
|
+
headers: this.authHeaders(options)
|
|
982
1476
|
}).json();
|
|
983
1477
|
}
|
|
984
1478
|
/**
|
|
@@ -1006,9 +1500,9 @@ var SemiontApiClient = class {
|
|
|
1006
1500
|
async getResourceRepresentation(id, options) {
|
|
1007
1501
|
const response = await this.http.get(`${this.baseUrl}/resources/${id}`, {
|
|
1008
1502
|
headers: {
|
|
1009
|
-
Accept: options?.accept || "text/plain"
|
|
1010
|
-
|
|
1011
|
-
|
|
1503
|
+
Accept: options?.accept || "text/plain",
|
|
1504
|
+
...this.authHeaders(options)
|
|
1505
|
+
}
|
|
1012
1506
|
});
|
|
1013
1507
|
const contentType = response.headers.get("content-type") || "application/octet-stream";
|
|
1014
1508
|
const data = await response.arrayBuffer();
|
|
@@ -1053,9 +1547,9 @@ var SemiontApiClient = class {
|
|
|
1053
1547
|
async getResourceRepresentationStream(id, options) {
|
|
1054
1548
|
const response = await this.http.get(`${this.baseUrl}/resources/${id}`, {
|
|
1055
1549
|
headers: {
|
|
1056
|
-
Accept: options?.accept || "text/plain"
|
|
1057
|
-
|
|
1058
|
-
|
|
1550
|
+
Accept: options?.accept || "text/plain",
|
|
1551
|
+
...this.authHeaders(options)
|
|
1552
|
+
}
|
|
1059
1553
|
});
|
|
1060
1554
|
const contentType = response.headers.get("content-type") || "application/octet-stream";
|
|
1061
1555
|
if (!response.body) {
|
|
@@ -1070,46 +1564,39 @@ var SemiontApiClient = class {
|
|
|
1070
1564
|
if (query) searchParams.append("q", query);
|
|
1071
1565
|
return this.http.get(`${this.baseUrl}/resources`, {
|
|
1072
1566
|
searchParams,
|
|
1073
|
-
|
|
1074
|
-
auth: options?.auth
|
|
1567
|
+
headers: this.authHeaders(options)
|
|
1075
1568
|
}).json();
|
|
1076
1569
|
}
|
|
1077
1570
|
async updateResource(id, data, options) {
|
|
1078
1571
|
await this.http.patch(`${this.baseUrl}/resources/${id}`, {
|
|
1079
1572
|
json: data,
|
|
1080
|
-
|
|
1081
|
-
auth: options?.auth
|
|
1573
|
+
headers: this.authHeaders(options)
|
|
1082
1574
|
}).text();
|
|
1083
1575
|
}
|
|
1084
1576
|
async getResourceEvents(id, options) {
|
|
1085
1577
|
return this.http.get(`${this.baseUrl}/resources/${id}/events`, {
|
|
1086
|
-
|
|
1087
|
-
auth: options?.auth
|
|
1578
|
+
headers: this.authHeaders(options)
|
|
1088
1579
|
}).json();
|
|
1089
1580
|
}
|
|
1090
1581
|
async browseReferences(id, options) {
|
|
1091
1582
|
return this.http.get(`${this.baseUrl}/resources/${id}/referenced-by`, {
|
|
1092
|
-
|
|
1093
|
-
auth: options?.auth
|
|
1583
|
+
headers: this.authHeaders(options)
|
|
1094
1584
|
}).json();
|
|
1095
1585
|
}
|
|
1096
1586
|
async generateCloneToken(id, options) {
|
|
1097
1587
|
return this.http.post(`${this.baseUrl}/resources/${id}/clone-with-token`, {
|
|
1098
|
-
|
|
1099
|
-
auth: options?.auth
|
|
1588
|
+
headers: this.authHeaders(options)
|
|
1100
1589
|
}).json();
|
|
1101
1590
|
}
|
|
1102
1591
|
async getResourceByToken(token, options) {
|
|
1103
1592
|
return this.http.get(`${this.baseUrl}/api/clone-tokens/${token}`, {
|
|
1104
|
-
|
|
1105
|
-
auth: options?.auth
|
|
1593
|
+
headers: this.authHeaders(options)
|
|
1106
1594
|
}).json();
|
|
1107
1595
|
}
|
|
1108
1596
|
async createResourceFromToken(data, options) {
|
|
1109
1597
|
return this.http.post(`${this.baseUrl}/api/clone-tokens/create-resource`, {
|
|
1110
1598
|
json: data,
|
|
1111
|
-
|
|
1112
|
-
auth: options?.auth
|
|
1599
|
+
headers: this.authHeaders(options)
|
|
1113
1600
|
}).json();
|
|
1114
1601
|
}
|
|
1115
1602
|
// ============================================================================
|
|
@@ -1118,20 +1605,17 @@ var SemiontApiClient = class {
|
|
|
1118
1605
|
async markAnnotation(id, data, options) {
|
|
1119
1606
|
return this.http.post(`${this.baseUrl}/resources/${id}/annotations`, {
|
|
1120
1607
|
json: data,
|
|
1121
|
-
|
|
1122
|
-
auth: options?.auth
|
|
1608
|
+
headers: this.authHeaders(options)
|
|
1123
1609
|
}).json();
|
|
1124
1610
|
}
|
|
1125
1611
|
async getAnnotation(id, options) {
|
|
1126
1612
|
return this.http.get(`${this.baseUrl}/annotations/${id}`, {
|
|
1127
|
-
|
|
1128
|
-
auth: options?.auth
|
|
1613
|
+
headers: this.authHeaders(options)
|
|
1129
1614
|
}).json();
|
|
1130
1615
|
}
|
|
1131
1616
|
async browseAnnotation(resourceId, annotationId, options) {
|
|
1132
1617
|
return this.http.get(`${this.baseUrl}/resources/${resourceId}/annotations/${annotationId}`, {
|
|
1133
|
-
|
|
1134
|
-
auth: options?.auth
|
|
1618
|
+
headers: this.authHeaders(options)
|
|
1135
1619
|
}).json();
|
|
1136
1620
|
}
|
|
1137
1621
|
async browseAnnotations(id, motivation, options) {
|
|
@@ -1139,29 +1623,24 @@ var SemiontApiClient = class {
|
|
|
1139
1623
|
if (motivation) searchParams.append("motivation", motivation);
|
|
1140
1624
|
return this.http.get(`${this.baseUrl}/resources/${id}/annotations`, {
|
|
1141
1625
|
searchParams,
|
|
1142
|
-
|
|
1143
|
-
auth: options?.auth
|
|
1626
|
+
headers: this.authHeaders(options)
|
|
1144
1627
|
}).json();
|
|
1145
1628
|
}
|
|
1146
1629
|
async deleteAnnotation(resourceId, annotationId, options) {
|
|
1147
1630
|
await this.http.delete(`${this.baseUrl}/resources/${resourceId}/annotations/${annotationId}`, {
|
|
1148
|
-
|
|
1149
|
-
auth: options?.auth
|
|
1631
|
+
headers: this.authHeaders(options)
|
|
1150
1632
|
});
|
|
1151
1633
|
}
|
|
1152
1634
|
async bindAnnotation(resourceId, annotationId, data, options) {
|
|
1153
1635
|
await this.http.put(`${this.baseUrl}/resources/${resourceId}/annotations/${annotationId}/body`, {
|
|
1154
1636
|
json: data,
|
|
1155
|
-
|
|
1156
|
-
auth: options?.auth
|
|
1637
|
+
headers: this.authHeaders(options)
|
|
1157
1638
|
});
|
|
1158
1639
|
}
|
|
1159
1640
|
async getAnnotationHistory(resourceId, annotationId, options) {
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
}
|
|
1164
|
-
return this.http.get(url).json();
|
|
1641
|
+
return this.http.get(`${this.baseUrl}/resources/${resourceId}/annotations/${annotationId}/history`, {
|
|
1642
|
+
headers: this.authHeaders(options)
|
|
1643
|
+
}).json();
|
|
1165
1644
|
}
|
|
1166
1645
|
// ============================================================================
|
|
1167
1646
|
// ENTITY TYPES
|
|
@@ -1169,21 +1648,18 @@ var SemiontApiClient = class {
|
|
|
1169
1648
|
async addEntityType(type, options) {
|
|
1170
1649
|
await this.http.post(`${this.baseUrl}/api/entity-types`, {
|
|
1171
1650
|
json: { tag: type },
|
|
1172
|
-
|
|
1173
|
-
auth: options?.auth
|
|
1651
|
+
headers: this.authHeaders(options)
|
|
1174
1652
|
});
|
|
1175
1653
|
}
|
|
1176
1654
|
async addEntityTypesBulk(types, options) {
|
|
1177
1655
|
await this.http.post(`${this.baseUrl}/api/entity-types/bulk`, {
|
|
1178
1656
|
json: { tags: types },
|
|
1179
|
-
|
|
1180
|
-
auth: options?.auth
|
|
1657
|
+
headers: this.authHeaders(options)
|
|
1181
1658
|
});
|
|
1182
1659
|
}
|
|
1183
1660
|
async listEntityTypes(options) {
|
|
1184
1661
|
return this.http.get(`${this.baseUrl}/api/entity-types`, {
|
|
1185
|
-
|
|
1186
|
-
auth: options?.auth
|
|
1662
|
+
headers: this.authHeaders(options)
|
|
1187
1663
|
}).json();
|
|
1188
1664
|
}
|
|
1189
1665
|
// ============================================================================
|
|
@@ -1192,8 +1668,7 @@ var SemiontApiClient = class {
|
|
|
1192
1668
|
async beckonAttention(participantId, data, options) {
|
|
1193
1669
|
return this.http.post(`${this.baseUrl}/api/participants/${participantId}/attention`, {
|
|
1194
1670
|
json: data,
|
|
1195
|
-
|
|
1196
|
-
auth: options?.auth
|
|
1671
|
+
headers: this.authHeaders(options)
|
|
1197
1672
|
}).json();
|
|
1198
1673
|
}
|
|
1199
1674
|
// ============================================================================
|
|
@@ -1201,14 +1676,12 @@ var SemiontApiClient = class {
|
|
|
1201
1676
|
// ============================================================================
|
|
1202
1677
|
async listUsers(options) {
|
|
1203
1678
|
return this.http.get(`${this.baseUrl}/api/admin/users`, {
|
|
1204
|
-
|
|
1205
|
-
auth: options?.auth
|
|
1679
|
+
headers: this.authHeaders(options)
|
|
1206
1680
|
}).json();
|
|
1207
1681
|
}
|
|
1208
1682
|
async getUserStats(options) {
|
|
1209
1683
|
return this.http.get(`${this.baseUrl}/api/admin/users/stats`, {
|
|
1210
|
-
|
|
1211
|
-
auth: options?.auth
|
|
1684
|
+
headers: this.authHeaders(options)
|
|
1212
1685
|
}).json();
|
|
1213
1686
|
}
|
|
1214
1687
|
/**
|
|
@@ -1218,14 +1691,12 @@ var SemiontApiClient = class {
|
|
|
1218
1691
|
async updateUser(id, data, options) {
|
|
1219
1692
|
return this.http.patch(`${this.baseUrl}/api/admin/users/${id}`, {
|
|
1220
1693
|
json: data,
|
|
1221
|
-
|
|
1222
|
-
auth: options?.auth
|
|
1694
|
+
headers: this.authHeaders(options)
|
|
1223
1695
|
}).json();
|
|
1224
1696
|
}
|
|
1225
1697
|
async getOAuthConfig(options) {
|
|
1226
1698
|
return this.http.get(`${this.baseUrl}/api/admin/oauth/config`, {
|
|
1227
|
-
|
|
1228
|
-
auth: options?.auth
|
|
1699
|
+
headers: this.authHeaders(options)
|
|
1229
1700
|
}).json();
|
|
1230
1701
|
}
|
|
1231
1702
|
// ============================================================================
|
|
@@ -1236,12 +1707,8 @@ var SemiontApiClient = class {
|
|
|
1236
1707
|
* Caller should use response.blob() to trigger a file download.
|
|
1237
1708
|
*/
|
|
1238
1709
|
async backupKnowledgeBase(options) {
|
|
1239
|
-
return
|
|
1240
|
-
|
|
1241
|
-
headers: {
|
|
1242
|
-
"Content-Type": "application/json",
|
|
1243
|
-
...options?.auth ? { Authorization: `Bearer ${options.auth}` } : {}
|
|
1244
|
-
}
|
|
1710
|
+
return this.http.post(`${this.baseUrl}/api/admin/exchange/backup`, {
|
|
1711
|
+
headers: this.authHeaders(options)
|
|
1245
1712
|
});
|
|
1246
1713
|
}
|
|
1247
1714
|
/**
|
|
@@ -1251,35 +1718,11 @@ var SemiontApiClient = class {
|
|
|
1251
1718
|
async restoreKnowledgeBase(file, options) {
|
|
1252
1719
|
const formData = new FormData();
|
|
1253
1720
|
formData.append("file", file);
|
|
1254
|
-
const response = await
|
|
1255
|
-
|
|
1256
|
-
headers:
|
|
1257
|
-
...options?.auth ? { Authorization: `Bearer ${options.auth}` } : {}
|
|
1258
|
-
},
|
|
1259
|
-
body: formData
|
|
1721
|
+
const response = await this.http.post(`${this.baseUrl}/api/admin/exchange/restore`, {
|
|
1722
|
+
body: formData,
|
|
1723
|
+
headers: this.authHeaders(options)
|
|
1260
1724
|
});
|
|
1261
|
-
|
|
1262
|
-
throw new Error(`Restore failed: ${response.status} ${response.statusText}`);
|
|
1263
|
-
}
|
|
1264
|
-
const reader = response.body.getReader();
|
|
1265
|
-
const decoder = new TextDecoder();
|
|
1266
|
-
let buffer = "";
|
|
1267
|
-
let finalResult = { phase: "unknown" };
|
|
1268
|
-
while (true) {
|
|
1269
|
-
const { done, value } = await reader.read();
|
|
1270
|
-
if (done) break;
|
|
1271
|
-
buffer += decoder.decode(value, { stream: true });
|
|
1272
|
-
const lines = buffer.split("\n");
|
|
1273
|
-
buffer = lines.pop();
|
|
1274
|
-
for (const line of lines) {
|
|
1275
|
-
if (line.startsWith("data: ")) {
|
|
1276
|
-
const event = JSON.parse(line.slice(6));
|
|
1277
|
-
options?.onProgress?.(event);
|
|
1278
|
-
finalResult = event;
|
|
1279
|
-
}
|
|
1280
|
-
}
|
|
1281
|
-
}
|
|
1282
|
-
return finalResult;
|
|
1725
|
+
return this.parseSSEStream(response, options?.onProgress);
|
|
1283
1726
|
}
|
|
1284
1727
|
// ============================================================================
|
|
1285
1728
|
// ADMIN — EXCHANGE (Linked Data Export/Import)
|
|
@@ -1289,13 +1732,10 @@ var SemiontApiClient = class {
|
|
|
1289
1732
|
* Caller should use response.blob() to trigger a file download.
|
|
1290
1733
|
*/
|
|
1291
1734
|
async exportKnowledgeBase(params, options) {
|
|
1292
|
-
const
|
|
1293
|
-
return
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
"Content-Type": "application/json",
|
|
1297
|
-
...options?.auth ? { Authorization: `Bearer ${options.auth}` } : {}
|
|
1298
|
-
}
|
|
1735
|
+
const searchParams = params?.includeArchived ? new URLSearchParams({ includeArchived: "true" }) : void 0;
|
|
1736
|
+
return this.http.post(`${this.baseUrl}/api/moderate/exchange/export`, {
|
|
1737
|
+
headers: this.authHeaders(options),
|
|
1738
|
+
...searchParams ? { searchParams } : {}
|
|
1299
1739
|
});
|
|
1300
1740
|
}
|
|
1301
1741
|
/**
|
|
@@ -1305,16 +1745,13 @@ var SemiontApiClient = class {
|
|
|
1305
1745
|
async importKnowledgeBase(file, options) {
|
|
1306
1746
|
const formData = new FormData();
|
|
1307
1747
|
formData.append("file", file);
|
|
1308
|
-
const response = await
|
|
1309
|
-
|
|
1310
|
-
headers:
|
|
1311
|
-
...options?.auth ? { Authorization: `Bearer ${options.auth}` } : {}
|
|
1312
|
-
},
|
|
1313
|
-
body: formData
|
|
1748
|
+
const response = await this.http.post(`${this.baseUrl}/api/moderate/exchange/import`, {
|
|
1749
|
+
body: formData,
|
|
1750
|
+
headers: this.authHeaders(options)
|
|
1314
1751
|
});
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1752
|
+
return this.parseSSEStream(response, options?.onProgress);
|
|
1753
|
+
}
|
|
1754
|
+
async parseSSEStream(response, onProgress) {
|
|
1318
1755
|
const reader = response.body.getReader();
|
|
1319
1756
|
const decoder = new TextDecoder();
|
|
1320
1757
|
let buffer = "";
|
|
@@ -1328,7 +1765,7 @@ var SemiontApiClient = class {
|
|
|
1328
1765
|
for (const line of lines) {
|
|
1329
1766
|
if (line.startsWith("data: ")) {
|
|
1330
1767
|
const event = JSON.parse(line.slice(6));
|
|
1331
|
-
|
|
1768
|
+
onProgress?.(event);
|
|
1332
1769
|
finalResult = event;
|
|
1333
1770
|
}
|
|
1334
1771
|
}
|
|
@@ -1339,10 +1776,9 @@ var SemiontApiClient = class {
|
|
|
1339
1776
|
// JOB STATUS
|
|
1340
1777
|
// ============================================================================
|
|
1341
1778
|
async getJobStatus(id, options) {
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
}
|
|
1345
|
-
return this.http.get(`${this.baseUrl}/api/jobs/${id}`).json();
|
|
1779
|
+
return this.http.get(`${this.baseUrl}/api/jobs/${id}`, {
|
|
1780
|
+
headers: this.authHeaders(options)
|
|
1781
|
+
}).json();
|
|
1346
1782
|
}
|
|
1347
1783
|
/**
|
|
1348
1784
|
* Poll a job until it completes or fails
|
|
@@ -1373,15 +1809,13 @@ var SemiontApiClient = class {
|
|
|
1373
1809
|
// ============================================================================
|
|
1374
1810
|
async healthCheck(options) {
|
|
1375
1811
|
return this.http.get(`${this.baseUrl}/api/health`, {
|
|
1376
|
-
|
|
1377
|
-
auth: options?.auth
|
|
1812
|
+
headers: this.authHeaders(options)
|
|
1378
1813
|
}).json();
|
|
1379
1814
|
}
|
|
1380
1815
|
async getStatus(options) {
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
}
|
|
1384
|
-
return this.http.get(`${this.baseUrl}/api/status`).json();
|
|
1816
|
+
return this.http.get(`${this.baseUrl}/api/status`, {
|
|
1817
|
+
headers: this.authHeaders(options)
|
|
1818
|
+
}).json();
|
|
1385
1819
|
}
|
|
1386
1820
|
async browseFiles(dirPath, sort, options) {
|
|
1387
1821
|
const searchParams = new URLSearchParams();
|
|
@@ -1389,13 +1823,12 @@ var SemiontApiClient = class {
|
|
|
1389
1823
|
if (sort) searchParams.append("sort", sort);
|
|
1390
1824
|
return this.http.get(`${this.baseUrl}/api/browse/files`, {
|
|
1391
1825
|
searchParams,
|
|
1392
|
-
|
|
1393
|
-
auth: options?.auth
|
|
1826
|
+
headers: this.authHeaders(options)
|
|
1394
1827
|
}).json();
|
|
1395
1828
|
}
|
|
1396
1829
|
};
|
|
1397
1830
|
async function eventBusRequest(eventBus, requestEvent, payload, successEvent, failureEvent, timeoutMs = 3e4) {
|
|
1398
|
-
const correlationId = payload
|
|
1831
|
+
const { correlationId } = payload;
|
|
1399
1832
|
const result$ = merge(
|
|
1400
1833
|
eventBus.get(successEvent).pipe(
|
|
1401
1834
|
filter((e) => e.correlationId === correlationId),
|
|
@@ -1596,7 +2029,7 @@ var EventBusClient = class {
|
|
|
1596
2029
|
const result$ = merge(
|
|
1597
2030
|
this.eventBus.get("gather:resource-complete").pipe(
|
|
1598
2031
|
filter((e) => e.correlationId === correlationId),
|
|
1599
|
-
map((e) => ({ ok: true, response: e.
|
|
2032
|
+
map((e) => ({ ok: true, response: e.response }))
|
|
1600
2033
|
),
|
|
1601
2034
|
this.eventBus.get("gather:resource-failed").pipe(
|
|
1602
2035
|
filter((e) => e.correlationId === correlationId),
|
|
@@ -1624,11 +2057,11 @@ var EventBusClient = class {
|
|
|
1624
2057
|
const result$ = merge(
|
|
1625
2058
|
this.eventBus.get("match:search-results").pipe(
|
|
1626
2059
|
filter((e) => e.correlationId === correlationId),
|
|
1627
|
-
map((e) => ({ ok: true,
|
|
2060
|
+
map((e) => ({ ok: true, response: e.response }))
|
|
1628
2061
|
),
|
|
1629
2062
|
this.eventBus.get("match:search-failed").pipe(
|
|
1630
2063
|
filter((e) => e.correlationId === correlationId),
|
|
1631
|
-
map((e) => ({ ok: false, error: e.error }))
|
|
2064
|
+
map((e) => ({ ok: false, error: new Error(e.error) }))
|
|
1632
2065
|
)
|
|
1633
2066
|
).pipe(take(1), timeout(this.timeoutMs));
|
|
1634
2067
|
const resultPromise = firstValueFrom(result$);
|
|
@@ -1658,7 +2091,7 @@ var EventBusClient = class {
|
|
|
1658
2091
|
if (!result.ok) {
|
|
1659
2092
|
throw result.error;
|
|
1660
2093
|
}
|
|
1661
|
-
return result.
|
|
2094
|
+
return result.response;
|
|
1662
2095
|
}
|
|
1663
2096
|
};
|
|
1664
2097
|
function getBodySource(body) {
|
|
@@ -2303,14 +2736,14 @@ function isValidEmail(email) {
|
|
|
2303
2736
|
|
|
2304
2737
|
// src/mime-utils.ts
|
|
2305
2738
|
function getExtensionForMimeType(mimeType) {
|
|
2306
|
-
const
|
|
2739
|
+
const map4 = {
|
|
2307
2740
|
"text/plain": "txt",
|
|
2308
2741
|
"text/markdown": "md",
|
|
2309
2742
|
"image/png": "png",
|
|
2310
2743
|
"image/jpeg": "jpg",
|
|
2311
2744
|
"application/pdf": "pdf"
|
|
2312
2745
|
};
|
|
2313
|
-
return
|
|
2746
|
+
return map4[mimeType] || "dat";
|
|
2314
2747
|
}
|
|
2315
2748
|
function isImageMimeType(mimeType) {
|
|
2316
2749
|
return mimeType === "image/png" || mimeType === "image/jpeg";
|
|
@@ -2331,6 +2764,6 @@ function getMimeCategory(mimeType) {
|
|
|
2331
2764
|
return "unsupported";
|
|
2332
2765
|
}
|
|
2333
2766
|
|
|
2334
|
-
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 };
|
|
2767
|
+
export { APIError, AnnotationStore, EventBusClient, FlowEngine, JWTTokenSchema, LOCALES, ResourceStore, 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 };
|
|
2335
2768
|
//# sourceMappingURL=index.js.map
|
|
2336
2769
|
//# sourceMappingURL=index.js.map
|