feat(cli): port bootstrap command to native TypeScript#5470
Merged
Conversation
Replaces the Phase-0 Go proxy for `supabase bootstrap` with a native
TypeScript implementation in the legacy shell. The command orchestrates:
workdir resolve/prompt -> template list/download -> blank init ->
ensure-login -> projects create -> api-keys (backoff) -> link services ->
health poll (backoff) -> write .env -> db push -> start suggestion.
Every step is native except the migration push, which is delegated to the
bundled Go binary via LegacyGoProxy as a documented interim until `db push`
is natively ported (LegacyGoProxy.exec exits on non-zero rather than
failing, so its push backoff is not reproducible from the proxy).
Per the "hoist before you duplicate" policy, shared orchestration cores are
extracted from the already-ported login/create/api-keys/link handlers and
those handlers refactored to delegate:
- legacy-ensure-login (browser login + post-login telemetry)
- legacy-project-create-core
- legacy-get-api-keys
- legacy-link-services-core
- legacy-tenant-keys (legacyExtractServiceKeys)
- login api/crypto layers moved to legacy/shared so bootstrap composes them
without a cross-command import
Go-parity notes:
- bootstrap fires no cli_project_linked event: Go calls link.LinkServices
(services only), not link.Run, so it skips the project-linked telemetry,
status check, and linked-project.json temp write.
- api-keys are fetched without `reveal` (Go's RunGetApiKeys uses empty params).
- workdir / db-password env vars are read prefixed (SUPABASE_WORKDIR,
SUPABASE_DB_PASSWORD) to match Go's viper SetEnvPrefix("SUPABASE").
- "Using workdir" prints only when the resolved workdir differs from the cwd.
Template download validates entries stay within the target directory, and
GitHub/health error bodies are sanitized before surfacing.
Supabase CLI previewnpx --yes https://pkg.pr.new/supabase@5470Preview package for commit |
avallete
reviewed
Jun 4, 2026
Resolve the review comments on the native bootstrap port: - Retry backoff now reproduces Go's full cenkalti policy (3s initial, factor 1.5, 60s max interval, +/-50% jitter, 15m max elapsed, 8 retries) and the NewErrorCallback "Retry (n/8)" notice (debug logger for failures 1-2, stderr from 3 on, none on the final attempt). Extracted to bootstrap.retry.ts. - linked-project.json now resolves against the bootstrap-resolved workdir via an optional LegacyLinkedProjectCache.cache(ref, workdir?) override, so it lands beside project-ref on the prompt path instead of cliConfig.workdir. - Template download: segment-aware root prefix stripping and an explicit guard for null/empty GitHub download_url (files >1MB / submodules). - Provide legacyDebugLoggerLayer to the bootstrap runtime base layers, fixing a "Service not found: DebugLogger" panic at the first HTTP call that the mocked integration tests could not catch.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
Replaces the Phase-0 Go proxy for
supabase bootstrapwith a native TypeScript implementation in the legacy shell.bootstrapis a meta-orchestrator that chains: workdir resolve/prompt → template list/download → blankinit→ ensure-login →projects create→projects api-keys(backoff) →linkservices → health poll (backoff) → write.env→db push→ start suggestion.Per the "hoist before you duplicate" policy, the shared orchestration is extracted from the already-ported
login/projects create/projects api-keys/linkhandlers intolegacy/shared/, and those handlers are refactored to delegate (no behavior change — their existing tests still pass):legacy-ensure-login(browser login flow + post-login telemetry)legacy-project-create-corelegacy-get-api-keyslegacy-link-services-corelegacy-tenant-keys(legacyExtractServiceKeys)legacy/shared/sobootstrapcan compose them without a cross-command importWhy
Phase 1+ native port of
bootstrap(the last Quick-Start command still proxied), unblocking native machine output (--output-format json|stream-json) and removing the Go dependency for everything except the migration push.Reviewer-relevant context
db pushis delegated to the bundled Go binary (interim). It is the only non-native step, pending a separate nativedb pushport.LegacyGoProxy.execexits the process on a non-zero exit rather than returning a failure, so Go's push backoff cannot be reproduced from the proxy (single attempt). Documented inSIDE_EFFECTS.md.cli_project_linkedtelemetry — Go'sbootstrapcallslink.LinkServices(services-only), notlink.Run, so it deliberately skips the project-linked event, status check, andlinked-project.jsontemp write.reveal(Go'sRunGetApiKeysuses empty params).SUPABASE_WORKDIR,SUPABASE_DB_PASSWORD) to match Go'sviper.SetEnvPrefix("SUPABASE").Using workdir …prints only when the resolved workdir differs from the cwd (matches Go'sChangeWorkDirguard).docs/go-cli-porting-status.mdflipsbootstrapwrapped→portedwith the interim-db-push note.Follow-ups (out of scope)
db pushport will remove the proxy delegation (eliminating the single-attempt and transient--password-in-process-table limitations).bootstrap.e2e.test.tsdeferred — integration coverage is comprehensive; e2e needs replayed API fixtures plus handling of the real Godb pushsubprocess.