@thomasfosterau/effect-sveltekit 0.3.0 → 0.4.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 +3 -3
- package/dist/Hooks.d.ts +4 -5
- package/dist/Hooks.js +3 -1
- package/dist/Hooks.js.map +1 -1
- package/dist/Navigation.d.ts +1 -3
- package/dist/Navigation.js +1 -1
- package/dist/Remote.d.ts +1 -3
- package/dist/Remote.js +1 -1
- package/dist/Remote.js.map +1 -1
- package/dist/State.d.ts +1 -3
- package/dist/State.js +1 -1
- package/dist/adapter/assets.d.ts +7 -5
- package/dist/adapter/assets.js +3 -3
- package/dist/adapter/assets.js.map +1 -1
- package/dist/adapter/handler.d.ts +4 -5
- package/dist/adapter/handler.js +12 -12
- package/dist/adapter/handler.js.map +1 -1
- package/dist/adapter/index.d.ts +1 -2
- package/dist/adapter/index.js +3 -3
- package/dist/adapter/index.js.map +1 -1
- package/dist/adapter/serve.d.ts +0 -1
- package/dist/adapter/serve.js +4 -4
- package/dist/adapter/serve.js.map +1 -1
- package/dist/api-client.d.ts +5 -6
- package/dist/api-client.js +2 -2
- package/dist/api-client.js.map +1 -1
- package/dist/app-runtime.d.ts +1 -2
- package/dist/app-runtime.js +3 -2
- package/dist/app-runtime.js.map +1 -1
- package/dist/client/Hooks.d.ts +1 -3
- package/dist/client/Hooks.js +1 -1
- package/dist/config.d.ts +2 -3
- package/dist/config.js +5 -5
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +88 -0
- package/dist/errors.js +126 -0
- package/dist/errors.js.map +1 -0
- package/dist/forms.d.ts +2 -3
- package/dist/forms.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/internal/app-state.d.ts +1 -2
- package/dist/internal/app-state.js +1 -1
- package/dist/internal/auto.d.ts +0 -1
- package/dist/internal/auto.js.map +1 -1
- package/dist/internal/enhance.d.ts +0 -1
- package/dist/internal/enhance.js.map +1 -1
- package/dist/internal/error.js +1 -1
- package/dist/internal/remote-run.d.ts +2 -2
- package/dist/internal/remote-run.js.map +1 -1
- package/dist/internal/remote-validators.js +1 -1
- package/dist/internal/route-params.d.ts +0 -1
- package/dist/kit.d.ts +2 -3
- package/dist/realtime.d.ts +3 -5
- package/dist/realtime.js +1 -1
- package/dist/realtime.js.map +1 -1
- package/dist/{remote.server.d.ts → remote-functions.d.ts} +4 -5
- package/dist/{remote.server.js → remote-functions.js} +4 -4
- package/dist/remote-functions.js.map +1 -0
- package/dist/remote-reactive.d.ts +1 -2
- package/dist/remote-reactive.js +1 -1
- package/dist/remote-reactive.js.map +1 -1
- package/dist/request-parse.d.ts +1 -2
- package/dist/request-parse.js.map +1 -1
- package/dist/request-runtime.d.ts +0 -1
- package/dist/request-runtime.js.map +1 -1
- package/dist/request-services.d.ts +0 -1
- package/dist/request-services.js.map +1 -1
- package/dist/response-headers.d.ts +24 -0
- package/dist/response-headers.js +35 -0
- package/dist/response-headers.js.map +1 -0
- package/dist/runtime.d.ts +2 -3
- package/dist/runtime.js +3 -3
- package/dist/runtime.js.map +1 -1
- package/dist/server/Endpoint.d.ts +18 -15
- package/dist/server/Endpoint.js +10 -9
- package/dist/server/Endpoint.js.map +1 -1
- package/dist/server/Hooks.d.ts +1 -3
- package/dist/server/Hooks.js +1 -1
- package/dist/server/Hooks.js.map +1 -1
- package/dist/server.d.ts +6 -5
- package/dist/server.js +6 -4
- package/dist/server.js.map +1 -1
- package/dist/streamed-load.d.ts +0 -1
- package/dist/streamed-load.js.map +1 -1
- package/dist/testing.d.ts +0 -1
- package/dist/testing.js.map +1 -1
- package/dist/transport.d.ts +0 -1
- package/dist/universal.d.ts +3 -4
- package/dist/universal.js +3 -3
- package/dist/universal.js.map +1 -1
- package/dist/vite.d.ts +0 -1
- package/dist/vite.js +2 -2
- package/dist/vite.js.map +1 -1
- package/package.json +8 -5
- package/dist/remote.server.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-services.js","names":[],"sources":["../src/request-services.ts"],"sourcesContent":["/**\n * Effect-native services for the three per-request surfaces on a SvelteKit\n * `RequestEvent` — cookies, response headers, and locals — each as a tagged\n * `Context.Service` that can be `yield*`-ed in any handler effect and mocked\n * in tests with `Layer.succeed`.\n *\n * All three services are provided automatically as part of the\n * {@link SvelteKitServices} per-request context when using\n * {@link makeServerRuntime}, the standalone `serverLoad`/`action`/`endpoint`\n * wrappers, or {@link makeRuntimeAdapter}. No extra layer setup is required.\n *\n * @example\n * ```ts\n * import { Effect } from \"effect\";\n * import {\n * SvelteKitCookies,\n * SvelteKitResponseHeaders,\n * SvelteKitLocals,\n * } from \"@thomasfosterau/effect-sveltekit/server\";\n *\n * export const load = serverLoad(() =>\n * Effect.gen(function* () {\n * const cookies = yield* SvelteKitCookies;\n * const session = yield* cookies.get(\"session\");\n *\n * const headers = yield* SvelteKitResponseHeaders;\n * yield* headers.set({ \"cache-control\": \"max-age=60, s-maxage=300\" });\n *\n * const locals = yield* SvelteKitLocals;\n * // locals is App.Locals — typed to your augmented interface\n * const user = locals.user;\n *\n * return { user };\n * }),\n * );\n * ```\n *\n * ## Testing\n *\n * Because these are tagged services, they can be replaced with stubs via\n * `Layer.succeed` in unit tests without involving a real `RequestEvent`:\n *\n * ```ts\n * import { Layer } from \"effect\";\n * import { SvelteKitCookies } from \"@thomasfosterau/effect-sveltekit/server\";\n * import { runServerLoad, TestRequestEvent } from \"@thomasfosterau/effect-sveltekit/testing\";\n *\n * const MockCookies = Layer.succeed(SvelteKitCookies, {\n * get: (name) => Effect.succeed(name === \"session\" ? \"tok_test\" : undefined),\n * getAll: () => Effect.succeed([{ name: \"session\", value: \"tok_test\" }]),\n * set: () => Effect.void,\n * delete: () => Effect.void,\n * serialize: (n, v) => Effect.succeed(`${n}=${v}`),\n * });\n *\n * const data = await runServerLoad(myLoadFn, TestRequestEvent(), { layer: MockCookies });\n * ```\n */\n\nimport type { Cookies, RequestEvent } from \"@sveltejs/kit\";\nimport { Context, Effect, Layer } from \"effect\";\nimport { SvelteKitRequestEvent } from \"./runtime.js\";\n\n// ─── SvelteKitCookies ─────────────────────────────────────────────────────────\n\n/**\n * The Effect-native interface exposed by {@link SvelteKitCookies}. Each method\n * mirrors the corresponding `Cookies` method from `@sveltejs/kit` but returns\n * an `Effect` rather than a raw value or `void`.\n */\nexport interface SvelteKitCookiesInterface {\n /** Get a cookie by name. Returns `undefined` when the cookie is absent. */\n readonly get: (...args: Parameters<Cookies[\"get\"]>) => Effect.Effect<ReturnType<Cookies[\"get\"]>>;\n /** Get all cookies as `{ name, value }` pairs. */\n readonly getAll: (\n ...args: Parameters<Cookies[\"getAll\"]>\n ) => Effect.Effect<ReturnType<Cookies[\"getAll\"]>>;\n /** Set a cookie (adds a `set-cookie` response header). */\n readonly set: (...args: Parameters<Cookies[\"set\"]>) => Effect.Effect<void>;\n /** Delete a cookie by setting it to an empty value with a past expiry. */\n readonly delete: (...args: Parameters<Cookies[\"delete\"]>) => Effect.Effect<void>;\n /** Serialize a cookie into a `Set-Cookie` string without adding it to the response. */\n readonly serialize: (\n ...args: Parameters<Cookies[\"serialize\"]>\n ) => Effect.Effect<ReturnType<Cookies[\"serialize\"]>>;\n}\n\n/**\n * An Effect service wrapping the `RequestEvent.cookies` API.\n *\n * Available automatically in every server handler effect (it is part of\n * {@link SvelteKitServices}). Use `yield* SvelteKitCookies` to obtain the\n * service; call its methods (each returns an `Effect`) to read or write\n * cookies.\n *\n * @example\n * ```ts\n * const session = yield* (yield* SvelteKitCookies).get(\"session\");\n * ```\n */\nexport class SvelteKitCookies extends Context.Service<\n SvelteKitCookies,\n SvelteKitCookiesInterface\n>()(\"@thomasfosterau/effect-sveltekit/SvelteKitCookies\") {\n /**\n * Layer that builds the `SvelteKitCookies` service from the current\n * {@link SvelteKitRequestEvent}. Included in the per-request context\n * automatically; expose as a standalone layer for custom setups.\n */\n static readonly layer: Layer.Layer<SvelteKitCookies, never, SvelteKitRequestEvent> = Layer.effect(\n SvelteKitCookies,\n Effect.gen(function* () {\n const event = yield* SvelteKitRequestEvent;\n const { cookies } = event;\n return {\n get: (...args) => Effect.sync(() => cookies.get(...args)),\n getAll: (...args) => Effect.sync(() => cookies.getAll(...args)),\n set: (...args) => Effect.sync(() => cookies.set(...args)),\n delete: (...args) => Effect.sync(() => cookies.delete(...args)),\n serialize: (...args) => Effect.sync(() => cookies.serialize(...args)),\n };\n }),\n );\n}\n\n// ─── SvelteKitResponseHeaders ─────────────────────────────────────────────────\n\n/**\n * The Effect-native interface exposed by {@link SvelteKitResponseHeaders}.\n */\nexport interface SvelteKitResponseHeadersInterface {\n /**\n * Set one or more response headers. Equivalent to `event.setHeaders(headers)`.\n *\n * Note: You cannot set `set-cookie` headers here — use\n * {@link SvelteKitCookies} instead.\n */\n readonly set: (headers: Record<string, string>) => Effect.Effect<void>;\n}\n\n/**\n * An Effect service wrapping the `RequestEvent.setHeaders` API.\n *\n * Available automatically in every server handler effect. Use\n * `yield* SvelteKitResponseHeaders` to obtain the service, then call\n * `headers.set(...)`.\n *\n * @example\n * ```ts\n * const headers = yield* SvelteKitResponseHeaders;\n * yield* headers.set({ \"cache-control\": \"max-age=60, s-maxage=300\" });\n * ```\n */\nexport class SvelteKitResponseHeaders extends Context.Service<\n SvelteKitResponseHeaders,\n SvelteKitResponseHeadersInterface\n>()(\"@thomasfosterau/effect-sveltekit/SvelteKitResponseHeaders\") {\n /**\n * Layer that builds the `SvelteKitResponseHeaders` service from the current\n * {@link SvelteKitRequestEvent}.\n */\n static readonly layer: Layer.Layer<SvelteKitResponseHeaders, never, SvelteKitRequestEvent> =\n Layer.effect(\n SvelteKitResponseHeaders,\n Effect.gen(function* () {\n const event = yield* SvelteKitRequestEvent;\n return { set: (headers) => Effect.sync(() => event.setHeaders(headers)) };\n }),\n );\n}\n\n// ─── SvelteKitLocals ──────────────────────────────────────────────────────────\n\n/**\n * An Effect service that exposes the mutable `App.Locals` object for the\n * current request.\n *\n * `yield* SvelteKitLocals` returns the live `event.locals` reference — the\n * same object mutations in `hooks.server.ts` (e.g. setting `event.locals.user`\n * in a `handle` hook) write to. Mutations made to it inside handler effects\n * propagate back to subsequent hook middleware.\n *\n * Available automatically in every server handler effect.\n *\n * @example\n * ```ts\n * // Read a typed local (requires App.Locals augmentation in your app):\n * const { user } = yield* SvelteKitLocals;\n *\n * // Write a local (useful in handle hooks run via makeServerRuntime.handle):\n * const locals = yield* SvelteKitLocals;\n * locals.user = yield* Auth.currentUser;\n * ```\n */\nexport class SvelteKitLocals extends Context.Service<SvelteKitLocals, App.Locals>()(\n \"@thomasfosterau/effect-sveltekit/SvelteKitLocals\",\n) {\n /**\n * Layer that exposes `event.locals` (the mutable `App.Locals` reference)\n * from the current {@link SvelteKitRequestEvent}.\n */\n static readonly layer: Layer.Layer<SvelteKitLocals, never, SvelteKitRequestEvent> = Layer.effect(\n SvelteKitLocals,\n Effect.gen(function* () {\n const event = yield* SvelteKitRequestEvent;\n return event.locals;\n }),\n );\n}\n\n// ─── Combined layer ───────────────────────────────────────────────────────────\n\n/**\n * A convenience layer that provides all three request services\n * ({@link SvelteKitCookies}, {@link SvelteKitResponseHeaders},\n * {@link SvelteKitLocals}) from the current {@link SvelteKitRequestEvent}.\n *\n * This layer is merged into the per-request context automatically by\n * {@link makeServerRuntime}, the standalone wrappers, and\n * {@link makeRuntimeAdapter}. Expose it here for use in custom setups that\n * already have `SvelteKitRequestEvent` in scope.\n */\nexport const requestServicesLayer: Layer.Layer<\n SvelteKitCookies | SvelteKitResponseHeaders | SvelteKitLocals,\n never,\n SvelteKitRequestEvent\n> = Layer.mergeAll(SvelteKitCookies.layer, SvelteKitResponseHeaders.layer, SvelteKitLocals.layer);\n\n/**\n * Build all three request services directly from a {@link RequestEvent},\n * without going through {@link SvelteKitRequestEvent}. Used internally by\n * `requestLayer` in `app-runtime.ts` to avoid an extra indirection.\n */\nexport const requestServicesFrom = (\n event: RequestEvent,\n): {\n cookies: SvelteKitCookiesInterface;\n responseHeaders: SvelteKitResponseHeadersInterface;\n locals: App.Locals;\n} => {\n const { cookies } = event;\n return {\n cookies: {\n get: (...args) => Effect.sync(() => cookies.get(...args)),\n getAll: (...args) => Effect.sync(() => cookies.getAll(...args)),\n set: (...args) => Effect.sync(() => cookies.set(...args)),\n delete: (...args) => Effect.sync(() => cookies.delete(...args)),\n serialize: (...args) => Effect.sync(() => cookies.serialize(...args)),\n },\n responseHeaders: { set: (headers) => Effect.sync(() => event.setHeaders(headers)) },\n locals: event.locals,\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAoGA,IAAa,mBAAb,MAAa,yBAAyB,QAAQ,QAG5C,EAAE,mDAAmD,EAAE;;;;;;CAMvD,OAAgB,QAAqE,MAAM,OACzF,kBACA,OAAO,IAAI,aAAa;EAEtB,MAAM,EAAE,YAAY,OADC;EAErB,OAAO;GACL,MAAM,GAAG,SAAS,OAAO,WAAW,QAAQ,IAAI,GAAG,IAAI,CAAC;GACxD,SAAS,GAAG,SAAS,OAAO,WAAW,QAAQ,OAAO,GAAG,IAAI,CAAC;GAC9D,MAAM,GAAG,SAAS,OAAO,WAAW,QAAQ,IAAI,GAAG,IAAI,CAAC;GACxD,SAAS,GAAG,SAAS,OAAO,WAAW,QAAQ,OAAO,GAAG,IAAI,CAAC;GAC9D,YAAY,GAAG,SAAS,OAAO,WAAW,QAAQ,UAAU,GAAG,IAAI,CAAC;EACtE;CACF,CAAC,CACH;AACF;;;;;;;;;;;;;;AA8BA,IAAa,2BAAb,MAAa,iCAAiC,QAAQ,QAGpD,EAAE,2DAA2D,EAAE;;;;;CAK/D,OAAgB,QACd,MAAM,OACJ,0BACA,OAAO,IAAI,aAAa;EACtB,MAAM,QAAQ,OAAO;EACrB,OAAO,EAAE,MAAM,YAAY,OAAO,WAAW,MAAM,WAAW,OAAO,CAAC,EAAE;CAC1E,CAAC,CACH;AACJ;;;;;;;;;;;;;;;;;;;;;;AAyBA,IAAa,kBAAb,MAAa,wBAAwB,QAAQ,QAAqC,EAChF,kDACF,EAAE;;;;;CAKA,OAAgB,QAAoE,MAAM,OACxF,iBACA,OAAO,IAAI,aAAa;EAEtB,QAAO,OADc,uBACR;CACf,CAAC,CACH;AACF;;;;;;;;;;;AAcA,MAAa,uBAIT,MAAM,SAAS,iBAAiB,OAAO,yBAAyB,OAAO,gBAAgB,KAAK;;;;;;AAOhG,MAAa,uBACX,UAKG;CACH,MAAM,EAAE,YAAY;CACpB,OAAO;EACL,SAAS;GACP,MAAM,GAAG,SAAS,OAAO,WAAW,QAAQ,IAAI,GAAG,IAAI,CAAC;GACxD,SAAS,GAAG,SAAS,OAAO,WAAW,QAAQ,OAAO,GAAG,IAAI,CAAC;GAC9D,MAAM,GAAG,SAAS,OAAO,WAAW,QAAQ,IAAI,GAAG,IAAI,CAAC;GACxD,SAAS,GAAG,SAAS,OAAO,WAAW,QAAQ,OAAO,GAAG,IAAI,CAAC;GAC9D,YAAY,GAAG,SAAS,OAAO,WAAW,QAAQ,UAAU,GAAG,IAAI,CAAC;EACtE;EACA,iBAAiB,EAAE,MAAM,YAAY,OAAO,WAAW,MAAM,WAAW,OAAO,CAAC,EAAE;EAClF,QAAQ,MAAM;CAChB;AACF"}
|
|
1
|
+
{"version":3,"file":"request-services.js","names":[],"sources":["../src/request-services.ts"],"sourcesContent":["/**\n * Effect-native services for the three per-request surfaces on a SvelteKit\n * `RequestEvent` — cookies, response headers, and locals — each as a tagged\n * `Context.Service` that can be `yield*`-ed in any handler effect and mocked\n * in tests with `Layer.succeed`.\n *\n * All three services are provided automatically as part of the\n * {@link SvelteKitServices} per-request context when using\n * {@link makeServerRuntime}, the standalone `serverLoad`/`action`/`endpoint`\n * wrappers, or {@link makeRuntimeAdapter}. No extra layer setup is required.\n *\n * @example\n * ```ts\n * import { Effect } from \"effect\";\n * import {\n * SvelteKitCookies,\n * SvelteKitResponseHeaders,\n * SvelteKitLocals,\n * } from \"@thomasfosterau/effect-sveltekit/server\";\n *\n * export const load = serverLoad(() =>\n * Effect.gen(function* () {\n * const cookies = yield* SvelteKitCookies;\n * const session = yield* cookies.get(\"session\");\n *\n * const headers = yield* SvelteKitResponseHeaders;\n * yield* headers.set({ \"cache-control\": \"max-age=60, s-maxage=300\" });\n *\n * const locals = yield* SvelteKitLocals;\n * // locals is App.Locals — typed to your augmented interface\n * const user = locals.user;\n *\n * return { user };\n * }),\n * );\n * ```\n *\n * ## Testing\n *\n * Because these are tagged services, they can be replaced with stubs via\n * `Layer.succeed` in unit tests without involving a real `RequestEvent`:\n *\n * ```ts\n * import { Layer } from \"effect\";\n * import { SvelteKitCookies } from \"@thomasfosterau/effect-sveltekit/server\";\n * import { runServerLoad, TestRequestEvent } from \"@thomasfosterau/effect-sveltekit/testing\";\n *\n * const MockCookies = Layer.succeed(SvelteKitCookies, {\n * get: (name) => Effect.succeed(name === \"session\" ? \"tok_test\" : undefined),\n * getAll: () => Effect.succeed([{ name: \"session\", value: \"tok_test\" }]),\n * set: () => Effect.void,\n * delete: () => Effect.void,\n * serialize: (n, v) => Effect.succeed(`${n}=${v}`),\n * });\n *\n * const data = await runServerLoad(myLoadFn, TestRequestEvent(), { layer: MockCookies });\n * ```\n */\n\nimport type { Cookies, RequestEvent } from \"@sveltejs/kit\";\nimport { Context, Effect, Layer } from \"effect\";\nimport { SvelteKitRequestEvent } from \"./runtime.js\";\n\n// ─── SvelteKitCookies ─────────────────────────────────────────────────────────\n\n/**\n * The Effect-native interface exposed by {@link SvelteKitCookies}. Each method\n * mirrors the corresponding `Cookies` method from `@sveltejs/kit` but returns\n * an `Effect` rather than a raw value or `void`.\n */\nexport interface SvelteKitCookiesInterface {\n /** Get a cookie by name. Returns `undefined` when the cookie is absent. */\n readonly get: (...args: Parameters<Cookies[\"get\"]>) => Effect.Effect<ReturnType<Cookies[\"get\"]>>;\n /** Get all cookies as `{ name, value }` pairs. */\n readonly getAll: (\n ...args: Parameters<Cookies[\"getAll\"]>\n ) => Effect.Effect<ReturnType<Cookies[\"getAll\"]>>;\n /** Set a cookie (adds a `set-cookie` response header). */\n readonly set: (...args: Parameters<Cookies[\"set\"]>) => Effect.Effect<void>;\n /** Delete a cookie by setting it to an empty value with a past expiry. */\n readonly delete: (...args: Parameters<Cookies[\"delete\"]>) => Effect.Effect<void>;\n /** Serialize a cookie into a `Set-Cookie` string without adding it to the response. */\n readonly serialize: (\n ...args: Parameters<Cookies[\"serialize\"]>\n ) => Effect.Effect<ReturnType<Cookies[\"serialize\"]>>;\n}\n\n/**\n * An Effect service wrapping the `RequestEvent.cookies` API.\n *\n * Available automatically in every server handler effect (it is part of\n * {@link SvelteKitServices}). Use `yield* SvelteKitCookies` to obtain the\n * service; call its methods (each returns an `Effect`) to read or write\n * cookies.\n *\n * @example\n * ```ts\n * const session = yield* (yield* SvelteKitCookies).get(\"session\");\n * ```\n */\nexport class SvelteKitCookies extends Context.Service<\n SvelteKitCookies,\n SvelteKitCookiesInterface\n>()(\"@thomasfosterau/effect-sveltekit/SvelteKitCookies\") {\n /**\n * Layer that builds the `SvelteKitCookies` service from the current\n * {@link SvelteKitRequestEvent}. Included in the per-request context\n * automatically; expose as a standalone layer for custom setups.\n */\n static readonly layer: Layer.Layer<SvelteKitCookies, never, SvelteKitRequestEvent> = Layer.effect(\n SvelteKitCookies,\n Effect.gen(function* () {\n const event = yield* SvelteKitRequestEvent;\n const { cookies } = event;\n return {\n get: (...args) => Effect.sync(() => cookies.get(...args)),\n getAll: (...args) => Effect.sync(() => cookies.getAll(...args)),\n set: (...args) => Effect.sync(() => cookies.set(...args)),\n delete: (...args) => Effect.sync(() => cookies.delete(...args)),\n serialize: (...args) => Effect.sync(() => cookies.serialize(...args)),\n };\n }),\n );\n}\n\n// ─── SvelteKitResponseHeaders ─────────────────────────────────────────────────\n\n/**\n * The Effect-native interface exposed by {@link SvelteKitResponseHeaders}.\n */\nexport interface SvelteKitResponseHeadersInterface {\n /**\n * Set one or more response headers. Equivalent to `event.setHeaders(headers)`.\n *\n * Note: You cannot set `set-cookie` headers here — use\n * {@link SvelteKitCookies} instead.\n */\n readonly set: (headers: Record<string, string>) => Effect.Effect<void>;\n}\n\n/**\n * An Effect service wrapping the `RequestEvent.setHeaders` API.\n *\n * Available automatically in every server handler effect. Use\n * `yield* SvelteKitResponseHeaders` to obtain the service, then call\n * `headers.set(...)`.\n *\n * @example\n * ```ts\n * const headers = yield* SvelteKitResponseHeaders;\n * yield* headers.set({ \"cache-control\": \"max-age=60, s-maxage=300\" });\n * ```\n */\nexport class SvelteKitResponseHeaders extends Context.Service<\n SvelteKitResponseHeaders,\n SvelteKitResponseHeadersInterface\n>()(\"@thomasfosterau/effect-sveltekit/SvelteKitResponseHeaders\") {\n /**\n * Layer that builds the `SvelteKitResponseHeaders` service from the current\n * {@link SvelteKitRequestEvent}.\n */\n static readonly layer: Layer.Layer<SvelteKitResponseHeaders, never, SvelteKitRequestEvent> =\n Layer.effect(\n SvelteKitResponseHeaders,\n Effect.gen(function* () {\n const event = yield* SvelteKitRequestEvent;\n return { set: (headers) => Effect.sync(() => event.setHeaders(headers)) };\n }),\n );\n}\n\n// ─── SvelteKitLocals ──────────────────────────────────────────────────────────\n\n/**\n * An Effect service that exposes the mutable `App.Locals` object for the\n * current request.\n *\n * `yield* SvelteKitLocals` returns the live `event.locals` reference — the\n * same object mutations in `hooks.server.ts` (e.g. setting `event.locals.user`\n * in a `handle` hook) write to. Mutations made to it inside handler effects\n * propagate back to subsequent hook middleware.\n *\n * Available automatically in every server handler effect.\n *\n * @example\n * ```ts\n * // Read a typed local (requires App.Locals augmentation in your app):\n * const { user } = yield* SvelteKitLocals;\n *\n * // Write a local (useful in handle hooks run via makeServerRuntime.handle):\n * const locals = yield* SvelteKitLocals;\n * locals.user = yield* Auth.currentUser;\n * ```\n */\nexport class SvelteKitLocals extends Context.Service<SvelteKitLocals, App.Locals>()(\n \"@thomasfosterau/effect-sveltekit/SvelteKitLocals\",\n) {\n /**\n * Layer that exposes `event.locals` (the mutable `App.Locals` reference)\n * from the current {@link SvelteKitRequestEvent}.\n */\n static readonly layer: Layer.Layer<SvelteKitLocals, never, SvelteKitRequestEvent> = Layer.effect(\n SvelteKitLocals,\n Effect.gen(function* () {\n const event = yield* SvelteKitRequestEvent;\n return event.locals;\n }),\n );\n}\n\n// ─── Combined layer ───────────────────────────────────────────────────────────\n\n/**\n * A convenience layer that provides all three request services\n * ({@link SvelteKitCookies}, {@link SvelteKitResponseHeaders},\n * {@link SvelteKitLocals}) from the current {@link SvelteKitRequestEvent}.\n *\n * This layer is merged into the per-request context automatically by\n * {@link makeServerRuntime}, the standalone wrappers, and\n * {@link makeRuntimeAdapter}. Expose it here for use in custom setups that\n * already have `SvelteKitRequestEvent` in scope.\n */\nexport const requestServicesLayer: Layer.Layer<\n SvelteKitCookies | SvelteKitResponseHeaders | SvelteKitLocals,\n never,\n SvelteKitRequestEvent\n> = Layer.mergeAll(SvelteKitCookies.layer, SvelteKitResponseHeaders.layer, SvelteKitLocals.layer);\n\n/**\n * Build all three request services directly from a {@link RequestEvent},\n * without going through {@link SvelteKitRequestEvent}. Used internally by\n * `requestLayer` in `app-runtime.ts` to avoid an extra indirection.\n */\nexport const requestServicesFrom = (\n event: RequestEvent,\n): {\n cookies: SvelteKitCookiesInterface;\n responseHeaders: SvelteKitResponseHeadersInterface;\n locals: App.Locals;\n} => {\n const { cookies } = event;\n return {\n cookies: {\n get: (...args) => Effect.sync(() => cookies.get(...args)),\n getAll: (...args) => Effect.sync(() => cookies.getAll(...args)),\n set: (...args) => Effect.sync(() => cookies.set(...args)),\n delete: (...args) => Effect.sync(() => cookies.delete(...args)),\n serialize: (...args) => Effect.sync(() => cookies.serialize(...args)),\n },\n responseHeaders: { set: (headers) => Effect.sync(() => event.setHeaders(headers)) },\n locals: event.locals,\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAoGA,IAAa,mBAAb,MAAa,yBAAyB,QAAQ,QAG5C,CAAC,CAAC,mDAAmD,CAAC,CAAC;;;;;;CAMvD,OAAgB,QAAqE,MAAM,OACzF,kBACA,OAAO,IAAI,aAAa;EAEtB,MAAM,EAAE,YAAY,OADC;EAErB,OAAO;GACL,MAAM,GAAG,SAAS,OAAO,WAAW,QAAQ,IAAI,GAAG,IAAI,CAAC;GACxD,SAAS,GAAG,SAAS,OAAO,WAAW,QAAQ,OAAO,GAAG,IAAI,CAAC;GAC9D,MAAM,GAAG,SAAS,OAAO,WAAW,QAAQ,IAAI,GAAG,IAAI,CAAC;GACxD,SAAS,GAAG,SAAS,OAAO,WAAW,QAAQ,OAAO,GAAG,IAAI,CAAC;GAC9D,YAAY,GAAG,SAAS,OAAO,WAAW,QAAQ,UAAU,GAAG,IAAI,CAAC;EACtE;CACF,CAAC,CACH;AACF;;;;;;;;;;;;;;AA8BA,IAAa,2BAAb,MAAa,iCAAiC,QAAQ,QAGpD,CAAC,CAAC,2DAA2D,CAAC,CAAC;;;;;CAK/D,OAAgB,QACd,MAAM,OACJ,0BACA,OAAO,IAAI,aAAa;EACtB,MAAM,QAAQ,OAAO;EACrB,OAAO,EAAE,MAAM,YAAY,OAAO,WAAW,MAAM,WAAW,OAAO,CAAC,EAAE;CAC1E,CAAC,CACH;AACJ;;;;;;;;;;;;;;;;;;;;;;AAyBA,IAAa,kBAAb,MAAa,wBAAwB,QAAQ,QAAqC,CAAC,CACjF,kDACF,CAAC,CAAC;;;;;CAKA,OAAgB,QAAoE,MAAM,OACxF,iBACA,OAAO,IAAI,aAAa;EAEtB,QAAO,OADc,sBAAA,CACR;CACf,CAAC,CACH;AACF;;;;;;;;;;;AAcA,MAAa,uBAIT,MAAM,SAAS,iBAAiB,OAAO,yBAAyB,OAAO,gBAAgB,KAAK;;;;;;AAOhG,MAAa,uBACX,UAKG;CACH,MAAM,EAAE,YAAY;CACpB,OAAO;EACL,SAAS;GACP,MAAM,GAAG,SAAS,OAAO,WAAW,QAAQ,IAAI,GAAG,IAAI,CAAC;GACxD,SAAS,GAAG,SAAS,OAAO,WAAW,QAAQ,OAAO,GAAG,IAAI,CAAC;GAC9D,MAAM,GAAG,SAAS,OAAO,WAAW,QAAQ,IAAI,GAAG,IAAI,CAAC;GACxD,SAAS,GAAG,SAAS,OAAO,WAAW,QAAQ,OAAO,GAAG,IAAI,CAAC;GAC9D,YAAY,GAAG,SAAS,OAAO,WAAW,QAAQ,UAAU,GAAG,IAAI,CAAC;EACtE;EACA,iBAAiB,EAAE,MAAM,YAAY,OAAO,WAAW,MAAM,WAAW,OAAO,CAAC,EAAE;EAClF,QAAQ,MAAM;CAChB;AACF"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Transporter } from "@sveltejs/kit";
|
|
2
|
+
//#region src/response-headers.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* A `Headers` that serialises to `{}` and knows how to copy itself onto a
|
|
5
|
+
* response. Everything else is the platform `Headers`.
|
|
6
|
+
*/
|
|
7
|
+
declare class ResponseHeaders extends globalThis.Headers {
|
|
8
|
+
/**
|
|
9
|
+
* Append every buffered header to `target` (typically `response.headers`
|
|
10
|
+
* after `resolve()`). Appends rather than sets, so repeated headers such as
|
|
11
|
+
* `set-cookie` all survive.
|
|
12
|
+
*/
|
|
13
|
+
appendTo(target: globalThis.Headers): void;
|
|
14
|
+
/** Serialises to an empty object: the contents never leave the server. */
|
|
15
|
+
toJSON(): Record<string, never>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The `transport` entry for {@link ResponseHeaders}: detected on the server,
|
|
19
|
+
* reconstructed on the client as a fresh, empty buffer.
|
|
20
|
+
*/
|
|
21
|
+
declare const responseHeadersTransporter: Transporter<ResponseHeaders, unknown>;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { ResponseHeaders, responseHeadersTransporter };
|
|
24
|
+
//# sourceMappingURL=response-headers.d.ts.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { markerTransporter } from "./transport.js";
|
|
2
|
+
//#region src/response-headers.ts
|
|
3
|
+
/**
|
|
4
|
+
* A `Headers` that serialises to `{}` and knows how to copy itself onto a
|
|
5
|
+
* response. Everything else is the platform `Headers`.
|
|
6
|
+
*/
|
|
7
|
+
var ResponseHeaders = class extends globalThis.Headers {
|
|
8
|
+
/**
|
|
9
|
+
* Append every buffered header to `target` (typically `response.headers`
|
|
10
|
+
* after `resolve()`). Appends rather than sets, so repeated headers such as
|
|
11
|
+
* `set-cookie` all survive.
|
|
12
|
+
*/
|
|
13
|
+
appendTo(target) {
|
|
14
|
+
for (const cookie of this.getSetCookie()) target.append("set-cookie", cookie);
|
|
15
|
+
this.forEach((value, key) => {
|
|
16
|
+
if (key !== "set-cookie") target.append(key, value);
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
/** Serialises to an empty object: the contents never leave the server. */
|
|
20
|
+
toJSON() {
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* The `transport` entry for {@link ResponseHeaders}: detected on the server,
|
|
26
|
+
* reconstructed on the client as a fresh, empty buffer.
|
|
27
|
+
*/
|
|
28
|
+
const responseHeadersTransporter = markerTransporter({
|
|
29
|
+
guard: (value) => value instanceof ResponseHeaders,
|
|
30
|
+
make: () => new ResponseHeaders()
|
|
31
|
+
});
|
|
32
|
+
//#endregion
|
|
33
|
+
export { ResponseHeaders, responseHeadersTransporter };
|
|
34
|
+
|
|
35
|
+
//# sourceMappingURL=response-headers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-headers.js","names":[],"sources":["../src/response-headers.ts"],"sourcesContent":["/**\n * A per-request **response-headers buffer** that can ride through `load` data.\n *\n * SvelteKit's `setHeaders` refuses `set-cookie` and throws when the same header\n * is set twice, and components rendering during SSR cannot reach it at all. The\n * pattern the applications converged on is a mutable `Headers` buffer on\n * `event.locals`: loads (and SSR components, via `page.data`) append to it, and\n * a server `handle` copies it onto the outgoing response after `resolve()`.\n *\n * Returning that buffer from a `load` needs a `transport` entry, or SvelteKit\n * refuses to serialise it (\"Cannot stringify arbitrary non-POJOs\"). Its contents\n * are deliberately *not* round-tripped — the server hook reads the live buffer\n * after rendering, so the client only needs a fresh, empty instance.\n * {@link ResponseHeaders} is the buffer, {@link responseHeadersTransporter} the\n * transport entry, and {@link ResponseHeaders.appendTo} the copy step.\n *\n * @example\n * ```ts\n * // src/hooks.ts\n * import { Hooks } from \"@thomasfosterau/effect-sveltekit\";\n *\n * export const transport = Hooks.transport({ ResponseHeaders: Hooks.responseHeadersTransporter });\n *\n * // src/hooks.server.ts\n * import { ResponseHeaders } from \"@thomasfosterau/effect-sveltekit\";\n * import type { Handle } from \"@sveltejs/kit\";\n *\n * export const handle: Handle = async ({ event, resolve }) => {\n * event.locals.headers = new ResponseHeaders();\n * const response = await resolve(event);\n * event.locals.headers.appendTo(response.headers);\n * return response;\n * };\n *\n * // src/routes/+layout.server.ts — expose the buffer to every page\n * export const load = ({ locals }) => ({ headers: locals.headers });\n * ```\n *\n * @module\n */\n\nimport type { Transporter } from \"@sveltejs/kit\";\nimport { markerTransporter } from \"./transport.js\";\n\n/**\n * A `Headers` that serialises to `{}` and knows how to copy itself onto a\n * response. Everything else is the platform `Headers`.\n */\nexport class ResponseHeaders extends globalThis.Headers {\n /**\n * Append every buffered header to `target` (typically `response.headers`\n * after `resolve()`). Appends rather than sets, so repeated headers such as\n * `set-cookie` all survive.\n */\n appendTo(target: globalThis.Headers): void {\n for (const cookie of this.getSetCookie()) target.append(\"set-cookie\", cookie);\n this.forEach((value, key) => {\n if (key !== \"set-cookie\") target.append(key, value);\n });\n }\n\n /** Serialises to an empty object: the contents never leave the server. */\n toJSON(): Record<string, never> {\n return {};\n }\n}\n\n/**\n * The `transport` entry for {@link ResponseHeaders}: detected on the server,\n * reconstructed on the client as a fresh, empty buffer.\n */\nexport const responseHeadersTransporter: Transporter<ResponseHeaders, unknown> = markerTransporter({\n guard: (value): value is ResponseHeaders => value instanceof ResponseHeaders,\n make: () => new ResponseHeaders(),\n});\n"],"mappings":";;;;;;AAgDA,IAAa,kBAAb,cAAqC,WAAW,QAAQ;;;;;;CAMtD,SAAS,QAAkC;EACzC,KAAK,MAAM,UAAU,KAAK,aAAa,GAAG,OAAO,OAAO,cAAc,MAAM;EAC5E,KAAK,SAAS,OAAO,QAAQ;GAC3B,IAAI,QAAQ,cAAc,OAAO,OAAO,KAAK,KAAK;EACpD,CAAC;CACH;;CAGA,SAAgC;EAC9B,OAAO,CAAC;CACV;AACF;;;;;AAMA,MAAa,6BAAoE,kBAAkB;CACjG,QAAQ,UAAoC,iBAAiB;CAC7D,YAAY,IAAI,gBAAgB;AAClC,CAAC"}
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Context, Effect, Layer, ManagedRuntime } from "effect";
|
|
2
|
-
import * as HttpClient from "effect/
|
|
2
|
+
import * as HttpClient from "effect/http/HttpClient";
|
|
3
3
|
import { RequestEvent } from "@sveltejs/kit";
|
|
4
|
-
|
|
5
4
|
//#region src/runtime.d.ts
|
|
6
5
|
declare const SvelteKitRequestEvent_base: Context.ServiceClass<SvelteKitRequestEvent, "SvelteKitRequestEvent", RequestEvent<Record<string, string>, string | null>>;
|
|
7
6
|
/**
|
|
@@ -21,7 +20,7 @@ declare class SvelteKitRequestEvent extends SvelteKitRequestEvent_base {}
|
|
|
21
20
|
* ```ts
|
|
22
21
|
* import { SvelteKitRuntime } from '@thomasfosterau/effect-sveltekit/server';
|
|
23
22
|
* import { Effect } from 'effect';
|
|
24
|
-
* import * as HttpClient from 'effect/
|
|
23
|
+
* import * as HttpClient from 'effect/http/HttpClient';
|
|
25
24
|
*
|
|
26
25
|
* export const load = (event) => {
|
|
27
26
|
* const runtime = SvelteKitRuntime.forRequest(event);
|
package/dist/runtime.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Context, Layer, ManagedRuntime } from "effect";
|
|
2
|
-
import * as FetchHttpClient from "effect/
|
|
3
|
-
import "effect/
|
|
2
|
+
import * as FetchHttpClient from "effect/http/FetchHttpClient";
|
|
3
|
+
import "effect/http/HttpClient";
|
|
4
4
|
//#region src/runtime.ts
|
|
5
5
|
/**
|
|
6
6
|
* Service that provides access to the current SvelteKit RequestEvent.
|
|
@@ -19,7 +19,7 @@ var SvelteKitRequestEvent = class extends Context.Service()("SvelteKitRequestEve
|
|
|
19
19
|
* ```ts
|
|
20
20
|
* import { SvelteKitRuntime } from '@thomasfosterau/effect-sveltekit/server';
|
|
21
21
|
* import { Effect } from 'effect';
|
|
22
|
-
* import * as HttpClient from 'effect/
|
|
22
|
+
* import * as HttpClient from 'effect/http/HttpClient';
|
|
23
23
|
*
|
|
24
24
|
* export const load = (event) => {
|
|
25
25
|
* const runtime = SvelteKitRuntime.forRequest(event);
|
package/dist/runtime.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","names":[],"sources":["../src/runtime.ts"],"sourcesContent":["import { Layer, ManagedRuntime, Context, Effect } from \"effect\";\nimport * as HttpClient from \"effect/
|
|
1
|
+
{"version":3,"file":"runtime.js","names":[],"sources":["../src/runtime.ts"],"sourcesContent":["import { Layer, ManagedRuntime, Context, Effect } from \"effect\";\nimport * as HttpClient from \"effect/http/HttpClient\";\nimport * as FetchHttpClient from \"effect/http/FetchHttpClient\";\nimport type { RequestEvent } from \"@sveltejs/kit\";\n\n/**\n * Service that provides access to the current SvelteKit RequestEvent.\n * This allows Effect code to access request-specific data like cookies, headers, etc.\n */\nexport class SvelteKitRequestEvent extends Context.Service<SvelteKitRequestEvent, RequestEvent>()(\n \"SvelteKitRequestEvent\",\n) {}\n\n/**\n * Custom runtime for SvelteKit server-side helpers.\n *\n * This runtime is designed for SvelteKit server-side execution and provides:\n * - HttpClient for making HTTP requests\n * - FetchHttpClient using the platform's fetch implementation\n * - SvelteKitRequestEvent for accessing SvelteKit-specific request data\n *\n * @example\n * ```ts\n * import { SvelteKitRuntime } from '@thomasfosterau/effect-sveltekit/server';\n * import { Effect } from 'effect';\n * import * as HttpClient from 'effect/http/HttpClient';\n *\n * export const load = (event) => {\n * const runtime = SvelteKitRuntime.forRequest(event);\n * return runtime.runPromise(\n * Effect.gen(function* () {\n * // Access HttpClient from the runtime\n * const client = yield* HttpClient.HttpClient;\n * const response = yield* client.get(\"https://api.example.com/data\");\n * return { data: response };\n * })\n * );\n * };\n * ```\n */\nexport class SvelteKitRuntime {\n /**\n * Creates a layer with platform services for a specific request.\n * This includes FetchHttpClient and access to the RequestEvent.\n *\n * @param event - The SvelteKit RequestEvent\n * @returns A layer providing platform services\n */\n private static createRequestLayer(\n event: RequestEvent,\n ): Layer.Layer<HttpClient.HttpClient | SvelteKitRequestEvent> {\n // Provide HttpClient using SvelteKit's fetch\n const httpClientLayer = FetchHttpClient.layer.pipe(\n Layer.provide(Layer.succeed(FetchHttpClient.Fetch, event.fetch)),\n );\n\n // Provide access to the RequestEvent\n const requestEventLayer = Layer.succeed(SvelteKitRequestEvent, event);\n\n return Layer.merge(httpClientLayer, requestEventLayer);\n }\n\n /**\n * Creates a runtime for a specific SvelteKit request.\n * This runtime includes all platform services configured for the request.\n *\n * @param event - The SvelteKit RequestEvent\n * @returns A managed runtime with platform services\n */\n static forRequest(\n event: RequestEvent,\n ): ManagedRuntime.ManagedRuntime<HttpClient.HttpClient | SvelteKitRequestEvent, never> {\n return ManagedRuntime.make(this.createRequestLayer(event));\n }\n\n /**\n * Extends the request runtime with additional services.\n *\n * @param event - The SvelteKit RequestEvent\n * @param layer - Additional layer to merge\n * @returns A managed runtime with both platform and custom services\n *\n * @example\n * ```ts\n * import { SvelteKitRuntime } from '@thomasfosterau/effect-sveltekit/server';\n * import { Layer, Context } from 'effect';\n *\n * class Database extends Context.Service<Database, {\n * query: (sql: string) => Effect.Effect<unknown>\n * }>()(\"Database\") {}\n *\n * const dbLayer = Layer.succeed(Database, {\n * query: (sql) => Effect.succeed([])\n * });\n *\n * export const load = (event) => {\n * const runtime = SvelteKitRuntime.extend(event, dbLayer);\n * // Use runtime...\n * };\n * ```\n */\n static extend<R, E>(\n event: RequestEvent,\n layer: Layer.Layer<R, E>,\n ): ManagedRuntime.ManagedRuntime<R | HttpClient.HttpClient | SvelteKitRequestEvent, E> {\n return ManagedRuntime.make(Layer.merge(this.createRequestLayer(event), layer));\n }\n\n /**\n * Creates a runtime that provides `HttpClient` backed by the given fetch\n * implementation, without a `SvelteKitRequestEvent`.\n *\n * This is used for universal `load` functions running on the client, where\n * there is no `RequestEvent` but the load event still exposes `fetch`.\n *\n * @param fetchFn - The fetch implementation to back HttpClient with\n * @returns A managed runtime providing HttpClient\n */\n static forFetch(\n fetchFn: typeof globalThis.fetch,\n ): ManagedRuntime.ManagedRuntime<HttpClient.HttpClient, never> {\n return ManagedRuntime.make(\n FetchHttpClient.layer.pipe(Layer.provide(Layer.succeed(FetchHttpClient.Fetch, fetchFn))),\n );\n }\n\n /**\n * The base layer for SvelteKit without request-specific services.\n * Use this for effects that don't need access to the request.\n */\n static readonly baseLayer = Layer.empty;\n\n /**\n * Creates a runtime from a custom layer.\n *\n * @param layer - The layer to use for the runtime\n * @returns A managed runtime\n */\n static make<R, E>(layer: Layer.Layer<R, E>): ManagedRuntime.ManagedRuntime<R, E> {\n return ManagedRuntime.make(layer);\n }\n}\n\n/**\n * Helper to run an effect with the SvelteKit runtime for a specific request.\n * This automatically sets up and tears down the runtime.\n *\n * @param event - The SvelteKit RequestEvent\n * @param effect - The effect to run\n * @returns A promise with the result\n *\n * @example\n * ```ts\n * import { runWithSvelteKitRuntime } from '@thomasfosterau/effect-sveltekit/server';\n * import { Effect } from 'effect';\n *\n * export const load = async (event) => {\n * return await runWithSvelteKitRuntime(event,\n * Effect.succeed({ message: \"Hello!\" })\n * );\n * };\n * ```\n */\nexport function runWithSvelteKitRuntime<A, E>(\n event: RequestEvent,\n effect: Effect.Effect<A, E, HttpClient.HttpClient | SvelteKitRequestEvent>,\n): Promise<A> {\n const runtime = SvelteKitRuntime.forRequest(event);\n return runtime.runPromise(effect);\n}\n"],"mappings":";;;;;;;;AASA,IAAa,wBAAb,cAA2C,QAAQ,QAA6C,CAAC,CAC/F,uBACF,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BH,IAAa,mBAAb,MAA8B;;;;;;;;CAQ5B,OAAe,mBACb,OAC4D;EAE5D,MAAM,kBAAkB,gBAAgB,MAAM,KAC5C,MAAM,QAAQ,MAAM,QAAQ,gBAAgB,OAAO,MAAM,KAAK,CAAC,CACjE;EAGA,MAAM,oBAAoB,MAAM,QAAQ,uBAAuB,KAAK;EAEpE,OAAO,MAAM,MAAM,iBAAiB,iBAAiB;CACvD;;;;;;;;CASA,OAAO,WACL,OACqF;EACrF,OAAO,eAAe,KAAK,KAAK,mBAAmB,KAAK,CAAC;CAC3D;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BA,OAAO,OACL,OACA,OACqF;EACrF,OAAO,eAAe,KAAK,MAAM,MAAM,KAAK,mBAAmB,KAAK,GAAG,KAAK,CAAC;CAC/E;;;;;;;;;;;CAYA,OAAO,SACL,SAC6D;EAC7D,OAAO,eAAe,KACpB,gBAAgB,MAAM,KAAK,MAAM,QAAQ,MAAM,QAAQ,gBAAgB,OAAO,OAAO,CAAC,CAAC,CACzF;CACF;;;;;CAMA,OAAgB,YAAY,MAAM;;;;;;;CAQlC,OAAO,KAAW,OAA+D;EAC/E,OAAO,eAAe,KAAK,KAAK;CAClC;AACF;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,wBACd,OACA,QACY;CAEZ,OADgB,iBAAiB,WAAW,KAC/B,CAAC,CAAC,WAAW,MAAM;AAClC"}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { Context, Duration, Effect, Layer, Scope, Stream } from "effect";
|
|
2
2
|
import { RequestHandler } from "@sveltejs/kit";
|
|
3
|
-
import * as HttpRouter from "effect/
|
|
4
|
-
import * as HttpServerRequest from "effect/
|
|
5
|
-
import * as HttpServerResponse from "effect/
|
|
6
|
-
import * as HttpApi from "effect/
|
|
7
|
-
import * as HttpApiGroup from "effect/
|
|
8
|
-
|
|
9
|
-
//#region src/server/Endpoint.d.ts
|
|
3
|
+
import * as HttpRouter from "effect/http/HttpRouter";
|
|
4
|
+
import * as HttpServerRequest from "effect/http/HttpServerRequest";
|
|
5
|
+
import * as HttpServerResponse from "effect/http/HttpServerResponse";
|
|
6
|
+
import * as HttpApi from "effect/http-api/HttpApi";
|
|
7
|
+
import * as HttpApiGroup from "effect/http-api/HttpApiGroup";
|
|
10
8
|
declare namespace Endpoint_d_exports {
|
|
11
9
|
export { EndpointHandler, EndpointOptions, FromStreamOptions, RequestContext, fromApi, fromHttpEffect, fromRouter, fromStream };
|
|
12
10
|
}
|
|
@@ -24,7 +22,8 @@ type RequestContext<RequestServices> = (request: Request) => Context.Context<Req
|
|
|
24
22
|
* (`fallback`, `GET`, ...). `dispose()` closes the scope of the layer behind it.
|
|
25
23
|
*/
|
|
26
24
|
type EndpointHandler = RequestHandler & {
|
|
27
|
-
/** Close the scope of the layer backing the endpoint (runs its finalizers). */
|
|
25
|
+
/** Close the scope of the layer backing the endpoint (runs its finalizers). */
|
|
26
|
+
readonly dispose: () => Promise<void>;
|
|
28
27
|
};
|
|
29
28
|
/** Shared options for every `Endpoint.from*` helper. */
|
|
30
29
|
interface EndpointOptions {
|
|
@@ -56,8 +55,10 @@ interface EndpointOptions {
|
|
|
56
55
|
* export const fallback = Endpoint.fromApi(api, ApiLive, { prefix: "/api" });
|
|
57
56
|
* ```
|
|
58
57
|
*/
|
|
59
|
-
declare const fromApi: <Id extends string, Groups extends HttpApiGroup.
|
|
60
|
-
/** Serve the OpenAPI spec for the API at this path (e.g. `"/openapi.json"`). */
|
|
58
|
+
declare const fromApi: <Id extends string, Groups extends HttpApiGroup.Constraint, E, LayerRequires = never, RequestServices = never>(api: HttpApi.HttpApi<Id, Groups>, layer: Layer.Layer<HttpApiGroup.ToService<Id, Groups>, E, LayerRequires>, options?: EndpointOptions & {
|
|
59
|
+
/** Serve the OpenAPI spec for the API at this path (e.g. `"/openapi.json"`). */
|
|
60
|
+
readonly openapiPath?: `/${string}`;
|
|
61
|
+
/** Add Effect's request logger middleware. Defaults to `false` (quiet). */
|
|
61
62
|
readonly logger?: boolean;
|
|
62
63
|
/**
|
|
63
64
|
* Provide the request-scoped services the API groups require, per request.
|
|
@@ -88,7 +89,7 @@ declare const fromApi: <Id extends string, Groups extends HttpApiGroup.Any, E, L
|
|
|
88
89
|
* // src/routes/api/[...path]/+server.ts
|
|
89
90
|
* import { Endpoint } from "@thomasfosterau/effect-sveltekit/server";
|
|
90
91
|
* import { Effect } from "effect";
|
|
91
|
-
* import { HttpRouter, HttpServerResponse } from "effect/
|
|
92
|
+
* import { HttpRouter, HttpServerResponse } from "effect/http";
|
|
92
93
|
*
|
|
93
94
|
* const RouterLive = HttpRouter.use((router) =>
|
|
94
95
|
* router.add("GET", "/hello", Effect.succeed(HttpServerResponse.text("hi"))),
|
|
@@ -98,7 +99,8 @@ declare const fromApi: <Id extends string, Groups extends HttpApiGroup.Any, E, L
|
|
|
98
99
|
* ```
|
|
99
100
|
*/
|
|
100
101
|
declare const fromRouter: <A, E, R extends HttpRouter.HttpRouter | HttpRouter.Request<"Requires", any> | HttpRouter.Request<"GlobalRequires", any> | HttpRouter.Request<"Error", any> | HttpRouter.Request<"GlobalError", any>, RequestServices = never>(layer: Layer.Layer<A, E, R>, options?: EndpointOptions & {
|
|
101
|
-
/** Add Effect's request logger middleware. Defaults to `false` (quiet). */
|
|
102
|
+
/** Add Effect's request logger middleware. Defaults to `false` (quiet). */
|
|
103
|
+
readonly logger?: boolean;
|
|
102
104
|
/**
|
|
103
105
|
* Provide the request-scoped services the router's routes require, per
|
|
104
106
|
* request (the routes' `HttpRouter.Request<"Requires", ...>` services). The
|
|
@@ -117,7 +119,7 @@ declare const fromRouter: <A, E, R extends HttpRouter.HttpRouter | HttpRouter.Re
|
|
|
117
119
|
* // src/routes/health/+server.ts
|
|
118
120
|
* import { Endpoint } from "@thomasfosterau/effect-sveltekit/server";
|
|
119
121
|
* import { Effect } from "effect";
|
|
120
|
-
* import { HttpServerResponse } from "effect/
|
|
122
|
+
* import { HttpServerResponse } from "effect/http";
|
|
121
123
|
*
|
|
122
124
|
* export const GET = Endpoint.fromHttpEffect(
|
|
123
125
|
* Effect.succeed(HttpServerResponse.text("ok")),
|
|
@@ -125,7 +127,8 @@ declare const fromRouter: <A, E, R extends HttpRouter.HttpRouter | HttpRouter.Re
|
|
|
125
127
|
* ```
|
|
126
128
|
*/
|
|
127
129
|
declare const fromHttpEffect: <E, R = never, ProvidedE = never>(effect: Effect.Effect<HttpServerResponse.HttpServerResponse, E, R | HttpServerRequest.HttpServerRequest | Scope.Scope>, options?: EndpointOptions & {
|
|
128
|
-
/** A layer providing the route's services (`R`), built once and shared. */
|
|
130
|
+
/** A layer providing the route's services (`R`), built once and shared. */
|
|
131
|
+
readonly layer?: Layer.Layer<R, ProvidedE>;
|
|
129
132
|
}) => EndpointHandler;
|
|
130
133
|
/** Options for {@link fromStream}: how to frame each element as an SSE event. */
|
|
131
134
|
interface FromStreamOptions<A, R = never> {
|
|
@@ -188,5 +191,5 @@ interface FromStreamOptions<A, R = never> {
|
|
|
188
191
|
*/
|
|
189
192
|
declare const fromStream: <A, E, R = never>(stream: Stream.Stream<A, E, R>, options?: FromStreamOptions<A, R>) => RequestHandler;
|
|
190
193
|
//#endregion
|
|
191
|
-
export { Endpoint_d_exports };
|
|
194
|
+
export { EndpointHandler, EndpointOptions, Endpoint_d_exports, FromStreamOptions, RequestContext, fromApi, fromHttpEffect, fromRouter, fromStream };
|
|
192
195
|
//# sourceMappingURL=Endpoint.d.ts.map
|
package/dist/server/Endpoint.js
CHANGED
|
@@ -3,11 +3,11 @@ import { HEARTBEAT_FRAME, SSE_HEADERS, encodeRetry, encodeSseFrame } from "../in
|
|
|
3
3
|
import { Effect, Layer, Schedule, Stream } from "effect";
|
|
4
4
|
import * as FileSystem from "effect/FileSystem";
|
|
5
5
|
import * as Path from "effect/Path";
|
|
6
|
-
import * as Etag from "effect/
|
|
7
|
-
import * as HttpEffect from "effect/
|
|
8
|
-
import * as HttpPlatform from "effect/
|
|
9
|
-
import * as HttpRouter from "effect/
|
|
10
|
-
import * as HttpApiBuilder from "effect/
|
|
6
|
+
import * as Etag from "effect/http/Etag";
|
|
7
|
+
import * as HttpEffect from "effect/http/HttpEffect";
|
|
8
|
+
import * as HttpPlatform from "effect/http/HttpPlatform";
|
|
9
|
+
import * as HttpRouter from "effect/http/HttpRouter";
|
|
10
|
+
import * as HttpApiBuilder from "effect/http-api/HttpApiBuilder";
|
|
11
11
|
//#region src/server/Endpoint.ts
|
|
12
12
|
var Endpoint_exports = /* @__PURE__ */ __exportAll({
|
|
13
13
|
fromApi: () => fromApi,
|
|
@@ -76,7 +76,7 @@ const fromApi = (api, layer, options) => {
|
|
|
76
76
|
* // src/routes/api/[...path]/+server.ts
|
|
77
77
|
* import { Endpoint } from "@thomasfosterau/effect-sveltekit/server";
|
|
78
78
|
* import { Effect } from "effect";
|
|
79
|
-
* import { HttpRouter, HttpServerResponse } from "effect/
|
|
79
|
+
* import { HttpRouter, HttpServerResponse } from "effect/http";
|
|
80
80
|
*
|
|
81
81
|
* const RouterLive = HttpRouter.use((router) =>
|
|
82
82
|
* router.add("GET", "/hello", Effect.succeed(HttpServerResponse.text("hi"))),
|
|
@@ -100,7 +100,7 @@ const fromRouter = (layer, options) => {
|
|
|
100
100
|
* // src/routes/health/+server.ts
|
|
101
101
|
* import { Endpoint } from "@thomasfosterau/effect-sveltekit/server";
|
|
102
102
|
* import { Effect } from "effect";
|
|
103
|
-
* import { HttpServerResponse } from "effect/
|
|
103
|
+
* import { HttpServerResponse } from "effect/http";
|
|
104
104
|
*
|
|
105
105
|
* export const GET = Endpoint.fromHttpEffect(
|
|
106
106
|
* Effect.succeed(HttpServerResponse.text("ok")),
|
|
@@ -112,7 +112,8 @@ const fromHttpEffect = (effect, options) => {
|
|
|
112
112
|
const { handler, dispose } = HttpEffect.toWebHandlerLayer(effect, options.layer);
|
|
113
113
|
return make(handler, dispose, options.prefix);
|
|
114
114
|
}
|
|
115
|
-
|
|
115
|
+
const handler = HttpEffect.toWebHandler(effect);
|
|
116
|
+
return make(handler, noopDispose, options?.prefix);
|
|
116
117
|
};
|
|
117
118
|
/**
|
|
118
119
|
* Create a SvelteKit endpoint that streams an Effect `Stream` to the browser as
|
|
@@ -158,6 +159,6 @@ const fromStream = (stream, options) => {
|
|
|
158
159
|
};
|
|
159
160
|
};
|
|
160
161
|
//#endregion
|
|
161
|
-
export { Endpoint_exports };
|
|
162
|
+
export { Endpoint_exports, fromApi, fromHttpEffect, fromRouter, fromStream };
|
|
162
163
|
|
|
163
164
|
//# sourceMappingURL=Endpoint.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Endpoint.js","names":[],"sources":["../../src/server/Endpoint.ts"],"sourcesContent":["/**\n * Create SvelteKit server endpoints (`+server.ts`) backed by Effect — the\n * `Endpoint` namespace of `@thomasfosterau/effect-sveltekit/server`.\n *\n * A SvelteKit endpoint is a `RequestHandler` (`(event) => Response`). Effect can\n * turn an [`HttpApi`](https://effect.website), an `HttpRouter`, or a single\n * route effect into a Web `fetch` handler; these helpers wrap one as a SvelteKit\n * endpoint handler so a route can be served by Effect. Mount it on a catch-all\n * route (`[...path]`) and assign it to `fallback` so every method and sub-path\n * reaches it:\n *\n * @example\n * ```ts\n * // src/routes/api/[...path]/+server.ts\n * import { Endpoint } from \"@thomasfosterau/effect-sveltekit/server\";\n * import { api } from \"$lib/server/api\";\n * import { ApiLive } from \"$lib/server/handlers\"; // HttpApiBuilder.group(...) + your services\n *\n * // `prefix` strips the SvelteKit mount path so the API's own paths\n * // (e.g. \"/users\") match.\n * export const fallback = Endpoint.fromApi(api, ApiLive, { prefix: \"/api\" });\n * ```\n *\n * The layer backing an endpoint is built once, lazily, on the first request and\n * shared across subsequent requests (like `makeServerRuntime`). The returned\n * handler carries a `dispose()` that closes the layer's scope — call it on\n * shutdown if the endpoint holds resources.\n *\n * The Effect handlers receive an Effect-native `HttpServerRequest` (built from\n * `event.request`), not the SvelteKit `RequestEvent`.\n */\n\nimport type { RequestHandler } from \"@sveltejs/kit\";\nimport { Context, type Duration, Effect, Layer, Schedule, Stream } from \"effect\";\nimport type { Scope } from \"effect\";\nimport * as FileSystem from \"effect/FileSystem\";\nimport * as Path from \"effect/Path\";\nimport * as Etag from \"effect/unstable/http/Etag\";\nimport * as HttpEffect from \"effect/unstable/http/HttpEffect\";\nimport * as HttpPlatform from \"effect/unstable/http/HttpPlatform\";\nimport * as HttpRouter from \"effect/unstable/http/HttpRouter\";\nimport type * as HttpServerRequest from \"effect/unstable/http/HttpServerRequest\";\nimport type * as HttpServerResponse from \"effect/unstable/http/HttpServerResponse\";\nimport type * as HttpApi from \"effect/unstable/httpapi/HttpApi\";\nimport * as HttpApiBuilder from \"effect/unstable/httpapi/HttpApiBuilder\";\nimport type * as HttpApiGroup from \"effect/unstable/httpapi/HttpApiGroup\";\nimport { encodeRetry, encodeSseFrame, HEARTBEAT_FRAME, SSE_HEADERS } from \"../internal/sse.js\";\n\n/** A Web `fetch`-style handler, as produced by Effect's `toWebHandler` family. */\ntype WebHandler = (request: Request) => Promise<Response>;\n\n/** A Web handler that also accepts a per-request service context. */\ntype WebHandlerWithContext = (\n request: Request,\n context?: Context.Context<never>,\n) => Promise<Response>;\n\n/**\n * Resolve a request-scoped service context, if a resolver was given. The\n * resolver may return a `Context` directly or an `Effect` producing one (run\n * with no requirements), so a consumer can read the request to build\n * session-aware services per dispatch.\n */\nexport type RequestContext<RequestServices> = (\n request: Request,\n) =>\n | Context.Context<RequestServices>\n | Effect.Effect<Context.Context<RequestServices>, never, never>;\n\nconst resolveRequestContext = async <RequestServices>(\n request: Request,\n context: RequestContext<RequestServices> | undefined,\n): Promise<Context.Context<RequestServices> | undefined> => {\n if (context === undefined) return undefined;\n const result = context(request);\n return Effect.isEffect(result) ? Effect.runPromise(result) : result;\n};\n\n/**\n * A SvelteKit endpoint handler — the built-in\n * [`RequestHandler`](https://svelte.dev/docs/kit/@sveltejs-kit#RequestHandler) —\n * backed by an Effect HTTP construct. Assign it to a `+server.ts` export\n * (`fallback`, `GET`, ...). `dispose()` closes the scope of the layer behind it.\n */\nexport type EndpointHandler = RequestHandler & {\n /** Close the scope of the layer backing the endpoint (runs its finalizers). */\n readonly dispose: () => Promise<void>;\n};\n\n/** Shared options for every `Endpoint.from*` helper. */\nexport interface EndpointOptions {\n /**\n * A leading path segment to strip from each request before it reaches the\n * Effect handler — the SvelteKit mount point. For an endpoint mounted at\n * `src/routes/api/[...path]/+server.ts` whose routes are defined relative to\n * the API root, pass `prefix: \"/api\"` so `/api/users` is dispatched as\n * `/users`. The match respects path boundaries (`/api` does not strip\n * `/apiary`). Defaults to no stripping.\n */\n readonly prefix?: string;\n}\n\nconst noopDispose = (): Promise<void> => Promise.resolve();\n\n/** Remove `prefix` from the request's path (respecting `/` boundaries). */\nconst stripPrefix = (request: Request, prefix: string): Request => {\n const normalized = prefix.endsWith(\"/\") ? prefix.slice(0, -1) : prefix;\n if (normalized === \"\") return request;\n\n const url = new URL(request.url);\n const path = url.pathname;\n if (path === normalized) {\n url.pathname = \"/\";\n } else if (path.startsWith(`${normalized}/`)) {\n url.pathname = path.slice(normalized.length);\n } else {\n return request;\n }\n return new Request(url, request);\n};\n\n/** Wrap a Web handler (and its dispose) as a SvelteKit endpoint handler. */\nconst make = <RequestServices = never>(\n webHandler: WebHandler | WebHandlerWithContext,\n dispose: () => Promise<void>,\n prefix: string | undefined,\n context?: RequestContext<RequestServices>,\n): EndpointHandler => {\n const handler: RequestHandler = async (event) => {\n const request = prefix === undefined ? event.request : stripPrefix(event.request, prefix);\n if (context === undefined) return (webHandler as WebHandler)(request);\n const ctx = await resolveRequestContext(request, context);\n return (webHandler as WebHandlerWithContext)(\n request,\n ctx as Context.Context<never> | undefined,\n );\n };\n return Object.assign(handler, { dispose });\n};\n\n/** The platform services an `HttpApi` needs, with a no-op file system. */\nconst apiPlatform = Layer.mergeAll(Path.layer, Etag.layerWeak, HttpPlatform.layer).pipe(\n Layer.provideMerge(FileSystem.layerNoop({})),\n);\n\n/**\n * Create a SvelteKit endpoint that serves an Effect\n * [`HttpApi`](https://effect.website).\n *\n * `layer` implements the API's groups (built with `HttpApiBuilder.group`), with\n * any application services already provided. The platform services an `HttpApi`\n * requires (`HttpPlatform`, `FileSystem`, `Path`, `Etag`) are supplied for you.\n *\n * @example\n * ```ts\n * // src/routes/api/[...path]/+server.ts\n * import { Endpoint } from \"@thomasfosterau/effect-sveltekit/server\";\n * import { api } from \"$lib/server/api\";\n * import { ApiLive } from \"$lib/server/handlers\";\n *\n * export const fallback = Endpoint.fromApi(api, ApiLive, { prefix: \"/api\" });\n * ```\n */\nexport const fromApi = <\n Id extends string,\n Groups extends HttpApiGroup.Any,\n E,\n LayerRequires = never,\n RequestServices = never,\n>(\n api: HttpApi.HttpApi<Id, Groups>,\n layer: Layer.Layer<HttpApiGroup.ToService<Id, Groups>, E, LayerRequires>,\n options?: EndpointOptions & {\n /** Serve the OpenAPI spec for the API at this path (e.g. `\"/openapi.json\"`). */\n readonly openapiPath?: `/${string}`;\n /** Add Effect's request logger middleware. Defaults to `false` (quiet). */\n readonly logger?: boolean;\n /**\n * Provide the request-scoped services the API groups require, per request.\n * The build-once platform layer (`HttpPlatform` / `FileSystem` / `Path` /\n * `Etag`) stays shared; only this slice is resolved and merged for each\n * dispatch — so a session-aware, request-pooled API can run on Workers\n * without rebuilding its platform layer.\n *\n * The resolver may return a `Context` or an `Effect` producing one. Leave\n * the matching services unprovided in `layer` and supply them here:\n *\n * ```ts\n * Endpoint.fromApi(api, ApiLive, {\n * prefix: \"/api\",\n * context: (request) => Context.make(CurrentUser, userFor(request)),\n * });\n * ```\n */\n readonly context?: RequestContext<RequestServices>;\n },\n): EndpointHandler => {\n const appLayer = HttpApiBuilder.layer(\n api,\n options?.openapiPath ? { openapiPath: options.openapiPath } : undefined,\n ).pipe(Layer.provide(layer), Layer.provide(apiPlatform));\n\n // The request-scoped services are supplied per dispatch via the web handler's\n // context argument, so they are hidden from the build-once layer here.\n const { handler, dispose } = HttpRouter.toWebHandler(\n appLayer as unknown as Layer.Layer<never, E, HttpRouter.HttpRouter>,\n { disableLogger: options?.logger !== true },\n );\n return make<RequestServices>(\n handler as WebHandlerWithContext,\n dispose,\n options?.prefix,\n options?.context,\n );\n};\n\n/**\n * Create a SvelteKit endpoint that serves an Effect `HttpRouter` (provided by\n * `layer`). The router's routes must be self-contained (any services they need\n * are provided within `layer`).\n *\n * @example\n * ```ts\n * // src/routes/api/[...path]/+server.ts\n * import { Endpoint } from \"@thomasfosterau/effect-sveltekit/server\";\n * import { Effect } from \"effect\";\n * import { HttpRouter, HttpServerResponse } from \"effect/unstable/http\";\n *\n * const RouterLive = HttpRouter.use((router) =>\n * router.add(\"GET\", \"/hello\", Effect.succeed(HttpServerResponse.text(\"hi\"))),\n * );\n *\n * export const fallback = Endpoint.fromRouter(RouterLive, { prefix: \"/api\" });\n * ```\n */\nexport const fromRouter = <\n A,\n E,\n R extends\n | HttpRouter.HttpRouter\n | HttpRouter.Request<\"Requires\", any>\n | HttpRouter.Request<\"GlobalRequires\", any>\n | HttpRouter.Request<\"Error\", any>\n | HttpRouter.Request<\"GlobalError\", any>,\n RequestServices = never,\n>(\n layer: Layer.Layer<A, E, R>,\n options?: EndpointOptions & {\n /** Add Effect's request logger middleware. Defaults to `false` (quiet). */\n readonly logger?: boolean;\n /**\n * Provide the request-scoped services the router's routes require, per\n * request (the routes' `HttpRouter.Request<\"Requires\", ...>` services). The\n * resolver may return a `Context` or an `Effect` producing one.\n */\n readonly context?: RequestContext<RequestServices>;\n },\n): EndpointHandler => {\n const { handler, dispose } = HttpRouter.toWebHandler(layer, {\n disableLogger: options?.logger !== true,\n });\n return make<RequestServices>(\n handler as WebHandlerWithContext,\n dispose,\n options?.prefix,\n options?.context,\n );\n};\n\n/**\n * Create a SvelteKit endpoint from a single Effect HTTP route — an effect\n * producing an `HttpServerResponse` for the current `HttpServerRequest`. Pass\n * `options.layer` to provide the route's services; the layer is built once and\n * shared.\n *\n * @example\n * ```ts\n * // src/routes/health/+server.ts\n * import { Endpoint } from \"@thomasfosterau/effect-sveltekit/server\";\n * import { Effect } from \"effect\";\n * import { HttpServerResponse } from \"effect/unstable/http\";\n *\n * export const GET = Endpoint.fromHttpEffect(\n * Effect.succeed(HttpServerResponse.text(\"ok\")),\n * );\n * ```\n */\nexport const fromHttpEffect = <E, R = never, ProvidedE = never>(\n effect: Effect.Effect<\n HttpServerResponse.HttpServerResponse,\n E,\n R | HttpServerRequest.HttpServerRequest | Scope.Scope\n >,\n options?: EndpointOptions & {\n /** A layer providing the route's services (`R`), built once and shared. */\n readonly layer?: Layer.Layer<R, ProvidedE>;\n },\n): EndpointHandler => {\n if (options?.layer) {\n const { handler, dispose } = HttpEffect.toWebHandlerLayer(effect, options.layer);\n return make(handler as WebHandler, dispose, options.prefix);\n }\n const handler = HttpEffect.toWebHandler(\n effect as Effect.Effect<\n HttpServerResponse.HttpServerResponse,\n E,\n HttpServerRequest.HttpServerRequest | Scope.Scope\n >,\n );\n return make(handler, noopDispose, options?.prefix);\n};\n\n/** Options for {@link fromStream}: how to frame each element as an SSE event. */\nexport interface FromStreamOptions<A, R = never> {\n /**\n * The event name (`event:` field). A string applies to every element, or a\n * function derives it per element (return `undefined` for an unnamed event).\n * Omit for the default unnamed `message` events.\n */\n readonly event?: string | ((value: A) => string | undefined);\n /**\n * Encode an element into the `data:` payload. Defaults to `JSON.stringify`.\n * Multi-line output is split across multiple `data:` lines automatically.\n */\n readonly data?: (value: A) => string;\n /** Derive an event id (`id:` field) the browser echoes on reconnect. */\n readonly id?: (value: A) => string | undefined;\n /**\n * The client reconnection delay in milliseconds, sent once as a leading\n * `retry:` field. The browser's `EventSource` reconnects automatically after\n * this delay when the connection drops.\n */\n readonly retry?: number;\n /**\n * Send a comment heartbeat on this interval to keep the connection alive\n * through proxies that time out idle streams. Accepts any `Duration.Input`\n * (e.g. `\"30 seconds\"`).\n */\n readonly heartbeat?: Duration.Input;\n /**\n * A layer (or context) providing the stream's services `R`, applied per\n * connection. Omit when the stream is self-contained (`R = never`).\n */\n readonly provide?: Layer.Layer<R> | Context.Context<R>;\n}\n\n/**\n * Create a SvelteKit endpoint that streams an Effect `Stream` to the browser as\n * [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events)\n * (`text/event-stream`). Consume it client-side with `Realtime.fromEventSource`\n * (from `@thomasfosterau/effect-sveltekit/client`) or the native `EventSource`.\n *\n * Each element is framed as one SSE event (`event` / `id` optional, `data`\n * defaults to JSON). A `retry` sets the reconnect delay; a `heartbeat` keeps\n * idle connections alive. The response closes when the stream ends; the stream\n * is interrupted (running its finalizers) when the client disconnects.\n *\n * @example\n * ```ts\n * // src/routes/events/+server.ts\n * import { Endpoint } from \"@thomasfosterau/effect-sveltekit/server\";\n * import { Schedule, Stream } from \"effect\";\n *\n * const ticks = Stream.fromSchedule(Schedule.spaced(\"1 second\"));\n *\n * export const GET = Endpoint.fromStream(ticks, {\n * event: \"tick\",\n * heartbeat: \"30 seconds\",\n * retry: 3000,\n * });\n * ```\n */\nexport const fromStream = <A, E, R = never>(\n stream: Stream.Stream<A, E, R>,\n options?: FromStreamOptions<A, R>,\n): RequestHandler => {\n const encodeData = options?.data ?? ((value: A): string => JSON.stringify(value));\n const eventOf = (value: A): string | undefined =>\n typeof options?.event === \"function\" ? options.event(value) : options?.event;\n\n return (event) => {\n // Frame each element, then encode the resulting strings to bytes.\n const events = stream.pipe(\n Stream.map((value) =>\n encodeSseFrame({\n data: encodeData(value),\n event: eventOf(value),\n id: options?.id?.(value),\n }),\n ),\n );\n\n // A leading `retry:` field, if configured.\n const withRetry =\n options?.retry === undefined ? events : Stream.prepend(events, [encodeRetry(options.retry)]);\n\n // Merge in a heartbeat that halts as soon as the data stream ends.\n const framed =\n options?.heartbeat === undefined\n ? withRetry\n : Stream.merge(\n withRetry,\n Stream.fromSchedule(Schedule.spaced(options.heartbeat)).pipe(\n Stream.map(() => HEARTBEAT_FRAME),\n ),\n { haltStrategy: \"left\" },\n );\n\n const bytes = Stream.encodeText(framed);\n const provided =\n options?.provide === undefined ? bytes : Stream.provide(bytes, options.provide);\n\n const body = Stream.toReadableStream(provided as Stream.Stream<Uint8Array, E>);\n\n // SvelteKit forwards a streaming body Response as-is.\n void event;\n return new Response(body, { headers: { ...SSE_HEADERS } });\n };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Endpoint.js","names":[],"sources":["../../src/server/Endpoint.ts"],"sourcesContent":["/**\n * Create SvelteKit server endpoints (`+server.ts`) backed by Effect — the\n * `Endpoint` namespace of `@thomasfosterau/effect-sveltekit/server`.\n *\n * A SvelteKit endpoint is a `RequestHandler` (`(event) => Response`). Effect can\n * turn an [`HttpApi`](https://effect.website), an `HttpRouter`, or a single\n * route effect into a Web `fetch` handler; these helpers wrap one as a SvelteKit\n * endpoint handler so a route can be served by Effect. Mount it on a catch-all\n * route (`[...path]`) and assign it to `fallback` so every method and sub-path\n * reaches it:\n *\n * @example\n * ```ts\n * // src/routes/api/[...path]/+server.ts\n * import { Endpoint } from \"@thomasfosterau/effect-sveltekit/server\";\n * import { api } from \"$lib/server/api\";\n * import { ApiLive } from \"$lib/server/handlers\"; // HttpApiBuilder.group(...) + your services\n *\n * // `prefix` strips the SvelteKit mount path so the API's own paths\n * // (e.g. \"/users\") match.\n * export const fallback = Endpoint.fromApi(api, ApiLive, { prefix: \"/api\" });\n * ```\n *\n * The layer backing an endpoint is built once, lazily, on the first request and\n * shared across subsequent requests (like `makeServerRuntime`). The returned\n * handler carries a `dispose()` that closes the layer's scope — call it on\n * shutdown if the endpoint holds resources.\n *\n * The Effect handlers receive an Effect-native `HttpServerRequest` (built from\n * `event.request`), not the SvelteKit `RequestEvent`.\n */\n\nimport type { RequestHandler } from \"@sveltejs/kit\";\nimport { Context, type Duration, Effect, Layer, Schedule, Stream } from \"effect\";\nimport type { Scope } from \"effect\";\nimport * as FileSystem from \"effect/FileSystem\";\nimport * as Path from \"effect/Path\";\nimport * as Etag from \"effect/http/Etag\";\nimport * as HttpEffect from \"effect/http/HttpEffect\";\nimport * as HttpPlatform from \"effect/http/HttpPlatform\";\nimport * as HttpRouter from \"effect/http/HttpRouter\";\nimport type * as HttpServerRequest from \"effect/http/HttpServerRequest\";\nimport type * as HttpServerResponse from \"effect/http/HttpServerResponse\";\nimport type * as HttpApi from \"effect/http-api/HttpApi\";\nimport * as HttpApiBuilder from \"effect/http-api/HttpApiBuilder\";\nimport type * as HttpApiGroup from \"effect/http-api/HttpApiGroup\";\nimport { encodeRetry, encodeSseFrame, HEARTBEAT_FRAME, SSE_HEADERS } from \"../internal/sse.js\";\n\n/** A Web `fetch`-style handler, as produced by Effect's `toWebHandler` family. */\ntype WebHandler = (request: Request) => Promise<Response>;\n\n/** A Web handler that also accepts a per-request service context. */\ntype WebHandlerWithContext = (\n request: Request,\n context?: Context.Context<never>,\n) => Promise<Response>;\n\n/**\n * Resolve a request-scoped service context, if a resolver was given. The\n * resolver may return a `Context` directly or an `Effect` producing one (run\n * with no requirements), so a consumer can read the request to build\n * session-aware services per dispatch.\n */\nexport type RequestContext<RequestServices> = (\n request: Request,\n) =>\n | Context.Context<RequestServices>\n | Effect.Effect<Context.Context<RequestServices>, never, never>;\n\nconst resolveRequestContext = async <RequestServices>(\n request: Request,\n context: RequestContext<RequestServices> | undefined,\n): Promise<Context.Context<RequestServices> | undefined> => {\n if (context === undefined) return undefined;\n const result = context(request);\n return Effect.isEffect(result) ? Effect.runPromise(result) : result;\n};\n\n/**\n * A SvelteKit endpoint handler — the built-in\n * [`RequestHandler`](https://svelte.dev/docs/kit/@sveltejs-kit#RequestHandler) —\n * backed by an Effect HTTP construct. Assign it to a `+server.ts` export\n * (`fallback`, `GET`, ...). `dispose()` closes the scope of the layer behind it.\n */\nexport type EndpointHandler = RequestHandler & {\n /** Close the scope of the layer backing the endpoint (runs its finalizers). */\n readonly dispose: () => Promise<void>;\n};\n\n/** Shared options for every `Endpoint.from*` helper. */\nexport interface EndpointOptions {\n /**\n * A leading path segment to strip from each request before it reaches the\n * Effect handler — the SvelteKit mount point. For an endpoint mounted at\n * `src/routes/api/[...path]/+server.ts` whose routes are defined relative to\n * the API root, pass `prefix: \"/api\"` so `/api/users` is dispatched as\n * `/users`. The match respects path boundaries (`/api` does not strip\n * `/apiary`). Defaults to no stripping.\n */\n readonly prefix?: string;\n}\n\nconst noopDispose = (): Promise<void> => Promise.resolve();\n\n/** Remove `prefix` from the request's path (respecting `/` boundaries). */\nconst stripPrefix = (request: Request, prefix: string): Request => {\n const normalized = prefix.endsWith(\"/\") ? prefix.slice(0, -1) : prefix;\n if (normalized === \"\") return request;\n\n const url = new URL(request.url);\n const path = url.pathname;\n if (path === normalized) {\n url.pathname = \"/\";\n } else if (path.startsWith(`${normalized}/`)) {\n url.pathname = path.slice(normalized.length);\n } else {\n return request;\n }\n return new Request(url, request);\n};\n\n/** Wrap a Web handler (and its dispose) as a SvelteKit endpoint handler. */\nconst make = <RequestServices = never>(\n webHandler: WebHandler | WebHandlerWithContext,\n dispose: () => Promise<void>,\n prefix: string | undefined,\n context?: RequestContext<RequestServices>,\n): EndpointHandler => {\n const handler: RequestHandler = async (event) => {\n const request = prefix === undefined ? event.request : stripPrefix(event.request, prefix);\n if (context === undefined) return (webHandler as WebHandler)(request);\n const ctx = await resolveRequestContext(request, context);\n return (webHandler as WebHandlerWithContext)(\n request,\n ctx as Context.Context<never> | undefined,\n );\n };\n return Object.assign(handler, { dispose });\n};\n\n/** The platform services an `HttpApi` needs, with a no-op file system. */\nconst apiPlatform = Layer.mergeAll(Path.layer, Etag.layerWeak, HttpPlatform.layer).pipe(\n Layer.provideMerge(FileSystem.layerNoop({})),\n);\n\n/**\n * Create a SvelteKit endpoint that serves an Effect\n * [`HttpApi`](https://effect.website).\n *\n * `layer` implements the API's groups (built with `HttpApiBuilder.group`), with\n * any application services already provided. The platform services an `HttpApi`\n * requires (`HttpPlatform`, `FileSystem`, `Path`, `Etag`) are supplied for you.\n *\n * @example\n * ```ts\n * // src/routes/api/[...path]/+server.ts\n * import { Endpoint } from \"@thomasfosterau/effect-sveltekit/server\";\n * import { api } from \"$lib/server/api\";\n * import { ApiLive } from \"$lib/server/handlers\";\n *\n * export const fallback = Endpoint.fromApi(api, ApiLive, { prefix: \"/api\" });\n * ```\n */\nexport const fromApi = <\n Id extends string,\n Groups extends HttpApiGroup.Constraint,\n E,\n LayerRequires = never,\n RequestServices = never,\n>(\n api: HttpApi.HttpApi<Id, Groups>,\n layer: Layer.Layer<HttpApiGroup.ToService<Id, Groups>, E, LayerRequires>,\n options?: EndpointOptions & {\n /** Serve the OpenAPI spec for the API at this path (e.g. `\"/openapi.json\"`). */\n readonly openapiPath?: `/${string}`;\n /** Add Effect's request logger middleware. Defaults to `false` (quiet). */\n readonly logger?: boolean;\n /**\n * Provide the request-scoped services the API groups require, per request.\n * The build-once platform layer (`HttpPlatform` / `FileSystem` / `Path` /\n * `Etag`) stays shared; only this slice is resolved and merged for each\n * dispatch — so a session-aware, request-pooled API can run on Workers\n * without rebuilding its platform layer.\n *\n * The resolver may return a `Context` or an `Effect` producing one. Leave\n * the matching services unprovided in `layer` and supply them here:\n *\n * ```ts\n * Endpoint.fromApi(api, ApiLive, {\n * prefix: \"/api\",\n * context: (request) => Context.make(CurrentUser, userFor(request)),\n * });\n * ```\n */\n readonly context?: RequestContext<RequestServices>;\n },\n): EndpointHandler => {\n const appLayer = HttpApiBuilder.layer(\n api,\n options?.openapiPath ? { openapiPath: options.openapiPath } : undefined,\n ).pipe(Layer.provide(layer), Layer.provide(apiPlatform));\n\n // The request-scoped services are supplied per dispatch via the web handler's\n // context argument, so they are hidden from the build-once layer here.\n const { handler, dispose } = HttpRouter.toWebHandler(\n appLayer as unknown as Layer.Layer<never, E, HttpRouter.HttpRouter>,\n { disableLogger: options?.logger !== true },\n );\n return make<RequestServices>(\n handler as WebHandlerWithContext,\n dispose,\n options?.prefix,\n options?.context,\n );\n};\n\n/**\n * Create a SvelteKit endpoint that serves an Effect `HttpRouter` (provided by\n * `layer`). The router's routes must be self-contained (any services they need\n * are provided within `layer`).\n *\n * @example\n * ```ts\n * // src/routes/api/[...path]/+server.ts\n * import { Endpoint } from \"@thomasfosterau/effect-sveltekit/server\";\n * import { Effect } from \"effect\";\n * import { HttpRouter, HttpServerResponse } from \"effect/http\";\n *\n * const RouterLive = HttpRouter.use((router) =>\n * router.add(\"GET\", \"/hello\", Effect.succeed(HttpServerResponse.text(\"hi\"))),\n * );\n *\n * export const fallback = Endpoint.fromRouter(RouterLive, { prefix: \"/api\" });\n * ```\n */\nexport const fromRouter = <\n A,\n E,\n R extends\n | HttpRouter.HttpRouter\n | HttpRouter.Request<\"Requires\", any>\n | HttpRouter.Request<\"GlobalRequires\", any>\n | HttpRouter.Request<\"Error\", any>\n | HttpRouter.Request<\"GlobalError\", any>,\n RequestServices = never,\n>(\n layer: Layer.Layer<A, E, R>,\n options?: EndpointOptions & {\n /** Add Effect's request logger middleware. Defaults to `false` (quiet). */\n readonly logger?: boolean;\n /**\n * Provide the request-scoped services the router's routes require, per\n * request (the routes' `HttpRouter.Request<\"Requires\", ...>` services). The\n * resolver may return a `Context` or an `Effect` producing one.\n */\n readonly context?: RequestContext<RequestServices>;\n },\n): EndpointHandler => {\n const { handler, dispose } = HttpRouter.toWebHandler(layer, {\n disableLogger: options?.logger !== true,\n });\n return make<RequestServices>(\n handler as WebHandlerWithContext,\n dispose,\n options?.prefix,\n options?.context,\n );\n};\n\n/**\n * Create a SvelteKit endpoint from a single Effect HTTP route — an effect\n * producing an `HttpServerResponse` for the current `HttpServerRequest`. Pass\n * `options.layer` to provide the route's services; the layer is built once and\n * shared.\n *\n * @example\n * ```ts\n * // src/routes/health/+server.ts\n * import { Endpoint } from \"@thomasfosterau/effect-sveltekit/server\";\n * import { Effect } from \"effect\";\n * import { HttpServerResponse } from \"effect/http\";\n *\n * export const GET = Endpoint.fromHttpEffect(\n * Effect.succeed(HttpServerResponse.text(\"ok\")),\n * );\n * ```\n */\nexport const fromHttpEffect = <E, R = never, ProvidedE = never>(\n effect: Effect.Effect<\n HttpServerResponse.HttpServerResponse,\n E,\n R | HttpServerRequest.HttpServerRequest | Scope.Scope\n >,\n options?: EndpointOptions & {\n /** A layer providing the route's services (`R`), built once and shared. */\n readonly layer?: Layer.Layer<R, ProvidedE>;\n },\n): EndpointHandler => {\n if (options?.layer) {\n const { handler, dispose } = HttpEffect.toWebHandlerLayer(effect, options.layer);\n return make(handler as WebHandler, dispose, options.prefix);\n }\n const handler = HttpEffect.toWebHandler(\n effect as Effect.Effect<\n HttpServerResponse.HttpServerResponse,\n E,\n HttpServerRequest.HttpServerRequest | Scope.Scope\n >,\n );\n return make(handler, noopDispose, options?.prefix);\n};\n\n/** Options for {@link fromStream}: how to frame each element as an SSE event. */\nexport interface FromStreamOptions<A, R = never> {\n /**\n * The event name (`event:` field). A string applies to every element, or a\n * function derives it per element (return `undefined` for an unnamed event).\n * Omit for the default unnamed `message` events.\n */\n readonly event?: string | ((value: A) => string | undefined);\n /**\n * Encode an element into the `data:` payload. Defaults to `JSON.stringify`.\n * Multi-line output is split across multiple `data:` lines automatically.\n */\n readonly data?: (value: A) => string;\n /** Derive an event id (`id:` field) the browser echoes on reconnect. */\n readonly id?: (value: A) => string | undefined;\n /**\n * The client reconnection delay in milliseconds, sent once as a leading\n * `retry:` field. The browser's `EventSource` reconnects automatically after\n * this delay when the connection drops.\n */\n readonly retry?: number;\n /**\n * Send a comment heartbeat on this interval to keep the connection alive\n * through proxies that time out idle streams. Accepts any `Duration.Input`\n * (e.g. `\"30 seconds\"`).\n */\n readonly heartbeat?: Duration.Input;\n /**\n * A layer (or context) providing the stream's services `R`, applied per\n * connection. Omit when the stream is self-contained (`R = never`).\n */\n readonly provide?: Layer.Layer<R> | Context.Context<R>;\n}\n\n/**\n * Create a SvelteKit endpoint that streams an Effect `Stream` to the browser as\n * [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events)\n * (`text/event-stream`). Consume it client-side with `Realtime.fromEventSource`\n * (from `@thomasfosterau/effect-sveltekit/client`) or the native `EventSource`.\n *\n * Each element is framed as one SSE event (`event` / `id` optional, `data`\n * defaults to JSON). A `retry` sets the reconnect delay; a `heartbeat` keeps\n * idle connections alive. The response closes when the stream ends; the stream\n * is interrupted (running its finalizers) when the client disconnects.\n *\n * @example\n * ```ts\n * // src/routes/events/+server.ts\n * import { Endpoint } from \"@thomasfosterau/effect-sveltekit/server\";\n * import { Schedule, Stream } from \"effect\";\n *\n * const ticks = Stream.fromSchedule(Schedule.spaced(\"1 second\"));\n *\n * export const GET = Endpoint.fromStream(ticks, {\n * event: \"tick\",\n * heartbeat: \"30 seconds\",\n * retry: 3000,\n * });\n * ```\n */\nexport const fromStream = <A, E, R = never>(\n stream: Stream.Stream<A, E, R>,\n options?: FromStreamOptions<A, R>,\n): RequestHandler => {\n const encodeData = options?.data ?? ((value: A): string => JSON.stringify(value));\n const eventOf = (value: A): string | undefined =>\n typeof options?.event === \"function\" ? options.event(value) : options?.event;\n\n return (event) => {\n // Frame each element, then encode the resulting strings to bytes.\n const events = stream.pipe(\n Stream.map((value) =>\n encodeSseFrame({\n data: encodeData(value),\n event: eventOf(value),\n id: options?.id?.(value),\n }),\n ),\n );\n\n // A leading `retry:` field, if configured.\n const withRetry =\n options?.retry === undefined ? events : Stream.prepend(events, [encodeRetry(options.retry)]);\n\n // Merge in a heartbeat that halts as soon as the data stream ends.\n const framed =\n options?.heartbeat === undefined\n ? withRetry\n : Stream.merge(\n withRetry,\n Stream.fromSchedule(Schedule.spaced(options.heartbeat)).pipe(\n Stream.map(() => HEARTBEAT_FRAME),\n ),\n { haltStrategy: \"left\" },\n );\n\n const bytes = Stream.encodeText(framed);\n const provided =\n options?.provide === undefined ? bytes : Stream.provide(bytes, options.provide);\n\n const body = Stream.toReadableStream(provided as Stream.Stream<Uint8Array, E>);\n\n // SvelteKit forwards a streaming body Response as-is.\n void event;\n return new Response(body, { headers: { ...SSE_HEADERS } });\n };\n};\n"],"mappings":"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"}
|
package/dist/server/Hooks.d.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { SvelteKitServices } from "../app-runtime.js";
|
|
2
2
|
import { Effect } from "effect";
|
|
3
3
|
import { Handle, HandleFetch, HandleServerError, ServerInit } from "@sveltejs/kit";
|
|
4
|
-
|
|
5
|
-
//#region src/server/Hooks.d.ts
|
|
6
4
|
declare namespace Hooks_d_exports {
|
|
7
5
|
export { handle, handleError, handleFetch, init };
|
|
8
6
|
}
|
|
@@ -93,5 +91,5 @@ declare function handleError(fn: (args: Parameters<HandleServerError>[0]) => Eff
|
|
|
93
91
|
*/
|
|
94
92
|
declare function init(effect: Effect.Effect<void, unknown>): ServerInit;
|
|
95
93
|
//#endregion
|
|
96
|
-
export { Hooks_d_exports };
|
|
94
|
+
export { Hooks_d_exports, handle, handleError, handleFetch, init };
|
|
97
95
|
//# sourceMappingURL=Hooks.d.ts.map
|
package/dist/server/Hooks.js
CHANGED
package/dist/server/Hooks.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Hooks.js","names":[],"sources":["../../src/server/Hooks.ts"],"sourcesContent":["/**\n * Effect wrappers for SvelteKit's server-side hooks (`src/hooks.server.ts`),\n * exposed as the `Hooks` namespace of `@thomasfosterau/effect-sveltekit/server`.\n *\n * Each helper turns an Effect (or a function returning one) into the\n * function-shaped export SvelteKit expects. Effects run on the SvelteKit server\n * runtime, so they have access to platform services (`HttpClient`, the\n * `RequestEvent`, ...). To additionally provide your application's services,\n * use the matching methods on an app-wide runtime from `makeServerRuntime`.\n *\n * @example\n * ```ts\n * // src/hooks.server.ts\n * import { Hooks } from '@thomasfosterau/effect-sveltekit/server';\n * import { Effect } from 'effect';\n *\n * export const handle = Hooks.handle(({ event, resolve }) =>\n * Effect.gen(function* () {\n * const response = yield* Effect.promise(() => resolve(event));\n * yield* Effect.logInfo(`${event.url.pathname} -> ${response.status}`);\n * return response;\n * })\n * );\n * ```\n */\n\nimport type { Handle, HandleFetch, HandleServerError, ServerInit } from \"@sveltejs/kit\";\nimport { Effect } from \"effect\";\nimport type { SvelteKitServices } from \"../app-runtime.js\";\nimport { defaultServerRuntime } from \"../internal/default-runtime.js\";\n\n/**\n * Wraps an Effect-based function as a SvelteKit\n * [`handle`](https://svelte.dev/docs/kit/hooks#Server-hooks-handle) hook, which\n * runs on every request and controls how the response is produced.\n *\n * SvelteKit control flow (`redirect()`, `error()`) raised inside the effect is\n * passed through to SvelteKit.\n *\n * @example\n * ```ts\n * // src/hooks.server.ts\n * import { Hooks } from '@thomasfosterau/effect-sveltekit/server';\n * import { Effect } from 'effect';\n *\n * export const handle = Hooks.handle(({ event, resolve }) =>\n * Effect.gen(function* () {\n * // custom logic before resolve\n * const response = yield* Effect.promise(() => resolve(event));\n * // custom logic after resolve\n * return response;\n * })\n * );\n * ```\n */\nexport function handle(\n fn: (args: Parameters<Handle>[0]) => Effect.Effect<Response, unknown, SvelteKitServices>,\n): Handle {\n return defaultServerRuntime().handle(fn);\n}\n\n/**\n * Wraps an Effect-based function as a SvelteKit\n * [`handleFetch`](https://svelte.dev/docs/kit/hooks#Server-hooks-handleFetch)\n * hook, which intercepts `event.fetch` calls made on the server (in `load`,\n * actions, endpoints, ...). The effect produces the `Response` to use.\n *\n * @example\n * ```ts\n * // src/hooks.server.ts\n * import { Hooks } from '@thomasfosterau/effect-sveltekit/server';\n * import { Effect } from 'effect';\n *\n * export const handleFetch = Hooks.handleFetch(({ request, fetch }) =>\n * Effect.gen(function* () {\n * // Redirect internal API calls to the upstream service.\n * const url = request.url.replace('https://api.internal', 'http://localhost:9999');\n * return yield* Effect.promise(() => fetch(new Request(url, request)));\n * })\n * );\n * ```\n */\nexport function handleFetch(\n fn: (args: Parameters<HandleFetch>[0]) => Effect.Effect<Response, unknown, SvelteKitServices>,\n): HandleFetch {\n return defaultServerRuntime().handleFetch(fn);\n}\n\n/**\n * Wraps an Effect-based function as the SvelteKit server\n * [`handleError`](https://svelte.dev/docs/kit/hooks#Shared-hooks-handleError)\n * hook, which runs when an unexpected error is thrown while responding to a\n * request. The effect receives the error and request event and produces the\n * shape exposed to the client (your `App.Error`, or nothing).\n *\n * @example\n * ```ts\n * // src/hooks.server.ts\n * import { Hooks } from '@thomasfosterau/effect-sveltekit/server';\n * import { Effect } from 'effect';\n *\n * export const handleError = Hooks.handleError(({ error, event }) =>\n * Effect.gen(function* () {\n * const id = crypto.randomUUID();\n * yield* Effect.logError(`${event.url.pathname} (${id})`, error);\n * return { message: 'Internal Error', id };\n * })\n * );\n * ```\n */\nexport function handleError(\n fn: (\n args: Parameters<HandleServerError>[0],\n ) => Effect.Effect<Awaited<ReturnType<HandleServerError>>, unknown, SvelteKitServices>,\n): HandleServerError {\n return defaultServerRuntime().handleError(fn);\n}\n\n/**\n * Wraps an Effect as the SvelteKit server\n * [`init`](https://svelte.dev/docs/kit/hooks#Shared-hooks-init) hook, which\n * runs once before the server responds to its first request. There is no\n * request event available, so the effect runs without per-request services.\n *\n * @example\n * ```ts\n * // src/hooks.server.ts\n * import { Hooks } from '@thomasfosterau/effect-sveltekit/server';\n * import { Effect } from 'effect';\n *\n * export const init = Hooks.init(Effect.logInfo('server starting up'));\n * ```\n */\nexport function init(effect: Effect.Effect<void, unknown>): ServerInit {\n return defaultServerRuntime().init(effect);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuDA,SAAgB,OACd,IACQ;CACR,OAAO,qBAAqB,
|
|
1
|
+
{"version":3,"file":"Hooks.js","names":[],"sources":["../../src/server/Hooks.ts"],"sourcesContent":["/**\n * Effect wrappers for SvelteKit's server-side hooks (`src/hooks.server.ts`),\n * exposed as the `Hooks` namespace of `@thomasfosterau/effect-sveltekit/server`.\n *\n * Each helper turns an Effect (or a function returning one) into the\n * function-shaped export SvelteKit expects. Effects run on the SvelteKit server\n * runtime, so they have access to platform services (`HttpClient`, the\n * `RequestEvent`, ...). To additionally provide your application's services,\n * use the matching methods on an app-wide runtime from `makeServerRuntime`.\n *\n * @example\n * ```ts\n * // src/hooks.server.ts\n * import { Hooks } from '@thomasfosterau/effect-sveltekit/server';\n * import { Effect } from 'effect';\n *\n * export const handle = Hooks.handle(({ event, resolve }) =>\n * Effect.gen(function* () {\n * const response = yield* Effect.promise(() => resolve(event));\n * yield* Effect.logInfo(`${event.url.pathname} -> ${response.status}`);\n * return response;\n * })\n * );\n * ```\n */\n\nimport type { Handle, HandleFetch, HandleServerError, ServerInit } from \"@sveltejs/kit\";\nimport { Effect } from \"effect\";\nimport type { SvelteKitServices } from \"../app-runtime.js\";\nimport { defaultServerRuntime } from \"../internal/default-runtime.js\";\n\n/**\n * Wraps an Effect-based function as a SvelteKit\n * [`handle`](https://svelte.dev/docs/kit/hooks#Server-hooks-handle) hook, which\n * runs on every request and controls how the response is produced.\n *\n * SvelteKit control flow (`redirect()`, `error()`) raised inside the effect is\n * passed through to SvelteKit.\n *\n * @example\n * ```ts\n * // src/hooks.server.ts\n * import { Hooks } from '@thomasfosterau/effect-sveltekit/server';\n * import { Effect } from 'effect';\n *\n * export const handle = Hooks.handle(({ event, resolve }) =>\n * Effect.gen(function* () {\n * // custom logic before resolve\n * const response = yield* Effect.promise(() => resolve(event));\n * // custom logic after resolve\n * return response;\n * })\n * );\n * ```\n */\nexport function handle(\n fn: (args: Parameters<Handle>[0]) => Effect.Effect<Response, unknown, SvelteKitServices>,\n): Handle {\n return defaultServerRuntime().handle(fn);\n}\n\n/**\n * Wraps an Effect-based function as a SvelteKit\n * [`handleFetch`](https://svelte.dev/docs/kit/hooks#Server-hooks-handleFetch)\n * hook, which intercepts `event.fetch` calls made on the server (in `load`,\n * actions, endpoints, ...). The effect produces the `Response` to use.\n *\n * @example\n * ```ts\n * // src/hooks.server.ts\n * import { Hooks } from '@thomasfosterau/effect-sveltekit/server';\n * import { Effect } from 'effect';\n *\n * export const handleFetch = Hooks.handleFetch(({ request, fetch }) =>\n * Effect.gen(function* () {\n * // Redirect internal API calls to the upstream service.\n * const url = request.url.replace('https://api.internal', 'http://localhost:9999');\n * return yield* Effect.promise(() => fetch(new Request(url, request)));\n * })\n * );\n * ```\n */\nexport function handleFetch(\n fn: (args: Parameters<HandleFetch>[0]) => Effect.Effect<Response, unknown, SvelteKitServices>,\n): HandleFetch {\n return defaultServerRuntime().handleFetch(fn);\n}\n\n/**\n * Wraps an Effect-based function as the SvelteKit server\n * [`handleError`](https://svelte.dev/docs/kit/hooks#Shared-hooks-handleError)\n * hook, which runs when an unexpected error is thrown while responding to a\n * request. The effect receives the error and request event and produces the\n * shape exposed to the client (your `App.Error`, or nothing).\n *\n * @example\n * ```ts\n * // src/hooks.server.ts\n * import { Hooks } from '@thomasfosterau/effect-sveltekit/server';\n * import { Effect } from 'effect';\n *\n * export const handleError = Hooks.handleError(({ error, event }) =>\n * Effect.gen(function* () {\n * const id = crypto.randomUUID();\n * yield* Effect.logError(`${event.url.pathname} (${id})`, error);\n * return { message: 'Internal Error', id };\n * })\n * );\n * ```\n */\nexport function handleError(\n fn: (\n args: Parameters<HandleServerError>[0],\n ) => Effect.Effect<Awaited<ReturnType<HandleServerError>>, unknown, SvelteKitServices>,\n): HandleServerError {\n return defaultServerRuntime().handleError(fn);\n}\n\n/**\n * Wraps an Effect as the SvelteKit server\n * [`init`](https://svelte.dev/docs/kit/hooks#Shared-hooks-init) hook, which\n * runs once before the server responds to its first request. There is no\n * request event available, so the effect runs without per-request services.\n *\n * @example\n * ```ts\n * // src/hooks.server.ts\n * import { Hooks } from '@thomasfosterau/effect-sveltekit/server';\n * import { Effect } from 'effect';\n *\n * export const init = Hooks.init(Effect.logInfo('server starting up'));\n * ```\n */\nexport function init(effect: Effect.Effect<void, unknown>): ServerInit {\n return defaultServerRuntime().init(effect);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuDA,SAAgB,OACd,IACQ;CACR,OAAO,qBAAqB,CAAC,CAAC,OAAO,EAAE;AACzC;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,YACd,IACa;CACb,OAAO,qBAAqB,CAAC,CAAC,YAAY,EAAE;AAC9C;;;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAgB,YACd,IAGmB;CACnB,OAAO,qBAAqB,CAAC,CAAC,YAAY,EAAE;AAC9C;;;;;;;;;;;;;;;;AAiBA,SAAgB,KAAK,QAAkD;CACrE,OAAO,qBAAqB,CAAC,CAAC,KAAK,MAAM;AAC3C"}
|
package/dist/server.d.ts
CHANGED
|
@@ -3,16 +3,17 @@ import { SvelteKitRequestEvent, SvelteKitRuntime, runWithSvelteKitRuntime } from
|
|
|
3
3
|
import { AdapterEndpointOptions, ErrorTranslator, FromLayerPerRequestOptions, RequestRuntime, RequestRuntimeProvider, RequestRuntimeRunners, RuntimeAdapter, RuntimeAdapterOptions, makeRuntimeAdapter } from "./request-runtime.js";
|
|
4
4
|
import { SvelteKitCookies, SvelteKitCookiesInterface, SvelteKitLocals, SvelteKitResponseHeaders, SvelteKitResponseHeadersInterface, requestServicesLayer } from "./request-services.js";
|
|
5
5
|
import { RequestRuntime as RequestRuntime$1, ServerRuntime, ServerRuntimeOptions, SvelteKitServices, makeServerRuntime } from "./app-runtime.js";
|
|
6
|
+
import { ResponseHeaders } from "./response-headers.js";
|
|
6
7
|
import { sveltekitConfig, sveltekitConfigProvider } from "./config.js";
|
|
7
8
|
import { Hooks_d_exports } from "./server/Hooks.js";
|
|
8
9
|
import { Endpoint_d_exports } from "./server/Endpoint.js";
|
|
9
|
-
import { RemoteFunction } from "./remote.
|
|
10
|
+
import { RemoteFunction } from "./remote-functions.js";
|
|
10
11
|
import { ParseError, ParseIssue, decodeFormData, decodeJson, decodeParams, decodeSearchParams } from "./request-parse.js";
|
|
11
12
|
import { defer } from "./streamed-load.js";
|
|
12
13
|
import { KitActionFailure, KitError, KitErrorTranslator, KitRedirect, KitTranslatorCase, SvelteKit } from "./kit.js";
|
|
14
|
+
import { errors_d_exports } from "./errors.js";
|
|
13
15
|
import { Effect } from "effect";
|
|
14
16
|
import { Action, Actions, RequestEvent, ServerLoad } from "@sveltejs/kit";
|
|
15
|
-
|
|
16
17
|
//#region src/server.d.ts
|
|
17
18
|
/**
|
|
18
19
|
* Wraps an Effect-based function to work as a SvelteKit server load function.
|
|
@@ -30,7 +31,7 @@ import { Action, Actions, RequestEvent, ServerLoad } from "@sveltejs/kit";
|
|
|
30
31
|
* ```ts
|
|
31
32
|
* import { serverLoad } from '@thomasfosterau/effect-sveltekit/server';
|
|
32
33
|
* import { Effect } from 'effect';
|
|
33
|
-
* import * as HttpClient from 'effect/
|
|
34
|
+
* import * as HttpClient from 'effect/http/HttpClient';
|
|
34
35
|
*
|
|
35
36
|
* export const load = serverLoad((event) =>
|
|
36
37
|
* Effect.gen(function* () {
|
|
@@ -95,7 +96,7 @@ declare function actions<Params extends SvelteRouteParams = SvelteRouteParams, O
|
|
|
95
96
|
* import { endpoint } from '@thomasfosterau/effect-sveltekit/server';
|
|
96
97
|
* import { Effect } from 'effect';
|
|
97
98
|
* import { json } from '@sveltejs/kit';
|
|
98
|
-
* import * as HttpClient from 'effect/
|
|
99
|
+
* import * as HttpClient from 'effect/http/HttpClient';
|
|
99
100
|
*
|
|
100
101
|
* export const GET = endpoint((event) =>
|
|
101
102
|
* Effect.gen(function* () {
|
|
@@ -110,5 +111,5 @@ declare function endpoint<Params extends SvelteRouteParams = SvelteRouteParams,
|
|
|
110
111
|
exposeErrors?: boolean;
|
|
111
112
|
}): (event: RequestEvent<Params, RouteId>) => Promise<Response>;
|
|
112
113
|
//#endregion
|
|
113
|
-
export { type AdapterEndpointOptions, Endpoint_d_exports as Endpoint, type ErrorTranslator, type FromLayerPerRequestOptions, Hooks_d_exports as Hooks, KitActionFailure, KitError, type KitErrorTranslator, KitRedirect, type KitTranslatorCase, ParseError, type ParseIssue, RemoteFunction, RequestRuntime, type RequestRuntimeProvider, type RequestRuntimeRunners, type RuntimeAdapter, type RuntimeAdapterOptions, type RequestRuntime$1 as ScopedRequestRuntime, type ServerRuntime, type ServerRuntimeOptions, SvelteKit, SvelteKitCookies, type SvelteKitCookiesInterface, SvelteKitLocals, SvelteKitRequestEvent, SvelteKitResponseHeaders, type SvelteKitResponseHeadersInterface, SvelteKitRuntime, type SvelteKitServices, action, actions, decodeFormData, decodeJson, decodeParams, decodeSearchParams, defer, endpoint, makeRuntimeAdapter, makeServerRuntime, requestServicesLayer, runWithSvelteKitRuntime, serverLoad, sveltekitConfig, sveltekitConfigProvider };
|
|
114
|
+
export { type AdapterEndpointOptions, Endpoint_d_exports as Endpoint, type ErrorTranslator, errors_d_exports as Errors, type FromLayerPerRequestOptions, Hooks_d_exports as Hooks, KitActionFailure, KitError, type KitErrorTranslator, KitRedirect, type KitTranslatorCase, ParseError, type ParseIssue, RemoteFunction, RequestRuntime, type RequestRuntimeProvider, type RequestRuntimeRunners, ResponseHeaders, type RuntimeAdapter, type RuntimeAdapterOptions, type RequestRuntime$1 as ScopedRequestRuntime, type ServerRuntime, type ServerRuntimeOptions, SvelteKit, SvelteKitCookies, type SvelteKitCookiesInterface, SvelteKitLocals, SvelteKitRequestEvent, SvelteKitResponseHeaders, type SvelteKitResponseHeadersInterface, SvelteKitRuntime, type SvelteKitServices, action, actions, decodeFormData, decodeJson, decodeParams, decodeSearchParams, defer, endpoint, makeRuntimeAdapter, makeServerRuntime, requestServicesLayer, runWithSvelteKitRuntime, serverLoad, sveltekitConfig, sveltekitConfigProvider };
|
|
114
115
|
//# sourceMappingURL=server.d.ts.map
|
package/dist/server.js
CHANGED
|
@@ -3,13 +3,15 @@ import { KitActionFailure, KitError, KitRedirect, SvelteKit } from "./kit.js";
|
|
|
3
3
|
import { SvelteKitCookies, SvelteKitLocals, SvelteKitResponseHeaders, requestServicesLayer } from "./request-services.js";
|
|
4
4
|
import { makeServerRuntime } from "./app-runtime.js";
|
|
5
5
|
import { defaultServerRuntime } from "./internal/default-runtime.js";
|
|
6
|
+
import { ResponseHeaders } from "./response-headers.js";
|
|
6
7
|
import { sveltekitConfig, sveltekitConfigProvider } from "./config.js";
|
|
7
8
|
import { Hooks_exports } from "./server/Hooks.js";
|
|
8
9
|
import { Endpoint_exports } from "./server/Endpoint.js";
|
|
9
|
-
import { RemoteFunction } from "./remote.
|
|
10
|
+
import { RemoteFunction } from "./remote-functions.js";
|
|
10
11
|
import { RequestRuntime, makeRuntimeAdapter } from "./request-runtime.js";
|
|
11
12
|
import { ParseError, decodeFormData, decodeJson, decodeParams, decodeSearchParams } from "./request-parse.js";
|
|
12
13
|
import { defer } from "./streamed-load.js";
|
|
14
|
+
import { errors_exports } from "./errors.js";
|
|
13
15
|
import { Cause, Exit } from "effect";
|
|
14
16
|
import { isHttpError, isRedirect } from "@sveltejs/kit";
|
|
15
17
|
//#region src/server.ts
|
|
@@ -29,7 +31,7 @@ import { isHttpError, isRedirect } from "@sveltejs/kit";
|
|
|
29
31
|
* ```ts
|
|
30
32
|
* import { serverLoad } from '@thomasfosterau/effect-sveltekit/server';
|
|
31
33
|
* import { Effect } from 'effect';
|
|
32
|
-
* import * as HttpClient from 'effect/
|
|
34
|
+
* import * as HttpClient from 'effect/http/HttpClient';
|
|
33
35
|
*
|
|
34
36
|
* export const load = serverLoad((event) =>
|
|
35
37
|
* Effect.gen(function* () {
|
|
@@ -100,7 +102,7 @@ function actions(actionsMap) {
|
|
|
100
102
|
* import { endpoint } from '@thomasfosterau/effect-sveltekit/server';
|
|
101
103
|
* import { Effect } from 'effect';
|
|
102
104
|
* import { json } from '@sveltejs/kit';
|
|
103
|
-
* import * as HttpClient from 'effect/
|
|
105
|
+
* import * as HttpClient from 'effect/http/HttpClient';
|
|
104
106
|
*
|
|
105
107
|
* export const GET = endpoint((event) =>
|
|
106
108
|
* Effect.gen(function* () {
|
|
@@ -131,6 +133,6 @@ function endpoint(fn, options) {
|
|
|
131
133
|
};
|
|
132
134
|
}
|
|
133
135
|
//#endregion
|
|
134
|
-
export { Endpoint_exports as Endpoint, Hooks_exports as Hooks, KitActionFailure, KitError, KitRedirect, ParseError, RemoteFunction, RequestRuntime, SvelteKit, SvelteKitCookies, SvelteKitLocals, SvelteKitRequestEvent, SvelteKitResponseHeaders, SvelteKitRuntime, action, actions, decodeFormData, decodeJson, decodeParams, decodeSearchParams, defer, endpoint, makeRuntimeAdapter, makeServerRuntime, requestServicesLayer, runWithSvelteKitRuntime, serverLoad, sveltekitConfig, sveltekitConfigProvider };
|
|
136
|
+
export { Endpoint_exports as Endpoint, errors_exports as Errors, Hooks_exports as Hooks, KitActionFailure, KitError, KitRedirect, ParseError, RemoteFunction, RequestRuntime, ResponseHeaders, SvelteKit, SvelteKitCookies, SvelteKitLocals, SvelteKitRequestEvent, SvelteKitResponseHeaders, SvelteKitRuntime, action, actions, decodeFormData, decodeJson, decodeParams, decodeSearchParams, defer, endpoint, makeRuntimeAdapter, makeServerRuntime, requestServicesLayer, runWithSvelteKitRuntime, serverLoad, sveltekitConfig, sveltekitConfigProvider };
|
|
135
137
|
|
|
136
138
|
//# sourceMappingURL=server.js.map
|