@10x-media/form-builder 0.1.0-beta.2 → 0.1.0-beta.21

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 (619) hide show
  1. package/CHANGELOG.md +360 -0
  2. package/README.md +7 -5
  3. package/dist/actions/assertNoBlockCollision.js +18 -0
  4. package/dist/actions/assertNoBlockCollision.js.map +1 -0
  5. package/dist/actions/body/converters.d.ts +20 -0
  6. package/dist/actions/body/converters.js +57 -0
  7. package/dist/actions/body/converters.js.map +1 -0
  8. package/dist/actions/body/escapeHtml.d.ts +6 -0
  9. package/dist/actions/body/escapeHtml.js +14 -0
  10. package/dist/actions/body/escapeHtml.js.map +1 -0
  11. package/dist/actions/body/serializeBody.d.ts +55 -0
  12. package/dist/actions/body/serializeBody.js +78 -0
  13. package/dist/actions/body/serializeBody.js.map +1 -0
  14. package/dist/actions/body/serializeSlate.js +31 -0
  15. package/dist/actions/body/serializeSlate.js.map +1 -0
  16. package/dist/actions/body/textOfBody.d.ts +13 -0
  17. package/dist/actions/body/textOfBody.js +35 -0
  18. package/dist/actions/body/textOfBody.js.map +1 -0
  19. package/dist/actions/body/wildcards.d.ts +10 -0
  20. package/dist/actions/body/wildcards.js +33 -0
  21. package/dist/actions/body/wildcards.js.map +1 -0
  22. package/dist/actions/buildActionBlocks.js +12 -9
  23. package/dist/actions/buildActionBlocks.js.map +1 -1
  24. package/dist/actions/builtin/confirmation.js +47 -43
  25. package/dist/actions/builtin/confirmation.js.map +1 -1
  26. package/dist/actions/builtin/emailAction.d.ts +20 -0
  27. package/dist/actions/builtin/emailAction.js +120 -0
  28. package/dist/actions/builtin/emailAction.js.map +1 -0
  29. package/dist/actions/builtin/emailTeam.js +20 -38
  30. package/dist/actions/builtin/emailTeam.js.map +1 -1
  31. package/dist/actions/builtin/index.d.ts +16 -1
  32. package/dist/actions/builtin/index.js +21 -7
  33. package/dist/actions/builtin/index.js.map +1 -1
  34. package/dist/actions/builtin/signedWebhook.js +6 -2
  35. package/dist/actions/builtin/signedWebhook.js.map +1 -1
  36. package/dist/actions/defineAction.d.ts +17 -5
  37. package/dist/actions/defineAction.js.map +1 -1
  38. package/dist/actions/dispatch.js +51 -6
  39. package/dist/actions/dispatch.js.map +1 -1
  40. package/dist/actions/dispatchContext.js +13 -0
  41. package/dist/actions/dispatchContext.js.map +1 -0
  42. package/dist/actions/emailRecipients.d.ts +12 -0
  43. package/dist/actions/emailRecipients.js +146 -0
  44. package/dist/actions/emailRecipients.js.map +1 -0
  45. package/dist/actions/fromAddresses.d.ts +37 -0
  46. package/dist/actions/fromAddresses.js +131 -0
  47. package/dist/actions/fromAddresses.js.map +1 -0
  48. package/dist/actions/recipientSources.d.ts +34 -0
  49. package/dist/actions/recipientSources.js +11 -0
  50. package/dist/actions/recipientSources.js.map +1 -0
  51. package/dist/actions/registry.d.ts +2 -1
  52. package/dist/actions/registry.js +5 -7
  53. package/dist/actions/registry.js.map +1 -1
  54. package/dist/actions/runActions.js +10 -1
  55. package/dist/actions/runActions.js.map +1 -1
  56. package/dist/actions/task.js +47 -16
  57. package/dist/actions/task.js.map +1 -1
  58. package/dist/aggregation/aggregateResponses.d.ts +9 -0
  59. package/dist/aggregation/aggregateResponses.js +8 -14
  60. package/dist/aggregation/aggregateResponses.js.map +1 -1
  61. package/dist/aggregation/resolveResultsRequest.d.ts +41 -6
  62. package/dist/aggregation/resolveResultsRequest.js +97 -11
  63. package/dist/aggregation/resolveResultsRequest.js.map +1 -1
  64. package/dist/calc/computeCalcFields.d.ts +5 -3
  65. package/dist/calc/computeCalcFields.js +6 -4
  66. package/dist/calc/computeCalcFields.js.map +1 -1
  67. package/dist/calc/evaluate.d.ts +26 -3
  68. package/dist/calc/evaluate.js +34 -13
  69. package/dist/calc/evaluate.js.map +1 -1
  70. package/dist/calc/formatCalc.d.ts +11 -0
  71. package/dist/calc/formatCalc.js +35 -0
  72. package/dist/calc/formatCalc.js.map +1 -0
  73. package/dist/calc/formatCalcValue.d.ts +17 -0
  74. package/dist/calc/formatCalcValue.js +17 -0
  75. package/dist/calc/formatCalcValue.js.map +1 -0
  76. package/dist/calc/normalizeCalc.d.ts +17 -3
  77. package/dist/calc/normalizeCalc.js +42 -33
  78. package/dist/calc/normalizeCalc.js.map +1 -1
  79. package/dist/calc/registry.d.ts +43 -0
  80. package/dist/calc/registry.js +27 -0
  81. package/dist/calc/registry.js.map +1 -0
  82. package/dist/calc/resolveCalcContext.d.ts +36 -0
  83. package/dist/calc/resolveCalcContext.js +87 -0
  84. package/dist/calc/resolveCalcContext.js.map +1 -0
  85. package/dist/calc/types.d.ts +25 -4
  86. package/dist/calc/types.js +23 -0
  87. package/dist/calc/types.js.map +1 -0
  88. package/dist/client/ByteSizeField.d.ts +29 -0
  89. package/dist/client/ByteSizeField.js +58 -0
  90. package/dist/client/ByteSizeField.js.map +1 -0
  91. package/dist/client/CalcExpressionBuilder.d.ts +20 -0
  92. package/dist/client/CalcExpressionBuilder.js +890 -0
  93. package/dist/client/CalcExpressionBuilder.js.map +1 -0
  94. package/dist/client/ClosePollButton.d.ts +15 -0
  95. package/dist/client/ClosePollButton.js +80 -0
  96. package/dist/client/ClosePollButton.js.map +1 -0
  97. package/dist/client/CondensedArray.d.ts +15 -0
  98. package/dist/client/CondensedArray.js +97 -0
  99. package/dist/client/CondensedArray.js.map +1 -0
  100. package/dist/client/ConditionBuilder.js +2 -1
  101. package/dist/client/ConditionBuilder.js.map +1 -1
  102. package/dist/client/ConsentBlockLabel.d.ts +15 -0
  103. package/dist/client/ConsentBlockLabel.js +71 -0
  104. package/dist/client/ConsentBlockLabel.js.map +1 -0
  105. package/dist/client/ConsentSourceRowLabel.d.ts +9 -0
  106. package/dist/client/ConsentSourceRowLabel.js +21 -0
  107. package/dist/client/ConsentSourceRowLabel.js.map +1 -0
  108. package/dist/client/EndpointOptionsSelect.d.ts +55 -0
  109. package/dist/client/EndpointOptionsSelect.js +112 -0
  110. package/dist/client/EndpointOptionsSelect.js.map +1 -0
  111. package/dist/client/FieldBlockLabel.d.ts +18 -0
  112. package/dist/client/FieldBlockLabel.js +34 -0
  113. package/dist/client/FieldBlockLabel.js.map +1 -0
  114. package/dist/client/FieldNameSelect.d.ts +37 -0
  115. package/dist/client/FieldNameSelect.js +72 -0
  116. package/dist/client/FieldNameSelect.js.map +1 -0
  117. package/dist/client/FlowBuilder.d.ts +2 -2
  118. package/dist/client/FlowBuilder.js +137 -88
  119. package/dist/client/FlowBuilder.js.map +1 -1
  120. package/dist/client/FormConditionField.js +1 -4
  121. package/dist/client/FormConditionField.js.map +1 -1
  122. package/dist/client/RecipientsSelect.d.ts +37 -0
  123. package/dist/client/RecipientsSelect.js +197 -0
  124. package/dist/client/RecipientsSelect.js.map +1 -0
  125. package/dist/client/RuleDescription.d.ts +21 -0
  126. package/dist/client/RuleDescription.js +19 -0
  127. package/dist/client/RuleDescription.js.map +1 -0
  128. package/dist/client/admin.css +557 -0
  129. package/dist/client/endpointOptions.d.ts +11 -0
  130. package/dist/client/endpointOptions.js +38 -0
  131. package/dist/client/endpointOptions.js.map +1 -0
  132. package/dist/client/flowAuthoring.js +142 -0
  133. package/dist/client/flowAuthoring.js.map +1 -0
  134. package/dist/client/synthesizeClientField.js +21 -10
  135. package/dist/client/synthesizeClientField.js.map +1 -1
  136. package/dist/client/toStaticLabel.js +13 -0
  137. package/dist/client/toStaticLabel.js.map +1 -0
  138. package/dist/collections/buttonFields.d.ts +34 -0
  139. package/dist/collections/buttonFields.js +35 -0
  140. package/dist/collections/buttonFields.js.map +1 -0
  141. package/dist/collections/cells/FieldCountCell.d.ts +15 -0
  142. package/dist/collections/cells/FieldCountCell.js +18 -0
  143. package/dist/collections/cells/FieldCountCell.js.map +1 -0
  144. package/dist/collections/cells/FlowStepsCell.d.ts +14 -0
  145. package/dist/collections/cells/FlowStepsCell.js +17 -0
  146. package/dist/collections/cells/FlowStepsCell.js.map +1 -0
  147. package/dist/collections/formSubmissions.js +114 -28
  148. package/dist/collections/formSubmissions.js.map +1 -1
  149. package/dist/collections/forms.js +449 -112
  150. package/dist/collections/forms.js.map +1 -1
  151. package/dist/collections/formsEndpoints.js +106 -0
  152. package/dist/collections/formsEndpoints.js.map +1 -0
  153. package/dist/collections/redirectFields.d.ts +29 -0
  154. package/dist/collections/settingsFields.d.ts +31 -0
  155. package/dist/collections/settingsFields.js +45 -0
  156. package/dist/collections/settingsFields.js.map +1 -0
  157. package/dist/conditions/conditionType.js +9 -2
  158. package/dist/conditions/conditionType.js.map +1 -1
  159. package/dist/conditions/evaluate.js +1 -1
  160. package/dist/conditions/evaluate.js.map +1 -1
  161. package/dist/conditions/fieldTypes.d.ts +3 -1
  162. package/dist/conditions/fieldTypes.js +4 -1
  163. package/dist/conditions/fieldTypes.js.map +1 -1
  164. package/dist/conditions/normalizeConditions.js +20 -6
  165. package/dist/conditions/normalizeConditions.js.map +1 -1
  166. package/dist/consent/applyConsentStatements.d.ts +14 -0
  167. package/dist/consent/applyConsentStatements.js +17 -0
  168. package/dist/consent/applyConsentStatements.js.map +1 -0
  169. package/dist/consent/captureConsent.d.ts +39 -11
  170. package/dist/consent/captureConsent.js +63 -13
  171. package/dist/consent/captureConsent.js.map +1 -1
  172. package/dist/consent/consentSourcesField.d.ts +66 -0
  173. package/dist/consent/consentSourcesField.js +98 -0
  174. package/dist/consent/consentSourcesField.js.map +1 -0
  175. package/dist/consent/effectiveStatement.js +16 -0
  176. package/dist/consent/effectiveStatement.js.map +1 -0
  177. package/dist/consent/resolveConsentEntries.d.ts +24 -0
  178. package/dist/consent/resolveConsentEntries.js +40 -0
  179. package/dist/consent/resolveConsentEntries.js.map +1 -0
  180. package/dist/consent/resolveConsentSourcesRequest.d.ts +37 -0
  181. package/dist/consent/resolveConsentSourcesRequest.js +54 -0
  182. package/dist/consent/resolveConsentSourcesRequest.js.map +1 -0
  183. package/dist/consent/resolveConsentStatements.d.ts +45 -0
  184. package/dist/consent/resolveConsentStatements.js +46 -0
  185. package/dist/consent/resolveConsentStatements.js.map +1 -0
  186. package/dist/consent/resolvePublishedVersionRef.d.ts +17 -11
  187. package/dist/consent/resolvePublishedVersionRef.js +13 -10
  188. package/dist/consent/resolvePublishedVersionRef.js.map +1 -1
  189. package/dist/consent/types.d.ts +69 -0
  190. package/dist/context/formContext.d.ts +30 -0
  191. package/dist/context/formContext.js +54 -0
  192. package/dist/context/formContext.js.map +1 -0
  193. package/dist/email/departments.d.ts +59 -0
  194. package/dist/email/departments.js +87 -0
  195. package/dist/email/departments.js.map +1 -0
  196. package/dist/email/departmentsField.d.ts +53 -0
  197. package/dist/email/departmentsField.js +73 -0
  198. package/dist/email/departmentsField.js.map +1 -0
  199. package/dist/exports/client.d.ts +14 -1
  200. package/dist/exports/client.js +14 -1
  201. package/dist/exports/i18n.d.ts +5 -2
  202. package/dist/exports/i18n.js +5 -2
  203. package/dist/exports/react.d.ts +34 -10
  204. package/dist/exports/react.js +24 -4
  205. package/dist/exports/rsc.d.ts +10 -1
  206. package/dist/exports/rsc.js +10 -1
  207. package/dist/exports/types.d.ts +20 -12
  208. package/dist/fields/buildFieldBlocks.js +46 -25
  209. package/dist/fields/buildFieldBlocks.js.map +1 -1
  210. package/dist/fields/builtin/calculation.d.ts +17 -0
  211. package/dist/fields/builtin/calculation.js +193 -18
  212. package/dist/fields/builtin/calculation.js.map +1 -1
  213. package/dist/fields/builtin/checkbox.js +23 -0
  214. package/dist/fields/builtin/checkbox.js.map +1 -1
  215. package/dist/fields/builtin/consent.js +49 -14
  216. package/dist/fields/builtin/consent.js.map +1 -1
  217. package/dist/fields/builtin/country.d.ts +13 -0
  218. package/dist/fields/builtin/country.js +30 -0
  219. package/dist/fields/builtin/country.js.map +1 -0
  220. package/dist/fields/builtin/date.js +31 -0
  221. package/dist/fields/builtin/date.js.map +1 -0
  222. package/dist/fields/builtin/email.js +8 -1
  223. package/dist/fields/builtin/email.js.map +1 -1
  224. package/dist/fields/builtin/file.d.ts +15 -0
  225. package/dist/fields/builtin/file.js +95 -8
  226. package/dist/fields/builtin/file.js.map +1 -1
  227. package/dist/fields/builtin/index.d.ts +30 -0
  228. package/dist/fields/builtin/index.js +37 -10
  229. package/dist/fields/builtin/index.js.map +1 -1
  230. package/dist/fields/builtin/message.js +30 -0
  231. package/dist/fields/builtin/message.js.map +1 -0
  232. package/dist/fields/builtin/repeater.js +8 -3
  233. package/dist/fields/builtin/repeater.js.map +1 -1
  234. package/dist/fields/builtin/select.js +28 -4
  235. package/dist/fields/builtin/select.js.map +1 -1
  236. package/dist/fields/builtin/state.d.ts +13 -0
  237. package/dist/fields/builtin/state.js +30 -0
  238. package/dist/fields/builtin/state.js.map +1 -0
  239. package/dist/fields/builtin/text.js +7 -0
  240. package/dist/fields/builtin/text.js.map +1 -1
  241. package/dist/fields/data/regions.d.ts +21 -0
  242. package/dist/fields/data/regions.js +1238 -0
  243. package/dist/fields/data/regions.js.map +1 -0
  244. package/dist/fields/fieldKey.d.ts +15 -0
  245. package/dist/fields/fieldKey.js +16 -0
  246. package/dist/fields/fieldKey.js.map +1 -0
  247. package/dist/fields/fieldNamesOfType.js +30 -0
  248. package/dist/fields/fieldNamesOfType.js.map +1 -0
  249. package/dist/fields/instanceOptions.js +20 -0
  250. package/dist/fields/instanceOptions.js.map +1 -0
  251. package/dist/fields/localizedIf.d.ts +13 -0
  252. package/dist/fields/localizedIf.js +12 -0
  253. package/dist/fields/localizedIf.js.map +1 -0
  254. package/dist/fields/registry.d.ts +3 -1
  255. package/dist/fields/registry.js +23 -8
  256. package/dist/fields/registry.js.map +1 -1
  257. package/dist/fields/sharedConfig.js +125 -59
  258. package/dist/fields/sharedConfig.js.map +1 -1
  259. package/dist/fields/types.d.ts +78 -9
  260. package/dist/flow/engine.d.ts +6 -4
  261. package/dist/flow/engine.js +11 -6
  262. package/dist/flow/engine.js.map +1 -1
  263. package/dist/flow/normalizeFlow.js +28 -9
  264. package/dist/flow/normalizeFlow.js.map +1 -1
  265. package/dist/flow/stepLabel.js +15 -0
  266. package/dist/flow/stepLabel.js.map +1 -0
  267. package/dist/flow/types.d.ts +12 -3
  268. package/dist/flow/types.js +11 -0
  269. package/dist/flow/types.js.map +1 -0
  270. package/dist/form/pollState.d.ts +23 -0
  271. package/dist/form/pollState.js +17 -0
  272. package/dist/form/pollState.js.map +1 -0
  273. package/dist/form/toFormDocument.d.ts +110 -0
  274. package/dist/form/toFormDocument.js +89 -0
  275. package/dist/form/toFormDocument.js.map +1 -0
  276. package/dist/form/types.d.ts +73 -0
  277. package/dist/index.d.ts +67 -61
  278. package/dist/index.js +120 -25
  279. package/dist/index.js.map +1 -1
  280. package/dist/options.d.ts +281 -0
  281. package/dist/plugin/applyRegistryConfig.d.ts +11 -0
  282. package/dist/plugin/applyRegistryConfig.js +20 -0
  283. package/dist/plugin/applyRegistryConfig.js.map +1 -0
  284. package/dist/plugin/customState.js +26 -0
  285. package/dist/plugin/customState.js.map +1 -0
  286. package/dist/plugin/registerCollections.js +43 -40
  287. package/dist/plugin/registerCollections.js.map +1 -1
  288. package/dist/plugin/uploadsCollection.d.ts +16 -0
  289. package/dist/plugin/uploadsCollection.js +53 -0
  290. package/dist/plugin/uploadsCollection.js.map +1 -0
  291. package/dist/poll/applyPollOptions.js +18 -0
  292. package/dist/poll/applyPollOptions.js.map +1 -0
  293. package/dist/poll/buildPollOptionSourceFields.js +50 -0
  294. package/dist/poll/buildPollOptionSourceFields.js.map +1 -0
  295. package/dist/poll/closeJob.d.ts +53 -0
  296. package/dist/poll/closeJob.js +121 -0
  297. package/dist/poll/closeJob.js.map +1 -0
  298. package/dist/poll/definePollOptionSource.d.ts +44 -0
  299. package/dist/poll/definePollOptionSource.js +6 -0
  300. package/dist/poll/definePollOptionSource.js.map +1 -0
  301. package/dist/poll/definePollType.d.ts +34 -0
  302. package/dist/poll/definePollType.js +6 -0
  303. package/dist/poll/definePollType.js.map +1 -0
  304. package/dist/poll/effectivePollOptions.d.ts +38 -0
  305. package/dist/poll/effectivePollOptions.js +64 -0
  306. package/dist/poll/effectivePollOptions.js.map +1 -0
  307. package/dist/poll/mostVoted.d.ts +21 -0
  308. package/dist/poll/mostVoted.js +32 -0
  309. package/dist/poll/mostVoted.js.map +1 -0
  310. package/dist/poll/outcomeBeforeChange.js +91 -0
  311. package/dist/poll/outcomeBeforeChange.js.map +1 -0
  312. package/dist/poll/outcomeFields.d.ts +38 -0
  313. package/dist/poll/outcomeFields.js +52 -0
  314. package/dist/poll/outcomeFields.js.map +1 -0
  315. package/dist/poll/pollTypeRegistry.d.ts +34 -0
  316. package/dist/poll/pollTypeRegistry.js +69 -0
  317. package/dist/poll/pollTypeRegistry.js.map +1 -0
  318. package/dist/poll/registry.d.ts +17 -0
  319. package/dist/poll/registry.js +12 -0
  320. package/dist/poll/registry.js.map +1 -0
  321. package/dist/poll/resolvePollCloseRequest.js +106 -0
  322. package/dist/poll/resolvePollCloseRequest.js.map +1 -0
  323. package/dist/poll/resolvePollOptions.d.ts +29 -0
  324. package/dist/poll/resolvePollOptions.js +52 -0
  325. package/dist/poll/resolvePollOptions.js.map +1 -0
  326. package/dist/poll/resolvePollOptionsRequest.js +50 -0
  327. package/dist/poll/resolvePollOptionsRequest.js.map +1 -0
  328. package/dist/poll/resolvePollOutcome.d.ts +40 -0
  329. package/dist/poll/resolvePollOutcome.js +90 -0
  330. package/dist/poll/resolvePollOutcome.js.map +1 -0
  331. package/dist/poll/resultsField.js +21 -0
  332. package/dist/poll/resultsField.js.map +1 -0
  333. package/dist/poll/votes/aggregateFromVotes.d.ts +27 -0
  334. package/dist/poll/votes/aggregateFromVotes.js +54 -0
  335. package/dist/poll/votes/aggregateFromVotes.js.map +1 -0
  336. package/dist/poll/votes/answerValues.js +16 -0
  337. package/dist/poll/votes/answerValues.js.map +1 -0
  338. package/dist/poll/votes/bumpPollVote.js +88 -0
  339. package/dist/poll/votes/bumpPollVote.js.map +1 -0
  340. package/dist/poll/votes/recountPollVotes.d.ts +20 -0
  341. package/dist/poll/votes/recountPollVotes.js +63 -0
  342. package/dist/poll/votes/recountPollVotes.js.map +1 -0
  343. package/dist/poll/votes/voteTallyHook.js +76 -0
  344. package/dist/poll/votes/voteTallyHook.js.map +1 -0
  345. package/dist/poll/votes/votesCollection.d.ts +19 -0
  346. package/dist/poll/votes/votesCollection.js +89 -0
  347. package/dist/poll/votes/votesCollection.js.map +1 -0
  348. package/dist/prefill/valuesFromSearchParams.js +5 -9
  349. package/dist/prefill/valuesFromSearchParams.js.map +1 -1
  350. package/dist/presentations/types.d.ts +3 -2
  351. package/dist/react/Form.d.ts +77 -35
  352. package/dist/react/Form.js +368 -222
  353. package/dist/react/Form.js.map +1 -1
  354. package/dist/react/FormContext.d.ts +51 -1
  355. package/dist/react/FormContext.js.map +1 -1
  356. package/dist/react/FormControls.d.ts +55 -0
  357. package/dist/react/FormControls.js +56 -0
  358. package/dist/react/FormControls.js.map +1 -0
  359. package/dist/react/FormFields.d.ts +18 -0
  360. package/dist/react/FormFields.js +114 -0
  361. package/dist/react/FormFields.js.map +1 -0
  362. package/dist/react/FormLayout.d.ts +4 -2
  363. package/dist/react/FormLayout.js +3 -2
  364. package/dist/react/FormLayout.js.map +1 -1
  365. package/dist/react/FormResults.d.ts +8 -3
  366. package/dist/react/FormResults.js +50 -29
  367. package/dist/react/FormResults.js.map +1 -1
  368. package/dist/react/FormSteps.d.ts +17 -0
  369. package/dist/react/FormSteps.js +35 -0
  370. package/dist/react/FormSteps.js.map +1 -0
  371. package/dist/react/Poll.d.ts +40 -6
  372. package/dist/react/Poll.js +137 -33
  373. package/dist/react/Poll.js.map +1 -1
  374. package/dist/react/adapters.d.ts +35 -0
  375. package/dist/react/adapters.js +11 -0
  376. package/dist/react/adapters.js.map +1 -0
  377. package/dist/react/captcha/HcaptchaCaptcha.d.ts +31 -0
  378. package/dist/react/captcha/HcaptchaCaptcha.js +53 -0
  379. package/dist/react/captcha/HcaptchaCaptcha.js.map +1 -0
  380. package/dist/react/captcha/RecaptchaCaptcha.d.ts +44 -0
  381. package/dist/react/captcha/RecaptchaCaptcha.js +93 -0
  382. package/dist/react/captcha/RecaptchaCaptcha.js.map +1 -0
  383. package/dist/react/captcha/TurnstileCaptcha.d.ts +31 -0
  384. package/dist/react/captcha/TurnstileCaptcha.js +53 -0
  385. package/dist/react/captcha/TurnstileCaptcha.js.map +1 -0
  386. package/dist/react/captcha/types.d.ts +8 -0
  387. package/dist/react/captcha/useCaptchaScript.js +63 -0
  388. package/dist/react/captcha/useCaptchaScript.js.map +1 -0
  389. package/dist/react/captcha/vendors.js +8 -0
  390. package/dist/react/captcha/vendors.js.map +1 -0
  391. package/dist/react/contract.d.ts +2 -3
  392. package/dist/react/contract.js.map +1 -1
  393. package/dist/react/fetchResults.d.ts +1 -1
  394. package/dist/react/fetchResults.js +1 -1
  395. package/dist/react/fetchResults.js.map +1 -1
  396. package/dist/react/presentation/DialogSurface.js +1 -4
  397. package/dist/react/presentation/DialogSurface.js.map +1 -1
  398. package/dist/react/primitives/Checkbox.d.ts +6 -2
  399. package/dist/react/primitives/Checkbox.js +4 -2
  400. package/dist/react/primitives/Checkbox.js.map +1 -1
  401. package/dist/react/primitives/ChoiceGroup.d.ts +40 -0
  402. package/dist/react/primitives/ChoiceGroup.js +33 -0
  403. package/dist/react/primitives/ChoiceGroup.js.map +1 -0
  404. package/dist/react/primitives/FieldShell.d.ts +13 -5
  405. package/dist/react/primitives/FieldShell.js +35 -32
  406. package/dist/react/primitives/FieldShell.js.map +1 -1
  407. package/dist/react/primitives/Input.d.ts +4 -2
  408. package/dist/react/primitives/Input.js +2 -1
  409. package/dist/react/primitives/Input.js.map +1 -1
  410. package/dist/react/renderers/calculation.js +7 -5
  411. package/dist/react/renderers/calculation.js.map +1 -1
  412. package/dist/react/renderers/checkbox.js +3 -5
  413. package/dist/react/renderers/checkbox.js.map +1 -1
  414. package/dist/react/renderers/consent.js +84 -36
  415. package/dist/react/renderers/consent.js.map +1 -1
  416. package/dist/react/renderers/date.js +33 -0
  417. package/dist/react/renderers/date.js.map +1 -0
  418. package/dist/react/renderers/email.js +4 -5
  419. package/dist/react/renderers/email.js.map +1 -1
  420. package/dist/react/renderers/file.js +29 -14
  421. package/dist/react/renderers/file.js.map +1 -1
  422. package/dist/react/renderers/index.js +7 -0
  423. package/dist/react/renderers/index.js.map +1 -1
  424. package/dist/react/renderers/message.js +41 -0
  425. package/dist/react/renderers/message.js.map +1 -0
  426. package/dist/react/renderers/number.js +1 -4
  427. package/dist/react/renderers/number.js.map +1 -1
  428. package/dist/react/renderers/region.js +43 -0
  429. package/dist/react/renderers/region.js.map +1 -0
  430. package/dist/react/renderers/repeater.js +32 -14
  431. package/dist/react/renderers/repeater.js.map +1 -1
  432. package/dist/react/renderers/select.js +21 -6
  433. package/dist/react/renderers/select.js.map +1 -1
  434. package/dist/react/renderers/text.js +4 -5
  435. package/dist/react/renderers/text.js.map +1 -1
  436. package/dist/react/renderers/textarea.js +1 -4
  437. package/dist/react/renderers/textarea.js.map +1 -1
  438. package/dist/react/state.d.ts +46 -3
  439. package/dist/react/state.js +73 -10
  440. package/dist/react/state.js.map +1 -1
  441. package/dist/react/submitForm.js +1 -1
  442. package/dist/react/submitForm.js.map +1 -1
  443. package/dist/react/uploadFile.d.ts +2 -2
  444. package/dist/react/uploadFile.js +1 -1
  445. package/dist/react/uploadFile.js.map +1 -1
  446. package/dist/react/useCalcValues.d.ts +10 -0
  447. package/dist/react/useCalcValues.js +13 -0
  448. package/dist/react/useCalcValues.js.map +1 -0
  449. package/dist/react/useField.d.ts +0 -1
  450. package/dist/react/useField.js +7 -6
  451. package/dist/react/useField.js.map +1 -1
  452. package/dist/react/useFormState.d.ts +1 -1
  453. package/dist/react/useFormState.js +1 -1
  454. package/dist/react/useFormState.js.map +1 -1
  455. package/dist/react/validateField.js +3 -6
  456. package/dist/react/validateField.js.map +1 -1
  457. package/dist/recall/interpolate.d.ts +4 -3
  458. package/dist/recall/interpolate.js +5 -4
  459. package/dist/recall/interpolate.js.map +1 -1
  460. package/dist/recall/resolver.d.ts +1 -1
  461. package/dist/recall/resolver.js +15 -3
  462. package/dist/recall/resolver.js.map +1 -1
  463. package/dist/spam/captcha.d.ts +4 -3
  464. package/dist/spam/captcha.js +4 -3
  465. package/dist/spam/captcha.js.map +1 -1
  466. package/dist/spam/clientIp.js +9 -0
  467. package/dist/spam/clientIp.js.map +1 -0
  468. package/dist/spam/constants.js +13 -1
  469. package/dist/spam/constants.js.map +1 -1
  470. package/dist/spam/identify.js +3 -6
  471. package/dist/spam/identify.js.map +1 -1
  472. package/dist/spam/providers/hcaptcha.d.ts +17 -0
  473. package/dist/spam/providers/hcaptcha.js +18 -0
  474. package/dist/spam/providers/hcaptcha.js.map +1 -0
  475. package/dist/spam/providers/recaptcha.d.ts +23 -0
  476. package/dist/spam/providers/recaptcha.js +23 -0
  477. package/dist/spam/providers/recaptcha.js.map +1 -0
  478. package/dist/spam/providers/siteverify.js +34 -0
  479. package/dist/spam/providers/siteverify.js.map +1 -0
  480. package/dist/spam/providers/turnstile.d.ts +17 -0
  481. package/dist/spam/providers/turnstile.js +18 -0
  482. package/dist/spam/providers/turnstile.js.map +1 -0
  483. package/dist/spam/resolveSpam.js +2 -1
  484. package/dist/spam/resolveSpam.js.map +1 -1
  485. package/dist/spam/spamGuard.js +25 -11
  486. package/dist/spam/spamGuard.js.map +1 -1
  487. package/dist/spam/types.d.ts +19 -4
  488. package/dist/submissions/SubmissionAnswers.js +6 -2
  489. package/dist/submissions/SubmissionAnswers.js.map +1 -1
  490. package/dist/submissions/SubmissionAnswersClient.js +100 -64
  491. package/dist/submissions/SubmissionAnswersClient.js.map +1 -1
  492. package/dist/submissions/coerceBoolean.js +14 -0
  493. package/dist/submissions/coerceBoolean.js.map +1 -0
  494. package/dist/submissions/createSubmission.d.ts +36 -0
  495. package/dist/submissions/createSubmission.js +26 -0
  496. package/dist/submissions/createSubmission.js.map +1 -0
  497. package/dist/submissions/formIdOf.js +13 -0
  498. package/dist/submissions/formIdOf.js.map +1 -0
  499. package/dist/submissions/resolveVotedSubmission.d.ts +27 -0
  500. package/dist/submissions/resolveVotedSubmission.js +51 -0
  501. package/dist/submissions/resolveVotedSubmission.js.map +1 -0
  502. package/dist/submissions/runSubmission.d.ts +10 -0
  503. package/dist/submissions/runSubmission.js +104 -54
  504. package/dist/submissions/runSubmission.js.map +1 -1
  505. package/dist/submissions/types.d.ts +11 -4
  506. package/dist/submissions/validateSubmission.js +99 -13
  507. package/dist/submissions/validateSubmission.js.map +1 -1
  508. package/dist/submissions/verifyContext.js +35 -0
  509. package/dist/submissions/verifyContext.js.map +1 -0
  510. package/dist/submissions/voteChangeEndpoint.js +105 -0
  511. package/dist/submissions/voteChangeEndpoint.js.map +1 -0
  512. package/dist/submissions/votedCookie.d.ts +15 -0
  513. package/dist/submissions/votedCookie.js +74 -0
  514. package/dist/submissions/votedCookie.js.map +1 -0
  515. package/dist/translations/clientRuntimeKeys.d.ts +17 -0
  516. package/dist/translations/clientRuntimeKeys.js +48 -0
  517. package/dist/translations/clientRuntimeKeys.js.map +1 -0
  518. package/dist/translations/de.d.ts +12 -0
  519. package/dist/translations/de.js +380 -0
  520. package/dist/translations/de.js.map +1 -0
  521. package/dist/translations/en.js +250 -28
  522. package/dist/translations/en.js.map +1 -1
  523. package/dist/translations/index.d.ts +14 -5
  524. package/dist/translations/index.js +14 -3
  525. package/dist/translations/index.js.map +1 -1
  526. package/dist/translations/keys.d.ts +245 -23
  527. package/dist/translations/keys.js +246 -24
  528. package/dist/translations/keys.js.map +1 -1
  529. package/dist/translations/makeTranslate.d.ts +7 -3
  530. package/dist/translations/makeTranslate.js +12 -3
  531. package/dist/translations/makeTranslate.js.map +1 -1
  532. package/dist/translations/server.js +8 -1
  533. package/dist/translations/server.js.map +1 -1
  534. package/dist/uploads/captureFileRef.d.ts +10 -3
  535. package/dist/uploads/captureFileRef.js +18 -9
  536. package/dist/uploads/captureFileRef.js.map +1 -1
  537. package/dist/uploads/formatBytes.d.ts +9 -0
  538. package/dist/uploads/formatBytes.js +25 -0
  539. package/dist/uploads/formatBytes.js.map +1 -0
  540. package/dist/uploads/resolveFileRef.js +3 -2
  541. package/dist/uploads/resolveFileRef.js.map +1 -1
  542. package/dist/uploads/types.d.ts +1 -2
  543. package/dist/validation/buildRuleBlocks.js +18 -17
  544. package/dist/validation/buildRuleBlocks.js.map +1 -1
  545. package/dist/validation/builtin/email.js +2 -1
  546. package/dist/validation/builtin/email.js.map +1 -1
  547. package/dist/validation/builtin/index.d.ts +14 -0
  548. package/dist/validation/builtin/index.js +14 -1
  549. package/dist/validation/builtin/index.js.map +1 -1
  550. package/dist/validation/builtin/integer.js +15 -0
  551. package/dist/validation/builtin/integer.js.map +1 -0
  552. package/dist/validation/builtin/matchesField.js +3 -7
  553. package/dist/validation/builtin/matchesField.js.map +1 -1
  554. package/dist/validation/builtin/max.js +1 -0
  555. package/dist/validation/builtin/max.js.map +1 -1
  556. package/dist/validation/builtin/maxDate.js +24 -0
  557. package/dist/validation/builtin/maxDate.js.map +1 -0
  558. package/dist/validation/builtin/maxLength.js +1 -0
  559. package/dist/validation/builtin/maxLength.js.map +1 -1
  560. package/dist/validation/builtin/min.js +1 -0
  561. package/dist/validation/builtin/min.js.map +1 -1
  562. package/dist/validation/builtin/minDate.js +24 -0
  563. package/dist/validation/builtin/minDate.js.map +1 -0
  564. package/dist/validation/builtin/minLength.js +1 -0
  565. package/dist/validation/builtin/minLength.js.map +1 -1
  566. package/dist/validation/builtin/notAlreadySubmitted.js +5 -1
  567. package/dist/validation/builtin/notAlreadySubmitted.js.map +1 -1
  568. package/dist/validation/builtin/oneOf.js +1 -0
  569. package/dist/validation/builtin/oneOf.js.map +1 -1
  570. package/dist/validation/builtin/pattern.js +11 -2
  571. package/dist/validation/builtin/pattern.js.map +1 -1
  572. package/dist/validation/builtin/url.js +1 -0
  573. package/dist/validation/builtin/url.js.map +1 -1
  574. package/dist/validation/builtin/validateDateBound.js +18 -0
  575. package/dist/validation/builtin/validateDateBound.js.map +1 -0
  576. package/dist/validation/builtin/validateRegexParams.js +44 -0
  577. package/dist/validation/builtin/validateRegexParams.js.map +1 -0
  578. package/dist/validation/emailPattern.js +10 -0
  579. package/dist/validation/emailPattern.js.map +1 -0
  580. package/dist/validation/fieldTargetParam.d.ts +22 -0
  581. package/dist/validation/fieldTargetParam.js +38 -0
  582. package/dist/validation/fieldTargetParam.js.map +1 -0
  583. package/dist/validation/registry.d.ts +2 -1
  584. package/dist/validation/registry.js +2 -9
  585. package/dist/validation/registry.js.map +1 -1
  586. package/dist/validation/runValidation.js +8 -29
  587. package/dist/validation/runValidation.js.map +1 -1
  588. package/dist/validation/types.d.ts +5 -11
  589. package/dist/validation/validateUrl.js +22 -0
  590. package/dist/validation/validateUrl.js.map +1 -0
  591. package/package.json +14 -6
  592. package/styles/form-builder.css +94 -190
  593. package/dist/collections/uploads.d.ts +0 -30
  594. package/dist/collections/uploads.js +0 -55
  595. package/dist/collections/uploads.js.map +0 -1
  596. package/dist/consent/buildConsentSourceConfig.js +0 -49
  597. package/dist/consent/buildConsentSourceConfig.js.map +0 -1
  598. package/dist/consent/builtin/index.d.ts +0 -7
  599. package/dist/consent/builtin/index.js +0 -11
  600. package/dist/consent/builtin/index.js.map +0 -1
  601. package/dist/consent/builtin/pageReference.js +0 -75
  602. package/dist/consent/builtin/pageReference.js.map +0 -1
  603. package/dist/consent/builtin/static.js +0 -44
  604. package/dist/consent/builtin/static.js.map +0 -1
  605. package/dist/consent/defineConsentSource.d.ts +0 -35
  606. package/dist/consent/defineConsentSource.js +0 -6
  607. package/dist/consent/defineConsentSource.js.map +0 -1
  608. package/dist/consent/registry.d.ts +0 -16
  609. package/dist/consent/registry.js +0 -16
  610. package/dist/consent/registry.js.map +0 -1
  611. package/dist/consent/resolveConsentLinks.d.ts +0 -19
  612. package/dist/consent/resolveConsentLinks.js +0 -26
  613. package/dist/consent/resolveConsentLinks.js.map +0 -1
  614. package/dist/presentations/registry.d.ts +0 -15
  615. package/dist/presentations/registry.js +0 -15
  616. package/dist/presentations/registry.js.map +0 -1
  617. package/dist/react/toFormDocument.d.ts +0 -24
  618. package/dist/react/toFormDocument.js +0 -22
  619. package/dist/react/toFormDocument.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"normalizeConditions.js","names":[],"sources":["../../src/conditions/normalizeConditions.ts"],"sourcesContent":["import type { Where } from 'payload'\nimport { transformWhereQuery } from 'payload/shared'\nimport type { ConditionFieldType } from './fieldTypes'\nimport { conditionOperators } from './fieldTypes'\n\nexport type FieldRow = {\n\tblockType: string\n\tname?: string\n\tvisibleWhen?: unknown\n\tvalidateWhen?: unknown\n\t[key: string]: unknown\n}\n\nconst isValidConstraint = (\n\tconstraint: unknown,\n\toperandTypes: Map<string, ConditionFieldType>\n): boolean => {\n\tif (constraint == null || typeof constraint !== 'object') {\n\t\treturn false\n\t}\n\tconst field = Object.keys(constraint as object)[0]\n\tif (!field) {\n\t\treturn false\n\t}\n\tconst type = operandTypes.get(field)\n\tif (!type) {\n\t\treturn false\n\t}\n\tconst ops = (constraint as Record<string, unknown>)[field]\n\tif (ops == null || typeof ops !== 'object') {\n\t\treturn false\n\t}\n\tconst operator = Object.keys(ops as object)[0]\n\treturn Boolean(operator && (conditionOperators[type] as readonly string[]).includes(operator))\n}\n\nconst normalizeOne = (\n\traw: unknown,\n\toperandTypes: Map<string, ConditionFieldType>\n): Where | undefined => {\n\tif (raw == null || typeof raw !== 'object' || Object.keys(raw as object).length === 0) {\n\t\treturn undefined\n\t}\n\tconst canonical = transformWhereQuery(raw as Where)\n\tconst or = Array.isArray(canonical.or)\n\t\t? canonical.or\n\t\t: Array.isArray(canonical.and)\n\t\t\t? [{ and: canonical.and }]\n\t\t\t: []\n\tconst groups = or\n\t\t.map((group) => {\n\t\t\tconst and = Array.isArray((group as Where).and) ? ((group as Where).and as unknown[]) : []\n\t\t\treturn and.filter((constraint) => isValidConstraint(constraint, operandTypes))\n\t\t})\n\t\t.filter((group) => group.length > 0)\n\treturn groups.length > 0 ? ({ or: groups.map((and) => ({ and })) } as Where) : undefined\n}\n\n/**\n * Normalize every field's `visibleWhen`/`validateWhen` against the form's own field list. Canonicalizes\n * to OR-of-ANDs and strips constraints whose operand field is missing or whose operator is invalid for\n * that field's condition type, so stored conditions always match what `evaluateCondition` can run.\n */\nexport const normalizeFormConditions = (\n\tfields: FieldRow[],\n\tconditionTypes: Record<string, ConditionFieldType>\n): FieldRow[] => {\n\tconst operandTypes = new Map<string, ConditionFieldType>()\n\tfor (const row of fields) {\n\t\tconst name = typeof row.name === 'string' ? row.name.trim() : ''\n\t\tif (name.length > 0) {\n\t\t\toperandTypes.set(name, conditionTypes[row.blockType] ?? 'text')\n\t\t}\n\t}\n\treturn fields.map((row) => {\n\t\tconst visibleWhen = normalizeOne(row.visibleWhen, operandTypes)\n\t\tconst validateWhen = normalizeOne(row.validateWhen, operandTypes)\n\t\treturn { ...row, visibleWhen, validateWhen }\n\t})\n}\n"],"mappings":";;;AAaA,MAAM,qBACL,YACA,iBACa;CACb,IAAI,cAAc,QAAQ,OAAO,eAAe,UAC/C,OAAO;CAER,MAAM,QAAQ,OAAO,KAAK,UAAoB,EAAE;CAChD,IAAI,CAAC,OACJ,OAAO;CAER,MAAM,OAAO,aAAa,IAAI,KAAK;CACnC,IAAI,CAAC,MACJ,OAAO;CAER,MAAM,MAAO,WAAuC;CACpD,IAAI,OAAO,QAAQ,OAAO,QAAQ,UACjC,OAAO;CAER,MAAM,WAAW,OAAO,KAAK,GAAa,EAAE;CAC5C,OAAO,QAAQ,YAAa,mBAAmB,MAA4B,SAAS,QAAQ,CAAC;AAC9F;AAEA,MAAM,gBACL,KACA,iBACuB;CACvB,IAAI,OAAO,QAAQ,OAAO,QAAQ,YAAY,OAAO,KAAK,GAAa,EAAE,WAAW,GACnF;CAED,MAAM,YAAY,oBAAoB,GAAY;CAMlD,MAAM,UALK,MAAM,QAAQ,UAAU,EAAE,IAClC,UAAU,KACV,MAAM,QAAQ,UAAU,GAAG,IAC1B,CAAC,EAAE,KAAK,UAAU,IAAI,CAAC,IACvB,CAAC,GAEH,KAAK,UAAU;EAEf,QADY,MAAM,QAAS,MAAgB,GAAG,IAAM,MAAgB,MAAoB,CAAC,GAC9E,QAAQ,eAAe,kBAAkB,YAAY,YAAY,CAAC;CAC9E,CAAC,EACA,QAAQ,UAAU,MAAM,SAAS,CAAC;CACpC,OAAO,OAAO,SAAS,IAAK,EAAE,IAAI,OAAO,KAAK,SAAS,EAAE,IAAI,EAAE,EAAE,IAAc,KAAA;AAChF;;;;;;AAOA,MAAa,2BACZ,QACA,mBACgB;CAChB,MAAM,+BAAe,IAAI,IAAgC;CACzD,KAAK,MAAM,OAAO,QAAQ;EACzB,MAAM,OAAO,OAAO,IAAI,SAAS,WAAW,IAAI,KAAK,KAAK,IAAI;EAC9D,IAAI,KAAK,SAAS,GACjB,aAAa,IAAI,MAAM,eAAe,IAAI,cAAc,MAAM;CAEhE;CACA,OAAO,OAAO,KAAK,QAAQ;EAC1B,MAAM,cAAc,aAAa,IAAI,aAAa,YAAY;EAC9D,MAAM,eAAe,aAAa,IAAI,cAAc,YAAY;EAChE,OAAO;GAAE,GAAG;GAAK;GAAa;EAAa;CAC5C,CAAC;AACF"}
