-
Notifications
You must be signed in to change notification settings - Fork 6
CLI local dev functions #249
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c910d1d
4a3d1f2
76eea43
44e36e6
4cabed5
b88c3d1
fd91937
e1ba899
ae42b91
39bc74c
7dce917
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| { | ||
| "$schema": "https://biomejs.dev/schemas/2.3.13/schema.json", | ||
| "$schema": "https://biomejs.dev/schemas/2.3.14/schema.json", | ||
| "assist": { | ||
| "actions": { | ||
| "source": { | ||
|
|
@@ -13,7 +13,7 @@ | |
| } | ||
| }, | ||
| "files": { | ||
| "includes": ["**", "!**/dist/**", "!**/node_modules/**", "!**/tests/fixtures/**", "!**/*.d.ts"] | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no related to PR, but the correct syntaxis is not to mention |
||
| "includes": ["**", "!**/dist", "!**/node_modules", "!**/tests/fixtures", "!**/*.d.ts"] | ||
| }, | ||
| "formatter": { | ||
| "enabled": true, | ||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| # Deno Runtime | ||
|
|
||
| This folder contains code that runs in **Deno**, not Node.js. | ||
|
|
||
| ## Why separate? | ||
|
|
||
| The CLI itself is a Node.js application, but backend functions are executed in Deno. This folder provides a local Deno server for development that mimics the production function runtime. | ||
|
|
||
| ## TypeScript Configuration | ||
|
|
||
| This folder has its own `tsconfig.json` with Deno types (`@types/deno`) instead of Node types. This prevents type conflicts between the two runtimes. | ||
|
|
||
| ## Usage | ||
|
|
||
| This server is started automatically by `base44 dev` to handle local function deployments. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| /** | ||
| * 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 | ||
| // @ts-expect-error - We're intentionally overriding Deno.serve | ||
| Deno.serve = ( | ||
| optionsOrHandler: | ||
| | Deno.ServeOptions | ||
| | Deno.ServeHandler | ||
| | (Deno.ServeOptions & { handler: Deno.ServeHandler }), | ||
| maybeHandler?: Deno.ServeHandler, | ||
| ): Deno.HttpServer<Deno.NetAddr> => { | ||
| 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 }); | ||
| }; | ||
|
|
||
| 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); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| { | ||
| "extends": "../tsconfig.base.json", | ||
| "compilerOptions": { | ||
| "lib": ["ES2022", "DOM"], | ||
| "moduleResolution": "bundler", | ||
| "allowImportingTsExtensions": true, | ||
| "typeRoots": ["../node_modules/@types"], | ||
| "types": ["deno"] | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Deno types are different from Node and in order to handle it without collision between types I need separate |
||
| }, | ||
| "include": ["./**/*"] | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| import { theme } from "@/cli/utils/theme"; | ||
|
|
||
| type LogType = "log" | "error" | "warn"; | ||
|
|
||
| export interface Logger { | ||
| log: (msg: string) => void; | ||
| error: (msg: string, err?: unknown) => void; | ||
| warn: (msg: string) => void; | ||
| } | ||
|
|
||
| const colorByType: Record<LogType, (text: string) => string> = { | ||
| error: theme.styles.error, | ||
| warn: theme.styles.warn, | ||
| log: (text: string) => text, | ||
| }; | ||
|
|
||
| export function createDevLogger(): Logger { | ||
| const print = (type: LogType, msg: string) => { | ||
| const colorize = colorByType[type]; | ||
| console[type](colorize(msg)); | ||
| }; | ||
|
|
||
| return { | ||
| log: (msg: string) => print("log", msg), | ||
| error: (msg: string, err?: unknown) => { | ||
| print("error", msg); | ||
| if (err) { | ||
| print("error", String(err)); | ||
| } | ||
| }, | ||
| warn: (msg: string) => print("warn", msg), | ||
| }; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no related to PR, but now schema is aligned to our version