@elysiajs/node
Version:
Elysia adapter to run Elysia on Node.js
243 lines (241 loc) • 7.97 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/ws.ts
var ws_exports = {};
__export(ws_exports, {
createWebSocketAdapter: () => createWebSocketAdapter
});
module.exports = __toCommonJS(ws_exports);
var import_crossws = require("crossws");
var import_elysia = require("elysia");
var import_utils = require("elysia/adapter/utils");
var import_utils2 = require("elysia/utils");
var import_ws = require("elysia/ws");
function createWebSocketAdapter() {
const store = {};
function handler(app, path, options) {
const { parse, body, response, ...rest } = options;
const validateMessage = (0, import_elysia.getSchemaValidator)(body, {
// @ts-expect-error private property
modules: app.definitions.typebox,
// @ts-expect-error private property
models: app.definitions.type,
normalize: app.config.normalize
});
const validateResponse = (0, import_elysia.getSchemaValidator)(response, {
// @ts-expect-error private property
modules: app.definitions.typebox,
// @ts-expect-error private property
models: app.definitions.type,
normalize: app.config.normalize
});
const toServerWebSocket = (peer, context) => {
const ws = peer;
ws.data = context;
ws.sendText = ws.send;
ws.sendBinary = ws.send;
ws.publishText = ws.publish;
ws.publishBinary = ws.publish;
ws.isSubscribed = (topic) => peer.topics.has(topic);
ws.cork = () => {
console.log("ws.cork is not supported yet");
};
return ws;
};
app.route(
"WS",
path,
// @ts-ignore
async (context) => {
const { set, path: path2, qi, headers, query, params } = context;
const id = context.request.wsId;
context.validator = validateResponse;
if (options.upgrade) {
if (typeof options.upgrade === "function") {
const temp = options.upgrade(context);
if (temp instanceof Promise) await temp;
} else if (options.upgrade)
Object.assign(
set.headers,
options.upgrade
);
}
if (set.cookie && (0, import_utils2.isNotEmpty)(set.cookie)) {
const cookie = (0, import_elysia.serializeCookie)(set.cookie);
if (cookie) set.headers["set-cookie"] = cookie;
}
if (set.headers["set-cookie"] && Array.isArray(set.headers["set-cookie"]))
set.headers = (0, import_utils.parseSetCookies)(
new Headers(set.headers),
set.headers["set-cookie"]
);
const handleResponse = (0, import_ws.createHandleWSResponse)(validateResponse);
const parseMessage = parse ? (0, import_ws.createWSMessageParser)(parse) : void 0;
if (typeof options.beforeHandle === "function") {
const result = options.beforeHandle(context);
if (result instanceof Promise) await result;
}
const errorHandlers = [
...options.error ? Array.isArray(options.error) ? options.error : [options.error] : [],
...(app.event.error ?? []).map(
(x) => typeof x === "function" ? x : x.fn
)
].filter((x) => x);
const handleErrors = errorHandlers.length ? async (ws, error) => {
for (const handleError of errorHandlers) {
let response2 = handleError(
Object.assign(context, { error })
);
if (response2 instanceof Promise)
response2 = await response2;
await handleResponse(ws, response2);
if (response2) break;
}
} : void 0;
store[id] = {
data: context,
validateResponse,
ping(ws, data) {
return options.ping?.(ws, data);
},
pong(ws, data) {
return options.pong?.(ws, data);
},
async open(_ws) {
const ws = toServerWebSocket(_ws, context);
try {
await handleResponse(
ws,
options.open?.(new import_ws.ElysiaWS(ws, context))
);
} catch (error) {
handleErrors?.(ws, error);
}
},
async message(ws, message) {
if (message.includes("ping")) {
try {
return void ws.pong(message);
} catch (error) {
handleErrors?.(ws, error);
}
}
if (parseMessage)
message = await parseMessage(ws, message);
if (message) {
if (validateMessage?.Check(message) === false)
return void ws.send(
new import_elysia.ValidationError(
"message",
validateMessage,
message
).message
);
}
try {
await handleResponse(
ws,
options.message?.(
new import_ws.ElysiaWS(ws, context, message),
message
)
);
} catch (error) {
handleErrors?.(ws, error);
}
},
async drain(ws) {
try {
await handleResponse(
ws,
options.drain?.(
new import_ws.ElysiaWS(ws, context)
)
);
} catch (error) {
handleErrors?.(ws, error);
}
},
async close(ws, code, reason) {
try {
await handleResponse(
ws,
options.close?.(
new import_ws.ElysiaWS(ws, context),
code,
reason
)
);
} catch (error) {
handleErrors?.(ws, error);
}
},
error(ws, error) {
handleErrors?.(ws, error);
}
};
return "";
},
{
...rest,
websocket: options
}
);
}
function createConfig(app) {
return (0, import_crossws.defineHooks)({
async upgrade(request) {
const id = request.wsId = (0, import_utils2.randomId)();
const response = await app.handle(request);
const context = store[id];
if (!context) return response;
return {
context,
headers: context.data.set.headers
};
},
open(ws) {
const context = ws.context;
context.open(ws);
},
message(ws, message) {
const context = ws.context;
context.message(ws, message.text());
},
close(ws, detail) {
const context = ws.context;
context.close(
// ws is parsed in context.open
ws,
detail.code,
detail.reason
);
},
error(ws, error) {
const context = ws.context;
context.error?.(ws, error);
}
});
}
return { handler, createConfig, context: store };
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
createWebSocketAdapter
});