clawfire 0.1.0

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.
Files changed (87) hide show
  1. package/README.md +182 -0
  2. package/dist/admin.cjs +309 -0
  3. package/dist/admin.cjs.map +1 -0
  4. package/dist/admin.d.cts +93 -0
  5. package/dist/admin.d.ts +93 -0
  6. package/dist/admin.js +274 -0
  7. package/dist/admin.js.map +1 -0
  8. package/dist/auth-DQ3cifhb.d.cts +55 -0
  9. package/dist/auth-DtnUPbXT.d.ts +55 -0
  10. package/dist/chunk-37Y2XI7X.js +75 -0
  11. package/dist/chunk-YGIPORYL.js +339 -0
  12. package/dist/cli.js +241 -0
  13. package/dist/client.cjs +97 -0
  14. package/dist/client.cjs.map +1 -0
  15. package/dist/client.d.cts +4 -0
  16. package/dist/client.d.ts +4 -0
  17. package/dist/client.js +68 -0
  18. package/dist/client.js.map +1 -0
  19. package/dist/codegen.cjs +648 -0
  20. package/dist/codegen.cjs.map +1 -0
  21. package/dist/codegen.d.cts +25 -0
  22. package/dist/codegen.d.ts +25 -0
  23. package/dist/codegen.js +617 -0
  24. package/dist/codegen.js.map +1 -0
  25. package/dist/config-QMBJRn9G.d.cts +46 -0
  26. package/dist/config-QMBJRn9G.d.ts +46 -0
  27. package/dist/dev-server-QAVWINAT.js +973 -0
  28. package/dist/dev.cjs +1388 -0
  29. package/dist/dev.cjs.map +1 -0
  30. package/dist/dev.d.cts +111 -0
  31. package/dist/dev.d.ts +111 -0
  32. package/dist/dev.js +1349 -0
  33. package/dist/dev.js.map +1 -0
  34. package/dist/discover-BPMAZFBD.js +9 -0
  35. package/dist/discover-DYNqz_ym.d.cts +28 -0
  36. package/dist/discover-DYNqz_ym.d.ts +28 -0
  37. package/dist/errors-s_mP7rs9.d.cts +33 -0
  38. package/dist/errors-s_mP7rs9.d.ts +33 -0
  39. package/dist/functions.cjs +1156 -0
  40. package/dist/functions.cjs.map +1 -0
  41. package/dist/functions.d.cts +115 -0
  42. package/dist/functions.d.ts +115 -0
  43. package/dist/functions.js +1108 -0
  44. package/dist/functions.js.map +1 -0
  45. package/dist/hosting-7WVFHAYJ.js +85 -0
  46. package/dist/html-PCUCJGBH.js +7 -0
  47. package/dist/index.cjs +349 -0
  48. package/dist/index.cjs.map +1 -0
  49. package/dist/index.d.cts +22 -0
  50. package/dist/index.d.ts +22 -0
  51. package/dist/index.js +312 -0
  52. package/dist/index.js.map +1 -0
  53. package/dist/playground.cjs +364 -0
  54. package/dist/playground.cjs.map +1 -0
  55. package/dist/playground.d.cts +12 -0
  56. package/dist/playground.d.ts +12 -0
  57. package/dist/playground.js +337 -0
  58. package/dist/playground.js.map +1 -0
  59. package/dist/router-BVB_I-tu.d.ts +65 -0
  60. package/dist/router-Cikk8Heq.d.cts +65 -0
  61. package/dist/schema-BJsictSV.d.cts +172 -0
  62. package/dist/schema-BJsictSV.d.ts +172 -0
  63. package/package.json +150 -0
  64. package/templates/CLAUDE.md +71 -0
  65. package/templates/app/routes/auth/login.ts +35 -0
  66. package/templates/app/routes/health.ts +20 -0
  67. package/templates/app/schemas/user.ts +26 -0
  68. package/templates/clawfire.config.ts +25 -0
  69. package/templates/functions/index.ts +43 -0
  70. package/templates/starter/.claude/skills/clawfire-api/SKILL.md +131 -0
  71. package/templates/starter/.claude/skills/clawfire-auth/SKILL.md +111 -0
  72. package/templates/starter/.claude/skills/clawfire-deploy/SKILL.md +95 -0
  73. package/templates/starter/.claude/skills/clawfire-diagnose/SKILL.md +99 -0
  74. package/templates/starter/.claude/skills/clawfire-model/SKILL.md +128 -0
  75. package/templates/starter/CLAUDE.md +227 -0
  76. package/templates/starter/app/routes/health.ts +20 -0
  77. package/templates/starter/app/routes/todos/create.ts +25 -0
  78. package/templates/starter/app/routes/todos/delete.ts +20 -0
  79. package/templates/starter/app/routes/todos/list.ts +26 -0
  80. package/templates/starter/app/routes/todos/update.ts +32 -0
  81. package/templates/starter/app/schemas/todo.ts +16 -0
  82. package/templates/starter/app/store.ts +56 -0
  83. package/templates/starter/clawfire.config.ts +25 -0
  84. package/templates/starter/dev.ts +12 -0
  85. package/templates/starter/package.json +19 -0
  86. package/templates/starter/public/index.html +365 -0
  87. package/templates/starter/tsconfig.json +17 -0
