@thunder-stack/create-thunder-app 0.0.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.
Files changed (69) hide show
  1. package/index.js +229 -0
  2. package/package.json +26 -0
  3. package/postpublish.js +14 -0
  4. package/prepublish.js +68 -0
  5. package/template/.env.example +13 -0
  6. package/template/README.md +1 -0
  7. package/template/THUNDER_STACK.md +120 -0
  8. package/template/client/assets/logo.svg +36 -0
  9. package/template/client/expo/App.test.tsx +20 -0
  10. package/template/client/expo/App.tsx +16 -0
  11. package/template/client/expo/app.json +30 -0
  12. package/template/client/expo/babel.config.js +12 -0
  13. package/template/client/expo/global.css +3 -0
  14. package/template/client/expo/jest.config.js +7 -0
  15. package/template/client/expo/metro.config.js +21 -0
  16. package/template/client/expo/package.json +33 -0
  17. package/template/client/expo/tsconfig.json +6 -0
  18. package/template/client/next/app/globals.css +14 -0
  19. package/template/client/next/app/layout.tsx +28 -0
  20. package/template/client/next/app/page.test.tsx +13 -0
  21. package/template/client/next/app/page.tsx +10 -0
  22. package/template/client/next/next-env.d.ts +5 -0
  23. package/template/client/next/next.config.js +21 -0
  24. package/template/client/next/package.json +39 -0
  25. package/template/client/next/playwright.config.ts +17 -0
  26. package/template/client/next/postcss.config.js +6 -0
  27. package/template/client/next/tsconfig.json +30 -0
  28. package/template/client/next/vitest.config.ts +11 -0
  29. package/template/client/next/vitest.setup.ts +1 -0
  30. package/template/client/shared/index.ts +2 -0
  31. package/template/client/shared/package.json +24 -0
  32. package/template/client/shared/src/components/Button.tsx +38 -0
  33. package/template/client/shared/src/components/Card.tsx +17 -0
  34. package/template/client/shared/src/features/auth/login.tsx +139 -0
  35. package/template/client/shared/src/features/dashboard/index.tsx +232 -0
  36. package/template/client/shared/src/features/home/screen.tsx +212 -0
  37. package/template/client/shared/src/features/management/roles.tsx +356 -0
  38. package/template/client/shared/src/features/management/users.tsx +245 -0
  39. package/template/client/shared/src/nativewind-env.d.ts +1 -0
  40. package/template/client/shared/src/utils/auth.ts +21 -0
  41. package/template/client/shared/tailwind.config.js +19 -0
  42. package/template/client/shared/tsconfig.json +9 -0
  43. package/template/package.json +47 -0
  44. package/template/packages/tsconfig/base.json +20 -0
  45. package/template/packages/tsconfig/package.json +11 -0
  46. package/template/pnpm-workspace.yaml +4 -0
  47. package/template/scripts/clean.js +56 -0
  48. package/template/server/db/drizzle.config.ts +10 -0
  49. package/template/server/db/migrations/0000_loving_mindworm.sql +86 -0
  50. package/template/server/db/migrations/meta/0000_snapshot.json +549 -0
  51. package/template/server/db/migrations/meta/_journal.json +13 -0
  52. package/template/server/db/package.json +28 -0
  53. package/template/server/db/src/index.ts +16 -0
  54. package/template/server/db/src/migrate.ts +28 -0
  55. package/template/server/db/src/schema/auth.ts +73 -0
  56. package/template/server/db/src/schema/index.ts +2 -0
  57. package/template/server/db/src/schema/rbac.ts +72 -0
  58. package/template/server/db/src/schema.ts +1 -0
  59. package/template/server/db/src/seed.ts +204 -0
  60. package/template/server/db/src/services/rbac.ts +144 -0
  61. package/template/server/db/src/services/user.ts +34 -0
  62. package/template/server/db/src/types/index.ts +34 -0
  63. package/template/server/db/tsconfig.json +8 -0
  64. package/template/server/hono/package.json +22 -0
  65. package/template/server/hono/src/auth.ts +29 -0
  66. package/template/server/hono/src/index.ts +215 -0
  67. package/template/server/hono/tsconfig.json +8 -0
  68. package/template/server/hono/wrangler.toml +12 -0
  69. package/template/turbo.json +68 -0
