create-tsrouter-app 0.3.1 → 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 (166) hide show
  1. package/README.md +53 -9
  2. package/dist/add-ons.js +69 -0
  3. package/dist/cli.js +78 -0
  4. package/dist/constants.js +4 -0
  5. package/dist/create-app.js +371 -0
  6. package/dist/index.js +2 -347
  7. package/dist/mcp.js +169 -0
  8. package/dist/options.js +261 -0
  9. package/dist/{utils/getPackageManager.js → package-manager.js} +1 -0
  10. package/dist/types.js +1 -0
  11. package/images/mcp-configuration.png +0 -0
  12. package/package.json +6 -3
  13. package/src/add-ons.ts +156 -0
  14. package/src/cli.ts +114 -0
  15. package/src/constants.ts +7 -0
  16. package/src/create-app.ts +582 -0
  17. package/src/index.ts +2 -507
  18. package/src/mcp.ts +205 -0
  19. package/src/options.ts +309 -0
  20. package/src/{utils/getPackageManager.ts → package-manager.ts} +1 -0
  21. package/src/types.ts +30 -0
  22. package/templates/react/add-on/clerk/README.md +3 -0
  23. package/templates/react/add-on/clerk/assets/_dot_env.local.append +2 -0
  24. package/templates/react/add-on/clerk/assets/src/integrations/clerk/header-user.tsx +19 -0
  25. package/templates/react/add-on/clerk/assets/src/integrations/clerk/provider.tsx +18 -0
  26. package/templates/react/add-on/clerk/assets/src/routes/demo.clerk.tsx +20 -0
  27. package/templates/react/add-on/clerk/info.json +13 -0
  28. package/templates/react/add-on/clerk/package.json +5 -0
  29. package/templates/react/add-on/convex/README.md +4 -0
  30. package/templates/react/add-on/convex/assets/_dot_cursorrules.append +93 -0
  31. package/templates/react/add-on/convex/assets/_dot_env.local.append +3 -0
  32. package/templates/react/add-on/convex/assets/convex/products.ts +8 -0
  33. package/templates/react/add-on/convex/assets/convex/schema.ts +10 -0
  34. package/templates/react/add-on/convex/assets/src/integrations/convex/provider.tsx +20 -0
  35. package/templates/react/add-on/convex/assets/src/routes/demo.convex.tsx +33 -0
  36. package/templates/react/add-on/convex/info.json +13 -0
  37. package/templates/react/add-on/convex/package.json +6 -0
  38. package/templates/react/add-on/form/assets/src/routes/demo.form.tsx.ejs +62 -0
  39. package/templates/react/add-on/form/info.json +13 -0
  40. package/templates/react/add-on/form/package.json +5 -0
  41. package/templates/react/add-on/module-federation/assets/module-federation.config.js.ejs +31 -0
  42. package/templates/react/add-on/module-federation/assets/src/demo-mf-component.tsx +3 -0
  43. package/templates/react/add-on/module-federation/assets/src/demo-mf-self-contained.tsx +11 -0
  44. package/templates/react/add-on/module-federation/info.json +7 -0
  45. package/templates/react/add-on/module-federation/package.json +5 -0
  46. package/templates/react/add-on/netlify/README.md +11 -0
  47. package/templates/react/add-on/netlify/info.json +7 -0
  48. package/templates/react/add-on/sentry/assets/_dot_cursorrules.append +22 -0
  49. package/templates/react/add-on/sentry/assets/_dot_env.local.append +2 -0
  50. package/templates/react/add-on/sentry/assets/src/app/global-middleware.ts +25 -0
  51. package/templates/react/add-on/sentry/assets/src/routes/demo.sentry.testing.tsx +480 -0
  52. package/templates/react/add-on/sentry/info.json +14 -0
  53. package/templates/react/add-on/sentry/package.json +7 -0
  54. package/templates/react/add-on/shadcn/README.md +7 -0
  55. package/templates/react/add-on/shadcn/assets/_dot_cursorrules.append +7 -0
  56. package/templates/react/add-on/shadcn/info.json +11 -0
  57. package/templates/react/add-on/start/assets/app.config.ts +16 -0
  58. package/templates/react/add-on/start/assets/postcss.config.ts +5 -0
  59. package/templates/react/add-on/start/assets/src/api.ts +6 -0
  60. package/templates/react/add-on/start/assets/src/client.tsx +10 -0
  61. package/templates/react/add-on/start/assets/src/router.tsx.ejs +51 -0
  62. package/templates/react/add-on/start/assets/src/routes/api.demo-names.ts +11 -0
  63. package/templates/react/add-on/start/assets/src/routes/demo.start.api-request.tsx.ejs +33 -0
  64. package/templates/react/add-on/start/assets/src/routes/demo.start.server-funcs.tsx +49 -0
  65. package/templates/react/add-on/start/assets/src/ssr.tsx +12 -0
  66. package/templates/react/add-on/start/info.json +19 -0
  67. package/templates/react/add-on/start/package.json +14 -0
  68. package/templates/react/add-on/store/assets/src/lib/demo-store.ts +13 -0
  69. package/templates/react/add-on/store/assets/src/routes/demo.store.tsx.ejs +75 -0
  70. package/templates/react/add-on/store/info.json +13 -0
  71. package/templates/react/add-on/store/package.json +6 -0
  72. package/templates/react/add-on/tanstack-query/assets/src/integrations/tanstack-query/layout.tsx +5 -0
  73. package/templates/react/add-on/tanstack-query/assets/src/integrations/tanstack-query/provider.tsx +9 -0
  74. package/templates/react/add-on/tanstack-query/assets/src/routes/demo.tanstack-query.tsx.ejs +38 -0
  75. package/templates/react/add-on/tanstack-query/info.json +13 -0
  76. package/templates/react/add-on/tanstack-query/package.json +6 -0
  77. package/templates/{base → react/base}/README.md.ejs +10 -1
  78. package/templates/react/base/src/components/Header.tsx.ejs +25 -0
  79. package/templates/{base/tsconfig.json → react/base/tsconfig.json.ejs} +5 -1
  80. package/templates/react/base/vite.config.js.ejs +24 -0
  81. package/templates/{code-router → react/code-router}/src/main.tsx.ejs +18 -1
  82. package/templates/react/example/tanchat/README.md +37 -0
  83. package/templates/react/example/tanchat/assets/_dot_env.local.append +2 -0
  84. package/templates/react/example/tanchat/assets/src/components/demo.SettingsDialog.tsx +148 -0
  85. package/templates/react/example/tanchat/assets/src/demo.index.css +220 -0
  86. package/templates/react/example/tanchat/assets/src/routes/example.chat.tsx.ejs +375 -0
  87. package/templates/react/example/tanchat/assets/src/store/demo.hooks.ts +21 -0
  88. package/templates/react/example/tanchat/assets/src/store/demo.store.ts +133 -0
  89. package/templates/react/example/tanchat/assets/src/utils/demo.ai.ts +108 -0
  90. package/templates/react/example/tanchat/info.json +15 -0
  91. package/templates/react/example/tanchat/package.json +10 -0
  92. package/templates/{file-router → react/file-router}/src/main.tsx.ejs +1 -1
  93. package/templates/react/file-router/src/routes/__root.tsx.ejs +71 -0
  94. package/templates/solid/add-on/form/assets/src/routes/demo.form.tsx.ejs +148 -0
  95. package/templates/solid/add-on/form/info.json +13 -0
  96. package/templates/solid/add-on/form/package.json +5 -0
  97. package/templates/solid/add-on/module-federation/assets/module-federation.config.js.ejs +27 -0
  98. package/templates/solid/add-on/module-federation/assets/src/demo-mf-component.tsx +3 -0
  99. package/templates/solid/add-on/module-federation/assets/src/demo-mf-self-contained.tsx +9 -0
  100. package/templates/solid/add-on/module-federation/info.json +7 -0
  101. package/templates/solid/add-on/module-federation/package.json +5 -0
  102. package/templates/solid/add-on/sentry/assets/_dot_cursorrules.append +22 -0
  103. package/templates/solid/add-on/sentry/assets/_dot_env.local.append +2 -0
  104. package/templates/solid/add-on/sentry/assets/src/routes/demo.sentry.bad-event-handler.tsx +20 -0
  105. package/templates/solid/add-on/sentry/info.json +13 -0
  106. package/templates/solid/add-on/sentry/package.json +5 -0
  107. package/templates/solid/add-on/solid-ui/README.md +9 -0
  108. package/templates/solid/add-on/solid-ui/assets/src/lib/utils.ts +6 -0
  109. package/templates/solid/add-on/solid-ui/assets/src/styles.css +138 -0
  110. package/templates/solid/add-on/solid-ui/assets/ui.config.json +13 -0
  111. package/templates/solid/add-on/solid-ui/info.json +11 -0
  112. package/templates/solid/add-on/solid-ui/package.json +9 -0
  113. package/templates/solid/add-on/store/assets/src/lib/demo-store.ts +13 -0
  114. package/templates/solid/add-on/store/assets/src/routes/demo.store.tsx.ejs +77 -0
  115. package/templates/solid/add-on/store/info.json +13 -0
  116. package/templates/solid/add-on/store/package.json +6 -0
  117. package/templates/solid/add-on/tanstack-query/assets/src/integrations/tanstack-query/header-user.tsx +5 -0
  118. package/templates/solid/add-on/tanstack-query/assets/src/integrations/tanstack-query/provider.tsx +15 -0
  119. package/templates/solid/add-on/tanstack-query/assets/src/routes/demo.tanstack-query.tsx +30 -0
  120. package/templates/solid/add-on/tanstack-query/info.json +13 -0
  121. package/templates/solid/add-on/tanstack-query/package.json +6 -0
  122. package/templates/solid/base/README.md.ejs +200 -0
  123. package/templates/solid/base/_dot_cursorrules.append +35 -0
  124. package/templates/solid/base/_dot_gitignore +5 -0
  125. package/templates/solid/base/_dot_vscode/settings.json +11 -0
  126. package/templates/solid/base/index.html.ejs +20 -0
  127. package/templates/solid/base/package.json +22 -0
  128. package/templates/solid/base/package.ts.json +5 -0
  129. package/templates/solid/base/package.tw.json +6 -0
  130. package/templates/solid/base/public/favicon.ico +0 -0
  131. package/templates/solid/base/public/logo192.png +0 -0
  132. package/templates/solid/base/public/logo512.png +0 -0
  133. package/templates/solid/base/public/manifest.json +25 -0
  134. package/templates/solid/base/public/robots.txt +3 -0
  135. package/templates/solid/base/src/App.css +0 -0
  136. package/templates/solid/base/src/App.tsx.ejs +47 -0
  137. package/templates/solid/base/src/components/Header.tsx.ejs +26 -0
  138. package/templates/solid/base/src/logo.svg +120 -0
  139. package/templates/solid/base/src/styles.css.ejs +15 -0
  140. package/templates/solid/base/tsconfig.json.ejs +30 -0
  141. package/templates/solid/base/vite.config.js.ejs +22 -0
  142. package/templates/solid/code-router/src/main.tsx.ejs +69 -0
  143. package/templates/solid/file-router/package.fr.json +5 -0
  144. package/templates/solid/file-router/src/main.tsx.ejs +44 -0
  145. package/templates/solid/file-router/src/routes/__root.tsx.ejs +41 -0
  146. package/templates/solid/file-router/src/routes/index.tsx +43 -0
  147. package/templates/base/vite.config.js.ejs +0 -15
  148. package/templates/file-router/src/routes/__root.tsx +0 -11
  149. /package/templates/{base → react/base}/_dot_gitignore +0 -0
  150. /package/templates/{base → react/base}/_dot_vscode/settings.json +0 -0
  151. /package/templates/{base → react/base}/index.html.ejs +0 -0
  152. /package/templates/{base → react/base}/package.json +0 -0
  153. /package/templates/{base → react/base}/package.ts.json +0 -0
  154. /package/templates/{base → react/base}/package.tw.json +0 -0
  155. /package/templates/{base → react/base}/public/favicon.ico +0 -0
  156. /package/templates/{base → react/base}/public/logo192.png +0 -0
  157. /package/templates/{base → react/base}/public/logo512.png +0 -0
  158. /package/templates/{base → react/base}/public/manifest.json +0 -0
  159. /package/templates/{base → react/base}/public/robots.txt +0 -0
  160. /package/templates/{base → react/base}/src/App.css +0 -0
  161. /package/templates/{base → react/base}/src/App.test.tsx.ejs +0 -0
  162. /package/templates/{base → react/base}/src/App.tsx.ejs +0 -0
  163. /package/templates/{base → react/base}/src/logo.svg +0 -0
  164. /package/templates/{base → react/base}/src/reportWebVitals.ts.ejs +0 -0
  165. /package/templates/{base → react/base}/src/styles.css.ejs +0 -0
  166. /package/templates/{file-router → react/file-router}/package.fr.json +0 -0
