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.
Files changed (154) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +88 -1
  3. package/bin/better-supabase.js +3 -0
  4. package/dist/casing-da0uRTqt.js +14 -0
  5. package/dist/cli/bin.d.ts +1 -0
  6. package/dist/cli/bin.js +15 -0
  7. package/dist/cli/index.d.ts +226 -0
  8. package/dist/cli/index.js +3 -0
  9. package/dist/cli-CoByWYja.js +6472 -0
  10. package/dist/client/index.d.ts +2 -0
  11. package/dist/client/index.js +112 -0
  12. package/dist/compiler-DL18ukPe.d.ts +14 -0
  13. package/dist/config/index.d.ts +3 -0
  14. package/dist/config/index.js +3 -0
  15. package/dist/config-D-aR2ZoN.js +276 -0
  16. package/dist/define-CTfWw-SS.d.ts +662 -0
  17. package/dist/define-QGkq04oe.js +1068 -0
  18. package/dist/edge/index.d.ts +43 -0
  19. package/dist/edge/index.js +103 -0
  20. package/dist/entitlements-BBg61DQZ.d.ts +20 -0
  21. package/dist/entitlements-BC_khwRy.js +17 -0
  22. package/dist/env/index.d.ts +2 -0
  23. package/dist/env/index.js +2 -0
  24. package/dist/env-BEToab0I.js +204 -0
  25. package/dist/errors-Bl3rkOzo.js +196 -0
  26. package/dist/events/index.d.ts +2 -0
  27. package/dist/events/index.js +2 -0
  28. package/dist/events-2OJsVG_d.d.ts +84 -0
  29. package/dist/events-BuzTgn2D.js +135 -0
  30. package/dist/executor-Bazhgsgq.d.ts +195 -0
  31. package/dist/executor-Bje4suQF.d.ts +25 -0
  32. package/dist/executor-Ceq60hPM.js +89 -0
  33. package/dist/hono/index.d.ts +45 -0
  34. package/dist/hono/index.js +70 -0
  35. package/dist/index-BD6wKthp.d.ts +597 -0
  36. package/dist/index-DQVvHzjW.d.ts +74 -0
  37. package/dist/index-DRid0qIv.d.ts +76 -0
  38. package/dist/index-Dup-nSe9.d.ts +117 -0
  39. package/dist/index-Dy6kuF0P.d.ts +71 -0
  40. package/dist/index-Hf8PP9sP.d.ts +116 -0
  41. package/dist/index-JXHBuS53.d.ts +144 -0
  42. package/dist/index-Nxo3TJcm.d.ts +208 -0
  43. package/dist/index-Sw43J8HG.d.ts +62 -0
  44. package/dist/index-cEeweTeM.d.ts +38 -0
  45. package/dist/index.d.ts +110 -0
  46. package/dist/index.js +42 -0
  47. package/dist/invalidate-DbxuL2jL.js +18 -0
  48. package/dist/jobs/index.d.ts +173 -0
  49. package/dist/jobs/index.js +477 -0
  50. package/dist/json-schema-BbwO2mZg.js +181 -0
  51. package/dist/lint/index.d.ts +75 -0
  52. package/dist/lint/index.js +167 -0
  53. package/dist/list/index.d.ts +2 -0
  54. package/dist/list/index.js +410 -0
  55. package/dist/live-6b9i72Ux.d.ts +180 -0
  56. package/dist/live-D8rV1Ldw.js +168 -0
  57. package/dist/mcp/index.d.ts +105 -0
  58. package/dist/mcp/index.js +330 -0
  59. package/dist/mfa-CpogP66z.js +521 -0
  60. package/dist/mfa-TVia554c.d.ts +44 -0
  61. package/dist/next/image/index.d.ts +34 -0
  62. package/dist/next/image/index.js +40 -0
  63. package/dist/next/index.d.ts +210 -0
  64. package/dist/next/index.js +426 -0
  65. package/dist/openapi/index.d.ts +2 -0
  66. package/dist/openapi/index.js +332 -0
  67. package/dist/orpc/index.d.ts +46 -0
  68. package/dist/orpc/index.js +50 -0
  69. package/dist/otel/index.d.ts +40 -0
  70. package/dist/otel/index.js +168 -0
  71. package/dist/path-Cv__-OTj.d.ts +17 -0
  72. package/dist/plugin-BqR6wKMB.js +23 -0
  73. package/dist/plugin-HvGqCurB.d.ts +118 -0
  74. package/dist/plugins/actor/index.d.ts +13 -0
  75. package/dist/plugins/actor/index.js +43 -0
  76. package/dist/plugins/rules/index.d.ts +88 -0
  77. package/dist/plugins/rules/index.js +174 -0
  78. package/dist/plugins/soft-delete/index.d.ts +38 -0
  79. package/dist/plugins/soft-delete/index.js +69 -0
  80. package/dist/plugins/tenant/index.d.ts +43 -0
  81. package/dist/plugins/tenant/index.js +73 -0
  82. package/dist/plugins/timestamps/index.d.ts +9 -0
  83. package/dist/plugins/timestamps/index.js +37 -0
  84. package/dist/plugins/validation/index.d.ts +24 -0
  85. package/dist/plugins/validation/index.js +59 -0
  86. package/dist/pool-BFeqzwQS.d.ts +37 -0
  87. package/dist/postgres/index.d.ts +28 -0
  88. package/dist/postgres/index.js +79 -0
  89. package/dist/postgrest-Dm-vhY6R.d.ts +43 -0
  90. package/dist/problem-DPu6Fh-t.js +97 -0
  91. package/dist/problem-DlgB0lYl.d.ts +47 -0
  92. package/dist/query/index.d.ts +2 -0
  93. package/dist/query/index.js +3 -0
  94. package/dist/query-ChvDbsDE.js +186 -0
  95. package/dist/react/index.d.ts +7 -0
  96. package/dist/react/index.js +5 -0
  97. package/dist/react/server.d.ts +13 -0
  98. package/dist/react/server.js +25 -0
  99. package/dist/react/session.d.ts +2 -0
  100. package/dist/react/session.js +3 -0
  101. package/dist/react-CrOvrnIP.js +241 -0
  102. package/dist/read-set-DhX2d04c.js +216 -0
  103. package/dist/realtime/index.d.ts +3 -0
  104. package/dist/realtime/index.js +253 -0
  105. package/dist/resolve-DW8h9NPm.d.ts +155 -0
  106. package/dist/resource-CYiu6Ygi.js +175 -0
  107. package/dist/resource-SkPTRJDD.d.ts +65 -0
  108. package/dist/respond-4-dhoV7x.js +380 -0
  109. package/dist/respond-PoTpy5DT.d.ts +169 -0
  110. package/dist/result-CTkCZ6JA.d.ts +198 -0
  111. package/dist/result-DWXatkd6.js +103 -0
  112. package/dist/scope-CDHcS7dE.js +90 -0
  113. package/dist/seed-CzecODcJ.js +101 -0
  114. package/dist/server/index.d.ts +42 -0
  115. package/dist/server/index.js +68 -0
  116. package/dist/session-C3osL21k.d.ts +21 -0
  117. package/dist/session-CD-3orO_.js +19 -0
  118. package/dist/shared-_6-uPL7E.js +57 -0
  119. package/dist/simplify-oHiDKRVQ.js +665 -0
  120. package/dist/spec-pins-CJPVghHy.d.ts +20 -0
  121. package/dist/spec-pins-t6sPaHvl.js +20 -0
  122. package/dist/sql-M8l3fnS0.js +260 -0
  123. package/dist/ssr/index.d.ts +5 -0
  124. package/dist/ssr/index.js +4 -0
  125. package/dist/standard-CyhRzctb.d.ts +7 -0
  126. package/dist/standard-FUi3Z3-7.js +21 -0
  127. package/dist/stats-3iy8u3_P.js +566 -0
  128. package/dist/storage/index.d.ts +4 -0
  129. package/dist/storage/index.js +2 -0
  130. package/dist/storage-BWXVUXGk.js +461 -0
  131. package/dist/tables-rZxRxNPW.js +59 -0
  132. package/dist/template-BeOGnynM.js +93 -0
  133. package/dist/template-mbvlysOo.d.ts +6 -0
  134. package/dist/testing/index.d.ts +294 -0
  135. package/dist/testing/index.js +751 -0
  136. package/dist/types-6cYK9pbJ.js +29 -0
  137. package/dist/types-C2fslP1z.d.ts +195 -0
  138. package/dist/version-Cqq1m3UY.js +4 -0
  139. package/dist/view-B0ltUmTi.d.ts +43 -0
  140. package/dist/view-B6F9QbG-.js +35 -0
  141. package/dist/webhooks/index.d.ts +152 -0
  142. package/dist/webhooks/index.js +2 -0
  143. package/dist/webhooks-DbMTJJX2.js +139 -0
  144. package/package.json +246 -17
  145. package/schemas/config-v1.json +328 -0
  146. package/schemas/doctor-report-v1.json +105 -0
  147. package/schemas/snapshot-v2.json +1002 -0
  148. package/skills/better-supabase/SKILL.md +84 -0
  149. package/skills/better-supabase/references/plugins.md +56 -0
  150. package/skills/better-supabase/references/troubleshooting.md +39 -0
  151. package/skills/better-supabase-api/SKILL.md +67 -0
  152. package/skills/better-supabase-api/references/adapters.md +108 -0
  153. package/skills/better-supabase-testing/SKILL.md +65 -0
  154. package/index.js +0 -1
