@kuroski/effect-svelte 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +223 -0
- package/dist/errors.d.ts +67 -0
- package/dist/errors.js +63 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/runner.d.ts +10 -0
- package/dist/runner.js +59 -0
- package/package.json +80 -0
package/README.md
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# effect-svelte
|
|
2
|
+
|
|
3
|
+
Integration library for [Effect](https://effect.website/) with [SvelteKit](https://kit.svelte.dev/). Run Effect programs in SvelteKit load functions and remote functions with automatic error handling, redirects, and form validation.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm add effect-svelte
|
|
9
|
+
# or
|
|
10
|
+
bun add effect-svelte
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
**Peer dependencies:** `effect >=3.19.15`, `svelte >=5`, `@sveltejs/kit >=2`
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
### 1. Create a Runner
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
// src/lib/server/runtime.ts
|
|
21
|
+
import { Effect, Layer, ManagedRuntime } from "effect";
|
|
22
|
+
import { createRunner } from "effect-svelte";
|
|
23
|
+
|
|
24
|
+
const AppLayer = Layer.mergeAll(
|
|
25
|
+
// your service layers
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const RuntimeServer = ManagedRuntime.make(AppLayer);
|
|
29
|
+
|
|
30
|
+
export const remoteRunner = createRunner({
|
|
31
|
+
runtime: RuntimeServer,
|
|
32
|
+
before: () => Effect.log("Starting operation"),
|
|
33
|
+
after: () => Effect.log("Operation completed"),
|
|
34
|
+
onError: (err, isUnexpectedError) =>
|
|
35
|
+
isUnexpectedError
|
|
36
|
+
? Effect.logError("Operation failed", err)
|
|
37
|
+
: Effect.void,
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 2. Use in Load Functions
|
|
42
|
+
|
|
43
|
+
The runner works directly inside SvelteKit `load` functions. Call it with an operation name, your Effect program, and an optional error-mapping pipeline:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
// src/routes/posts/+page.server.ts
|
|
47
|
+
import { Effect } from "effect";
|
|
48
|
+
import { httpErrorEffect } from "effect-svelte";
|
|
49
|
+
import { remoteRunner } from "$lib/server/runtime";
|
|
50
|
+
|
|
51
|
+
export async function load({ params }) {
|
|
52
|
+
return remoteRunner(
|
|
53
|
+
"load-posts",
|
|
54
|
+
Effect.gen(function* () {
|
|
55
|
+
const posts = yield* fetchPosts();
|
|
56
|
+
|
|
57
|
+
if (posts.length === 0) {
|
|
58
|
+
yield* httpErrorEffect(404, "NOT_FOUND", "No posts found");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return { posts };
|
|
62
|
+
}),
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```svelte
|
|
68
|
+
<!-- src/routes/posts/+page.svelte -->
|
|
69
|
+
<script lang="ts">
|
|
70
|
+
let { data } = $props();
|
|
71
|
+
</script>
|
|
72
|
+
|
|
73
|
+
<ul>
|
|
74
|
+
{#each data.posts as post (post.id)}
|
|
75
|
+
<li>{post.title}</li>
|
|
76
|
+
{/each}
|
|
77
|
+
</ul>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 3. Use in Remote Functions
|
|
81
|
+
|
|
82
|
+
The same runner works with SvelteKit's experimental [remote functions](https://svelte.dev/docs/kit/remote-functions):
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
// src/routes/posts.remote.ts
|
|
86
|
+
import { Effect } from "effect";
|
|
87
|
+
import { query } from "$app/server";
|
|
88
|
+
import { remoteRunner } from "$lib/server/runtime";
|
|
89
|
+
|
|
90
|
+
export const getPosts = query(() =>
|
|
91
|
+
remoteRunner(
|
|
92
|
+
"get-posts",
|
|
93
|
+
Effect.gen(function* () {
|
|
94
|
+
yield* Effect.logInfo("Fetching posts");
|
|
95
|
+
return { posts: [{ id: 1, title: "Hello" }] };
|
|
96
|
+
}),
|
|
97
|
+
),
|
|
98
|
+
);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
```svelte
|
|
102
|
+
<!-- src/routes/+page.svelte -->
|
|
103
|
+
<script lang="ts">
|
|
104
|
+
import { getPosts } from "./posts.remote.ts";
|
|
105
|
+
</script>
|
|
106
|
+
|
|
107
|
+
<svelte:boundary>
|
|
108
|
+
{#snippet pending()}
|
|
109
|
+
<p>loading...</p>
|
|
110
|
+
{/snippet}
|
|
111
|
+
|
|
112
|
+
{#snippet failed(error)}
|
|
113
|
+
<span>Error: {error}</span>
|
|
114
|
+
{/snippet}
|
|
115
|
+
|
|
116
|
+
{@const { posts } = await getPosts()}
|
|
117
|
+
<ul>
|
|
118
|
+
{#each posts as post (post.id)}
|
|
119
|
+
<li>{post.title}</li>
|
|
120
|
+
{/each}
|
|
121
|
+
</ul>
|
|
122
|
+
</svelte:boundary>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Error Handling
|
|
126
|
+
|
|
127
|
+
The library provides three tagged error types that map to SvelteKit's control flow:
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
import { Effect } from "effect";
|
|
131
|
+
import {
|
|
132
|
+
SvelteKitRedirect,
|
|
133
|
+
SvelteKitHttpError,
|
|
134
|
+
SvelteKitInvalidError,
|
|
135
|
+
redirectEffect,
|
|
136
|
+
httpErrorEffect,
|
|
137
|
+
invalidEffect,
|
|
138
|
+
} from "effect-svelte";
|
|
139
|
+
|
|
140
|
+
Effect.gen(function* () {
|
|
141
|
+
// Redirect (throws SvelteKit redirect())
|
|
142
|
+
yield* redirectEffect(303, "/login");
|
|
143
|
+
// or: yield* Effect.fail(SvelteKitRedirect.make(303, "/login"));
|
|
144
|
+
|
|
145
|
+
// HTTP error (throws SvelteKit error())
|
|
146
|
+
yield* httpErrorEffect(404, "NOT_FOUND", "Resource not found");
|
|
147
|
+
// or: yield* Effect.fail(SvelteKitHttpError.make(404, "NOT_FOUND", "Not found"));
|
|
148
|
+
|
|
149
|
+
// Form validation error (throws SvelteKit invalid())
|
|
150
|
+
yield* invalidEffect("email", "Invalid email format");
|
|
151
|
+
// or: yield* Effect.fail(SvelteKitInvalidError.make({ email: "Invalid" }));
|
|
152
|
+
});
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Pipeline for Error Mapping
|
|
156
|
+
|
|
157
|
+
Use the third argument of the runner to map domain errors to SvelteKit errors:
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
export const listProjects = remoteRunner(
|
|
161
|
+
"listProjects",
|
|
162
|
+
Effect.gen(function* () {
|
|
163
|
+
const service = yield* ProjectService;
|
|
164
|
+
return yield* service.all();
|
|
165
|
+
}),
|
|
166
|
+
(effect) =>
|
|
167
|
+
effect.pipe(
|
|
168
|
+
Effect.catchTags({
|
|
169
|
+
ParseError: () =>
|
|
170
|
+
httpErrorEffect(500, "PARSE_ERROR", "Unexpected data from the server"),
|
|
171
|
+
ResponseError: () =>
|
|
172
|
+
httpErrorEffect(500, "GENERIC_ERROR", "Unexpected server response"),
|
|
173
|
+
}),
|
|
174
|
+
),
|
|
175
|
+
);
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## API Reference
|
|
179
|
+
|
|
180
|
+
### `createRunner(options)`
|
|
181
|
+
|
|
182
|
+
Creates a runner function that executes Effect programs in a SvelteKit context.
|
|
183
|
+
|
|
184
|
+
**Options:**
|
|
185
|
+
|
|
186
|
+
| Option | Type | Description |
|
|
187
|
+
|--------|------|-------------|
|
|
188
|
+
| `runtime` | `ManagedRuntime<R, never>` | The Effect runtime to use |
|
|
189
|
+
| `before` | `() => Effect<void>` | Runs before the effect |
|
|
190
|
+
| `after` | `(result: A) => Effect<void>` | Runs after successful execution |
|
|
191
|
+
| `onError` | `(err, isUnexpectedError) => Effect<void>` | Error handler. `isUnexpectedError` is `true` for 500+ errors and unrecognized failures, `false` for redirects, validation errors, and <500 HTTP errors |
|
|
192
|
+
|
|
193
|
+
**Returns:** `Runner<R>` - a function with signature:
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
(operationName: string, effect: Effect<A, E, R>, pipeline?: PipelineFn<R>) => Promise<A>
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Execution order:** `before` → `effect` → `pipeline` → `onError` (on failure) → `after` (on success) → `withSpan(operationName)`
|
|
200
|
+
|
|
201
|
+
### Error Types
|
|
202
|
+
|
|
203
|
+
| Class | Converts to | Factory |
|
|
204
|
+
|-------|-------------|---------|
|
|
205
|
+
| `SvelteKitRedirect` | `redirect(status, location)` | `SvelteKitRedirect.make(status, location)` |
|
|
206
|
+
| `SvelteKitHttpError` | `error(status, body)` | `SvelteKitHttpError.make(status, code, message, details?)` |
|
|
207
|
+
| `SvelteKitInvalidError` | `invalid(issues)` | `SvelteKitInvalidError.make(issues)` |
|
|
208
|
+
|
|
209
|
+
### Convenience Functions
|
|
210
|
+
|
|
211
|
+
| Function | Description |
|
|
212
|
+
|----------|-------------|
|
|
213
|
+
| `redirectEffect(status, location)` | Returns `Effect.fail(SvelteKitRedirect.make(...))` |
|
|
214
|
+
| `httpErrorEffect(status, code, message, details?)` | Returns `Effect.fail(SvelteKitHttpError.make(...))` |
|
|
215
|
+
| `invalidEffect(issues)` | Returns `Effect.fail(SvelteKitInvalidError.make(...))` |
|
|
216
|
+
|
|
217
|
+
### `SvelteEffect.Code`
|
|
218
|
+
|
|
219
|
+
Error code type: `"GENERIC_ERROR" | "PARSE_ERROR" | "NOT_FOUND" | "UNAUTHORIZED"`
|
|
220
|
+
|
|
221
|
+
## License
|
|
222
|
+
|
|
223
|
+
MIT
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { HttpError, invalid, Redirect } from "@sveltejs/kit";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
export declare namespace SvelteEffect {
|
|
4
|
+
type Code = "GENERIC_ERROR" | "PARSE_ERROR" | "NOT_FOUND" | "UNAUTHORIZED";
|
|
5
|
+
interface ErrorBody {
|
|
6
|
+
code: Code;
|
|
7
|
+
details?: Record<string, unknown>;
|
|
8
|
+
message: string;
|
|
9
|
+
timestamp: string;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export declare class SvelteKitError extends Error implements SvelteEffect.ErrorBody {
|
|
13
|
+
code: SvelteEffect.Code;
|
|
14
|
+
details?: Record<string, unknown>;
|
|
15
|
+
timestamp: string;
|
|
16
|
+
constructor(message: string, code: SvelteEffect.Code, details?: Record<string, unknown>);
|
|
17
|
+
}
|
|
18
|
+
declare const SvelteKitRedirect_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
19
|
+
readonly _tag: "SvelteKitRedirect";
|
|
20
|
+
} & Readonly<A>;
|
|
21
|
+
/**
|
|
22
|
+
* Tagged error representing a SvelteKit redirect.
|
|
23
|
+
*
|
|
24
|
+
* When handled by the runner it is converted to a thrown SvelteKit `redirect()`.
|
|
25
|
+
*/
|
|
26
|
+
export declare class SvelteKitRedirect extends SvelteKitRedirect_base<{
|
|
27
|
+
readonly status: Redirect["status"];
|
|
28
|
+
readonly location: string;
|
|
29
|
+
}> {
|
|
30
|
+
static make(status: Redirect["status"], location: string): SvelteKitRedirect;
|
|
31
|
+
}
|
|
32
|
+
declare const SvelteKitHttpError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
33
|
+
readonly _tag: "SvelteKitHttpError";
|
|
34
|
+
} & Readonly<A>;
|
|
35
|
+
/**
|
|
36
|
+
* Tagged error representing a SvelteKit HTTP error.
|
|
37
|
+
*
|
|
38
|
+
* When handled by the runner it is converted to a thrown SvelteKit `error()`.
|
|
39
|
+
*/
|
|
40
|
+
export declare class SvelteKitHttpError extends SvelteKitHttpError_base<{
|
|
41
|
+
readonly status: HttpError["status"];
|
|
42
|
+
readonly body: {
|
|
43
|
+
code: SvelteEffect.Code;
|
|
44
|
+
details?: Record<string, unknown> | undefined;
|
|
45
|
+
message: string;
|
|
46
|
+
timestamp: string;
|
|
47
|
+
};
|
|
48
|
+
}> {
|
|
49
|
+
static make(status: HttpError["status"], code: SvelteEffect.Code, message: string, details?: Record<string, unknown> | undefined): SvelteKitHttpError;
|
|
50
|
+
}
|
|
51
|
+
declare const SvelteKitInvalidError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
52
|
+
readonly _tag: "SvelteKitInvalidError";
|
|
53
|
+
} & Readonly<A>;
|
|
54
|
+
/**
|
|
55
|
+
* Tagged error representing SvelteKit form validation errors.
|
|
56
|
+
*
|
|
57
|
+
* When handled by the runner it is converted to a thrown SvelteKit `invalid()`.
|
|
58
|
+
*/
|
|
59
|
+
export declare class SvelteKitInvalidError extends SvelteKitInvalidError_base<{
|
|
60
|
+
readonly issues: Parameters<typeof invalid>;
|
|
61
|
+
}> {
|
|
62
|
+
static make(...issues: Parameters<typeof invalid>): SvelteKitInvalidError;
|
|
63
|
+
}
|
|
64
|
+
export declare function redirectEffect(status: Redirect["status"], location: string): Effect.Effect<never, SvelteKitRedirect>;
|
|
65
|
+
export declare function httpErrorEffect(status: HttpError["status"], code: SvelteEffect.Code, message: string, details?: Record<string, unknown>): Effect.Effect<never, SvelteKitHttpError>;
|
|
66
|
+
export declare function invalidEffect(...issues: [field: string, message: string] | [Record<string, string>]): Effect.Effect<never, SvelteKitInvalidError>;
|
|
67
|
+
export {};
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Data, Effect } from "effect";
|
|
2
|
+
export class SvelteKitError extends Error {
|
|
3
|
+
constructor(message, code, details) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = "SvelteKitError";
|
|
6
|
+
this.code = code;
|
|
7
|
+
this.details = details;
|
|
8
|
+
this.timestamp = new Date().toISOString();
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Tagged errors (used inside Effect programs)
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
/**
|
|
15
|
+
* Tagged error representing a SvelteKit redirect.
|
|
16
|
+
*
|
|
17
|
+
* When handled by the runner it is converted to a thrown SvelteKit `redirect()`.
|
|
18
|
+
*/
|
|
19
|
+
export class SvelteKitRedirect extends Data.TaggedError("SvelteKitRedirect") {
|
|
20
|
+
static make(status, location) {
|
|
21
|
+
return new SvelteKitRedirect({ location, status });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Tagged error representing a SvelteKit HTTP error.
|
|
26
|
+
*
|
|
27
|
+
* When handled by the runner it is converted to a thrown SvelteKit `error()`.
|
|
28
|
+
*/
|
|
29
|
+
export class SvelteKitHttpError extends Data.TaggedError("SvelteKitHttpError") {
|
|
30
|
+
static make(status, code, message, details) {
|
|
31
|
+
return new SvelteKitHttpError({
|
|
32
|
+
body: {
|
|
33
|
+
code,
|
|
34
|
+
details,
|
|
35
|
+
message,
|
|
36
|
+
timestamp: new Date().toISOString(),
|
|
37
|
+
},
|
|
38
|
+
status,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Tagged error representing SvelteKit form validation errors.
|
|
44
|
+
*
|
|
45
|
+
* When handled by the runner it is converted to a thrown SvelteKit `invalid()`.
|
|
46
|
+
*/
|
|
47
|
+
export class SvelteKitInvalidError extends Data.TaggedError("SvelteKitInvalidError") {
|
|
48
|
+
static make(...issues) {
|
|
49
|
+
return new SvelteKitInvalidError({ issues });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Convenience effect constructors
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
export function redirectEffect(status, location) {
|
|
56
|
+
return Effect.fail(SvelteKitRedirect.make(status, location));
|
|
57
|
+
}
|
|
58
|
+
export function httpErrorEffect(status, code, message, details) {
|
|
59
|
+
return Effect.fail(SvelteKitHttpError.make(status, code, message, details));
|
|
60
|
+
}
|
|
61
|
+
export function invalidEffect(...issues) {
|
|
62
|
+
return Effect.fail(SvelteKitInvalidError.make(...issues));
|
|
63
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
package/dist/runner.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Effect, type ManagedRuntime } from "effect";
|
|
2
|
+
export interface RunnerOptions<R> {
|
|
3
|
+
runtime: ManagedRuntime.ManagedRuntime<R, never>;
|
|
4
|
+
before?: () => Effect.Effect<void>;
|
|
5
|
+
after?: <A>(result: A) => Effect.Effect<void>;
|
|
6
|
+
onError?: (err: unknown, isUnexpectedError: boolean) => Effect.Effect<void>;
|
|
7
|
+
}
|
|
8
|
+
export type PipelineFn<A, E, R> = (effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
|
|
9
|
+
export type Runner<R> = <A, E>(operationName: string, effect: Effect.Effect<A, E, R>, pipeline?: PipelineFn<A, E, R>) => Promise<A>;
|
|
10
|
+
export declare function createRunner<R>(options: RunnerOptions<R>): Runner<R>;
|
package/dist/runner.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { error, invalid, redirect } from "@sveltejs/kit";
|
|
2
|
+
import { Cause, Effect, Exit, Function, Match, Option, } from "effect";
|
|
3
|
+
import { SvelteKitError, SvelteKitHttpError, SvelteKitInvalidError, SvelteKitRedirect, } from "./errors.js";
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Internal helpers
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
function isUnexpectedError(err) {
|
|
8
|
+
if (err instanceof SvelteKitRedirect)
|
|
9
|
+
return false;
|
|
10
|
+
if (err instanceof SvelteKitInvalidError)
|
|
11
|
+
return false;
|
|
12
|
+
if (err instanceof SvelteKitHttpError && err.status < 500)
|
|
13
|
+
return false;
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
function handleExit(exit) {
|
|
17
|
+
return Exit.match(exit, {
|
|
18
|
+
onFailure: (cause) => Function.pipe(Cause.failureOption(cause), Option.match({
|
|
19
|
+
onNone: () => {
|
|
20
|
+
console.error("Unhandled Effect error:", Cause.pretty(cause));
|
|
21
|
+
throw error(500, new SvelteKitError("Internal Server Error", "GENERIC_ERROR"));
|
|
22
|
+
},
|
|
23
|
+
onSome: (failure) => Match.value(failure).pipe(Match.when(Match.instanceOf(SvelteKitRedirect), (err) => {
|
|
24
|
+
throw redirect(err.status, err.location);
|
|
25
|
+
}), Match.when(Match.instanceOf(SvelteKitHttpError), (err) => {
|
|
26
|
+
throw error(err.status, new SvelteKitError(err.body.message, err.body.code, err.body.details));
|
|
27
|
+
}), Match.when(Match.instanceOf(SvelteKitInvalidError), (err) => {
|
|
28
|
+
throw invalid(...err.issues);
|
|
29
|
+
}), Match.orElse(() => {
|
|
30
|
+
console.error("Unhandled Effect error:", Cause.pretty(cause));
|
|
31
|
+
throw error(500, new SvelteKitError("Internal Server Error", "GENERIC_ERROR"));
|
|
32
|
+
})),
|
|
33
|
+
})),
|
|
34
|
+
onSuccess: Function.identity,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// Public API
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
export function createRunner(options) {
|
|
41
|
+
return async function remoteRunner(operationName, effect, pipeline) {
|
|
42
|
+
let program = options.before
|
|
43
|
+
? Effect.zipRight(options.before(), effect)
|
|
44
|
+
: effect;
|
|
45
|
+
if (pipeline) {
|
|
46
|
+
program = pipeline(program);
|
|
47
|
+
}
|
|
48
|
+
program = program.pipe(Effect.tapError((err) => {
|
|
49
|
+
if (!options.onError)
|
|
50
|
+
return Effect.void;
|
|
51
|
+
return options.onError(err, isUnexpectedError(err));
|
|
52
|
+
}));
|
|
53
|
+
if (options.after) {
|
|
54
|
+
program = program.pipe(Effect.tap(options.after));
|
|
55
|
+
}
|
|
56
|
+
const exit = await options.runtime.runPromiseExit(program.pipe(Effect.withSpan(operationName)));
|
|
57
|
+
return handleExit(exit);
|
|
58
|
+
};
|
|
59
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"author": {
|
|
3
|
+
"email": "daniel.kuroski@gmail.com",
|
|
4
|
+
"name": "Daniel Kuroski",
|
|
5
|
+
"url": "https://github.com/kuroski"
|
|
6
|
+
},
|
|
7
|
+
"bugs": {
|
|
8
|
+
"url": "https://github.com/kuroski/effect-svelte/issues"
|
|
9
|
+
},
|
|
10
|
+
"description": "Integration library for Effect with SvelteKit - seamless effect handling in SvelteKit remote functions",
|
|
11
|
+
"devDependencies": {
|
|
12
|
+
"@biomejs/biome": "2.3.13",
|
|
13
|
+
"@commitlint/cli": "20.4.0",
|
|
14
|
+
"@commitlint/config-conventional": "20.4.0",
|
|
15
|
+
"@semantic-release/changelog": "6.0.3",
|
|
16
|
+
"@semantic-release/git": "10.0.1",
|
|
17
|
+
"@sveltejs/kit": "2.50.1",
|
|
18
|
+
"@sveltejs/package": "2.5.7",
|
|
19
|
+
"@sveltejs/vite-plugin-svelte": "6.2.4",
|
|
20
|
+
"husky": "9.1.7",
|
|
21
|
+
"publint": "0.3.17",
|
|
22
|
+
"semantic-release": "25.0.3",
|
|
23
|
+
"svelte": "5.49.1",
|
|
24
|
+
"svelte-check": "4.3.6",
|
|
25
|
+
"typescript": "5.9.3",
|
|
26
|
+
"vite": "7.3.1",
|
|
27
|
+
"vitest": "4.0.18"
|
|
28
|
+
},
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"default": "./dist/index.js"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist",
|
|
37
|
+
"!dist/**/*.test.*",
|
|
38
|
+
"!dist/**/*.spec.*"
|
|
39
|
+
],
|
|
40
|
+
"homepage": "https://github.com/kuroski/effect-svelte#readme",
|
|
41
|
+
"keywords": [
|
|
42
|
+
"sveltekit",
|
|
43
|
+
"effect",
|
|
44
|
+
"effect-ts",
|
|
45
|
+
"svelte",
|
|
46
|
+
"functional",
|
|
47
|
+
"error-handling"
|
|
48
|
+
],
|
|
49
|
+
"license": "MIT",
|
|
50
|
+
"name": "@kuroski/effect-svelte",
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"@sveltejs/kit": ">=2.0.0",
|
|
53
|
+
"effect": ">=3.19.15 <4.0.0",
|
|
54
|
+
"svelte": ">=5.49.1"
|
|
55
|
+
},
|
|
56
|
+
"repository": {
|
|
57
|
+
"type": "git",
|
|
58
|
+
"url": "git+https://github.com/kuroski/effect-svelte.git"
|
|
59
|
+
},
|
|
60
|
+
"scripts": {
|
|
61
|
+
"biome:check": "biome check --write",
|
|
62
|
+
"biome:ci": "biome check",
|
|
63
|
+
"build": "vite build && bun run prepack",
|
|
64
|
+
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
65
|
+
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
|
66
|
+
"dev": "vite dev",
|
|
67
|
+
"prepack": "svelte-kit sync && svelte-package && publint",
|
|
68
|
+
"prepare": "husky && (svelte-kit sync || echo '')",
|
|
69
|
+
"preview": "vite preview",
|
|
70
|
+
"test": "vitest run",
|
|
71
|
+
"test:watch": "vitest"
|
|
72
|
+
},
|
|
73
|
+
"type": "module",
|
|
74
|
+
"types": "./dist/index.d.ts",
|
|
75
|
+
"version": "1.0.0",
|
|
76
|
+
"publishConfig": {
|
|
77
|
+
"access": "public",
|
|
78
|
+
"provenance": true
|
|
79
|
+
}
|
|
80
|
+
}
|