ff-serv 0.1.3 → 0.1.4
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/dist/exports/orpc.cjs +233 -5
- package/dist/exports/orpc.cjs.map +1 -1
- package/dist/exports/orpc.d.cts +4 -4
- package/dist/exports/orpc.d.ts +4 -4
- package/dist/exports/orpc.js +233 -5
- package/dist/exports/orpc.js.map +1 -1
- package/dist/fetch-handler-Dwj0ax2Z.d.cts +32 -0
- package/dist/fetch-handler-Dwj0ax2Z.d.ts +32 -0
- package/dist/index.cjs +70 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -3
- package/dist/index.d.ts +21 -3
- package/dist/index.js +70 -29
- package/dist/index.js.map +1 -1
- package/package.json +7 -3
- package/src/http/__test__/utils.ts +46 -0
- package/src/http/basic.test.ts +110 -0
- package/src/http/basic.ts +48 -0
- package/src/http/fetch-handler.test.ts +78 -0
- package/src/http/fetch-handler.ts +63 -49
- package/src/http/index.ts +2 -1
- package/src/http/orpc.test.ts +43 -0
- package/src/http/orpc.ts +19 -11
- package/src/index.ts +2 -2
- package/dist/fetch-handler-BgTGMsrV.d.cts +0 -23
- package/dist/fetch-handler-BgTGMsrV.d.ts +0 -23
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { FetchHttpClient, FileSystem, HttpClient } from '@effect/platform';
|
|
2
|
+
import { describe, expect, expectTypeOf, it, layer } from '@effect/vitest';
|
|
3
|
+
import { Effect, Layer, type Scope } from 'effect';
|
|
4
|
+
import { serverTester } from './__test__/utils.ts';
|
|
5
|
+
import { basicHandler } from './basic.ts';
|
|
6
|
+
import { createFetchHandler, type Handler } from './fetch-handler.ts';
|
|
7
|
+
|
|
8
|
+
describe('type inferences', () => {
|
|
9
|
+
type DefaultRequirements = Scope.Scope;
|
|
10
|
+
|
|
11
|
+
it('no requirement', () => {
|
|
12
|
+
const handler = basicHandler('/dummy', () => new Response('ok'));
|
|
13
|
+
expectTypeOf(handler).toEqualTypeOf<Handler<'basicHandler', never>>();
|
|
14
|
+
|
|
15
|
+
expectTypeOf(createFetchHandler([handler])).toEqualTypeOf<
|
|
16
|
+
Effect.Effect<
|
|
17
|
+
(request: Request) => Promise<Response>,
|
|
18
|
+
never,
|
|
19
|
+
DefaultRequirements
|
|
20
|
+
>
|
|
21
|
+
>();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('with requirement', () => {
|
|
25
|
+
const handler = basicHandler('/dummy', () =>
|
|
26
|
+
Effect.gen(function* () {
|
|
27
|
+
yield* HttpClient.HttpClient;
|
|
28
|
+
return new Response('ok');
|
|
29
|
+
}),
|
|
30
|
+
);
|
|
31
|
+
expectTypeOf(handler).toEqualTypeOf<
|
|
32
|
+
Handler<'basicHandler', HttpClient.HttpClient>
|
|
33
|
+
>();
|
|
34
|
+
|
|
35
|
+
expectTypeOf(createFetchHandler([handler])).toEqualTypeOf<
|
|
36
|
+
Effect.Effect<
|
|
37
|
+
(request: Request) => Promise<Response>,
|
|
38
|
+
never,
|
|
39
|
+
HttpClient.HttpClient | DefaultRequirements
|
|
40
|
+
>
|
|
41
|
+
>();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('with requirements', () => {
|
|
45
|
+
expectTypeOf(
|
|
46
|
+
createFetchHandler([
|
|
47
|
+
basicHandler('/dummy', () =>
|
|
48
|
+
Effect.gen(function* () {
|
|
49
|
+
yield* HttpClient.HttpClient;
|
|
50
|
+
return new Response('ok');
|
|
51
|
+
}),
|
|
52
|
+
),
|
|
53
|
+
basicHandler('/dummy', () =>
|
|
54
|
+
Effect.gen(function* () {
|
|
55
|
+
yield* FileSystem.FileSystem;
|
|
56
|
+
return new Response('ok');
|
|
57
|
+
}),
|
|
58
|
+
),
|
|
59
|
+
]),
|
|
60
|
+
).toEqualTypeOf<
|
|
61
|
+
Effect.Effect<
|
|
62
|
+
(request: Request) => Promise<Response>,
|
|
63
|
+
never,
|
|
64
|
+
HttpClient.HttpClient | FileSystem.FileSystem | DefaultRequirements
|
|
65
|
+
>
|
|
66
|
+
>();
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
class Dummy extends Effect.Service<Dummy>()('dummy', {
|
|
71
|
+
sync: () => ({ message: 'ok-service' }),
|
|
72
|
+
}) {}
|
|
73
|
+
|
|
74
|
+
layer(Layer.mergeAll(FetchHttpClient.layer, Dummy.Default))((it) => {
|
|
75
|
+
it.effect('e2e', () =>
|
|
76
|
+
serverTester({
|
|
77
|
+
server: ({ port }) =>
|
|
78
|
+
Effect.gen(function* () {
|
|
79
|
+
return {
|
|
80
|
+
server: Bun.serve({
|
|
81
|
+
port: port,
|
|
82
|
+
fetch: yield* createFetchHandler([
|
|
83
|
+
basicHandler('/one', () => new Response('ok')),
|
|
84
|
+
basicHandler('/two', () =>
|
|
85
|
+
Effect.succeed(new Response('ok-effect')),
|
|
86
|
+
),
|
|
87
|
+
basicHandler('/three', () =>
|
|
88
|
+
Effect.gen(function* () {
|
|
89
|
+
const svc = yield* Dummy;
|
|
90
|
+
return new Response(svc.message);
|
|
91
|
+
}),
|
|
92
|
+
),
|
|
93
|
+
]),
|
|
94
|
+
}),
|
|
95
|
+
};
|
|
96
|
+
}),
|
|
97
|
+
test: ({ server }) =>
|
|
98
|
+
Effect.gen(function* () {
|
|
99
|
+
const call = (path: string) =>
|
|
100
|
+
HttpClient.get(`http://localhost:${server.port}${path}`).pipe(
|
|
101
|
+
Effect.flatMap((e) => e.text),
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
expect(yield* call('/one')).toEqual('ok');
|
|
105
|
+
expect(yield* call('/two')).toEqual('ok-effect');
|
|
106
|
+
expect(yield* call('/three')).toEqual('ok-service');
|
|
107
|
+
}),
|
|
108
|
+
}),
|
|
109
|
+
);
|
|
110
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Effect } from 'effect';
|
|
2
|
+
import { type AnyResponse, Handler } from './fetch-handler.js';
|
|
3
|
+
|
|
4
|
+
export namespace Path {
|
|
5
|
+
export type Type = `/${string}` | ((url: URL) => boolean);
|
|
6
|
+
export function matched(path: Type, url: URL) {
|
|
7
|
+
return typeof path === 'function' ? path(url) : path === url.pathname;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export namespace Fn {
|
|
12
|
+
type Input = [request: Request];
|
|
13
|
+
|
|
14
|
+
type OutputSync = AnyResponse;
|
|
15
|
+
type OutputEffect<R> = Effect.Effect<AnyResponse, unknown, R>;
|
|
16
|
+
|
|
17
|
+
export type FnSync = (...input: Input) => OutputSync;
|
|
18
|
+
export type FnEffect<R> = (...input: Input) => OutputEffect<R>;
|
|
19
|
+
export type FnAny<R> = (...input: Input) => OutputSync | OutputEffect<R>;
|
|
20
|
+
|
|
21
|
+
export function exec<R>(fn: FnAny<R>, ...[request]: Input) {
|
|
22
|
+
const response = fn(request);
|
|
23
|
+
if (!Effect.isEffect(response)) return Effect.succeed(response);
|
|
24
|
+
return response;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function basicHandler(
|
|
29
|
+
path: Path.Type,
|
|
30
|
+
fn: Fn.FnSync,
|
|
31
|
+
): Handler<'basicHandler', never>;
|
|
32
|
+
export function basicHandler<R>(
|
|
33
|
+
path: Path.Type,
|
|
34
|
+
fn: Fn.FnEffect<R>,
|
|
35
|
+
): Handler<'basicHandler', R>;
|
|
36
|
+
export function basicHandler<R>(path: Path.Type, fn: Fn.FnAny<R>) {
|
|
37
|
+
return new Handler('basicHandler', ({ url, request }) => {
|
|
38
|
+
if (!Path.matched(path, url))
|
|
39
|
+
return Effect.succeed({ matched: false, response: undefined });
|
|
40
|
+
|
|
41
|
+
return Effect.gen(function* () {
|
|
42
|
+
return {
|
|
43
|
+
matched: true,
|
|
44
|
+
response: yield* Fn.exec(fn, request),
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { FetchHttpClient, HttpClient } from '@effect/platform';
|
|
2
|
+
import { expect, layer } from '@effect/vitest';
|
|
3
|
+
import { Cause, Data, Effect, Layer, Ref } from 'effect';
|
|
4
|
+
import { serverTester } from './__test__/utils.ts';
|
|
5
|
+
import { basicHandler } from './basic.ts';
|
|
6
|
+
import { createFetchHandler } from './fetch-handler.ts';
|
|
7
|
+
|
|
8
|
+
class AlsoError extends Error {}
|
|
9
|
+
class CustomError extends Data.TaggedError('CustomError') {}
|
|
10
|
+
|
|
11
|
+
layer(
|
|
12
|
+
Layer.mergeAll(
|
|
13
|
+
FetchHttpClient.layer,
|
|
14
|
+
// Logger.pretty
|
|
15
|
+
),
|
|
16
|
+
)((it) => {
|
|
17
|
+
it.effect('e2e', () =>
|
|
18
|
+
serverTester({
|
|
19
|
+
server: ({ port }) =>
|
|
20
|
+
Effect.gen(function* () {
|
|
21
|
+
const errorsRef = yield* Ref.make<Array<Cause.Cause<unknown>>>([]);
|
|
22
|
+
return {
|
|
23
|
+
errors: errorsRef,
|
|
24
|
+
server: Bun.serve({
|
|
25
|
+
port: port,
|
|
26
|
+
fetch: yield* createFetchHandler(
|
|
27
|
+
[
|
|
28
|
+
basicHandler('/one', () => {
|
|
29
|
+
throw new AlsoError();
|
|
30
|
+
}),
|
|
31
|
+
basicHandler('/two', () =>
|
|
32
|
+
Effect.gen(function* () {
|
|
33
|
+
return yield* new CustomError();
|
|
34
|
+
}),
|
|
35
|
+
),
|
|
36
|
+
],
|
|
37
|
+
{
|
|
38
|
+
onError: ({ error }) =>
|
|
39
|
+
Effect.gen(function* () {
|
|
40
|
+
const errors = yield* Ref.get(errorsRef) ?? [];
|
|
41
|
+
errors.push(error);
|
|
42
|
+
yield* Ref.set(errorsRef, errors);
|
|
43
|
+
}),
|
|
44
|
+
},
|
|
45
|
+
),
|
|
46
|
+
}),
|
|
47
|
+
};
|
|
48
|
+
}),
|
|
49
|
+
test: ({ errors, server }) =>
|
|
50
|
+
Effect.gen(function* () {
|
|
51
|
+
const call = (path: string) =>
|
|
52
|
+
HttpClient.get(`http://localhost:${server.port}${path}`).pipe(
|
|
53
|
+
Effect.flatMap((e) => e.text),
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
expect(yield* call('/one')).toEqual('Internal Server Error');
|
|
57
|
+
yield* Effect.gen(function* () {
|
|
58
|
+
const cause = (yield* Ref.get(errors))[0];
|
|
59
|
+
const isDie = cause._tag === 'Die';
|
|
60
|
+
expect(isDie, `Cause is ${cause._tag}`).toEqual(true);
|
|
61
|
+
if (isDie) {
|
|
62
|
+
expect(cause.defect).toBeInstanceOf(AlsoError);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
expect(yield* call('/two')).toEqual('Internal Server Error');
|
|
67
|
+
yield* Effect.gen(function* () {
|
|
68
|
+
const cause = (yield* Ref.get(errors))[1];
|
|
69
|
+
const isFailType = Cause.isFailType(cause);
|
|
70
|
+
expect(isFailType, `Cause is ${cause._tag}`).toEqual(true);
|
|
71
|
+
if (isFailType) {
|
|
72
|
+
expect(cause.error).toBeInstanceOf(CustomError);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}),
|
|
76
|
+
}),
|
|
77
|
+
);
|
|
78
|
+
});
|
|
@@ -1,49 +1,53 @@
|
|
|
1
1
|
import { Effect, FiberSet } from 'effect';
|
|
2
|
+
import type { Cause } from 'effect/Cause';
|
|
2
3
|
import { nanoid } from 'nanoid';
|
|
3
4
|
import { Logger } from '../logger.js';
|
|
4
5
|
|
|
6
|
+
// #region Handler
|
|
7
|
+
|
|
8
|
+
export type AnyResponse = Response | Promise<Response>;
|
|
9
|
+
|
|
5
10
|
export type HandlerResult =
|
|
6
11
|
| {
|
|
7
12
|
matched: true;
|
|
8
|
-
response:
|
|
13
|
+
response: AnyResponse;
|
|
9
14
|
}
|
|
10
15
|
| {
|
|
11
16
|
matched: false;
|
|
12
17
|
response: undefined;
|
|
13
18
|
};
|
|
14
19
|
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
20
|
+
export class Handler<NAME extends string, R> {
|
|
21
|
+
constructor(
|
|
22
|
+
readonly _tag: NAME,
|
|
23
|
+
readonly handle: (opt: {
|
|
24
|
+
url: URL;
|
|
25
|
+
request: Request;
|
|
26
|
+
}) => Effect.Effect<HandlerResult, unknown, R>,
|
|
27
|
+
) {}
|
|
28
|
+
}
|
|
22
29
|
|
|
23
|
-
|
|
24
|
-
path: string | ((url: URL) => boolean),
|
|
25
|
-
handler: (request: Request) => Response | Promise<Response>,
|
|
26
|
-
): Handler<'basicHandler'> {
|
|
27
|
-
return {
|
|
28
|
-
_tag: 'basicHandler',
|
|
29
|
-
handle: ({ url, request }) => {
|
|
30
|
-
const matched =
|
|
31
|
-
typeof path === 'function' ? path(url) : path === url.pathname;
|
|
32
|
-
if (!matched) return { matched: false, response: undefined };
|
|
30
|
+
// #endregion
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
},
|
|
36
|
-
};
|
|
37
|
-
}
|
|
32
|
+
type ExtractRequirements<T> = T extends Handler<string, infer R> ? R : never;
|
|
38
33
|
|
|
39
|
-
export const createFetchHandler =
|
|
40
|
-
|
|
34
|
+
export const createFetchHandler = <
|
|
35
|
+
const HANDLERS extends [
|
|
36
|
+
Handler<string, unknown>,
|
|
37
|
+
...Array<Handler<string, unknown>>,
|
|
38
|
+
],
|
|
39
|
+
R = ExtractRequirements<HANDLERS[number]>,
|
|
40
|
+
>(
|
|
41
|
+
handlers: HANDLERS,
|
|
41
42
|
opts?: {
|
|
42
43
|
debug?: boolean;
|
|
44
|
+
onError?: (ctx: {
|
|
45
|
+
error: Cause<unknown>;
|
|
46
|
+
}) => Effect.Effect<unknown, unknown>;
|
|
43
47
|
},
|
|
44
48
|
) =>
|
|
45
49
|
Effect.gen(function* () {
|
|
46
|
-
const runFork = yield* FiberSet.makeRuntimePromise();
|
|
50
|
+
const runFork = yield* FiberSet.makeRuntimePromise<R>();
|
|
47
51
|
return async (request: Request) => {
|
|
48
52
|
const urlObj = new URL(request.url);
|
|
49
53
|
const requestId = nanoid(6);
|
|
@@ -54,14 +58,40 @@ export const createFetchHandler = (
|
|
|
54
58
|
'Request started',
|
|
55
59
|
);
|
|
56
60
|
|
|
57
|
-
for (const handler of
|
|
61
|
+
for (const handler of handlers) {
|
|
58
62
|
if (!handler) continue;
|
|
59
63
|
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
64
|
+
const result = yield* handler.handle({ url: urlObj, request }).pipe(
|
|
65
|
+
Effect.flatMap(({ matched, response }) =>
|
|
66
|
+
Effect.gen(function* () {
|
|
67
|
+
if (matched) {
|
|
68
|
+
return {
|
|
69
|
+
matched: true,
|
|
70
|
+
response:
|
|
71
|
+
response instanceof Promise
|
|
72
|
+
? yield* Effect.tryPromise(() => response)
|
|
73
|
+
: response,
|
|
74
|
+
} as const;
|
|
75
|
+
}
|
|
76
|
+
return { matched: false, response: undefined } as const;
|
|
77
|
+
}),
|
|
78
|
+
),
|
|
79
|
+
Effect.catchAllCause((error) =>
|
|
80
|
+
Effect.gen(function* () {
|
|
81
|
+
yield* Logger.error(
|
|
82
|
+
{ error },
|
|
83
|
+
`Unhandled exception in HTTP handler '${handler._tag}'`,
|
|
84
|
+
);
|
|
85
|
+
if (opts?.onError) yield* opts.onError({ error });
|
|
86
|
+
return {
|
|
87
|
+
matched: true,
|
|
88
|
+
response: new Response('Internal Server Error', {
|
|
89
|
+
status: 500,
|
|
90
|
+
}),
|
|
91
|
+
} as const;
|
|
92
|
+
}),
|
|
93
|
+
),
|
|
94
|
+
);
|
|
65
95
|
|
|
66
96
|
if (opts?.debug)
|
|
67
97
|
yield* Logger.debug(
|
|
@@ -75,32 +105,16 @@ export const createFetchHandler = (
|
|
|
75
105
|
|
|
76
106
|
return new Response('Not Found', { status: 404 });
|
|
77
107
|
}).pipe(
|
|
78
|
-
Effect.flatMap((response) =>
|
|
79
|
-
response instanceof Promise
|
|
80
|
-
? Effect.tryPromise(() => response)
|
|
81
|
-
: Effect.succeed(response),
|
|
82
|
-
),
|
|
83
108
|
Effect.tap((response) =>
|
|
84
109
|
response.ok
|
|
85
110
|
? Logger.info(`Request completed with status ${response.status}`)
|
|
86
111
|
: Logger.warn(`Request completed with status ${response.status}`),
|
|
87
112
|
),
|
|
88
|
-
Effect.catchAll((error) =>
|
|
89
|
-
Effect.gen(function* () {
|
|
90
|
-
yield* Logger.error(
|
|
91
|
-
{ error },
|
|
92
|
-
'Unhandled exception in HTTP handler',
|
|
93
|
-
);
|
|
94
|
-
return new Response('Internal Server Error', {
|
|
95
|
-
status: 500,
|
|
96
|
-
});
|
|
97
|
-
}),
|
|
98
|
-
),
|
|
99
113
|
Effect.withSpan('http'),
|
|
100
114
|
Effect.annotateLogs({ requestId }),
|
|
101
115
|
Effect.scoped,
|
|
102
|
-
)
|
|
116
|
+
) as Effect.Effect<Response, never, R>;
|
|
103
117
|
|
|
104
118
|
return runFork(effect);
|
|
105
119
|
};
|
|
106
|
-
});
|
|
120
|
+
});
|
package/src/http/index.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export
|
|
1
|
+
export { basicHandler } from './basic.js';
|
|
2
|
+
export { createFetchHandler } from './fetch-handler.js';
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { expect, it } from '@effect/vitest';
|
|
2
|
+
import { createORPCClient } from '@orpc/client';
|
|
3
|
+
import { RPCLink } from '@orpc/client/fetch';
|
|
4
|
+
import { os, type RouterClient } from '@orpc/server';
|
|
5
|
+
import { RPCHandler } from '@orpc/server/fetch';
|
|
6
|
+
import { Effect } from 'effect';
|
|
7
|
+
import { UnknownException } from 'effect/Cause';
|
|
8
|
+
import { wrapClient } from 'ff-effect';
|
|
9
|
+
import { serverTester } from './__test__/utils.ts';
|
|
10
|
+
import { createFetchHandler } from './fetch-handler.ts';
|
|
11
|
+
import { oRPCHandler } from './orpc.ts';
|
|
12
|
+
|
|
13
|
+
it.effect('e2e', () =>
|
|
14
|
+
serverTester({
|
|
15
|
+
server: ({ port }) =>
|
|
16
|
+
Effect.gen(function* () {
|
|
17
|
+
const router = {
|
|
18
|
+
health: os.handler(() => 'ok'),
|
|
19
|
+
};
|
|
20
|
+
const handler = new RPCHandler(router);
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
router,
|
|
24
|
+
server: Bun.serve({
|
|
25
|
+
port: port,
|
|
26
|
+
fetch: yield* createFetchHandler([oRPCHandler(handler)]),
|
|
27
|
+
}),
|
|
28
|
+
};
|
|
29
|
+
}),
|
|
30
|
+
test: ({ server, router }) =>
|
|
31
|
+
Effect.gen(function* () {
|
|
32
|
+
const orpcClient: RouterClient<typeof router> = createORPCClient(
|
|
33
|
+
new RPCLink({ url: `http://localhost:${server.port}` }),
|
|
34
|
+
);
|
|
35
|
+
const call = wrapClient({
|
|
36
|
+
client: orpcClient,
|
|
37
|
+
error: ({ cause }) => new UnknownException(cause),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
expect(yield* call((client) => client.health())).toEqual('ok');
|
|
41
|
+
}),
|
|
42
|
+
}),
|
|
43
|
+
);
|
package/src/http/orpc.ts
CHANGED
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
import type { Context } from '@orpc/server';
|
|
2
2
|
import type { FetchHandler } from '@orpc/server/fetch';
|
|
3
3
|
import type { FriendlyStandardHandleOptions } from '@orpc/server/standard';
|
|
4
|
-
import
|
|
4
|
+
import { Effect } from 'effect';
|
|
5
|
+
import { Handler } from './fetch-handler.js';
|
|
5
6
|
|
|
6
|
-
type MaybeOptionalOptions<TOptions> =
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
type MaybeOptionalOptions<TOptions> =
|
|
8
|
+
Record<never, never> extends TOptions
|
|
9
|
+
? [options?: TOptions]
|
|
10
|
+
: [options: TOptions];
|
|
9
11
|
|
|
10
|
-
export function oRPCHandler<T extends Context>(
|
|
12
|
+
export function oRPCHandler<T extends Context, E, R>(
|
|
11
13
|
handler: FetchHandler<T>,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
opt?:
|
|
15
|
+
| FriendlyStandardHandleOptions<T>
|
|
16
|
+
| Effect.Effect<FriendlyStandardHandleOptions<T>, E, R>,
|
|
17
|
+
) {
|
|
18
|
+
return new Handler('oRPCHandler', ({ request }) =>
|
|
19
|
+
Effect.gen(function* () {
|
|
20
|
+
const _opt = (
|
|
21
|
+
opt ? [Effect.isEffect(opt) ? yield* opt : opt] : []
|
|
22
|
+
) as MaybeOptionalOptions<FriendlyStandardHandleOptions<T>>;
|
|
23
|
+
return yield* Effect.tryPromise(() => handler.handle(request, ..._opt));
|
|
24
|
+
}),
|
|
25
|
+
);
|
|
18
26
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export
|
|
1
|
+
export * from './http/index.js';
|
|
2
2
|
export { Logger } from './logger.js';
|
|
3
|
-
export { getPort } from './port.js';
|
|
3
|
+
export { getPort } from './port.js';
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import * as effect_Scope from 'effect/Scope';
|
|
2
|
-
import { Effect } from 'effect';
|
|
3
|
-
|
|
4
|
-
type HandlerResult = {
|
|
5
|
-
matched: true;
|
|
6
|
-
response: Response | Promise<Response>;
|
|
7
|
-
} | {
|
|
8
|
-
matched: false;
|
|
9
|
-
response: undefined;
|
|
10
|
-
};
|
|
11
|
-
type Handler<T extends string = string> = {
|
|
12
|
-
_tag: T;
|
|
13
|
-
handle: (opt: {
|
|
14
|
-
url: URL;
|
|
15
|
-
request: Request;
|
|
16
|
-
}) => HandlerResult | Promise<HandlerResult>;
|
|
17
|
-
};
|
|
18
|
-
declare function basicHandler(path: string | ((url: URL) => boolean), handler: (request: Request) => Response | Promise<Response>): Handler<'basicHandler'>;
|
|
19
|
-
declare const createFetchHandler: (handlers?: Handler | [Handler, ...Array<Handler>], opts?: {
|
|
20
|
-
debug?: boolean;
|
|
21
|
-
}) => Effect.Effect<(request: Request) => Promise<Response>, never, effect_Scope.Scope>;
|
|
22
|
-
|
|
23
|
-
export { type Handler as H, basicHandler as b, createFetchHandler as c };
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import * as effect_Scope from 'effect/Scope';
|
|
2
|
-
import { Effect } from 'effect';
|
|
3
|
-
|
|
4
|
-
type HandlerResult = {
|
|
5
|
-
matched: true;
|
|
6
|
-
response: Response | Promise<Response>;
|
|
7
|
-
} | {
|
|
8
|
-
matched: false;
|
|
9
|
-
response: undefined;
|
|
10
|
-
};
|
|
11
|
-
type Handler<T extends string = string> = {
|
|
12
|
-
_tag: T;
|
|
13
|
-
handle: (opt: {
|
|
14
|
-
url: URL;
|
|
15
|
-
request: Request;
|
|
16
|
-
}) => HandlerResult | Promise<HandlerResult>;
|
|
17
|
-
};
|
|
18
|
-
declare function basicHandler(path: string | ((url: URL) => boolean), handler: (request: Request) => Response | Promise<Response>): Handler<'basicHandler'>;
|
|
19
|
-
declare const createFetchHandler: (handlers?: Handler | [Handler, ...Array<Handler>], opts?: {
|
|
20
|
-
debug?: boolean;
|
|
21
|
-
}) => Effect.Effect<(request: Request) => Promise<Response>, never, effect_Scope.Scope>;
|
|
22
|
-
|
|
23
|
-
export { type Handler as H, basicHandler as b, createFetchHandler as c };
|