create-daloy 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,7 +13,7 @@ bun create daloy my-api
13
13
  The CLI is interactive when arguments are missing. It will ask you for:
14
14
 
15
15
  - A project directory name (defaults to `my-daloy-app`)
16
- - A template (`node-basic` or `cloudflare-worker`)
16
+ - A template (`node-basic`, `vercel-edge`, or `cloudflare-worker`)
17
17
  - Whether to install dependencies
18
18
  - Whether to initialize a git repository
19
19
 
@@ -31,7 +31,7 @@ pnpm create daloy@latest my-api \
31
31
 
32
32
  | Flag | Description |
33
33
  | --- | --- |
34
- | `--template <name>` | `node-basic` (default) or `cloudflare-worker`. |
34
+ | `--template <name>` | `node-basic` (default), `vercel-edge`, or `cloudflare-worker`. |
35
35
  | `--package-manager <pm>` | `pnpm` (default), `npm`, `yarn`, or `bun`. |
36
36
  | `--install` / `--no-install` | Install dependencies after scaffolding. Defaults to interactive. |
37
37
  | `--git` / `--no-git` | Initialize a git repository. Defaults to interactive. |
@@ -60,6 +60,15 @@ A minimal Cloudflare Worker bootstrap using `@daloyjs/core/cloudflare` with:
60
60
  - Zod-validated route exposed as `fetch`.
61
61
  - A sample test that exercises `app.request(...)`.
62
62
 
63
+ ### `vercel-edge`
64
+
65
+ A Vercel Edge API bootstrap using `@daloyjs/core/vercel` with:
66
+
67
+ - `api/[...path].ts` catch-all routing so DaloyJS owns the API surface.
68
+ - `export const config = { runtime: "edge" }` ready for Vercel Edge.
69
+ - `vercel dev` / `vercel deploy` scripts.
70
+ - A health route and bookstore route mirroring the Node starter.
71
+
63
72
  ## What the CLI guarantees
64
73
 
65
74
  - Zero runtime dependencies (uses only Node built-ins) for a clean supply-chain footprint.
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { spawn } from "node:child_process";
6
6
  import { existsSync } from "node:fs";
7
- import { mkdir, readdir, readFile, stat, writeFile, copyFile, rename } from "node:fs/promises";
7
+ import { mkdir, readdir, readFile, writeFile, copyFile } from "node:fs/promises";
8
8
  import { createInterface } from "node:readline/promises";
9
9
  import { stdin as input, stdout as output } from "node:process";
10
10
  import path from "node:path";
@@ -14,7 +14,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
14
14
  const PKG_ROOT = path.resolve(__dirname, "..");
15
15
  const TEMPLATES_DIR = path.join(PKG_ROOT, "templates");
16
16
 
17
- const TEMPLATES = ["node-basic", "cloudflare-worker"];
17
+ const TEMPLATES = ["node-basic", "vercel-edge", "cloudflare-worker"];
18
18
  const PACKAGE_MANAGERS = ["pnpm", "npm", "yarn", "bun"];
19
19
 
