@ragable/sdk 0.7.10 → 0.8.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.d.mts +224 -102
- package/dist/index.d.ts +224 -102
- package/dist/index.js +361 -179
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +360 -176
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -47,6 +47,7 @@ __export(index_exports, {
|
|
|
47
47
|
RagableBrowserAiClient: () => RagableBrowserAiClient,
|
|
48
48
|
RagableBrowserAuthClient: () => RagableBrowserAuthClient,
|
|
49
49
|
RagableBrowserDatabaseClient: () => RagableBrowserDatabaseClient,
|
|
50
|
+
RagableBrowserFunctionsClient: () => RagableBrowserFunctionsClient,
|
|
50
51
|
RagableBrowserMailClient: () => RagableBrowserMailClient,
|
|
51
52
|
RagableBrowserStorageClient: () => RagableBrowserStorageClient,
|
|
52
53
|
RagableError: () => RagableError,
|
|
@@ -60,7 +61,6 @@ __export(index_exports, {
|
|
|
60
61
|
bindFetch: () => bindFetch,
|
|
61
62
|
buildInferenceRequestBody: () => buildInferenceRequestBody,
|
|
62
63
|
buildResponseFormat: () => buildResponseFormat,
|
|
63
|
-
bytesToBase64: () => bytesToBase64,
|
|
64
64
|
collectAssistantTextFromUiSegments: () => collectAssistantTextFromUiSegments,
|
|
65
65
|
collectionRecordToRowWithMeta: () => collectionRecordToRowWithMeta,
|
|
66
66
|
collectionRecordsToRowWithMeta: () => collectionRecordsToRowWithMeta,
|
|
@@ -76,7 +76,6 @@ __export(index_exports, {
|
|
|
76
76
|
formatPostgrestError: () => formatPostgrestError,
|
|
77
77
|
formatSdkError: () => formatSdkError,
|
|
78
78
|
generateIdempotencyKey: () => generateIdempotencyKey,
|
|
79
|
-
imagePartToUrl: () => imagePartToUrl,
|
|
80
79
|
isIncompleteAgentStreamError: () => isIncompleteAgentStreamError,
|
|
81
80
|
mapAgentEvent: () => mapAgentEvent,
|
|
82
81
|
mapFireworksChunk: () => mapFireworksChunk,
|
|
@@ -91,7 +90,6 @@ __export(index_exports, {
|
|
|
91
90
|
runAgentChatStreamLenient: () => runAgentChatStreamLenient,
|
|
92
91
|
streamObjectFromContext: () => streamObjectFromContext,
|
|
93
92
|
toRagableResult: () => toRagableResult,
|
|
94
|
-
toWireUserContent: () => toWireUserContent,
|
|
95
93
|
tryParsePartialJson: () => tryParsePartialJson,
|
|
96
94
|
unwrapPostgrest: () => unwrapPostgrest,
|
|
97
95
|
wrapStreamTextAsObject: () => wrapStreamTextAsObject
|
|
@@ -762,7 +760,11 @@ function generateIdempotencyKey() {
|
|
|
762
760
|
return `idk-${Date.now()}-${_uuidCounter}-${Math.random().toString(36).slice(2, 10)}`;
|
|
763
761
|
}
|
|
764
762
|
function requestCacheKey(req) {
|
|
765
|
-
|
|
763
|
+
const auth = req.headers.get("authorization") ?? "";
|
|
764
|
+
const dbInstance = req.headers.get("x-database-instance-id") ?? "";
|
|
765
|
+
return `${req.method}:${req.url}
|
|
766
|
+
${auth}
|
|
767
|
+
${dbInstance}`;
|
|
766
768
|
}
|
|
767
769
|
var Transport = class {
|
|
768
770
|
constructor(options = {}) {
|
|
@@ -789,13 +791,16 @@ var Transport = class {
|
|
|
789
791
|
async execute(req) {
|
|
790
792
|
if (req.method === "GET") {
|
|
791
793
|
const key = requestCacheKey(req);
|
|
792
|
-
|
|
793
|
-
if (
|
|
794
|
-
|
|
795
|
-
this.inflightGets.
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
794
|
+
let base = this.inflightGets.get(key);
|
|
795
|
+
if (!base) {
|
|
796
|
+
base = this._executeWithRetry(req);
|
|
797
|
+
this.inflightGets.set(key, base);
|
|
798
|
+
const clear = () => {
|
|
799
|
+
if (this.inflightGets.get(key) === base) this.inflightGets.delete(key);
|
|
800
|
+
};
|
|
801
|
+
base.then(clear, clear);
|
|
802
|
+
}
|
|
803
|
+
return base.then((r) => r.clone());
|
|
799
804
|
}
|
|
800
805
|
return this._executeWithRetry(req);
|
|
801
806
|
}
|
|
@@ -815,6 +820,8 @@ var Transport = class {
|
|
|
815
820
|
let lastError;
|
|
816
821
|
const maxAttempts = 1 + retryOpts.maxRetries;
|
|
817
822
|
let did401Refresh = false;
|
|
823
|
+
const isIdempotent = req.method === "GET" || req.method === "HEAD";
|
|
824
|
+
const retryEnabled = retryOpts.maxRetries > 0 && (isIdempotent || req.retry !== void 0);
|
|
818
825
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
819
826
|
try {
|
|
820
827
|
const response = await this._singleFetch(finalReq, timeoutMs);
|
|
@@ -827,7 +834,7 @@ var Transport = class {
|
|
|
827
834
|
continue;
|
|
828
835
|
}
|
|
829
836
|
}
|
|
830
|
-
if (!response.ok && retryOpts.retryOn.includes(response.status) && attempt < maxAttempts - 1) {
|
|
837
|
+
if (retryEnabled && !response.ok && retryOpts.retryOn.includes(response.status) && attempt < maxAttempts - 1) {
|
|
831
838
|
let delayMs = jitteredDelay(retryOpts.baseDelayMs, attempt, retryOpts.maxDelayMs);
|
|
832
839
|
if (retryOpts.respectRetryAfter) {
|
|
833
840
|
const ra = parseRetryAfter(response.headers.get("retry-after"));
|
|
@@ -843,7 +850,7 @@ var Transport = class {
|
|
|
843
850
|
throw e;
|
|
844
851
|
}
|
|
845
852
|
lastError = e;
|
|
846
|
-
if (attempt < maxAttempts - 1) {
|
|
853
|
+
if (retryEnabled && attempt < maxAttempts - 1) {
|
|
847
854
|
const delayMs = jitteredDelay(retryOpts.baseDelayMs, attempt, retryOpts.maxDelayMs);
|
|
848
855
|
this.onRetry?.(finalReq, attempt + 1, delayMs, e.message);
|
|
849
856
|
await sleep(delayMs);
|
|
@@ -975,13 +982,29 @@ function extractPostgRESTErrorMessage(payload, status, statusText) {
|
|
|
975
982
|
return msg;
|
|
976
983
|
}
|
|
977
984
|
async function parsePostgRESTResponse(response) {
|
|
978
|
-
if (response.status === 204) return null;
|
|
985
|
+
if (response.status === 204 && response.ok) return null;
|
|
979
986
|
const text = await response.text();
|
|
980
|
-
if (!text)
|
|
987
|
+
if (!text) {
|
|
988
|
+
if (!response.ok) {
|
|
989
|
+
throw new RagableError(
|
|
990
|
+
response.statusText || `HTTP ${response.status}`,
|
|
991
|
+
response.status,
|
|
992
|
+
null
|
|
993
|
+
);
|
|
994
|
+
}
|
|
995
|
+
return null;
|
|
996
|
+
}
|
|
981
997
|
let payload;
|
|
982
998
|
try {
|
|
983
999
|
payload = JSON.parse(text);
|
|
984
1000
|
} catch {
|
|
1001
|
+
if (!response.ok) {
|
|
1002
|
+
throw new RagableError(
|
|
1003
|
+
extractPostgRESTErrorMessage(text, response.status, response.statusText),
|
|
1004
|
+
response.status,
|
|
1005
|
+
null
|
|
1006
|
+
);
|
|
1007
|
+
}
|
|
985
1008
|
throw new RagableError(
|
|
986
1009
|
`PostgREST response parse error: ${text.slice(0, 200)}`,
|
|
987
1010
|
response.status,
|
|
@@ -1950,6 +1973,7 @@ var AuthBroadcastChannel = class {
|
|
|
1950
1973
|
};
|
|
1951
1974
|
|
|
1952
1975
|
// src/auth.ts
|
|
1976
|
+
var MAX_TIMEOUT_MS = 2 ** 31 - 1;
|
|
1953
1977
|
function parseExpiresInSeconds(raw) {
|
|
1954
1978
|
if (typeof raw === "number") return raw;
|
|
1955
1979
|
const s = raw.trim().toLowerCase();
|
|
@@ -1996,7 +2020,14 @@ var RagableAuth = class {
|
|
|
1996
2020
|
__publicField(this, "listeners", /* @__PURE__ */ new Map());
|
|
1997
2021
|
__publicField(this, "broadcast", null);
|
|
1998
2022
|
__publicField(this, "visibilityHandler", null);
|
|
1999
|
-
|
|
2023
|
+
/** Memoizes the one-shot restore so concurrent callers (constructor eager init,
|
|
2024
|
+
* every `onAuthStateChange` subscriber, `getSession`) share a single result.
|
|
2025
|
+
* Non-null also means "restore has started", replacing the old boolean flag. */
|
|
2026
|
+
__publicField(this, "initializePromise", null);
|
|
2027
|
+
/** Bumped on every explicit session change (sign-in/out, refresh). The async
|
|
2028
|
+
* restore captures this and refuses to overwrite a newer session op that
|
|
2029
|
+
* landed while it was reading storage (e.g. a sign-out during page load). */
|
|
2030
|
+
__publicField(this, "sessionEpoch", 0);
|
|
2000
2031
|
this.baseUrl = DEFAULT_RAGABLE_API_BASE.replace(/\/+$/, "");
|
|
2001
2032
|
this.authGroupId = config.authGroupId;
|
|
2002
2033
|
this.fetchImpl = bindFetch(config.fetch);
|
|
@@ -2030,33 +2061,43 @@ var RagableAuth = class {
|
|
|
2030
2061
|
if (this.debug) console.debug("[RagableAuth]", ...args);
|
|
2031
2062
|
}
|
|
2032
2063
|
// ── Lifecycle ──────────────────────────────────────────────────────────────
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
this.
|
|
2064
|
+
/**
|
|
2065
|
+
* Restore a persisted session (once). Memoized: every caller awaits the same
|
|
2066
|
+
* promise, so the eager constructor init, `getSession`, and each
|
|
2067
|
+
* `onAuthStateChange` subscriber's INITIAL_SESSION replay never race or
|
|
2068
|
+
* double-restore. Does NOT emit `INITIAL_SESSION` globally — that event is
|
|
2069
|
+
* delivered per-subscriber by `onAuthStateChange` (Supabase-parity), so a
|
|
2070
|
+
* listener attached after restore still sees the existing session.
|
|
2071
|
+
*/
|
|
2072
|
+
initialize() {
|
|
2073
|
+
if (this.initializePromise) return this.initializePromise;
|
|
2074
|
+
this.initializePromise = this._initialize();
|
|
2075
|
+
return this.initializePromise;
|
|
2076
|
+
}
|
|
2077
|
+
async _initialize() {
|
|
2078
|
+
if (!this.persistSession) return this.currentSession;
|
|
2079
|
+
const epoch = this.sessionEpoch;
|
|
2080
|
+
try {
|
|
2081
|
+
const raw = await this.storage.getItem(this.storageKey);
|
|
2082
|
+
if (!raw) return this.currentSession;
|
|
2083
|
+
if (this.sessionEpoch !== epoch) return this.currentSession;
|
|
2084
|
+
const session = JSON.parse(raw);
|
|
2085
|
+
const stillValid = !!session.expires_at && session.expires_at > nowSeconds();
|
|
2086
|
+
if (stillValid) {
|
|
2087
|
+
this.currentSession = session;
|
|
2088
|
+
this.scheduleRefresh(session);
|
|
2089
|
+
this.log("Restored session from storage");
|
|
2090
|
+
} else if (session.refresh_token) {
|
|
2091
|
+
this.currentSession = session;
|
|
2092
|
+
this.log("Stored session expired, attempting refresh");
|
|
2093
|
+
const refreshed = await this.singleFlightRefresh(session.refresh_token);
|
|
2094
|
+
if (refreshed) this.currentSession = refreshed;
|
|
2095
|
+
} else {
|
|
2096
|
+
await this.storage.removeItem(this.storageKey);
|
|
2057
2097
|
}
|
|
2098
|
+
} catch (e) {
|
|
2099
|
+
this.log("Failed to restore session", e);
|
|
2058
2100
|
}
|
|
2059
|
-
this.emit("INITIAL_SESSION", this.currentSession);
|
|
2060
2101
|
return this.currentSession;
|
|
2061
2102
|
}
|
|
2062
2103
|
// ── Auth methods ───────────────────────────────────────────────────────────
|
|
@@ -2086,6 +2127,7 @@ var RagableAuth = class {
|
|
|
2086
2127
|
});
|
|
2087
2128
|
}
|
|
2088
2129
|
async signOut(_options) {
|
|
2130
|
+
this.sessionEpoch++;
|
|
2089
2131
|
this.currentSession = null;
|
|
2090
2132
|
this.clearRefreshTimer();
|
|
2091
2133
|
if (this.persistSession) {
|
|
@@ -2105,12 +2147,12 @@ var RagableAuth = class {
|
|
|
2105
2147
|
});
|
|
2106
2148
|
}
|
|
2107
2149
|
async getSession() {
|
|
2108
|
-
|
|
2150
|
+
await this.initialize();
|
|
2109
2151
|
return { data: { session: this.currentSession }, error: null };
|
|
2110
2152
|
}
|
|
2111
2153
|
async getUser() {
|
|
2112
2154
|
return asPostgrestResponse(async () => {
|
|
2113
|
-
const token = this.
|
|
2155
|
+
const token = await this.getValidAccessToken();
|
|
2114
2156
|
if (!token) throw new RagableError("Not authenticated", 401, null);
|
|
2115
2157
|
return this.fetchAuthWithBearer("/me", "GET", token);
|
|
2116
2158
|
});
|
|
@@ -2155,6 +2197,15 @@ var RagableAuth = class {
|
|
|
2155
2197
|
_subCounter++;
|
|
2156
2198
|
const id = `sub-${_subCounter}`;
|
|
2157
2199
|
this.listeners.set(id, callback);
|
|
2200
|
+
void this.initialize().then((session) => {
|
|
2201
|
+
const cb = this.listeners.get(id);
|
|
2202
|
+
if (!cb) return;
|
|
2203
|
+
try {
|
|
2204
|
+
cb("INITIAL_SESSION", session);
|
|
2205
|
+
} catch (e) {
|
|
2206
|
+
this.log("Listener threw", e);
|
|
2207
|
+
}
|
|
2208
|
+
});
|
|
2158
2209
|
const unsubscribe = () => {
|
|
2159
2210
|
this.listeners.delete(id);
|
|
2160
2211
|
};
|
|
@@ -2164,12 +2215,19 @@ var RagableAuth = class {
|
|
|
2164
2215
|
getAccessToken() {
|
|
2165
2216
|
return this.currentSession?.access_token ?? null;
|
|
2166
2217
|
}
|
|
2167
|
-
|
|
2168
|
-
|
|
2218
|
+
/**
|
|
2219
|
+
* Returns an access token guaranteed fresh for at least `refreshSkewSeconds`,
|
|
2220
|
+
* refreshing (single-flight) if needed. Pass `force: true` to bypass the skew
|
|
2221
|
+
* check and refresh now — used by the transport's 401 handler so a token the
|
|
2222
|
+
* server rejected (key rotation, clock skew, early revocation) self-heals on
|
|
2223
|
+
* retry instead of failing the call.
|
|
2224
|
+
*/
|
|
2225
|
+
async getValidAccessToken(force = false) {
|
|
2226
|
+
await this.initialize();
|
|
2169
2227
|
const session = this.currentSession;
|
|
2170
2228
|
if (!session) return null;
|
|
2171
2229
|
const secondsUntilExpiry = session.expires_at - nowSeconds();
|
|
2172
|
-
if (secondsUntilExpiry <= this.refreshSkewSeconds) {
|
|
2230
|
+
if (force || secondsUntilExpiry <= this.refreshSkewSeconds) {
|
|
2173
2231
|
const refreshed = await this.singleFlightRefresh(session.refresh_token);
|
|
2174
2232
|
return refreshed?.access_token ?? null;
|
|
2175
2233
|
}
|
|
@@ -2262,6 +2320,7 @@ var RagableAuth = class {
|
|
|
2262
2320
|
};
|
|
2263
2321
|
}
|
|
2264
2322
|
async setSessionInternal(session, event) {
|
|
2323
|
+
this.sessionEpoch++;
|
|
2265
2324
|
this.currentSession = session;
|
|
2266
2325
|
await this.persistCurrentSession();
|
|
2267
2326
|
this.broadcast?.postSessionUpdated(JSON.stringify(session));
|
|
@@ -2292,12 +2351,13 @@ var RagableAuth = class {
|
|
|
2292
2351
|
if (!this.autoRefreshToken) return;
|
|
2293
2352
|
const secondsUntilExpiry = session.expires_at - nowSeconds();
|
|
2294
2353
|
const refreshIn = Math.max(0, secondsUntilExpiry - this.refreshSkewSeconds);
|
|
2295
|
-
|
|
2354
|
+
const delayMs = Math.min(refreshIn * 1e3, MAX_TIMEOUT_MS);
|
|
2355
|
+
this.log(`Scheduling refresh in ${Math.round(delayMs / 1e3)}s`);
|
|
2296
2356
|
this.refreshTimer = setTimeout(() => {
|
|
2297
2357
|
this.singleFlightRefresh(session.refresh_token).catch((e) => {
|
|
2298
2358
|
this.log("Scheduled refresh failed", e);
|
|
2299
2359
|
});
|
|
2300
|
-
},
|
|
2360
|
+
}, delayMs);
|
|
2301
2361
|
}
|
|
2302
2362
|
clearRefreshTimer() {
|
|
2303
2363
|
if (this.refreshTimer !== null) {
|
|
@@ -2305,16 +2365,57 @@ var RagableAuth = class {
|
|
|
2305
2365
|
this.refreshTimer = null;
|
|
2306
2366
|
}
|
|
2307
2367
|
}
|
|
2368
|
+
/**
|
|
2369
|
+
* Refresh the session, deduplicating concurrent callers onto one in-flight
|
|
2370
|
+
* request. Side effects (persisting the new session, or clearing it and
|
|
2371
|
+
* emitting SIGNED_OUT / TOKEN_REFRESH_FAILED) run exactly once inside the
|
|
2372
|
+
* shared promise, so two callers can't double-emit. Resolves to the new
|
|
2373
|
+
* session, or `null` when the refresh failed.
|
|
2374
|
+
*/
|
|
2308
2375
|
async singleFlightRefresh(refreshToken) {
|
|
2309
2376
|
if (this.refreshPromise) return this.refreshPromise;
|
|
2310
|
-
this.refreshPromise =
|
|
2377
|
+
this.refreshPromise = (async () => {
|
|
2378
|
+
const outcome = await this._doRefresh(refreshToken);
|
|
2379
|
+
if (outcome.ok) return outcome.session;
|
|
2380
|
+
if (outcome.terminal) {
|
|
2381
|
+
await this.handleTerminalRefreshFailure();
|
|
2382
|
+
} else {
|
|
2383
|
+
this.emit("TOKEN_REFRESH_FAILED", this.currentSession);
|
|
2384
|
+
}
|
|
2385
|
+
return null;
|
|
2386
|
+
})().finally(() => {
|
|
2311
2387
|
this.refreshPromise = null;
|
|
2312
2388
|
});
|
|
2313
2389
|
return this.refreshPromise;
|
|
2314
2390
|
}
|
|
2391
|
+
/** Clear the session locally and emit SIGNED_OUT after a definitively-rejected
|
|
2392
|
+
* refresh, so onAuthStateChange-driven UI redirects to login. */
|
|
2393
|
+
async handleTerminalRefreshFailure() {
|
|
2394
|
+
this.sessionEpoch++;
|
|
2395
|
+
this.currentSession = null;
|
|
2396
|
+
this.clearRefreshTimer();
|
|
2397
|
+
if (this.persistSession) {
|
|
2398
|
+
try {
|
|
2399
|
+
await this.storage.removeItem(this.storageKey);
|
|
2400
|
+
} catch (e) {
|
|
2401
|
+
this.log("Failed to clear session after terminal refresh failure", e);
|
|
2402
|
+
}
|
|
2403
|
+
}
|
|
2404
|
+
this.broadcast?.postSessionRemoved();
|
|
2405
|
+
this.emit("TOKEN_REFRESH_FAILED", null);
|
|
2406
|
+
this.emit("SIGNED_OUT", null);
|
|
2407
|
+
}
|
|
2315
2408
|
async _doRefresh(refreshToken) {
|
|
2409
|
+
let raw;
|
|
2410
|
+
try {
|
|
2411
|
+
raw = await this.fetchAuth("/refresh", "POST", { refreshToken });
|
|
2412
|
+
} catch (e) {
|
|
2413
|
+
const status = e instanceof RagableError ? e.status : 0;
|
|
2414
|
+
const terminal = status === 400 || status === 401 || status === 403;
|
|
2415
|
+
this.log("Refresh request failed", { status, terminal });
|
|
2416
|
+
return { ok: false, terminal, error: e };
|
|
2417
|
+
}
|
|
2316
2418
|
try {
|
|
2317
|
-
const raw = await this.fetchAuth("/refresh", "POST", { refreshToken });
|
|
2318
2419
|
const me = await this.fetchAuthWithBearer("/me", "GET", raw.accessToken);
|
|
2319
2420
|
const expiresIn = parseExpiresInSeconds(raw.expiresIn);
|
|
2320
2421
|
const session = {
|
|
@@ -2326,10 +2427,10 @@ var RagableAuth = class {
|
|
|
2326
2427
|
user: me.user
|
|
2327
2428
|
};
|
|
2328
2429
|
await this.setSessionInternal(session, "TOKEN_REFRESHED");
|
|
2329
|
-
return session;
|
|
2430
|
+
return { ok: true, session };
|
|
2330
2431
|
} catch (e) {
|
|
2331
|
-
this.log("
|
|
2332
|
-
return
|
|
2432
|
+
this.log("Post-refresh /me failed", e);
|
|
2433
|
+
return { ok: false, terminal: false, error: e };
|
|
2333
2434
|
}
|
|
2334
2435
|
}
|
|
2335
2436
|
// ─── Visibility listener ───────────────────────────────────────────────────
|
|
@@ -2431,95 +2532,6 @@ function stripTrailingCommas(text) {
|
|
|
2431
2532
|
return text.replace(/,(\s*[}\]])/g, "$1").replace(/,\s*$/, "");
|
|
2432
2533
|
}
|
|
2433
2534
|
|
|
2434
|
-
// src/content.ts
|
|
2435
|
-
var MAX_IMAGE_BYTES = 5 * 1024 * 1024;
|
|
2436
|
-
function toWireUserContent(content) {
|
|
2437
|
-
if (typeof content === "string") return content;
|
|
2438
|
-
const out = [];
|
|
2439
|
-
for (const part of content) {
|
|
2440
|
-
if (!part) continue;
|
|
2441
|
-
if (part.type === "text") {
|
|
2442
|
-
out.push(toWireTextPart(part));
|
|
2443
|
-
} else if (part.type === "image") {
|
|
2444
|
-
out.push(toWireImagePart(part));
|
|
2445
|
-
}
|
|
2446
|
-
}
|
|
2447
|
-
return out;
|
|
2448
|
-
}
|
|
2449
|
-
function toWireTextPart(part) {
|
|
2450
|
-
return { type: "text", text: part.text };
|
|
2451
|
-
}
|
|
2452
|
-
function toWireImagePart(part) {
|
|
2453
|
-
const url = imagePartToUrl(part);
|
|
2454
|
-
const detail = part.detail;
|
|
2455
|
-
return {
|
|
2456
|
-
type: "image_url",
|
|
2457
|
-
image_url: detail ? { url, detail } : { url }
|
|
2458
|
-
};
|
|
2459
|
-
}
|
|
2460
|
-
function imagePartToUrl(part) {
|
|
2461
|
-
const img = part.image;
|
|
2462
|
-
if (img instanceof URL) return img.href;
|
|
2463
|
-
if (typeof img === "string") {
|
|
2464
|
-
if (img.startsWith("http://") || img.startsWith("https://")) return img;
|
|
2465
|
-
if (img.startsWith("data:")) return img;
|
|
2466
|
-
const mediaType = requireMediaType(part, "raw base64 string");
|
|
2467
|
-
assertBase64SizeOk(img);
|
|
2468
|
-
return `data:${mediaType};base64,${img}`;
|
|
2469
|
-
}
|
|
2470
|
-
if (img instanceof Uint8Array || img instanceof ArrayBuffer) {
|
|
2471
|
-
const bytes = img instanceof Uint8Array ? img : new Uint8Array(img);
|
|
2472
|
-
assertBinarySizeOk(bytes);
|
|
2473
|
-
const mediaType = requireMediaType(part, "binary image data");
|
|
2474
|
-
const b64 = bytesToBase64(bytes);
|
|
2475
|
-
return `data:${mediaType};base64,${b64}`;
|
|
2476
|
-
}
|
|
2477
|
-
throw new RagableError(
|
|
2478
|
-
"ImagePart.image must be a string, URL, Uint8Array, or ArrayBuffer",
|
|
2479
|
-
400,
|
|
2480
|
-
{ code: "SDK_INVALID_IMAGE_PART" }
|
|
2481
|
-
);
|
|
2482
|
-
}
|
|
2483
|
-
function requireMediaType(part, what) {
|
|
2484
|
-
const m = part.mediaType?.trim();
|
|
2485
|
-
if (!m) {
|
|
2486
|
-
throw new RagableError(
|
|
2487
|
-
`ImagePart.mediaType is required for ${what} (e.g. "image/png")`,
|
|
2488
|
-
400,
|
|
2489
|
-
{ code: "SDK_IMAGE_MEDIA_TYPE_REQUIRED" }
|
|
2490
|
-
);
|
|
2491
|
-
}
|
|
2492
|
-
return m;
|
|
2493
|
-
}
|
|
2494
|
-
function assertBinarySizeOk(bytes) {
|
|
2495
|
-
if (bytes.byteLength > MAX_IMAGE_BYTES) {
|
|
2496
|
-
throw new RagableError(
|
|
2497
|
-
`Image exceeds 5MB limit (${bytes.byteLength} bytes)`,
|
|
2498
|
-
400,
|
|
2499
|
-
{ code: "SDK_IMAGE_TOO_LARGE" }
|
|
2500
|
-
);
|
|
2501
|
-
}
|
|
2502
|
-
}
|
|
2503
|
-
function assertBase64SizeOk(b64) {
|
|
2504
|
-
const approxBytes = Math.floor(b64.length * 3 / 4);
|
|
2505
|
-
if (approxBytes > MAX_IMAGE_BYTES) {
|
|
2506
|
-
throw new RagableError(
|
|
2507
|
-
`Image exceeds 5MB limit (~${approxBytes} bytes decoded)`,
|
|
2508
|
-
400,
|
|
2509
|
-
{ code: "SDK_IMAGE_TOO_LARGE" }
|
|
2510
|
-
);
|
|
2511
|
-
}
|
|
2512
|
-
}
|
|
2513
|
-
function bytesToBase64(bytes) {
|
|
2514
|
-
const CHUNK = 32768;
|
|
2515
|
-
let binary = "";
|
|
2516
|
-
for (let i = 0; i < bytes.length; i += CHUNK) {
|
|
2517
|
-
const slice = bytes.subarray(i, i + CHUNK);
|
|
2518
|
-
binary += String.fromCharCode(...slice);
|
|
2519
|
-
}
|
|
2520
|
-
return btoa(binary);
|
|
2521
|
-
}
|
|
2522
|
-
|
|
2523
2535
|
// src/stream-parts.ts
|
|
2524
2536
|
function normalizeFinishReason(raw) {
|
|
2525
2537
|
switch (raw) {
|
|
@@ -2732,9 +2744,7 @@ var ZERO_USAGE = {
|
|
|
2732
2744
|
function buildInferenceRequestBody(params, responseFormat) {
|
|
2733
2745
|
const body = {
|
|
2734
2746
|
model: params.model,
|
|
2735
|
-
messages: params.messages
|
|
2736
|
-
(m) => m.role === "user" ? { role: "user", content: toWireUserContent(m.content) } : m
|
|
2737
|
-
)
|
|
2747
|
+
messages: params.messages
|
|
2738
2748
|
};
|
|
2739
2749
|
if (params.system !== void 0) body.system = params.system;
|
|
2740
2750
|
if (typeof params.temperature === "number")
|
|
@@ -3197,6 +3207,8 @@ function normalizeBrowserApiBase() {
|
|
|
3197
3207
|
function effectiveDataAuth(options) {
|
|
3198
3208
|
if (options.dataAuth) return options.dataAuth;
|
|
3199
3209
|
const hasStatic = Boolean(options.dataStaticKey?.trim()) || typeof options.getDataStaticKey === "function";
|
|
3210
|
+
const canUserAuth = Boolean(options.authGroupId?.trim()) || typeof options.getAccessToken === "function";
|
|
3211
|
+
if (hasStatic && canUserAuth) return "auto";
|
|
3200
3212
|
if (hasStatic) return "publicAnon";
|
|
3201
3213
|
return "user";
|
|
3202
3214
|
}
|
|
@@ -3211,16 +3223,26 @@ function requireAuthGroupId(options) {
|
|
|
3211
3223
|
}
|
|
3212
3224
|
return id;
|
|
3213
3225
|
}
|
|
3214
|
-
async function
|
|
3226
|
+
async function tryGetUserAccessToken(options, ragableAuth) {
|
|
3215
3227
|
if (ragableAuth) {
|
|
3216
|
-
const token = await ragableAuth.getValidAccessToken();
|
|
3217
|
-
if (token) return token;
|
|
3228
|
+
const token = await ragableAuth.getValidAccessToken().catch(() => null);
|
|
3229
|
+
if (token?.trim()) return token.trim();
|
|
3218
3230
|
}
|
|
3219
3231
|
const getter = options.getAccessToken;
|
|
3220
3232
|
if (getter) {
|
|
3221
3233
|
const token = await getter();
|
|
3222
3234
|
if (token?.trim()) return token.trim();
|
|
3223
3235
|
}
|
|
3236
|
+
return null;
|
|
3237
|
+
}
|
|
3238
|
+
async function resolveStaticDataKey(options) {
|
|
3239
|
+
const fromGetter = options.getDataStaticKey ? await options.getDataStaticKey() : null;
|
|
3240
|
+
const key = (fromGetter?.trim() || options.dataStaticKey?.trim()) ?? "";
|
|
3241
|
+
return key || null;
|
|
3242
|
+
}
|
|
3243
|
+
async function requireAccessToken(options, ragableAuth) {
|
|
3244
|
+
const token = await tryGetUserAccessToken(options, ragableAuth);
|
|
3245
|
+
if (token) return token;
|
|
3224
3246
|
throw new RagableError(
|
|
3225
3247
|
"No access token available. Sign in first with auth.signInWithPassword() or provide getAccessToken callback.",
|
|
3226
3248
|
401,
|
|
@@ -3232,8 +3254,18 @@ async function resolveDatabaseAuthBearer(options, ragableAuth) {
|
|
|
3232
3254
|
if (mode === "user") {
|
|
3233
3255
|
return requireAccessToken(options, ragableAuth);
|
|
3234
3256
|
}
|
|
3235
|
-
|
|
3236
|
-
|
|
3257
|
+
if (mode === "auto") {
|
|
3258
|
+
const userTok = await tryGetUserAccessToken(options, ragableAuth);
|
|
3259
|
+
if (userTok) return userTok;
|
|
3260
|
+
const key2 = await resolveStaticDataKey(options);
|
|
3261
|
+
if (key2) return key2;
|
|
3262
|
+
throw new RagableError(
|
|
3263
|
+
"No access token or data key available. Sign in with auth.signInWithPassword() or configure dataStaticKey.",
|
|
3264
|
+
401,
|
|
3265
|
+
{ code: "SDK_NO_ACCESS_TOKEN" }
|
|
3266
|
+
);
|
|
3267
|
+
}
|
|
3268
|
+
const key = await resolveStaticDataKey(options);
|
|
3237
3269
|
if (!key) {
|
|
3238
3270
|
throw new RagableError(
|
|
3239
3271
|
mode === "publicAnon" ? "dataAuth publicAnon requires getDataStaticKey or dataStaticKey" : "dataAuth admin requires getDataStaticKey or dataStaticKey",
|
|
@@ -3337,6 +3369,14 @@ var RagableBrowserAuthClient = class {
|
|
|
3337
3369
|
getSession() {
|
|
3338
3370
|
return this.auth.getSession();
|
|
3339
3371
|
}
|
|
3372
|
+
/**
|
|
3373
|
+
* Returns a valid (auto-refreshed) access token for the current session, or
|
|
3374
|
+
* `null` if signed out. The sanctioned way to obtain a token for a hand-rolled
|
|
3375
|
+
* `fetch` to a custom endpoint — never read tokens out of storage yourself.
|
|
3376
|
+
*/
|
|
3377
|
+
getValidAccessToken() {
|
|
3378
|
+
return this.ragableAuth ? this.ragableAuth.getValidAccessToken() : Promise.resolve(null);
|
|
3379
|
+
}
|
|
3340
3380
|
};
|
|
3341
3381
|
function collectionRecordToRowWithMeta(record) {
|
|
3342
3382
|
const { data, id, createdAt, updatedAt } = record;
|
|
@@ -3375,13 +3415,11 @@ var BrowserCollectionApi = class {
|
|
|
3375
3415
|
const { returnMode, body } = this.normalizeFindArgs(whereOrParams);
|
|
3376
3416
|
const res = await this.requestFind(body);
|
|
3377
3417
|
if (res.error) return res;
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
}
|
|
3384
|
-
return res;
|
|
3418
|
+
const data = returnMode === "flat" ? collectionRecordsToRowWithMeta(res.data) : res.data;
|
|
3419
|
+
return {
|
|
3420
|
+
data,
|
|
3421
|
+
error: null
|
|
3422
|
+
};
|
|
3385
3423
|
});
|
|
3386
3424
|
/**
|
|
3387
3425
|
* @deprecated Use {@link BrowserCollectionApi.findMany} — same behavior.
|
|
@@ -3570,7 +3608,16 @@ var RagableBrowserDatabaseClient = class {
|
|
|
3570
3608
|
const headers = this.baseHeaders();
|
|
3571
3609
|
headers.set("Authorization", `Bearer ${token}`);
|
|
3572
3610
|
headers.set("Content-Type", "application/json");
|
|
3573
|
-
const
|
|
3611
|
+
const dataMode = effectiveDataAuth(this.options);
|
|
3612
|
+
let readOnly;
|
|
3613
|
+
if (dataMode === "publicAnon") {
|
|
3614
|
+
readOnly = true;
|
|
3615
|
+
} else if (dataMode === "auto") {
|
|
3616
|
+
const userTok = await tryGetUserAccessToken(this.options, this.ragableAuth);
|
|
3617
|
+
readOnly = userTok ? params.readOnly !== false : true;
|
|
3618
|
+
} else {
|
|
3619
|
+
readOnly = params.readOnly !== false;
|
|
3620
|
+
}
|
|
3574
3621
|
const response = await this.fetchImpl(
|
|
3575
3622
|
this.toUrl(`/auth-groups/${gid}/data/query`),
|
|
3576
3623
|
{
|
|
@@ -3863,10 +3910,11 @@ async function subscribeBrowserRealtime(options, ragableAuth, fetchImpl, params)
|
|
|
3863
3910
|
return subscription;
|
|
3864
3911
|
}
|
|
3865
3912
|
var BrowserStorageBucketClient = class {
|
|
3866
|
-
constructor(options, fetchImpl, bucketId) {
|
|
3913
|
+
constructor(options, fetchImpl, bucketId, ragableAuth = null) {
|
|
3867
3914
|
this.options = options;
|
|
3868
3915
|
this.fetchImpl = fetchImpl;
|
|
3869
3916
|
this.bucketId = bucketId;
|
|
3917
|
+
this.ragableAuth = ragableAuth;
|
|
3870
3918
|
}
|
|
3871
3919
|
get authGroupId() {
|
|
3872
3920
|
const id = this.options.authGroupId?.trim();
|
|
@@ -3876,14 +3924,28 @@ var BrowserStorageBucketClient = class {
|
|
|
3876
3924
|
base() {
|
|
3877
3925
|
return `${normalizeBrowserApiBase()}/auth-groups/${this.authGroupId}/storage/buckets/${encodeURIComponent(this.bucketId)}`;
|
|
3878
3926
|
}
|
|
3927
|
+
/**
|
|
3928
|
+
* Same credential resolution as the database client (see resolveDatabaseAuthBearer):
|
|
3929
|
+
* in the generated-site default (`auto`), a signed-in user's auto-refreshed JWT
|
|
3930
|
+
* is used so storage calls carry the user's identity; logged-out visitors fall
|
|
3931
|
+
* back to the anon key. Previously storage ignored the managed session entirely.
|
|
3932
|
+
*/
|
|
3879
3933
|
async bearerToken() {
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3934
|
+
return resolveDatabaseAuthBearer(this.options, this.ragableAuth);
|
|
3935
|
+
}
|
|
3936
|
+
/**
|
|
3937
|
+
* The storage backend has historically returned HTTP 200 with an `{ error }`
|
|
3938
|
+
* body on some failures; without this guard the SDK would resolve those as
|
|
3939
|
+
* successful uploads/deletes. Treat any 2xx whose body carries a non-empty
|
|
3940
|
+
* `error` as a failure.
|
|
3941
|
+
*/
|
|
3942
|
+
assertNoEmbeddedError(payload, status) {
|
|
3943
|
+
if (payload && typeof payload === "object" && !Array.isArray(payload)) {
|
|
3944
|
+
const err = payload.error;
|
|
3945
|
+
if (typeof err === "string" && err.trim()) {
|
|
3946
|
+
throw new RagableError(err, status, payload);
|
|
3947
|
+
}
|
|
3885
3948
|
}
|
|
3886
|
-
throw new RagableError("No auth token for storage. Provide dataStaticKey or getAccessToken.", 401, { code: "SDK_NO_ACCESS_TOKEN" });
|
|
3887
3949
|
}
|
|
3888
3950
|
async req(method, path, body) {
|
|
3889
3951
|
const token = await this.bearerToken();
|
|
@@ -3896,7 +3958,8 @@ var BrowserStorageBucketClient = class {
|
|
|
3896
3958
|
body: body instanceof FormData ? body : body !== void 0 ? JSON.stringify(body) : void 0
|
|
3897
3959
|
});
|
|
3898
3960
|
const payload = await res.json().catch(() => ({}));
|
|
3899
|
-
if (!res.ok) throw new RagableError(payload
|
|
3961
|
+
if (!res.ok) throw new RagableError(extractErrorMessage(payload, res.statusText), res.status, payload);
|
|
3962
|
+
this.assertNoEmbeddedError(payload, res.status);
|
|
3900
3963
|
return payload;
|
|
3901
3964
|
}
|
|
3902
3965
|
list(params = {}) {
|
|
@@ -3920,7 +3983,8 @@ var BrowserStorageBucketClient = class {
|
|
|
3920
3983
|
if (params.cacheControl) form.set("cacheControl", params.cacheControl);
|
|
3921
3984
|
const res = await this.fetchImpl(`${this.base()}/upload`, { method: "POST", headers, body: form });
|
|
3922
3985
|
const payload = await res.json().catch(() => ({}));
|
|
3923
|
-
if (!res.ok) throw new RagableError(payload
|
|
3986
|
+
if (!res.ok) throw new RagableError(extractErrorMessage(payload, res.statusText), res.status, payload);
|
|
3987
|
+
this.assertNoEmbeddedError(payload, res.status);
|
|
3924
3988
|
return payload;
|
|
3925
3989
|
}
|
|
3926
3990
|
download(params) {
|
|
@@ -3961,12 +4025,18 @@ var BrowserStorageBucketClient = class {
|
|
|
3961
4025
|
}
|
|
3962
4026
|
};
|
|
3963
4027
|
var RagableBrowserStorageClient = class {
|
|
3964
|
-
constructor(options, fetchImpl) {
|
|
4028
|
+
constructor(options, fetchImpl, ragableAuth = null) {
|
|
3965
4029
|
this.options = options;
|
|
3966
4030
|
this.fetchImpl = fetchImpl;
|
|
4031
|
+
this.ragableAuth = ragableAuth;
|
|
3967
4032
|
}
|
|
3968
4033
|
from(bucketId) {
|
|
3969
|
-
return new BrowserStorageBucketClient(
|
|
4034
|
+
return new BrowserStorageBucketClient(
|
|
4035
|
+
this.options,
|
|
4036
|
+
this.fetchImpl,
|
|
4037
|
+
bucketId,
|
|
4038
|
+
this.ragableAuth
|
|
4039
|
+
);
|
|
3970
4040
|
}
|
|
3971
4041
|
};
|
|
3972
4042
|
var RagableBrowserMailClient = class {
|
|
@@ -4083,6 +4153,99 @@ var RagableBrowserMailClient = class {
|
|
|
4083
4153
|
return message;
|
|
4084
4154
|
}
|
|
4085
4155
|
};
|
|
4156
|
+
var RagableBrowserFunctionsClient = class {
|
|
4157
|
+
constructor(options, auth) {
|
|
4158
|
+
this.options = options;
|
|
4159
|
+
this.auth = auth;
|
|
4160
|
+
__publicField(this, "fetchImpl");
|
|
4161
|
+
this.fetchImpl = bindFetch(options.fetch);
|
|
4162
|
+
}
|
|
4163
|
+
requireWebsiteId() {
|
|
4164
|
+
const websiteId = this.options.websiteId?.trim();
|
|
4165
|
+
if (!websiteId) {
|
|
4166
|
+
throw new RagableError(
|
|
4167
|
+
"websiteId is required for functions. Use createWebsiteRagableClient()/createAppClient() or pass createBrowserClient({ websiteId, ... }).",
|
|
4168
|
+
400,
|
|
4169
|
+
{ code: "SDK_MISSING_WEBSITE_ID" }
|
|
4170
|
+
);
|
|
4171
|
+
}
|
|
4172
|
+
return websiteId;
|
|
4173
|
+
}
|
|
4174
|
+
toUrl(name) {
|
|
4175
|
+
const orgId = this.options.organizationId;
|
|
4176
|
+
const websiteId = this.requireWebsiteId();
|
|
4177
|
+
return `${normalizeBrowserApiBase()}/public/organizations/${orgId}/websites/${websiteId}/functions/${encodeURIComponent(
|
|
4178
|
+
name
|
|
4179
|
+
)}/invoke`;
|
|
4180
|
+
}
|
|
4181
|
+
/**
|
|
4182
|
+
* Best-effort end-user bearer, forwarded to the function as `context.auth.token`.
|
|
4183
|
+
* Functions are public, so this never throws — anonymous calls send no token.
|
|
4184
|
+
*/
|
|
4185
|
+
async getOptionalToken() {
|
|
4186
|
+
if (this.auth) {
|
|
4187
|
+
const token = await this.auth.getValidAccessToken().catch(() => null);
|
|
4188
|
+
if (token) return token;
|
|
4189
|
+
}
|
|
4190
|
+
const caller = await Promise.resolve(this.options.getAccessToken?.()).catch(
|
|
4191
|
+
() => null
|
|
4192
|
+
);
|
|
4193
|
+
if (typeof caller === "string" && caller.trim()) return caller.trim();
|
|
4194
|
+
const staticKey = this.options.dataStaticKey?.trim();
|
|
4195
|
+
if (staticKey) return staticKey;
|
|
4196
|
+
return null;
|
|
4197
|
+
}
|
|
4198
|
+
/**
|
|
4199
|
+
* Invoke a function by name. Prefer the typed `client.functions.<name>(input)`
|
|
4200
|
+
* accessors; use this when the name is dynamic.
|
|
4201
|
+
*/
|
|
4202
|
+
async invoke(name, input, options) {
|
|
4203
|
+
const fnName = String(name ?? "").trim();
|
|
4204
|
+
if (!fnName) {
|
|
4205
|
+
throw new RagableError(
|
|
4206
|
+
"functions.invoke requires a function name",
|
|
4207
|
+
400,
|
|
4208
|
+
{ code: "SDK_MISSING_FUNCTION_NAME" }
|
|
4209
|
+
);
|
|
4210
|
+
}
|
|
4211
|
+
const headers = new Headers(options?.headers ?? this.options.headers);
|
|
4212
|
+
headers.set("Content-Type", "application/json");
|
|
4213
|
+
const token = await this.getOptionalToken();
|
|
4214
|
+
if (token) headers.set("Authorization", `Bearer ${token}`);
|
|
4215
|
+
const response = await this.fetchImpl(this.toUrl(fnName), {
|
|
4216
|
+
method: "POST",
|
|
4217
|
+
headers,
|
|
4218
|
+
body: JSON.stringify({ input: input ?? null }),
|
|
4219
|
+
...options?.signal ? { signal: options.signal } : {}
|
|
4220
|
+
});
|
|
4221
|
+
const payload = await parseMaybeJsonBody(response);
|
|
4222
|
+
if (!response.ok) {
|
|
4223
|
+
const message = extractErrorMessage(payload, response.statusText);
|
|
4224
|
+
throw new RagableError(message, response.status, payload);
|
|
4225
|
+
}
|
|
4226
|
+
if (payload && typeof payload === "object" && !Array.isArray(payload) && "result" in payload) {
|
|
4227
|
+
return payload.result;
|
|
4228
|
+
}
|
|
4229
|
+
return payload;
|
|
4230
|
+
}
|
|
4231
|
+
/** Build the typed Proxy exposed as `client.functions`. */
|
|
4232
|
+
asInvoker() {
|
|
4233
|
+
const invoke = this.invoke.bind(this);
|
|
4234
|
+
return new Proxy(
|
|
4235
|
+
{},
|
|
4236
|
+
{
|
|
4237
|
+
get: (_target, prop) => {
|
|
4238
|
+
if (typeof prop !== "string") return void 0;
|
|
4239
|
+
if (prop === "then") return void 0;
|
|
4240
|
+
if (prop === "invoke") {
|
|
4241
|
+
return (name, input, options) => invoke(name, input, options);
|
|
4242
|
+
}
|
|
4243
|
+
return (input, options) => invoke(prop, input, options);
|
|
4244
|
+
}
|
|
4245
|
+
}
|
|
4246
|
+
);
|
|
4247
|
+
}
|
|
4248
|
+
};
|
|
4086
4249
|
var RagableBrowserAgentsClient = class {
|
|
4087
4250
|
constructor(options) {
|
|
4088
4251
|
this.options = options;
|
|
@@ -4410,6 +4573,11 @@ var RagableBrowser = class {
|
|
|
4410
4573
|
__publicField(this, "db");
|
|
4411
4574
|
__publicField(this, "storage");
|
|
4412
4575
|
__publicField(this, "mail");
|
|
4576
|
+
/**
|
|
4577
|
+
* Backend edge functions — call a `/functions/<name>.ts` handler with
|
|
4578
|
+
* `client.functions.<name>(input)`. Runs server-side. See {@link FunctionInvoker}.
|
|
4579
|
+
*/
|
|
4580
|
+
__publicField(this, "functions");
|
|
4413
4581
|
__publicField(this, "transport");
|
|
4414
4582
|
__publicField(this, "_ragableAuth");
|
|
4415
4583
|
/** Delegates to `database.from()`. Kept for back-compat — prefer `database.from()`. */
|
|
@@ -4429,13 +4597,12 @@ var RagableBrowser = class {
|
|
|
4429
4597
|
auth: options.auth
|
|
4430
4598
|
});
|
|
4431
4599
|
this.transport.setRefreshHandler(async () => {
|
|
4432
|
-
|
|
4433
|
-
|
|
4600
|
+
const mode = effectiveDataAuth(options);
|
|
4601
|
+
if (mode !== "user" && mode !== "auto") return null;
|
|
4602
|
+
return this._ragableAuth.getValidAccessToken(true).catch(() => null);
|
|
4603
|
+
});
|
|
4604
|
+
this._ragableAuth.initialize().catch(() => {
|
|
4434
4605
|
});
|
|
4435
|
-
if (!options.getAccessToken && effectiveDataAuth(options) === "user") {
|
|
4436
|
-
this._ragableAuth.initialize().catch(() => {
|
|
4437
|
-
});
|
|
4438
|
-
}
|
|
4439
4606
|
} else {
|
|
4440
4607
|
this._ragableAuth = null;
|
|
4441
4608
|
}
|
|
@@ -4454,8 +4621,25 @@ var RagableBrowser = class {
|
|
|
4454
4621
|
);
|
|
4455
4622
|
this.database._setTransport(this.transport);
|
|
4456
4623
|
this.db = this.database;
|
|
4457
|
-
this.storage = new RagableBrowserStorageClient(
|
|
4624
|
+
this.storage = new RagableBrowserStorageClient(
|
|
4625
|
+
options,
|
|
4626
|
+
bindFetch(options.fetch),
|
|
4627
|
+
this._ragableAuth
|
|
4628
|
+
);
|
|
4458
4629
|
this.mail = new RagableBrowserMailClient(options, this._ragableAuth);
|
|
4630
|
+
this.functions = new RagableBrowserFunctionsClient(
|
|
4631
|
+
options,
|
|
4632
|
+
this._ragableAuth
|
|
4633
|
+
).asInvoker();
|
|
4634
|
+
}
|
|
4635
|
+
/**
|
|
4636
|
+
* Resolves once the persisted session has been restored (and refreshed if it
|
|
4637
|
+
* was expired). Await this before reading auth state at startup to avoid a
|
|
4638
|
+
* logged-out flash, e.g. `const session = await client.ready()`. Resolves
|
|
4639
|
+
* `null` when no auth group is configured or no session is stored.
|
|
4640
|
+
*/
|
|
4641
|
+
ready() {
|
|
4642
|
+
return this._ragableAuth ? this._ragableAuth.initialize() : Promise.resolve(null);
|
|
4459
4643
|
}
|
|
4460
4644
|
destroy() {
|
|
4461
4645
|
this._ragableAuth?.destroy();
|
|
@@ -4497,6 +4681,7 @@ function createClient(options) {
|
|
|
4497
4681
|
RagableBrowserAiClient,
|
|
4498
4682
|
RagableBrowserAuthClient,
|
|
4499
4683
|
RagableBrowserDatabaseClient,
|
|
4684
|
+
RagableBrowserFunctionsClient,
|
|
4500
4685
|
RagableBrowserMailClient,
|
|
4501
4686
|
RagableBrowserStorageClient,
|
|
4502
4687
|
RagableError,
|
|
@@ -4510,7 +4695,6 @@ function createClient(options) {
|
|
|
4510
4695
|
bindFetch,
|
|
4511
4696
|
buildInferenceRequestBody,
|
|
4512
4697
|
buildResponseFormat,
|
|
4513
|
-
bytesToBase64,
|
|
4514
4698
|
collectAssistantTextFromUiSegments,
|
|
4515
4699
|
collectionRecordToRowWithMeta,
|
|
4516
4700
|
collectionRecordsToRowWithMeta,
|
|
@@ -4526,7 +4710,6 @@ function createClient(options) {
|
|
|
4526
4710
|
formatPostgrestError,
|
|
4527
4711
|
formatSdkError,
|
|
4528
4712
|
generateIdempotencyKey,
|
|
4529
|
-
imagePartToUrl,
|
|
4530
4713
|
isIncompleteAgentStreamError,
|
|
4531
4714
|
mapAgentEvent,
|
|
4532
4715
|
mapFireworksChunk,
|
|
@@ -4541,7 +4724,6 @@ function createClient(options) {
|
|
|
4541
4724
|
runAgentChatStreamLenient,
|
|
4542
4725
|
streamObjectFromContext,
|
|
4543
4726
|
toRagableResult,
|
|
4544
|
-
toWireUserContent,
|
|
4545
4727
|
tryParsePartialJson,
|
|
4546
4728
|
unwrapPostgrest,
|
|
4547
4729
|
wrapStreamTextAsObject
|