@flaredev/cli 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 (97) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +47 -0
  3. package/bin/flare.js +2 -0
  4. package/dist/index.js +3664 -0
  5. package/package.json +56 -0
  6. package/templates/app/.dev.vars.example +13 -0
  7. package/templates/app/README.md +9 -0
  8. package/templates/app/_gitignore +10 -0
  9. package/templates/app/app/admin/actions.ts +113 -0
  10. package/templates/app/app/admin/layout.tsx +32 -0
  11. package/templates/app/app/admin/page.tsx +63 -0
  12. package/templates/app/app/api/auth/[...all]/route.ts +4 -0
  13. package/templates/app/app/api/health/route.ts +7 -0
  14. package/templates/app/app/api/storage/route.ts +6 -0
  15. package/templates/app/app/dashboard/page.tsx +18 -0
  16. package/templates/app/app/globals.css +156 -0
  17. package/templates/app/app/layout.tsx +26 -0
  18. package/templates/app/app/page.tsx +19 -0
  19. package/templates/app/app/sign-in/page.tsx +33 -0
  20. package/templates/app/app/sign-up/page.tsx +23 -0
  21. package/templates/app/components/admin/admin-header.tsx +78 -0
  22. package/templates/app/components/admin/fields/date-field.tsx +112 -0
  23. package/templates/app/components/admin/fields/field-widget.tsx +128 -0
  24. package/templates/app/components/admin/fields/file-field.tsx +302 -0
  25. package/templates/app/components/admin/fields/relation-field.tsx +132 -0
  26. package/templates/app/components/admin/query.ts +25 -0
  27. package/templates/app/components/admin/resource-form-page.tsx +55 -0
  28. package/templates/app/components/admin/resource-form.tsx +139 -0
  29. package/templates/app/components/admin/resource-icon.tsx +85 -0
  30. package/templates/app/components/admin/resource-nav.tsx +109 -0
  31. package/templates/app/components/admin/resource-table-toolbar.tsx +95 -0
  32. package/templates/app/components/admin/resource-table.tsx +251 -0
  33. package/templates/app/components/admin/row-actions.tsx +111 -0
  34. package/templates/app/components/auth-form.tsx +120 -0
  35. package/templates/app/components/sign-out-button.tsx +18 -0
  36. package/templates/app/components/ui/alert-dialog.tsx +196 -0
  37. package/templates/app/components/ui/alert.tsx +65 -0
  38. package/templates/app/components/ui/avatar.tsx +108 -0
  39. package/templates/app/components/ui/badge.tsx +53 -0
  40. package/templates/app/components/ui/breadcrumb.tsx +110 -0
  41. package/templates/app/components/ui/button.tsx +65 -0
  42. package/templates/app/components/ui/calendar.tsx +220 -0
  43. package/templates/app/components/ui/card.tsx +92 -0
  44. package/templates/app/components/ui/command.tsx +184 -0
  45. package/templates/app/components/ui/dialog.tsx +158 -0
  46. package/templates/app/components/ui/dropdown-menu.tsx +256 -0
  47. package/templates/app/components/ui/empty.tsx +103 -0
  48. package/templates/app/components/ui/field.tsx +248 -0
  49. package/templates/app/components/ui/input-group.tsx +170 -0
  50. package/templates/app/components/ui/input.tsx +20 -0
  51. package/templates/app/components/ui/label.tsx +23 -0
  52. package/templates/app/components/ui/pagination.tsx +127 -0
  53. package/templates/app/components/ui/popover.tsx +88 -0
  54. package/templates/app/components/ui/progress.tsx +30 -0
  55. package/templates/app/components/ui/select.tsx +189 -0
  56. package/templates/app/components/ui/separator.tsx +27 -0
  57. package/templates/app/components/ui/sheet.tsx +142 -0
  58. package/templates/app/components/ui/sidebar.tsx +726 -0
  59. package/templates/app/components/ui/skeleton.tsx +13 -0
  60. package/templates/app/components/ui/sonner.tsx +38 -0
  61. package/templates/app/components/ui/spinner.tsx +15 -0
  62. package/templates/app/components/ui/switch.tsx +34 -0
  63. package/templates/app/components/ui/table.tsx +115 -0
  64. package/templates/app/components/ui/textarea.tsx +17 -0
  65. package/templates/app/components/ui/tooltip.tsx +56 -0
  66. package/templates/app/components.json +21 -0
  67. package/templates/app/db/auth-schema.ts +118 -0
  68. package/templates/app/db/flare-schema.ts +15 -0
  69. package/templates/app/db/index.ts +10 -0
  70. package/templates/app/db/schema.ts +12 -0
  71. package/templates/app/drizzle.config.ts +8 -0
  72. package/templates/app/hooks/use-mobile.ts +19 -0
  73. package/templates/app/lib/admin-nav.ts +15 -0
  74. package/templates/app/lib/admin.ts +103 -0
  75. package/templates/app/lib/api.ts +24 -0
  76. package/templates/app/lib/auth-client.ts +4 -0
  77. package/templates/app/lib/auth.ts +44 -0
  78. package/templates/app/lib/cache.ts +83 -0
  79. package/templates/app/lib/mail.ts +36 -0
  80. package/templates/app/lib/realtime.ts +45 -0
  81. package/templates/app/lib/security.ts +13 -0
  82. package/templates/app/lib/session.ts +24 -0
  83. package/templates/app/lib/storage.ts +26 -0
  84. package/templates/app/lib/utils.ts +6 -0
  85. package/templates/app/migrations/0000_init.sql +66 -0
  86. package/templates/app/migrations/meta/0000_snapshot.json +438 -0
  87. package/templates/app/migrations/meta/_journal.json +13 -0
  88. package/templates/app/next.config.ts +5 -0
  89. package/templates/app/policies/index.ts +4 -0
  90. package/templates/app/postcss.config.mjs +7 -0
  91. package/templates/app/proxy.ts +20 -0
  92. package/templates/app/resources/index.ts +4 -0
  93. package/templates/app/resources/server.ts +6 -0
  94. package/templates/app/tsconfig.json +22 -0
  95. package/templates/app/vite.config.ts +27 -0
  96. package/templates/app/worker/index.ts +40 -0
  97. package/templates/app/wrangler.jsonc +52 -0
