@thomasfosterau/effect-sveltekit 0.1.1 → 0.2.1

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 (51) hide show
  1. package/dist/api-client.d.ts +32 -0
  2. package/dist/api-client.js +44 -0
  3. package/dist/api-client.js.map +1 -0
  4. package/dist/app-runtime.d.ts +2 -1
  5. package/dist/app-runtime.js +13 -11
  6. package/dist/app-runtime.js.map +1 -1
  7. package/dist/client.d.ts +3 -1
  8. package/dist/client.js +3 -1
  9. package/dist/config.d.ts +33 -2
  10. package/dist/config.js +33 -2
  11. package/dist/config.js.map +1 -1
  12. package/dist/forms.d.ts +30 -0
  13. package/dist/forms.js +66 -0
  14. package/dist/forms.js.map +1 -0
  15. package/dist/index.d.ts +3 -2
  16. package/dist/index.js +3 -2
  17. package/dist/internal/enhance.d.ts +39 -0
  18. package/dist/internal/enhance.js +24 -0
  19. package/dist/internal/enhance.js.map +1 -0
  20. package/dist/internal/remote-run.d.ts +12 -1
  21. package/dist/internal/remote-run.js +3 -5
  22. package/dist/internal/remote-run.js.map +1 -1
  23. package/dist/internal/sse.js +37 -0
  24. package/dist/internal/sse.js.map +1 -0
  25. package/dist/kit.d.ts +130 -0
  26. package/dist/kit.js +185 -0
  27. package/dist/kit.js.map +1 -0
  28. package/dist/realtime.d.ts +105 -0
  29. package/dist/realtime.js +111 -0
  30. package/dist/realtime.js.map +1 -0
  31. package/dist/request-parse.d.ts +89 -0
  32. package/dist/request-parse.js +121 -0
  33. package/dist/request-parse.js.map +1 -0
  34. package/dist/request-runtime.js +17 -16
  35. package/dist/request-runtime.js.map +1 -1
  36. package/dist/request-services.d.ts +120 -0
  37. package/dist/request-services.js +120 -0
  38. package/dist/request-services.js.map +1 -0
  39. package/dist/server/Endpoint.d.ts +62 -2
  40. package/dist/server/Endpoint.js +47 -2
  41. package/dist/server/Endpoint.js.map +1 -1
  42. package/dist/server.d.ts +5 -1
  43. package/dist/server.js +5 -1
  44. package/dist/server.js.map +1 -1
  45. package/dist/streamed-load.d.ts +23 -0
  46. package/dist/streamed-load.js +74 -0
  47. package/dist/streamed-load.js.map +1 -0
  48. package/dist/testing.d.ts +175 -0
  49. package/dist/testing.js +153 -0
  50. package/dist/testing.js.map +1 -0
  51. package/package.json +6 -2
@@ -0,0 +1,32 @@
1
+ import { Effect } from "effect";
2
+ import * as HttpClient from "effect/unstable/http/HttpClient";
3
+ import * as HttpApiClient from "effect/unstable/httpapi/HttpApiClient";
4
+ import * as HttpApi from "effect/unstable/httpapi/HttpApi";
5
+ import * as HttpApiGroup from "effect/unstable/httpapi/HttpApiGroup";
6
+
7
+ //#region src/api-client.d.ts
8
+ /** Options for {@link apiClient}. */
9
+ interface ApiClientOptions {
10
+ /**
11
+ * The base URL the API is mounted at. For an `Endpoint.fromApi` mounted at
12
+ * `src/routes/api/[...path]` with `prefix: "/api"`, pass `"/api"`. Defaults to
13
+ * the endpoint paths relative to the current origin.
14
+ */
15
+ readonly baseUrl?: URL | string;
16
+ /**
17
+ * The `fetch` implementation to use. In a `load`, pass `event.fetch` so the
18
+ * request joins SvelteKit's SSR fetch. Defaults to the platform `fetch`.
19
+ */
20
+ readonly fetch?: typeof globalThis.fetch;
21
+ /** Transform the underlying `HttpClient` (e.g. add headers, retries). */
22
+ readonly transformClient?: (client: HttpClient.HttpClient) => HttpClient.HttpClient;
23
+ }
24
+ /**
25
+ * Build a typed {@link HttpApiClient} for `api`, with the `HttpClient` provided
26
+ * via `FetchHttpClient`. Yields the client from an `Effect`; the only remaining
27
+ * requirement is any client middleware the API declares.
28
+ */
29
+ declare const apiClient: <ApiId extends string, Groups extends HttpApiGroup.Any>(api: HttpApi.HttpApi<ApiId, Groups>, options?: ApiClientOptions) => Effect.Effect<HttpApiClient.Client<Groups>, never, HttpApiGroup.MiddlewareClient<Groups>>;
30
+ //#endregion
31
+ export { ApiClientOptions, apiClient };
32
+ //# sourceMappingURL=api-client.d.ts.map
@@ -0,0 +1,44 @@
1
+ import { Effect, Layer } from "effect";
2
+ import * as FetchHttpClient from "effect/unstable/http/FetchHttpClient";
3
+ import * as HttpApiClient from "effect/unstable/httpapi/HttpApiClient";
4
+ //#region src/api-client.ts
5
+ /**
6
+ * A typed client for an Effect [`HttpApi`](https://effect.website) served by
7
+ * {@link Endpoint.fromApi}, closing the serve↔consume loop.
8
+ *
9
+ * {@link apiClient} wraps Effect's own `HttpApiClient.make` and provides the
10
+ * `HttpClient` for you (via `FetchHttpClient`), so a browser or a universal
11
+ * `load` can call the same-origin API with full end-to-end types derived from
12
+ * the shared `HttpApi` definition. In a `load`, pass `event.fetch` so the call
13
+ * participates in SvelteKit's SSR fetch (relative URLs, credentials, dedupe).
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * // src/routes/+page.ts — a universal load
18
+ * import { apiClient } from "@thomasfosterau/effect-sveltekit";
19
+ * import { Effect } from "effect";
20
+ * import { api } from "$lib/api"; // the shared HttpApi definition
21
+ *
22
+ * export const load = (event) =>
23
+ * Effect.gen(function* () {
24
+ * const client = yield* apiClient(api, { baseUrl: "/api", fetch: event.fetch });
25
+ * return { user: yield* client.users.get({ path: { id: event.params.id } }) };
26
+ * });
27
+ * ```
28
+ */
29
+ /**
30
+ * Build a typed {@link HttpApiClient} for `api`, with the `HttpClient` provided
31
+ * via `FetchHttpClient`. Yields the client from an `Effect`; the only remaining
32
+ * requirement is any client middleware the API declares.
33
+ */
34
+ const apiClient = (api, options) => {
35
+ const fetchLayer = options?.fetch === void 0 ? FetchHttpClient.layer : FetchHttpClient.layer.pipe(Layer.provide(Layer.succeed(FetchHttpClient.Fetch, options.fetch)));
36
+ return HttpApiClient.make(api, {
37
+ baseUrl: options?.baseUrl,
38
+ transformClient: options?.transformClient
39
+ }).pipe(Effect.provide(fetchLayer));
40
+ };
41
+ //#endregion
42
+ export { apiClient };
43
+
44
+ //# sourceMappingURL=api-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.js","names":[],"sources":["../src/api-client.ts"],"sourcesContent":["/**\n * A typed client for an Effect [`HttpApi`](https://effect.website) served by\n * {@link Endpoint.fromApi}, closing the serve↔consume loop.\n *\n * {@link apiClient} wraps Effect's own `HttpApiClient.make` and provides the\n * `HttpClient` for you (via `FetchHttpClient`), so a browser or a universal\n * `load` can call the same-origin API with full end-to-end types derived from\n * the shared `HttpApi` definition. In a `load`, pass `event.fetch` so the call\n * participates in SvelteKit's SSR fetch (relative URLs, credentials, dedupe).\n *\n * @example\n * ```ts\n * // src/routes/+page.ts — a universal load\n * import { apiClient } from \"@thomasfosterau/effect-sveltekit\";\n * import { Effect } from \"effect\";\n * import { api } from \"$lib/api\"; // the shared HttpApi definition\n *\n * export const load = (event) =>\n * Effect.gen(function* () {\n * const client = yield* apiClient(api, { baseUrl: \"/api\", fetch: event.fetch });\n * return { user: yield* client.users.get({ path: { id: event.params.id } }) };\n * });\n * ```\n */\n\nimport { Effect, Layer } from \"effect\";\nimport * as FetchHttpClient from \"effect/unstable/http/FetchHttpClient\";\nimport type * as HttpClient from \"effect/unstable/http/HttpClient\";\nimport type * as HttpApi from \"effect/unstable/httpapi/HttpApi\";\nimport * as HttpApiClient from \"effect/unstable/httpapi/HttpApiClient\";\nimport type * as HttpApiGroup from \"effect/unstable/httpapi/HttpApiGroup\";\n\n/** Options for {@link apiClient}. */\nexport interface ApiClientOptions {\n /**\n * The base URL the API is mounted at. For an `Endpoint.fromApi` mounted at\n * `src/routes/api/[...path]` with `prefix: \"/api\"`, pass `\"/api\"`. Defaults to\n * the endpoint paths relative to the current origin.\n */\n readonly baseUrl?: URL | string;\n /**\n * The `fetch` implementation to use. In a `load`, pass `event.fetch` so the\n * request joins SvelteKit's SSR fetch. Defaults to the platform `fetch`.\n */\n readonly fetch?: typeof globalThis.fetch;\n /** Transform the underlying `HttpClient` (e.g. add headers, retries). */\n readonly transformClient?: (client: HttpClient.HttpClient) => HttpClient.HttpClient;\n}\n\n/**\n * Build a typed {@link HttpApiClient} for `api`, with the `HttpClient` provided\n * via `FetchHttpClient`. Yields the client from an `Effect`; the only remaining\n * requirement is any client middleware the API declares.\n */\nexport const apiClient = <ApiId extends string, Groups extends HttpApiGroup.Any>(\n api: HttpApi.HttpApi<ApiId, Groups>,\n options?: ApiClientOptions,\n): Effect.Effect<HttpApiClient.Client<Groups>, never, HttpApiGroup.MiddlewareClient<Groups>> => {\n const fetchLayer =\n options?.fetch === undefined\n ? FetchHttpClient.layer\n : FetchHttpClient.layer.pipe(\n Layer.provide(Layer.succeed(FetchHttpClient.Fetch, options.fetch)),\n );\n\n return HttpApiClient.make(api, {\n baseUrl: options?.baseUrl,\n transformClient: options?.transformClient,\n }).pipe(Effect.provide(fetchLayer));\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsDA,MAAa,aACX,KACA,YAC8F;CAC9F,MAAM,aACJ,SAAS,UAAU,KAAA,IACf,gBAAgB,QAChB,gBAAgB,MAAM,KACpB,MAAM,QAAQ,MAAM,QAAQ,gBAAgB,OAAO,QAAQ,KAAK,CAAC,CACnE;CAEN,OAAO,cAAc,KAAK,KAAK;EAC7B,SAAS,SAAS;EAClB,iBAAiB,SAAS;CAC5B,CAAC,EAAE,KAAK,OAAO,QAAQ,UAAU,CAAC;AACpC"}
@@ -1,6 +1,7 @@
1
1
  import { SvelteRouteParams } from "./internal/route-params.js";
2
2
  import { SvelteKitRequestEvent } from "./runtime.js";
3
3
  import { ErrorTranslator } from "./request-runtime.js";
4
+ import { SvelteKitCookies, SvelteKitLocals, SvelteKitResponseHeaders } from "./request-services.js";
4
5
  import { Effect, Exit, Fiber, Layer, ManagedRuntime } from "effect";
5
6
  import * as HttpClient from "effect/unstable/http/HttpClient";
6
7
  import { Action, Actions, Handle, HandleFetch, HandleServerError, Load, RequestEvent, ServerInit, ServerLoad } from "@sveltejs/kit";
