@sisu-ai/server 7.0.1 → 7.0.2

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/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import http, { type IncomingMessage, type ServerResponse } from 'http';
2
- import https from 'https';
3
- import type { Agent, Logger } from '@sisu-ai/core';
4
- import type { AddressInfo } from 'net';
5
- export { matchRoute } from './router.js';
1
+ import http, { type IncomingMessage, type ServerResponse } from "http";
2
+ import https from "https";
3
+ import type { Agent, Logger, Ctx } from "@sisu-ai/core";
4
+ import type { AddressInfo } from "net";
5
+ export { matchRoute } from "./router.js";
6
6
  export interface ListenOptions<Ctx> {
7
7
  tls?: https.ServerOptions;
8
8
  port?: number;
@@ -15,10 +15,15 @@ export interface ListenOptions<Ctx> {
15
15
  logBanner?: boolean;
16
16
  bannerEndpoints?: string[];
17
17
  logger?: Logger;
18
- logLevel?: 'debug' | 'info' | 'warn' | 'error';
18
+ logLevel?: "debug" | "info" | "warn" | "error";
19
19
  redactLogKeys?: string[];
20
20
  }
21
- export declare class Server<Ctx = any> {
21
+ type HttpEnvelope<CtxT extends Ctx> = {
22
+ req?: IncomingMessage;
23
+ res?: ServerResponse;
24
+ agent?: Agent<CtxT>;
25
+ };
26
+ export declare class Server<CtxT extends Ctx & HttpEnvelope<CtxT>> {
22
27
  private agent;
23
28
  private opts;
24
29
  private server?;
@@ -26,59 +31,59 @@ export declare class Server<Ctx = any> {
26
31
  private healthPath;
27
32
  private createCtx;
28
33
  private emitter;
29
- constructor(agent: Agent<any>, opts?: ListenOptions<Ctx>);
34
+ constructor(agent: Agent<CtxT>, opts?: ListenOptions<CtxT>);
30
35
  private handle;
31
36
  listener(): (req: IncomingMessage, res: ServerResponse) => Promise<void>;
32
37
  listen(cb?: () => void): http.Server<typeof http.IncomingMessage, typeof http.ServerResponse> | https.Server<typeof http.IncomingMessage, typeof http.ServerResponse>;
33
38
  attach(server: http.Server | https.Server): void;
34
39
  close(cb?: (err?: Error) => void): void;
35
40
  address(): string | AddressInfo | null | undefined;
36
- on(event: 'listening', handler: (e: {
41
+ on(event: "listening", handler: (e: {
37
42
  url: string;
38
43
  address: string | AddressInfo | null | undefined;
39
44
  }) => void): this;
40
- on(event: 'request', handler: (e: {
45
+ on(event: "request", handler: (e: {
41
46
  method: string;
42
47
  url: string;
43
48
  }) => void): this;
44
- on(event: 'response', handler: (e: {
49
+ on(event: "response", handler: (e: {
45
50
  method: string;
46
51
  url: string;
47
52
  status: number;
48
53
  duration_ms: number;
49
54
  }) => void): this;
50
- on(event: 'error', handler: (err: Error) => void): this;
51
- on(event: 'close', handler: () => void): this;
52
- once(event: 'listening', handler: (e: {
55
+ on(event: "error", handler: (err: Error) => void): this;
56
+ on(event: "close", handler: () => void): this;
57
+ once(event: "listening", handler: (e: {
53
58
  url: string;
54
59
  address: string | AddressInfo | null | undefined;
55
60
  }) => void): this;
56
- once(event: 'request', handler: (e: {
61
+ once(event: "request", handler: (e: {
57
62
  method: string;
58
63
  url: string;
59
64
  }) => void): this;
60
- once(event: 'response', handler: (e: {
65
+ once(event: "response", handler: (e: {
61
66
  method: string;
62
67
  url: string;
63
68
  status: number;
64
69
  duration_ms: number;
65
70
  }) => void): this;
66
- once(event: 'error', handler: (err: Error) => void): this;
67
- once(event: 'close', handler: () => void): this;
68
- off(event: 'listening', handler: (e: {
71
+ once(event: "error", handler: (err: Error) => void): this;
72
+ once(event: "close", handler: () => void): this;
73
+ off(event: "listening", handler: (e: {
69
74
  url: string;
70
75
  address: string | AddressInfo | null | undefined;
71
76
  }) => void): this;
72
- off(event: 'request', handler: (e: {
77
+ off(event: "request", handler: (e: {
73
78
  method: string;
74
79
  url: string;
75
80
  }) => void): this;
76
- off(event: 'response', handler: (e: {
81
+ off(event: "response", handler: (e: {
77
82
  method: string;
78
83
  url: string;
79
84
  status: number;
80
85
  duration_ms: number;
81
86
  }) => void): this;
82
- off(event: 'error', handler: (err: Error) => void): this;
83
- off(event: 'close', handler: () => void): this;
87
+ off(event: "error", handler: (err: Error) => void): this;
88
+ off(event: "close", handler: () => void): this;
84
89
  }
package/dist/index.js CHANGED
@@ -1,33 +1,50 @@
1
- import http from 'http';
2
- import https from 'https';
3
- import { createConsoleLogger, createRedactingLogger } from '@sisu-ai/core';
4
- import { EventEmitter } from 'events';
5
- export { matchRoute } from './router.js';
1
+ import http from "http";
2
+ import https from "https";
3
+ import { createConsoleLogger, createRedactingLogger } from "@sisu-ai/core";
4
+ import { EventEmitter } from "events";
5
+ export { matchRoute } from "./router.js";
6
6
  export class Server {
7
7
  constructor(agent, opts = {}) {
8
8
  this.agent = agent;
9
9
  this.opts = opts;
10
10
  this.emitter = new EventEmitter();
11
- this.basePath = opts.basePath ?? '/api';
12
- this.healthPath = opts.healthPath ?? '/health';
13
- this.createCtx = opts.createCtx ?? ((req, res) => ({ req, res }));
11
+ this.basePath = opts.basePath ?? "/api";
12
+ this.healthPath = opts.healthPath ?? "/health";
13
+ this.createCtx =
14
+ opts.createCtx ?? ((req, res) => ({ req, res }));
14
15
  }
15
16
  async handle(req, res) {
16
17
  // Set up server-level request logging (independent of ctx)
17
- const baseLogger = this.opts.logger ?? createConsoleLogger({ level: this.opts.logLevel, timestamps: true });
18
- const srvLogger = createRedactingLogger(baseLogger, { keys: this.opts.redactLogKeys });
18
+ const baseLogger = this.opts.logger ??
19
+ createConsoleLogger({
20
+ level: this.opts.logLevel,
21
+ timestamps: true,
22
+ });
23
+ const srvLogger = createRedactingLogger(baseLogger, {
24
+ keys: this.opts.redactLogKeys,
25
+ });
19
26
  const started = Date.now();
20
- const { method = 'GET', url = '' } = req;
21
- srvLogger.info?.('[server] request', { method, url });
22
- res.once?.('finish', () => {
27
+ const { method = "GET", url = "" } = req;
28
+ srvLogger.info?.("[server] request", { method, url });
29
+ res.once?.("finish", () => {
23
30
  const ms = Date.now() - started;
24
- srvLogger.info?.('[server] response', { method, url, status: res.statusCode, duration_ms: ms });
25
- this.emitter.emit('response', { method, url, status: res.statusCode, duration_ms: ms });
31
+ srvLogger.info?.("[server] response", {
32
+ method,
33
+ url,
34
+ status: res.statusCode,
35
+ duration_ms: ms,
36
+ });
37
+ this.emitter.emit("response", {
38
+ method,
39
+ url,
40
+ status: res.statusCode,
41
+ duration_ms: ms,
42
+ });
26
43
  });
27
- this.emitter.emit('request', { method, url });
44
+ this.emitter.emit("request", { method, url });
28
45
  if (this.healthPath && req.url === this.healthPath) {
29
46
  res.statusCode = 200;
30
- res.end('ok');
47
+ res.end("ok");
31
48
  return;
32
49
  }
33
50
  if (!req.url || !req.url.startsWith(this.basePath)) {
@@ -44,16 +61,24 @@ export class Server {
44
61
  // Mark this context as an HTTP transport envelope and capture minimal request meta
45
62
  const headers = req.headers || {};
46
63
  const httpMeta = {
47
- method: req.method || 'GET',
48
- url: req.url || '',
49
- ip: (req.socket && (req.socket.remoteAddress || '')) || '',
64
+ method: req.method || "GET",
65
+ url: req.url || "",
66
+ ip: (req.socket && (req.socket.remoteAddress || "")) || "",
50
67
  headers: {
51
- 'user-agent': typeof headers['user-agent'] === 'string' ? headers['user-agent'] : undefined,
52
- 'accept': typeof headers['accept'] === 'string' ? headers['accept'] : undefined,
53
- 'content-type': typeof headers['content-type'] === 'string' ? headers['content-type'] : undefined,
68
+ "user-agent": typeof headers["user-agent"] === "string"
69
+ ? headers["user-agent"]
70
+ : undefined,
71
+ accept: typeof headers["accept"] === "string" ? headers["accept"] : undefined,
72
+ "content-type": typeof headers["content-type"] === "string"
73
+ ? headers["content-type"]
74
+ : undefined,
54
75
  },
55
76
  };
56
- ctx.state = { ...(ctx.state ?? {}), _transport: { type: 'http' }, _http: httpMeta };
77
+ ctx.state = {
78
+ ...(ctx.state ?? {}),
79
+ _transport: { type: "http" },
80
+ _http: httpMeta,
81
+ };
57
82
  const handler = this.agent.handler();
58
83
  await handler(ctx);
59
84
  // Only synthesize a 404 when nothing has been written at all.
@@ -77,17 +102,19 @@ export class Server {
77
102
  else {
78
103
  this.server.listen(this.opts.port ?? 0, this.opts.host, this.opts.backlog, cb);
79
104
  }
80
- this.server.on('error', (err) => this.emitter.emit('error', err));
81
- this.server.on('close', () => this.emitter.emit('close'));
105
+ this.server.on("error", (err) => this.emitter.emit("error", err));
106
+ this.server.on("close", () => this.emitter.emit("close"));
82
107
  const printBanner = this.opts.logBanner !== false;
83
108
  if (printBanner) {
84
109
  const addr = this.server.address();
85
- let url = '';
86
- if (typeof addr === 'object' && addr && 'port' in addr) {
87
- const host = this.opts.host && this.opts.host !== '0.0.0.0' ? this.opts.host : 'localhost';
110
+ let url = "";
111
+ if (typeof addr === "object" && addr && "port" in addr) {
112
+ const host = this.opts.host && this.opts.host !== "0.0.0.0"
113
+ ? this.opts.host
114
+ : "localhost";
88
115
  url = `http://${host}:${addr.port}`;
89
116
  }
90
- else if (typeof addr === 'string') {
117
+ else if (typeof addr === "string") {
91
118
  url = addr;
92
119
  }
93
120
  if (url)
@@ -97,16 +124,19 @@ export class Server {
97
124
  if (this.basePath)
98
125
  console.log(`[server] basePath: ${this.basePath}`);
99
126
  if (this.opts.bannerEndpoints?.length) {
100
- console.log('[server] endpoints:');
127
+ console.log("[server] endpoints:");
101
128
  for (const ep of this.opts.bannerEndpoints)
102
129
  console.log(` ${ep}`);
103
130
  }
104
- this.emitter.emit('listening', { url, address: addr });
131
+ this.emitter.emit("listening", {
132
+ url,
133
+ address: addr,
134
+ });
105
135
  }
106
136
  return this.server;
107
137
  }
108
138
  attach(server) {
109
- server.on('request', this.listener());
139
+ server.on("request", this.listener());
110
140
  this.server = server;
111
141
  }
112
142
  close(cb) {
@@ -115,7 +145,16 @@ export class Server {
115
145
  address() {
116
146
  return this.server?.address();
117
147
  }
118
- on(event, handler) { this.emitter.on(event, handler); return this; }
119
- once(event, handler) { this.emitter.once(event, handler); return this; }
120
- off(event, handler) { this.emitter.off(event, handler); return this; }
148
+ on(event, handler) {
149
+ this.emitter.on(event, handler);
150
+ return this;
151
+ }
152
+ once(event, handler) {
153
+ this.emitter.once(event, handler);
154
+ return this;
155
+ }
156
+ off(event, handler) {
157
+ this.emitter.off(event, handler);
158
+ return this;
159
+ }
121
160
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sisu-ai/server",
3
- "version": "7.0.1",
3
+ "version": "7.0.2",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",