create-convex-monorepo 0.2.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 (93) hide show
  1. package/CONTRIBUTING.md +55 -0
  2. package/LICENSE +21 -0
  3. package/README.md +213 -0
  4. package/assets/backend/PROVENANCE.md +3 -0
  5. package/assets/backend/convex/_generated/api.d.ts +51 -0
  6. package/assets/backend/convex/_generated/api.js +23 -0
  7. package/assets/backend/convex/_generated/dataModel.d.ts +60 -0
  8. package/assets/backend/convex/_generated/server.d.ts +162 -0
  9. package/assets/backend/convex/_generated/server.js +101 -0
  10. package/assets/backend/convex/messages.ts +38 -0
  11. package/assets/backend/convex/schema.ts +9 -0
  12. package/assets/backend/convex/tsconfig.json +26 -0
  13. package/assets/backend-blank/PROVENANCE.md +3 -0
  14. package/assets/backend-blank/convex/_generated/api.d.ts +45 -0
  15. package/assets/backend-blank/convex/_generated/api.js +23 -0
  16. package/assets/backend-blank/convex/_generated/dataModel.d.ts +60 -0
  17. package/assets/backend-blank/convex/_generated/server.d.ts +162 -0
  18. package/assets/backend-blank/convex/_generated/server.js +101 -0
  19. package/assets/backend-blank/convex/schema.ts +3 -0
  20. package/assets/setup/convex-setup.mjs +250 -0
  21. package/dist/cli/index.d.ts +2 -0
  22. package/dist/cli/index.js +19 -0
  23. package/dist/cli/index.js.map +1 -0
  24. package/dist/commands/create.d.ts +8 -0
  25. package/dist/commands/create.js +182 -0
  26. package/dist/commands/create.js.map +1 -0
  27. package/dist/generator/context.d.ts +3 -0
  28. package/dist/generator/context.js +81 -0
  29. package/dist/generator/context.js.map +1 -0
  30. package/dist/generator/index.d.ts +12 -0
  31. package/dist/generator/index.js +123 -0
  32. package/dist/generator/index.js.map +1 -0
  33. package/dist/generator/options.d.ts +15 -0
  34. package/dist/generator/options.js +85 -0
  35. package/dist/generator/options.js.map +1 -0
  36. package/dist/generator/types.d.ts +47 -0
  37. package/dist/generator/types.js +2 -0
  38. package/dist/generator/types.js.map +1 -0
  39. package/dist/index.d.ts +5 -0
  40. package/dist/index.js +3 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/integrations/auth/clerk/index.d.ts +2 -0
  43. package/dist/integrations/auth/clerk/index.js +114 -0
  44. package/dist/integrations/auth/clerk/index.js.map +1 -0
  45. package/dist/integrations/auth/index.d.ts +2 -0
  46. package/dist/integrations/auth/index.js +7 -0
  47. package/dist/integrations/auth/index.js.map +1 -0
  48. package/dist/integrations/auth/none/index.d.ts +2 -0
  49. package/dist/integrations/auth/none/index.js +18 -0
  50. package/dist/integrations/auth/none/index.js.map +1 -0
  51. package/dist/integrations/auth/shared.d.ts +11 -0
  52. package/dist/integrations/auth/shared.js +40 -0
  53. package/dist/integrations/auth/shared.js.map +1 -0
  54. package/dist/package-manager/index.d.ts +6 -0
  55. package/dist/package-manager/index.js +22 -0
  56. package/dist/package-manager/index.js.map +1 -0
  57. package/dist/templates/apps/expo/index.d.ts +2 -0
  58. package/dist/templates/apps/expo/index.js +91 -0
  59. package/dist/templates/apps/expo/index.js.map +1 -0
  60. package/dist/templates/apps/index.d.ts +2 -0
  61. package/dist/templates/apps/index.js +11 -0
  62. package/dist/templates/apps/index.js.map +1 -0
  63. package/dist/templates/apps/next/index.d.ts +2 -0
  64. package/dist/templates/apps/next/index.js +66 -0
  65. package/dist/templates/apps/next/index.js.map +1 -0
  66. package/dist/templates/apps/shared.d.ts +24 -0
  67. package/dist/templates/apps/shared.js +124 -0
  68. package/dist/templates/apps/shared.js.map +1 -0
  69. package/dist/templates/apps/tanstack-start/index.d.ts +2 -0
  70. package/dist/templates/apps/tanstack-start/index.js +82 -0
  71. package/dist/templates/apps/tanstack-start/index.js.map +1 -0
  72. package/dist/templates/apps/vite/index.d.ts +2 -0
  73. package/dist/templates/apps/vite/index.js +42 -0
  74. package/dist/templates/apps/vite/index.js.map +1 -0
  75. package/dist/templates/backend/index.d.ts +2 -0
  76. package/dist/templates/backend/index.js +58 -0
  77. package/dist/templates/backend/index.js.map +1 -0
  78. package/dist/templates/root/index.d.ts +2 -0
  79. package/dist/templates/root/index.js +178 -0
  80. package/dist/templates/root/index.js.map +1 -0
  81. package/dist/templates/versions.d.ts +18 -0
  82. package/dist/templates/versions.js +19 -0
  83. package/dist/templates/versions.js.map +1 -0
  84. package/dist/version.d.ts +1 -0
  85. package/dist/version.js +11 -0
  86. package/dist/version.js.map +1 -0
  87. package/docs/adding-a-framework.md +27 -0
  88. package/docs/adding-an-auth-provider.md +31 -0
  89. package/docs/architecture.md +49 -0
  90. package/docs/releases.md +78 -0
  91. package/docs/research.md +76 -0
  92. package/docs/verification.md +78 -0
  93. package/package.json +77 -0
