Ctrl K
ComunidadGuías…

scripts/supabase-worktree-config.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { createHash } from 'node:crypto'
import { spawnSync } from 'node:child_process'
import { realpathSync } from 'node:fs'
import { resolve } from 'node:path'

export interface SupabaseWorktreePorts {
  api: number
  db: number
  dbShadow: number
  dbPooler: number
  studio: number
  inbucket: number
  analytics: number
  edgeInspector: number
}

export interface SupabaseWorktreeConfig {
  repoRoot: string
  worktreeHash: string
  projectId: string
  ports: SupabaseWorktreePorts
}

/**
 * Best-effort repo root lookup for the current worktree.
 *
 * Falls back to `cwd` when git is unavailable.
 */
function getGitRepoRoot(cwd: string): string {
  const res = spawnSync('git', ['rev-parse', '--show-toplevel'], {
    cwd,
    encoding: 'utf8',
  })
  if (res.status === 0) {
    const out = (res.stdout || '').trim()
    if (out)
      return out
  }
  return cwd
}

/**
 * Resolve a deliberate CI port band when jobs share a runner.
 *
 * The default remains path-derived for local worktrees; CI supplies a reserved,
 * ten-port-aligned band so its jobs never depend on the runner's default ports.
 */
function getConfiguredPortOffset(): number | undefined {
  const raw = process.env.SUPABASE_WORKTREE_PORT_OFFSET
  if (!raw)
    return undefined

  if (!/^\d+$/.test(raw))
    throw new Error('SUPABASE_WORKTREE_PORT_OFFSET must be a non-negative integer.')

  const offset = Number(raw)
  if (!Number.isSafeInteger(offset) || offset % 10 !== 0 || offset > 11000)
    throw new Error('SUPABASE_WORKTREE_PORT_OFFSET must be a multiple of 10 no greater than 11000.')

  return offset
}

/**
 * Returns a deterministic per-worktree Supabase configuration (unique project_id and ports)
 * derived from the git worktree path and, when supplied, a CI job instance.
 *
 * This allows running multiple `supabase start` instances in parallel across worktrees
 * without Docker container/volume name collisions or port conflicts.
 */
export function getSupabaseWorktreeConfig(cwd: string = process.cwd()): SupabaseWorktreeConfig {
  const repoRootRaw = getGitRepoRoot(cwd)
  const repoRoot = realpathSync(resolve(repoRootRaw))
  const configuredOffset = getConfiguredPortOffset()
  const instance = process.env.SUPABASE_WORKTREE_INSTANCE?.trim()
  const identity = [repoRoot, instance, configuredOffset === undefined ? undefined : `ports:${configuredOffset}`]
    .filter((value): value is string => Boolean(value))
    .join('\0')

  // Hashing the worktree plus job identity gives isolated Docker resources and generated config.
  const worktreeHash = createHash('sha256').update(identity).digest('hex').slice(0, 8)
  const offset = configuredOffset ?? (Number.parseInt(worktreeHash.slice(0, 6), 16) % 1000) * 10

  const base = {
    api: 54321,
    db: 54322,
    dbShadow: 54320,
    dbPooler: 54329,
    studio: 54323,
    inbucket: 54324,
    analytics: 54327,
    edgeInspector: 8083,
  } satisfies SupabaseWorktreePorts

  return {
    repoRoot,
    worktreeHash,
    projectId: `capgo-app-${worktreeHash}`,
    ports: {
      api: base.api + offset,
      db: base.db + offset,
      dbShadow: base.dbShadow + offset,
      dbPooler: base.dbPooler + offset,
      studio: base.studio + offset,
      inbucket: base.inbucket + offset,
      analytics: base.analytics + offset,
      edgeInspector: base.edgeInspector + (offset / 10),
    },
  }
}