where-log 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,16 +1,152 @@
1
- // src/index.ts
1
+ // src/core/context.ts
2
+ function isRecord(value) {
3
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4
+ }
5
+ function mergeContexts(base, incoming) {
6
+ if (!base && !incoming) return void 0;
7
+ return {
8
+ ...base ?? {},
9
+ ...incoming ?? {}
10
+ };
11
+ }
12
+ function injectContext(value, context) {
13
+ if (!context) return value;
14
+ if (isRecord(value)) {
15
+ const existing = isRecord(value.context) ? value.context : void 0;
16
+ return {
17
+ ...value,
18
+ context: {
19
+ ...existing ?? {},
20
+ ...context
21
+ }
22
+ };
23
+ }
24
+ return {
25
+ value,
26
+ context
27
+ };
28
+ }
29
+
30
+ // src/core/format.ts
2
31
  import util from "util";
3
- import path from "path";
4
32
  function isNodeRuntime() {
5
33
  return typeof process !== "undefined" && !!process.versions?.node;
6
34
  }
35
+ function safeFastStringify(value) {
36
+ const seen = /* @__PURE__ */ new WeakSet();
37
+ return JSON.stringify(value, (_k, v) => {
38
+ if (typeof v === "object" && v !== null) {
39
+ if (seen.has(v)) return "[Circular]";
40
+ seen.add(v);
41
+ }
42
+ return v;
43
+ });
44
+ }
45
+ function formatFastValue(value) {
46
+ if (typeof value === "string") return value;
47
+ if (typeof value === "number") return String(value);
48
+ if (typeof value === "boolean") return String(value);
49
+ if (typeof value === "bigint") return value.toString();
50
+ if (typeof value === "undefined") return "undefined";
51
+ if (value === null) return "null";
52
+ if (typeof value === "symbol") return value.toString();
53
+ if (typeof value === "function") {
54
+ return `[Function ${value.name || "anonymous"}]`;
55
+ }
56
+ try {
57
+ return safeFastStringify(value);
58
+ } catch {
59
+ return "[Unserializable]";
60
+ }
61
+ }
62
+ function formatValue(value, options) {
63
+ const mode = options?.mode ?? "pretty";
64
+ if (mode === "fast") {
65
+ return formatFastValue(value);
66
+ }
67
+ if (!isNodeRuntime()) {
68
+ return value;
69
+ }
70
+ return util.inspect(value, {
71
+ depth: options?.inspectDepth ?? null,
72
+ colors: options?.colors ?? true,
73
+ compact: false
74
+ });
75
+ }
76
+ function formatLabeledValue(label, formattedValue) {
77
+ if (!label) return formattedValue;
78
+ if (typeof formattedValue === "string") {
79
+ return `${label}: ${formattedValue}`;
80
+ }
81
+ return `${label}: ${String(formattedValue)}`;
82
+ }
83
+
84
+ // src/core/level.ts
85
+ var LEVEL_METHOD_MAP = {
86
+ info: "info",
87
+ success: "log",
88
+ warn: "warn",
89
+ error: "error",
90
+ debug: "debug"
91
+ };
92
+ function levelToConsoleMethod(level) {
93
+ return LEVEL_METHOD_MAP[level];
94
+ }
95
+ function levelToTag(level) {
96
+ return `[${level.toUpperCase()}]`;
97
+ }
98
+ function resolveConsoleMethod(level, override) {
99
+ if (override) return override;
100
+ if (!level) return "log";
101
+ return levelToConsoleMethod(level);
102
+ }
103
+
104
+ // src/core/session.ts
105
+ var onceKeys = /* @__PURE__ */ new Set();
106
+ var timers = /* @__PURE__ */ new Map();
107
+ function checkAndMarkOnce(key) {
108
+ if (onceKeys.has(key)) return false;
109
+ onceKeys.add(key);
110
+ return true;
111
+ }
112
+ function clearOnce(keys) {
113
+ if (!keys || keys.length === 0) {
114
+ onceKeys.clear();
115
+ return;
116
+ }
117
+ for (const key of keys) {
118
+ onceKeys.delete(key);
119
+ }
120
+ }
121
+ function startTimer(key, now) {
122
+ timers.set(key, { startedAt: now });
123
+ }
124
+ function endTimer(key, now) {
125
+ const entry = timers.get(key);
126
+ if (!entry) return null;
127
+ timers.delete(key);
128
+ return Math.max(0, now - entry.startedAt);
129
+ }
130
+ function clearTimers(keys) {
131
+ if (!keys || keys.length === 0) {
132
+ timers.clear();
133
+ return;
134
+ }
135
+ for (const key of keys) {
136
+ timers.delete(key);
137
+ }
138
+ }
139
+
140
+ // src/core/stack.ts
7
141
  function safeToInt(input) {
8
142
  const n = Number.parseInt(input, 10);
9
143
  return Number.isFinite(n) ? n : 0;
10
144
  }
