Skip to content

Commit 27b6af1

Browse files
7ttpColy010
andauthored
feat(cli): port gen types (#5514)
## TL;DR Ports `supabase gen types` to native ts ## What’s introduced adds a ts implementation for `gen types` that preserves the existing command surface for local, linked, `--project-id`, and `--db-url` flows, keeps the legacy behavior, reuses the management api path for hosted ts generation, and runs `pg-meta` directly for generation also moves the ca bundle into ts based template files & coverage for all of this! ## ref - Closes CLI-1310 --------- Co-authored-by: Colum Ferry <cferry09@gmail.com>
1 parent 4260821 commit 27b6af1

13 files changed

Lines changed: 2571 additions & 52 deletions

apps/cli/docs/go-cli-porting-status.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ Legend:
281281
| `migration up` | `wrapped` | [`../src/legacy/commands/migration/up/up.command.ts`](../src/legacy/commands/migration/up/up.command.ts) |
282282
| `migration down` | `wrapped` | [`../src/legacy/commands/migration/down/down.command.ts`](../src/legacy/commands/migration/down/down.command.ts) |
283283
| `migration fetch` | `wrapped` | [`../src/legacy/commands/migration/fetch/fetch.command.ts`](../src/legacy/commands/migration/fetch/fetch.command.ts) |
284-
| `gen types` | `wrapped` | [`../src/legacy/commands/gen/types/types.command.ts`](../src/legacy/commands/gen/types/types.command.ts) |
284+
| `gen types` | `ported` | [`../src/legacy/commands/gen/types/types.command.ts`](../src/legacy/commands/gen/types/types.command.ts) |
285285
| `gen signing-key` | `ported` | [`../src/legacy/commands/gen/signing-key/signing-key.command.ts`](../src/legacy/commands/gen/signing-key/signing-key.command.ts) |
286286
| `gen bearer-jwt` | `wrapped` | [`../src/legacy/commands/gen/bearer-jwt/bearer-jwt.command.ts`](../src/legacy/commands/gen/bearer-jwt/bearer-jwt.command.ts) |
287287
| `gen keys` | `wrapped` | [`../src/legacy/commands/gen/keys/keys.command.ts`](../src/legacy/commands/gen/keys/keys.command.ts) |

apps/cli/src/legacy/commands/gen/types/SIDE_EFFECTS.md

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,43 +2,71 @@
22

33
## Files Read
44

5-
| Path | Format | When |
6-
| -------------------------------- | ---------- | ------------------------------------------------------------------- |
7-
| `~/.supabase/access-token` | plain text | when `SUPABASE_ACCESS_TOKEN` unset and `--linked` or `--project-id` |
8-
| `<workdir>/supabase/config.toml` | TOML | when `--local` is specified |
5+
| Path | Format | When |
6+
| ----------------------------------------- | ---------- | ---------------------------------------------------------------------------------------- |
7+
| `~/.supabase/access-token` | plain text | when `SUPABASE_ACCESS_TOKEN` unset and `--linked` or `--project-id` |
8+
| `<workdir>/supabase/config.toml` | TOML | when `--local` (required) or `--db-url` (best-effort) is specified |
9+
| `<workdir>/supabase/.temp/rest-version` | plain text | `--local` only, when `db.major_version > 14` — forces v9 compat if the tag contains `v9` |
10+
| `<workdir>/supabase/.temp/pgmeta-version` | plain text | `--local` only — overrides the pg-meta docker image tag |
911

1012
## Files Written
1113

1214
| Path | Format | When |
1315
| ---- | ------ | ---- |
1416
||||
1517

18+
No files are written. Container env (including the DB URL and TLS CA bundle) is
19+
passed via `docker run --env KEY=VALUE` arguments, mirroring Go's
20+
`container.Config.Env`; no temporary env-file is created.
21+
1622
## API Routes
1723

1824
| Method | Path | Auth | Request body | Response (used fields) |
1925
| ------ | ------------------------------------- | ------------ | ------------ | -------------------------------- |
2026
| `GET` | `/v1/projects/{ref}/types/typescript` | Bearer token | none | TypeScript type definitions text |
2127

28+
Called only for `--linked`, `--project-id`, and the implicit linked-project
29+
fallback. `--local` and `--db-url` do not call the Management API.
30+
31+
## Subprocesses
32+
33+
| Command | When | Purpose |
34+
| ----------------------------------------------------------------------------- | --------------------- | -------------------------------------------------- |
35+
| `docker container inspect supabase_db_<project_id>` | `--local` | assert `supabase start` is running |
36+
| `docker run --rm --network <net> --env … <pgmeta> node dist/server/server.js` | `--local`, `--db-url` | run pg-meta to generate types from a live database |
37+
38+
A raw TCP `SSLRequest` probe is also opened to the target database host/port to
39+
detect TLS support before launching pg-meta (mirrors Go's `isRequireSSL`).
40+
2241
## Environment Variables
2342

24-
| Variable | Purpose | Required? |
25-
| ----------------------- | ------------------------------------- | ------------------------------------------------------- |
26-
| `SUPABASE_ACCESS_TOKEN` | auth token for linked/project-id mode | no (falls back to keyring → `~/.supabase/access-token`) |
27-
| `SUPABASE_API_URL` | override Management API base URL | no (defaults to `https://api.supabase.com`) |
43+
| Variable | Purpose | Required? |
44+
| ---------------------------------- | ----------------------------------------------------------------- | ------------------------------------------------------- |
45+
| `SUPABASE_ACCESS_TOKEN` | auth token for linked/project-id mode | no (falls back to keyring → `~/.supabase/access-token`) |
46+
| `SUPABASE_API_URL` | override Management API base URL | no (defaults to `https://api.supabase.com`) |
47+
| `SUPABASE_DB_PASSWORD` | local database password for `--local` | no (defaults to `postgres`) |
48+
| `SUPABASE_SERVICES_HOSTNAME` | host used for the local TLS probe | no (defaults to `127.0.0.1`) |
49+
| `SUPABASE_INTERNAL_IMAGE_REGISTRY` | pg-meta image registry override (`docker.io` → Docker Hub) | no (defaults to the ECR registry) |
50+
| `SUPABASE_CA_SKIP_VERIFY` | when `true`, prints a TLS-verification-disabled warning to stderr | no |
2851

2952
## Exit Codes
3053

31-
| Code | Condition |
32-
| ---- | ---------------------------------------- |
33-
| `0` | success — types printed to stdout |
34-
| `1` | no target specified (must use one flag) |
35-
| `1` | API error or database connection failure |
54+
| Code | Condition |
55+
| ---- | ---------------------------------------------------------------- |
56+
| `0` | success — types printed to stdout |
57+
| `1` | no target specified (must use one flag) |
58+
| `1` | mutually exclusive flags combined |
59+
| `1` | `--postgrest-v9-compat` used without `--db-url` |
60+
| `1` | invalid `--query-timeout` duration or invalid `--db-url` |
61+
| `1` | `supabase start` not running (`--local`) or db inspection failed |
62+
| `1` | API error, TLS probe failure, or pg-meta container non-zero exit |
3663

3764
## Output
3865

3966
### `--output-format text` (Go CLI compatible)
4067

4168
Prints generated TypeScript (or other language) type definitions to stdout.
69+
Diagnostics (`Connecting to …`, pg-meta logs) go to stderr.
4270

4371
### `--output-format json`
4472

@@ -51,8 +79,14 @@ Not applicable.
5179
## Notes
5280

5381
- Exactly one of `--local`, `--linked`, `--project-id`, or `--db-url` must be specified.
54-
- `--lang` flag accepts `typescript` (default), `go`, `swift`, or `python`.
82+
- `--lang` flag accepts `typescript` (default), `go`, `swift`, or `python`. Non-typescript
83+
languages require a direct database connection (`--local` or `--db-url`).
5584
- `--schema` / `-s` accepts a comma-separated list of schemas to include.
5685
- `--swift-access-control` accepts `internal` (default) or `public`.
5786
- `--postgrest-v9-compat` generates types compatible with PostgREST v9 and below (requires `--db-url`).
5887
- `--query-timeout` sets the maximum timeout for the database query (default 15s, direct connection only).
88+
- The legacy positional language argument (`supabase gen types typescript`) is still accepted;
89+
any other positional language requires an explicit `--lang` flag.
90+
- The linked-project telemetry cache is written only when a project ref is resolved
91+
(`--linked`/`--project-id`/fallback), matching Go's `ensureProjectGroupsCached`, which
92+
returns early when no ref is available.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
export default `-----BEGIN CERTIFICATE-----
2+
MIIDxDCCAqygAwIBAgIUbLxMod62P2ktCiAkxnKJwtE9VPYwDQYJKoZIhvcNAQEL
3+
BQAwazELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB0RlbHdhcmUxEzARBgNVBAcMCk5l
4+
dyBDYXN0bGUxFTATBgNVBAoMDFN1cGFiYXNlIEluYzEeMBwGA1UEAwwVU3VwYWJh
5+
c2UgUm9vdCAyMDIxIENBMB4XDTIxMDQyODEwNTY1M1oXDTMxMDQyNjEwNTY1M1ow
6+
azELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB0RlbHdhcmUxEzARBgNVBAcMCk5ldyBD
7+
YXN0bGUxFTATBgNVBAoMDFN1cGFiYXNlIEluYzEeMBwGA1UEAwwVU3VwYWJhc2Ug
8+
Um9vdCAyMDIxIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqQXW
9+
QyHOB+qR2GJobCq/CBmQ40G0oDmCC3mzVnn8sv4XNeWtE5XcEL0uVih7Jo4Dkx1Q
10+
DmGHBH1zDfgs2qXiLb6xpw/CKQPypZW1JssOTMIfQppNQ87K75Ya0p25Y3ePS2t2
11+
GtvHxNjUV6kjOZjEn2yWEcBdpOVCUYBVFBNMB4YBHkNRDa/+S4uywAoaTWnCJLUi
12+
cvTlHmMw6xSQQn1UfRQHk50DMCEJ7Cy1RxrZJrkXXRP3LqQL2ijJ6F4yMfh+Gyb4
13+
O4XajoVj/+R4GwywKYrrS8PrSNtwxr5StlQO8zIQUSMiq26wM8mgELFlS/32Uclt
14+
NaQ1xBRizkzpZct9DwIDAQABo2AwXjALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFKjX
15+
uXY32CztkhImng4yJNUtaUYsMB8GA1UdIwQYMBaAFKjXuXY32CztkhImng4yJNUt
16+
aUYsMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAB8spzNn+4VU
17+
tVxbdMaX+39Z50sc7uATmus16jmmHjhIHz+l/9GlJ5KqAMOx26mPZgfzG7oneL2b
18+
VW+WgYUkTT3XEPFWnTp2RJwQao8/tYPXWEJDc0WVQHrpmnWOFKU/d3MqBgBm5y+6
19+
jB81TU/RG2rVerPDWP+1MMcNNy0491CTL5XQZ7JfDJJ9CCmXSdtTl4uUQnSuv/Qx
20+
Cea13BX2ZgJc7Au30vihLhub52De4P/4gonKsNHYdbWjg7OWKwNv/zitGDVDB9Y2
21+
CMTyZKG3XEu5Ghl1LEnI3QmEKsqaCLv12BnVjbkSeZsMnevJPs1Ye6TjjJwdik5P
22+
o/bKiIz+Fq8=
23+
-----END CERTIFICATE-----
24+
`;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
export default `-----BEGIN CERTIFICATE-----
2+
MIIDxzCCAq+gAwIBAgIUeX+gpfmsRW9asFkRvjyXjHxbfgcwDQYJKoZIhvcNAQEL
3+
BQAwazELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB0RlbHdhcmUxEzARBgNVBAcMCk5l
4+
dyBDYXN0bGUxFTATBgNVBAoMDFN1cGFiYXNlIEluYzEeMBwGA1UEAwwVU3VwYWJh
5+
c2UgUm9vdCAyMDIxIENBMB4XDTI1MDkwMzA4MDEyNVoXDTM1MDkwMTA4MDEyNVow
6+
azELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB0RlbHdhcmUxEzARBgNVBAcMCk5ldyBD
7+
YXN0bGUxFTATBgNVBAoMDFN1cGFiYXNlIEluYzEeMBwGA1UEAwwVU3VwYWJhc2Ug
8+
Um9vdCAyMDIxIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5Ve7
9+
i9UAmc7luUilELPtqzEk8nGHxg7nY0aCStr625M7+K4OPO6RUllTsHh47k1jWyzm
10+
LXLlyYwCsYCjQp+3vn06H+F/HRUxBt6CK2B7bNng230exTunk0xFvfkX6YgHR7B3
11+
1B7L25Rq3PhuRFPV4hnGYRam2XBZC4UNPqoAgrhV0HOYzXXAVoTr2yaBTMnB331Z
12+
RwOmINh7eqTCk/JRZbb6vfZOhZRAVAe9AoRLoG8aKwmeoLGwlu0UuFx6z3E+6bmA
13+
fSNa8Lx02GEoCdPLw9IRKUFq/SgBpQUKm44H1fDwTjH2CMM0N4p0mL/6wXnNeHvt
14+
C40MmKZ0RcVmHE5wBwIDAQABo2MwYTAdBgNVHQ4EFgQUjvEE541toZcwtXQlZlcB
15+
YOBRTnowHwYDVR0jBBgwFoAUjvEE541toZcwtXQlZlcBYOBRTnowDwYDVR0TAQH/
16+
BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggEBACD5IcGP
17+
XKvS9qg0CgEQPFqYavt5c7P+0xxFgiZe+xoG8fUw58yNeK2APtgGPRpxEOGfAlNx
18+
z9HDt4gcyHEE00B3qAVDm49pqNxioFWzNqU2LGfM/HL1QmN6urR7hCOkVCJddvOc
19+
FhFX4nZDuRfaBboDvS5HlK3Pzxddp9hvrJi2bemr8HLqYc3HzmVckgPGSLML6t+h
20+
4LRCXSlQsDgQ1LZ4KHsl4cq7K51N6FOXQBLB5q4lMKhs0VUhCT8Pdsj12+84laCV
21+
c22q6p2mdT9SaernCSRnWazXWisgpjv3H7Ex4S1DCYjJIwn3PUToGFv1r8YRN2/S
22+
O19yVSxxCIf64Sg=
23+
-----END CERTIFICATE-----
24+
`;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
export default `-----BEGIN CERTIFICATE-----
2+
MIID1DCCArygAwIBAgIUbYRdq/8/uNq8G9stMCdOFSBgA2MwDQYJKoZIhvcNAQEL
3+
BQAwczELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB0RlbHdhcmUxEzARBgNVBAcMCk5l
4+
dyBDYXN0bGUxFTATBgNVBAoMDFN1cGFiYXNlIEluYzEmMCQGA1UEAwwdU3VwYWJh
5+
c2UgU3RhZ2luZyBSb290IDIwMjEgQ0EwHhcNMjEwNDI4MTAzNjEzWhcNMzEwNDI2
6+
MTAzNjEzWjBzMQswCQYDVQQGEwJVUzEQMA4GA1UECAwHRGVsd2FyZTETMBEGA1UE
7+
BwwKTmV3IENhc3RsZTEVMBMGA1UECgwMU3VwYWJhc2UgSW5jMSYwJAYDVQQDDB1T
8+
dXBhYmFzZSBTdGFnaW5nIFJvb3QgMjAyMSBDQTCCASIwDQYJKoZIhvcNAQEBBQAD
9+
ggEPADCCAQoCggEBAN0AKRE8a56O8LaZxiOAcHFUFnwiKUvPoXPq26Ifw+Nv+7zg
10+
N2V5WnMZbbw24q61Os60ZUn0XmbVtuIeJ+stPHsO7qxxuL+bmPR+qU5tkDrIOyEe
11+
YD/2u8/q6ssVv42k4XcXbhM6RVz7CkCDY0TiBm1bMtRZso3xB6E9wAjxDf43XfV5
12+
PAGs3JI+Zo/vyqCDlN0hHOrB/aBl01JXqQWI84Gia5ooucq4SjA1CyawBcQ2IAvG
13+
rXuy1BouY+xM3zRuNvtfFP6rb5Mta+jCYEMh1AZ8yP8sYUWAyhxX6k9EbOb009wQ
14+
aZljbUCh/UglGWuBxdzePavx+zPjzWXB1NyVkpkCAwEAAaNgMF4wCwYDVR0PBAQD
15+
AgEGMB0GA1UdDgQWBBQFx+PHLf27iIo/PMfIfGqXF7Zb+DAfBgNVHSMEGDAWgBQF
16+
x+PHLf27iIo/PMfIfGqXF7Zb+DAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB
17+
CwUAA4IBAQB/xIiz5dDqzGXjqYqXZYx4iSfSxsVayeOPDMfmaiCfSMJEUG4cUiwG
18+
OvMPGztaUEYeip5SCvSKuAAjVkXyP7ahKR7t7lZ9mErVXyxSZoVLbOd578CuYiZk
19+
OgT17UjPv66WMzEKEr8wGpomTYWWfEkuqt8ENdiM1Z4LNFahdKj36+jm6/a+9R8K
20+
25VIL68DTaQpBxFWG6ixC1HRMHJ12lDhKsshIi099BVpkGibESlxPrQOdKKqBB/J
21+
vIX+/Hb+mS4H5zYMeK2wX0onp+GBcD6X9L1UJuXMVd+BRan8RFidXL5s3++xXjQq
22+
Nzbc6lnA69urKffvcT07YwMsY/OmHzVa
23+
-----END CERTIFICATE-----
24+
`;

apps/cli/src/legacy/commands/gen/types/types.command.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { Command, Flag } from "effect/unstable/cli";
22
import type * as CliCommand from "effect/unstable/cli/Command";
3+
import { withJsonErrorHandling } from "../../../../shared/output/json-error-handling.ts";
4+
import { legacyManagementApiRuntimeLayer } from "../../../shared/legacy-management-api-runtime.layer.ts";
5+
import { withLegacyCommandInstrumentation } from "../../../telemetry/legacy-command-instrumentation.ts";
36
import { legacyGenTypes } from "./types.handler.ts";
47

58
const LANG_VALUES = ["typescript", "go", "swift", "python"] as const;
@@ -21,24 +24,24 @@ const config = {
2124
Flag.optional,
2225
),
2326
lang: Flag.choice("lang", LANG_VALUES).pipe(
24-
Flag.withDescription("Output language of the generated types."),
25-
Flag.optional,
27+
Flag.withDescription("Output language of the generated types. (default typescript)"),
28+
Flag.withDefault("typescript"),
2629
),
2730
schema: Flag.string("schema").pipe(
2831
Flag.withAlias("s"),
2932
Flag.withDescription("Comma separated list of schema to include."),
3033
Flag.atLeast(0),
3134
),
3235
swiftAccessControl: Flag.choice("swift-access-control", SWIFT_ACCESS_CONTROL_VALUES).pipe(
33-
Flag.withDescription("Access control for Swift generated types."),
34-
Flag.optional,
36+
Flag.withDescription("Access control for Swift generated types. (default internal)"),
37+
Flag.withDefault("internal"),
3538
),
3639
postgrestV9Compat: Flag.boolean("postgrest-v9-compat").pipe(
3740
Flag.withDescription("Generate types compatible with PostgREST v9 and below."),
3841
),
3942
queryTimeout: Flag.string("query-timeout").pipe(
40-
Flag.withDescription("Maximum timeout allowed for the database query."),
41-
Flag.optional,
43+
Flag.withDescription("Maximum timeout allowed for the database query. (default 15s)"),
44+
Flag.withDefault("15s"),
4245
),
4346
} as const;
4447

@@ -65,5 +68,11 @@ export const legacyGenTypesCommand = Command.make("types", config).pipe(
6568
description: "Generate types from a database URL",
6669
},
6770
]),
68-
Command.withHandler((flags) => legacyGenTypes(flags)),
71+
Command.withHandler((flags) =>
72+
legacyGenTypes(flags).pipe(
73+
withLegacyCommandInstrumentation({ flags, safeFlags: ["project-id"] }),
74+
withJsonErrorHandling,
75+
),
76+
),
77+
Command.provide(legacyManagementApiRuntimeLayer(["gen", "types"])),
6978
);
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { Data } from "effect";
2+
3+
export class LegacyGenTypesNetworkError extends Data.TaggedError("LegacyGenTypesNetworkError")<{
4+
readonly message: string;
5+
}> {}
6+
7+
export class LegacyGenTypesUnexpectedStatusError extends Data.TaggedError(
8+
"LegacyGenTypesUnexpectedStatusError",
9+
)<{
10+
readonly status: number;
11+
readonly body: string;
12+
readonly message: string;
13+
}> {}
14+
15+
export class LegacyInvalidGenTypesDurationError extends Data.TaggedError(
16+
"LegacyInvalidGenTypesDurationError",
17+
)<{
18+
readonly message: string;
19+
}> {}
20+
21+
export class LegacyInvalidGenTypesDatabaseUrlError extends Data.TaggedError(
22+
"LegacyInvalidGenTypesDatabaseUrlError",
23+
)<{
24+
readonly message: string;
25+
}> {}

0 commit comments

Comments
 (0)