create-creek-app 0.0.0-dev.0 → 0.1.6

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/AGENTS.md ADDED
@@ -0,0 +1,136 @@
1
+ # create-creek-app — Agent Reference
2
+
3
+ You are interacting with `create-creek-app`, a CLI that scaffolds Creek projects from templates. Creek deploys to Cloudflare Workers.
4
+
5
+ ## Capabilities
6
+
7
+ - Scaffold a new project from a built-in or third-party template
8
+ - Discover available templates and their schemas (JSON output)
9
+ - Validate template parameters before scaffolding
10
+ - Customize templates via JSON data (inline or file)
11
+
12
+ ## Command Reference
13
+
14
+ All commands output JSON to **stdout**. Progress/errors go to **stderr**.
15
+
16
+ ### Discovery (read-only, no side effects)
17
+
18
+ ```bash
19
+ npx create-creek-app --list
20
+ ```
21
+ Returns JSON array to stdout:
22
+ ```json
23
+ [
24
+ { "name": "blank", "description": "Minimal Creek project (no UI)", "capabilities": [] },
25
+ { "name": "landing", "description": "Landing page with hero and CTA", "capabilities": [] },
26
+ { "name": "blog", "description": "Blog with posts (D1 database)", "capabilities": ["d1"] }
27
+ ]
28
+ ```
29
+
30
+ ```bash
31
+ npx create-creek-app --template landing --schema
32
+ ```
33
+ Returns the template's JSON Schema to stdout:
34
+ ```json
35
+ {
36
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
37
+ "type": "object",
38
+ "properties": {
39
+ "title": { "type": "string", "default": "My Product" },
40
+ "theme": { "type": "string", "enum": ["light", "dark"], "default": "dark" }
41
+ }
42
+ }
43
+ ```
44
+
45
+ ```bash
46
+ npx create-creek-app --template landing --validate --data '{"theme":"dark"}'
47
+ ```
48
+ Returns validation result to stdout:
49
+ ```json
50
+ { "valid": true, "errors": [] }
51
+ ```
52
+ On failure:
53
+ ```json
54
+ { "valid": false, "errors": [{ "path": "/theme", "message": "must be equal to one of the allowed values" }] }
55
+ ```
56
+
57
+ ### Scaffold (creates files)
58
+
59
+ ```bash
60
+ # Non-interactive scaffold
61
+ npx create-creek-app <dir> --template <name> --yes
62
+
63
+ # With custom parameters
64
+ npx create-creek-app <dir> --template <name> --data '<json>' --yes
65
+
66
+ # From a JSON config file
67
+ npx create-creek-app <dir> --template <name> --data-file <path> --yes
68
+
69
+ # Skip install and git init (faster, useful for testing)
70
+ npx create-creek-app <dir> --template <name> --yes --no-install --no-git
71
+
72
+ # Third-party template from GitHub
73
+ npx create-creek-app <dir> --template github:user/repo --yes
74
+ ```
75
+
76
+ ### Deploy (after scaffolding)
77
+
78
+ ```bash
79
+ cd <dir> && npx creek deploy --yes
80
+ ```
81
+
82
+ ## Recommended Workflow
83
+
84
+ 1. **`--list`** → pick a template based on description and capabilities
85
+ 2. **`--schema`** → read the JSON Schema to know valid parameters
86
+ 3. **`--validate`** → check your generated data (optional, scaffold validates too)
87
+ 4. **Scaffold** with `--template`, `--data`, `--yes`
88
+ 5. **Deploy** with `npx creek deploy --yes`
89
+
90
+ ## Exit Codes
91
+
92
+ | Code | Meaning |
93
+ |------|---------|
94
+ | `0` | Success |
95
+ | `1` | Error (validation failure, bad arguments, network error) |
96
+
97
+ ## Available Templates
98
+
99
+ | Name | Capabilities | Use when |
100
+ |------|-------------|----------|
101
+ | `blank` | — | Agent generates all code from scratch |
102
+ | `landing` | — | Marketing/product landing page |
103
+ | `blog` | D1 | Content site with database |
104
+ | `link-in-bio` | — | Social links page |
105
+ | `api` | D1 | REST API backend |
106
+ | `todo` | D1, Realtime | Full-stack app with WebSocket |
107
+ | `dashboard` | D1, Realtime | Data visualization with live updates |
108
+ | `form` | D1 | Form submissions with database storage |
109
+ | `chatbot` | D1, AI | AI-powered chat with conversation history |
110
+
111
+ ## Template Parameters
112
+
113
+ Parameters are template-specific. Always run `--schema` to discover them. Common patterns:
114
+
115
+ - `name` — project name (auto-populated from directory name)
116
+ - `title`, `tagline`, `description` — display text
117
+ - `theme` — typically `"light"` or `"dark"` (enum-constrained)
118
+ - `accentColor` — hex color string
119
+ - `features` — array of `{ title, description }` objects
120
+
121
+ ## What Creek Provides After Deploy
122
+
123
+ The scaffolded project deploys to Cloudflare's edge network via `creek deploy`. Depending on template capabilities:
124
+
125
+ - **All templates**: Global CDN, HTTPS, preview URLs
126
+ - **D1**: SQLite database — use `import { db } from "creek"` (no connection strings)
127
+ - **Realtime**: WebSocket — use `import { usePresence } from "creek/react"`
128
+ - **AI**: Workers AI — use `import { ai } from "creek"`
129
+
130
+ ## Important Notes
131
+
132
+ - Always use `--yes` to skip interactive prompts
133
+ - The `--data` flag accepts inline JSON; use `--data-file` for complex data
134
+ - Templates use runtime config (`creek-data.json`) — users can customize after scaffold by editing this file
135
+ - `creek-template.json` is metadata only — it's removed from the scaffolded project
136
+ - No API keys or credentials needed for scaffolding; `creek deploy` handles auth via OAuth
package/README.md ADDED
@@ -0,0 +1,353 @@
1
+ # create-creek-app
2
+
3
+ [![npm version](https://img.shields.io/npm/v/create-creek-app)](https://www.npmjs.com/package/create-creek-app)
4
+ [![license](https://img.shields.io/npm/l/create-creek-app)](https://github.com/solcreek/creek/blob/main/LICENSE)
5
+
6
+ Scaffold a new [Creek](https://creek.dev) project from a template — deploy to the edge in two commands.
7
+
8
+ ## What is Creek?
9
+
10
+ Creek is a deployment platform built on [Cloudflare Workers](https://developers.cloudflare.com/workers/). It replaces the manual setup of `wrangler.toml`, bindings, and resource provisioning with a single `creek.toml` config and zero-config CLI.
11
+
12
+ - **`creek.toml`** replaces `wrangler.toml` — Creek manages Workers, routes, and bindings for you
13
+ - **`creek deploy`** replaces `wrangler deploy` — one command provisions D1 databases, KV namespaces, R2 buckets, and deploys your code
14
+ - **You own the Cloudflare account** — Creek deploys to your CF account via OAuth, no vendor lock-in
15
+
16
+ If you already use Wrangler, Creek is a higher-level abstraction. If you're new to Cloudflare, Creek is the fastest way to get started.
17
+
18
+ ## Prerequisites
19
+
20
+ - **Node.js 18+** (LTS recommended)
21
+ - **Cloudflare account** — free tier works. Not needed for scaffolding, only for `creek deploy` (you'll be prompted to sign in via OAuth on first deploy)
22
+
23
+ > **`creek` vs `create-creek-app`**: `create-creek-app` scaffolds a new project. `creek` is the CLI that deploys, runs dev server, and manages your project. Both are installed on-demand via `npx`.
24
+
25
+ ## Quick Start
26
+
27
+ ```bash
28
+ # 1. Scaffold a landing page
29
+ npx create-creek-app my-site --template landing --yes
30
+
31
+ # 2. Local development
32
+ cd my-site && npx creek dev
33
+ # → http://localhost:5173 with hot reload
34
+
35
+ # 3. Deploy to production
36
+ npx creek deploy
37
+ # → https://my-site-your-team.bycreek.com (live in ~10 seconds)
38
+ ```
39
+
40
+ You get a globally distributed site on Cloudflare's edge network, with optional D1 database, KV storage, R2 files, AI inference, and Realtime WebSockets — all managed by Creek.
41
+
42
+ ## Usage
43
+
44
+ ### Interactive (human)
45
+
46
+ ```bash
47
+ npx create-creek-app
48
+ # prompts: template → project name → scaffold → install → git init
49
+ ```
50
+
51
+ ### Non-interactive (agent / CI)
52
+
53
+ ```bash
54
+ npx create-creek-app my-blog --template blog --data '{"name":"Alice"}' --yes
55
+ ```
56
+
57
+ ### From a JSON config file
58
+
59
+ ```bash
60
+ npx create-creek-app my-site --template landing --data-file config.json --yes
61
+ ```
62
+
63
+ ```json
64
+ // config.json
65
+ {
66
+ "title": "Acme Corp",
67
+ "tagline": "The best widgets",
68
+ "theme": "light",
69
+ "features": [
70
+ { "title": "Fast", "description": "Edge-powered performance" },
71
+ { "title": "Secure", "description": "Built-in DDoS protection" }
72
+ ]
73
+ }
74
+ ```
75
+
76
+ ### Template discovery
77
+
78
+ ```bash
79
+ # List all templates
80
+ npx create-creek-app --list
81
+ ```
82
+
83
+ ```json
84
+ [
85
+ { "name": "blank", "description": "Minimal Creek project (no UI)", "capabilities": [] },
86
+ { "name": "landing", "description": "Landing page with hero and CTA", "capabilities": [] },
87
+ { "name": "blog", "description": "Blog with posts (D1 database)", "capabilities": ["d1"] },
88
+ ...
89
+ ]
90
+ ```
91
+
92
+ ```bash
93
+ # Print a template's JSON Schema
94
+ npx create-creek-app --template landing --schema
95
+ ```
96
+
97
+ ```json
98
+ {
99
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
100
+ "type": "object",
101
+ "properties": {
102
+ "title": { "type": "string", "default": "My Product" },
103
+ "theme": { "type": "string", "enum": ["light", "dark"], "default": "dark" }
104
+ }
105
+ }
106
+ ```
107
+
108
+ ```bash
109
+ # Validate data before scaffolding
110
+ npx create-creek-app --template landing --validate --data '{"theme":"dark"}'
111
+ # → { "valid": true, "errors": [] }
112
+ ```
113
+
114
+ ### Third-party templates
115
+
116
+ ```bash
117
+ npx create-creek-app --template github:user/my-template
118
+ ```
119
+
120
+ ## Options
121
+
122
+ ```
123
+ npx create-creek-app [dir] [options]
124
+
125
+ dir Project directory (default: prompted or "my-creek-app")
126
+
127
+ -t, --template <name|github:user/repo> Template to use
128
+ --data <json> JSON data for template params
129
+ --data-file <path> JSON file for template params
130
+ --list List available templates (JSON)
131
+ --schema Print template JSON Schema
132
+ --validate Validate data against schema
133
+ --registry <url> Private template registry (enterprise)
134
+ -y, --yes Skip prompts, use defaults
135
+ --no-install Skip dependency installation
136
+ --no-git Skip git init
137
+ ```
138
+
139
+ ## Templates
140
+
141
+ Each template is a complete, deployable project — not a skeleton. Capabilities indicate which Creek-managed resources are pre-configured:
142
+
143
+ | Template | Description | Capabilities |
144
+ |----------|-------------|-------------|
145
+ | `blank` | Minimal Creek project (no UI) | — |
146
+ | `landing` | Landing page with hero and CTA | — |
147
+ | `blog` | Blog with posts | D1 database |
148
+ | `link-in-bio` | Social links page | — |
149
+ | `api` | REST API with Hono | D1 database |
150
+ | `todo` | Realtime todo app | D1 + WebSocket |
151
+ | `dashboard` | Data dashboard | D1 + WebSocket |
152
+ | `form` | Form collector | D1 database |
153
+ | `chatbot` | AI chatbot | D1 + Workers AI |
154
+
155
+ **Capabilities explained:**
156
+ - **D1** — SQLite database at the edge, managed by Creek (no connection strings, no migrations)
157
+ - **Realtime** — WebSocket connections via Creek's Realtime service (presence, broadcast)
158
+ - **AI** — Inference via Cloudflare Workers AI (LLMs, embeddings, image generation)
159
+
160
+ ## Template Schema
161
+
162
+ Each template defines customizable parameters via [JSON Schema](https://json-schema.org/) in `creek-template.json`. This enables both human prompts and programmatic validation.
163
+
164
+ ### creek-template.json
165
+
166
+ ```json
167
+ {
168
+ "name": "landing",
169
+ "description": "Landing page with hero, features, and CTA",
170
+ "capabilities": [],
171
+ "schema": {
172
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
173
+ "type": "object",
174
+ "properties": {
175
+ "title": { "type": "string", "default": "My Product" },
176
+ "tagline": { "type": "string", "default": "Ship faster with Creek" },
177
+ "theme": {
178
+ "type": "string",
179
+ "enum": ["light", "dark"],
180
+ "default": "dark"
181
+ }
182
+ }
183
+ }
184
+ }
185
+ ```
186
+
187
+ ### Fields
188
+
189
+ | Field | Type | Required | Description |
190
+ |-------|------|----------|-------------|
191
+ | `name` | string | yes | Template identifier |
192
+ | `description` | string | yes | Short description |
193
+ | `capabilities` | string[] | yes | Creek resources used: `d1`, `kv`, `r2`, `ai`, `realtime` |
194
+ | `thumbnail` | string | no | Path or URL to thumbnail image (400x300 recommended) |
195
+ | `screenshot` | string | no | Path or URL to full screenshot image |
196
+ | `schema` | object | no | JSON Schema defining customizable parameters |
197
+
198
+ ### creek-data.json
199
+
200
+ Default values for the schema parameters. Your app reads this file at runtime — no build-time string replacement. Users customize their project by editing this one file.
201
+
202
+ ```json
203
+ {
204
+ "title": "My Product",
205
+ "tagline": "Ship faster with Creek",
206
+ "theme": "dark"
207
+ }
208
+ ```
209
+
210
+ ```tsx
211
+ // src/App.tsx — reads config at runtime
212
+ import data from "../creek-data.json";
213
+
214
+ export function App() {
215
+ return <h1>{data.title}</h1>;
216
+ }
217
+ ```
218
+
219
+ ## Validation
220
+
221
+ Data is validated against the template's JSON Schema using [ajv](https://ajv.js.org/). Validation runs automatically during scaffold and can be triggered independently with `--validate`.
222
+
223
+ ### Supported constraints
224
+
225
+ - **type** — `string`, `number`, `integer`, `boolean`, `array`, `object`
226
+ - **enum** — fixed set of allowed values
227
+ - **default** — applied when the property is omitted
228
+ - **required** — within object items (array entries, nested objects)
229
+ - **items** — schema for array elements
230
+ - **nested objects** — full recursive validation
231
+
232
+ ### Validation examples
233
+
234
+ ```bash
235
+ # Valid — passes (exit code 0)
236
+ npx create-creek-app --template landing --validate --data '{"theme":"dark"}'
237
+ # → { "valid": true, "errors": [] }
238
+
239
+ # Invalid enum — fails (exit code 1)
240
+ npx create-creek-app --template landing --validate --data '{"theme":"invalid"}'
241
+ # → { "valid": false, "errors": [{ "path": "/theme", "message": "must be equal to one of the allowed values" }] }
242
+ ```
243
+
244
+ ## Exit Codes
245
+
246
+ | Code | Meaning |
247
+ |------|---------|
248
+ | `0` | Success |
249
+ | `1` | Error — validation failure, invalid arguments, scaffold failure, or network error |
250
+
251
+ All structured output (`--list`, `--schema`, `--validate`) goes to **stdout** as JSON. Progress messages and errors go to **stderr**.
252
+
253
+ ## Creating Custom Templates
254
+
255
+ A Creek template is a directory with at minimum a `package.json` and `creek.toml`. Add `creek-template.json` for schema-driven customization.
256
+
257
+ ### Template structure
258
+
259
+ ```
260
+ my-template/
261
+ ├── creek-template.json ← schema + metadata (removed on scaffold)
262
+ ├── creek-data.json ← default values (optional)
263
+ ├── creek.toml ← Creek project config
264
+ ├── package.json
265
+ ├── src/ ← your code
266
+ ├── worker/index.ts ← edge worker (if needed)
267
+ └── .gitignore
268
+ ```
269
+
270
+ ### Best practices
271
+
272
+ 1. **Use JSON Schema defaults** — every property should have a `default` so the template works without any `--data`
273
+ 2. **Read config at runtime** — import `creek-data.json` in your code instead of build-time placeholders
274
+ 3. **Keep schemas flat** — prefer top-level string/number/boolean properties
275
+ 4. **Use `enum` for constrained choices** — themes, layouts, color schemes. Agents discover valid options via `--schema`
276
+ 5. **Include a `name` property** — `create-creek-app` auto-populates it from the project directory
277
+
278
+ ### Publishing
279
+
280
+ Host your template on GitHub and use it directly:
281
+
282
+ ```bash
283
+ npx create-creek-app --template github:yourname/my-template
284
+ ```
285
+
286
+ Or submit it to the [Creek template gallery](https://github.com/solcreek/templates) via pull request.
287
+
288
+ ## Agent Workflow
289
+
290
+ `create-creek-app` is designed for both humans and AI agents. Typical agent flow:
291
+
292
+ ```bash
293
+ # 1. Discover templates
294
+ npx create-creek-app --list
295
+ # → JSON array to stdout
296
+
297
+ # 2. Read schema for chosen template
298
+ npx create-creek-app --template landing --schema
299
+ # → JSON Schema to stdout
300
+
301
+ # 3. Validate generated data
302
+ npx create-creek-app --template landing --validate --data '{"title":"Acme","theme":"dark"}'
303
+ # → { "valid": true, "errors": [] }
304
+
305
+ # 4. Scaffold
306
+ npx create-creek-app my-site --template landing --data '{"title":"Acme"}' --yes
307
+
308
+ # 5. Deploy
309
+ cd my-site && npx creek deploy --yes
310
+ # → { "ok": true, "url": "https://my-site-team.bycreek.com", ... }
311
+ ```
312
+
313
+ All discovery and validation commands output JSON to stdout for programmatic consumption. Use `--yes` to skip all interactive prompts.
314
+
315
+ ## Contributing Templates
316
+
317
+ The template ecosystem is open to everyone. We welcome contributions from individual developers, agencies, and framework authors.
318
+
319
+ ### How to submit
320
+
321
+ 1. Fork [solcreek/templates](https://github.com/solcreek/templates)
322
+ 2. Create your template directory following the [template structure](#template-structure)
323
+ 3. Ensure it scaffolds and deploys cleanly: `npx create-creek-app test-dir --template ./your-template --yes && cd test-dir && creek deploy`
324
+ 4. Open a pull request
325
+
326
+ ### Acceptance criteria
327
+
328
+ - **Works out of the box** — `--yes` with no `--data` must produce a deployable project
329
+ - **Has `creek-template.json`** — with description, capabilities, and schema (if customizable)
330
+ - **No secrets or API keys** — templates must not require external service credentials to scaffold
331
+ - **English** — template names, descriptions, and code comments in English
332
+
333
+ ### Template tiers
334
+
335
+ | Tier | Badge | Maintained by | Review |
336
+ |------|-------|--------------|--------|
337
+ | **Official** | `solcreek/templates` | Creek team | Creek team review |
338
+ | **Community** | `github:author/repo` | Author | Self-published, no review required |
339
+
340
+ Official templates are held to a higher standard: they must stay compatible with the latest Creek CLI and are tested in CI. Community templates can be used by anyone via `--template github:author/repo` — no approval process needed.
341
+
342
+ ### Ideas for templates
343
+
344
+ We'd especially love to see:
345
+ - Framework-specific starters (Astro + Creek, SvelteKit + Creek)
346
+ - Industry verticals (restaurant menu, event page, portfolio)
347
+ - Backend patterns (webhook receiver, cron job, queue processor)
348
+
349
+ See the [templates repo](https://github.com/solcreek/templates) for the full contribution guide.
350
+
351
+ ## License
352
+
353
+ Apache-2.0
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Merge user-supplied data into creek-data.json (and update creek.toml project name).
3
+ * `defaults` is what was already in the template's creek-data.json.
4
+ */
5
+ export declare function applyData(dir: string, userData: Record<string, unknown>, defaults: Record<string, unknown>): void;
@@ -0,0 +1,33 @@
1
+ import { join } from "node:path";
2
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
3
+ /**
4
+ * Merge user-supplied data into creek-data.json (and update creek.toml project name).
5
+ * `defaults` is what was already in the template's creek-data.json.
6
+ */
7
+ export function applyData(dir, userData, defaults) {
8
+ const merged = { ...defaults, ...userData };
9
+ // Write merged creek-data.json
10
+ const dataPath = join(dir, "creek-data.json");
11
+ writeFileSync(dataPath, JSON.stringify(merged, null, 2) + "\n");
12
+ // If "name" was provided, also update creek.toml and package.json
13
+ if (typeof merged.name === "string") {
14
+ updateCreekTomlName(dir, merged.name);
15
+ updatePackageJsonName(dir, merged.name);
16
+ }
17
+ }
18
+ function updateCreekTomlName(dir, name) {
19
+ const tomlPath = join(dir, "creek.toml");
20
+ if (!existsSync(tomlPath))
21
+ return;
22
+ let content = readFileSync(tomlPath, "utf-8");
23
+ content = content.replace(/^name\s*=\s*"[^"]*"/m, `name = "${name}"`);
24
+ writeFileSync(tomlPath, content);
25
+ }
26
+ function updatePackageJsonName(dir, name) {
27
+ const pkgPath = join(dir, "package.json");
28
+ if (!existsSync(pkgPath))
29
+ return;
30
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
31
+ pkg.name = name;
32
+ writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
33
+ }
@@ -0,0 +1,20 @@
1
+ export interface FetchResult {
2
+ dir: string;
3
+ templateConfig: TemplateConfig | null;
4
+ defaultData: Record<string, unknown>;
5
+ }
6
+ export interface TemplateConfig {
7
+ name: string;
8
+ description: string;
9
+ capabilities: string[];
10
+ thumbnail?: string;
11
+ screenshot?: string;
12
+ schema?: Record<string, unknown>;
13
+ }
14
+ /**
15
+ * Download a template into `dest`.
16
+ *
17
+ * Built-in templates: "landing" → github:solcreek/templates/landing
18
+ * Third-party: "github:user/repo" → passed to giget directly
19
+ */
20
+ export declare function fetchTemplate(template: string, dest: string): Promise<FetchResult>;
package/dist/fetch.js ADDED
@@ -0,0 +1,35 @@
1
+ import { downloadTemplate } from "giget";
2
+ import { join } from "node:path";
3
+ import { existsSync, readFileSync } from "node:fs";
4
+ const TEMPLATE_REPO = "github:solcreek/templates";
5
+ /**
6
+ * Download a template into `dest`.
7
+ *
8
+ * Built-in templates: "landing" → github:solcreek/templates/landing
9
+ * Third-party: "github:user/repo" → passed to giget directly
10
+ */
11
+ export async function fetchTemplate(template, dest) {
12
+ const source = isThirdParty(template)
13
+ ? template
14
+ : `${TEMPLATE_REPO}/${template}`;
15
+ const { dir } = await downloadTemplate(source, {
16
+ dir: dest,
17
+ force: true,
18
+ });
19
+ // Read creek-template.json if present
20
+ const configPath = join(dir, "creek-template.json");
21
+ let templateConfig = null;
22
+ if (existsSync(configPath)) {
23
+ templateConfig = JSON.parse(readFileSync(configPath, "utf-8"));
24
+ }
25
+ // Read creek-data.json defaults if present
26
+ const dataPath = join(dir, "creek-data.json");
27
+ let defaultData = {};
28
+ if (existsSync(dataPath)) {
29
+ defaultData = JSON.parse(readFileSync(dataPath, "utf-8"));
30
+ }
31
+ return { dir, templateConfig, defaultData };
32
+ }
33
+ function isThirdParty(template) {
34
+ return (template.includes(":") || template.includes("/") || template.startsWith("."));
35
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,171 @@
1
+ #!/usr/bin/env node
2
+ import { defineCommand, runMain } from "citty";
3
+ import consola from "consola";
4
+ import { mkdtempSync, readFileSync } from "node:fs";
5
+ import { tmpdir } from "node:os";
6
+ import { join } from "node:path";
7
+ import { TEMPLATES } from "./templates.js";
8
+ import { scaffold } from "./scaffold.js";
9
+ import { validateData } from "./validate.js";
10
+ import { fetchTemplate } from "./fetch.js";
11
+ import { promptTemplate, promptDir } from "./prompts.js";
12
+ const main = defineCommand({
13
+ meta: {
14
+ name: "create-creek-app",
15
+ description: "Create a new Creek project from a template",
16
+ },
17
+ args: {
18
+ dir: {
19
+ type: "positional",
20
+ description: "Project directory",
21
+ required: false,
22
+ },
23
+ template: {
24
+ type: "string",
25
+ alias: "t",
26
+ description: "Template name or github:user/repo",
27
+ },
28
+ data: {
29
+ type: "string",
30
+ description: "JSON data for template params",
31
+ },
32
+ "data-file": {
33
+ type: "string",
34
+ description: "Path to JSON file for template params",
35
+ },
36
+ list: {
37
+ type: "boolean",
38
+ description: "List available templates (JSON)",
39
+ default: false,
40
+ },
41
+ schema: {
42
+ type: "boolean",
43
+ description: "Print template JSON Schema",
44
+ default: false,
45
+ },
46
+ validate: {
47
+ type: "boolean",
48
+ description: "Validate data against template schema",
49
+ default: false,
50
+ },
51
+ registry: {
52
+ type: "string",
53
+ description: "Private template registry URL (enterprise)",
54
+ },
55
+ yes: {
56
+ type: "boolean",
57
+ alias: "y",
58
+ description: "Skip prompts, use defaults",
59
+ default: false,
60
+ },
61
+ install: {
62
+ type: "boolean",
63
+ description: "Install dependencies (use --no-install to skip)",
64
+ default: true,
65
+ },
66
+ git: {
67
+ type: "boolean",
68
+ description: "Initialize git repo (use --no-git to skip)",
69
+ default: true,
70
+ },
71
+ },
72
+ async run({ args }) {
73
+ // --registry: enterprise placeholder
74
+ if (args.registry) {
75
+ console.log(JSON.stringify({
76
+ error: "Private template registry is an enterprise feature. Coming soon — creek.dev/enterprise",
77
+ }));
78
+ process.exit(0);
79
+ }
80
+ // --list: output JSON array of templates
81
+ if (args.list) {
82
+ console.log(JSON.stringify(TEMPLATES, null, 2));
83
+ return;
84
+ }
85
+ // --schema: print template's JSON Schema
86
+ if (args.schema) {
87
+ const templateName = args.template;
88
+ if (!templateName) {
89
+ consola.error("--schema requires --template <name>");
90
+ process.exit(1);
91
+ }
92
+ const { templateConfig } = await fetchTemplate(templateName, makeTempDir());
93
+ if (!templateConfig?.schema) {
94
+ consola.error(`Template "${templateName}" has no schema`);
95
+ process.exit(1);
96
+ }
97
+ console.log(JSON.stringify(templateConfig.schema, null, 2));
98
+ return;
99
+ }
100
+ // Parse user data from --data or --data-file
101
+ let userData = {};
102
+ if (args.data) {
103
+ try {
104
+ userData = JSON.parse(args.data);
105
+ }
106
+ catch {
107
+ consola.error("Invalid JSON in --data");
108
+ process.exit(1);
109
+ }
110
+ }
111
+ else if (args["data-file"]) {
112
+ try {
113
+ userData = JSON.parse(readFileSync(args["data-file"], "utf-8"));
114
+ }
115
+ catch {
116
+ consola.error(`Cannot read --data-file: ${args["data-file"]}`);
117
+ process.exit(1);
118
+ }
119
+ }
120
+ // --validate: validate data and exit
121
+ if (args.validate) {
122
+ const templateName = args.template;
123
+ if (!templateName) {
124
+ consola.error("--validate requires --template <name>");
125
+ process.exit(1);
126
+ }
127
+ const { templateConfig, defaultData } = await fetchTemplate(templateName, makeTempDir());
128
+ if (!templateConfig?.schema) {
129
+ console.log(JSON.stringify({ valid: true, errors: [] }));
130
+ return;
131
+ }
132
+ const merged = { ...defaultData, ...userData };
133
+ const result = validateData(templateConfig.schema, merged);
134
+ console.log(JSON.stringify(result, null, 2));
135
+ process.exit(result.valid ? 0 : 1);
136
+ }
137
+ // Interactive or direct scaffold
138
+ let template = args.template;
139
+ let dir = args.dir;
140
+ if (!args.yes) {
141
+ // Interactive mode
142
+ if (!template) {
143
+ template = await promptTemplate();
144
+ }
145
+ if (!dir) {
146
+ dir = await promptDir();
147
+ }
148
+ }
149
+ else {
150
+ // Non-interactive: require --template, default dir
151
+ if (!template) {
152
+ template = "blank";
153
+ }
154
+ if (!dir) {
155
+ dir = "my-creek-app";
156
+ }
157
+ }
158
+ await scaffold({
159
+ template,
160
+ dir,
161
+ data: userData,
162
+ install: args.install,
163
+ git: args.git,
164
+ silent: false,
165
+ });
166
+ },
167
+ });
168
+ function makeTempDir() {
169
+ return mkdtempSync(join(tmpdir(), "creek-tpl-"));
170
+ }
171
+ runMain(main);
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Interactive template picker — used when no --template flag is given.
3
+ */
4
+ export declare function promptTemplate(): Promise<string>;
5
+ /**
6
+ * Prompt for project directory name.
7
+ */
8
+ export declare function promptDir(): Promise<string>;
@@ -0,0 +1,29 @@
1
+ import consola from "consola";
2
+ import { TEMPLATES } from "./templates.js";
3
+ /**
4
+ * Interactive template picker — used when no --template flag is given.
5
+ */
6
+ export async function promptTemplate() {
7
+ const choices = TEMPLATES.map((t) => ({
8
+ label: `${t.name} — ${t.description}`,
9
+ value: t.name,
10
+ hint: t.capabilities.length ? t.capabilities.join(", ") : undefined,
11
+ }));
12
+ const selected = await consola.prompt("Select a template:", {
13
+ type: "select",
14
+ options: choices,
15
+ });
16
+ // consola.prompt returns the value string for select type
17
+ return selected;
18
+ }
19
+ /**
20
+ * Prompt for project directory name.
21
+ */
22
+ export async function promptDir() {
23
+ const dir = await consola.prompt("Project name:", {
24
+ type: "text",
25
+ default: "my-creek-app",
26
+ placeholder: "my-creek-app",
27
+ });
28
+ return dir;
29
+ }
@@ -0,0 +1,14 @@
1
+ export interface ScaffoldOptions {
2
+ template: string;
3
+ dir: string;
4
+ data?: Record<string, unknown>;
5
+ install?: boolean;
6
+ git?: boolean;
7
+ silent?: boolean;
8
+ }
9
+ export interface ScaffoldResult {
10
+ dir: string;
11
+ template: string;
12
+ name: string;
13
+ }
14
+ export declare function scaffold(opts: ScaffoldOptions): Promise<ScaffoldResult>;
@@ -0,0 +1,76 @@
1
+ import { resolve, basename } from "node:path";
2
+ import { existsSync, unlinkSync } from "node:fs";
3
+ import { execSync } from "node:child_process";
4
+ import consola from "consola";
5
+ import { fetchTemplate } from "./fetch.js";
6
+ import { applyData } from "./apply-data.js";
7
+ import { validateData } from "./validate.js";
8
+ export async function scaffold(opts) {
9
+ const dest = resolve(opts.dir);
10
+ const projectName = basename(dest);
11
+ // 1. Fetch template
12
+ if (!opts.silent)
13
+ consola.start(`Downloading template: ${opts.template}`);
14
+ const { dir, templateConfig, defaultData } = await fetchTemplate(opts.template, dest);
15
+ // 2. Validate user data against schema (if schema exists)
16
+ const userData = { name: projectName, ...(opts.data ?? {}) };
17
+ if (templateConfig?.schema) {
18
+ const result = validateData(templateConfig.schema, { ...defaultData, ...userData });
19
+ if (!result.valid) {
20
+ consola.error("Data validation failed:");
21
+ for (const err of result.errors) {
22
+ consola.error(` ${err.path}: ${err.message}`);
23
+ }
24
+ throw new Error("Template data validation failed");
25
+ }
26
+ }
27
+ // 3. Apply data
28
+ applyData(dir, userData, defaultData);
29
+ // 4. Remove creek-template.json from output (metadata, not project file)
30
+ const templateConfigPath = resolve(dir, "creek-template.json");
31
+ if (existsSync(templateConfigPath)) {
32
+ unlinkSync(templateConfigPath);
33
+ }
34
+ // 6. Install dependencies
35
+ if (opts.install !== false) {
36
+ const pkgPath = resolve(dir, "package.json");
37
+ if (existsSync(pkgPath)) {
38
+ if (!opts.silent)
39
+ consola.start("Installing dependencies...");
40
+ try {
41
+ execSync("npm install", { cwd: dir, stdio: "pipe" });
42
+ if (!opts.silent)
43
+ consola.success("Dependencies installed");
44
+ }
45
+ catch {
46
+ consola.warn("Failed to install dependencies. Run `npm install` manually.");
47
+ }
48
+ }
49
+ }
50
+ // 7. Git init
51
+ if (opts.git !== false) {
52
+ try {
53
+ execSync("git init", { cwd: dir, stdio: "pipe" });
54
+ execSync("git add -A", { cwd: dir, stdio: "pipe" });
55
+ execSync('git commit -m "Initial commit from create-creek-app"', {
56
+ cwd: dir,
57
+ stdio: "pipe",
58
+ });
59
+ if (!opts.silent)
60
+ consola.success("Git repository initialized");
61
+ }
62
+ catch {
63
+ // git not available or failed — that's fine
64
+ }
65
+ }
66
+ if (!opts.silent) {
67
+ console.log("");
68
+ consola.success(`Created ${projectName} with template "${opts.template}"`);
69
+ console.log("");
70
+ consola.info(" Next steps:");
71
+ consola.info(` cd ${projectName}`);
72
+ consola.info(" creek deploy Deploy to production");
73
+ consola.info(" creek dev Start local development");
74
+ }
75
+ return { dir, template: opts.template, name: projectName };
76
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Template catalog — used for --list, interactive prompt, and gallery.
3
+ *
4
+ * Four types by output:
5
+ * site — Visual pages (deploy → shareable URL)
6
+ * app — Interactive UI + backend logic
7
+ * workflow — Background process (no/minimal UI), trigger + steps
8
+ * connector — Data bridge pattern (ingestion → storage)
9
+ */
10
+ export interface Template {
11
+ name: string;
12
+ description: string;
13
+ type: "site" | "app" | "workflow" | "connector" | "developer";
14
+ capabilities: string[];
15
+ trigger?: string;
16
+ }
17
+ export declare const TEMPLATES: Template[];
18
+ export type TemplateName = (typeof TEMPLATES)[number]["name"];
19
+ export type TemplateType = Template["type"];
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Template catalog — used for --list, interactive prompt, and gallery.
3
+ *
4
+ * Four types by output:
5
+ * site — Visual pages (deploy → shareable URL)
6
+ * app — Interactive UI + backend logic
7
+ * workflow — Background process (no/minimal UI), trigger + steps
8
+ * connector — Data bridge pattern (ingestion → storage)
9
+ */
10
+ export const TEMPLATES = [
11
+ // --- Sites (Level 4 — deploy → shareable) ---
12
+ { name: "landing", description: "Landing page with hero and CTA", type: "site", capabilities: [] },
13
+ { name: "blog", description: "Blog with image uploads", type: "site", capabilities: ["database", "storage"] },
14
+ { name: "link-in-bio", description: "Social links page", type: "site", capabilities: [] },
15
+ { name: "waitlist", description: "Waitlist with AI user segmentation", type: "site", capabilities: ["database", "ai"] },
16
+ // --- Apps (Level 3 — working data pipeline + UI) ---
17
+ { name: "form", description: "Form collector with admin dashboard", type: "app", capabilities: ["database"] },
18
+ { name: "dashboard", description: "Data dashboard with scheduled refresh", type: "app", capabilities: ["database", "realtime", "cron"] },
19
+ { name: "chatbot", description: "AI chatbot with conversation history", type: "app", capabilities: ["database", "ai"] },
20
+ { name: "survey", description: "Survey with AI-powered analysis", type: "app", capabilities: ["database", "ai"] },
21
+ { name: "knowledge-base", description: "Knowledge base with AI search", type: "app", capabilities: ["database", "ai", "storage"] },
22
+ { name: "status-page", description: "Service status page with uptime monitoring", type: "app", capabilities: ["database", "realtime", "cron", "cache"] },
23
+ { name: "file-share", description: "File upload/download with expiring links", type: "app", capabilities: ["database", "storage"] },
24
+ { name: "todo", description: "Realtime todo app (learning example)", type: "app", capabilities: ["database", "realtime"] },
25
+ // --- Workflows (Level 2-3 — trigger + steps, no/minimal UI) ---
26
+ { name: "approval-flow", description: "Approval workflow — leave, expense, procurement", type: "workflow", capabilities: ["database", "realtime", "queue"], trigger: "webhook" },
27
+ { name: "invoice-processor", description: "Email invoice → AI extract → DB → notify", type: "workflow", capabilities: ["database", "ai", "storage", "email"], trigger: "email" },
28
+ { name: "scheduled-report", description: "Scheduled query → AI summary → PDF report", type: "workflow", capabilities: ["database", "ai", "storage", "cron"], trigger: "cron" },
29
+ { name: "data-sync", description: "Scheduled API pull → diff → DB → notify", type: "workflow", capabilities: ["database", "cron"], trigger: "cron" },
30
+ { name: "ai-classifier", description: "Input → AI classify → route to queue", type: "workflow", capabilities: ["database", "ai", "queue"], trigger: "webhook" },
31
+ // --- Connectors (Level 2 — pure platform wiring) ---
32
+ { name: "api", description: "REST API with Hono", type: "connector", capabilities: ["database"], trigger: "http" },
33
+ { name: "webhook-receiver", description: "Receive and process external webhooks", type: "connector", capabilities: ["database", "queue"], trigger: "webhook" },
34
+ { name: "email-to-db", description: "Email → parse → attachments to R2 → DB", type: "connector", capabilities: ["database", "storage", "email"], trigger: "email" },
35
+ { name: "ftp-sync", description: "Scheduled FTP/SFTP pull → parse → DB", type: "connector", capabilities: ["database", "storage", "cron", "ftp"], trigger: "cron" },
36
+ // --- Developer ---
37
+ { name: "blank", description: "Minimal Creek project (empty canvas)", type: "developer", capabilities: [] },
38
+ ];
@@ -0,0 +1,13 @@
1
+ export interface ValidationResult {
2
+ valid: boolean;
3
+ errors: ValidationError[];
4
+ }
5
+ export interface ValidationError {
6
+ path: string;
7
+ message: string;
8
+ }
9
+ /**
10
+ * Validate data against a JSON Schema from creek-template.json.
11
+ * Returns { valid, errors }.
12
+ */
13
+ export declare function validateData(schema: Record<string, unknown>, data: Record<string, unknown>): ValidationResult;
@@ -0,0 +1,20 @@
1
+ import Ajv from "ajv";
2
+ const ajv = new Ajv({ allErrors: true, useDefaults: true });
3
+ /**
4
+ * Validate data against a JSON Schema from creek-template.json.
5
+ * Returns { valid, errors }.
6
+ */
7
+ export function validateData(schema, data) {
8
+ // Strip $schema meta field — ajv doesn't support 2020-12 meta-schema by default
9
+ const { $schema: _, ...schemaWithoutMeta } = schema;
10
+ const validate = ajv.compile(schemaWithoutMeta);
11
+ const valid = validate(data);
12
+ if (valid) {
13
+ return { valid: true, errors: [] };
14
+ }
15
+ const errors = (validate.errors ?? []).map((err) => ({
16
+ path: err.instancePath || "/",
17
+ message: err.message ?? "unknown error",
18
+ }));
19
+ return { valid: false, errors };
20
+ }
package/package.json CHANGED
@@ -1,8 +1,47 @@
1
1
  {
2
2
  "name": "create-creek-app",
3
- "version": "0.0.0-dev.0",
3
+ "version": "0.1.6",
4
+ "description": "Create a new Creek project from a template",
4
5
  "type": "module",
5
6
  "bin": {
6
- "create-creek-app": "./bin/create-creek-app.js"
7
+ "create-creek-app": "./dist/index.js"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "files": [
11
+ "dist",
12
+ "AGENTS.md"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "dev": "tsc --watch",
17
+ "test": "vitest run"
18
+ },
19
+ "keywords": [
20
+ "creek",
21
+ "create",
22
+ "scaffold",
23
+ "template",
24
+ "cloudflare",
25
+ "workers",
26
+ "d1"
27
+ ],
28
+ "author": "SolCreek",
29
+ "license": "Apache-2.0",
30
+ "homepage": "https://creek.dev",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://github.com/solcreek/creek.git",
34
+ "directory": "packages/create-creek-app"
35
+ },
36
+ "dependencies": {
37
+ "citty": "^0.1.6",
38
+ "consola": "^3.4.2",
39
+ "giget": "^2.0.0",
40
+ "ajv": "^8.17.1"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^22.0.0",
44
+ "typescript": "^5.8.2",
45
+ "vitest": "^4.1.1"
7
46
  }
8
47
  }
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- console.log("create-creek-app");