@dokebi/cli 0.2.5 → 0.4.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 (81) hide show
  1. package/AI.md +181 -87
  2. package/README.md +55 -24
  3. package/catalog.json +2203 -0
  4. package/dist/app-urls.d.ts +21 -0
  5. package/dist/app-urls.js +94 -0
  6. package/dist/banner-art.d.ts +4 -0
  7. package/dist/banner-art.js +31 -0
  8. package/dist/banner.d.ts +25 -0
  9. package/dist/banner.js +202 -0
  10. package/dist/bin.d.ts +2 -1
  11. package/dist/bin.js +475 -46
  12. package/dist/catalog.d.ts +161 -0
  13. package/dist/catalog.js +110 -0
  14. package/dist/check/form-rules.d.ts +13 -0
  15. package/dist/check/form-rules.js +224 -0
  16. package/dist/check/index.d.ts +23 -0
  17. package/dist/check/index.js +70 -0
  18. package/dist/check/packages.d.ts +17 -0
  19. package/dist/check/packages.js +161 -0
  20. package/dist/check/problems.d.ts +19 -0
  21. package/dist/check/problems.js +22 -0
  22. package/dist/check/project-rules.d.ts +10 -0
  23. package/dist/check/project-rules.js +142 -0
  24. package/dist/check/source-rules.d.ts +28 -0
  25. package/dist/check/source-rules.js +273 -0
  26. package/dist/check/typescript.d.ts +46 -0
  27. package/dist/check/typescript.js +168 -0
  28. package/dist/commands.d.ts +18 -0
  29. package/dist/commands.js +372 -0
  30. package/dist/config-edit.d.ts +5 -4
  31. package/dist/config-edit.js +9 -8
  32. package/dist/configuration.d.ts +1 -0
  33. package/dist/configuration.js +2 -1
  34. package/dist/dev-infra.d.ts +62 -0
  35. package/dist/dev-infra.js +215 -0
  36. package/dist/env-file.d.ts +24 -0
  37. package/dist/env-file.js +100 -0
  38. package/dist/generator.d.ts +24 -1
  39. package/dist/generator.js +57 -47
  40. package/dist/guide.d.ts +29 -0
  41. package/dist/guide.js +90 -0
  42. package/dist/install-plan.d.ts +8 -0
  43. package/dist/install-plan.js +21 -4
  44. package/dist/layout.d.ts +5 -4
  45. package/dist/layout.js +8 -7
  46. package/dist/log-writer-control.d.ts +55 -0
  47. package/dist/log-writer-control.js +327 -0
  48. package/dist/log-writer.js +53 -12
  49. package/dist/manifest.d.ts +28 -0
  50. package/dist/manifest.js +77 -2
  51. package/dist/npm-client.d.ts +49 -0
  52. package/dist/npm-client.js +162 -41
  53. package/dist/output.d.ts +1 -1
  54. package/dist/output.js +14 -8
  55. package/dist/plugin-lifecycle.d.ts +7 -0
  56. package/dist/plugin-lifecycle.js +21 -3
  57. package/dist/plugins-command.d.ts +47 -0
  58. package/dist/plugins-command.js +189 -0
  59. package/dist/project-guide.d.ts +36 -1
  60. package/dist/project-guide.js +142 -18
  61. package/dist/project-inspector.d.ts +10 -0
  62. package/dist/project-inspector.js +51 -2
  63. package/dist/project-state.d.ts +13 -2
  64. package/dist/project-state.js +8 -6
  65. package/dist/project.d.ts +89 -7
  66. package/dist/project.js +835 -85
  67. package/dist/recipe-record.d.ts +24 -0
  68. package/dist/recipe-record.js +67 -0
  69. package/dist/recipe.d.ts +120 -0
  70. package/dist/recipe.js +801 -0
  71. package/dist/registry.d.ts +79 -0
  72. package/dist/registry.js +212 -0
  73. package/dist/rotating-log.d.ts +12 -0
  74. package/dist/rotating-log.js +19 -0
  75. package/dist/server.d.ts +94 -4
  76. package/dist/server.js +624 -64
  77. package/dist/verify.d.ts +62 -0
  78. package/dist/verify.js +380 -0
  79. package/dist/vite-host-process.d.ts +20 -0
  80. package/dist/vite-host-process.js +117 -0
  81. package/package.json +30 -6
