@thomasfosterau/effect-sveltekit 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +21 -15
  2. package/dist/Hooks.d.ts +1 -1
  3. package/dist/Hooks.js.map +1 -1
  4. package/dist/Navigation.d.ts +17 -6
  5. package/dist/Navigation.js +17 -5
  6. package/dist/Navigation.js.map +1 -1
  7. package/dist/Remote.d.ts +1 -1
  8. package/dist/Remote.js.map +1 -1
  9. package/dist/State.d.ts +4 -4
  10. package/dist/State.js.map +1 -1
  11. package/dist/adapter/handler.d.ts +14 -12
  12. package/dist/adapter/handler.js +5 -7
  13. package/dist/adapter/handler.js.map +1 -1
  14. package/dist/adapter/index.js +25 -21
  15. package/dist/adapter/index.js.map +1 -1
  16. package/dist/api-client.js +1 -1
  17. package/dist/api-client.js.map +1 -1
  18. package/dist/app-runtime.d.ts +7 -6
  19. package/dist/app-runtime.js +5 -5
  20. package/dist/app-runtime.js.map +1 -1
  21. package/dist/client/Hooks.d.ts +1 -1
  22. package/dist/client/Hooks.js.map +1 -1
  23. package/dist/errors.js +3 -2
  24. package/dist/errors.js.map +1 -1
  25. package/dist/forms.d.ts +6 -6
  26. package/dist/forms.js.map +1 -1
  27. package/dist/internal/app-state.d.ts +1 -1
  28. package/dist/internal/app-state.js.map +1 -1
  29. package/dist/internal/auto.d.ts +2 -1
  30. package/dist/internal/auto.js.map +1 -1
  31. package/dist/internal/enhance.d.ts +1 -1
  32. package/dist/internal/enhance.js.map +1 -1
  33. package/dist/internal/error.js +23 -2
  34. package/dist/internal/error.js.map +1 -1
  35. package/dist/internal/remote-run.d.ts +3 -3
  36. package/dist/internal/remote-run.js.map +1 -1
  37. package/dist/kit.js +3 -3
  38. package/dist/kit.js.map +1 -1
  39. package/dist/remote-functions.d.ts +4 -4
  40. package/dist/remote-functions.js.map +1 -1
  41. package/dist/remote-reactive.d.ts +1 -1
  42. package/dist/remote-reactive.js.map +1 -1
  43. package/dist/response-headers.d.ts +1 -1
  44. package/dist/response-headers.js.map +1 -1
  45. package/dist/server/Endpoint.d.ts +2 -2
  46. package/dist/server/Endpoint.js +2 -2
  47. package/dist/server/Endpoint.js.map +1 -1
  48. package/dist/server/Hooks.d.ts +1 -1
  49. package/dist/server/Hooks.js.map +1 -1
  50. package/dist/transport.d.ts +1 -1
  51. package/dist/transport.js.map +1 -1
  52. package/dist/vite.d.ts +2 -2
  53. package/dist/vite.js.map +1 -1
  54. package/package.json +6 -4
@@ -1,6 +1,6 @@
1
1
  import { SvelteKitServices } from "../app-runtime.js";
2
2
  import { Effect } from "effect";
3
- import { Handle, HandleFetch, HandleServerError, ServerInit } from "@sveltejs/kit";
3
+ import { Handle, HandleFetch, HandleServerError, ServerInit } from "@sveltejs/kit/hooks";
4
4
  declare namespace Hooks_d_exports {
5
5
  export { handle, handleError, handleFetch, init };
6
6
  }
@@ -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,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"}
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/hooks\";\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"}
@@ -1,5 +1,5 @@
1
1
  import { Schema } from "effect";
2
- import { Transport, Transporter } from "@sveltejs/kit";
2
+ import { Transport, Transporter } from "@sveltejs/kit/hooks";
3
3
  //#region src/transport.d.ts
