@ragable/sdk 0.0.3 → 0.4.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
@@ -223,6 +223,74 @@ function toArrayBuffer(value) {
223
223
  return copy.buffer;
224
224
  }
225
225
 
226
+ // src/sse.ts
227
+ async function parseMaybeJsonBody(response) {
228
+ const contentType = response.headers.get("content-type") ?? "";
229
+ if (contentType.includes("application/json")) {
230
+ try {
231
+ return await response.json();
232
+ } catch {
233
+ return null;
234
+ }
235
+ }
236
+ try {
237
+ return await response.text();
238
+ } catch {
239
+ return null;
240
+ }
241
+ }
242
+ function parseSseDataLine(line) {
243
+ const dataPrefix = "data: ";
244
+ if (!line.startsWith(dataPrefix)) {
245
+ return null;
246
+ }
247
+ const json = line.slice(dataPrefix.length).trim();
248
+ if (json.length === 0 || json === "[DONE]") {
249
+ return null;
250
+ }
251
+ try {
252
+ return JSON.parse(json);
253
+ } catch {
254
+ return null;
255
+ }
256
+ }
257
+ async function* readSseStream(body) {
258
+ const reader = body.getReader();
259
+ const decoder = new TextDecoder();
260
+ let buffer = "";
261
+ try {
262
+ while (true) {
263
+ const { done, value } = await reader.read();
264
+ if (done) {
265
+ break;
266
+ }
267
+ buffer += decoder.decode(value, { stream: true });
268
+ let boundary = buffer.indexOf("\n\n");
269
+ while (boundary !== -1) {
270
+ const block = buffer.slice(0, boundary);
271
+ buffer = buffer.slice(boundary + 2);
272
+ for (const line of block.split("\n")) {
273
+ const evt = parseSseDataLine(line);
274
+ if (evt) {
275
+ yield evt;
276
+ }
277
+ }
278
+ boundary = buffer.indexOf("\n\n");
279
+ }
280
+ }
281
+ if (buffer.trim().length > 0) {
282
+ for (const line of buffer.split("\n")) {
283
+ const evt = parseSseDataLine(line);
284
+ if (evt) {
285
+ yield evt;
286
+ }
287
+ }
288
+ }
289
+ } finally {
290
+ reader.releaseLock();
291
+ }
292
+ }
293
+
226
294
  // src/agents.ts
