@aglyn/plugins-commerce 1.0.0-beta.289 → 1.0.0-beta.291

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 (140) hide show
  1. package/README.md +4 -2
  2. package/package.json +13 -13
  3. package/src/lib/components/commerce-console-page.js +2 -1
  4. package/src/lib/components/commerce-console-page.js.map +1 -1
  5. package/src/lib/components/console/commerce-pdf-download.d.ts +30 -0
  6. package/src/lib/components/console/commerce-pdf-download.js +53 -0
  7. package/src/lib/components/console/commerce-pdf-download.js.map +1 -0
  8. package/src/lib/components/console/host-orders-card.component.d.ts +6 -0
  9. package/src/lib/components/console/host-orders-card.component.js +3 -2
  10. package/src/lib/components/console/host-orders-card.component.js.map +1 -1
  11. package/src/lib/components/console/host-quotes-card.component.js +20 -4
  12. package/src/lib/components/console/host-quotes-card.component.js.map +1 -1
  13. package/src/lib/components/console/invoice-send.component.d.ts +44 -0
  14. package/src/lib/components/console/invoice-send.component.js +237 -0
  15. package/src/lib/components/console/invoice-send.component.js.map +1 -0
  16. package/src/lib/components/console/order-detail-dialog.component.d.ts +5 -0
  17. package/src/lib/components/console/order-detail-dialog.component.js +9 -2
  18. package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
  19. package/src/lib/components/console/order-invoice.component.d.ts +15 -4
  20. package/src/lib/components/console/order-invoice.component.js +93 -12
  21. package/src/lib/components/console/order-invoice.component.js.map +1 -1
  22. package/src/lib/components/console/quote-editor-dialog.component.d.ts +29 -0
  23. package/src/lib/components/console/quote-editor-dialog.component.js +154 -5
  24. package/src/lib/components/console/quote-editor-dialog.component.js.map +1 -1
  25. package/src/lib/components/console/quote-proofs.component.d.ts +48 -0
  26. package/src/lib/components/console/quote-proofs.component.js +694 -0
  27. package/src/lib/components/console/quote-proofs.component.js.map +1 -0
  28. package/src/lib/components/console/quote-send.component.d.ts +42 -0
  29. package/src/lib/components/console/quote-send.component.js +307 -0
  30. package/src/lib/components/console/quote-send.component.js.map +1 -0
  31. package/src/lib/components/console/quote-start.component.d.ts +45 -0
  32. package/src/lib/components/console/quote-start.component.js +182 -0
  33. package/src/lib/components/console/quote-start.component.js.map +1 -0
  34. package/src/lib/components/product-options-field-body.d.ts +44 -0
  35. package/src/lib/components/product-options-field-body.js +260 -0
  36. package/src/lib/components/product-options-field-body.js.map +1 -0
  37. package/src/lib/components/product-options-field.d.ts +32 -0
  38. package/src/lib/components/product-options-field.js +128 -0
  39. package/src/lib/components/product-options-field.js.map +1 -0
  40. package/src/lib/components/quote-page-body.js +67 -20
  41. package/src/lib/components/quote-page-body.js.map +1 -1
  42. package/src/lib/components/quote-proof-panel.d.ts +42 -0
  43. package/src/lib/components/quote-proof-panel.js +436 -0
  44. package/src/lib/components/quote-proof-panel.js.map +1 -0
  45. package/src/lib/model/commerce-invoices.d.ts +132 -0
  46. package/src/lib/model/commerce-invoices.js +332 -0
  47. package/src/lib/model/commerce-invoices.js.map +1 -0
  48. package/src/lib/model/commerce-orders.d.ts +29 -2
  49. package/src/lib/model/commerce-orders.js.map +1 -1
  50. package/src/lib/model/commerce-product-field.d.ts +23 -0
  51. package/src/lib/model/commerce-product-field.js +26 -0
  52. package/src/lib/model/commerce-product-field.js.map +1 -0
  53. package/src/lib/model/commerce-quote-email.d.ts +67 -0
  54. package/src/lib/model/commerce-quote-email.js +154 -0
  55. package/src/lib/model/commerce-quote-email.js.map +1 -0
  56. package/src/lib/model/commerce-quote-pay.d.ts +76 -6
  57. package/src/lib/model/commerce-quote-pay.js +105 -39
  58. package/src/lib/model/commerce-quote-pay.js.map +1 -1
  59. package/src/lib/model/commerce-quote-proofs.d.ts +159 -0
  60. package/src/lib/model/commerce-quote-proofs.js +348 -0
  61. package/src/lib/model/commerce-quote-proofs.js.map +1 -0
  62. package/src/lib/model/commerce-quote-request.d.ts +93 -0
  63. package/src/lib/model/commerce-quote-request.js +207 -0
  64. package/src/lib/model/commerce-quote-request.js.map +1 -0
  65. package/src/lib/model/commerce-quotes.d.ts +140 -3
  66. package/src/lib/model/commerce-quotes.js.map +1 -1
  67. package/src/lib/model/index.d.ts +4 -0
  68. package/src/lib/model/index.js +4 -0
  69. package/src/lib/model/index.js.map +1 -1
  70. package/src/lib/plugin.js +19 -0
  71. package/src/lib/plugin.js.map +1 -1
  72. package/src/lib/server/billing-webhook.js +115 -70
  73. package/src/lib/server/billing-webhook.js.map +1 -1
  74. package/src/lib/server/commerce-pdf.d.ts +104 -0
  75. package/src/lib/server/commerce-pdf.js +310 -0
  76. package/src/lib/server/commerce-pdf.js.map +1 -0
  77. package/src/lib/server/draft-order.js +23 -3
  78. package/src/lib/server/draft-order.js.map +1 -1
  79. package/src/lib/server/invoice-email.d.ts +76 -0
  80. package/src/lib/server/invoice-email.js +183 -0
  81. package/src/lib/server/invoice-email.js.map +1 -0
  82. package/src/lib/server/order-invoice-send.d.ts +43 -0
  83. package/src/lib/server/order-invoice-send.js +218 -0
  84. package/src/lib/server/order-invoice-send.js.map +1 -0
  85. package/src/lib/server/order-print.d.ts +6 -0
  86. package/src/lib/server/order-print.js +22 -5
  87. package/src/lib/server/order-print.js.map +1 -1
  88. package/src/lib/server/order-status.d.ts +11 -0
  89. package/src/lib/server/order-status.js +44 -8
  90. package/src/lib/server/order-status.js.map +1 -1
  91. package/src/lib/server/pdf-response.d.ts +31 -0
  92. package/src/lib/server/pdf-response.js +30 -0
  93. package/src/lib/server/pdf-response.js.map +1 -0
  94. package/src/lib/server/person-eraser.d.ts +3 -2
  95. package/src/lib/server/person-eraser.js +25 -6
  96. package/src/lib/server/person-eraser.js.map +1 -1
  97. package/src/lib/server/pos-reader-splash.d.ts +2 -18
  98. package/src/lib/server/pos-reader-splash.js +8 -93
  99. package/src/lib/server/pos-reader-splash.js.map +1 -1
  100. package/src/lib/server/quote-email.d.ts +85 -0
  101. package/src/lib/server/quote-email.js +211 -0
  102. package/src/lib/server/quote-email.js.map +1 -0
  103. package/src/lib/server/quote-link-token.d.ts +11 -0
  104. package/src/lib/server/quote-link-token.js +21 -0
  105. package/src/lib/server/quote-link-token.js.map +1 -1
  106. package/src/lib/server/quote-pay.d.ts +38 -6
  107. package/src/lib/server/quote-pay.js +115 -53
  108. package/src/lib/server/quote-pay.js.map +1 -1
  109. package/src/lib/server/quote-proofs.d.ts +51 -0
  110. package/src/lib/server/quote-proofs.js +500 -0
  111. package/src/lib/server/quote-proofs.js.map +1 -0
  112. package/src/lib/server/quote-uploads.d.ts +33 -0
  113. package/src/lib/server/quote-uploads.js +29 -0
  114. package/src/lib/server/quote-uploads.js.map +1 -0
  115. package/src/lib/server/quote.d.ts +25 -0
  116. package/src/lib/server/quote.js +638 -8
  117. package/src/lib/server/quote.js.map +1 -1
  118. package/src/lib/server/site-image-source.d.ts +38 -0
  119. package/src/lib/server/site-image-source.js +130 -0
  120. package/src/lib/server/site-image-source.js.map +1 -0
  121. package/src/lib/server/site-page-resolver.js +2 -1
  122. package/src/lib/server/site-page-resolver.js.map +1 -1
  123. package/src/lib/server.js +24 -1
  124. package/src/lib/server.js.map +1 -1
  125. package/src/lib/site.js +8 -0
  126. package/src/lib/site.js.map +1 -1
  127. package/src/lib/tenant-emails.js +243 -0
  128. package/src/lib/tenant-emails.js.map +1 -1
  129. package/src/lib/utils/commerce-document-pdf.d.ts +82 -0
  130. package/src/lib/utils/commerce-document-pdf.js +613 -0
  131. package/src/lib/utils/commerce-document-pdf.js.map +1 -0
  132. package/src/lib/utils/invoice-email-content.d.ts +45 -0
  133. package/src/lib/utils/invoice-email-content.js +126 -0
  134. package/src/lib/utils/invoice-email-content.js.map +1 -0
  135. package/src/lib/utils/order-invoice.d.ts +52 -3
  136. package/src/lib/utils/order-invoice.js +124 -64
  137. package/src/lib/utils/order-invoice.js.map +1 -1
  138. package/src/lib/utils/quote-email-content.d.ts +62 -0
  139. package/src/lib/utils/quote-email-content.js +154 -0
  140. package/src/lib/utils/quote-email-content.js.map +1 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/site-page-resolver.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { SitePageResolver } from '@aglyn/aglyn/server'\nimport { hostCollectionKind } from '@aglyn/aglyn/server'\nimport composeScreenNodes, {\n composeNodesWithChrome,\n} from '@aglyn/tenant-runtime/compose-screen-nodes'\nimport { resolveBuiltInPageLayoutId } from '@aglyn/tenant-runtime/built-in-page-layout'\nimport * as Aglyn from '@aglyn/aglyn/server'\nimport { ORDER_STATUS_PATH } from './order-status-token'\nimport { ORDER_STATUS_COMPONENT_ID } from '../constants/order-status'\nimport { RETURN_REQUEST_COMPONENT_ID, RETURN_REQUEST_PATH } from '../constants/return-request'\nimport { QUOTE_PAGE_COMPONENT_ID, QUOTE_PAGE_PATH } from '../constants/quote-page'\nimport getScreen from '@aglyn/tenant-runtime/get-screen'\nimport { collectSocialImageFacts } from '@aglyn/tenant-runtime/social-image-facts'\nimport { firebaseAdmin, getOrgForHost } from '@aglyn/tenant-data-admin'\nimport * as CommerceModel from '../model'\nimport { productAsksUseDateAnywhere, toPublicProductDetail } from './product'\nimport { readStoreDay } from './store-day'\nimport { readProductReviews } from './reviews'\n\n/**\n * Commerce page resolver (AGL-292/298/418), relocated verbatim from the\n * tenant loader: /products/{slug} renders the host's designated PDP\n * template with product tokens, /collections/{slug} the collection\n * template — both compose server-side and return complete page props.\n * Runs only for paths that didn't match a published screen; returns\n * undefined for everything else so the loader falls through.\n */\nexport const commerceSitePageResolver: SitePageResolver = async ({\n hostId,\n host,\n path,\n}) => {\n const hostRes = { host }\n // Product detail routes (AGL-292): /products/{slug} renders the\n // host's designated PDP template screen (settings/store\n // `pdpScreenId`, AGL-295) with product tokens; the product-detail\n // block hydrates variants client-side from the same slug. Same\n // mechanism as entry-template screens below.\n const pdpSegments = path.split('/').filter(Boolean)\n // The guest order-status page (AGL-3610), at /order-status — reached only\n // when the site has no page of its own there. The site's header and footer\n // around the order-status block, which reads the signed `?o=&t=` link after\n // hydration, so this page holds no order and is safe to cache. UNLISTED, so\n // the head says noindex: it is a private page, not a landing page.\n if (pdpSegments.length === 1 && pdpSegments[0] === ORDER_STATUS_PATH) {\n return composeOrderStatusPage(hostId, host)\n }\n // The buyer's return form (AGL-3611), at /order-return, under the same\n // terms: no page of the site's own there, the order read after hydration\n // from the link's `?o=&t=` (or the member's session), UNLISTED.\n if (pdpSegments.length === 1 && pdpSegments[0] === RETURN_REQUEST_PATH) {\n return composeReturnRequestPage(hostId, host)\n }\n // The customer's quote page (AGL-4094), at /pay-quote, under the same\n // terms: no page of the site's own there, the quote read after hydration\n // from the pay link's `?q=&t=`, UNLISTED.\n if (pdpSegments.length === 1 && pdpSegments[0] === QUOTE_PAGE_PATH) {\n return composeQuotePage(hostId, host)\n }\n if (pdpSegments.length === 2 && pdpSegments[0] === 'products') {\n const adminFirestore = firebaseAdmin.app().firestore()\n const hostDocRef = adminFirestore.collection('hosts').doc(hostId)\n const [storeSettings, productSnapshot] = await Promise.all([\n hostDocRef.collection('settings').doc('store').get(),\n hostDocRef\n .collection('products')\n .where('slug', '==', pdpSegments[1])\n .limit(1)\n .get(),\n ])\n const pdpScreenId = storeSettings.get('pdpScreenId')\n const productRaw = productSnapshot.docs[0]?.data() as any\n // Live, active and sold online (AGL-4060): a product sold in person only\n // has no page here, designed or built in, and falls through to the 404.\n const listedOnline = CommerceModel.productListedOnline(productRaw)\n if (pdpScreenId && listedOnline) {\n const product = CommerceModel.liftLegacyProduct(productRaw)\n const templateRes = await getScreen({\n hostId,\n screenId: pdpScreenId,\n // A PDP template renders against a routed PRODUCT, never at an address\n // of its own, so it is served here and 404s everywhere else (AGL-1400).\n allowTemplate: true,\n })\n if (templateRes.screen) {\n const [minPrice, maxPrice] = CommerceModel.productPriceRange(product)\n // Best-effort: a reviews read that fails costs the page its rating\n // snippet, not the page.\n const productReviews = await readProductReviews(\n hostId,\n productSnapshot.docs[0].id,\n ).catch((error) => {\n console.error('product review aggregate failed', error)\n return { reviews: [], aggregate: { count: 0, average: 0 } }\n })\n // The head shares this page as the template's image, then the site\n // default, so their documents are read in the template's own batch\n // (AGL-2850).\n const card = collectSocialImageFacts([\n (templateRes.screen as any).seo?.image,\n hostRes.host?.seo?.image,\n ])\n const templateNodes = await composeScreenNodes({\n hostId,\n screenId: pdpScreenId,\n screen: templateRes.screen,\n socialImages: card.socialImages,\n // The template's host variables, and its layout's, fill in from\n // this site as they do on every other page (AGL-2883).\n host: hostRes.host,\n tokens: {\n 'product.name': product.name,\n 'product.description': product.description ?? '',\n 'product.price': productPriceText(product, minPrice, maxPrice),\n 'product.image':\n product.mediaUrls?.[0] ?? product.imageUrl ?? '',\n 'product.slug': product.slug,\n },\n // Named as the product template it is if the page review holds it\n // (AGL-3374); without it the route has no page.\n page: {\n template: {\n role: 'entry',\n route: '/products/:slug',\n collectionName: 'Products',\n entryPath: `/products/${product.slug}`,\n fallback: 'not-found',\n },\n },\n })\n if (templateNodes) {\n return {\n props: JSON.parse(\n JSON.stringify({\n // The PDP block used to fetch this in an effect, so the\n // server rendered a skeleton and crawlers saw a product page\n // with no product in it (AGL-659). The product is already\n // loaded here — hand it down so it renders server-side.\n pageData: {\n commerce: {\n product: toPublicProductDetail(\n productSnapshot.docs[0].id,\n product,\n // The store's calendar, for a pass that asks for a day.\n { timeZone: await passDayTimeZone(hostId, hostRes.host, product) },\n ),\n // Rating aggregate (AGL-686): needed HERE because\n // `aggregateRating` belongs nested inside the Product\n // structured data, and that is emitted server-side.\n // The reviews block used to publish a free-standing\n // AggregateRating node, which schema.org ignores.\n ...(productReviews.aggregate.count\n ? { reviews: productReviews }\n : {}),\n },\n },\n data: {\n host: hostRes.host,\n screen: {\n data: {\n ...templateRes.screen,\n // The product NAMES this page; the template's own name\n // (\"Product detail\") describes none of the products it\n // renders. Kept distinct from the SEO title because the\n // head treats an authored title as verbatim and a name\n // as the side the site title joins (AGL-1341) — so a\n // product with its own SEO title gets exactly that, and\n // one without gets \"Blue Widget – Acme Store\".\n displayName: product.name,\n seo: {\n ...((templateRes.screen as any).seo ?? {}),\n // Only when the PRODUCT authored one: inheriting the\n // template screen's title would give every product\n // page in the store the same `<title>`.\n title: product.seo?.title ?? undefined,\n description:\n product.seo?.description ??\n product.description ??\n undefined,\n },\n },\n },\n },\n nodes: templateNodes,\n ...card.collected(),\n }),\n ),\n revalidate: 60,\n }\n }\n }\n }\n // No product template designated, or none that renders: the store's\n // built-in product page (AGL-3676), in the site's own header and footer,\n // rather than a 404 behind every card the product grid links. A store a\n // guided start built has no template of its own, and its grid links each\n // product here.\n if (listedOnline) {\n return composeBuiltInProductPage(\n hostId,\n host,\n productSnapshot.docs[0].id,\n CommerceModel.liftLegacyProduct(productRaw),\n storeSettings.get('returns'),\n )\n }\n }\n // Commerce collection routes (AGL-298): /collections/{slug} renders\n // the designated collection template with collection tokens; the\n // product-grid block derives the same slug from the URL.\n if (pdpSegments.length === 2 && pdpSegments[0] === 'collections') {\n const adminFirestore = firebaseAdmin.app().firestore()\n const hostDocRef = adminFirestore.collection('hosts').doc(hostId)\n const [storeSettings, collectionSnapshot] = await Promise.all([\n hostDocRef.collection('settings').doc('store').get(),\n hostDocRef\n .collection('collections')\n .where('slug', '==', pdpSegments[1])\n .limit(5)\n .get(),\n ])\n const collectionScreenId = storeSettings.get('collectionScreenId')\n // Content collections share this path and a slug is only unique within a\n // kind (AGL-954), so take the first CATALOG match rather than the first\n // doc — otherwise a blog with the same slug renders as a product page.\n const shopCollection = collectionSnapshot.docs\n .find((docSnapshot) => hostCollectionKind(docSnapshot.data()) === 'catalog')\n ?.data() as CommerceModel.HostCollection | undefined\n if (collectionScreenId && shopCollection) {\n const templateRes = await getScreen({\n hostId,\n screenId: collectionScreenId,\n allowTemplate: true,\n })\n if (templateRes.screen) {\n // As on the PDP above: the template's image, then the site default\n // (AGL-2850).\n const card = collectSocialImageFacts([\n (templateRes.screen as any).seo?.image,\n hostRes.host?.seo?.image,\n ])\n const templateNodes = await composeScreenNodes({\n hostId,\n screenId: collectionScreenId,\n screen: templateRes.screen,\n socialImages: card.socialImages,\n // As on the PDP above (AGL-2883).\n host: hostRes.host,\n tokens: {\n 'collection.name': shopCollection.name,\n 'collection.description': shopCollection.description ?? '',\n 'collection.image': shopCollection.imageUrl ?? '',\n 'collection.slug': shopCollection.slug,\n },\n // As on the PDP above (AGL-3374).\n page: {\n template: {\n role: 'entry',\n route: '/collections/:slug',\n collectionName: 'Store collections',\n entryPath: `/collections/${shopCollection.slug}`,\n fallback: 'not-found',\n },\n },\n })\n if (templateNodes) {\n return {\n props: JSON.parse(\n JSON.stringify({\n data: {\n host: hostRes.host,\n screen: {\n data: {\n ...templateRes.screen,\n // As on the PDP above: the catalog collection names the\n // page, and a name takes the site title after it while\n // an authored SEO title would not (AGL-1341). A shop\n // collection has no SEO title field of its own, so the\n // template's must not stand in for one.\n displayName: shopCollection.name,\n seo: {\n ...((templateRes.screen as any).seo ?? {}),\n title: undefined,\n description:\n shopCollection.description ?? undefined,\n },\n },\n },\n },\n nodes: templateNodes,\n ...card.collected(),\n }),\n ),\n revalidate: 60,\n }\n }\n }\n }\n }\n return undefined\n}\n\n/**\n * What `{{product.price}}` says: the price, \"From\" the lowest where variants\n * differ, or \"Price coming soon\" for a product listed before any variant has\n * one (AGL-3676) — never \"$0\".\n */\nexport function productPriceText(\n product: Pick<CommerceModel.HostProduct, 'variants'>,\n minPrice: number,\n maxPrice: number,\n): string {\n if (!(product.variants ?? []).some((variant) => CommerceModel.variantHasPrice(variant))) {\n return 'Price coming soon'\n }\n return minPrice === maxPrice ? `$${minPrice}` : `From $${minPrice}`\n}\n\nconst PRODUCT_PAGE_NODE = 'pdp__detail'\nconst PRODUCT_PAGE_REVIEWS_NODE = 'pdp__reviews'\nconst PRODUCT_PAGE_RELATED_NODE = 'pdp__related'\n\n/**\n * The store's built-in product page (AGL-3676), root first, for the layout's\n * slot: the product block for the routed slug — with its Details and\n * Shipping & returns folds under the description, as a designer theme's\n * product page has them — then the product's reviews where the store's plan\n * collects them, then the related products as a grid of photo cards.\n */\nexport function buildProductPageNodes(\n slug: string,\n options: { reviews?: boolean } = {},\n): Record<string, Aglyn.AglynNodeSchema> {\n const reviews = Boolean(options.reviews)\n return {\n [Aglyn.NODE_ROOT_ID]: {\n $id: Aglyn.NODE_ROOT_ID,\n componentId: 'div',\n nodes: ['pdp__container'],\n } as Aglyn.AglynNodeSchema,\n pdp__container: {\n $id: 'pdp__container',\n parentId: Aglyn.NODE_ROOT_ID,\n componentId: 'muiContainer',\n pluginId: 'mui',\n props: { maxWidth: 'lg', sx: { paddingTop: 6, paddingBottom: 10 } },\n nodes: [\n PRODUCT_PAGE_NODE,\n ...(reviews ? [PRODUCT_PAGE_REVIEWS_NODE] : []),\n PRODUCT_PAGE_RELATED_NODE,\n ],\n } as Aglyn.AglynNodeSchema,\n [PRODUCT_PAGE_NODE]: {\n $id: PRODUCT_PAGE_NODE,\n parentId: 'pdp__container',\n componentId: 'product-detail',\n pluginId: 'commerce',\n props: { slug, showDetails: true, showShipping: true },\n } as Aglyn.AglynNodeSchema,\n ...(reviews\n ? {\n [PRODUCT_PAGE_REVIEWS_NODE]: {\n $id: PRODUCT_PAGE_REVIEWS_NODE,\n parentId: 'pdp__container',\n componentId: 'product-reviews',\n pluginId: 'commerce',\n props: { heading: 'Reviews', sx: { marginTop: 8 } },\n } as Aglyn.AglynNodeSchema,\n }\n : {}),\n [PRODUCT_PAGE_RELATED_NODE]: {\n $id: PRODUCT_PAGE_RELATED_NODE,\n parentId: 'pdp__container',\n componentId: 'related-products',\n pluginId: 'commerce',\n props: {\n heading: 'You may also like',\n maxItems: 4,\n layout: 'grid',\n sx: { marginTop: 8 },\n },\n } as Aglyn.AglynNodeSchema,\n }\n}\n\n/**\n * The store's return window for this product, when the store takes returns of\n * its kind: the settings the return form enforces (`readReturnSettings`), so\n * the page never states a policy the store does not keep.\n */\nexport function productReturnWindow(\n product: Pick<CommerceModel.HostProduct, 'type'>,\n rawReturns: unknown,\n): { windowDays: number } | undefined {\n const settings = CommerceModel.readReturnSettings(rawReturns)\n if (!settings.enabled || settings.windowDays <= 0) return undefined\n if (!settings.eligibleTypes.includes(product.type ?? 'physical')) return undefined\n return { windowDays: settings.windowDays }\n}\n\n/** Whether the store's plan collects reviews; a failed read leaves them off. */\nasync function storeTakesReviews(hostId: string): Promise<boolean> {\n try {\n const org = await getOrgForHost(hostId)\n return Aglyn.checkEntitlement(org?.org as never, 'productReviews')\n } catch (error) {\n console.error('reviews entitlement read failed', error)\n return false\n }\n}\n\nasync function composeBuiltInProductPage(\n hostId: string,\n host: unknown,\n productId: string,\n product: ReturnType<typeof CommerceModel.liftLegacyProduct>,\n rawReturns?: unknown,\n) {\n try {\n const [layoutId, productReviews, reviewsOn] = await Promise.all([\n resolveBuiltInPageLayoutId({ hostId, host: host as never }),\n readProductReviews(hostId, productId).catch((error) => {\n console.error('product review aggregate failed', error)\n return { reviews: [], aggregate: { count: 0, average: 0 } }\n }),\n storeTakesReviews(hostId),\n ])\n const returns = productReturnWindow(product, rawReturns)\n const card = collectSocialImageFacts([\n product.mediaUrls?.[0] ?? product.imageUrl,\n (host as { seo?: { image?: string } } | null)?.seo?.image,\n ])\n const nodes = await composeNodesWithChrome({\n hostId,\n layoutId,\n screenNodes: buildProductPageNodes(product.slug, { reviews: reviewsOn }),\n socialImages: card.socialImages,\n host: host as Aglyn.HostTokenSource,\n })\n if (!nodes) return undefined\n return {\n props: JSON.parse(\n JSON.stringify({\n // Seeded, so the product renders server-side and the head writes\n // its Product structured data, as on a template page (AGL-659).\n pageData: {\n commerce: {\n product: toPublicProductDetail(productId, product, {\n timeZone: await passDayTimeZone(hostId, host, product),\n }),\n ...(productReviews.aggregate.count ? { reviews: productReviews } : {}),\n // The Shipping & returns fold's return line, only when the\n // store takes returns of this product's kind.\n ...(returns ? { returns } : {}),\n },\n },\n data: {\n host,\n screen: {\n data: {\n displayName: product.name,\n seo: {\n title: product.seo?.title ?? undefined,\n description: product.seo?.description ?? product.description ?? undefined,\n },\n },\n },\n },\n nodes,\n ...card.collected(),\n }),\n ),\n revalidate: 60,\n }\n } catch (error) {\n console.error('built-in product page composition failed', error)\n return undefined\n }\n}\n\nconst ORDER_STATUS_NODE = 'order-status__block'\n\n/** The order-status page's node tree, root first, for the layout's slot. */\nexport function buildOrderStatusNodes(): Record<string, Aglyn.AglynNodeSchema> {\n return {\n [Aglyn.NODE_ROOT_ID]: {\n $id: Aglyn.NODE_ROOT_ID,\n componentId: 'div',\n nodes: ['order-status__container'],\n } as Aglyn.AglynNodeSchema,\n 'order-status__container': {\n $id: 'order-status__container',\n parentId: Aglyn.NODE_ROOT_ID,\n componentId: 'muiContainer',\n pluginId: 'mui',\n props: { maxWidth: 'md', sx: { paddingTop: 6, paddingBottom: 8 } },\n nodes: [ORDER_STATUS_NODE],\n } as Aglyn.AglynNodeSchema,\n [ORDER_STATUS_NODE]: {\n $id: ORDER_STATUS_NODE,\n parentId: 'order-status__container',\n componentId: ORDER_STATUS_COMPONENT_ID,\n pluginId: 'commerce',\n props: {},\n } as Aglyn.AglynNodeSchema,\n }\n}\n\nasync function composeOrderStatusPage(hostId: string, host: unknown) {\n try {\n const layoutId = await resolveBuiltInPageLayoutId({ hostId, host: host as never })\n const nodes = await composeNodesWithChrome({\n hostId,\n layoutId,\n screenNodes: buildOrderStatusNodes(),\n host: host as Aglyn.HostTokenSource,\n })\n if (!nodes) return undefined\n return {\n props: JSON.parse(\n JSON.stringify({\n data: {\n host,\n screen: {\n data: {\n displayName: 'Order status',\n visibility: Aglyn.HostScreenVisibility.UNLISTED,\n },\n },\n },\n nodes,\n }),\n ),\n revalidate: 3600,\n }\n } catch (error) {\n console.error('order status page composition failed', error)\n return undefined\n }\n}\n\nconst RETURN_REQUEST_NODE = 'ret__block'\n\n/** The return form's node tree, root first, for the layout's slot. */\nexport function buildReturnRequestNodes(): Record<string, Aglyn.AglynNodeSchema> {\n return {\n [Aglyn.NODE_ROOT_ID]: {\n $id: Aglyn.NODE_ROOT_ID,\n componentId: 'div',\n nodes: ['ret__container'],\n } as Aglyn.AglynNodeSchema,\n ret__container: {\n $id: 'ret__container',\n parentId: Aglyn.NODE_ROOT_ID,\n componentId: 'muiContainer',\n pluginId: 'mui',\n props: { maxWidth: 'md', sx: { paddingTop: 6, paddingBottom: 8 } },\n nodes: [RETURN_REQUEST_NODE],\n } as Aglyn.AglynNodeSchema,\n [RETURN_REQUEST_NODE]: {\n $id: RETURN_REQUEST_NODE,\n parentId: 'ret__container',\n componentId: RETURN_REQUEST_COMPONENT_ID,\n pluginId: 'commerce',\n props: {},\n } as Aglyn.AglynNodeSchema,\n }\n}\n\nasync function composeReturnRequestPage(hostId: string, host: unknown) {\n try {\n const layoutId = await resolveBuiltInPageLayoutId({ hostId, host: host as never })\n const nodes = await composeNodesWithChrome({\n hostId,\n layoutId,\n screenNodes: buildReturnRequestNodes(),\n host: host as Aglyn.HostTokenSource,\n })\n if (!nodes) return undefined\n return {\n props: JSON.parse(\n JSON.stringify({\n data: {\n host,\n screen: {\n data: {\n displayName: 'Request a return',\n visibility: Aglyn.HostScreenVisibility.UNLISTED,\n },\n },\n },\n nodes,\n }),\n ),\n revalidate: 3600,\n }\n } catch (error) {\n console.error('return request page composition failed', error)\n return undefined\n }\n}\n\nconst QUOTE_PAGE_NODE = 'quote-page__block'\n\n/** The quote page's node tree, root first, for the layout's slot. */\nexport function buildQuotePageNodes(): Record<string, Aglyn.AglynNodeSchema> {\n return {\n [Aglyn.NODE_ROOT_ID]: {\n $id: Aglyn.NODE_ROOT_ID,\n componentId: 'div',\n nodes: ['quote-page__container'],\n } as Aglyn.AglynNodeSchema,\n 'quote-page__container': {\n $id: 'quote-page__container',\n parentId: Aglyn.NODE_ROOT_ID,\n componentId: 'muiContainer',\n pluginId: 'mui',\n props: { maxWidth: 'md', sx: { paddingTop: 6, paddingBottom: 8 } },\n nodes: [QUOTE_PAGE_NODE],\n } as Aglyn.AglynNodeSchema,\n [QUOTE_PAGE_NODE]: {\n $id: QUOTE_PAGE_NODE,\n parentId: 'quote-page__container',\n componentId: QUOTE_PAGE_COMPONENT_ID,\n pluginId: 'commerce',\n props: {},\n } as Aglyn.AglynNodeSchema,\n }\n}\n\nasync function composeQuotePage(hostId: string, host: unknown) {\n try {\n const layoutId = await resolveBuiltInPageLayoutId({ hostId, host: host as never })\n const nodes = await composeNodesWithChrome({\n hostId,\n layoutId,\n screenNodes: buildQuotePageNodes(),\n host: host as Aglyn.HostTokenSource,\n })\n if (!nodes) return undefined\n return {\n props: JSON.parse(\n JSON.stringify({\n data: {\n host,\n screen: {\n data: {\n displayName: 'Your quote',\n visibility: Aglyn.HostScreenVisibility.UNLISTED,\n },\n },\n },\n nodes,\n }),\n ),\n revalidate: 3600,\n }\n } catch (error) {\n console.error('quote page composition failed', error)\n return undefined\n }\n}\n\n/**\n * The store's time zone for a product page whose product asks for a use day\n * (AGL-4043), so the seeded page offers the same days the API's does; null\n * otherwise, without a read.\n */\nasync function passDayTimeZone(\n hostId: string,\n host: unknown,\n product: ReturnType<typeof CommerceModel.liftLegacyProduct>,\n): Promise<string | null> {\n if (!productAsksUseDateAnywhere(product)) return null\n const hostRef = firebaseAdmin.app().firestore().collection('hosts').doc(hostId)\n return (await readStoreDay(hostRef, { host: (host ?? null) as Record<string, unknown> | null })).timeZone\n}\n"],"names":["hostCollectionKind","composeScreenNodes","composeNodesWithChrome","resolveBuiltInPageLayoutId","Aglyn","ORDER_STATUS_PATH","ORDER_STATUS_COMPONENT_ID","RETURN_REQUEST_COMPONENT_ID","RETURN_REQUEST_PATH","QUOTE_PAGE_COMPONENT_ID","QUOTE_PAGE_PATH","getScreen","collectSocialImageFacts","firebaseAdmin","getOrgForHost","CommerceModel","productAsksUseDateAnywhere","toPublicProductDetail","readStoreDay","readProductReviews","commerceSitePageResolver","hostId","host","path","hostRes","pdpSegments","split","filter","Boolean","length","composeOrderStatusPage","composeReturnRequestPage","composeQuotePage","productSnapshot","adminFirestore","app","firestore","hostDocRef","collection","doc","storeSettings","Promise","all","get","where","limit","pdpScreenId","productRaw","docs","data","listedOnline","productListedOnline","product","liftLegacyProduct","templateRes","screenId","allowTemplate","screen","minPrice","maxPrice","productPriceRange","productReviews","id","catch","error","console","reviews","aggregate","count","average","card","seo","image","templateNodes","socialImages","tokens","name","description","productPriceText","mediaUrls","imageUrl","slug","page","template","role","route","collectionName","entryPath","fallback","props","JSON","parse","stringify","pageData","commerce","timeZone","passDayTimeZone","displayName","title","undefined","nodes","collected","revalidate","composeBuiltInProductPage","collectionSnapshot","collectionScreenId","shopCollection","find","docSnapshot","variants","some","variant","variantHasPrice","PRODUCT_PAGE_NODE","PRODUCT_PAGE_REVIEWS_NODE","PRODUCT_PAGE_RELATED_NODE","buildProductPageNodes","options","NODE_ROOT_ID","$id","componentId","pdp__container","parentId","pluginId","maxWidth","sx","paddingTop","paddingBottom","showDetails","showShipping","heading","marginTop","maxItems","layout","productReturnWindow","rawReturns","settings","readReturnSettings","enabled","windowDays","eligibleTypes","includes","type","storeTakesReviews","org","checkEntitlement","productId","layoutId","reviewsOn","returns","screenNodes","ORDER_STATUS_NODE","buildOrderStatusNodes","visibility","HostScreenVisibility","UNLISTED","RETURN_REQUEST_NODE","buildReturnRequestNodes","ret__container","QUOTE_PAGE_NODE","buildQuotePageNodes","hostRef"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/site-page-resolver.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { SitePageResolver } from '@aglyn/aglyn/server'\nimport { hostCollectionKind } from '@aglyn/aglyn/server'\nimport composeScreenNodes, {\n composeNodesWithChrome,\n} from '@aglyn/tenant-runtime/compose-screen-nodes'\nimport { resolveBuiltInPageLayoutId } from '@aglyn/tenant-runtime/built-in-page-layout'\nimport * as Aglyn from '@aglyn/aglyn/server'\nimport { ORDER_STATUS_PATH } from './order-status-token'\nimport { ORDER_STATUS_COMPONENT_ID } from '../constants/order-status'\nimport { RETURN_REQUEST_COMPONENT_ID, RETURN_REQUEST_PATH } from '../constants/return-request'\nimport { QUOTE_PAGE_COMPONENT_ID, QUOTE_PAGE_PATH } from '../constants/quote-page'\nimport getScreen from '@aglyn/tenant-runtime/get-screen'\nimport { collectSocialImageFacts } from '@aglyn/tenant-runtime/social-image-facts'\nimport { firebaseAdmin, getOrgForHost } from '@aglyn/tenant-data-admin'\nimport * as CommerceModel from '../model'\nimport { productAsksUseDateAnywhere, toPublicProductDetail } from './product'\nimport { readStoreDay } from './store-day'\nimport { readProductReviews } from './reviews'\n\n/**\n * Commerce page resolver (AGL-292/298/418), relocated verbatim from the\n * tenant loader: /products/{slug} renders the host's designated PDP\n * template with product tokens, /collections/{slug} the collection\n * template — both compose server-side and return complete page props.\n * Runs only for paths that didn't match a published screen; returns\n * undefined for everything else so the loader falls through.\n */\nexport const commerceSitePageResolver: SitePageResolver = async ({\n hostId,\n host,\n path,\n}) => {\n const hostRes = { host }\n // Product detail routes (AGL-292): /products/{slug} renders the\n // host's designated PDP template screen (settings/store\n // `pdpScreenId`, AGL-295) with product tokens; the product-detail\n // block hydrates variants client-side from the same slug. Same\n // mechanism as entry-template screens below.\n const pdpSegments = path.split('/').filter(Boolean)\n // The guest order-status page (AGL-3610), at /order-status — reached only\n // when the site has no page of its own there. The site's header and footer\n // around the order-status block, which reads the signed `?o=&t=` link after\n // hydration, so this page holds no order and is safe to cache. UNLISTED, so\n // the head says noindex: it is a private page, not a landing page.\n if (pdpSegments.length === 1 && pdpSegments[0] === ORDER_STATUS_PATH) {\n return composeOrderStatusPage(hostId, host)\n }\n // The buyer's return form (AGL-3611), at /order-return, under the same\n // terms: no page of the site's own there, the order read after hydration\n // from the link's `?o=&t=` (or the member's session), UNLISTED.\n if (pdpSegments.length === 1 && pdpSegments[0] === RETURN_REQUEST_PATH) {\n return composeReturnRequestPage(hostId, host)\n }\n // The customer's quote page (AGL-4094), at /pay-quote, under the same\n // terms: no page of the site's own there, the quote read after hydration\n // from the pay link's `?q=&t=`, UNLISTED.\n if (pdpSegments.length === 1 && pdpSegments[0] === QUOTE_PAGE_PATH) {\n return composeQuotePage(hostId, host)\n }\n if (pdpSegments.length === 2 && pdpSegments[0] === 'products') {\n const adminFirestore = firebaseAdmin.app().firestore()\n const hostDocRef = adminFirestore.collection('hosts').doc(hostId)\n const [storeSettings, productSnapshot] = await Promise.all([\n hostDocRef.collection('settings').doc('store').get(),\n hostDocRef\n .collection('products')\n .where('slug', '==', pdpSegments[1])\n .limit(1)\n .get(),\n ])\n const pdpScreenId = storeSettings.get('pdpScreenId')\n const productRaw = productSnapshot.docs[0]?.data() as any\n // Live, active and sold online (AGL-4060): a product sold in person only\n // has no page here, designed or built in, and falls through to the 404.\n const listedOnline = CommerceModel.productListedOnline(productRaw)\n if (pdpScreenId && listedOnline) {\n const product = CommerceModel.liftLegacyProduct(productRaw)\n const templateRes = await getScreen({\n hostId,\n screenId: pdpScreenId,\n // A PDP template renders against a routed PRODUCT, never at an address\n // of its own, so it is served here and 404s everywhere else (AGL-1400).\n allowTemplate: true,\n })\n if (templateRes.screen) {\n const [minPrice, maxPrice] = CommerceModel.productPriceRange(product)\n // Best-effort: a reviews read that fails costs the page its rating\n // snippet, not the page.\n const productReviews = await readProductReviews(\n hostId,\n productSnapshot.docs[0].id,\n ).catch((error) => {\n console.error('product review aggregate failed', error)\n return { reviews: [], aggregate: { count: 0, average: 0 } }\n })\n // The head shares this page as the template's image, then the site\n // default, so their documents are read in the template's own batch\n // (AGL-2850).\n const card = collectSocialImageFacts([\n (templateRes.screen as any).seo?.image,\n hostRes.host?.seo?.image,\n ])\n const templateNodes = await composeScreenNodes({\n hostId,\n screenId: pdpScreenId,\n screen: templateRes.screen,\n socialImages: card.socialImages,\n // The template's host variables, and its layout's, fill in from\n // this site as they do on every other page (AGL-2883).\n host: hostRes.host,\n tokens: {\n 'product.name': product.name,\n 'product.description': product.description ?? '',\n 'product.price': productPriceText(product, minPrice, maxPrice),\n 'product.image':\n product.mediaUrls?.[0] ?? product.imageUrl ?? '',\n 'product.slug': product.slug,\n },\n // Named as the product template it is if the page review holds it\n // (AGL-3374); without it the route has no page.\n page: {\n template: {\n role: 'entry',\n route: '/products/:slug',\n collectionName: 'Products',\n entryPath: `/products/${product.slug}`,\n fallback: 'not-found',\n },\n },\n })\n if (templateNodes) {\n return {\n props: JSON.parse(\n JSON.stringify({\n // The PDP block used to fetch this in an effect, so the\n // server rendered a skeleton and crawlers saw a product page\n // with no product in it (AGL-659). The product is already\n // loaded here — hand it down so it renders server-side.\n pageData: {\n commerce: {\n product: toPublicProductDetail(\n productSnapshot.docs[0].id,\n product,\n // The store's calendar, for a pass that asks for a day.\n { timeZone: await passDayTimeZone(hostId, hostRes.host, product) },\n ),\n // Rating aggregate (AGL-686): needed HERE because\n // `aggregateRating` belongs nested inside the Product\n // structured data, and that is emitted server-side.\n // The reviews block used to publish a free-standing\n // AggregateRating node, which schema.org ignores.\n ...(productReviews.aggregate.count\n ? { reviews: productReviews }\n : {}),\n },\n },\n data: {\n host: hostRes.host,\n screen: {\n data: {\n ...templateRes.screen,\n // The product NAMES this page; the template's own name\n // (\"Product detail\") describes none of the products it\n // renders. Kept distinct from the SEO title because the\n // head treats an authored title as verbatim and a name\n // as the side the site title joins (AGL-1341) — so a\n // product with its own SEO title gets exactly that, and\n // one without gets \"Blue Widget – Acme Store\".\n displayName: product.name,\n seo: {\n ...((templateRes.screen as any).seo ?? {}),\n // Only when the PRODUCT authored one: inheriting the\n // template screen's title would give every product\n // page in the store the same `<title>`.\n title: product.seo?.title ?? undefined,\n description:\n product.seo?.description ??\n product.description ??\n undefined,\n },\n },\n },\n },\n nodes: templateNodes,\n ...card.collected(),\n }),\n ),\n revalidate: 60,\n }\n }\n }\n }\n // No product template designated, or none that renders: the store's\n // built-in product page (AGL-3676), in the site's own header and footer,\n // rather than a 404 behind every card the product grid links. A store a\n // guided start built has no template of its own, and its grid links each\n // product here.\n if (listedOnline) {\n return composeBuiltInProductPage(\n hostId,\n host,\n productSnapshot.docs[0].id,\n CommerceModel.liftLegacyProduct(productRaw),\n storeSettings.get('returns'),\n )\n }\n }\n // Commerce collection routes (AGL-298): /collections/{slug} renders\n // the designated collection template with collection tokens; the\n // product-grid block derives the same slug from the URL.\n if (pdpSegments.length === 2 && pdpSegments[0] === 'collections') {\n const adminFirestore = firebaseAdmin.app().firestore()\n const hostDocRef = adminFirestore.collection('hosts').doc(hostId)\n const [storeSettings, collectionSnapshot] = await Promise.all([\n hostDocRef.collection('settings').doc('store').get(),\n hostDocRef\n .collection('collections')\n .where('slug', '==', pdpSegments[1])\n .limit(5)\n .get(),\n ])\n const collectionScreenId = storeSettings.get('collectionScreenId')\n // Content collections share this path and a slug is only unique within a\n // kind (AGL-954), so take the first CATALOG match rather than the first\n // doc — otherwise a blog with the same slug renders as a product page.\n const shopCollection = collectionSnapshot.docs\n .find((docSnapshot) => hostCollectionKind(docSnapshot.data()) === 'catalog')\n ?.data() as CommerceModel.HostCollection | undefined\n if (collectionScreenId && shopCollection) {\n const templateRes = await getScreen({\n hostId,\n screenId: collectionScreenId,\n allowTemplate: true,\n })\n if (templateRes.screen) {\n // As on the PDP above: the template's image, then the site default\n // (AGL-2850).\n const card = collectSocialImageFacts([\n (templateRes.screen as any).seo?.image,\n hostRes.host?.seo?.image,\n ])\n const templateNodes = await composeScreenNodes({\n hostId,\n screenId: collectionScreenId,\n screen: templateRes.screen,\n socialImages: card.socialImages,\n // As on the PDP above (AGL-2883).\n host: hostRes.host,\n tokens: {\n 'collection.name': shopCollection.name,\n 'collection.description': shopCollection.description ?? '',\n 'collection.image': shopCollection.imageUrl ?? '',\n 'collection.slug': shopCollection.slug,\n },\n // As on the PDP above (AGL-3374).\n page: {\n template: {\n role: 'entry',\n route: '/collections/:slug',\n collectionName: 'Store collections',\n entryPath: `/collections/${shopCollection.slug}`,\n fallback: 'not-found',\n },\n },\n })\n if (templateNodes) {\n return {\n props: JSON.parse(\n JSON.stringify({\n data: {\n host: hostRes.host,\n screen: {\n data: {\n ...templateRes.screen,\n // As on the PDP above: the catalog collection names the\n // page, and a name takes the site title after it while\n // an authored SEO title would not (AGL-1341). A shop\n // collection has no SEO title field of its own, so the\n // template's must not stand in for one.\n displayName: shopCollection.name,\n seo: {\n ...((templateRes.screen as any).seo ?? {}),\n title: undefined,\n description:\n shopCollection.description ?? undefined,\n },\n },\n },\n },\n nodes: templateNodes,\n ...card.collected(),\n }),\n ),\n revalidate: 60,\n }\n }\n }\n }\n }\n return undefined\n}\n\n/**\n * What `{{product.price}}` says: the price, \"From\" the lowest where variants\n * differ, or \"Price coming soon\" for a product listed before any variant has\n * one (AGL-3676) — never \"$0\".\n */\nexport function productPriceText(\n product: Pick<CommerceModel.HostProduct, 'variants'>,\n minPrice: number,\n maxPrice: number,\n): string {\n if (!(product.variants ?? []).some((variant) => CommerceModel.variantHasPrice(variant))) {\n return 'Price coming soon'\n }\n return minPrice === maxPrice ? `$${minPrice}` : `From $${minPrice}`\n}\n\nconst PRODUCT_PAGE_NODE = 'pdp__detail'\nconst PRODUCT_PAGE_REVIEWS_NODE = 'pdp__reviews'\nconst PRODUCT_PAGE_RELATED_NODE = 'pdp__related'\n\n/**\n * The store's built-in product page (AGL-3676), root first, for the layout's\n * slot: the product block for the routed slug — with its Details and\n * Shipping & returns folds under the description, as a designer theme's\n * product page has them — then the product's reviews where the store's plan\n * collects them, then the related products as a grid of photo cards.\n */\nexport function buildProductPageNodes(\n slug: string,\n options: { reviews?: boolean } = {},\n): Record<string, Aglyn.AglynNodeSchema> {\n const reviews = Boolean(options.reviews)\n return {\n [Aglyn.NODE_ROOT_ID]: {\n $id: Aglyn.NODE_ROOT_ID,\n componentId: 'div',\n nodes: ['pdp__container'],\n } as Aglyn.AglynNodeSchema,\n pdp__container: {\n $id: 'pdp__container',\n parentId: Aglyn.NODE_ROOT_ID,\n componentId: 'muiContainer',\n pluginId: 'mui',\n props: { maxWidth: 'lg', sx: { paddingTop: 6, paddingBottom: 10 } },\n nodes: [\n PRODUCT_PAGE_NODE,\n ...(reviews ? [PRODUCT_PAGE_REVIEWS_NODE] : []),\n PRODUCT_PAGE_RELATED_NODE,\n ],\n } as Aglyn.AglynNodeSchema,\n [PRODUCT_PAGE_NODE]: {\n $id: PRODUCT_PAGE_NODE,\n parentId: 'pdp__container',\n componentId: 'product-detail',\n pluginId: 'commerce',\n props: { slug, showDetails: true, showShipping: true },\n } as Aglyn.AglynNodeSchema,\n ...(reviews\n ? {\n [PRODUCT_PAGE_REVIEWS_NODE]: {\n $id: PRODUCT_PAGE_REVIEWS_NODE,\n parentId: 'pdp__container',\n componentId: 'product-reviews',\n pluginId: 'commerce',\n props: { heading: 'Reviews', sx: { marginTop: 8 } },\n } as Aglyn.AglynNodeSchema,\n }\n : {}),\n [PRODUCT_PAGE_RELATED_NODE]: {\n $id: PRODUCT_PAGE_RELATED_NODE,\n parentId: 'pdp__container',\n componentId: 'related-products',\n pluginId: 'commerce',\n props: {\n heading: 'You may also like',\n maxItems: 4,\n layout: 'grid',\n sx: { marginTop: 8 },\n },\n } as Aglyn.AglynNodeSchema,\n }\n}\n\n/**\n * The store's return window for this product, when the store takes returns of\n * its kind: the settings the return form enforces (`readReturnSettings`), so\n * the page never states a policy the store does not keep.\n */\nexport function productReturnWindow(\n product: Pick<CommerceModel.HostProduct, 'type'>,\n rawReturns: unknown,\n): { windowDays: number } | undefined {\n const settings = CommerceModel.readReturnSettings(rawReturns)\n if (!settings.enabled || settings.windowDays <= 0) return undefined\n if (!settings.eligibleTypes.includes(product.type ?? 'physical')) return undefined\n return { windowDays: settings.windowDays }\n}\n\n/** Whether the store's plan collects reviews; a failed read leaves them off. */\nasync function storeTakesReviews(hostId: string): Promise<boolean> {\n try {\n const org = await getOrgForHost(hostId)\n return Aglyn.checkEntitlement(org?.org as never, 'productReviews')\n } catch (error) {\n console.error('reviews entitlement read failed', error)\n return false\n }\n}\n\nasync function composeBuiltInProductPage(\n hostId: string,\n host: unknown,\n productId: string,\n product: ReturnType<typeof CommerceModel.liftLegacyProduct>,\n rawReturns?: unknown,\n) {\n try {\n const [layoutId, productReviews, reviewsOn] = await Promise.all([\n resolveBuiltInPageLayoutId({ hostId, host: host as never }),\n readProductReviews(hostId, productId).catch((error) => {\n console.error('product review aggregate failed', error)\n return { reviews: [], aggregate: { count: 0, average: 0 } }\n }),\n storeTakesReviews(hostId),\n ])\n const returns = productReturnWindow(product, rawReturns)\n const card = collectSocialImageFacts([\n product.mediaUrls?.[0] ?? product.imageUrl,\n (host as { seo?: { image?: string } } | null)?.seo?.image,\n ])\n const nodes = await composeNodesWithChrome({\n hostId,\n layoutId,\n screenNodes: buildProductPageNodes(product.slug, { reviews: reviewsOn }),\n socialImages: card.socialImages,\n host: host as Aglyn.HostTokenSource,\n })\n if (!nodes) return undefined\n return {\n props: JSON.parse(\n JSON.stringify({\n // Seeded, so the product renders server-side and the head writes\n // its Product structured data, as on a template page (AGL-659).\n pageData: {\n commerce: {\n product: toPublicProductDetail(productId, product, {\n timeZone: await passDayTimeZone(hostId, host, product),\n }),\n ...(productReviews.aggregate.count ? { reviews: productReviews } : {}),\n // The Shipping & returns fold's return line, only when the\n // store takes returns of this product's kind.\n ...(returns ? { returns } : {}),\n },\n },\n data: {\n host,\n screen: {\n data: {\n displayName: product.name,\n seo: {\n title: product.seo?.title ?? undefined,\n description: product.seo?.description ?? product.description ?? undefined,\n },\n },\n },\n },\n nodes,\n ...card.collected(),\n }),\n ),\n revalidate: 60,\n }\n } catch (error) {\n console.error('built-in product page composition failed', error)\n return undefined\n }\n}\n\nconst ORDER_STATUS_NODE = 'order-status__block'\n\n/** The order-status page's node tree, root first, for the layout's slot. */\nexport function buildOrderStatusNodes(): Record<string, Aglyn.AglynNodeSchema> {\n return {\n [Aglyn.NODE_ROOT_ID]: {\n $id: Aglyn.NODE_ROOT_ID,\n componentId: 'div',\n nodes: ['order-status__container'],\n } as Aglyn.AglynNodeSchema,\n 'order-status__container': {\n $id: 'order-status__container',\n parentId: Aglyn.NODE_ROOT_ID,\n componentId: 'muiContainer',\n pluginId: 'mui',\n props: { maxWidth: 'md', sx: { paddingTop: 6, paddingBottom: 8 } },\n nodes: [ORDER_STATUS_NODE],\n } as Aglyn.AglynNodeSchema,\n [ORDER_STATUS_NODE]: {\n $id: ORDER_STATUS_NODE,\n parentId: 'order-status__container',\n componentId: ORDER_STATUS_COMPONENT_ID,\n pluginId: 'commerce',\n props: {},\n } as Aglyn.AglynNodeSchema,\n }\n}\n\nasync function composeOrderStatusPage(hostId: string, host: unknown) {\n try {\n const layoutId = await resolveBuiltInPageLayoutId({ hostId, host: host as never })\n const nodes = await composeNodesWithChrome({\n hostId,\n layoutId,\n screenNodes: buildOrderStatusNodes(),\n host: host as Aglyn.HostTokenSource,\n })\n if (!nodes) return undefined\n return {\n props: JSON.parse(\n JSON.stringify({\n data: {\n host,\n screen: {\n data: {\n displayName: 'Order status',\n visibility: Aglyn.HostScreenVisibility.UNLISTED,\n },\n },\n },\n nodes,\n }),\n ),\n revalidate: 3600,\n }\n } catch (error) {\n console.error('order status page composition failed', error)\n return undefined\n }\n}\n\nconst RETURN_REQUEST_NODE = 'ret__block'\n\n/** The return form's node tree, root first, for the layout's slot. */\nexport function buildReturnRequestNodes(): Record<string, Aglyn.AglynNodeSchema> {\n return {\n [Aglyn.NODE_ROOT_ID]: {\n $id: Aglyn.NODE_ROOT_ID,\n componentId: 'div',\n nodes: ['ret__container'],\n } as Aglyn.AglynNodeSchema,\n ret__container: {\n $id: 'ret__container',\n parentId: Aglyn.NODE_ROOT_ID,\n componentId: 'muiContainer',\n pluginId: 'mui',\n props: { maxWidth: 'md', sx: { paddingTop: 6, paddingBottom: 8 } },\n nodes: [RETURN_REQUEST_NODE],\n } as Aglyn.AglynNodeSchema,\n [RETURN_REQUEST_NODE]: {\n $id: RETURN_REQUEST_NODE,\n parentId: 'ret__container',\n componentId: RETURN_REQUEST_COMPONENT_ID,\n pluginId: 'commerce',\n props: {},\n } as Aglyn.AglynNodeSchema,\n }\n}\n\nasync function composeReturnRequestPage(hostId: string, host: unknown) {\n try {\n const layoutId = await resolveBuiltInPageLayoutId({ hostId, host: host as never })\n const nodes = await composeNodesWithChrome({\n hostId,\n layoutId,\n screenNodes: buildReturnRequestNodes(),\n host: host as Aglyn.HostTokenSource,\n })\n if (!nodes) return undefined\n return {\n props: JSON.parse(\n JSON.stringify({\n data: {\n host,\n screen: {\n data: {\n displayName: 'Request a return',\n visibility: Aglyn.HostScreenVisibility.UNLISTED,\n },\n },\n },\n nodes,\n }),\n ),\n revalidate: 3600,\n }\n } catch (error) {\n console.error('return request page composition failed', error)\n return undefined\n }\n}\n\nconst QUOTE_PAGE_NODE = 'quote-page__block'\n\n/** The quote page's node tree, root first, for the layout's slot. */\nexport function buildQuotePageNodes(): Record<string, Aglyn.AglynNodeSchema> {\n return {\n [Aglyn.NODE_ROOT_ID]: {\n $id: Aglyn.NODE_ROOT_ID,\n componentId: 'div',\n nodes: ['quote-page__container'],\n } as Aglyn.AglynNodeSchema,\n 'quote-page__container': {\n $id: 'quote-page__container',\n parentId: Aglyn.NODE_ROOT_ID,\n componentId: 'muiContainer',\n pluginId: 'mui',\n props: { maxWidth: 'md', sx: { paddingTop: 6, paddingBottom: 8 } },\n nodes: [QUOTE_PAGE_NODE],\n } as Aglyn.AglynNodeSchema,\n [QUOTE_PAGE_NODE]: {\n $id: QUOTE_PAGE_NODE,\n parentId: 'quote-page__container',\n componentId: QUOTE_PAGE_COMPONENT_ID,\n pluginId: 'commerce',\n props: {},\n } as Aglyn.AglynNodeSchema,\n }\n}\n\nasync function composeQuotePage(hostId: string, host: unknown) {\n try {\n const layoutId = await resolveBuiltInPageLayoutId({ hostId, host: host as never })\n const nodes = await composeNodesWithChrome({\n hostId,\n layoutId,\n screenNodes: buildQuotePageNodes(),\n host: host as Aglyn.HostTokenSource,\n })\n if (!nodes) return undefined\n return {\n props: JSON.parse(\n JSON.stringify({\n data: {\n host,\n screen: {\n data: {\n // The page is the same for a quote's link and an invoice's (AGL-4099).\n displayName: 'Your quote or invoice',\n visibility: Aglyn.HostScreenVisibility.UNLISTED,\n },\n },\n },\n nodes,\n }),\n ),\n revalidate: 3600,\n }\n } catch (error) {\n console.error('quote page composition failed', error)\n return undefined\n }\n}\n\n/**\n * The store's time zone for a product page whose product asks for a use day\n * (AGL-4043), so the seeded page offers the same days the API's does; null\n * otherwise, without a read.\n */\nasync function passDayTimeZone(\n hostId: string,\n host: unknown,\n product: ReturnType<typeof CommerceModel.liftLegacyProduct>,\n): Promise<string | null> {\n if (!productAsksUseDateAnywhere(product)) return null\n const hostRef = firebaseAdmin.app().firestore().collection('hosts').doc(hostId)\n return (await readStoreDay(hostRef, { host: (host ?? null) as Record<string, unknown> | null })).timeZone\n}\n"],"names":["hostCollectionKind","composeScreenNodes","composeNodesWithChrome","resolveBuiltInPageLayoutId","Aglyn","ORDER_STATUS_PATH","ORDER_STATUS_COMPONENT_ID","RETURN_REQUEST_COMPONENT_ID","RETURN_REQUEST_PATH","QUOTE_PAGE_COMPONENT_ID","QUOTE_PAGE_PATH","getScreen","collectSocialImageFacts","firebaseAdmin","getOrgForHost","CommerceModel","productAsksUseDateAnywhere","toPublicProductDetail","readStoreDay","readProductReviews","commerceSitePageResolver","hostId","host","path","hostRes","pdpSegments","split","filter","Boolean","length","composeOrderStatusPage","composeReturnRequestPage","composeQuotePage","productSnapshot","adminFirestore","app","firestore","hostDocRef","collection","doc","storeSettings","Promise","all","get","where","limit","pdpScreenId","productRaw","docs","data","listedOnline","productListedOnline","product","liftLegacyProduct","templateRes","screenId","allowTemplate","screen","minPrice","maxPrice","productPriceRange","productReviews","id","catch","error","console","reviews","aggregate","count","average","card","seo","image","templateNodes","socialImages","tokens","name","description","productPriceText","mediaUrls","imageUrl","slug","page","template","role","route","collectionName","entryPath","fallback","props","JSON","parse","stringify","pageData","commerce","timeZone","passDayTimeZone","displayName","title","undefined","nodes","collected","revalidate","composeBuiltInProductPage","collectionSnapshot","collectionScreenId","shopCollection","find","docSnapshot","variants","some","variant","variantHasPrice","PRODUCT_PAGE_NODE","PRODUCT_PAGE_REVIEWS_NODE","PRODUCT_PAGE_RELATED_NODE","buildProductPageNodes","options","NODE_ROOT_ID","$id","componentId","pdp__container","parentId","pluginId","maxWidth","sx","paddingTop","paddingBottom","showDetails","showShipping","heading","marginTop","maxItems","layout","productReturnWindow","rawReturns","settings","readReturnSettings","enabled","windowDays","eligibleTypes","includes","type","storeTakesReviews","org","checkEntitlement","productId","layoutId","reviewsOn","returns","screenNodes","ORDER_STATUS_NODE","buildOrderStatusNodes","visibility","HostScreenVisibility","UNLISTED","RETURN_REQUEST_NODE","buildReturnRequestNodes","ret__container","QUOTE_PAGE_NODE","buildQuotePageNodes","hostRef"],"mappings":"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"}
package/src/lib/server.js CHANGED
@@ -404,6 +404,22 @@ registerPluginJob({
404
404
  recipientLink: true
405
405
  });
406
406
  registerPluginApiRoute('commerce/quote-pay', quotePayDoor, CARD_PAYMENT_DOOR);
407
+ // The quote as a PDF (AGL-4095), by the same signed link and on the same
408
+ // terms as the page's data. Loaded on first call, with sharp and the PDF
409
+ // writer behind it.
410
+ registerPluginApiRoute('commerce/quote-pdf', async (req, res)=>(await import("./server/commerce-pdf.js")).quotePdfHandler(req, res), {
411
+ recipientLink: true
412
+ });
413
+ // The quote's proofs (AGL-4096), by the same signed link and on the same
414
+ // terms as the page's data; and the customer's answer to them, with any
415
+ // artwork they send through the shared visitor upload. The two writes are
416
+ // ordinary visitor writes: the dispatcher's cross-origin check, lockdown
417
+ // and visitor-write limit stand in front of their own. Loaded on first call.
418
+ registerPluginApiRoute('commerce/quote-proof', async (req, res)=>(await import("./server/quote-proofs.js")).quoteProofHandler(req, res), {
419
+ recipientLink: true
420
+ });
421
+ registerPluginApiRoute('commerce/quote-upload', async (req, res)=>(await import("./server/quote-proofs.js")).quoteUploadHandler(req, res));
422
+ registerPluginApiRoute('commerce/quote-respond', async (req, res)=>(await import("./server/quote-proofs.js")).quoteRespondHandler(req, res));
407
423
  // What became of a session the shopper was returned from (AGL-3606).
408
424
  registerPluginApiRoute('commerce/checkout-status', checkoutStatusHandler);
409
425
  registerPluginApiRoute('commerce/product', productHandler);
@@ -503,6 +519,11 @@ registerPluginJob({
503
519
  // Quotes (AGL-4093): create, edit and delete a quote, and find the customer
504
520
  // it is for, under "Create and edit quotes". Loaded on first call.
505
521
  registerPluginApiRoute('commerce/quote', async (req, res)=>(await import("./server/quote.js")).quoteHandler(req, res));
522
+ // Send invoice (AGL-4099) for an order or a quote, under "Send quotes and
523
+ // invoices to customers": an unpaid one with the order's lasting pay link,
524
+ // a paid one as the record. The email, the PDF and sharp load on first
525
+ // call only.
526
+ registerPluginApiRoute('commerce/order-invoice-send', async (req, res)=>(await import("./server/order-invoice-send.js")).orderInvoiceSendHandler(req, res));
506
527
  // Fulfil + mark-delivered with the transition re-asked under the write
507
528
  // (AGL-1819) — the same stale-dialog hole cancel-order closes, minus the
508
529
  // stock release those two transitions never had. The customer REST API's
@@ -542,7 +563,9 @@ registerPluginJob({
542
563
  registerPluginApiRoute('commerce/order-restock-answer', async (req, res)=>(await import("./server/order-annotations.js")).orderRestockAnswerHandler(req, res));
543
564
  // The order dialog's Packing slip and Invoice for the native apps
544
565
  // (AGL-3841): the console's own two pages over the stored order, which the
545
- // apps print on the device's print sheet. Loaded on first call.
566
+ // apps print on the device's print sheet; and the invoice as a PDF file
567
+ // (`kind=invoice-pdf`, AGL-4095) for the console and the apps. Loaded on
568
+ // first call.
546
569
  registerPluginApiRoute('commerce/order-print', async (req, res)=>(await import("./server/order-print.js")).orderPrintHandler(req, res));
547
570
  // Issue / void store credit (AGL-2226). Server-side because the host
548
571
  // catch-all in the Firestore rules would otherwise let a client write
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../libs/plugins/commerce/src/lib/server.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n/**\n * Server half of the commerce plugin (AGL-396): the site-facing storefront\n * API handlers, registered with the plugin API registry and served by the\n * tenant dispatcher at their unchanged `/api/commerce/*` URLs. This module\n * pulls in firebase-admin + Stripe, so it is NOT re-exported from the client\n * barrel — apps import `@aglyn/plugins-commerce/server` only from their\n * (server-only) API dispatcher registration.\n */\n\nimport {\n registerBillingWebhookHandler,\n registerPluginApiRoute,\n registerPluginJob,\n registerSitePageEnricher,\n registerSitePageResolver,\n registerPluginPermissions,\n registerPluginConfigSchema,\n type PluginApiHandler,\n} from '@aglyn/aglyn/server'\nimport { isEmailConfigured } from '@aglyn/shared-util-email'\nimport { firebaseAdmin } from '@aglyn/tenant-data-admin'\nimport { BUNDLE_ID } from './constants/bundle-common'\nimport { registerCommerceMediaPublishGuard } from './server/media-publish-guard'\nimport { registerCommerceRecurringCharges } from './server/recurring-charges'\nimport { registerProductCardReader } from './server/product-card'\nimport { registerProductAiCapability } from './server/product-ai-capability'\nimport { registerStoreSetupAiCapabilities } from './server/store-setup-ai-capability'\nimport { registerStoreSetupAiWriter } from './server/store-setup-ai-writer.console'\nimport { registerProductDraftWriter } from './server/product-drafts'\nimport { registerCommerceTaxProfile } from './server/tax-profile'\nimport { registerTaxReturnSource } from '@aglyn/aglyn/plugin-manager/plugin-tax-return-sources'\nimport { commerceTaxReturnSource } from './server/tax-return-source'\nimport { taxSummaryHandler } from './server/tax-summary'\nimport { registerRevenueSource } from '@aglyn/aglyn/plugin-manager/plugin-revenue-sources'\nimport { commerceRevenueSource } from './server/revenue-source'\nimport { commerceBillingWebhookHandler } from './server/billing-webhook'\nimport { registerOrderFigureReaders } from './server/order-figures'\nimport { COMMERCE_PERMISSIONS } from './model/plugin-permissions'\nimport { COMMERCE_CONFIG_SCHEMA } from './plugin-config'\nimport { commerceSitePageEnricher } from './server/site-page-enricher'\nimport { commerceSitePageResolver } from './server/site-page-resolver'\nimport { cartCheckoutHandler } from './server/cart-checkout'\nimport { cartHandler } from './server/cart'\nimport { cartExtrasHandler } from './server/checkout-extras'\nimport { catalogHandler } from './server/catalog'\nimport { checkoutHandler } from './server/checkout'\nimport { downloadHandler } from './server/download'\nimport { newsletterHandler } from './server/newsletter'\nimport { notifyRestockHandler } from './server/notify-restock'\nimport { productHandler } from './server/product'\nimport { relatedHandler } from './server/related'\nimport { reservationAvailabilityHandler } from './server/reservation-availability'\nimport { gateHandler } from './server/gate'\nimport { memberFeedHandler } from './server/member-feed'\nimport { membershipAccountHandler } from './server/membership-account'\nimport { membershipAdminPasswordHandler } from './server/membership-admin-password'\nimport { membershipAdminRemoveHandler } from './server/membership-admin-remove'\nimport { membershipContentHandler } from './server/membership-content'\nimport { membershipLoginHandler } from './server/membership-login'\nimport { membershipLogoutHandler } from './server/membership-logout'\nimport { membershipRecoverHandler } from './server/membership-recover'\nimport { membershipRegisterHandler } from './server/membership-register'\nimport { membershipResetHandler } from './server/membership-reset'\nimport { membershipWishlistHandler } from './server/membership-wishlist'\nimport { reserveHandler } from './server/reserve'\nimport { streamHandler } from './server/stream'\nimport { subscriptionPortalHandler } from './server/subscription-portal'\nimport { reviewsHandler } from './server/reviews'\nimport { connectHandler } from './server/connect'\nimport { cancelOrderHandler } from './server/cancel-order'\nimport { carrierRatesAvailabilityHandler } from './server/carrier-rates-availability'\nimport { collectionMembershipHandler } from './server/collection-membership'\nimport { draftOrderHandler } from './server/draft-order'\nimport { fulfillOrderHandler } from './server/fulfill-order'\nimport { orderReceiptSendHandler } from './server/order-receipt-send'\nimport { orderStatusHandler, registerOrderStatusActions } from './server/order-status'\nimport { returnRequestStatusAction } from './server/return-status-action'\nimport { giftCardsHandler } from './server/gift-cards'\nimport { memberPostHandler } from './server/member-post'\nimport { orderAnalyticsHandler } from './server/order-analytics'\nimport { checkoutStatusHandler } from './server/checkout-status'\nimport { posOrderHandler } from './server/pos-order'\nimport { printersHandler } from './server/printers'\nimport { posPaymentHandler } from './server/pos-payment'\nimport { posReadersHandler } from './server/pos-readers'\nimport { posTerminalConnectionTokenHandler } from './server/pos-terminal-connection-token'\nimport { posDisplayHandler } from './server/pos-display'\nimport { posKioskHandler } from './server/pos-kiosk'\nimport { registerPosOpsRoutes } from './server/pos-ops-routes'\nimport {\n processAbandonedHandler,\n scanAbandonedCheckouts,\n} from './server/process-abandoned'\nimport { processRestockHandler, scanRestockAlerts } from './server/process-restock'\nimport { scanStockDecrements } from './server/reconcile-stock'\nimport { refundHandler } from './server/refund'\nimport { orderWebhooksHandler } from './server/order-webhooks'\nimport { returnRequestHandler, returnsHandler } from './server/returns'\nimport { scanSupplierDeliveries } from './server/supplier-outbox'\nimport { supplierUpdateHandler } from './server/supplier-update'\n\n/**\n * The two commerce beats (AGL-2227).\n *\n * `commerce/process-abandoned` and `commerce/process-restock` have existed\n * since AGL-323/326 as `x-cron-secret` HTTP doors, and `registerCommerceConsoleApi`\n * below has called them \"the scheduler-driven jobs\" in a comment that whole\n * time. **Nothing scheduled them.** Not `scheduled-crons.yml` (its table names\n * 11 paths; neither of these), not `vercel.json` (no `crons` key at all), not\n * `registerPluginJob` — the only two registrations in the repo were scheduled\n * publishing and the bookings hold-expiry.\n *\n * The cost was a Pro-tier entitlement (`abandonedCart`) that had never sent an\n * email, and a storefront \"notify me when it's back\" form writing into a queue\n * with no drain. AGL-1793 had already added the collection-group indexes these\n * two scans need, which is the clearest evidence they were always meant to run.\n *\n * Module scope, like the bookings job beside it: the runner route reaches jobs\n * through `ensureAll(['tenantApi'])`, and a registration inside a `register*`\n * function would depend on which entry point happened to be loaded.\n *\n * 15 minutes, not 1: `process-abandoned` will not remind a checkout younger\n * than an hour and `process-restock` only mails alerts whose product already\n * has stock, so a tighter beat buys nothing and costs two collection-group\n * scans a minute. Both are bounded (200 docs) and idempotent — each pass\n * stamps what it sent — so an overlapping or repeated beat cannot double-send.\n */\nconst RECOVERY_JOB_INTERVAL_MINUTES = 15\n\nregisterPluginJob({\n pluginId: BUNDLE_ID,\n name: 'abandoned-checkout-recovery',\n intervalMinutes: RECOVERY_JOB_INTERVAL_MINUTES,\n description:\n 'Email one recovery reminder per stalled checkout (abandonedCart plans).',\n lockdown: { scope: 'per-host' },\n handler: async (gate) => {\n // Quietly, not as an error: email is optional per deployment, and a beat\n // that logs every minute on a self-host without Resend buries everything\n // else in the log.\n if (!isEmailConfigured()) return\n const { sent } = await scanAbandonedCheckouts(gate)\n if (sent) console.info(`commerce: sent ${sent} abandoned-cart reminders`)\n },\n})\n\nregisterPluginJob({\n pluginId: BUNDLE_ID,\n name: 'back-in-stock-alerts',\n intervalMinutes: RECOVERY_JOB_INTERVAL_MINUTES,\n description: 'Email shoppers whose requested product is in stock again.',\n lockdown: { scope: 'per-host' },\n handler: async (gate) => {\n if (!isEmailConfigured()) return\n const { sent } = await scanRestockAlerts(gate)\n if (sent) console.info(`commerce: sent ${sent} back-in-stock alerts`)\n },\n})\n\n/**\n * The review-request email (AGL-3736). HOURLY: a request is owed days after\n * fulfilment, so an hour's lateness is invisible, and the scan is one\n * collection-group range query over `reviewRequestDueAtMs` — a field only\n * orders still owed a request carry, so an empty beat costs one read.\n */\nregisterPluginJob({\n pluginId: BUNDLE_ID,\n name: 'review-request-emails',\n intervalMinutes: 60,\n description:\n 'Email each buyer one review request, with a single-use link per product, ' +\n 'days after their order is fulfilled (AGL-3736).',\n lockdown: { scope: 'per-host' },\n handler: async (gate) => {\n if (!isEmailConfigured()) return\n const { scanReviewRequests } = await import('./server/review-requests')\n const { sent } = await scanReviewRequests(gate)\n if (sent) console.info(`commerce: sent ${sent} review requests`)\n },\n})\n\n/**\n * The missing-decrement detector (AGL-2358).\n *\n * HOURLY, not on the 15-minute recovery beat: it is a detector for a rare\n * process death, not a queue drain, and nothing it finds gets less true for\n * waiting an hour. The cost of the beat is what sets the interval — one\n * collection-group read of the platform's most recent orders, plus two\n * queries per host that has any — and an hour keeps that off the same tick as\n * the two scans above.\n *\n * NOT gated on `isEmailConfigured()`, unlike its two neighbours. Those send\n * mail; this writes a console notification and a log line, both of which work\n * on a self-host with no mail provider at all — and a stock count that is\n * silently wrong is exactly what a self-hoster least wants suppressed by a\n * setting about email.\n */\nregisterPluginJob({\n pluginId: BUNDLE_ID,\n name: 'stock-decrement-reconciliation',\n intervalMinutes: 60,\n description:\n 'Report paid orders whose stock decrement never landed (AGL-2358).',\n lockdown: { scope: 'per-host' },\n handler: async (gate) => {\n const scan = await scanStockDecrements(gate)\n if (scan.missingLines || scan.truncatedHosts) {\n console.warn(\n `commerce: ${scan.missingLines} order lines across ${scan.hosts} ` +\n `sites have no sale ledger row (${scan.reportedOrders} newly ` +\n `reported, ${scan.truncatedHosts} sites' ledger window truncated)`,\n )\n }\n },\n})\n\n/**\n * The dropship supplier outbox drain (AGL-2473).\n *\n * EVERY MINUTE, unlike the three above, and the interval is the point rather\n * than an oversight. This is the only one of the four that a BUYER is waiting\n * on: the row it drains is a paid order that has not been routed to whoever\n * ships it, and every minute it sits is a minute the parcel is not moving. The\n * first backoff step is also 60s, so a supplier that blipped is retried on the\n * next tick.\n *\n * The cost that set fifteen minutes for the recovery pair does not apply. Those\n * are collection-GROUP scans across every site on the platform; this is one\n * ordinary equality query against a top-level collection that is EMPTY in the\n * ordinary case — an empty result bills a single read, so the whole beat is\n * ~1,440 reads a day whether or not anyone is dropshipping.\n *\n * Not gated on `isEmailConfigured()`. The supplier notification is an HTTP POST\n * to the merchant's own supplier, and a self-host with no mail provider still\n * has dropship orders to route.\n */\nregisterPluginJob({\n pluginId: BUNDLE_ID,\n name: 'supplier-webhook-delivery',\n intervalMinutes: 1,\n description:\n 'Deliver queued dropship supplier notifications, with backoff and a ' +\n 'dead letter that tells the merchant (AGL-2473).',\n lockdown: { scope: 'per-host' },\n handler: async (gate) => {\n const scan = await scanSupplierDeliveries(gate)\n if (scan.deadLettered) {\n console.warn(\n `commerce: ${scan.deadLettered} dropship orders could not be routed ` +\n `to their supplier and have been reported on the order`,\n )\n }\n },\n})\n\n/**\n * Stripe payment method domains for every connected custom domain (AGL-3629).\n *\n * The backfill for domains connected before registration existed, and the\n * repair for a connect whose event was lost, in one daily pass. A domain\n * already registered costs a document read and no Stripe call, so the beat is\n * cheap; a day's delay costs only the Apple Pay button on a domain connected\n * while Stripe was unreachable, and the first in-page checkout there registers\n * it anyway.\n */\nregisterPluginJob({\n pluginId: BUNDLE_ID,\n name: 'payment-method-domains',\n intervalMinutes: 24 * 60,\n description:\n 'Register connected custom domains with Stripe so Apple Pay, Google Pay ' +\n 'and Link show on them (AGL-3629).',\n lockdown: { scope: 'per-host' },\n handler: async (gate) => {\n if (!process.env.STRIPE_SECRET_KEY) return\n const { reconcileCustomDomains } = await import('./server/payment-method-domains')\n const result = await reconcileCustomDomains(gate)\n if (result.registered || result.failed) {\n console.info(\n `commerce: payment method domains — ${result.registered} registered, ` +\n `${result.failed} failed across ${result.hosts} sites`,\n )\n }\n },\n})\n\n/**\n * The monthly 4G charge for Stripe Reader S710s (AGL-4038): each workspace\n * whose readers had 4G in the month just ended is charged once, through\n * core's usage-invoice charge. Every six hours, so the charge goes out early\n * on the 1st and one that could not reach Stripe is tried again the same\n * day; a month already settled costs a read per workspace. Nothing runs\n * where 4G is not offered (`POS_CELLULAR_MONTHLY_COST_CENTS` unset).\n * Per-host: a store locked for security or abuse is not charged while it is.\n */\nregisterPluginJob({\n pluginId: BUNDLE_ID,\n name: 'pos-cellular-billing',\n intervalMinutes: 6 * 60,\n description:\n 'Charge each workspace for 4G on its Stripe Reader S710s for the month just ended, once (AGL-4038).',\n lockdown: { scope: 'per-host' },\n handler: async (gate) => {\n if (!process.env.STRIPE_SECRET_KEY || !process.env.POS_CELLULAR_MONTHLY_COST_CENTS) return\n const { runPosCellularBilling } = await import('./server/pos-cellular-billing')\n const report = await runPosCellularBilling(gate)\n if (report.workspaces || report.storesGone || report.warned || report.turnedOff || report.paidLate) {\n console.info(\n `commerce: 4G for ${report.month} — ${report.paid} paid, ${report.open} left open, ` +\n `${report.failed} not reached, ${report.unbillable} not billable, ${report.deferred} deferred, ` +\n `${report.storesGone} deleted stores turned off; unpaid charges: ${report.warned} warned, ` +\n `${report.paidLate} paid since, ${report.turnedOff} turned off`,\n )\n }\n },\n})\n\n/**\n * Card reader start-up screens (AGL-4048) that went stale with nobody opening\n * the POS devices card: a logo changed on the organization profile or the\n * white-label brand, or the logo's file replaced in the media library. Every\n * 15 minutes, like the recovery pair: a store whose screen did not move costs\n * a few reads and no Stripe call, and nothing a merchant saves waits on it.\n * A screen Stripe refused is retried after six hours here, and at once when\n * the card is opened.\n */\nregisterPluginJob({\n pluginId: BUNDLE_ID,\n name: 'pos-reader-splash-refresh',\n intervalMinutes: RECOVERY_JOB_INTERVAL_MINUTES,\n description:\n 'Bring card reader start-up screens up to date after a logo change (AGL-4048).',\n lockdown: { scope: 'per-host' },\n handler: async (gate) => {\n if (!process.env.STRIPE_SECRET_KEY) return\n const { refreshPosReaderSplashes } = await import('./server/pos-reader-splash')\n const result = await refreshPosReaderSplashes(gate)\n if (result.applied || result.failed || result.more) {\n console.info(\n `commerce: reader start-up screens — ${result.applied} updated, ` +\n `${result.failed} failed${result.more ? ', more stores than one pass reaches' : ''}`,\n )\n }\n },\n})\n\n/**\n * Cards taken offline whose sale never synced (AGL-4039).\n *\n * HOURLY. The alert falls due six hours after the intent was first seen, and\n * Stripe's authorization lasts about two days, so an hour's delay costs\n * nothing and leaves the beat one collection-group range read that is empty in\n * the ordinary case. It never captures: without the sale there is no fee to\n * capture with, so it tells the operator and the site's managers instead.\n *\n * Not gated on `isEmailConfigured()`: the console notification and the\n * operator alert both work without mail.\n */\nregisterPluginJob({\n pluginId: BUNDLE_ID,\n name: 'offline-card-unsynced',\n intervalMinutes: 60,\n description:\n 'Tell the operator and the site when a card taken offline reached Stripe but its sale never synced (AGL-4039).',\n lockdown: { scope: 'per-host' },\n handler: async (gate) => {\n const { scanUnsyncedOfflineCards } = await import('./server/pos-offline-card-reconcile')\n const scan = await scanUnsyncedOfflineCards(gate)\n if (scan.alerted) {\n console.warn(`commerce: ${scan.alerted} cards taken offline have no synced sale`)\n }\n },\n})\n\n/**\n * A visitor's payment door: it opens a Stripe Checkout Session for whoever\n * calls it, so the dispatcher holds it to the card-testing counters\n * (AGL-3363). Declared here, beside the registration, so the door cannot\n * exist without it.\n */\nconst CARD_PAYMENT_DOOR = { cardPayment: true } as const\n\n/**\n * The quote page's Pay button (AGL-4094): a fresh Checkout Session for a\n * quote, for whoever holds its signed pay link. Loaded on first call.\n */\nconst quotePayDoor: PluginApiHandler = async (req, res) =>\n (await import('./server/quote-pay')).quotePayHandler(req, res)\n\n/** Registers the commerce plugin's storefront API routes. */\nexport function registerCommerceApi(): void {\n registerProductCardReader()\n // The merchant's tax rule, for every plugin that prices a charge here.\n registerCommerceTaxProfile()\n registerPluginPermissions(COMMERCE_PERMISSIONS)\n // Merchant-settable register discount ceiling (AGL-2161). Registered on\n // BOTH surfaces, like the permissions above: the POS route reads it\n // server-side, and the settings card renders it from the same schema.\n registerPluginConfigSchema(COMMERCE_CONFIG_SCHEMA)\n // PDP/PLP template pages (AGL-418): /products/* + /collections/*.\n registerSitePageResolver(commerceSitePageResolver)\n // Seeds product grids on ordinary screens (AGL-659) — the resolver above\n // only covers /products/* and /collections/*, so /products itself, and any\n // designed page with a grid on it, needed this to render server-side.\n registerSitePageEnricher(commerceSitePageEnricher)\n registerPluginApiRoute('commerce/cart-checkout', cartCheckoutHandler, CARD_PAYMENT_DOOR)\n registerPluginApiRoute('commerce/cart', cartHandler)\n // What the cart offers besides shipping (AGL-3624): pickup locations, and\n // local delivery's fee, minimum and windows for a postal code.\n registerPluginApiRoute('commerce/local-fulfillment-options', async (req, res) =>\n (await import('./server/local-fulfillment')).localFulfillmentOptionsHandler(req, res),\n )\n // Optional lines another plugin offers at the cart (AGL-3635).\n registerPluginApiRoute('commerce/cart-extras', cartExtrasHandler)\n registerPluginApiRoute('commerce/catalog', catalogHandler)\n registerPluginApiRoute('commerce/checkout', checkoutHandler, CARD_PAYMENT_DOOR)\n registerPluginApiRoute('commerce/download', downloadHandler)\n // The pre-channels Google feed address (AGL-299), now written by the\n // catalog's feed publisher (AGL-3637); the module loads with a fetch.\n registerPluginApiRoute('commerce/feed', {\n web: async (request) => (await import('./server/legacy-feed')).legacyFeedRoute(request),\n })\n registerPluginApiRoute('commerce/newsletter', newsletterHandler)\n registerPluginApiRoute('commerce/notify-restock', notifyRestockHandler)\n // GA-safe order projection for the storefront `purchase` (AGL-1641).\n registerPluginApiRoute('commerce/order-analytics', orderAnalyticsHandler)\n // The guest order-status page's data (AGL-3610), behind the signed link in\n // every buyer email — a recipient link, so it outlives the site's gates.\n registerPluginApiRoute('commerce/order-status', orderStatusHandler, { recipientLink: true })\n // …and its \"Request a return\" button (AGL-3611), on an order that can\n // still send something back.\n registerOrderStatusActions(returnRequestStatusAction)\n // The customer's quote page (AGL-4094), behind the signed pay link a\n // business sends: the quote, and its Pay button. The page's data is a\n // recipient link, so it outlives the site's gates like the order status.\n registerPluginApiRoute(\n 'commerce/quote-view',\n async (req, res) => (await import('./server/quote-pay')).quoteViewHandler(req, res),\n { recipientLink: true },\n )\n registerPluginApiRoute('commerce/quote-pay', quotePayDoor, CARD_PAYMENT_DOOR)\n // What became of a session the shopper was returned from (AGL-3606).\n registerPluginApiRoute('commerce/checkout-status', checkoutStatusHandler)\n registerPluginApiRoute('commerce/product', productHandler)\n registerPluginApiRoute('commerce/related', relatedHandler)\n registerPluginApiRoute('commerce/reservation-availability', reservationAvailabilityHandler)\n registerPluginApiRoute('commerce/reserve', reserveHandler, CARD_PAYMENT_DOOR)\n registerPluginApiRoute('commerce/gate', gateHandler)\n registerPluginApiRoute('commerce/member-feed', memberFeedHandler)\n registerPluginApiRoute('commerce/stream', streamHandler)\n registerPluginApiRoute('commerce/subscription-portal', subscriptionPortalHandler)\n registerPluginApiRoute('commerce/reviews', reviewsHandler)\n // A buyer's return request (AGL-3611), from their account or the signed\n // order-status link.\n registerPluginApiRoute('commerce/return-request', returnRequestHandler)\n registerPluginApiRoute('membership/account', membershipAccountHandler)\n registerPluginApiRoute('membership/content', membershipContentHandler)\n registerPluginApiRoute('membership/login', membershipLoginHandler)\n registerPluginApiRoute('membership/logout', membershipLogoutHandler)\n // Password recovery pair (AGL-552): request + complete.\n registerPluginApiRoute('membership/recover', membershipRecoverHandler)\n registerPluginApiRoute('membership/register', membershipRegisterHandler)\n registerPluginApiRoute('membership/reset', membershipResetHandler)\n registerPluginApiRoute('membership/wishlist', membershipWishlistHandler)\n}\n\n/**\n * Registers the commerce plugin's console-side API routes (AGL-396):\n * merchant/staff operations (Connect onboarding, refunds, draft & POS\n * orders, member posts), the supplier tracking callback, and the HTTP doors\n * for the abandoned-cart / restock passes.\n *\n * Those last two are NOT what schedules them — the `registerPluginJob` calls\n * above are (AGL-2227). This comment used to call them \"the scheduler-driven\n * jobs\", which is how they stayed dark for months: it asserted the wiring\n * instead of having it.\n */\nexport function registerCommerceConsoleApi(): void {\n // The register's gate (`managePos`) is resolved on THIS surface: every POS\n // route below runs in the console, and a key no surface registered here is\n // absent from the resolved map, which reads as refused — the site's own\n // owner was answered 403 at the register.\n registerPluginPermissions(COMMERCE_PERMISSIONS)\n // What a product looks like to a surface that is not this plugin's — a\n // campaign email that features one asks here rather than importing the model.\n registerProductCardReader()\n // …and a draft product another plugin asks for by name (AGL-3616): an AI\n // build setting a store up from a brief, unpriced unless the brief priced it.\n // The console runs AI jobs (AGL-3026).\n registerProductDraftWriter()\n // …and the operation an AI build plans for it, which that writer executes.\n registerProductAiCapability()\n // …and the store's shipping, pickup, local delivery and tax settings an AI\n // build sets up (AGL-3749), written live as the console's cards write them,\n // with the four operations that writer executes.\n registerStoreSetupAiWriter()\n registerStoreSetupAiCapabilities()\n // …and why a file somebody is SELLING may not be made public (AGL-3080).\n // The media library asks before it hands an asset its permanent CDN URL\n // back; what a product is, and which of its fields hold paid media, is\n // this plugin's to know.\n registerCommerceMediaPublishGuard()\n // …and which memberships a site sells, for a security lockdown to pause\n // (AGL-3364). The lockdown route runs on this surface.\n registerCommerceRecurringCharges()\n // …and the tax rule, for the webhook that confirms what they charged.\n registerCommerceTaxProfile()\n // …and its sales on the operator's own sales tax return (AGL-3080): the\n // tax a storefront checkout collected under the platform's registrations.\n // The staff return awaits this surface before it asks, and refuses to be\n // filed without this source — commerce declares `taxReturnSource`.\n registerTaxReturnSource(commerceTaxReturnSource, { pluginId: BUNDLE_ID })\n // …and the take its orders earn the operator, on the staff revenue report\n // (AGL-3080) — commerce declares `revenueSource`, so the report names this\n // source as unread rather than counting it as zero if it is missing.\n registerRevenueSource(commerceRevenueSource, { pluginId: BUNDLE_ID })\n // Stripe webhook sections (AGL-418): orders/carts/drafts/reservations/\n // subscriptions ride the platform webhook via the hook registry.\n registerBillingWebhookHandler(commerceBillingWebhookHandler)\n // A paid card-reader order from the POS hardware shop (AGL-4038), on the\n // same platform webhook: its own handler, self-selecting on the session's\n // `metadata.type`, so the storefront sections above never see it.\n registerBillingWebhookHandler(async (event) =>\n (await import('./server/pos-hardware-webhook')).posHardwareBillingWebhookHandler(event),\n )\n // A card the Aglyn POS app took offline (AGL-4039): its PaymentIntent can\n // reach Stripe before the sale reaches the server, so every event on one is\n // kept by the sale's key. Self-selecting on `metadata.kind`.\n registerBillingWebhookHandler(async (event) =>\n (await import('./server/pos-offline-card-reconcile')).posOfflineCardBillingWebhookHandler(event),\n )\n // Cancel + stock release in one transaction (AGL-1808). Server-side because\n // the release depends on the transition rule, and a client write could not\n // re-ask it under the same lock that flips the status.\n registerPluginApiRoute('commerce/cancel-order', cancelOrderHandler)\n // Whether live carrier rates can be offered on this site (AGL-3612).\n registerPluginApiRoute('commerce/shipping/carrier-rates', carrierRatesAvailabilityHandler)\n registerPluginApiRoute('commerce/connect', connectHandler)\n registerPluginApiRoute('commerce/draft-order', draftOrderHandler)\n // Quotes (AGL-4093): create, edit and delete a quote, and find the customer\n // it is for, under \"Create and edit quotes\". Loaded on first call.\n registerPluginApiRoute('commerce/quote', async (req, res) =>\n (await import('./server/quote')).quoteHandler(req, res),\n )\n // Fulfil + mark-delivered with the transition re-asked under the write\n // (AGL-1819) — the same stale-dialog hole cancel-order closes, minus the\n // stock release those two transitions never had. The customer REST API's\n // `PATCH /v1/sites/{id}/orders/{id}` records a shipment through the same\n // transaction (`server/api-v1/orders-and-products.ts`).\n registerPluginApiRoute('commerce/fulfill-order', fulfillOrderHandler)\n // Pickup and local delivery steps (AGL-3624) — ready, picked up, out for\n // delivery, delivered — from the console queue, the order dialog and the\n // native Aglyn app. Loaded on first call.\n registerPluginApiRoute('commerce/local-fulfillment', async (req, res) =>\n (await import('./server/local-fulfillment-status')).localFulfillmentHandler(req, res),\n )\n // \"Resend receipt\" from the order dialog (AGL-3610): by email, or by text\n // when the platform's SMS provider is configured. Rate-limited per member\n // and per order.\n registerPluginApiRoute('commerce/order-receipt-send', orderReceiptSendHandler)\n // The product editor's save and Adjust stock for the native apps (AGL-3652):\n // the console's own product-write computation under the rules' gate. Loaded\n // on first call.\n registerPluginApiRoute('commerce/products/save', async (req, res) =>\n (await import('./server/products-write')).productSaveHandler(req, res),\n )\n registerPluginApiRoute('commerce/products/stock', async (req, res) =>\n (await import('./server/products-write')).productStockHandler(req, res),\n )\n // A staff walk-in from the Reservations card and the native apps\n // (AGL-4046): availability re-asked inside the transaction that writes, so\n // two staff cannot hand out the last unit at once. Loaded on first call.\n registerPluginApiRoute('commerce/reservations/walk-in', async (req, res) =>\n (await import('./server/reservation-walk-in')).reservationWalkInHandler(req, res),\n )\n // A stay's guest count after it is booked (AGL-4043), from the Reservations\n // card and the check-in screen: the walk-in's gate, and the stay's\n // check-ins for today on brought in line in the same transaction. Loaded\n // on first call.\n registerPluginApiRoute('commerce/reservations/guests', async (req, res) =>\n (await import('./server/reservation-guests')).reservationGuestsHandler(req, res),\n )\n // The products list's Duplicate and Delete for the native apps (AGL-3841):\n // the console's own copy and soft delete, with the site-wide cache drop.\n registerPluginApiRoute('commerce/products/duplicate', async (req, res) =>\n (await import('./server/products-write')).productDuplicateHandler(req, res),\n )\n registerPluginApiRoute('commerce/products/delete', async (req, res) =>\n (await import('./server/products-write')).productDeleteHandler(req, res),\n )\n // The order dialog's note and restock answer for the native apps\n // (AGL-3651, AGL-3652): the console's own timeline computation, in one\n // transaction on the stored order. Loaded on first call.\n registerPluginApiRoute('commerce/order-note', async (req, res) =>\n (await import('./server/order-annotations')).orderNoteHandler(req, res),\n )\n registerPluginApiRoute('commerce/order-restock-answer', async (req, res) =>\n (await import('./server/order-annotations')).orderRestockAnswerHandler(req, res),\n )\n // The order dialog's Packing slip and Invoice for the native apps\n // (AGL-3841): the console's own two pages over the stored order, which the\n // apps print on the device's print sheet. Loaded on first call.\n registerPluginApiRoute('commerce/order-print', async (req, res) =>\n (await import('./server/order-print')).orderPrintHandler(req, res),\n )\n // Issue / void store credit (AGL-2226). Server-side because the host\n // catch-all in the Firestore rules would otherwise let a client write\n // its own `balanceCents`, which checkout applies as amount-off.\n registerPluginApiRoute('commerce/gift-cards', giftCardsHandler)\n // The merchant's own storefront sales tax, by who owes it (AGL-2440): the\n // same rows and classifier the operator's return reads, fenced to one site.\n registerPluginApiRoute('commerce/tax-summary', { web: taxSummaryHandler })\n // The payment methods card (AGL-3629): toggles, the platform's offer, the\n // payout account's capabilities and the site's wallet domains. Loaded with\n // the first request, so a console that never opens Settings never imports it.\n registerPluginApiRoute('commerce/payment-methods', {\n web: async (request) =>\n (await import('./server/payment-methods')).paymentMethodsHandler(request),\n })\n // A smart collection's rules changed or it was deleted: re-stamp which\n // products it holds (AGL-3321), the membership the storefront queries.\n registerPluginApiRoute('commerce/collection-membership', collectionMembershipHandler)\n // A site member's password help (AGL-914) and removal (AGL-3308), from the\n // Users page drawer and the Inbox. Console-auth, not the visitor cookie the\n // storefront's `membership/*` routes take, so they are served where the\n // console posts: the console's own dispatcher loads this surface only.\n registerPluginApiRoute(\n 'membership/admin-password',\n membershipAdminPasswordHandler,\n )\n registerPluginApiRoute('membership/admin-remove', membershipAdminRemoveHandler)\n registerPluginApiRoute('commerce/member-post', memberPostHandler)\n registerPluginApiRoute('commerce/pos-order', posOrderHandler)\n // A register's cloud receipt printers and the jobs a manager sends them\n // (AGL-3619), and the two doors the printers themselves poll. The doors are\n // MACHINE routes: a printer is no member and names no site cookie, so it\n // authenticates with the per-printer secret in its URL and its own device id,\n // and the route asks the plan before it hands over a job. Loaded with the\n // first poll, so a console that has no printers never imports them.\n registerPluginApiRoute('commerce/printers', printersHandler)\n registerPluginApiRoute(\n 'commerce/cloudprnt/:hostId/:printerId/:secret',\n {\n web: async (request, context) =>\n (await import('./server/printer-poll')).cloudPrntRoute(request, context),\n },\n { machine: true },\n )\n registerPluginApiRoute(\n 'commerce/epson-sdp/:hostId/:printerId/:secret',\n {\n web: async (request, context) =>\n (await import('./server/printer-poll')).epsonServerDirectPrintRoute(request, context),\n },\n { machine: true },\n )\n // The register's tenders against an open sale, its Stripe Terminal card\n // readers, and the paired customer display (AGL-3607, AGL-3608). The\n // display's `pair`/`poll`/`respond` take a display token and no console\n // session; every other action is gated like a sale.\n registerPluginApiRoute('commerce/pos-payment', posPaymentHandler)\n registerPluginApiRoute('commerce/pos-readers', posReadersHandler)\n registerPluginApiRoute('commerce/pos-display', posDisplayHandler)\n // The POS hardware shop (AGL-4038): the Hardware card's catalog, Checkout\n // and order list, gated like a sale and hidden until the deployment prices\n // it; and the staff page's orders, which name no site. Loaded on first call.\n registerPluginApiRoute('commerce/pos-hardware', async (req, res) =>\n (await import('./server/pos-hardware')).posHardwareHandler(req, res),\n )\n // Selling a card reader in person at the platform's own store's register\n // (AGL-4038): whether this store is that seller. Gated like a sale, and\n // silent about the configuration on every other store. Loaded on first call.\n registerPluginApiRoute('commerce/pos-hardware-sale', async (req, res) =>\n (await import('./server/pos-hardware-sale')).posHardwareSaleHandler(req, res),\n )\n // A store's card reader start-up screen (AGL-4048): the POS devices card's\n // setting, gated like a sale, and the staff page's platform default. Each\n // loads with its first call; the drawing they ask for is the images\n // route's, below.\n registerPluginApiRoute('commerce/pos-reader-splash', async (req, res) =>\n (await import('./server/pos-reader-splash')).posReaderSplashHandler(req, res),\n )\n registerPluginApiRoute('commerce/admin/reader-splash', {\n web: async (request) =>\n (await import('./server/pos-reader-splash-admin')).posReaderSplashAdmin(request),\n })\n // The image work behind both (AGL-4048): drawing a screen and reading an\n // uploaded one take `sharp`, whose native library only the console's\n // plugins' image function ships (`/api/plugin-images/…`), so the plugin\n // API's function does not carry it. Called by our own servers, signed; a\n // machine's door.\n registerPluginApiRoute(\n 'commerce/pos-reader-splash-images',\n {\n web: async (request) =>\n (await import('./server/pos-reader-splash-images-route')).posReaderSplashImagesRoute(request),\n },\n { machine: true, images: true },\n )\n registerPluginApiRoute('commerce/admin/hardware-orders', {\n web: async (request) =>\n (await import('./server/pos-hardware-admin')).posHardwareAdminOrders(request),\n })\n // The self-service kiosk (AGL-3623): a register's paired screen where the\n // customer orders and pays. Its device token, never a staff session; the\n // register's queue of \"pay at counter\" orders is gated like a sale.\n registerPluginApiRoute('commerce/pos-kiosk', posKioskHandler)\n // Shifts, staff PINs, the customer lookup and returns (AGL-3609).\n registerPosOpsRoutes()\n // The offline register (AGL-3625): the kit a register caches to sell cash\n // while the connection is down, and the sync that records those sales once.\n // Gated like a sale; loaded with its first call.\n registerPluginApiRoute('commerce/pos-offline-sync', async (req, res) =>\n (await import('./server/pos-offline-sync')).posOfflineSyncHandler(req, res),\n )\n // The native Aglyn POS app's Stripe Terminal SDK: a connection token scoped\n // to the site's Location, and the Location itself (AGL-3618). Gated like a\n // sale.\n registerPluginApiRoute('commerce/pos-terminal-connection-token', posTerminalConnectionTokenHandler)\n registerPluginApiRoute('commerce/process-abandoned', processAbandonedHandler)\n registerPluginApiRoute('commerce/process-restock', processRestockHandler)\n registerPluginApiRoute('commerce/refund', refundHandler)\n // Returns (AGL-3611): approve, decline, receive with restock, refund\n // through the route above, a label from a shipping plugin.\n registerPluginApiRoute('commerce/returns', returnsHandler)\n // The merchant's outbound order webhooks (AGL-3611): endpoints, secrets,\n // a test ping and a resend from the delivery log.\n registerPluginApiRoute('commerce/order-webhooks', orderWebhooksHandler)\n registerPluginApiRoute('commerce/supplier-update', supplierUpdateHandler)\n // Stamps the open orders that predate the shipping fields, before an\n // export for shipping (AGL-3613).\n registerPluginApiRoute('commerce/orders-shipping-prepare', async (req, res) =>\n (await import('./server/orders-shipping-prepare')).ordersShippingPrepareHandler(req, res),\n )\n // ShipStation's Custom Store endpoint (AGL-3613): ShipStation's servers\n // pull the order feed and post shipments back with the site's own Basic\n // credentials, so it is a MACHINE's route and asks the site's commerce,\n // plan, release and lockdown gates itself once the credentials prove the\n // site. Loaded on its first call, never with the console API surface.\n registerPluginApiRoute(\n 'commerce/shipstation/:hostId',\n {\n web: async (request, context) =>\n (await import('./server/shipstation')).shipStationRoute(request, context),\n },\n { machine: true },\n )\n // ShippingEasy's shipment callback (AGL-3633): ShippingEasy's servers post\n // each label bought for an order this store sent them, signed with the\n // merchant's own API secret, so it is a MACHINE's route like ShipStation's\n // above and asks the same gates once the signature proves the site.\n registerPluginApiRoute(\n 'commerce/shippingeasy/:hostId',\n {\n web: async (request, context) =>\n (await import('./server/shippingeasy')).shippingEasyRoute(request, context),\n },\n { machine: true },\n )\n // The ShipStation and ShippingEasy cards' connect, show, new password,\n // send open orders and disconnect.\n registerPluginApiRoute('commerce/shipping-connectors', async (req, res) =>\n (await import('./server/shipping-connectors')).shippingConnectorsHandler(req, res),\n )\n // The store's sales as figure tables (AGL-2915), for the AI plugin's\n // insights to read by id rather than by reading orders. The console runs\n // insight jobs, so the console surface registers them.\n registerOrderFigureReaders(() => firebaseAdmin.app().firestore())\n}\n\n// Shared with the (still app-side) membership/account route.\nexport { mintDownloadToken } from './server/download'\n\n// Site-member session primitives, shared with the (still app-side)\n// membership/* routes until those migrate too (AGL-396).\nexport * from './server/membership'\n\n// Type-only (AGL-3080): the plugin's entitlement keys, declared by module\n// augmentation, for every program that loads this entry point.\nexport type { commercePlanEntitlements } from './plan-entitlements'\n"],"names":["registerBillingWebhookHandler","registerPluginApiRoute","registerPluginJob","registerSitePageEnricher","registerSitePageResolver","registerPluginPermissions","registerPluginConfigSchema","isEmailConfigured","firebaseAdmin","BUNDLE_ID","registerCommerceMediaPublishGuard","registerCommerceRecurringCharges","registerProductCardReader","registerProductAiCapability","registerStoreSetupAiCapabilities","registerStoreSetupAiWriter","registerProductDraftWriter","registerCommerceTaxProfile","registerTaxReturnSource","commerceTaxReturnSource","taxSummaryHandler","registerRevenueSource","commerceRevenueSource","commerceBillingWebhookHandler","registerOrderFigureReaders","COMMERCE_PERMISSIONS","COMMERCE_CONFIG_SCHEMA","commerceSitePageEnricher","commerceSitePageResolver","cartCheckoutHandler","cartHandler","cartExtrasHandler","catalogHandler","checkoutHandler","downloadHandler","newsletterHandler","notifyRestockHandler","productHandler","relatedHandler","reservationAvailabilityHandler","gateHandler","memberFeedHandler","membershipAccountHandler","membershipAdminPasswordHandler","membershipAdminRemoveHandler","membershipContentHandler","membershipLoginHandler","membershipLogoutHandler","membershipRecoverHandler","membershipRegisterHandler","membershipResetHandler","membershipWishlistHandler","reserveHandler","streamHandler","subscriptionPortalHandler","reviewsHandler","connectHandler","cancelOrderHandler","carrierRatesAvailabilityHandler","collectionMembershipHandler","draftOrderHandler","fulfillOrderHandler","orderReceiptSendHandler","orderStatusHandler","registerOrderStatusActions","returnRequestStatusAction","giftCardsHandler","memberPostHandler","orderAnalyticsHandler","checkoutStatusHandler","posOrderHandler","printersHandler","posPaymentHandler","posReadersHandler","posTerminalConnectionTokenHandler","posDisplayHandler","posKioskHandler","registerPosOpsRoutes","processAbandonedHandler","scanAbandonedCheckouts","processRestockHandler","scanRestockAlerts","scanStockDecrements","refundHandler","orderWebhooksHandler","returnRequestHandler","returnsHandler","scanSupplierDeliveries","supplierUpdateHandler","RECOVERY_JOB_INTERVAL_MINUTES","pluginId","name","intervalMinutes","description","lockdown","scope","handler","gate","sent","console","info","scanReviewRequests","scan","missingLines","truncatedHosts","warn","hosts","reportedOrders","deadLettered","process","env","STRIPE_SECRET_KEY","reconcileCustomDomains","result","registered","failed","POS_CELLULAR_MONTHLY_COST_CENTS","runPosCellularBilling","report","workspaces","storesGone","warned","turnedOff","paidLate","month","paid","open","unbillable","deferred","refreshPosReaderSplashes","applied","more","scanUnsyncedOfflineCards","alerted","CARD_PAYMENT_DOOR","cardPayment","quotePayDoor","req","res","quotePayHandler","registerCommerceApi","localFulfillmentOptionsHandler","web","request","legacyFeedRoute","recipientLink","quoteViewHandler","registerCommerceConsoleApi","event","posHardwareBillingWebhookHandler","posOfflineCardBillingWebhookHandler","quoteHandler","localFulfillmentHandler","productSaveHandler","productStockHandler","reservationWalkInHandler","reservationGuestsHandler","productDuplicateHandler","productDeleteHandler","orderNoteHandler","orderRestockAnswerHandler","orderPrintHandler","paymentMethodsHandler","context","cloudPrntRoute","machine","epsonServerDirectPrintRoute","posHardwareHandler","posHardwareSaleHandler","posReaderSplashHandler","posReaderSplashAdmin","posReaderSplashImagesRoute","images","posHardwareAdminOrders","posOfflineSyncHandler","ordersShippingPrepareHandler","shipStationRoute","shippingEasyRoute","shippingConnectorsHandler","app","firestore","mintDownloadToken"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../libs/plugins/commerce/src/lib/server.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n/**\n * Server half of the commerce plugin (AGL-396): the site-facing storefront\n * API handlers, registered with the plugin API registry and served by the\n * tenant dispatcher at their unchanged `/api/commerce/*` URLs. This module\n * pulls in firebase-admin + Stripe, so it is NOT re-exported from the client\n * barrel — apps import `@aglyn/plugins-commerce/server` only from their\n * (server-only) API dispatcher registration.\n */\n\nimport {\n registerBillingWebhookHandler,\n registerPluginApiRoute,\n registerPluginJob,\n registerSitePageEnricher,\n registerSitePageResolver,\n registerPluginPermissions,\n registerPluginConfigSchema,\n type PluginApiHandler,\n} from '@aglyn/aglyn/server'\nimport { isEmailConfigured } from '@aglyn/shared-util-email'\nimport { firebaseAdmin } from '@aglyn/tenant-data-admin'\nimport { BUNDLE_ID } from './constants/bundle-common'\nimport { registerCommerceMediaPublishGuard } from './server/media-publish-guard'\nimport { registerCommerceRecurringCharges } from './server/recurring-charges'\nimport { registerProductCardReader } from './server/product-card'\nimport { registerProductAiCapability } from './server/product-ai-capability'\nimport { registerStoreSetupAiCapabilities } from './server/store-setup-ai-capability'\nimport { registerStoreSetupAiWriter } from './server/store-setup-ai-writer.console'\nimport { registerProductDraftWriter } from './server/product-drafts'\nimport { registerCommerceTaxProfile } from './server/tax-profile'\nimport { registerTaxReturnSource } from '@aglyn/aglyn/plugin-manager/plugin-tax-return-sources'\nimport { commerceTaxReturnSource } from './server/tax-return-source'\nimport { taxSummaryHandler } from './server/tax-summary'\nimport { registerRevenueSource } from '@aglyn/aglyn/plugin-manager/plugin-revenue-sources'\nimport { commerceRevenueSource } from './server/revenue-source'\nimport { commerceBillingWebhookHandler } from './server/billing-webhook'\nimport { registerOrderFigureReaders } from './server/order-figures'\nimport { COMMERCE_PERMISSIONS } from './model/plugin-permissions'\nimport { COMMERCE_CONFIG_SCHEMA } from './plugin-config'\nimport { commerceSitePageEnricher } from './server/site-page-enricher'\nimport { commerceSitePageResolver } from './server/site-page-resolver'\nimport { cartCheckoutHandler } from './server/cart-checkout'\nimport { cartHandler } from './server/cart'\nimport { cartExtrasHandler } from './server/checkout-extras'\nimport { catalogHandler } from './server/catalog'\nimport { checkoutHandler } from './server/checkout'\nimport { downloadHandler } from './server/download'\nimport { newsletterHandler } from './server/newsletter'\nimport { notifyRestockHandler } from './server/notify-restock'\nimport { productHandler } from './server/product'\nimport { relatedHandler } from './server/related'\nimport { reservationAvailabilityHandler } from './server/reservation-availability'\nimport { gateHandler } from './server/gate'\nimport { memberFeedHandler } from './server/member-feed'\nimport { membershipAccountHandler } from './server/membership-account'\nimport { membershipAdminPasswordHandler } from './server/membership-admin-password'\nimport { membershipAdminRemoveHandler } from './server/membership-admin-remove'\nimport { membershipContentHandler } from './server/membership-content'\nimport { membershipLoginHandler } from './server/membership-login'\nimport { membershipLogoutHandler } from './server/membership-logout'\nimport { membershipRecoverHandler } from './server/membership-recover'\nimport { membershipRegisterHandler } from './server/membership-register'\nimport { membershipResetHandler } from './server/membership-reset'\nimport { membershipWishlistHandler } from './server/membership-wishlist'\nimport { reserveHandler } from './server/reserve'\nimport { streamHandler } from './server/stream'\nimport { subscriptionPortalHandler } from './server/subscription-portal'\nimport { reviewsHandler } from './server/reviews'\nimport { connectHandler } from './server/connect'\nimport { cancelOrderHandler } from './server/cancel-order'\nimport { carrierRatesAvailabilityHandler } from './server/carrier-rates-availability'\nimport { collectionMembershipHandler } from './server/collection-membership'\nimport { draftOrderHandler } from './server/draft-order'\nimport { fulfillOrderHandler } from './server/fulfill-order'\nimport { orderReceiptSendHandler } from './server/order-receipt-send'\nimport { orderStatusHandler, registerOrderStatusActions } from './server/order-status'\nimport { returnRequestStatusAction } from './server/return-status-action'\nimport { giftCardsHandler } from './server/gift-cards'\nimport { memberPostHandler } from './server/member-post'\nimport { orderAnalyticsHandler } from './server/order-analytics'\nimport { checkoutStatusHandler } from './server/checkout-status'\nimport { posOrderHandler } from './server/pos-order'\nimport { printersHandler } from './server/printers'\nimport { posPaymentHandler } from './server/pos-payment'\nimport { posReadersHandler } from './server/pos-readers'\nimport { posTerminalConnectionTokenHandler } from './server/pos-terminal-connection-token'\nimport { posDisplayHandler } from './server/pos-display'\nimport { posKioskHandler } from './server/pos-kiosk'\nimport { registerPosOpsRoutes } from './server/pos-ops-routes'\nimport {\n processAbandonedHandler,\n scanAbandonedCheckouts,\n} from './server/process-abandoned'\nimport { processRestockHandler, scanRestockAlerts } from './server/process-restock'\nimport { scanStockDecrements } from './server/reconcile-stock'\nimport { refundHandler } from './server/refund'\nimport { orderWebhooksHandler } from './server/order-webhooks'\nimport { returnRequestHandler, returnsHandler } from './server/returns'\nimport { scanSupplierDeliveries } from './server/supplier-outbox'\nimport { supplierUpdateHandler } from './server/supplier-update'\n\n/**\n * The two commerce beats (AGL-2227).\n *\n * `commerce/process-abandoned` and `commerce/process-restock` have existed\n * since AGL-323/326 as `x-cron-secret` HTTP doors, and `registerCommerceConsoleApi`\n * below has called them \"the scheduler-driven jobs\" in a comment that whole\n * time. **Nothing scheduled them.** Not `scheduled-crons.yml` (its table names\n * 11 paths; neither of these), not `vercel.json` (no `crons` key at all), not\n * `registerPluginJob` — the only two registrations in the repo were scheduled\n * publishing and the bookings hold-expiry.\n *\n * The cost was a Pro-tier entitlement (`abandonedCart`) that had never sent an\n * email, and a storefront \"notify me when it's back\" form writing into a queue\n * with no drain. AGL-1793 had already added the collection-group indexes these\n * two scans need, which is the clearest evidence they were always meant to run.\n *\n * Module scope, like the bookings job beside it: the runner route reaches jobs\n * through `ensureAll(['tenantApi'])`, and a registration inside a `register*`\n * function would depend on which entry point happened to be loaded.\n *\n * 15 minutes, not 1: `process-abandoned` will not remind a checkout younger\n * than an hour and `process-restock` only mails alerts whose product already\n * has stock, so a tighter beat buys nothing and costs two collection-group\n * scans a minute. Both are bounded (200 docs) and idempotent — each pass\n * stamps what it sent — so an overlapping or repeated beat cannot double-send.\n */\nconst RECOVERY_JOB_INTERVAL_MINUTES = 15\n\nregisterPluginJob({\n pluginId: BUNDLE_ID,\n name: 'abandoned-checkout-recovery',\n intervalMinutes: RECOVERY_JOB_INTERVAL_MINUTES,\n description:\n 'Email one recovery reminder per stalled checkout (abandonedCart plans).',\n lockdown: { scope: 'per-host' },\n handler: async (gate) => {\n // Quietly, not as an error: email is optional per deployment, and a beat\n // that logs every minute on a self-host without Resend buries everything\n // else in the log.\n if (!isEmailConfigured()) return\n const { sent } = await scanAbandonedCheckouts(gate)\n if (sent) console.info(`commerce: sent ${sent} abandoned-cart reminders`)\n },\n})\n\nregisterPluginJob({\n pluginId: BUNDLE_ID,\n name: 'back-in-stock-alerts',\n intervalMinutes: RECOVERY_JOB_INTERVAL_MINUTES,\n description: 'Email shoppers whose requested product is in stock again.',\n lockdown: { scope: 'per-host' },\n handler: async (gate) => {\n if (!isEmailConfigured()) return\n const { sent } = await scanRestockAlerts(gate)\n if (sent) console.info(`commerce: sent ${sent} back-in-stock alerts`)\n },\n})\n\n/**\n * The review-request email (AGL-3736). HOURLY: a request is owed days after\n * fulfilment, so an hour's lateness is invisible, and the scan is one\n * collection-group range query over `reviewRequestDueAtMs` — a field only\n * orders still owed a request carry, so an empty beat costs one read.\n */\nregisterPluginJob({\n pluginId: BUNDLE_ID,\n name: 'review-request-emails',\n intervalMinutes: 60,\n description:\n 'Email each buyer one review request, with a single-use link per product, ' +\n 'days after their order is fulfilled (AGL-3736).',\n lockdown: { scope: 'per-host' },\n handler: async (gate) => {\n if (!isEmailConfigured()) return\n const { scanReviewRequests } = await import('./server/review-requests')\n const { sent } = await scanReviewRequests(gate)\n if (sent) console.info(`commerce: sent ${sent} review requests`)\n },\n})\n\n/**\n * The missing-decrement detector (AGL-2358).\n *\n * HOURLY, not on the 15-minute recovery beat: it is a detector for a rare\n * process death, not a queue drain, and nothing it finds gets less true for\n * waiting an hour. The cost of the beat is what sets the interval — one\n * collection-group read of the platform's most recent orders, plus two\n * queries per host that has any — and an hour keeps that off the same tick as\n * the two scans above.\n *\n * NOT gated on `isEmailConfigured()`, unlike its two neighbours. Those send\n * mail; this writes a console notification and a log line, both of which work\n * on a self-host with no mail provider at all — and a stock count that is\n * silently wrong is exactly what a self-hoster least wants suppressed by a\n * setting about email.\n */\nregisterPluginJob({\n pluginId: BUNDLE_ID,\n name: 'stock-decrement-reconciliation',\n intervalMinutes: 60,\n description:\n 'Report paid orders whose stock decrement never landed (AGL-2358).',\n lockdown: { scope: 'per-host' },\n handler: async (gate) => {\n const scan = await scanStockDecrements(gate)\n if (scan.missingLines || scan.truncatedHosts) {\n console.warn(\n `commerce: ${scan.missingLines} order lines across ${scan.hosts} ` +\n `sites have no sale ledger row (${scan.reportedOrders} newly ` +\n `reported, ${scan.truncatedHosts} sites' ledger window truncated)`,\n )\n }\n },\n})\n\n/**\n * The dropship supplier outbox drain (AGL-2473).\n *\n * EVERY MINUTE, unlike the three above, and the interval is the point rather\n * than an oversight. This is the only one of the four that a BUYER is waiting\n * on: the row it drains is a paid order that has not been routed to whoever\n * ships it, and every minute it sits is a minute the parcel is not moving. The\n * first backoff step is also 60s, so a supplier that blipped is retried on the\n * next tick.\n *\n * The cost that set fifteen minutes for the recovery pair does not apply. Those\n * are collection-GROUP scans across every site on the platform; this is one\n * ordinary equality query against a top-level collection that is EMPTY in the\n * ordinary case — an empty result bills a single read, so the whole beat is\n * ~1,440 reads a day whether or not anyone is dropshipping.\n *\n * Not gated on `isEmailConfigured()`. The supplier notification is an HTTP POST\n * to the merchant's own supplier, and a self-host with no mail provider still\n * has dropship orders to route.\n */\nregisterPluginJob({\n pluginId: BUNDLE_ID,\n name: 'supplier-webhook-delivery',\n intervalMinutes: 1,\n description:\n 'Deliver queued dropship supplier notifications, with backoff and a ' +\n 'dead letter that tells the merchant (AGL-2473).',\n lockdown: { scope: 'per-host' },\n handler: async (gate) => {\n const scan = await scanSupplierDeliveries(gate)\n if (scan.deadLettered) {\n console.warn(\n `commerce: ${scan.deadLettered} dropship orders could not be routed ` +\n `to their supplier and have been reported on the order`,\n )\n }\n },\n})\n\n/**\n * Stripe payment method domains for every connected custom domain (AGL-3629).\n *\n * The backfill for domains connected before registration existed, and the\n * repair for a connect whose event was lost, in one daily pass. A domain\n * already registered costs a document read and no Stripe call, so the beat is\n * cheap; a day's delay costs only the Apple Pay button on a domain connected\n * while Stripe was unreachable, and the first in-page checkout there registers\n * it anyway.\n */\nregisterPluginJob({\n pluginId: BUNDLE_ID,\n name: 'payment-method-domains',\n intervalMinutes: 24 * 60,\n description:\n 'Register connected custom domains with Stripe so Apple Pay, Google Pay ' +\n 'and Link show on them (AGL-3629).',\n lockdown: { scope: 'per-host' },\n handler: async (gate) => {\n if (!process.env.STRIPE_SECRET_KEY) return\n const { reconcileCustomDomains } = await import('./server/payment-method-domains')\n const result = await reconcileCustomDomains(gate)\n if (result.registered || result.failed) {\n console.info(\n `commerce: payment method domains — ${result.registered} registered, ` +\n `${result.failed} failed across ${result.hosts} sites`,\n )\n }\n },\n})\n\n/**\n * The monthly 4G charge for Stripe Reader S710s (AGL-4038): each workspace\n * whose readers had 4G in the month just ended is charged once, through\n * core's usage-invoice charge. Every six hours, so the charge goes out early\n * on the 1st and one that could not reach Stripe is tried again the same\n * day; a month already settled costs a read per workspace. Nothing runs\n * where 4G is not offered (`POS_CELLULAR_MONTHLY_COST_CENTS` unset).\n * Per-host: a store locked for security or abuse is not charged while it is.\n */\nregisterPluginJob({\n pluginId: BUNDLE_ID,\n name: 'pos-cellular-billing',\n intervalMinutes: 6 * 60,\n description:\n 'Charge each workspace for 4G on its Stripe Reader S710s for the month just ended, once (AGL-4038).',\n lockdown: { scope: 'per-host' },\n handler: async (gate) => {\n if (!process.env.STRIPE_SECRET_KEY || !process.env.POS_CELLULAR_MONTHLY_COST_CENTS) return\n const { runPosCellularBilling } = await import('./server/pos-cellular-billing')\n const report = await runPosCellularBilling(gate)\n if (report.workspaces || report.storesGone || report.warned || report.turnedOff || report.paidLate) {\n console.info(\n `commerce: 4G for ${report.month} — ${report.paid} paid, ${report.open} left open, ` +\n `${report.failed} not reached, ${report.unbillable} not billable, ${report.deferred} deferred, ` +\n `${report.storesGone} deleted stores turned off; unpaid charges: ${report.warned} warned, ` +\n `${report.paidLate} paid since, ${report.turnedOff} turned off`,\n )\n }\n },\n})\n\n/**\n * Card reader start-up screens (AGL-4048) that went stale with nobody opening\n * the POS devices card: a logo changed on the organization profile or the\n * white-label brand, or the logo's file replaced in the media library. Every\n * 15 minutes, like the recovery pair: a store whose screen did not move costs\n * a few reads and no Stripe call, and nothing a merchant saves waits on it.\n * A screen Stripe refused is retried after six hours here, and at once when\n * the card is opened.\n */\nregisterPluginJob({\n pluginId: BUNDLE_ID,\n name: 'pos-reader-splash-refresh',\n intervalMinutes: RECOVERY_JOB_INTERVAL_MINUTES,\n description:\n 'Bring card reader start-up screens up to date after a logo change (AGL-4048).',\n lockdown: { scope: 'per-host' },\n handler: async (gate) => {\n if (!process.env.STRIPE_SECRET_KEY) return\n const { refreshPosReaderSplashes } = await import('./server/pos-reader-splash')\n const result = await refreshPosReaderSplashes(gate)\n if (result.applied || result.failed || result.more) {\n console.info(\n `commerce: reader start-up screens — ${result.applied} updated, ` +\n `${result.failed} failed${result.more ? ', more stores than one pass reaches' : ''}`,\n )\n }\n },\n})\n\n/**\n * Cards taken offline whose sale never synced (AGL-4039).\n *\n * HOURLY. The alert falls due six hours after the intent was first seen, and\n * Stripe's authorization lasts about two days, so an hour's delay costs\n * nothing and leaves the beat one collection-group range read that is empty in\n * the ordinary case. It never captures: without the sale there is no fee to\n * capture with, so it tells the operator and the site's managers instead.\n *\n * Not gated on `isEmailConfigured()`: the console notification and the\n * operator alert both work without mail.\n */\nregisterPluginJob({\n pluginId: BUNDLE_ID,\n name: 'offline-card-unsynced',\n intervalMinutes: 60,\n description:\n 'Tell the operator and the site when a card taken offline reached Stripe but its sale never synced (AGL-4039).',\n lockdown: { scope: 'per-host' },\n handler: async (gate) => {\n const { scanUnsyncedOfflineCards } = await import('./server/pos-offline-card-reconcile')\n const scan = await scanUnsyncedOfflineCards(gate)\n if (scan.alerted) {\n console.warn(`commerce: ${scan.alerted} cards taken offline have no synced sale`)\n }\n },\n})\n\n/**\n * A visitor's payment door: it opens a Stripe Checkout Session for whoever\n * calls it, so the dispatcher holds it to the card-testing counters\n * (AGL-3363). Declared here, beside the registration, so the door cannot\n * exist without it.\n */\nconst CARD_PAYMENT_DOOR = { cardPayment: true } as const\n\n/**\n * The quote page's Pay button (AGL-4094): a fresh Checkout Session for a\n * quote, for whoever holds its signed pay link. Loaded on first call.\n */\nconst quotePayDoor: PluginApiHandler = async (req, res) =>\n (await import('./server/quote-pay')).quotePayHandler(req, res)\n\n/** Registers the commerce plugin's storefront API routes. */\nexport function registerCommerceApi(): void {\n registerProductCardReader()\n // The merchant's tax rule, for every plugin that prices a charge here.\n registerCommerceTaxProfile()\n registerPluginPermissions(COMMERCE_PERMISSIONS)\n // Merchant-settable register discount ceiling (AGL-2161). Registered on\n // BOTH surfaces, like the permissions above: the POS route reads it\n // server-side, and the settings card renders it from the same schema.\n registerPluginConfigSchema(COMMERCE_CONFIG_SCHEMA)\n // PDP/PLP template pages (AGL-418): /products/* + /collections/*.\n registerSitePageResolver(commerceSitePageResolver)\n // Seeds product grids on ordinary screens (AGL-659) — the resolver above\n // only covers /products/* and /collections/*, so /products itself, and any\n // designed page with a grid on it, needed this to render server-side.\n registerSitePageEnricher(commerceSitePageEnricher)\n registerPluginApiRoute('commerce/cart-checkout', cartCheckoutHandler, CARD_PAYMENT_DOOR)\n registerPluginApiRoute('commerce/cart', cartHandler)\n // What the cart offers besides shipping (AGL-3624): pickup locations, and\n // local delivery's fee, minimum and windows for a postal code.\n registerPluginApiRoute('commerce/local-fulfillment-options', async (req, res) =>\n (await import('./server/local-fulfillment')).localFulfillmentOptionsHandler(req, res),\n )\n // Optional lines another plugin offers at the cart (AGL-3635).\n registerPluginApiRoute('commerce/cart-extras', cartExtrasHandler)\n registerPluginApiRoute('commerce/catalog', catalogHandler)\n registerPluginApiRoute('commerce/checkout', checkoutHandler, CARD_PAYMENT_DOOR)\n registerPluginApiRoute('commerce/download', downloadHandler)\n // The pre-channels Google feed address (AGL-299), now written by the\n // catalog's feed publisher (AGL-3637); the module loads with a fetch.\n registerPluginApiRoute('commerce/feed', {\n web: async (request) => (await import('./server/legacy-feed')).legacyFeedRoute(request),\n })\n registerPluginApiRoute('commerce/newsletter', newsletterHandler)\n registerPluginApiRoute('commerce/notify-restock', notifyRestockHandler)\n // GA-safe order projection for the storefront `purchase` (AGL-1641).\n registerPluginApiRoute('commerce/order-analytics', orderAnalyticsHandler)\n // The guest order-status page's data (AGL-3610), behind the signed link in\n // every buyer email — a recipient link, so it outlives the site's gates.\n registerPluginApiRoute('commerce/order-status', orderStatusHandler, { recipientLink: true })\n // …and its \"Request a return\" button (AGL-3611), on an order that can\n // still send something back.\n registerOrderStatusActions(returnRequestStatusAction)\n // The customer's quote page (AGL-4094), behind the signed pay link a\n // business sends: the quote, and its Pay button. The page's data is a\n // recipient link, so it outlives the site's gates like the order status.\n registerPluginApiRoute(\n 'commerce/quote-view',\n async (req, res) => (await import('./server/quote-pay')).quoteViewHandler(req, res),\n { recipientLink: true },\n )\n registerPluginApiRoute('commerce/quote-pay', quotePayDoor, CARD_PAYMENT_DOOR)\n // The quote as a PDF (AGL-4095), by the same signed link and on the same\n // terms as the page's data. Loaded on first call, with sharp and the PDF\n // writer behind it.\n registerPluginApiRoute(\n 'commerce/quote-pdf',\n async (req, res) => (await import('./server/commerce-pdf')).quotePdfHandler(req, res),\n { recipientLink: true },\n )\n // The quote's proofs (AGL-4096), by the same signed link and on the same\n // terms as the page's data; and the customer's answer to them, with any\n // artwork they send through the shared visitor upload. The two writes are\n // ordinary visitor writes: the dispatcher's cross-origin check, lockdown\n // and visitor-write limit stand in front of their own. Loaded on first call.\n registerPluginApiRoute(\n 'commerce/quote-proof',\n async (req, res) => (await import('./server/quote-proofs')).quoteProofHandler(req, res),\n { recipientLink: true },\n )\n registerPluginApiRoute('commerce/quote-upload', async (req, res) =>\n (await import('./server/quote-proofs')).quoteUploadHandler(req, res),\n )\n registerPluginApiRoute('commerce/quote-respond', async (req, res) =>\n (await import('./server/quote-proofs')).quoteRespondHandler(req, res),\n )\n // What became of a session the shopper was returned from (AGL-3606).\n registerPluginApiRoute('commerce/checkout-status', checkoutStatusHandler)\n registerPluginApiRoute('commerce/product', productHandler)\n registerPluginApiRoute('commerce/related', relatedHandler)\n registerPluginApiRoute('commerce/reservation-availability', reservationAvailabilityHandler)\n registerPluginApiRoute('commerce/reserve', reserveHandler, CARD_PAYMENT_DOOR)\n registerPluginApiRoute('commerce/gate', gateHandler)\n registerPluginApiRoute('commerce/member-feed', memberFeedHandler)\n registerPluginApiRoute('commerce/stream', streamHandler)\n registerPluginApiRoute('commerce/subscription-portal', subscriptionPortalHandler)\n registerPluginApiRoute('commerce/reviews', reviewsHandler)\n // A buyer's return request (AGL-3611), from their account or the signed\n // order-status link.\n registerPluginApiRoute('commerce/return-request', returnRequestHandler)\n registerPluginApiRoute('membership/account', membershipAccountHandler)\n registerPluginApiRoute('membership/content', membershipContentHandler)\n registerPluginApiRoute('membership/login', membershipLoginHandler)\n registerPluginApiRoute('membership/logout', membershipLogoutHandler)\n // Password recovery pair (AGL-552): request + complete.\n registerPluginApiRoute('membership/recover', membershipRecoverHandler)\n registerPluginApiRoute('membership/register', membershipRegisterHandler)\n registerPluginApiRoute('membership/reset', membershipResetHandler)\n registerPluginApiRoute('membership/wishlist', membershipWishlistHandler)\n}\n\n/**\n * Registers the commerce plugin's console-side API routes (AGL-396):\n * merchant/staff operations (Connect onboarding, refunds, draft & POS\n * orders, member posts), the supplier tracking callback, and the HTTP doors\n * for the abandoned-cart / restock passes.\n *\n * Those last two are NOT what schedules them — the `registerPluginJob` calls\n * above are (AGL-2227). This comment used to call them \"the scheduler-driven\n * jobs\", which is how they stayed dark for months: it asserted the wiring\n * instead of having it.\n */\nexport function registerCommerceConsoleApi(): void {\n // The register's gate (`managePos`) is resolved on THIS surface: every POS\n // route below runs in the console, and a key no surface registered here is\n // absent from the resolved map, which reads as refused — the site's own\n // owner was answered 403 at the register.\n registerPluginPermissions(COMMERCE_PERMISSIONS)\n // What a product looks like to a surface that is not this plugin's — a\n // campaign email that features one asks here rather than importing the model.\n registerProductCardReader()\n // …and a draft product another plugin asks for by name (AGL-3616): an AI\n // build setting a store up from a brief, unpriced unless the brief priced it.\n // The console runs AI jobs (AGL-3026).\n registerProductDraftWriter()\n // …and the operation an AI build plans for it, which that writer executes.\n registerProductAiCapability()\n // …and the store's shipping, pickup, local delivery and tax settings an AI\n // build sets up (AGL-3749), written live as the console's cards write them,\n // with the four operations that writer executes.\n registerStoreSetupAiWriter()\n registerStoreSetupAiCapabilities()\n // …and why a file somebody is SELLING may not be made public (AGL-3080).\n // The media library asks before it hands an asset its permanent CDN URL\n // back; what a product is, and which of its fields hold paid media, is\n // this plugin's to know.\n registerCommerceMediaPublishGuard()\n // …and which memberships a site sells, for a security lockdown to pause\n // (AGL-3364). The lockdown route runs on this surface.\n registerCommerceRecurringCharges()\n // …and the tax rule, for the webhook that confirms what they charged.\n registerCommerceTaxProfile()\n // …and its sales on the operator's own sales tax return (AGL-3080): the\n // tax a storefront checkout collected under the platform's registrations.\n // The staff return awaits this surface before it asks, and refuses to be\n // filed without this source — commerce declares `taxReturnSource`.\n registerTaxReturnSource(commerceTaxReturnSource, { pluginId: BUNDLE_ID })\n // …and the take its orders earn the operator, on the staff revenue report\n // (AGL-3080) — commerce declares `revenueSource`, so the report names this\n // source as unread rather than counting it as zero if it is missing.\n registerRevenueSource(commerceRevenueSource, { pluginId: BUNDLE_ID })\n // Stripe webhook sections (AGL-418): orders/carts/drafts/reservations/\n // subscriptions ride the platform webhook via the hook registry.\n registerBillingWebhookHandler(commerceBillingWebhookHandler)\n // A paid card-reader order from the POS hardware shop (AGL-4038), on the\n // same platform webhook: its own handler, self-selecting on the session's\n // `metadata.type`, so the storefront sections above never see it.\n registerBillingWebhookHandler(async (event) =>\n (await import('./server/pos-hardware-webhook')).posHardwareBillingWebhookHandler(event),\n )\n // A card the Aglyn POS app took offline (AGL-4039): its PaymentIntent can\n // reach Stripe before the sale reaches the server, so every event on one is\n // kept by the sale's key. Self-selecting on `metadata.kind`.\n registerBillingWebhookHandler(async (event) =>\n (await import('./server/pos-offline-card-reconcile')).posOfflineCardBillingWebhookHandler(event),\n )\n // Cancel + stock release in one transaction (AGL-1808). Server-side because\n // the release depends on the transition rule, and a client write could not\n // re-ask it under the same lock that flips the status.\n registerPluginApiRoute('commerce/cancel-order', cancelOrderHandler)\n // Whether live carrier rates can be offered on this site (AGL-3612).\n registerPluginApiRoute('commerce/shipping/carrier-rates', carrierRatesAvailabilityHandler)\n registerPluginApiRoute('commerce/connect', connectHandler)\n registerPluginApiRoute('commerce/draft-order', draftOrderHandler)\n // Quotes (AGL-4093): create, edit and delete a quote, and find the customer\n // it is for, under \"Create and edit quotes\". Loaded on first call.\n registerPluginApiRoute('commerce/quote', async (req, res) =>\n (await import('./server/quote')).quoteHandler(req, res),\n )\n // Send invoice (AGL-4099) for an order or a quote, under \"Send quotes and\n // invoices to customers\": an unpaid one with the order's lasting pay link,\n // a paid one as the record. The email, the PDF and sharp load on first\n // call only.\n registerPluginApiRoute('commerce/order-invoice-send', async (req, res) =>\n (await import('./server/order-invoice-send')).orderInvoiceSendHandler(req, res),\n )\n // Fulfil + mark-delivered with the transition re-asked under the write\n // (AGL-1819) — the same stale-dialog hole cancel-order closes, minus the\n // stock release those two transitions never had. The customer REST API's\n // `PATCH /v1/sites/{id}/orders/{id}` records a shipment through the same\n // transaction (`server/api-v1/orders-and-products.ts`).\n registerPluginApiRoute('commerce/fulfill-order', fulfillOrderHandler)\n // Pickup and local delivery steps (AGL-3624) — ready, picked up, out for\n // delivery, delivered — from the console queue, the order dialog and the\n // native Aglyn app. Loaded on first call.\n registerPluginApiRoute('commerce/local-fulfillment', async (req, res) =>\n (await import('./server/local-fulfillment-status')).localFulfillmentHandler(req, res),\n )\n // \"Resend receipt\" from the order dialog (AGL-3610): by email, or by text\n // when the platform's SMS provider is configured. Rate-limited per member\n // and per order.\n registerPluginApiRoute('commerce/order-receipt-send', orderReceiptSendHandler)\n // The product editor's save and Adjust stock for the native apps (AGL-3652):\n // the console's own product-write computation under the rules' gate. Loaded\n // on first call.\n registerPluginApiRoute('commerce/products/save', async (req, res) =>\n (await import('./server/products-write')).productSaveHandler(req, res),\n )\n registerPluginApiRoute('commerce/products/stock', async (req, res) =>\n (await import('./server/products-write')).productStockHandler(req, res),\n )\n // A staff walk-in from the Reservations card and the native apps\n // (AGL-4046): availability re-asked inside the transaction that writes, so\n // two staff cannot hand out the last unit at once. Loaded on first call.\n registerPluginApiRoute('commerce/reservations/walk-in', async (req, res) =>\n (await import('./server/reservation-walk-in')).reservationWalkInHandler(req, res),\n )\n // A stay's guest count after it is booked (AGL-4043), from the Reservations\n // card and the check-in screen: the walk-in's gate, and the stay's\n // check-ins for today on brought in line in the same transaction. Loaded\n // on first call.\n registerPluginApiRoute('commerce/reservations/guests', async (req, res) =>\n (await import('./server/reservation-guests')).reservationGuestsHandler(req, res),\n )\n // The products list's Duplicate and Delete for the native apps (AGL-3841):\n // the console's own copy and soft delete, with the site-wide cache drop.\n registerPluginApiRoute('commerce/products/duplicate', async (req, res) =>\n (await import('./server/products-write')).productDuplicateHandler(req, res),\n )\n registerPluginApiRoute('commerce/products/delete', async (req, res) =>\n (await import('./server/products-write')).productDeleteHandler(req, res),\n )\n // The order dialog's note and restock answer for the native apps\n // (AGL-3651, AGL-3652): the console's own timeline computation, in one\n // transaction on the stored order. Loaded on first call.\n registerPluginApiRoute('commerce/order-note', async (req, res) =>\n (await import('./server/order-annotations')).orderNoteHandler(req, res),\n )\n registerPluginApiRoute('commerce/order-restock-answer', async (req, res) =>\n (await import('./server/order-annotations')).orderRestockAnswerHandler(req, res),\n )\n // The order dialog's Packing slip and Invoice for the native apps\n // (AGL-3841): the console's own two pages over the stored order, which the\n // apps print on the device's print sheet; and the invoice as a PDF file\n // (`kind=invoice-pdf`, AGL-4095) for the console and the apps. Loaded on\n // first call.\n registerPluginApiRoute('commerce/order-print', async (req, res) =>\n (await import('./server/order-print')).orderPrintHandler(req, res),\n )\n // Issue / void store credit (AGL-2226). Server-side because the host\n // catch-all in the Firestore rules would otherwise let a client write\n // its own `balanceCents`, which checkout applies as amount-off.\n registerPluginApiRoute('commerce/gift-cards', giftCardsHandler)\n // The merchant's own storefront sales tax, by who owes it (AGL-2440): the\n // same rows and classifier the operator's return reads, fenced to one site.\n registerPluginApiRoute('commerce/tax-summary', { web: taxSummaryHandler })\n // The payment methods card (AGL-3629): toggles, the platform's offer, the\n // payout account's capabilities and the site's wallet domains. Loaded with\n // the first request, so a console that never opens Settings never imports it.\n registerPluginApiRoute('commerce/payment-methods', {\n web: async (request) =>\n (await import('./server/payment-methods')).paymentMethodsHandler(request),\n })\n // A smart collection's rules changed or it was deleted: re-stamp which\n // products it holds (AGL-3321), the membership the storefront queries.\n registerPluginApiRoute('commerce/collection-membership', collectionMembershipHandler)\n // A site member's password help (AGL-914) and removal (AGL-3308), from the\n // Users page drawer and the Inbox. Console-auth, not the visitor cookie the\n // storefront's `membership/*` routes take, so they are served where the\n // console posts: the console's own dispatcher loads this surface only.\n registerPluginApiRoute(\n 'membership/admin-password',\n membershipAdminPasswordHandler,\n )\n registerPluginApiRoute('membership/admin-remove', membershipAdminRemoveHandler)\n registerPluginApiRoute('commerce/member-post', memberPostHandler)\n registerPluginApiRoute('commerce/pos-order', posOrderHandler)\n // A register's cloud receipt printers and the jobs a manager sends them\n // (AGL-3619), and the two doors the printers themselves poll. The doors are\n // MACHINE routes: a printer is no member and names no site cookie, so it\n // authenticates with the per-printer secret in its URL and its own device id,\n // and the route asks the plan before it hands over a job. Loaded with the\n // first poll, so a console that has no printers never imports them.\n registerPluginApiRoute('commerce/printers', printersHandler)\n registerPluginApiRoute(\n 'commerce/cloudprnt/:hostId/:printerId/:secret',\n {\n web: async (request, context) =>\n (await import('./server/printer-poll')).cloudPrntRoute(request, context),\n },\n { machine: true },\n )\n registerPluginApiRoute(\n 'commerce/epson-sdp/:hostId/:printerId/:secret',\n {\n web: async (request, context) =>\n (await import('./server/printer-poll')).epsonServerDirectPrintRoute(request, context),\n },\n { machine: true },\n )\n // The register's tenders against an open sale, its Stripe Terminal card\n // readers, and the paired customer display (AGL-3607, AGL-3608). The\n // display's `pair`/`poll`/`respond` take a display token and no console\n // session; every other action is gated like a sale.\n registerPluginApiRoute('commerce/pos-payment', posPaymentHandler)\n registerPluginApiRoute('commerce/pos-readers', posReadersHandler)\n registerPluginApiRoute('commerce/pos-display', posDisplayHandler)\n // The POS hardware shop (AGL-4038): the Hardware card's catalog, Checkout\n // and order list, gated like a sale and hidden until the deployment prices\n // it; and the staff page's orders, which name no site. Loaded on first call.\n registerPluginApiRoute('commerce/pos-hardware', async (req, res) =>\n (await import('./server/pos-hardware')).posHardwareHandler(req, res),\n )\n // Selling a card reader in person at the platform's own store's register\n // (AGL-4038): whether this store is that seller. Gated like a sale, and\n // silent about the configuration on every other store. Loaded on first call.\n registerPluginApiRoute('commerce/pos-hardware-sale', async (req, res) =>\n (await import('./server/pos-hardware-sale')).posHardwareSaleHandler(req, res),\n )\n // A store's card reader start-up screen (AGL-4048): the POS devices card's\n // setting, gated like a sale, and the staff page's platform default. Each\n // loads with its first call; the drawing they ask for is the images\n // route's, below.\n registerPluginApiRoute('commerce/pos-reader-splash', async (req, res) =>\n (await import('./server/pos-reader-splash')).posReaderSplashHandler(req, res),\n )\n registerPluginApiRoute('commerce/admin/reader-splash', {\n web: async (request) =>\n (await import('./server/pos-reader-splash-admin')).posReaderSplashAdmin(request),\n })\n // The image work behind both (AGL-4048): drawing a screen and reading an\n // uploaded one take `sharp`, whose native library only the console's\n // plugins' image function ships (`/api/plugin-images/…`), so the plugin\n // API's function does not carry it. Called by our own servers, signed; a\n // machine's door.\n registerPluginApiRoute(\n 'commerce/pos-reader-splash-images',\n {\n web: async (request) =>\n (await import('./server/pos-reader-splash-images-route')).posReaderSplashImagesRoute(request),\n },\n { machine: true, images: true },\n )\n registerPluginApiRoute('commerce/admin/hardware-orders', {\n web: async (request) =>\n (await import('./server/pos-hardware-admin')).posHardwareAdminOrders(request),\n })\n // The self-service kiosk (AGL-3623): a register's paired screen where the\n // customer orders and pays. Its device token, never a staff session; the\n // register's queue of \"pay at counter\" orders is gated like a sale.\n registerPluginApiRoute('commerce/pos-kiosk', posKioskHandler)\n // Shifts, staff PINs, the customer lookup and returns (AGL-3609).\n registerPosOpsRoutes()\n // The offline register (AGL-3625): the kit a register caches to sell cash\n // while the connection is down, and the sync that records those sales once.\n // Gated like a sale; loaded with its first call.\n registerPluginApiRoute('commerce/pos-offline-sync', async (req, res) =>\n (await import('./server/pos-offline-sync')).posOfflineSyncHandler(req, res),\n )\n // The native Aglyn POS app's Stripe Terminal SDK: a connection token scoped\n // to the site's Location, and the Location itself (AGL-3618). Gated like a\n // sale.\n registerPluginApiRoute('commerce/pos-terminal-connection-token', posTerminalConnectionTokenHandler)\n registerPluginApiRoute('commerce/process-abandoned', processAbandonedHandler)\n registerPluginApiRoute('commerce/process-restock', processRestockHandler)\n registerPluginApiRoute('commerce/refund', refundHandler)\n // Returns (AGL-3611): approve, decline, receive with restock, refund\n // through the route above, a label from a shipping plugin.\n registerPluginApiRoute('commerce/returns', returnsHandler)\n // The merchant's outbound order webhooks (AGL-3611): endpoints, secrets,\n // a test ping and a resend from the delivery log.\n registerPluginApiRoute('commerce/order-webhooks', orderWebhooksHandler)\n registerPluginApiRoute('commerce/supplier-update', supplierUpdateHandler)\n // Stamps the open orders that predate the shipping fields, before an\n // export for shipping (AGL-3613).\n registerPluginApiRoute('commerce/orders-shipping-prepare', async (req, res) =>\n (await import('./server/orders-shipping-prepare')).ordersShippingPrepareHandler(req, res),\n )\n // ShipStation's Custom Store endpoint (AGL-3613): ShipStation's servers\n // pull the order feed and post shipments back with the site's own Basic\n // credentials, so it is a MACHINE's route and asks the site's commerce,\n // plan, release and lockdown gates itself once the credentials prove the\n // site. Loaded on its first call, never with the console API surface.\n registerPluginApiRoute(\n 'commerce/shipstation/:hostId',\n {\n web: async (request, context) =>\n (await import('./server/shipstation')).shipStationRoute(request, context),\n },\n { machine: true },\n )\n // ShippingEasy's shipment callback (AGL-3633): ShippingEasy's servers post\n // each label bought for an order this store sent them, signed with the\n // merchant's own API secret, so it is a MACHINE's route like ShipStation's\n // above and asks the same gates once the signature proves the site.\n registerPluginApiRoute(\n 'commerce/shippingeasy/:hostId',\n {\n web: async (request, context) =>\n (await import('./server/shippingeasy')).shippingEasyRoute(request, context),\n },\n { machine: true },\n )\n // The ShipStation and ShippingEasy cards' connect, show, new password,\n // send open orders and disconnect.\n registerPluginApiRoute('commerce/shipping-connectors', async (req, res) =>\n (await import('./server/shipping-connectors')).shippingConnectorsHandler(req, res),\n )\n // The store's sales as figure tables (AGL-2915), for the AI plugin's\n // insights to read by id rather than by reading orders. The console runs\n // insight jobs, so the console surface registers them.\n registerOrderFigureReaders(() => firebaseAdmin.app().firestore())\n}\n\n// Shared with the (still app-side) membership/account route.\nexport { mintDownloadToken } from './server/download'\n\n// Site-member session primitives, shared with the (still app-side)\n// membership/* routes until those migrate too (AGL-396).\nexport * from './server/membership'\n\n// Type-only (AGL-3080): the plugin's entitlement keys, declared by module\n// augmentation, for every program that loads this entry point.\nexport type { commercePlanEntitlements } from './plan-entitlements'\n"],"names":["registerBillingWebhookHandler","registerPluginApiRoute","registerPluginJob","registerSitePageEnricher","registerSitePageResolver","registerPluginPermissions","registerPluginConfigSchema","isEmailConfigured","firebaseAdmin","BUNDLE_ID","registerCommerceMediaPublishGuard","registerCommerceRecurringCharges","registerProductCardReader","registerProductAiCapability","registerStoreSetupAiCapabilities","registerStoreSetupAiWriter","registerProductDraftWriter","registerCommerceTaxProfile","registerTaxReturnSource","commerceTaxReturnSource","taxSummaryHandler","registerRevenueSource","commerceRevenueSource","commerceBillingWebhookHandler","registerOrderFigureReaders","COMMERCE_PERMISSIONS","COMMERCE_CONFIG_SCHEMA","commerceSitePageEnricher","commerceSitePageResolver","cartCheckoutHandler","cartHandler","cartExtrasHandler","catalogHandler","checkoutHandler","downloadHandler","newsletterHandler","notifyRestockHandler","productHandler","relatedHandler","reservationAvailabilityHandler","gateHandler","memberFeedHandler","membershipAccountHandler","membershipAdminPasswordHandler","membershipAdminRemoveHandler","membershipContentHandler","membershipLoginHandler","membershipLogoutHandler","membershipRecoverHandler","membershipRegisterHandler","membershipResetHandler","membershipWishlistHandler","reserveHandler","streamHandler","subscriptionPortalHandler","reviewsHandler","connectHandler","cancelOrderHandler","carrierRatesAvailabilityHandler","collectionMembershipHandler","draftOrderHandler","fulfillOrderHandler","orderReceiptSendHandler","orderStatusHandler","registerOrderStatusActions","returnRequestStatusAction","giftCardsHandler","memberPostHandler","orderAnalyticsHandler","checkoutStatusHandler","posOrderHandler","printersHandler","posPaymentHandler","posReadersHandler","posTerminalConnectionTokenHandler","posDisplayHandler","posKioskHandler","registerPosOpsRoutes","processAbandonedHandler","scanAbandonedCheckouts","processRestockHandler","scanRestockAlerts","scanStockDecrements","refundHandler","orderWebhooksHandler","returnRequestHandler","returnsHandler","scanSupplierDeliveries","supplierUpdateHandler","RECOVERY_JOB_INTERVAL_MINUTES","pluginId","name","intervalMinutes","description","lockdown","scope","handler","gate","sent","console","info","scanReviewRequests","scan","missingLines","truncatedHosts","warn","hosts","reportedOrders","deadLettered","process","env","STRIPE_SECRET_KEY","reconcileCustomDomains","result","registered","failed","POS_CELLULAR_MONTHLY_COST_CENTS","runPosCellularBilling","report","workspaces","storesGone","warned","turnedOff","paidLate","month","paid","open","unbillable","deferred","refreshPosReaderSplashes","applied","more","scanUnsyncedOfflineCards","alerted","CARD_PAYMENT_DOOR","cardPayment","quotePayDoor","req","res","quotePayHandler","registerCommerceApi","localFulfillmentOptionsHandler","web","request","legacyFeedRoute","recipientLink","quoteViewHandler","quotePdfHandler","quoteProofHandler","quoteUploadHandler","quoteRespondHandler","registerCommerceConsoleApi","event","posHardwareBillingWebhookHandler","posOfflineCardBillingWebhookHandler","quoteHandler","orderInvoiceSendHandler","localFulfillmentHandler","productSaveHandler","productStockHandler","reservationWalkInHandler","reservationGuestsHandler","productDuplicateHandler","productDeleteHandler","orderNoteHandler","orderRestockAnswerHandler","orderPrintHandler","paymentMethodsHandler","context","cloudPrntRoute","machine","epsonServerDirectPrintRoute","posHardwareHandler","posHardwareSaleHandler","posReaderSplashHandler","posReaderSplashAdmin","posReaderSplashImagesRoute","images","posHardwareAdminOrders","posOfflineSyncHandler","ordersShippingPrepareHandler","shipStationRoute","shippingEasyRoute","shippingConnectorsHandler","app","firestore","mintDownloadToken"],"mappings":"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"}