4
4
  /**
5
5
  * Builds a SvelteKit {@link Transporter} from an Effect {@link Schema.Codec}.
@@ -1 +1 @@
1
- {"version":3,"file":"transport.js","names":[],"sources":["../src/transport.ts"],"sourcesContent":["/**\n * Effect Schema ⇄ SvelteKit `transport` hook.\n *\n * SvelteKit's universal [`transport`](https://svelte.dev/docs/kit/hooks#Universal-hooks-transport)\n * hook moves custom (non-POJO) values across the server/client boundary — for\n * data returned from `load` functions and from remote functions. Each entry is\n * a {@link Transporter}: a sync `encode` (server) / `decode` (client) pair,\n * where `encode` returns `false` for values it does not handle.\n *\n * An Effect {@link Schema.Codec} is exactly such a pair. {@link transporter}\n * turns a schema into a `Transporter`, and {@link transport} assembles a whole\n * `transport` object from a record of schemas — so `Option`, `DateTime`,\n * branded types, `Schema.Class` instances, tagged errors, etc. round-trip with\n * no hand-written serialization.\n *\n * ```ts\n * // src/hooks.ts\n * import { Hooks } from \"@thomasfosterau/effect-sveltekit\";\n * import { Schema } from \"effect\";\n *\n * export const transport = Hooks.transport({\n * Option: Schema.Option(Schema.Number),\n * Date: Schema.Date,\n * });\n * ```\n */\n\nimport type { Transport, Transporter } from \"@sveltejs/kit\";\nimport { Schema } from \"effect\";\n\n/**\n * Builds a SvelteKit {@link Transporter} from an Effect {@link Schema.Codec}.\n *\n * The decoded `Type` is detected with `Schema.is`; matching values are encoded\n * with `Schema.encodeSync` and wrapped in a single-element tuple. The wrapper\n * guarantees the encoding is truthy — SvelteKit treats a falsy `encode` result\n * (e.g. an encoded `0`, `\"\"`, `false`, or `null`) as \"not this type\" — and is\n * unwrapped again by `decode` on the client.\n */\nexport const transporter = <T, E>(schema: Schema.Codec<T, E>): Transporter<T, readonly [E]> => {\n const guard = Schema.is(schema);\n const encode = Schema.encodeSync(schema);\n const decode = Schema.decodeSync(schema);\n return {\n encode: (value) => (guard(value) ? ([encode(value)] as const) : false),\n decode: ([data]) => decode(data),\n };\n};\n\n/**\n * Builds a deliberately-lossy {@link Transporter} for a non-POJO wrapper whose\n * contents should *not* round-trip — the value is detected on the server and\n * reconstructed fresh on the client.\n *\n * Unlike {@link transporter} (which needs a round-tripping {@link Schema.Codec}),\n * this is for values that have no meaningful serialization but still need a\n * `transport` entry so SvelteKit doesn't reject them: `encode` returns a truthy\n * marker for matching values, and `decode` ignores it and produces a fresh value\n * from {@link MarkerTransporterOptions.make}.\n *\n * ```ts\n * // A non-serializable handle reconstructed as a fresh, empty instance:\n * export const transport = Hooks.transport({\n * Live: Hooks.markerTransporter({\n * guard: (v): v is LiveHandle => v instanceof LiveHandle,\n * make: () => LiveHandle.empty(),\n * }),\n * });\n * ```\n */\nexport const markerTransporter = <T>(\n options: MarkerTransporterOptions<T>,\n): Transporter<T, unknown> => {\n const marker = options.marker ?? 1;\n return {\n encode: (value) => (options.guard(value) ? marker : false),\n decode: () => options.make(),\n };\n};\n\n/** Options for {@link markerTransporter}. */\nexport interface MarkerTransporterOptions<T> {\n /** Detect, on the server, values this transporter handles. */\n readonly guard: (value: unknown) => value is T;\n /** Produce a fresh value on the client (the payload is discarded). */\n readonly make: () => T;\n /**\n * The truthy marker `encode` emits (SvelteKit treats a falsy `encode` result\n * as \"not this type\"). Defaults to `1`.\n */\n readonly marker?: unknown;\n}\n\n/** An entry accepted by {@link transport}: an Effect schema or a ready Transporter. */\nexport type TransportEntry = Schema.Codec<any, any> | Transporter<any, any>;\n\n/**\n * Assembles a SvelteKit `transport` object from a record of entries. Each entry\n * is either an Effect {@link Schema.Codec} (wrapped with {@link transporter}) or\n * a ready {@link Transporter} (e.g. from {@link markerTransporter}), so\n * round-tripping and marker-style values can be mixed. The keys are arbitrary\n * labels (they only need to be stable between server and client).\n */\nexport const transport = (entries: Record<string, TransportEntry>): Transport => {\n const result: Transport = {};\n for (const [name, entry] of Object.entries(entries)) {\n result[name] = Schema.isSchema(entry)\n ? transporter(entry as Schema.Codec<any, any>)\n : (entry as Transporter<any, any>);\n }\n return result;\n};\n"],"mappings":";;;;;;;;;;;AAuCA,MAAa,eAAqB,WAA6D;CAC7F,MAAM,QAAQ,OAAO,GAAG,MAAM;CAC9B,MAAM,SAAS,OAAO,WAAW,MAAM;CACvC,MAAM,SAAS,OAAO,WAAW,MAAM;CACvC,OAAO;EACL,SAAS,UAAW,MAAM,KAAK,IAAK,CAAC,OAAO,KAAK,CAAC,IAAc;EAChE,SAAS,CAAC,UAAU,OAAO,IAAI;CACjC;AACF;;;;;;;;;;;;;;;;;;;;;;AAuBA,MAAa,qBACX,YAC4B;CAC5B,MAAM,SAAS,QAAQ,UAAU;CACjC,OAAO;EACL,SAAS,UAAW,QAAQ,MAAM,KAAK,IAAI,SAAS;EACpD,cAAc,QAAQ,KAAK;CAC7B;AACF;;;;;;;;AAyBA,MAAa,aAAa,YAAuD;CAC/E,MAAM,SAAoB,CAAC;CAC3B,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,OAAO,GAChD,OAAO,QAAQ,OAAO,SAAS,KAAK,IAChC,YAAY,KAA+B,IAC1C;CAEP,OAAO;AACT"}
1
+ {"version":3,"file":"transport.js","names":[],"sources":["../src/transport.ts"],"sourcesContent":["/**\n * Effect Schema ⇄ SvelteKit `transport` hook.\n *\n * SvelteKit's universal [`transport`](https://svelte.dev/docs/kit/hooks#Universal-hooks-transport)\n * hook moves custom (non-POJO) values across the server/client boundary — for\n * data returned from `load` functions and from remote functions. Each entry is\n * a {@link Transporter}: a sync `encode` (server) / `decode` (client) pair,\n * where `encode` returns `false` for values it does not handle.\n *\n * An Effect {@link Schema.Codec} is exactly such a pair. {@link transporter}\n * turns a schema into a `Transporter`, and {@link transport} assembles a whole\n * `transport` object from a record of schemas — so `Option`, `DateTime`,\n * branded types, `Schema.Class` instances, tagged errors, etc. round-trip with\n * no hand-written serialization.\n *\n * ```ts\n * // src/hooks.ts\n * import { Hooks } from \"@thomasfosterau/effect-sveltekit\";\n * import { Schema } from \"effect\";\n *\n * export const transport = Hooks.transport({\n * Option: Schema.Option(Schema.Number),\n * Date: Schema.Date,\n * });\n * ```\n */\n\nimport type { Transport, Transporter } from \"@sveltejs/kit/hooks\";\nimport { Schema } from \"effect\";\n\n/**\n * Builds a SvelteKit {@link Transporter} from an Effect {@link Schema.Codec}.\n *\n * The decoded `Type` is detected with `Schema.is`; matching values are encoded\n * with `Schema.encodeSync` and wrapped in a single-element tuple. The wrapper\n * guarantees the encoding is truthy — SvelteKit treats a falsy `encode` result\n * (e.g. an encoded `0`, `\"\"`, `false`, or `null`) as \"not this type\" — and is\n * unwrapped again by `decode` on the client.\n */\nexport const transporter = <T, E>(schema: Schema.Codec<T, E>): Transporter<T, readonly [E]> => {\n const guard = Schema.is(schema);\n const encode = Schema.encodeSync(schema);\n const decode = Schema.decodeSync(schema);\n return {\n encode: (value) => (guard(value) ? ([encode(value)] as const) : false),\n decode: ([data]) => decode(data),\n };\n};\n\n/**\n * Builds a deliberately-lossy {@link Transporter} for a non-POJO wrapper whose\n * contents should *not* round-trip — the value is detected on the server and\n * reconstructed fresh on the client.\n *\n * Unlike {@link transporter} (which needs a round-tripping {@link Schema.Codec}),\n * this is for values that have no meaningful serialization but still need a\n * `transport` entry so SvelteKit doesn't reject them: `encode` returns a truthy\n * marker for matching values, and `decode` ignores it and produces a fresh value\n * from {@link MarkerTransporterOptions.make}.\n *\n * ```ts\n * // A non-serializable handle reconstructed as a fresh, empty instance:\n * export const transport = Hooks.transport({\n * Live: Hooks.markerTransporter({\n * guard: (v): v is LiveHandle => v instanceof LiveHandle,\n * make: () => LiveHandle.empty(),\n * }),\n * });\n * ```\n */\nexport const markerTransporter = <T>(\n options: MarkerTransporterOptions<T>,\n): Transporter<T, unknown> => {\n const marker = options.marker ?? 1;\n return {\n encode: (value) => (options.guard(value) ? marker : false),\n decode: () => options.make(),\n };\n};\n\n/** Options for {@link markerTransporter}. */\nexport interface MarkerTransporterOptions<T> {\n /** Detect, on the server, values this transporter handles. */\n readonly guard: (value: unknown) => value is T;\n /** Produce a fresh value on the client (the payload is discarded). */\n readonly make: () => T;\n /**\n * The truthy marker `encode` emits (SvelteKit treats a falsy `encode` result\n * as \"not this type\"). Defaults to `1`.\n */\n readonly marker?: unknown;\n}\n\n/** An entry accepted by {@link transport}: an Effect schema or a ready Transporter. */\nexport type TransportEntry = Schema.Codec<any, any> | Transporter<any, any>;\n\n/**\n * Assembles a SvelteKit `transport` object from a record of entries. Each entry\n * is either an Effect {@link Schema.Codec} (wrapped with {@link transporter}) or\n * a ready {@link Transporter} (e.g. from {@link markerTransporter}), so\n * round-tripping and marker-style values can be mixed. The keys are arbitrary\n * labels (they only need to be stable between server and client).\n */\nexport const transport = (entries: Record<string, TransportEntry>): Transport => {\n const result: Transport = {};\n for (const [name, entry] of Object.entries(entries)) {\n result[name] = Schema.isSchema(entry)\n ? transporter(entry as Schema.Codec<any, any>)\n : (entry as Transporter<any, any>);\n }\n return result;\n};\n"],"mappings":";;;;;;;;;;;AAuCA,MAAa,eAAqB,WAA6D;CAC7F,MAAM,QAAQ,OAAO,GAAG,MAAM;CAC9B,MAAM,SAAS,OAAO,WAAW,MAAM;CACvC,MAAM,SAAS,OAAO,WAAW,MAAM;CACvC,OAAO;EACL,SAAS,UAAW,MAAM,KAAK,IAAK,CAAC,OAAO,KAAK,CAAC,IAAc;EAChE,SAAS,CAAC,UAAU,OAAO,IAAI;CACjC;AACF;;;;;;;;;;;;;;;;;;;;;;AAuBA,MAAa,qBACX,YAC4B;CAC5B,MAAM,SAAS,QAAQ,UAAU;CACjC,OAAO;EACL,SAAS,UAAW,QAAQ,MAAM,KAAK,IAAI,SAAS;EACpD,cAAc,QAAQ,KAAK;CAC7B;AACF;;;;;;;;AAyBA,MAAa,aAAa,YAAuD;CAC/E,MAAM,SAAoB,CAAC;CAC3B,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,OAAO,GAChD,OAAO,QAAQ,OAAO,SAAS,KAAK,IAChC,YAAY,KAA+B,IAC1C;CAEP,OAAO;AACT"}
package/dist/vite.d.ts CHANGED
@@ -17,7 +17,7 @@ interface EffectKitPluginOptions {
17
17
  * `+layout.server.ts`, `+server.ts`, `hooks.server.ts`) have access to the
