@jay-framework/editor-server 0.6.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/dist/index.cjs +143 -0
- package/dist/index.d.ts +31 -0
- package/package.json +42 -0
- package/readme.md +71 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
4
|
+
var __publicField = (obj, key, value) => {
|
|
5
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
6
|
+
return value;
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
9
|
+
const socket_io = require("socket.io");
|
|
10
|
+
const http = require("http");
|
|
11
|
+
const getPort = require("get-port");
|
|
12
|
+
const editorProtocol = require("@jay-framework/editor-protocol");
|
|
13
|
+
class EditorServer {
|
|
14
|
+
constructor(options) {
|
|
15
|
+
__publicField(this, "io", null);
|
|
16
|
+
__publicField(this, "httpServer", null);
|
|
17
|
+
__publicField(this, "port", null);
|
|
18
|
+
__publicField(this, "editorId", null);
|
|
19
|
+
__publicField(this, "portRange");
|
|
20
|
+
__publicField(this, "onEditorId");
|
|
21
|
+
__publicField(this, "handlers", {});
|
|
22
|
+
this.portRange = options.portRange || [3101, 3200];
|
|
23
|
+
this.onEditorId = options.onEditorId;
|
|
24
|
+
this.editorId = options.editorId || null;
|
|
25
|
+
}
|
|
26
|
+
async start() {
|
|
27
|
+
this.port = await getPort({ port: this.portRange });
|
|
28
|
+
this.httpServer = http.createServer((req, res) => {
|
|
29
|
+
if (req.url?.startsWith("/editor-connect")) {
|
|
30
|
+
this.handlePortDiscovery(req, res);
|
|
31
|
+
} else {
|
|
32
|
+
res.writeHead(404);
|
|
33
|
+
res.end("Not Found");
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
this.io = new socket_io.Server(this.httpServer, {
|
|
37
|
+
cors: {
|
|
38
|
+
origin: "*",
|
|
39
|
+
methods: ["GET", "POST"]
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
this.setupSocketHandlers();
|
|
43
|
+
return new Promise((resolve, reject) => {
|
|
44
|
+
this.httpServer.listen(this.port, () => {
|
|
45
|
+
console.log(`Editor server started on port ${this.port}`);
|
|
46
|
+
resolve({ port: this.port, editorId: this.editorId || "init" });
|
|
47
|
+
});
|
|
48
|
+
this.httpServer.on("error", reject);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
async stop() {
|
|
52
|
+
if (this.io) {
|
|
53
|
+
this.io.close();
|
|
54
|
+
}
|
|
55
|
+
if (this.httpServer) {
|
|
56
|
+
this.httpServer.close();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// DevServerProtocol implementation
|
|
60
|
+
onPublish(callback) {
|
|
61
|
+
this.handlers.publish = callback;
|
|
62
|
+
}
|
|
63
|
+
onSaveImage(callback) {
|
|
64
|
+
this.handlers.saveImage = callback;
|
|
65
|
+
}
|
|
66
|
+
onHasImage(callback) {
|
|
67
|
+
this.handlers.hasImage = callback;
|
|
68
|
+
}
|
|
69
|
+
handlePortDiscovery(req, res) {
|
|
70
|
+
const url = new URL(req.url, `http://localhost:${this.port}`);
|
|
71
|
+
const tabId = url.searchParams.get("id");
|
|
72
|
+
if (!tabId) {
|
|
73
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
74
|
+
res.end(JSON.stringify({ error: "Missing tab ID" }));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (!this.editorId) {
|
|
78
|
+
this.editorId = tabId;
|
|
79
|
+
this.onEditorId && this.onEditorId(tabId);
|
|
80
|
+
}
|
|
81
|
+
const response = {
|
|
82
|
+
status: this.editorId === tabId ? "configured" : "init",
|
|
83
|
+
id: this.editorId,
|
|
84
|
+
port: this.port
|
|
85
|
+
};
|
|
86
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
87
|
+
res.end(JSON.stringify(response));
|
|
88
|
+
}
|
|
89
|
+
setupSocketHandlers() {
|
|
90
|
+
if (!this.io)
|
|
91
|
+
return;
|
|
92
|
+
this.io.on("connection", (socket) => {
|
|
93
|
+
console.log(`Editor connected: ${socket.id}`);
|
|
94
|
+
socket.on("protocol-message", async (message) => {
|
|
95
|
+
try {
|
|
96
|
+
const response = await this.handleProtocolMessage(message);
|
|
97
|
+
socket.emit("protocol-response", response);
|
|
98
|
+
} catch (error) {
|
|
99
|
+
const errorPayload = {
|
|
100
|
+
type: message.payload.type,
|
|
101
|
+
success: false,
|
|
102
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
103
|
+
};
|
|
104
|
+
const errorResponse = editorProtocol.createProtocolResponse(message.id, errorPayload);
|
|
105
|
+
socket.emit("protocol-response", errorResponse);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
socket.on("disconnect", () => {
|
|
109
|
+
console.log(`Editor disconnected: ${socket.id}`);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
async handleProtocolMessage(message) {
|
|
114
|
+
const { id, payload } = message;
|
|
115
|
+
switch (payload.type) {
|
|
116
|
+
case "publish":
|
|
117
|
+
if (!this.handlers.publish) {
|
|
118
|
+
throw new Error("Publish handler not registered");
|
|
119
|
+
}
|
|
120
|
+
const publishResult = await this.handlers.publish(payload);
|
|
121
|
+
return editorProtocol.createProtocolResponse(id, publishResult);
|
|
122
|
+
case "saveImage":
|
|
123
|
+
if (!this.handlers.saveImage) {
|
|
124
|
+
throw new Error("Save image handler not registered");
|
|
125
|
+
}
|
|
126
|
+
const saveResult = await this.handlers.saveImage(payload);
|
|
127
|
+
return editorProtocol.createProtocolResponse(id, saveResult);
|
|
128
|
+
case "hasImage":
|
|
129
|
+
if (!this.handlers.hasImage) {
|
|
130
|
+
throw new Error("Has image handler not registered");
|
|
131
|
+
}
|
|
132
|
+
const hasResult = await this.handlers.hasImage(payload);
|
|
133
|
+
return editorProtocol.createProtocolResponse(id, hasResult);
|
|
134
|
+
default:
|
|
135
|
+
throw new Error(`Unknown message type: ${payload.type}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function createEditorServer(options) {
|
|
140
|
+
return new EditorServer(options);
|
|
141
|
+
}
|
|
142
|
+
exports.EditorServer = EditorServer;
|
|
143
|
+
exports.createEditorServer = createEditorServer;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { DevServerProtocol, PublishMessage, PublishResponse, SaveImageMessage, SaveImageResponse, HasImageMessage, HasImageResponse } from '@jay-framework/editor-protocol';
|
|
2
|
+
|
|
3
|
+
interface EditorServerOptions {
|
|
4
|
+
editorId?: string;
|
|
5
|
+
onEditorId?: (editorId: string) => void;
|
|
6
|
+
portRange?: [number, number];
|
|
7
|
+
}
|
|
8
|
+
declare class EditorServer implements DevServerProtocol {
|
|
9
|
+
private io;
|
|
10
|
+
private httpServer;
|
|
11
|
+
private port;
|
|
12
|
+
private editorId;
|
|
13
|
+
private portRange;
|
|
14
|
+
private onEditorId;
|
|
15
|
+
private handlers;
|
|
16
|
+
constructor(options: EditorServerOptions);
|
|
17
|
+
start(): Promise<{
|
|
18
|
+
port: number;
|
|
19
|
+
editorId: string;
|
|
20
|
+
}>;
|
|
21
|
+
stop(): Promise<void>;
|
|
22
|
+
onPublish(callback: (params: PublishMessage) => Promise<PublishResponse>): void;
|
|
23
|
+
onSaveImage(callback: (params: SaveImageMessage) => Promise<SaveImageResponse>): void;
|
|
24
|
+
onHasImage(callback: (params: HasImageMessage) => Promise<HasImageResponse>): void;
|
|
25
|
+
private handlePortDiscovery;
|
|
26
|
+
private setupSocketHandlers;
|
|
27
|
+
private handleProtocolMessage;
|
|
28
|
+
}
|
|
29
|
+
declare function createEditorServer(options: EditorServerOptions): EditorServer;
|
|
30
|
+
|
|
31
|
+
export { EditorServer, type EditorServerOptions, createEditorServer };
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jay-framework/editor-server",
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"main": "dist/index.cjs",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"readme.md"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "npm run build:js && npm run build:types",
|
|
13
|
+
"build:watch": "npm run build:js -- --watch & npm run build:types -- --watch",
|
|
14
|
+
"build:js": "vite build",
|
|
15
|
+
"build:types": "tsup lib/index.ts --dts-only --format esm",
|
|
16
|
+
"build:check-types": "tsc",
|
|
17
|
+
"clean": "rimraf dist",
|
|
18
|
+
"confirm": "npm run clean && npm run build && npm run build:check-types && npm run test",
|
|
19
|
+
"test": "vitest run",
|
|
20
|
+
"test:watch": "vitest"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@jay-framework/editor-protocol": "^0.6.0",
|
|
24
|
+
"get-port": "^7.0.0",
|
|
25
|
+
"socket.io": "^4.7.4",
|
|
26
|
+
"uuid": "^9.0.1",
|
|
27
|
+
"yaml": "^2.3.4"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@jay-framework/dev-environment": "^0.6.0",
|
|
31
|
+
"@jay-framework/editor-client": "^0.6.0",
|
|
32
|
+
"@jay-framework/jay-cli": "^0.6.0",
|
|
33
|
+
"@types/express": "^5.0.2",
|
|
34
|
+
"@types/node": "^22.15.21",
|
|
35
|
+
"@types/uuid": "^9.0.7",
|
|
36
|
+
"rimraf": "^5.0.5",
|
|
37
|
+
"tsup": "^8.0.1",
|
|
38
|
+
"typescript": "^5.3.3",
|
|
39
|
+
"vite": "^5.0.11",
|
|
40
|
+
"vitest": "^1.2.1"
|
|
41
|
+
}
|
|
42
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# @jay-framework/editor-server
|
|
2
|
+
|
|
3
|
+
Socket.io server implementation for Jay dev servers to handle editor integration.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This package provides a Socket.io server that can be integrated into Jay dev servers to handle real-time communication with editor applications. It includes:
|
|
8
|
+
|
|
9
|
+
- Port discovery and automatic port allocation
|
|
10
|
+
- Socket.io server setup with CORS support
|
|
11
|
+
- Protocol message handling for publish, saveImage, and hasImage operations
|
|
12
|
+
- Default protocol handlers for file operations
|
|
13
|
+
- Configuration management via `.jay` files
|
|
14
|
+
- Memory filesystem support for testing
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { createEditorServer, createDefaultHandlers } from '@jay-framework/editor-server';
|
|
20
|
+
|
|
21
|
+
// Create the editor server
|
|
22
|
+
const server = createEditorServer({
|
|
23
|
+
projectRoot: '/path/to/project',
|
|
24
|
+
portRange: [3101, 3200],
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const handlePublish: EditorProtocol['publish'] = () => {}; // callback implementation
|
|
28
|
+
const handleSaveImage: EditorProtocol['saveImage'] = () => {}; // callback implementation
|
|
29
|
+
const handleHasImage: EditorProtocol['hasImage'] = () => {}; // callback implementation
|
|
30
|
+
|
|
31
|
+
// Register protocol handlers
|
|
32
|
+
server.onPublish(handlePublish);
|
|
33
|
+
server.onSaveImage(handleSaveImage);
|
|
34
|
+
server.onHasImage(handleHasImage);
|
|
35
|
+
|
|
36
|
+
// Start the server
|
|
37
|
+
const { port, editorId } = await server.start();
|
|
38
|
+
console.log(`Editor server running on port ${port} with ID ${editorId}`);
|
|
39
|
+
|
|
40
|
+
// Stop the server when done
|
|
41
|
+
await server.stop();
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Features
|
|
45
|
+
|
|
46
|
+
### Port Discovery
|
|
47
|
+
|
|
48
|
+
- Automatically finds available ports in the configured range
|
|
49
|
+
- Provides HTTP endpoint for editor port discovery
|
|
50
|
+
- Supports both "init" mode and "configured" mode
|
|
51
|
+
|
|
52
|
+
### Protocol Support
|
|
53
|
+
|
|
54
|
+
- **Publish**: Saves jay-html files to the project
|
|
55
|
+
- **Save Image**: Saves base64 image data to assets directory
|
|
56
|
+
- **Has Image**: Checks if an image already exists
|
|
57
|
+
|
|
58
|
+
### Protocol Message Structure
|
|
59
|
+
|
|
60
|
+
All messages use a wrapper structure with `id`, `timestamp`, and `payload` fields for reliable communication.
|
|
61
|
+
|
|
62
|
+
### Configuration
|
|
63
|
+
|
|
64
|
+
- optional `editorId` config
|
|
65
|
+
- if omitted, starts with `init` mode supporting discovery of `editorId` and callback `onEditorId` to save `editorId`
|
|
66
|
+
- if provided, only accepts connection with the same `editorId`
|
|
67
|
+
- Supports custom port ranges
|
|
68
|
+
|
|
69
|
+
## Integration with Dev Server
|
|
70
|
+
|
|
71
|
+
This package is designed to be integrated into the existing `@jay-framework/dev-server` package to provide editor integration capabilities.
|