@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.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
@@ -2431,95 +2429,6 @@ function stripTrailingCommas(text) {
2431
2429
  return text.replace(/,(\s*[}\]])/g, "$1").replace(/,\s*$/, "");
2432
2430
  }
2433
2431
 
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
2432
  // src/stream-parts.ts
2524
2433
  function normalizeFinishReason(raw) {
2525
2434
  switch (raw) {
@@ -2732,9 +2641,7 @@ var ZERO_USAGE = {
2732
2641
  function buildInferenceRequestBody(params, responseFormat) {
2733
2642
  const body = {
2734
2643
  model: params.model,
2735
- messages: params.messages.map(
2736
- (m) => m.role === "user" ? { role: "user", content: toWireUserContent(m.content) } : m
2737
- )
2644
+ messages: params.messages
2738
2645
  };
2739
2646
  if (params.system !== void 0) body.system = params.system;
2740
2647
  if (typeof params.temperature === "number")
@@ -4083,6 +3990,99 @@ var RagableBrowserMailClient = class {
4083
3990
  return message;
4084
3991
  }
4085
3992
  };
3993
+ var RagableBrowserFunctionsClient = class {
3994
+ constructor(options, auth) {
3995
+ this.options = options;
3996
+ this.auth = auth;
3997
+ __publicField(this, "fetchImpl");
3998
+ this.fetchImpl = bindFetch(options.fetch);
3999
+ }
4000
+ requireWebsiteId() {
4001
+ const websiteId = this.options.websiteId?.trim();
4002
+ if (!websiteId) {
4003
+ throw new RagableError(
4004
+ "websiteId is required for functions. Use createWebsiteRagableClient()/createAppClient() or pass createBrowserClient({ websiteId, ... }).",
4005
+ 400,
4006
+ { code: "SDK_MISSING_WEBSITE_ID" }
4007
+ );
4008
+ }
4009
+ return websiteId;
4010
+ }
4011
+ toUrl(name) {
4012
+ const orgId = this.options.organizationId;
4013
+ const websiteId = this.requireWebsiteId();
4014
+ return `${normalizeBrowserApiBase()}/public/organizations/${orgId}/websites/${websiteId}/functions/${encodeURIComponent(
4015
+ name
4016
+ )}/invoke`;
4017
+ }
4018
+ /**
4019
+ * Best-effort end-user bearer, forwarded to the function as `context.auth.token`.
4020
+ * Functions are public, so this never throws — anonymous calls send no token.
4021
+ */
4022
+ async getOptionalToken() {
4023
+ if (this.auth) {
4024
+ const token = await this.auth.getValidAccessToken().catch(() => null);
4025
+ if (token) return token;
4026
+ }
4027
+ const caller = await Promise.resolve(this.options.getAccessToken?.()).catch(
4028
+ () => null
4029
+ );
4030
+ if (typeof caller === "string" && caller.trim()) return caller.trim();
4031
+ const staticKey = this.options.dataStaticKey?.trim();
4032
+ if (staticKey) return staticKey;
4033
+ return null;
4034
+ }
4035
+ /**
4036
+ * Invoke a function by name. Prefer the typed `client.functions.<name>(input)`
4037
+ * accessors; use this when the name is dynamic.
4038
+ */
4039
+ async invoke(name, input, options) {
4040
+ const fnName = String(name ?? "").trim();
4041
+ if (!fnName) {
4042
+ throw new RagableError(
4043
+ "functions.invoke requires a function name",
4044
+ 400,
4045
+ { code: "SDK_MISSING_FUNCTION_NAME" }
4046
+ );
4047
+ }
4048
+ const headers = new Headers(options?.headers ?? this.options.headers);
4049
+ headers.set("Content-Type", "application/json");
4050
+ const token = await this.getOptionalToken();
4051
+ if (token) headers.set("Authorization", `Bearer ${token}`);
4052
+ const response = await this.fetchImpl(this.toUrl(fnName), {
4053
+ method: "POST",
4054
+ headers,
4055
+ body: JSON.stringify({ input: input ?? null }),
4056
+ ...options?.signal ? { signal: options.signal } : {}
4057
+ });
4058
+ const payload = await parseMaybeJsonBody(response);
4059
+ if (!response.ok) {
4060
+ const message = extractErrorMessage(payload, response.statusText);
4061
+ throw new RagableError(message, response.status, payload);
4062
+ }
4063
+ if (payload && typeof payload === "object" && !Array.isArray(payload) && "result" in payload) {
4064
+ return payload.result;
4065
+ }
4066
+ return payload;
4067
+ }
4068
+ /** Build the typed Proxy exposed as `client.functions`. */
4069
+ asInvoker() {
4070
+ const invoke = this.invoke.bind(this);
4071
+ return new Proxy(
4072
+ {},
4073
+ {
4074
+ get: (_target, prop) => {
4075
+ if (typeof prop !== "string") return void 0;
4076
+ if (prop === "then") return void 0;
4077
+ if (prop === "invoke") {
4078
+ return (name, input, options) => invoke(name, input, options);
4079
+ }
4080
+ return (input, options) => invoke(prop, input, options);
4081
+ }
4082
+ }
4083
+ );
4084
+ }
4085
+ };
4086
4086
  var RagableBrowserAgentsClient = class {
4087
4087
  constructor(options) {
4088
4088
  this.options = options;
@@ -4410,6 +4410,11 @@ var RagableBrowser = class {
4410
4410
  __publicField(this, "db");
4411
4411
  __publicField(this, "storage");
4412
4412
  __publicField(this, "mail");
4413
+ /**
4414
+ * Backend edge functions — call a `/functions/<name>.ts` handler with
4415
+ * `client.functions.<name>(input)`. Runs server-side. See {@link FunctionInvoker}.
4416
+ */
4417
+ __publicField(this, "functions");
4413
4418
  __publicField(this, "transport");
4414
4419
  __publicField(this, "_ragableAuth");
4415
4420
  /** Delegates to `database.from()`. Kept for back-compat — prefer `database.from()`. */
@@ -4456,6 +4461,10 @@ var RagableBrowser = class {
4456
4461
  this.db = this.database;
4457
4462
  this.storage = new RagableBrowserStorageClient(options, bindFetch(options.fetch));
4458
4463
  this.mail = new RagableBrowserMailClient(options, this._ragableAuth);
4464
+ this.functions = new RagableBrowserFunctionsClient(
4465
+ options,
4466
+ this._ragableAuth
4467
+ ).asInvoker();
4459
4468
  }
4460
4469
  destroy() {
4461
4470
  this._ragableAuth?.destroy();
@@ -4497,6 +4506,7 @@ function createClient(options) {
4497
4506
  RagableBrowserAiClient,
4498
4507
  RagableBrowserAuthClient,
4499
4508
  RagableBrowserDatabaseClient,
4509
+ RagableBrowserFunctionsClient,
4500
4510
  RagableBrowserMailClient,
4501
4511
  RagableBrowserStorageClient,
4502
4512
  RagableError,
@@ -4510,7 +4520,6 @@ function createClient(options) {
4510
4520
  bindFetch,
4511
4521
  buildInferenceRequestBody,
4512
4522
  buildResponseFormat,
4513
- bytesToBase64,
4514
4523
  collectAssistantTextFromUiSegments,
4515
4524
  collectionRecordToRowWithMeta,
4516
4525
  collectionRecordsToRowWithMeta,
@@ -4526,7 +4535,6 @@ function createClient(options) {
4526
4535
  formatPostgrestError,
4527
4536
  formatSdkError,
4528
4537
  generateIdempotencyKey,
4529
- imagePartToUrl,
4530
4538
  isIncompleteAgentStreamError,
4531
4539
  mapAgentEvent,
4532
4540
  mapFireworksChunk,
@@ -4541,7 +4549,6 @@ function createClient(options) {
4541
4549
  runAgentChatStreamLenient,
4542
4550
  streamObjectFromContext,
4543
4551
  toRagableResult,
4544
- toWireUserContent,
4545
4552
  tryParsePartialJson,
4546
4553
  unwrapPostgrest,
4547
4554
  wrapStreamTextAsObject