@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
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
17
|
-
import { diffOverride, isEmptyOverride, overrideWriteValue, readArtifactOverride, resolveOverride } from "./
|
|
18
|
-
import { resolveSiteTheme, themeArtifactContent } from "./
|
|
17
|
+
import { diffOverride, isEmptyOverride, overrideWriteValue, readArtifactOverride, resolveOverride } from "./artifact-overrides.js";
|
|
18
|
+
import { resolveSiteTheme, themeArtifactContent } from "./site-theme.js";
|
|
19
19
|
/**
|
|
20
20
|
* A site's theme library (AGL-3404): the themes a site can switch between,
|
|
21
21
|
* and the rule that switching, editing and saving never destroy one.
|
|
@@ -72,7 +72,14 @@ const KINDS = [
|
|
|
72
72
|
* leaves it. Before the library a site had exactly one theme of its own, so
|
|
73
73
|
* a fixed id cannot collide with another.
|
|
74
74
|
*/ export const SITE_THEME_ENTRY_ID = 'site-theme';
|
|
75
|
-
/**
|
|
75
|
+
/**
|
|
76
|
+
* The default's name, wherever the library names it.
|
|
77
|
+
*
|
|
78
|
+
* Not "Material UI": the platform default keeps MUI's palette but draws it in
|
|
79
|
+
* the platform's own type and component defaults, and stock Material UI is a
|
|
80
|
+
* built-in theme of its own (AGL-3422). A console shows the operator's brand
|
|
81
|
+
* name in its place.
|
|
82
|
+
*/ export const DEFAULT_THEME_NAME = 'Platform default';
|
|
76
83
|
/** A preset's entry id, which holds only its stash. */ export function presetEntryId(presetId) {
|
|
77
84
|
return `preset--${presetId.replace(/[/]/g, '_')}`;
|
|
78
85
|
}
|
|
@@ -98,7 +105,9 @@ function hasContent(theme) {
|
|
|
98
105
|
return {
|
|
99
106
|
kind: stored['kind'],
|
|
100
107
|
id: stored['id'],
|
|
101
|
-
|
|
108
|
+
// The default is always named by the constant: a selection stored
|
|
109
|
+
// before AGL-3422 calls it "Material UI", which is now another theme.
|
|
110
|
+
name: stored['kind'] === 'default' ? DEFAULT_THEME_NAME : typeof stored['name'] === 'string' && stored['name'] ? stored['name'] : 'Theme'
|
|
102
111
|
};
|
|
103
112
|
}
|
|
104
113
|
const listingId = host == null ? void 0 : (_host_themeInstalledFrom = host.themeInstalledFrom) == null ? void 0 : _host_themeInstalledFrom.listingId;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/theme-library.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 type { HostTheme } from '@aglyn/shared-data-types'\nimport {\n diffOverride,\n isEmptyOverride,\n overrideWriteValue,\n readArtifactOverride,\n resolveOverride,\n} from './marketplace-overrides'\nimport {\n resolveSiteTheme,\n themeArtifactContent,\n type ThemeHostDocument,\n} from './marketplace-theme'\n\n/**\n * A site's theme library (AGL-3404): the themes a site can switch between,\n * and the rule that switching, editing and saving never destroy one.\n *\n * ## Three layers, one of them picked\n *\n * The site renders `theme ⊕ themeOverride` (`resolveSiteTheme`), exactly as\n * it did before there was a library. What the library adds is WHERE `theme`\n * came from, named by `themeSelection`:\n *\n * - `default` — the platform default. `theme` is empty.\n * - `preset` — a built-in theme a plugin contributes. `theme` is a copy.\n * - `custom` — one of the site's own saved themes, kept in the library.\n * - `installed` — a marketplace theme, kept in the library with the\n * provenance an update needs.\n *\n * Every edit is an override patch over the picked theme and never a write to\n * it, so \"Restore\" is deleting the patch and the theme it restores to is\n * still exactly the one that was picked. \"Save as custom theme\" copies the\n * resolved result into a new library entry; the theme it started from stays\n * as it was.\n *\n * ## Switching keeps each theme's own edits\n *\n * Leaving a theme stashes its override on its library entry, and coming back\n * restores it — so trying another theme is not a way to lose work. A preset\n * or the default has no content to keep, so its entry holds only the stash.\n *\n * ## The site's own settings travel with the site\n *\n * `darkScheme` is a decision about the site's content, not about a design\n * (`THEME_ARTIFACT_FIELDS` says the same for publishing), so it survives every\n * switch, save and restore: whichever theme is picked, a site that switched\n * dark off stays light.\n *\n * Pure: the console route and the marketplace install route both plan here\n * and write the plan in their own transaction, so neither can file a switch\n * differently from the other.\n */\n\n/** The host subcollection the library lives in. */\nexport const THEME_LIBRARY_COLLECTION = 'themes'\n\n/**\n * The most custom themes one site keeps. A client can read the library, so an\n * unbounded one is an unbounded read on every visit to the theme page.\n */\nexport const THEME_LIBRARY_MAX_CUSTOM = 25\n\n/** The longest name a saved theme takes. */\nexport const THEME_NAME_MAX = 60\n\nexport type ThemeLibraryKind = 'default' | 'preset' | 'custom' | 'installed'\n\nconst KINDS: readonly ThemeLibraryKind[] = [\n 'default',\n 'preset',\n 'custom',\n 'installed',\n]\n\n/** What `themeSelection` on a host names. */\nexport interface HostThemeSelection {\n kind: ThemeLibraryKind\n /** The library entry id (or the preset's entry id). */\n id: string\n /** Shown in the picker; a copy, so a renamed entry renames the selection too. */\n name: string\n}\n\n/** A document in `hosts/{hostId}/themes`. */\nexport interface ThemeLibraryEntry {\n kind: ThemeLibraryKind\n name: string\n /** The theme itself, for `custom` and `installed`. Never edited in place by the editor. */\n theme?: HostTheme | null\n /** The override stashed while this theme is not the picked one. */\n override?: unknown\n /** Marketplace provenance, for `installed` — what `themeInstalledFrom` is restored from. */\n installedFrom?: Record<string, unknown> | null\n createdAt?: unknown\n updatedAt?: unknown\n}\n\n/** The entry id the platform default's stash lives under. */\nexport const DEFAULT_THEME_ENTRY_ID = 'default'\n\n/**\n * The entry id a pre-library site's own theme is filed under when it first\n * leaves it. Before the library a site had exactly one theme of its own, so\n * a fixed id cannot collide with another.\n */\nexport const SITE_THEME_ENTRY_ID = 'site-theme'\n\n/** The default's name when nothing else names it. */\nexport const DEFAULT_THEME_NAME = 'Material UI'\n\n/** A preset's entry id, which holds only its stash. */\nexport function presetEntryId(presetId: string): string {\n return `preset--${presetId.replace(/[/]/g, '_')}`\n}\n\n/** A marketplace theme's entry id: one per listing, so reinstalling updates it. */\nexport function installedEntryId(listingId: string): string {\n return `installed--${listingId.replace(/[/]/g, '_')}`\n}\n\n/** A host document as the library reads it. */\nexport interface ThemeLibraryHost extends ThemeHostDocument {\n themeSelection?: unknown\n themeInstalledFrom?:\n | ({ sha256?: string | null; listingId?: string; name?: string } & Record<\n string,\n unknown\n >)\n | null\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction hasContent(theme: HostTheme | null | undefined): theme is HostTheme {\n return Boolean(theme && Object.keys(theme).length)\n}\n\n/**\n * The theme a site has picked.\n *\n * A site from before the library has no `themeSelection`, and reads as what\n * it was: a marketplace theme, its own theme, or the default. That is what\n * lets the library ship without touching a single existing host document.\n */\nexport function readThemeSelection(\n host: ThemeLibraryHost | null | undefined,\n): HostThemeSelection {\n const stored = host?.themeSelection\n if (\n isRecord(stored) &&\n KINDS.includes(stored['kind'] as ThemeLibraryKind) &&\n typeof stored['id'] === 'string' &&\n stored['id']\n ) {\n return {\n kind: stored['kind'] as ThemeLibraryKind,\n id: stored['id'],\n name:\n typeof stored['name'] === 'string' && stored['name']\n ? stored['name']\n : stored['kind'] === 'default'\n ? DEFAULT_THEME_NAME\n : 'Theme',\n }\n }\n const listingId = host?.themeInstalledFrom?.listingId\n if (listingId) {\n const name = host?.themeInstalledFrom?.name\n return {\n kind: 'installed',\n id: installedEntryId(listingId),\n name: typeof name === 'string' && name ? name : 'Marketplace theme',\n }\n }\n if (hasContent(host?.theme)) {\n return { kind: 'custom', id: SITE_THEME_ENTRY_ID, name: 'Site theme' }\n }\n return {\n kind: 'default',\n id: DEFAULT_THEME_ENTRY_ID,\n name: DEFAULT_THEME_NAME,\n }\n}\n\n/** A name as stored: trimmed, bounded, and never empty. */\nexport function normalizeThemeName(name: unknown): string | null {\n if (typeof name !== 'string') return null\n const trimmed = name.replace(/\\s+/g, ' ').trim()\n if (!trimmed) return null\n return trimmed.slice(0, THEME_NAME_MAX)\n}\n\n/** Marks a field for deletion; the route writing the plan maps it to its store's delete. */\nexport const THEME_FIELD_DELETE = '__aglynThemeFieldDelete'\n\nexport type ThemeLibraryEntryWrite =\n | { id: string; op: 'create'; data: ThemeLibraryEntry }\n | { id: string; op: 'update'; data: Record<string, unknown> }\n | { id: string; op: 'delete' }\n\nexport type ThemeLibraryPlan =\n | {\n ok: true\n /**\n * Host fields to replace WHOLESALE (`update`, never a deep merge: a\n * merged override is the union of two patches, and a merged theme keeps\n * the tokens of the one it replaced).\n */\n host: Record<string, unknown>\n entries: ThemeLibraryEntryWrite[]\n /** The theme picked once the plan is written. */\n selection: HostThemeSelection\n }\n | { ok: false; status: number; error: string }\n\nexport type ThemeLibraryTarget =\n | { kind: 'default' }\n /** A plugin's theme, sent by the console that listed it. */\n | { kind: 'preset'; id: string; name: string; theme: HostTheme }\n | { kind: 'custom' | 'installed'; id: string }\n\nexport type ThemeLibraryAction =\n | { action: 'select'; target: ThemeLibraryTarget }\n | { action: 'save-as'; name: string }\n | { action: 'update' }\n | { action: 'restore' }\n | { action: 'rename'; id: string; name: string }\n | { action: 'delete'; id: string }\n | {\n action: 'install'\n listingId: string\n name: string\n theme: HostTheme\n installedFrom: Record<string, unknown>\n }\n\n/**\n * The override to store for a theme showing `edited` over `base`, or the\n * delete marker when they are the same.\n */\nfunction overrideValue(\n base: HostTheme,\n edited: HostTheme,\n baseSha256: string | null,\n): unknown {\n const patch = diffOverride(base, edited)\n const value = overrideWriteValue(patch, baseSha256)\n return value && !isEmptyOverride(value.patch) ? value : THEME_FIELD_DELETE\n}\n\n/** The site's own setting carried onto another theme. */\nfunction withSiteSettings(theme: HostTheme, from: HostTheme | undefined): HostTheme {\n const next = { ...theme }\n if (from?.darkScheme === 'off') next.darkScheme = 'off'\n else delete next.darkScheme\n return next\n}\n\n/** A stash as it resolves over the theme it belongs to. */\nfunction resolveStash(base: HostTheme, stash: unknown): HostTheme {\n const read = readArtifactOverride({ overrides: stash })\n return read ? resolveOverride<HostTheme>(base, read.patch) : base\n}\n\nfunction sha(installedFrom: unknown): string | null {\n return isRecord(installedFrom) && typeof installedFrom['sha256'] === 'string'\n ? installedFrom['sha256']\n : null\n}\n\n/**\n * Files the theme being left: its override goes onto its entry, and a theme\n * that exists nowhere but on the host (a pre-library site's own theme, or a\n * marketplace install from before the library) gets an entry of its own\n * first, so it is still in the list to come back to.\n *\n * `override` is what to stash — the live one when switching, none when the\n * edits have just moved into a new theme.\n */\nfunction fileCurrent(\n host: ThemeLibraryHost,\n current: HostThemeSelection,\n entries: Readonly<Record<string, ThemeLibraryEntry>>,\n override: unknown,\n): ThemeLibraryEntryWrite[] {\n const stash = override === undefined ? THEME_FIELD_DELETE : override\n if (entries[current.id]) {\n return [{ id: current.id, op: 'update', data: { override: stash } }]\n }\n // The default and a preset have no content to keep, so with nothing to\n // stash there is nothing to file.\n if (\n stash === THEME_FIELD_DELETE &&\n (current.kind === 'default' || current.kind === 'preset')\n ) {\n return []\n }\n const entry: ThemeLibraryEntry = { kind: current.kind, name: current.name }\n if (current.kind === 'custom' || current.kind === 'installed') {\n entry.theme = themeArtifactContent(host.theme)\n }\n if (current.kind === 'installed' && host.themeInstalledFrom) {\n entry.installedFrom = host.themeInstalledFrom\n }\n if (stash !== THEME_FIELD_DELETE) entry.override = stash\n return [{ id: current.id, op: 'create', data: entry }]\n}\n\n/** Host fields that point the site at `selection` over `base`. */\nfunction pointAt(\n selection: HostThemeSelection,\n base: HostTheme,\n override: unknown,\n installedFrom: unknown,\n): Record<string, unknown> {\n return {\n theme: hasContent(base) ? base : THEME_FIELD_DELETE,\n themeOverride: override,\n themeSelection: selection,\n themeInstalledFrom:\n selection.kind === 'installed' && installedFrom\n ? installedFrom\n : THEME_FIELD_DELETE,\n // The library is the way back now: every theme a site has left is in it,\n // edits included. A `themeReplaced` left behind would offer a second,\n // older \"previous theme\" that restores around the library.\n themeReplaced: THEME_FIELD_DELETE,\n }\n}\n\n/**\n * Plans one library action against the host document and its library as\n * read in the same transaction.\n *\n * `newId` mints a library entry id for a new custom theme.\n */\nexport function planThemeLibraryAction(input: {\n host: ThemeLibraryHost | null | undefined\n entries: Readonly<Record<string, ThemeLibraryEntry>>\n action: ThemeLibraryAction\n newId: () => string\n}): ThemeLibraryPlan {\n const host: ThemeLibraryHost = input.host ?? {}\n const { entries, action } = input\n const current = readThemeSelection(host)\n const resolved = resolveSiteTheme(host) ?? {}\n\n switch (action.action) {\n case 'select':\n return planSelect(host, current, resolved, entries, action.target)\n\n case 'install': {\n const id = installedEntryId(action.listingId)\n const name = normalizeThemeName(action.name) ?? 'Marketplace theme'\n const theme = themeArtifactContent(action.theme)\n const selection: HostThemeSelection = { kind: 'installed', id, name }\n if (current.kind === 'installed' && current.id === id) {\n // An update of the theme already picked. The override stays exactly\n // as stored — including the hash it was written against, which is\n // how the editor knows to say an override predates this version.\n return {\n ok: true,\n host: {\n theme,\n themeInstalledFrom: action.installedFrom,\n themeSelection: selection,\n },\n entries: [\n entries[id]\n ? {\n id,\n op: 'update',\n data: { theme, installedFrom: action.installedFrom, name },\n }\n : {\n id,\n op: 'create',\n data: {\n kind: 'installed',\n name,\n theme,\n installedFrom: action.installedFrom,\n },\n },\n ],\n selection,\n }\n }\n const stash = entries[id]?.override\n const edited = withSiteSettings(resolveStash(theme, stash), resolved)\n return {\n ok: true,\n host: pointAt(\n selection,\n theme,\n overrideValue(theme, edited, sha(action.installedFrom)),\n action.installedFrom,\n ),\n entries: [\n ...fileCurrent(host, current, entries, host.themeOverride),\n entries[id]\n ? {\n id,\n op: 'update',\n data: {\n theme,\n installedFrom: action.installedFrom,\n name,\n override: THEME_FIELD_DELETE,\n },\n }\n : {\n id,\n op: 'create',\n data: {\n kind: 'installed',\n name,\n theme,\n installedFrom: action.installedFrom,\n },\n },\n ],\n selection,\n }\n }\n\n case 'save-as': {\n const name = normalizeThemeName(action.name)\n if (!name) {\n return { ok: false, status: 400, error: 'Give the theme a name.' }\n }\n const customCount = Object.values(entries).filter(\n (entry) => entry.kind === 'custom',\n ).length\n if (customCount >= THEME_LIBRARY_MAX_CUSTOM) {\n return {\n ok: false,\n status: 409,\n error:\n `A site keeps up to ${THEME_LIBRARY_MAX_CUSTOM} custom themes. ` +\n 'Delete one you no longer use first.',\n }\n }\n const id = input.newId()\n const theme = themeArtifactContent(resolved)\n const selection: HostThemeSelection = { kind: 'custom', id, name }\n return {\n ok: true,\n host: pointAt(\n selection,\n theme,\n overrideValue(theme, withSiteSettings(theme, resolved), null),\n null,\n ),\n entries: [\n // The theme this started from stays as it was picked: the edits\n // now live in the new theme, not on top of the old one.\n ...fileCurrent(host, current, entries, undefined),\n { id, op: 'create', data: { kind: 'custom', name, theme } },\n ],\n selection,\n }\n }\n\n case 'update': {\n if (current.kind !== 'custom') {\n return {\n ok: false,\n status: 409,\n error:\n 'Only your own themes can be updated. Save your changes as a ' +\n 'custom theme instead.',\n }\n }\n const theme = themeArtifactContent(resolved)\n const override = overrideValue(\n theme,\n withSiteSettings(theme, resolved),\n null,\n )\n return {\n ok: true,\n host: {\n theme: hasContent(theme) ? theme : THEME_FIELD_DELETE,\n themeOverride: override,\n themeSelection: current,\n },\n entries: [\n entries[current.id]\n ? { id: current.id, op: 'update', data: { theme } }\n : {\n id: current.id,\n op: 'create',\n data: { kind: 'custom', name: current.name, theme },\n },\n ],\n selection: current,\n }\n }\n\n case 'restore': {\n const base = host.theme ?? {}\n return {\n ok: true,\n host: {\n themeOverride: overrideValue(\n base,\n withSiteSettings(base, resolved),\n current.kind === 'installed' ? sha(host.themeInstalledFrom) : null,\n ),\n },\n entries: [],\n selection: current,\n }\n }\n\n case 'rename': {\n const name = normalizeThemeName(action.name)\n if (!name) {\n return { ok: false, status: 400, error: 'Give the theme a name.' }\n }\n const isLegacySiteTheme =\n action.id === SITE_THEME_ENTRY_ID &&\n current.id === SITE_THEME_ENTRY_ID &&\n !entries[SITE_THEME_ENTRY_ID]\n const entry = entries[action.id]\n if (!isLegacySiteTheme && entry?.kind !== 'custom') {\n return { ok: false, status: 404, error: 'Only your own themes can be renamed.' }\n }\n const renamedSelection =\n current.id === action.id ? { ...current, name } : null\n return {\n ok: true,\n host: renamedSelection ? { themeSelection: renamedSelection } : {},\n entries: isLegacySiteTheme\n ? [\n {\n id: action.id,\n op: 'create',\n data: {\n kind: 'custom',\n name,\n theme: themeArtifactContent(host.theme),\n },\n },\n ]\n : [{ id: action.id, op: 'update', data: { name } }],\n selection: renamedSelection ?? current,\n }\n }\n\n case 'delete': {\n const entry = entries[action.id]\n if (!entry || (entry.kind !== 'custom' && entry.kind !== 'installed')) {\n return { ok: false, status: 404, error: 'There is no such theme to delete.' }\n }\n if (current.id === action.id) {\n return {\n ok: false,\n status: 409,\n error: 'This theme is in use. Pick another theme first, then delete it.',\n }\n }\n return {\n ok: true,\n host: {},\n entries: [{ id: action.id, op: 'delete' }],\n selection: current,\n }\n }\n }\n}\n\nfunction planSelect(\n host: ThemeLibraryHost,\n current: HostThemeSelection,\n resolved: HostTheme,\n entries: Readonly<Record<string, ThemeLibraryEntry>>,\n target: ThemeLibraryTarget,\n): ThemeLibraryPlan {\n let selection: HostThemeSelection\n let base: HostTheme\n let installedFrom: unknown = null\n if (target.kind === 'default') {\n selection = {\n kind: 'default',\n id: DEFAULT_THEME_ENTRY_ID,\n name: DEFAULT_THEME_NAME,\n }\n base = {}\n } else if (target.kind === 'preset') {\n const name = normalizeThemeName(target.name)\n if (!target.id || !name || !isRecord(target.theme)) {\n return { ok: false, status: 400, error: 'That theme could not be read.' }\n }\n selection = { kind: 'preset', id: presetEntryId(target.id), name }\n base = themeArtifactContent(target.theme)\n } else {\n const entry = entries[target.id]\n if (!entry || entry.kind !== target.kind) {\n return { ok: false, status: 404, error: 'That theme is not in this site’s library.' }\n }\n selection = { kind: entry.kind, id: target.id, name: entry.name }\n base = themeArtifactContent(entry.theme ?? {})\n installedFrom = entry.installedFrom ?? null\n }\n if (selection.id === current.id && selection.kind === current.kind) {\n return { ok: true, host: {}, entries: [], selection: current }\n }\n\n const stash = entries[selection.id]?.override\n const edited = withSiteSettings(resolveStash(base, stash), resolved)\n const writes: ThemeLibraryEntryWrite[] = fileCurrent(\n host,\n current,\n entries,\n host.themeOverride,\n )\n // Its stash is live again, so the entry stops holding a second copy.\n if (entries[selection.id]?.override !== undefined) {\n writes.push({\n id: selection.id,\n op: 'update',\n data: { override: THEME_FIELD_DELETE },\n })\n }\n return {\n ok: true,\n host: pointAt(\n selection,\n base,\n overrideValue(\n base,\n edited,\n selection.kind === 'installed' ? sha(installedFrom) : null,\n ),\n installedFrom,\n ),\n entries: writes,\n selection,\n }\n}\n\n/**\n * Whether the picked theme carries edits of this site's own — what \"Restore\"\n * and \"Update\" act on. The site's dark-scheme setting is not an edit to the\n * theme, so an override holding only that does not count.\n */\nexport function hasThemeEdits(host: ThemeLibraryHost | null | undefined): boolean {\n const read = readArtifactOverride({ overrides: host?.themeOverride })\n if (!read || isEmptyOverride(read.patch)) return false\n if (!isRecord(read.patch)) return true\n return Object.keys(read.patch).some((key) => key !== 'darkScheme')\n}\n"],"names":["diffOverride","isEmptyOverride","overrideWriteValue","readArtifactOverride","resolveOverride","resolveSiteTheme","themeArtifactContent","THEME_LIBRARY_COLLECTION","THEME_LIBRARY_MAX_CUSTOM","THEME_NAME_MAX","KINDS","DEFAULT_THEME_ENTRY_ID","SITE_THEME_ENTRY_ID","DEFAULT_THEME_NAME","presetEntryId","presetId","replace","installedEntryId","listingId","isRecord","value","Array","isArray","hasContent","theme","Boolean","Object","keys","length","readThemeSelection","host","stored","themeSelection","includes","kind","id","name","themeInstalledFrom","normalizeThemeName","trimmed","trim","slice","THEME_FIELD_DELETE","overrideValue","base","edited","baseSha256","patch","withSiteSettings","from","next","darkScheme","resolveStash","stash","read","overrides","sha","installedFrom","fileCurrent","current","entries","override","undefined","op","data","entry","pointAt","selection","themeOverride","themeReplaced","planThemeLibraryAction","input","action","resolved","planSelect","target","ok","status","error","customCount","values","filter","newId","isLegacySiteTheme","renamedSelection","writes","push","hasThemeEdits","some","key"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/theme-library.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 type { HostTheme } from '@aglyn/shared-data-types'\nimport {\n diffOverride,\n isEmptyOverride,\n overrideWriteValue,\n readArtifactOverride,\n resolveOverride,\n} from './artifact-overrides'\nimport {\n resolveSiteTheme,\n themeArtifactContent,\n type ThemeHostDocument,\n} from './site-theme'\n\n/**\n * A site's theme library (AGL-3404): the themes a site can switch between,\n * and the rule that switching, editing and saving never destroy one.\n *\n * ## Three layers, one of them picked\n *\n * The site renders `theme ⊕ themeOverride` (`resolveSiteTheme`), exactly as\n * it did before there was a library. What the library adds is WHERE `theme`\n * came from, named by `themeSelection`:\n *\n * - `default` — the platform default. `theme` is empty.\n * - `preset` — a built-in theme a plugin contributes. `theme` is a copy.\n * - `custom` — one of the site's own saved themes, kept in the library.\n * - `installed` — a marketplace theme, kept in the library with the\n * provenance an update needs.\n *\n * Every edit is an override patch over the picked theme and never a write to\n * it, so \"Restore\" is deleting the patch and the theme it restores to is\n * still exactly the one that was picked. \"Save as custom theme\" copies the\n * resolved result into a new library entry; the theme it started from stays\n * as it was.\n *\n * ## Switching keeps each theme's own edits\n *\n * Leaving a theme stashes its override on its library entry, and coming back\n * restores it — so trying another theme is not a way to lose work. A preset\n * or the default has no content to keep, so its entry holds only the stash.\n *\n * ## The site's own settings travel with the site\n *\n * `darkScheme` is a decision about the site's content, not about a design\n * (`THEME_ARTIFACT_FIELDS` says the same for publishing), so it survives every\n * switch, save and restore: whichever theme is picked, a site that switched\n * dark off stays light.\n *\n * Pure: the console route and the marketplace install route both plan here\n * and write the plan in their own transaction, so neither can file a switch\n * differently from the other.\n */\n\n/** The host subcollection the library lives in. */\nexport const THEME_LIBRARY_COLLECTION = 'themes'\n\n/**\n * The most custom themes one site keeps. A client can read the library, so an\n * unbounded one is an unbounded read on every visit to the theme page.\n */\nexport const THEME_LIBRARY_MAX_CUSTOM = 25\n\n/** The longest name a saved theme takes. */\nexport const THEME_NAME_MAX = 60\n\nexport type ThemeLibraryKind = 'default' | 'preset' | 'custom' | 'installed'\n\nconst KINDS: readonly ThemeLibraryKind[] = [\n 'default',\n 'preset',\n 'custom',\n 'installed',\n]\n\n/** What `themeSelection` on a host names. */\nexport interface HostThemeSelection {\n kind: ThemeLibraryKind\n /** The library entry id (or the preset's entry id). */\n id: string\n /** Shown in the picker; a copy, so a renamed entry renames the selection too. */\n name: string\n}\n\n/** A document in `hosts/{hostId}/themes`. */\nexport interface ThemeLibraryEntry {\n kind: ThemeLibraryKind\n name: string\n /** The theme itself, for `custom` and `installed`. Never edited in place by the editor. */\n theme?: HostTheme | null\n /** The override stashed while this theme is not the picked one. */\n override?: unknown\n /** Marketplace provenance, for `installed` — what `themeInstalledFrom` is restored from. */\n installedFrom?: Record<string, unknown> | null\n createdAt?: unknown\n updatedAt?: unknown\n}\n\n/** The entry id the platform default's stash lives under. */\nexport const DEFAULT_THEME_ENTRY_ID = 'default'\n\n/**\n * The entry id a pre-library site's own theme is filed under when it first\n * leaves it. Before the library a site had exactly one theme of its own, so\n * a fixed id cannot collide with another.\n */\nexport const SITE_THEME_ENTRY_ID = 'site-theme'\n\n/**\n * The default's name, wherever the library names it.\n *\n * Not \"Material UI\": the platform default keeps MUI's palette but draws it in\n * the platform's own type and component defaults, and stock Material UI is a\n * built-in theme of its own (AGL-3422). A console shows the operator's brand\n * name in its place.\n */\nexport const DEFAULT_THEME_NAME = 'Platform default'\n\n/** A preset's entry id, which holds only its stash. */\nexport function presetEntryId(presetId: string): string {\n return `preset--${presetId.replace(/[/]/g, '_')}`\n}\n\n/** A marketplace theme's entry id: one per listing, so reinstalling updates it. */\nexport function installedEntryId(listingId: string): string {\n return `installed--${listingId.replace(/[/]/g, '_')}`\n}\n\n/** A host document as the library reads it. */\nexport interface ThemeLibraryHost extends ThemeHostDocument {\n themeSelection?: unknown\n themeInstalledFrom?:\n | ({ sha256?: string | null; listingId?: string; name?: string } & Record<\n string,\n unknown\n >)\n | null\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction hasContent(theme: HostTheme | null | undefined): theme is HostTheme {\n return Boolean(theme && Object.keys(theme).length)\n}\n\n/**\n * The theme a site has picked.\n *\n * A site from before the library has no `themeSelection`, and reads as what\n * it was: a marketplace theme, its own theme, or the default. That is what\n * lets the library ship without touching a single existing host document.\n */\nexport function readThemeSelection(\n host: ThemeLibraryHost | null | undefined,\n): HostThemeSelection {\n const stored = host?.themeSelection\n if (\n isRecord(stored) &&\n KINDS.includes(stored['kind'] as ThemeLibraryKind) &&\n typeof stored['id'] === 'string' &&\n stored['id']\n ) {\n return {\n kind: stored['kind'] as ThemeLibraryKind,\n id: stored['id'],\n // The default is always named by the constant: a selection stored\n // before AGL-3422 calls it \"Material UI\", which is now another theme.\n name:\n stored['kind'] === 'default'\n ? DEFAULT_THEME_NAME\n : typeof stored['name'] === 'string' && stored['name']\n ? stored['name']\n : 'Theme',\n }\n }\n const listingId = host?.themeInstalledFrom?.listingId\n if (listingId) {\n const name = host?.themeInstalledFrom?.name\n return {\n kind: 'installed',\n id: installedEntryId(listingId),\n name: typeof name === 'string' && name ? name : 'Marketplace theme',\n }\n }\n if (hasContent(host?.theme)) {\n return { kind: 'custom', id: SITE_THEME_ENTRY_ID, name: 'Site theme' }\n }\n return {\n kind: 'default',\n id: DEFAULT_THEME_ENTRY_ID,\n name: DEFAULT_THEME_NAME,\n }\n}\n\n/** A name as stored: trimmed, bounded, and never empty. */\nexport function normalizeThemeName(name: unknown): string | null {\n if (typeof name !== 'string') return null\n const trimmed = name.replace(/\\s+/g, ' ').trim()\n if (!trimmed) return null\n return trimmed.slice(0, THEME_NAME_MAX)\n}\n\n/** Marks a field for deletion; the route writing the plan maps it to its store's delete. */\nexport const THEME_FIELD_DELETE = '__aglynThemeFieldDelete'\n\nexport type ThemeLibraryEntryWrite =\n | { id: string; op: 'create'; data: ThemeLibraryEntry }\n | { id: string; op: 'update'; data: Record<string, unknown> }\n | { id: string; op: 'delete' }\n\nexport type ThemeLibraryPlan =\n | {\n ok: true\n /**\n * Host fields to replace WHOLESALE (`update`, never a deep merge: a\n * merged override is the union of two patches, and a merged theme keeps\n * the tokens of the one it replaced).\n */\n host: Record<string, unknown>\n entries: ThemeLibraryEntryWrite[]\n /** The theme picked once the plan is written. */\n selection: HostThemeSelection\n }\n | { ok: false; status: number; error: string }\n\nexport type ThemeLibraryTarget =\n | { kind: 'default' }\n /** A plugin's theme, sent by the console that listed it. */\n | { kind: 'preset'; id: string; name: string; theme: HostTheme }\n | { kind: 'custom' | 'installed'; id: string }\n\nexport type ThemeLibraryAction =\n | { action: 'select'; target: ThemeLibraryTarget }\n | { action: 'save-as'; name: string }\n | { action: 'update' }\n | { action: 'restore' }\n | { action: 'rename'; id: string; name: string }\n | { action: 'delete'; id: string }\n | {\n action: 'install'\n listingId: string\n name: string\n theme: HostTheme\n installedFrom: Record<string, unknown>\n }\n\n/**\n * The override to store for a theme showing `edited` over `base`, or the\n * delete marker when they are the same.\n */\nfunction overrideValue(\n base: HostTheme,\n edited: HostTheme,\n baseSha256: string | null,\n): unknown {\n const patch = diffOverride(base, edited)\n const value = overrideWriteValue(patch, baseSha256)\n return value && !isEmptyOverride(value.patch) ? value : THEME_FIELD_DELETE\n}\n\n/** The site's own setting carried onto another theme. */\nfunction withSiteSettings(theme: HostTheme, from: HostTheme | undefined): HostTheme {\n const next = { ...theme }\n if (from?.darkScheme === 'off') next.darkScheme = 'off'\n else delete next.darkScheme\n return next\n}\n\n/** A stash as it resolves over the theme it belongs to. */\nfunction resolveStash(base: HostTheme, stash: unknown): HostTheme {\n const read = readArtifactOverride({ overrides: stash })\n return read ? resolveOverride<HostTheme>(base, read.patch) : base\n}\n\nfunction sha(installedFrom: unknown): string | null {\n return isRecord(installedFrom) && typeof installedFrom['sha256'] === 'string'\n ? installedFrom['sha256']\n : null\n}\n\n/**\n * Files the theme being left: its override goes onto its entry, and a theme\n * that exists nowhere but on the host (a pre-library site's own theme, or a\n * marketplace install from before the library) gets an entry of its own\n * first, so it is still in the list to come back to.\n *\n * `override` is what to stash — the live one when switching, none when the\n * edits have just moved into a new theme.\n */\nfunction fileCurrent(\n host: ThemeLibraryHost,\n current: HostThemeSelection,\n entries: Readonly<Record<string, ThemeLibraryEntry>>,\n override: unknown,\n): ThemeLibraryEntryWrite[] {\n const stash = override === undefined ? THEME_FIELD_DELETE : override\n if (entries[current.id]) {\n return [{ id: current.id, op: 'update', data: { override: stash } }]\n }\n // The default and a preset have no content to keep, so with nothing to\n // stash there is nothing to file.\n if (\n stash === THEME_FIELD_DELETE &&\n (current.kind === 'default' || current.kind === 'preset')\n ) {\n return []\n }\n const entry: ThemeLibraryEntry = { kind: current.kind, name: current.name }\n if (current.kind === 'custom' || current.kind === 'installed') {\n entry.theme = themeArtifactContent(host.theme)\n }\n if (current.kind === 'installed' && host.themeInstalledFrom) {\n entry.installedFrom = host.themeInstalledFrom\n }\n if (stash !== THEME_FIELD_DELETE) entry.override = stash\n return [{ id: current.id, op: 'create', data: entry }]\n}\n\n/** Host fields that point the site at `selection` over `base`. */\nfunction pointAt(\n selection: HostThemeSelection,\n base: HostTheme,\n override: unknown,\n installedFrom: unknown,\n): Record<string, unknown> {\n return {\n theme: hasContent(base) ? base : THEME_FIELD_DELETE,\n themeOverride: override,\n themeSelection: selection,\n themeInstalledFrom:\n selection.kind === 'installed' && installedFrom\n ? installedFrom\n : THEME_FIELD_DELETE,\n // The library is the way back now: every theme a site has left is in it,\n // edits included. A `themeReplaced` left behind would offer a second,\n // older \"previous theme\" that restores around the library.\n themeReplaced: THEME_FIELD_DELETE,\n }\n}\n\n/**\n * Plans one library action against the host document and its library as\n * read in the same transaction.\n *\n * `newId` mints a library entry id for a new custom theme.\n */\nexport function planThemeLibraryAction(input: {\n host: ThemeLibraryHost | null | undefined\n entries: Readonly<Record<string, ThemeLibraryEntry>>\n action: ThemeLibraryAction\n newId: () => string\n}): ThemeLibraryPlan {\n const host: ThemeLibraryHost = input.host ?? {}\n const { entries, action } = input\n const current = readThemeSelection(host)\n const resolved = resolveSiteTheme(host) ?? {}\n\n switch (action.action) {\n case 'select':\n return planSelect(host, current, resolved, entries, action.target)\n\n case 'install': {\n const id = installedEntryId(action.listingId)\n const name = normalizeThemeName(action.name) ?? 'Marketplace theme'\n const theme = themeArtifactContent(action.theme)\n const selection: HostThemeSelection = { kind: 'installed', id, name }\n if (current.kind === 'installed' && current.id === id) {\n // An update of the theme already picked. The override stays exactly\n // as stored — including the hash it was written against, which is\n // how the editor knows to say an override predates this version.\n return {\n ok: true,\n host: {\n theme,\n themeInstalledFrom: action.installedFrom,\n themeSelection: selection,\n },\n entries: [\n entries[id]\n ? {\n id,\n op: 'update',\n data: { theme, installedFrom: action.installedFrom, name },\n }\n : {\n id,\n op: 'create',\n data: {\n kind: 'installed',\n name,\n theme,\n installedFrom: action.installedFrom,\n },\n },\n ],\n selection,\n }\n }\n const stash = entries[id]?.override\n const edited = withSiteSettings(resolveStash(theme, stash), resolved)\n return {\n ok: true,\n host: pointAt(\n selection,\n theme,\n overrideValue(theme, edited, sha(action.installedFrom)),\n action.installedFrom,\n ),\n entries: [\n ...fileCurrent(host, current, entries, host.themeOverride),\n entries[id]\n ? {\n id,\n op: 'update',\n data: {\n theme,\n installedFrom: action.installedFrom,\n name,\n override: THEME_FIELD_DELETE,\n },\n }\n : {\n id,\n op: 'create',\n data: {\n kind: 'installed',\n name,\n theme,\n installedFrom: action.installedFrom,\n },\n },\n ],\n selection,\n }\n }\n\n case 'save-as': {\n const name = normalizeThemeName(action.name)\n if (!name) {\n return { ok: false, status: 400, error: 'Give the theme a name.' }\n }\n const customCount = Object.values(entries).filter(\n (entry) => entry.kind === 'custom',\n ).length\n if (customCount >= THEME_LIBRARY_MAX_CUSTOM) {\n return {\n ok: false,\n status: 409,\n error:\n `A site keeps up to ${THEME_LIBRARY_MAX_CUSTOM} custom themes. ` +\n 'Delete one you no longer use first.',\n }\n }\n const id = input.newId()\n const theme = themeArtifactContent(resolved)\n const selection: HostThemeSelection = { kind: 'custom', id, name }\n return {\n ok: true,\n host: pointAt(\n selection,\n theme,\n overrideValue(theme, withSiteSettings(theme, resolved), null),\n null,\n ),\n entries: [\n // The theme this started from stays as it was picked: the edits\n // now live in the new theme, not on top of the old one.\n ...fileCurrent(host, current, entries, undefined),\n { id, op: 'create', data: { kind: 'custom', name, theme } },\n ],\n selection,\n }\n }\n\n case 'update': {\n if (current.kind !== 'custom') {\n return {\n ok: false,\n status: 409,\n error:\n 'Only your own themes can be updated. Save your changes as a ' +\n 'custom theme instead.',\n }\n }\n const theme = themeArtifactContent(resolved)\n const override = overrideValue(\n theme,\n withSiteSettings(theme, resolved),\n null,\n )\n return {\n ok: true,\n host: {\n theme: hasContent(theme) ? theme : THEME_FIELD_DELETE,\n themeOverride: override,\n themeSelection: current,\n },\n entries: [\n entries[current.id]\n ? { id: current.id, op: 'update', data: { theme } }\n : {\n id: current.id,\n op: 'create',\n data: { kind: 'custom', name: current.name, theme },\n },\n ],\n selection: current,\n }\n }\n\n case 'restore': {\n const base = host.theme ?? {}\n return {\n ok: true,\n host: {\n themeOverride: overrideValue(\n base,\n withSiteSettings(base, resolved),\n current.kind === 'installed' ? sha(host.themeInstalledFrom) : null,\n ),\n },\n entries: [],\n selection: current,\n }\n }\n\n case 'rename': {\n const name = normalizeThemeName(action.name)\n if (!name) {\n return { ok: false, status: 400, error: 'Give the theme a name.' }\n }\n const isLegacySiteTheme =\n action.id === SITE_THEME_ENTRY_ID &&\n current.id === SITE_THEME_ENTRY_ID &&\n !entries[SITE_THEME_ENTRY_ID]\n const entry = entries[action.id]\n if (!isLegacySiteTheme && entry?.kind !== 'custom') {\n return { ok: false, status: 404, error: 'Only your own themes can be renamed.' }\n }\n const renamedSelection =\n current.id === action.id ? { ...current, name } : null\n return {\n ok: true,\n host: renamedSelection ? { themeSelection: renamedSelection } : {},\n entries: isLegacySiteTheme\n ? [\n {\n id: action.id,\n op: 'create',\n data: {\n kind: 'custom',\n name,\n theme: themeArtifactContent(host.theme),\n },\n },\n ]\n : [{ id: action.id, op: 'update', data: { name } }],\n selection: renamedSelection ?? current,\n }\n }\n\n case 'delete': {\n const entry = entries[action.id]\n if (!entry || (entry.kind !== 'custom' && entry.kind !== 'installed')) {\n return { ok: false, status: 404, error: 'There is no such theme to delete.' }\n }\n if (current.id === action.id) {\n return {\n ok: false,\n status: 409,\n error: 'This theme is in use. Pick another theme first, then delete it.',\n }\n }\n return {\n ok: true,\n host: {},\n entries: [{ id: action.id, op: 'delete' }],\n selection: current,\n }\n }\n }\n}\n\nfunction planSelect(\n host: ThemeLibraryHost,\n current: HostThemeSelection,\n resolved: HostTheme,\n entries: Readonly<Record<string, ThemeLibraryEntry>>,\n target: ThemeLibraryTarget,\n): ThemeLibraryPlan {\n let selection: HostThemeSelection\n let base: HostTheme\n let installedFrom: unknown = null\n if (target.kind === 'default') {\n selection = {\n kind: 'default',\n id: DEFAULT_THEME_ENTRY_ID,\n name: DEFAULT_THEME_NAME,\n }\n base = {}\n } else if (target.kind === 'preset') {\n const name = normalizeThemeName(target.name)\n if (!target.id || !name || !isRecord(target.theme)) {\n return { ok: false, status: 400, error: 'That theme could not be read.' }\n }\n selection = { kind: 'preset', id: presetEntryId(target.id), name }\n base = themeArtifactContent(target.theme)\n } else {\n const entry = entries[target.id]\n if (!entry || entry.kind !== target.kind) {\n return { ok: false, status: 404, error: 'That theme is not in this site’s library.' }\n }\n selection = { kind: entry.kind, id: target.id, name: entry.name }\n base = themeArtifactContent(entry.theme ?? {})\n installedFrom = entry.installedFrom ?? null\n }\n if (selection.id === current.id && selection.kind === current.kind) {\n return { ok: true, host: {}, entries: [], selection: current }\n }\n\n const stash = entries[selection.id]?.override\n const edited = withSiteSettings(resolveStash(base, stash), resolved)\n const writes: ThemeLibraryEntryWrite[] = fileCurrent(\n host,\n current,\n entries,\n host.themeOverride,\n )\n // Its stash is live again, so the entry stops holding a second copy.\n if (entries[selection.id]?.override !== undefined) {\n writes.push({\n id: selection.id,\n op: 'update',\n data: { override: THEME_FIELD_DELETE },\n })\n }\n return {\n ok: true,\n host: pointAt(\n selection,\n base,\n overrideValue(\n base,\n edited,\n selection.kind === 'installed' ? sha(installedFrom) : null,\n ),\n installedFrom,\n ),\n entries: writes,\n selection,\n }\n}\n\n/**\n * Whether the picked theme carries edits of this site's own — what \"Restore\"\n * and \"Update\" act on. The site's dark-scheme setting is not an edit to the\n * theme, so an override holding only that does not count.\n */\nexport function hasThemeEdits(host: ThemeLibraryHost | null | undefined): boolean {\n const read = readArtifactOverride({ overrides: host?.themeOverride })\n if (!read || isEmptyOverride(read.patch)) return false\n if (!isRecord(read.patch)) return true\n return Object.keys(read.patch).some((key) => key !== 'darkScheme')\n}\n"],"names":["diffOverride","isEmptyOverride","overrideWriteValue","readArtifactOverride","resolveOverride","resolveSiteTheme","themeArtifactContent","THEME_LIBRARY_COLLECTION","THEME_LIBRARY_MAX_CUSTOM","THEME_NAME_MAX","KINDS","DEFAULT_THEME_ENTRY_ID","SITE_THEME_ENTRY_ID","DEFAULT_THEME_NAME","presetEntryId","presetId","replace","installedEntryId","listingId","isRecord","value","Array","isArray","hasContent","theme","Boolean","Object","keys","length","readThemeSelection","host","stored","themeSelection","includes","kind","id","name","themeInstalledFrom","normalizeThemeName","trimmed","trim","slice","THEME_FIELD_DELETE","overrideValue","base","edited","baseSha256","patch","withSiteSettings","from","next","darkScheme","resolveStash","stash","read","overrides","sha","installedFrom","fileCurrent","current","entries","override","undefined","op","data","entry","pointAt","selection","themeOverride","themeReplaced","planThemeLibraryAction","input","action","resolved","planSelect","target","ok","status","error","customCount","values","filter","newId","isLegacySiteTheme","renamedSelection","writes","push","hasThemeEdits","some","key"],"mappings":"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"}
|
|
@@ -18,6 +18,11 @@
|
|
|
18
18
|
* Where an account came from (AGL-1731) — the campaign contract between the
|
|
19
19
|
* marketing site's links and the console's signup.
|
|
20
20
|
*
|
|
21
|
+
* Named for what it parses, the web's UTM labels. The `campaign` in
|
|
22
|
+
* `utm_campaign` is the label an ad push carries; it is not the Marketing
|
|
23
|
+
* plugin's campaign, and nothing here reads one. What a site's own visitors
|
|
24
|
+
* carry to the moment they identify is `campaign-touch.ts`'s.
|
|
25
|
+
*
|
|
21
26
|
* Until this existed a paid click, an organic visit and a partner link
|
|
22
27
|
* arrived indistinguishable: `sign_up` carried `method` and nothing else, so
|
|
23
28
|
* no report could say which spend produced a customer. That is tolerable
|
|
@@ -70,9 +75,9 @@
|
|
|
70
75
|
* identically — two spellings would read as two dimensions in GA4 and split
|
|
71
76
|
* every report in half.
|
|
72
77
|
*/
|
|
73
|
-
export declare const
|
|
78
|
+
export declare const UTM_QUERY_KEYS: readonly ["utm_source", "utm_medium", "utm_campaign"];
|
|
74
79
|
/** A campaign, with every field optional — a partial one is still worth having. */
|
|
75
|
-
export interface
|
|
80
|
+
export interface UtmAttribution {
|
|
76
81
|
/** `utm_source` — the channel: `google`, `hn`, a partner's name. */
|
|
77
82
|
source?: string;
|
|
78
83
|
/** `utm_medium` — the kind of placement: `cpc`, `email`, `referral`. */
|
|
@@ -81,7 +86,7 @@ export interface CampaignAttribution {
|
|
|
81
86
|
campaign?: string;
|
|
82
87
|
}
|
|
83
88
|
/** What a Server Component holds before it has a `URLSearchParams`. */
|
|
84
|
-
export type
|
|
89
|
+
export type UtmParamSource = URLSearchParams | Record<string, string | string[] | undefined> | null | undefined;
|
|
85
90
|
/**
|
|
86
91
|
* Read the campaign off a signup URL, or null when it names none.
|
|
87
92
|
*
|
|
@@ -89,12 +94,12 @@ export type CampaignParamSource = URLSearchParams | Record<string, string | stri
|
|
|
89
94
|
* all". An empty object written to an account would read as "arrived from
|
|
90
95
|
* nowhere, confirmed" instead of "never asked", and those are different facts.
|
|
91
96
|
*/
|
|
92
|
-
export declare function
|
|
97
|
+
export declare function parseUtmAttribution(params: UtmParamSource): UtmAttribution | null;
|
|
93
98
|
/**
|
|
94
99
|
* The canonical query string for a campaign — the ONLY place the stored form
|
|
95
100
|
* is written, so it cannot drift from what the parser reads back.
|
|
96
101
|
*/
|
|
97
|
-
export declare function
|
|
102
|
+
export declare function utmAttributionQuery(attribution: UtmAttribution | null | undefined): string;
|
|
98
103
|
/**
|
|
99
104
|
* The campaign as GA4 event parameters, ready to spread into `sign_up`.
|
|
100
105
|
*
|
|
@@ -110,7 +115,7 @@ export declare function campaignAttributionQuery(attribution: CampaignAttributio
|
|
|
110
115
|
* sanitizer as an absence but read, to whoever writes the report, as a
|
|
111
116
|
* dimension that is populated sometimes and broken the rest of the time.
|
|
112
117
|
*/
|
|
113
|
-
export declare function
|
|
118
|
+
export declare function utmEventParams(attribution: UtmAttribution | null | undefined): {
|
|
114
119
|
campaign_source?: string;
|
|
115
120
|
campaign_medium?: string;
|
|
116
121
|
campaign_name?: string;
|
|
@@ -18,6 +18,11 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
|
18
18
|
* Where an account came from (AGL-1731) — the campaign contract between the
|
|
19
19
|
* marketing site's links and the console's signup.
|
|
20
20
|
*
|
|
21
|
+
* Named for what it parses, the web's UTM labels. The `campaign` in
|
|
22
|
+
* `utm_campaign` is the label an ad push carries; it is not the Marketing
|
|
23
|
+
* plugin's campaign, and nothing here reads one. What a site's own visitors
|
|
24
|
+
* carry to the moment they identify is `campaign-touch.ts`'s.
|
|
25
|
+
*
|
|
21
26
|
* Until this existed a paid click, an organic visit and a partner link
|
|
22
27
|
* arrived indistinguishable: `sign_up` carried `method` and nothing else, so
|
|
23
28
|
* no report could say which spend produced a customer. That is tolerable
|
|
@@ -68,14 +73,14 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
|
68
73
|
* site's links, the stored wire form and this parser all have to spell them
|
|
69
74
|
* identically — two spellings would read as two dimensions in GA4 and split
|
|
70
75
|
* every report in half.
|
|
71
|
-
*/ export const
|
|
76
|
+
*/ export const UTM_QUERY_KEYS = [
|
|
72
77
|
'utm_source',
|
|
73
78
|
'utm_medium',
|
|
74
79
|
'utm_campaign'
|
|
75
80
|
];
|
|
76
81
|
/** Longest value stored or sent, matching `sanitizeEventParams`'s own cap. */ const MAX_VALUE_LENGTH = 100;
|
|
77
82
|
/** The same shape test the event sanitizer uses, applied to the stored exit too. */ const EMAIL_SHAPED = /[^\s@]+@[^\s@]+\.[^\s@]+/;
|
|
78
|
-
/** Which `
|
|
83
|
+
/** Which `UtmAttribution` field each URL key fills. */ const FIELD_FOR_KEY = {
|
|
79
84
|
utm_source: 'source',
|
|
80
85
|
utm_medium: 'medium',
|
|
81
86
|
utm_campaign: 'campaign'
|
|
@@ -113,10 +118,10 @@ function rawValue(params, key) {
|
|
|
113
118
|
* Null rather than `{}` so a caller can branch on "was there a campaign at
|
|
114
119
|
* all". An empty object written to an account would read as "arrived from
|
|
115
120
|
* nowhere, confirmed" instead of "never asked", and those are different facts.
|
|
116
|
-
*/ export function
|
|
121
|
+
*/ export function parseUtmAttribution(params) {
|
|
117
122
|
if (!params) return null;
|
|
118
123
|
const attribution = {};
|
|
119
|
-
for (const key of
|
|
124
|
+
for (const key of UTM_QUERY_KEYS){
|
|
120
125
|
const value = scrubValue(rawValue(params, key));
|
|
121
126
|
if (value) attribution[FIELD_FOR_KEY[key]] = value;
|
|
122
127
|
}
|
|
@@ -125,10 +130,10 @@ function rawValue(params, key) {
|
|
|
125
130
|
/**
|
|
126
131
|
* The canonical query string for a campaign — the ONLY place the stored form
|
|
127
132
|
* is written, so it cannot drift from what the parser reads back.
|
|
128
|
-
*/ export function
|
|
133
|
+
*/ export function utmAttributionQuery(attribution) {
|
|
129
134
|
if (!attribution) return '';
|
|
130
135
|
const params = new URLSearchParams();
|
|
131
|
-
for (const key of
|
|
136
|
+
for (const key of UTM_QUERY_KEYS){
|
|
132
137
|
const value = attribution[FIELD_FOR_KEY[key]];
|
|
133
138
|
if (value) params.set(key, value);
|
|
134
139
|
}
|
|
@@ -148,7 +153,7 @@ function rawValue(params, key) {
|
|
|
148
153
|
* `campaign_source: undefined` on every unattributed signup would survive the
|
|
149
154
|
* sanitizer as an absence but read, to whoever writes the report, as a
|
|
150
155
|
* dimension that is populated sometimes and broken the rest of the time.
|
|
151
|
-
*/ export function
|
|
156
|
+
*/ export function utmEventParams(attribution) {
|
|
152
157
|
if (!attribution) return {};
|
|
153
158
|
return _extends({}, attribution.source ? {
|
|
154
159
|
campaign_source: attribution.source
|
|
@@ -159,4 +164,4 @@ function rawValue(params, key) {
|
|
|
159
164
|
} : {});
|
|
160
165
|
}
|
|
161
166
|
|
|
162
|
-
//# sourceMappingURL=
|
|
167
|
+
//# sourceMappingURL=utm-attribution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/utm-attribution.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 * Where an account came from (AGL-1731) — the campaign contract between the\n * marketing site's links and the console's signup.\n *\n * Named for what it parses, the web's UTM labels. The `campaign` in\n * `utm_campaign` is the label an ad push carries; it is not the Marketing\n * plugin's campaign, and nothing here reads one. What a site's own visitors\n * carry to the moment they identify is `campaign-touch.ts`'s.\n *\n * Until this existed a paid click, an organic visit and a partner link\n * arrived indistinguishable: `sign_up` carried `method` and nothing else, so\n * no report could say which spend produced a customer. That is tolerable\n * while nothing is being spent and not tolerable the day advertising starts,\n * because the measurement has to exist BEFORE the traffic — a signup that\n * lands unattributed is unattributed forever.\n *\n * ## Why an allowlist, and why exactly three\n *\n * `utm_source`, `utm_medium` and `utm_campaign` are the three axes an ad\n * report is read on: which channel, what kind of placement, which push. They\n * are also the three the marketing site can be told to emit without further\n * decisions.\n *\n * `utm_term` and `utm_content` are deliberately OUT, matching the refusal the\n * tenant's own first-party collector already made for its visitors\n * (`apps/tenant/app/api/analytics/collect/route.ts`): keyword- and\n * variant-level labels multiply cardinality without answering a question\n * anyone asks of a signup, and a keyword string is the most likely of the\n * five to carry something a person typed. `gclid` and bare `ref` are out for\n * that same cardinality reason. Not for a privacy one: the property runs ads\n * personalization ON in every region, and Google's own auto-tagging already\n * carries the click identifier into it, so re-collecting `gclid` here would\n * duplicate a field the platform owns rather than withhold anything.\n *\n * The allowlist is the privacy mechanism, not a convenience. A parser that\n * copied \"the campaign-ish parameters\" would be one marketing link away from\n * storing `?email=` against a person, and the standing rule is that personal\n * data never travels in a URL parameter in the first place.\n *\n * ## Two exits, and only one of them is already guarded\n *\n * A parsed campaign leaves this process twice: onto the GA4 `sign_up` hit,\n * and into `users/{uid}` so revenue can be attributed to it months later.\n * Only the first passes `sanitizeEventParams`. The Firestore write does not,\n * so the scrub — email shape refused, length capped, blanks dropped — lives\n * HERE, on the way in, and both exits inherit it.\n *\n * ## Why the wire form is what gets stored\n *\n * Same contract as the AGL-1535 plan intent it rides beside: the stored value\n * is the query string, re-parsed by this parser on the way out. `users/{uid}`\n * is owner-writable, so a stored field is a client-FORGEABLE field. Re-parsing\n * means a hand-edited document can claim no more than a hand-edited URL could,\n * which is a marketing label and nothing that touches entitlement.\n */\n\n/**\n * The URL parameter names, in report order. Exported because the marketing\n * site's links, the stored wire form and this parser all have to spell them\n * identically — two spellings would read as two dimensions in GA4 and split\n * every report in half.\n */\nexport const UTM_QUERY_KEYS = [\n 'utm_source',\n 'utm_medium',\n 'utm_campaign',\n] as const\n\n/** A campaign, with every field optional — a partial one is still worth having. */\nexport interface UtmAttribution {\n /** `utm_source` — the channel: `google`, `hn`, a partner's name. */\n source?: string\n /** `utm_medium` — the kind of placement: `cpc`, `email`, `referral`. */\n medium?: string\n /** `utm_campaign` — which push: `sept-launch`. */\n campaign?: string\n}\n\n/** Longest value stored or sent, matching `sanitizeEventParams`'s own cap. */\nconst MAX_VALUE_LENGTH = 100\n\n/** The same shape test the event sanitizer uses, applied to the stored exit too. */\nconst EMAIL_SHAPED = /[^\\s@]+@[^\\s@]+\\.[^\\s@]+/\n\n/** Which `UtmAttribution` field each URL key fills. */\nconst FIELD_FOR_KEY: Record<\n (typeof UTM_QUERY_KEYS)[number],\n keyof UtmAttribution\n> = {\n utm_source: 'source',\n utm_medium: 'medium',\n utm_campaign: 'campaign',\n}\n\n/** What a Server Component holds before it has a `URLSearchParams`. */\nexport type UtmParamSource =\n | URLSearchParams\n | Record<string, string | string[] | undefined>\n | null\n | undefined\n\nfunction rawValue(params: UtmParamSource, key: string): string | null {\n if (!params) return null\n if (typeof (params as URLSearchParams).get === 'function') {\n return (params as URLSearchParams).get(key)\n }\n const value = (params as Record<string, string | string[] | undefined>)[key]\n // A repeated parameter arrives as an array. The first one wins rather than\n // being joined: `utm_medium=cpc&utm_medium=organic` is a malformed link, and\n // inventing `cpc,organic` would put a value in the reports that no campaign\n // ever set.\n if (Array.isArray(value)) return value.length ? value[0] : null\n return typeof value === 'string' ? value : null\n}\n\n/**\n * Reduce one raw parameter to something storable, or null to drop it.\n *\n * Dropping the single value rather than the whole campaign is deliberate: a\n * mail-merge link that puts an address in `utm_source` still names a real\n * `utm_campaign`, and keeping the half that is safe beats losing the\n * attribution to protect the half that is not.\n */\nfunction scrubValue(value: string | null): string | null {\n if (typeof value !== 'string') return null\n const trimmed = value.trim()\n if (!trimmed) return null\n if (EMAIL_SHAPED.test(trimmed)) return null\n return trimmed.slice(0, MAX_VALUE_LENGTH)\n}\n\n/**\n * Read the campaign off a signup URL, or null when it names none.\n *\n * Null rather than `{}` so a caller can branch on \"was there a campaign at\n * all\". An empty object written to an account would read as \"arrived from\n * nowhere, confirmed\" instead of \"never asked\", and those are different facts.\n */\nexport function parseUtmAttribution(\n params: UtmParamSource,\n): UtmAttribution | null {\n if (!params) return null\n const attribution: UtmAttribution = {}\n for (const key of UTM_QUERY_KEYS) {\n const value = scrubValue(rawValue(params, key))\n if (value) attribution[FIELD_FOR_KEY[key]] = value\n }\n return Object.keys(attribution).length ? attribution : null\n}\n\n/**\n * The canonical query string for a campaign — the ONLY place the stored form\n * is written, so it cannot drift from what the parser reads back.\n */\nexport function utmAttributionQuery(\n attribution: UtmAttribution | null | undefined,\n): string {\n if (!attribution) return ''\n const params = new URLSearchParams()\n for (const key of UTM_QUERY_KEYS) {\n const value = attribution[FIELD_FOR_KEY[key]]\n if (value) params.set(key, value)\n }\n return params.toString()\n}\n\n/**\n * The campaign as GA4 event parameters, ready to spread into `sign_up`.\n *\n * Renamed off the `utm_` spellings on purpose. These are OUR event parameters,\n * registered as custom dimensions on the property (see `docs/ANALYTICS.md`);\n * the `utm_` names belong to GA's own automatic campaign collection, and\n * shipping a custom parameter under a name the platform also owns is how a\n * dimension ends up meaning two things.\n *\n * Returns an empty object — never keys with `undefined` values — so that\n * spreading it into an organic signup's params adds nothing at all. A\n * `campaign_source: undefined` on every unattributed signup would survive the\n * sanitizer as an absence but read, to whoever writes the report, as a\n * dimension that is populated sometimes and broken the rest of the time.\n */\nexport function utmEventParams(\n attribution: UtmAttribution | null | undefined,\n): {\n campaign_source?: string\n campaign_medium?: string\n campaign_name?: string\n} {\n if (!attribution) return {}\n return {\n ...(attribution.source ? { campaign_source: attribution.source } : {}),\n ...(attribution.medium ? { campaign_medium: attribution.medium } : {}),\n ...(attribution.campaign ? { campaign_name: attribution.campaign } : {}),\n }\n}\n"],"names":["UTM_QUERY_KEYS","MAX_VALUE_LENGTH","EMAIL_SHAPED","FIELD_FOR_KEY","utm_source","utm_medium","utm_campaign","rawValue","params","key","get","value","Array","isArray","length","scrubValue","trimmed","trim","test","slice","parseUtmAttribution","attribution","Object","keys","utmAttributionQuery","URLSearchParams","set","toString","utmEventParams","source","campaign_source","medium","campaign_medium","campaign","campaign_name"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsDC,GAED;;;;;CAKC,GACD,OAAO,MAAMA,iBAAiB;IAC5B;IACA;IACA;CACD,CAAS;AAYV,4EAA4E,GAC5E,MAAMC,mBAAmB;AAEzB,kFAAkF,GAClF,MAAMC,eAAe;AAErB,qDAAqD,GACrD,MAAMC,gBAGF;IACFC,YAAY;IACZC,YAAY;IACZC,cAAc;AAChB;AASA,SAASC,SAASC,MAAsB,EAAEC,GAAW;IACnD,IAAI,CAACD,QAAQ,OAAO;IACpB,IAAI,OAAO,AAACA,OAA2BE,GAAG,KAAK,YAAY;QACzD,OAAO,AAACF,OAA2BE,GAAG,CAACD;IACzC;IACA,MAAME,QAAQ,AAACH,MAAwD,CAACC,IAAI;IAC5E,2EAA2E;IAC3E,6EAA6E;IAC7E,4EAA4E;IAC5E,YAAY;IACZ,IAAIG,MAAMC,OAAO,CAACF,QAAQ,OAAOA,MAAMG,MAAM,GAAGH,KAAK,CAAC,EAAE,GAAG;IAC3D,OAAO,OAAOA,UAAU,WAAWA,QAAQ;AAC7C;AAEA;;;;;;;CAOC,GACD,SAASI,WAAWJ,KAAoB;IACtC,IAAI,OAAOA,UAAU,UAAU,OAAO;IACtC,MAAMK,UAAUL,MAAMM,IAAI;IAC1B,IAAI,CAACD,SAAS,OAAO;IACrB,IAAId,aAAagB,IAAI,CAACF,UAAU,OAAO;IACvC,OAAOA,QAAQG,KAAK,CAAC,GAAGlB;AAC1B;AAEA;;;;;;CAMC,GACD,OAAO,SAASmB,oBACdZ,MAAsB;IAEtB,IAAI,CAACA,QAAQ,OAAO;IACpB,MAAMa,cAA8B,CAAC;IACrC,KAAK,MAAMZ,OAAOT,eAAgB;QAChC,MAAMW,QAAQI,WAAWR,SAASC,QAAQC;QAC1C,IAAIE,OAAOU,WAAW,CAAClB,aAAa,CAACM,IAAI,CAAC,GAAGE;IAC/C;IACA,OAAOW,OAAOC,IAAI,CAACF,aAAaP,MAAM,GAAGO,cAAc;AACzD;AAEA;;;CAGC,GACD,OAAO,SAASG,oBACdH,WAA8C;IAE9C,IAAI,CAACA,aAAa,OAAO;IACzB,MAAMb,SAAS,IAAIiB;IACnB,KAAK,MAAMhB,OAAOT,eAAgB;QAChC,MAAMW,QAAQU,WAAW,CAAClB,aAAa,CAACM,IAAI,CAAC;QAC7C,IAAIE,OAAOH,OAAOkB,GAAG,CAACjB,KAAKE;IAC7B;IACA,OAAOH,OAAOmB,QAAQ;AACxB;AAEA;;;;;;;;;;;;;;CAcC,GACD,OAAO,SAASC,eACdP,WAA8C;IAM9C,IAAI,CAACA,aAAa,OAAO,CAAC;IAC1B,OAAO,aACDA,YAAYQ,MAAM,GAAG;QAAEC,iBAAiBT,YAAYQ,MAAM;IAAC,IAAI,CAAC,GAChER,YAAYU,MAAM,GAAG;QAAEC,iBAAiBX,YAAYU,MAAM;IAAC,IAAI,CAAC,GAChEV,YAAYY,QAAQ,GAAG;QAAEC,eAAeb,YAAYY,QAAQ;IAAC,IAAI,CAAC;AAE1E"}
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
/**
|
|
18
|
-
* Carry the
|
|
18
|
+
* Carry the visit's UTM labels across the domain hop (AGL-1731).
|
|
19
19
|
*
|
|
20
|
-
* `
|
|
20
|
+
* `utm-attribution.ts` is the READER half of this contract and it works.
|
|
21
21
|
* This is the half that was missing, and without it the reader was fed
|
|
22
22
|
* nothing: `aglyn.com` is a tenant published site and `app.aglyn.com` is the
|
|
23
23
|
* console, a real cross-origin hop, and no code anywhere put a `utm_*`
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
* it. There is no default, no inference from the referrer, and no
|
|
96
96
|
* `utm_source=direct` — a signup with no campaign must reach the console with
|
|
97
97
|
* no campaign, so that "arrived from nowhere" and "never asked" stay the
|
|
98
|
-
* distinct facts `
|
|
98
|
+
* distinct facts `utm-attribution.ts` keeps them.
|
|
99
99
|
*
|
|
100
100
|
* Only links to OUR OWN console origin are touched, and the origin is supplied
|
|
101
101
|
* by the caller rather than written here — a self-host install points
|
|
@@ -115,14 +115,14 @@
|
|
|
115
115
|
* is the exact failure AGL-1731 is about, and it is worse than a few
|
|
116
116
|
* mislabelled rows that GA's own Hostname dimension can already separate.
|
|
117
117
|
*/
|
|
118
|
-
import { type
|
|
118
|
+
import { type UtmAttribution } from './utm-attribution';
|
|
119
119
|
/**
|
|
120
120
|
* Where the first touch of this visit is held. `sessionStorage`, so it dies
|
|
121
121
|
* with the tab: a campaign is a fact about one visit, and a value that
|
|
122
122
|
* outlived the visit would start attributing next week's organic return to
|
|
123
123
|
* this week's ad.
|
|
124
124
|
*/
|
|
125
|
-
export declare const
|
|
125
|
+
export declare const UTM_VISIT_STORAGE_KEY = "aglyn:campaign";
|
|
126
126
|
/**
|
|
127
127
|
* What a read of the first-touch store produced.
|
|
128
128
|
*
|
|
@@ -134,9 +134,9 @@ export declare const CAMPAIGN_VISIT_STORAGE_KEY = "aglyn:campaign";
|
|
|
134
134
|
* treats it differently: it falls through to the live URL instead of
|
|
135
135
|
* concluding anything.
|
|
136
136
|
*/
|
|
137
|
-
export type
|
|
137
|
+
export type VisitUtmRead = {
|
|
138
138
|
status: 'campaign';
|
|
139
|
-
campaign:
|
|
139
|
+
campaign: UtmAttribution;
|
|
140
140
|
} | {
|
|
141
141
|
status: 'none';
|
|
142
142
|
} | {
|
|
@@ -150,7 +150,7 @@ export type VisitCampaignRead = {
|
|
|
150
150
|
* string can claim no more than an inbound URL could — three allowlisted keys,
|
|
151
151
|
* trimmed, email shapes refused, capped.
|
|
152
152
|
*/
|
|
153
|
-
export declare function
|
|
153
|
+
export declare function readVisitUtm(): VisitUtmRead;
|
|
154
154
|
/**
|
|
155
155
|
* Remember the campaign on the current URL as this visit's first touch.
|
|
156
156
|
*
|
|
@@ -161,7 +161,7 @@ export declare function readVisitCampaign(): VisitCampaignRead;
|
|
|
161
161
|
*
|
|
162
162
|
* Returns what is now remembered so a caller can assert on it.
|
|
163
163
|
*/
|
|
164
|
-
export declare function
|
|
164
|
+
export declare function rememberVisitUtm(search?: string): UtmAttribution | null;
|
|
165
165
|
/**
|
|
166
166
|
* Tell this module what the visitor's analytics consent state is.
|
|
167
167
|
*
|
|
@@ -171,7 +171,7 @@ export declare function rememberVisitCampaign(search?: string): CampaignAttribut
|
|
|
171
171
|
* visitor who changes their mind mid-visit should not leave the thing they
|
|
172
172
|
* withdrew consent for sitting on their device.
|
|
173
173
|
*/
|
|
174
|
-
export declare function
|
|
174
|
+
export declare function setUtmForwardingConsent(allowed: boolean | null): void;
|
|
175
175
|
/**
|
|
176
176
|
* The campaign to forward, first touch preferred.
|
|
177
177
|
*
|
|
@@ -179,7 +179,7 @@ export declare function setCampaignForwardingConsent(allowed: boolean | null): v
|
|
|
179
179
|
* which is the point of carrying that state at all: a broken store degrades
|
|
180
180
|
* this to tier 1 rather than to silence.
|
|
181
181
|
*/
|
|
182
|
-
export declare function
|
|
182
|
+
export declare function utmToForward(search?: string): UtmAttribution | null;
|
|
183
183
|
/**
|
|
184
184
|
* The href a console-bound link should carry for this visitor, or null to
|
|
185
185
|
* leave it exactly as authored.
|
|
@@ -194,7 +194,7 @@ export declare function campaignToForward(search?: string): CampaignAttribution
|
|
|
194
194
|
* row describes an event that never happened. Everything else on the href —
|
|
195
195
|
* `plan`, `interval`, the AGL-1535 intent — is preserved untouched.
|
|
196
196
|
*/
|
|
197
|
-
export declare function
|
|
197
|
+
export declare function decorateUtmHref(href: string, baseHref: string, consoleOrigin: string, campaign: UtmAttribution | null): string | null;
|
|
198
198
|
/**
|
|
199
199
|
* Start forwarding the campaign onto console-bound links on this page.
|
|
200
200
|
*
|
|
@@ -213,8 +213,8 @@ export declare function decorateCampaignHref(href: string, baseHref: string, con
|
|
|
213
213
|
* Returns an uninstall function for tests and for a caller that owns the page
|
|
214
214
|
* lifecycle.
|
|
215
215
|
*/
|
|
216
|
-
export declare function
|
|
216
|
+
export declare function installUtmForwarding(options: {
|
|
217
217
|
consoleOrigin: string;
|
|
218
218
|
}): () => void;
|
|
219
219
|
/** Test seam — removes both listeners, forgets them, and forgets consent. */
|
|
220
|
-
export declare function
|
|
220
|
+
export declare function resetUtmForwarding(): void;
|