@livestore/solid 0.4.0-dev.22 → 0.4.0-dev.24
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/StoreRegistryContext.d.ts +56 -0
- package/dist/StoreRegistryContext.d.ts.map +1 -0
- package/dist/StoreRegistryContext.jsx +60 -0
- package/dist/StoreRegistryContext.jsx.map +1 -0
- package/dist/__tests__/fixture.d.ts +14 -0
- package/dist/__tests__/fixture.d.ts.map +1 -0
- package/dist/__tests__/fixture.jsx +13 -0
- package/dist/__tests__/fixture.jsx.map +1 -0
- package/dist/experimental/components/LiveList.d.ts +24 -0
- package/dist/experimental/components/LiveList.d.ts.map +1 -0
- package/dist/experimental/components/LiveList.jsx +24 -0
- package/dist/experimental/components/LiveList.jsx.map +1 -0
- package/dist/experimental/mod.d.ts +2 -0
- package/dist/experimental/mod.d.ts.map +1 -0
- package/dist/experimental/mod.js +2 -0
- package/dist/experimental/mod.js.map +1 -0
- package/dist/mod.d.ts +6 -2
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +4 -2
- package/dist/mod.js.map +1 -1
- package/dist/useClientDocument.client.test.d.ts +2 -0
- package/dist/useClientDocument.client.test.d.ts.map +1 -0
- package/dist/useClientDocument.client.test.jsx +177 -0
- package/dist/useClientDocument.client.test.jsx.map +1 -0
- package/dist/useClientDocument.d.ts +71 -0
- package/dist/useClientDocument.d.ts.map +1 -0
- package/dist/useClientDocument.js +74 -0
- package/dist/useClientDocument.js.map +1 -0
- package/dist/useClientDocument.server.test.d.ts +6 -0
- package/dist/useClientDocument.server.test.d.ts.map +1 -0
- package/dist/useClientDocument.server.test.jsx +76 -0
- package/dist/useClientDocument.server.test.jsx.map +1 -0
- package/dist/useQuery.client.test.d.ts +2 -0
- package/dist/useQuery.client.test.d.ts.map +1 -0
- package/dist/useQuery.client.test.jsx +165 -0
- package/dist/useQuery.client.test.jsx.map +1 -0
- package/dist/useQuery.d.ts +32 -0
- package/dist/useQuery.d.ts.map +1 -0
- package/dist/useQuery.js +64 -0
- package/dist/useQuery.js.map +1 -0
- package/dist/useQuery.server.test.d.ts +6 -0
- package/dist/useQuery.server.test.d.ts.map +1 -0
- package/dist/useQuery.server.test.jsx +88 -0
- package/dist/useQuery.server.test.jsx.map +1 -0
- package/dist/useStore.client.test.d.ts +2 -0
- package/dist/useStore.client.test.d.ts.map +1 -0
- package/dist/useStore.client.test.jsx +438 -0
- package/dist/useStore.client.test.jsx.map +1 -0
- package/dist/useStore.d.ts +91 -0
- package/dist/useStore.d.ts.map +1 -0
- package/dist/useStore.js +94 -0
- package/dist/useStore.js.map +1 -0
- package/dist/useStore.server.test.d.ts +6 -0
- package/dist/useStore.server.test.d.ts.map +1 -0
- package/dist/useStore.server.test.jsx +56 -0
- package/dist/useStore.server.test.jsx.map +1 -0
- package/dist/utils.d.ts +4 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +7 -0
- package/dist/utils.js.map +1 -0
- package/dist/whenever.d.ts +32 -0
- package/dist/whenever.d.ts.map +1 -0
- package/dist/whenever.js +51 -0
- package/dist/whenever.js.map +1 -0
- package/package.json +64 -16
- package/src/StoreRegistryContext.tsx +70 -0
- package/src/__snapshots__/useClientDocument.client.test.tsx.snap +570 -0
- package/src/__snapshots__/useQuery.client.test.tsx.snap +1550 -0
- package/src/__tests__/fixture.tsx +42 -0
- package/src/experimental/components/LiveList.tsx +54 -0
- package/src/experimental/mod.ts +1 -0
- package/src/mod.ts +6 -2
- package/src/useClientDocument.client.test.tsx +299 -0
- package/src/useClientDocument.server.test.tsx +107 -0
- package/src/useClientDocument.ts +146 -0
- package/src/useQuery.client.test.tsx +293 -0
- package/src/useQuery.server.test.tsx +128 -0
- package/src/useQuery.ts +115 -0
- package/src/useStore.client.test.tsx +632 -0
- package/src/useStore.server.test.tsx +70 -0
- package/src/useStore.ts +179 -0
- package/src/utils.ts +10 -0
- package/src/whenever.ts +80 -0
- package/dist/query.d.ts +0 -4
- package/dist/query.d.ts.map +0 -1
- package/dist/query.js +0 -15
- package/dist/query.js.map +0 -1
- package/dist/store.d.ts +0 -6
- package/dist/store.d.ts.map +0 -1
- package/dist/store.js +0 -99
- package/dist/store.js.map +0 -1
- package/src/query.ts +0 -22
- package/src/store.ts +0 -196
package/src/useStore.ts
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import * as Solid from 'solid-js'
|
|
2
|
+
|
|
3
|
+
import type { RowQuery, SessionIdSymbol } from '@livestore/common'
|
|
4
|
+
import type { LiveStoreSchema, State } from '@livestore/common/schema'
|
|
5
|
+
import type { Queryable, RegistryStoreOptions, Store } from '@livestore/livestore'
|
|
6
|
+
import type { Schema } from '@livestore/utils/effect'
|
|
7
|
+
|
|
8
|
+
import { useStoreRegistry } from './StoreRegistryContext.tsx'
|
|
9
|
+
import { type UseClientDocumentResult, useClientDocument } from './useClientDocument.ts'
|
|
10
|
+
import { useQuery } from './useQuery.ts'
|
|
11
|
+
import { type AccessorMaybe, resolve } from './utils.ts'
|
|
12
|
+
import { every, when } from './whenever.ts'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Solid-specific methods added to the store Resource returned by `useStore()`.
|
|
16
|
+
*
|
|
17
|
+
* These methods handle the case where the store might not be loaded yet,
|
|
18
|
+
* returning `undefined` or buffering locally until ready.
|
|
19
|
+
*/
|
|
20
|
+
export type SolidApi = {
|
|
21
|
+
useClientDocument: {
|
|
22
|
+
// case: table has default id → id is optional
|
|
23
|
+
<
|
|
24
|
+
TTableDef extends State.SQLite.ClientDocumentTableDef.Trait<
|
|
25
|
+
any,
|
|
26
|
+
any,
|
|
27
|
+
any,
|
|
28
|
+
{
|
|
29
|
+
partialSet: boolean
|
|
30
|
+
default: { id: string | SessionIdSymbol; value: any }
|
|
31
|
+
}
|
|
32
|
+
>,
|
|
33
|
+
>(
|
|
34
|
+
table: AccessorMaybe<TTableDef>,
|
|
35
|
+
id?: AccessorMaybe<State.SQLite.ClientDocumentTableDef.DefaultIdType<TTableDef> | SessionIdSymbol>,
|
|
36
|
+
options?: Partial<RowQuery.GetOrCreateOptions<TTableDef>>,
|
|
37
|
+
): UseClientDocumentResult<TTableDef>
|
|
38
|
+
|
|
39
|
+
// case: table has no default id → id is required
|
|
40
|
+
<
|
|
41
|
+
TTableDef extends State.SQLite.ClientDocumentTableDef.Trait<
|
|
42
|
+
any,
|
|
43
|
+
any,
|
|
44
|
+
any,
|
|
45
|
+
{ partialSet: boolean; default: { id: undefined; value: any } }
|
|
46
|
+
>,
|
|
47
|
+
>(
|
|
48
|
+
table: AccessorMaybe<TTableDef>,
|
|
49
|
+
id: AccessorMaybe<string | SessionIdSymbol>,
|
|
50
|
+
options?: Partial<RowQuery.GetOrCreateOptions<TTableDef>>,
|
|
51
|
+
): UseClientDocumentResult<TTableDef>
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Creates a reactive query that subscribes to store updates.
|
|
55
|
+
*
|
|
56
|
+
* @returns An accessor that returns:
|
|
57
|
+
* - `undefined` while the store is loading
|
|
58
|
+
* - The query result once the store is ready
|
|
59
|
+
*/
|
|
60
|
+
useQuery<TQueryable extends Queryable<any>>(
|
|
61
|
+
queryDef: AccessorMaybe<TQueryable>,
|
|
62
|
+
): Solid.Accessor<Queryable.Result<TQueryable> | undefined>
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Returns a store resource that suspends until the store is loaded.
|
|
67
|
+
* The store is cached by its `storeId` in the `StoreRegistry`.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```tsx
|
|
71
|
+
* import { Suspense } from 'solid-js'
|
|
72
|
+
*
|
|
73
|
+
* function Issue(props: { issueId: string }) {
|
|
74
|
+
* const store = useStore(issueStoreOptions(props.issueId))
|
|
75
|
+
* const issues = store()?.useQuery(queryDb(tables.issue.select()))
|
|
76
|
+
*
|
|
77
|
+
* return (
|
|
78
|
+
* <Show when={store()}>
|
|
79
|
+
* {(s) => <IssueView store={s()} />}
|
|
80
|
+
* </Show>
|
|
81
|
+
* )
|
|
82
|
+
* }
|
|
83
|
+
*
|
|
84
|
+
* // With Suspense boundary
|
|
85
|
+
* function App() {
|
|
86
|
+
* return (
|
|
87
|
+
* <Suspense fallback={<div>Loading...</div>}>
|
|
88
|
+
* <Issue issueId="abc123" />
|
|
89
|
+
* </Suspense>
|
|
90
|
+
* )
|
|
91
|
+
* }
|
|
92
|
+
* ```
|
|
93
|
+
*
|
|
94
|
+
* @remarks
|
|
95
|
+
* - Suspends until the store is loaded when used within a Suspense boundary.
|
|
96
|
+
* - Store is cached by its `storeId` in the `StoreRegistry`. Multiple calls with the same `storeId` return the same store instance.
|
|
97
|
+
* - Store is cached as long as it's being used, and after `unusedCacheTime` expires (default `60_000` ms in browser, `Infinity` in non-browser)
|
|
98
|
+
* - Default store options can be configured in `StoreRegistry` constructor.
|
|
99
|
+
* - Store options are only applied when the store is loaded. Subsequent calls with different options will not affect the store if it's already loaded and cached in the registry.
|
|
100
|
+
*
|
|
101
|
+
* @typeParam TSchema - The schema type for the store
|
|
102
|
+
* @typeParam TContext - User-defined context attached to the store
|
|
103
|
+
* @typeParam TSyncPayloadSchema - Schema for the sync payload sent to the backend
|
|
104
|
+
* @returns A Resource that resolves to the loaded store instance augmented with Solid hooks
|
|
105
|
+
*/
|
|
106
|
+
export const useStore = <
|
|
107
|
+
TSchema extends LiveStoreSchema,
|
|
108
|
+
TContext = {},
|
|
109
|
+
TSyncPayloadSchema extends Schema.Schema<any> = typeof Schema.JsonValue,
|
|
110
|
+
>(
|
|
111
|
+
options: AccessorMaybe<RegistryStoreOptions<TSchema, TContext, TSyncPayloadSchema>>,
|
|
112
|
+
): Solid.Resource<Store<TSchema, TContext>> & SolidApi => {
|
|
113
|
+
const storeRegistry = useStoreRegistry()
|
|
114
|
+
|
|
115
|
+
const [storeResource] = Solid.createResource(
|
|
116
|
+
() => resolve(options),
|
|
117
|
+
(opts) => {
|
|
118
|
+
const release = storeRegistry.retain(opts)
|
|
119
|
+
Solid.onCleanup(release)
|
|
120
|
+
|
|
121
|
+
return storeRegistry.getOrLoadPromise(opts)
|
|
122
|
+
},
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
return withSolidApi(storeResource)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Augments a Store instance with Solid-specific methods (`useQuery`, `useClientDocument`).
|
|
130
|
+
*
|
|
131
|
+
* This is called automatically by `useStore()`. You typically don't need to call it
|
|
132
|
+
* directly unless you're building custom integrations.
|
|
133
|
+
*
|
|
134
|
+
* @internal
|
|
135
|
+
*/
|
|
136
|
+
export const withSolidApi = <T extends Store<any, any> | Solid.Accessor<Store<any, any> | undefined>>(
|
|
137
|
+
store: T,
|
|
138
|
+
): T & SolidApi => {
|
|
139
|
+
return Object.assign(store, {
|
|
140
|
+
useQuery(queryDef) {
|
|
141
|
+
const memo = Solid.createMemo(when(store, (store) => useQuery(queryDef, { store })))
|
|
142
|
+
return () => memo()?.()
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
useClientDocument(table: any, id: any, options: any) {
|
|
146
|
+
const [localState, setLocalState] = Solid.createSignal()
|
|
147
|
+
|
|
148
|
+
const getClient = Solid.createMemo<UseClientDocumentResult<any> | undefined>(
|
|
149
|
+
when(
|
|
150
|
+
every(store, table),
|
|
151
|
+
([store, table]) => {
|
|
152
|
+
const client = useClientDocument(table, id, options, { store: store })
|
|
153
|
+
const _localState = Solid.untrack(localState)
|
|
154
|
+
if (_localState !== undefined) {
|
|
155
|
+
client[1](_localState)
|
|
156
|
+
setLocalState(undefined)
|
|
157
|
+
}
|
|
158
|
+
return client
|
|
159
|
+
},
|
|
160
|
+
(previous: UseClientDocumentResult<any> | undefined) => previous,
|
|
161
|
+
),
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
// State accessor: return store state if available, otherwise local buffer
|
|
165
|
+
const state = when(getClient, ([state]) => state(), localState)
|
|
166
|
+
|
|
167
|
+
// Setter: update store if ready, otherwise buffer locally
|
|
168
|
+
const setState = when(getClient, ([, set], value: any) => set(value), setLocalState)
|
|
169
|
+
|
|
170
|
+
// ID accessor
|
|
171
|
+
const idAccessor = when(getClient, ([, , id]) => id())
|
|
172
|
+
|
|
173
|
+
// Query accessor
|
|
174
|
+
const queryAccessor = when(getClient, ([, , , query]) => query())
|
|
175
|
+
|
|
176
|
+
return [state, setState, idAccessor, queryAccessor] as UseClientDocumentResult<any>
|
|
177
|
+
},
|
|
178
|
+
} as SolidApi)
|
|
179
|
+
}
|
package/src/utils.ts
ADDED
package/src/whenever.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reactive utilities to ease working with nullable signals.
|
|
3
|
+
* Inlined from @bigmistqke/solid-whenever to reduce external dependencies.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { type AccessorMaybe, resolve } from './utils.ts'
|
|
7
|
+
|
|
8
|
+
type NonNullable<T> = Exclude<T, null | undefined | false | 0 | ''>
|
|
9
|
+
type InferNonNullable<T> = T extends AccessorMaybe<infer TValue> | undefined ? NonNullable<TValue> : never
|
|
10
|
+
type InferNonNullableTuple<TAccessors extends Array<AccessorMaybe<any>>> = {
|
|
11
|
+
[TKey in keyof TAccessors]: InferNonNullable<TAccessors[TKey]>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Checks if the accessor's value is truthy and executes a callback with that value.
|
|
16
|
+
* @param accessor - The value or function returning a value to check for truthiness
|
|
17
|
+
* @param callback - The callback function to execute if the value is truthy
|
|
18
|
+
* @param fallback - Optional callback function to execute if the value is falsy
|
|
19
|
+
* @returns The result of the callback if truthy, fallback result if falsy, or undefined if no fallback
|
|
20
|
+
*/
|
|
21
|
+
const check = <TValue, TResult, TFallbackResult = undefined>(
|
|
22
|
+
accessor: AccessorMaybe<TValue>,
|
|
23
|
+
callback: (value: NonNullable<TValue>) => TResult,
|
|
24
|
+
fallback?: () => TFallbackResult,
|
|
25
|
+
): TResult | TFallbackResult | undefined => {
|
|
26
|
+
const value = resolve(accessor)
|
|
27
|
+
return Boolean(value) === true
|
|
28
|
+
? callback(value as NonNullable<TValue>)
|
|
29
|
+
: fallback !== undefined
|
|
30
|
+
? fallback()
|
|
31
|
+
: undefined
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Returns a function that conditionally executes a callback based on the truthiness of an accessor's value,
|
|
36
|
+
* suitable for use in reactive programming contexts.
|
|
37
|
+
* @param accessor - The value or function returning a value that is checked for truthiness
|
|
38
|
+
* @param callback - The callback function to be executed if the accessor's value is truthy
|
|
39
|
+
* @param fallback - Optional callback function to be executed if the accessor's value is falsy
|
|
40
|
+
* @returns A function that conditionally executes the callback or fallback based on the accessor's value
|
|
41
|
+
*/
|
|
42
|
+
export const when: {
|
|
43
|
+
<Args extends any[], TValue, TResult>(
|
|
44
|
+
accessor: AccessorMaybe<TValue>,
|
|
45
|
+
callback: (value: NonNullable<TValue>, ...args: Args) => TResult,
|
|
46
|
+
): (...args: Args) => TResult | undefined
|
|
47
|
+
<Args extends any[], TValue, TResult, TFallbackResult>(
|
|
48
|
+
accessor: AccessorMaybe<TValue>,
|
|
49
|
+
callback: (value: NonNullable<TValue>, ...args: Args) => TResult,
|
|
50
|
+
fallback: (...args: Args) => TFallbackResult,
|
|
51
|
+
): (...args: Args) => TResult | TFallbackResult
|
|
52
|
+
} = <Args extends any[], TValue, TResult, TFallbackResult>(
|
|
53
|
+
accessor: AccessorMaybe<TValue>,
|
|
54
|
+
callback: (value: NonNullable<TValue>, ...args: Args) => TResult,
|
|
55
|
+
fallback?: (...args: Args) => TFallbackResult,
|
|
56
|
+
): ((...args: Args) => TResult | TFallbackResult | undefined) => {
|
|
57
|
+
return (...args: Args) =>
|
|
58
|
+
check(accessor, (value) => callback(value, ...args), fallback !== undefined ? () => fallback(...args) : undefined)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Returns a function that conditionally executes and aggregates results from multiple accessors if all values are truthy.
|
|
63
|
+
*
|
|
64
|
+
* @param accessors Multiple accessors to be checked for truthiness.
|
|
65
|
+
* @returns A function that can be called to conditionally execute based on the truthiness of all accessor values,
|
|
66
|
+
* returning their results as an array or undefined if any are not truthy.
|
|
67
|
+
*/
|
|
68
|
+
export const every = <TAccessors extends Array<AccessorMaybe<any>>>(
|
|
69
|
+
...accessors: TAccessors
|
|
70
|
+
): (() => InferNonNullableTuple<TAccessors> | undefined) => {
|
|
71
|
+
return () => {
|
|
72
|
+
const values = new Array(accessors.length) as InferNonNullableTuple<TAccessors>
|
|
73
|
+
for (let i = 0; i < accessors.length; i++) {
|
|
74
|
+
const _value = resolve(accessors[i])
|
|
75
|
+
if (_value == null) return undefined
|
|
76
|
+
values[i] = _value
|
|
77
|
+
}
|
|
78
|
+
return values
|
|
79
|
+
}
|
|
80
|
+
}
|
package/dist/query.d.ts
DELETED
package/dist/query.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,KAAK,KAAK,MAAM,UAAU,CAAA;AAGjC,eAAO,MAAM,KAAK,GAAI,OAAO,EAC3B,UAAU,SAAS,CAAC,OAAO,CAAC,EAE5B,cAAc,OAAO,KACpB,KAAK,CAAC,QAAQ,CAAC,OAAO,CAaxB,CAAA"}
|
package/dist/query.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import * as Solid from 'solid-js';
|
|
2
|
-
import { storeToExport } from "./store.js";
|
|
3
|
-
export const query = (queryDef,
|
|
4
|
-
// TODO do we actually need an `initialValue` at all?
|
|
5
|
-
initialValue) => {
|
|
6
|
-
const [value, setValue] = Solid.createSignal(initialValue);
|
|
7
|
-
const store = storeToExport();
|
|
8
|
-
// TODO avoid null-optionality branching
|
|
9
|
-
const unsubscribe = store?.subscribe(queryDef, (value) => setValue(value));
|
|
10
|
-
Solid.onCleanup(() => {
|
|
11
|
-
unsubscribe?.();
|
|
12
|
-
});
|
|
13
|
-
return value;
|
|
14
|
-
};
|
|
15
|
-
//# sourceMappingURL=query.js.map
|
package/dist/query.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,UAAU,CAAA;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE1C,MAAM,CAAC,MAAM,KAAK,GAAG,CACnB,QAA4B;AAC5B,qDAAqD;AACrD,YAAqB,EACI,EAAE;IAC3B,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,KAAK,CAAC,YAAY,CAAC,YAAY,CAAC,CAAA;IAE1D,MAAM,KAAK,GAAG,aAAa,EAAE,CAAA;IAE7B,wCAAwC;IACxC,MAAM,WAAW,GAAG,KAAK,EAAE,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAY,CAAC,CAAC,CAAA;IAEjF,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,WAAW,EAAE,EAAE,CAAA;IACjB,CAAC,CAAC,CAAA;IAEF,OAAO,KAAK,CAAA;AACd,CAAC,CAAA"}
|
package/dist/store.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { LogConfig } from '@livestore/common';
|
|
2
|
-
import type { CreateStoreOptions, LiveStoreSchema, Store } from '@livestore/livestore';
|
|
3
|
-
import * as Solid from 'solid-js';
|
|
4
|
-
export declare const storeToExport: Solid.Accessor<Store<any, {}> | undefined>, setStoreToExport: Solid.Setter<Store<any, {}> | undefined>;
|
|
5
|
-
export declare const getStore: <Schema extends LiveStoreSchema>({ adapter, schema, storeId, logger, logLevel, }: Pick<CreateStoreOptions<Schema>, "schema" | "adapter" | "storeId"> & LogConfig.WithLoggerOptions) => Promise<Solid.Accessor<Store<Schema> | undefined>>;
|
|
6
|
-
//# sourceMappingURL=store.d.ts.map
|
package/dist/store.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,SAAS,EAIV,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EAEV,kBAAkB,EAClB,eAAe,EAEf,KAAK,EAEN,MAAM,sBAAsB,CAAA;AAI7B,OAAO,KAAK,KAAK,MAAM,UAAU,CAAA;AA4CjC,eAAO,MAAO,aAAa,8CAAE,gBAAgB,0CAGe,CAAA;AA2G5D,eAAO,MAAM,QAAQ,GAAU,MAAM,SAAS,eAAe,EAAE,iDAM5D,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC,iBAAiB,KAAG,OAAO,CAC3G,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC,CAgB1C,CAAA"}
|
package/dist/store.js
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import { LogConfig, provideOtel, StoreInterrupted, } from '@livestore/common';
|
|
2
|
-
import { createStore, makeShutdownDeferred } from '@livestore/livestore';
|
|
3
|
-
import { LS_DEV, omitUndefineds } from '@livestore/utils';
|
|
4
|
-
import { Cause, Deferred, Effect, Exit, identity, Scope, TaskTracing } from '@livestore/utils/effect';
|
|
5
|
-
import * as Solid from 'solid-js';
|
|
6
|
-
const interrupt = (componentScope, shutdownDeferred, error) => Effect.gen(function* () {
|
|
7
|
-
// console.log('[@livestore/livestore/solid] interupting', error)
|
|
8
|
-
yield* Scope.close(componentScope, Exit.fail(error));
|
|
9
|
-
yield* Deferred.fail(shutdownDeferred, error);
|
|
10
|
-
}).pipe(Effect.tapErrorCause((cause) => Effect.logDebug('[@livestore/livestore/solid] interrupting', cause)), Effect.runFork);
|
|
11
|
-
const semaphoreMap = new Map();
|
|
12
|
-
const withSemaphore = (schemaKey) => {
|
|
13
|
-
let semaphore = semaphoreMap.get(schemaKey);
|
|
14
|
-
if (!semaphore) {
|
|
15
|
-
semaphore = Effect.makeSemaphore(1).pipe(Effect.runSync);
|
|
16
|
-
semaphoreMap.set(schemaKey, semaphore);
|
|
17
|
-
}
|
|
18
|
-
return semaphore.withPermits(1);
|
|
19
|
-
};
|
|
20
|
-
const storeValue = {
|
|
21
|
-
value: { stage: 'loading' },
|
|
22
|
-
shutdownDeferred: undefined,
|
|
23
|
-
componentScope: undefined,
|
|
24
|
-
counter: 0,
|
|
25
|
-
};
|
|
26
|
-
const [, setInternalStore] = Solid.createSignal(storeValue);
|
|
27
|
-
// TODO remove `any` store type
|
|
28
|
-
// this will require fixing: error TS2742: The inferred type of 'storeToExport' cannot be named without a reference to '../node_modules/@livestore/common/src/schema/state/sqlite/db-schema/dsl/mod.ts'. This is likely not portable. A type annotation is necessary.
|
|
29
|
-
export const [storeToExport, setStoreToExport] = Solid.createSignal();
|
|
30
|
-
const setupStore = async ({ schema, storeId, boot, adapter, batchUpdates, disableDevtools, signal, setupDone, logger, logLevel, }) => {
|
|
31
|
-
Solid.createEffect(() => {
|
|
32
|
-
const counter = storeValue.counter;
|
|
33
|
-
const setContextValue = (value) => {
|
|
34
|
-
if (storeValue.counter !== counter)
|
|
35
|
-
return;
|
|
36
|
-
storeValue.value = value;
|
|
37
|
-
setInternalStore({
|
|
38
|
-
value: storeValue.value,
|
|
39
|
-
shutdownDeferred: storeValue.shutdownDeferred,
|
|
40
|
-
componentScope: storeValue.componentScope,
|
|
41
|
-
counter: counter + 1,
|
|
42
|
-
});
|
|
43
|
-
if (value.stage === 'running') {
|
|
44
|
-
setStoreToExport(value.store);
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
signal?.addEventListener('abort', () => {
|
|
48
|
-
if (storeValue.componentScope !== undefined &&
|
|
49
|
-
storeValue.shutdownDeferred !== undefined &&
|
|
50
|
-
storeValue.counter === counter) {
|
|
51
|
-
interrupt(storeValue.componentScope, storeValue.shutdownDeferred, new StoreInterrupted({ reason: 'Aborted via provided AbortController' }));
|
|
52
|
-
storeValue.componentScope = undefined;
|
|
53
|
-
storeValue.shutdownDeferred = undefined;
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
Effect.gen(function* () {
|
|
57
|
-
const componentScope = yield* Scope.make();
|
|
58
|
-
const shutdownDeferred = yield* makeShutdownDeferred;
|
|
59
|
-
yield* Effect.gen(function* () {
|
|
60
|
-
const store = yield* createStore({
|
|
61
|
-
schema,
|
|
62
|
-
storeId,
|
|
63
|
-
adapter,
|
|
64
|
-
...omitUndefineds({ boot, batchUpdates, disableDevtools }),
|
|
65
|
-
onBootStatus: (status) => {
|
|
66
|
-
if (storeValue.value.stage === 'running' || storeValue.value.stage === 'error')
|
|
67
|
-
return;
|
|
68
|
-
setContextValue(status);
|
|
69
|
-
},
|
|
70
|
-
}).pipe(Effect.tapErrorCause((cause) => Deferred.failCause(shutdownDeferred, cause)));
|
|
71
|
-
setContextValue({ stage: 'running', store });
|
|
72
|
-
setupDone();
|
|
73
|
-
}).pipe(Scope.extend(componentScope), Effect.forkIn(componentScope));
|
|
74
|
-
const shutdownContext = (cause) => Effect.sync(() => setContextValue({ stage: 'shutdown', cause }));
|
|
75
|
-
yield* Deferred.await(shutdownDeferred).pipe(Effect.tapErrorCause((cause) => Effect.logDebug('[@livestore/livestore/solid] shutdown', Cause.pretty(cause))), Effect.tap((intentionalShutdown) => shutdownContext(intentionalShutdown)), Effect.catchTag('InvalidPullError', (cause) => shutdownContext(cause)), Effect.catchTag('InvalidPushError', (cause) => shutdownContext(cause)), Effect.catchTag('LiveStore.StoreInterrupted', (cause) => shutdownContext(cause)), Effect.tapError((error) => Effect.sync(() => setContextValue({ stage: 'error', error }))), Effect.tapDefect((defect) => Effect.sync(() => setContextValue({ stage: 'error', error: defect }))), Effect.exit);
|
|
76
|
-
}).pipe(Effect.scoped, withSemaphore(storeId), Effect.withSpan('@livestore/solid:setupStore'), LS_DEV ? TaskTracing.withAsyncTaggingTracing((name) => console.createTask(name)) : identity, provideOtel({}), Effect.tapCauseLogPretty, Effect.annotateLogs({ thread: 'window' }), LogConfig.withLoggerConfig({ logger, logLevel }, { threadName: 'window' }), Effect.runFork);
|
|
77
|
-
Solid.onCleanup(() => {
|
|
78
|
-
if (storeValue.componentScope !== undefined && storeValue.shutdownDeferred !== undefined) {
|
|
79
|
-
interrupt(storeValue.componentScope, storeValue.shutdownDeferred, new StoreInterrupted({ reason: 'unmounting component' }));
|
|
80
|
-
storeValue.componentScope = undefined;
|
|
81
|
-
storeValue.shutdownDeferred = undefined;
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
};
|
|
86
|
-
export const getStore = async ({ adapter, schema, storeId, logger, logLevel, }) => {
|
|
87
|
-
const setupDone = Promise.withResolvers();
|
|
88
|
-
await setupStore({
|
|
89
|
-
adapter,
|
|
90
|
-
schema,
|
|
91
|
-
storeId,
|
|
92
|
-
logger,
|
|
93
|
-
logLevel,
|
|
94
|
-
setupDone: setupDone.resolve,
|
|
95
|
-
});
|
|
96
|
-
await setupDone.promise;
|
|
97
|
-
return storeToExport;
|
|
98
|
-
};
|
|
99
|
-
//# sourceMappingURL=store.js.map
|
package/dist/store.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,SAAS,EACT,WAAW,EACX,gBAAgB,GAEjB,MAAM,mBAAmB,CAAA;AAS1B,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACzD,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AACrG,OAAO,KAAK,KAAK,MAAM,UAAU,CAAA;AAEjC,MAAM,SAAS,GAAG,CAAC,cAAoC,EAAE,gBAAkC,EAAE,KAAuB,EAAE,EAAE,CACtH,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,iEAAiE;IACjE,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;IACpD,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAA;AAC/C,CAAC,CAAC,CAAC,IAAI,CACL,MAAM,CAAC,aAAa,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,2CAA2C,EAAE,KAAK,CAAC,CAAC,EACpG,MAAM,CAAC,OAAO,CACf,CAAA;AAGH,MAAM,YAAY,GAAG,IAAI,GAAG,EAA+B,CAAA;AAC3D,MAAM,aAAa,GAAG,CAAC,SAAoB,EAAE,EAAE;IAC7C,IAAI,SAAS,GAAG,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IAC3C,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,SAAS,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QACxD,YAAY,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;IACxC,CAAC;IACD,OAAO,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,CAAA;AACjC,CAAC,CAAA;AAED,MAAM,UAAU,GAKZ;IACF,KAAK,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE;IAC3B,gBAAgB,EAAE,SAAS;IAC3B,cAAc,EAAE,SAAS;IACzB,OAAO,EAAE,CAAC;CACX,CAAA;AAED,MAAM,CAAC,EAAE,gBAAgB,CAAC,GAAG,KAAK,CAAC,YAAY,CAK5C,UAAU,CAAC,CAAA;AAEd,+BAA+B;AAC/B,qQAAqQ;AACrQ,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAG1C,KAAK,CAAC,YAAY,EAAsC,CAAA;AAE5D,MAAM,UAAU,GAAG,KAAK,EAAE,EACxB,MAAM,EACN,OAAO,EACP,IAAI,EACJ,OAAO,EACP,YAAY,EACZ,eAAe,EACf,MAAM,EACN,SAAS,EACT,MAAM,EACN,QAAQ,GAEqE,EAAE,EAAE;IACjF,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE;QACtB,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAA;QAElC,MAAM,eAAe,GAAG,CAAC,KAAiC,EAAE,EAAE;YAC5D,IAAI,UAAU,CAAC,OAAO,KAAK,OAAO;gBAAE,OAAM;YAC1C,UAAU,CAAC,KAAK,GAAG,KAAK,CAAA;YACxB,gBAAgB,CAAC;gBACf,KAAK,EAAE,UAAU,CAAC,KAAK;gBACvB,gBAAgB,EAAE,UAAU,CAAC,gBAAgB;gBAC7C,cAAc,EAAE,UAAU,CAAC,cAAc;gBACzC,OAAO,EAAE,OAAO,GAAG,CAAC;aACrB,CAAC,CAAA;YACF,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;gBAC9B,gBAAgB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;YAC/B,CAAC;QACH,CAAC,CAAA;QAED,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;YACrC,IACE,UAAU,CAAC,cAAc,KAAK,SAAS;gBACvC,UAAU,CAAC,gBAAgB,KAAK,SAAS;gBACzC,UAAU,CAAC,OAAO,KAAK,OAAO,EAC9B,CAAC;gBACD,SAAS,CACP,UAAU,CAAC,cAAc,EACzB,UAAU,CAAC,gBAAgB,EAC3B,IAAI,gBAAgB,CAAC,EAAE,MAAM,EAAE,sCAAsC,EAAE,CAAC,CACzE,CAAA;gBACD,UAAU,CAAC,cAAc,GAAG,SAAS,CAAA;gBACrC,UAAU,CAAC,gBAAgB,GAAG,SAAS,CAAA;YACzC,CAAC;QACH,CAAC,CAAC,CAAA;QAEF,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAClB,MAAM,cAAc,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAA;YAC1C,MAAM,gBAAgB,GAAG,KAAK,CAAC,CAAC,oBAAoB,CAAA;YAEpD,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;gBACzB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,WAAW,CAAC;oBAC/B,MAAM;oBACN,OAAO;oBACP,OAAO;oBACP,GAAG,cAAc,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,eAAe,EAAE,CAAC;oBAC1D,YAAY,EAAE,CAAC,MAAM,EAAE,EAAE;wBACvB,IAAI,UAAU,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,UAAU,CAAC,KAAK,CAAC,KAAK,KAAK,OAAO;4BAAE,OAAM;wBACtF,eAAe,CAAC,MAAM,CAAC,CAAA;oBACzB,CAAC;iBACF,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC,CAAC,CAAA;gBAErF,eAAe,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAA;gBAC5C,SAAS,EAAE,CAAA;YACb,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAA;YAEpE,MAAM,eAAe,GAAG,CAAC,KAA8D,EAAE,EAAE,CACzF,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;YAElE,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAC1C,MAAM,CAAC,aAAa,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,uCAAuC,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAC9G,MAAM,CAAC,GAAG,CAAC,CAAC,mBAAmB,EAAE,EAAE,CAAC,eAAe,CAAC,mBAAmB,CAAC,CAAC,EACzE,MAAM,CAAC,QAAQ,CAAC,kBAAkB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,EACtE,MAAM,CAAC,QAAQ,CAAC,kBAAkB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,EACtE,MAAM,CAAC,QAAQ,CAAC,4BAA4B,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,EAChF,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EACzF,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EACnG,MAAM,CAAC,IAAI,CACZ,CAAA;QACH,CAAC,CAAC,CAAC,IAAI,CACL,MAAM,CAAC,MAAM,EACb,aAAa,CAAC,OAAO,CAAC,EACtB,MAAM,CAAC,QAAQ,CAAC,6BAA6B,CAAC,EAC9C,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,uBAAuB,CAAC,CAAC,IAAY,EAAE,EAAE,CAAE,OAAe,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAC5G,WAAW,CAAC,EAAE,CAAC,EACf,MAAM,CAAC,iBAAiB,EACxB,MAAM,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EACzC,SAAS,CAAC,gBAAgB,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,EAC1E,MAAM,CAAC,OAAO,CACf,CAAA;QAED,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;YACnB,IAAI,UAAU,CAAC,cAAc,KAAK,SAAS,IAAI,UAAU,CAAC,gBAAgB,KAAK,SAAS,EAAE,CAAC;gBACzF,SAAS,CACP,UAAU,CAAC,cAAc,EACzB,UAAU,CAAC,gBAAgB,EAC3B,IAAI,gBAAgB,CAAC,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC,CACzD,CAAA;gBACD,UAAU,CAAC,cAAc,GAAG,SAAS,CAAA;gBACrC,UAAU,CAAC,gBAAgB,GAAG,SAAS,CAAA;YACzC,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG,KAAK,EAAkC,EAC7D,OAAO,EACP,MAAM,EACN,OAAO,EACP,MAAM,EACN,QAAQ,GACyF,EAEjG,EAAE;IACF,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,EAAQ,CAAA;IAE/C,MAAM,UAAU,CAAC;QACf,OAAO;QACP,MAAM;QACN,OAAO;QACP,MAAM;QACN,QAAQ;QACR,SAAS,EAAE,SAAS,CAAC,OAAO;KAC7B,CAAC,CAAA;IAEF,MAAM,SAAS,CAAC,OAAO,CAAA;IAEvB,OAAO,aAAyD,CAAA;AAClE,CAAC,CAAA"}
|
package/src/query.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { Queryable } from '@livestore/livestore'
|
|
2
|
-
import * as Solid from 'solid-js'
|
|
3
|
-
import { storeToExport } from './store.ts'
|
|
4
|
-
|
|
5
|
-
export const query = <TResult>(
|
|
6
|
-
queryDef: Queryable<TResult>,
|
|
7
|
-
// TODO do we actually need an `initialValue` at all?
|
|
8
|
-
initialValue: TResult,
|
|
9
|
-
): Solid.Accessor<TResult> => {
|
|
10
|
-
const [value, setValue] = Solid.createSignal(initialValue)
|
|
11
|
-
|
|
12
|
-
const store = storeToExport()
|
|
13
|
-
|
|
14
|
-
// TODO avoid null-optionality branching
|
|
15
|
-
const unsubscribe = store?.subscribe(queryDef, (value) => setValue(value as any))
|
|
16
|
-
|
|
17
|
-
Solid.onCleanup(() => {
|
|
18
|
-
unsubscribe?.()
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
return value
|
|
22
|
-
}
|
package/src/store.ts
DELETED
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type IntentionalShutdownCause,
|
|
3
|
-
LogConfig,
|
|
4
|
-
provideOtel,
|
|
5
|
-
StoreInterrupted,
|
|
6
|
-
type SyncError,
|
|
7
|
-
} from '@livestore/common'
|
|
8
|
-
import type {
|
|
9
|
-
BootStatus,
|
|
10
|
-
CreateStoreOptions,
|
|
11
|
-
LiveStoreSchema,
|
|
12
|
-
ShutdownDeferred,
|
|
13
|
-
Store,
|
|
14
|
-
LiveStoreContext as StoreContext_,
|
|
15
|
-
} from '@livestore/livestore'
|
|
16
|
-
import { createStore, makeShutdownDeferred } from '@livestore/livestore'
|
|
17
|
-
import { LS_DEV, omitUndefineds } from '@livestore/utils'
|
|
18
|
-
import { Cause, Deferred, Effect, Exit, identity, Scope, TaskTracing } from '@livestore/utils/effect'
|
|
19
|
-
import * as Solid from 'solid-js'
|
|
20
|
-
|
|
21
|
-
const interrupt = (componentScope: Scope.CloseableScope, shutdownDeferred: ShutdownDeferred, error: StoreInterrupted) =>
|
|
22
|
-
Effect.gen(function* () {
|
|
23
|
-
// console.log('[@livestore/livestore/solid] interupting', error)
|
|
24
|
-
yield* Scope.close(componentScope, Exit.fail(error))
|
|
25
|
-
yield* Deferred.fail(shutdownDeferred, error)
|
|
26
|
-
}).pipe(
|
|
27
|
-
Effect.tapErrorCause((cause) => Effect.logDebug('[@livestore/livestore/solid] interrupting', cause)),
|
|
28
|
-
Effect.runFork,
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
type SchemaKey = string
|
|
32
|
-
const semaphoreMap = new Map<SchemaKey, Effect.Semaphore>()
|
|
33
|
-
const withSemaphore = (schemaKey: SchemaKey) => {
|
|
34
|
-
let semaphore = semaphoreMap.get(schemaKey)
|
|
35
|
-
if (!semaphore) {
|
|
36
|
-
semaphore = Effect.makeSemaphore(1).pipe(Effect.runSync)
|
|
37
|
-
semaphoreMap.set(schemaKey, semaphore)
|
|
38
|
-
}
|
|
39
|
-
return semaphore.withPermits(1)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const storeValue: {
|
|
43
|
-
value: StoreContext_ | BootStatus
|
|
44
|
-
shutdownDeferred: ShutdownDeferred | undefined
|
|
45
|
-
componentScope: Scope.CloseableScope | undefined
|
|
46
|
-
counter: number
|
|
47
|
-
} = {
|
|
48
|
-
value: { stage: 'loading' },
|
|
49
|
-
shutdownDeferred: undefined,
|
|
50
|
-
componentScope: undefined,
|
|
51
|
-
counter: 0,
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const [, setInternalStore] = Solid.createSignal<{
|
|
55
|
-
value: StoreContext_ | BootStatus
|
|
56
|
-
shutdownDeferred: ShutdownDeferred | undefined
|
|
57
|
-
componentScope: Scope.CloseableScope | undefined
|
|
58
|
-
counter: number
|
|
59
|
-
}>(storeValue)
|
|
60
|
-
|
|
61
|
-
// TODO remove `any` store type
|
|
62
|
-
// this will require fixing: error TS2742: The inferred type of 'storeToExport' cannot be named without a reference to '../node_modules/@livestore/common/src/schema/state/sqlite/db-schema/dsl/mod.ts'. This is likely not portable. A type annotation is necessary.
|
|
63
|
-
export const [storeToExport, setStoreToExport]: [
|
|
64
|
-
Solid.Accessor<Store<any> | undefined>,
|
|
65
|
-
Solid.Setter<Store<any> | undefined>,
|
|
66
|
-
] = Solid.createSignal<Store<LiveStoreSchema> | undefined>()
|
|
67
|
-
|
|
68
|
-
const setupStore = async ({
|
|
69
|
-
schema,
|
|
70
|
-
storeId,
|
|
71
|
-
boot,
|
|
72
|
-
adapter,
|
|
73
|
-
batchUpdates,
|
|
74
|
-
disableDevtools,
|
|
75
|
-
signal,
|
|
76
|
-
setupDone,
|
|
77
|
-
logger,
|
|
78
|
-
logLevel,
|
|
79
|
-
}: CreateStoreOptions<LiveStoreSchema> &
|
|
80
|
-
LogConfig.WithLoggerOptions & { signal?: AbortSignal; setupDone: () => void }) => {
|
|
81
|
-
Solid.createEffect(() => {
|
|
82
|
-
const counter = storeValue.counter
|
|
83
|
-
|
|
84
|
-
const setContextValue = (value: StoreContext_ | BootStatus) => {
|
|
85
|
-
if (storeValue.counter !== counter) return
|
|
86
|
-
storeValue.value = value
|
|
87
|
-
setInternalStore({
|
|
88
|
-
value: storeValue.value,
|
|
89
|
-
shutdownDeferred: storeValue.shutdownDeferred,
|
|
90
|
-
componentScope: storeValue.componentScope,
|
|
91
|
-
counter: counter + 1,
|
|
92
|
-
})
|
|
93
|
-
if (value.stage === 'running') {
|
|
94
|
-
setStoreToExport(value.store)
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
signal?.addEventListener('abort', () => {
|
|
99
|
-
if (
|
|
100
|
-
storeValue.componentScope !== undefined &&
|
|
101
|
-
storeValue.shutdownDeferred !== undefined &&
|
|
102
|
-
storeValue.counter === counter
|
|
103
|
-
) {
|
|
104
|
-
interrupt(
|
|
105
|
-
storeValue.componentScope,
|
|
106
|
-
storeValue.shutdownDeferred,
|
|
107
|
-
new StoreInterrupted({ reason: 'Aborted via provided AbortController' }),
|
|
108
|
-
)
|
|
109
|
-
storeValue.componentScope = undefined
|
|
110
|
-
storeValue.shutdownDeferred = undefined
|
|
111
|
-
}
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
Effect.gen(function* () {
|
|
115
|
-
const componentScope = yield* Scope.make()
|
|
116
|
-
const shutdownDeferred = yield* makeShutdownDeferred
|
|
117
|
-
|
|
118
|
-
yield* Effect.gen(function* () {
|
|
119
|
-
const store = yield* createStore({
|
|
120
|
-
schema,
|
|
121
|
-
storeId,
|
|
122
|
-
adapter,
|
|
123
|
-
...omitUndefineds({ boot, batchUpdates, disableDevtools }),
|
|
124
|
-
onBootStatus: (status) => {
|
|
125
|
-
if (storeValue.value.stage === 'running' || storeValue.value.stage === 'error') return
|
|
126
|
-
setContextValue(status)
|
|
127
|
-
},
|
|
128
|
-
}).pipe(Effect.tapErrorCause((cause) => Deferred.failCause(shutdownDeferred, cause)))
|
|
129
|
-
|
|
130
|
-
setContextValue({ stage: 'running', store })
|
|
131
|
-
setupDone()
|
|
132
|
-
}).pipe(Scope.extend(componentScope), Effect.forkIn(componentScope))
|
|
133
|
-
|
|
134
|
-
const shutdownContext = (cause: IntentionalShutdownCause | StoreInterrupted | SyncError) =>
|
|
135
|
-
Effect.sync(() => setContextValue({ stage: 'shutdown', cause }))
|
|
136
|
-
|
|
137
|
-
yield* Deferred.await(shutdownDeferred).pipe(
|
|
138
|
-
Effect.tapErrorCause((cause) => Effect.logDebug('[@livestore/livestore/solid] shutdown', Cause.pretty(cause))),
|
|
139
|
-
Effect.tap((intentionalShutdown) => shutdownContext(intentionalShutdown)),
|
|
140
|
-
Effect.catchTag('InvalidPullError', (cause) => shutdownContext(cause)),
|
|
141
|
-
Effect.catchTag('InvalidPushError', (cause) => shutdownContext(cause)),
|
|
142
|
-
Effect.catchTag('LiveStore.StoreInterrupted', (cause) => shutdownContext(cause)),
|
|
143
|
-
Effect.tapError((error) => Effect.sync(() => setContextValue({ stage: 'error', error }))),
|
|
144
|
-
Effect.tapDefect((defect) => Effect.sync(() => setContextValue({ stage: 'error', error: defect }))),
|
|
145
|
-
Effect.exit,
|
|
146
|
-
)
|
|
147
|
-
}).pipe(
|
|
148
|
-
Effect.scoped,
|
|
149
|
-
withSemaphore(storeId),
|
|
150
|
-
Effect.withSpan('@livestore/solid:setupStore'),
|
|
151
|
-
LS_DEV ? TaskTracing.withAsyncTaggingTracing((name: string) => (console as any).createTask(name)) : identity,
|
|
152
|
-
provideOtel({}),
|
|
153
|
-
Effect.tapCauseLogPretty,
|
|
154
|
-
Effect.annotateLogs({ thread: 'window' }),
|
|
155
|
-
LogConfig.withLoggerConfig({ logger, logLevel }, { threadName: 'window' }),
|
|
156
|
-
Effect.runFork,
|
|
157
|
-
)
|
|
158
|
-
|
|
159
|
-
Solid.onCleanup(() => {
|
|
160
|
-
if (storeValue.componentScope !== undefined && storeValue.shutdownDeferred !== undefined) {
|
|
161
|
-
interrupt(
|
|
162
|
-
storeValue.componentScope,
|
|
163
|
-
storeValue.shutdownDeferred,
|
|
164
|
-
new StoreInterrupted({ reason: 'unmounting component' }),
|
|
165
|
-
)
|
|
166
|
-
storeValue.componentScope = undefined
|
|
167
|
-
storeValue.shutdownDeferred = undefined
|
|
168
|
-
}
|
|
169
|
-
})
|
|
170
|
-
})
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
export const getStore = async <Schema extends LiveStoreSchema>({
|
|
174
|
-
adapter,
|
|
175
|
-
schema,
|
|
176
|
-
storeId,
|
|
177
|
-
logger,
|
|
178
|
-
logLevel,
|
|
179
|
-
}: Pick<CreateStoreOptions<Schema>, 'schema' | 'adapter' | 'storeId'> & LogConfig.WithLoggerOptions): Promise<
|
|
180
|
-
Solid.Accessor<Store<Schema> | undefined>
|
|
181
|
-
> => {
|
|
182
|
-
const setupDone = Promise.withResolvers<void>()
|
|
183
|
-
|
|
184
|
-
await setupStore({
|
|
185
|
-
adapter,
|
|
186
|
-
schema,
|
|
187
|
-
storeId,
|
|
188
|
-
logger,
|
|
189
|
-
logLevel,
|
|
190
|
-
setupDone: setupDone.resolve,
|
|
191
|
-
})
|
|
192
|
-
|
|
193
|
-
await setupDone.promise
|
|
194
|
-
|
|
195
|
-
return storeToExport as unknown as Solid.Accessor<Store<Schema>>
|
|
196
|
-
}
|