@dunx/http 3.6.0 → 3.8.0

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.
Files changed (40) hide show
  1. package/README.md +9 -0
  2. package/dist/chunk-08k9vq31.js +94 -0
  3. package/dist/{chunk-p9hdmkm6.js → chunk-1jt27yka.js} +8 -83
  4. package/dist/chunk-3eecdh6d.js +160 -0
  5. package/dist/chunk-cx4btdwe.js +56 -0
  6. package/dist/client/service.d.ts +13 -10
  7. package/dist/client/sse.d.ts +22 -8
  8. package/dist/client.d.ts +2 -0
  9. package/dist/client.js +72 -20
  10. package/dist/connect/middleware.d.ts +26 -0
  11. package/dist/connect/module.d.ts +29 -0
  12. package/dist/connect/options.d.ts +63 -0
  13. package/dist/connect/registry.d.ts +47 -0
  14. package/dist/connect.d.ts +12 -0
  15. package/dist/connect.js +213 -0
  16. package/dist/index.d.ts +4 -1
  17. package/dist/index.js +312 -189
  18. package/dist/internal.d.ts +8 -10
  19. package/dist/internal.js +7 -3
  20. package/dist/route/claims.d.ts +11 -0
  21. package/dist/route/metadata.d.ts +11 -0
  22. package/dist/route/prefix.d.ts +6 -0
  23. package/dist/server/application.d.ts +1 -1
  24. package/dist/server/binding.d.ts +4 -2
  25. package/dist/server/claimed-routes.d.ts +15 -0
  26. package/dist/server/cors.d.ts +2 -2
  27. package/dist/server/metrics.d.ts +2 -0
  28. package/dist/server/middleware.d.ts +19 -2
  29. package/dist/server/options-provider.d.ts +3 -0
  30. package/dist/server/options.d.ts +8 -0
  31. package/dist/server/routes.d.ts +7 -2
  32. package/dist/server/trace-context.d.ts +9 -11
  33. package/dist/sse/decorators.d.ts +28 -0
  34. package/dist/sse/event.d.ts +20 -0
  35. package/dist/sse/stream.d.ts +38 -0
  36. package/dist/static/files.d.ts +7 -0
  37. package/dist/static/options.d.ts +2 -2
  38. package/dist/throttle/guard.d.ts +3 -1
  39. package/package.json +19 -2
  40. package/dist/chunk-gmtwad7f.js +0 -71
package/dist/client.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  TRACEPARENT_HEADER2,
7
7
  TRACESTATE_HEADER2,
8
8
  TraceContext2
9
- } from "./chunk-gmtwad7f.js";
9
+ } from "./chunk-cx4btdwe.js";
10
10
 
11
11
  // src/client/errors.ts
12
12
  import { AppError } from "@dunx/core";
@@ -159,28 +159,78 @@ var readBody = async (response) => {
159
159
  };
160
160
 
161
161
  // src/client/sse.ts
