Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions apps/cli/docs/go-cli-porting-status.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,14 @@ This tracker is command-focused, but root global flag drift is large enough to n

These commands exist in the TS CLI today but have no direct top-level equivalent in the old Go CLI reference.

| TS command | TS path | Notes |
| ----------------- | ------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `dev` | `planned` | Reserved for a TS-native long-running local development workflow command that watches files and orchestrates subcommands. Track this as TS-only unless a direct Go equivalent emerges. |
| `logs` | [`../src/next/commands/logs/logs.command.ts`](../src/next/commands/logs/logs.command.ts) | Streams local stack logs. No top-level `logs` command exists in the old Go CLI reference. |
| `api` | [`../src/next/commands/platform/api.command.ts`](../src/next/commands/platform/api.command.ts) | Low-level Management API client. It supersedes the old generated tree with explicit discovery via `supabase api routes` and execution via `supabase api request <route> [--method <METHOD>]`. |
| `stack` | [`../src/next/cli/root.ts`](../src/next/cli/root.ts) | TS-only local runtime namespace exposing `stack start`, `stack stop`, `stack status`, `stack list`, and `stack update`. Top-level `start`, `stop`, and `status` remain aliases. |
| `branches switch` | [`../src/next/commands/branches/switch/switch.command.ts`](../src/next/commands/branches/switch/switch.command.ts) | No direct Go equivalent. Updates local active-branch state so subsequent commands target the selected branch. |
| TS command | TS path | Notes |
| ----------------- | ------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `dev` | `planned` | Reserved for a TS-native long-running local development workflow command that watches files and orchestrates subcommands. Track this as TS-only unless a direct Go equivalent emerges. |
| `logs` | [`../src/next/commands/logs/logs.command.ts`](../src/next/commands/logs/logs.command.ts) | Streams local stack logs. No top-level `logs` command exists in the old Go CLI reference. |
| `api` | [`../src/next/commands/platform/api.command.ts`](../src/next/commands/platform/api.command.ts) | Low-level Management API client. It supersedes the old generated tree with explicit discovery via `supabase api routes` and execution via `supabase api request <route> [--method <METHOD>]`. |
| `stack` | [`../src/next/cli/root.ts`](../src/next/cli/root.ts) | TS-only local runtime namespace exposing `stack start`, `stack stop`, `stack status`, `stack list`, and `stack update`. Top-level `start`, `stop`, and `status` remain aliases. |
| `branches switch` | [`../src/next/commands/branches/switch/switch.command.ts`](../src/next/commands/branches/switch/switch.command.ts) | No direct Go equivalent. Updates local active-branch state so subsequent commands target the selected branch. |
| `gen tanstack-db` | [`../src/legacy/commands/gen/tanstack-db/`](../src/legacy/commands/gen/tanstack-db/tanstack-db.command.ts) | No Go equivalent. Generates a Zod + TanStack DB collection file from the project's Postgres schema (`--local`/`--linked`/`--project-id`), inspired by the `supabase/supabase` `ui-library` tanstack-db registry block. Prints to stdout like `gen types`. |

## Quick Start

Expand Down
2 changes: 2 additions & 0 deletions apps/cli/src/legacy/commands/gen/gen.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { legacyGenTypesCommand } from "./types/types.command.ts";
import { legacyGenSigningKeyCommand } from "./signing-key/signing-key.command.ts";
import { legacyGenBearerJwtCommand } from "./bearer-jwt/bearer-jwt.command.ts";
import { legacyGenKeysCommand } from "./keys/keys.command.ts";
import { legacyGenTanstackDbCommand } from "./tanstack-db/tanstack-db.command.ts";

export const legacyGenCommand = Command.make("gen").pipe(
Command.withDescription("Run code generation tools."),
Expand All @@ -12,5 +13,6 @@ export const legacyGenCommand = Command.make("gen").pipe(
legacyGenSigningKeyCommand,
legacyGenBearerJwtCommand,
legacyGenKeysCommand,
legacyGenTanstackDbCommand,
]),
);
8 changes: 8 additions & 0 deletions apps/cli/src/legacy/commands/gen/legacy-gen-schemas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* Shared by `gen types` and `gen tanstack-db`: both let the user select
* schemas via `--schema`/`-s` and fall back to the project's configured
* `api.schemas` (plus `public`) when no flag value is given.
*/
export function defaultSchemas(extraSchemas: ReadonlyArray<string> = []) {
return [...new Set(["public", ...extraSchemas])];
}
71 changes: 71 additions & 0 deletions apps/cli/src/legacy/commands/gen/tanstack-db/SIDE_EFFECTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# `supabase gen tanstack-db`

