From bc150b046e809a085c6e984569cfa0c21e95fd4a Mon Sep 17 00:00:00 2001 From: Wojtek Majewski Date: Wed, 7 Jan 2026 21:23:09 +0100 Subject: [PATCH] fix: update local environment detection and test configurations Refactors local environment detection to rely on SUPABASE_URL host matching LOCAL_SUPABASE_HOST instead of deprecated keys. Updates related tests to use correct environment variables and URLs, ensuring consistent local environment recognition and test accuracy. Also includes minor adjustments to test data and environment setup for clarity and reliability. --- .changeset/fix-local-detection-step-output.md | 9 ++ pkgs/edge-worker/src/shared/localDetection.ts | 38 ++--- .../supabase/functions/auth_test/index.ts | 10 +- .../platform/SupabasePlatformAdapter.test.ts | 18 ++- .../unit/platform/connectionPriority.test.ts | 47 +++--- .../tests/unit/platform/formatters.test.ts | 44 +++--- .../tests/unit/platform/logging.test.ts | 14 +- .../tests/unit/shared/authValidation.test.ts | 14 +- .../tests/unit/shared/localDetection.test.ts | 134 +++++------------- ...auto-compilation-and-worker-management.mdx | 2 +- ...put-storage-for-conditional-execution.mdx} | 12 +- 11 files changed, 129 insertions(+), 213 deletions(-) create mode 100644 .changeset/fix-local-detection-step-output.md rename pkgs/website/src/content/docs/news/{pgflow-0-13-0-cli-fix-step-output-storage-for-conditional-execution.mdx => pgflow-0-13-1-cli-fix-step-output-storage-for-conditional-execution.mdx} (83%) diff --git a/.changeset/fix-local-detection-step-output.md b/.changeset/fix-local-detection-step-output.md new file mode 100644 index 000000000..cfd110e1d --- /dev/null +++ b/.changeset/fix-local-detection-step-output.md @@ -0,0 +1,9 @@ +--- +'@pgflow/edge-worker': patch +'@pgflow/core': patch +--- + +Note: Version 0.13.0 was yanked due to broken local environment detection. This release (0.13.1) includes both the fix and the features from 0.13.0. + +- Fix local environment detection to use SUPABASE_URL instead of API keys +- Add step output storage optimization for 2x faster Map chains (outputs now stored in step_states.output instead of aggregated on-demand) diff --git a/pkgs/edge-worker/src/shared/localDetection.ts b/pkgs/edge-worker/src/shared/localDetection.ts index 29576a58c..f58f46c47 100644 --- a/pkgs/edge-worker/src/shared/localDetection.ts +++ b/pkgs/edge-worker/src/shared/localDetection.ts @@ -1,31 +1,19 @@ -// Old HS256 JWT keys (Supabase CLI v1) -export const KNOWN_LOCAL_ANON_KEY = - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0'; - -export const KNOWN_LOCAL_SERVICE_ROLE_KEY = - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU'; - -// New opaque keys (Supabase CLI v2+) -// Source: https://github.com/supabase/cli/blob/develop/pkg/config/apikeys.go -export const KNOWN_LOCAL_PUBLISHABLE_KEY = - 'sb_publishable_ACJWlzQHlZjBrEguHvfOxg_3BJgxAaH'; - -export const KNOWN_LOCAL_SECRET_KEY = 'sb_secret_N7UND0UgjKTVK-Uodkm0Hg_xSvEMPvz'; +/** + * Local Supabase CLI sets SUPABASE_URL to this Docker-internal API gateway. + */ +export const LOCAL_SUPABASE_HOST = 'kong:8000'; /** - * Checks if the provided environment indicates local Supabase. - * Use when you have access to an env record (e.g., from PlatformAdapter). - * Supports both old HS256 JWT keys and new opaque keys from Supabase CLI v2+. + * Checks if the provided environment indicates local Supabase development. + * Uses SUPABASE_URL to detect local environment (more reliable than key matching). */ export function isLocalSupabaseEnv(env: Record): boolean { - const anonKey = env['SUPABASE_ANON_KEY']; - const serviceRoleKey = env['SUPABASE_SERVICE_ROLE_KEY']; - - const isLocalAnonKey = - anonKey === KNOWN_LOCAL_ANON_KEY || anonKey === KNOWN_LOCAL_PUBLISHABLE_KEY; - const isLocalServiceRoleKey = - serviceRoleKey === KNOWN_LOCAL_SERVICE_ROLE_KEY || - serviceRoleKey === KNOWN_LOCAL_SECRET_KEY; + const supabaseUrl = env['SUPABASE_URL']; + if (!supabaseUrl) return false; - return isLocalAnonKey || isLocalServiceRoleKey; + try { + return new URL(supabaseUrl).host === LOCAL_SUPABASE_HOST; + } catch { + return false; + } } diff --git a/pkgs/edge-worker/supabase/functions/auth_test/index.ts b/pkgs/edge-worker/supabase/functions/auth_test/index.ts index 41bfcb4a9..66a3e44ad 100644 --- a/pkgs/edge-worker/supabase/functions/auth_test/index.ts +++ b/pkgs/edge-worker/supabase/functions/auth_test/index.ts @@ -2,9 +2,7 @@ import { EdgeWorker } from '@pgflow/edge-worker'; import { configurePlatform } from '@pgflow/edge-worker/testing'; import { sql } from '../utils.ts'; -// Production-like keys (NOT the known local demo keys) -// These must match the values used in tests/e2e/authorization.test.ts -export const PRODUCTION_ANON_KEY = 'test-production-anon-key-abc123'; +// Production-like service role key for auth validation (must match test's Bearer token) export const PRODUCTION_SERVICE_ROLE_KEY = 'test-production-service-role-key-xyz789'; // Docker-internal URL for Supabase transaction pooler @@ -12,13 +10,13 @@ const DOCKER_POOLER_URL = 'postgresql://postgres.pooler-dev:postgres@pooler:6543 // Override environment BEFORE EdgeWorker.start() to enable auth validation // This simulates production mode where auth is NOT bypassed -// Note: We must include EDGE_WORKER_DB_URL because with production keys, +// Note: We must include EDGE_WORKER_DB_URL because with production SUPABASE_URL, // isLocalSupabaseEnv() returns false and the docker pooler fallback won't trigger configurePlatform({ getEnv: () => ({ ...Deno.env.toObject(), - SUPABASE_ANON_KEY: PRODUCTION_ANON_KEY, - SUPABASE_SERVICE_ROLE_KEY: PRODUCTION_SERVICE_ROLE_KEY, + SUPABASE_URL: 'https://test-project.supabase.co', // Production URL + SUPABASE_SERVICE_ROLE_KEY: PRODUCTION_SERVICE_ROLE_KEY, // For auth validation EDGE_WORKER_DB_URL: DOCKER_POOLER_URL, }), }); diff --git a/pkgs/edge-worker/tests/unit/platform/SupabasePlatformAdapter.test.ts b/pkgs/edge-worker/tests/unit/platform/SupabasePlatformAdapter.test.ts index 54408e4b4..6d22d5488 100644 --- a/pkgs/edge-worker/tests/unit/platform/SupabasePlatformAdapter.test.ts +++ b/pkgs/edge-worker/tests/unit/platform/SupabasePlatformAdapter.test.ts @@ -214,16 +214,14 @@ Deno.test({ // ============================================================ Deno.test({ - name: 'isLocalEnvironment returns true for local Supabase keys', + name: 'isLocalEnvironment returns true for local Supabase URL (kong)', sanitizeResources: false, fn: () => { - const KNOWN_LOCAL_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0'; - const deps = createMockDeps({ getEnv: () => ({ - SUPABASE_URL: 'http://test.supabase.co', - SUPABASE_ANON_KEY: KNOWN_LOCAL_ANON_KEY, - SUPABASE_SERVICE_ROLE_KEY: 'test-service-key', + SUPABASE_URL: 'http://kong:8000', // Local dev URL + SUPABASE_ANON_KEY: 'any-anon-key', + SUPABASE_SERVICE_ROLE_KEY: 'any-service-key', SB_EXECUTION_ID: 'test-exec-id', EDGE_WORKER_DB_URL: 'postgresql://postgres:postgres@localhost:54322/postgres', }), @@ -236,14 +234,14 @@ Deno.test({ }); Deno.test({ - name: 'isLocalEnvironment returns false for production keys', + name: 'isLocalEnvironment returns false for production URL', sanitizeResources: false, fn: () => { const deps = createMockDeps({ getEnv: () => ({ - SUPABASE_URL: 'http://test.supabase.co', - SUPABASE_ANON_KEY: 'production-anon-key', - SUPABASE_SERVICE_ROLE_KEY: 'production-service-key', + SUPABASE_URL: 'https://abc123.supabase.co', // Production URL + SUPABASE_ANON_KEY: 'any-anon-key', + SUPABASE_SERVICE_ROLE_KEY: 'any-service-key', SB_EXECUTION_ID: 'test-exec-id', EDGE_WORKER_DB_URL: 'postgresql://postgres:postgres@localhost:54322/postgres', }), diff --git a/pkgs/edge-worker/tests/unit/platform/connectionPriority.test.ts b/pkgs/edge-worker/tests/unit/platform/connectionPriority.test.ts index bda4ca7ea..d481dc157 100644 --- a/pkgs/edge-worker/tests/unit/platform/connectionPriority.test.ts +++ b/pkgs/edge-worker/tests/unit/platform/connectionPriority.test.ts @@ -1,8 +1,4 @@ import { assertEquals, assertThrows } from '@std/assert'; -import { - KNOWN_LOCAL_ANON_KEY, - KNOWN_LOCAL_SERVICE_ROLE_KEY, -} from '../../../src/shared/localDetection.ts'; import { resolveConnectionString, assertConnectionAvailable, @@ -11,31 +7,28 @@ import { } from '../../../src/platform/resolveConnection.ts'; import postgres from 'postgres'; +// Local URL for test envs (triggers isLocalSupabaseEnv = true) +const LOCAL_SUPABASE_URL = 'http://kong:8000'; + // ============================================================ // Local environment tests // ============================================================ Deno.test('connection priority - local env uses Docker pooler URL by default', () => { - const env = { SUPABASE_ANON_KEY: KNOWN_LOCAL_ANON_KEY }; - const result = resolveConnectionString(env); - assertEquals(result, DOCKER_TRANSACTION_POOLER_URL); -}); - -Deno.test('connection priority - local env with service role key uses Docker pooler URL', () => { - const env = { SUPABASE_SERVICE_ROLE_KEY: KNOWN_LOCAL_SERVICE_ROLE_KEY }; + const env = { SUPABASE_URL: LOCAL_SUPABASE_URL }; const result = resolveConnectionString(env); assertEquals(result, DOCKER_TRANSACTION_POOLER_URL); }); Deno.test('connection priority - local env respects config.connectionString override', () => { - const env = { SUPABASE_ANON_KEY: KNOWN_LOCAL_ANON_KEY }; + const env = { SUPABASE_URL: LOCAL_SUPABASE_URL }; const options = { connectionString: 'postgresql://custom:5432/db' }; const result = resolveConnectionString(env, options); assertEquals(result, 'postgresql://custom:5432/db'); }); Deno.test('connection priority - local env respects config.sql override', () => { - const env = { SUPABASE_ANON_KEY: KNOWN_LOCAL_ANON_KEY }; + const env = { SUPABASE_URL: LOCAL_SUPABASE_URL }; const options = { hasSql: true }; const result = resolveConnectionString(env, options); // When sql is provided, we don't use the local pooler URL @@ -45,7 +38,7 @@ Deno.test('connection priority - local env respects config.sql override', () => Deno.test('connection priority - local env with EDGE_WORKER_DB_URL uses it instead of docker pooler', () => { const env = { - SUPABASE_ANON_KEY: KNOWN_LOCAL_ANON_KEY, + SUPABASE_URL: LOCAL_SUPABASE_URL, EDGE_WORKER_DB_URL: 'postgresql://custom-local:5432/db', }; const result = resolveConnectionString(env); @@ -58,7 +51,7 @@ Deno.test('connection priority - local env with EDGE_WORKER_DB_URL uses it inste Deno.test('connection priority - production uses EDGE_WORKER_DB_URL', () => { const env = { - SUPABASE_ANON_KEY: 'prod-anon-key', + SUPABASE_URL: 'https://abc123.supabase.co', EDGE_WORKER_DB_URL: 'postgresql://prod:5432/db', }; const result = resolveConnectionString(env); @@ -67,7 +60,7 @@ Deno.test('connection priority - production uses EDGE_WORKER_DB_URL', () => { Deno.test('connection priority - production config.connectionString overrides env var', () => { const env = { - SUPABASE_ANON_KEY: 'prod-anon-key', + SUPABASE_URL: 'https://abc123.supabase.co', EDGE_WORKER_DB_URL: 'postgresql://prod:5432/db', }; const options = { connectionString: 'postgresql://override:5432/db' }; @@ -76,7 +69,7 @@ Deno.test('connection priority - production config.connectionString overrides en }); Deno.test('connection priority - production returns undefined when nothing configured', () => { - const env = { SUPABASE_ANON_KEY: 'prod-anon-key' }; + const env = { SUPABASE_URL: 'https://abc123.supabase.co' }; const result = resolveConnectionString(env); assertEquals(result, undefined); }); @@ -86,7 +79,7 @@ Deno.test('connection priority - production returns undefined when nothing confi // ============================================================ Deno.test('connection validation - throws when no connection available on production', () => { - const env = { SUPABASE_ANON_KEY: 'prod-anon-key' }; + const env = { SUPABASE_URL: 'https://abc123.supabase.co' }; const connectionString = resolveConnectionString(env); assertThrows( @@ -108,7 +101,7 @@ Deno.test('connection validation - does not throw when sql is provided', () => { }); Deno.test('connection validation - error message lists all options', () => { - const env = { SUPABASE_ANON_KEY: 'prod-anon-key' }; + const env = { SUPABASE_URL: 'https://abc123.supabase.co' }; const connectionString = resolveConnectionString(env); try { @@ -128,7 +121,7 @@ Deno.test('connection validation - error message lists all options', () => { Deno.test('connection priority - preview branch fallback pattern works', () => { // Simulates: connectionString: Deno.env.get('EDGE_WORKER_DB_URL') || Deno.env.get('SUPABASE_DB_URL') const env = { - SUPABASE_ANON_KEY: 'prod-anon-key', + SUPABASE_URL: 'https://abc123.supabase.co', // EDGE_WORKER_DB_URL not set (preview branch) }; @@ -146,7 +139,7 @@ Deno.test('connection priority - preview branch fallback pattern works', () => { Deno.test('resolveSqlConnection - priority 1: returns provided sql directly', () => { const mockSql = postgres('postgresql://mock:5432/db'); - const env = { SUPABASE_ANON_KEY: 'prod-anon-key' }; + const env = { SUPABASE_URL: 'https://abc123.supabase.co' }; const result = resolveSqlConnection(env, { sql: mockSql }); @@ -155,7 +148,7 @@ Deno.test('resolveSqlConnection - priority 1: returns provided sql directly', () }); Deno.test('resolveSqlConnection - priority 2: creates sql from connectionString', () => { - const env = { SUPABASE_ANON_KEY: 'prod-anon-key' }; + const env = { SUPABASE_URL: 'https://abc123.supabase.co' }; const options = { connectionString: 'postgresql://custom:5432/db' }; const result = resolveSqlConnection(env, options); @@ -166,7 +159,7 @@ Deno.test('resolveSqlConnection - priority 2: creates sql from connectionString' Deno.test('resolveSqlConnection - priority 3: creates sql from EDGE_WORKER_DB_URL', () => { const env = { - SUPABASE_ANON_KEY: 'prod-anon-key', + SUPABASE_URL: 'https://abc123.supabase.co', EDGE_WORKER_DB_URL: 'postgresql://env-var:5432/db', }; @@ -177,7 +170,7 @@ Deno.test('resolveSqlConnection - priority 3: creates sql from EDGE_WORKER_DB_UR }); Deno.test('resolveSqlConnection - priority 4: creates sql from Docker URL in local env', () => { - const env = { SUPABASE_ANON_KEY: KNOWN_LOCAL_ANON_KEY }; + const env = { SUPABASE_URL: LOCAL_SUPABASE_URL }; const result = resolveSqlConnection(env); @@ -186,7 +179,7 @@ Deno.test('resolveSqlConnection - priority 4: creates sql from Docker URL in loc }); Deno.test('resolveSqlConnection - throws when nothing configured in production', () => { - const env = { SUPABASE_ANON_KEY: 'prod-anon-key' }; + const env = { SUPABASE_URL: 'https://abc123.supabase.co' }; assertThrows( () => resolveSqlConnection(env), @@ -197,7 +190,7 @@ Deno.test('resolveSqlConnection - throws when nothing configured in production', Deno.test('resolveSqlConnection - connectionString takes priority over EDGE_WORKER_DB_URL', () => { const env = { - SUPABASE_ANON_KEY: 'prod-anon-key', + SUPABASE_URL: 'https://abc123.supabase.co', EDGE_WORKER_DB_URL: 'postgresql://env-var:5432/db', }; const options = { connectionString: 'postgresql://explicit:5432/db' }; @@ -212,7 +205,7 @@ Deno.test('resolveSqlConnection - connectionString takes priority over EDGE_WORK Deno.test('resolveSqlConnection - sql takes priority over everything', () => { const mockSql = postgres('postgresql://mock:5432/db'); const env = { - SUPABASE_ANON_KEY: KNOWN_LOCAL_ANON_KEY, + SUPABASE_URL: LOCAL_SUPABASE_URL, EDGE_WORKER_DB_URL: 'postgresql://env-var:5432/db', }; const options = { diff --git a/pkgs/edge-worker/tests/unit/platform/formatters.test.ts b/pkgs/edge-worker/tests/unit/platform/formatters.test.ts index d33049037..daf8d671f 100644 --- a/pkgs/edge-worker/tests/unit/platform/formatters.test.ts +++ b/pkgs/edge-worker/tests/unit/platform/formatters.test.ts @@ -39,7 +39,7 @@ Deno.test('FancyFormatter - taskCompleted outputs correct format with worker pre try { const factory = createLoggingFactory({ - SUPABASE_ANON_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0', + SUPABASE_URL: 'http://kong:8000', }); const logger = factory.createLogger('test'); @@ -81,7 +81,7 @@ Deno.test('FancyFormatter - taskCompleted shows colors when colorsEnabled', () = try { const factory = createLoggingFactory({ - SUPABASE_ANON_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0', + SUPABASE_URL: 'http://kong:8000', }); const logger = factory.createLogger('test'); @@ -112,7 +112,7 @@ Deno.test('FancyFormatter - taskFailed outputs error with worker prefix and flow try { const factory = createLoggingFactory({ - SUPABASE_ANON_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0', + SUPABASE_URL: 'http://kong:8000', }); const logger = factory.createLogger('test'); @@ -152,7 +152,7 @@ Deno.test('FancyFormatter - taskStarted outputs dim styling with identifiers (de try { const factory = createLoggingFactory({ - SUPABASE_ANON_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0', + SUPABASE_URL: 'http://kong:8000', EDGE_WORKER_LOG_LEVEL: 'debug', }); const logger = factory.createLogger('test'); @@ -192,7 +192,7 @@ Deno.test('FancyFormatter - taskStarted NOT logged when level is verbose', () => try { const factory = createLoggingFactory({ - SUPABASE_ANON_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0', + SUPABASE_URL: 'http://kong:8000', EDGE_WORKER_LOG_LEVEL: 'verbose', }); const logger = factory.createLogger('test'); @@ -221,7 +221,7 @@ Deno.test('FancyFormatter - retry information displayed when retryAttempt > 1', try { const factory = createLoggingFactory({ - SUPABASE_ANON_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0', + SUPABASE_URL: 'http://kong:8000', }); const logger = factory.createLogger('test'); @@ -254,7 +254,7 @@ Deno.test('FancyFormatter - polling outputs with worker prefix', () => { try { const factory = createLoggingFactory({ - SUPABASE_ANON_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0', + SUPABASE_URL: 'http://kong:8000', }); factory.setWorkerName('greet-user-worker'); const logger = factory.createLogger('test'); @@ -278,7 +278,7 @@ Deno.test('FancyFormatter - taskCount shows count with worker prefix when > 0', try { const factory = createLoggingFactory({ - SUPABASE_ANON_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0', + SUPABASE_URL: 'http://kong:8000', }); factory.setWorkerName('greet-user-worker'); const logger = factory.createLogger('test'); @@ -304,7 +304,7 @@ Deno.test('FancyFormatter - taskCount muted with worker prefix when count is 0', try { const factory = createLoggingFactory({ - SUPABASE_ANON_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0', + SUPABASE_URL: 'http://kong:8000', }); factory.setWorkerName('greet-user-worker'); const logger = factory.createLogger('test'); @@ -328,7 +328,7 @@ Deno.test('FancyFormatter - startupBanner shows multi-flow with aligned list', ( try { const factory = createLoggingFactory({ - SUPABASE_ANON_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0', + SUPABASE_URL: 'http://kong:8000', }); const logger = factory.createLogger('test'); @@ -372,7 +372,7 @@ Deno.test('FancyFormatter - shutdown shows correct phase with worker prefix', () try { const factory = createLoggingFactory({ - SUPABASE_ANON_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0', + SUPABASE_URL: 'http://kong:8000', }); factory.setWorkerName('greet-user-worker'); const logger = factory.createLogger('test'); @@ -399,7 +399,7 @@ Deno.test('SimpleFormatter - taskCompleted outputs key=value format with worker/ try { const factory = createLoggingFactory({ - SUPABASE_ANON_KEY: 'some-production-key', + SUPABASE_URL: 'https://abc123.supabase.co', EDGE_WORKER_LOG_LEVEL: 'verbose', }); const logger = factory.createLogger('test'); @@ -439,7 +439,7 @@ Deno.test('SimpleFormatter - taskFailed outputs structured error with worker/que try { const factory = createLoggingFactory({ - SUPABASE_ANON_KEY: 'some-production-key', + SUPABASE_URL: 'https://abc123.supabase.co', EDGE_WORKER_LOG_LEVEL: 'verbose', }); const logger = factory.createLogger('test'); @@ -478,7 +478,7 @@ Deno.test('SimpleFormatter - no ANSI colors in output', () => { try { const factory = createLoggingFactory({ - SUPABASE_ANON_KEY: 'some-production-key', + SUPABASE_URL: 'https://abc123.supabase.co', EDGE_WORKER_LOG_LEVEL: 'verbose', }); const logger = factory.createLogger('test'); @@ -514,7 +514,7 @@ Deno.test('NO_COLOR disables colors in fancy mode', () => { try { const factory = createLoggingFactory({ - SUPABASE_ANON_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0', + SUPABASE_URL: 'http://kong:8000', NO_COLOR: '1', }); const logger = factory.createLogger('test'); @@ -553,7 +553,7 @@ Deno.test('FancyFormatter - taskCompleted at DEBUG level includes identifiers', try { const factory = createLoggingFactory({ - SUPABASE_ANON_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0', + SUPABASE_URL: 'http://kong:8000', EDGE_WORKER_LOG_LEVEL: 'debug', }); const logger = factory.createLogger('test'); @@ -587,7 +587,7 @@ Deno.test('FancyFormatter - taskFailed at DEBUG level includes identifiers', () try { const factory = createLoggingFactory({ - SUPABASE_ANON_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0', + SUPABASE_URL: 'http://kong:8000', EDGE_WORKER_LOG_LEVEL: 'debug', }); const logger = factory.createLogger('test'); @@ -626,7 +626,7 @@ Deno.test('FancyFormatter - taskFailed shows retry pending info when retries rem try { const factory = createLoggingFactory({ - SUPABASE_ANON_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0', + SUPABASE_URL: 'http://kong:8000', }); const logger = factory.createLogger('test'); @@ -663,7 +663,7 @@ Deno.test('FancyFormatter - taskFailed calculates exponential backoff delay corr try { const factory = createLoggingFactory({ - SUPABASE_ANON_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0', + SUPABASE_URL: 'http://kong:8000', }); const logger = factory.createLogger('test'); @@ -699,7 +699,7 @@ Deno.test('FancyFormatter - taskFailed does NOT show retry info when no retries try { const factory = createLoggingFactory({ - SUPABASE_ANON_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0', + SUPABASE_URL: 'http://kong:8000', }); const logger = factory.createLogger('test'); @@ -734,7 +734,7 @@ Deno.test('SimpleFormatter - taskFailed shows retry info in key=value format', ( try { const factory = createLoggingFactory({ - SUPABASE_ANON_KEY: 'some-production-key', + SUPABASE_URL: 'https://abc123.supabase.co', EDGE_WORKER_LOG_LEVEL: 'verbose', }); const logger = factory.createLogger('test'); @@ -771,7 +771,7 @@ Deno.test('SimpleFormatter - taskFailed does NOT show retry info when no retries try { const factory = createLoggingFactory({ - SUPABASE_ANON_KEY: 'some-production-key', + SUPABASE_URL: 'https://abc123.supabase.co', EDGE_WORKER_LOG_LEVEL: 'verbose', }); const logger = factory.createLogger('test'); diff --git a/pkgs/edge-worker/tests/unit/platform/logging.test.ts b/pkgs/edge-worker/tests/unit/platform/logging.test.ts index 470dcd796..a99daf273 100644 --- a/pkgs/edge-worker/tests/unit/platform/logging.test.ts +++ b/pkgs/edge-worker/tests/unit/platform/logging.test.ts @@ -162,7 +162,7 @@ Deno.test('createLoggingFactory - format defaults to simple when env not provide Deno.test('createLoggingFactory - format is fancy for local Supabase environment', () => { const localEnv = { - SUPABASE_ANON_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0', + SUPABASE_URL: 'http://kong:8000', }; const factory = createLoggingFactory(localEnv); @@ -171,7 +171,7 @@ Deno.test('createLoggingFactory - format is fancy for local Supabase environment Deno.test('createLoggingFactory - format is simple for hosted Supabase environment', () => { const hostedEnv = { - SUPABASE_ANON_KEY: 'some-production-key', + SUPABASE_URL: 'https://abc123.supabase.co', }; const factory = createLoggingFactory(hostedEnv); @@ -181,7 +181,7 @@ Deno.test('createLoggingFactory - format is simple for hosted Supabase environme Deno.test('createLoggingFactory - EDGE_WORKER_LOG_FORMAT overrides auto-detection', () => { // Even in local env, explicit format override should win const localEnv = { - SUPABASE_ANON_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0', + SUPABASE_URL: 'http://kong:8000', EDGE_WORKER_LOG_FORMAT: 'simple', }; const factory = createLoggingFactory(localEnv); @@ -191,7 +191,7 @@ Deno.test('createLoggingFactory - EDGE_WORKER_LOG_FORMAT overrides auto-detectio Deno.test('createLoggingFactory - EDGE_WORKER_LOG_FORMAT can set fancy in hosted env', () => { const hostedEnv = { - SUPABASE_ANON_KEY: 'some-production-key', + SUPABASE_URL: 'https://abc123.supabase.co', EDGE_WORKER_LOG_FORMAT: 'fancy', }; const factory = createLoggingFactory(hostedEnv); @@ -201,7 +201,7 @@ Deno.test('createLoggingFactory - EDGE_WORKER_LOG_FORMAT can set fancy in hosted Deno.test('createLoggingFactory - default log level is verbose for local env', () => { const localEnv = { - SUPABASE_ANON_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0', + SUPABASE_URL: 'http://kong:8000', }; const factory = createLoggingFactory(localEnv); @@ -210,7 +210,7 @@ Deno.test('createLoggingFactory - default log level is verbose for local env', ( Deno.test('createLoggingFactory - default log level is info for hosted env', () => { const hostedEnv = { - SUPABASE_ANON_KEY: 'some-production-key', + SUPABASE_URL: 'https://abc123.supabase.co', }; const factory = createLoggingFactory(hostedEnv); @@ -219,7 +219,7 @@ Deno.test('createLoggingFactory - default log level is info for hosted env', () Deno.test('createLoggingFactory - EDGE_WORKER_LOG_LEVEL overrides default', () => { const localEnv = { - SUPABASE_ANON_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0', + SUPABASE_URL: 'http://kong:8000', EDGE_WORKER_LOG_LEVEL: 'debug', }; const factory = createLoggingFactory(localEnv); diff --git a/pkgs/edge-worker/tests/unit/shared/authValidation.test.ts b/pkgs/edge-worker/tests/unit/shared/authValidation.test.ts index 86e2ce90a..cf7398871 100644 --- a/pkgs/edge-worker/tests/unit/shared/authValidation.test.ts +++ b/pkgs/edge-worker/tests/unit/shared/authValidation.test.ts @@ -4,10 +4,6 @@ import { createUnauthorizedResponse, createServerErrorResponse, } from '../../../src/shared/authValidation.ts'; -import { - KNOWN_LOCAL_ANON_KEY, - KNOWN_LOCAL_SERVICE_ROLE_KEY, -} from '../../../src/shared/localDetection.ts'; // ============================================================ // Helper functions @@ -23,14 +19,14 @@ function createRequest(authHeader?: string): Request { function localEnv(): Record { return { - SUPABASE_ANON_KEY: KNOWN_LOCAL_ANON_KEY, - SUPABASE_SERVICE_ROLE_KEY: KNOWN_LOCAL_SERVICE_ROLE_KEY, + SUPABASE_URL: 'http://kong:8000', // Local dev URL + SUPABASE_SERVICE_ROLE_KEY: 'any-key', // Not used for local detection anymore }; } function productionEnv(serviceRoleKey?: string): Record { return { - SUPABASE_ANON_KEY: 'production-anon-key-abc', + SUPABASE_URL: 'https://abc123.supabase.co', // Production URL SUPABASE_SERVICE_ROLE_KEY: serviceRoleKey, }; } @@ -53,8 +49,8 @@ Deno.test('validateServiceRoleAuth - local mode: allows request with wrong auth assertEquals(result, { valid: true }); }); -Deno.test('validateServiceRoleAuth - local mode: allows request with correct auth header', () => { - const request = createRequest(`Bearer ${KNOWN_LOCAL_SERVICE_ROLE_KEY}`); +Deno.test('validateServiceRoleAuth - local mode: allows request with any auth header', () => { + const request = createRequest('Bearer any-key'); const result = validateServiceRoleAuth(request, localEnv()); assertEquals(result, { valid: true }); }); diff --git a/pkgs/edge-worker/tests/unit/shared/localDetection.test.ts b/pkgs/edge-worker/tests/unit/shared/localDetection.test.ts index 0fa654593..d08009972 100644 --- a/pkgs/edge-worker/tests/unit/shared/localDetection.test.ts +++ b/pkgs/edge-worker/tests/unit/shared/localDetection.test.ts @@ -1,136 +1,66 @@ import { assertEquals } from '@std/assert'; -import { - isLocalSupabaseEnv, - KNOWN_LOCAL_ANON_KEY, - KNOWN_LOCAL_SERVICE_ROLE_KEY, - KNOWN_LOCAL_PUBLISHABLE_KEY, - KNOWN_LOCAL_SECRET_KEY, -} from '../../../src/shared/localDetection.ts'; +import { isLocalSupabaseEnv, LOCAL_SUPABASE_HOST } from '../../../src/shared/localDetection.ts'; // ============================================================ -// Constants tests +// LOCAL_SUPABASE_HOST constant // ============================================================ -Deno.test('KNOWN_LOCAL_ANON_KEY - matches expected value', () => { - assertEquals( - KNOWN_LOCAL_ANON_KEY, - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0' - ); +Deno.test('LOCAL_SUPABASE_HOST - matches expected value', () => { + assertEquals(LOCAL_SUPABASE_HOST, 'kong:8000'); }); -Deno.test('KNOWN_LOCAL_SERVICE_ROLE_KEY - matches expected value', () => { - assertEquals( - KNOWN_LOCAL_SERVICE_ROLE_KEY, - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU' - ); +// ============================================================ +// isLocalSupabaseEnv() - returns true for local dev +// ============================================================ + +Deno.test('isLocalSupabaseEnv - returns true for http://kong:8000', () => { + assertEquals(isLocalSupabaseEnv({ SUPABASE_URL: 'http://kong:8000' }), true); }); -Deno.test('KNOWN_LOCAL_PUBLISHABLE_KEY - matches expected value', () => { - assertEquals( - KNOWN_LOCAL_PUBLISHABLE_KEY, - 'sb_publishable_ACJWlzQHlZjBrEguHvfOxg_3BJgxAaH' - ); +Deno.test('isLocalSupabaseEnv - returns true for http://kong:8000/ (trailing slash)', () => { + assertEquals(isLocalSupabaseEnv({ SUPABASE_URL: 'http://kong:8000/' }), true); }); -Deno.test('KNOWN_LOCAL_SECRET_KEY - matches expected value', () => { - assertEquals( - KNOWN_LOCAL_SECRET_KEY, - 'sb_secret_N7UND0UgjKTVK-Uodkm0Hg_xSvEMPvz' - ); +Deno.test('isLocalSupabaseEnv - returns true for https://kong:8000 (different protocol)', () => { + assertEquals(isLocalSupabaseEnv({ SUPABASE_URL: 'https://kong:8000' }), true); }); // ============================================================ -// isLocalSupabaseEnv() tests +// isLocalSupabaseEnv() - returns false for non-local // ============================================================ -Deno.test('isLocalSupabaseEnv - returns true when anon key matches local', () => { - const env = { SUPABASE_ANON_KEY: KNOWN_LOCAL_ANON_KEY }; - assertEquals(isLocalSupabaseEnv(env), true); -}); - -Deno.test('isLocalSupabaseEnv - returns true when service role key matches local', () => { - const env = { SUPABASE_SERVICE_ROLE_KEY: KNOWN_LOCAL_SERVICE_ROLE_KEY }; - assertEquals(isLocalSupabaseEnv(env), true); +Deno.test('isLocalSupabaseEnv - returns false for different port', () => { + assertEquals(isLocalSupabaseEnv({ SUPABASE_URL: 'http://kong:9000' }), false); }); -Deno.test('isLocalSupabaseEnv - returns true when both keys match local', () => { - const env = { - SUPABASE_ANON_KEY: KNOWN_LOCAL_ANON_KEY, - SUPABASE_SERVICE_ROLE_KEY: KNOWN_LOCAL_SERVICE_ROLE_KEY, - }; - assertEquals(isLocalSupabaseEnv(env), true); +Deno.test('isLocalSupabaseEnv - returns true for uppercase KONG (URL normalizes to lowercase)', () => { + assertEquals(isLocalSupabaseEnv({ SUPABASE_URL: 'http://KONG:8000' }), true); }); -Deno.test('isLocalSupabaseEnv - returns false for non-local keys', () => { - const env = { - SUPABASE_ANON_KEY: 'prod-key', - SUPABASE_SERVICE_ROLE_KEY: 'prod-service-key', - }; - assertEquals(isLocalSupabaseEnv(env), false); -}); - -Deno.test('isLocalSupabaseEnv - returns false for empty env', () => { - assertEquals(isLocalSupabaseEnv({}), false); +Deno.test('isLocalSupabaseEnv - returns false for supabase.co URL', () => { + assertEquals(isLocalSupabaseEnv({ SUPABASE_URL: 'https://abc123.supabase.co' }), false); }); -Deno.test('isLocalSupabaseEnv - returns false for undefined values', () => { - const env = { - SUPABASE_ANON_KEY: undefined, - SUPABASE_SERVICE_ROLE_KEY: undefined, - }; - assertEquals(isLocalSupabaseEnv(env), false); +Deno.test('isLocalSupabaseEnv - returns false for custom domain', () => { + assertEquals(isLocalSupabaseEnv({ SUPABASE_URL: 'https://api.myapp.com' }), false); }); -Deno.test('isLocalSupabaseEnv - returns true when only anon key matches (service is prod)', () => { - const env = { - SUPABASE_ANON_KEY: KNOWN_LOCAL_ANON_KEY, - SUPABASE_SERVICE_ROLE_KEY: 'prod-service-key', - }; - assertEquals(isLocalSupabaseEnv(env), true); -}); - -Deno.test('isLocalSupabaseEnv - returns true when only service role matches (anon is prod)', () => { - const env = { - SUPABASE_ANON_KEY: 'prod-anon-key', - SUPABASE_SERVICE_ROLE_KEY: KNOWN_LOCAL_SERVICE_ROLE_KEY, - }; - assertEquals(isLocalSupabaseEnv(env), true); +Deno.test('isLocalSupabaseEnv - returns false for localhost', () => { + assertEquals(isLocalSupabaseEnv({ SUPABASE_URL: 'http://localhost:54321' }), false); }); // ============================================================ -// New opaque key tests (Supabase CLI v2+) +// isLocalSupabaseEnv() - edge cases // ============================================================ -Deno.test('isLocalSupabaseEnv - returns true when anon key matches new publishable key', () => { - const env = { SUPABASE_ANON_KEY: KNOWN_LOCAL_PUBLISHABLE_KEY }; - assertEquals(isLocalSupabaseEnv(env), true); -}); - -Deno.test('isLocalSupabaseEnv - returns true when service role matches new secret key', () => { - const env = { SUPABASE_SERVICE_ROLE_KEY: KNOWN_LOCAL_SECRET_KEY }; - assertEquals(isLocalSupabaseEnv(env), true); -}); - -Deno.test('isLocalSupabaseEnv - returns true when both new opaque keys match', () => { - const env = { - SUPABASE_ANON_KEY: KNOWN_LOCAL_PUBLISHABLE_KEY, - SUPABASE_SERVICE_ROLE_KEY: KNOWN_LOCAL_SECRET_KEY, - }; - assertEquals(isLocalSupabaseEnv(env), true); +Deno.test('isLocalSupabaseEnv - returns false for empty env', () => { + assertEquals(isLocalSupabaseEnv({}), false); }); -Deno.test('isLocalSupabaseEnv - returns true when mixing old JWT anon with new secret key', () => { - const env = { - SUPABASE_ANON_KEY: KNOWN_LOCAL_ANON_KEY, - SUPABASE_SERVICE_ROLE_KEY: KNOWN_LOCAL_SECRET_KEY, - }; - assertEquals(isLocalSupabaseEnv(env), true); +Deno.test('isLocalSupabaseEnv - returns false for invalid URL', () => { + assertEquals(isLocalSupabaseEnv({ SUPABASE_URL: 'not-a-url' }), false); }); -Deno.test('isLocalSupabaseEnv - returns true when mixing new publishable with old JWT service role', () => { - const env = { - SUPABASE_ANON_KEY: KNOWN_LOCAL_PUBLISHABLE_KEY, - SUPABASE_SERVICE_ROLE_KEY: KNOWN_LOCAL_SERVICE_ROLE_KEY, - }; - assertEquals(isLocalSupabaseEnv(env), true); +Deno.test('isLocalSupabaseEnv - returns false for undefined SUPABASE_URL', () => { + assertEquals(isLocalSupabaseEnv({ SUPABASE_URL: undefined }), false); }); diff --git a/pkgs/website/src/content/docs/news/pgflow-0-10-0-auto-compilation-and-worker-management.mdx b/pkgs/website/src/content/docs/news/pgflow-0-10-0-auto-compilation-and-worker-management.mdx index 0820fdfb6..f05ee0a7c 100644 --- a/pkgs/website/src/content/docs/news/pgflow-0-10-0-auto-compilation-and-worker-management.mdx +++ b/pkgs/website/src/content/docs/news/pgflow-0-10-0-auto-compilation-and-worker-management.mdx @@ -10,7 +10,7 @@ tags: - auto-compilation - worker-management - developer-experience -featured: false +featured: true --- import { Aside } from "@astrojs/starlight/components"; diff --git a/pkgs/website/src/content/docs/news/pgflow-0-13-0-cli-fix-step-output-storage-for-conditional-execution.mdx b/pkgs/website/src/content/docs/news/pgflow-0-13-1-cli-fix-step-output-storage-for-conditional-execution.mdx similarity index 83% rename from pkgs/website/src/content/docs/news/pgflow-0-13-0-cli-fix-step-output-storage-for-conditional-execution.mdx rename to pkgs/website/src/content/docs/news/pgflow-0-13-1-cli-fix-step-output-storage-for-conditional-execution.mdx index 711de7a04..7a2575c0b 100644 --- a/pkgs/website/src/content/docs/news/pgflow-0-13-0-cli-fix-step-output-storage-for-conditional-execution.mdx +++ b/pkgs/website/src/content/docs/news/pgflow-0-13-1-cli-fix-step-output-storage-for-conditional-execution.mdx @@ -1,6 +1,6 @@ --- -draft: true -title: 'pgflow 0.13.0: CLI Fix + Step Output Storage for Conditional Execution' +draft: false +title: 'pgflow 0.13.1: CLI Fix + Step Output Storage for Conditional Execution' description: 'Fixes local development with recent Supabase CLI versions, plus 2x faster Map chains' date: 2026-01-03 authors: @@ -13,13 +13,17 @@ featured: true import { Aside, Steps } from "@astrojs/starlight/components"; -pgflow 0.13.0 fixes a compatibility issue with recent Supabase CLI versions and introduces atomic step output storage for 2x faster Map chains. + + +pgflow 0.13.1 fixes a compatibility issue with recent Supabase CLI versions and introduces atomic step output storage for 2x faster Map chains. ## Supabase CLI Compatibility Fix **If local development stopped working after a Supabase CLI update, this release fixes it.** -Recent versions of the Supabase CLI transitioned to new publishable/secret API keys instead of the previous JWT-based keys. pgflow now detects both key formats, ensuring local environment detection works correctly regardless of which CLI version you use. +pgflow now detects local development by checking the `SUPABASE_URL` environment variable. When running locally, Supabase CLI sets this to `http://kong:8000` (the Docker-internal API gateway). This is more reliable than the previous key-based detection, which broke when Supabase CLI transitioned to new opaque API keys. ## Step Output Storage