@aglyn/aglyn 1.0.0-beta.217 → 1.0.0-beta.219
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +14 -14
- package/src/lib/app-utils/actions.d.ts +25 -374
- package/src/lib/app-utils/actions.js +101 -561
- package/src/lib/app-utils/actions.js.map +1 -1
- package/src/lib/app-utils/activity-presenter.d.ts +3 -3
- package/src/lib/app-utils/activity-presenter.js +36 -52
- package/src/lib/app-utils/activity-presenter.js.map +1 -1
- package/src/lib/app-utils/admin-audit-index.js +2 -2
- package/src/lib/app-utils/admin-audit-index.js.map +1 -1
- package/src/lib/app-utils/analytics-events.d.ts +11 -2
- package/src/lib/app-utils/analytics-events.js +11 -2
- package/src/lib/app-utils/analytics-events.js.map +1 -1
- package/src/lib/app-utils/analytics-provider.d.ts +182 -0
- package/src/lib/app-utils/analytics-provider.js +133 -0
- package/src/lib/app-utils/analytics-provider.js.map +1 -0
- package/src/lib/app-utils/api-plugins.d.ts +46 -0
- package/src/lib/app-utils/api-plugins.js +19 -0
- package/src/lib/app-utils/api-plugins.js.map +1 -1
- package/src/lib/app-utils/{marketplace-overrides.d.ts → artifact-overrides.d.ts} +9 -6
- package/src/lib/app-utils/{marketplace-overrides.js → artifact-overrides.js} +10 -7
- package/src/lib/app-utils/artifact-overrides.js.map +1 -0
- package/src/lib/app-utils/{marketplace-provenance.d.ts → artifact-provenance.d.ts} +12 -10
- package/src/lib/app-utils/{marketplace-provenance.js → artifact-provenance.js} +9 -7
- package/src/lib/app-utils/artifact-provenance.js.map +1 -0
- package/src/lib/app-utils/assist-credits.js +2 -1
- package/src/lib/app-utils/assist-credits.js.map +1 -1
- package/src/lib/app-utils/binding-token-catalog.d.ts +5 -13
- package/src/lib/app-utils/binding-token-catalog.js +17 -41
- package/src/lib/app-utils/binding-token-catalog.js.map +1 -1
- package/src/lib/app-utils/binding-tokens.js +1 -1
- package/src/lib/app-utils/binding-tokens.js.map +1 -1
- package/src/lib/app-utils/brand-support-line.d.ts +36 -0
- package/src/lib/app-utils/brand-support-line.js +38 -0
- package/src/lib/app-utils/brand-support-line.js.map +1 -0
- package/src/lib/app-utils/campaign-touch.d.ts +5 -5
- package/src/lib/app-utils/campaign-touch.js +8 -8
- package/src/lib/app-utils/campaign-touch.js.map +1 -1
- package/src/lib/app-utils/collection-entries.d.ts +2 -2
- package/src/lib/app-utils/collection-entries.js.map +1 -1
- package/src/lib/app-utils/consent-group-change.d.ts +4 -0
- package/src/lib/app-utils/consent-group-change.js.map +1 -1
- package/src/lib/app-utils/console-record-links.d.ts +10 -89
- package/src/lib/app-utils/console-record-links.js +3 -107
- package/src/lib/app-utils/console-record-links.js.map +1 -1
- package/src/lib/app-utils/console-routes.d.ts +16 -7
- package/src/lib/app-utils/console-routes.js +9 -3
- package/src/lib/app-utils/console-routes.js.map +1 -1
- package/src/lib/app-utils/contacts.d.ts +23 -1
- package/src/lib/app-utils/contacts.js +21 -5
- package/src/lib/app-utils/contacts.js.map +1 -1
- package/src/lib/app-utils/cross-pool-desync.d.ts +39 -0
- package/src/lib/app-utils/cross-pool-desync.js +47 -0
- package/src/lib/app-utils/cross-pool-desync.js.map +1 -0
- package/src/lib/app-utils/csv-upload.d.ts +29 -0
- package/src/lib/app-utils/csv-upload.js +29 -0
- package/src/lib/app-utils/csv-upload.js.map +1 -0
- package/src/lib/app-utils/dataset-models.d.ts +5 -5
- package/src/lib/app-utils/dataset-models.js +19 -2
- package/src/lib/app-utils/dataset-models.js.map +1 -1
- package/src/lib/app-utils/datasets.d.ts +65 -11
- package/src/lib/app-utils/datasets.js +74 -11
- package/src/lib/app-utils/datasets.js.map +1 -1
- package/src/lib/app-utils/docs-deflection.d.ts +6 -6
- package/src/lib/app-utils/docs-deflection.js.map +1 -1
- package/src/lib/app-utils/docs-help.generated.d.ts +12 -6
- package/src/lib/app-utils/docs-help.generated.js +21 -6
- package/src/lib/app-utils/docs-help.generated.js.map +1 -1
- package/src/lib/app-utils/docs-index.generated.d.ts +2 -2
- package/src/lib/app-utils/docs-index.generated.js +514 -318
- package/src/lib/app-utils/docs-index.generated.js.map +1 -1
- package/src/lib/app-utils/docs-retrieval.d.ts +3 -3
- package/src/lib/app-utils/docs-retrieval.js +14 -10
- package/src/lib/app-utils/docs-retrieval.js.map +1 -1
- package/src/lib/app-utils/duplicate-resource.d.ts +4 -1
- package/src/lib/app-utils/duplicate-resource.js +7 -4
- package/src/lib/app-utils/duplicate-resource.js.map +1 -1
- package/src/lib/app-utils/dynamic-list-rule.d.ts +1 -1
- package/src/lib/app-utils/dynamic-list-rule.js.map +1 -1
- package/src/lib/app-utils/element-ui.d.ts +1 -1
- package/src/lib/app-utils/element-ui.js +1 -1
- package/src/lib/app-utils/element-ui.js.map +1 -1
- package/src/lib/app-utils/email-starter-policy.js +3 -3
- package/src/lib/app-utils/email-starter-policy.js.map +1 -1
- package/src/lib/app-utils/entity-picker-context.d.ts +10 -5
- package/src/lib/app-utils/entity-picker-context.js.map +1 -1
- package/src/lib/app-utils/error-beacon.d.ts +75 -6
- package/src/lib/app-utils/error-beacon.js +160 -21
- package/src/lib/app-utils/error-beacon.js.map +1 -1
- package/src/lib/app-utils/expand-repeatables.d.ts +10 -10
- package/src/lib/app-utils/expand-repeatables.js +10 -10
- package/src/lib/app-utils/expand-repeatables.js.map +1 -1
- package/src/lib/app-utils/host-events.d.ts +82 -0
- package/src/lib/app-utils/host-events.js +62 -0
- package/src/lib/app-utils/host-events.js.map +1 -0
- package/src/lib/app-utils/lockdown.d.ts +33 -1
- package/src/lib/app-utils/lockdown.js +45 -4
- package/src/lib/app-utils/lockdown.js.map +1 -1
- package/src/lib/app-utils/margin-utilization.d.ts +4 -69
- package/src/lib/app-utils/margin-utilization.js +82 -69
- package/src/lib/app-utils/margin-utilization.js.map +1 -1
- package/src/lib/app-utils/node-definition-sanitizer.d.ts +16 -16
- package/src/lib/app-utils/node-definition-sanitizer.js +24 -20
- package/src/lib/app-utils/node-definition-sanitizer.js.map +1 -1
- package/src/lib/app-utils/node-interactions.d.ts +7 -7
- package/src/lib/app-utils/node-interactions.js.map +1 -1
- package/src/lib/app-utils/notifications.d.ts +78 -47
- package/src/lib/app-utils/notifications.js +63 -44
- package/src/lib/app-utils/notifications.js.map +1 -1
- package/src/lib/app-utils/payments-configured.d.ts +8 -21
- package/src/lib/app-utils/payments-configured.js +8 -23
- package/src/lib/app-utils/payments-configured.js.map +1 -1
- package/src/lib/app-utils/plan-entitlements.d.ts +43 -128
- package/src/lib/app-utils/plan-entitlements.js +145 -304
- package/src/lib/app-utils/plan-entitlements.js.map +1 -1
- package/src/lib/app-utils/platform-brand.d.ts +10 -0
- package/src/lib/app-utils/platform-brand.js +14 -3
- package/src/lib/app-utils/platform-brand.js.map +1 -1
- package/src/lib/app-utils/plugin-api-rate-limit.d.ts +7 -1
- package/src/lib/app-utils/plugin-api-rate-limit.js +11 -3
- package/src/lib/app-utils/plugin-api-rate-limit.js.map +1 -1
- package/src/lib/app-utils/plugin-bundle-checks.js +2 -2
- package/src/lib/app-utils/plugin-bundle-checks.js.map +1 -1
- package/src/lib/app-utils/plugin-host-events.generated.d.ts +12 -0
- package/src/lib/app-utils/plugin-host-events.generated.js +169 -0
- package/src/lib/app-utils/plugin-host-events.generated.js.map +1 -0
- package/src/lib/app-utils/plugin-release-flags.generated.d.ts +12 -0
- package/src/lib/app-utils/plugin-release-flags.generated.js +106 -0
- package/src/lib/app-utils/plugin-release-flags.generated.js.map +1 -0
- package/src/lib/app-utils/realm-host-surface.generated.js +2 -0
- package/src/lib/app-utils/realm-host-surface.generated.js.map +1 -1
- package/src/lib/app-utils/release-flags.d.ts +14 -5
- package/src/lib/app-utils/release-flags.js +21 -125
- package/src/lib/app-utils/release-flags.js.map +1 -1
- package/src/lib/app-utils/repeat-sources.d.ts +9 -0
- package/src/lib/app-utils/repeat-sources.js.map +1 -1
- package/src/lib/app-utils/retained-refusals.d.ts +73 -0
- package/src/lib/app-utils/retained-refusals.js +186 -0
- package/src/lib/app-utils/retained-refusals.js.map +1 -0
- package/src/lib/app-utils/scope-tokens.d.ts +27 -0
- package/src/lib/app-utils/scope-tokens.js +61 -0
- package/src/lib/app-utils/scope-tokens.js.map +1 -1
- package/src/lib/app-utils/screen-link-context.js +3 -3
- package/src/lib/app-utils/screen-link-context.js.map +1 -1
- package/src/lib/app-utils/screen-route.d.ts +15 -0
- package/src/lib/app-utils/screen-route.js +21 -1
- package/src/lib/app-utils/screen-route.js.map +1 -1
- package/src/lib/app-utils/seo-audit.d.ts +132 -0
- package/src/lib/app-utils/seo-audit.js +246 -0
- package/src/lib/app-utils/seo-audit.js.map +1 -0
- package/src/lib/app-utils/seo-keywords.d.ts +48 -0
- package/src/lib/app-utils/seo-keywords.js +60 -0
- package/src/lib/app-utils/seo-keywords.js.map +1 -0
- package/src/lib/app-utils/seo-page-facts.d.ts +66 -0
- package/src/lib/app-utils/seo-page-facts.js +155 -0
- package/src/lib/app-utils/seo-page-facts.js.map +1 -0
- package/src/lib/app-utils/seo-site-scan.d.ts +126 -0
- package/src/lib/app-utils/seo-site-scan.js +162 -0
- package/src/lib/app-utils/seo-site-scan.js.map +1 -0
- package/src/lib/app-utils/seo-title-variables.js +1 -1
- package/src/lib/app-utils/seo-title-variables.js.map +1 -1
- package/src/lib/app-utils/server.d.ts +6 -9
- package/src/lib/app-utils/server.js +17 -27
- package/src/lib/app-utils/server.js.map +1 -1
- package/src/lib/app-utils/site-interactions.d.ts +501 -0
- package/src/lib/app-utils/site-interactions.js +554 -0
- package/src/lib/app-utils/site-interactions.js.map +1 -0
- package/src/lib/app-utils/{marketplace-theme.d.ts → site-theme.d.ts} +13 -2
- package/src/lib/app-utils/{marketplace-theme.js → site-theme.js} +5 -2
- package/src/lib/app-utils/site-theme.js.map +1 -0
- package/src/lib/app-utils/sitemap.d.ts +4 -3
- package/src/lib/app-utils/sitemap.js +9 -7
- package/src/lib/app-utils/sitemap.js.map +1 -1
- package/src/lib/app-utils/stale-build-error.d.ts +51 -0
- package/src/lib/app-utils/stale-build-error.js +100 -1
- package/src/lib/app-utils/stale-build-error.js.map +1 -1
- package/src/lib/app-utils/starter-templates.d.ts +20 -0
- package/src/lib/app-utils/starter-templates.js +49 -0
- package/src/lib/app-utils/starter-templates.js.map +1 -1
- package/src/lib/app-utils/tax-jurisdiction-figures.d.ts +118 -0
- package/src/lib/app-utils/tax-jurisdiction-figures.js +123 -0
- package/src/lib/app-utils/tax-jurisdiction-figures.js.map +1 -0
- package/src/lib/app-utils/theme-library.d.ts +10 -3
- package/src/lib/app-utils/theme-library.js +13 -4
- package/src/lib/app-utils/theme-library.js.map +1 -1
- package/src/lib/app-utils/{campaign-attribution.d.ts → utm-attribution.d.ts} +11 -6
- package/src/lib/app-utils/{campaign-attribution.js → utm-attribution.js} +13 -8
- package/src/lib/app-utils/utm-attribution.js.map +1 -0
- package/src/lib/app-utils/{campaign-forwarding.d.ts → utm-forwarding.d.ts} +14 -14
- package/src/lib/app-utils/{campaign-forwarding.js → utm-forwarding.js} +26 -26
- package/src/lib/app-utils/utm-forwarding.js.map +1 -0
- package/src/lib/app-utils/video-object.js +6 -5
- package/src/lib/app-utils/video-object.js.map +1 -1
- package/src/lib/app-utils/visitor-consent.d.ts +41 -164
- package/src/lib/app-utils/visitor-consent.js +66 -277
- package/src/lib/app-utils/visitor-consent.js.map +1 -1
- package/src/lib/app-utils/web-vitals-rum.d.ts +7 -7
- package/src/lib/app-utils/web-vitals-rum.js +31 -63
- package/src/lib/app-utils/web-vitals-rum.js.map +1 -1
- package/src/lib/app-utils/where-used.d.ts +11 -6
- package/src/lib/app-utils/where-used.js +3 -8
- package/src/lib/app-utils/where-used.js.map +1 -1
- package/src/lib/canvas-manager/canvas-manager.js +3 -3
- package/src/lib/canvas-manager/canvas-manager.js.map +1 -1
- package/src/lib/foundation/definitions/components.types.d.ts +1 -1
- package/src/lib/foundation/definitions/components.types.js +1 -1
- package/src/lib/foundation/definitions/components.types.js.map +1 -1
- package/src/lib/foundation/definitions/org-billing.types.d.ts +18 -135
- package/src/lib/foundation/definitions/org-billing.types.js.map +1 -1
- package/src/lib/foundation/definitions/organization.types.d.ts +6 -3
- package/src/lib/foundation/definitions/organization.types.js.map +1 -1
- package/src/lib/foundation/definitions/platform.types.d.ts +27 -5
- package/src/lib/foundation/definitions/platform.types.js.map +1 -1
- package/src/lib/foundation/definitions/write-deny-coverage.util.d.ts +16 -0
- package/src/lib/foundation/definitions/write-deny-coverage.util.js +20 -0
- package/src/lib/foundation/definitions/write-deny-coverage.util.js.map +1 -1
- package/src/lib/foundation/index.d.ts +1 -1
- package/src/lib/foundation/index.js.map +1 -1
- package/src/lib/plugin-manager/besigner-documents.d.ts +96 -0
- package/src/lib/plugin-manager/besigner-documents.js +61 -0
- package/src/lib/plugin-manager/besigner-documents.js.map +1 -0
- package/src/lib/plugin-manager/computed-variables.d.ts +71 -0
- package/src/lib/plugin-manager/computed-variables.js +74 -0
- package/src/lib/plugin-manager/computed-variables.js.map +1 -0
- package/src/lib/plugin-manager/custom-fields.d.ts +29 -2
- package/src/lib/plugin-manager/custom-fields.js +47 -1
- package/src/lib/plugin-manager/custom-fields.js.map +1 -1
- package/src/lib/plugin-manager/feature-plugins.d.ts +292 -20
- package/src/lib/plugin-manager/feature-plugins.js +105 -17
- package/src/lib/plugin-manager/feature-plugins.js.map +1 -1
- package/src/lib/plugin-manager/first-party-plugins.generated.d.ts +123 -0
- package/src/lib/plugin-manager/first-party-plugins.generated.js +785 -14
- package/src/lib/plugin-manager/first-party-plugins.generated.js.map +1 -1
- package/src/lib/plugin-manager/plugin-activity-actions.d.ts +12 -0
- package/src/lib/plugin-manager/plugin-activity-actions.js +25 -0
- package/src/lib/plugin-manager/plugin-activity-actions.js.map +1 -1
- package/src/lib/plugin-manager/plugin-contributions.d.ts +1 -1
- package/src/lib/plugin-manager/plugin-contributions.js.map +1 -1
- package/src/lib/plugin-manager/plugin-declarations-repair.d.ts +36 -0
- package/src/lib/plugin-manager/plugin-declarations-repair.js +64 -0
- package/src/lib/plugin-manager/plugin-declarations-repair.js.map +1 -0
- package/src/lib/plugin-manager/plugin-dependents.d.ts +101 -0
- package/src/lib/plugin-manager/plugin-dependents.js +75 -0
- package/src/lib/plugin-manager/plugin-dependents.js.map +1 -0
- package/src/lib/plugin-manager/plugin-distribution.d.ts +55 -0
- package/src/lib/plugin-manager/plugin-distribution.js +45 -0
- package/src/lib/plugin-manager/plugin-distribution.js.map +1 -0
- package/src/lib/plugin-manager/plugin-host-collections.d.ts +17 -0
- package/src/lib/plugin-manager/plugin-host-collections.js +6 -0
- package/src/lib/plugin-manager/plugin-host-collections.js.map +1 -1
- package/src/lib/plugin-manager/plugin-host-resources.d.ts +133 -0
- package/src/lib/plugin-manager/plugin-host-resources.js +52 -0
- package/src/lib/plugin-manager/plugin-host-resources.js.map +1 -0
- package/src/lib/plugin-manager/plugin-org-erasure.d.ts +28 -2
- package/src/lib/plugin-manager/plugin-org-erasure.js +61 -2
- package/src/lib/plugin-manager/plugin-org-erasure.js.map +1 -1
- package/src/lib/plugin-manager/plugin-plan-entitlements.d.ts +123 -0
- package/src/lib/plugin-manager/plugin-plan-entitlements.js +101 -0
- package/src/lib/plugin-manager/plugin-plan-entitlements.js.map +1 -0
- package/src/lib/plugin-manager/plugin-record-index.d.ts +95 -0
- package/src/lib/plugin-manager/plugin-record-index.js +51 -0
- package/src/lib/plugin-manager/plugin-record-index.js.map +1 -0
- package/src/lib/plugin-manager/plugin-record-written.d.ts +58 -0
- package/src/lib/plugin-manager/plugin-record-written.js +42 -0
- package/src/lib/plugin-manager/plugin-record-written.js.map +1 -0
- package/src/lib/plugin-manager/plugin-revenue-sources.d.ts +213 -0
- package/src/lib/plugin-manager/plugin-revenue-sources.js +194 -0
- package/src/lib/plugin-manager/plugin-revenue-sources.js.map +1 -0
- package/src/lib/plugin-manager/plugin-site-bundle.d.ts +145 -0
- package/src/lib/plugin-manager/plugin-site-bundle.js +78 -0
- package/src/lib/plugin-manager/plugin-site-bundle.js.map +1 -0
- package/src/lib/plugin-manager/plugin-site-cache.d.ts +12 -0
- package/src/lib/plugin-manager/plugin-site-cache.js.map +1 -1
- package/src/lib/plugin-manager/plugin-site-export.d.ts +81 -0
- package/src/lib/plugin-manager/plugin-site-export.js +40 -0
- package/src/lib/plugin-manager/plugin-site-export.js.map +1 -0
- package/src/lib/plugin-manager/plugin-sitemap-sections.d.ts +88 -0
- package/src/lib/plugin-manager/plugin-sitemap-sections.js +29 -0
- package/src/lib/plugin-manager/plugin-sitemap-sections.js.map +1 -0
- package/src/lib/plugin-manager/plugin-tax-profile.d.ts +20 -4
- package/src/lib/plugin-manager/plugin-tax-profile.js.map +1 -1
- package/src/lib/plugin-manager/plugin-tax-return-sources.d.ts +255 -0
- package/src/lib/plugin-manager/plugin-tax-return-sources.js +191 -0
- package/src/lib/plugin-manager/plugin-tax-return-sources.js.map +1 -0
- package/src/lib/plugin-manager/plugin-template-sources.d.ts +75 -0
- package/src/lib/plugin-manager/plugin-template-sources.js +37 -0
- package/src/lib/plugin-manager/plugin-template-sources.js.map +1 -0
- package/src/lib/plugin-manager/plugin-usage-axes.d.ts +107 -0
- package/src/lib/plugin-manager/plugin-usage-axes.js +107 -0
- package/src/lib/plugin-manager/plugin-usage-axes.js.map +1 -0
- package/src/lib/plugin-manager/plugin-zones.d.ts +4 -5
- package/src/lib/plugin-manager/plugin-zones.js.map +1 -1
- package/src/lib/plugin-manager/realm-host-aglyn.generated.js +2 -0
- package/src/lib/plugin-manager/realm-host-aglyn.generated.js.map +1 -1
- package/src/lib/plugin-manager/record-captured-contact.d.ts +1 -14
- package/src/lib/plugin-manager/record-captured-contact.js +10 -32
- package/src/lib/plugin-manager/record-captured-contact.js.map +1 -1
- package/src/lib/plugin-manager/repeat-rows.d.ts +124 -0
- package/src/lib/plugin-manager/repeat-rows.js +108 -0
- package/src/lib/plugin-manager/repeat-rows.js.map +1 -0
- package/src/lib/plugin-manager/submission-record-target.d.ts +144 -0
- package/src/lib/plugin-manager/submission-record-target.js +125 -0
- package/src/lib/plugin-manager/submission-record-target.js.map +1 -0
- package/src/lib/plugin-manager/video-embed-provider.d.ts +108 -0
- package/src/lib/plugin-manager/video-embed-provider.js +165 -0
- package/src/lib/plugin-manager/video-embed-provider.js.map +1 -0
- package/src/lib/types/nodes.d.ts +2 -2
- package/src/lib/types/nodes.js.map +1 -1
- package/src/lib/app-utils/campaign-attribution.js.map +0 -1
- package/src/lib/app-utils/campaign-forwarding.js.map +0 -1
- package/src/lib/app-utils/contact-holder.d.ts +0 -68
- package/src/lib/app-utils/contact-holder.js +0 -129
- package/src/lib/app-utils/contact-holder.js.map +0 -1
- package/src/lib/app-utils/contact-merge.d.ts +0 -136
- package/src/lib/app-utils/contact-merge.js +0 -412
- package/src/lib/app-utils/contact-merge.js.map +0 -1
- package/src/lib/app-utils/crm-csv.d.ts +0 -239
- package/src/lib/app-utils/crm-csv.js +0 -467
- package/src/lib/app-utils/crm-csv.js.map +0 -1
- package/src/lib/app-utils/crm-digest.d.ts +0 -185
- package/src/lib/app-utils/crm-digest.js +0 -272
- package/src/lib/app-utils/crm-digest.js.map +0 -1
- package/src/lib/app-utils/form-dataset-binding.d.ts +0 -50
- package/src/lib/app-utils/form-dataset-binding.js +0 -74
- package/src/lib/app-utils/form-dataset-binding.js.map +0 -1
- package/src/lib/app-utils/list-import.d.ts +0 -158
- package/src/lib/app-utils/list-import.js +0 -332
- package/src/lib/app-utils/list-import.js.map +0 -1
- package/src/lib/app-utils/marketplace-listing-visibility.d.ts +0 -122
- package/src/lib/app-utils/marketplace-listing-visibility.js +0 -147
- package/src/lib/app-utils/marketplace-listing-visibility.js.map +0 -1
- package/src/lib/app-utils/marketplace-overrides.js.map +0 -1
- package/src/lib/app-utils/marketplace-provenance.js.map +0 -1
- package/src/lib/app-utils/marketplace-theme.js.map +0 -1
- package/src/lib/app-utils/marketplace-update-state.d.ts +0 -119
- package/src/lib/app-utils/marketplace-update-state.js +0 -132
- package/src/lib/app-utils/marketplace-update-state.js.map +0 -1
- package/src/lib/app-utils/publisher-agreement.d.ts +0 -289
- package/src/lib/app-utils/publisher-agreement.js +0 -321
- package/src/lib/app-utils/publisher-agreement.js.map +0 -1
- package/src/lib/app-utils/wistia-embed.d.ts +0 -104
- package/src/lib/app-utils/wistia-embed.js +0 -138
- package/src/lib/app-utils/wistia-embed.js.map +0 -1
- package/src/lib/app-utils/workflows.d.ts +0 -136
- package/src/lib/app-utils/workflows.js +0 -346
- package/src/lib/app-utils/workflows.js.map +0 -1
- package/src/lib/plugin-manager/commerce-zone-props.d.ts +0 -172
- package/src/lib/plugin-manager/commerce-zone-props.js +0 -31
- package/src/lib/plugin-manager/commerce-zone-props.js.map +0 -1
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* A plugin's host collection as a KIND the platform's generic create route
|
|
19
|
+
* writes (AGL-3080).
|
|
20
|
+
*
|
|
21
|
+
* `/api/hosts/resources` is the only door a client creates quota-governed
|
|
22
|
+
* site documents through: the rules deny client `create` on each of these
|
|
23
|
+
* collections, and the route is the allow-list of what a client may write
|
|
24
|
+
* (AGL-1377), the count it is met against (AGL-473, AGL-2231) and the
|
|
25
|
+
* provenance it stamps (AGL-118). `duplicateResource` is its twin for a copy.
|
|
26
|
+
* Both used to hold every plugin's row — which collection a workflow lives
|
|
27
|
+
* in, which entitlement a product needs, which fields a redirect may carry —
|
|
28
|
+
* so the platform was the keeper of its plugins' document models, and a
|
|
29
|
+
* plugin could not add a kind without editing core.
|
|
30
|
+
*
|
|
31
|
+
* So the plugin that owns a collection declares the kind it is created as,
|
|
32
|
+
* beside the collection itself in the `hostCollections` block of
|
|
33
|
+
* `plugins.config.json` (a host collection's `resource`),
|
|
34
|
+
* and both readers ask this module.
|
|
35
|
+
*
|
|
36
|
+
* ## Compiled, and refused when absent
|
|
37
|
+
*
|
|
38
|
+
* The route is a SECURITY path: its field list is what stands between a
|
|
39
|
+
* client and a document the UI later presents as trustworthy. A runtime
|
|
40
|
+
* registry that one process had not filled would either refuse a legitimate
|
|
41
|
+
* create or — worse, if a reader ever fell back to an open list — store
|
|
42
|
+
* whatever it was sent. So these rows are compiled by
|
|
43
|
+
* `tools/scripts/generate-plugin-manifests.mjs`, present the moment this
|
|
44
|
+
* module is imported, and a kind nobody declares is REFUSED as an unknown
|
|
45
|
+
* resource. There is no registrar: `registerPluginHostCollections` refuses a
|
|
46
|
+
* declaration that carries a `resource`.
|
|
47
|
+
*
|
|
48
|
+
* The generator checks what a reader would otherwise have to trust: one owner
|
|
49
|
+
* per kind and none of core's own; a count on every kind (a plan `quotaKey` or
|
|
50
|
+
* a `platformCap`); no server-stamped field, stamp or approver field on the
|
|
51
|
+
* client's list; `externalDestination` only with the publishing role; and a
|
|
52
|
+
* copy's fields a subset of the create's.
|
|
53
|
+
*
|
|
54
|
+
* ## What core keeps
|
|
55
|
+
*
|
|
56
|
+
* The NUMBERS. A declaration names its plan counter and feature flag as keys
|
|
57
|
+
* (`quotaKey`, `entitlement`) and core's plan table resolves them, exactly as
|
|
58
|
+
* it does for its own kinds. A flat platform cap is named the same way —
|
|
59
|
+
* `platformCap` is the name of a constant core holds, resolved by
|
|
60
|
+
* {@link hostResourcePlatformCap} — so no plugin carries a number that is the
|
|
61
|
+
* platform's abuse ceiling. Core also keeps everything a create does for
|
|
62
|
+
* EVERY kind: the role gate, the lockdown verdict, the transaction that counts
|
|
63
|
+
* and writes, the node codec, the timestamps and `createdBy`.
|
|
64
|
+
*
|
|
65
|
+
* Reached by its own subpath, never the barrel: its readers are server routes.
|
|
66
|
+
*/
|
|
67
|
+
/** A constant value a create writes: never the client's, never another stamp's. */
|
|
68
|
+
export type PluginHostResourceStampValue = string | number | boolean | null;
|
|
69
|
+
/** How a whole copy of the kind is made, when the kind can be duplicated. */
|
|
70
|
+
export interface PluginHostResourceDuplicate {
|
|
71
|
+
/** The field the name lives in; the copy's is made unique among the live siblings. */
|
|
72
|
+
nameField: string;
|
|
73
|
+
/** The source fields carried onto the copy — a subset of the create's. */
|
|
74
|
+
fields: readonly string[];
|
|
75
|
+
/** What the copy carries beyond the source's fields: a cleared trigger. */
|
|
76
|
+
stamps?: Readonly<Record<string, PluginHostResourceStampValue>>;
|
|
77
|
+
}
|
|
78
|
+
export interface PluginHostResourceDeclaration {
|
|
79
|
+
/** The `resource` a caller names, in camelCase: `product`, `workflow`. */
|
|
80
|
+
kind: string;
|
|
81
|
+
/** Plural, for quota copy: "this site can run 5 {label}". */
|
|
82
|
+
label: string;
|
|
83
|
+
/** Singular, for the site activity line: "Created {activityNoun}". */
|
|
84
|
+
activityNoun: string;
|
|
85
|
+
/** The activity target type a row filters and deep-links by; `content` when absent. */
|
|
86
|
+
activityType?: string;
|
|
87
|
+
/** The plan counter, an `OrgEntitlements` key core resolves. */
|
|
88
|
+
quotaKey?: string;
|
|
89
|
+
/** The plan feature the kind needs at all, an `OrgFeatureFlags` key. */
|
|
90
|
+
entitlement?: string;
|
|
91
|
+
/** A flat platform cap by the name of core's constant; see {@link hostResourcePlatformCap}. */
|
|
92
|
+
platformCap?: string;
|
|
93
|
+
/** Deleting stamps `deletedAt`, so the cap counts live documents only. */
|
|
94
|
+
softDeletes?: boolean;
|
|
95
|
+
/** Creating it needs the publishing role rather than the write role. */
|
|
96
|
+
requiresPublishRole?: boolean;
|
|
97
|
+
/** The keys a client may set. Anything else it sends is dropped. */
|
|
98
|
+
fields: readonly string[];
|
|
99
|
+
/** Constant values every create writes, e.g. `deletedAt: null` for a kind born live. */
|
|
100
|
+
stamps?: Readonly<Record<string, PluginHostResourceStampValue>>;
|
|
101
|
+
/**
|
|
102
|
+
* A destination field that may point off the platform. When the value is
|
|
103
|
+
* not a site path, the creating publisher's VERIFIED uid is stamped into
|
|
104
|
+
* `approvedByField` — the evidence a serve path trusts that somebody chose
|
|
105
|
+
* to send traffic away. Only with `requiresPublishRole`.
|
|
106
|
+
*/
|
|
107
|
+
externalDestination?: {
|
|
108
|
+
field: string;
|
|
109
|
+
approvedByField: string;
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* The field holding the site path the document answers at the moment it
|
|
113
|
+
* exists. A create announces it to the site cache, because what used to
|
|
114
|
+
* answer there is already cached as the page.
|
|
115
|
+
*/
|
|
116
|
+
livePathField?: string;
|
|
117
|
+
duplicate?: PluginHostResourceDuplicate;
|
|
118
|
+
}
|
|
119
|
+
/** A declaration with the plugin that made it and the collection it writes. */
|
|
120
|
+
export type ResolvedPluginHostResource = PluginHostResourceDeclaration & {
|
|
121
|
+
pluginId: string;
|
|
122
|
+
/** The subcollection under `hosts/{hostId}` the kind is created in. */
|
|
123
|
+
collection: string;
|
|
124
|
+
};
|
|
125
|
+
/** Every declared kind, in config order. */
|
|
126
|
+
export declare function listPluginHostResources(): ResolvedPluginHostResource[];
|
|
127
|
+
/** One declared kind, or `null` — which every reader treats as unknown. */
|
|
128
|
+
export declare function pluginHostResource(kind: unknown): ResolvedPluginHostResource | null;
|
|
129
|
+
/**
|
|
130
|
+
* The number a `platformCap` names, or `null` for a name core does not hold —
|
|
131
|
+
* which the create route answers by refusing, never by leaving it uncapped.
|
|
132
|
+
*/
|
|
133
|
+
export declare function hostResourcePlatformCap(name: string): number | null;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright 2026 Aglyn LLC
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/ import { ACTIONS_MAX_PER_HOST, WEBHOOK_MAX_PER_HOST } from "../app-utils/actions.js";
|
|
18
|
+
import { PLUGIN_HOST_COLLECTIONS_DECLARED } from "./first-party-plugins.generated.js";
|
|
19
|
+
/** Every declared kind, in config order. */ export function listPluginHostResources() {
|
|
20
|
+
const out = [];
|
|
21
|
+
for (const row of PLUGIN_HOST_COLLECTIONS_DECLARED){
|
|
22
|
+
if (row.resource) {
|
|
23
|
+
out.push(_extends({}, row.resource, {
|
|
24
|
+
pluginId: row.pluginId,
|
|
25
|
+
collection: row.name
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return out;
|
|
30
|
+
}
|
|
31
|
+
/** One declared kind, or `null` — which every reader treats as unknown. */ export function pluginHostResource(kind) {
|
|
32
|
+
var _listPluginHostResources_find;
|
|
33
|
+
if (typeof kind !== 'string' || !kind) return null;
|
|
34
|
+
return (_listPluginHostResources_find = listPluginHostResources().find((one)=>one.kind === kind)) != null ? _listPluginHostResources_find : null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The flat platform caps a declaration may name (AGL-1360, AGL-2266): a
|
|
38
|
+
* ceiling on documents mintable from a browser that no plan varies, so it has
|
|
39
|
+
* no `OrgEntitlements` key. Keyed by the constant's own name, so a search for
|
|
40
|
+
* the constant finds the declaration that uses it.
|
|
41
|
+
*/ const HOST_RESOURCE_PLATFORM_CAPS = {
|
|
42
|
+
ACTIONS_MAX_PER_HOST,
|
|
43
|
+
WEBHOOK_MAX_PER_HOST
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* The number a `platformCap` names, or `null` for a name core does not hold —
|
|
47
|
+
* which the create route answers by refusing, never by leaving it uncapped.
|
|
48
|
+
*/ export function hostResourcePlatformCap(name) {
|
|
49
|
+
return Object.prototype.hasOwnProperty.call(HOST_RESOURCE_PLATFORM_CAPS, name) ? HOST_RESOURCE_PLATFORM_CAPS[name] : null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
//# sourceMappingURL=plugin-host-resources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/plugin-manager/plugin-host-resources.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ACTIONS_MAX_PER_HOST, WEBHOOK_MAX_PER_HOST } from '../app-utils/actions'\nimport { PLUGIN_HOST_COLLECTIONS_DECLARED } from './first-party-plugins.generated'\n\n/**\n * A plugin's host collection as a KIND the platform's generic create route\n * writes (AGL-3080).\n *\n * `/api/hosts/resources` is the only door a client creates quota-governed\n * site documents through: the rules deny client `create` on each of these\n * collections, and the route is the allow-list of what a client may write\n * (AGL-1377), the count it is met against (AGL-473, AGL-2231) and the\n * provenance it stamps (AGL-118). `duplicateResource` is its twin for a copy.\n * Both used to hold every plugin's row — which collection a workflow lives\n * in, which entitlement a product needs, which fields a redirect may carry —\n * so the platform was the keeper of its plugins' document models, and a\n * plugin could not add a kind without editing core.\n *\n * So the plugin that owns a collection declares the kind it is created as,\n * beside the collection itself in the `hostCollections` block of\n * `plugins.config.json` (a host collection's `resource`),\n * and both readers ask this module.\n *\n * ## Compiled, and refused when absent\n *\n * The route is a SECURITY path: its field list is what stands between a\n * client and a document the UI later presents as trustworthy. A runtime\n * registry that one process had not filled would either refuse a legitimate\n * create or — worse, if a reader ever fell back to an open list — store\n * whatever it was sent. So these rows are compiled by\n * `tools/scripts/generate-plugin-manifests.mjs`, present the moment this\n * module is imported, and a kind nobody declares is REFUSED as an unknown\n * resource. There is no registrar: `registerPluginHostCollections` refuses a\n * declaration that carries a `resource`.\n *\n * The generator checks what a reader would otherwise have to trust: one owner\n * per kind and none of core's own; a count on every kind (a plan `quotaKey` or\n * a `platformCap`); no server-stamped field, stamp or approver field on the\n * client's list; `externalDestination` only with the publishing role; and a\n * copy's fields a subset of the create's.\n *\n * ## What core keeps\n *\n * The NUMBERS. A declaration names its plan counter and feature flag as keys\n * (`quotaKey`, `entitlement`) and core's plan table resolves them, exactly as\n * it does for its own kinds. A flat platform cap is named the same way —\n * `platformCap` is the name of a constant core holds, resolved by\n * {@link hostResourcePlatformCap} — so no plugin carries a number that is the\n * platform's abuse ceiling. Core also keeps everything a create does for\n * EVERY kind: the role gate, the lockdown verdict, the transaction that counts\n * and writes, the node codec, the timestamps and `createdBy`.\n *\n * Reached by its own subpath, never the barrel: its readers are server routes.\n */\n\n/** A constant value a create writes: never the client's, never another stamp's. */\nexport type PluginHostResourceStampValue = string | number | boolean | null\n\n/** How a whole copy of the kind is made, when the kind can be duplicated. */\nexport interface PluginHostResourceDuplicate {\n /** The field the name lives in; the copy's is made unique among the live siblings. */\n nameField: string\n /** The source fields carried onto the copy — a subset of the create's. */\n fields: readonly string[]\n /** What the copy carries beyond the source's fields: a cleared trigger. */\n stamps?: Readonly<Record<string, PluginHostResourceStampValue>>\n}\n\nexport interface PluginHostResourceDeclaration {\n /** The `resource` a caller names, in camelCase: `product`, `workflow`. */\n kind: string\n /** Plural, for quota copy: \"this site can run 5 {label}\". */\n label: string\n /** Singular, for the site activity line: \"Created {activityNoun}\". */\n activityNoun: string\n /** The activity target type a row filters and deep-links by; `content` when absent. */\n activityType?: string\n /** The plan counter, an `OrgEntitlements` key core resolves. */\n quotaKey?: string\n /** The plan feature the kind needs at all, an `OrgFeatureFlags` key. */\n entitlement?: string\n /** A flat platform cap by the name of core's constant; see {@link hostResourcePlatformCap}. */\n platformCap?: string\n /** Deleting stamps `deletedAt`, so the cap counts live documents only. */\n softDeletes?: boolean\n /** Creating it needs the publishing role rather than the write role. */\n requiresPublishRole?: boolean\n /** The keys a client may set. Anything else it sends is dropped. */\n fields: readonly string[]\n /** Constant values every create writes, e.g. `deletedAt: null` for a kind born live. */\n stamps?: Readonly<Record<string, PluginHostResourceStampValue>>\n /**\n * A destination field that may point off the platform. When the value is\n * not a site path, the creating publisher's VERIFIED uid is stamped into\n * `approvedByField` — the evidence a serve path trusts that somebody chose\n * to send traffic away. Only with `requiresPublishRole`.\n */\n externalDestination?: { field: string; approvedByField: string }\n /**\n * The field holding the site path the document answers at the moment it\n * exists. A create announces it to the site cache, because what used to\n * answer there is already cached as the page.\n */\n livePathField?: string\n duplicate?: PluginHostResourceDuplicate\n}\n\n/** A declaration with the plugin that made it and the collection it writes. */\nexport type ResolvedPluginHostResource = PluginHostResourceDeclaration & {\n pluginId: string\n /** The subcollection under `hosts/{hostId}` the kind is created in. */\n collection: string\n}\n\n/** Every declared kind, in config order. */\nexport function listPluginHostResources(): ResolvedPluginHostResource[] {\n const out: ResolvedPluginHostResource[] = []\n for (const row of PLUGIN_HOST_COLLECTIONS_DECLARED) {\n if (row.resource) {\n out.push({ ...row.resource, pluginId: row.pluginId, collection: row.name })\n }\n }\n return out\n}\n\n/** One declared kind, or `null` — which every reader treats as unknown. */\nexport function pluginHostResource(kind: unknown): ResolvedPluginHostResource | null {\n if (typeof kind !== 'string' || !kind) return null\n return listPluginHostResources().find((one) => one.kind === kind) ?? null\n}\n\n/**\n * The flat platform caps a declaration may name (AGL-1360, AGL-2266): a\n * ceiling on documents mintable from a browser that no plan varies, so it has\n * no `OrgEntitlements` key. Keyed by the constant's own name, so a search for\n * the constant finds the declaration that uses it.\n */\nconst HOST_RESOURCE_PLATFORM_CAPS: Readonly<Record<string, number>> = {\n ACTIONS_MAX_PER_HOST,\n WEBHOOK_MAX_PER_HOST,\n}\n\n/**\n * The number a `platformCap` names, or `null` for a name core does not hold —\n * which the create route answers by refusing, never by leaving it uncapped.\n */\nexport function hostResourcePlatformCap(name: string): number | null {\n return Object.prototype.hasOwnProperty.call(HOST_RESOURCE_PLATFORM_CAPS, name)\n ? HOST_RESOURCE_PLATFORM_CAPS[name]\n : null\n}\n"],"names":["ACTIONS_MAX_PER_HOST","WEBHOOK_MAX_PER_HOST","PLUGIN_HOST_COLLECTIONS_DECLARED","listPluginHostResources","out","row","resource","push","pluginId","collection","name","pluginHostResource","kind","find","one","HOST_RESOURCE_PLATFORM_CAPS","hostResourcePlatformCap","Object","prototype","hasOwnProperty","call"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,oBAAoB,EAAEC,oBAAoB,QAAQ,0BAAsB;AACjF,SAASC,gCAAgC,QAAQ,qCAAiC;AAgHlF,0CAA0C,GAC1C,OAAO,SAASC;IACd,MAAMC,MAAoC,EAAE;IAC5C,KAAK,MAAMC,OAAOH,iCAAkC;QAClD,IAAIG,IAAIC,QAAQ,EAAE;YAChBF,IAAIG,IAAI,CAAC,aAAKF,IAAIC,QAAQ;gBAAEE,UAAUH,IAAIG,QAAQ;gBAAEC,YAAYJ,IAAIK,IAAI;;QAC1E;IACF;IACA,OAAON;AACT;AAEA,yEAAyE,GACzE,OAAO,SAASO,mBAAmBC,IAAa;QAEvCT;IADP,IAAI,OAAOS,SAAS,YAAY,CAACA,MAAM,OAAO;IAC9C,QAAOT,gCAAAA,0BAA0BU,IAAI,CAAC,CAACC,MAAQA,IAAIF,IAAI,KAAKA,iBAArDT,gCAA8D;AACvE;AAEA;;;;;CAKC,GACD,MAAMY,8BAAgE;IACpEf;IACAC;AACF;AAEA;;;CAGC,GACD,OAAO,SAASe,wBAAwBN,IAAY;IAClD,OAAOO,OAAOC,SAAS,CAACC,cAAc,CAACC,IAAI,CAACL,6BAA6BL,QACrEK,2BAA2B,CAACL,KAAK,GACjC;AACN"}
|
|
@@ -14,6 +14,20 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
|
+
import { PLUGIN_ORG_KEYED_COLLECTIONS, PLUGIN_REQUIRED_ORG_ERASERS } from './first-party-plugins.generated';
|
|
18
|
+
export { PLUGIN_ORG_KEYED_COLLECTIONS, PLUGIN_REQUIRED_ORG_ERASERS };
|
|
19
|
+
/**
|
|
20
|
+
* A plugin's top-level collection whose documents name an organization in a
|
|
21
|
+
* field, declared by that plugin. See the module note.
|
|
22
|
+
*/
|
|
23
|
+
export interface PluginOrgKeyedCollection {
|
|
24
|
+
/** The plugin that declared it. */
|
|
25
|
+
pluginId: string;
|
|
26
|
+
/** The top-level collection. */
|
|
27
|
+
name: string;
|
|
28
|
+
/** The field naming the organization a document belongs to. */
|
|
29
|
+
orgField: string;
|
|
30
|
+
}
|
|
17
31
|
/** What an eraser is asked to erase. */
|
|
18
32
|
export interface PluginOrgErasureRequest {
|
|
19
33
|
/** The workspace being erased. */
|
|
@@ -43,10 +57,22 @@ export declare function registerPluginOrgEraser(eraser: PluginOrgEraser, options
|
|
|
43
57
|
/**
|
|
44
58
|
* Runs every eraser, in registration order, and answers each plugin's
|
|
45
59
|
* report by plugin id: the eraser's own report, or `null` for one that
|
|
46
|
-
* threw.
|
|
60
|
+
* threw.
|
|
61
|
+
*
|
|
62
|
+
* Throws in exactly two cases, both about a REQUIRED eraser (`required`,
|
|
63
|
+
* the compiled {@link PLUGIN_REQUIRED_ORG_ERASERS} unless a spec passes its
|
|
64
|
+
* own): before running anything, when one is not registered; and after
|
|
65
|
+
* running every eraser, when one threw.
|
|
47
66
|
*/
|
|
48
|
-
export declare function runPluginOrgErasers(request: PluginOrgErasureRequest): Promise<Record<string, PluginOrgErasureReport | null>>;
|
|
67
|
+
export declare function runPluginOrgErasers(request: PluginOrgErasureRequest, required?: readonly string[]): Promise<Record<string, PluginOrgErasureReport | null>>;
|
|
49
68
|
/** The plugins with a workspace eraser, in the order they run. */
|
|
50
69
|
export declare function listPluginOrgErasers(): string[];
|
|
51
70
|
/** Test seam: forget every eraser. */
|
|
52
71
|
export declare function resetPluginOrgErasersForTests(): void;
|
|
72
|
+
/**
|
|
73
|
+
* Test seam: a no-op eraser for every REQUIRED plugin that has none, so a
|
|
74
|
+
* spec about the erasure's own sweeps can run it without loading a plugin
|
|
75
|
+
* (core and the data layer may not import one). A spec about a required
|
|
76
|
+
* plugin's share registers the real one through the app's manifest instead.
|
|
77
|
+
*/
|
|
78
|
+
export declare function standInRequiredOrgErasersForTests(): void;
|
|
@@ -46,7 +46,33 @@
|
|
|
46
46
|
* `consoleServerDeclarations` for an eraser that opens a credential only the
|
|
47
47
|
* console holds — so the eraser is in place in a server process that never
|
|
48
48
|
* loaded the plugin's API surface.
|
|
49
|
+
*
|
|
50
|
+
* ## A REQUIRED eraser (AGL-3080)
|
|
51
|
+
*
|
|
52
|
+
* Isolation is right for a share whose failure leaves the workspace's data
|
|
53
|
+
* gone and only a provider-side courtesy undone. It is wrong for a share the
|
|
54
|
+
* erasure PROMISES: a public record naming the erased organization, a payout
|
|
55
|
+
* identifier on a world-readable document. A plugin holding such a record
|
|
56
|
+
* declares `"requiredOrgEraser": true` in `plugins.config.json`, compiled into
|
|
57
|
+
* {@link PLUGIN_REQUIRED_ORG_ERASERS} so no registration can opt out of it, and:
|
|
58
|
+
*
|
|
59
|
+
* - an erasure REFUSES to start while a required eraser is not registered —
|
|
60
|
+
* a boot that failed to declare it must not produce a "complete" erasure
|
|
61
|
+
* with the record still standing;
|
|
62
|
+
* - a required eraser that throws still lets every other eraser run, and then
|
|
63
|
+
* fails the erasure's `plugins` step, which the cron retries.
|
|
64
|
+
*
|
|
65
|
+
* ## Plugin collections keyed by the organization (AGL-3080)
|
|
66
|
+
*
|
|
67
|
+
* A plugin's TOP-LEVEL collection whose documents carry the organization's id
|
|
68
|
+
* in a field is invisible to the erasure's path deletes. The plugin declares
|
|
69
|
+
* it (`orgKeyedCollections`, compiled into {@link PLUGIN_ORG_KEYED_COLLECTIONS})
|
|
70
|
+
* and the erasure sweeps it by that field in every process, with or without
|
|
71
|
+
* the plugin loaded — a deletion that must not depend on which bundles an
|
|
72
|
+
* erasing process happened to load, so it is data rather than an eraser.
|
|
49
73
|
*/ import { getRegisteringPluginId } from "../app-utils/registering-plugin.js";
|
|
74
|
+
import { PLUGIN_ORG_KEYED_COLLECTIONS, PLUGIN_REQUIRED_ORG_ERASERS } from "./first-party-plugins.generated.js";
|
|
75
|
+
export { PLUGIN_ORG_KEYED_COLLECTIONS, PLUGIN_REQUIRED_ORG_ERASERS };
|
|
50
76
|
const registrations = [];
|
|
51
77
|
/**
|
|
52
78
|
* Registers a plugin's workspace eraser. Owner = the loader's marker inside a
|
|
@@ -72,9 +98,20 @@ const registrations = [];
|
|
|
72
98
|
/**
|
|
73
99
|
* Runs every eraser, in registration order, and answers each plugin's
|
|
74
100
|
* report by plugin id: the eraser's own report, or `null` for one that
|
|
75
|
-
* threw.
|
|
76
|
-
|
|
101
|
+
* threw.
|
|
102
|
+
*
|
|
103
|
+
* Throws in exactly two cases, both about a REQUIRED eraser (`required`,
|
|
104
|
+
* the compiled {@link PLUGIN_REQUIRED_ORG_ERASERS} unless a spec passes its
|
|
105
|
+
* own): before running anything, when one is not registered; and after
|
|
106
|
+
* running every eraser, when one threw.
|
|
107
|
+
*/ export async function runPluginOrgErasers(request, required = PLUGIN_REQUIRED_ORG_ERASERS) {
|
|
108
|
+
const registered = new Set(registrations.map((entry)=>entry.pluginId));
|
|
109
|
+
const missing = required.filter((pluginId)=>!registered.has(pluginId));
|
|
110
|
+
if (missing.length) {
|
|
111
|
+
throw new Error(`[plugins] erasing org ${request.orgId} refused: ${missing.join(', ')} ` + 'declared a required org eraser and none is registered in this process');
|
|
112
|
+
}
|
|
77
113
|
const reports = {};
|
|
114
|
+
const failedRequired = [];
|
|
78
115
|
for (const { pluginId, eraser } of [
|
|
79
116
|
...registrations
|
|
80
117
|
]){
|
|
@@ -86,8 +123,12 @@ const registrations = [];
|
|
|
86
123
|
} catch (error) {
|
|
87
124
|
reports[pluginId] = null;
|
|
88
125
|
console.error(`[plugins] ${pluginId} failed to erase org ${request.orgId}`, error);
|
|
126
|
+
if (required.includes(pluginId)) failedRequired.push(pluginId);
|
|
89
127
|
}
|
|
90
128
|
}
|
|
129
|
+
if (failedRequired.length) {
|
|
130
|
+
throw new Error(`[plugins] erasing org ${request.orgId} incomplete: the required eraser of ` + `${failedRequired.join(', ')} failed`);
|
|
131
|
+
}
|
|
91
132
|
return reports;
|
|
92
133
|
}
|
|
93
134
|
/** The plugins with a workspace eraser, in the order they run. */ export function listPluginOrgErasers() {
|
|
@@ -96,5 +137,23 @@ const registrations = [];
|
|
|
96
137
|
/** Test seam: forget every eraser. */ export function resetPluginOrgErasersForTests() {
|
|
97
138
|
registrations.length = 0;
|
|
98
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* Test seam: a no-op eraser for every REQUIRED plugin that has none, so a
|
|
142
|
+
* spec about the erasure's own sweeps can run it without loading a plugin
|
|
143
|
+
* (core and the data layer may not import one). A spec about a required
|
|
144
|
+
* plugin's share registers the real one through the app's manifest instead.
|
|
145
|
+
*/ export function standInRequiredOrgErasersForTests() {
|
|
146
|
+
const registered = new Set(registrations.map((entry)=>entry.pluginId));
|
|
147
|
+
for (const pluginId of PLUGIN_REQUIRED_ORG_ERASERS){
|
|
148
|
+
if (!registered.has(pluginId)) {
|
|
149
|
+
registrations.push({
|
|
150
|
+
pluginId,
|
|
151
|
+
eraser: async ()=>({
|
|
152
|
+
standIn: true
|
|
153
|
+
})
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
99
158
|
|
|
100
159
|
//# sourceMappingURL=plugin-org-erasure.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/plugin-manager/plugin-org-erasure.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * A plugin's share of a workspace erasure (AGL-2978).\n *\n * The workspace erasure destroys what the platform holds for an\n * organization: its document tree, its sites, and the top-level records\n * keyed to it by a field. A plugin that holds something those deletes cannot\n * finish on their own registers an eraser here — a grant at a provider that\n * only the plugin can revoke, or a record outside every path and field the\n * erasure sweeps — and the erasure runs every eraser with the organization's\n * id.\n *\n * Erasers run BEFORE the erasure deletes anything of its own. The\n * organization, its roster and every record the erasure is about to sweep\n * still exist when an eraser runs, so an eraser that has to act through a\n * record — open a stored grant to revoke it — finds the record there. What\n * the erasure deletes on its own stays its to delete: an eraser adds to the\n * erasure, and the erasure does not wait on one to finish its own sweeps.\n *\n * Erasers run in registration order and are ISOLATED: a throw is logged\n * against its plugin, recorded as `null`, and does not stop the next one or\n * the erasure. An erasure runs against a legal clock, and one plugin's\n * outage must not keep every other plugin's data, or the workspace, past it.\n * The `null` is how the erasure's audit record says that plugin's share may\n * not be done, which a report of zero would hide.\n *\n * A DRY RUN is handed to every eraser, which must then touch no provider and\n * write nothing: it counts what it would do. A plan that reached a vendor\n * would be an erasure that happened without anybody deciding it should.\n *\n * Registered from a plugin's declarations — `serverDeclarations`, or\n * `consoleServerDeclarations` for an eraser that opens a credential only the\n * console holds — so the eraser is in place in a server process that never\n * loaded the plugin's API surface.\n */\n\nimport { getRegisteringPluginId } from '../app-utils/registering-plugin'\n\n/** What an eraser is asked to erase. */\nexport interface PluginOrgErasureRequest {\n /** The workspace being erased. */\n orgId: string\n /**\n * A plan, not an erasure: count, touch no provider, write nothing. The\n * erasure's own sweeps honor the same flag.\n */\n dryRun: boolean\n}\n\n/**\n * What an eraser reports for the erasure's audit record: counts and flags,\n * never the erased content, because the record outlives the data by design.\n * A `null` field is a figure the eraser could not measure, which is not zero.\n */\nexport type PluginOrgErasureReport = Readonly<Record<string, number | boolean | null>>\n\nexport type PluginOrgEraser = (\n request: PluginOrgErasureRequest,\n) => Promise<PluginOrgErasureReport>\n\ninterface Registration {\n pluginId: string\n eraser: PluginOrgEraser\n}\n\nconst registrations: Registration[] = []\n\n/**\n * Registers a plugin's workspace eraser. Owner = the loader's marker inside a\n * register fn, else `options.pluginId`; an eraser with neither throws. One\n * eraser per plugin: registering again replaces the plugin's earlier eraser\n * in place, so a module evaluated twice does not erase twice.\n */\nexport function registerPluginOrgEraser(\n eraser: PluginOrgEraser,\n options?: { pluginId?: string },\n): void {\n const pluginId = (getRegisteringPluginId() ?? options?.pluginId ?? '').trim()\n if (!pluginId) {\n throw new Error(\n 'a plugin org eraser was registered with no owner: pass { pluginId } ' +\n 'when registering outside a plugin register fn',\n )\n }\n const index = registrations.findIndex((entry) => entry.pluginId === pluginId)\n if (index >= 0) registrations[index] = { pluginId, eraser }\n else registrations.push({ pluginId, eraser })\n}\n\n/**\n * Runs every eraser, in registration order, and answers each plugin's\n * report by plugin id: the eraser's own report, or `null` for one that\n * threw. Never throws.\n */\nexport async function runPluginOrgErasers(\n request: PluginOrgErasureRequest,\n): Promise<Record<string, PluginOrgErasureReport | null>> {\n const reports: Record<string, PluginOrgErasureReport | null> = {}\n for (const { pluginId, eraser } of [...registrations]) {\n try {\n reports[pluginId] = await eraser({ orgId: request.orgId, dryRun: request.dryRun })\n } catch (error) {\n reports[pluginId] = null\n console.error(`[plugins] ${pluginId} failed to erase org ${request.orgId}`, error)\n }\n }\n return reports\n}\n\n/** The plugins with a workspace eraser, in the order they run. */\nexport function listPluginOrgErasers(): string[] {\n return registrations.map((entry) => entry.pluginId)\n}\n\n/** Test seam: forget every eraser. */\nexport function resetPluginOrgErasersForTests(): void {\n registrations.length = 0\n}\n"],"names":["getRegisteringPluginId","registrations","registerPluginOrgEraser","eraser","options","pluginId","trim","Error","index","findIndex","entry","push","runPluginOrgErasers","request","reports","orgId","dryRun","error","console","listPluginOrgErasers","map","resetPluginOrgErasersForTests","length"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiCC,GAED,SAASA,sBAAsB,QAAQ,qCAAiC;AA6BxE,MAAMC,gBAAgC,EAAE;AAExC;;;;;CAKC,GACD,OAAO,SAASC,wBACdC,MAAuB,EACvBC,OAA+B;QAEbJ,MAAAA;IAAlB,MAAMK,WAAW,EAACL,QAAAA,0BAAAA,oCAAAA,0BAA4BI,2BAAAA,QAASC,QAAQ,YAA7CL,OAAiD,IAAIM,IAAI;IAC3E,IAAI,CAACD,UAAU;QACb,MAAM,IAAIE,MACR,yEACE;IAEN;IACA,MAAMC,QAAQP,cAAcQ,SAAS,CAAC,CAACC,QAAUA,MAAML,QAAQ,KAAKA;IACpE,IAAIG,SAAS,GAAGP,aAAa,CAACO,MAAM,GAAG;QAAEH;QAAUF;IAAO;SACrDF,cAAcU,IAAI,CAAC;QAAEN;QAAUF;IAAO;AAC7C;AAEA;;;;CAIC,GACD,OAAO,eAAeS,oBACpBC,OAAgC;IAEhC,MAAMC,UAAyD,CAAC;IAChE,KAAK,MAAM,EAAET,QAAQ,EAAEF,MAAM,EAAE,IAAI;WAAIF;KAAc,CAAE;QACrD,IAAI;YACFa,OAAO,CAACT,SAAS,GAAG,MAAMF,OAAO;gBAAEY,OAAOF,QAAQE,KAAK;gBAAEC,QAAQH,QAAQG,MAAM;YAAC;QAClF,EAAE,OAAOC,OAAO;YACdH,OAAO,CAACT,SAAS,GAAG;YACpBa,QAAQD,KAAK,CAAC,CAAC,UAAU,EAAEZ,SAAS,qBAAqB,EAAEQ,QAAQE,KAAK,EAAE,EAAEE;QAC9E;IACF;IACA,OAAOH;AACT;AAEA,gEAAgE,GAChE,OAAO,SAASK;IACd,OAAOlB,cAAcmB,GAAG,CAAC,CAACV,QAAUA,MAAML,QAAQ;AACpD;AAEA,oCAAoC,GACpC,OAAO,SAASgB;IACdpB,cAAcqB,MAAM,GAAG;AACzB"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/plugin-manager/plugin-org-erasure.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * A plugin's share of a workspace erasure (AGL-2978).\n *\n * The workspace erasure destroys what the platform holds for an\n * organization: its document tree, its sites, and the top-level records\n * keyed to it by a field. A plugin that holds something those deletes cannot\n * finish on their own registers an eraser here — a grant at a provider that\n * only the plugin can revoke, or a record outside every path and field the\n * erasure sweeps — and the erasure runs every eraser with the organization's\n * id.\n *\n * Erasers run BEFORE the erasure deletes anything of its own. The\n * organization, its roster and every record the erasure is about to sweep\n * still exist when an eraser runs, so an eraser that has to act through a\n * record — open a stored grant to revoke it — finds the record there. What\n * the erasure deletes on its own stays its to delete: an eraser adds to the\n * erasure, and the erasure does not wait on one to finish its own sweeps.\n *\n * Erasers run in registration order and are ISOLATED: a throw is logged\n * against its plugin, recorded as `null`, and does not stop the next one or\n * the erasure. An erasure runs against a legal clock, and one plugin's\n * outage must not keep every other plugin's data, or the workspace, past it.\n * The `null` is how the erasure's audit record says that plugin's share may\n * not be done, which a report of zero would hide.\n *\n * A DRY RUN is handed to every eraser, which must then touch no provider and\n * write nothing: it counts what it would do. A plan that reached a vendor\n * would be an erasure that happened without anybody deciding it should.\n *\n * Registered from a plugin's declarations — `serverDeclarations`, or\n * `consoleServerDeclarations` for an eraser that opens a credential only the\n * console holds — so the eraser is in place in a server process that never\n * loaded the plugin's API surface.\n *\n * ## A REQUIRED eraser (AGL-3080)\n *\n * Isolation is right for a share whose failure leaves the workspace's data\n * gone and only a provider-side courtesy undone. It is wrong for a share the\n * erasure PROMISES: a public record naming the erased organization, a payout\n * identifier on a world-readable document. A plugin holding such a record\n * declares `\"requiredOrgEraser\": true` in `plugins.config.json`, compiled into\n * {@link PLUGIN_REQUIRED_ORG_ERASERS} so no registration can opt out of it, and:\n *\n * - an erasure REFUSES to start while a required eraser is not registered —\n * a boot that failed to declare it must not produce a \"complete\" erasure\n * with the record still standing;\n * - a required eraser that throws still lets every other eraser run, and then\n * fails the erasure's `plugins` step, which the cron retries.\n *\n * ## Plugin collections keyed by the organization (AGL-3080)\n *\n * A plugin's TOP-LEVEL collection whose documents carry the organization's id\n * in a field is invisible to the erasure's path deletes. The plugin declares\n * it (`orgKeyedCollections`, compiled into {@link PLUGIN_ORG_KEYED_COLLECTIONS})\n * and the erasure sweeps it by that field in every process, with or without\n * the plugin loaded — a deletion that must not depend on which bundles an\n * erasing process happened to load, so it is data rather than an eraser.\n */\n\nimport { getRegisteringPluginId } from '../app-utils/registering-plugin'\nimport {\n PLUGIN_ORG_KEYED_COLLECTIONS,\n PLUGIN_REQUIRED_ORG_ERASERS,\n} from './first-party-plugins.generated'\n\nexport { PLUGIN_ORG_KEYED_COLLECTIONS, PLUGIN_REQUIRED_ORG_ERASERS }\n\n/**\n * A plugin's top-level collection whose documents name an organization in a\n * field, declared by that plugin. See the module note.\n */\nexport interface PluginOrgKeyedCollection {\n /** The plugin that declared it. */\n pluginId: string\n /** The top-level collection. */\n name: string\n /** The field naming the organization a document belongs to. */\n orgField: string\n}\n\n/** What an eraser is asked to erase. */\nexport interface PluginOrgErasureRequest {\n /** The workspace being erased. */\n orgId: string\n /**\n * A plan, not an erasure: count, touch no provider, write nothing. The\n * erasure's own sweeps honor the same flag.\n */\n dryRun: boolean\n}\n\n/**\n * What an eraser reports for the erasure's audit record: counts and flags,\n * never the erased content, because the record outlives the data by design.\n * A `null` field is a figure the eraser could not measure, which is not zero.\n */\nexport type PluginOrgErasureReport = Readonly<Record<string, number | boolean | null>>\n\nexport type PluginOrgEraser = (\n request: PluginOrgErasureRequest,\n) => Promise<PluginOrgErasureReport>\n\ninterface Registration {\n pluginId: string\n eraser: PluginOrgEraser\n}\n\nconst registrations: Registration[] = []\n\n/**\n * Registers a plugin's workspace eraser. Owner = the loader's marker inside a\n * register fn, else `options.pluginId`; an eraser with neither throws. One\n * eraser per plugin: registering again replaces the plugin's earlier eraser\n * in place, so a module evaluated twice does not erase twice.\n */\nexport function registerPluginOrgEraser(\n eraser: PluginOrgEraser,\n options?: { pluginId?: string },\n): void {\n const pluginId = (getRegisteringPluginId() ?? options?.pluginId ?? '').trim()\n if (!pluginId) {\n throw new Error(\n 'a plugin org eraser was registered with no owner: pass { pluginId } ' +\n 'when registering outside a plugin register fn',\n )\n }\n const index = registrations.findIndex((entry) => entry.pluginId === pluginId)\n if (index >= 0) registrations[index] = { pluginId, eraser }\n else registrations.push({ pluginId, eraser })\n}\n\n/**\n * Runs every eraser, in registration order, and answers each plugin's\n * report by plugin id: the eraser's own report, or `null` for one that\n * threw.\n *\n * Throws in exactly two cases, both about a REQUIRED eraser (`required`,\n * the compiled {@link PLUGIN_REQUIRED_ORG_ERASERS} unless a spec passes its\n * own): before running anything, when one is not registered; and after\n * running every eraser, when one threw.\n */\nexport async function runPluginOrgErasers(\n request: PluginOrgErasureRequest,\n required: readonly string[] = PLUGIN_REQUIRED_ORG_ERASERS,\n): Promise<Record<string, PluginOrgErasureReport | null>> {\n const registered = new Set(registrations.map((entry) => entry.pluginId))\n const missing = required.filter((pluginId) => !registered.has(pluginId))\n if (missing.length) {\n throw new Error(\n `[plugins] erasing org ${request.orgId} refused: ${missing.join(', ')} ` +\n 'declared a required org eraser and none is registered in this process',\n )\n }\n const reports: Record<string, PluginOrgErasureReport | null> = {}\n const failedRequired: string[] = []\n for (const { pluginId, eraser } of [...registrations]) {\n try {\n reports[pluginId] = await eraser({ orgId: request.orgId, dryRun: request.dryRun })\n } catch (error) {\n reports[pluginId] = null\n console.error(`[plugins] ${pluginId} failed to erase org ${request.orgId}`, error)\n if (required.includes(pluginId)) failedRequired.push(pluginId)\n }\n }\n if (failedRequired.length) {\n throw new Error(\n `[plugins] erasing org ${request.orgId} incomplete: the required eraser of ` +\n `${failedRequired.join(', ')} failed`,\n )\n }\n return reports\n}\n\n/** The plugins with a workspace eraser, in the order they run. */\nexport function listPluginOrgErasers(): string[] {\n return registrations.map((entry) => entry.pluginId)\n}\n\n/** Test seam: forget every eraser. */\nexport function resetPluginOrgErasersForTests(): void {\n registrations.length = 0\n}\n\n/**\n * Test seam: a no-op eraser for every REQUIRED plugin that has none, so a\n * spec about the erasure's own sweeps can run it without loading a plugin\n * (core and the data layer may not import one). A spec about a required\n * plugin's share registers the real one through the app's manifest instead.\n */\nexport function standInRequiredOrgErasersForTests(): void {\n const registered = new Set(registrations.map((entry) => entry.pluginId))\n for (const pluginId of PLUGIN_REQUIRED_ORG_ERASERS) {\n if (!registered.has(pluginId)) {\n registrations.push({ pluginId, eraser: async () => ({ standIn: true }) })\n }\n }\n}\n"],"names":["getRegisteringPluginId","PLUGIN_ORG_KEYED_COLLECTIONS","PLUGIN_REQUIRED_ORG_ERASERS","registrations","registerPluginOrgEraser","eraser","options","pluginId","trim","Error","index","findIndex","entry","push","runPluginOrgErasers","request","required","registered","Set","map","missing","filter","has","length","orgId","join","reports","failedRequired","dryRun","error","console","includes","listPluginOrgErasers","resetPluginOrgErasersForTests","standInRequiredOrgErasersForTests","standIn"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyDC,GAED,SAASA,sBAAsB,QAAQ,qCAAiC;AACxE,SACEC,4BAA4B,EAC5BC,2BAA2B,QACtB,qCAAiC;AAExC,SAASD,4BAA4B,EAAEC,2BAA2B,GAAE;AA0CpE,MAAMC,gBAAgC,EAAE;AAExC;;;;;CAKC,GACD,OAAO,SAASC,wBACdC,MAAuB,EACvBC,OAA+B;QAEbN,MAAAA;IAAlB,MAAMO,WAAW,EAACP,QAAAA,0BAAAA,oCAAAA,0BAA4BM,2BAAAA,QAASC,QAAQ,YAA7CP,OAAiD,IAAIQ,IAAI;IAC3E,IAAI,CAACD,UAAU;QACb,MAAM,IAAIE,MACR,yEACE;IAEN;IACA,MAAMC,QAAQP,cAAcQ,SAAS,CAAC,CAACC,QAAUA,MAAML,QAAQ,KAAKA;IACpE,IAAIG,SAAS,GAAGP,aAAa,CAACO,MAAM,GAAG;QAAEH;QAAUF;IAAO;SACrDF,cAAcU,IAAI,CAAC;QAAEN;QAAUF;IAAO;AAC7C;AAEA;;;;;;;;;CASC,GACD,OAAO,eAAeS,oBACpBC,OAAgC,EAChCC,WAA8Bd,2BAA2B;IAEzD,MAAMe,aAAa,IAAIC,IAAIf,cAAcgB,GAAG,CAAC,CAACP,QAAUA,MAAML,QAAQ;IACtE,MAAMa,UAAUJ,SAASK,MAAM,CAAC,CAACd,WAAa,CAACU,WAAWK,GAAG,CAACf;IAC9D,IAAIa,QAAQG,MAAM,EAAE;QAClB,MAAM,IAAId,MACR,CAAC,sBAAsB,EAAEM,QAAQS,KAAK,CAAC,UAAU,EAAEJ,QAAQK,IAAI,CAAC,MAAM,CAAC,CAAC,GACtE;IAEN;IACA,MAAMC,UAAyD,CAAC;IAChE,MAAMC,iBAA2B,EAAE;IACnC,KAAK,MAAM,EAAEpB,QAAQ,EAAEF,MAAM,EAAE,IAAI;WAAIF;KAAc,CAAE;QACrD,IAAI;YACFuB,OAAO,CAACnB,SAAS,GAAG,MAAMF,OAAO;gBAAEmB,OAAOT,QAAQS,KAAK;gBAAEI,QAAQb,QAAQa,MAAM;YAAC;QAClF,EAAE,OAAOC,OAAO;YACdH,OAAO,CAACnB,SAAS,GAAG;YACpBuB,QAAQD,KAAK,CAAC,CAAC,UAAU,EAAEtB,SAAS,qBAAqB,EAAEQ,QAAQS,KAAK,EAAE,EAAEK;YAC5E,IAAIb,SAASe,QAAQ,CAACxB,WAAWoB,eAAed,IAAI,CAACN;QACvD;IACF;IACA,IAAIoB,eAAeJ,MAAM,EAAE;QACzB,MAAM,IAAId,MACR,CAAC,sBAAsB,EAAEM,QAAQS,KAAK,CAAC,oCAAoC,CAAC,GAC1E,GAAGG,eAAeF,IAAI,CAAC,MAAM,OAAO,CAAC;IAE3C;IACA,OAAOC;AACT;AAEA,gEAAgE,GAChE,OAAO,SAASM;IACd,OAAO7B,cAAcgB,GAAG,CAAC,CAACP,QAAUA,MAAML,QAAQ;AACpD;AAEA,oCAAoC,GACpC,OAAO,SAAS0B;IACd9B,cAAcoB,MAAM,GAAG;AACzB;AAEA;;;;;CAKC,GACD,OAAO,SAASW;IACd,MAAMjB,aAAa,IAAIC,IAAIf,cAAcgB,GAAG,CAAC,CAACP,QAAUA,MAAML,QAAQ;IACtE,KAAK,MAAMA,YAAYL,4BAA6B;QAClD,IAAI,CAACe,WAAWK,GAAG,CAACf,WAAW;YAC7BJ,cAAcU,IAAI,CAAC;gBAAEN;gBAAUF,QAAQ,UAAa,CAAA;wBAAE8B,SAAS;oBAAK,CAAA;YAAG;QACzE;IACF;AACF"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* WHAT EACH PLAN INCLUDES OF A PLUGIN'S OWN KEYS (AGL-3080).
|
|
19
|
+
*
|
|
20
|
+
* `plugin-entitlement-keys` gives a plugin the TYPE of a key it owns, by
|
|
21
|
+
* augmentation, so `OrgEntitlements` and `OrgFeatureFlags` carry the key
|
|
22
|
+
* without core naming it. That leaves the VALUE: what Free, Starter and every
|
|
23
|
+
* other plan include of it. A key that only a plugin's type declares still
|
|
24
|
+
* needs a figure in every row of `PLAN_ENTITLEMENTS`, and core writing the
|
|
25
|
+
* figure is core naming the key.
|
|
26
|
+
*
|
|
27
|
+
* So the owning plugin declares the figure per plan, beside the reasoning
|
|
28
|
+
* that sized it, and core composes it into the plan table. A plan row in
|
|
29
|
+
* `PLAN_ENTITLEMENTS` still answers every key the platform sells, at the same
|
|
30
|
+
* number — `/pricing`, the plan comparison, the pricing-table generator and
|
|
31
|
+
* every quota gate read the composed table and cannot tell the difference.
|
|
32
|
+
*
|
|
33
|
+
* ## Compiled, never registered
|
|
34
|
+
*
|
|
35
|
+
* The readers include the published pricing tables, which a generator builds
|
|
36
|
+
* from `PLAN_ENTITLEMENTS` with no plugin loaded, and the customer's plan
|
|
37
|
+
* comparison, which renders before any plugin surface does. A registry one of
|
|
38
|
+
* them had not filled would publish a plan without the band — a missing row on
|
|
39
|
+
* the price list, or a quota gate reading nothing — with nothing red. So a
|
|
40
|
+
* first-party plugin names a function under `register.planEntitlements` in
|
|
41
|
+
* `plugins.config.json`; `tools/scripts/generate-plugin-manifests.mjs` loads
|
|
42
|
+
* `${package}/plan-entitlements`, calls it, validates the answer and compiles
|
|
43
|
+
* it into `first-party-plugins.generated.ts` as data. There is no runtime
|
|
44
|
+
* registrar, for the reason `plugin-org-capacity` gives: a registrar nothing
|
|
45
|
+
* can safely call is worse than none.
|
|
46
|
+
*
|
|
47
|
+
* ## What a missing figure means
|
|
48
|
+
*
|
|
49
|
+
* A declaration names every plan: the generated rows are typed
|
|
50
|
+
* `Record<OrgPlan, …>`, so a plan left out does not compile. A key nobody
|
|
51
|
+
* declares is absent from the table, and each reader answers absence in the
|
|
52
|
+
* closed direction — a quota reads as nothing included, a feature as off.
|
|
53
|
+
* `planQuotaOf` below is that reading, and it never answers "unlimited" or
|
|
54
|
+
* "free" for a key that has no figure.
|
|
55
|
+
*
|
|
56
|
+
* ## One key, one owner, and never one of core's
|
|
57
|
+
*
|
|
58
|
+
* The generator refuses a key two plugins declare. A key the platform's own
|
|
59
|
+
* rows already carry is refused by `plan-entitlements.spec.ts` rather than
|
|
60
|
+
* here, because the generator cannot read core's rows without loading the
|
|
61
|
+
* module that imports this one; the composition keeps core's figure either
|
|
62
|
+
* way, so a collision can shadow nothing a customer is charged.
|
|
63
|
+
*/
|
|
64
|
+
import type { OrgPlan } from '../foundation';
|
|
65
|
+
/** A numeric entitlement a plugin owns: a band, a daily pace, a take rate. */
|
|
66
|
+
export interface PluginPlanQuotaDeclaration {
|
|
67
|
+
/** The stored key, exactly as `OrgEntitlements` and an override spell it. */
|
|
68
|
+
key: string;
|
|
69
|
+
/** What a staff page calls it. */
|
|
70
|
+
label: string;
|
|
71
|
+
/**
|
|
72
|
+
* What each plan includes. `Infinity` is `UNLIMITED`; every other value is
|
|
73
|
+
* a finite, non-negative number.
|
|
74
|
+
*/
|
|
75
|
+
byPlan: Readonly<Record<OrgPlan, number>>;
|
|
76
|
+
/**
|
|
77
|
+
* A PRICE rather than a cap — a percentage of a sale — so an uncapped plan
|
|
78
|
+
* comp must never lift it (`PRICE_ENTITLEMENT_KEYS`).
|
|
79
|
+
*/
|
|
80
|
+
price?: boolean;
|
|
81
|
+
}
|
|
82
|
+
/** A boolean gate a plugin owns. */
|
|
83
|
+
export interface PluginPlanFeatureDeclaration {
|
|
84
|
+
/** The stored key, exactly as `OrgFeatureFlags` and an override spell it. */
|
|
85
|
+
key: string;
|
|
86
|
+
label: string;
|
|
87
|
+
byPlan: Readonly<Record<OrgPlan, boolean>>;
|
|
88
|
+
}
|
|
89
|
+
/** What a plugin's `planEntitlements` function answers. */
|
|
90
|
+
export interface PluginPlanEntitlementsDeclaration {
|
|
91
|
+
quotas?: readonly PluginPlanQuotaDeclaration[];
|
|
92
|
+
features?: readonly PluginPlanFeatureDeclaration[];
|
|
93
|
+
}
|
|
94
|
+
/** A quota declaration with the plugin that made it. */
|
|
95
|
+
export type ResolvedPluginPlanQuota = PluginPlanQuotaDeclaration & {
|
|
96
|
+
pluginId: string;
|
|
97
|
+
};
|
|
98
|
+
/** A feature declaration with the plugin that made it. */
|
|
99
|
+
export type ResolvedPluginPlanFeature = PluginPlanFeatureDeclaration & {
|
|
100
|
+
pluginId: string;
|
|
101
|
+
};
|
|
102
|
+
/** Every declared quota, in catalog order. */
|
|
103
|
+
export declare function pluginPlanQuotas(): readonly ResolvedPluginPlanQuota[];
|
|
104
|
+
/** Every declared feature, in catalog order. */
|
|
105
|
+
export declare function pluginPlanFeatures(): readonly ResolvedPluginPlanFeature[];
|
|
106
|
+
/** The plugin that declared a quota or feature key, or `null`. */
|
|
107
|
+
export declare function pluginPlanEntitlementOwner(key: string): string | null;
|
|
108
|
+
/** The declared quotas' figures for one plan, keyed by the stored key. */
|
|
109
|
+
export declare function pluginPlanQuotaRow(plan: OrgPlan): Record<string, number>;
|
|
110
|
+
/** The declared features' answers for one plan, keyed by the stored key. */
|
|
111
|
+
export declare function pluginPlanFeatureRow(plan: OrgPlan): Record<string, boolean>;
|
|
112
|
+
/**
|
|
113
|
+
* A resolved quota read by its key — the reading core uses for a key a plugin
|
|
114
|
+
* owns, since core compiles without the plugin's type augmentation.
|
|
115
|
+
*
|
|
116
|
+
* ⚑ ABSENT IS NOTHING INCLUDED. A key no plugin declares, or a value that is
|
|
117
|
+
* not a number, reads as `0`: every gate that compares usage against it
|
|
118
|
+
* refuses, and every meter drawn from it shows full. That is the same
|
|
119
|
+
* direction `plugin-org-capacity` answers an unknown capacity in. Reading
|
|
120
|
+
* absence as `UNLIMITED` would be a plan giving away what nobody declared it
|
|
121
|
+
* sells.
|
|
122
|
+
*/
|
|
123
|
+
export declare function planQuotaOf(entitlements: object, key: string): number;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ /**
|
|
17
|
+
* WHAT EACH PLAN INCLUDES OF A PLUGIN'S OWN KEYS (AGL-3080).
|
|
18
|
+
*
|
|
19
|
+
* `plugin-entitlement-keys` gives a plugin the TYPE of a key it owns, by
|
|
20
|
+
* augmentation, so `OrgEntitlements` and `OrgFeatureFlags` carry the key
|
|
21
|
+
* without core naming it. That leaves the VALUE: what Free, Starter and every
|
|
22
|
+
* other plan include of it. A key that only a plugin's type declares still
|
|
23
|
+
* needs a figure in every row of `PLAN_ENTITLEMENTS`, and core writing the
|
|
24
|
+
* figure is core naming the key.
|
|
25
|
+
*
|
|
26
|
+
* So the owning plugin declares the figure per plan, beside the reasoning
|
|
27
|
+
* that sized it, and core composes it into the plan table. A plan row in
|
|
28
|
+
* `PLAN_ENTITLEMENTS` still answers every key the platform sells, at the same
|
|
29
|
+
* number — `/pricing`, the plan comparison, the pricing-table generator and
|
|
30
|
+
* every quota gate read the composed table and cannot tell the difference.
|
|
31
|
+
*
|
|
32
|
+
* ## Compiled, never registered
|
|
33
|
+
*
|
|
34
|
+
* The readers include the published pricing tables, which a generator builds
|
|
35
|
+
* from `PLAN_ENTITLEMENTS` with no plugin loaded, and the customer's plan
|
|
36
|
+
* comparison, which renders before any plugin surface does. A registry one of
|
|
37
|
+
* them had not filled would publish a plan without the band — a missing row on
|
|
38
|
+
* the price list, or a quota gate reading nothing — with nothing red. So a
|
|
39
|
+
* first-party plugin names a function under `register.planEntitlements` in
|
|
40
|
+
* `plugins.config.json`; `tools/scripts/generate-plugin-manifests.mjs` loads
|
|
41
|
+
* `${package}/plan-entitlements`, calls it, validates the answer and compiles
|
|
42
|
+
* it into `first-party-plugins.generated.ts` as data. There is no runtime
|
|
43
|
+
* registrar, for the reason `plugin-org-capacity` gives: a registrar nothing
|
|
44
|
+
* can safely call is worse than none.
|
|
45
|
+
*
|
|
46
|
+
* ## What a missing figure means
|
|
47
|
+
*
|
|
48
|
+
* A declaration names every plan: the generated rows are typed
|
|
49
|
+
* `Record<OrgPlan, …>`, so a plan left out does not compile. A key nobody
|
|
50
|
+
* declares is absent from the table, and each reader answers absence in the
|
|
51
|
+
* closed direction — a quota reads as nothing included, a feature as off.
|
|
52
|
+
* `planQuotaOf` below is that reading, and it never answers "unlimited" or
|
|
53
|
+
* "free" for a key that has no figure.
|
|
54
|
+
*
|
|
55
|
+
* ## One key, one owner, and never one of core's
|
|
56
|
+
*
|
|
57
|
+
* The generator refuses a key two plugins declare. A key the platform's own
|
|
58
|
+
* rows already carry is refused by `plan-entitlements.spec.ts` rather than
|
|
59
|
+
* here, because the generator cannot read core's rows without loading the
|
|
60
|
+
* module that imports this one; the composition keeps core's figure either
|
|
61
|
+
* way, so a collision can shadow nothing a customer is charged.
|
|
62
|
+
*/ import { PLUGIN_PLAN_FEATURES_DECLARED, PLUGIN_PLAN_QUOTAS_DECLARED } from "./first-party-plugins.generated.js";
|
|
63
|
+
/** Every declared quota, in catalog order. */ export function pluginPlanQuotas() {
|
|
64
|
+
return PLUGIN_PLAN_QUOTAS_DECLARED;
|
|
65
|
+
}
|
|
66
|
+
/** Every declared feature, in catalog order. */ export function pluginPlanFeatures() {
|
|
67
|
+
return PLUGIN_PLAN_FEATURES_DECLARED;
|
|
68
|
+
}
|
|
69
|
+
/** The plugin that declared a quota or feature key, or `null`. */ export function pluginPlanEntitlementOwner(key) {
|
|
70
|
+
var _ref, _ref1;
|
|
71
|
+
var _PLUGIN_PLAN_QUOTAS_DECLARED_find, _PLUGIN_PLAN_FEATURES_DECLARED_find;
|
|
72
|
+
return (_ref = (_ref1 = (_PLUGIN_PLAN_QUOTAS_DECLARED_find = PLUGIN_PLAN_QUOTAS_DECLARED.find((one)=>one.key === key)) == null ? void 0 : _PLUGIN_PLAN_QUOTAS_DECLARED_find.pluginId) != null ? _ref1 : (_PLUGIN_PLAN_FEATURES_DECLARED_find = PLUGIN_PLAN_FEATURES_DECLARED.find((one)=>one.key === key)) == null ? void 0 : _PLUGIN_PLAN_FEATURES_DECLARED_find.pluginId) != null ? _ref : null;
|
|
73
|
+
}
|
|
74
|
+
/** The declared quotas' figures for one plan, keyed by the stored key. */ export function pluginPlanQuotaRow(plan) {
|
|
75
|
+
return Object.fromEntries(PLUGIN_PLAN_QUOTAS_DECLARED.map((one)=>[
|
|
76
|
+
one.key,
|
|
77
|
+
one.byPlan[plan]
|
|
78
|
+
]));
|
|
79
|
+
}
|
|
80
|
+
/** The declared features' answers for one plan, keyed by the stored key. */ export function pluginPlanFeatureRow(plan) {
|
|
81
|
+
return Object.fromEntries(PLUGIN_PLAN_FEATURES_DECLARED.map((one)=>[
|
|
82
|
+
one.key,
|
|
83
|
+
one.byPlan[plan]
|
|
84
|
+
]));
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* A resolved quota read by its key — the reading core uses for a key a plugin
|
|
88
|
+
* owns, since core compiles without the plugin's type augmentation.
|
|
89
|
+
*
|
|
90
|
+
* ⚑ ABSENT IS NOTHING INCLUDED. A key no plugin declares, or a value that is
|
|
91
|
+
* not a number, reads as `0`: every gate that compares usage against it
|
|
92
|
+
* refuses, and every meter drawn from it shows full. That is the same
|
|
93
|
+
* direction `plugin-org-capacity` answers an unknown capacity in. Reading
|
|
94
|
+
* absence as `UNLIMITED` would be a plan giving away what nobody declared it
|
|
95
|
+
* sells.
|
|
96
|
+
*/ export function planQuotaOf(entitlements, key) {
|
|
97
|
+
const value = entitlements[key];
|
|
98
|
+
return typeof value === 'number' && !Number.isNaN(value) ? value : 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
//# sourceMappingURL=plugin-plan-entitlements.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/plugin-manager/plugin-plan-entitlements.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * WHAT EACH PLAN INCLUDES OF A PLUGIN'S OWN KEYS (AGL-3080).\n *\n * `plugin-entitlement-keys` gives a plugin the TYPE of a key it owns, by\n * augmentation, so `OrgEntitlements` and `OrgFeatureFlags` carry the key\n * without core naming it. That leaves the VALUE: what Free, Starter and every\n * other plan include of it. A key that only a plugin's type declares still\n * needs a figure in every row of `PLAN_ENTITLEMENTS`, and core writing the\n * figure is core naming the key.\n *\n * So the owning plugin declares the figure per plan, beside the reasoning\n * that sized it, and core composes it into the plan table. A plan row in\n * `PLAN_ENTITLEMENTS` still answers every key the platform sells, at the same\n * number — `/pricing`, the plan comparison, the pricing-table generator and\n * every quota gate read the composed table and cannot tell the difference.\n *\n * ## Compiled, never registered\n *\n * The readers include the published pricing tables, which a generator builds\n * from `PLAN_ENTITLEMENTS` with no plugin loaded, and the customer's plan\n * comparison, which renders before any plugin surface does. A registry one of\n * them had not filled would publish a plan without the band — a missing row on\n * the price list, or a quota gate reading nothing — with nothing red. So a\n * first-party plugin names a function under `register.planEntitlements` in\n * `plugins.config.json`; `tools/scripts/generate-plugin-manifests.mjs` loads\n * `${package}/plan-entitlements`, calls it, validates the answer and compiles\n * it into `first-party-plugins.generated.ts` as data. There is no runtime\n * registrar, for the reason `plugin-org-capacity` gives: a registrar nothing\n * can safely call is worse than none.\n *\n * ## What a missing figure means\n *\n * A declaration names every plan: the generated rows are typed\n * `Record<OrgPlan, …>`, so a plan left out does not compile. A key nobody\n * declares is absent from the table, and each reader answers absence in the\n * closed direction — a quota reads as nothing included, a feature as off.\n * `planQuotaOf` below is that reading, and it never answers \"unlimited\" or\n * \"free\" for a key that has no figure.\n *\n * ## One key, one owner, and never one of core's\n *\n * The generator refuses a key two plugins declare. A key the platform's own\n * rows already carry is refused by `plan-entitlements.spec.ts` rather than\n * here, because the generator cannot read core's rows without loading the\n * module that imports this one; the composition keeps core's figure either\n * way, so a collision can shadow nothing a customer is charged.\n */\n\nimport type { OrgPlan } from '../foundation'\nimport {\n PLUGIN_PLAN_FEATURES_DECLARED,\n PLUGIN_PLAN_QUOTAS_DECLARED,\n} from './first-party-plugins.generated'\n\n/** A numeric entitlement a plugin owns: a band, a daily pace, a take rate. */\nexport interface PluginPlanQuotaDeclaration {\n /** The stored key, exactly as `OrgEntitlements` and an override spell it. */\n key: string\n /** What a staff page calls it. */\n label: string\n /**\n * What each plan includes. `Infinity` is `UNLIMITED`; every other value is\n * a finite, non-negative number.\n */\n byPlan: Readonly<Record<OrgPlan, number>>\n /**\n * A PRICE rather than a cap — a percentage of a sale — so an uncapped plan\n * comp must never lift it (`PRICE_ENTITLEMENT_KEYS`).\n */\n price?: boolean\n}\n\n/** A boolean gate a plugin owns. */\nexport interface PluginPlanFeatureDeclaration {\n /** The stored key, exactly as `OrgFeatureFlags` and an override spell it. */\n key: string\n label: string\n byPlan: Readonly<Record<OrgPlan, boolean>>\n}\n\n/** What a plugin's `planEntitlements` function answers. */\nexport interface PluginPlanEntitlementsDeclaration {\n quotas?: readonly PluginPlanQuotaDeclaration[]\n features?: readonly PluginPlanFeatureDeclaration[]\n}\n\n/** A quota declaration with the plugin that made it. */\nexport type ResolvedPluginPlanQuota = PluginPlanQuotaDeclaration & {\n pluginId: string\n}\n\n/** A feature declaration with the plugin that made it. */\nexport type ResolvedPluginPlanFeature = PluginPlanFeatureDeclaration & {\n pluginId: string\n}\n\n/** Every declared quota, in catalog order. */\nexport function pluginPlanQuotas(): readonly ResolvedPluginPlanQuota[] {\n return PLUGIN_PLAN_QUOTAS_DECLARED\n}\n\n/** Every declared feature, in catalog order. */\nexport function pluginPlanFeatures(): readonly ResolvedPluginPlanFeature[] {\n return PLUGIN_PLAN_FEATURES_DECLARED\n}\n\n/** The plugin that declared a quota or feature key, or `null`. */\nexport function pluginPlanEntitlementOwner(key: string): string | null {\n return (\n PLUGIN_PLAN_QUOTAS_DECLARED.find((one) => one.key === key)?.pluginId ??\n PLUGIN_PLAN_FEATURES_DECLARED.find((one) => one.key === key)?.pluginId ??\n null\n )\n}\n\n/** The declared quotas' figures for one plan, keyed by the stored key. */\nexport function pluginPlanQuotaRow(plan: OrgPlan): Record<string, number> {\n return Object.fromEntries(\n PLUGIN_PLAN_QUOTAS_DECLARED.map((one) => [one.key, one.byPlan[plan]]),\n )\n}\n\n/** The declared features' answers for one plan, keyed by the stored key. */\nexport function pluginPlanFeatureRow(plan: OrgPlan): Record<string, boolean> {\n return Object.fromEntries(\n PLUGIN_PLAN_FEATURES_DECLARED.map((one) => [one.key, one.byPlan[plan]]),\n )\n}\n\n/**\n * A resolved quota read by its key — the reading core uses for a key a plugin\n * owns, since core compiles without the plugin's type augmentation.\n *\n * ⚑ ABSENT IS NOTHING INCLUDED. A key no plugin declares, or a value that is\n * not a number, reads as `0`: every gate that compares usage against it\n * refuses, and every meter drawn from it shows full. That is the same\n * direction `plugin-org-capacity` answers an unknown capacity in. Reading\n * absence as `UNLIMITED` would be a plan giving away what nobody declared it\n * sells.\n */\nexport function planQuotaOf(entitlements: object, key: string): number {\n const value = (entitlements as Record<string, unknown>)[key]\n return typeof value === 'number' && !Number.isNaN(value) ? value : 0\n}\n"],"names":["PLUGIN_PLAN_FEATURES_DECLARED","PLUGIN_PLAN_QUOTAS_DECLARED","pluginPlanQuotas","pluginPlanFeatures","pluginPlanEntitlementOwner","key","find","one","pluginId","pluginPlanQuotaRow","plan","Object","fromEntries","map","byPlan","pluginPlanFeatureRow","planQuotaOf","entitlements","value","Number","isNaN"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8CC,GAGD,SACEA,6BAA6B,EAC7BC,2BAA2B,QACtB,qCAAiC;AA4CxC,4CAA4C,GAC5C,OAAO,SAASC;IACd,OAAOD;AACT;AAEA,8CAA8C,GAC9C,OAAO,SAASE;IACd,OAAOH;AACT;AAEA,gEAAgE,GAChE,OAAO,SAASI,2BAA2BC,GAAW;QAElDJ;QAAAA,mCACAD;IAFF,QACEC,iBAAAA,oCAAAA,4BAA4BK,IAAI,CAAC,CAACC,MAAQA,IAAIF,GAAG,KAAKA,yBAAtDJ,kCAA4DO,QAAQ,qBACpER,sCAAAA,8BAA8BM,IAAI,CAAC,CAACC,MAAQA,IAAIF,GAAG,KAAKA,yBAAxDL,oCAA8DQ,QAAQ,YADtEP,OAEA;AAEJ;AAEA,wEAAwE,GACxE,OAAO,SAASQ,mBAAmBC,IAAa;IAC9C,OAAOC,OAAOC,WAAW,CACvBX,4BAA4BY,GAAG,CAAC,CAACN,MAAQ;YAACA,IAAIF,GAAG;YAAEE,IAAIO,MAAM,CAACJ,KAAK;SAAC;AAExE;AAEA,0EAA0E,GAC1E,OAAO,SAASK,qBAAqBL,IAAa;IAChD,OAAOC,OAAOC,WAAW,CACvBZ,8BAA8Ba,GAAG,CAAC,CAACN,MAAQ;YAACA,IAAIF,GAAG;YAAEE,IAAIO,MAAM,CAACJ,KAAK;SAAC;AAE1E;AAEA;;;;;;;;;;CAUC,GACD,OAAO,SAASM,YAAYC,YAAoB,EAAEZ,GAAW;IAC3D,MAAMa,QAAQ,AAACD,YAAwC,CAACZ,IAAI;IAC5D,OAAO,OAAOa,UAAU,YAAY,CAACC,OAAOC,KAAK,CAACF,SAASA,QAAQ;AACrE"}
|