@kikiutils/shared 20.0.1 → 20.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/buffer.js.map +1 -1
  2. package/dist/classes/enhanced-date.d.ts +2 -2
  3. package/dist/classes/enhanced-date.d.ts.map +1 -1
  4. package/dist/classes/enhanced-date.js.map +1 -1
  5. package/dist/classes/path.d.ts +1 -1
  6. package/dist/classes/path.d.ts.map +1 -1
  7. package/dist/classes/path.js.map +1 -1
  8. package/dist/enum.d.ts +3 -3
  9. package/dist/enum.d.ts.map +1 -1
  10. package/dist/enum.js.map +1 -1
  11. package/dist/event-awaiter.d.ts.map +1 -1
  12. package/dist/event-awaiter.js +1 -0
  13. package/dist/event-awaiter.js.map +1 -1
  14. package/dist/logger/_internals/formatter.d.ts +12 -4
  15. package/dist/logger/_internals/formatter.d.ts.map +1 -1
  16. package/dist/logger/_internals/formatter.js +12 -4
  17. package/dist/logger/_internals/formatter.js.map +1 -1
  18. package/dist/logger/_internals/logger.d.ts +6 -2
  19. package/dist/logger/_internals/logger.d.ts.map +1 -1
  20. package/dist/logger/_internals/logger.js +3 -1
  21. package/dist/logger/_internals/logger.js.map +1 -1
  22. package/dist/logger/node/_internals/file-writer.d.ts +3 -1
  23. package/dist/logger/node/_internals/file-writer.d.ts.map +1 -1
  24. package/dist/logger/node/_internals/file-writer.js +6 -2
  25. package/dist/logger/node/_internals/file-writer.js.map +1 -1
  26. package/dist/logger/node/_internals/formatter.d.ts +3 -1
  27. package/dist/logger/node/_internals/formatter.d.ts.map +1 -1
  28. package/dist/logger/node/_internals/formatter.js +3 -1
  29. package/dist/logger/node/_internals/formatter.js.map +1 -1
  30. package/dist/logger/node/index.js +3 -1
  31. package/dist/logger/node/index.js.map +1 -1
  32. package/dist/logger/node/types.d.ts +36 -12
  33. package/dist/logger/node/types.d.ts.map +1 -1
  34. package/dist/logger/types.d.ts +44 -19
  35. package/dist/logger/types.d.ts.map +1 -1
  36. package/dist/redis/script-runner.d.ts +1 -1
  37. package/dist/redis/script-runner.d.ts.map +1 -1
  38. package/dist/redis/script-runner.js.map +1 -1
  39. package/dist/types/filtered-key-path.d.ts +2 -2
  40. package/dist/types/filtered-key-path.d.ts.map +1 -1
  41. package/dist/types/index.d.ts +7 -0
  42. package/dist/types/index.d.ts.map +1 -1
  43. package/dist/url.d.ts.map +1 -1
  44. package/dist/url.js.map +1 -1
  45. package/package.json +3 -3
  46. package/src/buffer.ts +0 -1
  47. package/src/classes/enhanced-date.ts +2 -2
  48. package/src/classes/path.ts +1 -1
  49. package/src/enum.ts +3 -3
  50. package/src/event-awaiter.ts +3 -1
  51. package/src/logger/_internals/formatter.ts +12 -4
  52. package/src/logger/_internals/logger.ts +6 -2
  53. package/src/logger/node/_internals/file-writer.ts +6 -2
  54. package/src/logger/node/_internals/formatter.ts +3 -1
  55. package/src/logger/node/index.ts +4 -1
  56. package/src/logger/node/types.ts +36 -12
  57. package/src/logger/types.ts +45 -19
  58. package/src/redis/script-runner.ts +1 -1
  59. package/src/types/filtered-key-path.ts +2 -2
  60. package/src/types/index.ts +6 -0
  61. package/src/url.ts +0 -1
@@ -373,7 +373,7 @@ export class Path {
373
373
  recursive?: boolean;
374
374
  withFileTypes: true;
375
375
  },
