@telemetryos/cli 1.16.0 → 1.17.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/CHANGELOG.md +20 -0
- package/package.json +2 -2
- package/dist/commands/archive.d.ts +0 -13
- package/dist/commands/archive.js +0 -49
- package/dist/commands/auth.d.ts +0 -2
- package/dist/commands/auth.js +0 -60
- package/dist/commands/claude-code.d.ts +0 -2
- package/dist/commands/claude-code.js +0 -29
- package/dist/commands/init.d.ts +0 -2
- package/dist/commands/init.js +0 -176
- package/dist/commands/publish.d.ts +0 -22
- package/dist/commands/publish.js +0 -238
- package/dist/commands/root.d.ts +0 -2
- package/dist/commands/root.js +0 -5
- package/dist/commands/serve.d.ts +0 -2
- package/dist/commands/serve.js +0 -7
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -13
- package/dist/plugins/math-tools.d.ts +0 -2
- package/dist/plugins/math-tools.js +0 -18
- package/dist/services/api-client.d.ts +0 -18
- package/dist/services/api-client.js +0 -70
- package/dist/services/archiver.d.ts +0 -4
- package/dist/services/archiver.js +0 -65
- package/dist/services/build-poller.d.ts +0 -10
- package/dist/services/build-poller.js +0 -63
- package/dist/services/cli-config.d.ts +0 -10
- package/dist/services/cli-config.js +0 -45
- package/dist/services/config.d.ts +0 -5
- package/dist/services/config.js +0 -23
- package/dist/services/create-project.d.ts +0 -13
- package/dist/services/create-project.js +0 -188
- package/dist/services/generate-application.d.ts +0 -12
- package/dist/services/generate-application.js +0 -206
- package/dist/services/project-config.d.ts +0 -27
- package/dist/services/project-config.js +0 -54
- package/dist/services/run-server.d.ts +0 -5
- package/dist/services/run-server.js +0 -327
- package/dist/types/api.d.ts +0 -44
- package/dist/types/api.js +0 -1
- package/dist/types/applications.d.ts +0 -44
- package/dist/types/applications.js +0 -1
- package/dist/utils/ansi.d.ts +0 -11
- package/dist/utils/ansi.js +0 -11
- package/dist/utils/path-utils.d.ts +0 -55
- package/dist/utils/path-utils.js +0 -99
- package/dist/utils/template.d.ts +0 -2
- package/dist/utils/template.js +0 -30
- package/dist/utils/validate-project-name.d.ts +0 -19
- package/dist/utils/validate-project-name.js +0 -44
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
import { spawn, execSync } from 'child_process';
|
|
2
|
-
import fs from 'fs/promises';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { ansi } from '../utils/ansi.js';
|
|
5
|
-
const ignoredTemplateFiles = ['.DS_Store', 'thumbs.db', 'node_modules', '.git', 'dist'];
|
|
6
|
-
const templatesDir = path.join(import.meta.dirname, '../../templates');
|
|
7
|
-
const dotfileNames = ['_gitignore', '_claude'];
|
|
8
|
-
// Files that can exist in a directory without being considered conflicts
|
|
9
|
-
const safeExistingFiles = [
|
|
10
|
-
'.DS_Store',
|
|
11
|
-
'.git',
|
|
12
|
-
'.gitignore',
|
|
13
|
-
'.gitattributes',
|
|
14
|
-
'.idea',
|
|
15
|
-
'.vscode',
|
|
16
|
-
'Thumbs.db',
|
|
17
|
-
'LICENSE',
|
|
18
|
-
'README.md',
|
|
19
|
-
];
|
|
20
|
-
export async function generateApplication(options) {
|
|
21
|
-
const { name, description, author, version, template, projectPath, progressFn } = options;
|
|
22
|
-
await fs.mkdir(projectPath, { recursive: true });
|
|
23
|
-
// Initialize git repo early (before template dependencies that may have git hooks)
|
|
24
|
-
const gitInitialized = tryGitInit(projectPath);
|
|
25
|
-
if (gitInitialized) {
|
|
26
|
-
console.log('\nInitialized a git repository');
|
|
27
|
-
}
|
|
28
|
-
await copyDir(path.join(templatesDir, template), projectPath, {
|
|
29
|
-
name,
|
|
30
|
-
version,
|
|
31
|
-
description,
|
|
32
|
-
author,
|
|
33
|
-
}, progressFn);
|
|
34
|
-
// Install latest versions of @telemetryos/sdk and @telemetryos/cli
|
|
35
|
-
console.log('\nInstalling dependencies...');
|
|
36
|
-
await installPackages(projectPath);
|
|
37
|
-
// Create initial commit after all files are in place
|
|
38
|
-
if (gitInitialized) {
|
|
39
|
-
await tryGitCommit(projectPath);
|
|
40
|
-
}
|
|
41
|
-
printSuccessMessage(name, projectPath);
|
|
42
|
-
}
|
|
43
|
-
async function installPackages(projectPath) {
|
|
44
|
-
// Install SDK as a regular dependency
|
|
45
|
-
await new Promise((resolve, reject) => {
|
|
46
|
-
const sdkInstall = spawn('npm', ['install', '@telemetryos/sdk'], {
|
|
47
|
-
cwd: projectPath,
|
|
48
|
-
stdio: 'inherit',
|
|
49
|
-
shell: true,
|
|
50
|
-
});
|
|
51
|
-
sdkInstall.on('close', (code) => {
|
|
52
|
-
if (code === 0) {
|
|
53
|
-
resolve();
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
reject(new Error(`npm install @telemetryos/sdk failed with code ${code}`));
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
sdkInstall.on('error', (error) => {
|
|
60
|
-
reject(error);
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
// Install CLI as a dev dependency
|
|
64
|
-
await new Promise((resolve, reject) => {
|
|
65
|
-
const cliInstall = spawn('npm', ['install', '-D', '@telemetryos/cli'], {
|
|
66
|
-
cwd: projectPath,
|
|
67
|
-
stdio: 'inherit',
|
|
68
|
-
shell: true,
|
|
69
|
-
});
|
|
70
|
-
cliInstall.on('close', (code) => {
|
|
71
|
-
if (code === 0) {
|
|
72
|
-
resolve();
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
reject(new Error(`npm install -D @telemetryos/cli failed with code ${code}`));
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
cliInstall.on('error', (error) => {
|
|
79
|
-
reject(error);
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
function isInGitRepository(cwd) {
|
|
84
|
-
try {
|
|
85
|
-
execSync('git rev-parse --is-inside-work-tree', { cwd, stdio: 'ignore' });
|
|
86
|
-
return true;
|
|
87
|
-
}
|
|
88
|
-
catch {
|
|
89
|
-
return false;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
function tryGitInit(projectPath) {
|
|
93
|
-
try {
|
|
94
|
-
execSync('git --version', { stdio: 'ignore' });
|
|
95
|
-
if (isInGitRepository(projectPath)) {
|
|
96
|
-
return false;
|
|
97
|
-
}
|
|
98
|
-
execSync('git init', { cwd: projectPath, stdio: 'ignore' });
|
|
99
|
-
return true;
|
|
100
|
-
}
|
|
101
|
-
catch {
|
|
102
|
-
return false;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
async function tryGitCommit(projectPath) {
|
|
106
|
-
try {
|
|
107
|
-
execSync('git add -A', { cwd: projectPath, stdio: 'ignore' });
|
|
108
|
-
execSync('git commit -m "Initialize project using TelemetryOS CLI"', {
|
|
109
|
-
cwd: projectPath,
|
|
110
|
-
stdio: 'ignore',
|
|
111
|
-
});
|
|
112
|
-
console.log('Created initial commit');
|
|
113
|
-
return true;
|
|
114
|
-
}
|
|
115
|
-
catch {
|
|
116
|
-
// Commit failed (e.g., git user not configured)
|
|
117
|
-
// Remove .git directory to avoid half-initialized state
|
|
118
|
-
console.log('Git commit not created');
|
|
119
|
-
console.log('Removing .git directory...');
|
|
120
|
-
try {
|
|
121
|
-
await fs.rm(path.join(projectPath, '.git'), { recursive: true, force: true });
|
|
122
|
-
}
|
|
123
|
-
catch {
|
|
124
|
-
// Ignore cleanup errors
|
|
125
|
-
}
|
|
126
|
-
return false;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
export async function checkDirectoryConflicts(projectPath) {
|
|
130
|
-
try {
|
|
131
|
-
const entries = await fs.readdir(projectPath);
|
|
132
|
-
return entries.filter((file) => !safeExistingFiles.includes(file));
|
|
133
|
-
}
|
|
134
|
-
catch (error) {
|
|
135
|
-
// Directory doesn't exist, no conflicts
|
|
136
|
-
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
|
|
137
|
-
return [];
|
|
138
|
-
}
|
|
139
|
-
throw error;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
export async function removeConflictingFiles(projectPath, conflicts) {
|
|
143
|
-
for (const file of conflicts) {
|
|
144
|
-
const filePath = path.join(projectPath, file);
|
|
145
|
-
try {
|
|
146
|
-
const stat = await fs.stat(filePath);
|
|
147
|
-
if (stat.isDirectory()) {
|
|
148
|
-
await fs.rm(filePath, { recursive: true, force: true });
|
|
149
|
-
}
|
|
150
|
-
else {
|
|
151
|
-
await fs.unlink(filePath);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
catch (error) {
|
|
155
|
-
// Ignore errors for files that may have already been removed
|
|
156
|
-
console.error(`Warning: Could not remove ${file}: ${error instanceof Error ? error.message : error}`);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
function printSuccessMessage(name, projectPath) {
|
|
161
|
-
// Calculate relative path from cwd for cleaner display
|
|
162
|
-
const relativePath = path.relative(process.cwd(), projectPath);
|
|
163
|
-
const displayPath = relativePath || '.';
|
|
164
|
-
console.log(`
|
|
165
|
-
${ansi.green}Success!${ansi.reset} Created ${ansi.bold}${name}${ansi.reset} at ${ansi.cyan}${displayPath}${ansi.reset}
|
|
166
|
-
|
|
167
|
-
Inside that directory, you can run:
|
|
168
|
-
|
|
169
|
-
${ansi.cyan}npm run dev${ansi.reset}
|
|
170
|
-
Starts the development server
|
|
171
|
-
|
|
172
|
-
${ansi.cyan}npm run build${ansi.reset}
|
|
173
|
-
Builds the app for production
|
|
174
|
-
|
|
175
|
-
You may begin with:
|
|
176
|
-
|
|
177
|
-
${ansi.cyan}cd ${displayPath}${ansi.reset}
|
|
178
|
-
${ansi.cyan}npm run dev${ansi.reset}
|
|
179
|
-
|
|
180
|
-
`);
|
|
181
|
-
}
|
|
182
|
-
async function copyDir(source, destination, replacements, progressFn) {
|
|
183
|
-
const dirListing = await fs.readdir(source);
|
|
184
|
-
for (const dirEntry of dirListing) {
|
|
185
|
-
if (ignoredTemplateFiles.includes(dirEntry))
|
|
186
|
-
continue;
|
|
187
|
-
const sourcePath = path.join(source, dirEntry);
|
|
188
|
-
const destinationPath = path.join(destination, dotfileNames.includes(dirEntry) ? `.${dirEntry.slice(1)}` : dirEntry);
|
|
189
|
-
const stats = await fs.stat(sourcePath);
|
|
190
|
-
if (stats.isDirectory()) {
|
|
191
|
-
await fs.mkdir(destinationPath, { recursive: true });
|
|
192
|
-
await copyDir(sourcePath, destinationPath, replacements, progressFn);
|
|
193
|
-
}
|
|
194
|
-
else if (stats.isFile()) {
|
|
195
|
-
await copyFile(sourcePath, destinationPath, replacements, progressFn);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
async function copyFile(source, destination, replacements, progressFn) {
|
|
200
|
-
let contents = await fs.readFile(source, 'utf-8');
|
|
201
|
-
for (const [key, value] of Object.entries(replacements)) {
|
|
202
|
-
contents = contents.replace(new RegExp(`{{${key}}}`, 'g'), value);
|
|
203
|
-
}
|
|
204
|
-
await fs.writeFile(destination, contents, 'utf-8');
|
|
205
|
-
progressFn(destination);
|
|
206
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import z from 'zod';
|
|
2
|
-
export declare const projectConfigSchema: z.ZodObject<{
|
|
3
|
-
name: z.ZodOptional<z.ZodString>;
|
|
4
|
-
version: z.ZodOptional<z.ZodString>;
|
|
5
|
-
description: z.ZodOptional<z.ZodString>;
|
|
6
|
-
logoPath: z.ZodOptional<z.ZodString>;
|
|
7
|
-
thumbnailPath: z.ZodOptional<z.ZodString>;
|
|
8
|
-
mountPoints: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodObject<{
|
|
9
|
-
path: z.ZodString;
|
|
10
|
-
}, z.z.core.$strip>, z.ZodString]>>>;
|
|
11
|
-
backgroundWorkers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodObject<{
|
|
12
|
-
path: z.ZodString;
|
|
13
|
-
}, z.z.core.$strip>, z.ZodString]>>>;
|
|
14
|
-
serverWorkers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodObject<{
|
|
15
|
-
path: z.ZodString;
|
|
16
|
-
}, z.z.core.$strip>, z.ZodString]>>>;
|
|
17
|
-
containers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodObject<{
|
|
18
|
-
image: z.ZodString;
|
|
19
|
-
}, z.z.core.$strip>, z.ZodString]>>>;
|
|
20
|
-
useSpaRouting: z.ZodOptional<z.ZodBoolean>;
|
|
21
|
-
devServer: z.ZodOptional<z.ZodObject<{
|
|
22
|
-
runCommand: z.ZodOptional<z.ZodString>;
|
|
23
|
-
url: z.ZodString;
|
|
24
|
-
}, z.z.core.$strip>>;
|
|
25
|
-
}, z.z.core.$strip>;
|
|
26
|
-
export type ProjectConfig = z.infer<typeof projectConfigSchema>;
|
|
27
|
-
export declare function loadProjectConfig(projectPath: string): Promise<ProjectConfig>;
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { readFile } from 'fs/promises';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import z from 'zod';
|
|
4
|
-
const mountPointSchema = z.object({
|
|
5
|
-
path: z.string(),
|
|
6
|
-
});
|
|
7
|
-
const backgroundWorkerSchema = z.object({
|
|
8
|
-
path: z.string(),
|
|
9
|
-
});
|
|
10
|
-
const serverWorkerSchema = z.object({
|
|
11
|
-
path: z.string(),
|
|
12
|
-
});
|
|
13
|
-
const containerSchema = z.object({
|
|
14
|
-
image: z.string(),
|
|
15
|
-
});
|
|
16
|
-
export const projectConfigSchema = z.object({
|
|
17
|
-
name: z.string().optional(),
|
|
18
|
-
version: z.string().optional(),
|
|
19
|
-
description: z.string().optional(),
|
|
20
|
-
logoPath: z.string().optional(),
|
|
21
|
-
thumbnailPath: z.string().optional(),
|
|
22
|
-
mountPoints: z.record(z.string(), z.union([mountPointSchema, z.string()])).optional(),
|
|
23
|
-
backgroundWorkers: z.record(z.string(), z.union([backgroundWorkerSchema, z.string()])).optional(),
|
|
24
|
-
serverWorkers: z.record(z.string(), z.union([serverWorkerSchema, z.string()])).optional(),
|
|
25
|
-
containers: z.record(z.string(), z.union([containerSchema, z.string()])).optional(),
|
|
26
|
-
useSpaRouting: z.boolean().optional(),
|
|
27
|
-
devServer: z
|
|
28
|
-
.object({
|
|
29
|
-
runCommand: z.string().optional(),
|
|
30
|
-
url: z.string(),
|
|
31
|
-
})
|
|
32
|
-
.optional(),
|
|
33
|
-
});
|
|
34
|
-
export async function loadProjectConfig(projectPath) {
|
|
35
|
-
const configPath = path.join(projectPath, 'telemetry.config.json');
|
|
36
|
-
try {
|
|
37
|
-
const content = await readFile(configPath, 'utf-8');
|
|
38
|
-
const parsed = JSON.parse(content);
|
|
39
|
-
return projectConfigSchema.parse(parsed);
|
|
40
|
-
}
|
|
41
|
-
catch (error) {
|
|
42
|
-
if (error.code === 'ENOENT') {
|
|
43
|
-
throw new Error(`No telemetry.config.json found in ${projectPath}`);
|
|
44
|
-
}
|
|
45
|
-
if (error instanceof z.ZodError) {
|
|
46
|
-
const issues = error.issues.map((i) => ` ${i.path.join('.')}: ${i.message}`).join('\n');
|
|
47
|
-
throw new Error(`Invalid telemetry.config.json:\n${issues}`);
|
|
48
|
-
}
|
|
49
|
-
if (error instanceof SyntaxError) {
|
|
50
|
-
throw new Error(`Invalid JSON in telemetry.config.json: ${error.message}`);
|
|
51
|
-
}
|
|
52
|
-
throw error;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
@@ -1,327 +0,0 @@
|
|
|
1
|
-
import { spawn } from 'child_process';
|
|
2
|
-
import { access, readFile } from 'fs/promises';
|
|
3
|
-
import { fileURLToPath } from 'url';
|
|
4
|
-
import http from 'http';
|
|
5
|
-
import path from 'path';
|
|
6
|
-
import { createInterface } from 'readline/promises';
|
|
7
|
-
import serveHandler from 'serve-handler';
|
|
8
|
-
import pkg from '../../package.json' with { type: 'json' };
|
|
9
|
-
import { loadProjectConfig } from './project-config.js';
|
|
10
|
-
import { ansi, ansiRegex } from '../utils/ansi.js';
|
|
11
|
-
// import { handlePublishCommand } from '../commands/publish.js'
|
|
12
|
-
const IMAGE_MIME_TYPES = {
|
|
13
|
-
'.jpg': 'image/jpeg',
|
|
14
|
-
'.jpeg': 'image/jpeg',
|
|
15
|
-
'.png': 'image/png',
|
|
16
|
-
'.gif': 'image/gif',
|
|
17
|
-
'.svg': 'image/svg+xml',
|
|
18
|
-
'.webp': 'image/webp',
|
|
19
|
-
};
|
|
20
|
-
export async function runServer(projectPath, flags) {
|
|
21
|
-
printSplashScreen();
|
|
22
|
-
projectPath = path.resolve(process.cwd(), projectPath);
|
|
23
|
-
let projectConfig;
|
|
24
|
-
try {
|
|
25
|
-
projectConfig = await loadProjectConfig(projectPath);
|
|
26
|
-
}
|
|
27
|
-
catch (error) {
|
|
28
|
-
console.error(error.message);
|
|
29
|
-
process.exit(1);
|
|
30
|
-
}
|
|
31
|
-
await serveDevelopmentApplicationHostUI(projectPath, flags.port, projectConfig);
|
|
32
|
-
await serveTelemetryApplication(projectPath, projectConfig);
|
|
33
|
-
// Print ready message after Vite is confirmed ready
|
|
34
|
-
printServerInfo(flags.port);
|
|
35
|
-
}
|
|
36
|
-
async function serveDevelopmentApplicationHostUI(projectPath, port, projectConfig) {
|
|
37
|
-
const hostUiPath = await import.meta.resolve('@telemetryos/development-application-host-ui/dist');
|
|
38
|
-
const serveConfig = { public: fileURLToPath(hostUiPath) };
|
|
39
|
-
const server = http.createServer();
|
|
40
|
-
server.on('request', async (req, res) => {
|
|
41
|
-
var _a, _b;
|
|
42
|
-
const url = new URL(req.url, `http://${req.headers.origin}`);
|
|
43
|
-
if (url.pathname === '/__tos-config__') {
|
|
44
|
-
res.setHeader('Content-Type', 'application/json');
|
|
45
|
-
res.end(JSON.stringify(projectConfig));
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
if (url.pathname === '/__tos-logo__') {
|
|
49
|
-
await serveImageFile(res, projectPath, projectConfig.logoPath, 'logo');
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
if (url.pathname === '/__tos-thumbnail__') {
|
|
53
|
-
await serveImageFile(res, projectPath, projectConfig.thumbnailPath, 'thumbnail');
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
if (url.pathname === '/__dev_proxy__' && req.method === 'POST' && res) {
|
|
57
|
-
let body = '';
|
|
58
|
-
for await (const chunk of req) {
|
|
59
|
-
body += chunk;
|
|
60
|
-
}
|
|
61
|
-
try {
|
|
62
|
-
const { url, method, headers, body: requestBody } = JSON.parse(body);
|
|
63
|
-
const response = await fetch(url, {
|
|
64
|
-
method,
|
|
65
|
-
headers,
|
|
66
|
-
body: requestBody !== null && requestBody !== void 0 ? requestBody : undefined,
|
|
67
|
-
});
|
|
68
|
-
const contentType = response.headers.get('content-type') || '';
|
|
69
|
-
const isJson = contentType.includes('application/json');
|
|
70
|
-
const isText = contentType.includes('text/') ||
|
|
71
|
-
contentType.includes('application/javascript') ||
|
|
72
|
-
contentType.includes('application/xml');
|
|
73
|
-
let responseBody;
|
|
74
|
-
let bodyType;
|
|
75
|
-
if (isJson) {
|
|
76
|
-
const text = await response.text();
|
|
77
|
-
responseBody = text ? JSON.parse(text) : null;
|
|
78
|
-
bodyType = 'json';
|
|
79
|
-
}
|
|
80
|
-
else if (isText) {
|
|
81
|
-
responseBody = await response.text();
|
|
82
|
-
bodyType = 'text';
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
85
|
-
// Binary data - convert to base64 for JSON transport
|
|
86
|
-
const arrayBuffer = await response.arrayBuffer();
|
|
87
|
-
responseBody = Buffer.from(arrayBuffer).toString('base64');
|
|
88
|
-
bodyType = 'binary';
|
|
89
|
-
}
|
|
90
|
-
const responseHeaders = {};
|
|
91
|
-
response.headers.forEach((value, key) => {
|
|
92
|
-
responseHeaders[key] = value;
|
|
93
|
-
});
|
|
94
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
95
|
-
res.end(JSON.stringify({
|
|
96
|
-
success: true,
|
|
97
|
-
status: response.status,
|
|
98
|
-
statusText: response.statusText,
|
|
99
|
-
headers: responseHeaders,
|
|
100
|
-
body: responseBody,
|
|
101
|
-
bodyType,
|
|
102
|
-
ok: response.ok,
|
|
103
|
-
url: response.url,
|
|
104
|
-
}));
|
|
105
|
-
}
|
|
106
|
-
catch (error) {
|
|
107
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
108
|
-
res.end(JSON.stringify({
|
|
109
|
-
success: false,
|
|
110
|
-
errorMessage: `Proxy fetch failed: ${String(error)}`,
|
|
111
|
-
errorCause: error.cause ? String((_b = (_a = error.cause) === null || _a === void 0 ? void 0 : _a.message) !== null && _b !== void 0 ? _b : error.cause) : undefined,
|
|
112
|
-
}));
|
|
113
|
-
}
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
// TODO: Publish endpoint disabled until auth is working
|
|
117
|
-
// if (url.pathname === '/__publish__') {
|
|
118
|
-
// if (req.method !== 'GET') {
|
|
119
|
-
// res.statusCode = 405
|
|
120
|
-
// res.end('Method not allowed')
|
|
121
|
-
// return
|
|
122
|
-
// }
|
|
123
|
-
//
|
|
124
|
-
// // Set SSE headers
|
|
125
|
-
// res.setHeader('Content-Type', 'text/event-stream')
|
|
126
|
-
// res.setHeader('Cache-Control', 'no-cache')
|
|
127
|
-
// res.setHeader('Connection', 'keep-alive')
|
|
128
|
-
//
|
|
129
|
-
// const sendEvent = (event: string, data: any) => {
|
|
130
|
-
// res.write(`event: ${event}\n`)
|
|
131
|
-
// res.write(`data: ${JSON.stringify(data)}\n\n`)
|
|
132
|
-
// }
|
|
133
|
-
//
|
|
134
|
-
// try {
|
|
135
|
-
// sendEvent('state', { state: 'starting' })
|
|
136
|
-
//
|
|
137
|
-
// await handlePublishCommand(
|
|
138
|
-
// projectPath,
|
|
139
|
-
// {},
|
|
140
|
-
// {
|
|
141
|
-
// onLog: (line: string) => {
|
|
142
|
-
// sendEvent('log', { message: line })
|
|
143
|
-
// },
|
|
144
|
-
// onStateChange: (state: string) => {
|
|
145
|
-
// sendEvent('state', { state })
|
|
146
|
-
// },
|
|
147
|
-
// onComplete: (data: { success: boolean; buildIndex?: number; duration?: string }) => {
|
|
148
|
-
// sendEvent('complete', data)
|
|
149
|
-
// res.end()
|
|
150
|
-
// },
|
|
151
|
-
// onError: (error: Error) => {
|
|
152
|
-
// const isAuthError =
|
|
153
|
-
// error.message.includes('authenticate') ||
|
|
154
|
-
// error.message.includes('Not authenticated')
|
|
155
|
-
// sendEvent('error', {
|
|
156
|
-
// error: error.message,
|
|
157
|
-
// code: isAuthError ? 'AUTH_REQUIRED' : 'PUBLISH_FAILED',
|
|
158
|
-
// message: isAuthError
|
|
159
|
-
// ? "Run 'tos auth' in the terminal to authenticate"
|
|
160
|
-
// : error.message,
|
|
161
|
-
// })
|
|
162
|
-
// res.end()
|
|
163
|
-
// },
|
|
164
|
-
// },
|
|
165
|
-
// )
|
|
166
|
-
// } catch (error) {
|
|
167
|
-
// sendEvent('error', {
|
|
168
|
-
// error: (error as Error).message,
|
|
169
|
-
// code: 'UNEXPECTED_ERROR',
|
|
170
|
-
// message: (error as Error).message,
|
|
171
|
-
// })
|
|
172
|
-
// res.end()
|
|
173
|
-
// }
|
|
174
|
-
// return
|
|
175
|
-
// }
|
|
176
|
-
serveHandler(req, res, serveConfig).catch((err) => {
|
|
177
|
-
console.error('Error handling request:', err);
|
|
178
|
-
res.statusCode = 500;
|
|
179
|
-
res.end('Internal Server Error');
|
|
180
|
-
});
|
|
181
|
-
});
|
|
182
|
-
server.listen(port);
|
|
183
|
-
}
|
|
184
|
-
async function serveImageFile(res, projectPath, filePath, label) {
|
|
185
|
-
if (!filePath) {
|
|
186
|
-
res.statusCode = 404;
|
|
187
|
-
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
|
188
|
-
res.end(`No ${label} configured`);
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
const projectRoot = path.resolve(projectPath);
|
|
192
|
-
const validatePath = (fullPath) => fullPath.startsWith(projectRoot + path.sep) || fullPath === projectRoot;
|
|
193
|
-
// Try public/ first (Vite convention), then project root (backward compat)
|
|
194
|
-
const publicPath = path.resolve(projectPath, 'public', filePath);
|
|
195
|
-
const rootPath = path.resolve(projectPath, filePath);
|
|
196
|
-
let resolvedPath;
|
|
197
|
-
if (validatePath(publicPath)) {
|
|
198
|
-
try {
|
|
199
|
-
await access(publicPath);
|
|
200
|
-
resolvedPath = publicPath;
|
|
201
|
-
}
|
|
202
|
-
catch { }
|
|
203
|
-
}
|
|
204
|
-
if (!resolvedPath && validatePath(rootPath)) {
|
|
205
|
-
resolvedPath = rootPath;
|
|
206
|
-
}
|
|
207
|
-
if (!resolvedPath) {
|
|
208
|
-
res.statusCode = 403;
|
|
209
|
-
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
|
210
|
-
res.end('Forbidden: path escapes project root');
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
try {
|
|
214
|
-
const imageData = await readFile(resolvedPath);
|
|
215
|
-
const ext = path.extname(filePath).toLowerCase();
|
|
216
|
-
const contentType = IMAGE_MIME_TYPES[ext] || 'application/octet-stream';
|
|
217
|
-
res.setHeader('Content-Type', contentType);
|
|
218
|
-
res.end(imageData);
|
|
219
|
-
}
|
|
220
|
-
catch (error) {
|
|
221
|
-
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
|
222
|
-
if ((error === null || error === void 0 ? void 0 : error.code) === 'ENOENT') {
|
|
223
|
-
res.statusCode = 404;
|
|
224
|
-
res.end(`${label.charAt(0).toUpperCase() + label.slice(1)} file not found`);
|
|
225
|
-
}
|
|
226
|
-
else {
|
|
227
|
-
res.statusCode = 500;
|
|
228
|
-
res.end(`Error reading ${label}: ${(error === null || error === void 0 ? void 0 : error.message) || 'unknown error'}`);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
async function serveTelemetryApplication(rootPath, projectConfig) {
|
|
233
|
-
return new Promise((resolve, reject) => {
|
|
234
|
-
var _a;
|
|
235
|
-
if (!((_a = projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.devServer) === null || _a === void 0 ? void 0 : _a.runCommand)) {
|
|
236
|
-
console.log('No value in config at devServer.runCommand');
|
|
237
|
-
resolve();
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
const runCommand = projectConfig.devServer.runCommand;
|
|
241
|
-
const binPath = path.join(rootPath, 'node_modules', '.bin');
|
|
242
|
-
const childProcess = spawn(runCommand, {
|
|
243
|
-
shell: true,
|
|
244
|
-
env: {
|
|
245
|
-
...process.env,
|
|
246
|
-
FORCE_COLOR: '1',
|
|
247
|
-
PATH: `${binPath}${path.delimiter}${process.env.PATH}`,
|
|
248
|
-
},
|
|
249
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
250
|
-
cwd: rootPath,
|
|
251
|
-
});
|
|
252
|
-
const stdoutReadline = createInterface({
|
|
253
|
-
input: childProcess.stdout,
|
|
254
|
-
crlfDelay: Infinity,
|
|
255
|
-
});
|
|
256
|
-
const stderrReadline = createInterface({
|
|
257
|
-
input: childProcess.stderr,
|
|
258
|
-
crlfDelay: Infinity,
|
|
259
|
-
});
|
|
260
|
-
let cleaned = false;
|
|
261
|
-
const cleanup = () => {
|
|
262
|
-
if (cleaned)
|
|
263
|
-
return;
|
|
264
|
-
cleaned = true;
|
|
265
|
-
process.removeListener('exit', onParentExit);
|
|
266
|
-
clearTimeout(timeoutHandle);
|
|
267
|
-
childProcess.kill();
|
|
268
|
-
stdoutReadline.close();
|
|
269
|
-
stderrReadline.close();
|
|
270
|
-
};
|
|
271
|
-
const onParentExit = () => {
|
|
272
|
-
console.log('Shutting down development server...');
|
|
273
|
-
cleanup();
|
|
274
|
-
};
|
|
275
|
-
process.on('exit', onParentExit);
|
|
276
|
-
const timeoutHandle = setTimeout(() => {
|
|
277
|
-
cleanup();
|
|
278
|
-
reject(new Error('Vite dev server did not start within 30 seconds'));
|
|
279
|
-
}, 30000);
|
|
280
|
-
let viteReady = false;
|
|
281
|
-
stdoutReadline.on('line', (line) => {
|
|
282
|
-
console.log(`[application]: ${line}`);
|
|
283
|
-
// Detect Vite ready signal
|
|
284
|
-
if (!viteReady) {
|
|
285
|
-
const cleanLine = line.replace(ansiRegex, '');
|
|
286
|
-
if (cleanLine.includes('VITE') && cleanLine.includes('ready in')) {
|
|
287
|
-
viteReady = true;
|
|
288
|
-
clearTimeout(timeoutHandle);
|
|
289
|
-
resolve();
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
});
|
|
293
|
-
stderrReadline.on('line', (line) => {
|
|
294
|
-
console.error(`[application]: ${line}`);
|
|
295
|
-
});
|
|
296
|
-
childProcess.on('error', (error) => {
|
|
297
|
-
if (!viteReady) {
|
|
298
|
-
cleanup();
|
|
299
|
-
reject(error);
|
|
300
|
-
}
|
|
301
|
-
});
|
|
302
|
-
childProcess.on('close', (code) => {
|
|
303
|
-
if (!viteReady) {
|
|
304
|
-
cleanup();
|
|
305
|
-
reject(new Error(`Dev server process exited with code ${code} before becoming ready`));
|
|
306
|
-
}
|
|
307
|
-
});
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
function printSplashScreen() {
|
|
311
|
-
console.log(`
|
|
312
|
-
|
|
313
|
-
${ansi.white} █ █ █ ${ansi.yellow}▄▀▀▀▄ ▄▀▀▀▄
|
|
314
|
-
${ansi.white} █ █ █ ${ansi.yellow}█ █ █
|
|
315
|
-
${ansi.white}▀█▀ ▄▀▀▄ █ ▄▀▀▄ █▀▄▀▄ ▄▀▀▄ ▀█▀ █▄▀ █ █ ${ansi.yellow}█ █ ▀▀▀▄
|
|
316
|
-
${ansi.white} █ █▀▀▀ █ █▀▀▀ █ █ █ █▀▀▀ █ █ █ █ ${ansi.yellow}█ █ █
|
|
317
|
-
${ansi.white} ▀▄ ▀▄▄▀ █ ▀▄▄▀ █ █ █ ▀▄▄▀ ▀▄ █ █ ${ansi.yellow}▀▄▄▄▀ ▀▄▄▄▀
|
|
318
|
-
${ansi.white} ▄▀ ${ansi.reset}
|
|
319
|
-
v${pkg.version}`);
|
|
320
|
-
}
|
|
321
|
-
function printServerInfo(port) {
|
|
322
|
-
console.log(`
|
|
323
|
-
╔═══════════════════════════════════════════════════════════╗
|
|
324
|
-
║ ${ansi.bold}Development environment running at: ${ansi.cyan}http://localhost:${port}${ansi.reset} ║
|
|
325
|
-
╚═══════════════════════════════════════════════════════════╝
|
|
326
|
-
`);
|
|
327
|
-
}
|
package/dist/types/api.d.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
export type ApplicationKind = 'git' | 'github' | 'uploaded' | null;
|
|
2
|
-
export type Application = {
|
|
3
|
-
id: string;
|
|
4
|
-
title: string;
|
|
5
|
-
description: string;
|
|
6
|
-
kind: ApplicationKind;
|
|
7
|
-
baseImage: string;
|
|
8
|
-
buildWorkingPath?: string;
|
|
9
|
-
buildScript?: string;
|
|
10
|
-
buildOutputPath?: string;
|
|
11
|
-
buildEnvironmentVariables?: Record<string, string>;
|
|
12
|
-
versions?: ApplicationVersion[];
|
|
13
|
-
createdAt?: string;
|
|
14
|
-
updatedAt?: string;
|
|
15
|
-
};
|
|
16
|
-
export type ApplicationVersion = {
|
|
17
|
-
name?: string;
|
|
18
|
-
version?: string;
|
|
19
|
-
applicationId: string;
|
|
20
|
-
buildId: string;
|
|
21
|
-
applicationSpecifier: string;
|
|
22
|
-
publishedAt: string;
|
|
23
|
-
};
|
|
24
|
-
export type ApplicationBuild = {
|
|
25
|
-
id: string;
|
|
26
|
-
applicationId: string;
|
|
27
|
-
index: number;
|
|
28
|
-
state: 'pending' | 'building' | 'success' | 'failure' | 'failed' | 'cancelled';
|
|
29
|
-
logs: string[];
|
|
30
|
-
scheduledAt?: string;
|
|
31
|
-
startedAt?: string;
|
|
32
|
-
finishedAt?: string;
|
|
33
|
-
};
|
|
34
|
-
export type CreateApplicationRequest = {
|
|
35
|
-
kind: 'uploaded';
|
|
36
|
-
title: string;
|
|
37
|
-
description?: string;
|
|
38
|
-
baseImage: string;
|
|
39
|
-
baseImageRegistryAuth: string;
|
|
40
|
-
buildWorkingPath: string;
|
|
41
|
-
buildScript: string;
|
|
42
|
-
buildOutputPath: string;
|
|
43
|
-
buildEnvironmentVariables?: Record<string, string>;
|
|
44
|
-
};
|
package/dist/types/api.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|