@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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outcomeBeforeChange.js","names":[],"sources":["../../src/poll/outcomeBeforeChange.ts"],"sourcesContent":["import { type CollectionBeforeChangeHook, ValidationError } from 'payload'\nimport { FORMS_SLUG } from '../collections/forms'\nimport { pollConfigOf } from '../form/pollState'\nimport { keys } from '../translations/keys'\nimport { asTranslate } from '../translations/server'\nimport type { PollOption } from './definePollOptionSource'\nimport { resolveEffectivePollOptions } from './effectivePollOptions'\n\nconst WINNING_VALUES_PATH = 'poll.outcome.winningValues'\n\n/** The winning set as a deduped array of non-empty strings, ready to store and to compare. */\nconst normalizeWinning = (value: unknown): string[] => {\n\tif (!Array.isArray(value)) {\n\t\treturn []\n\t}\n\tconst seen = new Set<string>()\n\tfor (const entry of value) {\n\t\tif (typeof entry === 'string' && entry.length > 0) {\n\t\t\tseen.add(entry)\n\t\t}\n\t}\n\treturn [...seen]\n}\n\n/** Set equality on two already-deduped winner arrays: order-insensitive membership. */\nconst sameWinners = (a: string[], b: string[]): boolean => {\n\tif (a.length !== b.length) {\n\t\treturn false\n\t}\n\tconst set = new Set(a)\n\treturn b.every((value) => set.has(value))\n}\n\n/**\n * Owns the poll outcome lifecycle for every create and update, admin and API alike. When the save\n * writes `poll.outcome.winningValues` it validates a set or changed winner set against the poll's\n * effective options (source-resolved or authored, over a merged view of the doc so partial updates\n * validate against stored config) and requires the poll to be enabled; clearing is always allowed.\n * A tie is a set with more than one winner; every value must be a member of the effective options.\n *\n * It is also the single `resolvedAt` stamping point: stamped when the winner set is set or changed,\n * cleared with the set, untouched when the set is unchanged (order-insensitive). Callers can never\n * write `resolvedAt` themselves (field-level access strips it during the beforeValidate traversal,\n * before this hook runs), while values this hook sets survive to the database, so the stamp always\n * reflects the actual transition regardless of the write path.\n */\nexport const pollOutcomeBeforeChange: CollectionBeforeChangeHook = async ({\n\tdata,\n\toriginalDoc,\n\treq,\n}) => {\n\tconst incomingPoll =\n\t\tdata?.poll != null && typeof data.poll === 'object'\n\t\t\t? (data.poll as Record<string, unknown>)\n\t\t\t: undefined\n\tconst outcome =\n\t\tincomingPoll?.outcome != null && typeof incomingPoll.outcome === 'object'\n\t\t\t? (incomingPoll.outcome as Record<string, unknown>)\n\t\t\t: undefined\n\tif (!outcome || !('winningValues' in outcome)) {\n\t\treturn data\n\t}\n\tconst next = normalizeWinning(outcome.winningValues)\n\toutcome.winningValues = next\n\tconst previous = normalizeWinning(pollConfigOf(originalDoc?.poll)?.outcome?.winningValues)\n\tif (sameWinners(next, previous)) {\n\t\treturn data\n\t}\n\tif (next.length === 0) {\n\t\toutcome.resolvedAt = null\n\t\treturn data\n\t}\n\n\tconst t = asTranslate(req.t)\n\tconst fail = (message: string): never => {\n\t\tthrow new ValidationError(\n\t\t\t{ collection: FORMS_SLUG, errors: [{ path: WINNING_VALUES_PATH, message }] },\n\t\t\treq.t\n\t\t)\n\t}\n\tconst originalPoll =\n\t\toriginalDoc?.poll != null && typeof originalDoc.poll === 'object'\n\t\t\t? (originalDoc.poll as Record<string, unknown>)\n\t\t\t: undefined\n\tconst mergedPoll = { ...(originalPoll ?? {}), ...incomingPoll }\n\t// The poll-enable flag lives at the document root now; merge the incoming partial over the stored\n\t// doc so a partial update that omits it still validates against the persisted value.\n\tconst mergedPollEnabled = { ...(originalDoc ?? {}), ...data }.pollEnabled === true\n\tif (!mergedPollEnabled) {\n\t\tfail(t(keys.validationWinningValueDisabled))\n\t}\n\tconst id = (originalDoc?.id ?? data?.id) as number | string | undefined\n\tconst form = {\n\t\tid: id ?? '',\n\t\ttitle:\n\t\t\ttypeof data?.title === 'string' ? data.title : (originalDoc?.title as string | undefined),\n\t\tpollEnabled: mergedPollEnabled,\n\t\tpoll: mergedPoll,\n\t\tfields: data?.fields ?? originalDoc?.fields,\n\t}\n\tlet options: PollOption[]\n\ttry {\n\t\t// Without a doc id (create) the per-request options cache would key on '', so skip it.\n\t\toptions = await resolveEffectivePollOptions({\n\t\t\tpayload: req.payload,\n\t\t\treq: id != null ? req : undefined,\n\t\t\tform,\n\t\t})\n\t} catch {\n\t\treturn fail(t(keys.pollOptionsUnavailable))\n\t}\n\tconst allowed = new Set(options.map((option) => option.value))\n\tif (!next.every((value) => allowed.has(value))) {\n\t\tfail(t(keys.validationWinningValueUnknown))\n\t}\n\toutcome.resolvedAt = new Date().toISOString()\n\treturn data\n}\n"],"mappings":";;;;;;;AAQA,MAAM,sBAAsB;;AAG5B,MAAM,oBAAoB,UAA6B;CACtD,IAAI,CAAC,MAAM,QAAQ,KAAK,GACvB,OAAO,CAAC;CAET,MAAM,uBAAO,IAAI,IAAY;CAC7B,KAAK,MAAM,SAAS,OACnB,IAAI,OAAO,UAAU,YAAY,MAAM,SAAS,GAC/C,KAAK,IAAI,KAAK;CAGhB,OAAO,CAAC,GAAG,IAAI;AAChB;;AAGA,MAAM,eAAe,GAAa,MAAyB;CAC1D,IAAI,EAAE,WAAW,EAAE,QAClB,OAAO;CAER,MAAM,MAAM,IAAI,IAAI,CAAC;CACrB,OAAO,EAAE,OAAO,UAAU,IAAI,IAAI,KAAK,CAAC;AACzC;;;;;;;;;;;;;;AAeA,MAAa,0BAAsD,OAAO,EACzE,MACA,aACA,UACK;CACL,MAAM,eACL,MAAM,QAAQ,QAAQ,OAAO,KAAK,SAAS,WACvC,KAAK,OACN,KAAA;CACJ,MAAM,UACL,cAAc,WAAW,QAAQ,OAAO,aAAa,YAAY,WAC7D,aAAa,UACd,KAAA;CACJ,IAAI,CAAC,WAAW,EAAE,mBAAmB,UACpC,OAAO;CAER,MAAM,OAAO,iBAAiB,QAAQ,aAAa;CACnD,QAAQ,gBAAgB;CAExB,IAAI,YAAY,MADC,iBAAiB,aAAa,aAAa,IAAI,GAAG,SAAS,aAC/C,CAAC,GAC7B,OAAO;CAER,IAAI,KAAK,WAAW,GAAG;EACtB,QAAQ,aAAa;EACrB,OAAO;CACR;CAEA,MAAM,IAAI,YAAY,IAAI,CAAC;CAC3B,MAAM,QAAQ,YAA2B;EACxC,MAAM,IAAI,gBACT;GAAE,YAAY;GAAY,QAAQ,CAAC;IAAE,MAAM;IAAqB;GAAQ,CAAC;EAAE,GAC3E,IAAI,CACL;CACD;CAKA,MAAM,aAAa;EAAE,IAHpB,aAAa,QAAQ,QAAQ,OAAO,YAAY,SAAS,WACrD,YAAY,OACb,KAAA,MACqC,CAAC;EAAI,GAAG;CAAa;CAG9D,MAAM,oBAAoB;EAAE,GAAI,eAAe,CAAC;EAAI,GAAG;CAAK,EAAE,gBAAgB;CAC9E,IAAI,CAAC,mBACJ,KAAK,EAAE,KAAK,8BAA8B,CAAC;CAE5C,MAAM,KAAM,aAAa,MAAM,MAAM;CACrC,MAAM,OAAO;EACZ,IAAI,MAAM;EACV,OACC,OAAO,MAAM,UAAU,WAAW,KAAK,QAAS,aAAa;EAC9D,aAAa;EACb,MAAM;EACN,QAAQ,MAAM,UAAU,aAAa;CACtC;CACA,IAAI;CACJ,IAAI;EAEH,UAAU,MAAM,4BAA4B;GAC3C,SAAS,IAAI;GACb,KAAK,MAAM,OAAO,MAAM,KAAA;GACxB;EACD,CAAC;CACF,QAAQ;EACP,OAAO,KAAK,EAAE,KAAK,sBAAsB,CAAC;CAC3C;CACA,MAAM,UAAU,IAAI,IAAI,QAAQ,KAAK,WAAW,OAAO,KAAK,CAAC;CAC7D,IAAI,CAAC,KAAK,OAAO,UAAU,QAAQ,IAAI,KAAK,CAAC,GAC5C,KAAK,EAAE,KAAK,6BAA6B,CAAC;CAE3C,QAAQ,8BAAa,IAAI,KAAK,GAAE,YAAY;CAC5C,OAAO;AACR"}
@@ -0,0 +1,38 @@
1
+ import { Field } from "payload";
2
+
3
+ //#region src/poll/outcomeFields.d.ts
4
+ /** The default poll-outcome fields, keyed by field. What the `poll.outcomeFields` seam receives. */
5
+ type DefaultOutcomeFields = {
6
+ winningValues: Field;
7
+ resolvedAt: Field;
8
+ };
9
+ /**
10
+ * Composes the forms poll `outcome` group. Receives the two default fields; the returned array
11
+ * becomes the group's fields verbatim, so swapping `winningValues` for a host component (e.g. a
12
+ * relationship picker over the voteable records), reordering, or adding a field is explicit.
13
+ * `pollOutcomeBeforeChange` validates every stored winning value against the poll's effective
14
+ * options server-side regardless of which component renders it, so a swap cannot bypass the
15
+ * membership check.
16
+ */
17
+ type OutcomeFieldsOverride = (args: {
18
+ defaultFields: DefaultOutcomeFields;
19
+ }) => Field[];
20
+ /**
21
+ * The winners field (`poll.outcome.winningValues`): a `hasMany` text field whose default admin
22
+ * component is the `poll-options` endpoint select rendered as a multi-select, so a tie records
23
+ * every winner. Each stored value is matched against the poll's effective options by
24
+ * `pollOutcomeBeforeChange`; a host may swap the component, but the stored contract stays an array
25
+ * of `PollOption.value` strings so membership validation keeps working.
26
+ */
27
+ declare const buildWinningValuesField: () => Field;
28
+ /**
29
+ * The resolved-at stamp field (`poll.outcome.resolvedAt`): read-only and locked against every
30
+ * caller write via field-level access, so only `pollOutcomeBeforeChange` (which runs after access
31
+ * filtering) can stamp it. Kept in the defaults so a host override that preserves it keeps the lock.
32
+ */
33
+ declare const buildResolvedAtField: () => Field;
34
+ /** Both defaults, exactly what the `poll.outcomeFields` seam is handed. */
35
+ declare const buildDefaultOutcomeFields: () => DefaultOutcomeFields;
36
+ //#endregion
37
+ export { DefaultOutcomeFields, OutcomeFieldsOverride, buildDefaultOutcomeFields, buildResolvedAtField, buildWinningValuesField };
38
+ //# sourceMappingURL=outcomeFields.d.ts.map
@@ -0,0 +1,52 @@
1
+ import { keys } from "../translations/keys.js";
2
+ import { labelForKey } from "../translations/server.js";
3
+ //#region src/poll/outcomeFields.ts
4
+ const ENDPOINT_OPTIONS_SELECT_REF = "@10x-media/form-builder/client#EndpointOptionsSelect";
5
+ /**
6
+ * The winners field (`poll.outcome.winningValues`): a `hasMany` text field whose default admin
7
+ * component is the `poll-options` endpoint select rendered as a multi-select, so a tie records
8
+ * every winner. Each stored value is matched against the poll's effective options by
9
+ * `pollOutcomeBeforeChange`; a host may swap the component, but the stored contract stays an array
10
+ * of `PollOption.value` strings so membership validation keeps working.
11
+ */
12
+ const buildWinningValuesField = () => ({
13
+ name: "winningValues",
14
+ type: "text",
15
+ hasMany: true,
16
+ label: labelForKey(keys.pollWinningValue),
17
+ admin: {
18
+ condition: (data) => data?.poll?.type === "manual",
19
+ components: { Field: {
20
+ path: ENDPOINT_OPTIONS_SELECT_REF,
21
+ clientProps: {
22
+ endpoint: "poll-options",
23
+ descriptionKey: keys.pollWinningValueDescription,
24
+ isMulti: true
25
+ }
26
+ } }
27
+ }
28
+ });
29
+ /**
30
+ * The resolved-at stamp field (`poll.outcome.resolvedAt`): read-only and locked against every
31
+ * caller write via field-level access, so only `pollOutcomeBeforeChange` (which runs after access
32
+ * filtering) can stamp it. Kept in the defaults so a host override that preserves it keeps the lock.
33
+ */
34
+ const buildResolvedAtField = () => ({
35
+ name: "resolvedAt",
36
+ type: "date",
37
+ label: labelForKey(keys.pollResolvedAt),
38
+ admin: { readOnly: true },
39
+ access: {
40
+ create: () => false,
41
+ update: () => false
42
+ }
43
+ });
44
+ /** Both defaults, exactly what the `poll.outcomeFields` seam is handed. */
45
+ const buildDefaultOutcomeFields = () => ({
46
+ winningValues: buildWinningValuesField(),
47
+ resolvedAt: buildResolvedAtField()
48
+ });
49
+ //#endregion
50
+ export { buildDefaultOutcomeFields, buildResolvedAtField, buildWinningValuesField };
51
+
52
+ //# sourceMappingURL=outcomeFields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outcomeFields.js","names":[],"sources":["../../src/poll/outcomeFields.ts"],"sourcesContent":["import type { Field } from 'payload'\nimport { keys } from '../translations/keys'\nimport { labelForKey } from '../translations/server'\n\nconst ENDPOINT_OPTIONS_SELECT_REF = '@10x-media/form-builder/client#EndpointOptionsSelect'\n\n/** The default poll-outcome fields, keyed by field. What the `poll.outcomeFields` seam receives. */\nexport type DefaultOutcomeFields = {\n\twinningValues: Field\n\tresolvedAt: Field\n}\n\n/**\n * Composes the forms poll `outcome` group. Receives the two default fields; the returned array\n * becomes the group's fields verbatim, so swapping `winningValues` for a host component (e.g. a\n * relationship picker over the voteable records), reordering, or adding a field is explicit.\n * `pollOutcomeBeforeChange` validates every stored winning value against the poll's effective\n * options server-side regardless of which component renders it, so a swap cannot bypass the\n * membership check.\n */\nexport type OutcomeFieldsOverride = (args: { defaultFields: DefaultOutcomeFields }) => Field[]\n\n/**\n * The winners field (`poll.outcome.winningValues`): a `hasMany` text field whose default admin\n * component is the `poll-options` endpoint select rendered as a multi-select, so a tie records\n * every winner. Each stored value is matched against the poll's effective options by\n * `pollOutcomeBeforeChange`; a host may swap the component, but the stored contract stays an array\n * of `PollOption.value` strings so membership validation keeps working.\n */\nexport const buildWinningValuesField = (): Field => ({\n\tname: 'winningValues',\n\ttype: 'text',\n\thasMany: true,\n\tlabel: labelForKey(keys.pollWinningValue),\n\tadmin: {\n\t\t// Only a `manual` poll has a winner to hand-pick; `mostVoted` and `source` auto-resolve on close,\n\t\t// so a hand-picked value would just be discarded. Show the field for `manual` alone. A stored value\n\t\t// survives a save because Payload keeps a condition-hidden field's value in form state and resubmits\n\t\t// it, and the outcome hook's early-return leaves winningValues untouched when a save omits it. The\n\t\t// first Condition arg is the whole document (the field sits at poll.outcome.winningValues), so read\n\t\t// poll.type off it.\n\t\tcondition: (data) => (data as { poll?: { type?: string } })?.poll?.type === 'manual',\n\t\tcomponents: {\n\t\t\tField: {\n\t\t\t\tpath: ENDPOINT_OPTIONS_SELECT_REF,\n\t\t\t\tclientProps: {\n\t\t\t\t\tendpoint: 'poll-options',\n\t\t\t\t\tdescriptionKey: keys.pollWinningValueDescription,\n\t\t\t\t\tisMulti: true,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n})\n\n/**\n * The resolved-at stamp field (`poll.outcome.resolvedAt`): read-only and locked against every\n * caller write via field-level access, so only `pollOutcomeBeforeChange` (which runs after access\n * filtering) can stamp it. Kept in the defaults so a host override that preserves it keeps the lock.\n */\nexport const buildResolvedAtField = (): Field => ({\n\tname: 'resolvedAt',\n\ttype: 'date',\n\tlabel: labelForKey(keys.pollResolvedAt),\n\tadmin: { readOnly: true },\n\taccess: { create: () => false, update: () => false },\n})\n\n/** Both defaults, exactly what the `poll.outcomeFields` seam is handed. */\nexport const buildDefaultOutcomeFields = (): DefaultOutcomeFields => ({\n\twinningValues: buildWinningValuesField(),\n\tresolvedAt: buildResolvedAtField(),\n})\n"],"mappings":";;;AAIA,MAAM,8BAA8B;;;;;;;;AAyBpC,MAAa,iCAAwC;CACpD,MAAM;CACN,MAAM;CACN,SAAS;CACT,OAAO,YAAY,KAAK,gBAAgB;CACxC,OAAO;EAON,YAAY,SAAU,MAAuC,MAAM,SAAS;EAC5E,YAAY,EACX,OAAO;GACN,MAAM;GACN,aAAa;IACZ,UAAU;IACV,gBAAgB,KAAK;IACrB,SAAS;GACV;EACD,EACD;CACD;AACD;;;;;;AAOA,MAAa,8BAAqC;CACjD,MAAM;CACN,MAAM;CACN,OAAO,YAAY,KAAK,cAAc;CACtC,OAAO,EAAE,UAAU,KAAK;CACxB,QAAQ;EAAE,cAAc;EAAO,cAAc;CAAM;AACpD;;AAGA,MAAa,mCAAyD;CACrE,eAAe,wBAAwB;CACvC,YAAY,qBAAqB;AAClC"}
@@ -0,0 +1,34 @@
1
+ import { PollOutcomeStrategy } from "./definePollType.js";
2
+ import { Payload } from "payload";
3
+
4
+ //#region src/poll/pollTypeRegistry.d.ts
5
+ type PollTypeRegistry = Map<string, PollOutcomeStrategy>;
6
+ /**
7
+ * Host-supplied outcome strategies: a keyed record (the key forces `type`, like the field-type
8
+ * registry) or a plain array. There are no boolean toggles because the three built-ins are always
9
+ * registered; a host entry with a built-in's `type` replaces it.
10
+ */
11
+ type PollTypesConfig = Record<string, PollOutcomeStrategy> | PollOutcomeStrategy[];
12
+ /** The default: an admin records `winningValues` by hand, so there is nothing to auto-resolve. */
13
+ declare const manualStrategy: PollOutcomeStrategy;
14
+ /**
15
+ * Delegate to the poll's configured option source `resolveOutcome` (the same domain resolver that
16
+ * feeds explicit `resolvePollOutcome` auto mode before this task shipped). Returns `undefined` when
17
+ * the poll has no source, the source is unregistered, or it does not implement `resolveOutcome`, so a
18
+ * misconfigured poll never throws from the close job or the read fallback; a source that resolves to
19
+ * no decision (its `resolveOutcome` returns `undefined`) also yields `undefined`.
20
+ */
21
+ declare const sourceStrategy: PollOutcomeStrategy;
22
+ /**
23
+ * The active poll-type registry: the three always-registered built-ins (`manual`, `mostVoted`,
24
+ * `source`) plus any host strategies from the plugin `poll.types` option. A host entry keyed by (or
25
+ * carrying a `type` of) a built-in slug replaces that built-in. Mirrors the field-type registry: a
26
+ * record key forces the strategy's `type` so a keyed override cannot rename the slot.
27
+ */
28
+ declare const resolvePollTypes: (config?: PollTypesConfig) => PollTypeRegistry;
29
+ /** Store the resolved registry on the config so `resolvePollOutcome` can reach it via `payload.config`. */
30
+ declare const stashPollTypes: (custom: Record<string, unknown> | undefined, registry: PollTypeRegistry) => Record<string, unknown>;
31
+ declare const pollTypesOf: (payload: Payload) => PollTypeRegistry;
32
+ //#endregion
33
+ export { PollTypeRegistry, PollTypesConfig, manualStrategy, pollTypesOf, resolvePollTypes, sourceStrategy, stashPollTypes };
34
+ //# sourceMappingURL=pollTypeRegistry.d.ts.map
@@ -0,0 +1,69 @@
1
+ import { keys } from "../translations/keys.js";
2
+ import { applyRegistryConfig } from "../plugin/applyRegistryConfig.js";
3
+ import { customStateOf, stashCustomState } from "../plugin/customState.js";
4
+ import { pollOptionSourcesOf } from "./resolvePollOptions.js";
5
+ import { definePollType } from "./definePollType.js";
6
+ import { mostVotedStrategy } from "./mostVoted.js";
7
+ //#region src/poll/pollTypeRegistry.ts
8
+ /** The default: an admin records `winningValues` by hand, so there is nothing to auto-resolve. */
9
+ const manualStrategy = definePollType({
10
+ type: "manual",
11
+ label: keys.pollTypeManual,
12
+ resolveOutcome: () => void 0
13
+ });
14
+ /** One winner set as a deduped array of non-empty strings, or `undefined` when the source yields none. */
15
+ const normalizeSourceOutcome = (value) => {
16
+ if (value === void 0) return;
17
+ const cleaned = [...new Set((Array.isArray(value) ? value : [value]).filter((entry) => typeof entry === "string" && entry.length > 0))];
18
+ return cleaned.length > 0 ? cleaned : void 0;
19
+ };
20
+ /**
21
+ * Delegate to the poll's configured option source `resolveOutcome` (the same domain resolver that
22
+ * feeds explicit `resolvePollOutcome` auto mode before this task shipped). Returns `undefined` when
23
+ * the poll has no source, the source is unregistered, or it does not implement `resolveOutcome`, so a
24
+ * misconfigured poll never throws from the close job or the read fallback; a source that resolves to
25
+ * no decision (its `resolveOutcome` returns `undefined`) also yields `undefined`.
26
+ */
27
+ const sourceStrategy = definePollType({
28
+ type: "source",
29
+ label: keys.pollTypeSource,
30
+ resolveOutcome: async ({ payload, req, form, poll }) => {
31
+ const optionSource = typeof poll.optionSource === "string" && poll.optionSource.length > 0 ? poll.optionSource : void 0;
32
+ if (!optionSource) return;
33
+ const source = pollOptionSourcesOf(payload).get(optionSource);
34
+ if (!source?.resolveOutcome) return;
35
+ const config = poll.sourceConfig != null && typeof poll.sourceConfig === "object" ? poll.sourceConfig : {};
36
+ return normalizeSourceOutcome(await source.resolveOutcome({
37
+ config,
38
+ form: {
39
+ id: form.id,
40
+ title: typeof form.title === "string" ? form.title : void 0
41
+ },
42
+ payload,
43
+ req
44
+ }));
45
+ }
46
+ });
47
+ /**
48
+ * The active poll-type registry: the three always-registered built-ins (`manual`, `mostVoted`,
49
+ * `source`) plus any host strategies from the plugin `poll.types` option. A host entry keyed by (or
50
+ * carrying a `type` of) a built-in slug replaces that built-in. Mirrors the field-type registry: a
51
+ * record key forces the strategy's `type` so a keyed override cannot rename the slot.
52
+ */
53
+ const resolvePollTypes = (config) => {
54
+ const registry = new Map([
55
+ [manualStrategy.type, manualStrategy],
56
+ [mostVotedStrategy.type, mostVotedStrategy],
57
+ [sourceStrategy.type, sourceStrategy]
58
+ ]);
59
+ if (Array.isArray(config)) for (const strategy of config) registry.set(strategy.type, strategy);
60
+ else if (config) applyRegistryConfig(registry, config);
61
+ return registry;
62
+ };
63
+ /** Store the resolved registry on the config so `resolvePollOutcome` can reach it via `payload.config`. */
64
+ const stashPollTypes = (custom, registry) => stashCustomState(custom, { pollTypes: registry });
65
+ const pollTypesOf = (payload) => customStateOf(payload).pollTypes ?? /* @__PURE__ */ new Map();
66
+ //#endregion
67
+ export { manualStrategy, pollTypesOf, resolvePollTypes, sourceStrategy, stashPollTypes };
68
+
69
+ //# sourceMappingURL=pollTypeRegistry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pollTypeRegistry.js","names":[],"sources":["../../src/poll/pollTypeRegistry.ts"],"sourcesContent":["import type { Payload } from 'payload'\nimport { applyRegistryConfig } from '../plugin/applyRegistryConfig'\nimport { customStateOf, stashCustomState } from '../plugin/customState'\nimport { keys } from '../translations/keys'\nimport { definePollType, type PollOutcomeStrategy } from './definePollType'\nimport { mostVotedStrategy } from './mostVoted'\nimport { pollOptionSourcesOf } from './resolvePollOptions'\n\nexport type PollTypeRegistry = Map<string, PollOutcomeStrategy>\n\n/**\n * Host-supplied outcome strategies: a keyed record (the key forces `type`, like the field-type\n * registry) or a plain array. There are no boolean toggles because the three built-ins are always\n * registered; a host entry with a built-in's `type` replaces it.\n */\nexport type PollTypesConfig = Record<string, PollOutcomeStrategy> | PollOutcomeStrategy[]\n\n/** The default: an admin records `winningValues` by hand, so there is nothing to auto-resolve. */\nexport const manualStrategy: PollOutcomeStrategy = definePollType({\n\ttype: 'manual',\n\tlabel: keys.pollTypeManual,\n\tresolveOutcome: () => undefined,\n})\n\n/** One winner set as a deduped array of non-empty strings, or `undefined` when the source yields none. */\nconst normalizeSourceOutcome = (value: string | string[] | undefined): string[] | undefined => {\n\tif (value === undefined) {\n\t\treturn undefined\n\t}\n\tconst cleaned = [\n\t\t...new Set(\n\t\t\t(Array.isArray(value) ? value : [value]).filter(\n\t\t\t\t(entry): entry is string => typeof entry === 'string' && entry.length > 0\n\t\t\t)\n\t\t),\n\t]\n\treturn cleaned.length > 0 ? cleaned : undefined\n}\n\n/**\n * Delegate to the poll's configured option source `resolveOutcome` (the same domain resolver that\n * feeds explicit `resolvePollOutcome` auto mode before this task shipped). Returns `undefined` when\n * the poll has no source, the source is unregistered, or it does not implement `resolveOutcome`, so a\n * misconfigured poll never throws from the close job or the read fallback; a source that resolves to\n * no decision (its `resolveOutcome` returns `undefined`) also yields `undefined`.\n */\nexport const sourceStrategy: PollOutcomeStrategy = definePollType({\n\ttype: 'source',\n\tlabel: keys.pollTypeSource,\n\tresolveOutcome: async ({ payload, req, form, poll }) => {\n\t\tconst optionSource =\n\t\t\ttypeof poll.optionSource === 'string' && poll.optionSource.length > 0\n\t\t\t\t? poll.optionSource\n\t\t\t\t: undefined\n\t\tif (!optionSource) {\n\t\t\treturn undefined\n\t\t}\n\t\tconst source = pollOptionSourcesOf(payload).get(optionSource)\n\t\tif (!source?.resolveOutcome) {\n\t\t\treturn undefined\n\t\t}\n\t\tconst config =\n\t\t\tpoll.sourceConfig != null && typeof poll.sourceConfig === 'object'\n\t\t\t\t? (poll.sourceConfig as Record<string, unknown>)\n\t\t\t\t: {}\n\t\treturn normalizeSourceOutcome(\n\t\t\tawait source.resolveOutcome({\n\t\t\t\tconfig,\n\t\t\t\tform: { id: form.id, title: typeof form.title === 'string' ? form.title : undefined },\n\t\t\t\tpayload,\n\t\t\t\treq,\n\t\t\t})\n\t\t)\n\t},\n})\n\n/**\n * The active poll-type registry: the three always-registered built-ins (`manual`, `mostVoted`,\n * `source`) plus any host strategies from the plugin `poll.types` option. A host entry keyed by (or\n * carrying a `type` of) a built-in slug replaces that built-in. Mirrors the field-type registry: a\n * record key forces the strategy's `type` so a keyed override cannot rename the slot.\n */\nexport const resolvePollTypes = (config?: PollTypesConfig): PollTypeRegistry => {\n\tconst registry: PollTypeRegistry = new Map([\n\t\t[manualStrategy.type, manualStrategy],\n\t\t[mostVotedStrategy.type, mostVotedStrategy],\n\t\t[sourceStrategy.type, sourceStrategy],\n\t])\n\tif (Array.isArray(config)) {\n\t\tfor (const strategy of config) {\n\t\t\tregistry.set(strategy.type, strategy)\n\t\t}\n\t} else if (config) {\n\t\t// A keyed record shares the sibling registries' merge (the key forces `type`). There are no\n\t\t// boolean toggles here because the three built-ins are always registered, so those branches\n\t\t// are inert for this always-strategy config.\n\t\tapplyRegistryConfig(registry, config)\n\t}\n\treturn registry\n}\n\ntype PollTypesCustomState = { pollTypes: PollTypeRegistry }\n\n/** Store the resolved registry on the config so `resolvePollOutcome` can reach it via `payload.config`. */\nexport const stashPollTypes = (\n\tcustom: Record<string, unknown> | undefined,\n\tregistry: PollTypeRegistry\n): Record<string, unknown> =>\n\tstashCustomState<PollTypesCustomState>(custom, { pollTypes: registry })\n\nexport const pollTypesOf = (payload: Payload): PollTypeRegistry =>\n\tcustomStateOf<PollTypesCustomState>(payload).pollTypes ?? new Map()\n"],"mappings":";;;;;;;;AAkBA,MAAa,iBAAsC,eAAe;CACjE,MAAM;CACN,OAAO,KAAK;CACZ,sBAAsB,KAAA;AACvB,CAAC;;AAGD,MAAM,0BAA0B,UAA+D;CAC9F,IAAI,UAAU,KAAA,GACb;CAED,MAAM,UAAU,CACf,GAAG,IAAI,KACL,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK,GAAG,QACvC,UAA2B,OAAO,UAAU,YAAY,MAAM,SAAS,CACzE,CACD,CACD;CACA,OAAO,QAAQ,SAAS,IAAI,UAAU,KAAA;AACvC;;;;;;;;AASA,MAAa,iBAAsC,eAAe;CACjE,MAAM;CACN,OAAO,KAAK;CACZ,gBAAgB,OAAO,EAAE,SAAS,KAAK,MAAM,WAAW;EACvD,MAAM,eACL,OAAO,KAAK,iBAAiB,YAAY,KAAK,aAAa,SAAS,IACjE,KAAK,eACL,KAAA;EACJ,IAAI,CAAC,cACJ;EAED,MAAM,SAAS,oBAAoB,OAAO,EAAE,IAAI,YAAY;EAC5D,IAAI,CAAC,QAAQ,gBACZ;EAED,MAAM,SACL,KAAK,gBAAgB,QAAQ,OAAO,KAAK,iBAAiB,WACtD,KAAK,eACN,CAAC;EACL,OAAO,uBACN,MAAM,OAAO,eAAe;GAC3B;GACA,MAAM;IAAE,IAAI,KAAK;IAAI,OAAO,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,KAAA;GAAU;GACpF;GACA;EACD,CAAC,CACF;CACD;AACD,CAAC;;;;;;;AAQD,MAAa,oBAAoB,WAA+C;CAC/E,MAAM,WAA6B,IAAI,IAAI;EAC1C,CAAC,eAAe,MAAM,cAAc;EACpC,CAAC,kBAAkB,MAAM,iBAAiB;EAC1C,CAAC,eAAe,MAAM,cAAc;CACrC,CAAC;CACD,IAAI,MAAM,QAAQ,MAAM,GACvB,KAAK,MAAM,YAAY,QACtB,SAAS,IAAI,SAAS,MAAM,QAAQ;MAE/B,IAAI,QAIV,oBAAoB,UAAU,MAAM;CAErC,OAAO;AACR;;AAKA,MAAa,kBACZ,QACA,aAEA,iBAAuC,QAAQ,EAAE,WAAW,SAAS,CAAC;AAEvE,MAAa,eAAe,YAC3B,cAAoC,OAAO,EAAE,6BAAa,IAAI,IAAI"}
@@ -0,0 +1,17 @@
1
+ import { AnyPollOptionSource } from "./definePollOptionSource.js";
2
+ import { RegistryConfig } from "../plugin/applyRegistryConfig.js";
3
+
4
+ //#region src/poll/registry.d.ts
5
+ type PollOptionSourceRegistry = Map<string, AnyPollOptionSource>;
6
+ /** `false` removes a source, `true` keeps it (no-op: there are no built-ins), a definition adds or replaces one. */
7
+ type PollOptionSourceOption = boolean | AnyPollOptionSource;
8
+ type PollOptionSourcesConfig = RegistryConfig<AnyPollOptionSource>;
9
+ /**
10
+ * Resolve the active poll option-source registry from a consumer map. Unlike the consent and
11
+ * action registries there are no built-in defaults: the registry starts empty and only host
12
+ * definitions populate it, so `true`/`false` entries are accepted but change nothing.
13
+ */
14
+ declare const resolvePollOptionSources: (config?: PollOptionSourcesConfig) => PollOptionSourceRegistry;
15
+ //#endregion
16
+ export { PollOptionSourceOption, PollOptionSourceRegistry, PollOptionSourcesConfig, resolvePollOptionSources };
17
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1,12 @@
1
+ import { applyRegistryConfig } from "../plugin/applyRegistryConfig.js";
2
+ //#region src/poll/registry.ts
3
+ /**
4
+ * Resolve the active poll option-source registry from a consumer map. Unlike the consent and
5
+ * action registries there are no built-in defaults: the registry starts empty and only host
6
+ * definitions populate it, so `true`/`false` entries are accepted but change nothing.
7
+ */
8
+ const resolvePollOptionSources = (config = {}) => applyRegistryConfig(/* @__PURE__ */ new Map(), config);
9
+ //#endregion
10
+ export { resolvePollOptionSources };
11
+
12
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","names":[],"sources":["../../src/poll/registry.ts"],"sourcesContent":["import { applyRegistryConfig, type RegistryConfig } from '../plugin/applyRegistryConfig'\nimport type { AnyPollOptionSource } from './definePollOptionSource'\n\nexport type PollOptionSourceRegistry = Map<string, AnyPollOptionSource>\n\n/** `false` removes a source, `true` keeps it (no-op: there are no built-ins), a definition adds or replaces one. */\nexport type PollOptionSourceOption = boolean | AnyPollOptionSource\n\nexport type PollOptionSourcesConfig = RegistryConfig<AnyPollOptionSource>\n\n/**\n * Resolve the active poll option-source registry from a consumer map. Unlike the consent and\n * action registries there are no built-in defaults: the registry starts empty and only host\n * definitions populate it, so `true`/`false` entries are accepted but change nothing.\n */\nexport const resolvePollOptionSources = (\n\tconfig: PollOptionSourcesConfig = {}\n): PollOptionSourceRegistry => applyRegistryConfig(new Map<string, AnyPollOptionSource>(), config)\n"],"mappings":";;;;;;;AAeA,MAAa,4BACZ,SAAkC,CAAC,MACL,oCAAoB,IAAI,IAAiC,GAAG,MAAM"}
@@ -0,0 +1,106 @@
1
+ import { keys } from "../translations/keys.js";
2
+ import { asTranslate } from "../translations/server.js";
3
+ import { isPollClosed, pollConfigOf } from "../form/pollState.js";
4
+ import { resolvePollOutcome } from "./resolvePollOutcome.js";
5
+ import { FORMS_SLUG } from "../collections/forms.js";
6
+ //#region src/poll/resolvePollCloseRequest.ts
7
+ /** The recorded winning set as non-empty strings; empty means no winner has been set yet. */
8
+ const winnersOf = (poll) => {
9
+ const winners = poll.outcome?.winningValues;
10
+ if (!Array.isArray(winners)) return [];
11
+ return winners.filter((value) => typeof value === "string" && value.length > 0);
12
+ };
13
+ /** The selected outcome strategy slug; an absent or empty `type` is `manual`. */
14
+ const strategyOf = (poll) => typeof poll.type === "string" && poll.type.length > 0 ? poll.type : "manual";
15
+ /**
16
+ * Decide what closing a poll now should do, purely from a loaded form so the branch logic is testable
17
+ * without a boot. `manual` requires a winner to already be recorded (closing only stamps the time);
18
+ * `mostVoted`, `source`, and any host strategy auto-resolve on close. Refuses a non-poll form and an
19
+ * already-closed poll (idempotency), so the request helper performs no write unless this returns `ok`.
20
+ */
21
+ const planPollClose = (form) => {
22
+ const poll = pollConfigOf(form.poll);
23
+ if (form.pollEnabled !== true || !poll) return {
24
+ ok: false,
25
+ reason: "not-poll"
26
+ };
27
+ if (isPollClosed(poll)) return {
28
+ ok: false,
29
+ reason: "already-closed"
30
+ };
31
+ if (strategyOf(poll) === "manual" && winnersOf(poll).length === 0) return {
32
+ ok: false,
33
+ reason: "manual-no-winner"
34
+ };
35
+ return {
36
+ ok: true,
37
+ resolveOutcome: strategyOf(poll) !== "manual"
38
+ };
39
+ };
40
+ /**
41
+ * Authorize and perform a manual poll close backing `POST /:id/close`. Only an authenticated caller
42
+ * may close (anonymous is always 403, mirroring the other resolve* helpers); the route is a trusted
43
+ * admin action, so the load and write run with `overrideAccess`. Sets `closesAt` to now through
44
+ * `payload.update` so the collection hooks run, then for a non-manual strategy resolves the winners via
45
+ * `resolvePollOutcome` (auto mode; a non-decidable poll simply records none and the read fallback heals
46
+ * it later). A `manual` poll with no winner recorded is refused (400) so closing never strands a poll
47
+ * with no result. Idempotent: an already-closed poll returns 400 rather than re-closing.
48
+ */
49
+ const resolvePollCloseRequest = async (args) => {
50
+ const { payload, formId, isAuthed, pollVotesEnabled, req } = args;
51
+ if (!isAuthed) return {
52
+ status: 403,
53
+ body: { errors: [{ message: "Forbidden" }] }
54
+ };
55
+ if (formId == null) return {
56
+ status: 400,
57
+ body: { errors: [{ message: "Missing form id" }] }
58
+ };
59
+ const form = await payload.findByID({
60
+ collection: FORMS_SLUG,
61
+ id: formId,
62
+ depth: 0,
63
+ overrideAccess: true,
64
+ req
65
+ }).catch(() => null);
66
+ if (!form) return {
67
+ status: 404,
68
+ body: { errors: [{ message: "Not found" }] }
69
+ };
70
+ const plan = planPollClose(form);
71
+ if (!plan.ok) {
72
+ if (plan.reason === "manual-no-winner") return {
73
+ status: 400,
74
+ body: { errors: [{ message: asTranslate(req.t)(keys.pollCloseManualNoWinner) }] }
75
+ };
76
+ return {
77
+ status: 400,
78
+ body: { errors: [{ message: plan.reason === "already-closed" ? "Poll already closed" : "Not a poll" }] }
79
+ };
80
+ }
81
+ const closesAt = (/* @__PURE__ */ new Date()).toISOString();
82
+ await payload.update({
83
+ collection: FORMS_SLUG,
84
+ id: formId,
85
+ data: { poll: { closesAt } },
86
+ depth: 0,
87
+ overrideAccess: true,
88
+ req
89
+ });
90
+ return {
91
+ status: 200,
92
+ body: {
93
+ closesAt,
94
+ winningValues: plan.resolveOutcome ? await resolvePollOutcome({
95
+ payload,
96
+ formId,
97
+ pollVotesEnabled,
98
+ req
99
+ }) : winnersOf(pollConfigOf(form.poll) ?? {})
100
+ }
101
+ };
102
+ };
103
+ //#endregion
104
+ export { resolvePollCloseRequest };
105
+
106
+ //# sourceMappingURL=resolvePollCloseRequest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolvePollCloseRequest.js","names":[],"sources":["../../src/poll/resolvePollCloseRequest.ts"],"sourcesContent":["import type { Payload, PayloadRequest } from 'payload'\nimport { FORMS_SLUG } from '../collections/forms'\nimport { isPollClosed, type PollConfigLike, pollConfigOf } from '../form/pollState'\nimport { keys } from '../translations/keys'\nimport { asTranslate } from '../translations/server'\nimport { resolvePollOutcome } from './resolvePollOutcome'\n\n/** The recorded winning set as non-empty strings; empty means no winner has been set yet. */\nconst winnersOf = (poll: PollConfigLike): string[] => {\n\tconst winners = poll.outcome?.winningValues\n\tif (!Array.isArray(winners)) {\n\t\treturn []\n\t}\n\treturn winners.filter((value): value is string => typeof value === 'string' && value.length > 0)\n}\n\n/** The selected outcome strategy slug; an absent or empty `type` is `manual`. */\nconst strategyOf = (poll: PollConfigLike): string =>\n\ttypeof poll.type === 'string' && poll.type.length > 0 ? poll.type : 'manual'\n\n/** The slice of a loaded form the close planner reads. */\nexport type PollCloseFormLike = { pollEnabled?: boolean | null; poll?: unknown }\n\nexport type PollClosePlan =\n\t| { ok: false; reason: 'already-closed' | 'manual-no-winner' | 'not-poll' }\n\t| { ok: true; resolveOutcome: boolean }\n\n/**\n * Decide what closing a poll now should do, purely from a loaded form so the branch logic is testable\n * without a boot. `manual` requires a winner to already be recorded (closing only stamps the time);\n * `mostVoted`, `source`, and any host strategy auto-resolve on close. Refuses a non-poll form and an\n * already-closed poll (idempotency), so the request helper performs no write unless this returns `ok`.\n */\nexport const planPollClose = (form: PollCloseFormLike): PollClosePlan => {\n\tconst poll = pollConfigOf(form.poll)\n\tif (form.pollEnabled !== true || !poll) {\n\t\treturn { ok: false, reason: 'not-poll' }\n\t}\n\tif (isPollClosed(poll)) {\n\t\treturn { ok: false, reason: 'already-closed' }\n\t}\n\tif (strategyOf(poll) === 'manual' && winnersOf(poll).length === 0) {\n\t\treturn { ok: false, reason: 'manual-no-winner' }\n\t}\n\treturn { ok: true, resolveOutcome: strategyOf(poll) !== 'manual' }\n}\n\nexport type ResolvePollCloseRequestArgs = {\n\tpayload: Payload\n\tformId: number | string | undefined\n\t/** Whether the caller is authenticated (an admin/user). */\n\tisAuthed: boolean\n\t/** Whether the hidden tally store backs the outcome aggregation (see `resolvePollOutcome`). */\n\tpollVotesEnabled?: boolean\n\treq: PayloadRequest\n}\n\nexport type ResolvePollCloseRequestResult = {\n\tstatus: number\n\tbody: { closesAt: string; winningValues: string[] } | { errors: { message: string }[] }\n}\n\n/**\n * Authorize and perform a manual poll close backing `POST /:id/close`. Only an authenticated caller\n * may close (anonymous is always 403, mirroring the other resolve* helpers); the route is a trusted\n * admin action, so the load and write run with `overrideAccess`. Sets `closesAt` to now through\n * `payload.update` so the collection hooks run, then for a non-manual strategy resolves the winners via\n * `resolvePollOutcome` (auto mode; a non-decidable poll simply records none and the read fallback heals\n * it later). A `manual` poll with no winner recorded is refused (400) so closing never strands a poll\n * with no result. Idempotent: an already-closed poll returns 400 rather than re-closing.\n */\nexport const resolvePollCloseRequest = async (\n\targs: ResolvePollCloseRequestArgs\n): Promise<ResolvePollCloseRequestResult> => {\n\tconst { payload, formId, isAuthed, pollVotesEnabled, req } = args\n\tif (!isAuthed) {\n\t\treturn { status: 403, body: { errors: [{ message: 'Forbidden' }] } }\n\t}\n\tif (formId == null) {\n\t\treturn { status: 400, body: { errors: [{ message: 'Missing form id' }] } }\n\t}\n\tconst form = await payload\n\t\t.findByID({ collection: FORMS_SLUG, id: formId, depth: 0, overrideAccess: true, req })\n\t\t.catch(() => null)\n\tif (!form) {\n\t\treturn { status: 404, body: { errors: [{ message: 'Not found' }] } }\n\t}\n\n\tconst plan = planPollClose(form as PollCloseFormLike)\n\tif (!plan.ok) {\n\t\tif (plan.reason === 'manual-no-winner') {\n\t\t\treturn {\n\t\t\t\tstatus: 400,\n\t\t\t\tbody: { errors: [{ message: asTranslate(req.t)(keys.pollCloseManualNoWinner) }] },\n\t\t\t}\n\t\t}\n\t\tconst message = plan.reason === 'already-closed' ? 'Poll already closed' : 'Not a poll'\n\t\treturn { status: 400, body: { errors: [{ message }] } }\n\t}\n\n\tconst closesAt = new Date().toISOString()\n\tawait payload.update({\n\t\tcollection: FORMS_SLUG,\n\t\tid: formId,\n\t\tdata: { poll: { closesAt } },\n\t\tdepth: 0,\n\t\toverrideAccess: true,\n\t\treq,\n\t})\n\n\tconst winningValues = plan.resolveOutcome\n\t\t? await resolvePollOutcome({ payload, formId, pollVotesEnabled, req })\n\t\t: winnersOf(pollConfigOf(form.poll) ?? {})\n\treturn { status: 200, body: { closesAt, winningValues } }\n}\n"],"mappings":";;;;;;;AAQA,MAAM,aAAa,SAAmC;CACrD,MAAM,UAAU,KAAK,SAAS;CAC9B,IAAI,CAAC,MAAM,QAAQ,OAAO,GACzB,OAAO,CAAC;CAET,OAAO,QAAQ,QAAQ,UAA2B,OAAO,UAAU,YAAY,MAAM,SAAS,CAAC;AAChG;;AAGA,MAAM,cAAc,SACnB,OAAO,KAAK,SAAS,YAAY,KAAK,KAAK,SAAS,IAAI,KAAK,OAAO;;;;;;;AAerE,MAAa,iBAAiB,SAA2C;CACxE,MAAM,OAAO,aAAa,KAAK,IAAI;CACnC,IAAI,KAAK,gBAAgB,QAAQ,CAAC,MACjC,OAAO;EAAE,IAAI;EAAO,QAAQ;CAAW;CAExC,IAAI,aAAa,IAAI,GACpB,OAAO;EAAE,IAAI;EAAO,QAAQ;CAAiB;CAE9C,IAAI,WAAW,IAAI,MAAM,YAAY,UAAU,IAAI,EAAE,WAAW,GAC/D,OAAO;EAAE,IAAI;EAAO,QAAQ;CAAmB;CAEhD,OAAO;EAAE,IAAI;EAAM,gBAAgB,WAAW,IAAI,MAAM;CAAS;AAClE;;;;;;;;;;AA0BA,MAAa,0BAA0B,OACtC,SAC4C;CAC5C,MAAM,EAAE,SAAS,QAAQ,UAAU,kBAAkB,QAAQ;CAC7D,IAAI,CAAC,UACJ,OAAO;EAAE,QAAQ;EAAK,MAAM,EAAE,QAAQ,CAAC,EAAE,SAAS,YAAY,CAAC,EAAE;CAAE;CAEpE,IAAI,UAAU,MACb,OAAO;EAAE,QAAQ;EAAK,MAAM,EAAE,QAAQ,CAAC,EAAE,SAAS,kBAAkB,CAAC,EAAE;CAAE;CAE1E,MAAM,OAAO,MAAM,QACjB,SAAS;EAAE,YAAY;EAAY,IAAI;EAAQ,OAAO;EAAG,gBAAgB;EAAM;CAAI,CAAC,EACpF,YAAY,IAAI;CAClB,IAAI,CAAC,MACJ,OAAO;EAAE,QAAQ;EAAK,MAAM,EAAE,QAAQ,CAAC,EAAE,SAAS,YAAY,CAAC,EAAE;CAAE;CAGpE,MAAM,OAAO,cAAc,IAAyB;CACpD,IAAI,CAAC,KAAK,IAAI;EACb,IAAI,KAAK,WAAW,oBACnB,OAAO;GACN,QAAQ;GACR,MAAM,EAAE,QAAQ,CAAC,EAAE,SAAS,YAAY,IAAI,CAAC,EAAE,KAAK,uBAAuB,EAAE,CAAC,EAAE;EACjF;EAGD,OAAO;GAAE,QAAQ;GAAK,MAAM,EAAE,QAAQ,CAAC,EAAE,SADzB,KAAK,WAAW,mBAAmB,wBAAwB,aAC1B,CAAC,EAAE;EAAE;CACvD;CAEA,MAAM,4BAAW,IAAI,KAAK,GAAE,YAAY;CACxC,MAAM,QAAQ,OAAO;EACpB,YAAY;EACZ,IAAI;EACJ,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE;EAC3B,OAAO;EACP,gBAAgB;EAChB;CACD,CAAC;CAKD,OAAO;EAAE,QAAQ;EAAK,MAAM;GAAE;GAAU,eAHlB,KAAK,iBACxB,MAAM,mBAAmB;IAAE;IAAS;IAAQ;IAAkB;GAAI,CAAC,IACnE,UAAU,aAAa,KAAK,IAAI,KAAK,CAAC,CAAC;EACY;CAAE;AACzD"}
@@ -0,0 +1,29 @@
1
+ import { PollOption } from "./definePollOptionSource.js";
2
+ import { PollOptionSourceRegistry } from "./registry.js";
3
+ import { Payload, PayloadRequest } from "payload";
4
+
5
+ //#region src/poll/resolvePollOptions.d.ts
6
+ type ResolvePollOptionsArgs = {
7
+ payload: Payload;
8
+ req?: PayloadRequest; /** A loaded forms document; its top-level `pollEnabled` flag and `poll` config drive resolution. */
9
+ form: {
10
+ id: number | string;
11
+ title?: string | null;
12
+ pollEnabled?: boolean | null;
13
+ poll?: unknown;
14
+ }; /** Registry override for plugin-internal callers; defaults to the registry the plugin stashed on the config. */
15
+ sources?: PollOptionSourceRegistry;
16
+ };
17
+ /**
18
+ * Resolve a poll-enabled form's choice options from its configured option source (plugin option
19
+ * `poll.sources`). Returns `undefined` when the form is not poll-enabled or has no `optionSource`
20
+ * set, so hand-authored options render unchanged. Hosts call this server-side and hand the result
21
+ * to `toFormDocument(doc, { pollOptions })`; submission validation calls it too, making the
22
+ * resolved values the only accepted answers. Throws when the configured source type is not
23
+ * registered or its `resolve` fails; results are cached per request (keyed by form id) when a
24
+ * `req` is provided.
25
+ */
26
+ declare const resolvePollOptions: (args: ResolvePollOptionsArgs) => Promise<PollOption[] | undefined>;
27
+ //#endregion
28
+ export { ResolvePollOptionsArgs, resolvePollOptions };
29
+ //# sourceMappingURL=resolvePollOptions.d.ts.map
@@ -0,0 +1,52 @@
1
+ import { customStateOf, stashCustomState } from "../plugin/customState.js";
2
+ import { pollConfigOf } from "../form/pollState.js";
3
+ //#region src/poll/resolvePollOptions.ts
4
+ /** Store the resolved registry on the config so `resolvePollOptions` can find it via `payload.config`. */
5
+ const stashPollOptionSources = (custom, registry) => stashCustomState(custom, { pollOptionSources: registry });
6
+ const pollOptionSourcesOf = (payload) => customStateOf(payload).pollOptionSources ?? /* @__PURE__ */ new Map();
7
+ const CACHE_KEY = "formBuilderPollOptionsCache";
8
+ const cacheOf = (req) => {
9
+ if (!req?.context) return;
10
+ const existing = req.context[CACHE_KEY];
11
+ if (existing instanceof Map) return existing;
12
+ const created = /* @__PURE__ */ new Map();
13
+ req.context[CACHE_KEY] = created;
14
+ return created;
15
+ };
16
+ /**
17
+ * Resolve a poll-enabled form's choice options from its configured option source (plugin option
18
+ * `poll.sources`). Returns `undefined` when the form is not poll-enabled or has no `optionSource`
19
+ * set, so hand-authored options render unchanged. Hosts call this server-side and hand the result
20
+ * to `toFormDocument(doc, { pollOptions })`; submission validation calls it too, making the
21
+ * resolved values the only accepted answers. Throws when the configured source type is not
22
+ * registered or its `resolve` fails; results are cached per request (keyed by form id) when a
23
+ * `req` is provided.
24
+ */
25
+ const resolvePollOptions = async (args) => {
26
+ const { payload, req, form, sources } = args;
27
+ const poll = pollConfigOf(form.poll);
28
+ const optionSource = typeof poll?.optionSource === "string" ? poll.optionSource : void 0;
29
+ if (form.pollEnabled !== true || !poll || !optionSource) return;
30
+ const source = (sources ?? pollOptionSourcesOf(payload)).get(optionSource);
31
+ if (!source) throw new Error(`Poll option source "${optionSource}" is not registered. Register it via the plugin's poll.sources option.`);
32
+ const cache = cacheOf(req);
33
+ const cacheKey = String(form.id);
34
+ const cached = cache?.get(cacheKey);
35
+ if (cached) return cached;
36
+ const config = poll.sourceConfig != null && typeof poll.sourceConfig === "object" ? poll.sourceConfig : {};
37
+ const options = await source.resolve({
38
+ config,
39
+ form: {
40
+ id: form.id,
41
+ title: typeof form.title === "string" ? form.title : void 0
42
+ },
43
+ payload,
44
+ req
45
+ });
46
+ cache?.set(cacheKey, options);
47
+ return options;
48
+ };
49
+ //#endregion
50
+ export { pollOptionSourcesOf, resolvePollOptions, stashPollOptionSources };
51
+
52
+ //# sourceMappingURL=resolvePollOptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolvePollOptions.js","names":[],"sources":["../../src/poll/resolvePollOptions.ts"],"sourcesContent":["import type { Payload, PayloadRequest } from 'payload'\nimport { pollConfigOf } from '../form/pollState'\nimport { customStateOf, stashCustomState } from '../plugin/customState'\nimport type { PollOption } from './definePollOptionSource'\nimport type { PollOptionSourceRegistry } from './registry'\n\ntype PollCustomState = { pollOptionSources: PollOptionSourceRegistry }\n\n/** Store the resolved registry on the config so `resolvePollOptions` can find it via `payload.config`. */\nexport const stashPollOptionSources = (\n\tcustom: Record<string, unknown> | undefined,\n\tregistry: PollOptionSourceRegistry\n): Record<string, unknown> =>\n\tstashCustomState<PollCustomState>(custom, { pollOptionSources: registry })\n\nexport const pollOptionSourcesOf = (payload: Payload): PollOptionSourceRegistry =>\n\tcustomStateOf<PollCustomState>(payload).pollOptionSources ?? new Map()\n\nconst CACHE_KEY = 'formBuilderPollOptionsCache'\n\ntype OptionsCache = Map<string, PollOption[]>\n\nconst cacheOf = (req: PayloadRequest | undefined): OptionsCache | 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 OptionsCache\n\t}\n\tconst created: OptionsCache = new Map()\n\treq.context[CACHE_KEY] = created\n\treturn created\n}\n\nexport type ResolvePollOptionsArgs = {\n\tpayload: Payload\n\treq?: PayloadRequest\n\t/** A loaded forms document; its top-level `pollEnabled` flag and `poll` config drive resolution. */\n\tform: { id: number | string; title?: string | null; pollEnabled?: boolean | null; poll?: unknown }\n\t/** Registry override for plugin-internal callers; defaults to the registry the plugin stashed on the config. */\n\tsources?: PollOptionSourceRegistry\n}\n\n/**\n * Resolve a poll-enabled form's choice options from its configured option source (plugin option\n * `poll.sources`). Returns `undefined` when the form is not poll-enabled or has no `optionSource`\n * set, so hand-authored options render unchanged. Hosts call this server-side and hand the result\n * to `toFormDocument(doc, { pollOptions })`; submission validation calls it too, making the\n * resolved values the only accepted answers. Throws when the configured source type is not\n * registered or its `resolve` fails; results are cached per request (keyed by form id) when a\n * `req` is provided.\n */\nexport const resolvePollOptions = async (\n\targs: ResolvePollOptionsArgs\n): Promise<PollOption[] | undefined> => {\n\tconst { payload, req, form, sources } = args\n\tconst poll = pollConfigOf(form.poll)\n\tconst optionSource = typeof poll?.optionSource === 'string' ? poll.optionSource : undefined\n\tif (form.pollEnabled !== true || !poll || !optionSource) {\n\t\treturn undefined\n\t}\n\tconst source = (sources ?? pollOptionSourcesOf(payload)).get(optionSource)\n\tif (!source) {\n\t\tthrow new Error(\n\t\t\t`Poll option source \"${optionSource}\" is not registered. Register it via the plugin's poll.sources option.`\n\t\t)\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 config =\n\t\tpoll.sourceConfig != null && typeof poll.sourceConfig === 'object'\n\t\t\t? (poll.sourceConfig as Record<string, unknown>)\n\t\t\t: {}\n\tconst options = await source.resolve({\n\t\tconfig,\n\t\tform: { id: form.id, title: typeof form.title === 'string' ? form.title : undefined },\n\t\tpayload,\n\t\treq,\n\t})\n\tcache?.set(cacheKey, options)\n\treturn options\n}\n"],"mappings":";;;;AASA,MAAa,0BACZ,QACA,aAEA,iBAAkC,QAAQ,EAAE,mBAAmB,SAAS,CAAC;AAE1E,MAAa,uBAAuB,YACnC,cAA+B,OAAO,EAAE,qCAAqB,IAAI,IAAI;AAEtE,MAAM,YAAY;AAIlB,MAAM,WAAW,QAA8D;CAC9E,IAAI,CAAC,KAAK,SACT;CAED,MAAM,WAAW,IAAI,QAAQ;CAC7B,IAAI,oBAAoB,KACvB,OAAO;CAER,MAAM,0BAAwB,IAAI,IAAI;CACtC,IAAI,QAAQ,aAAa;CACzB,OAAO;AACR;;;;;;;;;;AAoBA,MAAa,qBAAqB,OACjC,SACuC;CACvC,MAAM,EAAE,SAAS,KAAK,MAAM,YAAY;CACxC,MAAM,OAAO,aAAa,KAAK,IAAI;CACnC,MAAM,eAAe,OAAO,MAAM,iBAAiB,WAAW,KAAK,eAAe,KAAA;CAClF,IAAI,KAAK,gBAAgB,QAAQ,CAAC,QAAQ,CAAC,cAC1C;CAED,MAAM,UAAU,WAAW,oBAAoB,OAAO,GAAG,IAAI,YAAY;CACzE,IAAI,CAAC,QACJ,MAAM,IAAI,MACT,uBAAuB,aAAa,uEACrC;CAED,MAAM,QAAQ,QAAQ,GAAG;CACzB,MAAM,WAAW,OAAO,KAAK,EAAE;CAC/B,MAAM,SAAS,OAAO,IAAI,QAAQ;CAClC,IAAI,QACH,OAAO;CAER,MAAM,SACL,KAAK,gBAAgB,QAAQ,OAAO,KAAK,iBAAiB,WACtD,KAAK,eACN,CAAC;CACL,MAAM,UAAU,MAAM,OAAO,QAAQ;EACpC;EACA,MAAM;GAAE,IAAI,KAAK;GAAI,OAAO,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,KAAA;EAAU;EACpF;EACA;CACD,CAAC;CACD,OAAO,IAAI,UAAU,OAAO;CAC5B,OAAO;AACR"}
@@ -0,0 +1,50 @@
1
+ import { resolveEffectivePollOptions } from "./effectivePollOptions.js";
2
+ import { FORMS_SLUG } from "../collections/forms.js";
3
+ //#region src/poll/resolvePollOptionsRequest.ts
4
+ /**
5
+ * Authorize and resolve the `GET /:id/poll-options` request backing the admin winner select:
6
+ * authenticated callers get the poll's effective options (source-resolved or authored, exactly the
7
+ * set outcome validation accepts), anonymous callers are always refused. Statuses mirror the
8
+ * results endpoint: 400 missing id, 403 unauthenticated, 404 unknown form, 503 when the option
9
+ * source fails (fail closed).
10
+ */
11
+ const resolvePollOptionsRequest = async (args) => {
12
+ const { payload, formId, isAuthed, req } = 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 resolveEffectivePollOptions({
35
+ payload,
36
+ req,
37
+ form
38
+ }) }
39
+ };
40
+ } catch {
41
+ return {
42
+ status: 503,
43
+ body: { errors: [{ message: "Poll options unavailable" }] }
44
+ };
45
+ }
46
+ };
47
+ //#endregion
48
+ export { resolvePollOptionsRequest };
49
+
50
+ //# sourceMappingURL=resolvePollOptionsRequest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolvePollOptionsRequest.js","names":[],"sources":["../../src/poll/resolvePollOptionsRequest.ts"],"sourcesContent":["import type { Payload, PayloadRequest } from 'payload'\nimport { FORMS_SLUG } from '../collections/forms'\nimport type { PollOption } from './definePollOptionSource'\nimport { resolveEffectivePollOptions } from './effectivePollOptions'\n\nexport type ResolvePollOptionsRequestArgs = {\n\tpayload: Payload\n\tformId: number | string | undefined\n\t/** Whether the caller is authenticated (an admin/user). */\n\tisAuthed: boolean\n\treq?: PayloadRequest\n}\n\nexport type ResolvePollOptionsRequestResult = {\n\tstatus: number\n\tbody: { options: PollOption[] } | { errors: { message: string }[] }\n}\n\n/**\n * Authorize and resolve the `GET /:id/poll-options` request backing the admin winner select:\n * authenticated callers get the poll's effective options (source-resolved or authored, exactly the\n * set outcome validation accepts), anonymous callers are always refused. Statuses mirror the\n * results endpoint: 400 missing id, 403 unauthenticated, 404 unknown form, 503 when the option\n * source fails (fail closed).\n */\nexport const resolvePollOptionsRequest = async (\n\targs: ResolvePollOptionsRequestArgs\n): Promise<ResolvePollOptionsRequestResult> => {\n\tconst { payload, formId, isAuthed, req } = args\n\tif (!isAuthed) {\n\t\treturn { status: 403, body: { errors: [{ message: 'Forbidden' }] } }\n\t}\n\tif (formId == null) {\n\t\treturn { status: 400, body: { errors: [{ message: 'Missing form id' }] } }\n\t}\n\t// Load under the caller's own read access (no overrideAccess): a tenant-scoped `forms.access.read`\n\t// then refuses a cross-tenant form id (null -> 404), so an authed user cannot read another tenant's\n\t// poll options.\n\tconst form = await payload\n\t\t.findByID({ collection: FORMS_SLUG, id: formId, depth: 0, req })\n\t\t.catch(() => null)\n\tif (!form) {\n\t\treturn { status: 404, body: { errors: [{ message: 'Not found' }] } }\n\t}\n\ttry {\n\t\tconst options = await resolveEffectivePollOptions({ payload, req, form })\n\t\treturn { status: 200, body: { options } }\n\t} catch {\n\t\treturn { status: 503, body: { errors: [{ message: 'Poll options unavailable' }] } }\n\t}\n}\n"],"mappings":";;;;;;;;;;AAyBA,MAAa,4BAA4B,OACxC,SAC8C;CAC9C,MAAM,EAAE,SAAS,QAAQ,UAAU,QAAQ;CAC3C,IAAI,CAAC,UACJ,OAAO;EAAE,QAAQ;EAAK,MAAM,EAAE,QAAQ,CAAC,EAAE,SAAS,YAAY,CAAC,EAAE;CAAE;CAEpE,IAAI,UAAU,MACb,OAAO;EAAE,QAAQ;EAAK,MAAM,EAAE,QAAQ,CAAC,EAAE,SAAS,kBAAkB,CAAC,EAAE;CAAE;CAK1E,MAAM,OAAO,MAAM,QACjB,SAAS;EAAE,YAAY;EAAY,IAAI;EAAQ,OAAO;EAAG;CAAI,CAAC,EAC9D,YAAY,IAAI;CAClB,IAAI,CAAC,MACJ,OAAO;EAAE,QAAQ;EAAK,MAAM,EAAE,QAAQ,CAAC,EAAE,SAAS,YAAY,CAAC,EAAE;CAAE;CAEpE,IAAI;EAEH,OAAO;GAAE,QAAQ;GAAK,MAAM,EAAE,SAAA,MADR,4BAA4B;IAAE;IAAS;IAAK;GAAK,CAAC,EAClC;EAAE;CACzC,QAAQ;EACP,OAAO;GAAE,QAAQ;GAAK,MAAM,EAAE,QAAQ,CAAC,EAAE,SAAS,2BAA2B,CAAC,EAAE;EAAE;CACnF;AACD"}
@@ -0,0 +1,40 @@
1
+ import { Payload, PayloadRequest } from "payload";
2
+
3
+ //#region src/poll/resolvePollOutcome.d.ts
4
+ type ResolvePollOutcomeArgs = {
5
+ payload: Payload;
6
+ formId: number | string;
7
+ /**
8
+ * The winning set: stable option values, each matching one of the poll's choice values (the
9
+ * host's contract with `PollOption.value`). Pass more than one for a tie, an empty array to clear
10
+ * the outcome. Omit to auto-resolve via the poll's selected outcome strategy (`poll.type`).
11
+ */
12
+ winningValues?: string[];
13
+ /**
14
+ * Whether the hidden tally store backs the auto-resolve aggregation (`mostVoted` and any host
15
+ * strategy that calls `aggregate()`). False keeps the submission scan, so persist-off forms
16
+ * only resolve correctly with the store enabled.
17
+ */
18
+ pollVotesEnabled?: boolean;
19
+ req?: PayloadRequest;
20
+ };
21
+ /**
22
+ * Record a poll's final outcome server-side, in one of two modes:
23
+ * - explicit: pass `winningValues` when host code already knows the winner(s); more than one is a
24
+ * tie, and an empty array clears the outcome;
25
+ * - auto: omit it and the poll's selected outcome strategy (`poll.type`, from the `poll.types`
26
+ * registry, defaulting to `manual`) resolves the winners. `manual` is a no-op; `mostVoted` reads
27
+ * the aggregated results field; `source` delegates to the option source. A strategy that is not
28
+ * yet decidable (or `manual`) writes nothing and this returns an empty set, so auto mode is safe
29
+ * to call repeatedly from the close job and the read fallback.
30
+ *
31
+ * Every write runs through `payload.update` with `overrideAccess`, so the forms collection hook
32
+ * validates each value against the poll's effective options and owns the `poll.outcome.resolvedAt`
33
+ * stamp in both modes (auto-resolved winners are validated exactly as hand-picked ones). Throws only
34
+ * when the form does not exist or is not poll-enabled. Returns the recorded winning set (empty when
35
+ * auto mode did not decide).
36
+ */
37
+ declare const resolvePollOutcome: (args: ResolvePollOutcomeArgs) => Promise<string[]>;
38
+ //#endregion
39
+ export { ResolvePollOutcomeArgs, resolvePollOutcome };
40
+ //# sourceMappingURL=resolvePollOutcome.d.ts.map