@voltro/logger 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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,52 @@
1
+ # Changelog
2
+
3
+ All notable changes to the `@voltro/*` packages are recorded here. The format
4
+ follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
+
6
+ ## Stability contract — read this before you pin a version
7
+
8
+ Voltro is **`0.x` — pre-1.0, and deliberately so.** Under SemVer, `0.y.z` means
9
+ "anything MAY change." We hold to exactly that, stated out loud:
10
+
11
+ - **Pin exact versions.** Depend on `@voltro/runtime@0.4.2`, never `^0.4.2` or
12
+ `~0.4.2`. There is no compatible-range promise below 1.0.
13
+ - **Every MINOR may break.** Breaking changes land on a minor bump (`0.4.x →
14
+ 0.5.0`); patches (`0.4.1 → 0.4.2`) are additive or fixes only. This is the
15
+ standard `0.x` reading of SemVer — the minor slot carries breaking under `0.x`.
16
+ - **Read this changelog before upgrading.** The `⚠ BREAKING` section of each
17
+ release lists every incompatible change with its migration. It is the only
18
+ migration path we provide — there is no deprecation cycle, no compat shim.
19
+ - **All packages release together (lockstep).** One coordinated version across
20
+ the whole framework; the git tag is the source of truth.
21
+
22
+ This is not a placeholder disclaimer — it is the contract. The framework is
23
+ refactored aggressively while it has no external stability obligations, and that
24
+ velocity is the point. A stable-core tier and per-package `1.0` graduation are
25
+ planned, but not yet; until then, treat the whole surface as movable and pin
26
+ exact.
27
+
28
+ The **public API** of each package is its `publishConfig.exports` entry points,
29
+ minus anything marked `@internal` (those are cross-package internals and are
30
+ stripped from the published `.d.ts`). Importing a deep path that isn't an
31
+ exported entry point is unsupported.
32
+
33
+ ---
34
+
35
+ ## [Unreleased]
36
+
37
+ _Changes staged for the next release accumulate here (rolled up from
38
+ `.changes/*.md` at tag time — see `.changes/README.md`)._
39
+
40
+ ---
41
+
42
+ ## [0.1.0]
43
+
44
+ Initial pre-release baseline. This is the starting point the changelog tracks
45
+ from; it is not an exhaustive history of prior development. The framework ships
46
+ as `@voltro/*` packages spanning the runtime, database/query layer, web client
47
+ and router, durable workflows, the CLI, and the plugin ecosystem
48
+ (auth, storage, mail, billing, observability, and more). Not published to a
49
+ public registry yet.
50
+
51
+ Subsequent releases record their deltas from here under dated headings, with
52
+ `⚠ BREAKING` first.
package/LICENSE ADDED
@@ -0,0 +1,57 @@
1
+ Voltro — Proprietary Software License
2
+
3
+ Copyright (c) 2026 Voltro UG. All rights reserved.
4
+
5
+ This software and all associated source code, documentation, and other
6
+ materials (the "Software") are the proprietary property of Voltro UG
7
+ ("Voltro"). This is NOT open-source software.
8
+
9
+ Your access to and use of the Software is governed exclusively by the Voltro
10
+ Terms of Service at:
11
+
12
+ https://voltro.cloud/legal/terms
13
+
14
+ By downloading, installing, or using the Software you agree to those Terms.
15
+ Subject to and conditioned on your continued compliance with them, Voltro
16
+ grants you a limited, non-exclusive, non-transferable, non-sublicensable,
17
+ revocable license to use the Software. All rights not expressly granted in the
18
+ Terms are reserved by Voltro. If you do not agree to the Terms, you have no
19
+ license and may not use the Software.
20
+
21
+ The Terms of Service — including the scope of permitted use, plan
22
+ entitlements, fees, and pricing — may change from time to time. The version in
23
+ force is the one published at the URL above. Commercial terms and pricing are
24
+ NOT part of this notice and are not fixed by, or granted in perpetuity by, the
25
+ version of the Software in which this file appears.
26
+
27
+ Permitted use — your own software. Voltro is a development framework. You may
28
+ use the Software to build, run, and commercially distribute your own
29
+ applications and services, and to charge your own customers for them, without
30
+ owing Voltro any share of that revenue or any further permission beyond the
31
+ Terms. Applications you build with the Software are yours.
32
+
33
+ Prohibited use — reselling Voltro. You may NOT redistribute, resell,
34
+ sublicense, publish, or otherwise provide the Software itself — in whole or in
35
+ part, in source or compiled form — to third parties as a library, framework,
36
+ SDK, template, starter, or development tool for them to build upon, whether
37
+ standalone or repackaged. Shipping the Software as a non-separable, bundled
38
+ dependency inside an application you deliver (for example, compiled into your
39
+ deployed app) is permitted; extracting or re-exposing it as a reusable
40
+ component for others is not.
41
+
42
+ Except as expressly permitted above or by the Terms, you may not copy, modify,
43
+ merge, publish, sublicense, sell, distribute, or create derivative works of the
44
+ Software, in whole or in part.
45
+
46
+ Third-party open-source components distributed alongside the Software are the
47
+ property of their respective owners and are licensed under their own terms; see
48
+ THIRD-PARTY-NOTICES.md where provided. Nothing in this notice limits your
49
+ rights, or extends Voltro's, in those components.
50
+
51
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
52
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
53
+ FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL
54
+ VOLTRO BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY ARISING FROM,
55
+ OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR ITS USE.
56
+
57
+ For licensing inquiries, contact Voltro UG.
package/README.md ADDED
@@ -0,0 +1,26 @@
1
+ <div align="center">
2
+
3
+ # @voltro/logger
4
+
5
+ **Effect-based structured logger with pretty terminal output + JSON for production.**
6
+
7
+ [📖 Documentation](https://docs.voltro.dev/docs/observability/overview) · [Changelog](./CHANGELOG.md) · [voltro.dev](https://voltro.dev) · [Voltro Cloud](https://voltro.cloud)
8
+
9
+ </div>
10
+
11
+ ---
12
+
13
+ ```sh
14
+ npm install @voltro/logger
15
+ ```
16
+
17
+ > ### [→ Read the documentation for @voltro/logger](https://docs.voltro.dev/docs/observability/overview)
18
+
19
+ Installation, guides, the full API reference, and examples all live in the
20
+ **[Voltro documentation](https://docs.voltro.dev/docs/intro/getting-started)** — the single source of truth. This README is
21
+ deliberately short so there is nothing here to drift out of date.
22
+
23
+ ## License
24
+
25
+ Proprietary. © 2026 Voltro UG. Your use is governed by the
26
+ [Terms of Service](https://voltro.cloud/legal/terms). See the bundled `LICENSE`.
package/SECURITY.md ADDED
@@ -0,0 +1,56 @@
1
+ # Security Policy
2
+
3
+ We take the security of Voltro and the applications built on it seriously. This
4
+ document explains how to report a vulnerability and what to expect in return.
5
+
6
+ ## Reporting a vulnerability
7
+
8
+ **Please do not open public issues or discuss suspected vulnerabilities in
9
+ public channels.** Report them privately by email:
10
+
11
+ **security contact: [support@voltro.dev](mailto:support@voltro.dev)**
12
+ (subject line: `SECURITY`).
13
+
14
+ Include, where you can:
15
+
16
+ - the affected package(s) and version(s) (e.g. `@voltro/runtime@x.y.z`);
17
+ - a description of the issue and its impact;
18
+ - a minimal reproduction or proof of concept;
19
+ - any suggested remediation.
20
+
21
+ If you'd like to encrypt your report, ask in a first plain email and we'll
22
+ arrange a key.
23
+
24
+ ## What to expect
25
+
26
+ - **Acknowledgement** of your report within **3 business days**.
27
+ - An initial assessment (severity, affected surface) and a remediation plan as
28
+ soon as we've reproduced the issue.
29
+ - **Coordinated disclosure:** we'll agree a disclosure timeline with you and
30
+ credit you in the release notes if you wish. Please give us reasonable time to
31
+ ship a fix before any public disclosure.
32
+
33
+ We do not currently run a paid bug-bounty program, but we genuinely appreciate
34
+ responsible disclosure and will credit reporters.
35
+
36
+ ## Software Bill of Materials (SBOM)
37
+
38
+ A CycloneDX SBOM of the third-party runtime dependency graph is generated for the
39
+ published packages (`pnpm gen:sbom` → `sbom.cdx.json`). If your procurement or
40
+ security team needs it, request it at
41
+ [support@voltro.dev](mailto:support@voltro.dev).
42
+
43
+ ## Supported versions
44
+
45
+ Voltro is pre-1.0 and ships in lockstep: **only the latest published minor of
46
+ each `@voltro/*` package receives security fixes.** Please upgrade to the latest
47
+ release before reporting, and pin exact versions in production.
48
+
49
+ ## Scope
50
+
51
+ In scope: the published `@voltro/*` packages and the framework's own code.
52
+
53
+ Out of scope: vulnerabilities in third-party dependencies that are already
54
+ tracked upstream (we monitor these via a production-dependency audit gate in
55
+ CI), and issues that require a non-default, explicitly-unsafe configuration. If
56
+ you're unsure, report it anyway — we'd rather hear about it.
@@ -0,0 +1,11 @@
1
+ # Third-Party Notices — @voltro/logger
2
+
3
+ This package depends on the open-source software listed below. Each is the
4
+ property of its respective copyright holders and is used under the terms of
5
+ its license. This file is provided for attribution; it grants no rights in
6
+ @voltro/logger itself, which is proprietary (see LICENSE).
7
+
8
+ Generated from the resolved runtime dependency closure (0 packages).
9
+
10
+ ---
11
+
@@ -0,0 +1,298 @@
1
+ import { Layer } from 'effect';
2
+ import { Logger } from 'effect';
3
+ import { LogLevel as LogLevel_2 } from 'effect';
4
+
5
+ export declare const addSink: (fn: LogSink) => (() => void);
6
+
7
+ export declare const ansi: {
8
+ reset: string;
9
+ dim: (s: string) => string;
10
+ bold: (s: string) => string;
11
+ italic: (s: string) => string;
12
+ gray: (s: string) => string;
13
+ red: (s: string) => string;
14
+ green: (s: string) => string;
15
+ yellow: (s: string) => string;
16
+ blue: (s: string) => string;
17
+ magenta: (s: string) => string;
18
+ cyan: (s: string) => string;
19
+ white: (s: string) => string;
20
+ brightRed: (s: string) => string;
21
+ brightGreen: (s: string) => string;
22
+ brightYellow: (s: string) => string;
23
+ brightBlue: (s: string) => string;
24
+ brightCyan: (s: string) => string;
25
+ bgRed: (s: string) => string;
26
+ bgYellow: (s: string) => string;
27
+ bgBlue: (s: string) => string;
28
+ bgCyan: (s: string) => string;
29
+ bgGray: (s: string) => string;
30
+ brand: (s: string) => string;
31
+ brandDim: (s: string) => string;
32
+ bgBrand: (s: string) => string;
33
+ red24: (s: string) => string;
34
+ brightRed24: (s: string) => string;
35
+ };
36
+
37
+ export declare type AppKind = 'web' | 'api' | 'preview';
38
+
39
+ export declare interface AppSurfaceOptions {
40
+ readonly appName: string;
41
+ readonly queries: ReadonlyArray<string>;
42
+ readonly mutations: ReadonlyArray<string>;
43
+ readonly actions: ReadonlyArray<string>;
44
+ readonly streams?: ReadonlyArray<string>;
45
+ readonly workflows: ReadonlyArray<string>;
46
+ /** Cron schedules (`*.cron.tsx` discovery). Rendered as its own
47
+ * category alongside the rpc primitives so the boot surface shows
48
+ * the WHOLE app at a glance — not just the request-driven half. */
49
+ readonly schedules?: ReadonlyArray<string>;
50
+ /** Materialised aggregates (`*.aggregate.ts` discovery). Same
51
+ * motivation as schedules — they're part of the app's surface even
52
+ * though no rpc tag points at them. */
53
+ readonly aggregates?: ReadonlyArray<string>;
54
+ /** Event triggers (`*.trigger.tsx`) — rendered as `event→workflow`. */
55
+ readonly triggers?: ReadonlyArray<string>;
56
+ /** Agents (`*.agent.tsx`) — each synthesizes `<name>.send` + `.messages`. */
57
+ readonly agents?: ReadonlyArray<string>;
58
+ /** Public REST routes (`*.route.tsx` / `restRoutes`) — `METHOD /path`. */
59
+ readonly restRoutes?: ReadonlyArray<string>;
60
+ /** Non-wire lifecycle primitives. Shown count-only because their
61
+ * names load later in boot (after this banner, which prints BEFORE
62
+ * the risky seed/startup runs on purpose). */
63
+ readonly lifecycle?: {
64
+ readonly seeds?: number;
65
+ readonly startups?: number;
66
+ readonly subscribers?: number;
67
+ readonly webhooks?: number;
68
+ readonly emails?: number;
69
+ };
70
+ readonly tenantTables?: ReadonlyArray<string>;
71
+ }
72
+
73
+ export declare interface BufferedSink<T> {
74
+ /** Buffer an item. Applies the `maxBuffer` drop-oldest guard, then the
75
+ * `admit` early-flush policy. */
76
+ readonly push: (item: T) => void;
77
+ /** Drain + ship whatever is buffered right now. Fail-soft — never
78
+ * throws; a `send` failure is routed to `onError`. A no-op when empty. */
79
+ readonly flush: () => Promise<void>;
80
+ /** Stop the timer + do one final best-effort drain. Idempotent —
81
+ * call it from a plugin's `onDeactivate`. */
82
+ readonly dispose: () => Promise<void>;
83
+ }
84
+
85
+ /**
86
+ * What `admit` decides for each pushed item. The helper appends the item
87
+ * to the buffer, then consults `admit` to decide whether the buffer must
88
+ * flush NOW (a size / byte budget crossed) — the buffer is handed in so
89
+ * the policy can measure it however it likes.
90
+ */
91
+ export declare interface BufferedSinkOptions<T> {
92
+ /** Flush interval in ms — the periodic timer fires `flush` this often. */
93
+ readonly intervalMs: number;
94
+ /**
95
+ * Ship a drained batch. MAY reject/throw — the helper catches it and
96
+ * routes it to `onError`, so a backend outage never propagates into the
97
+ * app. Called with the whole drained batch; an empty batch is never
98
+ * passed (the helper short-circuits).
99
+ */
100
+ readonly send: (batch: ReadonlyArray<T>) => Promise<void> | void;
101
+ /**
102
+ * Consulted BEFORE the incoming item is appended, with the CURRENT
103
+ * (non-empty) buffer. Return `true` to ship what's buffered FIRST so the
104
+ * outgoing batch stays under a budget (logship's byte cap), then start a
105
+ * fresh batch with the incoming item. Only called when the buffer is
106
+ * non-empty. Omit when no pre-append flush is needed.
107
+ */
108
+ readonly flushBefore?: (buffer: ReadonlyArray<T>, incoming: T) => boolean;
109
+ /**
110
+ * Consulted AFTER the item was appended. Return `'flush'` to ship the
111
+ * buffered batch immediately (a count budget was reached), or `'keep'`
112
+ * to leave it buffered for the timer. Omit for pure interval-only
113
+ * batching. The buffer passed in INCLUDES the just-appended item.
114
+ */
115
+ readonly admit?: (buffer: ReadonlyArray<T>, added: T) => 'flush' | 'keep';
116
+ /**
117
+ * Hard cap on buffered items — when exceeded, the OLDEST item is
118
+ * dropped (a ring buffer) so an unreachable backend can't grow the
119
+ * buffer without bound. Omit for no cap (rely on `admit` + interval).
120
+ */
121
+ readonly maxBuffer?: number;
122
+ /** Fail-soft error reporter — receives any error `send` produced. The
123
+ * app keeps running regardless; this is purely for a warn line. */
124
+ readonly onError?: (error: unknown, batchSize: number) => void;
125
+ }
126
+
127
+ export declare const createLogger: (config?: SyncLoggerConfig) => SyncLogger;
128
+
129
+ /**
130
+ * True when stdout looks like an interactive TTY. We use this to
131
+ * auto-disable colours on plain pipes / file redirection / CI runs.
132
+ */
133
+ export declare const isTty: () => boolean;
134
+
135
+ export declare const jsonFormat: (record: LogRecord) => string;
136
+
137
+ /**
138
+ * Default logger instance — useful for one-off scripts that don't
139
+ * want to manage their own. Has no scope; consumers can `.child(…)`
140
+ * to specialise.
141
+ */
142
+ export declare const log: SyncLogger;
143
+
144
+ export declare interface LoggerConfig {
145
+ readonly format?: 'pretty' | 'json';
146
+ readonly colour?: boolean;
147
+ /** With `LoggerLayer` this sets the runtime minimum log level
148
+ * (`Logger.minimumLogLevel`, env default). A bare `makeLogger`
149
+ * honours it too — an explicit `minLevel` drops sub-threshold
150
+ * entries inside the logger; unset, the Effect runtime's minimum
151
+ * governs (so `Logger.withMinimumLogLevel` keeps working). */
152
+ readonly minLevel?: LogLevel_2.LogLevel;
153
+ /** Default scope tag applied when an annotation doesn't set one. */
154
+ readonly defaultScope?: string;
155
+ /** Opt-in: mask any field (or nested value, or plain-object cause)
156
+ * whose KEY matches one of these (case-insensitive). OFF by default.
157
+ * Mirrors the sync `createLogger` surface so both code paths redact. */
158
+ readonly redactKeys?: ReadonlyArray<string>;
159
+ /** Opt-in: a custom record→record transform applied before the record
160
+ * is formatted. Runs after `redactKeys`. */
161
+ readonly redact?: Redactor;
162
+ }
163
+
164
+ /**
165
+ * Ready-to-install layer. Replaces the default Effect logger + sets
166
+ * the minimum log level from `VOLTRO_LOG_LEVEL`. Apps just add this
167
+ * to their main Layer chain:
168
+ *
169
+ * const Main = Layer.mergeAll(
170
+ * LoggerLayer({ defaultScope: 'voltro:cli' }),
171
+ * OtherLayers,
172
+ * )
173
+ */
174
+ export declare const LoggerLayer: (config?: LoggerConfig) => Layer.Layer<never>;
175
+
176
+ export declare type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
177
+
178
+ export declare interface LogRecord {
179
+ readonly ts: Date;
180
+ readonly level: LogLevel;
181
+ /** Optional logical scope ("voltro:cli", "@voltro-cloud/api", …). */
182
+ readonly scope?: string;
183
+ /** Optional Effect fiber id for correlating across async boundaries. */
184
+ readonly fiberId?: string;
185
+ readonly message: string;
186
+ /** Free-form structured fields. Effect logger annotations end up here. */
187
+ readonly fields: Readonly<Record<string, unknown>>;
188
+ /** Captured error (`cause` annotation from Effect) — separate so the
189
+ * formatters can format it specially (stack trace etc.). */
190
+ readonly cause?: unknown;
191
+ }
192
+
193
+ declare type LogSink = (record: LogRecord) => void;
194
+
195
+ /**
196
+ * Build a buffered sink: a bounded buffer drained on an interval and on
197
+ * demand, fail-soft, with a final drain on dispose. See
198
+ * `BufferedSinkOptions` for the buffer-membership hooks each consumer
199
+ * customises.
200
+ */
201
+ export declare const makeBufferedSink: <T>(options: BufferedSinkOptions<T>) => BufferedSink<T>;
202
+
203
+ /**
204
+ * Build a `Redactor` that masks every field (and nested object/array
205
+ * value, and plain-object `cause`) whose KEY matches one of `keys`
206
+ * (case-insensitive). Matched values become `options.mask`
207
+ * (default `'[redacted]'`).
208
+ *
209
+ * createLogger({ redactKeys: ['password', 'apiKey', 'authorization'] })
210
+ *
211
+ * Note: `cause` values that are `Error` INSTANCES are passed through
212
+ * unchanged — masking an Error's internals would break the pretty
213
+ * stack rendering, and an Error's own enumerable props are diagnostic
214
+ * (name / message / pg-driver fields), not secret-keyed config. Put a
215
+ * secret in a `fields` entry, not in an Error you throw, if you want
216
+ * it masked.
217
+ */
218
+ export declare const makeKeyRedactor: (keys: ReadonlyArray<string>, options?: {
219
+ readonly mask?: string;
220
+ }) => Redactor;
221
+
222
+ export declare const makeLogger: (config?: LoggerConfig) => Logger.Logger<unknown, void>;
223
+
224
+ export declare const prettyFormat: (record: LogRecord, options?: PrettyFormatOptions) => string;
225
+
226
+ export declare interface PrettyFormatOptions {
227
+ /** When false, suppress every ANSI code (file sinks, redirected stdout). */
228
+ readonly colour?: boolean;
229
+ /** Suppress the scope tag (when the consumer is a single app). */
230
+ readonly hideScope?: boolean;
231
+ }
232
+
233
+ export declare const printAppSurface: (options: AppSurfaceOptions) => void;
234
+
235
+ /**
236
+ * Print the ready block to stdout. Idempotent — safe to call once
237
+ * per boot. Always emits a trailing newline so the next prompt /
238
+ * log line starts clean.
239
+ */
240
+ export declare const printReadyBlock: (options: ReadyBlockOptions) => void;
241
+
242
+ export declare interface ReadyBlockOptions {
243
+ /** App's human-readable name (`app.config.ts.name`). */
244
+ readonly app: string;
245
+ readonly kind: AppKind;
246
+ /** Primary URL — appears on its own line, brand-styled. */
247
+ readonly url: string;
248
+ /** Optional extra URLs (admin, ws, inspector). Listed below the primary. */
249
+ readonly extras?: ReadonlyArray<{
250
+ readonly label: string;
251
+ readonly url: string;
252
+ }>;
253
+ /** Boot duration in milliseconds (start of boot → ready). */
254
+ readonly bootMs: number;
255
+ }
256
+
257
+ /** A pure transform applied to a record before it is formatted / fanned out. */
258
+ export declare type Redactor = (record: LogRecord) => LogRecord;
259
+
260
+ /**
261
+ * Strip ANSI sequences from a string. Useful when the same payload
262
+ * is being emitted to a file sink that doesn't grok escape codes.
263
+ */
264
+ export declare const stripAnsi: (s: string) => string;
265
+
266
+ export declare interface SyncLogger {
267
+ readonly trace: (msg: string, fields?: Record<string, unknown>) => void;
268
+ readonly debug: (msg: string, fields?: Record<string, unknown>) => void;
269
+ readonly info: (msg: string, fields?: Record<string, unknown>) => void;
270
+ readonly warn: (msg: string, fields?: Record<string, unknown>, cause?: unknown) => void;
271
+ readonly error: (msg: string, fields?: Record<string, unknown>, cause?: unknown) => void;
272
+ readonly fatal: (msg: string, fields?: Record<string, unknown>, cause?: unknown) => void;
273
+ /** Child logger with merged scope + fields. Useful for "every log
274
+ * from this sub-system gets `{ component: 'codegen' }` baked in".
275
+ * Pass `options.minLevel` to raise (or lower) verbosity for JUST this
276
+ * sub-system — e.g. `log.child('codegen', {}, { minLevel: 'debug' })`
277
+ * keeps the rest of the app at `info` while the codegen scope traces. */
278
+ readonly child: (scope: string, fields?: Record<string, unknown>, options?: {
279
+ readonly minLevel?: LogLevel;
280
+ }) => SyncLogger;
281
+ }
282
+
283
+ export declare interface SyncLoggerConfig {
284
+ readonly scope?: string;
285
+ readonly fields?: Record<string, unknown>;
286
+ readonly format?: 'pretty' | 'json';
287
+ readonly colour?: boolean;
288
+ readonly minLevel?: LogLevel;
289
+ /** Opt-in: mask any field (or nested value, or plain-object cause)
290
+ * whose KEY matches one of these (case-insensitive). OFF by default. */
291
+ readonly redactKeys?: ReadonlyArray<string>;
292
+ /** Opt-in: a custom record→record transform applied before the record
293
+ * is formatted AND before the sink fan-out (so a masked value never
294
+ * reaches stdout OR a downstream sink). Runs after `redactKeys`. */
295
+ readonly redact?: Redactor;
296
+ }
297
+
298
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,498 @@
1
+ import { Cause as e, FiberId as t, HashMap as n, Layer as r, List as i, LogLevel as a, Logger as o } from "effect";
2
+ //#region src/ansi.ts
3
+ var s = "\x1B[", c = `${s}0m`, l = (e) => (t) => `${e}${t}${c}`, u = {
4
+ reset: c,
5
+ dim: l(`${s}2m`),
6
+ bold: l(`${s}1m`),
7
+ italic: l(`${s}3m`),
8
+ gray: l(`${s}90m`),
9
+ red: l(`${s}31m`),
10
+ green: l(`${s}32m`),
11
+ yellow: l(`${s}33m`),
12
+ blue: l(`${s}34m`),
13
+ magenta: l(`${s}35m`),
14
+ cyan: l(`${s}36m`),
15
+ white: l(`${s}37m`),
16
+ brightRed: l(`${s}91m`),
17
+ brightGreen: l(`${s}92m`),
18
+ brightYellow: l(`${s}93m`),
19
+ brightBlue: l(`${s}94m`),
20
+ brightCyan: l(`${s}96m`),
21
+ bgRed: l(`${s}41m`),
22
+ bgYellow: l(`${s}43m`),
23
+ bgBlue: l(`${s}44m`),
24
+ bgCyan: l(`${s}46m`),
25
+ bgGray: l(`${s}100m`),
26
+ brand: l(`${s}38;2;166;140;255m`),
27
+ brandDim: l(`${s}38;2;124;101;208m`),
28
+ bgBrand: l(`${s}48;2;103;78;204m`),
29
+ red24: l(`${s}38;2;220;38;38m`),
30
+ brightRed24: l(`${s}38;2;239;68;68m`)
31
+ }, d = (e) => e.replace(/\x1b\[[0-9;]*m/g, ""), f = () => {
32
+ try {
33
+ return !!process.stdout.isTTY;
34
+ } catch {
35
+ return !1;
36
+ }
37
+ }, p = "[redacted]", m = (e, t, n, r) => {
38
+ if (typeof e != "object" || !e || e instanceof Error || r.has(e)) return e;
39
+ if (r.add(e), Array.isArray(e)) return e.map((e) => m(e, t, n, r));
40
+ let i = {};
41
+ for (let [a, o] of Object.entries(e)) i[a] = t.has(a.toLowerCase()) ? n : m(o, t, n, r);
42
+ return i;
43
+ }, h = (e, t = {}) => {
44
+ let n = new Set(e.map((e) => e.toLowerCase())), r = t.mask ?? p;
45
+ return n.size === 0 ? (e) => e : (e) => {
46
+ let t = m(e.fields, n, r, /* @__PURE__ */ new WeakSet()), i = {
47
+ ...e,
48
+ fields: t
49
+ };
50
+ return e.cause === void 0 ? i : {
51
+ ...i,
52
+ cause: m(e.cause, n, r, /* @__PURE__ */ new WeakSet())
53
+ };
54
+ };
55
+ }, g = (e) => {
56
+ let t = e.redactKeys && e.redactKeys.length > 0 ? h(e.redactKeys) : void 0, n = e.redact;
57
+ return t && n ? (e) => n(t(e)) : t ?? n;
58
+ }, _ = (e) => e < 10 ? `0${e}` : String(e), v = (e) => e < 10 ? `00${e}` : e < 100 ? `0${e}` : String(e), y = (e) => `${_(e.getHours())}:${_(e.getMinutes())}:${_(e.getSeconds())}.${v(e.getMilliseconds())}`, b = (e) => typeof e == "object" && !!e && !Array.isArray(e), x = (e) => {
59
+ if (e === null) return "null";
60
+ if (e === void 0) return "undefined";
61
+ if (typeof e == "string") return /[\s"=]/.test(e) ? JSON.stringify(e) : e;
62
+ if (typeof e == "number" || typeof e == "boolean") return String(e);
63
+ if (e instanceof Date) return e.toISOString();
64
+ try {
65
+ return JSON.stringify(e);
66
+ } catch {
67
+ return String(e);
68
+ }
69
+ }, S = {
70
+ trace: (e) => u.dim(u.gray(e.toUpperCase().padEnd(5))),
71
+ debug: (e) => u.cyan(e.toUpperCase().padEnd(5)),
72
+ info: (e) => u.brand(e.toUpperCase().padEnd(5)),
73
+ warn: (e) => u.yellow(e.toUpperCase().padEnd(5)),
74
+ error: (e) => u.brightRed24(e.toUpperCase().padEnd(5)),
75
+ fatal: (e) => u.bgRed(u.brightRed24(` ${e.toUpperCase()} `))
76
+ }, C = (e, t = {}) => {
77
+ let n = t.colour ?? !0, r = n ? u : k, i = r.dim(y(e.ts)), a = n ? S[e.level](e.level) : e.level.toUpperCase().padEnd(5), o = !t.hideScope && e.scope ? `${r.dim("[")}${r.brandDim(e.scope)}${r.dim("]")}` : "", s = [];
78
+ for (let [t, n] of Object.entries(e.fields)) s.push(`${r.dim(`${t}=`)}${x(n)}`);
79
+ let c = e.fiberId ? r.dim(`fiber=${e.fiberId}`) : "", l = [...s, c].filter((e) => e.length > 0).join(" "), d = [
80
+ i,
81
+ a,
82
+ o,
83
+ e.message,
84
+ l
85
+ ].filter((e) => e.length > 0).join(" ");
86
+ if (e.cause !== void 0) {
87
+ let t = w(e.cause, n);
88
+ return t.length > 0 ? `${d}\n${t}` : d;
89
+ }
90
+ return d;
91
+ }, w = (e, t) => {
92
+ let n = t ? u : k;
93
+ if (e instanceof Error) {
94
+ let t = n.red(` ${e.name}: ${e.message}`);
95
+ if (typeof e.stack == "string") {
96
+ let r = e.stack.split("\n").slice(1).map((e) => n.dim(` ${e.trim()}`)).join("\n");
97
+ return r.length > 0 ? `${t}\n${r}` : t;
98
+ }
99
+ return t;
100
+ }
101
+ if (b(e) && typeof e.stack == "string") {
102
+ let [t, ...r] = e.stack.split("\n"), i = n.red(` ${t ?? ""}`), a = r.map((e) => n.dim(` ${e.trimEnd()}`)).join("\n");
103
+ return a.length > 0 ? `${i}\n${a}` : i;
104
+ }
105
+ if (b(e)) try {
106
+ return n.red(` ${JSON.stringify(e, null, 2).replace(/\n/g, "\n ")}`);
107
+ } catch {
108
+ return n.red(` ${String(e)}`);
109
+ }
110
+ return n.red(` ${String(e)}`);
111
+ }, T = [
112
+ "severity",
113
+ "code",
114
+ "detail",
115
+ "hint",
116
+ "position",
117
+ "internalPosition",
118
+ "internalQuery",
119
+ "where",
120
+ "schema",
121
+ "table",
122
+ "column",
123
+ "dataType",
124
+ "constraint",
125
+ "file",
126
+ "line",
127
+ "routine"
128
+ ], E = (e, t = 0, n = /* @__PURE__ */ new WeakSet()) => {
129
+ if (t > 8) return "[cause: max-depth]";
130
+ if (typeof e != "object" || !e) return e;
131
+ if (n.has(e)) return "[cause: circular]";
132
+ if (n.add(e), e instanceof Error) {
133
+ let r = {
134
+ name: e.name,
135
+ message: e.message
136
+ };
137
+ typeof e.stack == "string" && (r.stack = e.stack);
138
+ let i = e;
139
+ for (let e of T) {
140
+ let t = i[e];
141
+ t !== void 0 && (r[e] = t);
142
+ }
143
+ return "cause" in e && e.cause !== void 0 && (r.cause = E(e.cause, t + 1, n)), r;
144
+ }
145
+ if (Array.isArray(e)) return e.map((e) => E(e, t + 1, n));
146
+ let r = {};
147
+ for (let [i, a] of Object.entries(e)) r[i] = E(a, t + 1, n);
148
+ return r;
149
+ }, D = (e) => {
150
+ let t = {};
151
+ for (let [n, r] of Object.entries(e.fields)) t[n] = E(r);
152
+ let n = {
153
+ ts: e.ts.toISOString(),
154
+ level: e.level,
155
+ msg: e.message,
156
+ ...e.scope ? { scope: e.scope } : {},
157
+ ...e.fiberId ? { fiberId: e.fiberId } : {},
158
+ ...t
159
+ };
160
+ e.cause !== void 0 && (n.cause = E(e.cause));
161
+ try {
162
+ return JSON.stringify(n);
163
+ } catch {
164
+ return JSON.stringify({
165
+ ts: n.ts,
166
+ level: n.level,
167
+ msg: n.msg,
168
+ ...n.scope ? { scope: n.scope } : {},
169
+ _serialiseError: !0
170
+ });
171
+ }
172
+ }, O = (e) => e, k = {
173
+ reset: "",
174
+ dim: O,
175
+ bold: O,
176
+ italic: O,
177
+ gray: O,
178
+ red: O,
179
+ green: O,
180
+ yellow: O,
181
+ blue: O,
182
+ magenta: O,
183
+ cyan: O,
184
+ white: O,
185
+ brightRed: O,
186
+ brightGreen: O,
187
+ brightYellow: O,
188
+ brightBlue: O,
189
+ brightCyan: O,
190
+ bgRed: O,
191
+ bgYellow: O,
192
+ bgBlue: O,
193
+ bgCyan: O,
194
+ bgGray: O,
195
+ brand: O,
196
+ brandDim: O,
197
+ bgBrand: O,
198
+ red24: O,
199
+ brightRed24: O
200
+ }, A = /* @__PURE__ */ new Set(), j = (e) => (A.add(e), () => {
201
+ A.delete(e);
202
+ }), M = (e) => {
203
+ if (A.size !== 0) for (let t of A) try {
204
+ t(e);
205
+ } catch {}
206
+ }, ee = () => {
207
+ let e = (process.env.VOLTRO_LOG_FORMAT ?? "").toLowerCase();
208
+ return e === "pretty" ? "pretty" : e === "json" ? "json" : f() ? "pretty" : "json";
209
+ }, N = () => {
210
+ let e = (process.env.VOLTRO_LOG_COLOUR ?? "").toLowerCase();
211
+ return e === "on" || e === "true" || e === "1" ? !0 : e === "off" || e === "false" || e === "0" ? !1 : f();
212
+ }, P = () => {
213
+ switch ((process.env.VOLTRO_LOG_LEVEL ?? "").toLowerCase()) {
214
+ case "trace": return a.Trace;
215
+ case "debug": return a.Debug;
216
+ case "info": return a.Info;
217
+ case "warn": return a.Warning;
218
+ case "error": return a.Error;
219
+ case "fatal": return a.Fatal;
220
+ default: {
221
+ let e = (process.env.NODE_ENV ?? "").toLowerCase();
222
+ return e !== "production" && e !== "prod" ? a.Debug : a.Info;
223
+ }
224
+ }
225
+ }, F = (e) => {
226
+ switch (e.label) {
227
+ case "TRACE": return "trace";
228
+ case "DEBUG": return "debug";
229
+ case "INFO": return "info";
230
+ case "WARN": return "warn";
231
+ case "ERROR": return "error";
232
+ case "FATAL": return "fatal";
233
+ default: return "info";
234
+ }
235
+ }, I = (r) => {
236
+ let a = {}, o;
237
+ n.forEach(r.annotations, (e, t) => {
238
+ if (t === "scope" && typeof e == "string") {
239
+ o = e;
240
+ return;
241
+ }
242
+ a[t] = e;
243
+ });
244
+ let s = [];
245
+ i.forEach(r.spans, (e) => {
246
+ s.push(e.label);
247
+ }), s.length > 0 && (a.span = s.join("."));
248
+ let c = r.fiberId !== void 0 && r.fiberId !== null && t.threadName(r.fiberId) || void 0, l = r.cause !== void 0 && r.cause !== null ? e.isEmpty(r.cause) ? void 0 : e.squash(r.cause) : void 0, u = L(r.message);
249
+ return {
250
+ ts: new Date(r.date.getTime()),
251
+ level: F(r.logLevel),
252
+ message: u,
253
+ fields: a,
254
+ ...o ? { scope: o } : {},
255
+ ...c ? { fiberId: c } : {},
256
+ ...l === void 0 ? {} : { cause: l }
257
+ };
258
+ }, L = (e) => typeof e == "string" ? e : Array.isArray(e) ? e.map((e) => typeof e == "string" ? e : e === void 0 ? "undefined" : e === null ? "null" : typeof e == "object" ? R(e) : String(e)).join(" ") : e === void 0 ? "" : e === null ? "null" : typeof e == "object" ? R(e) : String(e), R = (e) => {
259
+ try {
260
+ return JSON.stringify(e);
261
+ } catch {
262
+ return String(e);
263
+ }
264
+ }, z = (e, t) => {
265
+ (e.level === "error" || e.level === "fatal" ? process.stderr : process.stdout).write(`${t}\n`);
266
+ }, B = (e, t, n) => t === "json" ? D(e) : C(e, n), V = (e = {}) => {
267
+ let t = e.format ?? ee(), n = { colour: e.colour ?? N() }, r = g(e), i = e.minLevel;
268
+ return o.make((o) => {
269
+ if (i !== void 0 && a.lessThan(o.logLevel, i)) return;
270
+ let s = I(o), c = !s.scope && e.defaultScope ? {
271
+ ...s,
272
+ scope: e.defaultScope
273
+ } : s, l = r ? r(c) : c;
274
+ z(l, B(l, t, n)), M(l);
275
+ });
276
+ }, H = (e = {}) => r.mergeAll(o.replace(o.defaultLogger, V(e)), o.minimumLogLevel(e.minLevel ?? P())), U = {
277
+ trace: 10,
278
+ debug: 20,
279
+ info: 30,
280
+ warn: 40,
281
+ error: 50,
282
+ fatal: 60
283
+ }, W = (e) => {
284
+ try {
285
+ return typeof process < "u" && process.env && process.env[e] || "";
286
+ } catch {
287
+ return "";
288
+ }
289
+ }, G = () => {
290
+ let e = W("VOLTRO_LOG_FORMAT").toLowerCase();
291
+ return e === "pretty" ? "pretty" : e === "json" ? "json" : f() ? "pretty" : "json";
292
+ }, K = () => {
293
+ let e = W("VOLTRO_LOG_COLOUR").toLowerCase();
294
+ return e === "on" || e === "true" || e === "1" ? !0 : e === "off" || e === "false" || e === "0" ? !1 : f();
295
+ }, q = () => {
296
+ let e = W("VOLTRO_LOG_LEVEL").toLowerCase();
297
+ if (e === "trace" || e === "debug" || e === "info" || e === "warn" || e === "error" || e === "fatal") return e;
298
+ let t = W("NODE_ENV").toLowerCase();
299
+ return t !== "production" && t !== "prod" ? "debug" : "info";
300
+ }, J = globalThis.window !== void 0;
301
+ if (!J && typeof process < "u") for (let e of [process.stdout, process.stderr]) e && typeof e.on == "function" && e.on("error", (e) => {
302
+ if (e?.code !== "EPIPE") throw e;
303
+ });
304
+ var Y = (e, t, n, r) => {
305
+ let i = r ? r(e) : e;
306
+ if (J) {
307
+ let e = t === "json" ? D(i) : C(i, {
308
+ ...n,
309
+ colour: !1
310
+ });
311
+ (console[X(i.level)] ?? console.log).call(console, e);
312
+ } else {
313
+ let e = t === "json" ? D(i) : C(i, n), r = i.level === "error" || i.level === "fatal" ? process.stderr : process.stdout;
314
+ try {
315
+ r.write(`${e}\n`);
316
+ } catch {}
317
+ }
318
+ M(i);
319
+ }, X = (e) => {
320
+ switch (e) {
321
+ case "trace":
322
+ case "debug": return "debug";
323
+ case "info": return "log";
324
+ case "warn": return "warn";
325
+ case "error":
326
+ case "fatal": return "error";
327
+ }
328
+ }, Z = (e = {}) => {
329
+ let t = e.format ?? G(), n = e.colour ?? K(), r = U[e.minLevel ?? q()], i = e.fields ?? {}, a = e.scope, o = g(e), s = (e, s, c, l) => {
330
+ U[e] < r || Y({
331
+ ts: /* @__PURE__ */ new Date(),
332
+ level: e,
333
+ ...a ? { scope: a } : {},
334
+ message: s,
335
+ fields: {
336
+ ...i,
337
+ ...c ?? {}
338
+ },
339
+ ...l === void 0 ? {} : { cause: l }
340
+ }, t, { colour: n }, o);
341
+ };
342
+ return {
343
+ trace: (e, t) => s("trace", e, t),
344
+ debug: (e, t) => s("debug", e, t),
345
+ info: (e, t) => s("info", e, t),
346
+ warn: (e, t, n) => s("warn", e, t, n),
347
+ error: (e, t, n) => s("error", e, t, n),
348
+ fatal: (e, t, n) => s("fatal", e, t, n),
349
+ child: (t, n, r) => Z({
350
+ ...e,
351
+ scope: a ? `${a}:${t}` : t,
352
+ fields: {
353
+ ...i,
354
+ ...n ?? {}
355
+ },
356
+ ...r?.minLevel === void 0 ? {} : { minLevel: r.minLevel }
357
+ })
358
+ };
359
+ }, Q = Z(), te = (e) => {
360
+ let t = [], n, r = !1, i = async () => {
361
+ if (t.length === 0) return;
362
+ let n = t.splice(0, t.length);
363
+ try {
364
+ await e.send(n);
365
+ } catch (t) {
366
+ e.onError?.(t, n.length);
367
+ }
368
+ };
369
+ return n = setInterval(() => void i(), e.intervalMs), typeof n.unref == "function" && n.unref(), {
370
+ push: (n) => {
371
+ r || (e.flushBefore && t.length > 0 && e.flushBefore(t, n) && i(), t.push(n), e.maxBuffer !== void 0 && t.length > e.maxBuffer && t.shift(), e.admit && e.admit(t, n) === "flush" && i());
372
+ },
373
+ flush: i,
374
+ dispose: async () => {
375
+ if (r) {
376
+ await i();
377
+ return;
378
+ }
379
+ r = !0, n && clearInterval(n), n = void 0, await i(), t = [];
380
+ }
381
+ };
382
+ }, ne = {
383
+ web: "Web app",
384
+ api: "API app",
385
+ preview: "Preview"
386
+ }, re = (e) => e < 1e3 ? `${Math.round(e)} ms` : `${(e / 1e3).toFixed(1)} s`, ie = (e) => {
387
+ let t = f() ? u : ae(), n = [];
388
+ n.push(""), n.push(` ${t.brand("▲")} ${t.bold("Voltro")} ${t.dim("·")} ${t.dim(ne[e.kind])} ${t.dim("·")} ${e.app}`), n.push(""), n.push(` ${t.dim("➜")} ${t.dim("Local: ")}${t.bold(t.brand(e.url))}`);
389
+ for (let r of e.extras ?? []) {
390
+ let e = `${r.label}:`.padEnd(8, " ");
391
+ n.push(` ${t.dim("➜")} ${t.dim(e)}${t.brandDim(r.url)}`);
392
+ }
393
+ n.push(""), n.push(` ${t.dim(`ready in ${re(e.bootMs)}`)}`), n.push(""), process.stdout.write(n.join("\n") + "\n");
394
+ }, ae = () => {
395
+ let e = (e) => e;
396
+ return {
397
+ reset: "",
398
+ dim: e,
399
+ bold: e,
400
+ italic: e,
401
+ gray: e,
402
+ red: e,
403
+ green: e,
404
+ yellow: e,
405
+ blue: e,
406
+ magenta: e,
407
+ cyan: e,
408
+ white: e,
409
+ brightRed: e,
410
+ brightGreen: e,
411
+ brightYellow: e,
412
+ brightBlue: e,
413
+ brightCyan: e,
414
+ bgRed: e,
415
+ bgYellow: e,
416
+ bgBlue: e,
417
+ bgCyan: e,
418
+ bgGray: e,
419
+ brand: e,
420
+ brandDim: e,
421
+ bgBrand: e,
422
+ red24: e,
423
+ brightRed24: e
424
+ };
425
+ }, $ = (e) => {
426
+ let t = /* @__PURE__ */ new Map();
427
+ for (let n of e) {
428
+ let e = n.indexOf("."), r = e >= 0 ? n.slice(0, e) : "(top)", i = e >= 0 ? n.slice(e + 1) : n, a = t.get(r);
429
+ a ? a.push(i) : t.set(r, [i]);
430
+ }
431
+ return [...t.entries()].sort(([e], [t]) => e.localeCompare(t)).map(([e, t]) => ({
432
+ namespace: e,
433
+ operations: t.slice().sort()
434
+ }));
435
+ }, oe = (e) => {
436
+ let t = f() ? u : se(), n = e.schedules ?? [], r = e.aggregates ?? [], i = e.streams ?? [], a = e.triggers ?? [], o = e.agents ?? [], s = e.restRoutes ?? [], c = e.lifecycle ?? {}, l = (c.seeds ?? 0) + (c.startups ?? 0) + (c.subscribers ?? 0) + (c.webhooks ?? 0) + (c.emails ?? 0);
437
+ if (e.queries.length + e.mutations.length + e.actions.length + i.length + e.workflows.length + n.length + r.length + a.length + o.length + s.length + l === 0) return;
438
+ let d = [""], p = [
439
+ ...$(e.queries).map((e) => e.namespace),
440
+ ...$(e.mutations).map((e) => e.namespace),
441
+ ...$(e.actions).map((e) => e.namespace),
442
+ ...$(i).map((e) => e.namespace),
443
+ ...$(e.workflows).map((e) => e.namespace),
444
+ ...$(n).map((e) => e.namespace),
445
+ ...$(r).map((e) => e.namespace),
446
+ ...$(a).map((e) => e.namespace),
447
+ ...$(o).map((e) => e.namespace)
448
+ ].reduce((e, t) => Math.max(e, t.length), 0), m = (e, n) => {
449
+ if (n.length !== 0) {
450
+ d.push(` ${t.bold(e)} ${t.dim(`(${n.length})`)}`);
451
+ for (let { namespace: e, operations: r } of $(n)) {
452
+ let n = e.padEnd(p, " ");
453
+ d.push(` ${t.brand(n)} ${t.dim("·")} ${r.join(t.dim(", "))}`);
454
+ }
455
+ d.push("");
456
+ }
457
+ };
458
+ if (m("Queries", e.queries), m("Mutations", e.mutations), m("Actions", e.actions), m("Streams", i), m("REST routes", s), m("Workflows", e.workflows), m("Triggers", a), m("Schedules", n), m("Agents", o), m("Aggregates", r), l > 0) {
459
+ let e = [], n = (t, n, r) => {
460
+ t && t > 0 && e.push(`${t} ${t === 1 ? n : r}`);
461
+ };
462
+ n(c.seeds, "seed", "seeds"), n(c.startups, "startup", "startups"), n(c.subscribers, "subscriber", "subscribers"), n(c.webhooks, "webhook", "webhooks"), n(c.emails, "email", "emails"), d.push(` ${t.bold("Lifecycle")} ${t.dim("·")} ${e.join(t.dim(" · "))}`), d.push("");
463
+ }
464
+ e.tenantTables && e.tenantTables.length > 0 && (d.push(` ${t.dim("Tenant-scoped tables")} ${t.dim("·")} ${e.tenantTables.join(t.dim(", "))}`), d.push("")), process.stdout.write(d.join("\n"));
465
+ }, se = () => {
466
+ let e = (e) => e;
467
+ return {
468
+ reset: "",
469
+ dim: e,
470
+ bold: e,
471
+ italic: e,
472
+ gray: e,
473
+ red: e,
474
+ green: e,
475
+ yellow: e,
476
+ blue: e,
477
+ magenta: e,
478
+ cyan: e,
479
+ white: e,
480
+ brightRed: e,
481
+ brightGreen: e,
482
+ brightYellow: e,
483
+ brightBlue: e,
484
+ brightCyan: e,
485
+ bgRed: e,
486
+ bgYellow: e,
487
+ bgBlue: e,
488
+ bgCyan: e,
489
+ bgGray: e,
490
+ brand: e,
491
+ brandDim: e,
492
+ bgBrand: e,
493
+ red24: e,
494
+ brightRed24: e
495
+ };
496
+ };
497
+ //#endregion
498
+ export { H as LoggerLayer, j as addSink, u as ansi, Z as createLogger, f as isTty, D as jsonFormat, Q as log, te as makeBufferedSink, h as makeKeyRedactor, V as makeLogger, C as prettyFormat, oe as printAppSurface, ie as printReadyBlock, d as stripAnsi };
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@voltro/logger",
3
+ "version": "0.1.0",
4
+ "description": "Effect-based structured logger with pretty terminal output + JSON for production.",
5
+ "keywords": [
6
+ "voltro",
7
+ "typescript",
8
+ "framework"
9
+ ],
10
+ "license": "SEE LICENSE IN LICENSE",
11
+ "homepage": "https://voltro.dev",
12
+ "bugs": {
13
+ "email": "support@voltro.dev"
14
+ },
15
+ "author": {
16
+ "name": "Voltro UG",
17
+ "url": "https://voltro.dev"
18
+ },
19
+ "type": "module",
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "import": "./dist/index.js",
24
+ "default": "./dist/index.js"
25
+ }
26
+ },
27
+ "main": "./dist/index.js",
28
+ "module": "./dist/index.js",
29
+ "types": "./dist/index.d.ts",
30
+ "sideEffects": false,
31
+ "engines": {
32
+ "node": ">=24.0.0"
33
+ },
34
+ "peerDependencies": {
35
+ "effect": "^3.21.4"
36
+ },
37
+ "publishConfig": {
38
+ "access": "public"
39
+ }
40
+ }