@syfthub/sdk 0.2.0 → 0.2.1
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.cjs +140 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +53 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.js +140 -28
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2769,28 +2769,125 @@ var GenerationError = class extends exports.SyftHubError {
|
|
|
2769
2769
|
}
|
|
2770
2770
|
};
|
|
2771
2771
|
var SyftAIResource = class {
|
|
2772
|
-
|
|
2772
|
+
/**
|
|
2773
|
+
* @param http - Hub HTTP client, used to mint satellite tokens and settle
|
|
2774
|
+
* MPP payments. Endpoint queries themselves use direct `fetch`, since the
|
|
2775
|
+
* SyftAI-Space URL is arbitrary and not the Hub base URL.
|
|
2776
|
+
*/
|
|
2777
|
+
constructor(http) {
|
|
2778
|
+
this.http = http;
|
|
2779
|
+
}
|
|
2780
|
+
/**
|
|
2781
|
+
* Mint a satellite token for `audience` (the endpoint owner's username).
|
|
2782
|
+
*
|
|
2783
|
+
* Mirrors the aggregator's token coordination layer: try an authenticated
|
|
2784
|
+
* token first, then fall back to a guest token. Returns `undefined` if both
|
|
2785
|
+
* fail, so the caller can still attempt an unauthenticated request.
|
|
2786
|
+
*/
|
|
2787
|
+
async mintSatelliteToken(audience) {
|
|
2788
|
+
if (this.http.hasTokens()) {
|
|
2789
|
+
try {
|
|
2790
|
+
const res = await this.http.get("/api/v1/token", {
|
|
2791
|
+
aud: audience
|
|
2792
|
+
});
|
|
2793
|
+
if (res.targetToken) return res.targetToken;
|
|
2794
|
+
} catch {
|
|
2795
|
+
}
|
|
2796
|
+
}
|
|
2797
|
+
try {
|
|
2798
|
+
const res = await this.http.get(
|
|
2799
|
+
"/api/v1/token/guest",
|
|
2800
|
+
{ aud: audience },
|
|
2801
|
+
{ includeAuth: false }
|
|
2802
|
+
);
|
|
2803
|
+
return res.targetToken;
|
|
2804
|
+
} catch {
|
|
2805
|
+
return void 0;
|
|
2806
|
+
}
|
|
2807
|
+
}
|
|
2808
|
+
/**
|
|
2809
|
+
* Pay an MPP `402` challenge via the Hub wallet, returning an X-Payment credential.
|
|
2810
|
+
*
|
|
2811
|
+
* Mirrors the aggregator's `handleMppPayment`: the `WWW-Authenticate`
|
|
2812
|
+
* challenge is forwarded verbatim to the Hub's `/api/v1/wallet/pay`, which
|
|
2813
|
+
* parses it and returns an `x_payment` string to attach to a retry.
|
|
2814
|
+
*/
|
|
2815
|
+
async payMpp(wwwAuthenticate, slug) {
|
|
2816
|
+
if (!wwwAuthenticate) return void 0;
|
|
2817
|
+
const res = await this.http.post("/api/v1/wallet/pay", {
|
|
2818
|
+
wwwAuthenticate,
|
|
2819
|
+
endpointSlug: slug
|
|
2820
|
+
});
|
|
2821
|
+
return res.xPayment;
|
|
2822
|
+
}
|
|
2773
2823
|
/**
|
|
2774
2824
|
* Build headers for SyftAI-Space request.
|
|
2775
2825
|
*/
|
|
2776
|
-
buildHeaders(tenantName) {
|
|
2826
|
+
buildHeaders(tenantName, authorizationToken) {
|
|
2777
2827
|
const headers = {
|
|
2778
2828
|
"Content-Type": "application/json"
|
|
2779
2829
|
};
|
|
2780
2830
|
if (tenantName) {
|
|
2781
2831
|
headers["X-Tenant-Name"] = tenantName;
|
|
2782
2832
|
}
|
|
2833
|
+
if (authorizationToken) {
|
|
2834
|
+
headers["Authorization"] = `Bearer ${authorizationToken}`;
|
|
2835
|
+
}
|
|
2783
2836
|
return headers;
|
|
2784
2837
|
}
|
|
2838
|
+
/**
|
|
2839
|
+
* Parse documents from a SyftAI-Space query response.
|
|
2840
|
+
*
|
|
2841
|
+
* Mirrors the aggregator's `DataSourceClient._parse_syftai_response`: the
|
|
2842
|
+
* canonical shape nests documents under `references.documents` and names the
|
|
2843
|
+
* score `similarity_score`. A legacy top-level `documents` list (with
|
|
2844
|
+
* `score`) is still honoured for backward compatibility.
|
|
2845
|
+
*/
|
|
2846
|
+
parseDocuments(data) {
|
|
2847
|
+
const references = data["references"];
|
|
2848
|
+
let rawDocs;
|
|
2849
|
+
let scoreKey = "score";
|
|
2850
|
+
if (references && typeof references === "object") {
|
|
2851
|
+
rawDocs = references["documents"];
|
|
2852
|
+
scoreKey = "similarity_score";
|
|
2853
|
+
} else {
|
|
2854
|
+
rawDocs = data["documents"];
|
|
2855
|
+
}
|
|
2856
|
+
const documents = [];
|
|
2857
|
+
if (Array.isArray(rawDocs)) {
|
|
2858
|
+
for (const doc of rawDocs) {
|
|
2859
|
+
documents.push({
|
|
2860
|
+
content: String(doc["content"] ?? ""),
|
|
2861
|
+
score: Number(doc[scoreKey] ?? doc["score"] ?? 0),
|
|
2862
|
+
metadata: doc["metadata"] ?? {}
|
|
2863
|
+
});
|
|
2864
|
+
}
|
|
2865
|
+
}
|
|
2866
|
+
return documents;
|
|
2867
|
+
}
|
|
2785
2868
|
/**
|
|
2786
2869
|
* Query a data source endpoint directly.
|
|
2787
2870
|
*
|
|
2871
|
+
* Authentication mirrors the aggregator: SyftAI-Space endpoints expect a
|
|
2872
|
+
* satellite bearer token whose audience is the endpoint owner's username. If
|
|
2873
|
+
* `authorizationToken` is not supplied, one is minted automatically when an
|
|
2874
|
+
* owner is known (`ownerUsername` option or `endpoint.ownerUsername`).
|
|
2875
|
+
*
|
|
2788
2876
|
* @param options - Query options
|
|
2789
2877
|
* @returns Array of Document objects
|
|
2790
2878
|
* @throws {RetrievalError} If the query fails
|
|
2791
2879
|
*/
|
|
2792
2880
|
async queryDataSource(options) {
|
|
2793
|
-
const {
|
|
2881
|
+
const {
|
|
2882
|
+
endpoint,
|
|
2883
|
+
query,
|
|
2884
|
+
userEmail,
|
|
2885
|
+
topK = 5,
|
|
2886
|
+
similarityThreshold = 0.5,
|
|
2887
|
+
authorizationToken,
|
|
2888
|
+
ownerUsername,
|
|
2889
|
+
pay = false
|
|
2890
|
+
} = options;
|
|
2794
2891
|
const url = `${endpoint.url.replace(/\/$/, "")}/api/v1/endpoints/${endpoint.slug}/query`;
|
|
2795
2892
|
const requestBody = {
|
|
2796
2893
|
user_email: userEmail,
|
|
@@ -2799,19 +2896,44 @@ var SyftAIResource = class {
|
|
|
2799
2896
|
limit: topK,
|
|
2800
2897
|
similarity_threshold: similarityThreshold
|
|
2801
2898
|
};
|
|
2802
|
-
let
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2899
|
+
let token = authorizationToken;
|
|
2900
|
+
if (!token) {
|
|
2901
|
+
const audience = ownerUsername ?? endpoint.ownerUsername;
|
|
2902
|
+
if (audience) {
|
|
2903
|
+
token = await this.mintSatelliteToken(audience);
|
|
2904
|
+
}
|
|
2905
|
+
}
|
|
2906
|
+
const headers = this.buildHeaders(endpoint.tenantName, token);
|
|
2907
|
+
const postQuery = async (extraHeaders) => {
|
|
2908
|
+
try {
|
|
2909
|
+
return await fetch(url, {
|
|
2910
|
+
method: "POST",
|
|
2911
|
+
headers: { ...headers, ...extraHeaders },
|
|
2912
|
+
body: JSON.stringify(requestBody)
|
|
2913
|
+
});
|
|
2914
|
+
} catch (error) {
|
|
2915
|
+
throw new RetrievalError(
|
|
2916
|
+
`Failed to connect to data source '${endpoint.slug}': ${error instanceof Error ? error.message : String(error)}`,
|
|
2917
|
+
endpoint.slug,
|
|
2918
|
+
error
|
|
2919
|
+
);
|
|
2920
|
+
}
|
|
2921
|
+
};
|
|
2922
|
+
let response = await postQuery();
|
|
2923
|
+
if (response.status === 402 && pay) {
|
|
2924
|
+
let xPayment;
|
|
2925
|
+
try {
|
|
2926
|
+
xPayment = await this.payMpp(response.headers.get("www-authenticate") ?? "", endpoint.slug);
|
|
2927
|
+
} catch (error) {
|
|
2928
|
+
throw new RetrievalError(
|
|
2929
|
+
`Payment failed for data source '${endpoint.slug}': ${error instanceof Error ? error.message : String(error)}`,
|
|
2930
|
+
endpoint.slug,
|
|
2931
|
+
error
|
|
2932
|
+
);
|
|
2933
|
+
}
|
|
2934
|
+
if (xPayment) {
|
|
2935
|
+
response = await postQuery({ "X-Payment": xPayment });
|
|
2936
|
+
}
|
|
2815
2937
|
}
|
|
2816
2938
|
if (!response.ok) {
|
|
2817
2939
|
let message = `HTTP ${response.status}`;
|
|
@@ -2823,17 +2945,7 @@ var SyftAIResource = class {
|
|
|
2823
2945
|
throw new RetrievalError(`Data source query failed: ${message}`, endpoint.slug);
|
|
2824
2946
|
}
|
|
2825
2947
|
const data = await response.json();
|
|
2826
|
-
const documents =
|
|
2827
|
-
const docsData = data["documents"];
|
|
2828
|
-
if (Array.isArray(docsData)) {
|
|
2829
|
-
for (const doc of docsData) {
|
|
2830
|
-
documents.push({
|
|
2831
|
-
content: String(doc["content"] ?? ""),
|
|
2832
|
-
score: Number(doc["score"] ?? 0),
|
|
2833
|
-
metadata: doc["metadata"] ?? {}
|
|
2834
|
-
});
|
|
2835
|
-
}
|
|
2836
|
-
}
|
|
2948
|
+
const documents = this.parseDocuments(data);
|
|
2837
2949
|
return documents;
|
|
2838
2950
|
}
|
|
2839
2951
|
/**
|
|
@@ -3186,7 +3298,7 @@ var SyftHubClient = class {
|
|
|
3186
3298
|
*/
|
|
3187
3299
|
get syftai() {
|
|
3188
3300
|
if (!this._syftai) {
|
|
3189
|
-
this._syftai = new SyftAIResource();
|
|
3301
|
+
this._syftai = new SyftAIResource(this.http);
|
|
3190
3302
|
}
|
|
3191
3303
|
return this._syftai;
|
|
3192
3304
|
}
|