1
+ {"version":3,"file":"normalizeConditions.js","names":[],"sources":["../../src/conditions/normalizeConditions.ts"],"sourcesContent":["import type { Where } from 'payload'\nimport { transformWhereQuery } from 'payload/shared'\nimport type { ConditionFieldType } from './fieldTypes'\nimport { conditionOperators } from './fieldTypes'\n\nexport type FieldRow = {\n\tblockType: string\n\tname?: string\n\tvisibleWhen?: unknown\n\tvalidateWhen?: unknown\n\t[key: string]: unknown\n}\n\nconst isValidConstraint = (\n\tconstraint: unknown,\n\toperandTypes: Map<string, ConditionFieldType>\n): boolean => {\n\tif (constraint == null || typeof constraint !== 'object') {\n\t\treturn false\n\t}\n\tconst field = Object.keys(constraint as object)[0]\n\tif (!field) {\n\t\treturn false\n\t}\n\tconst type = operandTypes.get(field)\n\tif (!type) {\n\t\treturn false\n\t}\n\tconst ops = (constraint as Record<string, unknown>)[field]\n\tif (ops == null || typeof ops !== 'object') {\n\t\treturn false\n\t}\n\tconst operator = Object.keys(ops as object)[0]\n\treturn Boolean(operator && (conditionOperators[type] as readonly string[]).includes(operator))\n}\n\n/**\n * Canonicalize a `Where` to OR-of-ANDs and strip constraints whose operand field is unknown or whose\n * operator is invalid for that field's condition type. Returns undefined when nothing valid remains.\n */\nexport const normalizeWhere = (\n\traw: unknown,\n\toperandTypes: Map<string, ConditionFieldType>\n): Where | undefined => {\n\tif (raw == null || typeof raw !== 'object' || Object.keys(raw as object).length === 0) {\n\t\treturn undefined\n\t}\n\tconst canonical = transformWhereQuery(raw as Where)\n\tconst or = Array.isArray(canonical.or)\n\t\t? canonical.or\n\t\t: Array.isArray(canonical.and)\n\t\t\t? [{ and: canonical.and }]\n\t\t\t: []\n\tconst groups = or\n\t\t.map((group) => {\n\t\t\tconst and = Array.isArray((group as Where).and) ? ((group as Where).and as unknown[]) : []\n\t\t\treturn and.filter((constraint) => isValidConstraint(constraint, operandTypes))\n\t\t})\n\t\t.filter((group) => group.length > 0)\n\treturn groups.length > 0 ? ({ or: groups.map((and) => ({ and })) } as Where) : undefined\n}\n\n/**\n * Normalize every field's `visibleWhen`/`validateWhen` against the form's own field list. Canonicalizes\n * to OR-of-ANDs and strips constraints whose operand field is missing or whose operator is invalid for\n * that field's condition type, so stored conditions always match what `evaluateCondition` can run.\n */\n/**\n * The operand-name -> condition-type map for a form's fields. A field is a valid condition operand\n * only when it has a name and its block type has a condition type (display-only types are excluded),\n * so a constraint referencing anything else is stripped, matching the client operand list.\n */\nexport const buildOperandTypes = (\n\tfields: FieldRow[],\n\tconditionTypes: Record<string, ConditionFieldType>\n): Map<string, ConditionFieldType> => {\n\tconst operandTypes = new Map<string, ConditionFieldType>()\n\tfor (const row of fields) {\n\t\tconst name = typeof row.name === 'string' ? row.name.trim() : ''\n\t\tconst conditionType = conditionTypes[row.blockType]\n\t\tif (name.length > 0 && conditionType) {\n\t\t\toperandTypes.set(name, conditionType)\n\t\t}\n\t}\n\treturn operandTypes\n}\n\nexport const normalizeFormConditions = (\n\tfields: FieldRow[],\n\tconditionTypes: Record<string, ConditionFieldType>\n): FieldRow[] => {\n\tconst operandTypes = buildOperandTypes(fields, conditionTypes)\n\treturn fields.map((row) => {\n\t\tconst visibleWhen = normalizeWhere(row.visibleWhen, operandTypes)\n\t\tconst validateWhen = normalizeWhere(row.validateWhen, operandTypes)\n\t\treturn { ...row, visibleWhen, validateWhen }\n\t})\n}\n"],"mappings":";;;AAaA,MAAM,qBACL,YACA,iBACa;CACb,IAAI,cAAc,QAAQ,OAAO,eAAe,UAC/C,OAAO;CAER,MAAM,QAAQ,OAAO,KAAK,UAAoB,EAAE;CAChD,IAAI,CAAC,OACJ,OAAO;CAER,MAAM,OAAO,aAAa,IAAI,KAAK;CACnC,IAAI,CAAC,MACJ,OAAO;CAER,MAAM,MAAO,WAAuC;CACpD,IAAI,OAAO,QAAQ,OAAO,QAAQ,UACjC,OAAO;CAER,MAAM,WAAW,OAAO,KAAK,GAAa,EAAE;CAC5C,OAAO,QAAQ,YAAa,mBAAmB,MAA4B,SAAS,QAAQ,CAAC;AAC9F;;;;;AAMA,MAAa,kBACZ,KACA,iBACuB;CACvB,IAAI,OAAO,QAAQ,OAAO,QAAQ,YAAY,OAAO,KAAK,GAAa,EAAE,WAAW,GACnF;CAED,MAAM,YAAY,oBAAoB,GAAY;CAMlD,MAAM,UALK,MAAM,QAAQ,UAAU,EAAE,IAClC,UAAU,KACV,MAAM,QAAQ,UAAU,GAAG,IAC1B,CAAC,EAAE,KAAK,UAAU,IAAI,CAAC,IACvB,CAAC,GAEH,KAAK,UAAU;EAEf,QADY,MAAM,QAAS,MAAgB,GAAG,IAAM,MAAgB,MAAoB,CAAC,GAC9E,QAAQ,eAAe,kBAAkB,YAAY,YAAY,CAAC;CAC9E,CAAC,EACA,QAAQ,UAAU,MAAM,SAAS,CAAC;CACpC,OAAO,OAAO,SAAS,IAAK,EAAE,IAAI,OAAO,KAAK,SAAS,EAAE,IAAI,EAAE,EAAE,IAAc,KAAA;AAChF;;;;;;;;;;;AAYA,MAAa,qBACZ,QACA,mBACqC;CACrC,MAAM,+BAAe,IAAI,IAAgC;CACzD,KAAK,MAAM,OAAO,QAAQ;EACzB,MAAM,OAAO,OAAO,IAAI,SAAS,WAAW,IAAI,KAAK,KAAK,IAAI;EAC9D,MAAM,gBAAgB,eAAe,IAAI;EACzC,IAAI,KAAK,SAAS,KAAK,eACtB,aAAa,IAAI,MAAM,aAAa;CAEtC;CACA,OAAO;AACR;AAEA,MAAa,2BACZ,QACA,mBACgB;CAChB,MAAM,eAAe,kBAAkB,QAAQ,cAAc;CAC7D,OAAO,OAAO,KAAK,QAAQ;EAC1B,MAAM,cAAc,eAAe,IAAI,aAAa,YAAY;EAChE,MAAM,eAAe,eAAe,IAAI,cAAc,YAAY;EAClE,OAAO;GAAE,GAAG;GAAK;GAAa;EAAa;CAC5C,CAAC;AACF"}
@@ -0,0 +1,14 @@
1
+ import { ConsentStatements } from "./resolveConsentStatements.js";
2
+
3
+ //#region src/consent/applyConsentStatements.d.ts
4
+ /**
5
+ * Merge server-resolved statements onto the consent field instances they belong to, keyed by field
6
+ * name, without mutating the input. A field with no resolved statement (no source picked, or a key
7
+ * the host's sources no longer carry) is left untouched and renders without one.
8
+ */
9
+ declare const applyConsentStatements: <T extends {
10
+ name?: string;
11
+ }>(fields: T[], statements: ConsentStatements) => T[];
12
+ //#endregion
13
+ export { applyConsentStatements };
14
+ //# sourceMappingURL=applyConsentStatements.d.ts.map
@@ -0,0 +1,17 @@
1
+ //#region src/consent/applyConsentStatements.ts
2
+ /**
3
+ * Merge server-resolved statements onto the consent field instances they belong to, keyed by field
4
+ * name, without mutating the input. A field with no resolved statement (no source picked, or a key
5
+ * the host's sources no longer carry) is left untouched and renders without one.
6
+ */
7
+ const applyConsentStatements = (fields, statements) => fields.map((instance) => {
8
+ const resolved = instance.name ? statements[instance.name] : void 0;
9
+ return resolved ? {
10
+ ...instance,
11
+ ...resolved
12
+ } : instance;
13
+ });
14
+ //#endregion
15
+ export { applyConsentStatements };
16
+
17
+ //# sourceMappingURL=applyConsentStatements.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"applyConsentStatements.js","names":[],"sources":["../../src/consent/applyConsentStatements.ts"],"sourcesContent":["import type { ConsentStatements } from './resolveConsentStatements'\n\n/**\n * Merge server-resolved statements onto the consent field instances they belong to, keyed by field\n * name, without mutating the input. A field with no resolved statement (no source picked, or a key\n * the host's sources no longer carry) is left untouched and renders without one.\n */\nexport const applyConsentStatements = <T extends { name?: string }>(\n\tfields: T[],\n\tstatements: ConsentStatements\n): T[] =>\n\tfields.map((instance) => {\n\t\tconst resolved = instance.name ? statements[instance.name] : undefined\n\t\treturn resolved ? { ...instance, ...resolved } : instance\n\t})\n"],"mappings":";;;;;;AAOA,MAAa,0BACZ,QACA,eAEA,OAAO,KAAK,aAAa;CACxB,MAAM,WAAW,SAAS,OAAO,WAAW,SAAS,QAAQ,KAAA;CAC7D,OAAO,WAAW;EAAE,GAAG;EAAU,GAAG;CAAS,IAAI;AAClD,CAAC"}
@@ -1,28 +1,56 @@
1
1
  import { FormFieldInstance } from "../submissions/types.js";
