@toapi/client 1.3.3 → 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,4 +1,4 @@
1
- import type { Observable } from "@toapi/common";
1
+ import type { Logger, Observable } from "@toapi/common";
2
2
  import type { PubSub } from "./pub-sub.js";
3
3
  import type { Cache } from "./cache.js";
4
4
  interface Options {
@@ -7,6 +7,7 @@ interface Options {
7
7
  init: RequestInit;
8
8
  pubSub: PubSub;
9
9
  cache: Cache;
10
+ logger?: Logger;
10
11
  }
11
12
  export declare function buildObservable(options: Options): Observable<unknown> & Promise<unknown>;
12
13
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"build-observable.d.ts","sourceRoot":"","sources":["../src/build-observable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGxC,UAAU,OAAO;IACf,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACzD,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,KAAK,CAAC;CACd;AAMD,wBAAgB,eAAe,CAC7B,OAAO,EAAE,OAAO,GACf,UAAU,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAmBxC"}
1
+ {"version":3,"file":"build-observable.d.ts","sourceRoot":"","sources":["../src/build-observable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAgB,MAAM,eAAe,CAAC;AACtE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGxC,UAAU,OAAO;IACf,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACzD,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,KAAK,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,eAAe,CAC7B,OAAO,EAAE,OAAO,GACf,UAAU,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAwBxC"}
@@ -1,6 +1,6 @@
1
1
  import { request } from "./request.js";
2
2
  export function buildObservable(options) {
3
- const { url, pubSub } = options;
3
+ const { url, pubSub, logger } = options;
4
4
  const { data } = request(options);
5
5
  function subscribe(callback) {
6
6
  const { data } = request(options);
@@ -8,7 +8,13 @@ export function buildObservable(options) {
8
8
  return pubSub.subscribe(async (invalidUrls) => {
9
9
  if (invalidUrls.has(url)) {
10
10
  const { data } = request(options);
11
- callback(data);
11
+ // TODO in major release pass the finished data, not the promise here so subscribers don't need to bother with races.
12
+ try {
13
+ await callback(data);
14
+ }
15
+ catch (error) {
16
+ logger?.error?.(error);
17
+ }
12
18
  }
13
19
  });
14
20
  }
package/dist/cache.d.ts CHANGED
@@ -22,8 +22,8 @@ export declare class Cache {
22
22
  constructor(options: Options);
23
23
  set(url: string, entry: CacheEntry): void;
24
24
  get(url: string): CacheEntry | undefined;
25
- invalidateUrl(url: string): Promise<void>;
26
- invalidateTags(tags: string[]): Promise<void>;
25
+ invalidateUrl(url: string, force: boolean): Promise<void>;
26
+ invalidateTags(tags: string[], force: boolean): Promise<void>;
27
27
  invalidateAll(): Promise<void>;
28
28
  }
29
29
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5B,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxB,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;CACxB;AAED,UAAU,OAAO;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAID,qBAAa,KAAK;IAChB,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,QAAQ,CAAkC;IAClD,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAA2C;IAC3D,OAAO,CAAC,MAAM,CAAS;gBAEX,OAAO,EAAE,OAAO;IAOrB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU;IA8ClC,GAAG,CAAC,GAAG,EAAE,MAAM;IAIf,aAAa,CAAC,GAAG,EAAE,MAAM;IAKzB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE;IAiB7B,aAAa;CAMrB"}
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5B,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxB,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;CACxB;AAED,UAAU,OAAO;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAID,qBAAa,KAAK;IAChB,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,QAAQ,CAAkC;IAClD,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAA2C;IAC3D,OAAO,CAAC,MAAM,CAAS;IAEvB,YAAY,OAAO,EAAE,OAAO,EAK3B;IAEM,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,QA4CxC;IAEM,GAAG,CAAC,GAAG,EAAE,MAAM,0BAErB;IAEM,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,iBAG/C;IAEM,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,OAAO,iBAenD;IAEM,aAAa,kBAKnB;CACF"}
package/dist/cache.js CHANGED
@@ -49,7 +49,7 @@ export class Cache {
49
49
  if (cached !== entry)
50
50
  return;
51
51
  this.storage.delete(url);
52
- this.pubSub.publish(new Set([url]));
52
+ this.pubSub.publish(new Set([url]), false);
53
53
  }, Math.max(0, timeUntilRevalidation));
54
54
  })
55
55
  .catch(() => { });
@@ -57,11 +57,11 @@ export class Cache {
57
57
  get(url) {
58
58
  return this.storage.get(url);
59
59
  }
60
- invalidateUrl(url) {
60
+ invalidateUrl(url, force) {
61
61
  this.storage.delete(url);
62
- return this.pubSub.publish(new Set([url]));
62
+ return this.pubSub.publish(new Set([url]), force);
63
63
  }
64
- invalidateTags(tags) {
64
+ invalidateTags(tags, force) {
65
65
  const urls = new Set();
66
66
  for (const tag of tags) {
67
67
  const taggedUrls = this.tagIndex.get(tag);
@@ -77,12 +77,12 @@ export class Cache {
77
77
  urls.add(url);
78
78
  }
79
79
  }
80
- return this.pubSub.publish(urls);
80
+ return this.pubSub.publish(urls, force);
81
81
  }
82
82
  invalidateAll() {
83
83
  const urls = new Set(this.storage.keys());
84
84
  this.storage.clear();
85
85
  this.tagIndex.clear();
86
- return this.pubSub.publish(urls);
86
+ return this.pubSub.publish(urls, false);
87
87
  }
88
88
  }
@@ -1 +1 @@
1
- {"version":3,"file":"create-fetch-client.d.ts","sourceRoot":"","sources":["../src/create-fetch-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,IAAI,IAAI,QAAQ,EAChB,SAAS,EACT,MAAM,EACN,YAAY,EACb,MAAM,eAAe,CAAC;AAIvB,OAAO,KAAK,EAAE,MAAM,EAAgB,MAAM,mBAAmB,CAAC;AAO9D,UAAU,OAAO;IACf,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CACnC;AAID,wBAAgB,iBAAiB,CAC/B,MAAM,SAAS,MAAM,CAAC,QAAQ,EAAE,YAAY,CAAC,SAAS,CAAC,CAAC,EACxD,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,OAAY,GAoGpB,MAAM,CAAC,MAAM,CAAC,CAChC"}
1
+ {"version":3,"file":"create-fetch-client.d.ts","sourceRoot":"","sources":["../src/create-fetch-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,IAAI,IAAI,QAAQ,EAChB,SAAS,EACT,MAAM,EACN,YAAY,EACb,MAAM,eAAe,CAAC;AAIvB,OAAO,KAAK,EAAE,MAAM,EAAgB,MAAM,mBAAmB,CAAC;AAO9D,UAAU,OAAO;IACf,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CACnC;AAID,wBAAgB,iBAAiB,CAC/B,MAAM,SAAS,MAAM,CAAC,QAAQ,EAAE,YAAY,CAAC,SAAS,CAAC,CAAC,EACxD,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,OAAY,GAwGpB,MAAM,CAAC,MAAM,CAAC,CAChC"}
@@ -23,7 +23,7 @@ export function createFetchClient(apiUrl, options = {}) {
23
23
  : (options.invalidationsUrl ?? apiUrl + INVALIDATIONS_ROUTE);
24
24
  listenForInvalidations({
25
25
  fetch,
26
- onInvalidate: (tags) => cache.invalidateTags(tags),
26
+ onInvalidate: (tags) => cache.invalidateTags(tags, false),
27
27
  onConnect: () => cache.invalidateAll(),
28
28
  logger: options.logger,
29
29
  invalidationsUrl,
@@ -38,10 +38,11 @@ export function createFetchClient(apiUrl, options = {}) {
38
38
  },
39
39
  pubSub,
40
40
  cache,
41
+ logger: options.logger,
41
42
  });
42
43
  }
43
44
  async function revalidate(url) {
44
- await cache.invalidateUrl(url);
45
+ await cache.invalidateUrl(url, true);
45
46
  }
46
47
  function mutate(method, url, data, init = {}) {
47
48
  const headers = new Headers(init.headers);
@@ -62,7 +63,7 @@ export function createFetchClient(apiUrl, options = {}) {
62
63
  await options?.logger?.error?.(error);
63
64
  throw error;
64
65
  });
65
- const revalidated = response.then((res) => cache.invalidateTags(res.headers.get(TAGS_HEADER)?.split(" ") ?? []));
66
+ const revalidated = response.then((res) => cache.invalidateTags(res.headers.get(TAGS_HEADER)?.split(" ") ?? [], true));
66
67
  return Object.defineProperty(body, "revalidated", {
67
68
  get: async () => {
68
69
  const [data] = await Promise.all([body, revalidated]);
package/dist/pub-sub.d.ts CHANGED
@@ -9,7 +9,7 @@ export declare class PubSub {
9
9
  private minTTL;
10
10
  constructor(options: Options);
11
11
  subscribe(callback: Subscription): () => void;
12
- publish(urls: Set<string>): Promise<void>;
12
+ publish(urls: Set<string>, force: boolean): Promise<void>;
13
13
  }
14
14
  export {};
15
15
  //# sourceMappingURL=pub-sub.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pub-sub.d.ts","sourceRoot":"","sources":["../src/pub-sub.ts"],"names":[],"mappings":"AAAA,KAAK,YAAY,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEzD,UAAU,OAAO;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,MAAM;IACjB,OAAO,CAAC,aAAa,CAA2B;IAChD,OAAO,CAAC,gBAAgB,CAAoD;IAC5E,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,MAAM,CAAS;gBAEX,OAAO,EAAE,OAAO;IAI5B,SAAS,CAAC,QAAQ,EAAE,YAAY;IAO1B,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC;CA6BhC"}
1
+ {"version":3,"file":"pub-sub.d.ts","sourceRoot":"","sources":["../src/pub-sub.ts"],"names":[],"mappings":"AAAA,KAAK,YAAY,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEzD,UAAU,OAAO;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,MAAM;IACjB,OAAO,CAAC,aAAa,CAA2B;IAChD,OAAO,CAAC,gBAAgB,CAAoD;IAC5E,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,MAAM,CAAS;IAEvB,YAAY,OAAO,EAAE,OAAO,EAE3B;IAED,SAAS,CAAC,QAAQ,EAAE,YAAY,cAK/B;IAEK,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,iBAwC9C;CACF"}
package/dist/pub-sub.js CHANGED
@@ -12,7 +12,16 @@ export class PubSub {
12
12
  this.subscriptions.delete(callback);
13
13
  };
14
14
  }
15
- async publish(urls) {
15
+ async publish(urls, force) {
16
+ if (force) {
17
+ for (const url of urls) {
18
+ const timeout = this.debounceTimeouts.get(url);
19
+ clearTimeout(timeout);
20
+ this.debounceTimeouts.delete(url);
21
+ }
22
+ await Promise.all(this.subscriptions.values().map((callback) => callback(urls)));
23
+ return;
24
+ }
16
25
  for (const url of urls) {
17
26
  if (this.debounceTimeouts.has(url)) {
18
27
  // debounced, mark as requested and ignore now
@@ -30,7 +39,7 @@ export class PubSub {
30
39
  }
31
40
  // Consume pending invalidations and unlock the entire batch before replay.
32
41
  if (pendingUrls.size)
33
- return this.publish(pendingUrls);
42
+ return this.publish(pendingUrls, false);
34
43
  }, this.minTTL);
35
44
  for (const url of urls) {
36
45
  this.debounceTimeouts.set(url, timeout);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toapi/client",
3
- "version": "1.3.3",
3
+ "version": "1.4.0",
4
4
  "author": {
5
5
  "name": "Michel Smola",
6
6
  "email": "michel.smola@farbenmeer.de"
@@ -20,13 +20,13 @@
20
20
  }
21
21
  },
22
22
  "dependencies": {
23
- "@toapi/common": "^1.3.3"
23
+ "@toapi/common": "^1.4.0"
24
24
  },
25
25
  "devDependencies": {
26
26
  "@types/node": "^25.0.3",
27
27
  "vitest": "^5.0.0",
28
28
  "zod": "^4.0.17",
29
- "@toapi/server": "^1.3.3"
29
+ "@toapi/server": "^1.4.0"
30
30
  },
31
31
  "peerDependencies": {
32
32
  "typescript": "^5 || ^6.0.0 || ^7.0.0",