@stackframe/stack-shared 2.8.49 → 2.8.52
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 +18 -0
- package/dist/apps/apps-ui.d.mts +26 -0
- package/dist/apps/apps-ui.d.ts +26 -0
- package/dist/apps/apps-ui.js +110 -0
- package/dist/apps/apps-ui.js.map +1 -0
- package/dist/config/schema.d.mts +189 -189
- package/dist/config/schema.d.ts +189 -189
- package/dist/esm/apps/apps-ui.js +83 -0
- package/dist/esm/apps/apps-ui.js.map +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/interface/crud/svix-token.js +2 -1
- package/dist/esm/interface/crud/svix-token.js.map +1 -1
- package/dist/esm/interface/server-interface.js +11 -0
- package/dist/esm/interface/server-interface.js.map +1 -1
- package/dist/esm/known-errors.js +1 -1
- package/dist/esm/known-errors.js.map +1 -1
- package/dist/esm/utils/caches.js +16 -9
- package/dist/esm/utils/caches.js.map +1 -1
- package/dist/esm/utils/react.js +49 -2
- package/dist/esm/utils/react.js.map +1 -1
- package/dist/esm/utils/stores.js +1 -0
- package/dist/esm/utils/stores.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/interface/crud/svix-token.d.mts +4 -0
- package/dist/interface/crud/svix-token.d.ts +4 -0
- package/dist/interface/crud/svix-token.js +2 -1
- package/dist/interface/crud/svix-token.js.map +1 -1
- package/dist/interface/server-interface.d.mts +4 -0
- package/dist/interface/server-interface.d.ts +4 -0
- package/dist/interface/server-interface.js +11 -0
- package/dist/interface/server-interface.js.map +1 -1
- package/dist/known-errors.d.mts +1 -1
- package/dist/known-errors.d.ts +1 -1
- package/dist/known-errors.js +1 -1
- package/dist/known-errors.js.map +1 -1
- package/dist/utils/caches.d.mts +4 -3
- package/dist/utils/caches.d.ts +4 -3
- package/dist/utils/caches.js +16 -9
- package/dist/utils/caches.js.map +1 -1
- package/dist/utils/react.d.mts +3 -1
- package/dist/utils/react.d.ts +3 -1
- package/dist/utils/react.js +50 -1
- package/dist/utils/react.js.map +1 -1
- package/dist/utils/stores.js +1 -0
- package/dist/utils/stores.js.map +1 -1
- package/package.json +1 -1
package/dist/utils/react.js
CHANGED
|
@@ -39,6 +39,8 @@ __export(react_exports, {
|
|
|
39
39
|
shouldRethrowRenderingError: () => shouldRethrowRenderingError,
|
|
40
40
|
suspend: () => suspend,
|
|
41
41
|
suspendIfSsr: () => suspendIfSsr,
|
|
42
|
+
use: () => use,
|
|
43
|
+
useQueryState: () => useQueryState,
|
|
42
44
|
useRefState: () => useRefState
|
|
43
45
|
});
|
|
44
46
|
module.exports = __toCommonJS(react_exports);
|
|
@@ -51,6 +53,34 @@ function componentWrapper(displayName, render) {
|
|
|
51
53
|
Component.displayName = displayName;
|
|
52
54
|
return Component;
|
|
53
55
|
}
|
|
56
|
+
var react18PromiseCache = /* @__PURE__ */ new WeakMap();
|
|
57
|
+
function use(promise) {
|
|
58
|
+
if ("use" in import_react.default) {
|
|
59
|
+
return import_react.default.use(promise);
|
|
60
|
+
} else {
|
|
61
|
+
if (react18PromiseCache.has(promise)) {
|
|
62
|
+
const result = react18PromiseCache.get(promise);
|
|
63
|
+
if (result.status === "pending") {
|
|
64
|
+
throw promise;
|
|
65
|
+
} else if (result.status === "ok") {
|
|
66
|
+
return result.data;
|
|
67
|
+
} else {
|
|
68
|
+
throw result.error;
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
react18PromiseCache.set(promise, { "status": "pending", progress: void 0 });
|
|
72
|
+
(0, import_promises.runAsynchronously)(async () => {
|
|
73
|
+
try {
|
|
74
|
+
const res = await promise;
|
|
75
|
+
react18PromiseCache.set(promise, { "status": "ok", data: res });
|
|
76
|
+
} catch (e) {
|
|
77
|
+
react18PromiseCache.set(promise, { "status": "error", error: e });
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
throw promise;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
54
84
|
function forwardRefIfNeeded(render) {
|
|
55
85
|
const version = import_react.default.version;
|
|
56
86
|
const major = parseInt(version.split(".")[0]);
|
|
@@ -76,7 +106,7 @@ function getNodeText(node) {
|
|
|
76
106
|
throw new Error(`Unknown node type: ${typeof node}`);
|
|
77
107
|
}
|
|
78
108
|
function suspend() {
|
|
79
|
-
|
|
109
|
+
use((0, import_promises.neverResolve)());
|
|
80
110
|
throw new Error("Somehow a Promise that never resolves was resolved?");
|
|
81
111
|
}
|
|
82
112
|
function mapRef(ref, mapper) {
|
|
@@ -123,6 +153,23 @@ function mapRefState(refState, mapper, reverseMapper) {
|
|
|
123
153
|
}
|
|
124
154
|
};
|
|
125
155
|
}
|
|
156
|
+
function useQueryState(key, defaultValue) {
|
|
157
|
+
const getValue = () => new URLSearchParams(window.location.search).get(key) ?? defaultValue ?? "";
|
|
158
|
+
const [value, setValue] = import_react.default.useState(getValue);
|
|
159
|
+
import_react.default.useEffect(() => {
|
|
160
|
+
const onPopState = () => setValue(getValue());
|
|
161
|
+
window.addEventListener("popstate", onPopState);
|
|
162
|
+
return () => window.removeEventListener("popstate", onPopState);
|
|
163
|
+
}, []);
|
|
164
|
+
const update = (next) => {
|
|
165
|
+
const params = new URLSearchParams(window.location.search);
|
|
166
|
+
params.set(key, next);
|
|
167
|
+
const newUrl = `${window.location.pathname}?${params.toString()}`;
|
|
168
|
+
window.history.pushState(null, "", newUrl);
|
|
169
|
+
setValue(next);
|
|
170
|
+
};
|
|
171
|
+
return [value, update];
|
|
172
|
+
}
|
|
126
173
|
function shouldRethrowRenderingError(error) {
|
|
127
174
|
return !!error && typeof error === "object" && "digest" in error && error.digest === "BAILOUT_TO_CLIENT_SIDE_RENDERING";
|
|
128
175
|
}
|
|
@@ -178,6 +225,8 @@ function suspendIfSsr(caller) {
|
|
|
178
225
|
shouldRethrowRenderingError,
|
|
179
226
|
suspend,
|
|
180
227
|
suspendIfSsr,
|
|
228
|
+
use,
|
|
229
|
+
useQueryState,
|
|
181
230
|
useRefState
|
|
182
231
|
});
|
|
183
232
|
//# sourceMappingURL=react.js.map
|
package/dist/utils/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/react.tsx"],"sourcesContent":["import React, { SetStateAction } from \"react\";\nimport { isBrowserLike } from \"./env\";\nimport { neverResolve } from \"./promises\";\nimport { deindent } from \"./strings\";\n\nexport function componentWrapper<\n C extends React.ComponentType<any> | keyof React.JSX.IntrinsicElements,\n ExtraProps extends {} = {}\n>(displayName: string, render: React.ForwardRefRenderFunction<RefFromComponent<C>, React.ComponentPropsWithRef<C> & ExtraProps>) {\n const Component = forwardRefIfNeeded(render);\n Component.displayName = displayName;\n return Component;\n}\ntype RefFromComponent<C extends React.ComponentType<any> | keyof React.JSX.IntrinsicElements> = NonNullable<RefFromComponentDistCond<React.ComponentPropsWithRef<C>[\"ref\"]>>;\ntype RefFromComponentDistCond<A> = A extends React.RefObject<infer T> ? T : never; // distributive conditional type; see https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types\n\nexport function forwardRefIfNeeded<T, P = {}>(render: React.ForwardRefRenderFunction<T, P>): React.FC<P & { ref?: React.Ref<T> }> {\n // TODO: when we drop support for react 18, remove this\n\n const version = React.version;\n const major = parseInt(version.split(\".\")[0]);\n if (major < 19) {\n return React.forwardRef<T, P>(render as any) as any;\n } else {\n return ((props: P) => render(props, (props as any).ref)) as any;\n }\n}\n\nexport function getNodeText(node: React.ReactNode): string {\n if ([\"number\", \"string\"].includes(typeof node)) {\n return `${node}`;\n }\n if (!node) {\n return \"\";\n }\n if (Array.isArray(node)) {\n return node.map(getNodeText).join(\"\");\n }\n if (typeof node === \"object\" && \"props\" in node) {\n return getNodeText(node.props.children);\n }\n throw new Error(`Unknown node type: ${typeof node}`);\n}\nundefined?.test(\"getNodeText\", ({ expect }) => {\n // Test with string\n expect(getNodeText(\"hello\")).toBe(\"hello\");\n\n // Test with number\n expect(getNodeText(42)).toBe(\"42\");\n\n // Test with null/undefined\n expect(getNodeText(null)).toBe(\"\");\n expect(getNodeText(undefined)).toBe(\"\");\n\n // Test with array\n expect(getNodeText([\"hello\", \" \", \"world\"])).toBe(\"hello world\");\n expect(getNodeText([1, 2, 3])).toBe(\"123\");\n\n // Test with mixed array\n expect(getNodeText([\"hello\", 42, null])).toBe(\"hello42\");\n\n // Test with React element (mocked)\n const mockElement = {\n props: {\n children: \"child text\"\n }\n } as React.ReactElement;\n expect(getNodeText(mockElement)).toBe(\"child text\");\n\n // Test with nested React elements\n const nestedElement = {\n props: {\n children: {\n props: {\n children: \"nested text\"\n }\n } as React.ReactElement\n }\n } as React.ReactElement;\n expect(getNodeText(nestedElement)).toBe(\"nested text\");\n\n // Test with array of React elements\n const arrayOfElements = [\n { props: { children: \"first\" } } as React.ReactElement,\n { props: { children: \"second\" } } as React.ReactElement\n ];\n expect(getNodeText(arrayOfElements)).toBe(\"firstsecond\");\n});\n\n/**\n * Suspends the currently rendered component indefinitely. Will not unsuspend unless the component rerenders.\n *\n * You can use this to translate older query- or AsyncResult-based code to new the Suspense system, for example: `if (query.isLoading) suspend();`\n */\nexport function suspend(): never {\n React.use(neverResolve());\n throw new Error(\"Somehow a Promise that never resolves was resolved?\");\n}\n\nexport function mapRef<T, R>(ref: ReadonlyRef<T>, mapper: (value: T) => R): ReadonlyRef<R> {\n let last: [T, R] | null = null;\n return {\n get current() {\n const input = ref.current;\n if (last === null || input !== last[0]) {\n last = [input, mapper(input)];\n }\n return last[1];\n },\n };\n}\n\nexport type ReadonlyRef<T> = {\n readonly current: T,\n};\n\nexport type RefState<T> = ReadonlyRef<T> & {\n set: (updater: SetStateAction<T>) => void,\n};\n\n/**\n * Like useState, but its value is immediately available on refState.current after being set.\n *\n * Like useRef, but setting the value will cause a rerender.\n *\n * Note that useRefState returns a new object every time a rerender happens due to a value change, which is intentional\n * as it allows you to specify it in a dependency array like this:\n *\n * ```tsx\n * useEffect(() => {\n * // do something with refState.current\n * }, [refState]); // instead of refState.current\n * ```\n *\n * If you don't want this, you can wrap the result in a useMemo call.\n */\nexport function useRefState<T>(initialValue: T): RefState<T> {\n const [, setState] = React.useState(initialValue);\n const ref = React.useRef(initialValue);\n const setValue = React.useCallback((updater: SetStateAction<T>) => {\n const value: T = typeof updater === \"function\" ? (updater as any)(ref.current) : updater;\n ref.current = value;\n setState(value);\n }, []);\n const res = React.useMemo(() => ({\n get current() {\n return ref.current;\n },\n set: setValue,\n }), [setValue]);\n return res;\n}\n\nexport function mapRefState<T, R>(refState: RefState<T>, mapper: (value: T) => R, reverseMapper: (oldT: T, newR: R) => T): RefState<R> {\n let last: [T, R] | null = null;\n return {\n get current() {\n const input = refState.current;\n if (last === null || input !== last[0]) {\n last = [input, mapper(input)];\n }\n return last[1];\n },\n set(updater: SetStateAction<R>) {\n const value: R = typeof updater === \"function\" ? (updater as any)(this.current) : updater;\n refState.set(reverseMapper(refState.current, value));\n },\n };\n}\n\nexport function shouldRethrowRenderingError(error: unknown): boolean {\n return !!error && typeof error === \"object\" && \"digest\" in error && error.digest === \"BAILOUT_TO_CLIENT_SIDE_RENDERING\";\n}\n\nexport class NoSuspenseBoundaryError extends Error {\n digest: string;\n reason: string;\n\n constructor(options: { caller?: string }) {\n super(deindent`\n Suspense boundary not found! Read the error message below carefully on how to fix it.\n\n ${options.caller ?? \"This code path\"} attempted to display a loading indicator, but didn't find a Suspense boundary above it. Please read the error message below carefully.\n \n The fix depends on which of the 4 scenarios caused it:\n \n 1. [Next.js] You are missing a loading.tsx file in your app directory. Fix it by adding a loading.tsx file in your app directory.\n\n 2. [React] You are missing a <Suspense> boundary in your component. Fix it by wrapping your component (or the entire app) in a <Suspense> component.\n\n 3. [Next.js] The component is rendered in the root (outermost) layout.tsx or template.tsx file. Next.js does not wrap those files in a Suspense boundary, even if there is a loading.tsx file in the same folder. To fix it, wrap your layout inside a route group like this:\n\n - app\n - - layout.tsx // contains <html> and <body>, alongside providers and other components that don't need ${options.caller ?? \"this code path\"}\n - - loading.tsx // required for suspense\n - - (main)\n - - - layout.tsx // contains the main layout of your app, like a sidebar or a header, and can use ${options.caller ?? \"this code path\"}\n - - - route.tsx // your actual main page\n - - - the rest of your app\n\n For more information on this approach, see Next's documentation on route groups: https://nextjs.org/docs/app/building-your-application/routing/route-groups\n \n 4. You caught this error with try-catch or a custom error boundary. Fix this by rethrowing the error or not catching it in the first place.\n\n See: https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout\n\n More information on SSR and Suspense boundaries: https://react.dev/reference/react/Suspense#providing-a-fallback-for-server-errors-and-client-only-content\n `);\n\n this.name = \"NoSuspenseBoundaryError\";\n this.reason = options.caller ?? \"suspendIfSsr()\";\n\n // set the digest so nextjs doesn't log the error\n // https://github.com/vercel/next.js/blob/d01d6d9c35a8c2725b3d74c1402ab76d4779a6cf/packages/next/src/shared/lib/lazy-dynamic/bailout-to-csr.ts#L14\n this.digest = \"BAILOUT_TO_CLIENT_SIDE_RENDERING\";\n }\n}\nundefined?.test(\"NoSuspenseBoundaryError\", ({ expect }) => {\n // Test with default options\n const defaultError = new NoSuspenseBoundaryError({});\n expect(defaultError.name).toBe(\"NoSuspenseBoundaryError\");\n expect(defaultError.reason).toBe(\"suspendIfSsr()\");\n expect(defaultError.digest).toBe(\"BAILOUT_TO_CLIENT_SIDE_RENDERING\");\n expect(defaultError.message).toContain(\"This code path attempted to display a loading indicator\");\n\n // Test with custom caller\n const customError = new NoSuspenseBoundaryError({ caller: \"CustomComponent\" });\n expect(customError.name).toBe(\"NoSuspenseBoundaryError\");\n expect(customError.reason).toBe(\"CustomComponent\");\n expect(customError.digest).toBe(\"BAILOUT_TO_CLIENT_SIDE_RENDERING\");\n expect(customError.message).toContain(\"CustomComponent attempted to display a loading indicator\");\n\n // Verify error message contains all the necessary information\n expect(customError.message).toContain(\"loading.tsx\");\n expect(customError.message).toContain(\"route groups\");\n expect(customError.message).toContain(\"https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout\");\n});\n\n\n/**\n * Use this in a component or a hook to disable SSR. Should be wrapped in a Suspense boundary, or it will throw an error.\n */\nexport function suspendIfSsr(caller?: string) {\n if (!isBrowserLike()) {\n throw new NoSuspenseBoundaryError({ caller });\n }\n}\n"],"mappings":"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","names":["React"]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/react.tsx"],"sourcesContent":["import React, { SetStateAction } from \"react\";\nimport { isBrowserLike } from \"./env\";\nimport { neverResolve, runAsynchronously } from \"./promises\";\nimport { AsyncResult } from \"./results\";\nimport { deindent } from \"./strings\";\n\nexport function componentWrapper<\n C extends React.ComponentType<any> | keyof React.JSX.IntrinsicElements,\n ExtraProps extends {} = {}\n>(displayName: string, render: React.ForwardRefRenderFunction<RefFromComponent<C>, React.ComponentPropsWithRef<C> & ExtraProps>) {\n const Component = forwardRefIfNeeded(render);\n Component.displayName = displayName;\n return Component;\n}\ntype RefFromComponent<C extends React.ComponentType<any> | keyof React.JSX.IntrinsicElements> = NonNullable<RefFromComponentDistCond<React.ComponentPropsWithRef<C>[\"ref\"]>>;\ntype RefFromComponentDistCond<A> = A extends React.RefObject<infer T> ? T : never; // distributive conditional type; see https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types\n\nconst react18PromiseCache = new WeakMap<Promise<unknown>, AsyncResult<unknown, unknown>>();\nexport function use<T>(promise: Promise<T>): T {\n if (\"use\" in React) {\n return React.use(promise);\n } else {\n if (react18PromiseCache.has(promise)) {\n const result = react18PromiseCache.get(promise)!;\n if (result.status === \"pending\") {\n throw promise;\n } else if (result.status === \"ok\") {\n return result.data as T;\n } else {\n throw result.error;\n }\n } else {\n react18PromiseCache.set(promise, { \"status\": \"pending\", progress: undefined });\n runAsynchronously(async () => {\n try {\n const res = await promise;\n react18PromiseCache.set(promise, { \"status\": \"ok\", data: res });\n } catch (e) {\n react18PromiseCache.set(promise, { \"status\": \"error\", error: e });\n }\n });\n throw promise;\n }\n }\n}\n\nexport function forwardRefIfNeeded<T, P = {}>(render: React.ForwardRefRenderFunction<T, P>): React.FC<P & { ref?: React.Ref<T> }> {\n // TODO: when we drop support for react 18, remove this\n\n const version = React.version;\n const major = parseInt(version.split(\".\")[0]);\n if (major < 19) {\n return React.forwardRef<T, P>(render as any) as any;\n } else {\n return ((props: P) => render(props, (props as any).ref)) as any;\n }\n}\n\nexport function getNodeText(node: React.ReactNode): string {\n if ([\"number\", \"string\"].includes(typeof node)) {\n return `${node}`;\n }\n if (!node) {\n return \"\";\n }\n if (Array.isArray(node)) {\n return node.map(getNodeText).join(\"\");\n }\n if (typeof node === \"object\" && \"props\" in node) {\n return getNodeText(node.props.children);\n }\n throw new Error(`Unknown node type: ${typeof node}`);\n}\nundefined?.test(\"getNodeText\", ({ expect }) => {\n // Test with string\n expect(getNodeText(\"hello\")).toBe(\"hello\");\n\n // Test with number\n expect(getNodeText(42)).toBe(\"42\");\n\n // Test with null/undefined\n expect(getNodeText(null)).toBe(\"\");\n expect(getNodeText(undefined)).toBe(\"\");\n\n // Test with array\n expect(getNodeText([\"hello\", \" \", \"world\"])).toBe(\"hello world\");\n expect(getNodeText([1, 2, 3])).toBe(\"123\");\n\n // Test with mixed array\n expect(getNodeText([\"hello\", 42, null])).toBe(\"hello42\");\n\n // Test with React element (mocked)\n const mockElement = {\n props: {\n children: \"child text\"\n }\n } as React.ReactElement;\n expect(getNodeText(mockElement)).toBe(\"child text\");\n\n // Test with nested React elements\n const nestedElement = {\n props: {\n children: {\n props: {\n children: \"nested text\"\n }\n } as React.ReactElement\n }\n } as React.ReactElement;\n expect(getNodeText(nestedElement)).toBe(\"nested text\");\n\n // Test with array of React elements\n const arrayOfElements = [\n { props: { children: \"first\" } } as React.ReactElement,\n { props: { children: \"second\" } } as React.ReactElement\n ];\n expect(getNodeText(arrayOfElements)).toBe(\"firstsecond\");\n});\n\n/**\n * Suspends the currently rendered component indefinitely. Will not unsuspend unless the component rerenders.\n *\n * You can use this to translate older query- or AsyncResult-based code to new the Suspense system, for example: `if (query.isLoading) suspend();`\n */\nexport function suspend(): never {\n use(neverResolve());\n throw new Error(\"Somehow a Promise that never resolves was resolved?\");\n}\n\nexport function mapRef<T, R>(ref: ReadonlyRef<T>, mapper: (value: T) => R): ReadonlyRef<R> {\n let last: [T, R] | null = null;\n return {\n get current() {\n const input = ref.current;\n if (last === null || input !== last[0]) {\n last = [input, mapper(input)];\n }\n return last[1];\n },\n };\n}\n\nexport type ReadonlyRef<T> = {\n readonly current: T,\n};\n\nexport type RefState<T> = ReadonlyRef<T> & {\n set: (updater: SetStateAction<T>) => void,\n};\n\n/**\n * Like useState, but its value is immediately available on refState.current after being set.\n *\n * Like useRef, but setting the value will cause a rerender.\n *\n * Note that useRefState returns a new object every time a rerender happens due to a value change, which is intentional\n * as it allows you to specify it in a dependency array like this:\n *\n * ```tsx\n * useEffect(() => {\n * // do something with refState.current\n * }, [refState]); // instead of refState.current\n * ```\n *\n * If you don't want this, you can wrap the result in a useMemo call.\n */\nexport function useRefState<T>(initialValue: T): RefState<T> {\n const [, setState] = React.useState(initialValue);\n const ref = React.useRef(initialValue);\n const setValue = React.useCallback((updater: SetStateAction<T>) => {\n const value: T = typeof updater === \"function\" ? (updater as any)(ref.current) : updater;\n ref.current = value;\n setState(value);\n }, []);\n const res = React.useMemo(() => ({\n get current() {\n return ref.current;\n },\n set: setValue,\n }), [setValue]);\n return res;\n}\n\nexport function mapRefState<T, R>(refState: RefState<T>, mapper: (value: T) => R, reverseMapper: (oldT: T, newR: R) => T): RefState<R> {\n let last: [T, R] | null = null;\n return {\n get current() {\n const input = refState.current;\n if (last === null || input !== last[0]) {\n last = [input, mapper(input)];\n }\n return last[1];\n },\n set(updater: SetStateAction<R>) {\n const value: R = typeof updater === \"function\" ? (updater as any)(this.current) : updater;\n refState.set(reverseMapper(refState.current, value));\n },\n };\n}\n\nexport function useQueryState(key: string, defaultValue?: string) {\n const getValue = () => new URLSearchParams(window.location.search).get(key) ?? defaultValue ?? \"\";\n\n const [value, setValue] = React.useState(getValue);\n\n React.useEffect(() => {\n const onPopState = () => setValue(getValue());\n window.addEventListener(\"popstate\", onPopState);\n return () => window.removeEventListener(\"popstate\", onPopState);\n }, []);\n\n const update = (next: string) => {\n const params = new URLSearchParams(window.location.search);\n params.set(key, next);\n const newUrl = `${window.location.pathname}?${params.toString()}`;\n window.history.pushState(null, \"\", newUrl);\n setValue(next);\n };\n\n return [value, update] as const;\n}\n\nexport function shouldRethrowRenderingError(error: unknown): boolean {\n return !!error && typeof error === \"object\" && \"digest\" in error && error.digest === \"BAILOUT_TO_CLIENT_SIDE_RENDERING\";\n}\n\nexport class NoSuspenseBoundaryError extends Error {\n digest: string;\n reason: string;\n\n constructor(options: { caller?: string }) {\n super(deindent`\n Suspense boundary not found! Read the error message below carefully on how to fix it.\n\n ${options.caller ?? \"This code path\"} attempted to display a loading indicator, but didn't find a Suspense boundary above it. Please read the error message below carefully.\n \n The fix depends on which of the 4 scenarios caused it:\n \n 1. [Next.js] You are missing a loading.tsx file in your app directory. Fix it by adding a loading.tsx file in your app directory.\n\n 2. [React] You are missing a <Suspense> boundary in your component. Fix it by wrapping your component (or the entire app) in a <Suspense> component.\n\n 3. [Next.js] The component is rendered in the root (outermost) layout.tsx or template.tsx file. Next.js does not wrap those files in a Suspense boundary, even if there is a loading.tsx file in the same folder. To fix it, wrap your layout inside a route group like this:\n\n - app\n - - layout.tsx // contains <html> and <body>, alongside providers and other components that don't need ${options.caller ?? \"this code path\"}\n - - loading.tsx // required for suspense\n - - (main)\n - - - layout.tsx // contains the main layout of your app, like a sidebar or a header, and can use ${options.caller ?? \"this code path\"}\n - - - route.tsx // your actual main page\n - - - the rest of your app\n\n For more information on this approach, see Next's documentation on route groups: https://nextjs.org/docs/app/building-your-application/routing/route-groups\n \n 4. You caught this error with try-catch or a custom error boundary. Fix this by rethrowing the error or not catching it in the first place.\n\n See: https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout\n\n More information on SSR and Suspense boundaries: https://react.dev/reference/react/Suspense#providing-a-fallback-for-server-errors-and-client-only-content\n `);\n\n this.name = \"NoSuspenseBoundaryError\";\n this.reason = options.caller ?? \"suspendIfSsr()\";\n\n // set the digest so nextjs doesn't log the error\n // https://github.com/vercel/next.js/blob/d01d6d9c35a8c2725b3d74c1402ab76d4779a6cf/packages/next/src/shared/lib/lazy-dynamic/bailout-to-csr.ts#L14\n this.digest = \"BAILOUT_TO_CLIENT_SIDE_RENDERING\";\n }\n}\nundefined?.test(\"NoSuspenseBoundaryError\", ({ expect }) => {\n // Test with default options\n const defaultError = new NoSuspenseBoundaryError({});\n expect(defaultError.name).toBe(\"NoSuspenseBoundaryError\");\n expect(defaultError.reason).toBe(\"suspendIfSsr()\");\n expect(defaultError.digest).toBe(\"BAILOUT_TO_CLIENT_SIDE_RENDERING\");\n expect(defaultError.message).toContain(\"This code path attempted to display a loading indicator\");\n\n // Test with custom caller\n const customError = new NoSuspenseBoundaryError({ caller: \"CustomComponent\" });\n expect(customError.name).toBe(\"NoSuspenseBoundaryError\");\n expect(customError.reason).toBe(\"CustomComponent\");\n expect(customError.digest).toBe(\"BAILOUT_TO_CLIENT_SIDE_RENDERING\");\n expect(customError.message).toContain(\"CustomComponent attempted to display a loading indicator\");\n\n // Verify error message contains all the necessary information\n expect(customError.message).toContain(\"loading.tsx\");\n expect(customError.message).toContain(\"route groups\");\n expect(customError.message).toContain(\"https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout\");\n});\n\n\n/**\n * Use this in a component or a hook to disable SSR. Should be wrapped in a Suspense boundary, or it will throw an error.\n */\nexport function suspendIfSsr(caller?: string) {\n if (!isBrowserLike()) {\n throw new NoSuspenseBoundaryError({ caller });\n }\n}\n"],"mappings":"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","names":["React"]}
|
package/dist/utils/stores.js
CHANGED
|
@@ -168,6 +168,7 @@ var AsyncStore = class _AsyncStore {
|
|
|
168
168
|
}
|
|
169
169
|
setUnavailable() {
|
|
170
170
|
this._lastSuccessfulUpdate = ++this._updateCounter;
|
|
171
|
+
this._mostRecentOkValue = void 0;
|
|
171
172
|
this._isAvailable = false;
|
|
172
173
|
this._isRejected = false;
|
|
173
174
|
this._rejectionError = void 0;
|
package/dist/utils/stores.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/stores.tsx"],"sourcesContent":["import { ReadWriteLock } from \"./locks\";\nimport { ReactPromise, pending, rejected, resolved } from \"./promises\";\nimport { AsyncResult, Result } from \"./results\";\nimport { generateUuid } from \"./uuids\";\n\nexport type ReadonlyStore<T> = {\n get(): T,\n onChange(callback: (value: T, oldValue: T | undefined) => void): { unsubscribe: () => void },\n onceChange(callback: (value: T, oldValue: T | undefined) => void): { unsubscribe: () => void },\n};\n\nexport type AsyncStoreStateChangeCallback<T> = (args: { state: AsyncResult<T>, oldState: AsyncResult<T>, lastOkValue: T | undefined }) => void;\n\nexport type ReadonlyAsyncStore<T> = {\n isAvailable(): boolean,\n get(): AsyncResult<T, unknown, void>,\n getOrWait(): ReactPromise<T>,\n onChange(callback: (value: T, oldValue: T | undefined) => void): { unsubscribe: () => void },\n onceChange(callback: (value: T, oldValue: T | undefined) => void): { unsubscribe: () => void },\n onStateChange(callback: AsyncStoreStateChangeCallback<T>): { unsubscribe: () => void },\n onceStateChange(callback: AsyncStoreStateChangeCallback<T>): { unsubscribe: () => void },\n};\n\nexport class Store<T> implements ReadonlyStore<T> {\n private readonly _callbacks: Map<string, ((value: T, oldValue: T | undefined) => void)> = new Map();\n\n constructor(\n private _value: T\n ) {}\n\n get(): T {\n return this._value;\n }\n\n set(value: T): void {\n const oldValue = this._value;\n this._value = value;\n this._callbacks.forEach((callback) => callback(value, oldValue));\n }\n\n update(updater: (value: T) => T): T {\n const value = updater(this._value);\n this.set(value);\n return value;\n }\n\n onChange(callback: (value: T, oldValue: T | undefined) => void): { unsubscribe: () => void } {\n const uuid = generateUuid();\n this._callbacks.set(uuid, callback);\n return {\n unsubscribe: () => {\n this._callbacks.delete(uuid);\n },\n };\n }\n\n onceChange(callback: (value: T, oldValue: T | undefined) => void): { unsubscribe: () => void } {\n const { unsubscribe } = this.onChange((...args) => {\n unsubscribe();\n callback(...args);\n });\n return { unsubscribe };\n }\n}\n\nexport const storeLock = new ReadWriteLock();\n\n\nexport class AsyncStore<T> implements ReadonlyAsyncStore<T> {\n private _isAvailable: boolean;\n private _mostRecentOkValue: T | undefined = undefined;\n\n private _isRejected = false;\n private _rejectionError: unknown;\n private readonly _waitingRejectFunctions = new Map<string, ((error: unknown) => void)>();\n\n private readonly _callbacks: Map<string, AsyncStoreStateChangeCallback<T>> = new Map();\n\n private _updateCounter = 0;\n private _lastSuccessfulUpdate = -1;\n\n constructor(...args: [] | [T]) {\n if (args.length === 0) {\n this._isAvailable = false;\n } else {\n this._isAvailable = true;\n this._mostRecentOkValue = args[0];\n }\n }\n\n isAvailable(): boolean {\n return this._isAvailable;\n }\n\n isRejected(): boolean {\n return this._isRejected;\n }\n\n get() {\n if (this.isRejected()) {\n return AsyncResult.error(this._rejectionError);\n } else if (this.isAvailable()) {\n return AsyncResult.ok(this._mostRecentOkValue as T);\n } else {\n return AsyncResult.pending();\n }\n }\n\n getOrWait(): ReactPromise<T> {\n const uuid = generateUuid();\n if (this.isRejected()) {\n return rejected(this._rejectionError);\n } else if (this.isAvailable()) {\n return resolved(this._mostRecentOkValue as T);\n }\n const promise = new Promise<T>((resolve, reject) => {\n this.onceChange((value) => {\n resolve(value);\n });\n this._waitingRejectFunctions.set(uuid, reject);\n });\n const withFinally = promise.finally(() => {\n this._waitingRejectFunctions.delete(uuid);\n });\n return pending(withFinally);\n }\n\n _setIfLatest(result: Result<T>, curCounter: number) {\n const oldState = this.get();\n const oldValue = this._mostRecentOkValue;\n if (curCounter > this._lastSuccessfulUpdate) {\n switch (result.status) {\n case \"ok\": {\n if (!this._isAvailable || this._isRejected || this._mostRecentOkValue !== result.data) {\n this._lastSuccessfulUpdate = curCounter;\n this._isAvailable = true;\n this._isRejected = false;\n this._mostRecentOkValue = result.data;\n this._rejectionError = undefined;\n this._callbacks.forEach((callback) => callback({\n state: this.get(),\n oldState,\n lastOkValue: oldValue,\n }));\n return true;\n }\n return false;\n }\n case \"error\": {\n this._lastSuccessfulUpdate = curCounter;\n this._isAvailable = false;\n this._isRejected = true;\n this._rejectionError = result.error;\n this._waitingRejectFunctions.forEach((reject) => reject(result.error));\n this._callbacks.forEach((callback) => callback({\n state: this.get(),\n oldState,\n lastOkValue: oldValue,\n }));\n return true;\n }\n }\n }\n return false;\n }\n\n set(value: T): void {\n this._setIfLatest(Result.ok(value), ++this._updateCounter);\n }\n\n update(updater: (value: T | undefined) => T): T {\n const value = updater(this._mostRecentOkValue);\n this.set(value);\n return value;\n }\n\n async setAsync(promise: Promise<T>): Promise<boolean> {\n return await storeLock.withReadLock(async () => {\n const curCounter = ++this._updateCounter;\n const result = await Result.fromPromise(promise);\n return this._setIfLatest(result, curCounter);\n });\n }\n\n setUnavailable(): void {\n this._lastSuccessfulUpdate = ++this._updateCounter;\n this._isAvailable = false;\n this._isRejected = false;\n this._rejectionError = undefined;\n }\n\n setRejected(error: unknown): void {\n this._setIfLatest(Result.error(error), ++this._updateCounter);\n }\n\n map<U>(mapper: (value: T) => U): AsyncStore<U> {\n const store = new AsyncStore<U>();\n this.onChange((value) => {\n store.set(mapper(value));\n });\n return store;\n }\n\n onChange(callback: (value: T, oldValue: T | undefined) => void): { unsubscribe: () => void } {\n return this.onStateChange(({ state, lastOkValue }) => {\n if (state.status === \"ok\") {\n callback(state.data, lastOkValue);\n }\n });\n }\n\n onStateChange(callback: AsyncStoreStateChangeCallback<T>): { unsubscribe: () => void } {\n const uuid = generateUuid();\n this._callbacks.set(uuid, callback);\n return {\n unsubscribe: () => {\n this._callbacks.delete(uuid);\n },\n };\n }\n\n onceChange(callback: (value: T, oldValue: T | undefined) => void): { unsubscribe: () => void } {\n const { unsubscribe } = this.onChange((...args) => {\n unsubscribe();\n callback(...args);\n });\n return { unsubscribe };\n }\n\n onceStateChange(callback: AsyncStoreStateChangeCallback<T>): { unsubscribe: () => void } {\n const { unsubscribe } = this.onStateChange((...args) => {\n unsubscribe();\n callback(...args);\n });\n return { unsubscribe };\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/stores.tsx"],"sourcesContent":["import { ReadWriteLock } from \"./locks\";\nimport { ReactPromise, pending, rejected, resolved } from \"./promises\";\nimport { AsyncResult, Result } from \"./results\";\nimport { generateUuid } from \"./uuids\";\n\nexport type ReadonlyStore<T> = {\n get(): T,\n onChange(callback: (value: T, oldValue: T | undefined) => void): { unsubscribe: () => void },\n onceChange(callback: (value: T, oldValue: T | undefined) => void): { unsubscribe: () => void },\n};\n\nexport type AsyncStoreStateChangeCallback<T> = (args: { state: AsyncResult<T>, oldState: AsyncResult<T>, lastOkValue: T | undefined }) => void;\n\nexport type ReadonlyAsyncStore<T> = {\n isAvailable(): boolean,\n get(): AsyncResult<T, unknown, void>,\n getOrWait(): ReactPromise<T>,\n onChange(callback: (value: T, oldValue: T | undefined) => void): { unsubscribe: () => void },\n onceChange(callback: (value: T, oldValue: T | undefined) => void): { unsubscribe: () => void },\n onStateChange(callback: AsyncStoreStateChangeCallback<T>): { unsubscribe: () => void },\n onceStateChange(callback: AsyncStoreStateChangeCallback<T>): { unsubscribe: () => void },\n};\n\nexport class Store<T> implements ReadonlyStore<T> {\n private readonly _callbacks: Map<string, ((value: T, oldValue: T | undefined) => void)> = new Map();\n\n constructor(\n private _value: T\n ) {}\n\n get(): T {\n return this._value;\n }\n\n set(value: T): void {\n const oldValue = this._value;\n this._value = value;\n this._callbacks.forEach((callback) => callback(value, oldValue));\n }\n\n update(updater: (value: T) => T): T {\n const value = updater(this._value);\n this.set(value);\n return value;\n }\n\n onChange(callback: (value: T, oldValue: T | undefined) => void): { unsubscribe: () => void } {\n const uuid = generateUuid();\n this._callbacks.set(uuid, callback);\n return {\n unsubscribe: () => {\n this._callbacks.delete(uuid);\n },\n };\n }\n\n onceChange(callback: (value: T, oldValue: T | undefined) => void): { unsubscribe: () => void } {\n const { unsubscribe } = this.onChange((...args) => {\n unsubscribe();\n callback(...args);\n });\n return { unsubscribe };\n }\n}\n\nexport const storeLock = new ReadWriteLock();\n\n\nexport class AsyncStore<T> implements ReadonlyAsyncStore<T> {\n private _isAvailable: boolean;\n private _mostRecentOkValue: T | undefined = undefined;\n\n private _isRejected = false;\n private _rejectionError: unknown;\n private readonly _waitingRejectFunctions = new Map<string, ((error: unknown) => void)>();\n\n private readonly _callbacks: Map<string, AsyncStoreStateChangeCallback<T>> = new Map();\n\n private _updateCounter = 0;\n private _lastSuccessfulUpdate = -1;\n\n constructor(...args: [] | [T]) {\n if (args.length === 0) {\n this._isAvailable = false;\n } else {\n this._isAvailable = true;\n this._mostRecentOkValue = args[0];\n }\n }\n\n isAvailable(): boolean {\n return this._isAvailable;\n }\n\n isRejected(): boolean {\n return this._isRejected;\n }\n\n get() {\n if (this.isRejected()) {\n return AsyncResult.error(this._rejectionError);\n } else if (this.isAvailable()) {\n return AsyncResult.ok(this._mostRecentOkValue as T);\n } else {\n return AsyncResult.pending();\n }\n }\n\n getOrWait(): ReactPromise<T> {\n const uuid = generateUuid();\n if (this.isRejected()) {\n return rejected(this._rejectionError);\n } else if (this.isAvailable()) {\n return resolved(this._mostRecentOkValue as T);\n }\n const promise = new Promise<T>((resolve, reject) => {\n this.onceChange((value) => {\n resolve(value);\n });\n this._waitingRejectFunctions.set(uuid, reject);\n });\n const withFinally = promise.finally(() => {\n this._waitingRejectFunctions.delete(uuid);\n });\n return pending(withFinally);\n }\n\n _setIfLatest(result: Result<T>, curCounter: number) {\n const oldState = this.get();\n const oldValue = this._mostRecentOkValue;\n if (curCounter > this._lastSuccessfulUpdate) {\n switch (result.status) {\n case \"ok\": {\n if (!this._isAvailable || this._isRejected || this._mostRecentOkValue !== result.data) {\n this._lastSuccessfulUpdate = curCounter;\n this._isAvailable = true;\n this._isRejected = false;\n this._mostRecentOkValue = result.data;\n this._rejectionError = undefined;\n this._callbacks.forEach((callback) => callback({\n state: this.get(),\n oldState,\n lastOkValue: oldValue,\n }));\n return true;\n }\n return false;\n }\n case \"error\": {\n this._lastSuccessfulUpdate = curCounter;\n this._isAvailable = false;\n this._isRejected = true;\n this._rejectionError = result.error;\n this._waitingRejectFunctions.forEach((reject) => reject(result.error));\n this._callbacks.forEach((callback) => callback({\n state: this.get(),\n oldState,\n lastOkValue: oldValue,\n }));\n return true;\n }\n }\n }\n return false;\n }\n\n set(value: T): void {\n this._setIfLatest(Result.ok(value), ++this._updateCounter);\n }\n\n update(updater: (value: T | undefined) => T): T {\n const value = updater(this._mostRecentOkValue);\n this.set(value);\n return value;\n }\n\n async setAsync(promise: Promise<T>): Promise<boolean> {\n return await storeLock.withReadLock(async () => {\n const curCounter = ++this._updateCounter;\n const result = await Result.fromPromise(promise);\n return this._setIfLatest(result, curCounter);\n });\n }\n\n setUnavailable(): void {\n this._lastSuccessfulUpdate = ++this._updateCounter;\n this._mostRecentOkValue = undefined;\n this._isAvailable = false;\n this._isRejected = false;\n this._rejectionError = undefined;\n }\n\n setRejected(error: unknown): void {\n this._setIfLatest(Result.error(error), ++this._updateCounter);\n }\n\n map<U>(mapper: (value: T) => U): AsyncStore<U> {\n const store = new AsyncStore<U>();\n this.onChange((value) => {\n store.set(mapper(value));\n });\n return store;\n }\n\n onChange(callback: (value: T, oldValue: T | undefined) => void): { unsubscribe: () => void } {\n return this.onStateChange(({ state, lastOkValue }) => {\n if (state.status === \"ok\") {\n callback(state.data, lastOkValue);\n }\n });\n }\n\n onStateChange(callback: AsyncStoreStateChangeCallback<T>): { unsubscribe: () => void } {\n const uuid = generateUuid();\n this._callbacks.set(uuid, callback);\n return {\n unsubscribe: () => {\n this._callbacks.delete(uuid);\n },\n };\n }\n\n onceChange(callback: (value: T, oldValue: T | undefined) => void): { unsubscribe: () => void } {\n const { unsubscribe } = this.onChange((...args) => {\n unsubscribe();\n callback(...args);\n });\n return { unsubscribe };\n }\n\n onceStateChange(callback: AsyncStoreStateChangeCallback<T>): { unsubscribe: () => void } {\n const { unsubscribe } = this.onStateChange((...args) => {\n unsubscribe();\n callback(...args);\n });\n return { unsubscribe };\n }\n}\n"],"mappings":"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","names":[]}
|