2
- import { ConsentSourceRegistry } from "./registry.js";
2
+ import { ConsentSourceEntry, ConsentSourcePage } from "./types.js";
3
3
  import { Payload, PayloadRequest } from "payload";
4
4
 
5
5
  //#region src/consent/captureConsent.d.ts
6
+ /** What a submission snapshots of the agreed wording. `'hash'` and `'text'` combine as `'both'`. */
7
+ type ConsentSnapshotMode = 'hash' | 'text' | 'both' | false;
6
8
  type ConsentProof = {
7
- agreed: boolean;
8
- ref?: string;
9
- versionRef?: string;
9
+ agreed: boolean; /** The source `id` the field referenced; empty when the author never picked one. */
10
+ source: string;
11
+ page?: ConsentSourcePage;
12
+ versionRef?: string; /** The source label at submit time, so an audit names the statement even after a rename or delete. */
13
+ name?: string; /** sha256 of the statement plain text agreed to: tamper-evident and PII-free. */
14
+ statementHash?: string; /** Plain-text snapshot of the statement agreed to, for a human-readable audit. */
15
+ statementText?: string; /** Present only for a notice display, where submitting was the act of consent; absent means a ticked checkbox. */
16
+ display?: 'notice';
10
17
  at: string;
11
18
  };
