@specific.dev/spectest 0.45.0 → 0.46.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.
@@ -1,6 +1,7 @@
1
- import { type ServiceGroup, type ServicesMap } from "../index.js";
1
+ import { type ServiceDefinition, type ServiceGroup, type ServicesMap } from "../index.js";
2
2
  import { type SqlClient } from "../sql.js";
3
3
  import { type EmailHelpers } from "./email.js";
4
+ export type { MailTemplateId, MailTemplateSpec } from "./supabase-config.js";
4
5
  export interface SupabaseOptions {
5
6
  /**
6
7
  * Key of the API-gateway service and the prefix for every other piece.
@@ -22,25 +23,16 @@ export interface SupabaseOptions {
22
23
  * deterministically, so the warm-template cache stays stable.
23
24
  */
24
25
  jwtSecret?: string;
25
- /** Studio dashboard Basic-Auth username (only relevant with `studio`). Default `"supabase"`. */
26
- dashboardUsername?: string;
27
- /** Studio dashboard Basic-Auth password (only relevant with `studio`). */
28
- dashboardPassword?: string;
29
- /** Include GoTrue auth (`<name>-auth`). Default `true`. */
30
- auth?: boolean;
26
+ /**
27
+ * GoTrue auth. `false` drops it from the stack; an object configures the
28
+ * two settings that are **addresses in this environment** rather than
29
+ * behaviour — everything else about auth comes from your `config.toml`.
30
+ */
31
+ auth?: boolean | SupabaseAuthOptions;
31
32
  /** Include storage-api + imgproxy (`<name>-storage`, `<name>-imgproxy`). Default `true`. */
32
33
  storage?: boolean;
33
34
  /** Include Realtime (`<name>-realtime`). Default `true`. */
34
35
  realtime?: boolean;
35
- /**
36
- * Include the Studio dashboard (`<name>-studio`) and its postgres-meta
37
- * backend (`<name>-meta`). Off by default — Studio is a heavy Next.js image
38
- * and is only useful for interactive `ctx.browser()` exploration, not
39
- * automated backend assertions. Turning it on implies `meta`.
40
- */
41
- studio?: boolean;
42
- /** Include postgres-meta (`<name>-meta`). Defaults to whatever `studio` is. */
43
- meta?: boolean;
44
36
  /**
45
37
  * Also serve the gateway over **HTTPS** at `https://<hostname>` via the
46
38
  * daemon's CA-trusted TLS reverse proxy (in addition to the plain
@@ -83,75 +75,130 @@ export interface SupabaseOptions {
83
75
  serviceRole?: string[];
84
76
  };
85
77
  /**
86
- * Where the project's SQL migrations live, e.g. `"supabase/migrations"`
87
- * (relative to the project root, or absolute). **Nothing is applied unless
88
- * you set this** — there is no assumed path, so a project whose schema
89
- * arrives some other way (an app that migrates itself at boot, a dump
90
- * restored in `setup`) never gets a second, surprising source of DDL.
91
- *
92
- * Every `*.sql` directly in the directory is applied in sorted filename
93
- * order, then — the standard Supabase layout — the **`seed.sql` beside
94
- * that directory**, if there is one:
78
+ * The project's Supabase folder, e.g. `"supabase"` (relative to the project
79
+ * root, or absolute) — the layout `supabase init` creates and the CLI
80
+ * requires. This is the **only** way to point the stack at your project, and
81
+ * everything in the folder is used the way the Supabase CLI uses it:
95
82
  *
96
83
  * ```
97
84
  * supabase/
98
- * migrations/0001_init.sql ← applied, sorted
99
- * migrations/0002_todos.sql
100
- * seed.sql ← applied last
85
+ * config.toml ← auth rules, mail templates, per-function JWT verification
86
+ * migrations/ ← applied in filename order once the stack is up
87
+ * seed.sql ← applied after them, if it's there
88
+ * functions/ ← one directory per function, served at /functions/v1/<name>
101
89
  * ```
102
90
  *
103
- * It all runs **once the whole stack is up** — the same point `supabase db
104
- * reset` applies migrations — so your SQL may use schema the services
105
- * create when they boot (`storage.buckets`, the modern `auth.*` tables).
106
- * PostgREST's schema cache is reloaded afterwards.
91
+ * `config.json` is read in preference to `config.toml` where a newer CLI has
92
+ * written one. Nothing is derived unless you name the folder, and each piece
93
+ * is optional inside it — a folder with only a `config.toml` is fine.
107
94
  *
108
- * A path that doesn't resolve is an error at env start; a silent no-op
109
- * there surfaces much later as a confusing `relation … does not exist`.
110
- * Because `supabase/**` is project content, editing a migration correctly
111
- * forces a cold rebuild and re-apply (unlike `spectest/tests/**`).
95
+ * There is deliberately no per-piece path option and no way to configure
96
+ * mail, OTP, redirect or JWT behaviour here: those live in `config.toml`,
97
+ * where your project already declares them and where the Supabase CLI reads
98
+ * them too. One source of truth, and the environment matches the one you run
99
+ * locally.
112
100
  */
113
- migrations?: string;
101
+ dir?: string;
114
102
  /**
115
- * Where the project's **edge functions** live, e.g.
116
- * `"supabase/functions"` — one subdirectory per function, each with an
117
- * entrypoint the runtime can serve (`supabase/functions/hello/index.ts`).
103
+ * The `.env` of this environment — the values your `config.toml` reads with
104
+ * `env(...)`.
118
105
  *
119
- * **Nothing runs unless you set this.** Point at the directory and every
120
- * function in it is served on the real Supabase edge runtime at
121
- * `<url>/functions/v1/<name>` through the gateway — the same path
122
- * `supabase.functions.invoke(...)` derives, so the app under test needs no
123
- * override. Leave it unset and the runtime is left out of the stack
124
- * entirely, along with the gateway's `/functions/v1` route.
106
+ * ```toml
107
+ * # supabase/config.toml
108
+ * [edge_runtime.secrets]
109
+ * STRIPE_KEY = "env(STRIPE_SECRET_KEY)"
110
+ * FEATURE_X = "true"
125
111
  *
126
- * Function code is read straight from the repo — nothing is copied or
127
- * bundled — so editing a function is an ordinary project edit.
112
+ * [auth.external.google]
113
+ * client_id = "env(GOOGLE_OAUTH_CLIENT_ID)"
114
+ * ```
115
+ * ```ts
116
+ * supabase({
117
+ * dir: "supabase",
118
+ * env: {
119
+ * STRIPE_SECRET_KEY: "sk_test_…",
120
+ * GOOGLE_OAUTH_CLIENT_ID: "1234.apps.googleusercontent.com",
121
+ * },
122
+ * })
123
+ * ```
124
+ *
125
+ * Keyed exactly as your `supabase/.env` is: by the name inside `env(...)`.
126
+ * That file is what the Supabase CLI resolves against — locally at `start`,
127
+ * and in CI at `config push` / `secrets set` — and it is excluded from the
128
+ * upload here, deliberately, since real credentials should not enter a test
129
+ * environment. This is its stand-in, holding test values.
130
+ *
131
+ * It covers every `env(...)` in the file, not only secrets: a provider's
132
+ * client id is a field on your project's auth settings rather than a named
133
+ * secret, and it reads from the same place.
128
134
  *
129
- * Pass an object instead of a path to turn JWT verification off, or to set
130
- * the function secrets your code reads with `Deno.env.get(...)`.
135
+ * A value reaches your **functions** because `[edge_runtime.secrets]`
136
+ * declares it — `SECRET = "env(NAME)"` — not merely because it is here. A
137
+ * deployed project can have secrets its config never mentions (the dashboard
138
+ * and `supabase secrets set` write straight to the project's store), but
139
+ * declaring them is what makes the test environment's inputs reviewable in
140
+ * the project's own config rather than implicit in its test setup. A name
141
+ * passed here and referenced nowhere is called out in the boot log.
142
+ *
143
+ * A literal in the file needs nothing. An inline `encrypted:` ciphertext
144
+ * cannot be supplied this way at all — it names no variable, and decrypting
145
+ * it needs a `DOTENV_PRIVATE_KEY` a test environment has no business
146
+ * holding — so it is named in the boot log and left unset. Anything else
147
+ * left unresolved is reported the same way, and never passed through as the
148
+ * string `env(NAME)` or as base64.
131
149
  */
132
- functions?: string | SupabaseFunctionsOptions;
150
+ env?: Record<string, string>;
133
151
  }