package/catalog.json ADDED
@@ -0,0 +1,2203 @@
1
+ {
2
+ "$comment": "Generated by scripts/catalog/build.ts from package.json dokebiCatalog fields and packages/cli/catalog-src (D-0065). Do not edit; run node scripts/catalog/build.ts.",
3
+ "schemaVersion": 1,
4
+ "cli": "0.4.1",
5
+ "core": {
6
+ "package": "@dokebi/core",
7
+ "version": "0.4.0"
8
+ },
9
+ "capabilities": {
10
+ "admin.ui": {
11
+ "summary": "generated admin screens (CRUD generator)",
12
+ "en": "admin dashboard crud backoffice"
13
+ },
14
+ "auth": {
15
+ "summary": "login",
16
+ "users and permissions (authentication and authorization)": null,
17
+ "en": "auth authentication authorization login user password oauth jwt signup"
18
+ },
19
+ "cache.local": {
20
+ "summary": "in-process memory cache (LRU)",
21
+ "en": "cache memory lru"
22
+ },
23
+ "cache.redis": {
24
+ "summary": "shared Redis cache driver",
25
+ "en": "cache redis shared"
26
+ },
27
+ "cli.project": {
28
+ "summary": "commands to create a project",
29
+ "install plugins and verify it": null,
30
+ "en": "command line scaffold install verify"
31
+ },
32
+ "config.yaml": {
33
+ "summary": "read and validate dokebi.yaml (a required part of the core)",
34
+ "en": "yaml configuration"
35
+ },
36
+ "core.runtime": {
37
+ "summary": "application lifecycle",
38
+ "plugin registration": null,
39
+ "logger and shared libraries": null,
40
+ "en": "application lifecycle plugin registry logger"
41
+ },
42
+ "csrf": {
43
+ "summary": "issue and check CSRF tokens",
44
+ "en": "csrf xsrf token"
45
+ },
46
+ "db.connection": {
47
+ "summary": "named database connections (pools) with readiness checks and shutdown",
48
+ "en": "database connection pool"
49
+ },
50
+ "db.mariadb": {
51
+ "summary": "MariaDB connection (mariadb driver)",
52
+ "en": "mariadb sql database"
53
+ },
54
+ "db.migrate": {
55
+ "summary": "migrations (table and index changes) with history and a lock",
56
+ "en": "migration schema ddl"
57
+ },
58
+ "db.mongodb": {
59
+ "summary": "MongoDB connection (mongodb driver)",
60
+ "en": "mongodb mongo nosql document database"
61
+ },
62
+ "db.mysql": {
63
+ "summary": "MySQL connection (mysql2 driver)",
64
+ "en": "mysql mysql2 sql database"
65
+ },
66
+ "db.postgres": {
67
+ "summary": "PostgreSQL connection (pg driver)",
68
+ "en": "postgres postgresql pg sql database"
69
+ },
70
+ "db.seed": {
71
+ "summary": "run seed data",
72
+ "en": "seed fixtures"
73
+ },
74
+ "db.sqlite": {
75
+ "summary": "SQLite file database",
76
+ "en": "sqlite sqlite3 file database"
77
+ },
78
+ "events.bus": {
79
+ "summary": "event bus (in process or over NATS)",
80
+ "en": "event bus pubsub publish subscribe"
81
+ },
82
+ "health.checks": {
83
+ "summary": "live",
84
+ "ready and draining state with readiness checks": null,
85
+ "en": "health readiness liveness"
86
+ },
87
+ "i18n": {
88
+ "summary": "multiple languages (translated strings)",
89
+ "en": "i18n translation locale"
90
+ },
91
+ "job.durable": {
92
+ "summary": "at-least-once job queue (JetStream",
93
+ "retries": null,
94
+ "DLQ)": null,
95
+ "en": "job queue background task retry dlq"
96
+ },
97
+ "lock.local": {
98
+ "summary": "lock within one process",
99
+ "en": "lock mutex"
100
+ },
101
+ "lock.redis": {
102
+ "summary": "Redis lease lock (fencing tokens)",
103
+ "en": "distributed lock redis lease"
104
+ },
105
+ "mail": {
106
+ "summary": "send mail (SMTP)",
107
+ "en": "mail email smtp"
108
+ },
109
+ "markdown": {
110
+ "summary": "convert Markdown to HTML",
111
+ "en": "markdown md html"
112
+ },
113
+ "messaging.nats": {
114
+ "summary": "named NATS connections and JetStream publishing",
115
+ "en": "nats jetstream messaging"
116
+ },
117
+ "orm": {
118
+ "summary": "ORM",
119
+ "query builder and model mapping": null,
120
+ "en": "orm query builder model"
121
+ },
122
+ "process.cluster": {
123
+ "summary": "run several node:cluster workers",
124
+ "watch them and replace them one by one": null,
125
+ "en": "cluster multi process workers"
126
+ },
127
+ "rate-limit": {
128
+ "summary": "limit the number of requests",
129
+ "en": "rate limit throttle"
130
+ },
131
+ "realtime.hub": {
132
+ "summary": "hub of WebSocket clients",
133
+ "rooms and broadcast": null,
134
+ "en": "websocket hub rooms broadcast"
135
+ },
136
+ "realtime.sse": {
137
+ "summary": "server-sent events (SSE) streams and a browser client",
138
+ "en": "sse server sent events eventsource"
139
+ },
140
+ "realtime.websocket": {
141
+ "summary": "WebSocket routes",
142
+ "rooms and broadcast (across servers and workers)": null,
143
+ "en": "websocket socket realtime chat"
144
+ },
145
+ "redis.connection": {
146
+ "summary": "named Redis connections",
147
+ "en": "redis"
148
+ },
149
+ "redis.coordination": {
150
+ "summary": "Redis leader election and incremental state",
151
+ "en": "redis leader election coordination"
152
+ },
153
+ "rss": {
154
+ "summary": "RSS and Atom feeds",
155
+ "en": "rss atom feed"
156
+ },
157
+ "schedule.cron": {
158
+ "summary": "cron and fixed-interval schedules (submitted to the job queue)",
159
+ "en": "schedule cron interval timer"
160
+ },
161
+ "search": {
162
+ "summary": "full-text search",
163
+ "en": "search full text index"
164
+ },
165
+ "security.seal": {
166
+ "summary": "sealing of transport bodies (obfuscation",
167
+ "replay protection) and a browser client": null,
168
+ "en": "seal obfuscation replay encryption"
169
+ },
170
+ "upload": {
171
+ "summary": "receive and store file uploads (multipart)",
172
+ "en": "upload multipart file storage"
173
+ },
174
+ "view.ejs": {
175
+ "summary": "EJS server-rendered views (no build)",
176
+ "en": "ejs server side templates html"
177
+ },
178
+ "view.inertia-react": {
179
+ "summary": "Inertia + React views",
180
+ "en": "inertia react"
181
+ },
182
+ "view.inertia-vue": {
183
+ "summary": "Inertia + Vue 3 views (Vite build)",
184
+ "en": "inertia vue spa vite"
185
+ },
186
+ "view.inertia-vue-ssr": {
187
+ "summary": "Inertia + Vue 3 + server-side rendering (SSR)",
188
+ "en": "inertia vue ssr server side rendering"
189
+ },
190
+ "web.apps": {
191
+ "summary": "several apps by domain (src/apps)",
192
+ "en": "multi app domains virtual host"
193
+ },
194
+ "web.controller": {
195
+ "summary": "controller registry per app",
196
+ "en": "controller mvc"
197
+ },
198
+ "web.http": {
199
+ "summary": "HTTP server (Fastify) with 503 before ready",
200
+ "drain and health paths": null,
201
+ "en": "http server fastify web"
202
+ },
203
+ "web.modules": {
204
+ "summary": "feature modules (src/shared/modules)",
205
+ "en": "feature module"
206
+ },
207
+ "web.routing": {
208
+ "summary": "routes grouped under a prefix (mount)",
209
+ "en": "router routes prefix"
210
+ },
211
+ "web.session": {
212
+ "summary": "server-side sessions (signed cookie",
213
+ "memory or redis store": null,
214
+ "flash)": null,
215
+ "en": "session cookie flash"
216
+ },
217
+ "worker.thread": {
218
+ "summary": "worker thread pool for CPU work",
219
+ "en": "worker thread cpu pool"
220
+ }
221
+ },
222
+ "packages": [
223
+ {
224
+ "id": "dokebi-app",
225
+ "package": "@dokebi/app",
226
+ "version": "0.4.1",
227
+ "kind": "plugin",
228
+ "summary": "Several apps chosen by request domain (src/apps/<app>) with a template each; installs web, controller and template-ejs with it",
229
+ "description": "Multiple apps per project for Dokebi: pick the app and template by request domain, with EJS and Inertia skeletons.",
230
+ "keywords": [
231
+ "dokebi",
232
+ "dokebi-plugin",
233
+ "web",
234
+ "apps",
235
+ "domains",
236
+ "mvc"
237
+ ],
238
+ "maturity": "preview",
239
+ "core": "^0.4.0",
240
+ "provides": [
241
+ "web.apps"
242
+ ],
243
+ "variants": [],
244
+ "doesNot": [
245
+ "No login, permissions or admin screens",
246
+ "No React skeleton (EJS and Inertia Vue only)"
247
+ ],
248
+ "recipes": [
249
+ "api",
250
+ "blog"
251
+ ],
252
+ "requires": [
253
+ {
254
+ "id": "dokebi-web",
255
+ "range": "^0.4.1",
256
+ "package": "@dokebi/web",
257
+ "automatic": true
258
+ },
259
+ {
260
+ "id": "dokebi-controller",
261
+ "range": "^0.4.0",
262
+ "package": "@dokebi/controller",
263
+ "automatic": true
264
+ },
265
+ {
266
+ "id": "dokebi-template-ejs",
267
+ "range": "^0.4.0",
268
+ "package": "@dokebi/template-ejs",
269
+ "automatic": true
270
+ }
271
+ ],
272
+ "optional": [
273
+ {
274
+ "id": "dokebi-seal",
275
+ "range": "^0.4.0"
276
+ },
277
+ {
278
+ "id": "dokebi-session",
279
+ "range": "^0.4.0"
280
+ }
281
+ ],
282
+ "optionKeys": [
283
+ "apps",
284
+ "domains",
285
+ "unknownDomain"
286
+ ],
287
+ "docs": {
288
+ "ai": "AI.md",
289
+ "readme": "README.md"
290
+ },
291
+ "install": "npx dokebi add @dokebi/app"
292
+ },
293
+ {
294
+ "id": "dokebi-cache",
295
+ "package": "@dokebi/cache",
296
+ "version": "0.4.0",
297
+ "kind": "plugin",
298
+ "summary": "Named cache backends (local LRU by default; redis through the @dokebi/cache-redis driver)",
299
+ "description": "Named cache backends for Dokebi: in-process LRU or a shared Redis driver.",
300
+ "keywords": [
301
+ "dokebi",
302
+ "dokebi-plugin",
303
+ "cache",
304
+ "lru",
305
+ "redis"
306
+ ],
307
+ "maturity": "preview",
308
+ "core": "^0.4.0",
309
+ "provides": [
310
+ "cache.local"
311
+ ],
312
+ "variants": [],
313
+ "doesNot": [
314
+ "No values that are not JSON",
315
+ "The Redis driver is installed separately (@dokebi/cache-redis)"
316
+ ],
317
+ "recipes": [],
318
+ "requires": [],
319
+ "optional": [
320
+ {
321
+ "id": "dokebi-redis",
322
+ "range": "^0.4.0"
323
+ }
324
+ ],
325
+ "optionKeys": [
326
+ "backends"
327
+ ],
328
+ "docs": {
329
+ "ai": "AI.md",
330
+ "readme": "README.md"
331
+ },
332
+ "install": "npx dokebi add @dokebi/cache"
333
+ },
334
+ {
335
+ "id": null,
336
+ "package": "@dokebi/cache-redis",
337
+ "version": "0.4.0",
338
+ "kind": "driver",
339
+ "summary": "Redis driver of @dokebi/cache (not a plugin: install it with npm install)",
340
+ "description": "Redis driver for @dokebi/cache (not a plugin; install with npm).",
341
+ "keywords": [
342
+ "dokebi",
343
+ "dokebi-driver",
344
+ "cache",
345
+ "redis"
346
+ ],
347
+ "maturity": "preview",
348
+ "core": "^0.4.0",
349
+ "provides": [
350
+ "cache.redis"
351
+ ],
352
+ "variants": [],
353
+ "doesNot": [
354
+ "Not installed with dokebi add"
355
+ ],
356
+ "recipes": [],
357
+ "requires": [],
358
+ "optional": [],
359
+ "driverOf": "dokebi-cache",
360
+ "optionKeys": [],
361
+ "docs": {
362
+ "ai": "AI.md",
363
+ "readme": "README.md"
364
+ },
365
+ "install": "npm install @dokebi/cache-redis"
366
+ },
367
+ {
368
+ "id": null,
369
+ "package": "@dokebi/cli",
370
+ "version": "0.4.1",
371
+ "kind": "cli",
372
+ "summary": "Commands to create a project, browse the plugin catalog, run recipes, install plugins and verify (dokebi)",
373
+ "description": "Project scaffolding, plugin catalog, recipes, install and verification CLI for Dokebi.",
374
+ "keywords": [
375
+ "dokebi",
376
+ "cli",
377
+ "scaffold",
378
+ "plugins",
379
+ "catalog"
380
+ ],
381
+ "maturity": "preview",
382
+ "core": null,
383
+ "provides": [
384
+ "cli.project"
385
+ ],
386
+ "variants": [],
387
+ "doesNot": [
388
+ "It is not the npm package named dokebi (never npx -y dokebi)",
389
+ "It does not write app code for you"
390
+ ],
391
+ "recipes": [
392
+ "api",
393
+ "blog"
394
+ ],
395
+ "requires": [],
396
+ "optional": [],
397
+ "optionKeys": [],
398
+ "docs": {
399
+ "ai": "AI.md",
400
+ "readme": null
401
+ },
402
+ "install": "npx -y @dokebi/cli init <folder>"
403
+ },
404
+ {
405
+ "id": null,
406
+ "package": "@dokebi/cluster",
407
+ "version": "0.4.0",
408
+ "kind": "library",
409
+ "summary": "Runner that starts several app workers from a node:cluster parent process, watches them and replaces them one by one",
410
+ "description": "node:cluster runner for Dokebi: starts, watches and rolls independent application workers.",
411
+ "keywords": [
412
+ "dokebi",
413
+ "cluster",
414
+ "workers",
415
+ "process",
416
+ "rolling-restart"
417
+ ],
418
+ "maturity": "preview",
419
+ "core": "^0.4.0",
420
+ "provides": [
421
+ "process.cluster"
422
+ ],
423
+ "variants": [],
424
+ "doesNot": [
425
+ "Not a plugin you app.register",
426
+ "Not a CPU thread pool (@dokebi/worker)"
427
+ ],
428
+ "recipes": [],
429
+ "requires": [],
430
+ "optional": [],
431
+ "optionKeys": [],
432
+ "docs": {
433
+ "ai": "AI.md",
434
+ "readme": "README.md"
435
+ },
436
+ "install": "npm install @dokebi/cluster"
437
+ },
438
+ {
439
+ "id": "dokebi-config",
440
+ "package": "@dokebi/config",
441
+ "version": "0.4.0",
442
+ "kind": "required",
443
+ "summary": "Required part of the core that reads and validates dokebi.yaml into read-only settings per app (installed automatically)",
444
+ "description": "Validated immutable YAML configuration for Dokebi applications.",
445
+ "keywords": [
446
+ "dokebi",
447
+ "dokebi-plugin",
448
+ "config",
449
+ "yaml"
450
+ ],
451
+ "maturity": "preview",
452
+ "core": null,
453
+ "provides": [
454
+ "config.yaml"
455
+ ],
456
+ "variants": [],
457
+ "doesNot": [
458
+ "Not installed or removed by hand",
459
+ "No environment variable substitution"
460
+ ],
461
+ "recipes": [
462
+ "api",
463
+ "blog"
464
+ ],
465
+ "requires": [],
466
+ "optional": [],
467
+ "optionKeys": [],
468
+ "docs": {
469
+ "ai": "AI.md",
470
+ "readme": null
471
+ },
472
+ "install": "automatic (dokebi init)"
473
+ },
474
+ {
475
+ "id": "dokebi-controller",
476
+ "package": "@dokebi/controller",
477
+ "version": "0.4.0",
478
+ "kind": "plugin",
479
+ "summary": "Registry that creates each controller object once per app and hands it out with its type",
480
+ "description": "Per-app controller registry for Dokebi: build controllers once and read them with their types.",
481
+ "keywords": [
482
+ "dokebi",
483
+ "dokebi-plugin",
484
+ "web",
485
+ "controller",
486
+ "mvc"
487
+ ],
488
+ "maturity": "preview",
489
+ "core": "^0.4.0",
490
+ "provides": [
491
+ "web.controller"
492
+ ],
493
+ "variants": [],
494
+ "doesNot": [
495
+ "No decorator or reflection DI",
496
+ "No HTTP routing"
497
+ ],
498
+ "recipes": [
499
+ "api",
500
+ "blog"
501
+ ],
502
+ "requires": [],
503
+ "optional": [],
504
+ "optionKeys": [],
505
+ "docs": {
506
+ "ai": "AI.md",
507
+ "readme": "README.md"
508
+ },
509
+ "install": "npx dokebi add @dokebi/controller"
510
+ },
511
+ {
512
+ "id": null,
513
+ "package": "@dokebi/core",
514
+ "version": "0.4.0",
515
+ "kind": "core",
516
+ "summary": "Application core: settings loading, plugin registration, lifecycle, logger and shared libraries (required)",
517
+ "description": "Minimal composable Node.js application and plugin lifecycle framework.",
518
+ "keywords": [
519
+ "dokebi",
520
+ "framework",
521
+ "lifecycle",
522
+ "plugins",
523
+ "nodejs"
524
+ ],
525
+ "maturity": "preview",
526
+ "core": null,
527
+ "provides": [
528
+ "core.runtime"
529
+ ],
530
+ "variants": [],
531
+ "doesNot": [
532
+ "No web, database, Redis or similar features (all are optional plugins)",
533
+ "No AI-only runtime"
534
+ ],
535
+ "recipes": [
536
+ "api",
537
+ "blog"
538
+ ],
539
+ "requires": [],
540
+ "optional": [],
541
+ "optionKeys": [],
542
+ "docs": {
543
+ "ai": "AI.md",
544
+ "readme": null
545
+ },
546
+ "install": "automatic (dokebi init)"
547
+ },
548
+ {
549
+ "id": "dokebi-db",
550
+ "package": "@dokebi/db",
551
+ "version": "0.4.0",
552
+ "kind": "plugin",
553
+ "summary": "Named database connections (pools) with readiness checks and shutdown; you use the driver API as it is",
554
+ "description": "Named database connections for Dokebi: create, readiness check and close pools of pg, mysql2, mariadb or mongodb.",
555
+ "keywords": [
556
+ "dokebi",
557
+ "dokebi-plugin",
558
+ "database",
559
+ "postgres",
560
+ "mysql",
561
+ "mariadb",
562
+ "mongodb"
563
+ ],
564
+ "maturity": "preview",
565
+ "core": "^0.4.0",
566
+ "provides": [
567
+ "db.connection",
568
+ "db.mariadb",
569
+ "db.mongodb",
570
+ "db.mysql",
571
+ "db.postgres"
572
+ ],
573
+ "variants": [
574
+ {
575
+ "name": "postgres",
576
+ "capability": "db.postgres",
577
+ "adapter": "pg",
578
+ "driver": {
579
+ "package": "pg",
580
+ "version": "8.23.1"
581
+ },
582
+ "types": {
583
+ "package": "@types/pg",
584
+ "version": "8.23.1"
585
+ },
586
+ "migrate": true,
587
+ "devInfra": {
588
+ "docker": {
589
+ "image": "postgres:16.15-alpine",
590
+ "port": 5432,
591
+ "env": {
592
+ "POSTGRES_USER": "dokebi",
593
+ "POSTGRES_PASSWORD": "${DOKEBI_DB_PASSWORD}",
594
+ "POSTGRES_DB": "dokebi"
595
+ },
596
+ "healthcheck": [
597
+ "CMD",
598
+ "pg_isready",
599
+ "-U",
600
+ "dokebi",
601
+ "-d",
602
+ "dokebi"
603
+ ],
604
+ "url": "postgres://dokebi:{password}@127.0.0.1:{port}/dokebi"
605
+ }
606
+ }
607
+ },
608
+ {
609
+ "name": "mysql",
610
+ "capability": "db.mysql",
611
+ "adapter": "mysql2",
612
+ "driver": {
613
+ "package": "mysql2",
614
+ "version": "3.24.5"
615
+ },
616
+ "migrate": true,
617
+ "devInfra": {
618
+ "docker": {
619
+ "image": "mysql:8",
620
+ "port": 3306,
621
+ "env": {
622
+ "MYSQL_ROOT_PASSWORD": "${DOKEBI_DB_PASSWORD}",
623
+ "MYSQL_USER": "dokebi",
624
+ "MYSQL_PASSWORD": "${DOKEBI_DB_PASSWORD}",
625
+ "MYSQL_DATABASE": "dokebi"
626
+ },
627
+ "healthcheck": [
628
+ "CMD",
629
+ "mysqladmin",
630
+ "ping",
631
+ "-h",
632
+ "127.0.0.1",
633
+ "-udokebi",
634
+ "-p${DOKEBI_DB_PASSWORD}"
635
+ ],
636
+ "url": "mysql://dokebi:{password}@127.0.0.1:{port}/dokebi"
637
+ }
638
+ }
639
+ },
640
+ {
641
+ "name": "mariadb",
642
+ "capability": "db.mariadb",
643
+ "adapter": "mariadb",
644
+ "driver": {
645
+ "package": "mariadb",
646
+ "version": "3.5.4"
647
+ },
648
+ "migrate": true,
649
+ "devInfra": {
650
+ "docker": {
651
+ "image": "mariadb:11",
652
+ "port": 3306,
653
+ "env": {
654
+ "MARIADB_ROOT_PASSWORD": "${DOKEBI_DB_PASSWORD}",
655
+ "MARIADB_USER": "dokebi",
656
+ "MARIADB_PASSWORD": "${DOKEBI_DB_PASSWORD}",
657
+ "MARIADB_DATABASE": "dokebi"
658
+ },
659
+ "healthcheck": [
660
+ "CMD",
661
+ "healthcheck.sh",
662
+ "--connect",
663
+ "--innodb_initialized"
664
+ ],
665
+ "url": "mariadb://dokebi:{password}@127.0.0.1:{port}/dokebi"
666
+ }
667
+ }
668
+ },
669
+ {
670
+ "name": "mongodb",
671
+ "capability": "db.mongodb",
672
+ "adapter": "mongodb",
673
+ "driver": {
674
+ "package": "mongodb",
675
+ "version": "7.7.0"
676
+ },
677
+ "migrate": true,
678
+ "devInfra": {
679
+ "docker": {
680
+ "image": "mongo:7",
681
+ "port": 27017,
682
+ "env": {
683
+ "MONGO_INITDB_ROOT_USERNAME": "dokebi",
684
+ "MONGO_INITDB_ROOT_PASSWORD": "${DOKEBI_DB_PASSWORD}"
685
+ },
686
+ "healthcheck": [
687
+ "CMD",
688
+ "mongosh",
689
+ "--quiet",
690
+ "--eval",
691
+ "db.adminCommand('ping')"
692
+ ],
693
+ "url": "mongodb://dokebi:{password}@127.0.0.1:{port}/dokebi?authSource=admin"
694
+ }
695
+ }
696
+ }
697
+ ],
698
+ "doesNot": [
699
+ "No ORM, query builder or query API",
700
+ "No bundled driver (add --adapter installs it)",
701
+ "No table changes or seeds (@dokebi/migrate)",
702
+ "No SQLite adapter"
703
+ ],
704
+ "recipes": [
705
+ "api",
706
+ "blog"
707
+ ],
708
+ "requires": [],
709
+ "optional": [
710
+ {
711
+ "id": "dokebi-health",
712
+ "range": "^0.4.0"
713
+ }
714
+ ],
715
+ "optionKeys": [
716
+ "connections"
717
+ ],
718
+ "docs": {
719
+ "ai": "AI.md",
720
+ "readme": "README.md"
721
+ },
722
+ "install": "npx dokebi add @dokebi/db"
723
+ },
724
+ {
725
+ "id": "dokebi-event-bus",
726
+ "package": "@dokebi/event-bus",
727
+ "version": "0.4.0",
728
+ "kind": "plugin",
729
+ "summary": "Named event buses (local or NATS, at most once)",
730
+ "description": "Named event buses for Dokebi: in-process dispatch or NATS Core delivery between processes.",
731
+ "keywords": [
732
+ "dokebi",
733
+ "dokebi-plugin",
734
+ "events",
735
+ "pubsub",
736
+ "nats"
737
+ ],
738
+ "maturity": "preview",
739
+ "core": "^0.4.0",
740
+ "provides": [
741
+ "events.bus"
742
+ ],
743
+ "variants": [],
744
+ "doesNot": [
745
+ "No persistence, retries or exactly-once delivery (@dokebi/job)"
746
+ ],
747
+ "recipes": [],
748
+ "requires": [],
749
+ "optional": [
750
+ {
751
+ "id": "dokebi-nats",
752
+ "range": "^0.4.0"
753
+ }
754
+ ],
755
+ "optionKeys": [
756
+ "buses"
757
+ ],
758
+ "docs": {
759
+ "ai": "AI.md",
760
+ "readme": "README.md"
761
+ },
762
+ "install": "npx dokebi add @dokebi/event-bus"
763
+ },
764
+ {
765
+ "id": "dokebi-health",
766
+ "package": "@dokebi/health",
767
+ "version": "0.4.0",
768
+ "kind": "plugin",
769
+ "summary": "Collects the live, ready and draining state of the app and the readiness checks of plugins (web serves the HTTP paths)",
770
+ "description": "Liveness, readiness and draining state with plugin readiness checks for Dokebi.",
771
+ "keywords": [
772
+ "dokebi",
773
+ "dokebi-plugin",
774
+ "health",
775
+ "readiness",
776
+ "liveness"
777
+ ],
778
+ "maturity": "preview",
779
+ "core": "^0.4.0",
780
+ "provides": [
781
+ "health.checks"
782
+ ],
783
+ "variants": [],
784
+ "doesNot": [
785
+ "No periodic probes or automatic restarts",
786
+ "No aggregation across the cluster"
787
+ ],
788
+ "recipes": [],
789
+ "requires": [],
790
+ "optional": [],
791
+ "optionKeys": [
792
+ "maxChecks"
793
+ ],
794
+ "docs": {
795
+ "ai": "AI.md",
796
+ "readme": "README.md"
797
+ },
798
+ "install": "npx dokebi add @dokebi/health"
799
+ },
800
+ {
801
+ "id": "dokebi-job",
802
+ "package": "@dokebi/job",
803
+ "version": "0.4.0",
804
+ "kind": "plugin",
805
+ "summary": "NATS JetStream job queue (at least once, retries, DLQ)",
806
+ "description": "Bounded durable jobs over the Dokebi NATS provider: retries, delayed redelivery and a dead-letter stream.",
807
+ "keywords": [
808
+ "dokebi",
809
+ "dokebi-plugin",
810
+ "jobs",
811
+ "queue",
812
+ "nats",
813
+ "jetstream"
814
+ ],
815
+ "maturity": "preview",
816
+ "core": "^0.4.0",
817
+ "provides": [
818
+ "job.durable"
819
+ ],
820
+ "variants": [],
821
+ "doesNot": [
822
+ "No exactly-once delivery (handlers must be idempotent)",
823
+ "No database"
824
+ ],
825
+ "recipes": [],
826
+ "requires": [
827
+ {
828
+ "id": "dokebi-nats",
829
+ "range": "^0.4.0"
830
+ }
831
+ ],
832
+ "optional": [
833
+ {
834
+ "id": "dokebi-health",
835
+ "range": "^0.4.0"
836
+ }
837
+ ],
838
+ "optionKeys": [
839
+ "queues"
840
+ ],
841
+ "docs": {
842
+ "ai": "AI.md",
843
+ "readme": "README.md"
844
+ },
845
+ "install": "npx dokebi add @dokebi/job"
846
+ },
847
+ {
848
+ "id": "dokebi-lock",
849
+ "package": "@dokebi/lock",
850
+ "version": "0.4.0",
851
+ "kind": "plugin",
852
+ "summary": "Named locks (local by default; redis leases through the @dokebi/lock-redis driver) with fencing tokens",
853
+ "description": "Named lock backends for Dokebi with fencing tokens: in-process or Redis leases.",
854
+ "keywords": [
855
+ "dokebi",
856
+ "dokebi-plugin",
857
+ "lock",
858
+ "mutex",
859
+ "redis"
860
+ ],
861
+ "maturity": "preview",
862
+ "core": "^0.4.0",
863
+ "provides": [
864
+ "lock.local"
865
+ ],
866
+ "variants": [],
867
+ "doesNot": [
868
+ "The Redis driver is installed separately (@dokebi/lock-redis)"
869
+ ],
870
+ "recipes": [],
871
+ "requires": [],
872
+ "optional": [
873
+ {
874
+ "id": "dokebi-redis",
875
+ "range": "^0.4.0"
876
+ }
877
+ ],
878
+ "optionKeys": [
879
+ "backends"
880
+ ],
881
+ "docs": {
882
+ "ai": "AI.md",
883
+ "readme": "README.md"
884
+ },
885
+ "install": "npx dokebi add @dokebi/lock"
886
+ },
887
+ {
888
+ "id": null,
889
+ "package": "@dokebi/lock-redis",
890
+ "version": "0.4.0",
891
+ "kind": "driver",
892
+ "summary": "Redis lease driver of @dokebi/lock (not a plugin: install it with npm install)",
893
+ "description": "Redis lease driver for @dokebi/lock (not a plugin; install with npm).",
894
+ "keywords": [
895
+ "dokebi",
896
+ "dokebi-driver",
897
+ "lock",
898
+ "redis"
899
+ ],
900
+ "maturity": "preview",
901
+ "core": "^0.4.0",
902
+ "provides": [
903
+ "lock.redis"
904
+ ],
905
+ "variants": [],
906
+ "doesNot": [
907
+ "Not installed with dokebi add",
908
+ "No Redlock (several Redis servers)"
909
+ ],
910
+ "recipes": [],
911
+ "requires": [],
912
+ "optional": [],
913
+ "driverOf": "dokebi-lock",
914
+ "optionKeys": [],
915
+ "docs": {
916
+ "ai": "AI.md",
917
+ "readme": "README.md"
918
+ },
919
+ "install": "npm install @dokebi/lock-redis"
920
+ },
921
+ {
922
+ "id": "dokebi-migrate",
923
+ "package": "@dokebi/migrate",
924
+ "version": "0.4.0",
925
+ "kind": "plugin",
926
+ "summary": "Migration and seed runner for dokebi-db connections (dokebi-migrate up in the deploy step)",
927
+ "description": "Migrations and seeds for dokebi-db connections: history and lock for PostgreSQL, MySQL, MariaDB and MongoDB, run from the deployment.",
928
+ "keywords": [
929
+ "dokebi",
930
+ "dokebi-plugin",
931
+ "database",
932
+ "migrations",
933
+ "seeds"
934
+ ],
935
+ "maturity": "preview",
936
+ "core": "^0.4.0",
937
+ "provides": [
938
+ "db.migrate",
939
+ "db.seed"
940
+ ],
941
+ "variants": [],
942
+ "doesNot": [
943
+ "No DDL when the app starts",
944
+ "No tables generated from ORM models"
945
+ ],
946
+ "recipes": [
947
+ "api",
948
+ "blog"
949
+ ],
950
+ "requires": [
951
+ {
952
+ "id": "dokebi-db",
953
+ "range": "^0.4.0",
954
+ "package": "@dokebi/db",
955
+ "automatic": true
956
+ }
957
+ ],
958
+ "optional": [],
959
+ "optionKeys": [
960
+ "connections",
961
+ "directory",
962
+ "lockTimeoutMs",
963
+ "lockTtlMs",
964
+ "onPending"
965
+ ],
966
+ "docs": {
967
+ "ai": "AI.md",
968
+ "readme": "README.md"
969
+ },
970
+ "install": "npx dokebi add @dokebi/migrate"
971
+ },
972
+ {
973
+ "id": "dokebi-module",
974
+ "package": "@dokebi/module",
975
+ "version": "0.4.0",
976
+ "kind": "plugin",
977
+ "summary": "Modules that hold one feature each (src/shared/modules/<module>); an app attaches them under a prefix",
978
+ "description": "Feature modules for Dokebi apps: controllers, models, views and routes in one folder mounted under a prefix.",
979
+ "keywords": [
980
+ "dokebi",
981
+ "dokebi-plugin",
982
+ "web",
983
+ "modules",
984
+ "mvc"
985
+ ],
986
+ "maturity": "preview",
987
+ "core": "^0.4.0",
988
+ "provides": [
989
+ "web.modules"
990
+ ],
991
+ "variants": [],
992
+ "doesNot": [
993
+ "Does not attach modules to apps by itself (modules in app.ts)"
994
+ ],
995
+ "recipes": [
996
+ "api",
997
+ "blog"
998
+ ],
999
+ "requires": [],
1000
+ "optional": [],
1001
+ "optionKeys": [],
1002
+ "docs": {
1003
+ "ai": "AI.md",
1004
+ "readme": "README.md"
1005
+ },
1006
+ "install": "npx dokebi add @dokebi/module"
1007
+ },
1008
+ {
1009
+ "id": "dokebi-nats",
1010
+ "package": "@dokebi/nats",
1011
+ "version": "0.4.0",
1012
+ "kind": "plugin",
1013
+ "summary": "Named NATS connections (Core and JetStream publishing, durable consumers)",
1014
+ "description": "Named NATS connections and bounded JetStream publication for Dokebi.",
1015
+ "keywords": [
1016
+ "dokebi",
1017
+ "dokebi-plugin",
1018
+ "nats",
1019
+ "jetstream",
1020
+ "messaging"
1021
+ ],
1022
+ "maturity": "preview",
1023
+ "core": "^0.4.0",
1024
+ "provides": [
1025
+ "messaging.nats"
1026
+ ],
1027
+ "variants": [],
1028
+ "doesNot": [
1029
+ "No raw SDK client and no stream management rights"
1030
+ ],
1031
+ "recipes": [],
1032
+ "requires": [],
1033
+ "optional": [
1034
+ {
1035
+ "id": "dokebi-health",
1036
+ "range": "^0.4.0"
1037
+ }
1038
+ ],
1039
+ "optionKeys": [
1040
+ "connections"
1041
+ ],
1042
+ "docs": {
1043
+ "ai": "AI.md",
1044
+ "readme": "README.md"
1045
+ },
1046
+ "install": "npx dokebi add @dokebi/nats"
1047
+ },
1048
+ {
1049
+ "id": "dokebi-redis",
1050
+ "package": "@dokebi/redis",
1051
+ "version": "0.4.0",
1052
+ "kind": "plugin",
1053
+ "summary": "Named standalone Redis connections and leader election (coordination)",
1054
+ "description": "Named, lifecycle-owned Redis connections for Dokebi with leader election and coordination.",
1055
+ "keywords": [
1056
+ "dokebi",
1057
+ "dokebi-plugin",
1058
+ "redis",
1059
+ "coordination"
1060
+ ],
1061
+ "maturity": "preview",
1062
+ "core": "^0.4.0",
1063
+ "provides": [
1064
+ "redis.connection",
1065
+ "redis.coordination"
1066
+ ],
1067
+ "variants": [],
1068
+ "doesNot": [
1069
+ "No Cluster or Sentinel",
1070
+ "No raw client, pipeline or transaction"
1071
+ ],
1072
+ "recipes": [],
1073
+ "requires": [],
1074
+ "optional": [
1075
+ {
1076
+ "id": "dokebi-health",
1077
+ "range": "^0.4.0"
1078
+ }
1079
+ ],
1080
+ "optionKeys": [
1081
+ "connections"
1082
+ ],
1083
+ "docs": {
1084
+ "ai": "AI.md",
1085
+ "readme": "README.md"
1086
+ },
1087
+ "install": "npx dokebi add @dokebi/redis"
1088
+ },
1089
+ {
1090
+ "id": "dokebi-router",
1091
+ "package": "@dokebi/router",
1092
+ "version": "0.4.0",
1093
+ "kind": "plugin",
1094
+ "summary": "Adds routes in a prefix scope on top of dokebi-web (mount)",
1095
+ "description": "Prefix-mounted Fastify route scopes for @dokebi/web.",
1096
+ "keywords": [
1097
+ "dokebi",
1098
+ "dokebi-plugin",
1099
+ "web",
1100
+ "router",
1101
+ "routes"
1102
+ ],
1103
+ "maturity": "preview",
1104
+ "core": "^0.4.0",
1105
+ "provides": [
1106
+ "web.routing"
1107
+ ],
1108
+ "variants": [],
1109
+ "doesNot": [
1110
+ "Does not require controllers, views or a database"
1111
+ ],
1112
+ "recipes": [],
1113
+ "requires": [
1114
+ {
1115
+ "id": "dokebi-web",
1116
+ "range": "^0.4.0"
1117
+ }
1118
+ ],
1119
+ "optional": [],
1120
+ "optionKeys": [],
1121
+ "docs": {
1122
+ "ai": "AI.md",
1123
+ "readme": "README.md"
1124
+ },
1125
+ "install": "npx dokebi add @dokebi/router"
1126
+ },
1127
+ {
1128
+ "id": "dokebi-scheduler",
1129
+ "package": "@dokebi/scheduler",
1130
+ "version": "0.4.0",
1131
+ "kind": "plugin",
1132
+ "summary": "Submits fixed-interval and cron schedules as @dokebi/job jobs (one leader through Redis)",
1133
+ "description": "Interval and cron schedules (with time zones) for Dokebi that submit jobs, with one leader over Redis.",
1134
+ "keywords": [
1135
+ "dokebi",
1136
+ "dokebi-plugin",
1137
+ "scheduler",
1138
+ "cron",
1139
+ "jobs"
1140
+ ],
1141
+ "maturity": "preview",
1142
+ "core": "^0.4.0",
1143
+ "provides": [
1144
+ "schedule.cron"
1145
+ ],
1146
+ "variants": [],
1147
+ "doesNot": [
1148
+ "Does not run jobs itself (job runs them)"
1149
+ ],
1150
+ "recipes": [],
1151
+ "requires": [
1152
+ {
1153
+ "id": "dokebi-job",
1154
+ "range": "^0.4.0"
1155
+ }
1156
+ ],
1157
+ "optional": [
1158
+ {
1159
+ "id": "dokebi-redis",
1160
+ "range": "^0.4.0"
1161
+ }
1162
+ ],
1163
+ "optionKeys": [
1164
+ "allowInCluster",
1165
+ "coordination",
1166
+ "schedules",
1167
+ "shutdownTimeoutMs"
1168
+ ],
1169
+ "docs": {
1170
+ "ai": "AI.md",
1171
+ "readme": "README.md"
1172
+ },
1173
+ "install": "npx dokebi add @dokebi/scheduler"
1174
+ },
1175
+ {
1176
+ "id": "dokebi-seal",
1177
+ "package": "@dokebi/seal",
1178
+ "version": "0.4.0",
1179
+ "kind": "plugin",
1180
+ "summary": "Seals WebSocket frames and HTTP bodies (obfuscation, replay protection) with a browser client (WASM)",
1181
+ "description": "Payload sealing (obfuscation, replay defence, in-transit encryption) for seal hosts: @dokebi/websocket frames and @dokebi/web HTTP bodies, with browser socket, fetch and Inertia clients and their WASM loader",
1182
+ "keywords": [
1183
+ "dokebi",
1184
+ "dokebi-plugin",
1185
+ "seal",
1186
+ "websocket",
1187
+ "obfuscation"
1188
+ ],
1189
+ "maturity": "preview",
1190
+ "core": "^0.4.0",
1191
+ "provides": [
1192
+ "security.seal"
1193
+ ],
1194
+ "variants": [],
1195
+ "doesNot": [
1196
+ "Not a replacement for confidentiality (TLS)",
1197
+ "Not authentication, CSRF protection or a rate limit"
1198
+ ],
1199
+ "recipes": [],
1200
+ "requires": [],
1201
+ "optional": [
1202
+ {
1203
+ "id": "dokebi-web",
1204
+ "range": "^0.4.0"
1205
+ },
1206
+ {
1207
+ "id": "dokebi-websocket-hub",
1208
+ "range": "^0.4.0"
1209
+ }
1210
+ ],
1211
+ "optionKeys": [],
1212
+ "docs": {
1213
+ "ai": "AI.md",
1214
+ "readme": "README.md"
1215
+ },
1216
+ "install": "npx dokebi add @dokebi/seal"
1217
+ },
1218
+ {
1219
+ "id": "dokebi-session",
1220
+ "package": "@dokebi/session",
1221
+ "version": "0.4.0",
1222
+ "kind": "plugin",
1223
+ "summary": "Server-side sessions for @dokebi/web (signed cookie, memory or redis store, flash)",
1224
+ "description": "Server-side sessions for @dokebi/web: signed cookie, memory or Redis store, flash.",
1225
+ "keywords": [
1226
+ "dokebi",
1227
+ "dokebi-plugin",
1228
+ "web",
1229
+ "session",
1230
+ "cookie"
1231
+ ],
1232
+ "maturity": "preview",
1233
+ "core": "^0.4.0",
1234
+ "provides": [
1235
+ "web.session"
1236
+ ],
1237
+ "variants": [],
1238
+ "doesNot": [
1239
+ "Not user accounts or sign-in (there is no auth)",
1240
+ "Does not issue CSRF tokens"
1241
+ ],
1242
+ "recipes": [
1243
+ "blog"
1244
+ ],
1245
+ "requires": [
1246
+ {
1247
+ "id": "dokebi-web",
1248
+ "range": "^0.4.0"
1249
+ }
1250
+ ],
1251
+ "optional": [
1252
+ {
1253
+ "id": "dokebi-redis",
1254
+ "range": "^0.4.0"
1255
+ },
1256
+ {
1257
+ "id": "dokebi-health",
1258
+ "range": "^0.4.0"
1259
+ }
1260
+ ],
1261
+ "optionKeys": [
1262
+ "absoluteMs",
1263
+ "cookie",
1264
+ "exclude",
1265
+ "maxBytes",
1266
+ "refreshBelow",
1267
+ "rolling",
1268
+ "secrets",
1269
+ "secretsEnv",
1270
+ "store",
1271
+ "ttlMs"
1272
+ ],
1273
+ "docs": {
1274
+ "ai": "AI.md",
1275
+ "readme": "README.md"
1276
+ },
1277
+ "install": "npx dokebi add @dokebi/session"
1278
+ },
1279
+ {
1280
+ "id": "dokebi-sse",
1281
+ "package": "@dokebi/sse",
1282
+ "version": "0.4.0",
1283
+ "kind": "plugin",
1284
+ "summary": "Server-sent events (SSE) streams and rooms, delivery across workers, and a browser client",
1285
+ "description": "Server-sent events for @dokebi/web: authenticated streams, rooms, cross-worker fan-out over @dokebi/event-bus, and a browser client",
1286
+ "keywords": [
1287
+ "dokebi",
1288
+ "dokebi-plugin",
1289
+ "web",
1290
+ "sse",
1291
+ "realtime"
1292
+ ],
1293
+ "maturity": "preview",
1294
+ "core": "^0.4.0",
1295
+ "provides": [
1296
+ "realtime.sse"
1297
+ ],
1298
+ "variants": [],
1299
+ "doesNot": [
1300
+ "No ACK, redelivery or retention (at most once)"
1301
+ ],
1302
+ "recipes": [],
1303
+ "requires": [
1304
+ {
1305
+ "id": "dokebi-web",
1306
+ "range": "^0.4.0"
1307
+ }
1308
+ ],
1309
+ "optional": [
1310
+ {
1311
+ "id": "dokebi-event-bus",
1312
+ "range": "^0.4.0"
1313
+ },
1314
+ {
1315
+ "id": "dokebi-health",
1316
+ "range": "^0.4.0"
1317
+ }
1318
+ ],
1319
+ "optionKeys": [
1320
+ "allowInCluster",
1321
+ "busEvent",
1322
+ "eventBus",
1323
+ "heartbeatMs",
1324
+ "maxBufferedBytes",
1325
+ "maxConnections",
1326
+ "maxEventBytes",
1327
+ "maxRooms",
1328
+ "retryMs",
1329
+ "shutdownTimeoutMs"
1330
+ ],
1331
+ "docs": {
1332
+ "ai": "AI.md",
1333
+ "readme": "README.md"
1334
+ },
1335
+ "install": "npx dokebi add @dokebi/sse"
1336
+ },
1337
+ {
1338
+ "id": "dokebi-template-ejs",
1339
+ "package": "@dokebi/template-ejs",
1340
+ "version": "0.4.1",
1341
+ "kind": "plugin",
1342
+ "summary": "Compiles EJS templates at startup and renders them by name (layouts, partials, a scope per app)",
1343
+ "description": "Precompiled EJS templates for Dokebi apps: layouts, partials and per-app scopes.",
1344
+ "keywords": [
1345
+ "dokebi",
1346
+ "dokebi-plugin",
1347
+ "web",
1348
+ "views",
1349
+ "ejs",
1350
+ "templates"
1351
+ ],
1352
+ "maturity": "preview",
1353
+ "core": "^0.4.0",
1354
+ "provides": [
1355
+ "view.ejs"
1356
+ ],
1357
+ "variants": [
1358
+ {
1359
+ "name": "ejs",
1360
+ "capability": "view.ejs"
1361
+ }
1362
+ ],
1363
+ "doesNot": [
1364
+ "No client-side page updates (SPA)"
1365
+ ],
1366
+ "recipes": [
1367
+ "api",
1368
+ "blog"
1369
+ ],
1370
+ "requires": [],
1371
+ "optional": [],
1372
+ "optionKeys": [
1373
+ "defaultLayout",
1374
+ "extension",
1375
+ "maxTemplateBytes",
1376
+ "maxTemplates"
1377
+ ],
1378
+ "docs": {
1379
+ "ai": "AI.md",
1380
+ "readme": "README.md"
1381
+ },
1382
+ "install": "npx dokebi add @dokebi/template-ejs"
1383
+ },
1384
+ {
1385
+ "id": "dokebi-template-inertia",
1386
+ "package": "@dokebi/template-inertia",
1387
+ "version": "0.4.1",
1388
+ "kind": "plugin",
1389
+ "summary": "Inertia (v3) server adapter: Vue 3 views, Vite build files and optional server-side rendering (SSR)",
1390
+ "description": "Inertia v3 server adapter for Dokebi: page JSON, Vite manifest assets and optional server-side rendering.",
1391
+ "keywords": [
1392
+ "dokebi",
1393
+ "dokebi-plugin",
1394
+ "web",
1395
+ "views",
1396
+ "inertia",
1397
+ "vue",
1398
+ "ssr"
1399
+ ],
1400
+ "maturity": "preview",
1401
+ "core": "^0.4.0",
1402
+ "provides": [
1403
+ "view.inertia-vue",
1404
+ "view.inertia-vue-ssr"
1405
+ ],
1406
+ "variants": [
1407
+ {
1408
+ "name": "vue",
1409
+ "capability": "view.inertia-vue",
1410
+ "alsoInstalls": [
1411
+ "vite",
1412
+ "vue",
1413
+ "@inertiajs/vue3",
1414
+ "@vitejs/plugin-vue"
1415
+ ],
1416
+ "needs": [
1417
+ "vite-build"
1418
+ ]
1419
+ },
1420
+ {
1421
+ "name": "vue-ssr",
1422
+ "capability": "view.inertia-vue-ssr",
1423
+ "alsoInstalls": [
1424
+ "vite",
1425
+ "vue",
1426
+ "@inertiajs/vue3",
1427
+ "@vitejs/plugin-vue"
1428
+ ],
1429
+ "needs": [
1430
+ "vite-build"
1431
+ ]
1432
+ }
1433
+ ],
1434
+ "doesNot": [
1435
+ "No React skeleton",
1436
+ "Vue and Vite are not server dependencies (they are dev dependencies of the app)"
1437
+ ],
1438
+ "recipes": [
1439
+ "blog"
1440
+ ],
1441
+ "requires": [
1442
+ {
1443
+ "id": "dokebi-web",
1444
+ "range": "^0.4.1"
1445
+ }
1446
+ ],
1447
+ "optional": [
1448
+ {
1449
+ "id": "dokebi-session",
1450
+ "range": "^0.4.0"
1451
+ }
1452
+ ],
1453
+ "optionKeys": [
1454
+ "encryptHistory",
1455
+ "errorPage",
1456
+ "rootId",
1457
+ "scripts",
1458
+ "ssr",
1459
+ "styles",
1460
+ "title",
1461
+ "version",
1462
+ "vite"
1463
+ ],
1464
+ "docs": {
1465
+ "ai": "AI.md",
1466
+ "readme": "README.md"
1467
+ },
1468
+ "install": "npx dokebi add @dokebi/template-inertia"
1469
+ },
1470
+ {
1471
+ "id": "dokebi-web",
1472
+ "package": "@dokebi/web",
1473
+ "version": "0.4.1",
1474
+ "kind": "plugin",
1475
+ "summary": "Fastify 5 HTTP server (503 before ready, health paths, drain, zero-downtime cluster replacement)",
1476
+ "description": "Fastify 5 HTTP server owned by a Dokebi app: 503 before ready, health routes, drain and cluster handover.",
1477
+ "keywords": [
1478
+ "dokebi",
1479
+ "dokebi-plugin",
1480
+ "web",
1481
+ "http",
1482
+ "fastify"
1483
+ ],
1484
+ "maturity": "preview",
1485
+ "core": "^0.4.0",
1486
+ "provides": [
1487
+ "web.http"
1488
+ ],
1489
+ "variants": [],
1490
+ "doesNot": [
1491
+ "No built-in authentication, rate limit, CORS or security headers",
1492
+ "No file upload (multipart)"
1493
+ ],
1494
+ "recipes": [
1495
+ "api",
1496
+ "blog"
1497
+ ],
1498
+ "requires": [],
1499
+ "optional": [
1500
+ {
1501
+ "id": "dokebi-health",
1502
+ "range": "^0.4.0"
1503
+ }
1504
+ ],
1505
+ "optionKeys": [
1506
+ "developmentErrors",
1507
+ "formBody",
1508
+ "formMaxFields",
1509
+ "healthRoutes",
1510
+ "host",
1511
+ "maxBodyBytes",
1512
+ "port",
1513
+ "requestTimeoutMs",
1514
+ "sealDriftMs",
1515
+ "sealExclude",
1516
+ "trustProxy"
1517
+ ],
1518
+ "docs": {
1519
+ "ai": "AI.md",
1520
+ "readme": "README.md"
1521
+ },
1522
+ "install": "npx dokebi add @dokebi/web"
1523
+ },
1524
+ {
1525
+ "id": "dokebi-websocket",
1526
+ "package": "@dokebi/websocket",
1527
+ "version": "0.4.0",
1528
+ "kind": "plugin",
1529
+ "summary": "WebSocket routes, rooms and broadcast on top of dokebi-web (at most once)",
1530
+ "description": "WebSocket routes on @dokebi/web with rooms and broadcast across servers through @dokebi/websocket-hub.",
1531
+ "keywords": [
1532
+ "dokebi",
1533
+ "dokebi-plugin",
1534
+ "web",
1535
+ "websocket",
1536
+ "realtime"
1537
+ ],
1538
+ "maturity": "preview",
1539
+ "core": "^0.4.0",
1540
+ "provides": [
1541
+ "realtime.websocket"
1542
+ ],
1543
+ "variants": [],
1544
+ "doesNot": [
1545
+ "No delivery ACK or redelivery"
1546
+ ],
1547
+ "recipes": [],
1548
+ "requires": [
1549
+ {
1550
+ "id": "dokebi-websocket-hub",
1551
+ "range": "^0.4.0"
1552
+ },
1553
+ {
1554
+ "id": "dokebi-web",
1555
+ "range": "^0.4.0"
1556
+ }
1557
+ ],
1558
+ "optional": [
1559
+ {
1560
+ "id": "dokebi-seal",
1561
+ "range": "^0.4.0"
1562
+ }
1563
+ ],
1564
+ "optionKeys": [
1565
+ "heartbeatMs",
1566
+ "hubWaitMs",
1567
+ "idleTimeoutMs",
1568
+ "maxBufferedBytes",
1569
+ "maxConnections",
1570
+ "maxPayloadBytes",
1571
+ "maxPending",
1572
+ "sealDriftMs",
1573
+ "shutdownTimeoutMs"
1574
+ ],
1575
+ "docs": {
1576
+ "ai": "AI.md",
1577
+ "readme": "README.md"
1578
+ },
1579
+ "install": "npx dokebi add @dokebi/websocket"
1580
+ },
1581
+ {
1582
+ "id": "dokebi-websocket-hub",
1583
+ "package": "@dokebi/websocket-hub",
1584
+ "version": "0.4.0",
1585
+ "kind": "plugin",
1586
+ "summary": "Hub of WebSocket clients, rooms, broadcast and kick (usually used through @dokebi/websocket)",
1587
+ "description": "WebSocket hub for Dokebi: connection roster, rooms, broadcast and kick across workers and servers.",
1588
+ "keywords": [
1589
+ "dokebi",
1590
+ "dokebi-plugin",
1591
+ "websocket",
1592
+ "hub",
1593
+ "realtime"
1594
+ ],
1595
+ "maturity": "preview",
1596
+ "core": "^0.4.0",
1597
+ "provides": [
1598
+ "realtime.hub"
1599
+ ],
1600
+ "variants": [],
1601
+ "doesNot": [
1602
+ "No delivery ACK or redelivery"
1603
+ ],
1604
+ "recipes": [],
1605
+ "requires": [],
1606
+ "optional": [
1607
+ {
1608
+ "id": "dokebi-redis",
1609
+ "range": "^0.4.0"
1610
+ },
1611
+ {
1612
+ "id": "dokebi-nats",
1613
+ "range": "^0.4.0"
1614
+ }
1615
+ ],
1616
+ "optionKeys": [
1617
+ "advertiseHost",
1618
+ "allowInCluster",
1619
+ "host",
1620
+ "leaseMs",
1621
+ "maxConnections",
1622
+ "maxFrameBytes",
1623
+ "maxOwners",
1624
+ "maxPayloadBytes",
1625
+ "maxPending",
1626
+ "maxPendingBytes",
1627
+ "maxTotalConnections",
1628
+ "mode",
1629
+ "namespace",
1630
+ "natsConnection",
1631
+ "ownerTtlMs",
1632
+ "pollIntervalMs",
1633
+ "port",
1634
+ "redisConnection",
1635
+ "secret",
1636
+ "serverId",
1637
+ "startupTimeoutMs"
1638
+ ],
1639
+ "docs": {
1640
+ "ai": "AI.md",
1641
+ "readme": "README.md"
1642
+ },
1643
+ "install": "npx dokebi add @dokebi/websocket-hub"
1644
+ },
1645
+ {
1646
+ "id": "dokebi-worker",
1647
+ "package": "@dokebi/worker",
1648
+ "version": "0.4.0",
1649
+ "kind": "plugin",
1650
+ "summary": "Runs CPU-heavy functions in a worker thread pool",
1651
+ "description": "Worker thread pool for CPU-heavy functions in a Dokebi app.",
1652
+ "keywords": [
1653
+ "dokebi",
1654
+ "dokebi-plugin",
1655
+ "worker-threads",
1656
+ "cpu",
1657
+ "pool"
1658
+ ],
1659
+ "maturity": "preview",
1660
+ "core": "^0.4.0",
1661
+ "provides": [
1662
+ "worker.thread"
1663
+ ],
1664
+ "variants": [],
1665
+ "doesNot": [
1666
+ "Not several processes (cluster)",
1667
+ "Not a distributed job queue (@dokebi/job)"
1668
+ ],
1669
+ "recipes": [],
1670
+ "requires": [],
1671
+ "optional": [],
1672
+ "optionKeys": [
1673
+ "executionTimeoutMs",
1674
+ "maxPending",
1675
+ "maxThreadCrashes",
1676
+ "module",
1677
+ "size",
1678
+ "startupTimeoutMs",
1679
+ "threadCrashWindowMs"
1680
+ ],
1681
+ "docs": {
1682
+ "ai": "AI.md",
1683
+ "readme": null
1684
+ },
1685
+ "install": "npx dokebi add @dokebi/worker"
1686
+ }
1687
+ ],
1688
+ "recipes": [
1689
+ {
1690
+ "name": "api",
1691
+ "summary": "JSON API server (one app, one JSON module and a database of your choice)",
1692
+ "match": [
1693
+ "api",
1694
+ "rest",
1695
+ "json",
1696
+ "backend"
1697
+ ],
1698
+ "capabilities": [
1699
+ "web.apps",
1700
+ "web.modules"
1701
+ ],
1702
+ "questions": [
1703
+ "db",
1704
+ "devInfra"
1705
+ ],
1706
+ "fixed": {
1707
+ "view": "ejs",
1708
+ "admin": "none"
1709
+ },
1710
+ "module": {
1711
+ "name": "items",
1712
+ "views": false,
1713
+ "why": "A feature module that answers JSON: write the API in its routes.ts and controllers"
1714
+ },
1715
+ "web": {
1716
+ "port": 3000,
1717
+ "domain": "localhost"
1718
+ },
1719
+ "then": [
1720
+ "Attach the module to the app: modules: { \"/api/items\": items } in src/apps/main/app.ts"
1721
+ ]
1722
+ },
1723
+ {
1724
+ "name": "blog",
1725
+ "summary": "A blog web app with a post list and post pages (choose the views, database, development database and admin area)",
1726
+ "match": [
1727
+ "blog",
1728
+ "board",
1729
+ "posts",
1730
+ "articles",
1731
+ "cms"
1732
+ ],
1733
+ "capabilities": [
1734
+ "web.apps",
1735
+ "web.modules"
1736
+ ],
1737
+ "questions": [
1738
+ "view",
1739
+ "db",
1740
+ "devInfra",
1741
+ "admin"
1742
+ ],
1743
+ "module": {
1744
+ "name": "posts",
1745
+ "why": "The module for the posts feature: write its controllers, models and routes here"
1746
+ },
1747
+ "web": {
1748
+ "port": 3000,
1749
+ "domain": "localhost",
1750
+ "forms": true
1751
+ },
1752
+ "then": [
1753
+ "Attach the module to the app: modules: { \"/posts\": posts } in src/apps/main/app.ts (posts = the default export of src/shared/modules/posts/module.ts)",
1754
+ "Write the post list (GET /posts) and the post page (GET /posts/:id) in the routes.ts and controllers of the module",
1755
+ "The write form (GET /posts/new → POST /posts) reads request.body (with EJS the recipe turned on dokebi-web.formBody). With --admin none it is a public form (no login); with app-code it belongs to the admin app. Either way it needs a CSRF token check in app code (csrf is absent). A refused post throws validationError({ title: \"Required\" }) from @dokebi/web (D-0074): an EJS form shows data.errors.title and data.old.title (with @dokebi/session the refused post goes back to the form, 303; without it views/default/errors/422.ejs or errors/error.ejs shows the fields), an Inertia form gets them in form.errors (submit with only). Edit the shared layout src/shared/views/layouts/main.ejs where it is"
1756
+ ]
1757
+ }
1758
+ ],
1759
+ "choices": [
1760
+ {
1761
+ "id": "admin",
1762
+ "flag": "--admin",
1763
+ "from": "fixed",
1764
+ "question": "Do you need an admin area (a login that protects writing and managing posts)?",
1765
+ "default": "none",
1766
+ "defaultReason": "There is no auth plugin, so the app would have to write the login itself. When the request does not mention an admin area, none is made; a public write form is still possible (it needs no login)",
1767
+ "options": [
1768
+ {
1769
+ "value": "none",
1770
+ "label": "None (no login and no admin area; a public write form is still possible)",
1771
+ "capability": null,
1772
+ "available": true,
1773
+ "absent": false,
1774
+ "plugins": [],
1775
+ "alsoInstalls": [],
1776
+ "needs": [],
1777
+ "absentFeatures": [],
1778
+ "pros": [
1779
+ "The simplest choice with the smallest attack surface",
1780
+ "Posts can still be written in the browser with a public write form (with EJS the recipe turns on dokebi-web.formBody for it)"
1781
+ ],
1782
+ "cons": [
1783
+ "Without a login anyone who can open the site can use the write form",
1784
+ "The write form has no CSRF protection until the app adds a token check (csrf is absent)"
1785
+ ]
1786
+ },
1787
+ {
1788
+ "value": "app-code",
1789
+ "label": "An admin app written in app code",
1790
+ "capability": null,
1791
+ "available": true,
1792
+ "absent": false,
1793
+ "plugins": [
1794
+ "@dokebi/session"
1795
+ ],
1796
+ "alsoInstalls": [],
1797
+ "needs": [],
1798
+ "absentFeatures": [
1799
+ "auth",
1800
+ "admin.ui"
1801
+ ],
1802
+ "pros": [
1803
+ "One app on its own domain (such as admin.localhost) with sessions is set up"
1804
+ ],
1805
+ "cons": [
1806
+ "Login, password hashing, permission checks and CSRF must be written in app code (there is no plugin)"
1807
+ ]
1808
+ }
1809
+ ]
1810
+ },
1811
+ {
1812
+ "id": "db",
1813
+ "flag": "--db",
1814
+ "from": "variants",
1815
+ "capabilityPrefix": "db.",
1816
+ "question": "Which database should the app use?",
1817
+ "default": "postgres",
1818
+ "defaultReason": "The most widely used default for relational SQL, and it handles migrations, transactions and full-text search well",
1819
+ "options": [
1820
+ {
1821
+ "value": "postgres",
1822
+ "label": "PostgreSQL",
1823
+ "capability": "db.postgres",
1824
+ "available": true,
1825
+ "absent": false,
1826
+ "plugins": [
1827
+ "@dokebi/db"
1828
+ ],
1829
+ "alsoInstalls": [
1830
+ "pg"
1831
+ ],
1832
+ "needs": [],
1833
+ "absentFeatures": [],
1834
+ "pros": [
1835
+ "A general-purpose database with standard SQL, transactions, JSON columns and full-text search",
1836
+ "Many hosting choices (managed databases) for production"
1837
+ ],
1838
+ "cons": [
1839
+ "Needs its own server (one line with docker for development)"
1840
+ ]
1841
+ },
1842
+ {
1843
+ "value": "mysql",
1844
+ "label": "MySQL",
1845
+ "capability": "db.mysql",
1846
+ "available": true,
1847
+ "absent": false,
1848
+ "plugins": [
1849
+ "@dokebi/db"
1850
+ ],
1851
+ "alsoInstalls": [
1852
+ "mysql2"
1853
+ ],
1854
+ "needs": [],
1855
+ "absentFeatures": [],
1856
+ "pros": [
1857
+ "Common on web hosting, with plenty of material"
1858
+ ],
1859
+ "cons": [
1860
+ "Check its lenient defaults (character set, SQL mode)",
1861
+ "Needs its own server"
1862
+ ]
1863
+ },
1864
+ {
1865
+ "value": "mariadb",
1866
+ "label": "MariaDB",
1867
+ "capability": "db.mariadb",
1868
+ "available": true,
1869
+ "absent": false,
1870
+ "plugins": [
1871
+ "@dokebi/db"
1872
+ ],
1873
+ "alsoInstalls": [
1874
+ "mariadb"
1875
+ ],
1876
+ "needs": [],
1877
+ "absentFeatures": [],
1878
+ "pros": [
1879
+ "Open source and MySQL compatible, a default package of Linux distributions"
1880
+ ],
1881
+ "cons": [
1882
+ "Some features differ subtly from MySQL",
1883
+ "Needs its own server"
1884
+ ]
1885
+ },
1886
+ {
1887
+ "value": "mongodb",
1888
+ "label": "MongoDB",
1889
+ "capability": "db.mongodb",
1890
+ "available": true,
1891
+ "absent": false,
1892
+ "plugins": [
1893
+ "@dokebi/db"
1894
+ ],
1895
+ "alsoInstalls": [
1896
+ "mongodb"
1897
+ ],
1898
+ "needs": [],
1899
+ "absentFeatures": [],
1900
+ "pros": [
1901
+ "Stores documents (JSON) without a schema, handy for data whose shape changes often, such as posts"
1902
+ ],
1903
+ "cons": [
1904
+ "Relations, joins and transactions are less convenient than in a SQL database",
1905
+ "Needs its own server"
1906
+ ]
1907
+ },
1908
+ {
1909
+ "value": "sqlite",
1910
+ "label": "SQLite",
1911
+ "capability": "db.sqlite",
1912
+ "available": false,
1913
+ "absent": true,
1914
+ "why": "There is no SQLite adapter or driver template. Choose postgres, mysql, mariadb or mongodb (docker starts one for development right away)",
1915
+ "plugins": [],
1916
+ "alsoInstalls": [],
1917
+ "needs": [],
1918
+ "absentFeatures": [],
1919
+ "pros": [],
1920
+ "cons": []
1921
+ },
1922
+ {
1923
+ "value": "none",
1924
+ "label": "No database",
1925
+ "kind": "none",
1926
+ "capability": null,
1927
+ "available": true,
1928
+ "absent": false,
1929
+ "plugins": [],
1930
+ "alsoInstalls": [],
1931
+ "needs": [],
1932
+ "absentFeatures": [],
1933
+ "pros": [
1934
+ "The simplest to install and run"
1935
+ ],
1936
+ "cons": [
1937
+ "Posts are not stored (the app handles memory or files itself)"
1938
+ ]
1939
+ }
1940
+ ]
1941
+ },
1942
+ {
1943
+ "id": "devInfra",
1944
+ "flag": "--dev-infra",
1945
+ "from": "fixed",
1946
+ "when": {
1947
+ "db": "!none"
1948
+ },
1949
+ "question": "How should the development database server be provided?",
1950
+ "default": "docker",
1951
+ "defaultReason": "One compose.yaml starts and removes a database of the same version without installing anything",
1952
+ "options": [
1953
+ {
1954
+ "value": "docker",
1955
+ "label": "Start it with Docker (compose.yaml)",
1956
+ "capability": null,
1957
+ "available": true,
1958
+ "absent": false,
1959
+ "plugins": [],
1960
+ "alsoInstalls": [],
1961
+ "needs": [
1962
+ "docker"
1963
+ ],
1964
+ "absentFeatures": [],
1965
+ "pros": [
1966
+ "dokebi dev-infra writes compose.yaml, .env (the password) and the connection URL in dokebi.yaml",
1967
+ "A separate database per project, easy to remove"
1968
+ ],
1969
+ "cons": [
1970
+ "Docker must be installed and running",
1971
+ "When the port is taken, choose another one with --db-port (it is never changed behind your back)"
1972
+ ]
1973
+ },
1974
+ {
1975
+ "value": "url",
1976
+ "label": "Connect to a database server you already have",
1977
+ "capability": null,
1978
+ "available": true,
1979
+ "absent": false,
1980
+ "plugins": [],
1981
+ "alsoInstalls": [],
1982
+ "needs": [],
1983
+ "absentFeatures": [],
1984
+ "pros": [
1985
+ "No Docker needed"
1986
+ ],
1987
+ "cons": [
1988
+ "You write the connection URL (with its password) into dokebi.yaml yourself (never pass it with --set)"
1989
+ ]
1990
+ }
1991
+ ]
1992
+ },
1993
+ {
1994
+ "id": "view",
1995
+ "flag": "--view",
1996
+ "from": "variants",
1997
+ "capabilityPrefix": "view.",
1998
+ "question": "What should the views (screens) be built with?",
1999
+ "default": "ejs",
2000
+ "defaultReason": "No build step and it runs right away on one server. Enough for blog screens such as the post list and a post page",
2001
+ "options": [
2002
+ {
2003
+ "value": "ejs",
2004
+ "label": "EJS server rendering",
2005
+ "capability": "view.ejs",
2006
+ "available": true,
2007
+ "absent": false,
2008
+ "plugins": [
2009
+ "@dokebi/template-ejs"
2010
+ ],
2011
+ "alsoInstalls": [],
2012
+ "needs": [],
2013
+ "absentFeatures": [],
2014
+ "pros": [
2015
+ "Runs right away without a build (Vite)",
2016
+ "The server sends finished HTML, good for search engines and slow devices",
2017
+ "Few files, easy to learn first"
2018
+ ],
2019
+ "cons": [
2020
+ "Every page change loads the whole page again",
2021
+ "Rich interaction on a page needs hand-written JavaScript"
2022
+ ]
2023
+ },
2024
+ {
2025
+ "value": "inertia-vue",
2026
+ "label": "Inertia + Vue 3",
2027
+ "capability": "view.inertia-vue",
2028
+ "available": true,
2029
+ "absent": false,
2030
+ "plugins": [
2031
+ "@dokebi/template-inertia"
2032
+ ],
2033
+ "alsoInstalls": [
2034
+ "vite",
2035
+ "vue",
2036
+ "@inertiajs/vue3",
2037
+ "@vitejs/plugin-vue"
2038
+ ],
2039
+ "needs": [
2040
+ "vite-build"
2041
+ ],
2042
+ "absentFeatures": [],
2043
+ "pros": [
2044
+ "Fast page changes that feel like a SPA, with screens split into components",
2045
+ "Server routes and controllers stay as they are (no separate API)"
2046
+ ],
2047
+ "cons": [
2048
+ "Needs npm run build (Vite) and installs vue and vite",
2049
+ "The browser draws the first screen after running JavaScript (worse for search engines)"
2050
+ ]
2051
+ },
2052
+ {
2053
+ "value": "inertia-vue-ssr",
2054
+ "label": "Inertia + Vue 3 + server rendering",
2055
+ "capability": "view.inertia-vue-ssr",
2056
+ "available": true,
2057
+ "absent": false,
2058
+ "plugins": [
2059
+ "@dokebi/template-inertia"
2060
+ ],
2061
+ "alsoInstalls": [
2062
+ "vite",
2063
+ "vue",
2064
+ "@inertiajs/vue3",
2065
+ "@vitejs/plugin-vue"
2066
+ ],
2067
+ "needs": [
2068
+ "vite-build"
2069
+ ],
2070
+ "absentFeatures": [],
2071
+ "pros": [
2072
+ "The strengths of Inertia, and the server draws the first HTML, so search engines and the first paint are fast"
2073
+ ],
2074
+ "cons": [
2075
+ "Two builds (browser and server) and the most configuration",
2076
+ "Uses more server memory and CPU"
2077
+ ]
2078
+ },
2079
+ {
2080
+ "value": "inertia-react",
2081
+ "label": "Inertia + React",
2082
+ "capability": "view.inertia-react",
2083
+ "available": false,
2084
+ "absent": true,
2085
+ "why": "There is no Inertia React skeleton (Vue 3 only). Choose inertia-vue or use EJS. If React is a must, tell the user and set it up by hand",
2086
+ "plugins": [],
2087
+ "alsoInstalls": [],
2088
+ "needs": [],
2089
+ "absentFeatures": [],
2090
+ "pros": [],
2091
+ "cons": []
2092
+ }
2093
+ ]
2094
+ }
2095
+ ],
2096
+ "absent": [
2097
+ {
2098
+ "capability": "admin.ui",
2099
+ "summary": "There are no generated admin screens (CRUD generator)",
2100
+ "instead": "Create one more app with dokebi app add admin --domain admin.localhost and write its screens in app code (there is no auth either, so the app writes the login)",
2101
+ "verify": [
2102
+ "no-provider"
2103
+ ]
2104
+ },
2105
+ {
2106
+ "capability": "auth",
2107
+ "summary": "There is no login, sign-up or permission plugin",
2108
+ "instead": "Write it in app code. Keep the login state in @dokebi/session and hash passwords with scrypt from node:crypto. Install an outside auth library only with the permission of the user",
2109
+ "verify": [
2110
+ "no-provider"
2111
+ ]
2112
+ },
2113
+ {
2114
+ "capability": "csrf",
2115
+ "summary": "There is no CSRF token plugin",
2116
+ "instead": "The app keeps a random token in the session and compares it with a hidden form field or a header (the @dokebi/session AI.md says what sameSite does and does not block)",
2117
+ "verify": [
2118
+ "no-provider"
2119
+ ]
2120
+ },
2121
+ {
2122
+ "capability": "db.sqlite",
2123
+ "summary": "There is no SQLite adapter or driver template",
2124
+ "instead": "Choose postgres, mysql, mariadb or mongodb (docker starts one for development right away)",
2125
+ "verify": [
2126
+ "no-provider"
2127
+ ]
2128
+ },
2129
+ {
2130
+ "capability": "i18n",
2131
+ "summary": "There is no i18n plugin",
2132
+ "instead": "Keep an object of strings per language in app code",
2133
+ "verify": [
2134
+ "no-provider"
2135
+ ]
2136
+ },
2137
+ {
2138
+ "capability": "mail",
2139
+ "summary": "There is no mail plugin",
2140
+ "instead": "With the permission of the user, use an SMTP library in app code. Mail that must be sent goes through an @dokebi/job job",
2141
+ "verify": [
2142
+ "no-provider"
2143
+ ]
2144
+ },
2145
+ {
2146
+ "capability": "markdown",
2147
+ "summary": "There is no Markdown converter",
2148
+ "instead": "Store and show post bodies as plain text (EJS escapes with <%= %>), or use a Markdown library with the permission of the user",
2149
+ "verify": [
2150
+ "no-provider"
2151
+ ]
2152
+ },
2153
+ {
2154
+ "capability": "orm",
2155
+ "summary": "There is no ORM or query builder (use the driver API as it is)",
2156
+ "instead": "Query with the pg, mysql2, mariadb or mongodb API that connection(main) of @dokebi/db returns (main is the connection definition in src/infra/db/connections.ts)",
2157
+ "verify": [
2158
+ "no-provider"
2159
+ ]
2160
+ },
2161
+ {
2162
+ "capability": "rate-limit",
2163
+ "summary": "There is no rate limit plugin",
2164
+ "instead": "Limit requests in the front proxy (nginx or similar), or register a Fastify plugin with the permission of the user",
2165
+ "verify": [
2166
+ "no-provider"
2167
+ ]
2168
+ },
2169
+ {
2170
+ "capability": "rss",
2171
+ "summary": "There is no RSS or Atom feed generator",
2172
+ "instead": "Build the XML string in a controller and answer with application/rss+xml",
2173
+ "verify": [
2174
+ "no-provider"
2175
+ ]
2176
+ },
2177
+ {
2178
+ "capability": "search",
2179
+ "summary": "There is no full-text search plugin",
2180
+ "instead": "Use LIKE or the full-text search of the database (such as postgres tsvector) in app code",
2181
+ "verify": [
2182
+ "no-provider"
2183
+ ]
2184
+ },
2185
+ {
2186
+ "capability": "upload",
2187
+ "summary": "There is no file upload (multipart) plugin",
2188
+ "instead": "With the permission of the user the app registers a Fastify multipart plugin, or it starts without uploads",
2189
+ "verify": [
2190
+ "no-provider"
2191
+ ]
2192
+ },
2193
+ {
2194
+ "capability": "view.inertia-react",
2195
+ "summary": "There is no Inertia React skeleton (Vue 3 only)",
2196
+ "instead": "Choose inertia-vue or use EJS. If React is a must, tell the user and set it up by hand",
2197
+ "verify": [
2198
+ "no-provider",
2199
+ "no-flag:app add --react"
2200
+ ]
2201
+ }
2202
+ ]
2203
+ }