12
19
  /**
13
- * Build the authoritative consent proof at submit time: re-resolve the source server-side
14
- * (ignores any client ref), capturing a reference url -- never the policy text.
20
+ * The authoritative consent proof, built at submit time from the server's own view of the source
21
+ * (the field carries an id, never a statement, so there is nothing here the client could forge).
22
+ *
23
+ * Proof is id-based on purpose: it records which document was agreed to, so renaming, re-slugging,
24
+ * or re-routing the policy leaves every past proof intact and resolvable. `snapshot` additionally
25
+ * captures the agreed wording (a `statementHash`, the plain `statementText`, or both) plus the source
26
+ * `name`, so an audit shows exactly what was agreed to independent of later edits; `false` keeps the
27
+ * lean id-only proof. The snapshot is captured in every branch, including a refusal and a page-less
28
+ * source.
29
+ *
30
+ * Time-of-check/time-of-use: a visitor reads the wording resolved when the form loaded, but the
31
+ * snapshot here is re-resolved from the source at submit. If the source text changed in that window,
32
+ * the proof records the submit-time wording, not the exact bytes rendered earlier. This is
33
+ * deliberate, the server's live view is authoritative and the window is one visitor session; a form
34
+ * that must freeze the exact wording agreed to should version the source (drafts give a `versionRef`
35
+ * pinning the published version, below).
36
+ *
37
+ * `versionRef` is recorded only when the page's collection has drafts enabled, and then it is the
38
+ * published version document's own id. Versions without drafts get no `versionRef`, because there
39
+ * is no published/draft distinction to pin to: `_status` only exists under drafts, so a
40
+ * published-version lookup there matches nothing, and recording that as a version reference would
41
+ * be inventing one. Absent means absent, in both cases.
42
+ *
15
43
  * `now` is injected by the caller (`new Date().toISOString()`) for testability.
16
44
  */
