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.
- package/CONTRIBUTING.md +55 -0
- package/LICENSE +21 -0
- package/README.md +213 -0
- package/assets/backend/PROVENANCE.md +3 -0
- package/assets/backend/convex/_generated/api.d.ts +51 -0
- package/assets/backend/convex/_generated/api.js +23 -0
- package/assets/backend/convex/_generated/dataModel.d.ts +60 -0
- package/assets/backend/convex/_generated/server.d.ts +162 -0
- package/assets/backend/convex/_generated/server.js +101 -0
- package/assets/backend/convex/messages.ts +38 -0
- package/assets/backend/convex/schema.ts +9 -0
- package/assets/backend/convex/tsconfig.json +26 -0
- package/assets/backend-blank/PROVENANCE.md +3 -0
- package/assets/backend-blank/convex/_generated/api.d.ts +45 -0
- package/assets/backend-blank/convex/_generated/api.js +23 -0
- package/assets/backend-blank/convex/_generated/dataModel.d.ts +60 -0
- package/assets/backend-blank/convex/_generated/server.d.ts +162 -0
- package/assets/backend-blank/convex/_generated/server.js +101 -0
- package/assets/backend-blank/convex/schema.ts +3 -0
- package/assets/setup/convex-setup.mjs +250 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +19 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/commands/create.d.ts +8 -0
- package/dist/commands/create.js +182 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/generator/context.d.ts +3 -0
- package/dist/generator/context.js +81 -0
- package/dist/generator/context.js.map +1 -0
- package/dist/generator/index.d.ts +12 -0
- package/dist/generator/index.js +123 -0
- package/dist/generator/index.js.map +1 -0
- package/dist/generator/options.d.ts +15 -0
- package/dist/generator/options.js +85 -0
- package/dist/generator/options.js.map +1 -0
- package/dist/generator/types.d.ts +47 -0
- package/dist/generator/types.js +2 -0
- package/dist/generator/types.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/auth/clerk/index.d.ts +2 -0
- package/dist/integrations/auth/clerk/index.js +114 -0
- package/dist/integrations/auth/clerk/index.js.map +1 -0
- package/dist/integrations/auth/index.d.ts +2 -0
- package/dist/integrations/auth/index.js +7 -0
- package/dist/integrations/auth/index.js.map +1 -0
- package/dist/integrations/auth/none/index.d.ts +2 -0
- package/dist/integrations/auth/none/index.js +18 -0
- package/dist/integrations/auth/none/index.js.map +1 -0
- package/dist/integrations/auth/shared.d.ts +11 -0
- package/dist/integrations/auth/shared.js +40 -0
- package/dist/integrations/auth/shared.js.map +1 -0
- package/dist/package-manager/index.d.ts +6 -0
- package/dist/package-manager/index.js +22 -0
- package/dist/package-manager/index.js.map +1 -0
- package/dist/templates/apps/expo/index.d.ts +2 -0
- package/dist/templates/apps/expo/index.js +91 -0
- package/dist/templates/apps/expo/index.js.map +1 -0
- package/dist/templates/apps/index.d.ts +2 -0
- package/dist/templates/apps/index.js +11 -0
- package/dist/templates/apps/index.js.map +1 -0
- package/dist/templates/apps/next/index.d.ts +2 -0
- package/dist/templates/apps/next/index.js +66 -0
- package/dist/templates/apps/next/index.js.map +1 -0
- package/dist/templates/apps/shared.d.ts +24 -0
- package/dist/templates/apps/shared.js +124 -0
- package/dist/templates/apps/shared.js.map +1 -0
- package/dist/templates/apps/tanstack-start/index.d.ts +2 -0
- package/dist/templates/apps/tanstack-start/index.js +82 -0
- package/dist/templates/apps/tanstack-start/index.js.map +1 -0
- package/dist/templates/apps/vite/index.d.ts +2 -0
- package/dist/templates/apps/vite/index.js +42 -0
- package/dist/templates/apps/vite/index.js.map +1 -0
- package/dist/templates/backend/index.d.ts +2 -0
- package/dist/templates/backend/index.js +58 -0
- package/dist/templates/backend/index.js.map +1 -0
- package/dist/templates/root/index.d.ts +2 -0
- package/dist/templates/root/index.js +178 -0
- package/dist/templates/root/index.js.map +1 -0
- package/dist/templates/versions.d.ts +18 -0
- package/dist/templates/versions.js +19 -0
- package/dist/templates/versions.js.map +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +11 -0
- package/dist/version.js.map +1 -0
- package/docs/adding-a-framework.md +27 -0
- package/docs/adding-an-auth-provider.md +31 -0
- package/docs/architecture.md +49 -0
- package/docs/releases.md +78 -0
- package/docs/research.md +76 -0
- package/docs/verification.md +78 -0
- 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,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,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,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,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,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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"}
|