@thomasfosterau/effect-sveltekit 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/README.md +16 -13
  2. package/dist/Hooks.d.ts +3 -3
  3. package/dist/Hooks.js +1 -1
  4. package/dist/Hooks.js.map +1 -1
  5. package/dist/Navigation.d.ts +11 -11
  6. package/dist/Navigation.js +15 -2
  7. package/dist/Navigation.js.map +1 -1
  8. package/dist/Remote.d.ts +18 -17
  9. package/dist/Remote.js +2 -4
  10. package/dist/Remote.js.map +1 -1
  11. package/dist/State.d.ts +10 -6
  12. package/dist/State.js +2 -1
  13. package/dist/State.js.map +1 -1
  14. package/dist/adapter/assets.d.ts +24 -7
  15. package/dist/adapter/assets.js +58 -37
  16. package/dist/adapter/assets.js.map +1 -1
  17. package/dist/adapter/handler.d.ts +27 -12
  18. package/dist/adapter/handler.js +53 -26
  19. package/dist/adapter/handler.js.map +1 -1
  20. package/dist/adapter/index.d.ts +3 -3
  21. package/dist/adapter/index.js +1 -1
  22. package/dist/adapter/index.js.map +1 -1
  23. package/dist/adapter/serve.d.ts +6 -5
  24. package/dist/adapter/serve.js +3 -1
  25. package/dist/adapter/serve.js.map +1 -1
  26. package/dist/api-client.d.ts +3 -4
  27. package/dist/api-client.js +2 -1
  28. package/dist/api-client.js.map +1 -1
  29. package/dist/app-runtime.d.ts +12 -9
  30. package/dist/app-runtime.js +23 -14
  31. package/dist/app-runtime.js.map +1 -1
  32. package/dist/client/Hooks.d.ts +4 -4
  33. package/dist/client/Hooks.js +2 -1
  34. package/dist/client/Hooks.js.map +1 -1
  35. package/dist/client.d.ts +2 -2
  36. package/dist/config.d.ts +7 -5
  37. package/dist/config.js +5 -34
  38. package/dist/config.js.map +1 -1
  39. package/dist/errors.d.ts +14 -16
  40. package/dist/errors.js +20 -12
  41. package/dist/errors.js.map +1 -1
  42. package/dist/forms.d.ts +9 -10
  43. package/dist/forms.js +5 -2
  44. package/dist/forms.js.map +1 -1
  45. package/dist/internal/app-state.d.ts +16 -14
  46. package/dist/internal/app-state.js +9 -3
  47. package/dist/internal/app-state.js.map +1 -1
  48. package/dist/internal/auto.d.ts +23 -14
  49. package/dist/internal/auto.js +50 -40
  50. package/dist/internal/auto.js.map +1 -1
  51. package/dist/internal/enhance.d.ts +20 -18
  52. package/dist/internal/enhance.js +3 -1
  53. package/dist/internal/enhance.js.map +1 -1
  54. package/dist/internal/error.d.ts +13 -0
  55. package/dist/internal/error.js +4 -3
  56. package/dist/internal/error.js.map +1 -1
  57. package/dist/internal/navigation-events.js +3 -1
  58. package/dist/internal/navigation-events.js.map +1 -1
  59. package/dist/internal/remote-run.d.ts +6 -6
  60. package/dist/internal/remote-run.js +13 -16
  61. package/dist/internal/remote-run.js.map +1 -1
  62. package/dist/internal/remote-validators.js +4 -3
  63. package/dist/internal/remote-validators.js.map +1 -1
  64. package/dist/internal/route-params.d.ts +1 -2
  65. package/dist/internal/sse.js +2 -1
  66. package/dist/internal/sse.js.map +1 -1
  67. package/dist/kit.d.ts +12 -11
  68. package/dist/kit.js +6 -2
  69. package/dist/kit.js.map +1 -1
  70. package/dist/realtime.d.ts +29 -31
  71. package/dist/realtime.js +23 -4
  72. package/dist/realtime.js.map +1 -1
  73. package/dist/remote-functions.d.ts +34 -18
  74. package/dist/remote-functions.js +78 -46
  75. package/dist/remote-functions.js.map +1 -1
  76. package/dist/remote-reactive.d.ts +8 -4
  77. package/dist/remote-reactive.js.map +1 -1
  78. package/dist/request-parse.d.ts +13 -13
  79. package/dist/request-parse.js +29 -15
  80. package/dist/request-parse.js.map +1 -1
  81. package/dist/request-runtime.d.ts +16 -11
  82. package/dist/request-runtime.js +28 -29
  83. package/dist/request-runtime.js.map +1 -1
  84. package/dist/request-services.d.ts +10 -8
  85. package/dist/request-services.js +3 -1
  86. package/dist/request-services.js.map +1 -1
  87. package/dist/response-headers.d.ts +2 -3
  88. package/dist/response-headers.js +2 -1
  89. package/dist/response-headers.js.map +1 -1
  90. package/dist/runtime.d.ts +8 -5
  91. package/dist/runtime.js +4 -1
  92. package/dist/runtime.js.map +1 -1
  93. package/dist/server/Endpoint.d.ts +17 -11
  94. package/dist/server/Endpoint.js +18 -4
  95. package/dist/server/Endpoint.js.map +1 -1
  96. package/dist/server/Hooks.d.ts +6 -6
  97. package/dist/server/Hooks.js +1 -1
  98. package/dist/server/Hooks.js.map +1 -1
  99. package/dist/server.d.ts +8 -7
  100. package/dist/server.js +8 -8
  101. package/dist/server.js.map +1 -1
  102. package/dist/streamed-load.d.ts +2 -3
  103. package/dist/streamed-load.js +1 -1
  104. package/dist/streamed-load.js.map +1 -1
  105. package/dist/testing.d.ts +15 -14
  106. package/dist/testing.js +27 -7
  107. package/dist/testing.js.map +1 -1
  108. package/dist/transport.d.ts +6 -7
  109. package/dist/transport.js +3 -6
  110. package/dist/transport.js.map +1 -1
  111. package/dist/universal.d.ts +3 -3
  112. package/dist/universal.js +1 -1
  113. package/dist/universal.js.map +1 -1
  114. package/dist/vite.d.ts +4 -4
  115. package/dist/vite.js +102 -103
  116. package/dist/vite.js.map +1 -1
  117. package/package.json +12 -9
@@ -1,8 +1,10 @@
1
1
  import { SvelteKitRuntime } from "./runtime.js";
2
2
  import { isBareHandler as isBareHandler$1, toStandardValidator } from "./internal/remote-validators.js";
3
3
  import { defaultTranslate, makeRunHelpers } from "./internal/remote-run.js";
4
- import "effect";
4
+ import "effect/Effect";
5
+ import * as Predicate from "effect/Predicate";
5
6
  import "effect/http/HttpClient";
7
+ import * as Schema from "effect/Schema";
6
8
  import * as AppServer from "$app/server";
7
9
  //#region src/remote-functions.ts
8
10
  /** The default helpers: a fresh SvelteKit per-request runtime, passthrough translation. */
@@ -18,62 +20,92 @@ const helpersFromProvider = (provider, translate, formError) => makeRunHelpers((
18
20
  dispose: () => provider.disposeAfterResponse?.(event)
19
21
  };
20
22
  }, translate, formError);
23
+ /**
24
+ * Thrown synchronously, when a remote function is DEFINED, by a
25
+ * `RemoteFunction` factory called with arguments no overload accepts (a
26
+ * schema with no handler), or that needs an API the installed SvelteKit lacks.
27
+ * It is a programming error in the `*.remote.ts` module, never a request
28
+ * failure.
29
+ */
30
+ var RemoteFunctionUsageError = class extends Schema.TaggedError()("RemoteFunctionUsageError", { message: Schema.String }) {};
21
31
  function unavailable(name) {
22
- throw new Error(`${name} is not available in the installed SvelteKit version. Update @sveltejs/kit to use this API.`);
32
+ throw new RemoteFunctionUsageError({ message: `${name} is not available in the installed SvelteKit version. Update @sveltejs/kit to use this API.` });
23
33
  }
24
34
  /** True when the argument is the no-validation handler overload (typed narrowing). */
25
35
  const isBareHandler = (value) => isBareHandler$1(value);
26
- const makeQuery = (run) => ((arg1, arg2) => {
27
- if (isBareHandler(arg1)) {
28
- const handler = arg1;
29
- return AppServer.query(() => run(handler()));
30
- }
31
- if (!arg2) throw new Error("query requires a handler function when a schema is provided");
32
- return AppServer.query(toStandardValidator(arg1), (arg) => run(arg2(arg)));
33
- });
34
- const makeQueryBatch = (run) => ((validate, fn) => AppServer.query.batch(toStandardValidator(validate), (args) => run(fn(args))));
36
+ /**
37
+ * Normalise a validator for kit's `$app/server` helpers, typed as the
38
+ * `"unchecked"` overload so one call site serves every validator kind.
39
+ */
40
+ const toKitValidator = (validator) => toStandardValidator(validator);
41
+ const makeQuery = (run) => {
42
+ const impl = (arg1, arg2) => {
43
+ if (isBareHandler(arg1)) {
44
+ const handler = arg1;
45
+ return AppServer.query(() => run(handler()));
46
+ }
47
+ if (!arg2) throw new RemoteFunctionUsageError({ message: "query requires a handler function when a schema is provided" });
48
+ return AppServer.query(toKitValidator(arg1), (arg) => run(arg2(arg)));
49
+ };
50
+ return impl;
51
+ };
52
+ const makeQueryBatch = (run) => {
53
+ const impl = (validate, fn) => AppServer.query.batch(toKitValidator(validate), (args) => run(fn(args)));
54
+ return impl;
55
+ };
35
56
  const appServerCompat = AppServer;
36
- const queryCompat = AppServer.query;
37
57
  function getQueryLive() {
38
- const live = queryCompat.live;
39
- if (typeof live !== "function") unavailable("query.live");
58
+ const live = AppServer.query.live;
59
+ if (!Predicate.isFunction(live)) unavailable("query.live");
40
60
  return live;
41
61
  }
42
62
  function getRequested() {
43
63
  const requestedFn = appServerCompat.requested;
44
- if (typeof requestedFn !== "function") unavailable("requested");
64
+ if (!Predicate.isFunction(requestedFn)) unavailable("requested");
45
65
  return requestedFn;
46
66
  }