17
45
  declare const captureConsent: (args: {
18
46
  field: FormFieldInstance;
19
- agreed: boolean;
20
- registry: ConsentSourceRegistry;
47
+ agreed: boolean; /** The host's resolved sources for this request (see `resolveConsentEntries`). */
48
+ entries: ConsentSourceEntry[];
21
49
  payload: Payload;
22
50
  req?: PayloadRequest;
23
- locale: string;
24
- now: string;
51
+ now: string; /** What to snapshot of the agreed wording (plugin option `consent.snapshot`); defaults to `'both'`. */
52
+ snapshot?: ConsentSnapshotMode;
25
53
  }) => Promise<ConsentProof>;
26
54
  //#endregion
27
- export { ConsentProof, captureConsent };
55
+ export { ConsentProof, ConsentSnapshotMode, captureConsent };
28
56
  //# sourceMappingURL=captureConsent.d.ts.map
@@ -1,24 +1,74 @@
1
- import { resolveConsentLinks } from "./resolveConsentLinks.js";
1
+ import { textOfBody } from "../actions/body/textOfBody.js";
2
+ import { consentDisplayOf, effectiveConsentStatement } from "./effectiveStatement.js";
3
+ import { resolvePublishedVersionRef } from "./resolvePublishedVersionRef.js";
4
+ import { createHash } from "node:crypto";
5
+ import { hasDraftsEnabled } from "payload/shared";
2
6
  //#region src/consent/captureConsent.ts
3
7
  /**
4
- * Build the authoritative consent proof at submit time: re-resolve the source server-side
5
- * (ignores any client ref), capturing a reference url -- never the policy text.
8
+ * The authoritative consent proof, built at submit time from the server's own view of the source
9
+ * (the field carries an id, never a statement, so there is nothing here the client could forge).
10
+ *
11
+ * Proof is id-based on purpose: it records which document was agreed to, so renaming, re-slugging,
12
+ * or re-routing the policy leaves every past proof intact and resolvable. `snapshot` additionally
13
+ * captures the agreed wording (a `statementHash`, the plain `statementText`, or both) plus the source
14
+ * `name`, so an audit shows exactly what was agreed to independent of later edits; `false` keeps the
15
+ * lean id-only proof. The snapshot is captured in every branch, including a refusal and a page-less
16
+ * source.
17
+ *
18
+ * Time-of-check/time-of-use: a visitor reads the wording resolved when the form loaded, but the
19
+ * snapshot here is re-resolved from the source at submit. If the source text changed in that window,
20
+ * the proof records the submit-time wording, not the exact bytes rendered earlier. This is
21
+ * deliberate, the server's live view is authoritative and the window is one visitor session; a form
22
+ * that must freeze the exact wording agreed to should version the source (drafts give a `versionRef`
23
+ * pinning the published version, below).
24
+ *
25
+ * `versionRef` is recorded only when the page's collection has drafts enabled, and then it is the
26
+ * published version document's own id. Versions without drafts get no `versionRef`, because there
27
+ * is no published/draft distinction to pin to: `_status` only exists under drafts, so a
28
+ * published-version lookup there matches nothing, and recording that as a version reference would
29
+ * be inventing one. Absent means absent, in both cases.
30
+ *
6
31
  * `now` is injected by the caller (`new Date().toISOString()`) for testability.
7
32
  */
