diff --git a/packages/api/scripts/dependent-types-check-cache.unit.test.ts b/packages/api/scripts/dependent-types-check-cache.unit.test.ts new file mode 100644 index 0000000000..f5d0b03a8e --- /dev/null +++ b/packages/api/scripts/dependent-types-check-cache.unit.test.ts @@ -0,0 +1,71 @@ +import { execFileSync } from "node:child_process"; +import { closeSync, mkdtempSync, openSync, readFileSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { describe, expect, test } from "vitest"; + +// The scheduled API sync only rewrites this package, and the project-config mirror lives in +// @supabase/config, so apps/cli's type-level drift guards only run on a PR touching either if turbo +// folds that package's files into the dependent's cached `types:check` hash via `transit`. + +const scriptDir = path.dirname(fileURLToPath(import.meta.url)); +const packageDir = path.join(scriptDir, ".."); +const repoDir = path.join(packageDir, "..", ".."); +const turboBin = path.join(repoDir, "node_modules", ".bin", "turbo"); + +type DryRunTask = { readonly taskId: string; readonly dependencies: ReadonlyArray }; + +function dryRunTypesCheckForDependents(packageName: string): ReadonlyArray { + // Redirects stdout to a file: Bun on Linux truncates a child's piped stdout at ~219 KB, and + // the dry-run JSON lists every hashed input file. + const tempDir = mkdtempSync(path.join(tmpdir(), "turbo-dry-run-")); + try { + const outputPath = path.join(tempDir, "dry-run.json"); + const fd = openSync(outputPath, "w"); + try { + execFileSync(turboBin, ["run", "types:check", `--filter=...${packageName}`, "--dry=json"], { + cwd: repoDir, + stdio: ["ignore", fd, "pipe"], + }); + } finally { + closeSync(fd); + } + return JSON.parse(readFileSync(outputPath, "utf8")).tasks; + } finally { + rmSync(tempDir, { recursive: true, force: true }); + } +} + +function reachableTaskIds(tasks: ReadonlyArray, from: string): ReadonlySet { + const byId = new Map(tasks.map((task) => [task.taskId, task])); + const seen = new Set(); + const pending = [from]; + while (pending.length > 0) { + const taskId = pending.pop(); + if (taskId === undefined || seen.has(taskId)) continue; + seen.add(taskId); + pending.push(...(byId.get(taskId)?.dependencies ?? [])); + } + return seen; +} + +describe("dependent types:check cache key", () => { + test.each(["@supabase/api", "@supabase/config"])( + "includes %s's files for every workspace that depends on it", + (packageName) => { + const tasks = dryRunTypesCheckForDependents(packageName); + const dependentTypesChecks = tasks + .map((task) => task.taskId) + .filter( + (taskId) => taskId.endsWith("#types:check") && !taskId.startsWith(`${packageName}#`), + ); + + expect(dependentTypesChecks).toContain("supabase#types:check"); + for (const taskId of dependentTypesChecks) { + expect(reachableTaskIds(tasks, taskId), taskId).toContain(`${packageName}#transit`); + } + }, + 60_000, + ); +}); diff --git a/packages/config/src/project-config/api-attributes.ts b/packages/config/src/project-config/api-attributes.ts index 2a385e91cc..dca32a9ec1 100644 --- a/packages/config/src/project-config/api-attributes.ts +++ b/packages/config/src/project-config/api-attributes.ts @@ -12,6 +12,8 @@ import { Schema } from "effect"; const postgresSettingsAttributes = Schema.Struct({ effective_cache_size: Schema.optionalKey(Schema.String), logical_decoding_work_mem: Schema.optionalKey(Schema.String), + autovacuum_max_workers: Schema.optionalKey(Schema.Unknown), + autovacuum_work_mem: Schema.optionalKey(Schema.Unknown), log_autovacuum_min_duration: Schema.optionalKey(Schema.Unknown), log_checkpoints: Schema.optionalKey(Schema.Unknown), log_connections: Schema.optionalKey(Schema.Unknown), @@ -48,6 +50,8 @@ const postgresSettingsAttributes = Schema.Struct({ checkpoint_timeout: Schema.optionalKey(Schema.Unknown), hot_standby_feedback: Schema.optionalKey(Schema.Unknown), cron_log_statement: Schema.optionalKey(Schema.Unknown), + pg_net_batch_size: Schema.optionalKey(Schema.Unknown), + pg_stat_statements_max: Schema.optionalKey(Schema.Unknown), }); // `allowed_cidrs` is mapped (`filterCidrAddresses`, `./registry.ts`); the rest are unmapped. diff --git a/turbo.json b/turbo.json index 70cb4b17c8..b5406cad4e 100644 --- a/turbo.json +++ b/turbo.json @@ -4,8 +4,12 @@ "strictTaskEntrypointSelection": true }, "tasks": { + "transit": { + "dependsOn": ["^transit"] + }, "types:check": { - "cache": true + "cache": true, + "dependsOn": ["transit"] }, "lint:check": { "cache": false @@ -33,6 +37,7 @@ }, "@supabase/docs#types:check": { "cache": true, + "dependsOn": ["transit"], "outputs": [".source/**"] }, "test:unit:run": {