better-supabase 0.0.0 → 0.1.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/LICENSE +21 -0
- package/README.md +88 -1
- package/bin/better-supabase.js +3 -0
- package/dist/casing-da0uRTqt.js +14 -0
- package/dist/cli/bin.d.ts +1 -0
- package/dist/cli/bin.js +15 -0
- package/dist/cli/index.d.ts +226 -0
- package/dist/cli/index.js +3 -0
- package/dist/cli-CoByWYja.js +6472 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.js +112 -0
- package/dist/compiler-DL18ukPe.d.ts +14 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.js +3 -0
- package/dist/config-D-aR2ZoN.js +276 -0
- package/dist/define-CTfWw-SS.d.ts +662 -0
- package/dist/define-QGkq04oe.js +1068 -0
- package/dist/edge/index.d.ts +43 -0
- package/dist/edge/index.js +103 -0
- package/dist/entitlements-BBg61DQZ.d.ts +20 -0
- package/dist/entitlements-BC_khwRy.js +17 -0
- package/dist/env/index.d.ts +2 -0
- package/dist/env/index.js +2 -0
- package/dist/env-BEToab0I.js +204 -0
- package/dist/errors-Bl3rkOzo.js +196 -0
- package/dist/events/index.d.ts +2 -0
- package/dist/events/index.js +2 -0
- package/dist/events-2OJsVG_d.d.ts +84 -0
- package/dist/events-BuzTgn2D.js +135 -0
- package/dist/executor-Bazhgsgq.d.ts +195 -0
- package/dist/executor-Bje4suQF.d.ts +25 -0
- package/dist/executor-Ceq60hPM.js +89 -0
- package/dist/hono/index.d.ts +45 -0
- package/dist/hono/index.js +70 -0
- package/dist/index-BD6wKthp.d.ts +597 -0
- package/dist/index-DQVvHzjW.d.ts +74 -0
- package/dist/index-DRid0qIv.d.ts +76 -0
- package/dist/index-Dup-nSe9.d.ts +117 -0
- package/dist/index-Dy6kuF0P.d.ts +71 -0
- package/dist/index-Hf8PP9sP.d.ts +116 -0
- package/dist/index-JXHBuS53.d.ts +144 -0
- package/dist/index-Nxo3TJcm.d.ts +208 -0
- package/dist/index-Sw43J8HG.d.ts +62 -0
- package/dist/index-cEeweTeM.d.ts +38 -0
- package/dist/index.d.ts +110 -0
- package/dist/index.js +42 -0
- package/dist/invalidate-DbxuL2jL.js +18 -0
- package/dist/jobs/index.d.ts +173 -0
- package/dist/jobs/index.js +477 -0
- package/dist/json-schema-BbwO2mZg.js +181 -0
- package/dist/lint/index.d.ts +75 -0
- package/dist/lint/index.js +167 -0
- package/dist/list/index.d.ts +2 -0
- package/dist/list/index.js +410 -0
- package/dist/live-6b9i72Ux.d.ts +180 -0
- package/dist/live-D8rV1Ldw.js +168 -0
- package/dist/mcp/index.d.ts +105 -0
- package/dist/mcp/index.js +330 -0
- package/dist/mfa-CpogP66z.js +521 -0
- package/dist/mfa-TVia554c.d.ts +44 -0
- package/dist/next/image/index.d.ts +34 -0
- package/dist/next/image/index.js +40 -0
- package/dist/next/index.d.ts +210 -0
- package/dist/next/index.js +426 -0
- package/dist/openapi/index.d.ts +2 -0
- package/dist/openapi/index.js +332 -0
- package/dist/orpc/index.d.ts +46 -0
- package/dist/orpc/index.js +50 -0
- package/dist/otel/index.d.ts +40 -0
- package/dist/otel/index.js +168 -0
- package/dist/path-Cv__-OTj.d.ts +17 -0
- package/dist/plugin-BqR6wKMB.js +23 -0
- package/dist/plugin-HvGqCurB.d.ts +118 -0
- package/dist/plugins/actor/index.d.ts +13 -0
- package/dist/plugins/actor/index.js +43 -0
- package/dist/plugins/rules/index.d.ts +88 -0
- package/dist/plugins/rules/index.js +174 -0
- package/dist/plugins/soft-delete/index.d.ts +38 -0
- package/dist/plugins/soft-delete/index.js +69 -0
- package/dist/plugins/tenant/index.d.ts +43 -0
- package/dist/plugins/tenant/index.js +73 -0
- package/dist/plugins/timestamps/index.d.ts +9 -0
- package/dist/plugins/timestamps/index.js +37 -0
- package/dist/plugins/validation/index.d.ts +24 -0
- package/dist/plugins/validation/index.js +59 -0
- package/dist/pool-BFeqzwQS.d.ts +37 -0
- package/dist/postgres/index.d.ts +28 -0
- package/dist/postgres/index.js +79 -0
- package/dist/postgrest-Dm-vhY6R.d.ts +43 -0
- package/dist/problem-DPu6Fh-t.js +97 -0
- package/dist/problem-DlgB0lYl.d.ts +47 -0
- package/dist/query/index.d.ts +2 -0
- package/dist/query/index.js +3 -0
- package/dist/query-ChvDbsDE.js +186 -0
- package/dist/react/index.d.ts +7 -0
- package/dist/react/index.js +5 -0
- package/dist/react/server.d.ts +13 -0
- package/dist/react/server.js +25 -0
- package/dist/react/session.d.ts +2 -0
- package/dist/react/session.js +3 -0
- package/dist/react-CrOvrnIP.js +241 -0
- package/dist/read-set-DhX2d04c.js +216 -0
- package/dist/realtime/index.d.ts +3 -0
- package/dist/realtime/index.js +253 -0
- package/dist/resolve-DW8h9NPm.d.ts +155 -0
- package/dist/resource-CYiu6Ygi.js +175 -0
- package/dist/resource-SkPTRJDD.d.ts +65 -0
- package/dist/respond-4-dhoV7x.js +380 -0
- package/dist/respond-PoTpy5DT.d.ts +169 -0
- package/dist/result-CTkCZ6JA.d.ts +198 -0
- package/dist/result-DWXatkd6.js +103 -0
- package/dist/scope-CDHcS7dE.js +90 -0
- package/dist/seed-CzecODcJ.js +101 -0
- package/dist/server/index.d.ts +42 -0
- package/dist/server/index.js +68 -0
- package/dist/session-C3osL21k.d.ts +21 -0
- package/dist/session-CD-3orO_.js +19 -0
- package/dist/shared-_6-uPL7E.js +57 -0
- package/dist/simplify-oHiDKRVQ.js +665 -0
- package/dist/spec-pins-CJPVghHy.d.ts +20 -0
- package/dist/spec-pins-t6sPaHvl.js +20 -0
- package/dist/sql-M8l3fnS0.js +260 -0
- package/dist/ssr/index.d.ts +5 -0
- package/dist/ssr/index.js +4 -0
- package/dist/standard-CyhRzctb.d.ts +7 -0
- package/dist/standard-FUi3Z3-7.js +21 -0
- package/dist/stats-3iy8u3_P.js +566 -0
- package/dist/storage/index.d.ts +4 -0
- package/dist/storage/index.js +2 -0
- package/dist/storage-BWXVUXGk.js +461 -0
- package/dist/tables-rZxRxNPW.js +59 -0
- package/dist/template-BeOGnynM.js +93 -0
- package/dist/template-mbvlysOo.d.ts +6 -0
- package/dist/testing/index.d.ts +294 -0
- package/dist/testing/index.js +751 -0
- package/dist/types-6cYK9pbJ.js +29 -0
- package/dist/types-C2fslP1z.d.ts +195 -0
- package/dist/version-Cqq1m3UY.js +4 -0
- package/dist/view-B0ltUmTi.d.ts +43 -0
- package/dist/view-B6F9QbG-.js +35 -0
- package/dist/webhooks/index.d.ts +152 -0
- package/dist/webhooks/index.js +2 -0
- package/dist/webhooks-DbMTJJX2.js +139 -0
- package/package.json +246 -17
- package/schemas/config-v1.json +328 -0
- package/schemas/doctor-report-v1.json +105 -0
- package/schemas/snapshot-v2.json +1002 -0
- package/skills/better-supabase/SKILL.md +84 -0
- package/skills/better-supabase/references/plugins.md +56 -0
- package/skills/better-supabase/references/troubleshooting.md +39 -0
- package/skills/better-supabase-api/SKILL.md +67 -0
- package/skills/better-supabase-api/references/adapters.md +108 -0
- package/skills/better-supabase-testing/SKILL.md +65 -0
- package/index.js +0 -1
|
@@ -0,0 +1,662 @@
|
|
|
1
|
+
import { A as TableMeta, C as Relations, D as Simplify, E as SchemaMeta, M as UniqueKeyName, N as UniqueWhere, P as Update, S as RelationShape, T as Schema, h as Insert, k as TableKey, n as AnyModels, t as AnyFunctions, w as Row, y as PrimaryKeyValue } from "./types-C2fslP1z.js";
|
|
2
|
+
import { g as Operation, l as CountMode, r as Executor } from "./executor-Bazhgsgq.js";
|
|
3
|
+
import { p as DbError, s as ThrowMapper, t as AsyncResult, v as ErrorMapper } from "./result-CTkCZ6JA.js";
|
|
4
|
+
import { a as EventHub, f as Logger, i as EventHandler, o as EventName, s as MutationNotice, u as RpcNotice } from "./events-2OJsVG_d.js";
|
|
5
|
+
import { a as ExtensionOf, g as WithExtension, h as RequestContext, n as AnyPlugin, r as ApplyExtension } from "./plugin-HvGqCurB.js";
|
|
6
|
+
import { t as StandardSchemaV1 } from "./standard-CyhRzctb.js";
|
|
7
|
+
import { i as PostgrestPlan } from "./postgrest-Dm-vhY6R.js";
|
|
8
|
+
//#region src/ir/args.d.ts
|
|
9
|
+
interface BaseOps<V> {
|
|
10
|
+
readonly eq?: V;
|
|
11
|
+
readonly neq?: V;
|
|
12
|
+
readonly in?: readonly NonNullable<V>[];
|
|
13
|
+
readonly notIn?: readonly NonNullable<V>[];
|
|
14
|
+
readonly isNull?: boolean;
|
|
15
|
+
readonly not?: FieldFilter<V>;
|
|
16
|
+
}
|
|
17
|
+
interface ComparableOps<V> {
|
|
18
|
+
readonly gt?: V;
|
|
19
|
+
readonly gte?: V;
|
|
20
|
+
readonly lt?: V;
|
|
21
|
+
readonly lte?: V;
|
|
22
|
+
}
|
|
23
|
+
interface TextOps {
|
|
24
|
+
/** SQL LIKE pattern. `%` and `_` are wildcards. */
|
|
25
|
+
readonly like?: string;
|
|
26
|
+
/** Case-insensitive LIKE pattern. */
|
|
27
|
+
readonly ilike?: string;
|
|
28
|
+
/** Case-insensitive substring match; wildcards in the value are escaped. */
|
|
29
|
+
readonly contains?: string;
|
|
30
|
+
readonly startsWith?: string;
|
|
31
|
+
readonly endsWith?: string;
|
|
32
|
+
/** Full-text search (`websearch_to_tsquery`). */
|
|
33
|
+
readonly search?: string | {
|
|
34
|
+
readonly query: string;
|
|
35
|
+
readonly config?: string;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
interface ArrayOps<E> {
|
|
39
|
+
/** The array contains every given element. */
|
|
40
|
+
readonly hasEvery?: readonly E[];
|
|
41
|
+
/** The array shares at least one element with the given ones. */
|
|
42
|
+
readonly hasSome?: readonly E[];
|
|
43
|
+
/** The array contains the element. */
|
|
44
|
+
readonly has?: E;
|
|
45
|
+
/** The array is a subset of the given elements. */
|
|
46
|
+
readonly containedBy?: readonly E[];
|
|
47
|
+
}
|
|
48
|
+
interface JsonOps<V> {
|
|
49
|
+
/** jsonb `@>`: the value contains the given structure. */
|
|
50
|
+
readonly contains?: Partial<V> | Record<string, unknown>;
|
|
51
|
+
}
|
|
52
|
+
type OpsFor<V> = [NonNullable<V>] extends [string] ? BaseOps<V> & ComparableOps<V> & TextOps : [NonNullable<V>] extends [number | bigint] ? BaseOps<V> & ComparableOps<V> : [NonNullable<V>] extends [boolean] ? BaseOps<V> : [NonNullable<V>] extends [readonly (infer E)[]] ? BaseOps<V> & ArrayOps<E> : BaseOps<V> & JsonOps<NonNullable<V>>;
|
|
53
|
+
/** A value (equality, or `null` for `is null`) or an operator object. */
|
|
54
|
+
type FieldFilter<V> = V | OpsFor<V>;
|
|
55
|
+
type RelationFilter<M extends AnyModels, R> = R extends {
|
|
56
|
+
readonly table: infer X extends keyof M;
|
|
57
|
+
readonly kind: "many";
|
|
58
|
+
} ? {
|
|
59
|
+
/** At least one related row matches. `{}` means at least one exists. */
|
|
60
|
+
readonly some?: WhereInput<M, X>;
|
|
61
|
+
/** No related row matches. `{}` means none exist. */
|
|
62
|
+
readonly none?: WhereInput<M, X>;
|
|
63
|
+
/** Every related row matches (vacuously true without related rows). */
|
|
64
|
+
readonly every?: WhereInput<M, X>;
|
|
65
|
+
} : R extends {
|
|
66
|
+
readonly table: infer X extends keyof M;
|
|
67
|
+
readonly nullable: infer N;
|
|
68
|
+
} ? WhereInput<M, X> | (N extends true ? null : never) | {
|
|
69
|
+
readonly is?: WhereInput<M, X> | (N extends true ? null : never);
|
|
70
|
+
readonly isNot?: WhereInput<M, X> | (N extends true ? null : never);
|
|
71
|
+
} : never;
|
|
72
|
+
type WhereInput<M extends AnyModels, T extends keyof M> = { readonly [K in keyof Row<M, T>]?: FieldFilter<Row<M, T>[K]>; } & { readonly [R in keyof Relations<M, T>]?: RelationFilter<M, Relations<M, T>[R]>; } & {
|
|
73
|
+
readonly AND?: WhereInput<M, T> | readonly WhereInput<M, T>[];
|
|
74
|
+
readonly OR?: readonly WhereInput<M, T>[];
|
|
75
|
+
readonly NOT?: WhereInput<M, T>;
|
|
76
|
+
};
|
|
77
|
+
type SortDirection = "asc" | "desc";
|
|
78
|
+
type OrderByInput<M extends AnyModels, T extends keyof M> = { readonly [K in keyof Row<M, T>]?: SortDirection | {
|
|
79
|
+
readonly direction: SortDirection;
|
|
80
|
+
readonly nulls?: "first" | "last";
|
|
81
|
+
}; };
|
|
82
|
+
type OrderByArg<M extends AnyModels, T extends keyof M> = OrderByInput<M, T> | readonly OrderByInput<M, T>[];
|
|
83
|
+
type SelectArg<M extends AnyModels, T extends keyof M> = readonly Extract<keyof Row<M, T>, string>[];
|
|
84
|
+
interface IncludeArgs<M extends AnyModels, T extends keyof M> {
|
|
85
|
+
readonly select?: SelectArg<M, T>;
|
|
86
|
+
readonly include?: IncludeArg<M, T>;
|
|
87
|
+
readonly where?: WhereInput<M, T>;
|
|
88
|
+
readonly orderBy?: OrderByArg<M, T>;
|
|
89
|
+
readonly limit?: number;
|
|
90
|
+
/** Only return parent rows that have a matching related row. */
|
|
91
|
+
readonly required?: boolean;
|
|
92
|
+
}
|
|
93
|
+
type IncludeArg<M extends AnyModels, T extends keyof M> = { readonly [R in keyof Relations<M, T>]?: true | IncludeArgs<M, Extract<TargetOf<Relations<M, T>[R]>, keyof M>>; } & {
|
|
94
|
+
/** Counts related rows: `_count: { notes: true }` returns `_count.notes`. */
|
|
95
|
+
readonly _count?: CountArg<M, T>;
|
|
96
|
+
} & { readonly [K in MeasureKey]?: RelationMeasureArg<M, T>; };
|
|
97
|
+
type NumericKey<M extends AnyModels, T extends keyof M> = { [K in keyof Row<M, T>]: [NonNullable<Row<M, T>[K]>] extends [number | bigint | string] ? K : never; }[keyof Row<M, T>];
|
|
98
|
+
type MeasureKey = "_sum" | "_avg" | "_min" | "_max";
|
|
99
|
+
/** Columns to aggregate: `{ amount: true }`. */
|
|
100
|
+
type MeasureArg<M extends AnyModels, T extends keyof M> = { readonly [K in keyof Row<M, T>]?: true; };
|
|
101
|
+
/** `_sum` and `_avg` take number (and numeric-as-string) columns only. */
|
|
102
|
+
type NumericMeasureArg<M extends AnyModels, T extends keyof M> = { readonly [K in NumericKey<M, T>]?: true; };
|
|
103
|
+
/** Relation aggregates check numeric columns at runtime, to keep includes cheap to type. */
|
|
104
|
+
type RelationMeasureArg<M extends AnyModels, T extends keyof M> = { readonly [R in ManyRelations<M, T>]?: MeasureArg<M, Extract<TargetOf<Relations<M, T>[R]>, keyof M>>; };
|
|
105
|
+
type ManyRelations<M extends AnyModels, T extends keyof M> = { [R in keyof Relations<M, T>]: Relations<M, T>[R] extends {
|
|
106
|
+
readonly kind: "many";
|
|
107
|
+
} ? R : never; }[keyof Relations<M, T>];
|
|
108
|
+
type CountArg<M extends AnyModels, T extends keyof M> = { readonly [R in ManyRelations<M, T>]?: true | {
|
|
109
|
+
readonly where?: WhereInput<M, Extract<TargetOf<Relations<M, T>[R]>, keyof M>>;
|
|
110
|
+
}; };
|
|
111
|
+
type TargetOf<R> = R extends {
|
|
112
|
+
readonly table: infer X;
|
|
113
|
+
} ? X : never;
|
|
114
|
+
interface ReadArgs<M extends AnyModels, T extends keyof M> {
|
|
115
|
+
readonly select?: SelectArg<M, T>;
|
|
116
|
+
readonly include?: IncludeArg<M, T>;
|
|
117
|
+
readonly signal?: AbortSignal;
|
|
118
|
+
}
|
|
119
|
+
interface FindManyArgs<M extends AnyModels, T extends keyof M> extends ReadArgs<M, T> {
|
|
120
|
+
readonly where?: WhereInput<M, T>;
|
|
121
|
+
readonly orderBy?: OrderByArg<M, T>;
|
|
122
|
+
readonly limit?: number;
|
|
123
|
+
readonly offset?: number;
|
|
124
|
+
}
|
|
125
|
+
type FindFirstArgs<M extends AnyModels, T extends keyof M> = Omit<FindManyArgs<M, T>, "limit">;
|
|
126
|
+
interface CountArgs<M extends AnyModels, T extends keyof M> {
|
|
127
|
+
readonly where?: WhereInput<M, T>;
|
|
128
|
+
readonly mode?: "exact" | "planned" | "estimated";
|
|
129
|
+
readonly signal?: AbortSignal;
|
|
130
|
+
}
|
|
131
|
+
interface AggregateArgs<M extends AnyModels, T extends keyof M> {
|
|
132
|
+
readonly where?: WhereInput<M, T>;
|
|
133
|
+
/** One result per distinct combination; without it, one result. */
|
|
134
|
+
readonly groupBy?: SelectArg<M, T>;
|
|
135
|
+
/** The number of rows (per group). */
|
|
136
|
+
readonly _count?: true;
|
|
137
|
+
readonly _sum?: NumericMeasureArg<M, T>;
|
|
138
|
+
readonly _avg?: NumericMeasureArg<M, T>;
|
|
139
|
+
readonly _min?: MeasureArg<M, T>;
|
|
140
|
+
readonly _max?: MeasureArg<M, T>;
|
|
141
|
+
/** Sorts groups; only `groupBy` columns. */
|
|
142
|
+
readonly orderBy?: OrderByArg<M, T>;
|
|
143
|
+
readonly limit?: number;
|
|
144
|
+
readonly offset?: number;
|
|
145
|
+
readonly signal?: AbortSignal;
|
|
146
|
+
}
|
|
147
|
+
type SelectPart<M extends AnyModels, T extends keyof M, A> = A extends {
|
|
148
|
+
readonly select: readonly (infer K)[];
|
|
149
|
+
} ? Pick<Row<M, T>, Extract<K, keyof Row<M, T>>> : Row<M, T>;
|
|
150
|
+
type RelationPayload<M extends AnyModels, R, V> = R extends RelationShape ? R["kind"] extends "many" ? Payload<M, Extract<R["table"], keyof M>, V extends true ? unknown : V>[] : R["nullable"] extends true ? Payload<M, Extract<R["table"], keyof M>, V extends true ? unknown : V> | null : Payload<M, Extract<R["table"], keyof M>, V extends true ? unknown : V> : never;
|
|
151
|
+
type IncludePart<M extends AnyModels, T extends keyof M, A> = A extends {
|
|
152
|
+
readonly include: infer I;
|
|
153
|
+
} ? { -readonly [R in keyof I & keyof Relations<M, T>]: RelationPayload<M, Relations<M, T>[R], I[R]>; } & CountPart<I> & ([keyof I & MeasureKey] extends [never] ? unknown : RelationMeasures<M, T, I>) : unknown;
|
|
154
|
+
type CountPart<I> = I extends {
|
|
155
|
+
readonly _count: infer C;
|
|
156
|
+
} ? {
|
|
157
|
+
_count: { -readonly [R in keyof C]: number; };
|
|
158
|
+
} : unknown;
|
|
159
|
+
/**
|
|
160
|
+
* `_avg` is a number; `_sum` keeps exact `bigint` and `string` (numeric)
|
|
161
|
+
* columns; `_min`/`_max` have the column's type. All are `null` without rows.
|
|
162
|
+
*/
|
|
163
|
+
type MeasureValue<K extends MeasureKey, V> = K extends "_avg" ? number | null : K extends "_sum" ? [NonNullable<V>] extends [bigint] ? bigint | null : [NonNullable<V>] extends [string] ? string | null : number | null : NonNullable<V> | null;
|
|
164
|
+
type MeasuresOf<M extends AnyModels, T extends keyof M, C, K extends MeasureKey> = { -readonly [P in keyof C & keyof Row<M, T>]: MeasureValue<K, Row<M, T>[P]>; };
|
|
165
|
+
type RelationMeasures<M extends AnyModels, T extends keyof M, I> = { -readonly [K in keyof I & MeasureKey]: { -readonly [R in keyof I[K] & keyof Relations<M, T>]: MeasuresOf<M, Extract<TargetOf<Relations<M, T>[R]>, keyof M>, I[K][R], K>; }; };
|
|
166
|
+
type RootMeasures<M extends AnyModels, T extends keyof M, A, K extends MeasureKey> = A extends { readonly [P in K]: infer C; } ? { [P in K]: MeasuresOf<M, T, C, K>; } : unknown;
|
|
167
|
+
/** One aggregate result: the `groupBy` columns, `_count` and each measure. */
|
|
168
|
+
type AggregateRow<M extends AnyModels, T extends keyof M, A> = Simplify<(A extends {
|
|
169
|
+
readonly groupBy: readonly (infer K)[];
|
|
170
|
+
} ? Pick<Row<M, T>, Extract<K, keyof Row<M, T>>> : unknown) & (A extends {
|
|
171
|
+
readonly _count: true;
|
|
172
|
+
} ? {
|
|
173
|
+
_count: number;
|
|
174
|
+
} : unknown) & RootMeasures<M, T, A, "_sum"> & RootMeasures<M, T, A, "_avg"> & RootMeasures<M, T, A, "_min"> & RootMeasures<M, T, A, "_max">>;
|
|
175
|
+
/** `aggregate()` returns one row per group with `groupBy`, else one row. */
|
|
176
|
+
type AggregateResult<M extends AnyModels, T extends keyof M, A> = A extends {
|
|
177
|
+
readonly groupBy: readonly unknown[];
|
|
178
|
+
} ? AggregateRow<M, T, A>[] : AggregateRow<M, T, A>;
|
|
179
|
+
/** The row type returned for read arguments `A` on table `T`. */
|
|
180
|
+
type Payload<M extends AnyModels, T extends keyof M, A> = Simplify<SelectPart<M, T, A> & IncludePart<M, T, A>>;
|
|
181
|
+
//#endregion
|
|
182
|
+
//#region src/core/spec.d.ts
|
|
183
|
+
type ReadMethod = "findMany" | "findFirst" | "findUnique" | "findById" | "count" | "aggregate" | "exists" | "paginate";
|
|
184
|
+
declare const resultType: unique symbol;
|
|
185
|
+
/**
|
|
186
|
+
* A read, described as plain JSON: build it with `sb.spec`, run it with
|
|
187
|
+
* `db.$run(spec)`, send it from a Server Component to the client, or hand it
|
|
188
|
+
* to `/query` and `/next`. Args never carry a `signal`.
|
|
189
|
+
*/
|
|
190
|
+
interface QuerySpec<T extends string = string, K extends ReadMethod = ReadMethod, R = unknown> {
|
|
191
|
+
readonly v: 1;
|
|
192
|
+
readonly table: T;
|
|
193
|
+
readonly method: K;
|
|
194
|
+
/** Positional arguments of the repository method. */
|
|
195
|
+
readonly args: readonly unknown[];
|
|
196
|
+
/** Type-only: the result `db.$run(spec)` resolves to. */
|
|
197
|
+
readonly [resultType]?: R;
|
|
198
|
+
}
|
|
199
|
+
/** The result type of a `QuerySpec`. */
|
|
200
|
+
type InferResult<S> = S extends QuerySpec<string, ReadMethod, infer R> ? R : never;
|
|
201
|
+
type NoSignal<A> = Omit<A, "signal">;
|
|
202
|
+
interface TableSpecs<M extends AnyModels, T extends TableKey<M>, E> {
|
|
203
|
+
findMany<const A extends NoSignal<FindManyArgs<M, T>> & FindExt<E, M, T>>(args?: A): QuerySpec<T, "findMany", Payload<M, T, A>[]>;
|
|
204
|
+
findFirst<const A extends NoSignal<FindFirstArgs<M, T>> & FindExt<E, M, T>>(args?: A): QuerySpec<T, "findFirst", Payload<M, T, A> | null>;
|
|
205
|
+
findUnique<const A extends NoSignal<ReadArgs<M, T>> & {
|
|
206
|
+
readonly where: UniqueWhere<M, T>;
|
|
207
|
+
} & FindExt<E, M, T>>(args: A): QuerySpec<T, "findUnique", Payload<M, T, A> | null>;
|
|
208
|
+
findById<const A extends NoSignal<ReadArgs<M, T>> & FindExt<E, M, T>>(id: PrimaryKeyValue<M, T>, args?: A): QuerySpec<T, "findById", Payload<M, T, A>>;
|
|
209
|
+
count(args?: NoSignal<CountArgs<M, T>> & FindExt<E, M, T>): QuerySpec<T, "count", number>;
|
|
210
|
+
aggregate<const A extends NoSignal<AggregateArgs<M, T>> & FindExt<E, M, T>>(args: A): QuerySpec<T, "aggregate", AggregateResult<M, T, A>>;
|
|
211
|
+
exists(args?: {
|
|
212
|
+
readonly where?: WhereInput<M, T>;
|
|
213
|
+
} & FindExt<E, M, T>): QuerySpec<T, "exists", boolean>;
|
|
214
|
+
paginate<const A extends NoSignal<OffsetPageArgs<M, T> | CursorPageArgs<M, T>> & FindExt<E, M, T>>(args: A): QuerySpec<T, "paginate", PageOf<M, T, A>>;
|
|
215
|
+
}
|
|
216
|
+
type Specs<M extends AnyModels, E> = { readonly [T in TableKey<M>]: TableSpecs<M, T, E>; };
|
|
217
|
+
declare function isQuerySpec(value: unknown): value is QuerySpec;
|
|
218
|
+
/**
|
|
219
|
+
* App keys of every table a spec reads: its table, included relations and
|
|
220
|
+
* relations used in `where`. Queries keyed by a spec go stale when any of
|
|
221
|
+
* them changes. Invalid arguments yield just the spec's table; running the
|
|
222
|
+
* spec reports the error.
|
|
223
|
+
*/
|
|
224
|
+
declare function specTables(meta: SchemaMeta, spec: QuerySpec): string[];
|
|
225
|
+
//#endregion
|
|
226
|
+
//#region src/core/read-set.d.ts
|
|
227
|
+
type ScalarParamType = "uuid" | "text" | "bool" | "int2" | "int4" | "int8" | "float4" | "float8" | "numeric" | "date" | "timestamp" | "timestamptz";
|
|
228
|
+
/**
|
|
229
|
+
* The Postgres type of a read-set parameter. `[]` types take an array. Name
|
|
230
|
+
* enums and domains with their schema (`public.note_kind`): the function
|
|
231
|
+
* runs with an empty `search_path`.
|
|
232
|
+
*/
|
|
233
|
+
type ReadSetParamType = ScalarParamType | `${ScalarParamType}[]` | `${string}.${string}`;
|
|
234
|
+
type ReadSetParamTypes = Readonly<Record<string, ReadSetParamType>>;
|
|
235
|
+
type ScalarValue<T> = T extends "int2" | "int4" | "int8" | "float4" | "float8" | "numeric" ? number : T extends "bool" ? boolean : string;
|
|
236
|
+
/** The value a parameter of type `T` takes. */
|
|
237
|
+
type ReadSetParamValue<T> = T extends `${infer E}[]` ? readonly ScalarValue<E>[] : ScalarValue<T>;
|
|
238
|
+
type ReadSetParams<P extends ReadSetParamTypes> = { readonly [K in keyof P]: ReadSetParamValue<P[K]>; };
|
|
239
|
+
type ReadSetRole = "anon" | "authenticated";
|
|
240
|
+
/**
|
|
241
|
+
* Named reads that run together: one `stable` function over PostgREST (a
|
|
242
|
+
* single GET), one transaction over SQL. Build it with `defineReadSet`, run
|
|
243
|
+
* it with `db.$many(readSet, params)`.
|
|
244
|
+
*/
|
|
245
|
+
interface ReadSet<N extends string = string, P extends ReadSetParamTypes = ReadSetParamTypes, S extends Readonly<Record<string, QuerySpec>> = Readonly<Record<string, QuerySpec>>> {
|
|
246
|
+
readonly kind: "read-set";
|
|
247
|
+
readonly name: N;
|
|
248
|
+
/** The database function `better-supabase gen` writes for this set. */
|
|
249
|
+
readonly functionName: `rs_${N}`;
|
|
250
|
+
readonly params: P;
|
|
251
|
+
/** Roles granted execute on the function. */
|
|
252
|
+
readonly roles: readonly ReadSetRole[];
|
|
253
|
+
/** The reads, with placeholders where parameters go. */
|
|
254
|
+
readonly specs: S;
|
|
255
|
+
readonly definition: BetterSupabase;
|
|
256
|
+
}
|
|
257
|
+
/** What `db.$many(readSet, params)` resolves to. */
|
|
258
|
+
type ReadSetResult<S> = S extends ReadSet<string, ReadSetParamTypes, infer Q> ? { readonly [K in keyof Q]: InferResult<Q[K]>; } : never;
|
|
259
|
+
/** The parameters `db.$many(readSet, params)` takes. */
|
|
260
|
+
type InferReadSetParams<S> = S extends ReadSet<string, infer P> ? ReadSetParams<P> : never;
|
|
261
|
+
interface ReadSetOptions<P extends ReadSetParamTypes> {
|
|
262
|
+
readonly params?: P;
|
|
263
|
+
/** Roles that may call the function. Defaults to `['authenticated']`. */
|
|
264
|
+
readonly roles?: readonly ReadSetRole[];
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Registers reads that run as one round trip:
|
|
268
|
+
*
|
|
269
|
+
* ```ts
|
|
270
|
+
* export const appChrome = defineReadSet(
|
|
271
|
+
* sb,
|
|
272
|
+
* 'app_chrome',
|
|
273
|
+
* { params: { userId: 'uuid' } },
|
|
274
|
+
* (s, p) => ({
|
|
275
|
+
* unread: s.notifications.count({ where: { userId: p.userId, readAt: null } }),
|
|
276
|
+
* me: s.profiles.findFirst({ where: { id: p.userId } }),
|
|
277
|
+
* }),
|
|
278
|
+
* );
|
|
279
|
+
* ```
|
|
280
|
+
*
|
|
281
|
+
* `p` holds placeholders, not values: pass them straight into `where` (or
|
|
282
|
+
* `in`), where the function reads them from its `p jsonb` argument.
|
|
283
|
+
*/
|
|
284
|
+
declare function defineReadSet<M extends AnyModels, D, F extends AnyFunctions, E, const N extends string, const P extends ReadSetParamTypes, const S extends Readonly<Record<string, QuerySpec>>>(sb: BetterSupabase<M, D, F, E>, name: N, options: ReadSetOptions<P>, build: (specs: Specs<M, E>, params: ReadSetParams<P>) => S): ReadSet<N, P, S>;
|
|
285
|
+
declare function isReadSet(value: unknown): value is ReadSet;
|
|
286
|
+
/** App keys of every table the set reads. */
|
|
287
|
+
declare function readSetTables(set: ReadSet, meta?: SchemaMeta): string[];
|
|
288
|
+
//#endregion
|
|
289
|
+
//#region src/core/search.d.ts
|
|
290
|
+
/** `db.$search(table, args)`: the `k` rows nearest to `vector`. */
|
|
291
|
+
type SearchArgs<M extends AnyModels, T extends keyof M> = Pick<FindManyArgs<M, T>, "select" | "include" | "where" | "signal"> & {
|
|
292
|
+
/** The query embedding, as numbers or pgvector text (`'[0.1,0.2]'`). */
|
|
293
|
+
readonly vector: readonly number[] | string;
|
|
294
|
+
/** Rows to return. Defaults to 10. */
|
|
295
|
+
readonly k?: number;
|
|
296
|
+
};
|
|
297
|
+
//#endregion
|
|
298
|
+
//#region src/core/stats.d.ts
|
|
299
|
+
/** Database work for one request (or one `db`). */
|
|
300
|
+
interface DbStats {
|
|
301
|
+
/** Executor calls: repository operations and RPCs. */
|
|
302
|
+
readonly calls: number;
|
|
303
|
+
/**
|
|
304
|
+
* Sequential rounds. A wave starts when a call begins while nothing else
|
|
305
|
+
* is in flight, so `Promise.all` of three reads is one wave.
|
|
306
|
+
*/
|
|
307
|
+
readonly waves: number;
|
|
308
|
+
/** App keys of the tables read or written, and `name()` for RPCs. */
|
|
309
|
+
readonly tables: readonly string[];
|
|
310
|
+
/** From the first call's start to the last call's end. */
|
|
311
|
+
readonly ms: number;
|
|
312
|
+
}
|
|
313
|
+
declare const EMPTY_STATS: DbStats;
|
|
314
|
+
/**
|
|
315
|
+
* Counts calls and waves. A recorder with a `parent` also reports to it, so
|
|
316
|
+
* a request-wide recorder sees every scope's calls.
|
|
317
|
+
*/
|
|
318
|
+
declare class StatsRecorder {
|
|
319
|
+
#private;
|
|
320
|
+
constructor(parent?: StatsRecorder, now?: () => number);
|
|
321
|
+
/** Records a call to `table`; the returned function ends it. */
|
|
322
|
+
begin(table: string): () => void;
|
|
323
|
+
/** The totals so far. */
|
|
324
|
+
snapshot(): DbStats;
|
|
325
|
+
}
|
|
326
|
+
/** Wraps an executor so every call is recorded. */
|
|
327
|
+
declare function recordStats(executor: Executor, recorder: StatsRecorder): Executor;
|
|
328
|
+
//#endregion
|
|
329
|
+
//#region src/core/repository-types.d.ts
|
|
330
|
+
type FindExt<E, M extends AnyModels, T extends keyof M> = ApplyExtension<E, M, T, "findArgs">;
|
|
331
|
+
type DeleteExt<E, M extends AnyModels, T extends keyof M> = ApplyExtension<E, M, T, "deleteArgs">;
|
|
332
|
+
interface WriteArgs<M extends AnyModels, T extends keyof M> extends ReadArgs<M, T> {
|
|
333
|
+
/** `false` skips `RETURNING` (needed when RLS hides the written row). */
|
|
334
|
+
readonly returning?: boolean;
|
|
335
|
+
}
|
|
336
|
+
interface UpdateArgs<M extends AnyModels, T extends keyof M> extends WriteArgs<M, T> {
|
|
337
|
+
/**
|
|
338
|
+
* Optimistic concurrency: the update only applies when these columns still
|
|
339
|
+
* have these values. A mismatch returns a `stale` error.
|
|
340
|
+
*/
|
|
341
|
+
readonly expect?: Partial<Row<M, T>>;
|
|
342
|
+
}
|
|
343
|
+
type ConflictTarget<M extends AnyModels, T extends keyof M> = "primaryKey" | UniqueKeyName<M, T> | readonly Extract<keyof Row<M, T>, string>[];
|
|
344
|
+
interface UpsertArgs<M extends AnyModels, T extends keyof M> extends WriteArgs<M, T> {
|
|
345
|
+
/** Unique constraint name or column list. Defaults to the primary key. */
|
|
346
|
+
readonly onConflict?: ConflictTarget<M, T>;
|
|
347
|
+
/** Keep the existing row instead of updating it (`ON CONFLICT DO NOTHING`). */
|
|
348
|
+
readonly ignoreDuplicates?: boolean;
|
|
349
|
+
}
|
|
350
|
+
interface DeleteArgs {
|
|
351
|
+
readonly signal?: AbortSignal;
|
|
352
|
+
}
|
|
353
|
+
type Returned<M extends AnyModels, T extends keyof M, A> = A extends {
|
|
354
|
+
readonly returning: false;
|
|
355
|
+
} ? null : Payload<M, T, A>;
|
|
356
|
+
type OffsetPageArgs<M extends AnyModels, T extends keyof M> = Omit<FindManyArgs<M, T>, "limit" | "offset"> & {
|
|
357
|
+
/** 1-based page number. Defaults to 1. */
|
|
358
|
+
readonly page?: number;
|
|
359
|
+
readonly size: number;
|
|
360
|
+
/** Also count all matching rows. */
|
|
361
|
+
readonly count?: CountMode;
|
|
362
|
+
};
|
|
363
|
+
type CursorPageArgs<M extends AnyModels, T extends keyof M> = Omit<FindManyArgs<M, T>, "limit" | "offset"> & {
|
|
364
|
+
/** Cursor from the previous page, or `null` for the first page. */
|
|
365
|
+
readonly after: string | null;
|
|
366
|
+
readonly size: number;
|
|
367
|
+
};
|
|
368
|
+
interface OffsetPage<R> {
|
|
369
|
+
readonly items: R[];
|
|
370
|
+
readonly page: {
|
|
371
|
+
readonly number: number;
|
|
372
|
+
readonly size: number;
|
|
373
|
+
readonly total: number | null;
|
|
374
|
+
readonly pages: number | null;
|
|
375
|
+
readonly hasMore: boolean;
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
interface CursorPage<R> {
|
|
379
|
+
readonly items: R[];
|
|
380
|
+
readonly nextCursor: string | null;
|
|
381
|
+
readonly hasMore: boolean;
|
|
382
|
+
}
|
|
383
|
+
type PageOf<M extends AnyModels, T extends keyof M, A> = A extends {
|
|
384
|
+
readonly after: unknown;
|
|
385
|
+
} ? CursorPage<Payload<M, T, A>> : OffsetPage<Payload<M, T, A>>;
|
|
386
|
+
interface Repository<M extends AnyModels, T extends TableKey<M>, E = unknown> {
|
|
387
|
+
readonly $table: T;
|
|
388
|
+
readonly $meta: TableMeta;
|
|
389
|
+
findMany<const A extends FindManyArgs<M, T> & FindExt<E, M, T>>(args?: A): AsyncResult<Payload<M, T, A>[]>;
|
|
390
|
+
findFirst<const A extends FindFirstArgs<M, T> & FindExt<E, M, T>>(args?: A): AsyncResult<Payload<M, T, A> | null>;
|
|
391
|
+
/**
|
|
392
|
+
* The row with these values for the primary key or one named unique key
|
|
393
|
+
* (`{ email }`, `{ organizationId, slug }`), or `null`.
|
|
394
|
+
*/
|
|
395
|
+
findUnique<const A extends ReadArgs<M, T> & {
|
|
396
|
+
readonly where: UniqueWhere<M, T>;
|
|
397
|
+
} & FindExt<E, M, T>>(args: A): AsyncResult<Payload<M, T, A> | null>;
|
|
398
|
+
/** Returns a `not_found` error when no visible row has this key. */
|
|
399
|
+
findById<const A extends ReadArgs<M, T> & FindExt<E, M, T>>(id: PrimaryKeyValue<M, T>, args?: A): AsyncResult<Payload<M, T, A>>;
|
|
400
|
+
count(args?: CountArgs<M, T> & FindExt<E, M, T>): AsyncResult<number>;
|
|
401
|
+
/**
|
|
402
|
+
* Counts, sums, averages, minimums and maximums in one request, grouped by
|
|
403
|
+
* `groupBy` columns. Needs `pgrst.db_aggregates_enabled` over PostgREST.
|
|
404
|
+
*/
|
|
405
|
+
aggregate<const A extends AggregateArgs<M, T> & FindExt<E, M, T>>(args: A): AsyncResult<AggregateResult<M, T, A>>;
|
|
406
|
+
exists(args?: {
|
|
407
|
+
readonly where?: WhereInput<M, T>;
|
|
408
|
+
readonly signal?: AbortSignal;
|
|
409
|
+
} & FindExt<E, M, T>): AsyncResult<boolean>;
|
|
410
|
+
paginate<const A extends (OffsetPageArgs<M, T> | CursorPageArgs<M, T>) & FindExt<E, M, T>>(args: A): AsyncResult<PageOf<M, T, A>>;
|
|
411
|
+
create<const A extends WriteArgs<M, T> = {}>(data: Insert<M, T>, args?: A): AsyncResult<Returned<M, T, A>>;
|
|
412
|
+
createMany<const A extends WriteArgs<M, T> = {}>(rows: readonly Insert<M, T>[], args?: A): AsyncResult<A extends {
|
|
413
|
+
readonly returning: false;
|
|
414
|
+
} ? {
|
|
415
|
+
count: number;
|
|
416
|
+
} : Payload<M, T, A>[]>;
|
|
417
|
+
update<const A extends UpdateArgs<M, T> = {}>(id: PrimaryKeyValue<M, T>, patch: Update<M, T>, args?: A): AsyncResult<Returned<M, T, A>>;
|
|
418
|
+
updateMany(args: {
|
|
419
|
+
readonly where: WhereInput<M, T>;
|
|
420
|
+
readonly data: Update<M, T>;
|
|
421
|
+
readonly signal?: AbortSignal;
|
|
422
|
+
} & FindExt<E, M, T>): AsyncResult<{
|
|
423
|
+
count: number;
|
|
424
|
+
}>;
|
|
425
|
+
upsert<const A extends UpsertArgs<M, T> = {}>(data: Insert<M, T>, args?: A): AsyncResult<A extends {
|
|
426
|
+
readonly ignoreDuplicates: true;
|
|
427
|
+
} ? Returned<M, T, A> | null : Returned<M, T, A>>;
|
|
428
|
+
upsertMany<const A extends UpsertArgs<M, T> = {}>(rows: readonly Insert<M, T>[], args?: A): AsyncResult<A extends {
|
|
429
|
+
readonly returning: false;
|
|
430
|
+
} ? {
|
|
431
|
+
count: number;
|
|
432
|
+
} : Payload<M, T, A>[]>;
|
|
433
|
+
/** Returns a `not_found` error when no visible row has this key. */
|
|
434
|
+
delete(id: PrimaryKeyValue<M, T>, args?: DeleteArgs & DeleteExt<E, M, T>): AsyncResult<void>;
|
|
435
|
+
deleteMany(args: {
|
|
436
|
+
readonly where: WhereInput<M, T>;
|
|
437
|
+
readonly signal?: AbortSignal;
|
|
438
|
+
} & DeleteExt<E, M, T> & FindExt<E, M, T>): AsyncResult<{
|
|
439
|
+
count: number;
|
|
440
|
+
}>;
|
|
441
|
+
/** Adds methods built on this repository. */
|
|
442
|
+
extend<X extends object>(build: (base: this) => X): this & X;
|
|
443
|
+
}
|
|
444
|
+
type RepositoryOf<M extends AnyModels, T extends TableKey<M>, E> = Repository<M, T, E> & ApplyExtension<E, M, T, "methods">;
|
|
445
|
+
interface RpcOptions<R> {
|
|
446
|
+
readonly signal?: AbortSignal;
|
|
447
|
+
/** Validates the return value; the result carries the schema's output type. */
|
|
448
|
+
readonly returns?: StandardSchemaV1<unknown, R>;
|
|
449
|
+
readonly schema?: string;
|
|
450
|
+
}
|
|
451
|
+
type RpcArgs<F extends AnyFunctions, N extends keyof F> = Record<never, never> extends F[N]["Args"] ? [args?: F[N]["Args"]] : [args: F[N]["Args"]];
|
|
452
|
+
interface DbHelpers<M extends AnyModels, F extends AnyFunctions, E, C> {
|
|
453
|
+
/** The underlying client (supabase-js), for anything the repository lacks. */
|
|
454
|
+
readonly $client: C;
|
|
455
|
+
readonly $executor: Executor;
|
|
456
|
+
readonly $context: RequestContext;
|
|
457
|
+
/** Calls a database function with typed arguments. */
|
|
458
|
+
$rpc<N extends Extract<keyof F, string>, R = F[N]["Returns"]>(name: N, ...rest: [...RpcArgs<F, N>, options?: RpcOptions<R>]): AsyncResult<R>;
|
|
459
|
+
/** Same connection with more context (for example a tenant). */
|
|
460
|
+
$with(context: RequestContext): Db<M, F, E, C>;
|
|
461
|
+
/**
|
|
462
|
+
* Same connection without plugins: no tenant scoping, soft-delete filters,
|
|
463
|
+
* timestamps, rules or executor wrappers. For migrations and admin tools.
|
|
464
|
+
*/
|
|
465
|
+
$withoutPlugins(): Db<M, F, unknown, C>;
|
|
466
|
+
/**
|
|
467
|
+
* The repository for a table named at runtime (MCP tools, admin screens).
|
|
468
|
+
* Throws a `TypeError` for unknown names.
|
|
469
|
+
*/
|
|
470
|
+
$table<T extends TableKey<M>>(name: T): RepositoryOf<M, T, E>;
|
|
471
|
+
/** Calls, waves, tables and time for everything run through this `db`. */
|
|
472
|
+
$stats(): DbStats;
|
|
473
|
+
/** Runs a `QuerySpec` built with `sb.spec`. */
|
|
474
|
+
$run<S extends QuerySpec<TableKey<M>>>(spec: S, options?: {
|
|
475
|
+
readonly signal?: AbortSignal;
|
|
476
|
+
}): AsyncResult<InferResult<S>>;
|
|
477
|
+
/**
|
|
478
|
+
* Runs a read set as one round trip: a single GET to its function over
|
|
479
|
+
* PostgREST, one transaction over SQL. Query plugins don't apply; RLS does.
|
|
480
|
+
*/
|
|
481
|
+
$many<S extends ReadSet>(readSet: S, params: InferReadSetParams<S>, options?: {
|
|
482
|
+
readonly signal?: AbortSignal;
|
|
483
|
+
}): AsyncResult<ReadSetResult<S>>;
|
|
484
|
+
/**
|
|
485
|
+
* Runs specs together: in parallel over PostgREST, in one transaction when
|
|
486
|
+
* the executor has `batch`. Fails with the first error.
|
|
487
|
+
*/
|
|
488
|
+
$many<const S extends readonly QuerySpec<TableKey<M>>[]>(specs: S, options?: {
|
|
489
|
+
readonly signal?: AbortSignal;
|
|
490
|
+
}): AsyncResult<{ -readonly [K in keyof S]: InferResult<S[K]>; }>;
|
|
491
|
+
/**
|
|
492
|
+
* The `k` rows nearest to `vector`, nearest first, through the
|
|
493
|
+
* `search_<table>` function of the `vector-search` SQL kit module. RLS
|
|
494
|
+
* applies inside the search; `where` filters the `k` rows it returns.
|
|
495
|
+
*/
|
|
496
|
+
$search<T extends TableKey<M>, const A extends SearchArgs<M, T>>(table: T, args: A): AsyncResult<Payload<M, T, A>[]>;
|
|
497
|
+
}
|
|
498
|
+
type Db<M extends AnyModels, F extends AnyFunctions, E, C> = { readonly [T in TableKey<M>]: RepositoryOf<M, T, E>; } & DbHelpers<M, F, E, C>;
|
|
499
|
+
//#endregion
|
|
500
|
+
//#region src/core/cache.d.ts
|
|
501
|
+
/** What a mutation changed: a table, the primary keys of its rows and the tenant. */
|
|
502
|
+
interface CacheTarget {
|
|
503
|
+
/** App key of the table. */
|
|
504
|
+
readonly table: string;
|
|
505
|
+
/**
|
|
506
|
+
* App keys of every table whose cached reads are now stale: `table`, plus
|
|
507
|
+
* tables whose foreign keys cascade or set a value when `table` rows are
|
|
508
|
+
* deleted. Invalidate every read that touched one of them.
|
|
509
|
+
*/
|
|
510
|
+
readonly tables: readonly string[];
|
|
511
|
+
/** Primary keys of the changed rows; composite keys are joined with `,`. */
|
|
512
|
+
readonly ids: readonly string[];
|
|
513
|
+
readonly tenant?: string;
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Invalidates cached reads after a mutation. First-party adapters:
|
|
517
|
+
* `nextCache()` (Next.js cache tags) and `queryCache(client)` (TanStack
|
|
518
|
+
* Query). Attach one with `sb.cache(adapter)`; prove custom ones with
|
|
519
|
+
* `testCacheAdapter`.
|
|
520
|
+
*/
|
|
521
|
+
interface CacheAdapter {
|
|
522
|
+
readonly name: string;
|
|
523
|
+
invalidate(target: CacheTarget): void | Promise<void>;
|
|
524
|
+
}
|
|
525
|
+
/** Primary key of a row as a string, or `undefined` when it isn't returned. */
|
|
526
|
+
declare function rowKey(table: TableMeta, row: Readonly<Record<string, unknown>>): string | undefined;
|
|
527
|
+
declare function cacheTargetOf(meta: SchemaMeta, notice: MutationNotice): CacheTarget;
|
|
528
|
+
/** One target per table an RPC changes; RPCs report no row ids. */
|
|
529
|
+
declare function rpcCacheTargets(meta: SchemaMeta, notice: RpcNotice): CacheTarget[];
|
|
530
|
+
interface MemoryCache extends CacheAdapter {
|
|
531
|
+
readonly invalidated: readonly CacheTarget[];
|
|
532
|
+
clear(): void;
|
|
533
|
+
}
|
|
534
|
+
/** Records invalidations. For tests and for checking what a mutation touches. */
|
|
535
|
+
declare function memoryCache(): MemoryCache;
|
|
536
|
+
//#endregion
|
|
537
|
+
//#region src/core/postgrest-executor.d.ts
|
|
538
|
+
/**
|
|
539
|
+
* Anything with `schema(name).from(table)` or `from(table)`: a supabase-js
|
|
540
|
+
* `SupabaseClient` or a bare `PostgrestClient`.
|
|
541
|
+
*/
|
|
542
|
+
interface PostgrestClientLike {
|
|
543
|
+
from(relation: never): unknown;
|
|
544
|
+
schema?(schema: never): unknown;
|
|
545
|
+
rpc?(fn: never, args?: never): unknown;
|
|
546
|
+
}
|
|
547
|
+
declare function postgrestExecutor(client: PostgrestClientLike): Executor;
|
|
548
|
+
/** The compiled plan for an operation; useful for debugging and tests. */
|
|
549
|
+
declare function explainPostgrest(op: Operation): PostgrestPlan;
|
|
550
|
+
//#endregion
|
|
551
|
+
//#region src/core/define.d.ts
|
|
552
|
+
interface DefineSupabaseOptions {
|
|
553
|
+
/** Clock used by plugins (timestamps, soft delete). */
|
|
554
|
+
readonly now?: () => Date;
|
|
555
|
+
/** Extra error mappers, run before plugin mappers. */
|
|
556
|
+
readonly errors?: readonly ErrorMapper[];
|
|
557
|
+
/** Receives errors from event handlers, hooks and cache adapters. Defaults to `console`. */
|
|
558
|
+
readonly logger?: Logger;
|
|
559
|
+
/** RPCs that change tables, keyed by function name. Prefer `sb.defineRpc()`. */
|
|
560
|
+
readonly rpc?: Readonly<Record<string, RpcDefinition>>;
|
|
561
|
+
/** Builds the error `.orThrow()` throws. Prefer `sb.mapError()`. */
|
|
562
|
+
readonly throwAs?: ThrowMapper;
|
|
563
|
+
/** Validates verified JWT claims on the server. Prefer `sb.claims()`, which also types them. */
|
|
564
|
+
readonly claims?: StandardSchemaV1;
|
|
565
|
+
/**
|
|
566
|
+
* PostgREST's `db-max-rows`: the most rows one read returns. An unbounded
|
|
567
|
+
* `findMany` that returns this many sets `truncated` on the `query` event
|
|
568
|
+
* and logs a warning once per table. Defaults to 1000, the hosted default.
|
|
569
|
+
*/
|
|
570
|
+
readonly maxRows?: number;
|
|
571
|
+
}
|
|
572
|
+
interface ConnectOptions {
|
|
573
|
+
/** Also records this connection's calls into a request-wide recorder. */
|
|
574
|
+
readonly stats?: StatsRecorder;
|
|
575
|
+
/**
|
|
576
|
+
* Runs operations instead of the client's own executor, while `$client`
|
|
577
|
+
* stays the client (e.g. routing reads to a replica).
|
|
578
|
+
*/
|
|
579
|
+
readonly executor?: Executor;
|
|
580
|
+
}
|
|
581
|
+
interface RpcDefinition {
|
|
582
|
+
/** App keys of the tables the function writes; their cached reads are invalidated on success. */
|
|
583
|
+
readonly invalidates: readonly string[];
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* The isomorphic definition of your data layer: schema plus plugins. Holds no
|
|
587
|
+
* secrets and no connection; `connect()` binds it to a client per request.
|
|
588
|
+
*/
|
|
589
|
+
declare class BetterSupabase<M extends AnyModels = AnyModels, D = unknown, F extends AnyFunctions = AnyFunctions, E = unknown, C = unknown> {
|
|
590
|
+
#private;
|
|
591
|
+
readonly schema: Schema<M, D, F>;
|
|
592
|
+
readonly plugins: readonly AnyPlugin[];
|
|
593
|
+
readonly events: EventHub;
|
|
594
|
+
readonly options: DefineSupabaseOptions;
|
|
595
|
+
constructor(schema: Schema<M, D, F>, plugins?: readonly AnyPlugin[], options?: DefineSupabaseOptions, events?: EventHub);
|
|
596
|
+
get meta(): SchemaMeta;
|
|
597
|
+
/** The schema set by `claims()`; its output types `session.claims`. */
|
|
598
|
+
get claimsSchema(): StandardSchemaV1<unknown, C> | undefined;
|
|
599
|
+
/**
|
|
600
|
+
* Returns a new instance whose servers validate verified JWT claims (custom
|
|
601
|
+
* access token hook output) with `schema`, and whose sessions are typed by it.
|
|
602
|
+
* A token that fails it resolves to `{ kind: 'invalid', reason: 'claims' }`.
|
|
603
|
+
*
|
|
604
|
+
* ```ts
|
|
605
|
+
* const sb = defineSupabase(schema).claims(z.object({ tenant_id: z.uuid() }));
|
|
606
|
+
* ```
|
|
607
|
+
*/
|
|
608
|
+
claims<S extends StandardSchemaV1>(schema: S): BetterSupabase<M, D, F, E, StandardSchemaV1.InferOutput<S>>;
|
|
609
|
+
/**
|
|
610
|
+
* Returns a new instance whose `.orThrow()` throws `mapper(error)` instead
|
|
611
|
+
* of a `DbException`, and whose results `toBetterResult` maps the same way.
|
|
612
|
+
* Results themselves keep their `DbError`.
|
|
613
|
+
*
|
|
614
|
+
* ```ts
|
|
615
|
+
* const sb = defineSupabase(schema).mapError((error) => new AppError(error));
|
|
616
|
+
* ```
|
|
617
|
+
*/
|
|
618
|
+
mapError(mapper: (error: DbError) => unknown): BetterSupabase<M, D, F, E, C>;
|
|
619
|
+
/**
|
|
620
|
+
* Builds serializable `QuerySpec`s with the same arguments and result types
|
|
621
|
+
* as the repository: `sb.spec.customers.findMany({ select: ['id'] })`.
|
|
622
|
+
*/
|
|
623
|
+
get spec(): Specs<M, E>;
|
|
624
|
+
/** App keys of every table a spec reads; mutations of any of them make it stale. */
|
|
625
|
+
tablesOf(spec: QuerySpec): string[];
|
|
626
|
+
/** Returns a new instance with the plugin appended. */
|
|
627
|
+
use<P extends AnyPlugin>(plugin: P): BetterSupabase<M, D, F, WithExtension<E, ExtensionOf<P>>, C>;
|
|
628
|
+
/**
|
|
629
|
+
* Declares the tables an RPC writes, so cache adapters and live queries
|
|
630
|
+
* invalidate them after it succeeds.
|
|
631
|
+
*
|
|
632
|
+
* ```ts
|
|
633
|
+
* sb.defineRpc('archive_customer', { invalidates: ['customers', 'notes'] });
|
|
634
|
+
* ```
|
|
635
|
+
*/
|
|
636
|
+
defineRpc(name: Extract<keyof F, string>, options: {
|
|
637
|
+
readonly invalidates: readonly TableKey<M>[];
|
|
638
|
+
}): BetterSupabase<M, D, F, E, C>;
|
|
639
|
+
/** Observes queries, mutations, errors, auth and refreshes. */
|
|
640
|
+
on<K extends EventName>(name: K, handler: EventHandler<K>): () => void;
|
|
641
|
+
/**
|
|
642
|
+
* Invalidates `adapter` after every mutation in this runtime. Returns a
|
|
643
|
+
* function that detaches it. Adapter failures are logged, never thrown.
|
|
644
|
+
*/
|
|
645
|
+
cache(adapter: CacheAdapter): () => void;
|
|
646
|
+
/**
|
|
647
|
+
* Binds the definition to a supabase-js client (or any `Executor`) and a
|
|
648
|
+
* request context. Cheap: call it once per request.
|
|
649
|
+
*/
|
|
650
|
+
connect<C extends PostgrestClientLike>(client: C, context?: RequestContext, options?: ConnectOptions): Db<M, F, E, C>;
|
|
651
|
+
connect(executor: Executor, context?: RequestContext, options?: ConnectOptions): Db<M, F, E, undefined>;
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Creates the data-layer definition from the generated `schema`.
|
|
655
|
+
*
|
|
656
|
+
* ```ts
|
|
657
|
+
* export const sb = defineSupabase(schema).use(timestamps()).use(softDelete());
|
|
658
|
+
* ```
|
|
659
|
+
*/
|
|
660
|
+
declare function defineSupabase<M extends AnyModels, D, F extends AnyFunctions>(schema: Schema<M, D, F>, options?: DefineSupabaseOptions): BetterSupabase<M, D, F>;
|
|
661
|
+
//#endregion
|
|
662
|
+
export { Specs as $, RpcOptions as A, ReadSet as B, FindExt as C, WhereInput as Ct, Repository as D, PageOf as E, EMPTY_STATS as F, ReadSetParams as G, ReadSetParamType as H, StatsRecorder as I, isReadSet as J, ReadSetResult as K, recordStats as L, UpsertArgs as M, WriteArgs as N, RepositoryOf as O, DbStats as P, ReadMethod as Q, SearchArgs as R, DeleteExt as S, SortDirection as St, OffsetPageArgs as T, ReadSetParamTypes as U, ReadSetOptions as V, ReadSetParamValue as W, InferResult as X, readSetTables as Y, QuerySpec as Z, CursorPage as _, OrderByInput as _t, defineSupabase as a, AggregateRow as at, DbHelpers as b, RelationMeasureArg as bt, postgrestExecutor as c, FieldFilter as ct, MemoryCache as d, IncludeArg as dt, TableSpecs as et, cacheTargetOf as f, IncludeArgs as ft, ConflictTarget as g, OrderByArg as gt, rpcCacheTargets as h, NumericMeasureArg as ht, RpcDefinition as i, AggregateResult as it, UpdateArgs as j, Returned as k, CacheAdapter as l, FindFirstArgs as lt, rowKey as m, MeasureKey as mt, ConnectOptions as n, specTables as nt, PostgrestClientLike as o, CountArg as ot, memoryCache as p, MeasureArg as pt, defineReadSet as q, DefineSupabaseOptions as r, AggregateArgs as rt, explainPostgrest as s, CountArgs as st, BetterSupabase as t, isQuerySpec as tt, CacheTarget as u, FindManyArgs as ut, CursorPageArgs as v, Payload as vt, OffsetPage as w, DeleteArgs as x, SelectArg as xt, Db as y, ReadArgs as yt, InferReadSetParams as z };
|