From 73c6c6d96b8767603ec4591f23e02830c2977071 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 15 Feb 2026 13:53:07 +0000 Subject: [PATCH 1/9] Initial plan From 09f070b43f3bdd73807da028267dc63cb9234f51 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 15 Feb 2026 13:58:50 +0000 Subject: [PATCH 2/9] Add clickable case URL hyperlinks to XLSX export Co-authored-by: jayhill <116148+jayhill@users.noreply.github.com> --- .../app/handlers/__tests__/export.test.ts | 50 +++++++++++++++++++ serverless/app/handlers/export.ts | 28 +++++++++++ 2 files changed, 78 insertions(+) diff --git a/serverless/app/handlers/__tests__/export.test.ts b/serverless/app/handlers/__tests__/export.test.ts index d8a94bf..8a1b933 100644 --- a/serverless/app/handlers/__tests__/export.test.ts +++ b/serverless/app/handlers/__tests__/export.test.ts @@ -19,6 +19,16 @@ jest.mock('xlsx', () => ({ book_new: jest.fn(), json_to_sheet: jest.fn().mockReturnValue({}), book_append_sheet: jest.fn(), + decode_range: jest.fn().mockImplementation((range: string) => { + const [, end] = range.split(':'); + const col = end.replace(/\d/g, ''); + const row = Number(end.replace(/[A-Z]/g, '')); + return { + s: { c: 0, r: 0 }, + e: { c: col.charCodeAt(0) - 65, r: row - 1 }, + }; + }), + encode_cell: jest.fn().mockImplementation(({ r, c }: { r: number; c: number }) => `${String.fromCharCode(65 + c)}${r + 1}`), }, write: jest.fn().mockReturnValue(Buffer.from('mock-excel-content')), })); @@ -31,6 +41,7 @@ describe('export handler', () => { beforeEach(() => { jest.clearAllMocks(); + process.env.PORTAL_CASE_URL = 'https://portal.example.com/search-results'; }); it('should return 400 if body is missing', async () => { @@ -68,6 +79,7 @@ describe('export handler', () => { }; const mockZipCase = { + caseId: 'case-id-123', fetchStatus: { status: 'complete' }, }; @@ -102,6 +114,7 @@ describe('export handler', () => { Disposition: 'Guilty', 'Disposition Date': '2023-02-01', 'Arresting Agency': 'Test Agency', + 'Case URL': 'https://portal.example.com/search-results/#/case-id-123', Notes: '', }, ]); @@ -220,4 +233,41 @@ describe('export handler', () => { }, }); }); + + it('should create clickable hyperlink for case URL cells', async () => { + const mockCaseNumbers = ['CASE123']; + const worksheet = { + '!ref': 'A1:K2', + A1: { v: 'Case Number' }, + B1: { v: 'Court Name' }, + C1: { v: 'Arrest Date' }, + D1: { v: 'Offense Description' }, + E1: { v: 'Offense Level' }, + F1: { v: 'Offense Date' }, + G1: { v: 'Disposition' }, + H1: { v: 'Disposition Date' }, + I1: { v: 'Arresting Agency' }, + J1: { v: 'Case URL' }, + K1: { v: 'Notes' }, + J2: { v: 'https://portal.example.com/search-results/#/case-id-123' }, + }; + (XLSX.utils.json_to_sheet as jest.Mock).mockReturnValueOnce(worksheet); + + const mockSummary = { charges: [] }; + const mockZipCase = { caseId: 'case-id-123', fetchStatus: { status: 'complete' } }; + (BatchHelper.getMany as jest.Mock).mockImplementation(async (keys: any[]) => { + const map = new Map(); + keys.forEach(key => { + if (key.PK === 'CASE#CASE123' && key.SK === 'SUMMARY') map.set(key, mockSummary); + if (key.PK === 'CASE#CASE123' && key.SK === 'ID') map.set(key, mockZipCase); + }); + return map; + }); + + await handler(mockEvent({ caseNumbers: mockCaseNumbers }), {} as any, {} as any); + + expect(worksheet.J2).toMatchObject({ + l: { Target: 'https://portal.example.com/search-results/#/case-id-123' }, + }); + }); }); diff --git a/serverless/app/handlers/export.ts b/serverless/app/handlers/export.ts index db12723..f873b01 100644 --- a/serverless/app/handlers/export.ts +++ b/serverless/app/handlers/export.ts @@ -17,6 +17,7 @@ interface ExportRow { Disposition: string; 'Disposition Date': string; 'Arresting Agency': string; + 'Case URL': string; Notes: string; } @@ -64,6 +65,8 @@ export const handler: APIGatewayProxyHandler = async event => { continue; } + const caseUrl = zipCase.caseId && process.env.PORTAL_CASE_URL ? `${process.env.PORTAL_CASE_URL}/#/${zipCase.caseId}` : ''; + // Handle failed cases and those without summaries if (!summary || zipCase.fetchStatus.status === 'failed') { rows.push({ @@ -76,6 +79,7 @@ export const handler: APIGatewayProxyHandler = async event => { 'Disposition': '', 'Disposition Date': '', 'Arresting Agency': '', + 'Case URL': caseUrl, Notes: 'Failed to load case data', }); continue; @@ -92,6 +96,7 @@ export const handler: APIGatewayProxyHandler = async event => { 'Disposition': '', 'Disposition Date': '', 'Arresting Agency': summary.filingAgency || '', + 'Case URL': caseUrl, Notes: 'No charges found', }); continue; @@ -118,6 +123,7 @@ export const handler: APIGatewayProxyHandler = async event => { 'Disposition': disposition ? disposition.description : '', 'Disposition Date': disposition ? disposition.date : '', 'Arresting Agency': charge.filingAgency || summary.filingAgency || '', + 'Case URL': caseUrl, Notes: '', }); } @@ -127,6 +133,28 @@ export const handler: APIGatewayProxyHandler = async event => { const wb = XLSX.utils.book_new(); const ws = XLSX.utils.json_to_sheet(rows); + const worksheetRange = ws['!ref'] ? XLSX.utils.decode_range(ws['!ref']) : null; + if (worksheetRange) { + let caseUrlColumn = -1; + for (let col = worksheetRange.s.c; col <= worksheetRange.e.c; col++) { + const headerCell = ws[XLSX.utils.encode_cell({ r: 0, c: col })]; + if (headerCell?.v === 'Case URL') { + caseUrlColumn = col; + break; + } + } + + if (caseUrlColumn >= 0) { + for (let row = 1; row <= worksheetRange.e.r; row++) { + const cellRef = XLSX.utils.encode_cell({ r: row, c: caseUrlColumn }); + const cell = ws[cellRef]; + if (cell?.v) { + (cell as XLSX.CellObject).l = { Target: String(cell.v) }; + } + } + } + } + // Auto-fit columns if (rows.length > 0) { const headers = Object.keys(rows[0]); From d14684445ffb986033696901ba7e7b2c6a561ce2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 15 Feb 2026 14:00:37 +0000 Subject: [PATCH 3/9] Harden export hyperlink test mocks Co-authored-by: jayhill <116148+jayhill@users.noreply.github.com> --- serverless/app/handlers/__tests__/export.test.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/serverless/app/handlers/__tests__/export.test.ts b/serverless/app/handlers/__tests__/export.test.ts index 8a1b933..44cc4b0 100644 --- a/serverless/app/handlers/__tests__/export.test.ts +++ b/serverless/app/handlers/__tests__/export.test.ts @@ -23,12 +23,22 @@ jest.mock('xlsx', () => ({ const [, end] = range.split(':'); const col = end.replace(/\d/g, ''); const row = Number(end.replace(/[A-Z]/g, '')); + const colIndex = col.split('').reduce((acc, char) => acc * 26 + (char.charCodeAt(0) - 64), 0) - 1; return { s: { c: 0, r: 0 }, - e: { c: col.charCodeAt(0) - 65, r: row - 1 }, + e: { c: colIndex, r: row - 1 }, }; }), - encode_cell: jest.fn().mockImplementation(({ r, c }: { r: number; c: number }) => `${String.fromCharCode(65 + c)}${r + 1}`), + encode_cell: jest.fn().mockImplementation(({ r, c }: { r: number; c: number }) => { + let col = ''; + let current = c + 1; + while (current > 0) { + const rem = (current - 1) % 26; + col = String.fromCharCode(65 + rem) + col; + current = Math.floor((current - 1) / 26); + } + return `${col}${r + 1}`; + }), }, write: jest.fn().mockReturnValue(Buffer.from('mock-excel-content')), })); From c610aacf4979d43d6e78b9cd39450a2f537382d3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 15 Feb 2026 15:22:16 +0000 Subject: [PATCH 4/9] Apply reviewer feedback to hyperlink case number cells Co-authored-by: jayhill <116148+jayhill@users.noreply.github.com> --- .../app/handlers/__tests__/export.test.ts | 12 ++++------ serverless/app/handlers/export.ts | 24 ++++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/serverless/app/handlers/__tests__/export.test.ts b/serverless/app/handlers/__tests__/export.test.ts index 44cc4b0..c5efa9b 100644 --- a/serverless/app/handlers/__tests__/export.test.ts +++ b/serverless/app/handlers/__tests__/export.test.ts @@ -124,7 +124,6 @@ describe('export handler', () => { Disposition: 'Guilty', 'Disposition Date': '2023-02-01', 'Arresting Agency': 'Test Agency', - 'Case URL': 'https://portal.example.com/search-results/#/case-id-123', Notes: '', }, ]); @@ -244,10 +243,10 @@ describe('export handler', () => { }); }); - it('should create clickable hyperlink for case URL cells', async () => { + it('should create clickable hyperlink for case number cells', async () => { const mockCaseNumbers = ['CASE123']; const worksheet = { - '!ref': 'A1:K2', + '!ref': 'A1:J2', A1: { v: 'Case Number' }, B1: { v: 'Court Name' }, C1: { v: 'Arrest Date' }, @@ -257,9 +256,8 @@ describe('export handler', () => { G1: { v: 'Disposition' }, H1: { v: 'Disposition Date' }, I1: { v: 'Arresting Agency' }, - J1: { v: 'Case URL' }, - K1: { v: 'Notes' }, - J2: { v: 'https://portal.example.com/search-results/#/case-id-123' }, + J1: { v: 'Notes' }, + A2: { v: 'CASE123' }, }; (XLSX.utils.json_to_sheet as jest.Mock).mockReturnValueOnce(worksheet); @@ -276,7 +274,7 @@ describe('export handler', () => { await handler(mockEvent({ caseNumbers: mockCaseNumbers }), {} as any, {} as any); - expect(worksheet.J2).toMatchObject({ + expect(worksheet.A2).toMatchObject({ l: { Target: 'https://portal.example.com/search-results/#/case-id-123' }, }); }); diff --git a/serverless/app/handlers/export.ts b/serverless/app/handlers/export.ts index f873b01..2c178ef 100644 --- a/serverless/app/handlers/export.ts +++ b/serverless/app/handlers/export.ts @@ -17,7 +17,6 @@ interface ExportRow { Disposition: string; 'Disposition Date': string; 'Arresting Agency': string; - 'Case URL': string; Notes: string; } @@ -48,6 +47,7 @@ export const handler: APIGatewayProxyHandler = async event => { const dataMap = await BatchHelper.getMany(allKeys); const rows: ExportRow[] = []; + const caseNumberToUrlMap = new Map(); for (const caseNumber of caseNumbers) { const summaryKey = Key.Case(caseNumber).SUMMARY; @@ -66,6 +66,9 @@ export const handler: APIGatewayProxyHandler = async event => { } const caseUrl = zipCase.caseId && process.env.PORTAL_CASE_URL ? `${process.env.PORTAL_CASE_URL}/#/${zipCase.caseId}` : ''; + if (caseUrl) { + caseNumberToUrlMap.set(caseNumber, caseUrl); + } // Handle failed cases and those without summaries if (!summary || zipCase.fetchStatus.status === 'failed') { @@ -79,7 +82,6 @@ export const handler: APIGatewayProxyHandler = async event => { 'Disposition': '', 'Disposition Date': '', 'Arresting Agency': '', - 'Case URL': caseUrl, Notes: 'Failed to load case data', }); continue; @@ -96,7 +98,6 @@ export const handler: APIGatewayProxyHandler = async event => { 'Disposition': '', 'Disposition Date': '', 'Arresting Agency': summary.filingAgency || '', - 'Case URL': caseUrl, Notes: 'No charges found', }); continue; @@ -123,7 +124,6 @@ export const handler: APIGatewayProxyHandler = async event => { 'Disposition': disposition ? disposition.description : '', 'Disposition Date': disposition ? disposition.date : '', 'Arresting Agency': charge.filingAgency || summary.filingAgency || '', - 'Case URL': caseUrl, Notes: '', }); } @@ -135,21 +135,23 @@ export const handler: APIGatewayProxyHandler = async event => { const worksheetRange = ws['!ref'] ? XLSX.utils.decode_range(ws['!ref']) : null; if (worksheetRange) { - let caseUrlColumn = -1; + let caseNumberColumn = -1; for (let col = worksheetRange.s.c; col <= worksheetRange.e.c; col++) { const headerCell = ws[XLSX.utils.encode_cell({ r: 0, c: col })]; - if (headerCell?.v === 'Case URL') { - caseUrlColumn = col; + if (headerCell?.v === 'Case Number') { + caseNumberColumn = col; break; } } - if (caseUrlColumn >= 0) { + if (caseNumberColumn >= 0) { for (let row = 1; row <= worksheetRange.e.r; row++) { - const cellRef = XLSX.utils.encode_cell({ r: row, c: caseUrlColumn }); + const cellRef = XLSX.utils.encode_cell({ r: row, c: caseNumberColumn }); const cell = ws[cellRef]; - if (cell?.v) { - (cell as XLSX.CellObject).l = { Target: String(cell.v) }; + const caseNumber = cell?.v ? String(cell.v) : ''; + const caseUrl = caseNumberToUrlMap.get(caseNumber); + if (caseUrl && cell) { + (cell as XLSX.CellObject).l = { Target: caseUrl }; } } } From d804010efac158506ee6f9924b17195e9e85ab21 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 15 Feb 2026 16:06:50 +0000 Subject: [PATCH 5/9] Apply explicit hyperlink styling for exported case numbers Co-authored-by: jayhill <116148+jayhill@users.noreply.github.com> --- serverless/app/handlers/__tests__/export.test.ts | 6 ++++++ serverless/app/handlers/export.ts | 11 ++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/serverless/app/handlers/__tests__/export.test.ts b/serverless/app/handlers/__tests__/export.test.ts index c5efa9b..4d34662 100644 --- a/serverless/app/handlers/__tests__/export.test.ts +++ b/serverless/app/handlers/__tests__/export.test.ts @@ -276,6 +276,12 @@ describe('export handler', () => { expect(worksheet.A2).toMatchObject({ l: { Target: 'https://portal.example.com/search-results/#/case-id-123' }, + s: { + font: { + color: { rgb: '0563C1' }, + underline: true, + }, + }, }); }); }); diff --git a/serverless/app/handlers/export.ts b/serverless/app/handlers/export.ts index 2c178ef..7714d70 100644 --- a/serverless/app/handlers/export.ts +++ b/serverless/app/handlers/export.ts @@ -151,7 +151,16 @@ export const handler: APIGatewayProxyHandler = async event => { const caseNumber = cell?.v ? String(cell.v) : ''; const caseUrl = caseNumberToUrlMap.get(caseNumber); if (caseUrl && cell) { - (cell as XLSX.CellObject).l = { Target: caseUrl }; + const caseNumberCell = cell as XLSX.CellObject; + caseNumberCell.l = { Target: caseUrl }; + caseNumberCell.s = { + ...caseNumberCell.s, + font: { + ...(caseNumberCell.s as { font?: object } | undefined)?.font, + color: { rgb: '0563C1' }, + underline: true, + }, + }; } } } From ff31b0cceabe62dbeab0c91b478e8caab118d677 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 15 Feb 2026 20:31:37 +0000 Subject: [PATCH 6/9] Use HYPERLINK formulas for exported case-number links Co-authored-by: jayhill <116148+jayhill@users.noreply.github.com> --- .../app/handlers/__tests__/export.test.ts | 38 ++++++++++++++++--- serverless/app/handlers/export.ts | 13 +++---- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/serverless/app/handlers/__tests__/export.test.ts b/serverless/app/handlers/__tests__/export.test.ts index 4d34662..83ef165 100644 --- a/serverless/app/handlers/__tests__/export.test.ts +++ b/serverless/app/handlers/__tests__/export.test.ts @@ -276,12 +276,38 @@ describe('export handler', () => { expect(worksheet.A2).toMatchObject({ l: { Target: 'https://portal.example.com/search-results/#/case-id-123' }, - s: { - font: { - color: { rgb: '0563C1' }, - underline: true, - }, - }, + f: 'HYPERLINK("https://portal.example.com/search-results/#/case-id-123","CASE123")', + t: 's', + v: 'CASE123', + }); + }); + + it('should escape quotes in hyperlink formula values', async () => { + const mockCaseNumbers = ['CASE"123']; + const worksheet = { + '!ref': 'A1:J2', + A1: { v: 'Case Number' }, + J1: { v: 'Notes' }, + A2: { v: 'CASE"123' }, + }; + (XLSX.utils.json_to_sheet as jest.Mock).mockReturnValueOnce(worksheet); + + const mockSummary = { charges: [] }; + const mockZipCase = { caseId: 'case"id-123', fetchStatus: { status: 'complete' } }; + (BatchHelper.getMany as jest.Mock).mockImplementation(async (keys: any[]) => { + const map = new Map(); + keys.forEach(key => { + if (key.PK === 'CASE#CASE"123' && key.SK === 'SUMMARY') map.set(key, mockSummary); + if (key.PK === 'CASE#CASE"123' && key.SK === 'ID') map.set(key, mockZipCase); + }); + return map; + }); + + await handler(mockEvent({ caseNumbers: mockCaseNumbers }), {} as any, {} as any); + + expect(worksheet.A2).toMatchObject({ + l: { Target: 'https://portal.example.com/search-results/#/case"id-123' }, + f: 'HYPERLINK("https://portal.example.com/search-results/#/case""id-123","CASE""123")', }); }); }); diff --git a/serverless/app/handlers/export.ts b/serverless/app/handlers/export.ts index 7714d70..1603b14 100644 --- a/serverless/app/handlers/export.ts +++ b/serverless/app/handlers/export.ts @@ -152,15 +152,12 @@ export const handler: APIGatewayProxyHandler = async event => { const caseUrl = caseNumberToUrlMap.get(caseNumber); if (caseUrl && cell) { const caseNumberCell = cell as XLSX.CellObject; + const escapedCaseUrl = caseUrl.replace(/"/g, '""'); + const escapedCaseNumber = caseNumber.replace(/"/g, '""'); caseNumberCell.l = { Target: caseUrl }; - caseNumberCell.s = { - ...caseNumberCell.s, - font: { - ...(caseNumberCell.s as { font?: object } | undefined)?.font, - color: { rgb: '0563C1' }, - underline: true, - }, - }; + caseNumberCell.f = `HYPERLINK("${escapedCaseUrl}","${escapedCaseNumber}")`; + caseNumberCell.t = 's'; + caseNumberCell.v = caseNumber; } } } From 6d481cc204d82fa80de21c34054220b1c192ee7d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 15 Feb 2026 20:44:04 +0000 Subject: [PATCH 7/9] Persist case hyperlink styling in XLSX output Co-authored-by: jayhill <116148+jayhill@users.noreply.github.com> --- serverless/app/handlers/__tests__/export.test.ts | 7 +++++++ serverless/app/handlers/export.ts | 12 +++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/serverless/app/handlers/__tests__/export.test.ts b/serverless/app/handlers/__tests__/export.test.ts index 83ef165..e4e6924 100644 --- a/serverless/app/handlers/__tests__/export.test.ts +++ b/serverless/app/handlers/__tests__/export.test.ts @@ -111,6 +111,7 @@ describe('export handler', () => { }, isBase64Encoded: true, }); + expect(XLSX.write).toHaveBeenCalledWith(expect.anything(), expect.objectContaining({ type: 'buffer', bookType: 'xlsx', cellStyles: true })); // Verify XLSX calls expect(XLSX.utils.json_to_sheet).toHaveBeenCalledWith([ @@ -279,6 +280,12 @@ describe('export handler', () => { f: 'HYPERLINK("https://portal.example.com/search-results/#/case-id-123","CASE123")', t: 's', v: 'CASE123', + s: { + font: { + color: { rgb: '0563C1' }, + underline: true, + }, + }, }); }); diff --git a/serverless/app/handlers/export.ts b/serverless/app/handlers/export.ts index 1603b14..36998ce 100644 --- a/serverless/app/handlers/export.ts +++ b/serverless/app/handlers/export.ts @@ -158,6 +158,16 @@ export const handler: APIGatewayProxyHandler = async event => { caseNumberCell.f = `HYPERLINK("${escapedCaseUrl}","${escapedCaseNumber}")`; caseNumberCell.t = 's'; caseNumberCell.v = caseNumber; + const existingStyle = (caseNumberCell.s as Record | undefined) || {}; + const existingFont = (existingStyle.font as Record | undefined) || {}; + caseNumberCell.s = { + ...existingStyle, + font: { + ...existingFont, + color: { rgb: '0563C1' }, + underline: true, + }, + }; } } } @@ -182,7 +192,7 @@ export const handler: APIGatewayProxyHandler = async event => { XLSX.utils.book_append_sheet(wb, ws, 'Cases'); // Generate buffer - const buffer = XLSX.write(wb, { type: 'buffer', bookType: 'xlsx' }); + const buffer = XLSX.write(wb, { type: 'buffer', bookType: 'xlsx', cellStyles: true }); const timestamp = new Date().toISOString().replace(/[-:]/g, '').replace('T', '-').split('.')[0]; const filename = `ZipCase-Export-${timestamp}.xlsx`; From 5d7356d334cc55f2293d87bec658e650cc615d58 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 15 Feb 2026 23:53:51 +0000 Subject: [PATCH 8/9] Use l-property hyperlinks for exported case numbers Co-authored-by: jayhill <116148+jayhill@users.noreply.github.com> --- .../app/handlers/__tests__/export.test.ts | 16 ++++++---------- serverless/app/handlers/export.ts | 18 +++--------------- 2 files changed, 9 insertions(+), 25 deletions(-) diff --git a/serverless/app/handlers/__tests__/export.test.ts b/serverless/app/handlers/__tests__/export.test.ts index e4e6924..7b1a27b 100644 --- a/serverless/app/handlers/__tests__/export.test.ts +++ b/serverless/app/handlers/__tests__/export.test.ts @@ -111,7 +111,7 @@ describe('export handler', () => { }, isBase64Encoded: true, }); - expect(XLSX.write).toHaveBeenCalledWith(expect.anything(), expect.objectContaining({ type: 'buffer', bookType: 'xlsx', cellStyles: true })); + expect(XLSX.write).toHaveBeenCalledWith(expect.anything(), expect.objectContaining({ type: 'buffer', bookType: 'xlsx' })); // Verify XLSX calls expect(XLSX.utils.json_to_sheet).toHaveBeenCalledWith([ @@ -277,19 +277,13 @@ describe('export handler', () => { expect(worksheet.A2).toMatchObject({ l: { Target: 'https://portal.example.com/search-results/#/case-id-123' }, - f: 'HYPERLINK("https://portal.example.com/search-results/#/case-id-123","CASE123")', t: 's', v: 'CASE123', - s: { - font: { - color: { rgb: '0563C1' }, - underline: true, - }, - }, }); + expect(worksheet.A2.f).toBeUndefined(); }); - it('should escape quotes in hyperlink formula values', async () => { + it('should keep text value and hyperlink relationship for quoted case numbers', async () => { const mockCaseNumbers = ['CASE"123']; const worksheet = { '!ref': 'A1:J2', @@ -314,7 +308,9 @@ describe('export handler', () => { expect(worksheet.A2).toMatchObject({ l: { Target: 'https://portal.example.com/search-results/#/case"id-123' }, - f: 'HYPERLINK("https://portal.example.com/search-results/#/case""id-123","CASE""123")', + t: 's', + v: 'CASE"123', }); + expect(worksheet.A2.f).toBeUndefined(); }); }); diff --git a/serverless/app/handlers/export.ts b/serverless/app/handlers/export.ts index 36998ce..1d0d8a2 100644 --- a/serverless/app/handlers/export.ts +++ b/serverless/app/handlers/export.ts @@ -152,22 +152,10 @@ export const handler: APIGatewayProxyHandler = async event => { const caseUrl = caseNumberToUrlMap.get(caseNumber); if (caseUrl && cell) { const caseNumberCell = cell as XLSX.CellObject; - const escapedCaseUrl = caseUrl.replace(/"/g, '""'); - const escapedCaseNumber = caseNumber.replace(/"/g, '""'); - caseNumberCell.l = { Target: caseUrl }; - caseNumberCell.f = `HYPERLINK("${escapedCaseUrl}","${escapedCaseNumber}")`; caseNumberCell.t = 's'; caseNumberCell.v = caseNumber; - const existingStyle = (caseNumberCell.s as Record | undefined) || {}; - const existingFont = (existingStyle.font as Record | undefined) || {}; - caseNumberCell.s = { - ...existingStyle, - font: { - ...existingFont, - color: { rgb: '0563C1' }, - underline: true, - }, - }; + delete caseNumberCell.f; + caseNumberCell.l = { Target: caseUrl }; } } } @@ -192,7 +180,7 @@ export const handler: APIGatewayProxyHandler = async event => { XLSX.utils.book_append_sheet(wb, ws, 'Cases'); // Generate buffer - const buffer = XLSX.write(wb, { type: 'buffer', bookType: 'xlsx', cellStyles: true }); + const buffer = XLSX.write(wb, { type: 'buffer', bookType: 'xlsx' }); const timestamp = new Date().toISOString().replace(/[-:]/g, '').replace('T', '-').split('.')[0]; const filename = `ZipCase-Export-${timestamp}.xlsx`; From 39ba96073bf5724427bf55d6f602c516ec7c9435 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Feb 2026 00:15:15 +0000 Subject: [PATCH 9/9] Switch case export workbook generation to exceljs Co-authored-by: jayhill <116148+jayhill@users.noreply.github.com> --- .../app/handlers/__tests__/export.test.ts | 109 +-- serverless/app/handlers/export.ts | 95 +- serverless/package-lock.json | 863 ++++++++++++++++-- serverless/package.json | 1 + 4 files changed, 877 insertions(+), 191 deletions(-) diff --git a/serverless/app/handlers/__tests__/export.test.ts b/serverless/app/handlers/__tests__/export.test.ts index 7b1a27b..e1ffa54 100644 --- a/serverless/app/handlers/__tests__/export.test.ts +++ b/serverless/app/handlers/__tests__/export.test.ts @@ -1,6 +1,6 @@ import { handler } from '../export'; import { BatchHelper, Key } from '../../../lib/StorageClient'; -import * as XLSX from 'xlsx'; +import ExcelJS from 'exceljs'; // Mock dependencies jest.mock('../../../lib/StorageClient', () => ({ @@ -14,33 +14,32 @@ jest.mock('../../../lib/StorageClient', () => ({ }), }, })); -jest.mock('xlsx', () => ({ - utils: { - book_new: jest.fn(), - json_to_sheet: jest.fn().mockReturnValue({}), - book_append_sheet: jest.fn(), - decode_range: jest.fn().mockImplementation((range: string) => { - const [, end] = range.split(':'); - const col = end.replace(/\d/g, ''); - const row = Number(end.replace(/[A-Z]/g, '')); - const colIndex = col.split('').reduce((acc, char) => acc * 26 + (char.charCodeAt(0) - 64), 0) - 1; - return { - s: { c: 0, r: 0 }, - e: { c: colIndex, r: row - 1 }, - }; - }), - encode_cell: jest.fn().mockImplementation(({ r, c }: { r: number; c: number }) => { - let col = ''; - let current = c + 1; - while (current > 0) { - const rem = (current - 1) % 26; - col = String.fromCharCode(65 + rem) + col; - current = Math.floor((current - 1) / 26); +const mockCells = new Map(); +const mockWorksheet = { + columns: [] as unknown[], + addRows: jest.fn(), + getRow: jest.fn((rowNumber: number) => ({ + getCell: jest.fn((columnNumber: number) => { + const key = `${rowNumber}:${columnNumber}`; + if (!mockCells.has(key)) { + mockCells.set(key, {}); } - return `${col}${r + 1}`; + return mockCells.get(key)!; }), + })), +}; +const writeBufferMock = jest.fn().mockResolvedValue(Buffer.from('mock-excel-content')); +const mockWorkbook = { + addWorksheet: jest.fn().mockReturnValue(mockWorksheet), + xlsx: { + writeBuffer: writeBufferMock, + }, +}; +jest.mock('exceljs', () => ({ + __esModule: true, + default: { + Workbook: jest.fn().mockImplementation(() => mockWorkbook), }, - write: jest.fn().mockReturnValue(Buffer.from('mock-excel-content')), })); describe('export handler', () => { @@ -51,6 +50,8 @@ describe('export handler', () => { beforeEach(() => { jest.clearAllMocks(); + mockCells.clear(); + mockWorksheet.columns = []; process.env.PORTAL_CASE_URL = 'https://portal.example.com/search-results'; }); @@ -111,10 +112,11 @@ describe('export handler', () => { }, isBase64Encoded: true, }); - expect(XLSX.write).toHaveBeenCalledWith(expect.anything(), expect.objectContaining({ type: 'buffer', bookType: 'xlsx' })); + expect(ExcelJS.Workbook).toHaveBeenCalledTimes(1); + expect(writeBufferMock).toHaveBeenCalledTimes(1); - // Verify XLSX calls - expect(XLSX.utils.json_to_sheet).toHaveBeenCalledWith([ + // Verify worksheet rows + expect(mockWorksheet.addRows).toHaveBeenCalledWith([ { 'Case Number': 'CASE123', 'Court Name': 'Test Court', @@ -147,7 +149,7 @@ describe('export handler', () => { await handler(mockEvent({ caseNumbers: mockCaseNumbers }), {} as any, {} as any); - expect(XLSX.utils.json_to_sheet).toHaveBeenCalledWith([ + expect(mockWorksheet.addRows).toHaveBeenCalledWith([ expect.objectContaining({ 'Case Number': 'CASE_FAILED', Notes: 'Failed to load case data', @@ -178,7 +180,7 @@ describe('export handler', () => { await handler(mockEvent({ caseNumbers: mockCaseNumbers }), {} as any, {} as any); - expect(XLSX.utils.json_to_sheet).toHaveBeenCalledWith([ + expect(mockWorksheet.addRows).toHaveBeenCalledWith([ expect.objectContaining({ 'Case Number': 'CASE_NO_CHARGES', Notes: 'No charges found', @@ -214,7 +216,7 @@ describe('export handler', () => { await handler(mockEvent({ caseNumbers: mockCaseNumbers }), {} as any, {} as any); - const calls = (XLSX.utils.json_to_sheet as jest.Mock).mock.calls[0][0]; + const calls = (mockWorksheet.addRows as jest.Mock).mock.calls[0][0]; const levels = calls.map((row: any) => row['Offense Level']); expect(levels).toEqual(['M1', '', 'GL M', 'T', 'INF']); @@ -246,21 +248,6 @@ describe('export handler', () => { it('should create clickable hyperlink for case number cells', async () => { const mockCaseNumbers = ['CASE123']; - const worksheet = { - '!ref': 'A1:J2', - A1: { v: 'Case Number' }, - B1: { v: 'Court Name' }, - C1: { v: 'Arrest Date' }, - D1: { v: 'Offense Description' }, - E1: { v: 'Offense Level' }, - F1: { v: 'Offense Date' }, - G1: { v: 'Disposition' }, - H1: { v: 'Disposition Date' }, - I1: { v: 'Arresting Agency' }, - J1: { v: 'Notes' }, - A2: { v: 'CASE123' }, - }; - (XLSX.utils.json_to_sheet as jest.Mock).mockReturnValueOnce(worksheet); const mockSummary = { charges: [] }; const mockZipCase = { caseId: 'case-id-123', fetchStatus: { status: 'complete' } }; @@ -275,23 +262,20 @@ describe('export handler', () => { await handler(mockEvent({ caseNumbers: mockCaseNumbers }), {} as any, {} as any); - expect(worksheet.A2).toMatchObject({ - l: { Target: 'https://portal.example.com/search-results/#/case-id-123' }, - t: 's', - v: 'CASE123', + expect(mockWorksheet.getRow).toHaveBeenCalledWith(2); + const caseNumberCell = mockCells.get('2:1'); + expect(caseNumberCell?.value).toEqual({ + text: 'CASE123', + hyperlink: 'https://portal.example.com/search-results/#/case-id-123', + }); + expect(caseNumberCell?.font).toMatchObject({ + color: { argb: 'FF0563C1' }, + underline: true, }); - expect(worksheet.A2.f).toBeUndefined(); }); it('should keep text value and hyperlink relationship for quoted case numbers', async () => { const mockCaseNumbers = ['CASE"123']; - const worksheet = { - '!ref': 'A1:J2', - A1: { v: 'Case Number' }, - J1: { v: 'Notes' }, - A2: { v: 'CASE"123' }, - }; - (XLSX.utils.json_to_sheet as jest.Mock).mockReturnValueOnce(worksheet); const mockSummary = { charges: [] }; const mockZipCase = { caseId: 'case"id-123', fetchStatus: { status: 'complete' } }; @@ -306,11 +290,10 @@ describe('export handler', () => { await handler(mockEvent({ caseNumbers: mockCaseNumbers }), {} as any, {} as any); - expect(worksheet.A2).toMatchObject({ - l: { Target: 'https://portal.example.com/search-results/#/case"id-123' }, - t: 's', - v: 'CASE"123', + const caseNumberCell = mockCells.get('2:1'); + expect(caseNumberCell?.value).toEqual({ + text: 'CASE"123', + hyperlink: 'https://portal.example.com/search-results/#/case"id-123', }); - expect(worksheet.A2.f).toBeUndefined(); }); }); diff --git a/serverless/app/handlers/export.ts b/serverless/app/handlers/export.ts index 1d0d8a2..0c65fa4 100644 --- a/serverless/app/handlers/export.ts +++ b/serverless/app/handlers/export.ts @@ -1,5 +1,5 @@ import { APIGatewayProxyHandler } from 'aws-lambda'; -import * as XLSX from 'xlsx'; +import ExcelJS from 'exceljs'; import { BatchHelper, Key } from '../../lib/StorageClient'; import { CaseSummary, Disposition, ZipCase } from '../../../shared/types'; @@ -130,57 +130,58 @@ export const handler: APIGatewayProxyHandler = async event => { } // Create workbook and worksheet - const wb = XLSX.utils.book_new(); - const ws = XLSX.utils.json_to_sheet(rows); - - const worksheetRange = ws['!ref'] ? XLSX.utils.decode_range(ws['!ref']) : null; - if (worksheetRange) { - let caseNumberColumn = -1; - for (let col = worksheetRange.s.c; col <= worksheetRange.e.c; col++) { - const headerCell = ws[XLSX.utils.encode_cell({ r: 0, c: col })]; - if (headerCell?.v === 'Case Number') { - caseNumberColumn = col; - break; - } - } - - if (caseNumberColumn >= 0) { - for (let row = 1; row <= worksheetRange.e.r; row++) { - const cellRef = XLSX.utils.encode_cell({ r: row, c: caseNumberColumn }); - const cell = ws[cellRef]; - const caseNumber = cell?.v ? String(cell.v) : ''; - const caseUrl = caseNumberToUrlMap.get(caseNumber); - if (caseUrl && cell) { - const caseNumberCell = cell as XLSX.CellObject; - caseNumberCell.t = 's'; - caseNumberCell.v = caseNumber; - delete caseNumberCell.f; - caseNumberCell.l = { Target: caseUrl }; - } + const wb = new ExcelJS.Workbook(); + const ws = wb.addWorksheet('Cases'); + + const headers: (keyof ExportRow)[] = [ + 'Case Number', + 'Court Name', + 'Arrest Date', + 'Offense Description', + 'Offense Level', + 'Offense Date', + 'Disposition', + 'Disposition Date', + 'Arresting Agency', + 'Notes', + ]; + + const colWidths = headers.map(key => { + let maxLength = key.length; + rows.forEach(row => { + const val = row[key]; + const len = val ? String(val).length : 0; + if (len > maxLength) maxLength = len; + }); + return Math.min(Math.max(maxLength + 2, 10), 50); + }); + + ws.columns = headers.map((header, idx) => ({ + header, + key: header, + width: colWidths[idx], + })); + ws.addRows(rows); + + const caseNumberColumn = headers.indexOf('Case Number') + 1; + if (caseNumberColumn > 0) { + rows.forEach((row, idx) => { + const caseNumber = row['Case Number']; + const caseUrl = caseNumberToUrlMap.get(caseNumber); + if (caseUrl) { + const caseNumberCell = ws.getRow(idx + 2).getCell(caseNumberColumn); + caseNumberCell.value = { text: caseNumber, hyperlink: caseUrl }; + caseNumberCell.font = { + ...(caseNumberCell.font || {}), + color: { argb: 'FF0563C1' }, + underline: true, + }; } - } - } - - // Auto-fit columns - if (rows.length > 0) { - const headers = Object.keys(rows[0]); - const colWidths = headers.map(key => { - let maxLength = key.length; - rows.forEach(row => { - const val = row[key as keyof ExportRow]; - const len = val ? String(val).length : 0; - if (len > maxLength) maxLength = len; - }); - // Cap the width at 50 to prevent massive columns, but ensure at least 10 - return { wch: Math.min(Math.max(maxLength + 2, 10), 50) }; }); - ws['!cols'] = colWidths; } - XLSX.utils.book_append_sheet(wb, ws, 'Cases'); - // Generate buffer - const buffer = XLSX.write(wb, { type: 'buffer', bookType: 'xlsx' }); + const buffer = Buffer.from(await wb.xlsx.writeBuffer()); const timestamp = new Date().toISOString().replace(/[-:]/g, '').replace('T', '-').split('.')[0]; const filename = `ZipCase-Export-${timestamp}.xlsx`; diff --git a/serverless/package-lock.json b/serverless/package-lock.json index 6f916f4..e3142ce 100644 --- a/serverless/package-lock.json +++ b/serverless/package-lock.json @@ -4,7 +4,6 @@ "requires": true, "packages": { "": { - "name": "serverless", "dependencies": { "@aws-sdk/client-api-gateway": "^3.543.0", "@aws-sdk/client-cloudwatch": "^3.782.0", @@ -20,6 +19,7 @@ "axios": "^1.12.1", "axios-cookiejar-support": "^5.0.5", "cheerio": "^1.0.0", + "exceljs": "^4.4.0", "humanparser": "^2.7.0", "mammoth": "^1.11.0", "pdf-parse": "^1.1.1", @@ -7870,6 +7870,7 @@ "integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.2", @@ -9020,6 +9021,47 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@fast-csv/format": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@fast-csv/format/-/format-4.3.5.tgz", + "integrity": "sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A==", + "license": "MIT", + "dependencies": { + "@types/node": "^14.0.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.isboolean": "^3.0.3", + "lodash.isequal": "^4.5.0", + "lodash.isfunction": "^3.0.9", + "lodash.isnil": "^4.0.0" + } + }, + "node_modules/@fast-csv/format/node_modules/@types/node": { + "version": "14.18.63", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", + "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", + "license": "MIT" + }, + "node_modules/@fast-csv/parse": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/@fast-csv/parse/-/parse-4.3.6.tgz", + "integrity": "sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA==", + "license": "MIT", + "dependencies": { + "@types/node": "^14.0.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.groupby": "^4.6.0", + "lodash.isfunction": "^3.0.9", + "lodash.isnil": "^4.0.0", + "lodash.isundefined": "^3.0.1", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/@fast-csv/parse/node_modules/@types/node": { + "version": "14.18.63", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", + "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", + "license": "MIT" + }, "node_modules/@hapi/accept": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/@hapi/accept/-/accept-6.0.3.tgz", @@ -9446,9 +9488,7 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, "license": "ISC", - "peer": true, "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -10209,10 +10249,8 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, "license": "MIT", "optional": true, - "peer": true, "engines": { "node": ">=14" } @@ -11150,6 +11188,7 @@ "integrity": "sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~6.20.0" } @@ -11218,6 +11257,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.29.1.tgz", "integrity": "sha512-zczrHVEqEaTwh12gWBIJWj8nx+ayDcCJs06yoNMY0kwjMWDM6+kppljY+BxWI06d2Ja+h4+WdufDcwMnnMEWmg==", "dev": true, + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.29.1", "@typescript-eslint/types": "8.29.1", @@ -11383,6 +11423,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -11525,7 +11566,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -11538,7 +11578,6 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -11561,6 +11600,102 @@ "node": ">= 8" } }, + "node_modules/archiver": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz", + "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", + "license": "MIT", + "dependencies": { + "archiver-utils": "^2.1.0", + "async": "^3.2.4", + "buffer-crc32": "^0.2.1", + "readable-stream": "^3.6.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^2.2.0", + "zip-stream": "^4.1.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "license": "MIT", + "dependencies": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/archiver-utils/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/archiver-utils/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/archiver-utils/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/archiver/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -11610,7 +11745,6 @@ "version": "3.2.6", "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "dev": true, "license": "MIT" }, "node_modules/asynckit": { @@ -11624,6 +11758,7 @@ "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==", "license": "MIT", + "peer": true, "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", @@ -11655,7 +11790,6 @@ "integrity": "sha512-6uBVsBZzkB3tCC8iyx59mCjQckhB8+GQrI9Cop8eC7ybIsvs/KtnNgEBfRMSEa7GqK2VBGUzgjNYMdPIfotyPA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "tunnel": "^0.0.6" } @@ -11823,7 +11957,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, "license": "MIT" }, "node_modules/base64-js": { @@ -11856,6 +11989,53 @@ "node": ">=10.0.0" } }, + "node_modules/big-integer": { + "version": "1.6.52", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", + "license": "Unlicense", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", + "license": "MIT", + "dependencies": { + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/bluebird": { "version": "3.4.7", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", @@ -11901,7 +12081,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -11940,6 +12119,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", @@ -11976,6 +12156,39 @@ "node-int64": "^0.4.0" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -11983,6 +12196,23 @@ "dev": true, "license": "MIT" }, + "node_modules/buffer-indexof-polyfill": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", + "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", + "engines": { + "node": ">=0.2.0" + } + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -12040,6 +12270,18 @@ ], "license": "CC-BY-4.0" }, + "node_modules/chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", + "license": "MIT/X11", + "dependencies": { + "traverse": ">=0.3.0 <0.4" + }, + "engines": { + "node": "*" + } + }, "node_modules/chalk": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", @@ -12163,7 +12405,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -12176,7 +12417,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, "license": "MIT" }, "node_modules/combined-stream": { @@ -12191,11 +12431,39 @@ "node": ">= 0.8" } }, + "node_modules/compress-commons": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz", + "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", + "license": "MIT", + "dependencies": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^4.0.2", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/compress-commons/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, "license": "MIT" }, "node_modules/convert-source-map": { @@ -12211,6 +12479,45 @@ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "license": "MIT" }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz", + "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", + "license": "MIT", + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^3.4.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/crc32-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/create-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", @@ -12290,7 +12597,6 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -12339,6 +12645,12 @@ "node": ">= 12" } }, + "node_modules/dayjs": { + "version": "1.11.19", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz", + "integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==", + "license": "MIT" + }, "node_modules/debug": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", @@ -12533,11 +12845,19 @@ "node": ">= 0.4" } }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "license": "BSD-3-Clause", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, "license": "MIT" }, "node_modules/ejs": { @@ -12580,7 +12900,6 @@ "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, "license": "MIT" }, "node_modules/encoding-sniffer": { @@ -12596,6 +12915,15 @@ "url": "https://github.com/fb55/encoding-sniffer?sponsor=1" } }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -12752,6 +13080,7 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -13050,6 +13379,49 @@ "node": ">=0.10.0" } }, + "node_modules/exceljs": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/exceljs/-/exceljs-4.4.0.tgz", + "integrity": "sha512-XctvKaEMaj1Ii9oDOqbW/6e1gXknSY4g/aLCDicOXqBE4M0nRWkUu0PTp++UPNzoFY12BNHMfs/VadKIS6llvg==", + "license": "MIT", + "dependencies": { + "archiver": "^5.0.0", + "dayjs": "^1.8.34", + "fast-csv": "^4.3.1", + "jszip": "^3.10.1", + "readable-stream": "^3.6.0", + "saxes": "^5.0.1", + "tmp": "^0.2.0", + "unzipper": "^0.10.11", + "uuid": "^8.3.0" + }, + "engines": { + "node": ">=8.3.0" + } + }, + "node_modules/exceljs/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/exceljs/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/execa": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", @@ -13100,6 +13472,19 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/fast-csv": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/fast-csv/-/fast-csv-4.3.6.tgz", + "integrity": "sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw==", + "license": "MIT", + "dependencies": { + "@fast-csv/format": "4.3.5", + "@fast-csv/parse": "4.3.6" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -13322,9 +13707,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "dev": true, "license": "ISC", - "peer": true, "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -13365,6 +13748,12 @@ "node": ">=12.20.0" } }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "license": "MIT" + }, "node_modules/fs-extra": { "version": "11.3.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", @@ -13384,7 +13773,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, "license": "ISC" }, "node_modules/fsevents": { @@ -13402,6 +13790,35 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/fstream/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -13533,9 +13950,7 @@ "version": "10.5.0", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", - "dev": true, "license": "ISC", - "peer": true, "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -13591,7 +14006,6 @@ "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==", - "dev": true, "license": "ISC" }, "node_modules/graphemer": { @@ -13754,6 +14168,26 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -13829,7 +14263,6 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -13908,7 +14341,6 @@ "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==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -14004,7 +14436,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, "license": "ISC" }, "node_modules/istanbul-lib-coverage": { @@ -14082,9 +14513,7 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, "license": "BlueOak-1.0.0", - "peer": true, "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -14187,6 +14616,7 @@ "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", @@ -15595,6 +16025,7 @@ "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 10.16.0" } @@ -15730,6 +16161,18 @@ "node": ">=6" } }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "license": "MIT", + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -15769,6 +16212,12 @@ "dev": true, "license": "MIT" }, + "node_modules/listenercount": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", + "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==", + "license": "ISC" + }, "node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -15782,6 +16231,73 @@ "node": ">=8" } }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "license": "MIT" + }, + "node_modules/lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", + "license": "MIT" + }, + "node_modules/lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", + "license": "MIT" + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "license": "MIT" + }, + "node_modules/lodash.groupby": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", + "integrity": "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", + "license": "MIT" + }, + "node_modules/lodash.isfunction": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", + "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==", + "license": "MIT" + }, + "node_modules/lodash.isnil": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz", + "integrity": "sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isundefined": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz", + "integrity": "sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==", + "license": "MIT" + }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -15795,6 +16311,18 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", + "license": "MIT" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "license": "MIT" + }, "node_modules/long-timeout": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/long-timeout/-/long-timeout-0.1.1.tgz", @@ -15817,9 +16345,7 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/luxon": { "version": "3.5.0", @@ -15974,7 +16500,6 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -15986,17 +16511,36 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/minipass": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, "license": "ISC", - "peer": true, "engines": { "node": ">=16 || 14 >=14.17" } }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, "node_modules/mnemonist": { "version": "0.38.3", "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.3.tgz", @@ -16123,7 +16667,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -16180,7 +16723,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -16348,9 +16890,7 @@ "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==", - "dev": true, - "license": "BlueOak-1.0.0", - "peer": true + "license": "BlueOak-1.0.0" }, "node_modules/pako": { "version": "1.0.11", @@ -16449,7 +16989,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -16466,9 +17005,7 @@ "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, "license": "BlueOak-1.0.0", - "peer": true, "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -16710,6 +17247,27 @@ "util-deprecate": "~1.0.1" } }, + "node_modules/readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.1.0" + } + }, + "node_modules/readdir-glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -16800,7 +17358,6 @@ "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "glob": "^10.3.7" }, @@ -16851,8 +17408,19 @@ "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", "dev": true, + "license": "ISC" + }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", "license": "ISC", - "peer": true + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } }, "node_modules/semver": { "version": "7.7.1", @@ -17396,7 +17964,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -17409,7 +17976,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -17419,7 +17985,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, "license": "ISC", "engines": { "node": ">=14" @@ -17584,7 +18149,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", @@ -17603,9 +18167,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -17619,9 +18181,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -17630,17 +18190,13 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT", - "peer": true + "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==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -17652,7 +18208,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -17669,9 +18224,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -17683,9 +18236,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -17764,6 +18315,36 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -17843,6 +18424,15 @@ "integrity": "sha512-NaQa1W76W2aCGjXybvnMYzGSM4x8fvG2AN/pla7qxcg0ZHbooOPhA8kctmOZUDfZyhDL27OGNbwAeig8P4p1vg==", "license": "MIT" }, + "node_modules/tmp": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", + "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -17868,6 +18458,7 @@ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", "license": "BSD-3-Clause", + "peer": true, "dependencies": { "tldts": "^6.1.32" }, @@ -17875,6 +18466,15 @@ "node": ">=16" } }, + "node_modules/traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", + "license": "MIT/X11", + "engines": { + "node": "*" + } + }, "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", @@ -17962,6 +18562,7 @@ "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -18032,7 +18633,6 @@ "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.6.11 <=0.7.0 || >=0.7.3" } @@ -18078,6 +18678,7 @@ "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -18119,6 +18720,7 @@ "resolved": "https://registry.npmjs.org/undici/-/undici-6.23.0.tgz", "integrity": "sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g==", "license": "MIT", + "peer": true, "engines": { "node": ">=18.17" } @@ -18140,6 +18742,24 @@ "node": ">= 10.0.0" } }, + "node_modules/unzipper": { + "version": "0.10.14", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.14.tgz", + "integrity": "sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==", + "license": "MIT", + "dependencies": { + "big-integer": "^1.6.17", + "binary": "~0.3.0", + "bluebird": "~3.4.1", + "buffer-indexof-polyfill": "~1.0.0", + "duplexer2": "~0.1.4", + "fstream": "^1.0.12", + "graceful-fs": "^4.2.2", + "listenercount": "~1.0.1", + "readable-stream": "~2.3.6", + "setimmediate": "~1.0.4" + } + }, "node_modules/update-browserslist-db": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", @@ -18293,7 +18913,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -18334,7 +18953,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", @@ -18353,9 +18971,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -18372,9 +18988,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -18383,9 +18997,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -18400,17 +19012,13 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT", - "peer": true + "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==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -18424,9 +19032,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -18438,7 +19044,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, "license": "ISC" }, "node_modules/write-file-atomic": { @@ -18502,7 +19107,6 @@ "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" @@ -18517,11 +19121,16 @@ "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=4.0" } }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "license": "MIT" + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -18561,6 +19170,98 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zip-stream": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", + "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", + "license": "MIT", + "dependencies": { + "archiver-utils": "^3.0.4", + "compress-commons": "^4.1.2", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/zip-stream/node_modules/archiver-utils": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz", + "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", + "license": "MIT", + "dependencies": { + "glob": "^7.2.3", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/zip-stream/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/zip-stream/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/zip-stream/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/zip-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } } } } diff --git a/serverless/package.json b/serverless/package.json index 1d9fff8..0ac04d6 100644 --- a/serverless/package.json +++ b/serverless/package.json @@ -36,6 +36,7 @@ "axios": "^1.12.1", "axios-cookiejar-support": "^5.0.5", "cheerio": "^1.0.0", + "exceljs": "^4.4.0", "humanparser": "^2.7.0", "mammoth": "^1.11.0", "pdf-parse": "^1.1.1",