@@ -0,0 +1,91 @@
1
+ import { versions } from '../../versions.js';
2
+ import { common, entryContent, manifest } from '../shared.js';
3
+ export const expoTemplate = {
4
+ id: 'expo',
5
+ label: 'Expo / React Native',
6
+ async generate(context, app) {
7
+ const dir = `apps/${app.name}`;
8
+ const entry = entryContent(context, app, './src');
9
+ const pkg = manifest(context, app);
10
+ pkg.main = 'index.ts';
11
+ const devPort = 8081 + context.options.apps.findIndex((entry) => entry.name === app.name);
12
+ pkg.scripts = {
13
+ ...pkg.scripts,
14
+ dev: `expo start --port ${devPort}`,
15
+ android: 'expo run:android',
16
+ ios: 'expo run:ios',
17
+ build: 'expo export --platform ios --platform android',
18
+ };
19
+ pkg.dependencies = {
20
+ ...pkg.dependencies,
21
+ expo: versions.expo,
22
+ 'react-native': versions.reactNative,
23
+ };
24
+ await context.json(`${dir}/package.json`, pkg);
25
+ await context.json(`${dir}/tsconfig.json`, {
26
+ extends: 'expo/tsconfig.base',
27
+ compilerOptions: { strict: true, noEmit: true },
28
+ include: ['**/*.ts', '**/*.tsx'],
29
+ exclude: ['node_modules', 'dist'],
30
+ });
31
+ await context.json(`${dir}/app.json`, {
32
+ expo: {
33
+ name: app.name,
34
+ slug: `${context.options.name}-${app.name}`,
35
+ scheme: `ccm-${context.options.name}-${app.name}`,
36
+ version: '1.0.0',
37
+ orientation: 'portrait',
38
+ userInterfaceStyle: 'automatic',
39
+ ios: { supportsTablet: true },
40
+ },
41
+ });
42
+ await context.write(`${dir}/metro.config.cjs`, `const { getDefaultConfig } = require('expo/metro-config');\nmodule.exports = getDefaultConfig(__dirname);\n`);
43
+ await context.write(`${dir}/index.ts`, `import { registerRootComponent } from 'expo';\nimport App from './App';\nregisterRootComponent(App);\n`);
44
+ await context.write(`${dir}/App.tsx`, `import { Providers } from './src/providers';
45
+ import { AuthControls } from './src/auth-controls';
46
+ ${entry.imports}
47
+ export default function App() {
48
+ return <Providers><AuthControls />${entry.content}</Providers>;
49
+ }
50
+ `);
51
+ if (context.options.example === 'messages')
52
+ await context.write(`${dir}/src/messages.tsx`, `import { useState } from 'react';
53
+ import { Button, ScrollView, Text, TextInput, View } from 'react-native';
54
+ import { useMutation, useQuery } from 'convex/react';
55
+ import { api } from '@${context.scope}/backend/api';
56
+
57
+ export function Messages() {
58
+ const messages = useQuery(api.messages.list, {});
59
+ const send = useMutation(api.messages.send);
60
+ const [body, setBody] = useState('');
61
+ const [pending, setPending] = useState(false);
62
+ const [error, setError] = useState<string | null>(null);
63
+ async function submit() {
64
+ if (!body.trim() || pending) return;
65
+ setPending(true);
66
+ setError(null);
67
+ try {
68
+ await send({ body: body.trim() });
69
+ setBody('');
70
+ } catch (cause) {
71
+ setError(cause instanceof Error ? cause.message : 'Could not send the message.');
72
+ } finally {
73
+ setPending(false);
74
+ }
75
+ }
76
+ return <ScrollView contentContainerStyle={{ padding: 24, paddingTop: 64 }} keyboardShouldPersistTaps="handled">
77
+ <Text accessibilityRole="header">Messages</Text>
78
+ {messages === undefined ? <Text>Loading messages…</Text> : messages.length === 0 ? <Text>No messages yet.</Text> :
79
+ messages.map((message) => <Text key={message._id}>{message.body}</Text>)}
80
+ <View>
81
+ <TextInput accessibilityLabel="Message" placeholder="Message" value={body} onChangeText={setBody} maxLength={1000} editable={!pending} style={{ borderWidth: 1, padding: 12, marginVertical: 12 }} />
82
+ <Button title={pending ? 'Sending…' : 'Send'} disabled={pending || !body.trim()} onPress={() => { void submit(); }} />
83
+ </View>
84
+ {error && <Text accessibilityRole="alert">{error}</Text>}
85
+ </ScrollView>;
86
+ }
87
+ `);
88
+ await common(context, app, 'EXPO_PUBLIC_CONVEX_URL');
89
+ },
90
+ };
91
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/templates/apps/expo/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { AppTemplate, Framework } from '../../generator/types.js';
2
+ export declare const appTemplates: Record<Framework, AppTemplate>;
@@ -0,0 +1,11 @@
1
+ import { nextTemplate } from './next/index.js';
2
+ import { viteTemplate } from './vite/index.js';
3
+ import { tanstackStartTemplate } from './tanstack-start/index.js';
4
+ import { expoTemplate } from './expo/index.js';
5
+ export const appTemplates = {
6
+ next: nextTemplate,
7
+ vite: viteTemplate,
8
+ 'tanstack-start': tanstackStartTemplate,
9
+ expo: expoTemplate,
10
+ };
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/apps/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,MAAM,CAAC,MAAM,YAAY,GAAmC;IAC1D,IAAI,EAAE,YAAY;IAClB,IAAI,EAAE,YAAY;IAClB,gBAAgB,EAAE,qBAAqB;IACvC,IAAI,EAAE,YAAY;CACnB,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { AppTemplate } from '../../../generator/types.js';
2
+ export declare const nextTemplate: AppTemplate;
@@ -0,0 +1,66 @@
1
+ import { versions } from '../../versions.js';
2
+ import { common, entryContent, manifest, port, webMessages, webTsconfig, } from '../shared.js';
3
+ export const nextTemplate = {
4
+ id: 'next',
5
+ label: 'Next.js',
6
+ async generate(context, app) {
7
+ const dir = `apps/${app.name}`;
8
+ const entry = entryContent(context, app, '..');
9
+ const pkg = manifest(context, app);
10
+ pkg.scripts = {
11
+ ...pkg.scripts,
12
+ dev: `next dev --port ${port(context, app)}`,
13
+ build: 'next build',
14
+ start: `next start --port ${port(context, app)}`,
15
+ };
16
+ pkg.dependencies = {
17
+ ...pkg.dependencies,
18
+ next: versions.next,
19
+ 'react-dom': versions.react,
20
+ };
21
+ pkg.devDependencies = {
22
+ ...pkg.devDependencies,
23
+ '@types/react-dom': '19.2.7',
24
+ '@types/node': '26.5.0',
25
+ };
26
+ await context.json(`${dir}/package.json`, pkg);
27
+ const config = webTsconfig(context);
28
+ await context.json(`${dir}/tsconfig.json`, {
29
+ ...config,
30
+ compilerOptions: {
31
+ ...config.compilerOptions,
32
+ jsx: 'preserve',
33
+ allowJs: true,
34
+ resolveJsonModule: true,
35
+ isolatedModules: true,
36
+ incremental: true,
37
+ plugins: [{ name: 'next' }],
38
+ },
39
+ include: [
40
+ 'next-env.d.ts',
41
+ 'src/**/*.ts',
42
+ 'src/**/*.tsx',
43
+ '.next/types/**/*.ts',
44
+ '.next/dev/types/**/*.ts',
45
+ ],
46
+ });
47
+ await context.write(`${dir}/next.config.ts`, `import type { NextConfig } from 'next';\nconst config: NextConfig = { transpilePackages: ['@${context.scope}/backend'] };\nexport default config;\n`);
48
+ await context.write(`${dir}/next-env.d.ts`, '/// <reference types="next" />\n/// <reference types="next/image-types/global" />\n');
49
+ await context.write(`${dir}/src/app/layout.tsx`, `import type { ReactNode } from 'react';
50
+ export const metadata = { title: '${app.name}', description: 'A shared Convex workspace' };
51
+ export default function Layout({ children }: { children: ReactNode }) {
52
+ return <html lang="en"><body>{children}</body></html>;
53
+ }
54
+ `);
55
+ await context.write(`${dir}/src/app/page.tsx`, `import { Providers } from '../providers';
56
+ import { AuthControls } from '../auth-controls';
57
+ ${entry.imports}
58
+ export default function Home() {
59
+ return <main><Providers><AuthControls />${entry.content}</Providers></main>;
60
+ }
61
+ `);
62
+ await common(context, app, 'NEXT_PUBLIC_CONVEX_URL');
63
+ await webMessages(context, app);
64
+ },
65
+ };
66
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/templates/apps/next/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EACL,MAAM,EACN,YAAY,EACZ,QAAQ,EACR,IAAI,EACJ,WAAW,EACX,WAAW,GACZ,MAAM,cAAc,CAAC;AAEtB,MAAM,CAAC,MAAM,YAAY,GAAgB;IACvC,EAAE,EAAE,MAAM;IACV,KAAK,EAAE,SAAS;IAChB,KAAK,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG;QACzB,MAAM,GAAG,GAAG,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QAC/C,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACnC,GAAG,CAAC,OAAO,GAAG;YACZ,GAAG,GAAG,CAAC,OAAO;YACd,GAAG,EAAE,mBAAmB,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE;YAC5C,KAAK,EAAE,YAAY;YACnB,KAAK,EAAE,qBAAqB,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE;SACjD,CAAC;QACF,GAAG,CAAC,YAAY,GAAG;YACjB,GAAG,GAAG,CAAC,YAAY;YACnB,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,WAAW,EAAE,QAAQ,CAAC,KAAK;SAC5B,CAAC;QACF,GAAG,CAAC,eAAe,GAAG;YACpB,GAAG,GAAG,CAAC,eAAe;YACtB,kBAAkB,EAAE,QAAQ;YAC5B,aAAa,EAAE,QAAQ;SACxB,CAAC;QACF,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,GAAG,eAAe,EAAE,GAAG,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;QACpC,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,GAAG,gBAAgB,EAAE;YACzC,GAAG,MAAM;YACT,eAAe,EAAE;gBACf,GAAG,MAAM,CAAC,eAAe;gBACzB,GAAG,EAAE,UAAU;gBACf,OAAO,EAAE,IAAI;gBACb,iBAAiB,EAAE,IAAI;gBACvB,eAAe,EAAE,IAAI;gBACrB,WAAW,EAAE,IAAI;gBACjB,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;aAC5B;YACD,OAAO,EAAE;gBACP,eAAe;gBACf,aAAa;gBACb,cAAc;gBACd,qBAAqB;gBACrB,yBAAyB;aAC1B;SACF,CAAC,CAAC;QACH,MAAM,OAAO,CAAC,KAAK,CACjB,GAAG,GAAG,iBAAiB,EACvB,+FAA+F,OAAO,CAAC,KAAK,yCAAyC,CACtJ,CAAC;QACF,MAAM,OAAO,CAAC,KAAK,CACjB,GAAG,GAAG,gBAAgB,EACtB,qFAAqF,CACtF,CAAC;QACF,MAAM,OAAO,CAAC,KAAK,CACjB,GAAG,GAAG,qBAAqB,EAC3B;oCAC8B,GAAG,CAAC,IAAI;;;;CAI3C,CACI,CAAC;QACF,MAAM,OAAO,CAAC,KAAK,CACjB,GAAG,GAAG,mBAAmB,EACzB;;EAEJ,KAAK,CAAC,OAAO;;4CAE6B,KAAK,CAAC,OAAO;;CAExD,CACI,CAAC;QACF,MAAM,MAAM,CAAC,OAAO,EAAE,GAAG,EAAE,wBAAwB,CAAC,CAAC;QACrD,MAAM,WAAW,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAClC,CAAC;CACF,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { AppSpec, GeneratorContext, PackageManifest } from '../../generator/types.js';
2
+ export declare function manifest(context: GeneratorContext, app: AppSpec): PackageManifest;
3
+ export declare function common(context: GeneratorContext, app: AppSpec, env: string): Promise<void>;
4
+ export declare function webMessages(context: GeneratorContext, app: AppSpec): Promise<void>;
5
+ export declare function webTsconfig(context: GeneratorContext): {
6
+ extends: string;
7
+ compilerOptions: {
8
+ target: string;
9
+ lib: string[];
10
+ jsx: string;
11
+ module: string;
12
+ moduleResolution: string;
13
+ noEmit: boolean;
14
+ strict: boolean;
15
+ };
16
+ include: string[];
17
+ exclude: string[];
18
+ };
19
+ export declare function port(context: GeneratorContext, app: AppSpec): number;
20
+ /** Entry content varies independently of framework and auth setup. */
21
+ export declare function entryContent(context: GeneratorContext, app: AppSpec, from: string): {
22
+ imports: string;
23
+ content: string;
24
+ };
@@ -0,0 +1,124 @@
1
+ import { versions } from '../versions.js';
2
+ export function manifest(context, app) {
3
+ return {
4
+ name: `@${context.scope}/${app.name}`,
5
+ private: true,
6
+ version: '0.0.0',
7
+ type: 'module',
8
+ scripts: { typecheck: 'tsc --noEmit', lint: 'eslint .' },
9
+ dependencies: {
10
+ [`@${context.scope}/backend`]: 'workspace:*',
11
+ convex: versions.convex,
12
+ react: versions.react,
13
+ },
14
+ devDependencies: {
15
+ [`@${context.scope}/typescript-config`]: 'workspace:*',
16
+ [`@${context.scope}/eslint-config`]: 'workspace:*',
17
+ typescript: versions.typescript,
18
+ '@types/react': '19.2.18',
19
+ eslint: versions.eslint,
20
+ },
21
+ };
22
+ }
23
+ export async function common(context, app, env) {
24
+ const dir = `apps/${app.name}`;
25
+ await context.write(`${dir}/eslint.config.js`, `import config from '@${context.scope}/eslint-config';\nexport default config;\n`);
26
+ await context.write(`${dir}/.env.example`, `# Copy to .env.local, then copy only the public deployment URL from packages/backend/.env.local.\n${env}=\n`);
27
+ if (context.options.example === 'none')
28
+ return;
29
+ await context.write(`${dir}/src/convex-api.type-test.ts`, `import { api } from '@${context.scope}/backend/api';
30
+ import type { Doc, Id } from '@${context.scope}/backend/dataModel';
31
+ import type { FunctionArgs, FunctionReturnType } from 'convex/server';
32
+
33
+ type Assert<T extends true> = T;
34
+ type IsAny<T> = 0 extends (1 & T) ? true : false;
35
+ type Equal<A, B> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2) ? true : false;
36
+ export type ApiIsTyped = Assert<Equal<IsAny<typeof api>, false>>;
37
+ export type ListIsTyped = Assert<Equal<IsAny<typeof api.messages.list>, false>>;
38
+ export type ListResult = Assert<Equal<FunctionReturnType<typeof api.messages.list>, Doc<'messages'>[]>>;
39
+ export type SendArgs = Assert<Equal<FunctionArgs<typeof api.messages.send>, { body: string }>>;
40
+ export type SendResult = Assert<Equal<FunctionReturnType<typeof api.messages.send>, Id<'messages'>>>;
41
+ // These intentional negative tests fail if API references widen to arbitrary keys.
42
+ // @ts-expect-error No such backend module.
43
+ export type MissingModule = typeof api.notAModule;
44
+ // @ts-expect-error No such backend function.
45
+ export type MissingFunction = typeof api.messages.notAFunction;
46
+ `);
47
+ }
48
+ export async function webMessages(context, app) {
49
+ if (context.options.example === 'none')
50
+ return;
51
+ await context.write(`apps/${app.name}/src/messages.tsx`, `'use client';
52
+
53
+ import { useState } from 'react';
54
+ import { useMutation, useQuery } from 'convex/react';
55
+ import { api } from '@${context.scope}/backend/api';
56
+
57
+ export function Messages() {
58
+ const messages = useQuery(api.messages.list, {});
59
+ const send = useMutation(api.messages.send);
60
+ const [body, setBody] = useState('');
61
+ const [pending, setPending] = useState(false);
62
+ const [error, setError] = useState<string | null>(null);
63
+ async function submit() {
64
+ if (!body.trim() || pending) return;
65
+ setPending(true);
66
+ setError(null);
67
+ try {
68
+ await send({ body: body.trim() });
69
+ setBody('');
70
+ } catch (cause) {
71
+ setError(cause instanceof Error ? cause.message : 'Could not send the message.');
72
+ } finally {
73
+ setPending(false);
74
+ }
75
+ }
76
+ return <section aria-label="Messages">
77
+ <h1>Messages</h1>
78
+ {messages === undefined ? <p>Loading messages…</p> : messages.length === 0 ? <p>No messages yet.</p> :
79
+ <ul>{messages.map((message) => <li key={message._id}>{message.body}</li>)}</ul>}
80
+ <form onSubmit={(event) => { event.preventDefault(); void submit(); }}>
81
+ <label htmlFor="message">Message</label>{' '}
82
+ <input id="message" value={body} onChange={(event) => setBody(event.target.value)} maxLength={1000} disabled={pending} />{' '}
83
+ <button type="submit" disabled={pending || !body.trim()}>{pending ? 'Sending…' : 'Send'}</button>
84
+ </form>
85
+ {error && <p role="alert">{error}</p>}
86
+ </section>;
87
+ }
88
+ `);
89
+ }
90
+ export function webTsconfig(context) {
91
+ return {
92
+ extends: `@${context.scope}/typescript-config/base.json`,
93
+ compilerOptions: {
94
+ target: 'ES2022',
95
+ lib: ['DOM', 'DOM.Iterable', 'ES2022'],
96
+ jsx: 'react-jsx',
97
+ module: 'ESNext',
98
+ moduleResolution: 'Bundler',
99
+ noEmit: true,
100
+ strict: true,
101
+ },
102
+ include: ['src', '*.ts'],
103
+ exclude: ['node_modules', 'dist'],
104
+ };
105
+ }
106
+ export function port(context, app) {
107
+ return (3000 + context.options.apps.findIndex((entry) => entry.name === app.name));
108
+ }
109
+ /** Entry content varies independently of framework and auth setup. */
110
+ export function entryContent(context, app, from) {
111
+ if (context.options.example === 'messages') {
112
+ return {
113
+ imports: `import { Messages } from '${from}/messages';`,
114
+ content: '<Messages />',
115
+ };
116
+ }
117
+ return app.framework === 'expo'
118
+ ? {
119
+ imports: "import { Text } from 'react-native';",
120
+ content: `<Text>${app.name}</Text>`,
121
+ }
122
+ : { imports: '', content: `<h1>${app.name}</h1>` };
123
+ }
124
+ //# sourceMappingURL=shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../src/templates/apps/shared.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { AppTemplate } from '../../../generator/types.js';
2
+ export declare const tanstackStartTemplate: AppTemplate;
@@ -0,0 +1,82 @@
1
+ import { versions } from '../../versions.js';
2
+ import { common, entryContent, manifest, port, webMessages, webTsconfig, } from '../shared.js';
3
+ export const tanstackStartTemplate = {
4
+ id: 'tanstack-start',
5
+ label: 'TanStack Start',
6
+ async generate(context, app) {
7
+ const dir = `apps/${app.name}`;
8
+ const entry = entryContent(context, app, '..');
9
+ const pkg = manifest(context, app);
10
+ pkg.scripts = {
11
+ ...pkg.scripts,
12
+ dev: 'vite',
13
+ build: 'vite build',
14
+ typecheck: 'tsr generate && tsc --noEmit',
15
+ 'routes:generate': 'tsr generate',
16
+ };
17
+ pkg.dependencies = {
18
+ ...pkg.dependencies,
19
+ 'react-dom': versions.react,
20
+ '@tanstack/react-start': versions.tanstackStart,
21
+ '@tanstack/react-router': '1.170.33',
22
+ };
23
+ pkg.devDependencies = {
24
+ ...pkg.devDependencies,
25
+ vite: versions.vite,
26
+ '@vitejs/plugin-react': versions.viteReact,
27
+ '@tanstack/router-cli': '1.167.34',
28
+ '@types/react-dom': '19.2.7',
29
+ '@types/node': '26.5.0',
30
+ };
31
+ await context.json(`${dir}/package.json`, pkg);
32
+ const config = webTsconfig(context);
33
+ await context.json(`${dir}/tsconfig.json`, {
34
+ ...config,
35
+ compilerOptions: {
36
+ ...config.compilerOptions,
37
+ verbatimModuleSyntax: false,
38
+ },
39
+ });
40
+ await context.json(`${dir}/tsr.config.json`, {
41
+ routesDirectory: './src/routes',
42
+ generatedRouteTree: './src/routeTree.gen.ts',
43
+ quoteStyle: 'single',
44
+ });
45
+ await context.write(`${dir}/vite.config.ts`, `import { defineConfig } from 'vite';
46
+ import { tanstackStart } from '@tanstack/react-start/plugin/vite';
47
+ import react from '@vitejs/plugin-react';
48
+ export default defineConfig({ plugins: [tanstackStart(), react()], server: { port: ${port(context, app)}, strictPort: true } });
49
+ `);
50
+ await context.write(`${dir}/src/vite-env.d.ts`, '/// <reference types="vite/client" />\n');
51
+ await context.write(`${dir}/src/router.tsx`, `import { createRouter } from '@tanstack/react-router';
52
+ import { routeTree } from './routeTree.gen';
53
+ export function getRouter() {
54
+ return createRouter({ routeTree, scrollRestoration: true });
55
+ }
56
+ declare module '@tanstack/react-router' {
57
+ interface Register { router: ReturnType<typeof getRouter> }
58
+ }
59
+ `);
60
+ await context.write(`${dir}/src/routes/__root.tsx`, `import { createRootRoute, HeadContent, Outlet, Scripts } from '@tanstack/react-router';
61
+ export const Route = createRootRoute({
62
+ head: () => ({ meta: [{ charSet: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }, { title: '${app.name}' }] }),
63
+ component: Root,
64
+ });
65
+ function Root() {
66
+ return <html lang="en"><head><HeadContent /></head><body><Outlet /><Scripts /></body></html>;
67
+ }
68
+ `);
69
+ await context.write(`${dir}/src/routes/index.tsx`, `import { createFileRoute } from '@tanstack/react-router';
70
+ import { Providers } from '../providers';
71
+ import { AuthControls } from '../auth-controls';
72
+ ${entry.imports}
73
+ export const Route = createFileRoute('/')({ component: Home });
74
+ function Home() {
75
+ return <main><Providers><AuthControls />${entry.content}</Providers></main>;
76
+ }
77
+ `);
78
+ await common(context, app, 'VITE_CONVEX_URL');
79
+ await webMessages(context, app);
80
+ },
81
+ };
82
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/templates/apps/tanstack-start/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EACL,MAAM,EACN,YAAY,EACZ,QAAQ,EACR,IAAI,EACJ,WAAW,EACX,WAAW,GACZ,MAAM,cAAc,CAAC;AAEtB,MAAM,CAAC,MAAM,qBAAqB,GAAgB;IAChD,EAAE,EAAE,gBAAgB;IACpB,KAAK,EAAE,gBAAgB;IACvB,KAAK,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG;QACzB,MAAM,GAAG,GAAG,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QAC/C,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACnC,GAAG,CAAC,OAAO,GAAG;YACZ,GAAG,GAAG,CAAC,OAAO;YACd,GAAG,EAAE,MAAM;YACX,KAAK,EAAE,YAAY;YACnB,SAAS,EAAE,8BAA8B;YACzC,iBAAiB,EAAE,cAAc;SAClC,CAAC;QACF,GAAG,CAAC,YAAY,GAAG;YACjB,GAAG,GAAG,CAAC,YAAY;YACnB,WAAW,EAAE,QAAQ,CAAC,KAAK;YAC3B,uBAAuB,EAAE,QAAQ,CAAC,aAAa;YAC/C,wBAAwB,EAAE,UAAU;SACrC,CAAC;QACF,GAAG,CAAC,eAAe,GAAG;YACpB,GAAG,GAAG,CAAC,eAAe;YACtB,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,sBAAsB,EAAE,QAAQ,CAAC,SAAS;YAC1C,sBAAsB,EAAE,UAAU;YAClC,kBAAkB,EAAE,QAAQ;YAC5B,aAAa,EAAE,QAAQ;SACxB,CAAC;QACF,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,GAAG,eAAe,EAAE,GAAG,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;QACpC,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,GAAG,gBAAgB,EAAE;YACzC,GAAG,MAAM;YACT,eAAe,EAAE;gBACf,GAAG,MAAM,CAAC,eAAe;gBACzB,oBAAoB,EAAE,KAAK;aAC5B;SACF,CAAC,CAAC;QACH,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,GAAG,kBAAkB,EAAE;YAC3C,eAAe,EAAE,cAAc;YAC/B,kBAAkB,EAAE,wBAAwB;YAC5C,UAAU,EAAE,QAAQ;SACrB,CAAC,CAAC;QACH,MAAM,OAAO,CAAC,KAAK,CACjB,GAAG,GAAG,iBAAiB,EACvB;;;qFAG+E,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC;CACtG,CACI,CAAC;QACF,MAAM,OAAO,CAAC,KAAK,CACjB,GAAG,GAAG,oBAAoB,EAC1B,yCAAyC,CAC1C,CAAC;QACF,MAAM,OAAO,CAAC,KAAK,CACjB,GAAG,GAAG,iBAAiB,EACvB;;;;;;;;CAQL,CACI,CAAC;QACF,MAAM,OAAO,CAAC,KAAK,CACjB,GAAG,GAAG,wBAAwB,EAC9B;;gIAE0H,GAAG,CAAC,IAAI;;;;;;CAMvI,CACI,CAAC;QACF,MAAM,OAAO,CAAC,KAAK,CACjB,GAAG,GAAG,uBAAuB,EAC7B;;;EAGJ,KAAK,CAAC,OAAO;;;4CAG6B,KAAK,CAAC,OAAO;;CAExD,CACI,CAAC;QACF,MAAM,MAAM,CAAC,OAAO,EAAE,GAAG,EAAE,iBAAiB,CAAC,CAAC;QAC9C,MAAM,WAAW,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAClC,CAAC;CACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { AppTemplate } from '../../../generator/types.js';
2
+ export declare const viteTemplate: AppTemplate;
@@ -0,0 +1,42 @@
1
+ import { versions } from '../../versions.js';
2
+ import { common, entryContent, manifest, port, webMessages, webTsconfig, } from '../shared.js';
3
+ export const viteTemplate = {
4
+ id: 'vite',
5
+ label: 'Vite + React',
6
+ async generate(context, app) {
7
+ const dir = `apps/${app.name}`;
8
+ const entry = entryContent(context, app, '.');
9
+ const pkg = manifest(context, app);
10
+ pkg.scripts = {
11
+ ...pkg.scripts,
12
+ dev: 'vite',
13
+ build: 'vite build',
14
+ preview: 'vite preview',
15
+ };
16
+ pkg.dependencies = { ...pkg.dependencies, 'react-dom': versions.react };
17
+ pkg.devDependencies = {
18
+ ...pkg.devDependencies,
19
+ vite: versions.vite,
20
+ '@vitejs/plugin-react': versions.viteReact,
21
+ '@types/react-dom': '19.2.7',
22
+ '@types/node': '26.5.0',
23
+ };
24
+ await context.json(`${dir}/package.json`, pkg);
25
+ await context.json(`${dir}/tsconfig.json`, webTsconfig(context));
26
+ await context.write(`${dir}/vite.config.ts`, `import { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\nexport default defineConfig({ plugins: [react()], server: { port: ${port(context, app)}, strictPort: true } });\n`);
27
+ await context.write(`${dir}/index.html`, `<!doctype html>\n<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>${app.name}</title></head><body><div id="root"></div><script type="module" src="/src/main.tsx"></script></body></html>\n`);
28
+ await context.write(`${dir}/src/vite-env.d.ts`, '/// <reference types="vite/client" />\n');
29
+ await context.write(`${dir}/src/main.tsx`, `import { StrictMode } from 'react';
30
+ import { createRoot } from 'react-dom/client';
31
+ import { Providers } from './providers';
32
+ import { AuthControls } from './auth-controls';
33
+ ${entry.imports}
34
+ const root = document.getElementById('root');
35
+ if (!root) throw new Error('Missing root element.');
36
+ createRoot(root).render(<StrictMode><main><Providers><AuthControls />${entry.content}</Providers></main></StrictMode>);
37
+ `);
38
+ await common(context, app, 'VITE_CONVEX_URL');
39
+ await webMessages(context, app);
40
+ },
41
+ };
42
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/templates/apps/vite/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EACL,MAAM,EACN,YAAY,EACZ,QAAQ,EACR,IAAI,EACJ,WAAW,EACX,WAAW,GACZ,MAAM,cAAc,CAAC;AAEtB,MAAM,CAAC,MAAM,YAAY,GAAgB;IACvC,EAAE,EAAE,MAAM;IACV,KAAK,EAAE,cAAc;IACrB,KAAK,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG;QACzB,MAAM,GAAG,GAAG,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAC9C,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACnC,GAAG,CAAC,OAAO,GAAG;YACZ,GAAG,GAAG,CAAC,OAAO;YACd,GAAG,EAAE,MAAM;YACX,KAAK,EAAE,YAAY;YACnB,OAAO,EAAE,cAAc;SACxB,CAAC;QACF,GAAG,CAAC,YAAY,GAAG,EAAE,GAAG,GAAG,CAAC,YAAY,EAAE,WAAW,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC;QACxE,GAAG,CAAC,eAAe,GAAG;YACpB,GAAG,GAAG,CAAC,eAAe;YACtB,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,sBAAsB,EAAE,QAAQ,CAAC,SAAS;YAC1C,kBAAkB,EAAE,QAAQ;YAC5B,aAAa,EAAE,QAAQ;SACxB,CAAC;QACF,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,GAAG,eAAe,EAAE,GAAG,CAAC,CAAC;QAC/C,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,GAAG,gBAAgB,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;QACjE,MAAM,OAAO,CAAC,KAAK,CACjB,GAAG,GAAG,iBAAiB,EACvB,sJAAsJ,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,4BAA4B,CACrM,CAAC;QACF,MAAM,OAAO,CAAC,KAAK,CACjB,GAAG,GAAG,aAAa,EACnB,iJAAiJ,GAAG,CAAC,IAAI,+GAA+G,CACzQ,CAAC;QACF,MAAM,OAAO,CAAC,KAAK,CACjB,GAAG,GAAG,oBAAoB,EAC1B,yCAAyC,CAC1C,CAAC;QACF,MAAM,OAAO,CAAC,KAAK,CACjB,GAAG,GAAG,eAAe,EACrB;;;;EAIJ,KAAK,CAAC,OAAO;;;uEAGwD,KAAK,CAAC,OAAO;CACnF,CACI,CAAC;QACF,MAAM,MAAM,CAAC,OAAO,EAAE,GAAG,EAAE,iBAAiB,CAAC,CAAC;QAC9C,MAAM,WAAW,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAClC,CAAC;CACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { GeneratorContext } from '../../generator/types.js';
2
+ export declare function generateBackend(ctx: GeneratorContext): Promise<void>;
@@ -0,0 +1,58 @@
1
+ import { readdir, readFile } from 'node:fs/promises';
2
+ import { versions as v } from '../versions.js';
3
+ export async function generateBackend(ctx) {
4
+ const base = 'packages/backend';
5
+ await ctx.json(`${base}/package.json`, {
6
+ name: `@${ctx.scope}/backend`,
7
+ version: '0.0.0',
8
+ private: true,
9
+ type: 'module',
10
+ exports: {
11
+ './api': {
12
+ types: './convex/_generated/api.d.ts',
13
+ default: './convex/_generated/api.js',
14
+ },
15
+ './dataModel': { types: './convex/_generated/dataModel.d.ts' },
16
+ },
17
+ scripts: {
18
+ dev: 'convex dev',
19
+ codegen: 'convex codegen',
20
+ typecheck: 'tsc --noEmit -p convex/tsconfig.json',
21
+ build: 'tsc --noEmit -p convex/tsconfig.json',
22
+ lint: 'eslint .',
23
+ },
24
+ dependencies: { convex: v.convex },
25
+ devDependencies: {
26
+ typescript: v.typescript,
27
+ '@types/node': '24.12.2',
28
+ eslint: v.eslint,
29
+ [`@${ctx.scope}/eslint-config`]: 'workspace:*',
30
+ [`@${ctx.scope}/typescript-config`]: 'workspace:*',
31
+ },
32
+ });
33
+ await ctx.json(`${base}/convex.json`, {
34
+ $schema: './node_modules/convex/schemas/convex.schema.json',
35
+ aiFiles: { enabled: false },
36
+ });
37
+ await ctx.json(`${base}/tsconfig.json`, {
38
+ extends: './convex/tsconfig.json',
39
+ include: ['convex/**/*.ts'],
40
+ });
41
+ await ctx.write(`${base}/eslint.config.js`, `export { default } from '@${ctx.scope}/eslint-config';\n`);
42
+ await ctx.write(`${base}/.env.example`, "# Run pnpm convex:setup from the workspace root.\n# Convex writes deployment selection and public URLs to this package's .env.local.\n# Never copy this file wholesale into an application.\n");
43
+ const assetDir = new URL('../../../assets/backend/convex/', import.meta.url);
44
+ const selectedAssets = ctx.options.example === 'none'
45
+ ? new URL('../../../assets/backend-blank/convex/', import.meta.url)
46
+ : assetDir;
47
+ const files = ctx.options.example === 'none'
48
+ ? ['schema.ts', 'tsconfig.json']
49
+ : ['schema.ts', 'messages.ts', 'tsconfig.json'];
50
+ for (const file of files) {
51
+ await ctx.write(`${base}/convex/${file}`, await readFile(new URL(file, file === 'tsconfig.json' ? assetDir : selectedAssets), 'utf8'));
52
+ }
53
+ const generated = new URL('_generated/', selectedAssets);
54
+ for (const file of await readdir(generated)) {
55
+ await ctx.write(`${base}/convex/_generated/${file}`, await readFile(new URL(file, generated), 'utf8'));
56
+ }
57
+ }
58
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/backend/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { GeneratorContext } from '../../generator/types.js';
2
+ export declare function generateRoot(ctx: GeneratorContext): Promise<void>;