@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.mjs
CHANGED
|
@@ -666,7 +666,11 @@ function generateIdempotencyKey() {
|
|
|
666
666
|
return `idk-${Date.now()}-${_uuidCounter}-${Math.random().toString(36).slice(2, 10)}`;
|
|
667
667
|
}
|
|
668
668
|
function requestCacheKey(req) {
|
|
669
|
-
|
|
669
|
+
const auth = req.headers.get("authorization") ?? "";
|
|
670
|
+
const dbInstance = req.headers.get("x-database-instance-id") ?? "";
|
|
671
|
+
return `${req.method}:${req.url}
|
|
672
|
+
${auth}
|
|
673
|
+
${dbInstance}`;
|
|
670
674
|
}
|
|
671
675
|
var Transport = class {
|
|
672
676
|
constructor(options = {}) {
|
|
@@ -693,13 +697,16 @@ var Transport = class {
|
|
|
693
697
|
async execute(req) {
|
|
694
698
|
if (req.method === "GET") {
|
|
695
699
|
const key = requestCacheKey(req);
|
|
696
|
-
|
|
697
|
-
if (
|
|
698
|
-
|
|
699
|
-
this.inflightGets.
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
700
|
+
let base = this.inflightGets.get(key);
|
|
701
|
+
if (!base) {
|
|
702
|
+
base = this._executeWithRetry(req);
|
|
703
|
+
this.inflightGets.set(key, base);
|
|
704
|
+
const clear = () => {
|
|
705
|
+
if (this.inflightGets.get(key) === base) this.inflightGets.delete(key);
|
|
706
|
+
};
|
|
707
|
+
base.then(clear, clear);
|
|
708
|
+
}
|
|
709
|
+
return base.then((r) => r.clone());
|
|
703
710
|
}
|
|
704
711
|
return this._executeWithRetry(req);
|
|
705
712
|
}
|
|
@@ -719,6 +726,8 @@ var Transport = class {
|
|
|
719
726
|
let lastError;
|
|
720
727
|
const maxAttempts = 1 + retryOpts.maxRetries;
|
|
721
728
|
let did401Refresh = false;
|
|
729
|
+
const isIdempotent = req.method === "GET" || req.method === "HEAD";
|
|
730
|
+
const retryEnabled = retryOpts.maxRetries > 0 && (isIdempotent || req.retry !== void 0);
|
|
722
731
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
723
732
|
try {
|
|
724
733
|
const response = await this._singleFetch(finalReq, timeoutMs);
|
|
@@ -731,7 +740,7 @@ var Transport = class {
|
|
|
731
740
|
continue;
|
|
732
741
|
}
|
|
733
742
|
}
|
|
734
|
-
if (!response.ok && retryOpts.retryOn.includes(response.status) && attempt < maxAttempts - 1) {
|
|
743
|
+
if (retryEnabled && !response.ok && retryOpts.retryOn.includes(response.status) && attempt < maxAttempts - 1) {
|
|
735
744
|
let delayMs = jitteredDelay(retryOpts.baseDelayMs, attempt, retryOpts.maxDelayMs);
|
|
736
745
|
if (retryOpts.respectRetryAfter) {
|
|
737
746
|
const ra = parseRetryAfter(response.headers.get("retry-after"));
|
|
@@ -747,7 +756,7 @@ var Transport = class {
|
|
|
747
756
|
throw e;
|
|
748
757
|
}
|
|
749
758
|
lastError = e;
|
|
750
|
-
if (attempt < maxAttempts - 1) {
|
|
759
|
+
if (retryEnabled && attempt < maxAttempts - 1) {
|
|
751
760
|
const delayMs = jitteredDelay(retryOpts.baseDelayMs, attempt, retryOpts.maxDelayMs);
|
|
752
761
|
this.onRetry?.(finalReq, attempt + 1, delayMs, e.message);
|
|
753
762
|
await sleep(delayMs);
|
|
@@ -879,13 +888,29 @@ function extractPostgRESTErrorMessage(payload, status, statusText) {
|
|
|
879
888
|
return msg;
|
|
880
889
|
}
|
|
881
890
|
async function parsePostgRESTResponse(response) {
|
|
882
|
-
if (response.status === 204) return null;
|
|
891
|
+
if (response.status === 204 && response.ok) return null;
|
|
883
892
|
const text = await response.text();
|
|
884
|
-
if (!text)
|
|
893
|
+
if (!text) {
|
|
894
|
+
if (!response.ok) {
|
|
895
|
+
throw new RagableError(
|
|
896
|
+
response.statusText || `HTTP ${response.status}`,
|
|
897
|
+
response.status,
|
|
898
|
+
null
|
|
899
|
+
);
|
|
900
|
+
}
|
|
901
|
+
return null;
|
|
902
|
+
}
|
|
885
903
|
let payload;
|
|
886
904
|
try {
|
|
887
905
|
payload = JSON.parse(text);
|
|
888
906
|
} catch {
|
|
907
|
+
if (!response.ok) {
|
|
908
|
+
throw new RagableError(
|
|
909
|
+
extractPostgRESTErrorMessage(text, response.status, response.statusText),
|
|
910
|
+
response.status,
|
|
911
|
+
null
|
|
912
|
+
);
|
|
913
|
+
}
|
|
889
914
|
throw new RagableError(
|
|
890
915
|
`PostgREST response parse error: ${text.slice(0, 200)}`,
|
|
891
916
|
response.status,
|
|
@@ -1854,6 +1879,7 @@ var AuthBroadcastChannel = class {
|
|
|
1854
1879
|
};
|
|
1855
1880
|
|
|
1856
1881
|
// src/auth.ts
|
|
1882
|
+
var MAX_TIMEOUT_MS = 2 ** 31 - 1;
|
|
1857
1883
|
function parseExpiresInSeconds(raw) {
|
|
1858
1884
|
if (typeof raw === "number") return raw;
|
|
1859
1885
|
const s = raw.trim().toLowerCase();
|
|
@@ -1900,7 +1926,14 @@ var RagableAuth = class {
|
|
|
1900
1926
|
__publicField(this, "listeners", /* @__PURE__ */ new Map());
|
|
1901
1927
|
__publicField(this, "broadcast", null);
|
|
1902
1928
|
__publicField(this, "visibilityHandler", null);
|
|
1903
|
-
|
|
1929
|
+
/** Memoizes the one-shot restore so concurrent callers (constructor eager init,
|
|
1930
|
+
* every `onAuthStateChange` subscriber, `getSession`) share a single result.
|
|
1931
|
+
* Non-null also means "restore has started", replacing the old boolean flag. */
|
|
1932
|
+
__publicField(this, "initializePromise", null);
|
|
1933
|
+
/** Bumped on every explicit session change (sign-in/out, refresh). The async
|
|
1934
|
+
* restore captures this and refuses to overwrite a newer session op that
|
|
1935
|
+
* landed while it was reading storage (e.g. a sign-out during page load). */
|
|
1936
|
+
__publicField(this, "sessionEpoch", 0);
|
|
1904
1937
|
this.baseUrl = DEFAULT_RAGABLE_API_BASE.replace(/\/+$/, "");
|
|
1905
1938
|
this.authGroupId = config.authGroupId;
|
|
1906
1939
|
this.fetchImpl = bindFetch(config.fetch);
|
|
@@ -1934,33 +1967,43 @@ var RagableAuth = class {
|
|
|
1934
1967
|
if (this.debug) console.debug("[RagableAuth]", ...args);
|
|
1935
1968
|
}
|
|
1936
1969
|
// ── Lifecycle ──────────────────────────────────────────────────────────────
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
this.
|
|
1970
|
+
/**
|
|
1971
|
+
* Restore a persisted session (once). Memoized: every caller awaits the same
|
|
1972
|
+
* promise, so the eager constructor init, `getSession`, and each
|
|
1973
|
+
* `onAuthStateChange` subscriber's INITIAL_SESSION replay never race or
|
|
1974
|
+
* double-restore. Does NOT emit `INITIAL_SESSION` globally — that event is
|
|
1975
|
+
* delivered per-subscriber by `onAuthStateChange` (Supabase-parity), so a
|
|
1976
|
+
* listener attached after restore still sees the existing session.
|
|
1977
|
+
*/
|
|
1978
|
+
initialize() {
|
|
1979
|
+
if (this.initializePromise) return this.initializePromise;
|
|
1980
|
+
this.initializePromise = this._initialize();
|
|
1981
|
+
return this.initializePromise;
|
|
1982
|
+
}
|
|
1983
|
+
async _initialize() {
|
|
1984
|
+
if (!this.persistSession) return this.currentSession;
|
|
1985
|
+
const epoch = this.sessionEpoch;
|
|
1986
|
+
try {
|
|
1987
|
+
const raw = await this.storage.getItem(this.storageKey);
|
|
1988
|
+
if (!raw) return this.currentSession;
|
|
1989
|
+
if (this.sessionEpoch !== epoch) return this.currentSession;
|
|
1990
|
+
const session = JSON.parse(raw);
|
|
1991
|
+
const stillValid = !!session.expires_at && session.expires_at > nowSeconds();
|
|
1992
|
+
if (stillValid) {
|
|
1993
|
+
this.currentSession = session;
|
|
1994
|
+
this.scheduleRefresh(session);
|
|
1995
|
+
this.log("Restored session from storage");
|
|
1996
|
+
} else if (session.refresh_token) {
|
|
1997
|
+
this.currentSession = session;
|
|
1998
|
+
this.log("Stored session expired, attempting refresh");
|
|
1999
|
+
const refreshed = await this.singleFlightRefresh(session.refresh_token);
|
|
2000
|
+
if (refreshed) this.currentSession = refreshed;
|
|
2001
|
+
} else {
|
|
2002
|
+
await this.storage.removeItem(this.storageKey);
|
|
1961
2003
|
}
|
|
2004
|
+
} catch (e) {
|
|
2005
|
+
this.log("Failed to restore session", e);
|
|
1962
2006
|
}
|
|
1963
|
-
this.emit("INITIAL_SESSION", this.currentSession);
|
|
1964
2007
|
return this.currentSession;
|
|
1965
2008
|
}
|
|
1966
2009
|
// ── Auth methods ───────────────────────────────────────────────────────────
|
|
@@ -1990,6 +2033,7 @@ var RagableAuth = class {
|
|
|
1990
2033
|
});
|
|
1991
2034
|
}
|
|
1992
2035
|
async signOut(_options) {
|
|
2036
|
+
this.sessionEpoch++;
|
|
1993
2037
|
this.currentSession = null;
|
|
1994
2038
|
this.clearRefreshTimer();
|
|
1995
2039
|
if (this.persistSession) {
|
|
@@ -2009,12 +2053,12 @@ var RagableAuth = class {
|
|
|
2009
2053
|
});
|
|
2010
2054
|
}
|
|
2011
2055
|
async getSession() {
|
|
2012
|
-
|
|
2056
|
+
await this.initialize();
|
|
2013
2057
|
return { data: { session: this.currentSession }, error: null };
|
|
2014
2058
|
}
|
|
2015
2059
|
async getUser() {
|
|
2016
2060
|
return asPostgrestResponse(async () => {
|
|
2017
|
-
const token = this.
|
|
2061
|
+
const token = await this.getValidAccessToken();
|
|
2018
2062
|
if (!token) throw new RagableError("Not authenticated", 401, null);
|
|
2019
2063
|
return this.fetchAuthWithBearer("/me", "GET", token);
|
|
2020
2064
|
});
|
|
@@ -2059,6 +2103,15 @@ var RagableAuth = class {
|
|
|
2059
2103
|
_subCounter++;
|
|
2060
2104
|
const id = `sub-${_subCounter}`;
|
|
2061
2105
|
this.listeners.set(id, callback);
|
|
2106
|
+
void this.initialize().then((session) => {
|
|
2107
|
+
const cb = this.listeners.get(id);
|
|
2108
|
+
if (!cb) return;
|
|
2109
|
+
try {
|
|
2110
|
+
cb("INITIAL_SESSION", session);
|
|
2111
|
+
} catch (e) {
|
|
2112
|
+
this.log("Listener threw", e);
|
|
2113
|
+
}
|
|
2114
|
+
});
|
|
2062
2115
|
const unsubscribe = () => {
|
|
2063
2116
|
this.listeners.delete(id);
|
|
2064
2117
|
};
|
|
@@ -2068,12 +2121,19 @@ var RagableAuth = class {
|
|
|
2068
2121
|
getAccessToken() {
|
|
2069
2122
|
return this.currentSession?.access_token ?? null;
|
|
2070
2123
|
}
|
|
2071
|
-
|
|
2072
|
-
|
|
2124
|
+
/**
|
|
2125
|
+
* Returns an access token guaranteed fresh for at least `refreshSkewSeconds`,
|
|
2126
|
+
* refreshing (single-flight) if needed. Pass `force: true` to bypass the skew
|
|
2127
|
+
* check and refresh now — used by the transport's 401 handler so a token the
|
|
2128
|
+
* server rejected (key rotation, clock skew, early revocation) self-heals on
|
|
2129
|
+
* retry instead of failing the call.
|
|
2130
|
+
*/
|
|
2131
|
+
async getValidAccessToken(force = false) {
|
|
2132
|
+
await this.initialize();
|
|
2073
2133
|
const session = this.currentSession;
|
|
2074
2134
|
if (!session) return null;
|
|
2075
2135
|
const secondsUntilExpiry = session.expires_at - nowSeconds();
|
|
2076
|
-
if (secondsUntilExpiry <= this.refreshSkewSeconds) {
|
|
2136
|
+
if (force || secondsUntilExpiry <= this.refreshSkewSeconds) {
|
|
2077
2137
|
const refreshed = await this.singleFlightRefresh(session.refresh_token);
|
|
2078
2138
|
return refreshed?.access_token ?? null;
|
|
2079
2139
|
}
|
|
@@ -2166,6 +2226,7 @@ var RagableAuth = class {
|
|
|
2166
2226
|
};
|
|
2167
2227
|
}
|
|
2168
2228
|
async setSessionInternal(session, event) {
|
|
2229
|
+
this.sessionEpoch++;
|
|
2169
2230
|
this.currentSession = session;
|
|
2170
2231
|
await this.persistCurrentSession();
|
|
2171
2232
|
this.broadcast?.postSessionUpdated(JSON.stringify(session));
|
|
@@ -2196,12 +2257,13 @@ var RagableAuth = class {
|
|
|
2196
2257
|
if (!this.autoRefreshToken) return;
|
|
2197
2258
|
const secondsUntilExpiry = session.expires_at - nowSeconds();
|
|
2198
2259
|
const refreshIn = Math.max(0, secondsUntilExpiry - this.refreshSkewSeconds);
|
|
2199
|
-
|
|
2260
|
+
const delayMs = Math.min(refreshIn * 1e3, MAX_TIMEOUT_MS);
|
|
2261
|
+
this.log(`Scheduling refresh in ${Math.round(delayMs / 1e3)}s`);
|
|
2200
2262
|
this.refreshTimer = setTimeout(() => {
|
|
2201
2263
|
this.singleFlightRefresh(session.refresh_token).catch((e) => {
|
|
2202
2264
|
this.log("Scheduled refresh failed", e);
|
|
2203
2265
|
});
|
|
2204
|
-
},
|
|
2266
|
+
}, delayMs);
|
|
2205
2267
|
}
|
|
2206
2268
|
clearRefreshTimer() {
|
|
2207
2269
|
if (this.refreshTimer !== null) {
|
|
@@ -2209,16 +2271,57 @@ var RagableAuth = class {
|
|
|
2209
2271
|
this.refreshTimer = null;
|
|
2210
2272
|
}
|
|
2211
2273
|
}
|
|
2274
|
+
/**
|
|
2275
|
+
* Refresh the session, deduplicating concurrent callers onto one in-flight
|
|
2276
|
+
* request. Side effects (persisting the new session, or clearing it and
|
|
2277
|
+
* emitting SIGNED_OUT / TOKEN_REFRESH_FAILED) run exactly once inside the
|
|
2278
|
+
* shared promise, so two callers can't double-emit. Resolves to the new
|
|
2279
|
+
* session, or `null` when the refresh failed.
|
|
2280
|
+
*/
|
|
2212
2281
|
async singleFlightRefresh(refreshToken) {
|
|
2213
2282
|
if (this.refreshPromise) return this.refreshPromise;
|
|
2214
|
-
this.refreshPromise =
|
|
2283
|
+
this.refreshPromise = (async () => {
|
|
2284
|
+
const outcome = await this._doRefresh(refreshToken);
|
|
2285
|
+
if (outcome.ok) return outcome.session;
|
|
2286
|
+
if (outcome.terminal) {
|
|
2287
|
+
await this.handleTerminalRefreshFailure();
|
|
2288
|
+
} else {
|
|
2289
|
+
this.emit("TOKEN_REFRESH_FAILED", this.currentSession);
|
|
2290
|
+
}
|
|
2291
|
+
return null;
|
|
2292
|
+
})().finally(() => {
|
|
2215
2293
|
this.refreshPromise = null;
|
|
2216
2294
|
});
|
|
2217
2295
|
return this.refreshPromise;
|
|
2218
2296
|
}
|
|
2297
|
+
/** Clear the session locally and emit SIGNED_OUT after a definitively-rejected
|
|
2298
|
+
* refresh, so onAuthStateChange-driven UI redirects to login. */
|
|
2299
|
+
async handleTerminalRefreshFailure() {
|
|
2300
|
+
this.sessionEpoch++;
|
|
2301
|
+
this.currentSession = null;
|
|
2302
|
+
this.clearRefreshTimer();
|
|
2303
|
+
if (this.persistSession) {
|
|
2304
|
+
try {
|
|
2305
|
+
await this.storage.removeItem(this.storageKey);
|
|
2306
|
+
} catch (e) {
|
|
2307
|
+
this.log("Failed to clear session after terminal refresh failure", e);
|
|
2308
|
+
}
|
|
2309
|
+
}
|
|
2310
|
+
this.broadcast?.postSessionRemoved();
|
|
2311
|
+
this.emit("TOKEN_REFRESH_FAILED", null);
|
|
2312
|
+
this.emit("SIGNED_OUT", null);
|
|
2313
|
+
}
|
|
2219
2314
|
async _doRefresh(refreshToken) {
|
|
2315
|
+
let raw;
|
|
2316
|
+
try {
|
|
2317
|
+
raw = await this.fetchAuth("/refresh", "POST", { refreshToken });
|
|
2318
|
+
} catch (e) {
|
|
2319
|
+
const status = e instanceof RagableError ? e.status : 0;
|
|
2320
|
+
const terminal = status === 400 || status === 401 || status === 403;
|
|
2321
|
+
this.log("Refresh request failed", { status, terminal });
|
|
2322
|
+
return { ok: false, terminal, error: e };
|
|
2323
|
+
}
|
|
2220
2324
|
try {
|
|
2221
|
-
const raw = await this.fetchAuth("/refresh", "POST", { refreshToken });
|
|
2222
2325
|
const me = await this.fetchAuthWithBearer("/me", "GET", raw.accessToken);
|
|
2223
2326
|
const expiresIn = parseExpiresInSeconds(raw.expiresIn);
|
|
2224
2327
|
const session = {
|
|
@@ -2230,10 +2333,10 @@ var RagableAuth = class {
|
|
|
2230
2333
|
user: me.user
|
|
2231
2334
|
};
|
|
2232
2335
|
await this.setSessionInternal(session, "TOKEN_REFRESHED");
|
|
2233
|
-
return session;
|
|
2336
|
+
return { ok: true, session };
|
|
2234
2337
|
} catch (e) {
|
|
2235
|
-
this.log("
|
|
2236
|
-
return
|
|
2338
|
+
this.log("Post-refresh /me failed", e);
|
|
2339
|
+
return { ok: false, terminal: false, error: e };
|
|
2237
2340
|
}
|
|
2238
2341
|
}
|
|
2239
2342
|
// ─── Visibility listener ───────────────────────────────────────────────────
|
|
@@ -2335,95 +2438,6 @@ function stripTrailingCommas(text) {
|
|
|
2335
2438
|
return text.replace(/,(\s*[}\]])/g, "$1").replace(/,\s*$/, "");
|
|
2336
2439
|
}
|
|
2337
2440
|
|
|
2338
|
-
// src/content.ts
|
|
2339
|
-
var MAX_IMAGE_BYTES = 5 * 1024 * 1024;
|
|
2340
|
-
function toWireUserContent(content) {
|
|
2341
|
-
if (typeof content === "string") return content;
|
|
2342
|
-
const out = [];
|
|
2343
|
-
for (const part of content) {
|
|
2344
|
-
if (!part) continue;
|
|
2345
|
-
if (part.type === "text") {
|
|
2346
|
-
out.push(toWireTextPart(part));
|
|
2347
|
-
} else if (part.type === "image") {
|
|
2348
|
-
out.push(toWireImagePart(part));
|
|
2349
|
-
}
|
|
2350
|
-
}
|
|
2351
|
-
return out;
|
|
2352
|
-
}
|
|
2353
|
-
function toWireTextPart(part) {
|
|
2354
|
-
return { type: "text", text: part.text };
|
|
2355
|
-
}
|
|
2356
|
-
function toWireImagePart(part) {
|
|
2357
|
-
const url = imagePartToUrl(part);
|
|
2358
|
-
const detail = part.detail;
|
|
2359
|
-
return {
|
|
2360
|
-
type: "image_url",
|
|
2361
|
-
image_url: detail ? { url, detail } : { url }
|
|
2362
|
-
};
|
|
2363
|
-
}
|
|
2364
|
-
function imagePartToUrl(part) {
|
|
2365
|
-
const img = part.image;
|
|
2366
|
-
if (img instanceof URL) return img.href;
|
|
2367
|
-
if (typeof img === "string") {
|
|
2368
|
-
if (img.startsWith("http://") || img.startsWith("https://")) return img;
|
|
2369
|
-
if (img.startsWith("data:")) return img;
|
|
2370
|
-
const mediaType = requireMediaType(part, "raw base64 string");
|
|
2371
|
-
assertBase64SizeOk(img);
|
|
2372
|
-
return `data:${mediaType};base64,${img}`;
|
|
2373
|
-
}
|
|
2374
|
-
if (img instanceof Uint8Array || img instanceof ArrayBuffer) {
|
|
2375
|
-
const bytes = img instanceof Uint8Array ? img : new Uint8Array(img);
|
|
2376
|
-
assertBinarySizeOk(bytes);
|
|
2377
|
-
const mediaType = requireMediaType(part, "binary image data");
|
|
2378
|
-
const b64 = bytesToBase64(bytes);
|
|
2379
|
-
return `data:${mediaType};base64,${b64}`;
|
|
2380
|
-
}
|
|
2381
|
-
throw new RagableError(
|
|
2382
|
-
"ImagePart.image must be a string, URL, Uint8Array, or ArrayBuffer",
|
|
2383
|
-
400,
|
|
2384
|
-
{ code: "SDK_INVALID_IMAGE_PART" }
|
|
2385
|
-
);
|
|
2386
|
-
}
|
|
2387
|
-
function requireMediaType(part, what) {
|
|
2388
|
-
const m = part.mediaType?.trim();
|
|
2389
|
-
if (!m) {
|
|
2390
|
-
throw new RagableError(
|
|
2391
|
-
`ImagePart.mediaType is required for ${what} (e.g. "image/png")`,
|
|
2392
|
-
400,
|
|
2393
|
-
{ code: "SDK_IMAGE_MEDIA_TYPE_REQUIRED" }
|
|
2394
|
-
);
|
|
2395
|
-
}
|
|
2396
|
-
return m;
|
|
2397
|
-
}
|
|
2398
|
-
function assertBinarySizeOk(bytes) {
|
|
2399
|
-
if (bytes.byteLength > MAX_IMAGE_BYTES) {
|
|
2400
|
-
throw new RagableError(
|
|
2401
|
-
`Image exceeds 5MB limit (${bytes.byteLength} bytes)`,
|
|
2402
|
-
400,
|
|
2403
|
-
{ code: "SDK_IMAGE_TOO_LARGE" }
|
|
2404
|
-
);
|
|
2405
|
-
}
|
|
2406
|
-
}
|
|
2407
|
-
function assertBase64SizeOk(b64) {
|
|
2408
|
-
const approxBytes = Math.floor(b64.length * 3 / 4);
|
|
2409
|
-
if (approxBytes > MAX_IMAGE_BYTES) {
|
|
2410
|
-
throw new RagableError(
|
|
2411
|
-
`Image exceeds 5MB limit (~${approxBytes} bytes decoded)`,
|
|
2412
|
-
400,
|
|
2413
|
-
{ code: "SDK_IMAGE_TOO_LARGE" }
|
|
2414
|
-
);
|
|
2415
|
-
}
|
|
2416
|
-
}
|
|
2417
|
-
function bytesToBase64(bytes) {
|
|
2418
|
-
const CHUNK = 32768;
|
|
2419
|
-
let binary = "";
|
|
2420
|
-
for (let i = 0; i < bytes.length; i += CHUNK) {
|
|
2421
|
-
const slice = bytes.subarray(i, i + CHUNK);
|
|
2422
|
-
binary += String.fromCharCode(...slice);
|
|
2423
|
-
}
|
|
2424
|
-
return btoa(binary);
|
|
2425
|
-
}
|
|
2426
|
-
|
|
2427
2441
|
// src/stream-parts.ts
|
|
2428
2442
|
function normalizeFinishReason(raw) {
|
|
2429
2443
|
switch (raw) {
|
|
@@ -2636,9 +2650,7 @@ var ZERO_USAGE = {
|
|
|
2636
2650
|
function buildInferenceRequestBody(params, responseFormat) {
|
|
2637
2651
|
const body = {
|
|
2638
2652
|
model: params.model,
|
|
2639
|
-
messages: params.messages
|
|
2640
|
-
(m) => m.role === "user" ? { role: "user", content: toWireUserContent(m.content) } : m
|
|
2641
|
-
)
|
|
2653
|
+
messages: params.messages
|
|
2642
2654
|
};
|
|
2643
2655
|
if (params.system !== void 0) body.system = params.system;
|
|
2644
2656
|
if (typeof params.temperature === "number")
|
|
@@ -3101,6 +3113,8 @@ function normalizeBrowserApiBase() {
|
|
|
3101
3113
|
function effectiveDataAuth(options) {
|
|
3102
3114
|
if (options.dataAuth) return options.dataAuth;
|
|
3103
3115
|
const hasStatic = Boolean(options.dataStaticKey?.trim()) || typeof options.getDataStaticKey === "function";
|
|
3116
|
+
const canUserAuth = Boolean(options.authGroupId?.trim()) || typeof options.getAccessToken === "function";
|
|
3117
|
+
if (hasStatic && canUserAuth) return "auto";
|
|
3104
3118
|
if (hasStatic) return "publicAnon";
|
|
3105
3119
|
return "user";
|
|
3106
3120
|
}
|
|
@@ -3115,16 +3129,26 @@ function requireAuthGroupId(options) {
|
|
|
3115
3129
|
}
|
|
3116
3130
|
return id;
|
|
3117
3131
|
}
|
|
3118
|
-
async function
|
|
3132
|
+
async function tryGetUserAccessToken(options, ragableAuth) {
|
|
3119
3133
|
if (ragableAuth) {
|
|
3120
|
-
const token = await ragableAuth.getValidAccessToken();
|
|
3121
|
-
if (token) return token;
|
|
3134
|
+
const token = await ragableAuth.getValidAccessToken().catch(() => null);
|
|
3135
|
+
if (token?.trim()) return token.trim();
|
|
3122
3136
|
}
|
|
3123
3137
|
const getter = options.getAccessToken;
|
|
3124
3138
|
if (getter) {
|
|
3125
3139
|
const token = await getter();
|
|
3126
3140
|
if (token?.trim()) return token.trim();
|
|
3127
3141
|
}
|
|
3142
|
+
return null;
|
|
3143
|
+
}
|
|
3144
|
+
async function resolveStaticDataKey(options) {
|
|
3145
|
+
const fromGetter = options.getDataStaticKey ? await options.getDataStaticKey() : null;
|
|
3146
|
+
const key = (fromGetter?.trim() || options.dataStaticKey?.trim()) ?? "";
|
|
3147
|
+
return key || null;
|
|
3148
|
+
}
|
|
3149
|
+
async function requireAccessToken(options, ragableAuth) {
|
|
3150
|
+
const token = await tryGetUserAccessToken(options, ragableAuth);
|
|
3151
|
+
if (token) return token;
|
|
3128
3152
|
throw new RagableError(
|
|
3129
3153
|
"No access token available. Sign in first with auth.signInWithPassword() or provide getAccessToken callback.",
|
|
3130
3154
|
401,
|
|
@@ -3136,8 +3160,18 @@ async function resolveDatabaseAuthBearer(options, ragableAuth) {
|
|
|
3136
3160
|
if (mode === "user") {
|
|
3137
3161
|
return requireAccessToken(options, ragableAuth);
|
|
3138
3162
|
}
|
|
3139
|
-
|
|
3140
|
-
|
|
3163
|
+
if (mode === "auto") {
|
|
3164
|
+
const userTok = await tryGetUserAccessToken(options, ragableAuth);
|
|
3165
|
+
if (userTok) return userTok;
|
|
3166
|
+
const key2 = await resolveStaticDataKey(options);
|
|
3167
|
+
if (key2) return key2;
|
|
3168
|
+
throw new RagableError(
|
|
3169
|
+
"No access token or data key available. Sign in with auth.signInWithPassword() or configure dataStaticKey.",
|
|
3170
|
+
401,
|
|
3171
|
+
{ code: "SDK_NO_ACCESS_TOKEN" }
|
|
3172
|
+
);
|
|
3173
|
+
}
|
|
3174
|
+
const key = await resolveStaticDataKey(options);
|
|
3141
3175
|
if (!key) {
|
|
3142
3176
|
throw new RagableError(
|
|
3143
3177
|
mode === "publicAnon" ? "dataAuth publicAnon requires getDataStaticKey or dataStaticKey" : "dataAuth admin requires getDataStaticKey or dataStaticKey",
|
|
@@ -3241,6 +3275,14 @@ var RagableBrowserAuthClient = class {
|
|
|
3241
3275
|
getSession() {
|
|
3242
3276
|
return this.auth.getSession();
|
|
3243
3277
|
}
|
|
3278
|
+
/**
|
|
3279
|
+
* Returns a valid (auto-refreshed) access token for the current session, or
|
|
3280
|
+
* `null` if signed out. The sanctioned way to obtain a token for a hand-rolled
|
|
3281
|
+
* `fetch` to a custom endpoint — never read tokens out of storage yourself.
|
|
3282
|
+
*/
|
|
3283
|
+
getValidAccessToken() {
|
|
3284
|
+
return this.ragableAuth ? this.ragableAuth.getValidAccessToken() : Promise.resolve(null);
|
|
3285
|
+
}
|
|
3244
3286
|
};
|
|
3245
3287
|
function collectionRecordToRowWithMeta(record) {
|
|
3246
3288
|
const { data, id, createdAt, updatedAt } = record;
|
|
@@ -3279,13 +3321,11 @@ var BrowserCollectionApi = class {
|
|
|
3279
3321
|
const { returnMode, body } = this.normalizeFindArgs(whereOrParams);
|
|
3280
3322
|
const res = await this.requestFind(body);
|
|
3281
3323
|
if (res.error) return res;
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
}
|
|
3288
|
-
return res;
|
|
3324
|
+
const data = returnMode === "flat" ? collectionRecordsToRowWithMeta(res.data) : res.data;
|
|
3325
|
+
return {
|
|
3326
|
+
data,
|
|
3327
|
+
error: null
|
|
3328
|
+
};
|
|
3289
3329
|
});
|
|
3290
3330
|
/**
|
|
3291
3331
|
* @deprecated Use {@link BrowserCollectionApi.findMany} — same behavior.
|
|
@@ -3474,7 +3514,16 @@ var RagableBrowserDatabaseClient = class {
|
|
|
3474
3514
|
const headers = this.baseHeaders();
|
|
3475
3515
|
headers.set("Authorization", `Bearer ${token}`);
|
|
3476
3516
|
headers.set("Content-Type", "application/json");
|
|
3477
|
-
const
|
|
3517
|
+
const dataMode = effectiveDataAuth(this.options);
|
|
3518
|
+
let readOnly;
|
|
3519
|
+
if (dataMode === "publicAnon") {
|
|
3520
|
+
readOnly = true;
|
|
3521
|
+
} else if (dataMode === "auto") {
|
|
3522
|
+
const userTok = await tryGetUserAccessToken(this.options, this.ragableAuth);
|
|
3523
|
+
readOnly = userTok ? params.readOnly !== false : true;
|
|
3524
|
+
} else {
|
|
3525
|
+
readOnly = params.readOnly !== false;
|
|
3526
|
+
}
|
|
3478
3527
|
const response = await this.fetchImpl(
|
|
3479
3528
|
this.toUrl(`/auth-groups/${gid}/data/query`),
|
|
3480
3529
|
{
|
|
@@ -3767,10 +3816,11 @@ async function subscribeBrowserRealtime(options, ragableAuth, fetchImpl, params)
|
|
|
3767
3816
|
return subscription;
|
|
3768
3817
|
}
|
|
3769
3818
|
var BrowserStorageBucketClient = class {
|
|
3770
|
-
constructor(options, fetchImpl, bucketId) {
|
|
3819
|
+
constructor(options, fetchImpl, bucketId, ragableAuth = null) {
|
|
3771
3820
|
this.options = options;
|
|
3772
3821
|
this.fetchImpl = fetchImpl;
|
|
3773
3822
|
this.bucketId = bucketId;
|
|
3823
|
+
this.ragableAuth = ragableAuth;
|
|
3774
3824
|
}
|
|
3775
3825
|
get authGroupId() {
|
|
3776
3826
|
const id = this.options.authGroupId?.trim();
|
|
@@ -3780,14 +3830,28 @@ var BrowserStorageBucketClient = class {
|
|
|
3780
3830
|
base() {
|
|
3781
3831
|
return `${normalizeBrowserApiBase()}/auth-groups/${this.authGroupId}/storage/buckets/${encodeURIComponent(this.bucketId)}`;
|
|
3782
3832
|
}
|
|
3833
|
+
/**
|
|
3834
|
+
* Same credential resolution as the database client (see resolveDatabaseAuthBearer):
|
|
3835
|
+
* in the generated-site default (`auto`), a signed-in user's auto-refreshed JWT
|
|
3836
|
+
* is used so storage calls carry the user's identity; logged-out visitors fall
|
|
3837
|
+
* back to the anon key. Previously storage ignored the managed session entirely.
|
|
3838
|
+
*/
|
|
3783
3839
|
async bearerToken() {
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3840
|
+
return resolveDatabaseAuthBearer(this.options, this.ragableAuth);
|
|
3841
|
+
}
|
|
3842
|
+
/**
|
|
3843
|
+
* The storage backend has historically returned HTTP 200 with an `{ error }`
|
|
3844
|
+
* body on some failures; without this guard the SDK would resolve those as
|
|
3845
|
+
* successful uploads/deletes. Treat any 2xx whose body carries a non-empty
|
|
3846
|
+
* `error` as a failure.
|
|
3847
|
+
*/
|
|
3848
|
+
assertNoEmbeddedError(payload, status) {
|
|
3849
|
+
if (payload && typeof payload === "object" && !Array.isArray(payload)) {
|
|
3850
|
+
const err = payload.error;
|
|
3851
|
+
if (typeof err === "string" && err.trim()) {
|
|
3852
|
+
throw new RagableError(err, status, payload);
|
|
3853
|
+
}
|
|
3789
3854
|
}
|
|
3790
|
-
throw new RagableError("No auth token for storage. Provide dataStaticKey or getAccessToken.", 401, { code: "SDK_NO_ACCESS_TOKEN" });
|
|
3791
3855
|
}
|
|
3792
3856
|
async req(method, path, body) {
|
|
3793
3857
|
const token = await this.bearerToken();
|
|
@@ -3800,7 +3864,8 @@ var BrowserStorageBucketClient = class {
|
|
|
3800
3864
|
body: body instanceof FormData ? body : body !== void 0 ? JSON.stringify(body) : void 0
|
|
3801
3865
|
});
|
|
3802
3866
|
const payload = await res.json().catch(() => ({}));
|
|
3803
|
-
if (!res.ok) throw new RagableError(payload
|
|
3867
|
+
if (!res.ok) throw new RagableError(extractErrorMessage(payload, res.statusText), res.status, payload);
|
|
3868
|
+
this.assertNoEmbeddedError(payload, res.status);
|
|
3804
3869
|
return payload;
|
|
3805
3870
|
}
|
|
3806
3871
|
list(params = {}) {
|
|
@@ -3824,7 +3889,8 @@ var BrowserStorageBucketClient = class {
|
|
|
3824
3889
|
if (params.cacheControl) form.set("cacheControl", params.cacheControl);
|
|
3825
3890
|
const res = await this.fetchImpl(`${this.base()}/upload`, { method: "POST", headers, body: form });
|
|
3826
3891
|
const payload = await res.json().catch(() => ({}));
|
|
3827
|
-
if (!res.ok) throw new RagableError(payload
|
|
3892
|
+
if (!res.ok) throw new RagableError(extractErrorMessage(payload, res.statusText), res.status, payload);
|
|
3893
|
+
this.assertNoEmbeddedError(payload, res.status);
|
|
3828
3894
|
return payload;
|
|
3829
3895
|
}
|
|
3830
3896
|
download(params) {
|
|
@@ -3865,12 +3931,18 @@ var BrowserStorageBucketClient = class {
|
|
|
3865
3931
|
}
|
|
3866
3932
|
};
|
|
3867
3933
|
var RagableBrowserStorageClient = class {
|
|
3868
|
-
constructor(options, fetchImpl) {
|
|
3934
|
+
constructor(options, fetchImpl, ragableAuth = null) {
|
|
3869
3935
|
this.options = options;
|
|
3870
3936
|
this.fetchImpl = fetchImpl;
|
|
3937
|
+
this.ragableAuth = ragableAuth;
|
|
3871
3938
|
}
|
|
3872
3939
|
from(bucketId) {
|
|
3873
|
-
return new BrowserStorageBucketClient(
|
|
3940
|
+
return new BrowserStorageBucketClient(
|
|
3941
|
+
this.options,
|
|
3942
|
+
this.fetchImpl,
|
|
3943
|
+
bucketId,
|
|
3944
|
+
this.ragableAuth
|
|
3945
|
+
);
|
|
3874
3946
|
}
|
|
3875
3947
|
};
|
|
3876
3948
|
var RagableBrowserMailClient = class {
|
|
@@ -3987,6 +4059,99 @@ var RagableBrowserMailClient = class {
|
|
|
3987
4059
|
return message;
|
|
3988
4060
|
}
|
|
3989
4061
|
};
|
|
4062
|
+
var RagableBrowserFunctionsClient = class {
|
|
4063
|
+
constructor(options, auth) {
|
|
4064
|
+
this.options = options;
|
|
4065
|
+
this.auth = auth;
|
|
4066
|
+
__publicField(this, "fetchImpl");
|
|
4067
|
+
this.fetchImpl = bindFetch(options.fetch);
|
|
4068
|
+
}
|
|
4069
|
+
requireWebsiteId() {
|
|
4070
|
+
const websiteId = this.options.websiteId?.trim();
|
|
4071
|
+
if (!websiteId) {
|
|
4072
|
+
throw new RagableError(
|
|
4073
|
+
"websiteId is required for functions. Use createWebsiteRagableClient()/createAppClient() or pass createBrowserClient({ websiteId, ... }).",
|
|
4074
|
+
400,
|
|
4075
|
+
{ code: "SDK_MISSING_WEBSITE_ID" }
|
|
4076
|
+
);
|
|
4077
|
+
}
|
|
4078
|
+
return websiteId;
|
|
4079
|
+
}
|
|
4080
|
+
toUrl(name) {
|
|
4081
|
+
const orgId = this.options.organizationId;
|
|
4082
|
+
const websiteId = this.requireWebsiteId();
|
|
4083
|
+
return `${normalizeBrowserApiBase()}/public/organizations/${orgId}/websites/${websiteId}/functions/${encodeURIComponent(
|
|
4084
|
+
name
|
|
4085
|
+
)}/invoke`;
|
|
4086
|
+
}
|
|
4087
|
+
/**
|
|
4088
|
+
* Best-effort end-user bearer, forwarded to the function as `context.auth.token`.
|
|
4089
|
+
* Functions are public, so this never throws — anonymous calls send no token.
|
|
4090
|
+
*/
|
|
4091
|
+
async getOptionalToken() {
|
|
4092
|
+
if (this.auth) {
|
|
4093
|
+
const token = await this.auth.getValidAccessToken().catch(() => null);
|
|
4094
|
+
if (token) return token;
|
|
4095
|
+
}
|
|
4096
|
+
const caller = await Promise.resolve(this.options.getAccessToken?.()).catch(
|
|
4097
|
+
() => null
|
|
4098
|
+
);
|
|
4099
|
+
if (typeof caller === "string" && caller.trim()) return caller.trim();
|
|
4100
|
+
const staticKey = this.options.dataStaticKey?.trim();
|
|
4101
|
+
if (staticKey) return staticKey;
|
|
4102
|
+
return null;
|
|
4103
|
+
}
|
|
4104
|
+
/**
|
|
4105
|
+
* Invoke a function by name. Prefer the typed `client.functions.<name>(input)`
|
|
4106
|
+
* accessors; use this when the name is dynamic.
|
|
4107
|
+
*/
|
|
4108
|
+
async invoke(name, input, options) {
|
|
4109
|
+
const fnName = String(name ?? "").trim();
|
|
4110
|
+
if (!fnName) {
|
|
4111
|
+
throw new RagableError(
|
|
4112
|
+
"functions.invoke requires a function name",
|
|
4113
|
+
400,
|
|
4114
|
+
{ code: "SDK_MISSING_FUNCTION_NAME" }
|
|
4115
|
+
);
|
|
4116
|
+
}
|
|
4117
|
+
const headers = new Headers(options?.headers ?? this.options.headers);
|
|
4118
|
+
headers.set("Content-Type", "application/json");
|
|
4119
|
+
const token = await this.getOptionalToken();
|
|
4120
|
+
if (token) headers.set("Authorization", `Bearer ${token}`);
|
|
4121
|
+
const response = await this.fetchImpl(this.toUrl(fnName), {
|
|
4122
|
+
method: "POST",
|
|
4123
|
+
headers,
|
|
4124
|
+
body: JSON.stringify({ input: input ?? null }),
|
|
4125
|
+
...options?.signal ? { signal: options.signal } : {}
|
|
4126
|
+
});
|
|
4127
|
+
const payload = await parseMaybeJsonBody(response);
|
|
4128
|
+
if (!response.ok) {
|
|
4129
|
+
const message = extractErrorMessage(payload, response.statusText);
|
|
4130
|
+
throw new RagableError(message, response.status, payload);
|
|
4131
|
+
}
|
|
4132
|
+
if (payload && typeof payload === "object" && !Array.isArray(payload) && "result" in payload) {
|
|
4133
|
+
return payload.result;
|
|
4134
|
+
}
|
|
4135
|
+
return payload;
|
|
4136
|
+
}
|
|
4137
|
+
/** Build the typed Proxy exposed as `client.functions`. */
|
|
4138
|
+
asInvoker() {
|
|
4139
|
+
const invoke = this.invoke.bind(this);
|
|
4140
|
+
return new Proxy(
|
|
4141
|
+
{},
|
|
4142
|
+
{
|
|
4143
|
+
get: (_target, prop) => {
|
|
4144
|
+
if (typeof prop !== "string") return void 0;
|
|
4145
|
+
if (prop === "then") return void 0;
|
|
4146
|
+
if (prop === "invoke") {
|
|
4147
|
+
return (name, input, options) => invoke(name, input, options);
|
|
4148
|
+
}
|
|
4149
|
+
return (input, options) => invoke(prop, input, options);
|
|
4150
|
+
}
|
|
4151
|
+
}
|
|
4152
|
+
);
|
|
4153
|
+
}
|
|
4154
|
+
};
|
|
3990
4155
|
var RagableBrowserAgentsClient = class {
|
|
3991
4156
|
constructor(options) {
|
|
3992
4157
|
this.options = options;
|
|
@@ -4314,6 +4479,11 @@ var RagableBrowser = class {
|
|
|
4314
4479
|
__publicField(this, "db");
|
|
4315
4480
|
__publicField(this, "storage");
|
|
4316
4481
|
__publicField(this, "mail");
|
|
4482
|
+
/**
|
|
4483
|
+
* Backend edge functions — call a `/functions/<name>.ts` handler with
|
|
4484
|
+
* `client.functions.<name>(input)`. Runs server-side. See {@link FunctionInvoker}.
|
|
4485
|
+
*/
|
|
4486
|
+
__publicField(this, "functions");
|
|
4317
4487
|
__publicField(this, "transport");
|
|
4318
4488
|
__publicField(this, "_ragableAuth");
|
|
4319
4489
|
/** Delegates to `database.from()`. Kept for back-compat — prefer `database.from()`. */
|
|
@@ -4333,13 +4503,12 @@ var RagableBrowser = class {
|
|
|
4333
4503
|
auth: options.auth
|
|
4334
4504
|
});
|
|
4335
4505
|
this.transport.setRefreshHandler(async () => {
|
|
4336
|
-
|
|
4337
|
-
|
|
4506
|
+
const mode = effectiveDataAuth(options);
|
|
4507
|
+
if (mode !== "user" && mode !== "auto") return null;
|
|
4508
|
+
return this._ragableAuth.getValidAccessToken(true).catch(() => null);
|
|
4509
|
+
});
|
|
4510
|
+
this._ragableAuth.initialize().catch(() => {
|
|
4338
4511
|
});
|
|
4339
|
-
if (!options.getAccessToken && effectiveDataAuth(options) === "user") {
|
|
4340
|
-
this._ragableAuth.initialize().catch(() => {
|
|
4341
|
-
});
|
|
4342
|
-
}
|
|
4343
4512
|
} else {
|
|
4344
4513
|
this._ragableAuth = null;
|
|
4345
4514
|
}
|
|
@@ -4358,8 +4527,25 @@ var RagableBrowser = class {
|
|
|
4358
4527
|
);
|
|
4359
4528
|
this.database._setTransport(this.transport);
|
|
4360
4529
|
this.db = this.database;
|
|
4361
|
-
this.storage = new RagableBrowserStorageClient(
|
|
4530
|
+
this.storage = new RagableBrowserStorageClient(
|
|
4531
|
+
options,
|
|
4532
|
+
bindFetch(options.fetch),
|
|
4533
|
+
this._ragableAuth
|
|
4534
|
+
);
|
|
4362
4535
|
this.mail = new RagableBrowserMailClient(options, this._ragableAuth);
|
|
4536
|
+
this.functions = new RagableBrowserFunctionsClient(
|
|
4537
|
+
options,
|
|
4538
|
+
this._ragableAuth
|
|
4539
|
+
).asInvoker();
|
|
4540
|
+
}
|
|
4541
|
+
/**
|
|
4542
|
+
* Resolves once the persisted session has been restored (and refreshed if it
|
|
4543
|
+
* was expired). Await this before reading auth state at startup to avoid a
|
|
4544
|
+
* logged-out flash, e.g. `const session = await client.ready()`. Resolves
|
|
4545
|
+
* `null` when no auth group is configured or no session is stored.
|
|
4546
|
+
*/
|
|
4547
|
+
ready() {
|
|
4548
|
+
return this._ragableAuth ? this._ragableAuth.initialize() : Promise.resolve(null);
|
|
4363
4549
|
}
|
|
4364
4550
|
destroy() {
|
|
4365
4551
|
this._ragableAuth?.destroy();
|
|
@@ -4400,6 +4586,7 @@ export {
|
|
|
4400
4586
|
RagableBrowserAiClient,
|
|
4401
4587
|
RagableBrowserAuthClient,
|
|
4402
4588
|
RagableBrowserDatabaseClient,
|
|
4589
|
+
RagableBrowserFunctionsClient,
|
|
4403
4590
|
RagableBrowserMailClient,
|
|
4404
4591
|
RagableBrowserStorageClient,
|
|
4405
4592
|
RagableError,
|
|
@@ -4413,7 +4600,6 @@ export {
|
|
|
4413
4600
|
bindFetch,
|
|
4414
4601
|
buildInferenceRequestBody,
|
|
4415
4602
|
buildResponseFormat,
|
|
4416
|
-
bytesToBase64,
|
|
4417
4603
|
collectAssistantTextFromUiSegments,
|
|
4418
4604
|
collectionRecordToRowWithMeta,
|
|
4419
4605
|
collectionRecordsToRowWithMeta,
|
|
@@ -4429,7 +4615,6 @@ export {
|
|
|
4429
4615
|
formatPostgrestError,
|
|
4430
4616
|
formatSdkError,
|
|
4431
4617
|
generateIdempotencyKey,
|
|
4432
|
-
imagePartToUrl,
|
|
4433
4618
|
isIncompleteAgentStreamError,
|
|
4434
4619
|
mapAgentEvent,
|
|
4435
4620
|
mapFireworksChunk,
|
|
@@ -4444,7 +4629,6 @@ export {
|
|
|
4444
4629
|
runAgentChatStreamLenient,
|
|
4445
4630
|
streamObjectFromContext,
|
|
4446
4631
|
toRagableResult,
|
|
4447
|
-
toWireUserContent,
|
|
4448
4632
|
tryParsePartialJson,
|
|
4449
4633
|
unwrapPostgrest,
|
|
4450
4634
|
wrapStreamTextAsObject
|