@jay-framework/jay-stack-cli 0.5.3 → 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 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 a development server for Jay applications. It automatically configures and runs the Jay development server with sensible defaults, making it easy to get started with Jay stack development.
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
- ### Environment Variables
27
+ ### Configuration
28
28
 
29
- The CLI supports the following environment variables:
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
- - `PORT` - The port to run the server on (default: `5173`)
32
- - `BASE` - The base path for the server (default: `/`)
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
- Example:
41
+ If no `.jay` file is found, the CLI will use default values:
35
42
 
36
- ```bash
37
- PORT=3000 BASE=/app @jay-framework/@jay-framework/jay-cli
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**: `5173` (or `PORT` environment variable)
48
- - **Base Path**: `/` (or `BASE` environment variable)
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
@@ -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
- "use strict";
3
- const express = require("express");
4
- const devServer = require("@jay-framework/dev-server");
5
- const path = require("path");
6
- const port = process.env.PORT || 5173;
7
- const base = process.env.BASE || "/";
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 { server, viteServer, routes } = await devServer.mkDevServer({
15
- pagesBase: path.resolve("./src/pages"),
16
- serverBase: base,
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(port, () => {
25
- console.log(`Server started at http://localhost:${port}`);
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.5.3",
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.5.3",
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.5.3",
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/CHANGELOG.md DELETED
@@ -1,9 +0,0 @@
1
- # @jay-framework/jay-stack-cli
2
-
3
- ## 0.5.1
4
-
5
- ### Patch Changes
6
-
7
- - updating the dependencies to be fixed versions
8
- - Updated dependencies
9
- - @jay-framework/dev-server@0.5.1
package/dist/index.d.mts DELETED
@@ -1,2 +0,0 @@
1
-
2
- export { }