@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.
- package/LICENSE.md +9 -0
- package/README.md +178 -83
- package/dist/Hooks.d.ts +3 -3
- package/dist/Hooks.js +1 -1
- package/dist/Hooks.js.map +1 -1
- package/dist/Navigation.d.ts +70 -17
- package/dist/Navigation.js +93 -19
- package/dist/Navigation.js.map +1 -1
- package/dist/Remote.d.ts +54 -35
- package/dist/Remote.js +22 -11
- package/dist/Remote.js.map +1 -1
- package/dist/State.d.ts +79 -6
- package/dist/State.js +117 -27
- package/dist/State.js.map +1 -1
- package/dist/adapter/assets.d.ts +24 -7
- package/dist/adapter/assets.js +58 -37
- package/dist/adapter/assets.js.map +1 -1
- package/dist/adapter/handler.d.ts +27 -12
- package/dist/adapter/handler.js +53 -26
- package/dist/adapter/handler.js.map +1 -1
- package/dist/adapter/index.d.ts +3 -3
- package/dist/adapter/index.js +1 -1
- package/dist/adapter/index.js.map +1 -1
- package/dist/adapter/serve.d.ts +6 -5
- package/dist/adapter/serve.js +3 -1
- package/dist/adapter/serve.js.map +1 -1
- package/dist/api-client.d.ts +3 -4
- package/dist/api-client.js +2 -1
- package/dist/api-client.js.map +1 -1
- package/dist/app-runtime.d.ts +12 -9
- package/dist/app-runtime.js +23 -14
- package/dist/app-runtime.js.map +1 -1
- package/dist/client/Hooks.d.ts +4 -4
- package/dist/client/Hooks.js +2 -1
- package/dist/client/Hooks.js.map +1 -1
- package/dist/client.d.ts +2 -2
- package/dist/config.d.ts +7 -5
- package/dist/config.js +5 -34
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +14 -16
- package/dist/errors.js +20 -12
- package/dist/errors.js.map +1 -1
- package/dist/forms.d.ts +70 -8
- package/dist/forms.js +69 -5
- package/dist/forms.js.map +1 -1
- package/dist/internal/app-state.d.ts +42 -5
- package/dist/internal/app-state.js +64 -15
- package/dist/internal/app-state.js.map +1 -1
- package/dist/internal/auto.d.ts +23 -14
- package/dist/internal/auto.js +50 -40
- package/dist/internal/auto.js.map +1 -1
- package/dist/internal/enhance.d.ts +114 -14
- package/dist/internal/enhance.js +33 -7
- package/dist/internal/enhance.js.map +1 -1
- package/dist/internal/error.d.ts +13 -0
- package/dist/internal/error.js +4 -3
- package/dist/internal/error.js.map +1 -1
- package/dist/internal/navigation-events.js +3 -1
- package/dist/internal/navigation-events.js.map +1 -1
- package/dist/internal/remote-run.d.ts +6 -6
- package/dist/internal/remote-run.js +13 -16
- package/dist/internal/remote-run.js.map +1 -1
- package/dist/internal/remote-validators.js +4 -3
- package/dist/internal/remote-validators.js.map +1 -1
- package/dist/internal/route-params.d.ts +1 -2
- package/dist/internal/sse.js +2 -1
- package/dist/internal/sse.js.map +1 -1
- package/dist/internal/watch.svelte.js +33 -0
- package/dist/internal/watch.svelte.js.map +1 -0
- package/dist/kit.d.ts +12 -11
- package/dist/kit.js +6 -2
- package/dist/kit.js.map +1 -1
- package/dist/realtime.d.ts +49 -30
- package/dist/realtime.js +90 -46
- package/dist/realtime.js.map +1 -1
- package/dist/remote-functions.d.ts +34 -18
- package/dist/remote-functions.js +78 -46
- package/dist/remote-functions.js.map +1 -1
- package/dist/remote-reactive.d.ts +8 -4
- package/dist/remote-reactive.js.map +1 -1
- package/dist/request-parse.d.ts +13 -13
- package/dist/request-parse.js +29 -15
- package/dist/request-parse.js.map +1 -1
- package/dist/request-runtime.d.ts +16 -11
- package/dist/request-runtime.js +28 -29
- package/dist/request-runtime.js.map +1 -1
- package/dist/request-services.d.ts +10 -8
- package/dist/request-services.js +3 -1
- package/dist/request-services.js.map +1 -1
- package/dist/response-headers.d.ts +2 -3
- package/dist/response-headers.js +2 -1
- package/dist/response-headers.js.map +1 -1
- package/dist/runtime.d.ts +8 -5
- package/dist/runtime.js +4 -1
- package/dist/runtime.js.map +1 -1
- package/dist/server/Endpoint.d.ts +17 -11
- package/dist/server/Endpoint.js +18 -4
- package/dist/server/Endpoint.js.map +1 -1
- package/dist/server/Hooks.d.ts +6 -6
- package/dist/server/Hooks.js +1 -1
- package/dist/server/Hooks.js.map +1 -1
- package/dist/server.d.ts +8 -7
- package/dist/server.js +8 -8
- package/dist/server.js.map +1 -1
- package/dist/streamed-load.d.ts +2 -3
- package/dist/streamed-load.js +1 -1
- package/dist/streamed-load.js.map +1 -1
- package/dist/testing.d.ts +15 -14
- package/dist/testing.js +27 -7
- package/dist/testing.js.map +1 -1
- package/dist/transport.d.ts +6 -7
- package/dist/transport.js +3 -6
- package/dist/transport.js.map +1 -1
- package/dist/universal.d.ts +3 -3
- package/dist/universal.js +1 -1
- package/dist/universal.js.map +1 -1
- package/dist/vite.d.ts +4 -4
- package/dist/vite.js +102 -103
- package/dist/vite.js.map +1 -1
- package/package.json +14 -11
- package/LICENSE +0 -21
package/dist/adapter/handler.js
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
import { AssetSource } from "./assets.js";
|
|
2
|
-
import
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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.
|
|
137
|
-
|
|
138
|
-
|
|
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
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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.
|
|
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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"}
|
package/dist/adapter/index.d.ts
CHANGED
|
@@ -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 {
|
|
43
|
+
export { effectAdapter as default };
|
|
44
44
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/adapter/index.js
CHANGED
|
@@ -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
|
|
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
|
|
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"}
|
package/dist/adapter/serve.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { SvelteKitHttpApp } from "./handler.js";
|
|
2
|
-
import
|
|
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 {
|
|
46
|
+
export {};
|
|
46
47
|
//# sourceMappingURL=serve.d.ts.map
|
package/dist/adapter/serve.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import
|
|
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
|
|
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"}
|
package/dist/api-client.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import
|
|
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
|
package/dist/api-client.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
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
|
package/dist/api-client.js.map
CHANGED
|
@@ -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
|
|
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"}
|
package/dist/app-runtime.d.ts
CHANGED
|
@@ -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
|
|
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
|
package/dist/app-runtime.js
CHANGED
|
@@ -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
|
|
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:
|
|
113
|
+
runtime: requestRuntime
|
|
103
114
|
};
|
|
104
115
|
event.locals[RequestRuntimeKey] = entry;
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
-
|
|
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()
|