@ragable/sdk 0.7.10 → 0.8.0

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.mjs CHANGED
@@ -2335,95 +2335,6 @@ function stripTrailingCommas(text) {
2335
2335
  return text.replace(/,(\s*[}\]])/g, "$1").replace(/,\s*$/, "");
2336
2336
  }
2337
2337
 
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
2338
  // src/stream-parts.ts
2428
2339
  function normalizeFinishReason(raw) {
2429
2340
  switch (raw) {
@@ -2636,9 +2547,7 @@ var ZERO_USAGE = {
2636
2547
  function buildInferenceRequestBody(params, responseFormat) {
2637
2548
  const body = {
2638
2549
  model: params.model,
2639
- messages: params.messages.map(
2640
- (m) => m.role === "user" ? { role: "user", content: toWireUserContent(m.content) } : m
2641
- )
2550
+ messages: params.messages
2642
2551
  };
2643
2552
  if (params.system !== void 0) body.system = params.system;
2644
2553
  if (typeof params.temperature === "number")
@@ -3987,6 +3896,99 @@ var RagableBrowserMailClient = class {
3987
3896
  return message;
3988
3897
  }
3989
3898
  };
3899
+ var RagableBrowserFunctionsClient = class {
3900
+ constructor(options, auth) {
3901
+ this.options = options;
3902
+ this.auth = auth;
3903
+ __publicField(this, "fetchImpl");
3904
+ this.fetchImpl = bindFetch(options.fetch);
3905
+ }
3906
+ requireWebsiteId() {
3907
+ const websiteId = this.options.websiteId?.trim();
3908
+ if (!websiteId) {
3909
+ throw new RagableError(
3910
+ "websiteId is required for functions. Use createWebsiteRagableClient()/createAppClient() or pass createBrowserClient({ websiteId, ... }).",
3911
+ 400,
3912
+ { code: "SDK_MISSING_WEBSITE_ID" }
3913
+ );
3914
+ }
3915
+ return websiteId;
3916
+ }
3917
+ toUrl(name) {
3918
+ const orgId = this.options.organizationId;
3919
+ const websiteId = this.requireWebsiteId();
3920
+ return `${normalizeBrowserApiBase()}/public/organizations/${orgId}/websites/${websiteId}/functions/${encodeURIComponent(
3921
+ name
3922
+ )}/invoke`;
3923
+ }
3924
+ /**
3925
+ * Best-effort end-user bearer, forwarded to the function as `context.auth.token`.
3926
+ * Functions are public, so this never throws — anonymous calls send no token.
3927
+ */
3928
+ async getOptionalToken() {
3929
+ if (this.auth) {
3930
+ const token = await this.auth.getValidAccessToken().catch(() => null);
3931
+ if (token) return token;
3932
+ }
3933
+ const caller = await Promise.resolve(this.options.getAccessToken?.()).catch(
3934
+ () => null
3935
+ );
3936
+ if (typeof caller === "string" && caller.trim()) return caller.trim();
3937
+ const staticKey = this.options.dataStaticKey?.trim();
3938
+ if (staticKey) return staticKey;
3939
+ return null;
3940
+ }
3941
+ /**
3942
+ * Invoke a function by name. Prefer the typed `client.functions.<name>(input)`
3943
+ * accessors; use this when the name is dynamic.
3944
+ */
3945
+ async invoke(name, input, options) {
3946
+ const fnName = String(name ?? "").trim();
3947
+ if (!fnName) {
3948
+ throw new RagableError(
3949
+ "functions.invoke requires a function name",
3950
+ 400,
3951
+ { code: "SDK_MISSING_FUNCTION_NAME" }
3952
+ );
3953
+ }
3954
+ const headers = new Headers(options?.headers ?? this.options.headers);
3955
+ headers.set("Content-Type", "application/json");
3956
+ const token = await this.getOptionalToken();
3957
+ if (token) headers.set("Authorization", `Bearer ${token}`);
3958
+ const response = await this.fetchImpl(this.toUrl(fnName), {
3959
+ method: "POST",
3960
+ headers,
3961
+ body: JSON.stringify({ input: input ?? null }),
3962
+ ...options?.signal ? { signal: options.signal } : {}
3963
+ });
3964
+ const payload = await parseMaybeJsonBody(response);
3965
+ if (!response.ok) {
3966
+ const message = extractErrorMessage(payload, response.statusText);
3967
+ throw new RagableError(message, response.status, payload);
3968
+ }
3969
+ if (payload && typeof payload === "object" && !Array.isArray(payload) && "result" in payload) {
3970
+ return payload.result;
3971
+ }
3972
+ return payload;
3973
+ }
3974
+ /** Build the typed Proxy exposed as `client.functions`. */
3975
+ asInvoker() {
3976
+ const invoke = this.invoke.bind(this);
3977
+ return new Proxy(
3978
+ {},
3979
+ {
3980
+ get: (_target, prop) => {
3981
+ if (typeof prop !== "string") return void 0;
3982
+ if (prop === "then") return void 0;
3983
+ if (prop === "invoke") {
3984
+ return (name, input, options) => invoke(name, input, options);
3985
+ }
3986
+ return (input, options) => invoke(prop, input, options);
3987
+ }
3988
+ }
3989
+ );
3990
+ }
3991
+ };
3990
3992
  var RagableBrowserAgentsClient = class {
3991
3993
  constructor(options) {
3992
3994
  this.options = options;
@@ -4314,6 +4316,11 @@ var RagableBrowser = class {
4314
4316
  __publicField(this, "db");
4315
4317
  __publicField(this, "storage");
4316
4318
  __publicField(this, "mail");
4319
+ /**
4320
+ * Backend edge functions — call a `/functions/<name>.ts` handler with
4321
+ * `client.functions.<name>(input)`. Runs server-side. See {@link FunctionInvoker}.
4322
+ */
4323
+ __publicField(this, "functions");
4317
4324
  __publicField(this, "transport");
4318
4325
  __publicField(this, "_ragableAuth");
4319
4326
  /** Delegates to `database.from()`. Kept for back-compat — prefer `database.from()`. */
@@ -4360,6 +4367,10 @@ var RagableBrowser = class {
4360
4367
  this.db = this.database;
4361
4368
  this.storage = new RagableBrowserStorageClient(options, bindFetch(options.fetch));
4362
4369
  this.mail = new RagableBrowserMailClient(options, this._ragableAuth);
4370
+ this.functions = new RagableBrowserFunctionsClient(
4371
+ options,
4372
+ this._ragableAuth
4373
+ ).asInvoker();
4363
4374
  }
4364
4375
  destroy() {
4365
4376
  this._ragableAuth?.destroy();
@@ -4400,6 +4411,7 @@ export {
4400
4411
  RagableBrowserAiClient,
4401
4412
  RagableBrowserAuthClient,
4402
4413
  RagableBrowserDatabaseClient,
4414
+ RagableBrowserFunctionsClient,
4403
4415
  RagableBrowserMailClient,
4404
4416
  RagableBrowserStorageClient,
4405
4417
  RagableError,
@@ -4413,7 +4425,6 @@ export {
4413
4425
  bindFetch,
4414
4426
  buildInferenceRequestBody,
4415
4427
  buildResponseFormat,
4416
- bytesToBase64,
4417
4428
  collectAssistantTextFromUiSegments,
4418
4429
  collectionRecordToRowWithMeta,
4419
4430
  collectionRecordsToRowWithMeta,
@@ -4429,7 +4440,6 @@ export {
4429
4440
  formatPostgrestError,
4430
4441
  formatSdkError,
4431
4442
  generateIdempotencyKey,
4432
- imagePartToUrl,
4433
4443
  isIncompleteAgentStreamError,
4434
4444
  mapAgentEvent,
4435
4445
  mapFireworksChunk,
@@ -4444,7 +4454,6 @@ export {
4444
4454
  runAgentChatStreamLenient,
4445
4455
  streamObjectFromContext,
4446
4456
  toRagableResult,
4447
- toWireUserContent,
4448
4457
  tryParsePartialJson,
4449
4458
  unwrapPostgrest,
4450
4459
  wrapStreamTextAsObject