162
- async function* sseData(body) {
162
+ var LINE = /\r\n|\r|\n/;
163
+ var split = (line) => {
164
+ const colon = line.indexOf(":");
165
+ if (colon === -1)
166
+ return [line, ""];
167
+ const value = line.slice(colon + 1);
168
+ return [line.slice(0, colon), value.startsWith(" ") ? value.slice(1) : value];
169
+ };
170
+ async function* sseMessages(body) {
163
171
  const decoder = new TextDecoder;
164
172
  let buffer = "";
165
- for await (const chunk of body) {
166
- buffer += decoder.decode(chunk, { stream: true });
167
- let newline = buffer.indexOf(`
168
- `);
169
- while (newline !== -1) {
170
- const line = buffer.slice(0, newline).trim();
171
- buffer = buffer.slice(newline + 1);
172
- newline = buffer.indexOf(`
173
+ let data = [];
174
+ let event;
175
+ let id;
176
+ let retry;
177
+ const reader = body.getReader();
178
+ let done = false;
179
+ try {
180
+ for (;; ) {
181
+ let end = LINE.exec(buffer);
182
+ while (end !== null) {
183
+ if (!done && end[0] === "\r" && end.index + 1 === buffer.length)
184
+ break;
185
+ const line = buffer.slice(0, end.index);
186
+ buffer = buffer.slice(end.index + end[0].length);
187
+ end = LINE.exec(buffer);
188
+ if (line === "") {
189
+ const seen = data.length > 0;
190
+ const payload = data.join(`
173
191
  `);
174
- if (!line.startsWith("data:"))
175
- continue;
176
- const data = line.slice(5).trim();
177
- if (data === "[DONE]")
192
+ data = [];
193
+ if (!seen) {
194
+ event = undefined;
195
+ continue;
196
+ }
197
+ if (payload === "[DONE]")
198
+ return;
199
+ yield {
200
+ data: payload,
201
+ ...event === undefined ? {} : { event },
202
+ ...id === undefined ? {} : { id },
203
+ ...retry === undefined ? {} : { retry }
204
+ };
205
+ event = undefined;
206
+ continue;
207
+ }
208
+ if (line.startsWith(":"))
209
+ continue;
210
+ const [field, value] = split(line);
211
+ if (field === "data")
212
+ data.push(value);
213
+ else if (field === "event")
214
+ event = value;
215
+ else if (field === "id" && !value.includes("\x00"))
216
+ id = value;
217
+ else if (field === "retry" && /^\d+$/.test(value))
218
+ retry = Number(value);
219
+ }
220
+ if (done)
178
221
  return;
179
- yield data;
222
+ const next = await reader.read();
223
+ if (next.done) {
224
+ buffer += decoder.decode();
225
+ done = true;
226
+ continue;
227
+ }
228
+ buffer += decoder.decode(next.value, { stream: true });
180
229
  }
230
+ } finally {
231
+ reader.releaseLock();
181
232
  }
182
233
  }
183
-
184
234
  class ConnectDeadline {
185
235
  #controller = new AbortController;
186
236
  #timer;
@@ -297,6 +347,10 @@ class HttpService extends UrlHelper {
297
347
  });
298
348
  }
299
349
  async* streamSse(config) {
350
+ for await (const message of this.streamSseEvents(config))
351
+ yield message.data;
352
+ }
353
+ async* streamSseEvents(config) {
300
354
  const url = this.urlFor(config);
301
355
  const method = config.method ?? "POST";
302
356
  const startedAt = Date.now();
@@ -304,9 +358,7 @@ class HttpService extends UrlHelper {
304
358
  const deadline = new ConnectDeadline(config.timeoutMs ?? this.options.timeoutMs, url.href);
305
359
  let response;
306
360
  try {
307
- const policy = this.policyFor({ ...config, timeoutMs: 0 }, {
308
- maxRetries: 0
309
- });
361
+ const policy = this.policyFor({ ...config, timeoutMs: 0 }, { maxRetries: 0 });
310
362
  response = await policy.run((signal) => this.send({ ...config, method }, url, body, serialised, AbortSignal.any([signal, deadline.signal]), "text/event-stream"));
311
363
  } finally {
312
364
  deadline.clear();
@@ -317,7 +369,7 @@ class HttpService extends UrlHelper {
317
369
  }), { method, url: url.href, headers: response.headers });
318
370
  }
319
371
  try {
320
- yield* sseData(response.body);
372
+ yield* sseMessages(response.body);
321
373
  } finally {
322
374
  this.logger.debug(`SSE ${method} ${url.href} closed`, {
323
375
  elapsedMs: Date.now() - startedAt
@@ -0,0 +1,26 @@
1
+ import type { BunRequest } from 'bun';
2
+ import type { RouteContext } from '../server/context.js';
3
+ import type { ClaimsPaths, Middleware, Next } from '../server/middleware.js';
4
+ import { ConnectRegistry } from './registry.js';
5
+ /**
6
+ * Serves every registered RPC as ordinary middleware, so request logging, CORS,
7
+ * a guard and the dashboard apply to a call as they apply to a route. Register
8
+ * it with `app.use`, since position in the chain decides what covers it.
9
+ *
10
+ * RPC paths are in no route table, so they reach the `fetch` fallback, where
11
+ * `ctx.get(UNMATCHED)` is true and `ctx.path` is already parsed. Reading it
12
+ * first is what leaves a matched route paying nothing. Anything outside the
13
+ * registered paths falls through untouched.
14
+ *
15
+ * `ThrottleGuard` covers an RPC: its early return is for an unmatched path
16
+ * nobody claims, and a claimed path is served. See docs/guide/27-rpc.md.
17
+ */
18
+ export declare class ConnectMiddleware implements Middleware, ClaimsPaths {
19
+ #private;
20
+ constructor(registry: ConnectRegistry);
21
+ /** Every mounted RPC path, so a controller cannot shadow one unnoticed. */
22
+ claimedPaths(): readonly string[];
23
+ /** Connect and gRPC-Web both POST. Connect's GET form is not served here. */
24
+ claimedMethods(): readonly string[];
25
+ handle(req: BunRequest, ctx: RouteContext, next: Next): Promise<Response>;
26
+ }
@@ -0,0 +1,29 @@
1
+ import { type AsyncModuleConfig, type Deps, type DynamicModule } from '@dunx/core';
2
+ import { type ConnectOptionsInit, type ConnectServiceRegistration } from './options.js';
3
+ /** Everything `forRoot` takes except the services, which `forRootAsync` needs
4
+ * synchronously, and `imports`, which `AsyncModuleConfig` already carries. */
5
+ export type ConnectSettings = Omit<ConnectOptionsInit, 'services' | 'imports'>;
6
+ /**
7
+ * Serves protobuf services over Connect and gRPC-Web on the port `Bun.serve`
8
+ * already has. See `docs/guide/27-rpc.md`.
9
+ *
10
+ * ```ts
11
+ * ConnectModule.forRoot({
12
+ * services: [connectService(GreetService, GreetRpc)],
13
+ * // What GreetRpc injects: this module is its own scope.
14
+ * imports: [GreetingsModule],
15
+ * });
16
+ * ```
17
+ *
18
+ * It binds `ConnectMiddleware` and does not register it - position in the chain
19
+ * decides which guards cover an RPC, so the app calls `app.use`.
20
+ */
21
+ export declare class ConnectModule {
22
+ static forRoot(init: ConnectOptionsInit): DynamicModule;
23
+ /**
24
+ * `forRoot` with everything but the services behind a factory, so the prefix
25
+ * or the read limits can come off `ConfigService`. The services are positional
26
+ * because their classes have to be providers before any factory runs.
27
+ */
28
+ static forRootAsync<const D extends Deps>(services: readonly ConnectServiceRegistration[], config: AsyncModuleConfig<ConnectSettings, D>): DynamicModule;
29
+ }
@@ -0,0 +1,63 @@
1
+ import type { DescService } from '@bufbuild/protobuf';
2
+ import type { ConnectRouterOptions, ServiceImpl } from '@connectrpc/connect';
3
+ import { type Ctor, type ModuleRef } from '@dunx/core';
4
+ /**
5
+ * Everything `createConnectRouter` takes except the protocol switches and
6
+ * `shutdownSignal`, which the container owns. `interceptors`, `contextValues`,
7
+ * `requestGate`, `jsonOptions` and the rest pass through untouched.
8
+ */
9
+ export type ConnectRouterSettings = Omit<ConnectRouterOptions, 'connect' | 'grpc' | 'grpcWeb' | 'shutdownSignal'>;
10
+ /** One protobuf service and the class implementing it. */
11
+ export interface ConnectServiceRegistration {
12
+ readonly service: DescService;
13
+ readonly useClass: Ctor<object>;
14
+ }
15
+ /**
16
+ * Pairs a generated `DescService` with the class serving it, checking at compile
17
+ * time that the class has a method per RPC. A generic function rather than an
18
+ * object literal, which would lose the link between the two arguments.
19
+ */
20
+ export declare const connectService: <T extends DescService>(service: T, useClass: Ctor<ServiceImpl<T>>) => ConnectServiceRegistration;
21
+ export interface ConnectOptionsInit extends ConnectRouterSettings {
22
+ /** The services to serve, each paired with its implementation class. */
23
+ readonly services: readonly ConnectServiceRegistration[];
24
+ /**
25
+ * Modules whose exports the implementation classes may inject. This module is
26
+ * its own scope and the classes are constructed in it, so a provider they need
27
+ * has to be exported by a module named here - importing it alongside does not
28
+ * reach them.
29
+ */
30
+ readonly imports?: readonly ModuleRef[];
31
+ /**
32
+ * Mounted in front of every RPC path, empty by default, which leaves them at
33
+ * `/{package}.{Service}/{Method}`. `setGlobalPrefix` does not move them: that
34
+ * prefixes discovered routes, and these are matched by a middleware.
35
+ */
36
+ readonly prefix?: string;
37
+ /** Connect, which a `curl` POST of JSON also speaks. @default true */
38
+ readonly connect?: boolean;
39
+ /** gRPC-Web, which browsers and `connect-go` speak. @default true */
40
+ readonly grpcWeb?: boolean;
41
+ /**
42
+ * Seconds a **streaming** RPC may idle before `Bun.serve` severs it. `0` lifts
43
+ * the deadline for the whole call, which is the default because a gap between
44
+ * messages is the protocol rather than a symptom.
45
+ *
46
+ * Worth setting on a public mount: `ThrottleGuard` limits the calls, and this
47
+ * limits how long one that is already streaming may idle.
48
+ *
49
+ * @default 0
50
+ */
51
+ readonly streamTimeout?: number;
52
+ }
53
+ /** A class rather than an interface, so it is a runtime value the transform can
54
+ * record as a constructor parameter type. */
55
+ export declare class ConnectOptions {
56
+ readonly services: readonly ConnectServiceRegistration[];
57
+ readonly prefix: string;
58
+ readonly connect: boolean;
59
+ readonly grpcWeb: boolean;
60
+ readonly streamTimeout: number;
61
+ readonly router: ConnectRouterSettings;
62
+ constructor(init: ConnectOptionsInit);
63
+ }
@@ -0,0 +1,47 @@
1
+ import { ConnectOptions } from './options.js';
2
+ /** What `createFetchHandler` returns: the `Bun.serve` signature exactly. */
3
+ export type ConnectHandler = (req: Request) => Promise<Response>;
4
+ /** One mounted RPC. */
5
+ export interface ConnectMethodInfo {
6
+ /** The path it answers, including {@link ConnectOptions.prefix}. */
7
+ readonly path: string;
8
+ /** e.g. `greet.v1.GreetService`. */
9
+ readonly service: string;
10
+ /** e.g. `Say`. */
11
+ readonly method: string;
12
+ /** `unary`, `server_streaming`, `client_streaming` or `bidi_streaming`. */
13
+ readonly kind: string;
14
+ /** e.g. `['grpc-web', 'connect']`. */
15
+ readonly protocols: readonly string[];
16
+ }
17
+ /** What the middleware needs per path, in one lookup. */
18
+ export interface ConnectRoute {
19
+ readonly handle: ConnectHandler;
20
+ /** Anything but `unary`, so the gap between messages is the protocol. */
21
+ readonly streaming: boolean;
22
+ }
23
+ /**
24
+ * One fetch handler per RPC, built at boot into a path map, so a request costs a
25
+ * `Map.get`. Connect's own router picks the protocol off the content type.
26
+ *
27
+ * `grpc` is off and cannot be turned on: it carries `grpc-status` in an HTTP
28
+ * trailer and `Bun.serve` sends none, so advertising it would answer with a
29
+ * status no client reads. Probed on Bun 1.4.2.
30
+ */
31
+ export declare class ConnectRegistry {
32
+ #private;
33
+ /** Every mounted path, in registration order. */
34
+ get paths(): readonly string[];
35
+ /** Seconds a streaming call may idle; `0` lifts the deadline. */
36
+ readonly streamTimeout: number;
37
+ constructor(options: ConnectOptions, implementations: readonly object[]);
38
+ /** In registration order. */
39
+ get methods(): readonly ConnectMethodInfo[];
40
+ routeFor(path: string): ConnectRoute | undefined;
41
+ /**
42
+ * Aborts the signal every in-flight handler holds, so a long-running
43
+ * implementation gets its cue. It does not close an open response stream -
44
+ * the socket closing does. Measured on `@connectrpc/connect` 2.2.0.
45
+ */
46
+ onShutdown(): void;
47
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * `@dunx/http/connect` - protobuf services over Connect and gRPC-Web, mounted as
3
+ * middleware. `@connectrpc/connect` and `@bufbuild/protobuf` are optional peers,
4
+ * and importing `@dunx/http` does not load any of this.
5
+ *
6
+ * Native gRPC is not here: `grpc-status` travels in an HTTP trailer and
7
+ * `Bun.serve` sends none. See `internal/notes/research/rpc.md`.
8
+ */
9
+ export { ConnectMiddleware } from './connect/middleware.js';
10
+ export { ConnectModule, type ConnectSettings } from './connect/module.js';
11
+ export { connectService, ConnectOptions, type ConnectOptionsInit, type ConnectRouterSettings, type ConnectServiceRegistration, } from './connect/options.js';
12
+ export { ConnectRegistry, type ConnectHandler, type ConnectMethodInfo, type ConnectRoute, } from './connect/registry.js';
@@ -0,0 +1,213 @@
1
+ // @bun
2
+ import {
3
+ UNMATCHED2,
4
+ REQUEST_SERVER,
5
+ normalizePrefix
6
+ } from "./chunk-1jt27yka.js";
7
+ import {
8
+ HttpStatusCode2
9
+ } from "./chunk-bg0dr54z.js";
10
+ import {
11
+ __decoratorStart,
12
+ __decoratorMetadata,
13
+ __runInitializers,
14
+ __decorateElement,
15
+ PathClaims
16
+ } from "./chunk-08k9vq31.js";
17
+
18
+ // src/connect/registry.ts
19
+ import { AppError as AppError2 } from "@dunx/core";
20
+ import {
21
+ createConnectRouter
22
+ } from "@connectrpc/connect";
23
+ import { createFetchHandler } from "@connectrpc/connect/protocol";
24
+
25
+ // src/connect/options.ts
26
+ import { AppError } from "@dunx/core";
27
+ var connectService = (service, useClass) => ({ service, useClass });
28
+
29
+ class ConnectOptions {
30
+ services;
31
+ prefix;
32
+ connect;
33
+ grpcWeb;
34
+ streamTimeout;
35
+ router;
36
+ constructor(init) {
37
+ const {
38
+ services,
39
+ prefix,
40
+ connect,
41
+ grpcWeb,
42
+ streamTimeout,
43
+ imports: _imports,
44
+ ...router
45
+ } = init;
46
+ this.services = services;
47
+ const mounted = normalizePrefix(prefix ?? "");
48
+ this.prefix = mounted === "/" ? "" : mounted;
49
+ this.connect = connect ?? true;
50
+ this.grpcWeb = grpcWeb ?? true;
51
+ this.streamTimeout = streamTimeout ?? 0;
52
+ if (!Number.isFinite(this.streamTimeout) || this.streamTimeout < 0) {
53
+ throw new AppError(`ConnectModule streamTimeout must be a non-negative number of seconds, got ${String(streamTimeout)}.`);
54
+ }
55
+ this.router = router;
56
+ if (!this.connect && !this.grpcWeb) {
57
+ throw new AppError("ConnectModule needs at least one protocol, and both connect and " + "grpcWeb are false. Native gRPC is not a third option here: it " + "carries grpc-status in an HTTP trailer and Bun.serve sends none.");
58
+ }
59
+ if (services.length === 0) {
60
+ throw new AppError("ConnectModule.forRoot was given no services. Pass at least one " + "connectService(Desc, Impl), or drop the module.");
61
+ }
62
+ }
63
+ }
64
+ Object.defineProperty(ConnectOptions, Symbol.for("dunx.deps"), { value: () => [{ unresolved: "init: ConnectOptionsInit" }] });
65
+
66
+ // src/connect/registry.ts
67
+ class ConnectRegistry {
68
+ #routes = new Map;
69
+ get paths() {
70
+ return [...this.#routes.keys()];
71
+ }
72
+ streamTimeout;
73
+ #methods = [];
74
+ #stopping = new AbortController;
75
+ constructor(options, implementations) {
76
+ this.streamTimeout = options.streamTimeout;
77
+ const router = createConnectRouter({
78
+ ...options.router,
79
+ connect: options.connect,
80
+ grpcWeb: options.grpcWeb,
81
+ grpc: false,
82
+ shutdownSignal: this.#stopping.signal
83
+ });
84
+ options.services.forEach((registration, index) => {
85
+ const implementation = implementations[index];
86
+ if (implementation === undefined) {
87
+ throw new AppError2(`No instance was resolved for ${registration.useClass.name}, which ` + `serves ${registration.service.typeName}.`);
88
+ }
89
+ router.service(registration.service, implementation);
90
+ });
91
+ const claims = new PathClaims("RPC", "Register each service once, or give one its own prefix.");
92
+ for (const handler of router.handlers) {
93
+ const path = `${options.prefix}${handler.requestPath}`;
94
+ const rpc = `${handler.service.typeName}.${handler.method.name}`;
95
+ claims.claim(path, rpc);
96
+ this.#routes.set(path, {
97
+ handle: createFetchHandler(handler),
98
+ streaming: handler.method.methodKind !== "unary"
99
+ });
100
+ this.#methods.push({
101
+ path,
102
+ service: handler.service.typeName,
103
+ method: handler.method.name,
104
+ kind: handler.method.methodKind,
105
+ protocols: handler.protocolNames
106
+ });
107
+ }
108
+ }
109
+ get methods() {
110
+ return this.#methods;
111
+ }
112
+ routeFor(path) {
113
+ return this.#routes.get(path);
114
+ }
115
+ onShutdown() {
116
+ this.#stopping.abort();
117
+ }
118
+ }
119
+ Object.defineProperty(ConnectRegistry, Symbol.for("dunx.deps"), { value: () => [ConnectOptions, { unresolved: "implementations: readonly object[]" }] });
120
+
121
+ // src/connect/middleware.ts
122
+ var NATIVE_GRPC = /^\s*application\/grpc\s*(?:[;+]|$)/i;
123
+ var grpcUnsupported = () => Response.json({
124
+ code: "unimplemented",
125
+ message: "This endpoint serves Connect and gRPC-Web, not gRPC. gRPC carries " + "grpc-status in an HTTP trailer and Bun.serve sends no trailers, so a " + "gRPC client would read every call as a protocol error. Use a Connect " + "or gRPC-Web transport, or put a proxy in front that translates."
126
+ }, { status: HttpStatusCode2.UNSUPPORTED_MEDIA_TYPE });
127
+
128
+ class ConnectMiddleware {
129
+ #registry;
130
+ constructor(registry) {
131
+ this.#registry = registry;
132
+ }
133
+ claimedPaths() {
134
+ return this.#registry.paths;
135
+ }
136
+ claimedMethods() {
137
+ return ["POST"];
138
+ }
139
+ handle(req, ctx, next) {
140
+ if (ctx.get(UNMATCHED2) !== true)
141
+ return next();
142
+ const route = this.#registry.routeFor(ctx.path);
143
+ if (route === undefined)
144
+ return next();
145
+ const contentType = req.headers.get("content-type");
146
+ if (contentType !== null && NATIVE_GRPC.test(contentType)) {
147
+ return Promise.resolve(grpcUnsupported());
148
+ }
149
+ if (route.streaming) {
150
+ ctx.get(REQUEST_SERVER)?.timeout(req, this.#registry.streamTimeout);
151
+ }
152
+ return route.handle(req);
153
+ }
154
+ }
155
+ Object.defineProperty(ConnectMiddleware, Symbol.for("dunx.deps"), { value: () => [ConnectRegistry] });
156
+ // src/connect/module.ts
157
+ import {
158
+ Module,
159
+ provide
160
+ } from "@dunx/core";
161
+ var build = (services, options, imports) => {
162
+ const implementations = services.map((registration) => registration.useClass);
163
+ return {
164
+ module: ConnectModule,
165
+ imports,
166
+ exports: [ConnectOptions, ConnectRegistry, ConnectMiddleware],
167
+ providers: [
168
+ ...implementations,
169
+ options,
170
+ provide(ConnectRegistry, {
171
+ useFactory: (...deps) => {
172
+ const [resolved, ...instances] = deps;
173
+ return new ConnectRegistry(resolved, instances);
174
+ },
175
+ inject: [ConnectOptions, ...implementations]
176
+ }),
177
+ provide(ConnectMiddleware, {
178
+ useFactory: (registry) => new ConnectMiddleware(registry),
179
+ inject: [ConnectRegistry]
180
+ })
181
+ ]
182
+ };
183
+ };
184
+ var _dec = [
185
+ Module({})
186
+ ];
187
+ var _init = __decoratorStart(undefined);
188
+
189
+ class ConnectModule {
190
+ static forRoot(init) {
191
+ return build(init.services, provide(ConnectOptions, { useValue: new ConnectOptions(init) }), init.imports ?? []);
192
+ }
193
+ static forRootAsync(services, config) {
194
+ return build(services, provide(ConnectOptions, {
195
+ useFactory: async (...deps) => new ConnectOptions({
196
+ ...await config.useFactory(...deps),
197
+ services
198
+ }),
199
+ inject: config.inject ?? []
200
+ }), config.imports ?? []);
201
+ }
202
+ }
203
+ ConnectModule = __decorateElement(_init, 0, "ConnectModule", _dec, ConnectModule);
204
+ __runInitializers(_init, 1, ConnectModule);
205
+ __decoratorMetadata(_init, ConnectModule);
206
+ let _ConnectModule = ConnectModule;
207
+ export {
208
+ ConnectMiddleware,
209
+ ConnectModule,
210
+ ConnectOptions,
211
+ ConnectRegistry,
212
+ connectService
213
+ };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { Controller, Delete, Get, Patch, Post, Put, } from './route/decorators.js';
2
2
  export type { HttpMethod, RoutePath } from './route/marker.js';
3
- export { ApiHidden, HIDDEN, meta, metaKey, metaOf, mergeMeta, Public, PUBLIC, Roles, ROLES, UNMATCHED, UseGuards, type MetaKey, type MetaRecord, } from './route/metadata.js';
3
+ export { ApiHidden, HIDDEN, meta, metaKey, metaOf, mergeMeta, Public, PUBLIC, Roles, ROLES, STREAMS, UNMATCHED, UseGuards, type MetaKey, type MetaRecord, } from './route/metadata.js';
4
4
  export type { InferOutput, Input, JsonSchema, ResponseMap, Returns, RouteInput, RouteSchemas, StandardSchemaIssue, StandardSchemaResult, StandardSchemaV1, } from './route/schema.js';
5
5
  export { ClientAddress } from './server/client-address.js';
6
6
  export type { RouteContext } from './server/context.js';
@@ -19,6 +19,9 @@ export { StaticOptions, type StaticOptionsInit } from './static/options.js';
19
19
  export { Compression } from './compression/compression.js';
20
20
  export { CompressionModule } from './compression/module.js';
21
21
  export { CompressionEncoding, CompressionOptions, type CompressionOptionsInit, } from './compression/options.js';
22
+ export { Sse, type SseInput, type SseResult, type SseSchemas, } from './sse/decorators.js';
23
+ export type { SseEvent } from './sse/event.js';
24
+ export { SseStream, type SseStreamOptions } from './sse/stream.js';
22
25
  export { SKIP_THROTTLE, SkipThrottle, THROTTLE, Throttle, type ThrottleLimit, } from './throttle/decorators.js';
23
26
  export { ThrottleGuard } from './throttle/guard.js';
24
27
  export { ThrottleModule } from './throttle/module.js';