@stackframe/stack-shared 2.6.37 → 2.6.39

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 CHANGED
@@ -1,5 +1,19 @@
1
1
  # @stackframe/stack-shared
2
2
 
3
+ ## 2.6.39
4
+
5
+ ### Patch Changes
6
+
7
+ - Various changes
8
+ - @stackframe/stack-sc@2.6.39
9
+
10
+ ## 2.6.38
11
+
12
+ ### Patch Changes
13
+
14
+ - Various changes
15
+ - @stackframe/stack-sc@2.6.38
16
+
3
17
  ## 2.6.37
4
18
 
5
19
  ### Patch Changes
@@ -37,7 +37,7 @@ export declare class AsyncCache<D extends any[], T> {
37
37
  readonly forceSetCachedValue: (key: D, value: T) => void;
38
38
  readonly forceSetCachedValueAsync: (key: D, value: Promise<T>) => ReactPromise<boolean>;
39
39
  readonly refresh: (key: D) => Promise<T>;
40
- readonly invalidate: (key: D) => Promise<T>;
40
+ readonly invalidate: (key: D) => void;
41
41
  readonly onStateChange: (key: D, callback: (value: T, oldValue: T | undefined) => void) => {
42
42
  unsubscribe: () => void;
43
43
  };
@@ -78,8 +78,15 @@ declare class AsyncValueCache<T> {
78
78
  private _refetch;
79
79
  forceSetCachedValue(value: T): void;
80
80
  forceSetCachedValueAsync(value: Promise<T>): ReactPromise<boolean>;
81
+ /**
82
+ * Refetches the value from the fetcher, and updates the cache with it.
83
+ */
81
84
  refresh(): Promise<T>;
82
- invalidate(): Promise<T>;
85
+ /**
86
+ * Invalidates the cache, marking it to refresh on the next read. If anyone was listening to it, it will refresh
87
+ * immediately.
88
+ */
89
+ invalidate(): void;
83
90
  onStateChange(callback: (value: T, oldValue: T | undefined) => void): {
84
91
  unsubscribe: () => void;
85
92
  };
@@ -1,6 +1,6 @@
1
1
  import { DependenciesMap } from "./maps";
2
2
  import { filterUndefined } from "./objects";
3
- import { pending, rateLimited, resolved, runAsynchronously } from "./promises";
3
+ import { pending, rateLimited, resolved, runAsynchronously, wait } from "./promises";
4
4
  import { AsyncStore } from "./stores";
5
5
  /**
6
6
  * Can be used to cache the result of a function call, for example for the `use` hook in React.
@@ -111,23 +111,41 @@ class AsyncValueCache {
111
111
  forceSetCachedValueAsync(value) {
112
112
  return this._setAsync(value);
113
113
  }
114
+ /**
115
+ * Refetches the value from the fetcher, and updates the cache with it.
116
+ */
114
117
  async refresh() {
115
118
  return await this.getOrWait("write-only");
116
119
  }
117
- async invalidate() {
120
+ /**
121
+ * Invalidates the cache, marking it to refresh on the next read. If anyone was listening to it, it will refresh
122
+ * immediately.
123
+ */
124
+ invalidate() {
118
125
  this._store.setUnavailable();
119
126
  this._pendingPromise = undefined;
120
- return await this.refresh();
127
+ if (this._subscriptionsCount > 0) {
128
+ runAsynchronously(this.refresh());
129
+ }
121
130
  }
122
131
  onStateChange(callback) {
123
132
  const storeObj = this._store.onChange(callback);
133
+ runAsynchronously(this.getOrWait("read-write"));
124
134
  if (this._subscriptionsCount++ === 0 && this._options.onSubscribe) {
135
+ let mostRecentRefreshPromiseIndex = 0;
125
136
  const unsubscribe = this._options.onSubscribe(() => {
126
- runAsynchronously(this.refresh());
137
+ const currentRefreshPromiseIndex = mostRecentRefreshPromiseIndex++;
138
+ runAsynchronously(async () => {
139
+ // wait a few seconds; if anything changes during that time, we don't want to refresh
140
+ // else we do unnecessary requests if we unsubscribe and then subscribe again immediately
141
+ await wait(5000);
142
+ if (this._subscriptionsCount === 0 && currentRefreshPromiseIndex === mostRecentRefreshPromiseIndex) {
143
+ this.invalidate();
144
+ }
145
+ });
127
146
  });
128
147
  this._unsubscribers.push(unsubscribe);
129
148
  }
130
- runAsynchronously(this.refresh());
131
149
  let hasUnsubscribed = false;
132
150
  return {
133
151
  unsubscribe: () => {
@@ -80,8 +80,11 @@ export function registerErrorSink(sink) {
80
80
  }
81
81
  errorSinks.add(sink);
82
82
  }
83
- registerErrorSink((location, ...args) => {
84
- console.error(`\x1b[41mCaptured error in ${location}:`, ...args, "\x1b[0m");
83
+ registerErrorSink((location, error, ...extraArgs) => {
84
+ console.error(`\x1b[41mCaptured error in ${location}:`,
85
+ // HACK: Log a nicified version of the error to get around buggy Next.js pretty-printing
86
+ // https://www.reddit.com/r/nextjs/comments/1gkxdqe/comment/m19kxgn/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button
87
+ errorToNiceString(error), ...extraArgs, "\x1b[0m");
85
88
  });
86
89
  registerErrorSink((location, error, ...extraArgs) => {
87
90
  globalVar.stackCapturedErrors = globalVar.stackCapturedErrors ?? [];
@@ -89,10 +92,7 @@ registerErrorSink((location, error, ...extraArgs) => {
89
92
  });
90
93
  export function captureError(location, error) {
91
94
  for (const sink of errorSinks) {
92
- sink(location,
93
- // HACK: Log a nicified version of the error instead of statusError to get around buggy Next.js pretty-printing
94
- // https://www.reddit.com/r/nextjs/comments/1gkxdqe/comment/m19kxgn/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button
95
- errorToNiceString(error), ...error && (typeof error === 'object' || typeof error === 'function') && "customCaptureExtraArgs" in error && Array.isArray(error.customCaptureExtraArgs) ? error.customCaptureExtraArgs : []);
95
+ sink(location, error, ...error && (typeof error === 'object' || typeof error === 'function') && "customCaptureExtraArgs" in error && Array.isArray(error.customCaptureExtraArgs) ? error.customCaptureExtraArgs : []);
96
96
  }
97
97
  }
98
98
  export class StatusError extends Error {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackframe/stack-shared",
3
- "version": "2.6.37",
3
+ "version": "2.6.39",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "files": [
@@ -50,7 +50,7 @@
50
50
  "oauth4webapi": "^2.10.3",
51
51
  "semver": "^7.6.3",
52
52
  "uuid": "^9.0.1",
53
- "@stackframe/stack-sc": "2.6.37"
53
+ "@stackframe/stack-sc": "2.6.39"
54
54
  },
55
55
  "devDependencies": {
56
56
  "@simplewebauthn/types": "^11.0.0",