@thomasfosterau/effect-sveltekit 0.5.0 → 0.6.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.
@@ -1 +1 @@
1
- {"version":3,"file":"Navigation.js","names":["goto","kitGoto","invalidate","kitInvalidate","invalidateAll","kitInvalidateAll","refreshAll","kitRefreshAll","preloadData","kitPreloadData","preloadCode","kitPreloadCode","beforeNavigate","kitBeforeNavigate","afterNavigate","kitAfterNavigate","onNavigate","kitOnNavigate"],"sources":["../src/Navigation.ts"],"sourcesContent":["/**\n * Effect wrappers for SvelteKit's client-side\n * [`$app/navigation`](https://svelte.dev/docs/kit/$app-navigation) API.\n *\n * Each of SvelteKit's promise-returning navigation functions is wrapped as an\n * `Effect`, so navigation composes inside Effect pipelines (sequencing,\n * retries, `Effect.race`, tracing spans, ...). Alongside them sit the\n * client-side lifecycle callbacks (`beforeNavigate`, `afterNavigate`,\n * `onNavigate`) bridged to Effect. These run on the client only — calling them\n * during SSR throws, exactly as the underlying `$app/navigation` functions do.\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { Navigation } from '@thomasfosterau/effect-sveltekit/client';\n * import { Effect } from 'effect';\n * import { getRuntime } from '@thomasfosterau/effect-svelte';\n *\n * const runtime = getRuntime();\n * const save = () =>\n * runtime.runPromise(\n * Effect.gen(function* () {\n * yield* doSave();\n * yield* Navigation.refreshAll();\n * yield* Navigation.goto('/done');\n * }),\n * );\n * </script>\n * ```\n */\n\nimport {\n afterNavigate as kitAfterNavigate,\n beforeNavigate as kitBeforeNavigate,\n goto as kitGoto,\n invalidate as kitInvalidate,\n invalidateAll as kitInvalidateAll,\n onNavigate as kitOnNavigate,\n preloadCode as kitPreloadCode,\n preloadData as kitPreloadData,\n refreshAll as kitRefreshAll,\n} from \"$app/navigation\";\nimport type { AfterNavigate, BeforeNavigate, OnNavigate } from \"$app/navigation\";\nimport { Effect } from \"effect\";\nimport type { Stream } from \"effect\";\nimport { onNavigateWith, registeredStream } from \"./internal/navigation-events.js\";\n\n/**\n * Navigate to `url`. Wraps `$app/navigation`'s `goto`. SvelteKit rejects a URL\n * outside the app (external, or not matching a route); a rejection surfaces as\n * a defect.\n */\nexport const goto = (...args: Parameters<typeof kitGoto>): Effect.Effect<void> =>\n Effect.promise(() => kitGoto(...args));\n\n/** Re-run `load` functions that depend on `resource`. Wraps `invalidate`. */\nexport const invalidate = (...args: Parameters<typeof kitInvalidate>): Effect.Effect<void> =>\n Effect.promise(() => kitInvalidate(...args));\n\n/**\n * Re-run every `load` function for the active page. Wraps `invalidateAll`.\n *\n * @deprecated SvelteKit 3 deprecates `invalidateAll`; use {@link refreshAll},\n * which also refreshes active remote functions and keeps `page.state`.\n */\nexport const invalidateAll = (): Effect.Effect<void> => Effect.promise(() => kitInvalidateAll());\n\n/** Refresh active remote functions (and, by default, `load`s). Wraps `refreshAll`. */\nexport const refreshAll = (...args: Parameters<typeof kitRefreshAll>): Effect.Effect<void> =>\n Effect.promise(() => kitRefreshAll(...args));\n\n/** Preload the data for `href`. Wraps `preloadData`. */\nexport const preloadData = (\n href: string,\n): Effect.Effect<Awaited<ReturnType<typeof kitPreloadData>>> =>\n Effect.promise(() => kitPreloadData(href));\n\n/**\n * Preload the code for the route `id` (e.g. `/blog/[slug]`, without\n * `paths.base`). Wraps `preloadCode`.\n */\nexport const preloadCode = (...args: Parameters<typeof kitPreloadCode>): Effect.Effect<void> =>\n Effect.promise(() => kitPreloadCode(...args));\n\n/**\n * Registers a `beforeNavigate` callback and exposes every navigation about to\n * happen as an Effect `Stream`. Call during component initialization.\n *\n * Unlike the promise-returning navigation functions above, this is a\n * **callback-registration** function: it must be called *synchronously during\n * component initialization* (SvelteKit wires it to the component's lifecycle).\n * It registers its callback eagerly and feeds an internal `Queue`, returning a\n * `Stream` backed by that queue — the same push-based bridge as `SignalEmitter`\n * in `@thomasfosterau/effect-svelte`. Call it at the top level of `<script>`,\n * exactly where you'd call the bare `beforeNavigate`.\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { Navigation } from '@thomasfosterau/effect-sveltekit/client';\n * import { Stream, Effect } from 'effect';\n * import { getRuntime } from '@thomasfosterau/effect-svelte';\n *\n * // Register at init so the callback is wired to the component lifecycle.\n * const navigations = Navigation.beforeNavigate();\n *\n * getRuntime().runFork(\n * Stream.runForEach(navigations, (nav) =>\n * Effect.logInfo(`leaving: ${nav.from?.url.pathname}`),\n * ),\n * );\n * </script>\n * ```\n */\nexport function beforeNavigate(): Stream.Stream<BeforeNavigate> {\n return registeredStream<BeforeNavigate>(kitBeforeNavigate);\n}\n\n/**\n * Registers an `afterNavigate` callback and exposes every completed navigation\n * (including the initial one) as an Effect `Stream`. Call during component\n * initialization.\n *\n * Like {@link beforeNavigate}, this is a **callback-registration** function:\n * call it at the top level of `<script>`, exactly where you'd call the bare\n * `afterNavigate`.\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { Navigation } from '@thomasfosterau/effect-sveltekit/client';\n * import { Stream, Effect } from 'effect';\n * import { getRuntime } from '@thomasfosterau/effect-svelte';\n *\n * // Register at init so the callback is wired to the component lifecycle.\n * const navigations = Navigation.afterNavigate();\n *\n * getRuntime().runFork(\n * Stream.runForEach(navigations, (nav) =>\n * Effect.logInfo(`navigated: ${nav.to?.url.pathname}`),\n * ),\n * );\n * </script>\n * ```\n */\nexport function afterNavigate(): Stream.Stream<AfterNavigate> {\n return registeredStream<AfterNavigate>(kitAfterNavigate);\n}\n\n/**\n * Runs an `Effect` for each navigation, registered via `$app/navigation`'s\n * `onNavigate`. Call during component initialization.\n *\n * SvelteKit's `onNavigate` callback may return a cleanup function (or a promise\n * of one) that runs once the navigation completes and the DOM has updated; to\n * support that, `fn`'s Effect may succeed with a `() => void` cleanup, which is\n * forwarded to SvelteKit. The Effect is run with `runEffect` (default\n * {@link Effect.runPromise}); pass a managed runtime's `runPromise` to supply\n * services to `fn`.\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { Navigation } from '@thomasfosterau/effect-sveltekit/client';\n * import { Effect } from 'effect';\n *\n * Navigation.onNavigate((nav) =>\n * Effect.gen(function* () {\n * yield* Effect.logInfo(`navigating to ${nav.to?.url.pathname}`);\n * // Optionally return a cleanup that runs after the navigation:\n * return () => console.log(\"navigation done\");\n * }),\n * );\n * </script>\n * ```\n */\nexport function onNavigate(\n fn: (navigation: OnNavigate) => Effect.Effect<(() => void) | void>,\n runEffect: <X>(effect: Effect.Effect<X>) => Promise<X> = Effect.runPromise,\n): void {\n onNavigateWith<OnNavigate>(kitOnNavigate, fn, runEffect);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDA,MAAaA,UAAQ,GAAG,SACtB,OAAO,cAAcC,KAAQ,GAAG,IAAI,CAAC;;AAGvC,MAAaC,gBAAc,GAAG,SAC5B,OAAO,cAAcC,WAAc,GAAG,IAAI,CAAC;;;;;;;AAQ7C,MAAaC,wBAA2C,OAAO,cAAcC,cAAiB,CAAC;;AAG/F,MAAaC,gBAAc,GAAG,SAC5B,OAAO,cAAcC,WAAc,GAAG,IAAI,CAAC;;AAG7C,MAAaC,iBACX,SAEA,OAAO,cAAcC,YAAe,IAAI,CAAC;;;;;AAM3C,MAAaC,iBAAe,GAAG,SAC7B,OAAO,cAAcC,YAAe,GAAG,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgC9C,SAAgBC,mBAAgD;CAC9D,OAAO,iBAAiCC,cAAiB;AAC3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,SAAgBC,kBAA8C;CAC5D,OAAO,iBAAgCC,aAAgB;AACzD;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,SAAgBC,aACd,IACA,YAAyD,OAAO,YAC1D;CACN,eAA2BC,YAAe,IAAI,SAAS;AACzD"}
1
+ {"version":3,"file":"Navigation.js","names":["goto","kitGoto","invalidate","kitInvalidate","invalidateAll","kitInvalidateAll","refreshAll","kitRefreshAll","preloadData","kitPreloadData","preloadCode","kitPreloadCode","beforeNavigate","kitBeforeNavigate","afterNavigate","kitAfterNavigate","onNavigate","kitOnNavigate"],"sources":["../src/Navigation.ts"],"sourcesContent":["/**\n * Effect wrappers for SvelteKit's client-side\n * [`$app/navigation`](https://svelte.dev/docs/kit/$app-navigation) API.\n *\n * Each of SvelteKit's promise-returning navigation functions is wrapped as an\n * `Effect`, so navigation composes inside Effect pipelines (sequencing,\n * retries, `Effect.race`, tracing spans, ...). Alongside them sit the\n * client-side lifecycle callbacks (`beforeNavigate`, `afterNavigate`,\n * `onNavigate`) bridged to Effect. These run on the client only.\n *\n * When SvelteKit rejects (for example, `goto` to a URL outside the app) or\n * throws (for example, any of them run during server rendering), the wrapper\n * fails with a {@link NavigationError} that names the operation and carries\n * SvelteKit's original reason as its `cause`.\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { Navigation } from '@thomasfosterau/effect-sveltekit/client';\n * import { Effect } from 'effect';\n * import { getRuntime } from '@thomasfosterau/effect-svelte';\n *\n * const runtime = getRuntime();\n * const save = () =>\n * runtime.runPromise(\n * Effect.gen(function* () {\n * yield* doSave();\n * yield* Navigation.refreshAll();\n * yield* Navigation.goto('/done');\n * }),\n * );\n * </script>\n * ```\n */\n\nimport {\n afterNavigate as kitAfterNavigate,\n beforeNavigate as kitBeforeNavigate,\n goto as kitGoto,\n invalidate as kitInvalidate,\n invalidateAll as kitInvalidateAll,\n onNavigate as kitOnNavigate,\n preloadCode as kitPreloadCode,\n preloadData as kitPreloadData,\n refreshAll as kitRefreshAll,\n} from \"$app/navigation\";\nimport type { AfterNavigate, BeforeNavigate, OnNavigate } from \"$app/navigation\";\nimport { Data, Effect } from \"effect\";\nimport type { Stream } from \"effect\";\nimport { onNavigateWith, registeredStream } from \"./internal/navigation-events.js\";\n\n/**\n * A `$app/navigation` promise wrapper ({@link goto}, {@link invalidate},\n * {@link invalidateAll}, {@link refreshAll}, {@link preloadData},\n * {@link preloadCode}) rejected or threw. `operation` names the wrapper and\n * `cause` is SvelteKit's original reason, unchanged.\n *\n * SvelteKit 3 rejects `goto` with a URL outside the app (external, or matching\n * no route) and `preloadData` with a URL outside the app; `invalidate` throws on\n * a `resource` that cannot be parsed even relative to the current URL;\n * `preloadCode` rejects when a route's code fails to load; a navigation (including one that follows a `load` redirect during\n * `invalidate` / `refreshAll`) rejects when a `beforeNavigate` / `onNavigate`\n * callback throws; and every one of them throws when called during server\n * rendering. Recover with `Effect.catchTag(\"NavigationError\", ...)`.\n */\nexport class NavigationError extends Data.TaggedError(\"NavigationError\")<{\n /** The wrapper whose SvelteKit call failed. */\n readonly operation:\n | \"goto\"\n | \"invalidate\"\n | \"invalidateAll\"\n | \"refreshAll\"\n | \"preloadData\"\n | \"preloadCode\";\n /** The rejection reason, or the value thrown, as SvelteKit produced it. */\n readonly cause: unknown;\n}> {}\n\n/**\n * Runs a `$app/navigation` call as an Effect, so a rejection, or a synchronous\n * throw, fails with a {@link NavigationError} instead of becoming a defect.\n */\nconst fromNavigation = <A>(\n operation: NavigationError[\"operation\"],\n thunk: () => Promise<A>,\n): Effect.Effect<A, NavigationError> =>\n Effect.tryPromise({\n try: () => thunk(),\n catch: (cause) => new NavigationError({ operation, cause }),\n });\n\n/**\n * Navigate to `url`. Wraps `$app/navigation`'s `goto`.\n *\n * Fails with a {@link NavigationError} if SvelteKit rejects: a URL outside the\n * app (external, or not matching a route) rejects, as does a navigation whose\n * `beforeNavigate` / `onNavigate` callback throws, or a call during server\n * rendering. For an external URL, set `window.location` instead.\n */\nexport const goto = (...args: Parameters<typeof kitGoto>): Effect.Effect<void, NavigationError> =>\n fromNavigation(\"goto\", () => kitGoto(...args));\n\n/**\n * Re-run `load` functions that depend on `resource`. Wraps `invalidate`.\n *\n * Fails with a {@link NavigationError} if SvelteKit rejects or throws: a\n * `resource` string that cannot be parsed even relative to the current URL\n * throws, as does a call during server rendering, and the navigation that\n * follows a `load` redirect can reject.\n */\nexport const invalidate = (\n ...args: Parameters<typeof kitInvalidate>\n): Effect.Effect<void, NavigationError> =>\n fromNavigation(\"invalidate\", () => kitInvalidate(...args));\n\n/**\n * Re-run every `load` function for the active page. Wraps `invalidateAll`.\n *\n * Fails with a {@link NavigationError} if SvelteKit rejects or throws: for\n * example, when the navigation that follows a `load` redirect fails, or when\n * called during server rendering.\n *\n * @deprecated SvelteKit 3 deprecates `invalidateAll`; use {@link refreshAll},\n * which also refreshes active remote functions and keeps `page.state`.\n */\nexport const invalidateAll = (): Effect.Effect<void, NavigationError> =>\n fromNavigation(\"invalidateAll\", () => kitInvalidateAll());\n\n/**\n * Refresh active remote functions (and, by default, `load`s). Wraps `refreshAll`.\n *\n * Fails with a {@link NavigationError} if SvelteKit rejects or throws: for\n * example, when the navigation that follows a `load` redirect fails, or when\n * called during server rendering.\n */\nexport const refreshAll = (\n ...args: Parameters<typeof kitRefreshAll>\n): Effect.Effect<void, NavigationError> =>\n fromNavigation(\"refreshAll\", () => kitRefreshAll(...args));\n\n/**\n * Preload the data for `href`. Wraps `preloadData`, succeeding with SvelteKit's\n * result (`loaded`, `redirect`, or `error` when a `load` fails).\n *\n * Fails with a {@link NavigationError} if SvelteKit rejects: an `href` outside\n * the app rejects, as does a call during server rendering.\n */\nexport const preloadData = (\n href: string,\n): Effect.Effect<Awaited<ReturnType<typeof kitPreloadData>>, NavigationError> =>\n fromNavigation(\"preloadData\", () => kitPreloadData(href));\n\n/**\n * Preload the code for the route `id` (e.g. `/blog/[slug]`, without\n * `paths.base`). Wraps `preloadCode`.\n *\n * Fails with a {@link NavigationError} if SvelteKit rejects: a route module\n * that fails to load rejects, as does a call during server rendering (and, in\n * development, an `id` not starting with `/`).\n */\nexport const preloadCode = (\n ...args: Parameters<typeof kitPreloadCode>\n): Effect.Effect<void, NavigationError> =>\n fromNavigation(\"preloadCode\", () => kitPreloadCode(...args));\n\n/**\n * Registers a `beforeNavigate` callback and exposes every navigation about to\n * happen as an Effect `Stream`. Call during component initialization.\n *\n * Unlike the promise-returning navigation functions above, this is a\n * **callback-registration** function: it must be called *synchronously during\n * component initialization* (SvelteKit wires it to the component's lifecycle).\n * It registers its callback eagerly and feeds an internal unbounded `Queue`,\n * returning a `Stream` backed by that queue: a push-based bridge that buffers\n * every event for its single consumer. Call it at the top level of `<script>`,\n * exactly where you'd call the bare `beforeNavigate`.\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { Navigation } from '@thomasfosterau/effect-sveltekit/client';\n * import { Stream, Effect } from 'effect';\n * import { getRuntime } from '@thomasfosterau/effect-svelte';\n *\n * // Register at init so the callback is wired to the component lifecycle.\n * const navigations = Navigation.beforeNavigate();\n *\n * getRuntime().runFork(\n * Stream.runForEach(navigations, (nav) =>\n * Effect.logInfo(`leaving: ${nav.from?.url.pathname}`),\n * ),\n * );\n * </script>\n * ```\n */\nexport function beforeNavigate(): Stream.Stream<BeforeNavigate> {\n return registeredStream<BeforeNavigate>(kitBeforeNavigate);\n}\n\n/**\n * Registers an `afterNavigate` callback and exposes every completed navigation\n * (including the initial one) as an Effect `Stream`. Call during component\n * initialization.\n *\n * Like {@link beforeNavigate}, this is a **callback-registration** function:\n * call it at the top level of `<script>`, exactly where you'd call the bare\n * `afterNavigate`.\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { Navigation } from '@thomasfosterau/effect-sveltekit/client';\n * import { Stream, Effect } from 'effect';\n * import { getRuntime } from '@thomasfosterau/effect-svelte';\n *\n * // Register at init so the callback is wired to the component lifecycle.\n * const navigations = Navigation.afterNavigate();\n *\n * getRuntime().runFork(\n * Stream.runForEach(navigations, (nav) =>\n * Effect.logInfo(`navigated: ${nav.to?.url.pathname}`),\n * ),\n * );\n * </script>\n * ```\n */\nexport function afterNavigate(): Stream.Stream<AfterNavigate> {\n return registeredStream<AfterNavigate>(kitAfterNavigate);\n}\n\n/**\n * Runs an `Effect` for each navigation, registered via `$app/navigation`'s\n * `onNavigate`. Call during component initialization.\n *\n * SvelteKit's `onNavigate` callback may return a cleanup function (or a promise\n * of one) that runs once the navigation completes and the DOM has updated; to\n * support that, `fn`'s Effect may succeed with a `() => void` cleanup, which is\n * forwarded to SvelteKit. The Effect is run with `runEffect` (default\n * {@link Effect.runPromise}); pass a managed runtime's `runPromise` to supply\n * services to `fn`.\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { Navigation } from '@thomasfosterau/effect-sveltekit/client';\n * import { Effect } from 'effect';\n *\n * Navigation.onNavigate((nav) =>\n * Effect.gen(function* () {\n * yield* Effect.logInfo(`navigating to ${nav.to?.url.pathname}`);\n * // Optionally return a cleanup that runs after the navigation:\n * return () => console.log(\"navigation done\");\n * }),\n * );\n * </script>\n * ```\n */\nexport function onNavigate(\n fn: (navigation: OnNavigate) => Effect.Effect<(() => void) | void>,\n runEffect: <X>(effect: Effect.Effect<X>) => Promise<X> = Effect.runPromise,\n): void {\n onNavigateWith<OnNavigate>(kitOnNavigate, fn, runEffect);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiEA,IAAa,kBAAb,cAAqC,KAAK,YAAY,iBAAiB,CAAC,CAWrE,CAAC;;;;;AAMJ,MAAM,kBACJ,WACA,UAEA,OAAO,WAAW;CAChB,WAAW,MAAM;CACjB,QAAQ,UAAU,IAAI,gBAAgB;EAAE;EAAW;CAAM,CAAC;AAC5D,CAAC;;;;;;;;;AAUH,MAAaA,UAAQ,GAAG,SACtB,eAAe,cAAcC,KAAQ,GAAG,IAAI,CAAC;;;;;;;;;AAU/C,MAAaC,gBACX,GAAG,SAEH,eAAe,oBAAoBC,WAAc,GAAG,IAAI,CAAC;;;;;;;;;;;AAY3D,MAAaC,wBACX,eAAe,uBAAuBC,cAAiB,CAAC;;;;;;;;AAS1D,MAAaC,gBACX,GAAG,SAEH,eAAe,oBAAoBC,WAAc,GAAG,IAAI,CAAC;;;;;;;;AAS3D,MAAaC,iBACX,SAEA,eAAe,qBAAqBC,YAAe,IAAI,CAAC;;;;;;;;;AAU1D,MAAaC,iBACX,GAAG,SAEH,eAAe,qBAAqBC,YAAe,GAAG,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgC7D,SAAgBC,mBAAgD;CAC9D,OAAO,iBAAiCC,cAAiB;AAC3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,SAAgBC,kBAA8C;CAC5D,OAAO,iBAAgCC,aAAgB;AACzD;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,SAAgBC,aACd,IACA,YAAyD,OAAO,YAC1D;CACN,eAA2BC,YAAe,IAAI,SAAS;AACzD"}
package/dist/Remote.d.ts CHANGED
@@ -6,32 +6,40 @@ declare namespace Remote_d_exports {
6
6
  /**
7
7
  * Calls a SvelteKit remote `query` as an Effect that succeeds with its output.
8
8
  *
9
- * A rejected call (including a thrown `error()` / `redirect()`) surfaces as a
10
- * defect, not on the error channel, despite the declared `unknown` error type.
9
+ * Fails with the remote call's rejection reason, typed `unknown` and passed
10
+ * through unchanged. On the client, a server-side `error()` arrives as
11
+ * SvelteKit's `HttpError`; a server-side `redirect()` navigates instead of
12
+ * failing.
11
13
  */
12
14
  declare function callQuery<Output>(query: RemoteQueryFunction<void, Output>): Effect.Effect<Output, unknown, never>;
13
15
  /**
14
16
  * Calls a SvelteKit remote `query` with `input` as an Effect that succeeds
15
17
  * with its output.
16
18
  *
17
- * A rejected call (including a thrown `error()` / `redirect()`) surfaces as a
18
- * defect, not on the error channel, despite the declared `unknown` error type.
19
+ * Fails with the remote call's rejection reason, typed `unknown` and passed
20
+ * through unchanged. On the client, a server-side `error()` arrives as
21
+ * SvelteKit's `HttpError`; a server-side `redirect()` navigates instead of
22
+ * failing.
19
23
  */
20
24
  declare function callQuery<Input, Output>(query: RemoteQueryFunction<Input, Output>, input: Input): Effect.Effect<Output, unknown, never>;
21
25
  /**
22
26
  * Calls a SvelteKit remote `command` as an Effect that succeeds with its
23
27
  * output.
24
28
  *
25
- * A rejected call (including a thrown `error()` / `redirect()`) surfaces as a
26
- * defect, not on the error channel, despite the declared `unknown` error type.
29
+ * Fails with the remote call's rejection reason, typed `unknown` and passed
30
+ * through unchanged. On the client, a server-side `error()` arrives as
31
+ * SvelteKit's `HttpError`; commands may not `redirect()`, and SvelteKit
32
+ * rejects one with an `Error`.
27
33
  */
28
34
  declare function callCommand<Output>(command: RemoteCommand<void, Output>): Effect.Effect<Output, unknown, never>;
29
35
  /**
30
36
  * Calls a SvelteKit remote `command` with `input` as an Effect that succeeds
31
37
  * with its output.
32
38
  *
33
- * A rejected call (including a thrown `error()` / `redirect()`) surfaces as a
34
- * defect, not on the error channel, despite the declared `unknown` error type.
39
+ * Fails with the remote call's rejection reason, typed `unknown` and passed
40
+ * through unchanged. On the client, a server-side `error()` arrives as
41
+ * SvelteKit's `HttpError`; commands may not `redirect()`, and SvelteKit
42
+ * rejects one with an `Error`.
35
43
  */
36
44
  declare function callCommand<Input, Output>(command: RemoteCommand<Input, Output>, input: Input): Effect.Effect<Output, unknown, never>;
37
45
  /**
@@ -42,24 +50,30 @@ declare function callCommand<Input, Output>(command: RemoteCommand<Input, Output
42
50
  * changes data those queries depend on must list them here (or call
43
51
  * `query.refresh()` afterwards) for their cached values to update.
44
52
  *
45
- * A rejected call (including a thrown `error()` / `redirect()`) surfaces as a
46
- * defect, not on the error channel, despite the declared `unknown` error type.
53
+ * Fails with the remote call's rejection reason, typed `unknown` and passed
54
+ * through unchanged. On the client, a server-side `error()` arrives as
55
+ * SvelteKit's `HttpError`; commands may not `redirect()`, and SvelteKit
56
+ * rejects one with an `Error`.
47
57
  */
48
58
  declare function callCommandWithUpdates<Input, Output>(command: RemoteCommand<Input, Output>, input: Input, ...queries: Array<RemoteQuery<any> | RemoteQueryOverride>): Effect.Effect<Output, unknown, never>;
49
59
  /**
50
60
  * Calls a SvelteKit remote `prerender` function as an Effect that succeeds
51
61
  * with its output.
52
62
  *
53
- * A rejected call (including a thrown `error()` / `redirect()`) surfaces as a
54
- * defect, not on the error channel, despite the declared `unknown` error type.
63
+ * Fails with the remote call's rejection reason, typed `unknown` and passed
64
+ * through unchanged. On the client, a server-side `error()` arrives as
65
+ * SvelteKit's `HttpError`; a server-side `redirect()` navigates instead of
66
+ * failing.
55
67
  */
56
68
  declare function callPrerender<Output>(prerender: RemotePrerenderFunction<void, Output>): Effect.Effect<Output, unknown, never>;
57
69
  /**
58
70
  * Calls a SvelteKit remote `prerender` function with `input` as an Effect
59
71
  * that succeeds with its output.
60
72
  *
61
- * A rejected call (including a thrown `error()` / `redirect()`) surfaces as a
62
- * defect, not on the error channel, despite the declared `unknown` error type.
73
+ * Fails with the remote call's rejection reason, typed `unknown` and passed
74
+ * through unchanged. On the client, a server-side `error()` arrives as
75
+ * SvelteKit's `HttpError`; a server-side `redirect()` navigates instead of
76
+ * failing.
63
77
  */
64
78
  declare function callPrerender<Input, Output>(prerender: RemotePrerenderFunction<Input, Output>, input: Input): Effect.Effect<Output, unknown, never>;
65
79
  /**
@@ -73,16 +87,20 @@ type RemoteSubmit = () => PromiseLike<unknown> & {
73
87
  /**
74
88
  * Runs an enhanced remote form's `submit()` as an Effect.
75
89
  *
76
- * A rejected call (including a thrown `error()` / `redirect()`) surfaces as a
77
- * defect, not on the error channel, despite the declared `unknown` error type.
90
+ * Fails with the remote call's rejection reason, typed `unknown` and passed
91
+ * through unchanged. On the client, a server-side `error()` arrives as
92
+ * SvelteKit's `HttpError`; a server-side `redirect()` navigates instead of
93
+ * failing.
78
94
  */
79
95
  declare function submitForm(submit: () => PromiseLike<unknown>): Effect.Effect<void, unknown, never>;
80
96
  /**
81
97
  * Runs an enhanced remote form's `submit()` and refreshes the given queries in
82
98
  * the same round trip (SvelteKit's single-flight mutations).
83
99
  *
84
- * A rejected call (including a thrown `error()` / `redirect()`) surfaces as a
85
- * defect, not on the error channel, despite the declared `unknown` error type.
100
+ * Fails with the remote call's rejection reason, typed `unknown` and passed
101
+ * through unchanged. On the client, a server-side `error()` arrives as
102
+ * SvelteKit's `HttpError`; a server-side `redirect()` navigates instead of
103
+ * failing.
86
104
  */
87
105
  declare function submitFormWithUpdates(submit: RemoteSubmit, ...queries: Array<RemoteQuery<any> | RemoteQueryOverride>): Effect.Effect<void, unknown, never>;
88
106
  /**
package/dist/Remote.js CHANGED
@@ -10,8 +10,15 @@ var Remote_exports = /* @__PURE__ */ __exportAll({
10
10
  submitForm: () => submitForm,
11
11
  submitFormWithUpdates: () => submitFormWithUpdates
12
12
  });
13
+ /**
14
+ * Wraps a remote call so a rejection, or a synchronous throw from `thunk`,
15
+ * fails the Effect with the original reason instead of becoming a defect.
16
+ */
13
17
  function fromRemotePromise(thunk) {
14
- return Effect.promise(() => Promise.resolve(thunk()));
18
+ return Effect.tryPromise({
19
+ try: () => Promise.resolve(thunk()),
20
+ catch: (error) => error
21
+ });
15
22
  }
16
23
  function callQuery(query, input) {
17
24
  if (arguments.length === 1) return fromRemotePromise(() => query(void 0));
@@ -29,8 +36,10 @@ function callCommand(command, input) {
29
36
  * changes data those queries depend on must list them here (or call
30
37
  * `query.refresh()` afterwards) for their cached values to update.
31
38
  *
32
- * A rejected call (including a thrown `error()` / `redirect()`) surfaces as a
33
- * defect, not on the error channel, despite the declared `unknown` error type.
39
+ * Fails with the remote call's rejection reason, typed `unknown` and passed
40
+ * through unchanged. On the client, a server-side `error()` arrives as
41
+ * SvelteKit's `HttpError`; commands may not `redirect()`, and SvelteKit
42
+ * rejects one with an `Error`.
34
43
  */
35
44
  function callCommandWithUpdates(command, input, ...queries) {
36
45
  return fromRemotePromise(() => command(input).updates(...queries));
@@ -42,8 +51,10 @@ function callPrerender(prerender, input) {
42
51
  /**
43
52
  * Runs an enhanced remote form's `submit()` as an Effect.
44
53
  *
45
- * A rejected call (including a thrown `error()` / `redirect()`) surfaces as a
46
- * defect, not on the error channel, despite the declared `unknown` error type.
54
+ * Fails with the remote call's rejection reason, typed `unknown` and passed
55
+ * through unchanged. On the client, a server-side `error()` arrives as
56
+ * SvelteKit's `HttpError`; a server-side `redirect()` navigates instead of
57
+ * failing.
47
58
  */
48
59
  function submitForm(submit) {
49
60
  return Effect.asVoid(fromRemotePromise(() => submit()));
@@ -52,8 +63,10 @@ function submitForm(submit) {
52
63
  * Runs an enhanced remote form's `submit()` and refreshes the given queries in
53
64
  * the same round trip (SvelteKit's single-flight mutations).
54
65
  *
55
- * A rejected call (including a thrown `error()` / `redirect()`) surfaces as a
56
- * defect, not on the error channel, despite the declared `unknown` error type.
66
+ * Fails with the remote call's rejection reason, typed `unknown` and passed
67
+ * through unchanged. On the client, a server-side `error()` arrives as
68
+ * SvelteKit's `HttpError`; a server-side `redirect()` navigates instead of
69
+ * failing.
57
70
  */
58
71
  function submitFormWithUpdates(submit, ...queries) {
59
72
  return Effect.asVoid(fromRemotePromise(() => submit().updates(...queries)));
@@ -1 +1 @@
1
- {"version":3,"file":"Remote.js","names":[],"sources":["../src/Remote.ts"],"sourcesContent":["import type {\n RemoteCommand,\n RemoteLiveQuery,\n RemotePrerenderFunction,\n RemoteQuery,\n RemoteQueryFunction,\n RemoteQueryOverride,\n} from \"$app/server\";\nimport { Effect, Stream } from \"effect\";\n\nfunction fromRemotePromise<A>(thunk: () => PromiseLike<A>): Effect.Effect<A, unknown, never> {\n return Effect.promise(() => Promise.resolve(thunk()));\n}\n\n/**\n * Calls a SvelteKit remote `query` as an Effect that succeeds with its output.\n *\n * A rejected call (including a thrown `error()` / `redirect()`) surfaces as a\n * defect, not on the error channel, despite the declared `unknown` error type.\n */\nexport function callQuery<Output>(\n query: RemoteQueryFunction<void, Output>,\n): Effect.Effect<Output, unknown, never>;\n/**\n * Calls a SvelteKit remote `query` with `input` as an Effect that succeeds\n * with its output.\n *\n * A rejected call (including a thrown `error()` / `redirect()`) surfaces as a\n * defect, not on the error channel, despite the declared `unknown` error type.\n */\nexport function callQuery<Input, Output>(\n query: RemoteQueryFunction<Input, Output>,\n input: Input,\n): Effect.Effect<Output, unknown, never>;\nexport function callQuery<Input, Output>(\n query: RemoteQueryFunction<Input, Output>,\n input?: Input,\n): Effect.Effect<Output, unknown, never> {\n if (arguments.length === 1) {\n return fromRemotePromise(() =>\n (query as unknown as RemoteQueryFunction<void, Output>)(undefined),\n );\n }\n\n return fromRemotePromise(() => query(input as Input));\n}\n\n/**\n * Calls a SvelteKit remote `command` as an Effect that succeeds with its\n * output.\n *\n * A rejected call (including a thrown `error()` / `redirect()`) surfaces as a\n * defect, not on the error channel, despite the declared `unknown` error type.\n */\nexport function callCommand<Output>(\n command: RemoteCommand<void, Output>,\n): Effect.Effect<Output, unknown, never>;\n/**\n * Calls a SvelteKit remote `command` with `input` as an Effect that succeeds\n * with its output.\n *\n * A rejected call (including a thrown `error()` / `redirect()`) surfaces as a\n * defect, not on the error channel, despite the declared `unknown` error type.\n */\nexport function callCommand<Input, Output>(\n command: RemoteCommand<Input, Output>,\n input: Input,\n): Effect.Effect<Output, unknown, never>;\nexport function callCommand<Input, Output>(\n command: RemoteCommand<Input, Output>,\n input?: Input,\n): Effect.Effect<Output, unknown, never> {\n if (arguments.length === 1) {\n return fromRemotePromise(() => (command as unknown as RemoteCommand<void, Output>)(undefined));\n }\n\n return fromRemotePromise(() => command(input as Input));\n}\n\n/**\n * Calls a remote command and refreshes the given queries in the same round\n * trip (SvelteKit's single-flight mutations).\n *\n * Newer SvelteKit versions cache remote query instances, so a command that\n * changes data those queries depend on must list them here (or call\n * `query.refresh()` afterwards) for their cached values to update.\n *\n * A rejected call (including a thrown `error()` / `redirect()`) surfaces as a\n * defect, not on the error channel, despite the declared `unknown` error type.\n */\nexport function callCommandWithUpdates<Input, Output>(\n command: RemoteCommand<Input, Output>,\n input: Input,\n ...queries: Array<RemoteQuery<any> | RemoteQueryOverride>\n): Effect.Effect<Output, unknown, never> {\n return fromRemotePromise(() => command(input).updates(...queries));\n}\n\n/**\n * Calls a SvelteKit remote `prerender` function as an Effect that succeeds\n * with its output.\n *\n * A rejected call (including a thrown `error()` / `redirect()`) surfaces as a\n * defect, not on the error channel, despite the declared `unknown` error type.\n */\nexport function callPrerender<Output>(\n prerender: RemotePrerenderFunction<void, Output>,\n): Effect.Effect<Output, unknown, never>;\n/**\n * Calls a SvelteKit remote `prerender` function with `input` as an Effect\n * that succeeds with its output.\n *\n * A rejected call (including a thrown `error()` / `redirect()`) surfaces as a\n * defect, not on the error channel, despite the declared `unknown` error type.\n */\nexport function callPrerender<Input, Output>(\n prerender: RemotePrerenderFunction<Input, Output>,\n input: Input,\n): Effect.Effect<Output, unknown, never>;\nexport function callPrerender<Input, Output>(\n prerender: RemotePrerenderFunction<Input, Output>,\n input?: Input,\n): Effect.Effect<Output, unknown, never> {\n if (arguments.length === 1) {\n return fromRemotePromise(() =>\n (prerender as unknown as RemotePrerenderFunction<void, Output>)(undefined),\n );\n }\n\n return fromRemotePromise(() => prerender(input as Input));\n}\n\n/**\n * The shape of an enhanced remote form `submit` function. The promise result\n * is left open (SvelteKit returns `Promise<void>` in older versions and\n * `Promise<boolean>` in newer ones).\n */\nexport type RemoteSubmit = () => PromiseLike<unknown> & {\n updates: (...queries: Array<RemoteQuery<any> | RemoteQueryOverride>) => PromiseLike<unknown>;\n};\n\n/**\n * Runs an enhanced remote form's `submit()` as an Effect.\n *\n * A rejected call (including a thrown `error()` / `redirect()`) surfaces as a\n * defect, not on the error channel, despite the declared `unknown` error type.\n */\nexport function submitForm(\n submit: () => PromiseLike<unknown>,\n): Effect.Effect<void, unknown, never> {\n return Effect.asVoid(fromRemotePromise(() => submit()));\n}\n\n/**\n * Runs an enhanced remote form's `submit()` and refreshes the given queries in\n * the same round trip (SvelteKit's single-flight mutations).\n *\n * A rejected call (including a thrown `error()` / `redirect()`) surfaces as a\n * defect, not on the error channel, despite the declared `unknown` error type.\n */\nexport function submitFormWithUpdates(\n submit: RemoteSubmit,\n ...queries: Array<RemoteQuery<any> | RemoteQueryOverride>\n): Effect.Effect<void, unknown, never> {\n return Effect.asVoid(fromRemotePromise(() => submit().updates(...queries)));\n}\n\n/**\n * Consumes a SvelteKit live query (`query.live(...)`) as an Effect `Stream`.\n *\n * A `RemoteLiveQuery<T>` is an `AsyncIterable<T>` that yields every update\n * pushed from the server; this turns it into a `Stream` so live data can drive\n * Effect pipelines (and, via `useStream`, Svelte runes).\n *\n * @example\n * ```ts\n * import { Remote } from '@thomasfosterau/effect-sveltekit';\n * import { messages } from './chat.remote';\n * import { useStream } from '@thomasfosterau/effect-svelte';\n *\n * const feed = useStream(Remote.liveQueryStream(messages()));\n * ```\n */\nexport function liveQueryStream<Output>(\n query: RemoteLiveQuery<Output>,\n): Stream.Stream<Output, unknown> {\n return Stream.fromAsyncIterable(query, (error) => error);\n}\n"],"mappings":";;;;;;;;;;;;AAUA,SAAS,kBAAqB,OAA+D;CAC3F,OAAO,OAAO,cAAc,QAAQ,QAAQ,MAAM,CAAC,CAAC;AACtD;AAsBA,SAAgB,UACd,OACA,OACuC;CACvC,IAAI,UAAU,WAAW,GACvB,OAAO,wBACJ,MAAuD,KAAA,CAAS,CACnE;CAGF,OAAO,wBAAwB,MAAM,KAAc,CAAC;AACtD;AAuBA,SAAgB,YACd,SACA,OACuC;CACvC,IAAI,UAAU,WAAW,GACvB,OAAO,wBAAyB,QAAmD,KAAA,CAAS,CAAC;CAG/F,OAAO,wBAAwB,QAAQ,KAAc,CAAC;AACxD;;;;;;;;;;;;AAaA,SAAgB,uBACd,SACA,OACA,GAAG,SACoC;CACvC,OAAO,wBAAwB,QAAQ,KAAK,CAAC,CAAC,QAAQ,GAAG,OAAO,CAAC;AACnE;AAuBA,SAAgB,cACd,WACA,OACuC;CACvC,IAAI,UAAU,WAAW,GACvB,OAAO,wBACJ,UAA+D,KAAA,CAAS,CAC3E;CAGF,OAAO,wBAAwB,UAAU,KAAc,CAAC;AAC1D;;;;;;;AAiBA,SAAgB,WACd,QACqC;CACrC,OAAO,OAAO,OAAO,wBAAwB,OAAO,CAAC,CAAC;AACxD;;;;;;;;AASA,SAAgB,sBACd,QACA,GAAG,SACkC;CACrC,OAAO,OAAO,OAAO,wBAAwB,OAAO,CAAC,CAAC,QAAQ,GAAG,OAAO,CAAC,CAAC;AAC5E;;;;;;;;;;;;;;;;;AAkBA,SAAgB,gBACd,OACgC;CAChC,OAAO,OAAO,kBAAkB,QAAQ,UAAU,KAAK;AACzD"}
1
+ {"version":3,"file":"Remote.js","names":[],"sources":["../src/Remote.ts"],"sourcesContent":["import type {\n RemoteCommand,\n RemoteLiveQuery,\n RemotePrerenderFunction,\n RemoteQuery,\n RemoteQueryFunction,\n RemoteQueryOverride,\n} from \"$app/server\";\nimport { Effect, Stream } from \"effect\";\n\n/**\n * Wraps a remote call so a rejection, or a synchronous throw from `thunk`,\n * fails the Effect with the original reason instead of becoming a defect.\n */\nfunction fromRemotePromise<A>(thunk: () => PromiseLike<A>): Effect.Effect<A, unknown, never> {\n return Effect.tryPromise({\n try: () => Promise.resolve(thunk()),\n catch: (error) => error,\n });\n}\n\n/**\n * Calls a SvelteKit remote `query` as an Effect that succeeds with its output.\n *\n * Fails with the remote call's rejection reason, typed `unknown` and passed\n * through unchanged. On the client, a server-side `error()` arrives as\n * SvelteKit's `HttpError`; a server-side `redirect()` navigates instead of\n * failing.\n */\nexport function callQuery<Output>(\n query: RemoteQueryFunction<void, Output>,\n): Effect.Effect<Output, unknown, never>;\n/**\n * Calls a SvelteKit remote `query` with `input` as an Effect that succeeds\n * with its output.\n *\n * Fails with the remote call's rejection reason, typed `unknown` and passed\n * through unchanged. On the client, a server-side `error()` arrives as\n * SvelteKit's `HttpError`; a server-side `redirect()` navigates instead of\n * failing.\n */\nexport function callQuery<Input, Output>(\n query: RemoteQueryFunction<Input, Output>,\n input: Input,\n): Effect.Effect<Output, unknown, never>;\nexport function callQuery<Input, Output>(\n query: RemoteQueryFunction<Input, Output>,\n input?: Input,\n): Effect.Effect<Output, unknown, never> {\n if (arguments.length === 1) {\n return fromRemotePromise(() =>\n (query as unknown as RemoteQueryFunction<void, Output>)(undefined),\n );\n }\n\n return fromRemotePromise(() => query(input as Input));\n}\n\n/**\n * Calls a SvelteKit remote `command` as an Effect that succeeds with its\n * output.\n *\n * Fails with the remote call's rejection reason, typed `unknown` and passed\n * through unchanged. On the client, a server-side `error()` arrives as\n * SvelteKit's `HttpError`; commands may not `redirect()`, and SvelteKit\n * rejects one with an `Error`.\n */\nexport function callCommand<Output>(\n command: RemoteCommand<void, Output>,\n): Effect.Effect<Output, unknown, never>;\n/**\n * Calls a SvelteKit remote `command` with `input` as an Effect that succeeds\n * with its output.\n *\n * Fails with the remote call's rejection reason, typed `unknown` and passed\n * through unchanged. On the client, a server-side `error()` arrives as\n * SvelteKit's `HttpError`; commands may not `redirect()`, and SvelteKit\n * rejects one with an `Error`.\n */\nexport function callCommand<Input, Output>(\n command: RemoteCommand<Input, Output>,\n input: Input,\n): Effect.Effect<Output, unknown, never>;\nexport function callCommand<Input, Output>(\n command: RemoteCommand<Input, Output>,\n input?: Input,\n): Effect.Effect<Output, unknown, never> {\n if (arguments.length === 1) {\n return fromRemotePromise(() => (command as unknown as RemoteCommand<void, Output>)(undefined));\n }\n\n return fromRemotePromise(() => command(input as Input));\n}\n\n/**\n * Calls a remote command and refreshes the given queries in the same round\n * trip (SvelteKit's single-flight mutations).\n *\n * Newer SvelteKit versions cache remote query instances, so a command that\n * changes data those queries depend on must list them here (or call\n * `query.refresh()` afterwards) for their cached values to update.\n *\n * Fails with the remote call's rejection reason, typed `unknown` and passed\n * through unchanged. On the client, a server-side `error()` arrives as\n * SvelteKit's `HttpError`; commands may not `redirect()`, and SvelteKit\n * rejects one with an `Error`.\n */\nexport function callCommandWithUpdates<Input, Output>(\n command: RemoteCommand<Input, Output>,\n input: Input,\n ...queries: Array<RemoteQuery<any> | RemoteQueryOverride>\n): Effect.Effect<Output, unknown, never> {\n return fromRemotePromise(() => command(input).updates(...queries));\n}\n\n/**\n * Calls a SvelteKit remote `prerender` function as an Effect that succeeds\n * with its output.\n *\n * Fails with the remote call's rejection reason, typed `unknown` and passed\n * through unchanged. On the client, a server-side `error()` arrives as\n * SvelteKit's `HttpError`; a server-side `redirect()` navigates instead of\n * failing.\n */\nexport function callPrerender<Output>(\n prerender: RemotePrerenderFunction<void, Output>,\n): Effect.Effect<Output, unknown, never>;\n/**\n * Calls a SvelteKit remote `prerender` function with `input` as an Effect\n * that succeeds with its output.\n *\n * Fails with the remote call's rejection reason, typed `unknown` and passed\n * through unchanged. On the client, a server-side `error()` arrives as\n * SvelteKit's `HttpError`; a server-side `redirect()` navigates instead of\n * failing.\n */\nexport function callPrerender<Input, Output>(\n prerender: RemotePrerenderFunction<Input, Output>,\n input: Input,\n): Effect.Effect<Output, unknown, never>;\nexport function callPrerender<Input, Output>(\n prerender: RemotePrerenderFunction<Input, Output>,\n input?: Input,\n): Effect.Effect<Output, unknown, never> {\n if (arguments.length === 1) {\n return fromRemotePromise(() =>\n (prerender as unknown as RemotePrerenderFunction<void, Output>)(undefined),\n );\n }\n\n return fromRemotePromise(() => prerender(input as Input));\n}\n\n/**\n * The shape of an enhanced remote form `submit` function. The promise result\n * is left open (SvelteKit returns `Promise<void>` in older versions and\n * `Promise<boolean>` in newer ones).\n */\nexport type RemoteSubmit = () => PromiseLike<unknown> & {\n updates: (...queries: Array<RemoteQuery<any> | RemoteQueryOverride>) => PromiseLike<unknown>;\n};\n\n/**\n * Runs an enhanced remote form's `submit()` as an Effect.\n *\n * Fails with the remote call's rejection reason, typed `unknown` and passed\n * through unchanged. On the client, a server-side `error()` arrives as\n * SvelteKit's `HttpError`; a server-side `redirect()` navigates instead of\n * failing.\n */\nexport function submitForm(\n submit: () => PromiseLike<unknown>,\n): Effect.Effect<void, unknown, never> {\n return Effect.asVoid(fromRemotePromise(() => submit()));\n}\n\n/**\n * Runs an enhanced remote form's `submit()` and refreshes the given queries in\n * the same round trip (SvelteKit's single-flight mutations).\n *\n * Fails with the remote call's rejection reason, typed `unknown` and passed\n * through unchanged. On the client, a server-side `error()` arrives as\n * SvelteKit's `HttpError`; a server-side `redirect()` navigates instead of\n * failing.\n */\nexport function submitFormWithUpdates(\n submit: RemoteSubmit,\n ...queries: Array<RemoteQuery<any> | RemoteQueryOverride>\n): Effect.Effect<void, unknown, never> {\n return Effect.asVoid(fromRemotePromise(() => submit().updates(...queries)));\n}\n\n/**\n * Consumes a SvelteKit live query (`query.live(...)`) as an Effect `Stream`.\n *\n * A `RemoteLiveQuery<T>` is an `AsyncIterable<T>` that yields every update\n * pushed from the server; this turns it into a `Stream` so live data can drive\n * Effect pipelines (and, via `useStream`, Svelte runes).\n *\n * @example\n * ```ts\n * import { Remote } from '@thomasfosterau/effect-sveltekit';\n * import { messages } from './chat.remote';\n * import { useStream } from '@thomasfosterau/effect-svelte';\n *\n * const feed = useStream(Remote.liveQueryStream(messages()));\n * ```\n */\nexport function liveQueryStream<Output>(\n query: RemoteLiveQuery<Output>,\n): Stream.Stream<Output, unknown> {\n return Stream.fromAsyncIterable(query, (error) => error);\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAcA,SAAS,kBAAqB,OAA+D;CAC3F,OAAO,OAAO,WAAW;EACvB,WAAW,QAAQ,QAAQ,MAAM,CAAC;EAClC,QAAQ,UAAU;CACpB,CAAC;AACH;AA0BA,SAAgB,UACd,OACA,OACuC;CACvC,IAAI,UAAU,WAAW,GACvB,OAAO,wBACJ,MAAuD,KAAA,CAAS,CACnE;CAGF,OAAO,wBAAwB,MAAM,KAAc,CAAC;AACtD;AA2BA,SAAgB,YACd,SACA,OACuC;CACvC,IAAI,UAAU,WAAW,GACvB,OAAO,wBAAyB,QAAmD,KAAA,CAAS,CAAC;CAG/F,OAAO,wBAAwB,QAAQ,KAAc,CAAC;AACxD;;;;;;;;;;;;;;AAeA,SAAgB,uBACd,SACA,OACA,GAAG,SACoC;CACvC,OAAO,wBAAwB,QAAQ,KAAK,CAAC,CAAC,QAAQ,GAAG,OAAO,CAAC;AACnE;AA2BA,SAAgB,cACd,WACA,OACuC;CACvC,IAAI,UAAU,WAAW,GACvB,OAAO,wBACJ,UAA+D,KAAA,CAAS,CAC3E;CAGF,OAAO,wBAAwB,UAAU,KAAc,CAAC;AAC1D;;;;;;;;;AAmBA,SAAgB,WACd,QACqC;CACrC,OAAO,OAAO,OAAO,wBAAwB,OAAO,CAAC,CAAC;AACxD;;;;;;;;;;AAWA,SAAgB,sBACd,QACA,GAAG,SACkC;CACrC,OAAO,OAAO,OAAO,wBAAwB,OAAO,CAAC,CAAC,QAAQ,GAAG,OAAO,CAAC,CAAC;AAC5E;;;;;;;;;;;;;;;;;AAkBA,SAAgB,gBACd,OACgC;CAChC,OAAO,OAAO,kBAAkB,QAAQ,UAAU,KAAK;AACzD"}
package/dist/State.d.ts CHANGED
@@ -1,15 +1,84 @@
1
- import { PageSnapshot } from "./internal/app-state.js";
2
- import { Stream } from "effect";
1
+ import { CurrentPageShape, NavigatingSnapshot, PageSnapshot, UpdateCheckError } from "./internal/app-state.js";
2
+ import { Context, Effect, Layer, Option, Stream } from "effect";
3
3
  import { Page } from "$app/state";
4
4
  declare namespace State_d_exports {
5
- export { PageSnapshot, page$1 as page };
5
+ export { CurrentPage, CurrentPageInterface, NavigatingSnapshot, PageSnapshot, UpdateCheckError, checkForUpdate, navigating$1 as navigating, page$1 as page, updated$1 as updated };
6
6
  }
7
7
  /**
8
8
  * A `Stream` of the current SvelteKit `page`, emitting a shallow snapshot
9
- * immediately and again after every navigation. Call during component
10
- * initialization.
9
+ * immediately and again after every navigation; never fails. Call during
10
+ * component initialization. It follows `afterNavigate`, so page changes
11
+ * without a navigation (shallow routing, form results) don't emit — use
12
+ * {@link CurrentPage}'s `changes` for those.
11
13
  */
12
14
  declare function page$1(): Stream.Stream<PageSnapshot<Page>>;
15
+ /**
16
+ * A `Stream` of SvelteKit's in-flight navigation: `Option.some` with a
17
+ * {@link NavigatingSnapshot} while a navigation is in progress, `Option.none()`
18
+ * when idle. Emits the current state on the next Svelte flush, then on every
19
+ * change; never fails. Client-only, but callable anywhere (not only during
20
+ * component initialization).
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * const spinner = Stream.runForEach(State.navigating(), (nav) =>
25
+ * Effect.sync(() => (busy = Option.isSome(nav))),
26
+ * );
27
+ * ```
28
+ */
29
+ declare function navigating$1(): Stream.Stream<Option.Option<NavigatingSnapshot>>;
30
+ /**
31
+ * A `Stream` of SvelteKit's `updated.current`: whether a new version of the app
32
+ * has been deployed since this one loaded. Emits the current value on the next
33
+ * Svelte flush, then on every change (SvelteKit only ever flips it from `false`
34
+ * to `true`); never fails. Client-only, but callable anywhere.
35
+ */
36
+ declare function updated$1(): Stream.Stream<boolean>;
37
+ /**
38
+ * Asks SvelteKit to check for a new app version now (`updated.check()`),
39
+ * succeeding with whether one is available; a positive result also flips
40
+ * {@link updated}. Always succeeds with `false` in development. Fails with
41
+ * {@link UpdateCheckError} if the check rejects. Client-only.
42
+ */
43
+ declare function checkForUpdate(): Effect.Effect<boolean, UpdateCheckError>;
44
+ /**
45
+ * The service shape of {@link CurrentPage}: `get` snapshots the current page
46
+ * and `changes` streams it. Neither fails on the client; see
47
+ * {@link CurrentPage} for the server.
48
+ */
49
+ interface CurrentPageInterface extends CurrentPageShape<Page> {}
50
+ declare const CurrentPage_base: Context.ServiceClass<CurrentPage, "@thomasfosterau/effect-sveltekit/CurrentPage", CurrentPageInterface>;
51
+ /**
52
+ * The current SvelteKit page as an Effect service, so any client Effect can read
53
+ * it with `yield* State.CurrentPage` instead of taking it as an argument.
54
+ * `get` snapshots the page when run; `changes` emits the current page on the
55
+ * next Svelte flush, then a fresh snapshot whenever any field changes
56
+ * (navigations, but also shallow routing and form results). Neither fails on
57
+ * the client; on the server, Kit's `page` throws outside synchronous component
58
+ * rendering (including after an async boundary in an Effect forked during
59
+ * render), so `get` dies with a defect there.
60
+ *
61
+ * Provide {@link CurrentPage.layer} (backed by `$app/state`) in your client
62
+ * runtime, or `Layer.succeed(State.CurrentPage, …)` in tests.
63
+ *
64
+ * @example
65
+ * ```ts
66
+ * const trackView = Effect.gen(function* () {
67
+ * const page = yield* (yield* State.CurrentPage).get;
68
+ * yield* analytics.view(page.url.pathname);
69
+ * });
70
+ *
71
+ * runtime.runFork(trackView.pipe(Effect.provide(State.CurrentPage.layer)));
72
+ * ```
73
+ */
74
+ declare class CurrentPage extends CurrentPage_base {
75
+ /**
76
+ * A layer providing {@link CurrentPage} from `$app/state`'s `page`. Builds
77
+ * instantly and never fails; client-only (during server rendering `changes`
78
+ * never emits, so consuming it there hangs).
79
+ */
80
+ static readonly layer: Layer.Layer<CurrentPage>;
81
+ }
13
82
  //#endregion
14
- export { type PageSnapshot, State_d_exports, page$1 as page };
83
+ export { CurrentPage, CurrentPageInterface, type NavigatingSnapshot, type PageSnapshot, State_d_exports, UpdateCheckError, checkForUpdate, navigating$1 as navigating, page$1 as page, updated$1 as updated };
15
84
  //# sourceMappingURL=State.d.ts.map
package/dist/State.js CHANGED
@@ -1,34 +1,48 @@
1
1
  import { __exportAll } from "./_virtual/_rolldown/runtime.js";
2
- import { pageSnapshotStream } from "./internal/app-state.js";
2
+ import { UpdateCheckError, checkForUpdateWith, makeCurrentPage, pageSnapshotStream, snapshotNavigating, watchedStream } from "./internal/app-state.js";
3
+ import { watch } from "./internal/watch.svelte.js";
4
+ import { Context, Layer } from "effect";
3
5
  import { afterNavigate } from "$app/navigation";
4
- import { page } from "$app/state";
6
+ import { navigating, page, updated } from "$app/state";
5
7
  //#region src/State.ts
6
8
  /**
7
- * A minimal Effect-side bridge for SvelteKit's
8
- * [`$app/state`](https://svelte.dev/docs/kit/$app-state) `page`.
9
+ * An Effect-side bridge for SvelteKit's
10
+ * [`$app/state`](https://svelte.dev/docs/kit/$app-state): `page`, `navigating`
11
+ * and `updated`.
9
12
  *
10
- * `$app/state` exposes rune-reactive `page` / `navigating` / `updated` for use
11
- * inside components. This bridges `page` to an Effect `Stream` so navigation can
12
- * drive Effect pipelines without touching Svelte runes: it emits the current
13
- * `page` immediately, then again after each navigation, by registering
14
- * `afterNavigate` (from `$app/navigation`) and reading `page` (from
15
- * `$app/state`) at callback time.
13
+ * `$app/state` exposes rune-reactive objects for use inside components. This
14
+ * module turns them into Effect values so navigation and version state can
15
+ * drive Effect pipelines without touching Svelte runes:
16
16
  *
17
- * Each emission is a *shallow snapshot* (`url`, `params`, `route`, `data`,
18
- * `status`, `error`, `form`, `state`) rather than the live `$app/state` proxy:
19
- * the proxy mutates in place on every navigation, so a captured reference is
20
- * unreliable for downstream consumers — the snapshot gives each emission a
21
- * stable value. Reading at `afterNavigate` time also avoids needing a `.svelte`
22
- * runes file.
17
+ * - {@link page} — a `Stream` of page snapshots, emitted now and after each
18
+ * navigation (via `afterNavigate`, so call it during component
19
+ * initialization).
20
+ * - {@link navigating} — a `Stream` of the in-flight navigation as an
21
+ * `Option` (`None` when idle).
22
+ * - {@link updated} / {@link checkForUpdate} — whether a new app version has
23
+ * been deployed, as a `Stream<boolean>` and as an on-demand check.
24
+ * - {@link CurrentPage} — a `Context` service exposing the current page to any
25
+ * client Effect; provide {@link CurrentPage.layer} in your client runtime.
23
26
  *
24
- * Like the navigation-event helpers, `page` registers its callback during
25
- * component initialization (where `$app/navigation` requires), so call it at the
26
- * top level of `<script>`. Client-only.
27
+ * Each page emission is a *shallow snapshot* (`url`, `params`, `route`, `data`,
28
+ * `status`, `error`, `form`, `state`, `shallow`) rather than the live
29
+ * `$app/state` proxy: the proxy mutates in place on every navigation, so a
30
+ * captured reference is unreliable for downstream consumers — the snapshot
31
+ * gives each emission a stable value. `navigating` emissions are snapshots for
32
+ * the same reason.
27
33
  *
28
- * NOTE: this is intentionally minimal. A richer reactive bridge (a `CurrentPage`
29
- * service readable from any Effect, `navigating` / `updated` streams) may later
30
- * compose with the official `@effect/atom-svelte` integration (see issue #23)
31
- * rather than re-implementing runes plumbing here.
34
+ * `navigating`, `updated` and `CurrentPage.changes` watch the rune state with a
35
+ * root `$effect`, so they work anywhere on the client (not only during
36
+ * component initialization). Each stream is cold: a run opens its own watcher,
37
+ * emits the current value on the next Svelte flush and again whenever it
38
+ * changes, and disposes the watcher when the stream ends or is interrupted.
39
+ * All of this is client-only: during server rendering the watched streams
40
+ * never emit, so consuming one there (for example with `Stream.runHead`)
41
+ * hangs rather than failing.
42
+ *
43
+ * These are streams and a service rather than atoms; an atom-based variant
44
+ * may follow once the official `@effect/atom-svelte` integration lands (see
45
+ * issue #23).
32
46
  *
33
47
  * @example
34
48
  * ```svelte
@@ -46,11 +60,20 @@ import { page } from "$app/state";
46
60
  * <\/script>
47
61
  * ```
48
62
  */
49
- var State_exports = /* @__PURE__ */ __exportAll({ page: () => page$1 });
63
+ var State_exports = /* @__PURE__ */ __exportAll({
64
+ CurrentPage: () => CurrentPage,
65
+ UpdateCheckError: () => UpdateCheckError,
66
+ checkForUpdate: () => checkForUpdate,
67
+ navigating: () => navigating$1,
68
+ page: () => page$1,
69
+ updated: () => updated$1
70
+ });
50
71
  /**
51
72
  * A `Stream` of the current SvelteKit `page`, emitting a shallow snapshot
52
- * immediately and again after every navigation. Call during component
53
- * initialization.
73
+ * immediately and again after every navigation; never fails. Call during
74
+ * component initialization. It follows `afterNavigate`, so page changes
75
+ * without a navigation (shallow routing, form results) don't emit — use
76
+ * {@link CurrentPage}'s `changes` for those.
54
77
  */
55
78
  function page$1() {
56
79
  return pageSnapshotStream((callback) => {
@@ -59,7 +82,73 @@ function page$1() {
59
82
  });
60
83
  }, () => page);
61
84
  }
85
+ /**
86
+ * A `Stream` of SvelteKit's in-flight navigation: `Option.some` with a
87
+ * {@link NavigatingSnapshot} while a navigation is in progress, `Option.none()`
88
+ * when idle. Emits the current state on the next Svelte flush, then on every
89
+ * change; never fails. Client-only, but callable anywhere (not only during
90
+ * component initialization).
91
+ *
92
+ * @example
93
+ * ```ts
94
+ * const spinner = Stream.runForEach(State.navigating(), (nav) =>
95
+ * Effect.sync(() => (busy = Option.isSome(nav))),
96
+ * );
97
+ * ```
98
+ */
99
+ function navigating$1() {
100
+ return watchedStream(watch, () => snapshotNavigating(navigating));
101
+ }
102
+ /**
103
+ * A `Stream` of SvelteKit's `updated.current`: whether a new version of the app
104
+ * has been deployed since this one loaded. Emits the current value on the next
105
+ * Svelte flush, then on every change (SvelteKit only ever flips it from `false`
106
+ * to `true`); never fails. Client-only, but callable anywhere.
107
+ */
108
+ function updated$1() {
109
+ return watchedStream(watch, () => updated.current);
110
+ }
111
+ /**
112
+ * Asks SvelteKit to check for a new app version now (`updated.check()`),
113
+ * succeeding with whether one is available; a positive result also flips
114
+ * {@link updated}. Always succeeds with `false` in development. Fails with
115
+ * {@link UpdateCheckError} if the check rejects. Client-only.
116
+ */
117
+ function checkForUpdate() {
118
+ return checkForUpdateWith(() => updated.check());
119
+ }
120
+ /**
121
+ * The current SvelteKit page as an Effect service, so any client Effect can read
122
+ * it with `yield* State.CurrentPage` instead of taking it as an argument.
123
+ * `get` snapshots the page when run; `changes` emits the current page on the
124
+ * next Svelte flush, then a fresh snapshot whenever any field changes
125
+ * (navigations, but also shallow routing and form results). Neither fails on
126
+ * the client; on the server, Kit's `page` throws outside synchronous component
127
+ * rendering (including after an async boundary in an Effect forked during
128
+ * render), so `get` dies with a defect there.
129
+ *
130
+ * Provide {@link CurrentPage.layer} (backed by `$app/state`) in your client
131
+ * runtime, or `Layer.succeed(State.CurrentPage, …)` in tests.
132
+ *
133
+ * @example
134
+ * ```ts
135
+ * const trackView = Effect.gen(function* () {
136
+ * const page = yield* (yield* State.CurrentPage).get;
137
+ * yield* analytics.view(page.url.pathname);
138
+ * });
139
+ *
140
+ * runtime.runFork(trackView.pipe(Effect.provide(State.CurrentPage.layer)));
141
+ * ```
142
+ */
143
+ var CurrentPage = class CurrentPage extends Context.Service()("@thomasfosterau/effect-sveltekit/CurrentPage") {
144
+ /**
145
+ * A layer providing {@link CurrentPage} from `$app/state`'s `page`. Builds
146
+ * instantly and never fails; client-only (during server rendering `changes`
147
+ * never emits, so consuming it there hangs).
148
+ */
149
+ static layer = Layer.succeed(CurrentPage, makeCurrentPage(() => page, watch));
150
+ };
62
151
  //#endregion
63
- export { State_exports, page$1 as page };
152
+ export { CurrentPage, State_exports, UpdateCheckError, checkForUpdate, navigating$1 as navigating, page$1 as page, updated$1 as updated };
64
153
 
65
154
  //# sourceMappingURL=State.js.map
package/dist/State.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"State.js","names":["page","kitPage"],"sources":["../src/State.ts"],"sourcesContent":["/**\n * A minimal Effect-side bridge for SvelteKit's\n * [`$app/state`](https://svelte.dev/docs/kit/$app-state) `page`.\n *\n * `$app/state` exposes rune-reactive `page` / `navigating` / `updated` for use\n * inside components. This bridges `page` to an Effect `Stream` so navigation can\n * drive Effect pipelines without touching Svelte runes: it emits the current\n * `page` immediately, then again after each navigation, by registering\n * `afterNavigate` (from `$app/navigation`) and reading `page` (from\n * `$app/state`) at callback time.\n *\n * Each emission is a *shallow snapshot* (`url`, `params`, `route`, `data`,\n * `status`, `error`, `form`, `state`) rather than the live `$app/state` proxy:\n * the proxy mutates in place on every navigation, so a captured reference is\n * unreliable for downstream consumers — the snapshot gives each emission a\n * stable value. Reading at `afterNavigate` time also avoids needing a `.svelte`\n * runes file.\n *\n * Like the navigation-event helpers, `page` registers its callback during\n * component initialization (where `$app/navigation` requires), so call it at the\n * top level of `<script>`. Client-only.\n *\n * NOTE: this is intentionally minimal. A richer reactive bridge (a `CurrentPage`\n * service readable from any Effect, `navigating` / `updated` streams) may later\n * compose with the official `@effect/atom-svelte` integration (see issue #23)\n * rather than re-implementing runes plumbing here.\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { State } from '@thomasfosterau/effect-sveltekit/client';\n * import { Stream, Effect } from 'effect';\n * import { getRuntime } from '@thomasfosterau/effect-svelte';\n *\n * const pages = State.page();\n * getRuntime().runFork(\n * Stream.runForEach(pages, (page) =>\n * Effect.logInfo(`page: ${page.url.pathname}`),\n * ),\n * );\n * </script>\n * ```\n */\n\nimport { afterNavigate as kitAfterNavigate } from \"$app/navigation\";\nimport { page as kitPage } from \"$app/state\";\nimport type { Page } from \"$app/state\";\nimport type { Stream } from \"effect\";\nimport { type PageSnapshot, pageSnapshotStream } from \"./internal/app-state.js\";\n\n/** A shallow snapshot of SvelteKit's `page` — see {@link page}. */\nexport type { PageSnapshot } from \"./internal/app-state.js\";\n\n/**\n * A `Stream` of the current SvelteKit `page`, emitting a shallow snapshot\n * immediately and again after every navigation. Call during component\n * initialization.\n */\nexport function page(): Stream.Stream<PageSnapshot<Page>> {\n return pageSnapshotStream<Page>(\n (callback) => {\n kitAfterNavigate(() => {\n callback();\n });\n },\n () => kitPage,\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0DA,SAAgBA,SAA0C;CACxD,OAAO,oBACJ,aAAa;EACZ,oBAAuB;GACrB,SAAS;EACX,CAAC;CACH,SACMC,IACR;AACF"}
1
+ {"version":3,"file":"State.js","names":["page","kitPage","navigating","kitNavigating","updated","kitUpdated"],"sources":["../src/State.ts"],"sourcesContent":["/**\n * An Effect-side bridge for SvelteKit's\n * [`$app/state`](https://svelte.dev/docs/kit/$app-state): `page`, `navigating`\n * and `updated`.\n *\n * `$app/state` exposes rune-reactive objects for use inside components. This\n * module turns them into Effect values so navigation and version state can\n * drive Effect pipelines without touching Svelte runes:\n *\n * - {@link page} — a `Stream` of page snapshots, emitted now and after each\n * navigation (via `afterNavigate`, so call it during component\n * initialization).\n * - {@link navigating} — a `Stream` of the in-flight navigation as an\n * `Option` (`None` when idle).\n * - {@link updated} / {@link checkForUpdate} — whether a new app version has\n * been deployed, as a `Stream<boolean>` and as an on-demand check.\n * - {@link CurrentPage} — a `Context` service exposing the current page to any\n * client Effect; provide {@link CurrentPage.layer} in your client runtime.\n *\n * Each page emission is a *shallow snapshot* (`url`, `params`, `route`, `data`,\n * `status`, `error`, `form`, `state`, `shallow`) rather than the live\n * `$app/state` proxy: the proxy mutates in place on every navigation, so a\n * captured reference is unreliable for downstream consumers — the snapshot\n * gives each emission a stable value. `navigating` emissions are snapshots for\n * the same reason.\n *\n * `navigating`, `updated` and `CurrentPage.changes` watch the rune state with a\n * root `$effect`, so they work anywhere on the client (not only during\n * component initialization). Each stream is cold: a run opens its own watcher,\n * emits the current value on the next Svelte flush and again whenever it\n * changes, and disposes the watcher when the stream ends or is interrupted.\n * All of this is client-only: during server rendering the watched streams\n * never emit, so consuming one there (for example with `Stream.runHead`)\n * hangs rather than failing.\n *\n * These are streams and a service rather than atoms; an atom-based variant\n * may follow once the official `@effect/atom-svelte` integration lands (see\n * issue #23).\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { State } from '@thomasfosterau/effect-sveltekit/client';\n * import { Stream, Effect } from 'effect';\n * import { getRuntime } from '@thomasfosterau/effect-svelte';\n *\n * const pages = State.page();\n * getRuntime().runFork(\n * Stream.runForEach(pages, (page) =>\n * Effect.logInfo(`page: ${page.url.pathname}`),\n * ),\n * );\n * </script>\n * ```\n */\n\nimport { afterNavigate as kitAfterNavigate } from \"$app/navigation\";\nimport { navigating as kitNavigating, page as kitPage, updated as kitUpdated } from \"$app/state\";\nimport type { Page } from \"$app/state\";\nimport { Context, Layer } from \"effect\";\nimport type { Effect, Option, Stream } from \"effect\";\nimport {\n type CurrentPageShape,\n type NavigatingSnapshot,\n type PageSnapshot,\n type UpdateCheckError,\n checkForUpdateWith,\n makeCurrentPage,\n pageSnapshotStream,\n snapshotNavigating,\n watchedStream,\n} from \"./internal/app-state.js\";\nimport { watch } from \"./internal/watch.svelte.js\";\n\n/** A shallow snapshot of SvelteKit's `page` — see {@link page}. */\nexport type { PageSnapshot } from \"./internal/app-state.js\";\n\n/**\n * A snapshot of an in-flight SvelteKit navigation (`type`, `from`, `to`,\n * `willUnload`, `delta`, `complete`) — see {@link navigating}.\n */\nexport type { NavigatingSnapshot } from \"./internal/app-state.js\";\n\n/**\n * The error {@link checkForUpdate} fails with when SvelteKit's\n * `updated.check()` rejects (misuse such as calling it during server\n * rendering; a failed version request resolves `false` instead). The original\n * error is on `cause`.\n */\nexport { UpdateCheckError } from \"./internal/app-state.js\";\n\n/**\n * A `Stream` of the current SvelteKit `page`, emitting a shallow snapshot\n * immediately and again after every navigation; never fails. Call during\n * component initialization. It follows `afterNavigate`, so page changes\n * without a navigation (shallow routing, form results) don't emit — use\n * {@link CurrentPage}'s `changes` for those.\n */\nexport function page(): Stream.Stream<PageSnapshot<Page>> {\n return pageSnapshotStream<Page>(\n (callback) => {\n kitAfterNavigate(() => {\n callback();\n });\n },\n () => kitPage,\n );\n}\n\n/**\n * A `Stream` of SvelteKit's in-flight navigation: `Option.some` with a\n * {@link NavigatingSnapshot} while a navigation is in progress, `Option.none()`\n * when idle. Emits the current state on the next Svelte flush, then on every\n * change; never fails. Client-only, but callable anywhere (not only during\n * component initialization).\n *\n * @example\n * ```ts\n * const spinner = Stream.runForEach(State.navigating(), (nav) =>\n * Effect.sync(() => (busy = Option.isSome(nav))),\n * );\n * ```\n */\nexport function navigating(): Stream.Stream<Option.Option<NavigatingSnapshot>> {\n return watchedStream(watch, () => snapshotNavigating(kitNavigating));\n}\n\n/**\n * A `Stream` of SvelteKit's `updated.current`: whether a new version of the app\n * has been deployed since this one loaded. Emits the current value on the next\n * Svelte flush, then on every change (SvelteKit only ever flips it from `false`\n * to `true`); never fails. Client-only, but callable anywhere.\n */\nexport function updated(): Stream.Stream<boolean> {\n return watchedStream(watch, () => kitUpdated.current);\n}\n\n/**\n * Asks SvelteKit to check for a new app version now (`updated.check()`),\n * succeeding with whether one is available; a positive result also flips\n * {@link updated}. Always succeeds with `false` in development. Fails with\n * {@link UpdateCheckError} if the check rejects. Client-only.\n */\nexport function checkForUpdate(): Effect.Effect<boolean, UpdateCheckError> {\n return checkForUpdateWith(() => kitUpdated.check());\n}\n\n/**\n * The service shape of {@link CurrentPage}: `get` snapshots the current page\n * and `changes` streams it. Neither fails on the client; see\n * {@link CurrentPage} for the server.\n */\nexport interface CurrentPageInterface extends CurrentPageShape<Page> {}\n\n/**\n * The current SvelteKit page as an Effect service, so any client Effect can read\n * it with `yield* State.CurrentPage` instead of taking it as an argument.\n * `get` snapshots the page when run; `changes` emits the current page on the\n * next Svelte flush, then a fresh snapshot whenever any field changes\n * (navigations, but also shallow routing and form results). Neither fails on\n * the client; on the server, Kit's `page` throws outside synchronous component\n * rendering (including after an async boundary in an Effect forked during\n * render), so `get` dies with a defect there.\n *\n * Provide {@link CurrentPage.layer} (backed by `$app/state`) in your client\n * runtime, or `Layer.succeed(State.CurrentPage, …)` in tests.\n *\n * @example\n * ```ts\n * const trackView = Effect.gen(function* () {\n * const page = yield* (yield* State.CurrentPage).get;\n * yield* analytics.view(page.url.pathname);\n * });\n *\n * runtime.runFork(trackView.pipe(Effect.provide(State.CurrentPage.layer)));\n * ```\n */\nexport class CurrentPage extends Context.Service<CurrentPage, CurrentPageInterface>()(\n \"@thomasfosterau/effect-sveltekit/CurrentPage\",\n) {\n /**\n * A layer providing {@link CurrentPage} from `$app/state`'s `page`. Builds\n * instantly and never fails; client-only (during server rendering `changes`\n * never emits, so consuming it there hangs).\n */\n static readonly layer: Layer.Layer<CurrentPage> = Layer.succeed(\n CurrentPage,\n makeCurrentPage(() => kitPage, watch),\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkGA,SAAgBA,SAA0C;CACxD,OAAO,oBACJ,aAAa;EACZ,oBAAuB;GACrB,SAAS;EACX,CAAC;CACH,SACMC,IACR;AACF;;;;;;;;;;;;;;;AAgBA,SAAgBC,eAA+D;CAC7E,OAAO,cAAc,aAAa,mBAAmBC,UAAa,CAAC;AACrE;;;;;;;AAQA,SAAgBC,YAAkC;CAChD,OAAO,cAAc,aAAaC,QAAW,OAAO;AACtD;;;;;;;AAQA,SAAgB,iBAA2D;CACzE,OAAO,yBAAyBA,QAAW,MAAM,CAAC;AACpD;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,IAAa,cAAb,MAAa,oBAAoB,QAAQ,QAA2C,CAAC,CACnF,8CACF,CAAC,CAAC;;;;;;CAMA,OAAgB,QAAkC,MAAM,QACtD,aACA,sBAAsBJ,MAAS,KAAK,CACtC;AACF"}