@ai-matrx/data 0.18.33 → 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.d.cts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { MaybeSingleResponse } from './index.cjs';
2
2
  export { a as AuthCookie, b as AuthCookieOptions, A as AuthCookieValue, C as CreateAuthCookieArgs, D as DEFAULT_AUTH_COOKIE_NAME, R as ReconciledAuthCookies, c as createAuthCookie, p as parseCookieHeader } from './auth-cookie-BpgVyFw9.cjs';
3
3
  export { uniqueChannelTopic } from '@ai-matrx/realtime';
4
+ import { PostgrestError } from '@supabase/supabase-js';
4
5
  import './credentials-B-rePKU7.cjs';
5
6
  import './net.cjs';
6
7
 
@@ -561,4 +562,203 @@ declare function decodeOAuthRefreshClaims(token: string): JwtClaims | null;
561
562
  */
562
563
  declare function createOAuthRefreshFetch(args: CreateOAuthRefreshFetchArgs): typeof globalThis.fetch;
563
564
 
564
- export { type ActiveOrgCookie, type ActiveOrgCookieOptions, type ActiveOrgSelection, type AuthRetryableResult, type CreateActiveOrgCookieArgs, type CreateOAuthRefreshFetchArgs, type CreateSessionRetryOptions, DEFAULT_ACTIVE_ORG_COOKIE_MAX_AGE, DEFAULT_ACTIVE_ORG_COOKIE_NAME, type GuardedUpdateArgs, type GuardedUpdateResult, IncompleteReadError, type JsonObject, type MergeJsonColumnArgs, type MergeJsonColumnResult, type OAuthRefreshStorage, type PagedReadQuery, type PagedReadResult, type ReadAllRowsOptions, type ReadAllRowsRestOptions, type SessionSource, SessionUnavailableError, type VersionedRow, asJsonObject, createActiveOrgCookie, createOAuthRefreshFetch, createSessionRetry, decodeActiveOrgSelection, decodeOAuthRefreshClaims, encodeActiveOrgSelection, guardedUpdate, isMissingSessionError, mergeJsonColumn, readAllRows, readAllRowsRest, tryReadAllRows, tryReadAllRowsRest };
565
+ /** A non-2xx answer from a server, with the words already chosen. */
566
+ declare class WriteRefusedError extends Error {
567
+ readonly status: number;
568
+ /** What the server said for a person, when it said something a person can read. */
569
+ readonly serverMessage: string | null;
570
+ /** The developer line (method, path, status, body) — for diagnostics, never for the screen. */
571
+ readonly technical: string;
572
+ constructor(args: {
573
+ status: number;
574
+ serverMessage?: string | null;
575
+ technical: string;
576
+ });
577
+ }
578
+ /** Pull a human sentence out of a FastAPI-style error body, or null when there is none. */
579
+ declare function serverMessageFromBody(body: unknown): string | null;
580
+ /**
581
+ * THE STORE'S OWN WORDS, WHEN IT SAID SOME (lane HANDOVER, 2026-09-27). A door that refuses raises a
582
+ * sentence for a person — `You can see this record, but "Allergies" is not yours to change.` — or the
583
+ * same sentence behind its own name (`cat_write: this category is not yours to change.`). Postgres's
584
+ * native refusals (`permission denied for table …`, `new row violates …`) are never that. This hands
585
+ * back the door's sentence, capitalised and ended, or null when the text is not a person's words.
586
+ * test@test.com's refused Allergies edit read "Permission denied" because the scopes mapper threw
587
+ * the door's sentence away for a fixed string.
588
+ */
589
+ declare function personSentence(text: unknown): string | null;
590
+ /**
591
+ * A direct Supabase write that matched no row answers WITHOUT an error (RLS filters the row out,
592
+ * or it is gone), so the screen would say "saved" over nothing. Pass the `.select()` rows of an
593
+ * update/upsert: zero rows is a refusal, said in words.
594
+ */
595
+ declare function assertWriteLanded<T>(rows: T[] | T | null | undefined, technical: string): void;
596
+ interface WriteFailureWords {
597
+ /** "Could not pause this schedule." */
598
+ title: string;
599
+ /** Why, in words, then the remedy. */
600
+ description: string;
601
+ }
602
+ /**
603
+ * The words for a failed write. `action` completes "Could not …" ("pause this schedule");
604
+ * `remedy` is what to do next ("Try again or open the schedule's activity.").
605
+ */
606
+ declare function describeWriteFailure(err: unknown, { action, remedy }: {
607
+ action: string;
608
+ remedy?: string;
609
+ }): WriteFailureWords;
610
+
611
+ /**
612
+ * @ai-matrx/data/db — writeOne: THE single-record write that PROVES it landed.
613
+ *
614
+ * Ported verbatim from matrx-frontend `utils/supabase/writeOne.ts` (which now
615
+ * re-exports this module, so `WriteDidNotLandError` is ONE class everywhere).
616
+ *
617
+ * THE CLASS (flashcards, 2026-09-25). PostgREST answers an `.update()` or
618
+ * `.delete()` that row-level security filters to zero rows with
619
+ * `{ data: [], error: null }` — status 200, no error. A caller that judges
620
+ * success by `error == null` therefore tells the person "Card deleted" while
621
+ * nothing happened. The same is true when the row is already gone. Nothing
622
+ * fails silently: zero rows written is a refusal, and it is said in words.
623
+ *
624
+ * USE IT for every write aimed at ONE record (`.eq("id", …)`):
625
+ *
626
+ * await writeOne(
627
+ * supabase.from("notes").update({ label }).eq("id", noteId).select("id"),
628
+ * { action: "rename", noun: "note" },
629
+ * );
630
+ *
631
+ * - The builder MUST end in `.select(...)` — that is what makes PostgREST
632
+ * return the rows it actually wrote. Select only what you need (`"id"` is
633
+ * fine); the first written row is returned.
634
+ * - A database error is thrown AS IS (the PostgrestError), so existing error
635
+ * handling and `describeWriteFailure` keep working.
636
+ * - Zero rows throws `WriteDidNotLandError` — a `WriteRefusedError` whose
637
+ * message is already a sentence for a person:
638
+ * "Nothing was deleted: this card no longer exists, or your access does not
639
+ * allow deleting it."
640
+ * - `tryWriteOne` is the same check for result-style services that never
641
+ * throw: it returns `{ row, error }`.
642
+ *
643
+ * TWO MODES for writes that carry an extra condition (coordinator ruling,
644
+ * 2026-09-25):
645
+ *
646
+ * - IDEMPOTENT (`alreadyDone`): an archive filtered `.is("deleted_at", null)`
647
+ * writes zero rows when the record is ALREADY archived — and also when RLS
648
+ * refused. On zero rows the primitive re-reads the row by id: visible and
649
+ * already in the target state → success (the re-read row is returned);
650
+ * invisible or still live → the plain refusal.
651
+ *
652
+ * - COMPARE-AND-SET (`compareAndSet: true`): `.eq("status", "pending")`,
653
+ * `.is("answered_at", null)`… zero rows means someone else got there first.
654
+ * That is still told to the person: "This answer was already handled —
655
+ * refresh to see the latest." (`WriteDidNotLandError.reason === "taken"`).
656
+ *
657
+ * Optimistic-concurrency edits with a `version` token use `guardedUpdate`
658
+ * from `@ai-matrx/data/db`, which classifies zero rows as conflict or gone.
659
+ * A bulk `.in(...)` write is not a single-record write.
660
+ *
661
+ * Guard: `pnpm check:single-record-writes` (scripts/check-single-record-writes.ts)
662
+ * fails on a new single-record update/delete that judges success by error alone.
663
+ */
664
+
665
+ /** The verb the person asked for. Drives the refusal sentence. */
666
+ type WriteOneAction = "save" | "update" | "rename" | "move" | "delete" | "remove" | "archive" | "restore" | "publish" | "unpublish" | "change";
667
+ interface WriteOneOptions<Row = unknown> {
668
+ /** What the person asked for: "delete", "save", "archive"… */
669
+ action: WriteOneAction;
670
+ /** What it is, in the person's words: "card", "note", "saved view". */
671
+ noun: string;
672
+ /**
673
+ * Idempotent mode. On zero rows, `reread()` the record by id (end it in
674
+ * `.maybeSingle()`); when it is visible and `isDone(row)`, the write is a
675
+ * success and that row is returned. Otherwise the plain refusal.
676
+ */
677
+ alreadyDone?: {
678
+ reread: () => PromiseLike<{
679
+ data: Row | null;
680
+ error: unknown;
681
+ }>;
682
+ isDone: (row: Row) => boolean;
683
+ };
684
+ /** Compare-and-set mode: zero rows means someone else got there first. */
685
+ compareAndSet?: boolean;
686
+ }
687
+ /** Why nothing was written: refused/gone, or another writer took it first. */
688
+ type WriteDidNotLandReason = "refused" | "taken";
689
+ /** Zero rows were written: the record is gone, or the person may not change it. */
690
+ declare class WriteDidNotLandError extends WriteRefusedError {
691
+ readonly action: WriteOneAction;
692
+ readonly noun: string;
693
+ readonly reason: WriteDidNotLandReason;
694
+ constructor({ action, noun }: Pick<WriteOneOptions, "action" | "noun">, reason?: WriteDidNotLandReason);
695
+ }
696
+ /** Structural shape of an awaited supabase-js builder that ended in `.select()`. */
697
+ interface RowsResponse<Row> {
698
+ data: Row[] | null;
699
+ error: unknown;
700
+ }
701
+ /**
702
+ * Run a single-record write and prove it landed. Returns the first written
703
+ * row; throws the database error as is, or `WriteDidNotLandError` on zero rows.
704
+ */
705
+ declare function writeOne<Row>(write: PromiseLike<RowsResponse<Row>>, options: WriteOneOptions<Row>): Promise<Row>;
706
+ type TryWriteOneResult<Row> = {
707
+ row: Row;
708
+ error: null;
709
+ } | {
710
+ row: null;
711
+ error: Error;
712
+ };
713
+ /** `writeOne` for services that return results instead of throwing. */
714
+ declare function tryWriteOne<Row>(write: PromiseLike<RowsResponse<Row>>, options: WriteOneOptions<Row>): Promise<TryWriteOneResult<Row>>;
715
+ /**
716
+ * The HTTP status a route handler answers with for a failed write: the
717
+ * refusal's own status (403 refused / 409 taken) for `WriteDidNotLandError`,
718
+ * Database authorization/not-found/conflict codes retain their HTTP meaning;
719
+ * unknown failures remain 500. Server twin of the client's toast path.
720
+ */
721
+ declare function writeFailureStatus(error: unknown): number;
722
+ /**
723
+ * Several single-record writes where some did not land. The message names how
724
+ * many of how many failed and why (the first reason); `failures` keeps each
725
+ * record id with its own sentence so a screen can mark exactly those rows.
726
+ */
727
+ declare class BulkWriteError extends Error {
728
+ readonly failures: {
729
+ id: string;
730
+ message: string;
731
+ }[];
732
+ readonly attempted: number;
733
+ constructor(failures: {
734
+ id: string;
735
+ message: string;
736
+ }[], attempted: number);
737
+ }
738
+ type WriteOneRowResult<Row> = {
739
+ data: Row;
740
+ error: null;
741
+ } | {
742
+ data: null;
743
+ error: PostgrestError;
744
+ };
745
+ /**
746
+ * The drop-in for `.update(…).eq("id", …).select(…).single()` (and the
747
+ * `.maybeSingle()` twin whose caller never looks at `data`): same
748
+ * `{ data, error }` shape, same `PostgrestError` type, same `PGRST116` code on
749
+ * zero rows — but the message is the person's sentence ("Nothing was updated:
750
+ * this deal no longer exists, or your access does not allow updating it.")
751
+ * instead of PostgREST's "JSON object requested, multiple (or no) rows
752
+ * returned", which every screen rendered as a vague failure.
753
+ *
754
+ * const { data, error } = await writeOneRow(
755
+ * db.from("deal").update(patch).eq("id", id).select("*"),
756
+ * { action: "update", noun: "deal" },
757
+ * );
758
+ *
759
+ * Guard: `pnpm check:single-record-writes` flags the bare `.select().single()`
760
+ * shape on a write.
761
+ */
762
+ declare function writeOneRow<Row>(write: PromiseLike<RowsResponse<Row>>, options: Pick<WriteOneOptions, "action" | "noun" | "compareAndSet">): Promise<WriteOneRowResult<Row>>;
763
+
764
+ export { type ActiveOrgCookie, type ActiveOrgCookieOptions, type ActiveOrgSelection, type AuthRetryableResult, BulkWriteError, type CreateActiveOrgCookieArgs, type CreateOAuthRefreshFetchArgs, type CreateSessionRetryOptions, DEFAULT_ACTIVE_ORG_COOKIE_MAX_AGE, DEFAULT_ACTIVE_ORG_COOKIE_NAME, type GuardedUpdateArgs, type GuardedUpdateResult, IncompleteReadError, type JsonObject, type MergeJsonColumnArgs, type MergeJsonColumnResult, type OAuthRefreshStorage, type PagedReadQuery, type PagedReadResult, type ReadAllRowsOptions, type ReadAllRowsRestOptions, type SessionSource, SessionUnavailableError, type TryWriteOneResult, type VersionedRow, WriteDidNotLandError, type WriteDidNotLandReason, type WriteFailureWords, type WriteOneAction, type WriteOneOptions, type WriteOneRowResult, WriteRefusedError, asJsonObject, assertWriteLanded, createActiveOrgCookie, createOAuthRefreshFetch, createSessionRetry, decodeActiveOrgSelection, decodeOAuthRefreshClaims, describeWriteFailure, encodeActiveOrgSelection, guardedUpdate, isMissingSessionError, mergeJsonColumn, personSentence, readAllRows, readAllRowsRest, serverMessageFromBody, tryReadAllRows, tryReadAllRowsRest, tryWriteOne, writeFailureStatus, writeOne, writeOneRow };
package/dist/db.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { MaybeSingleResponse } from './index.js';
2
2
  export { a as AuthCookie, b as AuthCookieOptions, A as AuthCookieValue, C as CreateAuthCookieArgs, D as DEFAULT_AUTH_COOKIE_NAME, R as ReconciledAuthCookies, c as createAuthCookie, p as parseCookieHeader } from './auth-cookie-BpgVyFw9.js';
