@happyvertical/smrt-commerce 0.57.5 → 0.57.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/dist/chunks/{ContractLineItemCollection-D5hBzrct.js → ContractLineItemCollection-DQZqRiZi.js} +4 -4
  2. package/dist/chunks/{ContractLineItemCollection-D5hBzrct.js.map → ContractLineItemCollection-DQZqRiZi.js.map} +1 -1
  3. package/dist/chunks/{DocumentTaxCollection-C6cI5U89.js → DocumentTaxCollection-Dg942m_Z.js} +13 -10
  4. package/dist/chunks/DocumentTaxCollection-Dg942m_Z.js.map +1 -0
  5. package/dist/chunks/{InvoiceCollection-BolwughC.js → InvoiceCollection-XPcPyibo.js} +13 -10
  6. package/dist/chunks/InvoiceCollection-XPcPyibo.js.map +1 -0
  7. package/dist/chunks/{TaxCodeCollection-CW-tWjkU.js → TaxCodeCollection-CbTBWO8z.js} +2 -2
  8. package/dist/chunks/{TaxCodeCollection-CW-tWjkU.js.map → TaxCodeCollection-CbTBWO8z.js.map} +1 -1
  9. package/dist/chunks/{TaxComponentCollection-BiJ9aAe8.js → TaxComponentCollection-VZ_cGr2n.js} +3 -3
  10. package/dist/chunks/{TaxComponentCollection-BiJ9aAe8.js.map → TaxComponentCollection-VZ_cGr2n.js.map} +1 -1
  11. package/dist/chunks/{allocation-integrity-CH-i-hsY.js → allocation-integrity-Kr8uceRx.js} +6 -6
  12. package/dist/chunks/{allocation-integrity-CH-i-hsY.js.map → allocation-integrity-Kr8uceRx.js.map} +1 -1
  13. package/dist/chunks/{contract-money-BMsq4cpL.js → contract-money-DGNqQwf0.js} +6 -6
  14. package/dist/chunks/{contract-money-BMsq4cpL.js.map → contract-money-DGNqQwf0.js.map} +1 -1
  15. package/dist/chunks/{invoice-posting-IXic4UEP.js → invoice-posting-DVSkfSUm.js} +3 -3
  16. package/dist/chunks/{invoice-posting-IXic4UEP.js.map → invoice-posting-DVSkfSUm.js.map} +1 -1
  17. package/dist/chunks/{retention-accounting-c7kY7gFU.js → retention-accounting-Ct5Df6xx.js} +8 -8
  18. package/dist/chunks/{retention-accounting-c7kY7gFU.js.map → retention-accounting-Ct5Df6xx.js.map} +1 -1
  19. package/dist/chunks/{tenant-money-barrier-DEVLrpaB.js → tenant-money-barrier-CG78Xxja.js} +3 -3
  20. package/dist/chunks/{tenant-money-barrier-DEVLrpaB.js.map → tenant-money-barrier-CG78Xxja.js.map} +1 -1
  21. package/dist/index.js +12 -12
  22. package/dist/index.js.map +1 -1
  23. package/dist/invoices.js +1 -1
  24. package/dist/manifest.json +57 -15
  25. package/dist/models/Contract.d.ts.map +1 -1
  26. package/dist/models/Invoice.d.ts.map +1 -1
  27. package/dist/smrt-knowledge.json +3 -3
  28. package/package.json +13 -13
  29. package/dist/chunks/DocumentTaxCollection-C6cI5U89.js.map +0 -1
  30. package/dist/chunks/InvoiceCollection-BolwughC.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"InvoiceCollection-BolwughC.js","names":["field","seq"],"sources":["../../src/retention-money.ts","../../src/models/Invoice.ts","../../src/collections/InvoiceCollection.ts"],"sourcesContent":["/** Explicit retained-first settlement policy; no jurisdiction defaults. */\nimport { MoneyValidationError } from './money.js';\n\nexport interface InvoiceRetentionEvidence {\n requestId: string;\n policyVersion: string;\n evidenceRef: string;\n actorId: string;\n reason: string;\n /** Explicit business calendar date for original or current evidence; recordedAt stays actual record time. */\n effectiveOn?: string;\n sameDayCreditOrder?: 'credit-before-release' | 'release-before-credit' | null;\n}\nexport interface InvoiceRetentionRelease extends InvoiceRetentionEvidence {\n amountMinor: number;\n recordedAt: string;\n}\nexport interface InvoiceRetentionState extends InvoiceRetentionEvidence {\n version: 1;\n currency: string;\n creditPolicy: 'retained-first';\n retainedMinor: number;\n recordedAt: string;\n releases: InvoiceRetentionRelease[];\n}\nexport interface InvoicePayableFacts {\n grossMinor: number;\n retainedMinor: number;\n releasedMinor: number;\n creditedRetentionMinor: number;\n retainedRemainingMinor: number;\n allocationCapMinor: number;\n grossBalanceMinor: number;\n currentlyDueMinor: number;\n}\nfunction invalid(message: string): never {\n throw new MoneyValidationError('INVALID_MONEY_INPUT', message);\n}\nexport function assertRetentionMinor(amount: number, label: string): void {\n if (!Number.isSafeInteger(amount))\n invalid(`${label} must be a safe integer minor-unit amount`);\n}\nexport function validateRetentionEvidence(\n input: InvoiceRetentionEvidence,\n): void {\n for (const key of [\n 'requestId',\n 'policyVersion',\n 'evidenceRef',\n 'actorId',\n 'reason',\n ] as const) {\n const value = input[key];\n if (typeof value !== 'string' || !value || value.trim() !== value)\n invalid(`Retention ${key} must be nonempty trimmed text`);\n }\n}\nexport function parseInvoiceRetention(\n json: string,\n): InvoiceRetentionState | null {\n if (json === '') return null;\n let state: InvoiceRetentionState;\n try {\n state = JSON.parse(json);\n } catch {\n return invalid('Invalid retention state JSON');\n }\n if (\n !state ||\n state.version !== 1 ||\n state.creditPolicy !== 'retained-first' ||\n !Array.isArray(state.releases)\n )\n invalid('Unsupported retention state or credit policy');\n validateRetentionEvidence(state);\n if (!/^[A-Z]{3}$/.test(state.currency))\n invalid('Retention currency is required');\n const keys = new Set([state.requestId]);\n for (const event of [state, ...state.releases]) {\n validateRetentionEvidence(event);\n if (\n typeof event.recordedAt !== 'string' ||\n !Number.isFinite(Date.parse(event.recordedAt))\n )\n invalid('Retention event timestamp is required');\n if (\n event.effectiveOn !== undefined &&\n (!/^\\d{4}-\\d{2}-\\d{2}$/.test(event.effectiveOn) ||\n !Number.isFinite(Date.parse(event.effectiveOn)) ||\n new Date(event.effectiveOn).toISOString().slice(0, 10) !==\n event.effectiveOn)\n )\n invalid('Original retention event requires an exact calendar date');\n if (\n event.sameDayCreditOrder !== undefined &&\n event.sameDayCreditOrder !== null &&\n event.sameDayCreditOrder !== 'release-before-credit' &&\n event.sameDayCreditOrder !== 'credit-before-release'\n )\n invalid('Unsupported original retention release/credit ordering');\n if (event !== state) {\n if (keys.has(event.requestId))\n invalid('Duplicate retention request identity');\n keys.add(event.requestId);\n }\n }\n return state;\n}\nexport function calculateInvoicePayable(input: {\n totalAmount: number;\n creditedAmount: number;\n amountPaid: number;\n currency: string;\n retentionStateJson?: string;\n}): InvoicePayableFacts {\n for (const [name, amount] of Object.entries({\n gross: input.totalAmount,\n credits: input.creditedAmount,\n paid: input.amountPaid,\n })) {\n assertRetentionMinor(amount, name);\n if (amount < 0) invalid(`${name} cannot be negative`);\n }\n if (\n input.creditedAmount > input.totalAmount ||\n input.amountPaid > input.totalAmount\n )\n invalid('Credits or payments exceed invoice gross');\n const state = parseInvoiceRetention(input.retentionStateJson ?? '');\n const retained = state?.retainedMinor ?? 0;\n assertRetentionMinor(retained, 'Retained amount');\n if (retained < 0 || retained > input.totalAmount)\n invalid('Retention exceeds invoice gross');\n if (state && state.currency !== input.currency)\n invalid('Retention currency does not match invoice');\n let released = 0n;\n for (const event of state?.releases ?? []) {\n assertRetentionMinor(event.amountMinor, 'Released amount');\n if (event.amountMinor <= 0) invalid('Release amount must be positive');\n released += BigInt(event.amountMinor);\n }\n if (released > BigInt(retained)) invalid('Releases exceed retained amount');\n const unreleased = retained - Number(released);\n const creditedRetention = Math.min(unreleased, input.creditedAmount);\n const remaining = unreleased - creditedRetention;\n const cap = Math.max(0, input.totalAmount - input.creditedAmount - remaining);\n return {\n grossMinor: input.totalAmount,\n retainedMinor: retained,\n releasedMinor: Number(released),\n creditedRetentionMinor: creditedRetention,\n retainedRemainingMinor: remaining,\n allocationCapMinor: cap,\n grossBalanceMinor:\n input.totalAmount - input.creditedAmount - input.amountPaid,\n currentlyDueMinor: Math.max(0, cap - input.amountPaid),\n };\n}\n","/**\n * Invoice model - billing document sent to customers\n * @packageDocumentation\n */\n\nimport {\n crossPackageRef,\n field,\n foreignKey,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport type { DatabaseInterface } from '@happyvertical/smrt-core/migrations';\nimport type { Journal } from '@happyvertical/smrt-ledgers';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport {\n assertAllocationParent,\n claimAllocationParent,\n} from '../allocation-integrity.js';\nimport {\n DOCUMENT_MONEY_READ_REBIND,\n DOCUMENT_MONEY_WRITE,\n type DocumentMoneyReadRebindCapability,\n type DocumentMoneyWriteCapability,\n} from '../document-money-internal.js';\nimport type { FrozenInvoiceAccountingOptions } from '../invoice-accounting-sync.js';\nimport { assertIntegerMinorUnits, MoneyValidationError } from '../money.js';\nimport { calculateInvoicePayable } from '../retention-money.js';\nimport {\n type AccountingInvoiceInput,\n type CancelRevenueOptions,\n type InvoiceCollectionMethod,\n type InvoiceKind,\n type InvoiceOptions,\n InvoiceStatus,\n type RecognizeRevenueOptions,\n type TaxRegistrationOptions,\n} from '../types/index.js';\n\n/*\n * There is deliberately no `INVOICE_EPSILON` here any more (#2401).\n *\n * Every amount on this model is integer minor units, so `subtotal + taxAmount`\n * is exact, the sum of allocations is exact, and every comparison below is a\n * plain integer comparison. The old `0.01` tolerance existed because the values\n * were floats; keeping it against integers would silently forgive a genuine\n * one-cent discrepancy, and the \"snap `totalAmount` to `subtotal + taxAmount`\n * afterwards\" workaround it required (to stay inside the tighter smrt-ledgers\n * `BALANCE_EPSILON`) is gone with it — exact arithmetic needs no snap.\n */\n\n/**\n * Legal status transitions for an Invoice. Keyed by the prior (persisted)\n * status; the value is the set of statuses it may move to. A status mapping\n * to itself (no-op re-save) is always permitted and handled separately.\n *\n * Forward path: DRAFT → SENT → VIEWED → PARTIAL → PAID, with OVERDUE reachable\n * from any open status and CANCELLED / WRITTEN_OFF as terminal exits. Payment\n * progress (DRAFT/SENT/VIEWED ↔ PARTIAL ↔ PAID) is driven by `updatePaymentStatus`,\n * which can move both forward and backward as allocations change, so those\n * edges are bidirectional here.\n */\nconst INVOICE_STATUS_TRANSITIONS: Record<InvoiceStatus, InvoiceStatus[]> = {\n [InvoiceStatus.DRAFT]: [\n InvoiceStatus.SENT,\n InvoiceStatus.PARTIAL,\n InvoiceStatus.PAID,\n InvoiceStatus.CANCELLED,\n InvoiceStatus.WRITTEN_OFF,\n ],\n [InvoiceStatus.SENT]: [\n InvoiceStatus.VIEWED,\n InvoiceStatus.PARTIAL,\n InvoiceStatus.PAID,\n InvoiceStatus.OVERDUE,\n InvoiceStatus.CANCELLED,\n InvoiceStatus.WRITTEN_OFF,\n ],\n [InvoiceStatus.VIEWED]: [\n InvoiceStatus.SENT,\n InvoiceStatus.PARTIAL,\n InvoiceStatus.PAID,\n InvoiceStatus.OVERDUE,\n InvoiceStatus.CANCELLED,\n InvoiceStatus.WRITTEN_OFF,\n ],\n [InvoiceStatus.PARTIAL]: [\n InvoiceStatus.DRAFT,\n InvoiceStatus.SENT,\n InvoiceStatus.VIEWED,\n InvoiceStatus.PAID,\n InvoiceStatus.OVERDUE,\n InvoiceStatus.CANCELLED,\n InvoiceStatus.WRITTEN_OFF,\n ],\n [InvoiceStatus.OVERDUE]: [\n InvoiceStatus.SENT,\n InvoiceStatus.VIEWED,\n InvoiceStatus.PARTIAL,\n InvoiceStatus.PAID,\n InvoiceStatus.CANCELLED,\n InvoiceStatus.WRITTEN_OFF,\n ],\n // PAID can fall back to PARTIAL / VIEWED / SENT when a payment allocation is\n // removed or reversed (handled by updatePaymentStatus). It can also be\n // written off as bad debt in unusual reconciliation flows.\n [InvoiceStatus.PAID]: [\n InvoiceStatus.DRAFT,\n InvoiceStatus.PARTIAL,\n InvoiceStatus.VIEWED,\n InvoiceStatus.SENT,\n InvoiceStatus.OVERDUE,\n InvoiceStatus.CANCELLED,\n InvoiceStatus.WRITTEN_OFF,\n ],\n // Terminal states: no outbound transitions.\n [InvoiceStatus.CANCELLED]: [],\n [InvoiceStatus.WRITTEN_OFF]: [],\n};\n\n/**\n * Module-scoped record of the status each Invoice instance was loaded with.\n * Used by the save-time status-transition guard to compare the prior\n * persisted status against the one being written, without adding a\n * persisted column. A WeakMap keyed by the instance keeps it out of the\n * schema and garbage-collects with the instance — same pattern LicenseSale\n * uses for its rights snapshot.\n */\nconst loadedInvoiceStatus = new WeakMap<Invoice, InvoiceStatus>();\n\n/**\n * Invoice represents a bill sent to a customer for goods or services.\n *\n * Invoices are distinct from Contracts - a Contract is an agreement,\n * while an Invoice is the billing document requesting payment.\n *\n * Invoices integrate with:\n * - `@happyvertical/smrt-ledgers` for revenue recognition (double-entry accounting)\n * - `@happyvertical/accounting` SDK for syncing with external providers (QBO, Stripe)\n *\n * @example\n * ```typescript\n * // Create an invoice\n * const invoice = await invoices.create({\n * customerId: customer.id,\n * invoiceNumber: await invoices.generateInvoiceNumber(),\n * issueDate: new Date(),\n * dueDate: addDays(new Date(), 30),\n * subtotal: 1000,\n * taxAmount: 50,\n * totalAmount: 1050,\n * currency: 'CAD'\n * });\n *\n * // Recognize revenue in ledger\n * await invoice.recognizeRevenue({\n * arAccountId: arAccount.id,\n * revenueAccountId: revenueAccount.id,\n * taxAccountId: taxAccount.id\n * });\n * ```\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n // ROOT FIX (S5 audit #1390 round 4): the generated create/update surface may\n // only set the billing-document descriptors (who/when/identifiers). The\n // derived/integrity amounts (`subtotal`, `taxAmount`, `totalAmount`,\n // `amountPaid`) and `status` are EXCLUDED — totals are derived from line\n // items, amountPaid from PaymentAllocations, and status from\n // updatePaymentStatus()/the lifecycle helpers. A caller can therefore create\n // a DRAFT invoice (customer / dueDate / line-item refs) but can never forge a\n // total, an amountPaid, or a PAID status through a generated route. Ledger\n // journal refs and communication timestamps are server-managed too.\n api: {\n include: ['list', 'get', 'create', 'update'],\n writable: [\n 'customerId',\n 'contractId',\n 'invoiceNumber',\n 'reference',\n 'issueDate',\n 'dueDate',\n 'currency',\n 'lineAmountType',\n 'taxRoundingScope',\n 'notes',\n 'customerNotes',\n 'terms',\n 'externalId',\n 'customerExternalId',\n 'externalProvider',\n ],\n },\n // NOTE: `send` and `recognizeRevenue` are intentionally NOT exposed over\n // MCP. `recognizeRevenue` posts a balanced journal into smrt-ledgers\n // (i.e. moves money in the books) and `send` transmits a billing document\n // to a customer — neither is safe as an unauthenticated/unguarded MCP tool.\n // Generated MCP tools carry no authz; financial mutations must go through\n // application code that enforces permissions. MCP create/update honor the\n // same `api.writable` allowlist, so status/amounts are unsettable over MCP\n // too. See S5 audit #1390.\n mcp: {\n include: ['list', 'get'],\n serializers: {\n get: {\n importPath: '@happyvertical/smrt-commerce',\n exportName: 'serializeInvoiceMcpGet',\n },\n },\n },\n cli: { skipApiCheck: true },\n indexes: [\n {\n name: 'invoice_historical_source_identity',\n columns: ['tenantId', 'historicalSourceKeyHash'],\n unique: true,\n },\n ],\n})\nexport class Invoice extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-commerce\";\n /** Command-owned original sales authority; ordinary documents stay calculated. */\n @field({\n description:\n 'Whether amounts were calculated or retained from an original issued invoice.',\n })\n moneyAuthority: 'calculated' | 'historical' = 'calculated';\n historicalSalesMoneyJson = '';\n @field({ type: 'text', nullable: true }) historicalSourceKeyHash:\n | string\n | null = null;\n\n /** @internal Collection read guard returns this snapshot on its root DB. */\n rebindMoneyRead(\n capability: DocumentMoneyReadRebindCapability,\n db: DatabaseInterface,\n ): this {\n if (capability !== DOCUMENT_MONEY_READ_REBIND)\n throw new MoneyValidationError(\n 'FROZEN_DOCUMENT',\n 'Invoice read rebinding requires the owning capability',\n );\n this._db = db;\n this.options.db = db;\n return this;\n }\n\n @field({ description: 'Invoice or customer credit note.' })\n kind: InvoiceKind = 'invoice';\n\n @foreignKey('Invoice', { nullable: true })\n creditedInvoiceId: string | null = null;\n\n /** Issued credit-note total cached under the source invoice lock. */\n @field({ ui: { format: 'money' } })\n creditedAmount = 0;\n\n /** Server-owned immutable retention policy and append-only release evidence. */\n retentionStateJson = '';\n\n /** Command-owned durable provider retention bundle; never caller-writable. */\n @field({ sensitive: true })\n retentionAccountingStateJson = '';\n\n /** Command-owned ordinary provider adjustments; no retention agreement. */\n @field({ sensitive: true })\n ordinaryAccountingStateJson = '';\n\n getPayableFacts() {\n return calculateInvoicePayable(this);\n }\n\n /**\n * Tenant ID for multi-tenant isolation\n * Nullable to support both tenant-scoped and global invoices\n */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /**\n * Customer this invoice is for\n */\n @field({ description: 'The customer being billed.' })\n @foreignKey('Customer')\n customerId: string = '';\n\n /**\n * Optional link to Contract (cross-package reference)\n */\n @field({\n description: 'The order or agreement this invoice bills for, if any.',\n })\n @foreignKey('SalesContract', { validateSubtype: true })\n contractId: string = '';\n\n // ============================================================================\n // Identification\n // ============================================================================\n\n /**\n * Invoice number (e.g., INV-2025-0001)\n * Generated via InvoiceCollection.generateInvoiceNumber()\n */\n @field({ description: 'The number printed on the invoice.' })\n invoiceNumber: string = '';\n\n /**\n * External reference (e.g., customer PO number)\n */\n reference: string = '';\n\n // ============================================================================\n // Dates\n // ============================================================================\n\n /**\n * Date invoice was issued\n */\n @field({ description: 'The date the invoice was issued.' })\n issueDate: Date = new Date();\n\n /**\n * Payment due date\n */\n @field({\n type: 'datetime',\n nullable: true,\n description:\n 'The date payment is expected; null when the original source did not establish it.',\n })\n dueDate: Date | null = new Date();\n\n /**\n * Date invoice was fully paid\n */\n @field({ description: 'The date it was paid in full.' })\n paidDate: Date | null = null;\n\n // ============================================================================\n // Amounts\n // ============================================================================\n\n /**\n * Subtotal before tax, in **integer minor units** (cents, satoshis).\n *\n * The `= 0` initializer is load-bearing: SMRT maps an integer literal to\n * INTEGER and a decimal literal to DECIMAL. Money is exact, so it is stored\n * as minor units and never as a float — `$19.99` is `1999`, not `19.99`.\n * Writing a fractional major-unit value here is the bug; PostgreSQL rejects\n * it with `22P02` while SQLite's affinity silently stores it (#2361).\n */\n @field({ description: 'The amount before tax.', ui: { format: 'money' } })\n subtotal: number = 0;\n\n /**\n * Tax amount, in integer minor units (#2361). With line items this is the\n * sum of their rate-based tax plus {@link providerTaxAmount}.\n */\n @field({ description: 'The tax charged.', ui: { format: 'money' } })\n taxAmount: number = 0;\n\n /**\n * Tax calculated by the payment provider (for example Stripe Tax) from the\n * customer's tax location, in integer minor units (#3060). Server-managed:\n * billing-period close records it after the provider finalizes the invoice.\n * It is added to the line items' tax, so `taxAmount` and `totalAmount` stay\n * authoritative from line items plus this one provider figure.\n */\n @field({ ui: { format: 'money' } })\n providerTaxAmount: number = 0;\n\n /**\n * Total amount due (subtotal + tax), in integer minor units (#2361).\n */\n @field({\n description: 'What the customer owes in all, tax included.',\n ui: { format: 'money' },\n })\n totalAmount: number = 0;\n\n /**\n * Amount paid (sum of PaymentAllocations), in integer minor units (#2361).\n */\n @field({\n description: 'How much of the total has been paid so far.',\n ui: { format: 'money' },\n })\n amountPaid: number = 0;\n\n /**\n * Currency code (ISO 4217)\n */\n @field({\n description: 'The currency of the invoice.',\n ui: { widget: 'currency' },\n })\n currency: string = 'CAD';\n\n /** Pricing interpretation fixed for the document before issue. */\n lineAmountType: 'exclusive' | 'inclusive' | 'none' = 'exclusive';\n\n /** Component rounding scope fixed for the document before issue. */\n taxRoundingScope: 'line' | 'document' = 'line';\n\n /** Informational sum of resolved line discounts, in minor units. */\n @field({ ui: { format: 'money' } })\n discountTotal = 0;\n\n /** Immutable seller registration snapshot once the invoice leaves draft. */\n sellerTaxRegistrationsJson = '[]';\n\n get sellerTaxRegistrations(): TaxRegistrationOptions[] {\n try {\n const value: unknown = JSON.parse(this.sellerTaxRegistrationsJson);\n if (!Array.isArray(value)) return [];\n return value.filter(\n (entry): entry is TaxRegistrationOptions =>\n !!entry &&\n typeof entry === 'object' &&\n typeof (entry as TaxRegistrationOptions).taxComponentId ===\n 'string' &&\n typeof (entry as TaxRegistrationOptions).number === 'string' &&\n typeof (entry as TaxRegistrationOptions).label === 'string',\n );\n } catch {\n return [];\n }\n }\n\n set sellerTaxRegistrations(value: TaxRegistrationOptions[]) {\n this.sellerTaxRegistrationsJson = JSON.stringify(value);\n }\n\n /** Immutable customer tax identifier snapshot once issued. */\n partyTaxId = '';\n\n /** Stable issue/freeze identity, independent of lifecycle updated_at. */\n moneySnapshotId = '';\n\n // ============================================================================\n // Status\n // ============================================================================\n\n /**\n * Current invoice status\n */\n @field({\n description:\n 'Where the invoice stands: draft, sent, viewed, paid, overdue or cancelled.',\n })\n status: InvoiceStatus = InvoiceStatus.DRAFT;\n\n // ============================================================================\n // Ledger Integration\n // ============================================================================\n\n /**\n * Journal ID for AR recognition (cross-package ref to smrt-ledgers)\n */\n @crossPackageRef('@happyvertical/smrt-ledgers:Journal')\n arJournalId: string = '';\n\n /** Posted journal that exactly reverses arJournalId on cancellation. */\n @crossPackageRef('@happyvertical/smrt-ledgers:Journal', { nullable: true })\n arReversalJournalId: string | null = null;\n\n /**\n * Journal ID for revenue recognition (cross-package ref to smrt-ledgers)\n */\n @crossPackageRef('@happyvertical/smrt-ledgers:Journal')\n revenueJournalId: string = '';\n\n // ============================================================================\n // Provider Sync\n // ============================================================================\n\n /**\n * External ID in accounting provider (e.g., QBO invoice ID)\n */\n externalId: string = '';\n\n /**\n * Customer's external ID in accounting provider.\n * Used to link invoice to customer in external system.\n */\n customerExternalId: string = '';\n\n /**\n * Accounting provider name ('quickbooks' | 'stripe' | etc.)\n */\n externalProvider: string = '';\n\n /**\n * When invoice was last synced to provider\n */\n syncedAt: Date | null = null;\n\n /** Server-owned prepared/in-flight/result identity for frozen accounting sync. */\n @field({ sensitive: true })\n accountingSyncStateJson = '';\n\n /**\n * How the provider collects this invoice (#3190), decided once by billing\n * period close before its first push and reused on every retry, so it is\n * what the provider was asked for. Server-managed. A host must not offer\n * another payment rail on a `charge_automatically` invoice the provider is\n * still collecting.\n */\n collectionMethod: InvoiceCollectionMethod = '';\n\n // ============================================================================\n // Communication\n // ============================================================================\n\n /**\n * When invoice was sent to customer\n */\n sentAt: Date | null = null;\n\n /**\n * When customer viewed the invoice\n */\n viewedAt: Date | null = null;\n\n /**\n * Number of payment reminders sent\n */\n remindersSent: number = 0;\n\n /**\n * When last reminder was sent\n */\n lastReminderAt: Date | null = null;\n\n // ============================================================================\n // Notes\n // ============================================================================\n\n /**\n * Internal notes (not shown to customer)\n */\n @field({\n description: 'Private notes, not shown to the customer.',\n ui: { widget: 'textarea' },\n })\n notes: string = '';\n\n /**\n * Notes shown to customer on invoice\n */\n @field({\n description: 'A message shown to the customer on the invoice.',\n ui: { widget: 'textarea' },\n })\n customerNotes: string = '';\n\n /**\n * Payment terms text\n */\n @field({\n description: 'The payment conditions, such as Net 30.',\n ui: { widget: 'textarea' },\n })\n terms: string = '';\n\n constructor(options: InvoiceOptions = {}) {\n super(options);\n if (options.kind !== undefined) this.kind = options.kind;\n if (options.creditedInvoiceId !== undefined)\n this.creditedInvoiceId = options.creditedInvoiceId;\n if (options.moneyAuthority !== undefined)\n this.moneyAuthority = options.moneyAuthority;\n if (options.historicalSalesMoneyJson !== undefined)\n this.historicalSalesMoneyJson = options.historicalSalesMoneyJson;\n if (options.historicalSourceKeyHash !== undefined)\n this.historicalSourceKeyHash = options.historicalSourceKeyHash;\n if (options.creditedAmount !== undefined)\n this.creditedAmount = options.creditedAmount;\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.customerId !== undefined) this.customerId = options.customerId;\n if (options.contractId !== undefined) this.contractId = options.contractId;\n if (options.invoiceNumber !== undefined)\n this.invoiceNumber = options.invoiceNumber;\n if (options.reference !== undefined) this.reference = options.reference;\n if (options.issueDate !== undefined) this.issueDate = options.issueDate;\n if (options.dueDate !== undefined) this.dueDate = options.dueDate;\n if (options.paidDate !== undefined) this.paidDate = options.paidDate;\n if (options.subtotal !== undefined) this.subtotal = options.subtotal;\n if (options.taxAmount !== undefined) this.taxAmount = options.taxAmount;\n if (options.providerTaxAmount !== undefined)\n this.providerTaxAmount = options.providerTaxAmount;\n if (options.totalAmount !== undefined)\n this.totalAmount = options.totalAmount;\n if (options.amountPaid !== undefined) this.amountPaid = options.amountPaid;\n if (options.currency !== undefined) this.currency = options.currency;\n if (options.lineAmountType !== undefined)\n this.lineAmountType = options.lineAmountType;\n if (options.taxRoundingScope !== undefined)\n this.taxRoundingScope = options.taxRoundingScope;\n if (options.discountTotal !== undefined)\n this.discountTotal = options.discountTotal;\n if (options.sellerTaxRegistrationsJson !== undefined)\n this.sellerTaxRegistrationsJson = options.sellerTaxRegistrationsJson;\n if (options.sellerTaxRegistrations !== undefined)\n this.sellerTaxRegistrations = structuredClone(\n options.sellerTaxRegistrations,\n );\n if (options.partyTaxId !== undefined) this.partyTaxId = options.partyTaxId;\n if (options.moneySnapshotId !== undefined)\n this.moneySnapshotId = options.moneySnapshotId;\n if (options.status !== undefined) this.status = options.status;\n if (options.arJournalId !== undefined)\n this.arJournalId = options.arJournalId;\n if (options.arReversalJournalId !== undefined)\n this.arReversalJournalId = options.arReversalJournalId;\n if (options.revenueJournalId !== undefined)\n this.revenueJournalId = options.revenueJournalId;\n if (options.externalId !== undefined) this.externalId = options.externalId;\n if (options.customerExternalId !== undefined)\n this.customerExternalId = options.customerExternalId;\n if (options.externalProvider !== undefined)\n this.externalProvider = options.externalProvider;\n if (options.syncedAt !== undefined) this.syncedAt = options.syncedAt;\n if (options.accountingSyncStateJson !== undefined)\n this.accountingSyncStateJson = options.accountingSyncStateJson;\n if (options.collectionMethod !== undefined)\n this.collectionMethod = options.collectionMethod;\n if (options.sentAt !== undefined) this.sentAt = options.sentAt;\n if (options.viewedAt !== undefined) this.viewedAt = options.viewedAt;\n if (options.remindersSent !== undefined)\n this.remindersSent = options.remindersSent;\n if (options.lastReminderAt !== undefined)\n this.lastReminderAt = options.lastReminderAt;\n if (options.notes !== undefined) this.notes = options.notes;\n if (options.customerNotes !== undefined)\n this.customerNotes = options.customerNotes;\n if (options.terms !== undefined) this.terms = options.terms;\n }\n\n /**\n * Capture the persisted status the row was loaded with, so the save-time\n * transition guard can reject illegal status flips made via raw field\n * assignment (mass-assignment on a generated update route, a stale caller,\n * etc.). Only rows that already exist in the database carry a \"prior\"\n * status — freshly-constructed (not-yet-saved) invoices have no prior and\n * may start in any status.\n */\n override async initialize(): Promise<this> {\n await super.initialize();\n // A row read from the database must not be old-format money data.\n if (this.isPersisted) {\n const { assertHydratedMoneyRowCurrent } = await import(\n '../upgrade/detect.js'\n );\n await assertHydratedMoneyRowCurrent(this);\n }\n if (await this.isSaved()) {\n loadedInvoiceStatus.set(this, this.status);\n }\n return this;\n }\n\n // ============================================================================\n // Save-time financial-integrity guard (S5 audit #1390)\n // ============================================================================\n\n /**\n * Recompute and validate financial fields before every write so forged\n * totals, negative amounts, and illegal status flips can't be persisted via\n * raw mass-assignment on the generated CRUD routes.\n *\n * Behaviour:\n * - **Totals are authoritative from line items.** A draft's `subtotal` /\n * `discountTotal` / `taxAmount` / `totalAmount` are recomputed from its\n * lines and tax codes on every save, whatever the caller sent; a new\n * invoice with no lines starts at zero. Issued invoices are frozen.\n * - **amountPaid is derived/validated.** When persisted, it is recomputed\n * from PaymentAllocations rather than trusted from the caller. It may\n * never exceed `totalAmount`, and a new invoice cannot start paid.\n * - **Whole minor units and non-negativity** are enforced on all amounts.\n * - **Status transitions** are validated against the prior persisted status.\n */\n override async save(): Promise<this> {\n const { saveInvoice } = await import('../document-money.js');\n return (await saveInvoice(this)) as this;\n }\n\n /** @internal Aggregate persistence only. */\n async saveDerived(capability: DocumentMoneyWriteCapability): Promise<this> {\n if (capability !== DOCUMENT_MONEY_WRITE)\n throw new Error('Invoice money write capability is required');\n await claimAllocationParent(this, 'invoice');\n const persisted = await this.isSaved();\n const prior = await this.resolvePriorStatus(persisted);\n\n this.assertAmountsAreMinorUnits();\n if (persisted && this.id) await this.recomputeAmountPaid();\n else {\n // A new invoice has no PaymentAllocations behind it, so it cannot\n // start paid: payment status is derived from allocations.\n this.amountPaid = 0;\n if (\n this.status === InvoiceStatus.PAID ||\n this.status === InvoiceStatus.PARTIAL\n )\n throw new Error(\n `Invoice ${this.invoiceNumber || '<new>'}: a new invoice cannot start ` +\n `in status '${this.status}' — payment status is derived from ` +\n 'PaymentAllocations, not set at creation. Create the invoice unpaid ' +\n '(DRAFT / SENT) and record payments via allocations.',\n );\n }\n this.assertNonNegativeAmounts();\n this.assertStatusTransition(prior);\n this.assertPaymentStatusConsistent();\n const payable = calculateInvoicePayable(this);\n if (\n (this.retentionAccountingStateJson || this.ordinaryAccountingStateJson) &&\n [InvoiceStatus.CANCELLED, InvoiceStatus.WRITTEN_OFF].includes(this.status)\n )\n throw new MoneyValidationError(\n 'ACCOUNTING_SYNC_RECONCILIATION_REQUIRED',\n 'Provider retention cannot be voided or written off without an explicit reconciled reversal contract',\n );\n if (\n (this.retentionAccountingStateJson || this.ordinaryAccountingStateJson) &&\n (this.collectionMethod || this.providerTaxAmount)\n )\n throw new MoneyValidationError(\n 'INVALID_MONEY_INPUT',\n 'Retention accounting does not support provider collection or tax overrides',\n );\n if (\n payable.retainedRemainingMinor > 0 &&\n !this.retentionAccountingStateJson &&\n (this.externalId ||\n this.externalProvider ||\n this.accountingSyncStateJson ||\n this.collectionMethod ||\n this.providerTaxAmount)\n )\n throw new MoneyValidationError(\n 'INVALID_MONEY_INPUT',\n 'Unreleased retention requires an explicit provider retention contract',\n );\n await this.assertDraftDeliveryHistory(persisted);\n\n await assertAllocationParent(this, 'invoice');\n const result = (await super.save()) as this;\n loadedInvoiceStatus.set(this, this.status);\n return result;\n }\n\n override async delete(\n options: { expectedUpdatedAt?: Date | string } = {},\n ): Promise<void> {\n const { deleteInvoice } = await import('../document-money.js');\n await deleteInvoice(this, options);\n }\n\n /** @internal Aggregate persistence only. */\n async deleteDerived(\n capability: DocumentMoneyWriteCapability,\n options: { expectedUpdatedAt?: Date | string } = {},\n ): Promise<void> {\n if (capability !== DOCUMENT_MONEY_WRITE)\n throw new Error('Invoice money write capability is required');\n await super.delete(options);\n }\n\n /**\n * Resolve the AUTHORITATIVE prior status (S5 audit #1390 round 4). The\n * {@link loadedInvoiceStatus} WeakMap is only populated when {@link initialize}\n * hydrated the row, so a `create({ id: <existing>, _skipLoad: true })` upsert\n * yields an instance whose WeakMap entry is missing — trusting it would treat\n * the write as a brand-new row and skip the transition guard entirely. Read\n * the persisted row's status directly so a create-onto-existing is correctly\n * treated as an update. `undefined` means no row exists (genuinely new).\n */\n private async resolvePriorStatus(\n persisted: boolean,\n ): Promise<InvoiceStatus | undefined> {\n if (persisted && this.id) {\n try {\n const row = await this.db.get(this.tableName, { id: this.id });\n if (row && row.status != null) {\n return row.status as InvoiceStatus;\n }\n } catch {\n // DB not ready — fall through to the in-memory record.\n }\n }\n return loadedInvoiceStatus.get(this);\n }\n\n private async recomputeAmountPaid(): Promise<void> {\n const { PaymentAllocationCollection } = await import(\n '../collections/PaymentAllocationCollection.js'\n );\n const allocationCollection = await PaymentAllocationCollection.create({\n ...this.options,\n db: this.db,\n });\n if (!this.id) throw new Error('Persisted invoice is missing its ID');\n this.amountPaid = await allocationCollection.getTotalAllocatedToInvoice(\n this.id,\n );\n }\n\n /**\n * Whether `amountPaid` covers `totalAmount`. This is the SINGLE source of\n * truth for the **PAID** decision — both {@link updatePaymentStatus} (which\n * decides PAID) and {@link assertPaymentStatusConsistent} (which validates\n * PAID on save) call it, so the PAID-deciding comparison and the\n * PAID-validating comparison can never drift apart (S5 audit #1390\n * follow-up).\n *\n * With integer minor units this is a plain `>=` (#2401). The float-era\n * hazard it used to guard against — a total summed from `0.1 × 3` line items\n * reading as \"not covered\" by `>=` but \"covered\" by an epsilon-tolerant\n * guard, leaving a genuinely-paid invoice unsaveable — cannot arise when both\n * sides are exact integers. That also removes the documented PAID/PARTIAL\n * asymmetry: {@link updatePaymentStatus} and {@link isPartiallyPaid} now\n * agree that any `amountPaid > 0` is a partial payment, because there is no\n * such thing as sub-cent dust.\n */\n private isFullyPaid(): boolean {\n return this.amountPaid + this.creditedAmount >= this.totalAmount;\n }\n\n /**\n * Whether `amountPaid` is a non-trivial partial payment of `totalAmount`.\n * Derived from {@link isFullyPaid} so the two stay mutually exclusive.\n */\n private isPartiallyPaid(): boolean {\n return this.amountPaid + this.creditedAmount > 0 && !this.isFullyPaid();\n }\n\n /**\n * After amounts are recomputed and amountPaid is re-derived from allocations,\n * assert the persisted `status` is consistent with the derived\n * amountPaid-vs-totalAmount relationship. This blocks the raw\n * `SENT → PAID with amountPaid=0` flip (and its inverse, claiming PARTIAL/SENT\n * while fully allocated) that the status-transition map alone permits because\n * SENT → PAID is a structurally legal edge.\n *\n * Only enforced for the payment-derived statuses (PAID / PARTIAL and the\n * unpaid states DRAFT / SENT / VIEWED). Lifecycle statuses that aren't a\n * function of amountPaid — OVERDUE, CANCELLED, WRITTEN_OFF — are left\n * to their own transition rules.\n */\n private assertPaymentStatusConsistent(): void {\n const label = this.invoiceNumber || this.id || '<new>';\n const fullyPaid = this.isFullyPaid();\n const partiallyPaid = this.isPartiallyPaid();\n\n if (this.status === InvoiceStatus.DRAFT && this.amountPaid !== 0) {\n throw new Error(\n `Invoice ${label}: DRAFT requires zero derived payment allocations.`,\n );\n }\n if (this.status === InvoiceStatus.PAID && !fullyPaid) {\n throw new Error(\n `Invoice ${label}: status is PAID but derived amountPaid ${this.amountPaid} ` +\n `does not cover totalAmount ${this.totalAmount}. Payment status is ` +\n 'derived from PaymentAllocations — use updatePaymentStatus().',\n );\n }\n if (this.status === InvoiceStatus.PARTIAL && !partiallyPaid) {\n throw new Error(\n `Invoice ${label}: status is PARTIAL but derived amountPaid ${this.amountPaid} ` +\n `is not a partial payment of totalAmount ${this.totalAmount}. Payment ` +\n 'status is derived from PaymentAllocations — use updatePaymentStatus().',\n );\n }\n // Claiming an unpaid open status (SENT / VIEWED) while the invoice is in\n // fact fully covered by allocations is also inconsistent.\n if (\n (this.status === InvoiceStatus.SENT ||\n this.status === InvoiceStatus.VIEWED) &&\n this.totalAmount > 0 &&\n fullyPaid\n ) {\n throw new Error(\n `Invoice ${label}: status is '${this.status}' but derived amountPaid ` +\n `${this.amountPaid} fully covers totalAmount ${this.totalAmount}. ` +\n 'Use updatePaymentStatus() so the status reflects the allocations.',\n );\n }\n }\n\n /** A payment reversal cannot erase an actual delivery event. */\n private async assertDraftDeliveryHistory(persisted: boolean): Promise<void> {\n if (this.status !== InvoiceStatus.DRAFT) return;\n if (this.sentAt || this.viewedAt) {\n throw new Error('DRAFT requires an undelivered invoice');\n }\n if (persisted && this.id) {\n const { InvoiceCollection } = await import(\n '../collections/InvoiceCollection.js'\n );\n const invoices = await InvoiceCollection.create({ db: this.db });\n const prior = await invoices.get({ id: this.id }, { cache: false });\n if (prior?.sentAt || prior?.viewedAt) {\n throw new Error(\n 'DRAFT cannot erase persisted invoice delivery history',\n );\n }\n }\n }\n\n /**\n * Reject amounts that are not whole minor units, negative financial values,\n * and an amountPaid that exceeds the total (overpayment is modelled\n * elsewhere, not by letting amountPaid float above the invoice total).\n */\n private assertAmountsAreMinorUnits(): void {\n assertIntegerMinorUnits(\n 'Invoice',\n this.invoiceNumber || this.id || '<new>',\n [\n ['subtotal', this.subtotal],\n ['taxAmount', this.taxAmount],\n ['providerTaxAmount', this.providerTaxAmount],\n ['totalAmount', this.totalAmount],\n ['amountPaid', this.amountPaid],\n ['creditedAmount', this.creditedAmount],\n ],\n );\n }\n\n private assertNonNegativeAmounts(): void {\n const label = this.invoiceNumber || this.id || '<new>';\n const amounts = [\n ['subtotal', this.subtotal],\n ['taxAmount', this.taxAmount],\n ['providerTaxAmount', this.providerTaxAmount],\n ['totalAmount', this.totalAmount],\n ['amountPaid', this.amountPaid],\n ['creditedAmount', this.creditedAmount],\n ] as const;\n // Re-checked after the recompute: line-item sums and the allocation total\n // feed these, so integer-ness has to hold for the derived values too — it\n // is what lets every comparison below drop its epsilon.\n assertIntegerMinorUnits('Invoice', label, amounts);\n for (const [field, value] of amounts) {\n if (value < 0) {\n throw new Error(\n `Invoice ${label}: ${field} must be a non-negative number (got ${value}).`,\n );\n }\n }\n if (this.amountPaid > this.totalAmount) {\n throw new Error(\n `Invoice ${label}: amountPaid ${this.amountPaid} cannot exceed totalAmount ${this.totalAmount}.`,\n );\n }\n }\n\n /**\n * Reject an illegal status flip done via raw field assignment. Compares the\n * about-to-be-written status against the status the row was loaded with.\n * No-op transitions (status unchanged) and brand-new rows are always allowed.\n */\n private assertStatusTransition(prior: InvoiceStatus | undefined): void {\n if (prior === undefined) return; // new row — any starting status is fine\n if (prior === this.status) return; // no-op re-save\n const allowed = INVOICE_STATUS_TRANSITIONS[prior] ?? [];\n if (!allowed.includes(this.status)) {\n throw new Error(\n `Invoice ${this.invoiceNumber || this.id}: illegal status transition ` +\n `'${prior}' → '${this.status}'. Use the guarded transition helpers ` +\n '(markSent / markViewed / updatePaymentStatus / cancel / writeOff).',\n );\n }\n }\n\n // ============================================================================\n // Status Helpers\n // ============================================================================\n\n /**\n * Check if invoice is a draft\n */\n isDraft(): boolean {\n return this.status === InvoiceStatus.DRAFT;\n }\n\n /**\n * Check if invoice has been sent\n */\n isSent(): boolean {\n return this.status === InvoiceStatus.SENT;\n }\n\n /**\n * Check if invoice is fully paid\n */\n isPaid(): boolean {\n return this.status === InvoiceStatus.PAID;\n }\n\n /**\n * Check if invoice is partially paid\n */\n isPartial(): boolean {\n return this.status === InvoiceStatus.PARTIAL;\n }\n\n /**\n * Check if invoice is overdue\n */\n isOverdue(): boolean {\n if (this.getAmountDue() === 0) return false;\n if (this.status === InvoiceStatus.OVERDUE) return true;\n if (this.isPaid() || this.status === InvoiceStatus.CANCELLED) return false;\n return this.dueDate !== null && new Date() > this.dueDate;\n }\n\n /**\n * Get remaining amount due\n */\n getAmountDue(): number {\n return this.getPayableFacts().currentlyDueMinor;\n }\n\n /** Signed amount still owed after payments and issued credit notes. */\n getBalance(): number {\n return this.totalAmount - this.amountPaid - this.creditedAmount;\n }\n\n // ============================================================================\n // Status Transitions\n // ============================================================================\n\n /**\n * Mark invoice as sent\n */\n markSent(): void {\n // Payment progress and actual delivery are independent. A prepaid invoice\n // may be sent later; preserve its allocation-derived status and first send.\n if (\n this.status === InvoiceStatus.PARTIAL ||\n this.status === InvoiceStatus.PAID\n ) {\n this.sentAt ??= new Date();\n return;\n }\n if (this.status !== InvoiceStatus.DRAFT) {\n throw new Error(\n `Cannot send invoice with status '${this.status}'. Only draft or payment-progress invoices can be sent.`,\n );\n }\n this.status = InvoiceStatus.SENT;\n this.sentAt = new Date();\n }\n\n /**\n * Record that the invoice was viewed by the customer.\n *\n * This method is idempotent - calling it multiple times will only\n * record the first view time. Status only transitions to VIEWED if\n * the current status is SENT (other statuses like PARTIAL or PAID\n * are preserved).\n */\n markViewed(): void {\n if (this.viewedAt) return; // Already viewed\n this.viewedAt = new Date();\n if (this.status === InvoiceStatus.SENT) {\n this.status = InvoiceStatus.VIEWED;\n }\n }\n\n /**\n * Update payment amount and status.\n *\n * Called when PaymentAllocations change. Handles both forward transitions\n * (DRAFT/SENT → PARTIAL → PAID) and reversals (PAID → PARTIAL → original status).\n *\n * Terminal statuses (CANCELLED, WRITTEN_OFF) are not modified.\n */\n updatePaymentStatus(amountPaid: number): void {\n this.amountPaid = amountPaid;\n\n // Do not change payment status for terminal states\n if (\n this.status === InvoiceStatus.CANCELLED ||\n this.status === InvoiceStatus.WRITTEN_OFF\n ) {\n return;\n }\n\n // Use the SAME epsilon-tolerant \"fully paid\" test the save-time guard\n // (assertPaymentStatusConsistent) applies, so a float-summed total paid\n // exactly (e.g. 0.1×3 line items paid 0.3) is treated as PAID by both —\n // not PARTIAL here and then rejected on save (S5 audit #1390 follow-up).\n if (this.isFullyPaid()) {\n if (\n this.moneyAuthority !== 'historical' &&\n (this.status !== InvoiceStatus.PAID || !this.paidDate)\n ) {\n this.paidDate = new Date();\n }\n this.status = InvoiceStatus.PAID;\n } else if (amountPaid + this.creditedAmount > 0) {\n this.status = InvoiceStatus.PARTIAL;\n this.paidDate = null; // Clear paidDate if no longer fully paid\n } else {\n // No payment remaining: revert to the appropriate pre-payment status\n this.paidDate = null;\n if (this.viewedAt) {\n this.status = InvoiceStatus.VIEWED;\n } else if (this.sentAt || this.moneyAuthority === 'historical') {\n this.status = InvoiceStatus.SENT;\n } else {\n this.status = InvoiceStatus.DRAFT;\n }\n }\n }\n\n /**\n * Cancel the invoice\n */\n cancel(): void {\n if (\n (this.kind === 'invoice' && this.isPaid()) ||\n (this.kind === 'credit_note' && this.amountPaid > 0)\n ) {\n throw new Error(\n `Cannot cancel ${this.kind} with status '${this.status}' and refunded/paid amount ${this.amountPaid}.`,\n );\n }\n this.status = InvoiceStatus.CANCELLED;\n }\n\n /** Cancel a posted invoice with an exact atomic journal reversal. */\n async cancelWithRevenueReversal(\n options: CancelRevenueOptions,\n ): Promise<Journal> {\n const { cancelInvoiceWithRevenueReversal, rebindJournal } = await import(\n '../invoice-posting.js'\n );\n return rebindJournal(\n this.db,\n await cancelInvoiceWithRevenueReversal(this, options),\n );\n }\n\n /**\n * Write off the invoice (bad debt)\n */\n writeOff(): void {\n this.status = InvoiceStatus.WRITTEN_OFF;\n }\n\n // ============================================================================\n // Ledger Integration\n // ============================================================================\n\n /**\n * Post the issued invoice's revenue journal from its frozen money facts.\n *\n * Debits accounts receivable with the stored total, credits each line's\n * revenue account (or `revenueAccountId`) and each tax component's\n * liability account (or `taxAccountId`), then links the journal to the\n * invoice atomically. The invoice must be issued (frozen).\n *\n * @param options - Account IDs and the ledger book currency\n * @returns The posted journal\n *\n * @example\n * ```typescript\n * const journal = await invoice.recognizeRevenue({\n * arAccountId: '1120',\n * revenueAccountId: '4100',\n * taxAccountId: '2130',\n * bookCurrency: 'CAD',\n * });\n * ```\n */\n async recognizeRevenue(options: RecognizeRevenueOptions): Promise<Journal> {\n const { recognizeInvoiceRevenue, rebindJournal } = await import(\n '../invoice-posting.js'\n );\n return rebindJournal(this.db, await recognizeInvoiceRevenue(this, options));\n }\n\n /**\n * Get the AR journal entry (if revenue was recognized)\n */\n async getArJournal(): Promise<Journal | null> {\n if (!this.arJournalId) return null;\n\n try {\n const { JournalCollection } = await import('@happyvertical/smrt-ledgers');\n const collection = await JournalCollection.create(this.options);\n return await collection.get({ id: this.arJournalId });\n } catch {\n // smrt-ledgers not available\n return null;\n }\n }\n\n // ============================================================================\n // Provider Sync\n // ============================================================================\n\n /**\n * Convert to InvoiceInput for SDK accounting provider sync.\n *\n * Fetches line items and maps all fields to the format expected\n * by @happyvertical/accounting providers. The SDK takes currency **major**\n * units (`12.34` USD), so every amount is converted from this package's\n * integer minor units with the currency's ISO 4217 exponent (#3060).\n *\n * @returns InvoiceInput compatible with @happyvertical/accounting\n *\n * @example\n * ```typescript\n * const provider = await getAccountingProvider({ type: 'quickbooks', ... });\n * const input = await invoice.toAccountingInput();\n * const result = await provider.invoices.push(input);\n * invoice.externalId = result.externalId;\n * invoice.syncedAt = result.syncedAt;\n * await invoice.save();\n * ```\n */\n async toAccountingInput(\n options?: FrozenInvoiceAccountingOptions,\n ): Promise<AccountingInvoiceInput> {\n if (!options) {\n throw new MoneyValidationError(\n 'INVALID_MONEY_INPUT',\n 'Accounting conversion requires explicit realm mapping',\n );\n }\n if (!this.id || !this.tenantId) {\n throw new MoneyValidationError(\n 'INVALID_MONEY_INPUT',\n 'Accounting conversion requires a persisted tenant invoice',\n );\n }\n const { toFrozenInvoiceAccountingInput } = await import(\n '../invoice-accounting-sync.js'\n );\n return toFrozenInvoiceAccountingInput({\n db: this.db,\n tenantId: this.tenantId,\n invoiceId: this.id,\n mapping: options.mapping,\n });\n }\n}\n\nexport default Invoice;\n","/**\n * InvoiceCollection - Collection manager for Invoice objects\n * @packageDocumentation\n */\n\nimport {\n SmrtCollection,\n type SmrtListOptions,\n type SmrtObject,\n type SmrtSelectedRow,\n type SmrtSelectField,\n type SmrtStiReadScope,\n type SmrtWhereClause,\n} from '@happyvertical/smrt-core';\nimport {\n getTenantId,\n queryGlobal,\n queryWithGlobals,\n} from '@happyvertical/smrt-tenancy';\nimport { DOCUMENT_MONEY_READ_REBIND } from '../document-money-internal.js';\nimport { Invoice } from '../models/Invoice.js';\nimport { withTenantMoneyCollectionRead } from '../tenant-money-barrier.js';\nimport { InvoiceStatus } from '../types/index.js';\nimport { assertCommerceMoneySchemaCurrent } from '../upgrade/detect.js';\n\n/**\n * Statuses that indicate an invoice has outstanding balance.\n * Used for calculating outstanding amounts and finding unpaid invoices.\n */\nexport const UNPAID_STATUSES = [\n InvoiceStatus.SENT,\n InvoiceStatus.VIEWED,\n InvoiceStatus.PARTIAL,\n InvoiceStatus.OVERDUE,\n] as const;\n\n/**\n * Options for generating invoice numbers\n */\nexport interface InvoiceNumberOptions {\n /** Prefix for invoice numbers (default: 'INV') */\n prefix?: string;\n /** Format: 'prefix-year-seq' or 'prefix-seq' (default: 'prefix-year-seq') */\n format?: 'prefix-year-seq' | 'prefix-seq';\n}\n\nexport class InvoiceCollection extends SmrtCollection<Invoice> {\n static readonly _itemClass = Invoice;\n\n private async withMoneyRead<T>(operation: () => Promise<T>): Promise<T> {\n const rootDb = this.db;\n const tenantId = getTenantId();\n if (!tenantId) {\n // Without a tenant, still refuse a database with old money storage.\n await assertCommerceMoneySchemaCurrent(rootDb);\n return operation();\n }\n const result = await withTenantMoneyCollectionRead(\n rootDb,\n tenantId,\n (boundDb) => this.withDatabase(boundDb, operation),\n );\n if (result instanceof Invoice)\n result.rebindMoneyRead(DOCUMENT_MONEY_READ_REBIND, rootDb);\n else if (Array.isArray(result))\n for (const item of result)\n if (item instanceof Invoice)\n item.rebindMoneyRead(DOCUMENT_MONEY_READ_REBIND, rootDb);\n return result;\n }\n\n override async get(\n filter: string | SmrtWhereClause<Invoice>,\n options: Parameters<SmrtCollection<Invoice>['get']>[1] = {},\n ): Promise<Invoice | null> {\n return this.withMoneyRead(() => super.get(filter, options));\n }\n\n override async list<const Select extends readonly SmrtSelectField<Invoice>[]>(\n options: Omit<SmrtListOptions<Invoice>, 'select' | 'stiScope'> & {\n select: Select;\n include?: never;\n stiScope: SmrtStiReadScope;\n },\n ): Promise<Record<string, unknown>[]>;\n override async list<const Select extends readonly SmrtSelectField<Invoice>[]>(\n options: Omit<SmrtListOptions<Invoice>, 'select' | 'stiScope'> & {\n select: Select;\n include?: never;\n stiScope?: undefined;\n },\n ): Promise<SmrtSelectedRow<Invoice, Select>[]>;\n override async list(\n options: Omit<SmrtListOptions<Invoice>, 'select' | 'stiScope'> & {\n select?: undefined;\n stiScope: SmrtStiReadScope;\n },\n ): Promise<SmrtObject[]>;\n override async list(options?: undefined): Promise<Invoice[]>;\n override async list(\n options: Omit<SmrtListOptions<Invoice>, 'select' | 'stiScope'> & {\n select?: undefined;\n stiScope?: undefined;\n },\n ): Promise<Invoice[]>;\n override async list(\n options:\n | (Omit<SmrtListOptions<Invoice>, 'select'> & { select?: undefined })\n | undefined,\n ): Promise<SmrtObject[]>;\n override async list(\n options: SmrtListOptions<Invoice> | undefined,\n ): Promise<SmrtObject[] | Record<string, unknown>[]>;\n override async list(\n options: SmrtListOptions<Invoice> = {},\n ): Promise<SmrtObject[] | Record<string, unknown>[]> {\n return this.withMoneyRead(() => super.list(options));\n }\n\n /**\n * Find invoices by customer\n *\n * @param customerId - Customer ID\n * @returns Array of invoices\n */\n async findByCustomer(customerId: string): Promise<Invoice[]> {\n return await this.list({\n where: { customerId },\n orderBy: 'issueDate DESC',\n });\n }\n\n /**\n * Find invoices by contract\n *\n * @param contractId - Contract ID\n * @returns Array of invoices\n */\n async findByContract(contractId: string): Promise<Invoice[]> {\n return await this.list({\n where: { contractId },\n orderBy: 'issueDate DESC',\n });\n }\n\n /**\n * Find invoices by status\n *\n * @param status - Invoice status\n * @returns Array of invoices\n */\n async findByStatus(status: InvoiceStatus): Promise<Invoice[]> {\n return await this.list({\n where: { status },\n orderBy: 'issueDate DESC',\n });\n }\n\n /**\n * Find all draft invoices\n *\n * @returns Array of draft invoices\n */\n async findDrafts(): Promise<Invoice[]> {\n return await this.findByStatus(InvoiceStatus.DRAFT);\n }\n\n /**\n * Find all sent invoices\n *\n * @returns Array of sent invoices\n */\n async findSent(): Promise<Invoice[]> {\n return await this.findByStatus(InvoiceStatus.SENT);\n }\n\n /**\n * Find all paid invoices\n *\n * @returns Array of paid invoices\n */\n async findPaid(): Promise<Invoice[]> {\n return await this.findByStatus(InvoiceStatus.PAID);\n }\n\n /**\n * Find all partial invoices\n *\n * @returns Array of partially paid invoices\n */\n async findPartial(): Promise<Invoice[]> {\n return await this.findByStatus(InvoiceStatus.PARTIAL);\n }\n\n /**\n * Find overdue invoices (past due date, not paid).\n *\n * **Note**: This method finds invoices by date, but does not automatically\n * update their status to OVERDUE. Use a background job or scheduled task\n * to periodically update invoice statuses based on due dates.\n *\n * @returns Array of overdue invoices\n */\n async findOverdue(): Promise<Invoice[]> {\n const now = new Date().toISOString();\n\n // Get invoices that are sent/viewed/partial and past due\n const candidates = await this.list({\n where: {\n 'dueDate <': now,\n },\n orderBy: 'dueDate ASC',\n });\n\n return candidates.filter((inv) =>\n (UNPAID_STATUSES as readonly InvoiceStatus[]).includes(inv.status),\n );\n }\n\n /**\n * Find invoices in date range (by issue date)\n *\n * @param startDate - Start date\n * @param endDate - End date\n * @returns Array of invoices\n */\n async findByDateRange(startDate: Date, endDate: Date): Promise<Invoice[]> {\n return await this.list({\n where: {\n 'issueDate >=': startDate.toISOString(),\n 'issueDate <=': endDate.toISOString(),\n },\n orderBy: 'issueDate DESC',\n });\n }\n\n /**\n * Find invoice by external ID (from accounting provider)\n *\n * @param externalId - External ID\n * @returns Invoice or null\n */\n async findByExternalId(externalId: string): Promise<Invoice | null> {\n const results = await this.list({\n where: { externalId },\n limit: 1,\n });\n return results[0] || null;\n }\n\n /**\n * Find invoices needing sync to external provider\n * (no externalId or stale syncedAt)\n *\n * @returns Array of invoices needing sync\n */\n async findNeedingSync(): Promise<Invoice[]> {\n // Get all non-draft invoices without externalId\n const allInvoices = await this.list({\n orderBy: 'issueDate DESC',\n });\n\n return allInvoices.filter(\n (inv) =>\n inv.status !== InvoiceStatus.DRAFT &&\n inv.status !== InvoiceStatus.CANCELLED &&\n !inv.externalId,\n );\n }\n\n /**\n * Find invoice by invoice number\n *\n * @param invoiceNumber - Invoice number\n * @returns Invoice or null\n */\n async findByNumber(invoiceNumber: string): Promise<Invoice | null> {\n const results = await this.list({\n where: { invoiceNumber },\n limit: 1,\n });\n return results[0] || null;\n }\n\n /**\n * Count invoices for a given year\n *\n * @param year - Year to count\n * @returns Number of invoices\n */\n async countForYear(year: number): Promise<number> {\n const startDate = new Date(year, 0, 1).toISOString();\n const endDate = new Date(year + 1, 0, 1).toISOString();\n\n const invoices = await this.list({\n where: {\n 'issueDate >=': startDate,\n 'issueDate <': endDate,\n },\n });\n\n return invoices.length;\n }\n\n /**\n * Generate the next invoice number.\n *\n * **Warning**: This method has a potential race condition if multiple\n * invoices are created concurrently. For high-concurrency environments,\n * consider using a database sequence or atomic counter instead.\n *\n * @param options - Optional configuration for number format\n * @returns Generated invoice number (e.g., 'INV-2025-0001')\n *\n * @example\n * ```typescript\n * // Default format: INV-2025-0001\n * const num = await invoices.generateInvoiceNumber();\n *\n * // Custom prefix: BILL-2025-0001\n * const num = await invoices.generateInvoiceNumber({ prefix: 'BILL' });\n *\n * // Simple sequential: INV-000001\n * const num = await invoices.generateInvoiceNumber({ format: 'prefix-seq' });\n * ```\n */\n async generateInvoiceNumber(\n options: InvoiceNumberOptions = {},\n ): Promise<string> {\n const prefix = options.prefix || 'INV';\n const format = options.format || 'prefix-year-seq';\n\n const year = new Date().getFullYear();\n\n if (format === 'prefix-year-seq') {\n const count = await this.countForYear(year);\n const seq = String(count + 1).padStart(4, '0');\n return `${prefix}-${year}-${seq}`;\n }\n\n // Simple sequential format\n const allInvoices = await this.list({});\n const seq = String(allInvoices.length + 1).padStart(6, '0');\n return `${prefix}-${seq}`;\n }\n\n /**\n * Get total outstanding (unpaid) amount for a customer\n *\n * @param customerId - Customer ID\n * @returns Total amount due\n */\n async getTotalOutstandingForCustomer(customerId: string): Promise<number> {\n const invoices = await this.list({\n where: { customerId },\n });\n\n return invoices\n .filter((inv) =>\n (UNPAID_STATUSES as readonly InvoiceStatus[]).includes(inv.status),\n )\n .reduce((sum, inv) => sum + inv.getAmountDue(), 0);\n }\n\n // ============================================================================\n // Tenant Helper Methods\n // ============================================================================\n\n /**\n * Find all invoices belonging to a specific tenant\n *\n * @param tenantId - Tenant ID\n * @returns Array of invoices for the tenant\n */\n async findByTenant(tenantId: string): Promise<Invoice[]> {\n return this.list({ where: { tenantId } });\n }\n\n /**\n * Find all global invoices (not associated with any tenant).\n *\n * Routes through the shared tenant-global helper so it does not throw under\n * an active tenant context (an explicit `tenant_id IS NULL` filter would be\n * flagged as an isolation violation). (#1600)\n *\n * @returns Array of global invoices\n */\n async findGlobal(): Promise<Invoice[]> {\n return queryGlobal<Invoice>(this);\n }\n\n /**\n * Find invoices for a tenant including global invoices.\n *\n * Fails closed if an active tenant context requests a different tenant's\n * rows; the admin/system path keeps the cross-tenant capability. (#1600)\n *\n * @param tenantId - Tenant ID\n * @returns Array of tenant-specific and global invoices\n */\n async findWithGlobals(tenantId: string): Promise<Invoice[]> {\n return queryWithGlobals<Invoice>(this, tenantId, 'Invoice.findWithGlobals');\n }\n}\n"],"mappings":";;;;;;;;;AAmCA,SAAS,QAAQ,SAAwB;CACvC,MAAM,IAAI,qBAAqB,uBAAuB,OAAO;AAC/D;AACO,SAAS,qBAAqB,QAAgB,OAAqB;CACxE,IAAI,CAAC,OAAO,cAAc,MAAM,GAC9B,QAAQ,GAAG,MAAK,0CAA2C;AAC/D;AACO,SAAS,0BACd,OACM;CACN,KAAA,MAAW,OAAO;EAChB;EACA;EACA;EACA;EACA;CACF,GAAY;EACV,MAAM,QAAQ,MAAM;EACpB,IAAI,OAAO,UAAU,YAAY,CAAC,SAAS,MAAM,KAAK,MAAM,OAC1D,QAAQ,aAAa,IAAG,+BAAgC;CAC5D;AACF;AACO,SAAS,sBACd,MAC8B;CAC9B,IAAI,SAAS,IAAI,OAAO;CACxB,IAAI;CACJ,IAAI;EACF,QAAQ,KAAK,MAAM,IAAI;CACzB,QAAQ;EACN,OAAO,QAAQ,8BAA8B;CAC/C;CACA,IACE,CAAC,SACD,MAAM,YAAY,KAClB,MAAM,iBAAiB,oBACvB,CAAC,MAAM,QAAQ,MAAM,QAAQ,GAE7B,QAAQ,8CAA8C;CACxD,0BAA0B,KAAK;CAC/B,IAAI,CAAC,aAAa,KAAK,MAAM,QAAQ,GACnC,QAAQ,gCAAgC;CAC1C,MAAM,uBAAO,IAAI,IAAI,CAAC,MAAM,SAAS,CAAC;CACtC,KAAA,MAAW,SAAS,CAAC,OAAO,GAAG,MAAM,QAAQ,GAAG;EAC9C,0BAA0B,KAAK;EAC/B,IACE,OAAO,MAAM,eAAe,YAC5B,CAAC,OAAO,SAAS,KAAK,MAAM,MAAM,UAAU,CAAC,GAE7C,QAAQ,uCAAuC;EACjD,IACE,MAAM,gBAAgB,KAAA,MACrB,CAAC,sBAAsB,KAAK,MAAM,WAAW,KAC5C,CAAC,OAAO,SAAS,KAAK,MAAM,MAAM,WAAW,CAAC,KAC9C,IAAI,KAAK,MAAM,WAAW,CAAA,CAAE,YAAY,CAAA,CAAE,MAAM,GAAG,EAAE,MACnD,MAAM,cAEV,QAAQ,0DAA0D;EACpE,IACE,MAAM,uBAAuB,KAAA,KAC7B,MAAM,uBAAuB,QAC7B,MAAM,uBAAuB,2BAC7B,MAAM,uBAAuB,yBAE7B,QAAQ,wDAAwD;EAClE,IAAI,UAAU,OAAO;GACnB,IAAI,KAAK,IAAI,MAAM,SAAS,GAC1B,QAAQ,sCAAsC;GAChD,KAAK,IAAI,MAAM,SAAS;EAC1B;CACF;CACA,OAAO;AACT;AACO,SAAS,wBAAwB,OAMhB;CACtB,KAAA,MAAW,CAAC,MAAM,WAAW,OAAO,QAAQ;EAC1C,OAAO,MAAM;EACb,SAAS,MAAM;EACf,MAAM,MAAM;CACd,CAAC,GAAG;EACF,qBAAqB,QAAQ,IAAI;EACjC,IAAI,SAAS,GAAG,QAAQ,GAAG,KAAI,oBAAqB;CACtD;CACA,IACE,MAAM,iBAAiB,MAAM,eAC7B,MAAM,aAAa,MAAM,aAEzB,QAAQ,0CAA0C;CACpD,MAAM,QAAQ,sBAAsB,MAAM,sBAAsB,EAAE;CAClE,MAAM,WAAW,OAAO,iBAAiB;CACzC,qBAAqB,UAAU,iBAAiB;CAChD,IAAI,WAAW,KAAK,WAAW,MAAM,aACnC,QAAQ,iCAAiC;CAC3C,IAAI,SAAS,MAAM,aAAa,MAAM,UACpC,QAAQ,2CAA2C;CACrD,IAAI,WAAW;CACf,KAAA,MAAW,SAAS,OAAO,YAAY,CAAC,GAAG;EACzC,qBAAqB,MAAM,aAAa,iBAAiB;EACzD,IAAI,MAAM,eAAe,GAAG,QAAQ,iCAAiC;EACrE,YAAY,OAAO,MAAM,WAAW;CACtC;CACA,IAAI,WAAW,OAAO,QAAQ,GAAG,QAAQ,iCAAiC;CAC1E,MAAM,aAAa,WAAW,OAAO,QAAQ;CAC7C,MAAM,oBAAoB,KAAK,IAAI,YAAY,MAAM,cAAc;CACnE,MAAM,YAAY,aAAa;CAC/B,MAAM,MAAM,KAAK,IAAI,GAAG,MAAM,cAAc,MAAM,iBAAiB,SAAS;CAC5E,OAAO;EACL,YAAY,MAAM;EAClB,eAAe;EACf,eAAe,OAAO,QAAQ;EAC9B,wBAAwB;EACxB,wBAAwB;EACxB,oBAAoB;EACpB,mBACE,MAAM,cAAc,MAAM,iBAAiB,MAAM;EACnD,mBAAmB,KAAK,IAAI,GAAG,MAAM,MAAM,UAAU;CACvD;AACF;;;;;;;;;;;;;;;;;;AC/FA,IAAM,6BAAqE;EACxE,cAAc,QAAQ;EACrB,cAAc;EACd,cAAc;EACd,cAAc;EACd,cAAc;EACd,cAAc;CAChB;EACC,cAAc,OAAO;EACpB,cAAc;EACd,cAAc;EACd,cAAc;EACd,cAAc;EACd,cAAc;EACd,cAAc;CAChB;EACC,cAAc,SAAS;EACtB,cAAc;EACd,cAAc;EACd,cAAc;EACd,cAAc;EACd,cAAc;EACd,cAAc;CAChB;EACC,cAAc,UAAU;EACvB,cAAc;EACd,cAAc;EACd,cAAc;EACd,cAAc;EACd,cAAc;EACd,cAAc;EACd,cAAc;CAChB;EACC,cAAc,UAAU;EACvB,cAAc;EACd,cAAc;EACd,cAAc;EACd,cAAc;EACd,cAAc;EACd,cAAc;CAChB;EAIC,cAAc,OAAO;EACpB,cAAc;EACd,cAAc;EACd,cAAc;EACd,cAAc;EACd,cAAc;EACd,cAAc;EACd,cAAc;CAChB;EAEC,cAAc,YAAY,CAAC;EAC3B,cAAc,cAAc,CAAC;AAChC;AAUA,IAAM,sCAAsB,IAAI,QAAgC;AA2FzD,IAAM,UAAN,cAAsB,WAAW;CAMtC,iBAA8C;CAC9C,2BAA2B;CACc,0BAE9B;;CAGX,gBACE,YACA,IACM;EACN,IAAI,eAAe,4BACjB,MAAM,IAAI,qBACR,mBACA,uDACF;EACF,KAAK,MAAM;EACX,KAAK,QAAQ,KAAK;EAClB,OAAO;CACT;CAGA,OAAoB;CAGpB,oBAAmC;CAInC,iBAAiB;;CAGjB,qBAAqB;CAIrB,+BAA+B;CAI/B,8BAA8B;CAE9B,kBAAkB;EAChB,OAAO,wBAAwB,IAAI;CACrC;CAOA,WAA0B;CAO1B,aAAqB;CASrB,aAAqB;CAWrB,gBAAwB;;;;CAKxB,YAAoB;CAUpB,4BAAkB,IAAI,KAAK;CAW3B,0BAAuB,IAAI,KAAK;CAMhC,WAAwB;CAgBxB,WAAmB;CAOnB,YAAoB;CAUpB,oBAA4B;CAS5B,cAAsB;CAStB,aAAqB;CASrB,WAAmB;;CAGnB,iBAAqD;;CAGrD,mBAAwC;CAIxC,gBAAgB;;CAGhB,6BAA6B;CAE7B,IAAI,yBAAmD;EACrD,IAAI;GACF,MAAM,QAAiB,KAAK,MAAM,KAAK,0BAA0B;GACjE,IAAI,CAAC,MAAM,QAAQ,KAAK,GAAG,OAAO,CAAC;GACnC,OAAO,MAAM,QACV,UACC,CAAC,CAAC,SACF,OAAO,UAAU,YACjB,OAAQ,MAAiC,mBACvC,YACF,OAAQ,MAAiC,WAAW,YACpD,OAAQ,MAAiC,UAAU,QACvD;EACF,QAAQ;GACN,OAAO,CAAC;EACV;CACF;CAEA,IAAI,uBAAuB,OAAiC;EAC1D,KAAK,6BAA6B,KAAK,UAAU,KAAK;CACxD;;CAGA,aAAa;;CAGb,kBAAkB;CAalB,SAAwB,cAAc;CAUtC,cAAsB;CAItB,sBAAqC;CAMrC,mBAA2B;;;;CAS3B,aAAqB;;;;;CAMrB,qBAA6B;;;;CAK7B,mBAA2B;;;;CAK3B,WAAwB;CAIxB,0BAA0B;;;;;;;;CAS1B,mBAA4C;;;;CAS5C,SAAsB;;;;CAKtB,WAAwB;;;;CAKxB,gBAAwB;;;;CAKxB,iBAA8B;CAa9B,QAAgB;CAShB,gBAAwB;CASxB,QAAgB;CAEhB,YAAY,UAA0B,CAAC,GAAG;EACxC,MAAM,OAAO;EACb,IAAI,QAAQ,SAAS,KAAA,GAAW,KAAK,OAAO,QAAQ;EACpD,IAAI,QAAQ,sBAAsB,KAAA,GAChC,KAAK,oBAAoB,QAAQ;EACnC,IAAI,QAAQ,mBAAmB,KAAA,GAC7B,KAAK,iBAAiB,QAAQ;EAChC,IAAI,QAAQ,6BAA6B,KAAA,GACvC,KAAK,2BAA2B,QAAQ;EAC1C,IAAI,QAAQ,4BAA4B,KAAA,GACtC,KAAK,0BAA0B,QAAQ;EACzC,IAAI,QAAQ,mBAAmB,KAAA,GAC7B,KAAK,iBAAiB,QAAQ;EAChC,IAAI,QAAQ,aAAa,KAAA,GAAW,KAAK,WAAW,QAAQ;EAC5D,IAAI,QAAQ,eAAe,KAAA,GAAW,KAAK,aAAa,QAAQ;EAChE,IAAI,QAAQ,eAAe,KAAA,GAAW,KAAK,aAAa,QAAQ;EAChE,IAAI,QAAQ,kBAAkB,KAAA,GAC5B,KAAK,gBAAgB,QAAQ;EAC/B,IAAI,QAAQ,cAAc,KAAA,GAAW,KAAK,YAAY,QAAQ;EAC9D,IAAI,QAAQ,cAAc,KAAA,GAAW,KAAK,YAAY,QAAQ;EAC9D,IAAI,QAAQ,YAAY,KAAA,GAAW,KAAK,UAAU,QAAQ;EAC1D,IAAI,QAAQ,aAAa,KAAA,GAAW,KAAK,WAAW,QAAQ;EAC5D,IAAI,QAAQ,aAAa,KAAA,GAAW,KAAK,WAAW,QAAQ;EAC5D,IAAI,QAAQ,cAAc,KAAA,GAAW,KAAK,YAAY,QAAQ;EAC9D,IAAI,QAAQ,sBAAsB,KAAA,GAChC,KAAK,oBAAoB,QAAQ;EACnC,IAAI,QAAQ,gBAAgB,KAAA,GAC1B,KAAK,cAAc,QAAQ;EAC7B,IAAI,QAAQ,eAAe,KAAA,GAAW,KAAK,aAAa,QAAQ;EAChE,IAAI,QAAQ,aAAa,KAAA,GAAW,KAAK,WAAW,QAAQ;EAC5D,IAAI,QAAQ,mBAAmB,KAAA,GAC7B,KAAK,iBAAiB,QAAQ;EAChC,IAAI,QAAQ,qBAAqB,KAAA,GAC/B,KAAK,mBAAmB,QAAQ;EAClC,IAAI,QAAQ,kBAAkB,KAAA,GAC5B,KAAK,gBAAgB,QAAQ;EAC/B,IAAI,QAAQ,+BAA+B,KAAA,GACzC,KAAK,6BAA6B,QAAQ;EAC5C,IAAI,QAAQ,2BAA2B,KAAA,GACrC,KAAK,yBAAyB,gBAC5B,QAAQ,sBACV;EACF,IAAI,QAAQ,eAAe,KAAA,GAAW,KAAK,aAAa,QAAQ;EAChE,IAAI,QAAQ,oBAAoB,KAAA,GAC9B,KAAK,kBAAkB,QAAQ;EACjC,IAAI,QAAQ,WAAW,KAAA,GAAW,KAAK,SAAS,QAAQ;EACxD,IAAI,QAAQ,gBAAgB,KAAA,GAC1B,KAAK,cAAc,QAAQ;EAC7B,IAAI,QAAQ,wBAAwB,KAAA,GAClC,KAAK,sBAAsB,QAAQ;EACrC,IAAI,QAAQ,qBAAqB,KAAA,GAC/B,KAAK,mBAAmB,QAAQ;EAClC,IAAI,QAAQ,eAAe,KAAA,GAAW,KAAK,aAAa,QAAQ;EAChE,IAAI,QAAQ,uBAAuB,KAAA,GACjC,KAAK,qBAAqB,QAAQ;EACpC,IAAI,QAAQ,qBAAqB,KAAA,GAC/B,KAAK,mBAAmB,QAAQ;EAClC,IAAI,QAAQ,aAAa,KAAA,GAAW,KAAK,WAAW,QAAQ;EAC5D,IAAI,QAAQ,4BAA4B,KAAA,GACtC,KAAK,0BAA0B,QAAQ;EACzC,IAAI,QAAQ,qBAAqB,KAAA,GAC/B,KAAK,mBAAmB,QAAQ;EAClC,IAAI,QAAQ,WAAW,KAAA,GAAW,KAAK,SAAS,QAAQ;EACxD,IAAI,QAAQ,aAAa,KAAA,GAAW,KAAK,WAAW,QAAQ;EAC5D,IAAI,QAAQ,kBAAkB,KAAA,GAC5B,KAAK,gBAAgB,QAAQ;EAC/B,IAAI,QAAQ,mBAAmB,KAAA,GAC7B,KAAK,iBAAiB,QAAQ;EAChC,IAAI,QAAQ,UAAU,KAAA,GAAW,KAAK,QAAQ,QAAQ;EACtD,IAAI,QAAQ,kBAAkB,KAAA,GAC5B,KAAK,gBAAgB,QAAQ;EAC/B,IAAI,QAAQ,UAAU,KAAA,GAAW,KAAK,QAAQ,QAAQ;CACxD;;;;;;;;;CAUA,MAAe,aAA4B;EACzC,MAAM,MAAM,WAAW;EAEvB,IAAI,KAAK,aAAa;GACpB,MAAM,EAAE,kCAAkC,MAAM,OAC9C,uBAAA,CAAA,MAAA,MAAA,EAAA,CAAA;GAEF,MAAM,8BAA8B,IAAI;EAC1C;EACA,IAAI,MAAM,KAAK,QAAQ,GACrB,oBAAoB,IAAI,MAAM,KAAK,MAAM;EAE3C,OAAO;CACT;;;;;;;;;;;;;;;;;CAsBA,MAAe,OAAsB;EACnC,MAAM,EAAE,gBAAgB,MAAM,OAAO,sCAAA,CAAA,MAAA,MAAA,EAAA,CAAA;EACrC,OAAQ,MAAM,YAAY,IAAI;CAChC;;CAGA,MAAM,YAAY,YAAyD;EACzE,IAAI,eAAe,sBACjB,MAAM,IAAI,MAAM,4CAA4C;EAC9D,MAAM,sBAAsB,MAAM,SAAS;EAC3C,MAAM,YAAY,MAAM,KAAK,QAAQ;EACrC,MAAM,QAAQ,MAAM,KAAK,mBAAmB,SAAS;EAErD,KAAK,2BAA2B;EAChC,IAAI,aAAa,KAAK,IAAI,MAAM,KAAK,oBAAoB;OACpD;GAGH,KAAK,aAAa;GAClB,IACE,KAAK,WAAW,cAAc,QAC9B,KAAK,WAAW,cAAc,SAE9B,MAAM,IAAI,MACR,WAAW,KAAK,iBAAiB,QAAO,0CACxB,KAAK,OAAM,+JAG7B;EACJ;EACA,KAAK,yBAAyB;EAC9B,KAAK,uBAAuB,KAAK;EACjC,KAAK,8BAA8B;EACnC,MAAM,UAAU,wBAAwB,IAAI;EAC5C,KACG,KAAK,gCAAgC,KAAK,gCAC3C,CAAC,cAAc,WAAW,cAAc,WAAW,CAAA,CAAE,SAAS,KAAK,MAAM,GAEzE,MAAM,IAAI,qBACR,2CACA,qGACF;EACF,KACG,KAAK,gCAAgC,KAAK,iCAC1C,KAAK,oBAAoB,KAAK,oBAE/B,MAAM,IAAI,qBACR,uBACA,4EACF;EACF,IACE,QAAQ,yBAAyB,KACjC,CAAC,KAAK,iCACL,KAAK,cACJ,KAAK,oBACL,KAAK,2BACL,KAAK,oBACL,KAAK,oBAEP,MAAM,IAAI,qBACR,uBACA,uEACF;EACF,MAAM,KAAK,2BAA2B,SAAS;EAE/C,MAAM,uBAAuB,MAAM,SAAS;EAC5C,MAAM,SAAU,MAAM,MAAM,KAAK;EACjC,oBAAoB,IAAI,MAAM,KAAK,MAAM;EACzC,OAAO;CACT;CAEA,MAAe,OACb,UAAiD,CAAC,GACnC;EACf,MAAM,EAAE,kBAAkB,MAAM,OAAO,sCAAA,CAAA,MAAA,MAAA,EAAA,CAAA;EACvC,MAAM,cAAc,MAAM,OAAO;CACnC;;CAGA,MAAM,cACJ,YACA,UAAiD,CAAC,GACnC;EACf,IAAI,eAAe,sBACjB,MAAM,IAAI,MAAM,4CAA4C;EAC9D,MAAM,MAAM,OAAO,OAAO;CAC5B;;;;;;;;;;CAWA,MAAc,mBACZ,WACoC;EACpC,IAAI,aAAa,KAAK,IACpB,IAAI;GACF,MAAM,MAAM,MAAM,KAAK,GAAG,IAAI,KAAK,WAAW,EAAE,IAAI,KAAK,GAAG,CAAC;GAC7D,IAAI,OAAO,IAAI,UAAU,MACvB,OAAO,IAAI;EAEf,QAAQ,CAER;EAEF,OAAO,oBAAoB,IAAI,IAAI;CACrC;CAEA,MAAc,sBAAqC;EACjD,MAAM,EAAE,gCAAgC,MAAM,OAC5C,qCAAA,CAAA,MAAA,MAAA,EAAA,CAAA;EAEF,MAAM,uBAAuB,MAAM,4BAA4B,OAAO;GACpE,GAAG,KAAK;GACR,IAAI,KAAK;EACX,CAAC;EACD,IAAI,CAAC,KAAK,IAAI,MAAM,IAAI,MAAM,qCAAqC;EACnE,KAAK,aAAa,MAAM,qBAAqB,2BAC3C,KAAK,EACP;CACF;;;;;;;;;;;;;;;;;;CAmBQ,cAAuB;EAC7B,OAAO,KAAK,aAAa,KAAK,kBAAkB,KAAK;CACvD;;;;;CAMQ,kBAA2B;EACjC,OAAO,KAAK,aAAa,KAAK,iBAAiB,KAAK,CAAC,KAAK,YAAY;CACxE;;;;;;;;;;;;;;CAeQ,gCAAsC;EAC5C,MAAM,QAAQ,KAAK,iBAAiB,KAAK,MAAM;EAC/C,MAAM,YAAY,KAAK,YAAY;EACnC,MAAM,gBAAgB,KAAK,gBAAgB;EAE3C,IAAI,KAAK,WAAW,cAAc,SAAS,KAAK,eAAe,GAC7D,MAAM,IAAI,MACR,WAAW,MAAK,mDAClB;EAEF,IAAI,KAAK,WAAW,cAAc,QAAQ,CAAC,WACzC,MAAM,IAAI,MACR,WAAW,MAAK,0CAA2C,KAAK,WAAU,8BAC1C,KAAK,YAAW,sFAElD;EAEF,IAAI,KAAK,WAAW,cAAc,WAAW,CAAC,eAC5C,MAAM,IAAI,MACR,WAAW,MAAK,6CAA8C,KAAK,WAAU,2CAChC,KAAK,YAAW,sFAE/D;EAIF,KACG,KAAK,WAAW,cAAc,QAC7B,KAAK,WAAW,cAAc,WAChC,KAAK,cAAc,KACnB,WAEA,MAAM,IAAI,MACR,WAAW,MAAK,eAAgB,KAAK,OAAM,2BACtC,KAAK,WAAU,4BAA6B,KAAK,YAAW,oEAEnE;CAEJ;;CAGA,MAAc,2BAA2B,WAAmC;EAC1E,IAAI,KAAK,WAAW,cAAc,OAAO;EACzC,IAAI,KAAK,UAAU,KAAK,UACtB,MAAM,IAAI,MAAM,uCAAuC;EAEzD,IAAI,aAAa,KAAK,IAAI;GACxB,MAAM,EAAE,sBAAsB,MAAA,QAAA,QAAA,CAAA,CAAA,WAAA,yBAAA;GAI9B,MAAM,QAAQ,OAAM,MADG,kBAAkB,OAAO,EAAE,IAAI,KAAK,GAAG,CAAC,EAAA,CAClC,IAAI,EAAE,IAAI,KAAK,GAAG,GAAG,EAAE,OAAO,MAAM,CAAC;GAClE,IAAI,OAAO,UAAU,OAAO,UAC1B,MAAM,IAAI,MACR,uDACF;EAEJ;CACF;;;;;;CAOQ,6BAAmC;EACzC,wBACE,WACA,KAAK,iBAAiB,KAAK,MAAM,SACjC;GACE,CAAC,YAAY,KAAK,QAAQ;GAC1B,CAAC,aAAa,KAAK,SAAS;GAC5B,CAAC,qBAAqB,KAAK,iBAAiB;GAC5C,CAAC,eAAe,KAAK,WAAW;GAChC,CAAC,cAAc,KAAK,UAAU;GAC9B,CAAC,kBAAkB,KAAK,cAAc;EACxC,CACF;CACF;CAEQ,2BAAiC;EACvC,MAAM,QAAQ,KAAK,iBAAiB,KAAK,MAAM;EAC/C,MAAM,UAAU;GACd,CAAC,YAAY,KAAK,QAAQ;GAC1B,CAAC,aAAa,KAAK,SAAS;GAC5B,CAAC,qBAAqB,KAAK,iBAAiB;GAC5C,CAAC,eAAe,KAAK,WAAW;GAChC,CAAC,cAAc,KAAK,UAAU;GAC9B,CAAC,kBAAkB,KAAK,cAAc;EACxC;EAIA,wBAAwB,WAAW,OAAO,OAAO;EACjD,KAAA,MAAW,CAACA,QAAO,UAAU,SAC3B,IAAI,QAAQ,GACV,MAAM,IAAI,MACR,WAAW,MAAK,IAAKA,OAAK,sCAAuC,MAAK,GACxE;EAGJ,IAAI,KAAK,aAAa,KAAK,aACzB,MAAM,IAAI,MACR,WAAW,MAAK,eAAgB,KAAK,WAAU,6BAA8B,KAAK,YAAW,EAC/F;CAEJ;;;;;;CAOQ,uBAAuB,OAAwC;EACrE,IAAI,UAAU,KAAA,GAAW;EACzB,IAAI,UAAU,KAAK,QAAQ;EAE3B,IAAI,EADY,2BAA2B,UAAU,CAAC,EAAA,CACzC,SAAS,KAAK,MAAM,GAC/B,MAAM,IAAI,MACR,WAAW,KAAK,iBAAiB,KAAK,GAAE,+BAClC,MAAK,YAAQ,KAAK,OAAM,yGAEhC;CAEJ;;;;CASA,UAAmB;EACjB,OAAO,KAAK,WAAW,cAAc;CACvC;;;;CAKA,SAAkB;EAChB,OAAO,KAAK,WAAW,cAAc;CACvC;;;;CAKA,SAAkB;EAChB,OAAO,KAAK,WAAW,cAAc;CACvC;;;;CAKA,YAAqB;EACnB,OAAO,KAAK,WAAW,cAAc;CACvC;;;;CAKA,YAAqB;EACnB,IAAI,KAAK,aAAa,MAAM,GAAG,OAAO;EACtC,IAAI,KAAK,WAAW,cAAc,SAAS,OAAO;EAClD,IAAI,KAAK,OAAO,KAAK,KAAK,WAAW,cAAc,WAAW,OAAO;EACrE,OAAO,KAAK,YAAY,wBAAQ,IAAI,KAAK,IAAI,KAAK;CACpD;;;;CAKA,eAAuB;EACrB,OAAO,KAAK,gBAAgB,CAAA,CAAE;CAChC;;CAGA,aAAqB;EACnB,OAAO,KAAK,cAAc,KAAK,aAAa,KAAK;CACnD;;;;CASA,WAAiB;EAGf,IACE,KAAK,WAAW,cAAc,WAC9B,KAAK,WAAW,cAAc,MAC9B;GACA,KAAK,2BAAW,IAAI,KAAK;GACzB;EACF;EACA,IAAI,KAAK,WAAW,cAAc,OAChC,MAAM,IAAI,MACR,oCAAoC,KAAK,OAAM,wDACjD;EAEF,KAAK,SAAS,cAAc;EAC5B,KAAK,yBAAS,IAAI,KAAK;CACzB;;;;;;;;;CAUA,aAAmB;EACjB,IAAI,KAAK,UAAU;EACnB,KAAK,2BAAW,IAAI,KAAK;EACzB,IAAI,KAAK,WAAW,cAAc,MAChC,KAAK,SAAS,cAAc;CAEhC;;;;;;;;;CAUA,oBAAoB,YAA0B;EAC5C,KAAK,aAAa;EAGlB,IACE,KAAK,WAAW,cAAc,aAC9B,KAAK,WAAW,cAAc,aAE9B;EAOF,IAAI,KAAK,YAAY,GAAG;GACtB,IACE,KAAK,mBAAmB,iBACvB,KAAK,WAAW,cAAc,QAAQ,CAAC,KAAK,WAE7C,KAAK,2BAAW,IAAI,KAAK;GAE3B,KAAK,SAAS,cAAc;EAC9B,OAAA,IAAW,aAAa,KAAK,iBAAiB,GAAG;GAC/C,KAAK,SAAS,cAAc;GAC5B,KAAK,WAAW;EAClB,OAAO;GAEL,KAAK,WAAW;GAChB,IAAI,KAAK,UACP,KAAK,SAAS,cAAc;QAC9B,IAAW,KAAK,UAAU,KAAK,mBAAmB,cAChD,KAAK,SAAS,cAAc;QAE5B,KAAK,SAAS,cAAc;EAEhC;CACF;;;;CAKA,SAAe;EACb,IACG,KAAK,SAAS,aAAa,KAAK,OAAO,KACvC,KAAK,SAAS,iBAAiB,KAAK,aAAa,GAElD,MAAM,IAAI,MACR,iBAAiB,KAAK,KAAI,gBAAiB,KAAK,OAAM,6BAA8B,KAAK,WAAU,EACrG;EAEF,KAAK,SAAS,cAAc;CAC9B;;CAGA,MAAM,0BACJ,SACkB;EAClB,MAAM,EAAE,kCAAkC,kBAAkB,MAAM,OAChE;EAEF,OAAO,cACL,KAAK,IACL,MAAM,iCAAiC,MAAM,OAAO,CACtD;CACF;;;;CAKA,WAAiB;EACf,KAAK,SAAS,cAAc;CAC9B;;;;;;;;;;;;;;;;;;;;;;CA2BA,MAAM,iBAAiB,SAAoD;EACzE,MAAM,EAAE,yBAAyB,kBAAkB,MAAM,OACvD;EAEF,OAAO,cAAc,KAAK,IAAI,MAAM,wBAAwB,MAAM,OAAO,CAAC;CAC5E;;;;CAKA,MAAM,eAAwC;EAC5C,IAAI,CAAC,KAAK,aAAa,OAAO;EAE9B,IAAI;GACF,MAAM,EAAE,sBAAsB,MAAM,OAAO;GAE3C,OAAO,OAAM,MADY,kBAAkB,OAAO,KAAK,OAAO,EAAA,CACtC,IAAI,EAAE,IAAI,KAAK,YAAY,CAAC;EACtD,QAAQ;GAEN,OAAO;EACT;CACF;;;;;;;;;;;;;;;;;;;;;CA0BA,MAAM,kBACJ,SACiC;EACjC,IAAI,CAAC,SACH,MAAM,IAAI,qBACR,uBACA,uDACF;EAEF,IAAI,CAAC,KAAK,MAAM,CAAC,KAAK,UACpB,MAAM,IAAI,qBACR,uBACA,2DACF;EAEF,MAAM,EAAE,mCAAmC,MAAM,OAC/C,qCAAA,CAAA,MAAA,MAAA,EAAA,CAAA;EAEF,OAAO,+BAA+B;GACpC,IAAI,KAAK;GACT,UAAU,KAAK;GACf,WAAW,KAAK;GAChB,SAAS,QAAQ;EACnB,CAAC;CACH;AACF;AAxgC0C,cAA7B,SAAoC,mBAAkB,8BAAA;AAMjE,gBAAA,CAJC,MAAM,EACL,aACE,+EACJ,CAAC,CAAA,GALU,QAMX,WAAA,kBAAA,CAAA;AAEyC,gBAAA,CAAxC,MAAM;CAAE,MAAM;CAAQ,UAAU;AAAK,CAAC,CAAA,GAR5B,QAQ8B,WAAA,2BAAA,CAAA;AAoBzC,gBAAA,CADC,MAAM,EAAE,aAAa,mCAAmC,CAAC,CAAA,GA3B/C,QA4BX,WAAA,QAAA,CAAA;AAGA,gBAAA,CADC,WAAW,WAAW,EAAE,UAAU,KAAK,CAAC,CAAA,GA9B9B,QA+BX,WAAA,qBAAA,CAAA;AAIA,gBAAA,CADC,MAAM,EAAE,IAAI,EAAE,QAAQ,QAAQ,EAAE,CAAC,CAAA,GAlCvB,QAmCX,WAAA,kBAAA,CAAA;AAOA,gBAAA,CADC,MAAM,EAAE,WAAW,KAAK,CAAC,CAAA,GAzCf,QA0CX,WAAA,gCAAA,CAAA;AAIA,gBAAA,CADC,MAAM,EAAE,WAAW,KAAK,CAAC,CAAA,GA7Cf,QA8CX,WAAA,+BAAA,CAAA;AAWA,gBAAA,CADC,SAAS,EAAE,UAAU,KAAK,CAAC,CAAA,GAxDjB,QAyDX,WAAA,YAAA,CAAA;AAOA,gBAAA,CAFC,MAAM,EAAE,aAAa,6BAA6B,CAAC,GACnD,WAAW,UAAU,CAAA,GA/DX,QAgEX,WAAA,cAAA,CAAA;AASA,gBAAA,CAJC,MAAM,EACL,aAAa,yDACf,CAAC,GACA,WAAW,iBAAiB,EAAE,iBAAiB,KAAK,CAAC,CAAA,GAxE3C,QAyEX,WAAA,cAAA,CAAA;AAWA,gBAAA,CADC,MAAM,EAAE,aAAa,qCAAqC,CAAC,CAAA,GAnFjD,QAoFX,WAAA,iBAAA,CAAA;AAeA,gBAAA,CADC,MAAM,EAAE,aAAa,mCAAmC,CAAC,CAAA,GAlG/C,QAmGX,WAAA,aAAA,CAAA;AAWA,gBAAA,CANC,MAAM;CACL,MAAM;CACN,UAAU;CACV,aACE;AACJ,CAAC,CAAA,GA7GU,QA8GX,WAAA,WAAA,CAAA;AAMA,gBAAA,CADC,MAAM,EAAE,aAAa,gCAAgC,CAAC,CAAA,GAnH5C,QAoHX,WAAA,YAAA,CAAA;AAgBA,gBAAA,CADC,MAAM;CAAE,aAAa;CAA0B,IAAI,EAAE,QAAQ,QAAQ;AAAE,CAAC,CAAA,GAnI9D,QAoIX,WAAA,YAAA,CAAA;AAOA,gBAAA,CADC,MAAM;CAAE,aAAa;CAAoB,IAAI,EAAE,QAAQ,QAAQ;AAAE,CAAC,CAAA,GA1IxD,QA2IX,WAAA,aAAA,CAAA;AAUA,gBAAA,CADC,MAAM,EAAE,IAAI,EAAE,QAAQ,QAAQ,EAAE,CAAC,CAAA,GApJvB,QAqJX,WAAA,qBAAA,CAAA;AASA,gBAAA,CAJC,MAAM;CACL,aAAa;CACb,IAAI,EAAE,QAAQ,QAAQ;AACxB,CAAC,CAAA,GA7JU,QA8JX,WAAA,eAAA,CAAA;AASA,gBAAA,CAJC,MAAM;CACL,aAAa;CACb,IAAI,EAAE,QAAQ,QAAQ;AACxB,CAAC,CAAA,GAtKU,QAuKX,WAAA,cAAA,CAAA;AASA,gBAAA,CAJC,MAAM;CACL,aAAa;CACb,IAAI,EAAE,QAAQ,WAAW;AAC3B,CAAC,CAAA,GA/KU,QAgLX,WAAA,YAAA,CAAA;AAUA,gBAAA,CADC,MAAM,EAAE,IAAI,EAAE,QAAQ,QAAQ,EAAE,CAAC,CAAA,GAzLvB,QA0LX,WAAA,iBAAA,CAAA;AA4CA,gBAAA,CAJC,MAAM,EACL,aACE,6EACJ,CAAC,CAAA,GArOU,QAsOX,WAAA,UAAA,CAAA;AAUA,gBAAA,CADC,gBAAgB,qCAAqC,CAAA,GA/O3C,QAgPX,WAAA,eAAA,CAAA;AAIA,gBAAA,CADC,gBAAgB,uCAAuC,EAAE,UAAU,KAAK,CAAC,CAAA,GAnP/D,QAoPX,WAAA,uBAAA,CAAA;AAMA,gBAAA,CADC,gBAAgB,qCAAqC,CAAA,GAzP3C,QA0PX,WAAA,oBAAA,CAAA;AA6BA,gBAAA,CADC,MAAM,EAAE,WAAW,KAAK,CAAC,CAAA,GAtRf,QAuRX,WAAA,2BAAA,CAAA;AA8CA,gBAAA,CAJC,MAAM;CACL,aAAa;CACb,IAAI,EAAE,QAAQ,WAAW;AAC3B,CAAC,CAAA,GApUU,QAqUX,WAAA,SAAA,CAAA;AASA,gBAAA,CAJC,MAAM;CACL,aAAa;CACb,IAAI,EAAE,QAAQ,WAAW;AAC3B,CAAC,CAAA,GA7UU,QA8UX,WAAA,iBAAA,CAAA;AASA,gBAAA,CAJC,MAAM;CACL,aAAa;CACb,IAAI,EAAE,QAAQ,WAAW;AAC3B,CAAC,CAAA,GAtVU,QAuVX,WAAA,SAAA,CAAA;AAvVW,UAAN,gBAAA,CAzDN,aAAa,EAAE,MAAM,WAAW,CAAC,GACjC,KAAK;CAUJ,KAAK;EACH,SAAS;GAAC;GAAQ;GAAO;GAAU;EAAQ;EAC3C,UAAU;GACR;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF;CACF;CASA,KAAK;EACH,SAAS,CAAC,QAAQ,KAAK;EACvB,aAAa,EACX,KAAK;GACH,YAAY;GACZ,YAAY;EACd,EACF;CACF;CACA,KAAK,EAAE,cAAc,KAAK;CAC1B,SAAS,CACP;EACE,MAAM;EACN,SAAS,CAAC,YAAY,yBAAyB;EAC/C,QAAQ;CACV,CACF;AACF,CAAC,CAAA,GACY,OAAA;;;;;;;AC9LN,IAAM,kBAAkB;CAC7B,cAAc;CACd,cAAc;CACd,cAAc;CACd,cAAc;AAChB;AAYO,IAAM,oBAAN,cAAgC,eAAwB;CAC7D,OAAgB,aAAa;CAE7B,MAAc,cAAiB,WAAyC;EACtE,MAAM,SAAS,KAAK;EACpB,MAAM,WAAW,YAAY;EAC7B,IAAI,CAAC,UAAU;GAEb,MAAM,iCAAiC,MAAM;GAC7C,OAAO,UAAU;EACnB;EACA,MAAM,SAAS,MAAM,8BACnB,QACA,WACC,YAAY,KAAK,aAAa,SAAS,SAAS,CACnD;EACA,IAAI,kBAAkB,SACpB,OAAO,gBAAgB,4BAA4B,MAAM;OAAA,IAClD,MAAM,QAAQ,MAAM;QAC3B,MAAW,QAAQ,QACjB,IAAI,gBAAgB,SAClB,KAAK,gBAAgB,4BAA4B,MAAM;EAAA;EAC7D,OAAO;CACT;CAEA,MAAe,IACb,QACA,UAAyD,CAAC,GACjC;EACzB,OAAO,KAAK,oBAAoB,MAAM,IAAI,QAAQ,OAAO,CAAC;CAC5D;CAqCA,MAAe,KACb,UAAoC,CAAC,GACc;EACnD,OAAO,KAAK,oBAAoB,MAAM,KAAK,OAAO,CAAC;CACrD;;;;;;;CAQA,MAAM,eAAe,YAAwC;EAC3D,OAAO,MAAM,KAAK,KAAK;GACrB,OAAO,EAAE,WAAW;GACpB,SAAS;EACX,CAAC;CACH;;;;;;;CAQA,MAAM,eAAe,YAAwC;EAC3D,OAAO,MAAM,KAAK,KAAK;GACrB,OAAO,EAAE,WAAW;GACpB,SAAS;EACX,CAAC;CACH;;;;;;;CAQA,MAAM,aAAa,QAA2C;EAC5D,OAAO,MAAM,KAAK,KAAK;GACrB,OAAO,EAAE,OAAO;GAChB,SAAS;EACX,CAAC;CACH;;;;;;CAOA,MAAM,aAAiC;EACrC,OAAO,MAAM,KAAK,aAAa,cAAc,KAAK;CACpD;;;;;;CAOA,MAAM,WAA+B;EACnC,OAAO,MAAM,KAAK,aAAa,cAAc,IAAI;CACnD;;;;;;CAOA,MAAM,WAA+B;EACnC,OAAO,MAAM,KAAK,aAAa,cAAc,IAAI;CACnD;;;;;;CAOA,MAAM,cAAkC;EACtC,OAAO,MAAM,KAAK,aAAa,cAAc,OAAO;CACtD;;;;;;;;;;CAWA,MAAM,cAAkC;EACtC,MAAM,uBAAM,IAAI,KAAK,EAAA,CAAE,YAAY;EAUnC,QAAO,MAPkB,KAAK,KAAK;GACjC,OAAO,EACL,aAAa,IACf;GACA,SAAS;EACX,CAAC,EAAA,CAEiB,QAAQ,QACvB,gBAA6C,SAAS,IAAI,MAAM,CACnE;CACF;;;;;;;;CASA,MAAM,gBAAgB,WAAiB,SAAmC;EACxE,OAAO,MAAM,KAAK,KAAK;GACrB,OAAO;IACL,gBAAgB,UAAU,YAAY;IACtC,gBAAgB,QAAQ,YAAY;GACtC;GACA,SAAS;EACX,CAAC;CACH;;;;;;;CAQA,MAAM,iBAAiB,YAA6C;EAKlE,QAAO,MAJe,KAAK,KAAK;GAC9B,OAAO,EAAE,WAAW;GACpB,OAAO;EACT,CAAC,EAAA,CACc,MAAM;CACvB;;;;;;;CAQA,MAAM,kBAAsC;EAM1C,QAAO,MAJmB,KAAK,KAAK,EAClC,SAAS,iBACX,CAAC,EAAA,CAEkB,QAChB,QACC,IAAI,WAAW,cAAc,SAC7B,IAAI,WAAW,cAAc,aAC7B,CAAC,IAAI,UACT;CACF;;;;;;;CAQA,MAAM,aAAa,eAAgD;EAKjE,QAAO,MAJe,KAAK,KAAK;GAC9B,OAAO,EAAE,cAAc;GACvB,OAAO;EACT,CAAC,EAAA,CACc,MAAM;CACvB;;;;;;;CAQA,MAAM,aAAa,MAA+B;EAChD,MAAM,YAAY,IAAI,KAAK,MAAM,GAAG,CAAC,CAAA,CAAE,YAAY;EACnD,MAAM,UAAU,IAAI,KAAK,OAAO,GAAG,GAAG,CAAC,CAAA,CAAE,YAAY;EASrD,QAAO,MAPgB,KAAK,KAAK,EAC/B,OAAO;GACL,gBAAgB;GAChB,eAAe;EACjB,EACF,CAAC,EAAA,CAEe;CAClB;;;;;;;;;;;;;;;;;;;;;;;CAwBA,MAAM,sBACJ,UAAgC,CAAC,GAChB;EACjB,MAAM,SAAS,QAAQ,UAAU;EACjC,MAAM,SAAS,QAAQ,UAAU;EAEjC,MAAM,wBAAO,IAAI,KAAK,EAAA,CAAE,YAAY;EAEpC,IAAI,WAAW,mBAAmB;GAChC,MAAM,QAAQ,MAAM,KAAK,aAAa,IAAI;GAE1C,OAAO,GAAG,OAAM,GAAI,KAAI,GADZ,OAAO,QAAQ,CAAC,CAAA,CAAE,SAAS,GAAG,GACdC;EAC9B;EAGA,MAAM,cAAc,MAAM,KAAK,KAAK,CAAC,CAAC;EAEtC,OAAO,GAAG,OAAM,GADJ,OAAO,YAAY,SAAS,CAAC,CAAA,CAAE,SAAS,GAAG,GACnC;CACtB;;;;;;;CAQA,MAAM,+BAA+B,YAAqC;EAKxE,QAAO,MAJgB,KAAK,KAAK,EAC/B,OAAO,EAAE,WAAW,EACtB,CAAC,EAAA,CAGE,QAAQ,QACN,gBAA6C,SAAS,IAAI,MAAM,CACnE,CAAA,CACC,QAAQ,KAAK,QAAQ,MAAM,IAAI,aAAa,GAAG,CAAC;CACrD;;;;;;;CAYA,MAAM,aAAa,UAAsC;EACvD,OAAO,KAAK,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;CAC1C;;;;;;;;;;CAWA,MAAM,aAAiC;EACrC,OAAO,YAAqB,IAAI;CAClC;;;;;;;;;;CAWA,MAAM,gBAAgB,UAAsC;EAC1D,OAAO,iBAA0B,MAAM,UAAU,yBAAyB;CAC5E;AACF"}