@@ -10,7 +11,7 @@ import { Action, Actions, Handle, HandleFetch, HandleServerError, Load, RequestE
10
11
  * The services provided to every wrapped effect on the server, in addition to
11
12
  * the application's own layer.
12
13
  */
13
- type SvelteKitServices = HttpClient.HttpClient | SvelteKitRequestEvent;
14
+ type SvelteKitServices = HttpClient.HttpClient | SvelteKitRequestEvent | SvelteKitCookies | SvelteKitResponseHeaders | SvelteKitLocals;
14
15
  /**
15
16
  * A per-request Effect runtime: the application layer's services plus the
16
17
  * per-request {@link SvelteKitServices} (an `HttpClient` backed by the request's
@@ -1,5 +1,6 @@
1
1
  import { SvelteKitRequestEvent } from "./runtime.js";
2
- import { causeToThrowable } from "./internal/error.js";
2
+ import { SvelteKit } from "./kit.js";
3
+ import { SvelteKitCookies, SvelteKitLocals, SvelteKitResponseHeaders, requestServicesFrom } from "./request-services.js";
3
4
  import { Effect, Exit, Layer, ManagedRuntime, Scope } from "effect";
4
5
  import * as FetchHttpClient from "effect/unstable/http/FetchHttpClient";
5
6
  //#region src/app-runtime.ts
@@ -12,7 +13,10 @@ const RequestRuntimeKey = Symbol.for("@thomasfosterau/effect-sveltekit/requestRu
12
13
  /** Read the per-request runtime entry an event carries, if any. */
13
14
  const requestRuntimeEntry = (event) => event.locals?.[RequestRuntimeKey];
14
15
  /** Layer with the per-request services for a server-side request. */
15
- const requestLayer = (event) => Layer.merge(FetchHttpClient.layer.pipe(Layer.provide(Layer.succeed(FetchHttpClient.Fetch, event.fetch))), Layer.succeed(SvelteKitRequestEvent, event));
16
+ const requestLayer = (event) => {
17
+ const services = requestServicesFrom(event);
18
+ return Layer.mergeAll(FetchHttpClient.layer.pipe(Layer.provide(Layer.succeed(FetchHttpClient.Fetch, event.fetch))), Layer.succeed(SvelteKitRequestEvent, event), Layer.succeed(SvelteKitCookies, services.cookies), Layer.succeed(SvelteKitResponseHeaders, services.responseHeaders), Layer.succeed(SvelteKitLocals, services.locals));
19
+ };
16
20
  /** Layer providing `HttpClient` backed by an arbitrary fetch implementation. */
17
21
  const fetchLayer = (fetchFn) => FetchHttpClient.layer.pipe(Layer.provide(Layer.succeed(FetchHttpClient.Fetch, fetchFn)));
18
22
  /** Build a settle that returns a success value or throws via the translator. */
@@ -20,10 +24,8 @@ const makeSettle = (translate) => (exit) => Exit.match(exit, {
20
24
  onFailure: (cause) => translate(cause),
21
25
  onSuccess: (value) => value
22
26
  });
23
- /** The default settle: SvelteKit control flow through, anything else a 500. */
24
- const settle = makeSettle((cause) => {
25
- throw causeToThrowable(cause);
26
- });
27
+ /** The default settle: Kit control-flow errors through, anything else a 500. */
28
+ const settle = makeSettle(SvelteKit.translate);
27
29
  /**
28
30
  * Creates a {@link ServerRuntime} from an application layer.
29
31
  *
@@ -85,7 +87,7 @@ const makeServerRuntime = (layer, options) => {
85
87
  return runtime.runPromiseExit(provided);
86
88
  };
87
89
  const run = (event, effect) => runExit(event, effect).then(settleRequest);
88
- const action = (fn) => (event) => run(event, fn(event));
90
+ const action = (fn) => (event) => run(event, fn(event).pipe(Effect.withSpan(`action ${event.route.id ?? "(unknown)"}`, { kind: "server" })));
89
91
  /**
90
92
  * The `handle` hook: build a per-request runtime, store it on `event.locals`
91
93
  * so every other wrapper (and the user's own code) runs on it, run the user's
@@ -100,14 +102,14 @@ const makeServerRuntime = (layer, options) => {
100
102
  };
101
103
  event.locals[RequestRuntimeKey] = entry;
102
104
  try {
103
- return await entry.runtime.runPromise(fn(input));
105
+ return await entry.runtime.runPromise(fn(input).pipe(Effect.withSpan(`handle ${event.route.id ?? "(unknown)"}`, { kind: "server" })));
104
106
  } finally {
105
107
  await runtime.runPromise(Scope.close(scope, Exit.void));
106
108
  }
107
109
  };
108
110
  return {
109
111
  runtime,
110
- serverLoad: (fn) => (event) => run(event, fn(event)),
112
+ serverLoad: (fn) => (event) => run(event, fn(event).pipe(Effect.withSpan(`serverLoad ${event.route.id ?? "(unknown)"}`, { kind: "server" }))),
111
113
  action,
112
114
  actions: (actionsMap) => {
113
115
  const wrapped = {};
@@ -115,13 +117,13 @@ const makeServerRuntime = (layer, options) => {
115
117
  return wrapped;
116
118
  },
117
119
  handle,
118
- handleFetch: (fn) => (args) => run(args.event, fn(args)),
120
+ handleFetch: (fn) => (args) => run(args.event, fn(args).pipe(Effect.withSpan(`handleFetch ${args.event.route.id ?? "(unknown)"}`, { kind: "server" }))),
119
121
  handleError: (fn) => (args) => run(args.event, fn(args)),
120
122
  init: (effect) => async () => {
121
123
  settleRequest(await runtime.runPromiseExit(effect));
122
124
  },
123
125
  requestRuntime: requestRuntimeOf,
124
- endpoint: (fn) => (event) => run(event, fn(event)),
126
+ endpoint: (fn) => (event) => run(event, fn(event).pipe(Effect.withSpan(`${event.request.method} ${event.route.id ?? "(unknown)"}`, { kind: "server" }))),
125
127
  runPromise: run,
126
128
  runPromiseExit: runExit,
127
129
  dispose: () => runtime.dispose()
@@ -1 +1 @@
1
- {"version":3,"file":"app-runtime.js","names":[],"sources":["../src/app-runtime.ts"],"sourcesContent":["/**\n * App-wide Effect runtimes for SvelteKit.\n *\n * `makeServerRuntime` / `makeUniversalRuntime` let an application define its\n * Effect services (database clients, API wrappers, config, ...) as a single\n * `Layer`, built once per server process and shared by every request, instead\n * of being rebuilt for each `load` / `action` / endpoint invocation.\n *\n * Per-request services — the {@link SvelteKitRequestEvent} and an `HttpClient`\n * backed by the event's `fetch` — are provided on top of the shared runtime\n * for each call, so SvelteKit's fetch behaviours (cookie forwarding, request\n * deduplication, relative URLs) keep working as expected.\n */\n\nimport type {\n Action,\n Actions,\n Handle,\n HandleFetch,\n HandleServerError,\n Load,\n RequestEvent,\n ServerInit,\n ServerLoad,\n} from \"@sveltejs/kit\";\nimport { Context, Effect, type Fiber, Exit, Layer, ManagedRuntime, Scope } from \"effect\";\nimport * as FetchHttpClient from \"effect/unstable/http/FetchHttpClient\";\nimport type * as HttpClient from \"effect/unstable/http/HttpClient\";\nimport { SvelteKitRequestEvent } from \"./runtime.js\";\nimport type { SvelteRouteParams } from \"./internal/route-params.js\";\nimport { causeToThrowable } from \"./internal/error.js\";\nimport type { ErrorTranslator } from \"./request-runtime.js\";\n\n/**\n * The services provided to every wrapped effect on the server, in addition to\n * the application's own layer.\n */\nexport type SvelteKitServices = HttpClient.HttpClient | SvelteKitRequestEvent;\n\n/**\n * A per-request Effect runtime: the application layer's services plus the\n * per-request {@link SvelteKitServices} (an `HttpClient` backed by the request's\n * `fetch`, and the {@link SvelteKitRequestEvent}), with the request services\n * built once for the request and shared.\n *\n * A {@link ServerRuntime}'s `handle` hook creates one per request and stores it\n * on `event.locals` (`App.Locals`). Every other wrapper for the same runtime\n * (`serverLoad`, `action`, `endpoint`, ...) then runs on it, so a request's\n * effects share one `HttpClient` and one request scope. Retrieve it from an\n * event with `ServerRuntime.requestRuntime` to run your own effects.\n */\nexport interface RequestRuntime<R = never> {\n /** Run an effect for this request, returning its `Exit`. */\n readonly runPromiseExit: <A>(\n effect: Effect.Effect<A, unknown, R | SvelteKitServices>,\n ) => Promise<Exit.Exit<A, unknown>>;\n /** Run an effect for this request, throwing on failure (passing SvelteKit control flow through). */\n readonly runPromise: <A>(effect: Effect.Effect<A, unknown, R | SvelteKitServices>) => Promise<A>;\n /** Fork an effect for this request, returning the running fiber. */\n readonly runFork: <A>(\n effect: Effect.Effect<A, unknown, R | SvelteKitServices>,\n ) => Fiber.Fiber<A, unknown>;\n}\n\n/**\n * Symbol under which a {@link ServerRuntime}'s `handle` stores the per-request\n * {@link RequestRuntime} on `event.locals`. `Symbol.for` so the key is stable\n * across module instances.\n */\nconst RequestRuntimeKey: unique symbol = Symbol.for(\n \"@thomasfosterau/effect-sveltekit/requestRuntime\",\n);\n\n/**\n * The locals entry: the per-request runtime tagged with the `ServerRuntime`\n * that created it, so a different runtime's wrappers ignore it (and fall back\n * to building request services themselves) rather than running on the wrong\n * application layer.\n */\ninterface RequestRuntimeEntry {\n readonly owner: object;\n readonly runtime: RequestRuntime<any>;\n}\n\n/** Read the per-request runtime entry an event carries, if any. */\nconst requestRuntimeEntry = (event: RequestEvent): RequestRuntimeEntry | undefined =>\n (event.locals as Record<PropertyKey, unknown> | undefined)?.[RequestRuntimeKey] as\n | RequestRuntimeEntry\n | undefined;\n\n/** Layer with the per-request services for a server-side request. */\nconst requestLayer = (event: RequestEvent): Layer.Layer<SvelteKitServices> =>\n Layer.merge(\n FetchHttpClient.layer.pipe(Layer.provide(Layer.succeed(FetchHttpClient.Fetch, event.fetch))),\n Layer.succeed(SvelteKitRequestEvent, event),\n );\n\n/** Layer providing `HttpClient` backed by an arbitrary fetch implementation. */\nconst fetchLayer = (fetchFn: typeof globalThis.fetch): Layer.Layer<HttpClient.HttpClient> =>\n FetchHttpClient.layer.pipe(Layer.provide(Layer.succeed(FetchHttpClient.Fetch, fetchFn)));\n\n/** Build a settle that returns a success value or throws via the translator. */\nconst makeSettle =\n (translate: ErrorTranslator) =>\n <A>(exit: Exit.Exit<A, unknown>): A =>\n Exit.match(exit, {\n onFailure: (cause) => translate(cause),\n onSuccess: (value) => value,\n });\n\n/** The default settle: SvelteKit control flow through, anything else a 500. */\nconst settle = makeSettle((cause) => {\n throw causeToThrowable(cause);\n});\n\n/**\n * Options for {@link makeServerRuntime}.\n */\nexport interface ServerRuntimeOptions {\n /**\n * Translate a failed `Cause` into SvelteKit control flow at the boundary of\n * every wrapper (`serverLoad`, `action`, `actions`, `endpoint`, `handle`,\n * `handleFetch`, `handleError`, `init`). It may throw `redirect()` /\n * `error()` so a domain error catalogue surfaces as SvelteKit control flow\n * instead of a generic 500. Defaults to the package passthrough: SvelteKit's\n * own `redirect()` / `error()` are rethrown, anything else becomes an\n * `EffectCauseError` (a 500).\n */\n readonly translateError?: ErrorTranslator;\n}\n\n/**\n * A server-side Effect runtime bound to an application layer.\n *\n * Produced by {@link makeServerRuntime}. The wrapper methods mirror the\n * standalone helpers in `@thomasfosterau/effect-sveltekit/server`, but\n * effects additionally have access to the services `R` of the application\n * layer.\n */\nexport interface ServerRuntime<R = never, E = never> {\n /** The underlying managed runtime for the application layer. */\n readonly runtime: ManagedRuntime.ManagedRuntime<R, E>;\n\n /**\n * Wraps an Effect-based function as a SvelteKit server `load`.\n */\n readonly serverLoad: <\n Params extends SvelteRouteParams = SvelteRouteParams,\n ParentData extends Record<string, any> = any,\n OutputData extends Record<string, any> | void = any,\n RouteId extends string | null = any,\n >(\n fn: (\n event: RequestEvent<Params, RouteId>,\n ) => Effect.Effect<OutputData, unknown, R | SvelteKitServices>,\n ) => ServerLoad<Params, ParentData, OutputData, RouteId>;\n\n /**\n * Wraps an Effect-based function as a SvelteKit form action.\n */\n readonly action: <\n Params extends SvelteRouteParams = SvelteRouteParams,\n OutputData extends Record<string, any> | void = any,\n RouteId extends string | null = any,\n >(\n fn: (\n event: RequestEvent<Params, RouteId>,\n ) => Effect.Effect<OutputData, unknown, R | SvelteKitServices>,\n ) => Action<Params, OutputData, RouteId>;\n\n /**\n * Wraps an object of Effect-based form actions.\n */\n readonly actions: <\n Params extends SvelteRouteParams = SvelteRouteParams,\n OutputData extends Record<string, any> | void = any,\n RouteId extends string | null = any,\n >(\n actionsMap: Record<\n string,\n (\n event: RequestEvent<Params, RouteId>,\n ) => Effect.Effect<OutputData, unknown, R | SvelteKitServices>\n >,\n ) => Actions<Params, OutputData, RouteId>;\n\n /**\n * Wraps an Effect-based function as a SvelteKit `handle` hook.\n */\n readonly handle: (\n fn: (args: Parameters<Handle>[0]) => Effect.Effect<Response, unknown, R | SvelteKitServices>,\n ) => Handle;\n\n /**\n * Wraps an Effect-based function as a SvelteKit server `handleFetch` hook,\n * which intercepts `event.fetch` calls made on the server. The effect runs\n * with the per-request services on top of the application layer and produces\n * the `Response` to use.\n */\n readonly handleFetch: (\n fn: (\n args: Parameters<HandleFetch>[0],\n ) => Effect.Effect<Response, unknown, R | SvelteKitServices>,\n ) => HandleFetch;\n\n /**\n * Wraps an Effect-based function as a SvelteKit server `handleError` hook.\n *\n * The effect receives the error and the request event, and produces the\n * shape that SvelteKit exposes to the client (your `App.Error`, or nothing).\n * It runs with the per-request services on top of the application layer.\n */\n readonly handleError: (\n fn: (\n args: Parameters<HandleServerError>[0],\n ) => Effect.Effect<Awaited<ReturnType<HandleServerError>>, unknown, R | SvelteKitServices>,\n ) => HandleServerError;\n\n /**\n * Wraps an Effect as a SvelteKit server `init` hook, run once before the\n * server responds to its first request. There is no request event, so the\n * effect only has access to the application layer's services.\n */\n readonly init: (effect: Effect.Effect<void, unknown, R>) => ServerInit;\n\n /**\n * The per-request {@link RequestRuntime} this runtime's `handle` stored on the\n * event, or `undefined` when `handle` was not used for the request. Use it to\n * run your own effects on the same per-request runtime (shared `HttpClient`\n * and request scope) that `serverLoad` / `action` / `endpoint` use.\n *\n * @example\n * ```ts\n * // anywhere with the request event, e.g. another `handle` in the sequence\n * const rt = runtime.requestRuntime(event);\n * await rt?.runPromise(Effect.gen(function* () {\n * const user = yield* Auth.currentUser;\n * event.locals.user = user;\n * }));\n * ```\n */\n readonly requestRuntime: (event: RequestEvent) => RequestRuntime<R> | undefined;\n\n /**\n * Wraps an Effect-based function as a SvelteKit `+server.ts` endpoint\n * handler (`GET`, `POST`, ...).\n */\n readonly endpoint: <\n Params extends SvelteRouteParams = SvelteRouteParams,\n RouteId extends string | null = any,\n >(\n fn: (\n event: RequestEvent<Params, RouteId>,\n ) => Effect.Effect<Response, unknown, R | SvelteKitServices>,\n ) => (event: RequestEvent<Params, RouteId>) => Promise<Response>;\n\n /**\n * Runs an effect for a specific request, providing both the application\n * layer and the per-request services. Failures (other than SvelteKit\n * control flow) are thrown as `EffectCauseError`.\n */\n readonly runPromise: <A>(\n event: RequestEvent,\n effect: Effect.Effect<A, unknown, R | SvelteKitServices>,\n ) => Promise<A>;\n\n /**\n * Runs an effect for a specific request and returns the Exit, without\n * translating failures into thrown errors.\n */\n readonly runPromiseExit: <A>(\n event: RequestEvent,\n effect: Effect.Effect<A, unknown, R | SvelteKitServices>,\n ) => Promise<Exit.Exit<A, unknown>>;\n\n /**\n * Disposes the underlying managed runtime, running the layer's finalizers.\n * Call this on server shutdown or in tests.\n */\n readonly dispose: () => Promise<void>;\n}\n\n/**\n * Creates a {@link ServerRuntime} from an application layer.\n *\n * The layer is built lazily on first use and shared by all requests for the\n * lifetime of the server process. Define it once in a server-only module and\n * import its wrappers from your routes:\n *\n * @example\n * ```ts\n * // src/lib/server/runtime.ts\n * import { makeServerRuntime } from '@thomasfosterau/effect-sveltekit/server';\n * import { Layer } from 'effect';\n * import { Database } from './database';\n *\n * export const runtime = makeServerRuntime(Database.layer);\n * ```\n *\n * ```ts\n * // src/routes/items/+page.server.ts\n * import { runtime } from '$lib/server/runtime';\n * import { Effect } from 'effect';\n * import { Database } from '$lib/server/database';\n *\n * export const load = runtime.serverLoad((event) =>\n * Effect.gen(function* () {\n * const db = yield* Database;\n * return { items: yield* db.listItems() };\n * })\n * );\n * ```\n *\n * Note that the application layer is built outside of any request, so its\n * services cannot depend on the per-request `SvelteKitRequestEvent` or\n * `HttpClient`. Request-specific data should be passed to service methods as\n * arguments instead.\n */\nexport const makeServerRuntime = <R = never, E = never>(\n layer?: Layer.Layer<R, E>,\n options?: ServerRuntimeOptions,\n): ServerRuntime<R, E> => {\n const runtime = ManagedRuntime.make((layer ?? Layer.empty) as Layer.Layer<R, E>);\n\n // The boundary translator for this runtime's wrappers (defaults to the\n // package passthrough: SvelteKit control flow through, anything else a 500).\n const settleRequest = options?.translateError ? makeSettle(options.translateError) : settle;\n\n // Identity token tagging the per-request runtimes this runtime creates, so a\n // different runtime's wrappers don't run on the wrong application layer.\n const owner = {};\n\n /** A {@link ScopedRequestRuntime} that provides the prebuilt request services. */\n const makeRequestRuntime = (\n requestServices: Context.Context<SvelteKitServices>,\n ): RequestRuntime<R> => {\n const provide = <A>(effect: Effect.Effect<A, unknown, R | SvelteKitServices>) =>\n Effect.provideContext(effect, requestServices) as Effect.Effect<A, unknown, R>;\n return {\n runPromiseExit: (effect) =>\n runtime.runPromiseExit(provide(effect)) as Promise<Exit.Exit<any, unknown>>,\n runPromise: (effect) => runtime.runPromiseExit(provide(effect)).then(settleRequest),\n runFork: (effect) => runtime.runFork(provide(effect)) as Fiber.Fiber<any, unknown>,\n };\n };\n\n /** The per-request runtime for this runtime carried by the event, if any. */\n const requestRuntimeOf = (event: RequestEvent): RequestRuntime<R> | undefined => {\n const entry = requestRuntimeEntry(event);\n return entry?.owner === owner ? (entry.runtime as RequestRuntime<R>) : undefined;\n };\n\n const runExit = <A>(\n event: RequestEvent,\n effect: Effect.Effect<A, unknown, R | SvelteKitServices>,\n ): Promise<Exit.Exit<A, unknown>> => {\n // Reuse the per-request runtime `handle` installed, if any; otherwise build\n // the per-request services for this single call.\n const requestRuntime = requestRuntimeOf(event);\n if (requestRuntime !== undefined) return requestRuntime.runPromiseExit(effect);\n const provided = Effect.provide(effect, requestLayer(event)) as Effect.Effect<A, unknown, R>;\n return runtime.runPromiseExit(provided) as Promise<Exit.Exit<A, unknown>>;\n };\n\n const run = <A>(\n event: RequestEvent,\n effect: Effect.Effect<A, unknown, R | SvelteKitServices>,\n ): Promise<A> => runExit(event, effect).then(settleRequest);\n\n const action: ServerRuntime<R, E>[\"action\"] = (fn) => (event) => run(event, fn(event));\n\n /**\n * The `handle` hook: build a per-request runtime, store it on `event.locals`\n * so every other wrapper (and the user's own code) runs on it, run the user's\n * effect, then close the request scope.\n */\n const handle: ServerRuntime<R, E>[\"handle\"] = (fn) => async (input) => {\n const { event } = input;\n const scope = Scope.makeUnsafe();\n const requestServices = (await runtime.runPromise(\n Layer.buildWithScope(requestLayer(event), scope),\n )) as Context.Context<SvelteKitServices>;\n\n const entry: RequestRuntimeEntry = { owner, runtime: makeRequestRuntime(requestServices) };\n (event.locals as Record<PropertyKey, unknown>)[RequestRuntimeKey] = entry;\n\n try {\n return await (entry.runtime as RequestRuntime<R>).runPromise(fn(input));\n } finally {\n await runtime.runPromise(Scope.close(scope, Exit.void));\n }\n };\n\n return {\n runtime,\n serverLoad: (fn) => (event) => run(event, fn(event)),\n action,\n actions: (actionsMap) => {\n const wrapped: Record<string, Action<any, any, any>> = {};\n for (const [key, fn] of Object.entries(actionsMap)) {\n wrapped[key] = action(fn);\n }\n return wrapped as never;\n },\n handle,\n handleFetch: (fn) => (args) => run(args.event, fn(args)),\n handleError: (fn) => (args) => run(args.event, fn(args)),\n init: (effect) => async () => {\n // `init` runs outside of any request, so it executes directly on the\n // application runtime without the per-request layer.\n settleRequest(await runtime.runPromiseExit(effect));\n },\n requestRuntime: requestRuntimeOf,\n endpoint: (fn) => (event) => run(event, fn(event)),\n runPromise: run,\n runPromiseExit: runExit,\n dispose: () => runtime.dispose(),\n };\n};\n\n/**\n * A universal (client + server) Effect runtime bound to an application layer.\n *\n * Produced by {@link makeUniversalRuntime}. Because universal `load`\n * functions also run in the browser, the layer must only use services that\n * work in both environments.\n */\nexport interface UniversalRuntime<R = never, E = never> {\n /** The underlying managed runtime for the application layer. */\n readonly runtime: ManagedRuntime.ManagedRuntime<R, E>;\n\n /**\n * Wraps an Effect-based function as a SvelteKit universal `load`.\n *\n * The effect gets `HttpClient` (backed by the load event's `fetch`) on both\n * client and server, plus the services of the application layer.\n */\n readonly load: <\n Params extends SvelteRouteParams = SvelteRouteParams,\n InputData extends Record<string, unknown> | null = any,\n ParentData extends Record<string, unknown> = any,\n OutputData extends Record<string, unknown> | void = any,\n RouteId extends string | null = any,\n >(\n fn: (\n event: Parameters<Load<Params, InputData, ParentData, OutputData, RouteId>>[0],\n ) => Effect.Effect<OutputData, unknown, R | HttpClient.HttpClient>,\n ) => Load<Params, InputData, ParentData, OutputData, RouteId>;\n\n /**\n * Runs an effect with `HttpClient` backed by the given fetch implementation\n * plus the application layer.\n */\n readonly runPromise: <A>(\n fetchFn: typeof globalThis.fetch,\n effect: Effect.Effect<A, unknown, R | HttpClient.HttpClient>,\n ) => Promise<A>;\n\n /**\n * Disposes the underlying managed runtime, running the layer's finalizers.\n */\n readonly dispose: () => Promise<void>;\n}\n\n/**\n * Creates a {@link UniversalRuntime} from an application layer.\n *\n * @example\n * ```ts\n * // src/lib/runtime.ts\n * import { makeUniversalRuntime } from '@thomasfosterau/effect-sveltekit';\n * import { ApiClient } from '$lib/api';\n *\n * export const runtime = makeUniversalRuntime(ApiClient.layer);\n * ```\n *\n * ```ts\n * // src/routes/+page.ts\n * import { runtime } from '$lib/runtime';\n * import { Effect } from 'effect';\n * import { ApiClient } from '$lib/api';\n *\n * export const load = runtime.load((event) =>\n * Effect.gen(function* () {\n * const api = yield* ApiClient;\n * return { stories: yield* api.topStories() };\n * })\n * );\n * ```\n */\nexport const makeUniversalRuntime = <R = never, E = never>(\n layer?: Layer.Layer<R, E>,\n): UniversalRuntime<R, E> => {\n const runtime = ManagedRuntime.make((layer ?? Layer.empty) as Layer.Layer<R, E>);\n\n const run = <A>(\n fetchFn: typeof globalThis.fetch,\n effect: Effect.Effect<A, unknown, R | HttpClient.HttpClient>,\n event?: RequestEvent,\n ): Promise<A> => {\n // On the server the full request layer (HttpClient + SvelteKitRequestEvent)\n // is available; on the client only HttpClient backed by the event's fetch.\n const services = event ? requestLayer(event) : fetchLayer(fetchFn);\n const provided = Effect.provide(effect, services) as Effect.Effect<A, unknown, R>;\n return runtime.runPromiseExit(provided).then(settle);\n };\n\n return {\n runtime,\n load: (fn) => (event) => {\n const serverEvent = (event as { request?: unknown }).request\n ? (event as unknown as RequestEvent)\n : undefined;\n return run(event.fetch, fn(event), serverEvent);\n },\n runPromise: (fetchFn, effect) => run(fetchFn, effect),\n dispose: () => runtime.dispose(),\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"app-runtime.js","names":[],"sources":["../src/app-runtime.ts"],"sourcesContent":["/**\n * App-wide Effect runtimes for SvelteKit.\n *\n * `makeServerRuntime` / `makeUniversalRuntime` let an application define its\n * Effect services (database clients, API wrappers, config, ...) as a single\n * `Layer`, built once per server process and shared by every request, instead\n * of being rebuilt for each `load` / `action` / endpoint invocation.\n *\n * Per-request services — the {@link SvelteKitRequestEvent} and an `HttpClient`\n * backed by the event's `fetch` — are provided on top of the shared runtime\n * for each call, so SvelteKit's fetch behaviours (cookie forwarding, request\n * deduplication, relative URLs) keep working as expected.\n */\n\nimport type {\n Action,\n Actions,\n Handle,\n HandleFetch,\n HandleServerError,\n Load,\n RequestEvent,\n ServerInit,\n ServerLoad,\n} from \"@sveltejs/kit\";\nimport { Context, Effect, type Fiber, Exit, Layer, ManagedRuntime, Scope } from \"effect\";\nimport * as FetchHttpClient from \"effect/unstable/http/FetchHttpClient\";\nimport type * as HttpClient from \"effect/unstable/http/HttpClient\";\nimport { SvelteKitRequestEvent } from \"./runtime.js\";\nimport type { SvelteRouteParams } from \"./internal/route-params.js\";\nimport type { ErrorTranslator } from \"./request-runtime.js\";\nimport { SvelteKit } from \"./kit.js\";\nimport {\n SvelteKitCookies,\n SvelteKitLocals,\n SvelteKitResponseHeaders,\n requestServicesFrom,\n} from \"./request-services.js\";\n\n/**\n * The services provided to every wrapped effect on the server, in addition to\n * the application's own layer.\n */\nexport type SvelteKitServices =\n | HttpClient.HttpClient\n | SvelteKitRequestEvent\n | SvelteKitCookies\n | SvelteKitResponseHeaders\n | SvelteKitLocals;\n\n/**\n * A per-request Effect runtime: the application layer's services plus the\n * per-request {@link SvelteKitServices} (an `HttpClient` backed by the request's\n * `fetch`, and the {@link SvelteKitRequestEvent}), with the request services\n * built once for the request and shared.\n *\n * A {@link ServerRuntime}'s `handle` hook creates one per request and stores it\n * on `event.locals` (`App.Locals`). Every other wrapper for the same runtime\n * (`serverLoad`, `action`, `endpoint`, ...) then runs on it, so a request's\n * effects share one `HttpClient` and one request scope. Retrieve it from an\n * event with `ServerRuntime.requestRuntime` to run your own effects.\n */\nexport interface RequestRuntime<R = never> {\n /** Run an effect for this request, returning its `Exit`. */\n readonly runPromiseExit: <A>(\n effect: Effect.Effect<A, unknown, R | SvelteKitServices>,\n ) => Promise<Exit.Exit<A, unknown>>;\n /** Run an effect for this request, throwing on failure (passing SvelteKit control flow through). */\n readonly runPromise: <A>(effect: Effect.Effect<A, unknown, R | SvelteKitServices>) => Promise<A>;\n /** Fork an effect for this request, returning the running fiber. */\n readonly runFork: <A>(\n effect: Effect.Effect<A, unknown, R | SvelteKitServices>,\n ) => Fiber.Fiber<A, unknown>;\n}\n\n/**\n * Symbol under which a {@link ServerRuntime}'s `handle` stores the per-request\n * {@link RequestRuntime} on `event.locals`. `Symbol.for` so the key is stable\n * across module instances.\n */\nconst RequestRuntimeKey: unique symbol = Symbol.for(\n \"@thomasfosterau/effect-sveltekit/requestRuntime\",\n);\n\n/**\n * The locals entry: the per-request runtime tagged with the `ServerRuntime`\n * that created it, so a different runtime's wrappers ignore it (and fall back\n * to building request services themselves) rather than running on the wrong\n * application layer.\n */\ninterface RequestRuntimeEntry {\n readonly owner: object;\n readonly runtime: RequestRuntime<any>;\n}\n\n/** Read the per-request runtime entry an event carries, if any. */\nconst requestRuntimeEntry = (event: RequestEvent): RequestRuntimeEntry | undefined =>\n (event.locals as Record<PropertyKey, unknown> | undefined)?.[RequestRuntimeKey] as\n | RequestRuntimeEntry\n | undefined;\n\n/** Layer with the per-request services for a server-side request. */\nconst requestLayer = (event: RequestEvent): Layer.Layer<SvelteKitServices> => {\n const services = requestServicesFrom(event);\n return Layer.mergeAll(\n FetchHttpClient.layer.pipe(Layer.provide(Layer.succeed(FetchHttpClient.Fetch, event.fetch))),\n Layer.succeed(SvelteKitRequestEvent, event),\n Layer.succeed(SvelteKitCookies, services.cookies),\n Layer.succeed(SvelteKitResponseHeaders, services.responseHeaders),\n Layer.succeed(SvelteKitLocals, services.locals),\n );\n};\n\n/** Layer providing `HttpClient` backed by an arbitrary fetch implementation. */\nconst fetchLayer = (fetchFn: typeof globalThis.fetch): Layer.Layer<HttpClient.HttpClient> =>\n FetchHttpClient.layer.pipe(Layer.provide(Layer.succeed(FetchHttpClient.Fetch, fetchFn)));\n\n/** Build a settle that returns a success value or throws via the translator. */\nconst makeSettle =\n (translate: ErrorTranslator) =>\n <A>(exit: Exit.Exit<A, unknown>): A =>\n Exit.match(exit, {\n onFailure: (cause) => translate(cause),\n onSuccess: (value) => value,\n });\n\n/** The default settle: Kit control-flow errors through, anything else a 500. */\nconst settle = makeSettle(SvelteKit.translate);\n\n/**\n * Options for {@link makeServerRuntime}.\n */\nexport interface ServerRuntimeOptions {\n /**\n * Translate a failed `Cause` into SvelteKit control flow at the boundary of\n * every wrapper (`serverLoad`, `action`, `actions`, `endpoint`, `handle`,\n * `handleFetch`, `handleError`, `init`). It may throw `redirect()` /\n * `error()` so a domain error catalogue surfaces as SvelteKit control flow\n * instead of a generic 500. Defaults to the package passthrough: SvelteKit's\n * own `redirect()` / `error()` are rethrown, anything else becomes an\n * `EffectCauseError` (a 500).\n */\n readonly translateError?: ErrorTranslator;\n}\n\n/**\n * A server-side Effect runtime bound to an application layer.\n *\n * Produced by {@link makeServerRuntime}. The wrapper methods mirror the\n * standalone helpers in `@thomasfosterau/effect-sveltekit/server`, but\n * effects additionally have access to the services `R` of the application\n * layer.\n */\nexport interface ServerRuntime<R = never, E = never> {\n /** The underlying managed runtime for the application layer. */\n readonly runtime: ManagedRuntime.ManagedRuntime<R, E>;\n\n /**\n * Wraps an Effect-based function as a SvelteKit server `load`.\n */\n readonly serverLoad: <\n Params extends SvelteRouteParams = SvelteRouteParams,\n ParentData extends Record<string, any> = any,\n OutputData extends Record<string, any> | void = any,\n RouteId extends string | null = any,\n >(\n fn: (\n event: RequestEvent<Params, RouteId>,\n ) => Effect.Effect<OutputData, unknown, R | SvelteKitServices>,\n ) => ServerLoad<Params, ParentData, OutputData, RouteId>;\n\n /**\n * Wraps an Effect-based function as a SvelteKit form action.\n */\n readonly action: <\n Params extends SvelteRouteParams = SvelteRouteParams,\n OutputData extends Record<string, any> | void = any,\n RouteId extends string | null = any,\n >(\n fn: (\n event: RequestEvent<Params, RouteId>,\n ) => Effect.Effect<OutputData, unknown, R | SvelteKitServices>,\n ) => Action<Params, OutputData, RouteId>;\n\n /**\n * Wraps an object of Effect-based form actions.\n */\n readonly actions: <\n Params extends SvelteRouteParams = SvelteRouteParams,\n OutputData extends Record<string, any> | void = any,\n RouteId extends string | null = any,\n >(\n actionsMap: Record<\n string,\n (\n event: RequestEvent<Params, RouteId>,\n ) => Effect.Effect<OutputData, unknown, R | SvelteKitServices>\n >,\n ) => Actions<Params, OutputData, RouteId>;\n\n /**\n * Wraps an Effect-based function as a SvelteKit `handle` hook.\n */\n readonly handle: (\n fn: (args: Parameters<Handle>[0]) => Effect.Effect<Response, unknown, R | SvelteKitServices>,\n ) => Handle;\n\n /**\n * Wraps an Effect-based function as a SvelteKit server `handleFetch` hook,\n * which intercepts `event.fetch` calls made on the server. The effect runs\n * with the per-request services on top of the application layer and produces\n * the `Response` to use.\n */\n readonly handleFetch: (\n fn: (\n args: Parameters<HandleFetch>[0],\n ) => Effect.Effect<Response, unknown, R | SvelteKitServices>,\n ) => HandleFetch;\n\n /**\n * Wraps an Effect-based function as a SvelteKit server `handleError` hook.\n *\n * The effect receives the error and the request event, and produces the\n * shape that SvelteKit exposes to the client (your `App.Error`, or nothing).\n * It runs with the per-request services on top of the application layer.\n */\n readonly handleError: (\n fn: (\n args: Parameters<HandleServerError>[0],\n ) => Effect.Effect<Awaited<ReturnType<HandleServerError>>, unknown, R | SvelteKitServices>,\n ) => HandleServerError;\n\n /**\n * Wraps an Effect as a SvelteKit server `init` hook, run once before the\n * server responds to its first request. There is no request event, so the\n * effect only has access to the application layer's services.\n */\n readonly init: (effect: Effect.Effect<void, unknown, R>) => ServerInit;\n\n /**\n * The per-request {@link RequestRuntime} this runtime's `handle` stored on the\n * event, or `undefined` when `handle` was not used for the request. Use it to\n * run your own effects on the same per-request runtime (shared `HttpClient`\n * and request scope) that `serverLoad` / `action` / `endpoint` use.\n *\n * @example\n * ```ts\n * // anywhere with the request event, e.g. another `handle` in the sequence\n * const rt = runtime.requestRuntime(event);\n * await rt?.runPromise(Effect.gen(function* () {\n * const user = yield* Auth.currentUser;\n * event.locals.user = user;\n * }));\n * ```\n */\n readonly requestRuntime: (event: RequestEvent) => RequestRuntime<R> | undefined;\n\n /**\n * Wraps an Effect-based function as a SvelteKit `+server.ts` endpoint\n * handler (`GET`, `POST`, ...).\n */\n readonly endpoint: <\n Params extends SvelteRouteParams = SvelteRouteParams,\n RouteId extends string | null = any,\n >(\n fn: (\n event: RequestEvent<Params, RouteId>,\n ) => Effect.Effect<Response, unknown, R | SvelteKitServices>,\n ) => (event: RequestEvent<Params, RouteId>) => Promise<Response>;\n\n /**\n * Runs an effect for a specific request, providing both the application\n * layer and the per-request services. Failures (other than SvelteKit\n * control flow) are thrown as `EffectCauseError`.\n */\n readonly runPromise: <A>(\n event: RequestEvent,\n effect: Effect.Effect<A, unknown, R | SvelteKitServices>,\n ) => Promise<A>;\n\n /**\n * Runs an effect for a specific request and returns the Exit, without\n * translating failures into thrown errors.\n */\n readonly runPromiseExit: <A>(\n event: RequestEvent,\n effect: Effect.Effect<A, unknown, R | SvelteKitServices>,\n ) => Promise<Exit.Exit<A, unknown>>;\n\n /**\n * Disposes the underlying managed runtime, running the layer's finalizers.\n * Call this on server shutdown or in tests.\n */\n readonly dispose: () => Promise<void>;\n}\n\n/**\n * Creates a {@link ServerRuntime} from an application layer.\n *\n * The layer is built lazily on first use and shared by all requests for the\n * lifetime of the server process. Define it once in a server-only module and\n * import its wrappers from your routes:\n *\n * @example\n * ```ts\n * // src/lib/server/runtime.ts\n * import { makeServerRuntime } from '@thomasfosterau/effect-sveltekit/server';\n * import { Layer } from 'effect';\n * import { Database } from './database';\n *\n * export const runtime = makeServerRuntime(Database.layer);\n * ```\n *\n * ```ts\n * // src/routes/items/+page.server.ts\n * import { runtime } from '$lib/server/runtime';\n * import { Effect } from 'effect';\n * import { Database } from '$lib/server/database';\n *\n * export const load = runtime.serverLoad((event) =>\n * Effect.gen(function* () {\n * const db = yield* Database;\n * return { items: yield* db.listItems() };\n * })\n * );\n * ```\n *\n * Note that the application layer is built outside of any request, so its\n * services cannot depend on the per-request `SvelteKitRequestEvent` or\n * `HttpClient`. Request-specific data should be passed to service methods as\n * arguments instead.\n */\nexport const makeServerRuntime = <R = never, E = never>(\n layer?: Layer.Layer<R, E>,\n options?: ServerRuntimeOptions,\n): ServerRuntime<R, E> => {\n const runtime = ManagedRuntime.make((layer ?? Layer.empty) as Layer.Layer<R, E>);\n\n // The boundary translator for this runtime's wrappers (defaults to the\n // package passthrough: SvelteKit control flow through, anything else a 500).\n const settleRequest = options?.translateError ? makeSettle(options.translateError) : settle;\n\n // Identity token tagging the per-request runtimes this runtime creates, so a\n // different runtime's wrappers don't run on the wrong application layer.\n const owner = {};\n\n /** A {@link ScopedRequestRuntime} that provides the prebuilt request services. */\n const makeRequestRuntime = (\n requestServices: Context.Context<SvelteKitServices>,\n ): RequestRuntime<R> => {\n const provide = <A>(effect: Effect.Effect<A, unknown, R | SvelteKitServices>) =>\n Effect.provideContext(effect, requestServices) as Effect.Effect<A, unknown, R>;\n return {\n runPromiseExit: (effect) =>\n runtime.runPromiseExit(provide(effect)) as Promise<Exit.Exit<any, unknown>>,\n runPromise: (effect) => runtime.runPromiseExit(provide(effect)).then(settleRequest),\n runFork: (effect) => runtime.runFork(provide(effect)) as Fiber.Fiber<any, unknown>,\n };\n };\n\n /** The per-request runtime for this runtime carried by the event, if any. */\n const requestRuntimeOf = (event: RequestEvent): RequestRuntime<R> | undefined => {\n const entry = requestRuntimeEntry(event);\n return entry?.owner === owner ? (entry.runtime as RequestRuntime<R>) : undefined;\n };\n\n const runExit = <A>(\n event: RequestEvent,\n effect: Effect.Effect<A, unknown, R | SvelteKitServices>,\n ): Promise<Exit.Exit<A, unknown>> => {\n // Reuse the per-request runtime `handle` installed, if any; otherwise build\n // the per-request services for this single call.\n const requestRuntime = requestRuntimeOf(event);\n if (requestRuntime !== undefined) return requestRuntime.runPromiseExit(effect);\n const provided = Effect.provide(effect, requestLayer(event)) as Effect.Effect<A, unknown, R>;\n return runtime.runPromiseExit(provided) as Promise<Exit.Exit<A, unknown>>;\n };\n\n const run = <A>(\n event: RequestEvent,\n effect: Effect.Effect<A, unknown, R | SvelteKitServices>,\n ): Promise<A> => runExit(event, effect).then(settleRequest);\n\n const action: ServerRuntime<R, E>[\"action\"] = (fn) => (event) =>\n run(\n event,\n fn(event).pipe(\n Effect.withSpan(`action ${event.route.id ?? \"(unknown)\"}`, { kind: \"server\" }),\n ),\n );\n\n /**\n * The `handle` hook: build a per-request runtime, store it on `event.locals`\n * so every other wrapper (and the user's own code) runs on it, run the user's\n * effect, then close the request scope.\n */\n const handle: ServerRuntime<R, E>[\"handle\"] = (fn) => async (input) => {\n const { event } = input;\n const scope = Scope.makeUnsafe();\n const requestServices = (await runtime.runPromise(\n Layer.buildWithScope(requestLayer(event), scope),\n )) as Context.Context<SvelteKitServices>;\n\n const entry: RequestRuntimeEntry = { owner, runtime: makeRequestRuntime(requestServices) };\n (event.locals as Record<PropertyKey, unknown>)[RequestRuntimeKey] = entry;\n\n try {\n return await (entry.runtime as RequestRuntime<R>).runPromise(\n fn(input).pipe(\n Effect.withSpan(`handle ${event.route.id ?? \"(unknown)\"}`, { kind: \"server\" }),\n ),\n );\n } finally {\n await runtime.runPromise(Scope.close(scope, Exit.void));\n }\n };\n\n return {\n runtime,\n serverLoad: (fn) => (event) =>\n run(\n event,\n fn(event).pipe(\n Effect.withSpan(`serverLoad ${event.route.id ?? \"(unknown)\"}`, { kind: \"server\" }),\n ),\n ),\n action,\n actions: (actionsMap) => {\n const wrapped: Record<string, Action<any, any, any>> = {};\n for (const [key, fn] of Object.entries(actionsMap)) {\n wrapped[key] = action(fn);\n }\n return wrapped as never;\n },\n handle,\n handleFetch: (fn) => (args) =>\n run(\n args.event,\n fn(args).pipe(\n Effect.withSpan(`handleFetch ${args.event.route.id ?? \"(unknown)\"}`, { kind: \"server\" }),\n ),\n ),\n handleError: (fn) => (args) => run(args.event, fn(args)),\n init: (effect) => async () => {\n // `init` runs outside of any request, so it executes directly on the\n // application runtime without the per-request layer.\n settleRequest(await runtime.runPromiseExit(effect));\n },\n requestRuntime: requestRuntimeOf,\n endpoint: (fn) => (event) =>\n run(\n event,\n fn(event).pipe(\n Effect.withSpan(`${event.request.method} ${event.route.id ?? \"(unknown)\"}`, {\n kind: \"server\",\n }),\n ),\n ),\n runPromise: run,\n runPromiseExit: runExit,\n dispose: () => runtime.dispose(),\n };\n};\n\n/**\n * A universal (client + server) Effect runtime bound to an application layer.\n *\n * Produced by {@link makeUniversalRuntime}. Because universal `load`\n * functions also run in the browser, the layer must only use services that\n * work in both environments.\n */\nexport interface UniversalRuntime<R = never, E = never> {\n /** The underlying managed runtime for the application layer. */\n readonly runtime: ManagedRuntime.ManagedRuntime<R, E>;\n\n /**\n * Wraps an Effect-based function as a SvelteKit universal `load`.\n *\n * The effect gets `HttpClient` (backed by the load event's `fetch`) on both\n * client and server, plus the services of the application layer.\n */\n readonly load: <\n Params extends SvelteRouteParams = SvelteRouteParams,\n InputData extends Record<string, unknown> | null = any,\n ParentData extends Record<string, unknown> = any,\n OutputData extends Record<string, unknown> | void = any,\n RouteId extends string | null = any,\n >(\n fn: (\n event: Parameters<Load<Params, InputData, ParentData, OutputData, RouteId>>[0],\n ) => Effect.Effect<OutputData, unknown, R | HttpClient.HttpClient>,\n ) => Load<Params, InputData, ParentData, OutputData, RouteId>;\n\n /**\n * Runs an effect with `HttpClient` backed by the given fetch implementation\n * plus the application layer.\n */\n readonly runPromise: <A>(\n fetchFn: typeof globalThis.fetch,\n effect: Effect.Effect<A, unknown, R | HttpClient.HttpClient>,\n ) => Promise<A>;\n\n /**\n * Disposes the underlying managed runtime, running the layer's finalizers.\n */\n readonly dispose: () => Promise<void>;\n}\n\n/**\n * Creates a {@link UniversalRuntime} from an application layer.\n *\n * @example\n * ```ts\n * // src/lib/runtime.ts\n * import { makeUniversalRuntime } from '@thomasfosterau/effect-sveltekit';\n * import { ApiClient } from '$lib/api';\n *\n * export const runtime = makeUniversalRuntime(ApiClient.layer);\n * ```\n *\n * ```ts\n * // src/routes/+page.ts\n * import { runtime } from '$lib/runtime';\n * import { Effect } from 'effect';\n * import { ApiClient } from '$lib/api';\n *\n * export const load = runtime.load((event) =>\n * Effect.gen(function* () {\n * const api = yield* ApiClient;\n * return { stories: yield* api.topStories() };\n * })\n * );\n * ```\n */\nexport const makeUniversalRuntime = <R = never, E = never>(\n layer?: Layer.Layer<R, E>,\n): UniversalRuntime<R, E> => {\n const runtime = ManagedRuntime.make((layer ?? Layer.empty) as Layer.Layer<R, E>);\n\n const run = <A>(\n fetchFn: typeof globalThis.fetch,\n effect: Effect.Effect<A, unknown, R | HttpClient.HttpClient>,\n event?: RequestEvent,\n ): Promise<A> => {\n // On the server the full request layer (HttpClient + SvelteKitRequestEvent)\n // is available; on the client only HttpClient backed by the event's fetch.\n const services = event ? requestLayer(event) : fetchLayer(fetchFn);\n const provided = Effect.provide(effect, services) as Effect.Effect<A, unknown, R>;\n return runtime.runPromiseExit(provided).then(settle);\n };\n\n return {\n runtime,\n load: (fn) => (event) => {\n const serverEvent = (event as { request?: unknown }).request\n ? (event as unknown as RequestEvent)\n : undefined;\n return run(event.fetch, fn(event), serverEvent);\n },\n runPromise: (fetchFn, effect) => run(fetchFn, effect),\n dispose: () => runtime.dispose(),\n };\n};\n"],"mappings":";;;;;;;;;;;AAgFA,MAAM,oBAAmC,OAAO,IAC9C,iDACF;;AAcA,MAAM,uBAAuB,UAC1B,MAAM,SAAsD;;AAK/D,MAAM,gBAAgB,UAAwD;CAC5E,MAAM,WAAW,oBAAoB,KAAK;CAC1C,OAAO,MAAM,SACX,gBAAgB,MAAM,KAAK,MAAM,QAAQ,MAAM,QAAQ,gBAAgB,OAAO,MAAM,KAAK,CAAC,CAAC,GAC3F,MAAM,QAAQ,uBAAuB,KAAK,GAC1C,MAAM,QAAQ,kBAAkB,SAAS,OAAO,GAChD,MAAM,QAAQ,0BAA0B,SAAS,eAAe,GAChE,MAAM,QAAQ,iBAAiB,SAAS,MAAM,CAChD;AACF;;AAGA,MAAM,cAAc,YAClB,gBAAgB,MAAM,KAAK,MAAM,QAAQ,MAAM,QAAQ,gBAAgB,OAAO,OAAO,CAAC,CAAC;;AAGzF,MAAM,cACH,eACG,SACF,KAAK,MAAM,MAAM;CACf,YAAY,UAAU,UAAU,KAAK;CACrC,YAAY,UAAU;AACxB,CAAC;;AAGL,MAAM,SAAS,WAAW,UAAU,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6M7C,MAAa,qBACX,OACA,YACwB;CACxB,MAAM,UAAU,eAAe,KAAM,SAAS,MAAM,KAA2B;CAI/E,MAAM,gBAAgB,SAAS,iBAAiB,WAAW,QAAQ,cAAc,IAAI;CAIrF,MAAM,QAAQ,CAAC;;CAGf,MAAM,sBACJ,oBACsB;EACtB,MAAM,WAAc,WAClB,OAAO,eAAe,QAAQ,eAAe;EAC/C,OAAO;GACL,iBAAiB,WACf,QAAQ,eAAe,QAAQ,MAAM,CAAC;GACxC,aAAa,WAAW,QAAQ,eAAe,QAAQ,MAAM,CAAC,EAAE,KAAK,aAAa;GAClF,UAAU,WAAW,QAAQ,QAAQ,QAAQ,MAAM,CAAC;EACtD;CACF;;CAGA,MAAM,oBAAoB,UAAuD;EAC/E,MAAM,QAAQ,oBAAoB,KAAK;EACvC,OAAO,OAAO,UAAU,QAAS,MAAM,UAAgC,KAAA;CACzE;CAEA,MAAM,WACJ,OACA,WACmC;EAGnC,MAAM,iBAAiB,iBAAiB,KAAK;EAC7C,IAAI,mBAAmB,KAAA,GAAW,OAAO,eAAe,eAAe,MAAM;EAC7E,MAAM,WAAW,OAAO,QAAQ,QAAQ,aAAa,KAAK,CAAC;EAC3D,OAAO,QAAQ,eAAe,QAAQ;CACxC;CAEA,MAAM,OACJ,OACA,WACe,QAAQ,OAAO,MAAM,EAAE,KAAK,aAAa;CAE1D,MAAM,UAAyC,QAAQ,UACrD,IACE,OACA,GAAG,KAAK,EAAE,KACR,OAAO,SAAS,UAAU,MAAM,MAAM,MAAM,eAAe,EAAE,MAAM,SAAS,CAAC,CAC/E,CACF;;;;;;CAOF,MAAM,UAAyC,OAAO,OAAO,UAAU;EACrE,MAAM,EAAE,UAAU;EAClB,MAAM,QAAQ,MAAM,WAAW;EAK/B,MAAM,QAA6B;GAAE;GAAO,SAAS,mBAAmB,MAJzC,QAAQ,WACrC,MAAM,eAAe,aAAa,KAAK,GAAG,KAAK,CACjD,CAEuF;EAAE;EACzF,MAAO,OAAwC,qBAAqB;EAEpE,IAAI;GACF,OAAO,MAAO,MAAM,QAA8B,WAChD,GAAG,KAAK,EAAE,KACR,OAAO,SAAS,UAAU,MAAM,MAAM,MAAM,eAAe,EAAE,MAAM,SAAS,CAAC,CAC/E,CACF;EACF,UAAU;GACR,MAAM,QAAQ,WAAW,MAAM,MAAM,OAAO,KAAK,IAAI,CAAC;EACxD;CACF;CAEA,OAAO;EACL;EACA,aAAa,QAAQ,UACnB,IACE,OACA,GAAG,KAAK,EAAE,KACR,OAAO,SAAS,cAAc,MAAM,MAAM,MAAM,eAAe,EAAE,MAAM,SAAS,CAAC,CACnF,CACF;EACF;EACA,UAAU,eAAe;GACvB,MAAM,UAAiD,CAAC;GACxD,KAAK,MAAM,CAAC,KAAK,OAAO,OAAO,QAAQ,UAAU,GAC/C,QAAQ,OAAO,OAAO,EAAE;GAE1B,OAAO;EACT;EACA;EACA,cAAc,QAAQ,SACpB,IACE,KAAK,OACL,GAAG,IAAI,EAAE,KACP,OAAO,SAAS,eAAe,KAAK,MAAM,MAAM,MAAM,eAAe,EAAE,MAAM,SAAS,CAAC,CACzF,CACF;EACF,cAAc,QAAQ,SAAS,IAAI,KAAK,OAAO,GAAG,IAAI,CAAC;EACvD,OAAO,WAAW,YAAY;GAG5B,cAAc,MAAM,QAAQ,eAAe,MAAM,CAAC;EACpD;EACA,gBAAgB;EAChB,WAAW,QAAQ,UACjB,IACE,OACA,GAAG,KAAK,EAAE,KACR,OAAO,SAAS,GAAG,MAAM,QAAQ,OAAO,GAAG,MAAM,MAAM,MAAM,eAAe,EAC1E,MAAM,SACR,CAAC,CACH,CACF;EACF,YAAY;EACZ,gBAAgB;EAChB,eAAe,QAAQ,QAAQ;CACjC;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwEA,MAAa,wBACX,UAC2B;CAC3B,MAAM,UAAU,eAAe,KAAM,SAAS,MAAM,KAA2B;CAE/E,MAAM,OACJ,SACA,QACA,UACe;EAGf,MAAM,WAAW,QAAQ,aAAa,KAAK,IAAI,WAAW,OAAO;EACjE,MAAM,WAAW,OAAO,QAAQ,QAAQ,QAAQ;EAChD,OAAO,QAAQ,eAAe,QAAQ,EAAE,KAAK,MAAM;CACrD;CAEA,OAAO;EACL;EACA,OAAO,QAAQ,UAAU;GACvB,MAAM,cAAe,MAAgC,UAChD,QACD,KAAA;GACJ,OAAO,IAAI,MAAM,OAAO,GAAG,KAAK,GAAG,WAAW;EAChD;EACA,aAAa,SAAS,WAAW,IAAI,SAAS,MAAM;EACpD,eAAe,QAAQ,QAAQ;CACjC;AACF"}
package/dist/client.d.ts CHANGED
@@ -2,5 +2,7 @@ import { Navigation_d_exports } from "./Navigation.js";
2
2
  import { State_d_exports } from "./State.js";
