@ragable/sdk 0.4.2 → 0.5.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.js CHANGED
@@ -23,11 +23,17 @@ 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,
26
+ DEFAULT_RAGABLE_API_BASE: () => DEFAULT_RAGABLE_API_BASE,
27
+ PostgrestDeleteReturningBuilder: () => PostgrestDeleteReturningBuilder,
28
+ PostgrestDeleteRootBuilder: () => PostgrestDeleteRootBuilder,
29
+ PostgrestInsertReturningBuilder: () => PostgrestInsertReturningBuilder,
30
+ PostgrestInsertRootBuilder: () => PostgrestInsertRootBuilder,
28
31
  PostgrestSelectBuilder: () => PostgrestSelectBuilder,
29
32
  PostgrestTableApi: () => PostgrestTableApi,
30
- PostgrestUpdateBuilder: () => PostgrestUpdateBuilder,
33
+ PostgrestUpdateReturningBuilder: () => PostgrestUpdateReturningBuilder,
34
+ PostgrestUpdateRootBuilder: () => PostgrestUpdateRootBuilder,
35
+ PostgrestUpsertReturningBuilder: () => PostgrestUpsertReturningBuilder,
36
+ PostgrestUpsertRootBuilder: () => PostgrestUpsertRootBuilder,
31
37
  Ragable: () => Ragable,
32
38
  RagableBrowser: () => RagableBrowser,
33
39
  RagableBrowserAgentsClient: () => RagableBrowserAgentsClient,
@@ -58,6 +64,7 @@ function bindFetch(custom) {
58
64
  return f.call(globalThis, input, init);
59
65
  };
60
66
  }
