@thomasfosterau/effect-sveltekit 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/LICENSE.md +9 -0
  2. package/README.md +178 -83
  3. package/dist/Hooks.d.ts +3 -3
  4. package/dist/Hooks.js +1 -1
  5. package/dist/Hooks.js.map +1 -1
  6. package/dist/Navigation.d.ts +70 -17
  7. package/dist/Navigation.js +93 -19
  8. package/dist/Navigation.js.map +1 -1
  9. package/dist/Remote.d.ts +54 -35
  10. package/dist/Remote.js +22 -11
  11. package/dist/Remote.js.map +1 -1
  12. package/dist/State.d.ts +79 -6
  13. package/dist/State.js +117 -27
  14. package/dist/State.js.map +1 -1
  15. package/dist/adapter/assets.d.ts +24 -7
  16. package/dist/adapter/assets.js +58 -37
  17. package/dist/adapter/assets.js.map +1 -1
  18. package/dist/adapter/handler.d.ts +27 -12
  19. package/dist/adapter/handler.js +53 -26
  20. package/dist/adapter/handler.js.map +1 -1
  21. package/dist/adapter/index.d.ts +3 -3
  22. package/dist/adapter/index.js +1 -1
  23. package/dist/adapter/index.js.map +1 -1
  24. package/dist/adapter/serve.d.ts +6 -5
  25. package/dist/adapter/serve.js +3 -1
  26. package/dist/adapter/serve.js.map +1 -1
  27. package/dist/api-client.d.ts +3 -4
  28. package/dist/api-client.js +2 -1
  29. package/dist/api-client.js.map +1 -1
  30. package/dist/app-runtime.d.ts +12 -9
  31. package/dist/app-runtime.js +23 -14
  32. package/dist/app-runtime.js.map +1 -1
  33. package/dist/client/Hooks.d.ts +4 -4
  34. package/dist/client/Hooks.js +2 -1
  35. package/dist/client/Hooks.js.map +1 -1
  36. package/dist/client.d.ts +2 -2
  37. package/dist/config.d.ts +7 -5
  38. package/dist/config.js +5 -34
  39. package/dist/config.js.map +1 -1
  40. package/dist/errors.d.ts +14 -16
  41. package/dist/errors.js +20 -12
  42. package/dist/errors.js.map +1 -1
  43. package/dist/forms.d.ts +70 -8
  44. package/dist/forms.js +69 -5
  45. package/dist/forms.js.map +1 -1
  46. package/dist/internal/app-state.d.ts +42 -5
  47. package/dist/internal/app-state.js +64 -15
  48. package/dist/internal/app-state.js.map +1 -1
  49. package/dist/internal/auto.d.ts +23 -14
  50. package/dist/internal/auto.js +50 -40
  51. package/dist/internal/auto.js.map +1 -1
  52. package/dist/internal/enhance.d.ts +114 -14
  53. package/dist/internal/enhance.js +33 -7
  54. package/dist/internal/enhance.js.map +1 -1
  55. package/dist/internal/error.d.ts +13 -0
  56. package/dist/internal/error.js +4 -3
  57. package/dist/internal/error.js.map +1 -1
  58. package/dist/internal/navigation-events.js +3 -1
  59. package/dist/internal/navigation-events.js.map +1 -1
  60. package/dist/internal/remote-run.d.ts +6 -6
  61. package/dist/internal/remote-run.js +13 -16
  62. package/dist/internal/remote-run.js.map +1 -1
  63. package/dist/internal/remote-validators.js +4 -3
  64. package/dist/internal/remote-validators.js.map +1 -1
  65. package/dist/internal/route-params.d.ts +1 -2
  66. package/dist/internal/sse.js +2 -1
  67. package/dist/internal/sse.js.map +1 -1
  68. package/dist/internal/watch.svelte.js +33 -0
  69. package/dist/internal/watch.svelte.js.map +1 -0
  70. package/dist/kit.d.ts +12 -11
  71. package/dist/kit.js +6 -2
  72. package/dist/kit.js.map +1 -1
  73. package/dist/realtime.d.ts +49 -30
  74. package/dist/realtime.js +90 -46
  75. package/dist/realtime.js.map +1 -1
  76. package/dist/remote-functions.d.ts +34 -18
  77. package/dist/remote-functions.js +78 -46
  78. package/dist/remote-functions.js.map +1 -1
  79. package/dist/remote-reactive.d.ts +8 -4
  80. package/dist/remote-reactive.js.map +1 -1
  81. package/dist/request-parse.d.ts +13 -13
  82. package/dist/request-parse.js +29 -15
  83. package/dist/request-parse.js.map +1 -1
  84. package/dist/request-runtime.d.ts +16 -11
  85. package/dist/request-runtime.js +28 -29
  86. package/dist/request-runtime.js.map +1 -1
  87. package/dist/request-services.d.ts +10 -8
  88. package/dist/request-services.js +3 -1
  89. package/dist/request-services.js.map +1 -1
  90. package/dist/response-headers.d.ts +2 -3
  91. package/dist/response-headers.js +2 -1
  92. package/dist/response-headers.js.map +1 -1
  93. package/dist/runtime.d.ts +8 -5
  94. package/dist/runtime.js +4 -1
  95. package/dist/runtime.js.map +1 -1
  96. package/dist/server/Endpoint.d.ts +17 -11
  97. package/dist/server/Endpoint.js +18 -4
  98. package/dist/server/Endpoint.js.map +1 -1
  99. package/dist/server/Hooks.d.ts +6 -6
  100. package/dist/server/Hooks.js +1 -1
  101. package/dist/server/Hooks.js.map +1 -1
  102. package/dist/server.d.ts +8 -7
  103. package/dist/server.js +8 -8
  104. package/dist/server.js.map +1 -1
  105. package/dist/streamed-load.d.ts +2 -3
  106. package/dist/streamed-load.js +1 -1
  107. package/dist/streamed-load.js.map +1 -1
  108. package/dist/testing.d.ts +15 -14
  109. package/dist/testing.js +27 -7
  110. package/dist/testing.js.map +1 -1
  111. package/dist/transport.d.ts +6 -7
  112. package/dist/transport.js +3 -6
  113. package/dist/transport.js.map +1 -1
  114. package/dist/universal.d.ts +3 -3
  115. package/dist/universal.js +1 -1
  116. package/dist/universal.js.map +1 -1
  117. package/dist/vite.d.ts +4 -4
  118. package/dist/vite.js +102 -103
  119. package/dist/vite.js.map +1 -1
  120. package/package.json +14 -11
  121. package/LICENSE +0 -21
@@ -1,11 +1,18 @@
1
- import { AssetSource } from "./assets.js";
2
- import { Config, Effect, Option, Stream } from "effect";
1
+ import { AssetFetchError, AssetSource } from "./assets.js";
2
+ import * as Effect from "effect/Effect";
3
+ import "effect/Context";
4
+ import "effect/Layer";
5
+ import * as Result from "effect/Result";
6
+ import * as Stream from "effect/Stream";
7
+ import * as Schema from "effect/Schema";
3
8
  import * as FileSystem from "effect/FileSystem";
4
9
  import * as Path from "effect/Path";
5
10
  import * as HttpEffect from "effect/http/HttpEffect";
11
+ import * as Option from "effect/Option";
6
12
  import * as HttpMethod from "effect/http/HttpMethod";
7
13
  import * as HttpServerRequest from "effect/http/HttpServerRequest";
8
14
  import * as HttpServerResponse from "effect/http/HttpServerResponse";
15
+ import * as Config from "effect/Config";
9
16
  //#region src/adapter/handler.ts
10
17
  /** Runtime configuration, read from the environment (compatible with adapter-node). */
