@aglyn/plugins-commerce 1.0.0-beta.231 → 1.0.0-beta.233
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.
- package/package.json +13 -13
- package/src/lib/components/cart-extras.d.ts +6 -0
- package/src/lib/components/cart-extras.js +4 -1
- package/src/lib/components/cart-extras.js.map +1 -1
- package/src/lib/components/cart-fulfillment.d.ts +117 -0
- package/src/lib/components/cart-fulfillment.js +367 -0
- package/src/lib/components/cart-fulfillment.js.map +1 -0
- package/src/lib/components/cart.js +52 -10
- package/src/lib/components/cart.js.map +1 -1
- package/src/lib/components/commerce-console-page.js +42 -1
- package/src/lib/components/commerce-console-page.js.map +1 -1
- package/src/lib/components/console/catalog-organization-card.component.js +1 -0
- package/src/lib/components/console/catalog-organization-card.component.js.map +1 -1
- package/src/lib/components/console/host-orders-card.component.js +42 -11
- package/src/lib/components/console/host-orders-card.component.js.map +1 -1
- package/src/lib/components/console/local-delivery-settings-card.component.d.ts +37 -0
- package/src/lib/components/console/local-delivery-settings-card.component.js +542 -0
- package/src/lib/components/console/local-delivery-settings-card.component.js.map +1 -0
- package/src/lib/components/console/locations-card.component.js +177 -3
- package/src/lib/components/console/locations-card.component.js.map +1 -1
- package/src/lib/components/console/order-detail-dialog.component.js +10 -0
- package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
- package/src/lib/components/console/order-local-fulfillment-panel.component.d.ts +44 -0
- package/src/lib/components/console/order-local-fulfillment-panel.component.js +265 -0
- package/src/lib/components/console/order-local-fulfillment-panel.component.js.map +1 -0
- package/src/lib/components/console/order-offline-notice.component.d.ts +12 -0
- package/src/lib/components/console/order-offline-notice.component.js +53 -0
- package/src/lib/components/console/order-offline-notice.component.js.map +1 -0
- package/src/lib/components/console/pickup-delivery-queue-card.component.d.ts +35 -0
- package/src/lib/components/console/pickup-delivery-queue-card.component.js +222 -0
- package/src/lib/components/console/pickup-delivery-queue-card.component.js.map +1 -0
- package/src/lib/components/console/pos/pos-api.d.ts +24 -1
- package/src/lib/components/console/pos/pos-api.js +13 -0
- package/src/lib/components/console/pos/pos-api.js.map +1 -1
- package/src/lib/components/console/pos/pos-item-dialog.component.d.ts +12 -0
- package/src/lib/components/console/pos/pos-item-dialog.component.js +10 -8
- package/src/lib/components/console/pos/pos-item-dialog.component.js.map +1 -1
- package/src/lib/components/console/pos/pos-kiosk-queue.component.d.ts +22 -0
- package/src/lib/components/console/pos/pos-kiosk-queue.component.js +168 -0
- package/src/lib/components/console/pos/pos-kiosk-queue.component.js.map +1 -0
- package/src/lib/components/console/pos/pos-tender-dialogs.component.d.ts +18 -0
- package/src/lib/components/console/pos/pos-tender-dialogs.component.js +116 -1
- package/src/lib/components/console/pos/pos-tender-dialogs.component.js.map +1 -1
- package/src/lib/components/console/pos/pos-tender-panel.component.d.ts +8 -0
- package/src/lib/components/console/pos/pos-tender-panel.component.js +77 -18
- package/src/lib/components/console/pos/pos-tender-panel.component.js.map +1 -1
- package/src/lib/components/console/pos/use-pos-display.d.ts +5 -2
- package/src/lib/components/console/pos/use-pos-display.js +3 -2
- package/src/lib/components/console/pos/use-pos-display.js.map +1 -1
- package/src/lib/components/console/pos-devices-card.component.js +2 -2
- package/src/lib/components/console/pos-devices-card.component.js.map +1 -1
- package/src/lib/components/console/pos-display/pairing-screen.d.ts +5 -2
- package/src/lib/components/console/pos-display/pairing-screen.js +7 -5
- package/src/lib/components/console/pos-display/pairing-screen.js.map +1 -1
- package/src/lib/components/console/pos-display/pos-display-api.d.ts +7 -1
- package/src/lib/components/console/pos-display/pos-display-api.js +7 -2
- package/src/lib/components/console/pos-display/pos-display-api.js.map +1 -1
- package/src/lib/components/console/pos-kiosk/kiosk-checkout.d.ts +41 -0
- package/src/lib/components/console/pos-kiosk/kiosk-checkout.js +275 -0
- package/src/lib/components/console/pos-kiosk/kiosk-checkout.js.map +1 -0
- package/src/lib/components/console/pos-kiosk/kiosk-menu.d.ts +32 -0
- package/src/lib/components/console/pos-kiosk/kiosk-menu.js +344 -0
- package/src/lib/components/console/pos-kiosk/kiosk-menu.js.map +1 -0
- package/src/lib/components/console/pos-kiosk/kiosk-staff.d.ts +12 -0
- package/src/lib/components/console/pos-kiosk/kiosk-staff.js +257 -0
- package/src/lib/components/console/pos-kiosk/kiosk-staff.js.map +1 -0
- package/src/lib/components/console/pos-kiosk/pos-kiosk-api.d.ts +114 -0
- package/src/lib/components/console/pos-kiosk/pos-kiosk-api.js +189 -0
- package/src/lib/components/console/pos-kiosk/pos-kiosk-api.js.map +1 -0
- package/src/lib/components/console/pos-kiosk/use-kiosk-idle.d.ts +16 -0
- package/src/lib/components/console/pos-kiosk/use-kiosk-idle.js +80 -0
- package/src/lib/components/console/pos-kiosk/use-kiosk-idle.js.map +1 -0
- package/src/lib/components/console/pos-kiosk-page.component.d.ts +28 -0
- package/src/lib/components/console/pos-kiosk-page.component.js +791 -0
- package/src/lib/components/console/pos-kiosk-page.component.js.map +1 -0
- package/src/lib/components/console/pos-offline/pos-offline-api.d.ts +44 -0
- package/src/lib/components/console/pos-offline/pos-offline-api.js +69 -0
- package/src/lib/components/console/pos-offline/pos-offline-api.js.map +1 -0
- package/src/lib/components/console/pos-offline/pos-offline-banner.component.d.ts +7 -0
- package/src/lib/components/console/pos-offline/pos-offline-banner.component.js +135 -0
- package/src/lib/components/console/pos-offline/pos-offline-banner.component.js.map +1 -0
- package/src/lib/components/console/pos-offline/pos-offline-checkout.component.d.ts +32 -0
- package/src/lib/components/console/pos-offline/pos-offline-checkout.component.js +287 -0
- package/src/lib/components/console/pos-offline/pos-offline-checkout.component.js.map +1 -0
- package/src/lib/components/console/pos-offline/pos-offline-store.d.ts +63 -0
- package/src/lib/components/console/pos-offline/pos-offline-store.js +145 -0
- package/src/lib/components/console/pos-offline/pos-offline-store.js.map +1 -0
- package/src/lib/components/console/pos-offline/register-offline.d.ts +24 -0
- package/src/lib/components/console/pos-offline/register-offline.js +24 -0
- package/src/lib/components/console/pos-offline/register-offline.js.map +1 -0
- package/src/lib/components/console/pos-offline/use-pos-offline.d.ts +85 -0
- package/src/lib/components/console/pos-offline/use-pos-offline.js +542 -0
- package/src/lib/components/console/pos-offline/use-pos-offline.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js +72 -17
- package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js.map +1 -1
- package/src/lib/components/console/pos-page.component.js +228 -51
- package/src/lib/components/console/pos-page.component.js.map +1 -1
- package/src/lib/components/console/pos-zones.d.ts +23 -0
- package/src/lib/components/console/pos-zones.js +31 -0
- package/src/lib/components/console/pos-zones.js.map +1 -0
- package/src/lib/components/console/product-editor-dialog.component.js +10 -64
- package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
- package/src/lib/components/console/products-hub-card.component.js +46 -30
- package/src/lib/components/console/products-hub-card.component.js.map +1 -1
- package/src/lib/components/console/shipping-settings-card.component.js +1 -1
- package/src/lib/components/console/shipping-settings-card.component.js.map +1 -1
- package/src/lib/components/console/stock-movements-card.component.js +48 -16
- package/src/lib/components/console/stock-movements-card.component.js.map +1 -1
- package/src/lib/components/console/store-zones.d.ts +8 -1
- package/src/lib/components/console/store-zones.js +11 -1
- package/src/lib/components/console/store-zones.js.map +1 -1
- package/src/lib/components/console/storefront-tax-summary-card.component.js +1 -0
- package/src/lib/components/console/storefront-tax-summary-card.component.js.map +1 -1
- package/src/lib/components/order-status.js +66 -0
- package/src/lib/components/order-status.js.map +1 -1
- package/src/lib/components/product-detail.js +42 -15
- package/src/lib/components/product-detail.js.map +1 -1
- package/src/lib/constants/local-fulfillment-list-query.d.ts +48 -0
- package/src/lib/constants/local-fulfillment-list-query.js +84 -0
- package/src/lib/constants/local-fulfillment-list-query.js.map +1 -0
- package/src/lib/constants/orders-list-query.d.ts +7 -2
- package/src/lib/constants/orders-list-query.js +89 -8
- package/src/lib/constants/orders-list-query.js.map +1 -1
- package/src/lib/constants/pos-shift-list-query.d.ts +22 -0
- package/src/lib/constants/pos-shift-list-query.js +115 -0
- package/src/lib/constants/pos-shift-list-query.js.map +1 -0
- package/src/lib/constants/product-list-query.d.ts +6 -1
- package/src/lib/constants/product-list-query.js +77 -8
- package/src/lib/constants/product-list-query.js.map +1 -1
- package/src/lib/constants/stock-movement-query.d.ts +3 -2
- package/src/lib/constants/stock-movement-query.js +52 -8
- package/src/lib/constants/stock-movement-query.js.map +1 -1
- package/src/lib/declarations.server.js +21 -0
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/model/buyer-notifications.d.ts +5 -3
- package/src/lib/model/buyer-notifications.js +25 -4
- package/src/lib/model/buyer-notifications.js.map +1 -1
- package/src/lib/model/commerce-orders.d.ts +103 -1
- package/src/lib/model/commerce-orders.js +2 -1
- package/src/lib/model/commerce-orders.js.map +1 -1
- package/src/lib/model/commerce-pos-kiosk.d.ts +175 -0
- package/src/lib/model/commerce-pos-kiosk.js +147 -0
- package/src/lib/model/commerce-pos-kiosk.js.map +1 -0
- package/src/lib/model/commerce-pos-offline.d.ts +234 -0
- package/src/lib/model/commerce-pos-offline.js +301 -0
- package/src/lib/model/commerce-pos-offline.js.map +1 -0
- package/src/lib/model/commerce-pos-ops.d.ts +16 -6
- package/src/lib/model/commerce-pos-ops.js +12 -4
- package/src/lib/model/commerce-pos-ops.js.map +1 -1
- package/src/lib/model/commerce-pos.d.ts +13 -1
- package/src/lib/model/commerce-pos.js +5 -4
- package/src/lib/model/commerce-pos.js.map +1 -1
- package/src/lib/model/commerce-stock-holds.d.ts +24 -3
- package/src/lib/model/commerce-stock-holds.js +26 -8
- package/src/lib/model/commerce-stock-holds.js.map +1 -1
- package/src/lib/model/commerce.d.ts +7 -1
- package/src/lib/model/commerce.js.map +1 -1
- package/src/lib/model/index.d.ts +5 -0
- package/src/lib/model/index.js +5 -0
- package/src/lib/model/index.js.map +1 -1
- package/src/lib/model/local-fulfillment-settings.d.ts +178 -0
- package/src/lib/model/local-fulfillment-settings.js +361 -0
- package/src/lib/model/local-fulfillment-settings.js.map +1 -0
- package/src/lib/model/order-list-fields.d.ts +10 -1
- package/src/lib/model/order-list-fields.js +1 -0
- package/src/lib/model/order-list-fields.js.map +1 -1
- package/src/lib/model/order-local-fulfillment.d.ts +131 -0
- package/src/lib/model/order-local-fulfillment.js +125 -0
- package/src/lib/model/order-local-fulfillment.js.map +1 -0
- package/src/lib/model/order-shipping-export.js +4 -0
- package/src/lib/model/order-shipping-export.js.map +1 -1
- package/src/lib/model/order-status-view.d.ts +20 -1
- package/src/lib/model/order-status-view.js +60 -6
- package/src/lib/model/order-status-view.js.map +1 -1
- package/src/lib/model/product-write.d.ts +186 -0
- package/src/lib/model/product-write.js +116 -0
- package/src/lib/model/product-write.js.map +1 -0
- package/src/lib/plugin-config.js +6 -2
- package/src/lib/plugin-config.js.map +1 -1
- package/src/lib/plugin.js +11 -0
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/pos-kiosk-config.d.ts +26 -0
- package/src/lib/pos-kiosk-config.js +59 -0
- package/src/lib/pos-kiosk-config.js.map +1 -0
- package/src/lib/server/api-v1/openapi.js +8 -0
- package/src/lib/server/api-v1/openapi.js.map +1 -1
- package/src/lib/server/api-v1/order-view.d.ts +19 -0
- package/src/lib/server/api-v1/order-view.js +35 -0
- package/src/lib/server/api-v1/order-view.js.map +1 -1
- package/src/lib/server/billing-webhook.js +238 -87
- package/src/lib/server/billing-webhook.js.map +1 -1
- package/src/lib/server/cart-checkout.d.ts +2 -0
- package/src/lib/server/cart-checkout.js +173 -13
- package/src/lib/server/cart-checkout.js.map +1 -1
- package/src/lib/server/channel-order-updates.d.ts +50 -0
- package/src/lib/server/channel-order-updates.js +290 -0
- package/src/lib/server/channel-order-updates.js.map +1 -0
- package/src/lib/server/channel-orders.d.ts +85 -0
- package/src/lib/server/channel-orders.js +543 -0
- package/src/lib/server/channel-orders.js.map +1 -0
- package/src/lib/server/checkout-extras.js +18 -4
- package/src/lib/server/checkout-extras.js.map +1 -1
- package/src/lib/server/checkout.js +71 -14
- package/src/lib/server/checkout.js.map +1 -1
- package/src/lib/server/local-fulfillment-status.d.ts +86 -0
- package/src/lib/server/local-fulfillment-status.js +379 -0
- package/src/lib/server/local-fulfillment-status.js.map +1 -0
- package/src/lib/server/local-fulfillment.d.ts +190 -0
- package/src/lib/server/local-fulfillment.js +580 -0
- package/src/lib/server/local-fulfillment.js.map +1 -0
- package/src/lib/server/membership-register.js +3 -1
- package/src/lib/server/membership-register.js.map +1 -1
- package/src/lib/server/order-notifications.js +61 -0
- package/src/lib/server/order-notifications.js.map +1 -1
- package/src/lib/server/pos-display.d.ts +27 -1
- package/src/lib/server/pos-display.js +50 -9
- package/src/lib/server/pos-display.js.map +1 -1
- package/src/lib/server/pos-kiosk-principal.d.ts +29 -0
- package/src/lib/server/pos-kiosk-principal.js +42 -0
- package/src/lib/server/pos-kiosk-principal.js.map +1 -0
- package/src/lib/server/pos-kiosk.d.ts +54 -0
- package/src/lib/server/pos-kiosk.js +972 -0
- package/src/lib/server/pos-kiosk.js.map +1 -0
- package/src/lib/server/pos-offline-sync.d.ts +85 -0
- package/src/lib/server/pos-offline-sync.js +765 -0
- package/src/lib/server/pos-offline-sync.js.map +1 -0
- package/src/lib/server/pos-order.js +22 -4
- package/src/lib/server/pos-order.js.map +1 -1
- package/src/lib/server/pos-payment.d.ts +6 -0
- package/src/lib/server/pos-payment.js +225 -6
- package/src/lib/server/pos-payment.js.map +1 -1
- package/src/lib/server/pos-print.js +5 -0
- package/src/lib/server/pos-print.js.map +1 -1
- package/src/lib/server/pos-return.js +27 -0
- package/src/lib/server/pos-return.js.map +1 -1
- package/src/lib/server/pos-sale.d.ts +6 -0
- package/src/lib/server/pos-sale.js +2 -0
- package/src/lib/server/pos-sale.js.map +1 -1
- package/src/lib/server/pos-shift.js +8 -1
- package/src/lib/server/pos-shift.js.map +1 -1
- package/src/lib/server/product-catalog.js +5 -1
- package/src/lib/server/product-catalog.js.map +1 -1
- package/src/lib/server/product-drafts.d.ts +5 -1
- package/src/lib/server/product-drafts.js +3 -3
- package/src/lib/server/product-drafts.js.map +1 -1
- package/src/lib/server/product-writer.d.ts +19 -0
- package/src/lib/server/product-writer.js +261 -0
- package/src/lib/server/product-writer.js.map +1 -0
- package/src/lib/server/products-write.d.ts +61 -0
- package/src/lib/server/products-write.js +375 -0
- package/src/lib/server/products-write.js.map +1 -0
- package/src/lib/server/refund.js +3 -0
- package/src/lib/server/refund.js.map +1 -1
- package/src/lib/server/stock-hold.d.ts +9 -1
- package/src/lib/server/stock-hold.js +15 -7
- package/src/lib/server/stock-hold.js.map +1 -1
- package/src/lib/server.js +21 -0
- package/src/lib/server.js.map +1 -1
- package/src/lib/tenant-emails.js +161 -0
- package/src/lib/tenant-emails.js.map +1 -1
- package/src/lib/testing/memory-firestore.d.ts +16 -3
- package/src/lib/testing/memory-firestore.js +11 -3
- package/src/lib/testing/memory-firestore.js.map +1 -1
- package/src/lib/transfer/products.server.d.ts +5 -0
- package/src/lib/transfer/products.server.js +2 -2
- package/src/lib/transfer/products.server.js.map +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/pos-kiosk.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 { createHmac, timingSafeEqual } from 'crypto'\nimport * as Aglyn from '@aglyn/aglyn/server'\nimport type { PluginApiHandler, PluginApiRequest, PluginApiResponse } from '@aglyn/aglyn/server'\nimport { resolveMediaSrc } from '@aglyn/aglyn/app-utils/media-ref'\nimport { pluginSmsAvailable } from '@aglyn/aglyn/plugin-manager/plugin-sms-messaging'\nimport {\n consumeRateLimit,\n firebaseAdmin,\n getLockdownVerdict,\n getOrgForHost,\n getPluginConfig,\n} from '@aglyn/tenant-data-admin'\nimport { resolveOrgPermissions } from '@aglyn/tenant-runtime/org-permissions'\nimport * as CommerceModel from '../model'\nimport { posRegisterSettings, type PosRegisterSettings } from '../plugin-config'\nimport { posKioskSettings, type PosKioskSettings } from '../pos-kiosk-config'\nimport { verifyMemberPassword } from './membership'\nimport { authorizePosStaff, posIdempotencyKey, posQueryBody, posRequestBody, type PosStaff } from './pos-auth'\nimport {\n displayBranding,\n displayToken,\n posDisplayCurrency,\n resolveDisplayToken,\n type PosDeviceToken,\n} from './pos-display'\nimport { withPosKioskPrincipal } from './pos-kiosk-principal'\nimport { posOrderHandler } from './pos-order'\nimport { recordReceiptChoice, voidPosSale } from './pos-payment'\nimport { posPaymentId, posSaleSummary, readPosSale, type PosLiftedOrder } from './pos-sale'\nimport { posStripeTestMode, posTerminalAvailable } from './pos-stripe'\nimport {\n cancelPosCardPayment,\n createCardPresentIntent,\n createPosTerminalConnectionToken,\n refreshPosCardPayment,\n simulatePosReaderTap,\n startCardPresentPayment,\n} from './pos-terminal'\n\n/*==========================================\n * THE SELF-SERVICE KIOSK (AGL-3623): `/api/commerce/pos-kiosk`.\n *\n * ## Who is asking\n *\n * A kiosk is a register's paired screen with `mode: 'kiosk'` — the same\n * six-digit code and hashed device token as the customer display\n * (`pos-display.ts`), so pairing is one trust path, not two. It holds no\n * staff session. Every device action carries the token, and the gate below\n * re-checks, on every call, that the staff member whose code paired it may\n * still work this register (`admin`/`editor` on the site, `managePos`), that\n * the plan still includes POS, and that no lockdown covers them, the org or\n * the site. Demote them and the kiosk stops on its next tap.\n *\n * ## What it can reach\n *\n * Its own register's catalog, the orders IT opened (`kioskDeviceId`), and\n * nothing else: no staff names, no other customer's order, no register\n * state. A customer's email or phone goes straight onto their own order as\n * the receipt request and is never echoed back.\n *\n * ## Money\n *\n * The cart is priced by the register's own sale route (`pos-order.ts`), in\n * process, as an OPEN sale — the same tax, automatic promotions, platform\n * fee and idempotency as a cashier's sale, and none of a cashier's\n * discretion: no discount, no code, no customer, no stay. The amount a card\n * pays is always the server's balance; the kiosk names only a tip choice,\n * which is recomputed here from the store's own presets. Card payments are\n * the register's Stripe Terminal flow (AGL-3607) unchanged, and they stay\n * behind `STRIPE_TERMINAL_LIVE_ENABLED` exactly as the register's do.\n *\n * ## Staff\n *\n * `queue` and `take` are the register's: signed in and gated like a sale.\n * A queued (\"pay at counter\") order is an open sale like any other, and the\n * register takes payment on it through `commerce/pos-payment`.\n *=========================================*/\n\ntype Outcome = { status: number; body: Record<string, unknown> }\n\nconst DEVICE_READS = new Set(['context', 'catalog', 'sale'])\nconst STAFF_READS = new Set(['queue'])\n\ninterface KioskGate {\n device: PosDeviceToken\n /** The token hash prefix the kiosk's orders carry. */\n deviceId: string\n hostId: string\n registerId: string\n hostRef: FirebaseFirestore.DocumentReference\n /** The staff member who paired the kiosk; what it acts as. */\n uid: string\n orgId: string\n org: Record<string, any> | null\n register: Record<string, any>\n settings: PosRegisterSettings\n kiosk: PosKioskSettings\n}\n\n/** The prefix of a token row's id a kiosk's orders are stamped with. */\nexport function posKioskDeviceId(device: PosDeviceToken): string {\n return String(device.ref?.id ?? '').slice(0, 16)\n}\n\nfunction refuse(status: number, error: string): Outcome {\n return { status, body: { error } }\n}\n\n/** The kiosk's gate, asked again on every call. */\nasync function authorizeKiosk(\n req: PluginApiRequest,\n body: Record<string, any>,\n write: boolean,\n): Promise<KioskGate | Outcome> {\n const device = await resolveDisplayToken(displayToken(req, body))\n if (!device) return refuse(401, 'This kiosk is not paired.')\n if (device.mode !== 'kiosk') return refuse(403, 'This device is a customer display, not a kiosk.')\n const firestore = firebaseAdmin.app().firestore()\n const hostRef = firestore.collection('hosts').doc(device.hostId)\n const [host, register] = await Promise.all([\n hostRef.get(),\n hostRef.collection('registers').doc(device.registerId).get(),\n ])\n if (!host.exists || !register.exists) return refuse(401, 'This kiosk is not paired.')\n const role = (host.get('memberRoles') ?? {})[device.createdBy]\n const membership = device.createdBy\n ? await resolveOrgPermissions(device.createdBy, { hostId: device.hostId })\n : null\n if ((role !== 'admin' && role !== 'editor') || !membership?.permissions?.managePos) {\n return refuse(403, 'This kiosk needs a staff member to pair it again.')\n }\n const owner = await getOrgForHost(device.hostId)\n if (!Aglyn.checkEntitlement(owner?.org as any, 'pos')) {\n return refuse(403, 'This kiosk is not available. Please order at the counter.')\n }\n const locked = await getLockdownVerdict({\n uid: device.createdBy,\n org: owner?.org as never,\n host: host.data() as never,\n intent: write ? 'write' : 'read',\n })\n if (locked) return { status: 423, body: { error: 'This kiosk is paused. Please order at the counter.', locked: true } }\n const orgId = String(owner?.org?.id ?? owner?.orgId ?? '')\n const config = await getPluginConfig(orgId || undefined, 'commerce', { hostId: device.hostId }).catch(\n () => ({}),\n )\n return {\n device,\n deviceId: posKioskDeviceId(device),\n hostId: device.hostId,\n registerId: device.registerId,\n hostRef,\n uid: device.createdBy,\n orgId,\n org: (owner?.org as Record<string, any>) ?? null,\n register: (register.data() ?? {}) as Record<string, any>,\n settings: posRegisterSettings(config),\n kiosk: posKioskSettings(config),\n }\n}\n\n/** One durable budget per kiosk and action; refused requests do nothing. */\nasync function withinBudget(gate: KioskGate, action: string, limit: number): Promise<boolean> {\n const rate = await consumeRateLimit(`pos-kiosk:${action}:${gate.deviceId}`, {\n limit,\n windowMs: 10 * 60 * 1000,\n })\n return rate.allowed\n}\n\n/** The register's card readers, when Terminal is switched on. */\nasync function registerReaders(gate: KioskGate): Promise<Array<{ id: string; label: string; status: string }>> {\n if (!posTerminalAvailable()) return []\n const snapshot = await gate.hostRef\n .collection('terminalReaders')\n .where('registerId', '==', gate.registerId)\n .limit(10)\n .get()\n return snapshot.docs.map((doc: any) => ({\n id: String(doc.id),\n label: String(doc.get('label') ?? 'Card reader'),\n status: String(doc.get('status') ?? 'offline'),\n }))\n}\n\n/** The reader this kiosk sends cards to: the one chosen in its settings, else the register's only one. */\nasync function kioskReaderId(gate: KioskGate): Promise<string | null> {\n const readers = await registerReaders(gate)\n const chosen = String(gate.device.data['kioskReaderId'] ?? '')\n if (chosen && readers.some((reader) => reader.id === chosen)) return chosen\n return readers.length === 1 ? readers[0]!.id : null\n}\n\n/** The receipt choices this kiosk can honor. */\nasync function receiptChannels(gate: KioskGate): Promise<CommerceModel.PosReceiptChannel[]> {\n const channels: CommerceModel.PosReceiptChannel[] = ['email']\n if (pluginSmsAvailable()) channels.push('sms')\n // Printed on the register's own receipt printer, so offered only when it has one.\n const printers = await gate.hostRef\n .collection('printers')\n .where('registerId', '==', gate.registerId)\n .limit(1)\n .get()\n .catch(() => null)\n if (printers && !printers.empty) channels.push('print')\n channels.push('none')\n return channels\n}\n\nasync function context(gate: KioskGate): Promise<Outcome> {\n const [branding, currency, reader, receipts] = await Promise.all([\n displayBranding(gate.hostId),\n posDisplayCurrency(gate.hostId),\n kioskReaderId(gate),\n receiptChannels(gate),\n ])\n const value: CommerceModel.PosKioskContext = {\n branding: { ...branding, message: gate.kiosk.welcome || 'Order here' },\n currency,\n tipping: { enabled: gate.settings.tippingEnabled, percentages: gate.settings.tipPercentages },\n payments: {\n reader: Boolean(reader),\n cardPresent: posTerminalAvailable(),\n payAtCounter: gate.kiosk.payAtCounter,\n },\n receipts,\n offerMarketing: gate.settings.displayMarketingOptIn,\n idleSeconds: gate.kiosk.idleSeconds,\n testMode: posStripeTestMode(),\n }\n return { status: 200, body: value as unknown as Record<string, unknown> }\n}\n\n/**\n * Whether a product may be sold at a kiosk at all: what the register sells,\n * less what a customer cannot be handed at a counter — a subscription-only\n * product, a gift card whose code needs issuing, and a digital download.\n */\nexport function posKioskSellable(product: CommerceModel.HostProduct): boolean {\n if (product.status !== 'active') return false\n if (product.subscription && !product.subscriptionOptional) return false\n if (product.giftCard) return false\n if (product.type === 'digital') return false\n return (product.variants ?? []).some((variant) => CommerceModel.variantHasPrice(variant))\n}\n\n/** A product as the kiosk may show it: names, prices and choices, nothing else. */\nexport function posKioskProduct(\n id: string,\n product: CommerceModel.HostProduct,\n hostId: string,\n): CommerceModel.PosKioskProduct {\n const image = resolveMediaSrc(product.mediaUrls?.[0], { hostId })\n const description = String(product.description ?? '').trim().slice(0, 280)\n return {\n id,\n name: String(product.name ?? '').slice(0, 120),\n ...(description ? { description } : {}),\n ...(image ? { imageUrl: image } : {}),\n categoryIds: (product.categoryIds ?? []).slice(0, 20),\n options: (product.options ?? []).map((option) => ({ name: option.name, values: [...option.values] })),\n variants: (product.variants ?? [])\n .filter((variant) => CommerceModel.variantHasPrice(variant))\n .map((variant) => ({\n id: variant.id,\n options: { ...(variant.options ?? {}) },\n priceCents: Math.round(Number(variant.priceUsd) * 100),\n soldOut: Boolean(CommerceModel.stockShortfall(product, variant.id, 1)),\n })),\n modifierGroups: CommerceModel.productModifierGroups(product),\n }\n}\n\nasync function catalog(gate: KioskGate, body: Record<string, any>): Promise<Outcome> {\n const categoryId = String(body['categoryId'] ?? '')\n if (categoryId && !/^[A-Za-z0-9_-]{1,128}$/.test(categoryId)) return refuse(400, 'Unknown category')\n // The register grid's query (AGL-3321): live, active, by name — and a\n // category is a clause on the query, never a filter over what was read.\n let query: FirebaseFirestore.Query = gate.hostRef\n .collection('products')\n .where('deletedAt', '==', null)\n .where('status', '==', 'active')\n if (categoryId) query = query.where('categoryIds', 'array-contains', categoryId)\n const [products, categories, currency] = await Promise.all([\n query.orderBy('nameLower').limit(CommerceModel.POS_KIOSK_CATALOG_LIMIT).get(),\n gate.hostRef.collection('productCategories').limit(30).get(),\n posDisplayCurrency(gate.hostId),\n ])\n const value: CommerceModel.PosKioskCatalog = {\n products: products.docs\n .map((doc: any) => ({ id: String(doc.id), product: CommerceModel.liftLegacyProduct(doc.data()) }))\n .filter(({ product }) => posKioskSellable(product))\n .map(({ id, product }) => posKioskProduct(id, product, gate.hostId)),\n categories: categories.docs.map((doc: any) => ({\n id: String(doc.id),\n name: String(doc.get('name') ?? 'Category').slice(0, 60),\n })),\n currency,\n }\n return { status: 200, body: value as unknown as Record<string, unknown> }\n}\n\n/** An order as its kiosk reads it back; null for any order this kiosk did not open. */\nexport function posKioskSaleView(\n order: PosLiftedOrder | null,\n deviceId: string,\n): CommerceModel.PosKioskSale | null {\n if (!order || order.posSource !== 'kiosk' || order.kioskDeviceId !== deviceId) return null\n const summary = posSaleSummary(order)\n const status: CommerceModel.PosKioskSaleStatus =\n order.status === 'paid'\n ? 'paid'\n : order.status === 'pending'\n ? order.kioskQueueRegisterId\n ? 'queued'\n : 'open'\n : 'voided'\n const card = [...summary.payments]\n .reverse()\n .find((payment) => CommerceModel.isCardPaymentMethod(payment.method))\n return {\n orderId: order.$id,\n number: Number(order.number ?? 0),\n status,\n lines: (order.lineItems ?? []).map((line) => ({\n name: line.name,\n ...(line.variantLabel ? { variantLabel: line.variantLabel } : {}),\n quantity: line.quantity,\n amountCents: line.unitAmountCents * line.quantity,\n })),\n itemsCents: Number(order.totals?.itemsCents ?? 0),\n discountCents: Number(order.totals?.discountCents ?? 0),\n taxCents: Number(order.totals?.taxCents ?? 0),\n totalCents: summary.totalCents,\n tipCents: summary.tipCents,\n paidCents: summary.paidCents,\n dueCents: summary.dueCents,\n payment: card\n ? {\n id: card.id,\n status: card.status,\n ...(card.failureMessage ? { failureMessage: card.failureMessage } : {}),\n }\n : null,\n }\n}\n\n/** This kiosk's order, or a refusal that says nothing about anyone else's. */\nasync function readOwnSale(\n gate: KioskGate,\n rawOrderId: unknown,\n): Promise<{ order: PosLiftedOrder; view: CommerceModel.PosKioskSale } | Outcome> {\n const orderId = String(rawOrderId ?? '')\n if (!/^[A-Za-z0-9_-]{1,128}$/.test(orderId)) return refuse(404, 'Unknown order')\n const order = await readPosSale(gate.hostId, orderId)\n const view = posKioskSaleView(order, gate.deviceId)\n if (!order || !view) return refuse(404, 'Unknown order')\n return { order, view }\n}\n\n/** The response the in-process sale route wrote. */\nfunction recorder() {\n const result = { status: 500, body: {} as Record<string, any> }\n const res = {\n status(code: number) {\n result.status = code\n return res\n },\n json(value: unknown) {\n result.body = (value ?? {}) as Record<string, any>\n },\n send() {},\n setHeader() {},\n redirect() {},\n end() {},\n } as unknown as PluginApiResponse\n return { res, result }\n}\n\nasync function checkout(\n gate: KioskGate,\n req: PluginApiRequest,\n body: Record<string, any>,\n): Promise<Outcome> {\n const attemptKey = posIdempotencyKey(req)\n if (!attemptKey) return refuse(400, 'Missing Idempotency-Key')\n const cart = CommerceModel.sanitizePosKioskLines(body['lines'])\n if ('error' in cart) return refuse(400, cart.error)\n if (!(await withinBudget(gate, 'checkout', 40))) {\n return refuse(429, 'Too many orders from this kiosk. Please order at the counter.')\n }\n // What a customer may buy here, read from the product documents before\n // anything is priced: the sale route warns a cashier about stock and sells\n // anyway (the goods are in their hand); a kiosk refuses what is sold out.\n const ids = [...new Set(cart.lines.map((line) => line.productId))]\n const snapshots = await Promise.all(ids.map((id) => gate.hostRef.collection('products').doc(id).get()))\n const products = new Map(\n snapshots.map((snapshot: any) => [\n String(snapshot.id),\n snapshot.exists ? CommerceModel.liftLegacyProduct(snapshot.data()) : null,\n ]),\n )\n for (const line of cart.lines) {\n const product = products.get(line.productId)\n if (!product || (product as { deletedAt?: unknown }).deletedAt || !posKioskSellable(product)) {\n return refuse(409, 'An item in your cart is no longer available. Remove it and try again.')\n }\n const variant = line.variantId\n ? product.variants.find((candidate) => candidate.id === line.variantId)\n : product.variants[0]\n if (!variant || !CommerceModel.variantHasPrice(variant)) {\n return refuse(409, `${product.name} is no longer available. Remove it and try again.`)\n }\n const wanted = cart.lines\n .filter((other) => other.productId === line.productId && (other.variantId ?? '') === (line.variantId ?? ''))\n .reduce((sum, other) => sum + other.quantity, 0)\n if (CommerceModel.stockShortfall(product, variant.id, wanted)) {\n return refuse(409, `${product.name} is sold out. Remove it and try again.`)\n }\n }\n const { res, result } = recorder()\n const priced = withPosKioskPrincipal(\n {\n method: 'POST',\n headers: { 'idempotency-key': `kiosk:${gate.deviceId}:${attemptKey}` },\n query: {},\n cookies: {},\n socket: req.socket,\n body: {\n hostId: gate.hostId,\n registerId: gate.registerId,\n payment: 'open',\n lines: cart.lines,\n ...(typeof gate.register['locationId'] === 'string' && gate.register['locationId']\n ? { locationId: gate.register['locationId'] }\n : {}),\n },\n } as PluginApiRequest,\n { uid: gate.uid, registerId: gate.registerId, deviceId: gate.deviceId },\n )\n await posOrderHandler(priced, res)\n if (result.status !== 200 || !result.body['orderId']) {\n // A refusal about a product names it, and the customer can fix it. One\n // about the store — a shift, the tax setup, the plan — is the staff's to\n // fix, and the customer is sent to the counter.\n console.warn('[pos-kiosk] sale refused', gate.hostId, result.status, result.body['error'])\n if (result.status === 400 && result.body['error']) return refuse(400, String(result.body['error']))\n return refuse(\n result.status === 429 ? 429 : 409,\n 'This kiosk cannot take orders right now. Please order at the counter.',\n )\n }\n const own = await readOwnSale(gate, result.body['orderId'])\n if ('status' in own) return own\n if (own.view.totalCents <= 0) {\n // Nothing to take a card for, and nothing a kiosk should hand out free.\n await voidPosSale(kioskStaff(gate), own.order.$id).catch(() => undefined)\n return refuse(409, 'Please ask at the counter for this order.')\n }\n return { status: 200, body: { sale: own.view } }\n}\n\n/** The kiosk, as the register's payment helpers expect the person at the till. */\nfunction kioskStaff(gate: KioskGate): PosStaff {\n return { uid: gate.uid, hostId: gate.hostId, orgId: gate.orgId, org: gate.org }\n}\n\nasync function pay(gate: KioskGate, req: PluginApiRequest, body: Record<string, any>): Promise<Outcome> {\n const attemptKey = posIdempotencyKey(req)\n if (!attemptKey) return refuse(400, 'Missing Idempotency-Key')\n const method = String(body['method'] ?? '')\n if (method !== 'reader' && method !== 'tap') return refuse(400, 'Choose how to pay.')\n if (!posTerminalAvailable()) return refuse(409, 'Card payments are not available on this kiosk.')\n if (!(await withinBudget(gate, 'pay', 60))) return refuse(429, 'Too many tries. Please pay at the counter.')\n const own = await readOwnSale(gate, body['orderId'])\n if ('status' in own) return own\n if (own.view.status !== 'open') return refuse(409, 'This order is no longer waiting for payment.')\n const paymentId = posPaymentId(own.order.$id, `kiosk:${attemptKey}`)\n // A retried press finds the payment its first press reserved, for the\n // amount and tip that press chose: the reservation is already out of the\n // balance, so the balance alone would read as nothing left to pay.\n const pressed = CommerceModel.orderPayments(own.order).find((payment) => payment.id === paymentId)\n const amountCents = pressed ? pressed.amountCents : posSaleSummary(own.order).tenderableCents\n if (!(amountCents > 0)) return refuse(409, 'Nothing is left to pay on this order.')\n const tipCents = pressed ? Number(pressed.tipCents ?? 0) : CommerceModel.posKioskTipCents(body['tipChoice'], {\n baseCents: amountCents,\n enabled: gate.settings.tippingEnabled,\n percentages: gate.settings.tipPercentages,\n percent: body['tipPercent'],\n cents: body['tipCents'],\n })\n if (tipCents === null) return refuse(400, 'Choose one of the tips shown, or no tip.')\n const start = {\n hostId: gate.hostId,\n orderId: own.order.$id,\n paymentId,\n amountCents,\n tipCents,\n cashierId: gate.uid,\n org: gate.org,\n }\n let outcome: Awaited<ReturnType<typeof createCardPresentIntent>>\n if (method === 'reader') {\n const readerId = await kioskReaderId(gate)\n if (!readerId) return refuse(409, 'No card reader is set up for this kiosk. Please pay at the counter.')\n // The kiosk asked for the tip on its own screen: the reader must not ask again.\n outcome = await startCardPresentPayment({\n ...start,\n readerId,\n settings: { ...gate.settings, tippingEnabled: false },\n })\n } else {\n // Tap to Pay: collected by the native POS app's Stripe Terminal SDK\n // against this server-made intent (AGL-3618), settled like any reader.\n outcome = await createCardPresentIntent(start)\n }\n if ('error' in outcome) return refuse(outcome.status, outcome.error)\n const view = posKioskSaleView(outcome.order, gate.deviceId)\n return {\n status: 200,\n body: {\n sale: view,\n ...(outcome.payment ? { paymentId: outcome.payment.id } : {}),\n ...(outcome.clientSecret ? { clientSecret: outcome.clientSecret } : {}),\n ...(outcome.paymentIntentId ? { paymentIntentId: outcome.paymentIntentId } : {}),\n },\n }\n}\n\n/** A card payment on this kiosk's own order: refreshed, canceled or (test mode) tapped. */\nasync function cardStep(\n gate: KioskGate,\n body: Record<string, any>,\n step: 'payment-status' | 'cancel-payment' | 'simulate',\n): Promise<Outcome> {\n if (!(await withinBudget(gate, 'card', 900))) return refuse(429, 'Too many tries. Wait a moment.')\n const own = await readOwnSale(gate, body['orderId'])\n if ('status' in own) return own\n const paymentId = String(body['paymentId'] ?? '')\n if (!own.order.payments?.some((payment) => payment.id === paymentId)) return refuse(404, 'Unknown payment')\n const ref = { hostId: gate.hostId, orderId: own.order.$id, paymentId }\n let outcome\n if (step === 'payment-status') outcome = await refreshPosCardPayment(ref)\n else if (step === 'cancel-payment') outcome = await cancelPosCardPayment(ref)\n else {\n if (!posStripeTestMode()) return refuse(404, 'Unknown action')\n outcome = await simulatePosReaderTap({ ...ref, cardNumber: String(body['cardNumber'] ?? '') })\n }\n if ('error' in outcome) return refuse(outcome.status, outcome.error)\n return { status: 200, body: { sale: posKioskSaleView(outcome.order, gate.deviceId) } }\n}\n\n/** \"Pay at counter\": the order joins the register's queue with its number. */\nasync function sendToCounter(gate: KioskGate, body: Record<string, any>): Promise<Outcome> {\n if (!gate.kiosk.payAtCounter) return refuse(409, 'Please pay here with a card.')\n if (!(await withinBudget(gate, 'counter', 40))) return refuse(429, 'Too many orders from this kiosk.')\n const own = await readOwnSale(gate, body['orderId'])\n if ('status' in own) return own\n if (own.view.status === 'queued') return { status: 200, body: { sale: own.view } }\n const ref = gate.hostRef.collection('orders').doc(own.order.$id)\n const firestore = firebaseAdmin.app().firestore()\n // In a transaction: a card that settled between the customer's two taps\n // leaves a paid order, which never joins a queue.\n const queued = await firestore.runTransaction(async (transaction: any) => {\n const fresh = await transaction.get(ref)\n if (!fresh.exists || fresh.get('status') !== 'pending') return false\n const payments = CommerceModel.orderPayments(fresh.data() as any)\n if (payments.some((payment) => payment.status === 'pending' || payment.status === 'succeeded')) {\n return false\n }\n transaction.set(\n ref,\n {\n kioskQueueRegisterId: gate.registerId,\n kioskQueuedAtMs: Date.now(),\n timeline: CommerceModel.appendOrderEvent(\n { ...(fresh.data() as any) },\n 'pos-kiosk-pay-at-counter',\n 'Sent to the counter from the self-service kiosk',\n ),\n },\n { merge: true },\n )\n return true\n })\n if (!queued) return refuse(409, 'This order is already being paid. Check the screen.')\n const after = await readOwnSale(gate, own.order.$id)\n if ('status' in after) return after\n return { status: 200, body: { sale: after.view } }\n}\n\nasync function receipt(gate: KioskGate, body: Record<string, any>): Promise<Outcome> {\n if (!(await withinBudget(gate, 'receipt', 40))) return refuse(429, 'Too many tries.')\n const own = await readOwnSale(gate, body['orderId'])\n if ('status' in own) return own\n if (own.view.status !== 'paid') return refuse(409, 'Your receipt is ready once your order is paid.')\n const channel = String(body['channel'] ?? '') as CommerceModel.PosReceiptChannel\n if (!(await receiptChannels(gate)).includes(channel)) return refuse(400, 'Choose a receipt shown on the screen.')\n const outcome = await recordReceiptChoice(kioskStaff(gate), own.order.$id, {\n channel,\n to: body['to'],\n marketingOptIn: gate.settings.displayMarketingOptIn && body['marketingOptIn'] === true,\n })\n if ('error' in outcome) return refuse(outcome.status, outcome.error)\n // The address is on the order now; nothing of it comes back to the screen.\n return { status: 200, body: { ok: true } }\n}\n\n/**\n * The idle reset and \"Start over\": an order this kiosk opened and nobody\n * paid is voided, so it holds no promotion slot and no stock. A queued or\n * paid order is left exactly as it is.\n */\nasync function abandon(gate: KioskGate, body: Record<string, any>): Promise<Outcome> {\n const own = await readOwnSale(gate, body['orderId'])\n if ('status' in own) return own\n if (own.view.status !== 'open') return { status: 200, body: { sale: own.view } }\n // Money that already moved is the counter's to settle, never a screen's\n // to refund on its own.\n if (CommerceModel.orderPayments(own.order).some((payment) => payment.status === 'succeeded')) {\n return { status: 200, body: { sale: own.view } }\n }\n const outcome = await voidPosSale(kioskStaff(gate), own.order.$id)\n if ('error' in outcome) return refuse(outcome.status, outcome.error)\n return { status: 200, body: { sale: posKioskSaleView(outcome.order, gate.deviceId) } }\n}\n\n/*==========================================\n * STAFF UNLOCK.\n *\n * The register's staff PINs (AGL-3609), checked on the server: a PIN at a\n * kiosk unlocks its settings — choosing the card reader, leaving kiosk mode\n * — for a few minutes. A kiosk faces the public, so it shows no roster of\n * names; the PIN alone is checked against every member of the site who may\n * work the register. The attempt is claimed on the device's own token row\n * BEFORE any PIN is checked, so a burst of guesses gets\n * POS_KIOSK_UNLOCK_MAX_ATTEMPTS in the lockout window and no more, and a\n * member whose own PIN is locked at the register cannot unlock a kiosk\n * either.\n *=========================================*/\n\nfunction unlockSecret(): string {\n const secret = process.env['TOKEN_SIGNING_SECRET']\n if (!secret) throw new Error('TOKEN_SIGNING_SECRET is not configured')\n return secret\n}\n\nfunction signUnlock(payload: string): string {\n return createHmac('sha256', unlockSecret()).update(`pos-kiosk-unlock:${payload}`).digest('hex')\n}\n\n/** A short-lived, signed \"staff unlocked THIS kiosk\". */\nexport function mintPosKioskUnlock(deviceId: string, memberUid: string, nowMs: number): {\n unlock: string\n expiresAtMs: number\n} {\n const expiresAtMs = nowMs + CommerceModel.POS_KIOSK_UNLOCK_TTL_MS\n const payload = Buffer.from(JSON.stringify({ v: 1, d: deviceId, u: memberUid, e: expiresAtMs })).toString(\n 'base64url',\n )\n return { unlock: `${payload}.${signUnlock(payload)}`, expiresAtMs }\n}\n\n/** The member a valid unlock names for this kiosk, or null. */\nexport function readPosKioskUnlock(token: unknown, deviceId: string, nowMs: number): string | null {\n const value = typeof token === 'string' ? token.trim() : ''\n const dot = value.lastIndexOf('.')\n if (dot <= 0 || value.length > 1000) return null\n const payload = value.slice(0, dot)\n let expected: string\n try {\n expected = signUnlock(payload)\n } catch {\n return null\n }\n const a = Buffer.from(value.slice(dot + 1))\n const b = Buffer.from(expected)\n if (a.length !== b.length || !timingSafeEqual(new Uint8Array(a), new Uint8Array(b))) return null\n try {\n const claims = JSON.parse(Buffer.from(payload, 'base64url').toString('utf8'))\n if (claims?.v !== 1 || claims.d !== deviceId || typeof claims.u !== 'string' || !(Number(claims.e) > nowMs)) {\n return null\n }\n return claims.u\n } catch {\n return null\n }\n}\n\n/** Whether a member may still unlock: their role and `managePos` today. */\nasync function mayUnlock(gate: KioskGate, memberUid: string): Promise<boolean> {\n const host = await gate.hostRef.get()\n const role = (host.get('memberRoles') ?? {})[memberUid]\n if (role !== 'admin' && role !== 'editor') return false\n const membership = await resolveOrgPermissions(memberUid, { hostId: gate.hostId })\n return membership?.permissions?.managePos === true\n}\n\nasync function unlock(gate: KioskGate, req: PluginApiRequest, body: Record<string, any>): Promise<Outcome> {\n const pin = String(body['pin'] ?? '')\n if (!/^\\d{4,6}$/.test(pin)) return refuse(400, 'Enter your staff PIN.')\n const address = String(req.socket?.remoteAddress ?? '') || 'no-address'\n const rate = await consumeRateLimit(`pos-kiosk-unlock:${address}`, { limit: 20, windowMs: 15 * 60 * 1000 })\n if (!rate.allowed) return refuse(429, 'Too many tries. Wait a few minutes and try again.')\n try {\n unlockSecret()\n } catch {\n return refuse(501, 'Staff PINs are not configured on this server.')\n }\n const firestore = firebaseAdmin.app().firestore()\n const now = Date.now()\n const claim = await firestore.runTransaction(async (transaction: any) => {\n const snapshot = await transaction.get(gate.device.ref)\n if (!snapshot.exists) return { kind: 'gone' as const }\n const lockedUntilMs = Number(snapshot.get('kioskUnlockLockedUntilMs') ?? 0)\n if (lockedUntilMs > now) return { kind: 'locked' as const, lockedUntilMs }\n const failed = lockedUntilMs ? 0 : Number(snapshot.get('kioskUnlockFailures') ?? 0)\n if (failed >= CommerceModel.POS_KIOSK_UNLOCK_MAX_ATTEMPTS) {\n const until = now + CommerceModel.POS_KIOSK_UNLOCK_LOCKOUT_MS\n transaction.update(gate.device.ref, { kioskUnlockLockedUntilMs: until, kioskUnlockFailures: 0 })\n return { kind: 'locked' as const, lockedUntilMs: until }\n }\n transaction.update(gate.device.ref, { kioskUnlockFailures: failed + 1, kioskUnlockLockedUntilMs: null })\n return { kind: 'claimed' as const, attempt: failed + 1 }\n })\n if (claim.kind === 'gone') return refuse(401, 'This kiosk is not paired.')\n if (claim.kind === 'locked') {\n return { status: 423, body: { error: 'Too many wrong PINs. Try again later.', lockedUntilMs: claim.lockedUntilMs } }\n }\n const host = await gate.hostRef.get()\n const roles = (host.get('memberRoles') ?? {}) as Record<string, string>\n const pins = await gate.hostRef.collection('posStaffPins').limit(50).get()\n let matched = ''\n for (const doc of pins.docs) {\n const uid = String(doc.id)\n if (roles[uid] !== 'admin' && roles[uid] !== 'editor') continue\n if (Number(doc.get('lockedUntilMs') ?? 0) > now) continue\n const hash = String(doc.get('pinScrypt') ?? '')\n if (hash && verifyMemberPassword(pin, hash)) {\n matched = uid\n break\n }\n }\n if (!matched || !(await mayUnlock(gate, matched))) {\n const left = CommerceModel.POS_KIOSK_UNLOCK_MAX_ATTEMPTS - claim.attempt\n if (left <= 0) {\n await gate.device.ref.update({\n kioskUnlockLockedUntilMs: now + CommerceModel.POS_KIOSK_UNLOCK_LOCKOUT_MS,\n kioskUnlockFailures: 0,\n })\n return { status: 423, body: { error: 'Too many wrong PINs. Try again later.' } }\n }\n return { status: 401, body: { error: `That PIN is not right. ${left} ${left === 1 ? 'try' : 'tries'} left.` } }\n }\n await gate.device.ref.update({ kioskUnlockFailures: 0, kioskUnlockLockedUntilMs: null })\n const minted = mintPosKioskUnlock(gate.deviceId, matched, now)\n return { status: 200, body: minted }\n}\n\nasync function staffSettings(\n gate: KioskGate,\n body: Record<string, any>,\n action: 'settings' | 'set-reader' | 'exit',\n): Promise<Outcome> {\n const memberUid = readPosKioskUnlock(body['unlock'], gate.deviceId, Date.now())\n if (!memberUid || !(await mayUnlock(gate, memberUid))) return refuse(401, 'Enter your staff PIN again.')\n if (action === 'exit') {\n // Leaving kiosk mode unpairs the device: a new code from the register\n // is the only way back.\n await gate.device.ref.delete()\n return { status: 200, body: { ok: true } }\n }\n const readers = await registerReaders(gate)\n let data = gate.device.data\n if (action === 'set-reader') {\n const readerId = String(body['readerId'] ?? '')\n if (readerId && !readers.some((reader) => reader.id === readerId)) {\n return refuse(404, 'That card reader is not on this register.')\n }\n await gate.device.ref.set({ kioskReaderId: readerId || null }, { merge: true })\n data = { ...data, kioskReaderId: readerId || null }\n }\n const chosen = await kioskReaderId({ ...gate, device: { ...gate.device, data } })\n return {\n status: 200,\n body: {\n readers,\n readerId: chosen,\n label: String(gate.device.data['label'] ?? 'Self-service kiosk'),\n },\n }\n}\n\n/** A Terminal SDK connection token for the native app's Tap to Pay, scoped to the site's Location. */\nasync function connectionToken(gate: KioskGate): Promise<Outcome> {\n if (!posTerminalAvailable()) return refuse(409, 'Card payments are not available on this kiosk.')\n if (!(await withinBudget(gate, 'connection-token', 60))) return refuse(429, 'Too many tries.')\n const token = await createPosTerminalConnectionToken(gate.hostId)\n if (!token) return refuse(409, 'Set up a card reader location for this site first.')\n return { status: 200, body: token }\n}\n\n/*==========================================\n * THE REGISTER'S SIDE: the queue of \"pay at counter\" orders.\n *=========================================*/\n\nexport interface PosKioskQueueEntry {\n orderId: string\n number: number\n queuedAtMs: number\n totalCents: number\n itemCount: number\n}\n\nasync function staffAction(req: PluginApiRequest, body: Record<string, any>, action: string): Promise<Outcome> {\n const hostId = String(body['hostId'] ?? '')\n const gate = await authorizePosStaff(req, hostId)\n if ('error' in gate) return refuse(gate.status, gate.error)\n const registerId = String(body['registerId'] ?? '')\n if (!/^[A-Za-z0-9_-]{1,128}$/.test(registerId)) return refuse(400, 'Missing registerId')\n const hostRef = firebaseAdmin.app().firestore().collection('hosts').doc(hostId)\n if (!(await hostRef.collection('registers').doc(registerId).get()).exists) {\n return refuse(404, 'Unknown register')\n }\n if (action === 'queue') {\n // `kioskQueueRegisterId ==, status ==, kioskQueuedAtMs ASC`, declared in\n // the index file: the oldest order first, as a counter serves them.\n const snapshot = await hostRef\n .collection('orders')\n .where('kioskQueueRegisterId', '==', registerId)\n .where('status', '==', 'pending')\n .orderBy('kioskQueuedAtMs', 'asc')\n .limit(25)\n .get()\n const entries: PosKioskQueueEntry[] = snapshot.docs.map((doc: any) => {\n const order = CommerceModel.liftLegacyOrder(doc.data()) as CommerceModel.HostOrder\n return {\n orderId: String(doc.id),\n number: Number(order.number ?? 0),\n queuedAtMs: Number(order.kioskQueuedAtMs ?? 0),\n totalCents: Number(order.totals?.totalCents ?? 0),\n itemCount: (order.lineItems ?? []).reduce((sum, line) => sum + line.quantity, 0),\n }\n })\n return { status: 200, body: { entries, currency: await posDisplayCurrency(hostId) } }\n }\n // `take`: the queued order, as the register loads it into its tender panel.\n const orderId = String(body['orderId'] ?? '')\n if (!/^[A-Za-z0-9_-]{1,128}$/.test(orderId)) return refuse(400, 'Missing orderId')\n const order = await readPosSale(hostId, orderId)\n if (!order || order.kioskQueueRegisterId !== registerId) return refuse(404, 'Unknown order')\n if (order.status !== 'pending') return refuse(409, 'This order is no longer waiting for payment.')\n return {\n status: 200,\n body: {\n sale: posSaleSummary(order),\n number: Number(order.number ?? 0),\n lines: (order.lineItems ?? []).map((line) => ({\n productId: line.productId,\n ...(line.variantId ? { variantId: line.variantId } : {}),\n name: line.name,\n ...(line.variantLabel ? { variantLabel: line.variantLabel } : {}),\n unitAmountCents: line.unitAmountCents,\n quantity: line.quantity,\n ...(line.modifiers?.length\n ? { modifiers: line.modifiers.map((modifier) => ({ groupId: modifier.groupId, optionId: modifier.optionId })) }\n : {}),\n })),\n },\n }\n}\n\nexport async function handlePosKiosk(req: PluginApiRequest): Promise<Outcome> {\n const body = req.method === 'GET' ? posQueryBody(req) : posRequestBody(req)\n const action = String(body['action'] ?? '')\n const read = DEVICE_READS.has(action) || STAFF_READS.has(action)\n if (!(req.method === 'POST' || (req.method === 'GET' && read))) {\n return refuse(405, 'Method not allowed')\n }\n if (action === 'queue' || action === 'take') return await staffAction(req, body, action)\n const gate = await authorizeKiosk(req, body, !read)\n if ('status' in gate) return gate\n switch (action) {\n case 'context':\n return await context(gate)\n case 'catalog':\n return await catalog(gate, body)\n case 'sale': {\n const own = await readOwnSale(gate, body['orderId'])\n return 'status' in own ? own : { status: 200, body: { sale: own.view } }\n }\n case 'checkout':\n return await checkout(gate, req, body)\n case 'pay':\n return await pay(gate, req, body)\n case 'payment-status':\n case 'cancel-payment':\n case 'simulate':\n return await cardStep(gate, body, action)\n case 'counter':\n return await sendToCounter(gate, body)\n case 'receipt':\n return await receipt(gate, body)\n case 'abandon':\n return await abandon(gate, body)\n case 'connection-token':\n return await connectionToken(gate)\n case 'unlock':\n return await unlock(gate, req, body)\n case 'settings':\n case 'set-reader':\n case 'exit':\n return await staffSettings(gate, body, action)\n default:\n return refuse(400, 'Unknown action')\n }\n}\n\n/** `GET|POST /api/commerce/pos-kiosk`. */\nexport const posKioskHandler: PluginApiHandler = async (req, res) => {\n res.setHeader('Cache-Control', 'no-store')\n try {\n const outcome = await handlePosKiosk(req)\n return res.status(outcome.status).json(outcome.body)\n } catch (error) {\n console.error('[pos-kiosk]', error)\n return res.status(500).json({ error: 'Something went wrong. Please order at the counter.' })\n }\n}\n"],"names":["createHmac","timingSafeEqual","Aglyn","resolveMediaSrc","pluginSmsAvailable","consumeRateLimit","firebaseAdmin","getLockdownVerdict","getOrgForHost","getPluginConfig","resolveOrgPermissions","CommerceModel","posRegisterSettings","posKioskSettings","verifyMemberPassword","authorizePosStaff","posIdempotencyKey","posQueryBody","posRequestBody","displayBranding","displayToken","posDisplayCurrency","resolveDisplayToken","withPosKioskPrincipal","posOrderHandler","recordReceiptChoice","voidPosSale","posPaymentId","posSaleSummary","readPosSale","posStripeTestMode","posTerminalAvailable","cancelPosCardPayment","createCardPresentIntent","createPosTerminalConnectionToken","refreshPosCardPayment","simulatePosReaderTap","startCardPresentPayment","DEVICE_READS","Set","STAFF_READS","posKioskDeviceId","device","String","ref","id","slice","refuse","status","error","body","authorizeKiosk","req","write","host","owner","register","membership","mode","firestore","app","hostRef","collection","doc","hostId","Promise","all","get","registerId","exists","role","createdBy","permissions","managePos","checkEntitlement","org","locked","uid","data","intent","orgId","config","undefined","catch","deviceId","settings","kiosk","withinBudget","gate","action","limit","rate","windowMs","allowed","registerReaders","snapshot","where","docs","map","label","kioskReaderId","readers","chosen","some","reader","length","receiptChannels","channels","push","printers","empty","context","branding","currency","receipts","value","message","welcome","tipping","enabled","tippingEnabled","percentages","tipPercentages","payments","Boolean","cardPresent","payAtCounter","offerMarketing","displayMarketingOptIn","idleSeconds","testMode","posKioskSellable","product","subscription","subscriptionOptional","giftCard","type","variants","variant","variantHasPrice","posKioskProduct","image","mediaUrls","description","trim","name","imageUrl","categoryIds","options","option","values","filter","priceCents","Math","round","Number","priceUsd","soldOut","stockShortfall","modifierGroups","productModifierGroups","catalog","categoryId","test","query","products","categories","orderBy","POS_KIOSK_CATALOG_LIMIT","liftLegacyProduct","posKioskSaleView","order","posSource","kioskDeviceId","summary","kioskQueueRegisterId","card","reverse","find","payment","isCardPaymentMethod","method","orderId","$id","number","lines","lineItems","line","variantLabel","quantity","amountCents","unitAmountCents","itemsCents","totals","discountCents","taxCents","totalCents","tipCents","paidCents","dueCents","failureMessage","readOwnSale","rawOrderId","view","recorder","result","res","code","json","send","setHeader","redirect","end","checkout","attemptKey","cart","sanitizePosKioskLines","ids","productId","snapshots","Map","deletedAt","variantId","candidate","wanted","other","reduce","sum","priced","headers","cookies","socket","locationId","console","warn","own","kioskStaff","sale","pay","pressed","paymentId","orderPayments","tenderableCents","posKioskTipCents","baseCents","percent","cents","start","cashierId","outcome","readerId","clientSecret","paymentIntentId","cardStep","step","cardNumber","sendToCounter","queued","runTransaction","transaction","fresh","set","kioskQueuedAtMs","Date","now","timeline","appendOrderEvent","merge","after","receipt","channel","includes","to","marketingOptIn","ok","abandon","unlockSecret","secret","process","env","Error","signUnlock","payload","update","digest","mintPosKioskUnlock","memberUid","nowMs","expiresAtMs","POS_KIOSK_UNLOCK_TTL_MS","Buffer","from","JSON","stringify","v","d","u","e","toString","unlock","readPosKioskUnlock","token","dot","lastIndexOf","expected","a","b","Uint8Array","claims","parse","mayUnlock","pin","address","remoteAddress","claim","kind","lockedUntilMs","failed","POS_KIOSK_UNLOCK_MAX_ATTEMPTS","until","POS_KIOSK_UNLOCK_LOCKOUT_MS","kioskUnlockLockedUntilMs","kioskUnlockFailures","attempt","roles","pins","matched","hash","left","minted","staffSettings","delete","connectionToken","staffAction","entries","liftLegacyOrder","queuedAtMs","itemCount","modifiers","modifier","groupId","optionId","handlePosKiosk","read","has","posKioskHandler"],"mappings":"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"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import * as Aglyn from '@aglyn/aglyn/server';
|
|
18
|
+
import type { PluginApiHandler, PluginApiRequest } from '@aglyn/aglyn/server';
|
|
19
|
+
import * as CommerceModel from '../model';
|
|
20
|
+
import { type PosOfflineFlag, type PosOfflineKit, type PosOfflineStockConflict } from '../model/commerce-pos-offline';
|
|
21
|
+
import { type PosOpsDeps, type PosOpsStaff } from './pos-ops-gate';
|
|
22
|
+
import { type StockDecrementOutcome } from './reserve-stock';
|
|
23
|
+
/** The register's sync record: no customer data, only what dedupe and resume need. */
|
|
24
|
+
export interface PosOfflineSyncRecord {
|
|
25
|
+
saleKey: string;
|
|
26
|
+
orderId: string;
|
|
27
|
+
number: number | null;
|
|
28
|
+
signedInUid: string;
|
|
29
|
+
registerId: string;
|
|
30
|
+
soldAtMs: number;
|
|
31
|
+
syncedAtMs: number;
|
|
32
|
+
status: 'recorded' | 'settled';
|
|
33
|
+
flags: PosOfflineFlag[];
|
|
34
|
+
stockConflicts: PosOfflineStockConflict[];
|
|
35
|
+
/** Line indexes whose stock has been taken. */
|
|
36
|
+
stockLines: number[];
|
|
37
|
+
stockDone: boolean;
|
|
38
|
+
notified: boolean;
|
|
39
|
+
}
|
|
40
|
+
export interface PosOfflineAfterSale {
|
|
41
|
+
hostId: string;
|
|
42
|
+
orderId: string;
|
|
43
|
+
order: CommerceModel.HostOrder;
|
|
44
|
+
email: string;
|
|
45
|
+
name: string;
|
|
46
|
+
}
|
|
47
|
+
export interface PosOfflineSyncDeps extends PosOpsDeps {
|
|
48
|
+
/** The plan's take rate for one product type (AGL-2111). */
|
|
49
|
+
feePct(org: Record<string, any> | null, productType: 'physical' | 'digital' | 'service'): number;
|
|
50
|
+
/** Whether the register at this creation rank is within the site's cap (AGL-1775). */
|
|
51
|
+
registerWithinCap(org: Record<string, any> | null, hostId: string, rank: number): boolean;
|
|
52
|
+
/** Takes one line's units off the shelf, with its ledger row (AGL-2320). */
|
|
53
|
+
decrementStock(input: {
|
|
54
|
+
hostRef: FirebaseFirestore.DocumentReference;
|
|
55
|
+
hostId: string;
|
|
56
|
+
productId: string;
|
|
57
|
+
variantId: string;
|
|
58
|
+
quantity: number;
|
|
59
|
+
locationId?: string;
|
|
60
|
+
orderId: string;
|
|
61
|
+
}): Promise<StockDecrementOutcome>;
|
|
62
|
+
/** What a completed sale tells the rest of the workspace. Never throws. */
|
|
63
|
+
afterSale(input: PosOfflineAfterSale): Promise<void>;
|
|
64
|
+
}
|
|
65
|
+
export declare function defaultPosOfflineSyncDeps(): PosOfflineSyncDeps;
|
|
66
|
+
type Outcome = {
|
|
67
|
+
status: number;
|
|
68
|
+
body: Record<string, unknown>;
|
|
69
|
+
};
|
|
70
|
+
/** The store's in-person tax, as every register sale computes it. */
|
|
71
|
+
export declare function posInPersonTax(settings: CommerceModel.TaxSettings | undefined): {
|
|
72
|
+
ok: true;
|
|
73
|
+
pct: number | null;
|
|
74
|
+
pricesIncludeTax: boolean;
|
|
75
|
+
decision: CommerceModel.StorefrontTaxDecision;
|
|
76
|
+
} | {
|
|
77
|
+
ok: false;
|
|
78
|
+
reason: string;
|
|
79
|
+
};
|
|
80
|
+
/** The kit a register caches to sell offline. */
|
|
81
|
+
export declare function buildPosOfflineKit(deps: PosOfflineSyncDeps, staff: PosOpsStaff): Promise<PosOfflineKit>;
|
|
82
|
+
export declare function handlePosOfflineSync(deps: PosOfflineSyncDeps, req: PluginApiRequest): Promise<Outcome>;
|
|
83
|
+
export declare function createPosOfflineSyncHandler(deps?: () => PosOfflineSyncDeps): PluginApiHandler;
|
|
84
|
+
export declare const posOfflineSyncHandler: Aglyn.PluginApiHandler;
|
|
85
|
+
export {};
|