47
- const makeQueryLive = (run) => ((validate, fn) => {
48
- return getQueryLive()(toStandardValidator(validate), (arg) => run(fn(arg)));
49
- });
50
- const makeForm = (helpers) => ((arg1, arg2) => {
51
- if (isBareHandler(arg1)) {
52
- const handler = arg1;
53
- return AppServer.form(() => helpers.run(handler()));
54
- }
55
- if (!arg2) throw new Error("form requires a handler function when a schema is provided");
56
- return AppServer.form(toStandardValidator(arg1), (data, issue) => helpers.runForm(arg2(data, issue), {
57
- issue,
58
- data
59
- }));
60
- });
61
- const makeCommand = (run) => ((arg1, arg2) => {
62
- if (isBareHandler(arg1)) {
63
- const handler = arg1;
64
- return AppServer.command(() => run(handler()));
65
- }
66
- if (!arg2) throw new Error("command requires a handler function when a schema is provided");
67
- return AppServer.command(toStandardValidator(arg1), (arg) => run(arg2(arg)));
68
- });
69
- const makePrerender = (run) => ((arg1, arg2, arg3) => {
70
- if (isBareHandler(arg1)) {
71
- const handler = arg1;
72
- return AppServer.prerender(() => run(handler()), arg2);
73
- }
74
- if (typeof arg2 !== "function") throw new Error("prerender requires a handler function when a schema is provided");
75
- return AppServer.prerender(toStandardValidator(arg1), (arg) => run(arg2(arg)), arg3);
76
- });
67
+ const makeQueryLive = (run) => {
68
+ const impl = (validate, fn) => {
69
+ return getQueryLive()(toKitValidator(validate), (arg) => run(fn(arg)));
70
+ };
71
+ return impl;
72
+ };
73
+ const makeForm = (helpers) => {
74
+ const impl = (arg1, arg2) => {
75
+ if (isBareHandler(arg1)) {
76
+ const handler = arg1;
77
+ return AppServer.form(() => helpers.run(handler()));
78
+ }
79
+ if (!arg2) throw new RemoteFunctionUsageError({ message: "form requires a handler function when a schema is provided" });
80
+ return AppServer.form(toKitValidator(arg1), (data, issue) => helpers.runForm(arg2(data, issue), {
81
+ issue,
82
+ data
83
+ }));
84
+ };
85
+ return impl;
86
+ };
87
+ const makeCommand = (run) => {
88
+ const impl = (arg1, arg2) => {
89
+ if (isBareHandler(arg1)) {
90
+ const handler = arg1;
91
+ return AppServer.command(() => run(handler()));
92
+ }
93
+ if (!arg2) throw new RemoteFunctionUsageError({ message: "command requires a handler function when a schema is provided" });
94
+ return AppServer.command(toKitValidator(arg1), (arg) => run(arg2(arg)));
95
+ };
96
+ return impl;
97
+ };
98
+ const makePrerender = (run) => {
99
+ const impl = (arg1, arg2, arg3) => {
100
+ if (isBareHandler(arg1)) {
101
+ const handler = arg1;
102
+ return AppServer.prerender(() => run(handler()), arg2);
103
+ }
104
+ if (!Predicate.isFunction(arg2)) throw new RemoteFunctionUsageError({ message: "prerender requires a handler function when a schema is provided" });
105
+ return AppServer.prerender(toKitValidator(arg1), (arg) => run(arg2(arg)), arg3);
106
+ };
107
+ return impl;
108
+ };
77
109
  /**
78
110
  * SvelteKit's `requested` from `$app/server`, passed through. Throws when the
79
111
  * installed SvelteKit version does not provide it.
@@ -183,6 +215,6 @@ const RemoteFunction = {
183
215
  withRuntime
184
216
  };
185
217
  //#endregion
186
- export { RemoteFunction, command, form, prerender, query, requested, withRuntime };
218
+ export { RemoteFunction, RemoteFunctionUsageError, command, form, prerender, query, requested, withRuntime };
187
219
 
188
220
  //# sourceMappingURL=remote-functions.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"remote-functions.js","names":["isBareHandlerValue"],"sources":["../src/remote-functions.ts"],"sourcesContent":["// NOTE: This module builds the `query` / `form` / `command` / `prerender`\n// *factories* that consumers call inside their own `*.remote.ts` files — it is\n// NOT itself a SvelteKit remote module, and its exports (e.g. `RemoteFunction`)\n// are deliberately not remote functions. Its filename must therefore never match\n// SvelteKit's remote-module matcher `/[/.]remote(\\.[^/]+)+$/`\n// (kit `src/exports/vite/utils.js`), or kit's build-time validation will reject\n// the built file with \"all exports from this file must be remote functions\".\n// That is why this is `remote-functions.ts` and never `remote.server.ts` /\n// `*.remote.ts`. See `tests/remote-module-naming.test.ts` for the guard.\nimport * as AppServer from \"$app/server\";\nimport type {\n RemoteCommand,\n RemoteForm,\n RemoteFormInput,\n RemotePrerenderFunction,\n RemoteQueryFunction,\n RemoteFormInvalidField as InvalidField,\n} from \"$app/server\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport * as HttpClient from \"effect/http/HttpClient\";\nimport { Effect, type Schema } from \"effect\";\nimport { SvelteKitRuntime, SvelteKitRequestEvent } from \"./runtime.js\";\nimport {\n isBareHandler as isBareHandlerValue,\n toStandardValidator,\n} from \"./internal/remote-validators.js\";\nimport {\n defaultTranslate,\n makeRunHelpers,\n type FormErrorMapper,\n type RunHelpers,\n type Runner,\n} from \"./internal/remote-run.js\";\nimport type { ErrorTranslator, RequestRuntimeProvider } from \"./request-runtime.js\";\n\nexport type { FormErrorMapper } from \"./internal/remote-run.js\";\n\ntype SvelteKitEffectEnv = HttpClient.HttpClient | SvelteKitRequestEvent;\n\n/** The default helpers: a fresh SvelteKit per-request runtime, passthrough translation. */\nconst defaultHelpers: RunHelpers = makeRunHelpers(() => {\n const event = AppServer.getRequestEvent();\n return { runExit: (effect) => SvelteKitRuntime.forRequest(event).runPromiseExit(effect) };\n}, defaultTranslate);\n\n/** Build helpers from a {@link RequestRuntimeProvider}, translator, and form-error mapper. */\nconst helpersFromProvider = (\n provider: RequestRuntimeProvider<any, any>,\n translate: ErrorTranslator,\n formError?: FormErrorMapper,\n): RunHelpers =>\n makeRunHelpers(\n () => {\n const event = AppServer.getRequestEvent();\n return {\n runExit: (effect) => provider.run(event).runPromiseExit(effect),\n dispose: () => provider.disposeAfterResponse?.(event),\n };\n },\n translate,\n formError,\n );\n\nfunction unavailable(name: string): never {\n throw new Error(\n `${name} is not available in the installed SvelteKit version. Update @sveltejs/kit to use this API.`,\n );\n}\n\ntype EffectHandler<Env> = (arg: unknown) => Effect.Effect<unknown, unknown, Env>;\ntype EffectFormHandler<Env> = (\n data: unknown,\n issue: unknown,\n) => Effect.Effect<unknown, unknown, Env>;\ntype EffectVoidHandler<Env> = () => Effect.Effect<unknown, unknown, Env>;\n\n/** True when the argument is the no-validation handler overload (typed narrowing). */\nconst isBareHandler = <Env>(value: unknown): value is EffectVoidHandler<Env> =>\n isBareHandlerValue(value);\n\n/** The public shape of the `query` helper, parameterised by its handler env. */\nexport interface QueryFn<Env> {\n <Output>(fn: () => Effect.Effect<Output, unknown, Env>): RemoteQueryFunction<void, Output>;\n <Input, Output>(\n validate: \"unchecked\",\n fn: (arg: Input) => Effect.Effect<Output, unknown, Env>,\n ): RemoteQueryFunction<Input, Output>;\n <Sch extends StandardSchemaV1, Output>(\n schema: Sch,\n fn: (arg: StandardSchemaV1.InferOutput<Sch>) => Effect.Effect<Output, unknown, Env>,\n ): RemoteQueryFunction<StandardSchemaV1.InferInput<Sch>, Output>;\n <S extends Schema.Top, Output>(\n schema: S,\n fn: (arg: S[\"Type\"]) => Effect.Effect<Output, unknown, Env>,\n ): RemoteQueryFunction<S[\"Encoded\"], Output>;\n}\n\nconst makeQuery = <Env>(run: Runner): QueryFn<Env> =>\n ((arg1: unknown, arg2?: (arg: unknown) => Effect.Effect<unknown, unknown, Env>): any => {\n if (isBareHandler<Env>(arg1)) {\n const handler = arg1;\n return AppServer.query(() => run(handler()));\n }\n\n if (!arg2) {\n throw new Error(\"query requires a handler function when a schema is provided\");\n }\n\n return AppServer.query(toStandardValidator(arg1) as \"unchecked\", (arg: unknown) =>\n run(arg2(arg)),\n );\n }) as QueryFn<Env>;\n\n/** The public shape of `query.batch`, parameterised by its handler env. */\nexport interface QueryBatchFn<Env> {\n <Input, Output>(\n validate: \"unchecked\",\n fn: (args: Input[]) => Effect.Effect<(arg: Input, idx: number) => Output, unknown, Env>,\n ): RemoteQueryFunction<Input, Output>;\n <Sch extends StandardSchemaV1, Output>(\n schema: Sch,\n fn: (\n args: StandardSchemaV1.InferOutput<Sch>[],\n ) => Effect.Effect<\n (arg: StandardSchemaV1.InferOutput<Sch>, idx: number) => Output,\n unknown,\n Env\n >,\n ): RemoteQueryFunction<StandardSchemaV1.InferInput<Sch>, Output>;\n <S extends Schema.Top, Output>(\n schema: S,\n fn: (args: S[\"Type\"][]) => Effect.Effect<(arg: S[\"Type\"], idx: number) => Output, unknown, Env>,\n ): RemoteQueryFunction<S[\"Encoded\"], Output>;\n}\n\nconst makeQueryBatch = <Env>(run: Runner): QueryBatchFn<Env> =>\n ((\n validate: unknown,\n fn: (args: unknown[]) => Effect.Effect<(arg: unknown, idx: number) => unknown, unknown, Env>,\n ): any =>\n AppServer.query.batch(toStandardValidator(validate) as \"unchecked\", (args: unknown[]) =>\n run(fn(args)),\n )) as QueryBatchFn<Env>;\n\ntype QueryLiveFactory = (\n validate: unknown,\n fn: (arg: unknown) => Promise<AsyncIterable<unknown>> | AsyncIterable<unknown>,\n) => unknown;\n\ntype QueryWithCompat = typeof AppServer.query & {\n live?: QueryLiveFactory;\n};\n\ntype AppServerWithCompat = typeof AppServer & {\n requested?: (...args: unknown[]) => unknown;\n};\n\nconst appServerCompat = AppServer as AppServerWithCompat;\nconst queryCompat = AppServer.query as QueryWithCompat;\n\nfunction getQueryLive(): QueryLiveFactory {\n const live = queryCompat.live;\n\n if (typeof live !== \"function\") {\n unavailable(\"query.live\");\n }\n\n return live;\n}\n\nfunction getRequested(): (...args: unknown[]) => unknown {\n const requestedFn = appServerCompat.requested;\n\n if (typeof requestedFn !== \"function\") {\n unavailable(\"requested\");\n }\n\n return requestedFn;\n}\n\n/** The public shape of `query.live`, parameterised by its handler env. */\nexport interface QueryLiveFn<Env> {\n <Input, Output>(\n validate: \"unchecked\",\n fn: (arg: Input) => Effect.Effect<AsyncIterable<Output>, unknown, Env>,\n ): RemoteQueryFunction<Input, Output>;\n <Sch extends StandardSchemaV1, Output>(\n schema: Sch,\n fn: (\n arg: StandardSchemaV1.InferOutput<Sch>,\n ) => Effect.Effect<AsyncIterable<Output>, unknown, Env>,\n ): RemoteQueryFunction<StandardSchemaV1.InferInput<Sch>, Output>;\n <S extends Schema.Top, Output>(\n schema: S,\n fn: (arg: S[\"Type\"]) => Effect.Effect<AsyncIterable<Output>, unknown, Env>,\n ): RemoteQueryFunction<S[\"Encoded\"], Output>;\n}\n\nconst makeQueryLive = <Env>(run: Runner): QueryLiveFn<Env> =>\n ((\n validate: unknown,\n fn: (arg: unknown) => Effect.Effect<AsyncIterable<unknown>, unknown, Env>,\n ): any => {\n const live = getQueryLive();\n return live(toStandardValidator(validate), (arg) => run(fn(arg)));\n }) as QueryLiveFn<Env>;\n\n/** The public shape of the `form` helper, parameterised by its handler env. */\nexport interface FormFn<Env> {\n <Output>(fn: () => Effect.Effect<Output, unknown, Env>): RemoteForm<void, Output>;\n <Input, Output>(\n validate: \"unchecked\",\n fn: (\n data: Input,\n issue: InvalidField<Input & RemoteFormInput>,\n ) => Effect.Effect<Output, unknown, Env>,\n ): RemoteForm<Input & RemoteFormInput, Output>;\n <Sch extends StandardSchemaV1, Output>(\n validate: Sch,\n fn: (\n data: StandardSchemaV1.InferOutput<Sch>,\n issue: InvalidField<StandardSchemaV1.InferInput<Sch> & RemoteFormInput>,\n ) => Effect.Effect<Output, unknown, Env>,\n ): RemoteForm<StandardSchemaV1.InferInput<Sch> & RemoteFormInput, Output>;\n <S extends Schema.Top, Output>(\n validate: S,\n fn: (\n data: S[\"Type\"],\n issue: InvalidField<S[\"Encoded\"] & RemoteFormInput>,\n ) => Effect.Effect<Output, unknown, Env>,\n ): RemoteForm<S[\"Encoded\"] & RemoteFormInput, Output>;\n}\n\nconst makeForm = <Env>(helpers: RunHelpers): FormFn<Env> =>\n ((arg1: unknown, arg2?: unknown): any => {\n if (isBareHandler<Env>(arg1)) {\n const handler = arg1;\n return AppServer.form(() => helpers.run(handler()));\n }\n\n if (!arg2) {\n throw new Error(\"form requires a handler function when a schema is provided\");\n }\n\n return AppServer.form(\n toStandardValidator(arg1) as \"unchecked\",\n (data: unknown, issue: unknown) =>\n helpers.runForm((arg2 as EffectFormHandler<Env>)(data, issue), {\n issue: issue as InvalidField<any>,\n data,\n }),\n );\n }) as FormFn<Env>;\n\n/** The public shape of the `command` helper, parameterised by its handler env. */\nexport interface CommandFn<Env> {\n <Output>(fn: () => Effect.Effect<Output, unknown, Env>): RemoteCommand<void, Output>;\n <Input, Output>(\n validate: \"unchecked\",\n fn: (arg: Input) => Effect.Effect<Output, unknown, Env>,\n ): RemoteCommand<Input, Output>;\n <Sch extends StandardSchemaV1, Output>(\n validate: Sch,\n fn: (arg: StandardSchemaV1.InferOutput<Sch>) => Effect.Effect<Output, unknown, Env>,\n ): RemoteCommand<StandardSchemaV1.InferInput<Sch>, Output>;\n <S extends Schema.Top, Output>(\n validate: S,\n fn: (arg: S[\"Type\"]) => Effect.Effect<Output, unknown, Env>,\n ): RemoteCommand<S[\"Encoded\"], Output>;\n}\n\nconst makeCommand = <Env>(run: Runner): CommandFn<Env> =>\n ((arg1: unknown, arg2?: (arg: unknown) => Effect.Effect<unknown, unknown, Env>): any => {\n if (isBareHandler<Env>(arg1)) {\n const handler = arg1;\n return AppServer.command(() => run(handler()));\n }\n\n if (!arg2) {\n throw new Error(\"command requires a handler function when a schema is provided\");\n }\n\n return AppServer.command(toStandardValidator(arg1) as \"unchecked\", (arg: unknown) =>\n run(arg2(arg)),\n );\n }) as CommandFn<Env>;\n\n/** The public shape of the `prerender` helper, parameterised by its handler env. */\nexport interface PrerenderFn<Env> {\n <Output>(\n fn: () => Effect.Effect<Output, unknown, Env>,\n options?: {\n inputs?: () => Promise<void[]> | void[];\n dynamic?: boolean;\n },\n ): RemotePrerenderFunction<void, Output>;\n <Input, Output>(\n validate: \"unchecked\",\n fn: (arg: Input) => Effect.Effect<Output, unknown, Env>,\n options?: {\n inputs?: () => Promise<Input[]> | Input[];\n dynamic?: boolean;\n },\n ): RemotePrerenderFunction<Input, Output>;\n <Sch extends StandardSchemaV1, Output>(\n schema: Sch,\n fn: (arg: StandardSchemaV1.InferOutput<Sch>) => Effect.Effect<Output, unknown, Env>,\n options?: {\n inputs?: () =>\n | Promise<StandardSchemaV1.InferInput<Sch>[]>\n | StandardSchemaV1.InferInput<Sch>[];\n dynamic?: boolean;\n },\n ): RemotePrerenderFunction<StandardSchemaV1.InferInput<Sch>, Output>;\n <S extends Schema.Top, Output>(\n schema: S,\n fn: (arg: S[\"Type\"]) => Effect.Effect<Output, unknown, Env>,\n options?: {\n inputs?: () => Promise<S[\"Encoded\"][]> | S[\"Encoded\"][];\n dynamic?: boolean;\n },\n ): RemotePrerenderFunction<S[\"Encoded\"], Output>;\n}\n\nconst makePrerender = <Env>(run: Runner): PrerenderFn<Env> =>\n ((\n arg1: unknown,\n arg2?:\n | ((arg: unknown) => Effect.Effect<unknown, unknown, Env>)\n | {\n inputs?: () => Promise<unknown[]> | unknown[];\n dynamic?: boolean;\n },\n arg3?: {\n inputs?: () => Promise<unknown[]> | unknown[];\n dynamic?: boolean;\n },\n ): any => {\n if (isBareHandler<Env>(arg1)) {\n const handler = arg1;\n return AppServer.prerender(\n () => run(handler()),\n arg2 as { inputs?: () => Promise<void[]> | void[]; dynamic?: boolean } | undefined,\n );\n }\n\n if (typeof arg2 !== \"function\") {\n throw new Error(\"prerender requires a handler function when a schema is provided\");\n }\n\n return AppServer.prerender(\n toStandardValidator(arg1) as \"unchecked\",\n (arg: unknown) => run((arg2 as EffectHandler<Env>)(arg)),\n arg3,\n );\n }) as PrerenderFn<Env>;\n\n/**\n * SvelteKit's `requested` from `$app/server`, passed through. Throws when the\n * installed SvelteKit version does not provide it.\n */\nexport function requested<Result = unknown>(...args: unknown[]): Result {\n const requestedFn = getRequested();\n return requestedFn(...args) as Result;\n}\n\n/** A `query` with its `batch` / `live` helpers attached. */\nexport type QueryNamespace<Env> = QueryFn<Env> & {\n batch: QueryBatchFn<Env>;\n live: QueryLiveFn<Env>;\n};\n\nconst makeQueryNamespace = <Env>(run: Runner): QueryNamespace<Env> =>\n Object.assign(makeQuery<Env>(run), {\n batch: makeQueryBatch<Env>(run),\n live: makeQueryLive<Env>(run),\n }) as QueryNamespace<Env>;\n\n// ── Standalone exports (default SvelteKit per-request runtime) ──────────────\n\n/**\n * SvelteKit's remote `query` with an Effect handler. Accepts `\"unchecked\"`, a\n * Standard Schema or a bare Effect `Schema` as the validator; `query.batch`\n * and `query.live` are attached.\n *\n * Handlers run on the default per-request runtime (`HttpClient` plus\n * `SvelteKitRequestEvent`); a failure that is not a SvelteKit `error()` /\n * `redirect()` becomes a 500. Use {@link withRuntime} to run on your own\n * services.\n */\nexport const query: QueryNamespace<SvelteKitEffectEnv> = makeQueryNamespace(defaultHelpers.run);\n/**\n * SvelteKit's remote `query.batch` with an Effect handler (the same function\n * as `query.batch`).\n *\n * Handlers run on the default per-request runtime (`HttpClient` plus\n * `SvelteKitRequestEvent`); a failure that is not a SvelteKit `error()` /\n * `redirect()` becomes a 500. Use {@link withRuntime} to run on your own\n * services.\n */\nexport const queryBatch: QueryBatchFn<SvelteKitEffectEnv> = query.batch;\n/**\n * SvelteKit's remote `query.live` with an Effect handler that returns an\n * `AsyncIterable` (the same function as `query.live`).\n *\n * Handlers run on the default per-request runtime (`HttpClient` plus\n * `SvelteKitRequestEvent`); a failure that is not a SvelteKit `error()` /\n * `redirect()` becomes a 500. Use {@link withRuntime} to run on your own\n * services.\n */\nexport const queryLive: QueryLiveFn<SvelteKitEffectEnv> = query.live;\n/**\n * SvelteKit's remote `form` with an Effect handler.\n *\n * Handlers run on the default per-request runtime (`HttpClient` plus\n * `SvelteKitRequestEvent`); a failure that is not a SvelteKit `error()` /\n * `redirect()` becomes a 500. Use {@link withRuntime} to run on your own\n * services.\n */\nexport const form: FormFn<SvelteKitEffectEnv> = makeForm(defaultHelpers);\n/**\n * SvelteKit's remote `command` with an Effect handler.\n *\n * Handlers run on the default per-request runtime (`HttpClient` plus\n * `SvelteKitRequestEvent`); a failure that is not a SvelteKit `error()` /\n * `redirect()` becomes a 500. Use {@link withRuntime} to run on your own\n * services.\n */\nexport const command: CommandFn<SvelteKitEffectEnv> = makeCommand(defaultHelpers.run);\n/**\n * SvelteKit's remote `prerender` with an Effect handler.\n *\n * Handlers run on the default per-request runtime (`HttpClient` plus\n * `SvelteKitRequestEvent`); a failure that is not a SvelteKit `error()` /\n * `redirect()` becomes a 500. Use {@link withRuntime} to run on your own\n * services.\n */\nexport const prerender: PrerenderFn<SvelteKitEffectEnv> = makePrerender(defaultHelpers.run);\n\n/** The set of remote-function helpers bound to a particular runner. */\nexport interface RemoteFunctions<Env> {\n readonly query: QueryNamespace<Env>;\n readonly form: FormFn<Env>;\n readonly command: CommandFn<Env>;\n readonly prerender: PrerenderFn<Env>;\n}\n\n/**\n * Bind the remote-function helpers to a {@link RequestRuntimeProvider} (and an\n * optional boundary error translator), so their handlers run on the provider's\n * services `Env` — your own application catalogue — instead of the fixed\n * {@link SvelteKitServices}. The Standard-Schema / `\"unchecked\"` validation\n * argument and the native return types (`RemoteQueryFunction`, `RemoteForm`,\n * ...) are exactly as the standalone helpers.\n *\n * For remote forms, the failure path runs `opts.formError` when provided —\n * mapping a structured/nested error shape into SvelteKit's field issues (via the\n * `issue` helper / `invalid()`) so a domain validation failure drives\n * field-level invalidation rather than a generic failure. Otherwise the form\n * falls back to `translateError`.\n *\n * @example\n * ```ts\n * const { query, form, command } = RemoteFunction.withRuntime(\n * RequestRuntime.fromLocals((event) => event.locals.runtime),\n * {\n * translateError: toSvelteKit,\n * formError: (error, { issue }) => {\n * if (error instanceof ValidationFailure) issue.field(error.field, error.message);\n * invalid();\n * },\n * },\n * );\n *\n * export const items = query(() =>\n * Effect.gen(function* () {\n * const db = yield* Database;\n * return yield* db.list();\n * }),\n * );\n * ```\n */\nexport function withRuntime<R>(\n provider: RequestRuntimeProvider<R, any>,\n opts?: { translateError?: ErrorTranslator; formError?: FormErrorMapper },\n): RemoteFunctions<R> {\n const helpers = helpersFromProvider(\n provider,\n opts?.translateError ?? defaultTranslate,\n opts?.formError,\n );\n return {\n query: makeQueryNamespace<R>(helpers.run),\n form: makeForm<R>(helpers),\n command: makeCommand<R>(helpers.run),\n prerender: makePrerender<R>(helpers.run),\n };\n}\n\n/**\n * The remote-function helpers (`query`, `form`, `command`, `prerender`,\n * `requested`) bound to the default per-request runtime; `withRuntime` binds\n * them to your own services.\n */\nexport const RemoteFunction = {\n query,\n form,\n command,\n prerender,\n requested,\n withRuntime,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"remote-functions.js","names":["isBareHandlerValue"],"sources":["../src/remote-functions.ts"],"sourcesContent":["// NOTE: This module builds the `query` / `form` / `command` / `prerender`\n// *factories* that consumers call inside their own `*.remote.ts` files — it is\n// NOT itself a SvelteKit remote module, and its exports (e.g. `RemoteFunction`)\n// are deliberately not remote functions. Its filename must therefore never match\n// SvelteKit's remote-module matcher `/[/.]remote(\\.[^/]+)+$/`\n// (kit `src/exports/vite/utils.js`), or kit's build-time validation will reject\n// the built file with \"all exports from this file must be remote functions\".\n// That is why this is `remote-functions.ts` and never `remote.server.ts` /\n// `*.remote.ts`. See `tests/remote-module-naming.test.ts` for the guard.\nimport * as AppServer from \"$app/server\";\nimport type {\n RemoteCommand,\n RemoteForm,\n RemoteFormInput,\n RemoteLiveQueryFunction,\n RemotePrerenderFunction,\n RemoteQueryFunction,\n RemoteFormInvalidField as InvalidField,\n} from \"$app/server\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport * as HttpClient from \"effect/http/HttpClient\";\nimport * as Effect from \"effect/Effect\";\nimport * as Predicate from \"effect/Predicate\";\nimport * as Schema from \"effect/Schema\";\nimport { SvelteKitRuntime, SvelteKitRequestEvent } from \"./runtime.js\";\nimport {\n isBareHandler as isBareHandlerValue,\n toStandardValidator,\n} from \"./internal/remote-validators.js\";\nimport {\n defaultTranslate,\n makeRunHelpers,\n type FormErrorMapper,\n type RunHelpers,\n type Runner,\n} from \"./internal/remote-run.js\";\nimport type { ErrorTranslator, RequestRuntimeProvider } from \"./request-runtime.js\";\n\nexport type { FormErrorMapper } from \"./internal/remote-run.js\";\n\ntype SvelteKitEffectEnv = HttpClient.HttpClient | SvelteKitRequestEvent;\n\n/** The default helpers: a fresh SvelteKit per-request runtime, passthrough translation. */\nconst defaultHelpers: RunHelpers = makeRunHelpers(() => {\n const event = AppServer.getRequestEvent();\n return { runExit: (effect) => SvelteKitRuntime.forRequest(event).runPromiseExit(effect) };\n}, defaultTranslate);\n\n/** Build helpers from a {@link RequestRuntimeProvider}, translator, and form-error mapper. */\nconst helpersFromProvider = (\n provider: RequestRuntimeProvider<any, any>,\n translate: ErrorTranslator,\n formError?: FormErrorMapper,\n): RunHelpers =>\n makeRunHelpers(\n () => {\n const event = AppServer.getRequestEvent();\n return {\n runExit: (effect) => provider.run(event).runPromiseExit(effect),\n dispose: () => provider.disposeAfterResponse?.(event),\n };\n },\n translate,\n formError,\n );\n\n/**\n * Thrown synchronously, when a remote function is DEFINED, by a\n * `RemoteFunction` factory called with arguments no overload accepts (a\n * schema with no handler), or that needs an API the installed SvelteKit lacks.\n * It is a programming error in the `*.remote.ts` module, never a request\n * failure.\n */\nexport class RemoteFunctionUsageError extends Schema.TaggedError<RemoteFunctionUsageError>()(\n \"RemoteFunctionUsageError\",\n { message: Schema.String },\n) {}\n\nfunction unavailable(name: string): never {\n throw new RemoteFunctionUsageError({\n message: `${name} is not available in the installed SvelteKit version. Update @sveltejs/kit to use this API.`,\n });\n}\n\n/** Any validator argument the remote helpers accept in the handler-with-validation position. */\ntype Validator = \"unchecked\" | StandardSchemaV1 | Schema.Top;\n\ntype EffectHandler<In, Out, Env> = (arg: In) => Effect.Effect<Out, unknown, Env>;\ntype EffectVoidHandler<Out, Env> = () => Effect.Effect<Out, unknown, Env>;\n\n/** `inputs` / `dynamic` options of a remote `prerender`, for input type `In`. */\ninterface PrerenderOptions<In> {\n inputs?: () => Promise<In[]> | In[];\n dynamic?: boolean;\n}\n\n/** True when the argument is the no-validation handler overload (typed narrowing). */\nconst isBareHandler = <Out, Env>(\n value: Validator | EffectVoidHandler<Out, Env>,\n): value is EffectVoidHandler<Out, Env> => isBareHandlerValue(value);\n\n/**\n * Normalise a validator for kit's `$app/server` helpers, typed as the\n * `\"unchecked\"` overload so one call site serves every validator kind.\n */\n// SAFETY: `toStandardValidator` returns either the `\"unchecked\"` marker or a\n// Standard Schema (a bare Effect `Schema` is wrapped); kit accepts both at\n// runtime, and the `\"unchecked\"` typing only selects the overload whose handler\n// input is the generic `In` the public overloads already fixed.\nconst toKitValidator = (validator: Validator): \"unchecked\" =>\n toStandardValidator(validator) as \"unchecked\";\n\n/** The public shape of the `query` helper, parameterised by its handler env. */\nexport interface QueryFn<Env> {\n <Output>(fn: () => Effect.Effect<Output, unknown, Env>): RemoteQueryFunction<void, Output>;\n <Input, Output>(\n validate: \"unchecked\",\n fn: (arg: Input) => Effect.Effect<Output, unknown, Env>,\n ): RemoteQueryFunction<Input, Output>;\n <Sch extends StandardSchemaV1, Output>(\n schema: Sch,\n fn: (arg: StandardSchemaV1.InferOutput<Sch>) => Effect.Effect<Output, unknown, Env>,\n ): RemoteQueryFunction<StandardSchemaV1.InferInput<Sch>, Output>;\n <S extends Schema.Top, Output>(\n schema: S,\n fn: (arg: S[\"Type\"]) => Effect.Effect<Output, unknown, Env>,\n ): RemoteQueryFunction<S[\"Encoded\"], Output>;\n}\n\nconst makeQuery = <Env>(run: Runner): QueryFn<Env> => {\n const impl = <In, Out>(\n arg1: Validator | EffectVoidHandler<Out, Env>,\n arg2?: EffectHandler<In, Out, Env>,\n ) => {\n if (isBareHandler<Out, Env>(arg1)) {\n const handler = arg1;\n return AppServer.query(() => run(handler()));\n }\n\n if (!arg2) {\n throw new RemoteFunctionUsageError({\n message: \"query requires a handler function when a schema is provided\",\n });\n }\n\n return AppServer.query(toKitValidator(arg1), (arg: In) => run(arg2(arg)));\n };\n // SAFETY: `impl` dispatches on the argument kind exactly as the `QueryFn`\n // overloads distinguish them (bare handler, or validator then handler), and\n // returns kit's `RemoteQueryFunction` for that overload.\n return impl as QueryFn<Env>;\n};\n\n/** The public shape of `query.batch`, parameterised by its handler env. */\nexport interface QueryBatchFn<Env> {\n <Input, Output>(\n validate: \"unchecked\",\n fn: (args: Input[]) => Effect.Effect<(arg: Input, idx: number) => Output, unknown, Env>,\n ): RemoteQueryFunction<Input, Output>;\n <Sch extends StandardSchemaV1, Output>(\n schema: Sch,\n fn: (\n args: StandardSchemaV1.InferOutput<Sch>[],\n ) => Effect.Effect<\n (arg: StandardSchemaV1.InferOutput<Sch>, idx: number) => Output,\n unknown,\n Env\n >,\n ): RemoteQueryFunction<StandardSchemaV1.InferInput<Sch>, Output>;\n <S extends Schema.Top, Output>(\n schema: S,\n fn: (args: S[\"Type\"][]) => Effect.Effect<(arg: S[\"Type\"], idx: number) => Output, unknown, Env>,\n ): RemoteQueryFunction<S[\"Encoded\"], Output>;\n}\n\nconst makeQueryBatch = <Env>(run: Runner): QueryBatchFn<Env> => {\n const impl = <In, Out>(\n validate: Validator,\n fn: (args: In[]) => Effect.Effect<(arg: In, idx: number) => Out, unknown, Env>,\n ) => AppServer.query.batch(toKitValidator(validate), (args: In[]) => run(fn(args)));\n // SAFETY: every `QueryBatchFn` overload is (validator, batch handler), which\n // `impl` forwards to kit's `query.batch` unchanged.\n return impl as QueryBatchFn<Env>;\n};\n\n/** `$app/server`, with `requested` typed as a generic passthrough. */\ntype AppServerWithRequested = Omit<typeof AppServer, \"requested\"> & {\n readonly requested?: <Result>(...args: unknown[]) => Result;\n};\n\n// SAFETY: widens `requested` to optional (older kits may lack it, so the call\n// site checks before calling) and erases its overloads, which `requested` below\n// re-exposes with the caller-chosen `Result`.\nconst appServerCompat = AppServer as AppServerWithRequested;\n\nfunction getQueryLive(): typeof AppServer.query.live {\n const live: typeof AppServer.query.live | undefined = AppServer.query.live;\n\n if (!Predicate.isFunction(live)) {\n unavailable(\"query.live\");\n }\n\n return live;\n}\n\nfunction getRequested(): <Result>(...args: unknown[]) => Result {\n const requestedFn = appServerCompat.requested;\n\n if (!Predicate.isFunction(requestedFn)) {\n unavailable(\"requested\");\n }\n\n return requestedFn;\n}\n\n/**\n * The public shape of `query.live`, parameterised by its handler env: kit 3's\n * `query.live` overloads with an Effect handler that produces the\n * `AsyncIterable` of values.\n */\nexport interface QueryLiveFn<Env> {\n <Input, Output>(\n validate: \"unchecked\",\n fn: (arg: Input) => Effect.Effect<AsyncIterable<Output>, unknown, Env>,\n ): RemoteLiveQueryFunction<Input, Output>;\n <Sch extends StandardSchemaV1, Output>(\n schema: Sch,\n fn: (\n arg: StandardSchemaV1.InferOutput<Sch>,\n ) => Effect.Effect<AsyncIterable<Output>, unknown, Env>,\n ): RemoteLiveQueryFunction<\n StandardSchemaV1.InferInput<Sch>,\n Output,\n StandardSchemaV1.InferOutput<Sch>\n >;\n <S extends Schema.Top, Output>(\n schema: S,\n fn: (arg: S[\"Type\"]) => Effect.Effect<AsyncIterable<Output>, unknown, Env>,\n ): RemoteLiveQueryFunction<S[\"Encoded\"], Output, S[\"Type\"]>;\n}\n\nconst makeQueryLive = <Env>(run: Runner): QueryLiveFn<Env> => {\n const impl = <In, Out>(\n validate: Validator,\n fn: (arg: In) => Effect.Effect<AsyncIterable<Out>, unknown, Env>,\n ) => {\n const live = getQueryLive();\n return live(toKitValidator(validate), (arg: In) => run(fn(arg)));\n };\n // SAFETY: every `QueryLiveFn` overload is (validator, handler), which `impl`\n // forwards unchanged to kit's `query.live`, so each overload returns exactly\n // what the matching kit overload returns; `impl`'s single generic signature\n // cannot name the validated-input type parameter each overload fixes.\n return impl as QueryLiveFn<Env>;\n};\n\n/** The public shape of the `form` helper, parameterised by its handler env. */\nexport interface FormFn<Env> {\n <Output>(fn: () => Effect.Effect<Output, unknown, Env>): RemoteForm<void, Output>;\n <Input, Output>(\n validate: \"unchecked\",\n fn: (\n data: Input,\n issue: InvalidField<Input & RemoteFormInput>,\n ) => Effect.Effect<Output, unknown, Env>,\n ): RemoteForm<Input & RemoteFormInput, Output>;\n <Sch extends StandardSchemaV1, Output>(\n validate: Sch,\n fn: (\n data: StandardSchemaV1.InferOutput<Sch>,\n issue: InvalidField<StandardSchemaV1.InferInput<Sch> & RemoteFormInput>,\n ) => Effect.Effect<Output, unknown, Env>,\n ): RemoteForm<StandardSchemaV1.InferInput<Sch> & RemoteFormInput, Output>;\n <S extends Schema.Top, Output>(\n validate: S,\n fn: (\n data: S[\"Type\"],\n issue: InvalidField<S[\"Encoded\"] & RemoteFormInput>,\n ) => Effect.Effect<Output, unknown, Env>,\n ): RemoteForm<S[\"Encoded\"] & RemoteFormInput, Output>;\n}\n\nconst makeForm = <Env>(helpers: RunHelpers): FormFn<Env> => {\n const impl = <In extends RemoteFormInput, Out>(\n arg1: Validator | EffectVoidHandler<Out, Env>,\n arg2?: (data: In, issue: InvalidField<In>) => Effect.Effect<Out, unknown, Env>,\n ) => {\n if (isBareHandler<Out, Env>(arg1)) {\n const handler = arg1;\n return AppServer.form(() => helpers.run(handler()));\n }\n\n if (!arg2) {\n throw new RemoteFunctionUsageError({\n message: \"form requires a handler function when a schema is provided\",\n });\n }\n\n return AppServer.form(toKitValidator(arg1), (data: In, issue: InvalidField<In>) =>\n helpers.runForm(arg2(data, issue), { issue, data }),\n );\n };\n // SAFETY: `impl` dispatches on the argument kind exactly as the `FormFn`\n // overloads distinguish them (bare handler, or validator then handler), and\n // returns kit's `RemoteForm` for that overload.\n return impl as FormFn<Env>;\n};\n\n/** The public shape of the `command` helper, parameterised by its handler env. */\nexport interface CommandFn<Env> {\n <Output>(fn: () => Effect.Effect<Output, unknown, Env>): RemoteCommand<void, Output>;\n <Input, Output>(\n validate: \"unchecked\",\n fn: (arg: Input) => Effect.Effect<Output, unknown, Env>,\n ): RemoteCommand<Input, Output>;\n <Sch extends StandardSchemaV1, Output>(\n validate: Sch,\n fn: (arg: StandardSchemaV1.InferOutput<Sch>) => Effect.Effect<Output, unknown, Env>,\n ): RemoteCommand<StandardSchemaV1.InferInput<Sch>, Output>;\n <S extends Schema.Top, Output>(\n validate: S,\n fn: (arg: S[\"Type\"]) => Effect.Effect<Output, unknown, Env>,\n ): RemoteCommand<S[\"Encoded\"], Output>;\n}\n\nconst makeCommand = <Env>(run: Runner): CommandFn<Env> => {\n const impl = <In, Out>(\n arg1: Validator | EffectVoidHandler<Out, Env>,\n arg2?: EffectHandler<In, Out, Env>,\n ) => {\n if (isBareHandler<Out, Env>(arg1)) {\n const handler = arg1;\n return AppServer.command(() => run(handler()));\n }\n\n if (!arg2) {\n throw new RemoteFunctionUsageError({\n message: \"command requires a handler function when a schema is provided\",\n });\n }\n\n return AppServer.command(toKitValidator(arg1), (arg: In) => run(arg2(arg)));\n };\n // SAFETY: `impl` dispatches on the argument kind exactly as the `CommandFn`\n // overloads distinguish them (bare handler, or validator then handler), and\n // returns kit's `RemoteCommand` for that overload.\n return impl as CommandFn<Env>;\n};\n\n/** The public shape of the `prerender` helper, parameterised by its handler env. */\nexport interface PrerenderFn<Env> {\n <Output>(\n fn: () => Effect.Effect<Output, unknown, Env>,\n options?: {\n inputs?: () => Promise<void[]> | void[];\n dynamic?: boolean;\n },\n ): RemotePrerenderFunction<void, Output>;\n <Input, Output>(\n validate: \"unchecked\",\n fn: (arg: Input) => Effect.Effect<Output, unknown, Env>,\n options?: {\n inputs?: () => Promise<Input[]> | Input[];\n dynamic?: boolean;\n },\n ): RemotePrerenderFunction<Input, Output>;\n <Sch extends StandardSchemaV1, Output>(\n schema: Sch,\n fn: (arg: StandardSchemaV1.InferOutput<Sch>) => Effect.Effect<Output, unknown, Env>,\n options?: {\n inputs?: () =>\n | Promise<StandardSchemaV1.InferInput<Sch>[]>\n | StandardSchemaV1.InferInput<Sch>[];\n dynamic?: boolean;\n },\n ): RemotePrerenderFunction<StandardSchemaV1.InferInput<Sch>, Output>;\n <S extends Schema.Top, Output>(\n schema: S,\n fn: (arg: S[\"Type\"]) => Effect.Effect<Output, unknown, Env>,\n options?: {\n inputs?: () => Promise<S[\"Encoded\"][]> | S[\"Encoded\"][];\n dynamic?: boolean;\n },\n ): RemotePrerenderFunction<S[\"Encoded\"], Output>;\n}\n\nconst makePrerender = <Env>(run: Runner): PrerenderFn<Env> => {\n const impl = <In, Out>(\n arg1: Validator | EffectVoidHandler<Out, Env>,\n arg2?: EffectHandler<In, Out, Env> | PrerenderOptions<void>,\n arg3?: PrerenderOptions<In>,\n ) => {\n if (isBareHandler<Out, Env>(arg1)) {\n const handler = arg1;\n return AppServer.prerender(\n () => run(handler()),\n // SAFETY: in the bare-handler overload the second argument is the\n // (optional) options object, never a handler.\n arg2 as PrerenderOptions<void> | undefined,\n );\n }\n\n if (!Predicate.isFunction(arg2)) {\n throw new RemoteFunctionUsageError({\n message: \"prerender requires a handler function when a schema is provided\",\n });\n }\n\n return AppServer.prerender(toKitValidator(arg1), (arg: In) => run(arg2(arg)), arg3);\n };\n // SAFETY: `impl` dispatches on the argument kind exactly as the\n // `PrerenderFn` overloads distinguish them (bare handler plus options, or\n // validator, handler and options), and returns kit's\n // `RemotePrerenderFunction` for that overload.\n return impl as PrerenderFn<Env>;\n};\n\n/**\n * SvelteKit's `requested` from `$app/server`, passed through. Throws when the\n * installed SvelteKit version does not provide it.\n */\nexport function requested<Result = unknown>(...args: unknown[]): Result {\n const requestedFn = getRequested();\n return requestedFn<Result>(...args);\n}\n\n/** A `query` with its `batch` / `live` helpers attached. */\nexport type QueryNamespace<Env> = QueryFn<Env> & {\n batch: QueryBatchFn<Env>;\n live: QueryLiveFn<Env>;\n};\n\nconst makeQueryNamespace = <Env>(run: Runner): QueryNamespace<Env> =>\n Object.assign(makeQuery<Env>(run), {\n batch: makeQueryBatch<Env>(run),\n live: makeQueryLive<Env>(run),\n });\n\n// ── Standalone exports (default SvelteKit per-request runtime) ──────────────\n\n/**\n * SvelteKit's remote `query` with an Effect handler. Accepts `\"unchecked\"`, a\n * Standard Schema or a bare Effect `Schema` as the validator; `query.batch`\n * and `query.live` are attached.\n *\n * Handlers run on the default per-request runtime (`HttpClient` plus\n * `SvelteKitRequestEvent`); a failure that is not a SvelteKit `error()` /\n * `redirect()` becomes a 500. Use {@link withRuntime} to run on your own\n * services.\n */\nexport const query: QueryNamespace<SvelteKitEffectEnv> = makeQueryNamespace(defaultHelpers.run);\n/**\n * SvelteKit's remote `query.batch` with an Effect handler (the same function\n * as `query.batch`).\n *\n * Handlers run on the default per-request runtime (`HttpClient` plus\n * `SvelteKitRequestEvent`); a failure that is not a SvelteKit `error()` /\n * `redirect()` becomes a 500. Use {@link withRuntime} to run on your own\n * services.\n */\nexport const queryBatch: QueryBatchFn<SvelteKitEffectEnv> = query.batch;\n/**\n * SvelteKit's remote `query.live` with an Effect handler that returns an\n * `AsyncIterable` (the same function as `query.live`).\n *\n * Handlers run on the default per-request runtime (`HttpClient` plus\n * `SvelteKitRequestEvent`); a failure that is not a SvelteKit `error()` /\n * `redirect()` becomes a 500. Use {@link withRuntime} to run on your own\n * services.\n */\nexport const queryLive: QueryLiveFn<SvelteKitEffectEnv> = query.live;\n/**\n * SvelteKit's remote `form` with an Effect handler.\n *\n * Handlers run on the default per-request runtime (`HttpClient` plus\n * `SvelteKitRequestEvent`); a failure that is not a SvelteKit `error()` /\n * `redirect()` becomes a 500. Use {@link withRuntime} to run on your own\n * services.\n */\nexport const form: FormFn<SvelteKitEffectEnv> = makeForm(defaultHelpers);\n/**\n * SvelteKit's remote `command` with an Effect handler.\n *\n * Handlers run on the default per-request runtime (`HttpClient` plus\n * `SvelteKitRequestEvent`); a failure that is not a SvelteKit `error()` /\n * `redirect()` becomes a 500. Use {@link withRuntime} to run on your own\n * services.\n */\nexport const command: CommandFn<SvelteKitEffectEnv> = makeCommand(defaultHelpers.run);\n/**\n * SvelteKit's remote `prerender` with an Effect handler.\n *\n * Handlers run on the default per-request runtime (`HttpClient` plus\n * `SvelteKitRequestEvent`); a failure that is not a SvelteKit `error()` /\n * `redirect()` becomes a 500. Use {@link withRuntime} to run on your own\n * services.\n */\nexport const prerender: PrerenderFn<SvelteKitEffectEnv> = makePrerender(defaultHelpers.run);\n\n/** The set of remote-function helpers bound to a particular runner. */\nexport interface RemoteFunctions<Env> {\n readonly query: QueryNamespace<Env>;\n readonly form: FormFn<Env>;\n readonly command: CommandFn<Env>;\n readonly prerender: PrerenderFn<Env>;\n}\n\n/**\n * Bind the remote-function helpers to a {@link RequestRuntimeProvider} (and an\n * optional boundary error translator), so their handlers run on the provider's\n * services `Env` — your own application catalogue — instead of the fixed\n * {@link SvelteKitServices}. The Standard-Schema / `\"unchecked\"` validation\n * argument and the native return types (`RemoteQueryFunction`, `RemoteForm`,\n * ...) are exactly as the standalone helpers.\n *\n * For remote forms, the failure path runs `opts.formError` when provided —\n * mapping a structured/nested error shape into SvelteKit's field issues (via the\n * `issue` helper / `invalid()`) so a domain validation failure drives\n * field-level invalidation rather than a generic failure. Otherwise the form\n * falls back to `translateError`.\n *\n * @example\n * ```ts\n * const { query, form, command } = RemoteFunction.withRuntime(\n * RequestRuntime.fromLocals((event) => event.locals.runtime),\n * {\n * translateError: toSvelteKit,\n * formError: (error, { issue }) => {\n * if (error instanceof ValidationFailure) issue.field(error.field, error.message);\n * invalid();\n * },\n * },\n * );\n *\n * export const items = query(() =>\n * Effect.gen(function* () {\n * const db = yield* Database;\n * return yield* db.list();\n * }),\n * );\n * ```\n */\nexport function withRuntime<R>(\n provider: RequestRuntimeProvider<R, any>,\n opts?: { translateError?: ErrorTranslator; formError?: FormErrorMapper },\n): RemoteFunctions<R> {\n const helpers = helpersFromProvider(\n provider,\n opts?.translateError ?? defaultTranslate,\n opts?.formError,\n );\n return {\n query: makeQueryNamespace<R>(helpers.run),\n form: makeForm<R>(helpers),\n command: makeCommand<R>(helpers.run),\n prerender: makePrerender<R>(helpers.run),\n };\n}\n\n/**\n * The remote-function helpers (`query`, `form`, `command`, `prerender`,\n * `requested`) bound to the default per-request runtime; `withRuntime` binds\n * them to your own services.\n */\nexport const RemoteFunction = {\n query,\n form,\n command,\n prerender,\n requested,\n withRuntime,\n};\n"],"mappings":"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"}
@@ -1,6 +1,13 @@
1
1
  import { RemoteResource } from "$app/server";
2
2
  import * as AsyncResult from "effect/reactivity/AsyncResult";
3
3
  //#region src/remote-reactive.d.ts
4
+ /**
5
+ * What {@link useRemoteQuery} returns: the remote resource's state as an
6
+ * {@link AsyncResult.AsyncResult}, read reactively through `current`.
7
+ */
8
+ export interface RemoteQueryResult<T> {
9
+ readonly current: AsyncResult.AsyncResult<T, unknown>;
10
+ }
4
11
  /**
5
12
  * Bridges a SvelteKit remote resource (`query(...)`, `query.live(...)`,
6
13
  * `prerender(...)`) into Effect's native
@@ -29,9 +36,6 @@ import * as AsyncResult from "effect/reactivity/AsyncResult";
29
36
  * {/if}
30
37
  * ```
31
38
  */
32
- declare function useRemoteQuery<T>(query: RemoteResource<T>): {
33
- readonly current: AsyncResult.AsyncResult<T, unknown>;
34
- };
39
+ export declare function useRemoteQuery<T>(query: RemoteResource<T>): RemoteQueryResult<T>;
35
40
  //#endregion
36
- export { useRemoteQuery };
37
41
  //# sourceMappingURL=remote-reactive.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"remote-reactive.js","names":[],"sources":["../src/remote-reactive.ts"],"sourcesContent":["import type { RemoteResource } from \"$app/server\";\nimport * as AsyncResult from \"effect/reactivity/AsyncResult\";\n\n/**\n * Bridges a SvelteKit remote resource (`query(...)`, `query.live(...)`,\n * `prerender(...)`) into Effect's native\n * {@link AsyncResult.AsyncResult} — the same result type the Svelte hooks in\n * `@thomasfosterau/effect-svelte` expose — so remote-function data folds into\n * the same templates and combinators (`AsyncResult.match`, `isSuccess`, ...).\n *\n * A `RemoteResource<T>` is already reactive (`current` / `loading` / `error` /\n * `ready`); reading them inside the returned `current` getter tracks them, so\n * the result updates as the resource does. The `loading` flag is surfaced as\n * `AsyncResult`'s `waiting` (stale-while-revalidate): a refresh keeps the\n * previous `Success` on screen.\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { useRemoteQuery } from '@thomasfosterau/effect-sveltekit/client';\n * import { AsyncResult } from '@thomasfosterau/effect-svelte';\n * import { getTodos } from './todos.remote';\n *\n * const todos = useRemoteQuery(getTodos());\n * </script>\n *\n * {#if AsyncResult.isSuccess(todos.current)}\n * <ul>{#each todos.current.value as todo}<li>{todo.text}</li>{/each}</ul>\n * {/if}\n * ```\n */\nexport function useRemoteQuery<T>(query: RemoteResource<T>): {\n readonly current: AsyncResult.AsyncResult<T, unknown>;\n} {\n return {\n get current() {\n // Read every reactive field so the consumer's effect tracks the resource.\n const loading = query.loading;\n const error = query.error;\n const ready = query.ready;\n\n if (error !== undefined && error !== null) {\n return AsyncResult.fail<unknown, T>(error, { waiting: loading });\n }\n if (ready) {\n return AsyncResult.success<T, unknown>(query.current as T, { waiting: loading });\n }\n return AsyncResult.initial<T, unknown>(loading);\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,SAAgB,eAAkB,OAEhC;CACA,OAAO,EACL,IAAI,UAAU;EAEZ,MAAM,UAAU,MAAM;EACtB,MAAM,QAAQ,MAAM;EACpB,MAAM,QAAQ,MAAM;EAEpB,IAAI,UAAU,KAAA,KAAa,UAAU,MACnC,OAAO,YAAY,KAAiB,OAAO,EAAE,SAAS,QAAQ,CAAC;EAEjE,IAAI,OACF,OAAO,YAAY,QAAoB,MAAM,SAAc,EAAE,SAAS,QAAQ,CAAC;EAEjF,OAAO,YAAY,QAAoB,OAAO;CAChD,EACF;AACF"}
1
+ {"version":3,"file":"remote-reactive.js","names":[],"sources":["../src/remote-reactive.ts"],"sourcesContent":["import type { RemoteResource } from \"$app/server\";\nimport * as AsyncResult from \"effect/reactivity/AsyncResult\";\n\n/**\n * What {@link useRemoteQuery} returns: the remote resource's state as an\n * {@link AsyncResult.AsyncResult}, read reactively through `current`.\n */\nexport interface RemoteQueryResult<T> {\n readonly current: AsyncResult.AsyncResult<T, unknown>;\n}\n\n/**\n * Bridges a SvelteKit remote resource (`query(...)`, `query.live(...)`,\n * `prerender(...)`) into Effect's native\n * {@link AsyncResult.AsyncResult} — the same result type the Svelte hooks in\n * `@thomasfosterau/effect-svelte` expose — so remote-function data folds into\n * the same templates and combinators (`AsyncResult.match`, `isSuccess`, ...).\n *\n * A `RemoteResource<T>` is already reactive (`current` / `loading` / `error` /\n * `ready`); reading them inside the returned `current` getter tracks them, so\n * the result updates as the resource does. The `loading` flag is surfaced as\n * `AsyncResult`'s `waiting` (stale-while-revalidate): a refresh keeps the\n * previous `Success` on screen.\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { useRemoteQuery } from '@thomasfosterau/effect-sveltekit/client';\n * import { AsyncResult } from '@thomasfosterau/effect-svelte';\n * import { getTodos } from './todos.remote';\n *\n * const todos = useRemoteQuery(getTodos());\n * </script>\n *\n * {#if AsyncResult.isSuccess(todos.current)}\n * <ul>{#each todos.current.value as todo}<li>{todo.text}</li>{/each}</ul>\n * {/if}\n * ```\n */\nexport function useRemoteQuery<T>(query: RemoteResource<T>): RemoteQueryResult<T> {\n return {\n get current() {\n // Read every reactive field so the consumer's effect tracks the resource.\n const loading = query.loading;\n const error = query.error;\n const ready = query.ready;\n\n if (error !== undefined && error !== null) {\n return AsyncResult.fail<unknown, T>(error, { waiting: loading });\n }\n if (ready) {\n return AsyncResult.success<T, unknown>(query.current, { waiting: loading });\n }\n return AsyncResult.initial<T, unknown>(loading);\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCA,SAAgB,eAAkB,OAAgD;CAChF,OAAO,EACL,IAAI,UAAU;EAEZ,MAAM,UAAU,MAAM;EACtB,MAAM,QAAQ,MAAM;EACpB,MAAM,QAAQ,MAAM;EAEpB,IAAI,UAAU,KAAA,KAAa,UAAU,MACnC,OAAO,YAAY,KAAiB,OAAO,EAAE,SAAS,QAAQ,CAAC;EAEjE,IAAI,OACF,OAAO,YAAY,QAAoB,MAAM,SAAS,EAAE,SAAS,QAAQ,CAAC;EAE5E,OAAO,YAAY,QAAoB,OAAO;CAChD,EACF;AACF"}
@@ -1,17 +1,19 @@
1
1
  import { SvelteKitRequestEvent } from "./runtime.js";
2
- import { Effect, Schema } from "effect";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Schema from "effect/Schema";
3
4
  import { StandardSchemaV1 } from "@standard-schema/spec";
4
5
  //#region src/request-parse.d.ts
5
6
  /** A single issue reported by a Standard Schema validator. */
6
- interface ParseIssue {
7
+ export interface ParseIssue {
7
8
  readonly message: string;
8
9
  readonly path?: ReadonlyArray<PropertyKey | {
9
10
  readonly key: PropertyKey;
10
11
  }>;
11
12
  }
12
- declare const ParseError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
13
- readonly _tag: "ParseError";
14
- } & Readonly<A>;
13
+ declare const ParseError_base: Schema.Class<ParseError, Schema.TaggedStruct<"ParseError", {
14
+ /** The validator's issues, in the order it reported them. */
15
+ readonly issues: Schema.$Array<Schema.Codec<ParseIssue, ParseIssue, never, never>>;
16
+ }>, import("effect/Cause").YieldableError>;
15
17
  /**
16
18
  * Raised when a schema validator rejects the request data.
17
19
  *
@@ -28,9 +30,7 @@ declare const ParseError_base: new <A extends Record<string, any> = {}>(args: im
28
30
  * );
29
31
  * ```
30
32
  */
31
- declare class ParseError extends ParseError_base<{
32
- readonly issues: ReadonlyArray<ParseIssue>;
33
- }> {}
33
+ export declare class ParseError extends ParseError_base {}
34
34
  /**
35
35
  * Decode the route `params` object against `schema`.
36
36
  *
@@ -43,7 +43,7 @@ declare class ParseError extends ParseError_base<{
43
43
  * const { id } = yield* decodeParams(Params);
44
44
  * ```
45
45
  */
46
- declare const decodeParams: <O>(schema: Schema.Schema<O> | StandardSchemaV1<unknown, O>) => Effect.Effect<O, ParseError, SvelteKitRequestEvent>;
46
+ export declare const decodeParams: <O>(schema: Schema.Schema<O> | StandardSchemaV1<unknown, O>) => Effect.Effect<O, ParseError, SvelteKitRequestEvent>;
47
47
  /**
48
48
  * Decode the URL search / query parameters against `schema`.
49
49
  *
@@ -56,7 +56,7 @@ declare const decodeParams: <O>(schema: Schema.Schema<O> | StandardSchemaV1<unkn
56
56
  * const { page } = yield* decodeSearchParams(Query);
57
57
  * ```
58
58
  */
59
- declare const decodeSearchParams: <O>(schema: Schema.Schema<O> | StandardSchemaV1<unknown, O>) => Effect.Effect<O, ParseError, SvelteKitRequestEvent>;
59
+ export declare const decodeSearchParams: <O>(schema: Schema.Schema<O> | StandardSchemaV1<unknown, O>) => Effect.Effect<O, ParseError, SvelteKitRequestEvent>;
60
60
  /**
61
61
  * Parse the request body as JSON and decode it against `schema`.
62
62
  *
@@ -69,7 +69,7 @@ declare const decodeSearchParams: <O>(schema: Schema.Schema<O> | StandardSchemaV
69
69
  * const { name } = yield* decodeJson(Body);
70
70
  * ```
71
71
  */
72
- declare const decodeJson: <O>(schema: Schema.Schema<O> | StandardSchemaV1<unknown, O>) => Effect.Effect<O, ParseError, SvelteKitRequestEvent>;
72
+ export declare const decodeJson: <O>(schema: Schema.Schema<O> | StandardSchemaV1<unknown, O>) => Effect.Effect<O, ParseError, SvelteKitRequestEvent>;
73
73
  /**
74
74
  * Parse the request body as `FormData` and decode it against `schema`.
75
75
  *
@@ -82,7 +82,7 @@ declare const decodeJson: <O>(schema: Schema.Schema<O> | StandardSchemaV1<unknow
82
82
  * const { email } = yield* decodeFormData(Form);
83
83
  * ```
84
84
  */
85
- declare const decodeFormData: <O>(schema: Schema.Schema<O> | StandardSchemaV1<unknown, O>) => Effect.Effect<O, ParseError, SvelteKitRequestEvent>;
85
+ export declare const decodeFormData: <O>(schema: Schema.Schema<O> | StandardSchemaV1<unknown, O>) => Effect.Effect<O, ParseError, SvelteKitRequestEvent>;
86
86
  //#endregion
87
- export { ParseError, ParseIssue, decodeFormData, decodeJson, decodeParams, decodeSearchParams };
87
+ export {};
88
88
  //# sourceMappingURL=request-parse.d.ts.map
@@ -1,7 +1,15 @@
1
1
  import { SvelteKitRequestEvent } from "./runtime.js";
2
2
  import { toStandardValidator } from "./internal/remote-validators.js";
3
- import { Data, Effect } from "effect";
3
+ import * as Effect from "effect/Effect";
4
+ import * as Rec from "effect/Record";
5
+ import * as Arr from "effect/Array";
6
+ import * as Schema from "effect/Schema";
4
7
  //#region src/request-parse.ts
8
+ /** The schema of a {@link ParseIssue}, so {@link ParseError} can carry it. */
9
+ const ParseIssue = Schema.Struct({
10
+ message: Schema.String,
11
+ path: Schema.optionalKey(Schema.Array(Schema.Union([Schema.PropertyKey, Schema.Struct({ key: Schema.PropertyKey })])))
12
+ });
5
13
  /**
6
14
  * Raised when a schema validator rejects the request data.
7
15
  *
@@ -18,13 +26,17 @@ import { Data, Effect } from "effect";
18
26
  * );
19
27
  * ```
20
28
  */
21
- var ParseError = class extends Data.TaggedError("ParseError") {};
29
+ var ParseError = class extends Schema.TaggedError()("ParseError", {
30
+ /** The validator's issues, in the order it reported them. */
31
+ issues: Schema.Array(ParseIssue) }) {};
22
32
  /** Validate `value` against `schema` and return the typed output or fail. */
23
33
  const validate = (schema, value) => Effect.callback((resume) => {
24
34
  const resultOrPromise = schema["~standard"].validate(value);
25
35
  const settle = (result) => {
26
- if ("issues" in result && result.issues !== void 0) resume(Effect.fail(new ParseError({ issues: result.issues })));
27
- else resume(Effect.succeed(result.value));
36
+ if (result.issues !== void 0) {
37
+ const issues = result.issues;
38
+ resume(Effect.fail(new ParseError({ issues })));
39
+ } else resume(Effect.succeed(result.value));
28
40
  };
29
41
  if (resultOrPromise instanceof Promise) resultOrPromise.then(settle, (err) => {
30
42
  resume(Effect.fail(new ParseError({ issues: [{ message: String(err) }] })));
@@ -33,6 +45,16 @@ const validate = (schema, value) => Effect.callback((resume) => {
33
45
  });
34
46
  /** Normalise an Effect Schema or Standard Schema V1 to Standard Schema V1. */
35
47
  const normalise = (schema) => toStandardValidator(schema);
48
+ /** A field's values: the sole value of a single-valued field, else all of them. */
49
+ const fieldValue = (values) => {
50
+ const [first, ...others] = values;
51
+ return first !== void 0 && Arr.isReadonlyArrayEmpty(others) ? first : values;
52
+ };
53
+ /**
54
+ * Collect multi-valued fields (search params, form data) into a plain object,
55
+ * keyed in first-occurrence order.
56
+ */
57
+ const collectFields = (keys, getAll) => Rec.fromIterableWith(keys, (key) => [key, fieldValue(getAll(key))]);
36
58
  /**
37
59
  * Decode the route `params` object against `schema`.
38
60
  *
@@ -62,12 +84,8 @@ const decodeParams = (schema) => Effect.gen(function* () {
62
84
  * ```
63
85
  */
64
86
  const decodeSearchParams = (schema) => Effect.gen(function* () {
65
- const event = yield* SvelteKitRequestEvent;
66
- const raw = {};
67
- for (const key of event.url.searchParams.keys()) {
68
- const values = event.url.searchParams.getAll(key);
69
- raw[key] = values.length === 1 ? values[0] : values;
70
- }
87
+ const { searchParams } = (yield* SvelteKitRequestEvent).url;
88
+ const raw = collectFields(searchParams.keys(), (key) => searchParams.getAll(key));
71
89
  return yield* validate(normalise(schema), raw);
72
90
  });
73
91
  /**
@@ -108,11 +126,7 @@ const decodeFormData = (schema) => Effect.gen(function* () {
108
126
  try: () => event.request.formData(),
109
127
  catch: (err) => new ParseError({ issues: [{ message: `Failed to read form data: ${String(err)}` }] })
110
128
  });
111
- const raw = {};
112
- for (const key of formData.keys()) {
113
- const values = formData.getAll(key).map(String);
114
- raw[key] = values.length === 1 ? values[0] : values;
115
- }
129
+ const raw = collectFields(formData.keys(), (key) => Arr.map(formData.getAll(key), String));
116
130
  return yield* validate(normalise(schema), raw);
117
131
  });
118
132
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"request-parse.js","names":[],"sources":["../src/request-parse.ts"],"sourcesContent":["/**\n * Schema-driven request parsing utilities for SvelteKit server handlers.\n *\n * Each helper reads a part of the current request (route params, search params,\n * JSON body, or form data), validates it against a schema (Effect `Schema` or\n * any Standard Schema V1 validator), and returns the typed output as an\n * `Effect`. A validation failure surfaces as {@link ParseError}.\n *\n * All four utilities require `SvelteKitRequestEvent` in the environment so they\n * compose naturally inside `serverLoad` / `action` / `endpoint` handlers.\n *\n * @example\n * ```ts\n * import { serverLoad } from '@thomasfosterau/effect-sveltekit/server';\n * import { decodeParams, decodeSearchParams } from '@thomasfosterau/effect-sveltekit/server';\n * import { Schema } from 'effect';\n *\n * const Params = Schema.Struct({ id: Schema.String });\n * const Query = Schema.Struct({ page: Schema.NumberFromString });\n *\n * export const load = serverLoad(() =>\n * Effect.gen(function* () {\n * const { id } = yield* decodeParams(Params);\n * const { page } = yield* decodeSearchParams(Query);\n * return { id, page };\n * }),\n * );\n * ```\n */\n\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { Data, Effect, Schema } from \"effect\";\nimport { SvelteKitRequestEvent } from \"./runtime.js\";\nimport { toStandardValidator } from \"./internal/remote-validators.js\";\n\n// ---------------------------------------------------------------------------\n// ParseError\n// ---------------------------------------------------------------------------\n\n/** A single issue reported by a Standard Schema validator. */\nexport interface ParseIssue {\n readonly message: string;\n readonly path?: ReadonlyArray<PropertyKey | { readonly key: PropertyKey }>;\n}\n\n/**\n * Raised when a schema validator rejects the request data.\n *\n * Carry the raw `issues` array from the Standard Schema validator so callers\n * can pattern-match on specific field failures.\n *\n * @example\n * ```ts\n * import { ParseError } from '@thomasfosterau/effect-sveltekit/server';\n * import { Effect } from 'effect';\n *\n * const result = yield* decodeJson(MySchema).pipe(\n * Effect.catchTag(\"ParseError\", (e) => Effect.succeed({ fallback: true })),\n * );\n * ```\n */\nexport class ParseError extends Data.TaggedError(\"ParseError\")<{\n readonly issues: ReadonlyArray<ParseIssue>;\n}> {}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/** Validate `value` against `schema` and return the typed output or fail. */\nconst validate = <O>(\n schema: StandardSchemaV1<unknown, O>,\n value: unknown,\n): Effect.Effect<O, ParseError> =>\n Effect.callback<O, ParseError>((resume) => {\n const resultOrPromise = schema[\"~standard\"].validate(value);\n const settle = (result: StandardSchemaV1.Result<O>) => {\n if (\"issues\" in result && result.issues !== undefined) {\n resume(Effect.fail(new ParseError({ issues: result.issues as ReadonlyArray<ParseIssue> })));\n } else {\n resume(Effect.succeed((result as StandardSchemaV1.SuccessResult<O>).value));\n }\n };\n if (resultOrPromise instanceof Promise) {\n resultOrPromise.then(settle, (err: unknown) => {\n resume(Effect.fail(new ParseError({ issues: [{ message: String(err) }] })));\n });\n } else {\n settle(resultOrPromise);\n }\n });\n\n/** Normalise an Effect Schema or Standard Schema V1 to Standard Schema V1. */\nconst normalise = <O>(schema: unknown): StandardSchemaV1<unknown, O> =>\n toStandardValidator(schema) as StandardSchemaV1<unknown, O>;\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Decode the route `params` object against `schema`.\n *\n * `params` is a plain `Record<string, string>` from the matched URL segments;\n * the schema is free to coerce values (e.g. `Schema.NumberFromString`).\n *\n * @example\n * ```ts\n * const Params = Schema.Struct({ id: Schema.String });\n * const { id } = yield* decodeParams(Params);\n * ```\n */\nexport const decodeParams = <O>(\n schema: Schema.Schema<O> | StandardSchemaV1<unknown, O>,\n): Effect.Effect<O, ParseError, SvelteKitRequestEvent> =>\n Effect.gen(function* () {\n const event = yield* SvelteKitRequestEvent;\n return yield* validate(normalise<O>(schema), event.params);\n });\n\n/**\n * Decode the URL search / query parameters against `schema`.\n *\n * The raw value passed to the validator is a plain object built from\n * `event.url.searchParams` (multiple values for the same key become an array).\n *\n * @example\n * ```ts\n * const Query = Schema.Struct({ page: Schema.NumberFromString });\n * const { page } = yield* decodeSearchParams(Query);\n * ```\n */\nexport const decodeSearchParams = <O>(\n schema: Schema.Schema<O> | StandardSchemaV1<unknown, O>,\n): Effect.Effect<O, ParseError, SvelteKitRequestEvent> =>\n Effect.gen(function* () {\n const event = yield* SvelteKitRequestEvent;\n const raw: Record<string, string | string[]> = {};\n for (const key of event.url.searchParams.keys()) {\n const values = event.url.searchParams.getAll(key);\n raw[key] = values.length === 1 ? values[0]! : values;\n }\n return yield* validate(normalise<O>(schema), raw);\n });\n\n/**\n * Parse the request body as JSON and decode it against `schema`.\n *\n * Fails with `ParseError` if the body is not valid JSON or if the schema\n * rejects the parsed value.\n *\n * @example\n * ```ts\n * const Body = Schema.Struct({ name: Schema.String });\n * const { name } = yield* decodeJson(Body);\n * ```\n */\nexport const decodeJson = <O>(\n schema: Schema.Schema<O> | StandardSchemaV1<unknown, O>,\n): Effect.Effect<O, ParseError, SvelteKitRequestEvent> =>\n Effect.gen(function* () {\n const event = yield* SvelteKitRequestEvent;\n const json = yield* Effect.tryPromise({\n try: () => event.request.json() as Promise<unknown>,\n catch: (err) => new ParseError({ issues: [{ message: `Invalid JSON: ${String(err)}` }] }),\n });\n return yield* validate(normalise<O>(schema), json);\n });\n\n/**\n * Parse the request body as `FormData` and decode it against `schema`.\n *\n * The raw value passed to the validator is a plain object; fields with\n * multiple values (same name) become arrays.\n *\n * @example\n * ```ts\n * const Form = Schema.Struct({ email: Schema.String });\n * const { email } = yield* decodeFormData(Form);\n * ```\n */\nexport const decodeFormData = <O>(\n schema: Schema.Schema<O> | StandardSchemaV1<unknown, O>,\n): Effect.Effect<O, ParseError, SvelteKitRequestEvent> =>\n Effect.gen(function* () {\n const event = yield* SvelteKitRequestEvent;\n const formData = yield* Effect.tryPromise({\n try: () => event.request.formData(),\n catch: (err) =>\n new ParseError({ issues: [{ message: `Failed to read form data: ${String(err)}` }] }),\n });\n const raw: Record<string, string | string[]> = {};\n for (const key of formData.keys()) {\n const values = formData.getAll(key).map(String);\n raw[key] = values.length === 1 ? values[0]! : values;\n }\n return yield* validate(normalise<O>(schema), raw);\n });\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA6DA,IAAa,aAAb,cAAgC,KAAK,YAAY,YAAY,CAAC,CAE3D,CAAC;;AAOJ,MAAM,YACJ,QACA,UAEA,OAAO,UAAyB,WAAW;CACzC,MAAM,kBAAkB,OAAO,YAAY,CAAC,SAAS,KAAK;CAC1D,MAAM,UAAU,WAAuC;EACrD,IAAI,YAAY,UAAU,OAAO,WAAW,KAAA,GAC1C,OAAO,OAAO,KAAK,IAAI,WAAW,EAAE,QAAQ,OAAO,OAAoC,CAAC,CAAC,CAAC;OAE1F,OAAO,OAAO,QAAS,OAA6C,KAAK,CAAC;CAE9E;CACA,IAAI,2BAA2B,SAC7B,gBAAgB,KAAK,SAAS,QAAiB;EAC7C,OAAO,OAAO,KAAK,IAAI,WAAW,EAAE,QAAQ,CAAC,EAAE,SAAS,OAAO,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;CAC5E,CAAC;MAED,OAAO,eAAe;AAE1B,CAAC;;AAGH,MAAM,aAAgB,WACpB,oBAAoB,MAAM;;;;;;;;;;;;;AAkB5B,MAAa,gBACX,WAEA,OAAO,IAAI,aAAa;CACtB,MAAM,QAAQ,OAAO;CACrB,OAAO,OAAO,SAAS,UAAa,MAAM,GAAG,MAAM,MAAM;AAC3D,CAAC;;;;;;;;;;;;;AAcH,MAAa,sBACX,WAEA,OAAO,IAAI,aAAa;CACtB,MAAM,QAAQ,OAAO;CACrB,MAAM,MAAyC,CAAC;CAChD,KAAK,MAAM,OAAO,MAAM,IAAI,aAAa,KAAK,GAAG;EAC/C,MAAM,SAAS,MAAM,IAAI,aAAa,OAAO,GAAG;EAChD,IAAI,OAAO,OAAO,WAAW,IAAI,OAAO,KAAM;CAChD;CACA,OAAO,OAAO,SAAS,UAAa,MAAM,GAAG,GAAG;AAClD,CAAC;;;;;;;;;;;;;AAcH,MAAa,cACX,WAEA,OAAO,IAAI,aAAa;CACtB,MAAM,QAAQ,OAAO;CACrB,MAAM,OAAO,OAAO,OAAO,WAAW;EACpC,WAAW,MAAM,QAAQ,KAAK;EAC9B,QAAQ,QAAQ,IAAI,WAAW,EAAE,QAAQ,CAAC,EAAE,SAAS,iBAAiB,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC;CAC1F,CAAC;CACD,OAAO,OAAO,SAAS,UAAa,MAAM,GAAG,IAAI;AACnD,CAAC;;;;;;;;;;;;;AAcH,MAAa,kBACX,WAEA,OAAO,IAAI,aAAa;CACtB,MAAM,QAAQ,OAAO;CACrB,MAAM,WAAW,OAAO,OAAO,WAAW;EACxC,WAAW,MAAM,QAAQ,SAAS;EAClC,QAAQ,QACN,IAAI,WAAW,EAAE,QAAQ,CAAC,EAAE,SAAS,6BAA6B,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC;CACxF,CAAC;CACD,MAAM,MAAyC,CAAC;CAChD,KAAK,MAAM,OAAO,SAAS,KAAK,GAAG;EACjC,MAAM,SAAS,SAAS,OAAO,GAAG,CAAC,CAAC,IAAI,MAAM;EAC9C,IAAI,OAAO,OAAO,WAAW,IAAI,OAAO,KAAM;CAChD;CACA,OAAO,OAAO,SAAS,UAAa,MAAM,GAAG,GAAG;AAClD,CAAC"}
1
+ {"version":3,"file":"request-parse.js","names":[],"sources":["../src/request-parse.ts"],"sourcesContent":["/**\n * Schema-driven request parsing utilities for SvelteKit server handlers.\n *\n * Each helper reads a part of the current request (route params, search params,\n * JSON body, or form data), validates it against a schema (Effect `Schema` or\n * any Standard Schema V1 validator), and returns the typed output as an\n * `Effect`. A validation failure surfaces as {@link ParseError}.\n *\n * All four utilities require `SvelteKitRequestEvent` in the environment so they\n * compose naturally inside `serverLoad` / `action` / `endpoint` handlers.\n *\n * @example\n * ```ts\n * import { serverLoad } from '@thomasfosterau/effect-sveltekit/server';\n * import { decodeParams, decodeSearchParams } from '@thomasfosterau/effect-sveltekit/server';\n * import { Schema } from 'effect';\n *\n * const Params = Schema.Struct({ id: Schema.String });\n * const Query = Schema.Struct({ page: Schema.NumberFromString });\n *\n * export const load = serverLoad(() =>\n * Effect.gen(function* () {\n * const { id } = yield* decodeParams(Params);\n * const { page } = yield* decodeSearchParams(Query);\n * return { id, page };\n * }),\n * );\n * ```\n */\n\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport * as Arr from \"effect/Array\";\nimport * as Effect from \"effect/Effect\";\nimport * as Rec from \"effect/Record\";\nimport * as Schema from \"effect/Schema\";\nimport { SvelteKitRequestEvent } from \"./runtime.js\";\nimport { toStandardValidator } from \"./internal/remote-validators.js\";\n\n// ---------------------------------------------------------------------------\n// ParseError\n// ---------------------------------------------------------------------------\n\n/** A single issue reported by a Standard Schema validator. */\nexport interface ParseIssue {\n readonly message: string;\n readonly path?: ReadonlyArray<PropertyKey | { readonly key: PropertyKey }>;\n}\n\n/** The schema of a {@link ParseIssue}, so {@link ParseError} can carry it. */\nconst ParseIssue: Schema.Codec<ParseIssue> = Schema.Struct({\n message: Schema.String,\n path: Schema.optionalKey(\n Schema.Array(Schema.Union([Schema.PropertyKey, Schema.Struct({ key: Schema.PropertyKey })])),\n ),\n});\n\n/**\n * Raised when a schema validator rejects the request data.\n *\n * Carry the raw `issues` array from the Standard Schema validator so callers\n * can pattern-match on specific field failures.\n *\n * @example\n * ```ts\n * import { ParseError } from '@thomasfosterau/effect-sveltekit/server';\n * import { Effect } from 'effect';\n *\n * const result = yield* decodeJson(MySchema).pipe(\n * Effect.catchTag(\"ParseError\", (e) => Effect.succeed({ fallback: true })),\n * );\n * ```\n */\nexport class ParseError extends Schema.TaggedError<ParseError>()(\"ParseError\", {\n /** The validator's issues, in the order it reported them. */\n issues: Schema.Array(ParseIssue),\n}) {}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/** Validate `value` against `schema` and return the typed output or fail. */\nconst validate = <I, O>(schema: StandardSchemaV1<I, O>, value: I): Effect.Effect<O, ParseError> =>\n Effect.callback<O, ParseError>((resume) => {\n const resultOrPromise = schema[\"~standard\"].validate(value);\n const settle = (result: StandardSchemaV1.Result<O>) => {\n if (result.issues !== undefined) {\n // SAFETY: a Standard Schema `Issue` differs from `ParseIssue` only in\n // admitting an explicit `path: undefined`, which reads as an absent path.\n const issues = result.issues as ReadonlyArray<ParseIssue>;\n resume(Effect.fail(new ParseError({ issues })));\n } else {\n resume(Effect.succeed(result.value));\n }\n };\n if (resultOrPromise instanceof Promise) {\n resultOrPromise.then(settle, (err) => {\n resume(Effect.fail(new ParseError({ issues: [{ message: String(err) }] })));\n });\n } else {\n settle(resultOrPromise);\n }\n });\n\n/** Normalise an Effect Schema or Standard Schema V1 to Standard Schema V1. */\nconst normalise = <O>(\n schema: Schema.Schema<O> | StandardSchemaV1<unknown, O>,\n): StandardSchemaV1<unknown, O> =>\n // SAFETY: `toStandardValidator` wraps an Effect `Schema<O>` as a Standard\n // Schema with output `O` and passes a Standard Schema through unchanged.\n toStandardValidator(schema) as StandardSchemaV1<unknown, O>;\n\n/** A field's values: the sole value of a single-valued field, else all of them. */\nconst fieldValue = (values: Array<string>): string | Array<string> => {\n const [first, ...others] = values;\n return first !== undefined && Arr.isReadonlyArrayEmpty(others) ? first : values;\n};\n\n/**\n * Collect multi-valued fields (search params, form data) into a plain object,\n * keyed in first-occurrence order.\n */\nconst collectFields = (\n keys: Iterable<string>,\n getAll: (key: string) => Array<string>,\n): Record<string, string | Array<string>> =>\n Rec.fromIterableWith(keys, (key) => [key, fieldValue(getAll(key))]);\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Decode the route `params` object against `schema`.\n *\n * `params` is a plain `Record<string, string>` from the matched URL segments;\n * the schema is free to coerce values (e.g. `Schema.NumberFromString`).\n *\n * @example\n * ```ts\n * const Params = Schema.Struct({ id: Schema.String });\n * const { id } = yield* decodeParams(Params);\n * ```\n */\nexport const decodeParams = <O>(\n schema: Schema.Schema<O> | StandardSchemaV1<unknown, O>,\n): Effect.Effect<O, ParseError, SvelteKitRequestEvent> =>\n Effect.gen(function* () {\n const event = yield* SvelteKitRequestEvent;\n return yield* validate(normalise<O>(schema), event.params);\n });\n\n/**\n * Decode the URL search / query parameters against `schema`.\n *\n * The raw value passed to the validator is a plain object built from\n * `event.url.searchParams` (multiple values for the same key become an array).\n *\n * @example\n * ```ts\n * const Query = Schema.Struct({ page: Schema.NumberFromString });\n * const { page } = yield* decodeSearchParams(Query);\n * ```\n */\nexport const decodeSearchParams = <O>(\n schema: Schema.Schema<O> | StandardSchemaV1<unknown, O>,\n): Effect.Effect<O, ParseError, SvelteKitRequestEvent> =>\n Effect.gen(function* () {\n const event = yield* SvelteKitRequestEvent;\n const { searchParams } = event.url;\n const raw = collectFields(searchParams.keys(), (key) => searchParams.getAll(key));\n return yield* validate(normalise<O>(schema), raw);\n });\n\n/**\n * Parse the request body as JSON and decode it against `schema`.\n *\n * Fails with `ParseError` if the body is not valid JSON or if the schema\n * rejects the parsed value.\n *\n * @example\n * ```ts\n * const Body = Schema.Struct({ name: Schema.String });\n * const { name } = yield* decodeJson(Body);\n * ```\n */\nexport const decodeJson = <O>(\n schema: Schema.Schema<O> | StandardSchemaV1<unknown, O>,\n): Effect.Effect<O, ParseError, SvelteKitRequestEvent> =>\n Effect.gen(function* () {\n const event = yield* SvelteKitRequestEvent;\n const json = yield* Effect.tryPromise<unknown, ParseError>({\n try: () => event.request.json(),\n catch: (err) => new ParseError({ issues: [{ message: `Invalid JSON: ${String(err)}` }] }),\n });\n return yield* validate(normalise<O>(schema), json);\n });\n\n/**\n * Parse the request body as `FormData` and decode it against `schema`.\n *\n * The raw value passed to the validator is a plain object; fields with\n * multiple values (same name) become arrays.\n *\n * @example\n * ```ts\n * const Form = Schema.Struct({ email: Schema.String });\n * const { email } = yield* decodeFormData(Form);\n * ```\n */\nexport const decodeFormData = <O>(\n schema: Schema.Schema<O> | StandardSchemaV1<unknown, O>,\n): Effect.Effect<O, ParseError, SvelteKitRequestEvent> =>\n Effect.gen(function* () {\n const event = yield* SvelteKitRequestEvent;\n const formData = yield* Effect.tryPromise({\n try: () => event.request.formData(),\n catch: (err) =>\n new ParseError({ issues: [{ message: `Failed to read form data: ${String(err)}` }] }),\n });\n const raw = collectFields(formData.keys(), (key) => Arr.map(formData.getAll(key), String));\n return yield* validate(normalise<O>(schema), raw);\n });\n"],"mappings":";;;;;;;;AAiDA,MAAM,aAAuC,OAAO,OAAO;CACzD,SAAS,OAAO;CAChB,MAAM,OAAO,YACX,OAAO,MAAM,OAAO,MAAM,CAAC,OAAO,aAAa,OAAO,OAAO,EAAE,KAAK,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC,CAC7F;AACF,CAAC;;;;;;;;;;;;;;;;;AAkBD,IAAa,aAAb,cAAgC,OAAO,YAAwB,CAAC,CAAC,cAAc;;AAE7E,QAAQ,OAAO,MAAM,UAAU,EACjC,CAAC,CAAC,CAAC,CAAC;;AAOJ,MAAM,YAAkB,QAAgC,UACtD,OAAO,UAAyB,WAAW;CACzC,MAAM,kBAAkB,OAAO,YAAY,CAAC,SAAS,KAAK;CAC1D,MAAM,UAAU,WAAuC;EACrD,IAAI,OAAO,WAAW,KAAA,GAAW;GAG/B,MAAM,SAAS,OAAO;GACtB,OAAO,OAAO,KAAK,IAAI,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;EAChD,OACE,OAAO,OAAO,QAAQ,OAAO,KAAK,CAAC;CAEvC;CACA,IAAI,2BAA2B,SAC7B,gBAAgB,KAAK,SAAS,QAAQ;EACpC,OAAO,OAAO,KAAK,IAAI,WAAW,EAAE,QAAQ,CAAC,EAAE,SAAS,OAAO,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;CAC5E,CAAC;MAED,OAAO,eAAe;AAE1B,CAAC;;AAGH,MAAM,aACJ,WAIA,oBAAoB,MAAM;;AAG5B,MAAM,cAAc,WAAkD;CACpE,MAAM,CAAC,OAAO,GAAG,UAAU;CAC3B,OAAO,UAAU,KAAA,KAAa,IAAI,qBAAqB,MAAM,IAAI,QAAQ;AAC3E;;;;;AAMA,MAAM,iBACJ,MACA,WAEA,IAAI,iBAAiB,OAAO,QAAQ,CAAC,KAAK,WAAW,OAAO,GAAG,CAAC,CAAC,CAAC;;;;;;;;;;;;;AAkBpE,MAAa,gBACX,WAEA,OAAO,IAAI,aAAa;CACtB,MAAM,QAAQ,OAAO;CACrB,OAAO,OAAO,SAAS,UAAa,MAAM,GAAG,MAAM,MAAM;AAC3D,CAAC;;;;;;;;;;;;;AAcH,MAAa,sBACX,WAEA,OAAO,IAAI,aAAa;CAEtB,MAAM,EAAE,kBAAiB,OADJ,sBAAA,CACU;CAC/B,MAAM,MAAM,cAAc,aAAa,KAAK,IAAI,QAAQ,aAAa,OAAO,GAAG,CAAC;CAChF,OAAO,OAAO,SAAS,UAAa,MAAM,GAAG,GAAG;AAClD,CAAC;;;;;;;;;;;;;AAcH,MAAa,cACX,WAEA,OAAO,IAAI,aAAa;CACtB,MAAM,QAAQ,OAAO;CACrB,MAAM,OAAO,OAAO,OAAO,WAAgC;EACzD,WAAW,MAAM,QAAQ,KAAK;EAC9B,QAAQ,QAAQ,IAAI,WAAW,EAAE,QAAQ,CAAC,EAAE,SAAS,iBAAiB,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC;CAC1F,CAAC;CACD,OAAO,OAAO,SAAS,UAAa,MAAM,GAAG,IAAI;AACnD,CAAC;;;;;;;;;;;;;AAcH,MAAa,kBACX,WAEA,OAAO,IAAI,aAAa;CACtB,MAAM,QAAQ,OAAO;CACrB,MAAM,WAAW,OAAO,OAAO,WAAW;EACxC,WAAW,MAAM,QAAQ,SAAS;EAClC,QAAQ,QACN,IAAI,WAAW,EAAE,QAAQ,CAAC,EAAE,SAAS,6BAA6B,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC;CACxF,CAAC;CACD,MAAM,MAAM,cAAc,SAAS,KAAK,IAAI,QAAQ,IAAI,IAAI,SAAS,OAAO,GAAG,GAAG,MAAM,CAAC;CACzF,OAAO,OAAO,SAAS,UAAa,MAAM,GAAG,GAAG;AAClD,CAAC"}
@@ -1,6 +1,12 @@
1
1
  import { SvelteRouteParams } from "./internal/route-params.js";
2
- import { Cause, Context, Effect, Exit, Fiber, Layer, ManagedRuntime } from "effect";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Context from "effect/Context";
4
+ import * as Exit from "effect/Exit";
5
+ import * as Layer from "effect/Layer";
6
+ import * as ManagedRuntime from "effect/ManagedRuntime";
3
7
  import { Action, Actions, RequestEvent, RequestHandler, ServerLoad } from "@sveltejs/kit";
8
+ import * as Cause from "effect/Cause";
9
+ import * as Fiber from "effect/Fiber";
4
10
  //#region src/request-runtime.d.ts
5
11
  /**
6
12
  * The runners a {@link RequestRuntimeProvider} resolves for a single request:
@@ -8,7 +14,7 @@ import { Action, Actions, RequestEvent, RequestHandler, ServerLoad } from "@svel
8
14
  * `R`. The error channel is `unknown` because a boundary translator (see
9
15
  * {@link makeRuntimeAdapter}) decides how failures surface.
10
16
  */
11
- interface RequestRuntimeRunners<in R> {
17
+ export interface RequestRuntimeRunners<in R> {
12
18
  /** Run the request's effect, keeping its `Exit` (never rejects). */
13
19
  readonly runPromiseExit: <A>(effect: Effect.Effect<A, unknown, R>) => Promise<Exit.Exit<A, unknown>>;
14
20
  /** Fork the request's effect, returning the running fiber. */
@@ -22,7 +28,7 @@ interface RequestRuntimeRunners<in R> {
22
28
  * set of services the handler effect may require; `E` is the layer construction
23
29
  * error type (informational — failures surface through the translator).
24
30
  */
25
- interface RequestRuntimeProvider<R, E = never> {
31
+ export interface RequestRuntimeProvider<R, E = never> {
26
32
  /** Resolve the runners for a request. Consulted per call, never cached. */
27
33
  readonly run: (event: RequestEvent) => RequestRuntimeRunners<R>;
28
34
  /**
@@ -35,7 +41,7 @@ interface RequestRuntimeProvider<R, E = never> {
35
41
  readonly _E?: (_: never) => E;
36
42
  }
37
43
  /** Options for {@link RequestRuntime.fromLayerPerRequest}. */
38
- interface FromLayerPerRequestOptions {
44
+ export interface FromLayerPerRequestOptions {
39
45
  /**
40
46
  * Defer teardown of the per-request runtime to after the response is
41
47
  * produced, instead of awaiting `dispose()` inline. On Workers, route it
@@ -52,7 +58,7 @@ interface FromLayerPerRequestOptions {
52
58
  * Constructors for {@link RequestRuntimeProvider}. Each expresses one way to
53
59
  * obtain a request's execution context; the wrappers don't care which.
54
60
  */
55
- declare const RequestRuntime: {
61
+ export declare const RequestRuntime: {
56
62
  /**
57
63
  * Adopt a `ManagedRuntime` the consumer already built (the build-once model,
58
64
  * expressed as a provider).
@@ -85,9 +91,9 @@ declare const RequestRuntime: {
85
91
  fromLayerPerRequest: <R, E>(layer: (event: RequestEvent) => Layer.Layer<R, E>, opts?: FromLayerPerRequestOptions) => RequestRuntimeProvider<R, E>;
86
92
  };
87
93
  /** A boundary translator: turn a failed `Cause` into a thrown value. */
88
- type ErrorTranslator = (cause: Cause.Cause<unknown>) => never;
94
+ export type ErrorTranslator = (cause: Cause.Cause<unknown>) => never;
89
95
  /** Options shared by {@link makeRuntimeAdapter}. */
90
- interface RuntimeAdapterOptions {
96
+ export interface RuntimeAdapterOptions {
91
97
  /**
92
98
  * Translate a failed `Cause` into SvelteKit control flow at the boundary.
93
99
  * Called for `serverLoad` / `action` / `actions` failures; it may throw
@@ -98,7 +104,7 @@ interface RuntimeAdapterOptions {
98
104
  readonly translateError?: ErrorTranslator;
99
105
  }
100
106
  /** Options for the adapter's `endpoint` wrapper. */
101
- interface AdapterEndpointOptions {
107
+ export interface AdapterEndpointOptions {
102
108
  /**
103
109
  * Include full error details (`Cause.pretty`) in the default 500 JSON body.
104
110
  * Ignored when a `translateError` is configured. Defaults to `false`.
@@ -106,7 +112,7 @@ interface AdapterEndpointOptions {
106
112
  readonly exposeErrors?: boolean;
107
113
  }
108
114
  /** The wrappers produced by {@link makeRuntimeAdapter}, bound to a provider. */
109
- interface RuntimeAdapter<R> {
115
+ export interface RuntimeAdapter<R> {
110
116
  readonly serverLoad: <Params extends SvelteRouteParams = SvelteRouteParams, ParentData extends Record<string, any> = any, OutputData extends Record<string, any> | void = any, RouteId extends string | null = any>(fn: (event: RequestEvent<Params, RouteId>) => Effect.Effect<OutputData, unknown, R>) => ServerLoad<Params, ParentData, OutputData, RouteId>;
111
117
  readonly action: <Params extends SvelteRouteParams = SvelteRouteParams, OutputData extends Record<string, any> | void = any, RouteId extends string | null = any>(fn: (event: RequestEvent<Params, RouteId>) => Effect.Effect<OutputData, unknown, R>) => Action<Params, OutputData, RouteId>;
112
118
  readonly actions: <Params extends SvelteRouteParams = SvelteRouteParams, OutputData extends Record<string, any> | void = any, RouteId extends string | null = any>(map: Record<string, (event: RequestEvent<Params, RouteId>) => Effect.Effect<OutputData, unknown, R>>) => Actions<Params, OutputData, RouteId>;
@@ -132,7 +138,6 @@ interface RuntimeAdapter<R> {
132
138
  * );
133
139
  * ```
134
140
  */
135
- declare const makeRuntimeAdapter: <R>(provider: RequestRuntimeProvider<R, any>, opts?: RuntimeAdapterOptions) => RuntimeAdapter<R>;
141
+ export declare const makeRuntimeAdapter: <R>(provider: RequestRuntimeProvider<R, any>, opts?: RuntimeAdapterOptions) => RuntimeAdapter<R>;
136
142
  //#endregion
137
- export { AdapterEndpointOptions, ErrorTranslator, FromLayerPerRequestOptions, RequestRuntime, RequestRuntimeProvider, RequestRuntimeRunners, RuntimeAdapter, RuntimeAdapterOptions, makeRuntimeAdapter };
138
143
  //# sourceMappingURL=request-runtime.d.ts.map