clawfire 0.1.0 → 0.2.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 +386 -88
- package/dist/admin.d.cts +1 -1
- package/dist/admin.d.ts +1 -1
- package/dist/cli.js +23 -5
- package/dist/{config-QMBJRn9G.d.cts → config-D-Chojiu.d.cts} +7 -0
- package/dist/{config-QMBJRn9G.d.ts → config-D-Chojiu.d.ts} +7 -0
- package/dist/{dev-server-QAVWINAT.js → dev-server-ZGXJARNY.js} +712 -99
- package/dist/dev.cjs +712 -99
- package/dist/dev.cjs.map +1 -1
- package/dist/dev.d.cts +35 -36
- package/dist/dev.d.ts +35 -36
- package/dist/dev.js +712 -99
- package/dist/dev.js.map +1 -1
- package/dist/functions.d.cts +1 -1
- package/dist/functions.d.ts +1 -1
- package/dist/index.cjs +6 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/CLAUDE.md +18 -1
- package/templates/clawfire.config.ts +4 -0
- package/templates/starter/CLAUDE.md +85 -5
- package/templates/starter/app/components/footer.html +5 -0
- package/templates/starter/app/components/nav.html +14 -0
- package/templates/starter/app/pages/_404.html +9 -0
- package/templates/starter/app/pages/_layout.html +46 -0
- package/templates/starter/app/pages/about.html +84 -0
- package/templates/starter/app/pages/index.html +192 -0
- package/templates/starter/app/pages/todos/index.html +173 -0
- package/templates/starter/clawfire.config.ts +4 -0
- package/templates/starter/dev.ts +2 -1
- package/templates/starter/public/index.html +9 -345
package/README.md
CHANGED
|
@@ -2,56 +2,183 @@
|
|
|
2
2
|
|
|
3
3
|
**AI-First Firebase App Framework — Speak. Build. Deploy.**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/clawfire)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
|
|
8
|
+
Clawfire lets you build Firebase apps by talking to AI. Define your API contracts with Zod, and get type-safe routing, auto-generated clients, security rules, and deployment — all from a single source of truth.
|
|
9
|
+
|
|
10
|
+
---
|
|
6
11
|
|
|
7
12
|
## Features
|
|
8
13
|
|
|
9
|
-
- **Contract-based API** —
|
|
10
|
-
- **File-based Routing** — `app/routes
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
15
|
-
- **
|
|
16
|
-
- **
|
|
14
|
+
- **Contract-based API** — Define input/output with Zod schemas. Runtime validation, type safety, and docs come for free.
|
|
15
|
+
- **File-based Routing** — `app/routes/todos/create.ts` becomes `POST /api/todos/create`. No configuration.
|
|
16
|
+
- **Page Routing** — `app/pages/about.html` becomes `/about`. Layouts, components, and SPA navigation built in.
|
|
17
|
+
- **Layouts & Components** — `_layout.html` wraps pages via `<slot />`. `<c-nav />` inserts `app/components/nav.html`.
|
|
18
|
+
- **SPA Navigation** — Internal links swap page content without full reload. Tailwind CSS via CDN.
|
|
19
|
+
- **Two-Port Dev Server** — Frontend app on port 3000, API + Playground on port 3456. One command.
|
|
20
|
+
- **Hot Reload** — API, page, and CSS changes reload instantly. No manual refresh needed.
|
|
21
|
+
- **API Playground** — Interactive API explorer auto-generated from your route definitions.
|
|
22
|
+
- **Auto Client Generation** — Type-safe `api.todos.create({ title })` client generated from your contracts.
|
|
23
|
+
- **Firebase-Native** — Firestore, Auth, Functions, Hosting. Fully integrated, no alternatives needed.
|
|
24
|
+
- **Security by Default** — Input validation, CORS deny, rate limiting, XSS sanitization, log masking — all ON.
|
|
25
|
+
- **Auto Security Rules** — Firestore rules generated from model definitions.
|
|
26
|
+
- **AI Skills** — Six `/clawfire-*` Claude Code commands to manage your entire project.
|
|
27
|
+
|
|
28
|
+
---
|
|
17
29
|
|
|
18
30
|
## Quick Start
|
|
19
31
|
|
|
32
|
+
### 1. Create a New Project
|
|
33
|
+
|
|
20
34
|
```bash
|
|
21
|
-
|
|
35
|
+
mkdir my-app && cd my-app
|
|
22
36
|
npx clawfire init
|
|
37
|
+
npm install
|
|
38
|
+
```
|
|
23
39
|
|
|
24
|
-
|
|
25
|
-
|
|
40
|
+
### 2. Start the Dev Server
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npm run dev
|
|
26
44
|
```
|
|
27
45
|
|
|
28
|
-
|
|
46
|
+
This starts **two servers** in a single process:
|
|
29
47
|
|
|
30
|
-
|
|
48
|
+
```
|
|
49
|
+
⚡ Clawfire Dev Server
|
|
50
|
+
─────────────────────────────────────
|
|
51
|
+
App : http://localhost:3000
|
|
52
|
+
API : http://localhost:3456/api/...
|
|
53
|
+
Playground : http://localhost:3456
|
|
54
|
+
Pages : ON (app/pages/)
|
|
55
|
+
|
|
56
|
+
Routes (5):
|
|
57
|
+
POST /api/health [public] Health check endpoint
|
|
58
|
+
POST /api/todos/create [public] Create a new todo
|
|
59
|
+
POST /api/todos/delete [public] Delete a todo
|
|
60
|
+
POST /api/todos/list [public] List all todos
|
|
61
|
+
POST /api/todos/update [public] Update a todo
|
|
62
|
+
|
|
63
|
+
Hot Reload : ON
|
|
64
|
+
Watching: app/routes/, app/schemas/, app/pages/, app/components/, public/
|
|
65
|
+
```
|
|
31
66
|
|
|
32
|
-
|
|
33
|
-
// app/schemas/product.ts
|
|
34
|
-
import { defineModel } from "clawfire";
|
|
67
|
+
### 3. Open in Your Browser
|
|
35
68
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
69
|
+
| URL | What You'll See |
|
|
70
|
+
|-----|-----------------|
|
|
71
|
+
| [http://localhost:3000](http://localhost:3000) | Your app (Todo starter) |
|
|
72
|
+
| [http://localhost:3456](http://localhost:3456) | API Playground |
|
|
73
|
+
|
|
74
|
+
### 4. Test the API
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Via the API server directly
|
|
78
|
+
curl -s -X POST http://localhost:3456/api/health \
|
|
79
|
+
-H 'Content-Type: application/json' -d '{}' | jq
|
|
80
|
+
|
|
81
|
+
# Or via the frontend proxy (same result, no CORS issues)
|
|
82
|
+
curl -s -X POST http://localhost:3000/api/todos/create \
|
|
83
|
+
-H 'Content-Type: application/json' \
|
|
84
|
+
-d '{"title":"Learn Clawfire"}' | jq
|
|
50
85
|
```
|
|
51
86
|
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Dev Server Architecture
|
|
90
|
+
|
|
91
|
+
Clawfire runs a **two-port dev server** in a single process:
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
DevServer (single process)
|
|
95
|
+
├─ PageCompiler (compiles app/pages/ + app/components/ → HTML)
|
|
96
|
+
├─ Frontend Server (port 3000)
|
|
97
|
+
│ ├─ Serves compiled pages (app/pages/ → routes)
|
|
98
|
+
│ ├─ Serves public/ directory (static assets)
|
|
99
|
+
│ ├─ Auto-injects HMR script into HTML
|
|
100
|
+
│ ├─ Proxies /api/* → API server (no CORS)
|
|
101
|
+
│ └─ SPA fallback with partial page loading
|
|
102
|
+
│
|
|
103
|
+
└─ API Server (port 3456)
|
|
104
|
+
├─ API routes at /api/*
|
|
105
|
+
├─ Playground UI at /
|
|
106
|
+
└─ SSE for live reload
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Key behaviors:**
|
|
110
|
+
|
|
111
|
+
- **HMR auto-injection** — Every HTML response gets a `<script>` tag injected automatically. You never write SSE code.
|
|
112
|
+
- **CSS hot replace** — Edit a `.css` file in `public/` and see changes instantly without page reload.
|
|
113
|
+
- **API proxy** — Your frontend can call `fetch('/api/todos/list')` — the frontend server proxies it to the API server. No CORS configuration needed.
|
|
114
|
+
- **SPA fallback** — Unknown paths serve `index.html`, supporting client-side routing.
|
|
115
|
+
- **Playground** — Always available at the API server root. Auto-discovers routes, shows auth levels, generates example payloads.
|
|
116
|
+
|
|
117
|
+
### Custom Ports
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
npx clawfire dev --port=4000 --api-port=5000
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Or in `clawfire.config.ts`:
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
dev: {
|
|
127
|
+
port: 4000,
|
|
128
|
+
apiPort: 5000,
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Project Structure
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
my-app/
|
|
138
|
+
app/
|
|
139
|
+
store.ts In-memory data store (works without Firebase)
|
|
140
|
+
pages/ File-based page routing (frontend)
|
|
141
|
+
_layout.html Root layout (wraps all pages via <slot />)
|
|
142
|
+
_404.html 404 error page
|
|
143
|
+
index.html Home page (/)
|
|
144
|
+
about.html /about page
|
|
145
|
+
todos/
|
|
146
|
+
index.html /todos page
|
|
147
|
+
components/ Reusable HTML components
|
|
148
|
+
nav.html <c-nav /> navigation bar
|
|
149
|
+
footer.html <c-footer /> page footer
|
|
150
|
+
routes/ API route handlers (file-based routing)
|
|
151
|
+
health.ts → POST /api/health
|
|
152
|
+
todos/
|
|
153
|
+
list.ts → POST /api/todos/list
|
|
154
|
+
create.ts → POST /api/todos/create
|
|
155
|
+
update.ts → POST /api/todos/update
|
|
156
|
+
delete.ts → POST /api/todos/delete
|
|
157
|
+
schemas/ Firestore model definitions
|
|
158
|
+
todo.ts
|
|
159
|
+
public/ Static assets (CSS, images, fonts)
|
|
160
|
+
generated/ Auto-generated files (DO NOT EDIT)
|
|
161
|
+
api-client.ts Typed API client
|
|
162
|
+
manifest.json API manifest
|
|
163
|
+
functions/
|
|
164
|
+
index.ts Firebase Functions entry point (for deploy)
|
|
165
|
+
dev.ts Dev server entry point
|
|
166
|
+
clawfire.config.ts Configuration
|
|
167
|
+
firebase.json Firebase config
|
|
168
|
+
firestore.rules Firestore security rules
|
|
169
|
+
firestore.indexes.json Firestore indexes
|
|
170
|
+
CLAUDE.md Project guide for Claude AI
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Core Concepts
|
|
176
|
+
|
|
52
177
|
### Define an API
|
|
53
178
|
|
|
54
|
-
|
|
179
|
+
Every API endpoint is a file in `app/routes/` that exports a `defineAPI` contract:
|
|
180
|
+
|
|
181
|
+
```ts
|
|
55
182
|
// app/routes/products/list.ts
|
|
56
183
|
import { defineAPI, z } from "clawfire";
|
|
57
184
|
|
|
@@ -69,20 +196,137 @@ export default defineAPI({
|
|
|
69
196
|
hasMore: z.boolean(),
|
|
70
197
|
}),
|
|
71
198
|
meta: {
|
|
72
|
-
description: "
|
|
199
|
+
description: "List products",
|
|
73
200
|
auth: "public",
|
|
74
201
|
tags: ["products"],
|
|
75
202
|
},
|
|
76
203
|
handler: async (input, ctx) => {
|
|
77
|
-
// Your business logic here
|
|
78
204
|
return { products: [], hasMore: false };
|
|
79
205
|
},
|
|
80
206
|
});
|
|
81
207
|
```
|
|
82
208
|
|
|
83
|
-
|
|
209
|
+
**Rules:**
|
|
210
|
+
- All APIs are **POST only** — no HTTP method routing
|
|
211
|
+
- `input` and `output` must be `z.object({})`
|
|
212
|
+
- `meta.description` is required
|
|
213
|
+
- `handler` must be `async`
|
|
214
|
+
- File path = API path: `app/routes/products/list.ts` → `POST /api/products/list`
|
|
215
|
+
|
|
216
|
+
### Define a Model
|
|
84
217
|
|
|
85
|
-
|
|
218
|
+
Models define Firestore collections and auto-generate security rules:
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
// app/schemas/product.ts
|
|
222
|
+
import { defineModel } from "clawfire";
|
|
223
|
+
|
|
224
|
+
export const Product = defineModel({
|
|
225
|
+
collection: "products",
|
|
226
|
+
fields: {
|
|
227
|
+
name: { type: "string", required: true },
|
|
228
|
+
price: { type: "number", required: true },
|
|
229
|
+
category: { type: "string", enum: ["electronics", "clothing"] },
|
|
230
|
+
},
|
|
231
|
+
timestamps: true,
|
|
232
|
+
rules: {
|
|
233
|
+
read: "public",
|
|
234
|
+
create: "role",
|
|
235
|
+
createRoles: ["admin"],
|
|
236
|
+
update: "authenticated",
|
|
237
|
+
delete: "role",
|
|
238
|
+
deleteRoles: ["admin"],
|
|
239
|
+
ownerField: "userId",
|
|
240
|
+
},
|
|
241
|
+
});
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Error Handling
|
|
245
|
+
|
|
246
|
+
```ts
|
|
247
|
+
import { Errors } from "clawfire";
|
|
248
|
+
|
|
249
|
+
throw Errors.notFound("Product not found"); // 404
|
|
250
|
+
throw Errors.validation("Invalid input", err); // 400
|
|
251
|
+
throw Errors.forbidden("No access"); // 403
|
|
252
|
+
throw Errors.unauthorized("Login required"); // 401
|
|
253
|
+
throw Errors.conflict("Already exists"); // 409
|
|
254
|
+
throw Errors.rateLimited("Too many requests"); // 429
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
**Response format:**
|
|
258
|
+
|
|
259
|
+
```json
|
|
260
|
+
// Success
|
|
261
|
+
{ "data": { "products": [...], "hasMore": false } }
|
|
262
|
+
|
|
263
|
+
// Error
|
|
264
|
+
{ "error": { "code": "NOT_FOUND", "message": "Product not found" } }
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## Auth Levels
|
|
270
|
+
|
|
271
|
+
Every API endpoint declares an auth level in `meta.auth`:
|
|
272
|
+
|
|
273
|
+
| Level | Description | Header Required |
|
|
274
|
+
|-------|-------------|-----------------|
|
|
275
|
+
| `public` | No authentication | None |
|
|
276
|
+
| `authenticated` | Must be logged in | `Authorization: Bearer <token>` |
|
|
277
|
+
| `role` | Specific role required | Bearer token + role match |
|
|
278
|
+
| `reauth` | Recent login required (5 min) | Bearer token + fresh |
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
meta: {
|
|
282
|
+
description: "Delete user account",
|
|
283
|
+
auth: "reauth", // Must have re-authenticated within 5 minutes
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## Configuration
|
|
290
|
+
|
|
291
|
+
All settings in `clawfire.config.ts`:
|
|
292
|
+
|
|
293
|
+
```ts
|
|
294
|
+
import { configureClawfire } from "clawfire";
|
|
295
|
+
|
|
296
|
+
export default configureClawfire({
|
|
297
|
+
firebase: {
|
|
298
|
+
apiKey: "...",
|
|
299
|
+
authDomain: "myapp.firebaseapp.com",
|
|
300
|
+
projectId: "my-project",
|
|
301
|
+
appId: "1:123:web:abc",
|
|
302
|
+
},
|
|
303
|
+
server: {
|
|
304
|
+
region: "us-central1",
|
|
305
|
+
cors: ["https://myapp.web.app"],
|
|
306
|
+
rateLimit: 100,
|
|
307
|
+
},
|
|
308
|
+
security: {
|
|
309
|
+
validateInput: true,
|
|
310
|
+
safeHeaders: true,
|
|
311
|
+
maskLogs: true,
|
|
312
|
+
},
|
|
313
|
+
playground: {
|
|
314
|
+
enabled: true,
|
|
315
|
+
},
|
|
316
|
+
dev: {
|
|
317
|
+
port: 3000, // Frontend server
|
|
318
|
+
apiPort: 3456, // API server + Playground
|
|
319
|
+
},
|
|
320
|
+
});
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## Production Deployment
|
|
326
|
+
|
|
327
|
+
### Firebase Functions Entry Point
|
|
328
|
+
|
|
329
|
+
```ts
|
|
86
330
|
// functions/index.ts
|
|
87
331
|
import * as admin from "firebase-admin";
|
|
88
332
|
import * as functions from "firebase-functions";
|
|
@@ -106,10 +350,10 @@ export const api = functions.https.onRequest((req, res) => {
|
|
|
106
350
|
});
|
|
107
351
|
```
|
|
108
352
|
|
|
109
|
-
### Client
|
|
353
|
+
### Auto-Generated Client
|
|
110
354
|
|
|
111
|
-
```
|
|
112
|
-
//
|
|
355
|
+
```ts
|
|
356
|
+
// In your frontend code
|
|
113
357
|
import { api, configureClient } from "./generated/api-client";
|
|
114
358
|
import { getAuth } from "firebase/auth";
|
|
115
359
|
|
|
@@ -118,64 +362,118 @@ configureClient("https://us-central1-myapp.cloudfunctions.net", async () => {
|
|
|
118
362
|
return user ? user.getIdToken() : null;
|
|
119
363
|
});
|
|
120
364
|
|
|
365
|
+
// Fully typed — autocomplete and compile-time checking
|
|
121
366
|
const result = await api.products.list({ category: "electronics", limit: 10 });
|
|
122
367
|
```
|
|
123
368
|
|
|
124
|
-
|
|
369
|
+
---
|
|
125
370
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
clawfire.config.ts Clawfire configuration
|
|
371
|
+
## CLI Reference
|
|
372
|
+
|
|
373
|
+
```bash
|
|
374
|
+
clawfire init # Initialize a new project (starter template)
|
|
375
|
+
clawfire dev # Start dev server (frontend + API + Playground)
|
|
376
|
+
clawfire dev --port=4000 # Custom frontend port
|
|
377
|
+
clawfire dev --api-port=5000 # Custom API port
|
|
378
|
+
clawfire codegen # Generate route imports
|
|
379
|
+
clawfire playground # Generate standalone playground HTML
|
|
380
|
+
clawfire rules # Info about rules generation
|
|
381
|
+
clawfire help # Show help
|
|
138
382
|
```
|
|
139
383
|
|
|
140
|
-
|
|
384
|
+
---
|
|
141
385
|
|
|
142
|
-
|
|
143
|
-
|---------|-------------|
|
|
144
|
-
| `/clawfire-init` | Initialize project / connect Firebase |
|
|
145
|
-
| `/clawfire-model` | Create/modify data models |
|
|
146
|
-
| `/clawfire-api` | Create/modify APIs |
|
|
147
|
-
| `/clawfire-auth` | Configure authentication |
|
|
148
|
-
| `/clawfire-deploy` | Deploy to Firebase |
|
|
149
|
-
| `/clawfire-diagnose` | Diagnose and fix issues |
|
|
386
|
+
## AI Skills (Claude Code)
|
|
150
387
|
|
|
151
|
-
|
|
388
|
+
When using [Claude Code](https://claude.ai/claude-code), these slash commands are available:
|
|
152
389
|
|
|
153
|
-
|
|
|
154
|
-
|
|
155
|
-
| `
|
|
156
|
-
| `
|
|
157
|
-
| `
|
|
158
|
-
| `
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
|
167
|
-
|
|
168
|
-
| `clawfire
|
|
169
|
-
| `clawfire/
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
390
|
+
| Command | What It Does |
|
|
391
|
+
|---------|-------------|
|
|
392
|
+
| `/clawfire-init` | Initialize project, connect Firebase, set up config |
|
|
393
|
+
| `/clawfire-model` | Create/modify Firestore models → auto-generates rules + indexes |
|
|
394
|
+
| `/clawfire-api` | Create/modify API endpoints → auto-generates typed client |
|
|
395
|
+
| `/clawfire-auth` | Configure auth policies, roles, guards |
|
|
396
|
+
| `/clawfire-deploy` | Deploy to Firebase (explicit request only) |
|
|
397
|
+
| `/clawfire-diagnose` | Detect missing indexes, rule denials, permission issues |
|
|
398
|
+
|
|
399
|
+
---
|
|
400
|
+
|
|
401
|
+
## Package Exports
|
|
402
|
+
|
|
403
|
+
| Import Path | Contents |
|
|
404
|
+
|-------------|----------|
|
|
405
|
+
| `clawfire` | `defineAPI`, `defineModel`, `z`, `Errors`, `configureClawfire`, `ClawfireError` |
|
|
406
|
+
| `clawfire/functions` | `createRouter`, `createAdminDB`, `verifyToken`, `createSecurityMiddleware` |
|
|
407
|
+
| `clawfire/client` | `createClientAuth` |
|
|
408
|
+
| `clawfire/admin` | `generateFirestoreRules`, `generateFirestoreIndexes`, `setUserRole` |
|
|
409
|
+
| `clawfire/codegen` | `generateClientCode`, `discoverRoutes`, `generateRouteImports` |
|
|
410
|
+
| `clawfire/playground` | `generatePlaygroundHtml` |
|
|
411
|
+
| `clawfire/dev` | `DevServer`, `startDevServer`, `FileWatcher`, `PageCompiler` |
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
## Security Defaults
|
|
416
|
+
|
|
417
|
+
All security features are **ON by default**:
|
|
418
|
+
|
|
419
|
+
| Feature | Default | Description |
|
|
420
|
+
|---------|---------|-------------|
|
|
421
|
+
| Input Validation | ON | Zod schema validation on every request |
|
|
422
|
+
| CORS | Deny all | Must explicitly allow origins |
|
|
423
|
+
| Rate Limiting | 100 req/min/IP | Per-endpoint configurable |
|
|
424
|
+
| XSS Sanitization | ON | `<` `>` auto-escaped in string inputs |
|
|
425
|
+
| Safe Headers | ON | `X-Frame-Options`, `X-Content-Type-Options` |
|
|
426
|
+
| Log Masking | ON | `password`, `token`, `secret` fields masked |
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
430
|
+
## Dev vs Production
|
|
431
|
+
|
|
432
|
+
| | Dev Server | Production (Firebase) |
|
|
433
|
+
|--|-----------|----------------------|
|
|
434
|
+
| Frontend | `localhost:3000` (static + HMR) | Firebase Hosting |
|
|
435
|
+
| API | `localhost:3456` | Firebase Functions |
|
|
436
|
+
| Playground | Always on at `:3456` | Configurable |
|
|
437
|
+
| CORS | Allow all (`*`) | Configured origins only |
|
|
438
|
+
| Rate Limiting | Disabled | Enabled |
|
|
439
|
+
| Auth | Optional / mockable | Firebase Auth |
|
|
440
|
+
| Hot Reload | Yes (API + CSS + HTML) | N/A |
|
|
441
|
+
|
|
442
|
+
---
|
|
443
|
+
|
|
444
|
+
## Documentation
|
|
445
|
+
|
|
446
|
+
Full documentation is in the [`docs/`](./docs/) directory:
|
|
447
|
+
|
|
448
|
+
- [Getting Started](./docs/getting-started.md) — 5-minute quickstart
|
|
449
|
+
- [API Routes](./docs/api-routes.md) — `defineAPI`, file-based routing, handlers
|
|
450
|
+
- [Models](./docs/models.md) — `defineModel`, Firestore collections, rules
|
|
451
|
+
- [Dev Server](./docs/dev-server.md) — Two-port architecture, HMR, Playground
|
|
452
|
+
- [Authentication](./docs/authentication.md) — Auth levels, tokens, roles
|
|
453
|
+
- [Security](./docs/security.md) — Middleware, rate limiting, CORS, sanitization
|
|
454
|
+
- [Configuration](./docs/configuration.md) — All config options and defaults
|
|
455
|
+
- [Client Codegen](./docs/client-codegen.md) — Auto-generated typed API client
|
|
456
|
+
- [Deployment](./docs/deployment.md) — Firebase deploy workflow
|
|
457
|
+
- [CLI Reference](./docs/cli-reference.md) — All CLI commands and flags
|
|
458
|
+
- [Architecture](./docs/architecture.md) — How everything fits together
|
|
459
|
+
- [API Reference](./docs/api-reference.md) — Full TypeScript API reference
|
|
460
|
+
|
|
461
|
+
---
|
|
462
|
+
|
|
463
|
+
## Tech Stack
|
|
464
|
+
|
|
465
|
+
| Layer | Technology |
|
|
466
|
+
|-------|-----------|
|
|
467
|
+
| Database | Firestore |
|
|
468
|
+
| Auth | Firebase Auth |
|
|
469
|
+
| Hosting | Firebase Hosting |
|
|
470
|
+
| Backend | Firebase Functions |
|
|
471
|
+
| Schema | Zod |
|
|
472
|
+
| Language | TypeScript |
|
|
473
|
+
|
|
474
|
+
This stack is fixed by design. Clawfire is opinionated — one way to do things, done well.
|
|
475
|
+
|
|
476
|
+
---
|
|
179
477
|
|
|
180
478
|
## License
|
|
181
479
|
|
package/dist/admin.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { e as ModelDefinition } from './schema-BJsictSV.cjs';
|
|
2
2
|
export { f as ModelField, i as ModelIndex, j as ModelRules, h as defineModel, m as modelToZodSchema } from './schema-BJsictSV.cjs';
|
|
3
|
-
import { C as ClawfireConfig } from './config-
|
|
3
|
+
import { C as ClawfireConfig } from './config-D-Chojiu.cjs';
|
|
4
4
|
export { g as getUserRole, s as setCustomClaims, b as setUserRole } from './auth-DQ3cifhb.cjs';
|
|
5
5
|
import 'zod';
|
|
6
6
|
|
package/dist/admin.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { e as ModelDefinition } from './schema-BJsictSV.js';
|
|
2
2
|
export { f as ModelField, i as ModelIndex, j as ModelRules, h as defineModel, m as modelToZodSchema } from './schema-BJsictSV.js';
|
|
3
|
-
import { C as ClawfireConfig } from './config-
|
|
3
|
+
import { C as ClawfireConfig } from './config-D-Chojiu.js';
|
|
4
4
|
export { g as getUserRole, s as setCustomClaims, b as setUserRole } from './auth-DtnUPbXT.js';
|
|
5
5
|
import 'zod';
|
|
6
6
|
|
package/dist/cli.js
CHANGED
|
@@ -26,6 +26,11 @@ function printHelp() {
|
|
|
26
26
|
clawfire rules Generate Firestore security rules
|
|
27
27
|
clawfire help Show this help
|
|
28
28
|
|
|
29
|
+
Dev Server Flags:
|
|
30
|
+
--port=<n> Frontend server port (default: 3000)
|
|
31
|
+
--api-port=<n> API server port (default: 3456)
|
|
32
|
+
--no-hot-reload Disable hot reload
|
|
33
|
+
|
|
29
34
|
Most tasks are done through AI Skills, not CLI.
|
|
30
35
|
Run Claude Code and use /clawfire-* commands instead.
|
|
31
36
|
`);
|
|
@@ -112,6 +117,8 @@ async function initProject() {
|
|
|
112
117
|
const dirs = [
|
|
113
118
|
"app/routes",
|
|
114
119
|
"app/schemas",
|
|
120
|
+
"app/pages",
|
|
121
|
+
"app/components",
|
|
115
122
|
"generated",
|
|
116
123
|
"public",
|
|
117
124
|
"functions"
|
|
@@ -179,23 +186,34 @@ export const api = functions.https.onRequest((req, res) => {
|
|
|
179
186
|
console.log(" Created functions/index.ts");
|
|
180
187
|
}
|
|
181
188
|
console.log("\n \x1B[32m\u2713\x1B[0m Clawfire project initialized!\n");
|
|
189
|
+
console.log(" Project structure:");
|
|
190
|
+
console.log(" \x1B[36mapp/pages/\x1B[0m \u2192 File-based page routing (Tailwind + layouts)");
|
|
191
|
+
console.log(" \x1B[36mapp/components/\x1B[0m \u2192 Reusable HTML components (<c-name />)");
|
|
192
|
+
console.log(" \x1B[36mapp/routes/\x1B[0m \u2192 API endpoints (POST, Zod validation)");
|
|
193
|
+
console.log(" \x1B[36mapp/schemas/\x1B[0m \u2192 Firestore model definitions");
|
|
194
|
+
console.log(" \x1B[36mpublic/\x1B[0m \u2192 Static assets (CSS, images, fonts)");
|
|
195
|
+
console.log("");
|
|
182
196
|
console.log(" Next steps:");
|
|
183
197
|
console.log(" \x1B[36m1.\x1B[0m npm install");
|
|
184
198
|
console.log(" \x1B[36m2.\x1B[0m npm run dev");
|
|
185
|
-
console.log(" \x1B[36m3.\x1B[0m Open \x1B[1mhttp://localhost:
|
|
199
|
+
console.log(" \x1B[36m3.\x1B[0m Open \x1B[1mhttp://localhost:3000\x1B[0m");
|
|
200
|
+
console.log("");
|
|
201
|
+
console.log(" Your app is ready with a Todo demo, page routing, and API playground.");
|
|
186
202
|
console.log("");
|
|
187
|
-
console.log("
|
|
188
|
-
console.log(" Edit files in \x1B[1mapp/routes/\x1B[0m and see changes instantly.\n");
|
|
203
|
+
console.log(" npm: \x1B[4mhttps://www.npmjs.com/package/clawfire\x1B[0m\n");
|
|
189
204
|
}
|
|
190
205
|
async function runDevServer() {
|
|
191
206
|
const projectDir = process.cwd();
|
|
192
207
|
const portArg = args.find((a) => a.startsWith("--port="));
|
|
193
|
-
const
|
|
208
|
+
const apiPortArg = args.find((a) => a.startsWith("--api-port="));
|
|
209
|
+
const port = portArg ? parseInt(portArg.split("=")[1], 10) : 3e3;
|
|
210
|
+
const apiPort = apiPortArg ? parseInt(apiPortArg.split("=")[1], 10) : 3456;
|
|
194
211
|
const noHotReload = args.includes("--no-hot-reload");
|
|
195
|
-
const { startDevServer } = await import("./dev-server-
|
|
212
|
+
const { startDevServer } = await import("./dev-server-ZGXJARNY.js");
|
|
196
213
|
await startDevServer({
|
|
197
214
|
projectDir,
|
|
198
215
|
port,
|
|
216
|
+
apiPort,
|
|
199
217
|
hotReload: !noHotReload
|
|
200
218
|
});
|
|
201
219
|
}
|
|
@@ -39,6 +39,13 @@ interface ClawfireConfig {
|
|
|
39
39
|
/** 경로 */
|
|
40
40
|
path?: string;
|
|
41
41
|
};
|
|
42
|
+
/** 개발 서버 설정 */
|
|
43
|
+
dev?: {
|
|
44
|
+
/** 프론트엔드 서버 포트 (기본: 3000) */
|
|
45
|
+
port?: number;
|
|
46
|
+
/** API 서버 포트 (기본: 3456) */
|
|
47
|
+
apiPort?: number;
|
|
48
|
+
};
|
|
42
49
|
}
|
|
43
50
|
declare function configureClawfire(config: ClawfireConfig): ClawfireConfig;
|
|
44
51
|
declare function getConfig(): ClawfireConfig;
|
|
@@ -39,6 +39,13 @@ interface ClawfireConfig {
|
|
|
39
39
|
/** 경로 */
|
|
40
40
|
path?: string;
|
|
41
41
|
};
|
|
42
|
+
/** 개발 서버 설정 */
|
|
43
|
+
dev?: {
|
|
44
|
+
/** 프론트엔드 서버 포트 (기본: 3000) */
|
|
45
|
+
port?: number;
|
|
46
|
+
/** API 서버 포트 (기본: 3456) */
|
|
47
|
+
apiPort?: number;
|
|
48
|
+
};
|
|
42
49
|
}
|
|
43
50
|
declare function configureClawfire(config: ClawfireConfig): ClawfireConfig;
|
|
44
51
|
declare function getConfig(): ClawfireConfig;
|