67
+ var DEFAULT_RAGABLE_API_BASE = "https://ragable-341305259977.asia-southeast1.run.app/api";
61
68
  var RagableError = class extends Error {
62
69
  constructor(message, status, body) {
63
70
  super(message);
@@ -89,7 +96,7 @@ var RagableRequestClient = class {
89
96
  __publicField(this, "fetchImpl");
90
97
  __publicField(this, "defaultHeaders");
91
98
  this.apiKey = options.apiKey;
92
- this.baseUrl = options.baseUrl ?? "http://localhost:8080/api";
99
+ this.baseUrl = options.baseUrl ?? DEFAULT_RAGABLE_API_BASE;
93
100
  this.fetchImpl = bindFetch(options.fetch);
94
101
  this.defaultHeaders = options.headers;
95
102
  }
@@ -407,6 +414,18 @@ function quoteIdent(name) {
407
414
  assertIdent(name, "column");
408
415
  return `"${name}"`;
409
416
  }
417
+ function parseConflictColumns(onConflict) {
418
+ const parts = onConflict.split(",").map((s) => s.trim()).filter(Boolean);
419
+ if (parts.length === 0) {
420
+ throw new RagableError(
421
+ "upsert requires onConflict with at least one column (e.g. 'id' or 'org_id,user_id')",
422
+ 400,
423
+ null
424
+ );
425
+ }
426
+ for (const p of parts) assertIdent(p, "onConflict");
427
+ return parts;
428
+ }
410
429
  var OP_SQL = {
411
430
  eq: "=",
412
431
  neq: "<>",
@@ -489,7 +508,6 @@ var PostgrestSelectBuilder = class {
489
508
  this._order = { column, ascending: options?.ascending !== false };
490
509
  return this;
491
510
  }
492
- /** @param includeUserLimit when false, omit `.limit()` (for `.single()` / `.maybeSingle()`). */
493
511
  buildSelectCore(params, includeUserLimit) {
494
512
  const tbl = quoteIdent(this.table);
495
513
  const { clause } = buildWhere(this.filters, params);
@@ -529,12 +547,7 @@ var PostgrestSelectBuilder = class {
529
547
  params,
530
548
  readOnly: true
531
549
  });
532
- if (res.rows.length === 0) {
533
- throw new RagableError("JSON object requested, multiple (or no) rows returned", 406, {
534
- code: "PGRST116"
535
- });
536
- }
537
- if (res.rows.length > 1) {
550
+ if (res.rows.length === 0 || res.rows.length > 1) {
538
551
  throw new RagableError("JSON object requested, multiple (or no) rows returned", 406, {
539
552
  code: "PGRST116"
540
553
  });
@@ -562,23 +575,70 @@ var PostgrestSelectBuilder = class {
562
575
  });
563
576
  }
564
577
  };
565
- var PostgrestInsertBuilder = class {
578
+ var PostgrestInsertRootBuilder = class {
566
579
  constructor(run, databaseInstanceId, table, rows) {
567
580
  this.run = run;
568
581
  this.databaseInstanceId = databaseInstanceId;
569
582
  this.table = table;
570
583
  this.rows = rows;
571
- __publicField(this, "returning", "*");
572
584
  assertIdent(table, "table");
573
585
  }
586
+ /**
587
+ * Return inserted rows (Supabase: chain `.select()` to get data).
588
+ * @see https://supabase.com/docs/reference/javascript/insert
589
+ */
574
590
  select(columns = "*") {
575
- this.returning = columns;
576
- return this;
591
+ return new PostgrestInsertReturningBuilder(
592
+ this.run,
593
+ this.databaseInstanceId,
594
+ this.table,
595
+ this.rows,
596
+ columns
597
+ );
577
598
  }
578
599
  then(onfulfilled, onrejected) {
579
- return this.execute().then(onfulfilled, onrejected);
600
+ return this.executeNoReturn().then(onfulfilled, onrejected);
580
601
  }
581
- async execute() {
602
+ async executeNoReturn() {
603
+ return asPostgrestResponse(async () => {
604
+ if (this.rows.length === 0) return null;
605
+ const keys = Object.keys(this.rows[0]);
606
+ for (const k of keys) assertIdent(k, "column");
607
+ const tbl = quoteIdent(this.table);
608
+ const params = [];
609
+ const valueGroups = [];
610
+ for (const row of this.rows) {
611
+ const placeholders = [];
612
+ for (const k of keys) {
613
+ params.push(row[k]);
614
+ placeholders.push(`$${params.length}`);
615
+ }
616
+ valueGroups.push(`(${placeholders.join(", ")})`);
617
+ }
618
+ const cols = keys.map(quoteIdent).join(", ");
619
+ const sql = `INSERT INTO ${tbl} (${cols}) VALUES ${valueGroups.join(", ")}`;
620
+ await this.run({
621
+ databaseInstanceId: this.databaseInstanceId,
622
+ sql,
623
+ params,
624
+ readOnly: false
625
+ });
626
+ return null;
627
+ });
628
+ }
629
+ };
630
+ var PostgrestInsertReturningBuilder = class {
631
+ constructor(run, databaseInstanceId, table, rows, returning) {
632
+ this.run = run;
633
+ this.databaseInstanceId = databaseInstanceId;
634
+ this.table = table;
635
+ this.rows = rows;
636
+ this.returning = returning;
637
+ }
638
+ then(onfulfilled, onrejected) {
639
+ return this.executeMany().then(onfulfilled, onrejected);
640
+ }
641
+ async executeMany() {
582
642
  return asPostgrestResponse(async () => {
583
643
  if (this.rows.length === 0) return [];
584
644
  const keys = Object.keys(this.rows[0]);
@@ -605,29 +665,137 @@ var PostgrestInsertBuilder = class {
605
665
  return res.rows;
606
666
  });
607
667
  }
668
+ async single() {
669
+ return asPostgrestResponse(async () => {
670
+ const { data, error } = await this.executeMany();
671
+ if (error) throw error;
672
+ const rows = data ?? [];
673
+ if (rows.length === 0 || rows.length > 1) {
674
+ throw new RagableError("JSON object requested, multiple (or no) rows returned", 406, {
675
+ code: "PGRST116"
676
+ });
677
+ }
678
+ return rows[0];
679
+ });
680
+ }
681
+ async maybeSingle() {
682
+ return asPostgrestResponse(async () => {
683
+ const { data, error } = await this.executeMany();
684
+ if (error) throw error;
685
+ const rows = data ?? [];
686
+ if (rows.length > 1) {
687
+ throw new RagableError("JSON object requested, multiple (or no) rows returned", 406, {
688
+ code: "PGRST116"
689
+ });
690
+ }
691
+ return rows[0] ?? null;
692
+ });
693
+ }
608
694
  };
609
- var PostgrestUpdateBuilder = class {
695
+ var PostgrestUpdateRootBuilder = class {
610
696
  constructor(run, databaseInstanceId, table, patch) {
611
697
  this.run = run;
612
698
  this.databaseInstanceId = databaseInstanceId;
613
699
  this.table = table;
614
700
  this.patch = patch;
615
701
  __publicField(this, "filters", []);
616
- __publicField(this, "returning", "*");
617
702
  assertIdent(table, "table");
618
703
  }
619
704
  eq(column, value) {
620
705
  this.filters.push({ op: "eq", column, value });
621
706
  return this;
622
707
  }
623
- select(columns = "*") {
624
- this.returning = columns;
708
+ neq(column, value) {
709
+ this.filters.push({ op: "neq", column, value });
625
710
  return this;
626
711
  }
712
+ gt(column, value) {
713
+ this.filters.push({ op: "gt", column, value });
714
+ return this;
715
+ }
716
+ gte(column, value) {
717
+ this.filters.push({ op: "gte", column, value });
718
+ return this;
719
+ }
720
+ lt(column, value) {
721
+ this.filters.push({ op: "lt", column, value });
722
+ return this;
723
+ }
724
+ lte(column, value) {
725
+ this.filters.push({ op: "lte", column, value });
726
+ return this;
727
+ }
728
+ like(column, value) {
729
+ this.filters.push({ op: "like", column, value });
730
+ return this;
731
+ }
732
+ ilike(column, value) {
733
+ this.filters.push({ op: "ilike", column, value });
734
+ return this;
735
+ }
736
+ /**
737
+ * Return updated rows (Supabase: `.update().eq().select()`).
738
+ * @see https://supabase.com/docs/reference/javascript/update
739
+ */
740
+ select(columns = "*") {
741
+ return new PostgrestUpdateReturningBuilder(
742
+ this.run,
743
+ this.databaseInstanceId,
744
+ this.table,
745
+ this.patch,
746
+ this.filters,
747
+ columns
748
+ );
749
+ }
750
+ then(onfulfilled, onrejected) {
751
+ return this.executeNoReturn().then(onfulfilled, onrejected);
752
+ }
753
+ async executeNoReturn() {
754
+ return asPostgrestResponse(async () => {
755
+ const keys = Object.keys(this.patch);
756
+ if (keys.length === 0) {
757
+ throw new RagableError("Empty update payload", 400, null);
758
+ }
759
+ for (const k of keys) assertIdent(k, "column");
760
+ if (this.filters.length === 0) {
761
+ throw new RagableError(
762
+ "UPDATE requires a filter (e.g. .eq('id', value)) \u2014 refusing unscoped update",
763
+ 400,
764
+ null
765
+ );
766
+ }
767
+ const params = [];
768
+ const sets = [];
769
+ for (const k of keys) {
770
+ params.push(this.patch[k]);
771
+ sets.push(`${quoteIdent(k)} = $${params.length}`);
772
+ }
773
+ const { clause } = buildWhere(this.filters, params);
774
+ const tbl = quoteIdent(this.table);
775
+ const sql = `UPDATE ${tbl} SET ${sets.join(", ")}${clause}`;
776
+ await this.run({
777
+ databaseInstanceId: this.databaseInstanceId,
778
+ sql,
779
+ params,
780
+ readOnly: false
781
+ });
782
+ return null;
783
+ });
784
+ }
785
+ };
786
+ var PostgrestUpdateReturningBuilder = class {
787
+ constructor(run, databaseInstanceId, table, patch, filters, returning) {
788
+ this.run = run;
789
+ this.databaseInstanceId = databaseInstanceId;
790
+ this.table = table;
791
+ this.patch = patch;
792
+ this.filters = filters;
793
+ this.returning = returning;
794
+ }
627
795
  then(onfulfilled, onrejected) {
628
- return this.execute().then(onfulfilled, onrejected);
796
+ return this.executeMany().then(onfulfilled, onrejected);
629
797
  }
630
- async execute() {
798
+ async executeMany() {
631
799
  return asPostgrestResponse(async () => {
632
800
  const keys = Object.keys(this.patch);
633
801
  if (keys.length === 0) {
@@ -659,28 +827,124 @@ var PostgrestUpdateBuilder = class {
659
827
  return res.rows;
660
828
  });
661
829
  }
830
+ async single() {
831
+ return asPostgrestResponse(async () => {
832
+ const { data, error } = await this.executeMany();
833
+ if (error) throw error;
834
+ const rows = data ?? [];
835
+ if (rows.length === 0 || rows.length > 1) {
836
+ throw new RagableError("JSON object requested, multiple (or no) rows returned", 406, {
837
+ code: "PGRST116"
838
+ });
839
+ }
840
+ return rows[0];
841
+ });
842
+ }
843
+ async maybeSingle() {
844
+ return asPostgrestResponse(async () => {
845
+ const { data, error } = await this.executeMany();
846
+ if (error) throw error;
847
+ const rows = data ?? [];
848
+ if (rows.length > 1) {
849
+ throw new RagableError("JSON object requested, multiple (or no) rows returned", 406, {
850
+ code: "PGRST116"
851
+ });
852
+ }
853
+ return rows[0] ?? null;
854
+ });
855
+ }
662
856
  };
663
- var PostgrestDeleteBuilder = class {
857
+ var PostgrestDeleteRootBuilder = class {
664
858
  constructor(run, databaseInstanceId, table) {
665
859
  this.run = run;
666
860
  this.databaseInstanceId = databaseInstanceId;
667
861
  this.table = table;
668
862
  __publicField(this, "filters", []);
669
- __publicField(this, "returning", "*");
670
863
  assertIdent(table, "table");
671
864
  }
672
865
  eq(column, value) {
673
866
  this.filters.push({ op: "eq", column, value });
674
867
  return this;
675
868
  }
676
- select(columns = "*") {
677
- this.returning = columns;
869
+ neq(column, value) {
870
+ this.filters.push({ op: "neq", column, value });
871
+ return this;
872
+ }
873
+ gt(column, value) {
874
+ this.filters.push({ op: "gt", column, value });
875
+ return this;
876
+ }
877
+ gte(column, value) {
878
+ this.filters.push({ op: "gte", column, value });
678
879
  return this;
679
880
  }
881
+ lt(column, value) {
882
+ this.filters.push({ op: "lt", column, value });
883
+ return this;
884
+ }
885
+ lte(column, value) {
886
+ this.filters.push({ op: "lte", column, value });
887
+ return this;
888
+ }
889
+ like(column, value) {
890
+ this.filters.push({ op: "like", column, value });
891
+ return this;
892
+ }
893
+ ilike(column, value) {
894
+ this.filters.push({ op: "ilike", column, value });
895
+ return this;
896
+ }
897
+ /**
898
+ * Return deleted rows (Supabase: `.delete().eq().select()`).
899
+ * @see https://supabase.com/docs/reference/javascript/delete
900
+ */
901
+ select(columns = "*") {
902
+ return new PostgrestDeleteReturningBuilder(
903
+ this.run,
904
+ this.databaseInstanceId,
905
+ this.table,
906
+ this.filters,
907
+ columns
908
+ );
909
+ }
910
+ then(onfulfilled, onrejected) {
911
+ return this.executeNoReturn().then(onfulfilled, onrejected);
912
+ }
913
+ async executeNoReturn() {
914
+ return asPostgrestResponse(async () => {
915
+ if (this.filters.length === 0) {
916
+ throw new RagableError(
917
+ "DELETE requires a filter (e.g. .eq('id', value)) \u2014 refusing unscoped delete",
918
+ 400,
919
+ null
920
+ );
921
+ }
922
+ const params = [];
923
+ const { clause } = buildWhere(this.filters, params);
924
+ const tbl = quoteIdent(this.table);
925
+ const sql = `DELETE FROM ${tbl}${clause}`;
926
+ await this.run({
927
+ databaseInstanceId: this.databaseInstanceId,
928
+ sql,
929
+ params,
930
+ readOnly: false
931
+ });
932
+ return null;
933
+ });
934
+ }
935
+ };
936
+ var PostgrestDeleteReturningBuilder = class {
937
+ constructor(run, databaseInstanceId, table, filters, returning) {
938
+ this.run = run;
939
+ this.databaseInstanceId = databaseInstanceId;
940
+ this.table = table;
941
+ this.filters = filters;
942
+ this.returning = returning;
943
+ }
680
944
  then(onfulfilled, onrejected) {
681
- return this.execute().then(onfulfilled, onrejected);
945
+ return this.executeMany().then(onfulfilled, onrejected);
682
946
  }
683
- async execute() {
947
+ async executeMany() {
684
948
  return asPostgrestResponse(async () => {
685
949
  if (this.filters.length === 0) {
686
950
  throw new RagableError(
@@ -702,6 +966,145 @@ var PostgrestDeleteBuilder = class {
702
966
  return res.rows;
703
967
  });
704
968
  }
969
+ async single() {
970
+ return asPostgrestResponse(async () => {
971
+ const { data, error } = await this.executeMany();
972
+ if (error) throw error;
973
+ const rows = data ?? [];
974
+ if (rows.length === 0 || rows.length > 1) {
975
+ throw new RagableError("JSON object requested, multiple (or no) rows returned", 406, {
976
+ code: "PGRST116"
977
+ });
978
+ }
979
+ return rows[0];
980
+ });
981
+ }
982
+ async maybeSingle() {
983
+ return asPostgrestResponse(async () => {
984
+ const { data, error } = await this.executeMany();
985
+ if (error) throw error;
986
+ const rows = data ?? [];
987
+ if (rows.length > 1) {
988
+ throw new RagableError("JSON object requested, multiple (or no) rows returned", 406, {
989
+ code: "PGRST116"
990
+ });
991
+ }
992
+ return rows[0] ?? null;
993
+ });
994
+ }
995
+ };
996
+ var PostgrestUpsertRootBuilder = class {
997
+ constructor(run, databaseInstanceId, table, rows, onConflict, ignoreDuplicates) {
998
+ this.run = run;
999
+ this.databaseInstanceId = databaseInstanceId;
1000
+ this.table = table;
1001
+ this.rows = rows;
1002
+ this.ignoreDuplicates = ignoreDuplicates;
1003
+ __publicField(this, "conflictCols");
1004
+ assertIdent(table, "table");
1005
+ this.conflictCols = parseConflictColumns(onConflict);
1006
+ }
1007
+ /**
1008
+ * Return upserted rows (Supabase: `.upsert().select()`).
1009
+ * @see https://supabase.com/docs/reference/javascript/upsert
1010
+ */
1011
+ select(columns = "*") {
1012
+ return new PostgrestUpsertReturningBuilder(this, columns);
1013
+ }
1014
+ then(onfulfilled, onrejected) {
1015
+ return this.executeNoReturn().then(onfulfilled, onrejected);
1016
+ }
1017
+ async executeNoReturn() {
1018
+ return asPostgrestResponse(async () => {
1019
+ await this.runUpsert(null);
1020
+ return null;
1021
+ });
1022
+ }
1023
+ async runUpsert(returning) {
1024
+ if (this.rows.length === 0) {
1025
+ return { command: "INSERT", rowCount: 0, truncated: false, rows: [] };
1026
+ }
1027
+ const keys = Object.keys(this.rows[0]);
1028
+ for (const k of keys) assertIdent(k, "column");
1029
+ const tbl = quoteIdent(this.table);
1030
+ const conflictQuoted = this.conflictCols.map(quoteIdent).join(", ");
1031
+ const params = [];
1032
+ const valueGroups = [];
1033
+ for (const row of this.rows) {
1034
+ const placeholders = [];
1035
+ for (const k of keys) {
1036
+ params.push(row[k]);
1037
+ placeholders.push(`$${params.length}`);
1038
+ }
1039
+ valueGroups.push(`(${placeholders.join(", ")})`);
1040
+ }
1041
+ const cols = keys.map(quoteIdent).join(", ");
1042
+ let sql = `INSERT INTO ${tbl} (${cols}) VALUES ${valueGroups.join(", ")} ON CONFLICT (${conflictQuoted})`;
1043
+ if (this.ignoreDuplicates) {
1044
+ sql += " DO NOTHING";
1045
+ } else {
1046
+ const setParts = keys.filter((k) => !this.conflictCols.includes(k)).map((k) => `${quoteIdent(k)} = EXCLUDED.${quoteIdent(k)}`);
1047
+ if (setParts.length === 0) {
1048
+ sql += " DO NOTHING";
1049
+ } else {
1050
+ sql += ` DO UPDATE SET ${setParts.join(", ")}`;
1051
+ }
1052
+ }
1053
+ if (returning) {
1054
+ sql += ` RETURNING ${returning}`;
1055
+ }
1056
+ return this.run({
1057
+ databaseInstanceId: this.databaseInstanceId,
1058
+ sql,
1059
+ params,
1060
+ readOnly: false
1061
+ });
1062
+ }
1063
+ /** Used by returning builder */
1064
+ async runWithReturning(returning) {
1065
+ return this.runUpsert(returning);
1066
+ }
1067
+ };
1068
+ var PostgrestUpsertReturningBuilder = class {
1069
+ constructor(root, returning) {
1070
+ this.root = root;
1071
+ this.returning = returning;
1072
+ }
1073
+ then(onfulfilled, onrejected) {
1074
+ return this.executeMany().then(onfulfilled, onrejected);
1075
+ }
1076
+ async executeMany() {
1077
+ return asPostgrestResponse(async () => {
1078
+ const res = await this.root.runWithReturning(this.returning);
1079
+ return res.rows;
1080
+ });
1081
+ }
1082
+ async single() {
1083
+ return asPostgrestResponse(async () => {
1084
+ const { data, error } = await this.executeMany();
1085
+ if (error) throw error;
1086
+ const rows = data ?? [];
1087
+ if (rows.length === 0 || rows.length > 1) {
1088
+ throw new RagableError("JSON object requested, multiple (or no) rows returned", 406, {
1089
+ code: "PGRST116"
1090
+ });
1091
+ }
1092
+ return rows[0];
1093
+ });
1094
+ }
1095
+ async maybeSingle() {
1096
+ return asPostgrestResponse(async () => {
1097
+ const { data, error } = await this.executeMany();
1098
+ if (error) throw error;
1099
+ const rows = data ?? [];
1100
+ if (rows.length > 1) {
1101
+ throw new RagableError("JSON object requested, multiple (or no) rows returned", 406, {
1102
+ code: "PGRST116"
1103
+ });
1104
+ }
1105
+ return rows[0] ?? null;
1106
+ });
1107
+ }
705
1108
  };
706
1109
  var PostgrestTableApi = class {
707
1110
  constructor(run, databaseInstanceId, table) {
@@ -719,7 +1122,7 @@ var PostgrestTableApi = class {
719
1122
  }
720
1123
  insert(values) {
721
1124
  const rows = Array.isArray(values) ? values : [values];
722
- return new PostgrestInsertBuilder(
1125
+ return new PostgrestInsertRootBuilder(
723
1126
  this.run,
724
1127
  this.databaseInstanceId,
725
1128
  this.table,
@@ -727,7 +1130,7 @@ var PostgrestTableApi = class {
727
1130
  );
728
1131
  }
729
1132
  update(patch) {
730
- return new PostgrestUpdateBuilder(
1133
+ return new PostgrestUpdateRootBuilder(
731
1134
  this.run,
732
1135
  this.databaseInstanceId,
733
1136
  this.table,
@@ -735,17 +1138,33 @@ var PostgrestTableApi = class {
735
1138
  );
736
1139
  }
737
1140
  delete() {
738
- return new PostgrestDeleteBuilder(
1141
+ return new PostgrestDeleteRootBuilder(
739
1142
  this.run,
740
1143
  this.databaseInstanceId,
741
1144
  this.table
742
1145
  );
743
1146
  }
1147
+ /**
1148
+ * `INSERT ... ON CONFLICT ... DO UPDATE` (or `DO NOTHING` with `ignoreDuplicates`).
1149
+ * @see https://supabase.com/docs/reference/javascript/upsert
1150
+ */
1151
+ upsert(values, options) {
1152
+ const rows = Array.isArray(values) ? values : [values];
1153
+ return new PostgrestUpsertRootBuilder(
1154
+ this.run,
1155
+ this.databaseInstanceId,
1156
+ this.table,
1157
+ rows,
1158
+ options.onConflict,
1159
+ options.ignoreDuplicates === true
1160
+ );
1161
+ }
744
1162
  };
745
1163
 
746
1164
  // src/browser.ts
747
1165
  function normalizeBrowserApiBase(baseUrl) {
748
- return (baseUrl ?? "http://localhost:8080/api").replace(/\/+$/, "");
1166
+ const trimmed = (baseUrl ?? DEFAULT_RAGABLE_API_BASE).trim().replace(/\/+$/, "");
1167
+ return trimmed.endsWith("/api") ? trimmed : `${trimmed}/api`;
749
1168
  }
750
1169
  function requireAuthGroupId(options) {
751
1170
  const id = options.authGroupId?.trim();
@@ -769,6 +1188,20 @@ async function requireAccessToken(options) {
769
1188
  }
770
1189
  return token.trim();
771
1190
  }
1191
+ async function resolveDatabaseAuthBearer(options) {
1192
+ const mode = options.dataAuth ?? "user";
1193
+ if (mode === "user") {
1194
+ return requireAccessToken(options);
1195
+ }
1196
+ const fromGetter = options.getDataStaticKey ? await options.getDataStaticKey() : null;
1197
+ const key = (fromGetter?.trim() || options.dataStaticKey?.trim()) ?? "";
1198
+ if (!key) {
1199
+ throw new Error(
1200
+ mode === "publicAnon" ? "dataAuth publicAnon requires getDataStaticKey or dataStaticKey (rotate key in dashboard)" : "dataAuth admin requires getDataStaticKey or dataStaticKey (server-side only; rotate in dashboard)"
1201
+ );
1202
+ }
1203
+ return key;
1204
+ }
772
1205
  async function parseJsonOrThrow(response) {
773
1206
  const payload = await parseMaybeJsonBody(response);
774
1207
  if (!response.ok) {
@@ -938,7 +1371,7 @@ var RagableBrowserDatabaseClient = class {
938
1371
  }
939
1372
  async query(params) {
940
1373
  const gid = requireAuthGroupId(this.options);
941
- const token = await requireAccessToken(this.options);
1374
+ const token = await resolveDatabaseAuthBearer(this.options);
942
1375
  const databaseInstanceId = params.databaseInstanceId?.trim() || this.options.databaseInstanceId?.trim();
943
1376
  if (!databaseInstanceId) {
944
1377
  throw new Error(
@@ -948,6 +1381,7 @@ var RagableBrowserDatabaseClient = class {
948
1381
  const headers = this.baseHeaders();
949
1382
  headers.set("Authorization", `Bearer ${token}`);
950
1383
  headers.set("Content-Type", "application/json");
1384
+ const readOnly = (this.options.dataAuth ?? "user") === "publicAnon" ? true : params.readOnly !== false;
951
1385
  const response = await this.fetchImpl(
952
1386
  this.toUrl(`/auth-groups/${gid}/data/query`),
953
1387
  {
@@ -957,7 +1391,7 @@ var RagableBrowserDatabaseClient = class {
957
1391
  databaseInstanceId,
958
1392
  sql: params.sql,
959
1393
  ...params.params !== void 0 ? { params: params.params } : {},
960
- ...params.readOnly === false ? { readOnly: false } : {},
1394
+ readOnly,
961
1395
  ...params.timeoutMs !== void 0 ? { timeoutMs: params.timeoutMs } : {},
962
1396
  ...params.rowLimit !== void 0 ? { rowLimit: params.rowLimit } : {}
963
1397
  })
@@ -1133,11 +1567,17 @@ function createRagableServerClient(options) {
1133
1567
  // Annotate the CommonJS export names for ESM import in node:
1134
1568
  0 && (module.exports = {
1135
1569
  AgentsClient,
1136
- PostgrestDeleteBuilder,
1137
- PostgrestInsertBuilder,
1570
+ DEFAULT_RAGABLE_API_BASE,
1571
+ PostgrestDeleteReturningBuilder,
1572
+ PostgrestDeleteRootBuilder,
1573
+ PostgrestInsertReturningBuilder,
1574
+ PostgrestInsertRootBuilder,
1138
1575
  PostgrestSelectBuilder,
1139
1576
  PostgrestTableApi,
1140
- PostgrestUpdateBuilder,
1577
+ PostgrestUpdateReturningBuilder,
1578
+ PostgrestUpdateRootBuilder,
1579
+ PostgrestUpsertReturningBuilder,
1580
+ PostgrestUpsertRootBuilder,
1141
1581
  Ragable,
1142
1582
  RagableBrowser,
1143
1583
  RagableBrowserAgentsClient,