diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index de3dec7ff4..8cc068553b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -148,7 +148,7 @@ jobs: (github.event_name == 'merge_group' || inputs.force || github.event.pull_request.draft == false) - name: Run end-to-end tests (shard ${{ matrix.shard }}/3) + name: Run CLI end-to-end tests (shard ${{ matrix.shard }}/3) runs-on: blacksmith-8vcpu-ubuntu-2404 strategy: fail-fast: false @@ -186,16 +186,39 @@ jobs: run: pnpm exec turbo run supabase#build - name: Run end-to-end tests - run: pnpm exec turbo run test:e2e:run --only --concurrency=1 -- --shard=${{ matrix.shard }}/3 + run: pnpm exec turbo run test:e2e:run --only --concurrency=1 --filter=supabase --filter=@supabase/cli-e2e -- --shard=${{ matrix.shard }}/3 env: CLI_HARNESS_TARGET: ts-legacy SUPABASE_GO_BINARY: ${{ github.workspace }}/apps/cli-go/supabase-go - # Summary job that gates branch protection. The matrix `test-e2e` job - # produces per-shard check names (`Run end-to-end tests (shard N/3)`), so - # this job preserves the original `Run end-to-end tests` check name that - # branch protection rules already require. It succeeds iff every shard - # succeeded (or skipped — `success()` is true for skipped jobs). + test-stack-e2e: + if: | + !startsWith(github.head_ref, 'release-notes/') && + (github.event_name == 'merge_group' || + inputs.force || + github.event.pull_request.draft == false) + name: Run stack end-to-end tests (${{ matrix.runtime }}) + runs-on: blacksmith-8vcpu-ubuntu-2404 + strategy: + fail-fast: false + matrix: + runtime: [native, container] + steps: + - name: Checkout + uses: useblacksmith/checkout@6fd481652155169ed4d2f25ebaf97464f685175f # v1.0.0-beta + + - name: Setup + uses: ./.github/actions/setup + with: + dependency-firewall-token: ${{ secrets.DF_FIREWALL_TOKEN }} + + - name: Run stack end-to-end tests + run: pnpm --filter @supabase/stack test:e2e:run + env: + SUPABASE_STACK_E2E_RUNTIME: ${{ matrix.runtime }} + + # Summary job that gates branch protection. It preserves the original check + # name and succeeds iff every CLI shard and stack runtime succeeded. test-e2e-summary: if: | always() && @@ -204,13 +227,13 @@ jobs: inputs.force || github.event.pull_request.draft == false) name: Run end-to-end tests - needs: test-e2e + needs: [test-e2e, test-stack-e2e] runs-on: ubuntu-latest steps: - name: Verify all shards succeeded run: | - if [ "${{ needs.test-e2e.result }}" = "failure" ] || [ "${{ needs.test-e2e.result }}" = "cancelled" ]; then - echo "::error ::One or more e2e shards failed: ${{ needs.test-e2e.result }}" + if [ "${{ needs.test-e2e.result }}" = "failure" ] || [ "${{ needs.test-e2e.result }}" = "cancelled" ] || [ "${{ needs.test-stack-e2e.result }}" = "failure" ] || [ "${{ needs.test-stack-e2e.result }}" = "cancelled" ]; then + echo "::error ::One or more e2e jobs failed: cli=${{ needs.test-e2e.result }}, stack=${{ needs.test-stack-e2e.result }}" exit 1 fi - echo "All e2e shards reported: ${{ needs.test-e2e.result }}" + echo "All e2e jobs reported: cli=${{ needs.test-e2e.result }}, stack=${{ needs.test-stack-e2e.result }}" diff --git a/.gitignore b/.gitignore index 5a892f3aba..a1d49ff0cf 100644 --- a/.gitignore +++ b/.gitignore @@ -7,8 +7,10 @@ coverage/ !.env.example .claude/ .agents/.repos/effect-v3 +.repos/slim-services/ .worktrees/ .supabase/ +erl_crash.dump # Stray `supabase` project dir created by running the CLI at the repo root # (e.g. supabase/.temp/linked-project.json). This monorepo has no top-level # Supabase project — real fixtures live under apps/cli-e2e/fixtures/. @@ -23,6 +25,7 @@ packages/cli-*/bin/ # Turbo .turbo/ +apps/cli/.supabase/ # Transient render dir created by packages/api/scripts/generated-output-sync.unit.test.ts packages/api/.generated-output-sync-*/ diff --git a/.gitmodules b/.gitmodules index ec13d73342..084b300883 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,9 +13,6 @@ [submodule ".repos/cheffect"] path = .repos/cheffect url = https://github.com/tim-smart/cheffect.git -[submodule ".repos/process-compose"] - path = .repos/process-compose - url = https://github.com/F1bonacc1/process-compose.git [submodule ".repos/t3code"] path = .repos/t3code url = https://github.com/pingdotgg/t3code.git diff --git a/.oxlintrc.json b/.oxlintrc.json index 4d587a2f9a..7639dd613e 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -8,8 +8,6 @@ ".repos", "apps/cli-go", "apps/cli-e2e/fixtures", - "packages/stack", - "packages/process-compose", "**/testdata", "**/dist", "**/coverage", diff --git a/.repos/process-compose b/.repos/process-compose deleted file mode 160000 index a4038d6698..0000000000 --- a/.repos/process-compose +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a4038d669818c35fc68fc7fc240b39e371ce0e7a diff --git a/AGENTS.md b/AGENTS.md index a41624df94..ffa5c1c6da 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -12,13 +12,12 @@ Bun monorepo with workspaces under `apps/` and `packages/`. - `apps/docs` — internal Next.js docs site - `packages/api` — typed Supabase Management API client - `packages/config` — config schema and generated types -- `packages/process-compose` — process orchestration library - `packages/stack` — programmatic local Supabase stack runtime - `packages/cli-*` — platform-specific published CLI binary wrappers ## Package Structure -Use `packages/process-compose` as the reference for internal TypeScript/Bun workspaces such as `apps/cli`, `packages/api`, `packages/config`, `packages/process-compose`, and `packages/stack`. +Use the existing internal TypeScript/Bun workspaces as references for package structure and scripts. These workspaces should generally follow this structure: @@ -29,7 +28,7 @@ These workspaces should generally follow this structure: - Standard scripts: `test`, `types:check` - Standard devDependencies: `@tsconfig/bun`, `@types/bun`, `typescript` -Generic linting (`oxlint`), formatting (`oxfmt`), and unused-code analysis (`knip`) are repo-wide, not per-package: the tools are root devDependencies configured by `.oxlintrc.json`, `.oxfmtrc.json`, and `knip.json` at the repo root (knip's config maps each workspace under its `workspaces` key). Effect-specific linting is incrementally scoped to `packages/stack` and `packages/process-compose` through `.oxlintrc.effect.json`; run it with the root `lint:effect:check` or `lint:effect:fix` scripts. The root `check:all`/`fix:all` scripts are the sole repo-wide quality entrypoints and use Turbo to orchestrate the root-owned generic `lint:*`/`fmt:*`/`knip:*` scripts and package `types:check` targets; `fix:all` runs the Effect lint fix after those generic fixes complete. Package-local work can run `pnpm types:check` and the package's test scripts; `pnpm exec oxlint`, `pnpm exec oxfmt`, and `pnpm exec knip-bun` from the repo root also work directly. +Generic linting (`oxlint`), formatting (`oxfmt`), and unused-code analysis (`knip`) are repo-wide, not per-package: the tools are root devDependencies configured by `.oxlintrc.json`, `.oxfmtrc.json`, and `knip.json` at the repo root (knip's config maps each workspace under its `workspaces` key). Effect-specific linting is scoped to `packages/stack` through `.oxlintrc.effect.json`; run it with the root `lint:effect:check` or `lint:effect:fix` scripts. The root `check:all`/`fix:all` scripts are the sole repo-wide quality entrypoints and use Turbo to orchestrate the root-owned generic `lint:*`/`fmt:*`/`knip:*` scripts and package `types:check` targets; `fix:all` runs the Effect lint fix after those generic fixes complete. Package-local work can run `pnpm types:check` and the package's test scripts; `pnpm exec oxlint`, `pnpm exec oxfmt`, and `pnpm exec knip-bun` from the repo root also work directly. Expected exceptions: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1b20df8868..fdd93672a6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -94,7 +94,6 @@ That pulls `.repos/effect/`, which is the local source of truth for Effect v4 AP |-- packages/ | |-- api/ # Typed Supabase Management API client | |-- config/ # Supabase config schema and generated types -| |-- process-compose/ # Effect-based process orchestration library | |-- stack/ # Programmatic local Supabase stack runtime | `-- cli-*/ # Platform-specific CLI binary packages |-- tools/ # Repository tooling (release scripts, etc.) @@ -117,7 +116,6 @@ That pulls `.repos/effect/`, which is the local source of truth for Effect v4 AP | `packages/api` | Auto-generated TypeScript client for the Supabase Management API. | | `packages/cli-test-helpers` | CLI test harness library — `createHarness`/`exec` API for spawning TS Legacy and TS Next CLI subprocesses in tests. | | `packages/config` | JSON Schema and generated TypeScript types for Supabase configuration. | -| `packages/process-compose` | TypeScript/Bun port of `process-compose` used for multi-service orchestration. | | `packages/stack` | Programmatic local Supabase stack used by the CLI and other tooling. | | `packages/cli-darwin-arm64` | Published native CLI binary wrapper for macOS arm64. | | `packages/cli-darwin-x64` | Published native CLI binary wrapper for macOS x64. | @@ -142,7 +140,7 @@ pnpm run fix:all # run all fixers across every project ### Standard package scripts -Standard TypeScript workspaces (`apps/cli-e2e`, `apps/cli`, `packages/api`, `packages/cli-test-helpers`, `packages/config`, `packages/process-compose`, `packages/stack`) declare their package scripts explicitly. Test suites vary by package: unit tests are standard, while integration and e2e tests exist only where applicable. +Standard TypeScript workspaces (`apps/cli-e2e`, `apps/cli`, `packages/api`, `packages/cli-test-helpers`, `packages/config`, `packages/stack`) declare their package scripts explicitly. Test suites vary by package: unit tests are standard, while integration and e2e tests exist only where applicable. | Script | What it does | | ------------------ | -------------------------------------- | diff --git a/apps/cli/AGENTS.md b/apps/cli/AGENTS.md index b65c1a3cae..27c1a8e15f 100644 --- a/apps/cli/AGENTS.md +++ b/apps/cli/AGENTS.md @@ -383,7 +383,7 @@ export class LegacyThingMissingError extends Data.TaggedError("LegacyThingMissin - **An instance-dependent getter must stay valid when its fields are absent** — the drift guard evaluates it against a field-less probe. - **A plain `Error` subclass (no `_tag`) also declares its fingerprint identifier**: `static readonly [ErrorActionabilityFingerprintId] = ""`, matching the export name exactly. Tagged errors skip this — their fingerprint comes from the tag. The static identifier is what keeps `error:` fingerprints stable in minified release builds, where `constructor.name` is renamed. -**Errors defined outside `apps/cli/src`** (`@supabase/stack`, `@supabase/config`, `@supabase/process-compose`, `@supabase/api`, `effect`) cannot carry a declaration. Add a structural adapter keyed by `_tag` to `externalActionabilityByTag` in that same module, branching on the producer's typed fields. +**Errors defined outside `apps/cli/src`** (`@supabase/stack`, `@supabase/config`, `@supabase/api`, `effect`) cannot carry a declaration. Add a structural adapter keyed by `_tag` to `externalActionabilityByTag` in that same module, branching on the producer's typed fields. `error-actionability-coverage.unit.test.ts` enforces this. It scans every `TaggedError("Tag")`, every `*Error("Tag")` factory, and every `class X extends Error` under `apps/cli/src`, and fails when a class is unexported, has no own declaration, or is untagged without its matching static fingerprint identifier. A failure there is the guard working: classify the new error rather than loosening the guard, because `unknown` in production telemetry must mean a genuinely unforeseen failure, not one nobody categorized. diff --git a/apps/cli/package.json b/apps/cli/package.json index 3c1909d587..adb4c11221 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -58,7 +58,6 @@ "@supabase/config": "workspace:*", "@supabase/pg-delta": "1.0.0-alpha.49", "@supabase/pg-topo": "1.0.0-alpha.6", - "@supabase/stack": "workspace:*", "@tsconfig/bun": "catalog:", "@types/bun": "catalog:", "@types/pg": "^8.23.1", diff --git a/apps/cli/src/command-internal/db-bootstrap/health-check.ts b/apps/cli/src/command-internal/db-bootstrap/health-check.ts index 5480a2393a..5645011f91 100644 --- a/apps/cli/src/command-internal/db-bootstrap/health-check.ts +++ b/apps/cli/src/command-internal/db-bootstrap/health-check.ts @@ -69,7 +69,7 @@ export interface LegacyHealthCheckFailure { } /** Runtime-internal probe sentinel; exported only for the exhaustive actionability guard. */ -export class LegacyHealthCheckProbeError extends Data.TaggedError("LegacyHealthCheckProbeError")<{ +class LegacyHealthCheckProbeError extends Data.TaggedError("LegacyHealthCheckProbeError")<{ readonly failures: ReadonlyArray; }> { get [ErrorActionabilityId](): CliErrorActionabilityDeclaration { diff --git a/apps/cli/src/command-internal/db-bootstrap/reset-local-database.ts b/apps/cli/src/command-internal/db-bootstrap/reset-local-database.ts index ffc6aee7ed..32585d8dc7 100644 --- a/apps/cli/src/command-internal/db-bootstrap/reset-local-database.ts +++ b/apps/cli/src/command-internal/db-bootstrap/reset-local-database.ts @@ -70,7 +70,7 @@ import { legacyRecreateLocalDatabase } from "./recreate-local-database.ts"; * actionability guard can inspect its declaration; runtime callers consume the * enclosing effect rather than importing this class. */ -export class LegacyResetLocalDbNotRunningError extends Data.TaggedError( +class LegacyResetLocalDbNotRunningError extends Data.TaggedError( "LegacyResetLocalDbNotRunningError", )<{ readonly message: string; diff --git a/apps/cli/src/command-internal/db-bootstrap/shadow-cache.ts b/apps/cli/src/command-internal/db-bootstrap/shadow-cache.ts index d1b944bc41..141fc6239e 100644 --- a/apps/cli/src/command-internal/db-bootstrap/shadow-cache.ts +++ b/apps/cli/src/command-internal/db-bootstrap/shadow-cache.ts @@ -120,7 +120,7 @@ const legacyShadowCacheUnavailable = ( // --------------------------------------------------------------------------- /** One of the three PG15+ one-shot migrate jobs, as the cache key sees it. */ -export interface LegacyShadowCacheServiceInput { +interface LegacyShadowCacheServiceInput { readonly enabled: boolean; /** Registry-resolved image; hashed only when {@link enabled}. */ readonly image: string; diff --git a/apps/cli/src/command-internal/db-bootstrap/shadow-database.ts b/apps/cli/src/command-internal/db-bootstrap/shadow-database.ts index 913d83aaee..e2f4e6081b 100644 --- a/apps/cli/src/command-internal/db-bootstrap/shadow-database.ts +++ b/apps/cli/src/command-internal/db-bootstrap/shadow-database.ts @@ -155,7 +155,7 @@ export const LEGACY_SHADOW_CREATE_TEMPLATE_SQL = * (`apps/cli-go/internal/db/diff/diff.go:187,200`, `internal/migration/squash/squash.go:91`) * passes the same `10*time.Second` literal. */ -export const LEGACY_SHADOW_CONNECT_TIMEOUT_SECONDS = 10; +const LEGACY_SHADOW_CONNECT_TIMEOUT_SECONDS = 10; /** * Go's `NewBackoffPolicy(ctx, timeout)` (`apps/cli-go/internal/db/start/start.go:192-198`): a @@ -373,7 +373,7 @@ export interface LegacyShadowSourceResult { } /** Fields shared by `legacy-shadow-source.ts`'s `LegacyPrepareShadowSourceInput` and the shadow readiness probes. */ -export interface LegacyShadowConnectionInput extends LegacyCreateShadowDatabaseInput { +interface LegacyShadowConnectionInput extends LegacyCreateShadowDatabaseInput { readonly fs: FileSystem.FileSystem; readonly path: Path.Path; readonly hostname: string; @@ -777,7 +777,7 @@ export interface LegacyShadowBaselineState { } /** The baseline state every uncached caller passes: provision it, snapshot nothing. */ -export const LEGACY_SHADOW_BASELINE_COLD: LegacyShadowBaselineState = { +const LEGACY_SHADOW_BASELINE_COLD: LegacyShadowBaselineState = { baselinePresent: false, snapshotRequired: false, snapshotBaseline: Effect.void, diff --git a/apps/cli/src/command-internal/db-bootstrap/start-database.ts b/apps/cli/src/command-internal/db-bootstrap/start-database.ts index 986a394224..95c4851437 100644 --- a/apps/cli/src/command-internal/db-bootstrap/start-database.ts +++ b/apps/cli/src/command-internal/db-bootstrap/start-database.ts @@ -109,7 +109,7 @@ type Spawner = ChildProcessSpawner["Service"]; * Exported only so the exhaustive actionability guard can inspect its declaration; * runtime callers observe it through {@link LegacyStartDatabaseError}. */ -export class LegacyStartBackupVolumeExistsError extends Data.TaggedError( +class LegacyStartBackupVolumeExistsError extends Data.TaggedError( "LegacyStartBackupVolumeExistsError", )<{ readonly message: string; diff --git a/apps/cli/src/command-internal/db-bootstrap/start-local-database.ts b/apps/cli/src/command-internal/db-bootstrap/start-local-database.ts index f183673e6d..d3292c27a7 100644 --- a/apps/cli/src/command-internal/db-bootstrap/start-local-database.ts +++ b/apps/cli/src/command-internal/db-bootstrap/start-local-database.ts @@ -99,9 +99,9 @@ function wrapDbConfigOverride( }); } -export type LegacyStartLocalDatabaseStatus = "already-running" | "started"; +type LegacyStartLocalDatabaseStatus = "already-running" | "started"; -export interface LegacyStartLocalDatabaseResult { +interface LegacyStartLocalDatabaseResult { readonly status: LegacyStartLocalDatabaseStatus; } diff --git a/apps/cli/src/command-internal/legacy-config-validate.ts b/apps/cli/src/command-internal/legacy-config-validate.ts index aaca5ce204..02bbee59b3 100644 --- a/apps/cli/src/command-internal/legacy-config-validate.ts +++ b/apps/cli/src/command-internal/legacy-config-validate.ts @@ -918,7 +918,7 @@ export function legacyResolveEmailTemplateContentPath(args: { * loading, and the Kong template mount builder so every consumer sees the * SAME file. */ -export function legacyResolveNotificationContentPath(base: string, contentPath: string): string { +function legacyResolveNotificationContentPath(base: string, contentPath: string): string { if (isAbsolute(contentPath)) return contentPath; const resolved = join(base, contentPath); if (!legacyIsExistingFile(resolved)) { diff --git a/apps/cli/src/command-internal/legacy-db-config.toml-read.ts b/apps/cli/src/command-internal/legacy-db-config.toml-read.ts index e8bd13e24d..5f751e4af2 100644 --- a/apps/cli/src/command-internal/legacy-db-config.toml-read.ts +++ b/apps/cli/src/command-internal/legacy-db-config.toml-read.ts @@ -169,7 +169,7 @@ interface LegacyDbVaultSecretToml { * shape instead of re-declaring it inline, making field drift a compile error * rather than a silent cache-key gap. */ -export interface LegacyBaselineTomlConfig { +interface LegacyBaselineTomlConfig { /** `[auth] enabled`, default true. Gates `initSchema`'s auth service migration. */ readonly authEnabled: boolean; /** `[storage] enabled`, default true. */ @@ -301,7 +301,7 @@ function legacyResolveValidatedRemoteProjectId( * When a matched `[remotes.*]` block supplies any of these, the block value * must beat the matching env override. */ -export const LEGACY_ENV_OVERRIDABLE_KEYS = [ +const LEGACY_ENV_OVERRIDABLE_KEYS = [ // The matched `[remotes.]` block's own `project_id` field is what selected it in the // first place (`applyRemoteOverride` above matches on exactly this key) — same override-tier // reasoning as every other key in this array. NOT guaranteed present, though: a block can also diff --git a/apps/cli/src/command-internal/legacy-db-image.ts b/apps/cli/src/command-internal/legacy-db-image.ts index b2c4798274..9ef0e418ad 100644 --- a/apps/cli/src/command-internal/legacy-db-image.ts +++ b/apps/cli/src/command-internal/legacy-db-image.ts @@ -54,16 +54,6 @@ function compareSemver(a: string, b: string): number { return 0; } -export interface LegacyResolvedDbImage { - /** Pull/create reference — slim-translated when the flag is on and the pin is current. */ - readonly image: string; - /** - * Unprefixed docker.io / OrioleDB / 13–15 identity for version-compare. - * Never `ghcr.io/...` — {@link legacyPostgresImageVersionTag} splits on the first `:`. - */ - readonly configImage: string; -} - /** * Resolve the Postgres image for `majorVersion`, honoring the pinned version * written by `supabase start` to `supabase/.temp/postgres-version` (Go reads diff --git a/apps/cli/src/command-internal/legacy-docker-lifecycle.ts b/apps/cli/src/command-internal/legacy-docker-lifecycle.ts index d8e8470163..1bf6d1bfa4 100644 --- a/apps/cli/src/command-internal/legacy-docker-lifecycle.ts +++ b/apps/cli/src/command-internal/legacy-docker-lifecycle.ts @@ -1,4 +1,4 @@ -import { isDockerDaemonDownMessage } from "@supabase/stack/effect"; +import { isDockerDaemonDownMessage } from "../shared/stack-constants.ts"; import { Data, Effect, Stream } from "effect"; import type { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner"; diff --git a/apps/cli/src/command-internal/legacy-docker-remove-all.ts b/apps/cli/src/command-internal/legacy-docker-remove-all.ts index d16158aa34..8b49b879d0 100644 --- a/apps/cli/src/command-internal/legacy-docker-remove-all.ts +++ b/apps/cli/src/command-internal/legacy-docker-remove-all.ts @@ -27,9 +27,7 @@ type Spawner = ChildProcessSpawner["Service"]; * their string `_tag`, never by importing the classes themselves. The classes * are exported so the exhaustive telemetry guard can verify their declarations. */ -export class LegacyDockerRemoveAllListError extends Data.TaggedError( - "LegacyDockerRemoveAllListError", -)<{ +class LegacyDockerRemoveAllListError extends Data.TaggedError("LegacyDockerRemoveAllListError")<{ readonly message: string; }> { get [ErrorActionabilityId](): CliErrorActionabilityDeclaration { @@ -37,9 +35,7 @@ export class LegacyDockerRemoveAllListError extends Data.TaggedError( } } -export class LegacyDockerRemoveAllStopError extends Data.TaggedError( - "LegacyDockerRemoveAllStopError", -)<{ +class LegacyDockerRemoveAllStopError extends Data.TaggedError("LegacyDockerRemoveAllStopError")<{ readonly message: string; }> { get [ErrorActionabilityId](): CliErrorActionabilityDeclaration { @@ -47,7 +43,7 @@ export class LegacyDockerRemoveAllStopError extends Data.TaggedError( } } -export class LegacyDockerRemoveAllContainerPruneError extends Data.TaggedError( +class LegacyDockerRemoveAllContainerPruneError extends Data.TaggedError( "LegacyDockerRemoveAllContainerPruneError", )<{ readonly message: string; @@ -57,7 +53,7 @@ export class LegacyDockerRemoveAllContainerPruneError extends Data.TaggedError( } } -export class LegacyDockerRemoveAllVolumePruneError extends Data.TaggedError( +class LegacyDockerRemoveAllVolumePruneError extends Data.TaggedError( "LegacyDockerRemoveAllVolumePruneError", )<{ readonly message: string; @@ -67,7 +63,7 @@ export class LegacyDockerRemoveAllVolumePruneError extends Data.TaggedError( } } -export class LegacyDockerRemoveAllNetworkPruneError extends Data.TaggedError( +class LegacyDockerRemoveAllNetworkPruneError extends Data.TaggedError( "LegacyDockerRemoveAllNetworkPruneError", )<{ readonly message: string; diff --git a/apps/cli/src/command-internal/legacy-edge-runtime-script.service.ts b/apps/cli/src/command-internal/legacy-edge-runtime-script.service.ts index 9f0dc26341..6fcc794d84 100644 --- a/apps/cli/src/command-internal/legacy-edge-runtime-script.service.ts +++ b/apps/cli/src/command-internal/legacy-edge-runtime-script.service.ts @@ -48,7 +48,7 @@ export interface LegacyEdgeRuntimeRunOpts { readonly workdir?: string; } -export interface LegacyEdgeRuntimeRunResult { +interface LegacyEdgeRuntimeRunResult { readonly stdout: string; readonly stderr: string; } diff --git a/apps/cli/src/command-internal/legacy-local-config-values.ts b/apps/cli/src/command-internal/legacy-local-config-values.ts index 2dab9d896b..ae741e9245 100644 --- a/apps/cli/src/command-internal/legacy-local-config-values.ts +++ b/apps/cli/src/command-internal/legacy-local-config-values.ts @@ -3,7 +3,11 @@ import { basename } from "node:path"; import type { CliConfig } from "@supabase/config"; import { ENV_CAPTURE_REGEX } from "@supabase/config/internal"; -import { defaultJwtSecret, defaultPublishableKey, defaultSecretKey } from "@supabase/stack/effect"; +import { + defaultJwtSecret, + defaultPublishableKey, + defaultSecretKey, +} from "../shared/stack-constants.ts"; import { Schema } from "effect"; import { diff --git a/apps/cli/src/command-internal/legacy-password-requirements.ts b/apps/cli/src/command-internal/legacy-password-requirements.ts index 5488817f97..06baf8a5a1 100644 --- a/apps/cli/src/command-internal/legacy-password-requirements.ts +++ b/apps/cli/src/command-internal/legacy-password-requirements.ts @@ -7,7 +7,7 @@ * GoTrue service environment (`GOTRUE_PASSWORD_REQUIRED_CHARACTERS`), so the * two can never drift apart. */ -export const LEGACY_PASSWORD_REQUIREMENTS_TO_CHAR: Readonly> = { +const LEGACY_PASSWORD_REQUIREMENTS_TO_CHAR: Readonly> = { letters_digits: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ:0123456789", lower_upper_letters_digits: "abcdefghijklmnopqrstuvwxyz:ABCDEFGHIJKLMNOPQRSTUVWXYZ:0123456789", lower_upper_letters_digits_symbols: diff --git a/apps/cli/src/command-internal/legacy-size-units.ts b/apps/cli/src/command-internal/legacy-size-units.ts index 68cf70e2ab..e17cb5d781 100644 --- a/apps/cli/src/command-internal/legacy-size-units.ts +++ b/apps/cli/src/command-internal/legacy-size-units.ts @@ -1,9 +1,7 @@ /** * Ports of `github.com/docker/go-units` used by Go's `sizeInBytes` * (`pkg/config/config.go`). `file_size_limit` config values are parsed with - * `RAMInBytes` and re-serialised in the diff with `BytesSize` (`sizeInBytes` - * implements `MarshalText`, so BurntSushi emits a quoted human-readable size, - * e.g. `"5MiB"`). + * `RAMInBytes` before being sent to service APIs. * * Shared across the legacy shell: `config push` (storage/auth/api/db diffing) * and `seed buckets` (which converts each `[storage.buckets.*].file_size_limit` @@ -20,8 +18,6 @@ const BINARY_MAP: Readonly> = { p: 1024 ** 5, }; -const BINARY_ABBRS = ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"] as const; - const DIGIT_OR_DOT_OR_SPACE = "0123456789. "; /** @@ -100,37 +96,3 @@ export function ramInBytes(sizeStr: string): number { } return Math.trunc(size * mul); } - -/** - * Port of Go's `fmt`-style `%.4g`: at most 4 significant digits, trailing zeros - * removed, no exponent for the magnitudes `BytesSize` produces (scaled to - * `[0, 1024)`). - */ -function formatG4(n: number): string { - if (n === 0) return "0"; - let s = n.toPrecision(4); - if (s.includes("e") || s.includes("E")) { - return s; - } - if (s.includes(".")) { - s = s.replace(/0+$/, "").replace(/\.$/, ""); - } - return s; -} - -/** Port of Go `cast.IntToUint`: clamp negative values to 0 (Go takes an `int`, so no truncation). */ -export function intToUint(value: number): number { - return value < 0 ? 0 : value; -} - -/** Port of `units.BytesSize` — `CustomSize("%.4g%s", size, 1024, binaryAbbrs)`. */ -export function bytesSize(size: number): string { - let value = size; - let i = 0; - const limit = BINARY_ABBRS.length - 1; - while (value >= 1024 && i < limit) { - value = value / 1024; - i++; - } - return formatG4(value) + BINARY_ABBRS[i]; -} diff --git a/apps/cli/src/command-internal/legacy-storage-credentials.ts b/apps/cli/src/command-internal/legacy-storage-credentials.ts index eea990b3f6..284bbd374f 100644 --- a/apps/cli/src/command-internal/legacy-storage-credentials.ts +++ b/apps/cli/src/command-internal/legacy-storage-credentials.ts @@ -1,4 +1,4 @@ -import { defaultJwtSecret, generateJwt } from "@supabase/stack/effect"; +import { defaultJwtSecret, generateJwt } from "../shared/stack-constants.ts"; import { Effect, FileSystem, Path } from "effect"; import { LegacyPlatformApiFactory } from "../auth/legacy-platform-api-factory.service.ts"; diff --git a/apps/cli/src/command-internal/legacy-workdir-project.ts b/apps/cli/src/command-internal/legacy-workdir-project.ts index 4fa52f5627..c753fa5e29 100644 --- a/apps/cli/src/command-internal/legacy-workdir-project.ts +++ b/apps/cli/src/command-internal/legacy-workdir-project.ts @@ -83,7 +83,7 @@ export const legacyMissingProjectConfigMessageEffect = Effect.fnUntraced(functio * their own command-specific error type, matching the established pattern * for `LegacyWorkdirValidationError`. */ -export class LegacyWorkdirProjectMissingError extends Data.TaggedError( +class LegacyWorkdirProjectMissingError extends Data.TaggedError( "LegacyWorkdirProjectMissingError", )<{ readonly message: string; diff --git a/apps/cli/src/commands/config/pull/pull.command.ts b/apps/cli/src/commands/config/pull/pull.command.ts index e0b58dc86a..6afdd0e0aa 100644 --- a/apps/cli/src/commands/config/pull/pull.command.ts +++ b/apps/cli/src/commands/config/pull/pull.command.ts @@ -39,9 +39,7 @@ const config = { export type LegacyConfigPullFlags = CliCommand.Command.Config.Infer; -// Exported so integration tests can drive the exact wiring -// `Command.withHandler` uses below (same precedent as `legacyConfigDiffHandler`). -export const legacyConfigPullHandler = (flags: LegacyConfigPullFlags) => +const legacyConfigPullHandler = (flags: LegacyConfigPullFlags) => legacyConfigPull(flags).pipe( // `--project-ref` accepts branch names here (CLI-2167 vocabulary), so its // value is only safe to log verbatim when it is actually ref-shaped — a diff --git a/apps/cli/src/commands/config/pull/pull.format.ts b/apps/cli/src/commands/config/pull/pull.format.ts index d6f987c6cb..2d3b102f6c 100644 --- a/apps/cli/src/commands/config/pull/pull.format.ts +++ b/apps/cli/src/commands/config/pull/pull.format.ts @@ -44,7 +44,7 @@ export const LEGACY_CONFIG_PULL_PAYLOAD_VERSION = 1; * change `legacyPlanConfigPull` planned to write still ends up unwritten when * the run is a dry run or the user declined. */ -export type LegacyConfigPullChangeSkipReason = LegacyConfigPullSkipReason | "declined" | "dry_run"; +type LegacyConfigPullChangeSkipReason = LegacyConfigPullSkipReason | "declined" | "dry_run"; /** * The run's actual outcome, known only after the confirmation prompt (or diff --git a/apps/cli/src/commands/config/pull/pull.plan.ts b/apps/cli/src/commands/config/pull/pull.plan.ts index bb5702c61a..dd61e462c6 100644 --- a/apps/cli/src/commands/config/pull/pull.plan.ts +++ b/apps/cli/src/commands/config/pull/pull.plan.ts @@ -55,12 +55,12 @@ export type LegacyConfigPullSkipReason = | "unwritable" | "would_invalidate"; -export interface LegacyConfigPullSkip { +interface LegacyConfigPullSkip { readonly change: ConfigChange; readonly reason: LegacyConfigPullSkipReason; } -export interface LegacyConfigPullPlannedWrite { +interface LegacyConfigPullPlannedWrite { readonly change: ConfigChange; /** `change.path`, prefixed with `["remotes", label]` when the destination * is a `[remotes.*]` block — the exact path `applyConfigEdits` edits. */ @@ -68,7 +68,7 @@ export interface LegacyConfigPullPlannedWrite { readonly value: ConfigEditValue; } -export type LegacyConfigPullWarningKind = +type LegacyConfigPullWarningKind = | "dual_scope" | "duplicates_root" | "array_drift" diff --git a/apps/cli/src/commands/config/pull/pull.scope.ts b/apps/cli/src/commands/config/pull/pull.scope.ts index a4b2712e5c..3efb492830 100644 --- a/apps/cli/src/commands/config/pull/pull.scope.ts +++ b/apps/cli/src/commands/config/pull/pull.scope.ts @@ -39,11 +39,11 @@ import { legacySanitizeInlineName } from "../../../command-internal/legacy-http- * 5. Otherwise: the config root. */ -export interface LegacyConfigPullDestinationRoot { +interface LegacyConfigPullDestinationRoot { readonly kind: "root"; } -export interface LegacyConfigPullDestinationRemote { +interface LegacyConfigPullDestinationRemote { readonly kind: "remote"; /** * The `[remotes.