@tanstack/cta-engine 0.10.0-alpha.13 → 0.10.0-alpha.15
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/dist/cli.js +22 -21
- package/dist/create-app.js +9 -9
- package/dist/custom-add-on.js +9 -7
- package/dist/index.js +4 -0
- package/dist/options.js +10 -10
- package/dist/types/custom-add-on.d.ts +4 -1
- package/dist/types/index.d.ts +6 -0
- package/dist/types/types.d.ts +8 -7
- package/package.json +1 -1
- package/src/cli.ts +29 -22
- package/src/create-app.ts +9 -9
- package/src/custom-add-on.ts +10 -8
- package/src/index.ts +10 -0
- package/src/options.ts +11 -11
- package/src/types.ts +9 -7
- package/templates/react/add-on/clerk/assets/_dot_env.local.append +1 -1
- package/templates/react/add-on/convex/assets/_dot_env.local.append +2 -2
- package/templates/react/add-on/tanstack-query/assets/src/integrations/tanstack-query/root-provider.tsx.ejs +2 -2
- package/templates/react/example/tanchat/assets/src/routes/api.messages.ts +24 -0
- package/templates/react/example/tanchat/assets/src/routes/api.sse.ts +23 -0
- package/templates/react/example/tanchat/assets/src/utils/demo.sse.ts +31 -0
- package/templates/react/example/tanchat/package.json +1 -0
package/dist/cli.js
CHANGED
|
@@ -7,29 +7,30 @@ import { SUPPORTED_TOOLCHAINS } from './toolchain.js';
|
|
|
7
7
|
import runServer from './mcp.js';
|
|
8
8
|
import { listAddOns } from './add-ons.js';
|
|
9
9
|
import { DEFAULT_FRAMEWORK, SUPPORTED_FRAMEWORKS } from './constants.js';
|
|
10
|
-
|
|
10
|
+
import { initAddOn } from './custom-add-on.js';
|
|
11
11
|
import { createDefaultEnvironment } from './environment.js';
|
|
12
|
+
import { add } from './add.js';
|
|
12
13
|
export function cli({ name, appName, forcedMode, forcedAddOns, }) {
|
|
13
14
|
const program = new Command();
|
|
14
15
|
program.name(name).description(`CLI to create a new ${appName} application`);
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
16
|
+
program
|
|
17
|
+
.command('add')
|
|
18
|
+
.argument('add-on', 'Name of the add-on (or add-ons separated by commas)')
|
|
19
|
+
.action(async (addOn) => {
|
|
20
|
+
await add(addOn.split(',').map((addon) => addon.trim()));
|
|
21
|
+
});
|
|
22
|
+
program
|
|
23
|
+
.command('update-add-on')
|
|
24
|
+
.description('Create or update an add-on from the current project')
|
|
25
|
+
.action(async () => {
|
|
26
|
+
await initAddOn('add-on');
|
|
27
|
+
});
|
|
28
|
+
program
|
|
29
|
+
.command('update-starter')
|
|
30
|
+
.description('Create or update a project starter from the current project')
|
|
31
|
+
.action(async () => {
|
|
32
|
+
await initAddOn('starter');
|
|
33
|
+
});
|
|
33
34
|
program.argument('[project-name]', 'name of the project');
|
|
34
35
|
if (!forcedMode) {
|
|
35
36
|
program.option('--template <type>', 'project template (typescript, javascript, file-router)', (value) => {
|
|
@@ -48,7 +49,7 @@ export function cli({ name, appName, forcedMode, forcedAddOns, }) {
|
|
|
48
49
|
}
|
|
49
50
|
return value;
|
|
50
51
|
}, DEFAULT_FRAMEWORK)
|
|
51
|
-
|
|
52
|
+
.option('--starter [url]', 'initialize this project from a starter URL', false)
|
|
52
53
|
.option(`--package-manager <${SUPPORTED_PACKAGE_MANAGERS.join('|')}>`, `Explicitly tell the CLI to use this package manager`, (value) => {
|
|
53
54
|
if (!SUPPORTED_PACKAGE_MANAGERS.includes(value)) {
|
|
54
55
|
throw new InvalidArgumentError(`Invalid package manager: ${value}. The following are allowed: ${SUPPORTED_PACKAGE_MANAGERS.join(', ')}`);
|
|
@@ -71,7 +72,7 @@ export function cli({ name, appName, forcedMode, forcedAddOns, }) {
|
|
|
71
72
|
})
|
|
72
73
|
.option('--list-add-ons', 'list all available add-ons', false)
|
|
73
74
|
.option('--no-git', 'do not create a git repository')
|
|
74
|
-
.option('--target-dir <path>', 'the directory
|
|
75
|
+
.option('--target-dir <path>', 'the target directory for the application root')
|
|
75
76
|
.option('--mcp', 'run the MCP server', false)
|
|
76
77
|
.option('--mcp-sse', 'run the MCP server in SSE mode', false);
|
|
77
78
|
program.action(async (projectName, options) => {
|
package/dist/create-app.js
CHANGED
|
@@ -332,9 +332,9 @@ export async function createApp(options, { silent = false, environment, cwd, app
|
|
|
332
332
|
}
|
|
333
333
|
}
|
|
334
334
|
}
|
|
335
|
-
if (options.
|
|
336
|
-
if (options.
|
|
337
|
-
for (const component of options.
|
|
335
|
+
if (options.starter) {
|
|
336
|
+
if (options.starter.shadcnComponents) {
|
|
337
|
+
for (const component of options.starter.shadcnComponents) {
|
|
338
338
|
shadcnComponents.add(component);
|
|
339
339
|
}
|
|
340
340
|
}
|
|
@@ -433,11 +433,11 @@ export async function createApp(options, { silent = false, environment, cwd, app
|
|
|
433
433
|
}
|
|
434
434
|
// Create the README.md
|
|
435
435
|
await templateFile(templateDirBase, 'README.md.ejs');
|
|
436
|
-
// Adding
|
|
437
|
-
if (options.
|
|
438
|
-
s?.start(`Setting up
|
|
439
|
-
await runAddOn(options.
|
|
440
|
-
s?.stop(`
|
|
436
|
+
// Adding starter
|
|
437
|
+
if (options.starter) {
|
|
438
|
+
s?.start(`Setting up starter ${options.starter.name}...`);
|
|
439
|
+
await runAddOn(options.starter);
|
|
440
|
+
s?.stop(`Starter ${options.starter.name} setup complete`);
|
|
441
441
|
}
|
|
442
442
|
// Install dependencies
|
|
443
443
|
s?.start(`Installing dependencies via ${options.packageManager}...`);
|
|
@@ -492,6 +492,6 @@ Use the following commands to start your app:
|
|
|
492
492
|
% cd ${options.projectName}
|
|
493
493
|
% ${startCommand}
|
|
494
494
|
|
|
495
|
-
Please
|
|
495
|
+
Please check the README.md for more information on testing, styling, adding routes, react-query, etc.${errorStatement}`);
|
|
496
496
|
}
|
|
497
497
|
}
|
package/dist/custom-add-on.js
CHANGED
|
@@ -9,11 +9,11 @@ import { finalizeAddOns } from './add-ons.js';
|
|
|
9
9
|
import { readFileHelper } from './file-helper.js';
|
|
10
10
|
const INFO_FILE = {
|
|
11
11
|
'add-on': '.add-on/info.json',
|
|
12
|
-
|
|
12
|
+
starter: 'starter-info.json',
|
|
13
13
|
};
|
|
14
14
|
const COMPILED_FILE = {
|
|
15
15
|
'add-on': 'add-on.json',
|
|
16
|
-
|
|
16
|
+
starter: 'starter.json',
|
|
17
17
|
};
|
|
18
18
|
const ADD_ON_DIR = '.add-on';
|
|
19
19
|
const ASSETS_DIR = 'assets';
|
|
@@ -76,7 +76,7 @@ export default (parentRoute: RootRoute) => createRoute({
|
|
|
76
76
|
.trim();
|
|
77
77
|
return { url: path, code, name };
|
|
78
78
|
}
|
|
79
|
-
async function
|
|
79
|
+
export async function createAppOptionsFromPersisted(json) {
|
|
80
80
|
return {
|
|
81
81
|
...json,
|
|
82
82
|
chosenAddOns: await finalizeAddOns(json.framework, json.mode, [...json.existingAddOns]),
|
|
@@ -154,12 +154,13 @@ To create an add-on, the project must be created with TypeScript.`);
|
|
|
154
154
|
: {
|
|
155
155
|
name: `${persistedOptions.projectName}-${mode}`,
|
|
156
156
|
version: '0.0.1',
|
|
157
|
-
description: mode === 'add-on' ? 'Add-on' : 'Project
|
|
157
|
+
description: mode === 'add-on' ? 'Add-on' : 'Project starter',
|
|
158
158
|
author: 'Jane Smith <jane.smith@example.com>',
|
|
159
159
|
license: 'MIT',
|
|
160
160
|
link: `https://github.com/jane-smith/${persistedOptions.projectName}-${mode}`,
|
|
161
161
|
command: {},
|
|
162
162
|
shadcnComponents: [],
|
|
163
|
+
framework: persistedOptions.framework,
|
|
163
164
|
templates: [persistedOptions.mode],
|
|
164
165
|
routes: [],
|
|
165
166
|
warning: '',
|
|
@@ -173,7 +174,7 @@ To create an add-on, the project must be created with TypeScript.`);
|
|
|
173
174
|
},
|
|
174
175
|
};
|
|
175
176
|
const compiledInfo = JSON.parse(JSON.stringify(info));
|
|
176
|
-
const originalOutput = await runCreateApp(await
|
|
177
|
+
const originalOutput = await runCreateApp(await createAppOptionsFromPersisted(persistedOptions));
|
|
177
178
|
const originalPackageJson = JSON.parse(originalOutput.files[resolve(process.cwd(), 'package.json')]);
|
|
178
179
|
const currentPackageJson = JSON.parse((await readFile('package.json')).toString());
|
|
179
180
|
for (const script of Object.keys(currentPackageJson.scripts)) {
|
|
@@ -201,7 +202,7 @@ To create an add-on, the project must be created with TypeScript.`);
|
|
|
201
202
|
// Find altered files
|
|
202
203
|
const changedFiles = {};
|
|
203
204
|
await compareFiles('.', IGNORE_FILES, originalOutput.files, changedFiles);
|
|
204
|
-
if (mode === '
|
|
205
|
+
if (mode === 'starter') {
|
|
205
206
|
compiledInfo.files = changedFiles;
|
|
206
207
|
}
|
|
207
208
|
else {
|
|
@@ -235,7 +236,8 @@ To create an add-on, the project must be created with TypeScript.`);
|
|
|
235
236
|
compiledInfo.routes = info.routes;
|
|
236
237
|
compiledInfo.framework = persistedOptions.framework;
|
|
237
238
|
compiledInfo.addDependencies = persistedOptions.existingAddOns;
|
|
238
|
-
|
|
239
|
+
compiledInfo.packageAdditions = info.packageAdditions;
|
|
240
|
+
if (mode === 'starter') {
|
|
239
241
|
compiledInfo.mode = persistedOptions.mode;
|
|
240
242
|
compiledInfo.typescript = persistedOptions.typescript;
|
|
241
243
|
compiledInfo.tailwind = persistedOptions.tailwind;
|
package/dist/index.js
CHANGED
|
@@ -1 +1,5 @@
|
|
|
1
1
|
export { cli } from './cli.js';
|
|
2
|
+
export { getAllAddOns } from './add-ons.js';
|
|
3
|
+
export { createApp } from './create-app.js';
|
|
4
|
+
export { createAppOptionsFromPersisted } from './custom-add-on.js';
|
|
5
|
+
export { createMemoryEnvironment, createDefaultEnvironment, } from './environment.js';
|
package/dist/options.js
CHANGED
|
@@ -23,22 +23,22 @@ export async function normalizeOptions(cliOptions, forcedAddOns) {
|
|
|
23
23
|
tailwind = true;
|
|
24
24
|
}
|
|
25
25
|
let mode = cliOptions.template === 'file-router' ? FILE_ROUTER : CODE_ROUTER;
|
|
26
|
-
const
|
|
27
|
-
? (await loadRemoteAddOn(cliOptions.
|
|
26
|
+
const starter = cliOptions.starter
|
|
27
|
+
? (await loadRemoteAddOn(cliOptions.starter))
|
|
28
28
|
: undefined;
|
|
29
|
-
if (
|
|
30
|
-
tailwind =
|
|
31
|
-
typescript =
|
|
32
|
-
cliOptions.framework =
|
|
33
|
-
mode =
|
|
29
|
+
if (starter) {
|
|
30
|
+
tailwind = starter.tailwind;
|
|
31
|
+
typescript = starter.typescript;
|
|
32
|
+
cliOptions.framework = starter.framework;
|
|
33
|
+
mode = starter.mode;
|
|
34
34
|
}
|
|
35
35
|
let addOns = false;
|
|
36
36
|
let chosenAddOns = [];
|
|
37
37
|
if (Array.isArray(cliOptions.addOns) ||
|
|
38
|
-
|
|
38
|
+
starter?.dependsOn ||
|
|
39
39
|
forcedAddOns) {
|
|
40
40
|
addOns = true;
|
|
41
|
-
let finalAddOns = Array.from(new Set([...(
|
|
41
|
+
let finalAddOns = Array.from(new Set([...(starter?.dependsOn || []), ...(forcedAddOns || [])]));
|
|
42
42
|
if (cliOptions.addOns && Array.isArray(cliOptions.addOns)) {
|
|
43
43
|
finalAddOns = Array.from(new Set([
|
|
44
44
|
...(forcedAddOns || []),
|
|
@@ -64,7 +64,7 @@ export async function normalizeOptions(cliOptions, forcedAddOns) {
|
|
|
64
64
|
addOns,
|
|
65
65
|
chosenAddOns,
|
|
66
66
|
variableValues: {},
|
|
67
|
-
|
|
67
|
+
starter,
|
|
68
68
|
};
|
|
69
69
|
}
|
|
70
70
|
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
-
type
|
|
1
|
+
import type { Options } from './types.js';
|
|
2
|
+
import type { PersistedOptions } from './config-file.js';
|
|
3
|
+
type AddOnMode = 'add-on' | 'starter';
|
|
4
|
+
export declare function createAppOptionsFromPersisted(json: PersistedOptions): Promise<Required<Options>>;
|
|
2
5
|
export declare function initAddOn(mode: AddOnMode): Promise<void>;
|
|
3
6
|
export {};
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
1
|
export { cli } from './cli.js';
|
|
2
|
+
export { getAllAddOns } from './add-ons.js';
|
|
3
|
+
export { createApp } from './create-app.js';
|
|
4
|
+
export { createAppOptionsFromPersisted } from './custom-add-on.js';
|
|
5
|
+
export { createMemoryEnvironment, createDefaultEnvironment, } from './environment.js';
|
|
6
|
+
export type { AddOn, Framework, Mode } from './types.js';
|
|
7
|
+
export type { PersistedOptions } from './config-file.js';
|
package/dist/types/types.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { PackageManager } from './package-manager.js';
|
|
|
3
3
|
import type { ToolChain } from './toolchain.js';
|
|
4
4
|
export type Framework = 'solid' | 'react';
|
|
5
5
|
export type TemplateOptions = 'typescript' | 'javascript' | 'file-router';
|
|
6
|
+
export type Mode = typeof CODE_ROUTER | typeof FILE_ROUTER;
|
|
6
7
|
export interface Options {
|
|
7
8
|
framework: Framework;
|
|
8
9
|
projectName: string;
|
|
@@ -10,12 +11,12 @@ export interface Options {
|
|
|
10
11
|
tailwind: boolean;
|
|
11
12
|
packageManager: PackageManager;
|
|
12
13
|
toolchain: ToolChain;
|
|
13
|
-
mode:
|
|
14
|
+
mode: Mode;
|
|
14
15
|
addOns: boolean;
|
|
15
16
|
chosenAddOns: Array<AddOn>;
|
|
16
17
|
git: boolean;
|
|
17
18
|
variableValues: Record<string, string | number | boolean>;
|
|
18
|
-
|
|
19
|
+
starter?: AddOn | undefined;
|
|
19
20
|
}
|
|
20
21
|
export interface CliOptions {
|
|
21
22
|
template?: TemplateOptions;
|
|
@@ -29,7 +30,7 @@ export interface CliOptions {
|
|
|
29
30
|
listAddOns?: boolean;
|
|
30
31
|
mcp?: boolean;
|
|
31
32
|
mcpSse?: boolean;
|
|
32
|
-
|
|
33
|
+
starter?: string;
|
|
33
34
|
targetDir?: string;
|
|
34
35
|
}
|
|
35
36
|
export type Environment = {
|
|
@@ -69,7 +70,7 @@ export type AddOn = {
|
|
|
69
70
|
id: string;
|
|
70
71
|
name: string;
|
|
71
72
|
description: string;
|
|
72
|
-
type: 'add-on' | 'example' | '
|
|
73
|
+
type: 'add-on' | 'example' | 'starter';
|
|
73
74
|
link: string;
|
|
74
75
|
templates: Array<string>;
|
|
75
76
|
routes: Array<{
|
|
@@ -94,13 +95,13 @@ export type AddOn = {
|
|
|
94
95
|
files?: Record<string, string>;
|
|
95
96
|
deletedFiles?: Array<string>;
|
|
96
97
|
};
|
|
97
|
-
export type
|
|
98
|
-
type: '
|
|
98
|
+
export type Starter = AddOn & {
|
|
99
|
+
type: 'starter';
|
|
99
100
|
version: string;
|
|
100
101
|
author: string;
|
|
101
102
|
link: string;
|
|
102
103
|
license: string;
|
|
103
|
-
mode:
|
|
104
|
+
mode: Mode;
|
|
104
105
|
framework: Framework;
|
|
105
106
|
typescript: boolean;
|
|
106
107
|
tailwind: boolean;
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -9,10 +9,10 @@ import { SUPPORTED_TOOLCHAINS } from './toolchain.js'
|
|
|
9
9
|
import runServer from './mcp.js'
|
|
10
10
|
import { listAddOns } from './add-ons.js'
|
|
11
11
|
import { DEFAULT_FRAMEWORK, SUPPORTED_FRAMEWORKS } from './constants.js'
|
|
12
|
-
|
|
12
|
+
import { initAddOn } from './custom-add-on.js'
|
|
13
13
|
|
|
14
14
|
import { createDefaultEnvironment } from './environment.js'
|
|
15
|
-
|
|
15
|
+
import { add } from './add.js'
|
|
16
16
|
|
|
17
17
|
import type { PackageManager } from './package-manager.js'
|
|
18
18
|
import type { ToolChain } from './toolchain.js'
|
|
@@ -33,26 +33,26 @@ export function cli({
|
|
|
33
33
|
|
|
34
34
|
program.name(name).description(`CLI to create a new ${appName} application`)
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
program
|
|
37
|
+
.command('add')
|
|
38
|
+
.argument('add-on', 'Name of the add-on (or add-ons separated by commas)')
|
|
39
|
+
.action(async (addOn: string) => {
|
|
40
|
+
await add(addOn.split(',').map((addon) => addon.trim()))
|
|
41
|
+
})
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
program
|
|
44
|
+
.command('update-add-on')
|
|
45
|
+
.description('Create or update an add-on from the current project')
|
|
46
|
+
.action(async () => {
|
|
47
|
+
await initAddOn('add-on')
|
|
48
|
+
})
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
50
|
+
program
|
|
51
|
+
.command('update-starter')
|
|
52
|
+
.description('Create or update a project starter from the current project')
|
|
53
|
+
.action(async () => {
|
|
54
|
+
await initAddOn('starter')
|
|
55
|
+
})
|
|
56
56
|
|
|
57
57
|
program.argument('[project-name]', 'name of the project')
|
|
58
58
|
|
|
@@ -90,7 +90,11 @@ export function cli({
|
|
|
90
90
|
},
|
|
91
91
|
DEFAULT_FRAMEWORK,
|
|
92
92
|
)
|
|
93
|
-
|
|
93
|
+
.option(
|
|
94
|
+
'--starter [url]',
|
|
95
|
+
'initialize this project from a starter URL',
|
|
96
|
+
false,
|
|
97
|
+
)
|
|
94
98
|
.option<PackageManager>(
|
|
95
99
|
`--package-manager <${SUPPORTED_PACKAGE_MANAGERS.join('|')}>`,
|
|
96
100
|
`Explicitly tell the CLI to use this package manager`,
|
|
@@ -133,7 +137,10 @@ export function cli({
|
|
|
133
137
|
)
|
|
134
138
|
.option('--list-add-ons', 'list all available add-ons', false)
|
|
135
139
|
.option('--no-git', 'do not create a git repository')
|
|
136
|
-
.option(
|
|
140
|
+
.option(
|
|
141
|
+
'--target-dir <path>',
|
|
142
|
+
'the target directory for the application root',
|
|
143
|
+
)
|
|
137
144
|
.option('--mcp', 'run the MCP server', false)
|
|
138
145
|
.option('--mcp-sse', 'run the MCP server in SSE mode', false)
|
|
139
146
|
|
package/src/create-app.ts
CHANGED
|
@@ -529,9 +529,9 @@ export async function createApp(
|
|
|
529
529
|
}
|
|
530
530
|
}
|
|
531
531
|
}
|
|
532
|
-
if (options.
|
|
533
|
-
if (options.
|
|
534
|
-
for (const component of options.
|
|
532
|
+
if (options.starter) {
|
|
533
|
+
if (options.starter.shadcnComponents) {
|
|
534
|
+
for (const component of options.starter.shadcnComponents) {
|
|
535
535
|
shadcnComponents.add(component)
|
|
536
536
|
}
|
|
537
537
|
}
|
|
@@ -714,11 +714,11 @@ export async function createApp(
|
|
|
714
714
|
// Create the README.md
|
|
715
715
|
await templateFile(templateDirBase, 'README.md.ejs')
|
|
716
716
|
|
|
717
|
-
// Adding
|
|
718
|
-
if (options.
|
|
719
|
-
s?.start(`Setting up
|
|
720
|
-
await runAddOn(options.
|
|
721
|
-
s?.stop(`
|
|
717
|
+
// Adding starter
|
|
718
|
+
if (options.starter) {
|
|
719
|
+
s?.start(`Setting up starter ${options.starter.name}...`)
|
|
720
|
+
await runAddOn(options.starter)
|
|
721
|
+
s?.stop(`Starter ${options.starter.name} setup complete`)
|
|
722
722
|
}
|
|
723
723
|
|
|
724
724
|
// Install dependencies
|
|
@@ -799,6 +799,6 @@ Use the following commands to start your app:
|
|
|
799
799
|
% cd ${options.projectName}
|
|
800
800
|
% ${startCommand}
|
|
801
801
|
|
|
802
|
-
Please
|
|
802
|
+
Please check the README.md for more information on testing, styling, adding routes, react-query, etc.${errorStatement}`)
|
|
803
803
|
}
|
|
804
804
|
}
|
package/src/custom-add-on.ts
CHANGED
|
@@ -12,15 +12,15 @@ import { readFileHelper } from './file-helper.js'
|
|
|
12
12
|
import type { Framework, Options } from './types.js'
|
|
13
13
|
import type { PersistedOptions } from './config-file.js'
|
|
14
14
|
|
|
15
|
-
type AddOnMode = 'add-on' | '
|
|
15
|
+
type AddOnMode = 'add-on' | 'starter'
|
|
16
16
|
|
|
17
17
|
const INFO_FILE: Record<AddOnMode, string> = {
|
|
18
18
|
'add-on': '.add-on/info.json',
|
|
19
|
-
|
|
19
|
+
starter: 'starter-info.json',
|
|
20
20
|
}
|
|
21
21
|
const COMPILED_FILE: Record<AddOnMode, string> = {
|
|
22
22
|
'add-on': 'add-on.json',
|
|
23
|
-
|
|
23
|
+
starter: 'starter.json',
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
const ADD_ON_DIR = '.add-on'
|
|
@@ -102,7 +102,7 @@ export default (parentRoute: RootRoute) => createRoute({
|
|
|
102
102
|
return { url: path, code, name }
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
async function
|
|
105
|
+
export async function createAppOptionsFromPersisted(
|
|
106
106
|
json: PersistedOptions,
|
|
107
107
|
): Promise<Required<Options>> {
|
|
108
108
|
return {
|
|
@@ -198,12 +198,13 @@ To create an add-on, the project must be created with TypeScript.`)
|
|
|
198
198
|
: {
|
|
199
199
|
name: `${persistedOptions.projectName}-${mode}`,
|
|
200
200
|
version: '0.0.1',
|
|
201
|
-
description: mode === 'add-on' ? 'Add-on' : 'Project
|
|
201
|
+
description: mode === 'add-on' ? 'Add-on' : 'Project starter',
|
|
202
202
|
author: 'Jane Smith <jane.smith@example.com>',
|
|
203
203
|
license: 'MIT',
|
|
204
204
|
link: `https://github.com/jane-smith/${persistedOptions.projectName}-${mode}`,
|
|
205
205
|
command: {},
|
|
206
206
|
shadcnComponents: [],
|
|
207
|
+
framework: persistedOptions.framework,
|
|
207
208
|
templates: [persistedOptions.mode],
|
|
208
209
|
routes: [],
|
|
209
210
|
warning: '',
|
|
@@ -220,7 +221,7 @@ To create an add-on, the project must be created with TypeScript.`)
|
|
|
220
221
|
const compiledInfo = JSON.parse(JSON.stringify(info))
|
|
221
222
|
|
|
222
223
|
const originalOutput = await runCreateApp(
|
|
223
|
-
await
|
|
224
|
+
await createAppOptionsFromPersisted(persistedOptions),
|
|
224
225
|
)
|
|
225
226
|
|
|
226
227
|
const originalPackageJson = JSON.parse(
|
|
@@ -264,7 +265,7 @@ To create an add-on, the project must be created with TypeScript.`)
|
|
|
264
265
|
// Find altered files
|
|
265
266
|
const changedFiles: Record<string, string> = {}
|
|
266
267
|
await compareFiles('.', IGNORE_FILES, originalOutput.files, changedFiles)
|
|
267
|
-
if (mode === '
|
|
268
|
+
if (mode === 'starter') {
|
|
268
269
|
compiledInfo.files = changedFiles
|
|
269
270
|
} else {
|
|
270
271
|
const assetsDir = resolve(ADD_ON_DIR, ASSETS_DIR)
|
|
@@ -302,8 +303,9 @@ To create an add-on, the project must be created with TypeScript.`)
|
|
|
302
303
|
compiledInfo.routes = info.routes
|
|
303
304
|
compiledInfo.framework = persistedOptions.framework
|
|
304
305
|
compiledInfo.addDependencies = persistedOptions.existingAddOns
|
|
306
|
+
compiledInfo.packageAdditions = info.packageAdditions
|
|
305
307
|
|
|
306
|
-
if (mode === '
|
|
308
|
+
if (mode === 'starter') {
|
|
307
309
|
compiledInfo.mode = persistedOptions.mode
|
|
308
310
|
compiledInfo.typescript = persistedOptions.typescript
|
|
309
311
|
compiledInfo.tailwind = persistedOptions.tailwind
|
package/src/index.ts
CHANGED
|
@@ -1 +1,11 @@
|
|
|
1
1
|
export { cli } from './cli.js'
|
|
2
|
+
export { getAllAddOns } from './add-ons.js'
|
|
3
|
+
export { createApp } from './create-app.js'
|
|
4
|
+
export { createAppOptionsFromPersisted } from './custom-add-on.js'
|
|
5
|
+
export {
|
|
6
|
+
createMemoryEnvironment,
|
|
7
|
+
createDefaultEnvironment,
|
|
8
|
+
} from './environment.js'
|
|
9
|
+
|
|
10
|
+
export type { AddOn, Framework, Mode } from './types.js'
|
|
11
|
+
export type { PersistedOptions } from './config-file.js'
|
package/src/options.ts
CHANGED
|
@@ -16,7 +16,7 @@ import { DEFAULT_TOOLCHAIN, SUPPORTED_TOOLCHAINS } from './toolchain.js'
|
|
|
16
16
|
import { CODE_ROUTER, DEFAULT_FRAMEWORK, FILE_ROUTER } from './constants.js'
|
|
17
17
|
import { finalizeAddOns, getAllAddOns, loadRemoteAddOn } from './add-ons.js'
|
|
18
18
|
|
|
19
|
-
import type { AddOn, CliOptions, Options,
|
|
19
|
+
import type { AddOn, CliOptions, Options, Starter, Variable } from './types.js'
|
|
20
20
|
|
|
21
21
|
// If all CLI options are provided, use them directly
|
|
22
22
|
export async function normalizeOptions(
|
|
@@ -47,27 +47,27 @@ export async function normalizeOptions(
|
|
|
47
47
|
let mode: typeof FILE_ROUTER | typeof CODE_ROUTER =
|
|
48
48
|
cliOptions.template === 'file-router' ? FILE_ROUTER : CODE_ROUTER
|
|
49
49
|
|
|
50
|
-
const
|
|
51
|
-
? ((await loadRemoteAddOn(cliOptions.
|
|
50
|
+
const starter = cliOptions.starter
|
|
51
|
+
? ((await loadRemoteAddOn(cliOptions.starter)) as Starter)
|
|
52
52
|
: undefined
|
|
53
53
|
|
|
54
|
-
if (
|
|
55
|
-
tailwind =
|
|
56
|
-
typescript =
|
|
57
|
-
cliOptions.framework =
|
|
58
|
-
mode =
|
|
54
|
+
if (starter) {
|
|
55
|
+
tailwind = starter.tailwind
|
|
56
|
+
typescript = starter.typescript
|
|
57
|
+
cliOptions.framework = starter.framework
|
|
58
|
+
mode = starter.mode
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
let addOns = false
|
|
62
62
|
let chosenAddOns: Array<AddOn> = []
|
|
63
63
|
if (
|
|
64
64
|
Array.isArray(cliOptions.addOns) ||
|
|
65
|
-
|
|
65
|
+
starter?.dependsOn ||
|
|
66
66
|
forcedAddOns
|
|
67
67
|
) {
|
|
68
68
|
addOns = true
|
|
69
69
|
let finalAddOns = Array.from(
|
|
70
|
-
new Set([...(
|
|
70
|
+
new Set([...(starter?.dependsOn || []), ...(forcedAddOns || [])]),
|
|
71
71
|
)
|
|
72
72
|
if (cliOptions.addOns && Array.isArray(cliOptions.addOns)) {
|
|
73
73
|
finalAddOns = Array.from(
|
|
@@ -102,7 +102,7 @@ export async function normalizeOptions(
|
|
|
102
102
|
addOns,
|
|
103
103
|
chosenAddOns,
|
|
104
104
|
variableValues: {},
|
|
105
|
-
|
|
105
|
+
starter,
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
}
|
package/src/types.ts
CHANGED
|
@@ -6,6 +6,8 @@ export type Framework = 'solid' | 'react'
|
|
|
6
6
|
|
|
7
7
|
export type TemplateOptions = 'typescript' | 'javascript' | 'file-router'
|
|
8
8
|
|
|
9
|
+
export type Mode = typeof CODE_ROUTER | typeof FILE_ROUTER
|
|
10
|
+
|
|
9
11
|
export interface Options {
|
|
10
12
|
framework: Framework
|
|
11
13
|
projectName: string
|
|
@@ -13,12 +15,12 @@ export interface Options {
|
|
|
13
15
|
tailwind: boolean
|
|
14
16
|
packageManager: PackageManager
|
|
15
17
|
toolchain: ToolChain
|
|
16
|
-
mode:
|
|
18
|
+
mode: Mode
|
|
17
19
|
addOns: boolean
|
|
18
20
|
chosenAddOns: Array<AddOn>
|
|
19
21
|
git: boolean
|
|
20
22
|
variableValues: Record<string, string | number | boolean>
|
|
21
|
-
|
|
23
|
+
starter?: AddOn | undefined
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
export interface CliOptions {
|
|
@@ -33,7 +35,7 @@ export interface CliOptions {
|
|
|
33
35
|
listAddOns?: boolean
|
|
34
36
|
mcp?: boolean
|
|
35
37
|
mcpSse?: boolean
|
|
36
|
-
|
|
38
|
+
starter?: string
|
|
37
39
|
targetDir?: string
|
|
38
40
|
}
|
|
39
41
|
|
|
@@ -81,7 +83,7 @@ export type AddOn = {
|
|
|
81
83
|
id: string
|
|
82
84
|
name: string
|
|
83
85
|
description: string
|
|
84
|
-
type: 'add-on' | 'example' | '
|
|
86
|
+
type: 'add-on' | 'example' | 'starter'
|
|
85
87
|
link: string
|
|
86
88
|
templates: Array<string>
|
|
87
89
|
routes: Array<{
|
|
@@ -108,13 +110,13 @@ export type AddOn = {
|
|
|
108
110
|
deletedFiles?: Array<string>
|
|
109
111
|
}
|
|
110
112
|
|
|
111
|
-
export type
|
|
112
|
-
type: '
|
|
113
|
+
export type Starter = AddOn & {
|
|
114
|
+
type: 'starter'
|
|
113
115
|
version: string
|
|
114
116
|
author: string
|
|
115
117
|
link: string
|
|
116
118
|
license: string
|
|
117
|
-
mode:
|
|
119
|
+
mode: Mode
|
|
118
120
|
framework: Framework
|
|
119
121
|
typescript: boolean
|
|
120
122
|
tailwind: boolean
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
# Clerk configuration, get this key from your [Dashboard](
|
|
1
|
+
# Clerk configuration, get this key from your [Dashboard](dashboard.clerk.com)
|
|
2
2
|
VITE_CLERK_PUBLISHABLE_KEY=
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
# Convex configuration, get this URL from your [Dashboard](
|
|
1
|
+
# Convex configuration, get this URL from your [Dashboard](dashboard.convex.dev)
|
|
2
2
|
CONVEX_DEPLOYMENT=
|
|
3
|
-
VITE_CONVEX_URL=
|
|
3
|
+
VITE_CONVEX_URL=
|
|
@@ -13,7 +13,7 @@ function getUrl() {
|
|
|
13
13
|
if (typeof window !== "undefined") return "";
|
|
14
14
|
return `http://localhost:${process.env.PORT ?? 3000}`;
|
|
15
15
|
})();
|
|
16
|
-
return base
|
|
16
|
+
return `${base}/api/trpc`;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export const trpcClient = createTRPCClient<TRPCRouter>({
|
|
@@ -67,4 +67,4 @@ export function Provider({ children }: { children: React.ReactNode }) {
|
|
|
67
67
|
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
|
|
68
68
|
)
|
|
69
69
|
}
|
|
70
|
-
<% } %>
|
|
70
|
+
<% } %>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createAPIFileRoute } from "@tanstack/react-start/api";
|
|
2
|
+
import { getEvent } from "vinxi/http";
|
|
3
|
+
|
|
4
|
+
import { transports } from "@/utils/demo.sse";
|
|
5
|
+
|
|
6
|
+
export const APIRoute = createAPIFileRoute("/api/messages")({
|
|
7
|
+
// @ts-ignore
|
|
8
|
+
POST: async ({ request, params }) => {
|
|
9
|
+
const body = await request.json();
|
|
10
|
+
const url = new URL(request.url);
|
|
11
|
+
const sessionId = url.searchParams.get("sessionId") as string;
|
|
12
|
+
const transport = transports[sessionId];
|
|
13
|
+
if (transport) {
|
|
14
|
+
try {
|
|
15
|
+
getEvent().node.res.statusCode = 200;
|
|
16
|
+
await transport.handleMessage(body);
|
|
17
|
+
} catch (error) {
|
|
18
|
+
getEvent().node.res.send("Error handling message");
|
|
19
|
+
}
|
|
20
|
+
} else {
|
|
21
|
+
getEvent().node.res.send("No transport found for sessionId");
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createAPIFileRoute } from '@tanstack/react-start/api'
|
|
2
|
+
import { getEvent } from 'vinxi/http'
|
|
3
|
+
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'
|
|
4
|
+
|
|
5
|
+
import { transports, server } from '@/utils/demo.sse'
|
|
6
|
+
|
|
7
|
+
export const APIRoute = createAPIFileRoute('/api/sse')({
|
|
8
|
+
// @ts-ignore
|
|
9
|
+
GET: async ({}) => {
|
|
10
|
+
const transport = new SSEServerTransport(
|
|
11
|
+
'/api/messages',
|
|
12
|
+
getEvent().node.res,
|
|
13
|
+
)
|
|
14
|
+
transports[transport.sessionId] = transport
|
|
15
|
+
transport.onerror = (error) => {
|
|
16
|
+
console.error(error)
|
|
17
|
+
}
|
|
18
|
+
getEvent().node.res.on('close', () => {
|
|
19
|
+
delete transports[transport.sessionId]
|
|
20
|
+
})
|
|
21
|
+
await server.connect(transport)
|
|
22
|
+
},
|
|
23
|
+
})
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
3
|
+
import { getWebRequest } from "vinxi/http";
|
|
4
|
+
|
|
5
|
+
import guitars from "@/data/example-guitars";
|
|
6
|
+
|
|
7
|
+
export const server = new McpServer({
|
|
8
|
+
name: "guitar-server",
|
|
9
|
+
version: "1.0.0",
|
|
10
|
+
});
|
|
11
|
+
export const transports: { [sessionId: string]: SSEServerTransport } = {};
|
|
12
|
+
|
|
13
|
+
server.tool("getGuitars", {}, async ({}) => {
|
|
14
|
+
const port = new URL(getWebRequest().url).port;
|
|
15
|
+
return {
|
|
16
|
+
content: [
|
|
17
|
+
{
|
|
18
|
+
type: "text",
|
|
19
|
+
text: JSON.stringify(
|
|
20
|
+
guitars.map((guitar) => ({
|
|
21
|
+
id: guitar.id,
|
|
22
|
+
name: guitar.name,
|
|
23
|
+
description: guitar.description,
|
|
24
|
+
price: guitar.price,
|
|
25
|
+
image: `http://localhost:${port}${guitar.image}`,
|
|
26
|
+
}))
|
|
27
|
+
),
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
};
|
|
31
|
+
});
|