227
295
  var AgentsClient = class {
228
296
  constructor(client) {
@@ -266,72 +334,655 @@ var AgentsClient = class {
266
334
  if (!body) {
267
335
  return;
268
336
  }
269
- const reader = body.getReader();
270
- const decoder = new TextDecoder();
271
- let buffer = "";
272
- try {
273
- while (true) {
274
- const { done, value } = await reader.read();
275
- if (done) {
276
- break;
277
- }
278
- buffer += decoder.decode(value, { stream: true });
279
- let boundary = buffer.indexOf("\n\n");
280
- while (boundary !== -1) {
281
- const block = buffer.slice(0, boundary);
282
- buffer = buffer.slice(boundary + 2);
283
- for (const line of block.split("\n")) {
284
- const evt = parseSseDataLine(line);
285
- if (evt) {
286
- yield evt;
287
- }
288
- }
289
- boundary = buffer.indexOf("\n\n");
290
- }
337
+ yield* readSseStream(body);
338
+ }
339
+ };
340
+
341
+ // src/browser-postgrest.ts
342
+ function assertIdent(name, ctx) {
343
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {
344
+ throw new RagableError(
345
+ `Invalid ${ctx} identifier "${name}" (use letters, numbers, underscore)`,
346
+ 400,
347
+ null
348
+ );
349
+ }
350
+ }
351
+ function quoteIdent(name) {
352
+ assertIdent(name, "column");
353
+ return `"${name}"`;
354
+ }
355
+ var OP_SQL = {
356
+ eq: "=",
357
+ neq: "<>",
358
+ gt: ">",
359
+ gte: ">=",
360
+ lt: "<",
361
+ lte: "<=",
362
+ like: "LIKE",
363
+ ilike: "ILIKE"
364
+ };
365
+ async function asPostgrestResponse(fn) {
366
+ try {
367
+ const data = await fn();
368
+ return { data, error: null };
369
+ } catch (e) {
370
+ const err = e instanceof RagableError ? e : new RagableError(e.message, 500, null);
371
+ return { data: null, error: err };
372
+ }
373
+ }
374
+ function buildWhere(filters, params) {
375
+ if (filters.length === 0) return { clause: "", nextIdx: 1 };
376
+ const parts = [];
377
+ let i = params.length;
378
+ for (const f of filters) {
379
+ assertIdent(f.column, "filter");
380
+ i += 1;
381
+ parts.push(`${quoteIdent(f.column)} ${OP_SQL[f.op]} $${i}`);
382
+ params.push(f.value);
383
+ }
384
+ return { clause: ` WHERE ${parts.join(" AND ")}`, nextIdx: i };
385
+ }
386
+ var PostgrestSelectBuilder = class {
387
+ constructor(run, databaseInstanceId, table, columns) {
388
+ this.run = run;
389
+ this.databaseInstanceId = databaseInstanceId;
390
+ this.table = table;
391
+ this.columns = columns;
392
+ __publicField(this, "filters", []);
393
+ __publicField(this, "_limit");
394
+ __publicField(this, "_order");
395
+ assertIdent(table, "table");
396
+ }
397
+ eq(column, value) {
398
+ this.filters.push({ op: "eq", column, value });
399
+ return this;
400
+ }
401
+ neq(column, value) {
402
+ this.filters.push({ op: "neq", column, value });
403
+ return this;
404
+ }
405
+ gt(column, value) {
406
+ this.filters.push({ op: "gt", column, value });
407
+ return this;
408
+ }
409
+ gte(column, value) {
410
+ this.filters.push({ op: "gte", column, value });
411
+ return this;
412
+ }
413
+ lt(column, value) {
414
+ this.filters.push({ op: "lt", column, value });
415
+ return this;
416
+ }
417
+ lte(column, value) {
418
+ this.filters.push({ op: "lte", column, value });
419
+ return this;
420
+ }
421
+ like(column, value) {
422
+ this.filters.push({ op: "like", column, value });
423
+ return this;
424
+ }
425
+ ilike(column, value) {
426
+ this.filters.push({ op: "ilike", column, value });
427
+ return this;
428
+ }
429
+ limit(n) {
430
+ this._limit = n;
431
+ return this;
432
+ }
433
+ order(column, options) {
434
+ this._order = { column, ascending: options?.ascending !== false };
435
+ return this;
436
+ }
437
+ /** @param includeUserLimit when false, omit `.limit()` (for `.single()` / `.maybeSingle()`). */
438
+ buildSelectCore(params, includeUserLimit) {
439
+ const tbl = quoteIdent(this.table);
440
+ const { clause } = buildWhere(this.filters, params);
441
+ let sql = `SELECT ${this.columns} FROM ${tbl}${clause}`;
442
+ if (this._order) {
443
+ sql += ` ORDER BY ${quoteIdent(this._order.column)} ${this._order.ascending ? "ASC" : "DESC"}`;
444
+ }
445
+ if (includeUserLimit && this._limit != null) {
446
+ sql += ` LIMIT ${Math.max(0, Math.floor(this._limit))}`;
447
+ }
448
+ return sql;
449
+ }
450
+ then(onfulfilled, onrejected) {
451
+ return this.executeMany().then(onfulfilled, onrejected);
452
+ }
453
+ async executeMany() {
454
+ return asPostgrestResponse(async () => {
455
+ const params = [];
456
+ const sql = this.buildSelectCore(params, true);
457
+ const res = await this.run({
458
+ databaseInstanceId: this.databaseInstanceId,
459
+ sql,
460
+ params,
461
+ readOnly: true
462
+ });
463
+ return res.rows;
464
+ });
465
+ }
466
+ async single() {
467
+ return asPostgrestResponse(async () => {
468
+ const params = [];
469
+ const base = this.buildSelectCore(params, false);
470
+ const sql = `${base} LIMIT 2`;
471
+ const res = await this.run({
472
+ databaseInstanceId: this.databaseInstanceId,
473
+ sql,
474
+ params,
475
+ readOnly: true
476
+ });
477
+ if (res.rows.length === 0) {
478
+ throw new RagableError("JSON object requested, multiple (or no) rows returned", 406, {
479
+ code: "PGRST116"
480
+ });
291
481
  }
292
- if (buffer.trim().length > 0) {
293
- for (const line of buffer.split("\n")) {
294
- const evt = parseSseDataLine(line);
295
- if (evt) {
296
- yield evt;
297
- }
482
+ if (res.rows.length > 1) {
483
+ throw new RagableError("JSON object requested, multiple (or no) rows returned", 406, {
484
+ code: "PGRST116"
485
+ });
486
+ }
487
+ return res.rows[0];
488
+ });
489
+ }
490
+ async maybeSingle() {
491
+ return asPostgrestResponse(async () => {
492
+ const params = [];
493
+ const base = this.buildSelectCore(params, false);
494
+ const sql = `${base} LIMIT 2`;
495
+ const res = await this.run({
496
+ databaseInstanceId: this.databaseInstanceId,
497
+ sql,
498
+ params,
499
+ readOnly: true
500
+ });
501
+ if (res.rows.length > 1) {
502
+ throw new RagableError("JSON object requested, multiple (or no) rows returned", 406, {
503
+ code: "PGRST116"
504
+ });
505
+ }
506
+ return res.rows[0] ?? null;
507
+ });
508
+ }
509
+ };
510
+ var PostgrestInsertBuilder = class {
511
+ constructor(run, databaseInstanceId, table, rows) {
512
+ this.run = run;
513
+ this.databaseInstanceId = databaseInstanceId;
514
+ this.table = table;
515
+ this.rows = rows;
516
+ __publicField(this, "returning", "*");
517
+ assertIdent(table, "table");
518
+ }
519
+ select(columns = "*") {
520
+ this.returning = columns;
521
+ return this;
522
+ }
523
+ then(onfulfilled, onrejected) {
524
+ return this.execute().then(onfulfilled, onrejected);
525
+ }
526
+ async execute() {
527
+ return asPostgrestResponse(async () => {
528
+ if (this.rows.length === 0) return [];
529
+ const keys = Object.keys(this.rows[0]);
530
+ for (const k of keys) assertIdent(k, "column");
531
+ const tbl = quoteIdent(this.table);
532
+ const params = [];
533
+ const valueGroups = [];
534
+ for (const row of this.rows) {
535
+ const placeholders = [];
536
+ for (const k of keys) {
537
+ params.push(row[k]);
538
+ placeholders.push(`$${params.length}`);
298
539
  }
540
+ valueGroups.push(`(${placeholders.join(", ")})`);
299
541
  }
300
- } finally {
301
- reader.releaseLock();
302
- }
542
+ const cols = keys.map(quoteIdent).join(", ");
543
+ const sql = `INSERT INTO ${tbl} (${cols}) VALUES ${valueGroups.join(", ")} RETURNING ${this.returning}`;
544
+ const res = await this.run({
545
+ databaseInstanceId: this.databaseInstanceId,
546
+ sql,
547
+ params,
548
+ readOnly: false
549
+ });
550
+ return res.rows;
551
+ });
303
552
  }
304
553
  };
305
- async function parseMaybeJsonBody(response) {
306
- const contentType = response.headers.get("content-type") ?? "";
307
- if (contentType.includes("application/json")) {
308
- try {
309
- return await response.json();
310
- } catch {
311
- return null;
312
- }
554
+ var PostgrestUpdateBuilder = class {
555
+ constructor(run, databaseInstanceId, table, patch) {
556
+ this.run = run;
557
+ this.databaseInstanceId = databaseInstanceId;
558
+ this.table = table;
559
+ this.patch = patch;
560
+ __publicField(this, "filters", []);
561
+ __publicField(this, "returning", "*");
562
+ assertIdent(table, "table");
313
563
  }
314
- try {
315
- return await response.text();
316
- } catch {
317
- return null;
564
+ eq(column, value) {
565
+ this.filters.push({ op: "eq", column, value });
566
+ return this;
567
+ }
568
+ select(columns = "*") {
569
+ this.returning = columns;
570
+ return this;
571
+ }
572
+ then(onfulfilled, onrejected) {
573
+ return this.execute().then(onfulfilled, onrejected);
574
+ }
575
+ async execute() {
576
+ return asPostgrestResponse(async () => {
577
+ const keys = Object.keys(this.patch);
578
+ if (keys.length === 0) {
579
+ throw new RagableError("Empty update payload", 400, null);
580
+ }
581
+ for (const k of keys) assertIdent(k, "column");
582
+ if (this.filters.length === 0) {
583
+ throw new RagableError(
584
+ "UPDATE requires a filter (e.g. .eq('id', value)) \u2014 refusing unscoped update",
585
+ 400,
586
+ null
587
+ );
588
+ }
589
+ const params = [];
590
+ const sets = [];
591
+ for (const k of keys) {
592
+ params.push(this.patch[k]);
593
+ sets.push(`${quoteIdent(k)} = $${params.length}`);
594
+ }
595
+ const { clause } = buildWhere(this.filters, params);
596
+ const tbl = quoteIdent(this.table);
597
+ const sql = `UPDATE ${tbl} SET ${sets.join(", ")}${clause} RETURNING ${this.returning}`;
598
+ const res = await this.run({
599
+ databaseInstanceId: this.databaseInstanceId,
600
+ sql,
601
+ params,
602
+ readOnly: false
603
+ });
604
+ return res.rows;
605
+ });
606
+ }
607
+ };
608
+ var PostgrestDeleteBuilder = class {
609
+ constructor(run, databaseInstanceId, table) {
610
+ this.run = run;
611
+ this.databaseInstanceId = databaseInstanceId;
612
+ this.table = table;
613
+ __publicField(this, "filters", []);
614
+ __publicField(this, "returning", "*");
615
+ assertIdent(table, "table");
616
+ }
617
+ eq(column, value) {
618
+ this.filters.push({ op: "eq", column, value });
619
+ return this;
620
+ }
621
+ select(columns = "*") {
622
+ this.returning = columns;
623
+ return this;
624
+ }
625
+ then(onfulfilled, onrejected) {
626
+ return this.execute().then(onfulfilled, onrejected);
627
+ }
628
+ async execute() {
629
+ return asPostgrestResponse(async () => {
630
+ if (this.filters.length === 0) {
631
+ throw new RagableError(
632
+ "DELETE requires a filter (e.g. .eq('id', value)) \u2014 refusing unscoped delete",
633
+ 400,
634
+ null
635
+ );
636
+ }
637
+ const params = [];
638
+ const { clause } = buildWhere(this.filters, params);
639
+ const tbl = quoteIdent(this.table);
640
+ const sql = `DELETE FROM ${tbl}${clause} RETURNING ${this.returning}`;
641
+ const res = await this.run({
642
+ databaseInstanceId: this.databaseInstanceId,
643
+ sql,
644
+ params,
645
+ readOnly: false
646
+ });
647
+ return res.rows;
648
+ });
649
+ }
650
+ };
651
+ var PostgrestTableApi = class {
652
+ constructor(run, databaseInstanceId, table) {
653
+ this.run = run;
654
+ this.databaseInstanceId = databaseInstanceId;
655
+ this.table = table;
656
+ }
657
+ select(columns = "*") {
658
+ return new PostgrestSelectBuilder(
659
+ this.run,
660
+ this.databaseInstanceId,
661
+ this.table,
662
+ columns
663
+ );
664
+ }
665
+ insert(values) {
666
+ const rows = Array.isArray(values) ? values : [values];
667
+ return new PostgrestInsertBuilder(
668
+ this.run,
669
+ this.databaseInstanceId,
670
+ this.table,
671
+ rows
672
+ );
673
+ }
674
+ update(patch) {
675
+ return new PostgrestUpdateBuilder(
676
+ this.run,
677
+ this.databaseInstanceId,
678
+ this.table,
679
+ patch
680
+ );
681
+ }
682
+ delete() {
683
+ return new PostgrestDeleteBuilder(
684
+ this.run,
685
+ this.databaseInstanceId,
686
+ this.table
687
+ );
318
688
  }
689
+ };
690
+
691
+ // src/browser.ts
692
+ function normalizeBrowserApiBase(baseUrl) {
693
+ return (baseUrl ?? "http://localhost:8080/api").replace(/\/+$/, "");
319
694
  }
320
- function parseSseDataLine(line) {
321
- const dataPrefix = "data: ";
322
- if (!line.startsWith(dataPrefix)) {
323
- return null;
695
+ function requireAuthGroupId(options) {
696
+ const id = options.authGroupId?.trim();
697
+ if (!id) {
698
+ throw new Error(
699
+ "authGroupId is required for auth and database methods on the browser client"
700
+ );
324
701
  }
325
- const json = line.slice(dataPrefix.length).trim();
326
- if (json.length === 0 || json === "[DONE]") {
327
- return null;
702
+ return id;
703
+ }
704
+ async function requireAccessToken(options) {
705
+ const getter = options.getAccessToken;
706
+ if (!getter) {
707
+ throw new Error(
708
+ "getAccessToken is required for this call (return the end-user access JWT)"
709
+ );
328
710
  }
329
- try {
330
- return JSON.parse(json);
331
- } catch {
332
- return null;
711
+ const token = await getter();
712
+ if (!token?.trim()) {
713
+ throw new Error("getAccessToken returned no token");
714
+ }
715
+ return token.trim();
716
+ }
717
+ async function parseJsonOrThrow(response) {
718
+ const payload = await parseMaybeJsonBody(response);
719
+ if (!response.ok) {
720
+ const message = extractErrorMessage(payload, response.statusText);
721
+ throw new RagableError(message, response.status, payload);
722
+ }
723
+ return payload;
724
+ }
725
+ function parseExpiresInSeconds(expiresIn) {
726
+ const s = expiresIn.trim().toLowerCase();
727
+ const m = /^(\d+)([smhd])?$/.exec(s);
728
+ if (m) {
729
+ const n = Number(m[1]);
730
+ const u = m[2] ?? "s";
731
+ const mult = u === "s" ? 1 : u === "m" ? 60 : u === "h" ? 3600 : u === "d" ? 86400 : 1;
732
+ return n * mult;
733
+ }
734
+ const asNum = Number(s);
735
+ return Number.isFinite(asNum) ? asNum : 0;
736
+ }
737
+ function toSupabaseSession(s) {
738
+ return {
739
+ access_token: s.accessToken,
740
+ refresh_token: s.refreshToken,
741
+ expires_in: parseExpiresInSeconds(s.expiresIn),
742
+ token_type: "bearer",
743
+ user: s.user
744
+ };
745
+ }
746
+ var RagableBrowserAuthClient = class {
747
+ constructor(options) {
748
+ this.options = options;
749
+ }
750
+ get fetchImpl() {
751
+ return this.options.fetch ?? fetch;
752
+ }
753
+ toUrl(path) {
754
+ return `${normalizeBrowserApiBase(this.options.baseUrl)}${path.startsWith("/") ? path : `/${path}`}`;
755
+ }
756
+ baseHeaders(json) {
757
+ const h = new Headers(this.options.headers);
758
+ if (json) {
759
+ h.set("Content-Type", "application/json");
760
+ }
761
+ return h;
762
+ }
763
+ authPrefix() {
764
+ const gid = requireAuthGroupId(this.options);
765
+ return `/auth-groups/${gid}/auth`;
766
+ }
767
+ /** Supabase: `signUp` → `{ data: { user, session }, error }` */
768
+ async signUp(credentials) {
769
+ return asPostgrestResponse(async () => {
770
+ const name = typeof credentials.options?.data?.name === "string" ? credentials.options.data.name : void 0;
771
+ const session = await this.register({
772
+ email: credentials.email,
773
+ password: credentials.password,
774
+ name
775
+ });
776
+ return { user: session.user, session: toSupabaseSession(session) };
777
+ });
778
+ }
779
+ /** Supabase: `signInWithPassword` */
780
+ async signInWithPassword(credentials) {
781
+ return asPostgrestResponse(async () => {
782
+ const session = await this.login(credentials);
783
+ return { user: session.user, session: toSupabaseSession(session) };
784
+ });
785
+ }
786
+ /** Supabase: `refreshSession` */
787
+ async refreshSession(refreshToken) {
788
+ return asPostgrestResponse(async () => {
789
+ const tokens = await this.refresh({ refreshToken });
790
+ const me = await this.getUserFromToken(tokens.accessToken);
791
+ const session = {
792
+ access_token: tokens.accessToken,
793
+ refresh_token: tokens.refreshToken,
794
+ expires_in: parseExpiresInSeconds(tokens.expiresIn),
795
+ token_type: "bearer",
796
+ user: me.user
797
+ };
798
+ return { session, user: me.user };
799
+ });
800
+ }
801
+ /** Supabase: `getUser()` — needs `getAccessToken` on the client */
802
+ async getUser() {
803
+ return asPostgrestResponse(() => this.getMe());
804
+ }
805
+ /** Supabase: `updateUser` */
806
+ async updateUser(attributes) {
807
+ return asPostgrestResponse(
808
+ () => this.updateMe({
809
+ password: attributes.password,
810
+ name: attributes.data?.name
811
+ })
812
+ );
813
+ }
814
+ /**
815
+ * Supabase/Firebase: no server call — clear tokens in your app.
816
+ * Returns `{ error: null }` for API compatibility.
817
+ */
818
+ async signOut(_options) {
819
+ return { error: null };
820
+ }
821
+ async getUserFromToken(accessToken) {
822
+ const headers = this.baseHeaders(false);
823
+ headers.set("Authorization", `Bearer ${accessToken}`);
824
+ const response = await this.fetchImpl(`${this.toUrl(this.authPrefix())}/me`, {
825
+ method: "GET",
826
+ headers
827
+ });
828
+ return parseJsonOrThrow(response);
829
+ }
830
+ async register(body) {
831
+ const response = await this.fetchImpl(`${this.toUrl(this.authPrefix())}/register`, {
832
+ method: "POST",
833
+ headers: this.baseHeaders(true),
834
+ body: JSON.stringify(body)
835
+ });
836
+ return parseJsonOrThrow(response);
333
837
  }
838
+ async login(body) {
839
+ const response = await this.fetchImpl(`${this.toUrl(this.authPrefix())}/login`, {
840
+ method: "POST",
841
+ headers: this.baseHeaders(true),
842
+ body: JSON.stringify(body)
843
+ });
844
+ return parseJsonOrThrow(response);
845
+ }
846
+ async refresh(body) {
847
+ const response = await this.fetchImpl(`${this.toUrl(this.authPrefix())}/refresh`, {
848
+ method: "POST",
849
+ headers: this.baseHeaders(true),
850
+ body: JSON.stringify(body)
851
+ });
852
+ return parseJsonOrThrow(response);
853
+ }
854
+ async getMe() {
855
+ const token = await requireAccessToken(this.options);
856
+ const headers = this.baseHeaders(false);
857
+ headers.set("Authorization", `Bearer ${token}`);
858
+ const response = await this.fetchImpl(`${this.toUrl(this.authPrefix())}/me`, {
859
+ method: "GET",
860
+ headers
861
+ });
862
+ return parseJsonOrThrow(response);
863
+ }
864
+ async updateMe(body) {
865
+ const token = await requireAccessToken(this.options);
866
+ const headers = this.baseHeaders(true);
867
+ headers.set("Authorization", `Bearer ${token}`);
868
+ const response = await this.fetchImpl(`${this.toUrl(this.authPrefix())}/me`, {
869
+ method: "PATCH",
870
+ headers,
871
+ body: JSON.stringify(body)
872
+ });
873
+ return parseJsonOrThrow(response);
874
+ }
875
+ };
876
+ var RagableBrowserDatabaseClient = class {
877
+ constructor(options) {
878
+ this.options = options;
879
+ }
880
+ get fetchImpl() {
881
+ return this.options.fetch ?? fetch;
882
+ }
883
+ toUrl(path) {
884
+ return `${normalizeBrowserApiBase(this.options.baseUrl)}${path.startsWith("/") ? path : `/${path}`}`;
885
+ }
886
+ async query(params) {
887
+ const gid = requireAuthGroupId(this.options);
888
+ const token = await requireAccessToken(this.options);
889
+ const headers = this.baseHeaders();
890
+ headers.set("Authorization", `Bearer ${token}`);
891
+ headers.set("Content-Type", "application/json");
892
+ const response = await this.fetchImpl(
893
+ this.toUrl(`/auth-groups/${gid}/data/query`),
894
+ {
895
+ method: "POST",
896
+ headers,
897
+ body: JSON.stringify({
898
+ databaseInstanceId: params.databaseInstanceId,
899
+ sql: params.sql,
900
+ ...params.params !== void 0 ? { params: params.params } : {},
901
+ ...params.readOnly === false ? { readOnly: false } : {},
902
+ ...params.timeoutMs !== void 0 ? { timeoutMs: params.timeoutMs } : {},
903
+ ...params.rowLimit !== void 0 ? { rowLimit: params.rowLimit } : {}
904
+ })
905
+ }
906
+ );
907
+ return parseJsonOrThrow(response);
908
+ }
909
+ baseHeaders() {
910
+ return new Headers(this.options.headers);
911
+ }
912
+ };
913
+ var RagableBrowserAgentsClient = class {
914
+ constructor(options) {
915
+ this.options = options;
916
+ }
917
+ get fetchImpl() {
918
+ return this.options.fetch ?? fetch;
919
+ }
920
+ toUrl(path) {
921
+ return `${normalizeBrowserApiBase(this.options.baseUrl)}${path.startsWith("/") ? path : `/${path}`}`;
922
+ }
923
+ /**
924
+ * Stream agent execution as SSE (`POST /public/organizations/:orgId/agents/:agentId/chat/stream`).
925
+ */
926
+ async *chatStream(agentId, params) {
927
+ const orgId = this.options.organizationId;
928
+ const body = {
929
+ message: params.message,
930
+ ...params.history !== void 0 ? { history: params.history } : {},
931
+ ...params.triggerSubtype !== void 0 ? { triggerSubtype: params.triggerSubtype } : {},
932
+ ...params.triggerNodeId !== void 0 ? { triggerNodeId: params.triggerNodeId } : {}
933
+ };
934
+ const headers = new Headers(this.options.headers);
935
+ headers.set("Content-Type", "application/json");
936
+ const response = await this.fetchImpl(
937
+ this.toUrl(`/public/organizations/${orgId}/agents/${agentId}/chat/stream`),
938
+ {
939
+ method: "POST",
940
+ headers,
941
+ body: JSON.stringify(body)
942
+ }
943
+ );
944
+ if (!response.ok) {
945
+ const payload = await parseMaybeJsonBody(response);
946
+ const message = extractErrorMessage(payload, response.statusText);
947
+ throw new RagableError(message, response.status, payload);
948
+ }
949
+ const streamBody = response.body;
950
+ if (!streamBody) {
951
+ return;
952
+ }
953
+ yield* readSseStream(streamBody);
954
+ }
955
+ };
956
+ var RagableBrowser = class {
957
+ constructor(options) {
958
+ __publicField(this, "agents");
959
+ __publicField(this, "auth");
960
+ __publicField(this, "database");
961
+ __publicField(this, "options");
962
+ this.options = options;
963
+ this.agents = new RagableBrowserAgentsClient(options);
964
+ this.auth = new RagableBrowserAuthClient(options);
965
+ this.database = new RagableBrowserDatabaseClient(options);
966
+ }
967
+ /**
968
+ * Supabase-style table API: `.from('items').select().eq('id', 1).single()`.
969
+ * Pass `databaseInstanceId` here or set `databaseInstanceId` on the client options.
970
+ */
971
+ from(table, databaseInstanceId) {
972
+ const id = databaseInstanceId?.trim() || this.options.databaseInstanceId?.trim();
973
+ if (!id) {
974
+ throw new Error(
975
+ "RagableBrowser.from() requires databaseInstanceId in client options or as the second argument"
976
+ );
977
+ }
978
+ const run = (p) => this.database.query(p);
979
+ return new PostgrestTableApi(run, id, table);
980
+ }
981
+ };
982
+ function createBrowserClient(options) {
983
+ return new RagableBrowser(options);
334
984
  }
985
+ var createRagableBrowserClient = createBrowserClient;
335
986
 
336
987
  // src/rag.ts
337
988
  function formatRetrievalContext(results, options = {}) {
@@ -389,18 +1040,63 @@ var Ragable = class {
389
1040
  };
390
1041
  }
391
1042
  };
392
- function createClient(options) {
1043
+ function isServerClientOptions(o) {
1044
+ return typeof o === "object" && o !== null && "apiKey" in o && typeof o.apiKey === "string" && o.apiKey.length > 0;
1045
+ }
1046
+ function createClient(urlOrOptions, browserOptions) {
1047
+ if (typeof urlOrOptions === "string") {
1048
+ if (!browserOptions) {
1049
+ throw new Error(
1050
+ "createClient(url, options) requires options with at least organizationId"
1051
+ );
1052
+ }
1053
+ const raw = urlOrOptions.trim().replace(/\/+$/, "");
1054
+ const baseUrl = raw.endsWith("/api") ? raw : `${raw}/api`;
1055
+ return createBrowserClient({
1056
+ ...browserOptions,
1057
+ baseUrl: normalizeBrowserApiBase(baseUrl)
1058
+ });
1059
+ }
1060
+ if (isServerClientOptions(urlOrOptions)) {
1061
+ return new Ragable(urlOrOptions);
1062
+ }
1063
+ if (typeof urlOrOptions === "object" && urlOrOptions !== null && "organizationId" in urlOrOptions && typeof urlOrOptions.organizationId === "string") {
1064
+ return createBrowserClient(
1065
+ urlOrOptions
1066
+ );
1067
+ }
1068
+ throw new Error(
1069
+ "createClient(options) requires apiKey (server) or organizationId (browser)"
1070
+ );
1071
+ }
1072
+ function createRagableServerClient(options) {
393
1073
  return new Ragable(options);
394
1074
  }
395
1075
  export {
396
1076
  AgentsClient,
1077
+ PostgrestDeleteBuilder,
1078
+ PostgrestInsertBuilder,
1079
+ PostgrestSelectBuilder,
1080
+ PostgrestTableApi,
1081
+ PostgrestUpdateBuilder,
397
1082
  Ragable,
1083
+ RagableBrowser,
1084
+ RagableBrowserAgentsClient,
1085
+ RagableBrowserAuthClient,
1086
+ RagableBrowserDatabaseClient,
398
1087
  RagableError,
399
1088
  RagableRequestClient,
400
1089
  ShiftClient,
1090
+ asPostgrestResponse,
1091
+ createBrowserClient,
401
1092
  createClient,
402
1093
  createRagPipeline,
1094
+ createRagableBrowserClient,
1095
+ createRagableServerClient,
403
1096
  extractErrorMessage,
404
- formatRetrievalContext
1097
+ formatRetrievalContext,
1098
+ normalizeBrowserApiBase,
1099
+ parseSseDataLine,
1100
+ readSseStream
405
1101
  };
406
1102
  //# sourceMappingURL=index.mjs.map