8
33
  const captureConsent = async (args) => {
9
- const resolved = await resolveConsentLinks(args.field, {
10
- registry: args.registry,
11
- payload: args.payload,
12
- req: args.req,
13
- locale: args.locale
34
+ const source = typeof args.field.source === "string" ? args.field.source : "";
35
+ const entry = source ? args.entries.find((candidate) => candidate.id === source) : void 0;
36
+ const snapshot = args.snapshot ?? "both";
37
+ const display = consentDisplayOf(args.field);
38
+ const withSnapshot = (proof) => {
39
+ if (display === "notice") proof.display = "notice";
40
+ if (!entry || snapshot === false) return proof;
41
+ if (typeof entry.name === "string" && entry.name.trim().length > 0) proof.name = entry.name.trim();
42
+ const text = textOfBody(effectiveConsentStatement(entry, display));
43
+ if (text.length > 0) {
44
+ if (snapshot === "hash" || snapshot === "both") proof.statementHash = createHash("sha256").update(text).digest("hex");
45
+ if (snapshot === "text" || snapshot === "both") proof.statementText = text;
46
+ }
47
+ return proof;
48
+ };
49
+ const page = entry?.page;
50
+ if (!page) return withSnapshot({
51
+ agreed: args.agreed,
52
+ source,
53
+ at: args.now
14
54
  });
15
- const ref = resolved.links[0]?.url || void 0;
16
- return {
55
+ const collection = args.payload.collections[page.relationTo];
56
+ const versionRef = collection && hasDraftsEnabled(collection.config) ? await resolvePublishedVersionRef({
57
+ payload: args.payload,
58
+ collection: page.relationTo,
59
+ id: page.id,
60
+ req: args.req
61
+ }) : null;
62
+ return withSnapshot({
17
63
  agreed: args.agreed,
18
- ...ref ? { ref } : {},
19
- ...resolved.versionRef ? { versionRef: resolved.versionRef } : {},
64
+ source,
65
+ page: {
66
+ relationTo: page.relationTo,
67
+ id: page.id
68
+ },
69
+ ...versionRef ? { versionRef } : {},
20
70
  at: args.now
21
- };
71
+ });
22
72
  };
23
73
  //#endregion
24
74
  export { captureConsent };
@@ -1 +1 @@
1
- {"version":3,"file":"captureConsent.js","names":[],"sources":["../../src/consent/captureConsent.ts"],"sourcesContent":["import type { Payload, PayloadRequest } from 'payload'\nimport type { FormFieldInstance } from '../submissions/types'\nimport type { ConsentSourceRegistry } from './registry'\nimport { resolveConsentLinks } from './resolveConsentLinks'\n\nexport type ConsentProof = {\n\tagreed: boolean\n\tref?: string\n\tversionRef?: string\n\tat: string\n}\n\n/**\n * Build the authoritative consent proof at submit time: re-resolve the source server-side\n * (ignores any client ref), capturing a reference url -- never the policy text.\n * `now` is injected by the caller (`new Date().toISOString()`) for testability.\n */\nexport const captureConsent = async (args: {\n\tfield: FormFieldInstance\n\tagreed: boolean\n\tregistry: ConsentSourceRegistry\n\tpayload: Payload\n\treq?: PayloadRequest\n\tlocale: string\n\tnow: string\n}): Promise<ConsentProof> => {\n\tconst resolved = await resolveConsentLinks(args.field, {\n\t\tregistry: args.registry,\n\t\tpayload: args.payload,\n\t\treq: args.req,\n\t\tlocale: args.locale,\n\t})\n\tconst ref = resolved.links[0]?.url || undefined\n\treturn {\n\t\tagreed: args.agreed,\n\t\t...(ref ? { ref } : {}),\n\t\t...(resolved.versionRef ? { versionRef: resolved.versionRef } : {}),\n\t\tat: args.now,\n\t}\n}\n"],"mappings":";;;;;;;AAiBA,MAAa,iBAAiB,OAAO,SAQR;CAC5B,MAAM,WAAW,MAAM,oBAAoB,KAAK,OAAO;EACtD,UAAU,KAAK;EACf,SAAS,KAAK;EACd,KAAK,KAAK;EACV,QAAQ,KAAK;CACd,CAAC;CACD,MAAM,MAAM,SAAS,MAAM,IAAI,OAAO,KAAA;CACtC,OAAO;EACN,QAAQ,KAAK;EACb,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC;EACrB,GAAI,SAAS,aAAa,EAAE,YAAY,SAAS,WAAW,IAAI,CAAC;EACjE,IAAI,KAAK;CACV;AACD"}
1
+ {"version":3,"file":"captureConsent.js","names":[],"sources":["../../src/consent/captureConsent.ts"],"sourcesContent":["import { createHash } from 'node:crypto'\nimport type { Payload, PayloadRequest } from 'payload'\nimport { hasDraftsEnabled } from 'payload/shared'\nimport { textOfBody } from '../actions/body/textOfBody'\nimport type { FormFieldInstance } from '../submissions/types'\nimport { consentDisplayOf, effectiveConsentStatement } from './effectiveStatement'\nimport { resolvePublishedVersionRef } from './resolvePublishedVersionRef'\nimport type { ConsentSourceEntry, ConsentSourcePage } from './types'\n\n/** What a submission snapshots of the agreed wording. `'hash'` and `'text'` combine as `'both'`. */\nexport type ConsentSnapshotMode = 'hash' | 'text' | 'both' | false\n\nexport type ConsentProof = {\n\tagreed: boolean\n\t/** The source `id` the field referenced; empty when the author never picked one. */\n\tsource: string\n\tpage?: ConsentSourcePage\n\tversionRef?: string\n\t/** The source label at submit time, so an audit names the statement even after a rename or delete. */\n\tname?: string\n\t/** sha256 of the statement plain text agreed to: tamper-evident and PII-free. */\n\tstatementHash?: string\n\t/** Plain-text snapshot of the statement agreed to, for a human-readable audit. */\n\tstatementText?: string\n\t/** Present only for a notice display, where submitting was the act of consent; absent means a ticked checkbox. */\n\tdisplay?: 'notice'\n\tat: string\n}\n\n/**\n * The authoritative consent proof, built at submit time from the server's own view of the source\n * (the field carries an id, never a statement, so there is nothing here the client could forge).\n *\n * Proof is id-based on purpose: it records which document was agreed to, so renaming, re-slugging,\n * or re-routing the policy leaves every past proof intact and resolvable. `snapshot` additionally\n * captures the agreed wording (a `statementHash`, the plain `statementText`, or both) plus the source\n * `name`, so an audit shows exactly what was agreed to independent of later edits; `false` keeps the\n * lean id-only proof. The snapshot is captured in every branch, including a refusal and a page-less\n * source.\n *\n * Time-of-check/time-of-use: a visitor reads the wording resolved when the form loaded, but the\n * snapshot here is re-resolved from the source at submit. If the source text changed in that window,\n * the proof records the submit-time wording, not the exact bytes rendered earlier. This is\n * deliberate, the server's live view is authoritative and the window is one visitor session; a form\n * that must freeze the exact wording agreed to should version the source (drafts give a `versionRef`\n * pinning the published version, below).\n *\n * `versionRef` is recorded only when the page's collection has drafts enabled, and then it is the\n * published version document's own id. Versions without drafts get no `versionRef`, because there\n * is no published/draft distinction to pin to: `_status` only exists under drafts, so a\n * published-version lookup there matches nothing, and recording that as a version reference would\n * be inventing one. Absent means absent, in both cases.\n *\n * `now` is injected by the caller (`new Date().toISOString()`) for testability.\n */\nexport const captureConsent = async (args: {\n\tfield: FormFieldInstance\n\tagreed: boolean\n\t/** The host's resolved sources for this request (see `resolveConsentEntries`). */\n\tentries: ConsentSourceEntry[]\n\tpayload: Payload\n\treq?: PayloadRequest\n\tnow: string\n\t/** What to snapshot of the agreed wording (plugin option `consent.snapshot`); defaults to `'both'`. */\n\tsnapshot?: ConsentSnapshotMode\n}): Promise<ConsentProof> => {\n\tconst source = typeof args.field.source === 'string' ? args.field.source : ''\n\tconst entry = source ? args.entries.find((candidate) => candidate.id === source) : undefined\n\tconst snapshot = args.snapshot ?? 'both'\n\tconst display = consentDisplayOf(args.field)\n\n\t// Capture the agreed wording (and the source label) onto every proof branch. Kept out of the two\n\t// returns so a refusal and a page-less source are snapshotted the same as the happy path. The\n\t// wording is selected per the field's display through the same helper the render path uses, so\n\t// the proof attests to the sentence the visitor saw.\n\tconst withSnapshot = (proof: ConsentProof): ConsentProof => {\n\t\tif (display === 'notice') {\n\t\t\tproof.display = 'notice'\n\t\t}\n\t\tif (!entry || snapshot === false) {\n\t\t\treturn proof\n\t\t}\n\t\tif (typeof entry.name === 'string' && entry.name.trim().length > 0) {\n\t\t\tproof.name = entry.name.trim()\n\t\t}\n\t\tconst text = textOfBody(effectiveConsentStatement(entry, display))\n\t\tif (text.length > 0) {\n\t\t\tif (snapshot === 'hash' || snapshot === 'both') {\n\t\t\t\tproof.statementHash = createHash('sha256').update(text).digest('hex')\n\t\t\t}\n\t\t\tif (snapshot === 'text' || snapshot === 'both') {\n\t\t\t\tproof.statementText = text\n\t\t\t}\n\t\t}\n\t\treturn proof\n\t}\n\n\tconst page = entry?.page\n\tif (!page) {\n\t\treturn withSnapshot({ agreed: args.agreed, source, at: args.now })\n\t}\n\t// `page.relationTo` is a runtime string; cast the key so the lookup type-checks against a host's\n\t// narrowed collection map (a consumer's generated `CollectionSlug`) as well as the plugin's own\n\t// broad one. The value is still guarded below, since an unregistered slug resolves to undefined.\n\tconst collection = args.payload.collections[page.relationTo as keyof Payload['collections']]\n\tconst versionRef =\n\t\tcollection && hasDraftsEnabled(collection.config)\n\t\t\t? await resolvePublishedVersionRef({\n\t\t\t\t\tpayload: args.payload,\n\t\t\t\t\tcollection: page.relationTo,\n\t\t\t\t\tid: page.id,\n\t\t\t\t\treq: args.req,\n\t\t\t\t})\n\t\t\t: null\n\treturn withSnapshot({\n\t\tagreed: args.agreed,\n\t\tsource,\n\t\tpage: { relationTo: page.relationTo, id: page.id },\n\t\t...(versionRef ? { versionRef } : {}),\n\t\tat: args.now,\n\t})\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuDA,MAAa,iBAAiB,OAAO,SAUR;CAC5B,MAAM,SAAS,OAAO,KAAK,MAAM,WAAW,WAAW,KAAK,MAAM,SAAS;CAC3E,MAAM,QAAQ,SAAS,KAAK,QAAQ,MAAM,cAAc,UAAU,OAAO,MAAM,IAAI,KAAA;CACnF,MAAM,WAAW,KAAK,YAAY;CAClC,MAAM,UAAU,iBAAiB,KAAK,KAAK;CAM3C,MAAM,gBAAgB,UAAsC;EAC3D,IAAI,YAAY,UACf,MAAM,UAAU;EAEjB,IAAI,CAAC,SAAS,aAAa,OAC1B,OAAO;EAER,IAAI,OAAO,MAAM,SAAS,YAAY,MAAM,KAAK,KAAK,EAAE,SAAS,GAChE,MAAM,OAAO,MAAM,KAAK,KAAK;EAE9B,MAAM,OAAO,WAAW,0BAA0B,OAAO,OAAO,CAAC;EACjE,IAAI,KAAK,SAAS,GAAG;GACpB,IAAI,aAAa,UAAU,aAAa,QACvC,MAAM,gBAAgB,WAAW,QAAQ,EAAE,OAAO,IAAI,EAAE,OAAO,KAAK;GAErE,IAAI,aAAa,UAAU,aAAa,QACvC,MAAM,gBAAgB;EAExB;EACA,OAAO;CACR;CAEA,MAAM,OAAO,OAAO;CACpB,IAAI,CAAC,MACJ,OAAO,aAAa;EAAE,QAAQ,KAAK;EAAQ;EAAQ,IAAI,KAAK;CAAI,CAAC;CAKlE,MAAM,aAAa,KAAK,QAAQ,YAAY,KAAK;CACjD,MAAM,aACL,cAAc,iBAAiB,WAAW,MAAM,IAC7C,MAAM,2BAA2B;EACjC,SAAS,KAAK;EACd,YAAY,KAAK;EACjB,IAAI,KAAK;EACT,KAAK,KAAK;CACX,CAAC,IACA;CACJ,OAAO,aAAa;EACnB,QAAQ,KAAK;EACb;EACA,MAAM;GAAE,YAAY,KAAK;GAAY,IAAI,KAAK;EAAG;EACjD,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;EACnC,IAAI,KAAK;CACV,CAAC;AACF"}
@@ -0,0 +1,66 @@
1
+ import { ArrayField, CollectionSlug, RichTextField } from "payload";
2
+
3
+ //#region src/consent/consentSourcesField.d.ts
4
+ type ConsentSourcesFieldOptions = {
5
+ /** Field name, i.e. what the row array is stored under. Defaults to `consentSources`. */name?: string; /** Field label. Defaults to the plugin's translated one. */
6
+ label?: ArrayField['label'];
7
+ /**
8
+ * Collections whose documents can be picked as a source's policy page. Omitted (the default):
9
+ * no page picker at all, so sources are statement-only and their proofs carry no page or
10
+ * version reference. Always stored polymorphically, even for a single slug (see below).
11
+ */
12
+ relationTo?: CollectionSlug | CollectionSlug[];
13
+ /**
14
+ * Whether the visitor-facing `statement` and `name` carry `localized: true`. Default `true`;
15
+ * Payload strips the flag on hosts without `localization`, so it is safe either way. Mirrors
16
+ * the plugin's `localizeContent` option, which this host-called factory cannot see.
17
+ */
18
+ localized?: boolean; /** Overrides the project's default richText editor for the `statement`, as `richText.editor` does plugin-side. */
19
+ editor?: RichTextField['editor'];
20
+ };
21
+ /**
22
+ * The consent sources array, for the host to place on any collection or global they own: a
23
+ * settings global, a tenants collection, a legal-pages parent, wherever the sources belong. The
24
+ * plugin never registers it and never guesses where it lives; a matching `consent.sources` resolver
25
+ * reads it back (see {@link ConsentSourcesResolver}), which is also where multi-tenant scoping goes:
26
+ * place this on the tenant-scoped document and have the resolver return only the sources of the
27
+ * tenant it derives from `req`.
28
+ *
29
+ * A row is a `name` (shown when picking the source on a form, and used as the policy link text
30
+ * beside the statement), the `statement` the visitor agrees to, and optionally the `page` that
31
+ * statement belongs to. The stable reference a consent field stores, and the only part that must
32
+ * outlive edits, is the row's own auto-assigned `id`: it survives a `name` edit or reordering,
33
+ * unlike a hand-authored key would. Authors fill in no version, no URL, and no document id by
34
+ * hand: the version is detected and recorded at submit time, and the page is a picker.
35
+ *
36
+ * `page` is always polymorphic, even when `relationTo` names a single collection, because a
37
+ * monomorphic relationship stores a bare id: the proof needs the collection alongside it to stay
38
+ * resolvable, and a host adding a second collection later would otherwise change the stored shape.
39
+ *
40
+ * ```ts
41
+ * // The host's own collection or global:
42
+ * fields: [consentSourcesField({ relationTo: ['pages', 'legal-notices'] })]
43
+ *
44
+ * // The plugin, reading it back:
45
+ * formBuilder({
46
+ * consent: {
47
+ * sources: async ({ req }) => {
48
+ * const settings = await req.payload.findGlobal({ slug: 'settings', depth: 0, locale: req.locale, req })
49
+ * return (settings.consentSources ?? []).map((row) => ({ ... }))
50
+ * },
51
+ * },
52
+ * })
53
+ * ```
54
+ *
55
+ * The resolver receives the whole form document, so derive tenant scoping from a field on it rather
56
+ * than reading the form back: reading the `forms` collection from the resolver re-enters this form's
57
+ * afterRead hook (the plugin guards against the resulting recursion, but the read is still wasted).
58
+ *
59
+ * A resolver reading its settings document must not thread the save's `req` into a `locale: 'all'`
60
+ * read from within a form's save validation: that flips `req.locale` to `all` and corrupts the
61
+ * localized write of the document being saved. It reads already-committed data, so no `req` is needed.
62
+ */
63
+ declare const consentSourcesField: (options?: ConsentSourcesFieldOptions) => ArrayField;
64
+ //#endregion
65
+ export { ConsentSourcesFieldOptions, consentSourcesField };
66
+ //# sourceMappingURL=consentSourcesField.d.ts.map
@@ -0,0 +1,98 @@
1
+ import { keys } from "../translations/keys.js";
2
+ import { labelForKey } from "../translations/server.js";
3
+ import { localizedIf } from "../fields/localizedIf.js";
4
+ //#region src/consent/consentSourcesField.ts
5
+ /**
6
+ * The consent sources array, for the host to place on any collection or global they own: a
7
+ * settings global, a tenants collection, a legal-pages parent, wherever the sources belong. The
8
+ * plugin never registers it and never guesses where it lives; a matching `consent.sources` resolver
9
+ * reads it back (see {@link ConsentSourcesResolver}), which is also where multi-tenant scoping goes:
10
+ * place this on the tenant-scoped document and have the resolver return only the sources of the
11
+ * tenant it derives from `req`.
12
+ *
13
+ * A row is a `name` (shown when picking the source on a form, and used as the policy link text
14
+ * beside the statement), the `statement` the visitor agrees to, and optionally the `page` that
15
+ * statement belongs to. The stable reference a consent field stores, and the only part that must
16
+ * outlive edits, is the row's own auto-assigned `id`: it survives a `name` edit or reordering,
17
+ * unlike a hand-authored key would. Authors fill in no version, no URL, and no document id by
18
+ * hand: the version is detected and recorded at submit time, and the page is a picker.
19
+ *
20
+ * `page` is always polymorphic, even when `relationTo` names a single collection, because a
21
+ * monomorphic relationship stores a bare id: the proof needs the collection alongside it to stay
22
+ * resolvable, and a host adding a second collection later would otherwise change the stored shape.
23
+ *
24
+ * ```ts
25
+ * // The host's own collection or global:
26
+ * fields: [consentSourcesField({ relationTo: ['pages', 'legal-notices'] })]
27
+ *
28
+ * // The plugin, reading it back:
29
+ * formBuilder({
30
+ * consent: {
31
+ * sources: async ({ req }) => {
32
+ * const settings = await req.payload.findGlobal({ slug: 'settings', depth: 0, locale: req.locale, req })
33
+ * return (settings.consentSources ?? []).map((row) => ({ ... }))
34
+ * },
35
+ * },
36
+ * })
37
+ * ```
38
+ *
39
+ * The resolver receives the whole form document, so derive tenant scoping from a field on it rather
40
+ * than reading the form back: reading the `forms` collection from the resolver re-enters this form's
41
+ * afterRead hook (the plugin guards against the resulting recursion, but the read is still wasted).
42
+ *
43
+ * A resolver reading its settings document must not thread the save's `req` into a `locale: 'all'`
44
+ * read from within a form's save validation: that flips `req.locale` to `all` and corrupts the
45
+ * localized write of the document being saved. It reads already-committed data, so no `req` is needed.
46
+ */
47
+ const consentSourcesField = (options = {}) => {
48
+ const localize = options.localized !== false;
49
+ const relationTo = options.relationTo && (!Array.isArray(options.relationTo) || options.relationTo.length > 0) ? options.relationTo : void 0;
50
+ const pageField = relationTo ? [{
51
+ name: "page",
52
+ type: "relationship",
53
+ relationTo: Array.isArray(relationTo) ? relationTo : [relationTo],
54
+ label: labelForKey(keys.consentSourcePage),
55
+ admin: { description: labelForKey(keys.consentSourcePageDescription) }
56
+ }] : [];
57
+ return {
58
+ name: options.name ?? "consentSources",
59
+ type: "array",
60
+ label: options.label ?? labelForKey(keys.consentSourcesField),
61
+ labels: {
62
+ singular: labelForKey(keys.consentSourceSingular),
63
+ plural: labelForKey(keys.consentSourcePlural)
64
+ },
65
+ admin: {
66
+ description: labelForKey(keys.consentSourcesFieldDescription),
67
+ components: { RowLabel: "@10x-media/form-builder/client#ConsentSourceRowLabel" }
68
+ },
69
+ fields: [
70
+ {
71
+ name: "name",
72
+ type: "text",
73
+ label: labelForKey(keys.consentSourceLabel),
74
+ ...localizedIf(localize)
75
+ },
76
+ {
77
+ name: "statement",
78
+ type: "richText",
79
+ label: labelForKey(keys.consentSourceStatement),
80
+ ...options.editor ? { editor: options.editor } : {},
81
+ ...localizedIf(localize)
82
+ },
83
+ {
84
+ name: "noticeStatement",
85
+ type: "richText",
86
+ label: labelForKey(keys.consentSourceNoticeStatement),
87
+ admin: { description: labelForKey(keys.consentSourceNoticeStatementDescription) },
88
+ ...options.editor ? { editor: options.editor } : {},
89
+ ...localizedIf(localize)
90
+ },
91
+ ...pageField
92
+ ]
93
+ };
94
+ };
95
+ //#endregion
96
+ export { consentSourcesField };
97
+
98
+ //# sourceMappingURL=consentSourcesField.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consentSourcesField.js","names":[],"sources":["../../src/consent/consentSourcesField.ts"],"sourcesContent":["import type { ArrayField, CollectionSlug, Field, RichTextField } from 'payload'\nimport { localizedIf } from '../fields/localizedIf'\nimport { keys } from '../translations/keys'\nimport { labelForKey } from '../translations/server'\n\nexport type ConsentSourcesFieldOptions = {\n\t/** Field name, i.e. what the row array is stored under. Defaults to `consentSources`. */\n\tname?: string\n\t/** Field label. Defaults to the plugin's translated one. */\n\tlabel?: ArrayField['label']\n\t/**\n\t * Collections whose documents can be picked as a source's policy page. Omitted (the default):\n\t * no page picker at all, so sources are statement-only and their proofs carry no page or\n\t * version reference. Always stored polymorphically, even for a single slug (see below).\n\t */\n\trelationTo?: CollectionSlug | CollectionSlug[]\n\t/**\n\t * Whether the visitor-facing `statement` and `name` carry `localized: true`. Default `true`;\n\t * Payload strips the flag on hosts without `localization`, so it is safe either way. Mirrors\n\t * the plugin's `localizeContent` option, which this host-called factory cannot see.\n\t */\n\tlocalized?: boolean\n\t/** Overrides the project's default richText editor for the `statement`, as `richText.editor` does plugin-side. */\n\teditor?: RichTextField['editor']\n}\n\n/**\n * The consent sources array, for the host to place on any collection or global they own: a\n * settings global, a tenants collection, a legal-pages parent, wherever the sources belong. The\n * plugin never registers it and never guesses where it lives; a matching `consent.sources` resolver\n * reads it back (see {@link ConsentSourcesResolver}), which is also where multi-tenant scoping goes:\n * place this on the tenant-scoped document and have the resolver return only the sources of the\n * tenant it derives from `req`.\n *\n * A row is a `name` (shown when picking the source on a form, and used as the policy link text\n * beside the statement), the `statement` the visitor agrees to, and optionally the `page` that\n * statement belongs to. The stable reference a consent field stores, and the only part that must\n * outlive edits, is the row's own auto-assigned `id`: it survives a `name` edit or reordering,\n * unlike a hand-authored key would. Authors fill in no version, no URL, and no document id by\n * hand: the version is detected and recorded at submit time, and the page is a picker.\n *\n * `page` is always polymorphic, even when `relationTo` names a single collection, because a\n * monomorphic relationship stores a bare id: the proof needs the collection alongside it to stay\n * resolvable, and a host adding a second collection later would otherwise change the stored shape.\n *\n * ```ts\n * // The host's own collection or global:\n * fields: [consentSourcesField({ relationTo: ['pages', 'legal-notices'] })]\n *\n * // The plugin, reading it back:\n * formBuilder({\n * consent: {\n * sources: async ({ req }) => {\n * const settings = await req.payload.findGlobal({ slug: 'settings', depth: 0, locale: req.locale, req })\n * return (settings.consentSources ?? []).map((row) => ({ ... }))\n * },\n * },\n * })\n * ```\n *\n * The resolver receives the whole form document, so derive tenant scoping from a field on it rather\n * than reading the form back: reading the `forms` collection from the resolver re-enters this form's\n * afterRead hook (the plugin guards against the resulting recursion, but the read is still wasted).\n *\n * A resolver reading its settings document must not thread the save's `req` into a `locale: 'all'`\n * read from within a form's save validation: that flips `req.locale` to `all` and corrupts the\n * localized write of the document being saved. It reads already-committed data, so no `req` is needed.\n */\nexport const consentSourcesField = (options: ConsentSourcesFieldOptions = {}): ArrayField => {\n\tconst localize = options.localized !== false\n\t// An empty `relationTo` array is treated as \"no page picker\", not a relationship field pointing\n\t// at nothing (which Payload rejects at boot).\n\tconst relationTo =\n\t\toptions.relationTo && (!Array.isArray(options.relationTo) || options.relationTo.length > 0)\n\t\t\t? options.relationTo\n\t\t\t: undefined\n\tconst pageField: Field[] = relationTo\n\t\t? [\n\t\t\t\t{\n\t\t\t\t\tname: 'page',\n\t\t\t\t\ttype: 'relationship',\n\t\t\t\t\trelationTo: Array.isArray(relationTo) ? relationTo : [relationTo],\n\t\t\t\t\tlabel: labelForKey(keys.consentSourcePage),\n\t\t\t\t\tadmin: { description: labelForKey(keys.consentSourcePageDescription) },\n\t\t\t\t},\n\t\t\t]\n\t\t: []\n\n\treturn {\n\t\tname: options.name ?? 'consentSources',\n\t\ttype: 'array',\n\t\tlabel: options.label ?? labelForKey(keys.consentSourcesField),\n\t\tlabels: {\n\t\t\tsingular: labelForKey(keys.consentSourceSingular),\n\t\t\tplural: labelForKey(keys.consentSourcePlural),\n\t\t},\n\t\tadmin: {\n\t\t\tdescription: labelForKey(keys.consentSourcesFieldDescription),\n\t\t\tcomponents: { RowLabel: '@10x-media/form-builder/client#ConsentSourceRowLabel' },\n\t\t},\n\t\tfields: [\n\t\t\t{\n\t\t\t\tname: 'name',\n\t\t\t\ttype: 'text',\n\t\t\t\tlabel: labelForKey(keys.consentSourceLabel),\n\t\t\t\t...localizedIf(localize),\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'statement',\n\t\t\t\ttype: 'richText',\n\t\t\t\tlabel: labelForKey(keys.consentSourceStatement),\n\t\t\t\t...(options.editor ? { editor: options.editor } : {}),\n\t\t\t\t...localizedIf(localize),\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'noticeStatement',\n\t\t\t\ttype: 'richText',\n\t\t\t\tlabel: labelForKey(keys.consentSourceNoticeStatement),\n\t\t\t\tadmin: { description: labelForKey(keys.consentSourceNoticeStatementDescription) },\n\t\t\t\t...(options.editor ? { editor: options.editor } : {}),\n\t\t\t\t...localizedIf(localize),\n\t\t\t},\n\t\t\t...pageField,\n\t\t],\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoEA,MAAa,uBAAuB,UAAsC,CAAC,MAAkB;CAC5F,MAAM,WAAW,QAAQ,cAAc;CAGvC,MAAM,aACL,QAAQ,eAAe,CAAC,MAAM,QAAQ,QAAQ,UAAU,KAAK,QAAQ,WAAW,SAAS,KACtF,QAAQ,aACR,KAAA;CACJ,MAAM,YAAqB,aACxB,CACA;EACC,MAAM;EACN,MAAM;EACN,YAAY,MAAM,QAAQ,UAAU,IAAI,aAAa,CAAC,UAAU;EAChE,OAAO,YAAY,KAAK,iBAAiB;EACzC,OAAO,EAAE,aAAa,YAAY,KAAK,4BAA4B,EAAE;CACtE,CACD,IACC,CAAC;CAEJ,OAAO;EACN,MAAM,QAAQ,QAAQ;EACtB,MAAM;EACN,OAAO,QAAQ,SAAS,YAAY,KAAK,mBAAmB;EAC5D,QAAQ;GACP,UAAU,YAAY,KAAK,qBAAqB;GAChD,QAAQ,YAAY,KAAK,mBAAmB;EAC7C;EACA,OAAO;GACN,aAAa,YAAY,KAAK,8BAA8B;GAC5D,YAAY,EAAE,UAAU,uDAAuD;EAChF;EACA,QAAQ;GACP;IACC,MAAM;IACN,MAAM;IACN,OAAO,YAAY,KAAK,kBAAkB;IAC1C,GAAG,YAAY,QAAQ;GACxB;GACA;IACC,MAAM;IACN,MAAM;IACN,OAAO,YAAY,KAAK,sBAAsB;IAC9C,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;IACnD,GAAG,YAAY,QAAQ;GACxB;GACA;IACC,MAAM;IACN,MAAM;IACN,OAAO,YAAY,KAAK,4BAA4B;IACpD,OAAO,EAAE,aAAa,YAAY,KAAK,uCAAuC,EAAE;IAChF,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;IACnD,GAAG,YAAY,QAAQ;GACxB;GACA,GAAG;EACJ;CACD;AACD"}
@@ -0,0 +1,16 @@
1
+ import { textOfBody } from "../actions/body/textOfBody.js";
2
+ //#region src/consent/effectiveStatement.ts
3
+ /** A consent field instance's display, defaulting anything but an explicit `'notice'` to `'checkbox'`. */
4
+ const consentDisplayOf = (field) => field?.display === "notice" ? "notice" : "checkbox";
5
+ /**
6
+ * The wording a consent field shows for its display: the source's `noticeStatement` for a notice
7
+ * (falling back to `statement` when it is absent or empty), the `statement` for a checkbox. Both
8
+ * the render path (`resolveConsentStatements`) and the proof path (`captureConsent`) select
9
+ * through this one function, which is what guarantees the snapshot attests to the wording the
10
+ * visitor actually saw.
11
+ */
12
+ const effectiveConsentStatement = (entry, display) => display === "notice" && textOfBody(entry.noticeStatement).trim().length > 0 ? entry.noticeStatement : entry.statement;
13
+ //#endregion
14
+ export { consentDisplayOf, effectiveConsentStatement };
15
+
16
+ //# sourceMappingURL=effectiveStatement.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effectiveStatement.js","names":[],"sources":["../../src/consent/effectiveStatement.ts"],"sourcesContent":["import { textOfBody } from '../actions/body/textOfBody'\nimport type { ConsentSourceEntry } from './types'\n\n/** How a consent field presents itself: a box to tick, or a passive notice the submit agrees to. */\nexport type ConsentDisplay = 'checkbox' | 'notice'\n\n/** A consent field instance's display, defaulting anything but an explicit `'notice'` to `'checkbox'`. */\nexport const consentDisplayOf = (field: unknown): ConsentDisplay =>\n\t(field as { display?: unknown } | null | undefined)?.display === 'notice' ? 'notice' : 'checkbox'\n\n/**\n * The wording a consent field shows for its display: the source's `noticeStatement` for a notice\n * (falling back to `statement` when it is absent or empty), the `statement` for a checkbox. Both\n * the render path (`resolveConsentStatements`) and the proof path (`captureConsent`) select\n * through this one function, which is what guarantees the snapshot attests to the wording the\n * visitor actually saw.\n */\nexport const effectiveConsentStatement = (\n\tentry: Pick<ConsentSourceEntry, 'statement' | 'noticeStatement'>,\n\tdisplay: ConsentDisplay\n): unknown =>\n\tdisplay === 'notice' && textOfBody(entry.noticeStatement).trim().length > 0\n\t\t? entry.noticeStatement\n\t\t: entry.statement\n"],"mappings":";;;AAOA,MAAa,oBAAoB,UAC/B,OAAoD,YAAY,WAAW,WAAW;;;;;;;;AASxF,MAAa,6BACZ,OACA,YAEA,YAAY,YAAY,WAAW,MAAM,eAAe,EAAE,KAAK,EAAE,SAAS,IACvE,MAAM,kBACN,MAAM"}
@@ -0,0 +1,24 @@
1
+ import { ConsentSourceEntry, ConsentSourcesResolver } from "./types.js";
2
+ import { Payload, PayloadRequest } from "payload";
3
+
4
+ //#region src/consent/resolveConsentEntries.d.ts
5
+ type ResolveConsentEntriesArgs = {
6
+ payload: Payload;
7
+ req: PayloadRequest; /** The whole form being resolved; forwarded to the resolver, which casts for non-standard fields (e.g. tenant). */
8
+ form: {
9
+ id: number | string;
10
+ title?: string | null;
11
+ }; /** Resolver override for plugin-internal callers; defaults to the one the plugin stashed on the config. */
12
+ sources?: ConsentSourcesResolver;
13
+ };
14
+ /**
15
+ * The host's consent sources for this request, or an empty list when no resolver is configured
16
+ * (in which case the `consent` field type is not registered either, so nothing can reference one).
17
+ * Throws whatever the resolver throws: every caller decides how to fail, and none of them fail open.
18
+ * Cached per request and form id, so one submission resolves the host's sources once no matter how
19
+ * many consent fields the form carries.
20
+ */
21
+ declare const resolveConsentEntries: (args: ResolveConsentEntriesArgs) => Promise<ConsentSourceEntry[]>;
22
+ //#endregion
23
+ export { ResolveConsentEntriesArgs, resolveConsentEntries };
24
+ //# sourceMappingURL=resolveConsentEntries.d.ts.map
@@ -0,0 +1,40 @@
1
+ import { customStateOf, stashCustomState } from "../plugin/customState.js";
2
+ //#region src/consent/resolveConsentEntries.ts
3
+ /** Park the host's resolver on the config so root-level helpers can find it via `payload.config`. */
4
+ const stashConsentSources = (custom, sources) => stashCustomState(custom, { consentSources: sources });
5
+ const consentSourcesOf = (payload) => customStateOf(payload).consentSources;
6
+ const CACHE_KEY = "formBuilderConsentSourcesCache";
7
+ const cacheOf = (req) => {
8
+ if (!req.context) return;
9
+ const existing = req.context[CACHE_KEY];
10
+ if (existing instanceof Map) return existing;
11
+ const created = /* @__PURE__ */ new Map();
12
+ req.context[CACHE_KEY] = created;
13
+ return created;
14
+ };
15
+ /**
16
+ * The host's consent sources for this request, or an empty list when no resolver is configured
17
+ * (in which case the `consent` field type is not registered either, so nothing can reference one).
18
+ * Throws whatever the resolver throws: every caller decides how to fail, and none of them fail open.
19
+ * Cached per request and form id, so one submission resolves the host's sources once no matter how
20
+ * many consent fields the form carries.
21
+ */
22
+ const resolveConsentEntries = async (args) => {
23
+ const { payload, req, form } = args;
24
+ const resolver = args.sources ?? consentSourcesOf(payload);
25
+ if (!resolver) return [];
26
+ const cache = cacheOf(req);
27
+ const cacheKey = String(form.id);
28
+ const cached = cache?.get(cacheKey);
29
+ if (cached) return cached;
30
+ const entries = await resolver({
31
+ req,
32
+ form
33
+ });
34
+ cache?.set(cacheKey, entries);
35
+ return entries;
36
+ };
37
+ //#endregion
38
+ export { resolveConsentEntries, stashConsentSources };
39
+
40
+ //# sourceMappingURL=resolveConsentEntries.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveConsentEntries.js","names":[],"sources":["../../src/consent/resolveConsentEntries.ts"],"sourcesContent":["import type { Payload, PayloadRequest } from 'payload'\nimport { customStateOf, stashCustomState } from '../plugin/customState'\nimport type { ConsentSourceEntry, ConsentSourcesResolver } from './types'\n\ntype ConsentCustomState = { consentSources: ConsentSourcesResolver }\n\n/** Park the host's resolver on the config so root-level helpers can find it via `payload.config`. */\nexport const stashConsentSources = (\n\tcustom: Record<string, unknown> | undefined,\n\tsources: ConsentSourcesResolver\n): Record<string, unknown> =>\n\tstashCustomState<ConsentCustomState>(custom, { consentSources: sources })\n\nexport const consentSourcesOf = (payload: Payload): ConsentSourcesResolver | undefined =>\n\tcustomStateOf<ConsentCustomState>(payload).consentSources\n\nconst CACHE_KEY = 'formBuilderConsentSourcesCache'\n\ntype EntriesCache = Map<string, ConsentSourceEntry[]>\n\nconst cacheOf = (req: PayloadRequest): EntriesCache | undefined => {\n\tif (!req.context) {\n\t\treturn undefined\n\t}\n\tconst existing = req.context[CACHE_KEY]\n\tif (existing instanceof Map) {\n\t\treturn existing as EntriesCache\n\t}\n\tconst created: EntriesCache = new Map()\n\treq.context[CACHE_KEY] = created\n\treturn created\n}\n\nexport type ResolveConsentEntriesArgs = {\n\tpayload: Payload\n\treq: PayloadRequest\n\t/** The whole form being resolved; forwarded to the resolver, which casts for non-standard fields (e.g. tenant). */\n\tform: { id: number | string; title?: string | null }\n\t/** Resolver override for plugin-internal callers; defaults to the one the plugin stashed on the config. */\n\tsources?: ConsentSourcesResolver\n}\n\n/**\n * The host's consent sources for this request, or an empty list when no resolver is configured\n * (in which case the `consent` field type is not registered either, so nothing can reference one).\n * Throws whatever the resolver throws: every caller decides how to fail, and none of them fail open.\n * Cached per request and form id, so one submission resolves the host's sources once no matter how\n * many consent fields the form carries.\n */\nexport const resolveConsentEntries = async (\n\targs: ResolveConsentEntriesArgs\n): Promise<ConsentSourceEntry[]> => {\n\tconst { payload, req, form } = args\n\tconst resolver = args.sources ?? consentSourcesOf(payload)\n\tif (!resolver) {\n\t\treturn []\n\t}\n\tconst cache = cacheOf(req)\n\tconst cacheKey = String(form.id)\n\tconst cached = cache?.get(cacheKey)\n\tif (cached) {\n\t\treturn cached\n\t}\n\tconst entries = await resolver({ req, form })\n\tcache?.set(cacheKey, entries)\n\treturn entries\n}\n"],"mappings":";;;AAOA,MAAa,uBACZ,QACA,YAEA,iBAAqC,QAAQ,EAAE,gBAAgB,QAAQ,CAAC;AAEzE,MAAa,oBAAoB,YAChC,cAAkC,OAAO,EAAE;AAE5C,MAAM,YAAY;AAIlB,MAAM,WAAW,QAAkD;CAClE,IAAI,CAAC,IAAI,SACR;CAED,MAAM,WAAW,IAAI,QAAQ;CAC7B,IAAI,oBAAoB,KACvB,OAAO;CAER,MAAM,0BAAwB,IAAI,IAAI;CACtC,IAAI,QAAQ,aAAa;CACzB,OAAO;AACR;;;;;;;;AAkBA,MAAa,wBAAwB,OACpC,SACmC;CACnC,MAAM,EAAE,SAAS,KAAK,SAAS;CAC/B,MAAM,WAAW,KAAK,WAAW,iBAAiB,OAAO;CACzD,IAAI,CAAC,UACJ,OAAO,CAAC;CAET,MAAM,QAAQ,QAAQ,GAAG;CACzB,MAAM,WAAW,OAAO,KAAK,EAAE;CAC/B,MAAM,SAAS,OAAO,IAAI,QAAQ;CAClC,IAAI,QACH,OAAO;CAER,MAAM,UAAU,MAAM,SAAS;EAAE;EAAK;CAAK,CAAC;CAC5C,OAAO,IAAI,UAAU,OAAO;CAC5B,OAAO;AACR"}
@@ -0,0 +1,37 @@
1
+ import { ConsentSourcesResolver } from "./types.js";
2
+ import { Payload, PayloadRequest } from "payload";
3
+
4
+ //#region src/consent/resolveConsentSourcesRequest.d.ts
5
+ /** One selectable consent source for the consent field's `source` select. */
6
+ type ConsentSourceOption = {
7
+ label: string;
8
+ value: string;
9
+ };
10
+ type ResolveConsentSourcesRequestArgs = {
11
+ payload: Payload;
12
+ formId: number | string | undefined; /** Whether the caller is authenticated (an admin/user). */
13
+ isAuthed: boolean;
14
+ req: PayloadRequest;
15
+ resolver: ConsentSourcesResolver;
16
+ };
17
+ type ResolveConsentSourcesRequestResult = {
18
+ status: number;
19
+ body: {
20
+ options: ConsentSourceOption[];
21
+ } | {
22
+ errors: {
23
+ message: string;
24
+ }[];
25
+ };
26
+ };
27
+ /**
28
+ * Authorize and resolve the `GET /:id/consent-sources` request backing the consent `source` select:
29
+ * authenticated callers get the host's sources for this request (a multi-tenant resolver scoping by
30
+ * `req` therefore offers an author only their own tenant's), anonymous callers are always refused.
31
+ * Statuses mirror the poll-options endpoint: 400 missing id, 403 unauthenticated, 404 unknown form,
32
+ * 503 when the resolver throws (fail closed).
33
+ */
34
+ declare const resolveConsentSourcesRequest: (args: ResolveConsentSourcesRequestArgs) => Promise<ResolveConsentSourcesRequestResult>;
35
+ //#endregion
36
+ export { ConsentSourceOption, ResolveConsentSourcesRequestArgs, ResolveConsentSourcesRequestResult, resolveConsentSourcesRequest };
37
+ //# sourceMappingURL=resolveConsentSourcesRequest.d.ts.map
@@ -0,0 +1,54 @@
1
+ import { resolveConsentEntries } from "./resolveConsentEntries.js";
2
+ import { FORMS_SLUG } from "../collections/forms.js";
3
+ //#region src/consent/resolveConsentSourcesRequest.ts
4
+ /**
5
+ * Authorize and resolve the `GET /:id/consent-sources` request backing the consent `source` select:
6
+ * authenticated callers get the host's sources for this request (a multi-tenant resolver scoping by
7
+ * `req` therefore offers an author only their own tenant's), anonymous callers are always refused.
8
+ * Statuses mirror the poll-options endpoint: 400 missing id, 403 unauthenticated, 404 unknown form,
9
+ * 503 when the resolver throws (fail closed).
10
+ */
11
+ const resolveConsentSourcesRequest = async (args) => {
12
+ const { payload, formId, isAuthed, req, resolver } = args;
13
+ if (!isAuthed) return {
14
+ status: 403,
15
+ body: { errors: [{ message: "Forbidden" }] }
16
+ };
17
+ if (formId == null) return {
18
+ status: 400,
19
+ body: { errors: [{ message: "Missing form id" }] }
20
+ };
21
+ const form = await payload.findByID({
22
+ collection: FORMS_SLUG,
23
+ id: formId,
24
+ depth: 0,
25
+ req
26
+ }).catch(() => null);
27
+ if (!form) return {
28
+ status: 404,
29
+ body: { errors: [{ message: "Not found" }] }
30
+ };
31
+ try {
32
+ return {
33
+ status: 200,
34
+ body: { options: (await resolveConsentEntries({
35
+ payload,
36
+ req,
37
+ form,
38
+ sources: resolver
39
+ })).map((entry) => ({
40
+ label: entry.name ?? entry.id,
41
+ value: entry.id
42
+ })) }
43
+ };
44
+ } catch {
45
+ return {
46
+ status: 503,
47
+ body: { errors: [{ message: "Consent sources unavailable" }] }
48
+ };
49
+ }
50
+ };
51
+ //#endregion
52
+ export { resolveConsentSourcesRequest };
53
+
54
+ //# sourceMappingURL=resolveConsentSourcesRequest.js.map