package/src/options.ts ADDED
@@ -0,0 +1,309 @@
1
+ import {
2
+ cancel,
3
+ confirm,
4
+ isCancel,
5
+ multiselect,
6
+ select,
7
+ text,
8
+ } from '@clack/prompts'
9
+
10
+ import {
11
+ DEFAULT_PACKAGE_MANAGER,
12
+ SUPPORTED_PACKAGE_MANAGERS,
13
+ getPackageManager,
14
+ } from './package-manager.js'
15
+ import { CODE_ROUTER, DEFAULT_FRAMEWORK, FILE_ROUTER } from './constants.js'
16
+ import { finalizeAddOns, getAllAddOns } from './add-ons.js'
17
+ import type { AddOn, Variable } from './add-ons.js'
18
+
19
+ import type { CliOptions, Options } from './types.js'
20
+
21
+ // If all CLI options are provided, use them directly
22
+ export async function normalizeOptions(
23
+ cliOptions: CliOptions,
24
+ ): Promise<Required<Options> | undefined> {
25
+ if (cliOptions.projectName) {
26
+ let typescript =
27
+ cliOptions.template === 'typescript' ||
28
+ cliOptions.template === 'file-router' ||
29
+ cliOptions.framework === 'solid'
30
+
31
+ let tailwind = !!cliOptions.tailwind
32
+ if (cliOptions.framework === 'solid') {
33
+ tailwind = true
34
+ }
35
+
36
+ let addOns = false
37
+ let chosenAddOns: Array<AddOn> = []
38
+ if (Array.isArray(cliOptions.addOns)) {
39
+ addOns = true
40
+ chosenAddOns = await finalizeAddOns(
41
+ cliOptions.framework || DEFAULT_FRAMEWORK,
42
+ cliOptions.template === 'file-router' ? FILE_ROUTER : CODE_ROUTER,
43
+ cliOptions.addOns,
44
+ )
45
+ tailwind = true
46
+ typescript = true
47
+ }
48
+
49
+ return {
50
+ framework: cliOptions.framework || 'react',
51
+ projectName: cliOptions.projectName,
52
+ typescript,
53
+ tailwind,
54
+ packageManager: cliOptions.packageManager || DEFAULT_PACKAGE_MANAGER,
55
+ mode: cliOptions.template === 'file-router' ? FILE_ROUTER : CODE_ROUTER,
56
+ git: !!cliOptions.git,
57
+ addOns,
58
+ chosenAddOns,
59
+ variableValues: {},
60
+ }
61
+ }
62
+ }
63
+
64
+ async function collectVariables(
65
+ variables: Array<Variable>,
66
+ ): Promise<Record<string, string | number | boolean>> {
67
+ const responses: Record<string, string | number | boolean> = {}
68
+ for (const variable of variables) {
69
+ if (variable.type === 'string') {
70
+ const response = await text({
71
+ message: variable.description,
72
+ initialValue: variable.default,
73
+ })
74
+ if (isCancel(response)) {
75
+ cancel('Operation cancelled.')
76
+ process.exit(0)
77
+ }
78
+ responses[variable.name] = response
79
+ } else if (variable.type === 'number') {
80
+ const response = await text({
81
+ message: variable.description,
82
+ initialValue: variable.default.toString(),
83
+ })
84
+ if (isCancel(response)) {
85
+ cancel('Operation cancelled.')
86
+ process.exit(0)
87
+ }
88
+ responses[variable.name] = Number(response)
89
+ } else {
90
+ const response = await confirm({
91
+ message: variable.description,
92
+ initialValue: variable.default === true,
93
+ })
94
+ if (isCancel(response)) {
95
+ cancel('Operation cancelled.')
96
+ process.exit(0)
97
+ }
98
+ responses[variable.name] = response
99
+ }
100
+ }
101
+ return responses
102
+ }
103
+
104
+ export async function promptForOptions(
105
+ cliOptions: CliOptions,
106
+ ): Promise<Required<Options>> {
107
+ const options = {} as Required<Options>
108
+
109
+ options.framework = cliOptions.framework || DEFAULT_FRAMEWORK
110
+ if (options.framework === 'solid') {
111
+ options.typescript = true
112
+ options.tailwind = true
113
+ }
114
+
115
+ if (cliOptions.addOns) {
116
+ options.typescript = true
117
+ }
118
+
119
+ if (!cliOptions.projectName) {
120
+ const value = await text({
121
+ message: 'What would you like to name your project?',
122
+ defaultValue: 'my-app',
123
+ validate(value) {
124
+ if (!value) {
125
+ return 'Please enter a name'
126
+ }
127
+ },
128
+ })
129
+ if (isCancel(value)) {
130
+ cancel('Operation cancelled.')
131
+ process.exit(0)
132
+ }
133
+ options.projectName = value
134
+ }
135
+
136
+ // Router type selection
137
+ if (!cliOptions.template) {
138
+ const routerType = await select({
139
+ message: 'Select the router type:',
140
+ options: [
141
+ {
142
+ value: FILE_ROUTER,
143
+ label: 'File Router - File-based routing structure',
144
+ },
145
+ {
146
+ value: CODE_ROUTER,
147
+ label: 'Code Router - Traditional code-based routing',
148
+ },
149
+ ],
150
+ initialValue: FILE_ROUTER,
151
+ })
152
+ if (isCancel(routerType)) {
153
+ cancel('Operation cancelled.')
154
+ process.exit(0)
155
+ }
156
+ options.mode = routerType as typeof CODE_ROUTER | typeof FILE_ROUTER
157
+ } else {
158
+ options.mode = cliOptions.template as
159
+ | typeof CODE_ROUTER
160
+ | typeof FILE_ROUTER
161
+ if (options.mode === FILE_ROUTER) {
162
+ options.typescript = true
163
+ }
164
+ }
165
+
166
+ // TypeScript selection (if using Code Router)
167
+ if (!options.typescript) {
168
+ if (options.mode === CODE_ROUTER) {
169
+ const typescriptEnable = await confirm({
170
+ message: 'Would you like to use TypeScript?',
171
+ initialValue: true,
172
+ })
173
+ if (isCancel(typescriptEnable)) {
174
+ cancel('Operation cancelled.')
175
+ process.exit(0)
176
+ }
177
+ options.typescript = typescriptEnable
178
+ } else {
179
+ options.typescript = true
180
+ }
181
+ }
182
+
183
+ // Tailwind selection
184
+ if (cliOptions.tailwind === undefined && options.framework === 'react') {
185
+ const tailwind = await confirm({
186
+ message: 'Would you like to use Tailwind CSS?',
187
+ initialValue: true,
188
+ })
189
+ if (isCancel(tailwind)) {
190
+ cancel('Operation cancelled.')
191
+ process.exit(0)
192
+ }
193
+ options.tailwind = tailwind
194
+ } else {
195
+ options.tailwind = options.framework === 'solid' || !!cliOptions.tailwind
196
+ }
197
+
198
+ // Package manager selection
199
+ if (cliOptions.packageManager === undefined) {
200
+ const detectedPackageManager = getPackageManager()
201
+ if (!detectedPackageManager) {
202
+ const pm = await select({
203
+ message: 'Select package manager:',
204
+ options: SUPPORTED_PACKAGE_MANAGERS.map((pm) => ({
205
+ value: pm,
206
+ label: pm,
207
+ })),
208
+ initialValue: DEFAULT_PACKAGE_MANAGER,
209
+ })
210
+ if (isCancel(pm)) {
211
+ cancel('Operation cancelled.')
212
+ process.exit(0)
213
+ }
214
+ options.packageManager = pm
215
+ } else {
216
+ options.packageManager = detectedPackageManager
217
+ }
218
+ } else {
219
+ options.packageManager = cliOptions.packageManager
220
+ }
221
+
222
+ options.chosenAddOns = []
223
+ if (Array.isArray(cliOptions.addOns)) {
224
+ options.chosenAddOns = await finalizeAddOns(
225
+ options.framework,
226
+ options.mode,
227
+ cliOptions.addOns,
228
+ )
229
+ options.tailwind = true
230
+ } else if (cliOptions.addOns) {
231
+ // Select any add-ons
232
+ const allAddOns = await getAllAddOns(options.framework, options.mode)
233
+ const addOns = allAddOns.filter((addOn) => addOn.type === 'add-on')
234
+ let selectedAddOns: Array<string> = []
235
+ if (options.typescript && addOns.length > 0) {
236
+ const value = await multiselect({
237
+ message: 'What add-ons would you like for your project:',
238
+ options: addOns.map((addOn) => ({
239
+ value: addOn.id,
240
+ label: addOn.name,
241
+ hint: addOn.description,
242
+ })),
243
+ required: false,
244
+ })
245
+
246
+ if (isCancel(value)) {
247
+ cancel('Operation cancelled.')
248
+ process.exit(0)
249
+ }
250
+ selectedAddOns = value
251
+ }
252
+
253
+ // Select any examples
254
+ const selectedExamples: Array<string> = []
255
+ // const examples = allAddOns.filter((addOn) => addOn.type === 'example')
256
+ // if (options.typescript && examples.length > 0) {
257
+ // const value = await multiselect({
258
+ // message: 'Would you like any examples?',
259
+ // options: examples.map((addOn) => ({
260
+ // value: addOn.id,
261
+ // label: addOn.name,
262
+ // hint: addOn.description,
263
+ // })),
264
+ // required: false,
265
+ // })
266
+
267
+ // if (isCancel(value)) {
268
+ // cancel('Operation cancelled.')
269
+ // process.exit(0)
270
+ // }
271
+ // selectedExamples = value
272
+ // }
273
+
274
+ if (selectedAddOns.length > 0 || selectedExamples.length > 0) {
275
+ options.chosenAddOns = await finalizeAddOns(
276
+ options.framework,
277
+ options.mode,
278
+ [...selectedAddOns, ...selectedExamples],
279
+ )
280
+ options.tailwind = true
281
+ }
282
+ }
283
+
284
+ // Collect variables
285
+ const variables: Array<Variable> = []
286
+ for (const addOn of options.chosenAddOns) {
287
+ for (const variable of addOn.variables ?? []) {
288
+ variables.push(variable)
289
+ }
290
+ }
291
+ options.variableValues = await collectVariables(variables)
292
+
293
+ // Git selection
294
+ if (cliOptions.git === undefined) {
295
+ const git = await confirm({
296
+ message: 'Would you like to initialize a new git repository?',
297
+ initialValue: true,
298
+ })
299
+ if (isCancel(git)) {
300
+ cancel('Operation cancelled.')
301
+ process.exit(0)
302
+ }
303
+ options.git = git
304
+ } else {
305
+ options.git = !!cliOptions.git
306
+ }
307
+
308
+ return options
309
+ }
@@ -3,6 +3,7 @@ export const SUPPORTED_PACKAGE_MANAGERS = [
3
3
  'yarn',
4
4
  'pnpm',
5
5
  'bun',
6
+ 'deno',
6
7
  ] as const
