@aglyn/aglyn 1.0.0-beta.217 → 1.0.0-beta.219

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (348) hide show
  1. package/package.json +14 -14
  2. package/src/lib/app-utils/actions.d.ts +25 -374
  3. package/src/lib/app-utils/actions.js +101 -561
  4. package/src/lib/app-utils/actions.js.map +1 -1
  5. package/src/lib/app-utils/activity-presenter.d.ts +3 -3
  6. package/src/lib/app-utils/activity-presenter.js +36 -52
  7. package/src/lib/app-utils/activity-presenter.js.map +1 -1
  8. package/src/lib/app-utils/admin-audit-index.js +2 -2
  9. package/src/lib/app-utils/admin-audit-index.js.map +1 -1
  10. package/src/lib/app-utils/analytics-events.d.ts +11 -2
  11. package/src/lib/app-utils/analytics-events.js +11 -2
  12. package/src/lib/app-utils/analytics-events.js.map +1 -1
  13. package/src/lib/app-utils/analytics-provider.d.ts +182 -0
  14. package/src/lib/app-utils/analytics-provider.js +133 -0
  15. package/src/lib/app-utils/analytics-provider.js.map +1 -0
  16. package/src/lib/app-utils/api-plugins.d.ts +46 -0
  17. package/src/lib/app-utils/api-plugins.js +19 -0
  18. package/src/lib/app-utils/api-plugins.js.map +1 -1
  19. package/src/lib/app-utils/{marketplace-overrides.d.ts → artifact-overrides.d.ts} +9 -6
  20. package/src/lib/app-utils/{marketplace-overrides.js → artifact-overrides.js} +10 -7
  21. package/src/lib/app-utils/artifact-overrides.js.map +1 -0
  22. package/src/lib/app-utils/{marketplace-provenance.d.ts → artifact-provenance.d.ts} +12 -10
  23. package/src/lib/app-utils/{marketplace-provenance.js → artifact-provenance.js} +9 -7
  24. package/src/lib/app-utils/artifact-provenance.js.map +1 -0
  25. package/src/lib/app-utils/assist-credits.js +2 -1
  26. package/src/lib/app-utils/assist-credits.js.map +1 -1
  27. package/src/lib/app-utils/binding-token-catalog.d.ts +5 -13
  28. package/src/lib/app-utils/binding-token-catalog.js +17 -41
  29. package/src/lib/app-utils/binding-token-catalog.js.map +1 -1
  30. package/src/lib/app-utils/binding-tokens.js +1 -1
  31. package/src/lib/app-utils/binding-tokens.js.map +1 -1
  32. package/src/lib/app-utils/brand-support-line.d.ts +36 -0
  33. package/src/lib/app-utils/brand-support-line.js +38 -0
  34. package/src/lib/app-utils/brand-support-line.js.map +1 -0
  35. package/src/lib/app-utils/campaign-touch.d.ts +5 -5
  36. package/src/lib/app-utils/campaign-touch.js +8 -8
  37. package/src/lib/app-utils/campaign-touch.js.map +1 -1
  38. package/src/lib/app-utils/collection-entries.d.ts +2 -2
  39. package/src/lib/app-utils/collection-entries.js.map +1 -1
  40. package/src/lib/app-utils/consent-group-change.d.ts +4 -0
  41. package/src/lib/app-utils/consent-group-change.js.map +1 -1
  42. package/src/lib/app-utils/console-record-links.d.ts +10 -89
  43. package/src/lib/app-utils/console-record-links.js +3 -107
  44. package/src/lib/app-utils/console-record-links.js.map +1 -1
  45. package/src/lib/app-utils/console-routes.d.ts +16 -7
  46. package/src/lib/app-utils/console-routes.js +9 -3
  47. package/src/lib/app-utils/console-routes.js.map +1 -1
  48. package/src/lib/app-utils/contacts.d.ts +23 -1
  49. package/src/lib/app-utils/contacts.js +21 -5
  50. package/src/lib/app-utils/contacts.js.map +1 -1
  51. package/src/lib/app-utils/cross-pool-desync.d.ts +39 -0
  52. package/src/lib/app-utils/cross-pool-desync.js +47 -0
  53. package/src/lib/app-utils/cross-pool-desync.js.map +1 -0
  54. package/src/lib/app-utils/csv-upload.d.ts +29 -0
  55. package/src/lib/app-utils/csv-upload.js +29 -0
  56. package/src/lib/app-utils/csv-upload.js.map +1 -0
  57. package/src/lib/app-utils/dataset-models.d.ts +5 -5
  58. package/src/lib/app-utils/dataset-models.js +19 -2
  59. package/src/lib/app-utils/dataset-models.js.map +1 -1
  60. package/src/lib/app-utils/datasets.d.ts +65 -11
  61. package/src/lib/app-utils/datasets.js +74 -11
  62. package/src/lib/app-utils/datasets.js.map +1 -1
  63. package/src/lib/app-utils/docs-deflection.d.ts +6 -6
  64. package/src/lib/app-utils/docs-deflection.js.map +1 -1
  65. package/src/lib/app-utils/docs-help.generated.d.ts +12 -6
  66. package/src/lib/app-utils/docs-help.generated.js +21 -6
  67. package/src/lib/app-utils/docs-help.generated.js.map +1 -1
  68. package/src/lib/app-utils/docs-index.generated.d.ts +2 -2
  69. package/src/lib/app-utils/docs-index.generated.js +514 -318
  70. package/src/lib/app-utils/docs-index.generated.js.map +1 -1
  71. package/src/lib/app-utils/docs-retrieval.d.ts +3 -3
  72. package/src/lib/app-utils/docs-retrieval.js +14 -10
  73. package/src/lib/app-utils/docs-retrieval.js.map +1 -1
  74. package/src/lib/app-utils/duplicate-resource.d.ts +4 -1
  75. package/src/lib/app-utils/duplicate-resource.js +7 -4
  76. package/src/lib/app-utils/duplicate-resource.js.map +1 -1
  77. package/src/lib/app-utils/dynamic-list-rule.d.ts +1 -1
  78. package/src/lib/app-utils/dynamic-list-rule.js.map +1 -1
  79. package/src/lib/app-utils/element-ui.d.ts +1 -1
  80. package/src/lib/app-utils/element-ui.js +1 -1
  81. package/src/lib/app-utils/element-ui.js.map +1 -1
  82. package/src/lib/app-utils/email-starter-policy.js +3 -3
  83. package/src/lib/app-utils/email-starter-policy.js.map +1 -1
  84. package/src/lib/app-utils/entity-picker-context.d.ts +10 -5
  85. package/src/lib/app-utils/entity-picker-context.js.map +1 -1
  86. package/src/lib/app-utils/error-beacon.d.ts +75 -6
  87. package/src/lib/app-utils/error-beacon.js +160 -21
  88. package/src/lib/app-utils/error-beacon.js.map +1 -1
  89. package/src/lib/app-utils/expand-repeatables.d.ts +10 -10
  90. package/src/lib/app-utils/expand-repeatables.js +10 -10
  91. package/src/lib/app-utils/expand-repeatables.js.map +1 -1
  92. package/src/lib/app-utils/host-events.d.ts +82 -0
  93. package/src/lib/app-utils/host-events.js +62 -0
  94. package/src/lib/app-utils/host-events.js.map +1 -0
  95. package/src/lib/app-utils/lockdown.d.ts +33 -1
  96. package/src/lib/app-utils/lockdown.js +45 -4
  97. package/src/lib/app-utils/lockdown.js.map +1 -1
  98. package/src/lib/app-utils/margin-utilization.d.ts +4 -69
  99. package/src/lib/app-utils/margin-utilization.js +82 -69
  100. package/src/lib/app-utils/margin-utilization.js.map +1 -1
  101. package/src/lib/app-utils/node-definition-sanitizer.d.ts +16 -16
  102. package/src/lib/app-utils/node-definition-sanitizer.js +24 -20
  103. package/src/lib/app-utils/node-definition-sanitizer.js.map +1 -1
  104. package/src/lib/app-utils/node-interactions.d.ts +7 -7
  105. package/src/lib/app-utils/node-interactions.js.map +1 -1
  106. package/src/lib/app-utils/notifications.d.ts +78 -47
  107. package/src/lib/app-utils/notifications.js +63 -44
  108. package/src/lib/app-utils/notifications.js.map +1 -1
  109. package/src/lib/app-utils/payments-configured.d.ts +8 -21
  110. package/src/lib/app-utils/payments-configured.js +8 -23
  111. package/src/lib/app-utils/payments-configured.js.map +1 -1
  112. package/src/lib/app-utils/plan-entitlements.d.ts +43 -128
  113. package/src/lib/app-utils/plan-entitlements.js +145 -304
  114. package/src/lib/app-utils/plan-entitlements.js.map +1 -1
  115. package/src/lib/app-utils/platform-brand.d.ts +10 -0
  116. package/src/lib/app-utils/platform-brand.js +14 -3
  117. package/src/lib/app-utils/platform-brand.js.map +1 -1
  118. package/src/lib/app-utils/plugin-api-rate-limit.d.ts +7 -1
  119. package/src/lib/app-utils/plugin-api-rate-limit.js +11 -3
  120. package/src/lib/app-utils/plugin-api-rate-limit.js.map +1 -1
  121. package/src/lib/app-utils/plugin-bundle-checks.js +2 -2
  122. package/src/lib/app-utils/plugin-bundle-checks.js.map +1 -1
  123. package/src/lib/app-utils/plugin-host-events.generated.d.ts +12 -0
  124. package/src/lib/app-utils/plugin-host-events.generated.js +169 -0
  125. package/src/lib/app-utils/plugin-host-events.generated.js.map +1 -0
  126. package/src/lib/app-utils/plugin-release-flags.generated.d.ts +12 -0
  127. package/src/lib/app-utils/plugin-release-flags.generated.js +106 -0
  128. package/src/lib/app-utils/plugin-release-flags.generated.js.map +1 -0
  129. package/src/lib/app-utils/realm-host-surface.generated.js +2 -0
  130. package/src/lib/app-utils/realm-host-surface.generated.js.map +1 -1
  131. package/src/lib/app-utils/release-flags.d.ts +14 -5
  132. package/src/lib/app-utils/release-flags.js +21 -125
  133. package/src/lib/app-utils/release-flags.js.map +1 -1
  134. package/src/lib/app-utils/repeat-sources.d.ts +9 -0
  135. package/src/lib/app-utils/repeat-sources.js.map +1 -1
  136. package/src/lib/app-utils/retained-refusals.d.ts +73 -0
  137. package/src/lib/app-utils/retained-refusals.js +186 -0
  138. package/src/lib/app-utils/retained-refusals.js.map +1 -0
  139. package/src/lib/app-utils/scope-tokens.d.ts +27 -0
  140. package/src/lib/app-utils/scope-tokens.js +61 -0
  141. package/src/lib/app-utils/scope-tokens.js.map +1 -1
  142. package/src/lib/app-utils/screen-link-context.js +3 -3
  143. package/src/lib/app-utils/screen-link-context.js.map +1 -1
  144. package/src/lib/app-utils/screen-route.d.ts +15 -0
  145. package/src/lib/app-utils/screen-route.js +21 -1
  146. package/src/lib/app-utils/screen-route.js.map +1 -1
  147. package/src/lib/app-utils/seo-audit.d.ts +132 -0
  148. package/src/lib/app-utils/seo-audit.js +246 -0
  149. package/src/lib/app-utils/seo-audit.js.map +1 -0
  150. package/src/lib/app-utils/seo-keywords.d.ts +48 -0
  151. package/src/lib/app-utils/seo-keywords.js +60 -0
  152. package/src/lib/app-utils/seo-keywords.js.map +1 -0
  153. package/src/lib/app-utils/seo-page-facts.d.ts +66 -0
  154. package/src/lib/app-utils/seo-page-facts.js +155 -0
  155. package/src/lib/app-utils/seo-page-facts.js.map +1 -0
  156. package/src/lib/app-utils/seo-site-scan.d.ts +126 -0
  157. package/src/lib/app-utils/seo-site-scan.js +162 -0
  158. package/src/lib/app-utils/seo-site-scan.js.map +1 -0
  159. package/src/lib/app-utils/seo-title-variables.js +1 -1
  160. package/src/lib/app-utils/seo-title-variables.js.map +1 -1
  161. package/src/lib/app-utils/server.d.ts +6 -9
  162. package/src/lib/app-utils/server.js +17 -27
  163. package/src/lib/app-utils/server.js.map +1 -1
  164. package/src/lib/app-utils/site-interactions.d.ts +501 -0
  165. package/src/lib/app-utils/site-interactions.js +554 -0
  166. package/src/lib/app-utils/site-interactions.js.map +1 -0
  167. package/src/lib/app-utils/{marketplace-theme.d.ts → site-theme.d.ts} +13 -2
  168. package/src/lib/app-utils/{marketplace-theme.js → site-theme.js} +5 -2
  169. package/src/lib/app-utils/site-theme.js.map +1 -0
  170. package/src/lib/app-utils/sitemap.d.ts +4 -3
  171. package/src/lib/app-utils/sitemap.js +9 -7
  172. package/src/lib/app-utils/sitemap.js.map +1 -1
  173. package/src/lib/app-utils/stale-build-error.d.ts +51 -0
  174. package/src/lib/app-utils/stale-build-error.js +100 -1
  175. package/src/lib/app-utils/stale-build-error.js.map +1 -1
  176. package/src/lib/app-utils/starter-templates.d.ts +20 -0
  177. package/src/lib/app-utils/starter-templates.js +49 -0
  178. package/src/lib/app-utils/starter-templates.js.map +1 -1
  179. package/src/lib/app-utils/tax-jurisdiction-figures.d.ts +118 -0
  180. package/src/lib/app-utils/tax-jurisdiction-figures.js +123 -0
  181. package/src/lib/app-utils/tax-jurisdiction-figures.js.map +1 -0
  182. package/src/lib/app-utils/theme-library.d.ts +10 -3
  183. package/src/lib/app-utils/theme-library.js +13 -4
  184. package/src/lib/app-utils/theme-library.js.map +1 -1
  185. package/src/lib/app-utils/{campaign-attribution.d.ts → utm-attribution.d.ts} +11 -6
  186. package/src/lib/app-utils/{campaign-attribution.js → utm-attribution.js} +13 -8
  187. package/src/lib/app-utils/utm-attribution.js.map +1 -0
  188. package/src/lib/app-utils/{campaign-forwarding.d.ts → utm-forwarding.d.ts} +14 -14
  189. package/src/lib/app-utils/{campaign-forwarding.js → utm-forwarding.js} +26 -26
  190. package/src/lib/app-utils/utm-forwarding.js.map +1 -0
  191. package/src/lib/app-utils/video-object.js +6 -5
  192. package/src/lib/app-utils/video-object.js.map +1 -1
  193. package/src/lib/app-utils/visitor-consent.d.ts +41 -164
  194. package/src/lib/app-utils/visitor-consent.js +66 -277
  195. package/src/lib/app-utils/visitor-consent.js.map +1 -1
  196. package/src/lib/app-utils/web-vitals-rum.d.ts +7 -7
  197. package/src/lib/app-utils/web-vitals-rum.js +31 -63
  198. package/src/lib/app-utils/web-vitals-rum.js.map +1 -1
  199. package/src/lib/app-utils/where-used.d.ts +11 -6
  200. package/src/lib/app-utils/where-used.js +3 -8
  201. package/src/lib/app-utils/where-used.js.map +1 -1
  202. package/src/lib/canvas-manager/canvas-manager.js +3 -3
  203. package/src/lib/canvas-manager/canvas-manager.js.map +1 -1
  204. package/src/lib/foundation/definitions/components.types.d.ts +1 -1
  205. package/src/lib/foundation/definitions/components.types.js +1 -1
  206. package/src/lib/foundation/definitions/components.types.js.map +1 -1
  207. package/src/lib/foundation/definitions/org-billing.types.d.ts +18 -135
  208. package/src/lib/foundation/definitions/org-billing.types.js.map +1 -1
  209. package/src/lib/foundation/definitions/organization.types.d.ts +6 -3
  210. package/src/lib/foundation/definitions/organization.types.js.map +1 -1
  211. package/src/lib/foundation/definitions/platform.types.d.ts +27 -5
  212. package/src/lib/foundation/definitions/platform.types.js.map +1 -1
  213. package/src/lib/foundation/definitions/write-deny-coverage.util.d.ts +16 -0
  214. package/src/lib/foundation/definitions/write-deny-coverage.util.js +20 -0
  215. package/src/lib/foundation/definitions/write-deny-coverage.util.js.map +1 -1
  216. package/src/lib/foundation/index.d.ts +1 -1
  217. package/src/lib/foundation/index.js.map +1 -1
  218. package/src/lib/plugin-manager/besigner-documents.d.ts +96 -0
  219. package/src/lib/plugin-manager/besigner-documents.js +61 -0
  220. package/src/lib/plugin-manager/besigner-documents.js.map +1 -0
  221. package/src/lib/plugin-manager/computed-variables.d.ts +71 -0
  222. package/src/lib/plugin-manager/computed-variables.js +74 -0
  223. package/src/lib/plugin-manager/computed-variables.js.map +1 -0
  224. package/src/lib/plugin-manager/custom-fields.d.ts +29 -2
  225. package/src/lib/plugin-manager/custom-fields.js +47 -1
  226. package/src/lib/plugin-manager/custom-fields.js.map +1 -1
  227. package/src/lib/plugin-manager/feature-plugins.d.ts +292 -20
  228. package/src/lib/plugin-manager/feature-plugins.js +105 -17
  229. package/src/lib/plugin-manager/feature-plugins.js.map +1 -1
  230. package/src/lib/plugin-manager/first-party-plugins.generated.d.ts +123 -0
  231. package/src/lib/plugin-manager/first-party-plugins.generated.js +785 -14
  232. package/src/lib/plugin-manager/first-party-plugins.generated.js.map +1 -1
  233. package/src/lib/plugin-manager/plugin-activity-actions.d.ts +12 -0
  234. package/src/lib/plugin-manager/plugin-activity-actions.js +25 -0
  235. package/src/lib/plugin-manager/plugin-activity-actions.js.map +1 -1
  236. package/src/lib/plugin-manager/plugin-contributions.d.ts +1 -1
  237. package/src/lib/plugin-manager/plugin-contributions.js.map +1 -1
  238. package/src/lib/plugin-manager/plugin-declarations-repair.d.ts +36 -0
  239. package/src/lib/plugin-manager/plugin-declarations-repair.js +64 -0
  240. package/src/lib/plugin-manager/plugin-declarations-repair.js.map +1 -0
  241. package/src/lib/plugin-manager/plugin-dependents.d.ts +101 -0
  242. package/src/lib/plugin-manager/plugin-dependents.js +75 -0
  243. package/src/lib/plugin-manager/plugin-dependents.js.map +1 -0
  244. package/src/lib/plugin-manager/plugin-distribution.d.ts +55 -0
  245. package/src/lib/plugin-manager/plugin-distribution.js +45 -0
  246. package/src/lib/plugin-manager/plugin-distribution.js.map +1 -0
  247. package/src/lib/plugin-manager/plugin-host-collections.d.ts +17 -0
  248. package/src/lib/plugin-manager/plugin-host-collections.js +6 -0
  249. package/src/lib/plugin-manager/plugin-host-collections.js.map +1 -1
  250. package/src/lib/plugin-manager/plugin-host-resources.d.ts +133 -0
  251. package/src/lib/plugin-manager/plugin-host-resources.js +52 -0
  252. package/src/lib/plugin-manager/plugin-host-resources.js.map +1 -0
  253. package/src/lib/plugin-manager/plugin-org-erasure.d.ts +28 -2
  254. package/src/lib/plugin-manager/plugin-org-erasure.js +61 -2
  255. package/src/lib/plugin-manager/plugin-org-erasure.js.map +1 -1
  256. package/src/lib/plugin-manager/plugin-plan-entitlements.d.ts +123 -0
  257. package/src/lib/plugin-manager/plugin-plan-entitlements.js +101 -0
  258. package/src/lib/plugin-manager/plugin-plan-entitlements.js.map +1 -0
  259. package/src/lib/plugin-manager/plugin-record-index.d.ts +95 -0
  260. package/src/lib/plugin-manager/plugin-record-index.js +51 -0
  261. package/src/lib/plugin-manager/plugin-record-index.js.map +1 -0
  262. package/src/lib/plugin-manager/plugin-record-written.d.ts +58 -0
  263. package/src/lib/plugin-manager/plugin-record-written.js +42 -0
  264. package/src/lib/plugin-manager/plugin-record-written.js.map +1 -0
  265. package/src/lib/plugin-manager/plugin-revenue-sources.d.ts +213 -0
  266. package/src/lib/plugin-manager/plugin-revenue-sources.js +194 -0
  267. package/src/lib/plugin-manager/plugin-revenue-sources.js.map +1 -0
  268. package/src/lib/plugin-manager/plugin-site-bundle.d.ts +145 -0
  269. package/src/lib/plugin-manager/plugin-site-bundle.js +78 -0
  270. package/src/lib/plugin-manager/plugin-site-bundle.js.map +1 -0
  271. package/src/lib/plugin-manager/plugin-site-cache.d.ts +12 -0
  272. package/src/lib/plugin-manager/plugin-site-cache.js.map +1 -1
  273. package/src/lib/plugin-manager/plugin-site-export.d.ts +81 -0
  274. package/src/lib/plugin-manager/plugin-site-export.js +40 -0
  275. package/src/lib/plugin-manager/plugin-site-export.js.map +1 -0
  276. package/src/lib/plugin-manager/plugin-sitemap-sections.d.ts +88 -0
  277. package/src/lib/plugin-manager/plugin-sitemap-sections.js +29 -0
  278. package/src/lib/plugin-manager/plugin-sitemap-sections.js.map +1 -0
  279. package/src/lib/plugin-manager/plugin-tax-profile.d.ts +20 -4
  280. package/src/lib/plugin-manager/plugin-tax-profile.js.map +1 -1
  281. package/src/lib/plugin-manager/plugin-tax-return-sources.d.ts +255 -0
  282. package/src/lib/plugin-manager/plugin-tax-return-sources.js +191 -0
  283. package/src/lib/plugin-manager/plugin-tax-return-sources.js.map +1 -0
  284. package/src/lib/plugin-manager/plugin-template-sources.d.ts +75 -0
  285. package/src/lib/plugin-manager/plugin-template-sources.js +37 -0
  286. package/src/lib/plugin-manager/plugin-template-sources.js.map +1 -0
  287. package/src/lib/plugin-manager/plugin-usage-axes.d.ts +107 -0
  288. package/src/lib/plugin-manager/plugin-usage-axes.js +107 -0
  289. package/src/lib/plugin-manager/plugin-usage-axes.js.map +1 -0
  290. package/src/lib/plugin-manager/plugin-zones.d.ts +4 -5
  291. package/src/lib/plugin-manager/plugin-zones.js.map +1 -1
  292. package/src/lib/plugin-manager/realm-host-aglyn.generated.js +2 -0
  293. package/src/lib/plugin-manager/realm-host-aglyn.generated.js.map +1 -1
  294. package/src/lib/plugin-manager/record-captured-contact.d.ts +1 -14
  295. package/src/lib/plugin-manager/record-captured-contact.js +10 -32
  296. package/src/lib/plugin-manager/record-captured-contact.js.map +1 -1
  297. package/src/lib/plugin-manager/repeat-rows.d.ts +124 -0
  298. package/src/lib/plugin-manager/repeat-rows.js +108 -0
  299. package/src/lib/plugin-manager/repeat-rows.js.map +1 -0
  300. package/src/lib/plugin-manager/submission-record-target.d.ts +144 -0
  301. package/src/lib/plugin-manager/submission-record-target.js +125 -0
  302. package/src/lib/plugin-manager/submission-record-target.js.map +1 -0
  303. package/src/lib/plugin-manager/video-embed-provider.d.ts +108 -0
  304. package/src/lib/plugin-manager/video-embed-provider.js +165 -0
  305. package/src/lib/plugin-manager/video-embed-provider.js.map +1 -0
  306. package/src/lib/types/nodes.d.ts +2 -2
  307. package/src/lib/types/nodes.js.map +1 -1
  308. package/src/lib/app-utils/campaign-attribution.js.map +0 -1
  309. package/src/lib/app-utils/campaign-forwarding.js.map +0 -1
  310. package/src/lib/app-utils/contact-holder.d.ts +0 -68
  311. package/src/lib/app-utils/contact-holder.js +0 -129
  312. package/src/lib/app-utils/contact-holder.js.map +0 -1
  313. package/src/lib/app-utils/contact-merge.d.ts +0 -136
  314. package/src/lib/app-utils/contact-merge.js +0 -412
  315. package/src/lib/app-utils/contact-merge.js.map +0 -1
  316. package/src/lib/app-utils/crm-csv.d.ts +0 -239
  317. package/src/lib/app-utils/crm-csv.js +0 -467
  318. package/src/lib/app-utils/crm-csv.js.map +0 -1
  319. package/src/lib/app-utils/crm-digest.d.ts +0 -185
  320. package/src/lib/app-utils/crm-digest.js +0 -272
  321. package/src/lib/app-utils/crm-digest.js.map +0 -1
  322. package/src/lib/app-utils/form-dataset-binding.d.ts +0 -50
  323. package/src/lib/app-utils/form-dataset-binding.js +0 -74
  324. package/src/lib/app-utils/form-dataset-binding.js.map +0 -1
  325. package/src/lib/app-utils/list-import.d.ts +0 -158
  326. package/src/lib/app-utils/list-import.js +0 -332
  327. package/src/lib/app-utils/list-import.js.map +0 -1
  328. package/src/lib/app-utils/marketplace-listing-visibility.d.ts +0 -122
  329. package/src/lib/app-utils/marketplace-listing-visibility.js +0 -147
  330. package/src/lib/app-utils/marketplace-listing-visibility.js.map +0 -1
  331. package/src/lib/app-utils/marketplace-overrides.js.map +0 -1
  332. package/src/lib/app-utils/marketplace-provenance.js.map +0 -1
  333. package/src/lib/app-utils/marketplace-theme.js.map +0 -1
  334. package/src/lib/app-utils/marketplace-update-state.d.ts +0 -119
  335. package/src/lib/app-utils/marketplace-update-state.js +0 -132
  336. package/src/lib/app-utils/marketplace-update-state.js.map +0 -1
  337. package/src/lib/app-utils/publisher-agreement.d.ts +0 -289
  338. package/src/lib/app-utils/publisher-agreement.js +0 -321
  339. package/src/lib/app-utils/publisher-agreement.js.map +0 -1
  340. package/src/lib/app-utils/wistia-embed.d.ts +0 -104
  341. package/src/lib/app-utils/wistia-embed.js +0 -138
  342. package/src/lib/app-utils/wistia-embed.js.map +0 -1
  343. package/src/lib/app-utils/workflows.d.ts +0 -136
  344. package/src/lib/app-utils/workflows.js +0 -346
  345. package/src/lib/app-utils/workflows.js.map +0 -1
  346. package/src/lib/plugin-manager/commerce-zone-props.d.ts +0 -172
  347. package/src/lib/plugin-manager/commerce-zone-props.js +0 -31
  348. package/src/lib/plugin-manager/commerce-zone-props.js.map +0 -1
