Skip to content

Commit d2dfb83

Browse files
authored
add livestore integration (#253)
1 parent fa35f7d commit d2dfb83

15 files changed

Lines changed: 945 additions & 13 deletions

.changeset/dirty-bars-heal.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@effect-rx/rx-livestore": minor
3+
---
4+
5+
add livestore integration

packages/rx-livestore/.gitignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
coverage/
2+
*.tsbuildinfo
3+
node_modules/
4+
.ultra.cache.json
5+
.DS_Store
6+
tmp/
7+
build/
8+
dist/
9+
.direnv/
10+
11+
# files
12+
/src/tsconfig.json
13+
/dist
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.js
2+
*.ts

packages/rx-livestore/LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2023-present The Contributors
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

packages/rx-livestore/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
WIP.
2+
3+
Docs: https://effect-ts.github.io/rx

packages/rx-livestore/docgen.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"exclude": ["src/internal/**/*.ts"],
3+
"theme": "mikearnaldi/just-the-docs",
4+
"parseCompilerOptions": {
5+
"noEmit": true,
6+
"strict": true,
7+
"target": "es2015",
8+
"lib": ["es2015"],
9+
"paths": {
10+
"@effect-rx/rx": ["./src/index.ts"],
11+
"@effect-rx/rx/*": ["./src/*"]
12+
}
13+
},
14+
"examplesCompilerOptions": {
15+
"noEmit": true,
16+
"strict": true,
17+
"target": "es2015",
18+
"lib": ["es2015"],
19+
"paths": {
20+
"@effect-rx/rx": ["./src/index.ts"],
21+
"@effect-rx/rx/*": ["./src/*"]
22+
}
23+
}
24+
}

