feat(cli): generate types natively with postgrest-typegen - #6404
feat(cli): generate types natively with postgrest-typegen#6404avallete wants to merge 9 commits into
Conversation
Replace the pg-meta Docker container behind `gen types` with the new @supabase/postgrest-typegen package, running introspection and language generation in-process over a direct Postgres connection. - New LegacyGenTypesGenerator service seam: the production layer acquires a scoped pg.Pool via legacyAcquirePgPool (full driver parity: TLS mode, DoH resolver, connect-error mapping), feeds it to introspect(), sorts with sortGeneratorMetadata, and renders typescript/go/python/swift. - `--local` connects to the host-mapped db port instead of spawning the pg-meta image inside the stack network; the `container inspect` stack-running check and rest-version v9 forcing are unchanged. The obsolete `.temp/pgmeta-version` image override is removed. - `--db-url` now resolves through the shared LegacyDbConfigResolver (libpq keywords, options=reference pooler tenants, sslmode, PG* env fallbacks), matching every other --db-url command. - Project-ref non-TypeScript paths and the preview-branch fallback keep their Management API flow and IPv4 pooler retry, now classifying the native connect error instead of container stderr. - `--query-timeout` maps to statement_timeout plus the connect timeout, mirroring the PG_QUERY_TIMEOUT_SECS/PG_CONN_TIMEOUT_SECS envs pg-meta received; `--postgrest-v9-compat` disables one-to-one detection in the TypeScript generator; output keeps the trailing newline console.log added in pg-meta. - The pg-meta SSL probe, CA bundle templates, and --network-id container override are gone with the container; the linked TypeScript path still uses the Management API unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RpnbmgTzwdTMkWYF7uFR1V
Validated the native typegen end-to-end against a real Postgres 16 and against postgres-meta 0.98.0 on the same schema, which surfaced two issues: - The driver requires TLS for remote-looking targets, so `gen types --db-url` against a plain-TCP server (common when self-hosting) failed where the pg-meta path adapted via its SSL probe. Restore that adaptivity in the generator layer: when the DSN carries no explicit sslmode, the shared SSLRequest probe decides whether to connect with sslmode=disable; probe failures keep the TLS default so the real connect error still surfaces. - prettier 3.5.3 (postgrest-typegen's pin) trips a Bun bundler renaming bug under `bun build --compile`, breaking TypeScript generation in the compiled binary only. Override it to the repo's prettier 3.9.6, which bundles cleanly; pg-meta itself floated ^3.3.3, so there is no output-parity concern. Parity results against postgres-meta on the same database: TypeScript and Swift byte-identical; Go and Python identical content with canonical sorted entity ordering (sortGeneratorMetadata) instead of pg-meta's environment-dependent row order. Documented in SIDE_EFFECTS.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RpnbmgTzwdTMkWYF7uFR1V
develop's SUPABASE_USE_SLIM_IMAGES change (de133cf) touched gen types only through resolvePgmetaImage and its tests, all of which this branch deletes with the pg-meta container path, so the branch side wins in all four files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RpnbmgTzwdTMkWYF7uFR1V
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6d8c60d5cf
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
0.2.0 drops prettier for oxfmt, so the prettier bundling override goes away. oxfmt's ESM dist resolves its napi binding through createRequire(import.meta.url) and lazily imports optional prettier plugins — neither survives `bun build --compile` — so the CLI: - embeds the platform binding statically (the @parcel/watcher pattern: one @oxfmt/binding-* devDependency per shipped target, dispatched on platform/arch/SUPABASE_LIBC in types.oxfmt.ts) and injects it through the generator's new `format` option, verified byte-equivalent to the package's own default formatter; - marks the never-installed optional prettier plugins external in both the dev and release build scripts (shared bundle-externals.ts). Revalidated against a real Postgres 16 from the compiled binary: Go/Swift/Python output is byte-identical to the 0.1.0 integration; TypeScript content is identical with oxfmt's union-wrapping style (three lines differ from the prettier-era output), and source-run vs compiled-binary output is identical. SIDE_EFFECTS.md parity note updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RpnbmgTzwdTMkWYF7uFR1V
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ebb449be92
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Keep native typegen SIDE_EFFECTS; drop the slim-image pg-meta notes develop added, since this command no longer runs that container. Co-authored-by: Cursor <cursoragent@cursor.com>
Pin the embedded Supabase CA when the SSL probe reports TLS, treat --query-timeout 0 as disabled rather than an immediate connect timeout, let the flag override a DSN statement_timeout, bound introspect() on the client, and classify generator/formatter failures as internal instead of database findings. Co-authored-by: Cursor <cursoragent@cursor.com>
A probe error still leaves sslmode unset so the driver default and IPv6 pooler classification stay intact. Co-authored-by: Cursor <cursoragent@cursor.com>
Drop the duplicate TLS-probe comment, unused network-id test wiring, and a leftover localNetworkId assertion. Clarify that a TLS probe replaces sslrootcert when sslmode is omitted. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 39cb1577fe
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| ? yield* introspectEffect.pipe( | ||
| Effect.timeoutOrElse({ | ||
| duration: Duration.seconds(input.queryTimeoutSeconds), |
There was a problem hiding this comment.
Cancel the database operation when timing out
When an established connection stalls during introspection, this timeout interrupts only the Effect.tryPromise waiter; it does not cancel the underlying pool.query. The fresh evidence after the earlier review is that scope cleanup calls pool.end() through legacyAcquireProbedPool, but an active checked-out query prevents pool.end() from completing, and its one-second timeoutOption neither destroys the client nor closes its socket. Consequently the timeout error may be produced while the live socket still keeps the CLI process running indefinitely; make the foreign boundary cancellable by destroying/cancelling the owned query or pool when this timeout fires.
AGENTS.md reference: AGENTS.md:L92-L97
Useful? React with 👍 / 👎.
| if (typeof SUPABASE_LIBC !== "undefined" && SUPABASE_LIBC === "musl") { | ||
| return require("@oxfmt/binding-linux-x64-musl"); | ||
| } | ||
| return require("@oxfmt/binding-linux-x64-gnu"); |
There was a problem hiding this comment.
Detect musl outside release builds
When the CLI runs from source or is compiled with the standard build:legacy/build-binary.ts path on Alpine, SUPABASE_LIBC is never defined, so this condition is always false and the glibc binding is loaded on a musl system. The native addon then cannot load, causing TypeScript generation to fail; only the multi-target release build currently injects this define. Detect the current libc when the define is absent or pass the corresponding define from build-binary.ts.
Useful? React with 👍 / 👎.
The glibc and local compile paths already pass oxfmtExternalArgs; musl release binaries were still resolving those never-installed prettier plugins and would fail bun build --compile. Co-authored-by: Cursor <cursoragent@cursor.com>
Summary
Replaces the pg-meta Docker container behind
gen typeswith the new@supabase/postgrest-typegenpackage (0.2.0), running introspection and language generation in-process over a direct Postgres connection.LegacyGenTypesGeneratorservice seam: the production layer acquires a scopedpg.PoolvialegacyAcquirePgPool(full driver parity: TLS mode, DoH resolver, connect-error mapping), feeds it tointrospect(), sorts withsortGeneratorMetadata, and renders typescript/go/python/swift.--localconnects to the host-mapped db port instead of spawning the pg-meta image inside the stack network; thecontainer inspectstack-running check and rest-version v9 forcing are unchanged. The obsolete.temp/pgmeta-versionimage override is removed.--db-urlnow resolves through the sharedLegacyDbConfigResolver(libpq keywords,options=referencepooler tenants,sslmode,PG*env fallbacks), matching every other--db-urlcommand. When the DSN carries no explicitsslmode, the existing SSLRequest probe decides whether to connect withsslmode=disable, so plain-TCP servers (common when self-hosting) keep working as they did with pg-meta.--linked/--project-idTypeScript path still uses the Management API unchanged.--query-timeoutmaps tostatement_timeoutplus the connect timeout;--postgrest-v9-compatdisables one-to-one detection in the TypeScript generator; output keeps the trailing newline pg-meta'sconsole.logadded.createRequire(import.meta.url), whichbun build --compilecannot follow, so the CLI embeds the platform binding statically (the@parcel/watcherpattern) and injects it through the generator'sformatoption — verified byte-equivalent to the package default. The never-installed optional prettier plugins oxfmt lazily imports are marked external in both build scripts.Output parity against postgres-meta 0.98.0 on the same database: Swift byte-identical; Go and Python identical content in canonical sorted order (pg-meta emitted environment-dependent SQL row order); TypeScript identical content with oxfmt's union-wrapping style. Details in the command's
SIDE_EFFECTS.md.Linked issue
Resolves CLI-2279 (no GitHub issue).
open-for-contributionlabel (or I'm a Supabase maintainer).Checklist
fix(cli): …).pnpm check:allpasses; relevant package tests pass for every touched workspace, andpnpm types:checkpasses for each touched TypeScript workspace (or workspace declaring it).https://claude.ai/code/session_01RpnbmgTzwdTMkWYF7uFR1V