feat: Refactor server implementation to support Bun and Node environments
- Introduced `ServerNode` and `BunServer` classes to handle server logic for Node and Bun respectively. - Updated `App` class to initialize the appropriate server based on the runtime environment. - Enhanced `parseBody` function to handle request body parsing for both environments. - Modified WebSocket handling to support Bun's WebSocket upgrade mechanism. - Improved error handling and response structure across the server implementation. - Added support for custom middleware in the server's request handling. - Refactored server base functionality into `ServerBase` for better code organization. - Updated type definitions to reflect changes in server options and listener handling. - Added a new demo for testing the server functionality with various request types.
This commit is contained in:
@@ -13,7 +13,9 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
// const ws = new WebSocket('ws://localhost:4002/api/router');
|
// const ws = new WebSocket('ws://localhost:4002/api/router');
|
||||||
const ws = new WebSocket('ws://192.168.31.220:4002/api/router');
|
const ws = new WebSocket('ws://localhost:4002/api/router');
|
||||||
|
// const ws = new WebSocket('ws://localhost:4002/ws');
|
||||||
|
// const ws = new WebSocket('ws://192.168.31.220:4002/api/router');
|
||||||
|
|
||||||
// 当连接成功时
|
// 当连接成功时
|
||||||
ws.onopen = () => {
|
ws.onopen = () => {
|
||||||
@@ -24,12 +26,14 @@
|
|||||||
// ws.send(message);
|
// ws.send(message);
|
||||||
const message = JSON.stringify({
|
const message = JSON.stringify({
|
||||||
type: 'router',
|
type: 'router',
|
||||||
|
id: '123556',
|
||||||
data: {
|
data: {
|
||||||
path: 'demo',
|
path: 'demo',
|
||||||
key: '01',
|
key: '01',
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ws.send(message);
|
ws.send(message);
|
||||||
|
// ws.send(JSON.stringify('Hello Server!'));
|
||||||
};
|
};
|
||||||
|
|
||||||
// 接收服务器的消息
|
// 接收服务器的消息
|
||||||
@@ -68,6 +72,9 @@
|
|||||||
ws.onclose = () => {
|
ws.onclose = () => {
|
||||||
console.log('Disconnected from WebSocket server');
|
console.log('Disconnected from WebSocket server');
|
||||||
};
|
};
|
||||||
|
ws.onerror = (error) => {
|
||||||
|
console.error('WebSocket error:', error);
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Route, App } from '@kevisual/router';
|
import { Route, App } from '@kevisual/router/src/app.ts';
|
||||||
|
|
||||||
const app = new App({ io: true });
|
const app = new App({ serverOptions: { io: true } });
|
||||||
app.listen(4002);
|
app.listen(4002);
|
||||||
const route01 = new Route('demo', '01');
|
const route01 = new Route('demo', '01');
|
||||||
route01.run = async (ctx) => {
|
route01.run = async (ctx) => {
|
||||||
@@ -25,3 +25,14 @@ app.addRoute(route02);
|
|||||||
|
|
||||||
console.log(`http://localhost:4002/api/router?path=demo&key=02`);
|
console.log(`http://localhost:4002/api/router?path=demo&key=02`);
|
||||||
console.log(`http://localhost:4002/api/router?path=demo&key=01`);
|
console.log(`http://localhost:4002/api/router?path=demo&key=01`);
|
||||||
|
|
||||||
|
app.server.on({
|
||||||
|
id: 'abc',
|
||||||
|
path: '/ws',
|
||||||
|
io: true,
|
||||||
|
fun: async ({ data }, { end }) => {
|
||||||
|
console.log('Custom middleware for /ws');
|
||||||
|
console.log('Data received:', data);
|
||||||
|
end({ message: 'Hello from /ws middleware' });
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { SimpleRouter } from '@kevisual/router/simple';
|
import { SimpleRouter } from '@kevisual/router/src/router-simple.ts';
|
||||||
|
|
||||||
const router = new SimpleRouter();
|
export const router = new SimpleRouter();
|
||||||
|
|
||||||
router.get('/', async (req, res) => {
|
router.get('/', async (req, res) => {
|
||||||
console.log('get /');
|
console.log('get /');
|
||||||
@@ -8,21 +8,28 @@ router.get('/', async (req, res) => {
|
|||||||
|
|
||||||
router.post('/post', async (req, res) => {
|
router.post('/post', async (req, res) => {
|
||||||
console.log('post /post');
|
console.log('post /post');
|
||||||
|
console.log('req body:', req, res);
|
||||||
|
res.end('post response');
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/user/:id', async (req, res) => {
|
router.get('/user/:id', async (req, res) => {
|
||||||
console.log('get /user/:id', req.params);
|
console.log('get /user/:id', req.params);
|
||||||
|
res.end(`user id is ${req.params.id}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/user/:id', async (req, res) => {
|
router.post('/user/:id', async (req, res) => {
|
||||||
console.log('post /user/:id', req.params);
|
console.log('post /user/:id params', req.params);
|
||||||
|
const body = await router.getBody(req);
|
||||||
|
console.log('post body:', body);
|
||||||
|
res.end(`post user id is ${req.params.id}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/user/:id/a', async (req, res) => {
|
router.post('/user/:id/a', async (req, res) => {
|
||||||
console.log('post /user/:id', req.params);
|
console.log('post /user/:id', req.params);
|
||||||
|
res.end(`post user id is ${req.params.id} a`);
|
||||||
});
|
});
|
||||||
|
|
||||||
router.parse({ url: 'http://localhost:3000/', method: 'GET' } as any, {} as any);
|
// router.parse({ url: 'http://localhost:3000/', method: 'GET' } as any, {} as any);
|
||||||
router.parse({ url: 'http://localhost:3000/post', method: 'POST' } as any, {} as any);
|
// router.parse({ url: 'http://localhost:3000/post', method: 'POST' } as any, {} as any);
|
||||||
router.parse({ url: 'http://localhost:3000/user/1/a', method: 'GET' } as any, {} as any);
|
// router.parse({ url: 'http://localhost:3000/user/1/a', method: 'GET' } as any, {} as any);
|
||||||
router.parse({ url: 'http://localhost:3000/user/1/a', method: 'POST' } as any, {} as any);
|
// router.parse({ url: 'http://localhost:3000/user/1/a', method: 'POST' } as any, {} as any);
|
||||||
|
|||||||
56
demo/simple/src/simple-router/b.ts
Normal file
56
demo/simple/src/simple-router/b.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import { App } from '@kevisual/router/src/app.ts';
|
||||||
|
|
||||||
|
import { router } from './a.ts';
|
||||||
|
|
||||||
|
export const app = new App();
|
||||||
|
|
||||||
|
app.server.on([{
|
||||||
|
fun: async (req, res) => {
|
||||||
|
console.log('Received request:', req.method, req.url);
|
||||||
|
const p = await router.parse(req, res);
|
||||||
|
if (p) {
|
||||||
|
console.log('Router parse result:', p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: 'abc',
|
||||||
|
path: '/ws',
|
||||||
|
io: true,
|
||||||
|
fun: async (data, end) => {
|
||||||
|
console.log('Custom middleware for /ws');
|
||||||
|
console.log('Data received:', data);
|
||||||
|
end({ message: 'Hello from /ws middleware' });
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
app.server.listen(3004, () => {
|
||||||
|
console.log('Server is running on http://localhost:3004');
|
||||||
|
|
||||||
|
// fetch('http://localhost:3004/', { method: 'GET' }).then(async (res) => {
|
||||||
|
// const text = await res.text();
|
||||||
|
// console.log('Response for GET /:', text);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// fetch('http://localhost:3004/post', {
|
||||||
|
// method: 'POST',
|
||||||
|
// headers: { 'Content-Type': 'application/json' },
|
||||||
|
// body: JSON.stringify({ message: 'Hello, server!' }),
|
||||||
|
// }).then(async (res) => {
|
||||||
|
// const text = await res.text();
|
||||||
|
// console.log('Response for POST /post:', text);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// fetch('http://localhost:3004/user/123', { method: 'GET' }).then(async (res) => {
|
||||||
|
// const text = await res.text();
|
||||||
|
// console.log('Response for GET /user/123:', text);
|
||||||
|
// });
|
||||||
|
|
||||||
|
fetch('http://localhost:3004/user/456', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ name: 'User456' }),
|
||||||
|
}).then(async (res) => {
|
||||||
|
const text = await res.text();
|
||||||
|
console.log('Response for POST /user/456:', text);
|
||||||
|
});
|
||||||
|
});
|
||||||
25
package-lock.json
generated
25
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@kevisual/router",
|
"name": "@kevisual/router",
|
||||||
"version": "0.0.39",
|
"version": "0.0.41",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@kevisual/router",
|
"name": "@kevisual/router",
|
||||||
"version": "0.0.39",
|
"version": "0.0.41",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"path-to-regexp": "^8.3.0",
|
"path-to-regexp": "^8.3.0",
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
"@rollup/plugin-commonjs": "29.0.0",
|
"@rollup/plugin-commonjs": "29.0.0",
|
||||||
"@rollup/plugin-node-resolve": "^16.0.3",
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
||||||
"@rollup/plugin-typescript": "^12.3.0",
|
"@rollup/plugin-typescript": "^12.3.0",
|
||||||
|
"@types/bun": "^1.3.5",
|
||||||
"@types/node": "^25.0.3",
|
"@types/node": "^25.0.3",
|
||||||
"@types/send": "^1.2.1",
|
"@types/send": "^1.2.1",
|
||||||
"@types/ws": "^8.18.1",
|
"@types/ws": "^8.18.1",
|
||||||
@@ -729,6 +730,16 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/bun": {
|
||||||
|
"version": "1.3.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/bun/-/bun-1.3.5.tgz",
|
||||||
|
"integrity": "sha512-RnygCqNrd3srIPEWBd5LFeUYG7plCoH2Yw9WaZGyNmdTEei+gWaHqydbaIRkIkcbXwhBT94q78QljxN0Sk838w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"bun-types": "1.3.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/eslint": {
|
"node_modules/@types/eslint": {
|
||||||
"version": "9.6.1",
|
"version": "9.6.1",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@@ -1132,6 +1143,16 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
|
"node_modules/bun-types": {
|
||||||
|
"version": "1.3.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/bun-types/-/bun-types-1.3.5.tgz",
|
||||||
|
"integrity": "sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/bytestreamjs": {
|
"node_modules/bytestreamjs": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package",
|
"$schema": "https://json.schemastore.org/package",
|
||||||
"name": "@kevisual/router",
|
"name": "@kevisual/router",
|
||||||
"version": "0.0.41",
|
"version": "0.0.42",
|
||||||
"description": "",
|
"description": "",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/router.js",
|
"main": "./dist/router.js",
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "abearxiong",
|
"author": "abearxiong",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"packageManager": "pnpm@10.26.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@kevisual/local-proxy": "^0.0.8",
|
"@kevisual/local-proxy": "^0.0.8",
|
||||||
"@kevisual/query": "^0.0.32",
|
"@kevisual/query": "^0.0.32",
|
||||||
@@ -27,6 +28,7 @@
|
|||||||
"@rollup/plugin-commonjs": "29.0.0",
|
"@rollup/plugin-commonjs": "29.0.0",
|
||||||
"@rollup/plugin-node-resolve": "^16.0.3",
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
||||||
"@rollup/plugin-typescript": "^12.3.0",
|
"@rollup/plugin-typescript": "^12.3.0",
|
||||||
|
"@types/bun": "^1.3.5",
|
||||||
"@types/node": "^25.0.3",
|
"@types/node": "^25.0.3",
|
||||||
"@types/send": "^1.2.1",
|
"@types/send": "^1.2.1",
|
||||||
"@types/ws": "^8.18.1",
|
"@types/ws": "^8.18.1",
|
||||||
@@ -38,6 +40,7 @@
|
|||||||
"ts-loader": "^9.5.4",
|
"ts-loader": "^9.5.4",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
|
"tsx": "^4.21.0",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"ws": "npm:@kevisual/ws",
|
"ws": "npm:@kevisual/ws",
|
||||||
"xml2js": "^0.6.2",
|
"xml2js": "^0.6.2",
|
||||||
|
|||||||
507
pnpm-lock.yaml
generated
507
pnpm-lock.yaml
generated
@@ -15,15 +15,15 @@ importers:
|
|||||||
specifier: ^5.2.0
|
specifier: ^5.2.0
|
||||||
version: 5.2.0
|
version: 5.2.0
|
||||||
send:
|
send:
|
||||||
specifier: ^1.2.0
|
specifier: ^1.2.1
|
||||||
version: 1.2.0
|
version: 1.2.1
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@kevisual/local-proxy':
|
'@kevisual/local-proxy':
|
||||||
specifier: ^0.0.8
|
specifier: ^0.0.8
|
||||||
version: 0.0.8
|
version: 0.0.8
|
||||||
'@kevisual/query':
|
'@kevisual/query':
|
||||||
specifier: ^0.0.31
|
specifier: ^0.0.32
|
||||||
version: 0.0.31
|
version: 0.0.32
|
||||||
'@rollup/plugin-alias':
|
'@rollup/plugin-alias':
|
||||||
specifier: ^6.0.0
|
specifier: ^6.0.0
|
||||||
version: 6.0.0(rollup@4.53.5)
|
version: 6.0.0(rollup@4.53.5)
|
||||||
@@ -36,12 +36,12 @@ importers:
|
|||||||
'@rollup/plugin-typescript':
|
'@rollup/plugin-typescript':
|
||||||
specifier: ^12.3.0
|
specifier: ^12.3.0
|
||||||
version: 12.3.0(rollup@4.53.5)(tslib@2.8.1)(typescript@5.9.3)
|
version: 12.3.0(rollup@4.53.5)(tslib@2.8.1)(typescript@5.9.3)
|
||||||
'@types/lodash-es':
|
'@types/bun':
|
||||||
specifier: ^4.17.12
|
specifier: ^1.3.5
|
||||||
version: 4.17.12
|
version: 1.3.5
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^24.10.2
|
specifier: ^25.0.3
|
||||||
version: 24.10.4
|
version: 25.0.3
|
||||||
'@types/send':
|
'@types/send':
|
||||||
specifier: ^1.2.1
|
specifier: ^1.2.1
|
||||||
version: 1.2.1
|
version: 1.2.1
|
||||||
@@ -54,27 +54,27 @@ importers:
|
|||||||
cookie:
|
cookie:
|
||||||
specifier: ^1.1.1
|
specifier: ^1.1.1
|
||||||
version: 1.1.1
|
version: 1.1.1
|
||||||
lodash-es:
|
|
||||||
specifier: ^4.17.21
|
|
||||||
version: 4.17.21
|
|
||||||
nanoid:
|
nanoid:
|
||||||
specifier: ^5.1.6
|
specifier: ^5.1.6
|
||||||
version: 5.1.6
|
version: 5.1.6
|
||||||
rollup:
|
rollup:
|
||||||
specifier: ^4.53.3
|
specifier: ^4.53.5
|
||||||
version: 4.53.5
|
version: 4.53.5
|
||||||
rollup-plugin-dts:
|
rollup-plugin-dts:
|
||||||
specifier: ^6.3.0
|
specifier: ^6.3.0
|
||||||
version: 6.3.0(rollup@4.53.5)(typescript@5.9.3)
|
version: 6.3.0(rollup@4.53.5)(typescript@5.9.3)
|
||||||
ts-loader:
|
ts-loader:
|
||||||
specifier: ^9.5.4
|
specifier: ^9.5.4
|
||||||
version: 9.5.4(typescript@5.9.3)(webpack@5.102.1)
|
version: 9.5.4(typescript@5.9.3)(webpack@5.104.1)
|
||||||
ts-node:
|
ts-node:
|
||||||
specifier: ^10.9.2
|
specifier: ^10.9.2
|
||||||
version: 10.9.2(@types/node@24.10.4)(typescript@5.9.3)
|
version: 10.9.2(@types/node@25.0.3)(typescript@5.9.3)
|
||||||
tslib:
|
tslib:
|
||||||
specifier: ^2.8.1
|
specifier: ^2.8.1
|
||||||
version: 2.8.1
|
version: 2.8.1
|
||||||
|
tsx:
|
||||||
|
specifier: ^4.21.0
|
||||||
|
version: 4.21.0
|
||||||
typescript:
|
typescript:
|
||||||
specifier: ^5.9.3
|
specifier: ^5.9.3
|
||||||
version: 5.9.3
|
version: 5.9.3
|
||||||
@@ -85,9 +85,25 @@ importers:
|
|||||||
specifier: ^0.6.2
|
specifier: ^0.6.2
|
||||||
version: 0.6.2
|
version: 0.6.2
|
||||||
zod:
|
zod:
|
||||||
specifier: ^4.1.13
|
specifier: ^4.2.1
|
||||||
version: 4.2.1
|
version: 4.2.1
|
||||||
|
|
||||||
|
demo/simple:
|
||||||
|
dependencies:
|
||||||
|
'@kevisual/router':
|
||||||
|
specifier: ../..
|
||||||
|
version: link:../..
|
||||||
|
devDependencies:
|
||||||
|
cookie:
|
||||||
|
specifier: ^1.0.2
|
||||||
|
version: 1.1.1
|
||||||
|
ts-node:
|
||||||
|
specifier: ^10.9.2
|
||||||
|
version: 10.9.2(@types/node@25.0.3)(typescript@5.9.3)
|
||||||
|
typescript:
|
||||||
|
specifier: ^5.5.4
|
||||||
|
version: 5.9.3
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
'@babel/code-frame@7.27.1':
|
'@babel/code-frame@7.27.1':
|
||||||
@@ -102,6 +118,162 @@ packages:
|
|||||||
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
|
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
|
'@esbuild/aix-ppc64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [aix]
|
||||||
|
|
||||||
|
'@esbuild/android-arm64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@esbuild/android-arm@0.27.2':
|
||||||
|
resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@esbuild/android-x64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@esbuild/darwin-arm64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@esbuild/darwin-x64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@esbuild/freebsd-arm64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@esbuild/freebsd-x64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@esbuild/linux-arm64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-arm@0.27.2':
|
||||||
|
resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-ia32@0.27.2':
|
||||||
|
resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-loong64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [loong64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-mips64el@0.27.2':
|
||||||
|
resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [mips64el]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-ppc64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-riscv64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [riscv64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-s390x@0.27.2':
|
||||||
|
resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [s390x]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-x64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/netbsd-arm64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [netbsd]
|
||||||
|
|
||||||
|
'@esbuild/netbsd-x64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [netbsd]
|
||||||
|
|
||||||
|
'@esbuild/openbsd-arm64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [openbsd]
|
||||||
|
|
||||||
|
'@esbuild/openbsd-x64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [openbsd]
|
||||||
|
|
||||||
|
'@esbuild/openharmony-arm64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [openharmony]
|
||||||
|
|
||||||
|
'@esbuild/sunos-x64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [sunos]
|
||||||
|
|
||||||
|
'@esbuild/win32-arm64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@esbuild/win32-ia32@0.27.2':
|
||||||
|
resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@esbuild/win32-x64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
'@jridgewell/gen-mapping@0.3.13':
|
'@jridgewell/gen-mapping@0.3.13':
|
||||||
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
|
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
|
||||||
|
|
||||||
@@ -124,8 +296,8 @@ packages:
|
|||||||
'@kevisual/local-proxy@0.0.8':
|
'@kevisual/local-proxy@0.0.8':
|
||||||
resolution: {integrity: sha512-VX/P+6/Cc8ruqp34ag6gVX073BchUmf5VNZcTV/6MJtjrNE76G8V6TLpBE8bywLnrqyRtFLIspk4QlH8up9B5Q==}
|
resolution: {integrity: sha512-VX/P+6/Cc8ruqp34ag6gVX073BchUmf5VNZcTV/6MJtjrNE76G8V6TLpBE8bywLnrqyRtFLIspk4QlH8up9B5Q==}
|
||||||
|
|
||||||
'@kevisual/query@0.0.31':
|
'@kevisual/query@0.0.32':
|
||||||
resolution: {integrity: sha512-bBdepjmMICLpcj/a9fnn82/0CGGYUZiCV+usWsJZKAwVlZcnj+WtKmbgKT09KpP6g3jjYzYOaXHiNFB8N0bQAQ==}
|
resolution: {integrity: sha512-9WN9cjmwSW8I5A0SqITdts9oxlLBGdPP7kJ8vwrxkaQteHS9FzxKuMBJxZzGKZdyte/zJDvdrE+lMf254BGbbg==}
|
||||||
|
|
||||||
'@kevisual/ws@8.0.0':
|
'@kevisual/ws@8.0.0':
|
||||||
resolution: {integrity: sha512-jlFxSlXUEz93cFW+UYT5BXv/rFVgiMQnIfqRYZ0gj1hSP8PMGRqMqUoHSLfKvfRRS4jseLSvTTeEKSQpZJtURg==}
|
resolution: {integrity: sha512-jlFxSlXUEz93cFW+UYT5BXv/rFVgiMQnIfqRYZ0gj1hSP8PMGRqMqUoHSLfKvfRRS4jseLSvTTeEKSQpZJtURg==}
|
||||||
@@ -340,6 +512,9 @@ packages:
|
|||||||
'@tsconfig/node16@1.0.4':
|
'@tsconfig/node16@1.0.4':
|
||||||
resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==}
|
resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==}
|
||||||
|
|
||||||
|
'@types/bun@1.3.5':
|
||||||
|
resolution: {integrity: sha512-RnygCqNrd3srIPEWBd5LFeUYG7plCoH2Yw9WaZGyNmdTEei+gWaHqydbaIRkIkcbXwhBT94q78QljxN0Sk838w==}
|
||||||
|
|
||||||
'@types/eslint-scope@3.7.7':
|
'@types/eslint-scope@3.7.7':
|
||||||
resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==}
|
resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==}
|
||||||
|
|
||||||
@@ -352,14 +527,8 @@ packages:
|
|||||||
'@types/json-schema@7.0.15':
|
'@types/json-schema@7.0.15':
|
||||||
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
||||||
|
|
||||||
'@types/lodash-es@4.17.12':
|
'@types/node@25.0.3':
|
||||||
resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==}
|
resolution: {integrity: sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==}
|
||||||
|
|
||||||
'@types/lodash@4.17.20':
|
|
||||||
resolution: {integrity: sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==}
|
|
||||||
|
|
||||||
'@types/node@24.10.4':
|
|
||||||
resolution: {integrity: sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg==}
|
|
||||||
|
|
||||||
'@types/resolve@1.20.2':
|
'@types/resolve@1.20.2':
|
||||||
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
|
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
|
||||||
@@ -466,28 +635,31 @@ packages:
|
|||||||
resolution: {integrity: sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==}
|
resolution: {integrity: sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
|
|
||||||
baseline-browser-mapping@2.8.28:
|
baseline-browser-mapping@2.9.11:
|
||||||
resolution: {integrity: sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ==}
|
resolution: {integrity: sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
braces@3.0.3:
|
braces@3.0.3:
|
||||||
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
browserslist@4.28.0:
|
browserslist@4.28.1:
|
||||||
resolution: {integrity: sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==}
|
resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==}
|
||||||
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
buffer-from@1.1.2:
|
buffer-from@1.1.2:
|
||||||
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
|
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
|
||||||
|
|
||||||
|
bun-types@1.3.5:
|
||||||
|
resolution: {integrity: sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw==}
|
||||||
|
|
||||||
bytestreamjs@2.0.1:
|
bytestreamjs@2.0.1:
|
||||||
resolution: {integrity: sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ==}
|
resolution: {integrity: sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
|
|
||||||
caniuse-lite@1.0.30001754:
|
caniuse-lite@1.0.30001761:
|
||||||
resolution: {integrity: sha512-x6OeBXueoAceOmotzx3PO4Zpt4rzpeIFsSr6AAePTZxSkXiYDUmpypEl7e2+8NCd9bD7bXjqyef8CJYPC1jfxg==}
|
resolution: {integrity: sha512-JF9ptu1vP2coz98+5051jZ4PwQgd2ni8A+gYSN7EA7dPKIMf0pDlSUxhdmVOaV3/fYK5uWBkgSXJaRLr4+3A6g==}
|
||||||
|
|
||||||
chalk@4.1.2:
|
chalk@4.1.2:
|
||||||
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
|
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
|
||||||
@@ -541,19 +713,24 @@ packages:
|
|||||||
ee-first@1.1.1:
|
ee-first@1.1.1:
|
||||||
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
|
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
|
||||||
|
|
||||||
electron-to-chromium@1.5.252:
|
electron-to-chromium@1.5.267:
|
||||||
resolution: {integrity: sha512-53uTpjtRgS7gjIxZ4qCgFdNO2q+wJt/Z8+xAvxbCqXPJrY6h7ighUkadQmNMXH96crtpa6gPFNP7BF4UBGDuaA==}
|
resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==}
|
||||||
|
|
||||||
encodeurl@2.0.0:
|
encodeurl@2.0.0:
|
||||||
resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
|
resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
enhanced-resolve@5.18.3:
|
enhanced-resolve@5.18.4:
|
||||||
resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==}
|
resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==}
|
||||||
engines: {node: '>=10.13.0'}
|
engines: {node: '>=10.13.0'}
|
||||||
|
|
||||||
es-module-lexer@1.7.0:
|
es-module-lexer@2.0.0:
|
||||||
resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==}
|
resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==}
|
||||||
|
|
||||||
|
esbuild@0.27.2:
|
||||||
|
resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
escalade@3.2.0:
|
escalade@3.2.0:
|
||||||
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
|
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
|
||||||
@@ -620,6 +797,9 @@ packages:
|
|||||||
function-bind@1.1.2:
|
function-bind@1.1.2:
|
||||||
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
|
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
|
||||||
|
|
||||||
|
get-tsconfig@4.13.0:
|
||||||
|
resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==}
|
||||||
|
|
||||||
glob-to-regexp@0.4.1:
|
glob-to-regexp@0.4.1:
|
||||||
resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==}
|
resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==}
|
||||||
|
|
||||||
@@ -634,8 +814,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
http-errors@2.0.0:
|
http-errors@2.0.1:
|
||||||
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
|
resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
inherits@2.0.4:
|
inherits@2.0.4:
|
||||||
@@ -672,9 +852,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==}
|
resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==}
|
||||||
engines: {node: '>=6.11.5'}
|
engines: {node: '>=6.11.5'}
|
||||||
|
|
||||||
lodash-es@4.17.21:
|
|
||||||
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
|
|
||||||
|
|
||||||
magic-string@0.30.21:
|
magic-string@0.30.21:
|
||||||
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
|
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
|
||||||
|
|
||||||
@@ -700,9 +877,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
|
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
mime-types@3.0.1:
|
mime-types@3.0.2:
|
||||||
resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==}
|
resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
ms@2.1.3:
|
ms@2.1.3:
|
||||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||||
@@ -764,6 +941,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
|
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
resolve-pkg-maps@1.0.0:
|
||||||
|
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
|
||||||
|
|
||||||
resolve@1.22.11:
|
resolve@1.22.11:
|
||||||
resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==}
|
resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -800,8 +980,8 @@ packages:
|
|||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
send@1.2.0:
|
send@1.2.1:
|
||||||
resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==}
|
resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==}
|
||||||
engines: {node: '>= 18'}
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
serialize-javascript@6.0.2:
|
serialize-javascript@6.0.2:
|
||||||
@@ -821,10 +1001,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==}
|
resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==}
|
||||||
engines: {node: '>= 12'}
|
engines: {node: '>= 12'}
|
||||||
|
|
||||||
statuses@2.0.1:
|
|
||||||
resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
|
|
||||||
engines: {node: '>= 0.8'}
|
|
||||||
|
|
||||||
statuses@2.0.2:
|
statuses@2.0.2:
|
||||||
resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
|
resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
@@ -845,8 +1021,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==}
|
resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
terser-webpack-plugin@5.3.14:
|
terser-webpack-plugin@5.3.16:
|
||||||
resolution: {integrity: sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==}
|
resolution: {integrity: sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==}
|
||||||
engines: {node: '>= 10.13.0'}
|
engines: {node: '>= 10.13.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@swc/core': '*'
|
'@swc/core': '*'
|
||||||
@@ -901,6 +1077,11 @@ packages:
|
|||||||
tslib@2.8.1:
|
tslib@2.8.1:
|
||||||
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
||||||
|
|
||||||
|
tsx@4.21.0:
|
||||||
|
resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==}
|
||||||
|
engines: {node: '>=18.0.0'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
tsyringe@4.10.0:
|
tsyringe@4.10.0:
|
||||||
resolution: {integrity: sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==}
|
resolution: {integrity: sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==}
|
||||||
engines: {node: '>= 6.0.0'}
|
engines: {node: '>= 6.0.0'}
|
||||||
@@ -913,8 +1094,8 @@ packages:
|
|||||||
undici-types@7.16.0:
|
undici-types@7.16.0:
|
||||||
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
|
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
|
||||||
|
|
||||||
update-browserslist-db@1.1.4:
|
update-browserslist-db@1.2.3:
|
||||||
resolution: {integrity: sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==}
|
resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
browserslist: '>= 4.21.0'
|
browserslist: '>= 4.21.0'
|
||||||
@@ -930,8 +1111,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==}
|
resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==}
|
||||||
engines: {node: '>=10.13.0'}
|
engines: {node: '>=10.13.0'}
|
||||||
|
|
||||||
webpack@5.102.1:
|
webpack@5.104.1:
|
||||||
resolution: {integrity: sha512-7h/weGm9d/ywQ6qzJ+Xy+r9n/3qgp/thalBbpOi5i223dPXKi04IBtqPN9nTd+jBc7QKfvDbaBnFipYp4sJAUQ==}
|
resolution: {integrity: sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==}
|
||||||
engines: {node: '>=10.13.0'}
|
engines: {node: '>=10.13.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -971,6 +1152,84 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/trace-mapping': 0.3.9
|
'@jridgewell/trace-mapping': 0.3.9
|
||||||
|
|
||||||
|
'@esbuild/aix-ppc64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/android-arm64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/android-arm@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/android-x64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/darwin-arm64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/darwin-x64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/freebsd-arm64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/freebsd-x64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-arm64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-arm@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-ia32@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-loong64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-mips64el@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-ppc64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-riscv64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-s390x@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-x64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/netbsd-arm64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/netbsd-x64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/openbsd-arm64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/openbsd-x64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/openharmony-arm64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/sunos-x64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/win32-arm64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/win32-ia32@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/win32-x64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@jridgewell/gen-mapping@0.3.13':
|
'@jridgewell/gen-mapping@0.3.13':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/sourcemap-codec': 1.5.5
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
@@ -997,7 +1256,7 @@ snapshots:
|
|||||||
|
|
||||||
'@kevisual/local-proxy@0.0.8': {}
|
'@kevisual/local-proxy@0.0.8': {}
|
||||||
|
|
||||||
'@kevisual/query@0.0.31': {}
|
'@kevisual/query@0.0.32': {}
|
||||||
|
|
||||||
'@kevisual/ws@8.0.0': {}
|
'@kevisual/ws@8.0.0': {}
|
||||||
|
|
||||||
@@ -1210,6 +1469,10 @@ snapshots:
|
|||||||
|
|
||||||
'@tsconfig/node16@1.0.4': {}
|
'@tsconfig/node16@1.0.4': {}
|
||||||
|
|
||||||
|
'@types/bun@1.3.5':
|
||||||
|
dependencies:
|
||||||
|
bun-types: 1.3.5
|
||||||
|
|
||||||
'@types/eslint-scope@3.7.7':
|
'@types/eslint-scope@3.7.7':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/eslint': 9.6.1
|
'@types/eslint': 9.6.1
|
||||||
@@ -1224,13 +1487,7 @@ snapshots:
|
|||||||
|
|
||||||
'@types/json-schema@7.0.15': {}
|
'@types/json-schema@7.0.15': {}
|
||||||
|
|
||||||
'@types/lodash-es@4.17.12':
|
'@types/node@25.0.3':
|
||||||
dependencies:
|
|
||||||
'@types/lodash': 4.17.20
|
|
||||||
|
|
||||||
'@types/lodash@4.17.20': {}
|
|
||||||
|
|
||||||
'@types/node@24.10.4':
|
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 7.16.0
|
undici-types: 7.16.0
|
||||||
|
|
||||||
@@ -1238,15 +1495,15 @@ snapshots:
|
|||||||
|
|
||||||
'@types/send@1.2.1':
|
'@types/send@1.2.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 24.10.4
|
'@types/node': 25.0.3
|
||||||
|
|
||||||
'@types/ws@8.18.1':
|
'@types/ws@8.18.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 24.10.4
|
'@types/node': 25.0.3
|
||||||
|
|
||||||
'@types/xml2js@0.4.14':
|
'@types/xml2js@0.4.14':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 24.10.4
|
'@types/node': 25.0.3
|
||||||
|
|
||||||
'@webassemblyjs/ast@1.14.1':
|
'@webassemblyjs/ast@1.14.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -1366,25 +1623,29 @@ snapshots:
|
|||||||
pvutils: 1.1.5
|
pvutils: 1.1.5
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
|
|
||||||
baseline-browser-mapping@2.8.28: {}
|
baseline-browser-mapping@2.9.11: {}
|
||||||
|
|
||||||
braces@3.0.3:
|
braces@3.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
fill-range: 7.1.1
|
fill-range: 7.1.1
|
||||||
|
|
||||||
browserslist@4.28.0:
|
browserslist@4.28.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
baseline-browser-mapping: 2.8.28
|
baseline-browser-mapping: 2.9.11
|
||||||
caniuse-lite: 1.0.30001754
|
caniuse-lite: 1.0.30001761
|
||||||
electron-to-chromium: 1.5.252
|
electron-to-chromium: 1.5.267
|
||||||
node-releases: 2.0.27
|
node-releases: 2.0.27
|
||||||
update-browserslist-db: 1.1.4(browserslist@4.28.0)
|
update-browserslist-db: 1.2.3(browserslist@4.28.1)
|
||||||
|
|
||||||
buffer-from@1.1.2: {}
|
buffer-from@1.1.2: {}
|
||||||
|
|
||||||
|
bun-types@1.3.5:
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 25.0.3
|
||||||
|
|
||||||
bytestreamjs@2.0.1: {}
|
bytestreamjs@2.0.1: {}
|
||||||
|
|
||||||
caniuse-lite@1.0.30001754: {}
|
caniuse-lite@1.0.30001761: {}
|
||||||
|
|
||||||
chalk@4.1.2:
|
chalk@4.1.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -1419,16 +1680,45 @@ snapshots:
|
|||||||
|
|
||||||
ee-first@1.1.1: {}
|
ee-first@1.1.1: {}
|
||||||
|
|
||||||
electron-to-chromium@1.5.252: {}
|
electron-to-chromium@1.5.267: {}
|
||||||
|
|
||||||
encodeurl@2.0.0: {}
|
encodeurl@2.0.0: {}
|
||||||
|
|
||||||
enhanced-resolve@5.18.3:
|
enhanced-resolve@5.18.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
graceful-fs: 4.2.11
|
graceful-fs: 4.2.11
|
||||||
tapable: 2.3.0
|
tapable: 2.3.0
|
||||||
|
|
||||||
es-module-lexer@1.7.0: {}
|
es-module-lexer@2.0.0: {}
|
||||||
|
|
||||||
|
esbuild@0.27.2:
|
||||||
|
optionalDependencies:
|
||||||
|
'@esbuild/aix-ppc64': 0.27.2
|
||||||
|
'@esbuild/android-arm': 0.27.2
|
||||||
|
'@esbuild/android-arm64': 0.27.2
|
||||||
|
'@esbuild/android-x64': 0.27.2
|
||||||
|
'@esbuild/darwin-arm64': 0.27.2
|
||||||
|
'@esbuild/darwin-x64': 0.27.2
|
||||||
|
'@esbuild/freebsd-arm64': 0.27.2
|
||||||
|
'@esbuild/freebsd-x64': 0.27.2
|
||||||
|
'@esbuild/linux-arm': 0.27.2
|
||||||
|
'@esbuild/linux-arm64': 0.27.2
|
||||||
|
'@esbuild/linux-ia32': 0.27.2
|
||||||
|
'@esbuild/linux-loong64': 0.27.2
|
||||||
|
'@esbuild/linux-mips64el': 0.27.2
|
||||||
|
'@esbuild/linux-ppc64': 0.27.2
|
||||||
|
'@esbuild/linux-riscv64': 0.27.2
|
||||||
|
'@esbuild/linux-s390x': 0.27.2
|
||||||
|
'@esbuild/linux-x64': 0.27.2
|
||||||
|
'@esbuild/netbsd-arm64': 0.27.2
|
||||||
|
'@esbuild/netbsd-x64': 0.27.2
|
||||||
|
'@esbuild/openbsd-arm64': 0.27.2
|
||||||
|
'@esbuild/openbsd-x64': 0.27.2
|
||||||
|
'@esbuild/openharmony-arm64': 0.27.2
|
||||||
|
'@esbuild/sunos-x64': 0.27.2
|
||||||
|
'@esbuild/win32-arm64': 0.27.2
|
||||||
|
'@esbuild/win32-ia32': 0.27.2
|
||||||
|
'@esbuild/win32-x64': 0.27.2
|
||||||
|
|
||||||
escalade@3.2.0: {}
|
escalade@3.2.0: {}
|
||||||
|
|
||||||
@@ -1472,6 +1762,10 @@ snapshots:
|
|||||||
|
|
||||||
function-bind@1.1.2: {}
|
function-bind@1.1.2: {}
|
||||||
|
|
||||||
|
get-tsconfig@4.13.0:
|
||||||
|
dependencies:
|
||||||
|
resolve-pkg-maps: 1.0.0
|
||||||
|
|
||||||
glob-to-regexp@0.4.1: {}
|
glob-to-regexp@0.4.1: {}
|
||||||
|
|
||||||
graceful-fs@4.2.11: {}
|
graceful-fs@4.2.11: {}
|
||||||
@@ -1482,12 +1776,12 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
function-bind: 1.1.2
|
function-bind: 1.1.2
|
||||||
|
|
||||||
http-errors@2.0.0:
|
http-errors@2.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
depd: 2.0.0
|
depd: 2.0.0
|
||||||
inherits: 2.0.4
|
inherits: 2.0.4
|
||||||
setprototypeof: 1.2.0
|
setprototypeof: 1.2.0
|
||||||
statuses: 2.0.1
|
statuses: 2.0.2
|
||||||
toidentifier: 1.0.1
|
toidentifier: 1.0.1
|
||||||
|
|
||||||
inherits@2.0.4: {}
|
inherits@2.0.4: {}
|
||||||
@@ -1506,7 +1800,7 @@ snapshots:
|
|||||||
|
|
||||||
jest-worker@27.5.1:
|
jest-worker@27.5.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 24.10.4
|
'@types/node': 25.0.3
|
||||||
merge-stream: 2.0.0
|
merge-stream: 2.0.0
|
||||||
supports-color: 8.1.1
|
supports-color: 8.1.1
|
||||||
|
|
||||||
@@ -1519,8 +1813,6 @@ snapshots:
|
|||||||
|
|
||||||
loader-runner@4.3.1: {}
|
loader-runner@4.3.1: {}
|
||||||
|
|
||||||
lodash-es@4.17.21: {}
|
|
||||||
|
|
||||||
magic-string@0.30.21:
|
magic-string@0.30.21:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/sourcemap-codec': 1.5.5
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
@@ -1542,7 +1834,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
mime-db: 1.52.0
|
mime-db: 1.52.0
|
||||||
|
|
||||||
mime-types@3.0.1:
|
mime-types@3.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
mime-db: 1.54.0
|
mime-db: 1.54.0
|
||||||
|
|
||||||
@@ -1593,6 +1885,8 @@ snapshots:
|
|||||||
|
|
||||||
require-from-string@2.0.2: {}
|
require-from-string@2.0.2: {}
|
||||||
|
|
||||||
|
resolve-pkg-maps@1.0.0: {}
|
||||||
|
|
||||||
resolve@1.22.11:
|
resolve@1.22.11:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-core-module: 2.16.1
|
is-core-module: 2.16.1
|
||||||
@@ -1653,15 +1947,15 @@ snapshots:
|
|||||||
|
|
||||||
semver@7.7.3: {}
|
semver@7.7.3: {}
|
||||||
|
|
||||||
send@1.2.0:
|
send@1.2.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
encodeurl: 2.0.0
|
encodeurl: 2.0.0
|
||||||
escape-html: 1.0.3
|
escape-html: 1.0.3
|
||||||
etag: 1.8.1
|
etag: 1.8.1
|
||||||
fresh: 2.0.0
|
fresh: 2.0.0
|
||||||
http-errors: 2.0.0
|
http-errors: 2.0.1
|
||||||
mime-types: 3.0.1
|
mime-types: 3.0.2
|
||||||
ms: 2.1.3
|
ms: 2.1.3
|
||||||
on-finished: 2.4.1
|
on-finished: 2.4.1
|
||||||
range-parser: 1.2.1
|
range-parser: 1.2.1
|
||||||
@@ -1684,8 +1978,6 @@ snapshots:
|
|||||||
|
|
||||||
source-map@0.7.6: {}
|
source-map@0.7.6: {}
|
||||||
|
|
||||||
statuses@2.0.1: {}
|
|
||||||
|
|
||||||
statuses@2.0.2: {}
|
statuses@2.0.2: {}
|
||||||
|
|
||||||
supports-color@7.2.0:
|
supports-color@7.2.0:
|
||||||
@@ -1700,14 +1992,14 @@ snapshots:
|
|||||||
|
|
||||||
tapable@2.3.0: {}
|
tapable@2.3.0: {}
|
||||||
|
|
||||||
terser-webpack-plugin@5.3.14(webpack@5.102.1):
|
terser-webpack-plugin@5.3.16(webpack@5.104.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/trace-mapping': 0.3.31
|
'@jridgewell/trace-mapping': 0.3.31
|
||||||
jest-worker: 27.5.1
|
jest-worker: 27.5.1
|
||||||
schema-utils: 4.3.3
|
schema-utils: 4.3.3
|
||||||
serialize-javascript: 6.0.2
|
serialize-javascript: 6.0.2
|
||||||
terser: 5.44.1
|
terser: 5.44.1
|
||||||
webpack: 5.102.1
|
webpack: 5.104.1
|
||||||
|
|
||||||
terser@5.44.1:
|
terser@5.44.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -1722,24 +2014,24 @@ snapshots:
|
|||||||
|
|
||||||
toidentifier@1.0.1: {}
|
toidentifier@1.0.1: {}
|
||||||
|
|
||||||
ts-loader@9.5.4(typescript@5.9.3)(webpack@5.102.1):
|
ts-loader@9.5.4(typescript@5.9.3)(webpack@5.104.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
enhanced-resolve: 5.18.3
|
enhanced-resolve: 5.18.4
|
||||||
micromatch: 4.0.8
|
micromatch: 4.0.8
|
||||||
semver: 7.7.3
|
semver: 7.7.3
|
||||||
source-map: 0.7.6
|
source-map: 0.7.6
|
||||||
typescript: 5.9.3
|
typescript: 5.9.3
|
||||||
webpack: 5.102.1
|
webpack: 5.104.1
|
||||||
|
|
||||||
ts-node@10.9.2(@types/node@24.10.4)(typescript@5.9.3):
|
ts-node@10.9.2(@types/node@25.0.3)(typescript@5.9.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@cspotcode/source-map-support': 0.8.1
|
'@cspotcode/source-map-support': 0.8.1
|
||||||
'@tsconfig/node10': 1.0.12
|
'@tsconfig/node10': 1.0.12
|
||||||
'@tsconfig/node12': 1.0.11
|
'@tsconfig/node12': 1.0.11
|
||||||
'@tsconfig/node14': 1.0.3
|
'@tsconfig/node14': 1.0.3
|
||||||
'@tsconfig/node16': 1.0.4
|
'@tsconfig/node16': 1.0.4
|
||||||
'@types/node': 24.10.4
|
'@types/node': 25.0.3
|
||||||
acorn: 8.15.0
|
acorn: 8.15.0
|
||||||
acorn-walk: 8.3.4
|
acorn-walk: 8.3.4
|
||||||
arg: 4.1.3
|
arg: 4.1.3
|
||||||
@@ -1754,6 +2046,13 @@ snapshots:
|
|||||||
|
|
||||||
tslib@2.8.1: {}
|
tslib@2.8.1: {}
|
||||||
|
|
||||||
|
tsx@4.21.0:
|
||||||
|
dependencies:
|
||||||
|
esbuild: 0.27.2
|
||||||
|
get-tsconfig: 4.13.0
|
||||||
|
optionalDependencies:
|
||||||
|
fsevents: 2.3.3
|
||||||
|
|
||||||
tsyringe@4.10.0:
|
tsyringe@4.10.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib: 1.14.1
|
tslib: 1.14.1
|
||||||
@@ -1762,9 +2061,9 @@ snapshots:
|
|||||||
|
|
||||||
undici-types@7.16.0: {}
|
undici-types@7.16.0: {}
|
||||||
|
|
||||||
update-browserslist-db@1.1.4(browserslist@4.28.0):
|
update-browserslist-db@1.2.3(browserslist@4.28.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
browserslist: 4.28.0
|
browserslist: 4.28.1
|
||||||
escalade: 3.2.0
|
escalade: 3.2.0
|
||||||
picocolors: 1.1.1
|
picocolors: 1.1.1
|
||||||
|
|
||||||
@@ -1777,7 +2076,7 @@ snapshots:
|
|||||||
|
|
||||||
webpack-sources@3.3.3: {}
|
webpack-sources@3.3.3: {}
|
||||||
|
|
||||||
webpack@5.102.1:
|
webpack@5.104.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/eslint-scope': 3.7.7
|
'@types/eslint-scope': 3.7.7
|
||||||
'@types/estree': 1.0.8
|
'@types/estree': 1.0.8
|
||||||
@@ -1787,10 +2086,10 @@ snapshots:
|
|||||||
'@webassemblyjs/wasm-parser': 1.14.1
|
'@webassemblyjs/wasm-parser': 1.14.1
|
||||||
acorn: 8.15.0
|
acorn: 8.15.0
|
||||||
acorn-import-phases: 1.0.4(acorn@8.15.0)
|
acorn-import-phases: 1.0.4(acorn@8.15.0)
|
||||||
browserslist: 4.28.0
|
browserslist: 4.28.1
|
||||||
chrome-trace-event: 1.0.4
|
chrome-trace-event: 1.0.4
|
||||||
enhanced-resolve: 5.18.3
|
enhanced-resolve: 5.18.4
|
||||||
es-module-lexer: 1.7.0
|
es-module-lexer: 2.0.0
|
||||||
eslint-scope: 5.1.1
|
eslint-scope: 5.1.1
|
||||||
events: 3.3.0
|
events: 3.3.0
|
||||||
glob-to-regexp: 0.4.1
|
glob-to-regexp: 0.4.1
|
||||||
@@ -1801,7 +2100,7 @@ snapshots:
|
|||||||
neo-async: 2.6.2
|
neo-async: 2.6.2
|
||||||
schema-utils: 4.3.3
|
schema-utils: 4.3.3
|
||||||
tapable: 2.3.0
|
tapable: 2.3.0
|
||||||
terser-webpack-plugin: 5.3.14(webpack@5.102.1)
|
terser-webpack-plugin: 5.3.16(webpack@5.104.1)
|
||||||
watchpack: 2.4.4
|
watchpack: 2.4.4
|
||||||
webpack-sources: 3.3.3
|
webpack-sources: 3.3.3
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
|
|||||||
4
pnpm-workspace.yaml
Normal file
4
pnpm-workspace.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
onlyBuiltDependencies:
|
||||||
|
- esbuild
|
||||||
|
packages:
|
||||||
|
- 'demo/**/*'
|
||||||
37
src/app.ts
37
src/app.ts
@@ -1,20 +1,21 @@
|
|||||||
import { QueryRouter, Route, RouteContext, RouteOpts } from './route.ts';
|
import { QueryRouter, Route, RouteContext, RouteOpts } from './route.ts';
|
||||||
import { Server, ServerOpts, HandleCtx } from './server/server.ts';
|
import { ServerNode, ServerNodeOpts } from './server/server.ts';
|
||||||
import { WsServer } from './server/ws-server.ts';
|
import { HandleCtx } from './server/server-base.ts';
|
||||||
|
import { ServerType } from './server/server-type.ts';
|
||||||
import { CustomError } from './result/error.ts';
|
import { CustomError } from './result/error.ts';
|
||||||
import { handleServer } from './server/handle-server.ts';
|
import { handleServer } from './server/handle-server.ts';
|
||||||
import { IncomingMessage, ServerResponse } from 'http';
|
import { IncomingMessage, ServerResponse } from 'http';
|
||||||
|
import { isBun } from './utils/is-engine.ts';
|
||||||
|
import { BunServer } from './server/server-bun.ts';
|
||||||
|
|
||||||
type RouterHandle = (msg: { path: string;[key: string]: any }) => { code: string; data?: any; message?: string;[key: string]: any };
|
type RouterHandle = (msg: { path: string;[key: string]: any }) => { code: string; data?: any; message?: string;[key: string]: any };
|
||||||
type AppOptions<T = {}> = {
|
type AppOptions<T = {}> = {
|
||||||
router?: QueryRouter;
|
router?: QueryRouter;
|
||||||
server?: Server;
|
server?: ServerType;
|
||||||
/** handle msg 关联 */
|
/** handle msg 关联 */
|
||||||
routerHandle?: RouterHandle;
|
routerHandle?: RouterHandle;
|
||||||
routerContext?: RouteContext<T>;
|
routerContext?: RouteContext<T>;
|
||||||
serverOptions?: ServerOpts;
|
serverOptions?: ServerNodeOpts;
|
||||||
io?: boolean;
|
|
||||||
ioOpts?: { routerHandle?: RouterHandle; routerContext?: RouteContext<T>; path?: string };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AppRouteContext<T = {}> = HandleCtx & RouteContext<T> & { app: App<T> };
|
export type AppRouteContext<T = {}> = HandleCtx & RouteContext<T> & { app: App<T> };
|
||||||
@@ -25,18 +26,22 @@ export type AppRouteContext<T = {}> = HandleCtx & RouteContext<T> & { app: App<T
|
|||||||
*/
|
*/
|
||||||
export class App<U = {}> {
|
export class App<U = {}> {
|
||||||
router: QueryRouter;
|
router: QueryRouter;
|
||||||
server: Server;
|
server: ServerType;
|
||||||
io: WsServer;
|
|
||||||
constructor(opts?: AppOptions<U>) {
|
constructor(opts?: AppOptions<U>) {
|
||||||
const router = opts?.router || new QueryRouter();
|
const router = opts?.router || new QueryRouter();
|
||||||
const server = opts?.server || new Server(opts?.serverOptions || {});
|
let server = opts?.server;
|
||||||
|
if (!server) {
|
||||||
|
const serverOptions = opts?.serverOptions || {};
|
||||||
|
if (!isBun) {
|
||||||
|
server = new ServerNode(serverOptions)
|
||||||
|
} else {
|
||||||
|
server = new BunServer(serverOptions)
|
||||||
|
}
|
||||||
|
}
|
||||||
server.setHandle(router.getHandle(router, opts?.routerHandle, opts?.routerContext));
|
server.setHandle(router.getHandle(router, opts?.routerHandle, opts?.routerContext));
|
||||||
router.setContext({ needSerialize: true, ...opts?.routerContext });
|
router.setContext({ needSerialize: true, ...opts?.routerContext });
|
||||||
this.router = router;
|
this.router = router;
|
||||||
this.server = server;
|
this.server = server;
|
||||||
if (opts?.io) {
|
|
||||||
this.io = new WsServer(server, opts?.ioOpts);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
listen(port: number, hostname?: string, backlog?: number, listeningListener?: () => void): void;
|
listen(port: number, hostname?: string, backlog?: number, listeningListener?: () => void): void;
|
||||||
listen(port: number, hostname?: string, listeningListener?: () => void): void;
|
listen(port: number, hostname?: string, listeningListener?: () => void): void;
|
||||||
@@ -49,9 +54,6 @@ export class App<U = {}> {
|
|||||||
listen(...args: any[]) {
|
listen(...args: any[]) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.server.listen(...args);
|
this.server.listen(...args);
|
||||||
if (this.io) {
|
|
||||||
this.io.listen();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
use(path: string, fn: (ctx: any) => any, opts?: RouteOpts) {
|
use(path: string, fn: (ctx: any) => any, opts?: RouteOpts) {
|
||||||
const route = new Route(path, '', opts);
|
const route = new Route(path, '', opts);
|
||||||
@@ -130,7 +132,10 @@ export class App<U = {}> {
|
|||||||
if (!this.server) {
|
if (!this.server) {
|
||||||
throw new Error('Server is not initialized');
|
throw new Error('Server is not initialized');
|
||||||
}
|
}
|
||||||
this.server.on(fn);
|
this.server.on({
|
||||||
|
id: 'app-request-listener',
|
||||||
|
fun: fn
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ export type { RouteContext, RouteOpts, RouteMiddleware } from './route.ts';
|
|||||||
|
|
||||||
export type { Run } from './route.ts';
|
export type { Run } from './route.ts';
|
||||||
|
|
||||||
export { Server, handleServer } from './server/index.ts';
|
export { ServerNode, handleServer } from './server/index.ts';
|
||||||
/**
|
/**
|
||||||
* 自定义错误
|
* 自定义错误
|
||||||
*/
|
*/
|
||||||
@@ -13,7 +13,7 @@ export { CustomError } from './result/error.ts';
|
|||||||
|
|
||||||
export { createSchema } from './validator/index.ts';
|
export { createSchema } from './validator/index.ts';
|
||||||
|
|
||||||
export type { Rule, Schema, } from './validator/index.ts';
|
export type { Rule, Schema, } from './validator/index.ts';
|
||||||
|
|
||||||
export { App } from './app.ts';
|
export { App } from './app.ts';
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ export class SimpleRouter {
|
|||||||
}
|
}
|
||||||
isSse(req: Req) {
|
isSse(req: Req) {
|
||||||
const { headers } = req;
|
const { headers } = req;
|
||||||
|
if (!headers) return false;
|
||||||
if (headers['accept'] && headers['accept'].includes('text/event-stream')) {
|
if (headers['accept'] && headers['accept'].includes('text/event-stream')) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { IncomingMessage, ServerResponse } from 'node:http';
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
||||||
import { parseBody } from './parse-body.ts';
|
import { parseBody } from './parse-body.ts';
|
||||||
import url from 'node:url';
|
import url from 'node:url';
|
||||||
import { createHandleCtx } from './server.ts';
|
import { createHandleCtx } from './server-base.ts';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get params and body
|
* get params and body
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
export { Server } from './server.ts';
|
export { ServerNode } from './server.ts';
|
||||||
|
export { BunServer } from './server-bun.ts';
|
||||||
export { handleServer } from './handle-server.ts';
|
export { handleServer } from './handle-server.ts';
|
||||||
|
|||||||
@@ -1,7 +1,49 @@
|
|||||||
import type { IncomingMessage } from 'node:http';
|
import type { IncomingMessage } from 'node:http';
|
||||||
import url from 'node:url';
|
import url from 'node:url';
|
||||||
|
import { isBun } from '../utils/is-engine.ts';
|
||||||
export const parseBody = async <T = Record<string, any>>(req: IncomingMessage) => {
|
export const parseBody = async <T = Record<string, any>>(req: IncomingMessage) => {
|
||||||
|
const resolveBody = (body: string) => {
|
||||||
|
// 获取 Content-Type 头信息
|
||||||
|
const contentType = req.headers['content-type'] || '';
|
||||||
|
const resolve = (data: T) => {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
// 处理 application/json
|
||||||
|
if (contentType.includes('application/json')) {
|
||||||
|
return resolve(JSON.parse(body) as T);
|
||||||
|
}
|
||||||
|
// 处理 application/x-www-form-urlencoded
|
||||||
|
if (contentType.includes('application/x-www-form-urlencoded')) {
|
||||||
|
const formData = new URLSearchParams(body);
|
||||||
|
const result: Record<string, any> = {};
|
||||||
|
|
||||||
|
formData.forEach((value, key) => {
|
||||||
|
// 尝试将值解析为 JSON,如果失败则保留原始字符串
|
||||||
|
try {
|
||||||
|
result[key] = JSON.parse(value);
|
||||||
|
} catch {
|
||||||
|
result[key] = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return resolve(result as T);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 默认尝试 JSON 解析
|
||||||
|
try {
|
||||||
|
return resolve(JSON.parse(body) as T);
|
||||||
|
} catch {
|
||||||
|
return resolve({} as T);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isBun) {
|
||||||
|
// @ts-ignore
|
||||||
|
const body = req.body;
|
||||||
|
if (body) {
|
||||||
|
return resolveBody(body)
|
||||||
|
}
|
||||||
|
return {} as T;
|
||||||
|
}
|
||||||
return new Promise<T>((resolve, reject) => {
|
return new Promise<T>((resolve, reject) => {
|
||||||
const arr: any[] = [];
|
const arr: any[] = [];
|
||||||
req.on('data', (chunk) => {
|
req.on('data', (chunk) => {
|
||||||
@@ -10,39 +52,8 @@ export const parseBody = async <T = Record<string, any>>(req: IncomingMessage) =
|
|||||||
req.on('end', () => {
|
req.on('end', () => {
|
||||||
try {
|
try {
|
||||||
const body = Buffer.concat(arr).toString();
|
const body = Buffer.concat(arr).toString();
|
||||||
|
resolve(resolveBody(body));
|
||||||
|
|
||||||
// 获取 Content-Type 头信息
|
|
||||||
const contentType = req.headers['content-type'] || '';
|
|
||||||
|
|
||||||
// 处理 application/json
|
|
||||||
if (contentType.includes('application/json')) {
|
|
||||||
resolve(JSON.parse(body) as T);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 处理 application/x-www-form-urlencoded
|
|
||||||
if (contentType.includes('application/x-www-form-urlencoded')) {
|
|
||||||
const formData = new URLSearchParams(body);
|
|
||||||
const result: Record<string, any> = {};
|
|
||||||
|
|
||||||
formData.forEach((value, key) => {
|
|
||||||
// 尝试将值解析为 JSON,如果失败则保留原始字符串
|
|
||||||
try {
|
|
||||||
result[key] = JSON.parse(value);
|
|
||||||
} catch {
|
|
||||||
result[key] = value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
resolve(result as T);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 默认尝试 JSON 解析
|
|
||||||
try {
|
|
||||||
resolve(JSON.parse(body) as T);
|
|
||||||
} catch {
|
|
||||||
resolve({} as T);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
resolve({} as T);
|
resolve({} as T);
|
||||||
}
|
}
|
||||||
|
|||||||
265
src/server/server-base.ts
Normal file
265
src/server/server-base.ts
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
||||||
|
import { handleServer } from './handle-server.ts';
|
||||||
|
import * as cookie from './cookie.ts';
|
||||||
|
import { ServerType, Listener, OnListener, ServerOpts } from './server-type.ts';
|
||||||
|
import { parseIfJson } from '../utils/parse.ts';
|
||||||
|
|
||||||
|
type CookieFn = (name: string, value: string, options?: cookie.SerializeOptions, end?: boolean) => void;
|
||||||
|
|
||||||
|
export type HandleCtx = {
|
||||||
|
req: IncomingMessage & { cookies: Record<string, string> };
|
||||||
|
res: ServerResponse & {
|
||||||
|
/**
|
||||||
|
* cookie 函数, end 参数用于设置是否立即设置到响应头,设置了后面的cookie再设置会覆盖前面的
|
||||||
|
*/
|
||||||
|
cookie: CookieFn; //
|
||||||
|
};
|
||||||
|
};
|
||||||
|
// 实现函数
|
||||||
|
export function createHandleCtx(req: IncomingMessage, res: ServerResponse): HandleCtx {
|
||||||
|
// 用于存储所有的 Set-Cookie 字符串
|
||||||
|
const cookies: string[] = [];
|
||||||
|
let handReq = req as HandleCtx['req'];
|
||||||
|
let handRes = res as HandleCtx['res'];
|
||||||
|
// 扩展 res.cookie 方法
|
||||||
|
const cookieFn: CookieFn = (name, value, options = {}, end = true) => {
|
||||||
|
// 序列化新的 Cookie
|
||||||
|
const serializedCookie = cookie.serialize(name, value, options);
|
||||||
|
cookies.push(serializedCookie); // 将新的 Cookie 添加到数组
|
||||||
|
if (end) {
|
||||||
|
// 如果设置了 end 参数,则立即设置到响应头
|
||||||
|
res.setHeader('Set-Cookie', cookies);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 解析请求中的现有 Cookie
|
||||||
|
const parsedCookies = cookie.parse(req.headers.cookie || '');
|
||||||
|
handReq.cookies = parsedCookies;
|
||||||
|
handRes.cookie = cookieFn;
|
||||||
|
// 返回扩展的上下文
|
||||||
|
return {
|
||||||
|
req: handReq,
|
||||||
|
res: handRes,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export type Cors = {
|
||||||
|
/**
|
||||||
|
* @default '*''
|
||||||
|
*/
|
||||||
|
origin?: string | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const resultError = (error: string, code = 500) => {
|
||||||
|
const r = {
|
||||||
|
code: code,
|
||||||
|
message: error,
|
||||||
|
};
|
||||||
|
return JSON.stringify(r);
|
||||||
|
};
|
||||||
|
|
||||||
|
export class ServerBase implements ServerType {
|
||||||
|
path = '/api/router';
|
||||||
|
_server: any;
|
||||||
|
handle: ServerOpts['handle'];
|
||||||
|
_callback: any;
|
||||||
|
cors: Cors;
|
||||||
|
listeners: Listener[] = [];
|
||||||
|
constructor(opts?: ServerOpts) {
|
||||||
|
this.path = opts?.path || '/api/router';
|
||||||
|
this.handle = opts?.handle;
|
||||||
|
this.cors = opts?.cors;
|
||||||
|
|
||||||
|
}
|
||||||
|
listen(port: number, hostname?: string, backlog?: number, listeningListener?: () => void): void;
|
||||||
|
listen(port: number, hostname?: string, listeningListener?: () => void): void;
|
||||||
|
listen(port: number, backlog?: number, listeningListener?: () => void): void;
|
||||||
|
listen(port: number, listeningListener?: () => void): void;
|
||||||
|
listen(path: string, backlog?: number, listeningListener?: () => void): void;
|
||||||
|
listen(path: string, listeningListener?: () => void): void;
|
||||||
|
listen(handle: any, backlog?: number, listeningListener?: () => void): void;
|
||||||
|
listen(handle: any, listeningListener?: () => void): void;
|
||||||
|
listen(...args: any[]) {
|
||||||
|
this.customListen(...args);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* child class can custom listen method
|
||||||
|
* @param args
|
||||||
|
*/
|
||||||
|
customListen(...args: any[]) {
|
||||||
|
console.error('Please use createServer to create server instance');
|
||||||
|
}
|
||||||
|
get handleServer() {
|
||||||
|
return this._callback;
|
||||||
|
}
|
||||||
|
set handleServer(fn: any) {
|
||||||
|
this._callback = fn;
|
||||||
|
}
|
||||||
|
get callback() {
|
||||||
|
return this._callback || this.createCallback();
|
||||||
|
}
|
||||||
|
get server() {
|
||||||
|
return this._server;
|
||||||
|
}
|
||||||
|
setHandle(handle?: any) {
|
||||||
|
this.handle = handle;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* get callback
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
createCallback() {
|
||||||
|
const path = this.path;
|
||||||
|
const handle = this.handle;
|
||||||
|
const cors = this.cors;
|
||||||
|
const that = this;
|
||||||
|
const _callback = async (req: IncomingMessage, res: ServerResponse) => {
|
||||||
|
// only handle /api/router
|
||||||
|
if (req.url === '/favicon.ico') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const listeners = that.listeners || [];
|
||||||
|
for (const item of listeners) {
|
||||||
|
const fun = item.fun;
|
||||||
|
if (typeof fun === 'function' && !item.io) {
|
||||||
|
await fun(req, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (res.headersSent) {
|
||||||
|
// 程序已经在其他地方响应了
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!req.url.startsWith(path)) {
|
||||||
|
// 判断不是当前路径的请求,交给其他监听处理
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cors) {
|
||||||
|
res.setHeader('Access-Control-Allow-Origin', cors?.origin || '*'); // 允许所有域名的请求访问,可以根据需要设置具体的域名
|
||||||
|
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
|
||||||
|
res.setHeader('Access-Control-Allow-Methods', 'GET, POST');
|
||||||
|
if (req.method === 'OPTIONS') {
|
||||||
|
res.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const url = req.url;
|
||||||
|
if (!url.startsWith(path)) {
|
||||||
|
res.end(resultError(`not path:[${path}]`));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const messages = await handleServer(req, res);
|
||||||
|
if (!handle) {
|
||||||
|
res.end(resultError('no handle'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const end = await handle(messages as any, { req, res });
|
||||||
|
if (res.writableEnded) {
|
||||||
|
// 如果响应已经结束,则不进行任何操作
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
||||||
|
if (typeof end === 'string') {
|
||||||
|
res.end(end);
|
||||||
|
} else {
|
||||||
|
res.end(JSON.stringify(end));
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
||||||
|
if (e.code && typeof e.code === 'number') {
|
||||||
|
res.end(resultError(e.message || `Router Server error`, e.code));
|
||||||
|
} else {
|
||||||
|
res.end(resultError('Router Server error'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this._callback = _callback;
|
||||||
|
return _callback;
|
||||||
|
}
|
||||||
|
on(listener: OnListener) {
|
||||||
|
this.listeners = [];
|
||||||
|
if (typeof listener === 'function') {
|
||||||
|
this.listeners.push({ fun: listener });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Array.isArray(listener)) {
|
||||||
|
for (const item of listener) {
|
||||||
|
if (typeof item === 'function') {
|
||||||
|
this.listeners.push({ fun: item });
|
||||||
|
} else {
|
||||||
|
this.listeners.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.listeners.push(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async onWebSocket({ ws, message, pathname, token, id }) {
|
||||||
|
const listener = this.listeners.find((item) => item.path === pathname && item.io);
|
||||||
|
const data: any = parseIfJson(message);
|
||||||
|
|
||||||
|
if (listener) {
|
||||||
|
const end = (data: any) => {
|
||||||
|
ws.send(JSON.stringify(data));
|
||||||
|
}
|
||||||
|
listener.fun({
|
||||||
|
data,
|
||||||
|
token,
|
||||||
|
id,
|
||||||
|
ws,
|
||||||
|
}, { end });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof data === 'string') {
|
||||||
|
const cleanMessage = data.trim().replace(/^["']|["']$/g, '');
|
||||||
|
if (cleanMessage === 'close') {
|
||||||
|
ws.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cleanMessage === 'ping') {
|
||||||
|
ws.send('pong');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { type, data: typeData, ...rest } = data;
|
||||||
|
if (!type) {
|
||||||
|
ws.send(JSON.stringify({ code: 500, message: 'type is required' }));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = {
|
||||||
|
type,
|
||||||
|
data: {} as any,
|
||||||
|
...rest,
|
||||||
|
};
|
||||||
|
const end = (data: any, all?: Record<string, any>) => {
|
||||||
|
const result = {
|
||||||
|
...res,
|
||||||
|
data,
|
||||||
|
...all,
|
||||||
|
};
|
||||||
|
ws.send(JSON.stringify(result));
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// 调用 handle 处理消息
|
||||||
|
if (type === 'router' && this.handle) {
|
||||||
|
try {
|
||||||
|
const result = await this.handle(typeData as any);
|
||||||
|
end(result);
|
||||||
|
} catch (e: any) {
|
||||||
|
if (e.code && typeof e.code === 'number') {
|
||||||
|
end({
|
||||||
|
code: e.code,
|
||||||
|
message: e.message,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
end({ code: 500, message: 'Router Server error' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
end({ code: 500, message: `${type} server is error` });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
174
src/server/server-bun.ts
Normal file
174
src/server/server-bun.ts
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
/**
|
||||||
|
* @title Bun Server Implementation
|
||||||
|
* @description Bun 服务器实现,提供基于 Bun.serve 的 HTTP 和 WebSocket 功能
|
||||||
|
* @tags bun, server, websocket, http
|
||||||
|
* @createdAt 2025-12-20
|
||||||
|
*/
|
||||||
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
||||||
|
import { ServerType, type ServerOpts, type Cors, Listener } from './server-type.ts';
|
||||||
|
import { handleServer } from './handle-server.ts';
|
||||||
|
import { ServerBase } from './server-base.ts';
|
||||||
|
import { parseIfJson } from '../utils/parse.ts';
|
||||||
|
|
||||||
|
const resultError = (error: string, code = 500) => {
|
||||||
|
const r = {
|
||||||
|
code: code,
|
||||||
|
message: error,
|
||||||
|
};
|
||||||
|
return JSON.stringify(r);
|
||||||
|
};
|
||||||
|
|
||||||
|
export class BunServer extends ServerBase implements ServerType {
|
||||||
|
declare _server: any;
|
||||||
|
declare _callback: any;
|
||||||
|
declare cors: Cors;
|
||||||
|
constructor(opts?: ServerOpts) {
|
||||||
|
super(opts);
|
||||||
|
}
|
||||||
|
customListen(...args: any[]): void {
|
||||||
|
this.listenWithBun(...args);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Bun 运行时的 listen 实现
|
||||||
|
*/
|
||||||
|
private listenWithBun(...args: any[]) {
|
||||||
|
// @ts-ignore - Bun 全局 API
|
||||||
|
if (typeof Bun === 'undefined' || !Bun.serve) {
|
||||||
|
throw new Error('Bun runtime not detected');
|
||||||
|
}
|
||||||
|
|
||||||
|
let port: number = 3000;
|
||||||
|
let hostname: string = 'localhost';
|
||||||
|
let callback: (() => void) | undefined;
|
||||||
|
|
||||||
|
// 解析参数
|
||||||
|
if (typeof args[0] === 'number') {
|
||||||
|
port = args[0];
|
||||||
|
if (typeof args[1] === 'string') {
|
||||||
|
hostname = args[1];
|
||||||
|
callback = args[2] || args[3];
|
||||||
|
} else if (typeof args[1] === 'function') {
|
||||||
|
callback = args[1];
|
||||||
|
} else {
|
||||||
|
callback = args[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const requestCallback = this.createCallback();
|
||||||
|
const wsPath = this.path;
|
||||||
|
// @ts-ignore
|
||||||
|
this._server = Bun.serve({
|
||||||
|
port,
|
||||||
|
hostname,
|
||||||
|
idleTimeout: 0, // 4 minutes idle timeout (max 255 seconds)
|
||||||
|
fetch: async (request: Request, server: any) => {
|
||||||
|
const host = request.headers.get('host') || 'localhost';
|
||||||
|
const url = new URL(request.url, `http://${host}`);
|
||||||
|
// 处理 WebSocket 升级请求
|
||||||
|
if (request.headers.get('upgrade') === 'websocket') {
|
||||||
|
const listenPath = this.listeners.map((item) => item.path).filter((item) => item);
|
||||||
|
if (listenPath.includes(url.pathname) || url.pathname === wsPath) {
|
||||||
|
const token = url.searchParams.get('token') || '';
|
||||||
|
const id = url.searchParams.get('id') || '';
|
||||||
|
const upgraded = server.upgrade(request, {
|
||||||
|
data: { url: url, pathname: url.pathname, token, id },
|
||||||
|
});
|
||||||
|
if (upgraded) {
|
||||||
|
return undefined; // WebSocket 连接成功
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Response('WebSocket upgrade failed', { status: 400 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将 Bun 的 Request 转换为 Node.js 风格的 req/res
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const req: any = {
|
||||||
|
url: url.pathname + url.search,
|
||||||
|
method: request.method,
|
||||||
|
headers: Object.fromEntries(request.headers.entries()),
|
||||||
|
};
|
||||||
|
|
||||||
|
const res: any = {
|
||||||
|
statusCode: 200,
|
||||||
|
headersSent: false,
|
||||||
|
writableEnded: false,
|
||||||
|
_headers: {} as Record<string, string | string[]>,
|
||||||
|
writeHead(statusCode: number, headers: Record<string, string | string[]>) {
|
||||||
|
this.statusCode = statusCode;
|
||||||
|
for (const key in headers) {
|
||||||
|
this._headers[key] = headers[key];
|
||||||
|
}
|
||||||
|
this.headersSent = true;
|
||||||
|
},
|
||||||
|
setHeader(name: string, value: string | string[]) {
|
||||||
|
this._headers[name] = value;
|
||||||
|
},
|
||||||
|
cookie(name: string, value: string, options?: any) {
|
||||||
|
let cookieString = `${name}=${value}`;
|
||||||
|
if (options) {
|
||||||
|
if (options.maxAge) {
|
||||||
|
cookieString += `; Max-Age=${options.maxAge}`;
|
||||||
|
}
|
||||||
|
if (options.domain) {
|
||||||
|
cookieString += `; Domain=${options.domain}`;
|
||||||
|
}
|
||||||
|
if (options.path) {
|
||||||
|
cookieString += `; Path=${options.path}`;
|
||||||
|
}
|
||||||
|
if (options.expires) {
|
||||||
|
cookieString += `; Expires=${options.expires.toUTCString()}`;
|
||||||
|
}
|
||||||
|
if (options.httpOnly) {
|
||||||
|
cookieString += `; HttpOnly`;
|
||||||
|
}
|
||||||
|
if (options.secure) {
|
||||||
|
cookieString += `; Secure`;
|
||||||
|
}
|
||||||
|
if (options.sameSite) {
|
||||||
|
cookieString += `; SameSite=${options.sameSite}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setHeader('Set-Cookie', cookieString);
|
||||||
|
},
|
||||||
|
end(data?: string) {
|
||||||
|
this.writableEnded = true;
|
||||||
|
resolve(
|
||||||
|
new Response(data, {
|
||||||
|
status: this.statusCode,
|
||||||
|
headers: this._headers as any,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
// 处理请求体
|
||||||
|
if (request.method !== 'GET' && request.method !== 'HEAD') {
|
||||||
|
request.text().then((body) => {
|
||||||
|
(req as any).body = body;
|
||||||
|
requestCallback(req, res);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
requestCallback(req, res);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
websocket: {
|
||||||
|
open: (ws: any) => {
|
||||||
|
ws.send('connected');
|
||||||
|
},
|
||||||
|
message: async (ws: any, message: string | Buffer) => {
|
||||||
|
const pathname = ws.data.pathname || '';
|
||||||
|
const token = ws.data.token || '';
|
||||||
|
const id = ws.data.id || '';
|
||||||
|
await this.onWebSocket({ ws, message, pathname, token, id });
|
||||||
|
},
|
||||||
|
close: (ws: any) => {
|
||||||
|
// WebSocket 连接关闭
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (callback) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
70
src/server/server-type.ts
Normal file
70
src/server/server-type.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import * as http from 'http';
|
||||||
|
|
||||||
|
export type Listener = {
|
||||||
|
id?: string;
|
||||||
|
io?: boolean;
|
||||||
|
path?: string;
|
||||||
|
fun: (...args: any[]) => Promise<void> | void;
|
||||||
|
}
|
||||||
|
export type ListenerFun = (...args: any[]) => Promise<void> | void;
|
||||||
|
export type OnListener = Listener | Listener[] | ListenerFun | ListenerFun[];
|
||||||
|
export type Cors = {
|
||||||
|
/**
|
||||||
|
* @default '*''
|
||||||
|
*/
|
||||||
|
origin?: string | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ServerOpts<T = {}> = {
|
||||||
|
/**path default `/api/router` */
|
||||||
|
path?: string;
|
||||||
|
/**handle Fn */
|
||||||
|
handle?: (msg?: { path: string; key?: string;[key: string]: any }, ctx?: { req: http.IncomingMessage; res: http.ServerResponse }) => any;
|
||||||
|
cors?: Cors;
|
||||||
|
io?: boolean;
|
||||||
|
} & T;
|
||||||
|
|
||||||
|
export interface ServerType {
|
||||||
|
path?: string;
|
||||||
|
server?: any;
|
||||||
|
handle: ServerOpts['handle'];
|
||||||
|
setHandle(handle?: any): void;
|
||||||
|
listeners: Listener[];
|
||||||
|
listen(port: number, hostname?: string, backlog?: number, listeningListener?: () => void): void;
|
||||||
|
listen(port: number, hostname?: string, listeningListener?: () => void): void;
|
||||||
|
listen(port: number, backlog?: number, listeningListener?: () => void): void;
|
||||||
|
listen(port: number, listeningListener?: () => void): void;
|
||||||
|
listen(path: string, backlog?: number, listeningListener?: () => void): void;
|
||||||
|
listen(path: string, listeningListener?: () => void): void;
|
||||||
|
listen(handle: any, backlog?: number, listeningListener?: () => void): void;
|
||||||
|
listen(handle: any, listeningListener?: () => void): void;
|
||||||
|
/**
|
||||||
|
* 兜底监听,当除开 `/api/router` 之外的请求,框架只监听一个api,所以有其他的请求都执行其他的监听
|
||||||
|
* @description 主要是为了兼容其他的监听
|
||||||
|
* @param listener
|
||||||
|
*/
|
||||||
|
on(listener: OnListener): void;
|
||||||
|
onWebSocket({ ws, message, pathname, token, id }: { ws: WS; message: string | Buffer; pathname: string, token?: string, id?: string }): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
type WS = {
|
||||||
|
send: (data: any) => void;
|
||||||
|
close: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CommonReq = {
|
||||||
|
url: string;
|
||||||
|
method: string;
|
||||||
|
headers: Record<string, string>;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CommonRes = {
|
||||||
|
statusCode: number;
|
||||||
|
writableEnded: boolean;
|
||||||
|
writeHead: (statusCode: number, headers?: Record<string, string>) => void;
|
||||||
|
setHeader: (name: string, value: string | string[]) => void;
|
||||||
|
cookie: (name: string, value: string, options?: any) => void;
|
||||||
|
end: (data?: any) => void;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
@@ -1,64 +1,22 @@
|
|||||||
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
||||||
import http from 'node:http';
|
import http from 'node:http';
|
||||||
import https from 'node:https';
|
import https from 'node:https';
|
||||||
import http2 from 'node:http2';
|
import http2 from 'node:http2';
|
||||||
import { handleServer } from './handle-server.ts';
|
import { isBun } from '../utils/is-engine.ts';
|
||||||
import * as cookie from './cookie.ts';
|
import { ServerType, Listener, ServerOpts } from './server-type.ts';
|
||||||
export type Listener = (...args: any[]) => void;
|
import { ServerBase } from './server-base.ts';
|
||||||
|
import { WsServer } from './ws-server.ts';
|
||||||
|
|
||||||
type CookieFn = (name: string, value: string, options?: cookie.SerializeOptions, end?: boolean) => void;
|
|
||||||
|
|
||||||
export type HandleCtx = {
|
|
||||||
req: IncomingMessage & { cookies: Record<string, string> };
|
|
||||||
res: ServerResponse & {
|
|
||||||
/**
|
|
||||||
* cookie 函数, end 参数用于设置是否立即设置到响应头,设置了后面的cookie再设置会覆盖前面的
|
|
||||||
*/
|
|
||||||
cookie: CookieFn; //
|
|
||||||
};
|
|
||||||
};
|
|
||||||
// 实现函数
|
|
||||||
export function createHandleCtx(req: IncomingMessage, res: ServerResponse): HandleCtx {
|
|
||||||
// 用于存储所有的 Set-Cookie 字符串
|
|
||||||
const cookies: string[] = [];
|
|
||||||
let handReq = req as HandleCtx['req'];
|
|
||||||
let handRes = res as HandleCtx['res'];
|
|
||||||
// 扩展 res.cookie 方法
|
|
||||||
const cookieFn: CookieFn = (name, value, options = {}, end = true) => {
|
|
||||||
// 序列化新的 Cookie
|
|
||||||
const serializedCookie = cookie.serialize(name, value, options);
|
|
||||||
cookies.push(serializedCookie); // 将新的 Cookie 添加到数组
|
|
||||||
if (end) {
|
|
||||||
// 如果设置了 end 参数,则立即设置到响应头
|
|
||||||
res.setHeader('Set-Cookie', cookies);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// 解析请求中的现有 Cookie
|
|
||||||
const parsedCookies = cookie.parse(req.headers.cookie || '');
|
|
||||||
handReq.cookies = parsedCookies;
|
|
||||||
handRes.cookie = cookieFn;
|
|
||||||
// 返回扩展的上下文
|
|
||||||
return {
|
|
||||||
req: handReq,
|
|
||||||
res: handRes,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
export type Cors = {
|
export type Cors = {
|
||||||
/**
|
/**
|
||||||
* @default '*''
|
* @default '*''
|
||||||
*/
|
*/
|
||||||
origin?: string | undefined;
|
origin?: string | undefined;
|
||||||
};
|
};
|
||||||
export type ServerOpts = {
|
export type ServerNodeOpts = ServerOpts<{
|
||||||
/**path default `/api/router` */
|
|
||||||
path?: string;
|
|
||||||
/**handle Fn */
|
|
||||||
handle?: (msg?: { path: string; key?: string;[key: string]: any }, ctx?: { req: http.IncomingMessage; res: http.ServerResponse }) => any;
|
|
||||||
cors?: Cors;
|
|
||||||
httpType?: 'http' | 'https' | 'http2';
|
httpType?: 'http' | 'https' | 'http2';
|
||||||
httpsKey?: string;
|
httpsKey?: string;
|
||||||
httpsCert?: string;
|
httpsCert?: string;
|
||||||
};
|
}>;
|
||||||
export const resultError = (error: string, code = 500) => {
|
export const resultError = (error: string, code = 500) => {
|
||||||
const r = {
|
const r = {
|
||||||
code: code,
|
code: code,
|
||||||
@@ -67,41 +25,39 @@ export const resultError = (error: string, code = 500) => {
|
|||||||
return JSON.stringify(r);
|
return JSON.stringify(r);
|
||||||
};
|
};
|
||||||
|
|
||||||
export class Server {
|
export class ServerNode extends ServerBase implements ServerType {
|
||||||
path = '/api/router';
|
declare _server: http.Server | https.Server | http2.Http2SecureServer;
|
||||||
private _server: http.Server | https.Server | http2.Http2SecureServer;
|
declare _callback: any;
|
||||||
public handle: ServerOpts['handle'];
|
declare cors: Cors;
|
||||||
private _callback: any;
|
|
||||||
private cors: Cors;
|
|
||||||
private hasOn = false;
|
|
||||||
private httpType = 'http';
|
private httpType = 'http';
|
||||||
|
declare listeners: Listener[];
|
||||||
private options = {
|
private options = {
|
||||||
key: '',
|
key: '',
|
||||||
cert: '',
|
cert: '',
|
||||||
};
|
};
|
||||||
constructor(opts?: ServerOpts) {
|
io: WsServer | undefined;
|
||||||
this.path = opts?.path || '/api/router';
|
constructor(opts?: ServerNodeOpts) {
|
||||||
this.handle = opts?.handle;
|
super(opts);
|
||||||
this.cors = opts?.cors;
|
|
||||||
this.httpType = opts?.httpType || 'http';
|
this.httpType = opts?.httpType || 'http';
|
||||||
this.options = {
|
this.options = {
|
||||||
key: opts?.httpsKey || '',
|
key: opts?.httpsKey || '',
|
||||||
cert: opts?.httpsCert || '',
|
cert: opts?.httpsCert || '',
|
||||||
};
|
};
|
||||||
|
const io = opts?.io ?? false;
|
||||||
|
if (io) {
|
||||||
|
this.io = new WsServer(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
listen(port: number, hostname?: string, backlog?: number, listeningListener?: () => void): void;
|
customListen(...args: any[]): void {
|
||||||
listen(port: number, hostname?: string, listeningListener?: () => void): void;
|
if (isBun) {
|
||||||
listen(port: number, backlog?: number, listeningListener?: () => void): void;
|
throw new Error('Use BunServer from server-bun module for Bun runtime');
|
||||||
listen(port: number, listeningListener?: () => void): void;
|
}
|
||||||
listen(path: string, backlog?: number, listeningListener?: () => void): void;
|
|
||||||
listen(path: string, listeningListener?: () => void): void;
|
|
||||||
listen(handle: any, backlog?: number, listeningListener?: () => void): void;
|
|
||||||
listen(handle: any, listeningListener?: () => void): void;
|
|
||||||
listen(...args: any[]) {
|
|
||||||
this._server = this.createServer();
|
this._server = this.createServer();
|
||||||
const callback = this.createCallback();
|
const callback = this.createCallback();
|
||||||
this._server.on('request', callback);
|
this._server.on('request', callback);
|
||||||
this._server.listen(...args);
|
this._server.listen(...args);
|
||||||
|
|
||||||
|
this.io?.listen();
|
||||||
}
|
}
|
||||||
createServer() {
|
createServer() {
|
||||||
let server: http.Server | https.Server | http2.Http2SecureServer;
|
let server: http.Server | https.Server | http2.Http2SecureServer;
|
||||||
@@ -132,112 +88,4 @@ export class Server {
|
|||||||
server = http.createServer();
|
server = http.createServer();
|
||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
setHandle(handle?: any) {
|
|
||||||
this.handle = handle;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* get callback
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
createCallback() {
|
|
||||||
const path = this.path;
|
|
||||||
const handle = this.handle;
|
|
||||||
const cors = this.cors;
|
|
||||||
const _callback = async (req: IncomingMessage, res: ServerResponse) => {
|
|
||||||
// only handle /api/router
|
|
||||||
if (req.url === '/favicon.ico') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (res.headersSent) {
|
|
||||||
// 程序已经在其他地方响应了
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.hasOn && !req.url.startsWith(path)) {
|
|
||||||
// 其他监听存在,不判断不是当前路径的请求,
|
|
||||||
// 也就是不处理!url.startsWith(path)这个请求了
|
|
||||||
// 交给其他监听处理
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (cors) {
|
|
||||||
res.setHeader('Access-Control-Allow-Origin', cors?.origin || '*'); // 允许所有域名的请求访问,可以根据需要设置具体的域名
|
|
||||||
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
|
|
||||||
res.setHeader('Access-Control-Allow-Methods', 'GET, POST');
|
|
||||||
if (req.method === 'OPTIONS') {
|
|
||||||
res.end();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const url = req.url;
|
|
||||||
if (!url.startsWith(path)) {
|
|
||||||
res.end(resultError(`not path:[${path}]`));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const messages = await handleServer(req, res);
|
|
||||||
if (!handle) {
|
|
||||||
res.end(resultError('no handle'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const end = await handle(messages as any, { req, res });
|
|
||||||
if (res.writableEnded) {
|
|
||||||
// 如果响应已经结束,则不进行任何操作
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
||||||
if (typeof end === 'string') {
|
|
||||||
res.end(end);
|
|
||||||
} else {
|
|
||||||
res.end(JSON.stringify(end));
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
||||||
if (e.code && typeof e.code === 'number') {
|
|
||||||
res.end(resultError(e.message || `Router Server error`, e.code));
|
|
||||||
} else {
|
|
||||||
res.end(resultError('Router Server error'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this._callback = _callback;
|
|
||||||
return _callback;
|
|
||||||
}
|
|
||||||
get handleServer() {
|
|
||||||
return this._callback;
|
|
||||||
}
|
|
||||||
set handleServer(fn: any) {
|
|
||||||
this._callback = fn;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 兜底监听,当除开 `/api/router` 之外的请求,框架只监听一个api,所以有其他的请求都执行其他的监听
|
|
||||||
* @description 主要是为了兼容其他的监听
|
|
||||||
* @param listener
|
|
||||||
*/
|
|
||||||
on(listener: Listener | Listener[]) {
|
|
||||||
this._server = this._server || this.createServer();
|
|
||||||
this._server.removeAllListeners('request');
|
|
||||||
this.hasOn = true;
|
|
||||||
if (Array.isArray(listener)) {
|
|
||||||
listener.forEach((l) => this._server.on('request', l));
|
|
||||||
} else {
|
|
||||||
this._server.on('request', listener);
|
|
||||||
}
|
|
||||||
const callbackListener = this._callback || this.createCallback();
|
|
||||||
this._server.on('request', callbackListener);
|
|
||||||
return () => {
|
|
||||||
if (Array.isArray(listener)) {
|
|
||||||
listener.forEach((l) => this._server.removeListener('request', l as Listener));
|
|
||||||
} else {
|
|
||||||
this._server.removeListener('request', listener as Listener);
|
|
||||||
}
|
|
||||||
this.hasOn = false;
|
|
||||||
this._server.removeListener('request', callbackListener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
get callback() {
|
|
||||||
return this._callback || this.createCallback();
|
|
||||||
}
|
|
||||||
get server() {
|
|
||||||
return this._server;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,39 +1,38 @@
|
|||||||
// @ts-type=ws
|
// @ts-type=ws
|
||||||
import { WebSocketServer } from 'ws';
|
import { WebSocketServer } from 'ws';
|
||||||
import type { WebSocket } from 'ws';
|
import type { WebSocket } from 'ws';
|
||||||
import { Server } from './server.ts';
|
import { ServerType } from './server-type.ts'
|
||||||
import { parseIfJson } from '../utils/parse.ts';
|
import { parseIfJson } from '../utils/parse.ts';
|
||||||
|
import { isBun } from '../utils/is-engine.ts';
|
||||||
|
|
||||||
|
|
||||||
export const createWsServer = (server: Server) => {
|
export const createWsServer = (server: ServerType) => {
|
||||||
// 将 WebSocket 服务器附加到 HTTP 服务器
|
// 将 WebSocket 服务器附加到 HTTP 服务器
|
||||||
const wss = new WebSocketServer({ server: server.server as any });
|
const wss = new WebSocketServer({ server: server.server as any });
|
||||||
return wss;
|
return wss;
|
||||||
};
|
};
|
||||||
type WsServerBaseOpts = {
|
type WsServerBaseOpts = {
|
||||||
wss?: WebSocketServer;
|
wss?: WebSocketServer | null;
|
||||||
path?: string;
|
path?: string;
|
||||||
};
|
};
|
||||||
export type ListenerFn = (message: { data: Record<string, any>; ws: WebSocket; end: (data: any) => any }) => Promise<any>;
|
export type ListenerFn = (message: { data: Record<string, any>; ws: WebSocket; end: (data: any) => any }) => Promise<any>;
|
||||||
export type Listener<T = 'router' | 'chat' | 'ai'> = {
|
export type Listener<T = 'router' | 'chat' | 'ai'> = {
|
||||||
type: T;
|
type: T;
|
||||||
|
path?: string;
|
||||||
listener: ListenerFn;
|
listener: ListenerFn;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class WsServerBase {
|
export class WsServerBase {
|
||||||
wss: WebSocketServer;
|
wss: WebSocketServer | null;
|
||||||
path: string;
|
listeners: Listener[] = [];
|
||||||
listeners: { type: string; listener: ListenerFn }[] = [];
|
|
||||||
listening: boolean = false;
|
listening: boolean = false;
|
||||||
|
server: ServerType;
|
||||||
|
|
||||||
constructor(opts: WsServerBaseOpts) {
|
constructor(opts: WsServerBaseOpts) {
|
||||||
this.wss = opts.wss;
|
this.wss = opts.wss;
|
||||||
if (!this.wss) {
|
if (!this.wss && !isBun) {
|
||||||
throw new Error('wss is required');
|
throw new Error('wss is required');
|
||||||
}
|
}
|
||||||
this.path = opts.path || '';
|
|
||||||
}
|
|
||||||
setPath(path: string) {
|
|
||||||
this.path = path;
|
|
||||||
}
|
}
|
||||||
listen() {
|
listen() {
|
||||||
if (this.listening) {
|
if (this.listening) {
|
||||||
@@ -42,116 +41,49 @@ export class WsServerBase {
|
|||||||
}
|
}
|
||||||
this.listening = true;
|
this.listening = true;
|
||||||
|
|
||||||
this.wss.on('connection', (ws) => {
|
if (!this.wss) {
|
||||||
ws.on('message', async (message: string | Buffer) => {
|
// Bun 环境下,wss 可能为 null
|
||||||
const data = parseIfJson(message);
|
return;
|
||||||
if (typeof data === 'string') {
|
}
|
||||||
const cleanMessage = data.trim().replace(/^["']|["']$/g, '');
|
|
||||||
ws.emit('string', cleanMessage);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const { type, data: typeData, ...rest } = data;
|
|
||||||
if (!type) {
|
|
||||||
ws.send(JSON.stringify({ code: 500, message: 'type is required' }));
|
|
||||||
}
|
|
||||||
const listeners = this.listeners.find((item) => item.type === type);
|
|
||||||
const res = {
|
|
||||||
type,
|
|
||||||
data: {} as any,
|
|
||||||
...rest,
|
|
||||||
};
|
|
||||||
const end = (data: any, all?: Record<string, any>) => {
|
|
||||||
const result = {
|
|
||||||
...res,
|
|
||||||
data,
|
|
||||||
...all,
|
|
||||||
};
|
|
||||||
ws.send(JSON.stringify(result));
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!listeners) {
|
this.wss.on('connection', (ws, req) => {
|
||||||
const data = { code: 500, message: `${type} server is error` };
|
const url = new URL(req.url, 'http://localhost');
|
||||||
end(data);
|
const pathname = url.pathname;
|
||||||
return;
|
const token = url.searchParams.get('token') || '';
|
||||||
}
|
const id = url.searchParams.get('id') || '';
|
||||||
listeners.listener({
|
ws.on('message', async (message: string | Buffer) => {
|
||||||
data: typeData,
|
await this.server.onWebSocket({ ws, message, pathname, token, id });
|
||||||
ws,
|
|
||||||
end: end,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
ws.on('string', (message: string) => {
|
|
||||||
if (message === 'close') {
|
|
||||||
ws.close();
|
|
||||||
}
|
|
||||||
if (message == 'ping') {
|
|
||||||
ws.send('pong');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
ws.send('connected');
|
ws.send('connected');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
addListener(type: string, listener: ListenerFn) {
|
|
||||||
if (!type || !listener) {
|
|
||||||
throw new Error('type and listener is required');
|
|
||||||
}
|
|
||||||
const find = this.listeners.find((item) => item.type === type);
|
|
||||||
if (find) {
|
|
||||||
this.listeners = this.listeners.filter((item) => item.type !== type);
|
|
||||||
}
|
|
||||||
this.listeners.push({ type, listener });
|
|
||||||
}
|
|
||||||
removeListener(type: string) {
|
|
||||||
this.listeners = this.listeners.filter((item) => item.type !== type);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// TODO: ws handle and path and routerContext
|
// TODO: ws handle and path and routerContext
|
||||||
export class WsServer extends WsServerBase {
|
export class WsServer extends WsServerBase {
|
||||||
server: Server;
|
constructor(server: ServerType) {
|
||||||
constructor(server: Server, opts?: any) {
|
const wss = isBun ? null : new WebSocketServer({ noServer: true });
|
||||||
const wss = new WebSocketServer({ noServer: true });
|
|
||||||
const path = server.path;
|
|
||||||
super({ wss });
|
super({ wss });
|
||||||
this.server = server;
|
this.server = server;
|
||||||
this.setPath(opts?.path || path);
|
|
||||||
this.initListener();
|
|
||||||
}
|
|
||||||
initListener() {
|
|
||||||
const server = this.server;
|
|
||||||
const listener: Listener = {
|
|
||||||
type: 'router',
|
|
||||||
listener: async ({ data, ws, end }) => {
|
|
||||||
if (!server) {
|
|
||||||
end({ code: 500, message: 'server handle is error' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const handle = this.server.handle;
|
|
||||||
try {
|
|
||||||
const result = await handle(data as any);
|
|
||||||
end(result);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.code && typeof e.code === 'number') {
|
|
||||||
end({
|
|
||||||
code: e.code,
|
|
||||||
message: e.message,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
end({ code: 500, message: 'Router Server error' });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
this.addListener(listener.type, listener.listener);
|
|
||||||
}
|
}
|
||||||
listen() {
|
listen() {
|
||||||
|
if (isBun) {
|
||||||
|
// Bun 的 WebSocket 在 Bun.serve 中处理,这里不需要额外操作
|
||||||
|
// WebSocket 升级会在 listenWithBun 中处理
|
||||||
|
this.listening = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
super.listen();
|
super.listen();
|
||||||
const server = this.server;
|
const server = this.server;
|
||||||
const wss = this.wss;
|
const wss = this.wss;
|
||||||
|
|
||||||
// HTTP 服务器的 upgrade 事件
|
// HTTP 服务器的 upgrade 事件
|
||||||
|
// @ts-ignore
|
||||||
server.server.on('upgrade', (req, socket, head) => {
|
server.server.on('upgrade', (req, socket, head) => {
|
||||||
if (req.url === this.path) {
|
const url = new URL(req.url, 'http://localhost');
|
||||||
|
const listenPath = this.server.listeners.map((item) => item.path).filter((item) => item);
|
||||||
|
if (listenPath.includes(url.pathname) || url.pathname === this.server.path) {
|
||||||
wss.handleUpgrade(req, socket, head, (ws) => {
|
wss.handleUpgrade(req, socket, head, (ws) => {
|
||||||
// 这里手动触发 connection 事件
|
// 这里手动触发 connection事件
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
wss.emit('connection', ws, req);
|
wss.emit('connection', ws, req);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// import { Server } from 'node:http';
|
// import { Server } from 'node:http';
|
||||||
import { Server } from '../server/server.ts'
|
import { ServerNode } from '../server/server.ts'
|
||||||
|
|
||||||
const server = new Server({
|
const server = new ServerNode({
|
||||||
path: '/',
|
path: '/',
|
||||||
handle: async (data, ctx) => {
|
handle: async (data, ctx) => {
|
||||||
console.log('ctx', ctx.req.url)
|
console.log('ctx', ctx.req.url)
|
||||||
|
|||||||
@@ -2,9 +2,13 @@ export const isNode = typeof process !== 'undefined' && process.versions != null
|
|||||||
export const isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined' && typeof document.createElement === 'function';
|
export const isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined' && typeof document.createElement === 'function';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
export const isDeno = typeof Deno !== 'undefined' && typeof Deno.version === 'object' && typeof Deno.version.deno === 'string';
|
export const isDeno = typeof Deno !== 'undefined' && typeof Deno.version === 'object' && typeof Deno.version.deno === 'string';
|
||||||
|
// @ts-ignore
|
||||||
|
export const isBun = typeof Bun !== 'undefined' && typeof Bun.version === 'string';
|
||||||
|
|
||||||
export const getEngine = () => {
|
export const getEngine = () => {
|
||||||
if (isNode) {
|
if (isBun) {
|
||||||
|
return 'bun';
|
||||||
|
} else if (isNode) {
|
||||||
return 'node';
|
return 'node';
|
||||||
} else if (isBrowser) {
|
} else if (isBrowser) {
|
||||||
return 'browser';
|
return 'browser';
|
||||||
|
|||||||
Reference in New Issue
Block a user