3
3
  import { Remote_d_exports } from "./Remote.js";
4
4
  import { useRemoteQuery } from "./remote-reactive.js";
5
+ import { realtime_d_exports } from "./realtime.js";
6
+ import { forms_d_exports } from "./forms.js";
5
7
  import { Hooks_d_exports } from "./client/Hooks.js";
6
- export { Hooks_d_exports as Hooks, Navigation_d_exports as Navigation, Remote_d_exports as Remote, State_d_exports as State, useRemoteQuery };
8
+ export { forms_d_exports as Forms, Hooks_d_exports as Hooks, Navigation_d_exports as Navigation, realtime_d_exports as Realtime, Remote_d_exports as Remote, State_d_exports as State, useRemoteQuery };
package/dist/client.js CHANGED
@@ -2,5 +2,7 @@ import { Remote_exports } from "./Remote.js";
2
2
  import { Navigation_exports } from "./Navigation.js";
3
3
  import { State_exports } from "./State.js";
4
4
  import { useRemoteQuery } from "./remote-reactive.js";
5
+ import { realtime_exports } from "./realtime.js";
6
+ import { forms_exports } from "./forms.js";
5
7
  import { Hooks_exports } from "./client/Hooks.js";
6
- export { Hooks_exports as Hooks, Navigation_exports as Navigation, Remote_exports as Remote, State_exports as State, useRemoteQuery };
8
+ export { forms_exports as Forms, Hooks_exports as Hooks, Navigation_exports as Navigation, realtime_exports as Realtime, Remote_exports as Remote, State_exports as State, useRemoteQuery };
package/dist/config.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ConfigProvider, Layer } from "effect";
1
+ import { Config, ConfigProvider, Effect, Layer } from "effect";
2
2
 
