feat(transport): extract @webnet/transport package
Pulls RawTransport, RawDialer, RawListener, Reader, Writer, and PairSync out of @webnet/http into a new protocol-agnostic @webnet/transport package. Node and loopback transport implementations move there as sub-exports (./node, ./loopback); @webnet/http re-exports the types to keep existing internal imports resolving. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Generated
+29
@@ -4908,6 +4908,10 @@
|
||||
"resolved": "packages/test-app",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@webnet/transport": {
|
||||
"resolved": "packages/transport",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@webnet/tsconnect": {
|
||||
"resolved": "packages/tsconnect",
|
||||
"link": true
|
||||
@@ -12519,6 +12523,7 @@
|
||||
"name": "@webnet/http",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@webnet/transport": "*",
|
||||
"regexparam": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -12568,6 +12573,30 @@
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"packages/transport": {
|
||||
"name": "@webnet/transport",
|
||||
"version": "0.1.0",
|
||||
"devDependencies": {
|
||||
"@types/node": "^25.6.0",
|
||||
"c8": "^11.0.0",
|
||||
"tsx": "^4.21.0",
|
||||
"typescript": "^6.0.2"
|
||||
}
|
||||
},
|
||||
"packages/transport/node_modules/typescript": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz",
|
||||
"integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"packages/tsconnect": {
|
||||
"name": "@webnet/tsconnect",
|
||||
"version": "0.1.0",
|
||||
|
||||
@@ -38,22 +38,6 @@
|
||||
"types": "./dist/server/_internals.d.ts",
|
||||
"default": "./dist/server/_internals.js"
|
||||
},
|
||||
"./node": {
|
||||
"types": "./dist/node/index.d.ts",
|
||||
"default": "./dist/node/index.js"
|
||||
},
|
||||
"./node/_internals": {
|
||||
"types": "./dist/node/_internals.d.ts",
|
||||
"default": "./dist/node/_internals.js"
|
||||
},
|
||||
"./loopback": {
|
||||
"types": "./dist/loopback/index.d.ts",
|
||||
"default": "./dist/loopback/index.js"
|
||||
},
|
||||
"./loopback/_internals": {
|
||||
"types": "./dist/loopback/_internals.d.ts",
|
||||
"default": "./dist/loopback/_internals.js"
|
||||
},
|
||||
"./websocket": {
|
||||
"types": "./dist/websocket/index.d.ts",
|
||||
"default": "./dist/websocket/index.js"
|
||||
@@ -97,6 +81,7 @@
|
||||
"typescript": "^6.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@webnet/transport": "*",
|
||||
"regexparam": "^3.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ export { ClientResponseImpl, combineClientConnectionOptions } from "./client/_in
|
||||
export {
|
||||
BasicBodyReader,
|
||||
ChunkedBodyReader,
|
||||
PairSync,
|
||||
ReadBuffer,
|
||||
ReadableHttpImpl,
|
||||
TimeoutError,
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { ClientResponse } from "./types.js"
|
||||
import { ReadBuffer } from "../common/buffer.js"
|
||||
import type { RawTransport } from "../common/types.js"
|
||||
import { skipIfNotIntegration } from "../test-helpers/flags.js"
|
||||
import { loopbackTransportPair } from "../loopback/transport.js"
|
||||
import { loopbackTransportPair } from "@webnet/transport/loopback"
|
||||
import { TimeoutError } from "../common/utils.js"
|
||||
|
||||
const enc = new TextEncoder()
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import test, { suite, after } from "node:test"
|
||||
import { Fetch, makeFetch } from "../client/fetch.js"
|
||||
import { nodeDialer } from "./transport.js"
|
||||
import { type Fetch, makeFetch } from "./fetch.js"
|
||||
import { nodeDialer } from "@webnet/transport/node"
|
||||
import assert from "node:assert"
|
||||
import { UnpooledDialer } from "../client/pool.js"
|
||||
import { UnpooledDialer } from "./pool.js"
|
||||
import { skipIfNotExternal } from "../test-helpers/flags.js"
|
||||
|
||||
function fetchUrlTest(url: string, fetch: Fetch, count: number) {
|
||||
@@ -2,7 +2,7 @@ import test, { suite } from "node:test"
|
||||
import assert from "node:assert"
|
||||
import { fetch, fetchStream, makeFetch } from "./fetch.js"
|
||||
import { UnpooledDialer } from "./pool.js"
|
||||
import { loopbackListener, loopbackTransportPair } from "../loopback/transport.js"
|
||||
import { loopbackListener, loopbackTransportPair } from "@webnet/transport/loopback"
|
||||
import { ReadBuffer } from "../common/buffer.js"
|
||||
import { skipIfNotIntegration } from "../test-helpers/flags.js"
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import test, { suite } from "node:test"
|
||||
import assert from "node:assert"
|
||||
import { UnpooledDialer, PooledDialer } from "./pool.js"
|
||||
import { loopbackTransportPair, type LoopbackTransportHalf } from "../loopback/transport.js"
|
||||
import { loopbackTransportPair } from "@webnet/transport/loopback"
|
||||
import type { LoopbackTransportHalf } from "@webnet/transport/loopback/_internals"
|
||||
import type { RawDialer } from "./types.js"
|
||||
import { skipIfNotIntegration } from "../test-helpers/flags.js"
|
||||
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import type { RawTransport, ReadableHttp, WritableHttp } from "../common/types.js"
|
||||
import type { ClientConnectionOptions } from "./connection.js"
|
||||
|
||||
export interface RawDialer {
|
||||
dial(host: string, port: number): Promise<RawTransport>
|
||||
dialTls?(host: string, port: number): Promise<RawTransport>
|
||||
}
|
||||
export type { RawDialer } from "@webnet/transport"
|
||||
|
||||
export interface ClientInformationalResponse {
|
||||
readonly status: number
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
export { ReadableHttpImpl, WritableHttpImpl } from "./objects.js"
|
||||
export { prependTransport, ReadBuffer, WriteBuffer } from "./buffer.js"
|
||||
export { PairSync } from "./pair.js"
|
||||
export {
|
||||
BasicBodyReader,
|
||||
ChunkedBodyReader,
|
||||
|
||||
@@ -1,28 +1,5 @@
|
||||
import type { BodyReaderOptions } from "./reader.js"
|
||||
|
||||
export interface RawTransport {
|
||||
get closed(): boolean
|
||||
close(): void | Promise<void>
|
||||
|
||||
write(data: Uint8Array): Promise<void | number>
|
||||
read(): Promise<Uint8Array>
|
||||
|
||||
// optional features, should degrade gracefully if absent
|
||||
|
||||
// close the write end, not the entire socket
|
||||
halfClose?(): void | Promise<void>
|
||||
// true if the read end is closed
|
||||
readonly readEnded?: boolean
|
||||
// resolves when fully closed, to cancel ongoing work
|
||||
readonly whenClosed?: Promise<void>
|
||||
|
||||
// `host:port` format
|
||||
readonly remoteAddr?: string
|
||||
readonly localAddr?: string
|
||||
}
|
||||
|
||||
export type Reader = Pick<RawTransport, "closed" | "read">
|
||||
export type Writer = Pick<RawTransport, "write">
|
||||
export type { RawTransport, Reader, Writer } from "@webnet/transport"
|
||||
|
||||
export type SimpleBody = string | Uint8Array
|
||||
export type StreamBody = AsyncIterable<SimpleBody | { flush: true }>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { ServerResponseImpl } from "./objects.js"
|
||||
import type { RawTransport } from "../common/types.js"
|
||||
import type { ServerRequestImpl } from "./objects.js"
|
||||
import { ReadBuffer } from "../common/buffer.js"
|
||||
import { loopbackTransportPair } from "../loopback/transport.js"
|
||||
import { loopbackTransportPair } from "@webnet/transport/loopback"
|
||||
import assert from "node:assert"
|
||||
import { skipIfNotIntegration } from "../test-helpers/flags.js"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import test, { suite } from "node:test"
|
||||
import assert from "node:assert"
|
||||
import { ServerRequestImpl, ServerResponseImpl } from "./objects.js"
|
||||
import { loopbackTransportPair } from "../loopback/transport.js"
|
||||
import { loopbackTransportPair } from "@webnet/transport/loopback"
|
||||
import { Headers } from "../common/headers.js"
|
||||
|
||||
function makeReq({
|
||||
|
||||
@@ -1,16 +1,5 @@
|
||||
import type { RawTransport, ReadableHttp, WritableHttp } from "../common/types.js"
|
||||
|
||||
export interface RawListener {
|
||||
get closed(): boolean
|
||||
close(): void | Promise<void>
|
||||
|
||||
accept(): Promise<RawTransport>
|
||||
|
||||
// optional features, should degrade gracefully if absent
|
||||
|
||||
// `host:port` format
|
||||
readonly addr?: string
|
||||
}
|
||||
export type { RawListener } from "@webnet/transport"
|
||||
|
||||
export interface ServerRequest extends ReadableHttp {
|
||||
readonly transport: RawTransport
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import test, { suite } from "node:test"
|
||||
import assert from "node:assert"
|
||||
import { loopbackTransportPair, loopbackListener } from "../loopback/transport.js"
|
||||
import { loopbackTransportPair, loopbackListener } from "@webnet/transport/loopback"
|
||||
import { ServerConnection } from "../server/connection.js"
|
||||
import { ClientConnection } from "../client/connection.js"
|
||||
import { ClientRequestImpl } from "../client/objects.js"
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "@webnet/transport",
|
||||
"version": "0.1.0",
|
||||
"description": "Transport abstractions and implementations for webnet",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
},
|
||||
"./_internals": {
|
||||
"types": "./dist/_internals.d.ts",
|
||||
"default": "./dist/_internals.js"
|
||||
},
|
||||
"./node": {
|
||||
"types": "./dist/node/index.d.ts",
|
||||
"default": "./dist/node/index.js"
|
||||
},
|
||||
"./node/_internals": {
|
||||
"types": "./dist/node/_internals.d.ts",
|
||||
"default": "./dist/node/_internals.js"
|
||||
},
|
||||
"./loopback": {
|
||||
"types": "./dist/loopback/index.d.ts",
|
||||
"default": "./dist/loopback/index.js"
|
||||
},
|
||||
"./loopback/_internals": {
|
||||
"types": "./dist/loopback/_internals.d.ts",
|
||||
"default": "./dist/loopback/_internals.js"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": "rm -rf dist && tsc --project tsconfig.json",
|
||||
"test": "tsx --test --test-timeout=10000 'src/**/*.test.ts'",
|
||||
"test:unit": "RUN_INTEGRATION=false npm run test",
|
||||
"test:coverage": "c8 --src src --exclude 'src/**/*.test.ts' --exclude 'src/test-helpers/**' --reporter text --reporter lcov node --enable-source-maps --import tsx --test-timeout=10000 --test 'src/**/*.test.ts'",
|
||||
"test:coverage:unit": "RUN_INTEGRATION=false npm run test:coverage",
|
||||
"typecheck": "tsc --project tsconfig.json --noEmit"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^25.6.0",
|
||||
"c8": "^11.0.0",
|
||||
"tsx": "^4.21.0",
|
||||
"typescript": "^6.0.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { PairSync } from "./pair.js"
|
||||
@@ -0,0 +1 @@
|
||||
export type { RawTransport, Reader, Writer, RawDialer, RawListener } from "./types.js"
|
||||
+2
-4
@@ -1,7 +1,5 @@
|
||||
import type { RawDialer } from "../client/types.js"
|
||||
import { PairSync } from "../common/pair.js"
|
||||
import type { RawTransport } from "../common/types.js"
|
||||
import type { RawListener } from "../server/types.js"
|
||||
import type { RawDialer, RawTransport, RawListener } from "../types.js"
|
||||
import { PairSync } from "../pair.js"
|
||||
|
||||
export class LoopbackTransportHalf implements RawTransport {
|
||||
#buffers: Uint8Array[] = []
|
||||
@@ -1,8 +1,6 @@
|
||||
import { connect, createServer, Server, type Socket } from "node:net"
|
||||
import { connect as connectTls } from "node:tls"
|
||||
import type { RawTransport } from "../common/types.js"
|
||||
import type { RawDialer } from "../client/types.js"
|
||||
import type { RawListener } from "../server/types.js"
|
||||
import type { RawTransport, RawDialer, RawListener } from "../types.js"
|
||||
|
||||
export class NodeTransport implements RawTransport {
|
||||
#socket: Socket
|
||||
@@ -0,0 +1,14 @@
|
||||
function bool(val: string | undefined, def: boolean): boolean {
|
||||
if (val === undefined) return def
|
||||
return val === "1" || val.toLowerCase() === "true"
|
||||
}
|
||||
|
||||
export const RUN_INTEGRATION = bool(process.env.RUN_INTEGRATION, true)
|
||||
export const RUN_EXTERNAL = bool(process.env.RUN_EXTERNAL, false)
|
||||
|
||||
export const skipIfNotIntegration: boolean | string = RUN_INTEGRATION
|
||||
? false
|
||||
: "set RUN_INTEGRATION=true to enable"
|
||||
export const skipIfNotExternal: boolean | string = RUN_EXTERNAL
|
||||
? false
|
||||
: "set RUN_EXTERNAL=true to enable"
|
||||
@@ -0,0 +1,40 @@
|
||||
export interface RawTransport {
|
||||
get closed(): boolean
|
||||
close(): void | Promise<void>
|
||||
|
||||
write(data: Uint8Array): Promise<void | number>
|
||||
read(): Promise<Uint8Array>
|
||||
|
||||
// optional features, should degrade gracefully if absent
|
||||
|
||||
// close the write end, not the entire socket
|
||||
halfClose?(): void | Promise<void>
|
||||
// true if the read end is closed
|
||||
readonly readEnded?: boolean
|
||||
// resolves when fully closed, to cancel ongoing work
|
||||
readonly whenClosed?: Promise<void>
|
||||
|
||||
// `host:port` format
|
||||
readonly remoteAddr?: string
|
||||
readonly localAddr?: string
|
||||
}
|
||||
|
||||
export type Reader = Pick<RawTransport, "closed" | "read">
|
||||
export type Writer = Pick<RawTransport, "write">
|
||||
|
||||
export interface RawDialer {
|
||||
dial(host: string, port: number): Promise<RawTransport>
|
||||
dialTls?(host: string, port: number): Promise<RawTransport>
|
||||
}
|
||||
|
||||
export interface RawListener {
|
||||
get closed(): boolean
|
||||
close(): void | Promise<void>
|
||||
|
||||
accept(): Promise<RawTransport>
|
||||
|
||||
// optional features, should degrade gracefully if absent
|
||||
|
||||
// `host:port` format
|
||||
readonly addr?: string
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"verbatimModuleSyntax": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"lib": ["ES2022"],
|
||||
"types": ["node"],
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSourceMap": true,
|
||||
"inlineSources": true
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["src/**/*.test.ts", "src/test-helpers"]
|
||||
}
|
||||
Reference in New Issue
Block a user