11
18
  const handlerConfig = (prefix) => Config.all({
@@ -29,20 +36,19 @@ const originOf = (request, config) => {
29
36
  return port ? `${protocol}://${host.split(":")[0]}:${port}` : `${protocol}://${host}`;
30
37
  };
31
38
  /** Resolve the client address, honouring ADDRESS_HEADER / XFF_DEPTH if configured. */
39
+ /**
40
+ * The client address in an `X-Forwarded-For` value: the entry `xffDepth` hops
41
+ * from the right, or the leftmost one when `xffDepth` is out of range.
42
+ */
43
+ const forwardedForAddress = (value, xffDepth) => {
44
+ const addresses = value.split(",").map((address) => address.trim());
45
+ return addresses[xffDepth >= 1 && xffDepth <= addresses.length ? addresses.length - xffDepth : 0] ?? "";
46
+ };
32
47
  const clientAddressOf = (request, config) => {
33
48
  const addressHeader = Option.getOrUndefined(config.addressHeader)?.toLowerCase();
34
- if (addressHeader) {
35
- const value = request.headers[addressHeader];
36
- if (value) {
37
- if (addressHeader === "x-forwarded-for") {
38
- const addresses = value.split(",").map((address) => address.trim());
39
- if (config.xffDepth < 1 || config.xffDepth > addresses.length) return addresses[0] ?? "";
40
- return addresses[addresses.length - config.xffDepth];
41
- }
42
- return value;
43
- }
44
- }
45
- return Option.getOrElse(request.remoteAddress, () => "");
49
+ const value = addressHeader === void 0 ? void 0 : request.headers[addressHeader];
50
+ if (!value) return Option.getOrElse(request.remoteAddress, () => "");
51
+ return addressHeader === "x-forwarded-for" ? forwardedForAddress(value, config.xffDepth) : value;
46
52
  };
47
53
  /** Build a web `Request` for SvelteKit from an `HttpServerRequest`. */
48
54
  const toWebRequest = (request, url, context) => {
@@ -101,6 +107,18 @@ const makeHandler = (options) => Effect.gen(function* () {
101
107
  });
102
108
  });
103
109
  /**
110
+ * The SvelteKit server's `init` or `respond` rejected. SvelteKit turns a
111
+ * route's own errors into responses, so a rejection is a bug in the server
112
+ * build; the handler's error channel is `never`, so this reaches the platform
113
+ * as a DEFECT (a 500), carrying what SvelteKit rejected with as `cause`.
114
+ */
115
+ var SvelteKitServerError = class extends Schema.TaggedError()("SvelteKitServerError", {
116
+ /** Which `Server` method rejected. */
117
+ operation: Schema.Literals(["init", "respond"]),
118
+ /** What the method rejected with, or threw. */
119
+ cause: Schema.Defect()
120
+ }) {};
121
+ /**
104
122
  * The platform-neutral SSR core. Like {@link makeHandler}, but the asset source
105
123
  * and the server-asset `read` capability are injected, so the same SvelteKit
106
124
  * `HttpApp` can run on Node (file-system assets) or on Cloudflare Workers
@@ -133,21 +151,24 @@ const makeHandler = (options) => Effect.gen(function* () {
133
151
  const makeHandlerWith = (options) => Effect.gen(function* () {
134
152
  const config = yield* handlerConfig(options.envPrefix ?? "").pipe(Effect.orDie);
135
153
  const server = options.server;
136
- yield* Effect.promise(() => server.init({
137
- env: options.env ?? {},
138
- read: options.read
139
- }));
154
+ yield* Effect.tryPromise({
155
+ try: () => server.init({
156
+ env: options.env ?? {},
157
+ read: options.read
158
+ }),
159
+ catch: (cause) => new SvelteKitServerError({
160
+ operation: "init",
161
+ cause
162
+ })
163
+ }).pipe(Effect.orDie);
140
164
  return Effect.gen(function* () {
141
165
  const request = yield* HttpServerRequest.HttpServerRequest;
142
166
  const requestContext = yield* Effect.context();
143
167
  const origin = originOf(request, config);
144
168
  const url = new URL(request.url, origin);
145
- let pathname;
146
- try {
147
- pathname = decodeURIComponent(url.pathname);
148
- } catch {
149
- return HttpServerResponse.empty({ status: 400 });
150
- }
169
+ const decoded = Result.try(() => decodeURIComponent(url.pathname));
170
+ if (Result.isFailure(decoded)) return HttpServerResponse.empty({ status: 400 });
171
+ const pathname = decoded.success;
151
172
  if (request.method === "GET" || request.method === "HEAD") {
152
173
  const assetRequest = new Request(url, {
153
174
  method: request.method,
@@ -157,7 +178,13 @@ const makeHandlerWith = (options) => Effect.gen(function* () {
157
178
  if (Option.isSome(asset)) return asset.value;
158
179
  }
159
180
  const webRequest = toWebRequest(request, url, requestContext);
160
- const response = yield* Effect.promise(() => server.respond(webRequest, { getClientAddress: () => clientAddressOf(request, config) }));
181
+ const response = yield* Effect.tryPromise({
182
+ try: () => server.respond(webRequest, { getClientAddress: () => clientAddressOf(request, config) }),
183
+ catch: (cause) => new SvelteKitServerError({
184
+ operation: "respond",
185
+ cause
186
+ })
187
+ }).pipe(Effect.orDie);
161
188
  return HttpServerResponse.fromWeb(response);
162
189
  });
163
190
  });
@@ -180,6 +207,6 @@ const toWebHandler = (app, layer) => {
180
207
  return async (request) => (await build())(request);
181
208
  };
182
209
  //#endregion
183
- export { AssetSource, makeHandler, makeHandlerWith, toWebHandler };
210
+ export { AssetFetchError, AssetSource, SvelteKitServerError, makeHandler, makeHandlerWith, toWebHandler };
184
211
 
185
212
  //# sourceMappingURL=handler.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"handler.js","names":[],"sources":["../../src/adapter/handler.ts"],"sourcesContent":["/**\n * Runtime handler for the Effect SvelteKit adapter.\n *\n * `makeHandler` turns a built SvelteKit app (the `server` instance the adapter\n * generates with `builder.generateServerInstance`) into an Effect HTTP application that serves\n * static client assets, prerendered pages, and server-side rendered routes from\n * disk — the Node default.\n *\n * {@link makeHandlerWith} is the platform-neutral core: it takes an injected\n * {@link AssetSource} (where assets come from) and a `read` capability (how to\n * read server assets), so the same SvelteKit `HttpApp` can run on a Node server\n * or on Cloudflare Workers (assets from `env.ASSETS`).\n *\n * The returned app is an ordinary Effect value: it can be served with the\n * generated `build/index.js` entry (see `./serve.js`), mounted inside any\n * existing `effect/http` HTTP server, or converted to a `fetch` handler\n * (see {@link toWebHandler}).\n */\n\nimport type { Server as SvelteKitServer } from \"@sveltejs/kit\";\nimport * as FileSystem from \"effect/FileSystem\";\nimport * as HttpMethod from \"effect/http/HttpMethod\";\nimport * as HttpEffect from \"effect/http/HttpEffect\";\nimport * as HttpServerRequest from \"effect/http/HttpServerRequest\";\nimport * as HttpServerResponse from \"effect/http/HttpServerResponse\";\nimport * as Path from \"effect/Path\";\nimport { Config, Context, Effect, Layer, Option, Stream } from \"effect\";\nimport { AssetSource, type FileSystemAssetServices } from \"./assets.js\";\n\nexport { AssetSource, type FileSystemAssetServices } from \"./assets.js\";\n\n/**\n * The services required by the SvelteKit HTTP application when serving assets\n * from the file system (the Node default). All of them are provided by\n * `NodeHttpServer.layer` from `@effect/platform-node`.\n */\nexport type SvelteKitHttpAppServices = FileSystemAssetServices;\n\n/**\n * The SvelteKit application as a composable Effect HTTP handler: an effect that\n * produces an {@link HttpServerResponse.HttpServerResponse} for the current\n * request. The `HttpServerRequest` is supplied per request by the server. `R`\n * is the asset source's services (defaults to the file-system services).\n */\nexport type SvelteKitHttpApp<R = SvelteKitHttpAppServices> = Effect.Effect<\n HttpServerResponse.HttpServerResponse,\n never,\n R | HttpServerRequest.HttpServerRequest\n>;\n\n/** The SvelteKit build output {@link makeHandler} serves. */\nexport interface SvelteKitHandlerOptions {\n /** The SvelteKit `server` instance exported by the build output (`./server.js`). */\n readonly server: SvelteKitServer;\n /**\n * The application path, including any `paths.base` without its leading\n * slash (`\"_app\"`, or `\"my-app/_app\"` under a base), exported by the build\n * output (`./manifest.js`). Its `immutable/` subtree gets immutable cache\n * headers.\n */\n readonly appPath: string;\n /** The set of prerendered paths exported by the build output (`./manifest.js`). */\n readonly prerendered: ReadonlySet<string>;\n /** The configured `paths.base`, exported by the build output (`./manifest.js`). */\n readonly base: string;\n /** Absolute path of the build output directory (contains `client/`, `server/`, `prerendered/`). */\n readonly dir: string;\n /** Environment variables passed to the SvelteKit server (e.g. `process.env`). */\n readonly env?: Record<string, string | undefined>;\n /** Prefix for the runtime configuration environment variables (ORIGIN, ...). */\n readonly envPrefix?: string;\n}\n\n/** Options for the platform-neutral SSR core, {@link makeHandlerWith}. */\nexport interface SvelteKitNeutralHandlerOptions<RAssets> {\n /** The SvelteKit `server` instance exported by the build output (`./server.js`). */\n readonly server: SvelteKitServer;\n /** Environment variables passed to the SvelteKit server. */\n readonly env?: Record<string, string | undefined> | undefined;\n /** Prefix for the runtime configuration environment variables (ORIGIN, ...). */\n readonly envPrefix?: string | undefined;\n /** Where static client assets and prerendered pages come from. */\n readonly assets: AssetSource<RAssets>;\n /**\n * How to read a server asset (backs `read()` from `$app/server`). On Node\n * this streams from `<dir>/server`; on Workers, back it with the platform's\n * own mechanism.\n */\n readonly read: (file: string) => ReadableStream<Uint8Array>;\n}\n\n/** Runtime configuration, read from the environment (compatible with adapter-node). */\nconst handlerConfig = (prefix: string) =>\n Config.all({\n origin: Config.option(Config.String(`${prefix}ORIGIN`)),\n protocolHeader: Config.option(Config.String(`${prefix}PROTOCOL_HEADER`)),\n hostHeader: Config.option(Config.String(`${prefix}HOST_HEADER`)),\n portHeader: Config.option(Config.String(`${prefix}PORT_HEADER`)),\n addressHeader: Config.option(Config.String(`${prefix}ADDRESS_HEADER`)),\n xffDepth: Config.Int(`${prefix}XFF_DEPTH`).pipe(Config.withDefault(1)),\n });\n\ntype HandlerConfig = Effect.Success<ReturnType<typeof handlerConfig>>;\n\n/** Compute the request origin from configuration and headers (adapter-node semantics). */\nconst originOf = (request: HttpServerRequest.HttpServerRequest, config: HandlerConfig): string => {\n if (Option.isSome(config.origin)) return config.origin.value;\n\n const headers = request.headers;\n const protocolHeader = Option.getOrUndefined(config.protocolHeader)?.toLowerCase();\n const hostHeader = Option.getOrUndefined(config.hostHeader)?.toLowerCase() ?? \"host\";\n const portHeader = Option.getOrUndefined(config.portHeader)?.toLowerCase();\n\n const protocol = (protocolHeader && headers[protocolHeader]) || \"http\";\n const host = headers[hostHeader] ?? \"localhost\";\n const port = portHeader ? headers[portHeader] : undefined;\n\n return port ? `${protocol}://${host.split(\":\")[0]}:${port}` : `${protocol}://${host}`;\n};\n\n/** Resolve the client address, honouring ADDRESS_HEADER / XFF_DEPTH if configured. */\nconst clientAddressOf = (\n request: HttpServerRequest.HttpServerRequest,\n config: HandlerConfig,\n): string => {\n const addressHeader = Option.getOrUndefined(config.addressHeader)?.toLowerCase();\n if (addressHeader) {\n const value = request.headers[addressHeader];\n if (value) {\n if (addressHeader === \"x-forwarded-for\") {\n const addresses = value.split(\",\").map((address) => address.trim());\n if (config.xffDepth < 1 || config.xffDepth > addresses.length) {\n return addresses[0] ?? \"\";\n }\n return addresses[addresses.length - config.xffDepth]!;\n }\n return value;\n }\n }\n return Option.getOrElse(request.remoteAddress, () => \"\");\n};\n\n/** Build a web `Request` for SvelteKit from an `HttpServerRequest`. */\nconst toWebRequest = (\n request: HttpServerRequest.HttpServerRequest,\n url: URL,\n context: Context.Context<never>,\n): Request => {\n // `Headers` is a redactable record-like value; copy the enumerable string\n // entries into a plain record for the web `Request` constructor.\n const init: RequestInit & { duplex?: \"half\" } = {\n method: request.method,\n headers: { ...request.headers },\n };\n if (HttpMethod.hasBody(request.method)) {\n init.body = Stream.toReadableStreamWith(request.stream, context);\n init.duplex = \"half\";\n }\n return new Request(url, init);\n};\n\n/**\n * Creates the SvelteKit HTTP handler.\n *\n * The returned effect initialises the SvelteKit server (running your app's\n * server `init` hook) and yields an HTTP handler that:\n *\n * 1. serves static client assets from `<dir>/client` (with immutable cache\n * headers for hashed build assets),\n * 2. serves prerendered pages from `<dir>/prerendered`,\n * 3. falls back to server-side rendering via the SvelteKit server.\n *\n * @example\n * ```ts\n * // Mounting SvelteKit inside an existing effect/http server:\n * import { handler } from \"./build/handler.js\";\n * import * as HttpServer from \"effect/http/HttpServer\";\n * import { NodeHttpServer, NodeRuntime } from \"@effect/platform-node\";\n * import { Effect, Layer } from \"effect\";\n * import { createServer } from \"node:http\";\n *\n * const serverLayer = Layer.unwrap(\n * Effect.map(handler, (app) => HttpServer.serve(app))\n * ).pipe(Layer.provide(NodeHttpServer.layer(createServer, { port: 3000 })));\n *\n * NodeRuntime.runMain(Layer.launch(serverLayer));\n * ```\n */\nexport const makeHandler = (\n options: SvelteKitHandlerOptions,\n): Effect.Effect<SvelteKitHttpApp, never, SvelteKitHttpAppServices> =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const context = yield* Effect.context<never>();\n\n const serverDir = path.join(options.dir, \"server\");\n\n return yield* makeHandlerWith<SvelteKitHttpAppServices>({\n server: options.server,\n env: options.env,\n envPrefix: options.envPrefix,\n // `read` backs the `read()` helper from `$app/server`, streaming server\n // assets from the build output.\n read: (file) => Stream.toReadableStreamWith(fs.stream(path.join(serverDir, file)), context),\n assets: AssetSource.fileSystem({\n dir: options.dir,\n appPath: options.appPath,\n prerendered: options.prerendered,\n }),\n });\n });\n\n/**\n * The platform-neutral SSR core. Like {@link makeHandler}, but the asset source\n * and the server-asset `read` capability are injected, so the same SvelteKit\n * `HttpApp` can run on Node (file-system assets) or on Cloudflare Workers\n * (`AssetSource.cloudflareAssets(env.ASSETS)`).\n *\n * The returned app:\n *\n * 1. falls through to the injected {@link AssetSource} for static client assets\n * and prerendered pages (GET/HEAD), then\n * 2. server-side renders via the SvelteKit server.\n *\n * @example\n * ```ts\n * // Workers: a fetch handler with assets from env.ASSETS\n * import { makeHandlerWith, AssetSource, toWebHandler } from \"...adapter/handler\";\n * import { server } from \"./server.js\";\n *\n * export default {\n * fetch: (request, env, ctx) =>\n * toWebHandler(\n * makeHandlerWith({\n * server, env,\n * assets: AssetSource.cloudflareAssets(env.ASSETS),\n * read: () => { throw new Error(\"read() not supported on this deployment\"); },\n * }),\n * )(request),\n * };\n * ```\n */\nexport const makeHandlerWith = <RAssets = never>(\n options: SvelteKitNeutralHandlerOptions<RAssets>,\n): Effect.Effect<SvelteKitHttpApp<RAssets>, never, never> =>\n Effect.gen(function* () {\n const config = yield* handlerConfig(options.envPrefix ?? \"\").pipe(Effect.orDie);\n\n // Initialise the SvelteKit server. `read` backs `read()` from `$app/server`.\n const server = options.server;\n yield* Effect.promise(() =>\n server.init({\n env: options.env ?? {},\n read: options.read,\n }),\n );\n\n // The HTTP handler itself, evaluated once per request.\n return Effect.gen(function* () {\n const request = yield* HttpServerRequest.HttpServerRequest;\n const requestContext = yield* Effect.context<never>();\n\n const origin = originOf(request, config);\n const url = new URL(request.url, origin);\n\n let pathname: string;\n try {\n pathname = decodeURIComponent(url.pathname);\n } catch {\n return HttpServerResponse.empty({ status: 400 });\n }\n\n // 1. Static client assets / prerendered pages, via the injected source.\n // Only GET/HEAD reach assets; build a body-less request for the source.\n if (request.method === \"GET\" || request.method === \"HEAD\") {\n const assetRequest = new Request(url, {\n method: request.method,\n headers: { ...request.headers },\n });\n const asset = yield* options.assets.serveAsset(assetRequest, pathname);\n if (Option.isSome(asset)) return asset.value;\n }\n\n // 2. Server-side rendering.\n const webRequest = toWebRequest(request, url, requestContext);\n const response = yield* Effect.promise(() =>\n server.respond(webRequest, {\n getClientAddress: () => clientAddressOf(request, config),\n }),\n );\n return HttpServerResponse.fromWeb(response);\n });\n });\n\n/**\n * Convert a SvelteKit `HttpApp` to a Web `fetch` handler, providing the asset\n * source's services with `layer`. Use this for a Workers `fetch` export or any\n * runtime that speaks the Web platform.\n *\n * @example\n * ```ts\n * const fetchHandler = toWebHandler(\n * makeHandlerWith({ ..., assets: AssetSource.cloudflareAssets(env.ASSETS) }),\n * Layer.empty,\n * );\n * ```\n */\nexport const toWebHandler = <RAssets, E>(\n app: Effect.Effect<SvelteKitHttpApp<RAssets>, never, never>,\n layer: Layer.Layer<RAssets, E>,\n): ((request: Request) => Promise<Response>) => {\n // Build the app (server.init) and the per-request web handler once, lazily on\n // the first request, then dispatch each request through it.\n let built: Promise<(request: Request) => Promise<Response>> | undefined;\n const build = (): Promise<(request: Request) => Promise<Response>> =>\n (built ??= Effect.runPromise(app).then(\n (inner) =>\n HttpEffect.toWebHandlerLayer(inner, layer).handler as (\n request: Request,\n ) => Promise<Response>,\n ));\n return async (request) => (await build())(request);\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"handler.js","names":[],"sources":["../../src/adapter/handler.ts"],"sourcesContent":["/**\n * Runtime handler for the Effect SvelteKit adapter.\n *\n * `makeHandler` turns a built SvelteKit app (the `server` instance the adapter\n * generates with `builder.generateServerInstance`) into an Effect HTTP application that serves\n * static client assets, prerendered pages, and server-side rendered routes from\n * disk — the Node default.\n *\n * {@link makeHandlerWith} is the platform-neutral core: it takes an injected\n * {@link AssetSource} (where assets come from) and a `read` capability (how to\n * read server assets), so the same SvelteKit `HttpApp` can run on a Node server\n * or on Cloudflare Workers (assets from `env.ASSETS`).\n *\n * The returned app is an ordinary Effect value: it can be served with the\n * generated `build/index.js` entry (see `./serve.js`), mounted inside any\n * existing `effect/http` HTTP server, or converted to a `fetch` handler\n * (see {@link toWebHandler}).\n */\n\nimport type { Server as SvelteKitServer } from \"@sveltejs/kit\";\nimport * as FileSystem from \"effect/FileSystem\";\nimport * as HttpMethod from \"effect/http/HttpMethod\";\nimport * as HttpEffect from \"effect/http/HttpEffect\";\nimport * as HttpServerRequest from \"effect/http/HttpServerRequest\";\nimport * as HttpServerResponse from \"effect/http/HttpServerResponse\";\nimport * as Path from \"effect/Path\";\nimport * as Config from \"effect/Config\";\nimport * as Context from \"effect/Context\";\nimport * as Effect from \"effect/Effect\";\nimport * as Layer from \"effect/Layer\";\nimport * as Option from \"effect/Option\";\nimport * as Result from \"effect/Result\";\nimport * as Schema from \"effect/Schema\";\nimport * as Stream from \"effect/Stream\";\nimport { AssetSource, type FileSystemAssetServices } from \"./assets.js\";\n\nexport { AssetFetchError, AssetSource, type FileSystemAssetServices } from \"./assets.js\";\n\n/**\n * The services required by the SvelteKit HTTP application when serving assets\n * from the file system (the Node default). All of them are provided by\n * `NodeHttpServer.layer` from `@effect/platform-node`.\n */\nexport type SvelteKitHttpAppServices = FileSystemAssetServices;\n\n/**\n * The SvelteKit application as a composable Effect HTTP handler: an effect that\n * produces an {@link HttpServerResponse.HttpServerResponse} for the current\n * request. The `HttpServerRequest` is supplied per request by the server. `R`\n * is the asset source's services (defaults to the file-system services).\n */\nexport type SvelteKitHttpApp<R = SvelteKitHttpAppServices> = Effect.Effect<\n HttpServerResponse.HttpServerResponse,\n never,\n R | HttpServerRequest.HttpServerRequest\n>;\n\n/** The SvelteKit build output {@link makeHandler} serves. */\nexport interface SvelteKitHandlerOptions {\n /** The SvelteKit `server` instance exported by the build output (`./server.js`). */\n readonly server: SvelteKitServer;\n /**\n * The application path, including any `paths.base` without its leading\n * slash (`\"_app\"`, or `\"my-app/_app\"` under a base), exported by the build\n * output (`./manifest.js`). Its `immutable/` subtree gets immutable cache\n * headers.\n */\n readonly appPath: string;\n /** The prerendered paths exported by the build output (`./manifest.js`'s `Set`, or any iterable). */\n readonly prerendered: Iterable<string>;\n /** The configured `paths.base`, exported by the build output (`./manifest.js`). */\n readonly base: string;\n /** Absolute path of the build output directory (contains `client/`, `server/`, `prerendered/`). */\n readonly dir: string;\n /** Environment variables passed to the SvelteKit server (e.g. `process.env`). */\n readonly env?: Record<string, string | undefined>;\n /** Prefix for the runtime configuration environment variables (ORIGIN, ...). */\n readonly envPrefix?: string;\n}\n\n/** Options for the platform-neutral SSR core, {@link makeHandlerWith}. */\nexport interface SvelteKitNeutralHandlerOptions<RAssets> {\n /** The SvelteKit `server` instance exported by the build output (`./server.js`). */\n readonly server: SvelteKitServer;\n /** Environment variables passed to the SvelteKit server. */\n readonly env?: Record<string, string | undefined> | undefined;\n /** Prefix for the runtime configuration environment variables (ORIGIN, ...). */\n readonly envPrefix?: string | undefined;\n /** Where static client assets and prerendered pages come from. */\n readonly assets: AssetSource<RAssets>;\n /**\n * How to read a server asset (backs `read()` from `$app/server`). On Node\n * this streams from `<dir>/server`; on Workers, back it with the platform's\n * own mechanism.\n */\n readonly read: (file: string) => ReadableStream<Uint8Array>;\n}\n\n/** Runtime configuration, read from the environment (compatible with adapter-node). */\nconst handlerConfig = (prefix: string) =>\n Config.all({\n origin: Config.option(Config.String(`${prefix}ORIGIN`)),\n protocolHeader: Config.option(Config.String(`${prefix}PROTOCOL_HEADER`)),\n hostHeader: Config.option(Config.String(`${prefix}HOST_HEADER`)),\n portHeader: Config.option(Config.String(`${prefix}PORT_HEADER`)),\n addressHeader: Config.option(Config.String(`${prefix}ADDRESS_HEADER`)),\n xffDepth: Config.Int(`${prefix}XFF_DEPTH`).pipe(Config.withDefault(1)),\n });\n\ntype HandlerConfig = Effect.Success<ReturnType<typeof handlerConfig>>;\n\n/** Compute the request origin from configuration and headers (adapter-node semantics). */\nconst originOf = (request: HttpServerRequest.HttpServerRequest, config: HandlerConfig): string => {\n if (Option.isSome(config.origin)) return config.origin.value;\n\n const headers = request.headers;\n const protocolHeader = Option.getOrUndefined(config.protocolHeader)?.toLowerCase();\n const hostHeader = Option.getOrUndefined(config.hostHeader)?.toLowerCase() ?? \"host\";\n const portHeader = Option.getOrUndefined(config.portHeader)?.toLowerCase();\n\n const protocol = (protocolHeader && headers[protocolHeader]) || \"http\";\n const host = headers[hostHeader] ?? \"localhost\";\n const port = portHeader ? headers[portHeader] : undefined;\n\n return port ? `${protocol}://${host.split(\":\")[0]}:${port}` : `${protocol}://${host}`;\n};\n\n/** Resolve the client address, honouring ADDRESS_HEADER / XFF_DEPTH if configured. */\n/**\n * The client address in an `X-Forwarded-For` value: the entry `xffDepth` hops\n * from the right, or the leftmost one when `xffDepth` is out of range.\n */\nconst forwardedForAddress = (value: string, xffDepth: number): string => {\n const addresses = value.split(\",\").map((address) => address.trim());\n const inRange = xffDepth >= 1 && xffDepth <= addresses.length;\n return addresses[inRange ? addresses.length - xffDepth : 0] ?? \"\";\n};\n\nconst clientAddressOf = (\n request: HttpServerRequest.HttpServerRequest,\n config: HandlerConfig,\n): string => {\n const addressHeader = Option.getOrUndefined(config.addressHeader)?.toLowerCase();\n const value = addressHeader === undefined ? undefined : request.headers[addressHeader];\n if (!value) return Option.getOrElse(request.remoteAddress, () => \"\");\n return addressHeader === \"x-forwarded-for\" ? forwardedForAddress(value, config.xffDepth) : value;\n};\n\n/** Build a web `Request` for SvelteKit from an `HttpServerRequest`. */\nconst toWebRequest = (\n request: HttpServerRequest.HttpServerRequest,\n url: URL,\n context: Context.Context<never>,\n): Request => {\n // `Headers` is a redactable record-like value; copy the enumerable string\n // entries into a plain record for the web `Request` constructor.\n const init: RequestInit & { duplex?: \"half\" } = {\n method: request.method,\n headers: { ...request.headers },\n };\n if (HttpMethod.hasBody(request.method)) {\n init.body = Stream.toReadableStreamWith(request.stream, context);\n init.duplex = \"half\";\n }\n return new Request(url, init);\n};\n\n/**\n * Creates the SvelteKit HTTP handler.\n *\n * The returned effect initialises the SvelteKit server (running your app's\n * server `init` hook) and yields an HTTP handler that:\n *\n * 1. serves static client assets from `<dir>/client` (with immutable cache\n * headers for hashed build assets),\n * 2. serves prerendered pages from `<dir>/prerendered`,\n * 3. falls back to server-side rendering via the SvelteKit server.\n *\n * @example\n * ```ts\n * // Mounting SvelteKit inside an existing effect/http server:\n * import { handler } from \"./build/handler.js\";\n * import * as HttpServer from \"effect/http/HttpServer\";\n * import { NodeHttpServer, NodeRuntime } from \"@effect/platform-node\";\n * import { Effect, Layer } from \"effect\";\n * import { createServer } from \"node:http\";\n *\n * const serverLayer = Layer.unwrap(\n * Effect.map(handler, (app) => HttpServer.serve(app))\n * ).pipe(Layer.provide(NodeHttpServer.layer(createServer, { port: 3000 })));\n *\n * NodeRuntime.runMain(Layer.launch(serverLayer));\n * ```\n */\nexport const makeHandler = (\n options: SvelteKitHandlerOptions,\n): Effect.Effect<SvelteKitHttpApp, never, SvelteKitHttpAppServices> =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const context = yield* Effect.context<never>();\n\n const serverDir = path.join(options.dir, \"server\");\n\n return yield* makeHandlerWith<SvelteKitHttpAppServices>({\n server: options.server,\n env: options.env,\n envPrefix: options.envPrefix,\n // `read` backs the `read()` helper from `$app/server`, streaming server\n // assets from the build output.\n read: (file) => Stream.toReadableStreamWith(fs.stream(path.join(serverDir, file)), context),\n assets: AssetSource.fileSystem({\n dir: options.dir,\n appPath: options.appPath,\n prerendered: options.prerendered,\n }),\n });\n });\n\n/**\n * The SvelteKit server's `init` or `respond` rejected. SvelteKit turns a\n * route's own errors into responses, so a rejection is a bug in the server\n * build; the handler's error channel is `never`, so this reaches the platform\n * as a DEFECT (a 500), carrying what SvelteKit rejected with as `cause`.\n */\nexport class SvelteKitServerError extends Schema.TaggedError<SvelteKitServerError>()(\n \"SvelteKitServerError\",\n {\n /** Which `Server` method rejected. */\n operation: Schema.Literals([\"init\", \"respond\"]),\n /** What the method rejected with, or threw. */\n cause: Schema.Defect(),\n },\n) {}\n\n/**\n * The platform-neutral SSR core. Like {@link makeHandler}, but the asset source\n * and the server-asset `read` capability are injected, so the same SvelteKit\n * `HttpApp` can run on Node (file-system assets) or on Cloudflare Workers\n * (`AssetSource.cloudflareAssets(env.ASSETS)`).\n *\n * The returned app:\n *\n * 1. falls through to the injected {@link AssetSource} for static client assets\n * and prerendered pages (GET/HEAD), then\n * 2. server-side renders via the SvelteKit server.\n *\n * @example\n * ```ts\n * // Workers: a fetch handler with assets from env.ASSETS\n * import { makeHandlerWith, AssetSource, toWebHandler } from \"...adapter/handler\";\n * import { server } from \"./server.js\";\n *\n * export default {\n * fetch: (request, env, ctx) =>\n * toWebHandler(\n * makeHandlerWith({\n * server, env,\n * assets: AssetSource.cloudflareAssets(env.ASSETS),\n * read: () => { throw new Error(\"read() not supported on this deployment\"); },\n * }),\n * )(request),\n * };\n * ```\n */\nexport const makeHandlerWith = <RAssets = never>(\n options: SvelteKitNeutralHandlerOptions<RAssets>,\n): Effect.Effect<SvelteKitHttpApp<RAssets>, never, never> =>\n Effect.gen(function* () {\n const config = yield* handlerConfig(options.envPrefix ?? \"\").pipe(Effect.orDie);\n\n // Initialise the SvelteKit server. `read` backs `read()` from `$app/server`.\n const server = options.server;\n yield* Effect.tryPromise({\n try: () =>\n server.init({\n env: options.env ?? {},\n read: options.read,\n }),\n catch: (cause) => new SvelteKitServerError({ operation: \"init\", cause }),\n }).pipe(Effect.orDie);\n\n // The HTTP handler itself, evaluated once per request.\n return Effect.gen(function* () {\n const request = yield* HttpServerRequest.HttpServerRequest;\n const requestContext = yield* Effect.context<never>();\n\n const origin = originOf(request, config);\n const url = new URL(request.url, origin);\n\n // A malformed percent-encoding (`decodeURIComponent` throws) is a 400.\n const decoded = Result.try(() => decodeURIComponent(url.pathname));\n if (Result.isFailure(decoded)) return HttpServerResponse.empty({ status: 400 });\n const pathname = decoded.success;\n\n // 1. Static client assets / prerendered pages, via the injected source.\n // Only GET/HEAD reach assets; build a body-less request for the source.\n if (request.method === \"GET\" || request.method === \"HEAD\") {\n const assetRequest = new Request(url, {\n method: request.method,\n headers: { ...request.headers },\n });\n const asset = yield* options.assets.serveAsset(assetRequest, pathname);\n if (Option.isSome(asset)) return asset.value;\n }\n\n // 2. Server-side rendering.\n const webRequest = toWebRequest(request, url, requestContext);\n const response = yield* Effect.tryPromise({\n try: () =>\n server.respond(webRequest, {\n getClientAddress: () => clientAddressOf(request, config),\n }),\n catch: (cause) => new SvelteKitServerError({ operation: \"respond\", cause }),\n }).pipe(Effect.orDie);\n return HttpServerResponse.fromWeb(response);\n });\n });\n\n/**\n * Convert a SvelteKit `HttpApp` to a Web `fetch` handler, providing the asset\n * source's services with `layer`. Use this for a Workers `fetch` export or any\n * runtime that speaks the Web platform.\n *\n * @example\n * ```ts\n * const fetchHandler = toWebHandler(\n * makeHandlerWith({ ..., assets: AssetSource.cloudflareAssets(env.ASSETS) }),\n * Layer.empty,\n * );\n * ```\n */\nexport const toWebHandler = <RAssets, E>(\n app: Effect.Effect<SvelteKitHttpApp<RAssets>, never, never>,\n layer: Layer.Layer<RAssets, E>,\n): ((request: Request) => Promise<Response>) => {\n // Build the app (server.init) and the per-request web handler once, lazily on\n // the first request, then dispatch each request through it.\n let built: Promise<(request: Request) => Promise<Response>> | undefined;\n const build = (): Promise<(request: Request) => Promise<Response>> =>\n (built ??= Effect.runPromise(app).then(\n (inner) =>\n // SAFETY: `layer` provides `RAssets`, and the web handler provides the\n // `HttpServerRequest`, so the handler needs no per-request context; the\n // conditional type only stays unresolved while `RAssets` is generic.\n HttpEffect.toWebHandlerLayer(inner, layer).handler as (\n request: Request,\n ) => Promise<Response>,\n ));\n return async (request) => (await build())(request);\n};\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { Adapter } from "@sveltejs/kit";
2
2
  //#region src/adapter/index.d.ts
3
3
  /** Options for {@link effectAdapter}. */
4
- interface EffectAdapterOptions {
4
+ export interface EffectAdapterOptions {
5
5
  /**
6
6
  * The directory to write the production build to.
7
7
  * @default "build"
@@ -38,7 +38,7 @@ interface EffectAdapterOptions {
38
38
  /**
39
39
  * Creates the Effect SvelteKit adapter.
40
40
  */
41
- declare function effectAdapter(options?: EffectAdapterOptions): Adapter;
41
+ export declare function effectAdapter(options?: EffectAdapterOptions): Adapter;
42
42
  //#endregion
43
- export { EffectAdapterOptions, effectAdapter as default, effectAdapter };
43
+ export { effectAdapter as default };
44
44
  //# sourceMappingURL=index.d.ts.map
@@ -77,7 +77,7 @@ serve(handler, { envPrefix: ${JSON.stringify(envPrefix)} });
77
77
  * server-side rendered by the SvelteKit `HttpApp`.
78
78
  */
79
79
  const fetchEntryTemplate = (envPrefix) => `\
80
- import { Layer } from "effect";
80
+ import * as Layer from "effect/Layer";
81
81
  import { makeHandlerWith, AssetSource, toWebHandler } from "${PACKAGE}/adapter/handler";
82
82
  import { server } from "./server.js";
83
83
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/adapter/index.ts"],"sourcesContent":["/**\n * Effect deployment adapter for SvelteKit.\n *\n * Like `@sveltejs/adapter-node`, but the production server is an\n * `effect/http` HTTP server: requests are handled by an Effect HTTP\n * handler, configuration is read through `Config`, and startup/shutdown is\n * managed by Effect layers and scopes (SIGINT/SIGTERM trigger a graceful\n * shutdown that runs all finalizers).\n *\n * ```js\n * // vite.config.ts\n * import { sveltekit } from \"@sveltejs/kit/vite\";\n * import adapter from \"@thomasfosterau/effect-sveltekit/adapter\";\n * import { defineConfig } from \"vite\";\n *\n * export default defineConfig({\n * plugins: [sveltekit({ adapter: adapter() })],\n * });\n * ```\n *\n * The build output (`build/` by default) contains:\n *\n * - `index.js` — runs the production server: `node build`\n * - `handler.js` — exports the SvelteKit app as a composable Effect HTTP\n * handler, for mounting inside an existing `effect/http` server\n * - `client/`, `server/`, `prerendered/`, `server.js` (the SvelteKit\n * `server` instance), `manifest.js` (prerendered paths, base and app path) —\n * the built app\n *\n * Unlike `adapter-node`, the server output is not bundled: the deployment\n * needs `node_modules` with the app's production dependencies installed\n * (including `@thomasfosterau/effect-sveltekit`, `effect`, and\n * `@effect/platform-node`).\n */\n\nimport { mkdirSync, rmSync, writeFileSync } from \"node:fs\";\nimport type { Adapter } from \"@sveltejs/kit\";\n\n/** Options for {@link effectAdapter}. */\nexport interface EffectAdapterOptions {\n /**\n * The directory to write the production build to.\n * @default \"build\"\n */\n readonly out?: string;\n /**\n * Precompress static assets and prerendered pages with gzip and brotli.\n * @default true\n */\n readonly precompress?: boolean;\n /**\n * Prefix for the environment variables the production server reads\n * (`PORT`, `HOST`, `ORIGIN`, `PROTOCOL_HEADER`, `HOST_HEADER`,\n * `PORT_HEADER`, `ADDRESS_HEADER`, `XFF_DEPTH`).\n * @default \"\"\n */\n readonly envPrefix?: string;\n /**\n * The deployment target for the generated entry:\n *\n * - `\"node\"` (default) — a production Node HTTP server (`node build`) on\n * `@effect/platform-node`, serving assets from disk.\n * - `\"fetch\"` — a Web `fetch` handler suitable for Cloudflare Workers\n * (`build/index.js` exports `default { fetch }`), serving assets from the\n * `env.ASSETS` binding via `AssetSource.cloudflareAssets`.\n *\n * Both targets also write `build/handler.js` (the SvelteKit `HttpApp`), so you\n * can compose your own entry for any `effect/http` runtime.\n *\n * @default \"node\"\n */\n readonly target?: \"node\" | \"fetch\";\n}\n\nconst PACKAGE = \"@thomasfosterau/effect-sveltekit\";\n\n/** Template for the generated `<out>/handler.js`. */\nconst handlerTemplate = (envPrefix: string): string => `\\\nimport { dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport process from \"node:process\";\nimport { makeHandler } from \"${PACKAGE}/adapter/handler\";\nimport { server } from \"./server.js\";\nimport { prerendered, base, appPath } from \"./manifest.js\";\n\nconst dir = dirname(fileURLToPath(import.meta.url));\n\n/**\n * The SvelteKit application as a composable Effect HTTP handler.\n *\n * Serve it with the generated index.js, or mount it inside any\n * \\`effect/http\\` HTTP server.\n */\nexport const handler = makeHandler({\n server,\n appPath,\n prerendered,\n base,\n dir,\n env: process.env,\n envPrefix: ${JSON.stringify(envPrefix)},\n});\n`;\n\n/** Template for the generated Node `<out>/index.js`. */\nconst nodeEntryTemplate = (envPrefix: string): string => `\\\nimport { serve } from \"${PACKAGE}/adapter/serve\";\nimport { handler } from \"./handler.js\";\n\nserve(handler, { envPrefix: ${JSON.stringify(envPrefix)} });\n`;\n\n/**\n * Template for the generated Cloudflare Workers `<out>/index.js`.\n *\n * Exports a module worker (`default { fetch }`). Static client assets and\n * prerendered pages are served from the `ASSETS` binding; everything else is\n * server-side rendered by the SvelteKit `HttpApp`.\n */\nconst fetchEntryTemplate = (envPrefix: string): string => `\\\nimport { Layer } from \"effect\";\nimport { makeHandlerWith, AssetSource, toWebHandler } from \"${PACKAGE}/adapter/handler\";\nimport { server } from \"./server.js\";\n\nlet fetchHandler;\n\nexport default {\n /** @param {Request} request @param {Record<string, any>} env @param {any} ctx */\n fetch(request, env, ctx) {\n fetchHandler ??= toWebHandler(\n makeHandlerWith({\n server,\n env,\n envPrefix: ${JSON.stringify(envPrefix)},\n // Static assets come from the Workers ASSETS binding (configure it to\n // serve the uploaded \\`client/\\` + \\`prerendered/\\` output).\n assets: AssetSource.cloudflareAssets(env.ASSETS),\n // \\`read()\\` from \\`$app/server\\` is not backed by a file system on workerd.\n read: (file) => {\n throw new Error(\\`read() is not supported on this deployment (\\${file})\\`);\n },\n }),\n Layer.empty,\n );\n return fetchHandler(request);\n },\n};\n`;\n\n/**\n * Creates the Effect SvelteKit adapter.\n */\nexport function effectAdapter(options: EffectAdapterOptions = {}): Adapter {\n const { out = \"build\", precompress = true, envPrefix = \"\", target = \"node\" } = options;\n\n return {\n name: `${PACKAGE}/adapter`,\n\n async adapt(builder) {\n const base = builder.config.paths.base;\n\n rmSync(out, { recursive: true, force: true });\n mkdirSync(out, { recursive: true });\n\n builder.log.minor(\"Copying assets\");\n builder.writeClient(`${out}/client${base}`);\n builder.writePrerendered(`${out}/prerendered${base}`);\n\n if (precompress) {\n builder.log.minor(\"Compressing assets\");\n await Promise.all([\n builder.compress(`${out}/client`),\n builder.compress(`${out}/prerendered`),\n ]);\n }\n\n builder.log.minor(\"Building server\");\n builder.writeServer(`${out}/server`);\n // `<out>/server.js` exports the SvelteKit `server` instance, with the\n // manifest of the (non-prerendered) routes baked in.\n builder.generateServerInstance(`${out}/server.js`, { serverDirectory: `${out}/server` });\n\n writeFileSync(\n `${out}/manifest.js`,\n [\n `export const prerendered = new Set(${JSON.stringify(builder.prerendered.paths)});`,\n `export const base = ${JSON.stringify(base)};`,\n `export const appPath = ${JSON.stringify(builder.getAppPath())};`,\n ].join(\"\\n\\n\"),\n );\n\n builder.log.minor(\"Writing server entry\");\n writeFileSync(`${out}/handler.js`, handlerTemplate(envPrefix));\n writeFileSync(\n `${out}/index.js`,\n target === \"fetch\" ? fetchEntryTemplate(envPrefix) : nodeEntryTemplate(envPrefix),\n );\n },\n\n supports: {\n // On Node, `read()` from `$app/server` is backed by the platform\n // FileSystem. On the `fetch` (Workers) target it has no file system, so\n // routes using `read()` are unsupported there.\n read: () => target !== \"fetch\",\n },\n };\n}\n\nexport default effectAdapter;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0EA,MAAM,UAAU;;AAGhB,MAAM,mBAAmB,cAA8B;;;;+BAIxB,QAAQ;;;;;;;;;;;;;;;;;;;eAmBxB,KAAK,UAAU,SAAS,EAAE;;;;AAKzC,MAAM,qBAAqB,cAA8B;yBAChC,QAAQ;;;8BAGH,KAAK,UAAU,SAAS,EAAE;;;;;;;;;AAUxD,MAAM,sBAAsB,cAA8B;;8DAEI,QAAQ;;;;;;;;;;;;qBAYjD,KAAK,UAAU,SAAS,EAAE;;;;;;;;;;;;;;;;;;AAmB/C,SAAgB,cAAc,UAAgC,CAAC,GAAY;CACzE,MAAM,EAAE,MAAM,SAAS,cAAc,MAAM,YAAY,IAAI,SAAS,WAAW;CAE/E,OAAO;EACL,MAAM,GAAG,QAAQ;EAEjB,MAAM,MAAM,SAAS;GACnB,MAAM,OAAO,QAAQ,OAAO,MAAM;GAElC,OAAO,KAAK;IAAE,WAAW;IAAM,OAAO;GAAK,CAAC;GAC5C,UAAU,KAAK,EAAE,WAAW,KAAK,CAAC;GAElC,QAAQ,IAAI,MAAM,gBAAgB;GAClC,QAAQ,YAAY,GAAG,IAAI,SAAS,MAAM;GAC1C,QAAQ,iBAAiB,GAAG,IAAI,cAAc,MAAM;GAEpD,IAAI,aAAa;IACf,QAAQ,IAAI,MAAM,oBAAoB;IACtC,MAAM,QAAQ,IAAI,CAChB,QAAQ,SAAS,GAAG,IAAI,QAAQ,GAChC,QAAQ,SAAS,GAAG,IAAI,aAAa,CACvC,CAAC;GACH;GAEA,QAAQ,IAAI,MAAM,iBAAiB;GACnC,QAAQ,YAAY,GAAG,IAAI,QAAQ;GAGnC,QAAQ,uBAAuB,GAAG,IAAI,aAAa,EAAE,iBAAiB,GAAG,IAAI,SAAS,CAAC;GAEvF,cACE,GAAG,IAAI,eACP;IACE,sCAAsC,KAAK,UAAU,QAAQ,YAAY,KAAK,EAAE;IAChF,uBAAuB,KAAK,UAAU,IAAI,EAAE;IAC5C,0BAA0B,KAAK,UAAU,QAAQ,WAAW,CAAC,EAAE;GACjE,CAAC,CAAC,KAAK,MAAM,CACf;GAEA,QAAQ,IAAI,MAAM,sBAAsB;GACxC,cAAc,GAAG,IAAI,cAAc,gBAAgB,SAAS,CAAC;GAC7D,cACE,GAAG,IAAI,YACP,WAAW,UAAU,mBAAmB,SAAS,IAAI,kBAAkB,SAAS,CAClF;EACF;EAEA,UAAU,EAIR,YAAY,WAAW,QACzB;CACF;AACF"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/adapter/index.ts"],"sourcesContent":["/**\n * Effect deployment adapter for SvelteKit.\n *\n * Like `@sveltejs/adapter-node`, but the production server is an\n * `effect/http` HTTP server: requests are handled by an Effect HTTP\n * handler, configuration is read through `Config`, and startup/shutdown is\n * managed by Effect layers and scopes (SIGINT/SIGTERM trigger a graceful\n * shutdown that runs all finalizers).\n *\n * ```js\n * // vite.config.ts\n * import { sveltekit } from \"@sveltejs/kit/vite\";\n * import adapter from \"@thomasfosterau/effect-sveltekit/adapter\";\n * import { defineConfig } from \"vite\";\n *\n * export default defineConfig({\n * plugins: [sveltekit({ adapter: adapter() })],\n * });\n * ```\n *\n * The build output (`build/` by default) contains:\n *\n * - `index.js` — runs the production server: `node build`\n * - `handler.js` — exports the SvelteKit app as a composable Effect HTTP\n * handler, for mounting inside an existing `effect/http` server\n * - `client/`, `server/`, `prerendered/`, `server.js` (the SvelteKit\n * `server` instance), `manifest.js` (prerendered paths, base and app path) —\n * the built app\n *\n * Unlike `adapter-node`, the server output is not bundled: the deployment\n * needs `node_modules` with the app's production dependencies installed\n * (including `@thomasfosterau/effect-sveltekit`, `effect`, and\n * `@effect/platform-node`).\n */\n\nimport { mkdirSync, rmSync, writeFileSync } from \"node:fs\";\nimport type { Adapter } from \"@sveltejs/kit\";\n\n/** Options for {@link effectAdapter}. */\nexport interface EffectAdapterOptions {\n /**\n * The directory to write the production build to.\n * @default \"build\"\n */\n readonly out?: string;\n /**\n * Precompress static assets and prerendered pages with gzip and brotli.\n * @default true\n */\n readonly precompress?: boolean;\n /**\n * Prefix for the environment variables the production server reads\n * (`PORT`, `HOST`, `ORIGIN`, `PROTOCOL_HEADER`, `HOST_HEADER`,\n * `PORT_HEADER`, `ADDRESS_HEADER`, `XFF_DEPTH`).\n * @default \"\"\n */\n readonly envPrefix?: string;\n /**\n * The deployment target for the generated entry:\n *\n * - `\"node\"` (default) — a production Node HTTP server (`node build`) on\n * `@effect/platform-node`, serving assets from disk.\n * - `\"fetch\"` — a Web `fetch` handler suitable for Cloudflare Workers\n * (`build/index.js` exports `default { fetch }`), serving assets from the\n * `env.ASSETS` binding via `AssetSource.cloudflareAssets`.\n *\n * Both targets also write `build/handler.js` (the SvelteKit `HttpApp`), so you\n * can compose your own entry for any `effect/http` runtime.\n *\n * @default \"node\"\n */\n readonly target?: \"node\" | \"fetch\";\n}\n\nconst PACKAGE = \"@thomasfosterau/effect-sveltekit\";\n\n/** Template for the generated `<out>/handler.js`. */\nconst handlerTemplate = (envPrefix: string): string => `\\\nimport { dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport process from \"node:process\";\nimport { makeHandler } from \"${PACKAGE}/adapter/handler\";\nimport { server } from \"./server.js\";\nimport { prerendered, base, appPath } from \"./manifest.js\";\n\nconst dir = dirname(fileURLToPath(import.meta.url));\n\n/**\n * The SvelteKit application as a composable Effect HTTP handler.\n *\n * Serve it with the generated index.js, or mount it inside any\n * \\`effect/http\\` HTTP server.\n */\nexport const handler = makeHandler({\n server,\n appPath,\n prerendered,\n base,\n dir,\n env: process.env,\n envPrefix: ${JSON.stringify(envPrefix)},\n});\n`;\n\n/** Template for the generated Node `<out>/index.js`. */\nconst nodeEntryTemplate = (envPrefix: string): string => `\\\nimport { serve } from \"${PACKAGE}/adapter/serve\";\nimport { handler } from \"./handler.js\";\n\nserve(handler, { envPrefix: ${JSON.stringify(envPrefix)} });\n`;\n\n/**\n * Template for the generated Cloudflare Workers `<out>/index.js`.\n *\n * Exports a module worker (`default { fetch }`). Static client assets and\n * prerendered pages are served from the `ASSETS` binding; everything else is\n * server-side rendered by the SvelteKit `HttpApp`.\n */\nconst fetchEntryTemplate = (envPrefix: string): string => `\\\nimport * as Layer from \"effect/Layer\";\nimport { makeHandlerWith, AssetSource, toWebHandler } from \"${PACKAGE}/adapter/handler\";\nimport { server } from \"./server.js\";\n\nlet fetchHandler;\n\nexport default {\n /** @param {Request} request @param {Record<string, any>} env @param {any} ctx */\n fetch(request, env, ctx) {\n fetchHandler ??= toWebHandler(\n makeHandlerWith({\n server,\n env,\n envPrefix: ${JSON.stringify(envPrefix)},\n // Static assets come from the Workers ASSETS binding (configure it to\n // serve the uploaded \\`client/\\` + \\`prerendered/\\` output).\n assets: AssetSource.cloudflareAssets(env.ASSETS),\n // \\`read()\\` from \\`$app/server\\` is not backed by a file system on workerd.\n read: (file) => {\n throw new Error(\\`read() is not supported on this deployment (\\${file})\\`);\n },\n }),\n Layer.empty,\n );\n return fetchHandler(request);\n },\n};\n`;\n\n/**\n * Creates the Effect SvelteKit adapter.\n */\nexport function effectAdapter(options: EffectAdapterOptions = {}): Adapter {\n const { out = \"build\", precompress = true, envPrefix = \"\", target = \"node\" } = options;\n\n return {\n name: `${PACKAGE}/adapter`,\n\n async adapt(builder) {\n const base = builder.config.paths.base;\n\n rmSync(out, { recursive: true, force: true });\n mkdirSync(out, { recursive: true });\n\n builder.log.minor(\"Copying assets\");\n builder.writeClient(`${out}/client${base}`);\n builder.writePrerendered(`${out}/prerendered${base}`);\n\n if (precompress) {\n builder.log.minor(\"Compressing assets\");\n await Promise.all([\n builder.compress(`${out}/client`),\n builder.compress(`${out}/prerendered`),\n ]);\n }\n\n builder.log.minor(\"Building server\");\n builder.writeServer(`${out}/server`);\n // `<out>/server.js` exports the SvelteKit `server` instance, with the\n // manifest of the (non-prerendered) routes baked in.\n builder.generateServerInstance(`${out}/server.js`, { serverDirectory: `${out}/server` });\n\n writeFileSync(\n `${out}/manifest.js`,\n [\n `export const prerendered = new Set(${JSON.stringify(builder.prerendered.paths)});`,\n `export const base = ${JSON.stringify(base)};`,\n `export const appPath = ${JSON.stringify(builder.getAppPath())};`,\n ].join(\"\\n\\n\"),\n );\n\n builder.log.minor(\"Writing server entry\");\n writeFileSync(`${out}/handler.js`, handlerTemplate(envPrefix));\n writeFileSync(\n `${out}/index.js`,\n target === \"fetch\" ? fetchEntryTemplate(envPrefix) : nodeEntryTemplate(envPrefix),\n );\n },\n\n supports: {\n // On Node, `read()` from `$app/server` is backed by the platform\n // FileSystem. On the `fetch` (Workers) target it has no file system, so\n // routes using `read()` are unsupported there.\n read: () => target !== \"fetch\",\n },\n };\n}\n\nexport default effectAdapter;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0EA,MAAM,UAAU;;AAGhB,MAAM,mBAAmB,cAA8B;;;;+BAIxB,QAAQ;;;;;;;;;;;;;;;;;;;eAmBxB,KAAK,UAAU,SAAS,EAAE;;;;AAKzC,MAAM,qBAAqB,cAA8B;yBAChC,QAAQ;;;8BAGH,KAAK,UAAU,SAAS,EAAE;;;;;;;;;AAUxD,MAAM,sBAAsB,cAA8B;;8DAEI,QAAQ;;;;;;;;;;;;qBAYjD,KAAK,UAAU,SAAS,EAAE;;;;;;;;;;;;;;;;;;AAmB/C,SAAgB,cAAc,UAAgC,CAAC,GAAY;CACzE,MAAM,EAAE,MAAM,SAAS,cAAc,MAAM,YAAY,IAAI,SAAS,WAAW;CAE/E,OAAO;EACL,MAAM,GAAG,QAAQ;EAEjB,MAAM,MAAM,SAAS;GACnB,MAAM,OAAO,QAAQ,OAAO,MAAM;GAElC,OAAO,KAAK;IAAE,WAAW;IAAM,OAAO;GAAK,CAAC;GAC5C,UAAU,KAAK,EAAE,WAAW,KAAK,CAAC;GAElC,QAAQ,IAAI,MAAM,gBAAgB;GAClC,QAAQ,YAAY,GAAG,IAAI,SAAS,MAAM;GAC1C,QAAQ,iBAAiB,GAAG,IAAI,cAAc,MAAM;GAEpD,IAAI,aAAa;IACf,QAAQ,IAAI,MAAM,oBAAoB;IACtC,MAAM,QAAQ,IAAI,CAChB,QAAQ,SAAS,GAAG,IAAI,QAAQ,GAChC,QAAQ,SAAS,GAAG,IAAI,aAAa,CACvC,CAAC;GACH;GAEA,QAAQ,IAAI,MAAM,iBAAiB;GACnC,QAAQ,YAAY,GAAG,IAAI,QAAQ;GAGnC,QAAQ,uBAAuB,GAAG,IAAI,aAAa,EAAE,iBAAiB,GAAG,IAAI,SAAS,CAAC;GAEvF,cACE,GAAG,IAAI,eACP;IACE,sCAAsC,KAAK,UAAU,QAAQ,YAAY,KAAK,EAAE;IAChF,uBAAuB,KAAK,UAAU,IAAI,EAAE;IAC5C,0BAA0B,KAAK,UAAU,QAAQ,WAAW,CAAC,EAAE;GACjE,CAAC,CAAC,KAAK,MAAM,CACf;GAEA,QAAQ,IAAI,MAAM,sBAAsB;GACxC,cAAc,GAAG,IAAI,cAAc,gBAAgB,SAAS,CAAC;GAC7D,cACE,GAAG,IAAI,YACP,WAAW,UAAU,mBAAmB,SAAS,IAAI,kBAAkB,SAAS,CAClF;EACF;EAEA,UAAU,EAIR,YAAY,WAAW,QACzB;CACF;AACF"}
@@ -1,9 +1,10 @@
1
1
  import { SvelteKitHttpApp } from "./handler.js";
2
- import { Effect, Layer } from "effect";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Layer from "effect/Layer";
3
4
  import * as NodeHttpServer from "@effect/platform-node/NodeHttpServer";
4
5
  //#region src/adapter/serve.d.ts
5
6
  /** Options for {@link serve} and {@link layer}. */
6
- interface ServeOptions {
7
+ export interface ServeOptions {
7
8
  /** Prefix for the configuration environment variables (PORT, HOST, ...). */
8
9
  readonly envPrefix?: string;
9
10
  /**
@@ -23,7 +24,7 @@ interface ServeOptions {
23
24
  *
24
25
  * Launch it with `Layer.launch`, or merge it into a larger application.
25
26
  */
26
- declare const layer: (handler: Effect.Effect<SvelteKitHttpApp, never, NodeHttpServerServices>, options?: ServeOptions) => Layer.Layer<never, unknown>;
27
+ export declare const layer: (handler: Effect.Effect<SvelteKitHttpApp, never, NodeHttpServerServices>, options?: ServeOptions) => Layer.Layer<never, unknown>;
27
28
  /** The services provided to the handler effect by `NodeHttpServer.layerConfig`. */
28
29
  type NodeHttpServerServices = Layer.Success<ReturnType<typeof NodeHttpServer.layerConfig>>;
29
30
  /**
@@ -40,7 +41,7 @@ type NodeHttpServerServices = Layer.Success<ReturnType<typeof NodeHttpServer.lay
40
41
  * serve(handler);
41
42
  * ```
42
43
  */
43
- declare const serve: (handler: Effect.Effect<SvelteKitHttpApp, never, NodeHttpServerServices>, options?: ServeOptions) => void;
44
+ export declare const serve: (handler: Effect.Effect<SvelteKitHttpApp, never, NodeHttpServerServices>, options?: ServeOptions) => void;
44
45
  //#endregion
45
- export { ServeOptions, layer, serve };
46
+ export {};
46
47
  //# sourceMappingURL=serve.d.ts.map
@@ -1,4 +1,6 @@
1
- import { Config, Effect, Layer } from "effect";
1
+ import * as Effect from "effect/Effect";
2
+ import * as Layer from "effect/Layer";
3
+ import * as Config from "effect/Config";
2
4
  import { createServer } from "node:http";
3
5
  import * as HttpMiddleware from "effect/http/HttpMiddleware";
4
6
  import * as HttpServer from "effect/http/HttpServer";
@@ -1 +1 @@
1
- {"version":3,"file":"serve.js","names":[],"sources":["../../src/adapter/serve.ts"],"sourcesContent":["/**\n * Production server entry for the Effect SvelteKit adapter.\n *\n * The adapter's generated `build/index.js` calls {@link serve} with the\n * handler from `build/handler.js`. The server runs on\n * `@effect/platform-node`'s `NodeHttpServer`, with configuration read from\n * the environment and graceful shutdown handled by Effect scopes.\n *\n * For full control (custom layers, tracing, additional routes), skip the\n * generated entry and compose {@link layer} — or the handler itself — into\n * your own Effect application.\n */\n\nimport { createServer } from \"node:http\";\nimport * as HttpMiddleware from \"effect/http/HttpMiddleware\";\nimport * as HttpServer from \"effect/http/HttpServer\";\nimport * as NodeHttpServer from \"@effect/platform-node/NodeHttpServer\";\nimport * as NodeRuntime from \"@effect/platform-node/NodeRuntime\";\nimport { Config, Effect, Layer } from \"effect\";\nimport type { SvelteKitHttpApp } from \"./handler.js\";\n\n/** Options for {@link serve} and {@link layer}. */\nexport interface ServeOptions {\n /** Prefix for the configuration environment variables (PORT, HOST, ...). */\n readonly envPrefix?: string;\n /**\n * Additional layer merged into the server context, e.g. tracing or logging\n * layers.\n */\n readonly layer?: Layer.Layer<never, never>;\n /**\n * Disable the default request logger middleware.\n */\n readonly disableLogger?: boolean;\n}\n\n/**\n * Builds the full server layer for a SvelteKit HttpApp: HTTP listener\n * (`PORT` / `HOST` environment variables), request logging, and the\n * platform services the handler needs.\n *\n * Launch it with `Layer.launch`, or merge it into a larger application.\n */\nexport const layer = (\n handler: Effect.Effect<SvelteKitHttpApp, never, NodeHttpServerServices>,\n options: ServeOptions = {},\n): Layer.Layer<never, unknown> => {\n const prefix = options.envPrefix ?? \"\";\n\n const serveLayer = Layer.unwrap(\n Effect.map(handler, (app) =>\n options.disableLogger ? HttpServer.serve(app) : HttpServer.serve(app, HttpMiddleware.logger),\n ),\n );\n\n const listenLayer = NodeHttpServer.layerConfig(createServer, {\n port: Config.Int(`${prefix}PORT`).pipe(Config.withDefault(3000)),\n host: Config.String(`${prefix}HOST`).pipe(Config.withDefault(\"0.0.0.0\")),\n });\n\n const withListener = serveLayer.pipe(HttpServer.withLogAddress, Layer.provide(listenLayer));\n\n return options.layer ? Layer.merge(withListener, options.layer) : withListener;\n};\n\n/** The services provided to the handler effect by `NodeHttpServer.layerConfig`. */\ntype NodeHttpServerServices = Layer.Success<ReturnType<typeof NodeHttpServer.layerConfig>>;\n\n/**\n * Starts the production server and runs it until the process receives\n * SIGINT/SIGTERM, at which point the server (and every Effect resource) is\n * shut down gracefully.\n *\n * @example\n * ```ts\n * // build/index.js (generated by the adapter)\n * import { handler } from \"./handler.js\";\n * import { serve } from \"@thomasfosterau/effect-sveltekit/adapter/serve\";\n *\n * serve(handler);\n * ```\n */\nexport const serve = (\n handler: Effect.Effect<SvelteKitHttpApp, never, NodeHttpServerServices>,\n options: ServeOptions = {},\n): void => {\n NodeRuntime.runMain(Layer.launch(layer(handler, options)));\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA2CA,MAAa,SACX,SACA,UAAwB,CAAC,MACO;CAChC,MAAM,SAAS,QAAQ,aAAa;CAEpC,MAAM,aAAa,MAAM,OACvB,OAAO,IAAI,UAAU,QACnB,QAAQ,gBAAgB,WAAW,MAAM,GAAG,IAAI,WAAW,MAAM,KAAK,eAAe,MAAM,CAC7F,CACF;CAEA,MAAM,cAAc,eAAe,YAAY,cAAc;EAC3D,MAAM,OAAO,IAAI,GAAG,OAAO,KAAK,CAAC,CAAC,KAAK,OAAO,YAAY,GAAI,CAAC;EAC/D,MAAM,OAAO,OAAO,GAAG,OAAO,KAAK,CAAC,CAAC,KAAK,OAAO,YAAY,SAAS,CAAC;CACzE,CAAC;CAED,MAAM,eAAe,WAAW,KAAK,WAAW,gBAAgB,MAAM,QAAQ,WAAW,CAAC;CAE1F,OAAO,QAAQ,QAAQ,MAAM,MAAM,cAAc,QAAQ,KAAK,IAAI;AACpE;;;;;;;;;;;;;;;AAmBA,MAAa,SACX,SACA,UAAwB,CAAC,MAChB;CACT,YAAY,QAAQ,MAAM,OAAO,MAAM,SAAS,OAAO,CAAC,CAAC;AAC3D"}
1
+ {"version":3,"file":"serve.js","names":[],"sources":["../../src/adapter/serve.ts"],"sourcesContent":["/**\n * Production server entry for the Effect SvelteKit adapter.\n *\n * The adapter's generated `build/index.js` calls {@link serve} with the\n * handler from `build/handler.js`. The server runs on\n * `@effect/platform-node`'s `NodeHttpServer`, with configuration read from\n * the environment and graceful shutdown handled by Effect scopes.\n *\n * For full control (custom layers, tracing, additional routes), skip the\n * generated entry and compose {@link layer} — or the handler itself — into\n * your own Effect application.\n */\n\nimport { createServer } from \"node:http\";\nimport * as HttpMiddleware from \"effect/http/HttpMiddleware\";\nimport * as HttpServer from \"effect/http/HttpServer\";\nimport * as NodeHttpServer from \"@effect/platform-node/NodeHttpServer\";\nimport * as NodeRuntime from \"@effect/platform-node/NodeRuntime\";\nimport * as Config from \"effect/Config\";\nimport * as Effect from \"effect/Effect\";\nimport * as Layer from \"effect/Layer\";\nimport type { SvelteKitHttpApp } from \"./handler.js\";\n\n/** Options for {@link serve} and {@link layer}. */\nexport interface ServeOptions {\n /** Prefix for the configuration environment variables (PORT, HOST, ...). */\n readonly envPrefix?: string;\n /**\n * Additional layer merged into the server context, e.g. tracing or logging\n * layers.\n */\n readonly layer?: Layer.Layer<never, never>;\n /**\n * Disable the default request logger middleware.\n */\n readonly disableLogger?: boolean;\n}\n\n/**\n * Builds the full server layer for a SvelteKit HttpApp: HTTP listener\n * (`PORT` / `HOST` environment variables), request logging, and the\n * platform services the handler needs.\n *\n * Launch it with `Layer.launch`, or merge it into a larger application.\n */\nexport const layer = (\n handler: Effect.Effect<SvelteKitHttpApp, never, NodeHttpServerServices>,\n options: ServeOptions = {},\n): Layer.Layer<never, unknown> => {\n const prefix = options.envPrefix ?? \"\";\n\n const serveLayer = Layer.unwrap(\n Effect.map(handler, (app) =>\n options.disableLogger ? HttpServer.serve(app) : HttpServer.serve(app, HttpMiddleware.logger),\n ),\n );\n\n const listenLayer = NodeHttpServer.layerConfig(createServer, {\n port: Config.Int(`${prefix}PORT`).pipe(Config.withDefault(3000)),\n host: Config.String(`${prefix}HOST`).pipe(Config.withDefault(\"0.0.0.0\")),\n });\n\n const withListener = serveLayer.pipe(HttpServer.withLogAddress, Layer.provide(listenLayer));\n\n return options.layer ? Layer.merge(withListener, options.layer) : withListener;\n};\n\n/** The services provided to the handler effect by `NodeHttpServer.layerConfig`. */\ntype NodeHttpServerServices = Layer.Success<ReturnType<typeof NodeHttpServer.layerConfig>>;\n\n/**\n * Starts the production server and runs it until the process receives\n * SIGINT/SIGTERM, at which point the server (and every Effect resource) is\n * shut down gracefully.\n *\n * @example\n * ```ts\n * // build/index.js (generated by the adapter)\n * import { handler } from \"./handler.js\";\n * import { serve } from \"@thomasfosterau/effect-sveltekit/adapter/serve\";\n *\n * serve(handler);\n * ```\n */\nexport const serve = (\n handler: Effect.Effect<SvelteKitHttpApp, never, NodeHttpServerServices>,\n options: ServeOptions = {},\n): void => {\n NodeRuntime.runMain(Layer.launch(layer(handler, options)));\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CA,MAAa,SACX,SACA,UAAwB,CAAC,MACO;CAChC,MAAM,SAAS,QAAQ,aAAa;CAEpC,MAAM,aAAa,MAAM,OACvB,OAAO,IAAI,UAAU,QACnB,QAAQ,gBAAgB,WAAW,MAAM,GAAG,IAAI,WAAW,MAAM,KAAK,eAAe,MAAM,CAC7F,CACF;CAEA,MAAM,cAAc,eAAe,YAAY,cAAc;EAC3D,MAAM,OAAO,IAAI,GAAG,OAAO,KAAK,CAAC,CAAC,KAAK,OAAO,YAAY,GAAI,CAAC;EAC/D,MAAM,OAAO,OAAO,GAAG,OAAO,KAAK,CAAC,CAAC,KAAK,OAAO,YAAY,SAAS,CAAC;CACzE,CAAC;CAED,MAAM,eAAe,WAAW,KAAK,WAAW,gBAAgB,MAAM,QAAQ,WAAW,CAAC;CAE1F,OAAO,QAAQ,QAAQ,MAAM,MAAM,cAAc,QAAQ,KAAK,IAAI;AACpE;;;;;;;;;;;;;;;AAmBA,MAAa,SACX,SACA,UAAwB,CAAC,MAChB;CACT,YAAY,QAAQ,MAAM,OAAO,MAAM,SAAS,OAAO,CAAC,CAAC;AAC3D"}
@@ -1,11 +1,11 @@
1
- import { Effect } from "effect";
1
+ import * as Effect from "effect/Effect";
2
2
  import * as HttpClient from "effect/http/HttpClient";
3
3
  import * as HttpApiClient from "effect/http-api/HttpApiClient";
4
4
  import * as HttpApi from "effect/http-api/HttpApi";
5
5
  import * as HttpApiGroup from "effect/http-api/HttpApiGroup";
6
6
  //#region src/api-client.d.ts
7
7
  /** Options for {@link apiClient}. */
8
- interface ApiClientOptions {
8
+ export interface ApiClientOptions {
9
9
  /**
10
10
  * The base URL the API is mounted at. For an `Endpoint.fromApi` mounted at
11
11
  * `src/routes/api/[...path]` with `prefix: "/api"`, pass `"/api"`. Defaults to
@@ -25,7 +25,6 @@ interface ApiClientOptions {
25
25
  * via `FetchHttpClient`. Yields the client from an `Effect`; the only remaining
26
26
  * requirement is any client middleware the API declares.
27
27
  */
28
- declare const apiClient: <ApiId extends string, Groups extends HttpApiGroup.Constraint>(api: HttpApi.HttpApi<ApiId, Groups>, options?: ApiClientOptions) => Effect.Effect<HttpApiClient.Client<Groups>, never, HttpApiGroup.MiddlewareClient<Groups>>;
28
+ export declare const apiClient: <ApiId extends string, Groups extends HttpApiGroup.Constraint>(api: HttpApi.HttpApi<ApiId, Groups>, options?: ApiClientOptions) => Effect.Effect<HttpApiClient.Client<Groups>, never, HttpApiGroup.MiddlewareClient<Groups>>;
29
29
  //#endregion
30
- export { ApiClientOptions, apiClient };
31
30
  //# sourceMappingURL=api-client.d.ts.map
@@ -1,4 +1,5 @@
1
- import { Effect, Layer } from "effect";
1
+ import * as Effect from "effect/Effect";
2
+ import * as Layer from "effect/Layer";
2
3
  import * as FetchHttpClient from "effect/http/FetchHttpClient";
3
4
  import * as HttpApiClient from "effect/http-api/HttpApiClient";
4
5
  //#region src/api-client.ts
@@ -1 +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.ts\"; // 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/http/FetchHttpClient\";\nimport type * as HttpClient from \"effect/http/HttpClient\";\nimport type * as HttpApi from \"effect/http-api/HttpApi\";\nimport * as HttpApiClient from \"effect/http-api/HttpApiClient\";\nimport type * as HttpApiGroup from \"effect/http-api/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.Constraint>(\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,CAAC,CAAC,KAAK,OAAO,QAAQ,UAAU,CAAC;AACpC"}
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.ts\"; // 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 * as Effect from \"effect/Effect\";\nimport * as Layer from \"effect/Layer\";\nimport * as FetchHttpClient from \"effect/http/FetchHttpClient\";\nimport type * as HttpClient from \"effect/http/HttpClient\";\nimport type * as HttpApi from \"effect/http-api/HttpApi\";\nimport * as HttpApiClient from \"effect/http-api/HttpApiClient\";\nimport type * as HttpApiGroup from \"effect/http-api/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.Constraint>(\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuDA,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,CAAC,CAAC,KAAK,OAAO,QAAQ,UAAU,CAAC;AACpC"}
@@ -2,16 +2,20 @@ import { SvelteRouteParams } from "./internal/route-params.js";
2
2
  import { SvelteKitRequestEvent } from "./runtime.js";
3
3
  import { ErrorTranslator } from "./request-runtime.js";
4
4
  import { SvelteKitCookies, SvelteKitLocals, SvelteKitResponseHeaders } from "./request-services.js";
5
- import { Effect, Exit, Fiber, Layer, ManagedRuntime } from "effect";
5
+ import * as Effect from "effect/Effect";
6
+ import * as Exit from "effect/Exit";
7
+ import * as Layer from "effect/Layer";
8
+ import * as ManagedRuntime from "effect/ManagedRuntime";
6
9
  import * as HttpClient from "effect/http/HttpClient";
7
10
  import { Action, Actions, Load, RequestEvent, ServerLoad } from "@sveltejs/kit";
8
11
  import { Handle, HandleFetch, HandleServerError, ServerInit } from "@sveltejs/kit/hooks";
12
+ import * as Fiber from "effect/Fiber";
9
13
  //#region src/app-runtime.d.ts
10
14
  /**
11
15
  * The services provided to every wrapped effect on the server, in addition to
12
16
  * the application's own layer.
13
17
  */
14
- type SvelteKitServices = HttpClient.HttpClient | SvelteKitRequestEvent | SvelteKitCookies | SvelteKitResponseHeaders | SvelteKitLocals;
18
+ export type SvelteKitServices = HttpClient.HttpClient | SvelteKitRequestEvent | SvelteKitCookies | SvelteKitResponseHeaders | SvelteKitLocals;
15
19
  /**
16
20
  * A per-request Effect runtime: the application layer's services plus the
17
21
  * per-request {@link SvelteKitServices} (an `HttpClient` backed by the request's
@@ -24,7 +28,7 @@ type SvelteKitServices = HttpClient.HttpClient | SvelteKitRequestEvent | SvelteK
24
28
  * effects share one `HttpClient` and one request scope. Retrieve it from an
25
29
  * event with `ServerRuntime.requestRuntime` to run your own effects.
26
30
  */
27
- interface RequestRuntime<R = never> {
31
+ export interface RequestRuntime<R = never> {
28
32
  /** Run an effect for this request, returning its `Exit`. */
29
33
  readonly runPromiseExit: <A>(effect: Effect.Effect<A, unknown, R | SvelteKitServices>) => Promise<Exit.Exit<A, unknown>>;
30
34
  /** Run an effect for this request, throwing on failure (passing SvelteKit control flow through). */
@@ -35,7 +39,7 @@ interface RequestRuntime<R = never> {
35
39
  /**
36
40
  * Options for {@link makeServerRuntime}.
37
41
  */
38
- interface ServerRuntimeOptions {
42
+ export interface ServerRuntimeOptions {
39
43
  /**
40
44
  * Translate a failed `Cause` into SvelteKit control flow at the boundary of
41
45
  * every wrapper (`serverLoad`, `action`, `actions`, `endpoint`, `handle`,
@@ -55,7 +59,7 @@ interface ServerRuntimeOptions {
55
59
  * effects additionally have access to the services `R` of the application
56
60
  * layer.
57
61
  */
58
- interface ServerRuntime<R = never, E = never> {
62
+ export interface ServerRuntime<R = never, E = never> {
59
63
  /** The underlying managed runtime for the application layer. */
60
64
  readonly runtime: ManagedRuntime.ManagedRuntime<R, E>;
61
65
  /**
@@ -170,7 +174,7 @@ interface ServerRuntime<R = never, E = never> {
170
174
  * `HttpClient`. Request-specific data should be passed to service methods as
171
175
  * arguments instead.
172
176
  */
173
- declare const makeServerRuntime: <R = never, E = never>(layer?: Layer.Layer<R, E>, options?: ServerRuntimeOptions) => ServerRuntime<R, E>;
177
+ export declare const makeServerRuntime: <R = never, E = never>(layer?: Layer.Layer<R, E>, options?: ServerRuntimeOptions) => ServerRuntime<R, E>;
174
178
  /**
175
179
  * A universal (client + server) Effect runtime bound to an application layer.
176
180
  *
@@ -178,7 +182,7 @@ declare const makeServerRuntime: <R = never, E = never>(layer?: Layer.Layer<R, E
178
182
  * functions also run in the browser, the layer must only use services that
179
183
  * work in both environments.
180
184
  */
181
- interface UniversalRuntime<R = never, E = never> {
185
+ export interface UniversalRuntime<R = never, E = never> {
182
186
  /** The underlying managed runtime for the application layer. */
183
187
  readonly runtime: ManagedRuntime.ManagedRuntime<R, E>;
184
188
  /**
@@ -224,7 +228,6 @@ interface UniversalRuntime<R = never, E = never> {
224
228
  * );
225
229
  * ```
226
230
  */
227
- declare const makeUniversalRuntime: <R = never, E = never>(layer?: Layer.Layer<R, E>) => UniversalRuntime<R, E>;
231
+ export declare const makeUniversalRuntime: <R = never, E = never>(layer?: Layer.Layer<R, E>) => UniversalRuntime<R, E>;
228
232
  //#endregion
229
- export { RequestRuntime, ServerRuntime, ServerRuntimeOptions, SvelteKitServices, UniversalRuntime, makeServerRuntime, makeUniversalRuntime };
230
233
  //# sourceMappingURL=app-runtime.d.ts.map
@@ -1,7 +1,15 @@
1
1
  import { SvelteKitRequestEvent } from "./runtime.js";
2
2
  import { SvelteKit } from "./kit.js";
3
3
  import { SvelteKitCookies, SvelteKitLocals, SvelteKitResponseHeaders, requestServicesFrom } from "./request-services.js";
4
- import { Effect, Exit, Layer, ManagedRuntime, Scope } from "effect";
4
+ import * as Effect from "effect/Effect";
5
+ import "effect/Context";
6
+ import * as Exit from "effect/Exit";
7
+ import * as Layer from "effect/Layer";
8
+ import * as ManagedRuntime from "effect/ManagedRuntime";
9
+ import * as Predicate from "effect/Predicate";
10
+ import * as Rec from "effect/Record";
11
+ import * as Result from "effect/Result";
12
+ import * as Scope from "effect/Scope";
5
13
  import * as FetchHttpClient from "effect/http/FetchHttpClient";
6
14
  //#region src/app-runtime.ts
7
15
  /**
@@ -12,6 +20,8 @@ import * as FetchHttpClient from "effect/http/FetchHttpClient";
12
20
  const RequestRuntimeKey = Symbol.for("@thomasfosterau/effect-sveltekit/requestRuntime");
13
21
  /** Read the per-request runtime entry an event carries, if any. */
14
22
  const requestRuntimeEntry = (event) => event.locals?.[RequestRuntimeKey];
23
+ /** Whether a universal load event is a server-side `RequestEvent` (it carries a `request`). */
24
+ const isRequestEvent = (event) => Predicate.hasProperty(event, "request") && Boolean(event.request);
15
25
  /** Layer with the per-request services for a server-side request. */
16
26
  const requestLayer = (event) => {
17
27
  const services = requestServicesFrom(event);
@@ -97,26 +107,26 @@ const makeServerRuntime = (layer, options) => {
97
107
  const { event } = input;
98
108
  const scope = Scope.makeUnsafe();
99
109
  const requestServices = await runtime.runPromise(Layer.buildWithScope(requestLayer(event), scope));
110
+ const requestRuntime = makeRequestRuntime(requestServices);
100
111
  const entry = {
101
112
  owner,
102
- runtime: makeRequestRuntime(requestServices)
113
+ runtime: requestRuntime
103
114
  };
104
115
  event.locals[RequestRuntimeKey] = entry;
105
- try {
106
- return await entry.runtime.runPromise(fn(input).pipe(Effect.withSpan(`handle ${event.route.id ?? "(unknown)"}`, { kind: "server" })));
107
- } finally {
108
- await runtime.runPromise(Scope.close(scope, Exit.void));
109
- }
116
+ const closeScope = () => runtime.runPromise(Scope.close(scope, Exit.void));
117
+ const running = Result.try(() => requestRuntime.runPromise(fn(input).pipe(Effect.withSpan(`handle ${event.route.id ?? "(unknown)"}`, { kind: "server" }))));
118
+ return Result.match(running, {
119
+ onSuccess: (response) => response.finally(closeScope),
120
+ onFailure: (thrown) => closeScope().then(() => {
121
+ throw thrown;
122
+ })
123
+ });
110
124
  };
111
125
  return {
112
126
  runtime,
113
127
  serverLoad: (fn) => (event) => run(event, fn(event).pipe(Effect.withSpan(`serverLoad ${event.route.id ?? "(unknown)"}`, { kind: "server" }))),
114
128
  action,
115
- actions: (actionsMap) => {
116
- const wrapped = {};
117
- for (const [key, fn] of Object.entries(actionsMap)) wrapped[key] = action(fn);
118
- return wrapped;
119
- },
129
+ actions: (actionsMap) => Rec.map(actionsMap, (fn) => action(fn)),
120
130
  handle,
121
131
  handleFetch: (fn) => (args) => run(args.event, fn(args).pipe(Effect.withSpan(`handleFetch ${args.event.route.id ?? "(unknown)"}`, { kind: "server" }))),
122
132
  handleError: (fn) => (args) => run(args.event, fn(args)),
@@ -166,8 +176,7 @@ const makeUniversalRuntime = (layer) => {
166
176
  return {
167
177
  runtime,
168
178
  load: (fn) => (event) => {
169
- const serverEvent = event.request ? event : void 0;
170
- return run(event.fetch, fn(event), serverEvent);
179
+ return run(event.fetch, fn(event), isRequestEvent(event) ? event : void 0);
171
180
  },
172
181
  runPromise: (fetchFn, effect) => run(fetchFn, effect),
173
182
  dispose: () => runtime.dispose()