measure-fn 3.3.0 → 3.5.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/README.md +45 -39
- package/SKILL.md +38 -25
- package/example.ts +27 -28
- package/index.test.ts +108 -0
- package/index.ts +12 -6
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -218,61 +218,67 @@ formatDuration(91234); // "1m 31s"
|
|
|
218
218
|
resetCounter(); // reset ID counter for tests
|
|
219
219
|
```
|
|
220
220
|
|
|
221
|
-
##
|
|
221
|
+
## Error Handling
|
|
222
222
|
|
|
223
|
-
|
|
223
|
+
`measure` never throws. On error it logs `✗` with timing and stack trace, then returns `null`. This keeps pipelines resilient — one failing step doesn't crash the rest.
|
|
224
224
|
|
|
225
|
-
**
|
|
225
|
+
**When you need to handle the error**, pass an `onError` handler as the 3rd argument. It receives the original error and its return value replaces `null`:
|
|
226
226
|
|
|
227
|
-
|
|
227
|
+
```typescript
|
|
228
|
+
// Default: returns null on error
|
|
229
|
+
const user = await measure('Fetch user', () => fetchUser(1));
|
|
230
|
+
|
|
231
|
+
// With recovery: returns fallback on error
|
|
232
|
+
const user = await measure('Fetch user', () => fetchUser(1),
|
|
233
|
+
(error) => defaultUser
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
// With error inspection: handle known errors, rethrow unknown
|
|
237
|
+
const user = await measure('Fetch user', () => fetchUser(1),
|
|
238
|
+
(error) => {
|
|
239
|
+
if (error instanceof NotFoundError) return guestUser;
|
|
240
|
+
if (error instanceof NetworkError) return cachedUser;
|
|
241
|
+
throw error; // unexpected — propagates up
|
|
242
|
+
}
|
|
243
|
+
);
|
|
228
244
|
|
|
229
|
-
|
|
245
|
+
// Rethrow all: transparent observability (same as .assert())
|
|
246
|
+
const user = await measure('Fetch user', () => fetchUser(1),
|
|
247
|
+
(error) => { throw error }
|
|
248
|
+
);
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
**Bun.serve — never return null:**
|
|
230
252
|
|
|
231
253
|
```typescript
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
}
|
|
239
|
-
throw e; // unexpected — measure catches, logs ✗, returns null
|
|
240
|
-
}
|
|
254
|
+
Bun.serve({
|
|
255
|
+
fetch: (req) => measure(
|
|
256
|
+
{ label: `${req.method} ${req.url}` },
|
|
257
|
+
() => handleRequest(req),
|
|
258
|
+
(error) => new Response(`Error: ${error.message}`, { status: 500 })
|
|
259
|
+
),
|
|
241
260
|
});
|
|
242
261
|
```
|
|
243
262
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
**When you need the result to be non-null:**
|
|
263
|
+
**`.assert()` is sugar for the rethrow pattern:**
|
|
247
264
|
|
|
248
265
|
```typescript
|
|
249
|
-
//
|
|
250
|
-
|
|
266
|
+
// These are equivalent:
|
|
267
|
+
await measure.assert('Op', () => work());
|
|
268
|
+
await measure('Op', () => work(), (e) => { throw e });
|
|
251
269
|
|
|
252
|
-
//
|
|
253
|
-
|
|
270
|
+
// .assert() wraps the error with .cause for inspection:
|
|
271
|
+
// e.message → 'measure.assert: "Op" failed'
|
|
272
|
+
// e.cause → original error
|
|
254
273
|
```
|
|
255
274
|
|
|
256
275
|
**Summary:**
|
|
257
276
|
|
|
258
|
-
|
|
|
259
|
-
|
|
260
|
-
| `measure()` | logs `✗`, returns `null` | Default — pipeline
|
|
261
|
-
| `
|
|
262
|
-
| `measure.assert()` | logs `✗`,
|
|
263
|
-
| `?? fallback` | returns fallback | Graceful degradation |
|
|
264
|
-
|
|
265
|
-
**Watch out: layered architectures.** When you have `measure → handler → handler's own try/catch`, a `null` return is ambiguous — did the handler catch the error and return a valid fallback, or did measure catch it and swallow it? If your handler has its own error handling, use `measure.assert()` instead of `measure()` so measure stays out of the error path:
|
|
266
|
-
|
|
267
|
-
```typescript
|
|
268
|
-
// ✗ Ambiguous: did handler or measure catch the error?
|
|
269
|
-
const response = await measure('Handle', () => handler(req)); // null = ???
|
|
270
|
-
|
|
271
|
-
// ✓ Clear: measure observes, handler handles its own errors
|
|
272
|
-
const response = await measure.assert('Handle', () => handler(req));
|
|
273
|
-
// handler's try/catch runs first → returns error Response
|
|
274
|
-
// measure only catches if handler ITSELF throws (unexpected)
|
|
275
|
-
```
|
|
277
|
+
| Pattern | On error | Use when |
|
|
278
|
+
|---------|----------|----------|
|
|
279
|
+
| `measure(label, fn)` | logs `✗`, returns `null` | Default — pipeline resilience |
|
|
280
|
+
| `measure(label, fn, onError)` | logs `✗`, calls `onError(error)` | Recovery, fallbacks, error inspection |
|
|
281
|
+
| `measure.assert(label, fn)` | logs `✗`, throws with `.cause` | Must have non-null |
|
|
276
282
|
|
|
277
283
|
## Types
|
|
278
284
|
|
package/SKILL.md
CHANGED
|
@@ -139,29 +139,52 @@ await measure('Server ready'); // → [a] = Server ready
|
|
|
139
139
|
measureSync('Config loaded'); // → [b] = Config loaded
|
|
140
140
|
```
|
|
141
141
|
|
|
142
|
-
### 11.
|
|
142
|
+
### 11. Error handling — `onError` 3rd argument
|
|
143
143
|
|
|
144
|
-
`measure
|
|
144
|
+
`measure` never throws. Pass an `onError` handler as 3rd argument to handle errors:
|
|
145
145
|
|
|
146
146
|
```typescript
|
|
147
|
-
//
|
|
147
|
+
// Default: null on error
|
|
148
|
+
const user = await measure('Fetch user', () => fetchUser(1));
|
|
149
|
+
|
|
150
|
+
// Recovery: fallback on error
|
|
151
|
+
const user = await measure('Fetch user', () => fetchUser(1),
|
|
152
|
+
(error) => defaultUser
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
// Error inspection: handle known errors, rethrow unknown
|
|
156
|
+
const user = await measure('Fetch user', () => fetchUser(1),
|
|
157
|
+
(error) => {
|
|
158
|
+
if (error instanceof NetworkError) return cachedUser;
|
|
159
|
+
throw error;
|
|
160
|
+
}
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
// Bun.serve: always return a Response
|
|
148
164
|
Bun.serve({
|
|
149
|
-
fetch: (req) => measure
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
165
|
+
fetch: (req) => measure(
|
|
166
|
+
{ label: `${req.method} ${req.url}` },
|
|
167
|
+
() => handleRequest(req),
|
|
168
|
+
(error) => new Response('Internal Server Error', { status: 500 })
|
|
169
|
+
),
|
|
153
170
|
});
|
|
171
|
+
```
|
|
154
172
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
})) ?? new Response('Internal Server Error', { status: 500 });
|
|
161
|
-
},
|
|
162
|
-
});
|
|
173
|
+
`.assert()` is sugar for `(e) => { throw e }` with `.cause`:
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
await measure.assert('Op', () => work());
|
|
177
|
+
// equivalent to: measure('Op', () => work(), (e) => { throw e })
|
|
163
178
|
```
|
|
164
179
|
|
|
180
|
+
## Error Model
|
|
181
|
+
|
|
182
|
+
| Pattern | On error | Use when |
|
|
183
|
+
|---------|----------|----------|
|
|
184
|
+
| `measure(label, fn)` | logs `✗`, returns `null` | Default — pipeline resilience |
|
|
185
|
+
| `measure(label, fn, onError)` | logs `✗`, calls `onError(error)` | Recovery, fallbacks, error inspection |
|
|
186
|
+
| `measure.assert(label, fn)` | logs `✗`, throws with `.cause` | Must have non-null |
|
|
187
|
+
|
|
165
188
|
## Configuration
|
|
166
189
|
|
|
167
190
|
```typescript
|
|
@@ -186,16 +209,6 @@ const { result, duration } = await measure.timed('Fetch', () => fetchUsers());
|
|
|
186
209
|
if (duration > 1000) alert('Slow!');
|
|
187
210
|
```
|
|
188
211
|
|
|
189
|
-
## Error Model — measure Never Throws
|
|
190
|
-
|
|
191
|
-
Like Go's `result, err` pattern, `measure` treats errors as values: returns `null` on failure, **always** logs the error with timing and stack trace. One failing step doesn't crash the pipeline.
|
|
192
|
-
|
|
193
|
-
| Method | On error | Use when |
|
|
194
|
-
|--------|----------|----------|
|
|
195
|
-
| `measure()` | returns `null` | Default — resilient pipelines |
|
|
196
|
-
| `measure.assert()` | throws | Must have non-null (e.g. Bun.serve) |
|
|
197
|
-
| `?? fallback` | returns fallback | Graceful degradation |
|
|
198
|
-
|
|
199
212
|
## Anti-Patterns
|
|
200
213
|
|
|
201
214
|
```typescript
|
package/example.ts
CHANGED
|
@@ -100,18 +100,28 @@ async function main() {
|
|
|
100
100
|
|
|
101
101
|
// ─── Bun.serve patterns ──────────────────────────────────────────────
|
|
102
102
|
// measure() returns T | null — on error it returns null instead of throwing.
|
|
103
|
-
//
|
|
104
|
-
// swallows the error and returns null, Bun crashes.
|
|
105
|
-
//
|
|
106
|
-
// Solution: use measure.assert() which re-throws on error,
|
|
107
|
-
// or use nullish coalescing to provide a fallback Response.
|
|
103
|
+
// Use the onError 3rd argument to provide a fallback Response.
|
|
108
104
|
|
|
109
105
|
async function bunServeExample() {
|
|
110
106
|
console.log('\n─── Bun.serve Patterns ─────────────────────────────');
|
|
111
107
|
|
|
112
|
-
// ✅ Pattern 1:
|
|
108
|
+
// ✅ Pattern 1: onError — graceful 500 fallback with error details
|
|
113
109
|
const server1 = Bun.serve({
|
|
114
|
-
port: 0,
|
|
110
|
+
port: 0,
|
|
111
|
+
fetch: (req) => measure(
|
|
112
|
+
{ label: `${req.method} ${new URL(req.url).pathname}` },
|
|
113
|
+
async () => {
|
|
114
|
+
const url = new URL(req.url);
|
|
115
|
+
if (url.pathname === '/fail') throw new Error('Route error');
|
|
116
|
+
return new Response(`ok: ${url.pathname}`);
|
|
117
|
+
},
|
|
118
|
+
(error) => new Response(`Error: ${(error as Error).message}`, { status: 500 })
|
|
119
|
+
),
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// ✅ Pattern 2: measure.assert — throws on error (sugar for onError + throw)
|
|
123
|
+
const server2 = Bun.serve({
|
|
124
|
+
port: 0,
|
|
115
125
|
fetch: (req) => measure.assert('Handle request', async () => {
|
|
116
126
|
const url = new URL(req.url);
|
|
117
127
|
if (url.pathname === '/fail') throw new Error('Route error');
|
|
@@ -119,34 +129,23 @@ async function bunServeExample() {
|
|
|
119
129
|
}),
|
|
120
130
|
});
|
|
121
131
|
|
|
122
|
-
//
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
fetch: async (req) => {
|
|
126
|
-
return (await measure('Handle request', async () => {
|
|
127
|
-
const url = new URL(req.url);
|
|
128
|
-
if (url.pathname === '/fail') throw new Error('Route error');
|
|
129
|
-
return new Response(`ok: ${url.pathname}`);
|
|
130
|
-
})) ?? new Response('Internal Server Error', { status: 500 });
|
|
131
|
-
},
|
|
132
|
-
});
|
|
132
|
+
// Test Pattern 1: onError returns fallback Response
|
|
133
|
+
const r1ok = await fetch(`http://localhost:${server1.port}/hello`);
|
|
134
|
+
console.log(` onError pattern (ok): ${r1ok.status} ${await r1ok.text()}`);
|
|
133
135
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
136
|
+
const r1fail = await fetch(`http://localhost:${server1.port}/fail`);
|
|
137
|
+
console.log(` onError pattern (fail): ${r1fail.status} ${await r1fail.text()}`);
|
|
138
|
+
|
|
139
|
+
// Test Pattern 2: assert
|
|
140
|
+
const r2ok = await fetch(`http://localhost:${server2.port}/hello`);
|
|
141
|
+
console.log(` assert pattern (ok): ${r2ok.status} ${await r2ok.text()}`);
|
|
137
142
|
|
|
138
143
|
try {
|
|
139
|
-
await fetch(`http://localhost:${
|
|
144
|
+
await fetch(`http://localhost:${server2.port}/fail`);
|
|
140
145
|
} catch {
|
|
141
146
|
console.log(` assert pattern (fail): server rejected (expected)`);
|
|
142
147
|
}
|
|
143
148
|
|
|
144
|
-
const r2ok = await fetch(`http://localhost:${server2.port}/hello`);
|
|
145
|
-
console.log(` fallback pattern (ok): ${r2ok.status} ${await r2ok.text()}`);
|
|
146
|
-
|
|
147
|
-
const r2fail = await fetch(`http://localhost:${server2.port}/fail`);
|
|
148
|
-
console.log(` fallback pattern (fail): ${r2fail.status} ${await r2fail.text()}`);
|
|
149
|
-
|
|
150
149
|
server1.stop();
|
|
151
150
|
server2.stop();
|
|
152
151
|
}
|
package/index.test.ts
CHANGED
|
@@ -427,6 +427,114 @@ describe("measure.assert", () => {
|
|
|
427
427
|
});
|
|
428
428
|
});
|
|
429
429
|
|
|
430
|
+
// ─── onError (3rd argument) ──────────────────────────────────────────
|
|
431
|
+
|
|
432
|
+
describe("onError (3rd argument)", () => {
|
|
433
|
+
beforeEach(() => {
|
|
434
|
+
resetCounter();
|
|
435
|
+
configure({ silent: false, logger: null, timestamps: false });
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
test("returns fallback from onError on failure", async () => {
|
|
439
|
+
const out = captureConsole();
|
|
440
|
+
const result = await measure('Fetch user', async () => {
|
|
441
|
+
throw new Error('not found');
|
|
442
|
+
}, () => 'fallback');
|
|
443
|
+
out.restore();
|
|
444
|
+
expect(result).toBe('fallback');
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
test("returns normal result on success (onError ignored)", async () => {
|
|
448
|
+
const out = captureConsole();
|
|
449
|
+
const result = await measure('Fetch user', async () => 42, () => -1);
|
|
450
|
+
out.restore();
|
|
451
|
+
expect(result).toBe(42);
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
test("error object is passed to onError handler", async () => {
|
|
455
|
+
const out = captureConsole();
|
|
456
|
+
const original = new Error('network timeout');
|
|
457
|
+
let captured: unknown = null;
|
|
458
|
+
await measure('Fetch', async () => { throw original; }, (err) => {
|
|
459
|
+
captured = err;
|
|
460
|
+
return null;
|
|
461
|
+
});
|
|
462
|
+
out.restore();
|
|
463
|
+
expect(captured).toBe(original);
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
test("onError can rethrow (same as assert)", async () => {
|
|
467
|
+
const out = captureConsole();
|
|
468
|
+
const original = new Error('critical');
|
|
469
|
+
try {
|
|
470
|
+
await measure('Op', async () => { throw original; }, (e) => { throw e; });
|
|
471
|
+
expect(true).toBe(false);
|
|
472
|
+
} catch (e) {
|
|
473
|
+
expect(e).toBe(original);
|
|
474
|
+
}
|
|
475
|
+
out.restore();
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
test("onError can inspect error type and recover", async () => {
|
|
479
|
+
const out = captureConsole();
|
|
480
|
+
const result = await measure('Fetch', async () => {
|
|
481
|
+
throw new TypeError('invalid');
|
|
482
|
+
}, (error) => {
|
|
483
|
+
if (error instanceof TypeError) return 'recovered';
|
|
484
|
+
throw error;
|
|
485
|
+
});
|
|
486
|
+
out.restore();
|
|
487
|
+
expect(result).toBe('recovered');
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
test("sync onError returns fallback", () => {
|
|
491
|
+
const out = captureConsole();
|
|
492
|
+
const result = measureSync('Parse', () => {
|
|
493
|
+
throw new Error('bad input');
|
|
494
|
+
}, () => 'default');
|
|
495
|
+
out.restore();
|
|
496
|
+
expect(result).toBe('default');
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
test("sync onError receives error", () => {
|
|
500
|
+
const out = captureConsole();
|
|
501
|
+
const original = new Error('sync fail');
|
|
502
|
+
let captured: unknown = null;
|
|
503
|
+
measureSync('Op', () => { throw original; }, (err) => {
|
|
504
|
+
captured = err;
|
|
505
|
+
return null;
|
|
506
|
+
});
|
|
507
|
+
out.restore();
|
|
508
|
+
expect(captured).toBe(original);
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
test("still logs error even when onError handles it", async () => {
|
|
512
|
+
const events: any[] = [];
|
|
513
|
+
configure({ logger: (e) => events.push(e) });
|
|
514
|
+
await measure('Op', async () => { throw new Error('x'); }, () => 'fallback');
|
|
515
|
+
configure({ logger: null });
|
|
516
|
+
const errorEvent = events.find(e => e.type === 'error');
|
|
517
|
+
expect(errorEvent).toBeTruthy();
|
|
518
|
+
expect(errorEvent.label).toBe('Op');
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
test("Bun.serve pattern with onError fallback", async () => {
|
|
522
|
+
const out = captureConsole();
|
|
523
|
+
const result = await measure(
|
|
524
|
+
{ label: 'Handle request' },
|
|
525
|
+
async () => {
|
|
526
|
+
throw new Error('route error');
|
|
527
|
+
return new Response('ok');
|
|
528
|
+
},
|
|
529
|
+
(error) => new Response(`Error: ${(error as Error).message}`, { status: 500 })
|
|
530
|
+
);
|
|
531
|
+
out.restore();
|
|
532
|
+
expect(result).toBeInstanceOf(Response);
|
|
533
|
+
expect(result!.status).toBe(500);
|
|
534
|
+
expect(await result!.text()).toContain('route error');
|
|
535
|
+
});
|
|
536
|
+
});
|
|
537
|
+
|
|
430
538
|
// ─── measure.wrap ────────────────────────────────────────────────────
|
|
431
539
|
|
|
432
540
|
describe("measure.wrap", () => {
|
package/index.ts
CHANGED
|
@@ -214,16 +214,17 @@ const createNestedResolver = (
|
|
|
214
214
|
fullIdChain: string[],
|
|
215
215
|
childCounterRef: { value: number },
|
|
216
216
|
depth: number,
|
|
217
|
-
resolver: <U>(fn: any, action: any, chain: (string | number)[], depth: number) => Promise<U | null> | (U | null),
|
|
217
|
+
resolver: <U>(fn: any, action: any, chain: (string | number)[], depth: number, onError?: (error: unknown) => any) => Promise<U | null> | (U | null),
|
|
218
218
|
prefix?: string
|
|
219
219
|
) => {
|
|
220
220
|
return (...args: any[]) => {
|
|
221
221
|
const label = args[0];
|
|
222
222
|
const fn = args[1];
|
|
223
|
+
const onError = args[2];
|
|
223
224
|
|
|
224
225
|
if (typeof fn === 'function') {
|
|
225
226
|
const childParentChain = [...fullIdChain, childCounterRef.value++];
|
|
226
|
-
return resolver(fn, label, childParentChain, depth + 1);
|
|
227
|
+
return resolver(fn, label, childParentChain, depth + 1, typeof onError === 'function' ? onError : undefined);
|
|
227
228
|
} else {
|
|
228
229
|
emit({
|
|
229
230
|
type: 'annotation',
|
|
@@ -255,7 +256,8 @@ const createMeasureImpl = (prefix?: string, counterRef?: { value: number }) => {
|
|
|
255
256
|
fnInternal: (measure: MeasureFn) => Promise<U>,
|
|
256
257
|
actionInternal: string | object,
|
|
257
258
|
parentIdChain: (string | number)[],
|
|
258
|
-
depth: number
|
|
259
|
+
depth: number,
|
|
260
|
+
onError?: (error: unknown) => any
|
|
259
261
|
): Promise<U | null> => {
|
|
260
262
|
const start = performance.now();
|
|
261
263
|
const childCounterRef = { value: 0 };
|
|
@@ -285,6 +287,7 @@ const createMeasureImpl = (prefix?: string, counterRef?: { value: number }) => {
|
|
|
285
287
|
const duration = performance.now() - start;
|
|
286
288
|
emit({ type: 'error', id: idStr, label, depth, duration, error, budget }, prefix);
|
|
287
289
|
_lastError = error;
|
|
290
|
+
if (onError) return onError(error);
|
|
288
291
|
return null;
|
|
289
292
|
}
|
|
290
293
|
};
|
|
@@ -293,7 +296,8 @@ const createMeasureImpl = (prefix?: string, counterRef?: { value: number }) => {
|
|
|
293
296
|
fnInternal: (measure: MeasureSyncFn) => U,
|
|
294
297
|
actionInternal: string | object,
|
|
295
298
|
parentIdChain: (string | number)[],
|
|
296
|
-
depth: number
|
|
299
|
+
depth: number,
|
|
300
|
+
onError?: (error: unknown) => any
|
|
297
301
|
): U | null => {
|
|
298
302
|
const start = performance.now();
|
|
299
303
|
const childCounterRef = { value: 0 };
|
|
@@ -326,6 +330,7 @@ const createMeasureImpl = (prefix?: string, counterRef?: { value: number }) => {
|
|
|
326
330
|
const duration = performance.now() - start;
|
|
327
331
|
emit({ type: 'error', id: idStr, label, depth, duration, error, budget }, prefix);
|
|
328
332
|
_lastError = error;
|
|
333
|
+
if (onError) return onError(error);
|
|
329
334
|
return null;
|
|
330
335
|
}
|
|
331
336
|
};
|
|
@@ -334,10 +339,11 @@ const createMeasureImpl = (prefix?: string, counterRef?: { value: number }) => {
|
|
|
334
339
|
|
|
335
340
|
const measureFn = async <T = null>(
|
|
336
341
|
arg1: string | object,
|
|
337
|
-
arg2?: ((measure: MeasureFn) => Promise<T>)
|
|
342
|
+
arg2?: ((measure: MeasureFn) => Promise<T>) | ((measure: MeasureFn) => T),
|
|
343
|
+
arg3?: (error: unknown) => any
|
|
338
344
|
): Promise<T | null> => {
|
|
339
345
|
if (typeof arg2 === 'function') {
|
|
340
|
-
return _measureInternal(arg2, arg1, [counter.value++], 0) as Promise<T | null>;
|
|
346
|
+
return _measureInternal(arg2 as any, arg1, [counter.value++], 0, arg3) as Promise<T | null>;
|
|
341
347
|
} else {
|
|
342
348
|
const currentId = toAlpha(counter.value++);
|
|
343
349
|
emit({
|
package/package.json
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
"name": "measure-fn",
|
|
3
3
|
"module": "index.ts",
|
|
4
4
|
"main": "./index.ts",
|
|
5
|
-
"
|
|
5
|
+
"types": "./index.ts",
|
|
6
|
+
"version": "3.5.0",
|
|
6
7
|
"type": "module",
|
|
7
8
|
"private": false,
|
|
8
9
|
"description": "Zero-dependency function performance measurement with hierarchical logging",
|