@tanstack/cta-ui 0.10.0-alpha.24 → 0.10.0-alpha.27
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/README.md +20 -0
- package/dist/assets/index-DSKioOfX.css +1 -0
- package/dist/assets/index-DWTDdndE.js +213 -0
- package/dist/assets/index-DWTDdndE.js.map +1 -0
- package/dist/favicon.ico +0 -0
- package/dist/index.html +19 -0
- package/dist/logo-color-100w.png +0 -0
- package/dist/logo192.png +0 -0
- package/dist/logo512.png +0 -0
- package/dist/manifest.json +25 -0
- package/dist/robots.txt +3 -0
- package/dist/tailwind.svg +1 -0
- package/dist/tanstack.png +0 -0
- package/dist/typescript.svg +1 -0
- package/index.html +18 -0
- package/lib/engine-handling/add-to-app-wrapper.ts +134 -0
- package/{src → lib}/engine-handling/create-app-wrapper.ts +48 -39
- package/{src → lib}/engine-handling/file-helpers.ts +4 -2
- package/{src → lib}/engine-handling/generate-initial-payload.ts +58 -51
- package/lib/engine-handling/server-environment.ts +37 -0
- package/lib/index.ts +150 -34
- package/lib/types.d.ts +20 -0
- package/lib-dist/engine-handling/add-to-app-wrapper.d.ts +14 -0
- package/lib-dist/engine-handling/add-to-app-wrapper.js +78 -0
- package/lib-dist/engine-handling/create-app-wrapper.d.ts +14 -0
- package/lib-dist/engine-handling/create-app-wrapper.js +70 -0
- package/lib-dist/engine-handling/file-helpers.d.ts +2 -0
- package/lib-dist/engine-handling/file-helpers.js +21 -0
- package/lib-dist/engine-handling/framework-registration.d.ts +1 -0
- package/lib-dist/engine-handling/framework-registration.js +10 -0
- package/lib-dist/engine-handling/generate-initial-payload.d.ts +32 -0
- package/lib-dist/engine-handling/generate-initial-payload.js +88 -0
- package/lib-dist/engine-handling/server-environment.d.ts +17 -0
- package/lib-dist/engine-handling/server-environment.js +18 -0
- package/lib-dist/index.d.ts +5 -7
- package/lib-dist/index.js +124 -18
- package/package.json +12 -12
- package/public/logo-color-100w.png +0 -0
- package/src/components/background-animation.tsx +229 -0
- package/src/components/cta-sidebar.tsx +28 -33
- package/src/components/file-navigator.tsx +72 -74
- package/src/components/header.tsx +31 -0
- package/src/components/sidebar-items/add-ons.tsx +48 -45
- package/src/components/sidebar-items/mode-selector.tsx +6 -4
- package/src/components/sidebar-items/project-name.tsx +4 -5
- package/src/components/sidebar-items/typescript-switch.tsx +3 -3
- package/src/components/startup-dialog.tsx +4 -6
- package/src/components/ui/switch.tsx +6 -6
- package/src/hooks/use-mounted.ts +9 -0
- package/src/hooks/use-preferred-reduced-motion.ts +27 -0
- package/src/index.tsx +48 -0
- package/src/lib/api.ts +10 -8
- package/src/main.tsx +12 -0
- package/src/store/project.ts +36 -20
- package/src/styles.css +90 -18
- package/src/types.d.ts +1 -1
- package/tailwind.config.cjs +47 -0
- package/vite.config.ts +16 -0
- package/app.config.js +0 -22
- package/src/api.ts +0 -6
- package/src/client.tsx +0 -8
- package/src/engine-handling/add-to-app-wrapper.ts +0 -114
- package/src/engine-handling/server-environment.ts +0 -30
- package/src/integrations/tanstack-query/layout.tsx +0 -5
- package/src/integrations/tanstack-query/root-provider.tsx +0 -15
- package/src/logo.svg +0 -44
- package/src/routeTree.gen.ts +0 -88
- package/src/router.tsx +0 -32
- package/src/routes/__root.tsx +0 -86
- package/src/routes/api/add-to-app.ts +0 -21
- package/src/routes/api/create-app.ts +0 -21
- package/src/routes/api/dry-run-add-to-app.ts +0 -16
- package/src/routes/api/dry-run-create-app.ts +0 -16
- package/src/routes/api/initial-payload.ts +0 -10
- package/src/routes/api/load-remote-add-on.ts +0 -42
- package/src/routes/api/load-starter.ts +0 -47
- package/src/routes/api/shutdown.ts +0 -11
- package/src/routes/index.tsx +0 -17
- package/src/ssr.tsx +0 -12
- /package/{src → lib}/engine-handling/framework-registration.ts +0 -0
package/lib/index.ts
CHANGED
|
@@ -1,43 +1,159 @@
|
|
|
1
1
|
import { dirname, resolve } from 'node:path'
|
|
2
2
|
import { fileURLToPath } from 'node:url'
|
|
3
|
+
import express from 'express'
|
|
4
|
+
import cors from 'cors'
|
|
5
|
+
import chalk from 'chalk'
|
|
3
6
|
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
7
|
+
import {
|
|
8
|
+
AddOnCompiledSchema,
|
|
9
|
+
StarterCompiledSchema,
|
|
10
|
+
} from '@tanstack/cta-engine'
|
|
11
|
+
|
|
12
|
+
import { addToAppWrapper } from './engine-handling/add-to-app-wrapper.js'
|
|
13
|
+
import { createAppWrapper } from './engine-handling/create-app-wrapper.js'
|
|
14
|
+
import { generateInitialPayload } from './engine-handling/generate-initial-payload.js'
|
|
15
|
+
import { setServerEnvironment } from './engine-handling/server-environment.js'
|
|
16
|
+
|
|
17
|
+
import type { ServerEnvironment } from './engine-handling/server-environment.js'
|
|
18
|
+
import type { Environment } from '@tanstack/cta-engine'
|
|
19
|
+
|
|
20
|
+
export function launchUI(
|
|
21
|
+
options: Partial<ServerEnvironment> & {
|
|
22
|
+
port?: number
|
|
23
|
+
environmentFactory?: () => Environment
|
|
24
|
+
},
|
|
25
|
+
) {
|
|
26
|
+
const { port: requestedPort, ...rest } = options
|
|
27
|
+
setServerEnvironment(rest)
|
|
28
|
+
|
|
29
|
+
const app = express()
|
|
30
|
+
|
|
31
|
+
app.use(cors())
|
|
32
|
+
app.use(express.json())
|
|
33
|
+
app.use(express.urlencoded({ extended: true }))
|
|
34
|
+
|
|
35
|
+
const launchUI = !process.env.CTA_DISABLE_UI
|
|
36
|
+
if (launchUI) {
|
|
37
|
+
const packagePath = resolve(dirname(fileURLToPath(import.meta.url)), '..')
|
|
38
|
+
app.use(express.static(resolve(packagePath, 'dist')))
|
|
32
39
|
}
|
|
33
40
|
|
|
34
|
-
|
|
35
|
-
|
|
41
|
+
app.post('/api/add-to-app', async (req, res) => {
|
|
42
|
+
await addToAppWrapper(req.body.addOns, {
|
|
43
|
+
response: res,
|
|
44
|
+
environmentFactory: options.environmentFactory,
|
|
45
|
+
})
|
|
46
|
+
})
|
|
36
47
|
|
|
37
|
-
|
|
48
|
+
app.post('/api/create-app', async (req, res) => {
|
|
49
|
+
await createAppWrapper(req.body.options, {
|
|
50
|
+
response: res,
|
|
51
|
+
environmentFactory: options.environmentFactory,
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
app.post('/api/dry-run-add-to-app', async (req, res) => {
|
|
56
|
+
res.send(
|
|
57
|
+
await addToAppWrapper(req.body.addOns, {
|
|
58
|
+
dryRun: true,
|
|
59
|
+
environmentFactory: options.environmentFactory,
|
|
60
|
+
}),
|
|
61
|
+
)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
app.post('/api/dry-run-create-app', async (req, res) => {
|
|
65
|
+
res.send(
|
|
66
|
+
await createAppWrapper(req.body.options, {
|
|
67
|
+
dryRun: true,
|
|
68
|
+
environmentFactory: options.environmentFactory,
|
|
69
|
+
}),
|
|
70
|
+
)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
app.get('/api/initial-payload', async (_req, res) => {
|
|
74
|
+
res.send(await generateInitialPayload())
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
app.get('/api/load-remote-add-on', async (req, res) => {
|
|
78
|
+
const { url } = req.query
|
|
79
|
+
if (!url) {
|
|
80
|
+
res.status(400).send('URL is required')
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const response = await fetch(url as string)
|
|
85
|
+
const data = await response.json()
|
|
86
|
+
const parsed = AddOnCompiledSchema.safeParse(data)
|
|
87
|
+
if (!parsed.success) {
|
|
88
|
+
res.status(400).json({ error: 'Invalid add-on data' })
|
|
89
|
+
} else {
|
|
90
|
+
res.json({
|
|
91
|
+
id: url,
|
|
92
|
+
name: parsed.data.name,
|
|
93
|
+
description: parsed.data.description,
|
|
94
|
+
version: parsed.data.version,
|
|
95
|
+
author: parsed.data.author,
|
|
96
|
+
license: parsed.data.license,
|
|
97
|
+
link: parsed.data.link,
|
|
98
|
+
smallLogo: parsed.data.smallLogo,
|
|
99
|
+
logo: parsed.data.logo,
|
|
100
|
+
type: parsed.data.type,
|
|
101
|
+
modes: parsed.data.modes,
|
|
102
|
+
})
|
|
103
|
+
}
|
|
104
|
+
} catch {
|
|
105
|
+
res.status(500).send('Failed to load add-on')
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
app.get('/api/load-starter', async (req, res) => {
|
|
110
|
+
const { url } = req.query
|
|
111
|
+
if (!url) {
|
|
112
|
+
res.status(400).send('URL is required')
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
const response = await fetch(url as string)
|
|
117
|
+
const data = await response.json()
|
|
118
|
+
const parsed = StarterCompiledSchema.safeParse(data)
|
|
119
|
+
if (!parsed.success) {
|
|
120
|
+
res.status(400).json({ error: 'Invalid starter data' })
|
|
121
|
+
} else {
|
|
122
|
+
res.json({
|
|
123
|
+
url,
|
|
124
|
+
id: parsed.data.id,
|
|
125
|
+
name: parsed.data.name,
|
|
126
|
+
description: parsed.data.description,
|
|
127
|
+
version: parsed.data.version,
|
|
128
|
+
author: parsed.data.author,
|
|
129
|
+
license: parsed.data.license,
|
|
130
|
+
dependsOn: parsed.data.dependsOn,
|
|
131
|
+
mode: parsed.data.mode,
|
|
132
|
+
typescript: parsed.data.typescript,
|
|
133
|
+
tailwind: parsed.data.tailwind,
|
|
134
|
+
banner: parsed.data.banner
|
|
135
|
+
? (url as string).replace('starter.json', parsed.data.banner)
|
|
136
|
+
: undefined,
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
} catch {
|
|
140
|
+
res.status(500).send('Failed to load starter')
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
app.post('/api/shutdown', (_req, res) => {
|
|
145
|
+
setTimeout(() => {
|
|
146
|
+
process.exit(0)
|
|
147
|
+
}, 50)
|
|
148
|
+
res.send({ shutdown: true })
|
|
149
|
+
})
|
|
38
150
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
151
|
+
const port = requestedPort || process.env.PORT || 8080
|
|
152
|
+
app.listen(port, () => {
|
|
153
|
+
console.log(
|
|
154
|
+
`🔥 ${chalk.blueBright(`Create TanStack ${launchUI ? 'App' : 'API'}`)} is running on ${chalk.underline(
|
|
155
|
+
`http://localhost:${port}`,
|
|
156
|
+
)}`,
|
|
157
|
+
)
|
|
42
158
|
})
|
|
43
159
|
}
|
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type DryRunOutput = {
|
|
2
|
+
files: Record<string, string>
|
|
3
|
+
commands: Array<{
|
|
4
|
+
command: string
|
|
5
|
+
args: Array<string>
|
|
6
|
+
}>
|
|
7
|
+
deletedFiles: Array<string>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type AddOnInfo = {
|
|
11
|
+
id: string
|
|
12
|
+
name: string
|
|
13
|
+
description: string
|
|
14
|
+
type: 'add-on' | 'example' | 'starter' | 'toolchain'
|
|
15
|
+
modes: Array<'code-router' | 'file-router'>
|
|
16
|
+
smallLogo?: string
|
|
17
|
+
logo?: string
|
|
18
|
+
link: string
|
|
19
|
+
dependsOn?: Array<string>
|
|
20
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Environment } from '@tanstack/cta-engine';
|
|
2
|
+
import type { Response } from 'express';
|
|
3
|
+
export declare function addToAppWrapper(addOns: Array<string>, opts: {
|
|
4
|
+
dryRun?: boolean;
|
|
5
|
+
response?: Response;
|
|
6
|
+
environmentFactory?: () => Environment;
|
|
7
|
+
}): Promise<{
|
|
8
|
+
files: Record<string, string>;
|
|
9
|
+
deletedFiles: Array<string>;
|
|
10
|
+
commands: Array<{
|
|
11
|
+
command: string;
|
|
12
|
+
args: Array<string>;
|
|
13
|
+
}>;
|
|
14
|
+
} | undefined>;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { CONFIG_FILE, addToApp, createAppOptionsFromPersisted, createDefaultEnvironment, createMemoryEnvironment, createSerializedOptionsFromPersisted, readConfigFile, recursivelyGatherFiles, writeConfigFileToEnvironment, } from '@tanstack/cta-engine';
|
|
3
|
+
import { cleanUpFileArray, cleanUpFiles } from './file-helpers.js';
|
|
4
|
+
import { getProjectPath } from './server-environment.js';
|
|
5
|
+
import { createAppWrapper } from './create-app-wrapper.js';
|
|
6
|
+
export async function addToAppWrapper(addOns, opts) {
|
|
7
|
+
const projectPath = getProjectPath();
|
|
8
|
+
const persistedOptions = await readConfigFile(projectPath);
|
|
9
|
+
if (!persistedOptions) {
|
|
10
|
+
throw new Error('No config file found');
|
|
11
|
+
}
|
|
12
|
+
const options = await createAppOptionsFromPersisted(persistedOptions);
|
|
13
|
+
options.targetDir = projectPath;
|
|
14
|
+
const newAddons = [];
|
|
15
|
+
for (const addOn of addOns) {
|
|
16
|
+
if (!options.chosenAddOns.some((a) => a.id === addOn)) {
|
|
17
|
+
newAddons.push(addOn);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
if (newAddons.length === 0) {
|
|
21
|
+
const serializedOptions = createSerializedOptionsFromPersisted(persistedOptions);
|
|
22
|
+
return await createAppWrapper(serializedOptions, opts);
|
|
23
|
+
}
|
|
24
|
+
async function createEnvironment() {
|
|
25
|
+
if (opts.dryRun) {
|
|
26
|
+
const { environment, output } = createMemoryEnvironment(projectPath);
|
|
27
|
+
const localFiles = await cleanUpFiles(await recursivelyGatherFiles(projectPath, false));
|
|
28
|
+
for (const file of Object.keys(localFiles)) {
|
|
29
|
+
environment.writeFile(resolve(projectPath, file), localFiles[file]);
|
|
30
|
+
}
|
|
31
|
+
return { environment, output };
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
environment: opts.environmentFactory?.() ?? createDefaultEnvironment(),
|
|
35
|
+
output: { files: {}, deletedFiles: [], commands: [] },
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const { environment, output } = await createEnvironment();
|
|
39
|
+
if (opts.response) {
|
|
40
|
+
opts.response.writeHead(200, {
|
|
41
|
+
'Content-Type': 'text/plain',
|
|
42
|
+
'Transfer-Encoding': 'chunked',
|
|
43
|
+
});
|
|
44
|
+
environment.startStep = ({ id, type, message, }) => {
|
|
45
|
+
opts.response.write(JSON.stringify({
|
|
46
|
+
msgType: 'start',
|
|
47
|
+
id,
|
|
48
|
+
type,
|
|
49
|
+
message,
|
|
50
|
+
}) + '\n');
|
|
51
|
+
};
|
|
52
|
+
environment.finishStep = (id, message) => {
|
|
53
|
+
opts.response.write(JSON.stringify({
|
|
54
|
+
msgType: 'finish',
|
|
55
|
+
id,
|
|
56
|
+
message,
|
|
57
|
+
}) + '\n');
|
|
58
|
+
};
|
|
59
|
+
environment.startRun();
|
|
60
|
+
await addToApp(environment, newAddons, projectPath, {
|
|
61
|
+
forced: true,
|
|
62
|
+
});
|
|
63
|
+
environment.finishRun();
|
|
64
|
+
opts.response.end();
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
environment.startRun();
|
|
68
|
+
environment.writeFile(resolve(projectPath, CONFIG_FILE), JSON.stringify(persistedOptions, null, 2));
|
|
69
|
+
await addToApp(environment, newAddons, projectPath, {
|
|
70
|
+
forced: true,
|
|
71
|
+
});
|
|
72
|
+
writeConfigFileToEnvironment(environment, options);
|
|
73
|
+
environment.finishRun();
|
|
74
|
+
output.files = cleanUpFiles(output.files, projectPath);
|
|
75
|
+
output.deletedFiles = cleanUpFileArray(output.deletedFiles, projectPath);
|
|
76
|
+
return output;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Environment, SerializedOptions } from '@tanstack/cta-engine';
|
|
2
|
+
import type { Response } from 'express';
|
|
3
|
+
export declare function createAppWrapper(projectOptions: SerializedOptions, opts: {
|
|
4
|
+
dryRun?: boolean;
|
|
5
|
+
response?: Response;
|
|
6
|
+
environmentFactory?: () => Environment;
|
|
7
|
+
}): Promise<{
|
|
8
|
+
files: Record<string, string>;
|
|
9
|
+
deletedFiles: Array<string>;
|
|
10
|
+
commands: Array<{
|
|
11
|
+
command: string;
|
|
12
|
+
args: Array<string>;
|
|
13
|
+
}>;
|
|
14
|
+
} | undefined>;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { createApp, createDefaultEnvironment, createMemoryEnvironment, finalizeAddOns, getFrameworkById, loadStarter, } from '@tanstack/cta-engine';
|
|
3
|
+
import { registerFrameworks } from './framework-registration.js';
|
|
4
|
+
import { cleanUpFileArray, cleanUpFiles } from './file-helpers.js';
|
|
5
|
+
import { getApplicationMode, getProjectPath } from './server-environment.js';
|
|
6
|
+
export async function createAppWrapper(projectOptions, opts) {
|
|
7
|
+
registerFrameworks();
|
|
8
|
+
const framework = getFrameworkById(projectOptions.framework);
|
|
9
|
+
let starter;
|
|
10
|
+
const addOns = [...projectOptions.chosenAddOns];
|
|
11
|
+
if (projectOptions.starter) {
|
|
12
|
+
starter = await loadStarter(projectOptions.starter);
|
|
13
|
+
if (starter) {
|
|
14
|
+
for (const addOn of starter.dependsOn ?? []) {
|
|
15
|
+
addOns.push(addOn);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const chosenAddOns = await finalizeAddOns(framework, projectOptions.mode, addOns);
|
|
20
|
+
const projectPath = getProjectPath();
|
|
21
|
+
const targetDir = getApplicationMode() === 'add'
|
|
22
|
+
? projectOptions.targetDir
|
|
23
|
+
: resolve(projectPath, projectOptions.projectName);
|
|
24
|
+
const options = {
|
|
25
|
+
...projectOptions,
|
|
26
|
+
targetDir,
|
|
27
|
+
starter,
|
|
28
|
+
framework,
|
|
29
|
+
chosenAddOns,
|
|
30
|
+
};
|
|
31
|
+
function createEnvironment() {
|
|
32
|
+
if (opts.dryRun) {
|
|
33
|
+
return createMemoryEnvironment(targetDir);
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
environment: opts.environmentFactory?.() ?? createDefaultEnvironment(),
|
|
37
|
+
output: { files: {}, deletedFiles: [], commands: [] },
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const { environment, output } = createEnvironment();
|
|
41
|
+
if (opts.response) {
|
|
42
|
+
opts.response.writeHead(200, {
|
|
43
|
+
'Content-Type': 'text/plain',
|
|
44
|
+
'Transfer-Encoding': 'chunked',
|
|
45
|
+
});
|
|
46
|
+
environment.startStep = ({ id, type, message }) => {
|
|
47
|
+
opts.response.write(JSON.stringify({
|
|
48
|
+
msgType: 'start',
|
|
49
|
+
id,
|
|
50
|
+
type,
|
|
51
|
+
message,
|
|
52
|
+
}) + '\n');
|
|
53
|
+
};
|
|
54
|
+
environment.finishStep = (id, message) => {
|
|
55
|
+
opts.response.write(JSON.stringify({
|
|
56
|
+
msgType: 'finish',
|
|
57
|
+
id,
|
|
58
|
+
message,
|
|
59
|
+
}) + '\n');
|
|
60
|
+
};
|
|
61
|
+
await createApp(environment, options);
|
|
62
|
+
opts.response.end();
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
await createApp(environment, options);
|
|
66
|
+
output.files = cleanUpFiles(output.files, targetDir);
|
|
67
|
+
output.deletedFiles = cleanUpFileArray(output.deletedFiles, targetDir);
|
|
68
|
+
return output;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { basename } from 'node:path';
|
|
2
|
+
import { CONFIG_FILE } from '@tanstack/cta-engine';
|
|
3
|
+
export function cleanUpFiles(files, targetDir) {
|
|
4
|
+
return Object.keys(files).reduce((acc, file) => {
|
|
5
|
+
const content = files[file].startsWith('base64::')
|
|
6
|
+
? '<binary file>'
|
|
7
|
+
: files[file];
|
|
8
|
+
if (basename(file) !== CONFIG_FILE) {
|
|
9
|
+
acc[targetDir ? file.replace(targetDir, '.') : file] = content;
|
|
10
|
+
}
|
|
11
|
+
return acc;
|
|
12
|
+
}, {});
|
|
13
|
+
}
|
|
14
|
+
export function cleanUpFileArray(files, targetDir) {
|
|
15
|
+
return files.reduce((acc, file) => {
|
|
16
|
+
if (basename(file) !== CONFIG_FILE) {
|
|
17
|
+
acc.push(targetDir ? file.replace(targetDir, '.') : file);
|
|
18
|
+
}
|
|
19
|
+
return acc;
|
|
20
|
+
}, []);
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function registerFrameworks(): void;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { register as registerReactCra } from '@tanstack/cta-framework-react-cra';
|
|
2
|
+
import { register as registerSolid } from '@tanstack/cta-framework-solid';
|
|
3
|
+
let registered = false;
|
|
4
|
+
export function registerFrameworks() {
|
|
5
|
+
if (registered)
|
|
6
|
+
return;
|
|
7
|
+
registerReactCra();
|
|
8
|
+
registerSolid();
|
|
9
|
+
registered = true;
|
|
10
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { SerializedOptions } from '@tanstack/cta-engine';
|
|
2
|
+
import type { AddOnInfo } from '../types.js';
|
|
3
|
+
export declare function generateInitialPayload(): Promise<{
|
|
4
|
+
applicationMode: "add" | "setup";
|
|
5
|
+
localFiles: Record<string, string>;
|
|
6
|
+
addOns: {
|
|
7
|
+
'code-router': AddOnInfo[];
|
|
8
|
+
'file-router': AddOnInfo[];
|
|
9
|
+
};
|
|
10
|
+
options: SerializedOptions;
|
|
11
|
+
output: {
|
|
12
|
+
files: Record<string, string>;
|
|
13
|
+
deletedFiles: Array<string>;
|
|
14
|
+
commands: Array<{
|
|
15
|
+
command: string;
|
|
16
|
+
args: Array<string>;
|
|
17
|
+
}>;
|
|
18
|
+
} | undefined;
|
|
19
|
+
forcedRouterMode: import("@tanstack/cta-engine").Mode | undefined;
|
|
20
|
+
forcedAddOns: string[];
|
|
21
|
+
registry: {
|
|
22
|
+
"add-ons": never[];
|
|
23
|
+
starters: {
|
|
24
|
+
name: string;
|
|
25
|
+
description: string;
|
|
26
|
+
url: string;
|
|
27
|
+
banner?: string;
|
|
28
|
+
mode: Mode;
|
|
29
|
+
framework: string;
|
|
30
|
+
}[];
|
|
31
|
+
};
|
|
32
|
+
}>;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { basename, resolve } from 'node:path';
|
|
2
|
+
import { createSerializedOptionsFromPersisted, getAllAddOns, getFrameworkById, getRawRegistry, getRegistryAddOns, readConfigFile, recursivelyGatherFiles, } from '@tanstack/cta-engine';
|
|
3
|
+
import { cleanUpFiles } from './file-helpers.js';
|
|
4
|
+
import { createAppWrapper } from './create-app-wrapper.js';
|
|
5
|
+
import { registerFrameworks } from './framework-registration.js';
|
|
6
|
+
import { getApplicationMode, getForcedAddOns, getForcedRouterMode, getProjectOptions, getProjectPath, getRegistry as getRegistryURL, } from './server-environment.js';
|
|
7
|
+
function convertAddOnToAddOnInfo(addOn) {
|
|
8
|
+
return {
|
|
9
|
+
id: addOn.id,
|
|
10
|
+
name: addOn.name,
|
|
11
|
+
description: addOn.description,
|
|
12
|
+
modes: addOn.modes,
|
|
13
|
+
type: addOn.type,
|
|
14
|
+
smallLogo: addOn.smallLogo,
|
|
15
|
+
logo: addOn.logo,
|
|
16
|
+
link: addOn.link,
|
|
17
|
+
dependsOn: addOn.dependsOn,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export async function generateInitialPayload() {
|
|
21
|
+
registerFrameworks();
|
|
22
|
+
const projectPath = getProjectPath();
|
|
23
|
+
const applicationMode = getApplicationMode();
|
|
24
|
+
const localFiles = applicationMode === 'add'
|
|
25
|
+
? await cleanUpFiles(await recursivelyGatherFiles(projectPath, false))
|
|
26
|
+
: {};
|
|
27
|
+
const forcedRouterMode = getForcedRouterMode();
|
|
28
|
+
async function getSerializedOptions() {
|
|
29
|
+
if (applicationMode === 'setup') {
|
|
30
|
+
const projectOptions = getProjectOptions();
|
|
31
|
+
return {
|
|
32
|
+
...projectOptions,
|
|
33
|
+
framework: projectOptions.framework || 'react-cra',
|
|
34
|
+
projectName: projectOptions.projectName || basename(projectPath),
|
|
35
|
+
mode: forcedRouterMode || projectOptions.mode,
|
|
36
|
+
typescript: projectOptions.typescript || true,
|
|
37
|
+
tailwind: projectOptions.tailwind || true,
|
|
38
|
+
git: projectOptions.git || true,
|
|
39
|
+
targetDir: projectOptions.targetDir ||
|
|
40
|
+
resolve(projectPath, projectOptions.projectName),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
const persistedOptions = await readConfigFile(projectPath);
|
|
45
|
+
if (!persistedOptions) {
|
|
46
|
+
throw new Error('No config file found');
|
|
47
|
+
}
|
|
48
|
+
return createSerializedOptionsFromPersisted(persistedOptions);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const rawRegistry = await getRawRegistry(getRegistryURL());
|
|
52
|
+
const registryAddOns = await getRegistryAddOns(getRegistryURL());
|
|
53
|
+
const serializedOptions = await getSerializedOptions();
|
|
54
|
+
const output = await createAppWrapper(serializedOptions, {
|
|
55
|
+
dryRun: true,
|
|
56
|
+
});
|
|
57
|
+
const framework = await getFrameworkById(serializedOptions.framework);
|
|
58
|
+
const codeRouterAddOns = getAllAddOns(framework, 'code-router').map(convertAddOnToAddOnInfo);
|
|
59
|
+
const fileRouterAddOns = getAllAddOns(framework, 'file-router').map(convertAddOnToAddOnInfo);
|
|
60
|
+
for (const addOnInfo of registryAddOns || []) {
|
|
61
|
+
const addOnFramework = rawRegistry?.['add-ons'].find((addOn) => addOn.url === addOnInfo.id);
|
|
62
|
+
if (addOnFramework?.framework === serializedOptions.framework) {
|
|
63
|
+
if (addOnInfo.modes.includes('code-router')) {
|
|
64
|
+
codeRouterAddOns.push(convertAddOnToAddOnInfo(addOnInfo));
|
|
65
|
+
}
|
|
66
|
+
if (addOnInfo.modes.includes('file-router')) {
|
|
67
|
+
fileRouterAddOns.push(convertAddOnToAddOnInfo(addOnInfo));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const serializedRegistry = {
|
|
72
|
+
['add-ons']: [],
|
|
73
|
+
starters: (rawRegistry?.starters || []).filter((starter) => starter.framework === serializedOptions.framework),
|
|
74
|
+
};
|
|
75
|
+
return {
|
|
76
|
+
applicationMode,
|
|
77
|
+
localFiles,
|
|
78
|
+
addOns: {
|
|
79
|
+
'code-router': codeRouterAddOns,
|
|
80
|
+
'file-router': fileRouterAddOns,
|
|
81
|
+
},
|
|
82
|
+
options: serializedOptions,
|
|
83
|
+
output,
|
|
84
|
+
forcedRouterMode,
|
|
85
|
+
forcedAddOns: getForcedAddOns(),
|
|
86
|
+
registry: serializedRegistry,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Mode, SerializedOptions } from '@tanstack/cta-engine';
|
|
2
|
+
export type ServerEnvironment = {
|
|
3
|
+
projectPath: string;
|
|
4
|
+
mode: 'add' | 'setup';
|
|
5
|
+
options?: SerializedOptions;
|
|
6
|
+
addOns?: Array<string>;
|
|
7
|
+
forcedRouterMode?: Mode;
|
|
8
|
+
forcedAddOns?: Array<string>;
|
|
9
|
+
registry?: string;
|
|
10
|
+
};
|
|
11
|
+
export declare function setServerEnvironment(options: Partial<ServerEnvironment>): void;
|
|
12
|
+
export declare const getProjectPath: () => string;
|
|
13
|
+
export declare const getApplicationMode: () => "add" | "setup";
|
|
14
|
+
export declare const getProjectOptions: () => SerializedOptions;
|
|
15
|
+
export declare const getForcedRouterMode: () => Mode | undefined;
|
|
16
|
+
export declare const getForcedAddOns: () => string[];
|
|
17
|
+
export declare const getRegistry: () => string | undefined;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const serverEnvironment = {
|
|
2
|
+
projectPath: '',
|
|
3
|
+
mode: 'add',
|
|
4
|
+
options: {},
|
|
5
|
+
addOns: [],
|
|
6
|
+
forcedRouterMode: undefined,
|
|
7
|
+
forcedAddOns: undefined,
|
|
8
|
+
registry: undefined,
|
|
9
|
+
};
|
|
10
|
+
export function setServerEnvironment(options) {
|
|
11
|
+
Object.assign(serverEnvironment, options);
|
|
12
|
+
}
|
|
13
|
+
export const getProjectPath = () => serverEnvironment.projectPath;
|
|
14
|
+
export const getApplicationMode = () => serverEnvironment.mode;
|
|
15
|
+
export const getProjectOptions = () => serverEnvironment.options;
|
|
16
|
+
export const getForcedRouterMode = () => serverEnvironment.forcedRouterMode;
|
|
17
|
+
export const getForcedAddOns = () => serverEnvironment.forcedAddOns || [];
|
|
18
|
+
export const getRegistry = () => serverEnvironment.registry;
|
package/lib-dist/index.d.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
forcedMode?: Mode;
|
|
7
|
-
forcedAddOns?: Array<string>;
|
|
1
|
+
import type { ServerEnvironment } from './engine-handling/server-environment.js';
|
|
2
|
+
import type { Environment } from '@tanstack/cta-engine';
|
|
3
|
+
export declare function launchUI(options: Partial<ServerEnvironment> & {
|
|
4
|
+
port?: number;
|
|
5
|
+
environmentFactory?: () => Environment;
|
|
8
6
|
}): void;
|