3
3
  export { uniqueChannelTopic } from '@ai-matrx/realtime';
4
+ import { PostgrestError } from '@supabase/supabase-js';
4
5
  import './credentials-B-rePKU7.js';
5
6
  import './net.js';
6
7
 
@@ -561,4 +562,203 @@ declare function decodeOAuthRefreshClaims(token: string): JwtClaims | null;
561
562
  */
562
563
  declare function createOAuthRefreshFetch(args: CreateOAuthRefreshFetchArgs): typeof globalThis.fetch;
563
564
 
564
- export { type ActiveOrgCookie, type ActiveOrgCookieOptions, type ActiveOrgSelection, type AuthRetryableResult, type CreateActiveOrgCookieArgs, type CreateOAuthRefreshFetchArgs, type CreateSessionRetryOptions, DEFAULT_ACTIVE_ORG_COOKIE_MAX_AGE, DEFAULT_ACTIVE_ORG_COOKIE_NAME, type GuardedUpdateArgs, type GuardedUpdateResult, IncompleteReadError, type JsonObject, type MergeJsonColumnArgs, type MergeJsonColumnResult, type OAuthRefreshStorage, type PagedReadQuery, type PagedReadResult, type ReadAllRowsOptions, type ReadAllRowsRestOptions, type SessionSource, SessionUnavailableError, type VersionedRow, asJsonObject, createActiveOrgCookie, createOAuthRefreshFetch, createSessionRetry, decodeActiveOrgSelection, decodeOAuthRefreshClaims, encodeActiveOrgSelection, guardedUpdate, isMissingSessionError, mergeJsonColumn, readAllRows, readAllRowsRest, tryReadAllRows, tryReadAllRowsRest };
565
+ /** A non-2xx answer from a server, with the words already chosen. */
566
+ declare class WriteRefusedError extends Error {
567
+ readonly status: number;
568
+ /** What the server said for a person, when it said something a person can read. */
569
+ readonly serverMessage: string | null;
570
+ /** The developer line (method, path, status, body) — for diagnostics, never for the screen. */
571
+ readonly technical: string;
572
+ constructor(args: {
573
+ status: number;
574
+ serverMessage?: string | null;
575
+ technical: string;
576
+ });
577
+ }
578
+ /** Pull a human sentence out of a FastAPI-style error body, or null when there is none. */
579
+ declare function serverMessageFromBody(body: unknown): string | null;
580
+ /**
581
+ * THE STORE'S OWN WORDS, WHEN IT SAID SOME (lane HANDOVER, 2026-09-27). A door that refuses raises a
582
+ * sentence for a person — `You can see this record, but "Allergies" is not yours to change.` — or the
583
+ * same sentence behind its own name (`cat_write: this category is not yours to change.`). Postgres's
584
+ * native refusals (`permission denied for table …`, `new row violates …`) are never that. This hands
585
+ * back the door's sentence, capitalised and ended, or null when the text is not a person's words.
586
+ * test@test.com's refused Allergies edit read "Permission denied" because the scopes mapper threw
587
+ * the door's sentence away for a fixed string.
588
+ */
589
+ declare function personSentence(text: unknown): string | null;
590
+ /**
591
+ * A direct Supabase write that matched no row answers WITHOUT an error (RLS filters the row out,
592
+ * or it is gone), so the screen would say "saved" over nothing. Pass the `.select()` rows of an
593
+ * update/upsert: zero rows is a refusal, said in words.
594
+ */
595
+ declare function assertWriteLanded<T>(rows: T[] | T | null | undefined, technical: string): void;
596
+ interface WriteFailureWords {
597
+ /** "Could not pause this schedule." */
598
+ title: string;
599
+ /** Why, in words, then the remedy. */
600
+ description: string;
601
+ }
602
+ /**
603
+ * The words for a failed write. `action` completes "Could not …" ("pause this schedule");
604
+ * `remedy` is what to do next ("Try again or open the schedule's activity.").
605
+ */
606
+ declare function describeWriteFailure(err: unknown, { action, remedy }: {
607
+ action: string;
608
+ remedy?: string;
609
+ }): WriteFailureWords;
610
+
611
+ /**
612
+ * @ai-matrx/data/db — writeOne: THE single-record write that PROVES it landed.
613
+ *
614
+ * Ported verbatim from matrx-frontend `utils/supabase/writeOne.ts` (which now
615
+ * re-exports this module, so `WriteDidNotLandError` is ONE class everywhere).
616
+ *
617
+ * THE CLASS (flashcards, 2026-09-25). PostgREST answers an `.update()` or
618
+ * `.delete()` that row-level security filters to zero rows with
619
+ * `{ data: [], error: null }` — status 200, no error. A caller that judges
620
+ * success by `error == null` therefore tells the person "Card deleted" while
621
+ * nothing happened. The same is true when the row is already gone. Nothing
622
+ * fails silently: zero rows written is a refusal, and it is said in words.
623
+ *
624
+ * USE IT for every write aimed at ONE record (`.eq("id", …)`):
625
+ *
626
+ * await writeOne(
627
+ * supabase.from("notes").update({ label }).eq("id", noteId).select("id"),
628
+ * { action: "rename", noun: "note" },
629
+ * );
630
+ *
631
+ * - The builder MUST end in `.select(...)` — that is what makes PostgREST
632
+ * return the rows it actually wrote. Select only what you need (`"id"` is
633
+ * fine); the first written row is returned.
634
+ * - A database error is thrown AS IS (the PostgrestError), so existing error
635
+ * handling and `describeWriteFailure` keep working.
636
+ * - Zero rows throws `WriteDidNotLandError` — a `WriteRefusedError` whose
637
+ * message is already a sentence for a person:
638
+ * "Nothing was deleted: this card no longer exists, or your access does not
639
+ * allow deleting it."
640
+ * - `tryWriteOne` is the same check for result-style services that never
641
+ * throw: it returns `{ row, error }`.
642
+ *
643
+ * TWO MODES for writes that carry an extra condition (coordinator ruling,
644
+ * 2026-09-25):
645
+ *
646
+ * - IDEMPOTENT (`alreadyDone`): an archive filtered `.is("deleted_at", null)`
647
+ * writes zero rows when the record is ALREADY archived — and also when RLS
648
+ * refused. On zero rows the primitive re-reads the row by id: visible and
649
+ * already in the target state → success (the re-read row is returned);
650
+ * invisible or still live → the plain refusal.
651
+ *
652
+ * - COMPARE-AND-SET (`compareAndSet: true`): `.eq("status", "pending")`,
653
+ * `.is("answered_at", null)`… zero rows means someone else got there first.
654
+ * That is still told to the person: "This answer was already handled —
655
+ * refresh to see the latest." (`WriteDidNotLandError.reason === "taken"`).
656
+ *
657
+ * Optimistic-concurrency edits with a `version` token use `guardedUpdate`
658
+ * from `@ai-matrx/data/db`, which classifies zero rows as conflict or gone.
659
+ * A bulk `.in(...)` write is not a single-record write.
660
+ *
661
+ * Guard: `pnpm check:single-record-writes` (scripts/check-single-record-writes.ts)
662
+ * fails on a new single-record update/delete that judges success by error alone.
663
+ */
664
+
665
+ /** The verb the person asked for. Drives the refusal sentence. */
666
+ type WriteOneAction = "save" | "update" | "rename" | "move" | "delete" | "remove" | "archive" | "restore" | "publish" | "unpublish" | "change";
667
+ interface WriteOneOptions<Row = unknown> {
668
+ /** What the person asked for: "delete", "save", "archive"… */
669
+ action: WriteOneAction;
670
+ /** What it is, in the person's words: "card", "note", "saved view". */
671
+ noun: string;
672
+ /**
673
+ * Idempotent mode. On zero rows, `reread()` the record by id (end it in
674
+ * `.maybeSingle()`); when it is visible and `isDone(row)`, the write is a
675
+ * success and that row is returned. Otherwise the plain refusal.
676
+ */
677
+ alreadyDone?: {
678
+ reread: () => PromiseLike<{
679
+ data: Row | null;
680
+ error: unknown;
681
+ }>;
682
+ isDone: (row: Row) => boolean;
683
+ };
684
+ /** Compare-and-set mode: zero rows means someone else got there first. */
685
+ compareAndSet?: boolean;
686
+ }
687
+ /** Why nothing was written: refused/gone, or another writer took it first. */
688
+ type WriteDidNotLandReason = "refused" | "taken";
689
+ /** Zero rows were written: the record is gone, or the person may not change it. */
690
+ declare class WriteDidNotLandError extends WriteRefusedError {
691
+ readonly action: WriteOneAction;
692
+ readonly noun: string;
693
+ readonly reason: WriteDidNotLandReason;
694
+ constructor({ action, noun }: Pick<WriteOneOptions, "action" | "noun">, reason?: WriteDidNotLandReason);
695
+ }
696
+ /** Structural shape of an awaited supabase-js builder that ended in `.select()`. */
697
+ interface RowsResponse<Row> {
698
+ data: Row[] | null;
699
+ error: unknown;
700
+ }
701
+ /**
702
+ * Run a single-record write and prove it landed. Returns the first written
703
+ * row; throws the database error as is, or `WriteDidNotLandError` on zero rows.
704
+ */
705
+ declare function writeOne<Row>(write: PromiseLike<RowsResponse<Row>>, options: WriteOneOptions<Row>): Promise<Row>;
706
+ type TryWriteOneResult<Row> = {
707
+ row: Row;
708
+ error: null;
709
+ } | {
710
+ row: null;
711
+ error: Error;
712
+ };
713
+ /** `writeOne` for services that return results instead of throwing. */
714
+ declare function tryWriteOne<Row>(write: PromiseLike<RowsResponse<Row>>, options: WriteOneOptions<Row>): Promise<TryWriteOneResult<Row>>;
715
+ /**
716
+ * The HTTP status a route handler answers with for a failed write: the
717
+ * refusal's own status (403 refused / 409 taken) for `WriteDidNotLandError`,
718
+ * Database authorization/not-found/conflict codes retain their HTTP meaning;
719
+ * unknown failures remain 500. Server twin of the client's toast path.
720
+ */
721
+ declare function writeFailureStatus(error: unknown): number;
722
+ /**
723
+ * Several single-record writes where some did not land. The message names how
724
+ * many of how many failed and why (the first reason); `failures` keeps each
725
+ * record id with its own sentence so a screen can mark exactly those rows.
726
+ */
727
+ declare class BulkWriteError extends Error {
728
+ readonly failures: {
729
+ id: string;
730
+ message: string;
731
+ }[];
732
+ readonly attempted: number;
733
+ constructor(failures: {
734
+ id: string;
735
+ message: string;
736
+ }[], attempted: number);
737
+ }
738
+ type WriteOneRowResult<Row> = {
739
+ data: Row;
740
+ error: null;
741
+ } | {
742
+ data: null;
743
+ error: PostgrestError;
744
+ };
745
+ /**
746
+ * The drop-in for `.update(…).eq("id", …).select(…).single()` (and the
747
+ * `.maybeSingle()` twin whose caller never looks at `data`): same
748
+ * `{ data, error }` shape, same `PostgrestError` type, same `PGRST116` code on
749
+ * zero rows — but the message is the person's sentence ("Nothing was updated:
750
+ * this deal no longer exists, or your access does not allow updating it.")
751
+ * instead of PostgREST's "JSON object requested, multiple (or no) rows
752
+ * returned", which every screen rendered as a vague failure.
753
+ *
754
+ * const { data, error } = await writeOneRow(
755
+ * db.from("deal").update(patch).eq("id", id).select("*"),
756
+ * { action: "update", noun: "deal" },
757
+ * );
758
+ *
759
+ * Guard: `pnpm check:single-record-writes` flags the bare `.select().single()`
760
+ * shape on a write.
761
+ */
762
+ declare function writeOneRow<Row>(write: PromiseLike<RowsResponse<Row>>, options: Pick<WriteOneOptions, "action" | "noun" | "compareAndSet">): Promise<WriteOneRowResult<Row>>;
763
+
764
+ export { type ActiveOrgCookie, type ActiveOrgCookieOptions, type ActiveOrgSelection, type AuthRetryableResult, BulkWriteError, type CreateActiveOrgCookieArgs, type CreateOAuthRefreshFetchArgs, type CreateSessionRetryOptions, DEFAULT_ACTIVE_ORG_COOKIE_MAX_AGE, DEFAULT_ACTIVE_ORG_COOKIE_NAME, type GuardedUpdateArgs, type GuardedUpdateResult, IncompleteReadError, type JsonObject, type MergeJsonColumnArgs, type MergeJsonColumnResult, type OAuthRefreshStorage, type PagedReadQuery, type PagedReadResult, type ReadAllRowsOptions, type ReadAllRowsRestOptions, type SessionSource, SessionUnavailableError, type TryWriteOneResult, type VersionedRow, WriteDidNotLandError, type WriteDidNotLandReason, type WriteFailureWords, type WriteOneAction, type WriteOneOptions, type WriteOneRowResult, WriteRefusedError, asJsonObject, assertWriteLanded, createActiveOrgCookie, createOAuthRefreshFetch, createSessionRetry, decodeActiveOrgSelection, decodeOAuthRefreshClaims, describeWriteFailure, encodeActiveOrgSelection, guardedUpdate, isMissingSessionError, mergeJsonColumn, personSentence, readAllRows, readAllRowsRest, serverMessageFromBody, tryReadAllRows, tryReadAllRowsRest, tryWriteOne, writeFailureStatus, writeOne, writeOneRow };