@aglyn/aglyn 1.0.0-beta.218 → 1.0.0-beta.220
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 +12 -12
- package/src/lib/app-utils/actions.d.ts +26 -433
- package/src/lib/app-utils/actions.js +108 -633
- package/src/lib/app-utils/actions.js.map +1 -1
- package/src/lib/app-utils/activity-presenter.d.ts +3 -3
- package/src/lib/app-utils/activity-presenter.js +36 -52
- package/src/lib/app-utils/activity-presenter.js.map +1 -1
- package/src/lib/app-utils/analytics-events.d.ts +1 -1
- package/src/lib/app-utils/analytics-events.js.map +1 -1
- package/src/lib/app-utils/analytics-provider.d.ts +182 -0
- package/src/lib/app-utils/analytics-provider.js +133 -0
- package/src/lib/app-utils/analytics-provider.js.map +1 -0
- package/src/lib/app-utils/api-plugins.d.ts +46 -0
- package/src/lib/app-utils/api-plugins.js +19 -0
- package/src/lib/app-utils/api-plugins.js.map +1 -1
- package/src/lib/app-utils/{marketplace-overrides.d.ts → artifact-overrides.d.ts} +9 -6
- package/src/lib/app-utils/{marketplace-overrides.js → artifact-overrides.js} +10 -7
- package/src/lib/app-utils/artifact-overrides.js.map +1 -0
- package/src/lib/app-utils/{marketplace-provenance.d.ts → artifact-provenance.d.ts} +12 -10
- package/src/lib/app-utils/{marketplace-provenance.js → artifact-provenance.js} +9 -7
- package/src/lib/app-utils/artifact-provenance.js.map +1 -0
- package/src/lib/app-utils/binding-token-catalog.d.ts +5 -13
- package/src/lib/app-utils/binding-token-catalog.js +17 -41
- package/src/lib/app-utils/binding-token-catalog.js.map +1 -1
- package/src/lib/app-utils/brand-support-line.d.ts +36 -0
- package/src/lib/app-utils/brand-support-line.js +38 -0
- package/src/lib/app-utils/brand-support-line.js.map +1 -0
- package/src/lib/app-utils/collection-entries.d.ts +2 -2
- package/src/lib/app-utils/collection-entries.js.map +1 -1
- package/src/lib/app-utils/consent-group-change.d.ts +4 -0
- package/src/lib/app-utils/consent-group-change.js.map +1 -1
- package/src/lib/app-utils/consent-groups.d.ts +1 -1
- package/src/lib/app-utils/consent-groups.js.map +1 -1
- package/src/lib/app-utils/console-routes.d.ts +15 -42
- package/src/lib/app-utils/console-routes.js +10 -39
- package/src/lib/app-utils/console-routes.js.map +1 -1
- package/src/lib/app-utils/contacts.d.ts +24 -2
- package/src/lib/app-utils/contacts.js +21 -5
- package/src/lib/app-utils/contacts.js.map +1 -1
- package/src/lib/app-utils/container-membership.d.ts +93 -0
- package/src/lib/app-utils/container-membership.js +165 -0
- package/src/lib/app-utils/container-membership.js.map +1 -0
- package/src/lib/app-utils/crm-task-reminders.d.ts +23 -6
- package/src/lib/app-utils/crm-task-reminders.js +32 -11
- package/src/lib/app-utils/crm-task-reminders.js.map +1 -1
- package/src/lib/app-utils/crm.d.ts +24 -4
- package/src/lib/app-utils/crm.js +23 -0
- package/src/lib/app-utils/crm.js.map +1 -1
- package/src/lib/app-utils/cross-pool-desync.d.ts +39 -0
- package/src/lib/app-utils/cross-pool-desync.js +47 -0
- package/src/lib/app-utils/cross-pool-desync.js.map +1 -0
- package/src/lib/app-utils/csv-upload.d.ts +29 -0
- package/src/lib/app-utils/csv-upload.js +29 -0
- package/src/lib/app-utils/csv-upload.js.map +1 -0
- package/src/lib/app-utils/{dataset-csv.d.ts → csv.d.ts} +10 -43
- package/src/lib/app-utils/{dataset-csv.js → csv.js} +10 -81
- package/src/lib/app-utils/csv.js.map +1 -0
- package/src/lib/app-utils/dataset-models.d.ts +5 -5
- package/src/lib/app-utils/dataset-models.js +19 -2
- package/src/lib/app-utils/dataset-models.js.map +1 -1
- package/src/lib/app-utils/datasets.d.ts +65 -30
- package/src/lib/app-utils/datasets.js +74 -24
- package/src/lib/app-utils/datasets.js.map +1 -1
- package/src/lib/app-utils/docs-deflection.d.ts +6 -6
- package/src/lib/app-utils/docs-deflection.js.map +1 -1
- package/src/lib/app-utils/docs-help.generated.d.ts +14 -8
- package/src/lib/app-utils/docs-help.generated.js +23 -6
- package/src/lib/app-utils/docs-help.generated.js.map +1 -1
- package/src/lib/app-utils/docs-index.generated.d.ts +2 -2
- package/src/lib/app-utils/docs-index.generated.js +570 -346
- package/src/lib/app-utils/docs-index.generated.js.map +1 -1
- package/src/lib/app-utils/docs-retrieval.d.ts +3 -3
- package/src/lib/app-utils/docs-retrieval.js +14 -10
- package/src/lib/app-utils/docs-retrieval.js.map +1 -1
- package/src/lib/app-utils/duplicate-resource.d.ts +4 -1
- package/src/lib/app-utils/duplicate-resource.js +7 -4
- package/src/lib/app-utils/duplicate-resource.js.map +1 -1
- package/src/lib/app-utils/dynamic-list-rule.d.ts +1 -1
- package/src/lib/app-utils/dynamic-list-rule.js +3 -3
- package/src/lib/app-utils/dynamic-list-rule.js.map +1 -1
- package/src/lib/app-utils/element-ui.d.ts +1 -1
- package/src/lib/app-utils/element-ui.js +1 -1
- package/src/lib/app-utils/element-ui.js.map +1 -1
- package/src/lib/app-utils/email-starter-policy.js +3 -3
- package/src/lib/app-utils/email-starter-policy.js.map +1 -1
- package/src/lib/app-utils/email-text.d.ts +80 -0
- package/src/lib/app-utils/email-text.js +189 -0
- package/src/lib/app-utils/email-text.js.map +1 -0
- package/src/lib/app-utils/{list-assignment-policy.d.ts → enrollment-basis.d.ts} +4 -0
- package/src/lib/app-utils/{list-assignment-policy.js → enrollment-basis.js} +5 -1
- package/src/lib/app-utils/enrollment-basis.js.map +1 -0
- package/src/lib/app-utils/entity-picker-context.d.ts +10 -5
- package/src/lib/app-utils/entity-picker-context.js.map +1 -1
- package/src/lib/app-utils/error-beacon.d.ts +75 -6
- package/src/lib/app-utils/error-beacon.js +160 -21
- package/src/lib/app-utils/error-beacon.js.map +1 -1
- package/src/lib/app-utils/expand-repeatables.d.ts +10 -10
- package/src/lib/app-utils/expand-repeatables.js +14 -14
- package/src/lib/app-utils/expand-repeatables.js.map +1 -1
- package/src/lib/app-utils/forms.js +2 -2
- package/src/lib/app-utils/forms.js.map +1 -1
- package/src/lib/app-utils/health-report.d.ts +2 -3
- package/src/lib/app-utils/health-report.js +8 -6
- package/src/lib/app-utils/health-report.js.map +1 -1
- package/src/lib/app-utils/host-events.d.ts +82 -0
- package/src/lib/app-utils/host-events.js +62 -0
- package/src/lib/app-utils/host-events.js.map +1 -0
- package/src/lib/app-utils/inbound-mail-domain.d.ts +27 -0
- package/src/lib/app-utils/inbound-mail-domain.js +31 -0
- package/src/lib/app-utils/inbound-mail-domain.js.map +1 -0
- package/src/lib/app-utils/lockdown.d.ts +11 -0
- package/src/lib/app-utils/lockdown.js +33 -3
- package/src/lib/app-utils/lockdown.js.map +1 -1
- package/src/lib/app-utils/margin-utilization.d.ts +4 -69
- package/src/lib/app-utils/margin-utilization.js +82 -69
- package/src/lib/app-utils/margin-utilization.js.map +1 -1
- package/src/lib/app-utils/member-email-aliases.d.ts +25 -0
- package/src/lib/app-utils/member-email-aliases.js +29 -0
- package/src/lib/app-utils/member-email-aliases.js.map +1 -1
- package/src/lib/app-utils/node-definition-sanitizer.d.ts +16 -16
- package/src/lib/app-utils/node-definition-sanitizer.js +24 -20
- package/src/lib/app-utils/node-definition-sanitizer.js.map +1 -1
- package/src/lib/app-utils/node-interactions.d.ts +7 -7
- package/src/lib/app-utils/node-interactions.js.map +1 -1
- package/src/lib/app-utils/notifications.d.ts +147 -47
- package/src/lib/app-utils/notifications.js +182 -44
- package/src/lib/app-utils/notifications.js.map +1 -1
- package/src/lib/app-utils/operator-alerts.d.ts +15 -1
- package/src/lib/app-utils/operator-alerts.js +47 -10
- package/src/lib/app-utils/operator-alerts.js.map +1 -1
- package/src/lib/app-utils/payments-configured.d.ts +8 -21
- package/src/lib/app-utils/payments-configured.js +8 -23
- package/src/lib/app-utils/payments-configured.js.map +1 -1
- package/src/lib/app-utils/plan-entitlements.d.ts +207 -306
- package/src/lib/app-utils/plan-entitlements.js +345 -528
- package/src/lib/app-utils/plan-entitlements.js.map +1 -1
- package/src/lib/app-utils/platform-brand.d.ts +10 -0
- package/src/lib/app-utils/platform-brand.js +14 -3
- package/src/lib/app-utils/platform-brand.js.map +1 -1
- package/src/lib/app-utils/platform-marketing-consent.d.ts +56 -2
- package/src/lib/app-utils/platform-marketing-consent.js +6 -5
- package/src/lib/app-utils/platform-marketing-consent.js.map +1 -1
- package/src/lib/app-utils/plugin-api-rate-limit.d.ts +7 -1
- package/src/lib/app-utils/plugin-api-rate-limit.js +11 -3
- package/src/lib/app-utils/plugin-api-rate-limit.js.map +1 -1
- package/src/lib/app-utils/plugin-bundle-checks.js +2 -2
- package/src/lib/app-utils/plugin-bundle-checks.js.map +1 -1
- package/src/lib/app-utils/plugin-host-events.generated.d.ts +12 -0
- package/src/lib/app-utils/plugin-host-events.generated.js +169 -0
- package/src/lib/app-utils/plugin-host-events.generated.js.map +1 -0
- package/src/lib/app-utils/plugin-release-flags.generated.d.ts +12 -0
- package/src/lib/app-utils/plugin-release-flags.generated.js +106 -0
- package/src/lib/app-utils/plugin-release-flags.generated.js.map +1 -0
- package/src/lib/app-utils/plugin-starter-templates.generated.d.ts +12 -0
- package/src/lib/app-utils/plugin-starter-templates.generated.js +711 -0
- package/src/lib/app-utils/plugin-starter-templates.generated.js.map +1 -0
- package/src/lib/app-utils/realm-host-surface.generated.js +2 -0
- package/src/lib/app-utils/realm-host-surface.generated.js.map +1 -1
- package/src/lib/app-utils/release-flags.d.ts +14 -5
- package/src/lib/app-utils/release-flags.js +21 -125
- package/src/lib/app-utils/release-flags.js.map +1 -1
- package/src/lib/app-utils/repeat-query.d.ts +56 -0
- package/src/lib/app-utils/{dataset-query.js → repeat-query.js} +16 -16
- package/src/lib/app-utils/repeat-query.js.map +1 -0
- package/src/lib/app-utils/repeat-sources.d.ts +9 -0
- package/src/lib/app-utils/repeat-sources.js.map +1 -1
- package/src/lib/app-utils/retained-refusals.d.ts +73 -0
- package/src/lib/app-utils/retained-refusals.js +186 -0
- package/src/lib/app-utils/retained-refusals.js.map +1 -0
- package/src/lib/app-utils/scope-tokens.d.ts +27 -0
- package/src/lib/app-utils/scope-tokens.js +61 -0
- package/src/lib/app-utils/scope-tokens.js.map +1 -1
- package/src/lib/app-utils/screen-link-context.js +3 -3
- package/src/lib/app-utils/screen-link-context.js.map +1 -1
- package/src/lib/app-utils/screen-route.js +1 -1
- package/src/lib/app-utils/screen-route.js.map +1 -1
- package/src/lib/app-utils/seo-audit.d.ts +132 -0
- package/src/lib/app-utils/seo-audit.js +246 -0
- package/src/lib/app-utils/seo-audit.js.map +1 -0
- package/src/lib/app-utils/seo-keywords.d.ts +48 -0
- package/src/lib/app-utils/seo-keywords.js +60 -0
- package/src/lib/app-utils/seo-keywords.js.map +1 -0
- package/src/lib/app-utils/seo-page-facts.d.ts +66 -0
- package/src/lib/app-utils/seo-page-facts.js +155 -0
- package/src/lib/app-utils/seo-page-facts.js.map +1 -0
- package/src/lib/app-utils/seo-site-scan.d.ts +126 -0
- package/src/lib/app-utils/seo-site-scan.js +162 -0
- package/src/lib/app-utils/seo-site-scan.js.map +1 -0
- package/src/lib/app-utils/seo-title-variables.js +1 -1
- package/src/lib/app-utils/seo-title-variables.js.map +1 -1
- package/src/lib/app-utils/server.d.ts +13 -18
- package/src/lib/app-utils/server.js +33 -51
- package/src/lib/app-utils/server.js.map +1 -1
- package/src/lib/app-utils/site-interactions.d.ts +501 -0
- package/src/lib/app-utils/site-interactions.js +554 -0
- package/src/lib/app-utils/site-interactions.js.map +1 -0
- package/src/lib/app-utils/{marketplace-theme.d.ts → site-theme.d.ts} +13 -2
- package/src/lib/app-utils/{marketplace-theme.js → site-theme.js} +2 -2
- package/src/lib/app-utils/site-theme.js.map +1 -0
- package/src/lib/app-utils/sitemap.d.ts +4 -3
- package/src/lib/app-utils/sitemap.js +9 -7
- package/src/lib/app-utils/sitemap.js.map +1 -1
- package/src/lib/app-utils/stale-build-error.d.ts +51 -0
- package/src/lib/app-utils/stale-build-error.js +100 -1
- package/src/lib/app-utils/stale-build-error.js.map +1 -1
- package/src/lib/app-utils/starter-template-nodes.d.ts +137 -0
- package/src/lib/app-utils/starter-template-nodes.js +129 -0
- package/src/lib/app-utils/starter-template-nodes.js.map +1 -0
- package/src/lib/app-utils/starter-templates.d.ts +11 -34
- package/src/lib/app-utils/starter-templates.js +19 -230
- package/src/lib/app-utils/starter-templates.js.map +1 -1
- package/src/lib/app-utils/{email-topics.d.ts → subscription-topics.d.ts} +64 -48
- package/src/lib/app-utils/{email-topics.js → subscription-topics.js} +39 -109
- package/src/lib/app-utils/subscription-topics.js.map +1 -0
- package/src/lib/app-utils/tax-jurisdiction-figures.d.ts +118 -0
- package/src/lib/app-utils/tax-jurisdiction-figures.js +123 -0
- package/src/lib/app-utils/tax-jurisdiction-figures.js.map +1 -0
- package/src/lib/app-utils/theme-library.d.ts +10 -3
- package/src/lib/app-utils/theme-library.js +13 -4
- package/src/lib/app-utils/theme-library.js.map +1 -1
- package/src/lib/app-utils/usage-budget.d.ts +73 -188
- package/src/lib/app-utils/usage-budget.js +58 -194
- package/src/lib/app-utils/usage-budget.js.map +1 -1
- package/src/lib/app-utils/{campaign-attribution.d.ts → utm-attribution.d.ts} +11 -6
- package/src/lib/app-utils/{campaign-attribution.js → utm-attribution.js} +13 -8
- package/src/lib/app-utils/utm-attribution.js.map +1 -0
- package/src/lib/app-utils/{campaign-forwarding.d.ts → utm-forwarding.d.ts} +14 -14
- package/src/lib/app-utils/{campaign-forwarding.js → utm-forwarding.js} +26 -26
- package/src/lib/app-utils/utm-forwarding.js.map +1 -0
- package/src/lib/app-utils/{campaign-touch.d.ts → utm-touch.d.ts} +25 -17
- package/src/lib/app-utils/{campaign-touch.js → utm-touch.js} +38 -30
- package/src/lib/app-utils/utm-touch.js.map +1 -0
- package/src/lib/app-utils/variables.d.ts +9 -9
- package/src/lib/app-utils/variables.js.map +1 -1
- package/src/lib/app-utils/video-object.js +6 -5
- package/src/lib/app-utils/video-object.js.map +1 -1
- package/src/lib/app-utils/visitor-consent.d.ts +41 -164
- package/src/lib/app-utils/visitor-consent.js +66 -277
- package/src/lib/app-utils/visitor-consent.js.map +1 -1
- package/src/lib/app-utils/visitor-record-ceiling.d.ts +32 -0
- package/src/lib/app-utils/visitor-record-ceiling.js +39 -0
- package/src/lib/app-utils/visitor-record-ceiling.js.map +1 -1
- package/src/lib/app-utils/web-vitals-rum.d.ts +7 -7
- package/src/lib/app-utils/web-vitals-rum.js +31 -63
- package/src/lib/app-utils/web-vitals-rum.js.map +1 -1
- package/src/lib/app-utils/where-used.d.ts +11 -6
- package/src/lib/app-utils/where-used.js +3 -8
- package/src/lib/app-utils/where-used.js.map +1 -1
- package/src/lib/foundation/definitions/components.types.d.ts +1 -1
- package/src/lib/foundation/definitions/components.types.js +1 -1
- package/src/lib/foundation/definitions/components.types.js.map +1 -1
- package/src/lib/foundation/definitions/org-billing.types.d.ts +11 -137
- package/src/lib/foundation/definitions/org-billing.types.js.map +1 -1
- package/src/lib/foundation/definitions/organization.types.d.ts +1 -3
- package/src/lib/foundation/definitions/organization.types.js.map +1 -1
- package/src/lib/foundation/definitions/platform.types.d.ts +11 -5
- package/src/lib/foundation/definitions/platform.types.js.map +1 -1
- package/src/lib/foundation/definitions/write-deny-coverage.util.d.ts +16 -0
- package/src/lib/foundation/definitions/write-deny-coverage.util.js +20 -0
- package/src/lib/foundation/definitions/write-deny-coverage.util.js.map +1 -1
- package/src/lib/foundation/index.d.ts +1 -1
- package/src/lib/foundation/index.js.map +1 -1
- package/src/lib/plugin-manager/besigner-documents.d.ts +96 -0
- package/src/lib/plugin-manager/besigner-documents.js +61 -0
- package/src/lib/plugin-manager/besigner-documents.js.map +1 -0
- package/src/lib/plugin-manager/computed-variables.d.ts +71 -0
- package/src/lib/plugin-manager/computed-variables.js +74 -0
- package/src/lib/plugin-manager/computed-variables.js.map +1 -0
- package/src/lib/plugin-manager/custom-fields.d.ts +29 -2
- package/src/lib/plugin-manager/custom-fields.js +47 -1
- package/src/lib/plugin-manager/custom-fields.js.map +1 -1
- package/src/lib/plugin-manager/feature-plugins.d.ts +372 -99
- package/src/lib/plugin-manager/feature-plugins.js +126 -51
- package/src/lib/plugin-manager/feature-plugins.js.map +1 -1
- package/src/lib/plugin-manager/first-party-plugins.generated.d.ts +134 -0
- package/src/lib/plugin-manager/first-party-plugins.generated.js +840 -10
- package/src/lib/plugin-manager/first-party-plugins.generated.js.map +1 -1
- package/src/lib/plugin-manager/index.d.ts +0 -1
- package/src/lib/plugin-manager/index.js +0 -1
- package/src/lib/plugin-manager/index.js.map +1 -1
- package/src/lib/plugin-manager/plugin-activity-actions.d.ts +12 -0
- package/src/lib/plugin-manager/plugin-activity-actions.js +25 -0
- package/src/lib/plugin-manager/plugin-activity-actions.js.map +1 -1
- package/src/lib/plugin-manager/plugin-contact-capture.d.ts +9 -4
- package/src/lib/plugin-manager/plugin-contact-capture.js.map +1 -1
- package/src/lib/plugin-manager/plugin-containers.d.ts +68 -0
- package/src/lib/plugin-manager/plugin-containers.generated.d.ts +10 -0
- package/src/lib/plugin-manager/plugin-containers.generated.js +20 -0
- package/src/lib/plugin-manager/plugin-containers.generated.js.map +1 -0
- package/src/lib/plugin-manager/plugin-containers.js +27 -0
- package/src/lib/plugin-manager/plugin-containers.js.map +1 -0
- package/src/lib/plugin-manager/plugin-contributions.d.ts +1 -1
- package/src/lib/plugin-manager/plugin-contributions.js.map +1 -1
- package/src/lib/plugin-manager/plugin-declarations-repair.d.ts +36 -0
- package/src/lib/plugin-manager/plugin-declarations-repair.js +64 -0
- package/src/lib/plugin-manager/plugin-declarations-repair.js.map +1 -0
- package/src/lib/plugin-manager/plugin-dependents.d.ts +101 -0
- package/src/lib/plugin-manager/plugin-dependents.js +75 -0
- package/src/lib/plugin-manager/plugin-dependents.js.map +1 -0
- package/src/lib/plugin-manager/plugin-distribution.d.ts +55 -0
- package/src/lib/plugin-manager/plugin-distribution.js +45 -0
- package/src/lib/plugin-manager/plugin-distribution.js.map +1 -0
- package/src/lib/plugin-manager/plugin-entitlements.d.ts +8 -0
- package/src/lib/plugin-manager/plugin-entitlements.js.map +1 -1
- package/src/lib/plugin-manager/plugin-host-collections.d.ts +17 -0
- package/src/lib/plugin-manager/plugin-host-collections.js +6 -0
- package/src/lib/plugin-manager/plugin-host-collections.js.map +1 -1
- package/src/lib/plugin-manager/plugin-host-resources.d.ts +133 -0
- package/src/lib/plugin-manager/plugin-host-resources.js +52 -0
- package/src/lib/plugin-manager/plugin-host-resources.js.map +1 -0
- package/src/lib/plugin-manager/plugin-membership-detach.js +1 -1
- package/src/lib/plugin-manager/plugin-membership-detach.js.map +1 -1
- package/src/lib/plugin-manager/plugin-org-erasure.d.ts +28 -2
- package/src/lib/plugin-manager/plugin-org-erasure.js +61 -2
- package/src/lib/plugin-manager/plugin-org-erasure.js.map +1 -1
- package/src/lib/plugin-manager/plugin-plan-entitlements.d.ts +123 -0
- package/src/lib/plugin-manager/plugin-plan-entitlements.js +101 -0
- package/src/lib/plugin-manager/plugin-plan-entitlements.js.map +1 -0
- package/src/lib/plugin-manager/plugin-record-email-state.d.ts +69 -0
- package/src/lib/plugin-manager/plugin-record-email-state.js +32 -0
- package/src/lib/plugin-manager/plugin-record-email-state.js.map +1 -1
- package/src/lib/plugin-manager/plugin-record-index.d.ts +95 -0
- package/src/lib/plugin-manager/plugin-record-index.js +51 -0
- package/src/lib/plugin-manager/plugin-record-index.js.map +1 -0
- package/src/lib/plugin-manager/plugin-record-lists.d.ts +115 -0
- package/src/lib/plugin-manager/plugin-record-lists.js +75 -0
- package/src/lib/plugin-manager/plugin-record-lists.js.map +1 -0
- package/src/lib/plugin-manager/plugin-record-timeline.d.ts +42 -8
- package/src/lib/plugin-manager/plugin-record-timeline.js.map +1 -1
- package/src/lib/plugin-manager/plugin-record-written.d.ts +58 -0
- package/src/lib/plugin-manager/plugin-record-written.js +42 -0
- package/src/lib/plugin-manager/plugin-record-written.js.map +1 -0
- package/src/lib/plugin-manager/plugin-revenue-sources.d.ts +213 -0
- package/src/lib/plugin-manager/plugin-revenue-sources.js +194 -0
- package/src/lib/plugin-manager/plugin-revenue-sources.js.map +1 -0
- package/src/lib/plugin-manager/plugin-site-beacons.d.ts +71 -0
- package/src/lib/plugin-manager/plugin-site-beacons.js +54 -0
- package/src/lib/plugin-manager/plugin-site-beacons.js.map +1 -0
- package/src/lib/plugin-manager/plugin-site-bundle.d.ts +145 -0
- package/src/lib/plugin-manager/plugin-site-bundle.js +78 -0
- package/src/lib/plugin-manager/plugin-site-bundle.js.map +1 -0
- package/src/lib/plugin-manager/plugin-site-cache.d.ts +12 -0
- package/src/lib/plugin-manager/plugin-site-cache.js.map +1 -1
- package/src/lib/plugin-manager/plugin-site-export.d.ts +81 -0
- package/src/lib/plugin-manager/plugin-site-export.js +40 -0
- package/src/lib/plugin-manager/plugin-site-export.js.map +1 -0
- package/src/lib/plugin-manager/plugin-sitemap-sections.d.ts +88 -0
- package/src/lib/plugin-manager/plugin-sitemap-sections.js +29 -0
- package/src/lib/plugin-manager/plugin-sitemap-sections.js.map +1 -0
- package/src/lib/plugin-manager/plugin-subscription-topics.generated.d.ts +11 -0
- package/src/lib/plugin-manager/plugin-subscription-topics.generated.js +41 -0
- package/src/lib/plugin-manager/plugin-subscription-topics.generated.js.map +1 -0
- package/src/lib/plugin-manager/plugin-tax-profile.d.ts +20 -4
- package/src/lib/plugin-manager/plugin-tax-profile.js.map +1 -1
- package/src/lib/plugin-manager/plugin-tax-return-sources.d.ts +255 -0
- package/src/lib/plugin-manager/plugin-tax-return-sources.js +191 -0
- package/src/lib/plugin-manager/plugin-tax-return-sources.js.map +1 -0
- package/src/lib/plugin-manager/plugin-template-sources.d.ts +75 -0
- package/src/lib/plugin-manager/plugin-template-sources.js +37 -0
- package/src/lib/plugin-manager/plugin-template-sources.js.map +1 -0
- package/src/lib/plugin-manager/plugin-usage-axes.d.ts +319 -0
- package/src/lib/plugin-manager/plugin-usage-axes.js +186 -0
- package/src/lib/plugin-manager/plugin-usage-axes.js.map +1 -0
- package/src/lib/plugin-manager/plugin-usage-meters.d.ts +108 -0
- package/src/lib/plugin-manager/plugin-usage-meters.js +105 -0
- package/src/lib/plugin-manager/plugin-usage-meters.js.map +1 -0
- package/src/lib/plugin-manager/plugin-zones.d.ts +4 -5
- package/src/lib/plugin-manager/plugin-zones.js.map +1 -1
- package/src/lib/plugin-manager/realm-host-aglyn.generated.js +2 -0
- package/src/lib/plugin-manager/realm-host-aglyn.generated.js.map +1 -1
- package/src/lib/plugin-manager/record-captured-contact.d.ts +1 -14
- package/src/lib/plugin-manager/record-captured-contact.js +10 -32
- package/src/lib/plugin-manager/record-captured-contact.js.map +1 -1
- package/src/lib/plugin-manager/repeat-rows.d.ts +124 -0
- package/src/lib/plugin-manager/repeat-rows.js +108 -0
- package/src/lib/plugin-manager/repeat-rows.js.map +1 -0
- package/src/lib/plugin-manager/submission-record-target.d.ts +144 -0
- package/src/lib/plugin-manager/submission-record-target.js +125 -0
- package/src/lib/plugin-manager/submission-record-target.js.map +1 -0
- package/src/lib/plugin-manager/usage-alert-contributors.d.ts +76 -6
- package/src/lib/plugin-manager/usage-alert-contributors.js +23 -10
- package/src/lib/plugin-manager/usage-alert-contributors.js.map +1 -1
- package/src/lib/plugin-manager/video-embed-provider.d.ts +108 -0
- package/src/lib/plugin-manager/video-embed-provider.js +165 -0
- package/src/lib/plugin-manager/video-embed-provider.js.map +1 -0
- package/src/lib/types/nodes.d.ts +2 -2
- package/src/lib/types/nodes.js.map +1 -1
- package/src/lib/app-utils/assist-credits.d.ts +0 -482
- package/src/lib/app-utils/assist-credits.js +0 -509
- package/src/lib/app-utils/assist-credits.js.map +0 -1
- package/src/lib/app-utils/campaign-attribution.js.map +0 -1
- package/src/lib/app-utils/campaign-forwarding.js.map +0 -1
- package/src/lib/app-utils/campaign-membership.d.ts +0 -121
- package/src/lib/app-utils/campaign-membership.js +0 -189
- package/src/lib/app-utils/campaign-membership.js.map +0 -1
- package/src/lib/app-utils/campaign-touch.js.map +0 -1
- package/src/lib/app-utils/console-record-links.d.ts +0 -163
- package/src/lib/app-utils/console-record-links.js +0 -180
- package/src/lib/app-utils/console-record-links.js.map +0 -1
- package/src/lib/app-utils/contact-holder.d.ts +0 -68
- package/src/lib/app-utils/contact-holder.js +0 -129
- package/src/lib/app-utils/contact-holder.js.map +0 -1
- package/src/lib/app-utils/contact-merge.d.ts +0 -136
- package/src/lib/app-utils/contact-merge.js +0 -412
- package/src/lib/app-utils/contact-merge.js.map +0 -1
- package/src/lib/app-utils/crm-booking.d.ts +0 -75
- package/src/lib/app-utils/crm-booking.js +0 -133
- package/src/lib/app-utils/crm-booking.js.map +0 -1
- package/src/lib/app-utils/crm-csv.d.ts +0 -239
- package/src/lib/app-utils/crm-csv.js +0 -467
- package/src/lib/app-utils/crm-csv.js.map +0 -1
- package/src/lib/app-utils/crm-digest.d.ts +0 -185
- package/src/lib/app-utils/crm-digest.js +0 -272
- package/src/lib/app-utils/crm-digest.js.map +0 -1
- package/src/lib/app-utils/crm-inbound.d.ts +0 -245
- package/src/lib/app-utils/crm-inbound.js +0 -407
- package/src/lib/app-utils/crm-inbound.js.map +0 -1
- package/src/lib/app-utils/crm-reports.d.ts +0 -479
- package/src/lib/app-utils/crm-reports.js +0 -680
- package/src/lib/app-utils/crm-reports.js.map +0 -1
- package/src/lib/app-utils/dataset-csv.js.map +0 -1
- package/src/lib/app-utils/dataset-query.d.ts +0 -57
- package/src/lib/app-utils/dataset-query.js.map +0 -1
- package/src/lib/app-utils/email-topics.js.map +0 -1
- package/src/lib/app-utils/form-dataset-binding.d.ts +0 -50
- package/src/lib/app-utils/form-dataset-binding.js +0 -74
- package/src/lib/app-utils/form-dataset-binding.js.map +0 -1
- package/src/lib/app-utils/list-assignment-policy.js.map +0 -1
- package/src/lib/app-utils/list-import.d.ts +0 -158
- package/src/lib/app-utils/list-import.js +0 -332
- package/src/lib/app-utils/list-import.js.map +0 -1
- package/src/lib/app-utils/marketplace-listing-visibility.d.ts +0 -122
- package/src/lib/app-utils/marketplace-listing-visibility.js +0 -147
- package/src/lib/app-utils/marketplace-listing-visibility.js.map +0 -1
- package/src/lib/app-utils/marketplace-overrides.js.map +0 -1
- package/src/lib/app-utils/marketplace-provenance.js.map +0 -1
- package/src/lib/app-utils/marketplace-theme.js.map +0 -1
- package/src/lib/app-utils/marketplace-update-state.d.ts +0 -119
- package/src/lib/app-utils/marketplace-update-state.js +0 -132
- package/src/lib/app-utils/marketplace-update-state.js.map +0 -1
- package/src/lib/app-utils/publisher-agreement.d.ts +0 -289
- package/src/lib/app-utils/publisher-agreement.js +0 -321
- package/src/lib/app-utils/publisher-agreement.js.map +0 -1
- package/src/lib/app-utils/wistia-embed.d.ts +0 -104
- package/src/lib/app-utils/wistia-embed.js +0 -138
- package/src/lib/app-utils/wistia-embed.js.map +0 -1
- package/src/lib/app-utils/workflows.d.ts +0 -136
- package/src/lib/app-utils/workflows.js +0 -346
- package/src/lib/app-utils/workflows.js.map +0 -1
- package/src/lib/plugin-manager/commerce-zone-props.d.ts +0 -172
- package/src/lib/plugin-manager/commerce-zone-props.js +0 -31
- package/src/lib/plugin-manager/commerce-zone-props.js.map +0 -1
- package/src/lib/plugin-manager/plugin-metered-lines.d.ts +0 -97
- package/src/lib/plugin-manager/plugin-metered-lines.js +0 -123
- package/src/lib/plugin-manager/plugin-metered-lines.js.map +0 -1
|
@@ -19,6 +19,8 @@ import { isOrgOverrideReasonCode } from "./org-override-reason.js";
|
|
|
19
19
|
import { PLATFORM_BRAND_NAME, PLATFORM_BRANDING_PROFILE } from "./platform-brand.js";
|
|
20
20
|
import { listPluginFeatures, listPluginSeatAddons, pluginSeatAddon } from "../plugin-manager/plugin-entitlements.js";
|
|
21
21
|
import { pluginOrgCapacity } from "../plugin-manager/plugin-org-capacity.js";
|
|
22
|
+
import { declaredMeterReading, pluginCostAxes, pluginCostAxisFields } from "../plugin-manager/plugin-usage-axes.js";
|
|
23
|
+
import { planQuotaOf, pluginPlanFeatureRow, pluginPlanQuotaRow, pluginPlanQuotas } from "../plugin-manager/plugin-plan-entitlements.js";
|
|
22
24
|
/** Sentinel for quotas a plan does not cap; `checkQuota` always allows. */ export const UNLIMITED = Number.POSITIVE_INFINITY;
|
|
23
25
|
/**
|
|
24
26
|
* How many saved form definitions one site may hold, on every plan that can
|
|
@@ -159,78 +161,6 @@ import { pluginOrgCapacity } from "../plugin-manager/plugin-org-capacity.js";
|
|
|
159
161
|
* without moving the figure every other agreement is measured against — the
|
|
160
162
|
* same mechanism every numeric entitlement uses.
|
|
161
163
|
*/ export const ENTERPRISE_EMAIL_SENDS_PER_MONTH = 260000;
|
|
162
|
-
/**
|
|
163
|
-
* Aglyn Assist credits an Enterprise agreement includes per month, before the
|
|
164
|
-
* contract says otherwise.
|
|
165
|
-
*
|
|
166
|
-
* ## Never `UNLIMITED`, and the reason is not stylistic
|
|
167
|
-
*
|
|
168
|
-
* `UNLIMITED` is `Number.POSITIVE_INFINITY`, `JSON.stringify(Infinity)` is
|
|
169
|
-
* `null`, and `Number(null)` is `0`. An unbounded assist band therefore
|
|
170
|
-
* serialises to a band of ZERO through every route that does not also send
|
|
171
|
-
* the explicit flag `restoreQuotaLimit` rebuilds from — which would hand the
|
|
172
|
-
* only customers with a signed contract the one budget that refuses
|
|
173
|
-
* everything. A finite number crosses the wire as itself.
|
|
174
|
-
*
|
|
175
|
-
* The band is also a real liability rather than a capacity we already own.
|
|
176
|
-
* Storage and page views are infrastructure metered into the deal; assist is
|
|
177
|
-
* a per-token charge from a third party, and generative building spends it in
|
|
178
|
-
* units two orders of magnitude apart.
|
|
179
|
-
*
|
|
180
|
-
* ## Why this number
|
|
181
|
-
*
|
|
182
|
-
* Enterprise carries no list price, so the band cannot be sized the way every
|
|
183
|
-
* self-serve tier's is — against what that tier's other cost terms leave out
|
|
184
|
-
* of a known price. It is anchored to the top of the ladder instead: 116,000
|
|
185
|
-
* credits is twice Agency's band, the rule every Enterprise fallback follows
|
|
186
|
-
* since the 2026-09-07 pricing decision (see the `enterprise` row of
|
|
187
|
-
* `PLAN_ENTITLEMENTS`). In cost that is $116 of provider spend a month, or
|
|
188
|
-
* under 9% of any deal priced at or above the self-serve top. A deal below
|
|
189
|
-
* that is sold as Agency, not written as an Enterprise agreement.
|
|
190
|
-
*
|
|
191
|
-
* ## It is a DEFAULT, and a contract raises it
|
|
192
|
-
*
|
|
193
|
-
* `resolveOrgEntitlements` applies a per-org `entitlements.assistCreditsPerMonth`
|
|
194
|
-
* override ahead of this, so a deal that buys more assist buys it on that org
|
|
195
|
-
* without moving the figure every other agreement is measured against — the
|
|
196
|
-
* same mechanism the other contracted bands use.
|
|
197
|
-
*/ export const ENTERPRISE_ASSIST_CREDITS_PER_MONTH = 116000;
|
|
198
|
-
/**
|
|
199
|
-
* The Free AI taste (AGL-2925): the assist credits a Free workspace draws
|
|
200
|
-
* on each month, behind a hard wall.
|
|
201
|
-
*
|
|
202
|
-
* ## Why it exists
|
|
203
|
-
*
|
|
204
|
-
* So the AI landing pages can say "generate your first page free" and mean
|
|
205
|
-
* it. Three hundred credits is one or two generated sections or a handful
|
|
206
|
-
* of copy rewrites — enough to see what the assistant does, not enough to
|
|
207
|
-
* build a site on. The band is a WALL: `PLAN_PRICING.free
|
|
208
|
-
* .extraAssistCreditsUsdPer1k` stays `null`, so `assistBandRefuses` answers
|
|
209
|
-
* true and the reservation refuses at 100% with no overage, no switch and no
|
|
210
|
-
* invoice. Nothing about a Free workspace can produce a charge.
|
|
211
|
-
*
|
|
212
|
-
* ## What it costs, and why that is the number
|
|
213
|
-
*
|
|
214
|
-
* A credit is `ASSIST_CREDIT_COST_USD` of provider spend, so the band costs
|
|
215
|
-
* at most **$0.30 per Free workspace per month** — asserted by
|
|
216
|
-
* `apps/console/specs/tier-margin-floor.spec.ts`. It is the one AI band with
|
|
217
|
-
* no invoice behind it, which is why the same issue closes every multiplier
|
|
218
|
-
* a script could use before the flag flips:
|
|
219
|
-
*
|
|
220
|
-
* - it is metered per ACCOUNT as well as per workspace, so the three free
|
|
221
|
-
* workspaces an account may hold (AGL-2265) share one 300-credit
|
|
222
|
-
* allowance rather than tripling it (`reserveAssistMessage`);
|
|
223
|
-
* - a fresh account waits `AI_FREE_MIN_ACCOUNT_AGE_HOURS` before it can
|
|
224
|
-
* spend, and every free request is bounded per IP, per uid and per
|
|
225
|
-
* account per day;
|
|
226
|
-
* - a platform-wide daily ceiling on free spend pauses the taste for
|
|
227
|
-
* everyone until the UTC day rolls, paid workspaces untouched.
|
|
228
|
-
*
|
|
229
|
-
* The account allowance reads THIS constant rather than the workspace's
|
|
230
|
-
* resolved band, because a staff override that widens one workspace's band
|
|
231
|
-
* is a decision about that workspace, not about how much one person may
|
|
232
|
-
* draw across all of theirs.
|
|
233
|
-
*/ export const FREE_AI_TASTE_CREDITS_PER_MONTH = 300;
|
|
234
164
|
export const PLAN_ENTITLEMENTS = {
|
|
235
165
|
free: {
|
|
236
166
|
hostLimit: 1,
|
|
@@ -243,7 +173,6 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
243
173
|
maxManagersPerOrg: 1,
|
|
244
174
|
maxMembersPerHost: 1,
|
|
245
175
|
bandwidthGb: 2,
|
|
246
|
-
formSubmissionsPerMonth: 20,
|
|
247
176
|
// No saved-form CATALOG on Free: the form entity rides
|
|
248
177
|
// `reusableComponents`, which is Starter-and-above, so
|
|
249
178
|
// `/api/hosts/resources` refuses the create on the entitlement before it
|
|
@@ -260,22 +189,11 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
260
189
|
variablesPerHost: 3,
|
|
261
190
|
functionsPerHost: 1,
|
|
262
191
|
workflowsPerHost: 0,
|
|
263
|
-
workflowRunsPerMonth: 0,
|
|
264
192
|
servicesPerHost: 0,
|
|
265
193
|
redirectsPerHost: 0,
|
|
266
194
|
contactsPerHost: 100,
|
|
267
|
-
// No one-to-one email on Free, which has no CRM (below): the send lives
|
|
268
|
-
// on a record's page, and Free opens no record. Zero here is what
|
|
269
|
-
// `checkCrmEmailQuota` refuses
|
|
270
|
-
// against, so a per-org grant of `features.crm` alone still sends
|
|
271
|
-
// nothing until the band is raised with it.
|
|
272
|
-
crmEmailsPerDay: 0,
|
|
273
195
|
emailSendsPerMonth: 0,
|
|
274
196
|
actionRunsPerMonth: 0,
|
|
275
|
-
// The Free AI taste (AGL-2925): a real band, and a wall. See the
|
|
276
|
-
// constant for what it buys, what it costs and the precautions that
|
|
277
|
-
// keep one person from drawing it three times over.
|
|
278
|
-
assistCreditsPerMonth: FREE_AI_TASTE_CREDITS_PER_MONTH,
|
|
279
197
|
apiRequestsPerMonth: 0,
|
|
280
198
|
datasetsPerOrg: 0,
|
|
281
199
|
maxDatasetsPerOrg: 0,
|
|
@@ -286,11 +204,6 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
286
204
|
posRegisters: 0,
|
|
287
205
|
transactionFeePhysicalPct: 0,
|
|
288
206
|
transactionFeeDigitalPct: 0,
|
|
289
|
-
// Marketplace take rate (AGL-46/1543): free-plan sellers pay a higher
|
|
290
|
-
// share. `marketplaceSelling` is false here, so this rate only prices
|
|
291
|
-
// an org GRANTED selling via a per-org feature override — and any org
|
|
292
|
-
// whose dead subscription resolved it down to free.
|
|
293
|
-
marketplaceFeePct: 30,
|
|
294
207
|
features: {
|
|
295
208
|
abTesting: false,
|
|
296
209
|
versioning: false,
|
|
@@ -308,10 +221,9 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
308
221
|
dedicatedSendingDomain: false,
|
|
309
222
|
removeBranding: false,
|
|
310
223
|
scheduledPublishing: false,
|
|
311
|
-
marketplaceSelling: false,
|
|
312
224
|
// The two AI flags point opposite ways on Free, on purpose (AGL-2925).
|
|
313
225
|
// `aiAssist` is the guided rung of the console assistant — page-aware
|
|
314
|
-
// level-2 answers and the copy assistant — and
|
|
226
|
+
// level-2 answers and the copy assistant — and starts at Starter; Free
|
|
315
227
|
// keeps the docs-grounded level-1 chat it always had. `aiGenerative`
|
|
316
228
|
// is the generative door the taste is FOR: a Free workspace may
|
|
317
229
|
// generate against its 300-credit band, behind the wall and every
|
|
@@ -364,13 +276,10 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
364
276
|
marketingOverlays: false,
|
|
365
277
|
commerce: false,
|
|
366
278
|
pos: false,
|
|
367
|
-
storefrontSubscriptions: false,
|
|
368
279
|
contentGating: false,
|
|
369
|
-
giftCards: false,
|
|
370
280
|
productReviews: false,
|
|
371
281
|
abandonedCart: false,
|
|
372
282
|
dropshipRouting: false,
|
|
373
|
-
commerceAnalytics: false,
|
|
374
283
|
whiteLabel: false,
|
|
375
284
|
ssoEnabled: false
|
|
376
285
|
}
|
|
@@ -385,24 +294,15 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
385
294
|
managersPerOrg: 2,
|
|
386
295
|
maxManagersPerOrg: 5,
|
|
387
296
|
maxMembersPerHost: 10,
|
|
388
|
-
|
|
389
|
-
|
|
297
|
+
// Sized by the same annual-price invariant as Pro's — see that band.
|
|
298
|
+
bandwidthGb: 20,
|
|
390
299
|
formsPerHost: FORMS_PER_HOST_CEILING,
|
|
391
300
|
variablesPerHost: 25,
|
|
392
301
|
functionsPerHost: 10,
|
|
393
302
|
workflowsPerHost: 3,
|
|
394
|
-
workflowRunsPerMonth: 500,
|
|
395
303
|
servicesPerHost: 1,
|
|
396
304
|
redirectsPerHost: 25,
|
|
397
305
|
contactsPerHost: 1000,
|
|
398
|
-
// One-to-one email from a CRM record, per UTC day (AGL-2611). A hard
|
|
399
|
-
// daily pace rather than a monthly meter — see `crmEmailsPerDay` on
|
|
400
|
-
// `OrgEntitlements` — sized so the whole day spent at $0.0009 a message
|
|
401
|
-
// leaves the tier's CRM axis inside the 20% cost share the Drive
|
|
402
|
-
// pricing decision of 2026-09-05 sets. 50 a day is $1.35 a month against
|
|
403
|
-
// a $16 annual price. Every send still lands on the `emailSends` cost
|
|
404
|
-
// meter beside the transactional mail this tier already sends.
|
|
405
|
-
crmEmailsPerDay: 50,
|
|
406
306
|
// Campaign email starts at Pro. A site that may send campaigns needs its
|
|
407
307
|
// own verified provider sending domain, and provisioning one is a real
|
|
408
308
|
// per-site operational cost that a campaign allowance commits the platform
|
|
@@ -424,50 +324,6 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
424
324
|
// to it, and the CRM is what a Starter site builds before it upgrades.
|
|
425
325
|
emailSendsPerMonth: 0,
|
|
426
326
|
actionRunsPerMonth: 0,
|
|
427
|
-
// The first paid rung of the assist ladder (AGL-3203). Starter banded at
|
|
428
|
-
// 0 until 2026-09-20, which put a PAYING workspace below the Free taste's
|
|
429
|
-
// 300 on the one axis a visitor compares straight down the column — the
|
|
430
|
-
// `/pricing` row read `300 / mo` for Free and `—` for Starter. A paid
|
|
431
|
-
// plan that includes less of something than the free plan is not a
|
|
432
|
-
// packaging subtlety; it is the comparison table arguing against the
|
|
433
|
-
// upgrade.
|
|
434
|
-
//
|
|
435
|
-
// 750 is deliberately small: 2.5x the taste, enough that the assistant is
|
|
436
|
-
// a thing the tier HAS rather than a thing it is shown, and $0.75 of
|
|
437
|
-
// provider spend a month at `ASSIST_CREDIT_COST_USD` against a $16 annual
|
|
438
|
-
// price — a twentieth of the $8.81 the tier's other metered bands already
|
|
439
|
-
// cost, and the widest margin on the ladder absorbs it with room left
|
|
440
|
-
// (`tier-margin-floor.spec.ts` carries the arithmetic).
|
|
441
|
-
//
|
|
442
|
-
// It is NOT a wall, unlike Free's: `PLAN_PRICING.starter
|
|
443
|
-
// .extraAssistCreditsUsdPer1k` is $3.00, so past 750 the tier meters and
|
|
444
|
-
// bills like every paid plan above it. The two fields move together by
|
|
445
|
-
// rule — a positive band with no rate beside it is usage past a bound
|
|
446
|
-
// that is silently free, which `plan-entitlements.spec.ts` forbids.
|
|
447
|
-
//
|
|
448
|
-
// `features.aiAssist` is TRUE, and AGL-3203 shipping it false was the
|
|
449
|
-
// defect AGL-3207 closes. The reasoning then was "the band is credits,
|
|
450
|
-
// not the guided rung, exactly as on Free" — but on Free the band IS
|
|
451
|
-
// spendable, through `aiGenerative`, which is the door the taste exists
|
|
452
|
-
// for. Starter carried neither flag, so it was the only row on the
|
|
453
|
-
// ladder sold a band with nothing to spend it through: 750 credits
|
|
454
|
-
// reachable only by buying the $9 add-on that was also the only thing
|
|
455
|
-
// that made them usable. "No plan bands at zero any more" was true of
|
|
456
|
-
// the number and false of the capability.
|
|
457
|
-
//
|
|
458
|
-
// It opens `aiAssist` rather than `aiGenerative` because that is the
|
|
459
|
-
// shape of every paid rung above it — the included band funds the guided
|
|
460
|
-
// assistant and generation is the add-on. Opening the generative door
|
|
461
|
-
// here instead would hand the FIRST paid rung a door Pro through Agency
|
|
462
|
-
// have to buy.
|
|
463
|
-
//
|
|
464
|
-
// No cost moves: `tier-margin-floor.spec.ts` already prices this tier's
|
|
465
|
-
// assist term at 100% burn of the 750 credits, 75¢/mo. A door does not
|
|
466
|
-
// widen a band; it only makes spend that was already modeled reachable.
|
|
467
|
-
//
|
|
468
|
-
// The AI add-on adds `AI_ADDON_CREDITS_PER_MONTH.starter` on top and
|
|
469
|
-
// switches `aiGenerative` on as well.
|
|
470
|
-
assistCreditsPerMonth: 750,
|
|
471
327
|
apiRequestsPerMonth: 0,
|
|
472
328
|
datasetsPerOrg: 3,
|
|
473
329
|
maxDatasetsPerOrg: 10,
|
|
@@ -482,7 +338,6 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
482
338
|
// norm (Wix/BigCommerce/Squarespace-Core = 0% platform fee). See the
|
|
483
339
|
// Pricing Decision Log + Competitive Benchmark.
|
|
484
340
|
transactionFeeDigitalPct: 5,
|
|
485
|
-
marketplaceFeePct: 20,
|
|
486
341
|
features: {
|
|
487
342
|
abTesting: false,
|
|
488
343
|
versioning: false,
|
|
@@ -500,7 +355,6 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
500
355
|
dedicatedSendingDomain: false,
|
|
501
356
|
removeBranding: true,
|
|
502
357
|
scheduledPublishing: false,
|
|
503
|
-
marketplaceSelling: false,
|
|
504
358
|
aiAssist: true,
|
|
505
359
|
aiGenerative: false,
|
|
506
360
|
workflows: true,
|
|
@@ -527,13 +381,10 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
527
381
|
marketingOverlays: true,
|
|
528
382
|
commerce: true,
|
|
529
383
|
pos: false,
|
|
530
|
-
storefrontSubscriptions: false,
|
|
531
384
|
contentGating: false,
|
|
532
|
-
giftCards: false,
|
|
533
385
|
productReviews: false,
|
|
534
386
|
abandonedCart: false,
|
|
535
387
|
dropshipRouting: false,
|
|
536
|
-
commerceAnalytics: false,
|
|
537
388
|
whiteLabel: false,
|
|
538
389
|
ssoEnabled: false
|
|
539
390
|
}
|
|
@@ -548,36 +399,35 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
548
399
|
managersPerOrg: 5,
|
|
549
400
|
maxManagersPerOrg: 20,
|
|
550
401
|
maxMembersPerHost: 25,
|
|
551
|
-
// Page views are the largest term of this tier's modeled COGS
|
|
552
|
-
//
|
|
553
|
-
//
|
|
554
|
-
//
|
|
402
|
+
// Page views are the largest term of this tier's modeled COGS. One GB is
|
|
403
|
+
// 1,035 views at `ESTIMATED_PAGE_TRANSFER_BYTES`, priced where the CDN is
|
|
404
|
+
// dearest because it bills in the region that serves a visitor: $0.367 of
|
|
405
|
+
// weight (`perPageView`, transfer at $0.35 a GB) and $0.190 of CDN
|
|
406
|
+
// requests once the hosting plan's monthly allowance is spent
|
|
407
|
+
// (`PAGE_VIEW_CDN_REQUEST_COST_USD`, $3.20 per million). So a GB of
|
|
408
|
+
// included bandwidth costs $0.557, and the bandwidth band is what decides
|
|
409
|
+
// whether the tier survives a customer spending the whole allowance it
|
|
410
|
+
// was sold.
|
|
555
411
|
//
|
|
556
412
|
// The invariant the band is sized against is the ANNUAL price ($39 a
|
|
557
413
|
// month) net of Stripe's fee, with every band at 100% and the CRM seat
|
|
558
|
-
// and one-to-one email terms counted — the 2026-09-07 pricing decision
|
|
559
|
-
//
|
|
414
|
+
// and one-to-one email terms counted — the 2026-09-07 pricing decision —
|
|
415
|
+
// at that all-in gigabyte (AGL-3444). 35 GB is what it carries; every
|
|
416
|
+
// paid band on the ladder is sized the same way.
|
|
560
417
|
// `tier-margin-floor.spec.ts` holds the model and pins the figure.
|
|
561
418
|
//
|
|
562
419
|
// `meteredInfraPassThrough` is true here, so traffic past the band BILLS
|
|
563
420
|
// at the page-view pass-through rather than being refused or absorbed.
|
|
564
|
-
bandwidthGb:
|
|
565
|
-
formSubmissionsPerMonth: 1000,
|
|
421
|
+
bandwidthGb: 35,
|
|
566
422
|
formsPerHost: FORMS_PER_HOST_CEILING,
|
|
567
423
|
variablesPerHost: 100,
|
|
568
424
|
functionsPerHost: 50,
|
|
569
425
|
workflowsPerHost: 25,
|
|
570
|
-
workflowRunsPerMonth: 5000,
|
|
571
426
|
servicesPerHost: UNLIMITED,
|
|
572
427
|
redirectsPerHost: 100,
|
|
573
428
|
contactsPerHost: 10000,
|
|
574
|
-
crmEmailsPerDay: 150,
|
|
575
429
|
emailSendsPerMonth: 5000,
|
|
576
430
|
actionRunsPerMonth: 5000,
|
|
577
|
-
// $2.75 of provider spend, against the $8.35 the tier's other seven cost
|
|
578
|
-
// terms leave out of $56. See `OrgEntitlements.assistCreditsPerMonth` for
|
|
579
|
-
// why the remainder and not the price is what sizes this.
|
|
580
|
-
assistCreditsPerMonth: 2750,
|
|
581
431
|
apiRequestsPerMonth: 0,
|
|
582
432
|
datasetsPerOrg: 15,
|
|
583
433
|
maxDatasetsPerOrg: 50,
|
|
@@ -590,7 +440,6 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
590
440
|
// Pricing v3 (2026-07): softened 5→3 to smooth the digital fee ladder
|
|
591
441
|
// (Starter 5 → Pro 3 → Business 2 → Scale 1 → Advanced/Agency 0).
|
|
592
442
|
transactionFeeDigitalPct: 3,
|
|
593
|
-
marketplaceFeePct: 20,
|
|
594
443
|
features: {
|
|
595
444
|
abTesting: false,
|
|
596
445
|
versioning: true,
|
|
@@ -621,7 +470,6 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
621
470
|
dedicatedSendingDomain: true,
|
|
622
471
|
removeBranding: true,
|
|
623
472
|
scheduledPublishing: false,
|
|
624
|
-
marketplaceSelling: true,
|
|
625
473
|
aiAssist: true,
|
|
626
474
|
aiGenerative: false,
|
|
627
475
|
workflows: true,
|
|
@@ -643,13 +491,10 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
643
491
|
marketingOverlays: true,
|
|
644
492
|
commerce: true,
|
|
645
493
|
pos: true,
|
|
646
|
-
storefrontSubscriptions: false,
|
|
647
494
|
contentGating: false,
|
|
648
|
-
giftCards: false,
|
|
649
495
|
productReviews: true,
|
|
650
496
|
abandonedCart: true,
|
|
651
497
|
dropshipRouting: true,
|
|
652
|
-
commerceAnalytics: true,
|
|
653
498
|
whiteLabel: false,
|
|
654
499
|
ssoEnabled: false
|
|
655
500
|
}
|
|
@@ -665,21 +510,16 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
665
510
|
maxManagersPerOrg: 100,
|
|
666
511
|
maxMembersPerHost: 100,
|
|
667
512
|
// Sized by the same annual-price invariant as Pro's — see that band.
|
|
668
|
-
bandwidthGb:
|
|
669
|
-
formSubmissionsPerMonth: 8000,
|
|
513
|
+
bandwidthGb: 55,
|
|
670
514
|
formsPerHost: FORMS_PER_HOST_CEILING,
|
|
671
515
|
variablesPerHost: 1000,
|
|
672
516
|
functionsPerHost: 250,
|
|
673
517
|
workflowsPerHost: 100,
|
|
674
|
-
workflowRunsPerMonth: 50000,
|
|
675
518
|
servicesPerHost: UNLIMITED,
|
|
676
519
|
redirectsPerHost: UNLIMITED,
|
|
677
520
|
contactsPerHost: 50000,
|
|
678
|
-
crmEmailsPerDay: 200,
|
|
679
521
|
emailSendsPerMonth: 25000,
|
|
680
522
|
actionRunsPerMonth: 50000,
|
|
681
|
-
// $7.50, against the $22.69 the other seven terms leave out of $139.
|
|
682
|
-
assistCreditsPerMonth: 7500,
|
|
683
523
|
apiRequestsPerMonth: 100000,
|
|
684
524
|
datasetsPerOrg: 100,
|
|
685
525
|
maxDatasetsPerOrg: 250,
|
|
@@ -690,7 +530,6 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
690
530
|
posRegisters: 2,
|
|
691
531
|
transactionFeePhysicalPct: 0,
|
|
692
532
|
transactionFeeDigitalPct: 2,
|
|
693
|
-
marketplaceFeePct: 20,
|
|
694
533
|
features: {
|
|
695
534
|
abTesting: true,
|
|
696
535
|
versioning: true,
|
|
@@ -700,7 +539,6 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
700
539
|
dedicatedSendingDomain: true,
|
|
701
540
|
removeBranding: true,
|
|
702
541
|
scheduledPublishing: true,
|
|
703
|
-
marketplaceSelling: true,
|
|
704
542
|
aiAssist: true,
|
|
705
543
|
aiGenerative: false,
|
|
706
544
|
workflows: true,
|
|
@@ -722,13 +560,10 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
722
560
|
marketingOverlays: true,
|
|
723
561
|
commerce: true,
|
|
724
562
|
pos: true,
|
|
725
|
-
storefrontSubscriptions: true,
|
|
726
563
|
contentGating: true,
|
|
727
|
-
giftCards: true,
|
|
728
564
|
productReviews: true,
|
|
729
565
|
abandonedCart: true,
|
|
730
566
|
dropshipRouting: true,
|
|
731
|
-
commerceAnalytics: true,
|
|
732
567
|
whiteLabel: false,
|
|
733
568
|
ssoEnabled: false
|
|
734
569
|
}
|
|
@@ -746,21 +581,17 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
746
581
|
managersPerOrg: 25,
|
|
747
582
|
maxManagersPerOrg: 150,
|
|
748
583
|
maxMembersPerHost: 150,
|
|
749
|
-
|
|
750
|
-
|
|
584
|
+
// Sized by the same annual-price invariant as Pro's — see that band.
|
|
585
|
+
bandwidthGb: 90,
|
|
751
586
|
formsPerHost: FORMS_PER_HOST_CEILING,
|
|
752
587
|
variablesPerHost: 5000,
|
|
753
588
|
functionsPerHost: 500,
|
|
754
589
|
workflowsPerHost: 250,
|
|
755
|
-
workflowRunsPerMonth: 150000,
|
|
756
590
|
servicesPerHost: UNLIMITED,
|
|
757
591
|
redirectsPerHost: UNLIMITED,
|
|
758
592
|
contactsPerHost: 100000,
|
|
759
|
-
crmEmailsPerDay: 300,
|
|
760
593
|
emailSendsPerMonth: 40000,
|
|
761
594
|
actionRunsPerMonth: 100000,
|
|
762
|
-
// $10.00, against the $30.62 the other seven terms leave out of $249.
|
|
763
|
-
assistCreditsPerMonth: 10000,
|
|
764
595
|
apiRequestsPerMonth: 300000,
|
|
765
596
|
datasetsPerOrg: 250,
|
|
766
597
|
maxDatasetsPerOrg: 500,
|
|
@@ -771,7 +602,6 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
771
602
|
posRegisters: 3,
|
|
772
603
|
transactionFeePhysicalPct: 0,
|
|
773
604
|
transactionFeeDigitalPct: 1,
|
|
774
|
-
marketplaceFeePct: 20,
|
|
775
605
|
features: {
|
|
776
606
|
abTesting: true,
|
|
777
607
|
versioning: true,
|
|
@@ -781,7 +611,6 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
781
611
|
dedicatedSendingDomain: true,
|
|
782
612
|
removeBranding: true,
|
|
783
613
|
scheduledPublishing: true,
|
|
784
|
-
marketplaceSelling: true,
|
|
785
614
|
aiAssist: true,
|
|
786
615
|
aiGenerative: false,
|
|
787
616
|
workflows: true,
|
|
@@ -803,13 +632,10 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
803
632
|
marketingOverlays: true,
|
|
804
633
|
commerce: true,
|
|
805
634
|
pos: true,
|
|
806
|
-
storefrontSubscriptions: true,
|
|
807
635
|
contentGating: true,
|
|
808
|
-
giftCards: true,
|
|
809
636
|
productReviews: true,
|
|
810
637
|
abandonedCart: true,
|
|
811
638
|
dropshipRouting: true,
|
|
812
|
-
commerceAnalytics: true,
|
|
813
639
|
whiteLabel: false,
|
|
814
640
|
ssoEnabled: false
|
|
815
641
|
}
|
|
@@ -824,23 +650,17 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
824
650
|
managersPerOrg: 50,
|
|
825
651
|
maxManagersPerOrg: 250,
|
|
826
652
|
maxMembersPerHost: 250,
|
|
827
|
-
|
|
828
|
-
|
|
653
|
+
// Sized by the same annual-price invariant as Pro's — see that band.
|
|
654
|
+
bandwidthGb: 105,
|
|
829
655
|
formsPerHost: FORMS_PER_HOST_CEILING,
|
|
830
656
|
variablesPerHost: UNLIMITED,
|
|
831
657
|
functionsPerHost: 1000,
|
|
832
658
|
workflowsPerHost: 500,
|
|
833
|
-
workflowRunsPerMonth: 500000,
|
|
834
659
|
servicesPerHost: UNLIMITED,
|
|
835
660
|
redirectsPerHost: UNLIMITED,
|
|
836
661
|
contactsPerHost: 150000,
|
|
837
|
-
crmEmailsPerDay: 500,
|
|
838
662
|
emailSendsPerMonth: 65000,
|
|
839
663
|
actionRunsPerMonth: 250000,
|
|
840
|
-
// $13.00, against the $39.74 the other seven terms leave out of $399 —
|
|
841
|
-
// the thinnest remainder on the ladder, and the tier that binds the
|
|
842
|
-
// whole assist ladder's share of it.
|
|
843
|
-
assistCreditsPerMonth: 13000,
|
|
844
664
|
apiRequestsPerMonth: 1000000,
|
|
845
665
|
datasetsPerOrg: 500,
|
|
846
666
|
maxDatasetsPerOrg: 1000,
|
|
@@ -851,7 +671,6 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
851
671
|
posRegisters: 5,
|
|
852
672
|
transactionFeePhysicalPct: 0,
|
|
853
673
|
transactionFeeDigitalPct: 0,
|
|
854
|
-
marketplaceFeePct: 20,
|
|
855
674
|
features: {
|
|
856
675
|
abTesting: true,
|
|
857
676
|
versioning: true,
|
|
@@ -861,7 +680,6 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
861
680
|
dedicatedSendingDomain: true,
|
|
862
681
|
removeBranding: true,
|
|
863
682
|
scheduledPublishing: true,
|
|
864
|
-
marketplaceSelling: true,
|
|
865
683
|
aiAssist: true,
|
|
866
684
|
aiGenerative: false,
|
|
867
685
|
workflows: true,
|
|
@@ -883,13 +701,10 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
883
701
|
marketingOverlays: true,
|
|
884
702
|
commerce: true,
|
|
885
703
|
pos: true,
|
|
886
|
-
storefrontSubscriptions: true,
|
|
887
704
|
contentGating: true,
|
|
888
|
-
giftCards: true,
|
|
889
705
|
productReviews: true,
|
|
890
706
|
abandonedCart: true,
|
|
891
707
|
dropshipRouting: true,
|
|
892
|
-
commerceAnalytics: true,
|
|
893
708
|
whiteLabel: false,
|
|
894
709
|
ssoEnabled: false
|
|
895
710
|
}
|
|
@@ -908,33 +723,17 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
908
723
|
managersPerOrg: 100,
|
|
909
724
|
maxManagersPerOrg: 500,
|
|
910
725
|
maxMembersPerHost: 1000,
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
// `formSubmissionsPerMonth` is multiplied by `hostLimit` to get the
|
|
914
|
-
// org-wide band, so at 100 hosts an unbounded figure was not merely
|
|
915
|
-
// large — it made this tier's cost model unbounded, and an unbounded
|
|
916
|
-
// term reads as ZERO in any analysis that scores an absent band as
|
|
917
|
-
// nothing. That is how it stayed invisible: the biggest line item on the
|
|
918
|
-
// most expensive self-serve plan, contributing 0 to every total.
|
|
919
|
-
//
|
|
920
|
-
// Metering makes it safe to bound. `meteredInfraPassThrough` is true
|
|
921
|
-
// here, so submissions past the band BILL at the pass-through rate
|
|
922
|
-
// rather than being refused — a merchant's lead form does not stop
|
|
923
|
-
// working at 25,000.
|
|
924
|
-
formSubmissionsPerMonth: 25000,
|
|
726
|
+
// Sized by the same annual-price invariant as Pro's — see that band.
|
|
727
|
+
bandwidthGb: 485,
|
|
925
728
|
formsPerHost: FORMS_PER_HOST_CEILING,
|
|
926
729
|
variablesPerHost: UNLIMITED,
|
|
927
730
|
functionsPerHost: UNLIMITED,
|
|
928
731
|
workflowsPerHost: UNLIMITED,
|
|
929
|
-
workflowRunsPerMonth: 2000000,
|
|
930
732
|
servicesPerHost: UNLIMITED,
|
|
931
733
|
redirectsPerHost: UNLIMITED,
|
|
932
734
|
contactsPerHost: 500000,
|
|
933
|
-
crmEmailsPerDay: 1000,
|
|
934
735
|
emailSendsPerMonth: 130000,
|
|
935
736
|
actionRunsPerMonth: 1000000,
|
|
936
|
-
// $58.00, against the $176.71 the other seven terms leave out of $1,299.
|
|
937
|
-
assistCreditsPerMonth: 58000,
|
|
938
737
|
apiRequestsPerMonth: 5000000,
|
|
939
738
|
datasetsPerOrg: 2000,
|
|
940
739
|
maxDatasetsPerOrg: 5000,
|
|
@@ -945,7 +744,6 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
945
744
|
posRegisters: 20,
|
|
946
745
|
transactionFeePhysicalPct: 0,
|
|
947
746
|
transactionFeeDigitalPct: 0,
|
|
948
|
-
marketplaceFeePct: 20,
|
|
949
747
|
features: {
|
|
950
748
|
abTesting: true,
|
|
951
749
|
versioning: true,
|
|
@@ -955,7 +753,6 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
955
753
|
dedicatedSendingDomain: true,
|
|
956
754
|
removeBranding: true,
|
|
957
755
|
scheduledPublishing: true,
|
|
958
|
-
marketplaceSelling: true,
|
|
959
756
|
aiAssist: true,
|
|
960
757
|
aiGenerative: false,
|
|
961
758
|
workflows: true,
|
|
@@ -977,13 +774,10 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
977
774
|
marketingOverlays: true,
|
|
978
775
|
commerce: true,
|
|
979
776
|
pos: true,
|
|
980
|
-
storefrontSubscriptions: true,
|
|
981
777
|
contentGating: true,
|
|
982
|
-
giftCards: true,
|
|
983
778
|
productReviews: true,
|
|
984
779
|
abandonedCart: true,
|
|
985
780
|
dropshipRouting: true,
|
|
986
|
-
commerceAnalytics: true,
|
|
987
781
|
// White-Label Phase 1: the Agency-tier ($1,299) differentiator. Only
|
|
988
782
|
// this tier and Enterprise ship white-label by default.
|
|
989
783
|
whiteLabel: true,
|
|
@@ -1039,25 +833,16 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
1039
833
|
managersPerOrg: 200,
|
|
1040
834
|
maxManagersPerOrg: 1000,
|
|
1041
835
|
maxMembersPerHost: 2000,
|
|
1042
|
-
bandwidthGb:
|
|
1043
|
-
formSubmissionsPerMonth: 50000,
|
|
836
|
+
bandwidthGb: 970,
|
|
1044
837
|
formsPerHost: FORMS_PER_HOST_CEILING,
|
|
1045
838
|
variablesPerHost: UNLIMITED,
|
|
1046
839
|
functionsPerHost: UNLIMITED,
|
|
1047
840
|
workflowsPerHost: UNLIMITED,
|
|
1048
|
-
workflowRunsPerMonth: 4000000,
|
|
1049
841
|
servicesPerHost: UNLIMITED,
|
|
1050
842
|
redirectsPerHost: UNLIMITED,
|
|
1051
843
|
contactsPerHost: 1000000,
|
|
1052
|
-
// Finite like the campaign allowance beside it, and for the same reason
|
|
1053
|
-
// one-to-one mail is capped on every other tier: a rep with a template
|
|
1054
|
-
// and a list can put thousands of messages onto the platform's sending
|
|
1055
|
-
// reputation in an afternoon. A negotiated agreement whose reps need more
|
|
1056
|
-
// than 2,000 a day says so, and the override is what carries it.
|
|
1057
|
-
crmEmailsPerDay: 2000,
|
|
1058
844
|
emailSendsPerMonth: ENTERPRISE_EMAIL_SENDS_PER_MONTH,
|
|
1059
845
|
actionRunsPerMonth: 2000000,
|
|
1060
|
-
assistCreditsPerMonth: ENTERPRISE_ASSIST_CREDITS_PER_MONTH,
|
|
1061
846
|
apiRequestsPerMonth: 10000000,
|
|
1062
847
|
datasetsPerOrg: 4000,
|
|
1063
848
|
maxDatasetsPerOrg: 10000,
|
|
@@ -1068,7 +853,6 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
1068
853
|
posRegisters: 40,
|
|
1069
854
|
transactionFeePhysicalPct: 0,
|
|
1070
855
|
transactionFeeDigitalPct: 0,
|
|
1071
|
-
marketplaceFeePct: 20,
|
|
1072
856
|
features: {
|
|
1073
857
|
abTesting: true,
|
|
1074
858
|
versioning: true,
|
|
@@ -1078,7 +862,6 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
1078
862
|
dedicatedSendingDomain: true,
|
|
1079
863
|
removeBranding: true,
|
|
1080
864
|
scheduledPublishing: true,
|
|
1081
|
-
marketplaceSelling: true,
|
|
1082
865
|
aiAssist: true,
|
|
1083
866
|
aiGenerative: true,
|
|
1084
867
|
workflows: true,
|
|
@@ -1101,13 +884,10 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
1101
884
|
marketingOverlays: true,
|
|
1102
885
|
commerce: true,
|
|
1103
886
|
pos: true,
|
|
1104
|
-
storefrontSubscriptions: true,
|
|
1105
887
|
contentGating: true,
|
|
1106
|
-
giftCards: true,
|
|
1107
888
|
productReviews: true,
|
|
1108
889
|
abandonedCart: true,
|
|
1109
890
|
dropshipRouting: true,
|
|
1110
|
-
commerceAnalytics: true,
|
|
1111
891
|
whiteLabel: true,
|
|
1112
892
|
// SSO (AGL-1101) is the Enterprise differentiator — the only plan that
|
|
1113
893
|
// carries it by default. Lower tiers still need a per-org override.
|
|
@@ -1115,6 +895,32 @@ export const PLAN_ENTITLEMENTS = {
|
|
|
1115
895
|
}
|
|
1116
896
|
}
|
|
1117
897
|
};
|
|
898
|
+
/**
|
|
899
|
+
* Each plan row gains what the plugins declared for that plan (AGL-3080):
|
|
900
|
+
* a plugin's own band or gate — the AI credits, the CRM's one-to-one email
|
|
901
|
+
* pace, the marketplace's take rate — is written beside the reasoning that
|
|
902
|
+
* sized it, in that plugin's `plan-entitlements` module, and compiled into
|
|
903
|
+
* `first-party-plugins.generated.ts`. Filled here, once, as the module
|
|
904
|
+
* loads, so every reader of `PLAN_ENTITLEMENTS` — the pricing tables, the
|
|
905
|
+
* plan comparison, `resolveOrgEntitlements` — reads one table and cannot tell
|
|
906
|
+
* which half of a row a figure came from.
|
|
907
|
+
*
|
|
908
|
+
* Core's keys keep their order and a plugin's follow them. A key both declare
|
|
909
|
+
* keeps CORE's figure, so a declaration can never shadow what the platform
|
|
910
|
+
* already charges; `plan-entitlements.spec.ts` refuses the collision outright.
|
|
911
|
+
*/ function fillPluginPlanEntitlements(rows) {
|
|
912
|
+
for (const plan of Object.keys(rows)){
|
|
913
|
+
const quotas = rows[plan];
|
|
914
|
+
for (const [key, value] of Object.entries(pluginPlanQuotaRow(plan))){
|
|
915
|
+
if (!(key in quotas)) quotas[key] = value;
|
|
916
|
+
}
|
|
917
|
+
const features = rows[plan].features;
|
|
918
|
+
for (const [key, value] of Object.entries(pluginPlanFeatureRow(plan))){
|
|
919
|
+
if (!(key in features)) features[key] = value;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
fillPluginPlanEntitlements(PLAN_ENTITLEMENTS);
|
|
1118
924
|
/**
|
|
1119
925
|
* The tiers a customer can buy themselves — every plan EXCEPT `enterprise`
|
|
1120
926
|
* (AGL-1118), which is priced per deal and provisioned by staff (AGL-1110).
|
|
@@ -1962,6 +1768,74 @@ export const STRIPE_PROCESSOR_FEE_FIXED_USD = 0.3;
|
|
|
1962
1768
|
*
|
|
1963
1769
|
* The console keeps importing it from `usage-metering` unchanged.
|
|
1964
1770
|
*/ export const METERED_MARKUP = 1.3;
|
|
1771
|
+
/**
|
|
1772
|
+
* What the CDN requests behind ONE page view cost once the platform is past
|
|
1773
|
+
* its hosting plan's included request allowance, at the DEAREST region the
|
|
1774
|
+
* CDN bills, in USD per view (AGL-1879, AGL-3444). A page view billed past a
|
|
1775
|
+
* plan's band is priced at `(perPageView + this) × METERED_MARKUP` — $0.70
|
|
1776
|
+
* per 1,000 — and every `bandwidthGb` band is sized with it counted.
|
|
1777
|
+
*
|
|
1778
|
+
* ## Why a page view needs a second cost term
|
|
1779
|
+
*
|
|
1780
|
+
* `perPageView` prices what a view WEIGHS: the bytes it transfers at the
|
|
1781
|
+
* CDN's per-GB rate, plus the Firestore reads behind the render. The CDN also
|
|
1782
|
+
* charges per REQUEST once the team's monthly allowance is spent — Vercel Pro
|
|
1783
|
+
* includes 10,000,000 a month, then bills $2.00 to $3.20 per million by
|
|
1784
|
+
* region. A cold load of `aglyn.com/` makes 57 first-party requests to settle
|
|
1785
|
+
* (`tools/tenant-page-budget.json`, `wireCalibration.measuredAgainst`), so the
|
|
1786
|
+
* allowance is about 175,000 views of that page a month, platform-wide —
|
|
1787
|
+
* about 169 GB of included bandwidth — where the 1 TB transfer allowance
|
|
1788
|
+
* lasts about 1.4 million. The request allowance runs out first.
|
|
1789
|
+
*
|
|
1790
|
+
* ## Why the dearest region
|
|
1791
|
+
*
|
|
1792
|
+
* The CDN bills a request, and the bytes it transfers, in the region that
|
|
1793
|
+
* SERVES it — the one nearest the visitor — so a site whose audience is in
|
|
1794
|
+
* São Paulo or Cape Town costs what those regions cost, and nothing about a
|
|
1795
|
+
* plan can choose otherwise. The platform's rule is that no plan is under
|
|
1796
|
+
* water at any utilization and that "at cost + 30%" is true of every billed
|
|
1797
|
+
* unit, so both terms of a page view are priced where the CDN is dearest:
|
|
1798
|
+
* transfer at $0.35 per GB (in `perPageView`) and requests at $3.20 per
|
|
1799
|
+
* million (here). Past the allowance a view then costs:
|
|
1800
|
+
*
|
|
1801
|
+
* | | weight | requests | cost / 1k | margin at $0.70 |
|
|
1802
|
+
* |-----------------------------------|------------|-----------|-----------|-----------------|
|
|
1803
|
+
* | the page as measured (748.5 KB) | $0.262148 | $0.182400 | $0.4445 | +36.5% |
|
|
1804
|
+
* | the priced basis (1012.8 KB) | $0.354715 | $0.182400 | $0.5371 | +23.3% |
|
|
1805
|
+
*
|
|
1806
|
+
* — at least 30% over cost in every region, which is the claim `/pricing`
|
|
1807
|
+
* makes.
|
|
1808
|
+
*
|
|
1809
|
+
* ## The figure
|
|
1810
|
+
*
|
|
1811
|
+
* $0.00018374681 is 57.42 requests at $3.20 per million — the measured 57,
|
|
1812
|
+
* with the basis set ABOVE the measurement as the weight basis is — pinned so
|
|
1813
|
+
* the billed price lands on a whole cent: ($0.354715 + $0.1824) × 1.3 is
|
|
1814
|
+
* $0.6982 per 1,000, rounded up to $0.70, and ($0.354715 + $0.183747) × 1.3
|
|
1815
|
+
* is exactly $0.70. Published as "Our cost $0.538462 / You pay $0.70", the
|
|
1816
|
+
* "at cost + 30%" claim stays true of the cost a billed view incurs in the
|
|
1817
|
+
* dearest region, and so in every other.
|
|
1818
|
+
*
|
|
1819
|
+
* ## ⛔ Not in {@link ORG_COGS_UNIT_RATES_USD}, deliberately
|
|
1820
|
+
*
|
|
1821
|
+
* `perPageView` is half of a pair with `ESTIMATED_PAGE_TRANSFER_BYTES` — one
|
|
1822
|
+
* page weight in dollars and in bytes — and `npm run check:page-view-rate`
|
|
1823
|
+
* recovers that weight from the rate. A per-request charge is not
|
|
1824
|
+
* proportional to weight, so folding it into `perPageView` would make the
|
|
1825
|
+
* gate read a page nobody serves.
|
|
1826
|
+
*
|
|
1827
|
+
* ## The INCLUDED bands carry it too
|
|
1828
|
+
*
|
|
1829
|
+
* A view inside a plan's band makes the same requests as one past it, and
|
|
1830
|
+
* once the platform is past the allowance the CDN bills them either way, so
|
|
1831
|
+
* the `bandwidthGb` bands are sized with this term counted: $0.190 per
|
|
1832
|
+
* included GB on top of $0.367 of weight. `tier-margin-floor.spec.ts`
|
|
1833
|
+
* multiplies it in and pins every tier at 100% of every band.
|
|
1834
|
+
*
|
|
1835
|
+
* Lives HERE, beside the markup, for the reason the markup does: the
|
|
1836
|
+
* `/pricing` generator publishes the cost column from it and cannot import
|
|
1837
|
+
* anything under `apps/console`.
|
|
1838
|
+
*/ export const PAGE_VIEW_CDN_REQUEST_COST_USD = 0.00018374681;
|
|
1965
1839
|
/**
|
|
1966
1840
|
* Monthly unit costs for the meters the rollup already records (AGL-1134).
|
|
1967
1841
|
*
|
|
@@ -1985,6 +1859,23 @@ export const STRIPE_PROCESSOR_FEE_FIXED_USD = 0.3;
|
|
|
1985
1859
|
* infrastructure pass-through, and the customer is charged those figures
|
|
1986
1860
|
* times `METERED_MARKUP`. They therefore appear in `METERED_UNIT_RATES_USD`
|
|
1987
1861
|
* as well, with identical values, and must be changed in both places at once.
|
|
1862
|
+
* A page view billed past its band also carries
|
|
1863
|
+
* {@link PAGE_VIEW_CDN_REQUEST_COST_USD}, which neither table holds: it is
|
|
1864
|
+
* the per-request CDN charge past the hosting plan's allowance, and this
|
|
1865
|
+
* table's `perPageView` is the weight-proportional half of what a band is
|
|
1866
|
+
* sized against — the request term is the other.
|
|
1867
|
+
*
|
|
1868
|
+
* ## Every Vercel-billed input is priced at Vercel's dearest region
|
|
1869
|
+
*
|
|
1870
|
+
* The CDN and functions bill by region, from $0.15 to $0.35 per GB of
|
|
1871
|
+
* transfer, $2.00 to $3.20 per million requests, and $0.128 to $0.221 per
|
|
1872
|
+
* hour of active CPU (memory $0.0106 to $0.0183 per GB-hour), and a plan
|
|
1873
|
+
* cannot choose where its visitors are. So the Vercel share of every rate
|
|
1874
|
+
* here is priced at the dearest region (AGL-3444): the transfer inside
|
|
1875
|
+
* `perPageView`, the function invocation inside `perFormSubmission`, and the
|
|
1876
|
+
* compute inside `perRun`. The GCP shares — object and Firestore storage, and
|
|
1877
|
+
* the Firestore reads and writes behind a render, a submission or a run —
|
|
1878
|
+
* are priced as they were.
|
|
1988
1879
|
*
|
|
1989
1880
|
* Everything else here is a cost-model input ONLY. `dataStoragePerGbMonth`,
|
|
1990
1881
|
* `perApiRequest`, `perContactMonth` and `perEmailSend` price what an org
|
|
@@ -1994,9 +1885,11 @@ export const STRIPE_PROCESSOR_FEE_FIXED_USD = 0.3;
|
|
|
1994
1885
|
* "at cost + 30%" claim, which is true of exactly three meters.
|
|
1995
1886
|
*
|
|
1996
1887
|
* The first three were corrected 2026-08-09 (AGL-1280) — storage $0.03 →
|
|
1997
|
-
* $0.026 and form submissions $0.0005 → $0.00005 —
|
|
1998
|
-
* re-pegged 2026-09-09 (AGL-2711), from $0.0001 to $0.00016153846
|
|
1999
|
-
*
|
|
1888
|
+
* $0.026 and form submissions $0.0005 → $0.00005 — `perPageView` was
|
|
1889
|
+
* re-pegged 2026-09-09 (AGL-2711), from $0.0001 to $0.00016153846, and the
|
|
1890
|
+
* last two were re-priced at Vercel's dearest region on 2026-10-01
|
|
1891
|
+
* (AGL-3444): page views $0.00035471473, form submissions $0.000053846154.
|
|
1892
|
+
* All three MUST be changed here and in `METERED_UNIT_RATES_USD` together. See that
|
|
2000
1893
|
* table for each figure's basis; it is the one a customer is billed against,
|
|
2001
1894
|
* so it is the one that carries the working.
|
|
2002
1895
|
*
|
|
@@ -2016,10 +1909,10 @@ export const STRIPE_PROCESSOR_FEE_FIXED_USD = 0.3;
|
|
|
2016
1909
|
* ⛔ HALF OF A PAIR — see ESTIMATED_PAGE_TRANSFER_BYTES, which states the
|
|
2017
1910
|
* same page in bytes as this states it in dollars. Both are calibrated
|
|
2018
1911
|
* against a 1012.8 KB page and neither may move alone: their quotient is
|
|
2019
|
-
* the cost of a gigabyte, and that
|
|
2020
|
-
* ladder
|
|
2021
|
-
*/ perPageView: 0.
|
|
2022
|
-
perFormSubmission: 0.
|
|
1912
|
+
* the cost of a gigabyte's weight, and that — with the request term — is
|
|
1913
|
+
* what every bandwidthGb band on the ladder is sized against.
|
|
1914
|
+
*/ perPageView: 0.00035471473,
|
|
1915
|
+
perFormSubmission: 0.000053846154,
|
|
2023
1916
|
/** Firestore-backed dataset bytes — an order pricier than object storage. */ dataStoragePerGbMonth: 0.18,
|
|
2024
1917
|
perApiRequest: 0.000002,
|
|
2025
1918
|
perContactMonth: 0.0002,
|
|
@@ -2038,7 +1931,7 @@ export const STRIPE_PROCESSOR_FEE_FIXED_USD = 0.3;
|
|
|
2038
1931
|
* both concern a smaller quantity; this is the whole bill.
|
|
2039
1932
|
*/ perEmailSend: 0.0009,
|
|
2040
1933
|
/**
|
|
2041
|
-
* One workflow or action run — $
|
|
1934
|
+
* One workflow or action run — $13 per million.
|
|
2042
1935
|
*
|
|
2043
1936
|
* Derived from the run paths at list prices (2026-09-07), because nothing
|
|
2044
1937
|
* measurable exists yet: runs execute inside the Vercel request that fired
|
|
@@ -2057,9 +1950,11 @@ export const STRIPE_PROCESSOR_FEE_FIXED_USD = 0.3;
|
|
|
2057
1950
|
* - writes: the activity row and the counter increment — 2, at $0.18 per
|
|
2058
1951
|
* 100,000 = $0.0000036
|
|
2059
1952
|
* - compute: a few milliseconds of active CPU and memory on Fluid compute
|
|
2060
|
-
* for the expression evaluation, about $0.000001
|
|
1953
|
+
* for the expression evaluation, about $0.000001 in the cheapest
|
|
1954
|
+
* region and $0.0000017 in the dearest ($0.221 against $0.128 an
|
|
1955
|
+
* hour of active CPU), which is where it is priced
|
|
2061
1956
|
*
|
|
2062
|
-
* $0.
|
|
1957
|
+
* $0.0000125, carried as $0.000013. It scales with the catalog a site holds
|
|
2063
1958
|
* — every `limit(100)` read above is a query that costs one read per
|
|
2064
1959
|
* document returned — and a step that writes a dataset record or calls a
|
|
2065
1960
|
* webhook adds to it, so this is the typical figure, not the ceiling.
|
|
@@ -2068,8 +1963,24 @@ export const STRIPE_PROCESSOR_FEE_FIXED_USD = 0.3;
|
|
|
2068
1963
|
* band on a metered plan. It exists so a tier's run bands reach
|
|
2069
1964
|
* `orgMonthlyCogsUsd` and `tier-margin-floor.spec.ts` — Agency's 3,000,000
|
|
2070
1965
|
* runs are $36 a month that read as nothing while this was absent.
|
|
2071
|
-
*/ perRun: 0.
|
|
1966
|
+
*/ perRun: 0.000013
|
|
2072
1967
|
};
|
|
1968
|
+
/**
|
|
1969
|
+
* The unit rate a declared cost axis names, or 1 where it names none (the
|
|
1970
|
+
* rollup already records dollars).
|
|
1971
|
+
*
|
|
1972
|
+
* ⚑ A rate key core does not carry THROWS. Pricing an unknown axis at zero
|
|
1973
|
+
* would make an org cost less than it does, which is the direction that
|
|
1974
|
+
* approves a discount; `plugin-usage-axes.spec.ts` holds every declared key
|
|
1975
|
+
* to a rate that exists, so this is reached only by a tree that skipped it.
|
|
1976
|
+
*/ function cogsRateOf(axis) {
|
|
1977
|
+
if (axis.rate === undefined) return 1;
|
|
1978
|
+
const rate = ORG_COGS_UNIT_RATES_USD[axis.rate];
|
|
1979
|
+
if (typeof rate !== 'number' || !Number.isFinite(rate)) {
|
|
1980
|
+
throw new Error(`cost axis "${axis.id}" names the rate "${axis.rate}", which ORG_COGS_UNIT_RATES_USD does not carry`);
|
|
1981
|
+
}
|
|
1982
|
+
return rate;
|
|
1983
|
+
}
|
|
2073
1984
|
/**
|
|
2074
1985
|
* One org's monthly infrastructure COGS — the single cost model (AGL-1134).
|
|
2075
1986
|
*
|
|
@@ -2094,50 +2005,62 @@ export const STRIPE_PROCESSOR_FEE_FIXED_USD = 0.3;
|
|
|
2094
2005
|
* today, and will not until there is real traffic — which is the honest
|
|
2095
2006
|
* reason to build it now, while nothing depends on the answer.
|
|
2096
2007
|
*/ export function orgMonthlyCogsUsd(rollup, siteCount) {
|
|
2097
|
-
var _ref;
|
|
2098
2008
|
const num = (value)=>{
|
|
2099
2009
|
const parsed = Number(value != null ? value : 0);
|
|
2100
2010
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
|
|
2101
2011
|
};
|
|
2102
2012
|
const rates = ORG_COGS_UNIT_RATES_USD;
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2013
|
+
// The platform's own axes, at the positions the plugins' declared axes
|
|
2014
|
+
// interleave with (`order`, a multiple of 10 here). The generator refuses a
|
|
2015
|
+
// declaration that takes one of these ids or positions.
|
|
2016
|
+
const core = [
|
|
2017
|
+
{
|
|
2018
|
+
id: 'storage',
|
|
2019
|
+
order: 10,
|
|
2020
|
+
usd: num(rollup == null ? void 0 : rollup.storageGb) * rates.storagePerGbMonth
|
|
2021
|
+
},
|
|
2022
|
+
{
|
|
2023
|
+
id: 'pageViews',
|
|
2024
|
+
order: 20,
|
|
2025
|
+
usd: num(rollup == null ? void 0 : rollup.pageViews) * rates.perPageView
|
|
2026
|
+
},
|
|
2107
2027
|
// Megabytes on the doc, gigabytes in the rate — the unit mismatch is in
|
|
2108
2028
|
// the stored field name, so convert here rather than in each caller.
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2029
|
+
{
|
|
2030
|
+
id: 'dataStorage',
|
|
2031
|
+
order: 40,
|
|
2032
|
+
usd: num(rollup == null ? void 0 : rollup.dataStorageMb) / 1024 * rates.dataStoragePerGbMonth
|
|
2033
|
+
},
|
|
2034
|
+
{
|
|
2035
|
+
id: 'apiRequests',
|
|
2036
|
+
order: 50,
|
|
2037
|
+
usd: num(rollup == null ? void 0 : rollup.apiRequests) * rates.perApiRequest
|
|
2038
|
+
},
|
|
2116
2039
|
// Every send, not the overage — the provider bills the first message of
|
|
2117
|
-
// the month as much as the last, so a cost model that started counting
|
|
2118
|
-
// the plan's included band would report an org that stayed inside its
|
|
2040
|
+
// the month as much as the last, so a cost model that started counting
|
|
2041
|
+
// at the plan's included band would report an org that stayed inside its
|
|
2119
2042
|
// allowance as free.
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2043
|
+
{
|
|
2044
|
+
id: 'emailSends',
|
|
2045
|
+
order: 70,
|
|
2046
|
+
usd: num(rollup == null ? void 0 : rollup.emailSends) * rates.perEmailSend
|
|
2047
|
+
}
|
|
2048
|
+
];
|
|
2049
|
+
// Each plugin's meter, priced at the core rate its declaration names — or
|
|
2050
|
+
// at ×1 where the rollup already records dollars, as the AI plugin's
|
|
2051
|
+
// provider spend does.
|
|
2052
|
+
const declared = pluginCostAxes().map((axis)=>({
|
|
2053
|
+
id: axis.id,
|
|
2054
|
+
order: axis.order,
|
|
2055
|
+
usd: declaredMeterReading(rollup, axis) * cogsRateOf(axis)
|
|
2056
|
+
}));
|
|
2057
|
+
const breakdown = Object.fromEntries([
|
|
2058
|
+
...core,
|
|
2059
|
+
...declared
|
|
2060
|
+
].sort((a, b)=>a.order - b.order).map((axis)=>[
|
|
2061
|
+
axis.id,
|
|
2062
|
+
axis.usd
|
|
2063
|
+
]));
|
|
2141
2064
|
const measuredUsd = Object.values(breakdown).reduce((sum, x)=>sum + x, 0);
|
|
2142
2065
|
const floorUsd = Math.max(0, siteCount) * INFRA_COGS_PER_SITE_USD;
|
|
2143
2066
|
return {
|
|
@@ -2165,39 +2088,27 @@ export const STRIPE_PROCESSOR_FEE_FIXED_USD = 0.3;
|
|
|
2165
2088
|
* UNITS, because the field names do not all say: `storageGb` and
|
|
2166
2089
|
* `dataStorageMb` are gigabytes and MEGABYTES respectively (the conversion
|
|
2167
2090
|
* lives in `orgMonthlyCogsUsd`, with its own test); `pageViews`,
|
|
2168
|
-
* `
|
|
2169
|
-
*
|
|
2170
|
-
*
|
|
2091
|
+
* `apiRequests` and `emailSends` are counts FOR THE MONTH. A plugin's fields
|
|
2092
|
+
* carry the unit its cost-axis declaration states — a monthly count, a
|
|
2093
|
+
* point-in-time level, or dollars.
|
|
2171
2094
|
*/ export function orgCogsInputFrom(source) {
|
|
2172
2095
|
const read = (field)=>{
|
|
2173
2096
|
const value = source == null ? void 0 : source[field];
|
|
2174
2097
|
return value == null ? undefined : value;
|
|
2175
2098
|
};
|
|
2176
|
-
|
|
2099
|
+
const input = {
|
|
2177
2100
|
hostCount: read('hostCount'),
|
|
2178
2101
|
storageGb: read('storageGb'),
|
|
2179
2102
|
pageViews: read('pageViews'),
|
|
2180
|
-
formSubmissions: read('formSubmissions'),
|
|
2181
2103
|
dataStorageMb: read('dataStorageMb'),
|
|
2182
2104
|
apiRequests: read('apiRequests'),
|
|
2183
|
-
|
|
2184
|
-
// AGL-2611. The band's own figure, forwarded for the reason `assistCostUsd`
|
|
2185
|
-
// is: a projection that drops it prices the CRM at its contacts alone,
|
|
2186
|
-
// which is the direction that approves a discount.
|
|
2187
|
-
crmRecordsCount: read('crmRecordsCount'),
|
|
2188
|
-
companiesCount: read('companiesCount'),
|
|
2189
|
-
dealsCount: read('dealsCount'),
|
|
2190
|
-
emailSends: read('emailSends'),
|
|
2191
|
-
// AGL-2280. Dollars, not a meter — the projection still has to forward it
|
|
2192
|
-
// or the model prices Assist at nothing, which is the direction that
|
|
2193
|
-
// approves a discount.
|
|
2194
|
-
assistCostUsd: read('assistCostUsd'),
|
|
2195
|
-
// Priced since 2026-09-07 (`perRun`); a projection that drops them prices
|
|
2196
|
-
// the org's automations at nothing, the same direction as every other
|
|
2197
|
-
// omission on this list.
|
|
2198
|
-
workflowRuns: read('workflowRuns'),
|
|
2199
|
-
actionRuns: read('actionRuns')
|
|
2105
|
+
emailSends: read('emailSends')
|
|
2200
2106
|
};
|
|
2107
|
+
// Every field a plugin's cost axis reads or records — forwarded for the
|
|
2108
|
+
// reason the six above are: a projection that drops a priced field prices
|
|
2109
|
+
// the meter at nothing, which is the direction that approves a discount.
|
|
2110
|
+
for (const field of pluginCostAxisFields())input[field] = read(field);
|
|
2111
|
+
return input;
|
|
2201
2112
|
}
|
|
2202
2113
|
/**
|
|
2203
2114
|
* `orgMonthlyCogsUsd` behind an explicit readiness flag (AGL-1134).
|
|
@@ -2467,7 +2378,8 @@ function resolvePlan(org) {
|
|
|
2467
2378
|
*/ export const PRICE_ENTITLEMENT_KEYS = new Set([
|
|
2468
2379
|
'transactionFeePhysicalPct',
|
|
2469
2380
|
'transactionFeeDigitalPct',
|
|
2470
|
-
'
|
|
2381
|
+
// A plugin's percentage of a sale says so in its declaration.
|
|
2382
|
+
...pluginPlanQuotas().filter((declared)=>declared.price).map((declared)=>declared.key)
|
|
2471
2383
|
]);
|
|
2472
2384
|
/**
|
|
2473
2385
|
* The entitlements with every band lifted (AGL-3049): `UNLIMITED` on each
|
|
@@ -2960,10 +2872,10 @@ function resolvePlan(org) {
|
|
|
2960
2872
|
return 0;
|
|
2961
2873
|
}
|
|
2962
2874
|
/**
|
|
2963
|
-
* Stripe's processing cost on ONE
|
|
2964
|
-
* (AGL-2152) —
|
|
2965
|
-
* rounded UP on the percentage so the
|
|
2966
|
-
* Stripe actually debits.
|
|
2875
|
+
* Stripe's processing cost on ONE destination-charge sale, in cents
|
|
2876
|
+
* (AGL-2152) — a storefront order, a booking deposit — the dearest enabled
|
|
2877
|
+
* method's percentage plus the fixed 30¢, rounded UP on the percentage so the
|
|
2878
|
+
* answer is never a cent short of what Stripe actually debits.
|
|
2967
2879
|
*
|
|
2968
2880
|
* WHO PAYS THIS. Every storefront charge is a DESTINATION charge:
|
|
2969
2881
|
* `payment_intent_data[transfer_data][destination]` names the merchant's
|
|
@@ -2989,23 +2901,23 @@ function resolvePlan(org) {
|
|
|
2989
2901
|
* decides the set — and per AGL-2343 that configuration has `klarna` and
|
|
2990
2902
|
* `affirm` on beside the card family. Pricing this at the card rate would be
|
|
2991
2903
|
* wrong exactly on the orders where it cost the most, which is the same
|
|
2992
|
-
* reasoning
|
|
2993
|
-
*
|
|
2904
|
+
* reasoning the marketplace listing floor applies; both are defined from the
|
|
2905
|
+
* SAME processing constants so the two cannot drift.
|
|
2994
2906
|
*
|
|
2995
2907
|
* THE ONE-LINE LEVER. On a card-family order this over-recovers by the spread
|
|
2996
2908
|
* between the two rates. Pinning `payment_method_types` on the storefront
|
|
2997
2909
|
* sessions to the card family would make 2.9% the true binding rate, and
|
|
2998
|
-
* `
|
|
2910
|
+
* `SALE_PROCESSING_PERCENT` below is then the single identifier to
|
|
2999
2911
|
* repoint. That is a product decision about which payment methods a storefront
|
|
3000
2912
|
* offers, not this one; it is recorded on AGL-2152 and in the Pricing Decision
|
|
3001
2913
|
* Log so it can be taken deliberately.
|
|
3002
|
-
*/ // `
|
|
3003
|
-
//
|
|
3004
|
-
//
|
|
3005
|
-
//
|
|
3006
|
-
export function
|
|
2914
|
+
*/ // `SALE_PROCESSING_PERCENT` and `SALE_PROCESSING_FIXED_CENTS` are declared
|
|
2915
|
+
// beside the processing constants they are defined from, further down this
|
|
2916
|
+
// file — a `const` cannot be read before its declaration is evaluated, and
|
|
2917
|
+
// this function is only ever CALLED, never evaluated at import.
|
|
2918
|
+
export function saleProcessingCostCents(chargeCents) {
|
|
3007
2919
|
if (!Number.isFinite(chargeCents) || chargeCents <= 0) return 0;
|
|
3008
|
-
return Math.ceil(chargeCents *
|
|
2920
|
+
return Math.ceil(chargeCents * SALE_PROCESSING_PERCENT / 100) + SALE_PROCESSING_FIXED_CENTS;
|
|
3009
2921
|
}
|
|
3010
2922
|
/**
|
|
3011
2923
|
* The Stripe Connect `application_fee_amount` for ONE storefront sale
|
|
@@ -3039,7 +2951,7 @@ export function storefrontProcessingCostCents(chargeCents) {
|
|
|
3039
2951
|
// The `Math.max(1, …)` every door already applied: a rate above zero on
|
|
3040
2952
|
// goods the shopper pays for is a fee however small it rounds to.
|
|
3041
2953
|
const take = pct > 0 && base > 0 ? Math.max(1, Math.round(base * pct / 100)) : 0;
|
|
3042
|
-
return Math.min(charge, take +
|
|
2954
|
+
return Math.min(charge, take + saleProcessingCostCents(charge));
|
|
3043
2955
|
}
|
|
3044
2956
|
/**
|
|
3045
2957
|
* Stripe's processing cost on a RECURRING charge of `amountCents`, as the
|
|
@@ -3047,7 +2959,7 @@ export function storefrontProcessingCostCents(chargeCents) {
|
|
|
3047
2959
|
*
|
|
3048
2960
|
* A Stripe Subscription accepts no `application_fee_amount` — only
|
|
3049
2961
|
* `application_fee_percent`, a rate with at most two decimal places — so the
|
|
3050
|
-
* fixed 30¢ that `
|
|
2962
|
+
* fixed 30¢ that `saleProcessingCostCents` adds in cents has to be
|
|
3051
2963
|
* folded into the rate. `(rate × amount + fixed) ÷ amount` is, with the
|
|
3052
2964
|
* amount cancelled,
|
|
3053
2965
|
*
|
|
@@ -3064,15 +2976,15 @@ export function storefrontProcessingCostCents(chargeCents) {
|
|
|
3064
2976
|
* decimal outright, so the only honest direction is over. Integers, because
|
|
3065
2977
|
* `0.09 * 100` is not `9` in floating point and a percent one ulp above a
|
|
3066
2978
|
* whole hundredth would round up to the next one. The same two constants as
|
|
3067
|
-
* the one-time path, so repointing `
|
|
2979
|
+
* the one-time path, so repointing `SALE_PROCESSING_PERCENT` moves
|
|
3068
2980
|
* both surfaces together. Zero for a charge that is not a charge.
|
|
3069
|
-
*/ export function
|
|
2981
|
+
*/ export function saleProcessingPassThroughPercent(amountCents) {
|
|
3070
2982
|
const amount = Number.isFinite(amountCents) && amountCents > 0 ? Math.round(amountCents) : 0;
|
|
3071
2983
|
if (amount <= 0) return 0;
|
|
3072
|
-
const rateHundredths = Math.round(
|
|
2984
|
+
const rateHundredths = Math.round(SALE_PROCESSING_PERCENT * 100);
|
|
3073
2985
|
// 30¢ ÷ amount is a fraction; × 100 makes it a percent, × 100 again makes
|
|
3074
2986
|
// it hundredths of one.
|
|
3075
|
-
const fixedHundredths =
|
|
2987
|
+
const fixedHundredths = SALE_PROCESSING_FIXED_CENTS * 10000 / amount;
|
|
3076
2988
|
return Math.min(100, Math.ceil(rateHundredths + fixedHundredths) / 100);
|
|
3077
2989
|
}
|
|
3078
2990
|
/**
|
|
@@ -3097,7 +3009,7 @@ export function storefrontProcessingCostCents(chargeCents) {
|
|
|
3097
3009
|
const amount = Number.isFinite(amountCents) && amountCents > 0 ? Math.round(amountCents) : 0;
|
|
3098
3010
|
if (amount <= 0) return 0;
|
|
3099
3011
|
const take = resolveTransactionFeePct(org, productType);
|
|
3100
|
-
const passThrough =
|
|
3012
|
+
const passThrough = saleProcessingPassThroughPercent(amount);
|
|
3101
3013
|
return Math.min(100, (Math.round(take * 100) + Math.round(passThrough * 100)) / 100);
|
|
3102
3014
|
}
|
|
3103
3015
|
/**
|
|
@@ -3112,8 +3024,23 @@ export function storefrontProcessingCostCents(chargeCents) {
|
|
|
3112
3024
|
* conservative direction. A malformed override must never zero the
|
|
3113
3025
|
* platform's cut.
|
|
3114
3026
|
*/ export function resolveMarketplaceFeePct(org) {
|
|
3115
|
-
const pct = resolveOrgEntitlements(org)
|
|
3116
|
-
|
|
3027
|
+
const pct = takeRatePctOf(resolveOrgEntitlements(org));
|
|
3028
|
+
if (pct !== null) return pct;
|
|
3029
|
+
const fallback = takeRatePctOf(PLAN_ENTITLEMENTS.free);
|
|
3030
|
+
if (fallback !== null) return fallback;
|
|
3031
|
+
// No plan carries a take rate at all: the marketplace plugin's declaration
|
|
3032
|
+
// did not compile in. Pricing a sale at 0% would hand the whole charge to
|
|
3033
|
+
// the seller, so the sale is refused instead.
|
|
3034
|
+
throw new Error(`no plan declares "${TAKE_RATE_KEY}" — the marketplace take rate ` + 'is declared by the marketplace plugin (plugins.config.json)');
|
|
3035
|
+
}
|
|
3036
|
+
/**
|
|
3037
|
+
* The marketplace take rate's key. Declared by the marketplace plugin
|
|
3038
|
+
* (AGL-3080); read here by key because the storefront and the revenue report
|
|
3039
|
+
* price a marketplace sale from core.
|
|
3040
|
+
*/ const TAKE_RATE_KEY = 'marketplaceFeePct';
|
|
3041
|
+
/** A row's take rate when it is a usable percentage, else `null`. */ function takeRatePctOf(entitlements) {
|
|
3042
|
+
const pct = entitlements[TAKE_RATE_KEY];
|
|
3043
|
+
return typeof pct === 'number' && Number.isFinite(pct) && pct >= 0 && pct <= 100 ? pct : null;
|
|
3117
3044
|
}
|
|
3118
3045
|
/**
|
|
3119
3046
|
* The marketplace take rate that breaks even LATEST, derived from the plan
|
|
@@ -3126,183 +3053,46 @@ export function storefrontProcessingCostCents(chargeCents) {
|
|
|
3126
3053
|
* decays into wrong money copy shown to a publisher — the same reason
|
|
3127
3054
|
* `planGrantingFeature` reads the table instead of a map.
|
|
3128
3055
|
*/ export function bindingMarketplaceFeePct() {
|
|
3129
|
-
return Math.min(...Object.values(PLAN_ENTITLEMENTS).map((plan)=>
|
|
3056
|
+
return Math.min(...Object.values(PLAN_ENTITLEMENTS).map((plan)=>{
|
|
3057
|
+
var _takeRatePctOf;
|
|
3058
|
+
return (_takeRatePctOf = takeRatePctOf(plan)) != null ? _takeRatePctOf : 0;
|
|
3059
|
+
}).filter((pct)=>Number.isFinite(pct) && pct > 0));
|
|
3130
3060
|
}
|
|
3131
3061
|
/**
|
|
3132
|
-
* What one
|
|
3133
|
-
*
|
|
3134
|
-
*
|
|
3135
|
-
*
|
|
3136
|
-
*
|
|
3137
|
-
* the charged amounts are `resolveMarketplaceFeePct` and Stripe's own
|
|
3138
|
-
* invoicing — so changing one changes a sentence, never a bill.
|
|
3062
|
+
* What one destination-charge sale costs the PLATFORM to process (AGL-2343):
|
|
3063
|
+
* a storefront order, a booking deposit, a marketplace listing. On a
|
|
3064
|
+
* destination charge Stripe debits its fee from the PLATFORM's balance, so
|
|
3065
|
+
* every surface that sells through the platform's account prices its take
|
|
3066
|
+
* against these.
|
|
3139
3067
|
*
|
|
3140
|
-
*
|
|
3141
|
-
*
|
|
3142
|
-
*
|
|
3143
|
-
* owes it (AGL-1544). On a destination charge Stripe debits its fee from the
|
|
3144
|
-
* PLATFORM's balance, and it is charged on `amount_total` — the listing price
|
|
3145
|
-
* plus the tax added on top of it.
|
|
3146
|
-
*
|
|
3147
|
-
* So a $1 listing at a 20% take rate is a loss: the buyer pays $1.08, the
|
|
3148
|
-
* seller is transferred $0.80, $0.08 is owed to the state, Aglyn keeps $0.20
|
|
3149
|
-
* and pays Stripe about $0.33. Net −$0.13.
|
|
3068
|
+
* NONE OF THESE IS AN AGLYN PRICE. They are Stripe's published US rates, and
|
|
3069
|
+
* they exist only as inputs to a platform take and to figures a seller reads;
|
|
3070
|
+
* changing one never changes a price list.
|
|
3150
3071
|
*
|
|
3151
3072
|
* THE BNPL RATE IS THE ONE THAT BINDS, and it is not hypothetical: the live
|
|
3152
3073
|
* default payment method configuration has `klarna` and `affirm` enabled
|
|
3153
|
-
* alongside `card`, `cashapp`, `link`, `amazon_pay` and `apple_pay`, and
|
|
3154
|
-
*
|
|
3155
|
-
*
|
|
3156
|
-
*
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
*/ export const
|
|
3160
|
-
/**
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
*
|
|
3164
|
-
*
|
|
3165
|
-
*
|
|
3166
|
-
*
|
|
3167
|
-
* platform's
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
*
|
|
3171
|
-
*
|
|
3172
|
-
*
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
* constants, while being defined as one of them: the two surfaces share
|
|
3176
|
-
* Stripe's published rates and today share the platform's payment method
|
|
3177
|
-
* configuration, but they are separate product decisions. A future choice to
|
|
3178
|
-
* pin `payment_method_types` on storefront sessions to the card family — and
|
|
3179
|
-
* so to recover at `MARKETPLACE_PROCESSING_PERCENT_CARD` — must not silently
|
|
3180
|
-
* lower the marketplace listing floor, which is derived from the same figure
|
|
3181
|
-
* for a different flow.
|
|
3182
|
-
*/ export const STOREFRONT_PROCESSING_PERCENT = MARKETPLACE_PROCESSING_PERCENT_BNPL;
|
|
3183
|
-
/** Stripe's per-transaction fixed component, in cents. Not rate-dependent. */ export const STOREFRONT_PROCESSING_FIXED_CENTS = MARKETPLACE_PROCESSING_FIXED_CENTS;
|
|
3184
|
-
/**
|
|
3185
|
-
* The funds flow for one sale, mirroring what `checkout.ts` actually builds
|
|
3186
|
-
* (AGL-2343): tax exclusive and on top, a fixed transfer of the seller's share
|
|
3187
|
-
* of the PRE-tax price, and Stripe's fee charged on the buyer's total.
|
|
3188
|
-
*/ export function marketplaceSaleEconomics(priceUsd, feePercent, processingPercent = MARKETPLACE_PROCESSING_PERCENT_BNPL) {
|
|
3189
|
-
const priceCents = Math.max(0, Math.round(priceUsd * 100));
|
|
3190
|
-
const taxCents = Math.round(priceCents * MARKETPLACE_ASSUMED_TAX_PERCENT / 100);
|
|
3191
|
-
const buyerPaysCents = priceCents + taxCents;
|
|
3192
|
-
const platformFeeCents = Math.round(priceCents * feePercent / 100);
|
|
3193
|
-
const sellerReceivesCents = priceCents - platformFeeCents;
|
|
3194
|
-
// A zero-price listing takes no payment at all, so there is no fee to pay.
|
|
3195
|
-
const processingCents = priceCents === 0 ? 0 : Math.round(buyerPaysCents * processingPercent / 100 + MARKETPLACE_PROCESSING_FIXED_CENTS);
|
|
3196
|
-
return {
|
|
3197
|
-
priceCents,
|
|
3198
|
-
taxCents,
|
|
3199
|
-
buyerPaysCents,
|
|
3200
|
-
sellerReceivesCents,
|
|
3201
|
-
platformFeeCents,
|
|
3202
|
-
processingCents,
|
|
3203
|
-
platformNetCents: platformFeeCents - processingCents
|
|
3204
|
-
};
|
|
3205
|
-
}
|
|
3206
|
-
/**
|
|
3207
|
-
* The cheapest WHOLE-DOLLAR price at which the platform does not lose money on
|
|
3208
|
-
* a sale (AGL-2343).
|
|
3209
|
-
*
|
|
3210
|
-
* Whole dollars because every publish route rounds `priceUsd` to one, so a
|
|
3211
|
-
* fractional break-even is not a price anyone can actually set. Searched
|
|
3212
|
-
* rather than solved algebraically so that it can never disagree with
|
|
3213
|
-
* `marketplaceSaleEconomics` — the rounding in there is what decides the
|
|
3214
|
-
* answer at these amounts, and a closed form would drift from it silently.
|
|
3215
|
-
*
|
|
3216
|
-
* THIS IS THE ENFORCED FLOOR: `marketplaceMinPriceUsd` returns this figure
|
|
3217
|
-
* and every publish door refuses a paid listing under it. Recorded in the Pricing
|
|
3218
|
-
* Decision Log and on AGL-2343.
|
|
3219
|
-
*/ export function marketplaceBreakEvenUsd(feePercent = bindingMarketplaceFeePct(), processingPercent = MARKETPLACE_PROCESSING_PERCENT_BNPL) {
|
|
3220
|
-
// The listing price ceiling is the marketplace plugin's
|
|
3221
|
-
// `MARKETPLACE_MAX_PRICE_USD`, which this library may not import (an app-tier
|
|
3222
|
-
// lib cannot depend on an addon). The loop only needs SOME bound, and the
|
|
3223
|
-
// answer is single digits at every rate the table holds, so a generous local
|
|
3224
|
-
// one costs nothing and cannot drift into a wrong figure.
|
|
3225
|
-
const searchCeilingUsd = 1000;
|
|
3226
|
-
for(let priceUsd = 1; priceUsd <= searchCeilingUsd; priceUsd += 1){
|
|
3227
|
-
if (marketplaceSaleEconomics(priceUsd, feePercent, processingPercent).platformNetCents >= 0) {
|
|
3228
|
-
return priceUsd;
|
|
3229
|
-
}
|
|
3230
|
-
}
|
|
3231
|
-
return searchCeilingUsd;
|
|
3232
|
-
}
|
|
3233
|
-
/**
|
|
3234
|
-
* THE MINIMUM PRICE a paid marketplace listing may carry (AGL-2343).
|
|
3235
|
-
*
|
|
3236
|
-
* The floor is not a chosen round number — it is the break-even price itself,
|
|
3237
|
-
* the
|
|
3238
|
-
* cheapest whole dollar at which `marketplaceSaleEconomics` stops returning a
|
|
3239
|
-
* negative platform net, computed at the take rate that breaks even LATEST and
|
|
3240
|
-
* the dearest payment method the live configuration enables. Today that is $3.
|
|
3241
|
-
*
|
|
3242
|
-
* DERIVED, NEVER RESTATED. A second hand-written copy of this number in a
|
|
3243
|
-
* publish route or a form is the artifact that decays into a route refusing a
|
|
3244
|
-
* price a form invited, so both the server-side validator
|
|
3245
|
-
* (`MARKETPLACE_MIN_PRICE_USD` in the marketplace model) and every price field
|
|
3246
|
-
* read this. If the payment method set changes, or the plan table's lowest
|
|
3247
|
-
* take rate moves, the floor moves with them on the next call.
|
|
3248
|
-
*
|
|
3249
|
-
* ZERO IS NOT BELOW THE FLOOR. A free listing takes no payment at all, so it
|
|
3250
|
-
* costs nothing to process; the floor is a minimum on PAID listings only.
|
|
3251
|
-
*/ export function marketplaceMinPriceUsd() {
|
|
3252
|
-
return marketplaceBreakEvenUsd();
|
|
3253
|
-
}
|
|
3254
|
-
/**
|
|
3255
|
-
* Whether a price is a PAID price that the floor refuses (AGL-2343) — the one
|
|
3256
|
-
* predicate a form uses to mark its price field in error and hold its publish
|
|
3257
|
-
* button, so that the button and the server agree about what is publishable.
|
|
3258
|
-
*
|
|
3259
|
-
* Rounds first because every publish route does, and a form's value is a
|
|
3260
|
-
* string mid-type: `'2.6'` is stored as $3 and must read as allowed here, or
|
|
3261
|
-
* the button would refuse a price the route accepts.
|
|
3262
|
-
*/ export function isBelowMarketplacePriceFloor(priceUsd) {
|
|
3263
|
-
const price = Math.round(Number(priceUsd) || 0);
|
|
3264
|
-
return price > 0 && price < marketplaceMinPriceUsd();
|
|
3265
|
-
}
|
|
3266
|
-
/**
|
|
3267
|
-
* The sentence a publish form shows under its price field when the price is
|
|
3268
|
-
* below the floor (AGL-2343), or `undefined` when there is nothing to say.
|
|
3269
|
-
*
|
|
3270
|
-
* NOT ADVISORY ANY MORE. The same figure is enforced by every publish route
|
|
3271
|
-
* through `publishPreconditionRefusal`, so this text has to read as a
|
|
3272
|
-
* requirement rather than a warning — a publisher who is told "consider
|
|
3273
|
-
* raising it" and then refused has been lied to by the form. It still explains
|
|
3274
|
-
* WHY, because a bare minimum with no arithmetic behind it reads as an
|
|
3275
|
-
* arbitrary tax on cheap listings.
|
|
3276
|
-
*
|
|
3277
|
-
* Shared by every publish form rather than written into each, because the
|
|
3278
|
-
* figure has to be the same one in all of them and the wording is the only
|
|
3279
|
-
* place a publisher ever sees it.
|
|
3280
|
-
*
|
|
3281
|
-
* Quoted at the take rate that breaks even LATEST, so the sentence holds for a
|
|
3282
|
-
* free-plan publisher too.
|
|
3283
|
-
*/ export function marketplacePriceCostNote(priceUsd) {
|
|
3284
|
-
const price = Math.round(Number(priceUsd) || 0);
|
|
3285
|
-
const minimum = marketplaceMinPriceUsd();
|
|
3286
|
-
// A free listing takes no payment, so it costs nothing to process and has
|
|
3287
|
-
// nothing to warn about — silence there is the point, not an oversight.
|
|
3288
|
-
if (!isBelowMarketplacePriceFloor(price)) return undefined;
|
|
3289
|
-
const { processingCents, platformFeeCents } = marketplaceSaleEconomics(price, bindingMarketplaceFeePct());
|
|
3290
|
-
const usd = (cents)=>`$${(cents / 100).toFixed(2)}`;
|
|
3291
|
-
return `Too low to publish. Processing a $${price} payment costs about ` + `${usd(processingCents)}, more than the ${usd(platformFeeCents)} platform ` + `fee — the sale would lose money. The minimum paid price is ` + `$${minimum}, and a free listing ($0) takes no payment at all.`;
|
|
3292
|
-
}
|
|
3293
|
-
/**
|
|
3294
|
-
* The standing helper sentence a price field shows when there is nothing wrong
|
|
3295
|
-
* (AGL-2343): the minimum stated up front, so a publisher meets it while
|
|
3296
|
-
* typing instead of discovering it as a refusal.
|
|
3297
|
-
*
|
|
3298
|
-
* A capability that is not surfaced in the console does not count as shipped,
|
|
3299
|
-
* and that applies to a REFUSAL as much as to a feature: a floor only a route
|
|
3300
|
-
* knows about is a trap.
|
|
3301
|
-
*
|
|
3302
|
-
* @param suffix whatever else that particular form needs to say, appended.
|
|
3303
|
-
*/ export function marketplacePriceFloorHint(suffix) {
|
|
3304
|
-
return `0 for free, or $${marketplaceMinPriceUsd()} and up for a paid listing.` + (suffix ? ` ${suffix}` : '');
|
|
3305
|
-
}
|
|
3074
|
+
* alongside `card`, `cashapp`, `link`, `amazon_pay` and `apple_pay`, and no
|
|
3075
|
+
* checkout session pins `payment_method_types`, so a buyer may pay by either.
|
|
3076
|
+
* A cost computed from the cheapest method would be wrong exactly when it
|
|
3077
|
+
* mattered.
|
|
3078
|
+
*/ export const CARD_PROCESSING_PERCENT = 2.9;
|
|
3079
|
+
/** Klarna/Affirm, roughly. See the note above — this is the binding one. */ export const BNPL_PROCESSING_PERCENT = 6;
|
|
3080
|
+
/** Stripe's per-transaction fixed component, in cents. */ export const PROCESSING_FIXED_CENTS = 30;
|
|
3081
|
+
/**
|
|
3082
|
+
* The processing rate a storefront or booking destination charge is priced
|
|
3083
|
+
* against (AGL-2152), and the one identifier to repoint if those sessions'
|
|
3084
|
+
* payment method set changes.
|
|
3085
|
+
*
|
|
3086
|
+
* Deliberately its OWN name rather than a direct use of the binding rate,
|
|
3087
|
+
* while being defined as it: every seller shares Stripe's published rates and
|
|
3088
|
+
* today shares the platform's payment method configuration, but each surface
|
|
3089
|
+
* is a separate product decision. A future choice to pin
|
|
3090
|
+
* `payment_method_types` on storefront sessions to the card family — and so
|
|
3091
|
+
* to recover at `CARD_PROCESSING_PERCENT` — must not silently lower the
|
|
3092
|
+
* marketplace listing floor, which is derived from the binding rate for a
|
|
3093
|
+
* different flow.
|
|
3094
|
+
*/ export const SALE_PROCESSING_PERCENT = BNPL_PROCESSING_PERCENT;
|
|
3095
|
+
/** Stripe's per-transaction fixed component, in cents. Not rate-dependent. */ export const SALE_PROCESSING_FIXED_CENTS = PROCESSING_FIXED_CENTS;
|
|
3306
3096
|
/**
|
|
3307
3097
|
* The cheapest plan whose BASE features include `feature`, in ladder order —
|
|
3308
3098
|
* the answer to "which plan do I need for this?", which is the one thing an
|
|
@@ -3362,10 +3152,22 @@ export { PLATFORM_BRANDING_PROFILE } from "./platform-brand.js";
|
|
|
3362
3152
|
* entitlement the stored profile is ignored entirely and the full Aglyn
|
|
3363
3153
|
* brand is returned — so an org that white-labeled and then downgraded
|
|
3364
3154
|
* reverts cleanly.
|
|
3155
|
+
*
|
|
3156
|
+
* An org WITH the entitlement that has stored no brand value at all gets the
|
|
3157
|
+
* full Aglyn brand too (AGL-3440). The entitlement is the right to a brand,
|
|
3158
|
+
* not a brand: until the org sets one, every name it shows is the platform's
|
|
3159
|
+
* anyway, so the white-label profile's blanks — no logo, no support link, no
|
|
3160
|
+
* home — conceal nothing and only strip the platform's own header and footer
|
|
3161
|
+
* from mail whose every line already names the platform. Every Enterprise
|
|
3162
|
+
* org carries the entitlement, Aglyn's own included. One field set, and the
|
|
3163
|
+
* rules below apply.
|
|
3365
3164
|
*/ export function resolveBrandingProfile(org) {
|
|
3366
3165
|
var _ref, _cleanBrandString, _cleanBrandString1, _cleanBrandString2, _cleanBrandString3, _cleanBrandString4, _cleanBrandString5, _cleanBrandString6, _cleanBrandString7, _cleanBrandString8, _cleanBrandString9, _cleanBrandString10;
|
|
3367
3166
|
if (!checkEntitlement(org, 'whiteLabel')) return PLATFORM_BRANDING_PROFILE;
|
|
3368
3167
|
const profile = (_ref = org == null ? void 0 : org.brandingProfile) != null ? _ref : {};
|
|
3168
|
+
if (!Object.values(profile).some((value)=>cleanBrandString(value) !== undefined)) {
|
|
3169
|
+
return PLATFORM_BRANDING_PROFILE;
|
|
3170
|
+
}
|
|
3369
3171
|
return {
|
|
3370
3172
|
productName: (_cleanBrandString = cleanBrandString(profile.productName)) != null ? _cleanBrandString : PLATFORM_BRANDING_PROFILE.productName,
|
|
3371
3173
|
// NO FALLBACK — and this became load-bearing the moment
|
|
@@ -3778,7 +3580,7 @@ export function checkQuota(org, quota, currentUsage) {
|
|
|
3778
3580
|
* billing page reads the same document, member-readable, so a rep is never
|
|
3779
3581
|
* told their limit by being refused.
|
|
3780
3582
|
*/ export function checkCrmEmailQuota(org, usedToday, now = new Date()) {
|
|
3781
|
-
const included = resolveOrgEntitlements(org)
|
|
3583
|
+
const included = planQuotaOf(resolveOrgEntitlements(org), 'crmEmailsPerDay');
|
|
3782
3584
|
const used = Math.max(0, Math.floor(Number(usedToday) || 0));
|
|
3783
3585
|
const resetsAt = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 1));
|
|
3784
3586
|
return {
|
|
@@ -3875,7 +3677,7 @@ export function checkQuota(org, quota, currentUsage) {
|
|
|
3875
3677
|
* counter lives (`hosts/{id}/counters/formSubmissions`). Callers gating a
|
|
3876
3678
|
* single submission pass that site's month count.
|
|
3877
3679
|
*/ export function checkFormSubmissionQuota(org, usedThisMonth) {
|
|
3878
|
-
const included = resolveOrgEntitlements(org)
|
|
3680
|
+
const included = planQuotaOf(resolveOrgEntitlements(org), 'formSubmissionsPerMonth');
|
|
3879
3681
|
const metered = planMetersInfraOverage(org);
|
|
3880
3682
|
const used = Math.max(0, usedThisMonth);
|
|
3881
3683
|
return {
|
|
@@ -3930,7 +3732,7 @@ export function checkQuota(org, quota, currentUsage) {
|
|
|
3930
3732
|
* `cloud/firebase-firestore.rules`), so the count behind the ceiling cannot
|
|
3931
3733
|
* be lowered to launder past it.
|
|
3932
3734
|
*/ export function checkFormSubmissionAbuseCeiling(org, usedThisMonth) {
|
|
3933
|
-
const included = resolveOrgEntitlements(org)
|
|
3735
|
+
const included = planQuotaOf(resolveOrgEntitlements(org), 'formSubmissionsPerMonth');
|
|
3934
3736
|
const ceiling = Number.isFinite(included) ? Math.max(FORM_ABUSE_CEILING_FLOOR, included * FORM_ABUSE_CEILING_MULTIPLE) : FORM_ABUSE_CEILING_UNLIMITED;
|
|
3935
3737
|
const used = Math.max(0, usedThisMonth);
|
|
3936
3738
|
return {
|
|
@@ -3950,7 +3752,9 @@ export function checkQuota(org, quota, currentUsage) {
|
|
|
3950
3752
|
* view costs. They are one physical measurement written in two units, and
|
|
3951
3753
|
* what every `bandwidthGb` band is actually sized against is neither of them
|
|
3952
3754
|
* alone but their quotient — `(1 GB ÷ this) × perPageView`, the cost of a
|
|
3953
|
-
* gigabyte
|
|
3755
|
+
* gigabyte's WEIGHT, to which the band sizing adds the CDN requests the same
|
|
3756
|
+
* views make ({@link PAGE_VIEW_CDN_REQUEST_COST_USD}). That quotient is
|
|
3757
|
+
* stable even while the page's weight is not,
|
|
3954
3758
|
* which is precisely why moving one half re-prices every band on the ladder
|
|
3955
3759
|
* without touching a band: a heavier page costs more per view and buys fewer
|
|
3956
3760
|
* views per gigabyte, and the two cancel.
|
|
@@ -3999,11 +3803,13 @@ export function checkQuota(org, quota, currentUsage) {
|
|
|
3999
3803
|
* It is a CAP, not a price, and it is lower than {@link
|
|
4000
3804
|
* FORM_ABUSE_CEILING_MULTIPLE} because bandwidth is the largest cost line the
|
|
4001
3805
|
* platform carries and the one a stranger can spend on the customer's behalf.
|
|
4002
|
-
* Past the band every 1,000 views bills $0.
|
|
4003
|
-
* cost
|
|
4004
|
-
*
|
|
4005
|
-
*
|
|
4006
|
-
*
|
|
3806
|
+
* Past the band every 1,000 views bills $0.70 against at most $0.54 of real
|
|
3807
|
+
* cost — the dearest region's — once the CDN's request allowance is spent
|
|
3808
|
+
* ({@link PAGE_VIEW_CDN_REQUEST_COST_USD}), so the tail is not a loss — but a
|
|
3809
|
+
* scraper, a hotlinked asset or a botnet still bills the account holder for
|
|
3810
|
+
* traffic they did not ask for, and the ceiling is what bounds that before
|
|
3811
|
+
* staff look at it. At 10× the band that tail was open-ended on Agency; at 3×
|
|
3812
|
+
* it is bounded.
|
|
4007
3813
|
*/ export const BANDWIDTH_ABUSE_CEILING_MULTIPLE = 3;
|
|
4008
3814
|
/**
|
|
4009
3815
|
* Absolute floor for the bandwidth ceiling, in PAGE VIEWS per month, so the
|
|
@@ -4013,9 +3819,10 @@ export function checkQuota(org, quota, currentUsage) {
|
|
|
4013
3819
|
* Free includes 2 GB ≈ 2,071 views; 3× would be ~6,212, which a genuinely
|
|
4014
3820
|
* successful hobby site (a post that lands on Hacker News) reaches in an
|
|
4015
3821
|
* afternoon and would be a miserable first experience of the platform.
|
|
4016
|
-
* 100,000 views/month ≈ 96.6 GB ≈ **$
|
|
4017
|
-
* `METERED_UNIT_RATES_USD.perPageView`
|
|
4018
|
-
*
|
|
3822
|
+
* 100,000 views/month ≈ 96.6 GB ≈ **$54 of real COGS** at the dearest
|
|
3823
|
+
* region (`METERED_UNIT_RATES_USD.perPageView` plus
|
|
3824
|
+
* `PAGE_VIEW_CDN_REQUEST_COST_USD`) — well above the free band, and an order
|
|
3825
|
+
* of magnitude below the $538 a million views costs. It is the number
|
|
4019
3826
|
* that makes "free stays free" true without making it stingy.
|
|
4020
3827
|
*/ export const BANDWIDTH_ABUSE_CEILING_FLOOR = 100000;
|
|
4021
3828
|
/**
|
|
@@ -4128,15 +3935,25 @@ export function checkQuota(org, quota, currentUsage) {
|
|
|
4128
3935
|
/**
|
|
4129
3936
|
* Is the render path required to serve the capped notice instead of the page?
|
|
4130
3937
|
*
|
|
4131
|
-
*
|
|
4132
|
-
*
|
|
4133
|
-
*
|
|
4134
|
-
*
|
|
4135
|
-
*
|
|
4136
|
-
*
|
|
4137
|
-
|
|
3938
|
+
* Three things must hold: the flag is for THIS month, the trip was recorded
|
|
3939
|
+
* as one that degrades, and the org's CURRENT plan still degrades.
|
|
3940
|
+
*
|
|
3941
|
+
* The stored `degraded` alone cannot answer the last one. It is written once,
|
|
3942
|
+
* at trip time, and nothing rewrites it: the beacon stops evaluating a host
|
|
3943
|
+
* once it has tripped this month, and a contained site serves no pages to
|
|
3944
|
+
* beacon from. So a host that upgraded mid-month stayed on the notice until
|
|
3945
|
+
* the 1st, while the owner notice and the visitor notice both promised an
|
|
3946
|
+
* upgrade would bring it back. Re-deriving from `org` on every read releases
|
|
3947
|
+
* it on the next org-doc TTL with no write, the same asymmetry
|
|
3948
|
+
* `bandwidthCapEngaged` keeps for the plan band.
|
|
3949
|
+
*
|
|
3950
|
+
* Both halves still hold in the other direction: a flag written for a paying
|
|
3951
|
+
* host (`degraded: false`) can never take that host down, whatever its plan
|
|
3952
|
+
* becomes later. An unknown org (`null`) resolves as unmetered, so a lookup
|
|
3953
|
+
* failure keeps the containment rather than lifting it.
|
|
3954
|
+
*/ export function bandwidthCeilingDegradesHost(host, month, org) {
|
|
4138
3955
|
var _normalizeHostBandwidthCeiling;
|
|
4139
|
-
return ((_normalizeHostBandwidthCeiling = normalizeHostBandwidthCeiling(host, month)) == null ? void 0 : _normalizeHostBandwidthCeiling.degraded) === true;
|
|
3956
|
+
return ((_normalizeHostBandwidthCeiling = normalizeHostBandwidthCeiling(host, month)) == null ? void 0 : _normalizeHostBandwidthCeiling.degraded) === true && bandwidthCeilingDegradesRender(org);
|
|
4140
3957
|
}
|
|
4141
3958
|
/** UTC `YYYY-MM`, the key both the beacon and the render path agree on. */ export function bandwidthCeilingMonthKey(now = new Date()) {
|
|
4142
3959
|
return now.toISOString().slice(0, 7);
|