create-tsrouter-app 0.3.0 → 0.4.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 (165) hide show
  1. package/README.md +41 -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 +260 -0
  9. package/dist/{utils/getPackageManager.js → package-manager.js} +1 -0
  10. package/dist/types.js +1 -0
  11. package/package.json +6 -3
  12. package/src/add-ons.ts +156 -0
  13. package/src/cli.ts +114 -0
  14. package/src/constants.ts +7 -0
  15. package/src/create-app.ts +582 -0
  16. package/src/index.ts +2 -507
  17. package/src/mcp.ts +205 -0
  18. package/src/options.ts +308 -0
  19. package/src/{utils/getPackageManager.ts → package-manager.ts} +1 -0
  20. package/src/types.ts +30 -0
  21. package/templates/react/add-on/clerk/README.md +3 -0
  22. package/templates/react/add-on/clerk/assets/_dot_env.local.append +2 -0
  23. package/templates/react/add-on/clerk/assets/src/integrations/clerk/header-user.tsx +19 -0
  24. package/templates/react/add-on/clerk/assets/src/integrations/clerk/provider.tsx +18 -0
  25. package/templates/react/add-on/clerk/assets/src/routes/demo.clerk.tsx +20 -0
  26. package/templates/react/add-on/clerk/info.json +13 -0
  27. package/templates/react/add-on/clerk/package.json +5 -0
  28. package/templates/react/add-on/convex/README.md +4 -0
  29. package/templates/react/add-on/convex/assets/_dot_cursorrules.append +93 -0
  30. package/templates/react/add-on/convex/assets/_dot_env.local.append +3 -0
  31. package/templates/react/add-on/convex/assets/convex/products.ts +8 -0
  32. package/templates/react/add-on/convex/assets/convex/schema.ts +10 -0
  33. package/templates/react/add-on/convex/assets/src/integrations/convex/provider.tsx +20 -0
  34. package/templates/react/add-on/convex/assets/src/routes/demo.convex.tsx +33 -0
  35. package/templates/react/add-on/convex/info.json +13 -0
  36. package/templates/react/add-on/convex/package.json +6 -0
  37. package/templates/react/add-on/form/assets/src/routes/demo.form.tsx.ejs +62 -0
  38. package/templates/react/add-on/form/info.json +13 -0
  39. package/templates/react/add-on/form/package.json +5 -0
  40. package/templates/react/add-on/module-federation/assets/module-federation.config.js.ejs +31 -0
  41. package/templates/react/add-on/module-federation/assets/src/demo-mf-component.tsx +3 -0
  42. package/templates/react/add-on/module-federation/assets/src/demo-mf-self-contained.tsx +11 -0
  43. package/templates/react/add-on/module-federation/info.json +7 -0
  44. package/templates/react/add-on/module-federation/package.json +5 -0
  45. package/templates/react/add-on/netlify/README.md +11 -0
  46. package/templates/react/add-on/netlify/info.json +7 -0
  47. package/templates/react/add-on/sentry/assets/_dot_cursorrules.append +22 -0
  48. package/templates/react/add-on/sentry/assets/_dot_env.local.append +2 -0
  49. package/templates/react/add-on/sentry/assets/src/app/global-middleware.ts +25 -0
  50. package/templates/react/add-on/sentry/assets/src/routes/demo.sentry.testing.tsx +480 -0
  51. package/templates/react/add-on/sentry/info.json +14 -0
  52. package/templates/react/add-on/sentry/package.json +7 -0
  53. package/templates/react/add-on/shadcn/README.md +7 -0
  54. package/templates/react/add-on/shadcn/assets/_dot_cursorrules.append +7 -0
  55. package/templates/react/add-on/shadcn/info.json +11 -0
  56. package/templates/react/add-on/start/assets/app.config.ts +16 -0
  57. package/templates/react/add-on/start/assets/postcss.config.ts +5 -0
  58. package/templates/react/add-on/start/assets/src/api.ts +6 -0
  59. package/templates/react/add-on/start/assets/src/client.tsx +10 -0
  60. package/templates/react/add-on/start/assets/src/router.tsx.ejs +51 -0
  61. package/templates/react/add-on/start/assets/src/routes/api.demo-names.ts +11 -0
  62. package/templates/react/add-on/start/assets/src/routes/demo.start.api-request.tsx.ejs +33 -0
  63. package/templates/react/add-on/start/assets/src/routes/demo.start.server-funcs.tsx +49 -0
  64. package/templates/react/add-on/start/assets/src/ssr.tsx +12 -0
  65. package/templates/react/add-on/start/info.json +19 -0
  66. package/templates/react/add-on/start/package.json +14 -0
  67. package/templates/react/add-on/store/assets/src/lib/demo-store.ts +13 -0
  68. package/templates/react/add-on/store/assets/src/routes/demo.store.tsx.ejs +75 -0
  69. package/templates/react/add-on/store/info.json +13 -0
  70. package/templates/react/add-on/store/package.json +6 -0
  71. package/templates/react/add-on/tanstack-query/assets/src/integrations/tanstack-query/layout.tsx +5 -0
  72. package/templates/react/add-on/tanstack-query/assets/src/integrations/tanstack-query/provider.tsx +9 -0
  73. package/templates/react/add-on/tanstack-query/assets/src/routes/demo.tanstack-query.tsx.ejs +38 -0
  74. package/templates/react/add-on/tanstack-query/info.json +13 -0
  75. package/templates/react/add-on/tanstack-query/package.json +6 -0
  76. package/templates/{base → react/base}/README.md.ejs +9 -0
  77. package/templates/react/base/_dot_vscode/settings.json +11 -0
  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 +17 -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/react/file-router/src/routes/__root.tsx.ejs +71 -0
  93. package/templates/solid/add-on/form/assets/src/routes/demo.form.tsx.ejs +148 -0
  94. package/templates/solid/add-on/form/info.json +13 -0
  95. package/templates/solid/add-on/form/package.json +5 -0
  96. package/templates/solid/add-on/module-federation/assets/module-federation.config.js.ejs +27 -0
  97. package/templates/solid/add-on/module-federation/assets/src/demo-mf-component.tsx +3 -0
  98. package/templates/solid/add-on/module-federation/assets/src/demo-mf-self-contained.tsx +9 -0
  99. package/templates/solid/add-on/module-federation/info.json +7 -0
  100. package/templates/solid/add-on/module-federation/package.json +5 -0
  101. package/templates/solid/add-on/sentry/assets/_dot_cursorrules.append +22 -0
  102. package/templates/solid/add-on/sentry/assets/_dot_env.local.append +2 -0
  103. package/templates/solid/add-on/sentry/assets/src/routes/demo.sentry.bad-event-handler.tsx +20 -0
  104. package/templates/solid/add-on/sentry/info.json +13 -0
  105. package/templates/solid/add-on/sentry/package.json +5 -0
  106. package/templates/solid/add-on/solid-ui/README.md +9 -0
  107. package/templates/solid/add-on/solid-ui/assets/src/lib/utils.ts +6 -0
  108. package/templates/solid/add-on/solid-ui/assets/src/styles.css +138 -0
  109. package/templates/solid/add-on/solid-ui/assets/ui.config.json +13 -0
  110. package/templates/solid/add-on/solid-ui/info.json +11 -0
  111. package/templates/solid/add-on/solid-ui/package.json +9 -0
  112. package/templates/solid/add-on/store/assets/src/lib/demo-store.ts +13 -0
  113. package/templates/solid/add-on/store/assets/src/routes/demo.store.tsx.ejs +77 -0
  114. package/templates/solid/add-on/store/info.json +13 -0
  115. package/templates/solid/add-on/store/package.json +6 -0
  116. package/templates/solid/add-on/tanstack-query/assets/src/integrations/tanstack-query/header-user.tsx +5 -0
  117. package/templates/solid/add-on/tanstack-query/assets/src/integrations/tanstack-query/provider.tsx +15 -0
  118. package/templates/solid/add-on/tanstack-query/assets/src/routes/demo.tanstack-query.tsx +30 -0
  119. package/templates/solid/add-on/tanstack-query/info.json +13 -0
  120. package/templates/solid/add-on/tanstack-query/package.json +6 -0
  121. package/templates/solid/base/README.md.ejs +200 -0
  122. package/templates/solid/base/_dot_cursorrules.append +35 -0
  123. package/templates/solid/base/_dot_gitignore +5 -0
  124. package/templates/solid/base/_dot_vscode/settings.json +11 -0
  125. package/templates/solid/base/index.html.ejs +20 -0
  126. package/templates/solid/base/package.json +22 -0
  127. package/templates/solid/base/package.ts.json +5 -0
  128. package/templates/solid/base/package.tw.json +6 -0
  129. package/templates/solid/base/public/favicon.ico +0 -0
  130. package/templates/solid/base/public/logo192.png +0 -0
  131. package/templates/solid/base/public/logo512.png +0 -0
  132. package/templates/solid/base/public/manifest.json +25 -0
  133. package/templates/solid/base/public/robots.txt +3 -0
  134. package/templates/solid/base/src/App.css +0 -0
  135. package/templates/solid/base/src/App.tsx.ejs +47 -0
  136. package/templates/solid/base/src/components/Header.tsx.ejs +26 -0
  137. package/templates/solid/base/src/logo.svg +120 -0
  138. package/templates/solid/base/src/styles.css.ejs +15 -0
  139. package/templates/solid/base/tsconfig.json.ejs +30 -0
  140. package/templates/solid/base/vite.config.js.ejs +22 -0
  141. package/templates/solid/code-router/src/main.tsx.ejs +69 -0
  142. package/templates/solid/file-router/package.fr.json +5 -0
  143. package/templates/solid/file-router/src/main.tsx.ejs +44 -0
  144. package/templates/solid/file-router/src/routes/__root.tsx.ejs +41 -0
  145. package/templates/solid/file-router/src/routes/index.tsx +43 -0
  146. package/templates/base/vite.config.js.ejs +0 -15
  147. package/templates/file-router/src/routes/__root.tsx +0 -11
  148. /package/templates/{base/gitignore → react/base/_dot_gitignore} +0 -0
  149. /package/templates/{base → react/base}/index.html.ejs +0 -0
  150. /package/templates/{base → react/base}/package.json +0 -0
  151. /package/templates/{base → react/base}/package.ts.json +0 -0
  152. /package/templates/{base → react/base}/package.tw.json +0 -0
  153. /package/templates/{base → react/base}/public/favicon.ico +0 -0
  154. /package/templates/{base → react/base}/public/logo192.png +0 -0
  155. /package/templates/{base → react/base}/public/logo512.png +0 -0
  156. /package/templates/{base → react/base}/public/manifest.json +0 -0
  157. /package/templates/{base → react/base}/public/robots.txt +0 -0
  158. /package/templates/{base → react/base}/src/App.css +0 -0
  159. /package/templates/{base → react/base}/src/App.test.tsx.ejs +0 -0
  160. /package/templates/{base → react/base}/src/App.tsx.ejs +0 -0
  161. /package/templates/{base → react/base}/src/logo.svg +0 -0
  162. /package/templates/{base → react/base}/src/reportWebVitals.ts.ejs +0 -0
  163. /package/templates/{base → react/base}/src/styles.css.ejs +0 -0
  164. /package/templates/{file-router → react/file-router}/package.fr.json +0 -0
  165. /package/templates/{file-router → react/file-router}/src/main.tsx.ejs +0 -0