3
3
  //#region src/config.d.ts
4
4
  /**
@@ -12,6 +12,37 @@ declare const sveltekitConfigProvider: (env: Record<string, string | undefined>)
12
12
  * application layer's `Config` reads resolve from SvelteKit's environment.
13
13
  */
14
14
  declare const sveltekitConfig: (env: Record<string, string | undefined>) => Layer.Layer<never>;
15
+ /**
16
+ * Read a typed {@link Config} value directly from a SvelteKit env record, in
17
+ * one call — the typed bridge for reading configuration without wiring a
18
+ * provider into a runtime first.
19
+ *
20
+ * Which `$env` module you pass decides *when* the value is resolved:
21
+ *
22
+ * - `$env/static/public` / `$env/static/private` are **build-time** — inlined
23
+ * and fixed for the deployment (public values are safe in client bundles).
24
+ * - `$env/dynamic/public` / `$env/dynamic/private` are **runtime** — read from
25
+ * the process environment per request, so they can change between deploys of
26
+ * the same build.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * // Build-time public config (usable on the client)
31
+ * import { env } from "$env/static/public";
32
+ * import { readConfig } from "@thomasfosterau/effect-sveltekit";
33
+ * import { Config, Effect } from "effect";
34
+ *
35
+ * const settings = readConfig(
36
+ * env,
37
+ * Config.all({
38
+ * apiUrl: Config.string("PUBLIC_API_URL"),
39
+ * analytics: Config.string("PUBLIC_ANALYTICS_KEY").pipe(Config.withDefault("")),
40
+ * }),
41
+ * );
42
+ * // settings: Effect<{ apiUrl: string; analytics: string }, ConfigError>
43
+ * ```
44
+ */
45
+ declare const readConfig: <A>(env: Record<string, string | undefined>, config: Config.Config<A>) => Effect.Effect<A, Config.ConfigError>;
15
46
  //#endregion
