@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.
Files changed (455) hide show
  1. package/package.json +12 -12
  2. package/src/lib/app-utils/actions.d.ts +26 -433
  3. package/src/lib/app-utils/actions.js +108 -633
  4. package/src/lib/app-utils/actions.js.map +1 -1
  5. package/src/lib/app-utils/activity-presenter.d.ts +3 -3
  6. package/src/lib/app-utils/activity-presenter.js +36 -52
  7. package/src/lib/app-utils/activity-presenter.js.map +1 -1
  8. package/src/lib/app-utils/analytics-events.d.ts +1 -1
  9. package/src/lib/app-utils/analytics-events.js.map +1 -1
  10. package/src/lib/app-utils/analytics-provider.d.ts +182 -0
  11. package/src/lib/app-utils/analytics-provider.js +133 -0
  12. package/src/lib/app-utils/analytics-provider.js.map +1 -0
  13. package/src/lib/app-utils/api-plugins.d.ts +46 -0
  14. package/src/lib/app-utils/api-plugins.js +19 -0
  15. package/src/lib/app-utils/api-plugins.js.map +1 -1
  16. package/src/lib/app-utils/{marketplace-overrides.d.ts → artifact-overrides.d.ts} +9 -6
  17. package/src/lib/app-utils/{marketplace-overrides.js → artifact-overrides.js} +10 -7
  18. package/src/lib/app-utils/artifact-overrides.js.map +1 -0
  19. package/src/lib/app-utils/{marketplace-provenance.d.ts → artifact-provenance.d.ts} +12 -10
  20. package/src/lib/app-utils/{marketplace-provenance.js → artifact-provenance.js} +9 -7
  21. package/src/lib/app-utils/artifact-provenance.js.map +1 -0
  22. package/src/lib/app-utils/binding-token-catalog.d.ts +5 -13
  23. package/src/lib/app-utils/binding-token-catalog.js +17 -41
  24. package/src/lib/app-utils/binding-token-catalog.js.map +1 -1
  25. package/src/lib/app-utils/brand-support-line.d.ts +36 -0
  26. package/src/lib/app-utils/brand-support-line.js +38 -0
  27. package/src/lib/app-utils/brand-support-line.js.map +1 -0
  28. package/src/lib/app-utils/collection-entries.d.ts +2 -2
  29. package/src/lib/app-utils/collection-entries.js.map +1 -1
  30. package/src/lib/app-utils/consent-group-change.d.ts +4 -0
  31. package/src/lib/app-utils/consent-group-change.js.map +1 -1
  32. package/src/lib/app-utils/consent-groups.d.ts +1 -1
  33. package/src/lib/app-utils/consent-groups.js.map +1 -1
  34. package/src/lib/app-utils/console-routes.d.ts +15 -42
  35. package/src/lib/app-utils/console-routes.js +10 -39
  36. package/src/lib/app-utils/console-routes.js.map +1 -1
  37. package/src/lib/app-utils/contacts.d.ts +24 -2
  38. package/src/lib/app-utils/contacts.js +21 -5
  39. package/src/lib/app-utils/contacts.js.map +1 -1
  40. package/src/lib/app-utils/container-membership.d.ts +93 -0
  41. package/src/lib/app-utils/container-membership.js +165 -0
  42. package/src/lib/app-utils/container-membership.js.map +1 -0
  43. package/src/lib/app-utils/crm-task-reminders.d.ts +23 -6
  44. package/src/lib/app-utils/crm-task-reminders.js +32 -11
  45. package/src/lib/app-utils/crm-task-reminders.js.map +1 -1
  46. package/src/lib/app-utils/crm.d.ts +24 -4
  47. package/src/lib/app-utils/crm.js +23 -0
  48. package/src/lib/app-utils/crm.js.map +1 -1
  49. package/src/lib/app-utils/cross-pool-desync.d.ts +39 -0
  50. package/src/lib/app-utils/cross-pool-desync.js +47 -0
  51. package/src/lib/app-utils/cross-pool-desync.js.map +1 -0
  52. package/src/lib/app-utils/csv-upload.d.ts +29 -0
  53. package/src/lib/app-utils/csv-upload.js +29 -0
  54. package/src/lib/app-utils/csv-upload.js.map +1 -0
  55. package/src/lib/app-utils/{dataset-csv.d.ts → csv.d.ts} +10 -43
  56. package/src/lib/app-utils/{dataset-csv.js → csv.js} +10 -81
  57. package/src/lib/app-utils/csv.js.map +1 -0
  58. package/src/lib/app-utils/dataset-models.d.ts +5 -5
  59. package/src/lib/app-utils/dataset-models.js +19 -2
  60. package/src/lib/app-utils/dataset-models.js.map +1 -1
  61. package/src/lib/app-utils/datasets.d.ts +65 -30
  62. package/src/lib/app-utils/datasets.js +74 -24
  63. package/src/lib/app-utils/datasets.js.map +1 -1
  64. package/src/lib/app-utils/docs-deflection.d.ts +6 -6
  65. package/src/lib/app-utils/docs-deflection.js.map +1 -1
  66. package/src/lib/app-utils/docs-help.generated.d.ts +14 -8
  67. package/src/lib/app-utils/docs-help.generated.js +23 -6
  68. package/src/lib/app-utils/docs-help.generated.js.map +1 -1
  69. package/src/lib/app-utils/docs-index.generated.d.ts +2 -2
  70. package/src/lib/app-utils/docs-index.generated.js +570 -346
  71. package/src/lib/app-utils/docs-index.generated.js.map +1 -1
  72. package/src/lib/app-utils/docs-retrieval.d.ts +3 -3
  73. package/src/lib/app-utils/docs-retrieval.js +14 -10
  74. package/src/lib/app-utils/docs-retrieval.js.map +1 -1
  75. package/src/lib/app-utils/duplicate-resource.d.ts +4 -1
  76. package/src/lib/app-utils/duplicate-resource.js +7 -4
  77. package/src/lib/app-utils/duplicate-resource.js.map +1 -1
  78. package/src/lib/app-utils/dynamic-list-rule.d.ts +1 -1
  79. package/src/lib/app-utils/dynamic-list-rule.js +3 -3
  80. package/src/lib/app-utils/dynamic-list-rule.js.map +1 -1
  81. package/src/lib/app-utils/element-ui.d.ts +1 -1
  82. package/src/lib/app-utils/element-ui.js +1 -1
  83. package/src/lib/app-utils/element-ui.js.map +1 -1
  84. package/src/lib/app-utils/email-starter-policy.js +3 -3
  85. package/src/lib/app-utils/email-starter-policy.js.map +1 -1
  86. package/src/lib/app-utils/email-text.d.ts +80 -0
  87. package/src/lib/app-utils/email-text.js +189 -0
  88. package/src/lib/app-utils/email-text.js.map +1 -0
  89. package/src/lib/app-utils/{list-assignment-policy.d.ts → enrollment-basis.d.ts} +4 -0
  90. package/src/lib/app-utils/{list-assignment-policy.js → enrollment-basis.js} +5 -1
  91. package/src/lib/app-utils/enrollment-basis.js.map +1 -0
  92. package/src/lib/app-utils/entity-picker-context.d.ts +10 -5
  93. package/src/lib/app-utils/entity-picker-context.js.map +1 -1
  94. package/src/lib/app-utils/error-beacon.d.ts +75 -6
  95. package/src/lib/app-utils/error-beacon.js +160 -21
  96. package/src/lib/app-utils/error-beacon.js.map +1 -1
  97. package/src/lib/app-utils/expand-repeatables.d.ts +10 -10
  98. package/src/lib/app-utils/expand-repeatables.js +14 -14
  99. package/src/lib/app-utils/expand-repeatables.js.map +1 -1
  100. package/src/lib/app-utils/forms.js +2 -2
  101. package/src/lib/app-utils/forms.js.map +1 -1
  102. package/src/lib/app-utils/health-report.d.ts +2 -3
  103. package/src/lib/app-utils/health-report.js +8 -6
  104. package/src/lib/app-utils/health-report.js.map +1 -1
  105. package/src/lib/app-utils/host-events.d.ts +82 -0
  106. package/src/lib/app-utils/host-events.js +62 -0
  107. package/src/lib/app-utils/host-events.js.map +1 -0
  108. package/src/lib/app-utils/inbound-mail-domain.d.ts +27 -0
  109. package/src/lib/app-utils/inbound-mail-domain.js +31 -0
  110. package/src/lib/app-utils/inbound-mail-domain.js.map +1 -0
  111. package/src/lib/app-utils/lockdown.d.ts +11 -0
  112. package/src/lib/app-utils/lockdown.js +33 -3
  113. package/src/lib/app-utils/lockdown.js.map +1 -1
  114. package/src/lib/app-utils/margin-utilization.d.ts +4 -69
  115. package/src/lib/app-utils/margin-utilization.js +82 -69
  116. package/src/lib/app-utils/margin-utilization.js.map +1 -1
  117. package/src/lib/app-utils/member-email-aliases.d.ts +25 -0
  118. package/src/lib/app-utils/member-email-aliases.js +29 -0
  119. package/src/lib/app-utils/member-email-aliases.js.map +1 -1
  120. package/src/lib/app-utils/node-definition-sanitizer.d.ts +16 -16
  121. package/src/lib/app-utils/node-definition-sanitizer.js +24 -20
  122. package/src/lib/app-utils/node-definition-sanitizer.js.map +1 -1
  123. package/src/lib/app-utils/node-interactions.d.ts +7 -7
  124. package/src/lib/app-utils/node-interactions.js.map +1 -1
  125. package/src/lib/app-utils/notifications.d.ts +147 -47
  126. package/src/lib/app-utils/notifications.js +182 -44
  127. package/src/lib/app-utils/notifications.js.map +1 -1
  128. package/src/lib/app-utils/operator-alerts.d.ts +15 -1
  129. package/src/lib/app-utils/operator-alerts.js +47 -10
  130. package/src/lib/app-utils/operator-alerts.js.map +1 -1
  131. package/src/lib/app-utils/payments-configured.d.ts +8 -21
  132. package/src/lib/app-utils/payments-configured.js +8 -23
  133. package/src/lib/app-utils/payments-configured.js.map +1 -1
  134. package/src/lib/app-utils/plan-entitlements.d.ts +207 -306
  135. package/src/lib/app-utils/plan-entitlements.js +345 -528
  136. package/src/lib/app-utils/plan-entitlements.js.map +1 -1
  137. package/src/lib/app-utils/platform-brand.d.ts +10 -0
  138. package/src/lib/app-utils/platform-brand.js +14 -3
  139. package/src/lib/app-utils/platform-brand.js.map +1 -1
  140. package/src/lib/app-utils/platform-marketing-consent.d.ts +56 -2
  141. package/src/lib/app-utils/platform-marketing-consent.js +6 -5
  142. package/src/lib/app-utils/platform-marketing-consent.js.map +1 -1
  143. package/src/lib/app-utils/plugin-api-rate-limit.d.ts +7 -1
  144. package/src/lib/app-utils/plugin-api-rate-limit.js +11 -3
  145. package/src/lib/app-utils/plugin-api-rate-limit.js.map +1 -1
  146. package/src/lib/app-utils/plugin-bundle-checks.js +2 -2
  147. package/src/lib/app-utils/plugin-bundle-checks.js.map +1 -1
  148. package/src/lib/app-utils/plugin-host-events.generated.d.ts +12 -0
  149. package/src/lib/app-utils/plugin-host-events.generated.js +169 -0
  150. package/src/lib/app-utils/plugin-host-events.generated.js.map +1 -0
  151. package/src/lib/app-utils/plugin-release-flags.generated.d.ts +12 -0
  152. package/src/lib/app-utils/plugin-release-flags.generated.js +106 -0
  153. package/src/lib/app-utils/plugin-release-flags.generated.js.map +1 -0
  154. package/src/lib/app-utils/plugin-starter-templates.generated.d.ts +12 -0
  155. package/src/lib/app-utils/plugin-starter-templates.generated.js +711 -0
  156. package/src/lib/app-utils/plugin-starter-templates.generated.js.map +1 -0
  157. package/src/lib/app-utils/realm-host-surface.generated.js +2 -0
  158. package/src/lib/app-utils/realm-host-surface.generated.js.map +1 -1
  159. package/src/lib/app-utils/release-flags.d.ts +14 -5
  160. package/src/lib/app-utils/release-flags.js +21 -125
  161. package/src/lib/app-utils/release-flags.js.map +1 -1
  162. package/src/lib/app-utils/repeat-query.d.ts +56 -0
  163. package/src/lib/app-utils/{dataset-query.js → repeat-query.js} +16 -16
  164. package/src/lib/app-utils/repeat-query.js.map +1 -0
  165. package/src/lib/app-utils/repeat-sources.d.ts +9 -0
  166. package/src/lib/app-utils/repeat-sources.js.map +1 -1
  167. package/src/lib/app-utils/retained-refusals.d.ts +73 -0
  168. package/src/lib/app-utils/retained-refusals.js +186 -0
  169. package/src/lib/app-utils/retained-refusals.js.map +1 -0
  170. package/src/lib/app-utils/scope-tokens.d.ts +27 -0
  171. package/src/lib/app-utils/scope-tokens.js +61 -0
  172. package/src/lib/app-utils/scope-tokens.js.map +1 -1
  173. package/src/lib/app-utils/screen-link-context.js +3 -3
  174. package/src/lib/app-utils/screen-link-context.js.map +1 -1
  175. package/src/lib/app-utils/screen-route.js +1 -1
  176. package/src/lib/app-utils/screen-route.js.map +1 -1
  177. package/src/lib/app-utils/seo-audit.d.ts +132 -0
  178. package/src/lib/app-utils/seo-audit.js +246 -0
  179. package/src/lib/app-utils/seo-audit.js.map +1 -0
  180. package/src/lib/app-utils/seo-keywords.d.ts +48 -0
  181. package/src/lib/app-utils/seo-keywords.js +60 -0
  182. package/src/lib/app-utils/seo-keywords.js.map +1 -0
  183. package/src/lib/app-utils/seo-page-facts.d.ts +66 -0
  184. package/src/lib/app-utils/seo-page-facts.js +155 -0
  185. package/src/lib/app-utils/seo-page-facts.js.map +1 -0
  186. package/src/lib/app-utils/seo-site-scan.d.ts +126 -0
  187. package/src/lib/app-utils/seo-site-scan.js +162 -0
  188. package/src/lib/app-utils/seo-site-scan.js.map +1 -0
  189. package/src/lib/app-utils/seo-title-variables.js +1 -1
  190. package/src/lib/app-utils/seo-title-variables.js.map +1 -1
  191. package/src/lib/app-utils/server.d.ts +13 -18
  192. package/src/lib/app-utils/server.js +33 -51
  193. package/src/lib/app-utils/server.js.map +1 -1
  194. package/src/lib/app-utils/site-interactions.d.ts +501 -0
  195. package/src/lib/app-utils/site-interactions.js +554 -0
  196. package/src/lib/app-utils/site-interactions.js.map +1 -0
  197. package/src/lib/app-utils/{marketplace-theme.d.ts → site-theme.d.ts} +13 -2
  198. package/src/lib/app-utils/{marketplace-theme.js → site-theme.js} +2 -2
  199. package/src/lib/app-utils/site-theme.js.map +1 -0
  200. package/src/lib/app-utils/sitemap.d.ts +4 -3
  201. package/src/lib/app-utils/sitemap.js +9 -7
  202. package/src/lib/app-utils/sitemap.js.map +1 -1
  203. package/src/lib/app-utils/stale-build-error.d.ts +51 -0
  204. package/src/lib/app-utils/stale-build-error.js +100 -1
  205. package/src/lib/app-utils/stale-build-error.js.map +1 -1
  206. package/src/lib/app-utils/starter-template-nodes.d.ts +137 -0
  207. package/src/lib/app-utils/starter-template-nodes.js +129 -0
  208. package/src/lib/app-utils/starter-template-nodes.js.map +1 -0
  209. package/src/lib/app-utils/starter-templates.d.ts +11 -34
  210. package/src/lib/app-utils/starter-templates.js +19 -230
  211. package/src/lib/app-utils/starter-templates.js.map +1 -1
  212. package/src/lib/app-utils/{email-topics.d.ts → subscription-topics.d.ts} +64 -48
  213. package/src/lib/app-utils/{email-topics.js → subscription-topics.js} +39 -109
  214. package/src/lib/app-utils/subscription-topics.js.map +1 -0
  215. package/src/lib/app-utils/tax-jurisdiction-figures.d.ts +118 -0
  216. package/src/lib/app-utils/tax-jurisdiction-figures.js +123 -0
  217. package/src/lib/app-utils/tax-jurisdiction-figures.js.map +1 -0
  218. package/src/lib/app-utils/theme-library.d.ts +10 -3
  219. package/src/lib/app-utils/theme-library.js +13 -4
  220. package/src/lib/app-utils/theme-library.js.map +1 -1
  221. package/src/lib/app-utils/usage-budget.d.ts +73 -188
  222. package/src/lib/app-utils/usage-budget.js +58 -194
  223. package/src/lib/app-utils/usage-budget.js.map +1 -1
  224. package/src/lib/app-utils/{campaign-attribution.d.ts → utm-attribution.d.ts} +11 -6
  225. package/src/lib/app-utils/{campaign-attribution.js → utm-attribution.js} +13 -8
  226. package/src/lib/app-utils/utm-attribution.js.map +1 -0
  227. package/src/lib/app-utils/{campaign-forwarding.d.ts → utm-forwarding.d.ts} +14 -14
  228. package/src/lib/app-utils/{campaign-forwarding.js → utm-forwarding.js} +26 -26
  229. package/src/lib/app-utils/utm-forwarding.js.map +1 -0
  230. package/src/lib/app-utils/{campaign-touch.d.ts → utm-touch.d.ts} +25 -17
  231. package/src/lib/app-utils/{campaign-touch.js → utm-touch.js} +38 -30
  232. package/src/lib/app-utils/utm-touch.js.map +1 -0
  233. package/src/lib/app-utils/variables.d.ts +9 -9
  234. package/src/lib/app-utils/variables.js.map +1 -1
  235. package/src/lib/app-utils/video-object.js +6 -5
  236. package/src/lib/app-utils/video-object.js.map +1 -1
  237. package/src/lib/app-utils/visitor-consent.d.ts +41 -164
  238. package/src/lib/app-utils/visitor-consent.js +66 -277
  239. package/src/lib/app-utils/visitor-consent.js.map +1 -1
  240. package/src/lib/app-utils/visitor-record-ceiling.d.ts +32 -0
  241. package/src/lib/app-utils/visitor-record-ceiling.js +39 -0
  242. package/src/lib/app-utils/visitor-record-ceiling.js.map +1 -1
  243. package/src/lib/app-utils/web-vitals-rum.d.ts +7 -7
  244. package/src/lib/app-utils/web-vitals-rum.js +31 -63
  245. package/src/lib/app-utils/web-vitals-rum.js.map +1 -1
  246. package/src/lib/app-utils/where-used.d.ts +11 -6
  247. package/src/lib/app-utils/where-used.js +3 -8
  248. package/src/lib/app-utils/where-used.js.map +1 -1
  249. package/src/lib/foundation/definitions/components.types.d.ts +1 -1
  250. package/src/lib/foundation/definitions/components.types.js +1 -1
  251. package/src/lib/foundation/definitions/components.types.js.map +1 -1
  252. package/src/lib/foundation/definitions/org-billing.types.d.ts +11 -137
  253. package/src/lib/foundation/definitions/org-billing.types.js.map +1 -1
  254. package/src/lib/foundation/definitions/organization.types.d.ts +1 -3
  255. package/src/lib/foundation/definitions/organization.types.js.map +1 -1
  256. package/src/lib/foundation/definitions/platform.types.d.ts +11 -5
  257. package/src/lib/foundation/definitions/platform.types.js.map +1 -1
  258. package/src/lib/foundation/definitions/write-deny-coverage.util.d.ts +16 -0
  259. package/src/lib/foundation/definitions/write-deny-coverage.util.js +20 -0
  260. package/src/lib/foundation/definitions/write-deny-coverage.util.js.map +1 -1
  261. package/src/lib/foundation/index.d.ts +1 -1
  262. package/src/lib/foundation/index.js.map +1 -1
  263. package/src/lib/plugin-manager/besigner-documents.d.ts +96 -0
  264. package/src/lib/plugin-manager/besigner-documents.js +61 -0
  265. package/src/lib/plugin-manager/besigner-documents.js.map +1 -0
  266. package/src/lib/plugin-manager/computed-variables.d.ts +71 -0
  267. package/src/lib/plugin-manager/computed-variables.js +74 -0
  268. package/src/lib/plugin-manager/computed-variables.js.map +1 -0
  269. package/src/lib/plugin-manager/custom-fields.d.ts +29 -2
  270. package/src/lib/plugin-manager/custom-fields.js +47 -1
  271. package/src/lib/plugin-manager/custom-fields.js.map +1 -1
  272. package/src/lib/plugin-manager/feature-plugins.d.ts +372 -99
  273. package/src/lib/plugin-manager/feature-plugins.js +126 -51
  274. package/src/lib/plugin-manager/feature-plugins.js.map +1 -1
  275. package/src/lib/plugin-manager/first-party-plugins.generated.d.ts +134 -0
  276. package/src/lib/plugin-manager/first-party-plugins.generated.js +840 -10
  277. package/src/lib/plugin-manager/first-party-plugins.generated.js.map +1 -1
  278. package/src/lib/plugin-manager/index.d.ts +0 -1
  279. package/src/lib/plugin-manager/index.js +0 -1
  280. package/src/lib/plugin-manager/index.js.map +1 -1
  281. package/src/lib/plugin-manager/plugin-activity-actions.d.ts +12 -0
  282. package/src/lib/plugin-manager/plugin-activity-actions.js +25 -0
  283. package/src/lib/plugin-manager/plugin-activity-actions.js.map +1 -1
  284. package/src/lib/plugin-manager/plugin-contact-capture.d.ts +9 -4
  285. package/src/lib/plugin-manager/plugin-contact-capture.js.map +1 -1
  286. package/src/lib/plugin-manager/plugin-containers.d.ts +68 -0
  287. package/src/lib/plugin-manager/plugin-containers.generated.d.ts +10 -0
  288. package/src/lib/plugin-manager/plugin-containers.generated.js +20 -0
  289. package/src/lib/plugin-manager/plugin-containers.generated.js.map +1 -0
  290. package/src/lib/plugin-manager/plugin-containers.js +27 -0
  291. package/src/lib/plugin-manager/plugin-containers.js.map +1 -0
  292. package/src/lib/plugin-manager/plugin-contributions.d.ts +1 -1
  293. package/src/lib/plugin-manager/plugin-contributions.js.map +1 -1
  294. package/src/lib/plugin-manager/plugin-declarations-repair.d.ts +36 -0
  295. package/src/lib/plugin-manager/plugin-declarations-repair.js +64 -0
  296. package/src/lib/plugin-manager/plugin-declarations-repair.js.map +1 -0
  297. package/src/lib/plugin-manager/plugin-dependents.d.ts +101 -0
  298. package/src/lib/plugin-manager/plugin-dependents.js +75 -0
  299. package/src/lib/plugin-manager/plugin-dependents.js.map +1 -0
  300. package/src/lib/plugin-manager/plugin-distribution.d.ts +55 -0
  301. package/src/lib/plugin-manager/plugin-distribution.js +45 -0
  302. package/src/lib/plugin-manager/plugin-distribution.js.map +1 -0
  303. package/src/lib/plugin-manager/plugin-entitlements.d.ts +8 -0
  304. package/src/lib/plugin-manager/plugin-entitlements.js.map +1 -1
  305. package/src/lib/plugin-manager/plugin-host-collections.d.ts +17 -0
  306. package/src/lib/plugin-manager/plugin-host-collections.js +6 -0
  307. package/src/lib/plugin-manager/plugin-host-collections.js.map +1 -1
  308. package/src/lib/plugin-manager/plugin-host-resources.d.ts +133 -0
  309. package/src/lib/plugin-manager/plugin-host-resources.js +52 -0
  310. package/src/lib/plugin-manager/plugin-host-resources.js.map +1 -0
  311. package/src/lib/plugin-manager/plugin-membership-detach.js +1 -1
  312. package/src/lib/plugin-manager/plugin-membership-detach.js.map +1 -1
  313. package/src/lib/plugin-manager/plugin-org-erasure.d.ts +28 -2
  314. package/src/lib/plugin-manager/plugin-org-erasure.js +61 -2
  315. package/src/lib/plugin-manager/plugin-org-erasure.js.map +1 -1
  316. package/src/lib/plugin-manager/plugin-plan-entitlements.d.ts +123 -0
  317. package/src/lib/plugin-manager/plugin-plan-entitlements.js +101 -0
  318. package/src/lib/plugin-manager/plugin-plan-entitlements.js.map +1 -0
  319. package/src/lib/plugin-manager/plugin-record-email-state.d.ts +69 -0
  320. package/src/lib/plugin-manager/plugin-record-email-state.js +32 -0
  321. package/src/lib/plugin-manager/plugin-record-email-state.js.map +1 -1
  322. package/src/lib/plugin-manager/plugin-record-index.d.ts +95 -0
  323. package/src/lib/plugin-manager/plugin-record-index.js +51 -0
  324. package/src/lib/plugin-manager/plugin-record-index.js.map +1 -0
  325. package/src/lib/plugin-manager/plugin-record-lists.d.ts +115 -0
  326. package/src/lib/plugin-manager/plugin-record-lists.js +75 -0
  327. package/src/lib/plugin-manager/plugin-record-lists.js.map +1 -0
  328. package/src/lib/plugin-manager/plugin-record-timeline.d.ts +42 -8
  329. package/src/lib/plugin-manager/plugin-record-timeline.js.map +1 -1
  330. package/src/lib/plugin-manager/plugin-record-written.d.ts +58 -0
  331. package/src/lib/plugin-manager/plugin-record-written.js +42 -0
  332. package/src/lib/plugin-manager/plugin-record-written.js.map +1 -0
  333. package/src/lib/plugin-manager/plugin-revenue-sources.d.ts +213 -0
  334. package/src/lib/plugin-manager/plugin-revenue-sources.js +194 -0
  335. package/src/lib/plugin-manager/plugin-revenue-sources.js.map +1 -0
  336. package/src/lib/plugin-manager/plugin-site-beacons.d.ts +71 -0
  337. package/src/lib/plugin-manager/plugin-site-beacons.js +54 -0
  338. package/src/lib/plugin-manager/plugin-site-beacons.js.map +1 -0
  339. package/src/lib/plugin-manager/plugin-site-bundle.d.ts +145 -0
  340. package/src/lib/plugin-manager/plugin-site-bundle.js +78 -0
  341. package/src/lib/plugin-manager/plugin-site-bundle.js.map +1 -0
  342. package/src/lib/plugin-manager/plugin-site-cache.d.ts +12 -0
  343. package/src/lib/plugin-manager/plugin-site-cache.js.map +1 -1
  344. package/src/lib/plugin-manager/plugin-site-export.d.ts +81 -0
  345. package/src/lib/plugin-manager/plugin-site-export.js +40 -0
  346. package/src/lib/plugin-manager/plugin-site-export.js.map +1 -0
  347. package/src/lib/plugin-manager/plugin-sitemap-sections.d.ts +88 -0
  348. package/src/lib/plugin-manager/plugin-sitemap-sections.js +29 -0
  349. package/src/lib/plugin-manager/plugin-sitemap-sections.js.map +1 -0
  350. package/src/lib/plugin-manager/plugin-subscription-topics.generated.d.ts +11 -0
  351. package/src/lib/plugin-manager/plugin-subscription-topics.generated.js +41 -0
  352. package/src/lib/plugin-manager/plugin-subscription-topics.generated.js.map +1 -0
  353. package/src/lib/plugin-manager/plugin-tax-profile.d.ts +20 -4
  354. package/src/lib/plugin-manager/plugin-tax-profile.js.map +1 -1
  355. package/src/lib/plugin-manager/plugin-tax-return-sources.d.ts +255 -0
  356. package/src/lib/plugin-manager/plugin-tax-return-sources.js +191 -0
  357. package/src/lib/plugin-manager/plugin-tax-return-sources.js.map +1 -0
  358. package/src/lib/plugin-manager/plugin-template-sources.d.ts +75 -0
  359. package/src/lib/plugin-manager/plugin-template-sources.js +37 -0
  360. package/src/lib/plugin-manager/plugin-template-sources.js.map +1 -0
  361. package/src/lib/plugin-manager/plugin-usage-axes.d.ts +319 -0
  362. package/src/lib/plugin-manager/plugin-usage-axes.js +186 -0
  363. package/src/lib/plugin-manager/plugin-usage-axes.js.map +1 -0
  364. package/src/lib/plugin-manager/plugin-usage-meters.d.ts +108 -0
  365. package/src/lib/plugin-manager/plugin-usage-meters.js +105 -0
  366. package/src/lib/plugin-manager/plugin-usage-meters.js.map +1 -0
  367. package/src/lib/plugin-manager/plugin-zones.d.ts +4 -5
  368. package/src/lib/plugin-manager/plugin-zones.js.map +1 -1
  369. package/src/lib/plugin-manager/realm-host-aglyn.generated.js +2 -0
  370. package/src/lib/plugin-manager/realm-host-aglyn.generated.js.map +1 -1
  371. package/src/lib/plugin-manager/record-captured-contact.d.ts +1 -14
  372. package/src/lib/plugin-manager/record-captured-contact.js +10 -32
  373. package/src/lib/plugin-manager/record-captured-contact.js.map +1 -1
  374. package/src/lib/plugin-manager/repeat-rows.d.ts +124 -0
  375. package/src/lib/plugin-manager/repeat-rows.js +108 -0
  376. package/src/lib/plugin-manager/repeat-rows.js.map +1 -0
  377. package/src/lib/plugin-manager/submission-record-target.d.ts +144 -0
  378. package/src/lib/plugin-manager/submission-record-target.js +125 -0
  379. package/src/lib/plugin-manager/submission-record-target.js.map +1 -0
  380. package/src/lib/plugin-manager/usage-alert-contributors.d.ts +76 -6
  381. package/src/lib/plugin-manager/usage-alert-contributors.js +23 -10
  382. package/src/lib/plugin-manager/usage-alert-contributors.js.map +1 -1
  383. package/src/lib/plugin-manager/video-embed-provider.d.ts +108 -0
  384. package/src/lib/plugin-manager/video-embed-provider.js +165 -0
  385. package/src/lib/plugin-manager/video-embed-provider.js.map +1 -0
  386. package/src/lib/types/nodes.d.ts +2 -2
  387. package/src/lib/types/nodes.js.map +1 -1
  388. package/src/lib/app-utils/assist-credits.d.ts +0 -482
  389. package/src/lib/app-utils/assist-credits.js +0 -509
  390. package/src/lib/app-utils/assist-credits.js.map +0 -1
  391. package/src/lib/app-utils/campaign-attribution.js.map +0 -1
  392. package/src/lib/app-utils/campaign-forwarding.js.map +0 -1
  393. package/src/lib/app-utils/campaign-membership.d.ts +0 -121
  394. package/src/lib/app-utils/campaign-membership.js +0 -189
  395. package/src/lib/app-utils/campaign-membership.js.map +0 -1
  396. package/src/lib/app-utils/campaign-touch.js.map +0 -1
  397. package/src/lib/app-utils/console-record-links.d.ts +0 -163
  398. package/src/lib/app-utils/console-record-links.js +0 -180
  399. package/src/lib/app-utils/console-record-links.js.map +0 -1
  400. package/src/lib/app-utils/contact-holder.d.ts +0 -68
  401. package/src/lib/app-utils/contact-holder.js +0 -129
  402. package/src/lib/app-utils/contact-holder.js.map +0 -1
  403. package/src/lib/app-utils/contact-merge.d.ts +0 -136
  404. package/src/lib/app-utils/contact-merge.js +0 -412
  405. package/src/lib/app-utils/contact-merge.js.map +0 -1
  406. package/src/lib/app-utils/crm-booking.d.ts +0 -75
  407. package/src/lib/app-utils/crm-booking.js +0 -133
  408. package/src/lib/app-utils/crm-booking.js.map +0 -1
  409. package/src/lib/app-utils/crm-csv.d.ts +0 -239
  410. package/src/lib/app-utils/crm-csv.js +0 -467
  411. package/src/lib/app-utils/crm-csv.js.map +0 -1
  412. package/src/lib/app-utils/crm-digest.d.ts +0 -185
  413. package/src/lib/app-utils/crm-digest.js +0 -272
  414. package/src/lib/app-utils/crm-digest.js.map +0 -1
  415. package/src/lib/app-utils/crm-inbound.d.ts +0 -245
  416. package/src/lib/app-utils/crm-inbound.js +0 -407
  417. package/src/lib/app-utils/crm-inbound.js.map +0 -1
  418. package/src/lib/app-utils/crm-reports.d.ts +0 -479
  419. package/src/lib/app-utils/crm-reports.js +0 -680
  420. package/src/lib/app-utils/crm-reports.js.map +0 -1
  421. package/src/lib/app-utils/dataset-csv.js.map +0 -1
  422. package/src/lib/app-utils/dataset-query.d.ts +0 -57
  423. package/src/lib/app-utils/dataset-query.js.map +0 -1
  424. package/src/lib/app-utils/email-topics.js.map +0 -1
  425. package/src/lib/app-utils/form-dataset-binding.d.ts +0 -50
  426. package/src/lib/app-utils/form-dataset-binding.js +0 -74
  427. package/src/lib/app-utils/form-dataset-binding.js.map +0 -1
  428. package/src/lib/app-utils/list-assignment-policy.js.map +0 -1
  429. package/src/lib/app-utils/list-import.d.ts +0 -158
  430. package/src/lib/app-utils/list-import.js +0 -332
  431. package/src/lib/app-utils/list-import.js.map +0 -1
  432. package/src/lib/app-utils/marketplace-listing-visibility.d.ts +0 -122
  433. package/src/lib/app-utils/marketplace-listing-visibility.js +0 -147
  434. package/src/lib/app-utils/marketplace-listing-visibility.js.map +0 -1
  435. package/src/lib/app-utils/marketplace-overrides.js.map +0 -1
  436. package/src/lib/app-utils/marketplace-provenance.js.map +0 -1
  437. package/src/lib/app-utils/marketplace-theme.js.map +0 -1
  438. package/src/lib/app-utils/marketplace-update-state.d.ts +0 -119
  439. package/src/lib/app-utils/marketplace-update-state.js +0 -132
  440. package/src/lib/app-utils/marketplace-update-state.js.map +0 -1
  441. package/src/lib/app-utils/publisher-agreement.d.ts +0 -289
  442. package/src/lib/app-utils/publisher-agreement.js +0 -321
  443. package/src/lib/app-utils/publisher-agreement.js.map +0 -1
  444. package/src/lib/app-utils/wistia-embed.d.ts +0 -104
  445. package/src/lib/app-utils/wistia-embed.js +0 -138
  446. package/src/lib/app-utils/wistia-embed.js.map +0 -1
  447. package/src/lib/app-utils/workflows.d.ts +0 -136
  448. package/src/lib/app-utils/workflows.js +0 -346
  449. package/src/lib/app-utils/workflows.js.map +0 -1
  450. package/src/lib/plugin-manager/commerce-zone-props.d.ts +0 -172
  451. package/src/lib/plugin-manager/commerce-zone-props.js +0 -31
  452. package/src/lib/plugin-manager/commerce-zone-props.js.map +0 -1
  453. package/src/lib/plugin-manager/plugin-metered-lines.d.ts +0 -97
  454. package/src/lib/plugin-manager/plugin-metered-lines.js +0 -123
  455. 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 stays Pro and up; Free
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
- bandwidthGb: 50,
389
- formSubmissionsPerMonth: 200,
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 — one GB
552
- // is 1,035 views at `ESTIMATED_PAGE_TRANSFER_BYTES`, or $0.167 of
553
- // measured cost — so the bandwidth band is what decides whether the tier
554
- // survives a customer spending the whole allowance it was sold.
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
- // At 225 GB that price was 44% under water; 125 GB is what it carries.
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: 125,
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: 185,
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
- bandwidthGb: 290,
750
- formSubmissionsPerMonth: 25000,
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
- bandwidthGb: 345,
828
- formSubmissionsPerMonth: 40000,
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
- bandwidthGb: 1540,
912
- // FINITE, where every other capacity row on this tier is unbounded.
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: 3080,
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 — and `perPageView` was
1998
- * re-pegged 2026-09-09 (AGL-2711), from $0.0001 to $0.00016153846. All three
1999
- * MUST be changed here and in `METERED_UNIT_RATES_USD` together. See that
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 is what every bandwidthGb band on the
2020
- * ladder was sized against.
2021
- */ perPageView: 0.00016153846,
2022
- perFormSubmission: 0.00005,
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 — $12 per million.
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.0000118, carried as $0.000012. It scales with the catalog a site holds
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.000012
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
- const breakdown = {
2104
- storage: num(rollup == null ? void 0 : rollup.storageGb) * rates.storagePerGbMonth,
2105
- pageViews: num(rollup == null ? void 0 : rollup.pageViews) * rates.perPageView,
2106
- formSubmissions: num(rollup == null ? void 0 : rollup.formSubmissions) * rates.perFormSubmission,
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
- dataStorage: num(rollup == null ? void 0 : rollup.dataStorageMb) / 1024 * rates.dataStoragePerGbMonth,
2110
- apiRequests: num(rollup == null ? void 0 : rollup.apiRequests) * rates.perApiRequest,
2111
- // The records band (AGL-2611), under the axis name every breakdown reader
2112
- // already keys on. `??` and not `||`: a rollup that measured ZERO records
2113
- // has answered, and must not fall back to a contacts figure from a month
2114
- // written under the narrower basis.
2115
- contacts: num((_ref = rollup == null ? void 0 : rollup.crmRecordsCount) != null ? _ref : rollup == null ? void 0 : rollup.contactsCount) * rates.perContactMonth,
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 at
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
- emailSends: num(rollup == null ? void 0 : rollup.emailSends) * rates.perEmailSend,
2121
- /*==========================================
2122
- * AGLYN ASSIST PROVIDER SPEND (AGL-2280).
2123
- *
2124
- * Already dollars, so ×1 — see `OrgUsageRollupInput.assistCostUsd`.
2125
- *
2126
- * This is the ONE meter on the platform whose unit cost is not a fraction
2127
- * margin model read it: the discount guardrail priced six meters that
2128
- * together measured $0.0000054 for the largest real org, and ignored the
2129
- * only line item that can plausibly clear the $2/site floor on its own.
2130
- * A 93%-off coupon on an org burning $40/month of tokens rated green.
2131
- *
2132
- * It is deliberately NOT in `billedCents` — what an org is charged is a
2133
- * separate decision with a price sheet behind it. This is what the org
2134
- * COSTS US, which is the only question the guardrail asks.
2135
- *=========================================*/ assist: num(rollup == null ? void 0 : rollup.assistCostUsd),
2136
- // Both run counters on one line: one rate, one cost, whichever builder
2137
- // produced the run. Unpriced until 2026-09-07 — the two bands were
2138
- // recorded on every rollup and read as nothing.
2139
- runs: (num(rollup == null ? void 0 : rollup.workflowRuns) + num(rollup == null ? void 0 : rollup.actionRuns)) * rates.perRun
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
- * `formSubmissions`, `apiRequests` and `emailSends` are counts FOR THE MONTH;
2169
- * `contactsCount` and `crmRecordsCount` are point-in-time levels, not monthly
2170
- * flows.
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
- return {
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
- contactsCount: read('contactsCount'),
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
- 'marketplaceFeePct'
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 storefront destination charge, in cents
2964
- * (AGL-2152) — the dearest enabled method's percentage plus the fixed 30¢,
2965
- * rounded UP on the percentage so the answer is never a cent short of what
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 `marketplaceBreakEvenUsd` already applies to the listing floor;
2993
- * these are deliberately the SAME two constants so the two cannot drift.
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
- * `STOREFRONT_PROCESSING_PERCENT` below is then the single identifier to
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
- */ // `STOREFRONT_PROCESSING_PERCENT` and `STOREFRONT_PROCESSING_FIXED_CENTS` are
3003
- // declared beside the marketplace processing constants they are defined from,
3004
- // further down this file — a `const` cannot be read before its declaration is
3005
- // evaluated, and this function is only ever CALLED, never evaluated at import.
3006
- export function storefrontProcessingCostCents(chargeCents) {
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 * STOREFRONT_PROCESSING_PERCENT / 100) + STOREFRONT_PROCESSING_FIXED_CENTS;
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 + storefrontProcessingCostCents(charge));
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 `storefrontProcessingCostCents` adds in cents has to be
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 `STOREFRONT_PROCESSING_PERCENT` moves
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 storefrontProcessingPassThroughPercent(amountCents) {
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(STOREFRONT_PROCESSING_PERCENT * 100);
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 = STOREFRONT_PROCESSING_FIXED_CENTS * 10000 / amount;
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 = storefrontProcessingPassThroughPercent(amount);
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).marketplaceFeePct;
3116
- return Number.isFinite(pct) && pct >= 0 && pct <= 100 ? pct : PLAN_ENTITLEMENTS.free.marketplaceFeePct;
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)=>plan.marketplaceFeePct).filter((pct)=>Number.isFinite(pct) && pct > 0));
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 marketplace sale costs the PLATFORM to process (AGL-2343).
3133
- *
3134
- * NONE OF THESE IS AN AGLYN PRICE. They are Stripe's published US rates and
3135
- * the Texas rate the platform remits, and they exist only as inputs to a
3136
- * figure shown to a publisher while they type. Nothing is billed from them —
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
- * WHY THE PLATFORM PAYS THE PROCESSING FEE AT ALL. Marketplace checkout is a
3141
- * DESTINATION charge with a fixed `transfer_data[amount]` and deliberately no
3142
- * `application_fee_amount`, so that the sales tax stays with the platform that
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 the
3154
- * marketplace session pins no `payment_method_types`, so a buyer may pay by
3155
- * either. Break-even is computed from the dearest enabled method, because a
3156
- * figure computed from the cheapest would be wrong exactly when it mattered.
3157
- * IF BNPL IS EVER TURNED OFF FOR MARKETPLACE SESSIONS, this constant is what
3158
- * has to move with it.
3159
- */ export const MARKETPLACE_PROCESSING_PERCENT_CARD = 2.9;
3160
- /** Klarna/Affirm, roughly. See the note above — this is the binding one. */ export const MARKETPLACE_PROCESSING_PERCENT_BNPL = 6;
3161
- /** Stripe's per-transaction fixed component, in cents. */ export const MARKETPLACE_PROCESSING_FIXED_CENTS = 30;
3162
- /**
3163
- * The tax rate the break-even figure assumes. Tax is added ON TOP of the
3164
- * listing price and enlarges the base Stripe charges its percentage against,
3165
- * so it makes the platform's cost slightly worse; the real rate is whatever
3166
- * `automatic_tax` computes for the buyer's address, and this is the
3167
- * platform's own Texas rate as a representative figure.
3168
- */ export const MARKETPLACE_ASSUMED_TAX_PERCENT = 8.25;
3169
- /**
3170
- * The processing rate a STOREFRONT destination charge is priced against
3171
- * (AGL-2152), and the one identifier to repoint if the storefront's payment
3172
- * method set changes.
3173
- *
3174
- * Deliberately its OWN name rather than a direct use of the marketplace
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).crmEmailsPerDay;
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).formSubmissionsPerMonth;
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).formSubmissionsPerMonth;
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. That quotient is stable even while the page's weight is not,
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.21 against about $0.16 of real
4003
- * cost, so the tail is no longer a loss — but a scraper, a hotlinked asset or
4004
- * a botnet still bills the account holder for traffic they did not ask for,
4005
- * and the ceiling is what bounds that before staff look at it. At 10× the
4006
- * band that tail was open-ended on Agency; at 3× it is bounded.
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 ≈ **$16 of real COGS** at
4017
- * `METERED_UNIT_RATES_USD.perPageView` — well above the free band, and an
4018
- * order of magnitude below the $162 a million views costs. It is the number
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
- * Both halves must hold: the flag is for THIS month, and the trip was
4132
- * recorded as one that degrades. `degraded` is written by the evaluator from
4133
- * {@link bandwidthCeilingDegradesRender} at trip time rather than re-derived
4134
- * here, so a host that upgrades mid-month is not still being degraded by a
4135
- * flag written while it was free — and, in the other direction, a flag from a
4136
- * paying host can never take that host down.
4137
- */ export function bandwidthCeilingDegradesHost(host, month) {
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);