@open-mercato/checkout 0.6.7-develop.6862.1.c11a64ce0a → 0.6.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 (63) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/checkout/api/pay/[slug]/submit/route.js +28 -43
  3. package/dist/modules/checkout/api/pay/[slug]/submit/route.js.map +2 -2
  4. package/dist/modules/checkout/api/transactions/route.js +6 -23
  5. package/dist/modules/checkout/api/transactions/route.js.map +2 -2
  6. package/dist/modules/checkout/backend/checkout/pay-links/page.js +1 -2
  7. package/dist/modules/checkout/backend/checkout/pay-links/page.js.map +2 -2
  8. package/dist/modules/checkout/backend/checkout/templates/page.js +1 -2
  9. package/dist/modules/checkout/backend/checkout/templates/page.js.map +2 -2
  10. package/dist/modules/checkout/backend/checkout/transactions/page.js +1 -2
  11. package/dist/modules/checkout/backend/checkout/transactions/page.js.map +2 -2
  12. package/dist/modules/checkout/commands/links.js +1 -1
  13. package/dist/modules/checkout/commands/links.js.map +2 -2
  14. package/dist/modules/checkout/commands/transactions.js +13 -45
  15. package/dist/modules/checkout/commands/transactions.js.map +2 -2
  16. package/dist/modules/checkout/components/PayPage.js +38 -39
  17. package/dist/modules/checkout/components/PayPage.js.map +2 -2
  18. package/dist/modules/checkout/search.js +6 -44
  19. package/dist/modules/checkout/search.js.map +2 -2
  20. package/dist/modules/checkout/setup.js +0 -28
  21. package/dist/modules/checkout/setup.js.map +2 -2
  22. package/dist/modules/checkout/workers/transaction-expiry.worker.js +2 -9
  23. package/dist/modules/checkout/workers/transaction-expiry.worker.js.map +2 -2
  24. package/package.json +9 -10
  25. package/src/modules/checkout/api/pay/[slug]/submit/__tests__/route.test.ts +0 -77
  26. package/src/modules/checkout/api/pay/[slug]/submit/route.ts +28 -58
  27. package/src/modules/checkout/api/transactions/route.ts +6 -30
  28. package/src/modules/checkout/backend/checkout/pay-links/page.tsx +1 -2
  29. package/src/modules/checkout/backend/checkout/templates/page.tsx +1 -2
  30. package/src/modules/checkout/backend/checkout/transactions/page.tsx +1 -2
  31. package/src/modules/checkout/commands/links.ts +1 -5
  32. package/src/modules/checkout/commands/transactions.ts +13 -68
  33. package/src/modules/checkout/components/PayPage.tsx +37 -38
  34. package/src/modules/checkout/i18n/de.json +0 -1
  35. package/src/modules/checkout/i18n/en.json +0 -1
  36. package/src/modules/checkout/i18n/es.json +0 -1
  37. package/src/modules/checkout/i18n/pl.json +0 -1
  38. package/src/modules/checkout/search.ts +6 -44
  39. package/src/modules/checkout/setup.ts +0 -51
  40. package/src/modules/checkout/workers/transaction-expiry.worker.ts +0 -11
  41. package/dist/modules/checkout/__integration__/TC-CHKT-042.spec.js +0 -39
  42. package/dist/modules/checkout/__integration__/TC-CHKT-042.spec.js.map +0 -7
  43. package/dist/modules/checkout/__integration__/TC-CHKT-043-concurrent-status-update.spec.js +0 -62
  44. package/dist/modules/checkout/__integration__/TC-CHKT-043-concurrent-status-update.spec.js.map +0 -7
  45. package/dist/modules/checkout/extension-points.js +0 -68
  46. package/dist/modules/checkout/extension-points.js.map +0 -7
  47. package/dist/modules/checkout/lib/transaction-status-machine.js +0 -31
  48. package/dist/modules/checkout/lib/transaction-status-machine.js.map +0 -7
  49. package/dist/modules/checkout/subscribers/search-reindex-transaction-created.js +0 -32
  50. package/dist/modules/checkout/subscribers/search-reindex-transaction-created.js.map +0 -7
  51. package/src/modules/checkout/__integration__/TC-CHKT-042.spec.ts +0 -41
  52. package/src/modules/checkout/__integration__/TC-CHKT-043-concurrent-status-update.spec.ts +0 -112
  53. package/src/modules/checkout/__tests__/search.test.ts +0 -21
  54. package/src/modules/checkout/__tests__/setup-schedules.test.ts +0 -99
  55. package/src/modules/checkout/api/transactions/__tests__/route.test.ts +0 -113
  56. package/src/modules/checkout/commands/__tests__/update-transaction-status.test.ts +0 -363
  57. package/src/modules/checkout/extension-points.ts +0 -67
  58. package/src/modules/checkout/i18n/ko.json +0 -463
  59. package/src/modules/checkout/lib/__tests__/transaction-status-machine.test.ts +0 -152
  60. package/src/modules/checkout/lib/transaction-status-machine.ts +0 -71
  61. package/src/modules/checkout/subscribers/__tests__/search-reindex-transaction-created.test.ts +0 -29
  62. package/src/modules/checkout/subscribers/search-reindex-transaction-created.ts +0 -39
  63. package/src/modules/checkout/workers/__tests__/transaction-expiry.worker.test.ts +0 -124
@@ -1,7 +1,6 @@
1
1
  "use client";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
- import { extensionPoints } from "@open-mercato/checkout/modules/checkout/extension-points";
5
4
  import { useSearchParams } from "next/navigation";
6
5
  import { useT } from "@open-mercato/shared/lib/i18n/context";
7
6
  import { Page, PageBody } from "@open-mercato/ui/backend/Page";
@@ -198,7 +197,7 @@ function CheckoutTransactionsPage() {
198
197
  setPage(1);
199
198
  },
200
199
  pagination: { page, pageSize: 25, total, totalPages, onPageChange: setPage },
201
- perspective: { tableId: extensionPoints.hosts.transactionsTable.tableId },
200
+ perspective: { tableId: "checkout-transactions" },
202
201
  rowClickActionIds: ["view"],
203
202
  rowActions: (row) => /* @__PURE__ */ jsx(RowActions, { items: [{ id: "view", label: t("checkout.admin.transactions.actions.viewDetail"), href: `/backend/checkout/transactions/${encodeURIComponent(row.id)}` }] })
