@livestore/react 0.3.1 → 0.3.2-dev.1
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/dist/.tsbuildinfo +1 -1
- package/dist/LiveStoreContext.d.ts +2 -2
- package/dist/LiveStoreProvider.d.ts +5 -6
- package/dist/LiveStoreProvider.d.ts.map +1 -1
- package/dist/LiveStoreProvider.js +8 -7
- package/dist/LiveStoreProvider.js.map +1 -1
- package/dist/LiveStoreProvider.test.js +3 -2
- package/dist/LiveStoreProvider.test.js.map +1 -1
- package/dist/experimental/components/LiveList.js +1 -1
- package/dist/experimental/mod.d.ts +1 -1
- package/dist/experimental/mod.js +1 -1
- package/dist/mod.d.ts +6 -6
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +6 -6
- package/dist/mod.js.map +1 -1
- package/dist/useClientDocument.js +3 -3
- package/dist/useClientDocument.js.map +1 -1
- package/dist/useClientDocument.test.js +6 -1
- package/dist/useClientDocument.test.js.map +1 -1
- package/dist/useQuery.d.ts.map +1 -1
- package/dist/useQuery.js +8 -6
- package/dist/useQuery.js.map +1 -1
- package/dist/useQuery.test.d.ts +1 -0
- package/dist/useQuery.test.d.ts.map +1 -1
- package/dist/useQuery.test.js +2 -2
- package/dist/useQuery.test.js.map +1 -1
- package/dist/useRcResource.d.ts.map +1 -1
- package/dist/useRcResource.js +2 -6
- package/dist/useRcResource.js.map +1 -1
- package/dist/useStore.d.ts +1 -1
- package/dist/useStore.js +4 -6
- package/dist/useStore.js.map +1 -1
- package/dist/utils/stack-info.js +0 -1
- package/dist/utils/stack-info.js.map +1 -1
- package/dist/utils/useStateRefWithReactiveInput.d.ts.map +1 -1
- package/dist/utils/useStateRefWithReactiveInput.js +1 -1
- package/dist/utils/useStateRefWithReactiveInput.js.map +1 -1
- package/package.json +8 -8
- package/src/LiveStoreContext.ts +2 -2
- package/src/LiveStoreProvider.test.tsx +4 -2
- package/src/LiveStoreProvider.tsx +22 -23
- package/src/__snapshots__/useClientDocument.test.tsx.snap +2 -2
- package/src/ambient.d.ts +0 -1
- package/src/experimental/components/LiveList.tsx +1 -1
- package/src/experimental/mod.ts +1 -1
- package/src/mod.ts +9 -9
- package/src/useClientDocument.test.tsx +6 -2
- package/src/useClientDocument.ts +3 -3
- package/src/useQuery.test.tsx +2 -2
- package/src/useQuery.ts +8 -7
- package/src/useRcResource.ts +2 -6
- package/src/useStore.ts +7 -7
- package/src/utils/stack-info.ts +1 -1
- package/src/utils/useStateRefWithReactiveInput.ts +6 -9
package/dist/useStore.js
CHANGED
@@ -1,13 +1,11 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import { LiveStoreContext } from
|
3
|
-
import { useClientDocument } from
|
4
|
-
import { useQuery } from
|
2
|
+
import { LiveStoreContext } from "./LiveStoreContext.js";
|
3
|
+
import { useClientDocument } from "./useClientDocument.js";
|
4
|
+
import { useQuery } from "./useQuery.js";
|
5
5
|
export const withReactApi = (store) => {
|
6
6
|
// @ts-expect-error TODO properly implement this
|
7
|
-
// eslint-disable-next-line react-hooks/rules-of-hooks
|
8
7
|
store.useQuery = (queryDef) => useQuery(queryDef, { store });
|
9
8
|
// @ts-expect-error TODO properly implement this
|
10
|
-
// eslint-disable-next-line react-hooks/rules-of-hooks
|
11
9
|
store.useClientDocument = (table, idOrOptions, options) => useClientDocument(table, idOrOptions, options, { store });
|
12
10
|
return store;
|
13
11
|
};
|
@@ -15,7 +13,7 @@ export const useStore = (options) => {
|
|
15
13
|
if (options?.store !== undefined) {
|
16
14
|
return { store: withReactApi(options.store) };
|
17
15
|
}
|
18
|
-
//
|
16
|
+
// biome-ignore lint/correctness/useHookAtTopLevel: store is stable
|
19
17
|
const storeContext = React.useContext(LiveStoreContext);
|
20
18
|
if (storeContext === undefined) {
|
21
19
|
throw new Error(`useStore can only be used inside StoreContext.Provider`);
|
package/dist/useStore.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"useStore.js","sourceRoot":"","sources":["../src/useStore.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAExC,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,KAAY,EAAoB,EAAE;IAC7D,gDAAgD;
|
1
|
+
{"version":3,"file":"useStore.js","sourceRoot":"","sources":["../src/useStore.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAExC,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,KAAY,EAAoB,EAAE;IAC7D,gDAAgD;IAEhD,KAAK,CAAC,QAAQ,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;IAC5D,gDAAgD;IAEhD,KAAK,CAAC,iBAAiB,GAAG,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC,iBAAiB,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;IACpH,OAAO,KAAyB,CAAA;AAClC,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,OAA2B,EAA+B,EAAE;IACnF,IAAI,OAAO,EAAE,KAAK,KAAK,SAAS,EAAE,CAAC;QACjC,OAAO,EAAE,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAA;IAC/C,CAAC;IAED,mEAAmE;IACnE,MAAM,YAAY,GAAG,KAAK,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAA;IAEvD,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAA;IAC3E,CAAC;IAED,IAAI,YAAY,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAA;IACzE,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,YAAY,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAA;AACpD,CAAC,CAAA"}
|
package/dist/utils/stack-info.js
CHANGED
@@ -3,7 +3,6 @@ import React from 'react';
|
|
3
3
|
export const originalStackLimit = Error.stackTraceLimit;
|
4
4
|
export const useStackInfo = () => React.useMemo(() => {
|
5
5
|
Error.stackTraceLimit = 10;
|
6
|
-
// eslint-disable-next-line unicorn/error-message
|
7
6
|
const stack = new Error().stack;
|
8
7
|
Error.stackTraceLimit = originalStackLimit;
|
9
8
|
return extractStackInfoFromStackTrace(stack);
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"stack-info.js","sourceRoot":"","sources":["../../src/utils/stack-info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAkB,MAAM,sBAAsB,CAAA;AACrF,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,CAAC,eAAe,CAAA;AAEvD,MAAM,CAAC,MAAM,YAAY,GAAG,GAAc,EAAE,CAC1C,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;IACjB,KAAK,CAAC,eAAe,GAAG,EAAE,CAAA;
|
1
|
+
{"version":3,"file":"stack-info.js","sourceRoot":"","sources":["../../src/utils/stack-info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAkB,MAAM,sBAAsB,CAAA;AACrF,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,CAAC,eAAe,CAAA;AAEvD,MAAM,CAAC,MAAM,YAAY,GAAG,GAAc,EAAE,CAC1C,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;IACjB,KAAK,CAAC,eAAe,GAAG,EAAE,CAAA;IAE1B,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC,KAAM,CAAA;IAChC,KAAK,CAAC,eAAe,GAAG,kBAAkB,CAAA;IAC1C,OAAO,8BAA8B,CAAC,KAAK,CAAC,CAAA;AAC9C,CAAC,EAAE,EAAE,CAAC,CAAA"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"useStateRefWithReactiveInput.d.ts","sourceRoot":"","sources":["../../src/utils/useStateRefWithReactiveInput.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB;;;;;;;;;GASG;AACH,eAAO,MAAM,4BAA4B,GAAI,CAAC,EAC5C,YAAY,CAAC,KACZ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,
|
1
|
+
{"version":3,"file":"useStateRefWithReactiveInput.d.ts","sourceRoot":"","sources":["../../src/utils/useStateRefWithReactiveInput.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB;;;;;;;;;GASG;AACH,eAAO,MAAM,4BAA4B,GAAI,CAAC,EAC5C,YAAY,CAAC,KACZ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,CAqB/D,CAAA"}
|
@@ -23,7 +23,7 @@ export const useStateRefWithReactiveInput = (inputState) => {
|
|
23
23
|
const val = typeof newState === 'function' ? newState(stateRef.current) : newState;
|
24
24
|
stateRef.current = val;
|
25
25
|
rerender((c) => c + 1);
|
26
|
-
}, [
|
26
|
+
}, []);
|
27
27
|
return [stateRef, setStateAndRerender];
|
28
28
|
};
|
29
29
|
// Down-side of this implementation: Double render pass due to `setState` call (which forces a re-render)
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"useStateRefWithReactiveInput.js","sourceRoot":"","sources":["../../src/utils/useStateRefWithReactiveInput.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAC1C,UAAa,EACmD,EAAE;IAClE,MAAM,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;IAEvC,MAAM,sBAAsB,GAAG,KAAK,CAAC,MAAM,CAAI,UAAU,CAAC,CAAA;IAC1D,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAI,UAAU,CAAC,CAAA;IAE5C,IAAI,sBAAsB,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;QAClD,sBAAsB,CAAC,OAAO,GAAG,UAAU,CAAA;QAE3C,qHAAqH;QACrH,QAAQ,CAAC,OAAO,GAAG,UAAU,CAAA;IAC/B,CAAC;IAED,MAAM,mBAAmB,GAAG,KAAK,CAAC,WAAW,
|
1
|
+
{"version":3,"file":"useStateRefWithReactiveInput.js","sourceRoot":"","sources":["../../src/utils/useStateRefWithReactiveInput.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAC1C,UAAa,EACmD,EAAE;IAClE,MAAM,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;IAEvC,MAAM,sBAAsB,GAAG,KAAK,CAAC,MAAM,CAAI,UAAU,CAAC,CAAA;IAC1D,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAI,UAAU,CAAC,CAAA;IAE5C,IAAI,sBAAsB,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;QAClD,sBAAsB,CAAC,OAAO,GAAG,UAAU,CAAA;QAE3C,qHAAqH;QACrH,QAAQ,CAAC,OAAO,GAAG,UAAU,CAAA;IAC/B,CAAC;IAED,MAAM,mBAAmB,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,QAA8B,EAAE,EAAE;QAC/E,wEAAwE;QACxE,MAAM,GAAG,GAAG,OAAO,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAA;QAClF,QAAQ,CAAC,OAAO,GAAG,GAAG,CAAA;QACtB,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IACxB,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,OAAO,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAA;AACxC,CAAC,CAAA;AAED,yGAAyG;AACzG,iFAAiF;AACjF,4GAA4G;AAC5G,yEAAyE;AAEzE,wCAAwC;AACxC,mCAAmC;AACnC,MAAM;AAEN,6CAA6C;AAC7C,IAAI"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@livestore/react",
|
3
|
-
"version": "0.3.1",
|
3
|
+
"version": "0.3.2-dev.1",
|
4
4
|
"type": "module",
|
5
5
|
"sideEffects": false,
|
6
6
|
"exports": {
|
@@ -23,9 +23,9 @@
|
|
23
23
|
},
|
24
24
|
"dependencies": {
|
25
25
|
"@opentelemetry/api": "1.9.0",
|
26
|
-
"@livestore/
|
27
|
-
"@livestore/
|
28
|
-
"@livestore/
|
26
|
+
"@livestore/common": "0.3.2-dev.1",
|
27
|
+
"@livestore/utils": "0.3.2-dev.1",
|
28
|
+
"@livestore/livestore": "0.3.2-dev.1"
|
29
29
|
},
|
30
30
|
"devDependencies": {
|
31
31
|
"@opentelemetry/sdk-trace-base": "^2.0.0",
|
@@ -38,10 +38,10 @@
|
|
38
38
|
"react-dom": "^19.0.0",
|
39
39
|
"react-window": "^1.8.11",
|
40
40
|
"typescript": "^5.8.3",
|
41
|
-
"vite": "^
|
42
|
-
"vitest": "
|
43
|
-
"@livestore/
|
44
|
-
"@livestore/
|
41
|
+
"vite": "^7.0.0",
|
42
|
+
"vitest": "3.2.4",
|
43
|
+
"@livestore/utils-dev": "0.3.2-dev.1",
|
44
|
+
"@livestore/adapter-web": "0.3.2-dev.1"
|
45
45
|
},
|
46
46
|
"files": [
|
47
47
|
"package.json",
|
package/src/LiveStoreContext.ts
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
import type { LiveStoreContextRunning } from '@livestore/livestore'
|
2
2
|
import React from 'react'
|
3
3
|
|
4
|
-
import type { useClientDocument } from './useClientDocument.
|
5
|
-
import type { useQuery } from './useQuery.
|
4
|
+
import type { useClientDocument } from './useClientDocument.ts'
|
5
|
+
import type { useQuery } from './useQuery.ts'
|
6
6
|
|
7
7
|
export type ReactApi = {
|
8
8
|
useQuery: typeof useQuery
|
@@ -1,3 +1,4 @@
|
|
1
|
+
/** biome-ignore-all lint/a11y: test */
|
1
2
|
import { makeInMemoryAdapter } from '@livestore/adapter-web'
|
2
3
|
import { sql } from '@livestore/common'
|
3
4
|
import { rawSqlEvent } from '@livestore/common/schema'
|
@@ -41,7 +42,8 @@ describe.each([true, false])('LiveStoreProvider (strictMode: %s)', (strictMode)
|
|
41
42
|
),
|
42
43
|
[],
|
43
44
|
)
|
44
|
-
|
45
|
+
|
46
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: forceUpdate is used to force a re-render
|
45
47
|
const adapterMemo = React.useMemo(() => makeInMemoryAdapter(), [forceUpdate])
|
46
48
|
return (
|
47
49
|
<WithStrictMode>
|
@@ -104,7 +106,7 @@ describe.each([true, false])('LiveStoreProvider (strictMode: %s)', (strictMode)
|
|
104
106
|
),
|
105
107
|
[],
|
106
108
|
)
|
107
|
-
//
|
109
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: forceUpdate is used to force a re-render
|
108
110
|
const adapterMemo = React.useMemo(() => makeInMemoryAdapter(), [forceUpdate])
|
109
111
|
return (
|
110
112
|
<WithStrictMode>
|
@@ -3,10 +3,10 @@ import { provideOtel, UnexpectedError } from '@livestore/common'
|
|
3
3
|
import type { LiveStoreSchema } from '@livestore/common/schema'
|
4
4
|
import type {
|
5
5
|
CreateStoreOptions,
|
6
|
-
LiveStoreContext as StoreContext_,
|
7
6
|
OtelOptions,
|
8
7
|
ShutdownDeferred,
|
9
8
|
Store,
|
9
|
+
LiveStoreContext as StoreContext_,
|
10
10
|
} from '@livestore/livestore'
|
11
11
|
import { createStore, makeShutdownDeferred, StoreInterrupted } from '@livestore/livestore'
|
12
12
|
import { errorToString, IS_REACT_NATIVE, LS_DEV } from '@livestore/utils'
|
@@ -24,7 +24,6 @@ import {
|
|
24
24
|
TaskTracing,
|
25
25
|
} from '@livestore/utils/effect'
|
26
26
|
import type * as otel from '@opentelemetry/api'
|
27
|
-
import type { ReactElement, ReactNode } from 'react'
|
28
27
|
import React from 'react'
|
29
28
|
|
30
29
|
import { LiveStoreContext } from './LiveStoreContext.js'
|
@@ -47,9 +46,9 @@ export interface LiveStoreProviderProps {
|
|
47
46
|
ctx: { migrationsReport: MigrationsReport; parentSpan: otel.Span },
|
48
47
|
) => void | Promise<void> | Effect.Effect<void, unknown, OtelTracer.OtelTracer>
|
49
48
|
otelOptions?: Partial<OtelOptions>
|
50
|
-
renderLoading?: (status: BootStatus) =>
|
51
|
-
renderError?: (error: UnexpectedError | unknown) =>
|
52
|
-
renderShutdown?: (cause: IntentionalShutdownCause | StoreInterrupted) =>
|
49
|
+
renderLoading?: (status: BootStatus) => React.ReactNode
|
50
|
+
renderError?: (error: UnexpectedError | unknown) => React.ReactNode
|
51
|
+
renderShutdown?: (cause: IntentionalShutdownCause | StoreInterrupted) => React.ReactNode
|
53
52
|
adapter: Adapter
|
54
53
|
/**
|
55
54
|
* In order for LiveStore to apply multiple events in a single render,
|
@@ -85,7 +84,7 @@ export interface LiveStoreProviderProps {
|
|
85
84
|
}
|
86
85
|
|
87
86
|
const defaultRenderError = (error: UnexpectedError | unknown) =>
|
88
|
-
IS_REACT_NATIVE ?
|
87
|
+
IS_REACT_NATIVE ? null : Schema.is(UnexpectedError)(error) ? error.toString() : errorToString(error)
|
89
88
|
|
90
89
|
const defaultRenderShutdown = (cause: IntentionalShutdownCause | StoreInterrupted) => {
|
91
90
|
const reason =
|
@@ -101,11 +100,11 @@ const defaultRenderShutdown = (cause: IntentionalShutdownCause | StoreInterrupte
|
|
101
100
|
? 'manual shutdown'
|
102
101
|
: 'unknown reason'
|
103
102
|
|
104
|
-
return IS_REACT_NATIVE ?
|
103
|
+
return IS_REACT_NATIVE ? null : <>LiveStore Shutdown due to {reason}</>
|
105
104
|
}
|
106
105
|
|
107
106
|
const defaultRenderLoading = (status: BootStatus) =>
|
108
|
-
IS_REACT_NATIVE ?
|
107
|
+
IS_REACT_NATIVE ? null : <>LiveStore is loading ({status.stage})...</>
|
109
108
|
|
110
109
|
export const LiveStoreProvider = ({
|
111
110
|
renderLoading = defaultRenderLoading,
|
@@ -123,7 +122,7 @@ export const LiveStoreProvider = ({
|
|
123
122
|
confirmUnsavedChanges = true,
|
124
123
|
syncPayload,
|
125
124
|
debug,
|
126
|
-
}: LiveStoreProviderProps & { children?: ReactNode }): React.
|
125
|
+
}: LiveStoreProviderProps & { children?: React.ReactNode }): React.ReactNode => {
|
127
126
|
const storeCtx = useCreateStore({
|
128
127
|
storeId,
|
129
128
|
schema,
|
@@ -152,7 +151,7 @@ export const LiveStoreProvider = ({
|
|
152
151
|
|
153
152
|
globalThis.__debugLiveStore ??= {}
|
154
153
|
if (Object.keys(globalThis.__debugLiveStore).length === 0) {
|
155
|
-
globalThis.__debugLiveStore
|
154
|
+
globalThis.__debugLiveStore._ = storeCtx.store
|
156
155
|
}
|
157
156
|
globalThis.__debugLiveStore[debug?.instanceId ?? storeId] = storeCtx.store
|
158
157
|
|
@@ -211,19 +210,18 @@ const useCreateStore = ({
|
|
211
210
|
debugInstanceId,
|
212
211
|
})
|
213
212
|
|
214
|
-
const interrupt = (
|
215
|
-
componentScope: Scope.CloseableScope,
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
)
|
213
|
+
const interrupt = React.useCallback(
|
214
|
+
(componentScope: Scope.CloseableScope, shutdownDeferred: ShutdownDeferred, error: StoreInterrupted) =>
|
215
|
+
Effect.gen(function* () {
|
216
|
+
// console.log('[@livestore/livestore/react] interupting', error)
|
217
|
+
yield* Scope.close(componentScope, Exit.fail(error))
|
218
|
+
yield* Deferred.fail(shutdownDeferred, error)
|
219
|
+
}).pipe(
|
220
|
+
Effect.tapErrorCause((cause) => Effect.logDebug('[@livestore/livestore/react] interupting', cause)),
|
221
|
+
Effect.runFork,
|
222
|
+
),
|
223
|
+
[],
|
224
|
+
)
|
227
225
|
|
228
226
|
const inputPropChanges = {
|
229
227
|
schema: inputPropsCacheRef.current.schema !== schema,
|
@@ -400,6 +398,7 @@ const useCreateStore = ({
|
|
400
398
|
confirmUnsavedChanges,
|
401
399
|
syncPayload,
|
402
400
|
debugInstanceId,
|
401
|
+
interrupt,
|
403
402
|
])
|
404
403
|
|
405
404
|
return ctxValueRef.current.value
|
@@ -37,7 +37,7 @@ exports[`useClientDocument > otel > should update the data based on component ke
|
|
37
37
|
{
|
38
38
|
"_name": "client-session-sync-processor:pull",
|
39
39
|
"attributes": {
|
40
|
-
"code.stacktrace": "
|
40
|
+
"code.stacktrace": "<STACKTRACE>",
|
41
41
|
"span.label": "⚠︎ Interrupted",
|
42
42
|
"status.interrupted": true,
|
43
43
|
},
|
@@ -263,7 +263,7 @@ exports[`useClientDocument > otel > should update the data based on component ke
|
|
263
263
|
{
|
264
264
|
"_name": "client-session-sync-processor:pull",
|
265
265
|
"attributes": {
|
266
|
-
"code.stacktrace": "
|
266
|
+
"code.stacktrace": "<STACKTRACE>",
|
267
267
|
"span.label": "⚠︎ Interrupted",
|
268
268
|
"status.interrupted": true,
|
269
269
|
},
|
package/src/ambient.d.ts
CHANGED
@@ -81,7 +81,7 @@ const ItemWrapperMemo = React.memo(
|
|
81
81
|
ItemWrapper,
|
82
82
|
(prev, next) =>
|
83
83
|
prev.itemKey === next.itemKey &&
|
84
|
-
prev.renderItem ===
|
84
|
+
prev.renderItem === next.renderItem &&
|
85
85
|
prev.opts.index === next.opts.index &&
|
86
86
|
prev.opts.isInitialListRender === next.opts.isInitialListRender,
|
87
87
|
) as typeof ItemWrapper
|
package/src/experimental/mod.ts
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export { LiveList, type LiveListProps } from './components/LiveList.
|
1
|
+
export { LiveList, type LiveListProps } from './components/LiveList.ts'
|
package/src/mod.ts
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
export { LiveStoreContext, type ReactApi } from './LiveStoreContext.
|
2
|
-
export {
|
3
|
-
export { LiveStoreProvider } from './LiveStoreProvider.js'
|
4
|
-
export { useStackInfo } from './utils/stack-info.js'
|
5
|
-
export { useQuery, useQueryRef } from './useQuery.js'
|
1
|
+
export { LiveStoreContext, type ReactApi } from './LiveStoreContext.ts'
|
2
|
+
export { LiveStoreProvider } from './LiveStoreProvider.ts'
|
6
3
|
export {
|
7
|
-
useClientDocument,
|
8
|
-
type StateSetters,
|
9
|
-
type SetStateAction,
|
10
4
|
type Dispatch,
|
5
|
+
type SetStateAction,
|
6
|
+
type StateSetters,
|
11
7
|
type UseRowResult as UseStateResult,
|
12
|
-
|
8
|
+
useClientDocument,
|
9
|
+
} from './useClientDocument.ts'
|
10
|
+
export { useQuery, useQueryRef } from './useQuery.ts'
|
11
|
+
export { useStore, withReactApi } from './useStore.ts'
|
12
|
+
export { useStackInfo } from './utils/stack-info.ts'
|
@@ -1,3 +1,5 @@
|
|
1
|
+
/** biome-ignore-all lint/a11y/useValidAriaRole: not needed for testing */
|
2
|
+
/** biome-ignore-all lint/a11y/noStaticElementInteractions: not needed for testing */
|
1
3
|
import * as LiveStore from '@livestore/livestore'
|
2
4
|
import { getSimplifiedRootSpan } from '@livestore/livestore/internal/testing-utils'
|
3
5
|
import { Effect, ReadonlyRecord, Schema } from '@livestore/utils/effect'
|
@@ -5,7 +7,7 @@ import { Vitest } from '@livestore/utils-dev/node-vitest'
|
|
5
7
|
import * as otel from '@opentelemetry/api'
|
6
8
|
import { BasicTracerProvider, InMemorySpanExporter, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'
|
7
9
|
import * as ReactTesting from '@testing-library/react'
|
8
|
-
import React from 'react'
|
10
|
+
import type React from 'react'
|
9
11
|
import { beforeEach, expect, it } from 'vitest'
|
10
12
|
|
11
13
|
import { events, makeTodoMvcReact, tables } from './__tests__/fixture.js'
|
@@ -282,7 +284,9 @@ Vitest.describe('useClientDocument', () => {
|
|
282
284
|
|
283
285
|
const mapAttributes = (attributes: otel.Attributes) => {
|
284
286
|
return ReadonlyRecord.map(attributes, (val, key) => {
|
285
|
-
if (key === '
|
287
|
+
if (key === 'code.stacktrace') {
|
288
|
+
return '<STACKTRACE>'
|
289
|
+
} else if (key === 'firstStackInfo') {
|
286
290
|
const stackInfo = JSON.parse(val as string) as LiveStore.StackInfo
|
287
291
|
// stackInfo.frames.shift() // Removes `renderHook.wrapper` from the stack
|
288
292
|
stackInfo.frames.forEach((_) => {
|
package/src/useClientDocument.ts
CHANGED
@@ -6,8 +6,8 @@ import { queryDb } from '@livestore/livestore'
|
|
6
6
|
import { shouldNeverHappen } from '@livestore/utils'
|
7
7
|
import React from 'react'
|
8
8
|
|
9
|
-
import { LiveStoreContext } from './LiveStoreContext.
|
10
|
-
import { useQueryRef } from './useQuery.
|
9
|
+
import { LiveStoreContext } from './LiveStoreContext.ts'
|
10
|
+
import { useQueryRef } from './useQuery.ts'
|
11
11
|
|
12
12
|
export type UseRowResult<TTableDef extends State.SQLite.ClientDocumentTableDef.TraitAny> = [
|
13
13
|
row: TTableDef['Value'],
|
@@ -98,7 +98,7 @@ export const useClientDocument: {
|
|
98
98
|
|
99
99
|
const store =
|
100
100
|
storeArg?.store ??
|
101
|
-
//
|
101
|
+
// biome-ignore lint/correctness/useHookAtTopLevel: store is stable
|
102
102
|
React.useContext(LiveStoreContext)?.store ??
|
103
103
|
shouldNeverHappen(`No store provided to useClientDocument`)
|
104
104
|
|
package/src/useQuery.test.tsx
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
+
/** biome-ignore-all lint/a11y: test */
|
1
2
|
import '@livestore/utils-dev/node-vitest-polyfill'
|
2
3
|
|
3
|
-
import { queryDb, signal } from '@livestore/livestore'
|
4
4
|
import * as LiveStore from '@livestore/livestore'
|
5
|
+
import { queryDb, signal } from '@livestore/livestore'
|
5
6
|
import { RG } from '@livestore/livestore/internal/testing-utils'
|
6
7
|
import { Effect, Schema } from '@livestore/utils/effect'
|
7
8
|
import { Vitest } from '@livestore/utils-dev/node-vitest'
|
@@ -161,7 +162,6 @@ Vitest.describe.each([{ strictMode: true }, { strictMode: false }] as const)(
|
|
161
162
|
const ListItem: React.FC<{ data: ReadonlyArray<number>; index: number }> = ({ data: ids, index }) => {
|
162
163
|
const id = ids[index]!
|
163
164
|
const res = store.useQuery(LiveStore.computed(() => id, { label: `ListItem.${id}`, deps: id }))
|
164
|
-
// biome-ignore lint/a11y/useSemanticElements: <explanation>
|
165
165
|
return <div role="listitem">{res}</div>
|
166
166
|
}
|
167
167
|
|
package/src/useQuery.ts
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
/* eslint-disable react-hooks/rules-of-hooks */
|
2
1
|
import type { LiveQuery, LiveQueryDef, Store } from '@livestore/livestore'
|
3
2
|
import { extractStackInfoFromStackTrace, stackInfoToString } from '@livestore/livestore'
|
4
3
|
import type { LiveQueries } from '@livestore/livestore/internal'
|
@@ -6,10 +5,10 @@ import { deepEqual, indent, shouldNeverHappen } from '@livestore/utils'
|
|
6
5
|
import * as otel from '@opentelemetry/api'
|
7
6
|
import React from 'react'
|
8
7
|
|
9
|
-
import { LiveStoreContext } from './LiveStoreContext.
|
10
|
-
import { useRcResource } from './useRcResource.
|
11
|
-
import { originalStackLimit } from './utils/stack-info.
|
12
|
-
import { useStateRefWithReactiveInput } from './utils/useStateRefWithReactiveInput.
|
8
|
+
import { LiveStoreContext } from './LiveStoreContext.ts'
|
9
|
+
import { useRcResource } from './useRcResource.ts'
|
10
|
+
import { originalStackLimit } from './utils/stack-info.ts'
|
11
|
+
import { useStateRefWithReactiveInput } from './utils/useStateRefWithReactiveInput.ts'
|
13
12
|
|
14
13
|
/**
|
15
14
|
* Returns the result of a query and subscribes to future updates.
|
@@ -43,14 +42,16 @@ export const useQueryRef = <TQuery extends LiveQueryDef.Any>(
|
|
43
42
|
queryRcRef: LiveQueries.RcRef<LiveQuery<LiveQueries.GetResult<TQuery>>>
|
44
43
|
} => {
|
45
44
|
const store =
|
46
|
-
options?.store ??
|
45
|
+
options?.store ??
|
46
|
+
// biome-ignore lint/correctness/useHookAtTopLevel: store is stable
|
47
|
+
React.useContext(LiveStoreContext)?.store ??
|
48
|
+
shouldNeverHappen(`No store provided to useQuery`)
|
47
49
|
|
48
50
|
// It's important to use all "aspects" of a store instance here, otherwise we get unexpected cache mappings
|
49
51
|
const rcRefKey = `${store.storeId}_${store.clientId}_${store.sessionId}_${queryDef.hash}`
|
50
52
|
|
51
53
|
const stackInfo = React.useMemo(() => {
|
52
54
|
Error.stackTraceLimit = 10
|
53
|
-
// eslint-disable-next-line unicorn/error-message
|
54
55
|
const stack = new Error().stack!
|
55
56
|
Error.stackTraceLimit = originalStackLimit
|
56
57
|
return extractStackInfoFromStackTrace(stack)
|
package/src/useRcResource.ts
CHANGED
@@ -80,7 +80,7 @@ export const useRcResource = <T>(
|
|
80
80
|
const keyRef = React.useRef<string | undefined>(undefined)
|
81
81
|
const didDisposeInMemo = React.useRef(false)
|
82
82
|
|
83
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies:
|
83
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: Dependency is deliberately limited to `key` to avoid unintended re-creations.
|
84
84
|
const resource = React.useMemo(() => {
|
85
85
|
// console.debug('useMemo', key)
|
86
86
|
if (didDisposeInMemo.current) {
|
@@ -125,11 +125,9 @@ export const useRcResource = <T>(
|
|
125
125
|
const resource = create()
|
126
126
|
cache.set(key, { _tag: 'active', rc: 1, resource })
|
127
127
|
return resource
|
128
|
-
// Dependency is deliberately limited to `key` to avoid unintended re-creations.
|
129
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
130
128
|
}, [key])
|
131
129
|
|
132
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies:
|
130
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: We assume the `dispose` function is stable and won't change across renders
|
133
131
|
React.useEffect(() => {
|
134
132
|
return () => {
|
135
133
|
if (didDisposeInMemo.current) {
|
@@ -152,8 +150,6 @@ export const useRcResource = <T>(
|
|
152
150
|
cache.delete(key)
|
153
151
|
}
|
154
152
|
}
|
155
|
-
// We assume the `dispose` function is stable and won't change across renders
|
156
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
157
153
|
}, [key])
|
158
154
|
|
159
155
|
keyRef.current = key
|
package/src/useStore.ts
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
import type { Store } from '@livestore/livestore'
|
2
2
|
import React from 'react'
|
3
3
|
|
4
|
-
import type { ReactApi } from './LiveStoreContext.
|
5
|
-
import { LiveStoreContext } from './LiveStoreContext.
|
6
|
-
import { useClientDocument } from './useClientDocument.
|
7
|
-
import { useQuery } from './useQuery.
|
4
|
+
import type { ReactApi } from './LiveStoreContext.ts'
|
5
|
+
import { LiveStoreContext } from './LiveStoreContext.ts'
|
6
|
+
import { useClientDocument } from './useClientDocument.ts'
|
7
|
+
import { useQuery } from './useQuery.ts'
|
8
8
|
|
9
9
|
export const withReactApi = (store: Store): Store & ReactApi => {
|
10
10
|
// @ts-expect-error TODO properly implement this
|
11
|
-
|
11
|
+
|
12
12
|
store.useQuery = (queryDef) => useQuery(queryDef, { store })
|
13
13
|
// @ts-expect-error TODO properly implement this
|
14
|
-
|
14
|
+
|
15
15
|
store.useClientDocument = (table, idOrOptions, options) => useClientDocument(table, idOrOptions, options, { store })
|
16
16
|
return store as Store & ReactApi
|
17
17
|
}
|
@@ -21,7 +21,7 @@ export const useStore = (options?: { store?: Store }): { store: Store & ReactApi
|
|
21
21
|
return { store: withReactApi(options.store) }
|
22
22
|
}
|
23
23
|
|
24
|
-
//
|
24
|
+
// biome-ignore lint/correctness/useHookAtTopLevel: store is stable
|
25
25
|
const storeContext = React.useContext(LiveStoreContext)
|
26
26
|
|
27
27
|
if (storeContext === undefined) {
|
package/src/utils/stack-info.ts
CHANGED
@@ -6,7 +6,7 @@ export const originalStackLimit = Error.stackTraceLimit
|
|
6
6
|
export const useStackInfo = (): StackInfo =>
|
7
7
|
React.useMemo(() => {
|
8
8
|
Error.stackTraceLimit = 10
|
9
|
-
|
9
|
+
|
10
10
|
const stack = new Error().stack!
|
11
11
|
Error.stackTraceLimit = originalStackLimit
|
12
12
|
return extractStackInfoFromStackTrace(stack)
|
@@ -25,15 +25,12 @@ export const useStateRefWithReactiveInput = <T>(
|
|
25
25
|
stateRef.current = inputState
|
26
26
|
}
|
27
27
|
|
28
|
-
const setStateAndRerender = React.useCallback(
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
},
|
35
|
-
[rerender],
|
36
|
-
)
|
28
|
+
const setStateAndRerender = React.useCallback((newState: ((prev: T) => T) | T) => {
|
29
|
+
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/37663
|
30
|
+
const val = typeof newState === 'function' ? newState(stateRef.current) : newState
|
31
|
+
stateRef.current = val
|
32
|
+
rerender((c) => c + 1)
|
33
|
+
}, [])
|
37
34
|
|
38
35
|
return [stateRef, setStateAndRerender]
|
39
36
|
}
|