16
- export { sveltekitConfig, sveltekitConfigProvider };
47
+ export { readConfig, sveltekitConfig, sveltekitConfigProvider };
17
48
  //# sourceMappingURL=config.d.ts.map
package/dist/config.js CHANGED
@@ -1,4 +1,4 @@
1
- import { ConfigProvider } from "effect";
1
+ import { ConfigProvider, Effect } from "effect";
2
2
  //#region src/config.ts
3
3
  /**
4
4
  * SvelteKit `$env` ⇄ Effect `Config`.
@@ -45,7 +45,38 @@ const sveltekitConfigProvider = (env) => ConfigProvider.fromEnv({ env: definedEn
45
45
  * application layer's `Config` reads resolve from SvelteKit's environment.
46
46
  */
47
47
  const sveltekitConfig = (env) => ConfigProvider.layer(sveltekitConfigProvider(env));
48
+ /**
49
+ * Read a typed {@link Config} value directly from a SvelteKit env record, in
50
+ * one call — the typed bridge for reading configuration without wiring a
51
+ * provider into a runtime first.
52
+ *
53
+ * Which `$env` module you pass decides *when* the value is resolved:
54
+ *
55
+ * - `$env/static/public` / `$env/static/private` are **build-time** — inlined
56
+ * and fixed for the deployment (public values are safe in client bundles).
57
+ * - `$env/dynamic/public` / `$env/dynamic/private` are **runtime** — read from
58
+ * the process environment per request, so they can change between deploys of
59
+ * the same build.
60
+ *
61
+ * @example
62
+ * ```ts
63
+ * // Build-time public config (usable on the client)
64
+ * import { env } from "$env/static/public";
65
+ * import { readConfig } from "@thomasfosterau/effect-sveltekit";
66
+ * import { Config, Effect } from "effect";
67
+ *
68
+ * const settings = readConfig(
69
+ * env,
70
+ * Config.all({
71
+ * apiUrl: Config.string("PUBLIC_API_URL"),
72
+ * analytics: Config.string("PUBLIC_ANALYTICS_KEY").pipe(Config.withDefault("")),
73
+ * }),
74
+ * );
75
+ * // settings: Effect<{ apiUrl: string; analytics: string }, ConfigError>
76
+ * ```
77
+ */
78
+ const readConfig = (env, config) => Effect.provide(config, sveltekitConfig(env));
48
79
  //#endregion
