/** * Deno Function Wrapper * * This script is executed by Deno to run user functions. * It patches Deno.serve to inject a dynamic port before importing the user's function. * * Environment variables: * - FUNCTION_PATH: Absolute path to the user's function entry file * - FUNCTION_PORT: Port number for the function to listen on * - FUNCTION_NAME: Name of the function (for logging) */ // Make this file a module for top-level await support export {}; const functionPath = Deno.env.get("FUNCTION_PATH"); const port = parseInt(Deno.env.get("FUNCTION_PORT") || "8000", 10); const functionName = Deno.env.get("FUNCTION_NAME") || "unknown"; if (!functionPath) { console.error("[wrapper] FUNCTION_PATH environment variable is required"); Deno.exit(1); } // Store the original Deno.serve const originalServe = Deno.serve.bind(Deno); // Patch Deno.serve to inject our port and add onListen callback. const patchedServe = ( optionsOrHandler: | Deno.ServeOptions | Deno.ServeHandler | (Deno.ServeOptions & { handler: Deno.ServeHandler }), maybeHandler?: Deno.ServeHandler, ): Deno.HttpServer => { const onListen = () => { // This message is used by FunctionManager to detect when the function is ready console.log(`[${functionName}] Listening on http://localhost:${port}`); }; // Handle the different Deno.serve signatures: // 1. Deno.serve(handler) // 2. Deno.serve(options, handler) // 3. Deno.serve({ ...options, handler }) if (typeof optionsOrHandler === "function") { // Signature: Deno.serve(handler) return originalServe({ port, onListen }, optionsOrHandler); } if (maybeHandler) { // Signature: Deno.serve(options, handler) return originalServe({ ...optionsOrHandler, port, onListen }, maybeHandler); } // Signature: Deno.serve({ ...options, handler }) const options = optionsOrHandler as Deno.ServeOptions & { handler: Deno.ServeHandler; }; return originalServe({ ...options, port, onListen }); }; // Deno 2.8 exposes `Deno.serve` as a getter-only property, so a plain // `Deno.serve = ...` assignment throws. Use defineProperty to override it // (works on both the old writable property and the new accessor). Object.defineProperty(Deno, "serve", { value: patchedServe, writable: true, configurable: true, }); console.log(`[${functionName}] Starting function from ${functionPath}`); // Dynamically import the user's function // The function will call Deno.serve which is now patched to use our port try { await import(functionPath); } catch (error) { console.error(`[${functionName}] Failed to load function:`, error); Deno.exit(1); }