20
20
  const RENAME_ON_COPY = new Map([
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-daloy",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Scaffold a new DaloyJS project. Run with `pnpm create daloy`, `npm create daloy@latest`, `yarn create daloy`, or `bun create daloy`.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -0,0 +1,32 @@
1
+ # my-daloy-vercel-api
2
+
3
+ A [DaloyJS](https://daloyjs.dev) Vercel Edge API starter.
4
+
5
+ ## Develop
6
+
7
+ ```bash
8
+ pnpm install
9
+ pnpm dev # http://localhost:3000
10
+ ```
11
+
12
+ Try it:
13
+
14
+ ```bash
15
+ curl http://localhost:3000/healthz
16
+ curl http://localhost:3000/books/1
17
+ ```
18
+
19
+ ## Deploy
20
+
21
+ ```bash
22
+ pnpm deploy
23
+ ```
24
+
25
+ The API entry lives at `api/[...path].ts` and uses `@daloyjs/core/vercel`:
26
+
27
+ ```ts
28
+ export const config = { runtime: "edge" };
29
+ export default toEdgeHandler(app);
30
+ ```
31
+
32
+ That catch-all API route lets DaloyJS own routing while Vercel handles the Edge runtime.
@@ -0,0 +1 @@
1
+ # Add Vercel project env vars here.
@@ -0,0 +1,9 @@
1
+ node_modules/
2
+ .vercel/
3
+ dist/
4
+ coverage/
5
+ .DS_Store
6
+ *.log
7
+ .env
8
+ .env.*
9
+ !.env.example
@@ -0,0 +1,4 @@
1
+ auto-install-peers=true
2
+ strict-peer-dependencies=true
3
+ prefer-frozen-lockfile=true
4
+ verify-store-integrity=true
@@ -0,0 +1,55 @@
1
+ import { z } from "zod";
2
+ import { App, NotFoundError, requestId, secureHeaders } from "@daloyjs/core";
3
+ import { toEdgeHandler } from "@daloyjs/core/vercel";
4
+
5
+ export const config = { runtime: "edge" };
6
+
7
+ const app = new App({
8
+ bodyLimitBytes: 256 * 1024,
9
+ requestTimeoutMs: 5_000,
10
+ production: process.env.NODE_ENV === "production",
11
+ });
12
+
13
+ app.use(requestId());
14
+ app.use(secureHeaders());
15
+
16
+ app.route({
17
+ method: "GET",
18
+ path: "/healthz",
19
+ operationId: "healthz",
20
+ tags: ["Ops"],
21
+ responses: {
22
+ 200: {
23
+ description: "Service is healthy",
24
+ body: z.object({ ok: z.literal(true), runtime: z.literal("vercel-edge") }),
25
+ },
26
+ },
27
+ handler: async () => ({
28
+ status: 200,
29
+ body: { ok: true, runtime: "vercel-edge" as const },
30
+ }),
31
+ });
32
+
33
+ const Book = z.object({ id: z.string(), title: z.string() });
34
+ const books = new Map<string, z.infer<typeof Book>>([
35
+ ["1", { id: "1", title: "Noli Me Tangere" }],
36
+ ]);
37
+
38
+ app.route({
39
+ method: "GET",
40
+ path: "/books/:id",
41
+ operationId: "getBookById",
42
+ tags: ["Books"],
43
+ request: { params: z.object({ id: z.string() }) },
44
+ responses: {
45
+ 200: { description: "Found", body: Book },
46
+ 404: { description: "Not found" },
47
+ },
48
+ handler: async ({ params }) => {
49
+ const book = books.get(params.id);
50
+ if (!book) throw new NotFoundError(`Book ${params.id} not found`);
51
+ return { status: 200, body: book };
52
+ },
53
+ });
54
+
55
+ export default toEdgeHandler(app);
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "my-daloy-vercel-api",
3
+ "version": "0.0.1",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vercel dev",
8
+ "deploy": "vercel deploy",
9
+ "typecheck": "tsc --noEmit",
10
+ "test": "node --import tsx --test tests/**/*.test.ts"
11
+ },
12
+ "dependencies": {
13
+ "@daloyjs/core": "^0.1.1",
14
+ "zod": "^4.4.3"
15
+ },
16
+ "devDependencies": {
17
+ "@types/node": "^25.7.0",
18
+ "tsx": "^4.22.0",
19
+ "typescript": "^6.0.3",
20
+ "vercel": "^48.0.0"
21
+ }
22
+ }
@@ -0,0 +1,9 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+ import handler from "../api/[...path].js";
4
+
5
+ test("Vercel Edge handler responds through DaloyJS", async () => {
6
+ const response = await handler(new Request("https://example.test/healthz"));
7
+ assert.equal(response.status, 200);
8
+ assert.equal((await response.json()).runtime, "vercel-edge");
9
+ });
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "lib": ["ES2022", "DOM"],
7
+ "types": ["node"],
8
+ "strict": true,
9
+ "noUncheckedIndexedAccess": true,
10
+ "esModuleInterop": true,
11
+ "skipLibCheck": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "resolveJsonModule": true,
14
+ "isolatedModules": true,
15
+ "noEmit": true
16
+ },
17
+ "include": ["api/**/*.ts", "tests/**/*.ts"]
18
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "version": 2,
3
+ "cleanUrls": true
4
+ }