49
- export { sveltekitConfig, sveltekitConfigProvider };
80
+ export { readConfig, sveltekitConfig, sveltekitConfigProvider };
50
81
 
51
82
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","names":[],"sources":["../src/config.ts"],"sourcesContent":["/**\n * SvelteKit `$env` ⇄ Effect `Config`.\n *\n * Effect services read configuration through {@link Config} / a\n * {@link ConfigProvider}, while SvelteKit exposes configuration through its\n * `$env/static/*` and `$env/dynamic/*` virtual modules. These helpers bridge\n * the two: pass a SvelteKit env record and get back a `ConfigProvider` (or a\n * `Layer` that installs it), so any `Config.string(\"DATABASE_URL\")` resolves\n * from SvelteKit's environment.\n *\n * ```ts\n * // src/lib/server/runtime.ts\n * import { env } from \"$env/dynamic/private\";\n * import { sveltekitConfig } from \"@thomasfosterau/effect-sveltekit/server\";\n * import { makeServerRuntime } from \"@thomasfosterau/effect-sveltekit/server\";\n * import { Layer } from \"effect\";\n * import { Database } from \"./database\";\n *\n * export const runtime = makeServerRuntime(\n * // Database.layer reads Config.string(\"DATABASE_URL\"), now backed by $env\n * Database.layer.pipe(Layer.provide(sveltekitConfig(env))),\n * );\n * ```\n *\n * `ConfigProvider.fromEnv` joins/splits path segments on `_`, so nested config\n * (`Config.string(\"HOST\").pipe(...nested(\"DATABASE\"))`) resolves a\n * `DATABASE_HOST` env var just like it does from `process.env`.\n */\n\nimport { ConfigProvider, type Layer } from \"effect\";\n\n/** Drop `undefined` values so the record satisfies `ConfigProvider.fromEnv`. */\nconst definedEntries = (env: Record<string, string | undefined>): Record<string, string> => {\n const out: Record<string, string> = {};\n for (const [key, value] of Object.entries(env)) {\n if (value !== undefined) out[key] = value;\n }\n return out;\n};\n\n/**\n * Creates a {@link ConfigProvider} backed by a SvelteKit env record (e.g. the\n * `env` export of `$env/dynamic/private`, or `import.meta.env`-style objects).\n */\nexport const sveltekitConfigProvider = (\n env: Record<string, string | undefined>,\n): ConfigProvider.ConfigProvider => ConfigProvider.fromEnv({ env: definedEntries(env) });\n\n/**\n * Creates a `Layer` that installs {@link sveltekitConfigProvider} as the\n * ambient config provider. Provide it to a server/universal runtime so the\n * application layer's `Config` reads resolve from SvelteKit's environment.\n */\nexport const sveltekitConfig = (env: Record<string, string | undefined>): Layer.Layer<never> =>\n ConfigProvider.layer(sveltekitConfigProvider(env));\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,MAAM,kBAAkB,QAAoE;CAC1F,MAAM,MAA8B,CAAC;CACrC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,GAAG,GAC3C,IAAI,UAAU,KAAA,GAAW,IAAI,OAAO;CAEtC,OAAO;AACT;;;;;AAMA,MAAa,2BACX,QACkC,eAAe,QAAQ,EAAE,KAAK,eAAe,GAAG,EAAE,CAAC;;;;;;AAOvF,MAAa,mBAAmB,QAC9B,eAAe,MAAM,wBAAwB,GAAG,CAAC"}
1
+ {"version":3,"file":"config.js","names":[],"sources":["../src/config.ts"],"sourcesContent":["/**\n * SvelteKit `$env` ⇄ Effect `Config`.\n *\n * Effect services read configuration through {@link Config} / a\n * {@link ConfigProvider}, while SvelteKit exposes configuration through its\n * `$env/static/*` and `$env/dynamic/*` virtual modules. These helpers bridge\n * the two: pass a SvelteKit env record and get back a `ConfigProvider` (or a\n * `Layer` that installs it), so any `Config.string(\"DATABASE_URL\")` resolves\n * from SvelteKit's environment.\n *\n * ```ts\n * // src/lib/server/runtime.ts\n * import { env } from \"$env/dynamic/private\";\n * import { sveltekitConfig } from \"@thomasfosterau/effect-sveltekit/server\";\n * import { makeServerRuntime } from \"@thomasfosterau/effect-sveltekit/server\";\n * import { Layer } from \"effect\";\n * import { Database } from \"./database\";\n *\n * export const runtime = makeServerRuntime(\n * // Database.layer reads Config.string(\"DATABASE_URL\"), now backed by $env\n * Database.layer.pipe(Layer.provide(sveltekitConfig(env))),\n * );\n * ```\n *\n * `ConfigProvider.fromEnv` joins/splits path segments on `_`, so nested config\n * (`Config.string(\"HOST\").pipe(...nested(\"DATABASE\"))`) resolves a\n * `DATABASE_HOST` env var just like it does from `process.env`.\n */\n\nimport { type Config, ConfigProvider, Effect, type Layer } from \"effect\";\n\n/** Drop `undefined` values so the record satisfies `ConfigProvider.fromEnv`. */\nconst definedEntries = (env: Record<string, string | undefined>): Record<string, string> => {\n const out: Record<string, string> = {};\n for (const [key, value] of Object.entries(env)) {\n if (value !== undefined) out[key] = value;\n }\n return out;\n};\n\n/**\n * Creates a {@link ConfigProvider} backed by a SvelteKit env record (e.g. the\n * `env` export of `$env/dynamic/private`, or `import.meta.env`-style objects).\n */\nexport const sveltekitConfigProvider = (\n env: Record<string, string | undefined>,\n): ConfigProvider.ConfigProvider => ConfigProvider.fromEnv({ env: definedEntries(env) });\n\n/**\n * Creates a `Layer` that installs {@link sveltekitConfigProvider} as the\n * ambient config provider. Provide it to a server/universal runtime so the\n * application layer's `Config` reads resolve from SvelteKit's environment.\n */\nexport const sveltekitConfig = (env: Record<string, string | undefined>): Layer.Layer<never> =>\n ConfigProvider.layer(sveltekitConfigProvider(env));\n\n/**\n * Read a typed {@link Config} value directly from a SvelteKit env record, in\n * one call — the typed bridge for reading configuration without wiring a\n * provider into a runtime first.\n *\n * Which `$env` module you pass decides *when* the value is resolved:\n *\n * - `$env/static/public` / `$env/static/private` are **build-time** — inlined\n * and fixed for the deployment (public values are safe in client bundles).\n * - `$env/dynamic/public` / `$env/dynamic/private` are **runtime** — read from\n * the process environment per request, so they can change between deploys of\n * the same build.\n *\n * @example\n * ```ts\n * // Build-time public config (usable on the client)\n * import { env } from \"$env/static/public\";\n * import { readConfig } from \"@thomasfosterau/effect-sveltekit\";\n * import { Config, Effect } from \"effect\";\n *\n * const settings = readConfig(\n * env,\n * Config.all({\n * apiUrl: Config.string(\"PUBLIC_API_URL\"),\n * analytics: Config.string(\"PUBLIC_ANALYTICS_KEY\").pipe(Config.withDefault(\"\")),\n * }),\n * );\n * // settings: Effect<{ apiUrl: string; analytics: string }, ConfigError>\n * ```\n */\nexport const readConfig = <A>(\n env: Record<string, string | undefined>,\n config: Config.Config<A>,\n): Effect.Effect<A, Config.ConfigError> => Effect.provide(config, sveltekitConfig(env));\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,MAAM,kBAAkB,QAAoE;CAC1F,MAAM,MAA8B,CAAC;CACrC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,GAAG,GAC3C,IAAI,UAAU,KAAA,GAAW,IAAI,OAAO;CAEtC,OAAO;AACT;;;;;AAMA,MAAa,2BACX,QACkC,eAAe,QAAQ,EAAE,KAAK,eAAe,GAAG,EAAE,CAAC;;;;;;AAOvF,MAAa,mBAAmB,QAC9B,eAAe,MAAM,wBAAwB,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCnD,MAAa,cACX,KACA,WACyC,OAAO,QAAQ,QAAQ,gBAAgB,GAAG,CAAC"}
@@ -0,0 +1,30 @@
1
+ import { EnhanceHandlers, EnhanceOptions, EnhanceRuntime, ResultOptions, SubmitInput } from "./internal/enhance.js";
2
+ import { Effect } from "effect";
3
+ import { ActionResult } from "@sveltejs/kit";
4
+
5
+ //#region src/forms.d.ts
6
+ declare namespace forms_d_exports {
7
+ export { EnhanceHandlers, EnhanceOptions, EnhanceRuntime, ResultOptions, SubmitInput, applyAction, deserialize, enhance };
8
+ }
9
+ /**
10
+ * Build a `SubmitFunction` for `use:enhance` from Effect-based handlers.
11
+ *
12
+ * `onSubmit` runs before the request (call `input.cancel()` to abort);
13
+ * `onResult` runs on the response with SvelteKit's `update()`. Omit `onResult`
14
+ * to keep SvelteKit's default behaviour. Pass `{ runtime }` when the handlers
15
+ * require application services.
16
+ */
17
+ declare const enhance: <R = never>(handlers: EnhanceHandlers<R>, options?: EnhanceOptions<R>) => import("@sveltejs/kit").SubmitFunction;
18
+ /**
19
+ * Apply an `ActionResult` to the page (updating `page.form` / `page.status`,
20
+ * resetting the form, etc.) as an Effect. Wraps `$app/forms`' `applyAction`.
21
+ */
22
+ declare const applyAction: <Success extends Record<string, unknown> | undefined = Record<string, unknown>, Failure extends Record<string, unknown> | undefined = Record<string, unknown>>(result: ActionResult<Success, Failure>) => Effect.Effect<void>;
23
+ /**
24
+ * Deserialize a raw form-action response body into an `ActionResult`, as an
25
+ * Effect. Wraps `$app/forms`' `deserialize`; a malformed body fails the effect.
26
+ */
27
+ declare const deserialize: <Success extends Record<string, unknown> | undefined = Record<string, unknown>, Failure extends Record<string, unknown> | undefined = Record<string, unknown>>(result: string) => Effect.Effect<ActionResult<Success, Failure>, unknown>;
28
+ //#endregion
29
+ export { forms_d_exports };
30
+ //# sourceMappingURL=forms.d.ts.map
package/dist/forms.js ADDED
@@ -0,0 +1,66 @@
1
+ import { __exportAll } from "./_virtual/_rolldown/runtime.js";
2
+ import { makeSubmitFunction } from "./internal/enhance.js";
3
+ import { Effect } from "effect";
4
+ import { applyAction, deserialize } from "$app/forms";
5
+ //#region src/forms.ts
6
+ /**
7
+ * Effect bridge for SvelteKit's native form actions
8
+ * ([`$app/forms`](https://svelte.dev/docs/kit/$app-forms)) — the `Forms`
9
+ * namespace of `@thomasfosterau/effect-sveltekit/client`.
10
+ *
11
+ * This complements `Remote.submitForm` (which covers *remote* forms): here the
12
+ * progressive-enhancement `use:enhance` flow for page `actions` is expressed
13
+ * with Effects, and `applyAction` / `deserialize` are wrapped so a hand-rolled
14
+ * `fetch` submission can be finished off inside an Effect pipeline.
15
+ *
16
+ * @example
17
+ * ```svelte
18
+ * <script lang="ts">
19
+ * import { enhance } from '$app/forms';
20
+ * import { Forms } from '@thomasfosterau/effect-sveltekit/client';
21
+ * import { Effect } from 'effect';
22
+ *
23
+ * const submit = Forms.enhance({
24
+ * onSubmit: () => Effect.sync(() => { saving = true; }),
25
+ * onResult: ({ result, update }) =>
26
+ * Effect.gen(function* () {
27
+ * yield* Effect.promise(() => update());
28
+ * saving = false;
29
+ * }),
30
+ * });
31
+ * <\/script>
32
+ *
33
+ * <form method="POST" use:enhance={submit}>...</form>
34
+ * ```
35
+ */
36
+ var forms_exports = /* @__PURE__ */ __exportAll({
37
+ applyAction: () => applyAction$1,
38
+ deserialize: () => deserialize$1,
39
+ enhance: () => enhance
40
+ });
41
+ /**
42
+ * Build a `SubmitFunction` for `use:enhance` from Effect-based handlers.
43
+ *
44
+ * `onSubmit` runs before the request (call `input.cancel()` to abort);
45
+ * `onResult` runs on the response with SvelteKit's `update()`. Omit `onResult`
46
+ * to keep SvelteKit's default behaviour. Pass `{ runtime }` when the handlers
47
+ * require application services.
48
+ */
49
+ const enhance = makeSubmitFunction;
50
+ /**
51
+ * Apply an `ActionResult` to the page (updating `page.form` / `page.status`,
52
+ * resetting the form, etc.) as an Effect. Wraps `$app/forms`' `applyAction`.
53
+ */
54
+ const applyAction$1 = (result) => Effect.promise(() => applyAction(result));
55
+ /**
56
+ * Deserialize a raw form-action response body into an `ActionResult`, as an
57
+ * Effect. Wraps `$app/forms`' `deserialize`; a malformed body fails the effect.
58
+ */
59
+ const deserialize$1 = (result) => Effect.try({
60
+ try: () => deserialize(result),
61
+ catch: (error) => error
62
+ });
63
+ //#endregion
64
+ export { forms_exports };
65
+
66
+ //# sourceMappingURL=forms.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forms.js","names":["applyAction","kitApplyAction","deserialize","kitDeserialize"],"sources":["../src/forms.ts"],"sourcesContent":["/**\n * Effect bridge for SvelteKit's native form actions\n * ([`$app/forms`](https://svelte.dev/docs/kit/$app-forms)) — the `Forms`\n * namespace of `@thomasfosterau/effect-sveltekit/client`.\n *\n * This complements `Remote.submitForm` (which covers *remote* forms): here the\n * progressive-enhancement `use:enhance` flow for page `actions` is expressed\n * with Effects, and `applyAction` / `deserialize` are wrapped so a hand-rolled\n * `fetch` submission can be finished off inside an Effect pipeline.\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { enhance } from '$app/forms';\n * import { Forms } from '@thomasfosterau/effect-sveltekit/client';\n * import { Effect } from 'effect';\n *\n * const submit = Forms.enhance({\n * onSubmit: () => Effect.sync(() => { saving = true; }),\n * onResult: ({ result, update }) =>\n * Effect.gen(function* () {\n * yield* Effect.promise(() => update());\n * saving = false;\n * }),\n * });\n * </script>\n *\n * <form method=\"POST\" use:enhance={submit}>...</form>\n * ```\n */\n\nimport { applyAction as kitApplyAction, deserialize as kitDeserialize } from \"$app/forms\";\nimport type { ActionResult } from \"@sveltejs/kit\";\nimport { Effect } from \"effect\";\nimport { makeSubmitFunction } from \"./internal/enhance.js\";\n\nexport type {\n EnhanceHandlers,\n EnhanceOptions,\n EnhanceRuntime,\n SubmitInput,\n ResultOptions,\n} from \"./internal/enhance.js\";\n\n/**\n * Build a `SubmitFunction` for `use:enhance` from Effect-based handlers.\n *\n * `onSubmit` runs before the request (call `input.cancel()` to abort);\n * `onResult` runs on the response with SvelteKit's `update()`. Omit `onResult`\n * to keep SvelteKit's default behaviour. Pass `{ runtime }` when the handlers\n * require application services.\n */\nexport const enhance = makeSubmitFunction;\n\n/**\n * Apply an `ActionResult` to the page (updating `page.form` / `page.status`,\n * resetting the form, etc.) as an Effect. Wraps `$app/forms`' `applyAction`.\n */\nexport const applyAction = <\n Success extends Record<string, unknown> | undefined = Record<string, unknown>,\n Failure extends Record<string, unknown> | undefined = Record<string, unknown>,\n>(\n result: ActionResult<Success, Failure>,\n): Effect.Effect<void> => Effect.promise(() => kitApplyAction(result));\n\n/**\n * Deserialize a raw form-action response body into an `ActionResult`, as an\n * Effect. Wraps `$app/forms`' `deserialize`; a malformed body fails the effect.\n */\nexport const deserialize = <\n Success extends Record<string, unknown> | undefined = Record<string, unknown>,\n Failure extends Record<string, unknown> | undefined = Record<string, unknown>,\n>(\n result: string,\n): Effect.Effect<ActionResult<Success, Failure>, unknown> =>\n Effect.try({\n try: () => kitDeserialize<Success, Failure>(result),\n catch: (error) => error,\n });\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDA,MAAa,UAAU;;;;;AAMvB,MAAaA,iBAIX,WACwB,OAAO,cAAcC,YAAe,MAAM,CAAC;;;;;AAMrE,MAAaC,iBAIX,WAEA,OAAO,IAAI;CACT,WAAWC,YAAiC,MAAM;CAClD,QAAQ,UAAU;AACpB,CAAC"}
package/dist/index.d.ts CHANGED
@@ -2,5 +2,6 @@ import { Remote_d_exports } from "./Remote.js";
2
2
  import { SvelteKitServices, UniversalRuntime, makeUniversalRuntime } from "./app-runtime.js";
3
3
  import { load } from "./universal.js";
4
4
  import { Hooks_d_exports } from "./Hooks.js";
5
- import { sveltekitConfig, sveltekitConfigProvider } from "./config.js";
6
- export { Hooks_d_exports as Hooks, Remote_d_exports as Remote, type SvelteKitServices, type UniversalRuntime, load, makeUniversalRuntime, sveltekitConfig, sveltekitConfigProvider };
5
+ import { readConfig, sveltekitConfig, sveltekitConfigProvider } from "./config.js";
6
+ import { ApiClientOptions, apiClient } from "./api-client.js";
7
+ export { type ApiClientOptions, Hooks_d_exports as Hooks, Remote_d_exports as Remote, type SvelteKitServices, type UniversalRuntime, apiClient, load, makeUniversalRuntime, readConfig, sveltekitConfig, sveltekitConfigProvider };
package/dist/index.js CHANGED
@@ -2,5 +2,6 @@ import { makeUniversalRuntime } from "./app-runtime.js";
2
2
  import { load } from "./universal.js";
3
3
  import { Remote_exports } from "./Remote.js";
4
4
  import { Hooks_exports } from "./Hooks.js";
5
- import { sveltekitConfig, sveltekitConfigProvider } from "./config.js";
6
- export { Hooks_exports as Hooks, Remote_exports as Remote, load, makeUniversalRuntime, sveltekitConfig, sveltekitConfigProvider };
5
+ import { readConfig, sveltekitConfig, sveltekitConfigProvider } from "./config.js";
6
+ import { apiClient } from "./api-client.js";
7
+ export { Hooks_exports as Hooks, Remote_exports as Remote, apiClient, load, makeUniversalRuntime, readConfig, sveltekitConfig, sveltekitConfigProvider };
@@ -0,0 +1,39 @@
1
+ import { Context, Effect, ManagedRuntime } from "effect";
2
+ import { SubmitFunction } from "@sveltejs/kit";
3
+
4
+ //#region src/internal/enhance.d.ts
5
+ /** The input SvelteKit passes to a `SubmitFunction` before the request is sent. */
6
+ type SubmitInput = Parameters<SubmitFunction>[0];
7
+ /** The result callback a `SubmitFunction` may return, run once the action responds. */
8
+ type ResultCallback = Extract<Awaited<ReturnType<SubmitFunction>>, (...args: never) => unknown>;
9
+ /** The options passed to the result callback (`result`, `update`, ...). */
10
+ type ResultOptions = Parameters<ResultCallback>[0];
11
+ /** A runtime the handler effects can run against (a `Context` or `ManagedRuntime`). */
12
+ type EnhanceRuntime<R> = Context.Context<R> | ManagedRuntime.ManagedRuntime<R, never>;
13
+ /** Effect-based handlers for the two phases of an enhanced form submission. */
14
+ interface EnhanceHandlers<R = never> {
15
+ /**
16
+ * Runs before the request is sent. Call `input.cancel()` to abort the
17
+ * submission (the result phase then never runs). Use for optimistic UI or
18
+ * validation.
19
+ */
20
+ readonly onSubmit?: (input: SubmitInput) => Effect.Effect<void, never, R>;
21
+ /**
22
+ * Runs once the action responds, with the `ActionResult` and SvelteKit's
23
+ * `update()` (which applies the default behaviour — updating `page.form`,
24
+ * resetting the form, invalidating). If omitted, SvelteKit's default
25
+ * behaviour applies automatically.
26
+ */
27
+ readonly onResult?: (options: ResultOptions) => Effect.Effect<void, never, R>;
28
+ }
29
+ /** Options for {@link makeSubmitFunction}. */
30
+ interface EnhanceOptions<R = never> {
31
+ /**
32
+ * The runtime to run the handler effects against. Omit when the handlers
33
+ * require no services (`R = never`); they then run on the default runtime.
34
+ */
35
+ readonly runtime?: EnhanceRuntime<R>;
36
+ }
37
+ //#endregion
38
+ export { EnhanceHandlers, EnhanceOptions, EnhanceRuntime, ResultOptions, SubmitInput };
39
+ //# sourceMappingURL=enhance.d.ts.map
@@ -0,0 +1,24 @@
1
+ import { Context, Effect } from "effect";
2
+ //#region src/internal/enhance.ts
3
+ /** Run an `Effect<A, never, R>` on the given runtime (or the default when none). */
4
+ const runPromiseWith = (runtime) => (effect) => {
5
+ if (runtime === void 0) return Effect.runPromise(effect);
6
+ return Context.isContext(runtime) ? Effect.runPromiseWith(runtime)(effect) : runtime.runPromise(effect);
7
+ };
8
+ /**
9
+ * Build a SvelteKit `SubmitFunction` from Effect-based handlers. See
10
+ * `Forms.enhance` for the public entry point and documentation.
11
+ */
12
+ const makeSubmitFunction = (handlers, options) => {
13
+ const run = runPromiseWith(options?.runtime);
14
+ return async (input) => {
15
+ if (handlers.onSubmit) await run(handlers.onSubmit(input));
16
+ if (!handlers.onResult) return void 0;
17
+ const onResult = handlers.onResult;
18
+ return (resultOptions) => run(onResult(resultOptions));
19
+ };
20
+ };
21
+ //#endregion
22
+ export { makeSubmitFunction };
23
+
24
+ //# sourceMappingURL=enhance.js.map