@thomasfosterau/effect-sveltekit 0.6.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/README.md +16 -13
- 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 +11 -11
- package/dist/Navigation.js +15 -2
- package/dist/Navigation.js.map +1 -1
- package/dist/Remote.d.ts +18 -17
- package/dist/Remote.js +2 -4
- package/dist/Remote.js.map +1 -1
- package/dist/State.d.ts +10 -6
- package/dist/State.js +2 -1
- 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 +9 -10
- package/dist/forms.js +5 -2
- package/dist/forms.js.map +1 -1
- package/dist/internal/app-state.d.ts +16 -14
- package/dist/internal/app-state.js +9 -3
- 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 +20 -18
- package/dist/internal/enhance.js +3 -1
- 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/kit.d.ts +12 -11
- package/dist/kit.js +6 -2
- package/dist/kit.js.map +1 -1
- package/dist/realtime.d.ts +29 -31
- package/dist/realtime.js +23 -4
- 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 +12 -9
package/dist/adapter/assets.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Result from "effect/Result";
|
|
3
|
+
import * as Schema from "effect/Schema";
|
|
2
4
|
import * as FileSystem from "effect/FileSystem";
|
|
3
5
|
import * as Path from "effect/Path";
|
|
4
6
|
import "effect/http/HttpPlatform";
|
|
7
|
+
import * as Option from "effect/Option";
|
|
5
8
|
import * as HttpServerResponse from "effect/http/HttpServerResponse";
|
|
9
|
+
import * as HashSet from "effect/HashSet";
|
|
6
10
|
//#region src/adapter/assets.ts
|
|
7
11
|
/**
|
|
8
12
|
* Pluggable asset serving for the Effect SvelteKit adapter.
|
|
@@ -26,41 +30,52 @@ const IMMUTABLE_HEADERS = { "cache-control": "public, max-age=31536000, immutabl
|
|
|
26
30
|
* Serve static client assets and prerendered pages from a build directory on
|
|
27
31
|
* disk (the Node default). `dir` contains `client/` and `prerendered/`.
|
|
28
32
|
*/
|
|
29
|
-
const fileSystem = (config) =>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
`${pathname}.html`,
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
33
|
+
const fileSystem = (config) => {
|
|
34
|
+
const prerendered = HashSet.fromIterable(config.prerendered);
|
|
35
|
+
return { serveAsset: (request, pathname) => Effect.gen(function* () {
|
|
36
|
+
if (request.method !== "GET" && request.method !== "HEAD") return Option.none();
|
|
37
|
+
const path = yield* Path.Path;
|
|
38
|
+
const fs = yield* FileSystem.FileSystem;
|
|
39
|
+
const clientDir = path.join(config.dir, "client");
|
|
40
|
+
const prerenderedDir = path.join(config.dir, "prerendered");
|
|
41
|
+
const immutablePrefix = `/${config.appPath}/immutable/`;
|
|
42
|
+
/**
|
|
43
|
+
* Serve a file from `root` if `pathname` resolves to an existing file
|
|
44
|
+
* inside it (rejecting path traversal). `Option.none()` otherwise.
|
|
45
|
+
*/
|
|
46
|
+
const serveFile = (root, candidate, headers) => Effect.gen(function* () {
|
|
47
|
+
const filePath = path.join(root, candidate);
|
|
48
|
+
const relative = path.relative(root, filePath);
|
|
49
|
+
if (relative.startsWith("..") || path.isAbsolute(relative)) return Option.none();
|
|
50
|
+
const stat = yield* fs.stat(filePath).pipe(Effect.option);
|
|
51
|
+
if (Option.isNone(stat) || stat.value.type !== "File") return Option.none();
|
|
52
|
+
const response = yield* HttpServerResponse.file(filePath, { headers }).pipe(Effect.orDie);
|
|
53
|
+
return Option.some(response);
|
|
54
|
+
});
|
|
55
|
+
const asset = yield* serveFile(clientDir, pathname, pathname.startsWith(immutablePrefix) ? IMMUTABLE_HEADERS : void 0);
|
|
56
|
+
if (Option.isSome(asset)) return asset;
|
|
57
|
+
if (HashSet.has(prerendered, pathname) || HashSet.has(prerendered, pathname + "/")) {
|
|
58
|
+
const candidates = pathname === "/" ? ["/index.html"] : pathname.endsWith("/") ? [`${pathname}index.html`, `${pathname.slice(0, -1)}.html`] : [
|
|
59
|
+
pathname,
|
|
60
|
+
`${pathname}.html`,
|
|
61
|
+
`${pathname}/index.html`
|
|
62
|
+
];
|
|
63
|
+
return yield* Effect.findFirstFilter(candidates, (candidate) => serveFile(prerenderedDir, candidate).pipe(Effect.map(Result.fromOption(() => candidate))));
|
|
60
64
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
65
|
+
return Option.none();
|
|
66
|
+
}) };
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* A {@link cloudflareAssets} binding's `fetch` rejected. The asset source's
|
|
70
|
+
* error channel is `never`, so this reaches the handler as a DEFECT (a 500),
|
|
71
|
+
* carrying what `fetch` rejected with as `cause`.
|
|
72
|
+
*/
|
|
73
|
+
var AssetFetchError = class extends Schema.TaggedError()("AssetFetchError", {
|
|
74
|
+
/** The request path the binding was asked for. */
|
|
75
|
+
url: Schema.String,
|
|
76
|
+
/** What the binding's `fetch` rejected with, or threw. */
|
|
77
|
+
cause: Schema.Defect()
|
|
78
|
+
}) {};
|
|
64
79
|
/**
|
|
65
80
|
* Serve static assets from a Cloudflare Workers static-assets binding (commonly
|
|
66
81
|
* `env.ASSETS`). The binding's `fetch` resolves client assets and prerendered
|
|
@@ -72,7 +87,13 @@ const fileSystem = (config) => ({ serveAsset: (request, pathname) => Effect.gen(
|
|
|
72
87
|
*/
|
|
73
88
|
const cloudflareAssets = (assets) => ({ serveAsset: (request) => Effect.gen(function* () {
|
|
74
89
|
if (request.method !== "GET" && request.method !== "HEAD") return Option.none();
|
|
75
|
-
const response = yield* Effect.
|
|
90
|
+
const response = yield* Effect.tryPromise({
|
|
91
|
+
try: async () => assets.fetch(request),
|
|
92
|
+
catch: (cause) => new AssetFetchError({
|
|
93
|
+
url: request.url,
|
|
94
|
+
cause
|
|
95
|
+
})
|
|
96
|
+
}).pipe(Effect.orDie);
|
|
76
97
|
if (response.status === 404) return Option.none();
|
|
77
98
|
return Option.some(HttpServerResponse.fromWeb(response));
|
|
78
99
|
}) });
|
|
@@ -82,6 +103,6 @@ const AssetSource = {
|
|
|
82
103
|
cloudflareAssets
|
|
83
104
|
};
|
|
84
105
|
//#endregion
|
|
85
|
-
export { AssetSource, cloudflareAssets, fileSystem };
|
|
106
|
+
export { AssetFetchError, AssetSource, cloudflareAssets, fileSystem };
|
|
86
107
|
|
|
87
108
|
//# sourceMappingURL=assets.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assets.js","names":[],"sources":["../../src/adapter/assets.ts"],"sourcesContent":["/**\n * Pluggable asset serving for the Effect SvelteKit adapter.\n *\n * The SSR core ({@link makeHandler}) is platform-neutral: it falls through to an\n * injected {@link AssetSource} for static client assets and prerendered pages,\n * rather than reading the file system directly. This lets the same SvelteKit\n * `HttpApp` run on a Node server (assets from disk) or on Cloudflare Workers\n * (assets from the `env.ASSETS` binding, or any custom source — R2, KV, a CDN\n * passthrough).\n *\n * Ship several sources as equals and let the adapter (or the caller) pick:\n *\n * - {@link fileSystem} — serve `client/` + `prerendered/` from disk (Node\n * default). Requires `FileSystem` / `Path` / `HttpPlatform`.\n * - {@link cloudflareAssets} — serve from a Workers static-assets binding\n * (`env.ASSETS`). Requires nothing.\n */\n\nimport
|
|
1
|
+
{"version":3,"file":"assets.js","names":[],"sources":["../../src/adapter/assets.ts"],"sourcesContent":["/**\n * Pluggable asset serving for the Effect SvelteKit adapter.\n *\n * The SSR core ({@link makeHandler}) is platform-neutral: it falls through to an\n * injected {@link AssetSource} for static client assets and prerendered pages,\n * rather than reading the file system directly. This lets the same SvelteKit\n * `HttpApp` run on a Node server (assets from disk) or on Cloudflare Workers\n * (assets from the `env.ASSETS` binding, or any custom source — R2, KV, a CDN\n * passthrough).\n *\n * Ship several sources as equals and let the adapter (or the caller) pick:\n *\n * - {@link fileSystem} — serve `client/` + `prerendered/` from disk (Node\n * default). Requires `FileSystem` / `Path` / `HttpPlatform`.\n * - {@link cloudflareAssets} — serve from a Workers static-assets binding\n * (`env.ASSETS`). Requires nothing.\n */\n\nimport * as Effect from \"effect/Effect\";\nimport * as HashSet from \"effect/HashSet\";\nimport * as Option from \"effect/Option\";\nimport * as Result from \"effect/Result\";\nimport * as Schema from \"effect/Schema\";\nimport * as FileSystem from \"effect/FileSystem\";\nimport * as Path from \"effect/Path\";\nimport * as HttpPlatform from \"effect/http/HttpPlatform\";\nimport * as HttpServerResponse from \"effect/http/HttpServerResponse\";\n\n/**\n * A source of static assets. `serveAsset` returns the response for an asset\n * request, or `Option.none()` when the request is not an asset (so the SSR core\n * continues to server-side rendering). `R` is the set of services the source\n * needs (e.g. `FileSystem | Path | HttpPlatform` for {@link fileSystem}, or\n * `never` for {@link cloudflareAssets}).\n */\nexport interface AssetSource<R = never> {\n readonly serveAsset: (\n request: Request,\n pathname: string,\n ) => Effect.Effect<Option.Option<HttpServerResponse.HttpServerResponse>, never, R>;\n}\n\n/** The services a file-system {@link AssetSource} requires. */\nexport type FileSystemAssetServices = FileSystem.FileSystem | Path.Path | HttpPlatform.HttpPlatform;\n\nconst IMMUTABLE_HEADERS = { \"cache-control\": \"public, max-age=31536000, immutable\" };\n\n/**\n * Serve static client assets and prerendered pages from a build directory on\n * disk (the Node default). `dir` contains `client/` and `prerendered/`.\n */\nexport const fileSystem = (config: {\n /** Absolute path of the build output directory (contains `client/`, `prerendered/`). */\n readonly dir: string;\n /** The configured `manifest.appPath` — its `immutable/` subtree gets immutable caching. */\n readonly appPath: string;\n /**\n * The prerendered paths exported by the build output (the build's\n * `prerendered` `Set`, or any iterable of paths).\n */\n readonly prerendered: Iterable<string>;\n}): AssetSource<FileSystemAssetServices> => {\n const prerendered = HashSet.fromIterable(config.prerendered);\n return {\n serveAsset: (request, pathname) =>\n Effect.gen(function* () {\n // Only GET/HEAD reach static assets.\n if (request.method !== \"GET\" && request.method !== \"HEAD\") return Option.none();\n\n const path = yield* Path.Path;\n const fs = yield* FileSystem.FileSystem;\n\n const clientDir = path.join(config.dir, \"client\");\n const prerenderedDir = path.join(config.dir, \"prerendered\");\n const immutablePrefix = `/${config.appPath}/immutable/`;\n\n /**\n * Serve a file from `root` if `pathname` resolves to an existing file\n * inside it (rejecting path traversal). `Option.none()` otherwise.\n */\n const serveFile = (\n root: string,\n candidate: string,\n headers?: Record<string, string>,\n ): Effect.Effect<\n Option.Option<HttpServerResponse.HttpServerResponse>,\n never,\n FileSystemAssetServices\n > =>\n Effect.gen(function* () {\n const filePath = path.join(root, candidate);\n const relative = path.relative(root, filePath);\n if (relative.startsWith(\"..\") || path.isAbsolute(relative)) return Option.none();\n\n const stat = yield* fs.stat(filePath).pipe(Effect.option);\n if (Option.isNone(stat) || stat.value.type !== \"File\") return Option.none();\n\n const response = yield* HttpServerResponse.file(filePath, { headers }).pipe(\n Effect.orDie,\n );\n return Option.some(response);\n });\n\n // 1. Static client assets (hashed build assets get immutable caching).\n const isImmutable = pathname.startsWith(immutablePrefix);\n const asset = yield* serveFile(\n clientDir,\n pathname,\n isImmutable ? IMMUTABLE_HEADERS : undefined,\n );\n if (Option.isSome(asset)) return asset;\n\n // 2. Prerendered pages.\n if (HashSet.has(prerendered, pathname) || HashSet.has(prerendered, pathname + \"/\")) {\n const candidates =\n pathname === \"/\"\n ? [\"/index.html\"]\n : pathname.endsWith(\"/\")\n ? [`${pathname}index.html`, `${pathname.slice(0, -1)}.html`]\n : [pathname, `${pathname}.html`, `${pathname}/index.html`];\n // The first candidate that exists, tried in order.\n return yield* Effect.findFirstFilter(candidates, (candidate) =>\n serveFile(prerenderedDir, candidate).pipe(\n Effect.map(Result.fromOption(() => candidate)),\n ),\n );\n }\n\n return Option.none();\n }),\n };\n};\n\n/**\n * A {@link cloudflareAssets} binding's `fetch` rejected. The asset source's\n * error channel is `never`, so this reaches the handler as a DEFECT (a 500),\n * carrying what `fetch` rejected with as `cause`.\n */\nexport class AssetFetchError extends Schema.TaggedError<AssetFetchError>()(\"AssetFetchError\", {\n /** The request path the binding was asked for. */\n url: Schema.String,\n /** What the binding's `fetch` rejected with, or threw. */\n cause: Schema.Defect(),\n}) {}\n\n/**\n * Serve static assets from a Cloudflare Workers static-assets binding (commonly\n * `env.ASSETS`). The binding's `fetch` resolves client assets and prerendered\n * pages uploaded by the deployment; a 404 from it means \"not an asset\", so the\n * SSR core continues to server-side rendering.\n *\n * This is one provided convenience, not the assumption: pass any object with a\n * `fetch` (R2, KV, a CDN passthrough) or a custom {@link AssetSource}.\n */\nexport const cloudflareAssets = (assets: {\n fetch: (request: Request) => Promise<Response> | Response;\n}): AssetSource => ({\n serveAsset: (request) =>\n Effect.gen(function* () {\n if (request.method !== \"GET\" && request.method !== \"HEAD\") return Option.none();\n const response = yield* Effect.tryPromise({\n try: async () => assets.fetch(request),\n catch: (cause) => new AssetFetchError({ url: request.url, cause }),\n }).pipe(Effect.orDie);\n if (response.status === 404) return Option.none();\n return Option.some(HttpServerResponse.fromWeb(response));\n }),\n});\n\n/** The {@link AssetSource} constructors, grouped for the adapter API. */\nexport const AssetSource = {\n fileSystem,\n cloudflareAssets,\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CA,MAAM,oBAAoB,EAAE,iBAAiB,sCAAsC;;;;;AAMnF,MAAa,cAAc,WAUiB;CAC1C,MAAM,cAAc,QAAQ,aAAa,OAAO,WAAW;CAC3D,OAAO,EACL,aAAa,SAAS,aACpB,OAAO,IAAI,aAAa;EAEtB,IAAI,QAAQ,WAAW,SAAS,QAAQ,WAAW,QAAQ,OAAO,OAAO,KAAK;EAE9E,MAAM,OAAO,OAAO,KAAK;EACzB,MAAM,KAAK,OAAO,WAAW;EAE7B,MAAM,YAAY,KAAK,KAAK,OAAO,KAAK,QAAQ;EAChD,MAAM,iBAAiB,KAAK,KAAK,OAAO,KAAK,aAAa;EAC1D,MAAM,kBAAkB,IAAI,OAAO,QAAQ;;;;;EAM3C,MAAM,aACJ,MACA,WACA,YAMA,OAAO,IAAI,aAAa;GACtB,MAAM,WAAW,KAAK,KAAK,MAAM,SAAS;GAC1C,MAAM,WAAW,KAAK,SAAS,MAAM,QAAQ;GAC7C,IAAI,SAAS,WAAW,IAAI,KAAK,KAAK,WAAW,QAAQ,GAAG,OAAO,OAAO,KAAK;GAE/E,MAAM,OAAO,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,KAAK,OAAO,MAAM;GACxD,IAAI,OAAO,OAAO,IAAI,KAAK,KAAK,MAAM,SAAS,QAAQ,OAAO,OAAO,KAAK;GAE1E,MAAM,WAAW,OAAO,mBAAmB,KAAK,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC,KACrE,OAAO,KACT;GACA,OAAO,OAAO,KAAK,QAAQ;EAC7B,CAAC;EAIH,MAAM,QAAQ,OAAO,UACnB,WACA,UAHkB,SAAS,WAAW,eAI5B,IAAI,oBAAoB,KAAA,CACpC;EACA,IAAI,OAAO,OAAO,KAAK,GAAG,OAAO;EAGjC,IAAI,QAAQ,IAAI,aAAa,QAAQ,KAAK,QAAQ,IAAI,aAAa,WAAW,GAAG,GAAG;GAClF,MAAM,aACJ,aAAa,MACT,CAAC,aAAa,IACd,SAAS,SAAS,GAAG,IACnB,CAAC,GAAG,SAAS,aAAa,GAAG,SAAS,MAAM,GAAG,EAAE,EAAE,MAAM,IACzD;IAAC;IAAU,GAAG,SAAS;IAAQ,GAAG,SAAS;GAAY;GAE/D,OAAO,OAAO,OAAO,gBAAgB,aAAa,cAChD,UAAU,gBAAgB,SAAS,CAAC,CAAC,KACnC,OAAO,IAAI,OAAO,iBAAiB,SAAS,CAAC,CAC/C,CACF;EACF;EAEA,OAAO,OAAO,KAAK;CACrB,CAAC,EACL;AACF;;;;;;AAOA,IAAa,kBAAb,cAAqC,OAAO,YAA6B,CAAC,CAAC,mBAAmB;;CAE5F,KAAK,OAAO;;CAEZ,OAAO,OAAO,OAAO;AACvB,CAAC,CAAC,CAAC,CAAC;;;;;;;;;;AAWJ,MAAa,oBAAoB,YAEb,EAClB,aAAa,YACX,OAAO,IAAI,aAAa;CACtB,IAAI,QAAQ,WAAW,SAAS,QAAQ,WAAW,QAAQ,OAAO,OAAO,KAAK;CAC9E,MAAM,WAAW,OAAO,OAAO,WAAW;EACxC,KAAK,YAAY,OAAO,MAAM,OAAO;EACrC,QAAQ,UAAU,IAAI,gBAAgB;GAAE,KAAK,QAAQ;GAAK;EAAM,CAAC;CACnE,CAAC,CAAC,CAAC,KAAK,OAAO,KAAK;CACpB,IAAI,SAAS,WAAW,KAAK,OAAO,OAAO,KAAK;CAChD,OAAO,OAAO,KAAK,mBAAmB,QAAQ,QAAQ,CAAC;AACzD,CAAC,EACL;;AAGA,MAAa,cAAc;CACzB;CACA;AACF"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { AssetSource, FileSystemAssetServices } from "./assets.js";
|
|
2
|
-
import
|
|
1
|
+
import { AssetFetchError, AssetSource, FileSystemAssetServices } from "./assets.js";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import * as Layer from "effect/Layer";
|
|
3
4
|
import { Server } from "@sveltejs/kit";
|
|
5
|
+
import * as Schema from "effect/Schema";
|
|
4
6
|
import * as HttpServerRequest from "effect/http/HttpServerRequest";
|
|
5
7
|
import * as HttpServerResponse from "effect/http/HttpServerResponse";
|
|
6
8
|
//#region src/adapter/handler.d.ts
|
|
@@ -9,16 +11,16 @@ import * as HttpServerResponse from "effect/http/HttpServerResponse";
|
|
|
9
11
|
* from the file system (the Node default). All of them are provided by
|
|
10
12
|
* `NodeHttpServer.layer` from `@effect/platform-node`.
|
|
11
13
|
*/
|
|
12
|
-
type SvelteKitHttpAppServices = FileSystemAssetServices;
|
|
14
|
+
export type SvelteKitHttpAppServices = FileSystemAssetServices;
|
|
13
15
|
/**
|
|
14
16
|
* The SvelteKit application as a composable Effect HTTP handler: an effect that
|
|
15
17
|
* produces an {@link HttpServerResponse.HttpServerResponse} for the current
|
|
16
18
|
* request. The `HttpServerRequest` is supplied per request by the server. `R`
|
|
17
19
|
* is the asset source's services (defaults to the file-system services).
|
|
18
20
|
*/
|
|
19
|
-
type SvelteKitHttpApp<R = SvelteKitHttpAppServices> = Effect.Effect<HttpServerResponse.HttpServerResponse, never, R | HttpServerRequest.HttpServerRequest>;
|
|
21
|
+
export type SvelteKitHttpApp<R = SvelteKitHttpAppServices> = Effect.Effect<HttpServerResponse.HttpServerResponse, never, R | HttpServerRequest.HttpServerRequest>;
|
|
20
22
|
/** The SvelteKit build output {@link makeHandler} serves. */
|
|
21
|
-
interface SvelteKitHandlerOptions {
|
|
23
|
+
export interface SvelteKitHandlerOptions {
|
|
22
24
|
/** The SvelteKit `server` instance exported by the build output (`./server.js`). */
|
|
23
25
|
readonly server: Server;
|
|
24
26
|
/**
|
|
@@ -28,8 +30,8 @@ interface SvelteKitHandlerOptions {
|
|
|
28
30
|
* headers.
|
|
29
31
|
*/
|
|
30
32
|
readonly appPath: string;
|
|
31
|
-
/** The
|
|
32
|
-
readonly prerendered:
|
|
33
|
+
/** The prerendered paths exported by the build output (`./manifest.js`'s `Set`, or any iterable). */
|
|
34
|
+
readonly prerendered: Iterable<string>;
|
|
33
35
|
/** The configured `paths.base`, exported by the build output (`./manifest.js`). */
|
|
34
36
|
readonly base: string;
|
|
35
37
|
/** Absolute path of the build output directory (contains `client/`, `server/`, `prerendered/`). */
|
|
@@ -40,7 +42,7 @@ interface SvelteKitHandlerOptions {
|
|
|
40
42
|
readonly envPrefix?: string;
|
|
41
43
|
}
|
|
42
44
|
/** Options for the platform-neutral SSR core, {@link makeHandlerWith}. */
|
|
43
|
-
interface SvelteKitNeutralHandlerOptions<RAssets> {
|
|
45
|
+
export interface SvelteKitNeutralHandlerOptions<RAssets> {
|
|
44
46
|
/** The SvelteKit `server` instance exported by the build output (`./server.js`). */
|
|
45
47
|
readonly server: Server;
|
|
46
48
|
/** Environment variables passed to the SvelteKit server. */
|
|
@@ -83,7 +85,20 @@ interface SvelteKitNeutralHandlerOptions<RAssets> {
|
|
|
83
85
|
* NodeRuntime.runMain(Layer.launch(serverLayer));
|
|
84
86
|
* ```
|
|
85
87
|
*/
|
|
86
|
-
declare const makeHandler: (options: SvelteKitHandlerOptions) => Effect.Effect<SvelteKitHttpApp, never, SvelteKitHttpAppServices>;
|
|
88
|
+
export declare const makeHandler: (options: SvelteKitHandlerOptions) => Effect.Effect<SvelteKitHttpApp, never, SvelteKitHttpAppServices>;
|
|
89
|
+
declare const SvelteKitServerError_base: Schema.Class<SvelteKitServerError, Schema.TaggedStruct<"SvelteKitServerError", {
|
|
90
|
+
/** Which `Server` method rejected. */
|
|
91
|
+
readonly operation: Schema.Literals<readonly ["init", "respond"]>;
|
|
92
|
+
/** What the method rejected with, or threw. */
|
|
93
|
+
readonly cause: Schema.Defect;
|
|
94
|
+
}>, import("effect/Cause").YieldableError>;
|
|
95
|
+
/**
|
|
96
|
+
* The SvelteKit server's `init` or `respond` rejected. SvelteKit turns a
|
|
97
|
+
* route's own errors into responses, so a rejection is a bug in the server
|
|
98
|
+
* build; the handler's error channel is `never`, so this reaches the platform
|
|
99
|
+
* as a DEFECT (a 500), carrying what SvelteKit rejected with as `cause`.
|
|
100
|
+
*/
|
|
101
|
+
export declare class SvelteKitServerError extends SvelteKitServerError_base {}
|
|
87
102
|
/**
|
|
88
103
|
* The platform-neutral SSR core. Like {@link makeHandler}, but the asset source
|
|
89
104
|
* and the server-asset `read` capability are injected, so the same SvelteKit
|
|
@@ -114,7 +129,7 @@ declare const makeHandler: (options: SvelteKitHandlerOptions) => Effect.Effect<S
|
|
|
114
129
|
* };
|
|
115
130
|
* ```
|
|
116
131
|
*/
|
|
117
|
-
declare const makeHandlerWith: <RAssets = never>(options: SvelteKitNeutralHandlerOptions<RAssets>) => Effect.Effect<SvelteKitHttpApp<RAssets>, never, never>;
|
|
132
|
+
export declare const makeHandlerWith: <RAssets = never>(options: SvelteKitNeutralHandlerOptions<RAssets>) => Effect.Effect<SvelteKitHttpApp<RAssets>, never, never>;
|
|
118
133
|
/**
|
|
119
134
|
* Convert a SvelteKit `HttpApp` to a Web `fetch` handler, providing the asset
|
|
120
135
|
* source's services with `layer`. Use this for a Workers `fetch` export or any
|
|
@@ -128,7 +143,7 @@ declare const makeHandlerWith: <RAssets = never>(options: SvelteKitNeutralHandle
|
|
|
128
143
|
* );
|
|
129
144
|
* ```
|
|
130
145
|
*/
|
|
131
|
-
declare const toWebHandler: <RAssets, E>(app: Effect.Effect<SvelteKitHttpApp<RAssets>, never, never>, layer: Layer.Layer<RAssets, E>) => ((request: Request) => Promise<Response>);
|
|
146
|
+
export declare const toWebHandler: <RAssets, E>(app: Effect.Effect<SvelteKitHttpApp<RAssets>, never, never>, layer: Layer.Layer<RAssets, E>) => ((request: Request) => Promise<Response>);
|
|
132
147
|
//#endregion
|
|
133
|
-
export { AssetSource, type FileSystemAssetServices
|
|
148
|
+
export { AssetFetchError, AssetSource, type FileSystemAssetServices };
|
|
134
149
|
//# sourceMappingURL=handler.d.ts.map
|
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";
|