@jay-framework/jay-stack-cli 0.6.0 → 0.6.1
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 +33 -12
- package/dist/index.d.ts +24 -0
- package/dist/index.js +218 -12
- package/package.json +5 -3
- package/dist/index.d.mts +0 -2
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ A command-line interface for running Jay stack applications in development mode.
|
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
The Jay Stack CLI provides a simple way to start
|
|
7
|
+
The Jay Stack CLI provides a simple way to start both development and editor servers for Jay applications. It automatically configures and runs the Jay development server and editor server with sensible defaults, making it easy to get started with Jay stack development.
|
|
8
8
|
|
|
9
9
|
## Installation
|
|
10
10
|
|
|
@@ -22,30 +22,44 @@ Simply run the CLI from your project root:
|
|
|
22
22
|
@jay-framework/@jay-framework/jay-cli
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
This will start the development server with default configuration.
|
|
25
|
+
This will start both the development server and editor server with default configuration.
|
|
26
26
|
|
|
27
|
-
###
|
|
27
|
+
### Configuration
|
|
28
28
|
|
|
29
|
-
The CLI
|
|
29
|
+
The CLI uses a `.jay` configuration file (YAML format) to customize port ranges for both servers. Create a `.jay` file in your project root:
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
```yaml
|
|
32
|
+
devServer:
|
|
33
|
+
portRange: [3000, 3100]
|
|
34
|
+
pagesBase: './src/pages' # Directory containing your Jay pages
|
|
35
|
+
publicFolder: './public' # Directory for static files (CSS, JS, images, etc.)
|
|
36
|
+
editorServer:
|
|
37
|
+
portRange: [3101, 3200]
|
|
38
|
+
# editorId will be automatically set when an editor connects
|
|
39
|
+
```
|
|
33
40
|
|
|
34
|
-
|
|
41
|
+
If no `.jay` file is found, the CLI will use default values:
|
|
35
42
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
43
|
+
- **Dev Server Port Range**: `3000-3100`
|
|
44
|
+
- **Pages Directory**: `./src/pages`
|
|
45
|
+
- **Public Folder**: `./public`
|
|
46
|
+
- **Editor Server Port Range**: `3101-3200`
|
|
47
|
+
|
|
48
|
+
The CLI automatically finds available ports within these ranges using the `get-port` package.
|
|
49
|
+
|
|
50
|
+
**Note**: The `editorId` field in the configuration will be automatically updated when an editor connects to the server.
|
|
39
51
|
|
|
40
52
|
## Default Configuration
|
|
41
53
|
|
|
42
54
|
The CLI uses the following default configuration:
|
|
43
55
|
|
|
44
56
|
- **Pages Directory**: `./src/pages` - All Jay pages should be placed in this directory
|
|
57
|
+
- **Public Folder**: `./public` - Static files (CSS, JS, images) are served from this directory
|
|
45
58
|
- **TypeScript Config**: `./tsconfig.json` - Uses the project's TypeScript configuration
|
|
46
59
|
- **Output Directory**: `build/@jay-framework/runtime` - Compiled Jay runtime files
|
|
47
|
-
- **Server Port**: `
|
|
48
|
-
- **
|
|
60
|
+
- **Dev Server Port Range**: `3000-3100` - Automatically finds available port
|
|
61
|
+
- **Editor Server Port Range**: `3101-3200` - Automatically finds available port
|
|
62
|
+
- **Base Path**: `/`
|
|
49
63
|
|
|
50
64
|
## Project Structure
|
|
51
65
|
|
|
@@ -66,6 +80,10 @@ your-project/
|
|
|
66
80
|
│ └── [slug]/ # parameterized segment
|
|
67
81
|
│ ├── page.jay-html # a page with url parameters
|
|
68
82
|
│ ├── page.ts # optional logic for the segment parameterized page
|
|
83
|
+
├── public/ # Static files (CSS, JS, images, etc.)
|
|
84
|
+
│ ├── styles.css
|
|
85
|
+
│ ├── script.js
|
|
86
|
+
│ └── images/
|
|
69
87
|
├── tsconfig.json # TypeScript configuration
|
|
70
88
|
└── package.json
|
|
71
89
|
```
|
|
@@ -76,6 +94,8 @@ The CLI is built using:
|
|
|
76
94
|
|
|
77
95
|
- **Express.js** - HTTP server
|
|
78
96
|
- **Jay Dev Server** - Core development server functionality
|
|
97
|
+
- **Jay Editor Server** - Editor integration server
|
|
98
|
+
- **get-port** - Automatic port discovery
|
|
79
99
|
- **Vite** - Build tool integration
|
|
80
100
|
|
|
81
101
|
## Future Enhancements
|
|
@@ -91,6 +111,7 @@ The CLI is built using:
|
|
|
91
111
|
## Related Packages
|
|
92
112
|
|
|
93
113
|
- `@jay-framework/dev-server` - Core development server functionality
|
|
114
|
+
- `@jay-framework/editor-server` - Editor integration server
|
|
94
115
|
- `@jay-framework/stack-client-runtime` - Client-side runtime
|
|
95
116
|
- `@jay-framework/stack-server-runtime` - Server-side runtime
|
|
96
117
|
- `@jay-framework/fullstack-component` - Full-stack component system
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { PublishMessage, PublishResponse, SaveImageMessage, SaveImageResponse, HasImageMessage, HasImageResponse } from '@jay-framework/editor-protocol';
|
|
2
|
+
|
|
3
|
+
interface JayConfig {
|
|
4
|
+
devServer?: {
|
|
5
|
+
portRange?: [number, number];
|
|
6
|
+
pagesBase?: string;
|
|
7
|
+
publicFolder?: string;
|
|
8
|
+
};
|
|
9
|
+
editorServer?: {
|
|
10
|
+
portRange?: [number, number];
|
|
11
|
+
editorId?: string;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
declare function loadConfig(): JayConfig;
|
|
15
|
+
declare function getConfigWithDefaults(config: JayConfig): Required<JayConfig>;
|
|
16
|
+
declare function updateConfig(updates: Partial<JayConfig>): void;
|
|
17
|
+
|
|
18
|
+
declare function createEditorHandlers(config: JayConfig): {
|
|
19
|
+
onPublish: (params: PublishMessage) => Promise<PublishResponse>;
|
|
20
|
+
onSaveImage: (params: SaveImageMessage) => Promise<SaveImageResponse>;
|
|
21
|
+
onHasImage: (params: HasImageMessage) => Promise<HasImageResponse>;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export { type JayConfig, createEditorHandlers, getConfigWithDefaults, loadConfig, updateConfig };
|
package/dist/index.js
CHANGED
|
@@ -1,28 +1,234 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
import express from "express";
|
|
3
|
+
import { mkDevServer } from "@jay-framework/dev-server";
|
|
4
|
+
import { createEditorServer } from "@jay-framework/editor-server";
|
|
5
|
+
import getPort from "get-port";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import fs from "fs";
|
|
8
|
+
import YAML from "yaml";
|
|
9
|
+
const DEFAULT_CONFIG = {
|
|
10
|
+
devServer: {
|
|
11
|
+
portRange: [3e3, 3100],
|
|
12
|
+
pagesBase: "./src/pages",
|
|
13
|
+
publicFolder: "./public"
|
|
14
|
+
},
|
|
15
|
+
editorServer: {
|
|
16
|
+
portRange: [3101, 3200]
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
function loadConfig() {
|
|
20
|
+
const configPath = path.resolve(".jay");
|
|
21
|
+
if (!fs.existsSync(configPath)) {
|
|
22
|
+
return DEFAULT_CONFIG;
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
const configContent = fs.readFileSync(configPath, "utf-8");
|
|
26
|
+
const userConfig = YAML.parse(configContent);
|
|
27
|
+
return {
|
|
28
|
+
devServer: {
|
|
29
|
+
...DEFAULT_CONFIG.devServer,
|
|
30
|
+
...userConfig.devServer
|
|
31
|
+
},
|
|
32
|
+
editorServer: {
|
|
33
|
+
...DEFAULT_CONFIG.editorServer,
|
|
34
|
+
...userConfig.editorServer
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.warn("Failed to parse .jay YAML config file, using defaults:", error);
|
|
39
|
+
return DEFAULT_CONFIG;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function getConfigWithDefaults(config2) {
|
|
43
|
+
return {
|
|
44
|
+
devServer: {
|
|
45
|
+
portRange: config2.devServer?.portRange || DEFAULT_CONFIG.devServer.portRange,
|
|
46
|
+
pagesBase: config2.devServer?.pagesBase || DEFAULT_CONFIG.devServer.pagesBase,
|
|
47
|
+
publicFolder: config2.devServer?.publicFolder || DEFAULT_CONFIG.devServer.publicFolder
|
|
48
|
+
},
|
|
49
|
+
editorServer: {
|
|
50
|
+
portRange: config2.editorServer?.portRange || DEFAULT_CONFIG.editorServer.portRange,
|
|
51
|
+
editorId: config2.editorServer?.editorId
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function updateConfig(updates) {
|
|
56
|
+
const configPath = path.resolve(".jay");
|
|
57
|
+
try {
|
|
58
|
+
const existingConfig = loadConfig();
|
|
59
|
+
const updatedConfig = {
|
|
60
|
+
...existingConfig,
|
|
61
|
+
...updates,
|
|
62
|
+
devServer: {
|
|
63
|
+
...existingConfig.devServer,
|
|
64
|
+
...updates.devServer
|
|
65
|
+
},
|
|
66
|
+
editorServer: {
|
|
67
|
+
...existingConfig.editorServer,
|
|
68
|
+
...updates.editorServer
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const yamlContent = YAML.stringify(updatedConfig, { indent: 2 });
|
|
72
|
+
fs.writeFileSync(configPath, yamlContent);
|
|
73
|
+
} catch (error) {
|
|
74
|
+
console.warn("Failed to update .jay config file:", error);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function createEditorHandlers(config2) {
|
|
78
|
+
const resolvedConfig2 = getConfigWithDefaults(config2);
|
|
79
|
+
const onPublish = async (params) => {
|
|
80
|
+
const status = [];
|
|
81
|
+
for (const page of params.pages) {
|
|
82
|
+
try {
|
|
83
|
+
const pagesBasePath = path.resolve(resolvedConfig2.devServer.pagesBase);
|
|
84
|
+
const routePath = page.route === "/" ? "" : page.route;
|
|
85
|
+
const pageDir = path.join(pagesBasePath, routePath);
|
|
86
|
+
const pageFile = path.join(pageDir, "page.jay-html");
|
|
87
|
+
await fs.promises.mkdir(pageDir, { recursive: true });
|
|
88
|
+
await fs.promises.writeFile(pageFile, page.jayHtml, "utf-8");
|
|
89
|
+
console.log(`📝 Published page: ${pageFile}`);
|
|
90
|
+
status.push({
|
|
91
|
+
success: true,
|
|
92
|
+
filePath: pageFile
|
|
93
|
+
});
|
|
94
|
+
} catch (error) {
|
|
95
|
+
console.error(`Failed to publish page ${page.route}:`, error);
|
|
96
|
+
status.push({
|
|
97
|
+
success: false,
|
|
98
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
type: "publish",
|
|
104
|
+
success: status.every((s) => s.success),
|
|
105
|
+
status
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
const onSaveImage = async (params) => {
|
|
109
|
+
try {
|
|
110
|
+
const imagesDir = path.join(
|
|
111
|
+
path.resolve(resolvedConfig2.devServer.publicFolder),
|
|
112
|
+
"images"
|
|
113
|
+
);
|
|
114
|
+
await fs.promises.mkdir(imagesDir, { recursive: true });
|
|
115
|
+
const filename = `${params.imageId}.png`;
|
|
116
|
+
const imagePath = path.join(imagesDir, filename);
|
|
117
|
+
await fs.promises.writeFile(imagePath, Buffer.from(params.imageData, "base64"));
|
|
118
|
+
console.log(`🖼️ Saved image: ${imagePath}`);
|
|
119
|
+
return {
|
|
120
|
+
type: "saveImage",
|
|
121
|
+
success: true,
|
|
122
|
+
imageUrl: `/images/${filename}`
|
|
123
|
+
};
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.error("Failed to save image:", error);
|
|
126
|
+
return {
|
|
127
|
+
type: "saveImage",
|
|
128
|
+
success: false,
|
|
129
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
const onHasImage = async (params) => {
|
|
134
|
+
try {
|
|
135
|
+
const filename = `${params.imageId}.png`;
|
|
136
|
+
const imagePath = path.join(
|
|
137
|
+
path.resolve(resolvedConfig2.devServer.publicFolder),
|
|
138
|
+
"images",
|
|
139
|
+
filename
|
|
140
|
+
);
|
|
141
|
+
const exists = fs.existsSync(imagePath);
|
|
142
|
+
return {
|
|
143
|
+
type: "hasImage",
|
|
144
|
+
success: true,
|
|
145
|
+
exists,
|
|
146
|
+
imageUrl: exists ? `/images/${filename}` : void 0
|
|
147
|
+
};
|
|
148
|
+
} catch (error) {
|
|
149
|
+
console.error("Failed to check image:", error);
|
|
150
|
+
return {
|
|
151
|
+
type: "hasImage",
|
|
152
|
+
success: false,
|
|
153
|
+
exists: false,
|
|
154
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
return {
|
|
159
|
+
onPublish,
|
|
160
|
+
onSaveImage,
|
|
161
|
+
onHasImage
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
const config = loadConfig();
|
|
165
|
+
const resolvedConfig = getConfigWithDefaults(config);
|
|
8
166
|
const jayOptions = {
|
|
9
167
|
tsConfigFilePath: "./tsconfig.json",
|
|
10
168
|
outputDir: "build/jay-runtime"
|
|
11
169
|
};
|
|
12
170
|
const app = express();
|
|
13
171
|
async function initApp() {
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
172
|
+
const devServerPort = await getPort({ port: resolvedConfig.devServer.portRange });
|
|
173
|
+
const editorServer = createEditorServer({
|
|
174
|
+
portRange: resolvedConfig.editorServer.portRange,
|
|
175
|
+
editorId: resolvedConfig.editorServer.editorId,
|
|
176
|
+
onEditorId: (editorId2) => {
|
|
177
|
+
console.log(`Editor connected with ID: ${editorId2}`);
|
|
178
|
+
updateConfig({
|
|
179
|
+
editorServer: {
|
|
180
|
+
editorId: editorId2
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
const { port: editorPort, editorId } = await editorServer.start();
|
|
186
|
+
const handlers = createEditorHandlers(config);
|
|
187
|
+
editorServer.onPublish(handlers.onPublish);
|
|
188
|
+
editorServer.onSaveImage(handlers.onSaveImage);
|
|
189
|
+
editorServer.onHasImage(handlers.onHasImage);
|
|
190
|
+
const { server, viteServer, routes } = await mkDevServer({
|
|
191
|
+
pagesBase: path.resolve(resolvedConfig.devServer.pagesBase),
|
|
192
|
+
serverBase: "/",
|
|
17
193
|
dontCacheSlowly: false,
|
|
18
194
|
jayRollupConfig: jayOptions
|
|
19
195
|
});
|
|
20
196
|
app.use(server);
|
|
197
|
+
const publicPath = path.resolve(resolvedConfig.devServer.publicFolder);
|
|
198
|
+
if (fs.existsSync(publicPath)) {
|
|
199
|
+
app.use(express.static(publicPath));
|
|
200
|
+
} else {
|
|
201
|
+
console.log(`⚠️ Public folder not found: ${resolvedConfig.devServer.publicFolder}`);
|
|
202
|
+
}
|
|
21
203
|
routes.forEach((route) => {
|
|
22
204
|
app.get(route.path, route.handler);
|
|
23
205
|
});
|
|
24
|
-
app.listen(
|
|
25
|
-
console.log(
|
|
206
|
+
const expressServer = app.listen(devServerPort, () => {
|
|
207
|
+
console.log(`🚀 Jay Stack dev server started successfully!`);
|
|
208
|
+
console.log(`📱 Dev Server: http://localhost:${devServerPort}`);
|
|
209
|
+
console.log(`🎨 Editor Server: http://localhost:${editorPort} (ID: ${editorId})`);
|
|
210
|
+
console.log(`📁 Pages directory: ${resolvedConfig.devServer.pagesBase}`);
|
|
211
|
+
if (fs.existsSync(publicPath)) {
|
|
212
|
+
console.log(`📁 Public folder: ${resolvedConfig.devServer.publicFolder}`);
|
|
213
|
+
}
|
|
26
214
|
});
|
|
215
|
+
const shutdown = async () => {
|
|
216
|
+
console.log("\n🛑 Shutting down servers...");
|
|
217
|
+
await editorServer.stop();
|
|
218
|
+
expressServer.closeAllConnections();
|
|
219
|
+
await new Promise((resolve) => expressServer.close(resolve));
|
|
220
|
+
process.exit(0);
|
|
221
|
+
};
|
|
222
|
+
process.on("SIGTERM", shutdown);
|
|
223
|
+
process.on("SIGINT", shutdown);
|
|
27
224
|
}
|
|
28
|
-
initApp()
|
|
225
|
+
initApp().catch((error) => {
|
|
226
|
+
console.error("Failed to start servers:", error);
|
|
227
|
+
process.exit(1);
|
|
228
|
+
});
|
|
229
|
+
export {
|
|
230
|
+
createEditorHandlers,
|
|
231
|
+
getConfigWithDefaults,
|
|
232
|
+
loadConfig,
|
|
233
|
+
updateConfig
|
|
234
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jay-framework/jay-stack-cli",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
|
+
"type": "module",
|
|
5
6
|
"main": "dist/index.js",
|
|
6
7
|
"bin": "dist/index.js",
|
|
7
8
|
"files": [
|
|
@@ -22,12 +23,13 @@
|
|
|
22
23
|
"test:watch": ":"
|
|
23
24
|
},
|
|
24
25
|
"dependencies": {
|
|
25
|
-
"@jay-framework/dev-server": "^0.6.
|
|
26
|
+
"@jay-framework/dev-server": "^0.6.1",
|
|
27
|
+
"@jay-framework/editor-server": "^0.6.1",
|
|
26
28
|
"express": "^5.0.1",
|
|
27
29
|
"vite": "^5.0.11"
|
|
28
30
|
},
|
|
29
31
|
"devDependencies": {
|
|
30
|
-
"@jay-framework/dev-environment": "^0.6.
|
|
32
|
+
"@jay-framework/dev-environment": "^0.6.1",
|
|
31
33
|
"@types/express": "^5.0.2",
|
|
32
34
|
"@types/node": "^22.15.21",
|
|
33
35
|
"nodemon": "^3.0.3",
|
package/dist/index.d.mts
DELETED