134
- /** Tuning for `SupabaseOptions.functions`. */
135
- export interface SupabaseFunctionsOptions {
152
+ /** Tuning for {@link SupabaseOptions.auth}. */
153
+ export interface SupabaseAuthOptions {
136
154
  /**
137
- * Directory holding one subdirectory per function, relative to the project
138
- * root (or absolute). Required — there is no assumed location.
155
+ * Where GoTrue sends a user when a flow finishes — the base of every
156
+ * emailed confirmation, recovery and invite link's `redirect_to`, and the
157
+ * fallback when a requested redirect is refused. Defaults to the gateway
158
+ * (`http://<name>:8000`).
159
+ *
160
+ * This is deliberately **not** read from `config.toml`. That file's
161
+ * `site_url` is the developer's own machine (`http://localhost:3000`),
162
+ * which inside a VM is the browser's own namespace rather than the app
163
+ * container — so honouring it would point every redirect at nothing. Set
164
+ * it to the app under test's address in *this* environment:
165
+ *
166
+ * ```ts
167
+ * supabase({ dir: "supabase", auth: { siteUrl: "https://app.test" } })
168
+ * ```
139
169
  */
140
- dir: string;
170
+ siteUrl?: string;
141
171
  /**
142
- * Reject a call that carries no valid JWT, exactly as hosted Supabase
143
- * does. Default `true` — so a test that forgets the `Authorization`
144
- * header fails here instead of in production. Set `false` for the
145
- * `--no-verify-jwt` behaviour (webhooks, public endpoints).
172
+ * Extra addresses a flow may redirect to, beyond `siteUrl` (which GoTrue
173
+ * always allows). Glob patterns, exactly as `config.toml` spells them:
174
+ * `["https://app.test/**"]`.
175
+ *
176
+ * **Redirect validation is off unless you set this.** GoTrue has no switch
177
+ * for it — an empty allow list is its *strictest* state, not its loosest,
178
+ * because a redirect is then refused unless it matches `siteUrl` — so the
179
+ * default here is the wildcard, and a suite is never rejected for a
180
+ * redirect it didn't declare. Set it to make the environment enforce what
181
+ * production enforces; the addresses are per-environment, so they belong
182
+ * here rather than in the config file.
146
183
  */
147
- verifyJwt?: boolean;
184
+ additionalRedirectUrls?: string[];
148
185
  /**
149
- * Extra environment variables the functions read (`Deno.env.get("…")`) —
150
- * the local stand-in for function secrets. `SUPABASE_URL`,
151
- * `SUPABASE_ANON_KEY`, `SUPABASE_SERVICE_ROLE_KEY`, `SUPABASE_DB_URL` and
152
- * `JWT_SECRET` are already set for you.
186
+ * Provider components to serve the config's `[auth.external.*]` blocks
187
+ * with, keyed by the provider name GoTrue uses (`google`, `azure`,
188
+ * `github`, `apple`). **You do not normally need this**: a provider the
189
+ * config enables is stood up automatically with that component's defaults.
190
+ * Supply one to choose the accounts it offers, or to serve a provider this
191
+ * stack has no built-in emulator for:
192
+ *
193
+ * ```ts
194
+ * auth: {
195
+ * providers: {
196
+ * google: google({ users: [{ email: "alice@corp.test", name: "Alice" }] }),
197
+ * },
198
+ * }
199
+ * ```
153
200
  */
154
- env?: Record<string, string>;
201
+ providers?: Record<string, ServiceDefinition>;
155
202
  }
156
203
  /** Tuning for `SupabaseOptions.mail`. */
157
204
  export interface SupabaseMailOptions {
@@ -160,26 +207,14 @@ export interface SupabaseMailOptions {
160
207
  * services-map key) instead of adding one to the group — the way to keep a
161
208
  * single global mailbox when the app under test sends mail too. Assumes
162
209
  * the service's default ports (SMTP 1025, API 8025).
163
- */
164
- service?: string;
165
- /**
166
- * Whether GoTrue confirms a signup without the emailed verification.
167
- * **`true` by default**: signups complete in one step and send no
168
- * confirmation mail, which keeps account creation a single call in the
169
- * suites where it is setup rather than the thing under test.
170
210
  *
171
- * Set `false` to run the flow a hosted project runs: the signup issues no
172
- * session, and the test follows the emailed link out of the mailbox
173
- * exactly as a user would (see `examples/supabase-app`). Recovery,
174
- * magic-link, OTP and invite mail is sent either way. Forced `true` when
175
- * the stack has no mailbox (`mail: false`), since the confirmation would
176
- * go nowhere.
211
+ * This is the only mail option, deliberately. Everything else about mail —
212
+ * whether a signup is confirmed, the sender identity, custom templates and
213
+ * their subjects — is GoTrue behaviour your project already declares in
214
+ * `config.toml` (`[auth.email]`, `[auth.email.smtp]`,
215
+ * `[auth.email.template.*]`), and it is read from there.
177
216
  */
178
- autoconfirm?: boolean;
179
- /** Sender address GoTrue mails from. Default `admin@example.com`. */
180
- adminEmail?: string;
181
- /** Sender display name. Default `Supabase`. */
182
- senderName?: string;
217
+ service?: string;
183
218
  }
184
219
  /** Helpers the gateway service exposes on `ctx.svc.<name>`. */
185
220
  export interface SupabaseHelpers {
@@ -188,6 +223,11 @@ export interface SupabaseHelpers {
188
223
  * `postgres` superuser — every query lands on the test event log and its rows
189
224
  * come back provenance-wrapped, so `expect(...)` on a read links to the
190
225
  * query. Point of direct DB verification alongside the REST/auth surface.
226
+ *
227
+ * The same client the `postgres()` component exposes: a tagged template for
228
+ * ordinary queries, plus `unsafe(text, params?)` for what a template cannot
229
+ * carry — a whole `.sql` file, or a dynamic column list — which is recorded
230
+ * on the timeline just the same. See `spectest docs /components/postgres`.
191
231
  */
192
232
  sql: SqlClient;
193
233
  /** The gateway base URL the app uses as `SUPABASE_URL` (e.g. `http://supabase:8000`). */