@thomasfosterau/effect-svelte 0.0.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.
Files changed (46) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +58 -0
  3. package/dist/Store.d.ts +154 -0
  4. package/dist/Store.js +183 -0
  5. package/dist/Store.js.map +1 -0
  6. package/dist/_virtual/_rolldown/runtime.js +13 -0
  7. package/dist/context.svelte.d.ts +37 -0
  8. package/dist/context.svelte.js +53 -0
  9. package/dist/context.svelte.js.map +1 -0
  10. package/dist/derived.svelte.d.ts +43 -0
  11. package/dist/derived.svelte.js +65 -0
  12. package/dist/derived.svelte.js.map +1 -0
  13. package/dist/effect.svelte.d.ts +51 -0
  14. package/dist/effect.svelte.js +68 -0
  15. package/dist/effect.svelte.js.map +1 -0
  16. package/dist/emitter.d.ts +45 -0
  17. package/dist/emitter.js +60 -0
  18. package/dist/emitter.js.map +1 -0
  19. package/dist/index.d.ts +14 -0
  20. package/dist/index.js +13 -0
  21. package/dist/internal/result.svelte.js +36 -0
  22. package/dist/internal/result.svelte.js.map +1 -0
  23. package/dist/internal/run.d.ts +15 -0
  24. package/dist/internal/run.js +25 -0
  25. package/dist/internal/run.js.map +1 -0
  26. package/dist/internal/subscribe.js +79 -0
  27. package/dist/internal/subscribe.js.map +1 -0
  28. package/dist/query.svelte.d.ts +45 -0
  29. package/dist/query.svelte.js +41 -0
  30. package/dist/query.svelte.js.map +1 -0
  31. package/dist/reactivity.svelte.d.ts +123 -0
  32. package/dist/reactivity.svelte.js +186 -0
  33. package/dist/reactivity.svelte.js.map +1 -0
  34. package/dist/runtime.d.ts +81 -0
  35. package/dist/runtime.js +85 -0
  36. package/dist/runtime.js.map +1 -0
  37. package/dist/scope.svelte.d.ts +49 -0
  38. package/dist/scope.svelte.js +68 -0
  39. package/dist/scope.svelte.js.map +1 -0
  40. package/dist/stream.svelte.d.ts +48 -0
  41. package/dist/stream.svelte.js +34 -0
  42. package/dist/stream.svelte.js.map +1 -0
  43. package/dist/subscription.svelte.d.ts +69 -0
  44. package/dist/subscription.svelte.js +69 -0
  45. package/dist/subscription.svelte.js.map +1 -0
  46. package/package.json +53 -0
