From 951c592e56e6ab61c356fd62d95aa8c946831afa Mon Sep 17 00:00:00 2001 From: 7ttp <117663341+7ttp@users.noreply.github.com> Date: Thu, 13 Aug 2026 00:17:01 +0530 Subject: [PATCH 1/3] fix(cli): restore serve argument --- apps/cli/docs/go-cli-porting-status.md | 2 +- .../commands/functions/serve/SIDE_EFFECTS.md | 3 ++ .../serve/serve.command.integration.test.ts | 30 +++++++++++++++++++ .../commands/functions/serve/serve.command.ts | 12 ++++++-- 4 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 apps/cli/src/legacy/commands/functions/serve/serve.command.integration.test.ts diff --git a/apps/cli/docs/go-cli-porting-status.md b/apps/cli/docs/go-cli-porting-status.md index ce27ec807d..2dd89741cc 100644 --- a/apps/cli/docs/go-cli-porting-status.md +++ b/apps/cli/docs/go-cli-porting-status.md @@ -308,7 +308,7 @@ Legend: | `functions download` | `ported` | [`../src/legacy/commands/functions/download/download.command.ts`](../src/legacy/commands/functions/download/download.command.ts) — native for `--use-api` (lists, downloads, and extracts via the Management API directly) and the default Docker-unbundle path (`--use-docker`, CLI-1963); hidden `--legacy-bundle` still delegates to the Go binary (pre-1.120.0 fallback requiring a host Deno-binary install with no precedent elsewhere in this codebase — tracked separately, see CLI-1963) | | `functions deploy` | `ported` | [`../src/legacy/commands/functions/deploy/deploy.command.ts`](../src/legacy/commands/functions/deploy/deploy.command.ts) — Intentional divergence (CLI-2179, ruled 2026-08-12; PR #6164): the functions import scanner (`walkImportPaths`/`substituteImportMapValue`, shared with `functions serve` and `start`'s Edge Runtime bring-up) matches import-map keys per the import-maps spec that Deno/edge-runtime implement — a key matches exactly, or as a prefix only when it ends with `/`, and a `/`-suffixed key normalizes away entirely when its value does not also end in `/` — diverging from Go's any-key `strings.HasPrefix` (`pkg/function/deno.go:150-155`). Because the runtime is itself spec-compliant, Go's lax matching only ever fabricated paths the runtime could never resolve, producing the ENOTDIR crash family and mounting/uploading files no import can reach. Deploy upload sets and serve/start bind mounts may shrink for maps that relied on bare-key prefix matching; no runtime-resolvable import is affected. | | `functions new` | `ported` | [`../src/legacy/commands/functions/new/new.command.ts`](../src/legacy/commands/functions/new/new.command.ts) | -| `functions serve` | `ported` | [`../src/legacy/commands/functions/serve/serve.command.ts`](../src/legacy/commands/functions/serve/serve.command.ts) — Intentional divergence (CLI-2179, ruled 2026-08-12; PR #6164): shares the spec-strict import-map key matching described in the `functions deploy` row (`walkImportPaths`/`substituteImportMapValue`); bind mounts may shrink for maps that relied on Go's bare-key `strings.HasPrefix` matching (`pkg/function/deno.go:150-155`), but no runtime-resolvable import is affected. | +| `functions serve` | `ported` | [`../src/legacy/commands/functions/serve/serve.command.ts`](../src/legacy/commands/functions/serve/serve.command.ts) — Accepts and ignores one legacy Function name positional argument, preserving `functions serve ` compatibility while serving all Functions like the current Go command. Intentional divergence (CLI-2179, ruled 2026-08-12; PR #6164): shares the spec-strict import-map key matching described in the `functions deploy` row (`walkImportPaths`/`substituteImportMapValue`); bind mounts may shrink for maps that relied on Go's bare-key `strings.HasPrefix` matching (`pkg/function/deno.go:150-155`), but no runtime-resolvable import is affected. | | `storage ls` | `ported` | [`../src/legacy/commands/storage/ls/ls.command.ts`](../src/legacy/commands/storage/ls/ls.command.ts) | | `storage cp` | `ported` | [`../src/legacy/commands/storage/cp/cp.command.ts`](../src/legacy/commands/storage/cp/cp.command.ts) | | `storage mv` | `ported` | [`../src/legacy/commands/storage/mv/mv.command.ts`](../src/legacy/commands/storage/mv/mv.command.ts) | diff --git a/apps/cli/src/legacy/commands/functions/serve/SIDE_EFFECTS.md b/apps/cli/src/legacy/commands/functions/serve/SIDE_EFFECTS.md index fd1aac8776..213714fe9d 100644 --- a/apps/cli/src/legacy/commands/functions/serve/SIDE_EFFECTS.md +++ b/apps/cli/src/legacy/commands/functions/serve/SIDE_EFFECTS.md @@ -94,6 +94,9 @@ Long-running raw log / error events only; there is no terminal `result` event on ## Notes +- One optional legacy Function name positional argument is accepted and ignored. The command + always serves every discovered Function, matching the current Go behavior while preserving the + previously supported `supabase functions serve ` invocation. - The hidden `--all` flag is still parsed but ignored; the native port always serves every discovered function, matching the Go command. - Each restart re-reads config, rebuilds per-function bind mounts, recreates the `supabase_edge_runtime_` container, and best-effort reloads Kong afterwards. - The command creates or reuses Docker resources derived from the resolved project id: diff --git a/apps/cli/src/legacy/commands/functions/serve/serve.command.integration.test.ts b/apps/cli/src/legacy/commands/functions/serve/serve.command.integration.test.ts new file mode 100644 index 0000000000..8364ff3d1e --- /dev/null +++ b/apps/cli/src/legacy/commands/functions/serve/serve.command.integration.test.ts @@ -0,0 +1,30 @@ +import { describe, expect, it } from "@effect/vitest"; +import { BunServices } from "@effect/platform-bun"; +import { Effect, Exit, Layer } from "effect"; +import { CliOutput, Command } from "effect/unstable/cli"; +import { textCliOutputFormatter } from "../../../../shared/output/text-formatter.ts"; +import { legacyFunctionsServeCommand } from "./serve.command.ts"; + +describe("legacy functions serve command", () => { + it.live("accepts the legacy function name positional argument", () => { + let handlerRan = false; + const command = legacyFunctionsServeCommand.pipe( + Command.withHandler(() => + Effect.sync(() => { + handlerRan = true; + }), + ), + ); + + return Effect.gen(function* () { + const exit = yield* Command.runWith(command, { + version: "0.0.0-test", + })(["hello-world"]).pipe(Effect.exit); + + expect(Exit.isSuccess(exit)).toBe(true); + expect(handlerRan).toBe(true); + }).pipe( + Effect.provide(Layer.mergeAll(BunServices.layer, CliOutput.layer(textCliOutputFormatter()))), + ); + }); +}); diff --git a/apps/cli/src/legacy/commands/functions/serve/serve.command.ts b/apps/cli/src/legacy/commands/functions/serve/serve.command.ts index 83992053b6..daddbdfd30 100644 --- a/apps/cli/src/legacy/commands/functions/serve/serve.command.ts +++ b/apps/cli/src/legacy/commands/functions/serve/serve.command.ts @@ -1,5 +1,5 @@ import { Layer } from "effect"; -import { Command, Flag } from "effect/unstable/cli"; +import { Argument, Command, Flag } from "effect/unstable/cli"; import { withJsonErrorHandling } from "../../../../shared/output/json-error-handling.ts"; import { commandRuntimeLayer } from "../../../../shared/runtime/command-runtime.layer.ts"; import { @@ -49,7 +49,15 @@ const config = { ), } as const; -export const legacyFunctionsServeCommand = Command.make("serve", config).pipe( +const commandConfig = { + ...config, + legacyFunctionName: Argument.string("Function name").pipe( + Argument.withDescription("Legacy Function name. All Functions are served."), + Argument.optional, + ), +} as const; + +export const legacyFunctionsServeCommand = Command.make("serve", commandConfig).pipe( Command.withDescription("Serve all Functions locally."), Command.withShortDescription("Serve all Functions locally"), Command.withHandler((flags) => From 87e6b563379187d95cb72b9272d2a7e37f1eee3a Mon Sep 17 00:00:00 2001 From: 7ttp <117663341+7ttp@users.noreply.github.com> Date: Thu, 13 Aug 2026 01:24:11 +0530 Subject: [PATCH 2/3] rerun From 9c52ce4b30ccb589a596237da42498b6ac8faa22 Mon Sep 17 00:00:00 2001 From: 7ttp <117663341+7ttp@users.noreply.github.com> Date: Thu, 13 Aug 2026 01:32:47 +0530 Subject: [PATCH 3/3] fix(cli): preserve serve operands --- apps/cli/docs/go-cli-porting-status.md | 2 +- .../src/legacy/commands/functions/serve/SIDE_EFFECTS.md | 6 +++--- .../functions/serve/serve.command.integration.test.ts | 9 ++++++--- .../src/legacy/commands/functions/serve/serve.command.ts | 6 +++--- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/apps/cli/docs/go-cli-porting-status.md b/apps/cli/docs/go-cli-porting-status.md index 2dd89741cc..84db7a7f55 100644 --- a/apps/cli/docs/go-cli-porting-status.md +++ b/apps/cli/docs/go-cli-porting-status.md @@ -308,7 +308,7 @@ Legend: | `functions download` | `ported` | [`../src/legacy/commands/functions/download/download.command.ts`](../src/legacy/commands/functions/download/download.command.ts) — native for `--use-api` (lists, downloads, and extracts via the Management API directly) and the default Docker-unbundle path (`--use-docker`, CLI-1963); hidden `--legacy-bundle` still delegates to the Go binary (pre-1.120.0 fallback requiring a host Deno-binary install with no precedent elsewhere in this codebase — tracked separately, see CLI-1963) | | `functions deploy` | `ported` | [`../src/legacy/commands/functions/deploy/deploy.command.ts`](../src/legacy/commands/functions/deploy/deploy.command.ts) — Intentional divergence (CLI-2179, ruled 2026-08-12; PR #6164): the functions import scanner (`walkImportPaths`/`substituteImportMapValue`, shared with `functions serve` and `start`'s Edge Runtime bring-up) matches import-map keys per the import-maps spec that Deno/edge-runtime implement — a key matches exactly, or as a prefix only when it ends with `/`, and a `/`-suffixed key normalizes away entirely when its value does not also end in `/` — diverging from Go's any-key `strings.HasPrefix` (`pkg/function/deno.go:150-155`). Because the runtime is itself spec-compliant, Go's lax matching only ever fabricated paths the runtime could never resolve, producing the ENOTDIR crash family and mounting/uploading files no import can reach. Deploy upload sets and serve/start bind mounts may shrink for maps that relied on bare-key prefix matching; no runtime-resolvable import is affected. | | `functions new` | `ported` | [`../src/legacy/commands/functions/new/new.command.ts`](../src/legacy/commands/functions/new/new.command.ts) | -| `functions serve` | `ported` | [`../src/legacy/commands/functions/serve/serve.command.ts`](../src/legacy/commands/functions/serve/serve.command.ts) — Accepts and ignores one legacy Function name positional argument, preserving `functions serve ` compatibility while serving all Functions like the current Go command. Intentional divergence (CLI-2179, ruled 2026-08-12; PR #6164): shares the spec-strict import-map key matching described in the `functions deploy` row (`walkImportPaths`/`substituteImportMapValue`); bind mounts may shrink for maps that relied on Go's bare-key `strings.HasPrefix` matching (`pkg/function/deno.go:150-155`), but no runtime-resolvable import is affected. | +| `functions serve` | `ported` | [`../src/legacy/commands/functions/serve/serve.command.ts`](../src/legacy/commands/functions/serve/serve.command.ts) — Accepts and ignores any legacy Function name positional arguments, preserving parser compatibility while serving all Functions like the current Go command. Intentional divergence (CLI-2179, ruled 2026-08-12; PR #6164): shares the spec-strict import-map key matching described in the `functions deploy` row (`walkImportPaths`/`substituteImportMapValue`); bind mounts may shrink for maps that relied on Go's bare-key `strings.HasPrefix` matching (`pkg/function/deno.go:150-155`), but no runtime-resolvable import is affected. | | `storage ls` | `ported` | [`../src/legacy/commands/storage/ls/ls.command.ts`](../src/legacy/commands/storage/ls/ls.command.ts) | | `storage cp` | `ported` | [`../src/legacy/commands/storage/cp/cp.command.ts`](../src/legacy/commands/storage/cp/cp.command.ts) | | `storage mv` | `ported` | [`../src/legacy/commands/storage/mv/mv.command.ts`](../src/legacy/commands/storage/mv/mv.command.ts) | diff --git a/apps/cli/src/legacy/commands/functions/serve/SIDE_EFFECTS.md b/apps/cli/src/legacy/commands/functions/serve/SIDE_EFFECTS.md index 213714fe9d..460aa1fdd6 100644 --- a/apps/cli/src/legacy/commands/functions/serve/SIDE_EFFECTS.md +++ b/apps/cli/src/legacy/commands/functions/serve/SIDE_EFFECTS.md @@ -94,9 +94,9 @@ Long-running raw log / error events only; there is no terminal `result` event on ## Notes -- One optional legacy Function name positional argument is accepted and ignored. The command - always serves every discovered Function, matching the current Go behavior while preserving the - previously supported `supabase functions serve ` invocation. +- Any legacy Function name positional arguments are accepted and ignored. The command always + serves every discovered Function, matching the current Go behavior while preserving invocations + such as `supabase functions serve `. - The hidden `--all` flag is still parsed but ignored; the native port always serves every discovered function, matching the Go command. - Each restart re-reads config, rebuilds per-function bind mounts, recreates the `supabase_edge_runtime_` container, and best-effort reloads Kong afterwards. - The command creates or reuses Docker resources derived from the resolved project id: diff --git a/apps/cli/src/legacy/commands/functions/serve/serve.command.integration.test.ts b/apps/cli/src/legacy/commands/functions/serve/serve.command.integration.test.ts index 8364ff3d1e..c2ef452ec3 100644 --- a/apps/cli/src/legacy/commands/functions/serve/serve.command.integration.test.ts +++ b/apps/cli/src/legacy/commands/functions/serve/serve.command.integration.test.ts @@ -6,12 +6,14 @@ import { textCliOutputFormatter } from "../../../../shared/output/text-formatter import { legacyFunctionsServeCommand } from "./serve.command.ts"; describe("legacy functions serve command", () => { - it.live("accepts the legacy function name positional argument", () => { + it.live("accepts all legacy function name positional arguments", () => { let handlerRan = false; + let parsedFunctionNames: ReadonlyArray = []; const command = legacyFunctionsServeCommand.pipe( - Command.withHandler(() => + Command.withHandler(({ legacyFunctionNames }) => Effect.sync(() => { handlerRan = true; + parsedFunctionNames = legacyFunctionNames; }), ), ); @@ -19,10 +21,11 @@ describe("legacy functions serve command", () => { return Effect.gen(function* () { const exit = yield* Command.runWith(command, { version: "0.0.0-test", - })(["hello-world"]).pipe(Effect.exit); + })(["hello-world", "send-email"]).pipe(Effect.exit); expect(Exit.isSuccess(exit)).toBe(true); expect(handlerRan).toBe(true); + expect(parsedFunctionNames).toEqual(["hello-world", "send-email"]); }).pipe( Effect.provide(Layer.mergeAll(BunServices.layer, CliOutput.layer(textCliOutputFormatter()))), ); diff --git a/apps/cli/src/legacy/commands/functions/serve/serve.command.ts b/apps/cli/src/legacy/commands/functions/serve/serve.command.ts index daddbdfd30..bc269fc45a 100644 --- a/apps/cli/src/legacy/commands/functions/serve/serve.command.ts +++ b/apps/cli/src/legacy/commands/functions/serve/serve.command.ts @@ -51,9 +51,9 @@ const config = { const commandConfig = { ...config, - legacyFunctionName: Argument.string("Function name").pipe( - Argument.withDescription("Legacy Function name. All Functions are served."), - Argument.optional, + legacyFunctionNames: Argument.string("Function name").pipe( + Argument.withDescription("Legacy Function names. All Functions are served."), + Argument.variadic(), ), } as const;