@spfn/core 0.3.0-beta.4 → 0.3.0-beta.5

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.
@@ -2,7 +2,6 @@ import { randomBytes, createHmac, createHash, timingSafeEqual } from 'crypto';
2
2
  import { SerializableError } from '@spfn/core/errors';
3
3
  import { logger } from '@spfn/core/logger';
4
4
  import { env } from '@spfn/core/config';
5
- import { format } from 'util';
6
5
 
7
6
  // src/middleware/error-handler.ts
8
7
  var errorLogger = logger.child("@spfn/core:error-handler");
@@ -416,386 +415,6 @@ var ErrorRegistry = class _ErrorRegistry {
416
415
  return Array.from(this.errors.keys());
417
416
  }
418
417
  };
419
-
420
- // src/logger/types.ts
421
- var LOG_LEVEL_PRIORITY = {
422
- debug: 0,
423
- info: 1,
424
- warn: 2,
425
- error: 3,
426
- fatal: 4
427
- };
428
-
429
- // src/logger/formatters.ts
430
- var SENSITIVE_KEYS = [
431
- "password",
432
- "passwd",
433
- "pwd",
434
- "secret",
435
- "token",
436
- "apikey",
437
- "api_key",
438
- "accesstoken",
439
- "access_token",
440
- "refreshtoken",
441
- "refresh_token",
442
- "authorization",
443
- "auth",
444
- "cookie",
445
- "session",
446
- "sessionid",
447
- "session_id",
448
- "privatekey",
449
- "private_key",
450
- "creditcard",
451
- "credit_card",
452
- "cardnumber",
453
- "card_number",
454
- "cvv",
455
- "ssn",
456
- "pin"
457
- ];
458
- var MASKED_VALUE = "***MASKED***";
459
- function isSensitiveKey(key) {
460
- const lowerKey = key.toLowerCase();
461
- return SENSITIVE_KEYS.some((sensitive) => lowerKey.includes(sensitive));
462
- }
463
- function maskSensitiveData(data, seen = /* @__PURE__ */ new WeakSet()) {
464
- if (data === null || data === void 0) {
465
- return data;
466
- }
467
- if (typeof data !== "object") {
468
- return data;
469
- }
470
- if (seen.has(data)) {
471
- return "[Circular]";
472
- }
473
- seen.add(data);
474
- if (Array.isArray(data)) {
475
- return data.map((item) => maskSensitiveData(item, seen));
476
- }
477
- const masked = {};
478
- for (const [key, value] of Object.entries(data)) {
479
- if (isSensitiveKey(key)) {
480
- masked[key] = MASKED_VALUE;
481
- } else if (typeof value === "object" && value !== null) {
482
- masked[key] = maskSensitiveData(value, seen);
483
- } else {
484
- masked[key] = value;
485
- }
486
- }
487
- return masked;
488
- }
489
- var COLORS = {
490
- reset: "\x1B[0m",
491
- bright: "\x1B[1m",
492
- dim: "\x1B[2m",
493
- // 로그 레벨 컬러
494
- debug: "\x1B[36m",
495
- // cyan
496
- info: "\x1B[32m",
497
- // green
498
- warn: "\x1B[33m",
499
- // yellow
500
- error: "\x1B[31m",
501
- // red
502
- fatal: "\x1B[35m",
503
- // magenta
504
- // 추가 컬러
505
- gray: "\x1B[90m"
506
- };
507
- function formatTimestampHuman(date) {
508
- const year = date.getFullYear();
509
- const month = String(date.getMonth() + 1).padStart(2, "0");
510
- const day = String(date.getDate()).padStart(2, "0");
511
- const hours = String(date.getHours()).padStart(2, "0");
512
- const minutes = String(date.getMinutes()).padStart(2, "0");
513
- const seconds = String(date.getSeconds()).padStart(2, "0");
514
- const ms = String(date.getMilliseconds()).padStart(3, "0");
515
- return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${ms}`;
516
- }
517
- function formatError(error) {
518
- const lines = [];
519
- lines.push(`${error.name}: ${error.message}`);
520
- if (error.stack) {
521
- const stackLines = error.stack.split("\n").slice(1);
522
- lines.push(...stackLines);
523
- }
524
- if (error.cause instanceof Error) {
525
- lines.push(`Caused by: ${formatError(error.cause)}`);
526
- } else if (error.cause !== void 0) {
527
- lines.push(`Caused by: ${String(error.cause)}`);
528
- }
529
- return lines.join("\n");
530
- }
531
- function formatConsole(metadata, colorize = true) {
532
- const parts = [];
533
- const timestamp = formatTimestampHuman(metadata.timestamp);
534
- if (colorize) {
535
- parts.push(`${COLORS.gray}[${timestamp}]${COLORS.reset}`);
536
- } else {
537
- parts.push(`[${timestamp}]`);
538
- }
539
- const pid = process.pid;
540
- if (colorize) {
541
- parts.push(`${COLORS.dim}[pid=${pid}]${COLORS.reset}`);
542
- } else {
543
- parts.push(`[pid=${pid}]`);
544
- }
545
- if (metadata.module) {
546
- if (colorize) {
547
- parts.push(`${COLORS.dim}[module=${metadata.module}]${COLORS.reset}`);
548
- } else {
549
- parts.push(`[module=${metadata.module}]`);
550
- }
551
- }
552
- if (metadata.context && Object.keys(metadata.context).length > 0) {
553
- Object.entries(metadata.context).forEach(([key, value]) => {
554
- let valueStr;
555
- if (typeof value === "string") {
556
- valueStr = value;
557
- } else if (typeof value === "object" && value !== null) {
558
- try {
559
- valueStr = JSON.stringify(value);
560
- } catch (error) {
561
- valueStr = "[circular]";
562
- }
563
- } else {
564
- valueStr = String(value);
565
- }
566
- if (colorize) {
567
- parts.push(`${COLORS.dim}[${key}=${valueStr}]${COLORS.reset}`);
568
- } else {
569
- parts.push(`[${key}=${valueStr}]`);
570
- }
571
- });
572
- }
573
- const levelStr = metadata.level.toUpperCase();
574
- if (colorize) {
575
- const color = COLORS[metadata.level];
576
- parts.push(`${color}(${levelStr})${COLORS.reset}:`);
577
- } else {
578
- parts.push(`(${levelStr}):`);
579
- }
580
- if (colorize) {
581
- parts.push(`${COLORS.bright}${metadata.message}${COLORS.reset}`);
582
- } else {
583
- parts.push(metadata.message);
584
- }
585
- let output = parts.join(" ");
586
- if (metadata.error) {
587
- output += "\n" + formatError(metadata.error);
588
- }
589
- return output;
590
- }
591
-
592
- // src/logger/logger.ts
593
- var FORMAT_PATTERN = /%[sdifjoOc%]/;
594
- var Logger = class _Logger {
595
- config;
596
- module;
597
- constructor(config) {
598
- this.config = config;
599
- this.module = config.module;
600
- }
601
- /**
602
- * Convert unknown error to Error object
603
- */
604
- toError(error) {
605
- if (error instanceof Error) return error;
606
- if (typeof error === "string") return new Error(error);
607
- if (typeof error === "object" && error !== null) {
608
- return new Error(JSON.stringify(error));
609
- }
610
- return new Error(String(error));
611
- }
612
- /**
613
- * Check if value is a context object (not an error)
614
- */
615
- isContext(value) {
616
- if (typeof value !== "object" || value === null) return false;
617
- if (value instanceof Error) return false;
618
- const hasStack = "stack" in value && typeof value.stack === "string";
619
- if (hasStack) {
620
- return false;
621
- }
622
- return true;
623
- }
624
- /**
625
- * Get current log level
626
- */
627
- get level() {
628
- return this.config.level;
629
- }
630
- /**
631
- * Create child logger (per module)
632
- */
633
- child(module) {
634
- return new _Logger({
635
- ...this.config,
636
- module
637
- });
638
- }
639
- /**
640
- * Common log method with error/context detection
641
- */
642
- logWithLevel(level, message, errorOrContext, context) {
643
- if (errorOrContext !== void 0 && FORMAT_PATTERN.test(message)) {
644
- this.log(level, format(message, errorOrContext), void 0, context);
645
- return;
646
- }
647
- if (errorOrContext instanceof Error) {
648
- this.log(level, message, errorOrContext, context);
649
- } else if (errorOrContext !== void 0 && typeof errorOrContext === "object" && !this.isContext(errorOrContext)) {
650
- this.log(level, message, this.toError(errorOrContext), context);
651
- } else if (typeof errorOrContext === "string" || typeof errorOrContext === "number" || typeof errorOrContext === "boolean") {
652
- this.log(level, message, this.toError(errorOrContext), context);
653
- } else {
654
- this.log(level, message, void 0, errorOrContext);
655
- }
656
- }
657
- debug(message, errorOrContext, context) {
658
- this.logWithLevel("debug", message, errorOrContext, context);
659
- }
660
- info(message, errorOrContext, context) {
661
- this.logWithLevel("info", message, errorOrContext, context);
662
- }
663
- warn(message, errorOrContext, context) {
664
- this.logWithLevel("warn", message, errorOrContext, context);
665
- }
666
- error(message, errorOrContext, context) {
667
- this.logWithLevel("error", message, errorOrContext, context);
668
- }
669
- fatal(message, errorOrContext, context) {
670
- this.logWithLevel("fatal", message, errorOrContext, context);
671
- }
672
- /**
673
- * Log processing (internal)
674
- */
675
- log(level, message, error, context) {
676
- if (LOG_LEVEL_PRIORITY[level] < LOG_LEVEL_PRIORITY[this.config.level]) {
677
- return;
678
- }
679
- const metadata = {
680
- timestamp: /* @__PURE__ */ new Date(),
681
- level,
682
- message,
683
- module: this.module,
684
- error,
685
- // Mask sensitive information in context to prevent credential leaks
686
- context: context ? maskSensitiveData(context) : void 0
687
- };
688
- this.processTransports(metadata);
689
- }
690
- /**
691
- * Process Transports
692
- */
693
- processTransports(metadata) {
694
- const promises = this.config.transports.filter((transport) => transport.enabled).map((transport) => this.safeTransportLog(transport, metadata));
695
- Promise.all(promises).catch((error) => {
696
- const errorMessage = error instanceof Error ? error.message : String(error);
697
- process.stderr.write(`[Logger] Transport error: ${errorMessage}
698
- `);
699
- });
700
- }
701
- /**
702
- * Transport log (error-safe)
703
- */
704
- async safeTransportLog(transport, metadata) {
705
- try {
706
- await transport.log(metadata);
707
- } catch (error) {
708
- const errorMessage = error instanceof Error ? error.message : String(error);
709
- process.stderr.write(`[Logger] Transport "${transport.name}" failed: ${errorMessage}
710
- `);
711
- }
712
- }
713
- /**
714
- * Close all Transports
715
- */
716
- async close() {
717
- const closePromises = this.config.transports.filter((transport) => transport.close).map((transport) => transport.close());
718
- await Promise.all(closePromises);
719
- }
720
- };
721
-
722
- // src/logger/transports/console.ts
723
- var ConsoleTransport = class {
724
- name = "console";
725
- level;
726
- enabled;
727
- colorize;
728
- constructor(config) {
729
- this.level = config.level;
730
- this.enabled = config.enabled;
731
- this.colorize = config.colorize ?? true;
732
- }
733
- async log(metadata) {
734
- if (!this.enabled) {
735
- return;
736
- }
737
- if (LOG_LEVEL_PRIORITY[metadata.level] < LOG_LEVEL_PRIORITY[this.level]) {
738
- return;
739
- }
740
- const message = formatConsole(metadata, this.colorize);
741
- if (metadata.level === "warn" || metadata.level === "error" || metadata.level === "fatal") {
742
- console.error(message);
743
- } else {
744
- console.log(message);
745
- }
746
- }
747
- };
748
-
749
- // src/logger/config.ts
750
- function getConsoleConfig() {
751
- const isProduction = process.env.NODE_ENV === "production";
752
- return {
753
- level: "debug",
754
- enabled: true,
755
- colorize: !isProduction
756
- // Dev: colored output, Production: plain text
757
- };
758
- }
759
- function validateEnvironment() {
760
- const nodeEnv = process.env.NODE_ENV;
761
- if (!nodeEnv) {
762
- process.stderr.write(
763
- "[Logger] Warning: NODE_ENV is not set. Defaulting to test environment.\n"
764
- );
765
- }
766
- }
767
- function validateConfig() {
768
- validateEnvironment();
769
- }
770
-
771
- // src/logger/factory.ts
772
- function initializeTransports() {
773
- const transports = [];
774
- const consoleConfig = getConsoleConfig();
775
- transports.push(new ConsoleTransport(consoleConfig));
776
- return transports;
777
- }
778
- function getLogLevel() {
779
- const envLevel = process.env.SPFN_LOG_LEVEL || process.env.NEXT_PUBLIC_SPFN_LOG_LEVEL || "info";
780
- if (envLevel in LOG_LEVEL_PRIORITY) {
781
- return envLevel;
782
- }
783
- process.stderr.write(
784
- `[Logger] Invalid log level "${envLevel}", defaulting to "info"
785
- `
786
- );
787
- return "info";
788
- }
789
- function initializeLogger() {
790
- validateConfig();
791
- return new Logger({
792
- level: getLogLevel(),
793
- transports: initializeTransports()
794
- });
795
- }
796
- var logger4 = initializeLogger();
797
-
798
- // src/errors/serializable-error.ts
799
418
  var RESERVED_RESPONSE_KEYS = /* @__PURE__ */ new Set(["__type", "message", "error"]);
800
419
  var AUTHORING_ENVIRONMENTS = /* @__PURE__ */ new Set(["local", "development", "test"]);
801
420
  function refuseReservedKey(className, key) {
@@ -803,7 +422,7 @@ function refuseReservedKey(className, key) {
803
422
  if (AUTHORING_ENVIRONMENTS.has(process.env.NODE_ENV ?? "local")) {
804
423
  throw new Error(detail);
805
424
  }
806
- logger4.error(`[SerializableError] ${detail} The field is omitted from the response.`);
425
+ logger.error(`[SerializableError] ${detail} The field is omitted from the response.`);
807
426
  }
808
427
  var SerializableError2 = class extends Error {
809
428
  /**
@@ -1207,7 +826,7 @@ var MemoryRateLimitStore = class {
1207
826
  };
1208
827
 
1209
828
  // src/middleware/rate-limit.ts
1210
- var rateLimitLogger = logger4.child("@spfn/core:rate-limit");
829
+ var rateLimitLogger = logger.child("@spfn/core:rate-limit");
1211
830
  var memoryStore = new MemoryRateLimitStore();
1212
831
  function resetMemoryRateLimitStore() {
1213
832
  memoryStore.clear();
@@ -1335,7 +954,7 @@ function generateRequestId() {
1335
954
  const randomPart = randomBytes(6).toString("hex");
1336
955
  return `req_${timestamp}_${randomPart}`;
1337
956
  }
1338
- function maskSensitiveData2(obj, sensitiveFields, seen = /* @__PURE__ */ new WeakSet()) {
957
+ function maskSensitiveData(obj, sensitiveFields, seen = /* @__PURE__ */ new WeakSet()) {
1339
958
  if (!obj || typeof obj !== "object") return obj;
1340
959
  if (seen.has(obj)) return "[Circular]";
1341
960
  seen.add(obj);
@@ -1346,7 +965,7 @@ function maskSensitiveData2(obj, sensitiveFields, seen = /* @__PURE__ */ new Wea
1346
965
  if (lowerFields.some((field) => lowerKey.includes(field))) {
1347
966
  masked[key] = "***MASKED***";
1348
967
  } else if (typeof masked[key] === "object" && masked[key] !== null) {
1349
- masked[key] = maskSensitiveData2(masked[key], sensitiveFields, seen);
968
+ masked[key] = maskSensitiveData(masked[key], sensitiveFields, seen);
1350
969
  }
1351
970
  }
1352
971
  return masked;
@@ -1398,7 +1017,7 @@ function RequestLogger(options) {
1398
1017
  if (["POST", "PUT", "PATCH"].includes(method)) {
1399
1018
  try {
1400
1019
  const requestBody = await c.req.json();
1401
- logData.request = maskSensitiveData2(requestBody, cfg.sensitiveFields);
1020
+ logData.request = maskSensitiveData(requestBody, cfg.sensitiveFields);
1402
1021
  } catch {
1403
1022
  }
1404
1023
  }
@@ -1601,6 +1220,6 @@ function reject(c, mode, next, reason) {
1601
1220
  return next();
1602
1221
  }
1603
1222
 
1604
- export { CacheRateLimitStore, ErrorHandler, MemoryRateLimitStore, RequestLogger, createCacheNonceStore, createInMemoryNonceStore, createProxyGuard, getClientIp, getRateLimitPolicy, maskSensitiveData2 as maskSensitiveData, rateLimit, rateLimitPolicy, resetMemoryRateLimitStore, setRateLimitFailClosedDefault, setRateLimitPolicies };
1223
+ export { CacheRateLimitStore, ErrorHandler, MemoryRateLimitStore, RequestLogger, createCacheNonceStore, createInMemoryNonceStore, createProxyGuard, getClientIp, getRateLimitPolicy, maskSensitiveData, rateLimit, rateLimitPolicy, resetMemoryRateLimitStore, setRateLimitFailClosedDefault, setRateLimitPolicies };
1605
1224
  //# sourceMappingURL=index.js.map
1606
1225
  //# sourceMappingURL=index.js.map