@@ -0,0 +1,123 @@
1
+ import { Effect } from "effect";
2
+ import * as AsyncResult from "effect/unstable/reactivity/AsyncResult";
3
+
4
+ //#region src/reactivity.svelte.d.ts
5
+ interface ReactiveQueryReturn<A, E> {
6
+ /** The current result, re-derived whenever the keys are invalidated. */
7
+ readonly current: AsyncResult.AsyncResult<A, E>;
8
+ }
9
+ /**
10
+ * Creates a reactive query that automatically re-runs when the specified keys are invalidated.
11
+ *
12
+ * Note: Make sure your runtime includes `Reactivity.layer` from `effect/unstable/reactivity`.
13
+ *
14
+ * @param keys - Reactivity keys that this query depends on
15
+ * @param effectFn - The Effect to run when keys are invalidated
16
+ *
17
+ * @example
18
+ * ```svelte
19
+ * <script lang="ts">
20
+ * import { reactiveQuery, AsyncResult } from '@thomasfosterau/effect-svelte';
21
+ * import { Effect } from 'effect';
22
+ *
23
+ * // Query that depends on a user ID key
24
+ * let userId = $state(1);
25
+ *
26
+ * const user = reactiveQuery(
27
+ * () => ['user', userId],
28
+ * () => Effect.gen(function* () {
29
+ * const data = yield* fetchUser(userId);
30
+ * return data;
31
+ * })
32
+ * );
33
+ * </script>
34
+ *
35
+ * {#if AsyncResult.isSuccess(user.current)}
36
+ * <p>User: {user.current.value.name}</p>
37
+ * {/if}
38
+ * ```
39
+ */
40
+ declare function reactiveQuery<A, E, R>(keys: () => ReadonlyArray<unknown>, effectFn: () => Effect.Effect<A, E, R>): ReactiveQueryReturn<A, E>;
41
+ interface ReactiveStreamReturn<A, E> {
42
+ readonly current: AsyncResult.AsyncResult<ReadonlyArray<A>, E>;
43
+ readonly values: ReadonlyArray<A>;
44
+ readonly latest: A | undefined;
45
+ }
46
+ /**
47
+ * Creates a reactive stream that emits values whenever the specified keys are invalidated.
48
+ * The effect re-runs automatically when keys change.
49
+ *
50
+ * @param keys - Reactivity keys that this stream depends on
51
+ * @param effect - The Effect to run when keys are invalidated
52
+ *
53
+ * @example
54
+ * ```svelte
55
+ * <script lang="ts">
56
+ * import { reactiveStream } from '@thomasfosterau/effect-svelte';
57
+ * import { Effect } from 'effect';
58
+ *
59
+ * const messages = reactiveStream(
60
+ * ['messages'],
61
+ * Effect.gen(function* () {
62
+ * const data = yield* fetchMessages();
63
+ * return data;
64
+ * })
65
+ * );
66
+ * </script>
67
+ *
68
+ * <ul>
69
+ * {#each messages.values as msg}
70
+ * <li>{msg}</li>
71
+ * {/each}
72
+ * </ul>
73
+ * ```
74
+ */
75
+ declare function reactiveStream<A, E, R>(keys: ReadonlyArray<unknown> | (() => ReadonlyArray<unknown>), effect: Effect.Effect<A, E, R> | (() => Effect.Effect<A, E, R>)): ReactiveStreamReturn<A, E>;
76
+ interface ReactiveMutationReturn<A, E> {
77
+ readonly current: AsyncResult.AsyncResult<A, E>;
78
+ run: () => void;
79
+ }
80
+ /**
81
+ * Runs a mutation effect and invalidates the specified keys.
82
+ * This will cause any reactive queries depending on these keys to re-run.
83
+ *
84
+ * @param keys - Reactivity keys to invalidate after the mutation
85
+ * @param effect - The mutation effect to run
86
+ *
87
+ * @example
88
+ * ```svelte
89
+ * <script lang="ts">
90
+ * import { reactiveMutation } from '@thomasfosterau/effect-svelte';
91
+ * import { Effect } from 'effect';
92
+ *
93
+ * const updateUser = reactiveMutation(
94
+ * ['user', userId],
95
+ * Effect.gen(function* () {
96
+ * yield* updateUserInDB(userId, data);
97
+ * })
98
+ * );
99
+ * </script>
100
+ *
101
+ * <button onclick={() => updateUser.run()}>Update</button>
102
+ * ```
103
+ */
104
+ declare function reactiveMutation<A, E, R>(keys: ReadonlyArray<unknown> | (() => ReadonlyArray<unknown>), effect: Effect.Effect<A, E, R> | (() => Effect.Effect<A, E, R>)): ReactiveMutationReturn<A, E>;
105
+ /**
106
+ * Returns a function that manually invalidates reactivity keys, causing any
107
+ * reactive queries depending on those keys to re-run.
108
+ *
109
+ * @example
110
+ * ```svelte
111
+ * <script lang="ts">
112
+ * import { useInvalidateKeys } from '@thomasfosterau/effect-svelte';
113
+ *
114
+ * const invalidate = useInvalidateKeys();
115
+ * </script>
116
+ *
117
+ * <button onclick={() => invalidate(['users'])}>Refresh Users</button>
118
+ * ```
119
+ */
120
+ declare function useInvalidateKeys(): (keys: ReadonlyArray<unknown>) => void;
121
+ //#endregion
122
+ export { ReactiveMutationReturn, ReactiveQueryReturn, ReactiveStreamReturn, reactiveMutation, reactiveQuery, reactiveStream, useInvalidateKeys };
123
+ //# sourceMappingURL=reactivity.svelte.d.ts.map
@@ -0,0 +1,186 @@
1
+ import { getRuntimeContext } from "./context.svelte.js";
2
+ import { interruptFiber, runFork, runSync } from "./internal/run.js";
3
+ import { makeResult } from "./internal/result.svelte.js";
4
+ import { streamState } from "./internal/subscribe.js";
5
+ import { Effect, Fiber, Stream } from "effect";
6
+ import { Reactivity } from "effect/unstable/reactivity";
7
+ //#region src/reactivity.svelte.ts
8
+ /**
9
+ * Creates a reactive query that automatically re-runs when the specified keys are invalidated.
10
+ *
11
+ * Note: Make sure your runtime includes `Reactivity.layer` from `effect/unstable/reactivity`.
12
+ *
13
+ * @param keys - Reactivity keys that this query depends on
14
+ * @param effectFn - The Effect to run when keys are invalidated
15
+ *
16
+ * @example
17
+ * ```svelte
18
+ * <script lang="ts">
19
+ * import { reactiveQuery, AsyncResult } from '@thomasfosterau/effect-svelte';
20
+ * import { Effect } from 'effect';
21
+ *
22
+ * // Query that depends on a user ID key
23
+ * let userId = $state(1);
24
+ *
25
+ * const user = reactiveQuery(
26
+ * () => ['user', userId],
27
+ * () => Effect.gen(function* () {
28
+ * const data = yield* fetchUser(userId);
29
+ * return data;
30
+ * })
31
+ * );
32
+ * <\/script>
33
+ *
34
+ * {#if AsyncResult.isSuccess(user.current)}
35
+ * <p>User: {user.current.value.name}</p>
36
+ * {/if}
37
+ * ```
38
+ */
39
+ function reactiveQuery(keys, effectFn) {
40
+ const runtime = getRuntimeContext();
41
+ const state = makeResult();
42
+ let fiber = null;
43
+ $effect(() => {
44
+ const currentKeys = keys();
45
+ const effect = effectFn();
46
+ state.startWaiting();
47
+ const queryEffect = Effect.scoped(Effect.gen(function* () {
48
+ const queue = yield* Reactivity.query(effect, currentKeys);
49
+ yield* Stream.runForEach(Stream.fromQueue(queue), (value) => Effect.sync(() => {
50
+ state.succeed(value);
51
+ }));
52
+ })).pipe(Effect.catchCause((cause) => Effect.sync(() => {
53
+ state.failCause(cause);
54
+ })));
55
+ fiber = runFork(runtime)(queryEffect);
56
+ return () => {
57
+ if (fiber !== null) {
58
+ interruptFiber(fiber);
59
+ fiber = null;
60
+ }
61
+ };
62
+ });
63
+ return { get current() {
64
+ return state.current;
65
+ } };
66
+ }
67
+ /**
68
+ * Creates a reactive stream that emits values whenever the specified keys are invalidated.
69
+ * The effect re-runs automatically when keys change.
70
+ *
71
+ * @param keys - Reactivity keys that this stream depends on
72
+ * @param effect - The Effect to run when keys are invalidated
73
+ *
74
+ * @example
75
+ * ```svelte
76
+ * <script lang="ts">
77
+ * import { reactiveStream } from '@thomasfosterau/effect-svelte';
78
+ * import { Effect } from 'effect';
79
+ *
80
+ * const messages = reactiveStream(
81
+ * ['messages'],
82
+ * Effect.gen(function* () {
83
+ * const data = yield* fetchMessages();
84
+ * return data;
85
+ * })
86
+ * );
87
+ * <\/script>
88
+ *
89
+ * <ul>
90
+ * {#each messages.values as msg}
91
+ * <li>{msg}</li>
92
+ * {/each}
93
+ * </ul>
94
+ * ```
95
+ */
96
+ function reactiveStream(keys, effect) {
97
+ return streamState(getRuntimeContext(), () => {
98
+ const currentKeys = typeof keys === "function" ? keys() : keys;
99
+ const currentEffect = typeof effect === "function" ? effect() : effect;
100
+ return Reactivity.stream(currentEffect, currentKeys);
101
+ });
102
+ }
103
+ /**
104
+ * Runs a mutation effect and invalidates the specified keys.
105
+ * This will cause any reactive queries depending on these keys to re-run.
106
+ *
107
+ * @param keys - Reactivity keys to invalidate after the mutation
108
+ * @param effect - The mutation effect to run
109
+ *
110
+ * @example
111
+ * ```svelte
112
+ * <script lang="ts">
113
+ * import { reactiveMutation } from '@thomasfosterau/effect-svelte';
114
+ * import { Effect } from 'effect';
115
+ *
116
+ * const updateUser = reactiveMutation(
117
+ * ['user', userId],
118
+ * Effect.gen(function* () {
119
+ * yield* updateUserInDB(userId, data);
120
+ * })
121
+ * );
122
+ * <\/script>
123
+ *
124
+ * <button onclick={() => updateUser.run()}>Update</button>
125
+ * ```
126
+ */
127
+ function reactiveMutation(keys, effect) {
128
+ const runtime = getRuntimeContext();
129
+ const state = makeResult();
130
+ let currentFiber = null;
131
+ const run = () => {
132
+ if (currentFiber !== null) interruptFiber(currentFiber);
133
+ const currentKeys = typeof keys === "function" ? keys() : keys;
134
+ const currentEffect = typeof effect === "function" ? effect() : effect;
135
+ state.startWaiting();
136
+ const mutationEffect = Reactivity.mutation(currentEffect, currentKeys);
137
+ const runningFiber = runFork(runtime)(mutationEffect);
138
+ currentFiber = runningFiber;
139
+ runFork(runtime)(Effect.gen(function* () {
140
+ const exit = yield* Fiber.await(runningFiber);
141
+ if (currentFiber === runningFiber) {
142
+ state.settle(exit);
143
+ currentFiber = null;
144
+ }
145
+ }));
146
+ };
147
+ $effect(() => {
148
+ return () => {
149
+ if (currentFiber !== null) {
150
+ interruptFiber(currentFiber);
151
+ currentFiber = null;
152
+ }
153
+ };
154
+ });
155
+ return {
156
+ get current() {
157
+ return state.current;
158
+ },
159
+ run
160
+ };
161
+ }
162
+ /**
163
+ * Returns a function that manually invalidates reactivity keys, causing any
164
+ * reactive queries depending on those keys to re-run.
165
+ *
166
+ * @example
167
+ * ```svelte
168
+ * <script lang="ts">
169
+ * import { useInvalidateKeys } from '@thomasfosterau/effect-svelte';
170
+ *
171
+ * const invalidate = useInvalidateKeys();
172
+ * <\/script>
173
+ *
174
+ * <button onclick={() => invalidate(['users'])}>Refresh Users</button>
175
+ * ```
176
+ */
177
+ function useInvalidateKeys() {
178
+ const runtime = getRuntimeContext();
179
+ return (keys) => {
180
+ runSync(runtime)(Reactivity.invalidate(keys));
181
+ };
182
+ }
183
+ //#endregion
184
+ export { reactiveMutation, reactiveQuery, reactiveStream, useInvalidateKeys };
185
+
186
+ //# sourceMappingURL=reactivity.svelte.js.map
@@ -0,0 +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>;\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): ReactiveStreamReturn<A, E> {\n const 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): ReactiveMutationReturn<A, E> {\n const 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(): (keys: ReadonlyArray<unknown>) => void {\n const runtime = getRuntime() as RuntimeLike<Reactivity.Reactivity>;\n return (keys) => {\n runSync(runtime)(Reactivity.invalidate(keys));\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CA,SAAgB,cACd,MACA,UAC2B;CAC3B,MAAM,UAAUA,kBAAW;CAE3B,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,QAC4B;CAE5B,OAAO,YADSA,kBACS,SAAS;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,QAC8B;CAC9B,MAAM,UAAUA,kBAAW;CAE3B,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,oBAA4D;CAC1E,MAAM,UAAUA,kBAAW;CAC3B,QAAQ,SAAS;EACf,QAAQ,OAAO,EAAE,WAAW,WAAW,IAAI,CAAC;CAC9C;AACF"}
@@ -0,0 +1,81 @@
1
+ import { Layer, ManagedRuntime } from "effect";
2
+
3
+ //#region src/runtime.d.ts
4
+ /**
5
+ * Custom runtime for Svelte helpers.
6
+ *
7
+ * This runtime is designed specifically for Svelte components and provides:
8
+ * - Type-safe environment tracking
9
+ * - Optimized for client-side execution
10
+ * - Support for reactive primitives
11
+ *
12
+ * Users can extend this runtime with additional services as needed.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * import { SvelteRuntime } from '@thomasfosterau/effect-svelte';
17
+ * import { provideRuntime } from '@thomasfosterau/effect-svelte';
18
+ * import { Layer } from 'effect';
19
+ * import { MyService } from './services';
20
+ *
21
+ * // Extend the base runtime with custom services
22
+ * const customRuntime = SvelteRuntime.extend(Layer.succeed(MyService, myServiceImpl));
23
+ *
24
+ * // Provide to Svelte context
25
+ * provideRuntime(customRuntime);
26
+ * ```
27
+ */
28
+ declare class SvelteRuntime {
29
+ /**
30
+ * The base Svelte runtime with minimal services.
31
+ * This is suitable for most client-side Svelte applications.
32
+ */
33
+ private static readonly baseLayer;
34
+ /**
35
+ * The default managed runtime instance.
36
+ * This provides the core runtime without additional services.
37
+ */
38
+ static readonly defaultRuntime: ManagedRuntime.ManagedRuntime<never, never>;
39
+ /**
40
+ * Creates a custom runtime by extending the base Svelte runtime with additional layers.
41
+ *
42
+ * @param layer - The layer containing additional services to provide
43
+ * @returns A new managed runtime with the extended services
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * import { SvelteRuntime } from '@thomasfosterau/effect-svelte';
48
+ * import { Layer, Context } from 'effect';
49
+ *
50
+ * // Define a custom service
51
+ * class Analytics extends Context.Service<Analytics, {
52
+ * track: (event: string) => Effect.Effect<void>
53
+ * }>()("Analytics") {}
54
+ *
55
+ * // Create an implementation
56
+ * const analyticsLayer = Layer.succeed(Analytics, {
57
+ * track: (event) => Effect.sync(() => console.log(event))
58
+ * });
59
+ *
60
+ * // Extend the runtime
61
+ * const runtime = SvelteRuntime.extend(analyticsLayer);
62
+ * ```
63
+ */
64
+ static extend<R>(layer: Layer.Layer<R>): ManagedRuntime.ManagedRuntime<R, never>;
65
+ /**
66
+ * Creates a custom runtime from a layer, replacing the base layer entirely.
67
+ * Use this when you want full control over the runtime environment.
68
+ *
69
+ * @param layer - The complete layer to use for the runtime
70
+ * @returns A new managed runtime with only the provided services
71
+ */
72
+ static make<R>(layer: Layer.Layer<R>): ManagedRuntime.ManagedRuntime<R, never>;
73
+ }
74
+ /**
75
+ * Default runtime instance for convenience.
76
+ * This is the recommended runtime for most Svelte applications.
77
+ */
78
+ declare const defaultSvelteRuntime: ManagedRuntime.ManagedRuntime<never, never>;
79
+ //#endregion
80
+ export { SvelteRuntime, defaultSvelteRuntime };
81
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1,85 @@
1
+ import { Layer, ManagedRuntime } from "effect";
2
+ //#region src/runtime.ts
3
+ /**
4
+ * Custom runtime for Svelte helpers.
5
+ *
6
+ * This runtime is designed specifically for Svelte components and provides:
7
+ * - Type-safe environment tracking
8
+ * - Optimized for client-side execution
9
+ * - Support for reactive primitives
10
+ *
11
+ * Users can extend this runtime with additional services as needed.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { SvelteRuntime } from '@thomasfosterau/effect-svelte';
16
+ * import { provideRuntime } from '@thomasfosterau/effect-svelte';
17
+ * import { Layer } from 'effect';
18
+ * import { MyService } from './services';
19
+ *
20
+ * // Extend the base runtime with custom services
21
+ * const customRuntime = SvelteRuntime.extend(Layer.succeed(MyService, myServiceImpl));
22
+ *
23
+ * // Provide to Svelte context
24
+ * provideRuntime(customRuntime);
25
+ * ```
26
+ */
27
+ var SvelteRuntime = class {
28
+ /**
29
+ * The base Svelte runtime with minimal services.
30
+ * This is suitable for most client-side Svelte applications.
31
+ */
32
+ static baseLayer = Layer.empty;
33
+ /**
34
+ * The default managed runtime instance.
35
+ * This provides the core runtime without additional services.
36
+ */
37
+ static defaultRuntime = ManagedRuntime.make(this.baseLayer);
38
+ /**
39
+ * Creates a custom runtime by extending the base Svelte runtime with additional layers.
40
+ *
41
+ * @param layer - The layer containing additional services to provide
42
+ * @returns A new managed runtime with the extended services
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * import { SvelteRuntime } from '@thomasfosterau/effect-svelte';
47
+ * import { Layer, Context } from 'effect';
48
+ *
49
+ * // Define a custom service
50
+ * class Analytics extends Context.Service<Analytics, {
51
+ * track: (event: string) => Effect.Effect<void>
52
+ * }>()("Analytics") {}
53
+ *
54
+ * // Create an implementation
55
+ * const analyticsLayer = Layer.succeed(Analytics, {
56
+ * track: (event) => Effect.sync(() => console.log(event))
57
+ * });
58
+ *
59
+ * // Extend the runtime
60
+ * const runtime = SvelteRuntime.extend(analyticsLayer);
61
+ * ```
62
+ */
63
+ static extend(layer) {
64
+ return ManagedRuntime.make(Layer.merge(this.baseLayer, layer));
65
+ }
66
+ /**
67
+ * Creates a custom runtime from a layer, replacing the base layer entirely.
68
+ * Use this when you want full control over the runtime environment.
69
+ *
70
+ * @param layer - The complete layer to use for the runtime
71
+ * @returns A new managed runtime with only the provided services
72
+ */
73
+ static make(layer) {
74
+ return ManagedRuntime.make(layer);
75
+ }
76
+ };
77
+ /**
78
+ * Default runtime instance for convenience.
79
+ * This is the recommended runtime for most Svelte applications.
80
+ */
81
+ const defaultSvelteRuntime = SvelteRuntime.defaultRuntime;
82
+ //#endregion
83
+ export { SvelteRuntime, defaultSvelteRuntime };
84
+
85
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","names":[],"sources":["../src/runtime.ts"],"sourcesContent":["import { Layer, ManagedRuntime } from \"effect\";\n\n/**\n * Custom runtime for Svelte helpers.\n *\n * This runtime is designed specifically for Svelte components and provides:\n * - Type-safe environment tracking\n * - Optimized for client-side execution\n * - Support for reactive primitives\n *\n * Users can extend this runtime with additional services as needed.\n *\n * @example\n * ```ts\n * import { SvelteRuntime } from '@thomasfosterau/effect-svelte';\n * import { provideRuntime } from '@thomasfosterau/effect-svelte';\n * import { Layer } from 'effect';\n * import { MyService } from './services';\n *\n * // Extend the base runtime with custom services\n * const customRuntime = SvelteRuntime.extend(Layer.succeed(MyService, myServiceImpl));\n *\n * // Provide to Svelte context\n * provideRuntime(customRuntime);\n * ```\n */\nexport class SvelteRuntime {\n /**\n * The base Svelte runtime with minimal services.\n * This is suitable for most client-side Svelte applications.\n */\n private static readonly baseLayer = Layer.empty;\n\n /**\n * The default managed runtime instance.\n * This provides the core runtime without additional services.\n */\n static readonly defaultRuntime = ManagedRuntime.make(this.baseLayer);\n\n /**\n * Creates a custom runtime by extending the base Svelte runtime with additional layers.\n *\n * @param layer - The layer containing additional services to provide\n * @returns A new managed runtime with the extended services\n *\n * @example\n * ```ts\n * import { SvelteRuntime } from '@thomasfosterau/effect-svelte';\n * import { Layer, Context } from 'effect';\n *\n * // Define a custom service\n * class Analytics extends Context.Service<Analytics, {\n * track: (event: string) => Effect.Effect<void>\n * }>()(\"Analytics\") {}\n *\n * // Create an implementation\n * const analyticsLayer = Layer.succeed(Analytics, {\n * track: (event) => Effect.sync(() => console.log(event))\n * });\n *\n * // Extend the runtime\n * const runtime = SvelteRuntime.extend(analyticsLayer);\n * ```\n */\n static extend<R>(layer: Layer.Layer<R>): ManagedRuntime.ManagedRuntime<R, never> {\n return ManagedRuntime.make(Layer.merge(this.baseLayer, layer));\n }\n\n /**\n * Creates a custom runtime from a layer, replacing the base layer entirely.\n * Use this when you want full control over the runtime environment.\n *\n * @param layer - The complete layer to use for the runtime\n * @returns A new managed runtime with only the provided services\n */\n static make<R>(layer: Layer.Layer<R>): ManagedRuntime.ManagedRuntime<R, never> {\n return ManagedRuntime.make(layer);\n }\n}\n\n/**\n * Default runtime instance for convenience.\n * This is the recommended runtime for most Svelte applications.\n */\nexport const defaultSvelteRuntime = SvelteRuntime.defaultRuntime;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,IAAa,gBAAb,MAA2B;;;;;CAKzB,OAAwB,YAAY,MAAM;;;;;CAM1C,OAAgB,iBAAiB,eAAe,KAAK,KAAK,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BnE,OAAO,OAAU,OAAgE;EAC/E,OAAO,eAAe,KAAK,MAAM,MAAM,KAAK,WAAW,KAAK,CAAC;CAC/D;;;;;;;;CASA,OAAO,KAAQ,OAAgE;EAC7E,OAAO,eAAe,KAAK,KAAK;CAClC;AACF;;;;;AAMA,MAAa,uBAAuB,cAAc"}
@@ -0,0 +1,49 @@
1
+ import { Scope } from "effect";
2
+
3
+ //#region src/scope.svelte.d.ts
4
+ /**
5
+ * Creates an Effect Scope that is tied to the component lifecycle.
6
+ * The scope is created when the component mounts and closed when it unmounts.
7
+ *
8
+ * Note: Due to Svelte's initialization order ($effect runs after mount),
9
+ * the scope will be null initially. Use the callback-based approach for
10
+ * guaranteed availability.
11
+ *
12
+ * @example
13
+ * ```svelte
14
+ * <script lang="ts">
15
+ * import { useScope } from 'effect-svelte';
16
+ *
17
+ * const scope = useScope();
18
+ *
19
+ * $effect(() => {
20
+ * if (scope.current) {
21
+ * // Use scope.current here
22
+ * }
23
+ * });
24
+ * </script>
25
+ * ```
26
+ */
27
+ declare function useScope(): {
28
+ get current(): Scope.Closeable | null;
29
+ };
30
+ /**
31
+ * Callback-based variant of useScope that guarantees scope availability.
32
+ * The callback is executed once the scope is created and receives the scope as parameter.
33
+ *
34
+ * @example
35
+ * ```svelte
36
+ * <script lang="ts">
37
+ * import { useScopeCallback } from 'effect-svelte';
38
+ *
39
+ * useScopeCallback((scope) => {
40
+ * // Scope is guaranteed to be available here
41
+ * // Set up any scope-dependent resources
42
+ * });
43
+ * </script>
44
+ * ```
45
+ */
46
+ declare function useScopeCallback(callback: (scope: Scope.Closeable) => void | (() => void)): void;
47
+ //#endregion
48
+ export { useScope, useScopeCallback };
49
+ //# sourceMappingURL=scope.svelte.d.ts.map
@@ -0,0 +1,68 @@
1
+ import { untrack } from "svelte";
2
+ import { Effect, Exit, Scope } from "effect";
3
+ //#region src/scope.svelte.ts
4
+ /**
5
+ * Creates an Effect Scope that is tied to the component lifecycle.
6
+ * The scope is created when the component mounts and closed when it unmounts.
7
+ *
8
+ * Note: Due to Svelte's initialization order ($effect runs after mount),
9
+ * the scope will be null initially. Use the callback-based approach for
10
+ * guaranteed availability.
11
+ *
12
+ * @example
13
+ * ```svelte
14
+ * <script lang="ts">
15
+ * import { useScope } from 'effect-svelte';
16
+ *
17
+ * const scope = useScope();
18
+ *
19
+ * $effect(() => {
20
+ * if (scope.current) {
21
+ * // Use scope.current here
22
+ * }
23
+ * });
24
+ * <\/script>
25
+ * ```
26
+ */
27
+ function useScope() {
28
+ let scope = $state(null);
29
+ $effect(() => {
30
+ scope = Effect.runSync(Scope.make());
31
+ return () => {
32
+ if (scope) Effect.runSync(Scope.close(scope, Exit.void));
33
+ };
34
+ });
35
+ return { get current() {
36
+ return scope;
37
+ } };
38
+ }
39
+ /**
40
+ * Callback-based variant of useScope that guarantees scope availability.
41
+ * The callback is executed once the scope is created and receives the scope as parameter.
42
+ *
43
+ * @example
44
+ * ```svelte
45
+ * <script lang="ts">
46
+ * import { useScopeCallback } from 'effect-svelte';
47
+ *
48
+ * useScopeCallback((scope) => {
49
+ * // Scope is guaranteed to be available here
50
+ * // Set up any scope-dependent resources
51
+ * });
52
+ * <\/script>
53
+ * ```
54
+ */
55
+ function useScopeCallback(callback) {
56
+ $effect(() => {
57
+ const scope = Effect.runSync(Scope.make());
58
+ const cleanup = untrack(() => callback(scope));
59
+ return () => {
60
+ if (typeof cleanup === "function") cleanup();
61
+ Effect.runSync(Scope.close(scope, Exit.void));
62
+ };
63
+ });
64
+ }
65
+ //#endregion
66
+ export { useScope, useScopeCallback };
67
+
68
+ //# sourceMappingURL=scope.svelte.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.svelte.js","names":[],"sources":["../src/scope.svelte.ts"],"sourcesContent":["import { Scope, Exit, Effect } from \"effect\";\nimport { untrack } from \"svelte\";\n\n/**\n * Creates an Effect Scope that is tied to the component lifecycle.\n * The scope is created when the component mounts and closed when it unmounts.\n *\n * Note: Due to Svelte's initialization order ($effect runs after mount),\n * the scope will be null initially. Use the callback-based approach for\n * guaranteed availability.\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { useScope } from 'effect-svelte';\n *\n * const scope = useScope();\n *\n * $effect(() => {\n * if (scope.current) {\n * // Use scope.current here\n * }\n * });\n * </script>\n * ```\n */\nexport function useScope(): { get current(): Scope.Closeable | null } {\n let scope = $state<Scope.Closeable | null>(null);\n\n $effect(() => {\n // Create the scope when component mounts\n scope = Effect.runSync(Scope.make());\n\n // Clean up: close the scope when component unmounts\n return () => {\n if (scope) {\n Effect.runSync(Scope.close(scope, Exit.void));\n }\n };\n });\n\n return {\n get current() {\n return scope;\n },\n };\n}\n\n/**\n * Callback-based variant of useScope that guarantees scope availability.\n * The callback is executed once the scope is created and receives the scope as parameter.\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { useScopeCallback } from 'effect-svelte';\n *\n * useScopeCallback((scope) => {\n * // Scope is guaranteed to be available here\n * // Set up any scope-dependent resources\n * });\n * </script>\n * ```\n */\nexport function useScopeCallback(callback: (scope: Scope.Closeable) => void | (() => void)): void {\n $effect(() => {\n // Create the scope when component mounts\n const scope = Effect.runSync(Scope.make());\n\n // Execute the callback with the scope. The callback runs untracked so\n // that reactive state it touches does not become a dependency of this\n // effect — the callback is a once-per-mount setup, not a reactive one.\n const cleanup = untrack(() => callback(scope));\n\n // Clean up\n return () => {\n // Call user's cleanup if provided\n if (typeof cleanup === \"function\") {\n cleanup();\n }\n\n // Close the scope\n Effect.runSync(Scope.close(scope, Exit.void));\n };\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,SAAgB,WAAsD;CACpE,IAAI,QAAQ,OAA+B,IAAI;CAE/C,cAAc;EAEZ,QAAQ,OAAO,QAAQ,MAAM,KAAK,CAAC;EAGnC,aAAa;GACX,IAAI,OACF,OAAO,QAAQ,MAAM,MAAM,OAAO,KAAK,IAAI,CAAC;EAEhD;CACF,CAAC;CAED,OAAO,EACL,IAAI,UAAU;EACZ,OAAO;CACT,EACF;AACF;;;;;;;;;;;;;;;;;AAkBA,SAAgB,iBAAiB,UAAiE;CAChG,cAAc;EAEZ,MAAM,QAAQ,OAAO,QAAQ,MAAM,KAAK,CAAC;EAKzC,MAAM,UAAU,cAAc,SAAS,KAAK,CAAC;EAG7C,aAAa;GAEX,IAAI,OAAO,YAAY,YACrB,QAAQ;GAIV,OAAO,QAAQ,MAAM,MAAM,OAAO,KAAK,IAAI,CAAC;EAC9C;CACF,CAAC;AACH"}
@@ -0,0 +1,48 @@
1
+ import { Stream } from "effect";
2
+ import * as AsyncResult from "effect/unstable/reactivity/AsyncResult";
3
+
4
+ //#region src/stream.svelte.d.ts
5
+ interface UseStreamReturn<A, E> {
6
+ /**
7
+ * The current result state of the stream. `Initial`/`Success` carry a
8
+ * `waiting` flag while the stream is still live (stale-while-revalidate), and
9
+ * settle to a non-waiting `Success`/`Failure` once it completes.
10
+ */
11
+ readonly current: AsyncResult.AsyncResult<ReadonlyArray<A>, E>;
12
+ /**
13
+ * All values emitted by the stream so far
14
+ */
15
+ readonly values: ReadonlyArray<A>;
16
+ /**
17
+ * The most recent value emitted by the stream (undefined if none)
18
+ */
19
+ readonly latest: A | undefined;
20
+ }
21
+ /**
22
+ * Subscribe to a Stream and collect emissions.
23
+ *
24
+ * The subscription starts the first time `current`/`values`/`latest` is read
25
+ * inside an effect or template, and is interrupted automatically when the last
26
+ * reader is destroyed (via Svelte's `createSubscriber`).
27
+ *
28
+ * @example
29
+ * ```svelte
30
+ * <script lang="ts">
31
+ * import { useStream } from '@thomasfosterau/effect-svelte';
32
+ * import { Stream, Schedule } from 'effect';
33
+ *
34
+ * const counter = useStream(
35
+ * Stream.iterate(0, n => n + 1).pipe(
36
+ * Stream.schedule(Schedule.spaced('1 second'))
37
+ * )
38
+ * );
39
+ * </script>
40
+ *
41
+ * <p>Latest: {counter.latest}</p>
42
+ * <p>All values: {counter.values.join(', ')}</p>
43
+ * ```
44
+ */
45
+ declare function useStream<A, E, R>(stream: Stream.Stream<A, E, R>): UseStreamReturn<A, E>;
46
+ //#endregion
47
+ export { UseStreamReturn, useStream };
48
+ //# sourceMappingURL=stream.svelte.d.ts.map