> TS-only command — no Go CLI equivalent. See `docs/go-cli-porting-status.md` → "TS-only Commands".

## Files Read

| Path | Format | When |
| -------------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------- |
| `~/.supabase/access-token` | plain text | when `SUPABASE_ACCESS_TOKEN` unset and `--linked` / `--project-id` / the implicit linked fallback resolves a ref |
| `<workdir>/supabase/config.toml` | TOML | `--local` (required — fails if missing); best-effort otherwise to resolve default `--schema` values |

## Files Written

| Path | Format | When |
| ---- | ------ | ---- |
| — | — | — |

No files are written. The generated TanStack DB + Zod file is printed to stdout; the user redirects it to a file themselves (e.g. `supabase gen tanstack-db --linked > lib/tanstack-db.ts`), matching `supabase gen types`.

## API Routes

| Method | Path | Auth | Request body | Response (used fields) |
| ------ | ------------------------------------- | ------------ | ------------ | --------------------------------------------------- |
| `GET` | `/v1/projects/{ref}/database/openapi` | Bearer token | none | `definitions` (PostgREST OpenAPI table definitions) |

Called once per requested `--schema` value (default `public`) for `--linked`, `--project-id`, and the implicit linked-project fallback. `--local` does not call the Management API — instead it calls the local stack's own PostgREST gateway directly (see below).

## Local Stack Requests

| Method | URL | Headers | When |
| ------ | -------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------ |
| `GET` | `http://127.0.0.1:<api.port>/rest/v1/` | `apikey`, `Accept-Profile: <schema>`, and `Authorization: Bearer <key>` unless the key is a new-style `sb_…` key | `--local`, once per requested schema |

