@aglyn/aglyn 1.0.0-beta.221 → 1.0.0-beta.222
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 +15 -11
- package/src/lib/app-utils/agent-openapi.js +1 -1
- package/src/lib/app-utils/agent-openapi.js.map +1 -1
- package/src/lib/app-utils/analytics-events.d.ts +3 -2
- package/src/lib/app-utils/analytics-events.js +3 -2
- package/src/lib/app-utils/analytics-events.js.map +1 -1
- package/src/lib/app-utils/api-plugins.d.ts +30 -0
- package/src/lib/app-utils/api-plugins.js +24 -1
- package/src/lib/app-utils/api-plugins.js.map +1 -1
- package/src/lib/app-utils/author-html.d.ts +1 -1
- package/src/lib/app-utils/author-html.js.map +1 -1
- package/src/lib/app-utils/bandwidth-cap.d.ts +12 -1
- package/src/lib/app-utils/bandwidth-cap.js +17 -1
- package/src/lib/app-utils/bandwidth-cap.js.map +1 -1
- package/src/lib/app-utils/compose-reusable-components.d.ts +19 -0
- package/src/lib/app-utils/compose-reusable-components.js +116 -26
- package/src/lib/app-utils/compose-reusable-components.js.map +1 -1
- package/src/lib/app-utils/console-routes.d.ts +4 -0
- package/src/lib/app-utils/console-routes.js +3 -0
- package/src/lib/app-utils/console-routes.js.map +1 -1
- package/src/lib/app-utils/contacts.d.ts +71 -0
- package/src/lib/app-utils/contacts.js +55 -0
- package/src/lib/app-utils/contacts.js.map +1 -1
- package/src/lib/app-utils/contexts.d.ts +1 -0
- package/src/lib/app-utils/contexts.js +1 -0
- package/src/lib/app-utils/contexts.js.map +1 -1
- package/src/lib/app-utils/crm-email-templates.js +21 -4
- package/src/lib/app-utils/crm-email-templates.js.map +1 -1
- package/src/lib/app-utils/crm-kinds.d.ts +2 -0
- package/src/lib/app-utils/crm-kinds.js +1 -0
- package/src/lib/app-utils/crm-kinds.js.map +1 -1
- package/src/lib/app-utils/crm.d.ts +1199 -67
- package/src/lib/app-utils/crm.js +1951 -310
- package/src/lib/app-utils/crm.js.map +1 -1
- package/src/lib/app-utils/csv-import.d.ts +10 -38
- package/src/lib/app-utils/csv-import.js +17 -42
- package/src/lib/app-utils/csv-import.js.map +1 -1
- package/src/lib/app-utils/csv.d.ts +32 -11
- package/src/lib/app-utils/csv.js +43 -5
- package/src/lib/app-utils/csv.js.map +1 -1
- package/src/lib/app-utils/default-site.d.ts +116 -0
- package/src/lib/app-utils/default-site.js +1024 -0
- package/src/lib/app-utils/default-site.js.map +1 -0
- package/src/lib/app-utils/docs-help.generated.d.ts +22 -22
- package/src/lib/app-utils/docs-help.generated.js +44 -10
- package/src/lib/app-utils/docs-help.generated.js.map +1 -1
- package/src/lib/app-utils/docs-index.generated.js +738 -150
- package/src/lib/app-utils/docs-index.generated.js.map +1 -1
- package/src/lib/app-utils/draft-placeholders.d.ts +76 -0
- package/src/lib/app-utils/draft-placeholders.js +115 -0
- package/src/lib/app-utils/draft-placeholders.js.map +1 -0
- package/src/lib/app-utils/entity-picker-context.d.ts +19 -15
- package/src/lib/app-utils/entity-picker-context.js +4 -4
- package/src/lib/app-utils/entity-picker-context.js.map +1 -1
- package/src/lib/app-utils/expand-repeatables.d.ts +66 -10
- package/src/lib/app-utils/expand-repeatables.js +88 -14
- package/src/lib/app-utils/expand-repeatables.js.map +1 -1
- package/src/lib/app-utils/forms.d.ts +33 -22
- package/src/lib/app-utils/forms.js +47 -28
- package/src/lib/app-utils/forms.js.map +1 -1
- package/src/lib/app-utils/full-use-cost.d.ts +277 -0
- package/src/lib/app-utils/full-use-cost.js +421 -0
- package/src/lib/app-utils/full-use-cost.js.map +1 -0
- package/src/lib/app-utils/health-report.js +11 -0
- package/src/lib/app-utils/health-report.js.map +1 -1
- package/src/lib/app-utils/llms-txt.d.ts +20 -0
- package/src/lib/app-utils/llms-txt.js +7 -1
- package/src/lib/app-utils/llms-txt.js.map +1 -1
- package/src/lib/app-utils/media-asset-facts.d.ts +16 -1
- package/src/lib/app-utils/media-asset-facts.js +40 -13
- package/src/lib/app-utils/media-asset-facts.js.map +1 -1
- package/src/lib/app-utils/media-bandwidth.d.ts +52 -0
- package/src/lib/app-utils/media-bandwidth.js +94 -0
- package/src/lib/app-utils/media-bandwidth.js.map +1 -0
- package/src/lib/app-utils/media-ref.d.ts +241 -33
- package/src/lib/app-utils/media-ref.js +324 -43
- package/src/lib/app-utils/media-ref.js.map +1 -1
- package/src/lib/app-utils/media-src.d.ts +8 -8
- package/src/lib/app-utils/media-src.js +27 -11
- package/src/lib/app-utils/media-src.js.map +1 -1
- package/src/lib/app-utils/media-takedown-reach.d.ts +4 -1
- package/src/lib/app-utils/media-takedown-reach.js +6 -3
- package/src/lib/app-utils/media-takedown-reach.js.map +1 -1
- package/src/lib/app-utils/notifications.d.ts +1 -1
- package/src/lib/app-utils/notifications.js +2 -0
- package/src/lib/app-utils/notifications.js.map +1 -1
- package/src/lib/app-utils/organizations.d.ts +51 -2
- package/src/lib/app-utils/organizations.js +56 -3
- package/src/lib/app-utils/organizations.js.map +1 -1
- package/src/lib/app-utils/page-record-sources.d.ts +87 -0
- package/src/lib/app-utils/page-record-sources.js +53 -0
- package/src/lib/app-utils/page-record-sources.js.map +1 -0
- package/src/lib/app-utils/paid-media-source.d.ts +3 -7
- package/src/lib/app-utils/paid-media-source.js +5 -19
- package/src/lib/app-utils/paid-media-source.js.map +1 -1
- package/src/lib/app-utils/person-erasure.d.ts +5 -2
- package/src/lib/app-utils/person-erasure.js.map +1 -1
- package/src/lib/app-utils/picklists.d.ts +187 -0
- package/src/lib/app-utils/picklists.js +320 -0
- package/src/lib/app-utils/picklists.js.map +1 -0
- package/src/lib/app-utils/plan-entitlements.d.ts +220 -50
- package/src/lib/app-utils/plan-entitlements.js +309 -115
- package/src/lib/app-utils/plan-entitlements.js.map +1 -1
- 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 +1 -1
- package/src/lib/app-utils/release-flags.js +11 -0
- package/src/lib/app-utils/release-flags.js.map +1 -1
- package/src/lib/app-utils/rendered-widths.d.ts +121 -0
- package/src/lib/app-utils/rendered-widths.js +211 -0
- package/src/lib/app-utils/rendered-widths.js.map +1 -0
- package/src/lib/app-utils/repeat-sources.d.ts +2 -1
- package/src/lib/app-utils/repeat-sources.js.map +1 -1
- package/src/lib/app-utils/screen-route.d.ts +154 -36
- package/src/lib/app-utils/screen-route.js +185 -40
- package/src/lib/app-utils/screen-route.js.map +1 -1
- package/src/lib/app-utils/seo-audit.d.ts +11 -1
- package/src/lib/app-utils/seo-audit.js +33 -13
- package/src/lib/app-utils/seo-audit.js.map +1 -1
- package/src/lib/app-utils/seo-keywords.d.ts +11 -0
- package/src/lib/app-utils/seo-keywords.js +19 -5
- package/src/lib/app-utils/seo-keywords.js.map +1 -1
- package/src/lib/app-utils/seo-page-facts.d.ts +47 -4
- package/src/lib/app-utils/seo-page-facts.js +136 -31
- package/src/lib/app-utils/seo-page-facts.js.map +1 -1
- package/src/lib/app-utils/seo-site-scan.d.ts +42 -4
- package/src/lib/app-utils/seo-site-scan.js +113 -12
- package/src/lib/app-utils/seo-site-scan.js.map +1 -1
- package/src/lib/app-utils/server.d.ts +5 -4
- package/src/lib/app-utils/server.js +14 -5
- package/src/lib/app-utils/server.js.map +1 -1
- package/src/lib/app-utils/site-icon-set.d.ts +195 -0
- package/src/lib/app-utils/site-icon-set.js +351 -0
- package/src/lib/app-utils/site-icon-set.js.map +1 -0
- package/src/lib/app-utils/site-interactions.d.ts +101 -4
- package/src/lib/app-utils/site-interactions.js +120 -4
- package/src/lib/app-utils/site-interactions.js.map +1 -1
- package/src/lib/app-utils/starter-template-nodes.d.ts +7 -0
- package/src/lib/app-utils/starter-template-nodes.js +3 -0
- package/src/lib/app-utils/starter-template-nodes.js.map +1 -1
- package/src/lib/app-utils/starter-templates.d.ts +5 -19
- package/src/lib/app-utils/starter-templates.js +5 -49
- package/src/lib/app-utils/starter-templates.js.map +1 -1
- package/src/lib/app-utils/transfer-launcher-context.d.ts +136 -0
- package/src/lib/app-utils/transfer-launcher-context.js +23 -0
- package/src/lib/app-utils/transfer-launcher-context.js.map +1 -0
- package/src/lib/app-utils/transfer-resume-import.d.ts +39 -0
- package/src/lib/app-utils/transfer-resume-import.js +128 -0
- package/src/lib/app-utils/transfer-resume-import.js.map +1 -0
- package/src/lib/app-utils/upgrade-proposal.d.ts +66 -0
- package/src/lib/app-utils/upgrade-proposal.js +95 -0
- package/src/lib/app-utils/upgrade-proposal.js.map +1 -0
- package/src/lib/app-utils/utc-month.d.ts +33 -0
- package/src/lib/app-utils/utc-month.js +35 -0
- package/src/lib/app-utils/utc-month.js.map +1 -0
- package/src/lib/app-utils/visitor-record-ceiling.d.ts +4 -4
- package/src/lib/app-utils/visitor-record-ceiling.js +4 -4
- package/src/lib/app-utils/visitor-record-ceiling.js.map +1 -1
- package/src/lib/app-utils/wire-nodes.d.ts +39 -19
- package/src/lib/app-utils/wire-nodes.js +120 -34
- package/src/lib/app-utils/wire-nodes.js.map +1 -1
- package/src/lib/data-transfer/access.d.ts +74 -0
- package/src/lib/data-transfer/access.js +93 -0
- package/src/lib/data-transfer/access.js.map +1 -0
- package/src/lib/data-transfer/derive.d.ts +246 -0
- package/src/lib/data-transfer/derive.js +1007 -0
- package/src/lib/data-transfer/derive.js.map +1 -0
- package/src/lib/data-transfer/export-file.d.ts +46 -0
- package/src/lib/data-transfer/export-file.js +146 -0
- package/src/lib/data-transfer/export-file.js.map +1 -0
- package/src/lib/data-transfer/field-catalog.d.ts +134 -0
- package/src/lib/data-transfer/field-catalog.js +278 -0
- package/src/lib/data-transfer/field-catalog.js.map +1 -0
- package/src/lib/data-transfer/header-match.d.ts +129 -0
- package/src/lib/data-transfer/header-match.js +367 -0
- package/src/lib/data-transfer/header-match.js.map +1 -0
- package/src/lib/data-transfer/index.d.ts +34 -0
- package/src/lib/data-transfer/index.js +40 -0
- package/src/lib/data-transfer/index.js.map +1 -0
- package/src/lib/data-transfer/job.d.ts +190 -0
- package/src/lib/data-transfer/job.js +229 -0
- package/src/lib/data-transfer/job.js.map +1 -0
- package/src/lib/data-transfer/lookup.d.ts +45 -0
- package/src/lib/data-transfer/lookup.js +71 -0
- package/src/lib/data-transfer/lookup.js.map +1 -0
- package/src/lib/data-transfer/match.d.ts +99 -0
- package/src/lib/data-transfer/match.js +244 -0
- package/src/lib/data-transfer/match.js.map +1 -0
- package/src/lib/data-transfer/package-plan.d.ts +205 -0
- package/src/lib/data-transfer/package-plan.js +475 -0
- package/src/lib/data-transfer/package-plan.js.map +1 -0
- package/src/lib/data-transfer/package.d.ts +181 -0
- package/src/lib/data-transfer/package.js +426 -0
- package/src/lib/data-transfer/package.js.map +1 -0
- package/src/lib/data-transfer/picklist-map.d.ts +139 -0
- package/src/lib/data-transfer/picklist-map.js +271 -0
- package/src/lib/data-transfer/picklist-map.js.map +1 -0
- package/src/lib/data-transfer/plan.d.ts +176 -0
- package/src/lib/data-transfer/plan.js +451 -0
- package/src/lib/data-transfer/plan.js.map +1 -0
- package/src/lib/data-transfer/policy.d.ts +170 -0
- package/src/lib/data-transfer/policy.js +378 -0
- package/src/lib/data-transfer/policy.js.map +1 -0
- package/src/lib/data-transfer/resource.d.ts +211 -0
- package/src/lib/data-transfer/resource.js +241 -0
- package/src/lib/data-transfer/resource.js.map +1 -0
- package/src/lib/data-transfer/review.d.ts +70 -0
- package/src/lib/data-transfer/review.js +233 -0
- package/src/lib/data-transfer/review.js.map +1 -0
- package/src/lib/data-transfer/similarity.d.ts +40 -0
- package/src/lib/data-transfer/similarity.js +106 -0
- package/src/lib/data-transfer/similarity.js.map +1 -0
- package/src/lib/data-transfer/site-package.d.ts +365 -0
- package/src/lib/data-transfer/site-package.js +1077 -0
- package/src/lib/data-transfer/site-package.js.map +1 -0
- package/src/lib/data-transfer/source.d.ts +74 -0
- package/src/lib/data-transfer/source.js +293 -0
- package/src/lib/data-transfer/source.js.map +1 -0
- package/src/lib/data-transfer/transfer-api.d.ts +898 -0
- package/src/lib/data-transfer/transfer-api.js +107 -0
- package/src/lib/data-transfer/transfer-api.js.map +1 -0
- package/src/lib/foundation/definitions/org-billing.types.d.ts +31 -0
- package/src/lib/foundation/definitions/org-billing.types.js.map +1 -1
- package/src/lib/foundation/definitions/organization.types.d.ts +42 -1
- package/src/lib/foundation/definitions/organization.types.js.map +1 -1
- package/src/lib/foundation/definitions/platform.types.d.ts +6 -4
- package/src/lib/foundation/definitions/platform.types.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/feature-plugins.d.ts +91 -2
- package/src/lib/plugin-manager/feature-plugins.js +48 -3
- package/src/lib/plugin-manager/feature-plugins.js.map +1 -1
- package/src/lib/plugin-manager/first-party-plugins.generated.d.ts +50 -0
- package/src/lib/plugin-manager/first-party-plugins.generated.js +1129 -28
- 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/interaction-recipes.d.ts +142 -0
- package/src/lib/plugin-manager/interaction-recipes.js +104 -0
- package/src/lib/plugin-manager/interaction-recipes.js.map +1 -0
- package/src/lib/plugin-manager/interaction-step-checks.d.ts +66 -0
- package/src/lib/plugin-manager/interaction-step-checks.js +86 -0
- package/src/lib/plugin-manager/interaction-step-checks.js.map +1 -0
- package/src/lib/plugin-manager/plugin-artifact-types.d.ts +235 -0
- package/src/lib/plugin-manager/plugin-artifact-types.js +99 -0
- package/src/lib/plugin-manager/plugin-artifact-types.js.map +1 -0
- package/src/lib/plugin-manager/plugin-contact-capture.d.ts +8 -0
- package/src/lib/plugin-manager/plugin-contact-capture.js.map +1 -1
- package/src/lib/plugin-manager/plugin-conversion-credit.d.ts +216 -0
- package/src/lib/plugin-manager/plugin-conversion-credit.js +91 -0
- package/src/lib/plugin-manager/plugin-conversion-credit.js.map +1 -0
- package/src/lib/plugin-manager/plugin-entity-pickers.d.ts +83 -0
- package/src/lib/plugin-manager/plugin-entity-pickers.js +87 -0
- package/src/lib/plugin-manager/plugin-entity-pickers.js.map +1 -0
- package/src/lib/plugin-manager/plugin-host-resources.d.ts +6 -0
- package/src/lib/plugin-manager/plugin-host-resources.js +6 -1
- package/src/lib/plugin-manager/plugin-host-resources.js.map +1 -1
- package/src/lib/plugin-manager/plugin-intake-gates.d.ts +75 -0
- package/src/lib/plugin-manager/plugin-intake-gates.js +49 -0
- package/src/lib/plugin-manager/plugin-intake-gates.js.map +1 -0
- package/src/lib/plugin-manager/plugin-jobs.d.ts +5 -5
- package/src/lib/plugin-manager/plugin-jobs.js +7 -7
- package/src/lib/plugin-manager/plugin-jobs.js.map +1 -1
- package/src/lib/plugin-manager/plugin-live-paths.d.ts +70 -0
- package/src/lib/plugin-manager/plugin-live-paths.js +66 -0
- package/src/lib/plugin-manager/plugin-live-paths.js.map +1 -0
- package/src/lib/plugin-manager/plugin-org-erasure.d.ts +3 -2
- package/src/lib/plugin-manager/plugin-org-erasure.js +30 -5
- package/src/lib/plugin-manager/plugin-org-erasure.js.map +1 -1
- package/src/lib/plugin-manager/plugin-person-erasure.d.ts +68 -9
- package/src/lib/plugin-manager/plugin-person-erasure.js +196 -51
- package/src/lib/plugin-manager/plugin-person-erasure.js.map +1 -1
- package/src/lib/plugin-manager/plugin-person-records.d.ts +275 -0
- package/src/lib/plugin-manager/plugin-person-records.js +107 -0
- package/src/lib/plugin-manager/plugin-person-records.js.map +1 -0
- package/src/lib/plugin-manager/plugin-record-counts.d.ts +76 -0
- package/src/lib/plugin-manager/plugin-record-counts.js +49 -0
- package/src/lib/plugin-manager/plugin-record-counts.js.map +1 -0
- package/src/lib/plugin-manager/plugin-record-email-state.d.ts +26 -0
- package/src/lib/plugin-manager/plugin-record-email-state.js +16 -0
- package/src/lib/plugin-manager/plugin-record-email-state.js.map +1 -1
- package/src/lib/plugin-manager/plugin-record-index.d.ts +10 -0
- package/src/lib/plugin-manager/plugin-record-index.js.map +1 -1
- package/src/lib/plugin-manager/plugin-record-lists.d.ts +86 -6
- package/src/lib/plugin-manager/plugin-record-lists.js +42 -5
- package/src/lib/plugin-manager/plugin-record-lists.js.map +1 -1
- package/src/lib/plugin-manager/plugin-record-origin.d.ts +79 -0
- package/src/lib/plugin-manager/plugin-record-origin.js +46 -0
- package/src/lib/plugin-manager/plugin-record-origin.js.map +1 -0
- package/src/lib/plugin-manager/plugin-record-pages.d.ts +37 -0
- package/src/lib/plugin-manager/plugin-record-pages.js +52 -0
- package/src/lib/plugin-manager/plugin-record-pages.js.map +1 -0
- package/src/lib/plugin-manager/plugin-record-timeline.d.ts +60 -0
- package/src/lib/plugin-manager/plugin-record-timeline.js +16 -0
- package/src/lib/plugin-manager/plugin-record-timeline.js.map +1 -1
- package/src/lib/plugin-manager/plugin-resource-drafts.d.ts +5 -5
- package/src/lib/plugin-manager/plugin-resource-drafts.js.map +1 -1
- package/src/lib/plugin-manager/plugin-revocations.d.ts +64 -0
- package/src/lib/plugin-manager/plugin-revocations.js +47 -0
- package/src/lib/plugin-manager/plugin-revocations.js.map +1 -0
- package/src/lib/plugin-manager/plugin-send-tallies.d.ts +69 -0
- package/src/lib/plugin-manager/plugin-send-tallies.js +45 -0
- package/src/lib/plugin-manager/plugin-send-tallies.js.map +1 -0
- package/src/lib/plugin-manager/plugin-site-bundle.d.ts +40 -0
- package/src/lib/plugin-manager/plugin-site-bundle.js +4 -0
- package/src/lib/plugin-manager/plugin-site-bundle.js.map +1 -1
- package/src/lib/plugin-manager/plugin-site-export.d.ts +57 -1
- package/src/lib/plugin-manager/plugin-site-export.js +23 -10
- package/src/lib/plugin-manager/plugin-site-export.js.map +1 -1
- package/src/lib/plugin-manager/plugin-sitemap-readers.d.ts +146 -0
- package/src/lib/plugin-manager/plugin-sitemap-readers.js +110 -0
- package/src/lib/plugin-manager/plugin-sitemap-readers.js.map +1 -0
- package/src/lib/plugin-manager/plugin-transfer-resources.d.ts +714 -0
- package/src/lib/plugin-manager/plugin-transfer-resources.js +443 -0
- package/src/lib/plugin-manager/plugin-transfer-resources.js.map +1 -0
- package/src/lib/plugin-manager/plugin-usage-axes.d.ts +54 -5
- package/src/lib/plugin-manager/plugin-usage-axes.js +11 -3
- package/src/lib/plugin-manager/plugin-usage-axes.js.map +1 -1
- package/src/lib/plugin-manager/plugin-user-erasure.js +9 -1
- package/src/lib/plugin-manager/plugin-user-erasure.js.map +1 -1
- package/src/lib/plugin-manager/plugin-visitor-doors.d.ts +104 -0
- package/src/lib/plugin-manager/plugin-visitor-doors.js +108 -0
- package/src/lib/plugin-manager/plugin-visitor-doors.js.map +1 -0
- 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/repeat-rows.d.ts +5 -6
- package/src/lib/plugin-manager/repeat-rows.js.map +1 -1
- package/src/lib/app-utils/actions.d.ts +0 -310
- package/src/lib/app-utils/actions.js +0 -506
- package/src/lib/app-utils/actions.js.map +0 -1
- package/src/lib/app-utils/automation-placeholders.d.ts +0 -72
- package/src/lib/app-utils/automation-placeholders.js +0 -207
- package/src/lib/app-utils/automation-placeholders.js.map +0 -1
- package/src/lib/app-utils/dataset-models.d.ts +0 -339
- package/src/lib/app-utils/dataset-models.js +0 -722
- package/src/lib/app-utils/dataset-models.js.map +0 -1
- package/src/lib/app-utils/datasets.d.ts +0 -171
- package/src/lib/app-utils/datasets.js +0 -227
- package/src/lib/app-utils/datasets.js.map +0 -1
- package/src/lib/app-utils/form-abuse-ceiling.d.ts +0 -146
- package/src/lib/app-utils/form-abuse-ceiling.js +0 -158
- package/src/lib/app-utils/form-abuse-ceiling.js.map +0 -1
- package/src/lib/plugin-manager/order-fulfilment.d.ts +0 -142
- package/src/lib/plugin-manager/order-fulfilment.js +0 -104
- package/src/lib/plugin-manager/order-fulfilment.js.map +0 -1
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* THE PEOPLE A WORKSPACE KEEPS, asked for by the plugins that do not keep
|
|
19
|
+
* them (AGL-3080).
|
|
20
|
+
*
|
|
21
|
+
* `plugin-contact-capture` is how a silo hands somebody it MET to the plugin
|
|
22
|
+
* that keeps people. This is the other half: a plugin that has an address, or
|
|
23
|
+
* a record the owner handed it, and needs the person behind it.
|
|
24
|
+
*
|
|
25
|
+
* - a flow email asking whether the person agreed to marketing mail;
|
|
26
|
+
* - a campaign filling in the name a merge tag reads;
|
|
27
|
+
* - a refund taking money back off what a customer is worth;
|
|
28
|
+
* - an automation filing somebody under a campaign;
|
|
29
|
+
* - a sales sequence reading the people a rep enrolls.
|
|
30
|
+
*
|
|
31
|
+
* Each of those used to open the owner's collection itself — its path, its
|
|
32
|
+
* address index, which site may see which document — and broke the day the
|
|
33
|
+
* owner changed one. None of it is visible to `check:lib-boundaries`, because
|
|
34
|
+
* a collection name is not an import.
|
|
35
|
+
*
|
|
36
|
+
* So the plugin that keeps people registers ONE service here, and every rule
|
|
37
|
+
* stays the owner's: how an address is keyed, what an alternate address a
|
|
38
|
+
* merge folded in still answers to, which site may see which record, and what
|
|
39
|
+
* a refund or a filing writes.
|
|
40
|
+
*
|
|
41
|
+
* ## What a record is
|
|
42
|
+
*
|
|
43
|
+
* A {@link PluginPersonRecord} is a kind and an id in the owner's own words —
|
|
44
|
+
* the words `plugin-record-routes` addresses the record by — the person's
|
|
45
|
+
* primary address, and the record as the owner stores it. The fields the
|
|
46
|
+
* PLATFORM defines on a person record (the consent basis
|
|
47
|
+
* `marketing-consent.ts` reads, the `emailState` verdict, the `visibleTo`
|
|
48
|
+
* scope) are read off it with the platform's own readers; anything else is
|
|
49
|
+
* the owner's and is documented with its registration.
|
|
50
|
+
*
|
|
51
|
+
* ## Not registered is an answer
|
|
52
|
+
*
|
|
53
|
+
* Every reader answers `null` when no plugin keeps people in this process,
|
|
54
|
+
* which is a workspace with no record system and is not "nobody found". A
|
|
55
|
+
* caller treats the two differently: a send with no record system has no
|
|
56
|
+
* basis to read, which is not the same as a person who declined.
|
|
57
|
+
*
|
|
58
|
+
* A single-implementation contract: a workspace keeps one set of people, so
|
|
59
|
+
* a second plugin's service is refused naming both and the incumbent keeps
|
|
60
|
+
* serving. Registered from the owner's server declarations, so it is in place
|
|
61
|
+
* in a process that never loaded the owner's API surface.
|
|
62
|
+
*
|
|
63
|
+
* ## The caller proves who is asking
|
|
64
|
+
*
|
|
65
|
+
* Like the capture and timeline seams, the registry authenticates nobody. A
|
|
66
|
+
* caller decides in its own terms, before it asks, that the read or the write
|
|
67
|
+
* is the workspace's to make.
|
|
68
|
+
*
|
|
69
|
+
* Server-side: reached by its own subpath, never through
|
|
70
|
+
* `plugin-manager/index.ts`.
|
|
71
|
+
*/
|
|
72
|
+
/** A person record, by the owner's word for its kind and its id. */
|
|
73
|
+
export interface PluginPersonRecordRef {
|
|
74
|
+
/** The owner's word for the record — the kind `plugin-record-routes` addresses it by. */
|
|
75
|
+
kind: string;
|
|
76
|
+
id: string;
|
|
77
|
+
}
|
|
78
|
+
/** One person record, as the plugin that keeps people shares it. */
|
|
79
|
+
export interface PluginPersonRecord extends PluginPersonRecordRef {
|
|
80
|
+
/** The record's primary address, normalized, or `null` when it holds none. */
|
|
81
|
+
email: string | null;
|
|
82
|
+
/**
|
|
83
|
+
* The record as the owner stores it. The platform's own fields on it are
|
|
84
|
+
* read with the platform's readers; the rest is the owner's, documented
|
|
85
|
+
* with its registration.
|
|
86
|
+
*/
|
|
87
|
+
data: Readonly<Record<string, unknown>>;
|
|
88
|
+
}
|
|
89
|
+
/** Who to find by address, and where. */
|
|
90
|
+
export interface PluginPersonFindRequest {
|
|
91
|
+
/**
|
|
92
|
+
* The organization whose people are searched. A caller that knows only the
|
|
93
|
+
* site names `hostId` instead, and the owner reads the organization off it.
|
|
94
|
+
*/
|
|
95
|
+
orgId?: string | null;
|
|
96
|
+
/** The site asking. Required with {@link onlyVisibleToSite}. */
|
|
97
|
+
hostId?: string | null;
|
|
98
|
+
/** Raw: the owner normalizes it, alternate addresses included. */
|
|
99
|
+
email: unknown;
|
|
100
|
+
/**
|
|
101
|
+
* Answer only a record `hostId` may see. A record the address names but the
|
|
102
|
+
* site cannot see is `null`, never a reason to look further — one address
|
|
103
|
+
* names one person.
|
|
104
|
+
*/
|
|
105
|
+
onlyVisibleToSite?: boolean;
|
|
106
|
+
/**
|
|
107
|
+
* Look at every kind of record the owner keeps a person as, in the owner's
|
|
108
|
+
* order, instead of only the one a known person is held as. A send deciding
|
|
109
|
+
* whether it may mail somebody asks for this: a person not yet qualified is
|
|
110
|
+
* still a person whose answer counts.
|
|
111
|
+
*/
|
|
112
|
+
anyKind?: boolean;
|
|
113
|
+
}
|
|
114
|
+
/** Records to read, by the refs the owner handed out. */
|
|
115
|
+
export interface PluginPersonReadRequest {
|
|
116
|
+
orgId: string;
|
|
117
|
+
records: readonly PluginPersonRecordRef[];
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* File a person under containers (`plugin-containers.ts`) — the merchant's
|
|
121
|
+
* own act, through an automation step or an enrollment. Filing is not
|
|
122
|
+
* consent.
|
|
123
|
+
*/
|
|
124
|
+
export interface PluginPersonFileRequest {
|
|
125
|
+
/** The site filing them: the person is filed under the containers as this site holds them. */
|
|
126
|
+
hostId: string;
|
|
127
|
+
orgId?: string | null;
|
|
128
|
+
record: PluginPersonRecordRef;
|
|
129
|
+
/** The container kind, as `plugin-containers.ts` declares it. */
|
|
130
|
+
containerKind: string;
|
|
131
|
+
ids: readonly string[];
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Money handed back to a person a silo took it from: a refund, or a dispute
|
|
135
|
+
* lost. The owner records it beside what the person is worth; it never
|
|
136
|
+
* creates a person to hold it.
|
|
137
|
+
*/
|
|
138
|
+
export interface PluginPersonRefundRequest {
|
|
139
|
+
/** The site the money was taken on. */
|
|
140
|
+
hostId: string;
|
|
141
|
+
/** The buyer's address as the sale recorded it. Raw: the owner normalizes it. */
|
|
142
|
+
email: unknown;
|
|
143
|
+
/** Cents reversed by THIS refund, never the sale's total. */
|
|
144
|
+
amountCents: number;
|
|
145
|
+
/** The silo's own document the money went back on — what a timeline entry points at. */
|
|
146
|
+
refId: string;
|
|
147
|
+
/** True only for the refund that moved the sale into fully refunded. */
|
|
148
|
+
closedTheSale: boolean;
|
|
149
|
+
/** `chargeback` for a dispute lost; a refund otherwise. */
|
|
150
|
+
reason?: 'refund' | 'chargeback';
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* What became of a refund. `recorded`; `no-email` for a sale that never
|
|
154
|
+
* named its buyer; `no-person` for an address the workspace holds nobody at;
|
|
155
|
+
* `gone` for a person removed between the sale and the refund.
|
|
156
|
+
*/
|
|
157
|
+
export type PluginPersonRefundOutcome = 'recorded' | 'no-email' | 'no-person' | 'gone';
|
|
158
|
+
/**
|
|
159
|
+
* The people a saved selection the owner keeps names — a saved view of one of
|
|
160
|
+
* its lists — taken for one site, as the people a sequence or a send works
|
|
161
|
+
* through.
|
|
162
|
+
*/
|
|
163
|
+
export interface PluginPersonViewRequest {
|
|
164
|
+
orgId: string;
|
|
165
|
+
/** The site the people are taken for: only records it holds are answered. */
|
|
166
|
+
hostId: string;
|
|
167
|
+
/** The view, by the id the owner's record list handed out (`plugin-record-lists`). */
|
|
168
|
+
viewId: string;
|
|
169
|
+
/** The member asking: a view they may not list does not exist for them. */
|
|
170
|
+
viewerUid: string;
|
|
171
|
+
/** The most people answered. */
|
|
172
|
+
limit: number;
|
|
173
|
+
}
|
|
174
|
+
export type PluginPersonViewPeople = {
|
|
175
|
+
ok: true;
|
|
176
|
+
people: PluginPersonRecordRef[];
|
|
177
|
+
/** How many the view selects, as far as the owner read it. */
|
|
178
|
+
total: number;
|
|
179
|
+
/** The view selects more than `limit`, or more than the owner read. */
|
|
180
|
+
truncated: boolean;
|
|
181
|
+
} | {
|
|
182
|
+
ok: false;
|
|
183
|
+
/**
|
|
184
|
+
* `not-found`: no such view, or not this member's to list.
|
|
185
|
+
* `not-people`: a view of something that is not people.
|
|
186
|
+
* `unsupported`: the view narrows by something the owner cannot apply
|
|
187
|
+
* outside its own list, so taking it would select more people than the
|
|
188
|
+
* view shows; `unsupported` names what, in the owner's words.
|
|
189
|
+
*/
|
|
190
|
+
reason: 'not-found' | 'not-people' | 'unsupported';
|
|
191
|
+
unsupported?: string[];
|
|
192
|
+
};
|
|
193
|
+
/** Records to ask about, by the refs the owner handed out. */
|
|
194
|
+
export interface PluginPersonWroteInRequest {
|
|
195
|
+
orgId: string;
|
|
196
|
+
records: readonly PluginPersonRecordRef[];
|
|
197
|
+
}
|
|
198
|
+
export interface PluginPersonRecords {
|
|
199
|
+
/** The person an address belongs to, or `null`. A read; may throw, and the caller decides which way a failure falls. */
|
|
200
|
+
find(request: PluginPersonFindRequest): Promise<PluginPersonRecord | null>;
|
|
201
|
+
/** The records named, in the order asked; `null` for one that is gone. */
|
|
202
|
+
read(request: PluginPersonReadRequest): Promise<Array<PluginPersonRecord | null>>;
|
|
203
|
+
/**
|
|
204
|
+
* Files the person under the containers. Optional: an owner that keeps no
|
|
205
|
+
* containers answers nothing. `filed: false` is a record the owner could
|
|
206
|
+
* not find for the site.
|
|
207
|
+
*/
|
|
208
|
+
fileUnder?(request: PluginPersonFileRequest): Promise<{
|
|
209
|
+
filed: boolean;
|
|
210
|
+
}>;
|
|
211
|
+
/** Records money handed back. Optional. Never throws: the money has already moved. */
|
|
212
|
+
recordRefund?(request: PluginPersonRefundRequest): Promise<PluginPersonRefundOutcome>;
|
|
213
|
+
/** The people a saved view selects for a site. Optional: an owner that keeps no views answers nothing. */
|
|
214
|
+
peopleInView?(request: PluginPersonViewRequest): Promise<PluginPersonViewPeople>;
|
|
215
|
+
/**
|
|
216
|
+
* Whether each person has ever written to the workspace — an email they
|
|
217
|
+
* sent, on their record — in the order asked; `null` for one the owner
|
|
218
|
+
* could not answer. Optional.
|
|
219
|
+
*/
|
|
220
|
+
wroteIn?(request: PluginPersonWroteInRequest): Promise<Array<boolean | null>>;
|
|
221
|
+
}
|
|
222
|
+
export declare const PLUGIN_PERSON_RECORDS: import("./plugin-services").PluginServiceContract<PluginPersonRecords>;
|
|
223
|
+
/**
|
|
224
|
+
* Registers the plugin that keeps people. The owner is the loader's marker
|
|
225
|
+
* when a register fn is running, else `options.pluginId`; with neither the
|
|
226
|
+
* registration throws, and a second plugin's service is refused naming both —
|
|
227
|
+
* the incumbent keeps serving.
|
|
228
|
+
*/
|
|
229
|
+
export declare function registerPluginPersonRecords(records: PluginPersonRecords, options?: {
|
|
230
|
+
pluginId?: string;
|
|
231
|
+
}): void;
|
|
232
|
+
export interface ResolvedPluginPersonRecords {
|
|
233
|
+
/** The plugin that keeps people. */
|
|
234
|
+
pluginId: string;
|
|
235
|
+
records: PluginPersonRecords;
|
|
236
|
+
}
|
|
237
|
+
/** The service with its owner, or `null` when no plugin keeps people here. */
|
|
238
|
+
export declare function pluginPersonRecords(): ResolvedPluginPersonRecords | null;
|
|
239
|
+
/**
|
|
240
|
+
* The person an address belongs to, or `null` — for nobody found, and for a
|
|
241
|
+
* workspace no plugin keeps people for. A failed read is the owner's to
|
|
242
|
+
* throw and the caller's to decide which way it falls.
|
|
243
|
+
*/
|
|
244
|
+
export declare function findPluginPerson(request: PluginPersonFindRequest): Promise<PluginPersonRecord | null>;
|
|
245
|
+
/**
|
|
246
|
+
* The records named, in the order asked, `null` for each that is gone — or
|
|
247
|
+
* `null` whole when no plugin keeps people here, which is not "all gone".
|
|
248
|
+
*/
|
|
249
|
+
export declare function readPluginPeople(request: PluginPersonReadRequest): Promise<Array<PluginPersonRecord | null> | null>;
|
|
250
|
+
/**
|
|
251
|
+
* Files the person under the containers through whichever plugin keeps
|
|
252
|
+
* people, or answers `null` when none does or the one that does keeps no
|
|
253
|
+
* containers. A failed write throws, as the caller's own write would have.
|
|
254
|
+
*/
|
|
255
|
+
export declare function filePluginPersonUnder(request: PluginPersonFileRequest): Promise<{
|
|
256
|
+
filed: boolean;
|
|
257
|
+
} | null>;
|
|
258
|
+
/**
|
|
259
|
+
* Hands a refund to whichever plugin keeps people, or answers `null` when
|
|
260
|
+
* none does. Never throws: every caller has already moved the money and
|
|
261
|
+
* recorded it on its own document, and a person's figure is derived from it.
|
|
262
|
+
*/
|
|
263
|
+
export declare function recordPluginPersonRefund(request: PluginPersonRefundRequest): Promise<PluginPersonRefundOutcome | null>;
|
|
264
|
+
/**
|
|
265
|
+
* The people a saved view selects for a site, or `null` when no plugin keeps
|
|
266
|
+
* people here or the one that does keeps no views. A failed read throws.
|
|
267
|
+
*/
|
|
268
|
+
export declare function pluginPeopleInView(request: PluginPersonViewRequest): Promise<PluginPersonViewPeople | null>;
|
|
269
|
+
/**
|
|
270
|
+
* Whether each person has ever written to the workspace, in the order asked
|
|
271
|
+
* — `null` for each the owner could not answer, and `null` whole when no
|
|
272
|
+
* plugin keeps people here or the one that does cannot say. Never throws: a
|
|
273
|
+
* caller reads an unknown as unknown.
|
|
274
|
+
*/
|
|
275
|
+
export declare function pluginPeopleWroteIn(request: PluginPersonWroteInRequest): Promise<Array<boolean | null> | null>;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright 2026 Aglyn LLC
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/ import { definePluginServiceContract, registerPluginService, resolvePluginServices } from "./plugin-services.js";
|
|
18
|
+
export const PLUGIN_PERSON_RECORDS = definePluginServiceContract('core.person-records', {
|
|
19
|
+
multiple: false
|
|
20
|
+
});
|
|
21
|
+
/**
|
|
22
|
+
* Registers the plugin that keeps people. The owner is the loader's marker
|
|
23
|
+
* when a register fn is running, else `options.pluginId`; with neither the
|
|
24
|
+
* registration throws, and a second plugin's service is refused naming both —
|
|
25
|
+
* the incumbent keeps serving.
|
|
26
|
+
*/ export function registerPluginPersonRecords(records, options) {
|
|
27
|
+
registerPluginService(PLUGIN_PERSON_RECORDS, records, _extends({}, (options == null ? void 0 : options.pluginId) ? {
|
|
28
|
+
pluginId: options.pluginId
|
|
29
|
+
} : {}));
|
|
30
|
+
}
|
|
31
|
+
/** The service with its owner, or `null` when no plugin keeps people here. */ export function pluginPersonRecords() {
|
|
32
|
+
const entry = resolvePluginServices(PLUGIN_PERSON_RECORDS)[0];
|
|
33
|
+
return entry ? {
|
|
34
|
+
pluginId: entry.pluginId,
|
|
35
|
+
records: entry.impl
|
|
36
|
+
} : null;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The person an address belongs to, or `null` — for nobody found, and for a
|
|
40
|
+
* workspace no plugin keeps people for. A failed read is the owner's to
|
|
41
|
+
* throw and the caller's to decide which way it falls.
|
|
42
|
+
*/ export async function findPluginPerson(request) {
|
|
43
|
+
const resolved = pluginPersonRecords();
|
|
44
|
+
if (!resolved) return null;
|
|
45
|
+
return await resolved.records.find(request);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The records named, in the order asked, `null` for each that is gone — or
|
|
49
|
+
* `null` whole when no plugin keeps people here, which is not "all gone".
|
|
50
|
+
*/ export async function readPluginPeople(request) {
|
|
51
|
+
const resolved = pluginPersonRecords();
|
|
52
|
+
if (!resolved) return null;
|
|
53
|
+
if (!request.records.length) return [];
|
|
54
|
+
return await resolved.records.read(request);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Files the person under the containers through whichever plugin keeps
|
|
58
|
+
* people, or answers `null` when none does or the one that does keeps no
|
|
59
|
+
* containers. A failed write throws, as the caller's own write would have.
|
|
60
|
+
*/ export async function filePluginPersonUnder(request) {
|
|
61
|
+
const resolved = pluginPersonRecords();
|
|
62
|
+
if (!(resolved == null ? void 0 : resolved.records.fileUnder)) return null;
|
|
63
|
+
if (!request.ids.length) return {
|
|
64
|
+
filed: false
|
|
65
|
+
};
|
|
66
|
+
return await resolved.records.fileUnder(request);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Hands a refund to whichever plugin keeps people, or answers `null` when
|
|
70
|
+
* none does. Never throws: every caller has already moved the money and
|
|
71
|
+
* recorded it on its own document, and a person's figure is derived from it.
|
|
72
|
+
*/ export async function recordPluginPersonRefund(request) {
|
|
73
|
+
const resolved = pluginPersonRecords();
|
|
74
|
+
if (!(resolved == null ? void 0 : resolved.records.recordRefund)) return null;
|
|
75
|
+
try {
|
|
76
|
+
return await resolved.records.recordRefund(request);
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.error('[person-records] the record system could not record a refund', error);
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The people a saved view selects for a site, or `null` when no plugin keeps
|
|
84
|
+
* people here or the one that does keeps no views. A failed read throws.
|
|
85
|
+
*/ export async function pluginPeopleInView(request) {
|
|
86
|
+
const resolved = pluginPersonRecords();
|
|
87
|
+
if (!(resolved == null ? void 0 : resolved.records.peopleInView)) return null;
|
|
88
|
+
return await resolved.records.peopleInView(request);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Whether each person has ever written to the workspace, in the order asked
|
|
92
|
+
* — `null` for each the owner could not answer, and `null` whole when no
|
|
93
|
+
* plugin keeps people here or the one that does cannot say. Never throws: a
|
|
94
|
+
* caller reads an unknown as unknown.
|
|
95
|
+
*/ export async function pluginPeopleWroteIn(request) {
|
|
96
|
+
const resolved = pluginPersonRecords();
|
|
97
|
+
if (!(resolved == null ? void 0 : resolved.records.wroteIn)) return null;
|
|
98
|
+
if (!request.records.length) return [];
|
|
99
|
+
try {
|
|
100
|
+
return await resolved.records.wroteIn(request);
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.error('[person-records] the record system could not say who wrote in', error);
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
//# sourceMappingURL=plugin-person-records.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/plugin-manager/plugin-person-records.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 {\n definePluginServiceContract,\n registerPluginService,\n resolvePluginServices,\n} from './plugin-services'\n\n/**\n * THE PEOPLE A WORKSPACE KEEPS, asked for by the plugins that do not keep\n * them (AGL-3080).\n *\n * `plugin-contact-capture` is how a silo hands somebody it MET to the plugin\n * that keeps people. This is the other half: a plugin that has an address, or\n * a record the owner handed it, and needs the person behind it.\n *\n * - a flow email asking whether the person agreed to marketing mail;\n * - a campaign filling in the name a merge tag reads;\n * - a refund taking money back off what a customer is worth;\n * - an automation filing somebody under a campaign;\n * - a sales sequence reading the people a rep enrolls.\n *\n * Each of those used to open the owner's collection itself — its path, its\n * address index, which site may see which document — and broke the day the\n * owner changed one. None of it is visible to `check:lib-boundaries`, because\n * a collection name is not an import.\n *\n * So the plugin that keeps people registers ONE service here, and every rule\n * stays the owner's: how an address is keyed, what an alternate address a\n * merge folded in still answers to, which site may see which record, and what\n * a refund or a filing writes.\n *\n * ## What a record is\n *\n * A {@link PluginPersonRecord} is a kind and an id in the owner's own words —\n * the words `plugin-record-routes` addresses the record by — the person's\n * primary address, and the record as the owner stores it. The fields the\n * PLATFORM defines on a person record (the consent basis\n * `marketing-consent.ts` reads, the `emailState` verdict, the `visibleTo`\n * scope) are read off it with the platform's own readers; anything else is\n * the owner's and is documented with its registration.\n *\n * ## Not registered is an answer\n *\n * Every reader answers `null` when no plugin keeps people in this process,\n * which is a workspace with no record system and is not \"nobody found\". A\n * caller treats the two differently: a send with no record system has no\n * basis to read, which is not the same as a person who declined.\n *\n * A single-implementation contract: a workspace keeps one set of people, so\n * a second plugin's service is refused naming both and the incumbent keeps\n * serving. Registered from the owner's server declarations, so it is in place\n * in a process that never loaded the owner's API surface.\n *\n * ## The caller proves who is asking\n *\n * Like the capture and timeline seams, the registry authenticates nobody. A\n * caller decides in its own terms, before it asks, that the read or the write\n * is the workspace's to make.\n *\n * Server-side: reached by its own subpath, never through\n * `plugin-manager/index.ts`.\n */\n\n/** A person record, by the owner's word for its kind and its id. */\nexport interface PluginPersonRecordRef {\n /** The owner's word for the record — the kind `plugin-record-routes` addresses it by. */\n kind: string\n id: string\n}\n\n/** One person record, as the plugin that keeps people shares it. */\nexport interface PluginPersonRecord extends PluginPersonRecordRef {\n /** The record's primary address, normalized, or `null` when it holds none. */\n email: string | null\n /**\n * The record as the owner stores it. The platform's own fields on it are\n * read with the platform's readers; the rest is the owner's, documented\n * with its registration.\n */\n data: Readonly<Record<string, unknown>>\n}\n\n/** Who to find by address, and where. */\nexport interface PluginPersonFindRequest {\n /**\n * The organization whose people are searched. A caller that knows only the\n * site names `hostId` instead, and the owner reads the organization off it.\n */\n orgId?: string | null\n /** The site asking. Required with {@link onlyVisibleToSite}. */\n hostId?: string | null\n /** Raw: the owner normalizes it, alternate addresses included. */\n email: unknown\n /**\n * Answer only a record `hostId` may see. A record the address names but the\n * site cannot see is `null`, never a reason to look further — one address\n * names one person.\n */\n onlyVisibleToSite?: boolean\n /**\n * Look at every kind of record the owner keeps a person as, in the owner's\n * order, instead of only the one a known person is held as. A send deciding\n * whether it may mail somebody asks for this: a person not yet qualified is\n * still a person whose answer counts.\n */\n anyKind?: boolean\n}\n\n/** Records to read, by the refs the owner handed out. */\nexport interface PluginPersonReadRequest {\n orgId: string\n records: readonly PluginPersonRecordRef[]\n}\n\n/**\n * File a person under containers (`plugin-containers.ts`) — the merchant's\n * own act, through an automation step or an enrollment. Filing is not\n * consent.\n */\nexport interface PluginPersonFileRequest {\n /** The site filing them: the person is filed under the containers as this site holds them. */\n hostId: string\n orgId?: string | null\n record: PluginPersonRecordRef\n /** The container kind, as `plugin-containers.ts` declares it. */\n containerKind: string\n ids: readonly string[]\n}\n\n/**\n * Money handed back to a person a silo took it from: a refund, or a dispute\n * lost. The owner records it beside what the person is worth; it never\n * creates a person to hold it.\n */\nexport interface PluginPersonRefundRequest {\n /** The site the money was taken on. */\n hostId: string\n /** The buyer's address as the sale recorded it. Raw: the owner normalizes it. */\n email: unknown\n /** Cents reversed by THIS refund, never the sale's total. */\n amountCents: number\n /** The silo's own document the money went back on — what a timeline entry points at. */\n refId: string\n /** True only for the refund that moved the sale into fully refunded. */\n closedTheSale: boolean\n /** `chargeback` for a dispute lost; a refund otherwise. */\n reason?: 'refund' | 'chargeback'\n}\n\n/**\n * What became of a refund. `recorded`; `no-email` for a sale that never\n * named its buyer; `no-person` for an address the workspace holds nobody at;\n * `gone` for a person removed between the sale and the refund.\n */\nexport type PluginPersonRefundOutcome = 'recorded' | 'no-email' | 'no-person' | 'gone'\n\n/**\n * The people a saved selection the owner keeps names — a saved view of one of\n * its lists — taken for one site, as the people a sequence or a send works\n * through.\n */\nexport interface PluginPersonViewRequest {\n orgId: string\n /** The site the people are taken for: only records it holds are answered. */\n hostId: string\n /** The view, by the id the owner's record list handed out (`plugin-record-lists`). */\n viewId: string\n /** The member asking: a view they may not list does not exist for them. */\n viewerUid: string\n /** The most people answered. */\n limit: number\n}\n\nexport type PluginPersonViewPeople =\n | {\n ok: true\n people: PluginPersonRecordRef[]\n /** How many the view selects, as far as the owner read it. */\n total: number\n /** The view selects more than `limit`, or more than the owner read. */\n truncated: boolean\n }\n | {\n ok: false\n /**\n * `not-found`: no such view, or not this member's to list.\n * `not-people`: a view of something that is not people.\n * `unsupported`: the view narrows by something the owner cannot apply\n * outside its own list, so taking it would select more people than the\n * view shows; `unsupported` names what, in the owner's words.\n */\n reason: 'not-found' | 'not-people' | 'unsupported'\n unsupported?: string[]\n }\n\n/** Records to ask about, by the refs the owner handed out. */\nexport interface PluginPersonWroteInRequest {\n orgId: string\n records: readonly PluginPersonRecordRef[]\n}\n\nexport interface PluginPersonRecords {\n /** The person an address belongs to, or `null`. A read; may throw, and the caller decides which way a failure falls. */\n find(request: PluginPersonFindRequest): Promise<PluginPersonRecord | null>\n /** The records named, in the order asked; `null` for one that is gone. */\n read(request: PluginPersonReadRequest): Promise<Array<PluginPersonRecord | null>>\n /**\n * Files the person under the containers. Optional: an owner that keeps no\n * containers answers nothing. `filed: false` is a record the owner could\n * not find for the site.\n */\n fileUnder?(request: PluginPersonFileRequest): Promise<{ filed: boolean }>\n /** Records money handed back. Optional. Never throws: the money has already moved. */\n recordRefund?(request: PluginPersonRefundRequest): Promise<PluginPersonRefundOutcome>\n /** The people a saved view selects for a site. Optional: an owner that keeps no views answers nothing. */\n peopleInView?(request: PluginPersonViewRequest): Promise<PluginPersonViewPeople>\n /**\n * Whether each person has ever written to the workspace — an email they\n * sent, on their record — in the order asked; `null` for one the owner\n * could not answer. Optional.\n */\n wroteIn?(request: PluginPersonWroteInRequest): Promise<Array<boolean | null>>\n}\n\nexport const PLUGIN_PERSON_RECORDS = definePluginServiceContract<PluginPersonRecords>(\n 'core.person-records',\n { multiple: false },\n)\n\n/**\n * Registers the plugin that keeps people. The owner is the loader's marker\n * when a register fn is running, else `options.pluginId`; with neither the\n * registration throws, and a second plugin's service is refused naming both —\n * the incumbent keeps serving.\n */\nexport function registerPluginPersonRecords(\n records: PluginPersonRecords,\n options?: { pluginId?: string },\n): void {\n registerPluginService(PLUGIN_PERSON_RECORDS, records, {\n ...(options?.pluginId ? { pluginId: options.pluginId } : {}),\n })\n}\n\nexport interface ResolvedPluginPersonRecords {\n /** The plugin that keeps people. */\n pluginId: string\n records: PluginPersonRecords\n}\n\n/** The service with its owner, or `null` when no plugin keeps people here. */\nexport function pluginPersonRecords(): ResolvedPluginPersonRecords | null {\n const entry = resolvePluginServices(PLUGIN_PERSON_RECORDS)[0]\n return entry ? { pluginId: entry.pluginId, records: entry.impl } : null\n}\n\n/**\n * The person an address belongs to, or `null` — for nobody found, and for a\n * workspace no plugin keeps people for. A failed read is the owner's to\n * throw and the caller's to decide which way it falls.\n */\nexport async function findPluginPerson(\n request: PluginPersonFindRequest,\n): Promise<PluginPersonRecord | null> {\n const resolved = pluginPersonRecords()\n if (!resolved) return null\n return await resolved.records.find(request)\n}\n\n/**\n * The records named, in the order asked, `null` for each that is gone — or\n * `null` whole when no plugin keeps people here, which is not \"all gone\".\n */\nexport async function readPluginPeople(\n request: PluginPersonReadRequest,\n): Promise<Array<PluginPersonRecord | null> | null> {\n const resolved = pluginPersonRecords()\n if (!resolved) return null\n if (!request.records.length) return []\n return await resolved.records.read(request)\n}\n\n/**\n * Files the person under the containers through whichever plugin keeps\n * people, or answers `null` when none does or the one that does keeps no\n * containers. A failed write throws, as the caller's own write would have.\n */\nexport async function filePluginPersonUnder(\n request: PluginPersonFileRequest,\n): Promise<{ filed: boolean } | null> {\n const resolved = pluginPersonRecords()\n if (!resolved?.records.fileUnder) return null\n if (!request.ids.length) return { filed: false }\n return await resolved.records.fileUnder(request)\n}\n\n/**\n * Hands a refund to whichever plugin keeps people, or answers `null` when\n * none does. Never throws: every caller has already moved the money and\n * recorded it on its own document, and a person's figure is derived from it.\n */\nexport async function recordPluginPersonRefund(\n request: PluginPersonRefundRequest,\n): Promise<PluginPersonRefundOutcome | null> {\n const resolved = pluginPersonRecords()\n if (!resolved?.records.recordRefund) return null\n try {\n return await resolved.records.recordRefund(request)\n } catch (error) {\n console.error('[person-records] the record system could not record a refund', error)\n return null\n }\n}\n\n/**\n * The people a saved view selects for a site, or `null` when no plugin keeps\n * people here or the one that does keeps no views. A failed read throws.\n */\nexport async function pluginPeopleInView(\n request: PluginPersonViewRequest,\n): Promise<PluginPersonViewPeople | null> {\n const resolved = pluginPersonRecords()\n if (!resolved?.records.peopleInView) return null\n return await resolved.records.peopleInView(request)\n}\n\n/**\n * Whether each person has ever written to the workspace, in the order asked\n * — `null` for each the owner could not answer, and `null` whole when no\n * plugin keeps people here or the one that does cannot say. Never throws: a\n * caller reads an unknown as unknown.\n */\nexport async function pluginPeopleWroteIn(\n request: PluginPersonWroteInRequest,\n): Promise<Array<boolean | null> | null> {\n const resolved = pluginPersonRecords()\n if (!resolved?.records.wroteIn) return null\n if (!request.records.length) return []\n try {\n return await resolved.records.wroteIn(request)\n } catch (error) {\n console.error('[person-records] the record system could not say who wrote in', error)\n return null\n }\n}\n"],"names":["definePluginServiceContract","registerPluginService","resolvePluginServices","PLUGIN_PERSON_RECORDS","multiple","registerPluginPersonRecords","records","options","pluginId","pluginPersonRecords","entry","impl","findPluginPerson","request","resolved","find","readPluginPeople","length","read","filePluginPersonUnder","fileUnder","ids","filed","recordPluginPersonRefund","recordRefund","error","console","pluginPeopleInView","peopleInView","pluginPeopleWroteIn","wroteIn"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED,SACEA,2BAA2B,EAC3BC,qBAAqB,EACrBC,qBAAqB,QAChB,uBAAmB;AA2N1B,OAAO,MAAMC,wBAAwBH,4BACnC,uBACA;IAAEI,UAAU;AAAM,GACnB;AAED;;;;;CAKC,GACD,OAAO,SAASC,4BACdC,OAA4B,EAC5BC,OAA+B;IAE/BN,sBAAsBE,uBAAuBG,SAAS,aAChDC,CAAAA,2BAAAA,QAASC,QAAQ,IAAG;QAAEA,UAAUD,QAAQC,QAAQ;IAAC,IAAI,CAAC;AAE9D;AAQA,4EAA4E,GAC5E,OAAO,SAASC;IACd,MAAMC,QAAQR,sBAAsBC,sBAAsB,CAAC,EAAE;IAC7D,OAAOO,QAAQ;QAAEF,UAAUE,MAAMF,QAAQ;QAAEF,SAASI,MAAMC,IAAI;IAAC,IAAI;AACrE;AAEA;;;;CAIC,GACD,OAAO,eAAeC,iBACpBC,OAAgC;IAEhC,MAAMC,WAAWL;IACjB,IAAI,CAACK,UAAU,OAAO;IACtB,OAAO,MAAMA,SAASR,OAAO,CAACS,IAAI,CAACF;AACrC;AAEA;;;CAGC,GACD,OAAO,eAAeG,iBACpBH,OAAgC;IAEhC,MAAMC,WAAWL;IACjB,IAAI,CAACK,UAAU,OAAO;IACtB,IAAI,CAACD,QAAQP,OAAO,CAACW,MAAM,EAAE,OAAO,EAAE;IACtC,OAAO,MAAMH,SAASR,OAAO,CAACY,IAAI,CAACL;AACrC;AAEA;;;;CAIC,GACD,OAAO,eAAeM,sBACpBN,OAAgC;IAEhC,MAAMC,WAAWL;IACjB,IAAI,EAACK,4BAAAA,SAAUR,OAAO,CAACc,SAAS,GAAE,OAAO;IACzC,IAAI,CAACP,QAAQQ,GAAG,CAACJ,MAAM,EAAE,OAAO;QAAEK,OAAO;IAAM;IAC/C,OAAO,MAAMR,SAASR,OAAO,CAACc,SAAS,CAACP;AAC1C;AAEA;;;;CAIC,GACD,OAAO,eAAeU,yBACpBV,OAAkC;IAElC,MAAMC,WAAWL;IACjB,IAAI,EAACK,4BAAAA,SAAUR,OAAO,CAACkB,YAAY,GAAE,OAAO;IAC5C,IAAI;QACF,OAAO,MAAMV,SAASR,OAAO,CAACkB,YAAY,CAACX;IAC7C,EAAE,OAAOY,OAAO;QACdC,QAAQD,KAAK,CAAC,gEAAgEA;QAC9E,OAAO;IACT;AACF;AAEA;;;CAGC,GACD,OAAO,eAAeE,mBACpBd,OAAgC;IAEhC,MAAMC,WAAWL;IACjB,IAAI,EAACK,4BAAAA,SAAUR,OAAO,CAACsB,YAAY,GAAE,OAAO;IAC5C,OAAO,MAAMd,SAASR,OAAO,CAACsB,YAAY,CAACf;AAC7C;AAEA;;;;;CAKC,GACD,OAAO,eAAegB,oBACpBhB,OAAmC;IAEnC,MAAMC,WAAWL;IACjB,IAAI,EAACK,4BAAAA,SAAUR,OAAO,CAACwB,OAAO,GAAE,OAAO;IACvC,IAAI,CAACjB,QAAQP,OAAO,CAACW,MAAM,EAAE,OAAO,EAAE;IACtC,IAAI;QACF,OAAO,MAAMH,SAASR,OAAO,CAACwB,OAAO,CAACjB;IACxC,EAAE,OAAOY,OAAO;QACdC,QAAQD,KAAK,CAAC,iEAAiEA;QAC/E,OAAO;IACT;AACF"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import type { DocumentData, Firestore, Query } from 'firebase/firestore';
|
|
18
|
+
/**
|
|
19
|
+
* How many of a plugin's records one site produced, COUNTED in the console
|
|
20
|
+
* for another plugin's figure (AGL-3080) — the count's half of
|
|
21
|
+
* `plugin-record-lists`.
|
|
22
|
+
*
|
|
23
|
+
* A plugin that reports a share of another plugin's records — a campaign's
|
|
24
|
+
* conversions out of every form submission, booking, lead or contact the site
|
|
25
|
+
* holds — used to count the owner's collection from the browser itself: the
|
|
26
|
+
* path, which ones a site may be credited with, the filter the owner's
|
|
27
|
+
* security rules require. Each breaks the day the owner changes one.
|
|
28
|
+
*
|
|
29
|
+
* So the owner publishes a COUNT SOURCE for each record kind it keeps: the
|
|
30
|
+
* query whose aggregate count is how many records of the kind one site
|
|
31
|
+
* produced, provable by the signed-in member's read. The reader runs its own
|
|
32
|
+
* aggregation over it (`getCountFromServer`) and never learns where the
|
|
33
|
+
* records are stored. Which records a site "produced" is the owner's to say:
|
|
34
|
+
* a site's own submissions, the leads it captured, or — for a kind the
|
|
35
|
+
* organization holds once for all its sites — every one, which the reader
|
|
36
|
+
* must then present as a total across sites.
|
|
37
|
+
*
|
|
38
|
+
* ## Not registered is an answer
|
|
39
|
+
*
|
|
40
|
+
* No source for a kind means no plugin keeps it in this console. A reader
|
|
41
|
+
* withholds the figure rather than counting the collection itself.
|
|
42
|
+
*
|
|
43
|
+
* One source per kind; a second plugin claiming a kind another counts is
|
|
44
|
+
* refused, naming both.
|
|
45
|
+
*/
|
|
46
|
+
/** Which site's records a reader counts. */
|
|
47
|
+
export interface PluginRecordCountRequest {
|
|
48
|
+
hostId: string;
|
|
49
|
+
/** The site's organization, where the kind is held by the organization. */
|
|
50
|
+
orgId?: string | null;
|
|
51
|
+
}
|
|
52
|
+
export interface PluginRecordCountSource {
|
|
53
|
+
/**
|
|
54
|
+
* The query whose count is how many records of the kind the site
|
|
55
|
+
* produced, or `null` where the site has none to count (an organization
|
|
56
|
+
* not yet resolved).
|
|
57
|
+
*/
|
|
58
|
+
query(firestore: Firestore, request: PluginRecordCountRequest): Query<DocumentData> | null;
|
|
59
|
+
/**
|
|
60
|
+
* Whether the count is the ORGANIZATION's, shared by every site in it,
|
|
61
|
+
* rather than this site's alone — a reader dividing a site's figure by it
|
|
62
|
+
* must say the total crosses sites.
|
|
63
|
+
*/
|
|
64
|
+
crossesSites?: boolean;
|
|
65
|
+
}
|
|
66
|
+
export declare const PLUGIN_RECORD_COUNTS: import("./plugin-services").PluginServiceContract<PluginRecordCountSource>;
|
|
67
|
+
/**
|
|
68
|
+
* Publishes the count source for one record kind. The owner is the loader's
|
|
69
|
+
* marker when a register fn is running, else `options.pluginId`; with neither
|
|
70
|
+
* the registration throws. A kind another plugin counts throws naming both.
|
|
71
|
+
*/
|
|
72
|
+
export declare function registerPluginRecordCountSource(kind: string, source: PluginRecordCountSource, options?: {
|
|
73
|
+
pluginId?: string;
|
|
74
|
+
}): void;
|
|
75
|
+
/** The count source for a kind, or `null` when no plugin counts it here. */
|
|
76
|
+
export declare function pluginRecordCountSource(kind: string): PluginRecordCountSource | null;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ import { getRegisteringPluginId } from "../app-utils/registering-plugin.js";
|
|
17
|
+
import { definePluginServiceContract, registerPluginService, resolvePluginServices } from "./plugin-services.js";
|
|
18
|
+
export const PLUGIN_RECORD_COUNTS = definePluginServiceContract('core.record-counts', {
|
|
19
|
+
multiple: true
|
|
20
|
+
});
|
|
21
|
+
/**
|
|
22
|
+
* Publishes the count source for one record kind. The owner is the loader's
|
|
23
|
+
* marker when a register fn is running, else `options.pluginId`; with neither
|
|
24
|
+
* the registration throws. A kind another plugin counts throws naming both.
|
|
25
|
+
*/ export function registerPluginRecordCountSource(kind, source, options) {
|
|
26
|
+
var _ref, _getRegisteringPluginId;
|
|
27
|
+
const key = kind.trim();
|
|
28
|
+
if (!key) throw new Error('a record count source needs a record kind');
|
|
29
|
+
const pluginId = ((_ref = (_getRegisteringPluginId = getRegisteringPluginId()) != null ? _getRegisteringPluginId : options == null ? void 0 : options.pluginId) != null ? _ref : '').trim();
|
|
30
|
+
if (!pluginId) {
|
|
31
|
+
throw new Error(`the record count source for "${key}" was registered with no owner`);
|
|
32
|
+
}
|
|
33
|
+
const incumbent = resolvePluginServices(PLUGIN_RECORD_COUNTS).find((entry)=>entry.key === key);
|
|
34
|
+
if (incumbent && incumbent.pluginId !== pluginId) {
|
|
35
|
+
throw new Error(`record kind "${key}" is already counted by "${incumbent.pluginId}"; refused "${pluginId}"`);
|
|
36
|
+
}
|
|
37
|
+
registerPluginService(PLUGIN_RECORD_COUNTS, source, {
|
|
38
|
+
pluginId,
|
|
39
|
+
key
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/** The count source for a kind, or `null` when no plugin counts it here. */ export function pluginRecordCountSource(kind) {
|
|
43
|
+
var _ref;
|
|
44
|
+
var _resolvePluginServices_find;
|
|
45
|
+
const key = kind.trim();
|
|
46
|
+
return (_ref = (_resolvePluginServices_find = resolvePluginServices(PLUGIN_RECORD_COUNTS).find((one)=>one.key === key)) == null ? void 0 : _resolvePluginServices_find.impl) != null ? _ref : null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
//# sourceMappingURL=plugin-record-counts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/plugin-manager/plugin-record-counts.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 { DocumentData, Firestore, Query } from 'firebase/firestore'\nimport { getRegisteringPluginId } from '../app-utils/registering-plugin'\nimport {\n definePluginServiceContract,\n registerPluginService,\n resolvePluginServices,\n} from './plugin-services'\n\n/**\n * How many of a plugin's records one site produced, COUNTED in the console\n * for another plugin's figure (AGL-3080) — the count's half of\n * `plugin-record-lists`.\n *\n * A plugin that reports a share of another plugin's records — a campaign's\n * conversions out of every form submission, booking, lead or contact the site\n * holds — used to count the owner's collection from the browser itself: the\n * path, which ones a site may be credited with, the filter the owner's\n * security rules require. Each breaks the day the owner changes one.\n *\n * So the owner publishes a COUNT SOURCE for each record kind it keeps: the\n * query whose aggregate count is how many records of the kind one site\n * produced, provable by the signed-in member's read. The reader runs its own\n * aggregation over it (`getCountFromServer`) and never learns where the\n * records are stored. Which records a site \"produced\" is the owner's to say:\n * a site's own submissions, the leads it captured, or — for a kind the\n * organization holds once for all its sites — every one, which the reader\n * must then present as a total across sites.\n *\n * ## Not registered is an answer\n *\n * No source for a kind means no plugin keeps it in this console. A reader\n * withholds the figure rather than counting the collection itself.\n *\n * One source per kind; a second plugin claiming a kind another counts is\n * refused, naming both.\n */\n\n/** Which site's records a reader counts. */\nexport interface PluginRecordCountRequest {\n hostId: string\n /** The site's organization, where the kind is held by the organization. */\n orgId?: string | null\n}\n\nexport interface PluginRecordCountSource {\n /**\n * The query whose count is how many records of the kind the site\n * produced, or `null` where the site has none to count (an organization\n * not yet resolved).\n */\n query(firestore: Firestore, request: PluginRecordCountRequest): Query<DocumentData> | null\n /**\n * Whether the count is the ORGANIZATION's, shared by every site in it,\n * rather than this site's alone — a reader dividing a site's figure by it\n * must say the total crosses sites.\n */\n crossesSites?: boolean\n}\n\nexport const PLUGIN_RECORD_COUNTS = definePluginServiceContract<PluginRecordCountSource>(\n 'core.record-counts',\n { multiple: true },\n)\n\n/**\n * Publishes the count source for one record kind. The owner is the loader's\n * marker when a register fn is running, else `options.pluginId`; with neither\n * the registration throws. A kind another plugin counts throws naming both.\n */\nexport function registerPluginRecordCountSource(\n kind: string,\n source: PluginRecordCountSource,\n options?: { pluginId?: string },\n): void {\n const key = kind.trim()\n if (!key) throw new Error('a record count source needs a record kind')\n const pluginId = (getRegisteringPluginId() ?? options?.pluginId ?? '').trim()\n if (!pluginId) {\n throw new Error(`the record count source for \"${key}\" was registered with no owner`)\n }\n const incumbent = resolvePluginServices(PLUGIN_RECORD_COUNTS).find((entry) => entry.key === key)\n if (incumbent && incumbent.pluginId !== pluginId) {\n throw new Error(\n `record kind \"${key}\" is already counted by \"${incumbent.pluginId}\"; refused \"${pluginId}\"`,\n )\n }\n registerPluginService(PLUGIN_RECORD_COUNTS, source, { pluginId, key })\n}\n\n/** The count source for a kind, or `null` when no plugin counts it here. */\nexport function pluginRecordCountSource(kind: string): PluginRecordCountSource | null {\n const key = kind.trim()\n return resolvePluginServices(PLUGIN_RECORD_COUNTS).find((one) => one.key === key)?.impl ?? null\n}\n"],"names":["getRegisteringPluginId","definePluginServiceContract","registerPluginService","resolvePluginServices","PLUGIN_RECORD_COUNTS","multiple","registerPluginRecordCountSource","kind","source","options","key","trim","Error","pluginId","incumbent","find","entry","pluginRecordCountSource","one","impl"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAGD,SAASA,sBAAsB,QAAQ,qCAAiC;AACxE,SACEC,2BAA2B,EAC3BC,qBAAqB,EACrBC,qBAAqB,QAChB,uBAAmB;AAqD1B,OAAO,MAAMC,uBAAuBH,4BAClC,sBACA;IAAEI,UAAU;AAAK,GAClB;AAED;;;;CAIC,GACD,OAAO,SAASC,gCACdC,IAAY,EACZC,MAA+B,EAC/BC,OAA+B;QAIbT,MAAAA;IAFlB,MAAMU,MAAMH,KAAKI,IAAI;IACrB,IAAI,CAACD,KAAK,MAAM,IAAIE,MAAM;IAC1B,MAAMC,WAAW,EAACb,QAAAA,0BAAAA,oCAAAA,0BAA4BS,2BAAAA,QAASI,QAAQ,YAA7Cb,OAAiD,IAAIW,IAAI;IAC3E,IAAI,CAACE,UAAU;QACb,MAAM,IAAID,MAAM,CAAC,6BAA6B,EAAEF,IAAI,8BAA8B,CAAC;IACrF;IACA,MAAMI,YAAYX,sBAAsBC,sBAAsBW,IAAI,CAAC,CAACC,QAAUA,MAAMN,GAAG,KAAKA;IAC5F,IAAII,aAAaA,UAAUD,QAAQ,KAAKA,UAAU;QAChD,MAAM,IAAID,MACR,CAAC,aAAa,EAAEF,IAAI,yBAAyB,EAAEI,UAAUD,QAAQ,CAAC,YAAY,EAAEA,SAAS,CAAC,CAAC;IAE/F;IACAX,sBAAsBE,sBAAsBI,QAAQ;QAAEK;QAAUH;IAAI;AACtE;AAEA,0EAA0E,GAC1E,OAAO,SAASO,wBAAwBV,IAAY;;QAE3CJ;IADP,MAAMO,MAAMH,KAAKI,IAAI;IACrB,gBAAOR,8BAAAA,sBAAsBC,sBAAsBW,IAAI,CAAC,CAACG,MAAQA,IAAIR,GAAG,KAAKA,yBAAtEP,4BAA4EgB,IAAI,mBAAI;AAC7F"}
|
|
@@ -104,6 +104,20 @@ export interface PluginRecordEmailReachRequest {
|
|
|
104
104
|
/** The addresses delivered to, as the send addressed them. */
|
|
105
105
|
emails: readonly string[];
|
|
106
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* The people who wrote back to mail the workspace sent them (AGL-3080), so
|
|
109
|
+
* the record system can say a person is engaged — a lead nobody had worked is
|
|
110
|
+
* being worked now. Only a real reply: an opt-out answered with "remove me"
|
|
111
|
+
* is a refusal, filed through the suppression lists, and is not handed here.
|
|
112
|
+
*/
|
|
113
|
+
export interface PluginRecordEmailReplyRequest {
|
|
114
|
+
/** The organization whose records the reply is about. */
|
|
115
|
+
orgId: string;
|
|
116
|
+
/** The site the mail went out as; only records it holds are moved. */
|
|
117
|
+
hostId: string;
|
|
118
|
+
/** The addresses that wrote back, as the mail addressed them. */
|
|
119
|
+
emails: readonly string[];
|
|
120
|
+
}
|
|
107
121
|
export interface PluginRecordEmailStateWriter {
|
|
108
122
|
/** Never throws: a list is the control, the stamp is what a person reads. */
|
|
109
123
|
stamp(request: PluginRecordEmailStateRequest): Promise<PluginRecordEmailStateReport>;
|
|
@@ -120,6 +134,11 @@ export interface PluginRecordEmailStateWriter {
|
|
|
120
134
|
* already gone.
|
|
121
135
|
*/
|
|
122
136
|
reached?(request: PluginRecordEmailReachRequest): Promise<PluginRecordEmailStateReport>;
|
|
137
|
+
/**
|
|
138
|
+
* Notes that these people replied. Optional: a record system with no stage
|
|
139
|
+
* for it answers nothing. Never throws: the reply has already arrived.
|
|
140
|
+
*/
|
|
141
|
+
replied?(request: PluginRecordEmailReplyRequest): Promise<PluginRecordEmailStateReport>;
|
|
123
142
|
}
|
|
124
143
|
export declare const PLUGIN_RECORD_EMAIL_STATE: import("./plugin-services").PluginServiceContract<PluginRecordEmailStateWriter>;
|
|
125
144
|
/**
|
|
@@ -159,3 +178,10 @@ export declare function stampRecordEmailEngagement(request: PluginRecordEmailEng
|
|
|
159
178
|
* send has already delivered, and its bookkeeping must not fail it.
|
|
160
179
|
*/
|
|
161
180
|
export declare function stampRecordEmailReach(request: PluginRecordEmailReachRequest): Promise<PluginRecordEmailStateReport | null>;
|
|
181
|
+
/**
|
|
182
|
+
* Hands the addresses that wrote back to whichever plugin keeps the records
|
|
183
|
+
* (AGL-3080). Answers `null` when no plugin keeps records, or the one that
|
|
184
|
+
* does keeps no such stage. Never throws: the reply is already filed, and its
|
|
185
|
+
* bookkeeping must not fail the sync that read it.
|
|
186
|
+
*/
|
|
187
|
+
export declare function stampRecordEmailReply(request: PluginRecordEmailReplyRequest): Promise<PluginRecordEmailStateReport | null>;
|
|
@@ -81,5 +81,21 @@ export const PLUGIN_RECORD_EMAIL_STATE = definePluginServiceContract('core.recor
|
|
|
81
81
|
return null;
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Hands the addresses that wrote back to whichever plugin keeps the records
|
|
86
|
+
* (AGL-3080). Answers `null` when no plugin keeps records, or the one that
|
|
87
|
+
* does keeps no such stage. Never throws: the reply is already filed, and its
|
|
88
|
+
* bookkeeping must not fail the sync that read it.
|
|
89
|
+
*/ export async function stampRecordEmailReply(request) {
|
|
90
|
+
if (!request.emails.length) return null;
|
|
91
|
+
const resolved = pluginRecordEmailStateWriter();
|
|
92
|
+
if (!(resolved == null ? void 0 : resolved.writer.replied)) return null;
|
|
93
|
+
try {
|
|
94
|
+
return await resolved.writer.replied(request);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.error('[record-email-state] the record system could not note a reply', error);
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
84
100
|
|
|
85
101
|
//# sourceMappingURL=plugin-record-email-state.js.map
|