package/src/options.ts ADDED
@@ -0,0 +1,308 @@
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
+ const 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
+ }
47
+
48
+ return {
49
+ framework: cliOptions.framework || 'react',
50
+ projectName: cliOptions.projectName,
51
+ typescript,
52
+ tailwind,
53
+ packageManager: cliOptions.packageManager || DEFAULT_PACKAGE_MANAGER,
54
+ mode: cliOptions.template === 'file-router' ? FILE_ROUTER : CODE_ROUTER,
55
+ git: !!cliOptions.git,
56
+ addOns,
57
+ chosenAddOns,
58
+ variableValues: {},
59
+ }
60
+ }
61
+ }
62
+
63
+ async function collectVariables(
64
+ variables: Array<Variable>,
65
+ ): Promise<Record<string, string | number | boolean>> {
66
+ const responses: Record<string, string | number | boolean> = {}
67
+ for (const variable of variables) {
68
+ if (variable.type === 'string') {
69
+ const response = await text({
70
+ message: variable.description,
71
+ initialValue: variable.default,
72
+ })
73
+ if (isCancel(response)) {
74
+ cancel('Operation cancelled.')
75
+ process.exit(0)
76
+ }
77
+ responses[variable.name] = response
78
+ } else if (variable.type === 'number') {
79
+ const response = await text({
80
+ message: variable.description,
81
+ initialValue: variable.default.toString(),
82
+ })
83
+ if (isCancel(response)) {
84
+ cancel('Operation cancelled.')
85
+ process.exit(0)
86
+ }
87
+ responses[variable.name] = Number(response)
88
+ } else {
89
+ const response = await confirm({
90
+ message: variable.description,
91
+ initialValue: variable.default === true,
92
+ })
93
+ if (isCancel(response)) {
94
+ cancel('Operation cancelled.')
95
+ process.exit(0)
96
+ }
97
+ responses[variable.name] = response
98
+ }
99
+ }
100
+ return responses
101
+ }
102
+
103
+ export async function promptForOptions(
104
+ cliOptions: CliOptions,
105
+ ): Promise<Required<Options>> {
106
+ const options = {} as Required<Options>
107
+
108
+ options.framework = cliOptions.framework || DEFAULT_FRAMEWORK
109
+ if (options.framework === 'solid') {
110
+ options.typescript = true
111
+ options.tailwind = true
112
+ }
113
+
114
+ if (cliOptions.addOns) {
115
+ options.typescript = true
116
+ }
117
+
118
+ if (!cliOptions.projectName) {
119
+ const value = await text({
120
+ message: 'What would you like to name your project?',
121
+ defaultValue: 'my-app',
122
+ validate(value) {
123
+ if (!value) {
124
+ return 'Please enter a name'
125
+ }
126
+ },
127
+ })
128
+ if (isCancel(value)) {
129
+ cancel('Operation cancelled.')
130
+ process.exit(0)
131
+ }
132
+ options.projectName = value
133
+ }
134
+
135
+ // Router type selection
136
+ if (!cliOptions.template) {
137
+ const routerType = await select({
138
+ message: 'Select the router type:',
139
+ options: [
140
+ {
141
+ value: FILE_ROUTER,
142
+ label: 'File Router - File-based routing structure',
143
+ },
144
+ {
145
+ value: CODE_ROUTER,
146
+ label: 'Code Router - Traditional code-based routing',
147
+ },
148
+ ],
149
+ initialValue: FILE_ROUTER,
150
+ })
151
+ if (isCancel(routerType)) {
152
+ cancel('Operation cancelled.')
153
+ process.exit(0)
154
+ }
155
+ options.mode = routerType as typeof CODE_ROUTER | typeof FILE_ROUTER
156
+ } else {
157
+ options.mode = cliOptions.template as
158
+ | typeof CODE_ROUTER
159
+ | typeof FILE_ROUTER
160
+ if (options.mode === FILE_ROUTER) {
161
+ options.typescript = true
162
+ }
163
+ }
164
+
165
+ // TypeScript selection (if using Code Router)
166
+ if (!options.typescript) {
167
+ if (options.mode === CODE_ROUTER) {
168
+ const typescriptEnable = await confirm({
169
+ message: 'Would you like to use TypeScript?',
170
+ initialValue: true,
171
+ })
172
+ if (isCancel(typescriptEnable)) {
173
+ cancel('Operation cancelled.')
174
+ process.exit(0)
175
+ }
176
+ options.typescript = typescriptEnable
177
+ } else {
178
+ options.typescript = true
179
+ }
180
+ }
181
+
182
+ // Tailwind selection
183
+ if (cliOptions.tailwind === undefined && options.framework === 'react') {
184
+ const tailwind = await confirm({
185
+ message: 'Would you like to use Tailwind CSS?',
186
+ initialValue: true,
187
+ })
188
+ if (isCancel(tailwind)) {
189
+ cancel('Operation cancelled.')
190
+ process.exit(0)
191
+ }
192
+ options.tailwind = tailwind
193
+ } else {
194
+ options.tailwind = options.framework === 'solid' || !!cliOptions.tailwind
195
+ }
196
+
197
+ // Package manager selection
198
+ if (cliOptions.packageManager === undefined) {
199
+ const detectedPackageManager = getPackageManager()
200
+ if (!detectedPackageManager) {
201
+ const pm = await select({
202
+ message: 'Select package manager:',
203
+ options: SUPPORTED_PACKAGE_MANAGERS.map((pm) => ({
204
+ value: pm,
205
+ label: pm,
206
+ })),
207
+ initialValue: DEFAULT_PACKAGE_MANAGER,
208
+ })
209
+ if (isCancel(pm)) {
210
+ cancel('Operation cancelled.')
211
+ process.exit(0)
212
+ }
213
+ options.packageManager = pm
214
+ } else {
215
+ options.packageManager = detectedPackageManager
216
+ }
217
+ } else {
218
+ options.packageManager = cliOptions.packageManager
219
+ }
220
+
221
+ options.chosenAddOns = []
222
+ if (Array.isArray(cliOptions.addOns)) {
223
+ options.chosenAddOns = await finalizeAddOns(
224
+ options.framework,
225
+ options.mode,
226
+ cliOptions.addOns,
227
+ )
228
+ options.tailwind = true
229
+ } else if (cliOptions.addOns) {
230
+ // Select any add-ons
231
+ const allAddOns = await getAllAddOns(options.framework, options.mode)
232
+ const addOns = allAddOns.filter((addOn) => addOn.type === 'add-on')
233
+ let selectedAddOns: Array<string> = []
234
+ if (options.typescript && addOns.length > 0) {
235
+ const value = await multiselect({
236
+ message: 'What add-ons would you like for your project:',
237
+ options: addOns.map((addOn) => ({
238
+ value: addOn.id,
239
+ label: addOn.name,
240
+ hint: addOn.description,
241
+ })),
242
+ required: false,
243
+ })
244
+
245
+ if (isCancel(value)) {
246
+ cancel('Operation cancelled.')
247
+ process.exit(0)
248
+ }
249
+ selectedAddOns = value
250
+ }
251
+
252
+ // Select any examples
253
+ const selectedExamples: Array<string> = []
254
+ // const examples = allAddOns.filter((addOn) => addOn.type === 'example')
255
+ // if (options.typescript && examples.length > 0) {
256
+ // const value = await multiselect({
257
+ // message: 'Would you like any examples?',
258
+ // options: examples.map((addOn) => ({
259
+ // value: addOn.id,
260
+ // label: addOn.name,
261
+ // hint: addOn.description,
262
+ // })),
263
+ // required: false,
264
+ // })
265
+
266
+ // if (isCancel(value)) {
267
+ // cancel('Operation cancelled.')
268
+ // process.exit(0)
269
+ // }
270
+ // selectedExamples = value
271
+ // }
272
+
273
+ if (selectedAddOns.length > 0 || selectedExamples.length > 0) {
274
+ options.chosenAddOns = await finalizeAddOns(
275
+ options.framework,
276
+ options.mode,
277
+ [...selectedAddOns, ...selectedExamples],
278
+ )
279
+ options.tailwind = true
280
+ }
281
+ }
282
+
283
+ // Collect variables
284
+ const variables: Array<Variable> = []
285
+ for (const addOn of options.chosenAddOns) {
286
+ for (const variable of addOn.variables ?? []) {
287
+ variables.push(variable)
288
+ }
289
+ }
290
+ options.variableValues = await collectVariables(variables)
291
+
292
+ // Git selection
293
+ if (cliOptions.git === undefined) {
294
+ const git = await confirm({
295
+ message: 'Would you like to initialize a new git repository?',
296
+ initialValue: true,
297
+ })
298
+ if (isCancel(git)) {
299
+ cancel('Operation cancelled.')
300
+ process.exit(0)
301
+ }
302
+ options.git = git
303
+ } else {
304
+ options.git = !!cliOptions.git
305
+ }
306
+
307
+ return options
308
+ }
@@ -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
+ }