@aglyn/aglyn 1.0.0-beta.218 → 1.0.0-beta.220
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +12 -12
- package/src/lib/app-utils/actions.d.ts +26 -433
- package/src/lib/app-utils/actions.js +108 -633
- package/src/lib/app-utils/actions.js.map +1 -1
- package/src/lib/app-utils/activity-presenter.d.ts +3 -3
- package/src/lib/app-utils/activity-presenter.js +36 -52
- package/src/lib/app-utils/activity-presenter.js.map +1 -1
- package/src/lib/app-utils/analytics-events.d.ts +1 -1
- package/src/lib/app-utils/analytics-events.js.map +1 -1
- package/src/lib/app-utils/analytics-provider.d.ts +182 -0
- package/src/lib/app-utils/analytics-provider.js +133 -0
- package/src/lib/app-utils/analytics-provider.js.map +1 -0
- package/src/lib/app-utils/api-plugins.d.ts +46 -0
- package/src/lib/app-utils/api-plugins.js +19 -0
- package/src/lib/app-utils/api-plugins.js.map +1 -1
- package/src/lib/app-utils/{marketplace-overrides.d.ts → artifact-overrides.d.ts} +9 -6
- package/src/lib/app-utils/{marketplace-overrides.js → artifact-overrides.js} +10 -7
- package/src/lib/app-utils/artifact-overrides.js.map +1 -0
- package/src/lib/app-utils/{marketplace-provenance.d.ts → artifact-provenance.d.ts} +12 -10
- package/src/lib/app-utils/{marketplace-provenance.js → artifact-provenance.js} +9 -7
- package/src/lib/app-utils/artifact-provenance.js.map +1 -0
- package/src/lib/app-utils/binding-token-catalog.d.ts +5 -13
- package/src/lib/app-utils/binding-token-catalog.js +17 -41
- package/src/lib/app-utils/binding-token-catalog.js.map +1 -1
- package/src/lib/app-utils/brand-support-line.d.ts +36 -0
- package/src/lib/app-utils/brand-support-line.js +38 -0
- package/src/lib/app-utils/brand-support-line.js.map +1 -0
- package/src/lib/app-utils/collection-entries.d.ts +2 -2
- package/src/lib/app-utils/collection-entries.js.map +1 -1
- package/src/lib/app-utils/consent-group-change.d.ts +4 -0
- package/src/lib/app-utils/consent-group-change.js.map +1 -1
- package/src/lib/app-utils/consent-groups.d.ts +1 -1
- package/src/lib/app-utils/consent-groups.js.map +1 -1
- package/src/lib/app-utils/console-routes.d.ts +15 -42
- package/src/lib/app-utils/console-routes.js +10 -39
- package/src/lib/app-utils/console-routes.js.map +1 -1
- package/src/lib/app-utils/contacts.d.ts +24 -2
- package/src/lib/app-utils/contacts.js +21 -5
- package/src/lib/app-utils/contacts.js.map +1 -1
- package/src/lib/app-utils/container-membership.d.ts +93 -0
- package/src/lib/app-utils/container-membership.js +165 -0
- package/src/lib/app-utils/container-membership.js.map +1 -0
- package/src/lib/app-utils/crm-task-reminders.d.ts +23 -6
- package/src/lib/app-utils/crm-task-reminders.js +32 -11
- package/src/lib/app-utils/crm-task-reminders.js.map +1 -1
- package/src/lib/app-utils/crm.d.ts +24 -4
- package/src/lib/app-utils/crm.js +23 -0
- package/src/lib/app-utils/crm.js.map +1 -1
- package/src/lib/app-utils/cross-pool-desync.d.ts +39 -0
- package/src/lib/app-utils/cross-pool-desync.js +47 -0
- package/src/lib/app-utils/cross-pool-desync.js.map +1 -0
- package/src/lib/app-utils/csv-upload.d.ts +29 -0
- package/src/lib/app-utils/csv-upload.js +29 -0
- package/src/lib/app-utils/csv-upload.js.map +1 -0
- package/src/lib/app-utils/{dataset-csv.d.ts → csv.d.ts} +10 -43
- package/src/lib/app-utils/{dataset-csv.js → csv.js} +10 -81
- package/src/lib/app-utils/csv.js.map +1 -0
- package/src/lib/app-utils/dataset-models.d.ts +5 -5
- package/src/lib/app-utils/dataset-models.js +19 -2
- package/src/lib/app-utils/dataset-models.js.map +1 -1
- package/src/lib/app-utils/datasets.d.ts +65 -30
- package/src/lib/app-utils/datasets.js +74 -24
- package/src/lib/app-utils/datasets.js.map +1 -1
- package/src/lib/app-utils/docs-deflection.d.ts +6 -6
- package/src/lib/app-utils/docs-deflection.js.map +1 -1
- package/src/lib/app-utils/docs-help.generated.d.ts +14 -8
- package/src/lib/app-utils/docs-help.generated.js +23 -6
- package/src/lib/app-utils/docs-help.generated.js.map +1 -1
- package/src/lib/app-utils/docs-index.generated.d.ts +2 -2
- package/src/lib/app-utils/docs-index.generated.js +570 -346
- package/src/lib/app-utils/docs-index.generated.js.map +1 -1
- package/src/lib/app-utils/docs-retrieval.d.ts +3 -3
- package/src/lib/app-utils/docs-retrieval.js +14 -10
- package/src/lib/app-utils/docs-retrieval.js.map +1 -1
- package/src/lib/app-utils/duplicate-resource.d.ts +4 -1
- package/src/lib/app-utils/duplicate-resource.js +7 -4
- package/src/lib/app-utils/duplicate-resource.js.map +1 -1
- package/src/lib/app-utils/dynamic-list-rule.d.ts +1 -1
- package/src/lib/app-utils/dynamic-list-rule.js +3 -3
- package/src/lib/app-utils/dynamic-list-rule.js.map +1 -1
- package/src/lib/app-utils/element-ui.d.ts +1 -1
- package/src/lib/app-utils/element-ui.js +1 -1
- package/src/lib/app-utils/element-ui.js.map +1 -1
- package/src/lib/app-utils/email-starter-policy.js +3 -3
- package/src/lib/app-utils/email-starter-policy.js.map +1 -1
- package/src/lib/app-utils/email-text.d.ts +80 -0
- package/src/lib/app-utils/email-text.js +189 -0
- package/src/lib/app-utils/email-text.js.map +1 -0
- package/src/lib/app-utils/{list-assignment-policy.d.ts → enrollment-basis.d.ts} +4 -0
- package/src/lib/app-utils/{list-assignment-policy.js → enrollment-basis.js} +5 -1
- package/src/lib/app-utils/enrollment-basis.js.map +1 -0
- package/src/lib/app-utils/entity-picker-context.d.ts +10 -5
- package/src/lib/app-utils/entity-picker-context.js.map +1 -1
- package/src/lib/app-utils/error-beacon.d.ts +75 -6
- package/src/lib/app-utils/error-beacon.js +160 -21
- package/src/lib/app-utils/error-beacon.js.map +1 -1
- package/src/lib/app-utils/expand-repeatables.d.ts +10 -10
- package/src/lib/app-utils/expand-repeatables.js +14 -14
- package/src/lib/app-utils/expand-repeatables.js.map +1 -1
- package/src/lib/app-utils/forms.js +2 -2
- package/src/lib/app-utils/forms.js.map +1 -1
- package/src/lib/app-utils/health-report.d.ts +2 -3
- package/src/lib/app-utils/health-report.js +8 -6
- package/src/lib/app-utils/health-report.js.map +1 -1
- package/src/lib/app-utils/host-events.d.ts +82 -0
- package/src/lib/app-utils/host-events.js +62 -0
- package/src/lib/app-utils/host-events.js.map +1 -0
- package/src/lib/app-utils/inbound-mail-domain.d.ts +27 -0
- package/src/lib/app-utils/inbound-mail-domain.js +31 -0
- package/src/lib/app-utils/inbound-mail-domain.js.map +1 -0
- package/src/lib/app-utils/lockdown.d.ts +11 -0
- package/src/lib/app-utils/lockdown.js +33 -3
- package/src/lib/app-utils/lockdown.js.map +1 -1
- package/src/lib/app-utils/margin-utilization.d.ts +4 -69
- package/src/lib/app-utils/margin-utilization.js +82 -69
- package/src/lib/app-utils/margin-utilization.js.map +1 -1
- package/src/lib/app-utils/member-email-aliases.d.ts +25 -0
- package/src/lib/app-utils/member-email-aliases.js +29 -0
- package/src/lib/app-utils/member-email-aliases.js.map +1 -1
- package/src/lib/app-utils/node-definition-sanitizer.d.ts +16 -16
- package/src/lib/app-utils/node-definition-sanitizer.js +24 -20
- package/src/lib/app-utils/node-definition-sanitizer.js.map +1 -1
- package/src/lib/app-utils/node-interactions.d.ts +7 -7
- package/src/lib/app-utils/node-interactions.js.map +1 -1
- package/src/lib/app-utils/notifications.d.ts +147 -47
- package/src/lib/app-utils/notifications.js +182 -44
- package/src/lib/app-utils/notifications.js.map +1 -1
- package/src/lib/app-utils/operator-alerts.d.ts +15 -1
- package/src/lib/app-utils/operator-alerts.js +47 -10
- package/src/lib/app-utils/operator-alerts.js.map +1 -1
- package/src/lib/app-utils/payments-configured.d.ts +8 -21
- package/src/lib/app-utils/payments-configured.js +8 -23
- package/src/lib/app-utils/payments-configured.js.map +1 -1
- package/src/lib/app-utils/plan-entitlements.d.ts +207 -306
- package/src/lib/app-utils/plan-entitlements.js +345 -528
- package/src/lib/app-utils/plan-entitlements.js.map +1 -1
- package/src/lib/app-utils/platform-brand.d.ts +10 -0
- package/src/lib/app-utils/platform-brand.js +14 -3
- package/src/lib/app-utils/platform-brand.js.map +1 -1
- package/src/lib/app-utils/platform-marketing-consent.d.ts +56 -2
- package/src/lib/app-utils/platform-marketing-consent.js +6 -5
- package/src/lib/app-utils/platform-marketing-consent.js.map +1 -1
- package/src/lib/app-utils/plugin-api-rate-limit.d.ts +7 -1
- package/src/lib/app-utils/plugin-api-rate-limit.js +11 -3
- package/src/lib/app-utils/plugin-api-rate-limit.js.map +1 -1
- package/src/lib/app-utils/plugin-bundle-checks.js +2 -2
- package/src/lib/app-utils/plugin-bundle-checks.js.map +1 -1
- package/src/lib/app-utils/plugin-host-events.generated.d.ts +12 -0
- package/src/lib/app-utils/plugin-host-events.generated.js +169 -0
- package/src/lib/app-utils/plugin-host-events.generated.js.map +1 -0
- package/src/lib/app-utils/plugin-release-flags.generated.d.ts +12 -0
- package/src/lib/app-utils/plugin-release-flags.generated.js +106 -0
- package/src/lib/app-utils/plugin-release-flags.generated.js.map +1 -0
- package/src/lib/app-utils/plugin-starter-templates.generated.d.ts +12 -0
- package/src/lib/app-utils/plugin-starter-templates.generated.js +711 -0
- package/src/lib/app-utils/plugin-starter-templates.generated.js.map +1 -0
- package/src/lib/app-utils/realm-host-surface.generated.js +2 -0
- package/src/lib/app-utils/realm-host-surface.generated.js.map +1 -1
- package/src/lib/app-utils/release-flags.d.ts +14 -5
- package/src/lib/app-utils/release-flags.js +21 -125
- package/src/lib/app-utils/release-flags.js.map +1 -1
- package/src/lib/app-utils/repeat-query.d.ts +56 -0
- package/src/lib/app-utils/{dataset-query.js → repeat-query.js} +16 -16
- package/src/lib/app-utils/repeat-query.js.map +1 -0
- package/src/lib/app-utils/repeat-sources.d.ts +9 -0
- package/src/lib/app-utils/repeat-sources.js.map +1 -1
- package/src/lib/app-utils/retained-refusals.d.ts +73 -0
- package/src/lib/app-utils/retained-refusals.js +186 -0
- package/src/lib/app-utils/retained-refusals.js.map +1 -0
- package/src/lib/app-utils/scope-tokens.d.ts +27 -0
- package/src/lib/app-utils/scope-tokens.js +61 -0
- package/src/lib/app-utils/scope-tokens.js.map +1 -1
- package/src/lib/app-utils/screen-link-context.js +3 -3
- package/src/lib/app-utils/screen-link-context.js.map +1 -1
- package/src/lib/app-utils/screen-route.js +1 -1
- package/src/lib/app-utils/screen-route.js.map +1 -1
- package/src/lib/app-utils/seo-audit.d.ts +132 -0
- package/src/lib/app-utils/seo-audit.js +246 -0
- package/src/lib/app-utils/seo-audit.js.map +1 -0
- package/src/lib/app-utils/seo-keywords.d.ts +48 -0
- package/src/lib/app-utils/seo-keywords.js +60 -0
- package/src/lib/app-utils/seo-keywords.js.map +1 -0
- package/src/lib/app-utils/seo-page-facts.d.ts +66 -0
- package/src/lib/app-utils/seo-page-facts.js +155 -0
- package/src/lib/app-utils/seo-page-facts.js.map +1 -0
- package/src/lib/app-utils/seo-site-scan.d.ts +126 -0
- package/src/lib/app-utils/seo-site-scan.js +162 -0
- package/src/lib/app-utils/seo-site-scan.js.map +1 -0
- package/src/lib/app-utils/seo-title-variables.js +1 -1
- package/src/lib/app-utils/seo-title-variables.js.map +1 -1
- package/src/lib/app-utils/server.d.ts +13 -18
- package/src/lib/app-utils/server.js +33 -51
- package/src/lib/app-utils/server.js.map +1 -1
- package/src/lib/app-utils/site-interactions.d.ts +501 -0
- package/src/lib/app-utils/site-interactions.js +554 -0
- package/src/lib/app-utils/site-interactions.js.map +1 -0
- package/src/lib/app-utils/{marketplace-theme.d.ts → site-theme.d.ts} +13 -2
- package/src/lib/app-utils/{marketplace-theme.js → site-theme.js} +2 -2
- package/src/lib/app-utils/site-theme.js.map +1 -0
- package/src/lib/app-utils/sitemap.d.ts +4 -3
- package/src/lib/app-utils/sitemap.js +9 -7
- package/src/lib/app-utils/sitemap.js.map +1 -1
- package/src/lib/app-utils/stale-build-error.d.ts +51 -0
- package/src/lib/app-utils/stale-build-error.js +100 -1
- package/src/lib/app-utils/stale-build-error.js.map +1 -1
- package/src/lib/app-utils/starter-template-nodes.d.ts +137 -0
- package/src/lib/app-utils/starter-template-nodes.js +129 -0
- package/src/lib/app-utils/starter-template-nodes.js.map +1 -0
- package/src/lib/app-utils/starter-templates.d.ts +11 -34
- package/src/lib/app-utils/starter-templates.js +19 -230
- package/src/lib/app-utils/starter-templates.js.map +1 -1
- package/src/lib/app-utils/{email-topics.d.ts → subscription-topics.d.ts} +64 -48
- package/src/lib/app-utils/{email-topics.js → subscription-topics.js} +39 -109
- package/src/lib/app-utils/subscription-topics.js.map +1 -0
- package/src/lib/app-utils/tax-jurisdiction-figures.d.ts +118 -0
- package/src/lib/app-utils/tax-jurisdiction-figures.js +123 -0
- package/src/lib/app-utils/tax-jurisdiction-figures.js.map +1 -0
- package/src/lib/app-utils/theme-library.d.ts +10 -3
- package/src/lib/app-utils/theme-library.js +13 -4
- package/src/lib/app-utils/theme-library.js.map +1 -1
- package/src/lib/app-utils/usage-budget.d.ts +73 -188
- package/src/lib/app-utils/usage-budget.js +58 -194
- package/src/lib/app-utils/usage-budget.js.map +1 -1
- package/src/lib/app-utils/{campaign-attribution.d.ts → utm-attribution.d.ts} +11 -6
- package/src/lib/app-utils/{campaign-attribution.js → utm-attribution.js} +13 -8
- package/src/lib/app-utils/utm-attribution.js.map +1 -0
- package/src/lib/app-utils/{campaign-forwarding.d.ts → utm-forwarding.d.ts} +14 -14
- package/src/lib/app-utils/{campaign-forwarding.js → utm-forwarding.js} +26 -26
- package/src/lib/app-utils/utm-forwarding.js.map +1 -0
- package/src/lib/app-utils/{campaign-touch.d.ts → utm-touch.d.ts} +25 -17
- package/src/lib/app-utils/{campaign-touch.js → utm-touch.js} +38 -30
- package/src/lib/app-utils/utm-touch.js.map +1 -0
- package/src/lib/app-utils/variables.d.ts +9 -9
- package/src/lib/app-utils/variables.js.map +1 -1
- package/src/lib/app-utils/video-object.js +6 -5
- package/src/lib/app-utils/video-object.js.map +1 -1
- package/src/lib/app-utils/visitor-consent.d.ts +41 -164
- package/src/lib/app-utils/visitor-consent.js +66 -277
- package/src/lib/app-utils/visitor-consent.js.map +1 -1
- package/src/lib/app-utils/visitor-record-ceiling.d.ts +32 -0
- package/src/lib/app-utils/visitor-record-ceiling.js +39 -0
- package/src/lib/app-utils/visitor-record-ceiling.js.map +1 -1
- package/src/lib/app-utils/web-vitals-rum.d.ts +7 -7
- package/src/lib/app-utils/web-vitals-rum.js +31 -63
- package/src/lib/app-utils/web-vitals-rum.js.map +1 -1
- package/src/lib/app-utils/where-used.d.ts +11 -6
- package/src/lib/app-utils/where-used.js +3 -8
- package/src/lib/app-utils/where-used.js.map +1 -1
- package/src/lib/foundation/definitions/components.types.d.ts +1 -1
- package/src/lib/foundation/definitions/components.types.js +1 -1
- package/src/lib/foundation/definitions/components.types.js.map +1 -1
- package/src/lib/foundation/definitions/org-billing.types.d.ts +11 -137
- package/src/lib/foundation/definitions/org-billing.types.js.map +1 -1
- package/src/lib/foundation/definitions/organization.types.d.ts +1 -3
- package/src/lib/foundation/definitions/organization.types.js.map +1 -1
- package/src/lib/foundation/definitions/platform.types.d.ts +11 -5
- package/src/lib/foundation/definitions/platform.types.js.map +1 -1
- package/src/lib/foundation/definitions/write-deny-coverage.util.d.ts +16 -0
- package/src/lib/foundation/definitions/write-deny-coverage.util.js +20 -0
- package/src/lib/foundation/definitions/write-deny-coverage.util.js.map +1 -1
- package/src/lib/foundation/index.d.ts +1 -1
- package/src/lib/foundation/index.js.map +1 -1
- package/src/lib/plugin-manager/besigner-documents.d.ts +96 -0
- package/src/lib/plugin-manager/besigner-documents.js +61 -0
- package/src/lib/plugin-manager/besigner-documents.js.map +1 -0
- package/src/lib/plugin-manager/computed-variables.d.ts +71 -0
- package/src/lib/plugin-manager/computed-variables.js +74 -0
- package/src/lib/plugin-manager/computed-variables.js.map +1 -0
- package/src/lib/plugin-manager/custom-fields.d.ts +29 -2
- package/src/lib/plugin-manager/custom-fields.js +47 -1
- package/src/lib/plugin-manager/custom-fields.js.map +1 -1
- package/src/lib/plugin-manager/feature-plugins.d.ts +372 -99
- package/src/lib/plugin-manager/feature-plugins.js +126 -51
- package/src/lib/plugin-manager/feature-plugins.js.map +1 -1
- package/src/lib/plugin-manager/first-party-plugins.generated.d.ts +134 -0
- package/src/lib/plugin-manager/first-party-plugins.generated.js +840 -10
- package/src/lib/plugin-manager/first-party-plugins.generated.js.map +1 -1
- package/src/lib/plugin-manager/index.d.ts +0 -1
- package/src/lib/plugin-manager/index.js +0 -1
- package/src/lib/plugin-manager/index.js.map +1 -1
- package/src/lib/plugin-manager/plugin-activity-actions.d.ts +12 -0
- package/src/lib/plugin-manager/plugin-activity-actions.js +25 -0
- package/src/lib/plugin-manager/plugin-activity-actions.js.map +1 -1
- package/src/lib/plugin-manager/plugin-contact-capture.d.ts +9 -4
- package/src/lib/plugin-manager/plugin-contact-capture.js.map +1 -1
- package/src/lib/plugin-manager/plugin-containers.d.ts +68 -0
- package/src/lib/plugin-manager/plugin-containers.generated.d.ts +10 -0
- package/src/lib/plugin-manager/plugin-containers.generated.js +20 -0
- package/src/lib/plugin-manager/plugin-containers.generated.js.map +1 -0
- package/src/lib/plugin-manager/plugin-containers.js +27 -0
- package/src/lib/plugin-manager/plugin-containers.js.map +1 -0
- package/src/lib/plugin-manager/plugin-contributions.d.ts +1 -1
- package/src/lib/plugin-manager/plugin-contributions.js.map +1 -1
- package/src/lib/plugin-manager/plugin-declarations-repair.d.ts +36 -0
- package/src/lib/plugin-manager/plugin-declarations-repair.js +64 -0
- package/src/lib/plugin-manager/plugin-declarations-repair.js.map +1 -0
- package/src/lib/plugin-manager/plugin-dependents.d.ts +101 -0
- package/src/lib/plugin-manager/plugin-dependents.js +75 -0
- package/src/lib/plugin-manager/plugin-dependents.js.map +1 -0
- package/src/lib/plugin-manager/plugin-distribution.d.ts +55 -0
- package/src/lib/plugin-manager/plugin-distribution.js +45 -0
- package/src/lib/plugin-manager/plugin-distribution.js.map +1 -0
- package/src/lib/plugin-manager/plugin-entitlements.d.ts +8 -0
- package/src/lib/plugin-manager/plugin-entitlements.js.map +1 -1
- package/src/lib/plugin-manager/plugin-host-collections.d.ts +17 -0
- package/src/lib/plugin-manager/plugin-host-collections.js +6 -0
- package/src/lib/plugin-manager/plugin-host-collections.js.map +1 -1
- package/src/lib/plugin-manager/plugin-host-resources.d.ts +133 -0
- package/src/lib/plugin-manager/plugin-host-resources.js +52 -0
- package/src/lib/plugin-manager/plugin-host-resources.js.map +1 -0
- package/src/lib/plugin-manager/plugin-membership-detach.js +1 -1
- package/src/lib/plugin-manager/plugin-membership-detach.js.map +1 -1
- package/src/lib/plugin-manager/plugin-org-erasure.d.ts +28 -2
- package/src/lib/plugin-manager/plugin-org-erasure.js +61 -2
- package/src/lib/plugin-manager/plugin-org-erasure.js.map +1 -1
- package/src/lib/plugin-manager/plugin-plan-entitlements.d.ts +123 -0
- package/src/lib/plugin-manager/plugin-plan-entitlements.js +101 -0
- package/src/lib/plugin-manager/plugin-plan-entitlements.js.map +1 -0
- package/src/lib/plugin-manager/plugin-record-email-state.d.ts +69 -0
- package/src/lib/plugin-manager/plugin-record-email-state.js +32 -0
- package/src/lib/plugin-manager/plugin-record-email-state.js.map +1 -1
- package/src/lib/plugin-manager/plugin-record-index.d.ts +95 -0
- package/src/lib/plugin-manager/plugin-record-index.js +51 -0
- package/src/lib/plugin-manager/plugin-record-index.js.map +1 -0
- package/src/lib/plugin-manager/plugin-record-lists.d.ts +115 -0
- package/src/lib/plugin-manager/plugin-record-lists.js +75 -0
- package/src/lib/plugin-manager/plugin-record-lists.js.map +1 -0
- package/src/lib/plugin-manager/plugin-record-timeline.d.ts +42 -8
- package/src/lib/plugin-manager/plugin-record-timeline.js.map +1 -1
- package/src/lib/plugin-manager/plugin-record-written.d.ts +58 -0
- package/src/lib/plugin-manager/plugin-record-written.js +42 -0
- package/src/lib/plugin-manager/plugin-record-written.js.map +1 -0
- package/src/lib/plugin-manager/plugin-revenue-sources.d.ts +213 -0
- package/src/lib/plugin-manager/plugin-revenue-sources.js +194 -0
- package/src/lib/plugin-manager/plugin-revenue-sources.js.map +1 -0
- package/src/lib/plugin-manager/plugin-site-beacons.d.ts +71 -0
- package/src/lib/plugin-manager/plugin-site-beacons.js +54 -0
- package/src/lib/plugin-manager/plugin-site-beacons.js.map +1 -0
- package/src/lib/plugin-manager/plugin-site-bundle.d.ts +145 -0
- package/src/lib/plugin-manager/plugin-site-bundle.js +78 -0
- package/src/lib/plugin-manager/plugin-site-bundle.js.map +1 -0
- package/src/lib/plugin-manager/plugin-site-cache.d.ts +12 -0
- package/src/lib/plugin-manager/plugin-site-cache.js.map +1 -1
- package/src/lib/plugin-manager/plugin-site-export.d.ts +81 -0
- package/src/lib/plugin-manager/plugin-site-export.js +40 -0
- package/src/lib/plugin-manager/plugin-site-export.js.map +1 -0
- package/src/lib/plugin-manager/plugin-sitemap-sections.d.ts +88 -0
- package/src/lib/plugin-manager/plugin-sitemap-sections.js +29 -0
- package/src/lib/plugin-manager/plugin-sitemap-sections.js.map +1 -0
- package/src/lib/plugin-manager/plugin-subscription-topics.generated.d.ts +11 -0
- package/src/lib/plugin-manager/plugin-subscription-topics.generated.js +41 -0
- package/src/lib/plugin-manager/plugin-subscription-topics.generated.js.map +1 -0
- package/src/lib/plugin-manager/plugin-tax-profile.d.ts +20 -4
- package/src/lib/plugin-manager/plugin-tax-profile.js.map +1 -1
- package/src/lib/plugin-manager/plugin-tax-return-sources.d.ts +255 -0
- package/src/lib/plugin-manager/plugin-tax-return-sources.js +191 -0
- package/src/lib/plugin-manager/plugin-tax-return-sources.js.map +1 -0
- package/src/lib/plugin-manager/plugin-template-sources.d.ts +75 -0
- package/src/lib/plugin-manager/plugin-template-sources.js +37 -0
- package/src/lib/plugin-manager/plugin-template-sources.js.map +1 -0
- package/src/lib/plugin-manager/plugin-usage-axes.d.ts +319 -0
- package/src/lib/plugin-manager/plugin-usage-axes.js +186 -0
- package/src/lib/plugin-manager/plugin-usage-axes.js.map +1 -0
- package/src/lib/plugin-manager/plugin-usage-meters.d.ts +108 -0
- package/src/lib/plugin-manager/plugin-usage-meters.js +105 -0
- package/src/lib/plugin-manager/plugin-usage-meters.js.map +1 -0
- package/src/lib/plugin-manager/plugin-zones.d.ts +4 -5
- package/src/lib/plugin-manager/plugin-zones.js.map +1 -1
- package/src/lib/plugin-manager/realm-host-aglyn.generated.js +2 -0
- package/src/lib/plugin-manager/realm-host-aglyn.generated.js.map +1 -1
- package/src/lib/plugin-manager/record-captured-contact.d.ts +1 -14
- package/src/lib/plugin-manager/record-captured-contact.js +10 -32
- package/src/lib/plugin-manager/record-captured-contact.js.map +1 -1
- package/src/lib/plugin-manager/repeat-rows.d.ts +124 -0
- package/src/lib/plugin-manager/repeat-rows.js +108 -0
- package/src/lib/plugin-manager/repeat-rows.js.map +1 -0
- package/src/lib/plugin-manager/submission-record-target.d.ts +144 -0
- package/src/lib/plugin-manager/submission-record-target.js +125 -0
- package/src/lib/plugin-manager/submission-record-target.js.map +1 -0
- package/src/lib/plugin-manager/usage-alert-contributors.d.ts +76 -6
- package/src/lib/plugin-manager/usage-alert-contributors.js +23 -10
- package/src/lib/plugin-manager/usage-alert-contributors.js.map +1 -1
- package/src/lib/plugin-manager/video-embed-provider.d.ts +108 -0
- package/src/lib/plugin-manager/video-embed-provider.js +165 -0
- package/src/lib/plugin-manager/video-embed-provider.js.map +1 -0
- package/src/lib/types/nodes.d.ts +2 -2
- package/src/lib/types/nodes.js.map +1 -1
- package/src/lib/app-utils/assist-credits.d.ts +0 -482
- package/src/lib/app-utils/assist-credits.js +0 -509
- package/src/lib/app-utils/assist-credits.js.map +0 -1
- package/src/lib/app-utils/campaign-attribution.js.map +0 -1
- package/src/lib/app-utils/campaign-forwarding.js.map +0 -1
- package/src/lib/app-utils/campaign-membership.d.ts +0 -121
- package/src/lib/app-utils/campaign-membership.js +0 -189
- package/src/lib/app-utils/campaign-membership.js.map +0 -1
- package/src/lib/app-utils/campaign-touch.js.map +0 -1
- package/src/lib/app-utils/console-record-links.d.ts +0 -163
- package/src/lib/app-utils/console-record-links.js +0 -180
- package/src/lib/app-utils/console-record-links.js.map +0 -1
- package/src/lib/app-utils/contact-holder.d.ts +0 -68
- package/src/lib/app-utils/contact-holder.js +0 -129
- package/src/lib/app-utils/contact-holder.js.map +0 -1
- package/src/lib/app-utils/contact-merge.d.ts +0 -136
- package/src/lib/app-utils/contact-merge.js +0 -412
- package/src/lib/app-utils/contact-merge.js.map +0 -1
- package/src/lib/app-utils/crm-booking.d.ts +0 -75
- package/src/lib/app-utils/crm-booking.js +0 -133
- package/src/lib/app-utils/crm-booking.js.map +0 -1
- package/src/lib/app-utils/crm-csv.d.ts +0 -239
- package/src/lib/app-utils/crm-csv.js +0 -467
- package/src/lib/app-utils/crm-csv.js.map +0 -1
- package/src/lib/app-utils/crm-digest.d.ts +0 -185
- package/src/lib/app-utils/crm-digest.js +0 -272
- package/src/lib/app-utils/crm-digest.js.map +0 -1
- package/src/lib/app-utils/crm-inbound.d.ts +0 -245
- package/src/lib/app-utils/crm-inbound.js +0 -407
- package/src/lib/app-utils/crm-inbound.js.map +0 -1
- package/src/lib/app-utils/crm-reports.d.ts +0 -479
- package/src/lib/app-utils/crm-reports.js +0 -680
- package/src/lib/app-utils/crm-reports.js.map +0 -1
- package/src/lib/app-utils/dataset-csv.js.map +0 -1
- package/src/lib/app-utils/dataset-query.d.ts +0 -57
- package/src/lib/app-utils/dataset-query.js.map +0 -1
- package/src/lib/app-utils/email-topics.js.map +0 -1
- package/src/lib/app-utils/form-dataset-binding.d.ts +0 -50
- package/src/lib/app-utils/form-dataset-binding.js +0 -74
- package/src/lib/app-utils/form-dataset-binding.js.map +0 -1
- package/src/lib/app-utils/list-assignment-policy.js.map +0 -1
- package/src/lib/app-utils/list-import.d.ts +0 -158
- package/src/lib/app-utils/list-import.js +0 -332
- package/src/lib/app-utils/list-import.js.map +0 -1
- package/src/lib/app-utils/marketplace-listing-visibility.d.ts +0 -122
- package/src/lib/app-utils/marketplace-listing-visibility.js +0 -147
- package/src/lib/app-utils/marketplace-listing-visibility.js.map +0 -1
- package/src/lib/app-utils/marketplace-overrides.js.map +0 -1
- package/src/lib/app-utils/marketplace-provenance.js.map +0 -1
- package/src/lib/app-utils/marketplace-theme.js.map +0 -1
- package/src/lib/app-utils/marketplace-update-state.d.ts +0 -119
- package/src/lib/app-utils/marketplace-update-state.js +0 -132
- package/src/lib/app-utils/marketplace-update-state.js.map +0 -1
- package/src/lib/app-utils/publisher-agreement.d.ts +0 -289
- package/src/lib/app-utils/publisher-agreement.js +0 -321
- package/src/lib/app-utils/publisher-agreement.js.map +0 -1
- package/src/lib/app-utils/wistia-embed.d.ts +0 -104
- package/src/lib/app-utils/wistia-embed.js +0 -138
- package/src/lib/app-utils/wistia-embed.js.map +0 -1
- package/src/lib/app-utils/workflows.d.ts +0 -136
- package/src/lib/app-utils/workflows.js +0 -346
- package/src/lib/app-utils/workflows.js.map +0 -1
- package/src/lib/plugin-manager/commerce-zone-props.d.ts +0 -172
- package/src/lib/plugin-manager/commerce-zone-props.js +0 -31
- package/src/lib/plugin-manager/commerce-zone-props.js.map +0 -1
- package/src/lib/plugin-manager/plugin-metered-lines.d.ts +0 -97
- package/src/lib/plugin-manager/plugin-metered-lines.js +0 -123
- package/src/lib/plugin-manager/plugin-metered-lines.js.map +0 -1
|
@@ -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;
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/ /**
|
|
17
|
-
* Carry the
|
|
17
|
+
* Carry the visit's UTM labels across the domain hop (AGL-1731).
|
|
18
18
|
*
|
|
19
|
-
* `
|
|
19
|
+
* `utm-attribution.ts` is the READER half of this contract and it works.
|
|
20
20
|
* This is the half that was missing, and without it the reader was fed
|
|
21
21
|
* nothing: `aglyn.com` is a tenant published site and `app.aglyn.com` is the
|
|
22
22
|
* console, a real cross-origin hop, and no code anywhere put a `utm_*`
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
* it. There is no default, no inference from the referrer, and no
|
|
95
95
|
* `utm_source=direct` — a signup with no campaign must reach the console with
|
|
96
96
|
* no campaign, so that "arrived from nowhere" and "never asked" stay the
|
|
97
|
-
* distinct facts `
|
|
97
|
+
* distinct facts `utm-attribution.ts` keeps them.
|
|
98
98
|
*
|
|
99
99
|
* Only links to OUR OWN console origin are touched, and the origin is supplied
|
|
100
100
|
* by the caller rather than written here — a self-host install points
|
|
@@ -113,13 +113,13 @@
|
|
|
113
113
|
* set it would forward NOTHING while looking perfectly healthy. A silent zero
|
|
114
114
|
* is the exact failure AGL-1731 is about, and it is worse than a few
|
|
115
115
|
* mislabelled rows that GA's own Hostname dimension can already separate.
|
|
116
|
-
*/ import {
|
|
116
|
+
*/ import { UTM_QUERY_KEYS, utmAttributionQuery, parseUtmAttribution } from "./utm-attribution.js";
|
|
117
117
|
/**
|
|
118
118
|
* Where the first touch of this visit is held. `sessionStorage`, so it dies
|
|
119
119
|
* with the tab: a campaign is a fact about one visit, and a value that
|
|
120
120
|
* outlived the visit would start attributing next week's organic return to
|
|
121
121
|
* this week's ad.
|
|
122
|
-
*/ export const
|
|
122
|
+
*/ export const UTM_VISIT_STORAGE_KEY = 'aglyn:campaign';
|
|
123
123
|
/**
|
|
124
124
|
* Whether the visitor has granted analytics storage.
|
|
125
125
|
*
|
|
@@ -149,7 +149,7 @@ function sessionStore() {
|
|
|
149
149
|
* `sessionStorage` is writable by anything running on the page, so the stored
|
|
150
150
|
* string can claim no more than an inbound URL could — three allowlisted keys,
|
|
151
151
|
* trimmed, email shapes refused, capped.
|
|
152
|
-
*/ export function
|
|
152
|
+
*/ export function readVisitUtm() {
|
|
153
153
|
if (storageConsent !== true) return {
|
|
154
154
|
status: 'none'
|
|
155
155
|
};
|
|
@@ -159,7 +159,7 @@ function sessionStore() {
|
|
|
159
159
|
};
|
|
160
160
|
let raw;
|
|
161
161
|
try {
|
|
162
|
-
raw = store.getItem(
|
|
162
|
+
raw = store.getItem(UTM_VISIT_STORAGE_KEY);
|
|
163
163
|
} catch (unused) {
|
|
164
164
|
return {
|
|
165
165
|
status: 'unreadable'
|
|
@@ -168,7 +168,7 @@ function sessionStore() {
|
|
|
168
168
|
if (!raw) return {
|
|
169
169
|
status: 'none'
|
|
170
170
|
};
|
|
171
|
-
const campaign =
|
|
171
|
+
const campaign = parseUtmAttribution(new URLSearchParams(raw));
|
|
172
172
|
return campaign ? {
|
|
173
173
|
status: 'campaign',
|
|
174
174
|
campaign
|
|
@@ -185,17 +185,17 @@ function sessionStore() {
|
|
|
185
185
|
* quietly turn this into last-touch.
|
|
186
186
|
*
|
|
187
187
|
* Returns what is now remembered so a caller can assert on it.
|
|
188
|
-
*/ export function
|
|
189
|
-
const existing =
|
|
188
|
+
*/ export function rememberVisitUtm(search) {
|
|
189
|
+
const existing = readVisitUtm();
|
|
190
190
|
if (existing.status === 'campaign') return existing.campaign;
|
|
191
191
|
if (storageConsent !== true) return null;
|
|
192
192
|
const store = sessionStore();
|
|
193
193
|
if (!store) return null;
|
|
194
194
|
const source = typeof search === 'string' ? search : typeof window === 'undefined' ? '' : window.location.search;
|
|
195
|
-
const campaign =
|
|
195
|
+
const campaign = parseUtmAttribution(new URLSearchParams(source));
|
|
196
196
|
if (!campaign) return null;
|
|
197
197
|
try {
|
|
198
|
-
store.setItem(
|
|
198
|
+
store.setItem(UTM_VISIT_STORAGE_KEY, utmAttributionQuery(campaign));
|
|
199
199
|
} catch (unused) {
|
|
200
200
|
// A store that refuses the write costs the walk from the landing page to
|
|
201
201
|
// the pricing page, never the click itself — tier 1 still carries a
|
|
@@ -212,17 +212,17 @@ function sessionStore() {
|
|
|
212
212
|
* effect immediately: the stored value is dropped, not merely ignored. A
|
|
213
213
|
* visitor who changes their mind mid-visit should not leave the thing they
|
|
214
214
|
* withdrew consent for sitting on their device.
|
|
215
|
-
*/ export function
|
|
215
|
+
*/ export function setUtmForwardingConsent(allowed) {
|
|
216
216
|
storageConsent = allowed === true ? true : allowed === false ? false : null;
|
|
217
217
|
if (storageConsent === true) {
|
|
218
|
-
|
|
218
|
+
rememberVisitUtm();
|
|
219
219
|
return;
|
|
220
220
|
}
|
|
221
221
|
if (storageConsent === false) {
|
|
222
222
|
const store = sessionStore();
|
|
223
223
|
if (!store) return;
|
|
224
224
|
try {
|
|
225
|
-
store.removeItem(
|
|
225
|
+
store.removeItem(UTM_VISIT_STORAGE_KEY);
|
|
226
226
|
} catch (unused) {
|
|
227
227
|
// Nothing else to try, and a failed cleanup must not break the page.
|
|
228
228
|
}
|
|
@@ -234,11 +234,11 @@ function sessionStore() {
|
|
|
234
234
|
* The `unreadable` case falls through to the live URL rather than to nothing,
|
|
235
235
|
* which is the point of carrying that state at all: a broken store degrades
|
|
236
236
|
* this to tier 1 rather than to silence.
|
|
237
|
-
*/ export function
|
|
238
|
-
const stored =
|
|
237
|
+
*/ export function utmToForward(search) {
|
|
238
|
+
const stored = readVisitUtm();
|
|
239
239
|
if (stored.status === 'campaign') return stored.campaign;
|
|
240
240
|
const live = typeof search === 'string' ? search : typeof window === 'undefined' ? '' : window.location.search;
|
|
241
|
-
return
|
|
241
|
+
return parseUtmAttribution(new URLSearchParams(live));
|
|
242
242
|
}
|
|
243
243
|
function normalizeOrigin(value) {
|
|
244
244
|
if (!value) return '';
|
|
@@ -261,7 +261,7 @@ function normalizeOrigin(value) {
|
|
|
261
261
|
* three must not produce `source=hn` married to the author's `campaign=`: that
|
|
262
262
|
* row describes an event that never happened. Everything else on the href —
|
|
263
263
|
* `plan`, `interval`, the AGL-1535 intent — is preserved untouched.
|
|
264
|
-
*/ export function
|
|
264
|
+
*/ export function decorateUtmHref(href, baseHref, consoleOrigin, campaign) {
|
|
265
265
|
if (!campaign) return null;
|
|
266
266
|
const origin = normalizeOrigin(consoleOrigin);
|
|
267
267
|
if (!origin) return null;
|
|
@@ -272,8 +272,8 @@ function normalizeOrigin(value) {
|
|
|
272
272
|
return null;
|
|
273
273
|
}
|
|
274
274
|
if (url.origin !== origin) return null;
|
|
275
|
-
for (const key of
|
|
276
|
-
const query = new URLSearchParams(
|
|
275
|
+
for (const key of UTM_QUERY_KEYS)url.searchParams.delete(key);
|
|
276
|
+
const query = new URLSearchParams(utmAttributionQuery(campaign));
|
|
277
277
|
query.forEach((value, key)=>url.searchParams.set(key, value));
|
|
278
278
|
const next = url.toString();
|
|
279
279
|
return next === href ? null : next;
|
|
@@ -295,7 +295,7 @@ function normalizeOrigin(value) {
|
|
|
295
295
|
*
|
|
296
296
|
* Returns an uninstall function for tests and for a caller that owns the page
|
|
297
297
|
* lifecycle.
|
|
298
|
-
*/ export function
|
|
298
|
+
*/ export function installUtmForwarding(options) {
|
|
299
299
|
if (typeof document === 'undefined' || typeof window === 'undefined') {
|
|
300
300
|
return ()=>undefined;
|
|
301
301
|
}
|
|
@@ -308,7 +308,7 @@ function normalizeOrigin(value) {
|
|
|
308
308
|
if (!target || typeof target.closest !== 'function') return;
|
|
309
309
|
const anchor = target.closest('a[href]');
|
|
310
310
|
if (!anchor) return;
|
|
311
|
-
const decorated =
|
|
311
|
+
const decorated = decorateUtmHref(anchor.getAttribute('href') || '', window.location.href, origin, utmToForward());
|
|
312
312
|
if (decorated) anchor.setAttribute('href', decorated);
|
|
313
313
|
} catch (unused) {
|
|
314
314
|
// Attribution never breaks a navigation. A link that throws here would
|
|
@@ -318,9 +318,9 @@ function normalizeOrigin(value) {
|
|
|
318
318
|
installedHandler = onActivate;
|
|
319
319
|
document.addEventListener('pointerdown', onActivate, true);
|
|
320
320
|
document.addEventListener('click', onActivate, true);
|
|
321
|
-
return
|
|
321
|
+
return resetUtmForwarding;
|
|
322
322
|
}
|
|
323
|
-
/** Test seam — removes both listeners, forgets them, and forgets consent. */ export function
|
|
323
|
+
/** Test seam — removes both listeners, forgets them, and forgets consent. */ export function resetUtmForwarding() {
|
|
324
324
|
if (installedHandler && typeof document !== 'undefined') {
|
|
325
325
|
document.removeEventListener('pointerdown', installedHandler, true);
|
|
326
326
|
document.removeEventListener('click', installedHandler, true);
|
|
@@ -329,4 +329,4 @@ function normalizeOrigin(value) {
|
|
|
329
329
|
storageConsent = null;
|
|
330
330
|
}
|
|
331
331
|
|
|
332
|
-
//# sourceMappingURL=
|
|
332
|
+
//# sourceMappingURL=utm-forwarding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/utm-forwarding.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 * Carry the visit's UTM labels across the domain hop (AGL-1731).\n *\n * `utm-attribution.ts` is the READER half of this contract and it works.\n * This is the half that was missing, and without it the reader was fed\n * nothing: `aglyn.com` is a tenant published site and `app.aglyn.com` is the\n * console, a real cross-origin hop, and no code anywhere put a `utm_*`\n * parameter on a console-bound link. So `users/{uid}.signupCampaign` was\n * written for exactly one population — visitors whose CTA href had a campaign\n * typed into it by hand.\n *\n * A hand-typed one is worse than none. It is STATIC: `utm_source=google`\n * authored onto the pricing button attributes every clicker to Google whether\n * they arrived from Google, from Hacker News or from a bookmark. Confidently\n * wrong attribution reaches the same spend decisions as absent attribution and\n * is much harder to notice, because the report looks populated.\n *\n * What is needed instead is PER-VISITOR forwarding: the landing page copies\n * the campaign off its own inbound URL onto the console-bound href, at click\n * time, for that one visitor.\n *\n * ## Why a delegated listener and not `AppLink`\n *\n * The same reason `analytics-link-clicks.ts` gives, and it is the reason that\n * decides this file's shape. The CTAs on `aglyn.com` are authored besigner\n * content, not repo files; rich-text and Custom HTML anchors are written with\n * `dangerouslySetInnerHTML` and are plain DOM anchors with no React handler at\n * all. A prop on `AppLink` would miss them, and reaching them from `AppLink`\n * would mean `useSearchParams` in a component the console renders on every\n * page — a dynamic-rendering hazard on statically generated surfaces, paid on\n * every route to fix a link on one of them. A capture-phase listener on\n * `document` sees every anchor, costs one listener, and renders nothing.\n *\n * ## The two tiers, and why the storage tier is the SECOND one\n *\n * A visitor rarely signs up from the page the ad landed on. They land on\n * `/?utm_source=google&...`, read `/pricing`, then click. By then the campaign\n * is off the address bar, so reading the live URL at click time alone would\n * capture only the minority who convert without navigating.\n *\n * - **Tier 1 — the live URL.** Read `window.location.search` at click time.\n * This touches NO storage: the parameters are already in the page the\n * visitor asked for. Nothing is written to their device, so there is nothing\n * here to consent to, and it works for every visitor including one who has\n * declined analytics.\n * - **Tier 2 — the first touch of the visit**, in `sessionStorage`, which is\n * what survives the walk from the landing page to the pricing page.\n *\n * Tier 2 WINS when both exist, because first touch is the question being\n * asked. Last touch — re-deriving the campaign from whatever URL happens to be\n * current at signup — answers a different question and would disagree with\n * GA4's own session attribution.\n *\n * ## Why tier 2 is gated on analytics consent, and tier 1 is not\n *\n * Tier 2 writes to the visitor's device for an analytics purpose, so it is\n * `analytics_storage` in the consent-mode sense and it waits for the same\n * grant the GA tag waits for (AGL-1498). The gate is not re-implemented here\n * and no consent record is read here: the caller already computes\n * `analyticsAllowed` for the tag and hands the same boolean down, so there is\n * one gate and it cannot drift from itself.\n *\n * It is deliberately NOT gated on advertising storage. Nothing here reads or\n * writes an advertising identifier, sets a cookie, or leaves anything that\n * outlives the tab, and AGL-1649 has advertising denied with no route for a\n * host to grant it — gating on a permission that cannot currently be given\n * would be a feature that is dead by construction rather than one that is off.\n *\n * **Consent unresolved is not consent denied, and both are falsy.** With\n * `strictNullChecks` off repo-wide that distinction is the sort that\n * evaporates, so it is carried as an explicit tri-state: until the caller has\n * actually resolved the visitor's state, tier 2 neither reads nor writes.\n * Failing closed here costs an attribution; failing open would write to a\n * device before the visitor answered.\n *\n * ## What is never done\n *\n * A value is only ever forwarded if this visitor literally arrived carrying\n * it. There is no default, no inference from the referrer, and no\n * `utm_source=direct` — a signup with no campaign must reach the console with\n * no campaign, so that \"arrived from nowhere\" and \"never asked\" stay the\n * distinct facts `utm-attribution.ts` keeps them.\n *\n * Only links to OUR OWN console origin are touched, and the origin is supplied\n * by the caller rather than written here — a self-host install points\n * `NEXT_PUBLIC_CONSOLE_URL` somewhere else entirely. Decorating any other host\n * would post our campaign labels to a third party, which is a data leak dressed\n * up as attribution.\n *\n * ## One accepted consequence\n *\n * The tenant runtime serves `aglyn.com` AND every customer's published site,\n * so a customer site that links to our signup forwards ITS OWN inbound\n * campaign — an agency partner's `utm_source=their-newsletter` would land in our\n * acquisition report describing their spend, not ours. It is not gated on\n * \"is this the operator's marketing host\" deliberately: that gate needs a\n * second configured origin to compare against, and a deployment that forgot to\n * set it would forward NOTHING while looking perfectly healthy. A silent zero\n * is the exact failure AGL-1731 is about, and it is worse than a few\n * mislabelled rows that GA's own Hostname dimension can already separate.\n */\n\nimport {\n UTM_QUERY_KEYS,\n utmAttributionQuery,\n parseUtmAttribution,\n type UtmAttribution,\n} from './utm-attribution'\n\n/**\n * Where the first touch of this visit is held. `sessionStorage`, so it dies\n * with the tab: a campaign is a fact about one visit, and a value that\n * outlived the visit would start attributing next week's organic return to\n * this week's ad.\n */\nexport const UTM_VISIT_STORAGE_KEY = 'aglyn:campaign'\n\n/**\n * What a read of the first-touch store produced.\n *\n * Three states rather than \"a campaign or null\", and the third is the whole\n * point. `sessionStorage` throws outright in some privacy modes, and a\n * `catch` that returned null would report \"this visitor named no campaign\" —\n * indistinguishable from an organic arrival, which is how an unreadable source\n * becomes a measured zero. `unreadable` is a different answer and the caller\n * treats it differently: it falls through to the live URL instead of\n * concluding anything.\n */\nexport type VisitUtmRead =\n | { status: 'campaign'; campaign: UtmAttribution }\n | { status: 'none' }\n | { status: 'unreadable' }\n\n/**\n * Whether the visitor has granted analytics storage.\n *\n * `null` means NOT YET RESOLVED, and is not the same as `false`. The consent\n * state is settled client-side after hydration, so there is a window in every\n * pageview where the answer is genuinely unknown, and treating it as a denial\n * would be as wrong as treating it as a grant. Tier 2 does nothing in it.\n */\nlet storageConsent: boolean | null = null\n\n/** The one listener pair on `document`, or null. Held, not flagged — the same\n * reason `analytics-link-clicks.ts` holds its own: a boolean lets a caller\n * install over a listener that is still attached, and re-entrant decoration is\n * harder to see than a double-counted event. */\nlet installedHandler: ((event: Event) => void) | null = null\n\nfunction sessionStore(): Storage | null {\n if (typeof window === 'undefined') return null\n // Touching the property itself can throw, not just its methods.\n try {\n return window.sessionStorage ?? null\n } catch {\n return null\n }\n}\n\n/**\n * The campaign this visit began with, as far as the store can say.\n *\n * Re-parsed through the same allowlist that wrote it rather than trusted:\n * `sessionStorage` is writable by anything running on the page, so the stored\n * string can claim no more than an inbound URL could — three allowlisted keys,\n * trimmed, email shapes refused, capped.\n */\nexport function readVisitUtm(): VisitUtmRead {\n if (storageConsent !== true) return { status: 'none' }\n const store = sessionStore()\n if (!store) return { status: 'unreadable' }\n let raw: string | null\n try {\n raw = store.getItem(UTM_VISIT_STORAGE_KEY)\n } catch {\n return { status: 'unreadable' }\n }\n if (!raw) return { status: 'none' }\n const campaign = parseUtmAttribution(new URLSearchParams(raw))\n return campaign ? { status: 'campaign', campaign } : { status: 'none' }\n}\n\n/**\n * Remember the campaign on the current URL as this visit's first touch.\n *\n * First touch means FIRST: an existing entry is never replaced. A second\n * campaign arriving later in the same visit is a link the visitor followed\n * after we already knew where they came from, and letting it overwrite would\n * quietly turn this into last-touch.\n *\n * Returns what is now remembered so a caller can assert on it.\n */\nexport function rememberVisitUtm(search?: string): UtmAttribution | null {\n const existing = readVisitUtm()\n if (existing.status === 'campaign') return existing.campaign\n if (storageConsent !== true) return null\n const store = sessionStore()\n if (!store) return null\n const source =\n typeof search === 'string'\n ? search\n : typeof window === 'undefined'\n ? ''\n : window.location.search\n const campaign = parseUtmAttribution(new URLSearchParams(source))\n if (!campaign) return null\n try {\n store.setItem(UTM_VISIT_STORAGE_KEY, utmAttributionQuery(campaign))\n } catch {\n // A store that refuses the write costs the walk from the landing page to\n // the pricing page, never the click itself — tier 1 still carries a\n // visitor who converts without navigating.\n return null\n }\n return campaign\n}\n\n/**\n * Tell this module what the visitor's analytics consent state is.\n *\n * Called by whoever already computed it for the tag, on every render, so a\n * grant seeds the first touch the moment it is given and a WITHDRAWAL takes\n * effect immediately: the stored value is dropped, not merely ignored. A\n * visitor who changes their mind mid-visit should not leave the thing they\n * withdrew consent for sitting on their device.\n */\nexport function setUtmForwardingConsent(allowed: boolean | null): void {\n storageConsent = allowed === true ? true : allowed === false ? false : null\n if (storageConsent === true) {\n rememberVisitUtm()\n return\n }\n if (storageConsent === false) {\n const store = sessionStore()\n if (!store) return\n try {\n store.removeItem(UTM_VISIT_STORAGE_KEY)\n } catch {\n // Nothing else to try, and a failed cleanup must not break the page.\n }\n }\n}\n\n/**\n * The campaign to forward, first touch preferred.\n *\n * The `unreadable` case falls through to the live URL rather than to nothing,\n * which is the point of carrying that state at all: a broken store degrades\n * this to tier 1 rather than to silence.\n */\nexport function utmToForward(search?: string): UtmAttribution | null {\n const stored = readVisitUtm()\n if (stored.status === 'campaign') return stored.campaign\n const live =\n typeof search === 'string'\n ? search\n : typeof window === 'undefined'\n ? ''\n : window.location.search\n return parseUtmAttribution(new URLSearchParams(live))\n}\n\nfunction normalizeOrigin(value: string | null | undefined): string {\n if (!value) return ''\n try {\n return new URL(value).origin\n } catch {\n return ''\n }\n}\n\n/**\n * The href a console-bound link should carry for this visitor, or null to\n * leave it exactly as authored.\n *\n * Null — rather than \"the href unchanged\" — so that a caller cannot write back\n * a value it did not mean to change, and so a test can tell \"decided not to\n * touch this\" from \"touched it and produced the same string\".\n *\n * The three keys are replaced WHOLESALE, never merged key by key. A visitor\n * who arrived with only `utm_source=hn` clicking a button authored with all\n * three must not produce `source=hn` married to the author's `campaign=`: that\n * row describes an event that never happened. Everything else on the href —\n * `plan`, `interval`, the AGL-1535 intent — is preserved untouched.\n */\nexport function decorateUtmHref(\n href: string,\n baseHref: string,\n consoleOrigin: string,\n campaign: UtmAttribution | null,\n): string | null {\n if (!campaign) return null\n const origin = normalizeOrigin(consoleOrigin)\n if (!origin) return null\n let url: URL\n try {\n url = new URL(href, baseHref)\n } catch {\n return null\n }\n if (url.origin !== origin) return null\n for (const key of UTM_QUERY_KEYS) url.searchParams.delete(key)\n const query = new URLSearchParams(utmAttributionQuery(campaign))\n query.forEach((value, key) => url.searchParams.set(key, value))\n const next = url.toString()\n return next === href ? null : next\n}\n\n/**\n * Start forwarding the campaign onto console-bound links on this page.\n *\n * Idempotent and safe to call during render, the same contract as\n * `installLinkClickTracking` and for the same AGL-1550 reason: an effect only\n * runs if React commits, and a page that renders without committing would\n * otherwise ship links with no campaign on them.\n *\n * Both `pointerdown` and `click` are listened for, in capture phase.\n * `pointerdown` is what covers a middle-click, a modifier-click into a new\n * tab, and \"Copy link address\" from the context menu — all of which read the\n * href without ever firing `click`. `click` is what covers keyboard\n * activation, which fires no pointer event at all. Decoration is idempotent,\n * so a plain left click doing both is not a problem.\n *\n * Returns an uninstall function for tests and for a caller that owns the page\n * lifecycle.\n */\nexport function installUtmForwarding(options: {\n consoleOrigin: string\n}): () => void {\n if (typeof document === 'undefined' || typeof window === 'undefined') {\n return () => undefined\n }\n if (installedHandler) return () => undefined\n const origin = normalizeOrigin(options?.consoleOrigin)\n if (!origin) return () => undefined\n\n const onActivate = (event: Event) => {\n try {\n const target = event.target as Element | null\n if (!target || typeof target.closest !== 'function') return\n const anchor = target.closest('a[href]')\n if (!anchor) return\n const decorated = decorateUtmHref(\n anchor.getAttribute('href') || '',\n window.location.href,\n origin,\n utmToForward(),\n )\n if (decorated) anchor.setAttribute('href', decorated)\n } catch {\n // Attribution never breaks a navigation. A link that throws here would\n // be a link that does not work, which costs more than the campaign does.\n }\n }\n\n installedHandler = onActivate\n document.addEventListener('pointerdown', onActivate, true)\n document.addEventListener('click', onActivate, true)\n return resetUtmForwarding\n}\n\n/** Test seam — removes both listeners, forgets them, and forgets consent. */\nexport function resetUtmForwarding(): void {\n if (installedHandler && typeof document !== 'undefined') {\n document.removeEventListener('pointerdown', installedHandler, true)\n document.removeEventListener('click', installedHandler, true)\n }\n installedHandler = null\n storageConsent = null\n}\n"],"names":["UTM_QUERY_KEYS","utmAttributionQuery","parseUtmAttribution","UTM_VISIT_STORAGE_KEY","storageConsent","installedHandler","sessionStore","window","sessionStorage","readVisitUtm","status","store","raw","getItem","campaign","URLSearchParams","rememberVisitUtm","search","existing","source","location","setItem","setUtmForwardingConsent","allowed","removeItem","utmToForward","stored","live","normalizeOrigin","value","URL","origin","decorateUtmHref","href","baseHref","consoleOrigin","url","key","searchParams","delete","query","forEach","set","next","toString","installUtmForwarding","options","document","undefined","onActivate","event","target","closest","anchor","decorated","getAttribute","setAttribute","addEventListener","resetUtmForwarding","removeEventListener"],"mappings":"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"}
|
|
@@ -15,8 +15,13 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
/**
|
|
18
|
-
* THE VISITOR'S HALF OF
|
|
19
|
-
*
|
|
18
|
+
* THE VISITOR'S HALF OF ATTRIBUTION — the UTM touch that has to survive the
|
|
19
|
+
* gap between arriving from a labeled link and becoming somebody.
|
|
20
|
+
*
|
|
21
|
+
* The labels are the web's (`utm_source`/`utm_medium`/`utm_campaign`), not
|
|
22
|
+
* any plugin's model: every door that identifies a visitor — a form, a
|
|
23
|
+
* booking, a signup — attaches the touch, and whichever plugin credits its
|
|
24
|
+
* campaigns reads it on the server.
|
|
20
25
|
*
|
|
21
26
|
* ## The gap this exists to cross
|
|
22
27
|
*
|
|
@@ -42,7 +47,7 @@
|
|
|
42
47
|
*
|
|
43
48
|
* `localStorage`, expiring at {@link ATTRIBUTION_WINDOW_DAYS}.
|
|
44
49
|
*
|
|
45
|
-
* `
|
|
50
|
+
* `utm-forwarding.ts` holds its own campaign in `sessionStorage` and
|
|
46
51
|
* argues for it: a first touch that outlived the visit would start
|
|
47
52
|
* attributing next week's organic return to this week's ad. That argument is
|
|
48
53
|
* correct for the question it answers — which campaign produced THIS SIGNUP,
|
|
@@ -64,7 +69,7 @@
|
|
|
64
69
|
* The revenue join credits the LAST click, and a product where a lead and an
|
|
65
70
|
* order attribute by different rules is worse than one that is uniformly
|
|
66
71
|
* approximate. So a new campaign arrival OVERWRITES the stored one. This is
|
|
67
|
-
* the deliberate opposite of {@link
|
|
72
|
+
* the deliberate opposite of {@link rememberVisitUtm}, which keeps the
|
|
68
73
|
* first — that one describes a single visit's origin and this one describes
|
|
69
74
|
* which campaign most recently brought a person back.
|
|
70
75
|
*
|
|
@@ -104,7 +109,7 @@
|
|
|
104
109
|
* ## What is never carried
|
|
105
110
|
*
|
|
106
111
|
* Only the three allowlisted `utm_` labels, scrubbed by
|
|
107
|
-
* {@link
|
|
112
|
+
* {@link parseUtmAttribution} — which refuses an email-shaped value
|
|
108
113
|
* outright. No address, no person's identifier, no click id, nothing that
|
|
109
114
|
* names the visitor. A campaign link is exactly where putting a recipient in
|
|
110
115
|
* a query string would be tempting, and the parser is what makes it
|
|
@@ -120,13 +125,16 @@
|
|
|
120
125
|
* are the WEB channel's touch, and a campaign that carries none is joined by
|
|
121
126
|
* address instead.
|
|
122
127
|
*/
|
|
123
|
-
import { type
|
|
128
|
+
import { type UtmAttribution } from './utm-attribution';
|
|
124
129
|
/** Days between a campaign touch and a conversion it may be credited with. */
|
|
125
130
|
export declare const ATTRIBUTION_WINDOW_DAYS = 7;
|
|
126
131
|
/** The same window in milliseconds. */
|
|
127
132
|
export declare const ATTRIBUTION_WINDOW_MS: number;
|
|
128
|
-
/**
|
|
129
|
-
|
|
133
|
+
/**
|
|
134
|
+
* Where the touch is held. Namespaced like every other key this app sets, and
|
|
135
|
+
* spelled as visitors' devices already hold it.
|
|
136
|
+
*/
|
|
137
|
+
export declare const UTM_TOUCH_STORAGE_KEY = "aglyn:campaign-touch";
|
|
130
138
|
/**
|
|
131
139
|
* The parameter the touch's instant rides under inside the wire form.
|
|
132
140
|
*
|
|
@@ -135,17 +143,17 @@ export declare const CAMPAIGN_TOUCH_STORAGE_KEY = "aglyn:campaign-touch";
|
|
|
135
143
|
* by it or have to widen it. `t` is outside the allowlist and read
|
|
136
144
|
* separately.
|
|
137
145
|
*/
|
|
138
|
-
export declare const
|
|
146
|
+
export declare const UTM_TOUCH_TIME_KEY = "t";
|
|
139
147
|
/** A campaign the visitor arrived from, and when they arrived from it. */
|
|
140
|
-
export interface
|
|
148
|
+
export interface UtmTouch extends UtmAttribution {
|
|
141
149
|
/** When the visitor followed the campaign link, epoch ms. */
|
|
142
150
|
atMs: number;
|
|
143
151
|
}
|
|
144
152
|
/**
|
|
145
153
|
* The canonical stored form of a touch — the ONLY place it is written, so it
|
|
146
|
-
* cannot drift from what {@link
|
|
154
|
+
* cannot drift from what {@link parseUtmTouch} reads back.
|
|
147
155
|
*/
|
|
148
|
-
export declare function
|
|
156
|
+
export declare function utmTouchWire(touch: UtmTouch | null | undefined): string;
|
|
149
157
|
/**
|
|
150
158
|
* Read a stored or transmitted touch back, or `null`.
|
|
151
159
|
*
|
|
@@ -155,7 +163,7 @@ export declare function campaignTouchWire(touch: CampaignTouch | null | undefine
|
|
|
155
163
|
* future is refused for the reason the revenue join refuses one: a click
|
|
156
164
|
* after the conversion is the receipt, not the cause.
|
|
157
165
|
*/
|
|
158
|
-
export declare function
|
|
166
|
+
export declare function parseUtmTouch(wire: unknown, nowMs?: number): UtmTouch | null;
|
|
159
167
|
/**
|
|
160
168
|
* Tell this module what the visitor's analytics consent state is.
|
|
161
169
|
*
|
|
@@ -163,7 +171,7 @@ export declare function parseCampaignTouch(wire: unknown, nowMs?: number): Campa
|
|
|
163
171
|
* grant remembers the arrival the moment it is given and a withdrawal drops
|
|
164
172
|
* the stored touch immediately.
|
|
165
173
|
*/
|
|
166
|
-
export declare function
|
|
174
|
+
export declare function setUtmTouchConsent(allowed: boolean | null): void;
|
|
167
175
|
/**
|
|
168
176
|
* Remember the campaign on the current URL as this visitor's latest touch.
|
|
169
177
|
*
|
|
@@ -174,7 +182,7 @@ export declare function setCampaignTouchConsent(allowed: boolean | null): void;
|
|
|
174
182
|
*
|
|
175
183
|
* @returns what is now remembered, or `null`.
|
|
176
184
|
*/
|
|
177
|
-
export declare function
|
|
185
|
+
export declare function rememberUtmTouch(search?: string, nowMs?: number): UtmTouch | null;
|
|
178
186
|
/**
|
|
179
187
|
* The touch to credit a conversion happening right now, or `null`.
|
|
180
188
|
*
|
|
@@ -191,7 +199,7 @@ export declare function rememberCampaignTouch(search?: string, nowMs?: number):
|
|
|
191
199
|
* device would be keeping a record of where somebody came from for no purpose
|
|
192
200
|
* anything reads. The read that finds it removes it.
|
|
193
201
|
*/
|
|
194
|
-
export declare function
|
|
202
|
+
export declare function readUtmTouch(nowMs?: number): UtmTouch | null;
|
|
195
203
|
/**
|
|
196
204
|
* The fragment a conversion request spreads into its body, or `{}`.
|
|
197
205
|
*
|
|
@@ -201,6 +209,6 @@ export declare function readCampaignTouch(nowMs?: number): CampaignTouch | null;
|
|
|
201
209
|
* never `campaignTouch: undefined`, so that "arrived from nowhere" and "this
|
|
202
210
|
* door does not report" stay distinguishable on the wire.
|
|
203
211
|
*/
|
|
204
|
-
export declare function
|
|
212
|
+
export declare function utmTouchField(nowMs?: number): {
|
|
205
213
|
campaignTouch?: string;
|
|
206
214
|
};
|
|
@@ -15,8 +15,13 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
|
15
15
|
* See the License for the specific language governing permissions and
|
|
16
16
|
* limitations under the License.
|
|
17
17
|
*/ /**
|
|
18
|
-
* THE VISITOR'S HALF OF
|
|
19
|
-
*
|
|
18
|
+
* THE VISITOR'S HALF OF ATTRIBUTION — the UTM touch that has to survive the
|
|
19
|
+
* gap between arriving from a labeled link and becoming somebody.
|
|
20
|
+
*
|
|
21
|
+
* The labels are the web's (`utm_source`/`utm_medium`/`utm_campaign`), not
|
|
22
|
+
* any plugin's model: every door that identifies a visitor — a form, a
|
|
23
|
+
* booking, a signup — attaches the touch, and whichever plugin credits its
|
|
24
|
+
* campaigns reads it on the server.
|
|
20
25
|
*
|
|
21
26
|
* ## The gap this exists to cross
|
|
22
27
|
*
|
|
@@ -42,7 +47,7 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
|
42
47
|
*
|
|
43
48
|
* `localStorage`, expiring at {@link ATTRIBUTION_WINDOW_DAYS}.
|
|
44
49
|
*
|
|
45
|
-
* `
|
|
50
|
+
* `utm-forwarding.ts` holds its own campaign in `sessionStorage` and
|
|
46
51
|
* argues for it: a first touch that outlived the visit would start
|
|
47
52
|
* attributing next week's organic return to this week's ad. That argument is
|
|
48
53
|
* correct for the question it answers — which campaign produced THIS SIGNUP,
|
|
@@ -64,7 +69,7 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
|
64
69
|
* The revenue join credits the LAST click, and a product where a lead and an
|
|
65
70
|
* order attribute by different rules is worse than one that is uniformly
|
|
66
71
|
* approximate. So a new campaign arrival OVERWRITES the stored one. This is
|
|
67
|
-
* the deliberate opposite of {@link
|
|
72
|
+
* the deliberate opposite of {@link rememberVisitUtm}, which keeps the
|
|
68
73
|
* first — that one describes a single visit's origin and this one describes
|
|
69
74
|
* which campaign most recently brought a person back.
|
|
70
75
|
*
|
|
@@ -104,7 +109,7 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
|
104
109
|
* ## What is never carried
|
|
105
110
|
*
|
|
106
111
|
* Only the three allowlisted `utm_` labels, scrubbed by
|
|
107
|
-
* {@link
|
|
112
|
+
* {@link parseUtmAttribution} — which refuses an email-shaped value
|
|
108
113
|
* outright. No address, no person's identifier, no click id, nothing that
|
|
109
114
|
* names the visitor. A campaign link is exactly where putting a recipient in
|
|
110
115
|
* a query string would be tempting, and the parser is what makes it
|
|
@@ -119,7 +124,7 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
|
119
124
|
* recorded server-side against the recipient's address hash. The labels below
|
|
120
125
|
* are the WEB channel's touch, and a campaign that carries none is joined by
|
|
121
126
|
* address instead.
|
|
122
|
-
*/ import {
|
|
127
|
+
*/ import { utmAttributionQuery, parseUtmAttribution } from "./utm-attribution.js";
|
|
123
128
|
/*==========================================
|
|
124
129
|
* THE WINDOW, AND WHY THIS IS THE SECOND COPY OF A NUMBER.
|
|
125
130
|
*
|
|
@@ -152,7 +157,10 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
|
152
157
|
const age = convertedAtMs - touchedAtMs;
|
|
153
158
|
return age >= 0 && age <= ATTRIBUTION_WINDOW_MS;
|
|
154
159
|
}
|
|
155
|
-
/**
|
|
160
|
+
/**
|
|
161
|
+
* Where the touch is held. Namespaced like every other key this app sets, and
|
|
162
|
+
* spelled as visitors' devices already hold it.
|
|
163
|
+
*/ export const UTM_TOUCH_STORAGE_KEY = 'aglyn:campaign-touch';
|
|
156
164
|
/**
|
|
157
165
|
* The parameter the touch's instant rides under inside the wire form.
|
|
158
166
|
*
|
|
@@ -160,7 +168,7 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
|
160
168
|
* allowlist that reads a URL, and a fourth `utm_` key would either be dropped
|
|
161
169
|
* by it or have to widen it. `t` is outside the allowlist and read
|
|
162
170
|
* separately.
|
|
163
|
-
*/ export const
|
|
171
|
+
*/ export const UTM_TOUCH_TIME_KEY = 't';
|
|
164
172
|
/**
|
|
165
173
|
* Whether the visitor has granted analytics storage.
|
|
166
174
|
*
|
|
@@ -180,14 +188,14 @@ function localStore() {
|
|
|
180
188
|
}
|
|
181
189
|
/**
|
|
182
190
|
* The canonical stored form of a touch — the ONLY place it is written, so it
|
|
183
|
-
* cannot drift from what {@link
|
|
184
|
-
*/ export function
|
|
191
|
+
* cannot drift from what {@link parseUtmTouch} reads back.
|
|
192
|
+
*/ export function utmTouchWire(touch) {
|
|
185
193
|
if (!touch) return '';
|
|
186
|
-
const labels =
|
|
194
|
+
const labels = utmAttributionQuery(touch);
|
|
187
195
|
if (!labels) return '';
|
|
188
196
|
const atMs = Math.round(Number(touch.atMs));
|
|
189
197
|
if (!Number.isFinite(atMs) || atMs <= 0) return '';
|
|
190
|
-
return `${labels}&${
|
|
198
|
+
return `${labels}&${UTM_TOUCH_TIME_KEY}=${atMs}`;
|
|
191
199
|
}
|
|
192
200
|
/**
|
|
193
201
|
* Read a stored or transmitted touch back, or `null`.
|
|
@@ -197,7 +205,7 @@ function localStore() {
|
|
|
197
205
|
* agrees about what an expired touch is: nothing at all. A touch dated in the
|
|
198
206
|
* future is refused for the reason the revenue join refuses one: a click
|
|
199
207
|
* after the conversion is the receipt, not the cause.
|
|
200
|
-
*/ export function
|
|
208
|
+
*/ export function parseUtmTouch(wire, nowMs = Date.now()) {
|
|
201
209
|
if (typeof wire !== 'string' || !wire) return null;
|
|
202
210
|
let params;
|
|
203
211
|
try {
|
|
@@ -205,9 +213,9 @@ function localStore() {
|
|
|
205
213
|
} catch (unused) {
|
|
206
214
|
return null;
|
|
207
215
|
}
|
|
208
|
-
const campaign =
|
|
216
|
+
const campaign = parseUtmAttribution(params);
|
|
209
217
|
if (!campaign) return null;
|
|
210
|
-
const atMs = Number(params.get(
|
|
218
|
+
const atMs = Number(params.get(UTM_TOUCH_TIME_KEY));
|
|
211
219
|
if (!touchIsInWindow(atMs, nowMs)) return null;
|
|
212
220
|
return _extends({}, campaign, {
|
|
213
221
|
atMs
|
|
@@ -219,17 +227,17 @@ function localStore() {
|
|
|
219
227
|
* Called by whoever already computed it for the tag, on every render, so a
|
|
220
228
|
* grant remembers the arrival the moment it is given and a withdrawal drops
|
|
221
229
|
* the stored touch immediately.
|
|
222
|
-
*/ export function
|
|
230
|
+
*/ export function setUtmTouchConsent(allowed) {
|
|
223
231
|
storageConsent = allowed === true ? true : allowed === false ? false : null;
|
|
224
232
|
if (storageConsent === true) {
|
|
225
|
-
|
|
233
|
+
rememberUtmTouch();
|
|
226
234
|
return;
|
|
227
235
|
}
|
|
228
236
|
if (storageConsent === false) {
|
|
229
237
|
const store = localStore();
|
|
230
238
|
if (!store) return;
|
|
231
239
|
try {
|
|
232
|
-
store.removeItem(
|
|
240
|
+
store.removeItem(UTM_TOUCH_STORAGE_KEY);
|
|
233
241
|
} catch (unused) {
|
|
234
242
|
// Nothing else to try, and a failed cleanup must not break the page.
|
|
235
243
|
}
|
|
@@ -244,20 +252,20 @@ function localStore() {
|
|
|
244
252
|
* second pageview.
|
|
245
253
|
*
|
|
246
254
|
* @returns what is now remembered, or `null`.
|
|
247
|
-
*/ export function
|
|
255
|
+
*/ export function rememberUtmTouch(search, nowMs = Date.now()) {
|
|
248
256
|
if (storageConsent !== true) return null;
|
|
249
257
|
const store = localStore();
|
|
250
258
|
if (!store) return null;
|
|
251
259
|
const source = typeof search === 'string' ? search : typeof window === 'undefined' ? '' : window.location.search;
|
|
252
|
-
const campaign =
|
|
260
|
+
const campaign = parseUtmAttribution(new URLSearchParams(source));
|
|
253
261
|
if (!campaign) return null;
|
|
254
262
|
const touch = _extends({}, campaign, {
|
|
255
263
|
atMs: nowMs
|
|
256
264
|
});
|
|
257
|
-
const wire =
|
|
265
|
+
const wire = utmTouchWire(touch);
|
|
258
266
|
if (!wire) return null;
|
|
259
267
|
try {
|
|
260
|
-
store.setItem(
|
|
268
|
+
store.setItem(UTM_TOUCH_STORAGE_KEY, wire);
|
|
261
269
|
} catch (unused) {
|
|
262
270
|
// A store that refuses the write costs the walk from the landing page to
|
|
263
271
|
// the conversion, never a conversion on the landing page itself — the
|
|
@@ -281,8 +289,8 @@ function localStore() {
|
|
|
281
289
|
* A touch past the window can never be credited again, so leaving it on the
|
|
282
290
|
* device would be keeping a record of where somebody came from for no purpose
|
|
283
291
|
* anything reads. The read that finds it removes it.
|
|
284
|
-
*/ export function
|
|
285
|
-
const live = typeof window === 'undefined' ? null :
|
|
292
|
+
*/ export function readUtmTouch(nowMs = Date.now()) {
|
|
293
|
+
const live = typeof window === 'undefined' ? null : parseUtmAttribution(new URLSearchParams(window.location.search));
|
|
286
294
|
if (live) return _extends({}, live, {
|
|
287
295
|
atMs: nowMs
|
|
288
296
|
});
|
|
@@ -291,15 +299,15 @@ function localStore() {
|
|
|
291
299
|
if (!store) return null;
|
|
292
300
|
let raw;
|
|
293
301
|
try {
|
|
294
|
-
raw = store.getItem(
|
|
302
|
+
raw = store.getItem(UTM_TOUCH_STORAGE_KEY);
|
|
295
303
|
} catch (unused) {
|
|
296
304
|
return null;
|
|
297
305
|
}
|
|
298
306
|
if (!raw) return null;
|
|
299
|
-
const touch =
|
|
307
|
+
const touch = parseUtmTouch(raw, nowMs);
|
|
300
308
|
if (!touch) {
|
|
301
309
|
try {
|
|
302
|
-
store.removeItem(
|
|
310
|
+
store.removeItem(UTM_TOUCH_STORAGE_KEY);
|
|
303
311
|
} catch (unused) {
|
|
304
312
|
// The entry stays until the next read finds it again; it is already
|
|
305
313
|
// uncreditable, so nothing downstream is affected.
|
|
@@ -316,11 +324,11 @@ function localStore() {
|
|
|
316
324
|
* that produced none. Empty when there is no touch — never a placeholder,
|
|
317
325
|
* never `campaignTouch: undefined`, so that "arrived from nowhere" and "this
|
|
318
326
|
* door does not report" stay distinguishable on the wire.
|
|
319
|
-
*/ export function
|
|
320
|
-
const wire =
|
|
327
|
+
*/ export function utmTouchField(nowMs = Date.now()) {
|
|
328
|
+
const wire = utmTouchWire(readUtmTouch(nowMs));
|
|
321
329
|
return wire ? {
|
|
322
330
|
campaignTouch: wire
|
|
323
331
|
} : {};
|
|
324
332
|
}
|
|
325
333
|
|
|
326
|
-
//# sourceMappingURL=
|
|
334
|
+
//# sourceMappingURL=utm-touch.js.map
|