mirror of https://github.com/186526/handlers.js
Add CI & Deno Supported & Fix a lot of bugs & Webpack for building package
This commit is contained in:
parent
b3552cb6a2
commit
057c9b9cb5
|
@ -0,0 +1,14 @@
|
|||
# [Choice] Node.js version (use -bullseye variants on local arm64/Apple Silicon): 18, 16, 14, 18-bullseye, 16-bullseye, 14-bullseye, 18-buster, 16-buster, 14-buster
|
||||
ARG VARIANT=16-bullseye
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/typescript-node:0-${VARIANT}
|
||||
|
||||
# [Optional] Uncomment this section to install additional OS packages.
|
||||
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||
# && apt-get -y install --no-install-recommends <your-package-list-here>
|
||||
|
||||
# [Optional] Uncomment if you want to install an additional version of node using nvm
|
||||
# ARG EXTRA_NODE_VERSION=10
|
||||
# RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}"
|
||||
|
||||
# [Optional] Uncomment if you want to install more global node packages
|
||||
# RUN su node -c "npm install -g <your-package-list -here>"
|
|
@ -0,0 +1,17 @@
|
|||
# [Choice] Node.js version (use -bullseye variants on local arm64/Apple Silicon): 18, 16, 14, 18-bullseye, 16-bullseye, 14-bullseye, 18-buster, 16-buster, 14-buster
|
||||
ARG VARIANT=16-bullseye
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT}
|
||||
|
||||
# Install tslint, typescript. eslint is installed by javascript image
|
||||
ARG NODE_MODULES="tslint-to-eslint-config typescript"
|
||||
COPY library-scripts/meta.env /usr/local/etc/vscode-dev-containers
|
||||
RUN su node -c "umask 0002 && npm install -g ${NODE_MODULES}" \
|
||||
&& npm cache clean --force > /dev/null 2>&1
|
||||
|
||||
# [Optional] Uncomment this section to install additional OS packages.
|
||||
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||
# && apt-get -y install --no-install-recommends <your-package-list-here>
|
||||
|
||||
# [Optional] Uncomment if you want to install an additional version of node using nvm
|
||||
# ARG EXTRA_NODE_VERSION=10
|
||||
# RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}"
|
|
@ -0,0 +1,39 @@
|
|||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
|
||||
// https://github.com/microsoft/vscode-dev-containers/tree/v0.238.1/containers/typescript-node
|
||||
{
|
||||
"name": "Node.js & TypeScript",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile",
|
||||
// Update 'VARIANT' to pick a Node version: 18, 16, 14.
|
||||
// Append -bullseye or -buster to pin to an OS version.
|
||||
// Use -bullseye variants on local on arm64/Apple Silicon.
|
||||
"args": {
|
||||
"VARIANT": "16-bullseye"
|
||||
}
|
||||
},
|
||||
|
||||
// Configure tool-specific properties.
|
||||
"customizations": {
|
||||
// Configure properties specific to VS Code.
|
||||
"vscode": {
|
||||
// Add the IDs of extensions you want installed when the container is created.
|
||||
"extensions": [
|
||||
"dbaeumer.vscode-eslint",
|
||||
"ms-vscode.vscode-typescript-next",
|
||||
"oderwat.indent-rainbow",
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
// "forwardPorts": [],
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
"postCreateCommand": "yarn install",
|
||||
|
||||
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
||||
"remoteUser": "node",
|
||||
"features": {
|
||||
"git": "latest"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
name: CI
|
||||
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [14.x, 16.x, 18.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Install dependencies
|
||||
run: yarn install
|
||||
- name: Test handlers.js
|
||||
run: yarn test
|
|
@ -1,3 +1,5 @@
|
|||
{
|
||||
"compile-hero.disable-compile-files-on-did-save-code": false
|
||||
"compile-hero.disable-compile-files-on-did-save-code": true,
|
||||
"deno.enable": false,
|
||||
"editor.formatOnSave": true,
|
||||
}
|
|
@ -4,7 +4,6 @@ import {
|
|||
handler,
|
||||
route,
|
||||
response,
|
||||
ChainInterrupted,
|
||||
} from "../index";
|
||||
import errorHandler from "./errorHandler";
|
||||
|
||||
|
@ -25,10 +24,18 @@ App.binding(
|
|||
App.create(
|
||||
"ANY",
|
||||
(): Promise<string> =>
|
||||
new Promise((resolve) => {
|
||||
new Promise(() => {
|
||||
console.log("Hello World!");
|
||||
resolve("Hello World!");
|
||||
throw ChainInterrupted;
|
||||
throw new response("Hello World!");
|
||||
})
|
||||
)
|
||||
).binding(
|
||||
"/(.*)",
|
||||
App.create(
|
||||
"ANY",
|
||||
(): Promise<string> =>
|
||||
new Promise((resolve) => {
|
||||
resolve("Hello World?")
|
||||
})
|
||||
)
|
||||
);
|
||||
|
|
1
index.ts
1
index.ts
|
@ -6,7 +6,6 @@ export { router } from "./src/router";
|
|||
export { methodENUM as method } from "./src/interface/method";
|
||||
export { response } from "./src/interface/response";
|
||||
export { request } from "./src/interface/request";
|
||||
export { ChainInterrupted } from "./src/interface/index";
|
||||
export * as platformAdapater from "./src/platform/export";
|
||||
|
||||
export { rootRouter };
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
|
||||
export default {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
forceExit: true
|
||||
};
|
23
package.json
23
package.json
|
@ -20,22 +20,35 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "^3.13.0",
|
||||
"@types/jest": "^28.1.4",
|
||||
"@types/node": "^18.0.0",
|
||||
"@webpack-cli/generators": "^2.5.0",
|
||||
"axios": "^0.27.2",
|
||||
"jest": "^28.1.2",
|
||||
"prettier": "^2.7.1",
|
||||
"ts-jest": "^28.0.5",
|
||||
"ts-loader": "^9.3.1",
|
||||
"ts-node": "^10.8.1",
|
||||
"typescript": "^4.7.4",
|
||||
"webpack": "^5.73.0",
|
||||
"webpack-cli": "^4.10.0"
|
||||
},
|
||||
"sideEffects": false,
|
||||
"scripts": {
|
||||
"build": "yarn build:node && yarn build:webworker",
|
||||
"build:node": "TARGET=node webpack",
|
||||
"build:webworker": "TARGET=webworker webpack",
|
||||
"watch": "webpack --watch"
|
||||
"build": "yarn clean && yarn build:node && yarn build:serviceworker && yarn build:cfworker && yarn build:deno",
|
||||
"build:node": "BUILD_TARGET=node webpack",
|
||||
"build:serviceworker": "BUILD_TARGET=serviceworker webpack",
|
||||
"build:cfworker": "BUILD_TARGET=cfworker webpack",
|
||||
"build:deno": "BUILD_TARGET=deno webpack",
|
||||
"watch": "webpack --watch",
|
||||
"clean": "rm -rf ./dist",
|
||||
"demo": "env NODE_ENV=development yarn build:node && node ./dist/main.node.js",
|
||||
"tsc": "tsc",
|
||||
"test": "jest",
|
||||
"coverage": "jest --collectCoverage --"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"type": "module"
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
console.log("Hello World!");
|
|
@ -3,6 +3,5 @@ export { response } from "./response";
|
|||
export { method } from "./method";
|
||||
export { headers } from "./headers";
|
||||
export { responder } from "./responder";
|
||||
export const ChainInterrupted = new Error("ChainInterrupted");
|
||||
export const AllMismatchInterrupted = new Error("AllMismatchInterrupted");
|
||||
export type path = string | RegExp;
|
||||
|
|
|
@ -56,6 +56,6 @@ export enum methodENUM {
|
|||
ANY = "ANY",
|
||||
}
|
||||
|
||||
export type method = methodENUM | string;
|
||||
export type method = "CONNECT" | "DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PUT" | "TRACE" | "ANY" | methodENUM;
|
||||
|
||||
export default method;
|
16
src/lib.ts
16
src/lib.ts
|
@ -4,17 +4,23 @@ export const platform = (() => {
|
|||
if (typeof process != "undefined") {
|
||||
return "Node.js";
|
||||
}
|
||||
if (typeof self != "undefined") {
|
||||
return "Web Worker";
|
||||
if (typeof Deno != "undefined") {
|
||||
return "Deno";
|
||||
}
|
||||
|
||||
return "Unknown";
|
||||
if (typeof self != "undefined") {
|
||||
return "Service Worker";
|
||||
}
|
||||
return undefined;
|
||||
})();
|
||||
export const version = (() => {
|
||||
switch (platform) {
|
||||
case "Node.js":
|
||||
return process.version;
|
||||
case "Deno":
|
||||
return Deno.version.deno;
|
||||
case "Service Worker":
|
||||
return undefined;
|
||||
default:
|
||||
return "Unknown";
|
||||
return undefined;
|
||||
}
|
||||
})();
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
import { SWPlatformAdapter } from "./serviceworker";
|
||||
import { platformAdapater } from "./index";
|
||||
|
||||
import { request } from "../interface/request";
|
||||
import { headers } from "../interface/headers";
|
||||
import { methodENUM } from "src/interface/method";
|
||||
|
||||
|
||||
const DefaultConn: Deno.Conn = {
|
||||
localAddr: {
|
||||
transport: "tcp",
|
||||
hostname: "0.0.0.0",
|
||||
port: 80,
|
||||
},
|
||||
remoteAddr: {
|
||||
transport: "tcp",
|
||||
hostname: "0.0.0.0",
|
||||
port: 80,
|
||||
},
|
||||
rid: 0,
|
||||
closeWrite: async () => undefined,
|
||||
readable: "",
|
||||
writable: "",
|
||||
read: async (p: Uint8Array) => null,
|
||||
write: async (p: Uint8Array) => 0,
|
||||
close: () => undefined,
|
||||
};
|
||||
|
||||
export class DenoPlatformAdapter<T = any, K = any>
|
||||
extends SWPlatformAdapter<T, K>
|
||||
implements platformAdapater<T, K>
|
||||
{
|
||||
async listen(port: number): Promise<void> {
|
||||
const Server: Deno.Listener = Deno.listen({ port });
|
||||
|
||||
for await (const connection of Server) {
|
||||
const httpConnection = Deno.serveHttp(connection);
|
||||
|
||||
for await (const requestEvent of httpConnection) {
|
||||
requestEvent.respondWith(this.handler(requestEvent, connection));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async handleRequest(nativeRequest: Request, connection: Deno.Conn = DefaultConn): Promise<request<T>> {
|
||||
const requestHeaders = new headers(
|
||||
Object.fromEntries(nativeRequest.headers.entries())
|
||||
);
|
||||
const requestMessage: request<T> = new request(
|
||||
<methodENUM>nativeRequest.method,
|
||||
new URL(nativeRequest.url),
|
||||
requestHeaders,
|
||||
await nativeRequest.text(),
|
||||
{},
|
||||
`${connection.remoteAddr.hostname}:${connection.remoteAddr.port}` || ""
|
||||
);
|
||||
return requestMessage;
|
||||
}
|
||||
|
||||
async handler(event: FetchEvent, connection: Deno.Conn = DefaultConn): Promise<Response> {
|
||||
return await this.handleResponse(
|
||||
await this.handleRequest(event.request, connection).then((request) =>
|
||||
this.router.respond(request)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
import { NodePlatformAdapter } from "./node";
|
||||
import { SWPlatformAdapter } from "./serviceworker";
|
||||
import { DenoPlatformAdapter } from "./deno";
|
||||
|
||||
export const platformAdapaterMapping = {
|
||||
"Node.js": NodePlatformAdapter,
|
||||
"Web Worker": SWPlatformAdapter,
|
||||
"Service Worker": SWPlatformAdapter,
|
||||
"Deno": DenoPlatformAdapter,
|
||||
};
|
||||
|
||||
export { NodePlatformAdapter, SWPlatformAdapter };
|
||||
export { NodePlatformAdapter, SWPlatformAdapter, DenoPlatformAdapter };
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { request, response } from "../interface";
|
||||
import { router } from "../../index";
|
||||
import { request, response } from "../interface/index";
|
||||
import { router } from "../router";
|
||||
|
||||
export interface platformAdapater<T = any, K = any> {
|
||||
router: router<T, K>;
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { platformAdapater } from "./index";
|
||||
import { request, response } from "../interface";
|
||||
import { request, response } from "../interface/index";
|
||||
import { router } from "../router";
|
||||
import { headers } from "../interface/headers";
|
||||
|
||||
import http from "http";
|
||||
import { methodENUM } from "src/interface/method";
|
||||
|
||||
export class NodePlatformAdapter<T = any, K = any> implements platformAdapater {
|
||||
public router: router<T, K>;
|
||||
|
@ -38,7 +39,7 @@ export class NodePlatformAdapter<T = any, K = any> implements platformAdapater {
|
|||
}
|
||||
|
||||
let body: string = "";
|
||||
const ip: string = nativeRequest.socket.remoteAddress?.replace("::ffff:","") ?? "0.0.0.0";
|
||||
const ip: string = nativeRequest.socket.remoteAddress?.replace("::ffff:", "") ?? "0.0.0.0";
|
||||
const requestHeaders = new headers(<any>nativeRequest.headers);
|
||||
|
||||
if (!["GET", "HEAD", "DELETE", "OPTIONS"].includes(nativeRequest.method)) {
|
||||
|
@ -54,7 +55,7 @@ export class NodePlatformAdapter<T = any, K = any> implements platformAdapater {
|
|||
}
|
||||
|
||||
return new request<T>(
|
||||
nativeRequest.method,
|
||||
<methodENUM>nativeRequest.method,
|
||||
new URL(
|
||||
nativeRequest.url,
|
||||
`http://${requestHeaders.get("host") ?? "localhost"}`
|
||||
|
|
|
@ -4,6 +4,8 @@ import { response } from "../interface/response";
|
|||
import { router } from "../router";
|
||||
import { headers } from "../interface/headers";
|
||||
|
||||
import { methodENUM } from "src/interface/method";
|
||||
|
||||
export class SWPlatformAdapter<T = any, K = any> implements platformAdapater {
|
||||
public router: router<T, K>;
|
||||
|
||||
|
@ -22,7 +24,7 @@ export class SWPlatformAdapter<T = any, K = any> implements platformAdapater {
|
|||
Object.fromEntries(nativeRequest.headers.entries())
|
||||
);
|
||||
const requestMessage: request<T> = new request(
|
||||
nativeRequest.method,
|
||||
<methodENUM>nativeRequest.method,
|
||||
new URL(nativeRequest.url),
|
||||
requestHeaders,
|
||||
await nativeRequest.text(),
|
||||
|
|
|
@ -3,7 +3,6 @@ import {
|
|||
path,
|
||||
response,
|
||||
request,
|
||||
ChainInterrupted,
|
||||
AllMismatchInterrupted,
|
||||
responder,
|
||||
method,
|
||||
|
@ -132,8 +131,8 @@ export class router<K = any, V = any> {
|
|||
throw AllMismatchInterrupted;
|
||||
}
|
||||
} catch (e) {
|
||||
if (e === ChainInterrupted) {
|
||||
return e.response;
|
||||
if (e instanceof response) {
|
||||
throw e;
|
||||
}
|
||||
if (e === AllMismatchInterrupted) mismatchCount++;
|
||||
else {
|
||||
|
@ -183,16 +182,16 @@ export class rootRouter<K = any, V = any> extends router<K, V> {
|
|||
public adapater: platformAdapater<K, V>;
|
||||
errorResponder =
|
||||
(errorCode: number, errorMessage?: string) =>
|
||||
async (_request: request<K>): Promise<response<V>> =>
|
||||
new response(errorMessage ?? "", errorCode);
|
||||
async (_request: request<K>): Promise<response<V>> =>
|
||||
new response(errorMessage ?? "", errorCode);
|
||||
|
||||
respond = async (request: request<K>): Promise<response<V>> => {
|
||||
let responseMessage: response<V> = new response("");
|
||||
try {
|
||||
responseMessage = await this._respond(request, responseMessage);
|
||||
} catch (e) {
|
||||
if (e === ChainInterrupted) {
|
||||
return responseMessage;
|
||||
if (e instanceof response) {
|
||||
return e;
|
||||
} else if (e === AllMismatchInterrupted) {
|
||||
responseMessage =
|
||||
(await this.errorResponder(404, "404 Not Found\n")(request)) ??
|
||||
|
@ -214,7 +213,8 @@ export class rootRouter<K = any, V = any> extends router<K, V> {
|
|||
useMappingAdapter(
|
||||
mapping: { [platform: string]: platformAdapaterConstructor } = platformAdapaterMapping
|
||||
): this {
|
||||
if(mapping[platform] == undefined) throw new Error("Platform not found in mapping");
|
||||
if (typeof platform == "undefined") throw new Error("Cannot detect platform");
|
||||
if (mapping[platform] == undefined) throw new Error("Platform not found in mapping");
|
||||
else this.useAdapater(mapping[platform]);
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
import _ from "./test-server";
|
||||
|
||||
import Axios from "axios";
|
||||
|
||||
_.listen(3000);
|
||||
|
||||
const Instance = Axios.create({
|
||||
baseURL: "http://localhost:3000"
|
||||
})
|
||||
|
||||
const randomString = () => Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
|
||||
|
||||
describe("Test server", () => {
|
||||
test("normal 200 response", async () => {
|
||||
expect.assertions(2);
|
||||
|
||||
const { data, status } = await Instance.get("/");
|
||||
expect(status).toEqual(200);
|
||||
expect(data).toEqual("200 OK");
|
||||
})
|
||||
|
||||
test("post response", async () => {
|
||||
expect.assertions(2);
|
||||
const string = randomString();
|
||||
|
||||
const { data, status } = await Instance.post("/post", string);
|
||||
|
||||
expect(status).toEqual(200);
|
||||
expect(data).toEqual(string);
|
||||
})
|
||||
|
||||
test("change header and status code", async () => {
|
||||
expect.assertions(3);
|
||||
|
||||
const { data, status, headers } = await Instance.get("/header");
|
||||
|
||||
expect(status).toEqual(204);
|
||||
expect(headers["itis"]).toEqual("work");
|
||||
expect(data).toEqual("");
|
||||
})
|
||||
|
||||
test("get param", async () => {
|
||||
expect.assertions(2);
|
||||
|
||||
const string = randomString();
|
||||
const { data, status } = await Instance.get(`/info/${string}`);
|
||||
|
||||
expect(status).toEqual(200);
|
||||
expect(data).toEqual(string);
|
||||
})
|
||||
|
||||
test("chain interrupted", async () => {
|
||||
expect.assertions(2);
|
||||
|
||||
const { data, status } = await Instance.get(`/info/foo`);
|
||||
|
||||
expect(status).toEqual(200);
|
||||
expect(data).toEqual("hit");
|
||||
})
|
||||
})
|
|
@ -0,0 +1,25 @@
|
|||
import * as handlersJS from '../index';
|
||||
|
||||
const App = new handlersJS.rootRouter();
|
||||
|
||||
App.binding("/", App.create("GET", async () => "200 OK"));
|
||||
|
||||
App.binding("/post", App.create("POST", async (request: handlersJS.request<any>) => request.body));
|
||||
|
||||
App.binding("/header", App.create("GET", async () => {
|
||||
const response = new handlersJS.response<any>("");
|
||||
response.status = 204;
|
||||
response.headers.set("itis", "work");
|
||||
return response;
|
||||
}));
|
||||
|
||||
App
|
||||
.route("/info/(.*)")
|
||||
.binding("/foo", App.create("GET", (): Promise<handlersJS.response<any>> => new Promise(resolve => {
|
||||
throw new handlersJS.response("hit")
|
||||
})))
|
||||
.binding("/(.*)", App.create("GET", async (request: handlersJS.request<any>) => request.params[0] ?? "not found"));
|
||||
|
||||
App.useMappingAdapter();
|
||||
|
||||
export default App;
|
|
@ -1,14 +1,9 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"module": "commonjs",
|
||||
"lib": [
|
||||
"ESNext",
|
||||
],
|
||||
"types": [
|
||||
"@cloudflare/workers-types",
|
||||
"@types/node",
|
||||
],
|
||||
"module": "esnext",
|
||||
"lib": ["ESNext"],
|
||||
"types": ["@cloudflare/workers-types", "@types/node", "@types/jest"],
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
|
@ -28,18 +23,12 @@
|
|||
"experimentalDecorators": true,
|
||||
"resolveJsonModule": true,
|
||||
"baseUrl": ".",
|
||||
"plugins": [
|
||||
{
|
||||
"transform": "@zerollup/ts-transform-paths",
|
||||
}
|
||||
],
|
||||
"plugins": [{
|
||||
"transform": "@zerollup/ts-transform-paths"
|
||||
}],
|
||||
"declaration": true
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
],
|
||||
"include": [
|
||||
"index.ts",
|
||||
"src/**/*.ts",
|
||||
"demo/**/*.ts",
|
||||
],
|
||||
"exclude": ["node_modules"],
|
||||
"include": ["index.ts", "src/**/*.ts", "demo/**/*.ts", "types/deno.d.ts"],
|
||||
// "esm": true
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
declare namespace Deno {
|
||||
export const version: {
|
||||
/** Deno's version. For example: `"1.0.0"` */
|
||||
deno: string;
|
||||
/** The V8 version used by Deno. For example: `"8.0.0.0"` */
|
||||
v8: string;
|
||||
/** The TypeScript version used by Deno. For example: `"4.0.0"` */
|
||||
typescript: string;
|
||||
};
|
||||
|
||||
export interface NetAddr {
|
||||
transport: "tcp" | "udp";
|
||||
hostname: string;
|
||||
port: number;
|
||||
}
|
||||
|
||||
export type Addr = NetAddr;
|
||||
|
||||
export interface Closer {
|
||||
close(): void;
|
||||
}
|
||||
|
||||
export interface Reader {
|
||||
/** Reads up to `p.byteLength` bytes into `p`. It resolves to the number of
|
||||
* bytes read (`0` < `n` <= `p.byteLength`) and rejects if any error
|
||||
* encountered. Even if `read()` resolves to `n` < `p.byteLength`, it may
|
||||
* use all of `p` as scratch space during the call. If some data is
|
||||
* available but not `p.byteLength` bytes, `read()` conventionally resolves
|
||||
* to what is available instead of waiting for more.
|
||||
*
|
||||
* When `read()` encounters end-of-file condition, it resolves to EOF
|
||||
* (`null`).
|
||||
*
|
||||
* When `read()` encounters an error, it rejects with an error.
|
||||
*
|
||||
* Callers should always process the `n` > `0` bytes returned before
|
||||
* considering the EOF (`null`). Doing so correctly handles I/O errors that
|
||||
* happen after reading some bytes and also both of the allowed EOF
|
||||
* behaviors.
|
||||
*
|
||||
* Implementations should not retain a reference to `p`.
|
||||
*
|
||||
* Use `itereateReader` from from https://deno.land/std/streams/conversion.ts to
|
||||
* turn a Reader into an AsyncIterator.
|
||||
*/
|
||||
read(p: Uint8Array): Promise<number | null>;
|
||||
}
|
||||
|
||||
export interface Writer {
|
||||
/** Writes `p.byteLength` bytes from `p` to the underlying data stream. It
|
||||
* resolves to the number of bytes written from `p` (`0` <= `n` <=
|
||||
* `p.byteLength`) or reject with the error encountered that caused the
|
||||
* write to stop early. `write()` must reject with a non-null error if
|
||||
* would resolve to `n` < `p.byteLength`. `write()` must not modify the
|
||||
* slice data, even temporarily.
|
||||
*
|
||||
* Implementations should not retain a reference to `p`.
|
||||
*/
|
||||
write(p: Uint8Array): Promise<number>;
|
||||
}
|
||||
|
||||
export interface Conn extends Reader, Writer, Closer {
|
||||
/** The local address of the connection. */
|
||||
readonly localAddr: Addr;
|
||||
/** The remote address of the connection. */
|
||||
readonly remoteAddr: Addr;
|
||||
/** The resource ID of the connection. */
|
||||
readonly rid: number;
|
||||
/** Shuts down (`shutdown(2)`) the write side of the connection. Most
|
||||
* callers should just use `close()`. */
|
||||
closeWrite(): Promise<void>;
|
||||
|
||||
readonly readable: ReadableStream<Uint8Array>;
|
||||
readonly writable: WritableStream<Uint8Array>;
|
||||
}
|
||||
|
||||
/** A generic network listener for stream-oriented protocols. */
|
||||
export interface Listener extends AsyncIterable<Conn> {
|
||||
/** Waits for and resolves to the next connection to the `Listener`. */
|
||||
accept(): Promise<Conn>;
|
||||
/** Close closes the listener. Any pending accept promises will be rejected
|
||||
* with errors. */
|
||||
close(): void;
|
||||
/** Return the address of the `Listener`. */
|
||||
readonly addr: Addr;
|
||||
|
||||
/** Return the rid of the `Listener`. */
|
||||
readonly rid: number;
|
||||
|
||||
[Symbol.asyncIterator](): AsyncIterableIterator<Conn>;
|
||||
}
|
||||
|
||||
export interface ListenOptions {
|
||||
port: number;
|
||||
}
|
||||
|
||||
export function listen(
|
||||
options: ListenOptions & { transport?: "tcp" }
|
||||
): Listener;
|
||||
|
||||
export function serveHttp(conn: Conn): HttpConn;
|
||||
|
||||
export interface HttpConn extends AsyncIterable<FetchEvent> {
|
||||
readonly rid: number;
|
||||
|
||||
nextRequest(): Promise<FetchEvent | null>;
|
||||
close(): void;
|
||||
}
|
||||
}
|
|
@ -1,12 +1,20 @@
|
|||
// Generated using webpack-cli https://github.com/webpack/webpack-cli
|
||||
|
||||
const path = require("path");
|
||||
import path from "path";
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
const isProduction = process.env.NODE_ENV == "production";
|
||||
|
||||
const config = {
|
||||
output: {
|
||||
path: path.resolve(__dirname, "dist"),
|
||||
chunkFormat: "module",
|
||||
library: {
|
||||
type: 'module',
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
// Add your plugins here
|
||||
|
@ -30,9 +38,12 @@ const config = {
|
|||
"http": false
|
||||
}
|
||||
},
|
||||
experiments: {
|
||||
outputModule: true,
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = () => {
|
||||
export default () => {
|
||||
if (isProduction) {
|
||||
config.mode = "production";
|
||||
config.entry = "./index.ts";
|
||||
|
@ -40,14 +51,23 @@ module.exports = () => {
|
|||
config.mode = "development";
|
||||
config.entry = "./demo/index.ts";
|
||||
}
|
||||
switch(process.env.TARGET) {
|
||||
switch (process.env.BUILD_TARGET) {
|
||||
case "node":
|
||||
config.target = "node14";
|
||||
config.target = "node12";
|
||||
config.output.filename = "main.node.js";
|
||||
break;
|
||||
case "webworker":
|
||||
case "serviceworker":
|
||||
config.target = "webworker";
|
||||
config.output.filename = "main.webworker.js";
|
||||
config.output.filename = "main.serviceworker.js";
|
||||
break;
|
||||
case "deno":
|
||||
config.target = "webworker";
|
||||
config.output.filename = "main.deno.js";
|
||||
break;
|
||||
case "cfworker":
|
||||
config.mode = "production";
|
||||
config.target = "webworker";
|
||||
config.output.filename = "main.cfworker.js";
|
||||
break;
|
||||
default:
|
||||
config.target = "es6";
|
||||
|
|
Loading…
Reference in New Issue