@kikiutils/shared 20.1.0 → 20.1.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/classes/path.d.ts.map +1 -1
- package/dist/classes/path.js +30 -30
- package/dist/classes/path.js.map +1 -1
- package/dist/enum.d.ts +4 -3
- package/dist/enum.d.ts.map +1 -1
- package/dist/enum.js +3 -2
- package/dist/enum.js.map +1 -1
- package/dist/event-awaiter.d.ts.map +1 -1
- package/dist/event-awaiter.js +6 -6
- package/dist/event-awaiter.js.map +1 -1
- package/dist/general.d.ts +3 -2
- package/dist/general.d.ts.map +1 -1
- package/dist/general.js.map +1 -1
- package/dist/logger/_internals/logger.d.ts.map +1 -1
- package/dist/logger/_internals/logger.js +3 -2
- package/dist/logger/_internals/logger.js.map +1 -1
- package/dist/logger/node/_internals/file-writer.js +7 -7
- package/dist/logger/node/_internals/file-writer.js.map +1 -1
- package/dist/logger/node/index.js +8 -8
- package/dist/logger/node/index.js.map +1 -1
- package/dist/storages/redis/keyed-store.d.ts.map +1 -1
- package/dist/storages/redis/keyed-store.js +10 -10
- package/dist/storages/redis/keyed-store.js.map +1 -1
- package/dist/storages/redis/msgpack.js +2 -2
- package/dist/storages/redis/msgpack.js.map +1 -1
- package/dist/time.d.ts.map +1 -1
- package/dist/time.js +4 -4
- package/dist/time.js.map +1 -1
- package/package.json +15 -11
- package/src/classes/path.ts +30 -30
- package/src/enum.ts +11 -5
- package/src/event-awaiter.ts +6 -6
- package/src/general.ts +5 -3
- package/src/logger/_internals/logger.ts +7 -2
- package/src/logger/node/_internals/file-writer.ts +7 -7
- package/src/logger/node/index.ts +9 -9
- package/src/storages/redis/keyed-store.ts +10 -10
- package/src/storages/redis/msgpack.ts +2 -2
- package/src/time.ts +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-writer.js","names":[],"sources":["../../../../src/logger/node/_internals/file-writer.ts"],"sourcesContent":["import { Buffer } from 'node:buffer';\nimport { createWriteStream } from 'node:fs';\nimport { mkdir } from 'node:fs/promises';\nimport {\n basename,\n dirname,\n} from 'node:path';\nimport type { Writable } from 'node:stream';\nimport { fileURLToPath } from 'node:url';\n\nimport { Path } from '../../../classes/path';\nimport type { LoggerDiagnostic } from '../../types';\nimport type {\n LoggerFileOptions,\n NodeLoggerStats,\n} from '../types';\n\ninterface LoggerFileWriter {\n close: () => Promise<void>;\n getStats: () => Readonly<NodeLoggerStats>;\n write: (text: string) => Promise<void>;\n}\n\n// Constants/Variables\nconst defaultMaxPendingBytes = 8 * 1024 * 1024;\n\n// Functions\n\n/**\n * A bounded admission layer over the stream's own ordered write buffer; not a second FIFO.\n */\nexport async function createFileWriter(\n options: LoggerFileOptions,\n report: (event: LoggerDiagnostic) => void,\n): Promise<Readonly<LoggerFileWriter>> {\n const {\n maxPendingBytes,\n path,\n rotate,\n } = validateFileOptions(options);\n\n const createRotatingStream = rotate ? (await import('rotating-file-stream')).createStream : undefined;\n await mkdir(dirname(path), { recursive: true });\n const stream: Writable = rotate && createRotatingStream\n ? createRotatingStream(\n basename(path),\n {\n compress: rotate.compress === false ? false : 'gzip',\n ...rotate.interval === undefined ? {} : { interval: rotate.interval === 'hourly' ? '1h' : '1d' },\n intervalBoundary: true,\n intervalUTC: false,\n maxFiles: rotate.keepFiles ?? 30,\n ...rotate.maxTotalSize === undefined ? {} : { maxSize: rotate.maxTotalSize },\n path: dirname(path),\n ...rotate.maxSize === undefined ? {} : { size: rotate.maxSize },\n },\n )\n : createWriteStream(path, { flags: 'a' });\n\n let pendingBytes = 0;\n let droppedCount = 0;\n let writeErrorCount = 0;\n let failed = false;\n let closing = false;\n let closed = false;\n let closePromise: Promise<void> | undefined;\n let initializing = true;\n const unfinished = new Set<() => void>();\n let rejectInitialization: ((error: unknown) => void) | undefined;\n\n const settleAll = () => {\n for (const settle of unfinished) settle();\n };\n\n const fail = (error: unknown) => {\n rejectInitialization?.(error);\n if (!failed) {\n failed = true;\n if (!initializing) {\n writeErrorCount++;\n report({\n error,\n message: 'File output failed and has been disabled.',\n type: 'file',\n });\n }\n }\n\n settleAll();\n if (!stream.destroyed) stream.destroy();\n };\n\n stream.on('error', fail);\n stream.on(\n 'warning',\n (error: unknown) => {\n writeErrorCount++;\n report({\n error,\n message: 'File rotation cleanup failed.',\n type: 'file',\n });\n },\n );\n\n stream.on(\n 'close',\n () => {\n closed = true;\n if (!closing && !failed) fail(new Error('File stream closed unexpectedly.'));\n settleAll();\n },\n );\n\n // A write callback also waits for RFS's asynchronous initialization and initial rotation.\n try {\n await new Promise<void>((resolveReady, rejectReady) => {\n rejectInitialization = rejectReady;\n stream.write(\n Buffer.alloc(0),\n (error) => {\n if (error) rejectReady(error);\n else resolveReady();\n },\n );\n });\n\n if (failed || closed) throw new Error('File output failed during initialization.');\n } catch (error) {\n if (!stream.destroyed) stream.destroy();\n if (!closed) {\n await new Promise<void>((resolveClosed) => {\n stream.once('close', resolveClosed);\n });\n }\n\n throw error;\n } finally {\n rejectInitialization = undefined;\n initializing = false;\n }\n\n return Object.freeze({\n close() {\n if (closePromise) return closePromise;\n closing = true;\n closePromise = new Promise<void>((resolveClosed) => {\n if (closed) {\n resolveClosed();\n return;\n }\n\n stream.once('close', resolveClosed);\n try {\n if (!stream.destroyed) stream.end();\n } catch (error) {\n fail(error);\n }\n });\n\n return closePromise;\n },\n getStats: () => Object.freeze({\n droppedCount,\n pendingBytes,\n writeErrorCount,\n }),\n write(text: string) {\n if (closing || closed || failed) {\n report({\n message: 'File output is closed or unavailable.',\n type: 'closed',\n });\n\n return Promise.resolve();\n }\n\n const bytes = Buffer.byteLength(text);\n if (bytes > maxPendingBytes - pendingBytes) {\n droppedCount++;\n report({\n droppedCount,\n message: 'File output queue is full; the newest record was discarded.',\n type: 'overflow',\n });\n\n return Promise.resolve();\n }\n\n pendingBytes += bytes;\n return new Promise<void>((resolveWritten) => {\n let settled = false;\n const settle = () => {\n if (settled) return;\n settled = true;\n pendingBytes -= bytes;\n unfinished.delete(settle);\n resolveWritten();\n };\n\n unfinished.add(settle);\n try {\n stream.write(\n text,\n (error) => {\n if (error) fail(error);\n settle();\n },\n );\n } catch (error) {\n fail(error);\n }\n });\n },\n });\n}\n\n/**\n * Validate before mkdir, stream creation, or other filesystem side effects.\n */\nfunction validateFileOptions(options: LoggerFileOptions) {\n if (\n !options\n || typeof options !== 'object'\n || !(\n typeof options.path === 'string'\n || options.path instanceof Path\n || options.path instanceof URL\n || Buffer.isBuffer(options.path)\n )\n ) {\n throw new TypeError('file.path must be a string, Buffer, file URL, or Path');\n }\n\n const path = options.path instanceof URL\n ? fileURLToPath(options.path)\n : options.path.toString();\n\n if (Buffer.isBuffer(options.path) && !Buffer.from(path).equals(options.path)) {\n throw new TypeError('file.path Buffer must contain valid UTF-8');\n }\n\n if (!path.trim() || path.includes('\\0')) {\n throw new TypeError('file.path must be a nonempty path without null bytes');\n }\n\n const maxPendingBytes = options.maxPendingBytes ?? defaultMaxPendingBytes;\n if (!Number.isSafeInteger(maxPendingBytes) || maxPendingBytes <= 0) {\n throw new RangeError('file.maxPendingBytes must be a positive safe integer');\n }\n\n const rotate = options.rotate;\n if (rotate !== undefined && rotate !== false) {\n if (!rotate || typeof rotate !== 'object') {\n throw new TypeError('file.rotate must be false or an options object');\n }\n\n if (rotate.interval !== undefined && rotate.interval !== 'hourly' && rotate.interval !== 'daily') {\n throw new TypeError('file.rotate.interval must be hourly or daily');\n }\n\n if (rotate.interval === undefined && rotate.maxSize === undefined) {\n throw new TypeError('file.rotate requires interval or maxSize');\n }\n\n const keepFiles = rotate.keepFiles ?? 30;\n if (!Number.isSafeInteger(keepFiles) || keepFiles <= 0) {\n throw new RangeError('file.rotate.keepFiles must be a positive safe integer');\n }\n\n if (rotate.compress !== undefined && typeof rotate.compress !== 'boolean') {\n throw new TypeError('file.rotate.compress must be a boolean');\n }\n\n validateSize(rotate.maxSize, 'file.rotate.maxSize');\n validateSize(rotate.maxTotalSize, 'file.rotate.maxTotalSize');\n }\n\n return {\n maxPendingBytes,\n path: Path.resolve(path).value,\n rotate,\n };\n}\n\nfunction validateSize(value: string | undefined, name: string) {\n if (value === undefined) return;\n if (typeof value !== 'string' || !/^[1-9]\\d*[BKMG]$/.test(value)) {\n throw new TypeError(`${name} must be a positive integer followed by B, K, M, or G`);\n }\n\n const multiplier = {\n B: 1,\n G: 1024 ** 3,\n K: 1024,\n M: 1024 ** 2,\n }[value.at(-1) as 'B' | 'G' | 'K' | 'M'];\n\n if (!Number.isSafeInteger(Number(value.slice(0, -1)) * multiplier)) {\n throw new RangeError(`${name} exceeds the supported size range`);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"file-writer.js","names":[],"sources":["../../../../src/logger/node/_internals/file-writer.ts"],"sourcesContent":["import { Buffer } from 'node:buffer';\nimport { createWriteStream } from 'node:fs';\nimport { mkdir } from 'node:fs/promises';\nimport {\n basename,\n dirname,\n} from 'node:path';\nimport type { Writable } from 'node:stream';\nimport { fileURLToPath } from 'node:url';\n\nimport { Path } from '../../../classes/path';\nimport type { LoggerDiagnostic } from '../../types';\nimport type {\n LoggerFileOptions,\n NodeLoggerStats,\n} from '../types';\n\ninterface LoggerFileWriter {\n close: () => Promise<void>;\n getStats: () => Readonly<NodeLoggerStats>;\n write: (text: string) => Promise<void>;\n}\n\n// Constants/Variables\nconst defaultMaxPendingBytes = 8 * 1024 * 1024;\n\n// Functions\n\n/**\n * A bounded admission layer over the stream's own ordered write buffer; not a second FIFO.\n */\nexport async function createFileWriter(\n options: LoggerFileOptions,\n report: (event: LoggerDiagnostic) => void,\n): Promise<Readonly<LoggerFileWriter>> {\n const {\n maxPendingBytes,\n path,\n rotate,\n } = validateFileOptions(options);\n\n const createRotatingStream = rotate ? (await import('rotating-file-stream')).createStream : undefined;\n await mkdir(dirname(path), { recursive: true });\n const stream: Writable = rotate && createRotatingStream\n ? createRotatingStream(\n basename(path),\n {\n compress: rotate.compress === false ? false : 'gzip',\n ...rotate.interval === undefined ? {} : { interval: rotate.interval === 'hourly' ? '1h' : '1d' },\n intervalBoundary: true,\n intervalUTC: false,\n maxFiles: rotate.keepFiles ?? 30,\n ...rotate.maxTotalSize === undefined ? {} : { maxSize: rotate.maxTotalSize },\n path: dirname(path),\n ...rotate.maxSize === undefined ? {} : { size: rotate.maxSize },\n },\n )\n : createWriteStream(path, { flags: 'a' });\n\n let pendingBytes = 0;\n let droppedCount = 0;\n let writeErrorCount = 0;\n let failed = false;\n let closing = false;\n let closed = false;\n let closePromise: Promise<void> | undefined;\n let initializing = true;\n const unfinished = new Set<() => void>();\n let rejectInitialization: ((error: unknown) => void) | undefined;\n\n const settleAll = () => {\n for (const settle of unfinished) settle();\n };\n\n const fail = (error: unknown) => {\n rejectInitialization?.(error);\n if (!failed) {\n failed = true;\n if (!initializing) {\n writeErrorCount++;\n report({\n error,\n message: 'File output failed and has been disabled.',\n type: 'file',\n });\n }\n }\n\n settleAll();\n if (!stream.destroyed) stream.destroy();\n };\n\n stream.on('error', fail);\n stream.on(\n 'warning',\n (error: unknown) => {\n writeErrorCount++;\n report({\n error,\n message: 'File rotation cleanup failed.',\n type: 'file',\n });\n },\n );\n\n stream.on(\n 'close',\n () => {\n closed = true;\n if (!closing && !failed) fail(new Error('File stream closed unexpectedly.'));\n settleAll();\n },\n );\n\n // A write callback also waits for RFS's asynchronous initialization and initial rotation.\n try {\n await new Promise<void>((resolveReady, rejectReady) => {\n rejectInitialization = rejectReady;\n stream.write(\n Buffer.alloc(0),\n (error) => {\n if (error) rejectReady(error);\n else resolveReady();\n },\n );\n });\n\n if (failed || closed) throw new Error('File output failed during initialization.');\n } catch (error) {\n if (!stream.destroyed) stream.destroy();\n if (!closed) {\n await new Promise<void>((resolveClosed) => {\n stream.once('close', resolveClosed);\n });\n }\n\n throw error;\n } finally {\n rejectInitialization = undefined;\n initializing = false;\n }\n\n return Object.freeze({\n async close() {\n if (closePromise) return await closePromise;\n closing = true;\n closePromise = new Promise<void>((resolveClosed) => {\n if (closed) {\n resolveClosed();\n return;\n }\n\n stream.once('close', resolveClosed);\n try {\n if (!stream.destroyed) stream.end();\n } catch (error) {\n fail(error);\n }\n });\n\n return await closePromise;\n },\n getStats: () => Object.freeze({\n droppedCount,\n pendingBytes,\n writeErrorCount,\n }),\n async write(text: string) {\n if (closing || closed || failed) {\n report({\n message: 'File output is closed or unavailable.',\n type: 'closed',\n });\n\n return await Promise.resolve();\n }\n\n const bytes = Buffer.byteLength(text);\n if (bytes > maxPendingBytes - pendingBytes) {\n droppedCount++;\n report({\n droppedCount,\n message: 'File output queue is full; the newest record was discarded.',\n type: 'overflow',\n });\n\n return await Promise.resolve();\n }\n\n pendingBytes += bytes;\n return await new Promise<void>((resolveWritten) => {\n let settled = false;\n const settle = () => {\n if (settled) return;\n settled = true;\n pendingBytes -= bytes;\n unfinished.delete(settle);\n resolveWritten();\n };\n\n unfinished.add(settle);\n try {\n stream.write(\n text,\n (error) => {\n if (error) fail(error);\n settle();\n },\n );\n } catch (error) {\n fail(error);\n }\n });\n },\n });\n}\n\n/**\n * Validate before mkdir, stream creation, or other filesystem side effects.\n */\nfunction validateFileOptions(options: LoggerFileOptions) {\n if (\n !options\n || typeof options !== 'object'\n || !(\n typeof options.path === 'string'\n || options.path instanceof Path\n || options.path instanceof URL\n || Buffer.isBuffer(options.path)\n )\n ) {\n throw new TypeError('file.path must be a string, Buffer, file URL, or Path');\n }\n\n const path = options.path instanceof URL\n ? fileURLToPath(options.path)\n : options.path.toString();\n\n if (Buffer.isBuffer(options.path) && !Buffer.from(path).equals(options.path)) {\n throw new TypeError('file.path Buffer must contain valid UTF-8');\n }\n\n if (!path.trim() || path.includes('\\0')) {\n throw new TypeError('file.path must be a nonempty path without null bytes');\n }\n\n const maxPendingBytes = options.maxPendingBytes ?? defaultMaxPendingBytes;\n if (!Number.isSafeInteger(maxPendingBytes) || maxPendingBytes <= 0) {\n throw new RangeError('file.maxPendingBytes must be a positive safe integer');\n }\n\n const rotate = options.rotate;\n if (rotate !== undefined && rotate !== false) {\n if (!rotate || typeof rotate !== 'object') {\n throw new TypeError('file.rotate must be false or an options object');\n }\n\n if (rotate.interval !== undefined && rotate.interval !== 'hourly' && rotate.interval !== 'daily') {\n throw new TypeError('file.rotate.interval must be hourly or daily');\n }\n\n if (rotate.interval === undefined && rotate.maxSize === undefined) {\n throw new TypeError('file.rotate requires interval or maxSize');\n }\n\n const keepFiles = rotate.keepFiles ?? 30;\n if (!Number.isSafeInteger(keepFiles) || keepFiles <= 0) {\n throw new RangeError('file.rotate.keepFiles must be a positive safe integer');\n }\n\n if (rotate.compress !== undefined && typeof rotate.compress !== 'boolean') {\n throw new TypeError('file.rotate.compress must be a boolean');\n }\n\n validateSize(rotate.maxSize, 'file.rotate.maxSize');\n validateSize(rotate.maxTotalSize, 'file.rotate.maxTotalSize');\n }\n\n return {\n maxPendingBytes,\n path: Path.resolve(path).value,\n rotate,\n };\n}\n\nfunction validateSize(value: string | undefined, name: string) {\n if (value === undefined) return;\n if (typeof value !== 'string' || !/^[1-9]\\d*[BKMG]$/.test(value)) {\n throw new TypeError(`${name} must be a positive integer followed by B, K, M, or G`);\n }\n\n const multiplier = {\n B: 1,\n G: 1024 ** 3,\n K: 1024,\n M: 1024 ** 2,\n }[value.at(-1) as 'B' | 'G' | 'K' | 'M'];\n\n if (!Number.isSafeInteger(Number(value.slice(0, -1)) * multiplier)) {\n throw new RangeError(`${name} exceeds the supported size range`);\n }\n}\n"],"mappings":"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"}
|
|
@@ -24,7 +24,7 @@ async function createNodeLogger(options = {}) {
|
|
|
24
24
|
const consoleWrites = /* @__PURE__ */ new Set();
|
|
25
25
|
const logger = createLoggerCore(options, {
|
|
26
26
|
report,
|
|
27
|
-
write(record) {
|
|
27
|
+
async write(record) {
|
|
28
28
|
if (closed) {
|
|
29
29
|
report({
|
|
30
30
|
message: "Logger is closed.",
|
|
@@ -42,16 +42,16 @@ async function createNodeLogger(options = {}) {
|
|
|
42
42
|
consoleWrites.add(completion);
|
|
43
43
|
completion.then(() => consoleWrites.delete(completion));
|
|
44
44
|
const fileCompletion = writer?.write(`${stripVTControlCharacters(text)}\n`);
|
|
45
|
-
return fileCompletion ? Promise.all([completion, fileCompletion]).then(() => {}) : completion;
|
|
45
|
+
return fileCompletion ? await Promise.all([completion, fileCompletion]).then(() => {}) : await completion;
|
|
46
46
|
}
|
|
47
|
-
return writer?.write(`${stripVTControlCharacters(text)}\n`);
|
|
47
|
+
return await writer?.write(`${stripVTControlCharacters(text)}\n`);
|
|
48
48
|
}
|
|
49
49
|
});
|
|
50
50
|
if (options.file !== void 0 && options.file !== false) writer = await createFileWriter(options.file, report);
|
|
51
51
|
return Object.freeze({
|
|
52
52
|
...logger,
|
|
53
|
-
close() {
|
|
54
|
-
if (closePromise) return closePromise;
|
|
53
|
+
async close() {
|
|
54
|
+
if (closePromise) return await closePromise;
|
|
55
55
|
closed = true;
|
|
56
56
|
closePromise = (async () => {
|
|
57
57
|
await Promise.all([writer?.close(), ...consoleWrites]);
|
|
@@ -67,7 +67,7 @@ async function createNodeLogger(options = {}) {
|
|
|
67
67
|
}
|
|
68
68
|
consoleTargets.clear();
|
|
69
69
|
})();
|
|
70
|
-
return closePromise;
|
|
70
|
+
return await closePromise;
|
|
71
71
|
},
|
|
72
72
|
getStats: () => writer?.getStats() ?? Object.freeze({
|
|
73
73
|
droppedCount: 0,
|
|
@@ -79,7 +79,7 @@ async function createNodeLogger(options = {}) {
|
|
|
79
79
|
/**
|
|
80
80
|
* One error listener per shared output stream; retained until its last owning logger calls close().
|
|
81
81
|
*/
|
|
82
|
-
function writeConsole(target, text, report, owner) {
|
|
82
|
+
async function writeConsole(target, text, report, owner) {
|
|
83
83
|
let state = consoleStreams.get(target);
|
|
84
84
|
if (!state) {
|
|
85
85
|
const pending = /* @__PURE__ */ new Set();
|
|
@@ -99,7 +99,7 @@ function writeConsole(target, text, report, owner) {
|
|
|
99
99
|
}
|
|
100
100
|
state.owners.add(owner);
|
|
101
101
|
const current = state;
|
|
102
|
-
return new Promise((resolveWritten) => {
|
|
102
|
+
return await new Promise((resolveWritten) => {
|
|
103
103
|
let settled = false;
|
|
104
104
|
const settle = (error) => {
|
|
105
105
|
if (settled) return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/logger/node/index.ts"],"sourcesContent":["import { writeSync } from 'node:fs';\nimport { stripVTControlCharacters } from 'node:util';\n\nimport { supportsLoggerColor } from '../_internals/formatter';\nimport { getLoggerStreamName } from '../_internals/levels';\nimport {\n createDiagnosticReporter,\n createLoggerCore,\n} from '../_internals/logger';\nimport type { LoggerDiagnostic } from '../types';\n\nimport { createFileWriter } from './_internals/file-writer';\nimport { formatNodeLoggerRecord } from './_internals/formatter';\nimport type {\n NodeLogger,\n NodeLoggerOptions,\n} from './types';\n\ninterface ConsoleStreamState {\n onClose: () => void;\n onError: (error: Error) => void;\n owners: Set<object>;\n pending: Set<(error?: Error | null) => void>;\n}\n\n// Constants/Variables\nconst consoleStreams = new WeakMap<NodeJS.WriteStream, ConsoleStreamState>();\n\n// Functions\n\n/**\n * Creates a Node.js/Bun logger with optional bounded, append-only file output and rotation.\n *\n * Log calls never throw or reject. Awaiting them waits for processing, not proof of successful\n * persistence: overload drops the newest file record and failures are reported safely. Factory\n * validation/open failures reject. Call close explicitly; no process signal handlers are installed.\n */\nexport async function createNodeLogger(options: NodeLoggerOptions = {}): Promise<Readonly<NodeLogger>> {\n const report = createDiagnosticReporter(options.onError, (message) => writeSync(2, message));\n let writer: Awaited<ReturnType<typeof createFileWriter>> | undefined;\n let closed = false;\n let closePromise: Promise<void> | undefined;\n const consoleOwner = {};\n const consoleTargets = new Set<NodeJS.WriteStream>();\n const consoleWrites = new Set<Promise<void>>();\n const logger = createLoggerCore(\n options,\n {\n report,\n write(record) {\n if (closed) {\n report({\n message: 'Logger is closed.',\n type: 'closed',\n });\n\n return;\n }\n\n if (!record.console && !writer) return;\n const target = process[getLoggerStreamName(record.type)];\n\n const text = formatNodeLoggerRecord(record, record.console && supportsLoggerColor(target));\n if (record.console) {\n const line = `${text}\\n`;\n consoleTargets.add(target);\n const completion = writeConsole(target, line, report, consoleOwner);\n consoleWrites.add(completion);\n void completion.then(() => consoleWrites.delete(completion));\n const fileCompletion = writer?.write(`${stripVTControlCharacters(text)}\\n`);\n return fileCompletion\n ? Promise.all([\n completion,\n fileCompletion,\n ]).then(() => {})\n : completion;\n }\n\n return writer?.write(`${stripVTControlCharacters(text)}\\n`);\n },\n },\n );\n\n if (options.file !== undefined && options.file !== false) writer = await createFileWriter(options.file, report);\n\n return Object.freeze({\n ...logger,\n close() {\n if (closePromise) return closePromise;\n closed = true;\n closePromise = (async () => {\n await Promise.all([\n writer?.close(),\n ...consoleWrites,\n ]);\n\n for (const target of consoleTargets) {\n const state = consoleStreams.get(target);\n if (!state) continue;\n state.owners.delete(consoleOwner);\n if (!state.owners.size) {\n target.off('error', state.onError);\n target.off('close', state.onClose);\n consoleStreams.delete(target);\n }\n }\n\n consoleTargets.clear();\n })();\n\n return closePromise;\n },\n getStats: () => writer?.getStats() ?? Object.freeze({\n droppedCount: 0,\n pendingBytes: 0,\n writeErrorCount: 0,\n }),\n });\n}\n\n/**\n * One error listener per shared output stream; retained until its last owning logger calls close().\n */\
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/logger/node/index.ts"],"sourcesContent":["import { writeSync } from 'node:fs';\nimport { stripVTControlCharacters } from 'node:util';\n\nimport { supportsLoggerColor } from '../_internals/formatter';\nimport { getLoggerStreamName } from '../_internals/levels';\nimport {\n createDiagnosticReporter,\n createLoggerCore,\n} from '../_internals/logger';\nimport type { LoggerDiagnostic } from '../types';\n\nimport { createFileWriter } from './_internals/file-writer';\nimport { formatNodeLoggerRecord } from './_internals/formatter';\nimport type {\n NodeLogger,\n NodeLoggerOptions,\n} from './types';\n\ninterface ConsoleStreamState {\n onClose: () => void;\n onError: (error: Error) => void;\n owners: Set<object>;\n pending: Set<(error?: Error | null) => void>;\n}\n\n// Constants/Variables\nconst consoleStreams = new WeakMap<NodeJS.WriteStream, ConsoleStreamState>();\n\n// Functions\n\n/**\n * Creates a Node.js/Bun logger with optional bounded, append-only file output and rotation.\n *\n * Log calls never throw or reject. Awaiting them waits for processing, not proof of successful\n * persistence: overload drops the newest file record and failures are reported safely. Factory\n * validation/open failures reject. Call close explicitly; no process signal handlers are installed.\n */\nexport async function createNodeLogger(options: NodeLoggerOptions = {}): Promise<Readonly<NodeLogger>> {\n const report = createDiagnosticReporter(options.onError, (message) => writeSync(2, message));\n let writer: Awaited<ReturnType<typeof createFileWriter>> | undefined;\n let closed = false;\n let closePromise: Promise<void> | undefined;\n const consoleOwner = {};\n const consoleTargets = new Set<NodeJS.WriteStream>();\n const consoleWrites = new Set<Promise<void>>();\n const logger = createLoggerCore(\n options,\n {\n report,\n async write(record) {\n if (closed) {\n report({\n message: 'Logger is closed.',\n type: 'closed',\n });\n\n return;\n }\n\n if (!record.console && !writer) return;\n const target = process[getLoggerStreamName(record.type)];\n\n const text = formatNodeLoggerRecord(record, record.console && supportsLoggerColor(target));\n if (record.console) {\n const line = `${text}\\n`;\n consoleTargets.add(target);\n const completion = writeConsole(target, line, report, consoleOwner);\n consoleWrites.add(completion);\n void completion.then(() => consoleWrites.delete(completion));\n const fileCompletion = writer?.write(`${stripVTControlCharacters(text)}\\n`);\n return fileCompletion\n ? await Promise.all([\n completion,\n fileCompletion,\n ]).then(() => {})\n : await completion;\n }\n\n return await writer?.write(`${stripVTControlCharacters(text)}\\n`);\n },\n },\n );\n\n if (options.file !== undefined && options.file !== false) writer = await createFileWriter(options.file, report);\n\n return Object.freeze({\n ...logger,\n async close() {\n if (closePromise) return await closePromise;\n closed = true;\n closePromise = (async () => {\n await Promise.all([\n writer?.close(),\n ...consoleWrites,\n ]);\n\n for (const target of consoleTargets) {\n const state = consoleStreams.get(target);\n if (!state) continue;\n state.owners.delete(consoleOwner);\n if (!state.owners.size) {\n target.off('error', state.onError);\n target.off('close', state.onClose);\n consoleStreams.delete(target);\n }\n }\n\n consoleTargets.clear();\n })();\n\n return await closePromise;\n },\n getStats: () => writer?.getStats() ?? Object.freeze({\n droppedCount: 0,\n pendingBytes: 0,\n writeErrorCount: 0,\n }),\n });\n}\n\n/**\n * One error listener per shared output stream; retained until its last owning logger calls close().\n */\nasync function writeConsole(\n target: NodeJS.WriteStream,\n text: string,\n report: (event: LoggerDiagnostic) => void,\n owner: object,\n) {\n let state = consoleStreams.get(target);\n if (!state) {\n const pending = new Set<(error?: Error | null) => void>();\n const onError = (error: Error) => {\n for (const settle of pending) settle(error);\n };\n\n const onClose = () => onError(new Error('Console stream closed.'));\n state = {\n onClose,\n onError,\n owners: new Set(),\n pending,\n };\n\n consoleStreams.set(target, state);\n target.on('error', onError);\n target.on('close', onClose);\n }\n\n state.owners.add(owner);\n const current = state;\n return await new Promise<void>((resolveWritten) => {\n let settled = false;\n const settle = (error?: Error | null) => {\n if (settled) return;\n settled = true;\n current.pending.delete(settle);\n if (error) {\n report({\n error,\n message: 'Console output failed.',\n type: 'console',\n });\n }\n\n resolveWritten();\n };\n\n current.pending.add(settle);\n try {\n target.write(text, settle);\n } catch (error) {\n settle(error instanceof Error ? error : new Error('Console output failed.'));\n }\n });\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyed-store.d.ts","names":[],"sources":["../../../src/storages/redis/keyed-store.ts"],"mappings":";;;;;;;;;;;;;;;;;;wBAoBgB,sBAAsB,aAAa,SAAS,cAAc,qBAC9D,iBAAiB,WAAW,MAAM,iBAAY;
|
|
1
|
+
{"version":3,"file":"keyed-store.d.ts","names":[],"sources":["../../../src/storages/redis/keyed-store.ts"],"mappings":";;;;;;;;;;;;;;;;;;wBAoBgB,sBAAsB,aAAa,SAAS,cAAc,qBAC9D,iBAAiB,WAAW,MAAM,iBAAY;EAChB,sBAAA,MAAA,MAAC,QAAA;EACV,aAAA,MAAA,MAAC,QAAA;EACE,gBAAA,MAAA,MAAC;EACJ,aAAA,MAAA,MAAC;EACE,gBAAA,MAAA,MAAC;EACP,gBAAA,MAAA;EACC,UAAA,OAAA,MAAC,MAAW,MAAC;EACH,eAAA,oBAAM,OAAS,MAAC,MAAW,IAAC;EAGpB,uBAAA,oBAAM,OAAS,MAAC,MAAW,IAAC"}
|
|
@@ -17,18 +17,18 @@
|
|
|
17
17
|
*/
|
|
18
18
|
function createRedisKeyedStore(storage) {
|
|
19
19
|
return (keyFn) => Object.freeze({
|
|
20
|
-
getAndRemoveItem: (...args) => storage.getAndRemoveItem(keyFn(...args)),
|
|
21
|
-
getItem: (...args) => storage.getItem(keyFn(...args)),
|
|
22
|
-
getItemTtl: (...args) => storage.getItemTtl(keyFn(...args)),
|
|
23
|
-
hasItem: (...args) => storage.hasItem(keyFn(...args)),
|
|
24
|
-
removeItem: (...args) => storage.removeItem(keyFn(...args)),
|
|
20
|
+
getAndRemoveItem: async (...args) => await storage.getAndRemoveItem(keyFn(...args)),
|
|
21
|
+
getItem: async (...args) => await storage.getItem(keyFn(...args)),
|
|
22
|
+
getItemTtl: async (...args) => await storage.getItemTtl(keyFn(...args)),
|
|
23
|
+
hasItem: async (...args) => await storage.hasItem(keyFn(...args)),
|
|
24
|
+
removeItem: async (...args) => await storage.removeItem(keyFn(...args)),
|
|
25
25
|
resolveKey: (...args) => keyFn(...args),
|
|
26
|
-
setItem: (value, ...args) => storage.setItem(keyFn(...args), value),
|
|
27
|
-
setItemWithTtl(ttlSeconds, value, ...args) {
|
|
28
|
-
return storage.setItemWithTtl(keyFn(...args), ttlSeconds, value);
|
|
26
|
+
setItem: async (value, ...args) => await storage.setItem(keyFn(...args), value),
|
|
27
|
+
async setItemWithTtl(ttlSeconds, value, ...args) {
|
|
28
|
+
return await storage.setItemWithTtl(keyFn(...args), ttlSeconds, value);
|
|
29
29
|
},
|
|
30
|
-
setItemWithTtlIfAbsent(ttlSeconds, value, ...args) {
|
|
31
|
-
return storage.setItemWithTtlIfAbsent(keyFn(...args), ttlSeconds, value);
|
|
30
|
+
async setItemWithTtlIfAbsent(ttlSeconds, value, ...args) {
|
|
31
|
+
return await storage.setItemWithTtlIfAbsent(keyFn(...args), ttlSeconds, value);
|
|
32
32
|
}
|
|
33
33
|
});
|
|
34
34
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyed-store.js","names":[],"sources":["../../../src/storages/redis/keyed-store.ts"],"sourcesContent":["import type { MaybeReadonly } from '../../types';\n\nimport type { RedisLikeStorage } from './types';\n\n/**\n * Creates a keyed store factory sharing a caller-owned Redis-like storage facade.\n *\n * @remarks\n * The key resolver is called synchronously once per operation with the operation's key arguments.\n * Resolver exceptions propagate synchronously; asynchronous storage failures retain the underlying rejection.\n * `setItemWithTtl` and `setItemWithTtlIfAbsent` accept their TTL in seconds before the value and key arguments.\n * The factory does not open or close the underlying connection; cleanup remains the caller's responsibility.\n *\n * @typeParam D - The stored value type used by reads and writes.\n *\n * @param storage - The shared Redis-like storage instance.\n *\n * @returns A factory accepting a key resolver and returning a new frozen keyed facade sharing the storage.\n * Reads, atomic read-and-removals, writes, removals, and TTL results retain the underlying storage contract.\n */\nexport function createRedisKeyedStore<D = unknown>(storage: MaybeReadonly<RedisLikeStorage>) {\n return <P extends any[]>(keyFn: (...args: P) => string) => Object.freeze({\n getAndRemoveItem: (...args: P) => storage.getAndRemoveItem<D>(keyFn(...args)),\n getItem: (...args: P) => storage.getItem<D>(keyFn(...args)),\n getItemTtl: (...args: P) => storage.getItemTtl(keyFn(...args)),\n hasItem: (...args: P) => storage.hasItem(keyFn(...args)),\n removeItem: (...args: P) => storage.removeItem(keyFn(...args)),\n resolveKey: (...args: P) => keyFn(...args),\n setItem: (value: D, ...args: P) => storage.setItem(keyFn(...args), value),\n setItemWithTtl(ttlSeconds: number, value: D, ...args: P) {\n return storage.setItemWithTtl(keyFn(...args), ttlSeconds, value);\n },\n setItemWithTtlIfAbsent(ttlSeconds: number, value: D, ...args: P) {\n return storage.setItemWithTtlIfAbsent(keyFn(...args), ttlSeconds, value);\n },\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAoBA,SAAgB,sBAAmC,SAA0C;CACzF,QAAyB,UAAkC,OAAO,OAAO;EACrE,
|
|
1
|
+
{"version":3,"file":"keyed-store.js","names":[],"sources":["../../../src/storages/redis/keyed-store.ts"],"sourcesContent":["import type { MaybeReadonly } from '../../types';\n\nimport type { RedisLikeStorage } from './types';\n\n/**\n * Creates a keyed store factory sharing a caller-owned Redis-like storage facade.\n *\n * @remarks\n * The key resolver is called synchronously once per operation with the operation's key arguments.\n * Resolver exceptions propagate synchronously; asynchronous storage failures retain the underlying rejection.\n * `setItemWithTtl` and `setItemWithTtlIfAbsent` accept their TTL in seconds before the value and key arguments.\n * The factory does not open or close the underlying connection; cleanup remains the caller's responsibility.\n *\n * @typeParam D - The stored value type used by reads and writes.\n *\n * @param storage - The shared Redis-like storage instance.\n *\n * @returns A factory accepting a key resolver and returning a new frozen keyed facade sharing the storage.\n * Reads, atomic read-and-removals, writes, removals, and TTL results retain the underlying storage contract.\n */\nexport function createRedisKeyedStore<D = unknown>(storage: MaybeReadonly<RedisLikeStorage>) {\n return <P extends any[]>(keyFn: (...args: P) => string) => Object.freeze({\n getAndRemoveItem: async (...args: P) => await storage.getAndRemoveItem<D>(keyFn(...args)),\n getItem: async (...args: P) => await storage.getItem<D>(keyFn(...args)),\n getItemTtl: async (...args: P) => await storage.getItemTtl(keyFn(...args)),\n hasItem: async (...args: P) => await storage.hasItem(keyFn(...args)),\n removeItem: async (...args: P) => await storage.removeItem(keyFn(...args)),\n resolveKey: (...args: P) => keyFn(...args),\n setItem: async (value: D, ...args: P) => await storage.setItem(keyFn(...args), value),\n async setItemWithTtl(ttlSeconds: number, value: D, ...args: P) {\n return await storage.setItemWithTtl(keyFn(...args), ttlSeconds, value);\n },\n async setItemWithTtlIfAbsent(ttlSeconds: number, value: D, ...args: P) {\n return await storage.setItemWithTtlIfAbsent(keyFn(...args), ttlSeconds, value);\n },\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAoBA,SAAgB,sBAAmC,SAA0C;CACzF,QAAyB,UAAkC,OAAO,OAAO;EACrE,kBAAkB,OAAO,GAAG,SAAY,MAAM,QAAQ,iBAAoB,MAAM,GAAG,IAAI,CAAC;EACxF,SAAS,OAAO,GAAG,SAAY,MAAM,QAAQ,QAAW,MAAM,GAAG,IAAI,CAAC;EACtE,YAAY,OAAO,GAAG,SAAY,MAAM,QAAQ,WAAW,MAAM,GAAG,IAAI,CAAC;EACzE,SAAS,OAAO,GAAG,SAAY,MAAM,QAAQ,QAAQ,MAAM,GAAG,IAAI,CAAC;EACnE,YAAY,OAAO,GAAG,SAAY,MAAM,QAAQ,WAAW,MAAM,GAAG,IAAI,CAAC;EACzE,aAAa,GAAG,SAAY,MAAM,GAAG,IAAI;EACzC,SAAS,OAAO,OAAU,GAAG,SAAY,MAAM,QAAQ,QAAQ,MAAM,GAAG,IAAI,GAAG,KAAK;EACpF,MAAM,eAAe,YAAoB,OAAU,GAAG,MAAS;GAC3D,OAAO,MAAM,QAAQ,eAAe,MAAM,GAAG,IAAI,GAAG,YAAY,KAAK;EACzE;EACA,MAAM,uBAAuB,YAAoB,OAAU,GAAG,MAAS;GACnE,OAAO,MAAM,QAAQ,uBAAuB,MAAM,GAAG,IAAI,GAAG,YAAY,KAAK;EACjF;CACJ,CAAC;AACL"}
|
|
@@ -61,8 +61,8 @@ function createRedisMsgpackStorage(adapter) {
|
|
|
61
61
|
const rawValue = await adapter.getBuffer(key);
|
|
62
62
|
return rawValue ? decode(rawValue) : null;
|
|
63
63
|
},
|
|
64
|
-
getItemTtl: (key) => adapter.ttl(key),
|
|
65
|
-
hasItem: (key) => adapter.has(key),
|
|
64
|
+
getItemTtl: async (key) => await adapter.ttl(key),
|
|
65
|
+
hasItem: async (key) => await adapter.has(key),
|
|
66
66
|
removeItem: async (key) => await adapter.delete(key) === 1,
|
|
67
67
|
setItem: async (key, value) => await adapter.setBuffer(key, encode(value)) === "OK",
|
|
68
68
|
async setItemWithTtl(key, ttlSeconds, value) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"msgpack.js","names":[],"sources":["../../../src/storages/redis/msgpack.ts"],"sourcesContent":["import {\n decode,\n encode,\n isNativeAccelerationEnabled,\n} from 'msgpackr';\n\nimport type {\n RedisLikeAdapter,\n RedisLikeStorage,\n} from './types';\n\nif (!isNativeAccelerationEnabled) {\n console.warn('Native acceleration not enabled for msgpackr, verify that install finished properly');\n}\n\n/**\n * Creates a frozen Redis-like storage facade using MessagePack serialization.\n *\n * @remarks\n * Adapter rejections and MessagePack serialization errors propagate to the caller.\n * Reads resolve to `null` when no raw value exists; `getAndRemoveItem` reads and deletes in one atomic adapter call.\n * Writes resolve to `true` only when the adapter returns `OK`;\n * removal resolves to `true` only when exactly one key is deleted.\n * The adapter remains caller-owned; creating the facade does not open or close a connection.\n *\n * @param adapter - The caller-owned adapter for raw binary operations.\n *\n * @returns A new frozen facade sharing the supplied adapter.\n *\n * @example\n *\n * ```ts\n * import { createRedisMsgpackStorage } from '@kikiutils/shared/storages/redis/msgpack';\n * import type { RedisLikeAdapter } from '@kikiutils/shared/storages/redis/types';\n *\n * // This in-memory adapter demonstrates non-expiring operations without an external service.\n * const values = new Map<string, Uint8Array>();\n * const adapter: RedisLikeAdapter = {\n * delete: async (key) => values.delete(key) ? 1 : 0,\n * getBuffer: async (key) => values.get(key) ?? null,\n * getBufferAndDelete: async (key) => {\n * const value = values.get(key) ?? null;\n * values.delete(key);\n * return value;\n * },\n * has: async (key) => values.has(key),\n * setBuffer: async (key, value) => {\n * values.set(key, value);\n * return 'OK';\n * },\n * setBufferEx: async () => {\n * throw new Error('TTL writes are not supported by this example adapter');\n * },\n * setBufferExNx: async () => {\n * throw new Error('TTL writes are not supported by this example adapter');\n * },\n * ttl: async (key) => values.has(key) ? -1 : -2,\n * };\n *\n * const storage = createRedisMsgpackStorage(adapter);\n * await storage.setItem('profile', { name: 'Alice' });\n * const profile = await storage.getItem<{ name: string }>('profile');\n * console.log(profile); // => { name: 'Alice' }\n * ```\n */\nexport function createRedisMsgpackStorage(adapter: RedisLikeAdapter): Readonly<RedisLikeStorage> {\n return Object.freeze({\n async getAndRemoveItem<T = unknown>(key: string) {\n const rawValue = await adapter.getBufferAndDelete(key);\n return rawValue ? decode(rawValue) as T : null;\n },\n async getItem<T = unknown>(key: string) {\n const rawValue = await adapter.getBuffer(key);\n return rawValue ? decode(rawValue) as T : null;\n },\n getItemTtl: (key: string) => adapter.ttl(key),\n hasItem: (key: string) => adapter.has(key),\n removeItem: async (key: string) => await adapter.delete(key) === 1,\n setItem: async (key: string, value: any) => await adapter.setBuffer(key, encode(value)) === 'OK',\n async setItemWithTtl(key: string, ttlSeconds: number, value: any) {\n return await adapter.setBufferEx(key, ttlSeconds, encode(value)) === 'OK';\n },\n async setItemWithTtlIfAbsent(key: string, ttlSeconds: number, value: any) {\n return await adapter.setBufferExNx(key, ttlSeconds, encode(value)) === 'OK';\n },\n });\n}\n"],"mappings":";;AAWA,IAAI,CAAC,6BACD,QAAQ,KAAK,qFAAqF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqDtG,SAAgB,0BAA0B,SAAuD;CAC7F,OAAO,OAAO,OAAO;EACjB,MAAM,iBAA8B,KAAa;GAC7C,MAAM,WAAW,MAAM,QAAQ,mBAAmB,GAAG;GACrD,OAAO,WAAW,OAAO,QAAQ,IAAS;EAC9C;EACA,MAAM,QAAqB,KAAa;GACpC,MAAM,WAAW,MAAM,QAAQ,UAAU,GAAG;GAC5C,OAAO,WAAW,OAAO,QAAQ,IAAS;EAC9C;EACA,
|
|
1
|
+
{"version":3,"file":"msgpack.js","names":[],"sources":["../../../src/storages/redis/msgpack.ts"],"sourcesContent":["import {\n decode,\n encode,\n isNativeAccelerationEnabled,\n} from 'msgpackr';\n\nimport type {\n RedisLikeAdapter,\n RedisLikeStorage,\n} from './types';\n\nif (!isNativeAccelerationEnabled) {\n console.warn('Native acceleration not enabled for msgpackr, verify that install finished properly');\n}\n\n/**\n * Creates a frozen Redis-like storage facade using MessagePack serialization.\n *\n * @remarks\n * Adapter rejections and MessagePack serialization errors propagate to the caller.\n * Reads resolve to `null` when no raw value exists; `getAndRemoveItem` reads and deletes in one atomic adapter call.\n * Writes resolve to `true` only when the adapter returns `OK`;\n * removal resolves to `true` only when exactly one key is deleted.\n * The adapter remains caller-owned; creating the facade does not open or close a connection.\n *\n * @param adapter - The caller-owned adapter for raw binary operations.\n *\n * @returns A new frozen facade sharing the supplied adapter.\n *\n * @example\n *\n * ```ts\n * import { createRedisMsgpackStorage } from '@kikiutils/shared/storages/redis/msgpack';\n * import type { RedisLikeAdapter } from '@kikiutils/shared/storages/redis/types';\n *\n * // This in-memory adapter demonstrates non-expiring operations without an external service.\n * const values = new Map<string, Uint8Array>();\n * const adapter: RedisLikeAdapter = {\n * delete: async (key) => values.delete(key) ? 1 : 0,\n * getBuffer: async (key) => values.get(key) ?? null,\n * getBufferAndDelete: async (key) => {\n * const value = values.get(key) ?? null;\n * values.delete(key);\n * return value;\n * },\n * has: async (key) => values.has(key),\n * setBuffer: async (key, value) => {\n * values.set(key, value);\n * return 'OK';\n * },\n * setBufferEx: async () => {\n * throw new Error('TTL writes are not supported by this example adapter');\n * },\n * setBufferExNx: async () => {\n * throw new Error('TTL writes are not supported by this example adapter');\n * },\n * ttl: async (key) => values.has(key) ? -1 : -2,\n * };\n *\n * const storage = createRedisMsgpackStorage(adapter);\n * await storage.setItem('profile', { name: 'Alice' });\n * const profile = await storage.getItem<{ name: string }>('profile');\n * console.log(profile); // => { name: 'Alice' }\n * ```\n */\nexport function createRedisMsgpackStorage(adapter: RedisLikeAdapter): Readonly<RedisLikeStorage> {\n return Object.freeze({\n async getAndRemoveItem<T = unknown>(key: string) {\n const rawValue = await adapter.getBufferAndDelete(key);\n return rawValue ? decode(rawValue) as T : null;\n },\n async getItem<T = unknown>(key: string) {\n const rawValue = await adapter.getBuffer(key);\n return rawValue ? decode(rawValue) as T : null;\n },\n getItemTtl: async (key: string) => await adapter.ttl(key),\n hasItem: async (key: string) => await adapter.has(key),\n removeItem: async (key: string) => await adapter.delete(key) === 1,\n setItem: async (key: string, value: any) => await adapter.setBuffer(key, encode(value)) === 'OK',\n async setItemWithTtl(key: string, ttlSeconds: number, value: any) {\n return await adapter.setBufferEx(key, ttlSeconds, encode(value)) === 'OK';\n },\n async setItemWithTtlIfAbsent(key: string, ttlSeconds: number, value: any) {\n return await adapter.setBufferExNx(key, ttlSeconds, encode(value)) === 'OK';\n },\n });\n}\n"],"mappings":";;AAWA,IAAI,CAAC,6BACD,QAAQ,KAAK,qFAAqF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqDtG,SAAgB,0BAA0B,SAAuD;CAC7F,OAAO,OAAO,OAAO;EACjB,MAAM,iBAA8B,KAAa;GAC7C,MAAM,WAAW,MAAM,QAAQ,mBAAmB,GAAG;GACrD,OAAO,WAAW,OAAO,QAAQ,IAAS;EAC9C;EACA,MAAM,QAAqB,KAAa;GACpC,MAAM,WAAW,MAAM,QAAQ,UAAU,GAAG;GAC5C,OAAO,WAAW,OAAO,QAAQ,IAAS;EAC9C;EACA,YAAY,OAAO,QAAgB,MAAM,QAAQ,IAAI,GAAG;EACxD,SAAS,OAAO,QAAgB,MAAM,QAAQ,IAAI,GAAG;EACrD,YAAY,OAAO,QAAgB,MAAM,QAAQ,OAAO,GAAG,MAAM;EACjE,SAAS,OAAO,KAAa,UAAe,MAAM,QAAQ,UAAU,KAAK,OAAO,KAAK,CAAC,MAAM;EAC5F,MAAM,eAAe,KAAa,YAAoB,OAAY;GAC9D,OAAO,MAAM,QAAQ,YAAY,KAAK,YAAY,OAAO,KAAK,CAAC,MAAM;EACzE;EACA,MAAM,uBAAuB,KAAa,YAAoB,OAAY;GACtE,OAAO,MAAM,QAAQ,cAAc,KAAK,YAAY,OAAO,KAAK,CAAC,MAAM;EAC3E;CACJ,CAAC;AACL"}
|
package/dist/time.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time.d.ts","names":[],"sources":["../src/time.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"time.d.ts","names":[],"sources":["../src/time.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;wBAoBsB,MAAM,YAAY,SAAS,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;wBA2CzC,aAAa,YAAY,SAAS,cAAc"}
|
package/dist/time.js
CHANGED
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
* await delay(5000, controller.signal);
|
|
20
20
|
* ```
|
|
21
21
|
*/
|
|
22
|
-
function delay(ms, signal) {
|
|
23
|
-
return new Promise((resolve) => {
|
|
22
|
+
async function delay(ms, signal) {
|
|
23
|
+
return await new Promise((resolve) => {
|
|
24
24
|
if (signal?.aborted) {
|
|
25
25
|
resolve();
|
|
26
26
|
return;
|
|
@@ -58,8 +58,8 @@ function delay(ms, signal) {
|
|
|
58
58
|
* }
|
|
59
59
|
* ```
|
|
60
60
|
*/
|
|
61
|
-
function delayOrThrow(ms, signal) {
|
|
62
|
-
return new Promise((resolve, reject) => {
|
|
61
|
+
async function delayOrThrow(ms, signal) {
|
|
62
|
+
return await new Promise((resolve, reject) => {
|
|
63
63
|
if (signal?.aborted) {
|
|
64
64
|
reject(signal.reason);
|
|
65
65
|
return;
|
package/dist/time.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time.js","names":[],"sources":["../src/time.ts"],"sourcesContent":["/**\n * Waits until a duration elapses or cancellation occurs without rejecting on cancellation.\n *\n * @remarks\n * The promise resolves without a value when the timer completes or the signal aborts.\n * An already aborted signal resolves immediately; completion removes the abort listener and clears the timer.\n *\n * @param ms - The delay duration in milliseconds, using native `setTimeout` timing rules.\n * @param signal - The signal that ends the wait early.\n *\n * @example\n *\n * ```ts\n * import { delay } from '@kikiutils/shared/time';\n *\n * const controller = new AbortController();\n * controller.abort();\n * await delay(5000, controller.signal);\n * ```\n */\nexport function delay(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n if (signal?.aborted) {\n resolve();\n return;\n }\n\n const done = () => {\n // eslint-disable-next-line ts/no-use-before-define\n clearTimeout(timeout);\n signal?.removeEventListener('abort', done);\n resolve();\n };\n\n const timeout = setTimeout(done, ms);\n signal?.addEventListener('abort', done, { once: true });\n });\n}\n\n/**\n * Waits until a duration elapses and rejects on cancellation.\n *\n * @remarks\n * The promise resolves without a value when the timer completes and rejects with `signal.reason` if aborted.\n * An already aborted signal rejects immediately. Aborting clears the timer; timer completion removes the listener.\n *\n * @param ms - The delay duration in milliseconds, using native `setTimeout` timing rules.\n * @param signal - The signal that cancels the wait.\n *\n * @example\n *\n * ```ts\n * import { delayOrThrow } from '@kikiutils/shared/time';\n *\n * const controller = new AbortController();\n * controller.abort(new Error('Canceled'));\n * try {\n * await delayOrThrow(5000, controller.signal);\n * } catch (error) {\n * console.error(error);\n * }\n * ```\n */\nexport function delayOrThrow(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason);\n return;\n }\n\n const onAbort = () => {\n // eslint-disable-next-line ts/no-use-before-define\n clearTimeout(timeout);\n reject(signal!.reason);\n };\n\n const timeout = setTimeout(\n () => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n },\n ms,\n );\n\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAoBA,
|
|
1
|
+
{"version":3,"file":"time.js","names":[],"sources":["../src/time.ts"],"sourcesContent":["/**\n * Waits until a duration elapses or cancellation occurs without rejecting on cancellation.\n *\n * @remarks\n * The promise resolves without a value when the timer completes or the signal aborts.\n * An already aborted signal resolves immediately; completion removes the abort listener and clears the timer.\n *\n * @param ms - The delay duration in milliseconds, using native `setTimeout` timing rules.\n * @param signal - The signal that ends the wait early.\n *\n * @example\n *\n * ```ts\n * import { delay } from '@kikiutils/shared/time';\n *\n * const controller = new AbortController();\n * controller.abort();\n * await delay(5000, controller.signal);\n * ```\n */\nexport async function delay(ms: number, signal?: AbortSignal): Promise<void> {\n return await new Promise((resolve) => {\n if (signal?.aborted) {\n resolve();\n return;\n }\n\n const done = () => {\n // eslint-disable-next-line ts/no-use-before-define\n clearTimeout(timeout);\n signal?.removeEventListener('abort', done);\n resolve();\n };\n\n const timeout = setTimeout(done, ms);\n signal?.addEventListener('abort', done, { once: true });\n });\n}\n\n/**\n * Waits until a duration elapses and rejects on cancellation.\n *\n * @remarks\n * The promise resolves without a value when the timer completes and rejects with `signal.reason` if aborted.\n * An already aborted signal rejects immediately. Aborting clears the timer; timer completion removes the listener.\n *\n * @param ms - The delay duration in milliseconds, using native `setTimeout` timing rules.\n * @param signal - The signal that cancels the wait.\n *\n * @example\n *\n * ```ts\n * import { delayOrThrow } from '@kikiutils/shared/time';\n *\n * const controller = new AbortController();\n * controller.abort(new Error('Canceled'));\n * try {\n * await delayOrThrow(5000, controller.signal);\n * } catch (error) {\n * console.error(error);\n * }\n * ```\n */\nexport async function delayOrThrow(ms: number, signal?: AbortSignal): Promise<void> {\n return await new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason);\n return;\n }\n\n const onAbort = () => {\n // eslint-disable-next-line ts/no-use-before-define\n clearTimeout(timeout);\n reject(signal!.reason);\n };\n\n const timeout = setTimeout(\n () => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n },\n ms,\n );\n\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAoBA,eAAsB,MAAM,IAAY,QAAqC;CACzE,OAAO,MAAM,IAAI,SAAS,YAAY;EAClC,IAAI,QAAQ,SAAS;GACjB,QAAQ;GACR;EACJ;EAEA,MAAM,aAAa;GAEf,aAAa,OAAO;GACpB,QAAQ,oBAAoB,SAAS,IAAI;GACzC,QAAQ;EACZ;EAEA,MAAM,UAAU,WAAW,MAAM,EAAE;EACnC,QAAQ,iBAAiB,SAAS,MAAM,EAAE,MAAM,KAAK,CAAC;CAC1D,CAAC;AACL;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,eAAsB,aAAa,IAAY,QAAqC;CAChF,OAAO,MAAM,IAAI,SAAS,SAAS,WAAW;EAC1C,IAAI,QAAQ,SAAS;GACjB,OAAO,OAAO,MAAM;GACpB;EACJ;EAEA,MAAM,gBAAgB;GAElB,aAAa,OAAO;GACpB,OAAO,OAAQ,MAAM;EACzB;EAEA,MAAM,UAAU,iBACN;GACF,QAAQ,oBAAoB,SAAS,OAAO;GAC5C,QAAQ;EACZ,GACA,EACJ;EAEA,QAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;CAC7D,CAAC;AACL"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kikiutils/shared",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "20.1.
|
|
4
|
+
"version": "20.1.1",
|
|
5
5
|
"description": "A lightweight and modular utility library for modern JavaScript and TypeScript — includes secure hashing, flexible logging, datetime tools, Vue/web helpers, storage abstraction, and more.",
|
|
6
6
|
"author": "kiki-kanri",
|
|
7
7
|
"license": "MIT",
|
|
@@ -143,35 +143,39 @@
|
|
|
143
143
|
"optional": true
|
|
144
144
|
}
|
|
145
145
|
},
|
|
146
|
+
"dependencies": {
|
|
147
|
+
"ts-extras": "^2.0.0",
|
|
148
|
+
"type-fest": "^5.10.0"
|
|
149
|
+
},
|
|
146
150
|
"devDependencies": {
|
|
147
151
|
"@antfu/eslint-config": "^10.0.0",
|
|
148
152
|
"@arethetypeswrong/core": "^0.18.5",
|
|
149
|
-
"@kikiutils/eslint-config": "^
|
|
153
|
+
"@kikiutils/eslint-config": "^11.0.0",
|
|
150
154
|
"@kikiutils/tsconfigs": "^7.0.0",
|
|
151
155
|
"@noble/hashes": "^2.4.0",
|
|
152
156
|
"@types/node": "^26.6.6",
|
|
153
|
-
"@vitest/coverage-v8": "^5.0
|
|
157
|
+
"@vitest/coverage-v8": "^5.1.0",
|
|
154
158
|
"async-validator": "^4.2.5",
|
|
155
|
-
"bson": "^7.3.
|
|
159
|
+
"bson": "^7.3.4",
|
|
156
160
|
"changelogen": "^0.6.2",
|
|
157
161
|
"cross-env": "^10.1.0",
|
|
158
162
|
"date-fns": "^4.4.0",
|
|
159
163
|
"decimal.js": "^10.6.0",
|
|
160
|
-
"element-plus": "^2.14.
|
|
164
|
+
"element-plus": "^2.14.8",
|
|
161
165
|
"eslint": "^10.14.0",
|
|
162
166
|
"file-type": "^22.3.0",
|
|
163
|
-
"jsdom": "^
|
|
164
|
-
"knip": "^6.44.
|
|
167
|
+
"jsdom": "^31.0.0",
|
|
168
|
+
"knip": "^6.44.2",
|
|
165
169
|
"lru-cache": "^11.5.3",
|
|
166
170
|
"millify": "^6.1.0",
|
|
167
|
-
"msgpackr": "^2.1.
|
|
171
|
+
"msgpackr": "^2.1.4",
|
|
168
172
|
"publint": "^0.3.25",
|
|
169
173
|
"rotating-file-stream": "^3.2.10",
|
|
170
|
-
"tsdown": "^0.23.
|
|
174
|
+
"tsdown": "^0.23.7",
|
|
171
175
|
"typescript": "^6.0.3",
|
|
172
176
|
"unplugin-unused": "^0.6.0",
|
|
173
|
-
"vitest": "^5.0
|
|
174
|
-
"vue": "^3.5.
|
|
177
|
+
"vitest": "^5.1.0",
|
|
178
|
+
"vue": "^3.5.45",
|
|
175
179
|
"vue-router": "^5.4.0"
|
|
176
180
|
}
|
|
177
181
|
}
|
package/src/classes/path.ts
CHANGED
|
@@ -241,8 +241,8 @@ export class Path {
|
|
|
241
241
|
*
|
|
242
242
|
* @see {@link https://nodejs.org/api/fs.html | Node.js fsPromises.access}
|
|
243
243
|
*/
|
|
244
|
-
access(...args: DropFirstParameters<typeof fsp.access>) {
|
|
245
|
-
return fsp.access(this.#value, ...args);
|
|
244
|
+
async access(...args: DropFirstParameters<typeof fsp.access>) {
|
|
245
|
+
return await fsp.access(this.#value, ...args);
|
|
246
246
|
}
|
|
247
247
|
|
|
248
248
|
/**
|
|
@@ -253,8 +253,8 @@ export class Path {
|
|
|
253
253
|
*
|
|
254
254
|
* @see {@link https://nodejs.org/api/fs.html | Node.js fsPromises.appendFile}
|
|
255
255
|
*/
|
|
256
|
-
appendFile(...args: DropFirstParameters<typeof fsp.appendFile>) {
|
|
257
|
-
return fsp.appendFile(this.#value, ...args);
|
|
256
|
+
async appendFile(...args: DropFirstParameters<typeof fsp.appendFile>) {
|
|
257
|
+
return await fsp.appendFile(this.#value, ...args);
|
|
258
258
|
}
|
|
259
259
|
|
|
260
260
|
/**
|
|
@@ -265,8 +265,8 @@ export class Path {
|
|
|
265
265
|
*
|
|
266
266
|
* @see {@link https://nodejs.org/api/fs.html | Node.js fsPromises.chmod}
|
|
267
267
|
*/
|
|
268
|
-
chmod(...args: DropFirstParameters<typeof fsp.chmod>) {
|
|
269
|
-
return fsp.chmod(this.#value, ...args);
|
|
268
|
+
async chmod(...args: DropFirstParameters<typeof fsp.chmod>) {
|
|
269
|
+
return await fsp.chmod(this.#value, ...args);
|
|
270
270
|
}
|
|
271
271
|
|
|
272
272
|
/**
|
|
@@ -277,8 +277,8 @@ export class Path {
|
|
|
277
277
|
*
|
|
278
278
|
* @see {@link https://nodejs.org/api/fs.html | Node.js fsPromises.chown}
|
|
279
279
|
*/
|
|
280
|
-
chown(...args: DropFirstParameters<typeof fsp.chown>) {
|
|
281
|
-
return fsp.chown(this.#value, ...args);
|
|
280
|
+
async chown(...args: DropFirstParameters<typeof fsp.chown>) {
|
|
281
|
+
return await fsp.chown(this.#value, ...args);
|
|
282
282
|
}
|
|
283
283
|
|
|
284
284
|
/**
|
|
@@ -289,8 +289,8 @@ export class Path {
|
|
|
289
289
|
*
|
|
290
290
|
* @see {@link https://nodejs.org/api/fs.html | Node.js fsPromises.copyFile}
|
|
291
291
|
*/
|
|
292
|
-
copyFile(...args: DropFirstParameters<typeof fsp.copyFile>) {
|
|
293
|
-
return fsp.copyFile(this.#value, ...args);
|
|
292
|
+
async copyFile(...args: DropFirstParameters<typeof fsp.copyFile>) {
|
|
293
|
+
return await fsp.copyFile(this.#value, ...args);
|
|
294
294
|
}
|
|
295
295
|
|
|
296
296
|
/**
|
|
@@ -310,8 +310,8 @@ export class Path {
|
|
|
310
310
|
| null,
|
|
311
311
|
): Promise<void>;
|
|
312
312
|
mkdir(options?: fs.MakeDirectoryOptions | fs.Mode | null): Promise<string | undefined>;
|
|
313
|
-
mkdir(...args: any): any {
|
|
314
|
-
return fsp.mkdir(this.#value, ...args);
|
|
313
|
+
async mkdir(...args: any): Promise<any> {
|
|
314
|
+
return await fsp.mkdir(this.#value, ...args);
|
|
315
315
|
}
|
|
316
316
|
|
|
317
317
|
/**
|
|
@@ -322,8 +322,8 @@ export class Path {
|
|
|
322
322
|
*
|
|
323
323
|
* @see {@link https://nodejs.org/api/fs.html | Node.js fsPromises.open}
|
|
324
324
|
*/
|
|
325
|
-
open(...args: DropFirstParameters<typeof fsp.open>) {
|
|
326
|
-
return fsp.open(this.#value, ...args);
|
|
325
|
+
async open(...args: DropFirstParameters<typeof fsp.open>) {
|
|
326
|
+
return await fsp.open(this.#value, ...args);
|
|
327
327
|
}
|
|
328
328
|
|
|
329
329
|
/**
|
|
@@ -374,8 +374,8 @@ export class Path {
|
|
|
374
374
|
withFileTypes: true;
|
|
375
375
|
},
|
|
376
376
|
): Promise<Array<fs.Dirent<Buffer>>>;
|
|
377
|
-
readdir(...args: any): any {
|
|
378
|
-
return fsp.readdir(this.#value, ...args);
|
|
377
|
+
async readdir(...args: any): Promise<any> {
|
|
378
|
+
return await fsp.readdir(this.#value, ...args);
|
|
379
379
|
}
|
|
380
380
|
|
|
381
381
|
/**
|
|
@@ -412,8 +412,8 @@ export class Path {
|
|
|
412
412
|
| BufferEncoding
|
|
413
413
|
| null,
|
|
414
414
|
): Promise<Buffer | string>;
|
|
415
|
-
readFile(...args: any): any {
|
|
416
|
-
return fsp.readFile(this.#value, ...args);
|
|
415
|
+
async readFile(...args: any): Promise<any> {
|
|
416
|
+
return await fsp.readFile(this.#value, ...args);
|
|
417
417
|
}
|
|
418
418
|
|
|
419
419
|
/**
|
|
@@ -426,8 +426,8 @@ export class Path {
|
|
|
426
426
|
*
|
|
427
427
|
* @see {@link https://nodejs.org/api/fs.html | Node.js fsPromises.rename}
|
|
428
428
|
*/
|
|
429
|
-
rename(newPath: PathLike) {
|
|
430
|
-
return fsp.rename(this.#value, newPath.toString());
|
|
429
|
+
async rename(newPath: PathLike) {
|
|
430
|
+
return await fsp.rename(this.#value, newPath.toString());
|
|
431
431
|
}
|
|
432
432
|
|
|
433
433
|
/**
|
|
@@ -438,8 +438,8 @@ export class Path {
|
|
|
438
438
|
*
|
|
439
439
|
* @see {@link https://nodejs.org/api/fs.html | Node.js fsPromises.rm}
|
|
440
440
|
*/
|
|
441
|
-
rm(...args: DropFirstParameters<typeof fsp.rm>) {
|
|
442
|
-
return fsp.rm(this.#value, ...args);
|
|
441
|
+
async rm(...args: DropFirstParameters<typeof fsp.rm>) {
|
|
442
|
+
return await fsp.rm(this.#value, ...args);
|
|
443
443
|
}
|
|
444
444
|
|
|
445
445
|
/**
|
|
@@ -450,8 +450,8 @@ export class Path {
|
|
|
450
450
|
*
|
|
451
451
|
* @see {@link https://nodejs.org/api/fs.html | Node.js fsPromises.rmdir}
|
|
452
452
|
*/
|
|
453
|
-
rmdir(...args: DropFirstParameters<typeof fsp.rmdir>) {
|
|
454
|
-
return fsp.rmdir(this.#value, ...args);
|
|
453
|
+
async rmdir(...args: DropFirstParameters<typeof fsp.rmdir>) {
|
|
454
|
+
return await fsp.rmdir(this.#value, ...args);
|
|
455
455
|
}
|
|
456
456
|
|
|
457
457
|
/**
|
|
@@ -512,8 +512,8 @@ export class Path {
|
|
|
512
512
|
*
|
|
513
513
|
* @see {@link https://nodejs.org/api/fs.html | Node.js fsPromises.truncate}
|
|
514
514
|
*/
|
|
515
|
-
truncate(...args: DropFirstParameters<typeof fsp.truncate>) {
|
|
516
|
-
return fsp.truncate(this.#value, ...args);
|
|
515
|
+
async truncate(...args: DropFirstParameters<typeof fsp.truncate>) {
|
|
516
|
+
return await fsp.truncate(this.#value, ...args);
|
|
517
517
|
}
|
|
518
518
|
|
|
519
519
|
/**
|
|
@@ -524,8 +524,8 @@ export class Path {
|
|
|
524
524
|
*
|
|
525
525
|
* @see {@link https://nodejs.org/api/fs.html | Node.js fsPromises.unlink}
|
|
526
526
|
*/
|
|
527
|
-
unlink() {
|
|
528
|
-
return fsp.unlink(this.#value);
|
|
527
|
+
async unlink() {
|
|
528
|
+
return await fsp.unlink(this.#value);
|
|
529
529
|
}
|
|
530
530
|
|
|
531
531
|
/**
|
|
@@ -536,7 +536,7 @@ export class Path {
|
|
|
536
536
|
*
|
|
537
537
|
* @see {@link https://nodejs.org/api/fs.html | Node.js fsPromises.writeFile}
|
|
538
538
|
*/
|
|
539
|
-
writeFile(...args: DropFirstParameters<typeof fsp.writeFile>) {
|
|
540
|
-
return fsp.writeFile(this.#value, ...args);
|
|
539
|
+
async writeFile(...args: DropFirstParameters<typeof fsp.writeFile>) {
|
|
540
|
+
return await fsp.writeFile(this.#value, ...args);
|
|
541
541
|
}
|
|
542
542
|
}
|
package/src/enum.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
objectKeys,
|
|
3
|
+
objectValues,
|
|
4
|
+
} from 'ts-extras';
|
|
5
|
+
import type { ValueOf } from 'type-fest';
|
|
6
|
+
|
|
1
7
|
/**
|
|
2
8
|
* Extracts only the numeric values from an enumeration-like object.
|
|
3
9
|
*
|
|
@@ -22,7 +28,7 @@
|
|
|
22
28
|
* console.log(getEnumNumberValues(RecordType)); // => [0, 1]
|
|
23
29
|
* ```
|
|
24
30
|
*/
|
|
25
|
-
export function getEnumNumberValues<T extends Record<string, any>>(enumObject: T): Array<Extract<T
|
|
31
|
+
export function getEnumNumberValues<T extends Record<string, any>>(enumObject: T): Array<Extract<ValueOf<T>, number>> {
|
|
26
32
|
return getEnumValues(enumObject).filter((value) => typeof value === 'number');
|
|
27
33
|
}
|
|
28
34
|
|
|
@@ -50,7 +56,7 @@ export function getEnumNumberValues<T extends Record<string, any>>(enumObject: T
|
|
|
50
56
|
* console.log(getEnumStringValues(RecordType)); // => ['unknown']
|
|
51
57
|
* ```
|
|
52
58
|
*/
|
|
53
|
-
export function getEnumStringValues<T extends Record<string, any>>(enumObject: T): Array<Extract<T
|
|
59
|
+
export function getEnumStringValues<T extends Record<string, any>>(enumObject: T): Array<Extract<ValueOf<T>, string>> {
|
|
54
60
|
return getEnumValues(enumObject).filter((value) => typeof value === 'string');
|
|
55
61
|
}
|
|
56
62
|
|
|
@@ -102,9 +108,9 @@ export function getEnumStringValues<T extends Record<string, any>>(enumObject: T
|
|
|
102
108
|
* console.log(getEnumValues(RecordType)); // => [0, 1, 'unknown']
|
|
103
109
|
* ```
|
|
104
110
|
*/
|
|
105
|
-
export function getEnumValues<T extends Record<string, any>>(enumObject: T): Array<T
|
|
106
|
-
const values =
|
|
111
|
+
export function getEnumValues<T extends Record<string, any>>(enumObject: T): Array<ValueOf<T>> {
|
|
112
|
+
const values = objectValues(enumObject);
|
|
107
113
|
const hasNumberValues = values.some((value) => typeof value === 'number');
|
|
108
114
|
if (!hasNumberValues) return values;
|
|
109
|
-
return
|
|
115
|
+
return objectKeys(enumObject).filter((key) => Number.isNaN(Number(key))).map((key) => enumObject[key]);
|
|
110
116
|
}
|
package/src/event-awaiter.ts
CHANGED
|
@@ -58,8 +58,8 @@ export class EventAwaiter<T> {
|
|
|
58
58
|
*
|
|
59
59
|
* @throws Error through promise rejection if `strict` mode encounters an existing waiter.
|
|
60
60
|
*/
|
|
61
|
-
wait(key: string, timeoutMs?: number, mode?: 'override' | 'strict', signal?: AbortSignal) {
|
|
62
|
-
return new Promise<T | undefined>((resolve) => {
|
|
61
|
+
async wait(key: string, timeoutMs?: number, mode?: 'override' | 'strict', signal?: AbortSignal) {
|
|
62
|
+
return await new Promise<T | undefined>((resolve) => {
|
|
63
63
|
const resolvers = this.#promiseResolvers.get(key) || [];
|
|
64
64
|
if (resolvers.length) {
|
|
65
65
|
switch (mode) {
|
|
@@ -122,8 +122,8 @@ export class EventAwaiter<T> {
|
|
|
122
122
|
*
|
|
123
123
|
* @see {@link EventAwaiter.wait}
|
|
124
124
|
*/
|
|
125
|
-
waitExclusive(key: string, timeoutMs?: number, signal?: AbortSignal) {
|
|
126
|
-
return this.wait(key, timeoutMs, 'strict', signal);
|
|
125
|
+
async waitExclusive(key: string, timeoutMs?: number, signal?: AbortSignal) {
|
|
126
|
+
return await this.wait(key, timeoutMs, 'strict', signal);
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
/**
|
|
@@ -140,7 +140,7 @@ export class EventAwaiter<T> {
|
|
|
140
140
|
*
|
|
141
141
|
* @see {@link EventAwaiter.wait}
|
|
142
142
|
*/
|
|
143
|
-
waitLatest(key: string, timeoutMs?: number, signal?: AbortSignal) {
|
|
144
|
-
return this.wait(key, timeoutMs, 'override', signal);
|
|
143
|
+
async waitLatest(key: string, timeoutMs?: number, signal?: AbortSignal) {
|
|
144
|
+
return await this.wait(key, timeoutMs, 'override', signal);
|
|
145
145
|
}
|
|
146
146
|
}
|
package/src/general.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { Arrayable } from 'type-fest';
|
|
2
|
+
|
|
1
3
|
/* eslint-disable jsdoc/check-param-names */
|
|
2
4
|
|
|
3
5
|
/**
|
|
@@ -31,9 +33,9 @@
|
|
|
31
33
|
* console.log(extractFirstValue(undefined, 'fallback')); // => 'fallback'
|
|
32
34
|
* ```
|
|
33
35
|
*/
|
|
34
|
-
export function extractFirstValue<T>(value: T
|
|
35
|
-
export function extractFirstValue<T, D>(value: T
|
|
36
|
-
export function extractFirstValue<T, D>(value: T
|
|
36
|
+
export function extractFirstValue<T>(value: Arrayable<T>): T | undefined;
|
|
37
|
+
export function extractFirstValue<T, D>(value: Arrayable<T>, defaultValue: D): D | NonNullable<T>;
|
|
38
|
+
export function extractFirstValue<T, D>(value: Arrayable<T>, defaultValue?: D) {
|
|
37
39
|
return (Array.isArray(value) ? value[0] : value) ?? defaultValue;
|
|
38
40
|
}
|
|
39
41
|
|