@@ -0,0 +1,549 @@
1
+ {
2
+ "id": "3356b049-d5d9-48ef-9e50-67d7cf018bd6",
3
+ "prevId": "00000000-0000-0000-0000-000000000000",
4
+ "version": "7",
5
+ "dialect": "postgresql",
6
+ "tables": {
7
+ "public.account": {
8
+ "name": "account",
9
+ "schema": "",
10
+ "columns": {
11
+ "id": {
12
+ "name": "id",
13
+ "type": "text",
14
+ "primaryKey": true,
15
+ "notNull": true
16
+ },
17
+ "account_id": {
18
+ "name": "account_id",
19
+ "type": "text",
20
+ "primaryKey": false,
21
+ "notNull": true
22
+ },
23
+ "provider_id": {
24
+ "name": "provider_id",
25
+ "type": "text",
26
+ "primaryKey": false,
27
+ "notNull": true
28
+ },
29
+ "user_id": {
30
+ "name": "user_id",
31
+ "type": "text",
32
+ "primaryKey": false,
33
+ "notNull": true
34
+ },
35
+ "access_token": {
36
+ "name": "access_token",
37
+ "type": "text",
38
+ "primaryKey": false,
39
+ "notNull": false
40
+ },
41
+ "refresh_token": {
42
+ "name": "refresh_token",
43
+ "type": "text",
44
+ "primaryKey": false,
45
+ "notNull": false
46
+ },
47
+ "id_token": {
48
+ "name": "id_token",
49
+ "type": "text",
50
+ "primaryKey": false,
51
+ "notNull": false
52
+ },
53
+ "access_token_expires_at": {
54
+ "name": "access_token_expires_at",
55
+ "type": "timestamp",
56
+ "primaryKey": false,
57
+ "notNull": false
58
+ },
59
+ "refresh_token_expires_at": {
60
+ "name": "refresh_token_expires_at",
61
+ "type": "timestamp",
62
+ "primaryKey": false,
63
+ "notNull": false
64
+ },
65
+ "scope": {
66
+ "name": "scope",
67
+ "type": "text",
68
+ "primaryKey": false,
69
+ "notNull": false
70
+ },
71
+ "password": {
72
+ "name": "password",
73
+ "type": "text",
74
+ "primaryKey": false,
75
+ "notNull": false
76
+ },
77
+ "created_at": {
78
+ "name": "created_at",
79
+ "type": "timestamp",
80
+ "primaryKey": false,
81
+ "notNull": true
82
+ },
83
+ "updated_at": {
84
+ "name": "updated_at",
85
+ "type": "timestamp",
86
+ "primaryKey": false,
87
+ "notNull": true
88
+ }
89
+ },
90
+ "indexes": {},
91
+ "foreignKeys": {
92
+ "account_user_id_user_id_fk": {
93
+ "name": "account_user_id_user_id_fk",
94
+ "tableFrom": "account",
95
+ "tableTo": "user",
96
+ "columnsFrom": [
97
+ "user_id"
98
+ ],
99
+ "columnsTo": [
100
+ "id"
101
+ ],
102
+ "onDelete": "cascade",
103
+ "onUpdate": "no action"
104
+ }
105
+ },
106
+ "compositePrimaryKeys": {},
107
+ "uniqueConstraints": {},
108
+ "policies": {},
109
+ "checkConstraints": {},
110
+ "isRLSEnabled": false
111
+ },
112
+ "public.session": {
113
+ "name": "session",
114
+ "schema": "",
115
+ "columns": {
116
+ "id": {
117
+ "name": "id",
118
+ "type": "text",
119
+ "primaryKey": true,
120
+ "notNull": true
121
+ },
122
+ "expires_at": {
123
+ "name": "expires_at",
124
+ "type": "timestamp",
125
+ "primaryKey": false,
126
+ "notNull": true
127
+ },
128
+ "token": {
129
+ "name": "token",
130
+ "type": "text",
131
+ "primaryKey": false,
132
+ "notNull": true
133
+ },
134
+ "created_at": {
135
+ "name": "created_at",
136
+ "type": "timestamp",
137
+ "primaryKey": false,
138
+ "notNull": true
139
+ },
140
+ "updated_at": {
141
+ "name": "updated_at",
142
+ "type": "timestamp",
143
+ "primaryKey": false,
144
+ "notNull": true
145
+ },
146
+ "ip_address": {
147
+ "name": "ip_address",
148
+ "type": "text",
149
+ "primaryKey": false,
150
+ "notNull": false
151
+ },
152
+ "user_agent": {
153
+ "name": "user_agent",
154
+ "type": "text",
155
+ "primaryKey": false,
156
+ "notNull": false
157
+ },
158
+ "user_id": {
159
+ "name": "user_id",
160
+ "type": "text",
161
+ "primaryKey": false,
162
+ "notNull": true
163
+ }
164
+ },
165
+ "indexes": {},
166
+ "foreignKeys": {
167
+ "session_user_id_user_id_fk": {
168
+ "name": "session_user_id_user_id_fk",
169
+ "tableFrom": "session",
170
+ "tableTo": "user",
171
+ "columnsFrom": [
172
+ "user_id"
173
+ ],
174
+ "columnsTo": [
175
+ "id"
176
+ ],
177
+ "onDelete": "cascade",
178
+ "onUpdate": "no action"
179
+ }
180
+ },
181
+ "compositePrimaryKeys": {},
182
+ "uniqueConstraints": {
183
+ "session_token_unique": {
184
+ "name": "session_token_unique",
185
+ "nullsNotDistinct": false,
186
+ "columns": [
187
+ "token"
188
+ ]
189
+ }
190
+ },
191
+ "policies": {},
192
+ "checkConstraints": {},
193
+ "isRLSEnabled": false
194
+ },
195
+ "public.user": {
196
+ "name": "user",
197
+ "schema": "",
198
+ "columns": {
199
+ "id": {
200
+ "name": "id",
201
+ "type": "text",
202
+ "primaryKey": true,
203
+ "notNull": true
204
+ },
205
+ "name": {
206
+ "name": "name",
207
+ "type": "text",
208
+ "primaryKey": false,
209
+ "notNull": true
210
+ },
211
+ "email": {
212
+ "name": "email",
213
+ "type": "text",
214
+ "primaryKey": false,
215
+ "notNull": true
216
+ },
217
+ "email_verified": {
218
+ "name": "email_verified",
219
+ "type": "boolean",
220
+ "primaryKey": false,
221
+ "notNull": true
222
+ },
223
+ "image": {
224
+ "name": "image",
225
+ "type": "text",
226
+ "primaryKey": false,
227
+ "notNull": false
228
+ },
229
+ "created_at": {
230
+ "name": "created_at",
231
+ "type": "timestamp",
232
+ "primaryKey": false,
233
+ "notNull": true
234
+ },
235
+ "updated_at": {
236
+ "name": "updated_at",
237
+ "type": "timestamp",
238
+ "primaryKey": false,
239
+ "notNull": true
240
+ }
241
+ },
242
+ "indexes": {},
243
+ "foreignKeys": {},
244
+ "compositePrimaryKeys": {},
245
+ "uniqueConstraints": {
246
+ "user_email_unique": {
247
+ "name": "user_email_unique",
248
+ "nullsNotDistinct": false,
249
+ "columns": [
250
+ "email"
251
+ ]
252
+ }
253
+ },
254
+ "policies": {},
255
+ "checkConstraints": {},
256
+ "isRLSEnabled": false
257
+ },
258
+ "public.verification": {
259
+ "name": "verification",
260
+ "schema": "",
261
+ "columns": {
262
+ "id": {
263
+ "name": "id",
264
+ "type": "text",
265
+ "primaryKey": true,
266
+ "notNull": true
267
+ },
268
+ "identifier": {
269
+ "name": "identifier",
270
+ "type": "text",
271
+ "primaryKey": false,
272
+ "notNull": true
273
+ },
274
+ "value": {
275
+ "name": "value",
276
+ "type": "text",
277
+ "primaryKey": false,
278
+ "notNull": true
279
+ },
280
+ "expires_at": {
281
+ "name": "expires_at",
282
+ "type": "timestamp",
283
+ "primaryKey": false,
284
+ "notNull": true
285
+ },
286
+ "created_at": {
287
+ "name": "created_at",
288
+ "type": "timestamp",
289
+ "primaryKey": false,
290
+ "notNull": false
291
+ },
292
+ "updated_at": {
293
+ "name": "updated_at",
294
+ "type": "timestamp",
295
+ "primaryKey": false,
296
+ "notNull": false
297
+ }
298
+ },
299
+ "indexes": {},
300
+ "foreignKeys": {},
301
+ "compositePrimaryKeys": {},
302
+ "uniqueConstraints": {},
303
+ "policies": {},
304
+ "checkConstraints": {},
305
+ "isRLSEnabled": false
306
+ },
307
+ "public.permission": {
308
+ "name": "permission",
309
+ "schema": "",
310
+ "columns": {
311
+ "id": {
312
+ "name": "id",
313
+ "type": "text",
314
+ "primaryKey": true,
315
+ "notNull": true
316
+ },
317
+ "name": {
318
+ "name": "name",
319
+ "type": "text",
320
+ "primaryKey": false,
321
+ "notNull": true
322
+ },
323
+ "description": {
324
+ "name": "description",
325
+ "type": "text",
326
+ "primaryKey": false,
327
+ "notNull": false
328
+ },
329
+ "created_at": {
330
+ "name": "created_at",
331
+ "type": "timestamp",
332
+ "primaryKey": false,
333
+ "notNull": true
334
+ },
335
+ "updated_at": {
336
+ "name": "updated_at",
337
+ "type": "timestamp",
338
+ "primaryKey": false,
339
+ "notNull": true
340
+ }
341
+ },
342
+ "indexes": {},
343
+ "foreignKeys": {},
344
+ "compositePrimaryKeys": {},
345
+ "uniqueConstraints": {
346
+ "permission_name_unique": {
347
+ "name": "permission_name_unique",
348
+ "nullsNotDistinct": false,
349
+ "columns": [
350
+ "name"
351
+ ]
352
+ }
353
+ },
354
+ "policies": {},
355
+ "checkConstraints": {},
356
+ "isRLSEnabled": false
357
+ },
358
+ "public.role": {
359
+ "name": "role",
360
+ "schema": "",
361
+ "columns": {
362
+ "id": {
363
+ "name": "id",
364
+ "type": "text",
365
+ "primaryKey": true,
366
+ "notNull": true
367
+ },
368
+ "name": {
369
+ "name": "name",
370
+ "type": "text",
371
+ "primaryKey": false,
372
+ "notNull": true
373
+ },
374
+ "description": {
375
+ "name": "description",
376
+ "type": "text",
377
+ "primaryKey": false,
378
+ "notNull": false
379
+ },
380
+ "created_at": {
381
+ "name": "created_at",
382
+ "type": "timestamp",
383
+ "primaryKey": false,
384
+ "notNull": true
385
+ },
386
+ "updated_at": {
387
+ "name": "updated_at",
388
+ "type": "timestamp",
389
+ "primaryKey": false,
390
+ "notNull": true
391
+ }
392
+ },
393
+ "indexes": {},
394
+ "foreignKeys": {},
395
+ "compositePrimaryKeys": {},
396
+ "uniqueConstraints": {
397
+ "role_name_unique": {
398
+ "name": "role_name_unique",
399
+ "nullsNotDistinct": false,
400
+ "columns": [
401
+ "name"
402
+ ]
403
+ }
404
+ },
405
+ "policies": {},
406
+ "checkConstraints": {},
407
+ "isRLSEnabled": false
408
+ },
409
+ "public.role_permission": {
410
+ "name": "role_permission",
411
+ "schema": "",
412
+ "columns": {
413
+ "id": {
414
+ "name": "id",
415
+ "type": "text",
416
+ "primaryKey": true,
417
+ "notNull": true
418
+ },
419
+ "role_id": {
420
+ "name": "role_id",
421
+ "type": "text",
422
+ "primaryKey": false,
423
+ "notNull": true
424
+ },
425
+ "permission_id": {
426
+ "name": "permission_id",
427
+ "type": "text",
428
+ "primaryKey": false,
429
+ "notNull": true
430
+ },
431
+ "created_at": {
432
+ "name": "created_at",
433
+ "type": "timestamp",
434
+ "primaryKey": false,
435
+ "notNull": true
436
+ }
437
+ },
438
+ "indexes": {},
439
+ "foreignKeys": {
440
+ "role_permission_role_id_role_id_fk": {
441
+ "name": "role_permission_role_id_role_id_fk",
442
+ "tableFrom": "role_permission",
443
+ "tableTo": "role",
444
+ "columnsFrom": [
445
+ "role_id"
446
+ ],
447
+ "columnsTo": [
448
+ "id"
449
+ ],
450
+ "onDelete": "cascade",
451
+ "onUpdate": "no action"
452
+ },
453
+ "role_permission_permission_id_permission_id_fk": {
454
+ "name": "role_permission_permission_id_permission_id_fk",
455
+ "tableFrom": "role_permission",
456
+ "tableTo": "permission",
457
+ "columnsFrom": [
458
+ "permission_id"
459
+ ],
460
+ "columnsTo": [
461
+ "id"
462
+ ],
463
+ "onDelete": "cascade",
464
+ "onUpdate": "no action"
465
+ }
466
+ },
467
+ "compositePrimaryKeys": {},
468
+ "uniqueConstraints": {},
469
+ "policies": {},
470
+ "checkConstraints": {},
471
+ "isRLSEnabled": false
472
+ },
473
+ "public.user_role": {
474
+ "name": "user_role",
475
+ "schema": "",
476
+ "columns": {
477
+ "id": {
478
+ "name": "id",
479
+ "type": "text",
480
+ "primaryKey": true,
481
+ "notNull": true
482
+ },
483
+ "user_id": {
484
+ "name": "user_id",
485
+ "type": "text",
486
+ "primaryKey": false,
487
+ "notNull": true
488
+ },
489
+ "role_id": {
490
+ "name": "role_id",
491
+ "type": "text",
492
+ "primaryKey": false,
493
+ "notNull": true
494
+ },
495
+ "created_at": {
496
+ "name": "created_at",
497
+ "type": "timestamp",
498
+ "primaryKey": false,
499
+ "notNull": true
500
+ }
501
+ },
502
+ "indexes": {},
503
+ "foreignKeys": {
504
+ "user_role_user_id_user_id_fk": {
505
+ "name": "user_role_user_id_user_id_fk",
506
+ "tableFrom": "user_role",
507
+ "tableTo": "user",
508
+ "columnsFrom": [
509
+ "user_id"
510
+ ],
511
+ "columnsTo": [
512
+ "id"
513
+ ],
514
+ "onDelete": "cascade",
515
+ "onUpdate": "no action"
516
+ },
517
+ "user_role_role_id_role_id_fk": {
518
+ "name": "user_role_role_id_role_id_fk",
519
+ "tableFrom": "user_role",
520
+ "tableTo": "role",
521
+ "columnsFrom": [
522
+ "role_id"
523
+ ],
524
+ "columnsTo": [
525
+ "id"
526
+ ],
527
+ "onDelete": "cascade",
528
+ "onUpdate": "no action"
529
+ }
530
+ },
531
+ "compositePrimaryKeys": {},
532
+ "uniqueConstraints": {},
533
+ "policies": {},
534
+ "checkConstraints": {},
535
+ "isRLSEnabled": false
536
+ }
537
+ },
538
+ "enums": {},
539
+ "schemas": {},
540
+ "sequences": {},
541
+ "roles": {},
542
+ "policies": {},
543
+ "views": {},
544
+ "_meta": {
545
+ "columns": {},
546
+ "schemas": {},
547
+ "tables": {}
548
+ }
549
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "version": "7",
3
+ "dialect": "postgresql",
4
+ "entries": [
5
+ {
6
+ "idx": 0,
7
+ "version": "7",
8
+ "when": 1783415213767,
9
+ "tag": "0000_loving_mindworm",
10
+ "breakpoints": true
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@thunder/db",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "main": "src/index.ts",
6
+ "types": "src/index.ts",
7
+ "scripts": {
8
+ "typecheck": "tsc --noEmit",
9
+ "db:generate": "drizzle-kit generate",
10
+ "db:migrate": "tsx src/migrate.ts",
11
+ "db:seed": "tsx src/seed.ts"
12
+ },
13
+ "dependencies": {
14
+ "@better-auth/drizzle-adapter": "^1.6.23",
15
+ "@neondatabase/serverless": "^0.10.4",
16
+ "better-auth": "^1.6.23",
17
+ "dotenv": "^16.4.7",
18
+ "drizzle-orm": "^0.44.7",
19
+ "pg": "^8.22.0"
20
+ },
21
+ "devDependencies": {
22
+ "@thunder/tsconfig": "workspace:*",
23
+ "@types/pg": "^8.20.0",
24
+ "drizzle-kit": "^0.31.10",
25
+ "tsx": "^4.23.0",
26
+ "typescript": "^5.9.3"
27
+ }
28
+ }
@@ -0,0 +1,16 @@
1
+ import { drizzle } from "drizzle-orm/neon-http";
2
+ import { neon } from "@neondatabase/serverless";
3
+ import * as schema from "./schema";
4
+
5
+ export * from "./schema";
6
+
7
+ export const createDbClient = (databaseUrl: string) => {
8
+ const sql = neon(databaseUrl);
9
+ return drizzle(sql, { schema });
10
+ };
11
+
12
+ export type DbClient = ReturnType<typeof createDbClient>;
13
+
14
+ export * from "./types";
15
+ export * from "./services/rbac";
16
+ export * from "./services/user";
@@ -0,0 +1,28 @@
1
+ import { drizzle } from "drizzle-orm/node-postgres";
2
+ import { migrate } from "drizzle-orm/node-postgres/migrator";
3
+ import { Pool } from "pg";
4
+ import * as dotenv from "dotenv";
5
+
6
+ dotenv.config({ path: "../../.env" });
7
+
8
+ const runMigration = async () => {
9
+ if (!process.env.DATABASE_URL) {
10
+ throw new Error("DATABASE_URL is missing from environment variables");
11
+ }
12
+
13
+ console.log("Running migrations...");
14
+ const pool = new Pool({
15
+ connectionString: process.env.DATABASE_URL,
16
+ });
17
+
18
+ const db = drizzle(pool);
19
+
20
+ await migrate(db, { migrationsFolder: "./migrations" });
21
+ await pool.end();
22
+ console.log("Migrations successfully completed!");
23
+ };
24
+
25
+ runMigration().catch((err) => {
26
+ console.error("Migration failed:", err);
27
+ process.exit(1);
28
+ });