18
18
  * services of that runtime's layer.
19
19
  *
20
- * @example "$lib/server/runtime"
20
+ * @example "#lib/server/runtime.ts"
21
21
  */
22
22
  serverRuntime?: string;
23
23
  /**
@@ -28,7 +28,7 @@ interface EffectKitPluginOptions {
28
28
  * `+layout.ts`, `hooks.client.ts`) have access to the services of that
29
29
  * runtime's layer. The module must be safe to import in the browser.
30
30
  *
31
- * @example "$lib/runtime"
31
+ * @example "#lib/runtime.ts"
32
32
  */
33
33
  clientRuntime?: string;
34
34
  }
package/dist/vite.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"vite.js","names":[],"sources":["../src/vite.ts"],"sourcesContent":["/**\n * Vite plugin that lets you write SvelteKit route exports as Effects (or\n * functions returning Effects) without manually wrapping them.\n *\n * ```ts\n * // vite.config.ts\n * import { sveltekit } from \"@sveltejs/kit/vite\";\n * import { effectKit } from \"@thomasfosterau/effect-sveltekit/vite\";\n *\n * export default {\n * plugins: [effectKit(), sveltekit()],\n * };\n * ```\n *\n * ```ts\n * // +page.server.ts\n * import { Effect } from \"effect\";\n * import * as HttpClient from \"effect/http/HttpClient\";\n *\n * export const load = (event) =>\n * Effect.gen(function* () {\n * const client = yield* HttpClient.HttpClient;\n * return { hello: \"world\" };\n * });\n * ```\n *\n * Under the hood the plugin rewrites the export to call the same wrappers\n * that the explicit API (`serverLoad`, `actions`, `handle`, `endpoint`, ...)\n * uses. Plain functions that return promises or values pass through\n * unchanged, so the plugin is safe to enable on existing projects.\n */\n\nimport MagicString from \"magic-string\";\nimport type { Plugin } from \"vite\";\n\nconst INTERNAL_IMPORT = \"@thomasfosterau/effect-sveltekit/internal/auto\";\nconst ORIG_PREFIX = \"__effect_kit_orig_\";\nconst RUNTIME_IDENT = \"__effect_kit_runtime\";\n\n/** The SvelteKit route and hook file kinds `effectKit()` can rewrite. */\nexport type EffectKitFileKind =\n | \"pageServer\"\n | \"page\"\n | \"layoutServer\"\n | \"layout\"\n | \"server\"\n | \"hooks\"\n | \"hooksServer\"\n | \"hooksClient\";\n\n/** File kinds whose exports only ever run on the server. */\nconst serverKinds: ReadonlySet<EffectKitFileKind> = new Set([\n \"pageServer\",\n \"layoutServer\",\n \"server\",\n \"hooksServer\",\n]);\n\nconst wrapperByKind: Record<EffectKitFileKind, Record<string, string>> = {\n pageServer: { load: \"wrapServerLoad\", actions: \"wrapActions\" },\n page: { load: \"wrapLoad\" },\n layoutServer: { load: \"wrapServerLoad\" },\n layout: { load: \"wrapLoad\" },\n server: {\n GET: \"wrapEndpoint\",\n POST: \"wrapEndpoint\",\n PUT: \"wrapEndpoint\",\n PATCH: \"wrapEndpoint\",\n DELETE: \"wrapEndpoint\",\n OPTIONS: \"wrapEndpoint\",\n HEAD: \"wrapEndpoint\",\n fallback: \"wrapEndpoint\",\n },\n hooksServer: {\n handle: \"wrapHandle\",\n handleFetch: \"wrapHandleFetch\",\n handleError: \"wrapHandleError\",\n init: \"wrapInit\",\n },\n hooksClient: {\n handleError: \"wrapHandleError\",\n init: \"wrapInit\",\n },\n // Universal `src/hooks.ts`: only `reroute` is function-shaped (the `transport`\n // export is plain data and is intentionally left untouched).\n hooks: {\n reroute: \"wrapReroute\",\n },\n};\n\nfunction getFileKind(id: string): EffectKitFileKind | null {\n const path = id.split(\"?\")[0]!.replace(/\\\\/g, \"/\");\n if (/\\/\\+page\\.server\\.(?:ts|js|mts|mjs)$/.test(path)) return \"pageServer\";\n if (/\\/\\+page\\.(?:ts|js|mts|mjs)$/.test(path)) return \"page\";\n if (/\\/\\+layout\\.server\\.(?:ts|js|mts|mjs)$/.test(path)) return \"layoutServer\";\n if (/\\/\\+layout\\.(?:ts|js|mts|mjs)$/.test(path)) return \"layout\";\n if (/\\/\\+server\\.(?:ts|js|mts|mjs)$/.test(path)) return \"server\";\n if (/\\/hooks\\.server\\.(?:ts|js|mts|mjs)$/.test(path)) return \"hooksServer\";\n if (/\\/hooks\\.client\\.(?:ts|js|mts|mjs)$/.test(path)) return \"hooksClient\";\n // Plain `hooks.ts` is the universal hooks file; checked last so the\n // `.server.`/`.client.` variants above take precedence.\n if (/\\/hooks\\.(?:ts|js|mts|mjs)$/.test(path)) return \"hooks\";\n return null;\n}\n\n/**\n * Returns a copy of `source` with line/block comments and string/template\n * contents replaced by spaces (newlines preserved). Byte offsets in the\n * returned string line up with the original, so regex scans don't trip on\n * tokens inside comments or strings.\n */\nfunction maskCommentsAndStrings(source: string): string {\n const out: string[] = [];\n let i = 0;\n const len = source.length;\n\n while (i < len) {\n const c = source[i]!;\n const next = source[i + 1];\n\n if (c === \"/\" && next === \"/\") {\n out.push(\" \");\n i += 2;\n while (i < len && source[i] !== \"\\n\") {\n out.push(\" \");\n i++;\n }\n continue;\n }\n\n if (c === \"/\" && next === \"*\") {\n out.push(\" \");\n i += 2;\n while (i < len && !(source[i] === \"*\" && source[i + 1] === \"/\")) {\n out.push(source[i] === \"\\n\" ? \"\\n\" : \" \");\n i++;\n }\n if (i < len) {\n out.push(\" \");\n i += 2;\n }\n continue;\n }\n\n if (c === '\"' || c === \"'\") {\n const quote = c;\n out.push(quote);\n i++;\n while (i < len && source[i] !== quote) {\n if (source[i] === \"\\\\\" && i + 1 < len) {\n out.push(\" \");\n i += 2;\n continue;\n }\n out.push(source[i] === \"\\n\" ? \"\\n\" : \" \");\n i++;\n }\n if (i < len) {\n out.push(quote);\n i++;\n }\n continue;\n }\n\n if (c === \"`\") {\n out.push(\"`\");\n i++;\n while (i < len && source[i] !== \"`\") {\n if (source[i] === \"\\\\\" && i + 1 < len) {\n out.push(\" \");\n i += 2;\n continue;\n }\n if (source[i] === \"$\" && source[i + 1] === \"{\") {\n // Preserve template expression so nested strings are masked by\n // the outer loop.\n out.push(\"${\");\n i += 2;\n let depth = 1;\n while (i < len && depth > 0) {\n out.push(source[i]!);\n if (source[i] === \"{\") depth++;\n else if (source[i] === \"}\") depth--;\n i++;\n }\n continue;\n }\n out.push(source[i] === \"\\n\" ? \"\\n\" : \" \");\n i++;\n }\n if (i < len) {\n out.push(\"`\");\n i++;\n }\n continue;\n }\n\n out.push(c);\n i++;\n }\n\n return out.join(\"\");\n}\n\ninterface ExportMatch {\n name: string;\n start: number;\n end: number;\n replacement: string;\n}\n\n/**\n * Find top-level `export const|let|var|function NAME` declarations whose\n * NAME is in `targetNames`. Returns the slice of the original source to\n * replace, along with a renamed declaration to put in its place.\n *\n * `export { NAME }`, `export default`, and destructuring forms are not\n * supported — users who need them should use the explicit wrappers.\n */\nfunction findExports(masked: string, targetNames: ReadonlySet<string>): ExportMatch[] {\n const matches: ExportMatch[] = [];\n const pattern =\n /^[ \\t]*(export)[ \\t]+(?:async[ \\t]+)?(?:const|let|var|function)[ \\t]+([A-Za-z_$][\\w$]*)/gm;\n\n let m: RegExpExecArray | null;\n while ((m = pattern.exec(masked))) {\n const [full, , name] = m;\n if (!targetNames.has(name!)) continue;\n\n const exportStart = m.index + full.indexOf(\"export\");\n const nameEnd = m.index + full.length;\n const renamed = `${ORIG_PREFIX}${name}`;\n\n const slice = masked.slice(exportStart, nameEnd);\n const replacement = slice\n .replace(/^export[ \\t]+/, \"\")\n .replace(new RegExp(`\\\\b${name}$`), renamed);\n\n matches.push({ name: name!, start: exportStart, end: nameEnd, replacement });\n }\n\n return matches;\n}\n\n/** Options for {@link effectKit}. */\nexport interface EffectKitPluginOptions {\n /**\n * Restrict transformation to a subset of SvelteKit file kinds.\n * Defaults to all standard route files.\n */\n include?: ReadonlyArray<EffectKitFileKind>;\n\n /**\n * Import specifier of a server-only module whose `runtime` (or default)\n * export is an app-wide runtime created with `makeServerRuntime`.\n *\n * When set, Effects returned from server route files (`+page.server.ts`,\n * `+layout.server.ts`, `+server.ts`, `hooks.server.ts`) have access to the\n * services of that runtime's layer.\n *\n * @example \"$lib/server/runtime\"\n */\n serverRuntime?: string;\n\n /**\n * Import specifier of a universal module whose `runtime` (or default)\n * export is an app-wide runtime created with `makeUniversalRuntime`.\n *\n * When set, Effects returned from universal route files (`+page.ts`,\n * `+layout.ts`, `hooks.client.ts`) have access to the services of that\n * runtime's layer. The module must be safe to import in the browser.\n *\n * @example \"$lib/runtime\"\n */\n clientRuntime?: string;\n}\n\n/**\n * Vite plugin that rewrites SvelteKit route exports so that Effects, or\n * functions returning Effects, are accepted wherever SvelteKit expects a\n * function-shaped export.\n */\nexport function effectKit(options: EffectKitPluginOptions = {}): Plugin {\n const include = options.include ? new Set(options.include) : null;\n\n return {\n name: \"effect-kit\",\n enforce: \"pre\",\n transform(code, id) {\n const kind = getFileKind(id);\n if (!kind) return null;\n if (include && !include.has(kind)) return null;\n\n const wrappers = wrapperByKind[kind];\n const targetNames = new Set(Object.keys(wrappers));\n\n const masked = maskCommentsAndStrings(code);\n const found = findExports(masked, targetNames);\n if (found.length === 0) return null;\n\n const s = new MagicString(code);\n\n for (const match of found) {\n s.overwrite(match.start, match.end, match.replacement);\n }\n\n const wrapperImports = Array.from(new Set(found.map((m) => wrappers[m.name]!)));\n\n // Server-only files get the server runtime module; universal/client\n // files get the client runtime module (it must be browser-safe).\n const runtimeSpecifier = serverKinds.has(kind)\n ? options.serverRuntime\n : options.clientRuntime;\n\n const imports =\n `\\nimport { ${wrapperImports.join(\", \")} } from ${JSON.stringify(INTERNAL_IMPORT)};\\n` +\n (runtimeSpecifier\n ? `import * as ${RUNTIME_IDENT} from ${JSON.stringify(runtimeSpecifier)};\\n`\n : \"\");\n const runtimeArg = runtimeSpecifier ? `, ${RUNTIME_IDENT}` : \"\";\n const exports = found\n .map(\n (m) =>\n `export const ${m.name} = ${wrappers[m.name]}(${ORIG_PREFIX}${m.name}${runtimeArg});`,\n )\n .join(\"\\n\");\n\n s.append(`\\n${imports}${exports}\\n`);\n\n return {\n code: s.toString(),\n map: s.generateMap({ hires: \"boundary\", source: id }),\n };\n },\n };\n}\n\nexport default effectKit;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCA,MAAM,kBAAkB;AACxB,MAAM,cAAc;AACpB,MAAM,gBAAgB;;AActB,MAAM,8BAA8C,IAAI,IAAI;CAC1D;CACA;CACA;CACA;AACF,CAAC;AAED,MAAM,gBAAmE;CACvE,YAAY;EAAE,MAAM;EAAkB,SAAS;CAAc;CAC7D,MAAM,EAAE,MAAM,WAAW;CACzB,cAAc,EAAE,MAAM,iBAAiB;CACvC,QAAQ,EAAE,MAAM,WAAW;CAC3B,QAAQ;EACN,KAAK;EACL,MAAM;EACN,KAAK;EACL,OAAO;EACP,QAAQ;EACR,SAAS;EACT,MAAM;EACN,UAAU;CACZ;CACA,aAAa;EACX,QAAQ;EACR,aAAa;EACb,aAAa;EACb,MAAM;CACR;CACA,aAAa;EACX,aAAa;EACb,MAAM;CACR;CAGA,OAAO,EACL,SAAS,cACX;AACF;AAEA,SAAS,YAAY,IAAsC;CACzD,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,CAAC,EAAE,CAAE,QAAQ,OAAO,GAAG;CACjD,IAAI,uCAAuC,KAAK,IAAI,GAAG,OAAO;CAC9D,IAAI,+BAA+B,KAAK,IAAI,GAAG,OAAO;CACtD,IAAI,yCAAyC,KAAK,IAAI,GAAG,OAAO;CAChE,IAAI,iCAAiC,KAAK,IAAI,GAAG,OAAO;CACxD,IAAI,iCAAiC,KAAK,IAAI,GAAG,OAAO;CACxD,IAAI,sCAAsC,KAAK,IAAI,GAAG,OAAO;CAC7D,IAAI,sCAAsC,KAAK,IAAI,GAAG,OAAO;CAG7D,IAAI,8BAA8B,KAAK,IAAI,GAAG,OAAO;CACrD,OAAO;AACT;;;;;;;AAQA,SAAS,uBAAuB,QAAwB;CACtD,MAAM,MAAgB,CAAC;CACvB,IAAI,IAAI;CACR,MAAM,MAAM,OAAO;CAEnB,OAAO,IAAI,KAAK;EACd,MAAM,IAAI,OAAO;EACjB,MAAM,OAAO,OAAO,IAAI;EAExB,IAAI,MAAM,OAAO,SAAS,KAAK;GAC7B,IAAI,KAAK,IAAI;GACb,KAAK;GACL,OAAO,IAAI,OAAO,OAAO,OAAO,MAAM;IACpC,IAAI,KAAK,GAAG;IACZ;GACF;GACA;EACF;EAEA,IAAI,MAAM,OAAO,SAAS,KAAK;GAC7B,IAAI,KAAK,IAAI;GACb,KAAK;GACL,OAAO,IAAI,OAAO,EAAE,OAAO,OAAO,OAAO,OAAO,IAAI,OAAO,MAAM;IAC/D,IAAI,KAAK,OAAO,OAAO,OAAO,OAAO,GAAG;IACxC;GACF;GACA,IAAI,IAAI,KAAK;IACX,IAAI,KAAK,IAAI;IACb,KAAK;GACP;GACA;EACF;EAEA,IAAI,MAAM,QAAO,MAAM,KAAK;GAC1B,MAAM,QAAQ;GACd,IAAI,KAAK,KAAK;GACd;GACA,OAAO,IAAI,OAAO,OAAO,OAAO,OAAO;IACrC,IAAI,OAAO,OAAO,QAAQ,IAAI,IAAI,KAAK;KACrC,IAAI,KAAK,IAAI;KACb,KAAK;KACL;IACF;IACA,IAAI,KAAK,OAAO,OAAO,OAAO,OAAO,GAAG;IACxC;GACF;GACA,IAAI,IAAI,KAAK;IACX,IAAI,KAAK,KAAK;IACd;GACF;GACA;EACF;EAEA,IAAI,MAAM,KAAK;GACb,IAAI,KAAK,GAAG;GACZ;GACA,OAAO,IAAI,OAAO,OAAO,OAAO,KAAK;IACnC,IAAI,OAAO,OAAO,QAAQ,IAAI,IAAI,KAAK;KACrC,IAAI,KAAK,IAAI;KACb,KAAK;KACL;IACF;IACA,IAAI,OAAO,OAAO,OAAO,OAAO,IAAI,OAAO,KAAK;KAG9C,IAAI,KAAK,IAAI;KACb,KAAK;KACL,IAAI,QAAQ;KACZ,OAAO,IAAI,OAAO,QAAQ,GAAG;MAC3B,IAAI,KAAK,OAAO,EAAG;MACnB,IAAI,OAAO,OAAO,KAAK;WAClB,IAAI,OAAO,OAAO,KAAK;MAC5B;KACF;KACA;IACF;IACA,IAAI,KAAK,OAAO,OAAO,OAAO,OAAO,GAAG;IACxC;GACF;GACA,IAAI,IAAI,KAAK;IACX,IAAI,KAAK,GAAG;IACZ;GACF;GACA;EACF;EAEA,IAAI,KAAK,CAAC;EACV;CACF;CAEA,OAAO,IAAI,KAAK,EAAE;AACpB;;;;;;;;;AAiBA,SAAS,YAAY,QAAgB,aAAiD;CACpF,MAAM,UAAyB,CAAC;CAChC,MAAM,UACJ;CAEF,IAAI;CACJ,OAAQ,IAAI,QAAQ,KAAK,MAAM,GAAI;EACjC,MAAM,CAAC,QAAQ,QAAQ;EACvB,IAAI,CAAC,YAAY,IAAI,IAAK,GAAG;EAE7B,MAAM,cAAc,EAAE,QAAQ,KAAK,QAAQ,QAAQ;EACnD,MAAM,UAAU,EAAE,QAAQ,KAAK;EAC/B,MAAM,UAAU,GAAG,cAAc;EAGjC,MAAM,cADQ,OAAO,MAAM,aAAa,OAChB,CAAC,CACtB,QAAQ,iBAAiB,EAAE,CAAC,CAC5B,QAAQ,IAAI,OAAO,MAAM,KAAK,EAAE,GAAG,OAAO;EAE7C,QAAQ,KAAK;GAAQ;GAAO,OAAO;GAAa,KAAK;GAAS;EAAY,CAAC;CAC7E;CAEA,OAAO;AACT;;;;;;AAwCA,SAAgB,UAAU,UAAkC,CAAC,GAAW;CACtE,MAAM,UAAU,QAAQ,UAAU,IAAI,IAAI,QAAQ,OAAO,IAAI;CAE7D,OAAO;EACL,MAAM;EACN,SAAS;EACT,UAAU,MAAM,IAAI;GAClB,MAAM,OAAO,YAAY,EAAE;GAC3B,IAAI,CAAC,MAAM,OAAO;GAClB,IAAI,WAAW,CAAC,QAAQ,IAAI,IAAI,GAAG,OAAO;GAE1C,MAAM,WAAW,cAAc;GAC/B,MAAM,cAAc,IAAI,IAAI,OAAO,KAAK,QAAQ,CAAC;GAGjD,MAAM,QAAQ,YADC,uBAAuB,IACP,GAAG,WAAW;GAC7C,IAAI,MAAM,WAAW,GAAG,OAAO;GAE/B,MAAM,IAAI,IAAI,YAAY,IAAI;GAE9B,KAAK,MAAM,SAAS,OAClB,EAAE,UAAU,MAAM,OAAO,MAAM,KAAK,MAAM,WAAW;GAGvD,MAAM,iBAAiB,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,MAAM,SAAS,EAAE,KAAM,CAAC,CAAC;GAI9E,MAAM,mBAAmB,YAAY,IAAI,IAAI,IACzC,QAAQ,gBACR,QAAQ;GAEZ,MAAM,UACJ,cAAc,eAAe,KAAK,IAAI,EAAE,UAAU,KAAK,UAAU,eAAe,EAAE,QACjF,mBACG,eAAe,cAAc,QAAQ,KAAK,UAAU,gBAAgB,EAAE,OACtE;GACN,MAAM,aAAa,mBAAmB,KAAK,kBAAkB;GAC7D,MAAM,UAAU,MACb,KACE,MACC,gBAAgB,EAAE,KAAK,KAAK,SAAS,EAAE,MAAM,GAAG,cAAc,EAAE,OAAO,WAAW,GACtF,CAAC,CACA,KAAK,IAAI;GAEZ,EAAE,OAAO,KAAK,UAAU,QAAQ,GAAG;GAEnC,OAAO;IACL,MAAM,EAAE,SAAS;IACjB,KAAK,EAAE,YAAY;KAAE,OAAO;KAAY,QAAQ;IAAG,CAAC;GACtD;EACF;CACF;AACF"}
1
+ {"version":3,"file":"vite.js","names":[],"sources":["../src/vite.ts"],"sourcesContent":["/**\n * Vite plugin that lets you write SvelteKit route exports as Effects (or\n * functions returning Effects) without manually wrapping them.\n *\n * ```ts\n * // vite.config.ts\n * import { sveltekit } from \"@sveltejs/kit/vite\";\n * import { effectKit } from \"@thomasfosterau/effect-sveltekit/vite\";\n *\n * export default {\n * plugins: [effectKit(), sveltekit()],\n * };\n * ```\n *\n * ```ts\n * // +page.server.ts\n * import { Effect } from \"effect\";\n * import * as HttpClient from \"effect/http/HttpClient\";\n *\n * export const load = (event) =>\n * Effect.gen(function* () {\n * const client = yield* HttpClient.HttpClient;\n * return { hello: \"world\" };\n * });\n * ```\n *\n * Under the hood the plugin rewrites the export to call the same wrappers\n * that the explicit API (`serverLoad`, `actions`, `handle`, `endpoint`, ...)\n * uses. Plain functions that return promises or values pass through\n * unchanged, so the plugin is safe to enable on existing projects.\n */\n\nimport MagicString from \"magic-string\";\nimport type { Plugin } from \"vite\";\n\nconst INTERNAL_IMPORT = \"@thomasfosterau/effect-sveltekit/internal/auto\";\nconst ORIG_PREFIX = \"__effect_kit_orig_\";\nconst RUNTIME_IDENT = \"__effect_kit_runtime\";\n\n/** The SvelteKit route and hook file kinds `effectKit()` can rewrite. */\nexport type EffectKitFileKind =\n | \"pageServer\"\n | \"page\"\n | \"layoutServer\"\n | \"layout\"\n | \"server\"\n | \"hooks\"\n | \"hooksServer\"\n | \"hooksClient\";\n\n/** File kinds whose exports only ever run on the server. */\nconst serverKinds: ReadonlySet<EffectKitFileKind> = new Set([\n \"pageServer\",\n \"layoutServer\",\n \"server\",\n \"hooksServer\",\n]);\n\nconst wrapperByKind: Record<EffectKitFileKind, Record<string, string>> = {\n pageServer: { load: \"wrapServerLoad\", actions: \"wrapActions\" },\n page: { load: \"wrapLoad\" },\n layoutServer: { load: \"wrapServerLoad\" },\n layout: { load: \"wrapLoad\" },\n server: {\n GET: \"wrapEndpoint\",\n POST: \"wrapEndpoint\",\n PUT: \"wrapEndpoint\",\n PATCH: \"wrapEndpoint\",\n DELETE: \"wrapEndpoint\",\n OPTIONS: \"wrapEndpoint\",\n HEAD: \"wrapEndpoint\",\n fallback: \"wrapEndpoint\",\n },\n hooksServer: {\n handle: \"wrapHandle\",\n handleFetch: \"wrapHandleFetch\",\n handleError: \"wrapHandleError\",\n init: \"wrapInit\",\n },\n hooksClient: {\n handleError: \"wrapHandleError\",\n init: \"wrapInit\",\n },\n // Universal `src/hooks.ts`: only `reroute` is function-shaped (the `transport`\n // export is plain data and is intentionally left untouched).\n hooks: {\n reroute: \"wrapReroute\",\n },\n};\n\nfunction getFileKind(id: string): EffectKitFileKind | null {\n const path = id.split(\"?\")[0]!.replace(/\\\\/g, \"/\");\n if (/\\/\\+page\\.server\\.(?:ts|js|mts|mjs)$/.test(path)) return \"pageServer\";\n if (/\\/\\+page\\.(?:ts|js|mts|mjs)$/.test(path)) return \"page\";\n if (/\\/\\+layout\\.server\\.(?:ts|js|mts|mjs)$/.test(path)) return \"layoutServer\";\n if (/\\/\\+layout\\.(?:ts|js|mts|mjs)$/.test(path)) return \"layout\";\n if (/\\/\\+server\\.(?:ts|js|mts|mjs)$/.test(path)) return \"server\";\n if (/\\/hooks\\.server\\.(?:ts|js|mts|mjs)$/.test(path)) return \"hooksServer\";\n if (/\\/hooks\\.client\\.(?:ts|js|mts|mjs)$/.test(path)) return \"hooksClient\";\n // Plain `hooks.ts` is the universal hooks file; checked last so the\n // `.server.`/`.client.` variants above take precedence.\n if (/\\/hooks\\.(?:ts|js|mts|mjs)$/.test(path)) return \"hooks\";\n return null;\n}\n\n/**\n * Returns a copy of `source` with line/block comments and string/template\n * contents replaced by spaces (newlines preserved). Byte offsets in the\n * returned string line up with the original, so regex scans don't trip on\n * tokens inside comments or strings.\n */\nfunction maskCommentsAndStrings(source: string): string {\n const out: string[] = [];\n let i = 0;\n const len = source.length;\n\n while (i < len) {\n const c = source[i]!;\n const next = source[i + 1];\n\n if (c === \"/\" && next === \"/\") {\n out.push(\" \");\n i += 2;\n while (i < len && source[i] !== \"\\n\") {\n out.push(\" \");\n i++;\n }\n continue;\n }\n\n if (c === \"/\" && next === \"*\") {\n out.push(\" \");\n i += 2;\n while (i < len && !(source[i] === \"*\" && source[i + 1] === \"/\")) {\n out.push(source[i] === \"\\n\" ? \"\\n\" : \" \");\n i++;\n }\n if (i < len) {\n out.push(\" \");\n i += 2;\n }\n continue;\n }\n\n if (c === '\"' || c === \"'\") {\n const quote = c;\n out.push(quote);\n i++;\n while (i < len && source[i] !== quote) {\n if (source[i] === \"\\\\\" && i + 1 < len) {\n out.push(\" \");\n i += 2;\n continue;\n }\n out.push(source[i] === \"\\n\" ? \"\\n\" : \" \");\n i++;\n }\n if (i < len) {\n out.push(quote);\n i++;\n }\n continue;\n }\n\n if (c === \"`\") {\n out.push(\"`\");\n i++;\n while (i < len && source[i] !== \"`\") {\n if (source[i] === \"\\\\\" && i + 1 < len) {\n out.push(\" \");\n i += 2;\n continue;\n }\n if (source[i] === \"$\" && source[i + 1] === \"{\") {\n // Preserve template expression so nested strings are masked by\n // the outer loop.\n out.push(\"${\");\n i += 2;\n let depth = 1;\n while (i < len && depth > 0) {\n out.push(source[i]!);\n if (source[i] === \"{\") depth++;\n else if (source[i] === \"}\") depth--;\n i++;\n }\n continue;\n }\n out.push(source[i] === \"\\n\" ? \"\\n\" : \" \");\n i++;\n }\n if (i < len) {\n out.push(\"`\");\n i++;\n }\n continue;\n }\n\n out.push(c);\n i++;\n }\n\n return out.join(\"\");\n}\n\ninterface ExportMatch {\n name: string;\n start: number;\n end: number;\n replacement: string;\n}\n\n/**\n * Find top-level `export const|let|var|function NAME` declarations whose\n * NAME is in `targetNames`. Returns the slice of the original source to\n * replace, along with a renamed declaration to put in its place.\n *\n * `export { NAME }`, `export default`, and destructuring forms are not\n * supported — users who need them should use the explicit wrappers.\n */\nfunction findExports(masked: string, targetNames: ReadonlySet<string>): ExportMatch[] {\n const matches: ExportMatch[] = [];\n const pattern =\n /^[ \\t]*(export)[ \\t]+(?:async[ \\t]+)?(?:const|let|var|function)[ \\t]+([A-Za-z_$][\\w$]*)/gm;\n\n let m: RegExpExecArray | null;\n while ((m = pattern.exec(masked))) {\n const [full, , name] = m;\n if (!targetNames.has(name!)) continue;\n\n const exportStart = m.index + full.indexOf(\"export\");\n const nameEnd = m.index + full.length;\n const renamed = `${ORIG_PREFIX}${name}`;\n\n const slice = masked.slice(exportStart, nameEnd);\n const replacement = slice\n .replace(/^export[ \\t]+/, \"\")\n .replace(new RegExp(`\\\\b${name}$`), renamed);\n\n matches.push({ name: name!, start: exportStart, end: nameEnd, replacement });\n }\n\n return matches;\n}\n\n/** Options for {@link effectKit}. */\nexport interface EffectKitPluginOptions {\n /**\n * Restrict transformation to a subset of SvelteKit file kinds.\n * Defaults to all standard route files.\n */\n include?: ReadonlyArray<EffectKitFileKind>;\n\n /**\n * Import specifier of a server-only module whose `runtime` (or default)\n * export is an app-wide runtime created with `makeServerRuntime`.\n *\n * When set, Effects returned from server route files (`+page.server.ts`,\n * `+layout.server.ts`, `+server.ts`, `hooks.server.ts`) have access to the\n * services of that runtime's layer.\n *\n * @example \"#lib/server/runtime.ts\"\n */\n serverRuntime?: string;\n\n /**\n * Import specifier of a universal module whose `runtime` (or default)\n * export is an app-wide runtime created with `makeUniversalRuntime`.\n *\n * When set, Effects returned from universal route files (`+page.ts`,\n * `+layout.ts`, `hooks.client.ts`) have access to the services of that\n * runtime's layer. The module must be safe to import in the browser.\n *\n * @example \"#lib/runtime.ts\"\n */\n clientRuntime?: string;\n}\n\n/**\n * Vite plugin that rewrites SvelteKit route exports so that Effects, or\n * functions returning Effects, are accepted wherever SvelteKit expects a\n * function-shaped export.\n */\nexport function effectKit(options: EffectKitPluginOptions = {}): Plugin {\n const include = options.include ? new Set(options.include) : null;\n\n return {\n name: \"effect-kit\",\n enforce: \"pre\",\n transform(code, id) {\n const kind = getFileKind(id);\n if (!kind) return null;\n if (include && !include.has(kind)) return null;\n\n const wrappers = wrapperByKind[kind];\n const targetNames = new Set(Object.keys(wrappers));\n\n const masked = maskCommentsAndStrings(code);\n const found = findExports(masked, targetNames);\n if (found.length === 0) return null;\n\n const s = new MagicString(code);\n\n for (const match of found) {\n s.overwrite(match.start, match.end, match.replacement);\n }\n\n const wrapperImports = Array.from(new Set(found.map((m) => wrappers[m.name]!)));\n\n // Server-only files get the server runtime module; universal/client\n // files get the client runtime module (it must be browser-safe).\n const runtimeSpecifier = serverKinds.has(kind)\n ? options.serverRuntime\n : options.clientRuntime;\n\n const imports =\n `\\nimport { ${wrapperImports.join(\", \")} } from ${JSON.stringify(INTERNAL_IMPORT)};\\n` +\n (runtimeSpecifier\n ? `import * as ${RUNTIME_IDENT} from ${JSON.stringify(runtimeSpecifier)};\\n`\n : \"\");\n const runtimeArg = runtimeSpecifier ? `, ${RUNTIME_IDENT}` : \"\";\n const exports = found\n .map(\n (m) =>\n `export const ${m.name} = ${wrappers[m.name]}(${ORIG_PREFIX}${m.name}${runtimeArg});`,\n )\n .join(\"\\n\");\n\n s.append(`\\n${imports}${exports}\\n`);\n\n return {\n code: s.toString(),\n map: s.generateMap({ hires: \"boundary\", source: id }),\n };\n },\n };\n}\n\nexport default effectKit;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thomasfosterau/effect-sveltekit",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "Effect integration for SvelteKit: load/action/endpoint wrappers, remote functions, an effectKit() Vite plugin, and an Effect HTTP deployment adapter",
5
5
  "keywords": [
6
6
  "effect",
@@ -74,15 +74,17 @@
74
74
  "dependencies": {
75
75
  "@standard-schema/spec": "^1.1.0",
76
76
  "magic-string": "^1.4.2",
77
- "@thomasfosterau/effect-svelte": "^0.4.1"
77
+ "@thomasfosterau/effect-svelte": "^0.4.2"
78
78
  },
79
79
  "devDependencies": {
80
80
  "@effect/platform-node": "4.0.0",
81
+ "@sveltejs/kit": "^3.0.0",
82
+ "svelte": "^5.57.1",
81
83
  "typescript": "npm:@typescript/typescript6@6.0.2"
82
84
  },
83
85
  "peerDependencies": {
84
86
  "@effect/platform-node": ">=4.0.0-rc.118",
85
- "@sveltejs/kit": "^2.0.0 || ^3.0.0-next.0",
87
+ "@sveltejs/kit": "^3.0.0",
86
88
  "effect": ">=4.0.0-rc.118",
87
89
  "svelte": "^5.40.0",
88
90
  "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
@@ -99,7 +101,7 @@
99
101
  }
100
102
  },
101
103
  "engines": {
102
- "node": "^20.19.0 || >=22.12.0"
104
+ "node": ">=22.17"
103
105
  },
104
106
  "scripts": {
105
107
  "build": "vp pack",