create-m5kdev 0.33.0 → 0.35.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 (147) hide show
  1. package/dist/src/catalog.cjs +21 -1
  2. package/dist/src/catalog.cjs.map +1 -1
  3. package/dist/src/catalog.d.cts +3 -1
  4. package/dist/src/create.cjs +6 -2
  5. package/dist/src/create.cjs.map +1 -1
  6. package/dist/src/doctor.cjs.map +1 -1
  7. package/dist/src/fs.cjs +10 -5
  8. package/dist/src/fs.cjs.map +1 -1
  9. package/dist/src/prompts.cjs +32 -0
  10. package/dist/src/prompts.cjs.map +1 -1
  11. package/dist/src/prompts.d.cts +7 -1
  12. package/dist/src/template.cjs +23 -4
  13. package/dist/src/template.cjs.map +1 -1
  14. package/dist/src/template.d.cts +17 -3
  15. package/dist/src/types.d.cts +11 -4
  16. package/package.json +4 -1
  17. package/templates/minimal-app/.cursor/rules/frontend-data-guide.mdc +1 -0
  18. package/templates/minimal-app/.cursor/rules/module-dto-guide.mdc +1 -1
  19. package/templates/minimal-app/.cursor/rules/module-grants-guide.mdc +3 -3
  20. package/templates/minimal-app/.cursor/rules/module-module-guide.mdc +3 -2
  21. package/templates/minimal-app/.cursor/rules/module-service-guide.mdc +1 -1
  22. package/templates/minimal-app/.cursor/rules/server-event-emit.mdc +41 -0
  23. package/templates/minimal-app/.dockerignore.tpl +31 -0
  24. package/templates/minimal-app/.gitignore.tpl +1 -0
  25. package/templates/minimal-app/AGENTS.md.tpl +14 -10
  26. package/templates/minimal-app/CLAUDE.md.tpl +133 -131
  27. package/templates/minimal-app/README.md.tpl +51 -19
  28. package/templates/minimal-app/apps/e2e/package.json.tpl +23 -23
  29. package/templates/minimal-app/apps/e2e/playwright.config.ts.tpl +51 -39
  30. package/templates/minimal-app/apps/e2e/playwright.expo.config.ts.tpl +38 -38
  31. package/templates/minimal-app/apps/e2e/servers.ts.tpl +136 -112
  32. package/templates/minimal-app/apps/e2e/tests/conversation.spec.ts.tpl +22 -0
  33. package/templates/minimal-app/apps/e2e/tests/email.spec.ts.tpl +47 -47
  34. package/templates/minimal-app/apps/e2e/tests/expo-helpers.ts.tpl +73 -73
  35. package/templates/minimal-app/apps/e2e/tests/expo-standard.spec.ts.tpl +517 -517
  36. package/templates/minimal-app/apps/e2e/tests/expo-waitlist.spec.ts.tpl +94 -94
  37. package/templates/minimal-app/apps/e2e/tests/files.spec.ts.tpl +35 -0
  38. package/templates/minimal-app/apps/e2e/tests/helpers.ts.tpl +289 -289
  39. package/templates/minimal-app/apps/e2e/tests/standard.spec.ts.tpl +516 -516
  40. package/templates/minimal-app/apps/e2e/tests/waitlist.spec.ts.tpl +107 -107
  41. package/templates/minimal-app/apps/e2e/tests/workflow.spec.ts.tpl +26 -0
  42. package/templates/minimal-app/apps/e2e/tsconfig.json.tpl +10 -10
  43. package/templates/minimal-app/apps/email/package.json.tpl +34 -34
  44. package/templates/minimal-app/apps/email/src/emails/trialEndingEmail.tsx.tpl +40 -0
  45. package/templates/minimal-app/apps/email/src/index.ts.tpl +7 -0
  46. package/templates/minimal-app/apps/email/src/resources.ts.tpl +72 -65
  47. package/templates/minimal-app/apps/expo/app.json.tpl +36 -36
  48. package/templates/minimal-app/apps/expo/eslint.config.js.tpl +8 -8
  49. package/templates/minimal-app/apps/expo/metro.config.js.tpl +16 -16
  50. package/templates/minimal-app/apps/expo/src/app/_layout.tsx.tpl +31 -31
  51. package/templates/minimal-app/apps/expo/src/app/claim-account.tsx.tpl +151 -151
  52. package/templates/minimal-app/apps/expo/src/app/forgot-password.tsx.tpl +53 -53
  53. package/templates/minimal-app/apps/expo/src/app/index.tsx.tpl +8 -8
  54. package/templates/minimal-app/apps/expo/src/app/login.tsx.tpl +71 -71
  55. package/templates/minimal-app/apps/expo/src/app/logout.tsx.tpl +19 -19
  56. package/templates/minimal-app/apps/expo/src/app/organization/accept-invitation.tsx.tpl +85 -85
  57. package/templates/minimal-app/apps/expo/src/app/posts.tsx.tpl +40 -40
  58. package/templates/minimal-app/apps/expo/src/app/reset-password.tsx.tpl +75 -75
  59. package/templates/minimal-app/apps/expo/src/app/signup.tsx.tpl +193 -193
  60. package/templates/minimal-app/apps/expo/src/components/AuthScaffold.tsx.tpl +34 -34
  61. package/templates/minimal-app/apps/expo/src/components/FormTextField.tsx.tpl +37 -37
  62. package/templates/minimal-app/apps/expo/src/components/LoadingScreen.tsx.tpl +10 -10
  63. package/templates/minimal-app/apps/expo/src/components/StatusText.tsx.tpl +22 -22
  64. package/templates/minimal-app/apps/expo/src/config.ts.tpl +9 -9
  65. package/templates/minimal-app/apps/expo/src/global.css.tpl +11 -11
  66. package/templates/minimal-app/apps/expo/src/lib/trpc.ts.tpl +20 -20
  67. package/templates/minimal-app/apps/expo/tsconfig.json.tpl +11 -11
  68. package/templates/minimal-app/apps/expo/uniwind-env.d.ts.tpl +1 -1
  69. package/templates/minimal-app/apps/landing/.env.production.example.tpl +7 -0
  70. package/templates/minimal-app/apps/landing/Dockerfile.tpl +39 -0
  71. package/templates/minimal-app/apps/landing/fly.toml.tpl +20 -0
  72. package/templates/minimal-app/apps/landing/index.html.tpl +35 -0
  73. package/templates/minimal-app/apps/landing/package.json.tpl +34 -0
  74. package/templates/minimal-app/apps/landing/src/App.tsx.tpl +12 -0
  75. package/templates/minimal-app/apps/landing/src/LandingPage.tsx.tpl +37 -0
  76. package/templates/minimal-app/apps/landing/src/index.css.tpl +24 -0
  77. package/templates/minimal-app/apps/landing/src/main.tsx.tpl +16 -0
  78. package/templates/minimal-app/apps/landing/src/vite-env.d.ts.tpl +11 -0
  79. package/templates/minimal-app/apps/landing/tsconfig.json.tpl +12 -0
  80. package/templates/minimal-app/apps/landing/vite.config.ts.tpl +25 -0
  81. package/templates/minimal-app/apps/server/AGENTS.md.tpl +55 -46
  82. package/templates/minimal-app/apps/server/{drizzle/seed.e2e.ts.tpl → db.e2e.ts.tpl} +57 -40
  83. package/templates/minimal-app/apps/server/{drizzle/seed.ts.tpl → db.ts.tpl} +27 -20
  84. package/templates/minimal-app/apps/server/drizzle/0003_silly_the_liberteens.sql +27 -0
  85. package/templates/minimal-app/apps/server/drizzle/meta/0000_snapshot.json.tpl +56 -166
  86. package/templates/minimal-app/apps/server/drizzle/meta/0001_snapshot.json.tpl +1796 -1910
  87. package/templates/minimal-app/apps/server/drizzle/meta/0002_snapshot.json.tpl +1818 -1932
  88. package/templates/minimal-app/apps/server/drizzle/meta/0003_snapshot.json.tpl +2137 -0
  89. package/templates/minimal-app/apps/server/drizzle/meta/_journal.json.tpl +8 -1
  90. package/templates/minimal-app/apps/server/drizzle.config.ts.tpl +3 -33
  91. package/templates/minimal-app/apps/server/package.json.tpl +5 -3
  92. package/templates/minimal-app/apps/server/src/app.ts.tpl +36 -0
  93. package/templates/minimal-app/apps/server/src/modules/conversation/conversation.mastra.ts.tpl +26 -0
  94. package/templates/minimal-app/apps/server/src/modules/demo-workflow/demo-workflow.module.ts.tpl +51 -0
  95. package/templates/minimal-app/apps/server/src/modules/demo-workflow/demo-workflow.service.ts.tpl +51 -0
  96. package/templates/minimal-app/apps/server/src/modules/demo-workflow/demo-workflow.trpc.ts.tpl +16 -0
  97. package/templates/minimal-app/apps/server/src/modules/posts/posts.db.ts.tpl +28 -28
  98. package/templates/minimal-app/apps/server/src/modules/posts/posts.grants.ts.tpl +28 -28
  99. package/templates/minimal-app/apps/server/src/modules/posts/posts.module.ts.tpl +57 -54
  100. package/templates/minimal-app/apps/server/src/modules/posts/posts.repository.ts.tpl +67 -67
  101. package/templates/minimal-app/apps/server/src/modules/posts/posts.service.ts.tpl +116 -116
  102. package/templates/minimal-app/apps/server/src/modules/posts/posts.trpc.ts.tpl +37 -37
  103. package/templates/minimal-app/apps/server/src/modules/test-harness/test-harness.module.ts.tpl +279 -279
  104. package/templates/minimal-app/apps/server/src/schema.ts.tpl +31 -20
  105. package/templates/minimal-app/apps/server/src/types.ts.tpl +12 -12
  106. package/templates/minimal-app/apps/server/tsconfig.json.tpl +1 -1
  107. package/templates/minimal-app/apps/server/tsup.config.ts.tpl +23 -9
  108. package/templates/minimal-app/apps/shared/.env.example.tpl +5 -0
  109. package/templates/minimal-app/apps/shared/.env.production.example.tpl +23 -0
  110. package/templates/minimal-app/apps/shared/.env.tpl +5 -0
  111. package/templates/minimal-app/apps/shared/Dockerfile.tpl +48 -0
  112. package/templates/minimal-app/apps/shared/fly.toml.tpl +24 -0
  113. package/templates/minimal-app/apps/shared/package.json.tpl +26 -24
  114. package/templates/minimal-app/apps/shared/src/modules/app/app.constants.ts.tpl +28 -28
  115. package/templates/minimal-app/apps/shared/src/modules/conversation/conversation.constants.ts.tpl +1 -0
  116. package/templates/minimal-app/apps/shared/src/modules/demo-workflow/demo-workflow.constants.ts.tpl +1 -0
  117. package/templates/minimal-app/apps/shared/src/modules/notification/notification.schema.ts.tpl +3 -3
  118. package/templates/minimal-app/apps/shared/src/modules/posts/posts.constants.ts.tpl +5 -5
  119. package/templates/minimal-app/apps/shared/src/modules/posts/posts.schema.ts.tpl +25 -25
  120. package/templates/minimal-app/apps/webapp/package.json.tpl +53 -53
  121. package/templates/minimal-app/apps/webapp/public/push-sw.js.tpl +34 -34
  122. package/templates/minimal-app/apps/webapp/src/App.tsx.tpl +49 -44
  123. package/templates/minimal-app/apps/webapp/src/Layout.tsx.tpl +96 -65
  124. package/templates/minimal-app/apps/webapp/src/Router.tsx.tpl +114 -93
  125. package/templates/minimal-app/apps/webapp/src/StarterServerEventProvider.tsx.tpl +38 -0
  126. package/templates/minimal-app/apps/webapp/src/index.css.tpl +15 -15
  127. package/templates/minimal-app/apps/webapp/src/main.tsx.tpl +26 -26
  128. package/templates/minimal-app/apps/webapp/src/modules/conversation/ConversationRoute.tsx.tpl +36 -0
  129. package/templates/minimal-app/apps/webapp/src/modules/files/FilesRoute.tsx.tpl +88 -0
  130. package/templates/minimal-app/apps/webapp/src/modules/files/hooks/useFilesRoute.ts.tpl +50 -0
  131. package/templates/minimal-app/apps/webapp/src/modules/workflows/WorkflowsRoute.tsx.tpl +97 -0
  132. package/templates/minimal-app/apps/webapp/src/modules/workflows/hooks/useWorkflowsRoute.ts.tpl +64 -0
  133. package/templates/minimal-app/apps/webapp/src/utils/i18n.ts.tpl +13 -13
  134. package/templates/minimal-app/apps/webapp/src/utils/trpc.ts.tpl +10 -10
  135. package/templates/minimal-app/apps/webapp/src/vite-env.d.ts.tpl +1 -1
  136. package/templates/minimal-app/apps/webapp/translations/en/app.json.tpl +7 -7
  137. package/templates/minimal-app/apps/webapp/translations/en/{{APP_SLUG}}.json.tpl +193 -135
  138. package/templates/minimal-app/apps/webapp/tsconfig.json.tpl +17 -17
  139. package/templates/minimal-app/apps/webapp/vite.config.ts.tpl +31 -31
  140. package/templates/minimal-app/biome.json.tpl +17 -12
  141. package/templates/minimal-app/package.json.tpl +7 -2
  142. package/templates/minimal-app/pnpm-workspace.yaml.tpl +14 -7
  143. package/templates/minimal-app/template.manifest.json +93 -2
  144. package/templates/minimal-app/apps/server/drizzle/db.ts.tpl +0 -26
  145. package/templates/minimal-app/apps/server/drizzle/guard.ts.tpl +0 -36
  146. package/templates/minimal-app/apps/server/drizzle/reset.ts.tpl +0 -40
  147. package/templates/minimal-app/apps/server/drizzle/sync.ts.tpl +0 -16