7
8
  export type PackageManager = (typeof SUPPORTED_PACKAGE_MANAGERS)[number]
8
9
  export const DEFAULT_PACKAGE_MANAGER: PackageManager = 'npm'
package/src/types.ts ADDED
@@ -0,0 +1,30 @@
1
+ import type { AddOn } from './add-ons.js'
2
+ import type { CODE_ROUTER, FILE_ROUTER } from './constants.js'
3
+ import type { PackageManager } from './package-manager.js'
4
+
5
+ export type Framework = 'solid' | 'react'
6
+
7
+ export interface Options {
8
+ framework: Framework
9
+ projectName: string
10
+ typescript: boolean
11
+ tailwind: boolean
12
+ packageManager: PackageManager
13
+ mode: typeof CODE_ROUTER | typeof FILE_ROUTER
14
+ addOns: boolean
15
+ chosenAddOns: Array<AddOn>
16
+ git: boolean
17
+ variableValues: Record<string, string | number | boolean>
18
+ }
19
+
20
+ export interface CliOptions {
21
+ template?: 'typescript' | 'javascript' | 'file-router'
22
+ framework?: Framework
23
+ tailwind?: boolean
24
+ packageManager?: PackageManager
25
+ projectName?: string
26
+ git?: boolean
27
+ addOns?: Array<string> | boolean
28
+ listAddOns?: boolean
29
+ mcp?: boolean
30
+ }
@@ -0,0 +1,3 @@
1
+ ## Setting up Clerk
2
+
3
+ - Set the `VITE_CLERK_PUBLISHABLE_KEY` in your `.env.local`.
@@ -0,0 +1,2 @@
1
+ # Clerk configuration, get this key from your [Dashboard](https://clerk.com/dashboard).
2
+ VITE_CLERK_PUBLISHABLE_KEY=
@@ -0,0 +1,19 @@
1
+ import {
2
+ SignedIn,
3
+ SignInButton,
4
+ SignedOut,
5
+ UserButton,
6
+ } from '@clerk/clerk-react'
7
+
8
+ export default function HeaderUser() {
9
+ return (
10
+ <>
11
+ <SignedIn>
12
+ <UserButton />
13
+ </SignedIn>
14
+ <SignedOut>
15
+ <SignInButton />
16
+ </SignedOut>
17
+ </>
18
+ )
19
+ }
@@ -0,0 +1,18 @@
1
+ import { ClerkProvider } from '@clerk/clerk-react'
2
+
3
+ const PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY
4
+ if (!PUBLISHABLE_KEY) {
5
+ throw new Error('Add your Clerk Publishable Key to the .env.local file')
6
+ }
7
+
8
+ export default function AppClerkProvider({
9
+ children,
10
+ }: {
11
+ children: React.ReactNode
12
+ }) {
13
+ return (
14
+ <ClerkProvider publishableKey={PUBLISHABLE_KEY} afterSignOutUrl="/">
15
+ {children}
16
+ </ClerkProvider>
17
+ )
18
+ }
@@ -0,0 +1,20 @@
1
+ import { createFileRoute } from '@tanstack/react-router'
2
+ import { useUser } from '@clerk/clerk-react'
3
+
4
+ export const Route = createFileRoute('/demo/clerk')({
5
+ component: App,
6
+ })
7
+
8
+ function App() {
9
+ const { isSignedIn, user, isLoaded } = useUser()
10
+
11
+ if (!isLoaded) {
12
+ return <div className="p-4">Loading...</div>
13
+ }
14
+
15
+ if (!isSignedIn) {
16
+ return <div className="p-4">Sign in to view this page</div>
17
+ }
18
+
19
+ return <div className="p-4">Hello {user.firstName}!</div>
20
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "Clerk",
3
+ "description": "Add Clerk authentication to your application.",
4
+ "phase": "add-on",
5
+ "templates": ["file-router"],
6
+ "link": "https://clerk.com",
7
+ "routes": [
8
+ {
9
+ "url": "/demo/clerk",
10
+ "name": "Clerk"
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "dependencies": {
3
+ "@clerk/clerk-react": "^5.22.13"
4
+ }
5
+ }
@@ -0,0 +1,4 @@
1
+ ## Setting up Convex
2
+
3
+ - Set the `VITE_CONVEX_URL` and `CONVEX_DEPLOYMENT` environment variables in your `.env.local`. (Or run `npx convex init` to set them automatically.)
4
+ - Run `npx convex dev` to start the Convex server.
@@ -0,0 +1,93 @@
1
+ This document serves as some special instructions when working with Convex.
2
+
3
+ # Schemas
4
+
5
+ When designing the schema please see this page on built in System fields and data types available: https://docs.convex.dev/database/types
6
+
7
+ Here are some specifics that are often mishandled:
8
+
9
+ ## v (https://docs.convex.dev/api/modules/values#v)
10
+
11
+ The validator builder.
12
+
13
+ This builder allows you to build validators for Convex values.
14
+
15
+ Validators can be used in schema definitions and as input validators for Convex functions.
16
+
17
+ Type declaration
18
+ Name Type
19
+ id <TableName>(tableName: TableName) => VId<GenericId<TableName>, "required">
20
+ null () => VNull<null, "required">
21
+ number () => VFloat64<number, "required">
22
+ float64 () => VFloat64<number, "required">
23
+ bigint () => VInt64<bigint, "required">
24
+ int64 () => VInt64<bigint, "required">
25
+ boolean () => VBoolean<boolean, "required">
26
+ string () => VString<string, "required">
27
+ bytes () => VBytes<ArrayBuffer, "required">
28
+ literal <T>(literal: T) => VLiteral<T, "required">
29
+ array <T>(element: T) => VArray<T["type"][], T, "required">
30
+ object <T>(fields: T) => VObject<Expand<{ [Property in string | number | symbol]?: Exclude<Infer<T[Property]>, undefined> } & { [Property in string | number | symbol]: Infer<T[Property]> }>, T, "required", { [Property in string | number | symbol]: Property | `${Property & string}.${T[Property]["fieldPaths"]}` }[keyof T] & string>
31
+ record <Key, Value>(keys: Key, values: Value) => VRecord<Record<Infer<Key>, Value["type"]>, Key, Value, "required", string>
32
+ union <T>(...members: T) => VUnion<T[number]["type"], T, "required", T[number]["fieldPaths"]>
33
+ any () => VAny<any, "required", string>
34
+ optional <T>(value: T) => VOptional<T>
35
+
36
+ ## System fields (https://docs.convex.dev/database/types#system-fields)
37
+
38
+ Every document in Convex has two automatically-generated system fields:
39
+
40
+ _id: The document ID of the document.
41
+ _creationTime: The time this document was created, in milliseconds since the Unix epoch.
42
+
43
+ You do not need to add indices as these are added automatically.
44
+
45
+ ## Example Schema
46
+
47
+ This is an example of a well crafted schema.
48
+
49
+ ```ts
50
+ import { defineSchema, defineTable } from "convex/server";
51
+ import { v } from "convex/values";
52
+
53
+ export default defineSchema(
54
+ {
55
+ users: defineTable({
56
+ name: v.string(),
57
+ }),
58
+
59
+ sessions: defineTable({
60
+ userId: v.id("users"),
61
+ sessionId: v.string(),
62
+ }).index("sessionId", ["sessionId"]),
63
+
64
+ threads: defineTable({
65
+ uuid: v.string(),
66
+ summary: v.optional(v.string()),
67
+ summarizer: v.optional(v.id("_scheduled_functions")),
68
+ }).index("uuid", ["uuid"]),
69
+
70
+ messages: defineTable({
71
+ message: v.string(),
72
+ threadId: v.id("threads"),
73
+ author: v.union(
74
+ v.object({
75
+ role: v.literal("system"),
76
+ }),
77
+ v.object({
78
+ role: v.literal("assistant"),
79
+ context: v.array(v.id("messages")),
80
+ model: v.optional(v.string()),
81
+ }),
82
+ v.object({
83
+ role: v.literal("user"),
84
+ userId: v.id("users"),
85
+ }),
86
+ ),
87
+ })
88
+ .index("threadId", ["threadId"]),
89
+ },
90
+ );
91
+ ```
92
+
93
+ Sourced from: https://github.com/PatrickJS/awesome-cursorrules/blob/main/rules/convex-cursorrules-prompt-file/.cursorrules
@@ -0,0 +1,3 @@
1
+ # Convex configuration, get this URL from your [Dashboard](https://convex.dev/dashboard).
2
+ CONVEX_DEPLOYMENT=
3
+ VITE_CONVEX_URL=
@@ -0,0 +1,8 @@
1
+ import { query } from "./_generated/server";
2
+
3
+ export const get = query({
4
+ args: {},
5
+ handler: async (ctx) => {
6
+ return await ctx.db.query("products").collect();
7
+ },
8
+ });
@@ -0,0 +1,10 @@
1
+ import { defineSchema, defineTable } from "convex/server";
2
+ import { v } from "convex/values";
3
+
4
+ export default defineSchema({
5
+ products: defineTable({
6
+ title: v.string(),
7
+ imageId: v.string(),
8
+ price: v.number(),
9
+ }),
10
+ });
@@ -0,0 +1,20 @@
1
+ import { ConvexProvider } from 'convex/react'
2
+ import { ConvexQueryClient } from '@convex-dev/react-query'
3
+
4
+ const CONVEX_URL = (import.meta as any).env.VITE_CONVEX_URL
5
+ if (!CONVEX_URL) {
6
+ console.error('missing envar CONVEX_URL')
7
+ }
8
+ const convexQueryClient = new ConvexQueryClient(CONVEX_URL)
9
+
10
+ export default function AppConvexProvider({
11
+ children,
12
+ }: {
13
+ children: React.ReactNode
14
+ }) {
15
+ return (
16
+ <ConvexProvider client={convexQueryClient.convexClient}>
17
+ {children}
18
+ </ConvexProvider>
19
+ )
20
+ }
@@ -0,0 +1,33 @@
1
+ import { Suspense } from 'react'
2
+ import { createFileRoute } from '@tanstack/react-router'
3
+ import { useQuery } from 'convex/react'
4
+
5
+ import { api } from '../../convex/_generated/api'
6
+
7
+ export const Route = createFileRoute('/demo/convex')({
8
+ component: App,
9
+ })
10
+
11
+ function Products() {
12
+ const products = useQuery(api.products.get)
13
+
14
+ return (
15
+ <ul>
16
+ {(products || []).map((p) => (
17
+ <li key={p._id}>
18
+ {p.title} - {p.price}
19
+ </li>
20
+ ))}
21
+ </ul>
22
+ )
23
+ }
24
+
25
+ function App() {
26
+ return (
27
+ <div className="p-4">
28
+ <Suspense fallback={<div>Loading...</div>}>
29
+ <Products />
30
+ </Suspense>
31
+ </div>
32
+ )
33
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "Convex",
3
+ "description": "Add the Convex database to your application.",
4
+ "link": "https://convex.dev",
5
+ "phase": "add-on",
6
+ "templates": ["file-router"],
7
+ "routes": [
8
+ {
9
+ "url": "/demo/convex",
10
+ "name": "Convex"
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "dependencies": {
3
+ "@convex-dev/react-query": "0.0.0-alpha.8",
4
+ "convex": "^1.19.2"
5
+ }
6
+ }