The `apikey`/bearer value is `auth.publishable_key` (falling back to `auth.anon_key`, then the local stack's default publishable key) from `supabase/config.toml`.

## Environment Variables

| Variable | Purpose | Required? |
| ----------------------- | -------------------------------------------------------------- | ------------------------------------------------------- |
| `SUPABASE_ACCESS_TOKEN` | auth token for `--linked` / `--project-id` / implicit fallback | no (falls back to keyring → `~/.supabase/access-token`) |
| `SUPABASE_PROFILE` | built-in profile name or YAML file path | no (falls back to `~/.supabase/profile` -> `supabase`) |

## Exit Codes

| Code | Condition |
| ---- | --------------------------------------------------------------------------- |
| `0` | success — generated file printed to stdout |
| `1` | no target specified (must use one of `--local`, `--linked`, `--project-id`) |
| `1` | mutually exclusive flags combined (`--local`/`--linked`/`--project-id`) |
| `1` | `supabase/config.toml` not found (`--local`) |
| `1` | local stack unreachable (`--local`, "supabase start is not running.") |
| `1` | Management API error (network or non-2xx status) |
| `1` | a table has no primary key column |
| `1` | no tables found in the selected schema(s) |

## Output

### `--output-format text` (only supported mode)

Prints the generated TypeScript file (Zod schemas + TanStack DB collections, one pair per table) to stdout. Diagnostics, if any, go to stderr.

### `--output-format json` / `stream-json`

Not applicable — this is a TS-only command and does not model structured output modes; it always emits the raw generated file to stdout regardless of `--output-format`.

## Notes

- Exactly one of `--local`, `--linked`, or `--project-id` may be specified; when none is given, the linked project is used as a fallback (same resolution order as `gen types`), minus `--db-url`, which has no PostgREST endpoint to introspect.
- `--schema` / `-s` accepts a comma-separated list, repeatable; defaults to the project's configured `api.schemas` (always includes `public`). One OpenAPI document is fetched per schema and the table sets are merged; a table name present in more than one requested schema is last-write-wins.
- A table's primary key is detected from PostgREST's `Note:\nThis is a Primary Key.<pk/>` OpenAPI property description, falling back to a literal `id` column. A composite primary key produces a `keys` array with all of its columns.
- The generated file imports from `zod`, `@tanstack/db`, `@supabase-labs/tanstack-db`, and `@supabase/supabase-js`, and expects `SUPABASE_URL` and `SUPABASE_ANON_KEY` environment variables — none of these are installed or configured by this command.
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { Command, Flag } from "effect/unstable/cli";
import type * as CliCommand from "effect/unstable/cli/Command";
import { withJsonErrorHandling } from "../../../../shared/output/json-error-handling.ts";
import { withLegacyCommandInstrumentation } from "../../../telemetry/legacy-command-instrumentation.ts";
import { legacyParseSchemaFlags } from "../../../shared/legacy-schema-flags.ts";
import { legacyGenTanstackDb } from "./tanstack-db.handler.ts";
import { legacyGenTanstackDbRuntimeLayer } from "./tanstack-db.layers.ts";

const config = {
local: Flag.boolean("local").pipe(
Flag.withDescription("Generate the TanStack DB file from the local dev database."),
),
linked: Flag.boolean("linked").pipe(
Flag.withDescription("Generate the TanStack DB file from the linked project."),
),
projectId: Flag.string("project-id").pipe(
Flag.withDescription("Generate the TanStack DB file from a project ID."),
Flag.optional,
),
schema: Flag.string("schema").pipe(
Flag.withAlias("s"),
Flag.withDescription("Comma separated list of schema to include."),
Flag.atLeast(0),
Flag.mapTryCatch(
(rawValues) => legacyParseSchemaFlags(rawValues),
(err) => (err instanceof Error ? err.message : String(err)),
),
),
} as const;

export type LegacyGenTanstackDbFlags = CliCommand.Command.Config.Infer<typeof config>;

export const legacyGenTanstackDbCommand = Command.make("tanstack-db", config).pipe(
Command.withDescription(
"Generate a Zod + TanStack DB collection file from your Postgres schema.",
),
Command.withShortDescription("Generate a TanStack DB file from your Postgres schema"),
Command.withExamples([
{
command: "supabase gen tanstack-db --local",
description: "Generate a TanStack DB file from the local dev database",
},
{
command: "supabase gen tanstack-db --linked --schema public --schema private",
description: "Generate a TanStack DB file from the linked project with specific schemas",
},
{
command: "supabase gen tanstack-db --project-id abc-def-123",
description: "Generate a TanStack DB file from a project ID",
},
]),
Command.withHandler((flags) =>
legacyGenTanstackDb(flags).pipe(
withLegacyCommandInstrumentation({ flags, safeFlags: ["project-id"], config }),
withJsonErrorHandling,
),
),
Command.provide(legacyGenTanstackDbRuntimeLayer),
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Data } from "effect";

export class LegacyGenTanstackDbNetworkError extends Data.TaggedError(
"LegacyGenTanstackDbNetworkError",
)<{
readonly message: string;
}> {}

export class LegacyGenTanstackDbUnexpectedStatusError extends Data.TaggedError(
"LegacyGenTanstackDbUnexpectedStatusError",
)<{
readonly status: number;
readonly body: string;
readonly message: string;
}> {}

export class LegacyGenTanstackDbDecodeError extends Data.TaggedError(
"LegacyGenTanstackDbDecodeError",
)<{
readonly message: string;
}> {}

export class LegacyGenTanstackDbLocalStackNotRunningError extends Data.TaggedError(
"LegacyGenTanstackDbLocalStackNotRunningError",
)<{
readonly message: string;
}> {}

export class LegacyGenTanstackDbNoTablesError extends Data.TaggedError(
"LegacyGenTanstackDbNoTablesError",
)<{
readonly message: string;
}> {}

export class LegacyGenTanstackDbUnsafeNameError extends Data.TaggedError(
"LegacyGenTanstackDbUnsafeNameError",
)<{
readonly message: string;
}> {}

export class LegacyGenTanstackDbNoPrimaryKeyError extends Data.TaggedError(
"LegacyGenTanstackDbNoPrimaryKeyError",
)<{
readonly message: string;
}> {}
Loading
Loading