@livestore/livestore 0.4.0-dev.21 → 0.4.0-dev.22
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/effect/LiveStore.d.ts +123 -2
- package/dist/effect/LiveStore.d.ts.map +1 -1
- package/dist/effect/LiveStore.js +195 -1
- package/dist/effect/LiveStore.js.map +1 -1
- package/dist/effect/mod.d.ts +1 -1
- package/dist/effect/mod.d.ts.map +1 -1
- package/dist/effect/mod.js +3 -1
- package/dist/effect/mod.js.map +1 -1
- package/dist/mod.d.ts +1 -0
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +1 -0
- package/dist/mod.js.map +1 -1
- package/dist/store/StoreRegistry.d.ts +190 -0
- package/dist/store/StoreRegistry.d.ts.map +1 -0
- package/dist/store/StoreRegistry.js +244 -0
- package/dist/store/StoreRegistry.js.map +1 -0
- package/dist/store/StoreRegistry.test.d.ts +2 -0
- package/dist/store/StoreRegistry.test.d.ts.map +1 -0
- package/dist/store/StoreRegistry.test.js +380 -0
- package/dist/store/StoreRegistry.test.js.map +1 -0
- package/dist/store/create-store.d.ts +50 -4
- package/dist/store/create-store.d.ts.map +1 -1
- package/dist/store/create-store.js +19 -0
- package/dist/store/create-store.js.map +1 -1
- package/dist/store/devtools.d.ts.map +1 -1
- package/dist/store/devtools.js +13 -0
- package/dist/store/devtools.js.map +1 -1
- package/dist/store/store-types.d.ts +10 -25
- package/dist/store/store-types.d.ts.map +1 -1
- package/dist/store/store-types.js.map +1 -1
- package/dist/store/store.d.ts +23 -6
- package/dist/store/store.d.ts.map +1 -1
- package/dist/store/store.js +20 -2
- package/dist/store/store.js.map +1 -1
- package/docs/building-with-livestore/complex-ui-state/index.md +0 -2
- package/docs/building-with-livestore/crud/index.md +0 -2
- package/docs/building-with-livestore/data-modeling/index.md +29 -0
- package/docs/building-with-livestore/examples/todo-workspaces/index.md +0 -6
- package/docs/building-with-livestore/opentelemetry/index.md +25 -6
- package/docs/building-with-livestore/rules-for-ai-agents/index.md +2 -2
- package/docs/building-with-livestore/state/sql-queries/index.md +22 -0
- package/docs/building-with-livestore/state/sqlite-schema/index.md +2 -2
- package/docs/building-with-livestore/store/index.md +344 -0
- package/docs/framework-integrations/react-integration/index.md +380 -361
- package/docs/framework-integrations/vue-integration/index.md +2 -2
- package/docs/getting-started/expo/index.md +189 -43
- package/docs/getting-started/react-web/index.md +77 -24
- package/docs/getting-started/vue/index.md +3 -3
- package/docs/index.md +1 -2
- package/docs/llms.txt +0 -1
- package/docs/misc/troubleshooting/index.md +3 -3
- package/docs/overview/how-livestore-works/index.md +1 -1
- package/docs/overview/introduction/index.md +409 -1
- package/docs/overview/why-livestore/index.md +108 -2
- package/docs/patterns/auth/index.md +185 -34
- package/docs/patterns/effect/index.md +11 -1
- package/docs/patterns/storybook/index.md +43 -26
- package/docs/platform-adapters/expo-adapter/index.md +36 -19
- package/docs/platform-adapters/web-adapter/index.md +71 -2
- package/docs/tutorial/1-setup-starter-project/index.md +5 -5
- package/docs/tutorial/3-read-and-write-todos-via-livestore/index.md +54 -35
- package/docs/tutorial/5-expand-business-logic/index.md +1 -1
- package/docs/tutorial/6-persist-ui-state/index.md +12 -12
- package/package.json +6 -6
- package/src/effect/LiveStore.ts +385 -3
- package/src/effect/mod.ts +13 -1
- package/src/mod.ts +1 -0
- package/src/store/StoreRegistry.test.ts +516 -0
- package/src/store/StoreRegistry.ts +393 -0
- package/src/store/create-store.ts +50 -4
- package/src/store/devtools.ts +15 -0
- package/src/store/store-types.ts +17 -5
- package/src/store/store.ts +25 -5
- package/docs/building-with-livestore/examples/index.md +0 -30
package/src/effect/LiveStore.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { UnknownError } from '@livestore/common'
|
|
2
|
-
import type { LiveStoreSchema } from '@livestore/common/schema'
|
|
2
|
+
import type { LiveStoreEvent, LiveStoreSchema } from '@livestore/common/schema'
|
|
3
3
|
import { omitUndefineds } from '@livestore/utils'
|
|
4
4
|
import type { Cause, OtelTracer, Scope } from '@livestore/utils/effect'
|
|
5
|
-
import { Deferred, Duration, Effect, Layer, pipe } from '@livestore/utils/effect'
|
|
6
|
-
|
|
5
|
+
import { Context, Deferred, Duration, Effect, Layer, pipe } from '@livestore/utils/effect'
|
|
7
6
|
import type { LiveStoreContextProps } from '../store/create-store.ts'
|
|
8
7
|
import { createStore, DeferredStoreContext, LiveStoreContextRunning } from '../store/create-store.ts'
|
|
8
|
+
import type { Store as StoreClass } from '../store/store.ts'
|
|
9
|
+
import type { LiveStoreContextRunning as LiveStoreContextRunningType, Queryable } from '../store/store-types.ts'
|
|
9
10
|
|
|
10
11
|
export const makeLiveStoreContext = <TSchema extends LiveStoreSchema, TContext = {}>({
|
|
11
12
|
schema,
|
|
@@ -49,6 +50,19 @@ export const makeLiveStoreContext = <TSchema extends LiveStoreSchema, TContext =
|
|
|
49
50
|
Effect.withSpan('@livestore/livestore/effect:makeLiveStoreContext'),
|
|
50
51
|
)
|
|
51
52
|
|
|
53
|
+
/**
|
|
54
|
+
* @deprecated Use `Store.Tag(schema, storeId)` instead for type-safe store contexts.
|
|
55
|
+
*
|
|
56
|
+
* @example Migration
|
|
57
|
+
* ```ts
|
|
58
|
+
* // Before
|
|
59
|
+
* const layer = LiveStoreContextLayer({ schema, adapter, ... })
|
|
60
|
+
*
|
|
61
|
+
* // After
|
|
62
|
+
* class MainStore extends Store.Tag(schema, 'main') {}
|
|
63
|
+
* const layer = MainStore.layer({ adapter, ... })
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
52
66
|
export const LiveStoreContextLayer = <TSchema extends LiveStoreSchema, TContext = {}>(
|
|
53
67
|
props: LiveStoreContextProps<TSchema, TContext>,
|
|
54
68
|
): Layer.Layer<LiveStoreContextRunning, UnknownError | Cause.TimeoutException, OtelTracer.OtelTracer> =>
|
|
@@ -57,7 +71,375 @@ export const LiveStoreContextLayer = <TSchema extends LiveStoreSchema, TContext
|
|
|
57
71
|
Layer.provide(LiveStoreContextDeferred),
|
|
58
72
|
)
|
|
59
73
|
|
|
74
|
+
/**
|
|
75
|
+
* @deprecated Use `Store.Tag(schema, storeId)` and `MainStore.DeferredLayer` instead.
|
|
76
|
+
*/
|
|
60
77
|
export const LiveStoreContextDeferred = Layer.effect(
|
|
61
78
|
DeferredStoreContext,
|
|
62
79
|
Deferred.make<LiveStoreContextRunning['Type'], UnknownError>(),
|
|
63
80
|
)
|
|
81
|
+
|
|
82
|
+
// =============================================================================
|
|
83
|
+
// Store.Tag - Idiomatic Effect API
|
|
84
|
+
// =============================================================================
|
|
85
|
+
|
|
86
|
+
/** Branded type for unique store context identity */
|
|
87
|
+
declare const StoreContextTypeId: unique symbol
|
|
88
|
+
|
|
89
|
+
/** Phantom type carrying schema and storeId information */
|
|
90
|
+
export interface StoreContextId<TSchema extends LiveStoreSchema, TStoreId extends string> {
|
|
91
|
+
readonly [StoreContextTypeId]: {
|
|
92
|
+
readonly schema: TSchema
|
|
93
|
+
readonly storeId: TStoreId
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Phantom type for deferred store context */
|
|
98
|
+
declare const DeferredContextTypeId: unique symbol
|
|
99
|
+
|
|
100
|
+
export interface DeferredContextId<TStoreId extends string> {
|
|
101
|
+
readonly [DeferredContextTypeId]: {
|
|
102
|
+
readonly storeId: TStoreId
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Props for creating a store layer (schema and storeId are already provided) */
|
|
107
|
+
export type StoreLayerProps<TSchema extends LiveStoreSchema, TContext = {}> = Omit<
|
|
108
|
+
LiveStoreContextProps<TSchema, TContext>,
|
|
109
|
+
'storeId' | 'schema'
|
|
110
|
+
>
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Type for a Store.Tag class. This is the return type of `Store.Tag(schema, storeId)`.
|
|
114
|
+
* Can be extended as a class and is yieldable in Effect.gen.
|
|
115
|
+
*
|
|
116
|
+
* Note: This uses a type alias with a new() signature to make it extendable.
|
|
117
|
+
*/
|
|
118
|
+
export type StoreTagClass<TSchema extends LiveStoreSchema, TStoreId extends string> = {
|
|
119
|
+
/** Constructor signature (makes the type extendable as a class) */
|
|
120
|
+
new (): Context.Tag<StoreContextId<TSchema, TStoreId>, LiveStoreContextRunningType<TSchema>>
|
|
121
|
+
|
|
122
|
+
/** Tag identity type (from Context.Tag) */
|
|
123
|
+
readonly Id: StoreContextId<TSchema, TStoreId>
|
|
124
|
+
|
|
125
|
+
/** Service type (from Context.Tag) */
|
|
126
|
+
readonly Type: LiveStoreContextRunningType<TSchema>
|
|
127
|
+
|
|
128
|
+
/** The LiveStore schema for this store */
|
|
129
|
+
readonly schema: TSchema
|
|
130
|
+
|
|
131
|
+
/** Unique identifier for this store */
|
|
132
|
+
readonly storeId: TStoreId
|
|
133
|
+
|
|
134
|
+
/** Creates a layer that initializes the store */
|
|
135
|
+
layer<TContext = {}>(
|
|
136
|
+
props: StoreLayerProps<TSchema, TContext>,
|
|
137
|
+
): Layer.Layer<StoreTagClass<TSchema, TStoreId>, UnknownError | Cause.TimeoutException, OtelTracer.OtelTracer>
|
|
138
|
+
|
|
139
|
+
/** Deferred store tag for async initialization patterns */
|
|
140
|
+
readonly Deferred: Context.Tag<
|
|
141
|
+
DeferredContextId<TStoreId>,
|
|
142
|
+
Deferred.Deferred<LiveStoreContextRunningType<TSchema>, UnknownError>
|
|
143
|
+
>
|
|
144
|
+
|
|
145
|
+
/** Layer that provides the Deferred tag */
|
|
146
|
+
readonly DeferredLayer: Layer.Layer<DeferredContextId<TStoreId>, never, never>
|
|
147
|
+
|
|
148
|
+
/** Layer that waits for Deferred and provides the running store */
|
|
149
|
+
readonly fromDeferred: Layer.Layer<StoreTagClass<TSchema, TStoreId>, UnknownError, DeferredContextId<TStoreId>>
|
|
150
|
+
|
|
151
|
+
/** Query the store. Returns an Effect that yields the query result. */
|
|
152
|
+
query<TResult>(query: Queryable<TResult>): Effect.Effect<TResult, never, StoreTagClass<TSchema, TStoreId>>
|
|
153
|
+
|
|
154
|
+
/** Commit events to the store. */
|
|
155
|
+
commit(
|
|
156
|
+
...eventInputs: LiveStoreEvent.Input.ForSchema<TSchema>[]
|
|
157
|
+
): Effect.Effect<void, never, StoreTagClass<TSchema, TStoreId>>
|
|
158
|
+
|
|
159
|
+
/** Use the store with a callback function. */
|
|
160
|
+
use<A, E, R>(
|
|
161
|
+
f: (ctx: LiveStoreContextRunningType<TSchema>) => Effect.Effect<A, E, R>,
|
|
162
|
+
): Effect.Effect<A, E, R | StoreTagClass<TSchema, TStoreId>>
|
|
163
|
+
} & Context.Tag<StoreContextId<TSchema, TStoreId>, LiveStoreContextRunningType<TSchema>>
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Create a typed store context class for use with Effect.
|
|
167
|
+
*
|
|
168
|
+
* Returns a class that extends `Context.Tag`, making it directly yieldable in Effect code.
|
|
169
|
+
* The class includes static methods for creating layers and accessors for common operations.
|
|
170
|
+
*
|
|
171
|
+
* @param schema - The LiveStore schema (used for type inference and runtime)
|
|
172
|
+
* @param storeId - Unique identifier for this store
|
|
173
|
+
*
|
|
174
|
+
* @example Basic usage
|
|
175
|
+
* ```ts
|
|
176
|
+
* import { Store } from '@livestore/livestore/effect'
|
|
177
|
+
* import { schema } from './schema.ts'
|
|
178
|
+
*
|
|
179
|
+
* // Define your store (once per store)
|
|
180
|
+
* export class MainStore extends Store.Tag(schema, 'main') {}
|
|
181
|
+
*
|
|
182
|
+
* // Create the layer
|
|
183
|
+
* const storeLayer = MainStore.layer({
|
|
184
|
+
* adapter: myAdapter,
|
|
185
|
+
* batchUpdates: ReactDOM.unstable_batchedUpdates,
|
|
186
|
+
* })
|
|
187
|
+
*
|
|
188
|
+
* // Use in Effect code
|
|
189
|
+
* Effect.gen(function* () {
|
|
190
|
+
* const { store } = yield* MainStore
|
|
191
|
+
* // ^? Store<typeof schema> - fully typed!
|
|
192
|
+
*
|
|
193
|
+
* // Or use accessors
|
|
194
|
+
* const users = yield* MainStore.query(tables.users.all())
|
|
195
|
+
* yield* MainStore.commit(events.createUser({ id: '1', name: 'Alice' }))
|
|
196
|
+
* })
|
|
197
|
+
* ```
|
|
198
|
+
*
|
|
199
|
+
* @example Multiple stores
|
|
200
|
+
* ```ts
|
|
201
|
+
* class MainStore extends Store.Tag(mainSchema, 'main') {}
|
|
202
|
+
* class SettingsStore extends Store.Tag(settingsSchema, 'settings') {}
|
|
203
|
+
*
|
|
204
|
+
* // Both available in same Effect context
|
|
205
|
+
* Effect.gen(function* () {
|
|
206
|
+
* const main = yield* MainStore
|
|
207
|
+
* const settings = yield* SettingsStore
|
|
208
|
+
* })
|
|
209
|
+
*
|
|
210
|
+
* const layer = Layer.mergeAll(
|
|
211
|
+
* MainStore.layer({ adapter: mainAdapter }),
|
|
212
|
+
* SettingsStore.layer({ adapter: settingsAdapter }),
|
|
213
|
+
* )
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
const makeStoreTag = <TSchema extends LiveStoreSchema, TStoreId extends string>(
|
|
217
|
+
schema: TSchema,
|
|
218
|
+
storeId: TStoreId,
|
|
219
|
+
): StoreTagClass<TSchema, TStoreId> => {
|
|
220
|
+
type RunningType = LiveStoreContextRunningType<TSchema>
|
|
221
|
+
type DeferredType = Deferred.Deferred<RunningType, UnknownError>
|
|
222
|
+
|
|
223
|
+
// Create the deferred tag and layers upfront
|
|
224
|
+
const _DeferredTag = Context.GenericTag<DeferredContextId<TStoreId>, DeferredType>(
|
|
225
|
+
`@livestore/store-deferred/${storeId}`,
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
const _DeferredLayer = Layer.effect(_DeferredTag, Deferred.make<RunningType, UnknownError>())
|
|
229
|
+
|
|
230
|
+
class Tag extends Context.Tag(`@livestore/store/${storeId}`)<Tag, RunningType>() {
|
|
231
|
+
static readonly schema: TSchema = schema
|
|
232
|
+
static readonly storeId: TStoreId = storeId
|
|
233
|
+
|
|
234
|
+
static layer<TContext = {}>(props: StoreLayerProps<TSchema, TContext>) {
|
|
235
|
+
return pipe(
|
|
236
|
+
Effect.gen(function* () {
|
|
237
|
+
const store = yield* createStore({
|
|
238
|
+
schema,
|
|
239
|
+
storeId,
|
|
240
|
+
adapter: props.adapter,
|
|
241
|
+
batchUpdates: props.batchUpdates,
|
|
242
|
+
...omitUndefineds({
|
|
243
|
+
context: props.context,
|
|
244
|
+
boot: props.boot,
|
|
245
|
+
disableDevtools: props.disableDevtools,
|
|
246
|
+
onBootStatus: props.onBootStatus,
|
|
247
|
+
syncPayload: props.syncPayload,
|
|
248
|
+
syncPayloadSchema: props.syncPayloadSchema,
|
|
249
|
+
}),
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
globalThis.__debugLiveStore ??= {}
|
|
253
|
+
if (Object.keys(globalThis.__debugLiveStore).length === 0) {
|
|
254
|
+
globalThis.__debugLiveStore._ = store
|
|
255
|
+
}
|
|
256
|
+
globalThis.__debugLiveStore[storeId] = store
|
|
257
|
+
|
|
258
|
+
const ctx: RunningType = { stage: 'running', store: store as StoreClass<TSchema> }
|
|
259
|
+
|
|
260
|
+
// Also fulfill the deferred if it exists in context
|
|
261
|
+
yield* Effect.flatMap(Effect.serviceOption(_DeferredTag), (optDeferred) =>
|
|
262
|
+
optDeferred._tag === 'Some' ? Deferred.succeed(optDeferred.value, ctx) : Effect.void,
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
return ctx
|
|
266
|
+
}),
|
|
267
|
+
Effect.timeout(Duration.minutes(5)),
|
|
268
|
+
Effect.withSpan(`@livestore/effect:Store.Tag:${storeId}`),
|
|
269
|
+
Layer.scoped(Tag),
|
|
270
|
+
Layer.withSpan(`LiveStore:${storeId}`),
|
|
271
|
+
Layer.provide(_DeferredLayer),
|
|
272
|
+
)
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
static readonly Deferred = _DeferredTag
|
|
276
|
+
static readonly DeferredLayer = _DeferredLayer
|
|
277
|
+
|
|
278
|
+
static readonly fromDeferred = pipe(
|
|
279
|
+
Effect.gen(function* () {
|
|
280
|
+
const deferred = yield* _DeferredTag
|
|
281
|
+
const ctx = yield* deferred
|
|
282
|
+
return Layer.succeed(Tag, ctx)
|
|
283
|
+
}),
|
|
284
|
+
Layer.unwrapScoped,
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
static query<TResult>(query: Queryable<TResult>) {
|
|
288
|
+
return Effect.map(Tag, ({ store }) => store.query(query))
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
static commit(...eventInputs: LiveStoreEvent.Input.ForSchema<TSchema>[]) {
|
|
292
|
+
return Effect.map(Tag, ({ store }) => {
|
|
293
|
+
store.commit(...eventInputs)
|
|
294
|
+
})
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
static use<A, E, R>(f: (ctx: RunningType) => Effect.Effect<A, E, R>) {
|
|
298
|
+
return Effect.flatMap(Tag, f)
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return Tag as unknown as StoreTagClass<TSchema, TStoreId>
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Store utilities for Effect integration.
|
|
307
|
+
*
|
|
308
|
+
* @example
|
|
309
|
+
* ```ts
|
|
310
|
+
* import { Store } from '@livestore/livestore/effect'
|
|
311
|
+
*
|
|
312
|
+
* export class MainStore extends Store.Tag(schema, 'main') {}
|
|
313
|
+
* ```
|
|
314
|
+
*/
|
|
315
|
+
export const Store = {
|
|
316
|
+
/**
|
|
317
|
+
* Create a typed store context class for use with Effect.
|
|
318
|
+
* @see {@link makeStoreTag} for full documentation
|
|
319
|
+
*/
|
|
320
|
+
Tag: makeStoreTag,
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// =============================================================================
|
|
324
|
+
// Legacy API (deprecated)
|
|
325
|
+
// =============================================================================
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* @deprecated Use `Store.Tag(schema, storeId)` instead.
|
|
329
|
+
*
|
|
330
|
+
* @example Migration
|
|
331
|
+
* ```ts
|
|
332
|
+
* // Before
|
|
333
|
+
* const MainStoreContext = makeStoreContext<typeof schema>()('main')
|
|
334
|
+
* export const MainStore = MainStoreContext.Tag
|
|
335
|
+
* export const MainStoreLayer = MainStoreContext.Layer
|
|
336
|
+
*
|
|
337
|
+
* // After
|
|
338
|
+
* export class MainStore extends Store.Tag(schema, 'main') {}
|
|
339
|
+
* // MainStore.layer({ ... }) for the layer
|
|
340
|
+
* ```
|
|
341
|
+
*/
|
|
342
|
+
export interface StoreContext<TSchema extends LiveStoreSchema, TStoreId extends string> {
|
|
343
|
+
readonly storeId: TStoreId
|
|
344
|
+
readonly Tag: Context.Tag<StoreContextId<TSchema, TStoreId>, LiveStoreContextRunningType<TSchema>>
|
|
345
|
+
readonly DeferredTag: Context.Tag<
|
|
346
|
+
DeferredContextId<TStoreId>,
|
|
347
|
+
Deferred.Deferred<LiveStoreContextRunningType<TSchema>, UnknownError>
|
|
348
|
+
>
|
|
349
|
+
readonly Layer: <TContext = {}>(
|
|
350
|
+
props: Omit<LiveStoreContextProps<TSchema, TContext>, 'storeId'>,
|
|
351
|
+
) => Layer.Layer<StoreContextId<TSchema, TStoreId>, UnknownError | Cause.TimeoutException, OtelTracer.OtelTracer>
|
|
352
|
+
readonly DeferredLayer: Layer.Layer<DeferredContextId<TStoreId>, never, never>
|
|
353
|
+
readonly fromDeferred: Layer.Layer<StoreContextId<TSchema, TStoreId>, UnknownError, DeferredContextId<TStoreId>>
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* @deprecated Use `Store.Tag(schema, storeId)` instead.
|
|
358
|
+
*
|
|
359
|
+
* @example Migration
|
|
360
|
+
* ```ts
|
|
361
|
+
* // Before
|
|
362
|
+
* const MainStoreContext = makeStoreContext<typeof schema>()('main')
|
|
363
|
+
*
|
|
364
|
+
* // After
|
|
365
|
+
* class MainStore extends Store.Tag(schema, 'main') {}
|
|
366
|
+
* ```
|
|
367
|
+
*/
|
|
368
|
+
export const makeStoreContext =
|
|
369
|
+
<TSchema extends LiveStoreSchema>() =>
|
|
370
|
+
<TStoreId extends string>(storeId: TStoreId): StoreContext<TSchema, TStoreId> => {
|
|
371
|
+
type RunningType = LiveStoreContextRunningType<TSchema>
|
|
372
|
+
type DeferredType = Deferred.Deferred<RunningType, UnknownError>
|
|
373
|
+
|
|
374
|
+
const Tag = Context.GenericTag<StoreContextId<TSchema, TStoreId>, RunningType>(`@livestore/store/${storeId}`)
|
|
375
|
+
|
|
376
|
+
const DeferredTag = Context.GenericTag<DeferredContextId<TStoreId>, DeferredType>(
|
|
377
|
+
`@livestore/store-deferred/${storeId}`,
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
const DeferredLayer = Layer.effect(DeferredTag, Deferred.make<RunningType, UnknownError>())
|
|
381
|
+
|
|
382
|
+
const makeLayer = <TContext = {}>(
|
|
383
|
+
props: Omit<LiveStoreContextProps<TSchema, TContext>, 'storeId'>,
|
|
384
|
+
): Layer.Layer<StoreContextId<TSchema, TStoreId>, UnknownError | Cause.TimeoutException, OtelTracer.OtelTracer> =>
|
|
385
|
+
pipe(
|
|
386
|
+
Effect.gen(function* () {
|
|
387
|
+
const store = yield* createStore({
|
|
388
|
+
schema: props.schema,
|
|
389
|
+
storeId,
|
|
390
|
+
adapter: props.adapter,
|
|
391
|
+
batchUpdates: props.batchUpdates,
|
|
392
|
+
...omitUndefineds({
|
|
393
|
+
context: props.context,
|
|
394
|
+
boot: props.boot,
|
|
395
|
+
disableDevtools: props.disableDevtools,
|
|
396
|
+
onBootStatus: props.onBootStatus,
|
|
397
|
+
syncPayload: props.syncPayload,
|
|
398
|
+
syncPayloadSchema: props.syncPayloadSchema,
|
|
399
|
+
}),
|
|
400
|
+
})
|
|
401
|
+
|
|
402
|
+
globalThis.__debugLiveStore ??= {}
|
|
403
|
+
if (Object.keys(globalThis.__debugLiveStore).length === 0) {
|
|
404
|
+
globalThis.__debugLiveStore._ = store
|
|
405
|
+
}
|
|
406
|
+
globalThis.__debugLiveStore[storeId] = store
|
|
407
|
+
|
|
408
|
+
const ctx: RunningType = { stage: 'running', store: store as StoreClass<TSchema> }
|
|
409
|
+
|
|
410
|
+
// Also fulfill the deferred if it exists in context
|
|
411
|
+
yield* Effect.flatMap(Effect.serviceOption(DeferredTag), (optDeferred) =>
|
|
412
|
+
optDeferred._tag === 'Some' ? Deferred.succeed(optDeferred.value, ctx) : Effect.void,
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
return ctx
|
|
416
|
+
}),
|
|
417
|
+
Effect.timeout(Duration.minutes(5)),
|
|
418
|
+
Effect.withSpan(`@livestore/effect:makeStoreContext:${storeId}`),
|
|
419
|
+
Layer.scoped(Tag),
|
|
420
|
+
Layer.withSpan(`LiveStore:${storeId}`),
|
|
421
|
+
Layer.provide(DeferredLayer),
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
const fromDeferred: Layer.Layer<
|
|
425
|
+
StoreContextId<TSchema, TStoreId>,
|
|
426
|
+
UnknownError,
|
|
427
|
+
DeferredContextId<TStoreId>
|
|
428
|
+
> = pipe(
|
|
429
|
+
Effect.gen(function* () {
|
|
430
|
+
const deferred = yield* DeferredTag
|
|
431
|
+
const ctx = yield* deferred
|
|
432
|
+
return Layer.succeed(Tag, ctx)
|
|
433
|
+
}),
|
|
434
|
+
Layer.unwrapScoped,
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
return {
|
|
438
|
+
storeId,
|
|
439
|
+
Tag,
|
|
440
|
+
DeferredTag,
|
|
441
|
+
Layer: makeLayer,
|
|
442
|
+
DeferredLayer,
|
|
443
|
+
fromDeferred,
|
|
444
|
+
}
|
|
445
|
+
}
|
package/src/effect/mod.ts
CHANGED
|
@@ -4,4 +4,16 @@ export {
|
|
|
4
4
|
LiveStoreContextRunning as LiveStoreContext,
|
|
5
5
|
LiveStoreContextRunning,
|
|
6
6
|
} from '../store/create-store.ts'
|
|
7
|
-
|
|
7
|
+
// Store.Tag - Idiomatic Effect API
|
|
8
|
+
// Legacy API (deprecated)
|
|
9
|
+
export {
|
|
10
|
+
type DeferredContextId,
|
|
11
|
+
LiveStoreContextDeferred,
|
|
12
|
+
LiveStoreContextLayer,
|
|
13
|
+
makeStoreContext,
|
|
14
|
+
Store,
|
|
15
|
+
type StoreContext,
|
|
16
|
+
type StoreContextId,
|
|
17
|
+
type StoreLayerProps,
|
|
18
|
+
type StoreTagClass,
|
|
19
|
+
} from './LiveStore.ts'
|
package/src/mod.ts
CHANGED