@thomasfosterau/effect-svelte 0.1.0 → 0.3.0
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/await.svelte.d.ts +53 -0
- package/dist/await.svelte.js +44 -0
- package/dist/await.svelte.js.map +1 -0
- package/dist/context.svelte.d.ts +51 -1
- package/dist/context.svelte.js +43 -1
- package/dist/context.svelte.js.map +1 -1
- package/dist/derived.svelte.d.ts +32 -12
- package/dist/derived.svelte.js +23 -13
- package/dist/derived.svelte.js.map +1 -1
- package/dist/effect.svelte.d.ts +21 -2
- package/dist/effect.svelte.js +13 -3
- package/dist/effect.svelte.js.map +1 -1
- package/dist/index.d.ts +12 -7
- package/dist/index.js +6 -2
- package/dist/internal/await.js +52 -0
- package/dist/internal/await.js.map +1 -0
- package/dist/internal/live-stream.js +43 -0
- package/dist/internal/live-stream.js.map +1 -0
- package/dist/internal/mutation.d.ts +38 -0
- package/dist/internal/mutation.js +61 -0
- package/dist/internal/mutation.js.map +1 -0
- package/dist/internal/result.svelte.d.ts +1 -0
- package/dist/internal/writable.js +21 -0
- package/dist/internal/writable.js.map +1 -0
- package/dist/live-stream.svelte.d.ts +72 -0
- package/dist/live-stream.svelte.js +77 -0
- package/dist/live-stream.svelte.js.map +1 -0
- package/dist/mutation.svelte.d.ts +65 -0
- package/dist/mutation.svelte.js +53 -0
- package/dist/mutation.svelte.js.map +1 -0
- package/dist/query.svelte.d.ts +21 -2
- package/dist/query.svelte.js +10 -3
- package/dist/query.svelte.js.map +1 -1
- package/dist/reactivity.svelte.d.ts +15 -5
- package/dist/reactivity.svelte.js +8 -8
- package/dist/reactivity.svelte.js.map +1 -1
- package/dist/stream.svelte.d.ts +10 -2
- package/dist/stream.svelte.js +2 -2
- package/dist/stream.svelte.js.map +1 -1
- package/dist/subscription.svelte.d.ts +12 -3
- package/dist/subscription.svelte.js +4 -4
- package/dist/subscription.svelte.js.map +1 -1
- package/dist/writable-ref.svelte.d.ts +53 -0
- package/dist/writable-ref.svelte.js +66 -0
- package/dist/writable-ref.svelte.js.map +1 -0
- package/package.json +1 -1
|
@@ -36,8 +36,8 @@ import { Reactivity } from "effect/unstable/reactivity";
|
|
|
36
36
|
* {/if}
|
|
37
37
|
* ```
|
|
38
38
|
*/
|
|
39
|
-
function reactiveQuery(keys, effectFn) {
|
|
40
|
-
const runtime = getRuntimeContext();
|
|
39
|
+
function reactiveQuery(keys, effectFn, options = {}) {
|
|
40
|
+
const runtime = options.runtime ?? getRuntimeContext();
|
|
41
41
|
const state = makeResult();
|
|
42
42
|
let fiber = null;
|
|
43
43
|
$effect(() => {
|
|
@@ -93,8 +93,8 @@ function reactiveQuery(keys, effectFn) {
|
|
|
93
93
|
* </ul>
|
|
94
94
|
* ```
|
|
95
95
|
*/
|
|
96
|
-
function reactiveStream(keys, effect) {
|
|
97
|
-
return streamState(getRuntimeContext(), () => {
|
|
96
|
+
function reactiveStream(keys, effect, options = {}) {
|
|
97
|
+
return streamState(options.runtime ?? getRuntimeContext(), () => {
|
|
98
98
|
const currentKeys = typeof keys === "function" ? keys() : keys;
|
|
99
99
|
const currentEffect = typeof effect === "function" ? effect() : effect;
|
|
100
100
|
return Reactivity.stream(currentEffect, currentKeys);
|
|
@@ -124,8 +124,8 @@ function reactiveStream(keys, effect) {
|
|
|
124
124
|
* <button onclick={() => updateUser.run()}>Update</button>
|
|
125
125
|
* ```
|
|
126
126
|
*/
|
|
127
|
-
function reactiveMutation(keys, effect) {
|
|
128
|
-
const runtime = getRuntimeContext();
|
|
127
|
+
function reactiveMutation(keys, effect, options = {}) {
|
|
128
|
+
const runtime = options.runtime ?? getRuntimeContext();
|
|
129
129
|
const state = makeResult();
|
|
130
130
|
let currentFiber = null;
|
|
131
131
|
const run = () => {
|
|
@@ -174,8 +174,8 @@ function reactiveMutation(keys, effect) {
|
|
|
174
174
|
* <button onclick={() => invalidate(['users'])}>Refresh Users</button>
|
|
175
175
|
* ```
|
|
176
176
|
*/
|
|
177
|
-
function useInvalidateKeys() {
|
|
178
|
-
const runtime = getRuntimeContext();
|
|
177
|
+
function useInvalidateKeys(options = {}) {
|
|
178
|
+
const runtime = options.runtime ?? getRuntimeContext();
|
|
179
179
|
return (keys) => {
|
|
180
180
|
runSync(runtime)(Reactivity.invalidate(keys));
|
|
181
181
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reactivity.svelte.js","names":["getRuntime"],"sources":["../src/reactivity.svelte.ts"],"sourcesContent":["import { Effect, Fiber, Stream } from \"effect\";\nimport type * as AsyncResult from \"effect/unstable/reactivity/AsyncResult\";\nimport { Reactivity } from \"effect/unstable/reactivity\";\nimport { getRuntime } from \"./context.svelte.js\";\nimport { interruptFiber, runFork, runSync, type RuntimeLike } from \"./internal/run.js\";\nimport { makeResult } from \"./internal/result.svelte.js\";\nimport { streamState } from \"./internal/subscribe.js\";\n\nexport interface ReactiveQueryReturn<A, E> {\n /** The current result, re-derived whenever the keys are invalidated. */\n readonly current: AsyncResult.AsyncResult<A, E>;\n}\n\n/**\n * Creates a reactive query that automatically re-runs when the specified keys are invalidated.\n *\n * Note: Make sure your runtime includes `Reactivity.layer` from `effect/unstable/reactivity`.\n *\n * @param keys - Reactivity keys that this query depends on\n * @param effectFn - The Effect to run when keys are invalidated\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { reactiveQuery, AsyncResult } from '@thomasfosterau/effect-svelte';\n * import { Effect } from 'effect';\n *\n * // Query that depends on a user ID key\n * let userId = $state(1);\n *\n * const user = reactiveQuery(\n * () => ['user', userId],\n * () => Effect.gen(function* () {\n * const data = yield* fetchUser(userId);\n * return data;\n * })\n * );\n * </script>\n *\n * {#if AsyncResult.isSuccess(user.current)}\n * <p>User: {user.current.value.name}</p>\n * {/if}\n * ```\n */\nexport function reactiveQuery<A, E, R>(\n keys: () => ReadonlyArray<unknown>,\n effectFn: () => Effect.Effect<A, E, R>,\n): ReactiveQueryReturn<A, E> {\n const runtime = getRuntime() as RuntimeLike<R | Reactivity.Reactivity
|
|
1
|
+
{"version":3,"file":"reactivity.svelte.js","names":["getRuntime"],"sources":["../src/reactivity.svelte.ts"],"sourcesContent":["import { Effect, Fiber, Stream } from \"effect\";\nimport type * as AsyncResult from \"effect/unstable/reactivity/AsyncResult\";\nimport { Reactivity } from \"effect/unstable/reactivity\";\nimport { getRuntime } from \"./context.svelte.js\";\nimport { interruptFiber, runFork, runSync, type RuntimeLike } from \"./internal/run.js\";\nimport { makeResult } from \"./internal/result.svelte.js\";\nimport { streamState } from \"./internal/subscribe.js\";\n\nexport interface ReactiveQueryReturn<A, E> {\n /** The current result, re-derived whenever the keys are invalidated. */\n readonly current: AsyncResult.AsyncResult<A, E>;\n}\n\nexport interface ReactiveOptions<R> {\n /**\n * Run against this runtime instead of the ambient context. Must still provide\n * `Reactivity.Reactivity`; when provided, the effect's `R` is otherwise\n * constrained to what the runtime provides.\n */\n readonly runtime?: RuntimeLike<R | Reactivity.Reactivity>;\n}\n\n/**\n * Creates a reactive query that automatically re-runs when the specified keys are invalidated.\n *\n * Note: Make sure your runtime includes `Reactivity.layer` from `effect/unstable/reactivity`.\n *\n * @param keys - Reactivity keys that this query depends on\n * @param effectFn - The Effect to run when keys are invalidated\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { reactiveQuery, AsyncResult } from '@thomasfosterau/effect-svelte';\n * import { Effect } from 'effect';\n *\n * // Query that depends on a user ID key\n * let userId = $state(1);\n *\n * const user = reactiveQuery(\n * () => ['user', userId],\n * () => Effect.gen(function* () {\n * const data = yield* fetchUser(userId);\n * return data;\n * })\n * );\n * </script>\n *\n * {#if AsyncResult.isSuccess(user.current)}\n * <p>User: {user.current.value.name}</p>\n * {/if}\n * ```\n */\nexport function reactiveQuery<A, E, R>(\n keys: () => ReadonlyArray<unknown>,\n effectFn: () => Effect.Effect<A, E, R>,\n options: ReactiveOptions<R> = {},\n): ReactiveQueryReturn<A, E> {\n const runtime = options.runtime ?? (getRuntime() as RuntimeLike<R | Reactivity.Reactivity>);\n\n const state = makeResult<A, E>();\n let fiber: Fiber.Fiber<void, never> | null = null;\n\n $effect(() => {\n // Get the current keys (tracks Svelte dependencies)\n const currentKeys = keys();\n const effect = effectFn();\n\n // Mark as waiting, preserving any previous value.\n state.startWaiting();\n\n // Run the reactive query inside a scope so that the registered\n // invalidation handlers are cleaned up when the fiber is interrupted.\n const queryEffect = Effect.scoped(\n Effect.gen(function* () {\n const queue = yield* Reactivity.query(effect, currentKeys);\n yield* Stream.runForEach(Stream.fromQueue(queue), (value) =>\n Effect.sync(() => {\n state.succeed(value);\n }),\n );\n }),\n ).pipe(\n Effect.catchCause((cause) =>\n Effect.sync(() => {\n state.failCause(cause);\n }),\n ),\n );\n\n const runningFiber = runFork(runtime)(queryEffect);\n fiber = runningFiber;\n\n // Cleanup: interrupt the fiber when dependencies change or component unmounts\n return () => {\n if (fiber !== null) {\n interruptFiber(fiber);\n fiber = null;\n }\n };\n });\n\n return {\n get current() {\n return state.current;\n },\n };\n}\n\nexport interface ReactiveStreamReturn<A, E> {\n readonly current: AsyncResult.AsyncResult<ReadonlyArray<A>, E>;\n readonly values: ReadonlyArray<A>;\n readonly latest: A | undefined;\n}\n\n/**\n * Creates a reactive stream that emits values whenever the specified keys are invalidated.\n * The effect re-runs automatically when keys change.\n *\n * @param keys - Reactivity keys that this stream depends on\n * @param effect - The Effect to run when keys are invalidated\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { reactiveStream } from '@thomasfosterau/effect-svelte';\n * import { Effect } from 'effect';\n *\n * const messages = reactiveStream(\n * ['messages'],\n * Effect.gen(function* () {\n * const data = yield* fetchMessages();\n * return data;\n * })\n * );\n * </script>\n *\n * <ul>\n * {#each messages.values as msg}\n * <li>{msg}</li>\n * {/each}\n * </ul>\n * ```\n */\nexport function reactiveStream<A, E, R>(\n keys: ReadonlyArray<unknown> | (() => ReadonlyArray<unknown>),\n effect: Effect.Effect<A, E, R> | (() => Effect.Effect<A, E, R>),\n options: ReactiveOptions<R> = {},\n): ReactiveStreamReturn<A, E> {\n const runtime = options.runtime ?? (getRuntime() as RuntimeLike<R | Reactivity.Reactivity>);\n return streamState(runtime, () => {\n const currentKeys = typeof keys === \"function\" ? keys() : keys;\n const currentEffect = typeof effect === \"function\" ? effect() : effect;\n return Reactivity.stream(currentEffect, currentKeys);\n });\n}\n\nexport interface ReactiveMutationReturn<A, E> {\n readonly current: AsyncResult.AsyncResult<A, E>;\n run: () => void;\n}\n\n/**\n * Runs a mutation effect and invalidates the specified keys.\n * This will cause any reactive queries depending on these keys to re-run.\n *\n * @param keys - Reactivity keys to invalidate after the mutation\n * @param effect - The mutation effect to run\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { reactiveMutation } from '@thomasfosterau/effect-svelte';\n * import { Effect } from 'effect';\n *\n * const updateUser = reactiveMutation(\n * ['user', userId],\n * Effect.gen(function* () {\n * yield* updateUserInDB(userId, data);\n * })\n * );\n * </script>\n *\n * <button onclick={() => updateUser.run()}>Update</button>\n * ```\n */\nexport function reactiveMutation<A, E, R>(\n keys: ReadonlyArray<unknown> | (() => ReadonlyArray<unknown>),\n effect: Effect.Effect<A, E, R> | (() => Effect.Effect<A, E, R>),\n options: ReactiveOptions<R> = {},\n): ReactiveMutationReturn<A, E> {\n const runtime = options.runtime ?? (getRuntime() as RuntimeLike<R | Reactivity.Reactivity>);\n\n const state = makeResult<A, E>();\n let currentFiber: Fiber.Fiber<A, E> | null = null;\n\n const run = () => {\n if (currentFiber !== null) {\n interruptFiber(currentFiber);\n }\n\n const currentKeys = typeof keys === \"function\" ? keys() : keys;\n const currentEffect = typeof effect === \"function\" ? effect() : effect;\n\n state.startWaiting();\n\n const mutationEffect = Reactivity.mutation(currentEffect, currentKeys);\n const runningFiber = runFork(runtime)(mutationEffect);\n currentFiber = runningFiber;\n\n runFork(runtime)(\n Effect.gen(function* () {\n const exit = yield* Fiber.await(runningFiber);\n if (currentFiber === runningFiber) {\n state.settle(exit);\n currentFiber = null;\n }\n }),\n );\n };\n\n $effect(() => {\n // Cleanup: interrupt any running fiber on unmount\n return () => {\n if (currentFiber !== null) {\n interruptFiber(currentFiber);\n currentFiber = null;\n }\n };\n });\n\n return {\n get current() {\n return state.current;\n },\n run,\n };\n}\n\n/**\n * Returns a function that manually invalidates reactivity keys, causing any\n * reactive queries depending on those keys to re-run.\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { useInvalidateKeys } from '@thomasfosterau/effect-svelte';\n *\n * const invalidate = useInvalidateKeys();\n * </script>\n *\n * <button onclick={() => invalidate(['users'])}>Refresh Users</button>\n * ```\n */\nexport function useInvalidateKeys(\n options: ReactiveOptions<never> = {},\n): (keys: ReadonlyArray<unknown>) => void {\n const runtime = options.runtime ?? (getRuntime() as RuntimeLike<Reactivity.Reactivity>);\n return (keys) => {\n runSync(runtime)(Reactivity.invalidate(keys));\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqDA,SAAgB,cACd,MACA,UACA,UAA8B,CAAC,GACJ;CAC3B,MAAM,UAAU,QAAQ,WAAYA,kBAAW;CAE/C,MAAM,QAAQ,WAAiB;CAC/B,IAAI,QAAyC;CAE7C,cAAc;EAEZ,MAAM,cAAc,KAAK;EACzB,MAAM,SAAS,SAAS;EAGxB,MAAM,aAAa;EAInB,MAAM,cAAc,OAAO,OACzB,OAAO,IAAI,aAAa;GACtB,MAAM,QAAQ,OAAO,WAAW,MAAM,QAAQ,WAAW;GACzD,OAAO,OAAO,WAAW,OAAO,UAAU,KAAK,IAAI,UACjD,OAAO,WAAW;IAChB,MAAM,QAAQ,KAAK;GACrB,CAAC,CACH;EACF,CAAC,CACH,EAAE,KACA,OAAO,YAAY,UACjB,OAAO,WAAW;GAChB,MAAM,UAAU,KAAK;EACvB,CAAC,CACH,CACF;EAGA,QADqB,QAAQ,OAAO,EAAE,WACnB;EAGnB,aAAa;GACX,IAAI,UAAU,MAAM;IAClB,eAAe,KAAK;IACpB,QAAQ;GACV;EACF;CACF,CAAC;CAED,OAAO,EACL,IAAI,UAAU;EACZ,OAAO,MAAM;CACf,EACF;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCA,SAAgB,eACd,MACA,QACA,UAA8B,CAAC,GACH;CAE5B,OAAO,YADS,QAAQ,WAAYA,kBAAW,SACb;EAChC,MAAM,cAAc,OAAO,SAAS,aAAa,KAAK,IAAI;EAC1D,MAAM,gBAAgB,OAAO,WAAW,aAAa,OAAO,IAAI;EAChE,OAAO,WAAW,OAAO,eAAe,WAAW;CACrD,CAAC;AACH;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,SAAgB,iBACd,MACA,QACA,UAA8B,CAAC,GACD;CAC9B,MAAM,UAAU,QAAQ,WAAYA,kBAAW;CAE/C,MAAM,QAAQ,WAAiB;CAC/B,IAAI,eAAyC;CAE7C,MAAM,YAAY;EAChB,IAAI,iBAAiB,MACnB,eAAe,YAAY;EAG7B,MAAM,cAAc,OAAO,SAAS,aAAa,KAAK,IAAI;EAC1D,MAAM,gBAAgB,OAAO,WAAW,aAAa,OAAO,IAAI;EAEhE,MAAM,aAAa;EAEnB,MAAM,iBAAiB,WAAW,SAAS,eAAe,WAAW;EACrE,MAAM,eAAe,QAAQ,OAAO,EAAE,cAAc;EACpD,eAAe;EAEf,QAAQ,OAAO,EACb,OAAO,IAAI,aAAa;GACtB,MAAM,OAAO,OAAO,MAAM,MAAM,YAAY;GAC5C,IAAI,iBAAiB,cAAc;IACjC,MAAM,OAAO,IAAI;IACjB,eAAe;GACjB;EACF,CAAC,CACH;CACF;CAEA,cAAc;EAEZ,aAAa;GACX,IAAI,iBAAiB,MAAM;IACzB,eAAe,YAAY;IAC3B,eAAe;GACjB;EACF;CACF,CAAC;CAED,OAAO;EACL,IAAI,UAAU;GACZ,OAAO,MAAM;EACf;EACA;CACF;AACF;;;;;;;;;;;;;;;;AAiBA,SAAgB,kBACd,UAAkC,CAAC,GACK;CACxC,MAAM,UAAU,QAAQ,WAAYA,kBAAW;CAC/C,QAAQ,SAAS;EACf,QAAQ,OAAO,EAAE,WAAW,WAAW,IAAI,CAAC;CAC9C;AACF"}
|
package/dist/stream.svelte.d.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
|
+
import { RuntimeLike } from "./internal/run.js";
|
|
1
2
|
import { Stream } from "effect";
|
|
2
3
|
import * as AsyncResult from "effect/unstable/reactivity/AsyncResult";
|
|
3
4
|
|
|
4
5
|
//#region src/stream.svelte.d.ts
|
|
6
|
+
interface UseStreamOptions<R> {
|
|
7
|
+
/**
|
|
8
|
+
* Run against this runtime instead of the ambient context. When provided, the
|
|
9
|
+
* stream's `R` is constrained to what the runtime provides.
|
|
10
|
+
*/
|
|
11
|
+
readonly runtime?: RuntimeLike<R>;
|
|
12
|
+
}
|
|
5
13
|
interface UseStreamReturn<A, E> {
|
|
6
14
|
/**
|
|
7
15
|
* The current result state of the stream. `Initial`/`Success` carry a
|
|
@@ -42,7 +50,7 @@ interface UseStreamReturn<A, E> {
|
|
|
42
50
|
* <p>All values: {counter.values.join(', ')}</p>
|
|
43
51
|
* ```
|
|
44
52
|
*/
|
|
45
|
-
declare function useStream<A, E, R>(stream: Stream.Stream<A, E, R>): UseStreamReturn<A, E>;
|
|
53
|
+
declare function useStream<A, E, R>(stream: Stream.Stream<A, E, R>, options?: UseStreamOptions<R>): UseStreamReturn<A, E>;
|
|
46
54
|
//#endregion
|
|
47
|
-
export { UseStreamReturn, useStream };
|
|
55
|
+
export { UseStreamOptions, UseStreamReturn, useStream };
|
|
48
56
|
//# sourceMappingURL=stream.svelte.d.ts.map
|
package/dist/stream.svelte.js
CHANGED
|
@@ -25,8 +25,8 @@ import { streamState } from "./internal/subscribe.js";
|
|
|
25
25
|
* <p>All values: {counter.values.join(', ')}</p>
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
|
-
function useStream(stream) {
|
|
29
|
-
return streamState(getRuntimeContext(), () => stream);
|
|
28
|
+
function useStream(stream, options = {}) {
|
|
29
|
+
return streamState(options.runtime ?? getRuntimeContext(), () => stream);
|
|
30
30
|
}
|
|
31
31
|
//#endregion
|
|
32
32
|
export { useStream };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream.svelte.js","names":["getRuntime"],"sources":["../src/stream.svelte.ts"],"sourcesContent":["import type { Stream } from \"effect\";\nimport type * as AsyncResult from \"effect/unstable/reactivity/AsyncResult\";\nimport { getRuntime } from \"./context.svelte.js\";\nimport type { RuntimeLike } from \"./internal/run.js\";\nimport { streamState } from \"./internal/subscribe.js\";\n\nexport interface UseStreamReturn<A, E> {\n /**\n * The current result state of the stream. `Initial`/`Success` carry a\n * `waiting` flag while the stream is still live (stale-while-revalidate), and\n * settle to a non-waiting `Success`/`Failure` once it completes.\n */\n readonly current: AsyncResult.AsyncResult<ReadonlyArray<A>, E>;\n\n /**\n * All values emitted by the stream so far\n */\n readonly values: ReadonlyArray<A>;\n\n /**\n * The most recent value emitted by the stream (undefined if none)\n */\n readonly latest: A | undefined;\n}\n\n/**\n * Subscribe to a Stream and collect emissions.\n *\n * The subscription starts the first time `current`/`values`/`latest` is read\n * inside an effect or template, and is interrupted automatically when the last\n * reader is destroyed (via Svelte's `createSubscriber`).\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { useStream } from '@thomasfosterau/effect-svelte';\n * import { Stream, Schedule } from 'effect';\n *\n * const counter = useStream(\n * Stream.iterate(0, n => n + 1).pipe(\n * Stream.schedule(Schedule.spaced('1 second'))\n * )\n * );\n * </script>\n *\n * <p>Latest: {counter.latest}</p>\n * <p>All values: {counter.values.join(', ')}</p>\n * ```\n */\nexport function useStream<A, E, R>(stream: Stream.Stream<A, E, R>): UseStreamReturn<A, E> {\n const runtime = getRuntime() as RuntimeLike<R
|
|
1
|
+
{"version":3,"file":"stream.svelte.js","names":["getRuntime"],"sources":["../src/stream.svelte.ts"],"sourcesContent":["import type { Stream } from \"effect\";\nimport type * as AsyncResult from \"effect/unstable/reactivity/AsyncResult\";\nimport { getRuntime } from \"./context.svelte.js\";\nimport type { RuntimeLike } from \"./internal/run.js\";\nimport { streamState } from \"./internal/subscribe.js\";\n\nexport interface UseStreamOptions<R> {\n /**\n * Run against this runtime instead of the ambient context. When provided, the\n * stream's `R` is constrained to what the runtime provides.\n */\n readonly runtime?: RuntimeLike<R>;\n}\n\nexport interface UseStreamReturn<A, E> {\n /**\n * The current result state of the stream. `Initial`/`Success` carry a\n * `waiting` flag while the stream is still live (stale-while-revalidate), and\n * settle to a non-waiting `Success`/`Failure` once it completes.\n */\n readonly current: AsyncResult.AsyncResult<ReadonlyArray<A>, E>;\n\n /**\n * All values emitted by the stream so far\n */\n readonly values: ReadonlyArray<A>;\n\n /**\n * The most recent value emitted by the stream (undefined if none)\n */\n readonly latest: A | undefined;\n}\n\n/**\n * Subscribe to a Stream and collect emissions.\n *\n * The subscription starts the first time `current`/`values`/`latest` is read\n * inside an effect or template, and is interrupted automatically when the last\n * reader is destroyed (via Svelte's `createSubscriber`).\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { useStream } from '@thomasfosterau/effect-svelte';\n * import { Stream, Schedule } from 'effect';\n *\n * const counter = useStream(\n * Stream.iterate(0, n => n + 1).pipe(\n * Stream.schedule(Schedule.spaced('1 second'))\n * )\n * );\n * </script>\n *\n * <p>Latest: {counter.latest}</p>\n * <p>All values: {counter.values.join(', ')}</p>\n * ```\n */\nexport function useStream<A, E, R>(\n stream: Stream.Stream<A, E, R>,\n options: UseStreamOptions<R> = {},\n): UseStreamReturn<A, E> {\n const runtime = options.runtime ?? (getRuntime() as RuntimeLike<R>);\n return streamState(runtime, () => stream);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAyDA,SAAgB,UACd,QACA,UAA+B,CAAC,GACT;CAEvB,OAAO,YADS,QAAQ,WAAYA,kBAAW,SACb,MAAM;AAC1C"}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
|
+
import { RuntimeLike } from "./internal/run.js";
|
|
1
2
|
import { PubSub, SubscriptionRef } from "effect";
|
|
2
3
|
|
|
3
4
|
//#region src/subscription.svelte.d.ts
|
|
5
|
+
interface UseSubscriptionRefOptions<R> {
|
|
6
|
+
/** Run against this runtime instead of the ambient context. */
|
|
7
|
+
readonly runtime?: RuntimeLike<R>;
|
|
8
|
+
}
|
|
9
|
+
interface UsePubSubOptions<R> {
|
|
10
|
+
/** Run against this runtime instead of the ambient context. */
|
|
11
|
+
readonly runtime?: RuntimeLike<R>;
|
|
12
|
+
}
|
|
4
13
|
interface UseSubscriptionRefReturn<A> {
|
|
5
14
|
/**
|
|
6
15
|
* The current value of the SubscriptionRef
|
|
@@ -28,7 +37,7 @@ interface UseSubscriptionRefReturn<A> {
|
|
|
28
37
|
* <p>Count: {count.current}</p>
|
|
29
38
|
* ```
|
|
30
39
|
*/
|
|
31
|
-
declare function useSubscriptionRef<A>(ref: SubscriptionRef.SubscriptionRef<A>): UseSubscriptionRefReturn<A>;
|
|
40
|
+
declare function useSubscriptionRef<A, R = never>(ref: SubscriptionRef.SubscriptionRef<A>, options?: UseSubscriptionRefOptions<R>): UseSubscriptionRefReturn<A>;
|
|
32
41
|
interface UsePubSubReturn<A> {
|
|
33
42
|
/**
|
|
34
43
|
* All values received from the PubSub
|
|
@@ -63,7 +72,7 @@ interface UsePubSubReturn<A> {
|
|
|
63
72
|
* </ul>
|
|
64
73
|
* ```
|
|
65
74
|
*/
|
|
66
|
-
declare function usePubSub<A>(pubsub: PubSub.PubSub<A>): UsePubSubReturn<A>;
|
|
75
|
+
declare function usePubSub<A, R = never>(pubsub: PubSub.PubSub<A>, options?: UsePubSubOptions<R>): UsePubSubReturn<A>;
|
|
67
76
|
//#endregion
|
|
68
|
-
export { UsePubSubReturn, UseSubscriptionRefReturn, usePubSub, useSubscriptionRef };
|
|
77
|
+
export { UsePubSubOptions, UsePubSubReturn, UseSubscriptionRefOptions, UseSubscriptionRefReturn, usePubSub, useSubscriptionRef };
|
|
69
78
|
//# sourceMappingURL=subscription.svelte.d.ts.map
|
|
@@ -24,8 +24,8 @@ import { Stream, SubscriptionRef } from "effect";
|
|
|
24
24
|
* <p>Count: {count.current}</p>
|
|
25
25
|
* ```
|
|
26
26
|
*/
|
|
27
|
-
function useSubscriptionRef(ref) {
|
|
28
|
-
const runtime = getRuntimeContext();
|
|
27
|
+
function useSubscriptionRef(ref, options = {}) {
|
|
28
|
+
const runtime = options.runtime ?? getRuntimeContext();
|
|
29
29
|
return valueState(runtime, runSync(runtime)(SubscriptionRef.get(ref)), () => SubscriptionRef.changes(ref));
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
@@ -52,8 +52,8 @@ function useSubscriptionRef(ref) {
|
|
|
52
52
|
* </ul>
|
|
53
53
|
* ```
|
|
54
54
|
*/
|
|
55
|
-
function usePubSub(pubsub) {
|
|
56
|
-
const state = streamState(getRuntimeContext(), () => Stream.fromPubSub(pubsub));
|
|
55
|
+
function usePubSub(pubsub, options = {}) {
|
|
56
|
+
const state = streamState(options.runtime ?? getRuntimeContext(), () => Stream.fromPubSub(pubsub));
|
|
57
57
|
return {
|
|
58
58
|
get values() {
|
|
59
59
|
return state.values;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subscription.svelte.js","names":["getRuntime"],"sources":["../src/subscription.svelte.ts"],"sourcesContent":["import { PubSub, Stream, SubscriptionRef } from \"effect\";\nimport { getRuntime } from \"./context.svelte.js\";\nimport { runSync, type RuntimeLike } from \"./internal/run.js\";\nimport { streamState, valueState } from \"./internal/subscribe.js\";\n\nexport interface UseSubscriptionRefReturn<A> {\n /**\n * The current value of the SubscriptionRef\n */\n readonly current: A;\n}\n\n/**\n * Subscribe to an Effect SubscriptionRef and get reactive updates.\n * Returns an object exposing the current value via the `current` property.\n *\n * The initial value is read synchronously; the subscription that keeps it up to\n * date starts when `current` is first read inside an effect or template, and is\n * interrupted when the last reader is destroyed.\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { useSubscriptionRef } from '@thomasfosterau/effect-svelte';\n * import { SubscriptionRef, Effect } from 'effect';\n *\n * // Assume counterRef is a SubscriptionRef<number>\n * const count = useSubscriptionRef(counterRef);\n * </script>\n *\n * <p>Count: {count.current}</p>\n * ```\n */\nexport function useSubscriptionRef<A>(\n ref: SubscriptionRef.SubscriptionRef<A>,\n): UseSubscriptionRefReturn<A> {\n const runtime = getRuntime() as RuntimeLike<
|
|
1
|
+
{"version":3,"file":"subscription.svelte.js","names":["getRuntime"],"sources":["../src/subscription.svelte.ts"],"sourcesContent":["import { PubSub, Stream, SubscriptionRef } from \"effect\";\nimport { getRuntime } from \"./context.svelte.js\";\nimport { runSync, type RuntimeLike } from \"./internal/run.js\";\nimport { streamState, valueState } from \"./internal/subscribe.js\";\n\nexport interface UseSubscriptionRefOptions<R> {\n /** Run against this runtime instead of the ambient context. */\n readonly runtime?: RuntimeLike<R>;\n}\n\nexport interface UsePubSubOptions<R> {\n /** Run against this runtime instead of the ambient context. */\n readonly runtime?: RuntimeLike<R>;\n}\n\nexport interface UseSubscriptionRefReturn<A> {\n /**\n * The current value of the SubscriptionRef\n */\n readonly current: A;\n}\n\n/**\n * Subscribe to an Effect SubscriptionRef and get reactive updates.\n * Returns an object exposing the current value via the `current` property.\n *\n * The initial value is read synchronously; the subscription that keeps it up to\n * date starts when `current` is first read inside an effect or template, and is\n * interrupted when the last reader is destroyed.\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { useSubscriptionRef } from '@thomasfosterau/effect-svelte';\n * import { SubscriptionRef, Effect } from 'effect';\n *\n * // Assume counterRef is a SubscriptionRef<number>\n * const count = useSubscriptionRef(counterRef);\n * </script>\n *\n * <p>Count: {count.current}</p>\n * ```\n */\nexport function useSubscriptionRef<A, R = never>(\n ref: SubscriptionRef.SubscriptionRef<A>,\n options: UseSubscriptionRefOptions<R> = {},\n): UseSubscriptionRefReturn<A> {\n const runtime = options.runtime ?? (getRuntime() as RuntimeLike<R>);\n\n // Get the initial value synchronously so it is available before (and during\n // SSR, instead of) the subscription. `SubscriptionRef.changes` re-emits the\n // current value on subscribe, so no update is missed.\n const initial = runSync(runtime)(SubscriptionRef.get(ref));\n return valueState(runtime, initial, () => SubscriptionRef.changes(ref));\n}\n\nexport interface UsePubSubReturn<A> {\n /**\n * All values received from the PubSub\n */\n readonly values: ReadonlyArray<A>;\n\n /**\n * The most recent value (undefined if none)\n */\n readonly latest: A | undefined;\n}\n\n/**\n * Subscribe to an Effect PubSub and collect messages.\n *\n * The subscription starts when `values`/`latest` is first read inside an effect\n * or template, and is interrupted when the last reader is destroyed.\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { usePubSub } from '@thomasfosterau/effect-svelte';\n * import { PubSub } from 'effect';\n *\n * // Assume messagePubSub is a PubSub<string>\n * const messages = usePubSub(messagePubSub);\n * </script>\n *\n * <p>Latest: {messages.latest}</p>\n * <ul>\n * {#each messages.values as msg}\n * <li>{msg}</li>\n * {/each}\n * </ul>\n * ```\n */\nexport function usePubSub<A, R = never>(\n pubsub: PubSub.PubSub<A>,\n options: UsePubSubOptions<R> = {},\n): UsePubSubReturn<A> {\n const runtime = options.runtime ?? (getRuntime() as RuntimeLike<R>);\n const state = streamState(runtime, () => Stream.fromPubSub(pubsub));\n return {\n get values() {\n return state.values;\n },\n get latest() {\n return state.latest;\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA2CA,SAAgB,mBACd,KACA,UAAwC,CAAC,GACZ;CAC7B,MAAM,UAAU,QAAQ,WAAYA,kBAAW;CAM/C,OAAO,WAAW,SADF,QAAQ,OAAO,EAAE,gBAAgB,IAAI,GAAG,CACvB,SAAS,gBAAgB,QAAQ,GAAG,CAAC;AACxE;;;;;;;;;;;;;;;;;;;;;;;;;AAsCA,SAAgB,UACd,QACA,UAA+B,CAAC,GACZ;CAEpB,MAAM,QAAQ,YADE,QAAQ,WAAYA,kBAAW,SACN,OAAO,WAAW,MAAM,CAAC;CAClE,OAAO;EACL,IAAI,SAAS;GACX,OAAO,MAAM;EACf;EACA,IAAI,SAAS;GACX,OAAO,MAAM;EACf;CACF;AACF"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { RuntimeLike } from "./internal/run.js";
|
|
2
|
+
import { SubscriptionRef } from "effect";
|
|
3
|
+
|
|
4
|
+
//#region src/writable-ref.svelte.d.ts
|
|
5
|
+
interface UseWritableRefOptions<R> {
|
|
6
|
+
/** Run against this runtime instead of the ambient context. */
|
|
7
|
+
readonly runtime?: RuntimeLike<R>;
|
|
8
|
+
}
|
|
9
|
+
interface UseWritableRefReturn<A> {
|
|
10
|
+
/**
|
|
11
|
+
* The current value of the `SubscriptionRef`. Reading tracks it reactively;
|
|
12
|
+
* assigning writes back to the ref, so this property is usable directly with
|
|
13
|
+
* Svelte's `bind:` directive (e.g. `bind:value={name.current}`).
|
|
14
|
+
*/
|
|
15
|
+
current: A;
|
|
16
|
+
/** Replace the ref's value. */
|
|
17
|
+
readonly set: (value: A) => void;
|
|
18
|
+
/** Apply a function to the ref's current value. */
|
|
19
|
+
readonly update: (f: (current: A) => A) => void;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Two-way binding between an Effect `SubscriptionRef` and Svelte runes.
|
|
23
|
+
*
|
|
24
|
+
* Unlike {@link useSubscriptionRef} (read-only `{ current }`), this hook exposes
|
|
25
|
+
* a writable `current` — reading tracks the ref reactively and assigning writes
|
|
26
|
+
* back — so Effect-managed state can drive `bind:value` for shared form / app
|
|
27
|
+
* state. `set` and `update` are also provided for imperative writes.
|
|
28
|
+
*
|
|
29
|
+
* Local writes update `current` optimistically (so `bind:` does not glitch) and
|
|
30
|
+
* are reconciled by the ref's `changes` stream, which also delivers updates
|
|
31
|
+
* made elsewhere in the application.
|
|
32
|
+
*
|
|
33
|
+
* A `SubscriptionRef` is required (not a plain `Ref`): only a `SubscriptionRef`
|
|
34
|
+
* exposes the `changes` stream needed to observe external updates reactively.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```svelte
|
|
38
|
+
* <script lang="ts">
|
|
39
|
+
* import { useWritableRef } from '@thomasfosterau/effect-svelte';
|
|
40
|
+
* import { SubscriptionRef } from 'effect';
|
|
41
|
+
*
|
|
42
|
+
* // Assume nameRef is a SubscriptionRef<string> from shared app state
|
|
43
|
+
* const name = useWritableRef(nameRef);
|
|
44
|
+
* </script>
|
|
45
|
+
*
|
|
46
|
+
* <input bind:value={name.current} />
|
|
47
|
+
* <button onclick={() => name.set("")}>Clear</button>
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
declare function useWritableRef<A, R = never>(ref: SubscriptionRef.SubscriptionRef<A>, options?: UseWritableRefOptions<R>): UseWritableRefReturn<A>;
|
|
51
|
+
//#endregion
|
|
52
|
+
export { UseWritableRefOptions, UseWritableRefReturn, useWritableRef };
|
|
53
|
+
//# sourceMappingURL=writable-ref.svelte.d.ts.map
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { getRuntimeContext } from "./context.svelte.js";
|
|
2
|
+
import { interruptFiber, runFork, runSync } from "./internal/run.js";
|
|
3
|
+
import { refWriter } from "./internal/writable.js";
|
|
4
|
+
import { Effect, Stream, SubscriptionRef } from "effect";
|
|
5
|
+
//#region src/writable-ref.svelte.ts
|
|
6
|
+
/**
|
|
7
|
+
* Two-way binding between an Effect `SubscriptionRef` and Svelte runes.
|
|
8
|
+
*
|
|
9
|
+
* Unlike {@link useSubscriptionRef} (read-only `{ current }`), this hook exposes
|
|
10
|
+
* a writable `current` — reading tracks the ref reactively and assigning writes
|
|
11
|
+
* back — so Effect-managed state can drive `bind:value` for shared form / app
|
|
12
|
+
* state. `set` and `update` are also provided for imperative writes.
|
|
13
|
+
*
|
|
14
|
+
* Local writes update `current` optimistically (so `bind:` does not glitch) and
|
|
15
|
+
* are reconciled by the ref's `changes` stream, which also delivers updates
|
|
16
|
+
* made elsewhere in the application.
|
|
17
|
+
*
|
|
18
|
+
* A `SubscriptionRef` is required (not a plain `Ref`): only a `SubscriptionRef`
|
|
19
|
+
* exposes the `changes` stream needed to observe external updates reactively.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```svelte
|
|
23
|
+
* <script lang="ts">
|
|
24
|
+
* import { useWritableRef } from '@thomasfosterau/effect-svelte';
|
|
25
|
+
* import { SubscriptionRef } from 'effect';
|
|
26
|
+
*
|
|
27
|
+
* // Assume nameRef is a SubscriptionRef<string> from shared app state
|
|
28
|
+
* const name = useWritableRef(nameRef);
|
|
29
|
+
* <\/script>
|
|
30
|
+
*
|
|
31
|
+
* <input bind:value={name.current} />
|
|
32
|
+
* <button onclick={() => name.set("")}>Clear</button>
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
function useWritableRef(ref, options = {}) {
|
|
36
|
+
const runtime = options.runtime ?? getRuntimeContext();
|
|
37
|
+
let value = $state(runSync(runtime)(SubscriptionRef.get(ref)));
|
|
38
|
+
const writer = refWriter(runtime, ref);
|
|
39
|
+
const set = (next) => {
|
|
40
|
+
value = next;
|
|
41
|
+
writer.set(next);
|
|
42
|
+
};
|
|
43
|
+
const update = (f) => {
|
|
44
|
+
set(f(value));
|
|
45
|
+
};
|
|
46
|
+
$effect(() => {
|
|
47
|
+
const fiber = runFork(runtime)(Stream.runForEach(SubscriptionRef.changes(ref), (next) => Effect.sync(() => {
|
|
48
|
+
value = next;
|
|
49
|
+
})));
|
|
50
|
+
return () => interruptFiber(fiber);
|
|
51
|
+
});
|
|
52
|
+
return {
|
|
53
|
+
get current() {
|
|
54
|
+
return value;
|
|
55
|
+
},
|
|
56
|
+
set current(next) {
|
|
57
|
+
set(next);
|
|
58
|
+
},
|
|
59
|
+
set,
|
|
60
|
+
update
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
export { useWritableRef };
|
|
65
|
+
|
|
66
|
+
//# sourceMappingURL=writable-ref.svelte.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writable-ref.svelte.js","names":["getRuntime"],"sources":["../src/writable-ref.svelte.ts"],"sourcesContent":["import { Effect, Stream, SubscriptionRef } from \"effect\";\nimport { getRuntime } from \"./context.svelte.js\";\nimport { interruptFiber, runFork, runSync, type RuntimeLike } from \"./internal/run.js\";\nimport { refWriter } from \"./internal/writable.js\";\n\nexport interface UseWritableRefOptions<R> {\n /** Run against this runtime instead of the ambient context. */\n readonly runtime?: RuntimeLike<R>;\n}\n\nexport interface UseWritableRefReturn<A> {\n /**\n * The current value of the `SubscriptionRef`. Reading tracks it reactively;\n * assigning writes back to the ref, so this property is usable directly with\n * Svelte's `bind:` directive (e.g. `bind:value={name.current}`).\n */\n current: A;\n\n /** Replace the ref's value. */\n readonly set: (value: A) => void;\n\n /** Apply a function to the ref's current value. */\n readonly update: (f: (current: A) => A) => void;\n}\n\n/**\n * Two-way binding between an Effect `SubscriptionRef` and Svelte runes.\n *\n * Unlike {@link useSubscriptionRef} (read-only `{ current }`), this hook exposes\n * a writable `current` — reading tracks the ref reactively and assigning writes\n * back — so Effect-managed state can drive `bind:value` for shared form / app\n * state. `set` and `update` are also provided for imperative writes.\n *\n * Local writes update `current` optimistically (so `bind:` does not glitch) and\n * are reconciled by the ref's `changes` stream, which also delivers updates\n * made elsewhere in the application.\n *\n * A `SubscriptionRef` is required (not a plain `Ref`): only a `SubscriptionRef`\n * exposes the `changes` stream needed to observe external updates reactively.\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { useWritableRef } from '@thomasfosterau/effect-svelte';\n * import { SubscriptionRef } from 'effect';\n *\n * // Assume nameRef is a SubscriptionRef<string> from shared app state\n * const name = useWritableRef(nameRef);\n * </script>\n *\n * <input bind:value={name.current} />\n * <button onclick={() => name.set(\"\")}>Clear</button>\n * ```\n */\nexport function useWritableRef<A, R = never>(\n ref: SubscriptionRef.SubscriptionRef<A>,\n options: UseWritableRefOptions<R> = {},\n): UseWritableRefReturn<A> {\n const runtime = options.runtime ?? (getRuntime() as RuntimeLike<R>);\n\n // Read the initial value synchronously so it is available before (and during\n // SSR, instead of) the subscription.\n let value = $state(runSync(runtime)(SubscriptionRef.get(ref)));\n\n const writer = refWriter(runtime, ref);\n\n const set = (next: A): void => {\n // Optimistic local update so `bind:value` reflects the change immediately,\n // then persist to the ref (whose `changes` stream reconciles the value).\n value = next;\n writer.set(next);\n };\n\n const update = (f: (current: A) => A): void => {\n set(f(value));\n };\n\n // Keep `value` in sync with updates made anywhere else in the app. The\n // `changes` stream re-emits the current value on subscribe, so no update is\n // missed between the synchronous initial read and the subscription starting.\n $effect(() => {\n const fiber = runFork(runtime)(\n Stream.runForEach(SubscriptionRef.changes(ref), (next) =>\n Effect.sync(() => {\n value = next;\n }),\n ),\n );\n return () => interruptFiber(fiber);\n });\n\n return {\n get current() {\n return value;\n },\n set current(next: A) {\n set(next);\n },\n set,\n update,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsDA,SAAgB,eACd,KACA,UAAoC,CAAC,GACZ;CACzB,MAAM,UAAU,QAAQ,WAAYA,kBAAW;CAI/C,IAAI,QAAQ,OAAO,QAAQ,OAAO,EAAE,gBAAgB,IAAI,GAAG,CAAC,CAAC;CAE7D,MAAM,SAAS,UAAU,SAAS,GAAG;CAErC,MAAM,OAAO,SAAkB;EAG7B,QAAQ;EACR,OAAO,IAAI,IAAI;CACjB;CAEA,MAAM,UAAU,MAA+B;EAC7C,IAAI,EAAE,KAAK,CAAC;CACd;CAKA,cAAc;EACZ,MAAM,QAAQ,QAAQ,OAAO,EAC3B,OAAO,WAAW,gBAAgB,QAAQ,GAAG,IAAI,SAC/C,OAAO,WAAW;GAChB,QAAQ;EACV,CAAC,CACH,CACF;EACA,aAAa,eAAe,KAAK;CACnC,CAAC;CAED,OAAO;EACL,IAAI,UAAU;GACZ,OAAO;EACT;EACA,IAAI,QAAQ,MAAS;GACnB,IAAI,IAAI;EACV;EACA;EACA;CACF;AACF"}
|