From c6e3eae22e6823098ea19a49efec397ae76b1126 Mon Sep 17 00:00:00 2001 From: Eli-Class Date: Thu, 29 Jan 2026 09:24:48 +0000 Subject: [PATCH] Interface modified mmap to fd --- CUSTOM_SERIALIZER.md | 4 +- README.md | 4 +- lib/dat/reader.ts | 336 ++++++------- lib/dat/types.ts | 19 +- lib/dat/writer.ts | 240 +++++---- lib/idx/protocol.ts | 168 ++++--- lib/idx/reader.ts | 219 ++++---- lib/idx/types.ts | 39 +- lib/idx/writer.ts | 290 +++++++---- package-lock.json | 1138 ------------------------------------------ package.json | 3 +- 11 files changed, 727 insertions(+), 1733 deletions(-) diff --git a/CUSTOM_SERIALIZER.md b/CUSTOM_SERIALIZER.md index 2da2b0b..5d54f8d 100644 --- a/CUSTOM_SERIALIZER.md +++ b/CUSTOM_SERIALIZER.md @@ -1,3 +1,5 @@ +가변 길이 배열이 포함된 데이터의 커스텀 바이너리 직렬화 방법을 보여드릴게요. + ```typescript // 가변 배열 직렬화 예시 import { createSerializer, DataWriter, DataReader } from './src/data-file/index.js'; @@ -391,4 +393,4 @@ const orderSerializer = createSerializer( return { orderId, items, total }; } ); -``` +``` \ No newline at end of file diff --git a/README.md b/README.md index 1666211..a260fad 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ```typescript // example.ts -import { DataWriter, DataReader, jsonSerializer, createSerializer } from '@elilee/index-file'; +import { DataWriter, DataReader, jsonSerializer, createSerializer } from './index.js'; // ============================================ // 1. JSON 직렬화 (간단한 경우) @@ -178,4 +178,4 @@ msgpackSerializer() // 커스텀 바이너리 createSerializer(serialize, deserialize) -``` +``` \ No newline at end of file diff --git a/lib/dat/reader.ts b/lib/dat/reader.ts index a071846..9440bd2 100644 --- a/lib/dat/reader.ts +++ b/lib/dat/reader.ts @@ -1,213 +1,215 @@ // src/data-file/reader.ts import * as fs from 'node:fs'; -import mmap from '@elilee/mmap-native'; import { DATA_HEADER_SIZE } from './constants.js'; import { DataProtocol, DataHeader } from './protocol.js'; import { IndexReader } from '../idx/index.js'; import type { Serializer, DataEntry } from './types.js'; export class DataReader { - private fd: number | null = null; - private buffer: Buffer | null = null; - private header: DataHeader | null = null; + private fd: number | null = null; + private header: DataHeader | null = null; - private indexReader: IndexReader; - private serializer: Serializer; + private indexReader: IndexReader; + private serializer: Serializer; - readonly dataPath: string; - readonly indexPath: string; + readonly dataPath: string; + readonly indexPath: string; - constructor(basePath: string, serializer: Serializer) { - this.dataPath = `${basePath}.dat`; - this.indexPath = `${basePath}.idx`; - this.serializer = serializer; - this.indexReader = new IndexReader(this.indexPath); - } + constructor(basePath: string, serializer: Serializer) { + this.dataPath = `${basePath}.dat`; + this.indexPath = `${basePath}.idx`; + this.serializer = serializer; + this.indexReader = new IndexReader(this.indexPath); + } - open(): void { - const stats = fs.statSync(this.dataPath); - this.fd = fs.openSync(this.dataPath, 'r'); + open(): void { + this.fd = fs.openSync(this.dataPath, 'r'); - this.buffer = mmap.map( - stats.size, - mmap.PROT_READ, - mmap.MAP_SHARED, - this.fd, - 0 - ); + // Read header only + const headerBuf = Buffer.alloc(DATA_HEADER_SIZE); + fs.readSync(this.fd, headerBuf, 0, DATA_HEADER_SIZE, 0); + this.header = DataProtocol.readHeader(headerBuf); - this.header = DataProtocol.readHeader(this.buffer); - this.indexReader.open(); - } + this.indexReader.open(); + } - getHeader(): DataHeader { - if (!this.header) throw new Error('Data file not opened'); - return this.header; - } + private readRecord(offset: bigint, length: number): Buffer { + if (this.fd === null) throw new Error('Data file not opened'); - getBySequence(sequence: number): DataEntry | null { - if (!this.buffer) throw new Error('Data file not opened'); + const buf = Buffer.alloc(length); + fs.readSync(this.fd, buf, 0, length, Number(offset)); + return buf; + } - const found = this.indexReader.binarySearchBySequence(sequence); - if (!found) return null; + getHeader(): DataHeader { + if (!this.header) throw new Error('Data file not opened'); + return this.header; + } - const result = DataProtocol.deserializeRecord( - this.buffer, - Number(found.entry.offset), - this.serializer - ); - if (!result) return null; + getBySequence(sequence: number): DataEntry | null { + if (this.fd === null) throw new Error('Data file not opened'); - return { - sequence: found.entry.sequence, - timestamp: found.entry.timestamp, - data: result.data, - }; - } + const found = this.indexReader.binarySearchBySequence(sequence); + if (!found) return null; - getByIndex(index: number): DataEntry | null { - if (!this.buffer) throw new Error('Data file not opened'); - - const entry = this.indexReader.getEntry(index); - if (!entry) return null; - - const result = DataProtocol.deserializeRecord( - this.buffer, - Number(entry.offset), - this.serializer - ); - if (!result) return null; - - return { - sequence: entry.sequence, - timestamp: entry.timestamp, - data: result.data, - }; - } - - getBulkData(startSeq: number, endSeq: number): DataEntry[] { - if (!this.buffer) throw new Error('Data file not opened'); - - const results: DataEntry[] = []; - const indexHeader = this.indexReader.getHeader(); - let startIdx = this.findStartIndex(startSeq, indexHeader.validCount); - - for (let i = startIdx; i < indexHeader.validCount; i++) { - const entry = this.indexReader.getEntry(i); - if (!entry) continue; - - if (entry.sequence > endSeq) break; - - if (entry.sequence >= startSeq) { + const buf = this.readRecord(found.entry.offset, found.entry.length); const result = DataProtocol.deserializeRecord( - this.buffer, - Number(entry.offset), - this.serializer + buf, + 0, + this.serializer ); - if (result) { - results.push({ + if (!result) return null; + + return { + sequence: found.entry.sequence, + timestamp: found.entry.timestamp, + data: result.data, + }; + } + + getByIndex(index: number): DataEntry | null { + if (this.fd === null) throw new Error('Data file not opened'); + + const entry = this.indexReader.getEntry(index); + if (!entry) return null; + + const buf = this.readRecord(entry.offset, entry.length); + const result = DataProtocol.deserializeRecord( + buf, + 0, + this.serializer + ); + if (!result) return null; + + return { sequence: entry.sequence, timestamp: entry.timestamp, data: result.data, - }); + }; + } + + getBulkData(startSeq: number, endSeq: number): DataEntry[] { + if (this.fd === null) throw new Error('Data file not opened'); + + const results: DataEntry[] = []; + const indexHeader = this.indexReader.getHeader(); + let startIdx = this.findStartIndex(startSeq, indexHeader.writtenCnt); + + for (let i = startIdx; i < indexHeader.writtenCnt; i++) { + const entry = this.indexReader.getEntry(i); + if (!entry) continue; + + if (entry.sequence > endSeq) break; + + if (entry.sequence >= startSeq) { + const buf = this.readRecord(entry.offset, entry.length); + const result = DataProtocol.deserializeRecord( + buf, + 0, + this.serializer + ); + if (result) { + results.push({ + sequence: entry.sequence, + timestamp: entry.timestamp, + data: result.data, + }); + } + } } - } + + return results; } - return results; - } + private findStartIndex(targetSeq: number, writtenCnt: number): number { + let left = 0; + let right = writtenCnt - 1; + let result = 0; - private findStartIndex(targetSeq: number, validCount: number): number { - let left = 0; - let right = validCount - 1; - let result = 0; + while (left <= right) { + const mid = Math.floor((left + right) / 2); + const entry = this.indexReader.getEntry(mid); - while (left <= right) { - const mid = Math.floor((left + right) / 2); - const entry = this.indexReader.getEntry(mid); + if (!entry) { + right = mid - 1; + continue; + } - if (!entry) { - right = mid - 1; - continue; - } + if (entry.sequence >= targetSeq) { + result = mid; + right = mid - 1; + } else { + left = mid + 1; + } + } - if (entry.sequence >= targetSeq) { - result = mid; - right = mid - 1; - } else { - left = mid + 1; - } + return result; } - return result; - } + getBulkDataByTime(startTs: bigint, endTs: bigint): DataEntry[] { + if (this.fd === null) throw new Error('Data file not opened'); - getBulkDataByTime(startTs: bigint, endTs: bigint): DataEntry[] { - if (!this.buffer) throw new Error('Data file not opened'); + const indexResults = this.indexReader.findByTimeRange(startTs, endTs); + const results: DataEntry[] = []; - const indexResults = this.indexReader.findByTimeRange(startTs, endTs); - const results: DataEntry[] = []; + for (const { entry } of indexResults) { + const buf = this.readRecord(entry.offset, entry.length); + const result = DataProtocol.deserializeRecord( + buf, + 0, + this.serializer + ); + if (result) { + results.push({ + sequence: entry.sequence, + timestamp: entry.timestamp, + data: result.data, + }); + } + } - for (const { entry } of indexResults) { - const result = DataProtocol.deserializeRecord( - this.buffer, - Number(entry.offset), - this.serializer - ); - if (result) { - results.push({ - sequence: entry.sequence, - timestamp: entry.timestamp, - data: result.data, - }); - } + return results; } - return results; - } + getAllData(): DataEntry[] { + if (this.fd === null) throw new Error('Data file not opened'); - getAllData(): DataEntry[] { - if (!this.buffer) throw new Error('Data file not opened'); + const entries = this.indexReader.getAllEntries(); + const results: DataEntry[] = []; - const entries = this.indexReader.getAllEntries(); - const results: DataEntry[] = []; + for (const entry of entries) { + const buf = this.readRecord(entry.offset, entry.length); + const result = DataProtocol.deserializeRecord( + buf, + 0, + this.serializer + ); + if (result) { + results.push({ + sequence: entry.sequence, + timestamp: entry.timestamp, + data: result.data, + }); + } + } - for (const entry of entries) { - const result = DataProtocol.deserializeRecord( - this.buffer, - Number(entry.offset), - this.serializer - ); - if (result) { - results.push({ - sequence: entry.sequence, - timestamp: entry.timestamp, - data: result.data, - }); - } + return results; } - return results; - } - - getRecordCount(): number { - return this.indexReader.getHeader().validCount; - } - - getLastSequence(): number { - return this.indexReader.getHeader().lastSequence; - } - - close(): void { - if (this.buffer) { - mmap.unmap(this.buffer); - this.buffer = null; + getRecordCount(): number { + return this.indexReader.getHeader().writtenCnt; } - if (this.fd !== null) { - fs.closeSync(this.fd); - this.fd = null; + + getLastSequence(): number { + return this.indexReader.getHeader().latestSequence; } - this.header = null; - this.indexReader.close(); - } -} \ No newline at end of file + + close(): void { + if (this.fd !== null) { + fs.closeSync(this.fd); + this.fd = null; + } + this.header = null; + this.indexReader.close(); + } +} diff --git a/lib/dat/types.ts b/lib/dat/types.ts index b237bdb..acc00d8 100644 --- a/lib/dat/types.ts +++ b/lib/dat/types.ts @@ -1,16 +1,19 @@ +import { IndexFileOptions } from "../idx/types.js"; + // src/data-file/types.ts export interface Serializer { - serialize(data: T): Buffer; - deserialize(buf: Buffer): T; + serialize(data: T): Buffer; + deserialize(buf: Buffer): T; } export interface DataEntry { - sequence: number; - timestamp: bigint; - data: T; + sequence: number; + timestamp: bigint; + data: T; } export interface DataFileOptions { - serializer: Serializer; - maxEntries?: number; -} \ No newline at end of file + serializer: Serializer; + forceTruncate?: boolean; + indexFileOpt: IndexFileOptions; +} diff --git a/lib/dat/writer.ts b/lib/dat/writer.ts index 3a75a5f..f7a2338 100644 --- a/lib/dat/writer.ts +++ b/lib/dat/writer.ts @@ -2,119 +2,189 @@ import * as fs from 'node:fs'; import { DATA_HEADER_SIZE } from './constants.js'; import { DataProtocol } from './protocol.js'; -import { IndexWriter } from '../idx/index.js'; +import { IndexWriter, IndexFileOptionsRequired } from '../idx/index.js'; import type { Serializer, DataFileOptions } from './types.js'; export class DataWriter { - private fd: number | null = null; - private headerBuf: Buffer | null = null; - private currentOffset: bigint = BigInt(DATA_HEADER_SIZE); - private recordCount = 0; + private fd: number | null = null; + private headerBuf: Buffer | null = null; + private currentOffset: bigint = BigInt(DATA_HEADER_SIZE); + private recordCount = 0; - private indexWriter: IndexWriter; - private serializer: Serializer; + private indexWriter: IndexWriter; - readonly dataPath: string; - readonly indexPath: string; + // See DataFileOptions + private readonly serializer: Serializer; + private readonly forceTruncate: boolean; - constructor(basePath: string, options: DataFileOptions) { - this.dataPath = `${basePath}.dat`; - this.indexPath = `${basePath}.idx`; - this.serializer = options.serializer; + private latestSequence: number = 0; - const maxEntries = options.maxEntries ?? 10_000_000; - this.indexWriter = new IndexWriter(this.indexPath, { maxEntries }); - } + private readonly indexFileOpt: IndexFileOptionsRequired; - open(): void { - const isNew = !fs.existsSync(this.dataPath); + private dataPath: string | null = null; + private indexPath: string | null = null; - this.fd = fs.openSync(this.dataPath, isNew ? 'w+' : 'r+'); - this.headerBuf = Buffer.alloc(DATA_HEADER_SIZE); - if (isNew) { - const header = DataProtocol.createHeader(); - fs.writeSync(this.fd, header, 0, DATA_HEADER_SIZE, 0); - this.currentOffset = BigInt(DATA_HEADER_SIZE); - this.recordCount = 0; - } else { - fs.readSync(this.fd, this.headerBuf, 0, DATA_HEADER_SIZE, 0); - const header = DataProtocol.readHeader(this.headerBuf); - this.currentOffset = header.fileSize; - this.recordCount = header.recordCount; + constructor(options: DataFileOptions) { + this.serializer = options.serializer; + this.forceTruncate = options.forceTruncate ?? false; + + this.indexFileOpt = { + maxEntries: options.indexFileOpt.maxEntries ?? 10_000_000, + autoIncrementSequence: options.indexFileOpt.autoIncrementSequence ?? false + } + + this.indexWriter = new IndexWriter(this.indexFileOpt); } - this.indexWriter.open(); - } + open(basePath: string): void { + this.dataPath = `${basePath}.dat`; + this.indexPath = `${basePath}.idx`; - append(data: T, timestamp?: bigint): number { - if (this.fd === null) throw new Error('Data file not opened'); + // Index file 을 Open 함으로써 파일을 시작 할 수 있는지 검증 (Throw 로써) + // Open index file with maxEntries and autoIncrementSequence + const writtenCount = this.indexWriter.open(this.indexPath, this.forceTruncate); + const isNew = !fs.existsSync(this.dataPath); - const buf = DataProtocol.serializeRecord(data, this.serializer); - const offset = this.currentOffset; + // Index file 은 초기화인데, 신규파일 혹은 강제 클리어가 아니라면 + if (writtenCount === 0 && !(isNew || this.forceTruncate)) { + throw new Error(`Index file & Data File is invalid ${this.indexPath} is initial but ${this.dataPath} is exists`); + } + if (writtenCount > 0 && isNew) { + throw new Error(`Index file & Data File is invalid data of ${this.indexPath} | ${writtenCount} is exists but ${this.dataPath} is not exists`); + } - fs.writeSync(this.fd, buf, 0, buf.length, Number(offset)); + // Warn if forceTruncate will delete existing data + if (this.forceTruncate && !isNew) { + const stats = fs.statSync(this.dataPath); + const sizeMB = (stats.size / 1024 / 1024).toFixed(2); + console.warn( + `[DataWriter] forceTruncate enabled: Deleting ${sizeMB} MB of existing data\n` + + ` Index: ${this.indexPath} (${writtenCount} records)\n` + + ` Data: ${this.dataPath}` + ); + } - const sequence = this.indexWriter.getNextSequence(); - const ts = timestamp ?? BigInt(Date.now()) * 1000000n; + this.fd = fs.openSync(this.dataPath, + isNew || this.forceTruncate ? 'w+' : 'r+'); - this.indexWriter.append(offset, buf.length, ts); + try { + this.headerBuf = Buffer.alloc(DATA_HEADER_SIZE); - this.currentOffset += BigInt(buf.length); - this.recordCount++; + if (isNew || this.forceTruncate) { + const header = DataProtocol.createHeader(); + fs.writeSync(this.fd, header, 0, DATA_HEADER_SIZE, 0); + this.currentOffset = BigInt(DATA_HEADER_SIZE); + this.recordCount = 0; + this.latestSequence = 0; + } else { + fs.readSync(this.fd, this.headerBuf, 0, DATA_HEADER_SIZE, 0); + const header = DataProtocol.readHeader(this.headerBuf); - return sequence; - } + // Validate: Data file recordCount must match Index file writtenCnt + if (header.recordCount !== writtenCount) { + throw new Error( + `Data file record count mismatch: Data has ${header.recordCount} but Index has ${writtenCount}` + ); + } - appendBulk(records: T[], timestamp?: bigint): number[] { - const sequences: number[] = []; - const ts = timestamp ?? BigInt(Date.now()) * 1000000n; - - for (const record of records) { - const seq = this.append(record, ts); - sequences.push(seq); + this.currentOffset = header.fileSize; + this.recordCount = header.recordCount; + this.latestSequence = this.indexWriter.getLatestSequence(); + } + } catch (error) { + // Clean up resources on error + if (this.fd !== null) { + fs.closeSync(this.fd); + this.fd = null; + } + this.headerBuf = null; + throw error; + } } - return sequences; - } + append(data: T, sequence?: number, timestamp?: bigint): number { + if (this.fd === null) throw new Error('Data file not opened'); - getLastSequence(): number { - return this.indexWriter.getLastSequence(); - } + const buf = DataProtocol.serializeRecord(data, this.serializer); + const offset = this.currentOffset; - getNextSequence(): number { - return this.indexWriter.getNextSequence(); - } + fs.writeSync(this.fd, buf, 0, buf.length, Number(offset)); - sync(): void { - if (this.fd === null || !this.headerBuf) return; + // Write to index file + this.indexWriter.write(offset, buf.length, sequence, timestamp); - DataProtocol.updateHeader(this.headerBuf, this.currentOffset, this.recordCount); - fs.writeSync(this.fd, this.headerBuf, 0, DATA_HEADER_SIZE, 0); - fs.fsyncSync(this.fd); + // Update latestSequence to the most recent sequence + this.latestSequence = this.indexWriter.getLatestSequence(); - this.indexWriter.syncAll(); - } + this.currentOffset += BigInt(buf.length); + ++this.recordCount; - close(): void { - this.sync(); - - if (this.fd !== null) { - fs.closeSync(this.fd); - this.fd = null; + return this.latestSequence; } - this.indexWriter.close(); - this.headerBuf = null; - } + /* + appendBulk(records: T[], sequences?: number[], timestamp?: bigint): number[] { + // Runtime check: sequences required when autoIncrementSequence is false + if (!this.autoIncrementSequence) { + if (!sequences) { + throw new Error('sequences is required when autoIncrementSequence is false'); + } + if (sequences.length !== records.length) { + throw new Error(`sequences length (${sequences.length}) must match records length (${records.length})`); + } + } - getStats() { - return { - dataPath: this.dataPath, - indexPath: this.indexPath, - currentOffset: this.currentOffset, - recordCount: this.recordCount, - lastSequence: this.indexWriter.getLastSequence(), - }; - } -} \ No newline at end of file + const resultSequences: number[] = []; + const ts = timestamp ?? BigInt(Date.now()) * 1000000n; + + for (let i = 0; i < records.length; i++) { + const seq = sequences?.[i]; + const resultSeq = this.append(records[i], seq, ts); + resultSequences.push(resultSeq); + } + + return resultSequences; + } + */ + + getLatestSequence(): number { + return this.latestSequence; + } + + getNextSequence(): number { + return this.latestSequence + 1; + } + + sync(): void { + if (this.fd === null || !this.headerBuf) return; + + DataProtocol.updateHeader(this.headerBuf, this.currentOffset, this.recordCount); + fs.writeSync(this.fd, this.headerBuf, 0, DATA_HEADER_SIZE, 0); + fs.fsyncSync(this.fd); + + this.indexWriter.syncAll(); + } + + close(): void { + this.sync(); + + if (this.fd !== null) { + fs.closeSync(this.fd); + this.fd = null; + } + + this.indexWriter.close(); + this.headerBuf = null; + } + + getStats() { + return { + dataPath: this.dataPath, + indexPath: this.indexPath, + currentOffset: this.currentOffset, + recordCount: this.recordCount, + latestSequence: this.indexWriter.getLatestSequence(), + }; + } +} diff --git a/lib/idx/protocol.ts b/lib/idx/protocol.ts index 2423006..33d36ad 100644 --- a/lib/idx/protocol.ts +++ b/lib/idx/protocol.ts @@ -1,106 +1,108 @@ // src/index-file/protocol.ts import { - INDEX_MAGIC, - INDEX_VERSION, - INDEX_HEADER_SIZE, - INDEX_ENTRY_SIZE, - FLAG_VALID, + INDEX_MAGIC, + INDEX_VERSION, + INDEX_HEADER_SIZE, + INDEX_ENTRY_SIZE, + FLAG_VALID, } from './constants.js'; import type { IndexHeader, IndexEntry } from './types.js'; const CRC_TABLE = new Uint32Array(256); for (let i = 0; i < 256; i++) { - let c = i; - for (let j = 0; j < 8; j++) { - c = (c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1); - } - CRC_TABLE[i] = c >>> 0; + let c = i; + for (let j = 0; j < 8; j++) { + c = (c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1); + } + CRC_TABLE[i] = c >>> 0; } export function crc32(buf: Buffer, start = 0, end?: number): number { - let crc = 0xFFFFFFFF; - const len = end ?? buf.length; - for (let i = start; i < len; i++) { - crc = CRC_TABLE[(crc ^ buf[i]) & 0xFF] ^ (crc >>> 8); - } - return (~crc) >>> 0; + let crc = 0xFFFFFFFF; + const len = end ?? buf.length; + for (let i = start; i < len; i++) { + crc = CRC_TABLE[(crc ^ buf[i]) & 0xFF] ^ (crc >>> 8); + } + return (~crc) >>> 0; } export class IndexProtocol { - static createHeader(entryCount: number, magic = INDEX_MAGIC): Buffer { - const buf = Buffer.alloc(INDEX_HEADER_SIZE); - buf.write(magic, 0, 4, 'ascii'); - buf.writeUInt32LE(INDEX_VERSION, 4); - buf.writeBigUInt64LE(BigInt(Date.now()) * 1000000n, 8); - buf.writeUInt32LE(INDEX_ENTRY_SIZE, 16); - buf.writeUInt32LE(entryCount, 20); - buf.writeUInt32LE(0, 24); - buf.writeBigUInt64LE(0n, 28); - buf.writeUInt32LE(0, 36); - return buf; - } + static createHeader(entryCount: number, autoIncrementSequence: boolean, magic = INDEX_MAGIC): Buffer { + const buf = Buffer.alloc(INDEX_HEADER_SIZE); + buf.write(magic, 0, 4, 'ascii'); + buf.writeUInt32LE(INDEX_VERSION, 4); + buf.writeBigUInt64LE(BigInt(Date.now()) * 1000000n, 8); + buf.writeUInt32LE(INDEX_ENTRY_SIZE, 16); + buf.writeUInt32LE(entryCount, 20); + buf.writeUInt32LE(0, 24); // writtenCnt + buf.writeBigUInt64LE(0n, 28); // dataFileSize + buf.writeUInt32LE(0, 36); // latestSequence + buf.writeUInt8(autoIncrementSequence ? 1 : 0, 40); // autoIncrementSequence + return buf; + } - static readHeader(buf: Buffer): IndexHeader { - return { - magic: buf.toString('ascii', 0, 4), - version: buf.readUInt32LE(4), - createdAt: buf.readBigUInt64LE(8), - entrySize: buf.readUInt32LE(16), - entryCount: buf.readUInt32LE(20), - validCount: buf.readUInt32LE(24), - dataFileSize: buf.readBigUInt64LE(28), - lastSequence: buf.readUInt32LE(36), - reserved: buf.subarray(40, 64), - }; - } + static readHeader(buf: Buffer): IndexHeader { + return { + magic: buf.toString('ascii', 0, 4), + version: buf.readUInt32LE(4), + createdAt: buf.readBigUInt64LE(8), + entrySize: buf.readUInt32LE(16), + entryCount: buf.readUInt32LE(20), + writtenCnt: buf.readUInt32LE(24), + dataFileSize: buf.readBigUInt64LE(28), + latestSequence: buf.readUInt32LE(36), + autoIncrementSequence: buf.readUInt8(40) === 1, + reserved: buf.subarray(41, 64), + }; + } - static updateHeaderCounts( - buf: Buffer, - validCount: number, - dataFileSize: bigint, - lastSequence: number - ): void { - buf.writeUInt32LE(validCount, 24); - buf.writeBigUInt64LE(dataFileSize, 28); - buf.writeUInt32LE(lastSequence, 36); - } + static updateHeaderCounts( + buf: Buffer, + writtenCnt: number, + dataFileSize: bigint, + latestSequence: number + ): void { + buf.writeUInt32LE(writtenCnt, 24); + buf.writeBigUInt64LE(dataFileSize, 28); + buf.writeUInt32LE(latestSequence, 36); + } - static writeEntry(buf: Buffer, index: number, entry: Omit): void { - const off = INDEX_HEADER_SIZE + index * INDEX_ENTRY_SIZE; + static writeEntry(buf: Buffer, index: number, entry: Omit): void { + const off = INDEX_HEADER_SIZE + index * INDEX_ENTRY_SIZE; - buf.writeUInt32LE(entry.sequence, off); - buf.writeBigUInt64LE(entry.timestamp, off + 4); - buf.writeBigUInt64LE(entry.offset, off + 12); - buf.writeUInt32LE(entry.length, off + 20); - buf.writeUInt32LE(entry.flags | FLAG_VALID, off + 24); + buf.writeUInt32LE(entry.sequence, off); + buf.writeBigUInt64LE(entry.timestamp, off + 4); + buf.writeBigUInt64LE(entry.offset, off + 12); + buf.writeUInt32LE(entry.length, off + 20); + buf.writeUInt32LE(entry.flags | FLAG_VALID, off + 24); - const checksum = crc32(buf, off, off + 28); - buf.writeUInt32LE(checksum, off + 28); - } + const checksum = crc32(buf, off, off + 28); + buf.writeUInt32LE(checksum, off + 28); + } - static readEntry(buf: Buffer, index: number): IndexEntry | null { - const off = INDEX_HEADER_SIZE + index * INDEX_ENTRY_SIZE; - const flags = buf.readUInt32LE(off + 24); + static readEntry(buf: Buffer, index: number): IndexEntry | null { + const off = INDEX_HEADER_SIZE + index * INDEX_ENTRY_SIZE; + const flags = buf.readUInt32LE(off + 24); - if (!(flags & FLAG_VALID)) return null; + if (!(flags & FLAG_VALID)) return null; - return { - sequence: buf.readUInt32LE(off), - timestamp: buf.readBigUInt64LE(off + 4), - offset: buf.readBigUInt64LE(off + 12), - length: buf.readUInt32LE(off + 20), - flags, - checksum: buf.readUInt32LE(off + 28), - }; - } + return { + sequence: buf.readUInt32LE(off), + timestamp: buf.readBigUInt64LE(off + 4), + offset: buf.readBigUInt64LE(off + 12), + length: buf.readUInt32LE(off + 20), + flags, + checksum: buf.readUInt32LE(off + 28), + }; + } - static isValidEntry(buf: Buffer, index: number): boolean { - const off = INDEX_HEADER_SIZE + index * INDEX_ENTRY_SIZE; - const flags = buf.readUInt32LE(off + 24); - return (flags & FLAG_VALID) !== 0; - } + static isValidEntry(buf: Buffer, index: number): boolean { + const off = INDEX_HEADER_SIZE + index * INDEX_ENTRY_SIZE; + const flags = buf.readUInt32LE(off + 24); + return (flags & FLAG_VALID) !== 0; + } - static calcFileSize(entryCount: number): number { - return INDEX_HEADER_SIZE + INDEX_ENTRY_SIZE * entryCount; - } -} \ No newline at end of file + static calcFileSize(entryCount: number): number { + return INDEX_HEADER_SIZE + INDEX_ENTRY_SIZE * entryCount; + } +} diff --git a/lib/idx/reader.ts b/lib/idx/reader.ts index 256a12b..3498565 100644 --- a/lib/idx/reader.ts +++ b/lib/idx/reader.ts @@ -1,131 +1,114 @@ // src/index-file/reader.ts import * as fs from 'node:fs'; -import mmap from '@elilee/mmap-native'; import { IndexProtocol } from './protocol.js'; import type { IndexHeader, IndexEntry } from './types.js'; export class IndexReader { - private fd: number | null = null; - private buffer: Buffer | null = null; - private header: IndexHeader | null = null; + private buffer: Buffer | null = null; + private header: IndexHeader | null = null; - readonly path: string; + readonly path: string; - constructor(path: string) { - this.path = path; - } - - open(): void { - const stats = fs.statSync(this.path); - this.fd = fs.openSync(this.path, 'r'); - - this.buffer = mmap.map( - stats.size, - mmap.PROT_READ, - mmap.MAP_SHARED, - this.fd, - 0 - ); - - this.header = IndexProtocol.readHeader(this.buffer); - } - - getHeader(): IndexHeader { - if (!this.header) throw new Error('Index file not opened'); - return this.header; - } - - getEntry(index: number): IndexEntry | null { - if (!this.buffer || !this.header) throw new Error('Index file not opened'); - if (index < 0 || index >= this.header.entryCount) return null; - return IndexProtocol.readEntry(this.buffer, index); - } - - findBySequence(sequence: number): { index: number; entry: IndexEntry } | null { - if (!this.buffer || !this.header) throw new Error('Index file not opened'); - - for (let i = 0; i < this.header.validCount; i++) { - const entry = IndexProtocol.readEntry(this.buffer, i); - if (entry && entry.sequence === sequence) { - return { index: i, entry }; - } - } - return null; - } - - findBySequenceRange(startSeq: number, endSeq: number): { index: number; entry: IndexEntry }[] { - if (!this.buffer || !this.header) throw new Error('Index file not opened'); - - const results: { index: number; entry: IndexEntry }[] = []; - for (let i = 0; i < this.header.validCount; i++) { - const entry = IndexProtocol.readEntry(this.buffer, i); - if (entry && entry.sequence >= startSeq && entry.sequence <= endSeq) { - results.push({ index: i, entry }); - } - } - return results; - } - - getAllEntries(): IndexEntry[] { - if (!this.buffer || !this.header) throw new Error('Index file not opened'); - - const entries: IndexEntry[] = []; - for (let i = 0; i < this.header.validCount; i++) { - const entry = IndexProtocol.readEntry(this.buffer, i); - if (entry) entries.push(entry); - } - return entries; - } - - findByTimeRange(startTs: bigint, endTs: bigint): { index: number; entry: IndexEntry }[] { - if (!this.buffer || !this.header) throw new Error('Index file not opened'); - - const results: { index: number; entry: IndexEntry }[] = []; - for (let i = 0; i < this.header.validCount; i++) { - const entry = IndexProtocol.readEntry(this.buffer, i); - if (entry && entry.timestamp >= startTs && entry.timestamp <= endTs) { - results.push({ index: i, entry }); - } - } - return results; - } - - binarySearchBySequence(targetSeq: number): { index: number; entry: IndexEntry } | null { - if (!this.buffer || !this.header) throw new Error('Index file not opened'); - - let left = 0; - let right = this.header.validCount - 1; - - while (left <= right) { - const mid = Math.floor((left + right) / 2); - const entry = IndexProtocol.readEntry(this.buffer, mid); - - if (!entry) { - right = mid - 1; - continue; - } - - if (entry.sequence === targetSeq) { - return { index: mid, entry }; - } else if (entry.sequence < targetSeq) { - left = mid + 1; - } else { - right = mid - 1; - } + constructor(path: string) { + this.path = path; } - return null; - } + open(): void { + // Read entire file into buffer (simpler than mmap for read-only access) + this.buffer = fs.readFileSync(this.path); + this.header = IndexProtocol.readHeader(this.buffer); + } - close(): void { - if (this.buffer) { - mmap.unmap(this.buffer); - this.buffer = null; + getHeader(): IndexHeader { + if (!this.header) throw new Error('Index file not opened'); + return this.header; } - if (this.fd !== null) { - fs.closeSync(this.fd); - this.fd = null; + + getEntry(index: number): IndexEntry | null { + if (!this.buffer || !this.header) throw new Error('Index file not opened'); + if (index < 0 || index >= this.header.entryCount) return null; + return IndexProtocol.readEntry(this.buffer, index); } - this.header = null; - } -} \ No newline at end of file + + findBySequence(sequence: number): { index: number; entry: IndexEntry } | null { + if (!this.buffer || !this.header) throw new Error('Index file not opened'); + + for (let i = 0; i < this.header.writtenCnt; i++) { + const entry = IndexProtocol.readEntry(this.buffer, i); + if (entry && entry.sequence === sequence) { + return { index: i, entry }; + } + } + return null; + } + + findBySequenceRange(startSeq: number, endSeq: number): { index: number; entry: IndexEntry }[] { + if (!this.buffer || !this.header) throw new Error('Index file not opened'); + + const results: { index: number; entry: IndexEntry }[] = []; + for (let i = 0; i < this.header.writtenCnt; i++) { + const entry = IndexProtocol.readEntry(this.buffer, i); + if (entry && entry.sequence >= startSeq && entry.sequence <= endSeq) { + results.push({ index: i, entry }); + } + } + return results; + } + + getAllEntries(): IndexEntry[] { + if (!this.buffer || !this.header) throw new Error('Index file not opened'); + + const entries: IndexEntry[] = []; + for (let i = 0; i < this.header.writtenCnt; i++) { + const entry = IndexProtocol.readEntry(this.buffer, i); + if (entry) entries.push(entry); + } + return entries; + } + + findByTimeRange(startTs: bigint, endTs: bigint): { index: number; entry: IndexEntry }[] { + if (!this.buffer || !this.header) throw new Error('Index file not opened'); + + const results: { index: number; entry: IndexEntry }[] = []; + for (let i = 0; i < this.header.writtenCnt; i++) { + const entry = IndexProtocol.readEntry(this.buffer, i); + if (entry && entry.timestamp >= startTs && entry.timestamp <= endTs) { + results.push({ index: i, entry }); + } + } + return results; + } + + binarySearchBySequence(targetSeq: number): { index: number; entry: IndexEntry } | null { + if (!this.buffer || !this.header) throw new Error('Index file not opened'); + + let left = 0; + let right = this.header.writtenCnt - 1; + + while (left <= right) { + const mid = Math.floor((left + right) / 2); + const entry = IndexProtocol.readEntry(this.buffer, mid); + + if (!entry) { + right = mid - 1; + continue; + } + + if (entry.sequence === targetSeq) { + return { index: mid, entry }; + } else if (entry.sequence < targetSeq) { + left = mid + 1; + } else { + right = mid - 1; + } + } + + return null; + } + + close(): void { + // Simply release buffer reference (GC will handle cleanup) + this.buffer = null; + this.header = null; + } +} diff --git a/lib/idx/types.ts b/lib/idx/types.ts index a677b3b..19191fa 100644 --- a/lib/idx/types.ts +++ b/lib/idx/types.ts @@ -1,26 +1,29 @@ // src/index-file/types.ts export interface IndexHeader { - magic: string; - version: number; - createdAt: bigint; - entrySize: number; - entryCount: number; - validCount: number; - dataFileSize: bigint; - lastSequence: number; - reserved: Buffer; + magic: string; + version: number; + createdAt: bigint; + entrySize: number; + entryCount: number; + writtenCnt: number; + dataFileSize: bigint; + latestSequence: number; + autoIncrementSequence: boolean; + reserved: Buffer; } export interface IndexEntry { - sequence: number; - timestamp: bigint; - offset: bigint; - length: number; - flags: number; - checksum: number; + sequence: number; + timestamp: bigint; + offset: bigint; + length: number; + flags: number; + checksum: number; } export interface IndexFileOptions { - maxEntries: number; - magic?: string; -} \ No newline at end of file + maxEntries?: number; + autoIncrementSequence?: boolean; +} + +export type IndexFileOptionsRequired = Required; diff --git a/lib/idx/writer.ts b/lib/idx/writer.ts index 632d607..e9ffb13 100644 --- a/lib/idx/writer.ts +++ b/lib/idx/writer.ts @@ -1,141 +1,209 @@ // src/index-file/writer.ts import * as fs from 'node:fs'; -import mmap from '@elilee/mmap-native'; -import { INDEX_HEADER_SIZE, FLAG_VALID } from './constants.js'; +import { INDEX_HEADER_SIZE, INDEX_ENTRY_SIZE, FLAG_VALID } from './constants.js'; import { IndexProtocol } from './protocol.js'; -import type { IndexFileOptions } from './types.js'; +import { IndexFileOptionsRequired } from './types.js'; export class IndexWriter { - private fd: number | null = null; - private buffer: Buffer | null = null; - private validCount = 0; - private dataFileSize = 0n; - private lastSequence = 0; + private fd: number | null = null; + private headerBuf: Buffer | null = null; + private entryBuf: Buffer | null = null; - readonly path: string; - readonly maxEntries: number; - readonly fileSize: number; + private writtenCnt = 0; + private dataFileSize = 0n; + private latestSequence = 0; - constructor(path: string, options: IndexFileOptions) { - this.path = path; - this.maxEntries = options.maxEntries; - this.fileSize = IndexProtocol.calcFileSize(options.maxEntries); - } + private path: string | null = null; + private fileSize: number = 0; - open(): void { - const isNew = !fs.existsSync(this.path); + // see IndexFileOptions + private maxEntries: number = 0; + private autoIncrementSequence: boolean = false; - this.fd = fs.openSync(this.path, isNew ? 'w+' : 'r+'); - - if (isNew) { - fs.ftruncateSync(this.fd, this.fileSize); + constructor(opt: IndexFileOptionsRequired) { + // Empty constructor - maxEntries provided in open() + this.maxEntries = opt.maxEntries; + this.autoIncrementSequence = opt.autoIncrementSequence; } - this.buffer = mmap.map( - this.fileSize, - mmap.PROT_READ | mmap.PROT_WRITE, - mmap.MAP_SHARED, - this.fd, - 0 - ); + open(path: string, forceTruncate: boolean = false): number { + this.path = path; - if (isNew) { - const header = IndexProtocol.createHeader(this.maxEntries); - header.copy(this.buffer, 0); - this.syncHeader(); - } else { - const header = IndexProtocol.readHeader(this.buffer); - this.validCount = header.validCount; - this.dataFileSize = header.dataFileSize; - this.lastSequence = header.lastSequence; - } - } + const isNew = !fs.existsSync(this.path); - write( - index: number, - sequence: number, - offset: bigint, - length: number, - timestamp?: bigint - ): boolean { - if (!this.buffer) throw new Error('Index file not opened'); - if (index < 0 || index >= this.maxEntries) return false; + if (isNew || forceTruncate) { + // New file: use provided values + this.fileSize = IndexProtocol.calcFileSize(this.maxEntries); + this.writtenCnt = 0; + this.dataFileSize = 0n; + this.latestSequence = 0; - const ts = timestamp ?? BigInt(Date.now()) * 1000000n; + this.fd = fs.openSync(this.path, 'w+'); + fs.ftruncateSync(this.fd, this.fileSize); - IndexProtocol.writeEntry(this.buffer, index, { - sequence, - timestamp: ts, - offset, - length, - flags: FLAG_VALID, - }); + // Allocate buffers for header and entry + this.headerBuf = Buffer.alloc(INDEX_HEADER_SIZE); + this.entryBuf = Buffer.alloc(INDEX_ENTRY_SIZE); - this.validCount++; - if (sequence > this.lastSequence) { - this.lastSequence = sequence; + const header = IndexProtocol.createHeader(this.maxEntries, this.autoIncrementSequence); + header.copy(this.headerBuf, 0); + + // Write header to file + fs.writeSync(this.fd, this.headerBuf, 0, INDEX_HEADER_SIZE, 0); + fs.fsyncSync(this.fd); + } else { + // Existing file: read header first + this.fd = fs.openSync(this.path, 'r+'); + + try { + this.headerBuf = Buffer.alloc(INDEX_HEADER_SIZE); + this.entryBuf = Buffer.alloc(INDEX_ENTRY_SIZE); + + fs.readSync(this.fd, this.headerBuf, 0, INDEX_HEADER_SIZE, 0); + const header = IndexProtocol.readHeader(this.headerBuf); + + if (this.maxEntries !== header.entryCount) { + throw new Error( + `maxEntries mismatch: provided ${this.maxEntries} but file has ${header.entryCount}` + ); + } + if (this.autoIncrementSequence !== header.autoIncrementSequence) { + throw new Error( + `autoIncrementSequence mismatch: provided ${this.autoIncrementSequence} but file has ${header.autoIncrementSequence}` + ); + } + + const expectFileSize = IndexProtocol.calcFileSize(this.maxEntries); + const calcedFileSize = IndexProtocol.calcFileSize(header.entryCount); + if (expectFileSize !== calcedFileSize) { + // if (opt.version !== header.version) { 버전이 다른거니까 어떻게 처리 할지는 추후 고민 TODO } + throw new Error( + `Indexfile size calc is invalid : provided ${expectFileSize} but file has ${calcedFileSize}` + ); + } + + this.fileSize = calcedFileSize; + this.writtenCnt = header.writtenCnt; + this.dataFileSize = header.dataFileSize; + this.latestSequence = header.latestSequence; + } catch (error) { + // Clean up resources on error + if (this.fd !== null) { + fs.closeSync(this.fd); + this.fd = null; + } + this.headerBuf = null; + this.entryBuf = null; + throw error; + } + } + + return this.writtenCnt; } - const newDataEnd = offset + BigInt(length); - if (newDataEnd > this.dataFileSize) { - this.dataFileSize = newDataEnd; + write( + offset: bigint, + length: number, + sequence?: number, + timestamp?: bigint + ): boolean { + if (!this.entryBuf || this.fd === null) throw new Error('Index file not opened'); + if (this.writtenCnt >= this.maxEntries) { + throw new Error(`Data count exceed provide : ${this.writtenCnt + 1} - max : ${this.maxEntries}`); + } + + // Calculate sequence + let seq: number; + if (!this.autoIncrementSequence) { + if (sequence === undefined) { + throw new Error('sequence is required when autoIncrementSequence is false'); + } + seq = sequence; + } else { + seq = this.writtenCnt + 1; + } + + const ts = timestamp ?? BigInt(Date.now()) * 1000000n; + + // Create a temporary buffer for this entry + const tempBuf = Buffer.alloc(INDEX_HEADER_SIZE + (this.writtenCnt + 1) * INDEX_ENTRY_SIZE); + + // Write entry to temp buffer + IndexProtocol.writeEntry(tempBuf, this.writtenCnt, { + sequence: seq, + timestamp: ts, + offset, + length, + flags: FLAG_VALID, + }); + + // Calculate file offset for this entry + const fileOffset = INDEX_HEADER_SIZE + this.writtenCnt * INDEX_ENTRY_SIZE; + + // Write entry to file + fs.writeSync(this.fd, tempBuf, fileOffset, INDEX_ENTRY_SIZE, fileOffset); + + this.writtenCnt++; + this.latestSequence = seq; + + const newDataEnd = offset + BigInt(length); + if (newDataEnd > this.dataFileSize) { + this.dataFileSize = newDataEnd; + } + + return true; } - return true; - } + getLatestSequence(): number { + return this.latestSequence; + } - append(offset: bigint, length: number, timestamp?: bigint): number { - const index = this.validCount; - if (index >= this.maxEntries) return -1; + syncHeader(): void { + if (!this.headerBuf || this.fd === null) return; - const sequence = this.lastSequence + 1; - this.write(index, sequence, offset, length, timestamp); - return index; - } + // Update header counts + IndexProtocol.updateHeaderCounts( + this.headerBuf, + this.writtenCnt, + this.dataFileSize, + this.latestSequence + ); - getLastSequence(): number { - return this.lastSequence; - } + // Write header to file + fs.writeSync(this.fd, this.headerBuf, 0, INDEX_HEADER_SIZE, 0); + } - getNextSequence(): number { - return this.lastSequence + 1; - } + syncAll(): void { + if (this.fd === null) return; - syncHeader(): void { - if (!this.buffer) return; - IndexProtocol.updateHeaderCounts( - this.buffer, - this.validCount, - this.dataFileSize, - this.lastSequence - ); - mmap.sync(this.buffer, 0, INDEX_HEADER_SIZE, mmap.MS_ASYNC); - } + // Sync header first + this.syncHeader(); - syncAll(): void { - if (!this.buffer) return; - this.syncHeader(); - mmap.sync(this.buffer, 0, this.fileSize, mmap.MS_SYNC); - } + // Sync all file changes to disk + fs.fsyncSync(this.fd); + } - close(): void { - if (!this.buffer || this.fd === null) return; + close(): void { + if (this.fd === null) return; - this.syncAll(); - mmap.unmap(this.buffer); - fs.closeSync(this.fd); + // 1. Sync all changes + this.syncAll(); - this.buffer = null; - this.fd = null; - } + // 2. Close file descriptor + fs.closeSync(this.fd); + this.fd = null; - getStats() { - return { - path: this.path, - maxEntries: this.maxEntries, - validCount: this.validCount, - dataFileSize: this.dataFileSize, - lastSequence: this.lastSequence, - }; - } -} \ No newline at end of file + // 3. Clean up buffers + this.headerBuf = null; + this.entryBuf = null; + } + + getStats() { + return { + path: this.path, + writtenCnt: this.writtenCnt, + dataFileSize: this.dataFileSize, + latestSequence: this.latestSequence, + }; + } +} diff --git a/package-lock.json b/package-lock.json index 19d5fee..4ddae48 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,19 +7,10 @@ "": { "name": "@elilee/index-file", "version": "1.0.0", - "license": "MIT", - "dependencies": { - "@elilee/mmap-native": "git+https://git.satitech.co.kr/sati-open/sati.n-api.mmap.git" - } - }, - "node_modules/@elilee/mmap-native": { - "version": "1.0.1", - "resolved": "git+https://git.satitech.co.kr/sati-open/sati.n-api.mmap.git#f6e0201088d713f4dc06e984fa1aa316a39f6e83", "cpu": [ "x64", "arm64" ], - "hasInstallScript": true, "license": "MIT", "os": [ "linux", @@ -27,80 +18,12 @@ ], "dependencies": { "@types/node": "^22.0.0", - "node-gyp": "^11.0.0", "typescript": "^5.7.0" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", - "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", - "license": "ISC", - "dependencies": { - "minipass": "^7.0.4" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@npmcli/agent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-3.0.0.tgz", - "integrity": "sha512-S79NdEgDQd/NGCay6TCoVzXSj74skRZIKJcpJjC5lOq34SZzyI6MqtiiWoiVWoVrTcGjNeC4ipbh1VIHlpfF5Q==", - "license": "ISC", - "dependencies": { - "agent-base": "^7.1.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.1", - "lru-cache": "^10.0.1", - "socks-proxy-agent": "^8.0.3" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/@npmcli/fs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-4.0.0.tgz", - "integrity": "sha512-/xGlezI6xfGO9NwuJlnwz/K14qD1kCSAGtacBHnGzeAIuJGazcp45KP5NuyARXoKb7cwulAGWVsbeSxdG/cb0Q==", - "license": "ISC", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, "node_modules/@types/node": { "version": "22.19.7", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.7.tgz", @@ -110,928 +33,6 @@ "undici-types": "~6.21.0" } }, - "node_modules/abbrev": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz", - "integrity": "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==", - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" - }, - "node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/cacache": { - "version": "19.0.1", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-19.0.1.tgz", - "integrity": "sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ==", - "license": "ISC", - "dependencies": { - "@npmcli/fs": "^4.0.0", - "fs-minipass": "^3.0.0", - "glob": "^10.2.2", - "lru-cache": "^10.0.1", - "minipass": "^7.0.3", - "minipass-collect": "^2.0.1", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^7.0.2", - "ssri": "^12.0.0", - "tar": "^7.4.3", - "unique-filename": "^4.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/chownr": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", - "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cross-spawn/node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/cross-spawn/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "license": "MIT" - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "license": "MIT" - }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "license": "MIT", - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "license": "MIT" - }, - "node_modules/exponential-backoff": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", - "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", - "license": "Apache-2.0" - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/fs-minipass": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", - "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/glob": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC" - }, - "node_modules/http-cache-semantics": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", - "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", - "license": "BSD-2-Clause" - }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "license": "MIT", - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/ip-address": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", - "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", - "license": "ISC", - "engines": { - "node": ">=16" - } - }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "license": "ISC" - }, - "node_modules/make-fetch-happen": { - "version": "14.0.3", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-14.0.3.tgz", - "integrity": "sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ==", - "license": "ISC", - "dependencies": { - "@npmcli/agent": "^3.0.0", - "cacache": "^19.0.1", - "http-cache-semantics": "^4.1.1", - "minipass": "^7.0.2", - "minipass-fetch": "^4.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^1.0.0", - "proc-log": "^5.0.0", - "promise-retry": "^2.0.1", - "ssri": "^12.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/minipass-collect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", - "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/minipass-fetch": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-4.0.1.tgz", - "integrity": "sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ==", - "license": "MIT", - "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^3.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-flush/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-flush/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-pipeline/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-pipeline/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, - "node_modules/minizlib": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", - "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", - "license": "MIT", - "dependencies": { - "minipass": "^7.1.2" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/node-gyp": { - "version": "11.5.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-11.5.0.tgz", - "integrity": "sha512-ra7Kvlhxn5V9Slyus0ygMa2h+UqExPqUIkfk7Pc8QTLT956JLSy51uWFwHtIYy0vI8cB4BDhc/S03+880My/LQ==", - "license": "MIT", - "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^14.0.3", - "nopt": "^8.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.5", - "tar": "^7.4.3", - "tinyglobby": "^0.2.12", - "which": "^5.0.0" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/nopt": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", - "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==", - "license": "ISC", - "dependencies": { - "abbrev": "^3.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/p-map": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", - "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "license": "BlueOak-1.0.0" - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/proc-log": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-5.0.0.tgz", - "integrity": "sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==", - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "license": "MIT", - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT", - "optional": true - }, - "node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "license": "MIT", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks": { - "version": "2.8.7", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", - "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", - "license": "MIT", - "dependencies": { - "ip-address": "^10.0.1", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", - "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "socks": "^2.8.3" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/ssri": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-12.0.0.tgz", - "integrity": "sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==", - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/string-width-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/tar": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.6.tgz", - "integrity": "sha512-xqUeu2JAIJpXyvskvU3uvQW8PAmHrtXp2KDuMJwQqW8Sqq0CaZBAQ+dKS3RBXVhU4wC5NjAdKrmh84241gO9cA==", - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.1.0", - "yallist": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", @@ -1050,145 +51,6 @@ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "license": "MIT" - }, - "node_modules/unique-filename": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-4.0.0.tgz", - "integrity": "sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ==", - "license": "ISC", - "dependencies": { - "unique-slug": "^5.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/unique-slug": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-5.0.0.tgz", - "integrity": "sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg==", - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/which": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", - "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", - "license": "ISC", - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/wrap-ansi-cjs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yallist": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", - "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } } } } diff --git a/package.json b/package.json index 046249b..9212c39 100644 --- a/package.json +++ b/package.json @@ -14,8 +14,7 @@ ], "dependencies": { "typescript": "^5.7.0", - "@types/node": "^22.0.0", - "@elilee/mmap-native": "git+https://git.satitech.co.kr/sati-open/sati.n-api.mmap.git" + "@types/node": "^22.0.0" }, "scripts": { "prepare": "tsc -p tsconfig.json",