@atproto/lex-server 0.0.7 → 0.0.9
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 +30 -0
- package/dist/errors.d.ts +94 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +94 -0
- package/dist/errors.js.map +1 -1
- package/dist/lex-server.d.ts +481 -2
- package/dist/lex-server.d.ts.map +1 -1
- package/dist/lex-server.js +103 -0
- package/dist/lex-server.js.map +1 -1
- package/dist/lib/www-authenticate.d.ts +66 -0
- package/dist/lib/www-authenticate.d.ts.map +1 -1
- package/dist/lib/www-authenticate.js +28 -0
- package/dist/lib/www-authenticate.js.map +1 -1
- package/dist/nodejs.d.ts +279 -0
- package/dist/nodejs.d.ts.map +1 -1
- package/dist/nodejs.js +184 -1
- package/dist/nodejs.js.map +1 -1
- package/dist/service-auth.d.ts +151 -9
- package/dist/service-auth.d.ts.map +1 -1
- package/dist/service-auth.js +41 -2
- package/dist/service-auth.js.map +1 -1
- package/package.json +11 -11
- package/src/errors.ts +94 -0
- package/src/lex-server.test.ts +3 -2
- package/src/lex-server.ts +482 -2
- package/src/lib/www-authenticate.ts +66 -0
- package/src/nodejs.ts +280 -2
- package/src/service-auth.ts +151 -9
package/dist/nodejs.d.ts
CHANGED
|
@@ -1,33 +1,312 @@
|
|
|
1
1
|
import { IncomingMessage, Server as HttpServer, ServerOptions, ServerResponse } from 'node:http';
|
|
2
2
|
import { ListenOptions } from 'node:net';
|
|
3
3
|
import { FetchHandler } from './lex-server.js';
|
|
4
|
+
/**
|
|
5
|
+
* Upgrades an HTTP request to a WebSocket connection for Node.js.
|
|
6
|
+
*
|
|
7
|
+
* This function must be passed to the {@link LexRouter} constructor to enable
|
|
8
|
+
* subscription (WebSocket) support on Node.js. It creates a WebSocket instance
|
|
9
|
+
* and a placeholder response that signals the need for protocol upgrade.
|
|
10
|
+
*
|
|
11
|
+
* The actual upgrade is handled internally when the response is sent through
|
|
12
|
+
* {@link sendResponse}.
|
|
13
|
+
*
|
|
14
|
+
* @param request - The incoming HTTP request to upgrade
|
|
15
|
+
* @returns An object containing the WebSocket and upgrade response
|
|
16
|
+
* @throws {TypeError} If the request is not a valid WebSocket upgrade request
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* import { LexRouter } from '@atproto/lex-server'
|
|
21
|
+
* import { upgradeWebSocket } from '@atproto/lex-server/nodejs'
|
|
22
|
+
*
|
|
23
|
+
* // Pass to router for subscription support
|
|
24
|
+
* const router = new LexRouter({ upgradeWebSocket })
|
|
25
|
+
*
|
|
26
|
+
* // Now you can add subscription handlers
|
|
27
|
+
* router.add(subscribeRepos, async function* (ctx) {
|
|
28
|
+
* for await (const event of eventStream) {
|
|
29
|
+
* yield event
|
|
30
|
+
* }
|
|
31
|
+
* })
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
4
34
|
export declare function upgradeWebSocket(request: Request): {
|
|
5
35
|
response: Response;
|
|
6
36
|
socket: WebSocket;
|
|
7
37
|
};
|
|
38
|
+
/**
|
|
39
|
+
* Sends a fetch API Response through a Node.js ServerResponse.
|
|
40
|
+
*
|
|
41
|
+
* Handles both regular HTTP responses and WebSocket upgrades. For WebSocket
|
|
42
|
+
* upgrades (status 101), delegates to the WebSocket upgrade handler.
|
|
43
|
+
*
|
|
44
|
+
* This function is used internally by {@link toRequestListener} and
|
|
45
|
+
* {@link createServer}, but can be used directly for custom integrations.
|
|
46
|
+
*
|
|
47
|
+
* @param req - The Node.js IncomingMessage
|
|
48
|
+
* @param res - The Node.js ServerResponse to write to
|
|
49
|
+
* @param response - The fetch API Response to send
|
|
50
|
+
* @throws {TypeError} If headers have already been sent
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* import http from 'node:http'
|
|
55
|
+
* import { sendResponse } from '@atproto/lex-server/nodejs'
|
|
56
|
+
*
|
|
57
|
+
* const server = http.createServer(async (req, res) => {
|
|
58
|
+
* const response = new Response('Hello, World!', {
|
|
59
|
+
* headers: { 'Content-Type': 'text/plain' }
|
|
60
|
+
* })
|
|
61
|
+
* await sendResponse(req, res, response)
|
|
62
|
+
* })
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export declare function sendResponse(req: IncomingMessage, res: ServerResponse, response: Response): Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* Network address type for Node.js TCP connections.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```typescript
|
|
71
|
+
* const addr: NetAddr = {
|
|
72
|
+
* transport: 'tcp',
|
|
73
|
+
* hostname: '192.168.1.100',
|
|
74
|
+
* port: 54321
|
|
75
|
+
* }
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
8
78
|
export type NetAddr = {
|
|
79
|
+
/** Always 'tcp' for Node.js HTTP connections. */
|
|
9
80
|
transport: 'tcp';
|
|
81
|
+
/** The IP address of the remote client. */
|
|
10
82
|
hostname: string;
|
|
83
|
+
/** The port number of the remote client. */
|
|
11
84
|
port: number;
|
|
12
85
|
};
|
|
86
|
+
/**
|
|
87
|
+
* Connection metadata for Node.js HTTP requests.
|
|
88
|
+
*
|
|
89
|
+
* Provides information about the client connection, including the remote
|
|
90
|
+
* address and a promise that resolves when the connection is fully closed
|
|
91
|
+
* (including WebSocket connections).
|
|
92
|
+
*/
|
|
13
93
|
export type NodeConnectionInfo = {
|
|
94
|
+
/** Promise that resolves when the connection is fully closed. */
|
|
14
95
|
completed: Promise<void>;
|
|
96
|
+
/** The remote address of the client, if available. */
|
|
15
97
|
remoteAddr: NetAddr | undefined;
|
|
16
98
|
};
|
|
99
|
+
/**
|
|
100
|
+
* Interface for objects that can handle fetch-style requests.
|
|
101
|
+
*
|
|
102
|
+
* Used by {@link createServer} and {@link serve} to accept either
|
|
103
|
+
* a fetch handler function or an object with a `fetch` method
|
|
104
|
+
* (like {@link LexRouter}).
|
|
105
|
+
*/
|
|
17
106
|
export interface HandlerObject {
|
|
107
|
+
/** The fetch handler method. */
|
|
18
108
|
fetch: FetchHandler;
|
|
19
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* Converts a fetch-style handler to a Node.js request listener.
|
|
112
|
+
*
|
|
113
|
+
* The returned listener can be used with Node.js HTTP servers directly,
|
|
114
|
+
* or as middleware in frameworks like Express (supports the `next` callback).
|
|
115
|
+
*
|
|
116
|
+
* @typeParam Request - The request class type (default: IncomingMessage)
|
|
117
|
+
* @typeParam Response - The response class type (default: ServerResponse)
|
|
118
|
+
* @param fetchHandler - The fetch-style handler function
|
|
119
|
+
* @returns A Node.js RequestListener compatible with http.createServer
|
|
120
|
+
*
|
|
121
|
+
* @example Using as Express middleware
|
|
122
|
+
* ```typescript
|
|
123
|
+
* import express from 'express'
|
|
124
|
+
* import { toRequestListener } from '@atproto/lex-server/nodejs'
|
|
125
|
+
* import { LexRouter } from '@atproto/lex-server'
|
|
126
|
+
*
|
|
127
|
+
* const router = new LexRouter()
|
|
128
|
+
* // Register handlers...
|
|
129
|
+
*
|
|
130
|
+
* const app = express()
|
|
131
|
+
*
|
|
132
|
+
* // Mount the XRPC router
|
|
133
|
+
* app.use('/xrpc', toRequestListener(router.fetch))
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
20
136
|
export declare function toRequestListener<Request extends typeof IncomingMessage = typeof IncomingMessage, Response extends typeof ServerResponse<InstanceType<Request>> = typeof ServerResponse>(fetchHandler: FetchHandler): (req: InstanceType<Request>, res: InstanceType<Response> & {
|
|
21
137
|
req: InstanceType<Request>;
|
|
22
138
|
}, next?: (err?: unknown) => void) => void;
|
|
139
|
+
/**
|
|
140
|
+
* Options for creating an XRPC server.
|
|
141
|
+
*
|
|
142
|
+
* Extends Node.js {@link ServerOptions} with additional options for graceful shutdown.
|
|
143
|
+
*/
|
|
23
144
|
export type CreateServerOptions<Request extends typeof IncomingMessage = typeof IncomingMessage, Response extends typeof ServerResponse<InstanceType<Request>> = typeof ServerResponse> = ServerOptions<Request, Response> & {
|
|
145
|
+
/**
|
|
146
|
+
* Timeout in milliseconds for graceful termination.
|
|
147
|
+
*
|
|
148
|
+
* When `terminate()` is called, the server will wait up to this duration
|
|
149
|
+
* for active connections to complete before forcibly closing them.
|
|
150
|
+
*/
|
|
24
151
|
gracefulTerminationTimeout?: number;
|
|
25
152
|
};
|
|
153
|
+
/**
|
|
154
|
+
* Extended HTTP server with graceful shutdown support.
|
|
155
|
+
*
|
|
156
|
+
* Extends the standard Node.js HttpServer with a `terminate()` method
|
|
157
|
+
* for graceful shutdown and implements `AsyncDisposable` for use with
|
|
158
|
+
* `await using`.
|
|
159
|
+
*
|
|
160
|
+
* @typeParam Request - The request class type
|
|
161
|
+
* @typeParam Response - The response class type
|
|
162
|
+
*
|
|
163
|
+
* @example Graceful shutdown
|
|
164
|
+
* ```typescript
|
|
165
|
+
* const server = createServer(router)
|
|
166
|
+
* server.listen(3000)
|
|
167
|
+
*
|
|
168
|
+
* process.on('SIGTERM', async () => {
|
|
169
|
+
* console.log('Shutting down...')
|
|
170
|
+
* await server.terminate()
|
|
171
|
+
* console.log('Server stopped')
|
|
172
|
+
* })
|
|
173
|
+
* ```
|
|
174
|
+
*
|
|
175
|
+
* @example Using with await using
|
|
176
|
+
* ```typescript
|
|
177
|
+
* await using server = await serve(router, { port: 3000 })
|
|
178
|
+
* // Server will be automatically terminated when scope exits
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
26
181
|
export interface Server<Request extends typeof IncomingMessage = typeof IncomingMessage, Response extends typeof ServerResponse<InstanceType<Request>> = typeof ServerResponse> extends HttpServer<Request, Response>, AsyncDisposable {
|
|
182
|
+
/**
|
|
183
|
+
* Gracefully terminates the server.
|
|
184
|
+
*
|
|
185
|
+
* Stops accepting new connections and waits for active connections
|
|
186
|
+
* to complete (up to `gracefulTerminationTimeout`).
|
|
187
|
+
*
|
|
188
|
+
* @returns Promise that resolves when the server is fully stopped
|
|
189
|
+
*/
|
|
27
190
|
terminate(): Promise<void>;
|
|
28
191
|
[Symbol.asyncDispose](): Promise<void>;
|
|
29
192
|
}
|
|
193
|
+
/**
|
|
194
|
+
* Creates an HTTP server configured for XRPC request handling.
|
|
195
|
+
*
|
|
196
|
+
* The server includes graceful shutdown support and can be used with
|
|
197
|
+
* either a fetch handler function or an object with a `fetch` method
|
|
198
|
+
* (like {@link LexRouter}).
|
|
199
|
+
*
|
|
200
|
+
* Note: This creates the server but does not start listening. Call
|
|
201
|
+
* `server.listen()` to start the server, or use {@link serve} for
|
|
202
|
+
* a combined create-and-listen operation.
|
|
203
|
+
*
|
|
204
|
+
* @typeParam Request - The request class type
|
|
205
|
+
* @typeParam Response - The response class type
|
|
206
|
+
* @param handler - A fetch handler or object with fetch method
|
|
207
|
+
* @param options - Server configuration options
|
|
208
|
+
* @returns An HTTP server with graceful shutdown support
|
|
209
|
+
*
|
|
210
|
+
* @example Basic usage
|
|
211
|
+
* ```typescript
|
|
212
|
+
* import { LexRouter } from '@atproto/lex-server'
|
|
213
|
+
* import { createServer, upgradeWebSocket } from '@atproto/lex-server/nodejs'
|
|
214
|
+
*
|
|
215
|
+
* const router = new LexRouter({ upgradeWebSocket })
|
|
216
|
+
* router.add(myMethod, myHandler)
|
|
217
|
+
*
|
|
218
|
+
* const server = createServer(router)
|
|
219
|
+
* server.listen(3000, () => {
|
|
220
|
+
* console.log('Server listening on port 3000')
|
|
221
|
+
* })
|
|
222
|
+
* ```
|
|
223
|
+
*
|
|
224
|
+
* @example With graceful termination timeout
|
|
225
|
+
* ```typescript
|
|
226
|
+
* const server = createServer(router, {
|
|
227
|
+
* gracefulTerminationTimeout: 10000 // 10 seconds
|
|
228
|
+
* })
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
30
231
|
export declare function createServer<Request extends typeof IncomingMessage = typeof IncomingMessage, Response extends typeof ServerResponse<InstanceType<Request>> = typeof ServerResponse>(handler: FetchHandler | HandlerObject, options?: CreateServerOptions<Request, Response>): Server<Request, Response>;
|
|
232
|
+
/**
|
|
233
|
+
* Combined options for creating and starting an XRPC server.
|
|
234
|
+
*
|
|
235
|
+
* Includes both server creation options and network listen options.
|
|
236
|
+
*
|
|
237
|
+
* @typeParam Request - The request class type
|
|
238
|
+
* @typeParam Response - The response class type
|
|
239
|
+
*
|
|
240
|
+
* @example
|
|
241
|
+
* ```typescript
|
|
242
|
+
* const options: StartServerOptions = {
|
|
243
|
+
* port: 3000,
|
|
244
|
+
* host: '0.0.0.0',
|
|
245
|
+
* gracefulTerminationTimeout: 10000
|
|
246
|
+
* }
|
|
247
|
+
* ```
|
|
248
|
+
*/
|
|
31
249
|
export type StartServerOptions<Request extends typeof IncomingMessage = typeof IncomingMessage, Response extends typeof ServerResponse<InstanceType<Request>> = typeof ServerResponse> = ListenOptions & CreateServerOptions<Request, Response>;
|
|
250
|
+
/**
|
|
251
|
+
* Creates and starts an HTTP server, returning when it's ready to accept connections.
|
|
252
|
+
*
|
|
253
|
+
* This is a convenience function that combines {@link createServer} and `server.listen()`
|
|
254
|
+
* into a single async operation. The returned promise resolves once the server
|
|
255
|
+
* is actively listening.
|
|
256
|
+
*
|
|
257
|
+
* @typeParam Request - The request class type
|
|
258
|
+
* @typeParam Response - The response class type
|
|
259
|
+
* @param handler - A fetch handler or object with fetch method (like {@link LexRouter})
|
|
260
|
+
* @param options - Combined server and listen options
|
|
261
|
+
* @returns Promise resolving to the running server
|
|
262
|
+
*
|
|
263
|
+
* @example Basic usage
|
|
264
|
+
* ```typescript
|
|
265
|
+
* import { LexRouter } from '@atproto/lex-server'
|
|
266
|
+
* import { serve, upgradeWebSocket } from '@atproto/lex-server/nodejs'
|
|
267
|
+
*
|
|
268
|
+
* const router = new LexRouter({ upgradeWebSocket })
|
|
269
|
+
*
|
|
270
|
+
* // Register handlers
|
|
271
|
+
* router.add(getProfile, async (ctx) => {
|
|
272
|
+
* return { body: await db.getProfile(ctx.params.actor) }
|
|
273
|
+
* })
|
|
274
|
+
*
|
|
275
|
+
* // Start server on port 3000
|
|
276
|
+
* const server = await serve(router, { port: 3000 })
|
|
277
|
+
* console.log('Server listening on port 3000')
|
|
278
|
+
*
|
|
279
|
+
* // Graceful shutdown
|
|
280
|
+
* process.on('SIGTERM', () => server.terminate())
|
|
281
|
+
* process.on('SIGINT', () => server.terminate())
|
|
282
|
+
* ```
|
|
283
|
+
*
|
|
284
|
+
* @example With all options
|
|
285
|
+
* ```typescript
|
|
286
|
+
* const server = await serve(router, {
|
|
287
|
+
* port: 3000,
|
|
288
|
+
* host: '0.0.0.0',
|
|
289
|
+
* gracefulTerminationTimeout: 15000,
|
|
290
|
+
* })
|
|
291
|
+
* ```
|
|
292
|
+
*
|
|
293
|
+
* @example Using with await using (auto-cleanup)
|
|
294
|
+
* ```typescript
|
|
295
|
+
* async function main() {
|
|
296
|
+
* await using server = await serve(router, { port: 3000 })
|
|
297
|
+
*
|
|
298
|
+
* // Server is running...
|
|
299
|
+
* console.log('Server listening on port 3000')
|
|
300
|
+
*
|
|
301
|
+
* // Wait for termination signal
|
|
302
|
+
* await Promise.race([
|
|
303
|
+
* once(process, 'SIGINT'),
|
|
304
|
+
* once(process, 'SIGTERM'),
|
|
305
|
+
* ])
|
|
306
|
+
*
|
|
307
|
+
* // Server will be automatically terminated when scope exits
|
|
308
|
+
* }
|
|
309
|
+
* ```
|
|
310
|
+
*/
|
|
32
311
|
export declare function serve<Request extends typeof IncomingMessage = typeof IncomingMessage, Response extends typeof ServerResponse<InstanceType<Request>> = typeof ServerResponse>(handler: FetchHandler | HandlerObject, options?: StartServerOptions<Request, Response>): Promise<Server<Request, Response>>;
|
|
33
312
|
//# sourceMappingURL=nodejs.d.ts.map
|
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;AAKxC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAe9C,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
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.upgradeWebSocket = upgradeWebSocket;
|
|
4
|
+
exports.sendResponse = sendResponse;
|
|
4
5
|
exports.toRequestListener = toRequestListener;
|
|
5
6
|
exports.createServer = createServer;
|
|
6
7
|
exports.serve = serve;
|
|
@@ -18,6 +19,36 @@ function isUpgradeRequest(request, upgrade) {
|
|
|
18
19
|
request.headers.get('connection')?.toLowerCase() === 'upgrade' &&
|
|
19
20
|
request.headers.get('upgrade')?.toLowerCase() === upgrade);
|
|
20
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Upgrades an HTTP request to a WebSocket connection for Node.js.
|
|
24
|
+
*
|
|
25
|
+
* This function must be passed to the {@link LexRouter} constructor to enable
|
|
26
|
+
* subscription (WebSocket) support on Node.js. It creates a WebSocket instance
|
|
27
|
+
* and a placeholder response that signals the need for protocol upgrade.
|
|
28
|
+
*
|
|
29
|
+
* The actual upgrade is handled internally when the response is sent through
|
|
30
|
+
* {@link sendResponse}.
|
|
31
|
+
*
|
|
32
|
+
* @param request - The incoming HTTP request to upgrade
|
|
33
|
+
* @returns An object containing the WebSocket and upgrade response
|
|
34
|
+
* @throws {TypeError} If the request is not a valid WebSocket upgrade request
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* import { LexRouter } from '@atproto/lex-server'
|
|
39
|
+
* import { upgradeWebSocket } from '@atproto/lex-server/nodejs'
|
|
40
|
+
*
|
|
41
|
+
* // Pass to router for subscription support
|
|
42
|
+
* const router = new LexRouter({ upgradeWebSocket })
|
|
43
|
+
*
|
|
44
|
+
* // Now you can add subscription handlers
|
|
45
|
+
* router.add(subscribeRepos, async function* (ctx) {
|
|
46
|
+
* for await (const event of eventStream) {
|
|
47
|
+
* yield event
|
|
48
|
+
* }
|
|
49
|
+
* })
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
21
52
|
function upgradeWebSocket(request) {
|
|
22
53
|
if (!isUpgradeRequest(request, 'websocket')) {
|
|
23
54
|
throw new TypeError('upgradeWebSocket() expects a WebSocket upgrade');
|
|
@@ -79,6 +110,33 @@ function handleWebSocketUpgrade(req, response) {
|
|
|
79
110
|
req.emit(kUpgradeEvent, ws);
|
|
80
111
|
});
|
|
81
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Sends a fetch API Response through a Node.js ServerResponse.
|
|
115
|
+
*
|
|
116
|
+
* Handles both regular HTTP responses and WebSocket upgrades. For WebSocket
|
|
117
|
+
* upgrades (status 101), delegates to the WebSocket upgrade handler.
|
|
118
|
+
*
|
|
119
|
+
* This function is used internally by {@link toRequestListener} and
|
|
120
|
+
* {@link createServer}, but can be used directly for custom integrations.
|
|
121
|
+
*
|
|
122
|
+
* @param req - The Node.js IncomingMessage
|
|
123
|
+
* @param res - The Node.js ServerResponse to write to
|
|
124
|
+
* @param response - The fetch API Response to send
|
|
125
|
+
* @throws {TypeError} If headers have already been sent
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```typescript
|
|
129
|
+
* import http from 'node:http'
|
|
130
|
+
* import { sendResponse } from '@atproto/lex-server/nodejs'
|
|
131
|
+
*
|
|
132
|
+
* const server = http.createServer(async (req, res) => {
|
|
133
|
+
* const response = new Response('Hello, World!', {
|
|
134
|
+
* headers: { 'Content-Type': 'text/plain' }
|
|
135
|
+
* })
|
|
136
|
+
* await sendResponse(req, res, response)
|
|
137
|
+
* })
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
82
140
|
async function sendResponse(req, res, response) {
|
|
83
141
|
// Invalid usage
|
|
84
142
|
if (res.headersSent) {
|
|
@@ -90,7 +148,7 @@ async function sendResponse(req, res, response) {
|
|
|
90
148
|
res.statusCode = response.status;
|
|
91
149
|
res.statusMessage = response.statusText;
|
|
92
150
|
for (const [key, value] of response.headers) {
|
|
93
|
-
res.
|
|
151
|
+
res.setHeader(key, value);
|
|
94
152
|
}
|
|
95
153
|
if (response.body != null && req.method !== 'HEAD') {
|
|
96
154
|
const stream = node_stream_1.Readable.fromWeb(response.body);
|
|
@@ -210,6 +268,32 @@ function toConnectionInfo(req) {
|
|
|
210
268
|
: undefined,
|
|
211
269
|
};
|
|
212
270
|
}
|
|
271
|
+
/**
|
|
272
|
+
* Converts a fetch-style handler to a Node.js request listener.
|
|
273
|
+
*
|
|
274
|
+
* The returned listener can be used with Node.js HTTP servers directly,
|
|
275
|
+
* or as middleware in frameworks like Express (supports the `next` callback).
|
|
276
|
+
*
|
|
277
|
+
* @typeParam Request - The request class type (default: IncomingMessage)
|
|
278
|
+
* @typeParam Response - The response class type (default: ServerResponse)
|
|
279
|
+
* @param fetchHandler - The fetch-style handler function
|
|
280
|
+
* @returns A Node.js RequestListener compatible with http.createServer
|
|
281
|
+
*
|
|
282
|
+
* @example Using as Express middleware
|
|
283
|
+
* ```typescript
|
|
284
|
+
* import express from 'express'
|
|
285
|
+
* import { toRequestListener } from '@atproto/lex-server/nodejs'
|
|
286
|
+
* import { LexRouter } from '@atproto/lex-server'
|
|
287
|
+
*
|
|
288
|
+
* const router = new LexRouter()
|
|
289
|
+
* // Register handlers...
|
|
290
|
+
*
|
|
291
|
+
* const app = express()
|
|
292
|
+
*
|
|
293
|
+
* // Mount the XRPC router
|
|
294
|
+
* app.use('/xrpc', toRequestListener(router.fetch))
|
|
295
|
+
* ```
|
|
296
|
+
*/
|
|
213
297
|
function toRequestListener(fetchHandler) {
|
|
214
298
|
return ((req, res, next) => {
|
|
215
299
|
handleRequest(req, res, fetchHandler).catch((err) => {
|
|
@@ -228,6 +312,44 @@ function toRequestListener(fetchHandler) {
|
|
|
228
312
|
});
|
|
229
313
|
});
|
|
230
314
|
}
|
|
315
|
+
/**
|
|
316
|
+
* Creates an HTTP server configured for XRPC request handling.
|
|
317
|
+
*
|
|
318
|
+
* The server includes graceful shutdown support and can be used with
|
|
319
|
+
* either a fetch handler function or an object with a `fetch` method
|
|
320
|
+
* (like {@link LexRouter}).
|
|
321
|
+
*
|
|
322
|
+
* Note: This creates the server but does not start listening. Call
|
|
323
|
+
* `server.listen()` to start the server, or use {@link serve} for
|
|
324
|
+
* a combined create-and-listen operation.
|
|
325
|
+
*
|
|
326
|
+
* @typeParam Request - The request class type
|
|
327
|
+
* @typeParam Response - The response class type
|
|
328
|
+
* @param handler - A fetch handler or object with fetch method
|
|
329
|
+
* @param options - Server configuration options
|
|
330
|
+
* @returns An HTTP server with graceful shutdown support
|
|
331
|
+
*
|
|
332
|
+
* @example Basic usage
|
|
333
|
+
* ```typescript
|
|
334
|
+
* import { LexRouter } from '@atproto/lex-server'
|
|
335
|
+
* import { createServer, upgradeWebSocket } from '@atproto/lex-server/nodejs'
|
|
336
|
+
*
|
|
337
|
+
* const router = new LexRouter({ upgradeWebSocket })
|
|
338
|
+
* router.add(myMethod, myHandler)
|
|
339
|
+
*
|
|
340
|
+
* const server = createServer(router)
|
|
341
|
+
* server.listen(3000, () => {
|
|
342
|
+
* console.log('Server listening on port 3000')
|
|
343
|
+
* })
|
|
344
|
+
* ```
|
|
345
|
+
*
|
|
346
|
+
* @example With graceful termination timeout
|
|
347
|
+
* ```typescript
|
|
348
|
+
* const server = createServer(router, {
|
|
349
|
+
* gracefulTerminationTimeout: 10000 // 10 seconds
|
|
350
|
+
* })
|
|
351
|
+
* ```
|
|
352
|
+
*/
|
|
231
353
|
function createServer(handler, options = {}) {
|
|
232
354
|
const fetchHandler = typeof handler === 'function' ? handler : handler.fetch.bind(handler);
|
|
233
355
|
const listener = toRequestListener(fetchHandler);
|
|
@@ -257,6 +379,67 @@ function createServer(handler, options = {}) {
|
|
|
257
379
|
});
|
|
258
380
|
return server;
|
|
259
381
|
}
|
|
382
|
+
/**
|
|
383
|
+
* Creates and starts an HTTP server, returning when it's ready to accept connections.
|
|
384
|
+
*
|
|
385
|
+
* This is a convenience function that combines {@link createServer} and `server.listen()`
|
|
386
|
+
* into a single async operation. The returned promise resolves once the server
|
|
387
|
+
* is actively listening.
|
|
388
|
+
*
|
|
389
|
+
* @typeParam Request - The request class type
|
|
390
|
+
* @typeParam Response - The response class type
|
|
391
|
+
* @param handler - A fetch handler or object with fetch method (like {@link LexRouter})
|
|
392
|
+
* @param options - Combined server and listen options
|
|
393
|
+
* @returns Promise resolving to the running server
|
|
394
|
+
*
|
|
395
|
+
* @example Basic usage
|
|
396
|
+
* ```typescript
|
|
397
|
+
* import { LexRouter } from '@atproto/lex-server'
|
|
398
|
+
* import { serve, upgradeWebSocket } from '@atproto/lex-server/nodejs'
|
|
399
|
+
*
|
|
400
|
+
* const router = new LexRouter({ upgradeWebSocket })
|
|
401
|
+
*
|
|
402
|
+
* // Register handlers
|
|
403
|
+
* router.add(getProfile, async (ctx) => {
|
|
404
|
+
* return { body: await db.getProfile(ctx.params.actor) }
|
|
405
|
+
* })
|
|
406
|
+
*
|
|
407
|
+
* // Start server on port 3000
|
|
408
|
+
* const server = await serve(router, { port: 3000 })
|
|
409
|
+
* console.log('Server listening on port 3000')
|
|
410
|
+
*
|
|
411
|
+
* // Graceful shutdown
|
|
412
|
+
* process.on('SIGTERM', () => server.terminate())
|
|
413
|
+
* process.on('SIGINT', () => server.terminate())
|
|
414
|
+
* ```
|
|
415
|
+
*
|
|
416
|
+
* @example With all options
|
|
417
|
+
* ```typescript
|
|
418
|
+
* const server = await serve(router, {
|
|
419
|
+
* port: 3000,
|
|
420
|
+
* host: '0.0.0.0',
|
|
421
|
+
* gracefulTerminationTimeout: 15000,
|
|
422
|
+
* })
|
|
423
|
+
* ```
|
|
424
|
+
*
|
|
425
|
+
* @example Using with await using (auto-cleanup)
|
|
426
|
+
* ```typescript
|
|
427
|
+
* async function main() {
|
|
428
|
+
* await using server = await serve(router, { port: 3000 })
|
|
429
|
+
*
|
|
430
|
+
* // Server is running...
|
|
431
|
+
* console.log('Server listening on port 3000')
|
|
432
|
+
*
|
|
433
|
+
* // Wait for termination signal
|
|
434
|
+
* await Promise.race([
|
|
435
|
+
* once(process, 'SIGINT'),
|
|
436
|
+
* once(process, 'SIGTERM'),
|
|
437
|
+
* ])
|
|
438
|
+
*
|
|
439
|
+
* // Server will be automatically terminated when scope exits
|
|
440
|
+
* }
|
|
441
|
+
* ```
|
|
442
|
+
*/
|
|
260
443
|
async function serve(handler, options) {
|
|
261
444
|
const server = createServer(handler, options);
|
|
262
445
|
server.listen(options);
|