@toapi/server 1.3.4 → 1.4.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.
@@ -1 +1 @@
1
- {"version":3,"file":"create-request-handler.d.ts","sourceRoot":"","sources":["../src/create-request-handler.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAK9C,UAAU,OAAO;IACf,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAWD,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,aAAa,CAAC,MAAM,CAAC,QAAQ,EAAE,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,EAC7D,OAAO,GAAE,OAAY,SAmBF,OAAO,uBAqL3B;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOrD;AAuGD,wBAAsB,cAAc,CAAC,IAAI,EACvC,OAAO,EAAE,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,EACrC,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,mDAOnC"}
1
+ {"version":3,"file":"create-request-handler.d.ts","sourceRoot":"","sources":["../src/create-request-handler.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAK9C,UAAU,OAAO;IACf,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAWD,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,aAAa,CAAC,MAAM,CAAC,QAAQ,EAAE,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,EAC7D,OAAO,GAAE,OAAY,SAmBF,OAAO,uBAuL3B;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOrD;AAuGD,wBAAsB,cAAc,CAAC,IAAI,EACvC,OAAO,EAAE,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,EACrC,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,mDAOnC"}
@@ -28,6 +28,8 @@ export function createRequestHandler(api, options = {}) {
28
28
  if (url.pathname === `${basePath}${INVALIDATIONS_ROUTE}`) {
29
29
  return streamRevalidatedTags({
30
30
  cache: api.cache,
31
+ config: api.revalidationStreamConfig,
32
+ req,
31
33
  });
32
34
  }
33
35
  if (api.oas && url.pathname === `${basePath}${OPENAPI_ROUTE}`) {
@@ -3,6 +3,7 @@ import type { Logger } from "@toapi/common";
3
3
  import type { Path as BasePath, StrictParams } from "@toapi/common";
4
4
  import type { Route } from "@toapi/common";
5
5
  import { type Cache } from "./cache.js";
6
+ import type { RevalidationStreamConfig } from "./revalidation-stream.js";
6
7
  export interface OasInfo {
7
8
  title: string;
8
9
  version: string;
@@ -11,6 +12,7 @@ interface Options {
11
12
  cache?: Cache;
12
13
  oas?: OasInfo;
13
14
  logger?: Logger;
15
+ revalidationStream?: RevalidationStreamConfig;
14
16
  }
15
17
  export declare function defineApi(options?: Options): ApiDefinition<{}>;
16
18
  export declare class ApiDefinition<Routes extends Record<BasePath, unknown>> {
@@ -18,7 +20,8 @@ export declare class ApiDefinition<Routes extends Record<BasePath, unknown>> {
18
20
  cache: Cache;
19
21
  oas?: OasInfo | undefined;
20
22
  logger?: Logger | undefined;
21
- constructor(routes: Routes, cache: Cache, oas?: OasInfo | undefined, logger?: Logger | undefined);
23
+ revalidationStreamConfig?: RevalidationStreamConfig | undefined;
24
+ constructor(routes: Routes, cache: Cache, oas?: OasInfo | undefined, logger?: Logger | undefined, revalidationStreamConfig?: RevalidationStreamConfig | undefined);
22
25
  invalidate(tags: string[]): Promise<void>;
23
26
  route<Path extends BasePath, GetResponse = never, GetQuery extends Record<string, unknown> = never, PostResponse = never, PostQuery extends Record<string, unknown> = never, PostBody = never, DeleteResponse = never, DeleteQuery extends Record<string, unknown> = never, PutResponse = never, PutQuery extends Record<string, unknown> = never, PutBody = never, PatchResponse = never, PatchQuery extends Record<string, unknown> = never, PatchBody = never>(path: Path, route: MaybePromise<Route<StrictParams<Path>, GetResponse, GetQuery, PostResponse, PostQuery, PostBody, DeleteResponse, DeleteQuery, PutResponse, PutQuery, PutBody, PatchResponse, PatchQuery, PatchBody>>): ApiDefinition<Routes & { [path in Path]: MaybePromise<Route<StrictParams<Path>, GetResponse, GetQuery, PostResponse, PostQuery, PostBody, DeleteResponse, DeleteQuery, PutResponse, PutQuery, PutBody, PatchResponse, PatchQuery, PatchBody>>; }>;
24
27
  }
@@ -1 +1 @@
1
- {"version":3,"file":"define-api.d.ts","sourceRoot":"","sources":["../src/define-api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,IAAI,IAAI,QAAQ,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,KAAK,KAAK,EAAU,MAAM,YAAY,CAAC;AAEhD,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,OAAO;IACf,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,SAAS,CAAC,OAAO,GAAE,OAAY,qBAE9C;AAED,qBAAa,aAAa,CAAC,MAAM,SAAS,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC;IAExD,MAAM,EAAE,MAAM;IACd,KAAK,EAAE,KAAK;IACZ,GAAG,CAAC,EAAE,OAAO;IACb,MAAM,CAAC,EAAE,MAAM;IAJxB,YACS,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,KAAK,EACZ,GAAG,CAAC,EAAE,OAAO,YAAA,EACb,MAAM,CAAC,EAAE,MAAM,YAAA,EACpB;IAEE,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,iBAE9B;IAED,KAAK,CACH,IAAI,SAAS,QAAQ,EACrB,WAAW,GAAG,KAAK,EACnB,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,EAChD,YAAY,GAAG,KAAK,EACpB,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,EACjD,QAAQ,GAAG,KAAK,EAChB,cAAc,GAAG,KAAK,EACtB,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,EACnD,WAAW,GAAG,KAAK,EACnB,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,EAChD,OAAO,GAAG,KAAK,EACf,aAAa,GAAG,KAAK,EACrB,UAAU,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,EAClD,SAAS,GAAG,KAAK,EAEjB,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,YAAY,CACjB,KAAK,CACH,YAAY,CAAC,IAAI,CAAC,EAClB,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,cAAc,EACd,WAAW,EACX,WAAW,EACX,QAAQ,EACR,OAAO,EACP,aAAa,EACb,UAAU,EACV,SAAS,CACV,CACF,GAGyB,aAAa,CACrC,MAAM,GAAG,GACN,IAAI,IAAI,IAAI,GAAG,YAAY,CAC1B,KAAK,CACH,YAAY,CAAC,IAAI,CAAC,EAClB,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,cAAc,EACd,WAAW,EACX,WAAW,EACX,QAAQ,EACR,OAAO,EACP,aAAa,EACb,UAAU,EACV,SAAS,CACV,CACF,GACF,CACF,CACF;CACF"}
1
+ {"version":3,"file":"define-api.d.ts","sourceRoot":"","sources":["../src/define-api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,IAAI,IAAI,QAAQ,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,KAAK,KAAK,EAAU,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAEzE,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,OAAO;IACf,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kBAAkB,CAAC,EAAE,wBAAwB,CAAC;CAC/C;AAED,wBAAgB,SAAS,CAAC,OAAO,GAAE,OAAY,qBAQ9C;AAED,qBAAa,aAAa,CAAC,MAAM,SAAS,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC;IAExD,MAAM,EAAE,MAAM;IACd,KAAK,EAAE,KAAK;IACZ,GAAG,CAAC,EAAE,OAAO;IACb,MAAM,CAAC,EAAE,MAAM;IACf,wBAAwB,CAAC,EAAE,wBAAwB;IAL5D,YACS,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,KAAK,EACZ,GAAG,CAAC,EAAE,OAAO,YAAA,EACb,MAAM,CAAC,EAAE,MAAM,YAAA,EACf,wBAAwB,CAAC,EAAE,wBAAwB,YAAA,EACxD;IAEE,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,iBAE9B;IAED,KAAK,CACH,IAAI,SAAS,QAAQ,EACrB,WAAW,GAAG,KAAK,EACnB,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,EAChD,YAAY,GAAG,KAAK,EACpB,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,EACjD,QAAQ,GAAG,KAAK,EAChB,cAAc,GAAG,KAAK,EACtB,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,EACnD,WAAW,GAAG,KAAK,EACnB,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,EAChD,OAAO,GAAG,KAAK,EACf,aAAa,GAAG,KAAK,EACrB,UAAU,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,EAClD,SAAS,GAAG,KAAK,EAEjB,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,YAAY,CACjB,KAAK,CACH,YAAY,CAAC,IAAI,CAAC,EAClB,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,cAAc,EACd,WAAW,EACX,WAAW,EACX,QAAQ,EACR,OAAO,EACP,aAAa,EACb,UAAU,EACV,SAAS,CACV,CACF,GAGyB,aAAa,CACrC,MAAM,GAAG,GACN,IAAI,IAAI,IAAI,GAAG,YAAY,CAC1B,KAAK,CACH,YAAY,CAAC,IAAI,CAAC,EAClB,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,cAAc,EACd,WAAW,EACX,WAAW,EACX,QAAQ,EACR,OAAO,EACP,aAAa,EACb,UAAU,EACV,SAAS,CACV,CACF,GACF,CACF,CACF;CACF"}
@@ -1,17 +1,19 @@
1
1
  import { PubSub } from "./cache.js";
2
2
  export function defineApi(options = {}) {
3
- return new ApiDefinition({}, options?.cache ?? new PubSub(), options?.oas, options?.logger);
3
+ return new ApiDefinition({}, options?.cache ?? new PubSub(), options?.oas, options?.logger, options?.revalidationStream);
4
4
  }
5
5
  export class ApiDefinition {
6
6
  routes;
7
7
  cache;
8
8
  oas;
9
9
  logger;
10
- constructor(routes, cache, oas, logger) {
10
+ revalidationStreamConfig;
11
+ constructor(routes, cache, oas, logger, revalidationStreamConfig) {
11
12
  this.routes = routes;
12
13
  this.cache = cache;
13
14
  this.oas = oas;
14
15
  this.logger = logger;
16
+ this.revalidationStreamConfig = revalidationStreamConfig;
15
17
  }
16
18
  async invalidate(tags) {
17
19
  await this.cache.delete(tags);
@@ -1,7 +1,14 @@
1
1
  import type { Cache } from "./cache.js";
2
+ export interface RevalidationStreamConfig {
3
+ throttleTimeout?: number;
4
+ keepaliveInterval?: number;
5
+ filter?: (req: Request) => (tag: string) => boolean;
6
+ }
2
7
  interface Options {
3
8
  cache: Cache;
9
+ config?: RevalidationStreamConfig;
10
+ req: Request;
4
11
  }
5
- export declare function streamRevalidatedTags({ cache }: Options): Response;
12
+ export declare function streamRevalidatedTags({ cache, config, req }: Options): Response;
6
13
  export {};
7
14
  //# sourceMappingURL=revalidation-stream.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"revalidation-stream.d.ts","sourceRoot":"","sources":["../src/revalidation-stream.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAIxC,UAAU,OAAO;IACf,KAAK,EAAE,KAAK,CAAC;CACd;AAED,wBAAgB,qBAAqB,CAAC,EAAE,KAAK,EAAE,EAAE,OAAO,YA0CvD"}
1
+ {"version":3,"file":"revalidation-stream.d.ts","sourceRoot":"","sources":["../src/revalidation-stream.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAKxC,MAAM,WAAW,wBAAwB;IACvC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;CACrD;AAED,UAAU,OAAO;IACf,KAAK,EAAE,KAAK,CAAC;IACb,MAAM,CAAC,EAAE,wBAAwB,CAAC;IAClC,GAAG,EAAE,OAAO,CAAC;CACd;AAED,wBAAgB,qBAAqB,CAAC,EAAE,KAAK,EAAE,MAAW,EAAE,GAAG,EAAE,EAAE,OAAO,YAwEzE"}
@@ -1,11 +1,16 @@
1
- import { SESSION_COOKIE_NAME, TAGS_CONTENT_TYPE, } from "@toapi/common";
2
- const KEEPALIVE_INTERVAL = 10 * 1000;
3
- export function streamRevalidatedTags({ cache }) {
1
+ import { SESSION_COOKIE_NAME, TAGS_CONTENT_TYPE } from "@toapi/common";
2
+ const DEFAULT_KEEPALIVE_INTERVAL = 10 * 1000;
3
+ const DEFAULT_THROTTLE_TIMEOUT = 500;
4
+ export function streamRevalidatedTags({ cache, config = {}, req }) {
5
+ const { throttleTimeout = DEFAULT_THROTTLE_TIMEOUT, keepaliveInterval = DEFAULT_KEEPALIVE_INTERVAL, filter = () => () => true, } = config;
6
+ const filterTag = filter(req);
4
7
  const id = crypto.randomUUID();
5
8
  let interval = null;
9
+ let timeout = null;
6
10
  let unsubscribe = () => { };
7
11
  const stream = new ReadableStream({
8
12
  async start(controller) {
13
+ let queue = new Set();
9
14
  const textEncoder = new TextEncoder();
10
15
  // subscribe to tag invalidations
11
16
  unsubscribe = cache.subscribe((tags, meta) => {
@@ -15,19 +20,34 @@ export function streamRevalidatedTags({ cache }) {
15
20
  "clientId" in meta &&
16
21
  meta.clientId === id)
17
22
  return;
23
+ for (const tag of tags) {
24
+ if (filterTag(tag)) {
25
+ queue.add(tag);
26
+ }
27
+ }
18
28
  // send tags to client
19
- controller.enqueue(textEncoder.encode(`${tags.join(" ")}\n`));
29
+ if (queue.size > 0 && !timeout) {
30
+ controller.enqueue(textEncoder.encode(`${Array.from(queue).join(" ")}\n`));
31
+ queue = new Set();
32
+ timeout = setTimeout(() => {
33
+ controller.enqueue(textEncoder.encode(`${Array.from(queue).join(" ")}\n`));
34
+ queue = new Set();
35
+ timeout = null;
36
+ }, throttleTimeout);
37
+ }
20
38
  });
21
39
  // keepalive. The first one is sent right away so the response headers
22
40
  // are flushed immediately instead of only once the interval first
23
41
  // fires — consumers skip empty lines, so this is a no-op for them.
24
42
  const keepalive = () => controller.enqueue(textEncoder.encode("\n"));
25
43
  keepalive();
26
- interval = setInterval(keepalive, KEEPALIVE_INTERVAL);
44
+ interval = setInterval(keepalive, keepaliveInterval);
27
45
  },
28
46
  cancel() {
29
47
  if (interval)
30
48
  clearInterval(interval);
49
+ if (timeout)
50
+ clearTimeout(timeout);
31
51
  unsubscribe();
32
52
  },
33
53
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toapi/server",
3
- "version": "1.3.4",
3
+ "version": "1.4.0",
4
4
  "author": {
5
5
  "name": "Michel Smola",
6
6
  "email": "michel.smola@farbenmeer.de"
@@ -20,7 +20,7 @@
20
20
  }
21
21
  },
22
22
  "dependencies": {
23
- "@toapi/common": "^1.3.4",
23
+ "@toapi/common": "^1.4.0",
24
24
  "zod-openapi": "^6.0.0"
25
25
  },
26
26
  "devDependencies": {