@fluxstack/live-elysia 0.1.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.d.ts +11 -0
- package/dist/index.js +97 -0
- package/dist/index.js.map +1 -0
- package/package.json +42 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Elysia } from 'elysia';
|
|
2
|
+
import { LiveTransport, WebSocketConfig, HttpRouteDefinition } from '@fluxstack/live';
|
|
3
|
+
|
|
4
|
+
declare class ElysiaTransport implements LiveTransport {
|
|
5
|
+
private app;
|
|
6
|
+
constructor(app: Elysia<any>);
|
|
7
|
+
registerWebSocket(config: WebSocketConfig): void;
|
|
8
|
+
registerHttpRoutes(routes: HttpRouteDefinition[]): void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export { ElysiaTransport, ElysiaTransport as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
var ElysiaTransport = class {
|
|
3
|
+
app;
|
|
4
|
+
constructor(app) {
|
|
5
|
+
this.app = app;
|
|
6
|
+
}
|
|
7
|
+
registerWebSocket(config) {
|
|
8
|
+
this.app.ws(config.path, {
|
|
9
|
+
open(elysiaWs) {
|
|
10
|
+
const ws = wrapElysiaWs(elysiaWs);
|
|
11
|
+
config.onOpen(ws);
|
|
12
|
+
},
|
|
13
|
+
message(elysiaWs, rawMessage) {
|
|
14
|
+
const ws = wrapElysiaWs(elysiaWs);
|
|
15
|
+
const isBinary = rawMessage instanceof ArrayBuffer || rawMessage instanceof Uint8Array;
|
|
16
|
+
const message = !isBinary && typeof rawMessage === "object" && rawMessage !== null && !(rawMessage instanceof ArrayBuffer) && !(rawMessage instanceof Uint8Array) ? JSON.stringify(rawMessage) : rawMessage;
|
|
17
|
+
config.onMessage(ws, message, isBinary);
|
|
18
|
+
},
|
|
19
|
+
close(elysiaWs, code, reason) {
|
|
20
|
+
const ws = wrapElysiaWs(elysiaWs);
|
|
21
|
+
config.onClose(ws, code ?? 1e3, reason ?? "");
|
|
22
|
+
},
|
|
23
|
+
// @ts-ignore - Elysia's error handler signature varies between versions
|
|
24
|
+
error(elysiaWs, error) {
|
|
25
|
+
if (config.onError) {
|
|
26
|
+
const ws = wrapElysiaWs(elysiaWs);
|
|
27
|
+
config.onError(ws, error instanceof Error ? error : new Error(String(error)));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
registerHttpRoutes(routes) {
|
|
33
|
+
for (const route of routes) {
|
|
34
|
+
const handler = async (ctx) => {
|
|
35
|
+
const request = {
|
|
36
|
+
params: ctx.params || {},
|
|
37
|
+
query: ctx.query || {},
|
|
38
|
+
body: ctx.body,
|
|
39
|
+
headers: ctx.headers || {}
|
|
40
|
+
};
|
|
41
|
+
const response = await route.handler(request);
|
|
42
|
+
ctx.set.status = response.status ?? 200;
|
|
43
|
+
if (response.headers) {
|
|
44
|
+
for (const [key, value] of Object.entries(response.headers)) {
|
|
45
|
+
ctx.set.headers[key] = value;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return response.body;
|
|
49
|
+
};
|
|
50
|
+
switch (route.method) {
|
|
51
|
+
case "GET":
|
|
52
|
+
this.app.get(route.path, handler);
|
|
53
|
+
break;
|
|
54
|
+
case "POST":
|
|
55
|
+
this.app.post(route.path, handler);
|
|
56
|
+
break;
|
|
57
|
+
case "PUT":
|
|
58
|
+
this.app.put(route.path, handler);
|
|
59
|
+
break;
|
|
60
|
+
case "DELETE":
|
|
61
|
+
this.app.delete(route.path, handler);
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
function wrapElysiaWs(elysiaWs) {
|
|
68
|
+
const raw = elysiaWs.raw || elysiaWs;
|
|
69
|
+
if (raw.__liveWs) return raw.__liveWs;
|
|
70
|
+
const ws = {
|
|
71
|
+
send(data, compress) {
|
|
72
|
+
return raw.send(data, compress);
|
|
73
|
+
},
|
|
74
|
+
close(code, reason) {
|
|
75
|
+
raw.close(code, reason);
|
|
76
|
+
},
|
|
77
|
+
get data() {
|
|
78
|
+
return raw.__liveData;
|
|
79
|
+
},
|
|
80
|
+
set data(value) {
|
|
81
|
+
raw.__liveData = value;
|
|
82
|
+
},
|
|
83
|
+
get remoteAddress() {
|
|
84
|
+
return raw.remoteAddress || "";
|
|
85
|
+
},
|
|
86
|
+
get readyState() {
|
|
87
|
+
return raw.readyState;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
raw.__liveWs = ws;
|
|
91
|
+
return ws;
|
|
92
|
+
}
|
|
93
|
+
export {
|
|
94
|
+
ElysiaTransport,
|
|
95
|
+
ElysiaTransport as default
|
|
96
|
+
};
|
|
97
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// @fluxstack/live-elysia - Elysia Transport Adapter\r\n//\r\n// Bridges @fluxstack/live with Elysia's WebSocket and HTTP routing.\r\n//\r\n// Usage:\r\n// import Elysia from 'elysia'\r\n// import { LiveServer } from '@fluxstack/live'\r\n// import { ElysiaTransport } from '@fluxstack/live-elysia'\r\n//\r\n// const app = new Elysia()\r\n// const liveServer = new LiveServer({ transport: new ElysiaTransport(app) })\r\n// await liveServer.start()\r\n// app.listen(3000)\r\n\r\nimport type { Elysia } from 'elysia'\r\nimport type {\r\n LiveTransport,\r\n WebSocketConfig,\r\n HttpRouteDefinition,\r\n GenericWebSocket,\r\n LiveWSData,\r\n} from '@fluxstack/live'\r\n\r\nexport class ElysiaTransport implements LiveTransport {\r\n private app: Elysia<any>\r\n\r\n constructor(app: Elysia<any>) {\r\n this.app = app\r\n }\r\n\r\n registerWebSocket(config: WebSocketConfig): void {\r\n this.app.ws(config.path, {\r\n open(elysiaWs: any) {\r\n // Wrap Elysia WS into GenericWebSocket\r\n const ws = wrapElysiaWs(elysiaWs)\r\n config.onOpen(ws)\r\n },\r\n message(elysiaWs: any, rawMessage: unknown) {\r\n const ws = wrapElysiaWs(elysiaWs)\r\n const isBinary = rawMessage instanceof ArrayBuffer || rawMessage instanceof Uint8Array\r\n // Elysia auto-parses JSON messages into objects. LiveServer expects\r\n // raw strings, so re-stringify if needed.\r\n const message = (!isBinary && typeof rawMessage === 'object' && rawMessage !== null && !(rawMessage instanceof ArrayBuffer) && !(rawMessage instanceof Uint8Array))\r\n ? JSON.stringify(rawMessage)\r\n : rawMessage\r\n config.onMessage(ws, message, isBinary)\r\n },\r\n close(elysiaWs: any, code?: number, reason?: string) {\r\n const ws = wrapElysiaWs(elysiaWs)\r\n config.onClose(ws, code ?? 1000, reason ?? '')\r\n },\r\n // @ts-ignore - Elysia's error handler signature varies between versions\r\n error(elysiaWs: any, error: any) {\r\n if (config.onError) {\r\n const ws = wrapElysiaWs(elysiaWs)\r\n config.onError(ws, error instanceof Error ? error : new Error(String(error)))\r\n }\r\n },\r\n })\r\n }\r\n\r\n registerHttpRoutes(routes: HttpRouteDefinition[]): void {\r\n for (const route of routes) {\r\n const handler = async (ctx: any) => {\r\n const request = {\r\n params: ctx.params || {},\r\n query: ctx.query || {},\r\n body: ctx.body,\r\n headers: ctx.headers || {},\r\n }\r\n\r\n const response = await route.handler(request)\r\n ctx.set.status = response.status ?? 200\r\n if (response.headers) {\r\n for (const [key, value] of Object.entries(response.headers)) {\r\n ctx.set.headers[key] = value\r\n }\r\n }\r\n return response.body\r\n }\r\n\r\n switch (route.method) {\r\n case 'GET':\r\n this.app.get(route.path, handler)\r\n break\r\n case 'POST':\r\n this.app.post(route.path, handler)\r\n break\r\n case 'PUT':\r\n this.app.put(route.path, handler)\r\n break\r\n case 'DELETE':\r\n this.app.delete(route.path, handler)\r\n break\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Wrap Elysia's ServerWebSocket into a GenericWebSocket.\r\n *\r\n * Elysia stores its route context on `raw.data` (the Bun ServerWebSocket's data slot).\r\n * We must NOT overwrite it. Instead, LiveWSData is stored on a separate `__liveData`\r\n * property on the raw WS object.\r\n */\r\nfunction wrapElysiaWs(elysiaWs: any): GenericWebSocket {\r\n // Elysia wraps the raw Bun ServerWebSocket. Access the raw ws:\r\n const raw = elysiaWs.raw || elysiaWs\r\n\r\n // Reuse existing wrapper if already created (stored on the raw ws)\r\n if (raw.__liveWs) return raw.__liveWs\r\n\r\n const ws: GenericWebSocket = {\r\n send(data: string | ArrayBuffer | Uint8Array, compress?: boolean) {\r\n return raw.send(data, compress)\r\n },\r\n close(code?: number, reason?: string) {\r\n raw.close(code, reason)\r\n },\r\n get data(): LiveWSData {\r\n return raw.__liveData as LiveWSData\r\n },\r\n set data(value: LiveWSData) {\r\n raw.__liveData = value\r\n },\r\n get remoteAddress(): string {\r\n return raw.remoteAddress || ''\r\n },\r\n get readyState(): 0 | 1 | 2 | 3 {\r\n return raw.readyState\r\n }\r\n }\r\n\r\n raw.__liveWs = ws\r\n return ws\r\n}\r\n\r\nexport { ElysiaTransport as default }\r\n"],"mappings":";AAuBO,IAAM,kBAAN,MAA+C;AAAA,EAC5C;AAAA,EAER,YAAY,KAAkB;AAC5B,SAAK,MAAM;AAAA,EACb;AAAA,EAEA,kBAAkB,QAA+B;AAC/C,SAAK,IAAI,GAAG,OAAO,MAAM;AAAA,MACvB,KAAK,UAAe;AAElB,cAAM,KAAK,aAAa,QAAQ;AAChC,eAAO,OAAO,EAAE;AAAA,MAClB;AAAA,MACA,QAAQ,UAAe,YAAqB;AAC1C,cAAM,KAAK,aAAa,QAAQ;AAChC,cAAM,WAAW,sBAAsB,eAAe,sBAAsB;AAG5E,cAAM,UAAW,CAAC,YAAY,OAAO,eAAe,YAAY,eAAe,QAAQ,EAAE,sBAAsB,gBAAgB,EAAE,sBAAsB,cACnJ,KAAK,UAAU,UAAU,IACzB;AACJ,eAAO,UAAU,IAAI,SAAS,QAAQ;AAAA,MACxC;AAAA,MACA,MAAM,UAAe,MAAe,QAAiB;AACnD,cAAM,KAAK,aAAa,QAAQ;AAChC,eAAO,QAAQ,IAAI,QAAQ,KAAM,UAAU,EAAE;AAAA,MAC/C;AAAA;AAAA,MAEA,MAAM,UAAe,OAAY;AAC/B,YAAI,OAAO,SAAS;AAClB,gBAAM,KAAK,aAAa,QAAQ;AAChC,iBAAO,QAAQ,IAAI,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,QAC9E;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,mBAAmB,QAAqC;AACtD,eAAW,SAAS,QAAQ;AAC1B,YAAM,UAAU,OAAO,QAAa;AAClC,cAAM,UAAU;AAAA,UACd,QAAQ,IAAI,UAAU,CAAC;AAAA,UACvB,OAAO,IAAI,SAAS,CAAC;AAAA,UACrB,MAAM,IAAI;AAAA,UACV,SAAS,IAAI,WAAW,CAAC;AAAA,QAC3B;AAEA,cAAM,WAAW,MAAM,MAAM,QAAQ,OAAO;AAC5C,YAAI,IAAI,SAAS,SAAS,UAAU;AACpC,YAAI,SAAS,SAAS;AACpB,qBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,SAAS,OAAO,GAAG;AAC3D,gBAAI,IAAI,QAAQ,GAAG,IAAI;AAAA,UACzB;AAAA,QACF;AACA,eAAO,SAAS;AAAA,MAClB;AAEA,cAAQ,MAAM,QAAQ;AAAA,QACpB,KAAK;AACH,eAAK,IAAI,IAAI,MAAM,MAAM,OAAO;AAChC;AAAA,QACF,KAAK;AACH,eAAK,IAAI,KAAK,MAAM,MAAM,OAAO;AACjC;AAAA,QACF,KAAK;AACH,eAAK,IAAI,IAAI,MAAM,MAAM,OAAO;AAChC;AAAA,QACF,KAAK;AACH,eAAK,IAAI,OAAO,MAAM,MAAM,OAAO;AACnC;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACF;AASA,SAAS,aAAa,UAAiC;AAErD,QAAM,MAAM,SAAS,OAAO;AAG5B,MAAI,IAAI,SAAU,QAAO,IAAI;AAE7B,QAAM,KAAuB;AAAA,IAC3B,KAAK,MAAyC,UAAoB;AAChE,aAAO,IAAI,KAAK,MAAM,QAAQ;AAAA,IAChC;AAAA,IACA,MAAM,MAAe,QAAiB;AACpC,UAAI,MAAM,MAAM,MAAM;AAAA,IACxB;AAAA,IACA,IAAI,OAAmB;AACrB,aAAO,IAAI;AAAA,IACb;AAAA,IACA,IAAI,KAAK,OAAmB;AAC1B,UAAI,aAAa;AAAA,IACnB;AAAA,IACA,IAAI,gBAAwB;AAC1B,aAAO,IAAI,iBAAiB;AAAA,IAC9B;AAAA,IACA,IAAI,aAA4B;AAC9B,aAAO,IAAI;AAAA,IACb;AAAA,EACF;AAEA,MAAI,WAAW;AACf,SAAO;AACT;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fluxstack/live-elysia",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Elysia transport adapter for @fluxstack/live",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": ["dist"],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsup",
|
|
18
|
+
"dev": "tsup --watch",
|
|
19
|
+
"clean": "rm -rf dist",
|
|
20
|
+
"typecheck": "tsc --noEmit"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@fluxstack/live": "^0.1.0"
|
|
24
|
+
},
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"elysia": ">=1.0.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"elysia": "^1.4.6",
|
|
30
|
+
"tsup": "^8.4.0",
|
|
31
|
+
"typescript": "^5.8.3"
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "https://github.com/FluxStackCore/fluxstack-live",
|
|
39
|
+
"directory": "packages/elysia"
|
|
40
|
+
},
|
|
41
|
+
"license": "MIT"
|
|
42
|
+
}
|