@@ -0,0 +1,438 @@
1
+ {
2
+ "version": "6",
3
+ "dialect": "sqlite",
4
+ "id": "0d286de4-e9a3-4fb7-a0d3-e3fa1f8ac57f",
5
+ "prevId": "00000000-0000-0000-0000-000000000000",
6
+ "tables": {
7
+ "account": {
8
+ "name": "account",
9
+ "columns": {
10
+ "id": {
11
+ "name": "id",
12
+ "type": "text",
13
+ "primaryKey": true,
14
+ "notNull": true,
15
+ "autoincrement": false
16
+ },
17
+ "account_id": {
18
+ "name": "account_id",
19
+ "type": "text",
20
+ "primaryKey": false,
21
+ "notNull": true,
22
+ "autoincrement": false
23
+ },
24
+ "provider_id": {
25
+ "name": "provider_id",
26
+ "type": "text",
27
+ "primaryKey": false,
28
+ "notNull": true,
29
+ "autoincrement": false
30
+ },
31
+ "user_id": {
32
+ "name": "user_id",
33
+ "type": "text",
34
+ "primaryKey": false,
35
+ "notNull": true,
36
+ "autoincrement": false
37
+ },
38
+ "access_token": {
39
+ "name": "access_token",
40
+ "type": "text",
41
+ "primaryKey": false,
42
+ "notNull": false,
43
+ "autoincrement": false
44
+ },
45
+ "refresh_token": {
46
+ "name": "refresh_token",
47
+ "type": "text",
48
+ "primaryKey": false,
49
+ "notNull": false,
50
+ "autoincrement": false
51
+ },
52
+ "id_token": {
53
+ "name": "id_token",
54
+ "type": "text",
55
+ "primaryKey": false,
56
+ "notNull": false,
57
+ "autoincrement": false
58
+ },
59
+ "access_token_expires_at": {
60
+ "name": "access_token_expires_at",
61
+ "type": "integer",
62
+ "primaryKey": false,
63
+ "notNull": false,
64
+ "autoincrement": false
65
+ },
66
+ "refresh_token_expires_at": {
67
+ "name": "refresh_token_expires_at",
68
+ "type": "integer",
69
+ "primaryKey": false,
70
+ "notNull": false,
71
+ "autoincrement": false
72
+ },
73
+ "scope": {
74
+ "name": "scope",
75
+ "type": "text",
76
+ "primaryKey": false,
77
+ "notNull": false,
78
+ "autoincrement": false
79
+ },
80
+ "password": {
81
+ "name": "password",
82
+ "type": "text",
83
+ "primaryKey": false,
84
+ "notNull": false,
85
+ "autoincrement": false
86
+ },
87
+ "created_at": {
88
+ "name": "created_at",
89
+ "type": "integer",
90
+ "primaryKey": false,
91
+ "notNull": true,
92
+ "autoincrement": false,
93
+ "default": "(cast(unixepoch('subsecond') * 1000 as integer))"
94
+ },
95
+ "updated_at": {
96
+ "name": "updated_at",
97
+ "type": "integer",
98
+ "primaryKey": false,
99
+ "notNull": true,
100
+ "autoincrement": false
101
+ }
102
+ },
103
+ "indexes": {
104
+ "account_userId_idx": {
105
+ "name": "account_userId_idx",
106
+ "columns": [
107
+ "user_id"
108
+ ],
109
+ "isUnique": false
110
+ }
111
+ },
112
+ "foreignKeys": {
113
+ "account_user_id_user_id_fk": {
114
+ "name": "account_user_id_user_id_fk",
115
+ "tableFrom": "account",
116
+ "tableTo": "user",
117
+ "columnsFrom": [
118
+ "user_id"
119
+ ],
120
+ "columnsTo": [
121
+ "id"
122
+ ],
123
+ "onDelete": "cascade",
124
+ "onUpdate": "no action"
125
+ }
126
+ },
127
+ "compositePrimaryKeys": {},
128
+ "uniqueConstraints": {},
129
+ "checkConstraints": {}
130
+ },
131
+ "session": {
132
+ "name": "session",
133
+ "columns": {
134
+ "id": {
135
+ "name": "id",
136
+ "type": "text",
137
+ "primaryKey": true,
138
+ "notNull": true,
139
+ "autoincrement": false
140
+ },
141
+ "expires_at": {
142
+ "name": "expires_at",
143
+ "type": "integer",
144
+ "primaryKey": false,
145
+ "notNull": true,
146
+ "autoincrement": false
147
+ },
148
+ "token": {
149
+ "name": "token",
150
+ "type": "text",
151
+ "primaryKey": false,
152
+ "notNull": true,
153
+ "autoincrement": false
154
+ },
155
+ "created_at": {
156
+ "name": "created_at",
157
+ "type": "integer",
158
+ "primaryKey": false,
159
+ "notNull": true,
160
+ "autoincrement": false,
161
+ "default": "(cast(unixepoch('subsecond') * 1000 as integer))"
162
+ },
163
+ "updated_at": {
164
+ "name": "updated_at",
165
+ "type": "integer",
166
+ "primaryKey": false,
167
+ "notNull": true,
168
+ "autoincrement": false
169
+ },
170
+ "ip_address": {
171
+ "name": "ip_address",
172
+ "type": "text",
173
+ "primaryKey": false,
174
+ "notNull": false,
175
+ "autoincrement": false
176
+ },
177
+ "user_agent": {
178
+ "name": "user_agent",
179
+ "type": "text",
180
+ "primaryKey": false,
181
+ "notNull": false,
182
+ "autoincrement": false
183
+ },
184
+ "user_id": {
185
+ "name": "user_id",
186
+ "type": "text",
187
+ "primaryKey": false,
188
+ "notNull": true,
189
+ "autoincrement": false
190
+ },
191
+ "impersonated_by": {
192
+ "name": "impersonated_by",
193
+ "type": "text",
194
+ "primaryKey": false,
195
+ "notNull": false,
196
+ "autoincrement": false
197
+ }
198
+ },
199
+ "indexes": {
200
+ "session_token_unique": {
201
+ "name": "session_token_unique",
202
+ "columns": [
203
+ "token"
204
+ ],
205
+ "isUnique": true
206
+ },
207
+ "session_userId_idx": {
208
+ "name": "session_userId_idx",
209
+ "columns": [
210
+ "user_id"
211
+ ],
212
+ "isUnique": false
213
+ }
214
+ },
215
+ "foreignKeys": {
216
+ "session_user_id_user_id_fk": {
217
+ "name": "session_user_id_user_id_fk",
218
+ "tableFrom": "session",
219
+ "tableTo": "user",
220
+ "columnsFrom": [
221
+ "user_id"
222
+ ],
223
+ "columnsTo": [
224
+ "id"
225
+ ],
226
+ "onDelete": "cascade",
227
+ "onUpdate": "no action"
228
+ }
229
+ },
230
+ "compositePrimaryKeys": {},
231
+ "uniqueConstraints": {},
232
+ "checkConstraints": {}
233
+ },
234
+ "user": {
235
+ "name": "user",
236
+ "columns": {
237
+ "id": {
238
+ "name": "id",
239
+ "type": "text",
240
+ "primaryKey": true,
241
+ "notNull": true,
242
+ "autoincrement": false
243
+ },
244
+ "name": {
245
+ "name": "name",
246
+ "type": "text",
247
+ "primaryKey": false,
248
+ "notNull": true,
249
+ "autoincrement": false
250
+ },
251
+ "email": {
252
+ "name": "email",
253
+ "type": "text",
254
+ "primaryKey": false,
255
+ "notNull": true,
256
+ "autoincrement": false
257
+ },
258
+ "email_verified": {
259
+ "name": "email_verified",
260
+ "type": "integer",
261
+ "primaryKey": false,
262
+ "notNull": true,
263
+ "autoincrement": false,
264
+ "default": false
265
+ },
266
+ "image": {
267
+ "name": "image",
268
+ "type": "text",
269
+ "primaryKey": false,
270
+ "notNull": false,
271
+ "autoincrement": false
272
+ },
273
+ "created_at": {
274
+ "name": "created_at",
275
+ "type": "integer",
276
+ "primaryKey": false,
277
+ "notNull": true,
278
+ "autoincrement": false,
279
+ "default": "(cast(unixepoch('subsecond') * 1000 as integer))"
280
+ },
281
+ "updated_at": {
282
+ "name": "updated_at",
283
+ "type": "integer",
284
+ "primaryKey": false,
285
+ "notNull": true,
286
+ "autoincrement": false,
287
+ "default": "(cast(unixepoch('subsecond') * 1000 as integer))"
288
+ },
289
+ "role": {
290
+ "name": "role",
291
+ "type": "text",
292
+ "primaryKey": false,
293
+ "notNull": false,
294
+ "autoincrement": false
295
+ },
296
+ "banned": {
297
+ "name": "banned",
298
+ "type": "integer",
299
+ "primaryKey": false,
300
+ "notNull": false,
301
+ "autoincrement": false,
302
+ "default": false
303
+ },
304
+ "ban_reason": {
305
+ "name": "ban_reason",
306
+ "type": "text",
307
+ "primaryKey": false,
308
+ "notNull": false,
309
+ "autoincrement": false
310
+ },
311
+ "ban_expires": {
312
+ "name": "ban_expires",
313
+ "type": "integer",
314
+ "primaryKey": false,
315
+ "notNull": false,
316
+ "autoincrement": false
317
+ }
318
+ },
319
+ "indexes": {
320
+ "user_email_unique": {
321
+ "name": "user_email_unique",
322
+ "columns": [
323
+ "email"
324
+ ],
325
+ "isUnique": true
326
+ }
327
+ },
328
+ "foreignKeys": {},
329
+ "compositePrimaryKeys": {},
330
+ "uniqueConstraints": {},
331
+ "checkConstraints": {}
332
+ },
333
+ "verification": {
334
+ "name": "verification",
335
+ "columns": {
336
+ "id": {
337
+ "name": "id",
338
+ "type": "text",
339
+ "primaryKey": true,
340
+ "notNull": true,
341
+ "autoincrement": false
342
+ },
343
+ "identifier": {
344
+ "name": "identifier",
345
+ "type": "text",
346
+ "primaryKey": false,
347
+ "notNull": true,
348
+ "autoincrement": false
349
+ },
350
+ "value": {
351
+ "name": "value",
352
+ "type": "text",
353
+ "primaryKey": false,
354
+ "notNull": true,
355
+ "autoincrement": false
356
+ },
357
+ "expires_at": {
358
+ "name": "expires_at",
359
+ "type": "integer",
360
+ "primaryKey": false,
361
+ "notNull": true,
362
+ "autoincrement": false
363
+ },
364
+ "created_at": {
365
+ "name": "created_at",
366
+ "type": "integer",
367
+ "primaryKey": false,
368
+ "notNull": true,
369
+ "autoincrement": false,
370
+ "default": "(cast(unixepoch('subsecond') * 1000 as integer))"
371
+ },
372
+ "updated_at": {
373
+ "name": "updated_at",
374
+ "type": "integer",
375
+ "primaryKey": false,
376
+ "notNull": true,
377
+ "autoincrement": false,
378
+ "default": "(cast(unixepoch('subsecond') * 1000 as integer))"
379
+ }
380
+ },
381
+ "indexes": {
382
+ "verification_identifier_idx": {
383
+ "name": "verification_identifier_idx",
384
+ "columns": [
385
+ "identifier"
386
+ ],
387
+ "isUnique": false
388
+ }
389
+ },
390
+ "foreignKeys": {},
391
+ "compositePrimaryKeys": {},
392
+ "uniqueConstraints": {},
393
+ "checkConstraints": {}
394
+ },
395
+ "role": {
396
+ "name": "role",
397
+ "columns": {
398
+ "name": {
399
+ "name": "name",
400
+ "type": "text",
401
+ "primaryKey": true,
402
+ "notNull": true,
403
+ "autoincrement": false
404
+ },
405
+ "label": {
406
+ "name": "label",
407
+ "type": "text",
408
+ "primaryKey": false,
409
+ "notNull": true,
410
+ "autoincrement": false
411
+ },
412
+ "created_at": {
413
+ "name": "created_at",
414
+ "type": "integer",
415
+ "primaryKey": false,
416
+ "notNull": true,
417
+ "autoincrement": false,
418
+ "default": "(cast(unixepoch('subsecond') * 1000 as integer))"
419
+ }
420
+ },
421
+ "indexes": {},
422
+ "foreignKeys": {},
423
+ "compositePrimaryKeys": {},
424
+ "uniqueConstraints": {},
425
+ "checkConstraints": {}
426
+ }
427
+ },
428
+ "views": {},
429
+ "enums": {},
430
+ "_meta": {
431
+ "schemas": {},
432
+ "tables": {},
433
+ "columns": {}
434
+ },
435
+ "internal": {
436
+ "indexes": {}
437
+ }
438
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "version": "7",
3
+ "dialect": "sqlite",
4
+ "entries": [
5
+ {
6
+ "idx": 0,
7
+ "version": "6",
8
+ "when": 1789674564602,
9
+ "tag": "0000_init",
10
+ "breakpoints": true
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,5 @@
1
+ import type { NextConfig } from "next";
2
+
3
+ const nextConfig: NextConfig = {};
4
+
5
+ export default nextConfig;
@@ -0,0 +1,4 @@
1
+ // Registry of every resource policy (maintained by flare gen policy).
2
+ // generated:start
3
+ export const policies = {} as const;
4
+ // generated:end
@@ -0,0 +1,7 @@
1
+ const config = {
2
+ plugins: {
3
+ "@tailwindcss/postcss": {},
4
+ },
5
+ };
6
+
7
+ export default config;
@@ -0,0 +1,20 @@
1
+ import { NextResponse, type NextRequest } from "next/server";
2
+ import { getSessionCookie } from "better-auth/cookies";
3
+
4
+ /**
5
+ * Session middleware: an optimistic, cookie-only check that sends signed-out
6
+ * visitors to /sign-in before rendering. It does not hit the database, so it
7
+ * is NOT an authorization check: protected pages and routes must still call
8
+ * `requireSession()` / `getSession()` from `lib/session.ts`.
9
+ */
10
+ export function proxy(request: NextRequest) {
11
+ if (getSessionCookie(request)) return NextResponse.next();
12
+
13
+ const signIn = new URL("/sign-in", request.url);
14
+ signIn.searchParams.set("next", request.nextUrl.pathname + request.nextUrl.search);
15
+ return NextResponse.redirect(signIn);
16
+ }
17
+
18
+ export const config = {
19
+ matcher: ["/dashboard/:path*"],
20
+ };
@@ -0,0 +1,4 @@
1
+ // Registry of every resource descriptor (maintained by flare gen).
2
+ // generated:start
3
+ export const resources = [] as const;
4
+ // generated:end
@@ -0,0 +1,6 @@
1
+ // Server-only: resource name → descriptor and table (maintained by flare gen).
2
+ // generated:start
3
+ export const resourceTables = {} as const;
4
+
5
+ export type ResourceName = keyof typeof resourceTables;
6
+ // generated:end
@@ -0,0 +1,22 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": false,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "preserve",
15
+ "types": ["vinext/types", "node"],
16
+ "paths": {
17
+ "@/*": ["./*"]
18
+ }
19
+ },
20
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
21
+ "exclude": ["node_modules", "dist"]
22
+ }
@@ -0,0 +1,27 @@
1
+ import { defineConfig } from "vite";
2
+ import vinext from "vinext";
3
+ import { cloudflare } from "@cloudflare/vite-plugin";
4
+ import { kvDataAdapter } from "@vinext/cloudflare/cache/kv-data-adapter";
5
+
6
+ export default defineConfig({
7
+ plugins: [
8
+ vinext({
9
+ cache: {
10
+ // Data cache (`cached()`, fetch, "use cache") in Workers KV, shared by every colo.
11
+ // Entries live a day unless a tag revalidates them first; a colo may reuse its own
12
+ // copy for a minute after a write elsewhere.
13
+ data: kvDataAdapter({ ttlSeconds: 86_400, entryCacheTtlSeconds: 60 }),
14
+ // No `cdn` adapter yet. vinext's Workers Cache adapter (cdnAdapter) is experimental
15
+ // in the 1.0 beta: behind it, any page that redirects fails with "Too many
16
+ // redirects", and nothing is cached without an experimental two-stage deploy.
17
+ // See "Caching" in the Flare docs before turning it on.
18
+ },
19
+ }),
20
+ cloudflare({
21
+ viteEnvironment: {
22
+ name: "rsc",
23
+ childEnvironments: ["ssr"],
24
+ },
25
+ }),
26
+ ],
27
+ });
@@ -0,0 +1,40 @@
1
+ import app from "vinext/server/app-router-entry";
2
+ import { RealtimeChannel, handleRealtimeUpgrade } from "@flaredev/core/realtime/server";
3
+ import { SecurityMonitor } from "@flaredev/core/security/server";
4
+ import { authorizeRealtime } from "../lib/realtime";
5
+ import { protect } from "../lib/security";
6
+
7
+ // `DurableObjectNamespace` and `ExecutionContext` are ambient globals injected
8
+ // by the generated worker-configuration.d.ts (wrangler types), not exports of
9
+ // the `cloudflare:workers` module.
10
+
11
+ // Durable Object classes must be exported from the Worker's main module.
12
+ export { RealtimeChannel, SecurityMonitor };
13
+
14
+ export interface AppEnv {
15
+ ASSETS: Fetcher;
16
+ DB: D1Database;
17
+ FLARE_REALTIME: DurableObjectNamespace<RealtimeChannel>;
18
+ }
19
+
20
+ export interface AppContext {
21
+ waitUntil: (promise: Promise<unknown>) => void;
22
+ }
23
+
24
+ /**
25
+ * Custom entrypoint. Every request passes lib/security.ts first (bans, rate
26
+ * limits, abuse detection; a pass-through until `flare gen security`), then the
27
+ * realtime upgrade seam, then the vinext app.
28
+ */
29
+ export default {
30
+ async fetch(request: Request, env: AppEnv, ctx: AppContext): Promise<Response> {
31
+ return protect(request, env, ctx, async () => {
32
+ if (new URL(request.url).pathname.startsWith("/realtime/")) {
33
+ // Who may join which channel lives in lib/realtime.ts (authorizeRealtime).
34
+ const realtime = await handleRealtimeUpgrade(request, env.FLARE_REALTIME, { authorize: authorizeRealtime });
35
+ if (realtime) return realtime;
36
+ }
37
+ return app.fetch(request, env, ctx);
38
+ });
39
+ },
40
+ };
@@ -0,0 +1,52 @@
1
+ {
2
+ "$schema": "node_modules/wrangler/config-schema.json",
3
+ "name": "__APP_NAME__",
4
+ "compatibility_date": "__COMPAT_DATE__",
5
+ "compatibility_flags": ["nodejs_compat"],
6
+ "main": "./worker/index.ts",
7
+ "assets": {
8
+ "directory": "dist/client",
9
+ "not_found_handling": "none",
10
+ "binding": "ASSETS"
11
+ },
12
+ "durable_objects": {
13
+ "bindings": [
14
+ {
15
+ // Realtime channels (see lib/realtime.ts). Each channel is one Durable
16
+ // Object instance created on demand; wrangler provisions nothing upfront.
17
+ "name": "FLARE_REALTIME",
18
+ "class_name": "RealtimeChannel"
19
+ }
20
+ ]
21
+ },
22
+ "migrations": [
23
+ {
24
+ "tag": "v1",
25
+ "new_sqlite_classes": ["RealtimeChannel"]
26
+ }
27
+ ],
28
+ "d1_databases": [
29
+ {
30
+ // No database_id: wrangler creates the database on first deploy and
31
+ // uses a local SQLite file during development.
32
+ "binding": "DB",
33
+ "database_name": "__APP_NAME__-db",
34
+ "migrations_dir": "migrations"
35
+ }
36
+ ],
37
+ "kv_namespaces": [
38
+ {
39
+ // Data cache (see `cache.data` in vite.config.ts). No id: wrangler creates
40
+ // the namespace on first deploy; locally it's simulated on disk.
41
+ "binding": "VINEXT_KV_CACHE"
42
+ }
43
+ ],
44
+ "r2_buckets": [
45
+ {
46
+ // Simulated locally. No bucket needs creating first: wrangler provisions
47
+ // missing resources on deploy.
48
+ "binding": "STORAGE",
49
+ "bucket_name": "__APP_NAME__-storage"
50
+ }
51
+ ]
52
+ }