@hyperttp/core 2.0.1 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Core/HyperCore.d.ts +7 -2
- package/Core/HyperCore.d.ts.map +1 -1
- package/Core/HyperCore.js +1 -1
- package/Core/HyperCore.js.map +3 -3
- package/README.md +3 -3
- package/defaultConfig.d.ts +0 -5
- package/defaultConfig.d.ts.map +1 -1
- package/defaultConfig.js +1 -1
- package/defaultConfig.js.map +2 -2
- package/package.json +2 -2
- package/protocols/manager.d.ts.map +1 -1
- package/protocols/manager.js +1 -1
- package/protocols/manager.js.map +3 -3
- package/protocols/rest/index.d.ts +2 -1
- package/protocols/rest/index.d.ts.map +1 -1
- package/protocols/rest/index.js.map +2 -2
- package/protocols/rest/receiver.d.ts.map +1 -1
- package/protocols/rest/receiver.js +1 -1
- package/protocols/rest/receiver.js.map +3 -3
- package/protocols/rest/sender.d.ts +0 -19
- package/protocols/rest/sender.d.ts.map +1 -1
- package/protocols/rest/sender.js +1 -1
- package/protocols/rest/sender.js.map +3 -3
- package/protocols/rest/type.d.ts +11 -9
- package/protocols/rest/type.d.ts.map +1 -1
- package/protocols/rest/utils.d.ts +3 -0
- package/protocols/rest/utils.d.ts.map +1 -0
- package/protocols/rest/utils.js +2 -0
- package/protocols/rest/utils.js.map +7 -0
- package/rest.d.ts +1 -1
- package/rest.d.ts.map +1 -1
- package/transports/fetch.d.ts +9 -1
- package/transports/fetch.d.ts.map +1 -1
- package/transports/fetch.js +1 -1
- package/transports/fetch.js.map +3 -3
- package/transports/manager.d.ts +3 -1
- package/transports/manager.d.ts.map +1 -1
- package/transports/manager.js +1 -1
- package/transports/manager.js.map +3 -3
- package/utils/modules.d.ts +3 -0
- package/utils/modules.d.ts.map +1 -0
- package/utils/modules.js +2 -0
- package/utils/modules.js.map +7 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/protocols/rest/receiver.ts"],
|
|
4
|
-
"sourcesContent": ["import type {\n HyperReceiver,\n ServerRequestContext,\n TransportRequest,\n TransportResponse,\n} from \"@hyperttp/types\";\nimport type { RestServerHandler, RestServerInput, RestServerResponse } from \"./type.js\";\nimport { HyperClientError } from \"../../utils/errors.js\";\n\nconst JSON_TYPE = \"application/json\";\nconst TEXT_DECODER = new TextDecoder();\nconst TEXT_ENCODER = new TextEncoder();\nconst HAS_BUFFER = typeof Buffer !== \"undefined\";\n\nfunction decodeUtf8(bytes: Uint8Array): string {\n if (HAS_BUFFER) {\n return Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString(\"utf8\");\n }\n return TEXT_DECODER.decode(bytes);\n}\n\nfunction decodeArrayBuffer(ab: ArrayBuffer): string {\n if (HAS_BUFFER) {\n return Buffer.from(ab).toString(\"utf8\");\n }\n return TEXT_DECODER.decode(ab);\n}\n\nfunction encodeUtf8(str: string): Uint8Array {\n if (HAS_BUFFER) {\n return Buffer.from(str);\n }\n return TEXT_ENCODER.encode(str);\n}\n\
|
|
5
|
-
"mappings": "aAOA,OAAS,oBAAAA,MAAwB,
|
|
6
|
-
"names": ["HyperClientError", "JSON_TYPE", "TEXT_DECODER", "TEXT_ENCODER", "HAS_BUFFER", "decodeUtf8", "bytes", "decodeArrayBuffer", "ab", "encodeUtf8", "str", "
|
|
4
|
+
"sourcesContent": ["import type {\n HyperReceiver,\n ServerRequestContext,\n TransportRequest,\n TransportResponse,\n} from \"@hyperttp/types\";\nimport type { RestServerHandler, RestServerInput, RestServerResponse } from \"./type.js\";\nimport { HyperClientError } from \"../../utils/errors.js\";\nimport { DEFAULT_STATUS_TEXTS, getHeaderValue } from \"./utils.js\";\n\nconst JSON_TYPE = \"application/json\";\nconst TEXT_DECODER = new TextDecoder();\nconst TEXT_ENCODER = new TextEncoder();\nconst HAS_BUFFER = typeof Buffer !== \"undefined\";\n\nfunction decodeUtf8(bytes: Uint8Array): string {\n if (HAS_BUFFER) {\n return Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString(\"utf8\");\n }\n return TEXT_DECODER.decode(bytes);\n}\n\nfunction decodeArrayBuffer(ab: ArrayBuffer): string {\n if (HAS_BUFFER) {\n return Buffer.from(ab).toString(\"utf8\");\n }\n return TEXT_DECODER.decode(ab);\n}\n\nfunction encodeUtf8(str: string): Uint8Array {\n if (HAS_BUFFER) {\n return Buffer.from(str);\n }\n return TEXT_ENCODER.encode(str);\n}\n\n/**\n * @ru Разбирает query-строку URL в словарь (поддерживает повторные ключи как массивы).\n * @en Parses a URL query string into a dictionary (supports repeated keys as arrays).\n */\nfunction parseQuery(queryString: string): Record<string, string | string[]> {\n if (!queryString) return {};\n const out: Record<string, string | string[]> = {};\n\n for (const [key, value] of new URLSearchParams(queryString)) {\n const existing = out[key];\n if (existing === undefined) {\n out[key] = value;\n } else if (Array.isArray(existing)) {\n existing.push(value);\n } else {\n out[key] = [existing, value];\n }\n }\n\n return out;\n}\n\n/**\n * @ru Декодирует тело запроса по content-type.\n * @en Decodes the request body based on content-type.\n */\nfunction parseTextBody(\n headers: Readonly<Record<string, string | string[]>>,\n text: string,\n): unknown {\n const contentType = getHeaderValue(headers, \"content-type\") ?? \"\";\n if (contentType.includes(JSON_TYPE)) {\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n }\n return text;\n}\n\nfunction decodeBody(raw: TransportRequest): unknown {\n const body = raw.body;\n if (body == null) return undefined;\n if (body instanceof Uint8Array) {\n return parseTextBody(raw.headers, decodeUtf8(body));\n }\n if (body instanceof ArrayBuffer) {\n return parseTextBody(raw.headers, decodeArrayBuffer(body));\n }\n if (typeof body === \"string\") return parseTextBody(raw.headers, body);\n return body;\n}\n\n/**\n * @ru REST/HTTP серверный адаптер. Зеркальная к `RestSender` реализация\n * трёхфазного цикла receive → handle → respond.\n * @en REST/HTTP server adapter. Mirror implementation of `RestSender` for the\n * three-phase receive → handle → respond cycle.\n */\nexport class RestReceiver implements HyperReceiver<\n RestServerInput,\n RestServerResponse,\n TransportRequest,\n TransportResponse\n> {\n readonly protocol = \"rest\";\n protected readonly handler?: RestServerHandler;\n\n /**\n * @ru Создаёт REST-ресивер с необязательным application handler.\n * @en Creates a REST receiver with an optional application handler.\n * @param options - Настройки ресивера и его обработчик. @en Receiver settings and its handler.\n */\n constructor(options: { handler?: RestServerHandler } = {}) {\n this.handler = options.handler;\n }\n\n /**\n * @ru Фаза приёма: разбирает сырой запрос транспорта в REST-структуру.\n * @en Receive phase: parses raw transport request into REST input structure.\n */\n receive(raw: TransportRequest, _ctx: ServerRequestContext): RestServerInput {\n const url = new URL(raw.url, \"http://hyperttp.local\");\n\n return {\n method: raw.method,\n path: url.pathname,\n headers: raw.headers,\n query: parseQuery(url.search.slice(1)),\n body: decodeBody(raw),\n };\n }\n\n /**\n * @ru Фаза обработки: вызывает зарегистрированный handler.\n * @en Handle phase: executes the registered application handler.\n */\n handle(\n request: RestServerInput,\n ctx: ServerRequestContext,\n ): RestServerResponse | Promise<RestServerResponse> {\n if (ctx.signal?.aborted) {\n throw ctx.signal.reason ?? new Error(\"Request aborted\");\n }\n\n if (!this.handler) {\n throw new HyperClientError(\n '[RestReceiver] No application handler registered for protocol \"rest\".',\n );\n }\n\n return this.handler(request, ctx);\n }\n\n /**\n * @ru Фаза ответа: сериализует протокольный ответ в транспортный формат.\n * @en Respond phase: serializes protocol response to raw transport format.\n */\n respond(response: RestServerResponse, _ctx: ServerRequestContext): TransportResponse {\n const headers: Record<string, string> = { ...response.headers };\n const status = response.status ?? 200;\n\n let body: unknown = response.body;\n if (body instanceof ArrayBuffer) {\n body = new Uint8Array(body);\n } else if (ArrayBuffer.isView(body) && !(body instanceof Uint8Array)) {\n body = new Uint8Array(body.buffer, body.byteOffset, body.byteLength).slice();\n } else if (body != null && typeof body === \"object\" && !(body instanceof Uint8Array)) {\n body = JSON.stringify(body);\n const hasContentType = Object.keys(headers).some((k) => k.toLowerCase() === \"content-type\");\n if (!hasContentType) headers[\"content-type\"] = JSON_TYPE;\n }\n\n return {\n status,\n statusText: DEFAULT_STATUS_TEXTS[status] ?? \"\",\n headers,\n body: body == null ? undefined : body instanceof Uint8Array ? body : encodeUtf8(String(body)),\n };\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["HyperClientError", "DEFAULT_STATUS_TEXTS", "getHeaderValue", "JSON_TYPE", "TEXT_DECODER", "TEXT_ENCODER", "HAS_BUFFER", "decodeUtf8", "bytes", "decodeArrayBuffer", "ab", "encodeUtf8", "str", "parseQuery", "queryString", "out", "key", "value", "existing", "parseTextBody", "headers", "text", "decodeBody", "raw", "body", "options", "_ctx", "url", "request", "ctx", "response", "status", "k"]
|
|
7
7
|
}
|
|
@@ -1,31 +1,12 @@
|
|
|
1
1
|
import type { HyperSender, HyperTransport, RequestContext, SendRequest, TransportRequest, TransportResponse, UniversalResponse } from "@hyperttp/types";
|
|
2
2
|
import type { RestInput } from "./type.js";
|
|
3
|
-
/**
|
|
4
|
-
* @ru Опции REST-сендера. Транспорт выбирается ядром; поле `transport` сохранено
|
|
5
|
-
* для совместимости с пользовательскими конфигурациями.
|
|
6
|
-
* @en REST sender options. The core selects the transport; `transport` remains
|
|
7
|
-
* for compatibility with custom configurations.
|
|
8
|
-
*/
|
|
9
|
-
export interface RestSenderOptions {
|
|
10
|
-
/** @ru Пользовательский транспорт. @en Custom transport. */
|
|
11
|
-
transport?: HyperTransport;
|
|
12
|
-
[key: string]: unknown;
|
|
13
|
-
}
|
|
14
3
|
export declare class RestSender implements HyperSender<RestInput, unknown, TransportRequest, TransportResponse> {
|
|
15
4
|
readonly protocol = "rest";
|
|
16
|
-
protected readonly options?: RestSenderOptions;
|
|
17
|
-
/**
|
|
18
|
-
* @ru Создаёт REST-сендер с необязательными пользовательскими настройками.
|
|
19
|
-
* @en Creates a REST sender with optional custom settings.
|
|
20
|
-
* @param options - Настройки сендера. @en Sender settings.
|
|
21
|
-
*/
|
|
22
|
-
constructor(options?: RestSenderOptions);
|
|
23
5
|
readonly methods: Readonly<Record<string, (...args: any[]) => any>>;
|
|
24
6
|
prepare(request: SendRequest<RestInput, string>, ctx: RequestContext): TransportRequest;
|
|
25
7
|
send(prepared: TransportRequest, transport: HyperTransport, _ctx: RequestContext): Promise<TransportResponse>;
|
|
26
8
|
parse(raw: TransportResponse, _ctx: RequestContext): UniversalResponse<unknown>;
|
|
27
9
|
private dispatch;
|
|
28
10
|
private buildUrl;
|
|
29
|
-
private getHeaderValue;
|
|
30
11
|
}
|
|
31
12
|
//# sourceMappingURL=sender.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sender.d.ts","sourceRoot":"","sources":["../../../src/protocols/rest/sender.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,cAAc,EAEd,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,SAAS,EAAkC,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"sender.d.ts","sourceRoot":"","sources":["../../../src/protocols/rest/sender.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,cAAc,EAEd,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,SAAS,EAAkC,MAAM,WAAW,CAAC;AAgE3E,qBAAa,UAAW,YAAW,WAAW,CAC5C,SAAS,EACT,OAAO,EACP,gBAAgB,EAChB,iBAAiB,CAClB;IACC,QAAQ,CAAC,QAAQ,UAAU;IAE3B,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,CAAC,CAyGjE;IAEF,OAAO,CAAC,OAAO,EAAE,WAAW,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,cAAc,GAAG,gBAAgB,CAkEtF;IAEK,IAAI,CACR,QAAQ,EAAE,gBAAgB,EAC1B,SAAS,EAAE,cAAc,EACzB,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,iBAAiB,CAAC,CAiB5B;IAED,KAAK,CAAC,GAAG,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,GAAG,iBAAiB,CAAC,OAAO,CAAC,CA6B9E;IAED,OAAO,CAAC,QAAQ;IAQhB,OAAO,CAAC,QAAQ;CAsCjB"}
|
package/protocols/rest/sender.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";import{TimeoutError as g}from"../../utils/errors.js";import{applyTimeout as y}from"../../utils/abort.js";const p="rest:stream",
|
|
1
|
+
"use strict";import{TimeoutError as g}from"../../utils/errors.js";import{applyTimeout as y}from"../../utils/abort.js";import{DEFAULT_STATUS_TEXTS as m,getHeaderValue as T}from"./utils.js";const p="rest:stream",A=new TextDecoder,d=new WeakMap;function S(a){if(a===null||typeof a!="object")return!1;const t=Object.getPrototypeOf(a);return t===null||t===Object.prototype}async function E(a){if(a instanceof Uint8Array)return a;if(a instanceof ArrayBuffer)return new Uint8Array(a);if(ArrayBuffer.isView(a))return new Uint8Array(a.buffer,a.byteOffset,a.byteLength).slice();if(a&&typeof a=="object"&&"arrayBuffer"in a){const t=a.arrayBuffer;if(typeof t=="function")return new Uint8Array(await t.call(a))}if(typeof ReadableStream<"u"&&a instanceof ReadableStream){const t=a.getReader(),r=[];let e=0;for(;;){const{done:i,value:l}=await t.read();if(i)break;const o=l instanceof Uint8Array?l:new Uint8Array(l);r.push(o),e+=o.byteLength}const n=new Uint8Array(e);let s=0;for(const i of r)n.set(i,s),s+=i.byteLength;return n}return a}export class RestSender{protocol="rest";methods={get:(t,r,e,n)=>this.dispatch(t,{method:"GET",url:r,...e,signal:n??e?.signal}),post:(t,r,e,n,s)=>this.dispatch(t,{method:"POST",url:r,...n,body:e,signal:s??n?.signal}),put:(t,r,e,n,s)=>this.dispatch(t,{method:"PUT",url:r,...n,body:e,signal:s??n?.signal}),patch:(t,r,e,n,s)=>this.dispatch(t,{method:"PATCH",url:r,...n,body:e,signal:s??n?.signal}),delete:(t,r,e,n)=>this.dispatch(t,{method:"DELETE",url:r,...e,signal:n??e?.signal}),head:(t,r,e,n)=>this.dispatch(t,{method:"HEAD",url:r,...e,signal:n??e?.signal}),options:(t,r,e,n)=>this.dispatch(t,{method:"OPTIONS",url:r,...e,signal:n??e?.signal}),query:(t,r,e,n,s)=>this.dispatch(t,{method:"QUERY",url:r,...n,body:e,signal:s??n?.signal}),request:(t,r,e,n,s)=>this.dispatch(t,{method:r,url:e,...n,signal:s??n?.signal}),stream:(t,r,e,n)=>this.dispatch(t,{method:"GET",url:r,...e,stream:!0,signal:n??e?.signal})};prepare(t,r){const{input:e}=t,n=t.signal??e.signal??r.signal,s=e.timeout;let i,l=n;if(s!=null&&s>0){const f={};l=y(n,s,f,()=>new g(e.url,s)),i=f.cleanupSignal}const o={};if(e.headers)if(e.headers instanceof Headers)e.headers.forEach((f,u)=>{o[u.toLowerCase()]=f});else if(Array.isArray(e.headers))for(const[f,u]of e.headers)o[f.toLowerCase()]=u;else for(const f in e.headers){const u=e.headers[f];u!=null&&(o[f.toLowerCase()]=String(u))}let c=e.body;c!=null&&(S(c)||Array.isArray(c))?(c=Buffer.from(JSON.stringify(c)),o["content-type"]||(o["content-type"]="application/json; charset=utf-8")):typeof c=="string"&&(c=Buffer.from(c));const h={method:e.method.toUpperCase(),url:this.buildUrl(e.url,e.query),headers:o,body:c,signal:l,protocol:this.protocol,stream:e.stream,stealth:e.stealth,followRedirects:e.followRedirects,maxRedirects:e.maxRedirects};return i&&d.set(h,i),h}async send(t,r,e){const n=t;try{const s=await r.execute(t);if(n.stream)return{...s,[p]:!0};const i=await E(s.body);return i===s.body?s:{...s,body:i}}finally{const s=d.get(t);s&&(d.delete(t),s())}}parse(t,r){const e=t.status>=200&&t.status<300;let n=t.body;if(!t[p]&&t.body instanceof Uint8Array){const s=T(t.headers,"content-type")??"",i=A.decode(t.body);if(s.includes("application/json"))try{n=JSON.parse(i)}catch{n=i}else(s.includes("text/")||s.includes("application/xml"))&&(n=i)}return{protocol:this.protocol,ok:e,status:t.status,statusText:t.statusText||m[t.status]||"",headers:t.headers,url:t.url,data:n,raw:t}}dispatch(t,r){return t.send({protocol:"rest",input:r,signal:r.signal})}buildUrl(t,r){if(!r)return t;const e=[];for(const[l,o]of Object.entries(r)){if(o==null)continue;const c=Array.isArray(o)?o:[o];for(const h of c)e.push(`${encodeURIComponent(l)}=${encodeURIComponent(String(h))}`)}if(e.length===0)return t;const n=e.join("&"),s=t.indexOf("#");if(s!==-1){const l=t.slice(0,s),o=t.slice(s),c=l.includes("?")?"&":"?";return`${l}${c}${n}${o}`}const i=t.includes("?")?"&":"?";return`${t}${i}${n}`}}
|
|
2
2
|
//# sourceMappingURL=sender.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/protocols/rest/sender.ts"],
|
|
4
|
-
"sourcesContent": ["import type {\n HyperSender,\n HyperTransport,\n IHyperCore,\n RequestContext,\n SendRequest,\n TransportRequest,\n TransportResponse,\n UniversalResponse,\n} from \"@hyperttp/types\";\nimport type { RestInput, RestRequestOptions, HttpMethod } from \"./type.js\";\nimport { TimeoutError } from \"../../utils/errors.js\";\nimport { applyTimeout } from \"../../utils/abort.js\";\n\nconst STREAM_HINT = \"rest:stream\";\nconst TEXT_DECODER = new TextDecoder();\nconst REQUEST_CLEANUPS = new WeakMap<TransportRequest, () => void>();\n\ntype RestTransportRequest = TransportRequest & {\n stream?: boolean;\n};\n\ntype RestTransportResponse = TransportResponse & {\n [STREAM_HINT]?: boolean;\n};\n\n/**\n * @ru Опции REST-сендера. Транспорт выбирается ядром; поле `transport` сохранено\n * для совместимости с пользовательскими конфигурациями.\n * @en REST sender options. The core selects the transport; `transport` remains\n * for compatibility with custom configurations.\n */\nexport interface RestSenderOptions {\n /** @ru Пользовательский транспорт. @en Custom transport. */\n transport?: HyperTransport;\n [key: string]: unknown;\n}\n\nconst defaultStatusTexts: Record<number, string> = {\n 200: \"OK\",\n 201: \"Created\",\n 204: \"No Content\",\n 400: \"Bad Request\",\n 401: \"Unauthorized\",\n 403: \"Forbidden\",\n 404: \"Not Found\",\n 500: \"Internal Server Error\",\n};\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== \"object\") {\n return false;\n }\n const proto = Object.getPrototypeOf(value);\n return proto === null || proto === Object.prototype;\n}\n\nasync function collectBody(body: unknown): Promise<unknown> {\n if (body instanceof Uint8Array) return body;\n if (body instanceof ArrayBuffer) return new Uint8Array(body);\n if (ArrayBuffer.isView(body)) {\n return new Uint8Array(body.buffer, body.byteOffset, body.byteLength).slice();\n }\n\n if (body && typeof body === \"object\" && \"arrayBuffer\" in body) {\n const arrayBuffer = (body as { arrayBuffer?: unknown }).arrayBuffer;\n if (typeof arrayBuffer === \"function\") {\n return new Uint8Array(await arrayBuffer.call(body));\n }\n }\n\n if (typeof ReadableStream !== \"undefined\" && body instanceof ReadableStream) {\n const reader = body.getReader();\n const chunks: Uint8Array[] = [];\n let totalLength = 0;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n const chunk = value instanceof Uint8Array ? value : new Uint8Array(value);\n chunks.push(chunk);\n totalLength += chunk.byteLength;\n }\n\n const collected = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n collected.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return collected;\n }\n\n return body;\n}\n\nexport class RestSender implements HyperSender<\n RestInput,\n unknown,\n TransportRequest,\n TransportResponse\n> {\n readonly protocol = \"rest\";\n protected readonly options?: RestSenderOptions;\n\n /**\n * @ru Создаёт REST-сендер с необязательными пользовательскими настройками.\n * @en Creates a REST sender with optional custom settings.\n * @param options - Настройки сендера. @en Sender settings.\n */\n constructor(options?: RestSenderOptions) {\n this.options = options;\n }\n\n readonly methods: Readonly<Record<string, (...args: any[]) => any>> = {\n get: (core: IHyperCore, url: string, options?: RestRequestOptions, signal?: AbortSignal) =>\n this.dispatch(core, { method: \"GET\", url, ...options, signal: signal ?? options?.signal }),\n\n post: (\n core: IHyperCore,\n url: string,\n body?: unknown,\n options?: Omit<RestRequestOptions, \"body\">,\n signal?: AbortSignal,\n ) =>\n this.dispatch(core, {\n method: \"POST\",\n url,\n ...options,\n body,\n signal: signal ?? options?.signal,\n }),\n\n put: (\n core: IHyperCore,\n url: string,\n body?: unknown,\n options?: Omit<RestRequestOptions, \"body\">,\n signal?: AbortSignal,\n ) =>\n this.dispatch(core, {\n method: \"PUT\",\n url,\n ...options,\n body,\n signal: signal ?? options?.signal,\n }),\n\n patch: (\n core: IHyperCore,\n url: string,\n body?: unknown,\n options?: Omit<RestRequestOptions, \"body\">,\n signal?: AbortSignal,\n ) =>\n this.dispatch(core, {\n method: \"PATCH\",\n url,\n ...options,\n body,\n signal: signal ?? options?.signal,\n }),\n\n delete: (core: IHyperCore, url: string, options?: RestRequestOptions, signal?: AbortSignal) =>\n this.dispatch(core, { method: \"DELETE\", url, ...options, signal: signal ?? options?.signal }),\n\n head: (core: IHyperCore, url: string, options?: RestRequestOptions, signal?: AbortSignal) =>\n this.dispatch(core, { method: \"HEAD\", url, ...options, signal: signal ?? options?.signal }),\n\n options: (core: IHyperCore, url: string, options?: RestRequestOptions, signal?: AbortSignal) =>\n this.dispatch(core, {\n method: \"OPTIONS\",\n url,\n ...options,\n signal: signal ?? options?.signal,\n }),\n\n query: (\n core: IHyperCore,\n url: string,\n body?: unknown,\n options?: Omit<RestRequestOptions, \"body\">,\n signal?: AbortSignal,\n ) =>\n this.dispatch(core, {\n method: \"QUERY\",\n url,\n ...options,\n body,\n signal: signal ?? options?.signal,\n }),\n\n request: (\n core: IHyperCore,\n method: HttpMethod | (string & {}),\n url: string,\n options?: RestRequestOptions,\n signal?: AbortSignal,\n ) =>\n this.dispatch(core, {\n method: method as HttpMethod,\n url,\n ...options,\n signal: signal ?? options?.signal,\n }),\n\n stream: (\n core: IHyperCore,\n url: string,\n options?: Omit<RestRequestOptions, \"stream\">,\n signal?: AbortSignal,\n ) =>\n this.dispatch(core, {\n method: \"GET\",\n url,\n ...options,\n stream: true,\n signal: signal ?? options?.signal,\n }),\n };\n\n prepare(request: SendRequest<RestInput, string>, ctx: RequestContext): TransportRequest {\n const { input } = request;\n const inputSignal = request.signal ?? input.signal ?? ctx.signal;\n const timeout = input.timeout;\n let cleanupSignal: (() => void) | undefined;\n let signal = inputSignal;\n\n if (timeout != null && timeout > 0) {\n const timeoutMeta: { cleanupSignal?: () => void } = {};\n signal = applyTimeout(\n inputSignal,\n timeout,\n timeoutMeta,\n () => new TimeoutError(input.url, timeout),\n );\n cleanupSignal = timeoutMeta.cleanupSignal;\n }\n\n const headers: Record<string, string> = {};\n\n if (input.headers) {\n if (input.headers instanceof Headers) {\n input.headers.forEach((value, key) => {\n headers[key.toLowerCase()] = value;\n });\n } else if (Array.isArray(input.headers)) {\n for (const [key, value] of input.headers) {\n headers[key.toLowerCase()] = value;\n }\n } else {\n for (const key in input.headers) {\n const value = (input.headers as Record<string, unknown>)[key];\n\n if (value != null) {\n headers[key.toLowerCase()] = String(value);\n }\n }\n }\n }\n\n let body = input.body;\n\n if (body !== undefined && body !== null && (isPlainObject(body) || Array.isArray(body))) {\n body = JSON.stringify(body);\n if (!headers[\"content-type\"]) {\n headers[\"content-type\"] = \"application/json; charset=utf-8\";\n }\n }\n\n const prepared = {\n method: input.method.toUpperCase(),\n url: this.buildUrl(input.url, input.query),\n headers,\n body,\n signal,\n protocol: this.protocol,\n stream: input.stream,\n stealth: (input as any).stealth,\n followRedirects: input.followRedirects,\n maxRedirects: input.maxRedirects,\n } as RestTransportRequest;\n\n if (cleanupSignal) REQUEST_CLEANUPS.set(prepared, cleanupSignal);\n return prepared;\n }\n\n async send(\n prepared: TransportRequest,\n transport: HyperTransport,\n _ctx: RequestContext,\n ): Promise<TransportResponse> {\n const restRequest = prepared as RestTransportRequest;\n try {\n const response = await transport.execute(prepared);\n if (restRequest.stream) {\n return { ...response, [STREAM_HINT]: true } as RestTransportResponse;\n }\n\n const body = await collectBody(response.body);\n return body === response.body ? response : { ...response, body };\n } finally {\n const cleanup = REQUEST_CLEANUPS.get(prepared);\n if (cleanup) {\n REQUEST_CLEANUPS.delete(prepared);\n cleanup();\n }\n }\n }\n\n parse(raw: TransportResponse, _ctx: RequestContext): UniversalResponse<unknown> {\n const ok = raw.status >= 200 && raw.status < 300;\n let parsedData: unknown = raw.body;\n\n if (!(raw as RestTransportResponse)[STREAM_HINT] && raw.body instanceof Uint8Array) {\n const contentType = this.getHeaderValue(raw.headers, \"content-type\") ?? \"\";\n const text = TEXT_DECODER.decode(raw.body);\n\n if (contentType.includes(\"application/json\")) {\n try {\n parsedData = JSON.parse(text);\n } catch {\n parsedData = text;\n }\n } else if (contentType.includes(\"text/\") || contentType.includes(\"application/xml\")) {\n parsedData = text;\n }\n }\n\n return {\n protocol: this.protocol,\n ok,\n status: raw.status,\n statusText: raw.statusText || defaultStatusTexts[raw.status] || \"\",\n headers: raw.headers,\n url: raw.url,\n data: parsedData,\n raw,\n };\n }\n\n private dispatch(core: IHyperCore, input: RestInput): Promise<UniversalResponse<unknown>> {\n return core.send<RestInput, unknown, \"rest\">({\n protocol: \"rest\",\n input,\n signal: input.signal,\n });\n }\n\n private buildUrl(baseUrl: string, query?: RestInput[\"query\"]): string {\n if (!query) {\n return baseUrl;\n }\n\n const parts: string[] = [];\n\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null) {\n continue;\n }\n\n const values = Array.isArray(value) ? value : [value];\n\n for (const v of values) {\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(v))}`);\n }\n }\n\n if (parts.length === 0) {\n return baseUrl;\n }\n\n const queryString = parts.join(\"&\");\n const hashIndex = baseUrl.indexOf(\"#\");\n\n if (hashIndex !== -1) {\n const urlBeforeHash = baseUrl.slice(0, hashIndex);\n const hashPart = baseUrl.slice(hashIndex);\n const separator = urlBeforeHash.includes(\"?\") ? \"&\" : \"?\";\n\n return `${urlBeforeHash}${separator}${queryString}${hashPart}`;\n }\n\n const separator = baseUrl.includes(\"?\") ? \"&\" : \"?\";\n\n return `${baseUrl}${separator}${queryString}`;\n }\n\n private getHeaderValue(\n headers: Record<string, string | string[]>,\n name: string,\n ): string | undefined {\n const target = name.toLowerCase();\n const direct = headers[target] ?? headers[name];\n if (direct !== undefined) return Array.isArray(direct) ? direct[0] : direct;\n\n for (const key in headers) {\n if (key.toLowerCase() !== target) continue;\n const value = headers[key];\n return Array.isArray(value) ? value[0] : value;\n }\n return undefined;\n }\n}\n"],
|
|
5
|
-
"mappings": "aAWA,OAAS,gBAAAA,MAAoB,wBAC7B,OAAS,gBAAAC,MAAoB,
|
|
6
|
-
"names": ["TimeoutError", "applyTimeout", "
|
|
4
|
+
"sourcesContent": ["import type {\n HyperSender,\n HyperTransport,\n IHyperCore,\n RequestContext,\n SendRequest,\n TransportRequest,\n TransportResponse,\n UniversalResponse,\n} from \"@hyperttp/types\";\nimport type { RestInput, RestRequestOptions, HttpMethod } from \"./type.js\";\nimport { TimeoutError } from \"../../utils/errors.js\";\nimport { applyTimeout } from \"../../utils/abort.js\";\nimport { DEFAULT_STATUS_TEXTS, getHeaderValue } from \"./utils.js\";\n\nconst STREAM_HINT = \"rest:stream\";\nconst TEXT_DECODER = new TextDecoder();\nconst REQUEST_CLEANUPS = new WeakMap<TransportRequest, () => void>();\n\ntype RestTransportRequest = TransportRequest & {\n stealth?: boolean;\n};\n\ntype RestTransportResponse = TransportResponse & {\n [STREAM_HINT]?: boolean;\n};\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== \"object\") {\n return false;\n }\n const proto = Object.getPrototypeOf(value);\n return proto === null || proto === Object.prototype;\n}\n\nasync function collectBody(body: unknown): Promise<unknown> {\n if (body instanceof Uint8Array) return body;\n if (body instanceof ArrayBuffer) return new Uint8Array(body);\n if (ArrayBuffer.isView(body)) {\n return new Uint8Array(body.buffer, body.byteOffset, body.byteLength).slice();\n }\n\n if (body && typeof body === \"object\" && \"arrayBuffer\" in body) {\n const arrayBuffer = (body as { arrayBuffer?: unknown }).arrayBuffer;\n if (typeof arrayBuffer === \"function\") {\n return new Uint8Array(await arrayBuffer.call(body));\n }\n }\n\n if (typeof ReadableStream !== \"undefined\" && body instanceof ReadableStream) {\n const reader = body.getReader();\n const chunks: Uint8Array[] = [];\n let totalLength = 0;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n const chunk = value instanceof Uint8Array ? value : new Uint8Array(value);\n chunks.push(chunk);\n totalLength += chunk.byteLength;\n }\n\n const collected = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n collected.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return collected;\n }\n\n return body;\n}\n\nexport class RestSender implements HyperSender<\n RestInput,\n unknown,\n TransportRequest,\n TransportResponse\n> {\n readonly protocol = \"rest\";\n\n readonly methods: Readonly<Record<string, (...args: any[]) => any>> = {\n get: (core: IHyperCore, url: string, options?: RestRequestOptions, signal?: AbortSignal) =>\n this.dispatch(core, { method: \"GET\", url, ...options, signal: signal ?? options?.signal }),\n\n post: (\n core: IHyperCore,\n url: string,\n body?: unknown,\n options?: Omit<RestRequestOptions, \"body\">,\n signal?: AbortSignal,\n ) =>\n this.dispatch(core, {\n method: \"POST\",\n url,\n ...options,\n body,\n signal: signal ?? options?.signal,\n }),\n\n put: (\n core: IHyperCore,\n url: string,\n body?: unknown,\n options?: Omit<RestRequestOptions, \"body\">,\n signal?: AbortSignal,\n ) =>\n this.dispatch(core, {\n method: \"PUT\",\n url,\n ...options,\n body,\n signal: signal ?? options?.signal,\n }),\n\n patch: (\n core: IHyperCore,\n url: string,\n body?: unknown,\n options?: Omit<RestRequestOptions, \"body\">,\n signal?: AbortSignal,\n ) =>\n this.dispatch(core, {\n method: \"PATCH\",\n url,\n ...options,\n body,\n signal: signal ?? options?.signal,\n }),\n\n delete: (core: IHyperCore, url: string, options?: RestRequestOptions, signal?: AbortSignal) =>\n this.dispatch(core, { method: \"DELETE\", url, ...options, signal: signal ?? options?.signal }),\n\n head: (core: IHyperCore, url: string, options?: RestRequestOptions, signal?: AbortSignal) =>\n this.dispatch(core, { method: \"HEAD\", url, ...options, signal: signal ?? options?.signal }),\n\n options: (core: IHyperCore, url: string, options?: RestRequestOptions, signal?: AbortSignal) =>\n this.dispatch(core, {\n method: \"OPTIONS\",\n url,\n ...options,\n signal: signal ?? options?.signal,\n }),\n\n query: (\n core: IHyperCore,\n url: string,\n body?: unknown,\n options?: Omit<RestRequestOptions, \"body\">,\n signal?: AbortSignal,\n ) =>\n this.dispatch(core, {\n method: \"QUERY\",\n url,\n ...options,\n body,\n signal: signal ?? options?.signal,\n }),\n\n request: (\n core: IHyperCore,\n method: HttpMethod | (string & {}),\n url: string,\n options?: RestRequestOptions,\n signal?: AbortSignal,\n ) =>\n this.dispatch(core, {\n method: method as HttpMethod,\n url,\n ...options,\n signal: signal ?? options?.signal,\n }),\n\n stream: (\n core: IHyperCore,\n url: string,\n options?: Omit<RestRequestOptions, \"stream\">,\n signal?: AbortSignal,\n ) =>\n this.dispatch(core, {\n method: \"GET\",\n url,\n ...options,\n stream: true,\n signal: signal ?? options?.signal,\n }),\n };\n\n prepare(request: SendRequest<RestInput, string>, ctx: RequestContext): TransportRequest {\n const { input } = request;\n const inputSignal = request.signal ?? input.signal ?? ctx.signal;\n const timeout = input.timeout;\n let cleanupSignal: (() => void) | undefined;\n let signal = inputSignal;\n\n if (timeout != null && timeout > 0) {\n const timeoutMeta: { cleanupSignal?: () => void } = {};\n signal = applyTimeout(\n inputSignal,\n timeout,\n timeoutMeta,\n () => new TimeoutError(input.url, timeout),\n );\n cleanupSignal = timeoutMeta.cleanupSignal;\n }\n\n const headers: Record<string, string> = {};\n\n if (input.headers) {\n if (input.headers instanceof Headers) {\n input.headers.forEach((value, key) => {\n headers[key.toLowerCase()] = value;\n });\n } else if (Array.isArray(input.headers)) {\n for (const [key, value] of input.headers) {\n headers[key.toLowerCase()] = value;\n }\n } else {\n for (const key in input.headers) {\n const value = (input.headers as Record<string, unknown>)[key];\n\n if (value != null) {\n headers[key.toLowerCase()] = String(value);\n }\n }\n }\n }\n\n let body = input.body;\n\n if (body !== undefined && body !== null && (isPlainObject(body) || Array.isArray(body))) {\n body = Buffer.from(JSON.stringify(body));\n if (!headers[\"content-type\"]) {\n headers[\"content-type\"] = \"application/json; charset=utf-8\";\n }\n } else if (typeof body === \"string\") {\n body = Buffer.from(body);\n }\n\n const prepared = {\n method: input.method.toUpperCase(),\n url: this.buildUrl(input.url, input.query),\n headers,\n body,\n signal,\n protocol: this.protocol,\n stream: input.stream,\n stealth: input.stealth,\n followRedirects: input.followRedirects,\n maxRedirects: input.maxRedirects,\n } as RestTransportRequest;\n\n if (cleanupSignal) REQUEST_CLEANUPS.set(prepared, cleanupSignal);\n return prepared;\n }\n\n async send(\n prepared: TransportRequest,\n transport: HyperTransport,\n _ctx: RequestContext,\n ): Promise<TransportResponse> {\n const restRequest = prepared as RestTransportRequest;\n try {\n const response = await transport.execute(prepared);\n if (restRequest.stream) {\n return { ...response, [STREAM_HINT]: true } as RestTransportResponse;\n }\n\n const body = await collectBody(response.body);\n return body === response.body ? response : { ...response, body };\n } finally {\n const cleanup = REQUEST_CLEANUPS.get(prepared);\n if (cleanup) {\n REQUEST_CLEANUPS.delete(prepared);\n cleanup();\n }\n }\n }\n\n parse(raw: TransportResponse, _ctx: RequestContext): UniversalResponse<unknown> {\n const ok = raw.status >= 200 && raw.status < 300;\n let parsedData: unknown = raw.body;\n\n if (!(raw as RestTransportResponse)[STREAM_HINT] && raw.body instanceof Uint8Array) {\n const contentType = getHeaderValue(raw.headers, \"content-type\") ?? \"\";\n const text = TEXT_DECODER.decode(raw.body);\n\n if (contentType.includes(\"application/json\")) {\n try {\n parsedData = JSON.parse(text);\n } catch {\n parsedData = text;\n }\n } else if (contentType.includes(\"text/\") || contentType.includes(\"application/xml\")) {\n parsedData = text;\n }\n }\n\n return {\n protocol: this.protocol,\n ok,\n status: raw.status,\n statusText: raw.statusText || DEFAULT_STATUS_TEXTS[raw.status] || \"\",\n headers: raw.headers,\n url: raw.url,\n data: parsedData,\n raw,\n };\n }\n\n private dispatch(core: IHyperCore, input: RestInput): Promise<UniversalResponse<unknown>> {\n return core.send<RestInput, unknown, \"rest\">({\n protocol: \"rest\",\n input,\n signal: input.signal,\n });\n }\n\n private buildUrl(baseUrl: string, query?: RestInput[\"query\"]): string {\n if (!query) {\n return baseUrl;\n }\n\n const parts: string[] = [];\n\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null) {\n continue;\n }\n\n const values = Array.isArray(value) ? value : [value];\n\n for (const v of values) {\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(v))}`);\n }\n }\n\n if (parts.length === 0) {\n return baseUrl;\n }\n\n const queryString = parts.join(\"&\");\n const hashIndex = baseUrl.indexOf(\"#\");\n\n if (hashIndex !== -1) {\n const urlBeforeHash = baseUrl.slice(0, hashIndex);\n const hashPart = baseUrl.slice(hashIndex);\n const separator = urlBeforeHash.includes(\"?\") ? \"&\" : \"?\";\n\n return `${urlBeforeHash}${separator}${queryString}${hashPart}`;\n }\n\n const separator = baseUrl.includes(\"?\") ? \"&\" : \"?\";\n\n return `${baseUrl}${separator}${queryString}`;\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["TimeoutError", "applyTimeout", "DEFAULT_STATUS_TEXTS", "getHeaderValue", "STREAM_HINT", "TEXT_DECODER", "REQUEST_CLEANUPS", "isPlainObject", "value", "proto", "collectBody", "body", "arrayBuffer", "reader", "chunks", "totalLength", "done", "chunk", "collected", "offset", "core", "url", "options", "signal", "method", "request", "ctx", "input", "inputSignal", "timeout", "cleanupSignal", "timeoutMeta", "headers", "key", "prepared", "transport", "_ctx", "restRequest", "response", "cleanup", "raw", "ok", "parsedData", "contentType", "text", "baseUrl", "query", "parts", "values", "v", "queryString", "hashIndex", "urlBeforeHash", "hashPart", "separator"]
|
|
7
7
|
}
|
package/protocols/rest/type.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ServerRequestContext, UniversalResponse } from "@hyperttp/types";
|
|
2
2
|
/**
|
|
3
3
|
* @ru Поддерживаемый HTTP-метод REST-запроса. `QUERY` предназначен для совместимых
|
|
4
4
|
* с ним серверов и прокси.
|
|
@@ -6,6 +6,7 @@ import type { HyperSender, ServerRequestContext, UniversalResponse } from "@hype
|
|
|
6
6
|
* and proxies that support it.
|
|
7
7
|
*/
|
|
8
8
|
export type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS" | "QUERY";
|
|
9
|
+
export type RestHeaders = Headers | Record<string, string | number | boolean> | ReadonlyArray<readonly [string, string]>;
|
|
9
10
|
/**
|
|
10
11
|
* @ru Входные данные REST-запроса, используемые `core.send()` и методами `core.rest`.
|
|
11
12
|
* @en REST request input used by `core.send()` and `core.rest` methods.
|
|
@@ -24,7 +25,7 @@ export interface RestInput<TBody = unknown> {
|
|
|
24
25
|
/** @ru Абсолютный или относительный URL. @en Absolute or relative URL. */
|
|
25
26
|
url: string;
|
|
26
27
|
/** @ru Заголовки запроса. @en Request headers. */
|
|
27
|
-
headers?:
|
|
28
|
+
headers?: RestHeaders;
|
|
28
29
|
/** @ru Query-параметры, добавляемые к URL. @en Query parameters appended to the URL. */
|
|
29
30
|
query?: Record<string, string | number | boolean | (string | number | boolean)[]>;
|
|
30
31
|
/** @ru Тело запроса; plain object и массив сериализуются в JSON. @en Request body; plain objects and arrays are serialized as JSON. */
|
|
@@ -37,6 +38,8 @@ export interface RestInput<TBody = unknown> {
|
|
|
37
38
|
followRedirects?: boolean;
|
|
38
39
|
/** @ru Максимальное число redirect-ов, если транспорт поддерживает настройку. @en Maximum redirect count when supported by the transport. */
|
|
39
40
|
maxRedirects?: number;
|
|
41
|
+
/** @ru Опция транспорта для stealth-режима. @en Transport-specific stealth mode. */
|
|
42
|
+
stealth?: boolean;
|
|
40
43
|
/** @ru Сигнал отмены запроса. @en Request cancellation signal. */
|
|
41
44
|
signal?: AbortSignal;
|
|
42
45
|
}
|
|
@@ -97,15 +100,14 @@ declare module "@hyperttp/types" {
|
|
|
97
100
|
interface ProtocolInputMap {
|
|
98
101
|
rest: RestInput;
|
|
99
102
|
}
|
|
103
|
+
interface ProtocolServerRequestMap {
|
|
104
|
+
rest: RestServerInput;
|
|
105
|
+
}
|
|
106
|
+
interface ProtocolServerResponseMap {
|
|
107
|
+
rest: RestServerResponse;
|
|
108
|
+
}
|
|
100
109
|
interface HyperProtocols {
|
|
101
110
|
readonly rest: RestClientMethods;
|
|
102
111
|
}
|
|
103
|
-
interface BaseHyperClientOptions {
|
|
104
|
-
/**
|
|
105
|
-
* @ru Кастомный сендер протокола, заменяющий стандартный сендер для своего протокола.
|
|
106
|
-
* @en Custom protocol sender that overrides the default sender for its protocol.
|
|
107
|
-
*/
|
|
108
|
-
customSender?: HyperSender;
|
|
109
|
-
}
|
|
110
112
|
}
|
|
111
113
|
//# sourceMappingURL=type.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"type.d.ts","sourceRoot":"","sources":["../../../src/protocols/rest/type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"type.d.ts","sourceRoot":"","sources":["../../../src/protocols/rest/type.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/protocols/rest/utils.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASjE,CAAC;AAEF,wBAAgB,cAAc,CAC5B,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC,EACpD,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,SAAS,CAWpB"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";export const DEFAULT_STATUS_TEXTS={200:"OK",201:"Created",204:"No Content",400:"Bad Request",401:"Unauthorized",403:"Forbidden",404:"Not Found",500:"Internal Server Error"};export function getHeaderValue(r,e){const t=r[e]??r[e.toLowerCase()];if(t!==void 0)return Array.isArray(t)?t[0]:t;const a=e.toLowerCase();for(const n in r)if(n.toLowerCase()===a){const o=r[n];return Array.isArray(o)?o[0]:o}}
|
|
2
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/protocols/rest/utils.ts"],
|
|
4
|
+
"sourcesContent": ["export const DEFAULT_STATUS_TEXTS: Readonly<Record<number, string>> = {\n 200: \"OK\",\n 201: \"Created\",\n 204: \"No Content\",\n 400: \"Bad Request\",\n 401: \"Unauthorized\",\n 403: \"Forbidden\",\n 404: \"Not Found\",\n 500: \"Internal Server Error\",\n};\n\nexport function getHeaderValue(\n headers: Readonly<Record<string, string | string[]>>,\n name: string,\n): string | undefined {\n const direct = headers[name] ?? headers[name.toLowerCase()];\n if (direct !== undefined) return Array.isArray(direct) ? direct[0] : direct;\n\n const target = name.toLowerCase();\n for (const key in headers) {\n if (key.toLowerCase() === target) {\n const value = headers[key];\n return Array.isArray(value) ? value[0] : value;\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "aAAO,aAAM,qBAAyD,CACpE,IAAK,KACL,IAAK,UACL,IAAK,aACL,IAAK,cACL,IAAK,eACL,IAAK,YACL,IAAK,YACL,IAAK,yBAGD,gBAAU,eACdA,EACAC,EAAY,CAEZ,MAAMC,EAASF,EAAQC,CAAI,GAAKD,EAAQC,EAAK,YAAW,CAAE,EAC1D,GAAIC,IAAW,OAAW,OAAO,MAAM,QAAQA,CAAM,EAAIA,EAAO,CAAC,EAAIA,EAErE,MAAMC,EAASF,EAAK,YAAW,EAC/B,UAAWG,KAAOJ,EAChB,GAAII,EAAI,YAAW,IAAOD,EAAQ,CAChC,MAAME,EAAQL,EAAQI,CAAG,EACzB,OAAO,MAAM,QAAQC,CAAK,EAAIA,EAAM,CAAC,EAAIA,CAC3C,CAEJ",
|
|
6
|
+
"names": ["headers", "name", "direct", "target", "key", "value"]
|
|
7
|
+
}
|
package/rest.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export type { HttpMethod, RestInput, RestRequestOptions, RestClientMethods, RestServerInput, RestServerResponse, RestServerHandler, } from "./protocols/rest/type.js";
|
|
1
|
+
export type { HttpMethod, RestHeaders, RestInput, RestRequestOptions, RestClientMethods, RestServerInput, RestServerResponse, RestServerHandler, } from "./protocols/rest/type.js";
|
|
2
2
|
//# sourceMappingURL=rest.d.ts.map
|
package/rest.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rest.d.ts","sourceRoot":"","sources":["../src/rest.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,UAAU,EACV,SAAS,EACT,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,0BAA0B,CAAC"}
|
|
1
|
+
{"version":3,"file":"rest.d.ts","sourceRoot":"","sources":["../src/rest.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,UAAU,EACV,WAAW,EACX,SAAS,EACT,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,0BAA0B,CAAC"}
|
package/transports/fetch.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { HyperTransport, SenderProtocol, TransportListenOptions, TransportRequest, TransportResponse, TransportServer } from "@hyperttp/types";
|
|
1
|
+
import type { HyperTransport, LogLevel, SenderProtocol, TransportListenOptions, TransportRequest, TransportResponse, TransportServer } from "@hyperttp/types";
|
|
2
2
|
export interface FetchTransportOptions {
|
|
3
3
|
/**
|
|
4
4
|
* @ru Кастомный список поддерживаемых протоколов.
|
|
@@ -12,6 +12,12 @@ export interface FetchTransportOptions {
|
|
|
12
12
|
* HTTP 413 before the body reaches the handler.
|
|
13
13
|
*/
|
|
14
14
|
maxBodyBytes?: number;
|
|
15
|
+
/**
|
|
16
|
+
* @ru Обработчик ошибок входящих серверных запросов.
|
|
17
|
+
* @en Error hook for incoming server requests.
|
|
18
|
+
*/
|
|
19
|
+
onError?: (error: unknown, request: TransportRequest) => void;
|
|
20
|
+
logger?: (level: LogLevel, message: string, meta?: unknown) => void;
|
|
15
21
|
}
|
|
16
22
|
/**
|
|
17
23
|
* @ru Минимальный транспорт на базе нативного fetch. Гарантированный fallback,
|
|
@@ -22,6 +28,8 @@ export interface FetchTransportOptions {
|
|
|
22
28
|
export declare class FetchTransport implements HyperTransport {
|
|
23
29
|
readonly protocols: readonly SenderProtocol[];
|
|
24
30
|
private readonly maxBodyBytes;
|
|
31
|
+
private readonly onError?;
|
|
32
|
+
private readonly logger?;
|
|
25
33
|
/**
|
|
26
34
|
* @ru Создаёт fallback-транспорт на базе глобального `fetch`.
|
|
27
35
|
* @en Creates a fallback transport based on global `fetch`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../src/transports/fetch.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EACd,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EAChB,MAAM,iBAAiB,CAAC;AAIzB,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,SAAS,CAAC,EAAE,cAAc,EAAE,CAAC;IAC7B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../src/transports/fetch.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,EACd,QAAQ,EACR,cAAc,EACd,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EAChB,MAAM,iBAAiB,CAAC;AAIzB,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,SAAS,CAAC,EAAE,cAAc,EAAE,CAAC;IAC7B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC9D,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CACrE;AAgBD;;;;;GAKG;AACH,qBAAa,cAAe,YAAW,cAAc;IACnD,SAAgB,SAAS,EAAE,SAAS,cAAc,EAAE,CAAC;IACrD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAmC;IAC5D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAkC;IAE1D;;;;OAIG;IACH,YAAY,OAAO,GAAE,qBAA0B,EAK9C;IAEY,OAAO,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA4CtE;IAEY,MAAM,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,eAAe,CAAC,CA6J7E;IAEY,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAG;CACvC"}
|
package/transports/fetch.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const H=10485760;async function O(){if(typeof process>"u"||!process.versions?.node)throw new Error("[FetchTransport] listen() is only available in Node.js.");return import("node:http")}export class FetchTransport{protocols;maxBodyBytes;constructor(
|
|
1
|
+
"use strict";const H=10485760;async function O(){if(typeof process>"u"||!process.versions?.node)throw new Error("[FetchTransport] listen() is only available in Node.js.");return import("node:http")}export class FetchTransport{protocols;maxBodyBytes;onError;logger;constructor(r={}){this.protocols=Object.freeze(r.protocols??["rest"]),this.maxBodyBytes=r.maxBodyBytes??10485760,this.onError=r.onError,this.logger=r.logger}async execute(r){const f=r,g=r.method!=="GET"&&r.method!=="HEAD",t=await fetch(r.url,{method:r.method,headers:r.headers,body:g?r.body??null:null,signal:r.signal,redirect:f.followRedirects===!1?"manual":"follow"}),u=f.stream?t.body:new Uint8Array(await t.arrayBuffer()),i={};if(typeof t.headers.getSetCookie=="function"){const s=t.headers.getSetCookie();s.length>0&&(i["set-cookie"]=s)}return t.headers.forEach((s,y)=>{const c=y.toLowerCase();if(!(c==="set-cookie"&&i["set-cookie"]))if(i[c]){const l=i[c];i[c]=Array.isArray(l)?[...l,s]:[l,s]}else i[c]=s}),{status:t.status,statusText:t.statusText,headers:i,url:t.url,body:u}}async listen(r){const{host:f,port:g,signal:t,onRequest:u}=r;if(t?.aborted)throw t.reason??new DOMException("The operation was aborted","AbortError");const{createServer:i}=await O(),s=i(async(o,e)=>{const n=new AbortController,d=()=>{n.signal.aborted||n.abort(new DOMException("Client disconnected","AbortError"))},E=()=>{o.complete||d()},v=()=>{e.writableEnded||d()};o.once("aborted",d),o.once("close",E),e.once("close",v);try{const b=Number(o.headers["content-length"]??0);if(Number.isFinite(b)&&b>this.maxBodyBytes){e.writeHead(413),e.end("Payload Too Large");return}const p=[];let T=0;for await(const h of o){if(T+=h.byteLength,T>this.maxBodyBytes){e.writeHead(413),e.end("Payload Too Large");return}p.push(h)}const L=p.length>0?Buffer.concat(p):void 0,B={};for(const[h,m]of Object.entries(o.headers))m!==void 0&&(B[h]=m);const k={method:o.method??"GET",url:o.url??"/",headers:B,body:L,signal:n.signal,protocol:this.protocols[0]??"rest"};if(!u){e.writeHead(501),e.end("Not Implemented");return}const a=await u(k),x={};for(const[h,m]of Object.entries(a.headers))x[h]=m;e.writeHead(a.status,a.statusText??"",x),a.body!=null?a.body instanceof Uint8Array||typeof a.body=="string"?e.end(a.body):e.end(JSON.stringify(a.body)):e.end()}catch(b){this.onError?.(b,{method:o.method??"GET",url:o.url??"/",headers:o.headers,signal:n.signal,protocol:this.protocols[0]??"rest"}),e.headersSent?e.destroy():(e.writeHead(500),e.end("Internal Server Error"))}finally{o.removeListener("aborted",d),o.removeListener("close",E),e.removeListener("close",v)}});let y=!1;const c=()=>y||(y=!0,t?.removeEventListener("abort",l),s.removeListener("error",w),!s.listening)?Promise.resolve():new Promise((o,e)=>{s.close(n=>{n?e(n):o()})}),l=()=>{c()},w=o=>{const e="[FetchTransport] HTTP server error";this.logger?this.logger("error",e,o):console.error(`${e}:`,o)};if(t?.aborted)throw t.reason??new DOMException("The operation was aborted","AbortError");return t?.addEventListener("abort",l,{once:!0}),new Promise((o,e)=>{const n=d=>{t?.removeEventListener("abort",l),e(d)};s.once("error",n),s.listen({host:f,port:g},()=>{s.removeListener("error",n),s.on("error",w),o({close:c})})})}async close(){}}
|
|
2
2
|
//# sourceMappingURL=fetch.js.map
|
package/transports/fetch.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/transports/fetch.ts"],
|
|
4
|
-
"sourcesContent": ["import type { IncomingMessage, OutgoingHttpHeaders, ServerResponse } from \"node:http\";\nimport type {\n HyperTransport,\n SenderProtocol,\n TransportListenOptions,\n TransportRequest,\n TransportResponse,\n TransportServer,\n} from \"@hyperttp/types\";\n\nconst DEFAULT_MAX_BODY_BYTES = 10 * 1024 * 1024;\n\nexport interface FetchTransportOptions {\n /**\n * @ru Кастомный список поддерживаемых протоколов.\n * @en Custom list of supported protocols.\n */\n protocols?: SenderProtocol[];\n /**\n * @ru Максимальный размер входящего серверного тела в байтах. Превышение\n * возвращает HTTP 413 до передачи тела обработчику.\n * @en Maximum incoming server request body size in bytes. Exceeding it returns\n * HTTP 413 before the body reaches the handler.\n */\n maxBodyBytes?: number;\n}\n\ntype ExtendedTransportRequest = TransportRequest & {\n stream?: boolean;\n followRedirects?: boolean;\n};\n\nasync function loadNodeHttp(): Promise<typeof import(\"node:http\")> {\n if (typeof process === \"undefined\" || !process.versions?.node) {\n throw new Error(\"[FetchTransport] listen() is only available in Node.js.\");\n }\n\n const specifier = \"node:http\";\n return import(/* @vite-ignore */ specifier);\n}\n\n/**\n * @ru Минимальный транспорт на базе нативного fetch. Гарантированный fallback,\n * когда ни один пакетный транспорт (@hyperttp/transport-undici/bun) не установлен.\n * @en Minimal native fetch-based transport. A guaranteed fallback used when no\n * packaged transport (@hyperttp/transport-undici/bun) is installed.\n */\nexport class FetchTransport implements HyperTransport {\n public readonly protocols: readonly SenderProtocol[];\n private readonly maxBodyBytes: number;\n\n /**\n * @ru Создаёт fallback-транспорт на базе глобального `fetch`.\n * @en Creates a fallback transport based on global `fetch`.\n * @param options - Поддерживаемые протоколы и серверный лимит тела. @en Supported protocols and server body limit.\n */\n constructor(options: FetchTransportOptions = {}) {\n this.protocols = Object.freeze(options.protocols ?? [\"rest\"]);\n this.maxBodyBytes = options.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;\n }\n\n public async execute(req: TransportRequest): Promise<TransportResponse> {\n const extendedRequest = req as ExtendedTransportRequest;\n const isBodyAllowed = req.method !== \"GET\" && req.method !== \"HEAD\";\n\n const res = await fetch(req.url, {\n method: req.method,\n headers: req.headers as Record<string, string>,\n body: isBodyAllowed ? ((req.body ?? null) as BodyInit | null) : null,\n signal: req.signal,\n redirect: extendedRequest.followRedirects === false ? \"manual\" : \"follow\",\n });\n\n const body = extendedRequest.stream ? res.body : new Uint8Array(await res.arrayBuffer());\n const headers: Record<string, string | string[]> = {};\n\n if (typeof res.headers.getSetCookie === \"function\") {\n const cookies = res.headers.getSetCookie();\n if (cookies.length > 0) {\n headers[\"set-cookie\"] = cookies;\n }\n }\n\n res.headers.forEach((value, key) => {\n const lowerKey = key.toLowerCase();\n\n if (lowerKey === \"set-cookie\" && headers[\"set-cookie\"]) {\n return;\n }\n\n if (headers[lowerKey]) {\n const existing = headers[lowerKey];\n headers[lowerKey] = Array.isArray(existing) ? [...existing, value] : [existing, value];\n } else {\n headers[lowerKey] = value;\n }\n });\n\n return {\n status: res.status,\n statusText: res.statusText,\n headers,\n url: res.url,\n body,\n };\n }\n\n public async listen(options: TransportListenOptions): Promise<TransportServer> {\n const { host, port, signal, onRequest } = options;\n if (signal?.aborted) {\n throw signal.reason ?? new DOMException(\"The operation was aborted\", \"AbortError\");\n }\n\n const { createServer } = await loadNodeHttp();\n\n const server = createServer(async (req: IncomingMessage, res: ServerResponse) => {\n const requestController = new AbortController();\n const abortRequest = () => {\n if (!requestController.signal.aborted) {\n requestController.abort(new DOMException(\"Client disconnected\", \"AbortError\"));\n }\n };\n const abortIncompleteRequest = () => {\n if (!req.complete) abortRequest();\n };\n const abortIncompleteResponse = () => {\n if (!res.writableEnded) abortRequest();\n };\n\n req.once(\"aborted\", abortRequest);\n req.once(\"close\", abortIncompleteRequest);\n res.once(\"close\", abortIncompleteResponse);\n\n try {\n const contentLength = Number(req.headers[\"content-length\"] ?? 0);\n if (Number.isFinite(contentLength) && contentLength > this.maxBodyBytes) {\n res.writeHead(413);\n res.end(\"Payload Too Large\");\n return;\n }\n\n const chunks: Uint8Array[] = [];\n let receivedBytes = 0;\n\n for await (const chunk of req) {\n receivedBytes += chunk.byteLength;\n if (receivedBytes > this.maxBodyBytes) {\n res.writeHead(413);\n res.end(\"Payload Too Large\");\n return;\n }\n chunks.push(chunk);\n }\n\n const body = chunks.length > 0 ? Buffer.concat(chunks) : undefined;\n const headers: Record<string, string | string[]> = {};\n\n for (const [key, value] of Object.entries(req.headers)) {\n if (value !== undefined) {\n headers[key] = value;\n }\n }\n\n const transportRequest: TransportRequest = {\n method: req.method ?? \"GET\",\n url: req.url ?? \"/\",\n headers,\n body,\n signal: requestController.signal,\n protocol: this.protocols[0] ?? \"rest\",\n };\n\n if (!onRequest) {\n res.writeHead(501);\n res.end(\"Not Implemented\");\n return;\n }\n\n const response = await onRequest(transportRequest);\n const outgoingHeaders: OutgoingHttpHeaders = {};\n\n for (const [key, value] of Object.entries(response.headers)) {\n outgoingHeaders[key] = value;\n }\n\n res.writeHead(response.status, response.statusText ?? \"\", outgoingHeaders);\n\n if (response.body != null) {\n if (response.body instanceof Uint8Array) {\n res.end(response.body);\n } else if (typeof response.body === \"string\") {\n res.end(response.body);\n } else {\n res.end(JSON.stringify(response.body));\n }\n } else {\n res.end();\n }\n } catch {\n if (!res.headersSent) {\n res.writeHead(500);\n res.end(\"Internal Server Error\");\n } else {\n res.destroy();\n }\n } finally {\n req.removeListener(\"aborted\", abortRequest);\n req.removeListener(\"close\", abortIncompleteRequest);\n res.removeListener(\"close\", abortIncompleteResponse);\n }\n });\n\n let closed = false;\n const close = (): Promise<void> => {\n if (closed) return Promise.resolve();\n closed = true;\n signal?.removeEventListener(\"abort\", closeOnAbort);\n server.removeListener(\"error\", reportRuntimeError);\n\n if (!server.listening) return Promise.resolve();\n return new Promise<void>((resolveClose, rejectClose) => {\n server.close((error) => {\n if (error) rejectClose(error);\n else resolveClose();\n });\n });\n };\n const closeOnAbort = () => {\n void close();\n };\n const reportRuntimeError = (error: Error) => {\n
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["DEFAULT_MAX_BODY_BYTES", "loadNodeHttp", "options", "req", "extendedRequest", "isBodyAllowed", "res", "body", "headers", "cookies", "value", "key", "lowerKey", "existing", "host", "port", "signal", "onRequest", "createServer", "server", "requestController", "abortRequest", "abortIncompleteRequest", "abortIncompleteResponse", "contentLength", "chunks", "receivedBytes", "chunk", "transportRequest", "response", "outgoingHeaders", "closed", "close", "closeOnAbort", "reportRuntimeError", "resolveClose", "rejectClose", "
|
|
4
|
+
"sourcesContent": ["import type { IncomingMessage, OutgoingHttpHeaders, ServerResponse } from \"node:http\";\nimport type {\n HyperTransport,\n LogLevel,\n SenderProtocol,\n TransportListenOptions,\n TransportRequest,\n TransportResponse,\n TransportServer,\n} from \"@hyperttp/types\";\n\nconst DEFAULT_MAX_BODY_BYTES = 10 * 1024 * 1024;\n\nexport interface FetchTransportOptions {\n /**\n * @ru Кастомный список поддерживаемых протоколов.\n * @en Custom list of supported protocols.\n */\n protocols?: SenderProtocol[];\n /**\n * @ru Максимальный размер входящего серверного тела в байтах. Превышение\n * возвращает HTTP 413 до передачи тела обработчику.\n * @en Maximum incoming server request body size in bytes. Exceeding it returns\n * HTTP 413 before the body reaches the handler.\n */\n maxBodyBytes?: number;\n /**\n * @ru Обработчик ошибок входящих серверных запросов.\n * @en Error hook for incoming server requests.\n */\n onError?: (error: unknown, request: TransportRequest) => void;\n logger?: (level: LogLevel, message: string, meta?: unknown) => void;\n}\n\ntype ExtendedTransportRequest = TransportRequest & {\n stream?: boolean;\n followRedirects?: boolean;\n};\n\nasync function loadNodeHttp(): Promise<typeof import(\"node:http\")> {\n if (typeof process === \"undefined\" || !process.versions?.node) {\n throw new Error(\"[FetchTransport] listen() is only available in Node.js.\");\n }\n\n const specifier = \"node:http\";\n return import(/* @vite-ignore */ specifier);\n}\n\n/**\n * @ru Минимальный транспорт на базе нативного fetch. Гарантированный fallback,\n * когда ни один пакетный транспорт (@hyperttp/transport-undici/bun) не установлен.\n * @en Minimal native fetch-based transport. A guaranteed fallback used when no\n * packaged transport (@hyperttp/transport-undici/bun) is installed.\n */\nexport class FetchTransport implements HyperTransport {\n public readonly protocols: readonly SenderProtocol[];\n private readonly maxBodyBytes: number;\n private readonly onError?: FetchTransportOptions[\"onError\"];\n private readonly logger?: FetchTransportOptions[\"logger\"];\n\n /**\n * @ru Создаёт fallback-транспорт на базе глобального `fetch`.\n * @en Creates a fallback transport based on global `fetch`.\n * @param options - Поддерживаемые протоколы и серверный лимит тела. @en Supported protocols and server body limit.\n */\n constructor(options: FetchTransportOptions = {}) {\n this.protocols = Object.freeze(options.protocols ?? [\"rest\"]);\n this.maxBodyBytes = options.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;\n this.onError = options.onError;\n this.logger = options.logger;\n }\n\n public async execute(req: TransportRequest): Promise<TransportResponse> {\n const extendedRequest = req as ExtendedTransportRequest;\n const isBodyAllowed = req.method !== \"GET\" && req.method !== \"HEAD\";\n\n const res = await fetch(req.url, {\n method: req.method,\n headers: req.headers as Record<string, string>,\n body: isBodyAllowed ? ((req.body ?? null) as BodyInit | null) : null,\n signal: req.signal,\n redirect: extendedRequest.followRedirects === false ? \"manual\" : \"follow\",\n });\n\n const body = extendedRequest.stream ? res.body : new Uint8Array(await res.arrayBuffer());\n const headers: Record<string, string | string[]> = {};\n\n if (typeof res.headers.getSetCookie === \"function\") {\n const cookies = res.headers.getSetCookie();\n if (cookies.length > 0) {\n headers[\"set-cookie\"] = cookies;\n }\n }\n\n res.headers.forEach((value, key) => {\n const lowerKey = key.toLowerCase();\n\n if (lowerKey === \"set-cookie\" && headers[\"set-cookie\"]) {\n return;\n }\n\n if (headers[lowerKey]) {\n const existing = headers[lowerKey];\n headers[lowerKey] = Array.isArray(existing) ? [...existing, value] : [existing, value];\n } else {\n headers[lowerKey] = value;\n }\n });\n\n return {\n status: res.status,\n statusText: res.statusText,\n headers,\n url: res.url,\n body,\n };\n }\n\n public async listen(options: TransportListenOptions): Promise<TransportServer> {\n const { host, port, signal, onRequest } = options;\n if (signal?.aborted) {\n throw signal.reason ?? new DOMException(\"The operation was aborted\", \"AbortError\");\n }\n\n const { createServer } = await loadNodeHttp();\n\n const server = createServer(async (req: IncomingMessage, res: ServerResponse) => {\n const requestController = new AbortController();\n const abortRequest = () => {\n if (!requestController.signal.aborted) {\n requestController.abort(new DOMException(\"Client disconnected\", \"AbortError\"));\n }\n };\n const abortIncompleteRequest = () => {\n if (!req.complete) abortRequest();\n };\n const abortIncompleteResponse = () => {\n if (!res.writableEnded) abortRequest();\n };\n\n req.once(\"aborted\", abortRequest);\n req.once(\"close\", abortIncompleteRequest);\n res.once(\"close\", abortIncompleteResponse);\n\n try {\n const contentLength = Number(req.headers[\"content-length\"] ?? 0);\n if (Number.isFinite(contentLength) && contentLength > this.maxBodyBytes) {\n res.writeHead(413);\n res.end(\"Payload Too Large\");\n return;\n }\n\n const chunks: Uint8Array[] = [];\n let receivedBytes = 0;\n\n for await (const chunk of req) {\n receivedBytes += chunk.byteLength;\n if (receivedBytes > this.maxBodyBytes) {\n res.writeHead(413);\n res.end(\"Payload Too Large\");\n return;\n }\n chunks.push(chunk);\n }\n\n const body = chunks.length > 0 ? Buffer.concat(chunks) : undefined;\n const headers: Record<string, string | string[]> = {};\n\n for (const [key, value] of Object.entries(req.headers)) {\n if (value !== undefined) {\n headers[key] = value;\n }\n }\n\n const transportRequest: TransportRequest = {\n method: req.method ?? \"GET\",\n url: req.url ?? \"/\",\n headers,\n body,\n signal: requestController.signal,\n protocol: this.protocols[0] ?? \"rest\",\n };\n\n if (!onRequest) {\n res.writeHead(501);\n res.end(\"Not Implemented\");\n return;\n }\n\n const response = await onRequest(transportRequest);\n const outgoingHeaders: OutgoingHttpHeaders = {};\n\n for (const [key, value] of Object.entries(response.headers)) {\n outgoingHeaders[key] = value;\n }\n\n res.writeHead(response.status, response.statusText ?? \"\", outgoingHeaders);\n\n if (response.body != null) {\n if (response.body instanceof Uint8Array) {\n res.end(response.body);\n } else if (typeof response.body === \"string\") {\n res.end(response.body);\n } else {\n res.end(JSON.stringify(response.body));\n }\n } else {\n res.end();\n }\n } catch (error) {\n this.onError?.(error, {\n method: req.method ?? \"GET\",\n url: req.url ?? \"/\",\n headers: req.headers as Record<string, string | string[]>,\n signal: requestController.signal,\n protocol: this.protocols[0] ?? \"rest\",\n });\n if (!res.headersSent) {\n res.writeHead(500);\n res.end(\"Internal Server Error\");\n } else {\n res.destroy();\n }\n } finally {\n req.removeListener(\"aborted\", abortRequest);\n req.removeListener(\"close\", abortIncompleteRequest);\n res.removeListener(\"close\", abortIncompleteResponse);\n }\n });\n\n let closed = false;\n const close = (): Promise<void> => {\n if (closed) return Promise.resolve();\n closed = true;\n signal?.removeEventListener(\"abort\", closeOnAbort);\n server.removeListener(\"error\", reportRuntimeError);\n\n if (!server.listening) return Promise.resolve();\n return new Promise<void>((resolveClose, rejectClose) => {\n server.close((error) => {\n if (error) rejectClose(error);\n else resolveClose();\n });\n });\n };\n const closeOnAbort = () => {\n void close();\n };\n const reportRuntimeError = (error: Error) => {\n const message = \"[FetchTransport] HTTP server error\";\n if (this.logger) {\n this.logger(\"error\", message, error);\n } else {\n console.error(`${message}:`, error);\n }\n };\n\n if (signal?.aborted) {\n throw signal.reason ?? new DOMException(\"The operation was aborted\", \"AbortError\");\n }\n signal?.addEventListener(\"abort\", closeOnAbort, { once: true });\n\n return new Promise<TransportServer>((resolve, reject) => {\n const rejectStartup = (error: Error) => {\n signal?.removeEventListener(\"abort\", closeOnAbort);\n reject(error);\n };\n\n server.once(\"error\", rejectStartup);\n server.listen({ host, port }, () => {\n server.removeListener(\"error\", rejectStartup);\n server.on(\"error\", reportRuntimeError);\n resolve({ close });\n });\n });\n }\n\n public async close(): Promise<void> {}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["DEFAULT_MAX_BODY_BYTES", "loadNodeHttp", "options", "req", "extendedRequest", "isBodyAllowed", "res", "body", "headers", "cookies", "value", "key", "lowerKey", "existing", "host", "port", "signal", "onRequest", "createServer", "server", "requestController", "abortRequest", "abortIncompleteRequest", "abortIncompleteResponse", "contentLength", "chunks", "receivedBytes", "chunk", "transportRequest", "response", "outgoingHeaders", "error", "closed", "close", "closeOnAbort", "reportRuntimeError", "resolveClose", "rejectClose", "message", "resolve", "reject", "rejectStartup"]
|
|
7
7
|
}
|
package/transports/manager.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { HyperTransport, SenderProtocol } from "@hyperttp/types";
|
|
1
|
+
import type { HyperTransport, LogLevel, SenderProtocol } from "@hyperttp/types";
|
|
2
2
|
export type Runtime = "bun" | "node" | "deno" | "browser";
|
|
3
3
|
/**
|
|
4
4
|
* @ru Опции разрешения транспорта. `customTransport` имеет приоритет над автовыбором.
|
|
@@ -6,6 +6,8 @@ export type Runtime = "bun" | "node" | "deno" | "browser";
|
|
|
6
6
|
*/
|
|
7
7
|
export interface ResolveTransportOptions {
|
|
8
8
|
customTransport?: HyperTransport;
|
|
9
|
+
logger?: (level: LogLevel, message: string, meta?: unknown) => void;
|
|
10
|
+
verbose?: boolean;
|
|
9
11
|
[key: string]: unknown;
|
|
10
12
|
}
|
|
11
13
|
export declare const CURRENT_RUNTIME: Runtime;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/transports/manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/transports/manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAOhF,MAAM,MAAM,OAAO,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAE1D;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACtC,eAAe,CAAC,EAAE,cAAc,CAAC;IACjC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACpE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,eAAO,MAAM,eAAe,EAAE,OAK1B,CAAC;AA8EL;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,QAAQ,GAAE,cAAuB,EACjC,MAAM,CAAC,EAAE,uBAAuB,GAC/B,OAAO,CAAC,cAAc,CAAC,CA0BzB;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,GAAE,cAAuB,GAAG,cAAc,GAAG,SAAS,CAEhG;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,cAAc,GAAG,IAAI,CAMpE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAG3C"}
|
package/transports/manager.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";import{FetchTransport as
|
|
1
|
+
"use strict";import{FetchTransport as y}from"./fetch.js";import{dynamicImport as T,isModuleNotFoundError as h}from"../utils/modules.js";export const CURRENT_RUNTIME=typeof Bun<"u"?"bun":typeof Deno<"u"?"deno":typeof process<"u"&&process.versions?.node?"node":"browser";const m=[{runtime:["bun"],pkg:"@hyperttp/transport-bun",export:"BunTransport"},{runtime:["node"],pkg:"@hyperttp/transport-undici",export:"UndiciTransport"},{runtime:["deno"],pkg:"@hyperttp/transport-deno",export:"DenoTransport"}],d=m.filter(t=>t.runtime.includes(CURRENT_RUNTIME)),n=new Map,u=new Map;function c(t,e){return typeof t.supports=="function"?t.supports(e):t.protocols?.includes(e)??!0}async function l(t){try{typeof t.destroy=="function"?await t.destroy():typeof t.close=="function"&&await t.close()}catch{}}async function w(t,e){for(let s=0;s<d.length;s++){const a=d[s];try{const i=await T(a.pkg),f=i[a.export]??i.default;if(typeof f!="function")continue;const p=new f(e??{});if(!c(p,t)){await l(p);continue}return p}catch(i){if(!h(i))throw i}}const r=`[HyperCore] Fast transport (e.g. @hyperttp/transport-undici) unavailable for runtime "${CURRENT_RUNTIME}". Falling back to slow FetchTransport.`;e?.logger?e.logger("warn",r):e?.verbose&&console.warn(r);const o=new y(e);if(c(o,t))return o;throw await l(o),new Error(`[HyperCore] No transport available for protocol "${t}" in runtime "${CURRENT_RUNTIME}".`)}export async function resolveTransport(t="rest",e){if(e?.customTransport){if(!c(e.customTransport,t))throw new Error(`[HyperCore] Custom transport does not support protocol "${t}".`);return n.set(t,e.customTransport),e.customTransport}const r=n.get(t);if(r)return r;const o=u.get(t);if(o)return o;const s=w(t,e).then(a=>(n.set(t,a),a)).finally(()=>{u.delete(t)});return u.set(t,s),s}export function getCachedTransport(t="rest"){return n.get(t)}export function evictCachedTransport(t){for(const[e,r]of n)r===t&&n.delete(e)}export function resetCachedTransport(){n.clear(),u.clear()}
|
|
2
2
|
//# sourceMappingURL=manager.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/transports/manager.ts"],
|
|
4
|
-
"sourcesContent": ["import type { HyperTransport, SenderProtocol } from \"@hyperttp/types\";\nimport { FetchTransport, type FetchTransportOptions } from \"./fetch.js\";\n\ndeclare const Bun: unknown;\ndeclare const Deno: unknown;\n\nexport type Runtime = \"bun\" | \"node\" | \"deno\" | \"browser\";\n\n/**\n * @ru Опции разрешения транспорта. `customTransport` имеет приоритет над автовыбором.\n * @en Transport resolution options. `customTransport` takes priority over auto-selection.\n */\nexport interface ResolveTransportOptions {\n customTransport?: HyperTransport;\n [key: string]: unknown;\n}\n\nexport const CURRENT_RUNTIME: Runtime = (() => {\n if (typeof Bun !== \"undefined\") return \"bun\";\n if (typeof Deno !== \"undefined\") return \"deno\";\n if (typeof process !== \"undefined\" && process.versions?.node) return \"node\";\n return \"browser\";\n})();\n\ntype TransportDef = {\n readonly runtime: readonly Runtime[];\n readonly pkg: string;\n readonly export: string;\n
|
|
5
|
-
"mappings": "aACA,OAAS,kBAAAA,MAAkD,
|
|
6
|
-
"names": ["FetchTransport", "
|
|
4
|
+
"sourcesContent": ["import type { HyperTransport, LogLevel, SenderProtocol } from \"@hyperttp/types\";\nimport { FetchTransport, type FetchTransportOptions } from \"./fetch.js\";\nimport { dynamicImport, isModuleNotFoundError } from \"../utils/modules.js\";\n\ndeclare const Bun: unknown;\ndeclare const Deno: unknown;\n\nexport type Runtime = \"bun\" | \"node\" | \"deno\" | \"browser\";\n\n/**\n * @ru Опции разрешения транспорта. `customTransport` имеет приоритет над автовыбором.\n * @en Transport resolution options. `customTransport` takes priority over auto-selection.\n */\nexport interface ResolveTransportOptions {\n customTransport?: HyperTransport;\n logger?: (level: LogLevel, message: string, meta?: unknown) => void;\n verbose?: boolean;\n [key: string]: unknown;\n}\n\nexport const CURRENT_RUNTIME: Runtime = (() => {\n if (typeof Bun !== \"undefined\") return \"bun\";\n if (typeof Deno !== \"undefined\") return \"deno\";\n if (typeof process !== \"undefined\" && process.versions?.node) return \"node\";\n return \"browser\";\n})();\n\ntype TransportDef = {\n readonly runtime: readonly Runtime[];\n readonly pkg: string;\n readonly export: string;\n};\n\nconst TRANSPORT_DEFS: readonly TransportDef[] = [\n { runtime: [\"bun\"], pkg: \"@hyperttp/transport-bun\", export: \"BunTransport\" },\n { runtime: [\"node\"], pkg: \"@hyperttp/transport-undici\", export: \"UndiciTransport\" },\n { runtime: [\"deno\"], pkg: \"@hyperttp/transport-deno\", export: \"DenoTransport\" },\n];\n\nconst CANDIDATES = TRANSPORT_DEFS.filter((t) => t.runtime.includes(CURRENT_RUNTIME));\n\nconst transportCache = new Map<string, HyperTransport>();\nconst transportResolutions = new Map<string, Promise<HyperTransport>>();\n\nfunction supportsProtocol(transport: HyperTransport, protocol: SenderProtocol): boolean {\n return typeof transport.supports === \"function\"\n ? transport.supports(protocol)\n : (transport.protocols?.includes(protocol) ?? true);\n}\n\nasync function disposeUnusedTransport(transport: HyperTransport): Promise<void> {\n try {\n if (typeof transport.destroy === \"function\") {\n await transport.destroy();\n } else if (typeof transport.close === \"function\") {\n await transport.close();\n }\n } catch {\n //\n }\n}\n\nasync function createTransport(\n protocol: SenderProtocol,\n config?: ResolveTransportOptions,\n): Promise<HyperTransport> {\n for (let i = 0; i < CANDIDATES.length; i++) {\n const t = CANDIDATES[i]!;\n try {\n const mod = await dynamicImport(t.pkg);\n const candidate = (mod[t.export] ?? mod.default) as\n | { new (opts?: unknown): HyperTransport }\n | undefined;\n if (typeof candidate !== \"function\") continue;\n\n const instance = new candidate(config ?? {});\n if (!supportsProtocol(instance, protocol)) {\n await disposeUnusedTransport(instance);\n continue;\n }\n\n return instance;\n } catch (err) {\n if (!isModuleNotFoundError(err)) throw err;\n }\n }\n\n const message = `[HyperCore] Fast transport (e.g. @hyperttp/transport-undici) unavailable for runtime \"${CURRENT_RUNTIME}\". Falling back to slow FetchTransport.`;\n if (config?.logger) {\n config.logger(\"warn\", message);\n } else if (config?.verbose) {\n console.warn(message);\n }\n\n const fetchTransport = new FetchTransport(config as unknown as FetchTransportOptions);\n if (supportsProtocol(fetchTransport, protocol)) return fetchTransport;\n\n await disposeUnusedTransport(fetchTransport);\n throw new Error(\n `[HyperCore] No transport available for protocol \"${protocol}\" in runtime \"${CURRENT_RUNTIME}\".`,\n );\n}\n\n/**\n * @ru Разрешает оптимальный транспорт для указанного протокола и текущей среды.\n * Кастомный транспорт из конфигурации имеет приоритет над автовыбором.\n * @en Resolves optimal transport for the given protocol and current runtime.\n * A custom transport from the config takes priority over auto-selection.\n */\nexport async function resolveTransport(\n protocol: SenderProtocol = \"rest\",\n config?: ResolveTransportOptions,\n): Promise<HyperTransport> {\n if (config?.customTransport) {\n if (!supportsProtocol(config.customTransport, protocol)) {\n throw new Error(`[HyperCore] Custom transport does not support protocol \"${protocol}\".`);\n }\n transportCache.set(protocol, config.customTransport);\n return config.customTransport;\n }\n\n const cached = transportCache.get(protocol);\n if (cached) return cached;\n\n const pending = transportResolutions.get(protocol);\n if (pending) return pending;\n\n const resolution = createTransport(protocol, config)\n .then((transport) => {\n transportCache.set(protocol, transport);\n return transport;\n })\n .finally(() => {\n transportResolutions.delete(protocol);\n });\n\n transportResolutions.set(protocol, resolution);\n return resolution;\n}\n\n/**\n * @ru Синхронно возвращает транспорт из кэша без создания Promise.\n * @en Synchronously returns a cached transport without creating a Promise.\n * @param protocol - Протокол, для которого запрашивается транспорт. @en Protocol whose transport is requested.\n * @returns Кэшированный транспорт или `undefined`. @en Cached transport or `undefined`.\n */\nexport function getCachedTransport(protocol: SenderProtocol = \"rest\"): HyperTransport | undefined {\n return transportCache.get(protocol);\n}\n\n/**\n * @ru Удаляет все записи кэша, ссылающиеся на указанный транспорт.\n * @en Removes every cache entry that references the given transport.\n * @param transport - Экземпляр транспорта для удаления из кэша. @en Transport instance to evict from the cache.\n */\nexport function evictCachedTransport(transport: HyperTransport): void {\n for (const [protocol, cached] of transportCache) {\n if (cached === transport) {\n transportCache.delete(protocol);\n }\n }\n}\n\n/**\n * @ru Очищает кэш транспортов и ожидающих их разрешений. Не закрывает уже\n * созданные экземпляры транспорта.\n * @en Clears cached transports and pending resolutions. It does not close\n * already-created transport instances.\n */\nexport function resetCachedTransport(): void {\n transportCache.clear();\n transportResolutions.clear();\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["FetchTransport", "dynamicImport", "isModuleNotFoundError", "TRANSPORT_DEFS", "CANDIDATES", "transportCache", "transportResolutions", "supportsProtocol", "transport", "protocol", "disposeUnusedTransport", "createTransport", "config", "i", "t", "mod", "candidate", "instance", "err", "message", "fetchTransport", "cached", "pending", "resolution"]
|
|
7
7
|
}
|