@ragable/sdk 0.3.0 → 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.js CHANGED
@@ -23,6 +23,11 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
23
23
  var index_exports = {};
24
24
  __export(index_exports, {
25
25
  AgentsClient: () => AgentsClient,
26
+ PostgrestDeleteBuilder: () => PostgrestDeleteBuilder,
27
+ PostgrestInsertBuilder: () => PostgrestInsertBuilder,
28
+ PostgrestSelectBuilder: () => PostgrestSelectBuilder,
29
+ PostgrestTableApi: () => PostgrestTableApi,
30
+ PostgrestUpdateBuilder: () => PostgrestUpdateBuilder,
26
31
  Ragable: () => Ragable,
27
32
  RagableBrowser: () => RagableBrowser,
28
33
  RagableBrowserAgentsClient: () => RagableBrowserAgentsClient,
@@ -31,9 +36,12 @@ __export(index_exports, {
31
36
  RagableError: () => RagableError,
32
37
  RagableRequestClient: () => RagableRequestClient,
33
38
  ShiftClient: () => ShiftClient,
39
+ asPostgrestResponse: () => asPostgrestResponse,
34
40
  createBrowserClient: () => createBrowserClient,
35
41
  createClient: () => createClient,
36
42
  createRagPipeline: () => createRagPipeline,
43
+ createRagableBrowserClient: () => createRagableBrowserClient,
44
+ createRagableServerClient: () => createRagableServerClient,
37
45
  extractErrorMessage: () => extractErrorMessage,
38
46
  formatRetrievalContext: () => formatRetrievalContext,
39
47
  normalizeBrowserApiBase: () => normalizeBrowserApiBase,
@@ -378,6 +386,356 @@ var AgentsClient = class {
378
386
  }
379
387
  };
380
388
 
389
+ // src/browser-postgrest.ts
390
+ function assertIdent(name, ctx) {
391
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {
392
+ throw new RagableError(
393
+ `Invalid ${ctx} identifier "${name}" (use letters, numbers, underscore)`,
394
+ 400,
395
+ null
396
+ );
397
+ }
398
+ }
399
+ function quoteIdent(name) {
400
+ assertIdent(name, "column");
401
+ return `"${name}"`;
402
+ }
403
+ var OP_SQL = {
404
+ eq: "=",
405
+ neq: "<>",
406
+ gt: ">",
407
+ gte: ">=",
408
+ lt: "<",
409
+ lte: "<=",
410
+ like: "LIKE",
411
+ ilike: "ILIKE"
412
+ };
413
+ async function asPostgrestResponse(fn) {
414
+ try {
415
+ const data = await fn();
416
+ return { data, error: null };
417
+ } catch (e) {
418
+ const err = e instanceof RagableError ? e : new RagableError(e.message, 500, null);
419
+ return { data: null, error: err };
420
+ }
421
+ }
422
+ function buildWhere(filters, params) {
423
+ if (filters.length === 0) return { clause: "", nextIdx: 1 };
424
+ const parts = [];
425
+ let i = params.length;
426
+ for (const f of filters) {
427
+ assertIdent(f.column, "filter");
428
+ i += 1;
429
+ parts.push(`${quoteIdent(f.column)} ${OP_SQL[f.op]} $${i}`);
430
+ params.push(f.value);
431
+ }
432
+ return { clause: ` WHERE ${parts.join(" AND ")}`, nextIdx: i };
433
+ }
434
+ var PostgrestSelectBuilder = class {
435
+ constructor(run, databaseInstanceId, table, columns) {
436
+ this.run = run;
437
+ this.databaseInstanceId = databaseInstanceId;
438
+ this.table = table;
439
+ this.columns = columns;
440
+ __publicField(this, "filters", []);
441
+ __publicField(this, "_limit");
442
+ __publicField(this, "_order");
443
+ assertIdent(table, "table");
444
+ }
445
+ eq(column, value) {
446
+ this.filters.push({ op: "eq", column, value });
447
+ return this;
448
+ }
449
+ neq(column, value) {
450
+ this.filters.push({ op: "neq", column, value });
451
+ return this;
452
+ }
453
+ gt(column, value) {
454
+ this.filters.push({ op: "gt", column, value });
455
+ return this;
456
+ }
457
+ gte(column, value) {
458
+ this.filters.push({ op: "gte", column, value });
459
+ return this;
460
+ }
461
+ lt(column, value) {
462
+ this.filters.push({ op: "lt", column, value });
463
+ return this;
464
+ }
465
+ lte(column, value) {
466
+ this.filters.push({ op: "lte", column, value });
467
+ return this;
468
+ }
469
+ like(column, value) {
470
+ this.filters.push({ op: "like", column, value });
471
+ return this;
472
+ }
473
+ ilike(column, value) {
474
+ this.filters.push({ op: "ilike", column, value });
475
+ return this;
476
+ }
477
+ limit(n) {
478
+ this._limit = n;
479
+ return this;
480
+ }
481
+ order(column, options) {
482
+ this._order = { column, ascending: options?.ascending !== false };
483
+ return this;
484
+ }
485
+ /** @param includeUserLimit when false, omit `.limit()` (for `.single()` / `.maybeSingle()`). */
486
+ buildSelectCore(params, includeUserLimit) {
487
+ const tbl = quoteIdent(this.table);
488
+ const { clause } = buildWhere(this.filters, params);
489
+ let sql = `SELECT ${this.columns} FROM ${tbl}${clause}`;
490
+ if (this._order) {
491
+ sql += ` ORDER BY ${quoteIdent(this._order.column)} ${this._order.ascending ? "ASC" : "DESC"}`;
492
+ }
493
+ if (includeUserLimit && this._limit != null) {
494
+ sql += ` LIMIT ${Math.max(0, Math.floor(this._limit))}`;
495
+ }
496
+ return sql;
497
+ }
498
+ then(onfulfilled, onrejected) {
499
+ return this.executeMany().then(onfulfilled, onrejected);
500
+ }
501
+ async executeMany() {
502
+ return asPostgrestResponse(async () => {
503
+ const params = [];
504
+ const sql = this.buildSelectCore(params, true);
505
+ const res = await this.run({
506
+ databaseInstanceId: this.databaseInstanceId,
507
+ sql,
508
+ params,
509
+ readOnly: true
510
+ });
511
+ return res.rows;
512
+ });
513
+ }
514
+ async single() {
515
+ return asPostgrestResponse(async () => {
516
+ const params = [];
517
+ const base = this.buildSelectCore(params, false);
518
+ const sql = `${base} LIMIT 2`;
519
+ const res = await this.run({
520
+ databaseInstanceId: this.databaseInstanceId,
521
+ sql,
522
+ params,
523
+ readOnly: true
524
+ });
525
+ if (res.rows.length === 0) {
526
+ throw new RagableError("JSON object requested, multiple (or no) rows returned", 406, {
527
+ code: "PGRST116"
528
+ });
529
+ }
530
+ if (res.rows.length > 1) {
531
+ throw new RagableError("JSON object requested, multiple (or no) rows returned", 406, {
532
+ code: "PGRST116"
533
+ });
534
+ }
535
+ return res.rows[0];
536
+ });
537
+ }
538
+ async maybeSingle() {
539
+ return asPostgrestResponse(async () => {
540
+ const params = [];
541
+ const base = this.buildSelectCore(params, false);
542
+ const sql = `${base} LIMIT 2`;
543
+ const res = await this.run({
544
+ databaseInstanceId: this.databaseInstanceId,
545
+ sql,
546
+ params,
547
+ readOnly: true
548
+ });
549
+ if (res.rows.length > 1) {
550
+ throw new RagableError("JSON object requested, multiple (or no) rows returned", 406, {
551
+ code: "PGRST116"
552
+ });
553
+ }
554
+ return res.rows[0] ?? null;
555
+ });
556
+ }
557
+ };
558
+ var PostgrestInsertBuilder = class {
559
+ constructor(run, databaseInstanceId, table, rows) {
560
+ this.run = run;
561
+ this.databaseInstanceId = databaseInstanceId;
562
+ this.table = table;
563
+ this.rows = rows;
564
+ __publicField(this, "returning", "*");
565
+ assertIdent(table, "table");
566
+ }
567
+ select(columns = "*") {
568
+ this.returning = columns;
569
+ return this;
570
+ }
571
+ then(onfulfilled, onrejected) {
572
+ return this.execute().then(onfulfilled, onrejected);
573
+ }
574
+ async execute() {
575
+ return asPostgrestResponse(async () => {
576
+ if (this.rows.length === 0) return [];
577
+ const keys = Object.keys(this.rows[0]);
578
+ for (const k of keys) assertIdent(k, "column");
579
+ const tbl = quoteIdent(this.table);
580
+ const params = [];
581
+ const valueGroups = [];
582
+ for (const row of this.rows) {
583
+ const placeholders = [];
584
+ for (const k of keys) {
585
+ params.push(row[k]);
586
+ placeholders.push(`$${params.length}`);
587
+ }
588
+ valueGroups.push(`(${placeholders.join(", ")})`);
589
+ }
590
+ const cols = keys.map(quoteIdent).join(", ");
591
+ const sql = `INSERT INTO ${tbl} (${cols}) VALUES ${valueGroups.join(", ")} RETURNING ${this.returning}`;
592
+ const res = await this.run({
593
+ databaseInstanceId: this.databaseInstanceId,
594
+ sql,
595
+ params,
596
+ readOnly: false
597
+ });
598
+ return res.rows;
599
+ });
600
+ }
601
+ };
602
+ var PostgrestUpdateBuilder = class {
603
+ constructor(run, databaseInstanceId, table, patch) {
604
+ this.run = run;
605
+ this.databaseInstanceId = databaseInstanceId;
606
+ this.table = table;
607
+ this.patch = patch;
608
+ __publicField(this, "filters", []);
609
+ __publicField(this, "returning", "*");
610
+ assertIdent(table, "table");
611
+ }
612
+ eq(column, value) {
613
+ this.filters.push({ op: "eq", column, value });
614
+ return this;
615
+ }
616
+ select(columns = "*") {
617
+ this.returning = columns;
618
+ return this;
619
+ }
620
+ then(onfulfilled, onrejected) {
621
+ return this.execute().then(onfulfilled, onrejected);
622
+ }
623
+ async execute() {
624
+ return asPostgrestResponse(async () => {
625
+ const keys = Object.keys(this.patch);
626
+ if (keys.length === 0) {
627
+ throw new RagableError("Empty update payload", 400, null);
628
+ }
629
+ for (const k of keys) assertIdent(k, "column");
630
+ if (this.filters.length === 0) {
631
+ throw new RagableError(
632
+ "UPDATE requires a filter (e.g. .eq('id', value)) \u2014 refusing unscoped update",
633
+ 400,
634
+ null
635
+ );
636
+ }
637
+ const params = [];
638
+ const sets = [];
639
+ for (const k of keys) {
640
+ params.push(this.patch[k]);
641
+ sets.push(`${quoteIdent(k)} = $${params.length}`);
642
+ }
643
+ const { clause } = buildWhere(this.filters, params);
644
+ const tbl = quoteIdent(this.table);
645
+ const sql = `UPDATE ${tbl} SET ${sets.join(", ")}${clause} RETURNING ${this.returning}`;
646
+ const res = await this.run({
647
+ databaseInstanceId: this.databaseInstanceId,
648
+ sql,
649
+ params,
650
+ readOnly: false
651
+ });
652
+ return res.rows;
653
+ });
654
+ }
655
+ };
656
+ var PostgrestDeleteBuilder = class {
657
+ constructor(run, databaseInstanceId, table) {
658
+ this.run = run;
659
+ this.databaseInstanceId = databaseInstanceId;
660
+ this.table = table;
661
+ __publicField(this, "filters", []);
662
+ __publicField(this, "returning", "*");
663
+ assertIdent(table, "table");
664
+ }
665
+ eq(column, value) {
666
+ this.filters.push({ op: "eq", column, value });
667
+ return this;
668
+ }
669
+ select(columns = "*") {
670
+ this.returning = columns;
671
+ return this;
672
+ }
673
+ then(onfulfilled, onrejected) {
674
+ return this.execute().then(onfulfilled, onrejected);
675
+ }
676
+ async execute() {
677
+ return asPostgrestResponse(async () => {
678
+ if (this.filters.length === 0) {
679
+ throw new RagableError(
680
+ "DELETE requires a filter (e.g. .eq('id', value)) \u2014 refusing unscoped delete",
681
+ 400,
682
+ null
683
+ );
684
+ }
685
+ const params = [];
686
+ const { clause } = buildWhere(this.filters, params);
687
+ const tbl = quoteIdent(this.table);
688
+ const sql = `DELETE FROM ${tbl}${clause} RETURNING ${this.returning}`;
689
+ const res = await this.run({
690
+ databaseInstanceId: this.databaseInstanceId,
691
+ sql,
692
+ params,
693
+ readOnly: false
694
+ });
695
+ return res.rows;
696
+ });
697
+ }
698
+ };
699
+ var PostgrestTableApi = class {
700
+ constructor(run, databaseInstanceId, table) {
701
+ this.run = run;
702
+ this.databaseInstanceId = databaseInstanceId;
703
+ this.table = table;
704
+ }
705
+ select(columns = "*") {
706
+ return new PostgrestSelectBuilder(
707
+ this.run,
708
+ this.databaseInstanceId,
709
+ this.table,
710
+ columns
711
+ );
712
+ }
713
+ insert(values) {
714
+ const rows = Array.isArray(values) ? values : [values];
715
+ return new PostgrestInsertBuilder(
716
+ this.run,
717
+ this.databaseInstanceId,
718
+ this.table,
719
+ rows
720
+ );
721
+ }
722
+ update(patch) {
723
+ return new PostgrestUpdateBuilder(
724
+ this.run,
725
+ this.databaseInstanceId,
726
+ this.table,
727
+ patch
728
+ );
729
+ }
730
+ delete() {
731
+ return new PostgrestDeleteBuilder(
732
+ this.run,
733
+ this.databaseInstanceId,
734
+ this.table
735
+ );
736
+ }
737
+ };
738
+
381
739
  // src/browser.ts
382
740
  function normalizeBrowserApiBase(baseUrl) {
383
741
  return (baseUrl ?? "http://localhost:8080/api").replace(/\/+$/, "");
@@ -412,6 +770,27 @@ async function parseJsonOrThrow(response) {
412
770
  }
413
771
  return payload;
414
772
  }
773
+ function parseExpiresInSeconds(expiresIn) {
774
+ const s = expiresIn.trim().toLowerCase();
775
+ const m = /^(\d+)([smhd])?$/.exec(s);
776
+ if (m) {
777
+ const n = Number(m[1]);
778
+ const u = m[2] ?? "s";
779
+ const mult = u === "s" ? 1 : u === "m" ? 60 : u === "h" ? 3600 : u === "d" ? 86400 : 1;
780
+ return n * mult;
781
+ }
782
+ const asNum = Number(s);
783
+ return Number.isFinite(asNum) ? asNum : 0;
784
+ }
785
+ function toSupabaseSession(s) {
786
+ return {
787
+ access_token: s.accessToken,
788
+ refresh_token: s.refreshToken,
789
+ expires_in: parseExpiresInSeconds(s.expiresIn),
790
+ token_type: "bearer",
791
+ user: s.user
792
+ };
793
+ }
415
794
  var RagableBrowserAuthClient = class {
416
795
  constructor(options) {
417
796
  this.options = options;
@@ -433,6 +812,69 @@ var RagableBrowserAuthClient = class {
433
812
  const gid = requireAuthGroupId(this.options);
434
813
  return `/auth-groups/${gid}/auth`;
435
814
  }
815
+ /** Supabase: `signUp` → `{ data: { user, session }, error }` */
816
+ async signUp(credentials) {
817
+ return asPostgrestResponse(async () => {
818
+ const name = typeof credentials.options?.data?.name === "string" ? credentials.options.data.name : void 0;
819
+ const session = await this.register({
820
+ email: credentials.email,
821
+ password: credentials.password,
822
+ name
823
+ });
824
+ return { user: session.user, session: toSupabaseSession(session) };
825
+ });
826
+ }
827
+ /** Supabase: `signInWithPassword` */
828
+ async signInWithPassword(credentials) {
829
+ return asPostgrestResponse(async () => {
830
+ const session = await this.login(credentials);
831
+ return { user: session.user, session: toSupabaseSession(session) };
832
+ });
833
+ }
834
+ /** Supabase: `refreshSession` */
835
+ async refreshSession(refreshToken) {
836
+ return asPostgrestResponse(async () => {
837
+ const tokens = await this.refresh({ refreshToken });
838
+ const me = await this.getUserFromToken(tokens.accessToken);
839
+ const session = {
840
+ access_token: tokens.accessToken,
841
+ refresh_token: tokens.refreshToken,
842
+ expires_in: parseExpiresInSeconds(tokens.expiresIn),
843
+ token_type: "bearer",
844
+ user: me.user
845
+ };
846
+ return { session, user: me.user };
847
+ });
848
+ }
849
+ /** Supabase: `getUser()` — needs `getAccessToken` on the client */
850
+ async getUser() {
851
+ return asPostgrestResponse(() => this.getMe());
852
+ }
853
+ /** Supabase: `updateUser` */
854
+ async updateUser(attributes) {
855
+ return asPostgrestResponse(
856
+ () => this.updateMe({
857
+ password: attributes.password,
858
+ name: attributes.data?.name
859
+ })
860
+ );
861
+ }
862
+ /**
863
+ * Supabase/Firebase: no server call — clear tokens in your app.
864
+ * Returns `{ error: null }` for API compatibility.
865
+ */
866
+ async signOut(_options) {
867
+ return { error: null };
868
+ }
869
+ async getUserFromToken(accessToken) {
870
+ const headers = this.baseHeaders(false);
871
+ headers.set("Authorization", `Bearer ${accessToken}`);
872
+ const response = await this.fetchImpl(`${this.toUrl(this.authPrefix())}/me`, {
873
+ method: "GET",
874
+ headers
875
+ });
876
+ return parseJsonOrThrow(response);
877
+ }
436
878
  async register(body) {
437
879
  const response = await this.fetchImpl(`${this.toUrl(this.authPrefix())}/register`, {
438
880
  method: "POST",
@@ -504,6 +946,7 @@ var RagableBrowserDatabaseClient = class {
504
946
  databaseInstanceId: params.databaseInstanceId,
505
947
  sql: params.sql,
506
948
  ...params.params !== void 0 ? { params: params.params } : {},
949
+ ...params.readOnly === false ? { readOnly: false } : {},
507
950
  ...params.timeoutMs !== void 0 ? { timeoutMs: params.timeoutMs } : {},
508
951
  ...params.rowLimit !== void 0 ? { rowLimit: params.rowLimit } : {}
509
952
  })
@@ -563,14 +1006,31 @@ var RagableBrowser = class {
563
1006
  __publicField(this, "agents");
564
1007
  __publicField(this, "auth");
565
1008
  __publicField(this, "database");
1009
+ __publicField(this, "options");
1010
+ this.options = options;
566
1011
  this.agents = new RagableBrowserAgentsClient(options);
567
1012
  this.auth = new RagableBrowserAuthClient(options);
568
1013
  this.database = new RagableBrowserDatabaseClient(options);
569
1014
  }
1015
+ /**
1016
+ * Supabase-style table API: `.from('items').select().eq('id', 1).single()`.
1017
+ * Pass `databaseInstanceId` here or set `databaseInstanceId` on the client options.
1018
+ */
1019
+ from(table, databaseInstanceId) {
1020
+ const id = databaseInstanceId?.trim() || this.options.databaseInstanceId?.trim();
1021
+ if (!id) {
1022
+ throw new Error(
1023
+ "RagableBrowser.from() requires databaseInstanceId in client options or as the second argument"
1024
+ );
1025
+ }
1026
+ const run = (p) => this.database.query(p);
1027
+ return new PostgrestTableApi(run, id, table);
1028
+ }
570
1029
  };
571
1030
  function createBrowserClient(options) {
572
1031
  return new RagableBrowser(options);
573
1032
  }
1033
+ var createRagableBrowserClient = createBrowserClient;
574
1034
 
575
1035
  // src/rag.ts
576
1036
  function formatRetrievalContext(results, options = {}) {
@@ -628,12 +1088,46 @@ var Ragable = class {
628
1088
  };
629
1089
  }
630
1090
  };
631
- function createClient(options) {
1091
+ function isServerClientOptions(o) {
1092
+ return typeof o === "object" && o !== null && "apiKey" in o && typeof o.apiKey === "string" && o.apiKey.length > 0;
1093
+ }
1094
+ function createClient(urlOrOptions, browserOptions) {
1095
+ if (typeof urlOrOptions === "string") {
1096
+ if (!browserOptions) {
1097
+ throw new Error(
1098
+ "createClient(url, options) requires options with at least organizationId"
1099
+ );
1100
+ }
1101
+ const raw = urlOrOptions.trim().replace(/\/+$/, "");
1102
+ const baseUrl = raw.endsWith("/api") ? raw : `${raw}/api`;
1103
+ return createBrowserClient({
1104
+ ...browserOptions,
1105
+ baseUrl: normalizeBrowserApiBase(baseUrl)
1106
+ });
1107
+ }
1108
+ if (isServerClientOptions(urlOrOptions)) {
1109
+ return new Ragable(urlOrOptions);
1110
+ }
1111
+ if (typeof urlOrOptions === "object" && urlOrOptions !== null && "organizationId" in urlOrOptions && typeof urlOrOptions.organizationId === "string") {
1112
+ return createBrowserClient(
1113
+ urlOrOptions
1114
+ );
1115
+ }
1116
+ throw new Error(
1117
+ "createClient(options) requires apiKey (server) or organizationId (browser)"
1118
+ );
1119
+ }
1120
+ function createRagableServerClient(options) {
632
1121
  return new Ragable(options);
633
1122
  }
634
1123
  // Annotate the CommonJS export names for ESM import in node:
635
1124
  0 && (module.exports = {
636
1125
  AgentsClient,
1126
+ PostgrestDeleteBuilder,
1127
+ PostgrestInsertBuilder,
1128
+ PostgrestSelectBuilder,
1129
+ PostgrestTableApi,
1130
+ PostgrestUpdateBuilder,
637
1131
  Ragable,
638
1132
  RagableBrowser,
639
1133
  RagableBrowserAgentsClient,
@@ -642,9 +1136,12 @@ function createClient(options) {
642
1136
  RagableError,
643
1137
  RagableRequestClient,
644
1138
  ShiftClient,
1139
+ asPostgrestResponse,
645
1140
  createBrowserClient,
646
1141
  createClient,
647
1142
  createRagPipeline,
1143
+ createRagableBrowserClient,
1144
+ createRagableServerClient,
648
1145
  extractErrorMessage,
649
1146
  formatRetrievalContext,
650
1147
  normalizeBrowserApiBase,