packages/rx-livestore/package.json

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"name": "@effect-rx/rx-livestore",
3+
"version": "0.0.0",
4+
"description": "effect-rx bindings to livestore",
5+
"type": "module",
6+
"publishConfig": {
7+
"access": "public",
8+
"directory": "dist"
9+
},
10+
"repository": {
11+
"type": "git",
12+
"url": "https://github.com/effect-ts/rx.git"
13+
},
14+
"homepage": "https://github.com/effect-ts/rx",
15+
"scripts": {
16+
"build": "pnpm build-prepare && pnpm build-esm && pnpm build-cjs && pnpm build-annotate && build-utils pack-v2",
17+
"build-prepare": "build-utils prepare-v2",
18+
"build-esm": "tsc -b tsconfig.build.json",
19+
"build-cjs": "babel build/esm --plugins @babel/transform-export-namespace-from --plugins @babel/transform-modules-commonjs --out-dir build/cjs --source-maps",
20+
"build-annotate": "babel build --plugins annotate-pure-calls --out-dir build --source-maps"
21+
},
22+
"keywords": [],
23+
"author": "Effect contributors",
24+
"license": "MIT",
25+
"sideEffects": [],
26+
"devDependencies": {
27+
"@livestore/livestore": "^0.3.1",
28+
"effect": "^3.17.0"
29+
},
30+
"peerDependencies": {
31+
"@livestore/livestore": "*",
32+
"effect": "^3.17"
33+
},
34+
"dependencies": {
35+
"@effect-rx/rx": "workspace:^"
36+
}
37+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/**
2+
* @since 1.0.0
3+
*/
4+
/* eslint-disable @typescript-eslint/no-empty-object-type */
5+
import * as Result from "@effect-rx/rx/Result"
6+
import * as Rx from "@effect-rx/rx/Rx"
7+
import type { CreateStoreOptions, LiveQueryDef, LiveStoreSchema, OtelOptions, Store } from "@livestore/livestore"
8+
import { createStore, provideOtel } from "@livestore/livestore"
9+
import * as Context from "effect/Context"
10+
import * as Effect from "effect/Effect"
11+
import { constUndefined } from "effect/Function"
12+
import * as Layer from "effect/Layer"
13+
import type { Option } from "effect/Option"
14+
15+
/**
16+
* @since 1.0.0
17+
* @category Store
18+
*/
19+
export interface StoreService {
20+
readonly _: unique symbol
21+
}
22+
23+
/**
24+
* @since 1.0.0
25+
* @category Constructors
26+
*/
27+
export const make = <S extends LiveStoreSchema, Context = {}>(
28+
options: CreateStoreOptions<S, Context> & {
29+
readonly otelOptions?: Partial<OtelOptions> | undefined
30+
}
31+
): {
32+
readonly runtimeRx: Rx.RxRuntime<StoreService, never>
33+
readonly storeRx: Rx.Rx<Result.Result<Store<S, Context>>>
34+
readonly storeRxUnsafe: Rx.Rx<Store<S, Context>>
35+
readonly makeQueryRx: <A>(query: LiveQueryDef<A>) => Rx.Rx<Result.Result<A>>
36+
readonly makeQueryRxUnsafe: <A>(query: LiveQueryDef<A>) => Rx.Rx<A>
37+
readonly commitRx: Rx.Writable<Option<void>, {}>
38+
} => {
39+
const StoreService = Context.GenericTag<StoreService, Store<S, Context>>("@effect-rx/rx-livestore/StoreService")
40+
const runtimeRx = Rx.runtime(Layer.scoped(
41+
StoreService,
42+
createStore(options).pipe(
43+
provideOtel({
44+
parentSpanContext: options?.otelOptions?.rootSpanContext,
45+
otelTracer: options?.otelOptions?.tracer
46+
}),
47+
Effect.orDie
48+
)
49+
))
50+
const storeRx = runtimeRx.rx(StoreService)
51+
const storeRxUnsafe = Rx.readable((get) => {
52+
const result = get(storeRx)
53+
return Result.getOrElse(result, constUndefined) as Store<S, Context>
54+
})
55+
const makeQueryRx = <A>(query: LiveQueryDef<A>) =>
56+
Rx.readable((get) => {
57+
const store = get(storeRx)
58+
return Result.map(store, (store) => {
59+
const result = store.query(query)
60+
get.addFinalizer(
61+
store.subscribe(query, {
62+
onUpdate(value) {
63+
get.setSelf(Result.success(value))
64+
}
65+
})
66+
)
67+
return result
68+
})
69+
})
70+
const makeQueryRxUnsafe = <A>(query: LiveQueryDef<A>) =>
71+
Rx.readable((get) => {
72+
const store = get(storeRxUnsafe)
73+
get.addFinalizer(
74+
store.subscribe(query, {
75+
onUpdate(value) {
76+
get.setSelf(Result.success(value))
77+
}
78+
})
79+
)
80+
return store.query(query)
81+
})
82+
const commitRx = Rx.fnSync((event: {}, get) => {
83+
get(storeRxUnsafe)?.commit(event)
84+
})
85+
return {
86+
runtimeRx,
87+
storeRx,
88+
storeRxUnsafe,
89+
makeQueryRx,
90+
makeQueryRxUnsafe,
91+
commitRx
92+
} as const
93+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"extends": "./tsconfig.src.json",
3+
"compilerOptions": {
4+
"tsBuildInfoFile": ".tsbuildinfo/build.tsbuildinfo",
5+
"outDir": "build/esm",
6+
"declarationDir": "build/dts",
7+
"stripInternal": true
8+
},
9+
"references": [{ "path": "../rx" }]
10+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"extends": "../../tsconfig.base.json",
3+
"include": [
4+
"examples"
5+
],
6+
"references": [
7+
{
8+
"path": "tsconfig.build.json"
9+
}
10+
],
11+
"compilerOptions": {
12+
"tsBuildInfoFile": ".tsbuildinfo/examples.tsbuildinfo",
13+
"rootDir": "examples",
14+
"noEmit": true
15+
}
16+
}

0 commit comments

Comments
 (0)