@zuplo/editor 1.0.18282606817-dev → 1.0.18288423685-dev
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/client/{local-editor.html → local.html} +5 -5
- package/dist/client/static/css/App-DH9HRCOf.css +1 -0
- package/dist/client/static/css/main-DB0Klj1W.css +1 -0
- package/dist/client/static/js/App-B6G4730z.js +2162 -0
- package/dist/client/static/js/App-B6G4730z.js.map +1 -0
- package/dist/client/static/js/local-worker-Cd_QJYDp.js +2 -0
- package/dist/client/static/js/local-worker-Cd_QJYDp.js.map +1 -0
- package/dist/client/static/js/main-BKLfe0Z9.js +52 -0
- package/dist/client/static/js/main-BKLfe0Z9.js.map +1 -0
- package/dist/config.d.ts +54 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +54 -0
- package/dist/config.js.map +1 -0
- package/dist/error-handler.d.ts +3 -0
- package/dist/error-handler.d.ts.map +1 -0
- package/dist/error-handler.js +135 -0
- package/dist/error-handler.js.map +1 -0
- package/dist/interfaces.d.ts +24 -0
- package/dist/interfaces.d.ts.map +1 -0
- package/dist/interfaces.js +13 -0
- package/dist/interfaces.js.map +1 -0
- package/dist/routes/api.d.ts +2 -1
- package/dist/routes/api.d.ts.map +1 -1
- package/dist/routes/api.js +23 -21
- package/dist/routes/api.js.map +1 -1
- package/dist/routes/editor.d.ts.map +1 -1
- package/dist/routes/editor.js +37 -51
- package/dist/routes/editor.js.map +1 -1
- package/dist/routes/fs.d.ts.map +1 -1
- package/dist/routes/fs.js +219 -238
- package/dist/routes/fs.js.map +1 -1
- package/dist/routes/test.js +1 -1
- package/dist/routes/test.js.map +1 -1
- package/dist/routes/types.d.ts.map +1 -1
- package/dist/routes/types.js +30 -22
- package/dist/routes/types.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +38 -29
- package/dist/server.js.map +1 -1
- package/dist/utils/path.d.ts +33 -0
- package/dist/utils/path.d.ts.map +1 -0
- package/dist/utils/path.js +42 -0
- package/dist/utils/path.js.map +1 -0
- package/package.json +2 -1
- package/dist/client/static/css/main-D3M2tKfG.css +0 -1
- package/dist/client/static/js/local-worker-BVQSFGzz.js +0 -2
- package/dist/client/static/js/local-worker-BVQSFGzz.js.map +0 -1
- package/dist/client/static/js/main-CIyp_ifb.js +0 -2074
- package/dist/client/static/js/main-CIyp_ifb.js.map +0 -1
package/dist/config.d.ts
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
/**
|
2
|
+
* Configuration constants for the local editor server.
|
3
|
+
* Centralizes all magic numbers and configuration values.
|
4
|
+
*/
|
5
|
+
export declare const editorConfig: {
|
6
|
+
/**
|
7
|
+
* Server configuration
|
8
|
+
*/
|
9
|
+
readonly server: {
|
10
|
+
/** Default port for the editor server */
|
11
|
+
readonly port: 9100;
|
12
|
+
/** Default port for the local Zuplo gateway */
|
13
|
+
readonly gatewayPort: 9000;
|
14
|
+
/** Maximum request body size (100MB) */
|
15
|
+
readonly bodyLimit: number;
|
16
|
+
/** Default host for the server */
|
17
|
+
readonly host: "localhost";
|
18
|
+
};
|
19
|
+
/**
|
20
|
+
* Server-Sent Events configuration
|
21
|
+
*/
|
22
|
+
readonly sse: {
|
23
|
+
/**
|
24
|
+
* Keep-alive interval in milliseconds (30 seconds)
|
25
|
+
* Prevents proxy/browser timeouts for long-lived connections
|
26
|
+
*/
|
27
|
+
readonly keepAliveInterval: 30000;
|
28
|
+
};
|
29
|
+
/**
|
30
|
+
* File operation configuration
|
31
|
+
*/
|
32
|
+
readonly file: {
|
33
|
+
/**
|
34
|
+
* Tolerance window for conflict detection in milliseconds (2 seconds)
|
35
|
+
* Prevents false positives caused by:
|
36
|
+
* - Filesystem timestamp precision variations
|
37
|
+
* - Time between read and write operations
|
38
|
+
* - Network latency in distributed filesystems
|
39
|
+
*/
|
40
|
+
readonly conflictToleranceMs: 2000;
|
41
|
+
/** Maximum file size for uploads (100MB) */
|
42
|
+
readonly maxFileSize: number;
|
43
|
+
/** Allowed directories for file operations */
|
44
|
+
readonly allowedDirs: readonly ["config", "modules", "schemas"];
|
45
|
+
};
|
46
|
+
/**
|
47
|
+
* File watching configuration
|
48
|
+
*/
|
49
|
+
readonly watch: {
|
50
|
+
/** Directories to watch for changes */
|
51
|
+
readonly watchedDirs: readonly ["config", "modules", "schemas"];
|
52
|
+
};
|
53
|
+
};
|
54
|
+
//# sourceMappingURL=config.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,YAAY;IACvB;;OAEG;;QAED,yCAAyC;;QAEzC,+CAA+C;;QAE/C,wCAAwC;;QAExC,kCAAkC;;;IAIpC;;OAEG;;QAED;;;WAGG;;;IAIL;;OAEG;;QAED;;;;;;WAMG;;QAGH,4CAA4C;;QAG5C,8CAA8C;;;IAIhD;;OAEG;;QAED,uCAAuC;;;CAGjC,CAAC"}
|
package/dist/config.js
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
/**
|
2
|
+
* Configuration constants for the local editor server.
|
3
|
+
* Centralizes all magic numbers and configuration values.
|
4
|
+
*/
|
5
|
+
export const editorConfig = {
|
6
|
+
/**
|
7
|
+
* Server configuration
|
8
|
+
*/
|
9
|
+
server: {
|
10
|
+
/** Default port for the editor server */
|
11
|
+
port: 9100,
|
12
|
+
/** Default port for the local Zuplo gateway */
|
13
|
+
gatewayPort: 9000,
|
14
|
+
/** Maximum request body size (100MB) */
|
15
|
+
bodyLimit: 100 * 1024 * 1024,
|
16
|
+
/** Default host for the server */
|
17
|
+
host: "localhost",
|
18
|
+
},
|
19
|
+
/**
|
20
|
+
* Server-Sent Events configuration
|
21
|
+
*/
|
22
|
+
sse: {
|
23
|
+
/**
|
24
|
+
* Keep-alive interval in milliseconds (30 seconds)
|
25
|
+
* Prevents proxy/browser timeouts for long-lived connections
|
26
|
+
*/
|
27
|
+
keepAliveInterval: 30000,
|
28
|
+
},
|
29
|
+
/**
|
30
|
+
* File operation configuration
|
31
|
+
*/
|
32
|
+
file: {
|
33
|
+
/**
|
34
|
+
* Tolerance window for conflict detection in milliseconds (2 seconds)
|
35
|
+
* Prevents false positives caused by:
|
36
|
+
* - Filesystem timestamp precision variations
|
37
|
+
* - Time between read and write operations
|
38
|
+
* - Network latency in distributed filesystems
|
39
|
+
*/
|
40
|
+
conflictToleranceMs: 2000,
|
41
|
+
/** Maximum file size for uploads (100MB) */
|
42
|
+
maxFileSize: 100 * 1024 * 1024,
|
43
|
+
/** Allowed directories for file operations */
|
44
|
+
allowedDirs: ["config", "modules", "schemas"],
|
45
|
+
},
|
46
|
+
/**
|
47
|
+
* File watching configuration
|
48
|
+
*/
|
49
|
+
watch: {
|
50
|
+
/** Directories to watch for changes */
|
51
|
+
watchedDirs: ["config", "modules", "schemas"],
|
52
|
+
},
|
53
|
+
};
|
54
|
+
//# sourceMappingURL=config.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B;;OAEG;IACH,MAAM,EAAE;QACN,yCAAyC;QACzC,IAAI,EAAE,IAAI;QACV,+CAA+C;QAC/C,WAAW,EAAE,IAAI;QACjB,wCAAwC;QACxC,SAAS,EAAE,GAAG,GAAG,IAAI,GAAG,IAAI;QAC5B,kCAAkC;QAClC,IAAI,EAAE,WAAW;KAClB;IAED;;OAEG;IACH,GAAG,EAAE;QACH;;;WAGG;QACH,iBAAiB,EAAE,KAAK;KACzB;IAED;;OAEG;IACH,IAAI,EAAE;QACJ;;;;;;WAMG;QACH,mBAAmB,EAAE,IAAI;QAEzB,4CAA4C;QAC5C,WAAW,EAAE,GAAG,GAAG,IAAI,GAAG,IAAI;QAE9B,8CAA8C;QAC9C,WAAW,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAU;KACvD;IAED;;OAEG;IACH,KAAK,EAAE;QACL,uCAAuC;QACvC,WAAW,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAU;KACvD;CACO,CAAC"}
|
@@ -0,0 +1,3 @@
|
|
1
|
+
import { FastifyReply, FastifyRequest } from "fastify";
|
2
|
+
export declare function errorHandler(error: Error, request: FastifyRequest, reply: FastifyReply): FastifyReply<import("fastify").RouteGenericInterface, import("fastify").RawServerDefault, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, unknown, import("fastify").FastifySchema, import("fastify").FastifyTypeProviderDefault, unknown>;
|
3
|
+
//# sourceMappingURL=error-handler.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../src/error-handler.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAEvD,wBAAgB,YAAY,CAC1B,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,YAAY,6RA4HpB"}
|
@@ -0,0 +1,135 @@
|
|
1
|
+
import { ApiError, HttpStatusCode, Problems, } from "@zuplo/errors";
|
2
|
+
export function errorHandler(error, request, reply) {
|
3
|
+
let statusCode = 500;
|
4
|
+
let problem;
|
5
|
+
if (error instanceof ApiError) {
|
6
|
+
statusCode = error.status;
|
7
|
+
problem = {
|
8
|
+
type: error.type,
|
9
|
+
title: error.message,
|
10
|
+
status: error.status,
|
11
|
+
detail: error.detail,
|
12
|
+
instance: error.instance,
|
13
|
+
};
|
14
|
+
}
|
15
|
+
else if (typeof error === "object" &&
|
16
|
+
"validation" in error &&
|
17
|
+
"validationContext" in error) {
|
18
|
+
statusCode = HttpStatusCode.BAD_REQUEST;
|
19
|
+
problem = {
|
20
|
+
...Problems.BAD_REQUEST,
|
21
|
+
// validationContext will be 'body' or 'params' or 'headers' or 'query'
|
22
|
+
detail: `An error occurred when validating the ${error.validationContext}.`,
|
23
|
+
errors: error.validation,
|
24
|
+
};
|
25
|
+
}
|
26
|
+
else if (typeof error === "object" &&
|
27
|
+
"code" in error &&
|
28
|
+
error.code === "FST_ERR_NOT_FOUND") {
|
29
|
+
statusCode = 404;
|
30
|
+
problem = Problems.NOT_FOUND;
|
31
|
+
}
|
32
|
+
else if (typeof error === "object" &&
|
33
|
+
"code" in error &&
|
34
|
+
error.code === "FST_ERR_CTP_BODY_TOO_LARGE") {
|
35
|
+
statusCode = HttpStatusCode.PAYLOAD_TOO_LARGE;
|
36
|
+
problem = {
|
37
|
+
type: " https://zup.fail/http-status/413",
|
38
|
+
title: "Payload Too Large",
|
39
|
+
status: HttpStatusCode.PAYLOAD_TOO_LARGE,
|
40
|
+
detail: error.message,
|
41
|
+
};
|
42
|
+
}
|
43
|
+
else if (typeof error === "object" &&
|
44
|
+
"code" in error &&
|
45
|
+
error.code === "FST_ERR_CTP_INVALID_MEDIA_TYPE") {
|
46
|
+
statusCode = HttpStatusCode.UNSUPPORTED_MEDIA_TYPE;
|
47
|
+
problem = {
|
48
|
+
type: "https://zup.fail/http-status/415",
|
49
|
+
title: "Unsupported Media Type",
|
50
|
+
status: HttpStatusCode.UNSUPPORTED_MEDIA_TYPE,
|
51
|
+
detail: error.message,
|
52
|
+
};
|
53
|
+
}
|
54
|
+
else if (typeof error === "object" &&
|
55
|
+
"code" in error &&
|
56
|
+
typeof error.code === "string" &&
|
57
|
+
[
|
58
|
+
"FST_ERR_CTP_INVALID_TYPE",
|
59
|
+
"FST_ERR_CTP_EMPTY_TYPE",
|
60
|
+
"FST_ERR_CTP_INVALID_CONTENT_LENGTH",
|
61
|
+
"FST_ERR_CTP_EMPTY_JSON_BODY",
|
62
|
+
"FST_ERR_BAD_URL",
|
63
|
+
"FST_ERR_INVALID_URL",
|
64
|
+
"FST_ERR_VALIDATION",
|
65
|
+
"FST_ERR_ROUTE_METHOD_INVALID",
|
66
|
+
"FST_ERR_ROUTE_METHOD_NOT_SUPPORTED",
|
67
|
+
].includes(error.code)) {
|
68
|
+
statusCode = HttpStatusCode.BAD_REQUEST;
|
69
|
+
problem = {
|
70
|
+
...Problems.BAD_REQUEST,
|
71
|
+
detail: error.message,
|
72
|
+
};
|
73
|
+
}
|
74
|
+
else {
|
75
|
+
let errorStatus;
|
76
|
+
if (!reply.statusCode || reply.statusCode === 200) {
|
77
|
+
if (typeof error === "object" &&
|
78
|
+
"statusCode" in error &&
|
79
|
+
typeof error.statusCode === "number") {
|
80
|
+
errorStatus = error.statusCode;
|
81
|
+
}
|
82
|
+
else if (typeof error === "object" &&
|
83
|
+
"status" in error &&
|
84
|
+
typeof error.status === "number") {
|
85
|
+
errorStatus = error.status;
|
86
|
+
}
|
87
|
+
statusCode = errorStatus && errorStatus >= 400 ? errorStatus : 500;
|
88
|
+
}
|
89
|
+
else {
|
90
|
+
statusCode = reply.statusCode;
|
91
|
+
}
|
92
|
+
problem = getProblemFromStatus(statusCode);
|
93
|
+
if (typeof error === "object" && "message" in error) {
|
94
|
+
problem.detail = error.message;
|
95
|
+
}
|
96
|
+
else if (typeof error === "string") {
|
97
|
+
problem.detail = error;
|
98
|
+
}
|
99
|
+
}
|
100
|
+
problem.trace = {
|
101
|
+
timestamp: new Date().toJSON(),
|
102
|
+
requestId: request.id,
|
103
|
+
};
|
104
|
+
if (statusCode < 500) {
|
105
|
+
reply.log.warn({ req: request, res: reply, err: error }, error?.message);
|
106
|
+
}
|
107
|
+
else {
|
108
|
+
// Sentry.captureException(error);
|
109
|
+
reply.log.error({ req: request, res: reply, err: error }, error?.message);
|
110
|
+
}
|
111
|
+
const body = JSON.stringify(problem, null, 2);
|
112
|
+
return reply
|
113
|
+
.status(statusCode)
|
114
|
+
.header("content-type", "application/json")
|
115
|
+
.send(body);
|
116
|
+
}
|
117
|
+
function getProblemFromStatus(status) {
|
118
|
+
if (status === 401) {
|
119
|
+
return Problems.UNAUTHORIZED;
|
120
|
+
}
|
121
|
+
else if (status === 403) {
|
122
|
+
return Problems.FORBIDDEN;
|
123
|
+
}
|
124
|
+
else if (status === 404) {
|
125
|
+
return Problems.NOT_FOUND;
|
126
|
+
}
|
127
|
+
else if (status === 405) {
|
128
|
+
return Problems.METHOD_NOT_ALLOWED;
|
129
|
+
}
|
130
|
+
else if (status < 500 && status >= 400) {
|
131
|
+
return Problems.BAD_REQUEST;
|
132
|
+
}
|
133
|
+
return Problems.INTERNAL_SERVER_ERROR;
|
134
|
+
}
|
135
|
+
//# sourceMappingURL=error-handler.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../src/error-handler.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
/**
|
2
|
+
* Represents a Server-Sent Events (SSE) client connection.
|
3
|
+
* This is a subset of the http.ServerResponse interface
|
4
|
+
* with the methods we actually use for SSE.
|
5
|
+
*/
|
6
|
+
export interface SseClient {
|
7
|
+
/**
|
8
|
+
* Write data to the client connection
|
9
|
+
*/
|
10
|
+
write(data: string): boolean;
|
11
|
+
/**
|
12
|
+
* End the connection
|
13
|
+
*/
|
14
|
+
end(): void;
|
15
|
+
/**
|
16
|
+
* Check if the connection is writable
|
17
|
+
*/
|
18
|
+
writable: boolean;
|
19
|
+
}
|
20
|
+
/**
|
21
|
+
* Type guard to check if a response has the necessary methods for SSE
|
22
|
+
*/
|
23
|
+
export declare function isSseClient(response: unknown): response is SseClient;
|
24
|
+
//# sourceMappingURL=interfaces.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB;;OAEG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAE7B;;OAEG;IACH,GAAG,IAAI,IAAI,CAAC;IAEZ;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,QAAQ,IAAI,SAAS,CAUpE"}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
/**
|
2
|
+
* Type guard to check if a response has the necessary methods for SSE
|
3
|
+
*/
|
4
|
+
export function isSseClient(response) {
|
5
|
+
return (typeof response === "object" &&
|
6
|
+
response !== null &&
|
7
|
+
"write" in response &&
|
8
|
+
typeof response.write === "function" &&
|
9
|
+
"end" in response &&
|
10
|
+
typeof response.end === "function" &&
|
11
|
+
"writable" in response);
|
12
|
+
}
|
13
|
+
//# sourceMappingURL=interfaces.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAsBA;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,QAAiB;IAC3C,OAAO,CACL,OAAO,QAAQ,KAAK,QAAQ;QAC5B,QAAQ,KAAK,IAAI;QACjB,OAAO,IAAI,QAAQ;QACnB,OAAQ,QAAsB,CAAC,KAAK,KAAK,UAAU;QACnD,KAAK,IAAI,QAAQ;QACjB,OAAQ,QAAsB,CAAC,GAAG,KAAK,UAAU;QACjD,UAAU,IAAI,QAAQ,CACvB,CAAC;AACJ,CAAC"}
|
package/dist/routes/api.d.ts
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
import { FastifyInstance } from "fastify";
|
2
2
|
import type { Logger } from "pino";
|
3
|
+
import { type SseClient } from "../interfaces.js";
|
3
4
|
interface ApiRoutesOptions {
|
4
5
|
workingDir: string;
|
5
6
|
portalRoot: string;
|
6
7
|
logger: Logger;
|
7
|
-
sseClients: Set<
|
8
|
+
sseClients: Set<SseClient>;
|
8
9
|
deploymentUrl: string;
|
9
10
|
}
|
10
11
|
export declare function createApiRoutes(fastify: FastifyInstance, options: ApiRoutesOptions): Promise<void>;
|
package/dist/routes/api.d.ts.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/routes/api.ts"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/routes/api.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAQlD,UAAU,gBAAgB;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wBAAsB,eAAe,CACnC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,IAAI,CAAC,CA4Hf"}
|
package/dist/routes/api.js
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
import { ApiNotFoundError } from "@zuplo/errors";
|
2
|
+
import { editorConfig } from "../config.js";
|
1
3
|
import { createEditorRoutes } from "./editor.js";
|
2
4
|
import { createFsRoutes } from "./fs.js";
|
3
5
|
import { createTestRoutes } from "./test.js";
|
@@ -44,21 +46,27 @@ export async function createApiRoutes(fastify, options) {
|
|
44
46
|
// Send initial event
|
45
47
|
reply.raw.write(`data: ${JSON.stringify({ type: "init", filePath: POLICIES_FILENAME })}\n\n`);
|
46
48
|
sseClients.add(reply.raw);
|
47
|
-
// Send keep-alive comments
|
49
|
+
// Send keep-alive comments to prevent proxy/browser timeouts
|
48
50
|
const keepAliveInterval = setInterval(() => {
|
49
51
|
try {
|
50
|
-
reply.raw.
|
52
|
+
if (reply.raw.writable) {
|
53
|
+
reply.raw.write(": keep-alive\n\n");
|
54
|
+
}
|
55
|
+
else {
|
56
|
+
clearInterval(keepAliveInterval);
|
57
|
+
}
|
51
58
|
}
|
52
|
-
catch {
|
59
|
+
catch (err) {
|
60
|
+
logger.warn({ err }, "Error sending SSE keep-alive");
|
53
61
|
clearInterval(keepAliveInterval);
|
54
62
|
}
|
55
|
-
},
|
63
|
+
}, editorConfig.sse.keepAliveInterval);
|
56
64
|
request.raw.on("close", () => {
|
57
65
|
clearInterval(keepAliveInterval);
|
58
66
|
sseClients.delete(reply.raw);
|
59
67
|
});
|
60
68
|
request.raw.on("error", (err) => {
|
61
|
-
logger.error(
|
69
|
+
logger.error({ err }, "SSE connection error");
|
62
70
|
clearInterval(keepAliveInterval);
|
63
71
|
sseClients.delete(reply.raw);
|
64
72
|
});
|
@@ -87,26 +95,20 @@ export async function createApiRoutes(fastify, options) {
|
|
87
95
|
// Remove /api prefix and fetch from CDN
|
88
96
|
const cdnPath = request.url.replace("/api", "");
|
89
97
|
const cdnUrl = `https://cdn.zuplo.com${cdnPath}`;
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
return reply.status(response.status).send("Not found");
|
94
|
-
}
|
95
|
-
const contentType = response.headers.get("content-type");
|
96
|
-
if (contentType) {
|
97
|
-
reply.header("Content-Type", contentType);
|
98
|
-
}
|
99
|
-
const data = await response.text();
|
100
|
-
reply.send(data);
|
98
|
+
const response = await fetch(cdnUrl);
|
99
|
+
if (!response.ok) {
|
100
|
+
throw new ApiNotFoundError();
|
101
101
|
}
|
102
|
-
|
103
|
-
|
104
|
-
reply.
|
102
|
+
const contentType = response.headers.get("content-type");
|
103
|
+
if (contentType) {
|
104
|
+
reply.header("Content-Type", contentType);
|
105
105
|
}
|
106
|
+
const data = await response.text();
|
107
|
+
reply.send(data);
|
106
108
|
});
|
107
109
|
// Catch-all for unhandled API routes - return 404
|
108
|
-
fastify.all("/*", async (
|
109
|
-
|
110
|
+
fastify.all("/*", async () => {
|
111
|
+
throw new ApiNotFoundError();
|
110
112
|
});
|
111
113
|
}
|
112
114
|
//# sourceMappingURL=api.js.map
|
package/dist/routes/api.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/routes/api.ts"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/routes/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGjD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/C,MAAM,iBAAiB,GAAG,eAAe,CAAC;AAU1C,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAAwB,EACxB,OAAyB;IAEzB,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC;IAE9E,oBAAoB;IACpB,MAAM,OAAO,CAAC,QAAQ,CAAC,cAAc,EAAE;QACrC,MAAM,EAAE,0BAA0B;QAClC,UAAU;KACX,CAAC,CAAC;IAEH,oDAAoD;IACpD,MAAM,OAAO,CAAC,QAAQ,CAAC,iBAAiB,EAAE;QACxC,MAAM,EAAE,QAAQ;QAChB,UAAU;KACX,CAAC,CAAC;IAEH,uDAAuD;IACvD,MAAM,OAAO,CAAC,QAAQ,CAAC,kBAAkB,EAAE;QACzC,MAAM,EAAE,YAAY;QACpB,UAAU;KACX,CAAC,CAAC;IAEH,kEAAkE;IAClE,MAAM,OAAO,CAAC,QAAQ,CAAC,gBAAgB,EAAE;QACvC,MAAM,EAAE,KAAK;QACb,UAAU;QACV,MAAM;QACN,aAAa;KACd,CAAC,CAAC;IAEH,sCAAsC;IACtC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QAC/C,2CAA2C;QAC3C,KAAK,CAAC,MAAM,EAAE,CAAC;QAEf,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;YACvB,cAAc,EAAE,mBAAmB;YACnC,eAAe,EAAE,UAAU;YAC3B,UAAU,EAAE,YAAY;YACxB,mBAAmB,EAAE,IAAI,EAAE,0BAA0B;SACtD,CAAC,CAAC;QAEH,4BAA4B;QAC5B,IAAI,OAAO,KAAK,CAAC,GAAG,CAAC,YAAY,KAAK,UAAU,EAAE,CAAC;YACjD,KAAK,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;QAC3B,CAAC;QAED,qBAAqB;QACrB,KAAK,CAAC,GAAG,CAAC,KAAK,CACb,SAAS,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,EAAE,CAAC,MAAM,CAC7E,CAAC;QAEF,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,GAAgB,CAAC,CAAC;QAEvC,6DAA6D;QAC7D,MAAM,iBAAiB,GAAG,WAAW,CAAC,GAAG,EAAE;YACzC,IAAI,CAAC;gBACH,IAAI,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;oBACvB,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;gBACtC,CAAC;qBAAM,CAAC;oBACN,aAAa,CAAC,iBAAiB,CAAC,CAAC;gBACnC,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,8BAA8B,CAAC,CAAC;gBACrD,aAAa,CAAC,iBAAiB,CAAC,CAAC;YACnC,CAAC;QACH,CAAC,EAAE,YAAY,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;QAEvC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YAC3B,aAAa,CAAC,iBAAiB,CAAC,CAAC;YACjC,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YAC9B,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,sBAAsB,CAAC,CAAC;YAC9C,aAAa,CAAC,iBAAiB,CAAC,CAAC;YACjC,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,GAAgB,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,eAAe;IACf,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE;QAC7C,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEH,uDAAuD;IACvD,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE;QAC7D,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YACrB,iBAAiB,EAAE;gBACjB,MAAM,EAAE;oBACN;wBACE,KAAK,EAAE,KAAK;wBACZ,GAAG,EAAE,aAAa;qBACnB;iBACF;aACF;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,qEAAqE;IACrE,+DAA+D;IAC/D,2EAA2E;IAC3E,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACjD,wCAAwC;QACxC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,wBAAwB,OAAO,EAAE,CAAC;QAEjD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,CAAC;QACrC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,gBAAgB,EAAE,CAAC;QAC/B,CAAC;QAED,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QACzD,IAAI,WAAW,EAAE,CAAC;YAChB,KAAK,CAAC,MAAM,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;QAC5C,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC,CAAC,CAAC;IAEH,kDAAkD;IAClD,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE;QAC3B,MAAM,IAAI,gBAAgB,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;AACL,CAAC"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../src/routes/editor.ts"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../src/routes/editor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAiErE,UAAU,mBAAoB,SAAQ,oBAAoB;IACxD,UAAU,EAAE,MAAM,CAAC;CACpB;AAqBD,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAqFf"}
|
package/dist/routes/editor.js
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
import { ApiError, Problems } from "@zuplo/errors";
|
1
2
|
import fs from "node:fs/promises";
|
2
3
|
import { homedir } from "node:os";
|
3
4
|
import path from "node:path";
|
5
|
+
import { normalizeRelativePath } from "../utils/path.js";
|
4
6
|
// XDG config directory helpers
|
5
7
|
function getXdgConfigHome() {
|
6
8
|
return process.env.XDG_CONFIG_HOME ?? path.join(homedir(), ".config");
|
@@ -69,26 +71,19 @@ export async function createEditorRoutes(fastify, options) {
|
|
69
71
|
const { workingDir } = options;
|
70
72
|
// Detect editor: GET /editor/detect
|
71
73
|
fastify.get("/detect", async (_request, reply) => {
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
if (savedEditor && EDITORS[savedEditor]) {
|
76
|
-
return reply.status(200).send({
|
77
|
-
editor: savedEditor,
|
78
|
-
name: EDITORS[savedEditor].name,
|
79
|
-
});
|
80
|
-
}
|
81
|
-
// No editor found
|
74
|
+
// Check saved preference
|
75
|
+
const savedEditor = await loadEditorPreference();
|
76
|
+
if (savedEditor && EDITORS[savedEditor]) {
|
82
77
|
return reply.status(200).send({
|
83
|
-
editor:
|
84
|
-
name:
|
85
|
-
});
|
86
|
-
}
|
87
|
-
catch (err) {
|
88
|
-
return reply.status(500).send({
|
89
|
-
message: `Error detecting editor: ${err.message}`,
|
78
|
+
editor: savedEditor,
|
79
|
+
name: EDITORS[savedEditor].name,
|
90
80
|
});
|
91
81
|
}
|
82
|
+
// No editor found
|
83
|
+
return reply.status(200).send({
|
84
|
+
editor: null,
|
85
|
+
name: null,
|
86
|
+
});
|
92
87
|
});
|
93
88
|
// Get available editors: GET /editor/list
|
94
89
|
fastify.get("/list", async (_request, reply) => {
|
@@ -102,50 +97,41 @@ export async function createEditorRoutes(fastify, options) {
|
|
102
97
|
fastify.post("/preference", async (request, reply) => {
|
103
98
|
const { editor } = request.body;
|
104
99
|
if (!EDITORS[editor]) {
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
}
|
109
|
-
try {
|
110
|
-
await saveEditorPreference(editor);
|
111
|
-
return reply.status(200).send({ success: true });
|
112
|
-
}
|
113
|
-
catch (err) {
|
114
|
-
return reply.status(500).send({
|
115
|
-
message: `Error saving preference: ${err.message}`,
|
100
|
+
throw new ApiError({
|
101
|
+
...Problems.BAD_REQUEST,
|
102
|
+
detail: `Unknown editor: ${editor}`,
|
116
103
|
});
|
117
104
|
}
|
105
|
+
await saveEditorPreference(editor);
|
106
|
+
return reply.status(200).send({ success: true });
|
118
107
|
});
|
119
108
|
// Get URL to open file in editor: POST /editor/open
|
120
109
|
fastify.post("/open", async (request, reply) => {
|
121
110
|
const { file, line = 1, column = 1 } = request.body;
|
122
111
|
if (!file) {
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
const savedEditor = await loadEditorPreference();
|
128
|
-
if (!savedEditor || !EDITORS[savedEditor]) {
|
129
|
-
return reply.status(400).send({
|
130
|
-
message: "No editor preference set",
|
131
|
-
});
|
132
|
-
}
|
133
|
-
const editor = EDITORS[savedEditor];
|
134
|
-
// Build file path
|
135
|
-
const relativePath = file.startsWith("/") ? file.slice(1) : file;
|
136
|
-
const fullPath = path.join(workingDir, relativePath);
|
137
|
-
// Build URL from template
|
138
|
-
const url = editor.urlTemplate
|
139
|
-
.replace("{file}", fullPath)
|
140
|
-
.replace("{line}", String(line))
|
141
|
-
.replace("{column}", String(column));
|
142
|
-
return reply.status(200).send({ url });
|
112
|
+
throw new ApiError({
|
113
|
+
...Problems.BAD_REQUEST,
|
114
|
+
detail: "File path is required",
|
115
|
+
});
|
143
116
|
}
|
144
|
-
|
145
|
-
|
146
|
-
|
117
|
+
// Get editor preference
|
118
|
+
const savedEditor = await loadEditorPreference();
|
119
|
+
if (!savedEditor || !EDITORS[savedEditor]) {
|
120
|
+
throw new ApiError({
|
121
|
+
...Problems.BAD_REQUEST,
|
122
|
+
detail: "No editor preference set",
|
147
123
|
});
|
148
124
|
}
|
125
|
+
const editor = EDITORS[savedEditor];
|
126
|
+
// Build file path
|
127
|
+
const relativePath = normalizeRelativePath(file);
|
128
|
+
const fullPath = path.join(workingDir, relativePath);
|
129
|
+
// Build URL from template
|
130
|
+
const url = editor.urlTemplate
|
131
|
+
.replace("{file}", fullPath)
|
132
|
+
.replace("{line}", String(line))
|
133
|
+
.replace("{column}", String(column));
|
134
|
+
return reply.status(200).send({ url });
|
149
135
|
});
|
150
136
|
}
|
151
137
|
//# sourceMappingURL=editor.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"editor.js","sourceRoot":"","sources":["../../src/routes/editor.ts"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"editor.js","sourceRoot":"","sources":["../../src/routes/editor.ts"],"names":[],"mappings":"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"}
|
package/dist/routes/fs.d.ts.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../src/routes/fs.ts"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../src/routes/fs.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAwBrE,UAAU,eAAgB,SAAQ,oBAAoB;IACpD,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,cAAc,CAClC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,IAAI,CAAC,CA2Wf"}
|