@objectstack/cli 4.0.3 → 4.0.5
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 +12 -25
- package/dist/commands/build.d.ts +5 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +6 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/compile.d.ts +3 -0
- package/dist/commands/compile.d.ts.map +1 -1
- package/dist/commands/compile.js +128 -6
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/create.js +1 -1
- package/dist/commands/data/create.js +2 -2
- package/dist/commands/data/create.js.map +1 -1
- package/dist/commands/data/delete.js +2 -2
- package/dist/commands/data/delete.js.map +1 -1
- package/dist/commands/data/get.js +2 -2
- package/dist/commands/data/get.js.map +1 -1
- package/dist/commands/data/query.js +2 -2
- package/dist/commands/data/query.js.map +1 -1
- package/dist/commands/data/update.js +2 -2
- package/dist/commands/data/update.js.map +1 -1
- package/dist/commands/dev.d.ts +3 -0
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +48 -19
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/generate.js +9 -9
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/i18n/check.d.ts +18 -0
- package/dist/commands/i18n/check.d.ts.map +1 -0
- package/dist/commands/i18n/check.js +153 -0
- package/dist/commands/i18n/check.js.map +1 -0
- package/dist/commands/init.js +2 -2
- package/dist/commands/lint.d.ts +3 -0
- package/dist/commands/lint.d.ts.map +1 -1
- package/dist/commands/lint.js +24 -0
- package/dist/commands/lint.js.map +1 -1
- package/dist/commands/login.d.ts +17 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +313 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/{auth/logout.js → logout.js} +14 -2
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/meta/delete.js +2 -2
- package/dist/commands/meta/delete.js.map +1 -1
- package/dist/commands/meta/get.js +2 -2
- package/dist/commands/meta/get.js.map +1 -1
- package/dist/commands/meta/list.js +2 -2
- package/dist/commands/meta/list.js.map +1 -1
- package/dist/commands/meta/register.js +2 -2
- package/dist/commands/meta/register.js.map +1 -1
- package/dist/commands/projects/bind.d.ts +30 -0
- package/dist/commands/projects/bind.d.ts.map +1 -0
- package/dist/commands/projects/bind.js +132 -0
- package/dist/commands/projects/bind.js.map +1 -0
- package/dist/commands/projects/create.d.ts +28 -0
- package/dist/commands/projects/create.d.ts.map +1 -0
- package/dist/commands/projects/create.js +120 -0
- package/dist/commands/projects/create.js.map +1 -0
- package/dist/commands/projects/list.d.ts +21 -0
- package/dist/commands/projects/list.d.ts.map +1 -0
- package/dist/commands/projects/list.js +79 -0
- package/dist/commands/projects/list.js.map +1 -0
- package/dist/commands/projects/projects.test.d.ts +2 -0
- package/dist/commands/projects/projects.test.d.ts.map +1 -0
- package/dist/commands/projects/projects.test.js +56 -0
- package/dist/commands/projects/projects.test.js.map +1 -0
- package/dist/commands/projects/show.d.ts +21 -0
- package/dist/commands/projects/show.d.ts.map +1 -0
- package/dist/commands/projects/show.js +72 -0
- package/dist/commands/projects/show.js.map +1 -0
- package/dist/commands/projects/switch.d.ts +24 -0
- package/dist/commands/projects/switch.d.ts.map +1 -0
- package/dist/commands/projects/switch.js +64 -0
- package/dist/commands/projects/switch.js.map +1 -0
- package/dist/commands/publish.d.ts +14 -0
- package/dist/commands/publish.d.ts.map +1 -0
- package/dist/commands/publish.js +91 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/{auth/login.d.ts → register.d.ts} +3 -2
- package/dist/commands/register.d.ts.map +1 -0
- package/dist/commands/{auth/login.js → register.js} +44 -61
- package/dist/commands/register.js.map +1 -0
- package/dist/commands/serve.d.ts +8 -0
- package/dist/commands/serve.d.ts.map +1 -1
- package/dist/commands/serve.js +606 -44
- package/dist/commands/serve.js.map +1 -1
- package/dist/commands/start.d.ts +11 -0
- package/dist/commands/start.d.ts.map +1 -0
- package/dist/commands/start.js +43 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/whoami.d.ts.map +1 -0
- package/dist/commands/{auth/whoami.js → whoami.js} +5 -5
- package/dist/commands/whoami.js.map +1 -0
- package/dist/index.d.ts +7 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -5
- package/dist/index.js.map +1 -1
- package/dist/utils/account.d.ts +31 -0
- package/dist/utils/account.d.ts.map +1 -0
- package/dist/utils/account.js +154 -0
- package/dist/utils/account.js.map +1 -0
- package/dist/utils/api-client.d.ts +10 -4
- package/dist/utils/api-client.d.ts.map +1 -1
- package/dist/utils/api-client.js +13 -7
- package/dist/utils/api-client.js.map +1 -1
- package/dist/utils/auth-config.d.ts +6 -0
- package/dist/utils/auth-config.d.ts.map +1 -1
- package/dist/utils/auth-config.js.map +1 -1
- package/dist/utils/build-runtime.d.ts +45 -0
- package/dist/utils/build-runtime.d.ts.map +1 -0
- package/dist/utils/build-runtime.js +154 -0
- package/dist/utils/build-runtime.js.map +1 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +17 -2
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/console.d.ts +32 -0
- package/dist/utils/console.d.ts.map +1 -0
- package/dist/utils/console.js +169 -0
- package/dist/utils/console.js.map +1 -0
- package/dist/utils/extract-hook-body.d.ts +13 -0
- package/dist/utils/extract-hook-body.d.ts.map +1 -0
- package/dist/utils/extract-hook-body.js +175 -0
- package/dist/utils/extract-hook-body.js.map +1 -0
- package/dist/utils/format.d.ts +8 -0
- package/dist/utils/format.d.ts.map +1 -1
- package/dist/utils/format.js +15 -2
- package/dist/utils/format.js.map +1 -1
- package/dist/utils/i18n-coverage.d.ts +61 -0
- package/dist/utils/i18n-coverage.d.ts.map +1 -0
- package/dist/utils/i18n-coverage.js +176 -0
- package/dist/utils/i18n-coverage.js.map +1 -0
- package/dist/utils/lower-callables.d.ts +17 -0
- package/dist/utils/lower-callables.d.ts.map +1 -0
- package/dist/utils/lower-callables.js +181 -0
- package/dist/utils/lower-callables.js.map +1 -0
- package/dist/utils/plugin-detection.d.ts +1 -0
- package/dist/utils/plugin-detection.d.ts.map +1 -1
- package/dist/utils/plugin-detection.js +41 -0
- package/dist/utils/plugin-detection.js.map +1 -1
- package/dist/utils/studio.d.ts +1 -0
- package/dist/utils/studio.d.ts.map +1 -1
- package/dist/utils/studio.js +25 -9
- package/dist/utils/studio.js.map +1 -1
- package/package.json +55 -21
- package/.turbo/turbo-build.log +0 -4
- package/CHANGELOG.md +0 -805
- package/bin/run-dev.js +0 -5
- package/dist/commands/auth/login.d.ts.map +0 -1
- package/dist/commands/auth/login.js.map +0 -1
- package/dist/commands/auth/logout.d.ts.map +0 -1
- package/dist/commands/auth/logout.js.map +0 -1
- package/dist/commands/auth/whoami.d.ts.map +0 -1
- package/dist/commands/auth/whoami.js.map +0 -1
- package/dist/commands/codemod/v2-to-v3.d.ts +0 -10
- package/dist/commands/codemod/v2-to-v3.d.ts.map +0 -1
- package/dist/commands/codemod/v2-to-v3.js +0 -145
- package/dist/commands/codemod/v2-to-v3.js.map +0 -1
- package/dist/commands/plugin/add.d.ts +0 -22
- package/dist/commands/plugin/add.d.ts.map +0 -1
- package/dist/commands/plugin/add.js +0 -93
- package/dist/commands/plugin/add.js.map +0 -1
- package/dist/commands/plugin/build.d.ts +0 -29
- package/dist/commands/plugin/build.d.ts.map +0 -1
- package/dist/commands/plugin/build.js +0 -170
- package/dist/commands/plugin/build.js.map +0 -1
- package/dist/commands/plugin/info.d.ts +0 -10
- package/dist/commands/plugin/info.d.ts.map +0 -1
- package/dist/commands/plugin/info.js +0 -65
- package/dist/commands/plugin/info.js.map +0 -1
- package/dist/commands/plugin/list.d.ts +0 -13
- package/dist/commands/plugin/list.d.ts.map +0 -1
- package/dist/commands/plugin/list.js +0 -78
- package/dist/commands/plugin/list.js.map +0 -1
- package/dist/commands/plugin/publish.d.ts +0 -27
- package/dist/commands/plugin/publish.d.ts.map +0 -1
- package/dist/commands/plugin/publish.js +0 -152
- package/dist/commands/plugin/publish.js.map +0 -1
- package/dist/commands/plugin/remove.d.ts +0 -20
- package/dist/commands/plugin/remove.d.ts.map +0 -1
- package/dist/commands/plugin/remove.js +0 -79
- package/dist/commands/plugin/remove.js.map +0 -1
- package/dist/commands/plugin/validate.d.ts +0 -23
- package/dist/commands/plugin/validate.d.ts.map +0 -1
- package/dist/commands/plugin/validate.js +0 -251
- package/dist/commands/plugin/validate.js.map +0 -1
- package/src/bin.ts +0 -13
- package/src/commands/auth/login.ts +0 -188
- package/src/commands/auth/logout.ts +0 -51
- package/src/commands/auth/whoami.ts +0 -85
- package/src/commands/codemod/v2-to-v3.ts +0 -171
- package/src/commands/compile.ts +0 -114
- package/src/commands/create.ts +0 -281
- package/src/commands/data/create.ts +0 -110
- package/src/commands/data/delete.ts +0 -84
- package/src/commands/data/get.ts +0 -84
- package/src/commands/data/query.ts +0 -127
- package/src/commands/data/update.ts +0 -114
- package/src/commands/dev.ts +0 -83
- package/src/commands/diff.ts +0 -294
- package/src/commands/doctor.ts +0 -572
- package/src/commands/explain.ts +0 -412
- package/src/commands/generate.ts +0 -924
- package/src/commands/info.ts +0 -124
- package/src/commands/init.ts +0 -327
- package/src/commands/lint.ts +0 -315
- package/src/commands/meta/delete.ts +0 -79
- package/src/commands/meta/get.ts +0 -73
- package/src/commands/meta/list.ts +0 -105
- package/src/commands/meta/register.ts +0 -97
- package/src/commands/plugin/add.ts +0 -112
- package/src/commands/plugin/build.ts +0 -193
- package/src/commands/plugin/info.ts +0 -79
- package/src/commands/plugin/list.ts +0 -93
- package/src/commands/plugin/publish.ts +0 -176
- package/src/commands/plugin/remove.ts +0 -97
- package/src/commands/plugin/validate.ts +0 -268
- package/src/commands/serve.ts +0 -411
- package/src/commands/studio.ts +0 -52
- package/src/commands/test.ts +0 -135
- package/src/commands/validate.ts +0 -143
- package/src/index.ts +0 -22
- package/src/utils/api-client.ts +0 -88
- package/src/utils/auth-config.ts +0 -107
- package/src/utils/config.ts +0 -80
- package/src/utils/format.ts +0 -267
- package/src/utils/output-formatter.ts +0 -91
- package/src/utils/plugin-detection.ts +0 -16
- package/src/utils/plugin-helpers.ts +0 -37
- package/src/utils/studio.ts +0 -350
- package/test/commands.test.ts +0 -128
- package/test/create.test.ts +0 -25
- package/test/plugin-commands.test.ts +0 -44
- package/test/plugin.test.ts +0 -169
- package/test/remote-api-commands.test.ts +0 -188
- package/test/remote-api-utils.test.ts +0 -196
- package/test/serve-host-config.test.ts +0 -77
- package/tsconfig.build.json +0 -20
- package/tsconfig.json +0 -25
- package/tsup.config.ts +0 -23
- /package/dist/commands/{auth/logout.d.ts → logout.d.ts} +0 -0
- /package/dist/commands/{auth/whoami.d.ts → whoami.d.ts} +0 -0
package/src/utils/studio.ts
DELETED
|
@@ -1,350 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Studio UI Integration Utilities
|
|
5
|
-
*
|
|
6
|
-
* Handles resolving, spawning, and proxying the @objectstack/studio
|
|
7
|
-
* frontend when the CLI is started with --ui or via the `studio` command.
|
|
8
|
-
*/
|
|
9
|
-
import path from 'path';
|
|
10
|
-
import fs from 'fs';
|
|
11
|
-
import net from 'net';
|
|
12
|
-
import { createRequire } from 'module';
|
|
13
|
-
import { pathToFileURL } from 'url';
|
|
14
|
-
import { spawn, type ChildProcess } from 'child_process';
|
|
15
|
-
import chalk from 'chalk';
|
|
16
|
-
|
|
17
|
-
// ─── Constants ──────────────────────────────────────────────────────
|
|
18
|
-
|
|
19
|
-
/** URL mount path for the Console UI inside the ObjectStack server */
|
|
20
|
-
export const STUDIO_PATH = '/_studio';
|
|
21
|
-
|
|
22
|
-
/** Internal port range start for the Vite dev server */
|
|
23
|
-
const VITE_PORT_START = 24678;
|
|
24
|
-
|
|
25
|
-
// ─── Path Resolution ────────────────────────────────────────────────
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Resolve the filesystem path to the @objectstack/studio package.
|
|
29
|
-
* Searches workspace locations first, then falls back to node_modules.
|
|
30
|
-
*/
|
|
31
|
-
export function resolveStudioPath(): string | null {
|
|
32
|
-
const cwd = process.cwd();
|
|
33
|
-
|
|
34
|
-
// Workspace candidates (monorepo layouts)
|
|
35
|
-
const candidates = [
|
|
36
|
-
path.resolve(cwd, 'apps/studio'),
|
|
37
|
-
path.resolve(cwd, '../../apps/studio'),
|
|
38
|
-
path.resolve(cwd, '../apps/studio'),
|
|
39
|
-
];
|
|
40
|
-
|
|
41
|
-
for (const candidate of candidates) {
|
|
42
|
-
const pkgPath = path.join(candidate, 'package.json');
|
|
43
|
-
if (fs.existsSync(pkgPath)) {
|
|
44
|
-
try {
|
|
45
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
46
|
-
if (pkg.name === '@objectstack/studio') return candidate;
|
|
47
|
-
} catch {
|
|
48
|
-
// Skip invalid package.json
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Fallback: resolve from node_modules via createRequire.
|
|
54
|
-
// Try the consumer's cwd first (pnpm strict isolation means the CLI's own
|
|
55
|
-
// import.meta.url cannot see the consumer's dependencies), then the CLI itself.
|
|
56
|
-
const resolutionBases = [
|
|
57
|
-
pathToFileURL(path.join(cwd, 'package.json')).href, // consumer workspace
|
|
58
|
-
import.meta.url, // CLI package itself
|
|
59
|
-
];
|
|
60
|
-
|
|
61
|
-
for (const base of resolutionBases) {
|
|
62
|
-
try {
|
|
63
|
-
const req = createRequire(base);
|
|
64
|
-
const resolved = req.resolve('@objectstack/studio/package.json');
|
|
65
|
-
return path.dirname(resolved);
|
|
66
|
-
} catch {
|
|
67
|
-
// Not resolvable from this base — try next
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Last resort: direct filesystem check in cwd/node_modules
|
|
72
|
-
const directPath = path.join(cwd, 'node_modules', '@objectstack', 'studio');
|
|
73
|
-
if (fs.existsSync(path.join(directPath, 'package.json'))) {
|
|
74
|
-
return directPath;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Check whether the Studio has a pre-built `dist/` directory.
|
|
82
|
-
*/
|
|
83
|
-
export function hasStudioDist(studioPath: string): boolean {
|
|
84
|
-
return fs.existsSync(path.join(studioPath, 'dist', 'index.html'));
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// ─── Port Utilities ─────────────────────────────────────────────────
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Find the next available TCP port starting from `start`.
|
|
91
|
-
*/
|
|
92
|
-
export function findAvailablePort(start: number = VITE_PORT_START): Promise<number> {
|
|
93
|
-
return new Promise((resolve, reject) => {
|
|
94
|
-
const server = net.createServer();
|
|
95
|
-
server.once('error', () => {
|
|
96
|
-
// Port in use — try next
|
|
97
|
-
findAvailablePort(start + 1).then(resolve, reject);
|
|
98
|
-
});
|
|
99
|
-
server.once('listening', () => {
|
|
100
|
-
server.close(() => resolve(start));
|
|
101
|
-
});
|
|
102
|
-
server.listen(start);
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// ─── Vite Dev Server ────────────────────────────────────────────────
|
|
107
|
-
|
|
108
|
-
export interface ViteDevResult {
|
|
109
|
-
/** Port the Vite dev server is listening on */
|
|
110
|
-
port: number;
|
|
111
|
-
/** Child process handle */
|
|
112
|
-
process: ChildProcess;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Spawn a Vite dev server for the Console application.
|
|
117
|
-
*
|
|
118
|
-
* Sets environment variables so the Console runs in server mode and
|
|
119
|
-
* connects to the ObjectStack API on the same origin.
|
|
120
|
-
*
|
|
121
|
-
* @param studioPath - Absolute path to the @objectstack/studio package
|
|
122
|
-
* @param options.serverPort - The main ObjectStack server port (for display only)
|
|
123
|
-
*/
|
|
124
|
-
export async function spawnViteDevServer(
|
|
125
|
-
studioPath: string,
|
|
126
|
-
options: { serverPort?: number } = {},
|
|
127
|
-
): Promise<ViteDevResult> {
|
|
128
|
-
const vitePort = await findAvailablePort(VITE_PORT_START);
|
|
129
|
-
|
|
130
|
-
// Resolve the Vite binary from the Studio's own dependencies
|
|
131
|
-
const viteBinCandidates = [
|
|
132
|
-
path.join(studioPath, 'node_modules', '.bin', 'vite'),
|
|
133
|
-
path.join(studioPath, '..', '..', 'node_modules', '.bin', 'vite'),
|
|
134
|
-
];
|
|
135
|
-
|
|
136
|
-
let viteBin: string | null = null;
|
|
137
|
-
for (const candidate of viteBinCandidates) {
|
|
138
|
-
if (fs.existsSync(candidate)) {
|
|
139
|
-
viteBin = candidate;
|
|
140
|
-
break;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const command = viteBin || 'npx';
|
|
145
|
-
const args = viteBin
|
|
146
|
-
? ['--port', String(vitePort), '--strictPort']
|
|
147
|
-
: ['vite', '--port', String(vitePort), '--strictPort'];
|
|
148
|
-
|
|
149
|
-
const child = spawn(command, args, {
|
|
150
|
-
cwd: studioPath,
|
|
151
|
-
env: {
|
|
152
|
-
...process.env,
|
|
153
|
-
VITE_BASE: `${STUDIO_PATH}/`,
|
|
154
|
-
VITE_PORT: String(vitePort),
|
|
155
|
-
VITE_HMR_PORT: String(vitePort),
|
|
156
|
-
VITE_RUNTIME_MODE: 'server',
|
|
157
|
-
VITE_SERVER_URL: '', // Same-origin API
|
|
158
|
-
NODE_ENV: 'development',
|
|
159
|
-
},
|
|
160
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
// Accumulate stderr for error reporting
|
|
164
|
-
let stderr = '';
|
|
165
|
-
child.stderr?.on('data', (data: Buffer) => {
|
|
166
|
-
stderr += data.toString();
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
// Wait for Vite to signal readiness
|
|
170
|
-
await new Promise<void>((resolve, reject) => {
|
|
171
|
-
const timeout = setTimeout(() => {
|
|
172
|
-
child.kill();
|
|
173
|
-
reject(new Error(`Vite dev server timed out after 30 s.\n${stderr}`));
|
|
174
|
-
}, 30_000);
|
|
175
|
-
|
|
176
|
-
child.stdout?.on('data', (data: Buffer) => {
|
|
177
|
-
const output = data.toString();
|
|
178
|
-
// Vite prints "ready in Xms" or "Local: http://..." when ready
|
|
179
|
-
if (output.includes('Local:') || output.includes('ready in')) {
|
|
180
|
-
clearTimeout(timeout);
|
|
181
|
-
resolve();
|
|
182
|
-
}
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
child.on('error', (err) => {
|
|
186
|
-
clearTimeout(timeout);
|
|
187
|
-
reject(err);
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
child.on('exit', (code) => {
|
|
191
|
-
if (code !== 0 && code !== null) {
|
|
192
|
-
clearTimeout(timeout);
|
|
193
|
-
reject(new Error(`Vite exited with code ${code}.\n${stderr}`));
|
|
194
|
-
}
|
|
195
|
-
});
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
return { port: vitePort, process: child };
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// ─── Console Plugin Factories ───────────────────────────────────────
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Create a lightweight kernel plugin that proxies `/_studio/*` requests
|
|
205
|
-
* to the Vite dev server. Used in development mode.
|
|
206
|
-
*/
|
|
207
|
-
export function createStudioProxyPlugin(vitePort: number) {
|
|
208
|
-
return {
|
|
209
|
-
name: 'com.objectstack.studio-proxy',
|
|
210
|
-
|
|
211
|
-
init: async () => {},
|
|
212
|
-
|
|
213
|
-
start: async (ctx: any) => {
|
|
214
|
-
const httpServer = ctx.getService?.('http.server');
|
|
215
|
-
if (!httpServer?.getRawApp) {
|
|
216
|
-
ctx.logger?.warn?.('Studio proxy: http.server service not found — skipping');
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
const app = httpServer.getRawApp();
|
|
221
|
-
|
|
222
|
-
// Redirect bare path to trailing-slash (SPA convention)
|
|
223
|
-
app.get(STUDIO_PATH, (c: any) => c.redirect(`${STUDIO_PATH}/`));
|
|
224
|
-
|
|
225
|
-
// Proxy all /_studio/* requests to the Vite dev server
|
|
226
|
-
app.all(`${STUDIO_PATH}/*`, async (c: any) => {
|
|
227
|
-
const targetUrl = `http://localhost:${vitePort}${c.req.path}`;
|
|
228
|
-
|
|
229
|
-
try {
|
|
230
|
-
const headers = new Headers(c.req.raw.headers);
|
|
231
|
-
headers.delete('host');
|
|
232
|
-
|
|
233
|
-
const isBodyAllowed = !['GET', 'HEAD'].includes(c.req.method);
|
|
234
|
-
|
|
235
|
-
const resp = await fetch(targetUrl, {
|
|
236
|
-
method: c.req.method,
|
|
237
|
-
headers,
|
|
238
|
-
body: isBodyAllowed ? c.req.raw.body : undefined,
|
|
239
|
-
duplex: isBodyAllowed ? 'half' : undefined,
|
|
240
|
-
} as RequestInit);
|
|
241
|
-
|
|
242
|
-
// Forward the full response (status, headers, body)
|
|
243
|
-
return new Response(resp.body, {
|
|
244
|
-
status: resp.status,
|
|
245
|
-
headers: resp.headers,
|
|
246
|
-
});
|
|
247
|
-
} catch {
|
|
248
|
-
return c.text('Console dev server is starting…', 502);
|
|
249
|
-
}
|
|
250
|
-
});
|
|
251
|
-
},
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* Create a lightweight kernel plugin that serves the pre-built Studio
|
|
257
|
-
* static files at `/_studio/*`. Used in production mode.
|
|
258
|
-
*
|
|
259
|
-
* Uses Node.js built-in fs for static file serving to avoid external
|
|
260
|
-
* bundling dependencies.
|
|
261
|
-
*/
|
|
262
|
-
export function createStudioStaticPlugin(distPath: string, options?: { isDev?: boolean }) {
|
|
263
|
-
return {
|
|
264
|
-
name: 'com.objectstack.studio-static',
|
|
265
|
-
|
|
266
|
-
init: async () => {},
|
|
267
|
-
|
|
268
|
-
start: async (ctx: any) => {
|
|
269
|
-
const httpServer = ctx.getService?.('http.server');
|
|
270
|
-
if (!httpServer?.getRawApp) {
|
|
271
|
-
ctx.logger?.warn?.('Studio static: http.server service not found — skipping');
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
const app = httpServer.getRawApp();
|
|
276
|
-
const absoluteDist = path.resolve(distPath);
|
|
277
|
-
|
|
278
|
-
const indexPath = path.join(absoluteDist, 'index.html');
|
|
279
|
-
if (!fs.existsSync(indexPath)) {
|
|
280
|
-
ctx.logger?.warn?.(`Studio static: dist not found at ${absoluteDist}`);
|
|
281
|
-
return;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// Read and rewrite index.html so asset paths respect the mount path.
|
|
285
|
-
// The dist may have been built with base '/' (absolute paths like
|
|
286
|
-
// /assets/...) which won't resolve when mounted under /_studio/.
|
|
287
|
-
const rawHtml = fs.readFileSync(indexPath, 'utf-8');
|
|
288
|
-
const rewrittenHtml = rawHtml.replace(
|
|
289
|
-
/(\s(?:href|src))="\/(?!\/)/g,
|
|
290
|
-
`$1="${STUDIO_PATH}/`,
|
|
291
|
-
);
|
|
292
|
-
|
|
293
|
-
// In dev mode, redirect root to Studio for convenience
|
|
294
|
-
if (options?.isDev) {
|
|
295
|
-
app.get('/', (c: any) => c.redirect(`${STUDIO_PATH}/`));
|
|
296
|
-
}
|
|
297
|
-
// Redirect bare path
|
|
298
|
-
app.get(STUDIO_PATH, (c: any) => c.redirect(`${STUDIO_PATH}/`));
|
|
299
|
-
|
|
300
|
-
// Serve static files with SPA fallback
|
|
301
|
-
app.get(`${STUDIO_PATH}/*`, async (c: any) => {
|
|
302
|
-
const reqPath = c.req.path.substring(STUDIO_PATH.length) || '/';
|
|
303
|
-
const filePath = path.join(absoluteDist, reqPath);
|
|
304
|
-
|
|
305
|
-
// Security: prevent path traversal
|
|
306
|
-
if (!filePath.startsWith(absoluteDist)) {
|
|
307
|
-
return c.text('Forbidden', 403);
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
// Try serving the exact file
|
|
311
|
-
if (fs.existsSync(filePath) && fs.statSync(filePath).isFile()) {
|
|
312
|
-
const content = fs.readFileSync(filePath);
|
|
313
|
-
return new Response(content, {
|
|
314
|
-
headers: { 'content-type': mimeType(filePath) },
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// SPA fallback: serve rewritten index.html for non-file routes
|
|
319
|
-
return new Response(rewrittenHtml, {
|
|
320
|
-
headers: { 'content-type': 'text/html; charset=utf-8' },
|
|
321
|
-
});
|
|
322
|
-
});
|
|
323
|
-
},
|
|
324
|
-
};
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// ─── Helpers ────────────────────────────────────────────────────────
|
|
328
|
-
|
|
329
|
-
const MIME_TYPES: Record<string, string> = {
|
|
330
|
-
'.html': 'text/html; charset=utf-8',
|
|
331
|
-
'.js': 'application/javascript; charset=utf-8',
|
|
332
|
-
'.mjs': 'application/javascript; charset=utf-8',
|
|
333
|
-
'.css': 'text/css; charset=utf-8',
|
|
334
|
-
'.json': 'application/json; charset=utf-8',
|
|
335
|
-
'.svg': 'image/svg+xml',
|
|
336
|
-
'.png': 'image/png',
|
|
337
|
-
'.jpg': 'image/jpeg',
|
|
338
|
-
'.jpeg': 'image/jpeg',
|
|
339
|
-
'.gif': 'image/gif',
|
|
340
|
-
'.ico': 'image/x-icon',
|
|
341
|
-
'.woff': 'font/woff',
|
|
342
|
-
'.woff2': 'font/woff2',
|
|
343
|
-
'.ttf': 'font/ttf',
|
|
344
|
-
'.map': 'application/json',
|
|
345
|
-
};
|
|
346
|
-
|
|
347
|
-
function mimeType(filePath: string): string {
|
|
348
|
-
const ext = path.extname(filePath).toLowerCase();
|
|
349
|
-
return MIME_TYPES[ext] || 'application/octet-stream';
|
|
350
|
-
}
|
package/test/commands.test.ts
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import Compile from '../src/commands/compile';
|
|
3
|
-
import Serve from '../src/commands/serve';
|
|
4
|
-
import Dev from '../src/commands/dev';
|
|
5
|
-
import Doctor from '../src/commands/doctor';
|
|
6
|
-
import Create from '../src/commands/create';
|
|
7
|
-
import Test from '../src/commands/test';
|
|
8
|
-
import Validate from '../src/commands/validate';
|
|
9
|
-
import Init from '../src/commands/init';
|
|
10
|
-
import Info from '../src/commands/info';
|
|
11
|
-
import Generate from '../src/commands/generate';
|
|
12
|
-
import Lint from '../src/commands/lint';
|
|
13
|
-
import Diff from '../src/commands/diff';
|
|
14
|
-
import Explain from '../src/commands/explain';
|
|
15
|
-
import Studio from '../src/commands/studio';
|
|
16
|
-
import PluginList from '../src/commands/plugin/list';
|
|
17
|
-
import PluginInfo from '../src/commands/plugin/info';
|
|
18
|
-
import PluginAdd from '../src/commands/plugin/add';
|
|
19
|
-
import PluginRemove from '../src/commands/plugin/remove';
|
|
20
|
-
import PluginBuild from '../src/commands/plugin/build';
|
|
21
|
-
import PluginValidate from '../src/commands/plugin/validate';
|
|
22
|
-
import PluginPublish from '../src/commands/plugin/publish';
|
|
23
|
-
import V2ToV3 from '../src/commands/codemod/v2-to-v3';
|
|
24
|
-
|
|
25
|
-
describe('CLI Commands (oclif)', () => {
|
|
26
|
-
it('should have compile command', () => {
|
|
27
|
-
expect(Compile.description).toContain('Compile');
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('should have serve command', () => {
|
|
31
|
-
expect(Serve.description).toContain('server');
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('should have dev command', () => {
|
|
35
|
-
expect(Dev.description).toContain('development mode');
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('should have doctor command', () => {
|
|
39
|
-
expect(Doctor.description).toContain('health');
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('should have create command', () => {
|
|
43
|
-
expect(Create.description).toContain('Create');
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('should have test command', () => {
|
|
47
|
-
expect(Test.description).toContain('Quality Protocol');
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('should have validate command', () => {
|
|
51
|
-
expect(Validate.description).toContain('Validate');
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('should have init command', () => {
|
|
55
|
-
expect(Init.description).toContain('Initialize');
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('should have info command', () => {
|
|
59
|
-
expect(Info.description).toContain('summary');
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('should have generate command with alias', () => {
|
|
63
|
-
expect(Generate.aliases).toContain('g');
|
|
64
|
-
expect(Generate.description).toContain('Generate');
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('should have lint command', () => {
|
|
68
|
-
expect(Lint.description).toContain('style');
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it('should have diff command', () => {
|
|
72
|
-
expect(Diff.description).toContain('Compare');
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it('should have explain command', () => {
|
|
76
|
-
expect(Explain.description).toContain('explanation');
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('should have studio command', () => {
|
|
80
|
-
expect(Studio.description).toContain('Studio');
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it('should have codemod v2-to-v3 command', () => {
|
|
84
|
-
expect(V2ToV3.description).toContain('v2');
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
describe('Plugin subcommands', () => {
|
|
88
|
-
it('should have plugin list command', () => {
|
|
89
|
-
expect(PluginList.description).toContain('List');
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
it('should have plugin info command', () => {
|
|
93
|
-
expect(PluginInfo.description).toContain('information');
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('should have plugin add command', () => {
|
|
97
|
-
expect(PluginAdd.description).toContain('Add');
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it('should have plugin remove command', () => {
|
|
101
|
-
expect(PluginRemove.description).toContain('Remove');
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it('should have plugin remove alias', () => {
|
|
105
|
-
expect(PluginRemove.aliases).toContain('plugin rm');
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it('should have plugin list alias', () => {
|
|
109
|
-
expect(PluginList.aliases).toContain('plugin ls');
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it('should have plugin build command', () => {
|
|
113
|
-
expect(PluginBuild.description).toContain('Build');
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('should have plugin build alias', () => {
|
|
117
|
-
expect(PluginBuild.aliases).toContain('plugin pack');
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
it('should have plugin validate command', () => {
|
|
121
|
-
expect(PluginValidate.description).toContain('Validate');
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it('should have plugin publish command', () => {
|
|
125
|
-
expect(PluginPublish.description).toContain('Publish');
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
});
|
package/test/create.test.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { templates } from '../src/commands/create';
|
|
3
|
-
|
|
4
|
-
describe('Create Command Templates', () => {
|
|
5
|
-
describe('Example Template', () => {
|
|
6
|
-
it('should generate correct package.json scripts', () => {
|
|
7
|
-
const packageJsonFn = templates.example.files['package.json'];
|
|
8
|
-
const packageJson = packageJsonFn('test-app');
|
|
9
|
-
|
|
10
|
-
expect(packageJson.scripts.dev).toBe('objectstack dev');
|
|
11
|
-
expect(packageJson.scripts.build).toBe('objectstack compile');
|
|
12
|
-
expect(packageJson.dependencies['@objectstack/cli']).toBe('workspace:*');
|
|
13
|
-
});
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
describe('Plugin Template', () => {
|
|
17
|
-
it('should generate correct dependencies', () => {
|
|
18
|
-
const packageJsonFn = templates.plugin.files['package.json'];
|
|
19
|
-
const packageJson = packageJsonFn('test-plugin');
|
|
20
|
-
|
|
21
|
-
expect(packageJson.dependencies).toHaveProperty('@objectstack/spec');
|
|
22
|
-
expect(packageJson.keywords).toContain('test-plugin');
|
|
23
|
-
});
|
|
24
|
-
});
|
|
25
|
-
});
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* The custom loadPluginCommands mechanism has been removed.
|
|
5
|
-
* Plugin command extension is now handled by oclif's built-in plugin system.
|
|
6
|
-
*
|
|
7
|
-
* Plugins extend the CLI by:
|
|
8
|
-
* 1. Including `oclif` config in their package.json
|
|
9
|
-
* 2. Exporting oclif Command classes from `src/commands/`
|
|
10
|
-
* 3. Being installed via `os plugins install <package>`
|
|
11
|
-
*
|
|
12
|
-
* The objectstack.config.ts no longer determines CLI command availability.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
describe('oclif Plugin System', () => {
|
|
16
|
-
it('should have oclif plugins configured in package.json', async () => {
|
|
17
|
-
const { createRequire } = await import('module');
|
|
18
|
-
const require = createRequire(import.meta.url);
|
|
19
|
-
const pkg = require('../package.json');
|
|
20
|
-
|
|
21
|
-
expect(pkg.oclif).toBeDefined();
|
|
22
|
-
expect(pkg.oclif.plugins).toContain('@oclif/plugin-help');
|
|
23
|
-
expect(pkg.oclif.plugins).toContain('@oclif/plugin-plugins');
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('should have oclif command discovery configured', async () => {
|
|
27
|
-
const { createRequire } = await import('module');
|
|
28
|
-
const require = createRequire(import.meta.url);
|
|
29
|
-
const pkg = require('../package.json');
|
|
30
|
-
|
|
31
|
-
expect(pkg.oclif.commands).toBeDefined();
|
|
32
|
-
expect(pkg.oclif.commands.strategy).toBe('pattern');
|
|
33
|
-
expect(pkg.oclif.commands.target).toBe('./dist/commands');
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('should have bin entries pointing to oclif runner', async () => {
|
|
37
|
-
const { createRequire } = await import('module');
|
|
38
|
-
const require = createRequire(import.meta.url);
|
|
39
|
-
const pkg = require('../package.json');
|
|
40
|
-
|
|
41
|
-
expect(pkg.bin.os).toBe('./bin/run.js');
|
|
42
|
-
expect(pkg.bin.objectstack).toBe('./bin/run.js');
|
|
43
|
-
});
|
|
44
|
-
});
|