@ai-matrx/data 0.18.34 → 0.18.35

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/db.js CHANGED
@@ -628,28 +628,266 @@ function createOAuthRefreshFetch(args) {
628
628
  return normalizeOAuthResponse(adopted, responseSession, clientId);
629
629
  };
630
630
  }
631
+
632
+ // src/db/write-failure.ts
633
+ var WriteRefusedError = class extends Error {
634
+ status;
635
+ /** What the server said for a person, when it said something a person can read. */
636
+ serverMessage;
637
+ /** The developer line (method, path, status, body) — for diagnostics, never for the screen. */
638
+ technical;
639
+ constructor(args) {
640
+ super(refusalSentence(args.status, args.serverMessage ?? null));
641
+ this.name = "WriteRefusedError";
642
+ this.status = args.status;
643
+ this.serverMessage = args.serverMessage ?? null;
644
+ this.technical = args.technical;
645
+ }
646
+ };
647
+ function serverMessageFromBody(body) {
648
+ if (!body || typeof body !== "object") return null;
649
+ const b = body;
650
+ const detail = b.detail;
651
+ const pick = (v) => typeof v === "string" && v.trim() !== "" ? v.trim() : null;
652
+ if (detail && typeof detail === "object" && !Array.isArray(detail)) {
653
+ const d = detail;
654
+ return pick(d.user_message) ?? pick(d.message);
655
+ }
656
+ return pick(b.user_message) ?? pick(detail) ?? pick(b.message);
657
+ }
658
+ var LOOKS_TECHNICAL = /(^|\s)(GET|POST|PUT|PATCH|DELETE)\s+\/|https?:\/\/|\bHTTP \d{3}\b|Traceback|Exception\b|permission denied for|violates|row-level security|\brelation "|\bcolumn "|\bfunction .* does not exist|\bPGRST\d+|\bJWT\b|duplicate key|syntax error|invalid input syntax|JSON object requested|rows returned|\bnull value in column|\bundefined\b|\bat [\w.]+ \(/i;
659
+ function personSentence(text2) {
660
+ if (typeof text2 !== "string") return null;
661
+ let said = text2.trim();
662
+ const named = /^[a-z][a-z0-9_]*[a-z0-9]: (.+)$/s.exec(said);
663
+ if (named) said = (named[1] ?? "").trim().replace(/^[a-z]/, (c) => c.toUpperCase());
664
+ if (said.length < 8 || LOOKS_TECHNICAL.test(said) || !/^[A-Z"“']/.test(said) || !/\s/.test(said)) return null;
665
+ return /[.!?]["”']?$/.test(said) ? said : `${said}.`;
666
+ }
667
+ function isPostgrestShaped(err) {
668
+ if (!err || typeof err !== "object") return false;
669
+ const code = err.code;
670
+ return typeof code === "string" && /^(PGRST\d{3}|[0-9A-Z]{5})$/.test(code) && !("status" in err && typeof err.status === "number");
671
+ }
672
+ function isSerializedRefusal(err) {
673
+ if (!err || typeof err !== "object" || err instanceof Error) return false;
674
+ const e = err;
675
+ if (typeof e.message !== "string" || e.message.trim() === "") return false;
676
+ if (e.name === "WriteRefusedError" || e.name === "WriteDidNotLandError") return true;
677
+ return e.name === "Error" && !LOOKS_TECHNICAL.test(e.message);
678
+ }
679
+ function postgrestSentence(code) {
680
+ if (code === "42501" || code === "PGRST301" || code === "PGRST302") return "You do not have permission to do this.";
681
+ if (code === "PGRST303" || code === "PGRST300") return "Your sign-in has expired. Sign in again, then try again.";
682
+ if (code === "PGRST116") return "It is no longer there \u2014 it may have been deleted.";
683
+ if (code === "23505") return "Something with the same name or key already exists.";
684
+ if (code === "23503") return "It refers to something that no longer exists.";
685
+ if (code === "23514" || code === "23502" || code === "22P02") return "The database would not accept that value.";
686
+ if (code === "57014") return "The database took too long to answer.";
687
+ if (code === "40001" || code === "40P01") return "It changed while you were working. Reload to see the latest.";
688
+ return "The database refused it.";
689
+ }
690
+ function assertWriteLanded(rows, technical) {
691
+ const n = Array.isArray(rows) ? rows.length : rows == null ? 0 : 1;
692
+ if (n > 0) return;
693
+ throw new WriteRefusedError({
694
+ status: 403,
695
+ serverMessage: "Nothing was saved: you may not have permission to change this, or it no longer exists.",
696
+ technical: `${technical} matched 0 rows`
697
+ });
698
+ }
699
+ function refusalSentence(status, serverMessage) {
700
+ const said = serverMessage && !LOOKS_TECHNICAL.test(serverMessage) ? serverMessage : null;
701
+ if (status === 401) return "Your sign-in has expired. Sign in again, then try again.";
702
+ if (status === 403) return said ?? "You do not have permission to do this.";
703
+ if (status === 404) return said ?? "It is no longer there \u2014 it may have been deleted.";
704
+ if (status === 409 || status === 412) return said ?? "It changed while you were working. Reload to see the latest.";
705
+ if (status >= 500) return "The server refused the request.";
706
+ if (said) return `The server said: ${said.replace(/\.?$/, ".")}`;
707
+ return "The server did not accept it.";
708
+ }
709
+ function describeWriteFailure(err, { action, remedy = "Try again." }) {
710
+ const title = `Could not ${action}.`;
711
+ let why;
712
+ if (err instanceof WriteRefusedError) {
713
+ why = err.message;
714
+ } else if (isSerializedRefusal(err)) {
715
+ why = /[.!?]["”']?$/.test(err.message.trim()) ? err.message.trim() : `${err.message.trim()}.`;
716
+ } else if (isPostgrestShaped(err)) {
717
+ why = personSentence(err.message) ?? postgrestSentence(err.code);
718
+ } else if (err && typeof err === "object" && "status" in err && typeof err.status === "number") {
719
+ const e = err;
720
+ why = refusalSentence(e.status, typeof e.userMessage === "string" ? e.userMessage : null);
721
+ } else if (err instanceof TypeError || err instanceof Error && /Failed to fetch|NetworkError|Load failed/i.test(err.message)) {
722
+ why = "The server could not be reached. Check your connection.";
723
+ } else if (err instanceof Error && err.message && !LOOKS_TECHNICAL.test(err.message)) {
724
+ why = err.message.replace(/\.?$/, ".");
725
+ } else if (typeof err === "string" && err.trim() && !LOOKS_TECHNICAL.test(err)) {
726
+ why = err.trim().replace(/\.?$/, ".");
727
+ } else {
728
+ why = "Something went wrong on our side.";
729
+ }
730
+ return { title, description: `${why} ${remedy}`.trim() };
731
+ }
732
+
733
+ // src/db/write-one.ts
734
+ import { PostgrestError } from "@supabase/supabase-js";
735
+ var PAST = {
736
+ save: "saved",
737
+ update: "updated",
738
+ rename: "renamed",
739
+ move: "moved",
740
+ delete: "deleted",
741
+ remove: "removed",
742
+ archive: "archived",
743
+ restore: "restored",
744
+ publish: "published",
745
+ unpublish: "unpublished",
746
+ change: "changed"
747
+ };
748
+ var GERUND = {
749
+ save: "saving",
750
+ update: "updating",
751
+ rename: "renaming",
752
+ move: "moving",
753
+ delete: "deleting",
754
+ remove: "removing",
755
+ archive: "archiving",
756
+ restore: "restoring",
757
+ publish: "publishing",
758
+ unpublish: "unpublishing",
759
+ change: "changing"
760
+ };
761
+ var WriteDidNotLandError = class extends WriteRefusedError {
762
+ action;
763
+ noun;
764
+ reason;
765
+ constructor({ action, noun }, reason = "refused") {
766
+ super({
767
+ status: reason === "taken" ? 409 : 403,
768
+ serverMessage: reason === "taken" ? `This ${noun} was already handled \u2014 refresh to see the latest.` : `Nothing was ${PAST[action]}: this ${noun} no longer exists, or your access does not allow ${GERUND[action]} it.`,
769
+ technical: reason === "taken" ? `writeOne(${action} ${noun}) compare-and-set matched 0 rows \u2014 another writer got there first` : `writeOne(${action} ${noun}) matched 0 rows \u2014 RLS refused or the row is gone`
770
+ });
771
+ this.name = "WriteDidNotLandError";
772
+ this.action = action;
773
+ this.noun = noun;
774
+ this.reason = reason;
775
+ }
776
+ };
777
+ async function writeOne(write, options) {
778
+ const { data, error } = await write;
779
+ if (error) throw error;
780
+ if (Array.isArray(data) && data.length > 0) return data[0];
781
+ if (options.alreadyDone) {
782
+ const current = await options.alreadyDone.reread();
783
+ if (current.error) throw current.error;
784
+ const row = Array.isArray(current.data) ? current.data[0] : current.data;
785
+ if (row && options.alreadyDone.isDone(row)) return row;
786
+ }
787
+ throw new WriteDidNotLandError(options, options.compareAndSet ? "taken" : "refused");
788
+ }
789
+ async function tryWriteOne(write, options) {
790
+ try {
791
+ return { row: await writeOne(write, options), error: null };
792
+ } catch (caught) {
793
+ if (caught instanceof Error) return { row: null, error: caught };
794
+ if (caught && typeof caught === "object" && "code" in caught && typeof caught.code === "string" && "message" in caught && typeof caught.message === "string") {
795
+ return { row: null, error: new PostgrestError({
796
+ code: caught.code,
797
+ message: caught.message,
798
+ details: "details" in caught && typeof caught.details === "string" ? caught.details : "",
799
+ hint: "hint" in caught && typeof caught.hint === "string" ? caught.hint : ""
800
+ }) };
801
+ }
802
+ const message = caught && typeof caught === "object" && "message" in caught && typeof caught.message === "string" ? caught.message : String(caught);
803
+ const error = new Error(message);
804
+ error.cause = caught;
805
+ return { row: null, error };
806
+ }
807
+ }
808
+ function writeFailureStatus(error) {
809
+ if (error instanceof WriteDidNotLandError) return error.status;
810
+ if (error && typeof error === "object" && "code" in error) {
811
+ if (error.code === "42501") return 403;
812
+ if (error.code === "PGRST301" || error.code === "PGRST302" || error.code === "PGRST303") return 401;
813
+ if (error.code === "PGRST116") return 404;
814
+ if (error.code === "23505" || error.code === "40001" || error.code === "40P01") return 409;
815
+ }
816
+ return 500;
817
+ }
818
+ var BulkWriteError = class extends Error {
819
+ failures;
820
+ attempted;
821
+ constructor(failures, attempted) {
822
+ super(
823
+ `${failures.length} of ${attempted} ${attempted === 1 ? "change was" : "changes were"} not saved. ${failures[0]?.message ?? ""}`.trim()
824
+ );
825
+ this.name = "BulkWriteError";
826
+ this.failures = failures;
827
+ this.attempted = attempted;
828
+ }
829
+ };
830
+ async function writeOneRow(write, options) {
831
+ const { data, error } = await write;
832
+ if (error) {
833
+ if (error instanceof PostgrestError) return { data: null, error };
834
+ const e = error;
835
+ return {
836
+ data: null,
837
+ error: new PostgrestError({
838
+ message: typeof e.message === "string" ? e.message : String(error),
839
+ details: typeof e.details === "string" ? e.details : "",
840
+ hint: typeof e.hint === "string" ? e.hint : "",
841
+ code: typeof e.code === "string" ? e.code : ""
842
+ })
843
+ };
844
+ }
845
+ const rows = Array.isArray(data) ? data : [];
846
+ if (rows.length === 1) return { data: rows[0], error: null };
847
+ const refusal = new WriteDidNotLandError(options, options.compareAndSet ? "taken" : "refused");
848
+ return {
849
+ data: null,
850
+ error: new PostgrestError({
851
+ message: rows.length === 0 ? refusal.serverMessage ?? refusal.message : `${rows.length} records matched where one ${options.noun} was expected, and all of them were changed. Reload to see the result.`,
852
+ details: rows.length === 0 ? refusal.technical : `writeOneRow(${options.action} ${options.noun}) matched ${rows.length} rows`,
853
+ hint: "",
854
+ code: "PGRST116"
855
+ })
856
+ };
857
+ }
631
858
  export {
859
+ BulkWriteError,
632
860
  DEFAULT_ACTIVE_ORG_COOKIE_MAX_AGE,
633
861
  DEFAULT_ACTIVE_ORG_COOKIE_NAME,
634
862
  DEFAULT_AUTH_COOKIE_NAME,
635
863
  IncompleteReadError,
636
864
  SessionUnavailableError,
865
+ WriteDidNotLandError,
866
+ WriteRefusedError,
637
867
  asJsonObject,
868
+ assertWriteLanded,
638
869
  createActiveOrgCookie,
639
870
  createAuthCookie,
640
871
  createOAuthRefreshFetch,
641
872
  createSessionRetry,
642
873
  decodeActiveOrgSelection,
643
874
  decodeOAuthRefreshClaims,
875
+ describeWriteFailure,
644
876
  encodeActiveOrgSelection,
645
877
  guardedUpdate,
646
878
  isMissingSessionError,
647
879
  mergeJsonColumn,
648
880
  parseCookieHeader,
881
+ personSentence,
649
882
  readAllRows,
650
883
  readAllRowsRest,
884
+ serverMessageFromBody,
651
885
  tryReadAllRows,
652
886
  tryReadAllRowsRest,
653
- uniqueChannelTopic
887
+ tryWriteOne,
888
+ uniqueChannelTopic,
889
+ writeFailureStatus,
890
+ writeOne,
891
+ writeOneRow
654
892
  };
655
893
  //# sourceMappingURL=db.js.map