376
- ): Promise<fs.Dirent<Buffer>[]>;
376
+ ): Promise<Array<fs.Dirent<Buffer>>>;
377
377
  readdir(...args: any): any {
378
378
  return fsp.readdir(this.#value, ...args);
379
379
  }
package/src/enum.ts CHANGED
@@ -22,7 +22,7 @@
22
22
  * console.log(getEnumNumberValues(RecordType)); // => [0, 1]
23
23
  * ```
24
24
  */
25
- export function getEnumNumberValues<T extends Record<string, any>>(enumObject: T): Extract<T[keyof T], number>[] {
25
+ export function getEnumNumberValues<T extends Record<string, any>>(enumObject: T): Array<Extract<T[keyof T], number>> {
26
26
  return getEnumValues(enumObject).filter((value) => typeof value === 'number');
27
27
  }
28
28
 
@@ -50,7 +50,7 @@ export function getEnumNumberValues<T extends Record<string, any>>(enumObject: T
50
50
  * console.log(getEnumStringValues(RecordType)); // => ['unknown']
51
51
  * ```
52
52
  */
53
- export function getEnumStringValues<T extends Record<string, any>>(enumObject: T): Extract<T[keyof T], string>[] {
53
+ export function getEnumStringValues<T extends Record<string, any>>(enumObject: T): Array<Extract<T[keyof T], string>> {
54
54
  return getEnumValues(enumObject).filter((value) => typeof value === 'string');
55
55
  }
56
56
 
@@ -102,7 +102,7 @@ export function getEnumStringValues<T extends Record<string, any>>(enumObject: T
102
102
  * console.log(getEnumValues(RecordType)); // => [0, 1, 'unknown']
103
103
  * ```
104
104
  */
105
- export function getEnumValues<T extends Record<string, any>>(enumObject: T): (T[keyof T])[] {
105
+ export function getEnumValues<T extends Record<string, any>>(enumObject: T): Array<T[keyof T]> {
106
106
  const values = Object.values(enumObject);
107
107
  const hasNumberValues = values.some((value) => typeof value === 'number');
108
108
  if (!hasNumberValues) return values;
@@ -11,7 +11,7 @@
11
11
  */
12
12
  export class EventAwaiter<T> {
13
13
  // Private instance properties
14
- #promiseResolvers = new Map<string, ((value: PromiseLike<T | undefined> | T | undefined) => void)[]>();
14
+ #promiseResolvers = new Map<string, Array<(value: PromiseLike<T | undefined> | T | undefined) => void>>();
15
15
 
16
16
  // Public instance methods
17
17
 
@@ -69,6 +69,8 @@ export class EventAwaiter<T> {
69
69
  break;
70
70
  case 'strict':
71
71
  throw new Error(`Duplicate wait detected for key: ${key}`);
72
+ case undefined:
73
+ break;
72
74
  }
73
75
  }
74
76
 
@@ -6,7 +6,9 @@ import type { LoggerRecord } from './types';
6
6
 
7
7
  // Functions
8
8
 
9
- /** Native console formatting keeps user strings literal and objects expandable. */
9
+ /**
10
+ * Native console formatting keeps user strings literal and objects expandable.
11
+ */
10
12
  export function formatLoggerConsoleArgs(record: LoggerRecord): unknown[] {
11
13
  if (typeof process !== 'undefined' && process.versions?.node) {
12
14
  const target = process[getLoggerStreamName(record.type)];
@@ -39,7 +41,9 @@ export function formatLoggerConsoleArgs(record: LoggerRecord): unknown[] {
39
41
  ];
40
42
  }
41
43
 
42
- /** Keeps data arguments intact so browser developer tools can expand objects. */
44
+ /**
45
+ * Keeps data arguments intact so browser developer tools can expand objects.
46
+ */
43
47
  export function formatLoggerParts(record: LoggerRecord, colors = false): unknown[] {
44
48
  const parts: unknown[] = [];
45
49
  const paint = (text: string, color: string) => colors ? `\u001B[${color}m${text}\u001B[0m` : text;
@@ -51,7 +55,9 @@ export function formatLoggerParts(record: LoggerRecord, colors = false): unknown
51
55
  return parts;
52
56
  }
53
57
 
54
- /** Fixed local-time representation, deliberately without a per-second cache. */
58
+ /**
59
+ * Fixed local-time representation, deliberately without a per-second cache.
60
+ */
55
61
  export function formatLoggerTime(date: Date): string {
56
62
  const pad = (value: number, width = 2) => String(value).padStart(width, '0');
57
63
  const day = `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
@@ -59,7 +65,9 @@ export function formatLoggerTime(date: Date): string {
59
65
  return `[${day} ${time}.${pad(date.getMilliseconds(), 3)}]`;
60
66
  }
61
67
 
62
- /** Use native terminal detection; redirected streams still honor FORCE_COLOR. */
68
+ /**
69
+ * Use native terminal detection; redirected streams still honor FORCE_COLOR.
70
+ */
63
71
  export function supportsLoggerColor(target: { hasColors?: () => boolean; isTTY?: boolean }): boolean {
64
72
  if (target.hasColors) return target.hasColors();
65
73
  const forced = process.env.FORCE_COLOR;
@@ -10,7 +10,9 @@ import { loggerMethods } from './levels';
10
10
  import type { LoggerRecord } from './types';
11
11
 
12
12
  interface LoggerHooks {
13
- /** A non-throwing reporter created by createDiagnosticReporter. */
13
+ /**
14
+ * A non-throwing reporter created by createDiagnosticReporter.
15
+ */
14
16
  report: (event: LoggerDiagnostic) => void;
15
17
  write: (record: LoggerRecord) => Promise<void> | void;
16
18
  }
@@ -29,7 +31,9 @@ const stringPresentationKeys = [
29
31
 
30
32
  // Functions
31
33
 
32
- /** A non-recursive, rate-limited diagnostic boundary shared by server and browser adapters. */
34
+ /**
35
+ * A non-recursive, rate-limited diagnostic boundary shared by server and browser adapters.
36
+ */
33
37
  export function createDiagnosticReporter(
34
38
  onError?: (event: Readonly<LoggerDiagnostic>) => void,
35
39
  fallback?: (message: string) => void,
@@ -26,7 +26,9 @@ const defaultMaxPendingBytes = 8 * 1024 * 1024;
26
26
 
27
27
  // Functions
28
28
 
29
- /** A bounded admission layer over the stream's own ordered write buffer; not a second FIFO. */
29
+ /**
30
+ * A bounded admission layer over the stream's own ordered write buffer; not a second FIFO.
31
+ */
30
32
  export async function createFileWriter(
31
33
  options: LoggerFileOptions,
32
34
  report: (event: LoggerDiagnostic) => void,
@@ -213,7 +215,9 @@ export async function createFileWriter(
213
215
  });
214
216
  }
215
217
 
216
- /** Validate before mkdir, stream creation, or other filesystem side effects. */
218
+ /**
219
+ * Validate before mkdir, stream creation, or other filesystem side effects.
220
+ */
217
221
  function validateFileOptions(options: LoggerFileOptions) {
218
222
  if (
219
223
  !options
@@ -5,7 +5,9 @@ import type { LoggerRecord } from '../../_internals/types';
5
5
 
6
6
  // Functions
7
7
 
8
- /** Preserve user ANSI for console output without invoking custom inspect callbacks/getters. */
8
+ /**
9
+ * Preserve user ANSI for console output without invoking custom inspect callbacks/getters.
10
+ */
9
11
  export function formatNodeLoggerRecord(record: LoggerRecord, colors = false) {
10
12
  const message = record.args.map(
11
13
  (arg) => typeof arg === 'string'
@@ -107,6 +107,7 @@ export async function createNodeLogger(options: NodeLoggerOptions = {}): Promise
107
107
 
108
108
  consoleTargets.clear();
109
109
  })();
110
+
110
111
  return closePromise;
111
112
  },
112
113
  getStats: () => writer?.getStats() ?? Object.freeze({
@@ -117,7 +118,9 @@ export async function createNodeLogger(options: NodeLoggerOptions = {}): Promise
117
118
  });
118
119
  }
119
120
 
120
- /** One error listener per shared output stream; retained until its last owning logger calls close(). */
121
+ /**
122
+ * One error listener per shared output stream; retained until its last owning logger calls close().
123
+ */
121
124
  function writeConsole(
122
125
  target: NodeJS.WriteStream,
123
126
  text: string,
@@ -4,50 +4,74 @@ import type {
4
4
  LoggerOptions,
5
5
  } from '../types';
6
6
 
7
- /** Specify interval and/or maxSize. Size limits use positive integers with B, K, M, or G (binary units). */
7
+ /**
8
+ * Specify interval and/or maxSize. Size limits use positive integers with B, K, M, or G (binary units).
9
+ */
8
10
  export type LoggerRotationOptions = {
9
- /** Gzip historical files. Defaults to true. */
11
+ /**
12
+ * Gzip historical files. Defaults to true.
13
+ */
10
14
  compress?: boolean;
11
15
 
12
- /** Number of historical files, excluding the active file. Defaults to 30. */
16
+ /**
17
+ * Number of historical files, excluding the active file. Defaults to 30.
18
+ */
13
19
  keepFiles?: number;
14
20
 
15
- /** Maximum combined size of historical files. */
21
+ /**
22
+ * Maximum combined size of historical files.
23
+ */
16
24
  maxTotalSize?: string;
17
25
  } & (
18
26
  | {
19
- /** Opt-in time rotation aligned to the system's local calendar boundary. */
27
+ /**
28
+ * Opt-in time rotation aligned to the system's local calendar boundary.
29
+ */
20
30
  interval: 'daily' | 'hourly';
21
31
  maxSize?: string;
22
32
  }
23
33
  | {
24
- /** Opt-in time rotation aligned to the system's local calendar boundary. */
34
+ /**
35
+ * Opt-in time rotation aligned to the system's local calendar boundary.
36
+ */
25
37
  interval?: 'daily' | 'hourly';
26
38
  maxSize: string;
27
39
  }
28
40
  );
29
41
 
30
42
  export interface LoggerFileOptions {
31
- /** Maximum unfinished payload bytes, including data already submitted to the stream. */
43
+ /**
44
+ * Maximum unfinished payload bytes, including data already submitted to the stream.
45
+ */
32
46
  maxPendingBytes?: number;
33
47
 
34
- /** Resolved once at creation. The file is opened in append mode. */
48
+ /**
49
+ * Resolved once at creation. The file is opened in append mode.
50
+ */
35
51
  path: PathLike;
36
52
 
37
- /** Omitted or false disables rotation. An object must specify interval or maxSize. */
53
+ /**
54
+ * Omitted or false disables rotation. An object must specify interval or maxSize.
55
+ */
38
56
  rotate?: false | LoggerRotationOptions;
39
57
  }
40
58
 
41
59
  export interface NodeLogger extends Logger {
42
- /** Stop accepting records, finish accepted file writes, then release the stream. Not fsync. */
60
+ /**
61
+ * Stop accepting records, finish accepted file writes, then release the stream. Not fsync.
62
+ */
43
63
  close: () => Promise<void>;
44
64
 
45
- /** A fresh, frozen file-output snapshot. Dropped/failed records still resolve their logging promises. */
65
+ /**
66
+ * A fresh, frozen file-output snapshot. Dropped/failed records still resolve their logging promises.
67
+ */
46
68
  getStats: () => Readonly<NodeLoggerStats>;
47
69
  }
48
70
 
49
71
  export interface NodeLoggerOptions extends LoggerOptions {
50
- /** Disabled by default. Each logger owns at most one fixed file destination. */
72
+ /**
73
+ * Disabled by default. Each logger owns at most one fixed file destination.
74
+ */
51
75
  file?: false | LoggerFileOptions;
52
76
  }
53
77
 
@@ -1,7 +1,13 @@
1
- /** Minimum severity to emit; `success` uses the same threshold as `info`. */
1
+ import type { SafePromise } from '../types';
2
+
3
+ /**
4
+ * Minimum severity to emit; `success` uses the same threshold as `info`.
5
+ */
2
6
  export type LoggerLevel = 'debug' | 'error' | 'fatal' | 'info' | 'silent' | 'trace' | 'warn';
3
7
 
4
- /** A logging method, including the informational success presentation. */
8
+ /**
9
+ * A logging method, including the informational success presentation.
10
+ */
5
11
  export type LoggerMethod = 'success' | Exclude<LoggerLevel, 'silent'>;
6
12
 
7
13
  /**
@@ -13,48 +19,68 @@ export type LoggerMethod = 'success' | Exclude<LoggerLevel, 'silent'>;
13
19
  */
14
20
  export interface Logger {
15
21
  configure: (options: Pick<LoggerOptions, 'console' | 'icons' | 'prefix' | 'suffix' | 'timestamp'>) => void;
16
- debug: (...args: unknown[]) => Promise<void>;
17
- error: (...args: unknown[]) => Promise<void>;
18
- fatal: (...args: unknown[]) => Promise<void>;
19
- info: (...args: unknown[]) => Promise<void>;
22
+ debug: (...args: unknown[]) => SafePromise<void>;
23
+ error: (...args: unknown[]) => SafePromise<void>;
24
+ fatal: (...args: unknown[]) => SafePromise<void>;
25
+ info: (...args: unknown[]) => SafePromise<void>;
20
26
 
21
- /** Accepts success as an informational method; it is not a configurable threshold. */
27
+ /**
28
+ * Accepts success as an informational method; it is not a configurable threshold.
29
+ */
22
30
  isLevelEnabled: (level: LoggerLevel | LoggerMethod) => boolean;
23
31
 
24
- /** Sets a severity threshold (not success); env restores environment-driven filtering. */
32
+ /**
33
+ * Sets a severity threshold (not success); env restores environment-driven filtering.
34
+ */
25
35
  setLevel: (level: 'env' | LoggerLevel) => void;
26
- success: (...args: unknown[]) => Promise<void>;
27
- trace: (...args: unknown[]) => Promise<void>;
28
- warn: (...args: unknown[]) => Promise<void>;
36
+ success: (...args: unknown[]) => SafePromise<void>;
37
+ trace: (...args: unknown[]) => SafePromise<void>;
38
+ warn: (...args: unknown[]) => SafePromise<void>;
29
39
  }
30
40
 
31
- /** A shallow-frozen failure notification; nested error values retain their original ownership. */
41
+ /**
42
+ * A shallow-frozen failure notification; nested error values retain their original ownership.
43
+ */
32
44
  export interface LoggerDiagnostic {
33
45
  droppedCount?: number;
34
46
  error?: unknown;
35
47
  message: string;
36
48
 
37
- /** Same-type notifications suppressed since the previous emitted diagnostic. */
49
+ /**
50
+ * Same-type notifications suppressed since the previous emitted diagnostic.
51
+ */
38
52
  suppressedCount?: number;
39
53
  type: 'closed' | 'console' | 'file' | 'format' | 'invalid-level' | 'overflow';
40
54
  }
41
55
 
42
- /** Configuration shared by browser and server loggers. */
56
+ /**
57
+ * Configuration shared by browser and server loggers.
58
+ */
43
59
  export interface LoggerOptions {
44
- /** Enables console output. Defaults to `true`. */
60
+ /**
61
+ * Enables console output. Defaults to `true`.
62
+ */
45
63
  console?: boolean;
46
64
 
47
- /** Enables Unicode level icons. Defaults to `true`. */
65
+ /**
66
+ * Enables Unicode level icons. Defaults to `true`.
67
+ */
48
68
  icons?: boolean;
49
69
 
50
- /** Overrides LOG_LEVEL; `env` restores the environment-driven threshold. */
70
+ /**
71
+ * Overrides LOG_LEVEL; `env` restores the environment-driven threshold.
72
+ */
51
73
  level?: 'env' | LoggerLevel;
52
74
 
53
- /** Best-effort, rate-limited notification; failures in this callback are contained. */
75
+ /**
76
+ * Best-effort, rate-limited notification; failures in this callback are contained.
77
+ */
54
78
  onError?: (event: Readonly<LoggerDiagnostic>) => void;
55
79
  prefix?: string;
56
80
  suffix?: string;
57
81
 
58
- /** Enables the fixed local-time millisecond prefix. Defaults to `true`. */
82
+ /**
83
+ * Enables the fixed local-time millisecond prefix. Defaults to `true`.
84
+ */
59
85
  timestamp?: boolean;
60
86
  }
@@ -14,7 +14,7 @@ import { createHash } from 'node:crypto';
14
14
  *
15
15
  * @returns A promise resolving to the Redis script result after execution completes.
16
16
  */
17
- export type RedisScriptRunner<T = unknown> = (keys: readonly string[], args: readonly (number | string)[]) => Promise<
17
+ export type RedisScriptRunner<T = unknown> = (keys: readonly string[], args: ReadonlyArray<number | string>) => Promise<
18
18
  T
19
19
  >;
20
20
 
@@ -22,7 +22,7 @@ type DefaultPath<
22
22
  export type FilteredKeyPath<T, U = never> = T extends ReadonlyArray<infer V> ? (IsTuple<T> extends true ? { [K in TupleKey<T>]-?: PathImpl<Exclude<K, symbol>, T[K], U> }[TupleKey<T>] : PathImpl<number, V, U>) : { [K in keyof T]-?: PathImpl<Exclude<K, symbol>, T[K], U> }[keyof T];
23
23
  /* eslint-enable style/max-len */
24
24
 
25
- type IsTuple<T extends ReadonlyArray<any>> = number extends T['length'] ? false : true;
25
+ type IsTuple<T extends readonly any[]> = number extends T['length'] ? false : true;
26
26
  type PathImpl<K extends number | string, V, U> = [U] extends [never] ? DefaultPath<K, V> : ConditionalPath<K, V, U>;
27
27
  type TerminalType =
28
28
  | bigint
@@ -38,4 +38,4 @@ type TerminalType =
38
38
  | symbol
39
39
  | undefined;
40
40
 
41
- type TupleKey<T extends ReadonlyArray<any>> = Exclude<keyof T, keyof any[]>;
41
+ type TupleKey<T extends readonly any[]> = Exclude<keyof T, keyof any[]>;
@@ -40,3 +40,9 @@ export type ReadonlyPartialRecord<K extends keyof any, T> = Readonly<PartialReco
40
40
  * A readonly `Record`.
41
41
  */
42
42
  export type ReadonlyRecord<K extends keyof any, T> = Readonly<Record<K, T>>;
43
+
44
+ /**
45
+ * A promise whose rejection is handled internally and can safely be left unawaited.
46
+ * This type only marks that contract; it does not add runtime rejection handling.
47
+ */
48
+ export type SafePromise<T> = Promise<T> & { readonly __safePromise?: true };
package/src/url.ts CHANGED
@@ -12,7 +12,6 @@
12
12
  * @throws Error if `redirectPath` is not a safe same-origin application path.
13
13
  */
14
14
  export function appendRedirectParamToUrl(url: string, redirectPath: string) {
15
- // eslint-disable-next-line style/max-len
16
15
  if (!isSafeRedirectPath(redirectPath)) throw new Error(`Invalid redirect path: "${redirectPath}". Redirect paths must be safe same-origin paths starting with '/'.`);
17
16
 
18
17
  const [baseAndHash, rawQuery = ''] = url.split('?');