@@ -0,0 +1,76 @@
1
+ import { E as SchemaMeta } from "./types-C2fslP1z.js";
2
+ import { f as OpenApiParameter } from "./index-JXHBuS53.js";
3
+ //#region src/openapi/index.d.ts
4
+ type Json = Record<string, unknown>;
5
+ type ResourceOperation = "list" | "get" | "create" | "update" | "delete";
6
+ interface ResourceOptions {
7
+ /** Defaults to every operation for tables, `list` and `get` for views. */
8
+ readonly operations?: readonly ResourceOperation[];
9
+ /** Parameters for `list`, from `defineListQuery`. */
10
+ readonly list?: {
11
+ readonly openapi: readonly OpenApiParameter[];
12
+ };
13
+ /** Path of the collection. Defaults to `/<table>`. */
14
+ readonly path?: string;
15
+ readonly tag?: string;
16
+ readonly description?: string;
17
+ }
18
+ interface OpenApiOptions {
19
+ readonly info: {
20
+ readonly title: string;
21
+ readonly version: string;
22
+ readonly description?: string;
23
+ };
24
+ readonly servers?: readonly {
25
+ readonly url: string;
26
+ readonly description?: string;
27
+ }[];
28
+ /** Prefix for every path, e.g. `/api`. */
29
+ readonly basePath?: string;
30
+ /** Tables to publish, by app key. */
31
+ readonly resources: Readonly<Record<string, ResourceOptions | true>>;
32
+ /**
33
+ * Security schemes. `bearer` is a Supabase access token; `oauth2` uses the
34
+ * Supabase OAuth server and needs `supabaseUrl`. Defaults to `['bearer']`.
35
+ */
36
+ readonly security?: readonly ("bearer" | "oauth2")[];
37
+ readonly supabaseUrl?: string;
38
+ /** Tables with a JSON column typed in `better-supabase.config.ts`. */
39
+ readonly json?: Readonly<Record<string, unknown>>;
40
+ }
41
+ interface OpenApiDocument {
42
+ readonly openapi: string;
43
+ readonly info: OpenApiOptions["info"];
44
+ readonly jsonSchemaDialect: string;
45
+ readonly servers?: OpenApiOptions["servers"];
46
+ readonly tags: readonly {
47
+ readonly name: string;
48
+ readonly description?: string;
49
+ }[];
50
+ readonly paths: Readonly<Record<string, Json>>;
51
+ readonly components: {
52
+ readonly schemas: Readonly<Record<string, Json>>;
53
+ readonly responses: Readonly<Record<string, Json>>;
54
+ readonly securitySchemes: Readonly<Record<string, Json>>;
55
+ };
56
+ readonly security: readonly Readonly<Record<string, readonly string[]>>[];
57
+ }
58
+ /** JSON Schema for RFC 9457 Problem Details as better-supabase sends them. */
59
+ declare const PROBLEM_SCHEMA: Json;
60
+ /**
61
+ * An OpenAPI 3.1 document for REST resources over your tables, with schemas
62
+ * from the generated metadata, list-query parameters, Supabase security
63
+ * schemes and Problem Details errors.
64
+ *
65
+ * ```ts
66
+ * const doc = createOpenApi(sb, {
67
+ * info: { title: 'CRM API', version: '1.0.0' },
68
+ * resources: { customers: { list: customerList }, notes: { operations: ['list', 'get'] } },
69
+ * });
70
+ * ```
71
+ */
72
+ declare function createOpenApi(sb: {
73
+ readonly meta: SchemaMeta;
74
+ }, options: OpenApiOptions): OpenApiDocument;
75
+ //#endregion
76
+ export { ResourceOptions as a, ResourceOperation as i, OpenApiOptions as n, createOpenApi as o, PROBLEM_SCHEMA as r, OpenApiDocument as t };
@@ -0,0 +1,117 @@
1
+ import { N as UniqueWhere, P as Update, h as Insert, k as TableKey, n as AnyModels, t as AnyFunctions, y as PrimaryKeyValue } from "./types-C2fslP1z.js";
2
+ import { _ as DbException } from "./result-CTkCZ6JA.js";
3
+ import { C as FindExt, Ct as WhereInput, M as UpsertArgs, N as WriteArgs, S as DeleteExt, T as OffsetPageArgs, X as InferResult, Z as QuerySpec, _ as CursorPage, it as AggregateResult, j as UpdateArgs, k as Returned, l as CacheAdapter, lt as FindFirstArgs, rt as AggregateArgs, st as CountArgs, t as BetterSupabase, ut as FindManyArgs, v as CursorPageArgs, vt as Payload, w as OffsetPage, x as DeleteArgs, y as Db, yt as ReadArgs } from "./define-CTfWw-SS.js";
4
+ import { DataTag, InfiniteData, QueryClient, SkipToken } from "@tanstack/query-core";
5
+ //#region src/query/invalidate.d.ts
6
+ /** Carried by every better-supabase query: the tables whose changes make it stale. */
7
+ interface BetterQueryMeta {
8
+ readonly bsTables: readonly string[];
9
+ readonly [key: string]: unknown;
10
+ }
11
+ /**
12
+ * Invalidates every query that read one of `tables`: better-supabase queries
13
+ * by their `meta.bsTables`, and other `['bs', table, ...]` keys by prefix.
14
+ */
15
+ declare function invalidateTables(client: QueryClient, tables: readonly string[]): Promise<void>;
16
+ //#endregion
17
+ //#region src/query/index.d.ts
18
+ type QueryKeyOf<T> = DataTag<readonly unknown[], T, DbException>;
19
+ type QueryFnOf<T> = ((context: {
20
+ readonly signal: AbortSignal;
21
+ }) => Promise<T>) | SkipToken;
22
+ /** Options for `useQuery`, `createQuery`, `injectQuery`, `queryClient.fetchQuery` and `prefetchQuery`. */
23
+ interface QueryOptionsOf<T> {
24
+ readonly queryKey: QueryKeyOf<T>;
25
+ readonly queryFn: QueryFnOf<T>;
26
+ readonly meta: BetterQueryMeta;
27
+ readonly staleTime?: number;
28
+ }
29
+ /** Options for infinite queries over cursor (`string | null`) or offset (`number`) pages. */
30
+ interface InfiniteOptionsOf<P, Param> {
31
+ readonly queryKey: DataTag<readonly unknown[], InfiniteData<P>, DbException>;
32
+ readonly queryFn: (context: {
33
+ readonly signal: AbortSignal;
34
+ readonly pageParam: Param;
35
+ }) => Promise<P>;
36
+ readonly initialPageParam: Param;
37
+ readonly getNextPageParam: (last: P) => Param | undefined;
38
+ readonly meta: BetterQueryMeta;
39
+ readonly staleTime?: number;
40
+ }
41
+ /** Options for `useMutation`. Invalidates every query that read a changed table. */
42
+ interface MutationOptionsOf<V, R> {
43
+ readonly mutationKey: readonly unknown[];
44
+ readonly mutationFn: (variables: V) => Promise<R>;
45
+ readonly onSuccess: (data: R, variables: V, onMutateResult: unknown, context: {
46
+ readonly client: QueryClient;
47
+ }) => Promise<void>;
48
+ }
49
+ interface TableQueries<M extends AnyModels, T extends TableKey<M>, E> {
50
+ /** Prefix of every key for this table's own queries. */
51
+ readonly key: readonly ["bs", T];
52
+ findMany<const A extends FindManyArgs<M, T> & FindExt<E, M, T>>(args?: A | SkipToken): QueryOptionsOf<Payload<M, T, A>[]>;
53
+ findFirst<const A extends FindFirstArgs<M, T> & FindExt<E, M, T>>(args?: A | SkipToken): QueryOptionsOf<Payload<M, T, A> | null>;
54
+ findUnique<const A extends ReadArgs<M, T> & {
55
+ readonly where: UniqueWhere<M, T>;
56
+ } & FindExt<E, M, T>>(args: A | SkipToken): QueryOptionsOf<Payload<M, T, A> | null>;
57
+ findById<const A extends ReadArgs<M, T> & FindExt<E, M, T>>(id: PrimaryKeyValue<M, T> | SkipToken, args?: A): QueryOptionsOf<Payload<M, T, A>>;
58
+ count(args?: (CountArgs<M, T> & FindExt<E, M, T>) | SkipToken): QueryOptionsOf<number>;
59
+ aggregate<const A extends AggregateArgs<M, T> & FindExt<E, M, T>>(args: A | SkipToken): QueryOptionsOf<AggregateResult<M, T, A>>;
60
+ exists(args?: ({
61
+ readonly where?: WhereInput<M, T>;
62
+ } & FindExt<E, M, T>) | SkipToken): QueryOptionsOf<boolean>;
63
+ paginate<const A extends OffsetPageArgs<M, T> & FindExt<E, M, T>>(args: A | SkipToken): QueryOptionsOf<OffsetPage<Payload<M, T, A>>>;
64
+ /** Cursor pages for `useInfiniteQuery`. */
65
+ infinite<const A extends Omit<CursorPageArgs<M, T>, "after"> & FindExt<E, M, T>>(args: A): InfiniteOptionsOf<CursorPage<Payload<M, T, A>>, string | null>;
66
+ /** Numbered pages for `useInfiniteQuery`, starting at `args.page` (default 1). */
67
+ infinitePages<const A extends OffsetPageArgs<M, T> & FindExt<E, M, T>>(args: A): InfiniteOptionsOf<OffsetPage<Payload<M, T, A>>, number>;
68
+ create<const A extends WriteArgs<M, T> = {}>(args?: A): MutationOptionsOf<Insert<M, T>, Returned<M, T, A>>;
69
+ update<const A extends UpdateArgs<M, T> = {}>(args?: A): MutationOptionsOf<{
70
+ readonly id: PrimaryKeyValue<M, T>;
71
+ readonly patch: Update<M, T>;
72
+ }, Returned<M, T, A>>;
73
+ upsert<const A extends UpsertArgs<M, T> = {}>(args?: A): MutationOptionsOf<Insert<M, T>, Returned<M, T, A>>;
74
+ delete(args?: DeleteArgs & DeleteExt<E, M, T>): MutationOptionsOf<PrimaryKeyValue<M, T>, void>;
75
+ }
76
+ type RpcArgsOf<F extends AnyFunctions, N extends keyof F> = F[N]["Args"];
77
+ interface QueryHelpers<M extends AnyModels, F extends AnyFunctions> {
78
+ /** Prefix of every better-supabase key. */
79
+ readonly key: readonly ["bs"];
80
+ /** Query options for a `QuerySpec`, for example one sent from a Server Component. */
81
+ $spec<S extends QuerySpec<TableKey<M>>>(spec: S | SkipToken): QueryOptionsOf<InferResult<S>>;
82
+ /** Fetches a spec into `queryClient` for server rendering and hydration. */
83
+ $prefetch(queryClient: QueryClient, spec: QuerySpec<TableKey<M>>): Promise<void>;
84
+ /** Query options for a database function. `tables` lists what it reads, for invalidation. */
85
+ $rpc<N extends Extract<keyof F, string>>(name: N, args?: RpcArgsOf<F, N> | SkipToken, options?: {
86
+ readonly tables?: readonly TableKey<M>[];
87
+ }): QueryOptionsOf<F[N]["Returns"]>;
88
+ /** Mutation options for a database function; invalidates what `sb.defineRpc` declared. */
89
+ $rpcMutation<N extends Extract<keyof F, string>>(name: N): MutationOptionsOf<RpcArgsOf<F, N>, F[N]["Returns"]>;
90
+ }
91
+ type Queries<M extends AnyModels, E, F extends AnyFunctions = AnyFunctions> = { readonly [T in TableKey<M>]: TableQueries<M, T, E>; } & QueryHelpers<M, F>;
92
+ interface CreateQueriesOptions {
93
+ /**
94
+ * `staleTime` for every query option. Set it above zero when rendering on
95
+ * the server so hydrated data isn't refetched on mount.
96
+ */
97
+ readonly staleTime?: number;
98
+ }
99
+ /**
100
+ * TanStack Query option factories for every table, framework-neutral: pass
101
+ * them to `useQuery` (React), `createQuery` (Svelte, Solid), `useQuery`
102
+ * (Vue) or `injectQuery` (Angular). Payload types flow into the cache, errors
103
+ * are `DbException`s, and mutations invalidate every query that read a
104
+ * changed table.
105
+ *
106
+ * ```ts
107
+ * const q = createQueries(sb, () => browser.db);
108
+ * const { data } = useQuery(q.customers.findMany({ select: ['id', 'name'] }));
109
+ * ```
110
+ */
111
+ declare function createQueries<M extends AnyModels, D, F extends AnyFunctions, E>(sb: BetterSupabase<M, D, F, E>, db: Db<M, F, E, unknown> | (() => Db<M, F, E, unknown>), options?: CreateQueriesOptions): Queries<M, E, F>;
112
+ /** Invalidates every query that read a table in the target. */
113
+ declare function queryCache(client: QueryClient): CacheAdapter;
114
+ /** Invalidates affected queries for every mutation and declared RPC `sb` performs in this runtime. */
115
+ declare function invalidateOnMutation<M extends AnyModels, D, F extends AnyFunctions, E>(sb: BetterSupabase<M, D, F, E>, client: QueryClient): () => void;
116
+ //#endregion
117
+ export { QueryHelpers as a, TableQueries as c, queryCache as d, BetterQueryMeta as f, Queries as i, createQueries as l, InfiniteOptionsOf as n, QueryKeyOf as o, invalidateTables as p, MutationOptionsOf as r, QueryOptionsOf as s, CreateQueriesOptions as t, invalidateOnMutation as u };
@@ -0,0 +1,71 @@
1
+ import { StandardSchemaV1 } from "@standard-schema/spec";
2
+ import { SupabaseEnv } from "@supabase/server";
3
+ //#region src/env/index.d.ts
4
+ /** Validated Supabase settings. Only `publicEnv()` of it is safe to ship to a browser. */
5
+ interface BetterSupabaseEnv {
6
+ readonly url: string;
7
+ readonly publishableKey: string;
8
+ readonly secretKey?: string;
9
+ /** Named secret keys from `SUPABASE_SECRET_KEYS`, including `default` when `secretKey` is set. */
10
+ readonly secretKeys?: Readonly<Record<string, string>>;
11
+ /** `SUPABASE_JWKS_URL`, or `<url>/auth/v1/.well-known/jwks.json`. */
12
+ readonly jwksUrl: URL;
13
+ /** Direct Postgres connection string (`SUPABASE_DB_URL` / `DATABASE_URL`). */
14
+ readonly dbUrl?: string;
15
+ /** Project ref for hosted projects (`<ref>.supabase.co`). */
16
+ readonly projectRef?: string;
17
+ /** `SUPABASE_READ_URL`: a read replica or the `<ref>-all` load balancer, for reads. */
18
+ readonly readUrl?: string;
19
+ }
20
+ interface PublicEnv {
21
+ readonly url: string;
22
+ readonly publishableKey: string;
23
+ }
24
+ type EnvSource = Readonly<Record<string, string | undefined>>;
25
+ interface EnvIssue {
26
+ /** The variable names that were checked, first one preferred. */
27
+ readonly variables: readonly string[];
28
+ readonly message: string;
29
+ }
30
+ interface EnvOptions {
31
+ /** Settings that must be present. `url` and `publishableKey` always are. */
32
+ readonly require?: readonly ("secretKey" | "dbUrl")[];
33
+ }
34
+ type EnvResult = {
35
+ readonly ok: true;
36
+ readonly env: BetterSupabaseEnv;
37
+ readonly issues?: undefined;
38
+ } | {
39
+ readonly ok: false;
40
+ readonly env?: undefined;
41
+ readonly issues: readonly EnvIssue[];
42
+ };
43
+ declare const ENV_VARIABLES: {
44
+ readonly url: readonly string[];
45
+ readonly publishableKey: readonly string[];
46
+ readonly secretKey: readonly string[];
47
+ readonly dbUrl: readonly string[];
48
+ readonly jwksUrl: readonly string[];
49
+ readonly readUrl: readonly string[];
50
+ };
51
+ declare class EnvValidationError extends Error {
52
+ override readonly name = "EnvValidationError";
53
+ readonly issues: readonly EnvIssue[];
54
+ constructor(issues: readonly EnvIssue[]);
55
+ }
56
+ /**
57
+ * Reads and validates Supabase settings. Accepts the `SUPABASE_`,
58
+ * `NEXT_PUBLIC_`, `VITE_`, `PUBLIC_`, `EXPO_PUBLIC_` and `NUXT_PUBLIC_`
59
+ * spellings. Issues name variables, never values.
60
+ */
61
+ declare function parseEnv(source: EnvSource, options?: EnvOptions): EnvResult;
62
+ /** Like `parseEnv`, but throws `EnvValidationError`. Reads `process.env` by default. */
63
+ declare function loadEnv(source?: EnvSource, options?: EnvOptions): BetterSupabaseEnv;
64
+ /** The env validator as a Standard Schema, for t3-env, framework config or any validator slot. */
65
+ declare function envSchema(options?: EnvOptions): StandardSchemaV1<EnvSource, BetterSupabaseEnv>;
66
+ /** The parts that are safe in client bundles. */
67
+ declare function publicEnv(env: BetterSupabaseEnv): PublicEnv;
68
+ /** Converts to `@supabase/server`'s `SupabaseEnv` (the `env` option of `withSupabase`). */
69
+ declare function toServerEnv(env: BetterSupabaseEnv): SupabaseEnv;
70
+ //#endregion
71
+ export { EnvResult as a, PublicEnv as c, parseEnv as d, publicEnv as f, EnvOptions as i, envSchema as l, ENV_VARIABLES as n, EnvSource as o, toServerEnv as p, EnvIssue as r, EnvValidationError as s, BetterSupabaseEnv as t, loadEnv as u };
@@ -0,0 +1,116 @@
1
+ import { p as DbError } from "./result-CTkCZ6JA.js";
2
+ import { Z as QuerySpec } from "./define-CTfWw-SS.js";
3
+ import { i as BrowserAuth, t as AuthSnapshot } from "./index-Sw43J8HG.js";
4
+ import { n as TemplateValues } from "./template-mbvlysOo.js";
5
+ import { t as AuthSession } from "./view-B0ltUmTi.js";
6
+ import { a as LiveSource, g as Topic, h as SubscriptionStatus, p as SubscribeOptions, r as LiveCountSeed, u as EventSchemas, v as TopicHandlers, y as TopicMessage } from "./live-6b9i72Ux.js";
7
+ import "./entitlements-BBg61DQZ.js";
8
+ import "./session-C3osL21k.js";
9
+ import { SupabaseClient } from "@supabase/supabase-js";
10
+ import { ReactNode } from "react";
11
+ import { StandardSchemaV1 } from "@standard-schema/spec";
12
+ import { QueryClient } from "@tanstack/query-core";
13
+ //#region src/react/index.d.ts
14
+ /** The parts of `createBrowser()` the provider needs. */
15
+ interface BrowserLike {
16
+ readonly sb: LiveSource;
17
+ readonly supabase: SupabaseClient;
18
+ readonly auth: BrowserAuth;
19
+ readonly db: object;
20
+ readonly queries: object;
21
+ }
22
+ interface BetterSupabaseProviderProps {
23
+ readonly browser: BrowserLike;
24
+ /** better-supabase queries are removed when the user signs out or changes. */
25
+ readonly queryClient?: QueryClient;
26
+ readonly children?: ReactNode;
27
+ }
28
+ /** Provides the browser client to the hooks. */
29
+ declare function BetterSupabaseProvider(props: BetterSupabaseProviderProps): ReactNode;
30
+ /** The session state for UI: `loading`, `signed-out` or `signed-in` with the user and claims. */
31
+ declare function useAuth(): AuthSnapshot;
32
+ declare function useSupabase(): SupabaseClient;
33
+ interface BetterHooks<B extends BrowserLike> {
34
+ /** Repositories bound to the current session. Re-renders when the user changes. */
35
+ readonly useDb: () => B["db"];
36
+ /** TanStack Query option factories: `useQuery(useQueries().customers.findMany())`. */
37
+ readonly useQueries: () => B["queries"];
38
+ readonly useSupabase: () => SupabaseClient;
39
+ readonly useAuth: () => AuthSnapshot;
40
+ /** `useSession()` with the claims typed by the browser's `sb.claims(schema)`. */
41
+ readonly useSession: () => AuthSession<ClaimsOf<B>>;
42
+ }
43
+ /** The claims type of a browser's `sb.claims(schema)`, `unknown` without one. */
44
+ type ClaimsOf<B extends BrowserLike> = B["sb"] extends {
45
+ readonly claimsSchema: StandardSchemaV1<unknown, infer C> | undefined;
46
+ } ? C : unknown;
47
+ /**
48
+ * Hooks typed for your schema.
49
+ *
50
+ * ```ts
51
+ * export const { useDb, useQueries, useAuth } = createHooks<typeof browser>();
52
+ * ```
53
+ */
54
+ declare function createHooks<B extends BrowserLike>(): BetterHooks<B>;
55
+ interface BroadcastOptions extends Omit<SubscribeOptions, "onStatus"> {
56
+ /**
57
+ * Refetch after each message: table keys (every query that read one of
58
+ * them), or a function returning query keys. Needs `queryClient` on the
59
+ * provider.
60
+ */
61
+ readonly invalidate?: readonly string[] | ((message: TopicMessage) => readonly (readonly unknown[])[]);
62
+ }
63
+ /**
64
+ * Subscribes to a topic while mounted. Pass `null` values to pause. It
65
+ * resubscribes when the topic or the signed-in user changes.
66
+ *
67
+ * ```ts
68
+ * useBroadcast(customersTopic, orgId ? { orgId } : null, {}, { invalidate: ['customers'] });
69
+ * ```
70
+ */
71
+ declare function useBroadcast<P extends string, E extends EventSchemas>(topic: Topic<P, E>, values: TemplateValues<P> | null | undefined, handlers?: TopicHandlers<E>, options?: BroadcastOptions): SubscriptionStatus;
72
+ interface LiveQueryHookOptions {
73
+ /**
74
+ * Tenant for tenant-scoped tables. Defaults to the `org_id` claim
75
+ * (top-level or in `app_metadata`).
76
+ */
77
+ readonly tenant?: string;
78
+ /** Defaults to 100 ms. */
79
+ readonly debounceMs?: number;
80
+ }
81
+ /**
82
+ * Keeps a query fresh: invalidates every cached query that read a table the
83
+ * spec touches whenever one of them changes. Pass `null` to pause. It
84
+ * resubscribes when the spec, tenant or user changes.
85
+ *
86
+ * ```ts
87
+ * const spec = sb.spec.customers.findMany({ include: { notes: true } });
88
+ * const { data } = useQuery(q.$spec(spec));
89
+ * useLiveQuery(spec);
90
+ * ```
91
+ */
92
+ declare function useLiveQuery(spec: QuerySpec | null | undefined, options?: LiveQueryHookOptions): SubscriptionStatus;
93
+ interface LiveCountHookOptions extends LiveQueryHookOptions {
94
+ /** The count to show before the first fetch, e.g. from the server. */
95
+ readonly initial?: number;
96
+ }
97
+ interface LiveCount {
98
+ /** `undefined` until the first count arrives. */
99
+ readonly count: number | undefined;
100
+ readonly status: SubscriptionStatus;
101
+ /** The last failed refetch; the previous count stays. */
102
+ readonly error: DbError | undefined;
103
+ }
104
+ /**
105
+ * A count that stays current: refetches only the `count` spec (a HEAD
106
+ * request) after each debounced change to a table it reads, and after the
107
+ * channel rejoins. Takes a spec or a `next.liveCount()` seed; pass `null` to
108
+ * pause. Doesn't need a `QueryClient`.
109
+ *
110
+ * ```tsx
111
+ * const { count } = useLiveCount(seed); // seed = await next.liveCount(spec)
112
+ * ```
113
+ */
114
+ declare function useLiveCount(source: QuerySpec<string, "count", number> | LiveCountSeed | null | undefined, options?: LiveCountHookOptions): LiveCount;
115
+ //#endregion
116
+ export { BrowserLike as a, LiveCountHookOptions as c, useAuth as d, useBroadcast as f, useSupabase as h, BroadcastOptions as i, LiveQueryHookOptions as l, useLiveQuery as m, BetterSupabaseProvider as n, ClaimsOf as o, useLiveCount as p, BetterSupabaseProviderProps as r, LiveCount as s, BetterHooks as t, createHooks as u };
@@ -0,0 +1,144 @@
1
+ import { k as TableKey, n as AnyModels, t as AnyFunctions, w as Row } from "./types-C2fslP1z.js";
2
+ import { l as CountMode } from "./executor-Bazhgsgq.js";
3
+ import { b as ValidationIssue, t as AsyncResult } from "./result-CTkCZ6JA.js";
4
+ import { C as FindExt, Ct as WhereInput, O as RepositoryOf, T as OffsetPageArgs, dt as IncludeArg, gt as OrderByArg, t as BetterSupabase, vt as Payload, w as OffsetPage, xt as SelectArg } from "./define-CTfWw-SS.js";
5
+ import { StandardSchemaV1 } from "@standard-schema/spec";
6
+ //#region src/list/index.d.ts
7
+ /** Facet value meaning "not set": filters with `is null`. */
8
+ declare const UNSET = "__unset__";
9
+ type Column<M extends AnyModels, T extends keyof M> = Extract<keyof Row<M, T>, string>;
10
+ type TextColumn<M extends AnyModels, T extends keyof M> = { [K in Column<M, T>]: [NonNullable<Row<M, T>[K]>] extends [string] ? K : never; }[Column<M, T>];
11
+ interface ListQueryConfig<M extends AnyModels, T extends keyof M, S extends string, F extends string, C extends boolean = boolean> {
12
+ /**
13
+ * Also count rows per facet value, with one grouped aggregate that runs
14
+ * next to the page: 2 calls, 1 wave. Needs PostgREST aggregates.
15
+ */
16
+ readonly facetCounts?: C;
17
+ /** How the page total is counted. Defaults to `'exact'`. */
18
+ readonly count?: CountMode;
19
+ /** Text columns matched case-insensitively (OR), or a full-text column. */
20
+ readonly search?: readonly TextColumn<M, T>[] | {
21
+ readonly fts: Column<M, T>;
22
+ readonly config?: string;
23
+ };
24
+ /** Filterable columns by URL key. Values are validated against enums and CHECK unions. */
25
+ readonly facets?: { readonly [K in F]: Column<M, T>; };
26
+ /** Named orderings. Add a unique column last for stable pages. */
27
+ readonly sorts: { readonly [K in S]: OrderByArg<M, T>; };
28
+ readonly defaultSort: NoInfer<S>;
29
+ /** Defaults to 50. */
30
+ readonly pageSize?: number;
31
+ /** Defaults to 200. */
32
+ readonly maxPageSize?: number;
33
+ /** Defaults to 200 characters. */
34
+ readonly maxSearchLength?: number;
35
+ }
36
+ interface ListQuery<S extends string, F extends string> {
37
+ readonly q?: string;
38
+ readonly sort: S;
39
+ /** 1-based. */
40
+ readonly page: number;
41
+ readonly size: number;
42
+ readonly facets: { readonly [K in F]?: readonly string[]; };
43
+ }
44
+ /** Typed input (JSON APIs, actions, MCP tools). Everything is optional. */
45
+ interface ListQueryInput<S extends string, F extends string> {
46
+ readonly q?: string;
47
+ readonly sort?: S;
48
+ readonly page?: number;
49
+ readonly size?: number;
50
+ readonly facets?: { readonly [K in F]?: readonly string[]; };
51
+ }
52
+ /** URL input: `URLSearchParams` or a Next.js `searchParams` record. */
53
+ type ListSearchParams = URLSearchParams | Readonly<Record<string, string | readonly string[] | undefined>>;
54
+ type ListParseResult<S extends string, F extends string> = {
55
+ readonly ok: true;
56
+ readonly value: ListQuery<S, F>;
57
+ readonly issues?: undefined;
58
+ } | {
59
+ readonly ok: false;
60
+ readonly value?: undefined;
61
+ readonly issues: readonly ValidationIssue[];
62
+ };
63
+ interface ParserSpec<V> {
64
+ parse(value: string): V | null;
65
+ serialize(value: V): string;
66
+ }
67
+ interface OpenApiParameter {
68
+ readonly name: string;
69
+ readonly in: "query";
70
+ readonly required: false;
71
+ readonly description: string;
72
+ readonly schema: Readonly<Record<string, unknown>>;
73
+ readonly style?: "form";
74
+ readonly explode?: boolean;
75
+ }
76
+ interface FacetInfo {
77
+ readonly key: string;
78
+ readonly column: string;
79
+ readonly nullable: boolean;
80
+ /** Allowed values when the column is an enum or CHECK union. */
81
+ readonly values?: readonly string[];
82
+ }
83
+ /** Rows per facet value, keyed by facet and then by value (`UNSET` for empty). */
84
+ type FacetCounts<F extends string> = { readonly [K in F]: Readonly<Record<string, number>>; };
85
+ /** A page of a list; with `facetCounts: true`, also the counts per facet value. */
86
+ type ListPage<R, F extends string, C extends boolean> = OffsetPage<R> & ([C] extends [true] ? {
87
+ readonly facetCounts: FacetCounts<F>;
88
+ } : [C] extends [false] ? unknown : {
89
+ readonly facetCounts?: FacetCounts<F>;
90
+ });
91
+ interface ListDefinition<M extends AnyModels, T extends TableKey<M>, E, S extends string, F extends string, C extends boolean = false> {
92
+ readonly table: T;
93
+ readonly defaults: ListQuery<S, F>;
94
+ readonly facets: readonly FacetInfo[];
95
+ /** Validates typed input or URL params. Also a Standard Schema (`schema`). */
96
+ parse(input: ListQueryInput<S, F> | ListSearchParams | undefined): ListParseResult<S, F>;
97
+ readonly schema: StandardSchemaV1<ListQueryInput<S, F> | ListSearchParams | undefined, ListQuery<S, F>>;
98
+ /** URL params, leaving out defaults. */
99
+ toSearchParams(query: Partial<ListQuery<S, F>>): URLSearchParams;
100
+ /** `{ parse, serialize }` per URL key, for routers and nuqs (`list.nuqs(createParser)`). */
101
+ readonly parsers: ListParsers<S, F>;
102
+ nuqs<P>(createParser: (spec: ParserSpec<unknown>) => P): { readonly [K in keyof ListParsers<S, F>]: P; };
103
+ /** Repository arguments: `where`, `orderBy`, `page`, `size`, `count`. */
104
+ args(query: ListQuery<S, F>): OffsetPageArgs<M, T>;
105
+ /**
106
+ * Runs the list against a table, merging your `select`, `include`, `where`
107
+ * and `count`. One request, plus one for `facetCounts`, always one wave.
108
+ */
109
+ run<const A extends ListExtra<M, T> & FindExt<E, M, T>>(db: { readonly [K in T]: RepositoryOf<M, K, E>; }, query: ListQuery<S, F>, extra?: A): AsyncResult<ListPage<Payload<M, T, A>, F, C>>;
110
+ /** OpenAPI 3.1 query parameters. */
111
+ readonly openapi: readonly OpenApiParameter[];
112
+ /** JSON Schema of the typed input, e.g. for MCP tool arguments. */
113
+ readonly jsonSchema: Readonly<Record<string, unknown>>;
114
+ }
115
+ interface ListExtra<M extends AnyModels, T extends keyof M> {
116
+ readonly select?: SelectArg<M, T>;
117
+ readonly include?: IncludeArg<M, T>;
118
+ readonly where?: WhereInput<M, T>;
119
+ /** Overrides the config's `count` for this run. */
120
+ readonly count?: CountMode;
121
+ }
122
+ type ListParsers<S extends string, F extends string> = {
123
+ readonly q: ParserSpec<string>;
124
+ readonly sort: ParserSpec<S>;
125
+ readonly page: ParserSpec<number>;
126
+ readonly size: ParserSpec<number>;
127
+ } & { readonly [K in F]: ParserSpec<readonly string[]>; };
128
+ /**
129
+ * A reusable list endpoint for one table: search, facets, sorts and
130
+ * pagination, validated from URL params or typed input, with URL parsers,
131
+ * OpenAPI parameters and a JSON Schema derived from the same definition.
132
+ *
133
+ * ```ts
134
+ * export const customerList = defineListQuery(sb, 'customers', {
135
+ * search: ['name', 'kvk'],
136
+ * facets: { status: 'status' },
137
+ * sorts: { name: { name: 'asc' }, newest: [{ createdAt: 'desc' }, { id: 'asc' }] },
138
+ * defaultSort: 'newest',
139
+ * });
140
+ * ```
141
+ */
142
+ declare function defineListQuery<M extends AnyModels, D, Fn extends AnyFunctions, E, T extends TableKey<M>, const S extends string, const F extends string = never, const C extends boolean = false>(sb: BetterSupabase<M, D, Fn, E>, table: T, config: ListQueryConfig<M, T, S, F, C>): ListDefinition<M, T, E, S, F, C>;
143
+ //#endregion
144
+ export { ListPage as a, ListQuery as c, ListSearchParams as d, OpenApiParameter as f, defineListQuery as h, ListExtra as i, ListQueryConfig as l, UNSET as m, FacetInfo as n, ListParseResult as o, ParserSpec as p, ListDefinition as r, ListParsers as s, FacetCounts as t, ListQueryInput as u };