ff-serv 0.1.2 → 0.1.3
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 +38 -0
- package/dist/exports/orpc.cjs.map +1 -0
- package/dist/exports/orpc.d.cts +11 -0
- package/dist/exports/orpc.d.ts +11 -0
- package/dist/exports/orpc.js +11 -0
- package/dist/exports/orpc.js.map +1 -0
- package/dist/fetch-handler-BgTGMsrV.d.cts +23 -0
- package/dist/fetch-handler-BgTGMsrV.d.ts +23 -0
- package/dist/index.cjs +77 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +73 -1
- package/dist/index.js.map +1 -1
- package/package.json +16 -5
- package/src/exports/orpc.ts +1 -0
- package/src/http/fetch-handler.ts +106 -0
- package/src/http/index.ts +1 -0
- package/src/http/orpc.ts +18 -0
- package/src/index.ts +2 -0
- package/src/port.ts +5 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/exports/orpc.ts
|
|
21
|
+
var orpc_exports = {};
|
|
22
|
+
__export(orpc_exports, {
|
|
23
|
+
oRPCHandler: () => oRPCHandler
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(orpc_exports);
|
|
26
|
+
|
|
27
|
+
// src/http/orpc.ts
|
|
28
|
+
function oRPCHandler(handler, ...rest) {
|
|
29
|
+
return {
|
|
30
|
+
_tag: "oRPCHandler",
|
|
31
|
+
handle: async ({ request }) => handler.handle(request, ...rest)
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
35
|
+
0 && (module.exports = {
|
|
36
|
+
oRPCHandler
|
|
37
|
+
});
|
|
38
|
+
//# sourceMappingURL=orpc.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/exports/orpc.ts","../../src/http/orpc.ts"],"sourcesContent":["export { oRPCHandler } from '../http/orpc.js';","import type { Context } from '@orpc/server';\nimport type { FetchHandler } from '@orpc/server/fetch';\nimport type { FriendlyStandardHandleOptions } from '@orpc/server/standard';\nimport type { Handler } from './fetch-handler.js';\n\ntype MaybeOptionalOptions<TOptions> = Record<never, never> extends TOptions\n\t? [options?: TOptions]\n\t: [options: TOptions];\n\nexport function oRPCHandler<T extends Context>(\n\thandler: FetchHandler<T>,\n\t...rest: MaybeOptionalOptions<FriendlyStandardHandleOptions<T>>\n): Handler<'oRPCHandler'> {\n\treturn {\n\t\t_tag: 'oRPCHandler',\n\t\thandle: async ({ request }) => handler.handle(request, ...rest),\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACSO,SAAS,YACf,YACG,MACsB;AACzB,SAAO;AAAA,IACN,MAAM;AAAA,IACN,QAAQ,OAAO,EAAE,QAAQ,MAAM,QAAQ,OAAO,SAAS,GAAG,IAAI;AAAA,EAC/D;AACD;","names":[]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Context } from '@orpc/server';
|
|
2
|
+
import { FetchHandler } from '@orpc/server/fetch';
|
|
3
|
+
import { FriendlyStandardHandleOptions } from '@orpc/server/standard';
|
|
4
|
+
import { H as Handler } from '../fetch-handler-BgTGMsrV.cjs';
|
|
5
|
+
import 'effect/Scope';
|
|
6
|
+
import 'effect';
|
|
7
|
+
|
|
8
|
+
type MaybeOptionalOptions<TOptions> = Record<never, never> extends TOptions ? [options?: TOptions] : [options: TOptions];
|
|
9
|
+
declare function oRPCHandler<T extends Context>(handler: FetchHandler<T>, ...rest: MaybeOptionalOptions<FriendlyStandardHandleOptions<T>>): Handler<'oRPCHandler'>;
|
|
10
|
+
|
|
11
|
+
export { oRPCHandler };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Context } from '@orpc/server';
|
|
2
|
+
import { FetchHandler } from '@orpc/server/fetch';
|
|
3
|
+
import { FriendlyStandardHandleOptions } from '@orpc/server/standard';
|
|
4
|
+
import { H as Handler } from '../fetch-handler-BgTGMsrV.js';
|
|
5
|
+
import 'effect/Scope';
|
|
6
|
+
import 'effect';
|
|
7
|
+
|
|
8
|
+
type MaybeOptionalOptions<TOptions> = Record<never, never> extends TOptions ? [options?: TOptions] : [options: TOptions];
|
|
9
|
+
declare function oRPCHandler<T extends Context>(handler: FetchHandler<T>, ...rest: MaybeOptionalOptions<FriendlyStandardHandleOptions<T>>): Handler<'oRPCHandler'>;
|
|
10
|
+
|
|
11
|
+
export { oRPCHandler };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/http/orpc.ts"],"sourcesContent":["import type { Context } from '@orpc/server';\nimport type { FetchHandler } from '@orpc/server/fetch';\nimport type { FriendlyStandardHandleOptions } from '@orpc/server/standard';\nimport type { Handler } from './fetch-handler.js';\n\ntype MaybeOptionalOptions<TOptions> = Record<never, never> extends TOptions\n\t? [options?: TOptions]\n\t: [options: TOptions];\n\nexport function oRPCHandler<T extends Context>(\n\thandler: FetchHandler<T>,\n\t...rest: MaybeOptionalOptions<FriendlyStandardHandleOptions<T>>\n): Handler<'oRPCHandler'> {\n\treturn {\n\t\t_tag: 'oRPCHandler',\n\t\thandle: async ({ request }) => handler.handle(request, ...rest),\n\t};\n}\n"],"mappings":";AASO,SAAS,YACf,YACG,MACsB;AACzB,SAAO;AAAA,IACN,MAAM;AAAA,IACN,QAAQ,OAAO,EAAE,QAAQ,MAAM,QAAQ,OAAO,SAAS,GAAG,IAAI;AAAA,EAC/D;AACD;","names":[]}
|
|
@@ -0,0 +1,23 @@
|
|
|
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 };
|
|
@@ -0,0 +1,23 @@
|
|
|
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 };
|
package/dist/index.cjs
CHANGED
|
@@ -30,10 +30,17 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
-
Logger: () => Logger
|
|
33
|
+
Logger: () => Logger,
|
|
34
|
+
basicHandler: () => basicHandler,
|
|
35
|
+
createFetchHandler: () => createFetchHandler,
|
|
36
|
+
getPort: () => getPort
|
|
34
37
|
});
|
|
35
38
|
module.exports = __toCommonJS(index_exports);
|
|
36
39
|
|
|
40
|
+
// src/http/fetch-handler.ts
|
|
41
|
+
var import_effect2 = require("effect");
|
|
42
|
+
var import_nanoid = require("nanoid");
|
|
43
|
+
|
|
37
44
|
// src/logger.ts
|
|
38
45
|
var import_effect = require("effect");
|
|
39
46
|
var import_pino = __toESM(require("pino"), 1);
|
|
@@ -233,8 +240,76 @@ var Logger;
|
|
|
233
240
|
});
|
|
234
241
|
Logger2.flush = (..._params) => import_effect.Effect.void;
|
|
235
242
|
})(Logger || (Logger = {}));
|
|
243
|
+
|
|
244
|
+
// src/http/fetch-handler.ts
|
|
245
|
+
function basicHandler(path, handler) {
|
|
246
|
+
return {
|
|
247
|
+
_tag: "basicHandler",
|
|
248
|
+
handle: ({ url, request }) => {
|
|
249
|
+
const matched = typeof path === "function" ? path(url) : path === url.pathname;
|
|
250
|
+
if (!matched) return { matched: false, response: void 0 };
|
|
251
|
+
return { matched: true, response: handler(request) };
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
var createFetchHandler = (handlers, opts) => import_effect2.Effect.gen(function* () {
|
|
256
|
+
const runFork = yield* import_effect2.FiberSet.makeRuntimePromise();
|
|
257
|
+
return async (request) => {
|
|
258
|
+
const urlObj = new URL(request.url);
|
|
259
|
+
const requestId = (0, import_nanoid.nanoid)(6);
|
|
260
|
+
const effect = import_effect2.Effect.gen(function* () {
|
|
261
|
+
yield* Logger.info(
|
|
262
|
+
{ request: { pathname: urlObj.pathname } },
|
|
263
|
+
"Request started"
|
|
264
|
+
);
|
|
265
|
+
for (const handler of Array.isArray(handlers) ? handlers : [handlers]) {
|
|
266
|
+
if (!handler) continue;
|
|
267
|
+
const maybeResult = handler.handle({ url: urlObj, request });
|
|
268
|
+
const result = maybeResult instanceof Promise ? yield* import_effect2.Effect.tryPromise(() => maybeResult) : maybeResult;
|
|
269
|
+
if (opts?.debug)
|
|
270
|
+
yield* Logger.debug(
|
|
271
|
+
{ handler: handler._tag, request, result },
|
|
272
|
+
"Processed handler"
|
|
273
|
+
);
|
|
274
|
+
if (!result.matched) continue;
|
|
275
|
+
return result.response;
|
|
276
|
+
}
|
|
277
|
+
return new Response("Not Found", { status: 404 });
|
|
278
|
+
}).pipe(
|
|
279
|
+
import_effect2.Effect.flatMap(
|
|
280
|
+
(response) => response instanceof Promise ? import_effect2.Effect.tryPromise(() => response) : import_effect2.Effect.succeed(response)
|
|
281
|
+
),
|
|
282
|
+
import_effect2.Effect.tap(
|
|
283
|
+
(response) => response.ok ? Logger.info(`Request completed with status ${response.status}`) : Logger.warn(`Request completed with status ${response.status}`)
|
|
284
|
+
),
|
|
285
|
+
import_effect2.Effect.catchAll(
|
|
286
|
+
(error) => import_effect2.Effect.gen(function* () {
|
|
287
|
+
yield* Logger.error(
|
|
288
|
+
{ error },
|
|
289
|
+
"Unhandled exception in HTTP handler"
|
|
290
|
+
);
|
|
291
|
+
return new Response("Internal Server Error", {
|
|
292
|
+
status: 500
|
|
293
|
+
});
|
|
294
|
+
})
|
|
295
|
+
),
|
|
296
|
+
import_effect2.Effect.withSpan("http"),
|
|
297
|
+
import_effect2.Effect.annotateLogs({ requestId }),
|
|
298
|
+
import_effect2.Effect.scoped
|
|
299
|
+
);
|
|
300
|
+
return runFork(effect);
|
|
301
|
+
};
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
// src/port.ts
|
|
305
|
+
var import_effect3 = require("effect");
|
|
306
|
+
var GetPort = __toESM(require("get-port"), 1);
|
|
307
|
+
var getPort = (options) => import_effect3.Effect.tryPromise(() => GetPort.default(options));
|
|
236
308
|
// Annotate the CommonJS export names for ESM import in node:
|
|
237
309
|
0 && (module.exports = {
|
|
238
|
-
Logger
|
|
310
|
+
Logger,
|
|
311
|
+
basicHandler,
|
|
312
|
+
createFetchHandler,
|
|
313
|
+
getPort
|
|
239
314
|
});
|
|
240
315
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/logger.ts"],"sourcesContent":["export { Logger } from './logger.js';\n","import {\n\tConfig,\n\tContext,\n\tEffect,\n\tLogger as EffectLogger,\n\tHashMap,\n\tLayer,\n\tLogLevel,\n\tManagedRuntime,\n\tOption,\n} from 'effect';\nimport pino from 'pino';\n\n// Pino Instance\n\nnamespace LoggerType {\n\texport function fromPino(x: pino.Logger<never, boolean>) {\n\t\treturn {\n\t\t\tinfo: x.info.bind(x),\n\t\t\terror: x.error.bind(x),\n\t\t\twarn: x.warn.bind(x),\n\t\t\tdebug: x.debug.bind(x),\n\t\t\tchild: (...params: Parameters<typeof x.child>) => {\n\t\t\t\treturn fromPino(\n\t\t\t\t\tx.child(...params) as unknown as pino.Logger<never, boolean>,\n\t\t\t\t);\n\t\t\t},\n\t\t\tflush: x.flush.bind(x),\n\t\t\t_pino: x,\n\t\t};\n\t}\n\n\texport type CreateParams = {\n\t\tstream?: pino.DestinationStream;\n\t};\n\n\texport function create(params?: CreateParams) {\n\t\tconst logger = pino(\n\t\t\t{\n\t\t\t\tlevel: 'trace', // Level is managed by Effect, so we set the lowest here\n\t\t\t\tserializers: {\n\t\t\t\t\terror: pino.stdSerializers.errWithCause,\n\t\t\t\t\terr: pino.stdSerializers.errWithCause,\n\t\t\t\t},\n\t\t\t\tformatters: {\n\t\t\t\t\tlevel: (label) => {\n\t\t\t\t\t\treturn { level: label };\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tparams?.stream,\n\t\t);\n\t\treturn fromPino(logger);\n\t}\n\n\texport type Type = ReturnType<typeof LoggerType.create>;\n\n\texport function is(x: object): x is Type {\n\t\treturn '_pino' in x;\n\t}\n}\ntype LoggerType = LoggerType.Type;\n\n// The Gist\n\nconst createInstance = (params?: LoggerType.CreateParams) =>\n\tEffect.gen(function* () {\n\t\tconst isDev = Option.getOrNull(\n\t\t\tyield* Config.boolean('DEV').pipe(Config.option),\n\t\t);\n\t\tconst logFile = Option.getOrNull(\n\t\t\tyield* Config.boolean('LOGGER_LOGFILE').pipe(Config.option),\n\t\t);\n\n\t\treturn LoggerType.create({\n\t\t\t...params,\n\t\t\t...(isDev && {\n\t\t\t\tstream: logFile\n\t\t\t\t\t? pino.transport({\n\t\t\t\t\t\t\ttarget: 'pino/file',\n\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\tdestination: './logs/server.log',\n\t\t\t\t\t\t\t\tmkdir: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t})\n\t\t\t\t\t: pino.transport({\n\t\t\t\t\t\t\ttarget: 'pino-pretty',\n\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\tignore: 'pid,hostname',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t}),\n\t\t});\n\t});\n\n// Pino Context and Effect Logger integration\n\ntype LogParams = [obj: unknown, msg?: string];\nfunction extractParams(...[obj, msg]: LogParams) {\n\tif (typeof obj === 'string') {\n\t\treturn { message: obj };\n\t}\n\treturn { message: msg, attributes: obj as Record<string, any> };\n}\n\n/** A simple helper for calling pino log functions */\nfunction callPino(\n\t{\n\t\tannotations,\n\t\tmessage,\n\t}: Pick<EffectLogger.Logger.Options<unknown>, 'annotations' | 'message'>,\n\tcall: (...params: [obj: unknown, msg?: string]) => void,\n) {\n\tconst entries = HashMap.toEntries(annotations);\n\tif (entries.length > 0) {\n\t\treturn call(Object.fromEntries(entries), String(message));\n\t}\n\n\treturn call(String(message));\n}\n\nnamespace PinoCtx {\n\tconst tag = 'ff-serv/Pino';\n\texport type Type = ReturnType<typeof create>;\n\n\texport function is(obj: unknown): obj is Type {\n\t\treturn (\n\t\t\ttypeof obj === 'object' &&\n\t\t\tobj != null &&\n\t\t\t'_tag' in obj &&\n\t\t\tobj._tag === tag\n\t\t);\n\t}\n\n\texport function create(pino: LoggerType) {\n\t\treturn {\n\t\t\t_tag: tag,\n\t\t\tpino,\n\t\t\teffectLogger: EffectLogger.make(({ logLevel, ...input }) => {\n\t\t\t\tswitch (logLevel) {\n\t\t\t\t\tcase LogLevel.Info:\n\t\t\t\t\t\treturn callPino(input, pino.info);\n\t\t\t\t\tcase LogLevel.Debug:\n\t\t\t\t\t\treturn callPino(input, pino.debug);\n\t\t\t\t\tcase LogLevel.Warning:\n\t\t\t\t\t\treturn callPino(input, pino.warn);\n\t\t\t\t\tcase LogLevel.Error:\n\t\t\t\t\tcase LogLevel.Fatal:\n\t\t\t\t\t\treturn callPino(input, pino.error);\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn callPino(input, pino.info);\n\t\t\t\t}\n\t\t\t}),\n\t\t};\n\t}\n}\ntype PinoCtx = PinoCtx.Type;\n\nclass Pino extends Context.Tag('ff-serv/Pino')<Pino, PinoCtx>() {}\n\n// Facade\n\nexport namespace Logger {\n\texport const layer = (opts?: Parameters<typeof createInstance>[0]) =>\n\t\tEffectLogger.replaceEffect(\n\t\t\tEffectLogger.defaultLogger,\n\t\t\tEffect.gen(function* () {\n\t\t\t\treturn (yield* Pino).effectLogger;\n\t\t\t}),\n\t\t).pipe(\n\t\t\tLayer.provideMerge(\n\t\t\t\tLayer.effect(\n\t\t\t\t\tPino,\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\treturn PinoCtx.create(yield* createInstance(opts));\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\n\t//\n\n\texport const sync = () =>\n\t\tEffect.gen(function* () {\n\t\t\tconst pino = yield* Pino;\n\t\t\tconst runtime = ManagedRuntime.make(\n\t\t\t\tEffectLogger.replace(EffectLogger.defaultLogger, pino.effectLogger),\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tinfo: (...params: Parameters<typeof Logger.info>) =>\n\t\t\t\t\tLogger.info(...params).pipe((e) => runtime.runSync(e)),\n\t\t\t\tdebug: (...params: Parameters<typeof Logger.debug>) =>\n\t\t\t\t\tLogger.debug(...params).pipe((e) => runtime.runSync(e)),\n\t\t\t\twarn: (...params: Parameters<typeof Logger.warn>) =>\n\t\t\t\t\tLogger.warn(...params).pipe((e) => runtime.runSync(e)),\n\t\t\t\terror: (...params: Parameters<typeof Logger.error>) =>\n\t\t\t\t\tLogger.error(...params).pipe((e) => runtime.runSync(e)),\n\t\t\t};\n\t\t});\n\n\t/** @deprecated — will be renamed to `sync` */\n\texport const get = () => Logger.sync();\n\n\texport const replace =\n\t\t(logger: LoggerType | pino.Logger) =>\n\t\t<A, E, R>(e: Effect.Effect<A, E, R>) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst oldPinoCtx = yield* Pino;\n\t\t\t\tconst pino = LoggerType.is(logger)\n\t\t\t\t\t? logger\n\t\t\t\t\t: LoggerType.fromPino(logger);\n\t\t\t\tconst pinoCtx = PinoCtx.create(pino);\n\n\t\t\t\treturn yield* Effect.provide(\n\t\t\t\t\te,\n\t\t\t\t\tLayer.mergeAll(\n\t\t\t\t\t\tEffectLogger.replace(oldPinoCtx.effectLogger, pinoCtx.effectLogger),\n\t\t\t\t\t\tLayer.succeed(Pino, pinoCtx),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t});\n\n\texport const replaceChild =\n\t\t(...params: Parameters<LoggerType['child']>) =>\n\t\t<A, E, R>(e: Effect.Effect<A, E, R>) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst oldPinoCtx = yield* Pino;\n\t\t\t\tconst pino = oldPinoCtx.pino.child(...params);\n\t\t\t\tconst pinoCtx = PinoCtx.create(pino);\n\n\t\t\t\treturn yield* Effect.provide(\n\t\t\t\t\tEffect.provide(\n\t\t\t\t\t\te,\n\t\t\t\t\t\tEffectLogger.replace(oldPinoCtx.effectLogger, pinoCtx.effectLogger),\n\t\t\t\t\t),\n\t\t\t\t\tLayer.succeed(Pino, pinoCtx),\n\t\t\t\t);\n\t\t\t});\n\n\t// --\n\n\texport const info = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logInfo(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const debug = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logDebug(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const warn = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logWarning(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const error = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logError(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\t/** @deprecated */\n\texport const flush = (..._params: Parameters<LoggerType['flush']>) =>\n\t\tEffect.void;\n}\n"],"mappings":"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","names":["LoggerType","pino","PinoCtx","EffectLogger","Logger"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/http/fetch-handler.ts","../src/logger.ts","../src/port.ts"],"sourcesContent":["export { basicHandler, createFetchHandler } from './http/index.js';\nexport { Logger } from './logger.js';\nexport { getPort } from './port.js';","import { Effect, FiberSet } from 'effect';\nimport { nanoid } from 'nanoid';\nimport { Logger } from '../logger.js';\n\nexport type HandlerResult =\n\t| {\n\t\t\tmatched: true;\n\t\t\tresponse: Response | Promise<Response>;\n\t }\n\t| {\n\t\t\tmatched: false;\n\t\t\tresponse: undefined;\n\t };\n\nexport type Handler<T extends string = string> = {\n\t_tag: T;\n\thandle: (opt: {\n\t\turl: URL;\n\t\trequest: Request;\n\t}) => HandlerResult | Promise<HandlerResult>;\n};\n\nexport function basicHandler(\n\tpath: string | ((url: URL) => boolean),\n\thandler: (request: Request) => Response | Promise<Response>,\n): Handler<'basicHandler'> {\n\treturn {\n\t\t_tag: 'basicHandler',\n\t\thandle: ({ url, request }) => {\n\t\t\tconst matched =\n\t\t\t\ttypeof path === 'function' ? path(url) : path === url.pathname;\n\t\t\tif (!matched) return { matched: false, response: undefined };\n\n\t\t\treturn { matched: true, response: handler(request) };\n\t\t},\n\t};\n}\n\nexport const createFetchHandler = (\n\thandlers?: Handler | [Handler, ...Array<Handler>],\n\topts?: {\n\t\tdebug?: boolean;\n\t},\n) =>\n\tEffect.gen(function* () {\n\t\tconst runFork = yield* FiberSet.makeRuntimePromise();\n\t\treturn async (request: Request) => {\n\t\t\tconst urlObj = new URL(request.url);\n\t\t\tconst requestId = nanoid(6);\n\n\t\t\tconst effect = Effect.gen(function* () {\n\t\t\t\tyield* Logger.info(\n\t\t\t\t\t{ request: { pathname: urlObj.pathname } },\n\t\t\t\t\t'Request started',\n\t\t\t\t);\n\n\t\t\t\tfor (const handler of Array.isArray(handlers) ? handlers : [handlers]) {\n\t\t\t\t\tif (!handler) continue;\n\n\t\t\t\t\tconst maybeResult = handler.handle({ url: urlObj, request });\n\t\t\t\t\tconst result =\n\t\t\t\t\t\tmaybeResult instanceof Promise\n\t\t\t\t\t\t\t? yield* Effect.tryPromise(() => maybeResult)\n\t\t\t\t\t\t\t: maybeResult;\n\n\t\t\t\t\tif (opts?.debug)\n\t\t\t\t\t\tyield* Logger.debug(\n\t\t\t\t\t\t\t{ handler: handler._tag, request, result },\n\t\t\t\t\t\t\t'Processed handler',\n\t\t\t\t\t\t);\n\n\t\t\t\t\tif (!result.matched) continue;\n\t\t\t\t\treturn result.response;\n\t\t\t\t}\n\n\t\t\t\treturn new Response('Not Found', { status: 404 });\n\t\t\t}).pipe(\n\t\t\t\tEffect.flatMap((response) =>\n\t\t\t\t\tresponse instanceof Promise\n\t\t\t\t\t\t? Effect.tryPromise(() => response)\n\t\t\t\t\t\t: Effect.succeed(response),\n\t\t\t\t),\n\t\t\t\tEffect.tap((response) =>\n\t\t\t\t\tresponse.ok\n\t\t\t\t\t\t? Logger.info(`Request completed with status ${response.status}`)\n\t\t\t\t\t\t: Logger.warn(`Request completed with status ${response.status}`),\n\t\t\t\t),\n\t\t\t\tEffect.catchAll((error) =>\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\tyield* Logger.error(\n\t\t\t\t\t\t\t{ error },\n\t\t\t\t\t\t\t'Unhandled exception in HTTP handler',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn new Response('Internal Server Error', {\n\t\t\t\t\t\t\tstatus: 500,\n\t\t\t\t\t\t});\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t\tEffect.withSpan('http'),\n\t\t\t\tEffect.annotateLogs({ requestId }),\n\t\t\t\tEffect.scoped,\n\t\t\t);\n\n\t\t\treturn runFork(effect);\n\t\t};\n\t});","import {\n\tConfig,\n\tContext,\n\tEffect,\n\tLogger as EffectLogger,\n\tHashMap,\n\tLayer,\n\tLogLevel,\n\tManagedRuntime,\n\tOption,\n} from 'effect';\nimport pino from 'pino';\n\n// Pino Instance\n\nnamespace LoggerType {\n\texport function fromPino(x: pino.Logger<never, boolean>) {\n\t\treturn {\n\t\t\tinfo: x.info.bind(x),\n\t\t\terror: x.error.bind(x),\n\t\t\twarn: x.warn.bind(x),\n\t\t\tdebug: x.debug.bind(x),\n\t\t\tchild: (...params: Parameters<typeof x.child>) => {\n\t\t\t\treturn fromPino(\n\t\t\t\t\tx.child(...params) as unknown as pino.Logger<never, boolean>,\n\t\t\t\t);\n\t\t\t},\n\t\t\tflush: x.flush.bind(x),\n\t\t\t_pino: x,\n\t\t};\n\t}\n\n\texport type CreateParams = {\n\t\tstream?: pino.DestinationStream;\n\t};\n\n\texport function create(params?: CreateParams) {\n\t\tconst logger = pino(\n\t\t\t{\n\t\t\t\tlevel: 'trace', // Level is managed by Effect, so we set the lowest here\n\t\t\t\tserializers: {\n\t\t\t\t\terror: pino.stdSerializers.errWithCause,\n\t\t\t\t\terr: pino.stdSerializers.errWithCause,\n\t\t\t\t},\n\t\t\t\tformatters: {\n\t\t\t\t\tlevel: (label) => {\n\t\t\t\t\t\treturn { level: label };\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tparams?.stream,\n\t\t);\n\t\treturn fromPino(logger);\n\t}\n\n\texport type Type = ReturnType<typeof LoggerType.create>;\n\n\texport function is(x: object): x is Type {\n\t\treturn '_pino' in x;\n\t}\n}\ntype LoggerType = LoggerType.Type;\n\n// The Gist\n\nconst createInstance = (params?: LoggerType.CreateParams) =>\n\tEffect.gen(function* () {\n\t\tconst isDev = Option.getOrNull(\n\t\t\tyield* Config.boolean('DEV').pipe(Config.option),\n\t\t);\n\t\tconst logFile = Option.getOrNull(\n\t\t\tyield* Config.boolean('LOGGER_LOGFILE').pipe(Config.option),\n\t\t);\n\n\t\treturn LoggerType.create({\n\t\t\t...params,\n\t\t\t...(isDev && {\n\t\t\t\tstream: logFile\n\t\t\t\t\t? pino.transport({\n\t\t\t\t\t\t\ttarget: 'pino/file',\n\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\tdestination: './logs/server.log',\n\t\t\t\t\t\t\t\tmkdir: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t})\n\t\t\t\t\t: pino.transport({\n\t\t\t\t\t\t\ttarget: 'pino-pretty',\n\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\tignore: 'pid,hostname',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t}),\n\t\t});\n\t});\n\n// Pino Context and Effect Logger integration\n\ntype LogParams = [obj: unknown, msg?: string];\nfunction extractParams(...[obj, msg]: LogParams) {\n\tif (typeof obj === 'string') {\n\t\treturn { message: obj };\n\t}\n\treturn { message: msg, attributes: obj as Record<string, any> };\n}\n\n/** A simple helper for calling pino log functions */\nfunction callPino(\n\t{\n\t\tannotations,\n\t\tmessage,\n\t}: Pick<EffectLogger.Logger.Options<unknown>, 'annotations' | 'message'>,\n\tcall: (...params: [obj: unknown, msg?: string]) => void,\n) {\n\tconst entries = HashMap.toEntries(annotations);\n\tif (entries.length > 0) {\n\t\treturn call(Object.fromEntries(entries), String(message));\n\t}\n\n\treturn call(String(message));\n}\n\nnamespace PinoCtx {\n\tconst tag = 'ff-serv/Pino';\n\texport type Type = ReturnType<typeof create>;\n\n\texport function is(obj: unknown): obj is Type {\n\t\treturn (\n\t\t\ttypeof obj === 'object' &&\n\t\t\tobj != null &&\n\t\t\t'_tag' in obj &&\n\t\t\tobj._tag === tag\n\t\t);\n\t}\n\n\texport function create(pino: LoggerType) {\n\t\treturn {\n\t\t\t_tag: tag,\n\t\t\tpino,\n\t\t\teffectLogger: EffectLogger.make(({ logLevel, ...input }) => {\n\t\t\t\tswitch (logLevel) {\n\t\t\t\t\tcase LogLevel.Info:\n\t\t\t\t\t\treturn callPino(input, pino.info);\n\t\t\t\t\tcase LogLevel.Debug:\n\t\t\t\t\t\treturn callPino(input, pino.debug);\n\t\t\t\t\tcase LogLevel.Warning:\n\t\t\t\t\t\treturn callPino(input, pino.warn);\n\t\t\t\t\tcase LogLevel.Error:\n\t\t\t\t\tcase LogLevel.Fatal:\n\t\t\t\t\t\treturn callPino(input, pino.error);\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn callPino(input, pino.info);\n\t\t\t\t}\n\t\t\t}),\n\t\t};\n\t}\n}\ntype PinoCtx = PinoCtx.Type;\n\nclass Pino extends Context.Tag('ff-serv/Pino')<Pino, PinoCtx>() {}\n\n// Facade\n\nexport namespace Logger {\n\texport const layer = (opts?: Parameters<typeof createInstance>[0]) =>\n\t\tEffectLogger.replaceEffect(\n\t\t\tEffectLogger.defaultLogger,\n\t\t\tEffect.gen(function* () {\n\t\t\t\treturn (yield* Pino).effectLogger;\n\t\t\t}),\n\t\t).pipe(\n\t\t\tLayer.provideMerge(\n\t\t\t\tLayer.effect(\n\t\t\t\t\tPino,\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\treturn PinoCtx.create(yield* createInstance(opts));\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\n\t//\n\n\texport const sync = () =>\n\t\tEffect.gen(function* () {\n\t\t\tconst pino = yield* Pino;\n\t\t\tconst runtime = ManagedRuntime.make(\n\t\t\t\tEffectLogger.replace(EffectLogger.defaultLogger, pino.effectLogger),\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tinfo: (...params: Parameters<typeof Logger.info>) =>\n\t\t\t\t\tLogger.info(...params).pipe((e) => runtime.runSync(e)),\n\t\t\t\tdebug: (...params: Parameters<typeof Logger.debug>) =>\n\t\t\t\t\tLogger.debug(...params).pipe((e) => runtime.runSync(e)),\n\t\t\t\twarn: (...params: Parameters<typeof Logger.warn>) =>\n\t\t\t\t\tLogger.warn(...params).pipe((e) => runtime.runSync(e)),\n\t\t\t\terror: (...params: Parameters<typeof Logger.error>) =>\n\t\t\t\t\tLogger.error(...params).pipe((e) => runtime.runSync(e)),\n\t\t\t};\n\t\t});\n\n\t/** @deprecated — will be renamed to `sync` */\n\texport const get = () => Logger.sync();\n\n\texport const replace =\n\t\t(logger: LoggerType | pino.Logger) =>\n\t\t<A, E, R>(e: Effect.Effect<A, E, R>) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst oldPinoCtx = yield* Pino;\n\t\t\t\tconst pino = LoggerType.is(logger)\n\t\t\t\t\t? logger\n\t\t\t\t\t: LoggerType.fromPino(logger);\n\t\t\t\tconst pinoCtx = PinoCtx.create(pino);\n\n\t\t\t\treturn yield* Effect.provide(\n\t\t\t\t\te,\n\t\t\t\t\tLayer.mergeAll(\n\t\t\t\t\t\tEffectLogger.replace(oldPinoCtx.effectLogger, pinoCtx.effectLogger),\n\t\t\t\t\t\tLayer.succeed(Pino, pinoCtx),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t});\n\n\texport const replaceChild =\n\t\t(...params: Parameters<LoggerType['child']>) =>\n\t\t<A, E, R>(e: Effect.Effect<A, E, R>) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst oldPinoCtx = yield* Pino;\n\t\t\t\tconst pino = oldPinoCtx.pino.child(...params);\n\t\t\t\tconst pinoCtx = PinoCtx.create(pino);\n\n\t\t\t\treturn yield* Effect.provide(\n\t\t\t\t\tEffect.provide(\n\t\t\t\t\t\te,\n\t\t\t\t\t\tEffectLogger.replace(oldPinoCtx.effectLogger, pinoCtx.effectLogger),\n\t\t\t\t\t),\n\t\t\t\t\tLayer.succeed(Pino, pinoCtx),\n\t\t\t\t);\n\t\t\t});\n\n\t// --\n\n\texport const info = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logInfo(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const debug = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logDebug(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const warn = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logWarning(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const error = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logError(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\t/** @deprecated */\n\texport const flush = (..._params: Parameters<LoggerType['flush']>) =>\n\t\tEffect.void;\n}\n","import { Effect } from 'effect';\nimport * as GetPort from 'get-port';\n\nexport const getPort = (options?: GetPort.Options) =>\n\tEffect.tryPromise(() => GetPort.default(options));\n"],"mappings":"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","names":["import_effect","LoggerType","pino","PinoCtx","EffectLogger","Logger","import_effect"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
export { b as basicHandler, c as createFetchHandler } from './fetch-handler-BgTGMsrV.cjs';
|
|
1
2
|
import * as effect_ConfigError from 'effect/ConfigError';
|
|
2
3
|
import { Effect, Layer, Context, Logger as Logger$1 } from 'effect';
|
|
3
4
|
import pino from 'pino';
|
|
5
|
+
import * as effect_Cause from 'effect/Cause';
|
|
6
|
+
import * as GetPort from 'get-port';
|
|
7
|
+
import 'effect/Scope';
|
|
4
8
|
|
|
5
9
|
declare namespace LoggerType {
|
|
6
10
|
function fromPino(x: pino.Logger<never, boolean>): {
|
|
@@ -78,4 +82,6 @@ declare namespace Logger {
|
|
|
78
82
|
const flush: (..._params: Parameters<LoggerType["flush"]>) => Effect.Effect<void, never, never>;
|
|
79
83
|
}
|
|
80
84
|
|
|
81
|
-
|
|
85
|
+
declare const getPort: (options?: GetPort.Options) => Effect.Effect<number, effect_Cause.UnknownException, never>;
|
|
86
|
+
|
|
87
|
+
export { Logger, getPort };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
export { b as basicHandler, c as createFetchHandler } from './fetch-handler-BgTGMsrV.js';
|
|
1
2
|
import * as effect_ConfigError from 'effect/ConfigError';
|
|
2
3
|
import { Effect, Layer, Context, Logger as Logger$1 } from 'effect';
|
|
3
4
|
import pino from 'pino';
|
|
5
|
+
import * as effect_Cause from 'effect/Cause';
|
|
6
|
+
import * as GetPort from 'get-port';
|
|
7
|
+
import 'effect/Scope';
|
|
4
8
|
|
|
5
9
|
declare namespace LoggerType {
|
|
6
10
|
function fromPino(x: pino.Logger<never, boolean>): {
|
|
@@ -78,4 +82,6 @@ declare namespace Logger {
|
|
|
78
82
|
const flush: (..._params: Parameters<LoggerType["flush"]>) => Effect.Effect<void, never, never>;
|
|
79
83
|
}
|
|
80
84
|
|
|
81
|
-
|
|
85
|
+
declare const getPort: (options?: GetPort.Options) => Effect.Effect<number, effect_Cause.UnknownException, never>;
|
|
86
|
+
|
|
87
|
+
export { Logger, getPort };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
// src/http/fetch-handler.ts
|
|
2
|
+
import { Effect as Effect2, FiberSet } from "effect";
|
|
3
|
+
import { nanoid } from "nanoid";
|
|
4
|
+
|
|
1
5
|
// src/logger.ts
|
|
2
6
|
import {
|
|
3
7
|
Config,
|
|
@@ -207,7 +211,75 @@ var Logger;
|
|
|
207
211
|
});
|
|
208
212
|
Logger2.flush = (..._params) => Effect.void;
|
|
209
213
|
})(Logger || (Logger = {}));
|
|
214
|
+
|
|
215
|
+
// src/http/fetch-handler.ts
|
|
216
|
+
function basicHandler(path, handler) {
|
|
217
|
+
return {
|
|
218
|
+
_tag: "basicHandler",
|
|
219
|
+
handle: ({ url, request }) => {
|
|
220
|
+
const matched = typeof path === "function" ? path(url) : path === url.pathname;
|
|
221
|
+
if (!matched) return { matched: false, response: void 0 };
|
|
222
|
+
return { matched: true, response: handler(request) };
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
var createFetchHandler = (handlers, opts) => Effect2.gen(function* () {
|
|
227
|
+
const runFork = yield* FiberSet.makeRuntimePromise();
|
|
228
|
+
return async (request) => {
|
|
229
|
+
const urlObj = new URL(request.url);
|
|
230
|
+
const requestId = nanoid(6);
|
|
231
|
+
const effect = Effect2.gen(function* () {
|
|
232
|
+
yield* Logger.info(
|
|
233
|
+
{ request: { pathname: urlObj.pathname } },
|
|
234
|
+
"Request started"
|
|
235
|
+
);
|
|
236
|
+
for (const handler of Array.isArray(handlers) ? handlers : [handlers]) {
|
|
237
|
+
if (!handler) continue;
|
|
238
|
+
const maybeResult = handler.handle({ url: urlObj, request });
|
|
239
|
+
const result = maybeResult instanceof Promise ? yield* Effect2.tryPromise(() => maybeResult) : maybeResult;
|
|
240
|
+
if (opts?.debug)
|
|
241
|
+
yield* Logger.debug(
|
|
242
|
+
{ handler: handler._tag, request, result },
|
|
243
|
+
"Processed handler"
|
|
244
|
+
);
|
|
245
|
+
if (!result.matched) continue;
|
|
246
|
+
return result.response;
|
|
247
|
+
}
|
|
248
|
+
return new Response("Not Found", { status: 404 });
|
|
249
|
+
}).pipe(
|
|
250
|
+
Effect2.flatMap(
|
|
251
|
+
(response) => response instanceof Promise ? Effect2.tryPromise(() => response) : Effect2.succeed(response)
|
|
252
|
+
),
|
|
253
|
+
Effect2.tap(
|
|
254
|
+
(response) => response.ok ? Logger.info(`Request completed with status ${response.status}`) : Logger.warn(`Request completed with status ${response.status}`)
|
|
255
|
+
),
|
|
256
|
+
Effect2.catchAll(
|
|
257
|
+
(error) => Effect2.gen(function* () {
|
|
258
|
+
yield* Logger.error(
|
|
259
|
+
{ error },
|
|
260
|
+
"Unhandled exception in HTTP handler"
|
|
261
|
+
);
|
|
262
|
+
return new Response("Internal Server Error", {
|
|
263
|
+
status: 500
|
|
264
|
+
});
|
|
265
|
+
})
|
|
266
|
+
),
|
|
267
|
+
Effect2.withSpan("http"),
|
|
268
|
+
Effect2.annotateLogs({ requestId }),
|
|
269
|
+
Effect2.scoped
|
|
270
|
+
);
|
|
271
|
+
return runFork(effect);
|
|
272
|
+
};
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
// src/port.ts
|
|
276
|
+
import { Effect as Effect3 } from "effect";
|
|
277
|
+
import * as GetPort from "get-port";
|
|
278
|
+
var getPort = (options) => Effect3.tryPromise(() => GetPort.default(options));
|
|
210
279
|
export {
|
|
211
|
-
Logger
|
|
280
|
+
Logger,
|
|
281
|
+
basicHandler,
|
|
282
|
+
createFetchHandler,
|
|
283
|
+
getPort
|
|
212
284
|
};
|
|
213
285
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/logger.ts"],"sourcesContent":["import {\n\tConfig,\n\tContext,\n\tEffect,\n\tLogger as EffectLogger,\n\tHashMap,\n\tLayer,\n\tLogLevel,\n\tManagedRuntime,\n\tOption,\n} from 'effect';\nimport pino from 'pino';\n\n// Pino Instance\n\nnamespace LoggerType {\n\texport function fromPino(x: pino.Logger<never, boolean>) {\n\t\treturn {\n\t\t\tinfo: x.info.bind(x),\n\t\t\terror: x.error.bind(x),\n\t\t\twarn: x.warn.bind(x),\n\t\t\tdebug: x.debug.bind(x),\n\t\t\tchild: (...params: Parameters<typeof x.child>) => {\n\t\t\t\treturn fromPino(\n\t\t\t\t\tx.child(...params) as unknown as pino.Logger<never, boolean>,\n\t\t\t\t);\n\t\t\t},\n\t\t\tflush: x.flush.bind(x),\n\t\t\t_pino: x,\n\t\t};\n\t}\n\n\texport type CreateParams = {\n\t\tstream?: pino.DestinationStream;\n\t};\n\n\texport function create(params?: CreateParams) {\n\t\tconst logger = pino(\n\t\t\t{\n\t\t\t\tlevel: 'trace', // Level is managed by Effect, so we set the lowest here\n\t\t\t\tserializers: {\n\t\t\t\t\terror: pino.stdSerializers.errWithCause,\n\t\t\t\t\terr: pino.stdSerializers.errWithCause,\n\t\t\t\t},\n\t\t\t\tformatters: {\n\t\t\t\t\tlevel: (label) => {\n\t\t\t\t\t\treturn { level: label };\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tparams?.stream,\n\t\t);\n\t\treturn fromPino(logger);\n\t}\n\n\texport type Type = ReturnType<typeof LoggerType.create>;\n\n\texport function is(x: object): x is Type {\n\t\treturn '_pino' in x;\n\t}\n}\ntype LoggerType = LoggerType.Type;\n\n// The Gist\n\nconst createInstance = (params?: LoggerType.CreateParams) =>\n\tEffect.gen(function* () {\n\t\tconst isDev = Option.getOrNull(\n\t\t\tyield* Config.boolean('DEV').pipe(Config.option),\n\t\t);\n\t\tconst logFile = Option.getOrNull(\n\t\t\tyield* Config.boolean('LOGGER_LOGFILE').pipe(Config.option),\n\t\t);\n\n\t\treturn LoggerType.create({\n\t\t\t...params,\n\t\t\t...(isDev && {\n\t\t\t\tstream: logFile\n\t\t\t\t\t? pino.transport({\n\t\t\t\t\t\t\ttarget: 'pino/file',\n\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\tdestination: './logs/server.log',\n\t\t\t\t\t\t\t\tmkdir: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t})\n\t\t\t\t\t: pino.transport({\n\t\t\t\t\t\t\ttarget: 'pino-pretty',\n\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\tignore: 'pid,hostname',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t}),\n\t\t});\n\t});\n\n// Pino Context and Effect Logger integration\n\ntype LogParams = [obj: unknown, msg?: string];\nfunction extractParams(...[obj, msg]: LogParams) {\n\tif (typeof obj === 'string') {\n\t\treturn { message: obj };\n\t}\n\treturn { message: msg, attributes: obj as Record<string, any> };\n}\n\n/** A simple helper for calling pino log functions */\nfunction callPino(\n\t{\n\t\tannotations,\n\t\tmessage,\n\t}: Pick<EffectLogger.Logger.Options<unknown>, 'annotations' | 'message'>,\n\tcall: (...params: [obj: unknown, msg?: string]) => void,\n) {\n\tconst entries = HashMap.toEntries(annotations);\n\tif (entries.length > 0) {\n\t\treturn call(Object.fromEntries(entries), String(message));\n\t}\n\n\treturn call(String(message));\n}\n\nnamespace PinoCtx {\n\tconst tag = 'ff-serv/Pino';\n\texport type Type = ReturnType<typeof create>;\n\n\texport function is(obj: unknown): obj is Type {\n\t\treturn (\n\t\t\ttypeof obj === 'object' &&\n\t\t\tobj != null &&\n\t\t\t'_tag' in obj &&\n\t\t\tobj._tag === tag\n\t\t);\n\t}\n\n\texport function create(pino: LoggerType) {\n\t\treturn {\n\t\t\t_tag: tag,\n\t\t\tpino,\n\t\t\teffectLogger: EffectLogger.make(({ logLevel, ...input }) => {\n\t\t\t\tswitch (logLevel) {\n\t\t\t\t\tcase LogLevel.Info:\n\t\t\t\t\t\treturn callPino(input, pino.info);\n\t\t\t\t\tcase LogLevel.Debug:\n\t\t\t\t\t\treturn callPino(input, pino.debug);\n\t\t\t\t\tcase LogLevel.Warning:\n\t\t\t\t\t\treturn callPino(input, pino.warn);\n\t\t\t\t\tcase LogLevel.Error:\n\t\t\t\t\tcase LogLevel.Fatal:\n\t\t\t\t\t\treturn callPino(input, pino.error);\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn callPino(input, pino.info);\n\t\t\t\t}\n\t\t\t}),\n\t\t};\n\t}\n}\ntype PinoCtx = PinoCtx.Type;\n\nclass Pino extends Context.Tag('ff-serv/Pino')<Pino, PinoCtx>() {}\n\n// Facade\n\nexport namespace Logger {\n\texport const layer = (opts?: Parameters<typeof createInstance>[0]) =>\n\t\tEffectLogger.replaceEffect(\n\t\t\tEffectLogger.defaultLogger,\n\t\t\tEffect.gen(function* () {\n\t\t\t\treturn (yield* Pino).effectLogger;\n\t\t\t}),\n\t\t).pipe(\n\t\t\tLayer.provideMerge(\n\t\t\t\tLayer.effect(\n\t\t\t\t\tPino,\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\treturn PinoCtx.create(yield* createInstance(opts));\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\n\t//\n\n\texport const sync = () =>\n\t\tEffect.gen(function* () {\n\t\t\tconst pino = yield* Pino;\n\t\t\tconst runtime = ManagedRuntime.make(\n\t\t\t\tEffectLogger.replace(EffectLogger.defaultLogger, pino.effectLogger),\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tinfo: (...params: Parameters<typeof Logger.info>) =>\n\t\t\t\t\tLogger.info(...params).pipe((e) => runtime.runSync(e)),\n\t\t\t\tdebug: (...params: Parameters<typeof Logger.debug>) =>\n\t\t\t\t\tLogger.debug(...params).pipe((e) => runtime.runSync(e)),\n\t\t\t\twarn: (...params: Parameters<typeof Logger.warn>) =>\n\t\t\t\t\tLogger.warn(...params).pipe((e) => runtime.runSync(e)),\n\t\t\t\terror: (...params: Parameters<typeof Logger.error>) =>\n\t\t\t\t\tLogger.error(...params).pipe((e) => runtime.runSync(e)),\n\t\t\t};\n\t\t});\n\n\t/** @deprecated — will be renamed to `sync` */\n\texport const get = () => Logger.sync();\n\n\texport const replace =\n\t\t(logger: LoggerType | pino.Logger) =>\n\t\t<A, E, R>(e: Effect.Effect<A, E, R>) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst oldPinoCtx = yield* Pino;\n\t\t\t\tconst pino = LoggerType.is(logger)\n\t\t\t\t\t? logger\n\t\t\t\t\t: LoggerType.fromPino(logger);\n\t\t\t\tconst pinoCtx = PinoCtx.create(pino);\n\n\t\t\t\treturn yield* Effect.provide(\n\t\t\t\t\te,\n\t\t\t\t\tLayer.mergeAll(\n\t\t\t\t\t\tEffectLogger.replace(oldPinoCtx.effectLogger, pinoCtx.effectLogger),\n\t\t\t\t\t\tLayer.succeed(Pino, pinoCtx),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t});\n\n\texport const replaceChild =\n\t\t(...params: Parameters<LoggerType['child']>) =>\n\t\t<A, E, R>(e: Effect.Effect<A, E, R>) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst oldPinoCtx = yield* Pino;\n\t\t\t\tconst pino = oldPinoCtx.pino.child(...params);\n\t\t\t\tconst pinoCtx = PinoCtx.create(pino);\n\n\t\t\t\treturn yield* Effect.provide(\n\t\t\t\t\tEffect.provide(\n\t\t\t\t\t\te,\n\t\t\t\t\t\tEffectLogger.replace(oldPinoCtx.effectLogger, pinoCtx.effectLogger),\n\t\t\t\t\t),\n\t\t\t\t\tLayer.succeed(Pino, pinoCtx),\n\t\t\t\t);\n\t\t\t});\n\n\t// --\n\n\texport const info = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logInfo(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const debug = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logDebug(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const warn = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logWarning(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const error = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logError(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\t/** @deprecated */\n\texport const flush = (..._params: Parameters<LoggerType['flush']>) =>\n\t\tEffect.void;\n}\n"],"mappings":"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","names":["LoggerType","PinoCtx","pino","Logger"]}
|
|
1
|
+
{"version":3,"sources":["../src/http/fetch-handler.ts","../src/logger.ts","../src/port.ts"],"sourcesContent":["import { Effect, FiberSet } from 'effect';\nimport { nanoid } from 'nanoid';\nimport { Logger } from '../logger.js';\n\nexport type HandlerResult =\n\t| {\n\t\t\tmatched: true;\n\t\t\tresponse: Response | Promise<Response>;\n\t }\n\t| {\n\t\t\tmatched: false;\n\t\t\tresponse: undefined;\n\t };\n\nexport type Handler<T extends string = string> = {\n\t_tag: T;\n\thandle: (opt: {\n\t\turl: URL;\n\t\trequest: Request;\n\t}) => HandlerResult | Promise<HandlerResult>;\n};\n\nexport function basicHandler(\n\tpath: string | ((url: URL) => boolean),\n\thandler: (request: Request) => Response | Promise<Response>,\n): Handler<'basicHandler'> {\n\treturn {\n\t\t_tag: 'basicHandler',\n\t\thandle: ({ url, request }) => {\n\t\t\tconst matched =\n\t\t\t\ttypeof path === 'function' ? path(url) : path === url.pathname;\n\t\t\tif (!matched) return { matched: false, response: undefined };\n\n\t\t\treturn { matched: true, response: handler(request) };\n\t\t},\n\t};\n}\n\nexport const createFetchHandler = (\n\thandlers?: Handler | [Handler, ...Array<Handler>],\n\topts?: {\n\t\tdebug?: boolean;\n\t},\n) =>\n\tEffect.gen(function* () {\n\t\tconst runFork = yield* FiberSet.makeRuntimePromise();\n\t\treturn async (request: Request) => {\n\t\t\tconst urlObj = new URL(request.url);\n\t\t\tconst requestId = nanoid(6);\n\n\t\t\tconst effect = Effect.gen(function* () {\n\t\t\t\tyield* Logger.info(\n\t\t\t\t\t{ request: { pathname: urlObj.pathname } },\n\t\t\t\t\t'Request started',\n\t\t\t\t);\n\n\t\t\t\tfor (const handler of Array.isArray(handlers) ? handlers : [handlers]) {\n\t\t\t\t\tif (!handler) continue;\n\n\t\t\t\t\tconst maybeResult = handler.handle({ url: urlObj, request });\n\t\t\t\t\tconst result =\n\t\t\t\t\t\tmaybeResult instanceof Promise\n\t\t\t\t\t\t\t? yield* Effect.tryPromise(() => maybeResult)\n\t\t\t\t\t\t\t: maybeResult;\n\n\t\t\t\t\tif (opts?.debug)\n\t\t\t\t\t\tyield* Logger.debug(\n\t\t\t\t\t\t\t{ handler: handler._tag, request, result },\n\t\t\t\t\t\t\t'Processed handler',\n\t\t\t\t\t\t);\n\n\t\t\t\t\tif (!result.matched) continue;\n\t\t\t\t\treturn result.response;\n\t\t\t\t}\n\n\t\t\t\treturn new Response('Not Found', { status: 404 });\n\t\t\t}).pipe(\n\t\t\t\tEffect.flatMap((response) =>\n\t\t\t\t\tresponse instanceof Promise\n\t\t\t\t\t\t? Effect.tryPromise(() => response)\n\t\t\t\t\t\t: Effect.succeed(response),\n\t\t\t\t),\n\t\t\t\tEffect.tap((response) =>\n\t\t\t\t\tresponse.ok\n\t\t\t\t\t\t? Logger.info(`Request completed with status ${response.status}`)\n\t\t\t\t\t\t: Logger.warn(`Request completed with status ${response.status}`),\n\t\t\t\t),\n\t\t\t\tEffect.catchAll((error) =>\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\tyield* Logger.error(\n\t\t\t\t\t\t\t{ error },\n\t\t\t\t\t\t\t'Unhandled exception in HTTP handler',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn new Response('Internal Server Error', {\n\t\t\t\t\t\t\tstatus: 500,\n\t\t\t\t\t\t});\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t\tEffect.withSpan('http'),\n\t\t\t\tEffect.annotateLogs({ requestId }),\n\t\t\t\tEffect.scoped,\n\t\t\t);\n\n\t\t\treturn runFork(effect);\n\t\t};\n\t});","import {\n\tConfig,\n\tContext,\n\tEffect,\n\tLogger as EffectLogger,\n\tHashMap,\n\tLayer,\n\tLogLevel,\n\tManagedRuntime,\n\tOption,\n} from 'effect';\nimport pino from 'pino';\n\n// Pino Instance\n\nnamespace LoggerType {\n\texport function fromPino(x: pino.Logger<never, boolean>) {\n\t\treturn {\n\t\t\tinfo: x.info.bind(x),\n\t\t\terror: x.error.bind(x),\n\t\t\twarn: x.warn.bind(x),\n\t\t\tdebug: x.debug.bind(x),\n\t\t\tchild: (...params: Parameters<typeof x.child>) => {\n\t\t\t\treturn fromPino(\n\t\t\t\t\tx.child(...params) as unknown as pino.Logger<never, boolean>,\n\t\t\t\t);\n\t\t\t},\n\t\t\tflush: x.flush.bind(x),\n\t\t\t_pino: x,\n\t\t};\n\t}\n\n\texport type CreateParams = {\n\t\tstream?: pino.DestinationStream;\n\t};\n\n\texport function create(params?: CreateParams) {\n\t\tconst logger = pino(\n\t\t\t{\n\t\t\t\tlevel: 'trace', // Level is managed by Effect, so we set the lowest here\n\t\t\t\tserializers: {\n\t\t\t\t\terror: pino.stdSerializers.errWithCause,\n\t\t\t\t\terr: pino.stdSerializers.errWithCause,\n\t\t\t\t},\n\t\t\t\tformatters: {\n\t\t\t\t\tlevel: (label) => {\n\t\t\t\t\t\treturn { level: label };\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tparams?.stream,\n\t\t);\n\t\treturn fromPino(logger);\n\t}\n\n\texport type Type = ReturnType<typeof LoggerType.create>;\n\n\texport function is(x: object): x is Type {\n\t\treturn '_pino' in x;\n\t}\n}\ntype LoggerType = LoggerType.Type;\n\n// The Gist\n\nconst createInstance = (params?: LoggerType.CreateParams) =>\n\tEffect.gen(function* () {\n\t\tconst isDev = Option.getOrNull(\n\t\t\tyield* Config.boolean('DEV').pipe(Config.option),\n\t\t);\n\t\tconst logFile = Option.getOrNull(\n\t\t\tyield* Config.boolean('LOGGER_LOGFILE').pipe(Config.option),\n\t\t);\n\n\t\treturn LoggerType.create({\n\t\t\t...params,\n\t\t\t...(isDev && {\n\t\t\t\tstream: logFile\n\t\t\t\t\t? pino.transport({\n\t\t\t\t\t\t\ttarget: 'pino/file',\n\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\tdestination: './logs/server.log',\n\t\t\t\t\t\t\t\tmkdir: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t})\n\t\t\t\t\t: pino.transport({\n\t\t\t\t\t\t\ttarget: 'pino-pretty',\n\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\tignore: 'pid,hostname',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t}),\n\t\t});\n\t});\n\n// Pino Context and Effect Logger integration\n\ntype LogParams = [obj: unknown, msg?: string];\nfunction extractParams(...[obj, msg]: LogParams) {\n\tif (typeof obj === 'string') {\n\t\treturn { message: obj };\n\t}\n\treturn { message: msg, attributes: obj as Record<string, any> };\n}\n\n/** A simple helper for calling pino log functions */\nfunction callPino(\n\t{\n\t\tannotations,\n\t\tmessage,\n\t}: Pick<EffectLogger.Logger.Options<unknown>, 'annotations' | 'message'>,\n\tcall: (...params: [obj: unknown, msg?: string]) => void,\n) {\n\tconst entries = HashMap.toEntries(annotations);\n\tif (entries.length > 0) {\n\t\treturn call(Object.fromEntries(entries), String(message));\n\t}\n\n\treturn call(String(message));\n}\n\nnamespace PinoCtx {\n\tconst tag = 'ff-serv/Pino';\n\texport type Type = ReturnType<typeof create>;\n\n\texport function is(obj: unknown): obj is Type {\n\t\treturn (\n\t\t\ttypeof obj === 'object' &&\n\t\t\tobj != null &&\n\t\t\t'_tag' in obj &&\n\t\t\tobj._tag === tag\n\t\t);\n\t}\n\n\texport function create(pino: LoggerType) {\n\t\treturn {\n\t\t\t_tag: tag,\n\t\t\tpino,\n\t\t\teffectLogger: EffectLogger.make(({ logLevel, ...input }) => {\n\t\t\t\tswitch (logLevel) {\n\t\t\t\t\tcase LogLevel.Info:\n\t\t\t\t\t\treturn callPino(input, pino.info);\n\t\t\t\t\tcase LogLevel.Debug:\n\t\t\t\t\t\treturn callPino(input, pino.debug);\n\t\t\t\t\tcase LogLevel.Warning:\n\t\t\t\t\t\treturn callPino(input, pino.warn);\n\t\t\t\t\tcase LogLevel.Error:\n\t\t\t\t\tcase LogLevel.Fatal:\n\t\t\t\t\t\treturn callPino(input, pino.error);\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn callPino(input, pino.info);\n\t\t\t\t}\n\t\t\t}),\n\t\t};\n\t}\n}\ntype PinoCtx = PinoCtx.Type;\n\nclass Pino extends Context.Tag('ff-serv/Pino')<Pino, PinoCtx>() {}\n\n// Facade\n\nexport namespace Logger {\n\texport const layer = (opts?: Parameters<typeof createInstance>[0]) =>\n\t\tEffectLogger.replaceEffect(\n\t\t\tEffectLogger.defaultLogger,\n\t\t\tEffect.gen(function* () {\n\t\t\t\treturn (yield* Pino).effectLogger;\n\t\t\t}),\n\t\t).pipe(\n\t\t\tLayer.provideMerge(\n\t\t\t\tLayer.effect(\n\t\t\t\t\tPino,\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\treturn PinoCtx.create(yield* createInstance(opts));\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\n\t//\n\n\texport const sync = () =>\n\t\tEffect.gen(function* () {\n\t\t\tconst pino = yield* Pino;\n\t\t\tconst runtime = ManagedRuntime.make(\n\t\t\t\tEffectLogger.replace(EffectLogger.defaultLogger, pino.effectLogger),\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tinfo: (...params: Parameters<typeof Logger.info>) =>\n\t\t\t\t\tLogger.info(...params).pipe((e) => runtime.runSync(e)),\n\t\t\t\tdebug: (...params: Parameters<typeof Logger.debug>) =>\n\t\t\t\t\tLogger.debug(...params).pipe((e) => runtime.runSync(e)),\n\t\t\t\twarn: (...params: Parameters<typeof Logger.warn>) =>\n\t\t\t\t\tLogger.warn(...params).pipe((e) => runtime.runSync(e)),\n\t\t\t\terror: (...params: Parameters<typeof Logger.error>) =>\n\t\t\t\t\tLogger.error(...params).pipe((e) => runtime.runSync(e)),\n\t\t\t};\n\t\t});\n\n\t/** @deprecated — will be renamed to `sync` */\n\texport const get = () => Logger.sync();\n\n\texport const replace =\n\t\t(logger: LoggerType | pino.Logger) =>\n\t\t<A, E, R>(e: Effect.Effect<A, E, R>) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst oldPinoCtx = yield* Pino;\n\t\t\t\tconst pino = LoggerType.is(logger)\n\t\t\t\t\t? logger\n\t\t\t\t\t: LoggerType.fromPino(logger);\n\t\t\t\tconst pinoCtx = PinoCtx.create(pino);\n\n\t\t\t\treturn yield* Effect.provide(\n\t\t\t\t\te,\n\t\t\t\t\tLayer.mergeAll(\n\t\t\t\t\t\tEffectLogger.replace(oldPinoCtx.effectLogger, pinoCtx.effectLogger),\n\t\t\t\t\t\tLayer.succeed(Pino, pinoCtx),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t});\n\n\texport const replaceChild =\n\t\t(...params: Parameters<LoggerType['child']>) =>\n\t\t<A, E, R>(e: Effect.Effect<A, E, R>) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst oldPinoCtx = yield* Pino;\n\t\t\t\tconst pino = oldPinoCtx.pino.child(...params);\n\t\t\t\tconst pinoCtx = PinoCtx.create(pino);\n\n\t\t\t\treturn yield* Effect.provide(\n\t\t\t\t\tEffect.provide(\n\t\t\t\t\t\te,\n\t\t\t\t\t\tEffectLogger.replace(oldPinoCtx.effectLogger, pinoCtx.effectLogger),\n\t\t\t\t\t),\n\t\t\t\t\tLayer.succeed(Pino, pinoCtx),\n\t\t\t\t);\n\t\t\t});\n\n\t// --\n\n\texport const info = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logInfo(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const debug = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logDebug(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const warn = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logWarning(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const error = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logError(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\t/** @deprecated */\n\texport const flush = (..._params: Parameters<LoggerType['flush']>) =>\n\t\tEffect.void;\n}\n","import { Effect } from 'effect';\nimport * as GetPort from 'get-port';\n\nexport const getPort = (options?: GetPort.Options) =>\n\tEffect.tryPromise(() => GetPort.default(options));\n"],"mappings":"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","names":["Effect","LoggerType","PinoCtx","pino","Logger","Effect","Effect"]}
|
package/package.json
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ff-serv",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
8
8
|
"import": "./dist/index.js",
|
|
9
9
|
"require": "./dist/index.cjs"
|
|
10
|
+
},
|
|
11
|
+
"./orpc": {
|
|
12
|
+
"types": "./dist/exports/orpc.d.ts",
|
|
13
|
+
"import": "./dist/exports/orpc.js",
|
|
14
|
+
"require": "./dist/exports/orpc.cjs"
|
|
10
15
|
}
|
|
11
16
|
},
|
|
12
17
|
"files": [
|
|
@@ -24,9 +29,11 @@
|
|
|
24
29
|
"typescript": "^5.9.3"
|
|
25
30
|
},
|
|
26
31
|
"peerDependencies": {
|
|
27
|
-
"effect": "^3
|
|
32
|
+
"effect": "^3",
|
|
28
33
|
"pino": "^9",
|
|
29
|
-
"@effect/opentelemetry": "^0.60.0"
|
|
34
|
+
"@effect/opentelemetry": "^0.60.0",
|
|
35
|
+
"get-port": "^7",
|
|
36
|
+
"@orpc/server": "^1"
|
|
30
37
|
},
|
|
31
38
|
"publishConfig": {
|
|
32
39
|
"access": "public"
|
|
@@ -43,5 +50,9 @@
|
|
|
43
50
|
"effect",
|
|
44
51
|
"server",
|
|
45
52
|
"service"
|
|
46
|
-
]
|
|
47
|
-
|
|
53
|
+
],
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@effect/platform": "^0.94.1",
|
|
56
|
+
"nanoid": "^5.1.6"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { oRPCHandler } from '../http/orpc.js';
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { Effect, FiberSet } from 'effect';
|
|
2
|
+
import { nanoid } from 'nanoid';
|
|
3
|
+
import { Logger } from '../logger.js';
|
|
4
|
+
|
|
5
|
+
export type HandlerResult =
|
|
6
|
+
| {
|
|
7
|
+
matched: true;
|
|
8
|
+
response: Response | Promise<Response>;
|
|
9
|
+
}
|
|
10
|
+
| {
|
|
11
|
+
matched: false;
|
|
12
|
+
response: undefined;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type Handler<T extends string = string> = {
|
|
16
|
+
_tag: T;
|
|
17
|
+
handle: (opt: {
|
|
18
|
+
url: URL;
|
|
19
|
+
request: Request;
|
|
20
|
+
}) => HandlerResult | Promise<HandlerResult>;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export function basicHandler(
|
|
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 };
|
|
33
|
+
|
|
34
|
+
return { matched: true, response: handler(request) };
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const createFetchHandler = (
|
|
40
|
+
handlers?: Handler | [Handler, ...Array<Handler>],
|
|
41
|
+
opts?: {
|
|
42
|
+
debug?: boolean;
|
|
43
|
+
},
|
|
44
|
+
) =>
|
|
45
|
+
Effect.gen(function* () {
|
|
46
|
+
const runFork = yield* FiberSet.makeRuntimePromise();
|
|
47
|
+
return async (request: Request) => {
|
|
48
|
+
const urlObj = new URL(request.url);
|
|
49
|
+
const requestId = nanoid(6);
|
|
50
|
+
|
|
51
|
+
const effect = Effect.gen(function* () {
|
|
52
|
+
yield* Logger.info(
|
|
53
|
+
{ request: { pathname: urlObj.pathname } },
|
|
54
|
+
'Request started',
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
for (const handler of Array.isArray(handlers) ? handlers : [handlers]) {
|
|
58
|
+
if (!handler) continue;
|
|
59
|
+
|
|
60
|
+
const maybeResult = handler.handle({ url: urlObj, request });
|
|
61
|
+
const result =
|
|
62
|
+
maybeResult instanceof Promise
|
|
63
|
+
? yield* Effect.tryPromise(() => maybeResult)
|
|
64
|
+
: maybeResult;
|
|
65
|
+
|
|
66
|
+
if (opts?.debug)
|
|
67
|
+
yield* Logger.debug(
|
|
68
|
+
{ handler: handler._tag, request, result },
|
|
69
|
+
'Processed handler',
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
if (!result.matched) continue;
|
|
73
|
+
return result.response;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return new Response('Not Found', { status: 404 });
|
|
77
|
+
}).pipe(
|
|
78
|
+
Effect.flatMap((response) =>
|
|
79
|
+
response instanceof Promise
|
|
80
|
+
? Effect.tryPromise(() => response)
|
|
81
|
+
: Effect.succeed(response),
|
|
82
|
+
),
|
|
83
|
+
Effect.tap((response) =>
|
|
84
|
+
response.ok
|
|
85
|
+
? Logger.info(`Request completed with status ${response.status}`)
|
|
86
|
+
: Logger.warn(`Request completed with status ${response.status}`),
|
|
87
|
+
),
|
|
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
|
+
Effect.withSpan('http'),
|
|
100
|
+
Effect.annotateLogs({ requestId }),
|
|
101
|
+
Effect.scoped,
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
return runFork(effect);
|
|
105
|
+
};
|
|
106
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './fetch-handler.js';
|
package/src/http/orpc.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Context } from '@orpc/server';
|
|
2
|
+
import type { FetchHandler } from '@orpc/server/fetch';
|
|
3
|
+
import type { FriendlyStandardHandleOptions } from '@orpc/server/standard';
|
|
4
|
+
import type { Handler } from './fetch-handler.js';
|
|
5
|
+
|
|
6
|
+
type MaybeOptionalOptions<TOptions> = Record<never, never> extends TOptions
|
|
7
|
+
? [options?: TOptions]
|
|
8
|
+
: [options: TOptions];
|
|
9
|
+
|
|
10
|
+
export function oRPCHandler<T extends Context>(
|
|
11
|
+
handler: FetchHandler<T>,
|
|
12
|
+
...rest: MaybeOptionalOptions<FriendlyStandardHandleOptions<T>>
|
|
13
|
+
): Handler<'oRPCHandler'> {
|
|
14
|
+
return {
|
|
15
|
+
_tag: 'oRPCHandler',
|
|
16
|
+
handle: async ({ request }) => handler.handle(request, ...rest),
|
|
17
|
+
};
|
|
18
|
+
}
|
package/src/index.ts
CHANGED