@@ -0,0 +1,227 @@
1
+ # Clawfire Project
2
+
3
+ This is a **Clawfire** project — an AI-First Firebase app framework.
4
+ **"Speak. Build. Deploy."**
5
+
6
+ 사용자가 자연어로 요청하면 Claude가 자율적으로 API, 모델, 인증, 배포를 수행합니다.
7
+
8
+ ---
9
+
10
+ ## Stack (Fixed — do not change)
11
+
12
+ | Layer | Technology |
13
+ |-------|-----------|
14
+ | DB | Firestore |
15
+ | Auth | Firebase Auth |
16
+ | Hosting | Firebase Hosting |
17
+ | Backend | Firebase Functions |
18
+ | Schema | Zod |
19
+ | Language | TypeScript |
20
+ | Framework | clawfire |
21
+
22
+ **이 스택은 고정입니다. 다른 DB, 다른 프레임워크를 제안하지 마세요.**
23
+
24
+ ---
25
+
26
+ ## Project Structure
27
+
28
+ ```
29
+ app/
30
+ store.ts ← 인메모리 데이터 저장소 (Firebase 없이 동작)
31
+ routes/ ← API 라우트 핸들러 (파일 기반 라우팅)
32
+ health.ts ← 서버 상태 확인
33
+ todos/ ← Todo CRUD
34
+ list.ts
35
+ create.ts
36
+ update.ts
37
+ delete.ts
38
+ schemas/ ← Firestore 모델 정의
39
+ todo.ts
40
+ public/
41
+ index.html ← 프론트엔드 (바닐라 JS, 빌드 불필요)
42
+ generated/ ← 자동 생성 파일 (DO NOT EDIT)
43
+ functions/
44
+ index.ts ← Firebase Functions 진입점 (배포용)
45
+ dev.ts ← Dev 서버 진입점
46
+ clawfire.config.ts ← Clawfire 설정
47
+ firebase.json ← Firebase 설정
48
+ firestore.rules ← Firestore 보안 규칙
49
+ firestore.indexes.json ← Firestore 인덱스
50
+ ```
51
+
52
+ ---
53
+
54
+ ## Commands
55
+
56
+ ```bash
57
+ npm run dev # 개발 서버 시작 (http://localhost:3456)
58
+ npm run build # TypeScript 체크
59
+ npm run deploy # Firebase 배포
60
+ ```
61
+
62
+ ---
63
+
64
+ ## AI Skills (slash commands)
65
+
66
+ | Command | Description |
67
+ |---------|-------------|
68
+ | `/clawfire-api` | API 생성/수정 → 라우트 + 클라이언트 자동 생성 |
69
+ | `/clawfire-model` | 모델 생성/수정 → Rules + 인덱스 자동 생성 |
70
+ | `/clawfire-auth` | 인증 정책 설정 → Guards 자동 반영 |
71
+ | `/clawfire-deploy` | Firebase 배포 (명시적 요청 필요) |
72
+ | `/clawfire-diagnose` | 문제 탐지 및 수정 제안 |
73
+
74
+ ---
75
+
76
+ ## Core Pattern: defineAPI
77
+
78
+ 모든 API는 이 패턴을 따릅니다:
79
+
80
+ ```ts
81
+ import { defineAPI, z } from "clawfire";
82
+
83
+ export default defineAPI({
84
+ input: z.object({ ... }), // Zod 입력 스키마
85
+ output: z.object({ ... }), // Zod 출력 스키마
86
+ meta: {
87
+ description: "...", // 필수 — AI/Playground가 읽음
88
+ auth: "public", // "public" | "authenticated" | "role" | "reauth"
89
+ tags: ["..."], // 그룹화용
90
+ },
91
+ handler: async (input, ctx) => { // 비즈니스 로직
92
+ return { ... };
93
+ },
94
+ });
95
+ ```
96
+
97
+ **절대 규칙:**
98
+ - 모든 API는 **POST만** 사용
99
+ - `input`과 `output`은 반드시 `z.object({})`
100
+ - `meta.description`은 필수
101
+ - `handler`는 반드시 `async`
102
+ - import는 `from "clawfire"` (NOT `"clawfire"`)
103
+
104
+ ---
105
+
106
+ ## Core Pattern: defineModel
107
+
108
+ ```ts
109
+ import { defineModel } from "clawfire";
110
+
111
+ export const Todo = defineModel({
112
+ collection: "todos",
113
+ fields: {
114
+ title: { type: "string", required: true },
115
+ completed: { type: "boolean", required: true },
116
+ },
117
+ timestamps: true,
118
+ rules: {
119
+ read: "public",
120
+ create: "authenticated",
121
+ update: "authenticated",
122
+ delete: "role",
123
+ deleteRoles: ["admin"],
124
+ ownerField: "userId",
125
+ },
126
+ });
127
+ ```
128
+
129
+ ---
130
+
131
+ ## File-Based Routing
132
+
133
+ 파일 경로 = API 경로:
134
+
135
+ ```
136
+ app/routes/health.ts → POST /api/health
137
+ app/routes/todos/list.ts → POST /api/todos/list
138
+ app/routes/products/[id]/get.ts → POST /api/products/:id/get
139
+ ```
140
+
141
+ ---
142
+
143
+ ## Error Handling
144
+
145
+ ```ts
146
+ import { Errors } from "clawfire";
147
+
148
+ throw Errors.notFound("Not found"); // 404
149
+ throw Errors.validation("Bad input", err); // 400
150
+ throw Errors.forbidden("No access"); // 403
151
+ throw Errors.unauthorized("Login required");// 401
152
+ throw Errors.conflict("Already exists"); // 409
153
+ ```
154
+
155
+ ---
156
+
157
+ ## Response Format
158
+
159
+ 성공: `{ "data": { ... } }`
160
+ 실패: `{ "error": { "code": "NOT_FOUND", "message": "..." } }`
161
+
162
+ ---
163
+
164
+ ## Auth Levels
165
+
166
+ | Level | 의미 | Header |
167
+ |-------|------|--------|
168
+ | `public` | 인증 불필요 | 없음 |
169
+ | `authenticated` | 로그인 필수 | `Authorization: Bearer <token>` |
170
+ | `role` | 특정 역할 필요 | Bearer + role 매칭 |
171
+ | `reauth` | 최근 인증 필요 (5분) | Bearer + 최신 토큰 |
172
+
173
+ ---
174
+
175
+ ## Adding a New Resource (Step-by-Step)
176
+
177
+ 사용자가 "상품 API 만들어줘"라고 하면:
178
+
179
+ ### Step 1: Store 추가 (인메모리 모드)
180
+
181
+ `app/store.ts`에 새 Map + CRUD 메서드 추가.
182
+
183
+ ### Step 2: Schema 생성
184
+
185
+ `app/schemas/product.ts` 생성 → `defineModel(...)`.
186
+
187
+ ### Step 3: Routes 생성
188
+
189
+ ```
190
+ app/routes/products/
191
+ list.ts ← 목록 조회
192
+ create.ts ← 생성
193
+ update.ts ← 수정
194
+ delete.ts ← 삭제
195
+ ```
196
+
197
+ 각 파일에 `defineAPI(...)` with 적절한 input/output/handler.
198
+
199
+ ### Step 4: Dev 서버 확인
200
+
201
+ `npm run dev` → 라우트 자동 발견, 핫 리로드.
202
+
203
+ ### Step 5: Frontend 업데이트
204
+
205
+ `public/index.html`에 UI 추가하거나, 사용자에게 별도 프론트엔드 구현 안내.
206
+
207
+ ---
208
+
209
+ ## Security Defaults (변경하지 마세요)
210
+
211
+ - Input validation: **ON** (Zod 스키마 자동 검증)
212
+ - CORS: **Deny all** (dev에서만 허용)
213
+ - Rate limit: **100 req/min/IP**
214
+ - XSS sanitization: **ON** (`<` `>` 자동 이스케이프)
215
+ - Safe headers: **ON** (X-Frame-Options, X-Content-Type-Options)
216
+ - Log masking: **ON** (password, token 등 자동 마스킹)
217
+
218
+ ---
219
+
220
+ ## Important: What NOT to do
221
+
222
+ - HTTP method routing 사용 금지 (GET, PUT, DELETE 등) — 모든 것은 POST
223
+ - Express, Fastify 등 다른 프레임워크 사용 금지
224
+ - `from "clawfire"` import 금지 — 반드시 `from "clawfire"`
225
+ - `generated/` 폴더 내 파일 직접 수정 금지
226
+ - Firestore 보안 규칙을 수동으로 작성하지 마세요 — `/clawfire-model` 사용
227
+ - 불필요한 보안 규칙 완화 금지 (최소 권한 원칙)
@@ -0,0 +1,20 @@
1
+ import { defineAPI, z } from "clawfire";
2
+
3
+ export default defineAPI({
4
+ input: z.object({}),
5
+ output: z.object({
6
+ status: z.string(),
7
+ timestamp: z.string(),
8
+ version: z.string(),
9
+ }),
10
+ meta: {
11
+ description: "Health check endpoint",
12
+ auth: "public",
13
+ tags: ["system"],
14
+ },
15
+ handler: async () => ({
16
+ status: "ok",
17
+ timestamp: new Date().toISOString(),
18
+ version: "1.0.0",
19
+ }),
20
+ });
@@ -0,0 +1,25 @@
1
+ import { defineAPI, z } from "clawfire";
2
+ import { todoStore } from "../../store.js";
3
+
4
+ export default defineAPI({
5
+ input: z.object({
6
+ title: z.string().min(1).max(200),
7
+ }),
8
+ output: z.object({
9
+ todo: z.object({
10
+ id: z.string(),
11
+ title: z.string(),
12
+ completed: z.boolean(),
13
+ createdAt: z.string(),
14
+ }),
15
+ }),
16
+ meta: {
17
+ description: "Create a new todo",
18
+ auth: "public",
19
+ tags: ["todos"],
20
+ },
21
+ handler: async (input) => {
22
+ const todo = todoStore.create(input.title);
23
+ return { todo };
24
+ },
25
+ });
@@ -0,0 +1,20 @@
1
+ import { defineAPI, z } from "clawfire";
2
+ import { todoStore } from "../../store.js";
3
+
4
+ export default defineAPI({
5
+ input: z.object({
6
+ id: z.string(),
7
+ }),
8
+ output: z.object({
9
+ success: z.boolean(),
10
+ }),
11
+ meta: {
12
+ description: "Delete a todo",
13
+ auth: "public",
14
+ tags: ["todos"],
15
+ },
16
+ handler: async (input) => {
17
+ const success = todoStore.delete(input.id);
18
+ return { success };
19
+ },
20
+ });
@@ -0,0 +1,26 @@
1
+ import { defineAPI, z } from "clawfire";
2
+ import { todoStore } from "../../store.js";
3
+
4
+ export default defineAPI({
5
+ input: z.object({}),
6
+ output: z.object({
7
+ todos: z.array(
8
+ z.object({
9
+ id: z.string(),
10
+ title: z.string(),
11
+ completed: z.boolean(),
12
+ createdAt: z.string(),
13
+ }),
14
+ ),
15
+ count: z.number(),
16
+ }),
17
+ meta: {
18
+ description: "List all todos",
19
+ auth: "public",
20
+ tags: ["todos"],
21
+ },
22
+ handler: async () => {
23
+ const todos = todoStore.list();
24
+ return { todos, count: todos.length };
25
+ },
26
+ });
@@ -0,0 +1,32 @@
1
+ import { defineAPI, z } from "clawfire";
2
+ import { todoStore } from "../../store.js";
3
+
4
+ export default defineAPI({
5
+ input: z.object({
6
+ id: z.string(),
7
+ title: z.string().min(1).max(200).optional(),
8
+ completed: z.boolean().optional(),
9
+ }),
10
+ output: z.object({
11
+ todo: z
12
+ .object({
13
+ id: z.string(),
14
+ title: z.string(),
15
+ completed: z.boolean(),
16
+ createdAt: z.string(),
17
+ })
18
+ .nullable(),
19
+ }),
20
+ meta: {
21
+ description: "Update a todo (toggle complete, edit title)",
22
+ auth: "public",
23
+ tags: ["todos"],
24
+ },
25
+ handler: async (input) => {
26
+ const todo = todoStore.update(input.id, {
27
+ title: input.title,
28
+ completed: input.completed,
29
+ });
30
+ return { todo };
31
+ },
32
+ });
@@ -0,0 +1,16 @@
1
+ import { defineModel } from "clawfire";
2
+
3
+ export const Todo = defineModel({
4
+ collection: "todos",
5
+ fields: {
6
+ title: { type: "string", required: true, description: "Todo title" },
7
+ completed: { type: "boolean", required: true, description: "Completion status" },
8
+ },
9
+ timestamps: true,
10
+ rules: {
11
+ read: "public",
12
+ create: "public",
13
+ update: "public",
14
+ delete: "public",
15
+ },
16
+ });
@@ -0,0 +1,56 @@
1
+ /**
2
+ * In-memory Todo Store
3
+ *
4
+ * Firebase 없이 동작하는 간단한 인메모리 저장소.
5
+ * 나중에 Firestore로 교체할 수 있습니다.
6
+ */
7
+
8
+ export interface Todo {
9
+ id: string;
10
+ title: string;
11
+ completed: boolean;
12
+ createdAt: string;
13
+ }
14
+
15
+ const todos: Map<string, Todo> = new Map();
16
+ let idCounter = 0;
17
+
18
+ function generateId(): string {
19
+ return `todo_${++idCounter}_${Date.now()}`;
20
+ }
21
+
22
+ export const todoStore = {
23
+ list(): Todo[] {
24
+ return Array.from(todos.values()).sort(
25
+ (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),
26
+ );
27
+ },
28
+
29
+ get(id: string): Todo | undefined {
30
+ return todos.get(id);
31
+ },
32
+
33
+ create(title: string): Todo {
34
+ const todo: Todo = {
35
+ id: generateId(),
36
+ title,
37
+ completed: false,
38
+ createdAt: new Date().toISOString(),
39
+ };
40
+ todos.set(todo.id, todo);
41
+ return todo;
42
+ },
43
+
44
+ update(id: string, data: Partial<Pick<Todo, "title" | "completed">>): Todo | null {
45
+ const todo = todos.get(id);
46
+ if (!todo) return null;
47
+ if (data.title !== undefined) todo.title = data.title;
48
+ if (data.completed !== undefined) todo.completed = data.completed;
49
+ todos.set(id, todo);
50
+ return todo;
51
+ },
52
+
53
+ delete(id: string): boolean {
54
+ return todos.delete(id);
55
+ },
56
+ };
@@ -0,0 +1,25 @@
1
+ import { configureClawfire } from "clawfire";
2
+
3
+ export default configureClawfire({
4
+ firebase: {
5
+ apiKey: "YOUR_API_KEY",
6
+ authDomain: "YOUR_PROJECT.firebaseapp.com",
7
+ projectId: "YOUR_PROJECT_ID",
8
+ storageBucket: "YOUR_PROJECT.firebasestorage.app",
9
+ appId: "YOUR_APP_ID",
10
+ },
11
+ server: {
12
+ region: "us-central1",
13
+ cors: [],
14
+ rateLimit: 100,
15
+ },
16
+ security: {
17
+ validateInput: true,
18
+ safeHeaders: true,
19
+ maskLogs: true,
20
+ },
21
+ playground: {
22
+ enabled: true,
23
+ path: "/__playground",
24
+ },
25
+ });
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Clawfire Dev Server Entry Point
3
+ *
4
+ * Usage: npx tsx dev.ts
5
+ * Or: npm run dev
6
+ */
7
+ import { startDevServer } from "clawfire/dev";
8
+
9
+ startDevServer({
10
+ port: 3456,
11
+ hotReload: true,
12
+ });
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "my-clawfire-app",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "npx tsx dev.ts",
8
+ "build": "tsc --noEmit",
9
+ "deploy": "npx clawfire deploy"
10
+ },
11
+ "dependencies": {
12
+ "clawfire": "latest"
13
+ },
14
+ "devDependencies": {
15
+ "tsx": "^4.0.0",
16
+ "typescript": "^5.5.0",
17
+ "@types/node": "^20.0.0"
18
+ }
19
+ }