@fayz-ai/admin 0.62.0 → 0.65.2
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/dist/{CommandPalette-B5PMQFDG.js → CommandPalette-XDJJ5E3O.js} +3 -3
- package/dist/{CommandPalette-B5PMQFDG.js.map → CommandPalette-XDJJ5E3O.js.map} +1 -1
- package/dist/ConnectedBrandingSettings-43ZM3HCI.js +680 -0
- package/dist/ConnectedBrandingSettings-43ZM3HCI.js.map +1 -0
- package/dist/ConnectedCompanySettings-I4MALI2Q.js +197 -0
- package/dist/ConnectedCompanySettings-I4MALI2Q.js.map +1 -0
- package/dist/ConnectedModulesSettings-A2VJ5BMJ.js +563 -0
- package/dist/ConnectedModulesSettings-A2VJ5BMJ.js.map +1 -0
- package/dist/ConnectedSecuritySettings-25AHA4HJ.js +189 -0
- package/dist/ConnectedSecuritySettings-25AHA4HJ.js.map +1 -0
- package/dist/ConnectedUserProfile-E7USJRUE.js +424 -0
- package/dist/ConnectedUserProfile-E7USJRUE.js.map +1 -0
- package/dist/FieldRulesEditor-YGIPKI5T.js +129 -0
- package/dist/FieldRulesEditor-YGIPKI5T.js.map +1 -0
- package/dist/GettingStartedWidget-HMIJ3Y24.js +12 -0
- package/dist/GettingStartedWidget-HMIJ3Y24.js.map +1 -0
- package/dist/PermissionProfilesTab-3ZPRCHMZ.js +548 -0
- package/dist/PermissionProfilesTab-3ZPRCHMZ.js.map +1 -0
- package/dist/PersonTimeline-HQZT527S.js +3 -0
- package/dist/{PersonTimeline-X7JTPUWJ.js.map → PersonTimeline-HQZT527S.js.map} +1 -1
- package/dist/ProjectsSettings-7O2F27MD.js +5 -0
- package/dist/ProjectsSettings-7O2F27MD.js.map +1 -0
- package/dist/ScheduleEditor-54ELWR45.js +8 -0
- package/dist/{ScheduleEditor-L2UJXKMY.js.map → ScheduleEditor-54ELWR45.js.map} +1 -1
- package/dist/SeuSiteWidget-QLSUVC63.js +6 -0
- package/dist/SeuSiteWidget-QLSUVC63.js.map +1 -0
- package/dist/SubscriptionPage-5GE5HFJK.js +17 -0
- package/dist/{SubscriptionPage-IDVEFLZ5.js.map → SubscriptionPage-5GE5HFJK.js.map} +1 -1
- package/dist/TeamTab-6RAULFLW.js +502 -0
- package/dist/TeamTab-6RAULFLW.js.map +1 -0
- package/dist/TrialWidget-Z6CLUCU3.js +7 -0
- package/dist/TrialWidget-Z6CLUCU3.js.map +1 -0
- package/dist/app/AdminShell.d.ts.map +1 -1
- package/dist/app/admin-app.d.ts.map +1 -1
- package/dist/app/config.d.ts +14 -0
- package/dist/app/config.d.ts.map +1 -1
- package/dist/app/routing.d.ts +6 -0
- package/dist/app/routing.d.ts.map +1 -1
- package/dist/app/scaffold.d.ts.map +1 -1
- package/dist/billing/index.js +9 -4
- package/dist/chunk-2H46WDG5.js +53 -0
- package/dist/chunk-2H46WDG5.js.map +1 -0
- package/dist/chunk-3HLX7YB2.js +94 -0
- package/dist/chunk-3HLX7YB2.js.map +1 -0
- package/dist/chunk-3OUD4XBK.js +3 -0
- package/dist/chunk-3OUD4XBK.js.map +1 -0
- package/dist/{chunk-IXSY4GPK.js → chunk-5D5QLMOQ.js} +5 -3
- package/dist/chunk-5D5QLMOQ.js.map +1 -0
- package/dist/chunk-5WR62X2R.js +1081 -0
- package/dist/chunk-5WR62X2R.js.map +1 -0
- package/dist/{chunk-KPYRTOCK.js → chunk-6CQFGMEO.js} +4 -140
- package/dist/chunk-6CQFGMEO.js.map +1 -0
- package/dist/chunk-6MMSYC2I.js +116 -0
- package/dist/chunk-6MMSYC2I.js.map +1 -0
- package/dist/chunk-6QFOE3UD.js +1466 -0
- package/dist/chunk-6QFOE3UD.js.map +1 -0
- package/dist/chunk-6UUFVQ2E.js +283 -0
- package/dist/chunk-6UUFVQ2E.js.map +1 -0
- package/dist/chunk-7WNLL3F6.js +7889 -0
- package/dist/chunk-7WNLL3F6.js.map +1 -0
- package/dist/chunk-A74IHAQE.js +439 -0
- package/dist/chunk-A74IHAQE.js.map +1 -0
- package/dist/{chunk-JOBRLBIQ.js → chunk-AFA6IO23.js} +4 -3
- package/dist/chunk-AFA6IO23.js.map +1 -0
- package/dist/{chunk-P5UIGQFY.js → chunk-ALCSIN3Z.js} +5 -5
- package/dist/chunk-ALCSIN3Z.js.map +1 -0
- package/dist/chunk-AWM4AMBS.js +39 -0
- package/dist/chunk-AWM4AMBS.js.map +1 -0
- package/dist/{chunk-OQARLKZN.js → chunk-BG5Z6KLN.js} +6 -18
- package/dist/chunk-BG5Z6KLN.js.map +1 -0
- package/dist/chunk-DPNFZONC.js +19 -0
- package/dist/chunk-DPNFZONC.js.map +1 -0
- package/dist/chunk-DRCV643L.js +193 -0
- package/dist/chunk-DRCV643L.js.map +1 -0
- package/dist/chunk-E6DF3VR6.js +206 -0
- package/dist/chunk-E6DF3VR6.js.map +1 -0
- package/dist/chunk-ENHCVGXZ.js +120 -0
- package/dist/chunk-ENHCVGXZ.js.map +1 -0
- package/dist/chunk-FK6RHGI7.js +56 -0
- package/dist/chunk-FK6RHGI7.js.map +1 -0
- package/dist/chunk-G5HNA5QK.js +233 -0
- package/dist/chunk-G5HNA5QK.js.map +1 -0
- package/dist/chunk-HCFO4Z6A.js +53 -0
- package/dist/chunk-HCFO4Z6A.js.map +1 -0
- package/dist/chunk-JFIU6NQP.js +51 -0
- package/dist/chunk-JFIU6NQP.js.map +1 -0
- package/dist/chunk-JRZJBMOY.js +3 -0
- package/dist/chunk-JRZJBMOY.js.map +1 -0
- package/dist/{chunk-3YP7KW47.js → chunk-JVVOL4BB.js} +41 -512
- package/dist/chunk-JVVOL4BB.js.map +1 -0
- package/dist/chunk-KAQ3UIAA.js +415 -0
- package/dist/chunk-KAQ3UIAA.js.map +1 -0
- package/dist/{chunk-P6XUDT2P.js → chunk-KJELMULA.js} +4 -51
- package/dist/chunk-KJELMULA.js.map +1 -0
- package/dist/chunk-KLO7DKXX.js +1651 -0
- package/dist/chunk-KLO7DKXX.js.map +1 -0
- package/dist/chunk-M2CMDWUI.js +75 -0
- package/dist/chunk-M2CMDWUI.js.map +1 -0
- package/dist/chunk-PQ47MLTH.js +255 -0
- package/dist/chunk-PQ47MLTH.js.map +1 -0
- package/dist/{chunk-VX3WJLKK.js → chunk-QD7BMUDF.js} +17 -8
- package/dist/chunk-QD7BMUDF.js.map +1 -0
- package/dist/{chunk-E4MESMNR.js → chunk-QTSKCPSW.js} +7 -10
- package/dist/chunk-QTSKCPSW.js.map +1 -0
- package/dist/chunk-S56FQKPL.js +186 -0
- package/dist/chunk-S56FQKPL.js.map +1 -0
- package/dist/chunk-SGAFPNMA.js +75 -0
- package/dist/chunk-SGAFPNMA.js.map +1 -0
- package/dist/{chunk-OD7P4L3D.js → chunk-SOKCLVM4.js} +3 -3
- package/dist/{chunk-OD7P4L3D.js.map → chunk-SOKCLVM4.js.map} +1 -1
- package/dist/chunk-TL42NKTH.js +3 -0
- package/dist/chunk-TL42NKTH.js.map +1 -0
- package/dist/chunk-U6ZCO2PS.js +2964 -0
- package/dist/chunk-U6ZCO2PS.js.map +1 -0
- package/dist/chunk-VSXNROYH.js +16 -0
- package/dist/chunk-VSXNROYH.js.map +1 -0
- package/dist/chunk-WPFZCYZL.js +619 -0
- package/dist/chunk-WPFZCYZL.js.map +1 -0
- package/dist/chunk-XFTNIBDW.js +23 -0
- package/dist/chunk-XFTNIBDW.js.map +1 -0
- package/dist/chunk-Y66JDL6I.js +1020 -0
- package/dist/chunk-Y66JDL6I.js.map +1 -0
- package/dist/chunk-YEHIBPIX.js +137 -0
- package/dist/chunk-YEHIBPIX.js.map +1 -0
- package/dist/chunk-YKPPCV2Z.js +53 -0
- package/dist/chunk-YKPPCV2Z.js.map +1 -0
- package/dist/components/chat/markdown.d.ts.map +1 -1
- package/dist/components/plugins/PluginSettingsPanel.d.ts.map +1 -1
- package/dist/components/settings/SettingsPage.d.ts.map +1 -1
- package/dist/connect-XKQJOWR7.js +18 -0
- package/dist/connect-XKQJOWR7.js.map +1 -0
- package/dist/crud/CrudDetailPage.d.ts.map +1 -1
- package/dist/crud/CrudListView.d.ts.map +1 -1
- package/dist/crud/CrudPage.d.ts.map +1 -1
- package/dist/crud/RelatedListTab.d.ts.map +1 -1
- package/dist/crud/archetypes/EntityLink.d.ts +1 -1
- package/dist/crud/archetypes/EntityLink.d.ts.map +1 -1
- package/dist/crud/record-chrome.d.ts.map +1 -1
- package/dist/entity-routes-PGU7EHAD.js +4 -0
- package/dist/{entity-routes-LXOBW5IB.js.map → entity-routes-PGU7EHAD.js.map} +1 -1
- package/dist/hooks/useModuleNavigation.d.ts.map +1 -1
- package/dist/impersonation/ImpersonateDialog.d.ts.map +1 -1
- package/dist/impersonation/session.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11951 -33576
- package/dist/index.js.map +1 -1
- package/dist/lib/attention.d.ts +6 -0
- package/dist/lib/attention.d.ts.map +1 -1
- package/dist/lib/entity-routes.d.ts.map +1 -1
- package/dist/org/index.js +4 -2
- package/dist/plugins/PluginRegistryManager.d.ts.map +1 -1
- package/dist/settings/MessageTemplateRow.d.ts.map +1 -1
- package/dist/timeline/PersonTimeline.d.ts.map +1 -1
- package/dist/timeline/TimelineList.d.ts.map +1 -1
- package/dist/units/UnitRailPage.d.ts.map +1 -1
- package/dist/units/useUnitFilter.d.ts.map +1 -1
- package/package.json +5 -5
- package/dist/PersonTimeline-X7JTPUWJ.js +0 -3
- package/dist/ScheduleEditor-L2UJXKMY.js +0 -6
- package/dist/SubscriptionPage-IDVEFLZ5.js +0 -8
- package/dist/chunk-3YP7KW47.js.map +0 -1
- package/dist/chunk-E4MESMNR.js.map +0 -1
- package/dist/chunk-IXSY4GPK.js.map +0 -1
- package/dist/chunk-JOBRLBIQ.js.map +0 -1
- package/dist/chunk-KPYRTOCK.js.map +0 -1
- package/dist/chunk-OQARLKZN.js.map +0 -1
- package/dist/chunk-P5UIGQFY.js.map +0 -1
- package/dist/chunk-P6XUDT2P.js.map +0 -1
- package/dist/chunk-VX3WJLKK.js.map +0 -1
- package/dist/entity-routes-LXOBW5IB.js +0 -4
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/billing/store.ts","../src/billing/trial.ts","../src/billing/module-pricing.ts","../src/billing/ai-usage.ts"],"names":["paidPlanIds","named","units","React2"],"mappings":"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","file":"chunk-KPYRTOCK.js","sourcesContent":["import { create } from 'zustand'\nimport type { Plan, BillingCheckoutFn } from '@fayz-ai/core'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface Subscription {\n id: string\n orgId: string\n planId: string\n status: 'active' | 'trialing' | 'past_due' | 'canceled' | 'incomplete'\n currentPeriodStart: string\n currentPeriodEnd: string\n cancelAtPeriodEnd?: boolean\n stripeSubscriptionId?: string\n}\n\nexport interface Invoice {\n id: string\n orgId: string\n amount: number\n currency: string\n status: 'paid' | 'open' | 'void' | 'uncollectible'\n pdfUrl?: string\n createdAt: string\n}\n\nexport interface BillingState {\n subscription: Subscription | null\n invoices: Invoice[]\n plans: Plan[]\n loading: boolean\n /** Payment-gateway seam seeded from `config.billing.onCheckout` (see core\n * BillingConfig). When set, the Subscription page routes plan changes through\n * it instead of writing `plan` straight onto the org. */\n checkout: BillingCheckoutFn | null\n}\n\n// ---------------------------------------------------------------------------\n// Store\n// ---------------------------------------------------------------------------\n\nexport interface BillingStore extends BillingState {\n setSubscription: (subscription: Subscription | null) => void\n setInvoices: (invoices: Invoice[]) => void\n setPlans: (plans: Plan[]) => void\n setLoading: (loading: boolean) => void\n setCheckout: (checkout: BillingCheckoutFn | null) => void\n reset: () => void\n}\n\nconst initialState: BillingState = {\n subscription: null,\n invoices: [],\n plans: [],\n loading: false,\n checkout: null,\n}\n\nexport const useBillingStore = create<BillingStore>((set) => ({\n ...initialState,\n setSubscription: (subscription) => set({ subscription }),\n setInvoices: (invoices) => set({ invoices }),\n setPlans: (plans) => set({ plans }),\n setLoading: (loading) => set({ loading }),\n setCheckout: (checkout) => set({ checkout }),\n reset: () => set(initialState),\n}))\n","import * as React from 'react'\nimport type { Organization, Plan } from '@fayz-ai/core'\nimport { useOrganizationStore } from '../org/store'\nimport { useBillingStore } from './store'\n\n/**\n * The free trial, as one derived fact.\n *\n * A trial is not a fourth plan or a state machine — it is a WINDOW during which\n * a tenant on the free plan is entitled to a paid one. Modelling it that way is\n * what keeps it out of every gate in the product: the access provider resolves\n * the effective plan once, and the nav crowns, the entitlement gates, the limit\n * caps and the assistant's lock all follow without knowing a trial exists.\n *\n * `trialEndsAt` is written by the database when the tenant is created (see\n * migration 147) and is never written by the client — a trial the browser could\n * extend is not a trial. A tenant with no `trialEndsAt` predates the column and\n * is left alone: status `none`, plan exactly as stored.\n */\n\nexport type TrialStatus = 'none' | 'active' | 'expired'\n\nexport interface TrialState {\n status: TrialStatus\n /** ISO date the window closes. */\n endsAt?: string\n /** Whole days remaining, floored at 0. `0` on the last day, not a negative. */\n daysLeft: number\n /** The last 48 hours, when the banner stops being informational. */\n endingSoon: boolean\n}\n\nexport const NO_TRIAL: TrialState = { status: 'none', daysLeft: 0, endingSoon: false }\n\nconst DAY_MS = 86_400_000\n\n/** Pure — the part worth testing, and it needs neither React nor a clock. */\nexport function resolveTrial(\n org: Pick<Organization, 'plan' | 'trialEndsAt'> | null | undefined,\n paidPlanIds: ReadonlySet<string>,\n now: number = Date.now(),\n): TrialState {\n if (!org?.trialEndsAt) return NO_TRIAL\n // Somebody who is paying is not on a trial, whatever the column still says.\n if (org.plan && paidPlanIds.has(org.plan)) return NO_TRIAL\n\n const ends = Date.parse(org.trialEndsAt)\n if (Number.isNaN(ends)) return NO_TRIAL\n\n const remaining = ends - now\n if (remaining <= 0) return { status: 'expired', endsAt: org.trialEndsAt, daysLeft: 0, endingSoon: false }\n\n const daysLeft = Math.ceil(remaining / DAY_MS)\n return {\n status: 'active',\n endsAt: org.trialEndsAt,\n daysLeft,\n endingSoon: remaining <= 2 * DAY_MS,\n }\n}\n\n/**\n * The plan whose entitlements apply RIGHT NOW.\n *\n * During the trial that is the trial plan — by default the most expensive one\n * configured, because the point of a trial is to be worth losing. After it, the\n * tenant's own plan, which for a free tenant is the free one: that fall is the\n * paywall, and it needs no separate enforcement path.\n *\n * ── Por que um plano desconhecido cai no piso, e não em `null` ──────────────\n * A frase acima (\"essa queda é o paywall\") só era verdade quando o id gravado\n * em `tenants.plan` existia no catálogo do app. Quando não existia — o\n * ChefControl vendia `starter/professional/enterprise` enquanto o pool grava\n * `free/pro/business` — isto devolvia `null`, e `null` não é \"sem plano\": é SEM\n * TETO. `resolveLimit` lê teto ausente como ilimitado e `isEntitledByPlan` só\n * nega com um `false` explícito. O resultado é que vencer o trial LIBERAVA em\n * vez de travar, que é o oposto do paywall.\n *\n * Então um id que o catálogo não conhece cai no plano mais barato — o piso é a\n * resposta segura para \"não sei em que plano esta conta está\". `null` fica\n * reservado para o único caso em que ilimitado é a leitura certa: o app que não\n * vende plano nenhum e portanto não tem o que travar.\n */\nexport function effectivePlan(\n org: Pick<Organization, 'plan'> | null | undefined,\n plans: Plan[],\n trial: TrialState,\n trialPlanId?: string,\n): Plan | null {\n if (trial.status === 'active') {\n const named = trialPlanId ? plans.find((p) => p.id === trialPlanId) : undefined\n if (named) return named\n const paid = plans.filter((p) => p.price > 0)\n if (paid.length) return paid.reduce((best, p) => (p.price > best.price ? p : best))\n }\n if (plans.length === 0) return null\n\n const named = org?.plan ? plans.find((p) => p.id === org.plan) : undefined\n if (named) return named\n\n const floor = plans.reduce((cheapest, p) => (p.price < cheapest.price ? p : cheapest))\n if (org?.plan) {\n // Avisa alto: é um defeito de dados (catálogo e pool discordando), e quem\n // vê primeiro é quem estiver com o console aberto.\n console.warn(\n `[billing] tenant plan \"${org.plan}\" não existe neste catálogo (${plans.map((p) => p.id).join(', ')}) — aplicando o piso \"${floor.id}\"`,\n )\n }\n return floor\n}\n\n/** Ids of the plans somebody actually pays for. */\nexport function paidPlanIds(plans: Plan[]): Set<string> {\n return new Set(plans.filter((p) => p.price > 0).map((p) => p.id))\n}\n\n/**\n * Live trial state for the current workspace.\n *\n * Ticks once an hour rather than on a timer per second: nothing on screen\n * counts down in real time, and a banner that says \"2 days left\" only has to be\n * right the next time somebody looks at it.\n */\nexport function useTrial(): TrialState {\n const org = useOrganizationStore((s) => s.currentOrg)\n const plans = useBillingStore((s) => s.plans)\n const [now, setNow] = React.useState(() => Date.now())\n\n React.useEffect(() => {\n const id = window.setInterval(() => setNow(Date.now()), 3_600_000)\n return () => window.clearInterval(id)\n }, [])\n\n return React.useMemo(\n () => resolveTrial(org, paidPlanIds(plans), now),\n [org?.plan, org?.trialEndsAt, plans, now],\n )\n}\n","import { tl } from '@fayz-ai/core'\n\n/**\n * Module pricing — the account pays for what it turns on, scaled by how big\n * the operation is. Rationale and the worked examples live in\n * docs/saas/MODULE-PRICING.md; this file is the one place the numbers live.\n */\n\nexport type PriceBasis = 'unit' | 'account'\n\nexport interface PriceEntry {\n /** Monthly list price (BRL) for the first unit, or once for an account-wide item. */\n price: number\n /** `unit`: each unit uses it on its own (a till, a kitchen, a time clock).\n * `account`: one copy serves the whole group (the client base, the DRE). */\n per: PriceBasis\n /** [English, Portuguese] — resolved when quoted, not at import. */\n label: readonly [string, string]\n /** A proposed price for a module not built yet: listed, never billed. */\n comingSoon?: boolean\n}\n\n/** Keyed `plugin` for the module, `plugin.facet` for a paid part of it. Modules\n * not listed cost nothing on their own — they are the floor every account has. */\nexport const PRICE_BOOK: Record<string, PriceEntry> = {\n // Selling and the floor\n orders: { price: 99, per: 'unit', label: ['Orders & POS', 'Pedidos e PDV'] },\n 'orders.scale': { price: 29, per: 'unit', label: ['Scale & sale by weight', 'Balança e venda por peso'] },\n // The orders facet that takes delivery-app orders (iFood, 99Food…).\n 'orders.delivery': { price: 39, per: 'unit', label: ['Delivery & iFood', 'Delivery e iFood'] },\n tables: { price: 79, per: 'unit', label: ['Tables & tabs', 'Salão e mesas'] },\n 'tables.tablets': { price: 39, per: 'unit', label: ['Table tablets', 'Tablets de mesa'] },\n 'tables.waitlist': { price: 29, per: 'unit', label: ['Waitlist', 'Fila de espera'] },\n reservations: { price: 29, per: 'unit', label: ['Reservations', 'Reservas'] },\n menu: { price: 39, per: 'unit', label: ['Menu', 'Cardápio'] },\n 'menu.qr_menu': { price: 29, per: 'unit', label: ['QR menu', 'Cardápio digital (QR)'] },\n production: { price: 49, per: 'unit', label: ['Kitchen (KDS)', 'Cozinha (KDS)'] },\n // The resto preset mounts the kitchen as `kitchen`; same price, never both on.\n kitchen: { price: 49, per: 'unit', label: ['Kitchen (KDS)', 'Cozinha (KDS)'] },\n shop: { price: 79, per: 'account', label: ['Online store', 'Loja online'] },\n // Services\n agenda: { price: 79, per: 'unit', label: ['Schedule', 'Agenda'] },\n 'agenda.public_booking': { price: 29, per: 'unit', label: ['Online booking', 'Agendamento online'] },\n 'agenda.smart_fit': { price: 29, per: 'unit', label: ['Smart fit', 'Encaixe inteligente'] },\n 'agenda.kiosk': { price: 39, per: 'unit', label: ['Kiosks', 'Totens'] },\n clinical: { price: 79, per: 'unit', label: ['Clinical records', 'Prontuário'] },\n // Back office\n inventory: { price: 69, per: 'unit', label: ['Inventory', 'Estoque'] },\n 'inventory.costing': { price: 29, per: 'unit', label: ['Recipe costing & margin', 'Ficha técnica e CMV'] },\n 'inventory.purchasing': { price: 39, per: 'unit', label: ['Purchasing', 'Compras e reposição'] },\n financial: { price: 79, per: 'unit', label: ['Financial', 'Financeiro'] },\n 'financial.reconciliation': { price: 39, per: 'unit', label: ['Bank reconciliation', 'Conciliação bancária'] },\n 'financial.dre': { price: 19, per: 'account', label: ['P&L and cash flow', 'DRE e fluxo de caixa'] },\n 'fiscal-br': { price: 59, per: 'unit', label: ['Invoicing (NFC-e/NF-e)', 'Fiscal (NFC-e/NF-e)'] },\n openbanking: { price: 29, per: 'account', label: ['Open banking', 'Open banking'] },\n workforce: { price: 49, per: 'unit', label: ['Team & shifts', 'Equipe e escala'] },\n 'workforce.time_clock': { price: 39, per: 'unit', label: ['Time clock', 'Ponto eletrônico'] },\n // Clients and growth — one client base for the whole group\n crm: { price: 39, per: 'account', label: ['Clients (CRM)', 'Clientes (CRM)'] },\n 'crm.pipeline': { price: 19, per: 'account', label: ['Sales pipeline', 'Funil de vendas'] },\n 'crm.automation': { price: 29, per: 'account', label: ['Pipeline automations', 'Automações de funil'] },\n 'crm.loyalty': { price: 39, per: 'account', label: ['Club & cashback', 'Clube e Cashback'] },\n conversations: { price: 49, per: 'account', label: ['Conversations (WhatsApp)', 'Conversas (WhatsApp)'] },\n // The upsell every trade gets: an AI attendant answering each unit's WhatsApp.\n // Below a generic AI agent (R$ 500+) and a fraction of a receptionist.\n 'conversations.atendeai': { price: 149, per: 'unit', label: ['AI attendant', 'AtendeAI'] },\n marketing: { price: 49, per: 'account', label: ['Marketing', 'Marketing'] },\n automations: { price: 39, per: 'account', label: ['Automations', 'Automações'] },\n forms: { price: 29, per: 'account', label: ['Forms & contracts', 'Formulários e contratos'] },\n // The forms plugin's runtime id.\n custom_forms: { price: 29, per: 'account', label: ['Forms & contracts', 'Formulários e contratos'] },\n scribe: { price: 49, per: 'account', label: ['AI scribe', 'Escriba (IA)'] },\n reports: { price: 29, per: 'account', label: ['Reports', 'Relatórios'] },\n reputation: { price: 29, per: 'account', label: ['Reviews', 'Avaliações'] },\n sites: { price: 29, per: 'account', label: ['Website', 'Site'] },\n courses: { price: 49, per: 'account', label: ['Courses', 'Cursos'] },\n // Coming soon — proposed prices (docs/saas/PRICING-COMPETITORS.md), never billed.\n tiss: { price: 99, per: 'unit', label: ['Health-plan billing (TISS)', 'Faturamento de Convênio (TISS)'], comingSoon: true },\n 'pet.grooming': { price: 79, per: 'unit', label: ['Bath & grooming', 'Banho e tosa'], comingSoon: true },\n 'pet.vet': { price: 99, per: 'unit', label: ['Vet records', 'Prontuário veterinário'], comingSoon: true },\n 'pet.lodging': { price: 49, per: 'unit', label: ['Pet hotel & daycare', 'Hotel e creche'], comingSoon: true },\n 'pet.packages': { price: 29, per: 'account', label: ['Pet packages', 'Pacotes pet'], comingSoon: true },\n marketplaces: { price: 79, per: 'account', label: ['Marketplaces (Mercado Livre…)', 'Marketplaces (Mercado Livre…)'], comingSoon: true },\n}\n\n/** Modules on the price list that do not exist yet. */\nexport const COMING_SOON_MODULES: readonly string[] = Object.keys(PRICE_BOOK).filter((k) => PRICE_BOOK[k]!.comingSoon)\n\n/** Each extra unit costs less than the one before it: the first pays full, the\n * network's fiftieth pays the price of what it actually adds. */\nexport const UNIT_TIERS: ReadonlyArray<{ from: number; factor: number }> = [\n { from: 1, factor: 1 },\n { from: 2, factor: 0.85 },\n { from: 6, factor: 0.65 },\n { from: 21, factor: 0.45 },\n]\n\nexport const EXTRA_SEAT_PRICE = 19\n\n// ── The base package ───────────────────────────────────────────────────────\n// What a trade's product sells as one line, per unit: ChefControl is the\n// counter, the dining room and the back office; what a house adds on top\n// (delivery, scale, kitchen screen, invoicing, time clock, AI…) is an extra.\n// The lists are data, one place, edited per product — not a flag on a module:\n// Pedidos comes in ChefControl and StoreControl and is an extra for a salon\n// that also sells at a counter.\n\nexport interface BasePackage {\n id: string\n /** The product name the line carries (\"ChefControl · 3 unidades\"). */\n name: string\n /** Per unit, a month; units after the first take the multi-unit discount. */\n unitPrice: number\n /** Modules (and facets, when listed) that come in the package. */\n includes: readonly string[]\n}\n\nconst BACK_OFFICE = ['financial', 'inventory', 'crm', 'forms', 'custom_forms', 'marketing', 'automations', 'reports'] as const\n\nexport const BASE_PACKAGES: Readonly<Record<string, BasePackage>> = {\n // Calibrated so the 3-unit restaurant archetype lands at R$ 1.950 on Scale,\n // the price of the first proposal sent.\n chefcontrol: { id: 'chefcontrol', name: 'ChefControl', unitPrice: 328, includes: [...BACK_OFFICE, 'orders', 'tables', 'menu', 'reservations'] },\n beautycontrol: { id: 'beautycontrol', name: 'BeautyControl', unitPrice: 199, includes: [...BACK_OFFICE, 'agenda'] },\n storecontrol: { id: 'storecontrol', name: 'StoreControl', unitPrice: 189, includes: [...BACK_OFFICE, 'shop', 'orders'] },\n gocontrol: { id: 'gocontrol', name: 'GoControl', unitPrice: 149, includes: [...BACK_OFFICE] },\n}\n\n/** Which package each trade buys. Trades without a product of their own buy GoControl. */\nexport const PACKAGE_BY_TRADE: Readonly<Record<string, string>> = {\n food: 'chefcontrol', beauty: 'beautycontrol', commerce: 'storecontrol',\n}\n\n/** The package for an operation: the one named, else the trade's, else read\n * from what it runs (a counter → ChefControl, a schedule → BeautyControl). */\nexport function packageFor(opts: { package?: string; trades?: readonly string[]; modules?: readonly string[] } = {}): BasePackage {\n if (opts.package && BASE_PACKAGES[opts.package]) return BASE_PACKAGES[opts.package]!\n for (const t of opts.trades ?? []) {\n const id = PACKAGE_BY_TRADE[t]\n if (id) return BASE_PACKAGES[id]!\n }\n const on = new Set(opts.modules ?? [])\n if (['tables', 'menu', 'kitchen', 'production', 'reservations'].some((k) => on.has(k))) return BASE_PACKAGES.chefcontrol!\n if (['agenda', 'clinical'].some((k) => on.has(k))) return BASE_PACKAGES.beautycontrol!\n if (on.has('shop')) return BASE_PACKAGES.storecontrol!\n return BASE_PACKAGES.gocontrol!\n}\n\n/** A module or facet the package covers. A facet is covered only when listed:\n * Pedidos is in ChefControl, Balança (orders.scale) is still an extra. */\nexport function includedIn(pkg: BasePackage | null | undefined, key: string, extra?: readonly string[]): boolean {\n return !!pkg && (pkg.includes.includes(key) || !!extra?.includes(key))\n}\n\nexport interface PricingPlan {\n id: string\n name: readonly [string, string]\n /** Platform fee: login, registries, dashboard, support. Paid once. */\n platformFee: number\n /** Logins included per unit; `null` is unlimited. */\n seatsPerUnit: number | null\n /** Off the modules subtotal (after unit tiers). */\n discount: number\n /** AI assistant credits included a month. */\n aiCredits?: number\n}\n\n/** Credits a free plan includes when the app does not say. */\nexport const FREE_AI_CREDITS = 30\n\n/** Proposal (docs/saas/MODULE-PRICING.md): extra assistant credits, monthly packs. */\n/** The add-on the screen offers when it is off. */\nexport const UPSELL_KEY = 'conversations.atendeai'\n\nexport const EXTRA_AI_CREDITS: ReadonlyArray<{ credits: number; price: number }> = [\n { credits: 100, price: 19 },\n { credits: 1000, price: 149 },\n]\n\n/** `a-la-carte` is the price without a plan; the other ids are the ones\n * `app.plan_grants` uses. */\nexport const PRICING_PLANS: readonly PricingPlan[] = [\n { id: 'a-la-carte', name: ['À la carte', 'Avulso'], platformFee: 99, seatsPerUnit: 3, discount: 0, aiCredits: 50 },\n { id: 'essential', name: ['Essential', 'Essencial'], platformFee: 79, seatsPerUnit: 5, discount: 0, aiCredits: 100 },\n // Pro is the natural middle: a lower fee and a real discount make it the\n // cheapest choice once a salon or restaurant outgrows five logins.\n { id: 'pro', name: ['Pro', 'Pro'], platformFee: 119, seatsPerUnit: 7, discount: 0.08, aiCredits: 300 },\n { id: 'scale', name: ['Scale', 'Scale'], platformFee: 449, seatsPerUnit: null, discount: 0.1, aiCredits: 1000 },\n]\n\n/** One unit and the per-unit modules it actually runs: a dark kitchen has no\n * dining room, so it does not pay for one. */\nexport interface UnitFootprint {\n id: string\n name: string\n modules: readonly string[]\n}\n\nexport interface OperationSize {\n /** Units (stores, branches). At least 1 is charged. */\n units: number\n /** What each unit runs. Absent, every unit runs every per-unit module on. */\n unitModules?: readonly UnitFootprint[]\n /** People with a login. */\n users: number\n /** Active modules and paid facets: `plugin` or `plugin.facet`. */\n modules: readonly string[]\n /** The base package (`BASE_PACKAGES` id). Absent, read from the trade or the modules. */\n package?: string\n /** The trades this operation runs, when known. */\n trades?: readonly string[]\n /** Extras negotiated into the package for this account. */\n alsoIncluded?: readonly string[]\n}\n\nexport type QuoteLineKind = 'platform' | 'package' | 'module' | 'unit' | 'tier' | 'seats' | 'discount' | 'credits'\n\nexport interface QuoteLine {\n kind: QuoteLineKind\n key: string\n label: string\n /** Human formula: \"R$ 79 × 3 unidades\". */\n detail: string\n amount: number\n}\n\nexport interface Quote {\n planId: string\n planName: string\n lines: QuoteLine[]\n total: number\n}\n\nconst round = (n: number) => Math.round(n * 100) / 100\nconst brl = (n: number) => `R$ ${n.toLocaleString('pt-BR', { minimumFractionDigits: 0, maximumFractionDigits: 2 })}`\n\n/** \"Pedidos e PDV, Salão e mesas, … e Análises\" — the package's priced contents. */\nexport function packageSummary(pkg: BasePackage): string {\n const seen = new Set<string>()\n const names = pkg.includes\n .filter((k) => PRICE_BOOK[k])\n .map((k) => tl(...PRICE_BOOK[k]!.label))\n .filter((n) => (seen.has(n) ? false : (seen.add(n), true)))\n return names.length > 1 ? `${names.slice(0, -1).join(', ')} ${tl('and', 'e')} ${names[names.length - 1]}` : names.join('')\n}\n\n/** The share the n-th unit (1-based) pays of its per-unit modules. */\nexport function tierFactorAt(n: number): number {\n let factor = UNIT_TIERS[0]!.factor\n for (const tier of UNIT_TIERS) if (n >= tier.from) factor = tier.factor\n return factor\n}\n\n/** Sum of the tier factors for `units` units: 3 units → 1 + 0.85 + 0.85. */\nexport function unitFactor(units: number): number {\n const n = Math.max(1, Math.floor(units))\n let sum = 0\n for (let i = 1; i <= n; i++) {\n let factor = UNIT_TIERS[0]!.factor\n for (const tier of UNIT_TIERS) if (i >= tier.from) factor = tier.factor\n sum += factor\n }\n return sum\n}\n\n/** Only priced keys, once each, in price-book order. */\nexport function billableModules(modules: readonly string[], pkg?: BasePackage | null, alsoIncluded?: readonly string[]): string[] {\n const on = new Set(modules)\n return Object.keys(PRICE_BOOK).filter((key) => {\n if (!on.has(key) || PRICE_BOOK[key]!.comingSoon || includedIn(pkg, key, alsoIncluded)) return false\n // A facet without its module is not running, so it is not billed.\n const dot = key.indexOf('.')\n return dot < 0 || on.has(key.slice(0, dot))\n })\n}\n\nexport function quote(size: OperationSize, plan: PricingPlan): Quote {\n const units = Math.max(1, Math.floor(size.unitModules?.length || size.units))\n const lines: QuoteLine[] = [{\n kind: 'platform', key: 'platform', label: tl('Platform', 'Plataforma'),\n detail: tl('Login, registries, dashboard and support', 'Acesso, cadastros, painel e suporte'),\n amount: plan.platformFee,\n }]\n\n const footprints = size.unitModules?.length ? size.unitModules : null\n const all = [...size.modules, ...(footprints ?? []).flatMap((u) => u.modules)]\n const pkg = packageFor({ package: size.package, trades: size.trades, modules: all })\n const negotiated = size.alsoIncluded\n\n // The package is ONE line: every unit pays it, the next ones less.\n const base = pkg.unitPrice * unitFactor(units)\n let modules = base\n let tierOff = 0\n lines.push({\n kind: 'package', key: `package:${pkg.id}`,\n label: `${pkg.name} · ${units} ${units === 1 ? tl('unit', 'unidade') : tl('units', 'unidades')}`,\n detail: `${tl('Includes', 'Inclui')} ${packageSummary(pkg)} · ${brl(pkg.unitPrice)} ${tl('the first unit, less for the next', 'a primeira unidade, menos nas seguintes')}`,\n amount: round(base),\n })\n // A unit's add-on switches on its account-wide module too (AtendeAI → Conversas), billed once.\n const on = billableModules(all, pkg, negotiated)\n\n if (footprints) {\n // Each unit is a line with what it runs; the unit that spends most pays in\n // full and the others take the multi-unit discount by their position.\n const perUnit = footprints.map((u) => {\n const keys = billableModules(u.modules, pkg, negotiated).filter((k) => PRICE_BOOK[k]!.per === 'unit')\n return { u, keys, list: keys.reduce((sum, k) => sum + PRICE_BOOK[k]!.price, 0) }\n }).sort((a, b) => b.list - a.list)\n perUnit.forEach(({ u, keys, list }, i) => {\n modules += list\n tierOff += list * (1 - tierFactorAt(i + 1))\n // A unit that runs only the package adds nothing to say.\n if (!keys.length) return\n lines.push({\n kind: 'unit', key: `unit:${u.id}`, label: u.name,\n detail: keys.map((k) => tl(...PRICE_BOOK[k]!.label)).join(' · ') || tl('No per-unit module', 'Nenhum módulo por unidade'),\n amount: list,\n })\n })\n }\n\n let perUnitList = 0\n for (const key of on) {\n const entry = PRICE_BOOK[key]!\n if (footprints && entry.per === 'unit') continue\n const amount = entry.per === 'unit' ? entry.price * units : entry.price\n if (entry.per === 'unit') perUnitList += entry.price\n modules += amount\n lines.push({\n kind: 'module', key, label: tl(...entry.label),\n detail: entry.per === 'unit' && units > 1\n ? `${brl(entry.price)} × ${units} ${tl('units', 'unidades')}`\n : entry.per === 'unit' ? tl('per unit', 'por unidade') : tl('whole group', 'grupo todo'),\n amount,\n })\n }\n\n // Volume: units beyond the first pay a smaller share of the per-unit modules.\n if (!footprints) tierOff = perUnitList * (units - unitFactor(units))\n tierOff = round(tierOff)\n if (tierOff > 0) {\n lines.push({\n kind: 'tier', key: 'unit-tiers', label: tl('Multi-unit discount', 'Desconto por unidade adicional'),\n detail: tl('Units 2–5 pay 85%, 6–20 pay 65%, 21+ pay 45%', 'Unidades 2–5 pagam 85%, 6–20 pagam 65%, 21+ pagam 45%'),\n amount: -tierOff,\n })\n }\n\n if (plan.discount > 0 && modules > 0) {\n const off = round((modules - tierOff) * plan.discount)\n lines.push({\n kind: 'discount', key: 'plan-discount', label: `${tl('Plan discount', 'Desconto do plano')} ${tl(...plan.name)}`,\n detail: `${Math.round(plan.discount * 100)}% ${tl('off the modules', 'sobre os módulos')}`,\n amount: -off,\n })\n }\n\n if (plan.seatsPerUnit === null) {\n lines.push({ kind: 'seats', key: 'seats', label: tl('Users', 'Usuários'), detail: tl('Unlimited', 'Ilimitados'), amount: 0 })\n } else {\n const included = plan.seatsPerUnit * units\n const extra = Math.max(0, Math.floor(size.users) - included)\n lines.push({\n kind: 'seats', key: 'seats', label: tl('Users', 'Usuários'),\n detail: extra > 0\n ? `${extra} ${tl('beyond the', 'além dos')} ${included} ${tl('included', 'incluídos')} × ${brl(EXTRA_SEAT_PRICE)}`\n : `${Math.floor(size.users)} ${tl('of', 'de')} ${included} ${tl('included', 'incluídos')}`,\n amount: extra * EXTRA_SEAT_PRICE,\n })\n }\n\n if (plan.aiCredits) {\n lines.push({\n kind: 'credits', key: 'ai-credits', label: tl('AI assistant', 'Assistente de IA'),\n detail: `${plan.aiCredits.toLocaleString('pt-BR')} ${tl('credits/mo included', 'créditos/mês incluídos')}`,\n amount: 0,\n })\n }\n\n const total = round(lines.reduce((sum, line) => sum + line.amount, 0))\n return { planId: plan.id, planName: tl(...plan.name), lines, total }\n}\n\n/** Every plan for one operation, cheapest first marked by the caller. */\nexport function quoteAll(size: OperationSize, plans: readonly PricingPlan[] = PRICING_PLANS): Quote[] {\n return plans.map((plan) => quote(size, plan))\n}\n\n/** The plugin runtime's view of what is on, as price-book keys. */\n/** The plugin runtime's view of what is on, as price-book keys. A plugin\n * running only because another needs it (orders under a salon's agenda) is not\n * something the account chose, so it is not billed; with `trades`/`offered`,\n * only what the account's trade offers counts. */\nexport function activeModuleKeys(\n plugins: ReadonlyArray<{ id: string; isActive?: boolean; activationReason?: string; config?: { facets?: unknown } | null }>,\n opts: { trades?: readonly Trade[]; offered?: readonly string[] } = {},\n): string[] {\n const out: string[] = []\n for (const plugin of plugins) {\n if (!plugin.isActive || plugin.activationReason === 'dependency') continue\n if (opts.offered?.length && !opts.offered.includes(plugin.id)) continue\n const keys = [plugin.id]\n const facets = (plugin.config?.facets ?? {}) as Record<string, boolean>\n for (const [facet, on] of Object.entries(facets)) if (on) keys.push(`${plugin.id}.${facet}`)\n out.push(...(opts.trades?.length ? keys.filter((k) => moduleFitsTrades(k, opts.trades!)) : keys))\n }\n return out\n}\n\n// ── Which trade a module belongs to ────────────────────────────────────────\n// One place for the rule \"o ofício oferece\": the pricing sheet and the Módulos\n// page both read it. A salon never sees Pedidos e PDV; a restaurant books\n// through Reservas, never Agenda.\n\n/** The same vocabulary as `tenants.vertical_id` (097). */\n// `pet` has no app yet; it tags the coming-soon pet modules.\nexport type Trade = 'food' | 'beauty' | 'commerce' | 'education' | 'events' | 'accounting' | 'generic' | 'pet'\n\nconst FOOD_COMMERCE: readonly Trade[] = ['food', 'commerce']\nconst SERVICES: readonly Trade[] = ['beauty', 'education']\n\n/** Keys missing here (financial, crm, inventory…) serve every trade. */\nexport const MODULE_TRADES: Readonly<Record<string, readonly Trade[]>> = {\n orders: FOOD_COMMERCE,\n 'orders.scale': FOOD_COMMERCE,\n 'orders.delivery': FOOD_COMMERCE,\n shop: ['commerce', 'food'],\n tables: ['food'],\n 'tables.tablets': ['food'],\n 'tables.waitlist': ['food'],\n reservations: ['food'],\n menu: ['food'],\n 'menu.qr_menu': ['food'],\n production: ['food'],\n kitchen: ['food'],\n 'inventory.costing': ['food'],\n agenda: SERVICES,\n 'agenda.public_booking': SERVICES,\n 'agenda.smart_fit': SERVICES,\n 'agenda.kiosk': SERVICES,\n clinical: ['beauty'],\n scribe: ['beauty'],\n courses: ['education'],\n tiss: ['beauty'],\n 'pet.grooming': ['pet'],\n 'pet.vet': ['pet'],\n 'pet.lodging': ['pet'],\n 'pet.packages': ['pet'],\n marketplaces: ['commerce'],\n}\n\n/** The trade each app (`app.apps.id`) sells to — 097's table. */\nexport const TRADE_BY_APP: Readonly<Record<string, Trade>> = {\n resto: 'food', beauty: 'beauty', shop: 'commerce', school: 'education',\n ticket: 'events', fiscal: 'accounting', full: 'generic',\n}\n\n/** A module (or facet) that serves at least one of `trades`. */\nexport function moduleFitsTrades(key: string, trades: readonly Trade[]): boolean {\n const own = MODULE_TRADES[key] ?? MODULE_TRADES[key.split('.')[0]!]\n return !own || own.some((t) => trades.includes(t))\n}\n\n/** Every priced key this trade can turn on, in price-book order. */\nexport function modulesForTrade(trade: Trade): string[] {\n return Object.keys(PRICE_BOOK).filter((k) => moduleFitsTrades(k, [trade]))\n}\n\n/** The per-unit priced modules among `modules`, for a unit's footprint. */\nexport function perUnitModules(modules: readonly string[], pkg?: BasePackage | null): string[] {\n return billableModules(modules, pkg).filter((k) => PRICE_BOOK[k]!.per === 'unit')\n}\n\n/** Generic operations the Assinatura screen prices next to the account's own.\n * Shipped to every tenant: archetypes only, never a customer's name or size. */\nexport type ScenarioVertical = 'food' | 'beauty' | 'commerce' | 'generic'\n\nexport interface PricingScenario {\n id: string\n name: readonly [string, string]\n vertical: ScenarioVertical\n assumptions?: readonly string[]\n size: OperationSize\n}\n\nexport const SCENARIO_VERTICAL_LABELS: Record<ScenarioVertical, readonly [string, string]> = {\n food: ['Food service', 'Alimentação'],\n beauty: ['Beauty & clinics', 'Beleza e clínicas'],\n commerce: ['Retail & e-commerce', 'Varejo e loja online'],\n generic: ['Other', 'Outros'],\n}\n\nconst BEAUTY_UNIT = ['agenda', 'inventory', 'financial', 'fiscal-br', 'workforce'] as const\nconst BEAUTY_ACCOUNT = ['crm', 'marketing', 'automations', 'custom_forms', 'reports'] as const\nconst RESTAURANT_UNIT = ['orders', 'orders.delivery', 'tables', 'reservations', 'menu', 'menu.qr_menu', 'kitchen', 'inventory', 'inventory.costing', 'financial', 'fiscal-br', 'workforce'] as const\nconst units = (n: number, prefix: string, modules: readonly string[]): UnitFootprint[] =>\n Array.from({ length: n }, (_, i) => ({ id: `${prefix}-${i + 1}`, name: `${prefix === 'u' ? 'Unidade' : prefix} ${i + 1}`, modules }))\n\nexport const PRICING_SCENARIOS: ReadonlyArray<PricingScenario> = [\n {\n // Calibration point: a three-format restaurant group lands near R$ 1.950 on the top plan.\n id: 'restaurante-3-unidades',\n name: ['Restaurant group, 3 units (store, dining room, dark kitchen)', 'Restaurante com 3 unidades (empório, salão, dark kitchen)'],\n vertical: 'food',\n assumptions: ['Usuários ilimitados no plano de cima; 40 pessoas com login.'],\n size: {\n units: 3,\n users: 40,\n modules: ['crm', 'financial', 'financial.dre', 'reports'],\n unitModules: [\n { id: 'emporio', name: 'Empório', modules: ['orders', 'orders.scale', 'orders.delivery', 'inventory', 'inventory.purchasing', 'financial', 'financial.reconciliation', 'fiscal-br', 'workforce', 'workforce.time_clock'] },\n { id: 'salao', name: 'Restaurante com salão', modules: ['tables', 'reservations', 'menu', 'menu.qr_menu', 'orders', 'orders.delivery', 'production', 'inventory', 'inventory.costing', 'financial', 'fiscal-br', 'workforce', 'workforce.time_clock'] },\n { id: 'dark', name: 'Dark kitchen', modules: ['orders', 'orders.delivery', 'production', 'inventory', 'inventory.costing', 'financial', 'fiscal-br', 'workforce', 'workforce.time_clock'] },\n ],\n },\n },\n {\n id: 'cafe',\n name: ['Café, 1 unit', 'Café de 1 unidade'],\n vertical: 'food',\n size: { units: 1, users: 4, modules: ['orders', 'financial', 'inventory', 'fiscal-br'] },\n },\n {\n id: 'rede-10',\n name: ['Restaurant network, 10 units', 'Rede de restaurantes, 10 unidades'],\n vertical: 'food',\n size: {\n units: 10,\n users: 120,\n modules: ['orders', 'orders.delivery', 'menu', 'menu.qr_menu', 'production', 'inventory', 'inventory.costing', 'financial', 'financial.dre', 'fiscal-br', 'workforce', 'workforce.time_clock', 'crm', 'crm.loyalty', 'reports'],\n },\n },\n {\n id: 'restaurante-e-servicos',\n name: ['Restaurant + back office, 2 units', 'Restaurante + escritório, 2 unidades'],\n vertical: 'food',\n assumptions: ['Uma unidade com toda a operação; a outra só com financeiro, equipe e ponto.'],\n size: {\n units: 2,\n users: 25,\n modules: ['crm', 'financial', 'financial.dre', 'reports'],\n unitModules: [\n { id: 'restaurante', name: 'Restaurante', modules: [...RESTAURANT_UNIT] },\n { id: 'escritorio', name: 'Escritório', modules: ['financial', 'workforce', 'workforce.time_clock'] },\n ],\n },\n },\n {\n id: 'rede-estetica-60',\n name: ['Beauty network, 60 units', 'Rede de estética, 60 unidades'],\n vertical: 'beauty',\n assumptions: ['Todas as unidades com agenda, prontuário, estoque, financeiro, fiscal e equipe; 6 logins por unidade.'],\n size: { units: 60, users: 360, modules: [...BEAUTY_ACCOUNT, 'financial', 'financial.dre'], unitModules: units(60, 'u', [...BEAUTY_UNIT, 'clinical']) },\n },\n {\n id: 'saloes-3',\n name: ['Salon chain, 3 units', 'Rede de salões, 3 unidades'],\n vertical: 'beauty',\n size: { units: 3, users: 24, modules: [...BEAUTY_ACCOUNT, 'financial', 'financial.dre'], unitModules: units(3, 'u', [...BEAUTY_UNIT]) },\n },\n {\n id: 'salao-1',\n name: ['Salon, 1 unit', 'Salão de 1 unidade'],\n vertical: 'beauty',\n size: { units: 1, users: 6, modules: [...BEAUTY_UNIT, ...BEAUTY_ACCOUNT] },\n },\n {\n id: 'clinica-1',\n name: ['Aesthetic clinic, 1 unit', 'Clínica de estética, 1 unidade'],\n vertical: 'beauty',\n size: { units: 1, users: 5, modules: ['agenda', 'clinical', 'financial', 'fiscal-br', 'crm', 'custom_forms'] },\n },\n {\n id: 'cozinha-loja-online',\n name: ['Central kitchen + online store', 'Cozinha central + loja online'],\n vertical: 'food',\n size: { units: 1, users: 9, modules: ['shop', 'orders', 'kitchen', 'inventory', 'inventory.costing', 'inventory.purchasing', 'financial', 'fiscal-br', 'crm'] },\n },\n {\n id: 'loja-online-fisica',\n name: ['Online store + physical store', 'Loja online + loja física'],\n vertical: 'commerce',\n size: {\n units: 2,\n users: 4,\n modules: ['shop', 'financial', 'crm'],\n unitModules: [\n { id: 'online', name: 'Loja online', modules: ['orders', 'inventory', 'financial'] },\n { id: 'fisica', name: 'Loja física', modules: ['orders', 'inventory', 'financial', 'fiscal-br'] },\n ],\n },\n },\n]\n\n/** The slice of an app plan the price model reads. */\nexport interface PricedPlanSource {\n id: string\n name: string\n price: number\n pricing?: { platformFee: number; seatsPerUnit: number | null; discount: number; aiCredits?: number }\n entitlements?: { limits?: Record<string, number> }\n}\n\n/**\n * Price-model parameters for each app plan, in the same order. A plan's own\n * `pricing` wins; otherwise paid plans take the model's tiers from the top\n * (the richest plan is Scale) and a free plan stays free (`null`).\n */\nexport function pricingForPlans(plans: readonly PricedPlanSource[]): Array<PricingPlan | null> {\n const tiers = PRICING_PLANS.filter((p) => p.id !== 'a-la-carte')\n const paid = plans.filter((p) => p.price > 0 && !p.pricing).sort((a, b) => a.price - b.price)\n return plans.map((plan) => {\n const declared = plan.entitlements?.limits?.ai_credits_month\n const credits = declared !== undefined && declared >= 0 ? { aiCredits: declared } : {}\n if (plan.pricing) return { id: plan.id, name: [plan.name, plan.name], ...plan.pricing, ...credits }\n if (plan.price <= 0) return null\n const rank = paid.indexOf(plan) - paid.length + tiers.length\n const tier = tiers[Math.max(0, rank)]!\n return { ...tier, id: plan.id, name: [plan.name, plan.name], ...credits }\n })\n}\n\nexport type PlanFit = { fits: true } | { fits: false; limit: 'locations' | 'users'; max: number; have: number }\n\n/** AI credits a plan includes a month: what the app declares, else the mapped\n * tier, else the free allowance. */\nexport function aiCreditsFor(plan: PricedPlanSource, pricing: PricingPlan | null): number {\n const declared = plan.entitlements?.limits?.ai_credits_month\n if (declared !== undefined && declared >= 0) return declared\n return pricing?.aiCredits ?? FREE_AI_CREDITS\n}\n\n/** Whether the operation fits the plan's caps (units, logins); -1 is unlimited. */\nexport function planFit(plan: PricedPlanSource, size: Pick<OperationSize, 'units' | 'users' | 'unitModules'>): PlanFit {\n const limits = plan.entitlements?.limits ?? {}\n const units = size.unitModules?.length || size.units\n const checks: Array<['locations' | 'users', number]> = [['locations', units], ['users', size.users]]\n for (const [limit, have] of checks) {\n const max = limits[limit]\n if (max !== undefined && max >= 0 && have > max) return { fits: false, limit, max, have }\n }\n return { fits: true }\n}\n","import * as React from 'react'\nimport { getSupabaseClientOptional } from '../lib/supabase'\nimport { useOrganizationStore } from '../org/store'\n\n/** What the usage source reports for one period. */\nexport interface AiUsageRaw {\n /** Credits spent per member (this tenant only — the source is tenant-scoped). */\n byUser: Array<{ userId: string; credits: number }>\n /** Credits per feature key: `assistant`, `atendeai`, `scribe`… */\n byFeature: Array<{ feature: string; credits: number }>\n}\n\nexport interface AiUsageSummary {\n used: number\n included: number\n remaining: number\n /** 0–1+, used ÷ included. */\n ratio: number\n over: boolean\n /** Credits beyond the allowance. */\n overBy: number\n periodStart: Date\n periodEnd: Date\n daysLeft: number\n /** Credits at the end of the period at the current daily pace. */\n projected: number\n projectedOver: boolean\n byUser: Array<{ userId: string; name: string; credits: number }>\n byFeature: Array<{ feature: string; credits: number }>\n}\n\nconst DAY = 86_400_000\n\n/** The billing period: the calendar month `now` falls in. */\nexport function currentPeriod(now: Date = new Date()): { start: Date; end: Date } {\n return {\n start: new Date(now.getFullYear(), now.getMonth(), 1),\n end: new Date(now.getFullYear(), now.getMonth() + 1, 1),\n }\n}\n\n/** Pure: the period's numbers from what the source reported. */\nexport function summarizeAiUsage(\n raw: AiUsageRaw,\n included: number,\n now: Date = new Date(),\n names: Record<string, string> = {},\n): AiUsageSummary {\n const { start, end } = currentPeriod(now)\n const used = raw.byUser.reduce((sum, u) => sum + u.credits, 0)\n const elapsedDays = Math.max(1, (now.getTime() - start.getTime()) / DAY)\n const totalDays = Math.round((Date.UTC(end.getFullYear(), end.getMonth(), 1) - Date.UTC(start.getFullYear(), start.getMonth(), 1)) / DAY)\n const projected = Math.round((used / elapsedDays) * totalDays)\n return {\n used,\n included,\n remaining: Math.max(0, included - used),\n ratio: included > 0 ? used / included : used > 0 ? Infinity : 0,\n over: used > included,\n overBy: Math.max(0, used - included),\n periodStart: start,\n periodEnd: end,\n // Calendar days, so a daylight-saving hour never adds one.\n daysLeft: Math.max(0, Math.round((Date.UTC(end.getFullYear(), end.getMonth(), end.getDate()) - Date.UTC(now.getFullYear(), now.getMonth(), now.getDate())) / DAY)),\n projected,\n projectedOver: projected > included,\n byUser: [...raw.byUser]\n .sort((a, b) => b.credits - a.credits)\n // Someone who spent credits and has since left the team.\n .map((u) => ({ ...u, name: names[u.userId] ?? 'Ex-integrante da equipe' })),\n byFeature: [...raw.byFeature].sort((a, b) => b.credits - a.credits),\n }\n}\n\nexport type AiUsageState =\n | { status: 'loading' }\n /** No meter is recording credits yet: the screen says so, it shows no number. */\n | { status: 'not-metered' }\n /** Metered, nothing spent this period. */\n | { status: 'empty'; summary: AiUsageSummary }\n | { status: 'ok'; summary: AiUsageSummary }\n\n/**\n * This tenant's AI credit usage in the current period, read from the\n * `ai_usage_summary(p_from, p_to)` RPC — the seam the assistant broker writes\n * behind. Until that RPC exists the state is `not-metered`, never a guess.\n */\nexport function useAiUsage(included: number): AiUsageState {\n const tenantId = useOrganizationStore((s) => s.currentOrg?.id ?? null)\n const members = useOrganizationStore((s) => s.members)\n const [raw, setRaw] = React.useState<AiUsageRaw | null | 'missing'>(null)\n\n React.useEffect(() => {\n const supabase = getSupabaseClientOptional() as any\n if (!supabase || !tenantId) { setRaw('missing'); return }\n let alive = true\n const { start, end } = currentPeriod()\n void supabase.rpc('ai_usage_summary', { p_from: start.toISOString(), p_to: end.toISOString() })\n .then((res: { data: any; error: any }) => {\n if (!alive) return\n if (res.error || !res.data) { setRaw('missing'); return }\n setRaw({\n byUser: (res.data.by_user ?? []).map((u: any) => ({ userId: String(u.user_id), credits: Number(u.credits) || 0 })),\n byFeature: (res.data.by_feature ?? []).map((f: any) => ({ feature: String(f.feature), credits: Number(f.credits) || 0 })),\n })\n })\n return () => { alive = false }\n }, [tenantId])\n\n const names = React.useMemo(() => {\n const out: Record<string, string> = {}\n for (const m of members) out[m.userId] = m.user?.fullName || m.user?.email || '—'\n return out\n }, [members])\n\n if (raw === null) return { status: 'loading' }\n if (raw === 'missing') return { status: 'not-metered' }\n const summary = summarizeAiUsage(raw, included, new Date(), names)\n return summary.used > 0 ? { status: 'ok', summary } : { status: 'empty', summary }\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/billing/plan-badge.ts","../src/billing/TrialWidget.tsx"],"names":[],"mappings":"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","file":"chunk-OQARLKZN.js","sourcesContent":["import type { Plan } from '@fayz-ai/core'\n\nexport interface PlanBadgeInfo {\n /** Display label, e.g. 'Free' or 'Pro'. */\n label: string\n /** Resolved plan id (falls back to the raw org.plan string). */\n planId: string\n /** Paid plan (price > 0) — drives the Crown icon + gold styling in the menus. */\n paid: boolean\n}\n\nfunction capitalize(s: string): string {\n return s ? s.charAt(0).toUpperCase() + s.slice(1) : s\n}\n\n/**\n * Resolve an org's `plan` string against the configured billing plans into the\n * badge shown next to the user in both menus. Falls back to a capitalized\n * version of the raw string when the id isn't in config (defensive — e.g. a\n * legacy 'free' tenant before billing was wired).\n */\nexport function resolvePlanBadge(\n planId: string | undefined | null,\n plans: Plan[],\n): PlanBadgeInfo {\n const id = planId || 'free'\n const match = plans.find((p) => p.id === id)\n if (match) {\n return { label: match.name, planId: match.id, paid: match.price > 0 }\n }\n return { label: capitalize(id), planId: id, paid: false }\n}\n","import * as React from 'react'\nimport { Clock, Crown } from 'lucide-react'\nimport { tl } from '@fayz-ai/core'\nimport { cn } from '../lib/cn'\nimport { navigateTo } from '../app/routing'\nimport { Button, useLayoutStore } from '@fayz-ai/ui'\nimport { useTrial } from './trial'\n\nexport interface TrialWidgetProps {\n /** Length of the window, for the progress bar. Matches the DB column default (migration 044). */\n totalDays?: number\n /** Where \"see the plans\" goes. */\n route?: string\n className?: string\n}\n\n/**\n * The trial, in the rail.\n *\n * A countdown is a promise about the future, so it belongs where somebody looks\n * at their own progress — one line under the getting-started checklist, in the\n * menu's own colours, not a banner across the app. Two states only:\n *\n * • RUNNING — informational, and quiet until the last two days.\n * • ENDED — the paywall's face. It stops being a note and becomes a button,\n * because at that point every gated feature in the product is already\n * answering \"not on your plan\" and this is the one place that says why.\n *\n * There is no third state: a paying tenant, or one that predates trials, gets\n * nothing at all.\n */\nexport function TrialWidget({ totalDays = 30, route = '/settings/subscription', className }: TrialWidgetProps) {\n const trial = useTrial()\n const collapsed = useLayoutStore((s) => s.sidebarCollapsed)\n\n if (trial.status === 'none') return null\n\n const expired = trial.status === 'expired'\n const pct = Math.max(0, Math.min(100, (trial.daysLeft / totalDays) * 100))\n\n const label = expired\n ? tl('Trial ended', 'Seu teste terminou')\n : trial.daysLeft <= 1\n ? tl('Last day of your trial', 'Último dia do teste')\n : tl(`${trial.daysLeft} days of trial left`, `${trial.daysLeft} dias de teste`)\n\n if (collapsed) {\n return (\n <Button\n variant=\"bare\"\n size=\"bare\"\n type=\"button\"\n onClick={() => navigateTo(route)}\n title={label}\n aria-label={label}\n data-tour=\"billing.trial\"\n className={cn(\n 'flex w-full items-center justify-center rounded-button p-1.5 transition-colors',\n expired\n ? 'bg-primary/15 text-primary hover:bg-primary/25'\n : 'text-sidebar-foreground/70 hover:bg-sidebar-accent/60',\n className,\n )}\n >\n {expired ? <Crown className=\"h-4 w-4\" /> : <Clock className=\"h-4 w-4\" />}\n </Button>\n )\n }\n\n return (\n <Button\n variant=\"bare\"\n size=\"bare\"\n type=\"button\"\n onClick={() => navigateTo(route)}\n data-tour=\"billing.trial\"\n className={cn(\n 'w-full rounded-button px-1.5 py-1.5 text-left transition-colors inline-block whitespace-normal text-[length:inherit] font-normal',\n expired ? 'bg-primary/15 hover:bg-primary/25' : 'hover:bg-sidebar-accent/50',\n className,\n )}\n >\n <span className=\"flex items-center gap-2\">\n {expired\n ? <Crown className=\"h-3.5 w-3.5 shrink-0 text-primary\" />\n : <Clock className={cn('h-3.5 w-3.5 shrink-0', trial.endingSoon ? 'text-warning' : 'text-sidebar-muted')} />}\n <span\n className={cn(\n 'min-w-0 flex-1 truncate text-[12px] font-medium',\n expired ? 'text-sidebar-foreground' : 'text-sidebar-foreground/90',\n )}\n >\n {label}\n </span>\n </span>\n {expired ? (\n <span className=\"mt-1 block pl-[22px] text-[11px] leading-snug text-sidebar-muted\">\n {tl('Choose a plan to keep the assistant', 'Escolha um plano para manter o assistente')}\n </span>\n ) : (\n <span className=\"mt-1.5 block h-1 overflow-hidden rounded-full bg-sidebar-accent\">\n <span\n className={cn(\n 'block h-full rounded-full transition-all',\n trial.endingSoon ? 'bg-warning' : 'bg-sidebar-foreground/70',\n )}\n style={{ width: `${pct}%` }}\n />\n </span>\n )}\n </Button>\n )\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/entity-routes.ts"],"names":[],"mappings":"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","file":"chunk-P5UIGQFY.js","sourcesContent":["/**\n * Global entity route registry.\n *\n * Populated once during buildNavigation() with mappings from\n * \"archetype:kind\" (e.g. \"person:staff\") to the registered route path\n * (e.g. \"/registry/staff\"). Used by PersonLink, command palette, and\n * any component that needs to resolve an entity detail URL.\n *\n * An entry records whether the route can take an id: a CRUD page owns\n * `/path/:id`, a hand-built page (the agenda) only has its list.\n */\n\nimport { navigateTo } from '../app/routing'\n\nexport interface EntityRouteEntry {\n path: string\n /** The route renders `${path}/${id}` as a detail view. */\n detail: boolean\n}\n\nlet routeMap = new Map<string, EntityRouteEntry>()\n\n/** Replace the entity route map (called once at app init by buildNavigation).\n * Accepts the legacy `Map<string, string>` shape (all detail-capable). */\nexport function setEntityRouteMap(map: Map<string, EntityRouteEntry | string>): void {\n const next = new Map<string, EntityRouteEntry>()\n for (const [key, value] of map) {\n next.set(key, typeof value === 'string' ? { path: value, detail: true } : value)\n }\n routeMap = next\n}\n\nfunction lookup(archetype?: string, kind?: string, entityKey?: string): EntityRouteEntry | null {\n if (archetype && kind) {\n const specific = routeMap.get(`${archetype}:${kind}`)\n if (specific) return specific\n }\n if (archetype) {\n const general = routeMap.get(archetype)\n if (general) return general\n }\n // The only route a non-archetype entity has — without it a plugin registry\n // is findable by search and unopenable.\n if (entityKey) {\n const byKey = routeMap.get(entityKey)\n if (byKey) return byKey\n }\n return null\n}\n\n/**\n * Resolve the route path for an entity given its archetype and kind.\n * Returns the registered path (e.g. \"/registry/staff\") or null if not found.\n *\n * Tries \"archetype:kind\", then \"archetype\", then the entity key.\n */\nexport function resolveEntityRoute(archetype?: string, kind?: string, entityKey?: string): string | null {\n return lookup(archetype, kind, entityKey)?.path ?? null\n}\n\n/** Whether the resolved route can show a single record, or only its list. */\nexport function entityRouteHasDetail(archetype?: string, kind?: string, entityKey?: string): boolean {\n return lookup(archetype, kind, entityKey)?.detail ?? false\n}\n\n/**\n * Build a full URL path for an entity detail page.\n * Returns e.g. \"/registry/staff/uuid\" or \"/registry/staff/uuid/schedule\".\n * Falls back to \"/kind/uuid\" if no route registered.\n *\n * A list-only route (a plugin page that shows these records but has no detail\n * view) returns the bare path — appending an id there is a dead end.\n */\nexport function resolveEntityHref(id: string, archetype?: string, kind?: string, tab?: string, entityKey?: string): string {\n const entry = lookup(archetype, kind, entityKey)\n if (entry && !entry.detail) return entry.path\n\n let href: string\n if (entry) {\n href = `${entry.path}/${id}`\n } else if (kind) {\n const plural = kind.endsWith('s') ? kind : kind + 's'\n href = `/${plural}/${id}`\n } else {\n href = `/${id}`\n }\n if (tab) href += `/${tab}`\n return href\n}\n\n/** The href form — hash-prefixed, because the admin is a hash router. Use this\n * for links, `openEntity` for clicks. */\nexport function resolveEntityAnchor(\n id: string,\n archetype?: string,\n kind?: string,\n tab?: string,\n entityKey?: string,\n): string {\n return `#${resolveEntityHref(id, archetype, kind, tab, entityKey)}`\n}\n\n/**\n * Resolve a record's URL and go there — the only way a surface should open one.\n * `resolveEntityHref` returns a plain admin path, and handing that to a generic\n * router adapter assigns `location.href`: a full page load to a URL the app does\n * not serve. The palette and the chat chips both got that wrong independently.\n */\nexport function openEntity(\n id: string,\n archetype?: string,\n kind?: string,\n tab?: string,\n entityKey?: string,\n): void {\n navigateTo(resolveEntityHref(id, archetype, kind, tab, entityKey))\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/data/client.ts","../src/org/store.ts","../src/lib/supabase.ts"],"names":["headers","unit","tenant","_getOpt"],"mappings":"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","file":"chunk-P6XUDT2P.js","sourcesContent":["import { createClient, type SupabaseClient } from '@supabase/supabase-js'\nimport { setGlobalSupabaseClient, getActiveUnitId, getActiveTenantId } from '@fayz-ai/core'\nimport { createDedupedFetch } from '@fayz-ai/sdk'\n\nlet _client: SupabaseClient | null = null\n\n/**\n * Para onde a requisição vai, nos três formatos que `fetch` aceita.\n *\n * `input` pode ser uma string, uma URL ou um Request — e ler `.url` de uma\n * string devolve `undefined` em silêncio, que é como um filtro destes deixa\n * passar exatamente o que devia barrar.\n */\nexport function requestUrl(input: RequestInfo | URL): string {\n if (typeof input === 'string') return input\n if (input instanceof URL) return input.toString()\n return input?.url ?? ''\n}\n\n/** O caminho que o Supabase dá a toda função de borda. Exportada para o teste. */\nexport function isEdgeFunctionCall(input: RequestInfo | URL): boolean {\n return requestUrl(input).includes('/functions/v1/')\n}\n\nlet _serviceUrl: string | null = null\nlet _routes: Readonly<Record<string, string>> = {}\n\n/**\n * Where the integration service answers (ADR 0003 phase 2), and which former\n * edge functions it is READY to answer for.\n *\n * The list comes from the service itself (`GET /v1/service/routes`): a function\n * appears there only once its module is mounted and its keys are configured.\n * Until the list arrives, and for anything not on it, calls stay on the edge\n * functions, so a function moves only when the service can really do its job.\n * Null keeps everything on the edge.\n */\nexport async function setServiceUrl(\n url: string | null | undefined,\n fetcher: typeof fetch = (...args) => fetch(...args),\n): Promise<void> {\n _serviceUrl = url ? url.replace(/\\/+$/u, '') : null\n _routes = {}\n if (!_serviceUrl) return\n try {\n const response = await fetcher(`${_serviceUrl}/v1/service/routes`)\n if (!response.ok) return\n const body = (await response.json()) as { routes?: Record<string, unknown> }\n const table: Record<string, string> = {}\n for (const [slug, path] of Object.entries(body.routes ?? {})) {\n if (typeof path === 'string' && path.startsWith('/v1/')) table[slug] = path\n }\n _routes = Object.freeze(table)\n } catch {\n // The service is unreachable: everything stays on the edge functions.\n }\n}\n\n/** Where the integration service answers, or null when everything stays on the edge. */\nexport function serviceBaseUrl(): string | null {\n return _serviceUrl\n}\n\n/** The routes the service answered with, for tests and diagnostics. */\nexport function serviceRoutes(): Readonly<Record<string, string>> {\n return _routes\n}\n\n/**\n * The service URL for an edge-function call, or null when it stays an edge\n * function. `/functions/v1/<slug>` and anything after it (a query) map to the\n * route; an unlisted slug is left alone.\n */\nexport function serviceUrlFor(input: RequestInfo | URL): string | null {\n if (!_serviceUrl) return null\n const url = requestUrl(input)\n const match = /\\/functions\\/v1\\/([a-z0-9-]+)(\\?.*)?$/u.exec(url)\n const route = match ? _routes[match[1]!] : undefined\n return route ? `${_serviceUrl}${route}${match?.[2] ?? ''}` : null\n}\n\n/**\n * Create (and cache) the Supabase client for the Fayz app.\n * Also registers it as the global client in @fayz-ai/core so data providers\n * can resolve it without prop-drilling.\n *\n * Idempotent — subsequent calls with the same URL return the cached client.\n */\nexport function createFayzSupabaseClient(url: string, anonKey: string): SupabaseClient {\n if (_client) return _client\n\n if (!url || !anonKey) {\n throw new Error(\n '[@fayz-ai/admin] Supabase URL and anon key are required. ' +\n 'Pass supabaseUrl and supabaseAnonKey to createFayzApp.',\n )\n }\n\n // Every read goes through this client — the one place that can see two\n // components asking the same thing at the same instant.\n const deduped = createDedupedFetch()\n\n _client = createClient(url, anonKey, {\n auth: { autoRefreshToken: true, persistSession: true },\n global: {\n // The active unit rides on every request so the DATABASE can stamp a\n // write with it (041's trigger reads this header). Reads are narrowed by\n // an explicit filter, not by this — a header cannot be trusted to narrow,\n // and it must never be able to widen: the policies resolve unit access\n // through `public.user_unit_ids()`, never through what was sent here.\n //\n // `x-fayz-unit` is in the dedupe vary list. Without that, two identical\n // URLs under different units collapse into one response.\n fetch: (input: RequestInfo | URL, init: RequestInit = {}) => {\n // Estes cabeçalhos são para o BANCO, e só para ele. Uma função de borda\n // recebe o tenant no corpo (`tenantId`) e nunca leu nenhum dos dois — o\n // que ela faz com um cabeçalho desconhecido é RECUSAR O PREFLIGHT, e o\n // navegador então bloqueia o POST antes de ele sair. Nenhuma requisição\n // chega ao log, e quem está usando vê a palavra \"CORS\".\n //\n // As vinte funções deste repositório declaram listas fixas de\n // `Access-Control-Allow-Headers` e nenhuma delas cita `x-fayz-tenant`.\n // Mandar o cabeçalho para lá não compra nada e derruba todas de uma vez.\n // A function the integration service hosts goes there instead, and it\n // DOES take the tenant and unit headers: its CORS answers whatever the\n // browser asks to send, and it acts in the tenant the caller named.\n const serviceTarget = serviceUrlFor(input)\n if (serviceTarget) {\n const headers = new Headers(init.headers)\n const unit = getActiveUnitId()\n const tenant = getActiveTenantId()\n if (unit) headers.set('x-fayz-unit', unit)\n if (tenant) headers.set('x-fayz-tenant', tenant)\n return fetch(serviceTarget, { ...init, headers })\n }\n if (isEdgeFunctionCall(input)) return deduped(input, init)\n\n const unit = getActiveUnitId()\n // `x-fayz-tenant` rides the same way, for the reason 145 spells out:\n // the archetype policies resolve tenant through app.current_tenant_id(),\n // which knew only the signed JWT claim (nobody mints one) or \"your only\n // account\". A user with two accounts therefore read NOTHING from\n // public.people / orders / products — silently, and long before any\n // screen moved. This is the app finally saying which account it is in.\n //\n // Same rule as the unit header, and 145 enforces it: the value only\n // CHOOSES among the accounts the user already belongs to, validated\n // against app.memberships. It narrows; it can never widen.\n const tenant = getActiveTenantId()\n if (!unit && !tenant) return deduped(input, init)\n const headers = new Headers(init.headers)\n if (unit) headers.set('x-fayz-unit', unit)\n if (tenant) headers.set('x-fayz-tenant', tenant)\n return deduped(input, { ...init, headers })\n },\n },\n })\n\n // Register globally so @fayz-ai/core data providers can use it\n setGlobalSupabaseClient(_client)\n\n return _client\n}\n\n/** Get the cached client — throws if not initialised */\nexport function getFayzSupabaseClient(): SupabaseClient {\n if (!_client) {\n throw new Error(\n '[@fayz-ai/admin] Supabase client not initialised. Call createFayzApp with supabaseUrl and supabaseAnonKey first.',\n )\n }\n return _client\n}\n\n/** Safe getter — returns null if not initialised (mock/offline mode) */\nexport function getFayzSupabaseClientOptional(): SupabaseClient | null {\n return _client\n}\n","import { create } from 'zustand'\nimport { setActiveTenantId, type Organization, type OrgMember, type OrgMembership } from '@fayz-ai/core'\n\nconst STORAGE_KEY = 'fayz:current-org'\n\n// ---------------------------------------------------------------------------\n// Persistence helpers\n// ---------------------------------------------------------------------------\n\nfunction getPersistedOrgId(): string | null {\n try {\n if (typeof localStorage === 'undefined') return null\n return localStorage.getItem(STORAGE_KEY)\n } catch {\n return null\n }\n}\n\nfunction persistOrgId(orgId: string | null): void {\n try {\n if (typeof localStorage === 'undefined') return\n if (orgId) {\n localStorage.setItem(STORAGE_KEY, orgId)\n } else {\n localStorage.removeItem(STORAGE_KEY)\n }\n } catch {\n // ignore\n }\n}\n\n// ---------------------------------------------------------------------------\n// Store interface\n// ---------------------------------------------------------------------------\n\nexport interface OrgStore {\n currentOrg: Organization | null\n userOrgs: OrgMembership[]\n members: OrgMember[]\n /** Person `kind`s that make up the team (from config.team.personKinds). Drives\n * the Person-first Team screen; empty = legacy membership-only mode. */\n teamPersonKinds: string[]\n loading: boolean\n\n /**\n * A conta ativa, e a ESCOLHA que ela representa: persiste o pino.\n *\n * Use quando alguém decidiu — a troca de conta, a resolução do boot. Para\n * apenas PINTAR o que já se sabia, use `paintCurrentOrg`.\n */\n setCurrentOrg: (org: Organization | null) => void\n /**\n * Pinta a conta sem gravar o pino.\n *\n * O snapshot repinta a última conta conhecida antes de o primeiro filho\n * renderizar, para ninguém ver um quadro sem org. Isso é CACHE, não\n * decisão — e enquanto ele gravava o pino, vencia o\n * `decideWorkspaceChoice`: quem usa duas contas ficava preso na última que\n * o snapshot viu, e nada escolhido sobrevivia ao boot.\n */\n paintCurrentOrg: (org: Organization | null) => void\n setUserOrgs: (orgs: OrgMembership[]) => void\n setMembers: (members: OrgMember[]) => void\n setTeamPersonKinds: (kinds: string[]) => void\n setLoading: (loading: boolean) => void\n reset: () => void\n}\n\nexport const useOrganizationStore = create<OrgStore>((set) => ({\n currentOrg: null,\n userOrgs: [],\n members: [],\n teamPersonKinds: [],\n loading: false,\n\n setCurrentOrg: (org) => {\n setActiveTenantId(org?.id)\n persistOrgId(org?.id ?? null)\n set({ currentOrg: org })\n },\n\n // Sem `persistOrgId`: é a única diferença, e é toda a diferença.\n paintCurrentOrg: (org) => {\n setActiveTenantId(org?.id)\n set({ currentOrg: org })\n },\n setUserOrgs: (orgs) => set({ userOrgs: orgs }),\n setMembers: (members) => set({ members }),\n setTeamPersonKinds: (kinds) => set({ teamPersonKinds: kinds }),\n setLoading: (loading) => set({ loading }),\n reset: () => {\n setActiveTenantId(undefined)\n // NOTE: do NOT clear the persisted org id here. The org providers call\n // reset() whenever the auth store transiently reports `user === null` —\n // which happens on every fresh load while the Supabase session hydrates\n // asynchronously. Wiping 'fayz:current-org' at that moment drops a\n // multi-org user's workspace selection BEFORE loadOrgs can read it back,\n // so the app always falls to memberships[0] on reload (single-org users\n // never noticed). The pin is a last-selected hint that's re-validated\n // against the fresh membership list on load, so it's safe to keep across\n // sign-out too (a mismatching pin just falls back to memberships[0]).\n set({ currentOrg: null, userOrgs: [], members: [], loading: false })\n },\n}))\n\nexport { getPersistedOrgId, persistOrgId }\n","// Shim → native Supabase client (unified singleton across shell + plugins).\nimport type { SupabaseClient } from '@supabase/supabase-js'\nimport { getSupabaseClientOptional as _getOpt } from '@fayz-ai/core'\nexport { createSupabaseProvider, setGlobalSupabaseClient } from '@fayz-ai/core'\n// @fayz-ai/core returns a loosely-typed client (no hard supabase coupling); the\n// shell does `.from(...)` against the single public client, so surface it as\n// the real client type.\nexport const getSupabaseClientOptional = (): SupabaseClient | null =>\n _getOpt() as unknown as SupabaseClient | null\nexport {\n getFayzSupabaseClient as getSupabaseClient,\n getFayzSupabaseClientOptional as getSupabaseClientSafe,\n createFayzSupabaseClient as createSupabaseClient,\n} from '../data/client'\nimport { getFayzSupabaseClient } from '../data/client'\n// Core tables now live in the public schema — the \"core\" client is just the\n// plain public client. Kept as a backward-compatible alias for call sites.\nexport const getCoreClient = getFayzSupabaseClient\nexport const getCoreSupabaseClient = getFayzSupabaseClient\nexport const getProjectSupabaseClient = getFayzSupabaseClient\nexport type { SupabaseClient }\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/app/routing.tsx"],"names":[],"mappings":"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","file":"chunk-VX3WJLKK.js","sourcesContent":["import * as React from 'react'\nimport { hashRouterAdapter } from '@fayz-ai/core'\n\n// ---------------------------------------------------------------------------\n// Admin hash router — the same lightweight approach the storefront uses. The\n// admin shell collects routes from the plugin runtime + manifest pages and\n// switches on the current hash path. Deliberately not react-router: an SDK\n// shell shipping a router creates singleton hazards under source-alias dev.\n// ---------------------------------------------------------------------------\n\nconst adapter = hashRouterAdapter()\n\nexport function normalizeAdminPath(path: string): string {\n const clean = `/${path}`.replace(/\\/+/g, '/')\n return clean.length > 1 ? clean.replace(/\\/+$/, '') : clean\n}\n\nexport function navigateTo(to: string): void {\n adapter.navigate(normalizeAdminPath(to))\n}\n\nexport function useAdminPath(): string {\n const [path, setPath] = React.useState(() => normalizeAdminPath(adapter.getCurrentPath() || '/'))\n React.useEffect(() => {\n return adapter.onPathChange((p) => {\n setPath(normalizeAdminPath(p || '/'))\n if (typeof window !== 'undefined') window.scrollTo(0, 0)\n })\n }, [])\n return path\n}\n\n/** Match '/courses/:id' against '/courses/abc' → { id: 'abc' }; supports a\n * trailing '/*' wildcard (matches the base and any deeper path). */\nexport function matchRoute(pattern: string, path: string): Record<string, string> | null {\n const cleanPath = (path.split('?')[0] ?? '').replace(/\\/+$/, '') || '/'\n if (pattern.endsWith('/*')) {\n const base = pattern.slice(0, -2)\n if (cleanPath === base || cleanPath.startsWith(`${base}/`)) return {}\n return null\n }\n const patternParts = pattern.split('/').filter(Boolean)\n const pathParts = cleanPath.split('/').filter(Boolean)\n if (patternParts.length !== pathParts.length) return null\n const params: Record<string, string> = {}\n for (let i = 0; i < patternParts.length; i++) {\n const pat = patternParts[i]!\n const part = pathParts[i]!\n if (pat.startsWith(':')) params[pat.slice(1)] = decodeURIComponent(part)\n else if (pat !== part) return null\n }\n return params\n}\n\n/** Score a route pattern for specificity so the most specific match wins\n * (static segments beat params; longer beats shorter; wildcard loses). */\nexport function routeScore(pattern: string): number {\n const isWildcard = pattern.endsWith('/*')\n const routePattern = isWildcard ? pattern.slice(0, -2) : pattern\n const parts = routePattern.split('/').filter(Boolean)\n let score = parts.length * 10\n for (const p of parts) if (!p.startsWith(':')) score += 5\n if (isWildcard) score -= 1\n return score\n}\n"]}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
export { entityRouteHasDetail, openEntity, resolveEntityAnchor, resolveEntityHref, resolveEntityRoute, setEntityRouteMap } from './chunk-P5UIGQFY.js';
|
|
2
|
-
import './chunk-VX3WJLKK.js';
|
|
3
|
-
//# sourceMappingURL=entity-routes-LXOBW5IB.js.map
|
|
4
|
-
//# sourceMappingURL=entity-routes-LXOBW5IB.js.map
|