@@ -1,31 +1,31 @@
1
- import path from "node:path";
2
- import tailwindcss from "@tailwindcss/vite";
3
- import react from "@vitejs/plugin-react";
4
- import { defineConfig } from "vite";
5
- import i18nextLoader from "vite-plugin-i18next-loader";
6
- import tsconfigPaths from "vite-tsconfig-paths";
7
-
8
- export default defineConfig({
9
- root: __dirname,
10
- plugins: [
11
- tailwindcss(),
12
- react({
13
- babel: {
14
- plugins: ["babel-plugin-react-compiler"],
15
- },
16
- }),
17
- tsconfigPaths(),
18
- i18nextLoader({
19
- include: ["**/*.json"],
20
- paths: [
21
- path.resolve(__dirname, "./node_modules/@m5kdev/web-ui/dist/translations"),
22
- path.resolve(__dirname, "./translations"),
23
- ],
24
- namespaceResolution: "basename",
25
- }),
26
- ],
27
- resolve: {
28
- dedupe: ["react", "react-dom", "react-i18next", "react-router", "nuqs"],
29
- },
30
- envDir: "../shared",
31
- });
1
+ import path from "node:path";
2
+ import tailwindcss from "@tailwindcss/vite";
3
+ import react from "@vitejs/plugin-react";
4
+ import { defineConfig } from "vite";
5
+ import i18nextLoader from "vite-plugin-i18next-loader";
6
+ import tsconfigPaths from "vite-tsconfig-paths";
7
+
8
+ export default defineConfig({
9
+ root: __dirname,
10
+ plugins: [
11
+ tailwindcss(),
12
+ react({
13
+ babel: {
14
+ plugins: ["babel-plugin-react-compiler"],
15
+ },
16
+ }),
17
+ tsconfigPaths(),
18
+ i18nextLoader({
19
+ include: ["**/*.json"],
20
+ paths: [
21
+ path.resolve(__dirname, "./node_modules/@m5kdev/web-ui/dist/translations"),
22
+ path.resolve(__dirname, "./translations"),
23
+ ],
24
+ namespaceResolution: "basename",
25
+ }),
26
+ ],
27
+ resolve: {
28
+ dedupe: ["react", "react-dom", "react-i18next", "react-router", "nuqs"],
29
+ },
30
+ envDir: "../shared",
31
+ });
@@ -1,5 +1,5 @@
1
1
  {
2
- "$schema": "https://biomejs.dev/schemas/2.2.0/schema.json",
2
+ "$schema": "https://biomejs.dev/schemas/2.5.9/schema.json",
3
3
  "vcs": {
4
4
  "enabled": false,
5
5
  "clientKind": "git",
@@ -7,27 +7,27 @@
7
7
  },
8
8
  "files": {
9
9
  "ignoreUnknown": false,
10
- "includes": [
11
- "**",
12
- "!**/node_modules",
13
- "!**/dist",
14
- "!**/.react-router",
15
- "!**/.m5kdev.json",
16
- "!**/drizzle/meta"
17
- ]
10
+ "includes": [
11
+ "**",
12
+ "!**/node_modules",
13
+ "!!**/dist",
14
+ "!!**/storybook-static",
15
+ "!**/.react-router",
16
+ "!**/.m5kdev.json",
17
+ "!**/drizzle/meta"
18
+ ]
18
19
  },
19
20
  "formatter": {
20
21
  "enabled": true,
21
22
  "indentWidth": 2,
22
23
  "indentStyle": "space",
23
24
  "lineWidth": 100,
24
- "lineEnding": "lf"
25
+ "lineEnding": "lf"
25
26
  },
26
27
  "linter": {
27
28
  "enabled": true,
28
29
  "rules": {
29
- "nursery": {},
30
- "recommended": true,
30
+ "preset": "recommended",
31
31
  "correctness": {
32
32
  "noUnusedVariables": "warn",
33
33
  "useExhaustiveDependencies": "warn",
@@ -72,6 +72,11 @@
72
72
  "semicolons": "always"
73
73
  }
74
74
  },
75
+ "css": {
76
+ "parser": {
77
+ "tailwindDirectives": true
78
+ }
79
+ },
75
80
  "assist": {
76
81
  "enabled": true,
77
82
  "actions": {
@@ -7,15 +7,20 @@
7
7
  "dev": "turbo run dev",
8
8
  "lint": "turbo run lint",
9
9
  "lint:fix": "turbo run lint:fix",
10
- "check-types": "turbo run check-types"
10
+ "check-types": "turbo run check-types",
11
+ "app:deploy": "m5kdev-fly-deploy --config apps/shared/fly.toml --dockerfile apps/shared/Dockerfile --env apps/shared/.env.production",
12
+ "app:secrets": "m5kdev-fly-secrets --config apps/shared/fly.toml --env apps/shared/.env.production",
13
+ "landing:deploy": "m5kdev-fly-deploy --config apps/landing/fly.toml --dockerfile apps/landing/Dockerfile --env apps/landing/.env.production",
14
+ "landing:secrets": "m5kdev-fly-secrets --config apps/landing/fly.toml --env apps/landing/.env.production"
11
15
  },
12
16
  "devDependencies": {
13
17
  "@biomejs/biome": "catalog:m5kdev",
18
+ "@m5kdev/backend": "catalog:m5kdev",
14
19
  "turbo": "catalog:m5kdev",
15
20
  "typescript": "catalog:m5kdev"
16
21
  },
17
22
  "packageManager": "pnpm@10.13.1",
18
23
  "engines": {
19
- "node": ">=22"
24
+ "node": ">=24"
20
25
  }
21
26
  }
@@ -3,16 +3,23 @@ packages:
3
3
  catalog: {}
4
4
  catalogs:
5
5
  m5kdev:
6
- "@biomejs/biome": 2.2.0
6
+ "@biomejs/biome": 2.5.9
7
7
  "@heroui/react": 3.0.3
8
8
  "@heroui/styles": 3.0.3
9
9
  "@libsql/client": 0.17.4
10
- "@m5kdev/backend": 0.33.0
11
- "@m5kdev/commons": 0.33.0
12
- "@m5kdev/config": 0.33.0
13
- "@m5kdev/email": 0.33.0
14
- "@m5kdev/frontend": 0.33.0
15
- "@m5kdev/web-ui": 0.33.0
10
+ "@m5kdev/backend": 0.35.0
11
+ "@m5kdev/commons": 0.35.0
12
+ "@m5kdev/config": 0.35.0
13
+ "@m5kdev/email": 0.35.0
14
+ "@m5kdev/frontend": 0.35.0
15
+ "@m5kdev/module-clay": 0.35.0
16
+ "@m5kdev/module-docx": 0.35.0
17
+ "@m5kdev/module-pdf": 0.35.0
18
+ "@m5kdev/module-social": 0.35.0
19
+ "@m5kdev/module-video": 0.35.0
20
+ "@m5kdev/web-ui": 0.35.0
21
+ "@mastra/core": 1.51.0
22
+ "@openrouter/ai-sdk-provider": 3.0.0
16
23
  "@opentelemetry/api": 1.9.0
17
24
  "@playwright/test": 1.57.0
18
25
  "@react-email/components": 1.0.1
@@ -2,21 +2,87 @@
2
2
  "schemaVersion": 1,
3
3
  "features": {
4
4
  "test-harness": {
5
+ "kind": "harness",
5
6
  "paths": [
6
7
  "apps/e2e/",
7
8
  "apps/server/src/modules/test-harness/",
8
- "apps/server/drizzle/seed.e2e.ts"
9
+ "apps/server/db.e2e.ts"
9
10
  ]
10
11
  },
11
12
  "webapp": {
13
+ "kind": "platform",
12
14
  "paths": [
13
15
  "apps/webapp/"
14
16
  ]
15
17
  },
16
18
  "expo": {
19
+ "kind": "platform",
17
20
  "paths": [
18
21
  "apps/expo/"
19
22
  ]
23
+ },
24
+ "billing": {
25
+ "kind": "module",
26
+ "label": "Billing",
27
+ "paths": []
28
+ },
29
+ "files": {
30
+ "kind": "module",
31
+ "label": "Files",
32
+ "paths": [
33
+ "apps/webapp/src/modules/files/",
34
+ "apps/e2e/tests/files.spec.ts"
35
+ ]
36
+ },
37
+ "workflows": {
38
+ "kind": "module",
39
+ "label": "Workflows",
40
+ "paths": [
41
+ "apps/webapp/src/modules/workflows/",
42
+ "apps/server/src/modules/demo-workflow/",
43
+ "apps/shared/src/modules/demo-workflow/",
44
+ "apps/e2e/tests/workflow.spec.ts"
45
+ ]
46
+ },
47
+ "ai": {
48
+ "kind": "module",
49
+ "label": "AI",
50
+ "paths": [
51
+ "apps/webapp/src/modules/conversation/",
52
+ "apps/server/src/modules/conversation/",
53
+ "apps/shared/src/modules/conversation/",
54
+ "apps/e2e/tests/conversation.spec.ts"
55
+ ]
56
+ },
57
+ "notifications": {
58
+ "kind": "module",
59
+ "label": "Notifications",
60
+ "experimental": true,
61
+ "paths": []
62
+ },
63
+ "tags": {
64
+ "kind": "module",
65
+ "label": "Tags",
66
+ "experimental": true,
67
+ "paths": []
68
+ },
69
+ "connect": {
70
+ "kind": "module",
71
+ "label": "Connect",
72
+ "experimental": true,
73
+ "paths": []
74
+ },
75
+ "recurrence": {
76
+ "kind": "module",
77
+ "label": "Recurrence",
78
+ "experimental": true,
79
+ "paths": []
80
+ },
81
+ "webhook": {
82
+ "kind": "module",
83
+ "label": "Webhook",
84
+ "experimental": true,
85
+ "paths": []
20
86
  }
21
87
  },
22
88
  "requiredPaths": [
@@ -24,7 +90,8 @@
24
90
  "pnpm-workspace.yaml",
25
91
  "apps/shared/package.json",
26
92
  "apps/server/package.json",
27
- "apps/email/package.json"
93
+ "apps/email/package.json",
94
+ "apps/landing/package.json"
28
95
  ],
29
96
  "sync": {
30
97
  "defaultPolicy": "merge",
@@ -37,6 +104,18 @@
37
104
  "pattern": "**/.env",
38
105
  "policy": "ignore"
39
106
  },
107
+ {
108
+ "pattern": ".env.production",
109
+ "policy": "ignore"
110
+ },
111
+ {
112
+ "pattern": "**/.env.production",
113
+ "policy": "ignore"
114
+ },
115
+ {
116
+ "pattern": "**/fly.toml",
117
+ "policy": "ignore"
118
+ },
40
119
  {
41
120
  "pattern": "**/drizzle/*.sql",
42
121
  "policy": "ignore"
@@ -44,6 +123,18 @@
44
123
  {
45
124
  "pattern": "**/drizzle/meta/**",
46
125
  "policy": "ignore"
126
+ },
127
+ {
128
+ "pattern": "apps/server/db.ts",
129
+ "policy": "ensure"
130
+ },
131
+ {
132
+ "pattern": "apps/server/db.e2e.ts",
133
+ "policy": "ensure"
134
+ },
135
+ {
136
+ "pattern": "apps/server/drizzle.config.ts",
137
+ "policy": "ensure"
47
138
  }
48
139
  ],
49
140
  "renames": []
@@ -1,26 +0,0 @@
1
- import { createClient } from "@libsql/client";
2
- import { drizzle } from "drizzle-orm/libsql";
3
- import * as schema from "../src/schema";
4
-
5
- /**
6
- * Standalone DB handle for scripts (seed, maintenance). Deliberately does NOT
7
- * import ./app — constructing the backend app opens Redis/queue connections
8
- * that keep short-lived scripts alive forever. The running server gets its own
9
- * connection through createBackendApp.
10
- */
11
- const databaseUrl = process.env.DATABASE_URL ?? "file:./local.db";
12
- const syncUrl = process.env.TURSO_DATABASE_URL;
13
- const authToken = process.env.TURSO_AUTH_TOKEN;
14
-
15
- export const isRemote = syncUrl && authToken;
16
-
17
- const client = createClient(
18
- isRemote ? { url: databaseUrl, syncUrl, authToken } : { url: databaseUrl }
19
- );
20
-
21
- export const orm = drizzle(client, { schema });
22
-
23
- export type Orm = typeof orm;
24
- export type Schema = typeof schema;
25
-
26
- export { schema };
@@ -1,36 +0,0 @@
1
- import net from "node:net";
2
-
3
- const CONNECT_TIMEOUT_MS = 500;
4
-
5
- function isPortInUse(port: number): Promise<boolean> {
6
- return new Promise((resolve) => {
7
- const socket = net.connect({ port, host: "127.0.0.1" });
8
- const done = (result: boolean) => {
9
- socket.destroy();
10
- resolve(result);
11
- };
12
- socket.setTimeout(CONNECT_TIMEOUT_MS);
13
- socket.once("connect", () => done(true));
14
- socket.once("timeout", () => done(false));
15
- socket.once("error", () => done(false));
16
- });
17
- }
18
-
19
- /**
20
- * The dev server holds its own libsql connection on the local database file —
21
- * an embedded replica when Turso is configured. A second process syncing or
22
- * deleting that file corrupts the WAL, so db scripts must not run while the
23
- * server is up. Best-effort check: only the conventional PORT is probed.
24
- */
25
- export async function ensureDevServerStopped(): Promise<void> {
26
- if (process.env.SKIP_DB_GUARD === "true") return;
27
- const databaseUrl = process.env.DATABASE_URL ?? "file:./local.db";
28
- if (!databaseUrl.startsWith("file:")) return;
29
- const port = Number.parseInt(process.env.PORT ?? "8080", 10);
30
- if (Number.isNaN(port) || !(await isPortInUse(port))) return;
31
- console.error(
32
- `[drizzle] A server is listening on port ${port} and holds ${databaseUrl}. ` +
33
- "Stop the dev server first, or set SKIP_DB_GUARD=true to override."
34
- );
35
- process.exit(1);
36
- }
@@ -1,40 +0,0 @@
1
- import fs from "node:fs/promises";
2
- import path from "node:path";
3
- import { ensureDevServerStopped } from "./guard";
4
-
5
- /** Deletes the local SQLite database (and stored-email output) for a clean slate. */
6
- function sqlitePathFromDatabaseUrl(url: string) {
7
- if (!url.startsWith("file:")) return null;
8
- return path.resolve(process.cwd(), url.slice("file:".length));
9
- }
10
-
11
- // Sidecars include the embedded-replica sync metadata (-info, -client_wal_index);
12
- // leaving those behind next to a recreated file causes WAL/sync conflicts.
13
- const DB_SIDECAR_SUFFIXES = ["-shm", "-wal", "-journal", "-info", "-client_wal_index"];
14
-
15
- async function removeIfExists(target: string) {
16
- await fs.rm(target, { recursive: true, force: true });
17
- }
18
-
19
- async function reset() {
20
- await ensureDevServerStopped();
21
- const dbPath = sqlitePathFromDatabaseUrl(process.env.DATABASE_URL ?? "");
22
- if (dbPath) {
23
- await removeIfExists(dbPath);
24
- for (const suffix of DB_SIDECAR_SUFFIXES) {
25
- await removeIfExists(`${dbPath}${suffix}`);
26
- }
27
- await fs.mkdir(path.dirname(dbPath), { recursive: true });
28
- }
29
-
30
- const emailDirectory = process.env.EMAIL_OUTPUT_DIRECTORY
31
- ? path.resolve(process.cwd(), process.env.EMAIL_OUTPUT_DIRECTORY)
32
- : null;
33
-
34
- if (emailDirectory) {
35
- await removeIfExists(emailDirectory);
36
- await fs.mkdir(emailDirectory, { recursive: true });
37
- }
38
- }
39
-
40
- void reset();
@@ -1,16 +0,0 @@
1
- import { isRemote, orm } from "./db";
2
- import { ensureDevServerStopped } from "./guard";
3
-
4
- async function sync() {
5
- await ensureDevServerStopped();
6
- if (isRemote) {
7
- await orm.$client.sync();
8
- } else {
9
- console.info("Local database no sync required");
10
- }
11
- }
12
-
13
- sync().then(() => {
14
- console.info("Sync completed");
15
- process.exit(0);
16
- });