11
- function normalizeFile(filePath) {
145
+ function basename(filePath) {
12
146
  const clean = filePath.replace(/^file:\/\//, "");
13
- return path.basename(clean);
147
+ const normalized = clean.replace(/\\/g, "/");
148
+ const last = normalized.lastIndexOf("/");
149
+ return last >= 0 ? normalized.slice(last + 1) : normalized;
14
150
  }
15
151
  function parseFrameLine(frame) {
16
152
  const cleaned = frame.trim();
@@ -18,14 +154,14 @@ function parseFrameLine(frame) {
18
154
  const v8Match = cleaned.match(/(?:at\s+)?(?:.+\s+\()?(.+):(\d+):(\d+)\)?$/);
19
155
  if (v8Match) {
20
156
  return {
21
- file: normalizeFile(v8Match[1]),
157
+ file: basename(v8Match[1]),
22
158
  line: safeToInt(v8Match[2])
23
159
  };
24
160
  }
25
161
  const ffMatch = cleaned.match(/@(.+):(\d+):(\d+)$/);
26
162
  if (ffMatch) {
27
163
  return {
28
- file: normalizeFile(ffMatch[1]),
164
+ file: basename(ffMatch[1]),
29
165
  line: safeToInt(ffMatch[2])
30
166
  };
31
167
  }
@@ -33,41 +169,105 @@ function parseFrameLine(frame) {
33
169
  }
34
170
  function getCallerFromStack(stack) {
35
171
  if (!stack) return { file: "unknown", line: 0 };
36
- const frames = stack.split("\n").map((line) => line.trim()).filter(Boolean);
37
- for (const frame of frames) {
172
+ const frames = stack.split("\n");
173
+ for (let i = 0; i < frames.length; i += 1) {
174
+ const frame = frames[i].trim();
175
+ if (!frame) continue;
38
176
  if (frame.includes("getCallerFromStack")) continue;
39
177
  if (frame.includes("at log")) continue;
40
178
  if (frame.includes("at Object.log")) continue;
41
179
  if (frame.includes("/src/index.ts")) continue;
42
180
  if (frame.includes("\\src\\index.ts")) continue;
181
+ if (frame.includes("/src/core/")) continue;
182
+ if (frame.includes("\\src\\core\\")) continue;
43
183
  const parsed = parseFrameLine(frame);
44
184
  if (parsed) return parsed;
45
185
  }
46
186
  return { file: "unknown", line: 0 };
47
187
  }
48
- function isLogOptions(value) {
49
- if (!value || typeof value !== "object") return false;
50
- const record = value;
51
- return "colors" in record || "formatter" in record;
188
+
189
+ // src/core/transform.ts
190
+ function isObjectLike(value) {
191
+ return typeof value === "object" && value !== null;
52
192
  }
53
- function formatValue(value, options) {
54
- if (!isNodeRuntime()) {
55
- return value;
193
+ function cloneDeep(value, seen = /* @__PURE__ */ new WeakMap()) {
194
+ if (!isObjectLike(value)) return value;
195
+ if (seen.has(value)) return seen.get(value);
196
+ if (Array.isArray(value)) {
197
+ const arr = [];
198
+ seen.set(value, arr);
199
+ for (let i = 0; i < value.length; i += 1) {
200
+ arr.push(cloneDeep(value[i], seen));
201
+ }
202
+ return arr;
56
203
  }
57
- return util.inspect(value, {
58
- depth: null,
59
- colors: options?.colors ?? true,
60
- compact: false
61
- });
204
+ const obj = {};
205
+ seen.set(value, obj);
206
+ for (const [k, v] of Object.entries(value)) {
207
+ obj[k] = cloneDeep(v, seen);
208
+ }
209
+ return obj;
62
210
  }
63
- function formatLabeledValue(label, formattedValue) {
64
- if (!label) return formattedValue;
65
- if (typeof formattedValue === "string") {
66
- return `${label}: ${formattedValue}`;
211
+ function redactPath(target, path) {
212
+ if (!isObjectLike(target) || path.length === 0) return;
213
+ const [head, ...rest] = path;
214
+ if (Array.isArray(target)) {
215
+ const idx = Number.parseInt(head, 10);
216
+ if (!Number.isFinite(idx) || idx < 0 || idx >= target.length) return;
217
+ if (rest.length === 0) {
218
+ target[idx] = "[REDACTED]";
219
+ return;
220
+ }
221
+ redactPath(target[idx], rest);
222
+ return;
67
223
  }
68
- return `${label}: ${String(formattedValue)}`;
224
+ if (!(head in target)) return;
225
+ if (rest.length === 0) {
226
+ target[head] = "[REDACTED]";
227
+ return;
228
+ }
229
+ redactPath(target[head], rest);
69
230
  }
70
- function log(arg1, arg2, arg3) {
231
+ function truncateArrays(target, maxArrayLength) {
232
+ if (!isObjectLike(target)) return target;
233
+ if (Array.isArray(target)) {
234
+ const sliced = target.slice(0, maxArrayLength).map((item) => truncateArrays(item, maxArrayLength));
235
+ if (target.length > maxArrayLength) {
236
+ sliced.push(`[... ${target.length - maxArrayLength} more items]`);
237
+ }
238
+ return sliced;
239
+ }
240
+ const out = {};
241
+ for (const [k, v] of Object.entries(target)) {
242
+ out[k] = truncateArrays(v, maxArrayLength);
243
+ }
244
+ return out;
245
+ }
246
+ function transformValue(value, options) {
247
+ if (!options?.redact?.length && options?.maxArrayLength == null) {
248
+ return value;
249
+ }
250
+ const cloned = cloneDeep(value);
251
+ if (options.redact?.length) {
252
+ for (const rawPath of options.redact) {
253
+ const path = rawPath.split(".").map((part) => part.trim()).filter(Boolean);
254
+ if (path.length === 0) continue;
255
+ redactPath(cloned, path);
256
+ }
257
+ }
258
+ if (typeof options.maxArrayLength === "number" && options.maxArrayLength >= 0) {
259
+ return truncateArrays(cloned, options.maxArrayLength);
260
+ }
261
+ return cloned;
262
+ }
263
+
264
+ // src/index.ts
265
+ function isLogOptions(value) {
266
+ if (!value || typeof value !== "object") return false;
267
+ const record = value;
268
+ return "colors" in record || "formatter" in record || "enabled" in record || "mode" in record || "includeLocation" in record || "inspectDepth" in record || "maxArrayLength" in record || "redact" in record || "level" in record || "showLevelTag" in record || "levelTagStyle" in record || "consoleMethod" in record || "context" in record || "clockNow" in record || "warnThresholdMs" in record || "errorThresholdMs" in record || "includeDurationOnly" in record;
269
+ }
270
+ function resolveLogArgs(arg1, arg2, arg3) {
71
271
  let label;
72
272
  let value;
73
273
  let options;
@@ -79,31 +279,338 @@ function log(arg1, arg2, arg3) {
79
279
  value = arg1;
80
280
  options = isLogOptions(arg2) ? arg2 : void 0;
81
281
  }
82
- const stack = new Error().stack;
83
- const caller = getCallerFromStack(stack);
282
+ return { label, value, options };
283
+ }
284
+ function resolveOnceArgs(key, arg2, arg3, arg4) {
285
+ if (typeof arg2 === "string" && arg3 !== void 0 && !isLogOptions(arg3)) {
286
+ return {
287
+ key,
288
+ label: arg2,
289
+ value: arg3,
290
+ options: arg4
291
+ };
292
+ }
293
+ return {
294
+ key,
295
+ value: arg2,
296
+ options: isLogOptions(arg3) ? arg3 : void 0
297
+ };
298
+ }
299
+ function resolveTimeEndArgs(key, arg2, arg3, arg4) {
300
+ if (arg2 === void 0) {
301
+ return { key };
302
+ }
303
+ if (isLogOptions(arg2)) {
304
+ return { key, options: arg2 };
305
+ }
306
+ if (typeof arg2 === "string" && arg3 !== void 0 && !isLogOptions(arg3)) {
307
+ return {
308
+ key,
309
+ label: arg2,
310
+ value: arg3,
311
+ options: arg4
312
+ };
313
+ }
314
+ return {
315
+ key,
316
+ value: arg2,
317
+ options: isLogOptions(arg3) ? arg3 : void 0
318
+ };
319
+ }
320
+ function writeLine(method, line) {
321
+ const sink = console[method];
322
+ if (typeof sink === "function") {
323
+ sink(line);
324
+ return;
325
+ }
326
+ console.log(line);
327
+ }
328
+ function runLog(args, ctx) {
329
+ const { label, value, options } = args;
330
+ if (options?.enabled === false) {
331
+ return;
332
+ }
333
+ const level = options?.level ?? ctx?.forceLevel;
334
+ const consoleMethod = resolveConsoleMethod(level, options?.consoleMethod);
335
+ const showLevelTag = options?.showLevelTag ?? (ctx?.defaultShowLevelTag ?? false);
336
+ const includeLocation = options?.includeLocation ?? true;
337
+ const stack = includeLocation ? new Error().stack : void 0;
338
+ const caller = includeLocation ? getCallerFromStack(stack) : { file: "disabled", line: 0 };
84
339
  const location = `${caller.file}:${caller.line}`;
85
- const formattedValue = formatValue(value, options);
340
+ const mergedContext = mergeContexts(ctx?.defaultContext, options?.context);
341
+ const contextualValue = injectContext(value, mergedContext);
342
+ const transformedValue = transformValue(contextualValue, {
343
+ redact: options?.redact,
344
+ maxArrayLength: options?.maxArrayLength
345
+ });
346
+ const formatOptions = {
347
+ colors: options?.colors,
348
+ mode: options?.mode,
349
+ inspectDepth: options?.inspectDepth
350
+ };
351
+ const formattedValue = formatValue(transformedValue, formatOptions);
352
+ const levelTag = level ? levelToTag(level) : void 0;
86
353
  if (options?.formatter) {
87
354
  const formatted = options.formatter({
88
355
  location,
89
356
  label,
90
- value,
91
- formattedValue
357
+ value: transformedValue,
358
+ formattedValue,
359
+ level,
360
+ levelTag
92
361
  });
93
- console.log(formatted.locationLine);
94
- console.log(formatted.valueLine);
362
+ writeLine(consoleMethod, formatted.locationLine);
363
+ writeLine(consoleMethod, formatted.valueLine);
95
364
  return;
96
365
  }
97
- console.log(location);
98
- console.log(formatLabeledValue(label, formattedValue));
366
+ if (includeLocation) {
367
+ writeLine(consoleMethod, location);
368
+ }
369
+ const labeledValue = formatLabeledValue(label, formattedValue);
370
+ const valueLine = showLevelTag && levelTag ? `${levelTag} ${String(labeledValue)}` : labeledValue;
371
+ writeLine(consoleMethod, valueLine);
372
+ }
373
+ var DEV_PRESET = {
374
+ mode: "pretty",
375
+ includeLocation: true,
376
+ colors: true
377
+ };
378
+ var PROD_PRESET = {
379
+ mode: "fast",
380
+ includeLocation: false,
381
+ colors: false
382
+ };
383
+ function mergeOptions(base, incoming) {
384
+ if (!base && !incoming) return void 0;
385
+ const merged = {
386
+ ...base ?? {},
387
+ ...incoming ?? {}
388
+ };
389
+ merged.context = mergeContexts(base?.context, incoming?.context);
390
+ return merged;
391
+ }
392
+ function resolveTimingLevel(durationMs, options) {
393
+ const errorThreshold = options?.errorThresholdMs;
394
+ const warnThreshold = options?.warnThresholdMs;
395
+ if (typeof errorThreshold === "number" && durationMs >= errorThreshold) return "error";
396
+ if (typeof warnThreshold === "number" && durationMs >= warnThreshold) return "warn";
397
+ return "info";
398
+ }
399
+ function log(arg1, arg2, arg3) {
400
+ runLog(resolveLogArgs(arg1, arg2, arg3));
401
+ }
402
+ function once(key, arg2, arg3, arg4) {
403
+ const resolved = resolveOnceArgs(key, arg2, arg3, arg4);
404
+ if (resolved.options?.enabled === false) return;
405
+ if (!checkAndMarkOnce(key)) return;
406
+ runLog({ label: resolved.label, value: resolved.value, options: resolved.options });
407
+ }
408
+ function resetOnce(keys) {
409
+ clearOnce(keys);
410
+ }
411
+ function time(key, options) {
412
+ if (options?.enabled === false) return;
413
+ const now = options?.clockNow?.() ?? Date.now();
414
+ startTimer(key, now);
415
+ }
416
+ function timeEnd(key, arg2, arg3, arg4) {
417
+ const resolved = resolveTimeEndArgs(key, arg2, arg3, arg4);
418
+ if (resolved.options?.enabled === false) return;
419
+ const now = resolved.options?.clockNow?.() ?? Date.now();
420
+ const durationMs = endTimer(key, now);
421
+ if (durationMs == null) {
422
+ runLog(
423
+ {
424
+ label: resolved.label ?? "timer",
425
+ value: {
426
+ key,
427
+ error: "timer_not_started"
428
+ },
429
+ options: resolved.options
430
+ },
431
+ {
432
+ forceLevel: "warn",
433
+ defaultShowLevelTag: true
434
+ }
435
+ );
436
+ return;
437
+ }
438
+ const timedPayload = resolved.options?.includeDurationOnly ? { durationMs } : {
439
+ key,
440
+ durationMs,
441
+ ...resolved.value !== void 0 ? { value: resolved.value } : {}
442
+ };
443
+ const timingLevel = resolveTimingLevel(durationMs, resolved.options);
444
+ runLog(
445
+ {
446
+ label: resolved.label ?? "timer",
447
+ value: timedPayload,
448
+ options: resolved.options
449
+ },
450
+ {
451
+ forceLevel: timingLevel,
452
+ defaultShowLevelTag: true
453
+ }
454
+ );
455
+ }
456
+ function resetTimers(keys) {
457
+ clearTimers(keys);
458
+ }
459
+ function logDev(arg1, arg2, arg3) {
460
+ const resolved = resolveLogArgs(arg1, arg2, arg3);
461
+ runLog({
462
+ ...resolved,
463
+ options: mergeOptions(DEV_PRESET, resolved.options)
464
+ });
465
+ }
466
+ function logProd(arg1, arg2, arg3) {
467
+ const resolved = resolveLogArgs(arg1, arg2, arg3);
468
+ runLog({
469
+ ...resolved,
470
+ options: mergeOptions(PROD_PRESET, resolved.options)
471
+ });
472
+ }
473
+ function makeLevelMethod(level, presetOptions, defaultContext) {
474
+ const method = (arg1, arg2, arg3) => {
475
+ const resolved = resolveLogArgs(arg1, arg2, arg3);
476
+ runLog(
477
+ {
478
+ ...resolved,
479
+ options: mergeOptions(presetOptions, resolved.options)
480
+ },
481
+ {
482
+ forceLevel: level,
483
+ defaultShowLevelTag: true,
484
+ defaultContext
485
+ }
486
+ );
487
+ };
488
+ return method;
489
+ }
490
+ function createLogger(presetOptions) {
491
+ const baseContext = presetOptions?.context;
492
+ const fn = (arg1, arg2, arg3) => {
493
+ const resolved = resolveLogArgs(arg1, arg2, arg3);
494
+ runLog(
495
+ {
496
+ ...resolved,
497
+ options: mergeOptions(presetOptions, resolved.options)
498
+ },
499
+ {
500
+ defaultContext: baseContext
501
+ }
502
+ );
503
+ };
504
+ const logger = fn;
505
+ logger.info = makeLevelMethod("info", presetOptions, baseContext);
506
+ logger.success = makeLevelMethod("success", presetOptions, baseContext);
507
+ logger.warn = makeLevelMethod("warn", presetOptions, baseContext);
508
+ logger.error = makeLevelMethod("error", presetOptions, baseContext);
509
+ logger.debug = makeLevelMethod("debug", presetOptions, baseContext);
510
+ logger.once = ((key, arg2, arg3, arg4) => {
511
+ const resolved = resolveOnceArgs(key, arg2, arg3, arg4);
512
+ const merged = mergeOptions(presetOptions, resolved.options);
513
+ if (merged?.enabled === false) return;
514
+ if (!checkAndMarkOnce(key)) return;
515
+ runLog(
516
+ {
517
+ label: resolved.label,
518
+ value: resolved.value,
519
+ options: merged
520
+ },
521
+ {
522
+ defaultContext: baseContext
523
+ }
524
+ );
525
+ });
526
+ logger.time = ((key, options) => {
527
+ const merged = mergeOptions(presetOptions, options);
528
+ if (merged?.enabled === false) return;
529
+ const now = merged?.clockNow?.() ?? Date.now();
530
+ startTimer(key, now);
531
+ });
532
+ logger.timeEnd = ((key, arg2, arg3, arg4) => {
533
+ const resolved = resolveTimeEndArgs(key, arg2, arg3, arg4);
534
+ const merged = mergeOptions(presetOptions, resolved.options);
535
+ if (merged?.enabled === false) return;
536
+ const now = merged?.clockNow?.() ?? Date.now();
537
+ const durationMs = endTimer(key, now);
538
+ if (durationMs == null) {
539
+ runLog(
540
+ {
541
+ label: resolved.label ?? "timer",
542
+ value: { key, error: "timer_not_started" },
543
+ options: merged
544
+ },
545
+ {
546
+ forceLevel: "warn",
547
+ defaultShowLevelTag: true,
548
+ defaultContext: baseContext
549
+ }
550
+ );
551
+ return;
552
+ }
553
+ const timedPayload = merged?.includeDurationOnly ? { durationMs } : {
554
+ key,
555
+ durationMs,
556
+ ...resolved.value !== void 0 ? { value: resolved.value } : {}
557
+ };
558
+ const level = resolveTimingLevel(durationMs, merged);
559
+ runLog(
560
+ {
561
+ label: resolved.label ?? "timer",
562
+ value: timedPayload,
563
+ options: merged
564
+ },
565
+ {
566
+ forceLevel: level,
567
+ defaultShowLevelTag: true,
568
+ defaultContext: baseContext
569
+ }
570
+ );
571
+ });
572
+ logger.withContext = (context) => {
573
+ return createLogger(mergeOptions(presetOptions, { context }));
574
+ };
575
+ logger.resetOnce = (keys) => clearOnce(keys);
576
+ logger.resetTimers = (keys) => clearTimers(keys);
577
+ return logger;
578
+ }
579
+ function withContext(context, presetOptions) {
580
+ return createLogger(mergeOptions(presetOptions, { context }));
99
581
  }
582
+ var info = makeLevelMethod("info");
583
+ var success = makeLevelMethod("success");
584
+ var warn = makeLevelMethod("warn");
585
+ var error = makeLevelMethod("error");
586
+ var debug = makeLevelMethod("debug");
100
587
  var __internal = {
101
588
  getCallerFromStack,
102
589
  parseFrameLine,
103
590
  formatLabeledValue,
104
- isLogOptions
591
+ isLogOptions,
592
+ resolveLogArgs,
593
+ mergeOptions,
594
+ writeLine,
595
+ resolveOnceArgs,
596
+ resolveTimeEndArgs,
597
+ resolveTimingLevel
105
598
  };
106
599
  export {
107
600
  __internal,
108
- log
601
+ createLogger,
602
+ debug,
603
+ error,
604
+ info,
605
+ log,
606
+ logDev,
607
+ logProd,
608
+ once,
609
+ resetOnce,
610
+ resetTimers,
611
+ success,
612
+ time,
613
+ timeEnd,
614
+ warn,
615
+ withContext
109
616
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "where-log",
3
- "version": "0.1.1",
3
+ "version": "0.2.1",
4
4
  "description": "Log values with caller file and line number.",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -23,7 +23,10 @@
23
23
  "build": "tsup --config tsup.config.ts",
24
24
  "typecheck": "tsc --noEmit",
25
25
  "test": "vitest run --pool=threads",
26
+ "smoke:imports": "node scripts/smoke-imports.mjs",
26
27
  "dev": "vitest --pool=threads",
28
+ "bench": "node bench/run-bench.mjs",
29
+ "bench:ci": "node bench/run-bench.mjs --ci",
27
30
  "pack:dry-run": "npm pack --dry-run --cache ./.npm-cache",
28
31
  "publish:dry-run": "npm publish --dry-run --cache ./.npm-cache",
29
32
  "release:check": "npm run pack:dry-run && npm run publish:dry-run"
@@ -43,4 +46,4 @@
43
46
  "typescript": "^5.5.4",
44
47
  "vitest": "^2.0.5"
45
48
  }
46
- }
49
+ }