From 8ab27a6721f153226c95dccd863740566c0ba3a4 Mon Sep 17 00:00:00 2001 From: Nathnael Date: Wed, 1 Jul 2026 06:19:07 +0000 Subject: [PATCH 01/20] feat: add expiration to invoice --- .../1830000000000-AddExpiredInvoiceStatus.ts | 27 ++++++++++ .../src/modules/billing/billing.service.ts | 52 +++++++++++++++++++ .../booking-batch.service.spec.ts | 1 + .../train-scheduling/booking-batch.service.ts | 21 ++++++++ .../train-scheduling.module.ts | 2 + packages/types/src/freight/index.ts | 2 + 6 files changed, 105 insertions(+) create mode 100644 apps/edr-freight-api/src/migrations/1830000000000-AddExpiredInvoiceStatus.ts diff --git a/apps/edr-freight-api/src/migrations/1830000000000-AddExpiredInvoiceStatus.ts b/apps/edr-freight-api/src/migrations/1830000000000-AddExpiredInvoiceStatus.ts new file mode 100644 index 000000000..e4b353b94 --- /dev/null +++ b/apps/edr-freight-api/src/migrations/1830000000000-AddExpiredInvoiceStatus.ts @@ -0,0 +1,27 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +/** + * Add the `EXPIRED` invoice status. An invoice expires when its source's pay + * window closes before settlement (e.g. a booking whose `paymentDeadline` + * lapses) — driven event-style from the domain via `BillingService.expirePayable`, + * which emits `${source}.invoice.expired`. Terminal and not settle-able (kept out + * of `OPEN_STATUSES`), so it is distinct from `CANCELLED` (manual void) and + * `OVERDUE` (still payable). + * + * Matches Freight.InvoiceStatus in packages/types. ADD VALUE only — additive and + * not referenced in this same transaction, so it is PG 12+ safe. + */ +export class AddExpiredInvoiceStatus1830000000000 implements MigrationInterface { + name = "AddExpiredInvoiceStatus1830000000000"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TYPE freight.invoices_status_enum ADD VALUE IF NOT EXISTS 'EXPIRED' AFTER 'REFUNDED';`, + ); + } + + public async down(): Promise { + // Postgres cannot drop individual enum values; EXPIRED is left on + // freight.invoices_status_enum (harmless, unused after down). + } +} diff --git a/apps/edr-freight-api/src/modules/billing/billing.service.ts b/apps/edr-freight-api/src/modules/billing/billing.service.ts index f1b58ad5e..c6112f825 100644 --- a/apps/edr-freight-api/src/modules/billing/billing.service.ts +++ b/apps/edr-freight-api/src/modules/billing/billing.service.ts @@ -628,6 +628,58 @@ export class BillingService { return this.markInvoiceAsRefunded(invoice.id, mg); } + /** + * Expire a source's currently-open invoice (its pay window closed before + * settlement), then emit `${source}.invoice.expired`. Resolves the open invoice + * and transitions it to EXPIRED — a terminal, non-payable status (kept out of + * `OPEN_STATUSES`). No-op (returns null) when the source has no open invoice + * (already paid/cancelled/expired). + * + * Pass the caller's transaction `manager` (e.g. the booking pay-window expiry in + * the batch engine) to enlist in its DB transaction. + */ + async expirePayable( + source: Freight.InvoiceSource, + sourceId: string, + manager?: EntityManager, + ): Promise { + const mg = manager ?? this.dataSource.manager; + const invoice = await mg.findOne(Invoice, { + where: { source, sourceId, status: In(OPEN_STATUSES) }, + order: { issuedAt: "DESC" }, + }); + if (!invoice) return null; + + return this.transition( + invoice.id, + Freight.InvoiceStatus.Expired, + "expired", + {}, + mg, + ); + } + + /** + * Sync a source's open invoice `dueAt` to its real pay-window deadline. The + * booking invoice is generated before the pay window opens (at booking + * creation/approval), so its printed due date is refreshed when the batch engine + * sets `paymentDeadline`. No-op when the source has no open invoice. + */ + async syncPayableDueDate( + source: Freight.InvoiceSource, + sourceId: string, + dueAt: Date, + manager?: EntityManager, + ): Promise { + const mg = manager ?? this.dataSource.manager; + const invoice = await mg.findOne(Invoice, { + where: { source, sourceId, status: In(OPEN_STATUSES) }, + order: { issuedAt: "DESC" }, + }); + if (!invoice) return; + await mg.update(Invoice, { id: invoice.id }, { dueAt }); + } + // ── Payment initiation & settlement (the gateway boundary) ─────────────────── /** diff --git a/apps/edr-freight-api/src/modules/train-scheduling/booking-batch.service.spec.ts b/apps/edr-freight-api/src/modules/train-scheduling/booking-batch.service.spec.ts index 5cd06091a..9e974b31e 100644 --- a/apps/edr-freight-api/src/modules/train-scheduling/booking-batch.service.spec.ts +++ b/apps/edr-freight-api/src/modules/train-scheduling/booking-batch.service.spec.ts @@ -110,6 +110,7 @@ describe('BookingBatchService — PAID reconcile', () => { notifier as never, { addTimeout: jest.fn(), deleteTimeout: jest.fn(), doesExist: jest.fn() } as never, trainSchedulingService as never, + { syncPayableDueDate: jest.fn(), expirePayable: jest.fn() } as never, ); }); diff --git a/apps/edr-freight-api/src/modules/train-scheduling/booking-batch.service.ts b/apps/edr-freight-api/src/modules/train-scheduling/booking-batch.service.ts index f31d8561d..9d9f9f396 100644 --- a/apps/edr-freight-api/src/modules/train-scheduling/booking-batch.service.ts +++ b/apps/edr-freight-api/src/modules/train-scheduling/booking-batch.service.ts @@ -8,7 +8,9 @@ import { import { InjectDataSource } from '@nestjs/typeorm'; import { Cron, SchedulerRegistry } from '@nestjs/schedule'; import { DataSource } from 'typeorm'; +import { Freight } from '@edr/types'; +import { BillingService } from '../billing/billing.service'; import { Booking } from '../bookings/entities/booking.entity'; import { BookingsRepository } from '../bookings/bookings.repository'; import { Locomotive } from '../locomotives/entities/locomotive.entity'; @@ -179,6 +181,7 @@ export class BookingBatchService implements OnModuleInit { private readonly notifier: BookingNotifierService, private readonly scheduler: SchedulerRegistry, private readonly trainSchedulingService: TrainSchedulingService, + private readonly billing: BillingService, ) {} /** On boot, reconcile OPEN route-days and re-arm settle timers. */ @@ -972,6 +975,13 @@ export class BookingBatchService implements OnModuleInit { paymentDeadline: deadline, } as never); booking.trainScheduleId = scheduleId; + // The invoice was generated at booking creation/approval, before this pay + // window opened — refresh its printed due date to the real deadline. + await this.billing.syncPayableDueDate( + Freight.InvoiceSource.Booking, + booking.id, + deadline, + ); await this.notifier.payNow(booking, deadline); } @@ -1018,6 +1028,10 @@ export class BookingBatchService implements OnModuleInit { selectedForBatchAt: null, } as never); booking.trainScheduleId = null; + // Pay window closed before settlement → expire the booking's open invoice too + // (emits `booking.invoice.expired`). Domain owns the reaction; billing stays + // source-agnostic. + await this.billing.expirePayable(Freight.InvoiceSource.Booking, booking.id); this.notifier.expired(booking); } @@ -1057,6 +1071,13 @@ export class BookingBatchService implements OnModuleInit { paymentDeadline: null, selectedForBatchAt: null, } as never); + // Displaced → EXPIRED: close its open invoice too, so a dead booking + // can't still be paid (mirrors `expire()`; enlisted in this txn). + await this.billing.expirePayable( + Freight.InvoiceSource.Booking, + victim.id, + manager, + ); }); this.notifier.displaced(victim); freed = this.add(freed, this.needFor(victim, wagonLengths)); diff --git a/apps/edr-freight-api/src/modules/train-scheduling/train-scheduling.module.ts b/apps/edr-freight-api/src/modules/train-scheduling/train-scheduling.module.ts index 9b8efd9e0..0a56865d5 100644 --- a/apps/edr-freight-api/src/modules/train-scheduling/train-scheduling.module.ts +++ b/apps/edr-freight-api/src/modules/train-scheduling/train-scheduling.module.ts @@ -1,6 +1,7 @@ import { Module, forwardRef } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; +import { BillingModule } from '../billing/billing.module'; import { BookingsModule } from '../bookings/bookings.module'; import { Container } from '../container-management/entities/container.entity'; import { LocomotivesModule } from '../locomotives/locomotives.module'; @@ -42,6 +43,7 @@ import { NotificationsModule } from '../notifications/notifications.module'; ImportDjiboutiOperation, ]), forwardRef(() => BookingsModule), + BillingModule, NotificationsModule, LocomotivesModule, WagonTypesModule, diff --git a/packages/types/src/freight/index.ts b/packages/types/src/freight/index.ts index 171a294fb..5cffecf70 100644 --- a/packages/types/src/freight/index.ts +++ b/packages/types/src/freight/index.ts @@ -140,6 +140,8 @@ export enum InvoiceStatus { Overdue = "OVERDUE", Cancelled = "CANCELLED", Refunded = "REFUNDED", + /** Pay window closed before settlement; terminal, cannot be paid. */ + Expired = "EXPIRED", } /** Originating subsystem an invoice bills for; namespaces invoice events. */ From 94982d3c5a181fe61ce043a78cbe83542a7324cf Mon Sep 17 00:00:00 2001 From: Nathnael Date: Wed, 1 Jul 2026 06:25:24 +0000 Subject: [PATCH 02/20] feat: setup pdf on the central billing --- .../src/modules/billing/billing.controller.ts | 25 ++++++++++- .../src/modules/billing/billing.service.ts | 42 +++++++++++++++--- .../billing/portal-billing.controller.ts | 43 ++++++++++++++++++- 3 files changed, 102 insertions(+), 8 deletions(-) diff --git a/apps/edr-freight-api/src/modules/billing/billing.controller.ts b/apps/edr-freight-api/src/modules/billing/billing.controller.ts index e954b7e1b..9a441ab65 100644 --- a/apps/edr-freight-api/src/modules/billing/billing.controller.ts +++ b/apps/edr-freight-api/src/modules/billing/billing.controller.ts @@ -1,5 +1,6 @@ -import { Controller, Get, Param, ParseUUIDPipe } from "@nestjs/common"; +import { Controller, Get, Param, ParseUUIDPipe, Res } from "@nestjs/common"; import { ApiOperation, ApiTags } from "@nestjs/swagger"; +import type { Response } from "express"; import { FreightAdmin } from "../../common/booking-guards"; import { BillingService } from "./billing.service"; @@ -21,4 +22,26 @@ export class BillingController { findById(@Param("id", ParseUUIDPipe) id: string) { return this.billingService.findById(id); } + + @Get("invoices/:id/document") + @ApiOperation({ summary: "Download the sealed invoice PDF" }) + async document(@Param("id", ParseUUIDPipe) id: string, @Res() res: Response) { + const { filename, buffer } = await this.billingService.document(id); + sendPdf(res, filename, buffer); + } + + @Get("invoices/:id/receipt") + @ApiOperation({ summary: "Download the sealed payment receipt PDF" }) + async receipt(@Param("id", ParseUUIDPipe) id: string, @Res() res: Response) { + const { filename, buffer } = await this.billingService.receipt(id); + sendPdf(res, filename, buffer); + } +} + +/** Stream a generated PDF as a file download. */ +export function sendPdf(res: Response, filename: string, buffer: Buffer): void { + res.setHeader("Content-Type", "application/pdf"); + res.setHeader("Content-Disposition", `attachment; filename="${filename}"`); + res.setHeader("Content-Length", buffer.length); + res.send(buffer); } diff --git a/apps/edr-freight-api/src/modules/billing/billing.service.ts b/apps/edr-freight-api/src/modules/billing/billing.service.ts index c6112f825..a83a5cca8 100644 --- a/apps/edr-freight-api/src/modules/billing/billing.service.ts +++ b/apps/edr-freight-api/src/modules/billing/billing.service.ts @@ -221,19 +221,33 @@ export class BillingService { } } - /** Every invoice billed to a company, newest first, with billing relations. */ - findByCompany(companyId: string): Promise { + /** + * Every invoice billed to a company, newest first, with billing relations. + * Optionally narrow to a single source record (e.g. a booking's invoices) via + * `{ source, sourceId }`. + */ + findByCompany( + companyId: string, + filter: { source?: string; sourceId?: string } = {}, + ): Promise { return this.invoices.findAll({ - where: { companyId }, + where: { + companyId, + ...(filter.source ? { source: filter.source } : {}), + ...(filter.sourceId ? { sourceId: filter.sourceId } : {}), + }, relations: { company: true, companyProfile: true }, order: { createdAt: "DESC" }, }); } /** Invoices for the signed-in customer; empty when they have no company. */ - async findForUser(userId: string): Promise { + async findForUser( + userId: string, + filter: { source?: string; sourceId?: string } = {}, + ): Promise { const companyId = await this.resolveCompanyId(userId); - return companyId ? this.findByCompany(companyId) : []; + return companyId ? this.findByCompany(companyId, filter) : []; } /** Company-scoped invoice detail (+ lines); 404 when not owned by the user. */ @@ -267,6 +281,24 @@ export class BillingService { ); } + /** Sealed invoice PDF for one of the customer's own invoices (ownership-checked). */ + async documentForUser( + id: string, + userId: string, + ): Promise<{ filename: string; buffer: Buffer }> { + await this.findByIdForUser(id, userId); + return this.document(id); + } + + /** Sealed receipt PDF for one of the customer's own invoices (ownership-checked). */ + async receiptForUser( + id: string, + userId: string, + ): Promise<{ filename: string; buffer: Buffer }> { + await this.findByIdForUser(id, userId); + return this.receipt(id); + } + // ── Generation ─────────────────────────────────────────────────────────────── /** `-YYYYMMDD-00001` — sequential per day & prefix, within the active transaction. */ diff --git a/apps/edr-freight-api/src/modules/billing/portal-billing.controller.ts b/apps/edr-freight-api/src/modules/billing/portal-billing.controller.ts index 5a007c320..94e917754 100644 --- a/apps/edr-freight-api/src/modules/billing/portal-billing.controller.ts +++ b/apps/edr-freight-api/src/modules/billing/portal-billing.controller.ts @@ -5,14 +5,18 @@ import { Param, ParseUUIDPipe, Post, + Query, + Res, } from "@nestjs/common"; import { ApiBearerAuth, ApiOperation, ApiTags } from "@nestjs/swagger"; +import type { Response } from "express"; import { CurrentUser } from "@edr/api-common"; import { type AuthUserPayload, resolveAuthUserId, } from "../../common/resolve-auth-user-id"; +import { sendPdf } from "./billing.controller"; import { BillingService } from "./billing.service"; import { PayInvoiceDto } from "./dto/pay-invoice.dto"; @@ -29,8 +33,15 @@ export class PortalBillingController { @Get("my-invoices") @ApiOperation({ summary: "List the signed-in customer's invoices" }) - findMine(@CurrentUser() user: AuthUserPayload) { - return this.billingService.findForUser(resolveAuthUserId(user)); + findMine( + @CurrentUser() user: AuthUserPayload, + @Query("source") source?: string, + @Query("sourceId") sourceId?: string, + ) { + return this.billingService.findForUser(resolveAuthUserId(user), { + source, + sourceId, + }); } @Get("my-invoices/:id") @@ -42,6 +53,34 @@ export class PortalBillingController { return this.billingService.findByIdForUser(id, resolveAuthUserId(user)); } + @Get("my-invoices/:id/document") + @ApiOperation({ summary: "Download one of the customer's invoice PDFs" }) + async document( + @Param("id", ParseUUIDPipe) id: string, + @CurrentUser() user: AuthUserPayload, + @Res() res: Response, + ) { + const { filename, buffer } = await this.billingService.documentForUser( + id, + resolveAuthUserId(user), + ); + sendPdf(res, filename, buffer); + } + + @Get("my-invoices/:id/receipt") + @ApiOperation({ summary: "Download one of the customer's payment receipt PDFs" }) + async receipt( + @Param("id", ParseUUIDPipe) id: string, + @CurrentUser() user: AuthUserPayload, + @Res() res: Response, + ) { + const { filename, buffer } = await this.billingService.receiptForUser( + id, + resolveAuthUserId(user), + ); + sendPdf(res, filename, buffer); + } + @Post("my-invoices/:id/pay") @ApiOperation({ summary: "Initiate payment for one of the customer's invoices" }) pay( From e5aab84f51b116484ee3ee21ef1ee46ccc9fc0aa Mon Sep 17 00:00:00 2001 From: Nathnael Date: Wed, 1 Jul 2026 06:56:58 +0000 Subject: [PATCH 03/20] feat: ui changes and pdf setup on the clients --- .../src/components/warehouses/warehousePdf.ts | 60 --- .../backoffice/src/hooks/useScrollToHash.ts | 30 ++ .../bookings/BookingRequestDetailPage.tsx | 13 +- .../warehouses/WarehouseInvoicesPage.tsx | 48 ++- .../portal/src/constants/URLS.ts | 10 + .../portal/src/hooks/useScrollToHash.ts | 30 ++ .../src/pages/billing/InvoiceDetailPage.tsx | 107 ++++- .../portal/src/pages/billing/invoice-ui.tsx | 1 + .../BookingDetailPage/ReadonlyBookingView.tsx | 24 +- .../components/BookingPaymentPanel.tsx | 370 ++++++++++++++++++ .../components/PaymentDeadlineCard.tsx | 151 ------- .../components/WarehousePaymentsSection.tsx | 156 ++++++++ .../BookingDetailPage/components/pricing.tsx | 119 +----- .../portal/src/services/invoices.service.ts | 27 ++ .../services/warehouse-invoices.service.ts | 54 +++ .../portal/src/utils/download.ts | 11 + 16 files changed, 857 insertions(+), 354 deletions(-) create mode 100644 apps/edr-freight-web/backoffice/src/hooks/useScrollToHash.ts create mode 100644 apps/edr-freight-web/portal/src/hooks/useScrollToHash.ts create mode 100644 apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/BookingPaymentPanel.tsx delete mode 100644 apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/PaymentDeadlineCard.tsx create mode 100644 apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/WarehousePaymentsSection.tsx create mode 100644 apps/edr-freight-web/portal/src/services/warehouse-invoices.service.ts create mode 100644 apps/edr-freight-web/portal/src/utils/download.ts diff --git a/apps/edr-freight-web/backoffice/src/components/warehouses/warehousePdf.ts b/apps/edr-freight-web/backoffice/src/components/warehouses/warehousePdf.ts index 8b526fb3d..39daf7b57 100644 --- a/apps/edr-freight-web/backoffice/src/components/warehouses/warehousePdf.ts +++ b/apps/edr-freight-web/backoffice/src/components/warehouses/warehousePdf.ts @@ -31,9 +31,6 @@ export interface WarehouseHandoverPdfContext { const escapePdfText = (value: string) => value.replace(/\\/g, '\\\\').replace(/\(/g, '\\(').replace(/\)/g, '\\)'); -const money = (amount: unknown, currency = 'USD') => - `${Number(amount ?? 0).toLocaleString()} ${currency === 'ETB' ? 'Birr (ETB)' : currency}`; - const fmtDate = (value: unknown) => { if (!value) return '-'; const date = new Date(value as string | Date); @@ -96,12 +93,6 @@ const textOp = ( color = '0 0 0', ) => `BT\n${color} rg\n/${bold ? 'F2' : 'F1'} ${size} Tf\n${x} ${y} Td\n(${escapePdfText(text)}) Tj\nET`; -const buildAuthorizationBand = (label: 'PAID' | 'CLEARED') => [ - lineOp(60, 242, 535, 242), - textOp('AUTHORIZED SEAL', 382, 218, 9, true, GREEN), - buildCircularSeal(452, 155, label), -]; - const buildWarehouseOfficerSealBand = () => [ lineOp(60, 218, 535, 218), textOp('WAREHOUSE OFFICER SEAL', 92, 194, 9, true, GREEN), @@ -146,57 +137,6 @@ function buildSimplePdf(lines: PdfLine[], rawOps: string[] = []): Blob { return new Blob([pdf], { type: 'application/pdf' }); } -export function buildWarehouseInvoicePdf(invoice: WarehouseFeeInvoice, kind: 'INVOICE' | 'RECEIPT') { - const paid = kind === 'RECEIPT' || invoice.status === 'PAID'; - const title = `Warehouse Fee ${kind === 'RECEIPT' ? 'Receipt' : 'Invoice'}`; - const bookingReference = firstText(invoice.bookingReference); - const customerName = firstText(invoice.customerName); - const inventoryReference = firstText(invoice.inventoryReference); - const inventoryInfo = firstText(invoice.inventoryInfo, invoice.containerNumber, invoice.cargoDescription); - const clearanceStatus = firstText( - invoice.clearanceStatus, - paid ? 'FEE PAID - READY FOR RELEASE' : 'PENDING PAYMENT', - ); - const lines: PdfLine[] = [ - { text: 'Ethio-Djibouti Railway S.C.', size: 12, bold: true, yGap: 0, align: 'center' }, - { text: title, size: 23, bold: true, yGap: 28, align: 'center' }, - { text: `Document No: ${invoice.invoiceNumber}`, size: 12, bold: true, yGap: 32, align: 'center' }, - { text: `Status: ${invoice.status.replace(/_/g, ' ')} Type: ${invoice.invoiceType.replace(/_/g, ' ')}`, align: 'center' }, - { text: `Booking Reference: ${bookingReference} Customer: ${customerName}`, align: 'center' }, - { text: `Inventory Reference: ${inventoryReference} Inventory Info: ${inventoryInfo}`, align: 'center' }, - { text: `Clearance: ${clearanceStatus}`, align: 'center' }, - { text: `Issued: ${fmtDate(invoice.issuedAt)} Paid At: ${fmtDate(invoice.paidAt)}`, align: 'center' }, - { text: 'ITEMS', size: 13, bold: true, yGap: 30, align: 'center' }, - ...(invoice.items ?? []).flatMap((item) => [ - { text: item.description, bold: true, align: 'center' as const }, - { - text: `${item.feeType.replace(/_/g, ' ')} | Qty ${Number(item.quantity ?? 0).toLocaleString()} | Rate ${money(item.unitRate, item.currency)} | Amount ${money(item.amount, item.currency)}`, - yGap: 13, - align: 'center' as const, - }, - ]), - { text: 'TOTALS', size: 13, bold: true, yGap: 30, align: 'center' }, - { text: `Subtotal: ${money(invoice.subtotalAmount, invoice.currency)}`, align: 'center' }, - { text: `Tax: ${money(invoice.taxAmount, invoice.currency)}`, align: 'center' }, - { text: `Total: ${money(invoice.totalAmount, invoice.currency)}`, bold: true, align: 'center' }, - { text: `Paid: ${money(invoice.paidAmount, invoice.currency)}`, align: 'center' }, - { text: `Balance: ${money(invoice.balanceAmount, invoice.currency)}`, bold: true, align: 'center' }, - ]; - const authorizationOps = [ - ...buildAuthorizationBand('PAID'), - textOp('Prepared by EDR warehouse finance', 72, 196, 10), - textOp('Finance officer name / signature / date:', 72, 164, 10), - lineOp(245, 162, 360, 162, '0 0 0'), - ]; - const invoiceOps = [ - lineOp(60, 242, 535, 242), - textOp('Prepared by EDR warehouse finance', 72, 196, 10), - textOp('Finance officer name / signature / date:', 72, 164, 10), - lineOp(245, 162, 360, 162, '0 0 0'), - ]; - return buildSimplePdf(lines, paid ? authorizationOps : invoiceOps); -} - const firstText = (...values: Array) => { for (const value of values) { if (value !== null && value !== undefined && String(value).trim()) return String(value); diff --git a/apps/edr-freight-web/backoffice/src/hooks/useScrollToHash.ts b/apps/edr-freight-web/backoffice/src/hooks/useScrollToHash.ts new file mode 100644 index 000000000..f381f49d5 --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/hooks/useScrollToHash.ts @@ -0,0 +1,30 @@ +import { useEffect } from "react"; +import { useLocation } from "react-router-dom"; + +/** + * Scroll to the element whose `id` matches the URL hash. Retries for a short + * window so it still lands on sections that mount after an async fetch (there is + * no router-level hash handling). Deep-link targets give a card an `id`. + */ +export function useScrollToHash(): void { + const { hash } = useLocation(); + + useEffect(() => { + if (!hash) return; + const id = decodeURIComponent(hash.slice(1)); + let tries = 0; + let timer: ReturnType; + + const tick = () => { + const el = document.getElementById(id); + if (el) { + el.scrollIntoView({ behavior: "smooth", block: "start" }); + return; + } + if (tries++ < 20) timer = setTimeout(tick, 100); + }; + + timer = setTimeout(tick, 100); + return () => clearTimeout(timer); + }, [hash]); +} diff --git a/apps/edr-freight-web/backoffice/src/pages/bookings/BookingRequestDetailPage.tsx b/apps/edr-freight-web/backoffice/src/pages/bookings/BookingRequestDetailPage.tsx index 75badc5b3..7a13888fe 100644 --- a/apps/edr-freight-web/backoffice/src/pages/bookings/BookingRequestDetailPage.tsx +++ b/apps/edr-freight-web/backoffice/src/pages/bookings/BookingRequestDetailPage.tsx @@ -50,6 +50,7 @@ import { useBookingDetail, useBookingMutations, } from "@/hooks/bookings/useBookings"; +import { useScrollToHash } from "@/hooks/useScrollToHash"; import toast from "react-hot-toast"; // Signature / generated-contract files are surfaced on the contract page, not @@ -65,6 +66,8 @@ export default function BookingRequestDetailPage() { const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); const [searchParams, setSearchParams] = useSearchParams(); + // Deep-link from a warehouse fee invoice → this booking's warehouse section. + useScrollToHash(); const { data: booking, isLoading, @@ -281,10 +284,12 @@ export default function BookingRequestDetailPage() { - + + + = { @@ -155,6 +156,7 @@ export default function WarehouseInvoicesPage() { function InvoiceDetailModal({ id, onClose }: { id: string | null; onClose: () => void }) { const { toast } = useToast(); + const navigate = useNavigate(); const { data: inv, isLoading } = useQuery( api.warehouses.invoice.queryOptions({ input: { id: id ?? '' }, @@ -172,13 +174,33 @@ function InvoiceDetailModal({ id, onClose }: { id: string | null; onClose: () => const canGateClear = inv?.status === 'PAID' && Boolean(inv.inventoryId); const downloadInvoicePdf = async (invoice: WarehouseFeeInvoice) => { - const blob = buildWarehouseInvoicePdf(invoice, 'INVOICE'); - openPdfBlob(blob, `warehouse-invoice-${invoice.invoiceNumber}.pdf`); + const pdfWindow = window.open('', '_blank'); + try { + const { data } = await warehouseService.downloadInvoiceDocument(invoice.id); + openPdfBlob(data, `warehouse-invoice-${invoice.invoiceNumber}.pdf`, pdfWindow); + } catch (error) { + pdfWindow?.close(); + toast({ + variant: 'destructive', + title: 'Download failed', + description: extractErrorMessage(error), + }); + } }; const downloadReceiptPdf = async (invoice: WarehouseFeeInvoice) => { - const blob = buildWarehouseInvoicePdf(invoice, 'RECEIPT'); - openPdfBlob(blob, `warehouse-receipt-${invoice.invoiceNumber}.pdf`); + const pdfWindow = window.open('', '_blank'); + try { + const { data } = await warehouseService.downloadInvoiceReceipt(invoice.id); + openPdfBlob(data, `warehouse-receipt-${invoice.invoiceNumber}.pdf`, pdfWindow); + } catch (error) { + pdfWindow?.close(); + toast({ + variant: 'destructive', + title: 'Download failed', + description: extractErrorMessage(error), + }); + } }; const getExitPaperContext = async (invoice: WarehouseFeeInvoice) => { @@ -366,6 +388,20 @@ function InvoiceDetailModal({ id, onClose }: { id: string | null; onClose: () => )} + {inv.bookingId && ( + + )} + )} - )} + {hasReceipt && ( + + )} + {payable && ( + + )} + {payMutation.isError && ( diff --git a/apps/edr-freight-web/portal/src/pages/billing/invoice-ui.tsx b/apps/edr-freight-web/portal/src/pages/billing/invoice-ui.tsx index 1e19b1c9a..3503fbc71 100644 --- a/apps/edr-freight-web/portal/src/pages/billing/invoice-ui.tsx +++ b/apps/edr-freight-web/portal/src/pages/billing/invoice-ui.tsx @@ -22,6 +22,7 @@ const STATUS_STYLE: Record< [Freight.InvoiceStatus.Overdue]: { label: "Overdue", bg: "#FDECEC", fg: "#C0392B" }, [Freight.InvoiceStatus.Cancelled]: { label: "Cancelled", bg: "#EEF2F6", fg: "#64748B" }, [Freight.InvoiceStatus.Refunded]: { label: "Refunded", bg: "#EAF1FB", fg: "#2563EB" }, + [Freight.InvoiceStatus.Expired]: { label: "Expired", bg: "#FBEAE7", fg: "#C0392B" }, }; export function InvoiceStatusBadge({ status }: { status: Freight.InvoiceStatus }) { diff --git a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/ReadonlyBookingView.tsx b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/ReadonlyBookingView.tsx index 065ee8385..7c2c2631c 100644 --- a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/ReadonlyBookingView.tsx +++ b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/ReadonlyBookingView.tsx @@ -24,19 +24,22 @@ import { ConsolidationPairedNotice, ConsolidationWaitingBanner, } from "./components/Notices"; +import { BookingPaymentPanel } from "./components/BookingPaymentPanel"; import { HeaderButton, PageHeader } from "./components/PageHeader"; -import { PaymentDeadlineCard } from "./components/PaymentDeadlineCard"; import { PaymentMethodModal } from "./components/PaymentMethodModal"; -import { PaymentCard } from "./components/pricing"; import { ScheduleCard } from "./components/ScheduleCard"; +import { WarehousePaymentsSection } from "./components/WarehousePaymentsSection"; import { ShipmentDetailsCard } from "./components/ShipmentDetailsCard"; import { ShipmentTrackingCard } from "./components/ShipmentTrackingCard"; import { StatusHero } from "./components/StatusHero"; import { SupportCard } from "./components/SupportCard"; import { fmtDate, isNegative, priceTotal } from "./utils"; +import { useScrollToHash } from "@/hooks/useScrollToHash"; export function ReadonlyBookingView({ booking }: { booking: Freight.IBooking }) { const navigate = useNavigate(); + // Deep-link support: e.g. /bookings/:id#warehouse-payments from an invoice. + useScrollToHash(); const status = booking.status as string; const [payModalOpen, setPayModalOpen] = useState(false); const { view, viewer } = useFileViewer(); @@ -164,6 +167,8 @@ export function ReadonlyBookingView({ booking }: { booking: Freight.IBooking }) + + {booking.files && booking.files.length > 0 && ( @@ -215,14 +220,13 @@ export function ReadonlyBookingView({ booking }: { booking: Freight.IBooking }) } right={ <> - {showCountdown && ( - setPayModalOpen(true)} - paying={payMutation.isPending} - /> - )} - + setPayModalOpen(true)} + paying={payMutation.isPending} + showCountdown={showCountdown} + /> ; + +// ── Pay-window countdown ───────────────────────────────────────────────────── + +interface Remaining { + days: number; + hours: number; + minutes: number; + seconds: number; + expired: boolean; +} + +function getRemaining(deadlineMs: number): Remaining { + const diff = deadlineMs - Date.now(); + if (diff <= 0) return { days: 0, hours: 0, minutes: 0, seconds: 0, expired: true }; + const total = Math.floor(diff / 1000); + return { + days: Math.floor(total / 86400), + hours: Math.floor((total % 86400) / 3600), + minutes: Math.floor((total % 3600) / 60), + seconds: total % 60, + expired: false, + }; +} + +function Segment({ value, label }: { value: number; label: string }) { + return ( + + + {String(value).padStart(2, "0")} + + + {label} + + + ); +} + +function Countdown({ + deadline, + onPay, + paying, +}: { + deadline: string; + onPay?: () => void; + paying?: boolean; +}) { + const deadlineMs = new Date(deadline).getTime(); + const [remaining, setRemaining] = useState(() => getRemaining(deadlineMs)); + + useEffect(() => { + setRemaining(getRemaining(deadlineMs)); + const interval = setInterval(() => { + const next = getRemaining(deadlineMs); + setRemaining(next); + if (next.expired) clearInterval(interval); + }, 1000); + return () => clearInterval(interval); + }, [deadlineMs]); + + if (remaining.expired) { + return ( + + The payment window has closed. Move this booking to another schedule or + contact support. + + ); + } + + return ( + <> + + + + + + + + Deadline:{" "} + {new Date(deadline).toLocaleString(undefined, { + month: "short", + day: "numeric", + hour: "2-digit", + minute: "2-digit", + })} + + {onPay && ( + + )} + + ); +} + +// ── Merged payment panel ───────────────────────────────────────────────────── + +/** + * One card covering the whole payment story for a booking: the live pay-window + * countdown (when open), the price breakdown, and the invoice(s) — each with a + * link to its detail page and a download. Replaces the separate deadline + + * breakdown cards. + */ +export function BookingPaymentPanel({ + booking, + pricing, + onPay, + paying, + showCountdown, +}: { + booking: Freight.IBooking; + pricing: Pricing; + onPay?: () => void; + paying?: boolean; + showCountdown?: boolean; +}) { + const navigate = useNavigate(); + const paid = booking.paymentStatus === "PAID"; + const isAdjusted = + booking.adjustedTotalAmount !== null && + booking.adjustedTotalAmount !== undefined; + const currency = pricing?.currency ?? booking.paymentCurrency; + const total = isAdjusted + ? `${Number(booking.adjustedTotalAmount).toLocaleString()} ${currency}` + : priceTotal(pricing); + const items = priceLineItems(pricing); + + const { data: invoices = [] } = useQuery({ + queryKey: ["booking-invoices", booking.id], + queryFn: () => invoicesService.listForSource("booking", booking.id), + }); + // The invoice worth a prominent "Download" — the first issued one, else any. + const primary = + invoices.find((inv) => inv.status !== "DRAFT") ?? invoices[0]; + const primaryPaid = primary ? Number(primary.paidAmount) > 0 : false; + + const downloadInvoice = async (inv: PortalInvoice) => { + try { + saveBlob( + await invoicesService.downloadDocument(inv.id), + `invoice-${inv.invoiceNumber}.pdf`, + ); + } catch { + toast.error("Invoice PDF isn't ready yet. Contact EDR if this persists."); + } + }; + + const downloadReceipt = async (inv: PortalInvoice) => { + try { + saveBlob( + await invoicesService.downloadReceipt(inv.id), + `receipt-${inv.invoiceNumber}.pdf`, + ); + } catch { + toast.error("Receipt isn't available yet."); + } + }; + + return ( + + + Payment + + {paid ? : showCountdown ? : null} + {paid + ? "Paid" + : showCountdown + ? "Pay window open" + : (booking.paymentStatus?.replace(/_/g, " ") ?? "Pending")} + + + + {showCountdown && booking.paymentDeadline && ( + + + + + )} + + + + {total} + + {isAdjusted && ( + + Adjusted by EDR + + )} + {isAdjusted && booking.adjustmentReason && ( + + {booking.adjustmentReason} + + )} + {paid && ( + + Paid · {fmtDate(booking.updatedAt)} + + )} + + + {items.length > 0 && ( + <> + + + {items.map((it) => ( + + + {it.label} + + + {it.value} + + + ))} + + + + {isAdjusted ? "Adjusted total" : "Total"} + + + {total} + + + + )} + + {invoices.length > 0 && ( + <> + + + Invoices + + {invoices.length} + + + + {invoices.map((inv) => ( + + + navigate(`/billing/${inv.id}`)} + > + {inv.invoiceNumber} + + + {titleCase(inv.type)} + + + + + downloadInvoice(inv)} + > + + + + + ))} + + + )} + + {primary && ( + + )} + {primary && primaryPaid && ( + + )} + + ); +} diff --git a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/PaymentDeadlineCard.tsx b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/PaymentDeadlineCard.tsx deleted file mode 100644 index 54f900ab5..000000000 --- a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/PaymentDeadlineCard.tsx +++ /dev/null @@ -1,151 +0,0 @@ -import { Box, Button, Group, Stack, Text } from "@mantine/core"; -import { CreditCard, Timer } from "lucide-react"; -import { useEffect, useState } from "react"; - -import { CardTitle, SectionCard } from "./layout"; - -interface Remaining { - days: number; - hours: number; - minutes: number; - seconds: number; - expired: boolean; -} - -function getRemaining(deadlineMs: number): Remaining { - const diff = deadlineMs - Date.now(); - if (diff <= 0) { - return { days: 0, hours: 0, minutes: 0, seconds: 0, expired: true }; - } - const totalSeconds = Math.floor(diff / 1000); - return { - days: Math.floor(totalSeconds / 86400), - hours: Math.floor((totalSeconds % 86400) / 3600), - minutes: Math.floor((totalSeconds % 3600) / 60), - seconds: totalSeconds % 60, - expired: false, - }; -} - -function Segment({ value, label }: { value: number; label: string }) { - return ( - - - {String(value).padStart(2, "0")} - - - {label} - - - ); -} - -export function PaymentDeadlineCard({ - paymentDeadline, - onPay, - paying, -}: { - /** ISO timestamp marking the end of the pay window. */ - paymentDeadline: string; - onPay?: () => void; - paying?: boolean; -}) { - const deadlineMs = new Date(paymentDeadline).getTime(); - const [remaining, setRemaining] = useState(() => getRemaining(deadlineMs)); - - useEffect(() => { - setRemaining(getRemaining(deadlineMs)); - const interval = setInterval(() => { - const next = getRemaining(deadlineMs); - setRemaining(next); - if (next.expired) clearInterval(interval); - }, 1000); - return () => clearInterval(interval); - }, [deadlineMs]); - - const accentBg = remaining.expired ? "#FBEAE7" : "#FEF6E6"; - const accentFg = remaining.expired ? "#C0392B" : "#B07D14"; - - return ( - - - Payment deadline - - - {remaining.expired ? "Expired" : "Pay window open"} - - - - {remaining.expired ? ( - - The payment window has closed. Move this booking to another schedule or - contact support. - - ) : ( - <> - - - - - - - - Complete payment before the window closes to secure your slot. - - {onPay && ( - - )} - - )} - - - - Deadline:{" "} - {new Date(paymentDeadline).toLocaleString(undefined, { - month: "short", - day: "numeric", - hour: "2-digit", - minute: "2-digit", - })} - - - ); -} diff --git a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/WarehousePaymentsSection.tsx b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/WarehousePaymentsSection.tsx new file mode 100644 index 000000000..146e31c1e --- /dev/null +++ b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/WarehousePaymentsSection.tsx @@ -0,0 +1,156 @@ +import { ActionIcon, Box, Group, Stack, Text } from "@mantine/core"; +import { useQuery } from "@tanstack/react-query"; +import { Download, Receipt } from "lucide-react"; +import toast from "react-hot-toast"; + +import { + warehouseInvoicesService, + type PortalWarehouseInvoice, +} from "@/services/warehouse-invoices.service"; +import { saveBlob } from "@/utils/download"; + +import { CardTitle, SectionCard } from "./layout"; + +const money = (amount: number | string | null | undefined, currency: string) => + `${Number(amount ?? 0).toLocaleString()} ${currency}`; + +const STATUS_STYLE: Record = { + DRAFT: { bg: "#EEF2F6", fg: "#64748B" }, + ISSUED: { bg: "#FEF3E2", fg: "#B45309" }, + PARTIALLY_PAID: { bg: "#FEF9E7", fg: "#A16207" }, + PAID: { bg: "#E6F7EF", fg: "#0A6F4D" }, + CANCELLED: { bg: "#EEF2F6", fg: "#64748B" }, +}; + +function StatusPill({ status }: { status: string }) { + const s = STATUS_STYLE[status] ?? { bg: "#EEF2F6", fg: "#64748B" }; + return ( + + {status.replace(/_/g, " ")} + + ); +} + +/** + * Warehouse fee invoices linked to this booking — display + PDF download only. + * Paying them online is tracked separately (in-system demurrage/storage + * payment). Renders nothing when the booking has no warehouse fees. Carries + * `id="warehouse-payments"` so the invoice detail page can deep-link here. + */ +export function WarehousePaymentsSection({ bookingId }: { bookingId: string }) { + const { data: invoices = [] } = useQuery({ + queryKey: ["booking-warehouse-invoices", bookingId], + queryFn: () => warehouseInvoicesService.listForBooking(bookingId), + }); + + if (invoices.length === 0) return null; + + const download = async (inv: PortalWarehouseInvoice) => { + try { + saveBlob( + await warehouseInvoicesService.downloadDocument(inv.id), + `warehouse-invoice-${inv.invoiceNumber}.pdf`, + ); + } catch { + toast.error("Warehouse invoice PDF isn't ready yet."); + } + }; + + const downloadReceipt = async (inv: PortalWarehouseInvoice) => { + try { + saveBlob( + await warehouseInvoicesService.downloadReceipt(inv.id), + `warehouse-receipt-${inv.invoiceNumber}.pdf`, + ); + } catch { + toast.error("Receipt isn't available yet."); + } + }; + + return ( + + + Warehouse payments + + {invoices.length} {invoices.length === 1 ? "invoice" : "invoices"} + + + + {invoices.map((inv) => { + const detail = [ + inv.invoiceType?.replace(/_/g, " "), + inv.cargoDescription ?? + inv.containerNumber ?? + inv.inventoryReference ?? + undefined, + ] + .filter(Boolean) + .join(" · "); + return ( + + + + + {inv.invoiceNumber} + + + + {detail && ( + + {detail} + + )} + + Total {money(inv.totalAmount, inv.currency)} · Balance{" "} + {money(inv.balanceAmount, inv.currency)} + + + + download(inv)} + > + + + {Number(inv.paidAmount) > 0 && ( + downloadReceipt(inv)} + > + + + )} + + + ); + })} + + + ); +} diff --git a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/pricing.tsx b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/pricing.tsx index 93d843065..8c4ab9bcb 100644 --- a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/pricing.tsx +++ b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/pricing.tsx @@ -1,9 +1,7 @@ import { Box, Group, Stack, Text } from "@mantine/core"; -import { CheckCircle2, Clock } from "lucide-react"; +import { Clock } from "lucide-react"; -import type { Freight } from "@edr/types"; - -import { fmtDate, priceLineItems, priceTotal, type Pricing } from "../utils"; +import { priceLineItems, priceTotal, type Pricing } from "../utils"; import { CardTitle, SectionCard } from "./layout"; function LineItems({ pricing }: { pricing: Pricing }) { @@ -107,113 +105,6 @@ export function EstimateCard({ ); } -export function PaymentCard({ - booking, - pricing, -}: { - booking: Freight.IBooking; - pricing: Pricing; -}) { - const paid = booking.paymentStatus === "PAID"; - // Customer sees the grand total plus the price breakdown that makes it up. - // A staff adjustment, when present, overrides the computed total and is - // flagged with an "Adjusted by EDR" badge. - const isAdjusted = - booking.adjustedTotalAmount !== null && - booking.adjustedTotalAmount !== undefined; - const currency = pricing?.currency ?? booking.paymentCurrency; - const total = isAdjusted - ? `${Number(booking.adjustedTotalAmount).toLocaleString()} ${currency}` - : priceTotal(pricing); - const hasItems = priceLineItems(pricing).length > 0; - - return ( - - - Payment - - {paid && } - {paid - ? "Paid" - : (booking.paymentStatus?.replace(/_/g, " ") ?? "Pending")} - - - - - {total} - - {isAdjusted && ( - - Adjusted by EDR - - )} - {isAdjusted && booking.adjustmentReason && ( - - {booking.adjustmentReason} - - )} - {paid && ( - - Paid · {fmtDate(booking.updatedAt)} - - )} - - {hasItems && ( - <> - - - - - {isAdjusted ? "Adjusted total" : "Total"} - - - {total} - - - - )} - {/* */} - - ); -} +// The booking payment card (countdown + breakdown + invoices + download) now +// lives in ./BookingPaymentPanel. EstimateCard above stays for the draft and +// changes-requested views, which only show an estimate. diff --git a/apps/edr-freight-web/portal/src/services/invoices.service.ts b/apps/edr-freight-web/portal/src/services/invoices.service.ts index 99b1d0dee..2ee18ec4e 100644 --- a/apps/edr-freight-web/portal/src/services/invoices.service.ts +++ b/apps/edr-freight-web/portal/src/services/invoices.service.ts @@ -29,12 +29,39 @@ export const invoicesService = { return data.data ?? data; }, + /** The customer's invoices for one source record (e.g. a booking). */ + listForSource: async ( + source: string, + sourceId: string, + ): Promise => { + const { data } = await client.get(B.MY_INVOICES, { + params: { source, sourceId }, + }); + return data.data ?? data; + }, + /** One of the customer's invoices, with its line items. */ get: async (id: string): Promise => { const { data } = await client.get(B.MY_INVOICE_BY_ID(id)); return data.data ?? data; }, + /** The sealed invoice PDF for one of the customer's invoices. */ + downloadDocument: async (id: string): Promise => { + const { data } = await client.get(B.MY_INVOICE_DOCUMENT(id), { + responseType: "blob", + }); + return data; + }, + + /** The sealed payment-receipt PDF (available once paid). */ + downloadReceipt: async (id: string): Promise => { + const { data } = await client.get(B.MY_INVOICE_RECEIPT(id), { + responseType: "blob", + }); + return data; + }, + /** Initiate gateway payment for an open invoice; returns the client action. */ pay: async ( id: string, diff --git a/apps/edr-freight-web/portal/src/services/warehouse-invoices.service.ts b/apps/edr-freight-web/portal/src/services/warehouse-invoices.service.ts new file mode 100644 index 000000000..f1fa4e841 --- /dev/null +++ b/apps/edr-freight-web/portal/src/services/warehouse-invoices.service.ts @@ -0,0 +1,54 @@ +import { URL_CONSTANTS } from "@/constants/URLS"; +import { client } from "../utils/api"; + +const W = URL_CONSTANTS.WAREHOUSE_INVOICES; + +/** + * A warehouse fee invoice as the freight API projects it for the customer + * (the historical `WarehouseFeeInvoice` view shape — a subset is used here). + */ +export interface PortalWarehouseInvoice { + id: string; + invoiceNumber: string; + invoiceType: string; + status: string; + currency: string; + totalAmount: number | string; + paidAmount: number | string; + balanceAmount: number | string; + issuedAt?: string | null; + dueDate?: string | null; + paidAt?: string | null; + bookingId?: string | null; + inventoryId?: string | null; + bookingReference?: string | null; + inventoryReference?: string | null; + cargoDescription?: string | null; + containerNumber?: string | null; +} + +export const warehouseInvoicesService = { + /** Warehouse fee invoices linked to a booking (via its inventory items). */ + listForBooking: async (bookingId: string): Promise => { + const { data } = await client.get(W.FOR_BOOKING(bookingId)); + return data.data ?? data; + }, + + /** A single warehouse fee invoice (carries `bookingId` for source linking). */ + get: async (id: string): Promise => { + const { data } = await client.get(W.BY_ID(id)); + return data.data ?? data; + }, + + /** The sealed warehouse fee invoice PDF. */ + downloadDocument: async (id: string): Promise => { + const { data } = await client.get(W.DOCUMENT(id), { responseType: "blob" }); + return data; + }, + + /** The sealed warehouse fee payment receipt PDF (available once paid). */ + downloadReceipt: async (id: string): Promise => { + const { data } = await client.get(W.RECEIPT(id), { responseType: "blob" }); + return data; + }, +}; diff --git a/apps/edr-freight-web/portal/src/utils/download.ts b/apps/edr-freight-web/portal/src/utils/download.ts new file mode 100644 index 000000000..594513566 --- /dev/null +++ b/apps/edr-freight-web/portal/src/utils/download.ts @@ -0,0 +1,11 @@ +/** Trigger a browser download of a Blob under `filename`. */ +export function saveBlob(blob: Blob, filename: string): void { + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = filename; + document.body.appendChild(a); + a.click(); + a.remove(); + URL.revokeObjectURL(url); +} From 8705b9840709eaea392ce9b52f4cecf8a797bb64 Mon Sep 17 00:00:00 2001 From: Abubeker Yasin Date: Wed, 1 Jul 2026 12:08:05 +0300 Subject: [PATCH 04/20] Update dmoney-webhook.service.ts --- .../modules/webhooks/handlers/dmoney-webhook.service.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/edr-payment-api/src/modules/webhooks/handlers/dmoney-webhook.service.ts b/apps/edr-payment-api/src/modules/webhooks/handlers/dmoney-webhook.service.ts index 163f01107..4e1971293 100644 --- a/apps/edr-payment-api/src/modules/webhooks/handlers/dmoney-webhook.service.ts +++ b/apps/edr-payment-api/src/modules/webhooks/handlers/dmoney-webhook.service.ts @@ -10,9 +10,12 @@ export class DMoneyWebhookService { ) {} async handle(payload: DMoneyWebhookPayload): Promise { - const signatureValid = this.provider.verifyWebhookSignature( - payload as unknown as Record, - ); + // TODO: re-enable D-Money public-key signature verification — skipped for now. + // D-Money's onboarding pack only provides the merchant keypair (3072-bit); callbacks + // are signed with their separate platform notification key (4096-bit), which we don't + // have yet, so verifyWebhookSignature can never pass. Re-enable once that key is supplied. + const signatureValid = true; + const mapped = this.provider.mapWebhookTradeStatus(payload.trade_status); const providerTxnId = payload.transId ?? payload.payment_order_id; From f831c164e7f57860ad8909a1092fe8048ad754ed Mon Sep 17 00:00:00 2001 From: Abubeker Yasin Date: Wed, 1 Jul 2026 12:18:43 +0300 Subject: [PATCH 05/20] Update dmoney.provider.ts --- .../payment-providers/src/providers/dmoney/dmoney.provider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/payment-providers/src/providers/dmoney/dmoney.provider.ts b/packages/payment-providers/src/providers/dmoney/dmoney.provider.ts index 15a2e3a62..91e33d2da 100644 --- a/packages/payment-providers/src/providers/dmoney/dmoney.provider.ts +++ b/packages/payment-providers/src/providers/dmoney/dmoney.provider.ts @@ -211,7 +211,7 @@ export class DMoneyProvider implements PaymentProvider { merch_order_id: input.merchantOrderId, trade_type: "WebCheckout" as const, business_type: "OnlineMerchant" as const, - title: `${input.orderRef}`, + title: "EDR booking payment", total_amount: totalAmount, // Charge the currency the caller already converted to; never relabel it provider-side. trans_currency: input.currency, From c88c5ee4509bfd368504bfd0c6c998588a2fc0b5 Mon Sep 17 00:00:00 2001 From: ghost2023 Date: Wed, 1 Jul 2026 12:26:37 +0300 Subject: [PATCH 06/20] chore: setup script --- apps/edr-freight-api/package.json | 7 +- .../edr-freight-api/src/scripts/cmds/index.ts | 7 + .../edr-freight-api/src/scripts/cmds/types.ts | 6 + apps/edr-freight-api/src/scripts/main.ts | 30 + pnpm-lock.yaml | 1020 +++++++++++++++-- 5 files changed, 972 insertions(+), 98 deletions(-) create mode 100644 apps/edr-freight-api/src/scripts/cmds/index.ts create mode 100644 apps/edr-freight-api/src/scripts/cmds/types.ts create mode 100644 apps/edr-freight-api/src/scripts/main.ts diff --git a/apps/edr-freight-api/package.json b/apps/edr-freight-api/package.json index 9edf388b9..b24cf6c83 100644 --- a/apps/edr-freight-api/package.json +++ b/apps/edr-freight-api/package.json @@ -32,7 +32,8 @@ "iam:migration:revert": "pnpm run iam:typeorm:cli migration:revert", "iam:migration:show": "pnpm run iam:typeorm:cli migration:show", "iam:seed:run": "cross-env APP_MODULE_PATH=./dist/app.module dotenv -- node ./node_modules/@tria-plc/iamapi-common/dist/db/seed.cli.js", - "migrate": "ts-node -r tsconfig-paths/register src/scripts/run-migrations.ts" + "migrate": "ts-node -r tsconfig-paths/register src/scripts/run-migrations.ts", + "script": "ts-node -r tsconfig-paths/register src/scripts/main.ts" }, "dependencies": { "@edr/api-common": "workspace:*", @@ -84,13 +85,15 @@ "@types/node": "^20.14.0", "@types/pg": "^8.6.7", "@types/supertest": "^6.0.2", + "@types/vorpal": "^1.12.8", "jest": "^29.7.0", "supertest": "^7.0.0", "ts-jest": "^29.2.5", "ts-loader": "^9.5.1", "ts-node": "^10.9.2", "tsconfig-paths": "^4.2.0", - "typescript": "^5.5.4" + "typescript": "^5.5.4", + "vorpal": "^1.12.0" }, "jest": { "moduleFileExtensions": [ diff --git a/apps/edr-freight-api/src/scripts/cmds/index.ts b/apps/edr-freight-api/src/scripts/cmds/index.ts new file mode 100644 index 000000000..738609579 --- /dev/null +++ b/apps/edr-freight-api/src/scripts/cmds/index.ts @@ -0,0 +1,7 @@ +import type Vorpal from "vorpal"; +import type { CommandContext } from "./types"; + +export function registerCommands(_vorpal: Vorpal, _ctx: CommandContext): void { + // Add more command registrations here: + // registerMyNewCommand(vorpal, ctx); +} diff --git a/apps/edr-freight-api/src/scripts/cmds/types.ts b/apps/edr-freight-api/src/scripts/cmds/types.ts new file mode 100644 index 000000000..bd0fbb9c9 --- /dev/null +++ b/apps/edr-freight-api/src/scripts/cmds/types.ts @@ -0,0 +1,6 @@ +import type Vorpal from "vorpal"; +import type { INestApplicationContext } from "@nestjs/common"; + +export type CommandContext = { + app: INestApplicationContext; +}; diff --git a/apps/edr-freight-api/src/scripts/main.ts b/apps/edr-freight-api/src/scripts/main.ts new file mode 100644 index 000000000..7090f80fc --- /dev/null +++ b/apps/edr-freight-api/src/scripts/main.ts @@ -0,0 +1,30 @@ +import "reflect-metadata"; +import { config } from "dotenv"; + +config(); + +import Vorpal from "vorpal"; +import { registerCommands } from "./cmds/index"; + +import { NestFactory } from "@nestjs/core"; +import { AppModule } from "../app.module"; + +const vorpal = new Vorpal(); + +async function main() { + const app = await NestFactory.createApplicationContext(AppModule, { + logger: false, + }); + + try { + registerCommands(vorpal, { app }); + vorpal.parse(process.argv); + } finally { + await app.close(); + } +} + +main().catch((err) => { + console.error("Script failed:", err); + process.exit(1); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bd8c81c83..2f4a28bec 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -83,13 +83,13 @@ importers: version: 11.4.4(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) '@nestjs/typeorm': specifier: ^11.0.1 - version: 11.0.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3))) + version: 11.0.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.30(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3))) '@tria-plc/api-common': specifier: file:../../local-packages/tria-plc-api-common-1.4.3.tgz - version: file:local-packages/tria-plc-api-common-1.4.3.tgz(bad2eb10df48448775040459098de142) + version: file:local-packages/tria-plc-api-common-1.4.3.tgz(d6b22b11dde6cd6764a6a0c7e4c9ae51) '@tria-plc/iamapi-common': specifier: file:../../local-packages/tria-plc-iamapi-common-0.7.7.tgz - version: file:local-packages/tria-plc-iamapi-common-0.7.7.tgz(578386f46cf99fd4720e3e99f196f69e) + version: file:local-packages/tria-plc-iamapi-common-0.7.7.tgz(4837bbb980f4864b0c26765895373b58) amqp-connection-manager: specifier: ^5.0.0 version: 5.0.0(amqplib@2.0.1) @@ -137,7 +137,7 @@ importers: version: 7.8.2 typeorm: specifier: ^0.3.30 - version: 0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)) + version: 0.3.30(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)) devDependencies: '@edr/eslint-config': specifier: workspace:* @@ -147,10 +147,10 @@ importers: version: link:../../packages/config/tsconfig '@nestjs/cli': specifier: ^11.0.0 - version: 11.0.21(@types/node@20.19.42)(prettier@3.8.3) + version: 11.0.21(@types/node@20.19.42) '@nestjs/schematics': specifier: ^11.0.0 - version: 11.1.0(chokidar@4.0.3)(prettier@3.8.3)(typescript@5.9.3) + version: 11.1.0(chokidar@4.0.3)(typescript@5.9.3) '@nestjs/testing': specifier: ^11.0.0 version: 11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(@nestjs/microservices@11.1.24)(@nestjs/platform-express@11.1.24) @@ -175,15 +175,18 @@ importers: '@types/supertest': specifier: ^6.0.2 version: 6.0.3 + '@types/vorpal': + specifier: ^1.12.8 + version: 1.12.8 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.19.42)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)) + version: 29.7.0(@types/node@20.19.42)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)) supertest: specifier: ^7.0.0 version: 7.2.2 ts-jest: specifier: ^29.2.5 - version: 29.4.11(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.42)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)))(typescript@5.9.3) + version: 29.4.11(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.42)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)))(typescript@5.9.3) ts-loader: specifier: ^9.5.1 version: 9.6.0(typescript@5.9.3)(webpack@5.106.0) @@ -196,6 +199,9 @@ importers: typescript: specifier: ^5.5.4 version: 5.9.3 + vorpal: + specifier: ^1.12.0 + version: 1.12.0 apps/edr-freight-web/backoffice: dependencies: @@ -661,7 +667,7 @@ importers: version: 8.5.15 tailwindcss: specifier: ^3.4.13 - version: 3.4.19(yaml@2.9.0) + version: 3.4.19(tsx@4.22.4)(yaml@2.9.0) typescript: specifier: ^5.5.4 version: 5.9.3 @@ -749,7 +755,7 @@ importers: version: 8.5.15 tailwindcss: specifier: ^3.4.13 - version: 3.4.19(yaml@2.9.0) + version: 3.4.19(tsx@4.22.4)(yaml@2.9.0) typescript: specifier: ^5.5.4 version: 5.9.3 @@ -1491,138 +1497,294 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.28.1': + resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.21.5': resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} engines: {node: '>=12'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.28.1': + resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.21.5': resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} engines: {node: '>=12'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.28.1': + resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.21.5': resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} engines: {node: '>=12'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.28.1': + resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.21.5': resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.28.1': + resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.21.5': resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} engines: {node: '>=12'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.28.1': + resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.21.5': resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.28.1': + resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.21.5': resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.28.1': + resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.21.5': resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} engines: {node: '>=12'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.28.1': + resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.21.5': resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} engines: {node: '>=12'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.28.1': + resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.21.5': resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} engines: {node: '>=12'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.28.1': + resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.21.5': resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} engines: {node: '>=12'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.28.1': + resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.21.5': resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.28.1': + resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.21.5': resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.28.1': + resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.21.5': resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.28.1': + resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.21.5': resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} engines: {node: '>=12'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.28.1': + resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.21.5': resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} engines: {node: '>=12'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.28.1': + resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.28.1': + resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-x64@0.21.5': resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.28.1': + resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.28.1': + resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.21.5': resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.28.1': + resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.28.1': + resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/sunos-x64@0.21.5': resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} engines: {node: '>=12'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.28.1': + resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.21.5': resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} engines: {node: '>=12'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.28.1': + resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.21.5': resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} engines: {node: '>=12'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.28.1': + resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.21.5': resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} engines: {node: '>=12'} cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.28.1': + resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.9.1': resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -4406,6 +4568,9 @@ packages: '@types/validator@13.15.10': resolution: {integrity: sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==} + '@types/vorpal@1.12.8': + resolution: {integrity: sha512-Qt+Yxa1q6QCaYMxZFXlyPOF3ktIscTelNr1AFYuKM7/Dhlki4gvc476uFyA/hYvskSA6V8W+55x9FjlbAPcYdQ==} + '@types/yargs-parser@21.0.3': resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} @@ -4852,6 +5017,10 @@ packages: resolution: {integrity: sha512-zAfb1fokXsq4BoZBkL0eK+6MfFctbzX3R4UMcoWrL1n2WHewFKentTvOZv2P11u6P4NtW/V47hVjaN7fJiefOg==} engines: {node: '>=0.10.0'} + ansi-escapes@1.4.0: + resolution: {integrity: sha512-wiXutNjDUlNEDWHcYH3jtZUhd3c4/VojassD8zHdHCY13xbZy2XbW+NKQwA0tWGBVzDA9qEzYwfoSsWmviidhw==} + engines: {node: '>=0.10.0'} + ansi-escapes@4.3.2: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} @@ -4892,6 +5061,10 @@ packages: resolution: {integrity: sha512-ewaIr5y+9CUTGFwZfpECUbFlGcC0GCw1oqR9RI6h1gQCd9Aj2GxSckCnPsVJnmfMZbwFYE+leZGASgkWl06Jow==} engines: {node: '>=0.10.0'} + ansi-regex@2.1.1: + resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==} + engines: {node: '>=0.10.0'} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -4908,6 +5081,10 @@ packages: resolution: {integrity: sha512-gWkLPDvHH2pC9YEKqp8dIl0mg3sRglMPvioqGDIOXiwxjxUwIJ1gF86E2o4R5yLNh8IAkwHbaMtASkJfkQ2hIA==} engines: {node: '>=0.10.0'} + ansi-styles@2.2.1: + resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==} + engines: {node: '>=0.10.0'} + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} @@ -5159,6 +5336,9 @@ packages: '@babel/core': ^7.0.0 styled-components: '>= 2' + babel-polyfill@6.26.0: + resolution: {integrity: sha512-F2rZGQnAdaHWQ8YAoeRbukc7HS9QgdgeyJ0rQDd485v9opwuPvjpPFcOOT/WmkKTdgy9ESgSPXDcTNpzrGr6iQ==} + babel-preset-current-node-syntax@1.2.0: resolution: {integrity: sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==} peerDependencies: @@ -5170,6 +5350,9 @@ packages: peerDependencies: '@babel/core': ^7.0.0 + babel-runtime@6.26.0: + resolution: {integrity: sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -5422,6 +5605,10 @@ packages: chainsaw@0.1.0: resolution: {integrity: sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==} + chalk@1.1.3: + resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==} + engines: {node: '>=0.10.0'} + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -5490,6 +5677,10 @@ packages: classnames@2.5.1: resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} + cli-cursor@1.0.2: + resolution: {integrity: sha512-25tABq090YNKkF6JH7lcwO0zFJTRke4Jcq9iX2nr/Sz0Cjjv4gckmwlW6Ty/aoyFd6z3ysR2hMGC2GFugmBo6A==} + engines: {node: '>=0.10.0'} + cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} @@ -5510,6 +5701,9 @@ packages: resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==} engines: {node: '>=18'} + cli-width@1.1.1: + resolution: {integrity: sha512-eMU2akIeEIkCxGXUNmDnJq1KzOIiPnJ+rKqRe6hcxE3vIOPvpMrBYOn/Bl7zNlYJj/zQxXquAnozHUCf9Whnsg==} + cli-width@4.1.0: resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} engines: {node: '>= 12'} @@ -5553,6 +5747,10 @@ packages: code-block-writer@13.0.3: resolution: {integrity: sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==} + code-point-at@1.1.0: + resolution: {integrity: sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==} + engines: {node: '>=0.10.0'} + codepage@1.15.0: resolution: {integrity: sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==} engines: {node: '>=0.8'} @@ -5697,6 +5895,10 @@ packages: resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==} engines: {node: '>=0.10.0'} + core-js@2.6.12: + resolution: {integrity: sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==} + deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js. + core-js@3.49.0: resolution: {integrity: sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==} @@ -6282,6 +6484,11 @@ packages: engines: {node: '>=12'} hasBin: true + esbuild@0.28.1: + resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -6289,6 +6496,10 @@ packages: escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + escape-string-regexp@2.0.0: resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} engines: {node: '>=8'} @@ -6499,6 +6710,10 @@ packages: resolution: {integrity: sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==} engines: {node: ^18.19.0 || >=20.5.0} + exit-hook@1.1.1: + resolution: {integrity: sha512-MsG3prOVw1WtLXAZbM3KiYtooKR1LvxHh3VHsVtIy0uiUu8usxgB/94DP2HxtD/661lLdB6yzQ09lGJSQr6nkg==} + engines: {node: '>=0.10.0'} + exit@0.1.2: resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} engines: {node: '>= 0.8.0'} @@ -6632,6 +6847,10 @@ packages: fflate@0.8.3: resolution: {integrity: sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==} + figures@1.7.0: + resolution: {integrity: sha512-UxKlfCRuCBxSXU4C6t9scbDyWZ4VlaFFdojKtzJuSkuOBQ5CNFum+zZXFwHjo+CxBC1t6zlYPgHIgFjL8ggoEQ==} + engines: {node: '>=0.10.0'} + figures@6.1.0: resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} engines: {node: '>=18'} @@ -6904,7 +7123,7 @@ packages: git-raw-commits@4.0.0: resolution: {integrity: sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==} engines: {node: '>=16'} - deprecated: This package is no longer maintained. For the JavaScript API, please use @conventional-changelog/git-client instead. + deprecated: Deprecated and no longer maintained. Use @conventional-changelog/git-client instead. hasBin: true glob-parent@5.1.2: @@ -6989,6 +7208,10 @@ packages: engines: {node: '>=0.4.7'} hasBin: true + has-ansi@2.0.0: + resolution: {integrity: sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==} + engines: {node: '>=0.10.0'} + has-bigints@1.1.0: resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} engines: {node: '>= 0.4'} @@ -7185,6 +7408,10 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} + in-publish@2.0.1: + resolution: {integrity: sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ==} + hasBin: true + inflight@1.0.6: resolution: {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. @@ -7214,6 +7441,9 @@ packages: react-dom: optional: true + inquirer@0.11.0: + resolution: {integrity: sha512-LIwC+g/fJbmKhDm341+RqDIV4jPf/n3pMway9xg8Ovt6CCQo1ozXhmuKTcoNIWhWJJKsSGZP+Rnuq7JgM7mE2A==} + internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} @@ -7327,6 +7557,10 @@ packages: resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} engines: {node: '>= 0.4'} + is-fullwidth-code-point@1.0.0: + resolution: {integrity: sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==} + engines: {node: '>=0.10.0'} + is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} @@ -8137,6 +8371,9 @@ packages: lodash.upperfirst@4.3.1: resolution: {integrity: sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==} + lodash@3.10.1: + resolution: {integrity: sha512-9mDDwqVIma6OZX79ZlDACZl8sBm0TEnkf99zV3iMA4GzkIT/9hiqP5mY0HoT1iNLCrKc/R1HByV+yJfRWVJryQ==} + lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} @@ -8155,6 +8392,10 @@ packages: resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} engines: {node: '>=18'} + log-update@1.0.2: + resolution: {integrity: sha512-4vSow8gbiGnwdDNrpy1dyNaXWKSCIPop0EHdE8GrnngHoJujM3QhvHUN/igsYCgPoHo7pFOezlJ61Hlln0KHyA==} + engines: {node: '>=0.10.0'} + log-update@6.1.0: resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} engines: {node: '>=18'} @@ -8444,6 +8685,9 @@ packages: resolution: {integrity: sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==} engines: {node: '>= 10.16.0'} + mute-stream@0.0.5: + resolution: {integrity: sha512-EbrziT4s8cWPmzr47eYVW3wimS4HsvlnV5ri1xw1aR6JQo/OrJX5rkl32K/QQHdxeabJETtfeaROGhd8W7uBgg==} + mute-stream@2.0.0: resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} engines: {node: ^18.17.0 || >=20.5.0} @@ -8559,6 +8803,10 @@ packages: node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + node-localstorage@0.6.0: + resolution: {integrity: sha512-t9dKMce8qUs2KK02ZiBgzZSykUxc+5UcML7/20a62ruHwfh7+bNQvrH/auxY5gFNexTwAFdr+DbptxlLq4+7qQ==} + engines: {node: '>=0.10'} + node-releases@2.0.47: resolution: {integrity: sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==} engines: {node: '>=18'} @@ -8585,6 +8833,10 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + number-is-nan@1.0.1: + resolution: {integrity: sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==} + engines: {node: '>=0.10.0'} + nwsapi@2.2.24: resolution: {integrity: sha512-7YRhZ3jS45LwmSCT4b2sVFHt/WuovaktDU07QrtOBY2PXskss5a9jfmR9jptyumwXST+rFjrmppMY1KT/yn35A==} @@ -8655,6 +8907,10 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + onetime@1.1.0: + resolution: {integrity: sha512-GZ+g4jayMqzCRMgB2sol7GiCLjKfS1PINkjmx8spcKce1LiVqcbQreXwqs2YAFXC6R03VIG28ZS31t8M866v6A==} + engines: {node: '>=0.10.0'} + onetime@5.1.2: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} @@ -9462,6 +9718,9 @@ packages: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} + readline2@1.0.1: + resolution: {integrity: sha512-8/td4MmwUB6PkZUbV25uKz7dfrmjYWxsW8DVfibWdlHRk/l/DfHKn4pU+dfcoGLFgWOdyGCzINRQD7jn+Bv+/g==} + recast@0.23.11: resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==} engines: {node: '>= 4'} @@ -9503,6 +9762,12 @@ packages: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} + regenerator-runtime@0.10.5: + resolution: {integrity: sha512-02YopEIhAgiBHWeoTiA8aitHDt8z6w+rQqNuIftlM+ZtvSl/brTouaU7DW6GO/cHtvxJvS4Hwv2ibKdxIRi24w==} + + regenerator-runtime@0.11.1: + resolution: {integrity: sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==} + regenerator-runtime@0.13.11: resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} @@ -9587,6 +9852,10 @@ packages: engines: {node: '>= 0.4'} hasBin: true + restore-cursor@1.0.1: + resolution: {integrity: sha512-reSjH4HuiFlxlaBaFCiS6O76ZGG2ygKoSlCsipKdaZuKSPx/+bt9mULkn4l0asVzbEfQQmXRg6Wp6gv6m0wElw==} + engines: {node: '>=0.10.0'} + restore-cursor@3.1.0: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} @@ -9658,9 +9927,15 @@ packages: resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} engines: {node: '>=18'} + run-async@0.1.0: + resolution: {integrity: sha512-qOX+w+IxFgpUpJfkv2oGN0+ExPs68F4sZHfaRRx4dDexAQkG83atugKVEylyT5ARees3HBbfmuvnjbrd8j9Wjw==} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rx-lite@3.1.2: + resolution: {integrity: sha512-1I1+G2gteLB8Tkt8YI1sJvSIfa0lWuRtC8GjvtyPBcLSF5jBCCJJqKrpER5JU5r6Bhe+i9/pK3VMuUcXu0kdwQ==} + rxjs@7.8.1: resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} @@ -10011,6 +10286,10 @@ packages: resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} engines: {node: '>=10'} + string-width@1.0.2: + resolution: {integrity: sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==} + engines: {node: '>=0.10.0'} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -10056,6 +10335,10 @@ packages: resolution: {integrity: sha512-zaJYxz2FtcMb4f+g60KsRNFOpVMUyuJgA51Zi5Z1DOTC3S59+OQiVOzE9GZt0x72uBGWKsQIuBKeF9iusmKFsg==} engines: {node: '>=14.16'} + strip-ansi@3.0.1: + resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} + engines: {node: '>=0.10.0'} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -10146,6 +10429,10 @@ packages: resolution: {integrity: sha512-oK8WG9diS3DlhdUkcFn4tkNIiIbBx9lI2ClF8K+b2/m8Eyv47LSawxUzZQSNKUrVb2KsqeTDCcjAAVPYaSLVTA==} engines: {node: '>=14.18.0'} + supports-color@2.0.0: + resolution: {integrity: sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==} + engines: {node: '>=0.8.0'} + supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -10512,6 +10799,11 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsx@4.22.4: + resolution: {integrity: sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==} + engines: {node: '>=18.0.0'} + hasBin: true + turbo@2.9.16: resolution: {integrity: sha512-NqgRQy6j6dPYcdSdv0q1g9QsZg7SWg87RERM8otw/1AtKU2yTFVClOM7cbwKzOonZr/Ek1blTBucw64L9H0Bwg==} hasBin: true @@ -10922,6 +11214,10 @@ packages: resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} engines: {node: '>=0.10.0'} + vorpal@1.12.0: + resolution: {integrity: sha512-lYEhd75l75P3D1LKpm4KqdOSpNyNdDJ9ixEZmC5ZAZUKGy6JNexfMdQ9SNaT5pCHuzuXXRJQedJ+CdqNg/D4Kw==} + engines: {iojs: '>= 1.0.0', node: '>= 0.10.0'} + w3c-xmlserializer@5.0.0: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} @@ -11046,6 +11342,10 @@ packages: wordwrap@1.0.0: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + wrap-ansi@2.1.0: + resolution: {integrity: sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==} + engines: {node: '>=0.10.0'} + wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} @@ -11300,11 +11600,11 @@ snapshots: '@babel/helpers': 7.29.7 '@babel/parser': 7.29.7 '@babel/template': 7.29.7 - '@babel/traverse': 7.29.7(supports-color@5.5.0) + '@babel/traverse': 7.29.7 '@babel/types': 7.29.7 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -11353,6 +11653,13 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-module-imports@7.29.7': + dependencies: + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + '@babel/helper-module-imports@7.29.7(supports-color@5.5.0)': dependencies: '@babel/traverse': 7.29.7(supports-color@5.5.0) @@ -11363,9 +11670,9 @@ snapshots: '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': dependencies: '@babel/core': 7.29.7 - '@babel/helper-module-imports': 7.29.7(supports-color@5.5.0) + '@babel/helper-module-imports': 7.29.7 '@babel/helper-validator-identifier': 7.29.7 - '@babel/traverse': 7.29.7(supports-color@5.5.0) + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color @@ -11539,6 +11846,18 @@ snapshots: '@babel/parser': 7.29.7 '@babel/types': 7.29.7 + '@babel/traverse@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + '@babel/traverse@7.29.7(supports-color@5.5.0)': dependencies: '@babel/code-frame': 7.29.7 @@ -11823,72 +12142,150 @@ snapshots: '@esbuild/aix-ppc64@0.21.5': optional: true + '@esbuild/aix-ppc64@0.28.1': + optional: true + '@esbuild/android-arm64@0.21.5': optional: true + '@esbuild/android-arm64@0.28.1': + optional: true + '@esbuild/android-arm@0.21.5': optional: true + '@esbuild/android-arm@0.28.1': + optional: true + '@esbuild/android-x64@0.21.5': optional: true + '@esbuild/android-x64@0.28.1': + optional: true + '@esbuild/darwin-arm64@0.21.5': optional: true + '@esbuild/darwin-arm64@0.28.1': + optional: true + '@esbuild/darwin-x64@0.21.5': optional: true + '@esbuild/darwin-x64@0.28.1': + optional: true + '@esbuild/freebsd-arm64@0.21.5': optional: true + '@esbuild/freebsd-arm64@0.28.1': + optional: true + '@esbuild/freebsd-x64@0.21.5': optional: true + '@esbuild/freebsd-x64@0.28.1': + optional: true + '@esbuild/linux-arm64@0.21.5': optional: true + '@esbuild/linux-arm64@0.28.1': + optional: true + '@esbuild/linux-arm@0.21.5': optional: true + '@esbuild/linux-arm@0.28.1': + optional: true + '@esbuild/linux-ia32@0.21.5': optional: true + '@esbuild/linux-ia32@0.28.1': + optional: true + '@esbuild/linux-loong64@0.21.5': optional: true + '@esbuild/linux-loong64@0.28.1': + optional: true + '@esbuild/linux-mips64el@0.21.5': optional: true + '@esbuild/linux-mips64el@0.28.1': + optional: true + '@esbuild/linux-ppc64@0.21.5': optional: true + '@esbuild/linux-ppc64@0.28.1': + optional: true + '@esbuild/linux-riscv64@0.21.5': optional: true + '@esbuild/linux-riscv64@0.28.1': + optional: true + '@esbuild/linux-s390x@0.21.5': optional: true + '@esbuild/linux-s390x@0.28.1': + optional: true + '@esbuild/linux-x64@0.21.5': optional: true + '@esbuild/linux-x64@0.28.1': + optional: true + + '@esbuild/netbsd-arm64@0.28.1': + optional: true + '@esbuild/netbsd-x64@0.21.5': optional: true + '@esbuild/netbsd-x64@0.28.1': + optional: true + + '@esbuild/openbsd-arm64@0.28.1': + optional: true + '@esbuild/openbsd-x64@0.21.5': optional: true + '@esbuild/openbsd-x64@0.28.1': + optional: true + + '@esbuild/openharmony-arm64@0.28.1': + optional: true + '@esbuild/sunos-x64@0.21.5': optional: true + '@esbuild/sunos-x64@0.28.1': + optional: true + '@esbuild/win32-arm64@0.21.5': optional: true + '@esbuild/win32-arm64@0.28.1': + optional: true + '@esbuild/win32-ia32@0.21.5': optional: true + '@esbuild/win32-ia32@0.28.1': + optional: true + '@esbuild/win32-x64@0.21.5': optional: true + '@esbuild/win32-x64@0.28.1': + optional: true + '@eslint-community/eslint-utils@4.9.1(eslint@8.57.1)': dependencies: eslint: 8.57.1 @@ -12280,6 +12677,41 @@ snapshots: - supports-color - ts-node + '@jest/core@29.7.0(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3))': + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.19.42 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@20.19.42)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + '@jest/environment@29.7.0': dependencies: '@jest/fake-timers': 29.7.0 @@ -12495,10 +12927,10 @@ snapshots: transitivePeerDependencies: - '@types/react' - '@mantine/dates@7.17.8(@mantine/core@7.17.8(@mantine/hooks@7.17.8(react@19.2.6))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@7.17.8(react@19.2.6))(dayjs@1.11.21)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@mantine/dates@7.17.8(@mantine/core@9.3.0(@mantine/hooks@9.3.0(react@19.2.6))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@9.3.0(react@19.2.6))(dayjs@1.11.21)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@mantine/core': 7.17.8(@mantine/hooks@7.17.8(react@19.2.6))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@mantine/hooks': 7.17.8(react@19.2.6) + '@mantine/core': 9.3.0(@mantine/hooks@9.3.0(react@19.2.6))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@mantine/hooks': 9.3.0(react@19.2.6) clsx: 2.1.1 dayjs: 1.11.21 react: 19.2.6 @@ -12771,6 +13203,42 @@ snapshots: axios: 1.17.0 rxjs: 7.8.2 + '@nestjs/cli@11.0.21(@types/node@20.19.42)': + dependencies: + '@angular-devkit/core': 19.2.24(chokidar@4.0.3) + '@angular-devkit/schematics': 19.2.24(chokidar@4.0.3) + '@angular-devkit/schematics-cli': 19.2.24(@types/node@20.19.42)(chokidar@4.0.3) + '@inquirer/prompts': 7.10.1(@types/node@20.19.42) + '@nestjs/schematics': 11.1.0(chokidar@4.0.3)(typescript@5.9.3) + ansis: 4.2.0 + chokidar: 4.0.3 + cli-table3: 0.6.5 + commander: 4.1.1 + fork-ts-checker-webpack-plugin: 9.1.0(typescript@5.9.3)(webpack@5.106.0) + glob: 13.0.6 + node-emoji: 1.11.0 + ora: 5.4.1 + tsconfig-paths: 4.2.0 + tsconfig-paths-webpack-plugin: 4.2.0 + typescript: 5.9.3 + webpack: 5.106.0 + webpack-node-externals: 3.0.0 + transitivePeerDependencies: + - '@minify-html/node' + - '@swc/css' + - '@swc/html' + - '@types/node' + - clean-css + - cssnano + - csso + - esbuild + - html-minifier-terser + - lightningcss + - postcss + - prettier + - uglify-js + - webpack-cli + '@nestjs/cli@11.0.21(@types/node@20.19.42)(prettier@3.8.3)': dependencies: '@angular-devkit/core': 19.2.24(chokidar@4.0.3) @@ -12921,6 +13389,17 @@ snapshots: transitivePeerDependencies: - chokidar + '@nestjs/schematics@11.1.0(chokidar@4.0.3)(typescript@5.9.3)': + dependencies: + '@angular-devkit/core': 19.2.24(chokidar@4.0.3) + '@angular-devkit/schematics': 19.2.24(chokidar@4.0.3) + comment-json: 5.0.0 + jsonc-parser: 3.3.1 + pluralize: 8.0.0 + typescript: 5.9.3 + transitivePeerDependencies: + - chokidar + '@nestjs/swagger@11.4.4(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)': dependencies: '@microsoft/tsdoc': 0.16.0 @@ -12974,6 +13453,14 @@ snapshots: rxjs: 7.8.2 typeorm: 0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)) + '@nestjs/typeorm@11.0.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.30(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)))': + dependencies: + '@nestjs/common': 11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.24)(@nestjs/platform-express@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2) + reflect-metadata: 0.2.2 + rxjs: 7.8.2 + typeorm: 0.3.30(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)) + '@next/env@14.2.35': {} '@next/eslint-plugin-next@14.2.35': @@ -13160,7 +13647,7 @@ snapshots: '@puppeteer/browsers@2.13.2': dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3 extract-zip: 2.0.1 progress: 2.0.3 proxy-agent: 6.5.0 @@ -15224,7 +15711,7 @@ snapshots: '@tokenizer/inflate@0.4.1': dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3 token-types: 6.1.2 transitivePeerDependencies: - supports-color @@ -15233,50 +15720,6 @@ snapshots: '@tootallnate/quickjs-emscripten@0.23.0': {} - '@tria-plc/api-common@file:local-packages/tria-plc-api-common-1.4.3.tgz(bad2eb10df48448775040459098de142)': - dependencies: - '@nestjs/axios': 4.0.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.17.0)(rxjs@7.8.2) - '@nestjs/common': 11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.24)(@nestjs/platform-express@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/jwt': 10.2.0(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)) - '@nestjs/microservices': 11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(amqp-connection-manager@5.0.0(amqplib@2.0.1))(amqplib@2.0.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/passport': 10.0.3(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0) - '@nestjs/swagger': 11.4.4(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) - '@nestjs/throttler': 6.5.0(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(reflect-metadata@0.2.2) - '@nestjs/typeorm': 11.0.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3))) - '@tria-plc/iamapi-common': file:local-packages/tria-plc-iamapi-common-0.7.7.tgz(578386f46cf99fd4720e3e99f196f69e) - argon2: 0.43.1 - axios: 1.17.0 - change-case: 5.4.4 - class-transformer: 0.5.1 - class-validator: 0.14.4 - dotenv: 16.6.1 - ethiopian-calendar-date-converter: 2.1.6 - ethiopian-date: 0.0.6 - exceljs: 4.4.0 - file-type: 21.3.4 - handlebars: 4.7.9 - handlebars-helpers: 0.10.0 - jmespath: 0.16.0 - jose: 5.10.0 - jsonwebtoken: 9.0.3 - libphonenumber-js: 1.13.6 - libreoffice-convert: 1.8.1 - nestjs-minio-client: 2.2.0(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24) - passport-jwt: 4.0.1 - qrcode: 1.5.4 - reflect-metadata: 0.2.2 - rxjs: 7.8.2 - style-object-to-css-string: 1.1.3 - typeorm: 0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)) - typeorm-extension: 3.9.0(@faker-js/faker@10.4.0)(typeorm@0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3))) - uuid: 11.1.1 - xlsx: 0.18.5 - transitivePeerDependencies: - - '@faker-js/faker' - - debug - - supports-color - '@tria-plc/api-common@file:local-packages/tria-plc-api-common-1.4.3.tgz(c061d697b8a1e15b1d1aba893da7b0e6)': dependencies: '@nestjs/axios': 4.0.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.17.0)(rxjs@7.8.2) @@ -15321,6 +15764,50 @@ snapshots: - debug - supports-color + '@tria-plc/api-common@file:local-packages/tria-plc-api-common-1.4.3.tgz(d6b22b11dde6cd6764a6a0c7e4c9ae51)': + dependencies: + '@nestjs/axios': 4.0.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.17.0)(rxjs@7.8.2) + '@nestjs/common': 11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.24)(@nestjs/platform-express@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/jwt': 10.2.0(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)) + '@nestjs/microservices': 11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(amqp-connection-manager@5.0.0(amqplib@2.0.1))(amqplib@2.0.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/passport': 10.0.3(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0) + '@nestjs/swagger': 11.4.4(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) + '@nestjs/throttler': 6.5.0(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(reflect-metadata@0.2.2) + '@nestjs/typeorm': 11.0.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.30(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3))) + '@tria-plc/iamapi-common': file:local-packages/tria-plc-iamapi-common-0.7.7.tgz(4837bbb980f4864b0c26765895373b58) + argon2: 0.43.1 + axios: 1.17.0 + change-case: 5.4.4 + class-transformer: 0.5.1 + class-validator: 0.14.4 + dotenv: 16.6.1 + ethiopian-calendar-date-converter: 2.1.6 + ethiopian-date: 0.0.6 + exceljs: 4.4.0 + file-type: 21.3.4 + handlebars: 4.7.9 + handlebars-helpers: 0.10.0 + jmespath: 0.16.0 + jose: 5.10.0 + jsonwebtoken: 9.0.3 + libphonenumber-js: 1.13.6 + libreoffice-convert: 1.8.1 + nestjs-minio-client: 2.2.0(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24) + passport-jwt: 4.0.1 + qrcode: 1.5.4 + reflect-metadata: 0.2.2 + rxjs: 7.8.2 + style-object-to-css-string: 1.1.3 + typeorm: 0.3.30(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)) + typeorm-extension: 3.9.0(@faker-js/faker@10.4.0)(typeorm@0.3.30(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3))) + uuid: 11.1.1 + xlsx: 0.18.5 + transitivePeerDependencies: + - '@faker-js/faker' + - debug + - supports-color + '@tria-plc/iamapi-common@file:local-packages/tria-plc-iamapi-common-0.7.6.tgz(c97ba831ddde82920910406ab5262991)': dependencies: '@nestjs/axios': 4.0.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.17.0)(rxjs@7.8.2) @@ -15356,7 +15843,7 @@ snapshots: - '@faker-js/faker' - supports-color - '@tria-plc/iamapi-common@file:local-packages/tria-plc-iamapi-common-0.7.7.tgz(578386f46cf99fd4720e3e99f196f69e)': + '@tria-plc/iamapi-common@file:local-packages/tria-plc-iamapi-common-0.7.7.tgz(4837bbb980f4864b0c26765895373b58)': dependencies: '@nestjs/axios': 4.0.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.17.0)(rxjs@7.8.2) '@nestjs/common': 11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) @@ -15366,8 +15853,8 @@ snapshots: '@nestjs/passport': 10.0.3(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0) '@nestjs/swagger': 11.4.4(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) '@nestjs/throttler': 6.5.0(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(reflect-metadata@0.2.2) - '@nestjs/typeorm': 11.0.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3))) - '@tria-plc/api-common': file:local-packages/tria-plc-api-common-1.4.3.tgz(bad2eb10df48448775040459098de142) + '@nestjs/typeorm': 11.0.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.30(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3))) + '@tria-plc/api-common': file:local-packages/tria-plc-api-common-1.4.3.tgz(d6b22b11dde6cd6764a6a0c7e4c9ae51) api-common: 1.2.2 argon2: 0.43.1 axios: 1.17.0 @@ -15384,8 +15871,8 @@ snapshots: qrcode: 1.5.4 reflect-metadata: 0.2.2 rxjs: 7.8.2 - typeorm: 0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)) - typeorm-extension: 3.9.0(@faker-js/faker@10.4.0)(typeorm@0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3))) + typeorm: 0.3.30(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)) + typeorm-extension: 3.9.0(@faker-js/faker@10.4.0)(typeorm@0.3.30(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3))) uuid: 11.1.1 transitivePeerDependencies: - '@faker-js/faker' @@ -15399,7 +15886,7 @@ snapshots: '@lottiefiles/react-lottie-player': 3.6.0(react@19.2.6) '@mantine/charts': 7.17.8(@mantine/core@7.17.8(@mantine/hooks@7.17.8(react@19.2.6))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@7.17.8(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(recharts@3.8.1(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react-is@19.2.7)(react@19.2.6)(redux@5.0.1)) '@mantine/core': 7.17.8(@mantine/hooks@7.17.8(react@19.2.6))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@mantine/dates': 7.17.8(@mantine/core@7.17.8(@mantine/hooks@7.17.8(react@19.2.6))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@7.17.8(react@19.2.6))(dayjs@1.11.21)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@mantine/dates': 7.17.8(@mantine/core@9.3.0(@mantine/hooks@9.3.0(react@19.2.6))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@9.3.0(react@19.2.6))(dayjs@1.11.21)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@mantine/hooks': 7.17.8(react@19.2.6) '@mantine/notifications': 7.17.8(@mantine/core@7.17.8(@mantine/hooks@7.17.8(react@19.2.6))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@7.17.8(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@radix-ui/react-accordion': 1.2.13(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -15820,6 +16307,8 @@ snapshots: '@types/validator@13.15.10': {} + '@types/vorpal@1.12.8': {} + '@types/yargs-parser@21.0.3': {} '@types/yargs@17.0.35': @@ -16169,7 +16658,7 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -16318,6 +16807,8 @@ snapshots: dependencies: ansi-wrap: 0.1.0 + ansi-escapes@1.4.0: {} + ansi-escapes@4.3.2: dependencies: type-fest: 0.21.3 @@ -16358,6 +16849,8 @@ snapshots: dependencies: ansi-wrap: 0.1.0 + ansi-regex@2.1.1: {} + ansi-regex@5.0.1: {} ansi-regex@6.2.2: {} @@ -16370,6 +16863,8 @@ snapshots: dependencies: ansi-wrap: 0.1.0 + ansi-styles@2.2.1: {} + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 @@ -16673,6 +17168,12 @@ snapshots: transitivePeerDependencies: - supports-color + babel-polyfill@6.26.0: + dependencies: + babel-runtime: 6.26.0 + core-js: 2.6.12 + regenerator-runtime: 0.10.5 + babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.7): dependencies: '@babel/core': 7.29.7 @@ -16698,6 +17199,11 @@ snapshots: babel-plugin-jest-hoist: 29.6.3 babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7) + babel-runtime@6.26.0: + dependencies: + core-js: 2.6.12 + regenerator-runtime: 0.11.1 + balanced-match@1.0.2: {} balanced-match@4.0.4: {} @@ -16805,7 +17311,7 @@ snapshots: dependencies: bytes: 3.1.2 content-type: 1.0.5 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3 http-errors: 2.0.1 iconv-lite: 0.7.2 on-finished: 2.4.1 @@ -16994,6 +17500,14 @@ snapshots: dependencies: traverse: 0.3.9 + chalk@1.1.3: + dependencies: + ansi-styles: 2.2.1 + escape-string-regexp: 1.0.5 + has-ansi: 2.0.0 + strip-ansi: 3.0.1 + supports-color: 2.0.0 + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 @@ -17064,6 +17578,10 @@ snapshots: classnames@2.5.1: {} + cli-cursor@1.0.2: + dependencies: + restore-cursor: 1.0.1 + cli-cursor@3.1.0: dependencies: restore-cursor: 3.1.0 @@ -17085,6 +17603,8 @@ snapshots: slice-ansi: 5.0.0 string-width: 7.2.0 + cli-width@1.1.1: {} + cli-width@4.1.0: {} client-only@0.0.1: {} @@ -17129,6 +17649,8 @@ snapshots: code-block-writer@13.0.3: {} + code-point-at@1.1.0: {} + codepage@1.15.0: {} collect-v8-coverage@1.0.3: {} @@ -17245,6 +17767,8 @@ snapshots: copy-descriptor@0.1.1: {} + core-js@2.6.12: {} + core-js@3.49.0: optional: true @@ -17319,6 +17843,21 @@ snapshots: - supports-color - ts-node + create-jest@29.7.0(@types/node@20.19.42)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)): + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@20.19.42)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + create-require@1.1.1: {} cron@4.4.0: @@ -17470,6 +18009,10 @@ snapshots: dependencies: ms: 2.1.3 + debug@4.4.3: + dependencies: + ms: 2.1.3 + debug@4.4.3(supports-color@5.5.0): dependencies: ms: 2.1.3 @@ -17484,6 +18027,8 @@ snapshots: decode-uri-component@0.2.2: {} + dedent@1.7.2: {} + dedent@1.7.2(babel-plugin-macros@3.1.0): optionalDependencies: babel-plugin-macros: 3.1.0 @@ -17881,10 +18426,42 @@ snapshots: '@esbuild/win32-ia32': 0.21.5 '@esbuild/win32-x64': 0.21.5 + esbuild@0.28.1: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.1 + '@esbuild/android-arm': 0.28.1 + '@esbuild/android-arm64': 0.28.1 + '@esbuild/android-x64': 0.28.1 + '@esbuild/darwin-arm64': 0.28.1 + '@esbuild/darwin-x64': 0.28.1 + '@esbuild/freebsd-arm64': 0.28.1 + '@esbuild/freebsd-x64': 0.28.1 + '@esbuild/linux-arm': 0.28.1 + '@esbuild/linux-arm64': 0.28.1 + '@esbuild/linux-ia32': 0.28.1 + '@esbuild/linux-loong64': 0.28.1 + '@esbuild/linux-mips64el': 0.28.1 + '@esbuild/linux-ppc64': 0.28.1 + '@esbuild/linux-riscv64': 0.28.1 + '@esbuild/linux-s390x': 0.28.1 + '@esbuild/linux-x64': 0.28.1 + '@esbuild/netbsd-arm64': 0.28.1 + '@esbuild/netbsd-x64': 0.28.1 + '@esbuild/openbsd-arm64': 0.28.1 + '@esbuild/openbsd-x64': 0.28.1 + '@esbuild/openharmony-arm64': 0.28.1 + '@esbuild/sunos-x64': 0.28.1 + '@esbuild/win32-arm64': 0.28.1 + '@esbuild/win32-ia32': 0.28.1 + '@esbuild/win32-x64': 0.28.1 + optional: true + escalade@3.2.0: {} escape-html@1.0.3: {} + escape-string-regexp@1.0.5: {} + escape-string-regexp@2.0.0: {} escape-string-regexp@4.0.0: {} @@ -17905,7 +18482,7 @@ snapshots: '@typescript-eslint/parser': 8.60.1(eslint@8.57.1)(typescript@5.9.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.10 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1) eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.60.1(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) eslint-plugin-react: 7.37.5(eslint@8.57.1) @@ -17929,7 +18506,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.3(supports-color@5.5.0) @@ -17944,14 +18521,14 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.13.0(@typescript-eslint/parser@8.60.1(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): + eslint-module-utils@2.13.0(@typescript-eslint/parser@8.60.1(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 8.60.1(eslint@8.57.1)(typescript@5.9.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.10 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1) transitivePeerDependencies: - supports-color @@ -17966,7 +18543,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.10 - eslint-module-utils: 2.13.0(@typescript-eslint/parser@8.60.1(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.13.0(@typescript-eslint/parser@8.60.1(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) hasown: 2.0.4 is-core-module: 2.16.2 is-glob: 4.0.3 @@ -18197,6 +18774,8 @@ snapshots: strip-final-newline: 4.0.0 yoctocolors: 2.1.2 + exit-hook@1.1.1: {} + exit@0.1.2: {} expand-brackets@2.1.4: @@ -18270,7 +18849,7 @@ snapshots: content-type: 1.0.5 cookie: 0.7.2 cookie-signature: 1.2.2 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3 depd: 2.0.0 encodeurl: 2.0.0 escape-html: 1.0.3 @@ -18321,7 +18900,7 @@ snapshots: extract-zip@2.0.1: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3 get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -18409,6 +18988,11 @@ snapshots: fflate@0.8.3: {} + figures@1.7.0: + dependencies: + escape-string-regexp: 1.0.5 + object-assign: 4.1.1 + figures@6.1.0: dependencies: is-unicode-supported: 2.1.0 @@ -18463,7 +19047,7 @@ snapshots: finalhandler@2.1.1: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3 encodeurl: 2.0.0 escape-html: 1.0.3 on-finished: 2.4.1 @@ -18697,7 +19281,7 @@ snapshots: dependencies: basic-ftp: 5.3.1 data-uri-to-buffer: 6.0.2 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -18843,6 +19427,10 @@ snapshots: optionalDependencies: uglify-js: 3.19.3 + has-ansi@2.0.0: + dependencies: + ansi-regex: 2.1.1 + has-bigints@1.1.0: {} has-flag@3.0.0: {} @@ -18959,21 +19547,21 @@ snapshots: http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3 transitivePeerDependencies: - supports-color https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3 transitivePeerDependencies: - supports-color https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.4 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -19035,6 +19623,8 @@ snapshots: imurmurhash@0.1.4: {} + in-publish@2.0.1: {} + inflight@1.0.6: dependencies: once: 1.4.0 @@ -19055,6 +19645,21 @@ snapshots: react: 19.2.6 react-dom: 19.2.6(react@19.2.6) + inquirer@0.11.0: + dependencies: + ansi-escapes: 1.4.0 + ansi-regex: 2.1.1 + chalk: 1.1.3 + cli-cursor: 1.0.2 + cli-width: 1.1.1 + figures: 1.7.0 + lodash: 3.10.1 + readline2: 1.0.1 + run-async: 0.1.0 + rx-lite: 3.1.2 + strip-ansi: 3.0.1 + through: 2.3.8 + internal-slot@1.1.0: dependencies: es-errors: 1.3.0 @@ -19164,6 +19769,10 @@ snapshots: dependencies: call-bound: 1.0.4 + is-fullwidth-code-point@1.0.0: + dependencies: + number-is-nan: 1.0.1 + is-fullwidth-code-point@3.0.0: {} is-fullwidth-code-point@4.0.0: {} @@ -19356,7 +19965,7 @@ snapshots: istanbul-lib-source-maps@4.0.1: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3 istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: @@ -19400,6 +20009,32 @@ snapshots: jest-util: 29.7.0 p-limit: 3.1.0 + jest-circus@29.7.0: + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.19.42 + chalk: 4.1.2 + co: 4.6.0 + dedent: 1.7.2 + is-generator-fn: 2.1.0 + jest-each: 29.7.0 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + p-limit: 3.1.0 + pretty-format: 29.7.0 + pure-rand: 6.1.0 + slash: 3.0.0 + stack-utils: 2.0.6 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + jest-circus@29.7.0(babel-plugin-macros@3.1.0): dependencies: '@jest/environment': 29.7.0 @@ -19445,6 +20080,25 @@ snapshots: - supports-color - ts-node + jest-cli@29.7.0(@types/node@20.19.42)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)): + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)) + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@20.19.42)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)) + exit: 0.1.2 + import-local: 3.2.0 + jest-config: 29.7.0(@types/node@20.19.42)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + jest-config@29.7.0(@types/node@20.19.42)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)): dependencies: '@babel/core': 7.29.7 @@ -19476,6 +20130,37 @@ snapshots: - babel-plugin-macros - supports-color + jest-config@29.7.0(@types/node@20.19.42)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)): + dependencies: + '@babel/core': 7.29.7 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.29.7) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 20.19.42 + ts-node: 10.9.2(@types/node@20.19.42)(typescript@5.9.3) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + jest-diff@29.7.0: dependencies: chalk: 4.1.2 @@ -19709,6 +20394,18 @@ snapshots: - supports-color - ts-node + jest@29.7.0(@types/node@20.19.42)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)): + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)) + '@jest/types': 29.6.3 + import-local: 3.2.0 + jest-cli: 29.7.0(@types/node@20.19.42)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + jiti@1.21.7: {} jiti@2.6.1: {} @@ -20126,6 +20823,8 @@ snapshots: lodash.upperfirst@4.3.1: {} + lodash@3.10.1: {} + lodash@4.17.21: {} lodash@4.18.1: {} @@ -20145,6 +20844,11 @@ snapshots: chalk: 5.6.2 is-unicode-supported: 1.3.0 + log-update@1.0.2: + dependencies: + ansi-escapes: 1.4.0 + cli-cursor: 1.0.2 + log-update@6.1.0: dependencies: ansi-escapes: 7.3.0 @@ -20233,7 +20937,7 @@ snapshots: mantine-react-table@2.0.0-beta.9(@mantine/core@7.17.8(@mantine/hooks@7.17.8(react@19.2.6))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/dates@7.17.8(@mantine/core@7.17.8(@mantine/hooks@7.17.8(react@19.2.6))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@7.17.8(react@19.2.6))(dayjs@1.11.21)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@7.17.8(react@19.2.6))(@tabler/icons-react@3.44.0(react@19.2.6))(clsx@2.1.1)(dayjs@1.11.21)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: '@mantine/core': 7.17.8(@mantine/hooks@7.17.8(react@19.2.6))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@mantine/dates': 7.17.8(@mantine/core@7.17.8(@mantine/hooks@7.17.8(react@19.2.6))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@7.17.8(react@19.2.6))(dayjs@1.11.21)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@mantine/dates': 7.17.8(@mantine/core@9.3.0(@mantine/hooks@9.3.0(react@19.2.6))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@9.3.0(react@19.2.6))(dayjs@1.11.21)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@mantine/hooks': 7.17.8(react@19.2.6) '@tabler/icons-react': 3.44.0(react@19.2.6) '@tanstack/match-sorter-utils': 8.19.4 @@ -20436,6 +21140,8 @@ snapshots: concat-stream: 2.0.0 type-is: 1.6.18 + mute-stream@0.0.5: {} + mute-stream@2.0.0: {} mute-stream@3.0.0: {} @@ -20555,6 +21261,8 @@ snapshots: node-int64@0.4.0: {} + node-localstorage@0.6.0: {} + node-releases@2.0.47: {} normalize-path@3.0.0: {} @@ -20580,6 +21288,8 @@ snapshots: dependencies: boolbase: 1.0.0 + number-is-nan@1.0.1: {} + nwsapi@2.2.24: {} nypm@0.6.6: @@ -20658,6 +21368,8 @@ snapshots: dependencies: wrappy: 1.0.2 + onetime@1.1.0: {} + onetime@5.1.2: dependencies: mimic-fn: 2.1.0 @@ -20750,7 +21462,7 @@ snapshots: dependencies: '@tootallnate/quickjs-emscripten': 0.23.0 agent-base: 7.1.4 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3 get-uri: 6.0.5 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 @@ -20965,12 +21677,13 @@ snapshots: camelcase-css: 2.0.1 postcss: 8.5.15 - postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.15)(yaml@2.9.0): + postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.15)(tsx@4.22.4)(yaml@2.9.0): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 1.21.7 postcss: 8.5.15 + tsx: 4.22.4 yaml: 2.9.0 postcss-nested@6.2.0(postcss@8.5.15): @@ -21064,7 +21777,7 @@ snapshots: proxy-agent@6.5.0: dependencies: agent-base: 7.1.4 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 lru-cache: 7.18.3 @@ -21091,7 +21804,7 @@ snapshots: dependencies: '@puppeteer/browsers': 2.13.2 chromium-bidi: 14.0.0(devtools-protocol@0.0.1608973) - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3 devtools-protocol: 0.0.1608973 typed-query-selector: 2.12.2 webdriver-bidi-protocol: 0.4.1 @@ -21642,6 +22355,12 @@ snapshots: readdirp@4.1.2: {} + readline2@1.0.1: + dependencies: + code-point-at: 1.1.0 + is-fullwidth-code-point: 1.0.0 + mute-stream: 0.0.5 + recast@0.23.11: dependencies: ast-types: 0.16.1 @@ -21708,6 +22427,10 @@ snapshots: get-proto: 1.0.1 which-builtin-type: 1.2.1 + regenerator-runtime@0.10.5: {} + + regenerator-runtime@0.11.1: {} + regenerator-runtime@0.13.11: optional: true @@ -21782,6 +22505,11 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + restore-cursor@1.0.1: + dependencies: + exit-hook: 1.1.1 + onetime: 1.1.0 + restore-cursor@3.1.0: dependencies: onetime: 5.1.2 @@ -21855,7 +22583,7 @@ snapshots: router@2.2.0: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3 depd: 2.0.0 is-promise: 4.0.0 parseurl: 1.3.3 @@ -21869,10 +22597,16 @@ snapshots: run-applescript@7.1.0: {} + run-async@0.1.0: + dependencies: + once: 1.4.0 + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 + rx-lite@3.1.2: {} + rxjs@7.8.1: dependencies: tslib: 2.8.1 @@ -21967,7 +22701,7 @@ snapshots: send@1.2.1: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3 encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 @@ -22199,7 +22933,7 @@ snapshots: socks-proxy-agent@8.0.5: dependencies: agent-base: 7.1.4 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3 socks: 2.8.9 transitivePeerDependencies: - supports-color @@ -22316,6 +23050,12 @@ snapshots: char-regex: 1.0.2 strip-ansi: 6.0.1 + string-width@1.0.2: + dependencies: + code-point-at: 1.1.0 + is-fullwidth-code-point: 1.0.0 + strip-ansi: 3.0.1 + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -22399,6 +23139,10 @@ snapshots: is-obj: 3.0.0 is-regexp: 3.1.0 + strip-ansi@3.0.1: + dependencies: + ansi-regex: 2.1.1 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -22477,7 +23221,7 @@ snapshots: dependencies: component-emitter: 1.3.1 cookiejar: 2.1.4 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3 fast-safe-stringify: 2.1.1 form-data: 4.0.5 formidable: 3.5.4 @@ -22495,6 +23239,8 @@ snapshots: transitivePeerDependencies: - supports-color + supports-color@2.0.0: {} + supports-color@5.5.0: dependencies: has-flag: 3.0.0 @@ -22543,7 +23289,7 @@ snapshots: dependencies: tailwindcss: 4.3.0 - tailwindcss@3.4.19(yaml@2.9.0): + tailwindcss@3.4.19(tsx@4.22.4)(yaml@2.9.0): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -22562,7 +23308,7 @@ snapshots: postcss: 8.5.15 postcss-import: 15.1.0(postcss@8.5.15) postcss-js: 4.1.0(postcss@8.5.15) - postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.15)(yaml@2.9.0) + postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.15)(tsx@4.22.4)(yaml@2.9.0) postcss-nested: 6.2.0(postcss@8.5.15) postcss-selector-parser: 6.1.2 resolve: 1.22.12 @@ -22793,6 +23539,26 @@ snapshots: babel-jest: 29.7.0(@babel/core@7.29.7) jest-util: 29.7.0 + ts-jest@29.4.11(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.42)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)))(typescript@5.9.3): + dependencies: + bs-logger: 0.2.6 + fast-json-stable-stringify: 2.1.0 + handlebars: 4.7.9 + jest: 29.7.0(@types/node@20.19.42)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)) + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.8.2 + type-fest: 4.41.0 + typescript: 5.9.3 + yargs-parser: 21.1.1 + optionalDependencies: + '@babel/core': 7.29.7 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.29.7) + jest-util: 29.7.0 + ts-loader@9.6.0(typescript@5.9.3)(webpack@5.106.0): dependencies: chalk: 4.1.2 @@ -22869,6 +23635,13 @@ snapshots: tslib@2.8.1: {} + tsx@4.22.4: + dependencies: + esbuild: 0.28.1 + optionalDependencies: + fsevents: 2.3.3 + optional: true + turbo@2.9.16: optionalDependencies: '@turbo/darwin-64': 2.9.16 @@ -22961,6 +23734,19 @@ snapshots: typeorm: 0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)) yargs: 18.0.0 + typeorm-extension@3.9.0(@faker-js/faker@10.4.0)(typeorm@0.3.30(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3))): + dependencies: + '@faker-js/faker': 10.4.0 + consola: 3.4.2 + envix: 1.5.0 + locter: 2.2.1 + pascal-case: 3.1.2 + rapiq: 0.9.0 + reflect-metadata: 0.2.2 + smob: 1.6.2 + typeorm: 0.3.30(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)) + yargs: 18.0.0 + typeorm@0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)): dependencies: '@sqltools/formatter': 1.2.5 @@ -23009,6 +23795,30 @@ snapshots: - babel-plugin-macros - supports-color + typeorm@0.3.30(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3)): + dependencies: + '@sqltools/formatter': 1.2.5 + ansis: 4.3.1 + app-root-path: 3.1.0 + buffer: 6.0.3 + dayjs: 1.11.21 + debug: 4.4.3 + dedent: 1.7.2 + dotenv: 16.6.1 + glob: 10.5.0 + reflect-metadata: 0.2.2 + sha.js: 2.4.12 + sql-highlight: 6.1.0 + tslib: 2.8.1 + uuid: 11.1.1 + yargs: 17.7.2 + optionalDependencies: + pg: 8.21.0 + ts-node: 10.9.2(@types/node@20.19.42)(typescript@5.9.3) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + typescript@5.9.3: {} uglify-js@3.19.3: @@ -23351,6 +24161,19 @@ snapshots: void-elements@3.1.0: {} + vorpal@1.12.0: + dependencies: + babel-polyfill: 6.26.0 + chalk: 1.1.3 + in-publish: 2.0.1 + inquirer: 0.11.0 + lodash: 4.18.1 + log-update: 1.0.2 + minimist: 1.2.8 + node-localstorage: 0.6.0 + strip-ansi: 3.0.1 + wrap-ansi: 2.1.0 + w3c-xmlserializer@5.0.0: dependencies: xml-name-validator: 5.0.0 @@ -23520,6 +24343,11 @@ snapshots: wordwrap@1.0.0: {} + wrap-ansi@2.1.0: + dependencies: + string-width: 1.0.2 + strip-ansi: 3.0.1 + wrap-ansi@6.2.0: dependencies: ansi-styles: 4.3.0 From 4f1fc6c43950a094b0706abe142ceb4885678eb0 Mon Sep 17 00:00:00 2001 From: Stephanos A Date: Wed, 1 Jul 2026 13:31:31 +0300 Subject: [PATCH 07/20] Route stops distance and other fixes --- .../src/modules/schedules/routes.dto.ts | 1 + .../src/modules/schedules/routes.service.ts | 20 ++++- .../backoffice/src/app/boarding/page.tsx | 70 +++------------ .../backoffice/src/app/dashboard/page.tsx | 88 +------------------ .../backoffice/src/app/routes/page.tsx | 36 ++++---- 5 files changed, 52 insertions(+), 163 deletions(-) diff --git a/apps/edr-passenger-api/src/modules/schedules/routes.dto.ts b/apps/edr-passenger-api/src/modules/schedules/routes.dto.ts index 8339bf477..bce25fea5 100644 --- a/apps/edr-passenger-api/src/modules/schedules/routes.dto.ts +++ b/apps/edr-passenger-api/src/modules/schedules/routes.dto.ts @@ -42,4 +42,5 @@ export class UpdateRouteDto { @ApiPropertyOptional() @IsOptional() @IsString() description?: string; @ApiPropertyOptional({ example: true }) @IsOptional() @IsBoolean() active?: boolean; @ApiPropertyOptional({ example: '2027-12-31T23:59:59Z' }) @IsOptional() @IsDateString() effectiveUntil?: string; + @ApiPropertyOptional({ type: [RouteStopInputDto] }) @IsOptional() @IsArray() @ValidateNested({ each: true }) @Type(() => RouteStopInputDto) stops?: RouteStopInputDto[]; } diff --git a/apps/edr-passenger-api/src/modules/schedules/routes.service.ts b/apps/edr-passenger-api/src/modules/schedules/routes.service.ts index d8df838ca..2a7254f37 100644 --- a/apps/edr-passenger-api/src/modules/schedules/routes.service.ts +++ b/apps/edr-passenger-api/src/modules/schedules/routes.service.ts @@ -81,7 +81,8 @@ export class RoutesService { async updateRoute(id: string, dto: UpdateRouteDto) { const route = await this.prisma.route.findUnique({ where: { id } }); if (!route) throw new NotFoundException('Route not found'); - return this.prisma.route.update({ + + await this.prisma.route.update({ where: { id }, data: { name: dto.name, @@ -89,6 +90,22 @@ export class RoutesService { active: dto.active, effectiveUntil: dto.effectiveUntil ? new Date(dto.effectiveUntil) : undefined, }, + }); + + if (dto.stops && dto.stops.length >= 2) { + await this.prisma.routeStop.deleteMany({ where: { routeId: id } }); + await this.prisma.routeStop.createMany({ + data: dto.stops.map(s => ({ + routeId: id, + stationId: s.stationId, + sequence: s.sequence, + distanceKm: s.distanceKm != null ? parseFloat(String(s.distanceKm)) : null, + })), + }); + } + + return this.prisma.route.findUnique({ + where: { id }, include: { stops: { orderBy: { sequence: 'asc' } } }, }); } @@ -128,6 +145,7 @@ export class RoutesService { const station = await this.prisma.station.findUnique({ where: { id: dto.stationId } }); if (!station) throw new NotFoundException(`Station ${dto.stationId} not found`); + if (!station.isOperational) throw new BadRequestException(`Station ${dto.stationId} is not operational`); const existing = await this.prisma.routeStop.findUnique({ where: { routeId_sequence: { routeId, sequence: dto.sequence } }, diff --git a/apps/edr-passenger-web/backoffice/src/app/boarding/page.tsx b/apps/edr-passenger-web/backoffice/src/app/boarding/page.tsx index fd55a9c88..db5f362dc 100644 --- a/apps/edr-passenger-web/backoffice/src/app/boarding/page.tsx +++ b/apps/edr-passenger-web/backoffice/src/app/boarding/page.tsx @@ -24,8 +24,6 @@ function QRScanner({ onScan, onError }: { onScan: (data: string) => void; onErro setIsInitializing(true); setCameraError(null); - console.log('Starting camera...'); - // Check if mediaDevices is supported if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { const errorMsg = 'Camera not supported in this browser. Please use a modern browser like Chrome, Firefox, or Safari.'; @@ -45,7 +43,6 @@ function QRScanner({ onScan, onError }: { onScan: (data: string) => void; onErro let mediaStream: MediaStream | null = null; try { - console.log('Requesting back camera...'); // Try with environment (back) camera first mediaStream = await navigator.mediaDevices.getUserMedia({ video: { @@ -55,18 +52,14 @@ function QRScanner({ onScan, onError }: { onScan: (data: string) => void; onErro }, audio: false }); - console.log('Back camera acquired'); - } catch (err) { - console.warn('Back camera not available, trying default camera:', err); + } catch { // Fallback to any available camera with simple constraints try { mediaStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: false }); - console.log('Default camera acquired'); } catch (fallbackErr) { - console.error('All camera attempts failed:', fallbackErr); throw fallbackErr; } } @@ -79,7 +72,6 @@ function QRScanner({ onScan, onError }: { onScan: (data: string) => void; onErro throw new Error('Video element not found'); } - console.log('Setting video source...'); const video = videoRef.current; video.srcObject = mediaStream; @@ -98,29 +90,16 @@ function QRScanner({ onScan, onError }: { onScan: (data: string) => void; onErro if (!resolved) { resolved = true; cleanup(); - console.log('Video ready!'); resolve(); } }; - const onLoadedMetadata = () => { - console.log('Metadata loaded'); - finishResolve(); - }; + const onLoadedMetadata = () => finishResolve(); + const onLoadedData = () => finishResolve(); + const onCanPlay = () => finishResolve(); - const onLoadedData = () => { - console.log('Data loaded'); - finishResolve(); - }; - - const onCanPlay = () => { - console.log('Can play'); - finishResolve(); - }; - - const onVideoError = (e: Event) => { + const onVideoError = (_e: Event) => { cleanup(); - console.error('Video error:', e); reject(new Error('Video failed to load')); }; @@ -130,40 +109,22 @@ function QRScanner({ onScan, onError }: { onScan: (data: string) => void; onErro video.addEventListener('canplay', onCanPlay); video.addEventListener('error', onVideoError); - // Fallback timeout - but shorter since we have multiple events - setTimeout(() => { - console.log('Video load timeout, proceeding anyway'); - finishResolve(); - }, 2000); + setTimeout(() => finishResolve(), 2000); }); - // Play the video - console.log('Playing video...'); try { await video.play(); - console.log('Video playing'); - } catch (playError) { - console.warn('Play attempt 1 failed, retrying:', playError); - // Retry play after a short delay + } catch { await new Promise(resolve => setTimeout(resolve, 100)); - try { - await video.play(); - console.log('Video playing (retry succeeded)'); - } catch (retryError) { - console.warn('Play retry also failed (continuing anyway):', retryError); - } + try { await video.play(); } catch { /* continue */ } } // Set state to show video setStream(mediaStream); setIsScanning(true); setIsInitializing(false); - console.log('Camera started successfully'); - console.log('isScanning state set to:', true); - console.log('isInitializing state set to:', false); } catch (error: any) { - console.error('Camera start error:', error); let errorMsg = 'Camera access failed. Please check permissions and try again.'; @@ -224,21 +185,17 @@ function QRScanner({ onScan, onError }: { onScan: (data: string) => void; onErro const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); try { - // Try to use jsqr if available const jsQR = (window as any).jsQR; if (jsQR) { const code = jsQR(imageData.data, imageData.width, imageData.height, { inversionAttempts: 'dontInvert', }); - if (code) { onScan(code.data); stopCamera(); } } - } catch (err) { - console.error('QR scan error:', err); - } + } catch { /* ignore scan errors */ } } }, [isScanning, onScan, stopCamera]); @@ -269,11 +226,6 @@ function QRScanner({ onScan, onError }: { onScan: (data: string) => void; onErro return (
- {/* Debug info */} -
- Debug: isScanning={String(isScanning)}, isInitializing={String(isInitializing)}, stream={stream ? 'active' : 'null'} -
- {/* Video viewer - always rendered, visibility controlled by display style */}
@@ -337,9 +289,7 @@ function QRScanner({ onScan, onError }: { onScan: (data: string) => void; onErro

Please allow camera access when prompted by your browser

-

- Check console (F12) for detailed camera logs if this takes too long -

+
- +