@ayepi/log 0.1.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.
@@ -0,0 +1,37 @@
1
+ import { middleware } from "@ayepi/core";
2
+ //#region src/middleware.ts
3
+ /**
4
+ * # @ayepi/log/middleware
5
+ *
6
+ * The frontend-safe **def** for a trace-context middleware. It declares a
7
+ * no-context middleware (it establishes the log context for the downstream chain +
8
+ * handler, but contributes nothing to the payload), with no `node:async_hooks` —
9
+ * that lives in the impl bound via [`logMiddleware.server`](../server) from
10
+ * `@ayepi/log/server`.
11
+ *
12
+ * ```ts
13
+ * // shared.ts (frontend-safe)
14
+ * import { logMiddleware } from '@ayepi/log/middleware';
15
+ * const trace = logMiddleware({ requires: [auth] });
16
+ * spec({ endpoints: { ...trace.group({ … }) } });
17
+ *
18
+ * // server.ts
19
+ * import { logMiddleware } from '@ayepi/log/server';
20
+ * implement(api).middleware(logMiddleware.server(trace, {
21
+ * context: (ctx, req) => ({ userId: ctx.user.id, path: new URL(req.url).pathname }),
22
+ * }));
23
+ * ```
24
+ *
25
+ * @module
26
+ */
27
+ /**
28
+ * Create a trace-context middleware **def** — a no-context, frontend-safe contract.
29
+ * Bind the context builder with [`logMiddleware.server(def, { context })`](../server).
30
+ *
31
+ * @typeParam R - inferred from `requires`.
32
+ */
33
+ function logMiddleware(opts) {
34
+ return middleware(opts?.name ?? "log", { requires: opts?.requires ?? [] });
35
+ }
36
+ //#endregion
37
+ export { logMiddleware };
@@ -0,0 +1,40 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_internal = require("./internal.cjs");
3
+ const require_middleware = require("./middleware.cjs");
4
+ //#region src/server.ts
5
+ /** Bind a {@link logMiddleware} def to its runtime impl. */
6
+ function logServer(def, opts) {
7
+ const wrap = opts.logWith ?? require_internal.runWith;
8
+ const report = (err) => {
9
+ try {
10
+ opts.onError?.(err);
11
+ } catch {}
12
+ };
13
+ const run = (io) => {
14
+ let fields;
15
+ try {
16
+ fields = opts.context(io.ctx, io.req);
17
+ } catch (err) {
18
+ report(err);
19
+ return Promise.resolve(io.next());
20
+ }
21
+ try {
22
+ return Promise.resolve(wrap(fields, () => io.next()));
23
+ } catch (err) {
24
+ report(err);
25
+ return Promise.resolve(io.next());
26
+ }
27
+ };
28
+ return {
29
+ def,
30
+ impl: run
31
+ };
32
+ }
33
+ /**
34
+ * The {@link logMiddleware} def factory, augmented with a `.server(def, opts)` binder.
35
+ * Import from `@ayepi/log/server` in your server entry to bind a def created in a
36
+ * frontend-safe spec.
37
+ */
38
+ const logMiddleware = Object.assign(require_middleware.logMiddleware, { server: logServer });
39
+ //#endregion
40
+ exports.logMiddleware = logMiddleware;
@@ -0,0 +1,36 @@
1
+ import { logMiddleware as logMiddleware$1 } from "./middleware.cjs";
2
+ import { AnyMiddleware, BoundMiddleware, StackCtx } from "@ayepi/core";
3
+
4
+ //#region src/server.d.ts
5
+
6
+ /** The `requires` chain of a middleware def. */
7
+ type ReqOf<M extends AnyMiddleware> = M['__req'];
8
+ /**
9
+ * Server-side options for binding a {@link logMiddleware} def.
10
+ *
11
+ * @typeParam M - the def being bound (its `requires` type the `context` callback reads).
12
+ */
13
+ interface LogMiddlewareServerOptions<M extends AnyMiddleware> {
14
+ /** Build the context object to push for the downstream chain + handler. */
15
+ readonly context: (ctx: StackCtx<ReqOf<M>>, req: Request) => object;
16
+ /** `logWith` to use (default the package's shared trace context). Pass a specific logger's `logWith` to scope it. */
17
+ readonly logWith?: <T>(add: object, inner: () => T) => T;
18
+ /**
19
+ * Observe an error thrown while building or pushing the trace context. The middleware is
20
+ * **fail-open**: such an error never breaks the request (the chain runs without the context).
21
+ * Off by default. It must not throw; if it does, the throw is ignored.
22
+ */
23
+ readonly onError?: (err: unknown) => void;
24
+ }
25
+ /** Bind a {@link logMiddleware} def to its runtime impl. */
26
+ declare function logServer<M extends AnyMiddleware>(def: M, opts: LogMiddlewareServerOptions<M>): BoundMiddleware<M>;
27
+ /**
28
+ * The {@link logMiddleware} def factory, augmented with a `.server(def, opts)` binder.
29
+ * Import from `@ayepi/log/server` in your server entry to bind a def created in a
30
+ * frontend-safe spec.
31
+ */
32
+ declare const logMiddleware: typeof logMiddleware$1 & {
33
+ server: typeof logServer;
34
+ };
35
+ //#endregion
36
+ export { LogMiddlewareServerOptions, logMiddleware };
@@ -0,0 +1,36 @@
1
+ import { logMiddleware as logMiddleware$1 } from "./middleware.js";
2
+ import { AnyMiddleware, BoundMiddleware, StackCtx } from "@ayepi/core";
3
+
4
+ //#region src/server.d.ts
5
+
6
+ /** The `requires` chain of a middleware def. */
7
+ type ReqOf<M extends AnyMiddleware> = M['__req'];
8
+ /**
9
+ * Server-side options for binding a {@link logMiddleware} def.
10
+ *
11
+ * @typeParam M - the def being bound (its `requires` type the `context` callback reads).
12
+ */
13
+ interface LogMiddlewareServerOptions<M extends AnyMiddleware> {
14
+ /** Build the context object to push for the downstream chain + handler. */
15
+ readonly context: (ctx: StackCtx<ReqOf<M>>, req: Request) => object;
16
+ /** `logWith` to use (default the package's shared trace context). Pass a specific logger's `logWith` to scope it. */
17
+ readonly logWith?: <T>(add: object, inner: () => T) => T;
18
+ /**
19
+ * Observe an error thrown while building or pushing the trace context. The middleware is
20
+ * **fail-open**: such an error never breaks the request (the chain runs without the context).
21
+ * Off by default. It must not throw; if it does, the throw is ignored.
22
+ */
23
+ readonly onError?: (err: unknown) => void;
24
+ }
25
+ /** Bind a {@link logMiddleware} def to its runtime impl. */
26
+ declare function logServer<M extends AnyMiddleware>(def: M, opts: LogMiddlewareServerOptions<M>): BoundMiddleware<M>;
27
+ /**
28
+ * The {@link logMiddleware} def factory, augmented with a `.server(def, opts)` binder.
29
+ * Import from `@ayepi/log/server` in your server entry to bind a def created in a
30
+ * frontend-safe spec.
31
+ */
32
+ declare const logMiddleware: typeof logMiddleware$1 & {
33
+ server: typeof logServer;
34
+ };
35
+ //#endregion
36
+ export { LogMiddlewareServerOptions, logMiddleware };
package/dist/server.js ADDED
@@ -0,0 +1,39 @@
1
+ import { b as runWith } from "./internal.js";
2
+ import { logMiddleware as logMiddleware$1 } from "./middleware.js";
3
+ //#region src/server.ts
4
+ /** Bind a {@link logMiddleware} def to its runtime impl. */
5
+ function logServer(def, opts) {
6
+ const wrap = opts.logWith ?? runWith;
7
+ const report = (err) => {
8
+ try {
9
+ opts.onError?.(err);
10
+ } catch {}
11
+ };
12
+ const run = (io) => {
13
+ let fields;
14
+ try {
15
+ fields = opts.context(io.ctx, io.req);
16
+ } catch (err) {
17
+ report(err);
18
+ return Promise.resolve(io.next());
19
+ }
20
+ try {
21
+ return Promise.resolve(wrap(fields, () => io.next()));
22
+ } catch (err) {
23
+ report(err);
24
+ return Promise.resolve(io.next());
25
+ }
26
+ };
27
+ return {
28
+ def,
29
+ impl: run
30
+ };
31
+ }
32
+ /**
33
+ * The {@link logMiddleware} def factory, augmented with a `.server(def, opts)` binder.
34
+ * Import from `@ayepi/log/server` in your server entry to bind a def created in a
35
+ * frontend-safe spec.
36
+ */
37
+ const logMiddleware = Object.assign(logMiddleware$1, { server: logServer });
38
+ //#endregion
39
+ export { logMiddleware };
package/package.json ADDED
@@ -0,0 +1,100 @@
1
+ {
2
+ "name": "@ayepi/log",
3
+ "version": "0.1.0",
4
+ "description": "Structured logging for ayepi — AsyncLocalStorage trace context, console interception, console/file transports, error serialization, middleware",
5
+ "license": "MIT",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/ClickerMonkey/ayepi.git",
12
+ "directory": "packages/log"
13
+ },
14
+ "homepage": "https://github.com/ClickerMonkey/ayepi/tree/main/packages/log#readme",
15
+ "bugs": {
16
+ "url": "https://github.com/ClickerMonkey/ayepi/issues"
17
+ },
18
+ "type": "module",
19
+ "sideEffects": false,
20
+ "files": [
21
+ "dist"
22
+ ],
23
+ "exports": {
24
+ ".": {
25
+ "import": {
26
+ "types": "./dist/index.d.ts",
27
+ "default": "./dist/index.js"
28
+ },
29
+ "require": {
30
+ "types": "./dist/index.d.cts",
31
+ "default": "./dist/index.cjs"
32
+ }
33
+ },
34
+ "./file": {
35
+ "import": {
36
+ "types": "./dist/file.d.ts",
37
+ "default": "./dist/file.js"
38
+ },
39
+ "require": {
40
+ "types": "./dist/file.d.cts",
41
+ "default": "./dist/file.cjs"
42
+ }
43
+ },
44
+ "./middleware": {
45
+ "import": {
46
+ "types": "./dist/middleware.d.ts",
47
+ "default": "./dist/middleware.js"
48
+ },
49
+ "require": {
50
+ "types": "./dist/middleware.d.cts",
51
+ "default": "./dist/middleware.cjs"
52
+ }
53
+ },
54
+ "./server": {
55
+ "import": {
56
+ "types": "./dist/server.d.ts",
57
+ "default": "./dist/server.js"
58
+ },
59
+ "require": {
60
+ "types": "./dist/server.d.cts",
61
+ "default": "./dist/server.cjs"
62
+ }
63
+ },
64
+ "./package.json": "./package.json"
65
+ },
66
+ "engines": {
67
+ "node": ">=18"
68
+ },
69
+ "peerDependencies": {
70
+ "@ayepi/core": "^0.1.0"
71
+ },
72
+ "peerDependenciesMeta": {
73
+ "@ayepi/core": {
74
+ "optional": true
75
+ }
76
+ },
77
+ "devDependencies": {
78
+ "@vitest/coverage-v8": "^2.1.8",
79
+ "publint": "^0.3.0",
80
+ "tsdown": "^0.12.0",
81
+ "vitest": "^2.1.8",
82
+ "zod": "^4.4.3",
83
+ "@ayepi/core": "0.1.0"
84
+ },
85
+ "keywords": [
86
+ "ayepi",
87
+ "logging",
88
+ "logger",
89
+ "structured-logging",
90
+ "async-local-storage",
91
+ "tracing",
92
+ "middleware"
93
+ ],
94
+ "scripts": {
95
+ "build": "tsdown",
96
+ "typecheck": "tsc --noEmit",
97
+ "test": "vitest run --coverage",
98
+ "publint": "publint"
99
+ }
100
+ }