diff --git a/apps/cli/src/next/commands/functions/new/new.handler.ts b/apps/cli/src/next/commands/functions/new/new.handler.ts index c5c2c1f09c..39076f6f6a 100644 --- a/apps/cli/src/next/commands/functions/new/new.handler.ts +++ b/apps/cli/src/next/commands/functions/new/new.handler.ts @@ -1,7 +1,7 @@ import { dirname } from "node:path"; import { - edgeFunctionDenoConfigFileName, edgeFunctionEntrypointFileName, + edgeFunctionPackageManifestFileName, edgeFunctionsDirectoryName, findProjectPaths, } from "@supabase/config"; @@ -16,20 +16,24 @@ import { const functionSlugPattern = /^[A-Za-z0-9_-]+$/; -const denoJson = `${JSON.stringify( +const packageJson = `${JSON.stringify( { - imports: { - "@supabase/functions-js": "jsr:@supabase/functions-js@^2", - }, + private: true, + type: "module", + dependencies: {}, }, null, 2, )}\n`; -const entrypointSource = `Deno.serve(async (req) => { - const { name } = await req.json(); - return Response.json({ message: \`Hello \${name}!\` }); -}); +const entrypointSource = `export default { + async fetch(request: Request): Promise { + const name = new URL(request.url).searchParams.get("name") ?? "World"; + return new Response(\`Hello \${name}!\`, { + headers: { "content-type": "text/plain" }, + }); + }, +}; `; function validateSlugMessage(slug: string): string | undefined { @@ -91,7 +95,7 @@ export const functionsNew = Effect.fnUntraced(function* (slugInput: Option.Optio projectPaths === null ? runtimeInfo.cwd : projectRootForConfigPath(projectPaths.configPath); const functionDir = path.join(projectRoot, "supabase", edgeFunctionsDirectoryName, slug); const entrypointPath = path.join(functionDir, edgeFunctionEntrypointFileName); - const denoConfigPath = path.join(functionDir, edgeFunctionDenoConfigFileName); + const packageManifestPath = path.join(functionDir, edgeFunctionPackageManifestFileName); if (yield* fs.exists(entrypointPath)) { return yield* Effect.fail( @@ -104,15 +108,15 @@ export const functionsNew = Effect.fnUntraced(function* (slugInput: Option.Optio yield* fs.makeDirectory(functionDir, { recursive: true }); yield* fs.writeFileString(entrypointPath, entrypointSource); - if (!(yield* fs.exists(denoConfigPath))) { - yield* fs.writeFileString(denoConfigPath, denoJson); + if (!(yield* fs.exists(packageManifestPath))) { + yield* fs.writeFileString(packageManifestPath, packageJson); } yield* output.success("Created Edge Function.", { function_slug: slug, function_dir: functionDir, entrypoint_path: entrypointPath, - deno_config_path: denoConfigPath, + package_manifest_path: packageManifestPath, }); yield* output.outro(`Created ${path.join("supabase", edgeFunctionsDirectoryName, slug)}.`); }); diff --git a/apps/cli/src/next/commands/functions/new/new.integration.test.ts b/apps/cli/src/next/commands/functions/new/new.integration.test.ts index 7396813785..19fb448f7a 100644 --- a/apps/cli/src/next/commands/functions/new/new.integration.test.ts +++ b/apps/cli/src/next/commands/functions/new/new.integration.test.ts @@ -98,22 +98,29 @@ describe("functions new", () => { yield* Effect.tryPromise(() => readFile(join(tempDir, "supabase", "functions", "hello-world", "index.ts"), "utf8"), ), - ).toBe(`Deno.serve(async (req) => { - const { name } = await req.json(); - return Response.json({ message: \`Hello \${name}!\` }); -}); + ).toBe(`export default { + async fetch(request: Request): Promise { + const name = new URL(request.url).searchParams.get("name") ?? "World"; + return new Response(\`Hello \${name}!\`, { + headers: { "content-type": "text/plain" }, + }); + }, +}; `); expect( JSON.parse( yield* Effect.tryPromise(() => - readFile(join(tempDir, "supabase", "functions", "hello-world", "deno.json"), "utf8"), + readFile(join(tempDir, "supabase", "functions", "hello-world", "package.json"), "utf8"), ), ), ).toEqual({ - imports: { - "@supabase/functions-js": "jsr:@supabase/functions-js@^2", - }, + private: true, + type: "module", + dependencies: {}, }); + expect(existsSync(join(tempDir, "supabase", "functions", "hello-world", "deno.json"))).toBe( + false, + ); expect(out.messages).toContainEqual( expect.objectContaining({ type: "success", message: "Created Edge Function." }), ); @@ -151,7 +158,7 @@ describe("functions new", () => { yield* Effect.tryPromise(() => readFile(join(tempDir, "supabase", "functions", "hello-world", "index.ts"), "utf8"), ), - ).toContain("Deno.serve"); + ).toContain("export default"); }).pipe( Effect.ensuring(Effect.tryPromise(() => rm(tempDir, { recursive: true, force: true }))), ); @@ -175,7 +182,7 @@ describe("functions new", () => { yield* Effect.tryPromise(() => readFile(join(tempDir, "supabase", "functions", "hello-world", "index.ts"), "utf8"), ), - ).toContain("Deno.serve"); + ).toContain("export default"); }).pipe( Effect.ensuring(Effect.tryPromise(() => rm(tempDir, { recursive: true, force: true }))), ); @@ -239,7 +246,7 @@ describe("functions new", () => { yield* Effect.tryPromise(() => readFile(join(tempDir, "supabase", "functions", "hello-world", "index.ts"), "utf8"), ), - ).toContain("Deno.serve"); + ).toContain("export default"); }).pipe( Effect.ensuring(Effect.tryPromise(() => rm(tempDir, { recursive: true, force: true }))), ); diff --git a/packages/config/src/functions-manifest.ts b/packages/config/src/functions-manifest.ts index 63322169fa..576d5ba9d6 100644 --- a/packages/config/src/functions-manifest.ts +++ b/packages/config/src/functions-manifest.ts @@ -10,6 +10,7 @@ const emptyConfig = decodeProjectConfig({}); export const edgeFunctionsDirectoryName = "functions"; export const edgeFunctionEntrypointFileName = "index.ts"; export const edgeFunctionDenoConfigFileName = "deno.json"; +export const edgeFunctionPackageManifestFileName = "package.json"; export interface ResolvedFunctionConfig { readonly enabled: boolean; diff --git a/packages/config/src/index.ts b/packages/config/src/index.ts index 77af2064ae..9124f702bc 100644 --- a/packages/config/src/index.ts +++ b/packages/config/src/index.ts @@ -22,6 +22,7 @@ export { export { edgeFunctionDenoConfigFileName, edgeFunctionEntrypointFileName, + edgeFunctionPackageManifestFileName, edgeFunctionsDirectoryName, type FunctionsManifest, type ResolvedFunctionConfig,