@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,185 +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
- import { type CrmLeadFields, type CrmTask } from './crm';
18
- /**
19
- * The zone the digest's "today" is read in when nothing else names one.
20
- *
21
- * The schedule fires at 13:00 UTC, which is 08:00 here, so the window this
22
- * zone draws is the morning the mail arrives in for the people the product
23
- * is built with. A member elsewhere reads a window that is at most a few
24
- * hours off their own, which is what a morning summary can tolerate and a
25
- * "due at 9:00" reminder could not — that reminder is the assignment
26
- * notification's job, not this one's.
27
- */
28
- export declare const CRM_DIGEST_DEFAULT_TIME_ZONE = "America/Chicago";
29
- /** How long a `new` lead may sit untouched before the digest names it. */
30
- export declare const CRM_DIGEST_LEAD_AGE_MS: number;
31
- /**
32
- * The most due tasks one org's sweep reads.
33
- *
34
- * One query per org, ordered soonest-due first, so an org with more than this
35
- * many overdue-or-today tasks digests the oldest five hundred and reports the
36
- * window as full rather than reading without bound. Five hundred is an org
37
- * whose problem is not that nobody reminded them.
38
- */
39
- export declare const CRM_DIGEST_TASK_CEILING = 500;
40
- /**
41
- * The most old leads one site's sweep reads.
42
- *
43
- * The same shape the Leads section uses, for the same reason it gives: a
44
- * lead the capture door wrote carries no `status` field, and Firestore
45
- * cannot select on a field's absence, so "unworked" is a filter over a
46
- * loaded window rather than a query. The window is the newest old leads by
47
- * first sighting, which is where the ones still worth a call are.
48
- */
49
- export declare const CRM_DIGEST_LEAD_WINDOW = 200;
50
- /** How many items one section of the email lists before "and N more". */
51
- export declare const CRM_DIGEST_LIST_MAX = 10;
52
- /** Midnight at the start of the calendar day `ms` falls in, in `timeZone`. */
53
- export declare function startOfDayInZone(ms: number, timeZone: string): number;
54
- /**
55
- * Midnight at the start of the NEXT calendar day in `timeZone` — built from
56
- * the calendar rather than by adding 24 hours, for the reason the tasks
57
- * section gives: a day a clock change falls in is 23 or 25 hours long.
58
- */
59
- export declare function startOfNextDayInZone(ms: number, timeZone: string): number;
60
- /** `YYYY-MM-DD` of the UTC day `ms` falls in — the digest's idempotence key. */
61
- export declare function utcDayKey(ms: number): string;
62
- /** The half-open window `[start of today, start of tomorrow)` in a zone. */
63
- export interface CrmDigestWindow {
64
- startMs: number;
65
- endMs: number;
66
- }
67
- export declare function crmDigestWindow(nowMs: number, timeZone: string): CrmDigestWindow;
68
- /** A due task as the digest carries it: the fields a line and a link need. */
69
- export interface CrmDigestTask extends Pick<CrmTask, 'title' | 'kind' | 'contactId' | 'companyId' | 'dealId'> {
70
- id: string;
71
- dueAtMs: number;
72
- assigneeUid: string;
73
- /** The site the task was created on — where its link opens. */
74
- hostId: string;
75
- }
76
- /** An unworked lead as the digest carries it. */
77
- export interface CrmDigestLead {
78
- id: string;
79
- hostId: string;
80
- email: string;
81
- name?: string;
82
- ownerUid?: string;
83
- firstSeenAtMs: number;
84
- }
85
- export interface CrmDigestCounts {
86
- overdue: number;
87
- today: number;
88
- leads: number;
89
- }
90
- /** One member's morning. */
91
- export interface CrmMemberDigest {
92
- overdue: CrmDigestTask[];
93
- today: CrmDigestTask[];
94
- leads: CrmDigestLead[];
95
- }
96
- /**
97
- * Where a due task stands against the digest's window. Only tasks due
98
- * BEFORE the window's end are read at all, so `later` names a task the
99
- * query should not have returned and the bucketing refuses to count.
100
- */
101
- export declare function crmDigestTaskState(dueAtMs: number, window: CrmDigestWindow): 'overdue' | 'today' | 'later';
102
- /**
103
- * Whether a lead is one the digest should name: still `new` — which an
104
- * absent status reads as, because the capture door stamps none — and first
105
- * seen at least {@link CRM_DIGEST_LEAD_AGE_MS} ago.
106
- */
107
- export declare function isUnworkedLead(lead: Pick<CrmLeadFields, 'status'> & {
108
- firstSeenAtMs?: unknown;
109
- }, nowMs: number, ageMs?: number): boolean;
110
- /**
111
- * Whether a lead is THIS member's to work: theirs by owner, or nobody's on
112
- * a site they reach. An owned lead is one person's; an unowned one is on
113
- * everybody's list until somebody takes it, which is what the digest is for.
114
- */
115
- export declare function leadIsForMember(lead: Pick<CrmDigestLead, 'ownerUid' | 'hostId'>, member: {
116
- uid: string;
117
- reachesHost: (hostId: string) => boolean;
118
- }): boolean;
119
- /**
120
- * Whether the org's plan carries the CRM (AGL-2611's `features.crm`).
121
- *
122
- * Read by key rather than through the typed flag map so this module does not
123
- * depend on the key existing: the flag lands with the CRM's gate, and a
124
- * plan that has not declared it is a plan that does not include it — a
125
- * digest about a surface the plan cannot open would be a reminder to pay.
126
- */
127
- export declare function crmDigestEntitled(features: Record<string, boolean | undefined> | null | undefined): boolean;
128
- /**
129
- * Every member's digest, from what the org's sweep read.
130
- *
131
- * A task goes to its assignee and to nobody else — an unassigned task is a
132
- * deliberate choice in the drawer, and an assignee no longer on the roster
133
- * is a task nobody owes. A lead goes to its owner, or to every member who
134
- * reaches the site when it has none. Members with nothing owed are simply
135
- * absent from the result, which is what makes "per member with open work"
136
- * cost nothing for everyone else.
137
- */
138
- export declare function buildMemberDigests(input: {
139
- tasks: readonly CrmDigestTask[];
140
- leads: readonly CrmDigestLead[];
141
- members: ReadonlyArray<{
142
- uid: string;
143
- reachesHost: (hostId: string) => boolean;
144
- }>;
145
- window: CrmDigestWindow;
146
- }): Map<string, CrmMemberDigest>;
147
- export declare function crmDigestCounts(digest: CrmMemberDigest): CrmDigestCounts;
148
- /**
149
- * The one line the notification is: "3 tasks due today, 2 overdue, 4
150
- * unworked leads". Segments that are zero are left out rather than read as
151
- * "0 overdue" — the line is what is owed, and nothing owed is no segment.
152
- */
153
- export declare function composeCrmDigestSummary(counts: CrmDigestCounts): string;
154
- export declare function composeCrmDigestSubject(counts: CrmDigestCounts): string;
155
- /** What the digest email needs from the route besides the digest itself. */
156
- export interface CrmDigestEmailInput {
157
- digest: CrmMemberDigest;
158
- nowMs: number;
159
- timeZone: string;
160
- /** The product name the mail reads as — the org's brand when white-labeled. */
161
- productName: string;
162
- /** The Tasks section, on the site the member's first task belongs to. */
163
- tasksUrl: string;
164
- /** The Leads section of a site, for the sites that have unworked leads. */
165
- leadsUrl: (hostId: string) => string;
166
- /** Account settings → Notifications, where the digest can be switched off. */
167
- settingsUrl: string;
168
- /** A site's name for a lead line; the id when the site is unknown. */
169
- hostName: (hostId: string) => string;
170
- /** The brand's support line, already prefixed, or empty. */
171
- supportLine?: string;
172
- /**
173
- * Leave out the closing paragraph and the support line (AGL-3367), for the
174
- * copy that goes inside a system email: its footer says why the mail came
175
- * and where to get help, and its body links the settings page.
176
- */
177
- omitClosing?: boolean;
178
- }
179
- /**
180
- * The plain-text email. Text rather than a designed template because the
181
- * body is a list, and `sendEmail` synthesizes the HTML part that makes its
182
- * links live. Overdue first — it is the section a reader acts on — then
183
- * today, then the leads, each capped and counted, and the links last.
184
- */
185
- export declare function composeCrmDigestEmailText(input: CrmDigestEmailInput): string;
@@ -1,272 +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
- * The daily CRM digest (AGL-2619): what one member is owed this morning,
18
- * computed from the tasks and leads a scheduled route has read.
19
- *
20
- * "Overdue" and "due today" are read off the clock at read time by design
21
- * (AGL-2599) — nothing stamps them — which is why nothing ever told anybody.
22
- * The digest is the one reader that runs on a schedule: once a day it
23
- * counts, per org and per member, the open tasks whose due date has passed
24
- * or falls today and the leads nobody has worked, and says so once, in the
25
- * console and by mail. Every judgment here is pure so the route that sends
26
- * and the spec that proves it read the same arithmetic.
27
- *
28
- * ## Whose day
29
- *
30
- * A task's "today" on screen is the READER's calendar day, from their own
31
- * clock. A server has no reader, so the digest reads the day in ONE zone —
32
- * {@link CRM_DIGEST_DEFAULT_TIME_ZONE}, the zone the schedule was chosen for
33
- * (08:00 there) — taken as a parameter so an org-level setting can supply
34
- * its own the day one exists. The idempotence key is the UTC day
35
- * ({@link utcDayKey}), which is a fact about the run and not about anybody's
36
- * morning.
37
- */ import { startOfNextZonedDay, startOfZonedDay } from "@aglyn/shared-util-timestamp/zoned-time";
38
- import { crmLeadStatus } from "./crm.js";
39
- /**
40
- * The zone the digest's "today" is read in when nothing else names one.
41
- *
42
- * The schedule fires at 13:00 UTC, which is 08:00 here, so the window this
43
- * zone draws is the morning the mail arrives in for the people the product
44
- * is built with. A member elsewhere reads a window that is at most a few
45
- * hours off their own, which is what a morning summary can tolerate and a
46
- * "due at 9:00" reminder could not — that reminder is the assignment
47
- * notification's job, not this one's.
48
- */ export const CRM_DIGEST_DEFAULT_TIME_ZONE = 'America/Chicago';
49
- /** How long a `new` lead may sit untouched before the digest names it. */ export const CRM_DIGEST_LEAD_AGE_MS = 2 * 24 * 60 * 60 * 1000;
50
- /**
51
- * The most due tasks one org's sweep reads.
52
- *
53
- * One query per org, ordered soonest-due first, so an org with more than this
54
- * many overdue-or-today tasks digests the oldest five hundred and reports the
55
- * window as full rather than reading without bound. Five hundred is an org
56
- * whose problem is not that nobody reminded them.
57
- */ export const CRM_DIGEST_TASK_CEILING = 500;
58
- /**
59
- * The most old leads one site's sweep reads.
60
- *
61
- * The same shape the Leads section uses, for the same reason it gives: a
62
- * lead the capture door wrote carries no `status` field, and Firestore
63
- * cannot select on a field's absence, so "unworked" is a filter over a
64
- * loaded window rather than a query. The window is the newest old leads by
65
- * first sighting, which is where the ones still worth a call are.
66
- */ export const CRM_DIGEST_LEAD_WINDOW = 200;
67
- /** How many items one section of the email lists before "and N more". */ export const CRM_DIGEST_LIST_MAX = 10;
68
- /*==========================================
69
- * CALENDAR DAYS IN A NAMED ZONE
70
- *
71
- * The zone math lives in `@aglyn/shared-util-timestamp/zoned-time`, where
72
- * booking slots and sending windows read it as well; the digest route and
73
- * its spec call it by the names below.
74
- *=========================================*/ /** Midnight at the start of the calendar day `ms` falls in, in `timeZone`. */ export function startOfDayInZone(ms, timeZone) {
75
- return startOfZonedDay(ms, timeZone);
76
- }
77
- /**
78
- * Midnight at the start of the NEXT calendar day in `timeZone` — built from
79
- * the calendar rather than by adding 24 hours, for the reason the tasks
80
- * section gives: a day a clock change falls in is 23 or 25 hours long.
81
- */ export function startOfNextDayInZone(ms, timeZone) {
82
- return startOfNextZonedDay(ms, timeZone);
83
- }
84
- /** `YYYY-MM-DD` of the UTC day `ms` falls in — the digest's idempotence key. */ export function utcDayKey(ms) {
85
- return new Date(ms).toISOString().slice(0, 10);
86
- }
87
- export function crmDigestWindow(nowMs, timeZone) {
88
- return {
89
- startMs: startOfDayInZone(nowMs, timeZone),
90
- endMs: startOfNextDayInZone(nowMs, timeZone)
91
- };
92
- }
93
- /**
94
- * Where a due task stands against the digest's window. Only tasks due
95
- * BEFORE the window's end are read at all, so `later` names a task the
96
- * query should not have returned and the bucketing refuses to count.
97
- */ export function crmDigestTaskState(dueAtMs, window) {
98
- if (dueAtMs < window.startMs) return 'overdue';
99
- if (dueAtMs < window.endMs) return 'today';
100
- return 'later';
101
- }
102
- /**
103
- * Whether a lead is one the digest should name: still `new` — which an
104
- * absent status reads as, because the capture door stamps none — and first
105
- * seen at least {@link CRM_DIGEST_LEAD_AGE_MS} ago.
106
- */ export function isUnworkedLead(lead, nowMs, ageMs = CRM_DIGEST_LEAD_AGE_MS) {
107
- if (crmLeadStatus(lead) !== 'new') return false;
108
- const firstSeen = Number(lead.firstSeenAtMs);
109
- return Number.isFinite(firstSeen) && firstSeen > 0 && firstSeen <= nowMs - ageMs;
110
- }
111
- /**
112
- * Whether a lead is THIS member's to work: theirs by owner, or nobody's on
113
- * a site they reach. An owned lead is one person's; an unowned one is on
114
- * everybody's list until somebody takes it, which is what the digest is for.
115
- */ export function leadIsForMember(lead, member) {
116
- if (lead.ownerUid) return lead.ownerUid === member.uid;
117
- return member.reachesHost(lead.hostId);
118
- }
119
- /**
120
- * Whether the org's plan carries the CRM (AGL-2611's `features.crm`).
121
- *
122
- * Read by key rather than through the typed flag map so this module does not
123
- * depend on the key existing: the flag lands with the CRM's gate, and a
124
- * plan that has not declared it is a plan that does not include it — a
125
- * digest about a surface the plan cannot open would be a reminder to pay.
126
- */ export function crmDigestEntitled(features) {
127
- return (features == null ? void 0 : features['crm']) === true;
128
- }
129
- /**
130
- * Every member's digest, from what the org's sweep read.
131
- *
132
- * A task goes to its assignee and to nobody else — an unassigned task is a
133
- * deliberate choice in the drawer, and an assignee no longer on the roster
134
- * is a task nobody owes. A lead goes to its owner, or to every member who
135
- * reaches the site when it has none. Members with nothing owed are simply
136
- * absent from the result, which is what makes "per member with open work"
137
- * cost nothing for everyone else.
138
- */ export function buildMemberDigests(input) {
139
- const { tasks, leads, members, window } = input;
140
- const digests = new Map();
141
- const digestFor = (uid)=>{
142
- let digest = digests.get(uid);
143
- if (!digest) {
144
- digest = {
145
- overdue: [],
146
- today: [],
147
- leads: []
148
- };
149
- digests.set(uid, digest);
150
- }
151
- return digest;
152
- };
153
- const roster = new Map(members.map((member)=>[
154
- member.uid,
155
- member
156
- ]));
157
- for (const task of tasks){
158
- if (!task.assigneeUid || !roster.has(task.assigneeUid)) continue;
159
- const state = crmDigestTaskState(task.dueAtMs, window);
160
- if (state === 'later') continue;
161
- digestFor(task.assigneeUid)[state].push(task);
162
- }
163
- for (const lead of leads){
164
- for (const member of members){
165
- if (leadIsForMember(lead, member)) digestFor(member.uid).leads.push(lead);
166
- }
167
- }
168
- for (const digest of digests.values()){
169
- digest.overdue.sort((a, b)=>a.dueAtMs - b.dueAtMs);
170
- digest.today.sort((a, b)=>a.dueAtMs - b.dueAtMs);
171
- digest.leads.sort((a, b)=>a.firstSeenAtMs - b.firstSeenAtMs);
172
- }
173
- return digests;
174
- }
175
- export function crmDigestCounts(digest) {
176
- return {
177
- overdue: digest.overdue.length,
178
- today: digest.today.length,
179
- leads: digest.leads.length
180
- };
181
- }
182
- const plural = (count, noun)=>`${count} ${noun}${count === 1 ? '' : 's'}`;
183
- /**
184
- * The one line the notification is: "3 tasks due today, 2 overdue, 4
185
- * unworked leads". Segments that are zero are left out rather than read as
186
- * "0 overdue" — the line is what is owed, and nothing owed is no segment.
187
- */ export function composeCrmDigestSummary(counts) {
188
- const segments = [];
189
- if (counts.today > 0) segments.push(`${plural(counts.today, 'task')} due today`);
190
- if (counts.overdue > 0) {
191
- segments.push(counts.today > 0 ? `${counts.overdue} overdue` : `${plural(counts.overdue, 'task')} overdue`);
192
- }
193
- if (counts.leads > 0) segments.push(`${plural(counts.leads, 'unworked lead')}`);
194
- return segments.join(', ');
195
- }
196
- export function composeCrmDigestSubject(counts) {
197
- return `Your CRM today: ${composeCrmDigestSummary(counts)}`;
198
- }
199
- function whenInZone(ms, timeZone) {
200
- return new Date(ms).toLocaleString('en-US', {
201
- timeZone,
202
- weekday: 'short',
203
- month: 'short',
204
- day: 'numeric',
205
- hour: 'numeric',
206
- minute: '2-digit'
207
- });
208
- }
209
- function dateInZone(ms, timeZone) {
210
- return new Date(ms).toLocaleDateString('en-US', {
211
- timeZone,
212
- month: 'short',
213
- day: 'numeric'
214
- });
215
- }
216
- function section(heading, lines) {
217
- const shown = lines.slice(0, CRM_DIGEST_LIST_MAX);
218
- const rest = lines.length - shown.length;
219
- return [
220
- `${heading} (${lines.length})`,
221
- ...shown.map((line)=>`- ${line}`),
222
- ...rest > 0 ? [
223
- ` and ${rest} more`
224
- ] : [],
225
- ''
226
- ];
227
- }
228
- /**
229
- * The plain-text email. Text rather than a designed template because the
230
- * body is a list, and `sendEmail` synthesizes the HTML part that makes its
231
- * links live. Overdue first — it is the section a reader acts on — then
232
- * today, then the leads, each capped and counted, and the links last.
233
- */ export function composeCrmDigestEmailText(input) {
234
- var _input_supportLine;
235
- const { digest, nowMs, timeZone, productName } = input;
236
- const counts = crmDigestCounts(digest);
237
- const day = new Date(nowMs).toLocaleDateString('en-US', {
238
- timeZone,
239
- weekday: 'long',
240
- month: 'long',
241
- day: 'numeric'
242
- });
243
- const lines = [
244
- `Here is your ${productName} CRM for ${day}: ${composeCrmDigestSummary(counts)}.`,
245
- ''
246
- ];
247
- const taskLine = (task)=>`${task.title} · ${whenInZone(task.dueAtMs, timeZone)}`;
248
- if (digest.overdue.length) {
249
- lines.push(...section('Overdue', digest.overdue.map(taskLine)));
250
- }
251
- if (digest.today.length) {
252
- lines.push(...section('Due today', digest.today.map(taskLine)));
253
- }
254
- if (digest.leads.length) {
255
- lines.push(...section('Unworked leads', digest.leads.map((lead)=>{
256
- const who = lead.name ? `${lead.name} <${lead.email}>` : lead.email;
257
- return `${who} · ${input.hostName(lead.hostId)} · first seen ${dateInZone(lead.firstSeenAtMs, timeZone)}`;
258
- })));
259
- }
260
- if (counts.overdue + counts.today > 0) lines.push(`Open your tasks: ${input.tasksUrl}`);
261
- const leadHosts = [
262
- ...new Set(digest.leads.map((lead)=>lead.hostId))
263
- ].slice(0, 3);
264
- for (const hostId of leadHosts){
265
- lines.push(`Leads on ${input.hostName(hostId)}: ${input.leadsUrl(hostId)}`);
266
- }
267
- if (input.omitClosing) return lines.join('\n').trimEnd();
268
- lines.push('', 'You get this each morning because the Daily CRM digest is on in your ' + `notification settings: ${input.settingsUrl}`);
269
- return lines.join('\n') + ((_input_supportLine = input.supportLine) != null ? _input_supportLine : '');
270
- }
271
-
272
- //# sourceMappingURL=crm-digest.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/crm-digest.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 * The daily CRM digest (AGL-2619): what one member is owed this morning,\n * computed from the tasks and leads a scheduled route has read.\n *\n * \"Overdue\" and \"due today\" are read off the clock at read time by design\n * (AGL-2599) — nothing stamps them — which is why nothing ever told anybody.\n * The digest is the one reader that runs on a schedule: once a day it\n * counts, per org and per member, the open tasks whose due date has passed\n * or falls today and the leads nobody has worked, and says so once, in the\n * console and by mail. Every judgment here is pure so the route that sends\n * and the spec that proves it read the same arithmetic.\n *\n * ## Whose day\n *\n * A task's \"today\" on screen is the READER's calendar day, from their own\n * clock. A server has no reader, so the digest reads the day in ONE zone —\n * {@link CRM_DIGEST_DEFAULT_TIME_ZONE}, the zone the schedule was chosen for\n * (08:00 there) — taken as a parameter so an org-level setting can supply\n * its own the day one exists. The idempotence key is the UTC day\n * ({@link utcDayKey}), which is a fact about the run and not about anybody's\n * morning.\n */\n\nimport {\n startOfNextZonedDay,\n startOfZonedDay,\n} from '@aglyn/shared-util-timestamp/zoned-time'\nimport { type CrmLeadFields, type CrmTask, crmLeadStatus } from './crm'\n\n/**\n * The zone the digest's \"today\" is read in when nothing else names one.\n *\n * The schedule fires at 13:00 UTC, which is 08:00 here, so the window this\n * zone draws is the morning the mail arrives in for the people the product\n * is built with. A member elsewhere reads a window that is at most a few\n * hours off their own, which is what a morning summary can tolerate and a\n * \"due at 9:00\" reminder could not — that reminder is the assignment\n * notification's job, not this one's.\n */\nexport const CRM_DIGEST_DEFAULT_TIME_ZONE = 'America/Chicago'\n\n/** How long a `new` lead may sit untouched before the digest names it. */\nexport const CRM_DIGEST_LEAD_AGE_MS = 2 * 24 * 60 * 60 * 1000\n\n/**\n * The most due tasks one org's sweep reads.\n *\n * One query per org, ordered soonest-due first, so an org with more than this\n * many overdue-or-today tasks digests the oldest five hundred and reports the\n * window as full rather than reading without bound. Five hundred is an org\n * whose problem is not that nobody reminded them.\n */\nexport const CRM_DIGEST_TASK_CEILING = 500\n\n/**\n * The most old leads one site's sweep reads.\n *\n * The same shape the Leads section uses, for the same reason it gives: a\n * lead the capture door wrote carries no `status` field, and Firestore\n * cannot select on a field's absence, so \"unworked\" is a filter over a\n * loaded window rather than a query. The window is the newest old leads by\n * first sighting, which is where the ones still worth a call are.\n */\nexport const CRM_DIGEST_LEAD_WINDOW = 200\n\n/** How many items one section of the email lists before \"and N more\". */\nexport const CRM_DIGEST_LIST_MAX = 10\n\n/*==========================================\n * CALENDAR DAYS IN A NAMED ZONE\n *\n * The zone math lives in `@aglyn/shared-util-timestamp/zoned-time`, where\n * booking slots and sending windows read it as well; the digest route and\n * its spec call it by the names below.\n *=========================================*/\n\n/** Midnight at the start of the calendar day `ms` falls in, in `timeZone`. */\nexport function startOfDayInZone(ms: number, timeZone: string): number {\n return startOfZonedDay(ms, timeZone)\n}\n\n/**\n * Midnight at the start of the NEXT calendar day in `timeZone` — built from\n * the calendar rather than by adding 24 hours, for the reason the tasks\n * section gives: a day a clock change falls in is 23 or 25 hours long.\n */\nexport function startOfNextDayInZone(ms: number, timeZone: string): number {\n return startOfNextZonedDay(ms, timeZone)\n}\n\n/** `YYYY-MM-DD` of the UTC day `ms` falls in — the digest's idempotence key. */\nexport function utcDayKey(ms: number): string {\n return new Date(ms).toISOString().slice(0, 10)\n}\n\n/** The half-open window `[start of today, start of tomorrow)` in a zone. */\nexport interface CrmDigestWindow {\n startMs: number\n endMs: number\n}\n\nexport function crmDigestWindow(nowMs: number, timeZone: string): CrmDigestWindow {\n return {\n startMs: startOfDayInZone(nowMs, timeZone),\n endMs: startOfNextDayInZone(nowMs, timeZone),\n }\n}\n\n/*==========================================\n * WHAT A DIGEST IS MADE OF\n *=========================================*/\n\n/** A due task as the digest carries it: the fields a line and a link need. */\nexport interface CrmDigestTask\n extends Pick<CrmTask, 'title' | 'kind' | 'contactId' | 'companyId' | 'dealId'> {\n id: string\n dueAtMs: number\n assigneeUid: string\n /** The site the task was created on — where its link opens. */\n hostId: string\n}\n\n/** An unworked lead as the digest carries it. */\nexport interface CrmDigestLead {\n id: string\n hostId: string\n email: string\n name?: string\n ownerUid?: string\n firstSeenAtMs: number\n}\n\nexport interface CrmDigestCounts {\n overdue: number\n today: number\n leads: number\n}\n\n/** One member's morning. */\nexport interface CrmMemberDigest {\n overdue: CrmDigestTask[]\n today: CrmDigestTask[]\n leads: CrmDigestLead[]\n}\n\n/**\n * Where a due task stands against the digest's window. Only tasks due\n * BEFORE the window's end are read at all, so `later` names a task the\n * query should not have returned and the bucketing refuses to count.\n */\nexport function crmDigestTaskState(\n dueAtMs: number,\n window: CrmDigestWindow,\n): 'overdue' | 'today' | 'later' {\n if (dueAtMs < window.startMs) return 'overdue'\n if (dueAtMs < window.endMs) return 'today'\n return 'later'\n}\n\n/**\n * Whether a lead is one the digest should name: still `new` — which an\n * absent status reads as, because the capture door stamps none — and first\n * seen at least {@link CRM_DIGEST_LEAD_AGE_MS} ago.\n */\nexport function isUnworkedLead(\n lead: Pick<CrmLeadFields, 'status'> & { firstSeenAtMs?: unknown },\n nowMs: number,\n ageMs: number = CRM_DIGEST_LEAD_AGE_MS,\n): boolean {\n if (crmLeadStatus(lead) !== 'new') return false\n const firstSeen = Number(lead.firstSeenAtMs)\n return Number.isFinite(firstSeen) && firstSeen > 0 && firstSeen <= nowMs - ageMs\n}\n\n/**\n * Whether a lead is THIS member's to work: theirs by owner, or nobody's on\n * a site they reach. An owned lead is one person's; an unowned one is on\n * everybody's list until somebody takes it, which is what the digest is for.\n */\nexport function leadIsForMember(\n lead: Pick<CrmDigestLead, 'ownerUid' | 'hostId'>,\n member: { uid: string; reachesHost: (hostId: string) => boolean },\n): boolean {\n if (lead.ownerUid) return lead.ownerUid === member.uid\n return member.reachesHost(lead.hostId)\n}\n\n/**\n * Whether the org's plan carries the CRM (AGL-2611's `features.crm`).\n *\n * Read by key rather than through the typed flag map so this module does not\n * depend on the key existing: the flag lands with the CRM's gate, and a\n * plan that has not declared it is a plan that does not include it — a\n * digest about a surface the plan cannot open would be a reminder to pay.\n */\nexport function crmDigestEntitled(\n features: Record<string, boolean | undefined> | null | undefined,\n): boolean {\n return features?.['crm'] === true\n}\n\n/**\n * Every member's digest, from what the org's sweep read.\n *\n * A task goes to its assignee and to nobody else — an unassigned task is a\n * deliberate choice in the drawer, and an assignee no longer on the roster\n * is a task nobody owes. A lead goes to its owner, or to every member who\n * reaches the site when it has none. Members with nothing owed are simply\n * absent from the result, which is what makes \"per member with open work\"\n * cost nothing for everyone else.\n */\nexport function buildMemberDigests(input: {\n tasks: readonly CrmDigestTask[]\n leads: readonly CrmDigestLead[]\n members: ReadonlyArray<{ uid: string; reachesHost: (hostId: string) => boolean }>\n window: CrmDigestWindow\n}): Map<string, CrmMemberDigest> {\n const { tasks, leads, members, window } = input\n const digests = new Map<string, CrmMemberDigest>()\n const digestFor = (uid: string): CrmMemberDigest => {\n let digest = digests.get(uid)\n if (!digest) {\n digest = { overdue: [], today: [], leads: [] }\n digests.set(uid, digest)\n }\n return digest\n }\n const roster = new Map(members.map((member) => [member.uid, member]))\n for (const task of tasks) {\n if (!task.assigneeUid || !roster.has(task.assigneeUid)) continue\n const state = crmDigestTaskState(task.dueAtMs, window)\n if (state === 'later') continue\n digestFor(task.assigneeUid)[state].push(task)\n }\n for (const lead of leads) {\n for (const member of members) {\n if (leadIsForMember(lead, member)) digestFor(member.uid).leads.push(lead)\n }\n }\n for (const digest of digests.values()) {\n digest.overdue.sort((a, b) => a.dueAtMs - b.dueAtMs)\n digest.today.sort((a, b) => a.dueAtMs - b.dueAtMs)\n digest.leads.sort((a, b) => a.firstSeenAtMs - b.firstSeenAtMs)\n }\n return digests\n}\n\nexport function crmDigestCounts(digest: CrmMemberDigest): CrmDigestCounts {\n return {\n overdue: digest.overdue.length,\n today: digest.today.length,\n leads: digest.leads.length,\n }\n}\n\nconst plural = (count: number, noun: string): string =>\n `${count} ${noun}${count === 1 ? '' : 's'}`\n\n/**\n * The one line the notification is: \"3 tasks due today, 2 overdue, 4\n * unworked leads\". Segments that are zero are left out rather than read as\n * \"0 overdue\" — the line is what is owed, and nothing owed is no segment.\n */\nexport function composeCrmDigestSummary(counts: CrmDigestCounts): string {\n const segments: string[] = []\n if (counts.today > 0) segments.push(`${plural(counts.today, 'task')} due today`)\n if (counts.overdue > 0) {\n segments.push(\n counts.today > 0 ? `${counts.overdue} overdue` : `${plural(counts.overdue, 'task')} overdue`,\n )\n }\n if (counts.leads > 0) segments.push(`${plural(counts.leads, 'unworked lead')}`)\n return segments.join(', ')\n}\n\nexport function composeCrmDigestSubject(counts: CrmDigestCounts): string {\n return `Your CRM today: ${composeCrmDigestSummary(counts)}`\n}\n\n/** What the digest email needs from the route besides the digest itself. */\nexport interface CrmDigestEmailInput {\n digest: CrmMemberDigest\n nowMs: number\n timeZone: string\n /** The product name the mail reads as — the org's brand when white-labeled. */\n productName: string\n /** The Tasks section, on the site the member's first task belongs to. */\n tasksUrl: string\n /** The Leads section of a site, for the sites that have unworked leads. */\n leadsUrl: (hostId: string) => string\n /** Account settings → Notifications, where the digest can be switched off. */\n settingsUrl: string\n /** A site's name for a lead line; the id when the site is unknown. */\n hostName: (hostId: string) => string\n /** The brand's support line, already prefixed, or empty. */\n supportLine?: string\n /**\n * Leave out the closing paragraph and the support line (AGL-3367), for the\n * copy that goes inside a system email: its footer says why the mail came\n * and where to get help, and its body links the settings page.\n */\n omitClosing?: boolean\n}\n\nfunction whenInZone(ms: number, timeZone: string): string {\n return new Date(ms).toLocaleString('en-US', {\n timeZone,\n weekday: 'short',\n month: 'short',\n day: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n })\n}\n\nfunction dateInZone(ms: number, timeZone: string): string {\n return new Date(ms).toLocaleDateString('en-US', {\n timeZone,\n month: 'short',\n day: 'numeric',\n })\n}\n\nfunction section(heading: string, lines: string[]): string[] {\n const shown = lines.slice(0, CRM_DIGEST_LIST_MAX)\n const rest = lines.length - shown.length\n return [\n `${heading} (${lines.length})`,\n ...shown.map((line) => `- ${line}`),\n ...(rest > 0 ? [` and ${rest} more`] : []),\n '',\n ]\n}\n\n/**\n * The plain-text email. Text rather than a designed template because the\n * body is a list, and `sendEmail` synthesizes the HTML part that makes its\n * links live. Overdue first — it is the section a reader acts on — then\n * today, then the leads, each capped and counted, and the links last.\n */\nexport function composeCrmDigestEmailText(input: CrmDigestEmailInput): string {\n const { digest, nowMs, timeZone, productName } = input\n const counts = crmDigestCounts(digest)\n const day = new Date(nowMs).toLocaleDateString('en-US', {\n timeZone,\n weekday: 'long',\n month: 'long',\n day: 'numeric',\n })\n const lines: string[] = [\n `Here is your ${productName} CRM for ${day}: ${composeCrmDigestSummary(counts)}.`,\n '',\n ]\n const taskLine = (task: CrmDigestTask) =>\n `${task.title} · ${whenInZone(task.dueAtMs, timeZone)}`\n if (digest.overdue.length) {\n lines.push(...section('Overdue', digest.overdue.map(taskLine)))\n }\n if (digest.today.length) {\n lines.push(...section('Due today', digest.today.map(taskLine)))\n }\n if (digest.leads.length) {\n lines.push(\n ...section(\n 'Unworked leads',\n digest.leads.map((lead) => {\n const who = lead.name ? `${lead.name} <${lead.email}>` : lead.email\n return `${who} · ${input.hostName(lead.hostId)} · first seen ${dateInZone(\n lead.firstSeenAtMs,\n timeZone,\n )}`\n }),\n ),\n )\n }\n if (counts.overdue + counts.today > 0) lines.push(`Open your tasks: ${input.tasksUrl}`)\n const leadHosts = [...new Set(digest.leads.map((lead) => lead.hostId))].slice(0, 3)\n for (const hostId of leadHosts) {\n lines.push(`Leads on ${input.hostName(hostId)}: ${input.leadsUrl(hostId)}`)\n }\n if (input.omitClosing) return lines.join('\\n').trimEnd()\n lines.push(\n '',\n 'You get this each morning because the Daily CRM digest is on in your ' +\n `notification settings: ${input.settingsUrl}`,\n )\n return lines.join('\\n') + (input.supportLine ?? '')\n}\n"],"names":["startOfNextZonedDay","startOfZonedDay","crmLeadStatus","CRM_DIGEST_DEFAULT_TIME_ZONE","CRM_DIGEST_LEAD_AGE_MS","CRM_DIGEST_TASK_CEILING","CRM_DIGEST_LEAD_WINDOW","CRM_DIGEST_LIST_MAX","startOfDayInZone","ms","timeZone","startOfNextDayInZone","utcDayKey","Date","toISOString","slice","crmDigestWindow","nowMs","startMs","endMs","crmDigestTaskState","dueAtMs","window","isUnworkedLead","lead","ageMs","firstSeen","Number","firstSeenAtMs","isFinite","leadIsForMember","member","ownerUid","uid","reachesHost","hostId","crmDigestEntitled","features","buildMemberDigests","input","tasks","leads","members","digests","Map","digestFor","digest","get","overdue","today","set","roster","map","task","assigneeUid","has","state","push","values","sort","a","b","crmDigestCounts","length","plural","count","noun","composeCrmDigestSummary","counts","segments","join","composeCrmDigestSubject","whenInZone","toLocaleString","weekday","month","day","hour","minute","dateInZone","toLocaleDateString","section","heading","lines","shown","rest","line","composeCrmDigestEmailText","productName","taskLine","title","who","name","email","hostName","tasksUrl","leadHosts","Set","leadsUrl","omitClosing","trimEnd","settingsUrl","supportLine"],"mappings":"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"}
@@ -1,50 +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
- import type { AglynNodeSchema, NodeId } from '../foundation';
18
- /**
19
- * Where a form's submissions are also written as dataset records, read off
20
- * the form as a page renders it.
21
- */
22
- export interface FormDatasetBinding {
23
- /** The dataset, by id, so renaming it never breaks the binding (AGL-556). */
24
- datasetId?: string;
25
- /** The legacy by-name binding, honored when no id is set (AGL-141). */
26
- datasetName?: string;
27
- /** Submitted field name → the dataset field id the value is stored under. */
28
- fieldMap: Record<string, string>;
29
- }
30
- /** The most fields a submission may carry, and so the most a map can name. */
31
- export declare const FORM_DATASET_BINDING_MAX_FIELDS = 20;
32
- /**
33
- * The dataset binding a `form` node declares, or null when it declares none.
34
- *
35
- * The map is built the way the browser builds the submission: every
36
- * `formField` under the form, in reading order, keyed by the name the field
37
- * submits under (`fieldName`, or `field` when it has none), and a later field
38
- * under the same name replaces an earlier one. A field with no
39
- * `datasetFieldId` maps nothing and its value falls back to matching dataset
40
- * fields by name.
41
- *
42
- * Read from the COMPOSED tree, so a form grafted from a layout, a reusable
43
- * component or a form entity is read exactly as the page renders it.
44
- */
45
- export declare function formDatasetBindingOf(nodes: Record<NodeId, AglynNodeSchema | undefined> | undefined | null, formNodeId: NodeId): FormDatasetBinding | null;
46
- /** Every `form` node in a composed tree that declares a dataset binding. */
47
- export declare function formDatasetBindingsOf(nodes: Record<NodeId, AglynNodeSchema | undefined> | undefined | null): Array<{
48
- nodeId: NodeId;
49
- binding: FormDatasetBinding;
50
- }>;
@@ -1,74 +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
- */ import { _ as _extends } from "@swc/helpers/_/_extends";
17
- import { collectFormFieldNodeIds, FORM_COMPONENT_ID } from "./forms.js";
18
- /** The most fields a submission may carry, and so the most a map can name. */ export const FORM_DATASET_BINDING_MAX_FIELDS = 20;
19
- const text = (value, max)=>typeof value === 'string' ? value.trim().slice(0, max) : '';
20
- /**
21
- * The dataset binding a `form` node declares, or null when it declares none.
22
- *
23
- * The map is built the way the browser builds the submission: every
24
- * `formField` under the form, in reading order, keyed by the name the field
25
- * submits under (`fieldName`, or `field` when it has none), and a later field
26
- * under the same name replaces an earlier one. A field with no
27
- * `datasetFieldId` maps nothing and its value falls back to matching dataset
28
- * fields by name.
29
- *
30
- * Read from the COMPOSED tree, so a form grafted from a layout, a reusable
31
- * component or a form entity is read exactly as the page renders it.
32
- */ export function formDatasetBindingOf(nodes, formNodeId) {
33
- var _node_props;
34
- const node = nodes == null ? void 0 : nodes[formNodeId];
35
- if ((node == null ? void 0 : node.componentId) !== FORM_COMPONENT_ID) return null;
36
- const props = (_node_props = node.props) != null ? _node_props : {};
37
- const datasetId = text(props['datasetId'], 128);
38
- const datasetName = text(props['datasetName'], 60);
39
- if (!datasetId && !datasetName) return null;
40
- const fieldMap = {};
41
- for (const fieldNodeId of collectFormFieldNodeIds(nodes, formNodeId)){
42
- var _ref;
43
- var _nodes_fieldNodeId;
44
- const fieldProps = (_ref = nodes == null ? void 0 : (_nodes_fieldNodeId = nodes[fieldNodeId]) == null ? void 0 : _nodes_fieldNodeId.props) != null ? _ref : {};
45
- const datasetFieldId = text(fieldProps['datasetFieldId'], 64);
46
- if (!datasetFieldId) continue;
47
- const submittedKey = text(fieldProps['fieldName'], 64) || 'field';
48
- if (!(submittedKey in fieldMap) && Object.keys(fieldMap).length >= FORM_DATASET_BINDING_MAX_FIELDS) {
49
- continue;
50
- }
51
- fieldMap[submittedKey] = datasetFieldId;
52
- }
53
- return _extends({}, datasetId ? {
54
- datasetId
55
- } : {}, datasetName ? {
56
- datasetName
57
- } : {}, {
58
- fieldMap
59
- });
60
- }
61
- /** Every `form` node in a composed tree that declares a dataset binding. */ export function formDatasetBindingsOf(nodes) {
62
- const found = [];
63
- for (const [nodeId, node] of Object.entries(nodes != null ? nodes : {})){
64
- if ((node == null ? void 0 : node.componentId) !== FORM_COMPONENT_ID) continue;
65
- const binding = formDatasetBindingOf(nodes, nodeId);
66
- if (binding) found.push({
67
- nodeId: nodeId,
68
- binding
69
- });
70
- }
71
- return found;
72
- }
73
-
74
- //# sourceMappingURL=form-dataset-binding.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/form-dataset-binding.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 { AglynNodeSchema, NodeId } from '../foundation'\nimport { collectFormFieldNodeIds, FORM_COMPONENT_ID } from './forms'\n\n/**\n * Where a form's submissions are also written as dataset records, read off\n * the form as a page renders it.\n */\nexport interface FormDatasetBinding {\n /** The dataset, by id, so renaming it never breaks the binding (AGL-556). */\n datasetId?: string\n /** The legacy by-name binding, honored when no id is set (AGL-141). */\n datasetName?: string\n /** Submitted field name → the dataset field id the value is stored under. */\n fieldMap: Record<string, string>\n}\n\n/** The most fields a submission may carry, and so the most a map can name. */\nexport const FORM_DATASET_BINDING_MAX_FIELDS = 20\n\nconst text = (value: unknown, max: number): string =>\n typeof value === 'string' ? value.trim().slice(0, max) : ''\n\n/**\n * The dataset binding a `form` node declares, or null when it declares none.\n *\n * The map is built the way the browser builds the submission: every\n * `formField` under the form, in reading order, keyed by the name the field\n * submits under (`fieldName`, or `field` when it has none), and a later field\n * under the same name replaces an earlier one. A field with no\n * `datasetFieldId` maps nothing and its value falls back to matching dataset\n * fields by name.\n *\n * Read from the COMPOSED tree, so a form grafted from a layout, a reusable\n * component or a form entity is read exactly as the page renders it.\n */\nexport function formDatasetBindingOf(\n nodes: Record<NodeId, AglynNodeSchema | undefined> | undefined | null,\n formNodeId: NodeId,\n): FormDatasetBinding | null {\n const node = nodes?.[formNodeId]\n if (node?.componentId !== FORM_COMPONENT_ID) return null\n const props = (node.props ?? {}) as Record<string, unknown>\n const datasetId = text(props['datasetId'], 128)\n const datasetName = text(props['datasetName'], 60)\n if (!datasetId && !datasetName) return null\n const fieldMap: Record<string, string> = {}\n for (const fieldNodeId of collectFormFieldNodeIds(nodes, formNodeId)) {\n const fieldProps = (nodes?.[fieldNodeId]?.props ?? {}) as Record<\n string,\n unknown\n >\n const datasetFieldId = text(fieldProps['datasetFieldId'], 64)\n if (!datasetFieldId) continue\n const submittedKey = text(fieldProps['fieldName'], 64) || 'field'\n if (\n !(submittedKey in fieldMap) &&\n Object.keys(fieldMap).length >= FORM_DATASET_BINDING_MAX_FIELDS\n ) {\n continue\n }\n fieldMap[submittedKey] = datasetFieldId\n }\n return {\n ...(datasetId ? { datasetId } : {}),\n ...(datasetName ? { datasetName } : {}),\n fieldMap,\n }\n}\n\n/** Every `form` node in a composed tree that declares a dataset binding. */\nexport function formDatasetBindingsOf(\n nodes: Record<NodeId, AglynNodeSchema | undefined> | undefined | null,\n): Array<{ nodeId: NodeId; binding: FormDatasetBinding }> {\n const found: Array<{ nodeId: NodeId; binding: FormDatasetBinding }> = []\n for (const [nodeId, node] of Object.entries(nodes ?? {})) {\n if (node?.componentId !== FORM_COMPONENT_ID) continue\n const binding = formDatasetBindingOf(nodes, nodeId as NodeId)\n if (binding) found.push({ nodeId: nodeId as NodeId, binding })\n }\n return found\n}\n"],"names":["collectFormFieldNodeIds","FORM_COMPONENT_ID","FORM_DATASET_BINDING_MAX_FIELDS","text","value","max","trim","slice","formDatasetBindingOf","nodes","formNodeId","node","componentId","props","datasetId","datasetName","fieldMap","fieldNodeId","fieldProps","datasetFieldId","submittedKey","Object","keys","length","formDatasetBindingsOf","found","nodeId","entries","binding","push"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC;AAGD,SAASA,uBAAuB,EAAEC,iBAAiB,QAAQ,aAAS;AAepE,4EAA4E,GAC5E,OAAO,MAAMC,kCAAkC,GAAE;AAEjD,MAAMC,OAAO,CAACC,OAAgBC,MAC5B,OAAOD,UAAU,WAAWA,MAAME,IAAI,GAAGC,KAAK,CAAC,GAAGF,OAAO;AAE3D;;;;;;;;;;;;CAYC,GACD,OAAO,SAASG,qBACdC,KAAqE,EACrEC,UAAkB;QAIHC;IAFf,MAAMA,OAAOF,yBAAAA,KAAO,CAACC,WAAW;IAChC,IAAIC,CAAAA,wBAAAA,KAAMC,WAAW,MAAKX,mBAAmB,OAAO;IACpD,MAAMY,SAASF,cAAAA,KAAKE,KAAK,YAAVF,cAAc,CAAC;IAC9B,MAAMG,YAAYX,KAAKU,KAAK,CAAC,YAAY,EAAE;IAC3C,MAAME,cAAcZ,KAAKU,KAAK,CAAC,cAAc,EAAE;IAC/C,IAAI,CAACC,aAAa,CAACC,aAAa,OAAO;IACvC,MAAMC,WAAmC,CAAC;IAC1C,KAAK,MAAMC,eAAejB,wBAAwBS,OAAOC,YAAa;;YAChDD;QAApB,MAAMS,qBAAcT,0BAAAA,qBAAAA,KAAO,CAACQ,YAAY,qBAApBR,mBAAsBI,KAAK,mBAAI,CAAC;QAIpD,MAAMM,iBAAiBhB,KAAKe,UAAU,CAAC,iBAAiB,EAAE;QAC1D,IAAI,CAACC,gBAAgB;QACrB,MAAMC,eAAejB,KAAKe,UAAU,CAAC,YAAY,EAAE,OAAO;QAC1D,IACE,CAAEE,CAAAA,gBAAgBJ,QAAO,KACzBK,OAAOC,IAAI,CAACN,UAAUO,MAAM,IAAIrB,iCAChC;YACA;QACF;QACAc,QAAQ,CAACI,aAAa,GAAGD;IAC3B;IACA,OAAO,aACDL,YAAY;QAAEA;IAAU,IAAI,CAAC,GAC7BC,cAAc;QAAEA;IAAY,IAAI,CAAC;QACrCC;;AAEJ;AAEA,0EAA0E,GAC1E,OAAO,SAASQ,sBACdf,KAAqE;IAErE,MAAMgB,QAAgE,EAAE;IACxE,KAAK,MAAM,CAACC,QAAQf,KAAK,IAAIU,OAAOM,OAAO,CAAClB,gBAAAA,QAAS,CAAC,GAAI;QACxD,IAAIE,CAAAA,wBAAAA,KAAMC,WAAW,MAAKX,mBAAmB;QAC7C,MAAM2B,UAAUpB,qBAAqBC,OAAOiB;QAC5C,IAAIE,SAASH,MAAMI,IAAI,CAAC;YAAEH,QAAQA;YAAkBE;QAAQ;IAC9D;IACA,OAAOH;AACT"}