flingit 0.0.14 → 0.0.18
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 +2 -1
- package/dist/cli/commands/cron.d.ts +29 -0
- package/dist/cli/commands/cron.d.ts.map +1 -1
- package/dist/cli/commands/cron.js +54 -37
- package/dist/cli/commands/cron.js.map +1 -1
- package/dist/cli/commands/db.d.ts.map +1 -1
- package/dist/cli/commands/db.js +15 -19
- package/dist/cli/commands/db.js.map +1 -1
- package/dist/cli/commands/dev.d.ts +1 -0
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/dev.js +344 -86
- package/dist/cli/commands/dev.js.map +1 -1
- package/dist/cli/commands/feedback.js +3 -3
- package/dist/cli/commands/feedback.js.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +9 -2
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/launch.d.ts +45 -3
- package/dist/cli/commands/launch.d.ts.map +1 -1
- package/dist/cli/commands/launch.js +39 -17
- package/dist/cli/commands/launch.js.map +1 -1
- package/dist/cli/commands/logout.d.ts +18 -0
- package/dist/cli/commands/logout.d.ts.map +1 -1
- package/dist/cli/commands/logout.js +40 -14
- package/dist/cli/commands/logout.js.map +1 -1
- package/dist/cli/commands/logs.d.ts +3 -2
- package/dist/cli/commands/logs.d.ts.map +1 -1
- package/dist/cli/commands/logs.js +26 -43
- package/dist/cli/commands/logs.js.map +1 -1
- package/dist/cli/commands/onboard.d.ts.map +1 -1
- package/dist/cli/commands/onboard.js +3 -3
- package/dist/cli/commands/onboard.js.map +1 -1
- package/dist/cli/commands/project.d.ts.map +1 -1
- package/dist/cli/commands/project.js +44 -23
- package/dist/cli/commands/project.js.map +1 -1
- package/dist/cli/commands/push.d.ts.map +1 -1
- package/dist/cli/commands/push.js +6 -4
- package/dist/cli/commands/push.js.map +1 -1
- package/dist/cli/commands/register.d.ts +37 -0
- package/dist/cli/commands/register.d.ts.map +1 -1
- package/dist/cli/commands/register.js +96 -74
- package/dist/cli/commands/register.js.map +1 -1
- package/dist/cli/commands/tunnel.js +2 -2
- package/dist/cli/commands/tunnel.js.map +1 -1
- package/dist/cli/commands/whoami.d.ts +18 -0
- package/dist/cli/commands/whoami.d.ts.map +1 -1
- package/dist/cli/commands/whoami.js +54 -28
- package/dist/cli/commands/whoami.js.map +1 -1
- package/dist/cli/index.js +10 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/utils/cli-io-impl.d.ts +33 -2
- package/dist/cli/utils/cli-io-impl.d.ts.map +1 -1
- package/dist/cli/utils/cli-io-impl.js +99 -14
- package/dist/cli/utils/cli-io-impl.js.map +1 -1
- package/dist/cli/utils/cli-io.d.ts +27 -9
- package/dist/cli/utils/cli-io.d.ts.map +1 -1
- package/dist/cli/utils/config.d.ts.map +1 -1
- package/dist/cli/utils/config.js +2 -2
- package/dist/cli/utils/config.js.map +1 -1
- package/dist/cli/utils/db-adapter.d.ts +59 -0
- package/dist/cli/utils/db-adapter.d.ts.map +1 -0
- package/dist/cli/utils/db-adapter.js +74 -0
- package/dist/cli/utils/db-adapter.js.map +1 -0
- package/dist/cli/utils/email.d.ts +15 -0
- package/dist/cli/utils/email.d.ts.map +1 -0
- package/dist/cli/utils/email.js +31 -0
- package/dist/cli/utils/email.js.map +1 -0
- package/dist/cli/utils/project-name.d.ts +10 -2
- package/dist/cli/utils/project-name.d.ts.map +1 -1
- package/dist/cli/utils/project-name.js +12 -6
- package/dist/cli/utils/project-name.js.map +1 -1
- package/dist/cli/utils/project.d.ts +17 -6
- package/dist/cli/utils/project.d.ts.map +1 -1
- package/dist/cli/utils/project.js +30 -36
- package/dist/cli/utils/project.js.map +1 -1
- package/dist/cli/utils/registry.d.ts +8 -6
- package/dist/cli/utils/registry.d.ts.map +1 -1
- package/dist/cli/utils/registry.js +32 -30
- package/dist/cli/utils/registry.js.map +1 -1
- package/dist/shared/constants.d.ts +16 -3
- package/dist/shared/constants.d.ts.map +1 -1
- package/dist/shared/constants.js +16 -3
- package/dist/shared/constants.js.map +1 -1
- package/dist/worker-runtime/discord.js +1 -1
- package/dist/worker-runtime/discord.js.map +1 -1
- package/dist/worker-runtime/index.d.ts +2 -1
- package/dist/worker-runtime/index.d.ts.map +1 -1
- package/dist/worker-runtime/index.js +19 -6
- package/dist/worker-runtime/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/default/.claude/settings.local.json +1 -0
- package/templates/default/CLAUDE.md +2 -314
- package/templates/default/skills/fling/.hash +1 -1
- package/templates/default/skills/fling/API.md +45 -4
- package/templates/default/skills/fling/SKILL.md +92 -1
- package/dist/cli/commands/admin.d.ts +0 -8
- package/dist/cli/commands/admin.d.ts.map +0 -1
- package/dist/cli/commands/admin.js +0 -244
- package/dist/cli/commands/admin.js.map +0 -1
- package/dist/cli/commands/dev-worker.d.ts +0 -12
- package/dist/cli/commands/dev-worker.d.ts.map +0 -1
- package/dist/cli/commands/dev-worker.js +0 -66
- package/dist/cli/commands/dev-worker.js.map +0 -1
- package/dist/cli/commands/tun.d.ts +0 -13
- package/dist/cli/commands/tun.d.ts.map +0 -1
- package/dist/cli/commands/tun.js +0 -189
- package/dist/cli/commands/tun.js.map +0 -1
- package/dist/cli/utils/launch-io-impl.d.ts +0 -13
- package/dist/cli/utils/launch-io-impl.d.ts.map +0 -1
- package/dist/cli/utils/launch-io-impl.js +0 -51
- package/dist/cli/utils/launch-io-impl.js.map +0 -1
- package/dist/cli/utils/launch-io.d.ts +0 -42
- package/dist/cli/utils/launch-io.d.ts.map +0 -1
- package/dist/cli/utils/launch-io.js +0 -8
- package/dist/cli/utils/launch-io.js.map +0 -1
- package/dist/cli/utils/onboarding-io-impl.d.ts +0 -12
- package/dist/cli/utils/onboarding-io-impl.d.ts.map +0 -1
- package/dist/cli/utils/onboarding-io-impl.js +0 -85
- package/dist/cli/utils/onboarding-io-impl.js.map +0 -1
- package/dist/cli/utils/onboarding-io.d.ts +0 -60
- package/dist/cli/utils/onboarding-io.d.ts.map +0 -1
- package/dist/cli/utils/onboarding-io.js +0 -9
- package/dist/cli/utils/onboarding-io.js.map +0 -1
- package/dist/client/assets/index-BqVrS7t9.js +0 -40
- package/dist/client/assets/index-DSLUsCtO.css +0 -1
- package/dist/client/index.html +0 -14
- package/dist/client/vite.svg +0 -1
|
@@ -1,317 +1,5 @@
|
|
|
1
1
|
# Fling Project
|
|
2
2
|
|
|
3
|
-
This is a Fling project - a personal software platform for building and deploying personal tools with a React frontend
|
|
3
|
+
This is a Fling project - a personal software platform for building and deploying personal tools with a React frontend, API backend, SQL database, storage, and more.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Fling handles all of this automatically. When the user asks you to build something:
|
|
8
|
-
1. Write backend code in `src/worker/index.ts` using the Fling API
|
|
9
|
-
2. Write frontend code in `src/react-app/` using React
|
|
10
|
-
3. Run `npm start` to test it locally (you have bash access - run commands yourself!)
|
|
11
|
-
4. When it works, run `npm exec fling push` to deploy
|
|
12
|
-
|
|
13
|
-
**IMPORTANT: Run CLI commands yourself.** You have bash access. Do NOT ask the user to run commands like `fling push`, `fling dev`, or `npm start`. Execute them directly and report the results.
|
|
14
|
-
|
|
15
|
-
## Project Structure
|
|
16
|
-
|
|
17
|
-
```
|
|
18
|
-
src/
|
|
19
|
-
worker/
|
|
20
|
-
index.ts # Backend API entry point (routes, migrations)
|
|
21
|
-
react-app/
|
|
22
|
-
main.tsx # React entry point
|
|
23
|
-
App.tsx # Main React component
|
|
24
|
-
App.css # Component styles
|
|
25
|
-
index.css # Global styles
|
|
26
|
-
public/ # Static assets (served by Vite)
|
|
27
|
-
index.html # Vite entry HTML
|
|
28
|
-
vite.config.ts # Vite configuration
|
|
29
|
-
.fling/secrets # Local secrets (gitignored)
|
|
30
|
-
.fling/data/ # SQLite database (gitignored)
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## Development
|
|
34
|
-
|
|
35
|
-
Run `npm start` (or `fling dev`) to start development:
|
|
36
|
-
- **Frontend**: http://localhost:5173 (Vite with React HMR)
|
|
37
|
-
- **API**: http://localhost:3210 (Hono backend)
|
|
38
|
-
- Vite proxies `/api/*` requests to the API server
|
|
39
|
-
|
|
40
|
-
### Hot Module Replacement (HMR)
|
|
41
|
-
|
|
42
|
-
The dev server provides hot reloading for both frontend AND backend - no restart needed:
|
|
43
|
-
- **Frontend (React)**: Changes to `src/react-app/` are instantly reflected via Vite HMR
|
|
44
|
-
- **Backend (Worker)**: Changes to `src/worker/` are automatically reloaded via tsx watch
|
|
45
|
-
|
|
46
|
-
Just edit and save - changes appear immediately.
|
|
47
|
-
|
|
48
|
-
## Fling API (Backend)
|
|
49
|
-
|
|
50
|
-
All primitives are imported from `"flingit"` in the backend:
|
|
51
|
-
|
|
52
|
-
```typescript
|
|
53
|
-
import { app, db, migrate, secrets, cron, storage } from "flingit";
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### HTTP Routes (Hono)
|
|
57
|
-
|
|
58
|
-
```typescript
|
|
59
|
-
// API routes should use /api prefix for Vite proxy
|
|
60
|
-
app.get("/api/hello", (c) => c.json({ message: "Hello!" }));
|
|
61
|
-
app.post("/api/data", async (c) => {
|
|
62
|
-
const body = await c.req.json();
|
|
63
|
-
return c.json({ received: body });
|
|
64
|
-
});
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
**Note:** Paths starting with `/__` are reserved for internal platform use. Do not create routes with these prefixes.
|
|
68
|
-
|
|
69
|
-
### Migrations
|
|
70
|
-
|
|
71
|
-
**IMPORTANT: Migrations MUST be idempotent** (safe to run multiple times).
|
|
72
|
-
|
|
73
|
-
```typescript
|
|
74
|
-
migrate("001_create_users", async () => {
|
|
75
|
-
await db.prepare(`
|
|
76
|
-
CREATE TABLE IF NOT EXISTS users (
|
|
77
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
78
|
-
name TEXT NOT NULL,
|
|
79
|
-
created_at TEXT DEFAULT (datetime('now'))
|
|
80
|
-
)
|
|
81
|
-
`).run();
|
|
82
|
-
});
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### Database (SQLite, D1-compatible)
|
|
86
|
-
|
|
87
|
-
```typescript
|
|
88
|
-
// Query
|
|
89
|
-
const item = await db.prepare("SELECT * FROM items WHERE id = ?").bind(id).first();
|
|
90
|
-
const all = await db.prepare("SELECT * FROM items").all();
|
|
91
|
-
|
|
92
|
-
// Insert/Update/Delete
|
|
93
|
-
await db.prepare("INSERT INTO items (name) VALUES (?)").bind(name).run();
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
### Secrets
|
|
97
|
-
|
|
98
|
-
```typescript
|
|
99
|
-
const apiKey = secrets.get("API_KEY"); // Throws if not set
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
### Cron Jobs
|
|
103
|
-
|
|
104
|
-
Schedule tasks to run automatically on a schedule using standard cron syntax:
|
|
105
|
-
|
|
106
|
-
```typescript
|
|
107
|
-
cron("daily-cleanup", "0 3 * * *", async () => {
|
|
108
|
-
// Runs at 3 AM daily
|
|
109
|
-
await db.prepare("DELETE FROM old_logs WHERE created_at < ?")
|
|
110
|
-
.bind(Date.now() - 86400000).run();
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
cron("hourly-report", "0 * * * *", async () => {
|
|
114
|
-
// Runs every hour - can return a result that's stored in history
|
|
115
|
-
const count = await processRecords();
|
|
116
|
-
return { processed: count };
|
|
117
|
-
});
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
Cron expressions: `minute hour day-of-month month day-of-week`
|
|
121
|
-
- `"0 9 * * *"` - 9 AM daily
|
|
122
|
-
- `"*/15 * * * *"` - Every 15 minutes
|
|
123
|
-
- `"0 0 * * 1"` - Midnight on Mondays
|
|
124
|
-
|
|
125
|
-
Manage cron jobs with CLI:
|
|
126
|
-
```bash
|
|
127
|
-
npm exec fling cron list # List all cron jobs
|
|
128
|
-
npm exec fling cron history <name> # View invocation history
|
|
129
|
-
npm exec fling cron trigger <name> # Manually trigger a job
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
### Storage (R2)
|
|
133
|
-
|
|
134
|
-
Store and retrieve files. Uses local filesystem in development, Cloudflare R2 in production.
|
|
135
|
-
|
|
136
|
-
```typescript
|
|
137
|
-
import { storage } from "flingit";
|
|
138
|
-
|
|
139
|
-
// Store objects
|
|
140
|
-
await storage.put("images/logo.png", imageBuffer, { contentType: "image/png" });
|
|
141
|
-
await storage.put("data/config.json", JSON.stringify(config));
|
|
142
|
-
|
|
143
|
-
// Retrieve objects
|
|
144
|
-
const file = await storage.get("images/logo.png");
|
|
145
|
-
if (file) {
|
|
146
|
-
const buffer = await file.arrayBuffer();
|
|
147
|
-
const text = await file.text();
|
|
148
|
-
const json = await file.json<ConfigType>();
|
|
149
|
-
// Or stream: file.body (ReadableStream)
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// Check existence without downloading
|
|
153
|
-
const meta = await storage.head("images/logo.png");
|
|
154
|
-
|
|
155
|
-
// Delete objects
|
|
156
|
-
await storage.delete("old-file.txt");
|
|
157
|
-
await storage.delete(["file1.txt", "file2.txt"]); // Batch delete
|
|
158
|
-
|
|
159
|
-
// List objects
|
|
160
|
-
const result = await storage.list({ prefix: "images/", limit: 100 });
|
|
161
|
-
for (const obj of result.objects) {
|
|
162
|
-
console.log(`${obj.key}: ${obj.size} bytes`);
|
|
163
|
-
}
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
Manage storage with CLI:
|
|
167
|
-
```bash
|
|
168
|
-
npm exec fling storage list # List local storage objects
|
|
169
|
-
npm exec fling storage put key file.txt # Upload file to storage
|
|
170
|
-
npm exec fling storage get key output # Download object to file
|
|
171
|
-
npm exec fling storage delete key --yes # Delete object
|
|
172
|
-
npm exec fling storage info # Show storage stats
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
## React Frontend
|
|
176
|
-
|
|
177
|
-
The frontend is a standard React + Vite setup. Call the backend API:
|
|
178
|
-
|
|
179
|
-
```typescript
|
|
180
|
-
// In React components
|
|
181
|
-
useEffect(() => {
|
|
182
|
-
fetch("/api/hello")
|
|
183
|
-
.then(res => res.json())
|
|
184
|
-
.then(data => setMessage(data.message));
|
|
185
|
-
}, []);
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
## CLI Commands
|
|
189
|
-
|
|
190
|
-
Always use `npm exec` to run the project's Fling:
|
|
191
|
-
|
|
192
|
-
```bash
|
|
193
|
-
npm exec fling dev # Start local dev server (API + Vite)
|
|
194
|
-
npm exec fling dev -- --port 8080 # Custom API port
|
|
195
|
-
npm exec fling db sql "SELECT * FROM users" # Query local SQLite
|
|
196
|
-
npm exec fling db reset # Wipe local database
|
|
197
|
-
npm exec fling db sql "SELECT * FROM users" # Query local SQLite
|
|
198
|
-
npm exec fling secret set K=V # Set local secret
|
|
199
|
-
npm exec fling secret list # List local secrets
|
|
200
|
-
npm exec fling logs # View local logs
|
|
201
|
-
npm exec fling storage list # List storage objects
|
|
202
|
-
npm exec fling storage put K F # Upload file F as key K
|
|
203
|
-
npm exec fling storage get K O # Download key K to file O
|
|
204
|
-
npm exec fling push # Build and deploy to production
|
|
205
|
-
npm exec fling tunnel 3000 # Expose localhost:3000 via public URL
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
### Local vs Production (`--prod`)
|
|
209
|
-
|
|
210
|
-
Most CLI commands operate on the **local** environment by default. Add `--prod` for production:
|
|
211
|
-
|
|
212
|
-
```bash
|
|
213
|
-
# Local (default)
|
|
214
|
-
npm exec fling secret list # Local secrets
|
|
215
|
-
npm exec fling logs # Local logs
|
|
216
|
-
npm exec fling db sql "SELECT 1" # Local SQLite
|
|
217
|
-
npm exec fling storage list # Local storage
|
|
218
|
-
|
|
219
|
-
# Production (requires login)
|
|
220
|
-
npm exec fling -- --prod logs # Deployed logs
|
|
221
|
-
npm exec fling -- --prod db sql "SELECT 1" # Deployed D1
|
|
222
|
-
npm exec fling -- --prod storage list # R2 storage
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
**Note:** Production logs have a delay of ~10 seconds or more before they appear.
|
|
226
|
-
|
|
227
|
-
**Secrets:** Always stored locally in `.fling/secrets`. Use `fling push` to deploy secrets to production along with your code.
|
|
228
|
-
|
|
229
|
-
## Deployment
|
|
230
|
-
|
|
231
|
-
`fling push` handles everything automatically:
|
|
232
|
-
|
|
233
|
-
1. Builds React frontend with Vite → `dist/client/`
|
|
234
|
-
2. Uploads static assets (HTML, JS, CSS, images, fonts)
|
|
235
|
-
3. Bundles backend code with esbuild
|
|
236
|
-
4. Deploys to Cloudflare Workers
|
|
237
|
-
|
|
238
|
-
**Limits:** 25MB per file, 100MB total assets.
|
|
239
|
-
|
|
240
|
-
**Routing in production:**
|
|
241
|
-
- `/api/*` → Backend worker code
|
|
242
|
-
- Everything else → Static assets from `dist/client/`
|
|
243
|
-
- SPA fallback: Unknown paths serve `index.html`
|
|
244
|
-
|
|
245
|
-
## Platform Limitations
|
|
246
|
-
|
|
247
|
-
Be aware of these constraints when building:
|
|
248
|
-
|
|
249
|
-
### Feature Scope
|
|
250
|
-
- **Supported:** Frontend (React), backend (Hono API), database (SQLite/D1), cron jobs, file storage (R2), Discord integration
|
|
251
|
-
- **Not yet supported:** Websockets
|
|
252
|
-
- If the user needs unsupported features, encourage them to send feedback via `npm exec fling feedback`
|
|
253
|
-
|
|
254
|
-
### Backend Memory (128MB limit)
|
|
255
|
-
- The backend runs in a Cloudflare Worker with ~128MB memory
|
|
256
|
-
- Cannot process large datasets in memory all at once
|
|
257
|
-
- For large data: use streaming, pagination, or chunked processing
|
|
258
|
-
- Example: process files line-by-line instead of loading entirely into memory
|
|
259
|
-
|
|
260
|
-
### Cloudflare Workers Runtime
|
|
261
|
-
- Workers do NOT have the full Node.js API
|
|
262
|
-
- Some npm packages won't work (those requiring `fs`, `path`, `child_process`, native modules)
|
|
263
|
-
- Must use Workers-compatible packages (check package docs for "Cloudflare Workers" or "edge runtime" support)
|
|
264
|
-
- Web standard APIs work fine (fetch, crypto.subtle, TextEncoder, etc.)
|
|
265
|
-
|
|
266
|
-
### Backend Assets (Images, Fonts, etc.)
|
|
267
|
-
|
|
268
|
-
If the backend needs to return or process an asset (image, icon, font), keep it small and store the base64 data in a separate file to keep your main code clean:
|
|
269
|
-
|
|
270
|
-
```typescript
|
|
271
|
-
// src/worker/assets/favicon.ts - separate file for the asset
|
|
272
|
-
export const FAVICON_BASE64 = "iVBORw0KGgo..."; // base64-encoded PNG
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
```typescript
|
|
276
|
-
// src/worker/index.ts - import and use the asset
|
|
277
|
-
import { FAVICON_BASE64 } from "./assets/favicon";
|
|
278
|
-
|
|
279
|
-
app.get("/favicon.ico", (c) => {
|
|
280
|
-
const buffer = Uint8Array.from(atob(FAVICON_BASE64), c => c.charCodeAt(0));
|
|
281
|
-
return new Response(buffer, {
|
|
282
|
-
headers: { "Content-Type": "image/x-icon" }
|
|
283
|
-
});
|
|
284
|
-
});
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
This approach:
|
|
288
|
-
- Keeps the main code readable (no long base64 strings inline)
|
|
289
|
-
- Makes assets easy to find and update
|
|
290
|
-
- Base64 keeps assets bundled with the code (required for Workers)
|
|
291
|
-
|
|
292
|
-
**For large assets:** Serve them from the frontend (`public/` folder) instead.
|
|
293
|
-
|
|
294
|
-
**If the user's request might hit these limitations, warn them early and suggest alternatives.**
|
|
295
|
-
|
|
296
|
-
## Key Points
|
|
297
|
-
|
|
298
|
-
- **Don't ask about hosting** - Fling handles deployment
|
|
299
|
-
- **Don't ask about databases** - Use `db` from fling
|
|
300
|
-
- **Don't suggest external services** - Fling provides what you need
|
|
301
|
-
- **Use /api prefix** - For Vite proxy to work in development
|
|
302
|
-
- **Run commands yourself** - You have bash access, don't ask the user to run CLI commands
|
|
303
|
-
|
|
304
|
-
## After First Deployment
|
|
305
|
-
|
|
306
|
-
After your first `fling push`, consider asking the user if they want a custom URL.
|
|
307
|
-
Their project was auto-assigned a slug like `proj-abc123`.
|
|
308
|
-
|
|
309
|
-
To change it: `npm exec fling project slug:set my-custom-slug`
|
|
310
|
-
|
|
311
|
-
Slugs must be:
|
|
312
|
-
- More than 4 characters
|
|
313
|
-
- Lowercase alphanumeric with optional hyphens
|
|
314
|
-
- Globally unique across all Fling projects
|
|
315
|
-
|
|
316
|
-
See `.claude/skills/fling/` for detailed API documentation.
|
|
317
|
-
See `.claude/skills/discord/` for Discord chatops integration (slash commands, messages, interactions).
|
|
5
|
+
Read the `fling` skill in detail!
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
48c43a6cab25d1a064e710509399ca76
|
|
@@ -190,7 +190,7 @@ migrate("004_normalize_emails", async () => {
|
|
|
190
190
|
|
|
191
191
|
- Migrations MUST be declared at module top-level (not inside functions)
|
|
192
192
|
- Each migration must have a unique name
|
|
193
|
-
-
|
|
193
|
+
- `db.exec()` doesn't return results, so it is not suitable for `SELECT` queries.
|
|
194
194
|
- Tables starting with `_` are reserved for the system (`_migrations`, `_fling_logs`)
|
|
195
195
|
- Do NOT perform database operations at module top-level outside of migrations
|
|
196
196
|
- The `_migrations` table is created automatically on first migration
|
|
@@ -263,6 +263,20 @@ await db.prepare("DELETE FROM users WHERE id = ?")
|
|
|
263
263
|
.run();
|
|
264
264
|
```
|
|
265
265
|
|
|
266
|
+
### Batch
|
|
267
|
+
|
|
268
|
+
Execute multiple statements atomically:
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
const results = await db.batch([
|
|
272
|
+
db.prepare("INSERT INTO users (name) VALUES (?)").bind("Alice"),
|
|
273
|
+
db.prepare("INSERT INTO users (name) VALUES (?)").bind("Bob"),
|
|
274
|
+
]);
|
|
275
|
+
// Returns: [{ success: true, meta: ... }, { success: true, meta: ... }]
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
This is also faster than executing statements individually.
|
|
279
|
+
|
|
266
280
|
### Schema (DDL)
|
|
267
281
|
|
|
268
282
|
Schema changes should be done in migrations (see Migrations section above):
|
|
@@ -284,8 +298,6 @@ migrate("001_create_users", async () => {
|
|
|
284
298
|
});
|
|
285
299
|
```
|
|
286
300
|
|
|
287
|
-
**Important**: Always use `db.prepare(...).run()` for DDL statements. The `db.exec()` method does not work in production D1 databases.
|
|
288
|
-
|
|
289
301
|
### Important Notes
|
|
290
302
|
|
|
291
303
|
- Schema changes should be done in migrations (see Migrations section)
|
|
@@ -333,6 +345,36 @@ Secret names must be uppercase with underscores:
|
|
|
333
345
|
- `apiKey` ✗
|
|
334
346
|
- `github-token` ✗
|
|
335
347
|
|
|
348
|
+
## Cron Jobs
|
|
349
|
+
|
|
350
|
+
Schedule tasks to run automatically on a schedule using standard cron syntax:
|
|
351
|
+
|
|
352
|
+
```typescript
|
|
353
|
+
cron("daily-cleanup", "0 3 * * *", async () => {
|
|
354
|
+
// Runs at 3 AM daily
|
|
355
|
+
await db.prepare("DELETE FROM old_logs WHERE created_at < ?")
|
|
356
|
+
.bind(Date.now() - 86400000).run();
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
cron("hourly-report", "0 * * * *", async () => {
|
|
360
|
+
// Runs every hour - can return a result that's stored in history
|
|
361
|
+
const count = await processRecords();
|
|
362
|
+
return { processed: count };
|
|
363
|
+
});
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
Cron expressions: `minute hour day-of-month month day-of-week`
|
|
367
|
+
- `"0 9 * * *"` - 9 AM daily
|
|
368
|
+
- `"*/15 * * * *"` - Every 15 minutes
|
|
369
|
+
- `"0 0 * * 1"` - Midnight on Mondays
|
|
370
|
+
|
|
371
|
+
Manage cron jobs with CLI:
|
|
372
|
+
```bash
|
|
373
|
+
npm exec fling cron list # List all cron jobs
|
|
374
|
+
npm exec fling cron history <name> # View invocation history
|
|
375
|
+
npm exec fling cron trigger <name> # Manually trigger a job
|
|
376
|
+
```
|
|
377
|
+
|
|
336
378
|
## Storage (R2)
|
|
337
379
|
|
|
338
380
|
Object storage for files and binary data. Uses local filesystem in development, Cloudflare R2 in production.
|
|
@@ -618,4 +660,3 @@ app.get("/api/compute", async (c) => {
|
|
|
618
660
|
- **Cloudflare blocks dynamic WASM compilation** - You cannot use `WebAssembly.instantiate(bytes)` with raw bytes fetched at runtime. WASM must be imported statically so Cloudflare can pre-compile it at deploy time.
|
|
619
661
|
- **Initialize once** - WASM initialization is expensive. Cache the instance and reuse it across requests.
|
|
620
662
|
- **Bundle size** - WASM modules count toward the 10MB bundle limit. Large WASM files may require optimization.
|
|
621
|
-
|
|
@@ -7,6 +7,25 @@ description: Building and deploying this app easily to the internet
|
|
|
7
7
|
|
|
8
8
|
You are working on a Fling project - a personal software platform for building and deploying personal tools with a React frontend and Hono API backend.
|
|
9
9
|
|
|
10
|
+
## IMPORTANT: Do NOT ask about deployment, hosting, or technology choices!
|
|
11
|
+
|
|
12
|
+
Fling handles all of this automatically. When the user asks you to build something:
|
|
13
|
+
1. Write backend code in `src/worker/index.ts` using the Fling API
|
|
14
|
+
2. Write frontend code in `src/react-app/` using React
|
|
15
|
+
3. Run `npm start` to test it locally (you have bash access - run commands yourself!)
|
|
16
|
+
4. When it works, run `npm exec fling push` to deploy
|
|
17
|
+
|
|
18
|
+
## When to Send Feedback
|
|
19
|
+
|
|
20
|
+
Fling can send feedback to its authors. Read FEEDBACK.md for details.
|
|
21
|
+
|
|
22
|
+
Proactively offer to send feedback in these situations:
|
|
23
|
+
|
|
24
|
+
1. **User frustration** - When the user expresses frustration with Fling
|
|
25
|
+
2. **Product limitations** - When Fling can't do something the user needs
|
|
26
|
+
3. **After difficulties** - When you've helped resolve a confusing issue
|
|
27
|
+
4. **Feature requests** - When the user wishes Fling could do something differently
|
|
28
|
+
|
|
10
29
|
## Core Concepts
|
|
11
30
|
|
|
12
31
|
Fling provides seven primitives that work identically in local development and production:
|
|
@@ -181,11 +200,33 @@ Run `npm start` (or `fling dev`) to start development:
|
|
|
181
200
|
- **API**: http://localhost:3210 (Hono backend)
|
|
182
201
|
- Vite proxies `/api/*` requests to the API server
|
|
183
202
|
|
|
203
|
+
### Hot Module Replacement (HMR)
|
|
204
|
+
|
|
205
|
+
The dev server provides hot reloading for both frontend AND backend - no restart needed:
|
|
206
|
+
- **Frontend (React)**: Changes to `src/react-app/` are instantly reflected via Vite HMR
|
|
207
|
+
- **Backend (Worker)**: Changes to `src/worker/` are automatically reloaded via tsx watch
|
|
208
|
+
|
|
209
|
+
Just edit and save - changes appear immediately.
|
|
210
|
+
|
|
184
211
|
## Deployment
|
|
185
212
|
|
|
186
|
-
When the user's request is complete and working locally, deploy it
|
|
213
|
+
When the user's request is complete and working locally, offer to deploy it. But if their app has a backend and no secure authorization method, you must make it clear to them that the deployed app will be visible on the internet, and that they should not expose anything that should not be publicly visible!
|
|
214
|
+
|
|
215
|
+
To deploy:
|
|
187
216
|
**Run `npm exec fling push` directly** - you have bash access, don't ask the user to run commands.
|
|
188
217
|
|
|
218
|
+
### After First Deployment
|
|
219
|
+
|
|
220
|
+
After your first `fling push`, consider asking the user if they want a custom URL.
|
|
221
|
+
Their project was auto-assigned a slug like `proj-abc123`.
|
|
222
|
+
|
|
223
|
+
To change it: `npm exec fling project slug:set my-custom-slug`
|
|
224
|
+
|
|
225
|
+
Slugs must be:
|
|
226
|
+
- More than 4 characters
|
|
227
|
+
- Lowercase alphanumeric with optional hyphens
|
|
228
|
+
- Globally unique across all Fling projects
|
|
229
|
+
|
|
189
230
|
### What `fling push` does:
|
|
190
231
|
|
|
191
232
|
1. **Builds frontend** - Runs `vite build`, outputs to `dist/client/`
|
|
@@ -193,6 +234,8 @@ When the user's request is complete and working locally, deploy it:
|
|
|
193
234
|
3. **Bundles backend** - Compiles `src/worker/index.ts` with esbuild
|
|
194
235
|
4. **Deploys to Cloudflare** - Both frontend and backend go live
|
|
195
236
|
|
|
237
|
+
**Secrets:** Always stored locally in `.fling/secrets`. Use `fling push` to deploy secrets to production along with your code.
|
|
238
|
+
|
|
196
239
|
### Static Asset Limits
|
|
197
240
|
|
|
198
241
|
- **25MB** per file maximum
|
|
@@ -245,4 +288,52 @@ This gives collaborators:
|
|
|
245
288
|
|
|
246
289
|
**If the user's request might hit platform limitations, warn them early and suggest alternatives.**
|
|
247
290
|
|
|
291
|
+
## Migrations
|
|
292
|
+
|
|
293
|
+
**IMPORTANT: Migrations MUST be idempotent** (safe to run multiple times).
|
|
294
|
+
|
|
295
|
+
Use the `migrate` helper for schema changes:
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
import { migrate, db } from "flingit";
|
|
299
|
+
|
|
300
|
+
migrate("001_create_users", async () => {
|
|
301
|
+
await db.prepare(`
|
|
302
|
+
CREATE TABLE IF NOT EXISTS users (
|
|
303
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
304
|
+
name TEXT NOT NULL,
|
|
305
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
306
|
+
)
|
|
307
|
+
`).run();
|
|
308
|
+
});
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
## Backend Assets (Images, Fonts, etc.)
|
|
312
|
+
|
|
313
|
+
If the backend needs to return or process an asset (image, icon, font), keep it small and store the base64 data in a separate file to keep your main code clean:
|
|
314
|
+
|
|
315
|
+
```typescript
|
|
316
|
+
// src/worker/assets/favicon.ts - separate file for the asset
|
|
317
|
+
export const FAVICON_BASE64 = "iVBORw0KGgo..."; // base64-encoded PNG
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
// src/worker/index.ts - import and use the asset
|
|
322
|
+
import { FAVICON_BASE64 } from "./assets/favicon";
|
|
323
|
+
|
|
324
|
+
app.get("/favicon.ico", (c) => {
|
|
325
|
+
const buffer = Uint8Array.from(atob(FAVICON_BASE64), c => c.charCodeAt(0));
|
|
326
|
+
return new Response(buffer, {
|
|
327
|
+
headers: { "Content-Type": "image/x-icon" }
|
|
328
|
+
});
|
|
329
|
+
});
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
This approach:
|
|
333
|
+
- Keeps the main code readable (no long base64 strings inline)
|
|
334
|
+
- Makes assets easy to find and update
|
|
335
|
+
- Base64 keeps assets bundled with the code (required for Workers)
|
|
336
|
+
|
|
337
|
+
**For large assets:** Serve them from the frontend (`public/` folder) instead.
|
|
338
|
+
|
|
248
339
|
See API.md for detailed API reference, EXAMPLES.md for common patterns, and FEEDBACK.md for collecting user feedback.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/admin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmKpC,eAAO,MAAM,YAAY,SAWtB,CAAC"}
|