@@ -1,158 +0,0 @@
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 most addresses one uploaded file may name.
19
- *
20
- * A bound on the WORK an import represents, not a capacity limit: it refuses
21
- * a FILE, before anything is written, and it can never drop a person already
22
- * on a list or trim one to make room. A merchant with more than this splits
23
- * the file, which is a nuisance; a merchant whose audience got silently
24
- * truncated has an audience they cannot reason about.
25
- *
26
- * 50,000 is Klaviyo's shape rather than a number of our own — its only
27
- * published hard import limit is a 50 MB CSV, which is the same statement in
28
- * bytes. Above this the parse itself is the cost, and it happens in one
29
- * request.
30
- */
31
- export declare const LIST_IMPORT_MAX_ADDRESSES = 50000;
32
- /**
33
- * The most characters one uploaded file may carry.
34
- *
35
- * Checked before the parse rather than after, because the parse is what the
36
- * ceiling is protecting: a 400 answered on the byte count costs nothing,
37
- * where discovering the file was too big by materializing all of its cells
38
- * has already spent the memory the limit exists to bound.
39
- */
40
- export declare const LIST_IMPORT_MAX_CHARACTERS = 8000000;
41
- /**
42
- * Local parts that make an address a ROLE account.
43
- *
44
- * A mailbox several people read, or none. M3AAWG's Vetting BCP: their
45
- * appearance on a customer list "may be indicative of poor acquisition
46
- * practices" — a list built by scraping a website collects these, a list
47
- * built from signups does not.
48
- *
49
- * Reported, never dropped. A merchant importing their own supplier contacts
50
- * legitimately has `orders@`, and an importer that quietly removed addresses
51
- * would be telling the operator a different number went on the list than did.
52
- */
53
- export declare const ROLE_ACCOUNT_LOCAL_PARTS: readonly string[];
54
- /**
55
- * Column names that say where the file came from, when the answer is "not
56
- * from people who asked".
57
- *
58
- * M3AAWG names `jigsaw` and `append` specifically. The rest are the same tell
59
- * in the vocabulary the data brokers actually use, and they are matched as
60
- * substrings of a normalized header so `Appended Email` and `append_date`
61
- * both hit.
62
- *
63
- * Every vendor surveyed prohibits purchased lists outright, Apple bans
64
- * purchased, rented and appended lists, and M3AAWG calls appending "a direct
65
- * violation of core M3AAWG values". This is not a policy we invented and the
66
- * screening exists so that a merchant cannot attest their way past it without
67
- * having been shown it.
68
- */
69
- export declare const PURCHASE_TELL_COLUMNS: readonly string[];
70
- /** What the merchant's file says about one person. */
71
- export interface ListImportRow {
72
- /** The source line, verbatim, so a bad one can be pointed at on screen. */
73
- input: string;
74
- /** The normalized address, or `null` when the line does not carry one. */
75
- email: string | null;
76
- /** A display name from the file, or `''`. */
77
- name: string;
78
- /**
79
- * Where the file says this person opted in, or `''`.
80
- *
81
- * Evidence for the operator's assertion and never a basis of its own — see
82
- * the module note.
83
- */
84
- declaredSource: string;
85
- /** When the file says they opted in, or `''`, kept as written. */
86
- declaredAt: string;
87
- }
88
- /** What one file turned out to be. */
89
- export interface ParsedListImport {
90
- /** The header row's column names, or `[]` for a bare list of addresses. */
91
- columns: string[];
92
- /**
93
- * One row per usable, first-seen address, plus one per unusable line.
94
- *
95
- * A repeat of an address already seen is collapsed and counted in
96
- * {@link duplicates} rather than carried: the membership is keyed by the
97
- * normalized address, so two lines would be one row and reporting them as
98
- * two would tell the operator they are attesting for more people than they
99
- * are. That is exactly the rule `resolveAddresses` applies to a paste.
100
- */
101
- rows: ListImportRow[];
102
- /** Rows carrying a usable address. */
103
- usable: number;
104
- /** Lines that are not addresses. Reported, never dropped. */
105
- unusable: number;
106
- /** Repeat appearances of an address already counted. */
107
- duplicates: number;
108
- /** True when the file names more than {@link LIST_IMPORT_MAX_ADDRESSES}. */
109
- overCeiling: boolean;
110
- }
111
- /** What the mechanical screening found. Signals, not verdicts. */
112
- export interface ListImportScreening {
113
- /** Addresses at a shared or unattended mailbox. */
114
- roleAccounts: string[];
115
- /** Column names in the file that read as purchase or append tells. */
116
- purchaseTellColumns: string[];
117
- /** True when the file declares an opt-in source or date per row. */
118
- declaresBasis: boolean;
119
- }
120
- /**
121
- * Reads an uploaded or pasted file into rows.
122
- *
123
- * Handles the two shapes a merchant's list actually arrives in: a CSV with a
124
- * header, and a bare column of addresses with no header at all. Both go
125
- * through one parser — `parseCsv` — because a newline-separated list of
126
- * addresses IS a single-column CSV, and a second code path for it would be a
127
- * second place for the quoting rules to differ.
128
- *
129
- * ## Every line comes back, including the bad ones
130
- *
131
- * A file that silently discarded its malformed lines would tell an operator
132
- * that 100 addresses went on the list when 94 did, and the six they never
133
- * hear about are the six they typed wrong. This is the rule `resolveAddresses`
134
- * already applies to a paste, restated for a file.
135
- */
136
- export declare function parseListImport(text: string): ParsedListImport;
137
- /**
138
- * The mechanical checks, over a parsed file.
139
- *
140
- * Cheap by construction: two substring passes and one set membership per
141
- * address. It is deliberately not a deliverability service — Omnisend's own
142
- * caveat on the one that exists is that "list cleaning confirms
143
- * deliverability only and does not establish recipient consent", and consent
144
- * is the only question this import actually turns on.
145
- */
146
- export declare function screenListImport(parsed: Pick<ParsedListImport, 'columns' | 'rows'>): ListImportScreening;
147
- /**
148
- * The sentence recorded as the REASON behind an imported person's basis.
149
- *
150
- * One line, built from what the file actually declared, so a compliance
151
- * question about one address gets an answer about that address rather than
152
- * "somebody ticked a box on an import once". Empty declarations produce the
153
- * plain sentence rather than a sentence with holes in it.
154
- */
155
- export declare function importedBasisReason(row: {
156
- declaredSource: string;
157
- declaredAt: string;
158
- }): string;
@@ -1,332 +0,0 @@
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
- * READING A MERCHANT'S CONTACT FILE, and saying what is in it.
18
- *
19
- * `docs/specs/email-competitive-gaps.md` G5 is the product gap — a customer
20
- * arriving with a list has no way to bring it — and P4 is its condition: an
21
- * importer is simultaneously the biggest onboarding blocker and the biggest
22
- * abuse vector, so it ships WITH its controls or not at all. This module is
23
- * the pure half of those controls. It parses, it de-duplicates, and it
24
- * SCREENS. It decides nothing about consent and it enrolls nobody: the
25
- * consent question belongs to `list-assignment-policy`, which the one-address
26
- * add path already asks, and an import that answered it a second way would be
27
- * exactly the defect class the register has a P1 entry for.
28
- *
29
- * ## The screening reports, it never refuses
30
- *
31
- * M3AAWG's Vetting BCP supplies two cheap mechanical checks and both are
32
- * signals rather than verdicts. A role account (`sales@`, `info@`) is, in
33
- * M3AAWG's words, indicative of poor acquisition practice — it is not proof
34
- * of one, and plenty of legitimate B2B lists carry a handful. A column named
35
- * `jigsaw` or `append` is a purchase tell, and again a merchant may simply
36
- * have named a column badly.
37
- *
38
- * So neither one drops an address. Both are put in front of the operator
39
- * BEFORE they attest, because the attestation is the thing with teeth: an
40
- * operator who states they have permission for a file whose headers say it
41
- * was appended has made a claim their own console showed them the evidence
42
- * against. That is what makes the record worth keeping.
43
- *
44
- * ## A declared basis per address, and why it is still an assertion
45
- *
46
- * P4 asks for "a declared basis per address, not one checkbox over the file".
47
- * A file may carry an opt-in source and an opt-in date per row, and when it
48
- * does they are read here and carried onto the import as evidence. They do
49
- * NOT become the person's own opt-in. Nothing arriving in a spreadsheet is a
50
- * checkbox somebody ticked; it is the merchant telling us about one, which is
51
- * an operator assertion however many columns it arrives in. The basis stays
52
- * `operator-attested` and the declared source rides along as the reason.
53
- */ import { parseCsv } from "./dataset-csv.js";
54
- import { normalizeContactEmail } from "./contacts.js";
55
- /**
56
- * The most addresses one uploaded file may name.
57
- *
58
- * A bound on the WORK an import represents, not a capacity limit: it refuses
59
- * a FILE, before anything is written, and it can never drop a person already
60
- * on a list or trim one to make room. A merchant with more than this splits
61
- * the file, which is a nuisance; a merchant whose audience got silently
62
- * truncated has an audience they cannot reason about.
63
- *
64
- * 50,000 is Klaviyo's shape rather than a number of our own — its only
65
- * published hard import limit is a 50 MB CSV, which is the same statement in
66
- * bytes. Above this the parse itself is the cost, and it happens in one
67
- * request.
68
- */ export const LIST_IMPORT_MAX_ADDRESSES = 50000;
69
- /**
70
- * The most characters one uploaded file may carry.
71
- *
72
- * Checked before the parse rather than after, because the parse is what the
73
- * ceiling is protecting: a 400 answered on the byte count costs nothing,
74
- * where discovering the file was too big by materializing all of its cells
75
- * has already spent the memory the limit exists to bound.
76
- */ export const LIST_IMPORT_MAX_CHARACTERS = 8000000;
77
- /**
78
- * Local parts that make an address a ROLE account.
79
- *
80
- * A mailbox several people read, or none. M3AAWG's Vetting BCP: their
81
- * appearance on a customer list "may be indicative of poor acquisition
82
- * practices" — a list built by scraping a website collects these, a list
83
- * built from signups does not.
84
- *
85
- * Reported, never dropped. A merchant importing their own supplier contacts
86
- * legitimately has `orders@`, and an importer that quietly removed addresses
87
- * would be telling the operator a different number went on the list than did.
88
- */ export const ROLE_ACCOUNT_LOCAL_PARTS = [
89
- 'abuse',
90
- 'admin',
91
- 'billing',
92
- 'contact',
93
- 'enquiries',
94
- 'help',
95
- 'hello',
96
- 'hr',
97
- 'info',
98
- 'inquiries',
99
- 'mail',
100
- 'marketing',
101
- 'noreply',
102
- 'no-reply',
103
- 'office',
104
- 'orders',
105
- 'postmaster',
106
- 'sales',
107
- 'security',
108
- 'staff',
109
- 'support',
110
- 'team',
111
- 'webmaster'
112
- ];
113
- /**
114
- * Column names that say where the file came from, when the answer is "not
115
- * from people who asked".
116
- *
117
- * M3AAWG names `jigsaw` and `append` specifically. The rest are the same tell
118
- * in the vocabulary the data brokers actually use, and they are matched as
119
- * substrings of a normalized header so `Appended Email` and `append_date`
120
- * both hit.
121
- *
122
- * Every vendor surveyed prohibits purchased lists outright, Apple bans
123
- * purchased, rented and appended lists, and M3AAWG calls appending "a direct
124
- * violation of core M3AAWG values". This is not a policy we invented and the
125
- * screening exists so that a merchant cannot attest their way past it without
126
- * having been shown it.
127
- */ export const PURCHASE_TELL_COLUMNS = [
128
- 'jigsaw',
129
- 'append',
130
- 'purchased',
131
- 'rented',
132
- 'databroker',
133
- 'data broker',
134
- 'leadgen',
135
- 'lead gen',
136
- 'scraped'
137
- ];
138
- /** Header aliases that name the address column. */ const EMAIL_COLUMNS = [
139
- 'email',
140
- 'emailaddress',
141
- 'email address',
142
- 'e-mail',
143
- 'e-mail address',
144
- 'mail',
145
- 'contact email',
146
- 'primary email'
147
- ];
148
- /** Header aliases that name a display name. */ const NAME_COLUMNS = [
149
- 'name',
150
- 'full name',
151
- 'fullname',
152
- 'display name',
153
- 'contact name',
154
- 'first name',
155
- 'firstname',
156
- 'given name'
157
- ];
158
- /** Header aliases carrying the merchant's declared opt-in source. */ const OPT_IN_SOURCE_COLUMNS = [
159
- 'opt-in source',
160
- 'optin source',
161
- 'opt in source',
162
- 'consent source',
163
- 'signup source',
164
- 'subscription source',
165
- 'source'
166
- ];
167
- /** Header aliases carrying the merchant's declared opt-in date. */ const OPT_IN_DATE_COLUMNS = [
168
- 'opt-in date',
169
- 'optin date',
170
- 'opt in date',
171
- 'consent date',
172
- 'signup date',
173
- 'subscribed at',
174
- 'date subscribed',
175
- 'confirmed at'
176
- ];
177
- /** Normalizes a header cell for alias matching. */ function headerKey(value) {
178
- return String(value != null ? value : '').trim().toLowerCase().replace(/[_]+/g, ' ').replace(/\s+/g, ' ');
179
- }
180
- /** The index of the first column matching one of `aliases`, or -1. */ function columnIndex(columns, aliases) {
181
- const keys = columns.map(headerKey);
182
- for (const alias of aliases){
183
- const at = keys.indexOf(alias);
184
- if (at !== -1) return at;
185
- }
186
- return -1;
187
- }
188
- /**
189
- * Whether a parsed first row is a HEADER rather than a person.
190
- *
191
- * A header is a row with no address in it. That test rather than an alias
192
- * match, because the common shape of a merchant's export is a header whose
193
- * address column is called something we have never seen — and treating that
194
- * file as headerless would import the word "Email Address" as a line that is
195
- * not an address, and shift every subsequent column read by one.
196
- *
197
- * A one-column file of bare addresses therefore has no header, correctly:
198
- * every row including the first carries an address.
199
- */ function looksLikeHeader(cells) {
200
- return !cells.some((cell)=>normalizeContactEmail(cell));
201
- }
202
- /**
203
- * Reads an uploaded or pasted file into rows.
204
- *
205
- * Handles the two shapes a merchant's list actually arrives in: a CSV with a
206
- * header, and a bare column of addresses with no header at all. Both go
207
- * through one parser — `parseCsv` — because a newline-separated list of
208
- * addresses IS a single-column CSV, and a second code path for it would be a
209
- * second place for the quoting rules to differ.
210
- *
211
- * ## Every line comes back, including the bad ones
212
- *
213
- * A file that silently discarded its malformed lines would tell an operator
214
- * that 100 addresses went on the list when 94 did, and the six they never
215
- * hear about are the six they typed wrong. This is the rule `resolveAddresses`
216
- * already applies to a paste, restated for a file.
217
- */ export function parseListImport(text) {
218
- const table = parseCsv(String(text != null ? text : ''));
219
- if (!table.length) {
220
- return {
221
- columns: [],
222
- rows: [],
223
- usable: 0,
224
- unusable: 0,
225
- duplicates: 0,
226
- overCeiling: false
227
- };
228
- }
229
- const headed = table.length > 1 && looksLikeHeader(table[0]);
230
- const columns = headed ? table[0].map((cell)=>String(cell != null ? cell : '').trim()) : [];
231
- const body = headed ? table.slice(1) : table;
232
- const emailAt = headed ? columnIndex(columns, EMAIL_COLUMNS) : 0;
233
- const nameAt = headed ? columnIndex(columns, NAME_COLUMNS) : -1;
234
- const sourceAt = headed ? columnIndex(columns, OPT_IN_SOURCE_COLUMNS) : -1;
235
- const dateAt = headed ? columnIndex(columns, OPT_IN_DATE_COLUMNS) : -1;
236
- const seen = new Set();
237
- const rows = [];
238
- let usable = 0;
239
- let unusable = 0;
240
- let duplicates = 0;
241
- let overCeiling = false;
242
- for (const cells of body){
243
- var _cells_emailAt, _cells_find, _cells_nameAt, _cells_sourceAt, _cells_dateAt;
244
- /*
245
- * The named column when the header named one, and otherwise the first
246
- * cell in the row that IS an address.
247
- *
248
- * The fallback is what makes an unrecognized header survivable: an
249
- * export whose address column is called `Primary contact e-mail (work)`
250
- * matches no alias, and refusing the whole file over a column name would
251
- * be refusing the customer's migration over our vocabulary.
252
- */ const raw = emailAt >= 0 && emailAt < cells.length ? String((_cells_emailAt = cells[emailAt]) != null ? _cells_emailAt : '') : (_cells_find = cells.find((cell)=>normalizeContactEmail(cell))) != null ? _cells_find : '';
253
- const email = normalizeContactEmail(raw);
254
- const input = String(raw != null ? raw : '').trim() || cells.join(', ').trim();
255
- if (!email) {
256
- unusable += 1;
257
- rows.push({
258
- input,
259
- email: null,
260
- name: '',
261
- declaredSource: '',
262
- declaredAt: ''
263
- });
264
- continue;
265
- }
266
- if (seen.has(email)) {
267
- duplicates += 1;
268
- continue;
269
- }
270
- if (seen.size >= LIST_IMPORT_MAX_ADDRESSES) {
271
- overCeiling = true;
272
- break;
273
- }
274
- seen.add(email);
275
- usable += 1;
276
- rows.push({
277
- input,
278
- email,
279
- name: nameAt >= 0 ? String((_cells_nameAt = cells[nameAt]) != null ? _cells_nameAt : '').trim() : '',
280
- declaredSource: sourceAt >= 0 ? String((_cells_sourceAt = cells[sourceAt]) != null ? _cells_sourceAt : '').trim() : '',
281
- declaredAt: dateAt >= 0 ? String((_cells_dateAt = cells[dateAt]) != null ? _cells_dateAt : '').trim() : ''
282
- });
283
- }
284
- return {
285
- columns,
286
- rows,
287
- usable,
288
- unusable,
289
- duplicates,
290
- overCeiling
291
- };
292
- }
293
- /**
294
- * The mechanical checks, over a parsed file.
295
- *
296
- * Cheap by construction: two substring passes and one set membership per
297
- * address. It is deliberately not a deliverability service — Omnisend's own
298
- * caveat on the one that exists is that "list cleaning confirms
299
- * deliverability only and does not establish recipient consent", and consent
300
- * is the only question this import actually turns on.
301
- */ export function screenListImport(parsed) {
302
- const roleAccounts = [];
303
- for (const row of parsed.rows){
304
- if (!row.email) continue;
305
- const local = row.email.slice(0, row.email.indexOf('@'));
306
- if (ROLE_ACCOUNT_LOCAL_PARTS.includes(local)) roleAccounts.push(row.email);
307
- }
308
- const purchaseTellColumns = parsed.columns.filter((column)=>{
309
- const key = headerKey(column);
310
- return PURCHASE_TELL_COLUMNS.some((tell)=>key.includes(tell));
311
- });
312
- return {
313
- roleAccounts,
314
- purchaseTellColumns,
315
- declaresBasis: parsed.rows.some((row)=>!!row.declaredSource || !!row.declaredAt)
316
- };
317
- }
318
- /**
319
- * The sentence recorded as the REASON behind an imported person's basis.
320
- *
321
- * One line, built from what the file actually declared, so a compliance
322
- * question about one address gets an answer about that address rather than
323
- * "somebody ticked a box on an import once". Empty declarations produce the
324
- * plain sentence rather than a sentence with holes in it.
325
- */ export function importedBasisReason(row) {
326
- const parts = [];
327
- if (row.declaredSource) parts.push(`declared source: ${row.declaredSource}`);
328
- if (row.declaredAt) parts.push(`declared opt-in: ${row.declaredAt}`);
329
- return parts.length ? `Imported from a file, attested by the operator (${parts.join('; ')}).` : 'Imported from a file, attested by the operator.';
330
- }
331
-
332
- //# sourceMappingURL=list-import.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/list-import.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 * READING A MERCHANT'S CONTACT FILE, and saying what is in it.\n *\n * `docs/specs/email-competitive-gaps.md` G5 is the product gap — a customer\n * arriving with a list has no way to bring it — and P4 is its condition: an\n * importer is simultaneously the biggest onboarding blocker and the biggest\n * abuse vector, so it ships WITH its controls or not at all. This module is\n * the pure half of those controls. It parses, it de-duplicates, and it\n * SCREENS. It decides nothing about consent and it enrolls nobody: the\n * consent question belongs to `list-assignment-policy`, which the one-address\n * add path already asks, and an import that answered it a second way would be\n * exactly the defect class the register has a P1 entry for.\n *\n * ## The screening reports, it never refuses\n *\n * M3AAWG's Vetting BCP supplies two cheap mechanical checks and both are\n * signals rather than verdicts. A role account (`sales@`, `info@`) is, in\n * M3AAWG's words, indicative of poor acquisition practice — it is not proof\n * of one, and plenty of legitimate B2B lists carry a handful. A column named\n * `jigsaw` or `append` is a purchase tell, and again a merchant may simply\n * have named a column badly.\n *\n * So neither one drops an address. Both are put in front of the operator\n * BEFORE they attest, because the attestation is the thing with teeth: an\n * operator who states they have permission for a file whose headers say it\n * was appended has made a claim their own console showed them the evidence\n * against. That is what makes the record worth keeping.\n *\n * ## A declared basis per address, and why it is still an assertion\n *\n * P4 asks for \"a declared basis per address, not one checkbox over the file\".\n * A file may carry an opt-in source and an opt-in date per row, and when it\n * does they are read here and carried onto the import as evidence. They do\n * NOT become the person's own opt-in. Nothing arriving in a spreadsheet is a\n * checkbox somebody ticked; it is the merchant telling us about one, which is\n * an operator assertion however many columns it arrives in. The basis stays\n * `operator-attested` and the declared source rides along as the reason.\n */\n\nimport { parseCsv } from './dataset-csv'\nimport { normalizeContactEmail } from './contacts'\n\n/**\n * The most addresses one uploaded file may name.\n *\n * A bound on the WORK an import represents, not a capacity limit: it refuses\n * a FILE, before anything is written, and it can never drop a person already\n * on a list or trim one to make room. A merchant with more than this splits\n * the file, which is a nuisance; a merchant whose audience got silently\n * truncated has an audience they cannot reason about.\n *\n * 50,000 is Klaviyo's shape rather than a number of our own — its only\n * published hard import limit is a 50 MB CSV, which is the same statement in\n * bytes. Above this the parse itself is the cost, and it happens in one\n * request.\n */\nexport const LIST_IMPORT_MAX_ADDRESSES = 50_000\n\n/**\n * The most characters one uploaded file may carry.\n *\n * Checked before the parse rather than after, because the parse is what the\n * ceiling is protecting: a 400 answered on the byte count costs nothing,\n * where discovering the file was too big by materializing all of its cells\n * has already spent the memory the limit exists to bound.\n */\nexport const LIST_IMPORT_MAX_CHARACTERS = 8_000_000\n\n/**\n * Local parts that make an address a ROLE account.\n *\n * A mailbox several people read, or none. M3AAWG's Vetting BCP: their\n * appearance on a customer list \"may be indicative of poor acquisition\n * practices\" — a list built by scraping a website collects these, a list\n * built from signups does not.\n *\n * Reported, never dropped. A merchant importing their own supplier contacts\n * legitimately has `orders@`, and an importer that quietly removed addresses\n * would be telling the operator a different number went on the list than did.\n */\nexport const ROLE_ACCOUNT_LOCAL_PARTS: readonly string[] = [\n 'abuse',\n 'admin',\n 'billing',\n 'contact',\n 'enquiries',\n 'help',\n 'hello',\n 'hr',\n 'info',\n 'inquiries',\n 'mail',\n 'marketing',\n 'noreply',\n 'no-reply',\n 'office',\n 'orders',\n 'postmaster',\n 'sales',\n 'security',\n 'staff',\n 'support',\n 'team',\n 'webmaster',\n]\n\n/**\n * Column names that say where the file came from, when the answer is \"not\n * from people who asked\".\n *\n * M3AAWG names `jigsaw` and `append` specifically. The rest are the same tell\n * in the vocabulary the data brokers actually use, and they are matched as\n * substrings of a normalized header so `Appended Email` and `append_date`\n * both hit.\n *\n * Every vendor surveyed prohibits purchased lists outright, Apple bans\n * purchased, rented and appended lists, and M3AAWG calls appending \"a direct\n * violation of core M3AAWG values\". This is not a policy we invented and the\n * screening exists so that a merchant cannot attest their way past it without\n * having been shown it.\n */\nexport const PURCHASE_TELL_COLUMNS: readonly string[] = [\n 'jigsaw',\n 'append',\n 'purchased',\n 'rented',\n 'databroker',\n 'data broker',\n 'leadgen',\n 'lead gen',\n 'scraped',\n]\n\n/** Header aliases that name the address column. */\nconst EMAIL_COLUMNS = [\n 'email',\n 'emailaddress',\n 'email address',\n 'e-mail',\n 'e-mail address',\n 'mail',\n 'contact email',\n 'primary email',\n]\n\n/** Header aliases that name a display name. */\nconst NAME_COLUMNS = [\n 'name',\n 'full name',\n 'fullname',\n 'display name',\n 'contact name',\n 'first name',\n 'firstname',\n 'given name',\n]\n\n/** Header aliases carrying the merchant's declared opt-in source. */\nconst OPT_IN_SOURCE_COLUMNS = [\n 'opt-in source',\n 'optin source',\n 'opt in source',\n 'consent source',\n 'signup source',\n 'subscription source',\n 'source',\n]\n\n/** Header aliases carrying the merchant's declared opt-in date. */\nconst OPT_IN_DATE_COLUMNS = [\n 'opt-in date',\n 'optin date',\n 'opt in date',\n 'consent date',\n 'signup date',\n 'subscribed at',\n 'date subscribed',\n 'confirmed at',\n]\n\n/** What the merchant's file says about one person. */\nexport interface ListImportRow {\n /** The source line, verbatim, so a bad one can be pointed at on screen. */\n input: string\n /** The normalized address, or `null` when the line does not carry one. */\n email: string | null\n /** A display name from the file, or `''`. */\n name: string\n /**\n * Where the file says this person opted in, or `''`.\n *\n * Evidence for the operator's assertion and never a basis of its own — see\n * the module note.\n */\n declaredSource: string\n /** When the file says they opted in, or `''`, kept as written. */\n declaredAt: string\n}\n\n/** What one file turned out to be. */\nexport interface ParsedListImport {\n /** The header row's column names, or `[]` for a bare list of addresses. */\n columns: string[]\n /**\n * One row per usable, first-seen address, plus one per unusable line.\n *\n * A repeat of an address already seen is collapsed and counted in\n * {@link duplicates} rather than carried: the membership is keyed by the\n * normalized address, so two lines would be one row and reporting them as\n * two would tell the operator they are attesting for more people than they\n * are. That is exactly the rule `resolveAddresses` applies to a paste.\n */\n rows: ListImportRow[]\n /** Rows carrying a usable address. */\n usable: number\n /** Lines that are not addresses. Reported, never dropped. */\n unusable: number\n /** Repeat appearances of an address already counted. */\n duplicates: number\n /** True when the file names more than {@link LIST_IMPORT_MAX_ADDRESSES}. */\n overCeiling: boolean\n}\n\n/** What the mechanical screening found. Signals, not verdicts. */\nexport interface ListImportScreening {\n /** Addresses at a shared or unattended mailbox. */\n roleAccounts: string[]\n /** Column names in the file that read as purchase or append tells. */\n purchaseTellColumns: string[]\n /** True when the file declares an opt-in source or date per row. */\n declaresBasis: boolean\n}\n\n/** Normalizes a header cell for alias matching. */\nfunction headerKey(value: string): string {\n return String(value ?? '')\n .trim()\n .toLowerCase()\n .replace(/[_]+/g, ' ')\n .replace(/\\s+/g, ' ')\n}\n\n/** The index of the first column matching one of `aliases`, or -1. */\nfunction columnIndex(columns: string[], aliases: readonly string[]): number {\n const keys = columns.map(headerKey)\n for (const alias of aliases) {\n const at = keys.indexOf(alias)\n if (at !== -1) return at\n }\n return -1\n}\n\n/**\n * Whether a parsed first row is a HEADER rather than a person.\n *\n * A header is a row with no address in it. That test rather than an alias\n * match, because the common shape of a merchant's export is a header whose\n * address column is called something we have never seen — and treating that\n * file as headerless would import the word \"Email Address\" as a line that is\n * not an address, and shift every subsequent column read by one.\n *\n * A one-column file of bare addresses therefore has no header, correctly:\n * every row including the first carries an address.\n */\nfunction looksLikeHeader(cells: readonly string[]): boolean {\n return !cells.some((cell) => normalizeContactEmail(cell))\n}\n\n/**\n * Reads an uploaded or pasted file into rows.\n *\n * Handles the two shapes a merchant's list actually arrives in: a CSV with a\n * header, and a bare column of addresses with no header at all. Both go\n * through one parser — `parseCsv` — because a newline-separated list of\n * addresses IS a single-column CSV, and a second code path for it would be a\n * second place for the quoting rules to differ.\n *\n * ## Every line comes back, including the bad ones\n *\n * A file that silently discarded its malformed lines would tell an operator\n * that 100 addresses went on the list when 94 did, and the six they never\n * hear about are the six they typed wrong. This is the rule `resolveAddresses`\n * already applies to a paste, restated for a file.\n */\nexport function parseListImport(text: string): ParsedListImport {\n const table = parseCsv(String(text ?? ''))\n if (!table.length) {\n return {\n columns: [],\n rows: [],\n usable: 0,\n unusable: 0,\n duplicates: 0,\n overCeiling: false,\n }\n }\n const headed = table.length > 1 && looksLikeHeader(table[0])\n const columns = headed ? table[0].map((cell) => String(cell ?? '').trim()) : []\n const body = headed ? table.slice(1) : table\n\n const emailAt = headed ? columnIndex(columns, EMAIL_COLUMNS) : 0\n const nameAt = headed ? columnIndex(columns, NAME_COLUMNS) : -1\n const sourceAt = headed ? columnIndex(columns, OPT_IN_SOURCE_COLUMNS) : -1\n const dateAt = headed ? columnIndex(columns, OPT_IN_DATE_COLUMNS) : -1\n\n const seen = new Set<string>()\n const rows: ListImportRow[] = []\n let usable = 0\n let unusable = 0\n let duplicates = 0\n let overCeiling = false\n\n for (const cells of body) {\n /*\n * The named column when the header named one, and otherwise the first\n * cell in the row that IS an address.\n *\n * The fallback is what makes an unrecognized header survivable: an\n * export whose address column is called `Primary contact e-mail (work)`\n * matches no alias, and refusing the whole file over a column name would\n * be refusing the customer's migration over our vocabulary.\n */\n const raw =\n emailAt >= 0 && emailAt < cells.length\n ? String(cells[emailAt] ?? '')\n : (cells.find((cell) => normalizeContactEmail(cell)) ?? '')\n const email = normalizeContactEmail(raw)\n const input = String(raw ?? '').trim() || cells.join(', ').trim()\n if (!email) {\n unusable += 1\n rows.push({\n input,\n email: null,\n name: '',\n declaredSource: '',\n declaredAt: '',\n })\n continue\n }\n if (seen.has(email)) {\n duplicates += 1\n continue\n }\n if (seen.size >= LIST_IMPORT_MAX_ADDRESSES) {\n overCeiling = true\n break\n }\n seen.add(email)\n usable += 1\n rows.push({\n input,\n email,\n name: nameAt >= 0 ? String(cells[nameAt] ?? '').trim() : '',\n declaredSource: sourceAt >= 0 ? String(cells[sourceAt] ?? '').trim() : '',\n declaredAt: dateAt >= 0 ? String(cells[dateAt] ?? '').trim() : '',\n })\n }\n\n return { columns, rows, usable, unusable, duplicates, overCeiling }\n}\n\n/**\n * The mechanical checks, over a parsed file.\n *\n * Cheap by construction: two substring passes and one set membership per\n * address. It is deliberately not a deliverability service — Omnisend's own\n * caveat on the one that exists is that \"list cleaning confirms\n * deliverability only and does not establish recipient consent\", and consent\n * is the only question this import actually turns on.\n */\nexport function screenListImport(\n parsed: Pick<ParsedListImport, 'columns' | 'rows'>,\n): ListImportScreening {\n const roleAccounts: string[] = []\n for (const row of parsed.rows) {\n if (!row.email) continue\n const local = row.email.slice(0, row.email.indexOf('@'))\n if (ROLE_ACCOUNT_LOCAL_PARTS.includes(local)) roleAccounts.push(row.email)\n }\n const purchaseTellColumns = parsed.columns.filter((column) => {\n const key = headerKey(column)\n return PURCHASE_TELL_COLUMNS.some((tell) => key.includes(tell))\n })\n return {\n roleAccounts,\n purchaseTellColumns,\n declaresBasis: parsed.rows.some(\n (row) => !!row.declaredSource || !!row.declaredAt,\n ),\n }\n}\n\n/**\n * The sentence recorded as the REASON behind an imported person's basis.\n *\n * One line, built from what the file actually declared, so a compliance\n * question about one address gets an answer about that address rather than\n * \"somebody ticked a box on an import once\". Empty declarations produce the\n * plain sentence rather than a sentence with holes in it.\n */\nexport function importedBasisReason(row: {\n declaredSource: string\n declaredAt: string\n}): string {\n const parts: string[] = []\n if (row.declaredSource) parts.push(`declared source: ${row.declaredSource}`)\n if (row.declaredAt) parts.push(`declared opt-in: ${row.declaredAt}`)\n return parts.length\n ? `Imported from a file, attested by the operator (${parts.join('; ')}).`\n : 'Imported from a file, attested by the operator.'\n}\n"],"names":["parseCsv","normalizeContactEmail","LIST_IMPORT_MAX_ADDRESSES","LIST_IMPORT_MAX_CHARACTERS","ROLE_ACCOUNT_LOCAL_PARTS","PURCHASE_TELL_COLUMNS","EMAIL_COLUMNS","NAME_COLUMNS","OPT_IN_SOURCE_COLUMNS","OPT_IN_DATE_COLUMNS","headerKey","value","String","trim","toLowerCase","replace","columnIndex","columns","aliases","keys","map","alias","at","indexOf","looksLikeHeader","cells","some","cell","parseListImport","text","table","length","rows","usable","unusable","duplicates","overCeiling","headed","body","slice","emailAt","nameAt","sourceAt","dateAt","seen","Set","raw","find","email","input","join","push","name","declaredSource","declaredAt","has","size","add","screenListImport","parsed","roleAccounts","row","local","includes","purchaseTellColumns","filter","column","key","tell","declaresBasis","importedBasisReason","parts"],"mappings":"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"}
@@ -1,122 +0,0 @@
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
- * Who is allowed to see a marketplace listing (AGL-432/658/968/1196).
19
- *
20
- * These four predicates live in core for the same reason
21
- * `MarketplaceArtifactType` (AGL-1016) and the verification policy (AGL-1217)
22
- * do: a `scope:app` project may not depend on an `aglyn:addons` lib, and the
23
- * console now has to ask the question outside the marketplace plugin. The
24
- * listing route's `generateMetadata` (AGL-876) builds a social card from the
25
- * listing document, and that card is emitted to an UNAUTHENTICATED fetcher —
26
- * so it has to apply the same visibility rule the browse grid applies, or a
27
- * rejected, private or taken-down listing gets its name and description
28
- * unfurled into a chat message by anyone holding the URL.
29
- *
30
- * They were moved rather than copied. A second copy of "is this listing
31
- * public" is the failure mode this file exists to prevent: the rule already
32
- * gates browse AND install (AGL-965 added the second call site after the
33
- * first proved insufficient on its own), and a third reading that drifts
34
- * would be a disclosure bug, not a cosmetic one.
35
- *
36
- * `libs/plugins/marketplace/src/lib/model/marketplace.ts` re-exports all four,
37
- * so publishing and install code keeps importing them from one place.
38
- */
39
- import type { MarketplaceArtifactType } from './marketplace-provenance';
40
- /**
41
- * The listing's artifact type, tolerating the pre-AGL-654 shape.
42
- *
43
- * Legacy listings carry `type`/`kind` instead; a component was the absence
44
- * of both, which is why this defaults there rather than throwing. Keeping
45
- * the fallback means old docs keep resolving correctly instead of silently
46
- * becoming un-installable.
47
- */
48
- export declare function listingArtifactType(listing: {
49
- artifactType?: string;
50
- type?: string;
51
- kind?: string;
52
- }): MarketplaceArtifactType;
53
- /**
54
- * Private plugins (AGL-968): an org builds for its own sites without
55
- * publishing to anyone. Never browsable — not even for the owner, who
56
- * reaches it through their own plugins area — and installable only by the
57
- * owning org (enforced in `install-plugin`, not in the UI). The review bar
58
- * is identical: private code still runs on our infrastructure.
59
- */
60
- export declare function isPrivateListing(listing: {
61
- visibility?: string;
62
- }): boolean;
63
- /**
64
- * Whether a listing has been soft-deleted (AGL-1196).
65
- *
66
- * Browse used to express this as `where('deletedAt','==',null)` in the query
67
- * itself. That put a MUTABLE field in a predicate: `deletedAt` flips on every
68
- * unpublish/republish, and a document that stops matching a live query can
69
- * leave a `noDocument` tombstone at its own path — which the detail page then
70
- * reads BY ID and 404s on (AGL-827, AGL-929). Filtering in memory removes the
71
- * mechanism instead of healing it.
72
- *
73
- * FALSY, not `=== null`. Firestore's `== null` matches only an explicit null
74
- * and cannot express "field is absent", so a listing written without the field
75
- * was invisible to the old query. Absent means live.
76
- *
77
- * Deliberately NOT folded into `isListingBrowsable`: that check carries an
78
- * owner exemption, so a publisher can watch their own submission move through
79
- * review. Deletion has no such exemption — a deleted listing is gone for
80
- * everyone, including the org that owns it.
81
- */
82
- export declare function isListingDeleted(listing: {
83
- deletedAt?: unknown;
84
- }): boolean;
85
- /** Whether a plugin listing is publicly browsable (AGL-432). */
86
- export declare function isListingBrowsable(listing: {
87
- artifactType?: string;
88
- type?: string;
89
- kind?: string;
90
- reviewStatus?: string;
91
- hiddenAt?: unknown;
92
- visibility?: string;
93
- workspaceLockedAt?: unknown;
94
- }): boolean;
95
- /**
96
- * Listing fields a publisher may legitimately write, each with the reason
97
- * (AGL-1361). Everything else must be denied in the rules' listing key diff.
98
- *
99
- * They live here rather than beside `MarketplaceListing` for the same reason
100
- * the visibility policy does: this module is what READS the fields that decide
101
- * whether a listing is browsable, and `scope:app` may not depend on
102
- * `aglyn:addons`. `marketplace.ts` re-exports them so publishing code keeps
103
- * one import site.
104
- *
105
- * The list is short on purpose. Nothing in the repo writes a listing
106
- * document client-side any more: the unpublish/republish toggle in the org
107
- * seller panel was the last, and it goes through the publish API since
108
- * AGL-3321 — as publish, content edits, review and install always did. So
109
- * the fields below are classified writable because a publisher OWNS them,
110
- * not because anything would break: denying the rest cost nothing, which is
111
- * how AGL-1364 closed.
112
- */
113
- export declare const LISTING_CLIENT_WRITABLE_FIELDS: Readonly<Record<string, string>>;
114
- /**
115
- * Listing keys that never reach Firestore, so the rules have no opinion.
116
- *
117
- * Empty today — `MarketplaceListing` declares no `$id`, because listing code
118
- * carries the id alongside the data rather than folding it in. Kept as the
119
- * partition's third arm so a future projection field has a home that is not
120
- * "client-writable".
121
- */
122
- export declare const LISTING_UNPERSISTED_FIELDS: Readonly<Record<string, string>>;