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",
|
"resolved": "packages/test-app",
|
||||||
"link": true
|
"link": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@webnet/transport": {
|
||||||
|
"resolved": "packages/transport",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
"node_modules/@webnet/tsconnect": {
|
"node_modules/@webnet/tsconnect": {
|
||||||
"resolved": "packages/tsconnect",
|
"resolved": "packages/tsconnect",
|
||||||
"link": true
|
"link": true
|
||||||
@@ -12519,6 +12523,7 @@
|
|||||||
"name": "@webnet/http",
|
"name": "@webnet/http",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@webnet/transport": "*",
|
||||||
"regexparam": "^3.0.0"
|
"regexparam": "^3.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -12568,6 +12573,30 @@
|
|||||||
"node": ">=14.17"
|
"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": {
|
"packages/tsconnect": {
|
||||||
"name": "@webnet/tsconnect",
|
"name": "@webnet/tsconnect",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
|
|||||||
@@ -38,22 +38,6 @@
|
|||||||
"types": "./dist/server/_internals.d.ts",
|
"types": "./dist/server/_internals.d.ts",
|
||||||
"default": "./dist/server/_internals.js"
|
"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": {
|
"./websocket": {
|
||||||
"types": "./dist/websocket/index.d.ts",
|
"types": "./dist/websocket/index.d.ts",
|
||||||
"default": "./dist/websocket/index.js"
|
"default": "./dist/websocket/index.js"
|
||||||
@@ -97,6 +81,7 @@
|
|||||||
"typescript": "^6.0.2"
|
"typescript": "^6.0.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@webnet/transport": "*",
|
||||||
"regexparam": "^3.0.0"
|
"regexparam": "^3.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ export { ClientResponseImpl, combineClientConnectionOptions } from "./client/_in
|
|||||||
export {
|
export {
|
||||||
BasicBodyReader,
|
BasicBodyReader,
|
||||||
ChunkedBodyReader,
|
ChunkedBodyReader,
|
||||||
PairSync,
|
|
||||||
ReadBuffer,
|
ReadBuffer,
|
||||||
ReadableHttpImpl,
|
ReadableHttpImpl,
|
||||||
TimeoutError,
|
TimeoutError,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import type { ClientResponse } from "./types.js"
|
|||||||
import { ReadBuffer } from "../common/buffer.js"
|
import { ReadBuffer } from "../common/buffer.js"
|
||||||
import type { RawTransport } from "../common/types.js"
|
import type { RawTransport } from "../common/types.js"
|
||||||
import { skipIfNotIntegration } from "../test-helpers/flags.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"
|
import { TimeoutError } from "../common/utils.js"
|
||||||
|
|
||||||
const enc = new TextEncoder()
|
const enc = new TextEncoder()
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import test, { suite, after } from "node:test"
|
import test, { suite, after } from "node:test"
|
||||||
import { Fetch, makeFetch } from "../client/fetch.js"
|
import { type Fetch, makeFetch } from "./fetch.js"
|
||||||
import { nodeDialer } from "./transport.js"
|
import { nodeDialer } from "@webnet/transport/node"
|
||||||
import assert from "node:assert"
|
import assert from "node:assert"
|
||||||
import { UnpooledDialer } from "../client/pool.js"
|
import { UnpooledDialer } from "./pool.js"
|
||||||
import { skipIfNotExternal } from "../test-helpers/flags.js"
|
import { skipIfNotExternal } from "../test-helpers/flags.js"
|
||||||
|
|
||||||
function fetchUrlTest(url: string, fetch: Fetch, count: number) {
|
function fetchUrlTest(url: string, fetch: Fetch, count: number) {
|
||||||
@@ -2,7 +2,7 @@ import test, { suite } from "node:test"
|
|||||||
import assert from "node:assert"
|
import assert from "node:assert"
|
||||||
import { fetch, fetchStream, makeFetch } from "./fetch.js"
|
import { fetch, fetchStream, makeFetch } from "./fetch.js"
|
||||||
import { UnpooledDialer } from "./pool.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 { ReadBuffer } from "../common/buffer.js"
|
||||||
import { skipIfNotIntegration } from "../test-helpers/flags.js"
|
import { skipIfNotIntegration } from "../test-helpers/flags.js"
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import test, { suite } from "node:test"
|
import test, { suite } from "node:test"
|
||||||
import assert from "node:assert"
|
import assert from "node:assert"
|
||||||
import { UnpooledDialer, PooledDialer } from "./pool.js"
|
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 type { RawDialer } from "./types.js"
|
||||||
import { skipIfNotIntegration } from "../test-helpers/flags.js"
|
import { skipIfNotIntegration } from "../test-helpers/flags.js"
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
import type { RawTransport, ReadableHttp, WritableHttp } from "../common/types.js"
|
import type { RawTransport, ReadableHttp, WritableHttp } from "../common/types.js"
|
||||||
import type { ClientConnectionOptions } from "./connection.js"
|
import type { ClientConnectionOptions } from "./connection.js"
|
||||||
|
export type { RawDialer } from "@webnet/transport"
|
||||||
export interface RawDialer {
|
|
||||||
dial(host: string, port: number): Promise<RawTransport>
|
|
||||||
dialTls?(host: string, port: number): Promise<RawTransport>
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ClientInformationalResponse {
|
export interface ClientInformationalResponse {
|
||||||
readonly status: number
|
readonly status: number
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
export { ReadableHttpImpl, WritableHttpImpl } from "./objects.js"
|
export { ReadableHttpImpl, WritableHttpImpl } from "./objects.js"
|
||||||
export { prependTransport, ReadBuffer, WriteBuffer } from "./buffer.js"
|
export { prependTransport, ReadBuffer, WriteBuffer } from "./buffer.js"
|
||||||
export { PairSync } from "./pair.js"
|
|
||||||
export {
|
export {
|
||||||
BasicBodyReader,
|
BasicBodyReader,
|
||||||
ChunkedBodyReader,
|
ChunkedBodyReader,
|
||||||
|
|||||||
@@ -1,28 +1,5 @@
|
|||||||
import type { BodyReaderOptions } from "./reader.js"
|
import type { BodyReaderOptions } from "./reader.js"
|
||||||
|
export type { RawTransport, Reader, Writer } from "@webnet/transport"
|
||||||
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 SimpleBody = string | Uint8Array
|
export type SimpleBody = string | Uint8Array
|
||||||
export type StreamBody = AsyncIterable<SimpleBody | { flush: true }>
|
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 { RawTransport } from "../common/types.js"
|
||||||
import type { ServerRequestImpl } from "./objects.js"
|
import type { ServerRequestImpl } from "./objects.js"
|
||||||
import { ReadBuffer } from "../common/buffer.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 assert from "node:assert"
|
||||||
import { skipIfNotIntegration } from "../test-helpers/flags.js"
|
import { skipIfNotIntegration } from "../test-helpers/flags.js"
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import test, { suite } from "node:test"
|
import test, { suite } from "node:test"
|
||||||
import assert from "node:assert"
|
import assert from "node:assert"
|
||||||
import { ServerRequestImpl, ServerResponseImpl } from "./objects.js"
|
import { ServerRequestImpl, ServerResponseImpl } from "./objects.js"
|
||||||
import { loopbackTransportPair } from "../loopback/transport.js"
|
import { loopbackTransportPair } from "@webnet/transport/loopback"
|
||||||
import { Headers } from "../common/headers.js"
|
import { Headers } from "../common/headers.js"
|
||||||
|
|
||||||
function makeReq({
|
function makeReq({
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
import type { RawTransport, ReadableHttp, WritableHttp } from "../common/types.js"
|
import type { RawTransport, ReadableHttp, WritableHttp } from "../common/types.js"
|
||||||
|
export type { RawListener } from "@webnet/transport"
|
||||||
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 interface ServerRequest extends ReadableHttp {
|
export interface ServerRequest extends ReadableHttp {
|
||||||
readonly transport: RawTransport
|
readonly transport: RawTransport
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import test, { suite } from "node:test"
|
import test, { suite } from "node:test"
|
||||||
import assert from "node:assert"
|
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 { ServerConnection } from "../server/connection.js"
|
||||||
import { ClientConnection } from "../client/connection.js"
|
import { ClientConnection } from "../client/connection.js"
|
||||||
import { ClientRequestImpl } from "../client/objects.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 type { RawDialer, RawTransport, RawListener } from "../types.js"
|
||||||
import { PairSync } from "../common/pair.js"
|
import { PairSync } from "../pair.js"
|
||||||
import type { RawTransport } from "../common/types.js"
|
|
||||||
import type { RawListener } from "../server/types.js"
|
|
||||||
|
|
||||||
export class LoopbackTransportHalf implements RawTransport {
|
export class LoopbackTransportHalf implements RawTransport {
|
||||||
#buffers: Uint8Array[] = []
|
#buffers: Uint8Array[] = []
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
import { connect, createServer, Server, type Socket } from "node:net"
|
import { connect, createServer, Server, type Socket } from "node:net"
|
||||||
import { connect as connectTls } from "node:tls"
|
import { connect as connectTls } from "node:tls"
|
||||||
import type { RawTransport } from "../common/types.js"
|
import type { RawTransport, RawDialer, RawListener } from "../types.js"
|
||||||
import type { RawDialer } from "../client/types.js"
|
|
||||||
import type { RawListener } from "../server/types.js"
|
|
||||||
|
|
||||||
export class NodeTransport implements RawTransport {
|
export class NodeTransport implements RawTransport {
|
||||||
#socket: Socket
|
#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