204
203
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/checkout/backend/checkout/transactions/page.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { extensionPoints } from '@open-mercato/checkout/modules/checkout/extension-points'\nimport { useSearchParams } from 'next/navigation'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { apiCall, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\n\ntype TransactionRow = {\n id: string\n linkId: string\n linkName?: string | null\n firstName?: string | null\n lastName?: string | null\n email?: string | null\n amount?: number | null\n currencyCode: string\n status: string\n paymentStatus?: string | null\n createdAt?: string | null\n}\n\ntype TransactionsResponse = {\n items: TransactionRow[]\n total: number\n totalPages: number\n canViewPii?: boolean\n}\n\ntype LinkLookupResponse = {\n id: string\n name?: string | null\n}\n\ntype LinkListResponse = {\n items?: Array<Record<string, unknown>>\n}\n\nfunction formatDate(value: string | null | undefined): string {\n if (!value) return '\u2014'\n const parsed = new Date(value)\n return Number.isNaN(parsed.getTime()) ? value : parsed.toLocaleDateString()\n}\n\nfunction formatAmount(amount: number | null | undefined, currencyCode: string): string {\n const resolved = typeof amount === 'number' ? amount : 0\n try {\n return new Intl.NumberFormat(undefined, { style: 'currency', currency: currencyCode }).format(resolved)\n } catch {\n return `${resolved.toFixed(2)} ${currencyCode}`\n }\n}\n\nexport default function CheckoutTransactionsPage() {\n const t = useT()\n const searchParams = useSearchParams()\n const initialLinkId = React.useMemo(() => {\n const raw = searchParams.get('linkId')\n return raw && raw.trim().length > 0 ? raw.trim() : ''\n }, [searchParams])\n const [rows, setRows] = React.useState<TransactionRow[]>([])\n const [page, setPage] = React.useState(1)\n const [search, setSearch] = React.useState('')\n const [filters, setFilters] = React.useState<FilterValues>(() => (initialLinkId ? { linkId: initialLinkId } : {}))\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [loading, setLoading] = React.useState(true)\n const [canViewPii, setCanViewPii] = React.useState(false)\n const [linkLabels, setLinkLabels] = React.useState<Record<string, string>>({})\n\n const rememberLinkOptions = React.useCallback((options: Array<{ value: string; label: string }>) => {\n if (!options.length) return\n setLinkLabels((prev) => {\n let changed = false\n const next = { ...prev }\n for (const option of options) {\n if (!option.value || !option.label) continue\n if (next[option.value] === option.label) continue\n next[option.value] = option.label\n changed = true\n }\n return changed ? next : prev\n })\n }, [])\n\n const loadLinkOptions = React.useCallback(async (query?: string): Promise<Array<{ value: string; label: string }>> => {\n const params = new URLSearchParams({ page: '1', pageSize: '20' })\n if (query && query.trim().length > 0) params.set('search', query.trim())\n try {\n const call = await apiCall<LinkListResponse>(`/api/checkout/links?${params.toString()}`)\n if (!call.ok) return []\n const items = Array.isArray(call.result?.items) ? call.result.items : []\n const options = items\n .map((item): { value: string; label: string } | null => {\n const id = typeof item.id === 'string' ? item.id : null\n const name = typeof item.name === 'string' ? item.name : null\n if (!id || !name) return null\n return { value: id, label: name }\n })\n .filter((option): option is { value: string; label: string } => option !== null)\n rememberLinkOptions(options)\n return options\n } catch {\n return []\n }\n }, [rememberLinkOptions])\n\n React.useEffect(() => {\n if (!initialLinkId || linkLabels[initialLinkId]) return\n let active = true\n void readApiResultOrThrow<LinkLookupResponse>(`/api/checkout/links/${encodeURIComponent(initialLinkId)}`)\n .then((result) => {\n if (!active) return\n const name = typeof result.name === 'string' ? result.name.trim() : ''\n if (!name) return\n rememberLinkOptions([{ value: initialLinkId, label: name }])\n })\n .catch(() => null)\n return () => {\n active = false\n }\n }, [initialLinkId, linkLabels, rememberLinkOptions])\n\n const filterDefs = React.useMemo<FilterDef[]>(() => [\n {\n id: 'linkId',\n label: t('checkout.admin.transactions.filters.link'),\n type: 'combobox',\n placeholder: t('checkout.admin.payLinks.searchPlaceholder'),\n loadOptions: loadLinkOptions,\n formatValue: (value) => linkLabels[value] ?? value,\n },\n {\n id: 'status',\n label: t('checkout.admin.transactions.filters.status'),\n type: 'select',\n options: [\n { value: 'pending', label: t('checkout.admin.transactions.status.pending') },\n { value: 'processing', label: t('checkout.admin.transactions.status.processing') },\n { value: 'completed', label: t('checkout.admin.transactions.status.completed') },\n { value: 'failed', label: t('checkout.admin.transactions.status.failed') },\n { value: 'cancelled', label: t('checkout.admin.transactions.status.cancelled') },\n { value: 'expired', label: t('checkout.admin.transactions.status.expired') },\n ],\n },\n ], [linkLabels, loadLinkOptions, t])\n\n const loadRows = React.useCallback(async () => {\n setLoading(true)\n const params = new URLSearchParams({\n page: String(page),\n pageSize: '25',\n search,\n })\n if (typeof filters.status === 'string' && filters.status) params.set('status', filters.status)\n if (typeof filters.linkId === 'string' && filters.linkId) params.set('linkId', filters.linkId)\n const result = await readApiResultOrThrow<TransactionsResponse>(`/api/checkout/transactions?${params.toString()}`)\n setRows(result.items ?? [])\n rememberLinkOptions(\n (result.items ?? [])\n .map((item) => {\n if (!item.linkId || !item.linkName) return null\n return { value: item.linkId, label: item.linkName }\n })\n .filter((option): option is { value: string; label: string } => option !== null),\n )\n setTotal(result.total ?? 0)\n setTotalPages(result.totalPages ?? 1)\n setCanViewPii(result.canViewPii === true)\n setLoading(false)\n }, [filters.linkId, filters.status, page, rememberLinkOptions, search])\n\n React.useEffect(() => {\n void loadRows()\n }, [loadRows])\n\n const columns = React.useMemo<ColumnDef<TransactionRow>[]>(() => {\n const baseColumns: ColumnDef<TransactionRow>[] = [\n { accessorKey: 'linkName', header: t('checkout.admin.transactions.columns.link') },\n ]\n if (canViewPii) {\n baseColumns.push(\n {\n id: 'customer',\n header: t('checkout.admin.transactions.columns.customer'),\n cell: ({ row }) => [row.original.firstName, row.original.lastName].filter(Boolean).join(' ') || t('checkout.common.emptyValue'),\n },\n {\n accessorKey: 'email',\n header: t('checkout.admin.transactions.columns.email'),\n cell: ({ row }) => row.original.email ?? t('checkout.common.emptyValue'),\n },\n )\n }\n baseColumns.push(\n {\n accessorKey: 'amount',\n header: t('checkout.admin.transactions.columns.amount'),\n cell: ({ row }) => formatAmount(row.original.amount, row.original.currencyCode),\n },\n {\n accessorKey: 'status',\n header: t('checkout.admin.transactions.columns.status'),\n cell: ({ row }) => <Badge variant=\"secondary\">{t(`checkout.admin.transactions.status.${row.original.status}`, row.original.status)}</Badge>,\n },\n {\n accessorKey: 'paymentStatus',\n header: t('checkout.admin.transactions.columns.paymentStatus'),\n cell: ({ row }) => row.original.paymentStatus ?? t('checkout.common.emptyValue'),\n },\n {\n accessorKey: 'createdAt',\n header: t('checkout.admin.transactions.columns.date'),\n cell: ({ row }) => formatDate(row.original.createdAt),\n },\n )\n return baseColumns\n }, [canViewPii, t])\n\n return (\n <Page>\n <PageBody>\n <DataTable\n title={t('checkout.admin.transactions.title')}\n columns={columns}\n data={rows}\n isLoading={loading}\n searchValue={search}\n onSearchChange={(value) => { setSearch(value); setPage(1) }}\n searchPlaceholder={t('checkout.admin.transactions.searchPlaceholder')}\n filters={filterDefs}\n filterValues={filters}\n onFiltersApply={(next) => { setFilters(next); setPage(1) }}\n onFiltersClear={() => { setFilters({}); setPage(1) }}\n pagination={{ page, pageSize: 25, total, totalPages, onPageChange: setPage }}\n perspective={{ tableId: extensionPoints.hosts.transactionsTable.tableId }}\n rowClickActionIds={['view']}\n rowActions={(row) => <RowActions items={[{ id: 'view', label: t('checkout.admin.transactions.actions.viewDetail'), href: `/backend/checkout/transactions/${encodeURIComponent(row.id)}` }]} />}\n />\n </PageBody>\n </Page>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useSearchParams } from 'next/navigation'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { apiCall, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\n\ntype TransactionRow = {\n id: string\n linkId: string\n linkName?: string | null\n firstName?: string | null\n lastName?: string | null\n email?: string | null\n amount?: number | null\n currencyCode: string\n status: string\n paymentStatus?: string | null\n createdAt?: string | null\n}\n\ntype TransactionsResponse = {\n items: TransactionRow[]\n total: number\n totalPages: number\n canViewPii?: boolean\n}\n\ntype LinkLookupResponse = {\n id: string\n name?: string | null\n}\n\ntype LinkListResponse = {\n items?: Array<Record<string, unknown>>\n}\n\nfunction formatDate(value: string | null | undefined): string {\n if (!value) return '\u2014'\n const parsed = new Date(value)\n return Number.isNaN(parsed.getTime()) ? value : parsed.toLocaleDateString()\n}\n\nfunction formatAmount(amount: number | null | undefined, currencyCode: string): string {\n const resolved = typeof amount === 'number' ? amount : 0\n try {\n return new Intl.NumberFormat(undefined, { style: 'currency', currency: currencyCode }).format(resolved)\n } catch {\n return `${resolved.toFixed(2)} ${currencyCode}`\n }\n}\n\nexport default function CheckoutTransactionsPage() {\n const t = useT()\n const searchParams = useSearchParams()\n const initialLinkId = React.useMemo(() => {\n const raw = searchParams.get('linkId')\n return raw && raw.trim().length > 0 ? raw.trim() : ''\n }, [searchParams])\n const [rows, setRows] = React.useState<TransactionRow[]>([])\n const [page, setPage] = React.useState(1)\n const [search, setSearch] = React.useState('')\n const [filters, setFilters] = React.useState<FilterValues>(() => (initialLinkId ? { linkId: initialLinkId } : {}))\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [loading, setLoading] = React.useState(true)\n const [canViewPii, setCanViewPii] = React.useState(false)\n const [linkLabels, setLinkLabels] = React.useState<Record<string, string>>({})\n\n const rememberLinkOptions = React.useCallback((options: Array<{ value: string; label: string }>) => {\n if (!options.length) return\n setLinkLabels((prev) => {\n let changed = false\n const next = { ...prev }\n for (const option of options) {\n if (!option.value || !option.label) continue\n if (next[option.value] === option.label) continue\n next[option.value] = option.label\n changed = true\n }\n return changed ? next : prev\n })\n }, [])\n\n const loadLinkOptions = React.useCallback(async (query?: string): Promise<Array<{ value: string; label: string }>> => {\n const params = new URLSearchParams({ page: '1', pageSize: '20' })\n if (query && query.trim().length > 0) params.set('search', query.trim())\n try {\n const call = await apiCall<LinkListResponse>(`/api/checkout/links?${params.toString()}`)\n if (!call.ok) return []\n const items = Array.isArray(call.result?.items) ? call.result.items : []\n const options = items\n .map((item): { value: string; label: string } | null => {\n const id = typeof item.id === 'string' ? item.id : null\n const name = typeof item.name === 'string' ? item.name : null\n if (!id || !name) return null\n return { value: id, label: name }\n })\n .filter((option): option is { value: string; label: string } => option !== null)\n rememberLinkOptions(options)\n return options\n } catch {\n return []\n }\n }, [rememberLinkOptions])\n\n React.useEffect(() => {\n if (!initialLinkId || linkLabels[initialLinkId]) return\n let active = true\n void readApiResultOrThrow<LinkLookupResponse>(`/api/checkout/links/${encodeURIComponent(initialLinkId)}`)\n .then((result) => {\n if (!active) return\n const name = typeof result.name === 'string' ? result.name.trim() : ''\n if (!name) return\n rememberLinkOptions([{ value: initialLinkId, label: name }])\n })\n .catch(() => null)\n return () => {\n active = false\n }\n }, [initialLinkId, linkLabels, rememberLinkOptions])\n\n const filterDefs = React.useMemo<FilterDef[]>(() => [\n {\n id: 'linkId',\n label: t('checkout.admin.transactions.filters.link'),\n type: 'combobox',\n placeholder: t('checkout.admin.payLinks.searchPlaceholder'),\n loadOptions: loadLinkOptions,\n formatValue: (value) => linkLabels[value] ?? value,\n },\n {\n id: 'status',\n label: t('checkout.admin.transactions.filters.status'),\n type: 'select',\n options: [\n { value: 'pending', label: t('checkout.admin.transactions.status.pending') },\n { value: 'processing', label: t('checkout.admin.transactions.status.processing') },\n { value: 'completed', label: t('checkout.admin.transactions.status.completed') },\n { value: 'failed', label: t('checkout.admin.transactions.status.failed') },\n { value: 'cancelled', label: t('checkout.admin.transactions.status.cancelled') },\n { value: 'expired', label: t('checkout.admin.transactions.status.expired') },\n ],\n },\n ], [linkLabels, loadLinkOptions, t])\n\n const loadRows = React.useCallback(async () => {\n setLoading(true)\n const params = new URLSearchParams({\n page: String(page),\n pageSize: '25',\n search,\n })\n if (typeof filters.status === 'string' && filters.status) params.set('status', filters.status)\n if (typeof filters.linkId === 'string' && filters.linkId) params.set('linkId', filters.linkId)\n const result = await readApiResultOrThrow<TransactionsResponse>(`/api/checkout/transactions?${params.toString()}`)\n setRows(result.items ?? [])\n rememberLinkOptions(\n (result.items ?? [])\n .map((item) => {\n if (!item.linkId || !item.linkName) return null\n return { value: item.linkId, label: item.linkName }\n })\n .filter((option): option is { value: string; label: string } => option !== null),\n )\n setTotal(result.total ?? 0)\n setTotalPages(result.totalPages ?? 1)\n setCanViewPii(result.canViewPii === true)\n setLoading(false)\n }, [filters.linkId, filters.status, page, rememberLinkOptions, search])\n\n React.useEffect(() => {\n void loadRows()\n }, [loadRows])\n\n const columns = React.useMemo<ColumnDef<TransactionRow>[]>(() => {\n const baseColumns: ColumnDef<TransactionRow>[] = [\n { accessorKey: 'linkName', header: t('checkout.admin.transactions.columns.link') },\n ]\n if (canViewPii) {\n baseColumns.push(\n {\n id: 'customer',\n header: t('checkout.admin.transactions.columns.customer'),\n cell: ({ row }) => [row.original.firstName, row.original.lastName].filter(Boolean).join(' ') || t('checkout.common.emptyValue'),\n },\n {\n accessorKey: 'email',\n header: t('checkout.admin.transactions.columns.email'),\n cell: ({ row }) => row.original.email ?? t('checkout.common.emptyValue'),\n },\n )\n }\n baseColumns.push(\n {\n accessorKey: 'amount',\n header: t('checkout.admin.transactions.columns.amount'),\n cell: ({ row }) => formatAmount(row.original.amount, row.original.currencyCode),\n },\n {\n accessorKey: 'status',\n header: t('checkout.admin.transactions.columns.status'),\n cell: ({ row }) => <Badge variant=\"secondary\">{t(`checkout.admin.transactions.status.${row.original.status}`, row.original.status)}</Badge>,\n },\n {\n accessorKey: 'paymentStatus',\n header: t('checkout.admin.transactions.columns.paymentStatus'),\n cell: ({ row }) => row.original.paymentStatus ?? t('checkout.common.emptyValue'),\n },\n {\n accessorKey: 'createdAt',\n header: t('checkout.admin.transactions.columns.date'),\n cell: ({ row }) => formatDate(row.original.createdAt),\n },\n )\n return baseColumns\n }, [canViewPii, t])\n\n return (\n <Page>\n <PageBody>\n <DataTable\n title={t('checkout.admin.transactions.title')}\n columns={columns}\n data={rows}\n isLoading={loading}\n searchValue={search}\n onSearchChange={(value) => { setSearch(value); setPage(1) }}\n searchPlaceholder={t('checkout.admin.transactions.searchPlaceholder')}\n filters={filterDefs}\n filterValues={filters}\n onFiltersApply={(next) => { setFilters(next); setPage(1) }}\n onFiltersClear={() => { setFilters({}); setPage(1) }}\n pagination={{ page, pageSize: 25, total, totalPages, onPageChange: setPage }}\n perspective={{ tableId: 'checkout-transactions' }}\n rowClickActionIds={['view']}\n rowActions={(row) => <RowActions items={[{ id: 'view', label: t('checkout.admin.transactions.actions.viewDetail'), href: `/backend/checkout/transactions/${encodeURIComponent(row.id)}` }]} />}\n />\n </PageBody>\n </Page>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -496,7 +496,7 @@ registerCommand(createLinkCommand);
496
496
  registerCommand(updateLinkCommand);
497
497
  registerCommand(deleteLinkCommand);
498
498
  function serializeLinkRecord(record) {
499
- return { ...serializeTemplateOrLink(record), completionCount: record.completionCount ?? 0 };
499
+ return serializeTemplateOrLink(record);
500
500
  }
501
501
  export {
502
502
  serializeLinkRecord
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/checkout/commands/links.ts"],
4
- "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport { buildCustomFieldResetMap, loadCustomFieldSnapshot } from '@open-mercato/shared/lib/commands/customFieldSnapshots'\nimport { setCustomFieldsIfAny } from '@open-mercato/shared/lib/commands/helpers'\nimport { resolveRedoSnapshot } from '@open-mercato/shared/lib/commands/redo'\nimport { loadCustomFieldValues } from '@open-mercato/shared/lib/crud/custom-fields'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { enforceCommandOptimisticLockWithGuards } from '@open-mercato/shared/lib/crud/optimistic-lock-command'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CheckoutLink, CheckoutLinkTemplate, CheckoutTransaction } from '../data/entities'\nimport { createLinkSchema, updateLinkSchema } from '../data/validators'\nimport { CHECKOUT_ENTITY_IDS } from '../lib/constants'\nimport {\n ensureGatewayProviderConfigured,\n type PaymentGatewayDescriptorService,\n} from '../lib/gatewayProviderAvailability'\nimport { emitCheckoutEvent } from '../events'\nimport {\n deriveConfiguredCurrencies,\n ensureUniqueSlug,\n hashCheckoutPassword,\n isCheckoutLinkPublic,\n parseCheckoutInput,\n pickExplicitParsedOverrides,\n resolveLoadedCheckoutCustomFields,\n serializeTemplateOrLink,\n toMoneyString,\n toTemplateOrLinkMutationInput,\n validateDescriptorCurrencies,\n} from '../lib/utils'\nimport {\n captureLinkSnapshot,\n createLinkFromSnapshot,\n extractUndoPayload,\n readCommandId,\n resolveCommandScope,\n restoreLinkFromSnapshot,\n toCheckoutAuditSnapshot,\n type CheckoutLinkSnapshot,\n} from './shared'\n\nconst ACTIVE_TRANSACTION_STATUSES = ['pending', 'processing']\n\ntype CheckoutLinkUndoPayload = {\n before?: CheckoutLinkSnapshot | null\n after?: CheckoutLinkSnapshot | null\n}\n\nasync function resolveRestoredLinkSlug(\n em: EntityManager,\n snapshot: CheckoutLinkSnapshot,\n): Promise<string> {\n return ensureUniqueSlug(\n em,\n {\n tenantId: snapshot.tenantId,\n organizationId: snapshot.organizationId,\n },\n snapshot.slug,\n snapshot.title ?? snapshot.name,\n snapshot.id,\n )\n}\n\nconst createLinkCommand: CommandHandler<Record<string, unknown>, { id: string; slug: string }> = {\n id: 'checkout.link.create',\n async execute(rawInput, ctx) {\n const { parsed, customFields } = parseCheckoutInput(rawInput, createLinkSchema.parse)\n const scope = resolveCommandScope(ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n\n let sourceValues = parsed\n let templateCustomFields: Record<string, unknown> = {}\n if (parsed.templateId) {\n const template = await findOneWithDecryption(em, CheckoutLinkTemplate, {\n id: parsed.templateId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!template) throw new CrudHttpError(404, { error: 'Template not found' })\n sourceValues = toTemplateOrLinkMutationInput(template, {\n ...pickExplicitParsedOverrides(rawInput, parsed),\n templateId: template.id,\n })\n const loaded = await loadCustomFieldValues({\n em,\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordIds: [template.id],\n tenantIdByRecord: { [template.id]: scope.tenantId },\n organizationIdByRecord: { [template.id]: scope.organizationId },\n })\n templateCustomFields = resolveLoadedCheckoutCustomFields(loaded[template.id])\n }\n\n validateDescriptorCurrencies(sourceValues.gatewayProviderKey ?? null, deriveConfiguredCurrencies(sourceValues))\n const descriptorService = ctx.container.resolve('paymentGatewayDescriptorService') as PaymentGatewayDescriptorService\n await ensureGatewayProviderConfigured(sourceValues.gatewayProviderKey ?? null, descriptorService, scope)\n if (isCheckoutLinkPublic(sourceValues.status) && !sourceValues.gatewayProviderKey) {\n throw new CrudHttpError(422, { error: 'A payment gateway must be configured before this link can be published' })\n }\n const slug = await ensureUniqueSlug(\n em,\n scope,\n sourceValues.slug ?? null,\n sourceValues.title ?? sourceValues.name,\n )\n const link = em.create(CheckoutLink, {\n ...sourceValues,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n completionCount: 0,\n activeReservationCount: 0,\n isLocked: false,\n fixedPriceAmount: toMoneyString(sourceValues.fixedPriceAmount),\n fixedPriceOriginalAmount: toMoneyString(sourceValues.fixedPriceOriginalAmount),\n customAmountMin: toMoneyString(sourceValues.customAmountMin),\n customAmountMax: toMoneyString(sourceValues.customAmountMax),\n slug,\n passwordHash: await hashCheckoutPassword(sourceValues.password),\n } as any)\n em.persist(link)\n await em.flush()\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n values: { ...templateCustomFields, ...customFields },\n })\n await emitCheckoutEvent('checkout.link.created', {\n id: link.id,\n slug: link.slug,\n status: link.status,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n if (link.status === 'active') {\n await emitCheckoutEvent('checkout.link.published', {\n id: link.id,\n slug: link.slug,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n }\n return { id: link.id, slug: link.slug }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const link = await findOneWithDecryption(em, CheckoutLink, { id: result.id })\n if (!link) return null\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: link.tenantId,\n organizationId: link.organizationId,\n })\n return captureLinkSnapshot(link, custom)\n },\n buildLog: async ({ result, snapshots }) => {\n const { translate } = await resolveTranslations()\n const after = snapshots.after as CheckoutLinkSnapshot | null | undefined\n return {\n actionLabel: translate('checkout.audit.links.create', 'Create pay link'),\n resourceKind: 'checkout.link',\n resourceId: result.id,\n tenantId: after?.tenantId ?? null,\n organizationId: after?.organizationId ?? null,\n snapshotAfter: after ? toCheckoutAuditSnapshot(after) : null,\n payload: {\n undo: {\n after: after ?? null,\n } satisfies CheckoutLinkUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const after = extractUndoPayload<CheckoutLinkUndoPayload>(logEntry)?.after\n if (!after) return\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n const reset = buildCustomFieldResetMap(undefined, after.custom)\n if (Object.keys(reset).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: after.id,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n values: reset,\n notify: false,\n })\n }\n const link = await em.findOne(CheckoutLink, { id: after.id })\n if (!link) return\n link.deletedAt = new Date()\n await em.flush()\n },\n redo: async ({ logEntry, ctx }) => {\n const after = resolveRedoSnapshot<CheckoutLinkSnapshot>(logEntry)\n if (!after) throw new CrudHttpError(400, { error: '[internal] redo snapshot unavailable for checkout link create' })\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n let link = await findOneWithDecryption(\n em,\n CheckoutLink,\n { id: after.id },\n {},\n { tenantId: after.tenantId, organizationId: after.organizationId },\n )\n if (link) {\n restoreLinkFromSnapshot(link, after)\n link.deletedAt = null\n link.slug = await resolveRestoredLinkSlug(em, after)\n } else {\n link = em.create(CheckoutLink, {\n ...createLinkFromSnapshot(after),\n slug: await resolveRestoredLinkSlug(em, after),\n })\n em.persist(link)\n }\n await em.flush()\n const reset = buildCustomFieldResetMap(after.custom, undefined)\n if (Object.keys(reset).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: after.id,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n values: reset,\n notify: false,\n })\n }\n await emitCheckoutEvent('checkout.link.created', {\n id: link.id,\n slug: link.slug,\n status: link.status,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n }).catch(() => undefined)\n if (link.status === 'active') {\n await emitCheckoutEvent('checkout.link.published', {\n id: link.id,\n slug: link.slug,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n }).catch(() => undefined)\n }\n return { id: link.id, slug: link.slug }\n },\n}\n\nconst updateLinkCommand: CommandHandler<Record<string, unknown>, { ok: true; slug: string }> = {\n id: 'checkout.link.update',\n async prepare(rawInput, ctx) {\n const { parsed } = parseCheckoutInput(rawInput, updateLinkSchema.parse)\n const scope = resolveCommandScope(ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const link = await findOneWithDecryption(em, CheckoutLink, {\n id: parsed.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!link) return {}\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: link.tenantId,\n organizationId: link.organizationId,\n })\n return { before: captureLinkSnapshot(link, custom) }\n },\n async execute(rawInput, ctx) {\n const { parsed, customFields } = parseCheckoutInput(rawInput, updateLinkSchema.parse)\n const scope = resolveCommandScope(ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n const link = await findOneWithDecryption(em, CheckoutLink, {\n id: parsed.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!link) throw new CrudHttpError(404, { error: 'Link not found' })\n await enforceCommandOptimisticLockWithGuards(ctx.container, {\n resourceKind: 'checkout.link',\n resourceId: link.id,\n current: link.updatedAt ?? null,\n request: ctx.request ?? null,\n })\n if (link.isLocked) {\n throw new CrudHttpError(422, { error: 'This link has active transactions and cannot be edited' })\n }\n const nextValues = toTemplateOrLinkMutationInput(link, parsed)\n validateDescriptorCurrencies(\n parsed.gatewayProviderKey ?? link.gatewayProviderKey ?? null,\n deriveConfiguredCurrencies(nextValues),\n )\n const descriptorService = ctx.container.resolve('paymentGatewayDescriptorService') as PaymentGatewayDescriptorService\n await ensureGatewayProviderConfigured(nextValues.gatewayProviderKey ?? null, descriptorService, scope)\n if (isCheckoutLinkPublic(nextValues.status) && !nextValues.gatewayProviderKey) {\n throw new CrudHttpError(422, { error: 'A payment gateway must be configured before this link can be published' })\n }\n const slug = parsed.slug !== undefined || parsed.name !== undefined || parsed.title !== undefined\n ? await ensureUniqueSlug(em, scope, parsed.slug ?? link.slug, parsed.title ?? parsed.name ?? link.title ?? link.name, link.id)\n : link.slug\n const passwordHash = parsed.password !== undefined ? await hashCheckoutPassword(parsed.password) : link.passwordHash\n const previousStatus = link.status\n Object.assign(link, {\n ...parsed,\n fixedPriceAmount: parsed.fixedPriceAmount !== undefined ? toMoneyString(parsed.fixedPriceAmount) : link.fixedPriceAmount,\n fixedPriceOriginalAmount: parsed.fixedPriceOriginalAmount !== undefined ? toMoneyString(parsed.fixedPriceOriginalAmount) : link.fixedPriceOriginalAmount,\n customAmountMin: parsed.customAmountMin !== undefined ? toMoneyString(parsed.customAmountMin) : link.customAmountMin,\n customAmountMax: parsed.customAmountMax !== undefined ? toMoneyString(parsed.customAmountMax) : link.customAmountMax,\n slug,\n passwordHash,\n })\n await em.flush()\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n values: customFields,\n })\n await emitCheckoutEvent('checkout.link.updated', {\n id: link.id,\n slug: link.slug,\n status: link.status,\n previousStatus,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n if (previousStatus !== 'active' && link.status === 'active') {\n await emitCheckoutEvent('checkout.link.published', {\n id: link.id,\n slug: link.slug,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n }\n return { ok: true, slug: link.slug }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const link = await findOneWithDecryption(em, CheckoutLink, { slug: result.slug, deletedAt: null })\n if (!link) return null\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: link.tenantId,\n organizationId: link.organizationId,\n })\n return captureLinkSnapshot(link, custom)\n },\n buildLog: async ({ snapshots, result }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as CheckoutLinkSnapshot | null | undefined\n const after = snapshots.after as CheckoutLinkSnapshot | null | undefined\n return {\n actionLabel: translate('checkout.audit.links.update', 'Update pay link'),\n resourceKind: 'checkout.link',\n resourceId: after?.id ?? before?.id ?? null,\n tenantId: after?.tenantId ?? before?.tenantId ?? null,\n organizationId: after?.organizationId ?? before?.organizationId ?? null,\n snapshotBefore: before ? toCheckoutAuditSnapshot(before) : null,\n snapshotAfter: after ? toCheckoutAuditSnapshot(after) : null,\n payload: {\n undo: {\n before: before ?? null,\n after: after ?? null,\n } satisfies CheckoutLinkUndoPayload,\n },\n context: result.slug ? { slug: result.slug } : null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<CheckoutLinkUndoPayload>(logEntry)\n const before = undo?.before\n const after = undo?.after\n if (!before) return\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n const link = await em.findOne(CheckoutLink, { id: before.id, deletedAt: null })\n if (!link) return\n restoreLinkFromSnapshot(link, before)\n link.slug = await resolveRestoredLinkSlug(em, before)\n await em.flush()\n const reset = buildCustomFieldResetMap(before.custom, after?.custom)\n if (Object.keys(reset).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n values: reset,\n notify: false,\n })\n }\n },\n}\n\nconst deleteLinkCommand: CommandHandler<Record<string, unknown>, { ok: true }> = {\n id: 'checkout.link.delete',\n async prepare(rawInput, ctx) {\n const linkId = readCommandId(rawInput, 'Link id is required')\n const scope = resolveCommandScope(ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const link = await findOneWithDecryption(em, CheckoutLink, {\n id: linkId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!link) return {}\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: link.tenantId,\n organizationId: link.organizationId,\n })\n return { before: captureLinkSnapshot(link, custom) }\n },\n async execute(rawInput, ctx) {\n const linkId = readCommandId(rawInput, 'Link id is required')\n const scope = resolveCommandScope(ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const link = await findOneWithDecryption(em, CheckoutLink, {\n id: linkId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!link) throw new CrudHttpError(404, { error: 'Link not found' })\n await enforceCommandOptimisticLockWithGuards(ctx.container, {\n resourceKind: 'checkout.link',\n resourceId: link.id,\n current: link.updatedAt ?? null,\n request: ctx.request ?? null,\n })\n const activeCount = await em.count(CheckoutTransaction, {\n linkId: link.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n status: { $in: ACTIVE_TRANSACTION_STATUSES as Array<CheckoutTransaction['status']> },\n })\n if (activeCount > 0) {\n throw new CrudHttpError(422, { error: 'This link has active transactions and cannot be deleted' })\n }\n link.deletedAt = new Date()\n await em.flush()\n await emitCheckoutEvent('checkout.link.deleted', {\n id: link.id,\n slug: link.slug,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n return { ok: true }\n },\n buildLog: async ({ snapshots, input }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as CheckoutLinkSnapshot | null | undefined\n return {\n actionLabel: translate('checkout.audit.links.delete', 'Delete pay link'),\n resourceKind: 'checkout.link',\n resourceId: before?.id ?? readCommandId(input, 'Link id is required'),\n tenantId: before?.tenantId ?? null,\n organizationId: before?.organizationId ?? null,\n snapshotBefore: before ? toCheckoutAuditSnapshot(before) : null,\n payload: {\n undo: {\n before: before ?? null,\n } satisfies CheckoutLinkUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const before = extractUndoPayload<CheckoutLinkUndoPayload>(logEntry)?.before\n if (!before) return\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n let link = await em.findOne(CheckoutLink, { id: before.id })\n if (link) {\n restoreLinkFromSnapshot(link, before)\n link.slug = await resolveRestoredLinkSlug(em, before)\n } else {\n link = em.create(CheckoutLink, {\n ...createLinkFromSnapshot(before),\n slug: await resolveRestoredLinkSlug(em, before),\n })\n em.persist(link)\n }\n await em.flush()\n const reset = buildCustomFieldResetMap(before.custom, undefined)\n if (Object.keys(reset).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n values: reset,\n notify: false,\n })\n }\n },\n}\n\nregisterCommand(createLinkCommand)\nregisterCommand(updateLinkCommand)\nregisterCommand(deleteLinkCommand)\n\nexport function serializeLinkRecord(record: CheckoutLink) {\n // completionCount is link-only state (templates have no completions), so it is\n // added here rather than in the shared template/link serializer. It is the\n // observable proof that a terminal transaction was applied exactly once, which\n // TC-CHKT-043 asserts and could not previously read from any API.\n return { ...serializeTemplateOrLink(record), completionCount: record.completionCount ?? 0 }\n}\n"],
5
- "mappings": "AAGA,SAAS,uBAAuB;AAChC,SAAS,0BAA0B,+BAA+B;AAClE,SAAS,4BAA4B;AACrC,SAAS,2BAA2B;AACpC,SAAS,6BAA6B;AACtC,SAAS,qBAAqB;AAC9B,SAAS,8CAA8C;AACvD,SAAS,6BAA6B;AACtC,SAAS,2BAA2B;AACpC,SAAS,cAAc,sBAAsB,2BAA2B;AACxE,SAAS,kBAAkB,wBAAwB;AACnD,SAAS,2BAA2B;AACpC;AAAA,EACE;AAAA,OAEK;AACP,SAAS,yBAAyB;AAClC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAEP,MAAM,8BAA8B,CAAC,WAAW,YAAY;AAO5D,eAAe,wBACb,IACA,UACiB;AACjB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,UAAU,SAAS;AAAA,MACnB,gBAAgB,SAAS;AAAA,IAC3B;AAAA,IACA,SAAS;AAAA,IACT,SAAS,SAAS,SAAS;AAAA,IAC3B,SAAS;AAAA,EACX;AACF;AAEA,MAAM,oBAA2F;AAAA,EAC/F,IAAI;AAAA,EACJ,MAAM,QAAQ,UAAU,KAAK;AAC3B,UAAM,EAAE,QAAQ,aAAa,IAAI,mBAAmB,UAAU,iBAAiB,KAAK;AACpF,UAAM,QAAQ,oBAAoB,GAAG;AACrC,UAAM,KAAK,IAAI,UAAU,QAAQ,IAAI;AACrC,UAAM,aAAa,IAAI,UAAU,QAAQ,YAAY;AAErD,QAAI,eAAe;AACnB,QAAI,uBAAgD,CAAC;AACrD,QAAI,OAAO,YAAY;AACrB,YAAM,WAAW,MAAM,sBAAsB,IAAI,sBAAsB;AAAA,QACrE,IAAI,OAAO;AAAA,QACX,gBAAgB,MAAM;AAAA,QACtB,UAAU,MAAM;AAAA,QAChB,WAAW;AAAA,MACb,GAAG,QAAW,KAAK;AACnB,UAAI,CAAC,SAAU,OAAM,IAAI,cAAc,KAAK,EAAE,OAAO,qBAAqB,CAAC;AAC3E,qBAAe,8BAA8B,UAAU;AAAA,QACrD,GAAG,4BAA4B,UAAU,MAAM;AAAA,QAC/C,YAAY,SAAS;AAAA,MACvB,CAAC;AACD,YAAM,SAAS,MAAM,sBAAsB;AAAA,QACzC;AAAA,QACA,UAAU,oBAAoB;AAAA,QAC9B,WAAW,CAAC,SAAS,EAAE;AAAA,QACvB,kBAAkB,EAAE,CAAC,SAAS,EAAE,GAAG,MAAM,SAAS;AAAA,QAClD,wBAAwB,EAAE,CAAC,SAAS,EAAE,GAAG,MAAM,eAAe;AAAA,MAChE,CAAC;AACD,6BAAuB,kCAAkC,OAAO,SAAS,EAAE,CAAC;AAAA,IAC9E;AAEA,iCAA6B,aAAa,sBAAsB,MAAM,2BAA2B,YAAY,CAAC;AAC9G,UAAM,oBAAoB,IAAI,UAAU,QAAQ,iCAAiC;AACjF,UAAM,gCAAgC,aAAa,sBAAsB,MAAM,mBAAmB,KAAK;AACvG,QAAI,qBAAqB,aAAa,MAAM,KAAK,CAAC,aAAa,oBAAoB;AACjF,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,yEAAyE,CAAC;AAAA,IAClH;AACA,UAAM,OAAO,MAAM;AAAA,MACjB;AAAA,MACA;AAAA,MACA,aAAa,QAAQ;AAAA,MACrB,aAAa,SAAS,aAAa;AAAA,IACrC;AACA,UAAM,OAAO,GAAG,OAAO,cAAc;AAAA,MACnC,GAAG;AAAA,MACH,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB,iBAAiB;AAAA,MACjB,wBAAwB;AAAA,MACxB,UAAU;AAAA,MACV,kBAAkB,cAAc,aAAa,gBAAgB;AAAA,MAC7D,0BAA0B,cAAc,aAAa,wBAAwB;AAAA,MAC7E,iBAAiB,cAAc,aAAa,eAAe;AAAA,MAC3D,iBAAiB,cAAc,aAAa,eAAe;AAAA,MAC3D;AAAA,MACA,cAAc,MAAM,qBAAqB,aAAa,QAAQ;AAAA,IAChE,CAAQ;AACR,OAAG,QAAQ,IAAI;AACf,UAAM,GAAG,MAAM;AACf,UAAM,qBAAqB;AAAA,MACzB;AAAA,MACA,UAAU,oBAAoB;AAAA,MAC9B,UAAU,KAAK;AAAA,MACf,UAAU,MAAM;AAAA,MAChB,gBAAgB,MAAM;AAAA,MACtB,QAAQ,EAAE,GAAG,sBAAsB,GAAG,aAAa;AAAA,IACrD,CAAC;AACD,UAAM,kBAAkB,yBAAyB;AAAA,MAC/C,IAAI,KAAK;AAAA,MACT,MAAM,KAAK;AAAA,MACX,QAAQ,KAAK;AAAA,MACb,UAAU,MAAM;AAAA,MAChB,gBAAgB,MAAM;AAAA,IACxB,CAAC,EAAE,MAAM,MAAM,MAAS;AACxB,QAAI,KAAK,WAAW,UAAU;AAC5B,YAAM,kBAAkB,2BAA2B;AAAA,QACjD,IAAI,KAAK;AAAA,QACT,MAAM,KAAK;AAAA,QACX,UAAU,MAAM;AAAA,QAChB,gBAAgB,MAAM;AAAA,MACxB,CAAC,EAAE,MAAM,MAAM,MAAS;AAAA,IAC1B;AACA,WAAO,EAAE,IAAI,KAAK,IAAI,MAAM,KAAK,KAAK;AAAA,EACxC;AAAA,EACA,cAAc,OAAO,QAAQ,QAAQ,QAAQ;AAC3C,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,OAAO,MAAM,sBAAsB,IAAI,cAAc,EAAE,IAAI,OAAO,GAAG,CAAC;AAC5E,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,SAAS,MAAM,wBAAwB,IAAI;AAAA,MAC/C,UAAU,oBAAoB;AAAA,MAC9B,UAAU,KAAK;AAAA,MACf,UAAU,KAAK;AAAA,MACf,gBAAgB,KAAK;AAAA,IACvB,CAAC;AACD,WAAO,oBAAoB,MAAM,MAAM;AAAA,EACzC;AAAA,EACA,UAAU,OAAO,EAAE,QAAQ,UAAU,MAAM;AACzC,UAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,UAAM,QAAQ,UAAU;AACxB,WAAO;AAAA,MACL,aAAa,UAAU,+BAA+B,iBAAiB;AAAA,MACvE,cAAc;AAAA,MACd,YAAY,OAAO;AAAA,MACnB,UAAU,OAAO,YAAY;AAAA,MAC7B,gBAAgB,OAAO,kBAAkB;AAAA,MACzC,eAAe,QAAQ,wBAAwB,KAAK,IAAI;AAAA,MACxD,SAAS;AAAA,QACP,MAAM;AAAA,UACJ,OAAO,SAAS;AAAA,QAClB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,MAAM,OAAO,EAAE,UAAU,IAAI,MAAM;AACjC,UAAM,QAAQ,mBAA4C,QAAQ,GAAG;AACrE,QAAI,CAAC,MAAO;AACZ,UAAM,KAAK,IAAI,UAAU,QAAQ,IAAI;AACrC,UAAM,aAAa,IAAI,UAAU,QAAQ,YAAY;AACrD,UAAM,QAAQ,yBAAyB,QAAW,MAAM,MAAM;AAC9D,QAAI,OAAO,KAAK,KAAK,EAAE,QAAQ;AAC7B,YAAM,qBAAqB;AAAA,QACzB;AAAA,QACA,UAAU,oBAAoB;AAAA,QAC9B,UAAU,MAAM;AAAA,QAChB,UAAU,MAAM;AAAA,QAChB,gBAAgB,MAAM;AAAA,QACtB,QAAQ;AAAA,QACR,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AACA,UAAM,OAAO,MAAM,GAAG,QAAQ,cAAc,EAAE,IAAI,MAAM,GAAG,CAAC;AAC5D,QAAI,CAAC,KAAM;AACX,SAAK,YAAY,oBAAI,KAAK;AAC1B,UAAM,GAAG,MAAM;AAAA,EACjB;AAAA,EACA,MAAM,OAAO,EAAE,UAAU,IAAI,MAAM;AACjC,UAAM,QAAQ,oBAA0C,QAAQ;AAChE,QAAI,CAAC,MAAO,OAAM,IAAI,cAAc,KAAK,EAAE,OAAO,gEAAgE,CAAC;AACnH,UAAM,KAAK,IAAI,UAAU,QAAQ,IAAI;AACrC,UAAM,aAAa,IAAI,UAAU,QAAQ,YAAY;AACrD,QAAI,OAAO,MAAM;AAAA,MACf;AAAA,MACA;AAAA,MACA,EAAE,IAAI,MAAM,GAAG;AAAA,MACf,CAAC;AAAA,MACD,EAAE,UAAU,MAAM,UAAU,gBAAgB,MAAM,eAAe;AAAA,IACnE;AACA,QAAI,MAAM;AACR,8BAAwB,MAAM,KAAK;AACnC,WAAK,YAAY;AACjB,WAAK,OAAO,MAAM,wBAAwB,IAAI,KAAK;AAAA,IACrD,OAAO;AACL,aAAO,GAAG,OAAO,cAAc;AAAA,QAC7B,GAAG,uBAAuB,KAAK;AAAA,QAC/B,MAAM,MAAM,wBAAwB,IAAI,KAAK;AAAA,MAC/C,CAAC;AACD,SAAG,QAAQ,IAAI;AAAA,IACjB;AACA,UAAM,GAAG,MAAM;AACf,UAAM,QAAQ,yBAAyB,MAAM,QAAQ,MAAS;AAC9D,QAAI,OAAO,KAAK,KAAK,EAAE,QAAQ;AAC7B,YAAM,qBAAqB;AAAA,QACzB;AAAA,QACA,UAAU,oBAAoB;AAAA,QAC9B,UAAU,MAAM;AAAA,QAChB,UAAU,MAAM;AAAA,QAChB,gBAAgB,MAAM;AAAA,QACtB,QAAQ;AAAA,QACR,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AACA,UAAM,kBAAkB,yBAAyB;AAAA,MAC/C,IAAI,KAAK;AAAA,MACT,MAAM,KAAK;AAAA,MACX,QAAQ,KAAK;AAAA,MACb,UAAU,MAAM;AAAA,MAChB,gBAAgB,MAAM;AAAA,IACxB,CAAC,EAAE,MAAM,MAAM,MAAS;AACxB,QAAI,KAAK,WAAW,UAAU;AAC5B,YAAM,kBAAkB,2BAA2B;AAAA,QACjD,IAAI,KAAK;AAAA,QACT,MAAM,KAAK;AAAA,QACX,UAAU,MAAM;AAAA,QAChB,gBAAgB,MAAM;AAAA,MACxB,CAAC,EAAE,MAAM,MAAM,MAAS;AAAA,IAC1B;AACA,WAAO,EAAE,IAAI,KAAK,IAAI,MAAM,KAAK,KAAK;AAAA,EACxC;AACF;AAEA,MAAM,oBAAyF;AAAA,EAC7F,IAAI;AAAA,EACJ,MAAM,QAAQ,UAAU,KAAK;AAC3B,UAAM,EAAE,OAAO,IAAI,mBAAmB,UAAU,iBAAiB,KAAK;AACtE,UAAM,QAAQ,oBAAoB,GAAG;AACrC,UAAM,KAAK,IAAI,UAAU,QAAQ,IAAI;AACrC,UAAM,OAAO,MAAM,sBAAsB,IAAI,cAAc;AAAA,MACzD,IAAI,OAAO;AAAA,MACX,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB,WAAW;AAAA,IACb,GAAG,QAAW,KAAK;AACnB,QAAI,CAAC,KAAM,QAAO,CAAC;AACnB,UAAM,SAAS,MAAM,wBAAwB,IAAI;AAAA,MAC/C,UAAU,oBAAoB;AAAA,MAC9B,UAAU,KAAK;AAAA,MACf,UAAU,KAAK;AAAA,MACf,gBAAgB,KAAK;AAAA,IACvB,CAAC;AACD,WAAO,EAAE,QAAQ,oBAAoB,MAAM,MAAM,EAAE;AAAA,EACrD;AAAA,EACA,MAAM,QAAQ,UAAU,KAAK;AAC3B,UAAM,EAAE,QAAQ,aAAa,IAAI,mBAAmB,UAAU,iBAAiB,KAAK;AACpF,UAAM,QAAQ,oBAAoB,GAAG;AACrC,UAAM,KAAK,IAAI,UAAU,QAAQ,IAAI;AACrC,UAAM,aAAa,IAAI,UAAU,QAAQ,YAAY;AACrD,UAAM,OAAO,MAAM,sBAAsB,IAAI,cAAc;AAAA,MACzD,IAAI,OAAO;AAAA,MACX,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB,WAAW;AAAA,IACb,GAAG,QAAW,KAAK;AACnB,QAAI,CAAC,KAAM,OAAM,IAAI,cAAc,KAAK,EAAE,OAAO,iBAAiB,CAAC;AACnE,UAAM,uCAAuC,IAAI,WAAW;AAAA,MAC1D,cAAc;AAAA,MACd,YAAY,KAAK;AAAA,MACjB,SAAS,KAAK,aAAa;AAAA,MAC3B,SAAS,IAAI,WAAW;AAAA,IAC1B,CAAC;AACD,QAAI,KAAK,UAAU;AACjB,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,yDAAyD,CAAC;AAAA,IAClG;AACA,UAAM,aAAa,8BAA8B,MAAM,MAAM;AAC7D;AAAA,MACE,OAAO,sBAAsB,KAAK,sBAAsB;AAAA,MACxD,2BAA2B,UAAU;AAAA,IACvC;AACA,UAAM,oBAAoB,IAAI,UAAU,QAAQ,iCAAiC;AACjF,UAAM,gCAAgC,WAAW,sBAAsB,MAAM,mBAAmB,KAAK;AACrG,QAAI,qBAAqB,WAAW,MAAM,KAAK,CAAC,WAAW,oBAAoB;AAC7E,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,yEAAyE,CAAC;AAAA,IAClH;AACA,UAAM,OAAO,OAAO,SAAS,UAAa,OAAO,SAAS,UAAa,OAAO,UAAU,SACpF,MAAM,iBAAiB,IAAI,OAAO,OAAO,QAAQ,KAAK,MAAM,OAAO,SAAS,OAAO,QAAQ,KAAK,SAAS,KAAK,MAAM,KAAK,EAAE,IAC3H,KAAK;AACT,UAAM,eAAe,OAAO,aAAa,SAAY,MAAM,qBAAqB,OAAO,QAAQ,IAAI,KAAK;AACxG,UAAM,iBAAiB,KAAK;AAC5B,WAAO,OAAO,MAAM;AAAA,MAClB,GAAG;AAAA,MACH,kBAAkB,OAAO,qBAAqB,SAAY,cAAc,OAAO,gBAAgB,IAAI,KAAK;AAAA,MACxG,0BAA0B,OAAO,6BAA6B,SAAY,cAAc,OAAO,wBAAwB,IAAI,KAAK;AAAA,MAChI,iBAAiB,OAAO,oBAAoB,SAAY,cAAc,OAAO,eAAe,IAAI,KAAK;AAAA,MACrG,iBAAiB,OAAO,oBAAoB,SAAY,cAAc,OAAO,eAAe,IAAI,KAAK;AAAA,MACrG;AAAA,MACA;AAAA,IACF,CAAC;AACD,UAAM,GAAG,MAAM;AACf,UAAM,qBAAqB;AAAA,MACzB;AAAA,MACA,UAAU,oBAAoB;AAAA,MAC9B,UAAU,KAAK;AAAA,MACf,UAAU,MAAM;AAAA,MAChB,gBAAgB,MAAM;AAAA,MACtB,QAAQ;AAAA,IACV,CAAC;AACD,UAAM,kBAAkB,yBAAyB;AAAA,MAC/C,IAAI,KAAK;AAAA,MACT,MAAM,KAAK;AAAA,MACX,QAAQ,KAAK;AAAA,MACb;AAAA,MACA,UAAU,MAAM;AAAA,MAChB,gBAAgB,MAAM;AAAA,IACxB,CAAC,EAAE,MAAM,MAAM,MAAS;AACxB,QAAI,mBAAmB,YAAY,KAAK,WAAW,UAAU;AAC3D,YAAM,kBAAkB,2BAA2B;AAAA,QACjD,IAAI,KAAK;AAAA,QACT,MAAM,KAAK;AAAA,QACX,UAAU,MAAM;AAAA,QAChB,gBAAgB,MAAM;AAAA,MACxB,CAAC,EAAE,MAAM,MAAM,MAAS;AAAA,IAC1B;AACA,WAAO,EAAE,IAAI,MAAM,MAAM,KAAK,KAAK;AAAA,EACrC;AAAA,EACA,cAAc,OAAO,QAAQ,QAAQ,QAAQ;AAC3C,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,OAAO,MAAM,sBAAsB,IAAI,cAAc,EAAE,MAAM,OAAO,MAAM,WAAW,KAAK,CAAC;AACjG,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,SAAS,MAAM,wBAAwB,IAAI;AAAA,MAC/C,UAAU,oBAAoB;AAAA,MAC9B,UAAU,KAAK;AAAA,MACf,UAAU,KAAK;AAAA,MACf,gBAAgB,KAAK;AAAA,IACvB,CAAC;AACD,WAAO,oBAAoB,MAAM,MAAM;AAAA,EACzC;AAAA,EACA,UAAU,OAAO,EAAE,WAAW,OAAO,MAAM;AACzC,UAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,UAAM,SAAS,UAAU;AACzB,UAAM,QAAQ,UAAU;AACxB,WAAO;AAAA,MACL,aAAa,UAAU,+BAA+B,iBAAiB;AAAA,MACvE,cAAc;AAAA,MACd,YAAY,OAAO,MAAM,QAAQ,MAAM;AAAA,MACvC,UAAU,OAAO,YAAY,QAAQ,YAAY;AAAA,MACjD,gBAAgB,OAAO,kBAAkB,QAAQ,kBAAkB;AAAA,MACnE,gBAAgB,SAAS,wBAAwB,MAAM,IAAI;AAAA,MAC3D,eAAe,QAAQ,wBAAwB,KAAK,IAAI;AAAA,MACxD,SAAS;AAAA,QACP,MAAM;AAAA,UACJ,QAAQ,UAAU;AAAA,UAClB,OAAO,SAAS;AAAA,QAClB;AAAA,MACF;AAAA,MACA,SAAS,OAAO,OAAO,EAAE,MAAM,OAAO,KAAK,IAAI;AAAA,IACjD;AAAA,EACF;AAAA,EACA,MAAM,OAAO,EAAE,UAAU,IAAI,MAAM;AACjC,UAAM,OAAO,mBAA4C,QAAQ;AACjE,UAAM,SAAS,MAAM;AACrB,UAAM,QAAQ,MAAM;AACpB,QAAI,CAAC,OAAQ;AACb,UAAM,KAAK,IAAI,UAAU,QAAQ,IAAI;AACrC,UAAM,aAAa,IAAI,UAAU,QAAQ,YAAY;AACrD,UAAM,OAAO,MAAM,GAAG,QAAQ,cAAc,EAAE,IAAI,OAAO,IAAI,WAAW,KAAK,CAAC;AAC9E,QAAI,CAAC,KAAM;AACX,4BAAwB,MAAM,MAAM;AACpC,SAAK,OAAO,MAAM,wBAAwB,IAAI,MAAM;AACpD,UAAM,GAAG,MAAM;AACf,UAAM,QAAQ,yBAAyB,OAAO,QAAQ,OAAO,MAAM;AACnE,QAAI,OAAO,KAAK,KAAK,EAAE,QAAQ;AAC7B,YAAM,qBAAqB;AAAA,QACzB;AAAA,QACA,UAAU,oBAAoB;AAAA,QAC9B,UAAU,OAAO;AAAA,QACjB,UAAU,OAAO;AAAA,QACjB,gBAAgB,OAAO;AAAA,QACvB,QAAQ;AAAA,QACR,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,MAAM,oBAA2E;AAAA,EAC/E,IAAI;AAAA,EACJ,MAAM,QAAQ,UAAU,KAAK;AAC3B,UAAM,SAAS,cAAc,UAAU,qBAAqB;AAC5D,UAAM,QAAQ,oBAAoB,GAAG;AACrC,UAAM,KAAK,IAAI,UAAU,QAAQ,IAAI;AACrC,UAAM,OAAO,MAAM,sBAAsB,IAAI,cAAc;AAAA,MACzD,IAAI;AAAA,MACJ,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB,WAAW;AAAA,IACb,GAAG,QAAW,KAAK;AACnB,QAAI,CAAC,KAAM,QAAO,CAAC;AACnB,UAAM,SAAS,MAAM,wBAAwB,IAAI;AAAA,MAC/C,UAAU,oBAAoB;AAAA,MAC9B,UAAU,KAAK;AAAA,MACf,UAAU,KAAK;AAAA,MACf,gBAAgB,KAAK;AAAA,IACvB,CAAC;AACD,WAAO,EAAE,QAAQ,oBAAoB,MAAM,MAAM,EAAE;AAAA,EACrD;AAAA,EACA,MAAM,QAAQ,UAAU,KAAK;AAC3B,UAAM,SAAS,cAAc,UAAU,qBAAqB;AAC5D,UAAM,QAAQ,oBAAoB,GAAG;AACrC,UAAM,KAAK,IAAI,UAAU,QAAQ,IAAI;AACrC,UAAM,OAAO,MAAM,sBAAsB,IAAI,cAAc;AAAA,MACzD,IAAI;AAAA,MACJ,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB,WAAW;AAAA,IACb,GAAG,QAAW,KAAK;AACnB,QAAI,CAAC,KAAM,OAAM,IAAI,cAAc,KAAK,EAAE,OAAO,iBAAiB,CAAC;AACnE,UAAM,uCAAuC,IAAI,WAAW;AAAA,MAC1D,cAAc;AAAA,MACd,YAAY,KAAK;AAAA,MACjB,SAAS,KAAK,aAAa;AAAA,MAC3B,SAAS,IAAI,WAAW;AAAA,IAC1B,CAAC;AACD,UAAM,cAAc,MAAM,GAAG,MAAM,qBAAqB;AAAA,MACtD,QAAQ,KAAK;AAAA,MACb,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB,QAAQ,EAAE,KAAK,4BAAoE;AAAA,IACrF,CAAC;AACD,QAAI,cAAc,GAAG;AACnB,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,0DAA0D,CAAC;AAAA,IACnG;AACA,SAAK,YAAY,oBAAI,KAAK;AAC1B,UAAM,GAAG,MAAM;AACf,UAAM,kBAAkB,yBAAyB;AAAA,MAC/C,IAAI,KAAK;AAAA,MACT,MAAM,KAAK;AAAA,MACX,UAAU,MAAM;AAAA,MAChB,gBAAgB,MAAM;AAAA,IACxB,CAAC,EAAE,MAAM,MAAM,MAAS;AACxB,WAAO,EAAE,IAAI,KAAK;AAAA,EACpB;AAAA,EACA,UAAU,OAAO,EAAE,WAAW,MAAM,MAAM;AACxC,UAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,UAAM,SAAS,UAAU;AACzB,WAAO;AAAA,MACL,aAAa,UAAU,+BAA+B,iBAAiB;AAAA,MACvE,cAAc;AAAA,MACd,YAAY,QAAQ,MAAM,cAAc,OAAO,qBAAqB;AAAA,MACpE,UAAU,QAAQ,YAAY;AAAA,MAC9B,gBAAgB,QAAQ,kBAAkB;AAAA,MAC1C,gBAAgB,SAAS,wBAAwB,MAAM,IAAI;AAAA,MAC3D,SAAS;AAAA,QACP,MAAM;AAAA,UACJ,QAAQ,UAAU;AAAA,QACpB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,MAAM,OAAO,EAAE,UAAU,IAAI,MAAM;AACjC,UAAM,SAAS,mBAA4C,QAAQ,GAAG;AACtE,QAAI,CAAC,OAAQ;AACb,UAAM,KAAK,IAAI,UAAU,QAAQ,IAAI;AACrC,UAAM,aAAa,IAAI,UAAU,QAAQ,YAAY;AACrD,QAAI,OAAO,MAAM,GAAG,QAAQ,cAAc,EAAE,IAAI,OAAO,GAAG,CAAC;AAC3D,QAAI,MAAM;AACR,8BAAwB,MAAM,MAAM;AACpC,WAAK,OAAO,MAAM,wBAAwB,IAAI,MAAM;AAAA,IACtD,OAAO;AACL,aAAO,GAAG,OAAO,cAAc;AAAA,QAC7B,GAAG,uBAAuB,MAAM;AAAA,QAChC,MAAM,MAAM,wBAAwB,IAAI,MAAM;AAAA,MAChD,CAAC;AACD,SAAG,QAAQ,IAAI;AAAA,IACjB;AACA,UAAM,GAAG,MAAM;AACf,UAAM,QAAQ,yBAAyB,OAAO,QAAQ,MAAS;AAC/D,QAAI,OAAO,KAAK,KAAK,EAAE,QAAQ;AAC7B,YAAM,qBAAqB;AAAA,QACzB;AAAA,QACA,UAAU,oBAAoB;AAAA,QAC9B,UAAU,OAAO;AAAA,QACjB,UAAU,OAAO;AAAA,QACjB,gBAAgB,OAAO;AAAA,QACvB,QAAQ;AAAA,QACR,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,gBAAgB,iBAAiB;AACjC,gBAAgB,iBAAiB;AACjC,gBAAgB,iBAAiB;AAE1B,SAAS,oBAAoB,QAAsB;AAKxD,SAAO,EAAE,GAAG,wBAAwB,MAAM,GAAG,iBAAiB,OAAO,mBAAmB,EAAE;AAC5F;",
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport { buildCustomFieldResetMap, loadCustomFieldSnapshot } from '@open-mercato/shared/lib/commands/customFieldSnapshots'\nimport { setCustomFieldsIfAny } from '@open-mercato/shared/lib/commands/helpers'\nimport { resolveRedoSnapshot } from '@open-mercato/shared/lib/commands/redo'\nimport { loadCustomFieldValues } from '@open-mercato/shared/lib/crud/custom-fields'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { enforceCommandOptimisticLockWithGuards } from '@open-mercato/shared/lib/crud/optimistic-lock-command'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CheckoutLink, CheckoutLinkTemplate, CheckoutTransaction } from '../data/entities'\nimport { createLinkSchema, updateLinkSchema } from '../data/validators'\nimport { CHECKOUT_ENTITY_IDS } from '../lib/constants'\nimport {\n ensureGatewayProviderConfigured,\n type PaymentGatewayDescriptorService,\n} from '../lib/gatewayProviderAvailability'\nimport { emitCheckoutEvent } from '../events'\nimport {\n deriveConfiguredCurrencies,\n ensureUniqueSlug,\n hashCheckoutPassword,\n isCheckoutLinkPublic,\n parseCheckoutInput,\n pickExplicitParsedOverrides,\n resolveLoadedCheckoutCustomFields,\n serializeTemplateOrLink,\n toMoneyString,\n toTemplateOrLinkMutationInput,\n validateDescriptorCurrencies,\n} from '../lib/utils'\nimport {\n captureLinkSnapshot,\n createLinkFromSnapshot,\n extractUndoPayload,\n readCommandId,\n resolveCommandScope,\n restoreLinkFromSnapshot,\n toCheckoutAuditSnapshot,\n type CheckoutLinkSnapshot,\n} from './shared'\n\nconst ACTIVE_TRANSACTION_STATUSES = ['pending', 'processing']\n\ntype CheckoutLinkUndoPayload = {\n before?: CheckoutLinkSnapshot | null\n after?: CheckoutLinkSnapshot | null\n}\n\nasync function resolveRestoredLinkSlug(\n em: EntityManager,\n snapshot: CheckoutLinkSnapshot,\n): Promise<string> {\n return ensureUniqueSlug(\n em,\n {\n tenantId: snapshot.tenantId,\n organizationId: snapshot.organizationId,\n },\n snapshot.slug,\n snapshot.title ?? snapshot.name,\n snapshot.id,\n )\n}\n\nconst createLinkCommand: CommandHandler<Record<string, unknown>, { id: string; slug: string }> = {\n id: 'checkout.link.create',\n async execute(rawInput, ctx) {\n const { parsed, customFields } = parseCheckoutInput(rawInput, createLinkSchema.parse)\n const scope = resolveCommandScope(ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n\n let sourceValues = parsed\n let templateCustomFields: Record<string, unknown> = {}\n if (parsed.templateId) {\n const template = await findOneWithDecryption(em, CheckoutLinkTemplate, {\n id: parsed.templateId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!template) throw new CrudHttpError(404, { error: 'Template not found' })\n sourceValues = toTemplateOrLinkMutationInput(template, {\n ...pickExplicitParsedOverrides(rawInput, parsed),\n templateId: template.id,\n })\n const loaded = await loadCustomFieldValues({\n em,\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordIds: [template.id],\n tenantIdByRecord: { [template.id]: scope.tenantId },\n organizationIdByRecord: { [template.id]: scope.organizationId },\n })\n templateCustomFields = resolveLoadedCheckoutCustomFields(loaded[template.id])\n }\n\n validateDescriptorCurrencies(sourceValues.gatewayProviderKey ?? null, deriveConfiguredCurrencies(sourceValues))\n const descriptorService = ctx.container.resolve('paymentGatewayDescriptorService') as PaymentGatewayDescriptorService\n await ensureGatewayProviderConfigured(sourceValues.gatewayProviderKey ?? null, descriptorService, scope)\n if (isCheckoutLinkPublic(sourceValues.status) && !sourceValues.gatewayProviderKey) {\n throw new CrudHttpError(422, { error: 'A payment gateway must be configured before this link can be published' })\n }\n const slug = await ensureUniqueSlug(\n em,\n scope,\n sourceValues.slug ?? null,\n sourceValues.title ?? sourceValues.name,\n )\n const link = em.create(CheckoutLink, {\n ...sourceValues,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n completionCount: 0,\n activeReservationCount: 0,\n isLocked: false,\n fixedPriceAmount: toMoneyString(sourceValues.fixedPriceAmount),\n fixedPriceOriginalAmount: toMoneyString(sourceValues.fixedPriceOriginalAmount),\n customAmountMin: toMoneyString(sourceValues.customAmountMin),\n customAmountMax: toMoneyString(sourceValues.customAmountMax),\n slug,\n passwordHash: await hashCheckoutPassword(sourceValues.password),\n } as any)\n em.persist(link)\n await em.flush()\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n values: { ...templateCustomFields, ...customFields },\n })\n await emitCheckoutEvent('checkout.link.created', {\n id: link.id,\n slug: link.slug,\n status: link.status,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n if (link.status === 'active') {\n await emitCheckoutEvent('checkout.link.published', {\n id: link.id,\n slug: link.slug,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n }\n return { id: link.id, slug: link.slug }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const link = await findOneWithDecryption(em, CheckoutLink, { id: result.id })\n if (!link) return null\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: link.tenantId,\n organizationId: link.organizationId,\n })\n return captureLinkSnapshot(link, custom)\n },\n buildLog: async ({ result, snapshots }) => {\n const { translate } = await resolveTranslations()\n const after = snapshots.after as CheckoutLinkSnapshot | null | undefined\n return {\n actionLabel: translate('checkout.audit.links.create', 'Create pay link'),\n resourceKind: 'checkout.link',\n resourceId: result.id,\n tenantId: after?.tenantId ?? null,\n organizationId: after?.organizationId ?? null,\n snapshotAfter: after ? toCheckoutAuditSnapshot(after) : null,\n payload: {\n undo: {\n after: after ?? null,\n } satisfies CheckoutLinkUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const after = extractUndoPayload<CheckoutLinkUndoPayload>(logEntry)?.after\n if (!after) return\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n const reset = buildCustomFieldResetMap(undefined, after.custom)\n if (Object.keys(reset).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: after.id,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n values: reset,\n notify: false,\n })\n }\n const link = await em.findOne(CheckoutLink, { id: after.id })\n if (!link) return\n link.deletedAt = new Date()\n await em.flush()\n },\n redo: async ({ logEntry, ctx }) => {\n const after = resolveRedoSnapshot<CheckoutLinkSnapshot>(logEntry)\n if (!after) throw new CrudHttpError(400, { error: '[internal] redo snapshot unavailable for checkout link create' })\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n let link = await findOneWithDecryption(\n em,\n CheckoutLink,\n { id: after.id },\n {},\n { tenantId: after.tenantId, organizationId: after.organizationId },\n )\n if (link) {\n restoreLinkFromSnapshot(link, after)\n link.deletedAt = null\n link.slug = await resolveRestoredLinkSlug(em, after)\n } else {\n link = em.create(CheckoutLink, {\n ...createLinkFromSnapshot(after),\n slug: await resolveRestoredLinkSlug(em, after),\n })\n em.persist(link)\n }\n await em.flush()\n const reset = buildCustomFieldResetMap(after.custom, undefined)\n if (Object.keys(reset).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: after.id,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n values: reset,\n notify: false,\n })\n }\n await emitCheckoutEvent('checkout.link.created', {\n id: link.id,\n slug: link.slug,\n status: link.status,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n }).catch(() => undefined)\n if (link.status === 'active') {\n await emitCheckoutEvent('checkout.link.published', {\n id: link.id,\n slug: link.slug,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n }).catch(() => undefined)\n }\n return { id: link.id, slug: link.slug }\n },\n}\n\nconst updateLinkCommand: CommandHandler<Record<string, unknown>, { ok: true; slug: string }> = {\n id: 'checkout.link.update',\n async prepare(rawInput, ctx) {\n const { parsed } = parseCheckoutInput(rawInput, updateLinkSchema.parse)\n const scope = resolveCommandScope(ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const link = await findOneWithDecryption(em, CheckoutLink, {\n id: parsed.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!link) return {}\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: link.tenantId,\n organizationId: link.organizationId,\n })\n return { before: captureLinkSnapshot(link, custom) }\n },\n async execute(rawInput, ctx) {\n const { parsed, customFields } = parseCheckoutInput(rawInput, updateLinkSchema.parse)\n const scope = resolveCommandScope(ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n const link = await findOneWithDecryption(em, CheckoutLink, {\n id: parsed.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!link) throw new CrudHttpError(404, { error: 'Link not found' })\n await enforceCommandOptimisticLockWithGuards(ctx.container, {\n resourceKind: 'checkout.link',\n resourceId: link.id,\n current: link.updatedAt ?? null,\n request: ctx.request ?? null,\n })\n if (link.isLocked) {\n throw new CrudHttpError(422, { error: 'This link has active transactions and cannot be edited' })\n }\n const nextValues = toTemplateOrLinkMutationInput(link, parsed)\n validateDescriptorCurrencies(\n parsed.gatewayProviderKey ?? link.gatewayProviderKey ?? null,\n deriveConfiguredCurrencies(nextValues),\n )\n const descriptorService = ctx.container.resolve('paymentGatewayDescriptorService') as PaymentGatewayDescriptorService\n await ensureGatewayProviderConfigured(nextValues.gatewayProviderKey ?? null, descriptorService, scope)\n if (isCheckoutLinkPublic(nextValues.status) && !nextValues.gatewayProviderKey) {\n throw new CrudHttpError(422, { error: 'A payment gateway must be configured before this link can be published' })\n }\n const slug = parsed.slug !== undefined || parsed.name !== undefined || parsed.title !== undefined\n ? await ensureUniqueSlug(em, scope, parsed.slug ?? link.slug, parsed.title ?? parsed.name ?? link.title ?? link.name, link.id)\n : link.slug\n const passwordHash = parsed.password !== undefined ? await hashCheckoutPassword(parsed.password) : link.passwordHash\n const previousStatus = link.status\n Object.assign(link, {\n ...parsed,\n fixedPriceAmount: parsed.fixedPriceAmount !== undefined ? toMoneyString(parsed.fixedPriceAmount) : link.fixedPriceAmount,\n fixedPriceOriginalAmount: parsed.fixedPriceOriginalAmount !== undefined ? toMoneyString(parsed.fixedPriceOriginalAmount) : link.fixedPriceOriginalAmount,\n customAmountMin: parsed.customAmountMin !== undefined ? toMoneyString(parsed.customAmountMin) : link.customAmountMin,\n customAmountMax: parsed.customAmountMax !== undefined ? toMoneyString(parsed.customAmountMax) : link.customAmountMax,\n slug,\n passwordHash,\n })\n await em.flush()\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n values: customFields,\n })\n await emitCheckoutEvent('checkout.link.updated', {\n id: link.id,\n slug: link.slug,\n status: link.status,\n previousStatus,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n if (previousStatus !== 'active' && link.status === 'active') {\n await emitCheckoutEvent('checkout.link.published', {\n id: link.id,\n slug: link.slug,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n }\n return { ok: true, slug: link.slug }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const link = await findOneWithDecryption(em, CheckoutLink, { slug: result.slug, deletedAt: null })\n if (!link) return null\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: link.tenantId,\n organizationId: link.organizationId,\n })\n return captureLinkSnapshot(link, custom)\n },\n buildLog: async ({ snapshots, result }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as CheckoutLinkSnapshot | null | undefined\n const after = snapshots.after as CheckoutLinkSnapshot | null | undefined\n return {\n actionLabel: translate('checkout.audit.links.update', 'Update pay link'),\n resourceKind: 'checkout.link',\n resourceId: after?.id ?? before?.id ?? null,\n tenantId: after?.tenantId ?? before?.tenantId ?? null,\n organizationId: after?.organizationId ?? before?.organizationId ?? null,\n snapshotBefore: before ? toCheckoutAuditSnapshot(before) : null,\n snapshotAfter: after ? toCheckoutAuditSnapshot(after) : null,\n payload: {\n undo: {\n before: before ?? null,\n after: after ?? null,\n } satisfies CheckoutLinkUndoPayload,\n },\n context: result.slug ? { slug: result.slug } : null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<CheckoutLinkUndoPayload>(logEntry)\n const before = undo?.before\n const after = undo?.after\n if (!before) return\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n const link = await em.findOne(CheckoutLink, { id: before.id, deletedAt: null })\n if (!link) return\n restoreLinkFromSnapshot(link, before)\n link.slug = await resolveRestoredLinkSlug(em, before)\n await em.flush()\n const reset = buildCustomFieldResetMap(before.custom, after?.custom)\n if (Object.keys(reset).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n values: reset,\n notify: false,\n })\n }\n },\n}\n\nconst deleteLinkCommand: CommandHandler<Record<string, unknown>, { ok: true }> = {\n id: 'checkout.link.delete',\n async prepare(rawInput, ctx) {\n const linkId = readCommandId(rawInput, 'Link id is required')\n const scope = resolveCommandScope(ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const link = await findOneWithDecryption(em, CheckoutLink, {\n id: linkId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!link) return {}\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: link.tenantId,\n organizationId: link.organizationId,\n })\n return { before: captureLinkSnapshot(link, custom) }\n },\n async execute(rawInput, ctx) {\n const linkId = readCommandId(rawInput, 'Link id is required')\n const scope = resolveCommandScope(ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const link = await findOneWithDecryption(em, CheckoutLink, {\n id: linkId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!link) throw new CrudHttpError(404, { error: 'Link not found' })\n await enforceCommandOptimisticLockWithGuards(ctx.container, {\n resourceKind: 'checkout.link',\n resourceId: link.id,\n current: link.updatedAt ?? null,\n request: ctx.request ?? null,\n })\n const activeCount = await em.count(CheckoutTransaction, {\n linkId: link.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n status: { $in: ACTIVE_TRANSACTION_STATUSES as Array<CheckoutTransaction['status']> },\n })\n if (activeCount > 0) {\n throw new CrudHttpError(422, { error: 'This link has active transactions and cannot be deleted' })\n }\n link.deletedAt = new Date()\n await em.flush()\n await emitCheckoutEvent('checkout.link.deleted', {\n id: link.id,\n slug: link.slug,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n return { ok: true }\n },\n buildLog: async ({ snapshots, input }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as CheckoutLinkSnapshot | null | undefined\n return {\n actionLabel: translate('checkout.audit.links.delete', 'Delete pay link'),\n resourceKind: 'checkout.link',\n resourceId: before?.id ?? readCommandId(input, 'Link id is required'),\n tenantId: before?.tenantId ?? null,\n organizationId: before?.organizationId ?? null,\n snapshotBefore: before ? toCheckoutAuditSnapshot(before) : null,\n payload: {\n undo: {\n before: before ?? null,\n } satisfies CheckoutLinkUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const before = extractUndoPayload<CheckoutLinkUndoPayload>(logEntry)?.before\n if (!before) return\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n let link = await em.findOne(CheckoutLink, { id: before.id })\n if (link) {\n restoreLinkFromSnapshot(link, before)\n link.slug = await resolveRestoredLinkSlug(em, before)\n } else {\n link = em.create(CheckoutLink, {\n ...createLinkFromSnapshot(before),\n slug: await resolveRestoredLinkSlug(em, before),\n })\n em.persist(link)\n }\n await em.flush()\n const reset = buildCustomFieldResetMap(before.custom, undefined)\n if (Object.keys(reset).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n values: reset,\n notify: false,\n })\n }\n },\n}\n\nregisterCommand(createLinkCommand)\nregisterCommand(updateLinkCommand)\nregisterCommand(deleteLinkCommand)\n\nexport function serializeLinkRecord(record: CheckoutLink) {\n return serializeTemplateOrLink(record)\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -10,7 +10,6 @@ import {
10
10
  parseCheckoutInput,
11
11
  toMoneyString
12
12
  } from "../lib/utils.js";
13
- import { assertValidCheckoutStatusTransition } from "../lib/transaction-status-machine.js";
14
13
  function resolveTransactionScope(input) {
15
14
  if (!input.organizationId || !input.tenantId) {
16
15
  throw new CrudHttpError(400, { error: "Transaction scope is required" });
@@ -146,39 +145,10 @@ const updateTransactionStatusCommand = {
146
145
  const nextStatus = parsed.status;
147
146
  const previousTerminal = isTerminalCheckoutStatus(previousStatus);
148
147
  const nextTerminal = isTerminalCheckoutStatus(nextStatus);
149
- assertValidCheckoutStatusTransition(previousStatus, nextStatus);
150
- const newPaymentStatus = parsed.paymentStatus ?? transaction.paymentStatus ?? null;
151
- const newGatewayTransactionId = parsed.gatewayTransactionId ?? transaction.gatewayTransactionId ?? null;
152
- const affected = await tx.nativeUpdate(
153
- CheckoutTransaction,
154
- {
155
- id: parsed.id,
156
- organizationId: scope.organizationId,
157
- tenantId: scope.tenantId,
158
- status: previousStatus
159
- },
160
- {
161
- status: nextStatus,
162
- paymentStatus: newPaymentStatus,
163
- gatewayTransactionId: newGatewayTransactionId,
164
- updatedAt: /* @__PURE__ */ new Date()
165
- }
166
- );
167
- if (affected === 0) {
168
- const actualTx = await tx.findOne(
169
- CheckoutTransaction,
170
- { id: parsed.id, organizationId: scope.organizationId, tenantId: scope.tenantId },
171
- { fields: ["status"], refresh: true }
172
- );
173
- throw new CrudHttpError(409, {
174
- error: `[internal] Transaction status was already updated by a concurrent process (expected "${previousStatus}", actual "${actualTx?.status ?? "unknown"}")`,
175
- code: "concurrent_status_update",
176
- expectedStatus: previousStatus,
177
- currentStatus: actualTx?.status ?? "unknown",
178
- requestedStatus: nextStatus
179
- });
180
- }
181
- await tx.refresh(transaction);
148
+ transaction.status = nextStatus;
149
+ transaction.paymentStatus = parsed.paymentStatus ?? transaction.paymentStatus ?? null;
150
+ transaction.gatewayTransactionId = parsed.gatewayTransactionId ?? transaction.gatewayTransactionId ?? null;
151
+ await tx.flush();
182
152
  if (!previousTerminal && nextTerminal) {
183
153
  const { usageLimitReached } = applyTerminalTransactionState(link, nextStatus);
184
154
  await tx.flush();
@@ -188,7 +158,7 @@ const updateTransactionStatusCommand = {
188
158
  usageLimitReachedLinkSlug = link.slug;
189
159
  }
190
160
  }
191
- if (nextTerminal && previousStatus !== nextStatus) {
161
+ if (nextTerminal) {
192
162
  terminalEventPayload = {
193
163
  transactionId: transaction.id,
194
164
  linkId: transaction.linkId,
@@ -206,16 +176,14 @@ const updateTransactionStatusCommand = {
206
176
  };
207
177
  }
208
178
  });
209
- if (terminalEventPayload !== null) {
210
- if (parsed.status === "completed") {
211
- await emitCheckoutEvent("checkout.transaction.completed", terminalEventPayload).catch(() => void 0);
212
- } else if (parsed.status === "failed") {
213
- await emitCheckoutEvent("checkout.transaction.failed", terminalEventPayload).catch(() => void 0);
214
- } else if (parsed.status === "cancelled") {
215
- await emitCheckoutEvent("checkout.transaction.cancelled", terminalEventPayload).catch(() => void 0);
216
- } else if (parsed.status === "expired") {
217
- await emitCheckoutEvent("checkout.transaction.expired", terminalEventPayload).catch(() => void 0);
218
- }
179
+ if (parsed.status === "completed") {
180
+ await emitCheckoutEvent("checkout.transaction.completed", terminalEventPayload ?? {}).catch(() => void 0);
181
+ } else if (parsed.status === "failed") {
182
+ await emitCheckoutEvent("checkout.transaction.failed", terminalEventPayload ?? {}).catch(() => void 0);
183
+ } else if (parsed.status === "cancelled") {
184
+ await emitCheckoutEvent("checkout.transaction.cancelled", terminalEventPayload ?? {}).catch(() => void 0);
185
+ } else if (parsed.status === "expired") {
186
+ await emitCheckoutEvent("checkout.transaction.expired", terminalEventPayload ?? {}).catch(() => void 0);
219
187
  }
220
188
  if (emitUsageLimitReached && usageLimitReachedLinkId && usageLimitReachedLinkSlug) {
221
189
  await emitCheckoutEvent("checkout.link.usageLimitReached", {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/checkout/commands/transactions.ts"],
4
- "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { CheckoutLink, CheckoutTransaction } from '../data/entities'\nimport { transactionCreateSchema, transactionUpdateStatusSchema } from '../data/validators'\nimport { emitCheckoutEvent } from '../events'\nimport {\n applyTerminalTransactionState,\n isTerminalCheckoutStatus,\n mapGatewayStatusToCheckoutStatus,\n parseCheckoutInput,\n toMoneyString,\n} from '../lib/utils'\nimport { assertValidCheckoutStatusTransition } from '../lib/transaction-status-machine'\n\nfunction resolveTransactionScope(input: { tenantId?: string | null; organizationId?: string | null }) {\n if (!input.organizationId || !input.tenantId) {\n throw new CrudHttpError(400, { error: 'Transaction scope is required' })\n }\n return {\n organizationId: input.organizationId,\n tenantId: input.tenantId,\n }\n}\n\ntype CheckoutTerminalEventPayload = {\n transactionId: string\n linkId: string\n templateId: string | null\n slug: string\n status: CheckoutTransaction['status']\n paymentStatus: string | null\n amount: number\n currency: string\n gatewayProvider: string | null\n gatewayTransactionId: string | null\n occurredAt: string\n tenantId: string\n organizationId: string\n}\n\nconst createTransactionCommand: CommandHandler<Record<string, unknown>, { id: string }> = {\n id: 'checkout.transaction.create',\n async execute(rawInput, ctx) {\n const { parsed } = parseCheckoutInput(rawInput, transactionCreateSchema.parse)\n const scope = resolveTransactionScope(parsed)\n const em = ctx.container.resolve('em') as EntityManager\n let lockedLinkId: string | null = null\n let lockedLinkSlug: string | null = null\n let lockedLinkTemplateId: string | null = null\n let lockedLinkGatewayProvider: string | null = null\n let shouldEmitLockedEvent = false\n const transaction = await em.transactional(async (tx) => {\n const currentLink = await tx.findOne(CheckoutLink, {\n id: parsed.linkId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!currentLink) {\n throw new CrudHttpError(404, { error: 'Payment link not found' })\n }\n if (currentLink.status !== 'active') {\n throw new CrudHttpError(422, { error: 'This payment link is not currently accepting payments' })\n }\n const reserved = await tx.getConnection().execute<Array<{ id: string }>>(\n `\n UPDATE checkout_links\n SET active_reservation_count = active_reservation_count + 1,\n is_locked = true,\n updated_at = now()\n WHERE id = ?\n AND organization_id = ?\n AND tenant_id = ?\n AND deleted_at IS NULL\n AND status = 'active'\n AND (\n max_completions IS NULL\n OR completion_count + active_reservation_count < max_completions\n )\n RETURNING id\n `,\n [parsed.linkId, scope.organizationId, scope.tenantId],\n )\n if (!reserved[0]?.id) {\n throw new CrudHttpError(422, { error: 'This payment link is no longer available' })\n }\n lockedLinkId = currentLink.id\n lockedLinkSlug = currentLink.slug\n lockedLinkTemplateId = currentLink.templateId ?? null\n lockedLinkGatewayProvider = currentLink.gatewayProviderKey ?? null\n shouldEmitLockedEvent = !currentLink.isLocked\n const transaction = tx.create(CheckoutTransaction, {\n ...parsed,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n amount: toMoneyString(parsed.amount) ?? '0.00',\n status: 'processing',\n })\n tx.persist(transaction)\n await tx.flush()\n return transaction\n })\n if (shouldEmitLockedEvent && lockedLinkId && lockedLinkSlug) {\n await emitCheckoutEvent('checkout.link.locked', {\n id: lockedLinkId,\n slug: lockedLinkSlug,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n }\n await emitCheckoutEvent('checkout.transaction.created', {\n transactionId: transaction.id,\n linkId: transaction.linkId,\n status: transaction.status,\n amount: Number(transaction.amount),\n currency: transaction.currencyCode,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n await emitCheckoutEvent('checkout.transaction.customerDataCaptured', {\n transactionId: transaction.id,\n linkId: transaction.linkId,\n templateId: lockedLinkTemplateId,\n slug: lockedLinkSlug,\n status: transaction.status,\n paymentStatus: transaction.paymentStatus ?? null,\n amount: Number(transaction.amount),\n currency: transaction.currencyCode,\n gatewayProvider: lockedLinkGatewayProvider,\n gatewayTransactionId: transaction.gatewayTransactionId ?? null,\n occurredAt: new Date().toISOString(),\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n customerDataCaptured: true,\n }).catch(() => undefined)\n return { id: transaction.id }\n },\n}\n\nconst updateTransactionStatusCommand: CommandHandler<Record<string, unknown>, { ok: true }> = {\n id: 'checkout.transaction.updateStatus',\n async execute(rawInput, ctx) {\n const { parsed } = parseCheckoutInput(rawInput, transactionUpdateStatusSchema.parse)\n const scope = resolveTransactionScope(parsed)\n const em = ctx.container.resolve('em') as EntityManager\n let terminalEventPayload: CheckoutTerminalEventPayload | null = null\n let emitUsageLimitReached = false\n let usageLimitReachedLinkId: string | null = null\n let usageLimitReachedLinkSlug: string | null = null\n await em.transactional(async (tx) => {\n const transaction = await tx.findOne(CheckoutTransaction, {\n id: parsed.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n if (!transaction) throw new CrudHttpError(404, { error: 'Transaction not found' })\n const link = await tx.findOne(CheckoutLink, {\n id: transaction.linkId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!link) throw new CrudHttpError(404, { error: 'Payment link not found' })\n\n const previousStatus = transaction.status\n const nextStatus = parsed.status\n const previousTerminal = isTerminalCheckoutStatus(previousStatus)\n const nextTerminal = isTerminalCheckoutStatus(nextStatus)\n\n // State-machine guard: reject any transition not permitted by the\n // VALID_CHECKOUT_TRANSITIONS map (e.g. completed \u2192 processing).\n // This runs inside the DB transaction so the check and the write share\n // the same serialisable snapshot.\n assertValidCheckoutStatusTransition(previousStatus, nextStatus)\n\n // Resolve the new field values before the write.\n const newPaymentStatus = parsed.paymentStatus ?? transaction.paymentStatus ?? null\n const newGatewayTransactionId = parsed.gatewayTransactionId ?? transaction.gatewayTransactionId ?? null\n\n // Atomic compare-and-swap: the WHERE clause pins the current status so\n // a concurrent writer that already advanced the status to a terminal\n // state will cause this update to match 0 rows \u2014 eliminating the TOCTOU\n // window between the findOne above and this write.\n const affected = await tx.nativeUpdate(\n CheckoutTransaction,\n {\n id: parsed.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n status: previousStatus,\n },\n {\n status: nextStatus,\n paymentStatus: newPaymentStatus,\n gatewayTransactionId: newGatewayTransactionId,\n updatedAt: new Date(),\n },\n )\n\n if (affected === 0) {\n // A concurrent writer already advanced the status. Force a DB round-trip\n // (refresh: true bypasses the MikroORM identity map) so the reported\n // currentStatus reflects the winning writer's value, not the stale snapshot.\n const actualTx = await tx.findOne(\n CheckoutTransaction,\n { id: parsed.id, organizationId: scope.organizationId, tenantId: scope.tenantId },\n { fields: ['status'], refresh: true },\n )\n throw new CrudHttpError(409, {\n error: `[internal] Transaction status was already updated by a concurrent process (expected \"${previousStatus}\", actual \"${actualTx?.status ?? 'unknown'}\")`,\n code: 'concurrent_status_update',\n expectedStatus: previousStatus,\n currentStatus: actualTx?.status ?? 'unknown',\n requestedStatus: nextStatus,\n })\n }\n\n // Sync the entity state in the unit of work by refreshing it.\n // This loads the updated values (status, paymentStatus, gatewayTransactionId)\n // from the DB and marks the entity as clean, avoiding a redundant second write\n // during the subsequent tx.flush().\n await tx.refresh(transaction)\n\n // Only apply terminal link state and emit the terminal event when the\n // status actually changes \u2014 prevents double-notification on idempotent\n // redeliveries (e.g. authorized \u2192 captured, both mapping to 'completed').\n if (!previousTerminal && nextTerminal) {\n const { usageLimitReached } = applyTerminalTransactionState(link, nextStatus)\n await tx.flush()\n if (usageLimitReached) {\n emitUsageLimitReached = true\n usageLimitReachedLinkId = link.id\n usageLimitReachedLinkSlug = link.slug\n }\n }\n if (nextTerminal && previousStatus !== nextStatus) {\n terminalEventPayload = {\n transactionId: transaction.id,\n linkId: transaction.linkId,\n templateId: link.templateId ?? null,\n slug: link.slug,\n status: transaction.status,\n paymentStatus: transaction.paymentStatus ?? null,\n amount: Number(transaction.amount),\n currency: transaction.currencyCode,\n gatewayProvider: link.gatewayProviderKey ?? null,\n gatewayTransactionId: transaction.gatewayTransactionId ?? null,\n occurredAt: new Date().toISOString(),\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }\n }\n })\n if (terminalEventPayload !== null) {\n if (parsed.status === 'completed') {\n await emitCheckoutEvent('checkout.transaction.completed', terminalEventPayload).catch(() => undefined)\n } else if (parsed.status === 'failed') {\n await emitCheckoutEvent('checkout.transaction.failed', terminalEventPayload).catch(() => undefined)\n } else if (parsed.status === 'cancelled') {\n await emitCheckoutEvent('checkout.transaction.cancelled', terminalEventPayload).catch(() => undefined)\n } else if (parsed.status === 'expired') {\n await emitCheckoutEvent('checkout.transaction.expired', terminalEventPayload).catch(() => undefined)\n }\n }\n if (emitUsageLimitReached && usageLimitReachedLinkId && usageLimitReachedLinkSlug) {\n await emitCheckoutEvent('checkout.link.usageLimitReached', {\n id: usageLimitReachedLinkId,\n slug: usageLimitReachedLinkSlug,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n }\n return { ok: true }\n },\n}\n\nregisterCommand(createTransactionCommand)\nregisterCommand(updateTransactionStatusCommand)\n\nexport function mapGatewayStatusForCommand(status: string | null | undefined) {\n return mapGatewayStatusToCheckoutStatus(status)\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { CheckoutLink, CheckoutTransaction } from '../data/entities'\nimport { transactionCreateSchema, transactionUpdateStatusSchema } from '../data/validators'\nimport { emitCheckoutEvent } from '../events'\nimport {\n applyTerminalTransactionState,\n isTerminalCheckoutStatus,\n mapGatewayStatusToCheckoutStatus,\n parseCheckoutInput,\n toMoneyString,\n} from '../lib/utils'\n\nfunction resolveTransactionScope(input: { tenantId?: string | null; organizationId?: string | null }) {\n if (!input.organizationId || !input.tenantId) {\n throw new CrudHttpError(400, { error: 'Transaction scope is required' })\n }\n return {\n organizationId: input.organizationId,\n tenantId: input.tenantId,\n }\n}\n\ntype CheckoutTerminalEventPayload = {\n transactionId: string\n linkId: string\n templateId: string | null\n slug: string\n status: CheckoutTransaction['status']\n paymentStatus: string | null\n amount: number\n currency: string\n gatewayProvider: string | null\n gatewayTransactionId: string | null\n occurredAt: string\n tenantId: string\n organizationId: string\n}\n\nconst createTransactionCommand: CommandHandler<Record<string, unknown>, { id: string }> = {\n id: 'checkout.transaction.create',\n async execute(rawInput, ctx) {\n const { parsed } = parseCheckoutInput(rawInput, transactionCreateSchema.parse)\n const scope = resolveTransactionScope(parsed)\n const em = ctx.container.resolve('em') as EntityManager\n let lockedLinkId: string | null = null\n let lockedLinkSlug: string | null = null\n let lockedLinkTemplateId: string | null = null\n let lockedLinkGatewayProvider: string | null = null\n let shouldEmitLockedEvent = false\n const transaction = await em.transactional(async (tx) => {\n const currentLink = await tx.findOne(CheckoutLink, {\n id: parsed.linkId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!currentLink) {\n throw new CrudHttpError(404, { error: 'Payment link not found' })\n }\n if (currentLink.status !== 'active') {\n throw new CrudHttpError(422, { error: 'This payment link is not currently accepting payments' })\n }\n const reserved = await tx.getConnection().execute<Array<{ id: string }>>(\n `\n UPDATE checkout_links\n SET active_reservation_count = active_reservation_count + 1,\n is_locked = true,\n updated_at = now()\n WHERE id = ?\n AND organization_id = ?\n AND tenant_id = ?\n AND deleted_at IS NULL\n AND status = 'active'\n AND (\n max_completions IS NULL\n OR completion_count + active_reservation_count < max_completions\n )\n RETURNING id\n `,\n [parsed.linkId, scope.organizationId, scope.tenantId],\n )\n if (!reserved[0]?.id) {\n throw new CrudHttpError(422, { error: 'This payment link is no longer available' })\n }\n lockedLinkId = currentLink.id\n lockedLinkSlug = currentLink.slug\n lockedLinkTemplateId = currentLink.templateId ?? null\n lockedLinkGatewayProvider = currentLink.gatewayProviderKey ?? null\n shouldEmitLockedEvent = !currentLink.isLocked\n const transaction = tx.create(CheckoutTransaction, {\n ...parsed,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n amount: toMoneyString(parsed.amount) ?? '0.00',\n status: 'processing',\n })\n tx.persist(transaction)\n await tx.flush()\n return transaction\n })\n if (shouldEmitLockedEvent && lockedLinkId && lockedLinkSlug) {\n await emitCheckoutEvent('checkout.link.locked', {\n id: lockedLinkId,\n slug: lockedLinkSlug,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n }\n await emitCheckoutEvent('checkout.transaction.created', {\n transactionId: transaction.id,\n linkId: transaction.linkId,\n status: transaction.status,\n amount: Number(transaction.amount),\n currency: transaction.currencyCode,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n await emitCheckoutEvent('checkout.transaction.customerDataCaptured', {\n transactionId: transaction.id,\n linkId: transaction.linkId,\n templateId: lockedLinkTemplateId,\n slug: lockedLinkSlug,\n status: transaction.status,\n paymentStatus: transaction.paymentStatus ?? null,\n amount: Number(transaction.amount),\n currency: transaction.currencyCode,\n gatewayProvider: lockedLinkGatewayProvider,\n gatewayTransactionId: transaction.gatewayTransactionId ?? null,\n occurredAt: new Date().toISOString(),\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n customerDataCaptured: true,\n }).catch(() => undefined)\n return { id: transaction.id }\n },\n}\n\nconst updateTransactionStatusCommand: CommandHandler<Record<string, unknown>, { ok: true }> = {\n id: 'checkout.transaction.updateStatus',\n async execute(rawInput, ctx) {\n const { parsed } = parseCheckoutInput(rawInput, transactionUpdateStatusSchema.parse)\n const scope = resolveTransactionScope(parsed)\n const em = ctx.container.resolve('em') as EntityManager\n let terminalEventPayload: CheckoutTerminalEventPayload | null = null\n let emitUsageLimitReached = false\n let usageLimitReachedLinkId: string | null = null\n let usageLimitReachedLinkSlug: string | null = null\n await em.transactional(async (tx) => {\n const transaction = await tx.findOne(CheckoutTransaction, {\n id: parsed.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n if (!transaction) throw new CrudHttpError(404, { error: 'Transaction not found' })\n const link = await tx.findOne(CheckoutLink, {\n id: transaction.linkId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!link) throw new CrudHttpError(404, { error: 'Payment link not found' })\n\n const previousStatus = transaction.status\n const nextStatus = parsed.status\n const previousTerminal = isTerminalCheckoutStatus(previousStatus)\n const nextTerminal = isTerminalCheckoutStatus(nextStatus)\n\n transaction.status = nextStatus\n transaction.paymentStatus = parsed.paymentStatus ?? transaction.paymentStatus ?? null\n transaction.gatewayTransactionId = parsed.gatewayTransactionId ?? transaction.gatewayTransactionId ?? null\n await tx.flush()\n\n if (!previousTerminal && nextTerminal) {\n const { usageLimitReached } = applyTerminalTransactionState(link, nextStatus)\n await tx.flush()\n if (usageLimitReached) {\n emitUsageLimitReached = true\n usageLimitReachedLinkId = link.id\n usageLimitReachedLinkSlug = link.slug\n }\n }\n if (nextTerminal) {\n terminalEventPayload = {\n transactionId: transaction.id,\n linkId: transaction.linkId,\n templateId: link.templateId ?? null,\n slug: link.slug,\n status: transaction.status,\n paymentStatus: transaction.paymentStatus ?? null,\n amount: Number(transaction.amount),\n currency: transaction.currencyCode,\n gatewayProvider: link.gatewayProviderKey ?? null,\n gatewayTransactionId: transaction.gatewayTransactionId ?? null,\n occurredAt: new Date().toISOString(),\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }\n }\n })\n if (parsed.status === 'completed') {\n await emitCheckoutEvent('checkout.transaction.completed', terminalEventPayload ?? {}).catch(() => undefined)\n } else if (parsed.status === 'failed') {\n await emitCheckoutEvent('checkout.transaction.failed', terminalEventPayload ?? {}).catch(() => undefined)\n } else if (parsed.status === 'cancelled') {\n await emitCheckoutEvent('checkout.transaction.cancelled', terminalEventPayload ?? {}).catch(() => undefined)\n } else if (parsed.status === 'expired') {\n await emitCheckoutEvent('checkout.transaction.expired', terminalEventPayload ?? {}).catch(() => undefined)\n }\n if (emitUsageLimitReached && usageLimitReachedLinkId && usageLimitReachedLinkSlug) {\n await emitCheckoutEvent('checkout.link.usageLimitReached', {\n id: usageLimitReachedLinkId,\n slug: usageLimitReachedLinkSlug,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n }\n return { ok: true }\n },\n}\n\nregisterCommand(createTransactionCommand)\nregisterCommand(updateTransactionStatusCommand)\n\nexport function mapGatewayStatusForCommand(status: string | null | undefined) {\n return mapGatewayStatusToCheckoutStatus(status)\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["transaction"]
7
7
  }