@atproto/lex-server 0.0.1 → 0.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/CHANGELOG.md +20 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lex-server.d.ts +12 -9
- package/dist/lex-server.d.ts.map +1 -1
- package/dist/lex-server.js +35 -27
- package/dist/lex-server.js.map +1 -1
- package/dist/nodejs.d.ts +3 -3
- package/dist/nodejs.d.ts.map +1 -1
- package/dist/nodejs.js +49 -19
- package/dist/nodejs.js.map +1 -1
- package/dist/service-auth.d.ts +67 -0
- package/dist/service-auth.d.ts.map +1 -0
- package/dist/service-auth.js +191 -0
- package/dist/service-auth.js.map +1 -0
- package/package.json +10 -7
- package/src/index.ts +1 -0
- package/src/lex-server.test.ts +2 -2
- package/src/lex-server.ts +56 -45
- package/src/nodejs.ts +64 -30
- package/src/service-auth.ts +375 -0
- package/dist/example.d.ts +0 -2
- package/dist/example.d.ts.map +0 -1
- package/dist/example.js +0 -36
- package/dist/example.js.map +0 -1
- package/dist/lex-auth-error.d.ts +0 -15
- package/dist/lex-auth-error.d.ts.map +0 -1
- package/dist/lex-auth-error.js +0 -52
- package/dist/lex-auth-error.js.map +0 -1
- package/dist/subscripotion.d.ts +0 -2
- package/dist/subscripotion.d.ts.map +0 -1
- package/dist/subscripotion.js +0 -36
- package/dist/subscripotion.js.map +0 -1
- package/dist/test.d.mts +0 -2
- package/dist/test.d.mts.map +0 -1
- package/dist/test.mjs +0 -52
- package/dist/test.mjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @atproto/lex-server
|
|
2
2
|
|
|
3
|
+
## 0.0.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#4501](https://github.com/bluesky-social/atproto/pull/4501) [`2f78893`](https://github.com/bluesky-social/atproto/commit/2f78893ace3bbf14d4bac36837820ddb46658c98) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Add service auth authentication method
|
|
8
|
+
|
|
9
|
+
- Updated dependencies [[`2f78893`](https://github.com/bluesky-social/atproto/commit/2f78893ace3bbf14d4bac36837820ddb46658c98), [`2f78893`](https://github.com/bluesky-social/atproto/commit/2f78893ace3bbf14d4bac36837820ddb46658c98), [`2f78893`](https://github.com/bluesky-social/atproto/commit/2f78893ace3bbf14d4bac36837820ddb46658c98), [`2f78893`](https://github.com/bluesky-social/atproto/commit/2f78893ace3bbf14d4bac36837820ddb46658c98), [`2f78893`](https://github.com/bluesky-social/atproto/commit/2f78893ace3bbf14d4bac36837820ddb46658c98)]:
|
|
10
|
+
- @atproto/lex-data@0.0.6
|
|
11
|
+
- @atproto/did@0.2.4
|
|
12
|
+
- @atproto/lex-schema@0.0.7
|
|
13
|
+
- @atproto/lex-cbor@0.0.6
|
|
14
|
+
- @atproto/lex-json@0.0.6
|
|
15
|
+
- @atproto-labs/did-resolver@0.2.5
|
|
16
|
+
|
|
17
|
+
## 0.0.2
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- [#4498](https://github.com/bluesky-social/atproto/pull/4498) [`e9f065f`](https://github.com/bluesky-social/atproto/commit/e9f065fce85cd7940617eb611050e6ef65c54c04) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Add AbortSignal to context
|
|
22
|
+
|
|
3
23
|
## 0.0.1
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,KAAK,YAAY,EACjB,KAAK,YAAY,GAClB,MAAM,mBAAmB,CAAA;AAE1B,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,KAAK,YAAY,EACjB,KAAK,YAAY,GAClB,MAAM,mBAAmB,CAAA;AAE1B,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,mBAAmB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -6,4 +6,5 @@ var lex_data_1 = require("@atproto/lex-data");
|
|
|
6
6
|
Object.defineProperty(exports, "LexError", { enumerable: true, get: function () { return lex_data_1.LexError; } });
|
|
7
7
|
tslib_1.__exportStar(require("./errors.js"), exports);
|
|
8
8
|
tslib_1.__exportStar(require("./lex-server.js"), exports);
|
|
9
|
+
tslib_1.__exportStar(require("./service-auth.js"), exports);
|
|
9
10
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;AAAA,8CAI0B;AAHxB,oGAAA,QAAQ,OAAA;AAKV,sDAA2B;AAC3B,0DAA+B","sourcesContent":["export {\n LexError,\n type LexErrorCode,\n type LexErrorData,\n} from '@atproto/lex-data'\n\nexport * from './errors.js'\nexport * from './lex-server.js'\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;AAAA,8CAI0B;AAHxB,oGAAA,QAAQ,OAAA;AAKV,sDAA2B;AAC3B,0DAA+B;AAC/B,4DAAiC","sourcesContent":["export {\n LexError,\n type LexErrorCode,\n type LexErrorData,\n} from '@atproto/lex-data'\n\nexport * from './errors.js'\nexport * from './lex-server.js'\nexport * from './service-auth.js'\n"]}
|
package/dist/lex-server.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { InferMethodInput, InferMethodMessage, InferMethodOutput, InferMethodOutputBody, InferMethodOutputEncoding, InferMethodParams, Main, Procedure, Query, Subscription } from '@atproto/lex-schema';
|
|
2
|
-
type
|
|
2
|
+
type Awaitable<T> = T | Promise<T>;
|
|
3
|
+
export type LexMethod = Query | Procedure | Subscription;
|
|
3
4
|
export type NetAddr = {
|
|
4
5
|
hostname: string;
|
|
5
6
|
port: number;
|
|
@@ -9,10 +10,10 @@ export type UnixAddr = {
|
|
|
9
10
|
path: string;
|
|
10
11
|
transport: 'unix' | 'unixpacket';
|
|
11
12
|
};
|
|
12
|
-
export type Addr = NetAddr | UnixAddr;
|
|
13
|
-
export type ConnectionInfo = {
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
export type Addr = NetAddr | UnixAddr | undefined;
|
|
14
|
+
export type ConnectionInfo<A extends Addr = Addr> = {
|
|
15
|
+
remoteAddr: A;
|
|
16
|
+
completed: Promise<void>;
|
|
16
17
|
};
|
|
17
18
|
type Handler = (request: Request, connection?: ConnectionInfo) => Promise<Response>;
|
|
18
19
|
export type LexRouterHandlerContext<Method extends LexMethod, Credentials> = {
|
|
@@ -20,6 +21,7 @@ export type LexRouterHandlerContext<Method extends LexMethod, Credentials> = {
|
|
|
20
21
|
input: InferMethodInput<Method, Body>;
|
|
21
22
|
params: InferMethodParams<Method>;
|
|
22
23
|
request: Request;
|
|
24
|
+
signal: AbortSignal;
|
|
23
25
|
connection?: ConnectionInfo;
|
|
24
26
|
};
|
|
25
27
|
type AsOptionalPayloadOptions<T> = T extends undefined | void ? {
|
|
@@ -32,22 +34,23 @@ export type LexRouterHandlerOutput<Method extends Query | Procedure> = Response
|
|
|
32
34
|
encoding?: 'application/json';
|
|
33
35
|
body: InferMethodOutputBody<Method>;
|
|
34
36
|
} : AsOptionalPayloadOptions<InferMethodOutput<Method, BodyInit>>));
|
|
35
|
-
export type LexRouterMethodHandler<Method extends Query | Procedure = Query | Procedure, Credentials = unknown> = (ctx: LexRouterHandlerContext<Method, Credentials>) =>
|
|
37
|
+
export type LexRouterMethodHandler<Method extends Query | Procedure = Query | Procedure, Credentials = unknown> = (ctx: LexRouterHandlerContext<Method, Credentials>) => Awaitable<LexRouterHandlerOutput<Method>>;
|
|
36
38
|
export type LexRouterMethodConfig<Method extends Query | Procedure = Query | Procedure, Credentials = unknown> = {
|
|
37
39
|
handler: LexRouterMethodHandler<Method, Credentials>;
|
|
38
|
-
auth: LexRouterAuth<
|
|
40
|
+
auth: LexRouterAuth<Credentials, Method>;
|
|
39
41
|
};
|
|
40
42
|
export type LexRouterSubscriptionHandler<Method extends Subscription = Subscription, Credentials = unknown> = (ctx: LexRouterHandlerContext<Method, Credentials>) => AsyncIterable<InferMethodMessage<Method>>;
|
|
41
43
|
export type LexRouterSubscriptionConfig<Method extends Subscription = Subscription, Credentials = unknown> = {
|
|
42
44
|
handler: LexRouterSubscriptionHandler<Method, Credentials>;
|
|
43
|
-
auth: LexRouterAuth<
|
|
45
|
+
auth: LexRouterAuth<Credentials, Method>;
|
|
44
46
|
};
|
|
45
47
|
export type LexRouterAuthContext<Method extends LexMethod = LexMethod> = {
|
|
48
|
+
method: Method;
|
|
46
49
|
params: InferMethodParams<Method>;
|
|
47
50
|
request: Request;
|
|
48
51
|
connection?: ConnectionInfo;
|
|
49
52
|
};
|
|
50
|
-
export type LexRouterAuth<Method extends LexMethod = LexMethod
|
|
53
|
+
export type LexRouterAuth<Credentials = unknown, Method extends LexMethod = LexMethod> = (ctx: LexRouterAuthContext<Method>) => Credentials | Promise<Credentials>;
|
|
51
54
|
export type LexErrorHandlerContext = {
|
|
52
55
|
error: unknown;
|
|
53
56
|
request: Request;
|
package/dist/lex-server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lex-server.d.ts","sourceRoot":"","sources":["../src/lex-server.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,EACrB,yBAAyB,EACzB,iBAAiB,EACjB,IAAI,EAEJ,SAAS,EACT,KAAK,EACL,YAAY,EAGb,MAAM,qBAAqB,CAAA;AAG5B,KAAK,SAAS,GAAG,KAAK,GAAG,SAAS,GAAG,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"lex-server.d.ts","sourceRoot":"","sources":["../src/lex-server.ts"],"names":[],"mappings":"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"}
|
package/dist/lex-server.js
CHANGED
|
@@ -43,7 +43,7 @@ class LexRouter {
|
|
|
43
43
|
const url = new URL(request.url);
|
|
44
44
|
const params = method.parameters.fromURLSearchParams(url.searchParams);
|
|
45
45
|
const credentials = auth
|
|
46
|
-
? await auth({ params, request, connection })
|
|
46
|
+
? await auth({ method, params, request, connection })
|
|
47
47
|
: undefined;
|
|
48
48
|
const input = await getInput(request);
|
|
49
49
|
const output = await methodHandler({
|
|
@@ -52,6 +52,7 @@ class LexRouter {
|
|
|
52
52
|
input,
|
|
53
53
|
request,
|
|
54
54
|
connection,
|
|
55
|
+
signal: request.signal,
|
|
55
56
|
});
|
|
56
57
|
if (output instanceof Response) {
|
|
57
58
|
return output;
|
|
@@ -97,57 +98,57 @@ class LexRouter {
|
|
|
97
98
|
},
|
|
98
99
|
});
|
|
99
100
|
}
|
|
101
|
+
if (request.signal.aborted) {
|
|
102
|
+
return Response.json({ error: 'RequestAborted', message: 'The request was aborted' }, { status: 499 });
|
|
103
|
+
}
|
|
100
104
|
try {
|
|
101
105
|
const { response, socket } = upgradeWebSocket(request);
|
|
102
|
-
|
|
103
|
-
|
|
106
|
+
// @NOTE We are using a distinct signal than request.signal because that
|
|
107
|
+
// signal may get aborted before the WebSocket is closed (this is the
|
|
108
|
+
// case with Deno).
|
|
109
|
+
const abortController = new AbortController();
|
|
110
|
+
const { signal } = abortController;
|
|
111
|
+
const abort = () => abortController.abort();
|
|
112
|
+
const onMessage = (event) => {
|
|
113
|
+
const error = new lex_data_1.LexError('InvalidRequest', 'XRPC subscriptions do not accept messages', { cause: event });
|
|
104
114
|
socket.send(encodeErrorFrame(error));
|
|
105
115
|
socket.close(1008, error.error);
|
|
106
|
-
}
|
|
107
|
-
|
|
116
|
+
};
|
|
117
|
+
const onOpen = async () => {
|
|
108
118
|
try {
|
|
109
119
|
const url = new URL(request.url);
|
|
110
120
|
const params = method.parameters.fromURLSearchParams(url.searchParams);
|
|
111
121
|
const credentials = auth
|
|
112
|
-
? await auth({ params, request, connection })
|
|
122
|
+
? await auth({ method, params, request, connection })
|
|
113
123
|
: undefined;
|
|
114
|
-
|
|
124
|
+
signal.throwIfAborted();
|
|
115
125
|
const iterable = methodHandler({
|
|
116
126
|
credentials,
|
|
117
127
|
params,
|
|
118
128
|
input: undefined,
|
|
119
129
|
request,
|
|
120
130
|
connection,
|
|
131
|
+
signal,
|
|
121
132
|
});
|
|
122
133
|
const iterator = iterable[Symbol.asyncIterator]();
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
await iterator.return();
|
|
129
|
-
}
|
|
130
|
-
catch {
|
|
131
|
-
// Ignore
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
socket.addEventListener('error', abort);
|
|
135
|
-
socket.addEventListener('close', abort);
|
|
136
|
-
}
|
|
137
|
-
while (socket.readyState === 1) {
|
|
134
|
+
signal.addEventListener('abort', async () => {
|
|
135
|
+
// @NOTE will cause the process to crash if this throws
|
|
136
|
+
await iterator.return?.();
|
|
137
|
+
});
|
|
138
|
+
while (!signal.aborted && socket.readyState === 1) {
|
|
138
139
|
const result = await iterator.next();
|
|
139
140
|
if (result.done)
|
|
140
141
|
break;
|
|
141
|
-
// Should not be needed (socket would emit "close" event)
|
|
142
|
-
request.signal.throwIfAborted();
|
|
143
142
|
// @TODO add validation of output based on method.output.schema?
|
|
144
143
|
const data = encodeMessageFrame(method, result.value);
|
|
145
144
|
socket.send(data);
|
|
146
145
|
// Apply backpressure by waiting for the buffered data to drain
|
|
147
146
|
// before generating the next message
|
|
148
|
-
await (0, drain_websocket_js_1.drainWebsocket)(socket,
|
|
147
|
+
await (0, drain_websocket_js_1.drainWebsocket)(socket, signal, this.options);
|
|
148
|
+
}
|
|
149
|
+
if (socket.readyState === 1) {
|
|
150
|
+
socket.close(1000);
|
|
149
151
|
}
|
|
150
|
-
socket.close(1000);
|
|
151
152
|
}
|
|
152
153
|
catch (error) {
|
|
153
154
|
// If the socket is still open, send an error frame before closing
|
|
@@ -165,7 +166,14 @@ class LexRouter {
|
|
|
165
166
|
await onHandlerError({ error, request, method });
|
|
166
167
|
}
|
|
167
168
|
}
|
|
168
|
-
|
|
169
|
+
finally {
|
|
170
|
+
abortController.abort();
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
socket.addEventListener('error', abort);
|
|
174
|
+
socket.addEventListener('close', abort);
|
|
175
|
+
socket.addEventListener('open', onOpen);
|
|
176
|
+
socket.addEventListener('message', onMessage);
|
|
169
177
|
return response;
|
|
170
178
|
}
|
|
171
179
|
catch (error) {
|
package/dist/lex-server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lex-server.js","sourceRoot":"","sources":["../src/lex-server.ts"],"names":[],"mappings":"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","sourcesContent":["import { encode } from '@atproto/lex-cbor'\nimport { LexError, LexValue, isPlainObject, ui8Concat } from '@atproto/lex-data'\nimport { lexParse, lexToJson } from '@atproto/lex-json'\nimport {\n InferMethodInput,\n InferMethodMessage,\n InferMethodOutput,\n InferMethodOutputBody,\n InferMethodOutputEncoding,\n InferMethodParams,\n Main,\n NsidString,\n Procedure,\n Query,\n Subscription,\n getMain,\n isNsidString,\n} from '@atproto/lex-schema'\nimport { drainWebsocket } from './lib/drain-websocket.js'\n\ntype LexMethod = Query | Procedure | Subscription\n\nexport type NetAddr = {\n hostname: string\n port: number\n transport: 'tcp' | 'udp'\n}\n\nexport type UnixAddr = {\n path: string\n transport: 'unix' | 'unixpacket'\n}\n\nexport type Addr = NetAddr | UnixAddr\n\nexport type ConnectionInfo = {\n localAddr?: Addr\n remoteAddr?: Addr\n}\n\ntype Handler = (\n request: Request,\n connection?: ConnectionInfo,\n) => Promise<Response>\n\nexport type LexRouterHandlerContext<Method extends LexMethod, Credentials> = {\n credentials: Credentials\n input: InferMethodInput<Method, Body>\n params: InferMethodParams<Method>\n request: Request\n connection?: ConnectionInfo\n}\n\ntype AsOptionalPayloadOptions<T> = T extends undefined | void\n ? { encoding?: undefined; body?: undefined }\n : T\n\nexport type LexRouterHandlerOutput<Method extends Query | Procedure> =\n | Response\n | ({\n headers?: HeadersInit\n } & (InferMethodOutputEncoding<Method> extends 'application/json'\n ? {\n // Allow omitting body when output is JSON\n encoding?: 'application/json'\n body: InferMethodOutputBody<Method>\n }\n : AsOptionalPayloadOptions<InferMethodOutput<Method, BodyInit>>))\n\nexport type LexRouterMethodHandler<\n Method extends Query | Procedure = Query | Procedure,\n Credentials = unknown,\n> = (\n ctx: LexRouterHandlerContext<Method, Credentials>,\n) => Promise<LexRouterHandlerOutput<Method>>\n\nexport type LexRouterMethodConfig<\n Method extends Query | Procedure = Query | Procedure,\n Credentials = unknown,\n> = {\n handler: LexRouterMethodHandler<Method, Credentials>\n auth: LexRouterAuth<Method, Credentials>\n}\n\nexport type LexRouterSubscriptionHandler<\n Method extends Subscription = Subscription,\n Credentials = unknown,\n> = (\n ctx: LexRouterHandlerContext<Method, Credentials>,\n) => AsyncIterable<InferMethodMessage<Method>>\n\nexport type LexRouterSubscriptionConfig<\n Method extends Subscription = Subscription,\n Credentials = unknown,\n> = {\n handler: LexRouterSubscriptionHandler<Method, Credentials>\n auth: LexRouterAuth<Method, Credentials>\n}\n\nexport type LexRouterAuthContext<Method extends LexMethod = LexMethod> = {\n params: InferMethodParams<Method>\n request: Request\n connection?: ConnectionInfo\n}\n\nexport type LexRouterAuth<\n Method extends LexMethod = LexMethod,\n Credentials = unknown,\n> = (ctx: LexRouterAuthContext<Method>) => Credentials | Promise<Credentials>\n\nexport type LexErrorHandlerContext = {\n error: unknown\n request: Request\n method: LexMethod\n}\n\nexport type UpgradeWebSocket = (request: Request) => {\n socket: WebSocket\n response: Response\n}\n\nexport type LexRouterOptions = {\n upgradeWebSocket?: UpgradeWebSocket\n onHandlerError?: (ctx: LexErrorHandlerContext) => void | Promise<void>\n highWaterMark?: number\n lowWaterMark?: number\n}\n\nexport class LexRouter {\n private handlers: Map<NsidString, Handler> = new Map()\n\n constructor(readonly options: LexRouterOptions = {}) {}\n\n add<M extends Subscription>(\n ns: Main<M>,\n handler: LexRouterSubscriptionHandler<M, void>,\n ): this\n add<M extends Subscription, Credentials>(\n ns: Main<M>,\n config: LexRouterSubscriptionConfig<M, Credentials>,\n ): this\n add<M extends Query | Procedure>(\n ns: Main<M>,\n handler: LexRouterMethodHandler<M, void>,\n ): this\n add<M extends Query | Procedure, Credentials>(\n ns: Main<M>,\n config: LexRouterMethodConfig<M, Credentials>,\n ): this\n add<M extends LexMethod>(\n ns: Main<M>,\n config:\n | LexRouterSubscriptionHandler<any, any>\n | LexRouterSubscriptionConfig<any, any>\n | LexRouterMethodHandler<any, any>\n | LexRouterMethodConfig<any, any>,\n ) {\n const method = getMain(ns)\n if (this.handlers.has(method.nsid)) {\n throw new TypeError(`Method ${method.nsid} already registered`)\n }\n const methodConfig =\n typeof config === 'function'\n ? { handler: config, auth: undefined }\n : config\n\n const handler: Handler =\n method.type === 'subscription'\n ? this.buildSubscriptionHandler(\n method,\n methodConfig.handler as LexRouterSubscriptionHandler<any, any>,\n methodConfig.auth,\n )\n : this.buildMethodHandler(\n method,\n methodConfig.handler as LexRouterMethodHandler<any, any>,\n methodConfig.auth,\n )\n\n this.handlers.set(method.nsid, handler)\n\n return this\n }\n\n private buildMethodHandler<Method extends Query | Procedure, Credentials>(\n method: Method,\n methodHandler: LexRouterMethodHandler<Method, Credentials>,\n auth?: LexRouterAuth<Method, Credentials>,\n ): Handler {\n const getInput = (\n method.type === 'procedure'\n ? getProcedureInput.bind(method)\n : getQueryInput.bind(method)\n ) as (request: Request) => Promise<InferMethodInput<Method, Body>>\n\n return async (\n request: Request,\n connection?: ConnectionInfo,\n ): Promise<Response> => {\n // @NOTE CORS requests should be handled by a middleware before reaching\n // this point.\n if (\n (method.type === 'procedure' && request.method !== 'POST') ||\n (method.type === 'query' &&\n request.method !== 'GET' &&\n request.method !== 'HEAD')\n ) {\n return Response.json(\n { error: 'InvalidRequest', message: 'Method not allowed' },\n { status: 405 },\n )\n }\n\n try {\n const url = new URL(request.url)\n const params = method.parameters.fromURLSearchParams(url.searchParams)\n\n const credentials = auth\n ? await auth({ params, request, connection })\n : (undefined as Credentials)\n\n const input = await getInput(request)\n\n const output = await methodHandler({\n credentials,\n params,\n input,\n request,\n connection,\n })\n\n if (output instanceof Response) {\n return output\n }\n\n // @TODO add validation of output based on method.output.schema?\n\n if (output.body === undefined && output.encoding === undefined) {\n return new Response(null, { status: 200, headers: output.headers })\n }\n\n if (method.output?.encoding === 'application/json') {\n return Response.json(lexToJson(output.body as LexValue), {\n status: 200,\n headers: output.headers,\n })\n }\n\n const headers = new Headers(output.headers)\n headers.set('content-type', output.encoding!)\n return new Response(output.body, { status: 200, headers })\n } catch (error) {\n return this.handleError(request, method, error)\n }\n }\n }\n\n private buildSubscriptionHandler<Method extends Subscription, Credentials>(\n method: Method,\n methodHandler: LexRouterSubscriptionHandler<Method, Credentials>,\n auth?: LexRouterAuth<Method, Credentials>,\n ): Handler {\n const {\n onHandlerError,\n upgradeWebSocket = (globalThis as any).Deno?.upgradeWebSocket as\n | UpgradeWebSocket\n | undefined,\n } = this.options\n if (!upgradeWebSocket) {\n throw new TypeError(\n 'WebSocket upgrade not supported in this environment. Please provide an upgradeWebSocket option when creating the LexRouter.',\n )\n }\n\n return async (\n request: Request,\n connection?: ConnectionInfo,\n ): Promise<Response> => {\n if (request.method !== 'GET') {\n return Response.json(\n { error: 'InvalidRequest', message: 'Method not allowed' },\n { status: 405 },\n )\n }\n\n if (\n request.headers.get('connection')?.toLowerCase() !== 'upgrade' ||\n request.headers.get('upgrade')?.toLowerCase() !== 'websocket'\n ) {\n return Response.json(\n {\n error: 'InvalidRequest',\n message: 'XRPC subscriptions are only available over WebSocket',\n },\n {\n status: 426,\n headers: {\n Connection: 'Upgrade',\n Upgrade: 'websocket',\n },\n },\n )\n }\n\n try {\n const { response, socket } = upgradeWebSocket(request)\n\n socket.addEventListener('message', () => {\n const error = new LexError(\n 'InvalidRequest',\n 'XRPC subscriptions do not accept messages',\n )\n socket.send(encodeErrorFrame(error))\n socket.close(1008, error.error)\n })\n\n socket.addEventListener('open', async () => {\n try {\n const url = new URL(request.url)\n const params = method.parameters.fromURLSearchParams(\n url.searchParams,\n )\n\n const credentials: Credentials = auth\n ? await auth({ params, request, connection })\n : (undefined as Credentials)\n\n request.signal.throwIfAborted()\n\n const iterable = methodHandler({\n credentials,\n params,\n input: undefined as InferMethodInput<Method, Body>,\n request,\n connection,\n })\n\n const iterator = iterable[Symbol.asyncIterator]()\n\n if (iterator.return) {\n const abort = async () => {\n socket.removeEventListener('error', abort)\n socket.removeEventListener('close', abort)\n try {\n await iterator.return!()\n } catch {\n // Ignore\n }\n }\n socket.addEventListener('error', abort)\n socket.addEventListener('close', abort)\n }\n\n while (socket.readyState === 1) {\n const result = await iterator.next()\n if (result.done) break\n\n // Should not be needed (socket would emit \"close\" event)\n request.signal.throwIfAborted()\n\n // @TODO add validation of output based on method.output.schema?\n\n const data = encodeMessageFrame(method, result.value)\n\n socket.send(data)\n\n // Apply backpressure by waiting for the buffered data to drain\n // before generating the next message\n await drainWebsocket(socket, request.signal, this.options)\n }\n\n socket.close(1000)\n } catch (error) {\n // If the socket is still open, send an error frame before closing\n if (socket.readyState === 1) {\n const lexError =\n error instanceof LexError\n ? error\n : new LexError('InternalError', 'An internal error occurred')\n\n socket.send(encodeErrorFrame(lexError))\n\n socket.close(\n // https://www.rfc-editor.org/rfc/rfc6455#section-7.4.1\n error instanceof LexError ? 1008 : 1011,\n lexError.error,\n )\n }\n\n // Only report unexpected processing errors\n if (onHandlerError && !isAbortReason(request.signal, error)) {\n await onHandlerError({ error, request, method })\n }\n }\n })\n\n return response\n } catch (error) {\n return this.handleError(request, method, error)\n }\n }\n }\n\n private async handleError(\n request: Request,\n method: LexMethod,\n error: unknown,\n ) {\n // Only report unexpected processing errors\n const { onHandlerError } = this.options\n if (onHandlerError && !isAbortReason(request.signal, error)) {\n await onHandlerError({ error, request, method })\n }\n\n if (error instanceof LexError) {\n return error.toResponse()\n }\n\n return Response.json(\n { error: 'InternalError', message: 'An internal error occurred' },\n { status: 500 },\n )\n }\n\n handle: Handler = async (\n request: Request,\n connection?: ConnectionInfo,\n ): Promise<Response> => {\n const nsid = extractMethodNsid(request)\n\n const handler = (this.handlers as Map<string | null, Handler>).get(nsid)\n if (handler) return handler(request, connection)\n\n if (!nsid || !isNsidString(nsid)) {\n return Response.json(\n {\n error: 'InvalidRequest',\n message: 'Invalid XRPC method path',\n },\n { status: 404 },\n )\n }\n\n return Response.json(\n {\n error: 'MethodNotImplemented',\n message: `XRPC method \"${nsid}\" not implemented on this server`,\n },\n { status: 501 },\n )\n }\n}\n\nfunction extractMethodNsid(request: Request): string | null {\n const { pathname } = new URL(request.url)\n if (!pathname.startsWith('/xrpc/')) return null\n if (pathname.includes('/', 6)) return null\n // We don't really need to validate the NSID here, the existence of the route\n // (which is looked up based on an NSID) is sufficient.\n return pathname.slice(6)\n}\n\nasync function getProcedureInput<M extends Procedure>(\n this: M,\n request: Request,\n): Promise<InferMethodInput<M, Body>> {\n const encodingRaw = request.headers\n .get('content-type')\n ?.split(';')[0]\n .trim()\n .toLowerCase()\n\n const encoding =\n encodingRaw ||\n // If the caller did not provide a content-type, but the method\n // expects an input, assume binary\n (request.body != null && this.input.encoding != null\n ? 'application/octet-stream'\n : undefined)\n\n if (!this.input.matchesEncoding(encoding)) {\n throw new LexError('InvalidRequest', `Invalid content-type: ${encoding}`)\n }\n\n if (this.input.encoding === 'application/json') {\n // @TODO limit size?\n const body = this.input.schema\n ? this.input.schema.parse(lexParse(await request.text()))\n : lexParse(await request.text())\n return { encoding, body } as InferMethodInput<M, Body>\n } else if (this.input.encoding) {\n const body: Body = request\n return { encoding, body } as InferMethodInput<M, Body>\n } else {\n return undefined as InferMethodInput<M, Body>\n }\n}\n\nasync function getQueryInput<M extends Query>(\n this: M,\n request: Request,\n): Promise<InferMethodInput<M, Body>> {\n if (\n request.body ||\n request.headers.has('content-type') ||\n request.headers.has('content-length')\n ) {\n throw new LexError('InvalidRequest', 'GET requests must not have a body')\n }\n\n return undefined as InferMethodInput<M, Body>\n}\n\n// Pre-encoded frame header for error frames\nconst ERROR_FRAME_HEADER = /*#__PURE__*/ encode({ op: -1 })\n\nfunction encodeErrorFrame(error: LexError): Uint8Array {\n return ui8Concat([ERROR_FRAME_HEADER, encode(error.toJSON())])\n}\n\n// Pre-encoded frame header for message frames with unknown type\nconst UNKNOWN_MESSAGE_FRAME_HEADER = /*#__PURE__*/ encode({ op: 1 })\n\nfunction encodeMessageFrame(method: Subscription, value: LexValue): Uint8Array {\n if (isPlainObject(value) && typeof value.$type === 'string') {\n const { $type, ...rest } = value\n return ui8Concat([\n encode({\n op: 1,\n t:\n // If $type starts with `nsid#`, strip the NSID prefix\n $type.charCodeAt(0) !== 0x23 && // '#'\n $type.charCodeAt(method.nsid.length) === 0x23 && // '#'\n $type.startsWith(method.nsid)\n ? $type.slice(method.nsid.length)\n : $type,\n }),\n encode(rest),\n ])\n }\n\n return ui8Concat([UNKNOWN_MESSAGE_FRAME_HEADER, encode(value)])\n}\n\nfunction isAbortReason(signal: AbortSignal, error: unknown): boolean {\n if (!signal.aborted || signal.reason == null) return false\n return (\n error === signal.reason ||\n (error instanceof Error && error.cause === signal.reason)\n )\n}\n"]}
|
|
1
|
+
{"version":3,"file":"lex-server.js","sourceRoot":"","sources":["../src/lex-server.ts"],"names":[],"mappings":"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","sourcesContent":["import { encode } from '@atproto/lex-cbor'\nimport { LexError, LexValue, isPlainObject, ui8Concat } from '@atproto/lex-data'\nimport { lexParse, lexToJson } from '@atproto/lex-json'\nimport {\n InferMethodInput,\n InferMethodMessage,\n InferMethodOutput,\n InferMethodOutputBody,\n InferMethodOutputEncoding,\n InferMethodParams,\n Main,\n NsidString,\n Procedure,\n Query,\n Subscription,\n getMain,\n isNsidString,\n} from '@atproto/lex-schema'\nimport { drainWebsocket } from './lib/drain-websocket.js'\n\ntype Awaitable<T> = T | Promise<T>\nexport type LexMethod = Query | Procedure | Subscription\n\nexport type NetAddr = {\n hostname: string\n port: number\n transport: 'tcp' | 'udp'\n}\n\nexport type UnixAddr = {\n path: string\n transport: 'unix' | 'unixpacket'\n}\n\nexport type Addr = NetAddr | UnixAddr | undefined\n\nexport type ConnectionInfo<A extends Addr = Addr> = {\n remoteAddr: A\n completed: Promise<void>\n}\n\ntype Handler = (\n request: Request,\n connection?: ConnectionInfo,\n) => Promise<Response>\n\nexport type LexRouterHandlerContext<Method extends LexMethod, Credentials> = {\n credentials: Credentials\n input: InferMethodInput<Method, Body>\n params: InferMethodParams<Method>\n request: Request\n signal: AbortSignal\n connection?: ConnectionInfo\n}\n\ntype AsOptionalPayloadOptions<T> = T extends undefined | void\n ? { encoding?: undefined; body?: undefined }\n : T\n\nexport type LexRouterHandlerOutput<Method extends Query | Procedure> =\n | Response\n | ({\n headers?: HeadersInit\n } & (InferMethodOutputEncoding<Method> extends 'application/json'\n ? {\n // Allow omitting body when output is JSON\n encoding?: 'application/json'\n body: InferMethodOutputBody<Method>\n }\n : AsOptionalPayloadOptions<InferMethodOutput<Method, BodyInit>>))\n\nexport type LexRouterMethodHandler<\n Method extends Query | Procedure = Query | Procedure,\n Credentials = unknown,\n> = (\n ctx: LexRouterHandlerContext<Method, Credentials>,\n) => Awaitable<LexRouterHandlerOutput<Method>>\n\nexport type LexRouterMethodConfig<\n Method extends Query | Procedure = Query | Procedure,\n Credentials = unknown,\n> = {\n handler: LexRouterMethodHandler<Method, Credentials>\n auth: LexRouterAuth<Credentials, Method>\n}\n\nexport type LexRouterSubscriptionHandler<\n Method extends Subscription = Subscription,\n Credentials = unknown,\n> = (\n ctx: LexRouterHandlerContext<Method, Credentials>,\n) => AsyncIterable<InferMethodMessage<Method>>\n\nexport type LexRouterSubscriptionConfig<\n Method extends Subscription = Subscription,\n Credentials = unknown,\n> = {\n handler: LexRouterSubscriptionHandler<Method, Credentials>\n auth: LexRouterAuth<Credentials, Method>\n}\n\nexport type LexRouterAuthContext<Method extends LexMethod = LexMethod> = {\n method: Method\n params: InferMethodParams<Method>\n request: Request\n connection?: ConnectionInfo\n}\n\nexport type LexRouterAuth<\n Credentials = unknown,\n Method extends LexMethod = LexMethod,\n> = (ctx: LexRouterAuthContext<Method>) => Credentials | Promise<Credentials>\n\nexport type LexErrorHandlerContext = {\n error: unknown\n request: Request\n method: LexMethod\n}\n\nexport type UpgradeWebSocket = (request: Request) => {\n socket: WebSocket\n response: Response\n}\n\nexport type LexRouterOptions = {\n upgradeWebSocket?: UpgradeWebSocket\n onHandlerError?: (ctx: LexErrorHandlerContext) => void | Promise<void>\n highWaterMark?: number\n lowWaterMark?: number\n}\n\nexport class LexRouter {\n private handlers: Map<NsidString, Handler> = new Map()\n\n constructor(readonly options: LexRouterOptions = {}) {}\n\n add<M extends Subscription>(\n ns: Main<M>,\n handler: LexRouterSubscriptionHandler<M, void>,\n ): this\n add<M extends Subscription, Credentials>(\n ns: Main<M>,\n config: LexRouterSubscriptionConfig<M, Credentials>,\n ): this\n add<M extends Query | Procedure>(\n ns: Main<M>,\n handler: LexRouterMethodHandler<M, void>,\n ): this\n add<M extends Query | Procedure, Credentials>(\n ns: Main<M>,\n config: LexRouterMethodConfig<M, Credentials>,\n ): this\n add<M extends LexMethod>(\n ns: Main<M>,\n config:\n | LexRouterSubscriptionHandler<any, any>\n | LexRouterSubscriptionConfig<any, any>\n | LexRouterMethodHandler<any, any>\n | LexRouterMethodConfig<any, any>,\n ) {\n const method = getMain(ns)\n if (this.handlers.has(method.nsid)) {\n throw new TypeError(`Method ${method.nsid} already registered`)\n }\n const methodConfig =\n typeof config === 'function'\n ? { handler: config, auth: undefined }\n : config\n\n const handler: Handler =\n method.type === 'subscription'\n ? this.buildSubscriptionHandler(\n method,\n methodConfig.handler as LexRouterSubscriptionHandler<any, any>,\n methodConfig.auth,\n )\n : this.buildMethodHandler(\n method,\n methodConfig.handler as LexRouterMethodHandler<any, any>,\n methodConfig.auth,\n )\n\n this.handlers.set(method.nsid, handler)\n\n return this\n }\n\n private buildMethodHandler<Method extends Query | Procedure, Credentials>(\n method: Method,\n methodHandler: LexRouterMethodHandler<Method, Credentials>,\n auth?: LexRouterAuth<Credentials, Method>,\n ): Handler {\n const getInput = (\n method.type === 'procedure'\n ? getProcedureInput.bind(method)\n : getQueryInput.bind(method)\n ) as (request: Request) => Promise<InferMethodInput<Method, Body>>\n\n return async (request, connection) => {\n // @NOTE CORS requests should be handled by a middleware before reaching\n // this point.\n if (\n (method.type === 'procedure' && request.method !== 'POST') ||\n (method.type === 'query' &&\n request.method !== 'GET' &&\n request.method !== 'HEAD')\n ) {\n return Response.json(\n { error: 'InvalidRequest', message: 'Method not allowed' },\n { status: 405 },\n )\n }\n\n try {\n const url = new URL(request.url)\n const params = method.parameters.fromURLSearchParams(url.searchParams)\n\n const credentials = auth\n ? await auth({ method, params, request, connection })\n : (undefined as Credentials)\n\n const input = await getInput(request)\n\n const output = await methodHandler({\n credentials,\n params,\n input,\n request,\n connection,\n signal: request.signal,\n })\n\n if (output instanceof Response) {\n return output\n }\n\n // @TODO add validation of output based on method.output.schema?\n\n if (output.body === undefined && output.encoding === undefined) {\n return new Response(null, { status: 200, headers: output.headers })\n }\n\n if (method.output?.encoding === 'application/json') {\n return Response.json(lexToJson(output.body as LexValue), {\n status: 200,\n headers: output.headers,\n })\n }\n\n const headers = new Headers(output.headers)\n headers.set('content-type', output.encoding!)\n return new Response(output.body, { status: 200, headers })\n } catch (error) {\n return this.handleError(request, method, error)\n }\n }\n }\n\n private buildSubscriptionHandler<Method extends Subscription, Credentials>(\n method: Method,\n methodHandler: LexRouterSubscriptionHandler<Method, Credentials>,\n auth?: LexRouterAuth<Credentials, Method>,\n ): Handler {\n const {\n onHandlerError,\n upgradeWebSocket = (globalThis as any).Deno?.upgradeWebSocket as\n | UpgradeWebSocket\n | undefined,\n } = this.options\n if (!upgradeWebSocket) {\n throw new TypeError(\n 'WebSocket upgrade not supported in this environment. Please provide an upgradeWebSocket option when creating the LexRouter.',\n )\n }\n\n return async (request, connection) => {\n if (request.method !== 'GET') {\n return Response.json(\n { error: 'InvalidRequest', message: 'Method not allowed' },\n { status: 405 },\n )\n }\n\n if (\n request.headers.get('connection')?.toLowerCase() !== 'upgrade' ||\n request.headers.get('upgrade')?.toLowerCase() !== 'websocket'\n ) {\n return Response.json(\n {\n error: 'InvalidRequest',\n message: 'XRPC subscriptions are only available over WebSocket',\n },\n {\n status: 426,\n headers: {\n Connection: 'Upgrade',\n Upgrade: 'websocket',\n },\n },\n )\n }\n\n if (request.signal.aborted) {\n return Response.json(\n { error: 'RequestAborted', message: 'The request was aborted' },\n { status: 499 },\n )\n }\n\n try {\n const { response, socket } = upgradeWebSocket(request)\n\n // @NOTE We are using a distinct signal than request.signal because that\n // signal may get aborted before the WebSocket is closed (this is the\n // case with Deno).\n const abortController = new AbortController()\n const { signal } = abortController\n const abort = () => abortController.abort()\n\n const onMessage = (event: unknown) => {\n const error = new LexError(\n 'InvalidRequest',\n 'XRPC subscriptions do not accept messages',\n { cause: event },\n )\n socket.send(encodeErrorFrame(error))\n socket.close(1008, error.error)\n }\n\n const onOpen = async () => {\n try {\n const url = new URL(request.url)\n const params = method.parameters.fromURLSearchParams(\n url.searchParams,\n )\n\n const credentials: Credentials = auth\n ? await auth({ method, params, request, connection })\n : (undefined as Credentials)\n\n signal.throwIfAborted()\n\n const iterable = methodHandler({\n credentials,\n params,\n input: undefined as InferMethodInput<Method, Body>,\n request,\n connection,\n signal,\n })\n\n const iterator = iterable[Symbol.asyncIterator]()\n\n signal.addEventListener('abort', async () => {\n // @NOTE will cause the process to crash if this throws\n await iterator.return?.()\n })\n\n while (!signal.aborted && socket.readyState === 1) {\n const result = await iterator.next()\n if (result.done) break\n\n // @TODO add validation of output based on method.output.schema?\n\n const data = encodeMessageFrame(method, result.value)\n\n socket.send(data)\n\n // Apply backpressure by waiting for the buffered data to drain\n // before generating the next message\n await drainWebsocket(socket, signal, this.options)\n }\n\n if (socket.readyState === 1) {\n socket.close(1000)\n }\n } catch (error) {\n // If the socket is still open, send an error frame before closing\n if (socket.readyState === 1) {\n const lexError =\n error instanceof LexError\n ? error\n : new LexError('InternalError', 'An internal error occurred')\n\n socket.send(encodeErrorFrame(lexError))\n\n socket.close(\n // https://www.rfc-editor.org/rfc/rfc6455#section-7.4.1\n error instanceof LexError ? 1008 : 1011,\n lexError.error,\n )\n }\n\n // Only report unexpected processing errors\n if (onHandlerError && !isAbortReason(request.signal, error)) {\n await onHandlerError({ error, request, method })\n }\n } finally {\n abortController.abort()\n }\n }\n\n socket.addEventListener('error', abort)\n socket.addEventListener('close', abort)\n socket.addEventListener('open', onOpen)\n socket.addEventListener('message', onMessage)\n\n return response\n } catch (error) {\n return this.handleError(request, method, error)\n }\n }\n }\n\n private async handleError(\n request: Request,\n method: LexMethod,\n error: unknown,\n ) {\n // Only report unexpected processing errors\n const { onHandlerError } = this.options\n if (onHandlerError && !isAbortReason(request.signal, error)) {\n await onHandlerError({ error, request, method })\n }\n\n if (error instanceof LexError) {\n return error.toResponse()\n }\n\n return Response.json(\n { error: 'InternalError', message: 'An internal error occurred' },\n { status: 500 },\n )\n }\n\n handle: Handler = async (\n request: Request,\n connection?: ConnectionInfo,\n ): Promise<Response> => {\n const nsid = extractMethodNsid(request)\n\n const handler = (this.handlers as Map<string | null, Handler>).get(nsid)\n if (handler) return handler(request, connection)\n\n if (!nsid || !isNsidString(nsid)) {\n return Response.json(\n {\n error: 'InvalidRequest',\n message: 'Invalid XRPC method path',\n },\n { status: 404 },\n )\n }\n\n return Response.json(\n {\n error: 'MethodNotImplemented',\n message: `XRPC method \"${nsid}\" not implemented on this server`,\n },\n { status: 501 },\n )\n }\n}\n\nfunction extractMethodNsid(request: Request): string | null {\n const { pathname } = new URL(request.url)\n if (!pathname.startsWith('/xrpc/')) return null\n if (pathname.includes('/', 6)) return null\n // We don't really need to validate the NSID here, the existence of the route\n // (which is looked up based on an NSID) is sufficient.\n return pathname.slice(6)\n}\n\nasync function getProcedureInput<M extends Procedure>(\n this: M,\n request: Request,\n): Promise<InferMethodInput<M, Body>> {\n const encodingRaw = request.headers\n .get('content-type')\n ?.split(';')[0]\n .trim()\n .toLowerCase()\n\n const encoding =\n encodingRaw ||\n // If the caller did not provide a content-type, but the method\n // expects an input, assume binary\n (request.body != null && this.input.encoding != null\n ? 'application/octet-stream'\n : undefined)\n\n if (!this.input.matchesEncoding(encoding)) {\n throw new LexError('InvalidRequest', `Invalid content-type: ${encoding}`)\n }\n\n if (this.input.encoding === 'application/json') {\n // @TODO limit size?\n const body = this.input.schema\n ? this.input.schema.parse(lexParse(await request.text()))\n : lexParse(await request.text())\n return { encoding, body } as InferMethodInput<M, Body>\n } else if (this.input.encoding) {\n const body: Body = request\n return { encoding, body } as InferMethodInput<M, Body>\n } else {\n return undefined as InferMethodInput<M, Body>\n }\n}\n\nasync function getQueryInput<M extends Query>(\n this: M,\n request: Request,\n): Promise<InferMethodInput<M, Body>> {\n if (\n request.body ||\n request.headers.has('content-type') ||\n request.headers.has('content-length')\n ) {\n throw new LexError('InvalidRequest', 'GET requests must not have a body')\n }\n\n return undefined as InferMethodInput<M, Body>\n}\n\n// Pre-encoded frame header for error frames\nconst ERROR_FRAME_HEADER = /*#__PURE__*/ encode({ op: -1 })\n\nfunction encodeErrorFrame(error: LexError): Uint8Array {\n return ui8Concat([ERROR_FRAME_HEADER, encode(error.toJSON())])\n}\n\n// Pre-encoded frame header for message frames with unknown type\nconst UNKNOWN_MESSAGE_FRAME_HEADER = /*#__PURE__*/ encode({ op: 1 })\n\nfunction encodeMessageFrame(method: Subscription, value: LexValue): Uint8Array {\n if (isPlainObject(value) && typeof value.$type === 'string') {\n const { $type, ...rest } = value\n return ui8Concat([\n encode({\n op: 1,\n t:\n // If $type starts with `nsid#`, strip the NSID prefix\n $type.charCodeAt(0) !== 0x23 && // '#'\n $type.charCodeAt(method.nsid.length) === 0x23 && // '#'\n $type.startsWith(method.nsid)\n ? $type.slice(method.nsid.length)\n : $type,\n }),\n encode(rest),\n ])\n }\n\n return ui8Concat([UNKNOWN_MESSAGE_FRAME_HEADER, encode(value)])\n}\n\nfunction isAbortReason(signal: AbortSignal, error: unknown): boolean {\n if (!signal.aborted || signal.reason == null) return false\n return (\n error === signal.reason ||\n (error instanceof Error && error.cause === signal.reason)\n )\n}\n"]}
|
package/dist/nodejs.d.ts
CHANGED
|
@@ -5,13 +5,13 @@ export declare function upgradeWebSocket(request: Request): {
|
|
|
5
5
|
socket: WebSocket;
|
|
6
6
|
};
|
|
7
7
|
export type NetAddr = {
|
|
8
|
+
transport: 'tcp';
|
|
8
9
|
hostname: string;
|
|
9
10
|
port: number;
|
|
10
|
-
transport: 'tcp';
|
|
11
11
|
};
|
|
12
12
|
export type NodeConnectionInfo = {
|
|
13
|
-
|
|
14
|
-
remoteAddr
|
|
13
|
+
completed: Promise<void>;
|
|
14
|
+
remoteAddr: NetAddr | undefined;
|
|
15
15
|
};
|
|
16
16
|
export interface HandlerFunction {
|
|
17
17
|
(req: Request, info: NodeConnectionInfo): Response | Promise<Response>;
|
package/dist/nodejs.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nodejs.d.ts","sourceRoot":"","sources":["../src/nodejs.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,eAAe,EAEf,MAAM,IAAI,UAAU,EACpB,aAAa,EACb,cAAc,EAEf,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAmBxC,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG;IAClD,QAAQ,EAAE,QAAQ,CAAA;IAClB,MAAM,EAAE,SAAS,CAAA;CAClB,CAkCA;
|
|
1
|
+
{"version":3,"file":"nodejs.d.ts","sourceRoot":"","sources":["../src/nodejs.ts"],"names":[],"mappings":"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"}
|
package/dist/nodejs.js
CHANGED
|
@@ -48,6 +48,7 @@ function upgradeWebSocket(request) {
|
|
|
48
48
|
});
|
|
49
49
|
return { response, socket };
|
|
50
50
|
}
|
|
51
|
+
const kUpgradeEvent = Symbol.for('@atproto/lex-server:upgrade');
|
|
51
52
|
function handleWebSocketUpgrade(req, response) {
|
|
52
53
|
const ws = response[kResponseWs];
|
|
53
54
|
if (!ws)
|
|
@@ -75,6 +76,7 @@ function handleWebSocketUpgrade(req, response) {
|
|
|
75
76
|
// @TODO find a way to properly "close" the _socket when the server is
|
|
76
77
|
// shutting down (might require replacing http-terminator with a local
|
|
77
78
|
// implementation)
|
|
79
|
+
req.emit(kUpgradeEvent, ws);
|
|
78
80
|
});
|
|
79
81
|
}
|
|
80
82
|
async function sendResponse(req, res, response) {
|
|
@@ -106,18 +108,9 @@ function toRequest(req) {
|
|
|
106
108
|
const url = new URL(req.url ?? '/', `${protocol}://${host}`);
|
|
107
109
|
const headers = toHeaders(req.headers);
|
|
108
110
|
const body = toBody(req);
|
|
109
|
-
const
|
|
110
|
-
const abort = (err) => abortController.abort(err);
|
|
111
|
-
req.on('close', abort);
|
|
112
|
-
req.on('error', abort);
|
|
113
|
-
req.on('end', abort);
|
|
114
|
-
abortController.signal.addEventListener('abort', () => {
|
|
115
|
-
req.off('close', abort);
|
|
116
|
-
req.off('error', abort);
|
|
117
|
-
req.off('end', abort);
|
|
118
|
-
}, { once: true });
|
|
111
|
+
const signal = requestSignal(req);
|
|
119
112
|
return new Request(url, {
|
|
120
|
-
signal
|
|
113
|
+
signal,
|
|
121
114
|
method: req.method,
|
|
122
115
|
headers,
|
|
123
116
|
body,
|
|
@@ -127,6 +120,49 @@ function toRequest(req) {
|
|
|
127
120
|
duplex: body ? 'half' : undefined,
|
|
128
121
|
});
|
|
129
122
|
}
|
|
123
|
+
function requestSignal(req) {
|
|
124
|
+
if (req.destroyed)
|
|
125
|
+
return AbortSignal.abort();
|
|
126
|
+
const abortController = new AbortController();
|
|
127
|
+
const abort = (err) => {
|
|
128
|
+
abortController.abort(err instanceof Error ? err : undefined);
|
|
129
|
+
req.off('close', abort);
|
|
130
|
+
req.off('error', abort);
|
|
131
|
+
req.off('end', abort);
|
|
132
|
+
req.off(kUpgradeEvent, abort);
|
|
133
|
+
};
|
|
134
|
+
req.on('close', abort);
|
|
135
|
+
req.on('error', abort);
|
|
136
|
+
req.on('end', abort);
|
|
137
|
+
req.on(kUpgradeEvent, abort);
|
|
138
|
+
return abortController.signal;
|
|
139
|
+
}
|
|
140
|
+
function requestCompletion(req) {
|
|
141
|
+
if (req.destroyed)
|
|
142
|
+
return Promise.resolve();
|
|
143
|
+
// Unlike the abort signal, we complete the promise only when the request
|
|
144
|
+
// is fully done, accounting for websocket upgrade.
|
|
145
|
+
return new Promise((resolve) => {
|
|
146
|
+
const cleanup = () => {
|
|
147
|
+
req.off('close', done);
|
|
148
|
+
req.off('error', done);
|
|
149
|
+
req.off('end', done);
|
|
150
|
+
req.off(kUpgradeEvent, onUpgrade);
|
|
151
|
+
};
|
|
152
|
+
const onUpgrade = (ws) => {
|
|
153
|
+
cleanup();
|
|
154
|
+
ws.addEventListener('close', () => resolve());
|
|
155
|
+
};
|
|
156
|
+
const done = () => {
|
|
157
|
+
resolve();
|
|
158
|
+
cleanup();
|
|
159
|
+
};
|
|
160
|
+
req.on('close', done);
|
|
161
|
+
req.on('error', done);
|
|
162
|
+
req.on('end', done);
|
|
163
|
+
req.on(kUpgradeEvent, onUpgrade);
|
|
164
|
+
});
|
|
165
|
+
}
|
|
130
166
|
function toHeaders(headers) {
|
|
131
167
|
const result = new Headers();
|
|
132
168
|
for (const [key, value] of Object.entries(headers)) {
|
|
@@ -164,18 +200,12 @@ async function handleRequest(req, res, handlerFn) {
|
|
|
164
200
|
function toConnectionInfo(req) {
|
|
165
201
|
const { socket } = req;
|
|
166
202
|
return {
|
|
167
|
-
|
|
168
|
-
? {
|
|
169
|
-
hostname: socket.localAddress,
|
|
170
|
-
port: socket.localPort,
|
|
171
|
-
transport: 'tcp',
|
|
172
|
-
}
|
|
173
|
-
: undefined,
|
|
203
|
+
completed: requestCompletion(req),
|
|
174
204
|
remoteAddr: socket.remoteAddress != null
|
|
175
205
|
? {
|
|
206
|
+
transport: 'tcp',
|
|
176
207
|
hostname: socket.remoteAddress,
|
|
177
208
|
port: socket.remotePort,
|
|
178
|
-
transport: 'tcp',
|
|
179
209
|
}
|
|
180
210
|
: undefined,
|
|
181
211
|
};
|
package/dist/nodejs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nodejs.js","sourceRoot":"","sources":["../src/nodejs.ts"],"names":[],"mappings":"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","sourcesContent":["import { once } from 'node:events'\nimport {\n IncomingHttpHeaders,\n IncomingMessage,\n RequestListener,\n Server as HttpServer,\n ServerOptions,\n ServerResponse,\n createServer as createHttpServer,\n} from 'node:http'\nimport { ListenOptions } from 'node:net'\nimport { Readable } from 'node:stream'\nimport { pipeline } from 'node:stream/promises'\nimport { createHttpTerminator } from 'http-terminator'\nimport { WebSocket as WebSocketPonyfill, WebSocketServer } from 'ws'\n\n// @ts-expect-error\nSymbol.asyncDispose ??= Symbol.for('Symbol.asyncDispose')\n\nconst kResponseWs = Symbol.for('@atproto/lex-server:WebSocket')\n\nfunction isUpgradeRequest(request: Request, upgrade: string): boolean {\n return (\n request.method === 'GET' &&\n request.headers.get('connection')?.toLowerCase() === 'upgrade' &&\n request.headers.get('upgrade')?.toLowerCase() === upgrade\n )\n}\n\nexport function upgradeWebSocket(request: Request): {\n response: Response\n socket: WebSocket\n} {\n if (!isUpgradeRequest(request, 'websocket')) {\n throw new TypeError('upgradeWebSocket() expects a WebSocket upgrade')\n }\n\n // Placeholder response for WebSocket upgrade. The actual handling will happen\n // through the handleWebSocketUpgrade function. Headers set on the response\n // will be applied during the upgrade.\n const response = new Response(null, { status: 200 })\n\n // The Response constructor does not allow setting status 101, so we\n // define it directly. The purpose of this response is just to signal\n // that an upgrade is needed, and to carry any headers.\n Object.defineProperty(response, 'status', {\n value: 101,\n enumerable: false,\n configurable: false,\n writable: false,\n })\n\n // @ts-expect-error\n const socket: WebSocket = new WebSocketPonyfill(null, undefined, {\n autoPong: true,\n })\n\n // Attach the WebSocket to the response for later retrieval\n Object.defineProperty(response, kResponseWs, {\n value: socket,\n enumerable: false,\n configurable: false,\n writable: false,\n })\n\n return { response, socket }\n}\n\nfunction handleWebSocketUpgrade(\n req: IncomingMessage,\n response: Response,\n): void {\n const ws = (response as { [kResponseWs]?: WebSocketPonyfill })[kResponseWs]\n if (!ws) throw new TypeError('Response not created by upgradeWebSocket()')\n\n // Create a one time use WebSocketServer to handle the upgrade\n const wss = new WebSocketServer({\n autoPong: true,\n noServer: true,\n clientTracking: false,\n perMessageDeflate: true,\n // @ts-expect-error\n WebSocket: function () {\n // Return the websocket that was created earlier instead of a new instance\n return ws\n },\n })\n\n // Apply headers that might have been set on the response object during\n // handling. This will be called during wss.handleUpgrade().\n wss.on('headers', (headers) => {\n for (const [name, value] of response.headers) {\n headers.push(`${name}: ${value}`)\n }\n })\n\n wss.handleUpgrade(req, req.socket, Buffer.alloc(0), (_socket) => {\n // @TODO find a way to properly \"close\" the _socket when the server is\n // shutting down (might require replacing http-terminator with a local\n // implementation)\n })\n}\n\nasync function sendResponse(\n req: IncomingMessage,\n res: ServerResponse,\n response: Response,\n): Promise<void> {\n // Invalid usage\n if (res.headersSent) {\n throw new TypeError('Response has already been sent')\n }\n\n if (response.status === 101) {\n return handleWebSocketUpgrade(req, response)\n }\n\n res.statusCode = response.status\n res.statusMessage = response.statusText\n\n for (const [key, value] of response.headers) {\n res.appendHeader(key, value)\n }\n\n if (response.body != null && req.method !== 'HEAD') {\n const stream = Readable.fromWeb(response.body as any)\n await pipeline(stream, res)\n } else {\n await response.body?.cancel()\n res.end()\n }\n}\n\nfunction toRequest(req: IncomingMessage): Request {\n const host = req.headers.host ?? req.socket?.localAddress ?? 'localhost'\n const isEncrypted = (req.socket as any).encrypted === true\n const protocol = isEncrypted ? 'https' : 'http'\n const url = new URL(req.url ?? '/', `${protocol}://${host}`)\n const headers = toHeaders(req.headers)\n const body = toBody(req)\n\n const abortController = new AbortController()\n const abort = (err?: Error) => abortController.abort(err)\n\n req.on('close', abort)\n req.on('error', abort)\n req.on('end', abort)\n\n abortController.signal.addEventListener(\n 'abort',\n () => {\n req.off('close', abort)\n req.off('error', abort)\n req.off('end', abort)\n },\n { once: true },\n )\n\n return new Request(url, {\n signal: abortController.signal,\n method: req.method,\n headers,\n body,\n referrer: headers.get('referrer') ?? headers.get('referer') ?? undefined,\n redirect: 'manual',\n // @ts-expect-error\n duplex: body ? 'half' : undefined,\n })\n}\n\nfunction toHeaders(headers: IncomingHttpHeaders): Headers {\n const result = new Headers()\n for (const [key, value] of Object.entries(headers)) {\n if (value === undefined) continue\n if (Array.isArray(value)) {\n for (const v of value) result.append(key, v)\n } else {\n result.set(key, value)\n }\n }\n return result\n}\n\nfunction toBody(req: IncomingMessage): null | ReadableStream<Uint8Array> {\n if (\n req.method === 'GET' ||\n req.method === 'HEAD' ||\n req.method === 'OPTIONS'\n ) {\n return null\n }\n\n if (\n req.headers['content-type'] == null &&\n req.headers['transfer-encoding'] == null &&\n req.headers['content-length'] == null\n ) {\n return null\n }\n\n return Readable.toWeb(req) as ReadableStream<Uint8Array>\n}\n\nexport type NetAddr = {\n hostname: string\n port: number\n transport: 'tcp'\n}\n\nexport type NodeConnectionInfo = {\n localAddr?: NetAddr\n remoteAddr?: NetAddr\n}\n\nexport interface HandlerFunction {\n (req: Request, info: NodeConnectionInfo): Response | Promise<Response>\n}\n\nexport interface HandlerObject {\n handle: HandlerFunction\n}\n\nasync function handleRequest(\n req: IncomingMessage,\n res: ServerResponse,\n handlerFn: HandlerFunction,\n) {\n const request = toRequest(req)\n const info = toConnectionInfo(req)\n const response = await handlerFn(request, info)\n await sendResponse(req, res, response)\n}\n\nfunction toConnectionInfo(req: IncomingMessage): NodeConnectionInfo {\n const { socket } = req\n return {\n localAddr:\n socket.localAddress != null\n ? {\n hostname: socket.localAddress,\n port: socket.localPort!,\n transport: 'tcp',\n }\n : undefined,\n remoteAddr:\n socket.remoteAddress != null\n ? {\n hostname: socket.remoteAddress,\n port: socket.remotePort!,\n transport: 'tcp',\n }\n : undefined,\n }\n}\n\nexport function toRequestListener<\n Request extends typeof IncomingMessage = typeof IncomingMessage,\n Response extends typeof ServerResponse<\n InstanceType<Request>\n > = typeof ServerResponse,\n>(handlerFn: HandlerFunction) {\n return ((\n req: InstanceType<Request>,\n res: InstanceType<Response> & { req: InstanceType<Request> },\n next?: (err?: unknown) => void,\n ): void => {\n handleRequest(req, res, handlerFn).catch((err) => {\n if (next) next(err)\n else {\n if (!res.headersSent) {\n res.statusCode = 500\n res.setHeader('content-type', 'text/plain; charset=utf-8')\n res.end('Internal Server Error')\n } else if (!res.writableEnded) {\n res.destroy()\n }\n }\n })\n }) satisfies RequestListener<Request, Response>\n}\n\nexport type CreateServerOptions<\n Request extends typeof IncomingMessage = typeof IncomingMessage,\n Response extends typeof ServerResponse<\n InstanceType<Request>\n > = typeof ServerResponse,\n> = ServerOptions<Request, Response> & {\n gracefulTerminationTimeout?: number\n}\n\nexport interface Server<\n Request extends typeof IncomingMessage = typeof IncomingMessage,\n Response extends typeof ServerResponse<\n InstanceType<Request>\n > = typeof ServerResponse,\n> extends HttpServer<Request, Response>,\n AsyncDisposable {\n terminate(): Promise<void>\n [Symbol.asyncDispose](): Promise<void>\n}\n\nexport function createServer<\n Request extends typeof IncomingMessage = typeof IncomingMessage,\n Response extends typeof ServerResponse<\n InstanceType<Request>\n > = typeof ServerResponse,\n>(\n handler: HandlerFunction | HandlerObject,\n options: CreateServerOptions<Request, Response> = {},\n): Server<Request, Response> {\n const handlerFn =\n typeof handler === 'function' ? handler : handler.handle.bind(handler)\n\n const listener = toRequestListener(handlerFn)\n const server = createHttpServer(options, listener)\n\n const terminator = createHttpTerminator({\n server: server as HttpServer,\n gracefulTerminationTimeout: options?.gracefulTerminationTimeout,\n })\n\n const terminate = async function terminate(this: Server<Request, Response>) {\n if (this !== server) {\n throw new TypeError('Server.terminate called with incorrect context')\n }\n // @TODO properly close all active WebSocket connections\n return terminator.terminate()\n }\n\n Object.defineProperty(server, 'terminate', {\n value: terminate,\n enumerable: false,\n configurable: false,\n writable: false,\n })\n\n Object.defineProperty(server, Symbol.asyncDispose, {\n value: terminate,\n enumerable: false,\n configurable: false,\n writable: false,\n })\n\n return server as Server<Request, Response>\n}\n\nexport type StartServerOptions<\n Request extends typeof IncomingMessage = typeof IncomingMessage,\n Response extends typeof ServerResponse<\n InstanceType<Request>\n > = typeof ServerResponse,\n> = ListenOptions & CreateServerOptions<Request, Response>\n\nexport async function serve<\n Request extends typeof IncomingMessage = typeof IncomingMessage,\n Response extends typeof ServerResponse<\n InstanceType<Request>\n > = typeof ServerResponse,\n>(\n handler: HandlerFunction | HandlerObject,\n options?: StartServerOptions<Request, Response>,\n): Promise<Server<Request, Response>> {\n const server = createServer(handler, options)\n server.listen(options)\n await once(server, 'listening')\n return server\n}\n"]}
|
|
1
|
+
{"version":3,"file":"nodejs.js","sourceRoot":"","sources":["../src/nodejs.ts"],"names":[],"mappings":"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","sourcesContent":["import { once } from 'node:events'\nimport {\n IncomingHttpHeaders,\n IncomingMessage,\n RequestListener,\n Server as HttpServer,\n ServerOptions,\n ServerResponse,\n createServer as createHttpServer,\n} from 'node:http'\nimport { ListenOptions } from 'node:net'\nimport { Readable } from 'node:stream'\nimport { pipeline } from 'node:stream/promises'\nimport { createHttpTerminator } from 'http-terminator'\nimport { WebSocket as WebSocketPonyfill, WebSocketServer } from 'ws'\n\n// @ts-expect-error\nSymbol.asyncDispose ??= Symbol.for('Symbol.asyncDispose')\n\nconst kResponseWs = Symbol.for('@atproto/lex-server:WebSocket')\n\nfunction isUpgradeRequest(request: Request, upgrade: string): boolean {\n return (\n request.method === 'GET' &&\n request.headers.get('connection')?.toLowerCase() === 'upgrade' &&\n request.headers.get('upgrade')?.toLowerCase() === upgrade\n )\n}\n\nexport function upgradeWebSocket(request: Request): {\n response: Response\n socket: WebSocket\n} {\n if (!isUpgradeRequest(request, 'websocket')) {\n throw new TypeError('upgradeWebSocket() expects a WebSocket upgrade')\n }\n\n // Placeholder response for WebSocket upgrade. The actual handling will happen\n // through the handleWebSocketUpgrade function. Headers set on the response\n // will be applied during the upgrade.\n const response = new Response(null, { status: 200 })\n\n // The Response constructor does not allow setting status 101, so we\n // define it directly. The purpose of this response is just to signal\n // that an upgrade is needed, and to carry any headers.\n Object.defineProperty(response, 'status', {\n value: 101,\n enumerable: false,\n configurable: false,\n writable: false,\n })\n\n // @ts-expect-error\n const socket: WebSocket = new WebSocketPonyfill(null, undefined, {\n autoPong: true,\n })\n\n // Attach the WebSocket to the response for later retrieval\n Object.defineProperty(response, kResponseWs, {\n value: socket,\n enumerable: false,\n configurable: false,\n writable: false,\n })\n\n return { response, socket }\n}\n\nconst kUpgradeEvent = Symbol.for('@atproto/lex-server:upgrade')\n\nfunction handleWebSocketUpgrade(\n req: IncomingMessage,\n response: Response,\n): void {\n const ws = (response as { [kResponseWs]?: WebSocketPonyfill })[kResponseWs]\n if (!ws) throw new TypeError('Response not created by upgradeWebSocket()')\n\n // Create a one time use WebSocketServer to handle the upgrade\n const wss = new WebSocketServer({\n autoPong: true,\n noServer: true,\n clientTracking: false,\n perMessageDeflate: true,\n // @ts-expect-error\n WebSocket: function () {\n // Return the websocket that was created earlier instead of a new instance\n return ws\n },\n })\n\n // Apply headers that might have been set on the response object during\n // handling. This will be called during wss.handleUpgrade().\n wss.on('headers', (headers) => {\n for (const [name, value] of response.headers) {\n headers.push(`${name}: ${value}`)\n }\n })\n\n wss.handleUpgrade(req, req.socket, Buffer.alloc(0), (_socket) => {\n // @TODO find a way to properly \"close\" the _socket when the server is\n // shutting down (might require replacing http-terminator with a local\n // implementation)\n\n req.emit(kUpgradeEvent, ws)\n })\n}\n\nasync function sendResponse(\n req: IncomingMessage,\n res: ServerResponse,\n response: Response,\n): Promise<void> {\n // Invalid usage\n if (res.headersSent) {\n throw new TypeError('Response has already been sent')\n }\n\n if (response.status === 101) {\n return handleWebSocketUpgrade(req, response)\n }\n\n res.statusCode = response.status\n res.statusMessage = response.statusText\n\n for (const [key, value] of response.headers) {\n res.appendHeader(key, value)\n }\n\n if (response.body != null && req.method !== 'HEAD') {\n const stream = Readable.fromWeb(response.body as any)\n await pipeline(stream, res)\n } else {\n await response.body?.cancel()\n res.end()\n }\n}\n\nfunction toRequest(req: IncomingMessage): Request {\n const host = req.headers.host ?? req.socket?.localAddress ?? 'localhost'\n const isEncrypted = (req.socket as any).encrypted === true\n const protocol = isEncrypted ? 'https' : 'http'\n const url = new URL(req.url ?? '/', `${protocol}://${host}`)\n const headers = toHeaders(req.headers)\n const body = toBody(req)\n const signal = requestSignal(req)\n\n return new Request(url, {\n signal,\n method: req.method,\n headers,\n body,\n referrer: headers.get('referrer') ?? headers.get('referer') ?? undefined,\n redirect: 'manual',\n // @ts-expect-error\n duplex: body ? 'half' : undefined,\n })\n}\n\nfunction requestSignal(req: IncomingMessage): AbortSignal {\n if (req.destroyed) return AbortSignal.abort()\n\n const abortController = new AbortController()\n\n const abort = (err?: Error | WebSocket) => {\n abortController.abort(err instanceof Error ? err : undefined)\n\n req.off('close', abort)\n req.off('error', abort)\n req.off('end', abort)\n req.off(kUpgradeEvent, abort)\n }\n\n req.on('close', abort)\n req.on('error', abort)\n req.on('end', abort)\n req.on(kUpgradeEvent, abort)\n\n return abortController.signal\n}\n\nfunction requestCompletion(req: IncomingMessage): Promise<void> {\n if (req.destroyed) return Promise.resolve()\n\n // Unlike the abort signal, we complete the promise only when the request\n // is fully done, accounting for websocket upgrade.\n return new Promise((resolve) => {\n const cleanup = () => {\n req.off('close', done)\n req.off('error', done)\n req.off('end', done)\n req.off(kUpgradeEvent, onUpgrade)\n }\n\n const onUpgrade = (ws: WebSocket) => {\n cleanup()\n ws.addEventListener('close', () => resolve())\n }\n\n const done = () => {\n resolve()\n cleanup()\n }\n\n req.on('close', done)\n req.on('error', done)\n req.on('end', done)\n req.on(kUpgradeEvent, onUpgrade)\n })\n}\n\nfunction toHeaders(headers: IncomingHttpHeaders): Headers {\n const result = new Headers()\n for (const [key, value] of Object.entries(headers)) {\n if (value === undefined) continue\n if (Array.isArray(value)) {\n for (const v of value) result.append(key, v)\n } else {\n result.set(key, value)\n }\n }\n return result\n}\n\nfunction toBody(req: IncomingMessage): null | ReadableStream<Uint8Array> {\n if (\n req.method === 'GET' ||\n req.method === 'HEAD' ||\n req.method === 'OPTIONS'\n ) {\n return null\n }\n\n if (\n req.headers['content-type'] == null &&\n req.headers['transfer-encoding'] == null &&\n req.headers['content-length'] == null\n ) {\n return null\n }\n\n return Readable.toWeb(req) as ReadableStream<Uint8Array>\n}\n\nexport type NetAddr = {\n transport: 'tcp'\n hostname: string\n port: number\n}\n\nexport type NodeConnectionInfo = {\n completed: Promise<void>\n remoteAddr: NetAddr | undefined\n}\n\nexport interface HandlerFunction {\n (req: Request, info: NodeConnectionInfo): Response | Promise<Response>\n}\n\nexport interface HandlerObject {\n handle: HandlerFunction\n}\n\nasync function handleRequest(\n req: IncomingMessage,\n res: ServerResponse,\n handlerFn: HandlerFunction,\n) {\n const request = toRequest(req)\n const info = toConnectionInfo(req)\n const response = await handlerFn(request, info)\n await sendResponse(req, res, response)\n}\n\nfunction toConnectionInfo(req: IncomingMessage): NodeConnectionInfo {\n const { socket } = req\n\n return {\n completed: requestCompletion(req),\n remoteAddr:\n socket.remoteAddress != null\n ? {\n transport: 'tcp',\n hostname: socket.remoteAddress,\n port: socket.remotePort!,\n }\n : undefined,\n }\n}\n\nexport function toRequestListener<\n Request extends typeof IncomingMessage = typeof IncomingMessage,\n Response extends typeof ServerResponse<\n InstanceType<Request>\n > = typeof ServerResponse,\n>(handlerFn: HandlerFunction) {\n return ((\n req: InstanceType<Request>,\n res: InstanceType<Response> & { req: InstanceType<Request> },\n next?: (err?: unknown) => void,\n ): void => {\n handleRequest(req, res, handlerFn).catch((err) => {\n if (next) next(err)\n else {\n if (!res.headersSent) {\n res.statusCode = 500\n res.setHeader('content-type', 'text/plain; charset=utf-8')\n res.end('Internal Server Error')\n } else if (!res.writableEnded) {\n res.destroy()\n }\n }\n })\n }) satisfies RequestListener<Request, Response>\n}\n\nexport type CreateServerOptions<\n Request extends typeof IncomingMessage = typeof IncomingMessage,\n Response extends typeof ServerResponse<\n InstanceType<Request>\n > = typeof ServerResponse,\n> = ServerOptions<Request, Response> & {\n gracefulTerminationTimeout?: number\n}\n\nexport interface Server<\n Request extends typeof IncomingMessage = typeof IncomingMessage,\n Response extends typeof ServerResponse<\n InstanceType<Request>\n > = typeof ServerResponse,\n> extends HttpServer<Request, Response>,\n AsyncDisposable {\n terminate(): Promise<void>\n [Symbol.asyncDispose](): Promise<void>\n}\n\nexport function createServer<\n Request extends typeof IncomingMessage = typeof IncomingMessage,\n Response extends typeof ServerResponse<\n InstanceType<Request>\n > = typeof ServerResponse,\n>(\n handler: HandlerFunction | HandlerObject,\n options: CreateServerOptions<Request, Response> = {},\n): Server<Request, Response> {\n const handlerFn =\n typeof handler === 'function' ? handler : handler.handle.bind(handler)\n\n const listener = toRequestListener(handlerFn)\n const server = createHttpServer(options, listener)\n\n const terminator = createHttpTerminator({\n server: server as HttpServer,\n gracefulTerminationTimeout: options?.gracefulTerminationTimeout,\n })\n\n const terminate = async function terminate(this: Server<Request, Response>) {\n if (this !== server) {\n throw new TypeError('Server.terminate called with incorrect context')\n }\n // @TODO properly close all active WebSocket connections\n return terminator.terminate()\n }\n\n Object.defineProperty(server, 'terminate', {\n value: terminate,\n enumerable: false,\n configurable: false,\n writable: false,\n })\n\n Object.defineProperty(server, Symbol.asyncDispose, {\n value: terminate,\n enumerable: false,\n configurable: false,\n writable: false,\n })\n\n return server as Server<Request, Response>\n}\n\nexport type StartServerOptions<\n Request extends typeof IncomingMessage = typeof IncomingMessage,\n Response extends typeof ServerResponse<\n InstanceType<Request>\n > = typeof ServerResponse,\n> = ListenOptions & CreateServerOptions<Request, Response>\n\nexport async function serve<\n Request extends typeof IncomingMessage = typeof IncomingMessage,\n Response extends typeof ServerResponse<\n InstanceType<Request>\n > = typeof ServerResponse,\n>(\n handler: HandlerFunction | HandlerObject,\n options?: StartServerOptions<Request, Response>,\n): Promise<Server<Request, Response>> {\n const server = createServer(handler, options)\n server.listen(options)\n await once(server, 'listening')\n return server\n}\n"]}
|