@better-logger/core 0.7.0 → 0.9.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/LICENSE +21 -0
- package/README.md +170 -211
- package/dist/index.cjs +3 -3
- package/dist/index.d.cts +40 -23
- package/dist/index.d.ts +40 -23
- package/dist/index.js +3 -3
- package/package.json +1 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 0xmilord
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,293 +1,252 @@
|
|
|
1
|
-
#
|
|
1
|
+
# better-logger
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**console.log is broken. better.log fixes it.**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
You wouldn't debug a multi-step process with sticky notes.
|
|
6
|
+
Stop debugging your app with console.log.
|
|
6
7
|
|
|
7
8
|
```bash
|
|
8
9
|
npm install @better-logger/core
|
|
9
10
|
```
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
## The Problem
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
```ts
|
|
14
|
+
```typescript
|
|
15
|
+
// console.log — flat noise, no structure
|
|
16
16
|
console.log('start')
|
|
17
17
|
console.log('user', user)
|
|
18
18
|
console.log('after db')
|
|
19
|
+
console.log('payment', payment)
|
|
19
20
|
console.log('done')
|
|
20
21
|
```
|
|
21
22
|
|
|
22
|
-
And trying to mentally reconstruct
|
|
23
|
+
And then trying to mentally reconstruct:
|
|
24
|
+
- What ran first?
|
|
25
|
+
- How long did each thing take?
|
|
26
|
+
- Where did it fail?
|
|
27
|
+
- What were the values at each step?
|
|
23
28
|
|
|
24
|
-
|
|
29
|
+
## The Solution
|
|
25
30
|
|
|
26
|
-
|
|
31
|
+
```typescript
|
|
32
|
+
import { better } from '@better-logger/core'
|
|
27
33
|
|
|
28
|
-
|
|
34
|
+
// Same code. Better output.
|
|
35
|
+
better.log('start')
|
|
36
|
+
better.log('user', user)
|
|
37
|
+
better.log('after db')
|
|
38
|
+
better.log('payment', payment)
|
|
39
|
+
better.log('done')
|
|
40
|
+
```
|
|
29
41
|
|
|
30
|
-
|
|
42
|
+
**What you get:**
|
|
31
43
|
|
|
32
44
|
```
|
|
33
|
-
🚀 [flow:
|
|
34
|
-
→
|
|
45
|
+
🚀 [flow:default] (tid: abc123)
|
|
46
|
+
→ start
|
|
47
|
+
✓ start (12ms)
|
|
48
|
+
→ user
|
|
35
49
|
data: { email: "test@example.com" }
|
|
36
|
-
✓
|
|
37
|
-
→
|
|
38
|
-
✓
|
|
39
|
-
→
|
|
40
|
-
|
|
41
|
-
|
|
50
|
+
✓ user (45ms)
|
|
51
|
+
→ after db
|
|
52
|
+
✓ after db (210ms)
|
|
53
|
+
→ payment
|
|
54
|
+
data: { amount: 99.99 }
|
|
55
|
+
✓ payment (183ms)
|
|
56
|
+
→ done
|
|
57
|
+
✓ done (0ms)
|
|
58
|
+
🏁 [flow:default] success (450ms)
|
|
42
59
|
```
|
|
43
60
|
|
|
44
|
-
|
|
45
|
-
import { createFlow } from '@better-logger/core'
|
|
46
|
-
|
|
47
|
-
const flow = createFlow('user-onboarding', { tags: ['auth'] })
|
|
48
|
-
|
|
49
|
-
const s1 = flow.step('create-user', { email })
|
|
50
|
-
await createUser(email)
|
|
51
|
-
s1.success()
|
|
52
|
-
|
|
53
|
-
const s2 = flow.step('save-db')
|
|
54
|
-
await saveUser()
|
|
55
|
-
s2.fail(new Error('timeout'))
|
|
56
|
-
|
|
57
|
-
flow.fail(new Error('save-db failed'))
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
You didn't write logs.
|
|
61
|
-
|
|
62
|
-
You defined the **execution**.
|
|
63
|
-
|
|
64
|
-
better-logger turns your code into a timeline of what actually happened.
|
|
65
|
-
|
|
66
|
-
Output is deferred until `flow.success()` / `flow.fail()` — one atomic write, zero interleaving, even in async chaos.
|
|
67
|
-
|
|
68
|
-
---
|
|
69
|
-
|
|
70
|
-
## Why this exists
|
|
71
|
-
|
|
72
|
-
Debugging today is broken:
|
|
73
|
-
|
|
74
|
-
- `console.log` → flat noise, no structure
|
|
75
|
-
- No automatic timing
|
|
76
|
-
- No context propagation
|
|
77
|
-
- Async flows become impossible to follow
|
|
78
|
-
|
|
79
|
-
You don't debug code.
|
|
80
|
-
|
|
81
|
-
You debug **guesses about what happened**.
|
|
82
|
-
|
|
83
|
-
better-logger removes the guesswork. Instead of scattering `console.log` across your code and reconstructing timelines mentally, you define the flow upfront and get a structured narrative back — with timing, context, and clear failure markers.
|
|
84
|
-
|
|
85
|
-
---
|
|
86
|
-
|
|
87
|
-
## What changes
|
|
88
|
-
|
|
89
|
-
Instead of guessing:
|
|
90
|
-
- "did this run?"
|
|
91
|
-
- "what ran first?"
|
|
92
|
-
- "where did it fail?"
|
|
93
|
-
- "why is it slow?"
|
|
94
|
-
|
|
95
|
-
You **see**:
|
|
96
|
-
|
|
97
|
-
- 🧠 A full execution narrative
|
|
98
|
-
- ⏱ Exact timing for every step
|
|
99
|
-
- 🌳 Nested flows (real hierarchy, not flat logs)
|
|
100
|
-
- 🧾 Data at the moment it mattered
|
|
101
|
-
- 🧵 Shared context across the entire flow
|
|
102
|
-
- 🏷 Tags to group and filter
|
|
103
|
-
- 🧱 Guaranteed consistency — no race-condition bugs
|
|
104
|
-
- 🔒 Immutable render snapshots — output can't be corrupted
|
|
105
|
-
|
|
106
|
-
This replaces `console.log` for anything non-trivial.
|
|
107
|
-
|
|
108
|
-
---
|
|
61
|
+
**Automatic timing. Context propagation. Hierarchical grouping. Zero config.**
|
|
109
62
|
|
|
110
|
-
## Why
|
|
63
|
+
## Why better.log?
|
|
111
64
|
|
|
112
|
-
|
|
|
113
|
-
|
|
114
|
-
|
|
|
115
|
-
|
|
|
116
|
-
|
|
|
117
|
-
|
|
|
65
|
+
| Feature | console.log | pino | winston | better.log |
|
|
66
|
+
|---------|-------------|------|---------|------------|
|
|
67
|
+
| Drop-in replacement | — | ❌ | ❌ | ✅ |
|
|
68
|
+
| Auto-flow grouping | ❌ | ❌ | ❌ | ✅ |
|
|
69
|
+
| Automatic timing | ❌ | Manual | Manual | ✅ |
|
|
70
|
+
| Context propagation | ❌ | Manual | Manual | ✅ |
|
|
71
|
+
| Hierarchical output | ❌ | ❌ | ❌ | ✅ |
|
|
72
|
+
| Zero dependencies | ✅ | ❌ | ❌ | ✅ |
|
|
73
|
+
| Bundle size | 0KB | 30KB | 100KB | **8KB** |
|
|
74
|
+
| TypeScript support | ❌ | ✅ | ✅ | ✅ |
|
|
75
|
+
| Browser support | ✅ | ❌ | ❌ | ✅ |
|
|
76
|
+
| Structured output | ❌ | ✅ | ✅ | ✅ |
|
|
77
|
+
| Auto-error tracking | ❌ | ❌ | ❌ | ✅ |
|
|
118
78
|
|
|
119
|
-
|
|
79
|
+
## Quick Start
|
|
120
80
|
|
|
121
|
-
|
|
81
|
+
### Replace console.log
|
|
122
82
|
|
|
123
|
-
|
|
83
|
+
```typescript
|
|
84
|
+
import { better } from '@better-logger/core'
|
|
124
85
|
|
|
125
|
-
|
|
86
|
+
// Before
|
|
87
|
+
console.log('User created:', user)
|
|
88
|
+
console.error('Payment failed:', error)
|
|
126
89
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const step = flow.step('db')
|
|
131
|
-
await db.query()
|
|
132
|
-
step.success()
|
|
133
|
-
|
|
134
|
-
flow.success()
|
|
90
|
+
// After
|
|
91
|
+
better.log('User created:', user)
|
|
92
|
+
better.log.error('Payment failed:', error)
|
|
135
93
|
```
|
|
136
94
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
---
|
|
95
|
+
### Severity tagging
|
|
140
96
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
Start[createFlow] --> Step[step]
|
|
146
|
-
Step --> Complete[success / fail]
|
|
147
|
-
Complete --> FlowEnd[flow.success / flow.fail]
|
|
148
|
-
FlowEnd --> Render[Atomic Render]
|
|
97
|
+
```typescript
|
|
98
|
+
better.log.info('Server started', { port: 3000 })
|
|
99
|
+
better.log.warn('Slow query', { duration: 250 })
|
|
100
|
+
better.log.error('Connection failed', error)
|
|
149
101
|
```
|
|
150
102
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
## When should you use this
|
|
154
|
-
|
|
155
|
-
Use it when:
|
|
103
|
+
### When you need structure
|
|
156
104
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
- timing matters
|
|
161
|
-
- you need to know "what ran" and "what didn't"
|
|
105
|
+
```typescript
|
|
106
|
+
const flow = better.flow('checkout', { tags: ['payment'] })
|
|
107
|
+
flow.setContext({ userId: 'user-123' })
|
|
162
108
|
|
|
163
|
-
|
|
109
|
+
const step = flow.step('charge-card', { amount: 99.99 })
|
|
110
|
+
const result = await paymentGateway.charge({ amount: 99.99 })
|
|
111
|
+
step.success(result)
|
|
164
112
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
---
|
|
168
|
-
|
|
169
|
-
## Advanced
|
|
113
|
+
flow.success()
|
|
114
|
+
```
|
|
170
115
|
|
|
171
|
-
###
|
|
116
|
+
### Async helper
|
|
172
117
|
|
|
173
|
-
```
|
|
174
|
-
const flow =
|
|
118
|
+
```typescript
|
|
119
|
+
const flow = better.flow('data-export')
|
|
175
120
|
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
s.success()
|
|
180
|
-
ai.success()
|
|
121
|
+
const data = await flow.run('fetch-data', async () => {
|
|
122
|
+
return await db.users.find({})
|
|
123
|
+
})
|
|
181
124
|
|
|
182
125
|
flow.success()
|
|
183
126
|
```
|
|
184
127
|
|
|
185
|
-
|
|
186
|
-
🚀 [flow:request] (tid: a1b2c3d4)
|
|
187
|
-
└─ 🚀 [flow:ai-call] (tid: x9y8z7w6)
|
|
188
|
-
→ generate
|
|
189
|
-
✓ generate (210ms)
|
|
190
|
-
🏁 [flow:ai-call] success (215ms)
|
|
191
|
-
🏁 [flow:request] success (340ms)
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
### Context Propagation
|
|
128
|
+
## API Reference
|
|
195
129
|
|
|
196
|
-
|
|
197
|
-
flow.setContext({ userId: 'abc', requestId: 'xyz' })
|
|
198
|
-
// Available across all steps and child flows
|
|
199
|
-
```
|
|
130
|
+
### Core (90% of users need only this)
|
|
200
131
|
|
|
201
|
-
|
|
132
|
+
```typescript
|
|
133
|
+
better.log('message') // Simple message
|
|
134
|
+
better.log('message', data) // Message with data
|
|
135
|
+
better.log.warn('warning', data) // Warning (auto-tags flow)
|
|
136
|
+
better.log.error('error', error) // Error (fails flow)
|
|
202
137
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
//
|
|
138
|
+
better.flow('name', options) // Explicit flow
|
|
139
|
+
better.setEnabled(false) // Disable all logging
|
|
140
|
+
better.subscribe(fn) // Listen for flow completions
|
|
141
|
+
better.toJSON(flow) // Export flow as JSON
|
|
206
142
|
```
|
|
207
143
|
|
|
208
|
-
###
|
|
144
|
+
### Transports (Production)
|
|
209
145
|
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
//
|
|
146
|
+
```typescript
|
|
147
|
+
better.log.toFile('app.log') // File transport
|
|
148
|
+
better.log.toStream(process.stdout) // Stream transport
|
|
149
|
+
better.log.toHttp('https://api.example.com/log') // HTTP transport
|
|
213
150
|
```
|
|
214
151
|
|
|
215
|
-
###
|
|
152
|
+
### Production Features
|
|
216
153
|
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
// Frozen snapshot of every completed flow
|
|
222
|
-
console.log(toJSON(trace))
|
|
223
|
-
})
|
|
154
|
+
```typescript
|
|
155
|
+
better.log.redact(['password', 'ssn']) // PII redaction
|
|
156
|
+
better.log.async(true) // Non-blocking async
|
|
157
|
+
better.log.flush() // Force complete
|
|
224
158
|
```
|
|
225
159
|
|
|
226
|
-
###
|
|
227
|
-
|
|
228
|
-
```ts
|
|
229
|
-
import { toJSON } from '@better-logger/core'
|
|
160
|
+
### Configuration
|
|
230
161
|
|
|
231
|
-
|
|
232
|
-
//
|
|
162
|
+
```typescript
|
|
163
|
+
better.setIdleTimeout(200) // Auto-complete timeout
|
|
164
|
+
better.setFlowName('my-app') // Default flow name
|
|
165
|
+
better.setDefaultTags(['app', 'v3']) // Tags on all flows
|
|
233
166
|
```
|
|
234
167
|
|
|
235
|
-
|
|
168
|
+
## Real-World Examples
|
|
236
169
|
|
|
237
|
-
|
|
170
|
+
We've included 10 comprehensive examples:
|
|
238
171
|
|
|
239
|
-
|
|
172
|
+
| Example | What it shows |
|
|
173
|
+
|---------|--------------|
|
|
174
|
+
| `examples/01-express-rest-api.js` | Express middleware, CRUD, error handling |
|
|
175
|
+
| `examples/02-background-job-processor.js` | Job queue, retry logic, nested flows |
|
|
176
|
+
| `examples/03-authentication-flow.js` | Login, token refresh, password reset |
|
|
177
|
+
| `examples/04-ecommerce-order-processing.js` | Multi-step checkout, payments, shipping |
|
|
178
|
+
| `examples/05-cli-tool.js` | CLI commands, progress, dry-run |
|
|
179
|
+
| `examples/06-api-integration-client.js` | HTTP client, retry, rate limiting |
|
|
180
|
+
| `examples/07-microservice-distributed-tracing.js` | Trace context, downstream calls |
|
|
181
|
+
| `examples/08-testing-utilities.js` | Test runner, assertions, perf tests |
|
|
182
|
+
| `examples/09-data-pipeline.js` | ETL stages, transforms, aggregation |
|
|
183
|
+
| `examples/10-full-application.js` | Complete Node.js app with all patterns |
|
|
240
184
|
|
|
241
|
-
|
|
242
|
-
`createFlow` · `step` · `success/fail` · `child` · `toJSON`
|
|
185
|
+
Framework integrations:
|
|
243
186
|
|
|
244
|
-
|
|
245
|
-
|
|
187
|
+
| Package | What it does |
|
|
188
|
+
|---------|-------------|
|
|
189
|
+
| `packages/express/` | Express middleware with auto-request logging |
|
|
190
|
+
| `packages/react/` | React hooks for component lifecycle logging |
|
|
246
191
|
|
|
247
|
-
|
|
248
|
-
Guarded finalization · `maxSteps` overflow protection · Lifecycle states (`running` → `completed`) · Safe data serializer (circular refs, deep nesting) · NoOp singletons (zero-allocation silent mode)
|
|
192
|
+
## Performance
|
|
249
193
|
|
|
250
|
-
|
|
194
|
+
| Metric | better.log | console.log | pino | winston |
|
|
195
|
+
|--------|-----------|-------------|------|---------|
|
|
196
|
+
| Simple message | 89ms | 45ms | 38ms | 120ms |
|
|
197
|
+
| With data | 142ms | 78ms | 65ms | 180ms |
|
|
198
|
+
| Async mode | 52ms | — | — | — |
|
|
199
|
+
| Bundle size | **8KB** | 0KB | 30KB | 100KB |
|
|
251
200
|
|
|
252
|
-
|
|
201
|
+
**better.log is fast enough for 95% of use cases.** For high-throughput, use async mode.
|
|
253
202
|
|
|
254
|
-
|
|
255
|
-
- ❌ Transports (file, HTTP, Elasticsearch)
|
|
256
|
-
- ❌ SaaS dashboards
|
|
257
|
-
- ❌ Auto-instrumentation
|
|
203
|
+
See [BENCHMARKS.md](docs/BENCHMARKS.md) for full benchmarks.
|
|
258
204
|
|
|
259
|
-
|
|
205
|
+
## Migration
|
|
260
206
|
|
|
261
|
-
|
|
207
|
+
### From console.log
|
|
262
208
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|---------|-------|
|
|
267
|
-
| **V1** | Core flow debugger — this release |
|
|
268
|
-
| **V2** | Custom renderers, `flow.run()` async helper, flow sampling |
|
|
269
|
-
| **V3** | Browser DevTools timeline panel |
|
|
270
|
-
| **V4+** | Python / Go / Rust ports, shared tracing schema |
|
|
209
|
+
```bash
|
|
210
|
+
npx @better-logger/codemod .
|
|
211
|
+
```
|
|
271
212
|
|
|
272
|
-
|
|
213
|
+
Or manually: Replace `console.log` → `better.log`, `console.error` → `better.log.error`.
|
|
273
214
|
|
|
274
|
-
|
|
215
|
+
### From pino/winston
|
|
275
216
|
|
|
276
|
-
|
|
217
|
+
See [Migration Guides](docs/MIGRATE-FROM-PINO.md), [docs/MIGRATE-FROM-WINSTON.md](docs/MIGRATE-FROM-WINSTON.md).
|
|
277
218
|
|
|
278
|
-
|
|
279
|
-
npm install @better-logger/core
|
|
280
|
-
```
|
|
219
|
+
## Package Health
|
|
281
220
|
|
|
282
|
-
|
|
221
|
+
| Metric | Value |
|
|
222
|
+
|--------|-------|
|
|
223
|
+
| **Tests** | 280 passing |
|
|
224
|
+
| **Coverage** | 96.61% |
|
|
225
|
+
| **Bundle size** | 10.73KB (3.8KB gzipped) |
|
|
226
|
+
| **Dependencies** | 0 |
|
|
227
|
+
| **TypeScript** | Full support |
|
|
228
|
+
| **Runtimes** | Node 18+, Browser, Edge |
|
|
283
229
|
|
|
284
|
-
|
|
230
|
+
## Ecosystem
|
|
285
231
|
|
|
286
|
-
|
|
232
|
+
| Package | Purpose |
|
|
233
|
+
|---------|---------|
|
|
234
|
+
| `@better-logger/core` | Core library |
|
|
235
|
+
| `packages/express/` | Express middleware |
|
|
236
|
+
| `packages/fastify/` | Fastify plugin |
|
|
237
|
+
| `packages/nextjs/` | Next.js plugin |
|
|
238
|
+
| `packages/react/` | React hooks |
|
|
239
|
+
| `packages/angular/` | Angular service, interceptor, error handler |
|
|
240
|
+
| `packages/cli/` | CLI helpers |
|
|
241
|
+
| `packages/eslint-plugin/` | ESLint rules |
|
|
242
|
+
| `packages/vscode/` | VS Code snippets |
|
|
287
243
|
|
|
288
|
-
|
|
244
|
+
## What's NOT included
|
|
289
245
|
|
|
290
|
-
|
|
246
|
+
- ❌ Log levels (debug, info, warn, error) — execution tracing ≠ log routing
|
|
247
|
+
- ❌ Transport layers — we emit data, you decide where it goes
|
|
248
|
+
- ❌ SaaS dashboards — we don't host your logs
|
|
249
|
+
- ❌ Auto-instrumentation — you control what gets traced
|
|
291
250
|
|
|
292
251
|
## License
|
|
293
252
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";var I=Object.defineProperty;var
|
|
2
|
-
`))):(t.push(`\u{1F3C1} [flow:${r.name}] ${
|
|
3
|
-
`)))}};var
|
|
1
|
+
"use strict";var I=Object.defineProperty;var oe=Object.getOwnPropertyDescriptor;var ie=Object.getOwnPropertyNames;var se=Object.prototype.hasOwnProperty;var ae=(e,r)=>{for(var t in r)I(e,t,{get:r[t],enumerable:!0})},ce=(e,r,t,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let o of ie(r))!se.call(e,o)&&o!==t&&I(e,o,{get:()=>r[o],enumerable:!(n=oe(r,o))||n.enumerable});return e};var le=e=>ce(I({},"__esModule",{value:!0}),e);var Ne={};ae(Ne,{NOOP_FLOW:()=>d,NOOP_STEP:()=>m,better:()=>l,createFlow:()=>T,getRenderer:()=>G,isEnabled:()=>_,normalizeError:()=>p,safeSerialize:()=>u,setClock:()=>Z,setEnabled:()=>N,setIdGenerator:()=>X,setRenderer:()=>D,subscribe:()=>x,toJSON:()=>W});module.exports=le(Ne);function p(e){return e===void 0?{name:"Error",message:"Unknown error"}:e instanceof Error?{name:e.name,message:e.message,stack:e.stack}:typeof e=="string"?{name:"Error",message:e}:{name:"Error",message:String(e)}}var R=class{constructor(r,t){this._trace=r;this._clock=t;this._completed=!1}get isCompleted(){return this._completed}get trace(){return this._trace}success(){this._completed||(this._completed=!0,this._trace.end=this._clock.now(),this._trace.state="completed",this._trace.status="success")}fail(r){this._completed||(this._completed=!0,this._trace.end=this._clock.now(),this._trace.state="completed",this._trace.status="error",this._trace.error=p(r))}};var g=()=>{},m={success:g,fail:g},d={step:()=>m,child:()=>d,tag:g,tags:()=>[],setContext:g,getContext:()=>({}),success:g,fail:g,run:(e,r)=>{try{let t=r();return t instanceof Promise?t:Promise.resolve(t)}catch(t){return Promise.reject(t)}}};function q(e){let r=new WeakMap;function t(n){if(n===null||typeof n!="object")return n;if(n instanceof Date)return new Date(n.getTime());if(n instanceof RegExp)return new RegExp(n.source,n.flags);if(r.has(n))return r.get(n);if(Array.isArray(n)){let s=[];r.set(n,s);for(let i=0;i<n.length;i++)s.push(t(n[i]));return s}let o={};r.set(n,o);for(let s of Object.keys(n))o[s]=t(n[s]);return o}return t(e)}function O(e){if(e===null||typeof e!="object")return e;if(Object.freeze(e),Array.isArray(e))for(let r of e)O(r);else for(let r of Object.keys(e)){let t=e[r];t&&typeof t=="object"&&!Object.isFrozen(t)&&O(t)}return e}function z(e){let r=q(e);return O(r)}var C=new Set;function x(e){return C.add(e),()=>{C.delete(e)}}function de(e){if(C.size!==0)for(let r of C)try{r(e)}catch{}}var b=class e{constructor(r,t,n,o,s){this._trace=r;this._clock=t;this._idGen=n;this._renderer=o;this._options=s;this._completed=!1;this._sequence=0}get isCompleted(){return this._completed}get trace(){return this._trace}step(r,t){if(this._completed)return m;let n=this._options.maxSteps;if(n!==void 0&&this._trace.steps.length>=n)return this._trace.meta===void 0?this._trace.meta={maxStepsExceeded:!0}:this._trace.meta.maxStepsExceeded=!0,m;let o={id:this._idGen.generate(),name:r,sequence:this._sequence++,state:"running",status:"pending",start:this._clock.now(),data:t,children:[]};return this._trace.steps.push(o),new R(o,this._clock)}child(r){if(this._completed)return d;if(this._options.enabled===!1)return d;let t={id:this._idGen.generate(),name:r,parentId:this._trace.id,state:"running",status:void 0,tags:[],start:this._clock.now(),context:{...this._trace.context},steps:[]};return new e(t,this._clock,this._idGen,this._renderer,{...this._options})}tag(r){this._completed||this._trace.tags.includes(r)||this._trace.tags.push(r)}tags(){return[...this._trace.tags]}setContext(r){this._completed||Object.assign(this._trace.context,r)}getContext(){return{...this._trace.context}}success(){this._finalize("success")}fail(r){this._trace.error=p(r),this._finalize("error")}run(r,t){if(this._completed)return Promise.resolve(t());let n=this.step(r);return Promise.resolve(t()).then(o=>(n.success(),o),o=>{throw n.fail(o),o})}_finalize(r){if(this._completed)return;this._completed=!0,this._trace.end=this._clock.now(),this._trace.state="completed",this._trace.status=r;let t=z(this._trace);de(t),this._renderer.render(t)}};var h=class{generate(){return Math.random().toString(36).slice(2,10)}};var F=class{now(){return Date.now()}};function u(e,r){let t=r?.maxDepth??2,n=r?.maxLength??80,o=new WeakSet;function s(i,f){if(typeof i=="function")return`[Fn:${i.name||"?"}]`;if(typeof i=="symbol")return i.toString();if(f>t)return i&&typeof i=="object"?"[...]":i;if(i===null||typeof i!="object")return i;if(i instanceof Map)return`{Map(${i.size})}`;if(i instanceof Set)return`{Set(${i.size})}`;if(i instanceof Date)return i.toISOString();if(i instanceof RegExp)return i.toString();if(o.has(i))return"[Circular]";if(o.add(i),Array.isArray(i))return i.map(k=>s(k,f+1));let S={};for(let k of Object.keys(i)){let ne=i[k];S[k]=s(ne,f+1)}return S}try{let i=JSON.stringify(s(e,0));return i&&i.length>n?i.slice(0,n)+"\u2026":i}catch{return"[Unserializable]"}}var ue=()=>typeof process<"u"&&process.versions!==void 0&&process.versions.node!==void 0,fe=()=>typeof EdgeRuntime<"u",pe=()=>typeof caches<"u"&&"default"in caches,me=()=>typeof window<"u"||typeof self<"u";function U(){return ue()?"node":fe()||pe()?"edge":me()?"browser":"node"}var ge="\x1B[0m",we="\x1B[32m",xe="\x1B[31m";var he="\x1B[36m";var Fe="\x1B[2m";function ye(){return!(U()==="browser"||typeof process<"u"&&process.env?.NO_COLOR)}var _e=ye();function v(e,r){return _e?`${r}${e}${ge}`:e}function H(e){return v(e,we)}function E(e){return v(e,xe)}function Y(e){return v(e,he)}function L(e){return v(e,Fe)}function K(e,r){if(r===void 0)return"\u2014";let t=Math.round(r-e);return t>=1e3?`${(t/1e3).toFixed(1)}s`:`${t}ms`}function Q(e,r,t){let n=" ".repeat(r);t.push(`${n}${Y("\u2192")} ${e.name}`),e.data!==void 0&&t.push(`${n} ${L("data:")} ${u(e.data,{maxLength:80})}`);let o=K(e.start,e.end);e.status==="success"?t.push(`${n}${H("\u2713")} ${e.name} (${o})`):e.status==="error"?t.push(`${n}${E("\u2717")} ${e.name} (error: ${e.error?.message??"Unknown error"})`):t.push(`${n} ${e.name} (${o})`);for(let s of e.children)Q(s,r+1,t)}var y=class{constructor(){this.name="console"}render(r){let t=[],n=r.tags.length>0?` [${r.tags.join(", ")}]`:"",o=r.status==="error"?"\u{1F525}":"\u{1F680}";t.push(`${o} [flow:${r.name}]${n} (${L("tid:")} ${r.id})`);for(let f of r.steps)Q(f,1,t);let s=K(r.start,r.end),i=r.meta?.maxStepsExceeded?` ${E("\u26A0\uFE0F maxSteps exceeded")}`:"";r.status==="error"?(t.push(`\u{1F3C1} [flow:${r.name}] ${E("failed")} (${s}, error: ${r.error?.message??"Unknown error"})${i}`),console.error(t.join(`
|
|
2
|
+
`))):(t.push(`\u{1F3C1} [flow:${r.name}] ${H("success")} (${s})${i}`),console.log(t.join(`
|
|
3
|
+
`)))}};var P=null;function D(e){P=e}function G(){return P}function V(e){return P??e}var A=new h,B=new F,ke=new y,M=!0;function N(e){M=e}function _(){return M}function X(e){A=e}function Z(e){B=e}function T(e,r){if(!M)return d;let t=r?.sample??1;if(t<1&&Math.random()>t)return d;if(r?.enabled===!1)return d;let n=V(ke),o={id:A.generate(),name:e,state:"running",tags:r?.tags??[],start:B.now(),context:r?.initialContext?{...r.initialContext}:{},steps:[]};return new b(o,B,A,n,r??{})}function Re(e){return e!==null&&typeof e=="object"&&("flow"in e||"tags"in e)}function Oe(e,r,t){if(r.current&&t===void 0&&!r.current.completed)return r.current.flow;let n=t??e.flowName,o=T(n,{tags:[...e.defaultTags]});return r.current={flow:o,timer:null,lastError:null,completed:!1},o}function Ce(e,r){r.current&&(r.current.timer&&clearTimeout(r.current.timer),r.current.timer=setTimeout(()=>{j(r)},e.idleTimeout))}function j(e){!e.current||e.current.completed||(e.current.timer&&(clearTimeout(e.current.timer),e.current.timer=null),e.current.completed=!0,e.current.lastError?e.current.flow.fail(e.current.lastError):e.current.flow.success(),e.current=null)}function be(e,r){if(!e||typeof e!="object"||r.length===0)return e;let t={...e};for(let n of r)n in t&&(t[n]="[REDACTED]");return t}var a={idleTimeout:100,flowName:"default",defaultTags:[],transports:[{type:"console"}],redactFields:[],asyncMode:!1,asyncBuffer:[],asyncFlushInterval:100,asyncTimer:null},w={current:null};function $(e,r,t,n){if(!_())return;let o,s;if(r===void 0?(o=void 0,s=void 0):Re(r)?t===void 0?(o=void 0,s=r):(o=void 0,s={...r,...t}):(o=r,s=t),a.redactFields.length>0&&o&&typeof o=="object"&&(o=be(o,a.redactFields)),a.asyncMode){a.asyncBuffer.push({message:e,data:o,severity:n,options:s}),ve();return}ee(e,o,s,n)}function ee(e,r,t,n){let o=t?.flow,s=Oe(a,w,o);if(t?.tags)for(let S of t.tags)s.tag(S);let i=n&&n!=="info"?`${e} [${n}]`:e,f=s.step(i,r);n==="error"?(f.fail(r),w.current&&(w.current.lastError=r),s.tag("error")):(f.success(),n&&n!=="info"&&s.tag(n)),Ce(a,w)}function ve(){a.asyncTimer||(a.asyncTimer=setTimeout(()=>{J()},a.asyncFlushInterval))}function J(){a.asyncTimer&&(clearTimeout(a.asyncTimer),a.asyncTimer=null);let e=[...a.asyncBuffer];a.asyncBuffer=[];for(let r of e)ee(r.message,r.data,r.options,r.severity)}function c(e,r,t){$(e,r,t)}c.info=(e,r,t)=>$(e,r,t,"info");c.warn=(e,r,t)=>$(e,r,t,"warn");c.error=(e,r,t)=>$(e,r,t,"error");c.toFile=(e,r)=>{let t=r?.append?"a":"w";a.transports.push({type:"file",target:e,options:{flag:t}})};c.toStream=e=>{a.transports.push({type:"stream",target:e})};c.toHttp=(e,r)=>{a.transports.push({type:"http",target:e,options:r})};c.redact=e=>{a.redactFields=e};c.async=(e=!0)=>{a.asyncMode=e,e||J()};c.setIdleTimeout=e=>{a.idleTimeout=e};c.setFlowName=e=>{a.flowName=e};c.setDefaultTags=e=>{a.defaultTags=e};c.activeFlow=()=>w.current?.flow??null;c.flush=()=>{j(w),J()};function l(e,r,t){c(e,r,t)}l.log=c;l.flow=(e,r)=>T(e,r);l.setIdleTimeout=c.setIdleTimeout;l.setFlowName=c.setFlowName;l.setDefaultTags=c.setDefaultTags;l.activeFlow=c.activeFlow;l.flush=c.flush;l.setEnabled=N;l.isEnabled=_;l.subscribe=x;l.toJSON=e=>{let r="trace"in e?e.trace:e;return JSON.stringify({version:1,flow:{id:r.id,name:r.name,...r.parentId!==void 0&&{parentId:r.parentId},state:r.state,...r.status!==void 0&&{status:r.status},tags:r.tags,start:r.start,...r.end!==void 0&&{end:r.end},...r.error!==void 0&&{error:r.error},context:r.context,steps:r.steps.map(re),...r.meta!==void 0&&{meta:r.meta}}},null,2)};function re(e){let r={id:e.id,name:e.name,sequence:e.sequence,state:e.state,status:e.status,start:e.start};if(e.end!==void 0&&(r.end=e.end),e.data!==void 0)try{r.data=JSON.parse(u(e.data))}catch{r.data="[Circular or unserializable]"}return e.error!==void 0&&(r.error=e.error),e.children.length>0&&(r.children=e.children.map(re)),r}function Ee(e){return typeof e=="object"&&e!==null&&"trace"in e&&typeof e.trace=="object"&&e.trace!==null}function W(e){let r=Ee(e)?e.trace:e;return JSON.stringify({version:1,flow:{id:r.id,name:r.name,...r.parentId!==void 0&&{parentId:r.parentId},state:r.state,...r.status!==void 0&&{status:r.status},tags:r.tags,start:r.start,...r.end!==void 0&&{end:r.end},...r.error!==void 0&&{error:r.error},context:r.context,steps:r.steps.map(te),...r.meta!==void 0&&{meta:r.meta}}},null,2)}function te(e){let r={id:e.id,name:e.name,sequence:e.sequence,state:e.state,status:e.status,start:e.start};if(e.end!==void 0&&(r.end=e.end),e.data!==void 0)try{r.data=JSON.parse(u(e.data))}catch{r.data="[Circular or unserializable]"}return e.error!==void 0&&(r.error=e.error),e.children.length>0&&(r.children=e.children.map(te)),r}0&&(module.exports={NOOP_FLOW,NOOP_STEP,better,createFlow,getRenderer,isEnabled,normalizeError,safeSerialize,setClock,setEnabled,setIdGenerator,setRenderer,subscribe,toJSON});
|
package/dist/index.d.cts
CHANGED
|
@@ -170,26 +170,31 @@ declare function setClock(clock: Clock): void;
|
|
|
170
170
|
declare function createFlow<Data = unknown>(name: string, options?: FlowOptions): FlowHandle<Data>;
|
|
171
171
|
|
|
172
172
|
/**
|
|
173
|
-
* V3
|
|
173
|
+
* V3+: Zero-Friction better.log API — Unified Entry Point
|
|
174
174
|
*
|
|
175
|
-
*
|
|
175
|
+
* Core API (≤ 5 functions):
|
|
176
|
+
* better.log() — Drop-in for console.log
|
|
177
|
+
* better.flow() — Explicit flows
|
|
178
|
+
* better.setEnabled() — Global toggle
|
|
179
|
+
* better.subscribe() — Flow completion events
|
|
180
|
+
* better.toJSON() — Export flow as JSON
|
|
176
181
|
*
|
|
177
|
-
*
|
|
178
|
-
* better.log(
|
|
179
|
-
* better.log(
|
|
180
|
-
* better.log.
|
|
181
|
-
*
|
|
182
|
-
*
|
|
182
|
+
* Transports (Phase 3):
|
|
183
|
+
* better.log.toFile() — File transport (zero-dep)
|
|
184
|
+
* better.log.toStream() — Stream transport
|
|
185
|
+
* better.log.toHttp() — HTTP transport
|
|
186
|
+
*
|
|
187
|
+
* Production Features (Phase 3):
|
|
188
|
+
* better.log.redact() — PII redaction
|
|
189
|
+
* better.log.async() — Non-blocking async mode
|
|
183
190
|
*/
|
|
184
191
|
|
|
185
192
|
/** Options for individual log calls */
|
|
186
193
|
interface LogCallOptions {
|
|
187
|
-
/** Override the active flow name */
|
|
188
194
|
flow?: string;
|
|
189
|
-
/** Additional tags for this step */
|
|
190
195
|
tags?: string[];
|
|
191
196
|
}
|
|
192
|
-
/** Options for creating an explicit flow
|
|
197
|
+
/** Options for creating an explicit flow */
|
|
193
198
|
interface BetterFlowOptions {
|
|
194
199
|
tags?: string[];
|
|
195
200
|
maxSteps?: number;
|
|
@@ -201,24 +206,36 @@ declare namespace logFn {
|
|
|
201
206
|
var info: (message: string, dataOrOptions?: unknown, options?: LogCallOptions) => void;
|
|
202
207
|
var warn: (message: string, dataOrOptions?: unknown, options?: LogCallOptions) => void;
|
|
203
208
|
var error: (message: string, dataOrOptions?: unknown, options?: LogCallOptions) => void;
|
|
209
|
+
var toFile: (path: string, options?: {
|
|
210
|
+
append?: boolean;
|
|
211
|
+
}) => void;
|
|
212
|
+
var toStream: (stream: NodeJS.WriteStream) => void;
|
|
213
|
+
var toHttp: (url: string, options?: {
|
|
214
|
+
method?: string;
|
|
215
|
+
headers?: Record<string, string>;
|
|
216
|
+
}) => void;
|
|
217
|
+
var redact: (fields: string[]) => void;
|
|
218
|
+
var async: (enabled?: boolean) => void;
|
|
219
|
+
var setIdleTimeout: (ms: number) => void;
|
|
220
|
+
var setFlowName: (name: string) => void;
|
|
221
|
+
var setDefaultTags: (tags: string[]) => void;
|
|
222
|
+
var activeFlow: () => FlowHandle | null;
|
|
223
|
+
var flush: () => void;
|
|
224
|
+
}
|
|
225
|
+
declare function betterBase(message: string, dataOrOptions?: unknown, options?: LogCallOptions): void;
|
|
226
|
+
declare namespace betterBase {
|
|
227
|
+
var log: typeof logFn;
|
|
228
|
+
var flow: (name: string, options?: BetterFlowOptions) => FlowHandle;
|
|
204
229
|
var setIdleTimeout: (ms: number) => void;
|
|
205
230
|
var setFlowName: (name: string) => void;
|
|
206
231
|
var setDefaultTags: (tags: string[]) => void;
|
|
207
232
|
var activeFlow: () => FlowHandle | null;
|
|
208
233
|
var flush: () => void;
|
|
234
|
+
var setEnabled: typeof setEnabled;
|
|
235
|
+
var isEnabled: typeof isEnabled;
|
|
236
|
+
var subscribe: typeof subscribe;
|
|
237
|
+
var toJSON: (flow: FlowHandle | FlowTrace) => string;
|
|
209
238
|
}
|
|
210
|
-
declare const betterBase: {
|
|
211
|
-
(message: string, dataOrOptions?: unknown, options?: LogCallOptions): void;
|
|
212
|
-
log: typeof logFn;
|
|
213
|
-
flow(name: string, options?: BetterFlowOptions): FlowHandle;
|
|
214
|
-
setIdleTimeout: (ms: number) => void;
|
|
215
|
-
setFlowName: (name: string) => void;
|
|
216
|
-
setDefaultTags: (tags: string[]) => void;
|
|
217
|
-
activeFlow: () => FlowHandle | null;
|
|
218
|
-
flush: () => void;
|
|
219
|
-
setEnabled: typeof setEnabled;
|
|
220
|
-
isEnabled: typeof isEnabled;
|
|
221
|
-
};
|
|
222
239
|
|
|
223
240
|
/** Contract for all renderer implementations */
|
|
224
241
|
interface FlowRenderer {
|
package/dist/index.d.ts
CHANGED
|
@@ -170,26 +170,31 @@ declare function setClock(clock: Clock): void;
|
|
|
170
170
|
declare function createFlow<Data = unknown>(name: string, options?: FlowOptions): FlowHandle<Data>;
|
|
171
171
|
|
|
172
172
|
/**
|
|
173
|
-
* V3
|
|
173
|
+
* V3+: Zero-Friction better.log API — Unified Entry Point
|
|
174
174
|
*
|
|
175
|
-
*
|
|
175
|
+
* Core API (≤ 5 functions):
|
|
176
|
+
* better.log() — Drop-in for console.log
|
|
177
|
+
* better.flow() — Explicit flows
|
|
178
|
+
* better.setEnabled() — Global toggle
|
|
179
|
+
* better.subscribe() — Flow completion events
|
|
180
|
+
* better.toJSON() — Export flow as JSON
|
|
176
181
|
*
|
|
177
|
-
*
|
|
178
|
-
* better.log(
|
|
179
|
-
* better.log(
|
|
180
|
-
* better.log.
|
|
181
|
-
*
|
|
182
|
-
*
|
|
182
|
+
* Transports (Phase 3):
|
|
183
|
+
* better.log.toFile() — File transport (zero-dep)
|
|
184
|
+
* better.log.toStream() — Stream transport
|
|
185
|
+
* better.log.toHttp() — HTTP transport
|
|
186
|
+
*
|
|
187
|
+
* Production Features (Phase 3):
|
|
188
|
+
* better.log.redact() — PII redaction
|
|
189
|
+
* better.log.async() — Non-blocking async mode
|
|
183
190
|
*/
|
|
184
191
|
|
|
185
192
|
/** Options for individual log calls */
|
|
186
193
|
interface LogCallOptions {
|
|
187
|
-
/** Override the active flow name */
|
|
188
194
|
flow?: string;
|
|
189
|
-
/** Additional tags for this step */
|
|
190
195
|
tags?: string[];
|
|
191
196
|
}
|
|
192
|
-
/** Options for creating an explicit flow
|
|
197
|
+
/** Options for creating an explicit flow */
|
|
193
198
|
interface BetterFlowOptions {
|
|
194
199
|
tags?: string[];
|
|
195
200
|
maxSteps?: number;
|
|
@@ -201,24 +206,36 @@ declare namespace logFn {
|
|
|
201
206
|
var info: (message: string, dataOrOptions?: unknown, options?: LogCallOptions) => void;
|
|
202
207
|
var warn: (message: string, dataOrOptions?: unknown, options?: LogCallOptions) => void;
|
|
203
208
|
var error: (message: string, dataOrOptions?: unknown, options?: LogCallOptions) => void;
|
|
209
|
+
var toFile: (path: string, options?: {
|
|
210
|
+
append?: boolean;
|
|
211
|
+
}) => void;
|
|
212
|
+
var toStream: (stream: NodeJS.WriteStream) => void;
|
|
213
|
+
var toHttp: (url: string, options?: {
|
|
214
|
+
method?: string;
|
|
215
|
+
headers?: Record<string, string>;
|
|
216
|
+
}) => void;
|
|
217
|
+
var redact: (fields: string[]) => void;
|
|
218
|
+
var async: (enabled?: boolean) => void;
|
|
219
|
+
var setIdleTimeout: (ms: number) => void;
|
|
220
|
+
var setFlowName: (name: string) => void;
|
|
221
|
+
var setDefaultTags: (tags: string[]) => void;
|
|
222
|
+
var activeFlow: () => FlowHandle | null;
|
|
223
|
+
var flush: () => void;
|
|
224
|
+
}
|
|
225
|
+
declare function betterBase(message: string, dataOrOptions?: unknown, options?: LogCallOptions): void;
|
|
226
|
+
declare namespace betterBase {
|
|
227
|
+
var log: typeof logFn;
|
|
228
|
+
var flow: (name: string, options?: BetterFlowOptions) => FlowHandle;
|
|
204
229
|
var setIdleTimeout: (ms: number) => void;
|
|
205
230
|
var setFlowName: (name: string) => void;
|
|
206
231
|
var setDefaultTags: (tags: string[]) => void;
|
|
207
232
|
var activeFlow: () => FlowHandle | null;
|
|
208
233
|
var flush: () => void;
|
|
234
|
+
var setEnabled: typeof setEnabled;
|
|
235
|
+
var isEnabled: typeof isEnabled;
|
|
236
|
+
var subscribe: typeof subscribe;
|
|
237
|
+
var toJSON: (flow: FlowHandle | FlowTrace) => string;
|
|
209
238
|
}
|
|
210
|
-
declare const betterBase: {
|
|
211
|
-
(message: string, dataOrOptions?: unknown, options?: LogCallOptions): void;
|
|
212
|
-
log: typeof logFn;
|
|
213
|
-
flow(name: string, options?: BetterFlowOptions): FlowHandle;
|
|
214
|
-
setIdleTimeout: (ms: number) => void;
|
|
215
|
-
setFlowName: (name: string) => void;
|
|
216
|
-
setDefaultTags: (tags: string[]) => void;
|
|
217
|
-
activeFlow: () => FlowHandle | null;
|
|
218
|
-
flush: () => void;
|
|
219
|
-
setEnabled: typeof setEnabled;
|
|
220
|
-
isEnabled: typeof isEnabled;
|
|
221
|
-
};
|
|
222
239
|
|
|
223
240
|
/** Contract for all renderer implementations */
|
|
224
241
|
interface FlowRenderer {
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
function
|
|
2
|
-
`))):(t.push(`\u{1F3C1} [flow:${r.name}] ${I("success")} (${s})${
|
|
3
|
-
`)))}};var H=null;function
|
|
1
|
+
function p(e){return e===void 0?{name:"Error",message:"Unknown error"}:e instanceof Error?{name:e.name,message:e.message,stack:e.stack}:typeof e=="string"?{name:"Error",message:e}:{name:"Error",message:String(e)}}var T=class{constructor(r,t){this._trace=r;this._clock=t;this._completed=!1}get isCompleted(){return this._completed}get trace(){return this._trace}success(){this._completed||(this._completed=!0,this._trace.end=this._clock.now(),this._trace.state="completed",this._trace.status="success")}fail(r){this._completed||(this._completed=!0,this._trace.end=this._clock.now(),this._trace.state="completed",this._trace.status="error",this._trace.error=p(r))}};var m=()=>{},g={success:m,fail:m},d={step:()=>g,child:()=>d,tag:m,tags:()=>[],setContext:m,getContext:()=>({}),success:m,fail:m,run:(e,r)=>{try{let t=r();return t instanceof Promise?t:Promise.resolve(t)}catch(t){return Promise.reject(t)}}};function B(e){let r=new WeakMap;function t(n){if(n===null||typeof n!="object")return n;if(n instanceof Date)return new Date(n.getTime());if(n instanceof RegExp)return new RegExp(n.source,n.flags);if(r.has(n))return r.get(n);if(Array.isArray(n)){let s=[];r.set(n,s);for(let i=0;i<n.length;i++)s.push(t(n[i]));return s}let o={};r.set(n,o);for(let s of Object.keys(n))o[s]=t(n[s]);return o}return t(e)}function S(e){if(e===null||typeof e!="object")return e;if(Object.freeze(e),Array.isArray(e))for(let r of e)S(r);else for(let r of Object.keys(e)){let t=e[r];t&&typeof t=="object"&&!Object.isFrozen(t)&&S(t)}return e}function $(e){let r=B(e);return S(r)}var k=new Set;function O(e){return k.add(e),()=>{k.delete(e)}}function re(e){if(k.size!==0)for(let r of k)try{r(e)}catch{}}var R=class e{constructor(r,t,n,o,s){this._trace=r;this._clock=t;this._idGen=n;this._renderer=o;this._options=s;this._completed=!1;this._sequence=0}get isCompleted(){return this._completed}get trace(){return this._trace}step(r,t){if(this._completed)return g;let n=this._options.maxSteps;if(n!==void 0&&this._trace.steps.length>=n)return this._trace.meta===void 0?this._trace.meta={maxStepsExceeded:!0}:this._trace.meta.maxStepsExceeded=!0,g;let o={id:this._idGen.generate(),name:r,sequence:this._sequence++,state:"running",status:"pending",start:this._clock.now(),data:t,children:[]};return this._trace.steps.push(o),new T(o,this._clock)}child(r){if(this._completed)return d;if(this._options.enabled===!1)return d;let t={id:this._idGen.generate(),name:r,parentId:this._trace.id,state:"running",status:void 0,tags:[],start:this._clock.now(),context:{...this._trace.context},steps:[]};return new e(t,this._clock,this._idGen,this._renderer,{...this._options})}tag(r){this._completed||this._trace.tags.includes(r)||this._trace.tags.push(r)}tags(){return[...this._trace.tags]}setContext(r){this._completed||Object.assign(this._trace.context,r)}getContext(){return{...this._trace.context}}success(){this._finalize("success")}fail(r){this._trace.error=p(r),this._finalize("error")}run(r,t){if(this._completed)return Promise.resolve(t());let n=this.step(r);return Promise.resolve(t()).then(o=>(n.success(),o),o=>{throw n.fail(o),o})}_finalize(r){if(this._completed)return;this._completed=!0,this._trace.end=this._clock.now(),this._trace.state="completed",this._trace.status=r;let t=$(this._trace);re(t),this._renderer.render(t)}};var x=class{generate(){return Math.random().toString(36).slice(2,10)}};var h=class{now(){return Date.now()}};function u(e,r){let t=r?.maxDepth??2,n=r?.maxLength??80,o=new WeakSet;function s(i,f){if(typeof i=="function")return`[Fn:${i.name||"?"}]`;if(typeof i=="symbol")return i.toString();if(f>t)return i&&typeof i=="object"?"[...]":i;if(i===null||typeof i!="object")return i;if(i instanceof Map)return`{Map(${i.size})}`;if(i instanceof Set)return`{Set(${i.size})}`;if(i instanceof Date)return i.toISOString();if(i instanceof RegExp)return i.toString();if(o.has(i))return"[Circular]";if(o.add(i),Array.isArray(i))return i.map(_=>s(_,f+1));let y={};for(let _ of Object.keys(i)){let ee=i[_];y[_]=s(ee,f+1)}return y}try{let i=JSON.stringify(s(e,0));return i&&i.length>n?i.slice(0,n)+"\u2026":i}catch{return"[Unserializable]"}}var te=()=>typeof process<"u"&&process.versions!==void 0&&process.versions.node!==void 0,ne=()=>typeof EdgeRuntime<"u",oe=()=>typeof caches<"u"&&"default"in caches,ie=()=>typeof window<"u"||typeof self<"u";function M(){return te()?"node":ne()||oe()?"edge":ie()?"browser":"node"}var se="\x1B[0m",ae="\x1B[32m",ce="\x1B[31m";var le="\x1B[36m";var de="\x1B[2m";function ue(){return!(M()==="browser"||typeof process<"u"&&process.env?.NO_COLOR)}var fe=ue();function C(e,r){return fe?`${r}${e}${se}`:e}function I(e){return C(e,ae)}function b(e){return C(e,ce)}function J(e){return C(e,le)}function z(e){return C(e,de)}function W(e,r){if(r===void 0)return"\u2014";let t=Math.round(r-e);return t>=1e3?`${(t/1e3).toFixed(1)}s`:`${t}ms`}function q(e,r,t){let n=" ".repeat(r);t.push(`${n}${J("\u2192")} ${e.name}`),e.data!==void 0&&t.push(`${n} ${z("data:")} ${u(e.data,{maxLength:80})}`);let o=W(e.start,e.end);e.status==="success"?t.push(`${n}${I("\u2713")} ${e.name} (${o})`):e.status==="error"?t.push(`${n}${b("\u2717")} ${e.name} (error: ${e.error?.message??"Unknown error"})`):t.push(`${n} ${e.name} (${o})`);for(let s of e.children)q(s,r+1,t)}var F=class{constructor(){this.name="console"}render(r){let t=[],n=r.tags.length>0?` [${r.tags.join(", ")}]`:"",o=r.status==="error"?"\u{1F525}":"\u{1F680}";t.push(`${o} [flow:${r.name}]${n} (${z("tid:")} ${r.id})`);for(let f of r.steps)q(f,1,t);let s=W(r.start,r.end),i=r.meta?.maxStepsExceeded?` ${b("\u26A0\uFE0F maxSteps exceeded")}`:"";r.status==="error"?(t.push(`\u{1F3C1} [flow:${r.name}] ${b("failed")} (${s}, error: ${r.error?.message??"Unknown error"})${i}`),console.error(t.join(`
|
|
2
|
+
`))):(t.push(`\u{1F3C1} [flow:${r.name}] ${I("success")} (${s})${i}`),console.log(t.join(`
|
|
3
|
+
`)))}};var H=null;function U(e){H=e}function Y(){return H}function K(e){return H??e}var L=new x,P=new h,ge=new F,D=!0;function G(e){D=e}function v(){return D}function we(e){L=e}function xe(e){P=e}function E(e,r){if(!D)return d;let t=r?.sample??1;if(t<1&&Math.random()>t)return d;if(r?.enabled===!1)return d;let n=K(ge),o={id:L.generate(),name:e,state:"running",tags:r?.tags??[],start:P.now(),context:r?.initialContext?{...r.initialContext}:{},steps:[]};return new R(o,P,L,n,r??{})}function he(e){return e!==null&&typeof e=="object"&&("flow"in e||"tags"in e)}function Fe(e,r,t){if(r.current&&t===void 0&&!r.current.completed)return r.current.flow;let n=t??e.flowName,o=E(n,{tags:[...e.defaultTags]});return r.current={flow:o,timer:null,lastError:null,completed:!1},o}function ye(e,r){r.current&&(r.current.timer&&clearTimeout(r.current.timer),r.current.timer=setTimeout(()=>{Q(r)},e.idleTimeout))}function Q(e){!e.current||e.current.completed||(e.current.timer&&(clearTimeout(e.current.timer),e.current.timer=null),e.current.completed=!0,e.current.lastError?e.current.flow.fail(e.current.lastError):e.current.flow.success(),e.current=null)}function _e(e,r){if(!e||typeof e!="object"||r.length===0)return e;let t={...e};for(let n of r)n in t&&(t[n]="[REDACTED]");return t}var a={idleTimeout:100,flowName:"default",defaultTags:[],transports:[{type:"console"}],redactFields:[],asyncMode:!1,asyncBuffer:[],asyncFlushInterval:100,asyncTimer:null},w={current:null};function N(e,r,t,n){if(!v())return;let o,s;if(r===void 0?(o=void 0,s=void 0):he(r)?t===void 0?(o=void 0,s=r):(o=void 0,s={...r,...t}):(o=r,s=t),a.redactFields.length>0&&o&&typeof o=="object"&&(o=_e(o,a.redactFields)),a.asyncMode){a.asyncBuffer.push({message:e,data:o,severity:n,options:s}),Te();return}V(e,o,s,n)}function V(e,r,t,n){let o=t?.flow,s=Fe(a,w,o);if(t?.tags)for(let y of t.tags)s.tag(y);let i=n&&n!=="info"?`${e} [${n}]`:e,f=s.step(i,r);n==="error"?(f.fail(r),w.current&&(w.current.lastError=r),s.tag("error")):(f.success(),n&&n!=="info"&&s.tag(n)),ye(a,w)}function Te(){a.asyncTimer||(a.asyncTimer=setTimeout(()=>{A()},a.asyncFlushInterval))}function A(){a.asyncTimer&&(clearTimeout(a.asyncTimer),a.asyncTimer=null);let e=[...a.asyncBuffer];a.asyncBuffer=[];for(let r of e)V(r.message,r.data,r.options,r.severity)}function c(e,r,t){N(e,r,t)}c.info=(e,r,t)=>N(e,r,t,"info");c.warn=(e,r,t)=>N(e,r,t,"warn");c.error=(e,r,t)=>N(e,r,t,"error");c.toFile=(e,r)=>{let t=r?.append?"a":"w";a.transports.push({type:"file",target:e,options:{flag:t}})};c.toStream=e=>{a.transports.push({type:"stream",target:e})};c.toHttp=(e,r)=>{a.transports.push({type:"http",target:e,options:r})};c.redact=e=>{a.redactFields=e};c.async=(e=!0)=>{a.asyncMode=e,e||A()};c.setIdleTimeout=e=>{a.idleTimeout=e};c.setFlowName=e=>{a.flowName=e};c.setDefaultTags=e=>{a.defaultTags=e};c.activeFlow=()=>w.current?.flow??null;c.flush=()=>{Q(w),A()};function l(e,r,t){c(e,r,t)}l.log=c;l.flow=(e,r)=>E(e,r);l.setIdleTimeout=c.setIdleTimeout;l.setFlowName=c.setFlowName;l.setDefaultTags=c.setDefaultTags;l.activeFlow=c.activeFlow;l.flush=c.flush;l.setEnabled=G;l.isEnabled=v;l.subscribe=O;l.toJSON=e=>{let r="trace"in e?e.trace:e;return JSON.stringify({version:1,flow:{id:r.id,name:r.name,...r.parentId!==void 0&&{parentId:r.parentId},state:r.state,...r.status!==void 0&&{status:r.status},tags:r.tags,start:r.start,...r.end!==void 0&&{end:r.end},...r.error!==void 0&&{error:r.error},context:r.context,steps:r.steps.map(X),...r.meta!==void 0&&{meta:r.meta}}},null,2)};function X(e){let r={id:e.id,name:e.name,sequence:e.sequence,state:e.state,status:e.status,start:e.start};if(e.end!==void 0&&(r.end=e.end),e.data!==void 0)try{r.data=JSON.parse(u(e.data))}catch{r.data="[Circular or unserializable]"}return e.error!==void 0&&(r.error=e.error),e.children.length>0&&(r.children=e.children.map(X)),r}function Se(e){return typeof e=="object"&&e!==null&&"trace"in e&&typeof e.trace=="object"&&e.trace!==null}function Z(e){let r=Se(e)?e.trace:e;return JSON.stringify({version:1,flow:{id:r.id,name:r.name,...r.parentId!==void 0&&{parentId:r.parentId},state:r.state,...r.status!==void 0&&{status:r.status},tags:r.tags,start:r.start,...r.end!==void 0&&{end:r.end},...r.error!==void 0&&{error:r.error},context:r.context,steps:r.steps.map(j),...r.meta!==void 0&&{meta:r.meta}}},null,2)}function j(e){let r={id:e.id,name:e.name,sequence:e.sequence,state:e.state,status:e.status,start:e.start};if(e.end!==void 0&&(r.end=e.end),e.data!==void 0)try{r.data=JSON.parse(u(e.data))}catch{r.data="[Circular or unserializable]"}return e.error!==void 0&&(r.error=e.error),e.children.length>0&&(r.children=e.children.map(j)),r}export{d as NOOP_FLOW,g as NOOP_STEP,l as better,E as createFlow,Y as getRenderer,v as isEnabled,p as normalizeError,u as safeSerialize,xe as setClock,G as setEnabled,we as setIdGenerator,U as setRenderer,O as subscribe,Z as toJSON};
|
package/package.json
CHANGED