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

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 (406) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/README.md +45 -1402
  3. package/dist/actions/buildActionBlocks.js +19 -0
  4. package/dist/actions/buildActionBlocks.js.map +1 -0
  5. package/dist/actions/builtin/confirmation.js +49 -0
  6. package/dist/actions/builtin/confirmation.js.map +1 -0
  7. package/dist/actions/builtin/emailTeam.js +46 -0
  8. package/dist/actions/builtin/emailTeam.js.map +1 -0
  9. package/dist/actions/builtin/index.d.ts +7 -0
  10. package/dist/actions/builtin/index.js +13 -0
  11. package/dist/actions/builtin/index.js.map +1 -0
  12. package/dist/actions/builtin/signedWebhook.js +49 -0
  13. package/dist/actions/builtin/signedWebhook.js.map +1 -0
  14. package/dist/actions/defineAction.d.ts +36 -0
  15. package/dist/actions/defineAction.js +6 -0
  16. package/dist/actions/defineAction.js.map +1 -0
  17. package/dist/actions/dispatch.js +48 -0
  18. package/dist/actions/dispatch.js.map +1 -0
  19. package/dist/actions/registry.d.ts +16 -0
  20. package/dist/actions/registry.js +16 -0
  21. package/dist/actions/registry.js.map +1 -0
  22. package/dist/actions/runActions.d.ts +9 -0
  23. package/dist/actions/runActions.js +34 -0
  24. package/dist/actions/runActions.js.map +1 -0
  25. package/dist/actions/sign.d.ts +7 -0
  26. package/dist/actions/sign.js +9 -0
  27. package/dist/actions/sign.js.map +1 -0
  28. package/dist/actions/task.js +82 -0
  29. package/dist/actions/task.js.map +1 -0
  30. package/dist/aggregation/aggregateResponses.d.ts +31 -0
  31. package/dist/aggregation/aggregateResponses.js +86 -0
  32. package/dist/aggregation/aggregateResponses.js.map +1 -0
  33. package/dist/aggregation/aggregateRows.d.ts +10 -0
  34. package/dist/aggregation/aggregateRows.js +64 -0
  35. package/dist/aggregation/aggregateRows.js.map +1 -0
  36. package/dist/aggregation/resolveResultsRequest.d.ts +32 -0
  37. package/dist/aggregation/resolveResultsRequest.js +56 -0
  38. package/dist/aggregation/resolveResultsRequest.js.map +1 -0
  39. package/dist/aggregation/types.d.ts +39 -0
  40. package/dist/calc/computeCalcFields.d.ts +15 -0
  41. package/dist/calc/computeCalcFields.js +27 -0
  42. package/dist/calc/computeCalcFields.js.map +1 -0
  43. package/dist/calc/evaluate.d.ts +8 -0
  44. package/dist/calc/evaluate.js +59 -0
  45. package/dist/calc/evaluate.js.map +1 -0
  46. package/dist/calc/normalizeCalc.d.ts +8 -0
  47. package/dist/calc/normalizeCalc.js +100 -0
  48. package/dist/calc/normalizeCalc.js.map +1 -0
  49. package/dist/calc/types.d.ts +28 -0
  50. package/dist/client/ConditionBuilder.js +121 -0
  51. package/dist/client/ConditionBuilder.js.map +1 -0
  52. package/dist/client/ConditionRow.js +150 -0
  53. package/dist/client/ConditionRow.js.map +1 -0
  54. package/dist/client/FlowBuilder.d.ts +15 -0
  55. package/dist/client/FlowBuilder.js +408 -0
  56. package/dist/client/FlowBuilder.js.map +1 -0
  57. package/dist/client/FormConditionField.d.ts +21 -0
  58. package/dist/client/FormConditionField.js +33 -0
  59. package/dist/client/FormConditionField.js.map +1 -0
  60. package/dist/client/synthesizeClientField.js +46 -0
  61. package/dist/client/synthesizeClientField.js.map +1 -0
  62. package/dist/collections/formSubmissions.js +157 -0
  63. package/dist/collections/formSubmissions.js.map +1 -0
  64. package/dist/collections/forms.js +198 -0
  65. package/dist/collections/forms.js.map +1 -0
  66. package/dist/collections/uploads.d.ts +30 -0
  67. package/dist/collections/uploads.js +55 -0
  68. package/dist/collections/uploads.js.map +1 -0
  69. package/dist/conditions/conditionType.js +14 -0
  70. package/dist/conditions/conditionType.js.map +1 -0
  71. package/dist/conditions/evaluate.d.ts +17 -0
  72. package/dist/conditions/evaluate.js +94 -0
  73. package/dist/conditions/evaluate.js.map +1 -0
  74. package/dist/conditions/fieldTypes.d.ts +9 -0
  75. package/dist/{fieldTypes-CzhhJXjg.js → conditions/fieldTypes.js} +2 -2
  76. package/dist/conditions/fieldTypes.js.map +1 -0
  77. package/dist/conditions/normalizeConditions.js +47 -0
  78. package/dist/conditions/normalizeConditions.js.map +1 -0
  79. package/dist/conditions/types.d.ts +8 -0
  80. package/dist/consent/buildConsentSourceConfig.js +49 -0
  81. package/dist/consent/buildConsentSourceConfig.js.map +1 -0
  82. package/dist/consent/builtin/index.d.ts +7 -0
  83. package/dist/consent/builtin/index.js +11 -0
  84. package/dist/consent/builtin/index.js.map +1 -0
  85. package/dist/consent/builtin/pageReference.js +75 -0
  86. package/dist/consent/builtin/pageReference.js.map +1 -0
  87. package/dist/consent/builtin/static.js +44 -0
  88. package/dist/consent/builtin/static.js.map +1 -0
  89. package/dist/consent/captureConsent.d.ts +28 -0
  90. package/dist/consent/captureConsent.js +26 -0
  91. package/dist/consent/captureConsent.js.map +1 -0
  92. package/dist/consent/defineConsentSource.d.ts +35 -0
  93. package/dist/consent/defineConsentSource.js +6 -0
  94. package/dist/consent/defineConsentSource.js.map +1 -0
  95. package/dist/consent/registry.d.ts +16 -0
  96. package/dist/consent/registry.js +16 -0
  97. package/dist/consent/registry.js.map +1 -0
  98. package/dist/consent/resolveConsentLinks.d.ts +19 -0
  99. package/dist/consent/resolveConsentLinks.js +26 -0
  100. package/dist/consent/resolveConsentLinks.js.map +1 -0
  101. package/dist/consent/resolvePublishedVersionRef.d.ts +17 -0
  102. package/dist/consent/resolvePublishedVersionRef.js +27 -0
  103. package/dist/consent/resolvePublishedVersionRef.js.map +1 -0
  104. package/dist/events/noopSink.js +6 -0
  105. package/dist/events/noopSink.js.map +1 -0
  106. package/dist/events/resolveEventSink.js +8 -0
  107. package/dist/events/resolveEventSink.js.map +1 -0
  108. package/dist/events/types.d.ts +31 -0
  109. package/dist/exports/client.d.ts +3 -21
  110. package/dist/exports/client.js +3 -319
  111. package/dist/exports/i18n.d.ts +3 -138
  112. package/dist/exports/i18n.js +2 -2
  113. package/dist/exports/react.d.ts +45 -550
  114. package/dist/exports/react.js +39 -1563
  115. package/dist/exports/rsc.d.ts +2 -16
  116. package/dist/exports/rsc.js +1 -54
  117. package/dist/exports/types.d.ts +28 -5
  118. package/dist/fields/buildFieldBlocks.js +60 -0
  119. package/dist/fields/buildFieldBlocks.js.map +1 -0
  120. package/dist/fields/builtin/calculation.js +24 -0
  121. package/dist/fields/builtin/calculation.js.map +1 -0
  122. package/dist/fields/builtin/checkbox.js +13 -0
  123. package/dist/fields/builtin/checkbox.js.map +1 -0
  124. package/dist/fields/builtin/consent.js +32 -0
  125. package/dist/fields/builtin/consent.js.map +1 -0
  126. package/dist/fields/builtin/email.js +18 -0
  127. package/dist/fields/builtin/email.js.map +1 -0
  128. package/dist/fields/builtin/file.js +40 -0
  129. package/dist/fields/builtin/file.js.map +1 -0
  130. package/dist/fields/builtin/index.js +27 -0
  131. package/dist/fields/builtin/index.js.map +1 -0
  132. package/dist/fields/builtin/number.js +17 -0
  133. package/dist/fields/builtin/number.js.map +1 -0
  134. package/dist/fields/builtin/repeater.js +44 -0
  135. package/dist/fields/builtin/repeater.js.map +1 -0
  136. package/dist/fields/builtin/select.js +44 -0
  137. package/dist/fields/builtin/select.js.map +1 -0
  138. package/dist/fields/builtin/text.js +13 -0
  139. package/dist/fields/builtin/text.js.map +1 -0
  140. package/dist/fields/builtin/textarea.js +13 -0
  141. package/dist/fields/builtin/textarea.js.map +1 -0
  142. package/dist/fields/defineFormField.d.ts +13 -0
  143. package/dist/fields/defineFormField.js +12 -0
  144. package/dist/fields/defineFormField.js.map +1 -0
  145. package/dist/fields/registry.d.ts +10 -0
  146. package/dist/fields/registry.js +24 -0
  147. package/dist/fields/registry.js.map +1 -0
  148. package/dist/fields/sharedConfig.js +89 -0
  149. package/dist/fields/sharedConfig.js.map +1 -0
  150. package/dist/fields/types.d.ts +89 -0
  151. package/dist/flow/engine.d.ts +17 -0
  152. package/dist/flow/engine.js +24 -0
  153. package/dist/flow/engine.js.map +1 -0
  154. package/dist/flow/normalizeFlow.js +35 -0
  155. package/dist/flow/normalizeFlow.js.map +1 -0
  156. package/dist/{types-DsJ_6kGJ.d.ts → flow/types.d.ts} +2 -2
  157. package/dist/index.d.ts +93 -4
  158. package/dist/index.js +43 -1890
  159. package/dist/index.js.map +1 -1
  160. package/dist/plugin/access.js +12 -0
  161. package/dist/plugin/access.js.map +1 -0
  162. package/dist/plugin/collectionOverrides.d.ts +22 -0
  163. package/dist/plugin/registerCollections.js +68 -0
  164. package/dist/plugin/registerCollections.js.map +1 -0
  165. package/dist/plugin/registerTranslations.js +19 -0
  166. package/dist/plugin/registerTranslations.js.map +1 -0
  167. package/dist/prefill/valuesFromSearchParams.d.ts +18 -0
  168. package/dist/prefill/valuesFromSearchParams.js +45 -0
  169. package/dist/prefill/valuesFromSearchParams.js.map +1 -0
  170. package/dist/presentations/defaults.d.ts +33 -0
  171. package/dist/presentations/defaults.js +35 -0
  172. package/dist/presentations/defaults.js.map +1 -0
  173. package/dist/presentations/registry.d.ts +15 -0
  174. package/dist/presentations/registry.js +15 -0
  175. package/dist/presentations/registry.js.map +1 -0
  176. package/dist/presentations/types.d.ts +18 -0
  177. package/dist/react/Form.d.ts +110 -0
  178. package/dist/react/Form.js +499 -0
  179. package/dist/react/Form.js.map +1 -0
  180. package/dist/react/FormContext.d.ts +16 -0
  181. package/dist/react/FormContext.js +14 -0
  182. package/dist/react/FormContext.js.map +1 -0
  183. package/dist/react/FormLayout.d.ts +20 -0
  184. package/dist/react/FormLayout.js +14 -0
  185. package/dist/react/FormLayout.js.map +1 -0
  186. package/dist/react/FormResults.d.ts +25 -0
  187. package/dist/react/FormResults.js +85 -0
  188. package/dist/react/FormResults.js.map +1 -0
  189. package/dist/react/Honeypot.d.ts +22 -0
  190. package/dist/react/Honeypot.js +38 -0
  191. package/dist/react/Honeypot.js.map +1 -0
  192. package/dist/react/Poll.d.ts +32 -0
  193. package/dist/react/Poll.js +77 -0
  194. package/dist/react/Poll.js.map +1 -0
  195. package/dist/react/cn.d.ts +6 -0
  196. package/dist/react/cn.js +8 -0
  197. package/dist/react/cn.js.map +1 -0
  198. package/dist/react/contract.d.ts +32 -0
  199. package/dist/react/contract.js +7 -0
  200. package/dist/react/contract.js.map +1 -0
  201. package/dist/react/events.js +14 -0
  202. package/dist/react/events.js.map +1 -0
  203. package/dist/react/fetchResults.d.ts +25 -0
  204. package/dist/react/fetchResults.js +31 -0
  205. package/dist/react/fetchResults.js.map +1 -0
  206. package/dist/react/presentation/Backdrop.d.ts +18 -0
  207. package/dist/react/presentation/Backdrop.js +14 -0
  208. package/dist/react/presentation/Backdrop.js.map +1 -0
  209. package/dist/react/presentation/DialogSurface.d.ts +35 -0
  210. package/dist/react/presentation/DialogSurface.js +56 -0
  211. package/dist/react/presentation/DialogSurface.js.map +1 -0
  212. package/dist/react/presentation/presentations.d.ts +7 -0
  213. package/dist/react/presentation/presentations.js +32 -0
  214. package/dist/react/presentation/presentations.js.map +1 -0
  215. package/dist/react/presentation/registry.d.ts +11 -0
  216. package/dist/react/presentation/registry.js +12 -0
  217. package/dist/react/presentation/registry.js.map +1 -0
  218. package/dist/react/presentation/types.d.ts +19 -0
  219. package/dist/react/presentation/useDismiss.d.ts +19 -0
  220. package/dist/react/presentation/useDismiss.js +33 -0
  221. package/dist/react/presentation/useDismiss.js.map +1 -0
  222. package/dist/react/presentation/useFocusTrap.d.ts +8 -0
  223. package/dist/react/presentation/useFocusTrap.js +35 -0
  224. package/dist/react/presentation/useFocusTrap.js.map +1 -0
  225. package/dist/react/presentation/useScrollLock.d.ts +6 -0
  226. package/dist/react/presentation/useScrollLock.js +18 -0
  227. package/dist/react/presentation/useScrollLock.js.map +1 -0
  228. package/dist/react/primitives/Checkbox.d.ts +26 -0
  229. package/dist/react/primitives/Checkbox.js +20 -0
  230. package/dist/react/primitives/Checkbox.js.map +1 -0
  231. package/dist/react/primitives/FieldShell.d.ts +31 -0
  232. package/dist/react/primitives/FieldShell.js +51 -0
  233. package/dist/react/primitives/FieldShell.js.map +1 -0
  234. package/dist/react/primitives/Input.d.ts +30 -0
  235. package/dist/react/primitives/Input.js +21 -0
  236. package/dist/react/primitives/Input.js.map +1 -0
  237. package/dist/react/primitives/Select.d.ts +34 -0
  238. package/dist/react/primitives/Select.js +26 -0
  239. package/dist/react/primitives/Select.js.map +1 -0
  240. package/dist/react/primitives/Textarea.d.ts +28 -0
  241. package/dist/react/primitives/Textarea.js +20 -0
  242. package/dist/react/primitives/Textarea.js.map +1 -0
  243. package/dist/react/recall.js +20 -0
  244. package/dist/react/recall.js.map +1 -0
  245. package/dist/react/registry.d.ts +16 -0
  246. package/dist/react/registry.js +16 -0
  247. package/dist/react/registry.js.map +1 -0
  248. package/dist/react/renderers/calculation.js +30 -0
  249. package/dist/react/renderers/calculation.js.map +1 -0
  250. package/dist/react/renderers/checkbox.js +35 -0
  251. package/dist/react/renderers/checkbox.js.map +1 -0
  252. package/dist/react/renderers/consent.js +54 -0
  253. package/dist/react/renderers/consent.js.map +1 -0
  254. package/dist/react/renderers/email.js +37 -0
  255. package/dist/react/renderers/email.js.map +1 -0
  256. package/dist/react/renderers/file.js +92 -0
  257. package/dist/react/renderers/file.js.map +1 -0
  258. package/dist/react/renderers/index.d.ts +8 -0
  259. package/dist/react/renderers/index.js +28 -0
  260. package/dist/react/renderers/index.js.map +1 -0
  261. package/dist/react/renderers/number.js +40 -0
  262. package/dist/react/renderers/number.js.map +1 -0
  263. package/dist/react/renderers/repeater.js +113 -0
  264. package/dist/react/renderers/repeater.js.map +1 -0
  265. package/dist/react/renderers/select.js +38 -0
  266. package/dist/react/renderers/select.js.map +1 -0
  267. package/dist/react/renderers/text.js +37 -0
  268. package/dist/react/renderers/text.js.map +1 -0
  269. package/dist/react/renderers/textarea.js +36 -0
  270. package/dist/react/renderers/textarea.js.map +1 -0
  271. package/dist/react/resolveForm.js +16 -0
  272. package/dist/react/resolveForm.js.map +1 -0
  273. package/dist/react/state.d.ts +15 -0
  274. package/dist/react/state.js +70 -0
  275. package/dist/react/state.js.map +1 -0
  276. package/dist/react/submitForm.d.ts +31 -0
  277. package/dist/react/submitForm.js +58 -0
  278. package/dist/react/submitForm.js.map +1 -0
  279. package/dist/react/toFormDocument.d.ts +24 -0
  280. package/dist/react/toFormDocument.js +22 -0
  281. package/dist/react/toFormDocument.js.map +1 -0
  282. package/dist/react/uploadFile.d.ts +23 -0
  283. package/dist/react/uploadFile.js +39 -0
  284. package/dist/react/uploadFile.js.map +1 -0
  285. package/dist/react/useField.d.ts +14 -0
  286. package/dist/react/useField.js +49 -0
  287. package/dist/react/useField.js.map +1 -0
  288. package/dist/react/useFormState.d.ts +8 -0
  289. package/dist/react/useFormState.js +9 -0
  290. package/dist/react/useFormState.js.map +1 -0
  291. package/dist/react/useFormStep.d.ts +8 -0
  292. package/dist/react/useFormStep.js +9 -0
  293. package/dist/react/useFormStep.js.map +1 -0
  294. package/dist/react/validateField.js +30 -0
  295. package/dist/react/validateField.js.map +1 -0
  296. package/dist/recall/interpolate.d.ts +10 -0
  297. package/dist/recall/interpolate.js +16 -0
  298. package/dist/recall/interpolate.js.map +1 -0
  299. package/dist/recall/resolver.d.ts +22 -0
  300. package/dist/recall/resolver.js +36 -0
  301. package/dist/recall/resolver.js.map +1 -0
  302. package/dist/spam/captcha.d.ts +12 -0
  303. package/dist/spam/captcha.js +11 -0
  304. package/dist/spam/captcha.js.map +1 -0
  305. package/dist/spam/constants.d.ts +12 -0
  306. package/dist/spam/constants.js +15 -0
  307. package/dist/spam/constants.js.map +1 -0
  308. package/dist/spam/identify.d.ts +12 -0
  309. package/dist/spam/identify.js +20 -0
  310. package/dist/spam/identify.js.map +1 -0
  311. package/dist/spam/rateLimiter.d.ts +18 -0
  312. package/dist/spam/rateLimiter.js +41 -0
  313. package/dist/spam/rateLimiter.js.map +1 -0
  314. package/dist/spam/reserved.js +30 -0
  315. package/dist/spam/reserved.js.map +1 -0
  316. package/dist/spam/resolveSpam.d.ts +12 -0
  317. package/dist/spam/resolveSpam.js +42 -0
  318. package/dist/spam/resolveSpam.js.map +1 -0
  319. package/dist/spam/spamGuard.js +68 -0
  320. package/dist/spam/spamGuard.js.map +1 -0
  321. package/dist/spam/types.d.ts +73 -0
  322. package/dist/spam/uploadHooks.js +33 -0
  323. package/dist/spam/uploadHooks.js.map +1 -0
  324. package/dist/submissions/SubmissionAnswers.d.ts +14 -0
  325. package/dist/submissions/SubmissionAnswers.js +133 -0
  326. package/dist/submissions/SubmissionAnswers.js.map +1 -0
  327. package/dist/submissions/SubmissionAnswersClient.js +142 -0
  328. package/dist/submissions/SubmissionAnswersClient.js.map +1 -0
  329. package/dist/submissions/runSubmission.js +257 -0
  330. package/dist/submissions/runSubmission.js.map +1 -0
  331. package/dist/submissions/types.d.ts +34 -0
  332. package/dist/submissions/validateSubmission.js +59 -0
  333. package/dist/submissions/validateSubmission.js.map +1 -0
  334. package/dist/translations/en.d.ts +12 -0
  335. package/dist/{translations-edMqq_2e.js → translations/en.js} +29 -23
  336. package/dist/translations/en.js.map +1 -0
  337. package/dist/translations/index.d.ts +14 -0
  338. package/dist/translations/index.js +26 -0
  339. package/dist/translations/index.js.map +1 -0
  340. package/dist/translations/keys.d.ts +157 -0
  341. package/dist/{keys-N5xGiUsh.js → translations/keys.js} +28 -3
  342. package/dist/translations/keys.js.map +1 -0
  343. package/dist/translations/makeTranslate.d.ts +11 -0
  344. package/dist/translations/makeTranslate.js +11 -0
  345. package/dist/translations/makeTranslate.js.map +1 -0
  346. package/dist/translations/server.js +25 -0
  347. package/dist/translations/server.js.map +1 -0
  348. package/dist/translations/useTranslation.js +12 -0
  349. package/dist/translations/useTranslation.js.map +1 -0
  350. package/dist/uploads/captureFileRef.d.ts +27 -0
  351. package/dist/uploads/captureFileRef.js +34 -0
  352. package/dist/uploads/captureFileRef.js.map +1 -0
  353. package/dist/uploads/resolveFileRef.d.ts +26 -0
  354. package/dist/uploads/resolveFileRef.js +44 -0
  355. package/dist/uploads/resolveFileRef.js.map +1 -0
  356. package/dist/uploads/types.d.ts +20 -0
  357. package/dist/validation/buildRuleBlocks.js +46 -0
  358. package/dist/validation/buildRuleBlocks.js.map +1 -0
  359. package/dist/validation/builtin/email.js +19 -0
  360. package/dist/validation/builtin/email.js.map +1 -0
  361. package/dist/validation/builtin/index.js +27 -0
  362. package/dist/validation/builtin/index.js.map +1 -0
  363. package/dist/validation/builtin/matchesField.js +20 -0
  364. package/dist/validation/builtin/matchesField.js.map +1 -0
  365. package/dist/validation/builtin/max.js +21 -0
  366. package/dist/validation/builtin/max.js.map +1 -0
  367. package/dist/validation/builtin/maxLength.js +26 -0
  368. package/dist/validation/builtin/maxLength.js.map +1 -0
  369. package/dist/validation/builtin/min.js +21 -0
  370. package/dist/validation/builtin/min.js.map +1 -0
  371. package/dist/validation/builtin/minLength.js +26 -0
  372. package/dist/validation/builtin/minLength.js.map +1 -0
  373. package/dist/validation/builtin/notAlreadySubmitted.js +32 -0
  374. package/dist/validation/builtin/notAlreadySubmitted.js.map +1 -0
  375. package/dist/validation/builtin/oneOf.js +34 -0
  376. package/dist/validation/builtin/oneOf.js.map +1 -0
  377. package/dist/validation/builtin/pattern.js +41 -0
  378. package/dist/validation/builtin/pattern.js.map +1 -0
  379. package/dist/validation/builtin/url.js +22 -0
  380. package/dist/validation/builtin/url.js.map +1 -0
  381. package/dist/validation/defineValidationRule.d.ts +12 -0
  382. package/dist/validation/defineValidationRule.js +11 -0
  383. package/dist/validation/defineValidationRule.js.map +1 -0
  384. package/dist/validation/message.js +14 -0
  385. package/dist/validation/message.js.map +1 -0
  386. package/dist/validation/registry.d.ts +10 -0
  387. package/dist/validation/registry.js +20 -0
  388. package/dist/validation/registry.js.map +1 -0
  389. package/dist/validation/runValidation.js +111 -0
  390. package/dist/validation/runValidation.js.map +1 -0
  391. package/dist/validation/types.d.ts +76 -0
  392. package/package.json +8 -5
  393. package/styles/form-builder.css +201 -11
  394. package/dist/constants-B-BUfetP.d.ts +0 -288
  395. package/dist/exports/client.js.map +0 -1
  396. package/dist/exports/react.js.map +0 -1
  397. package/dist/exports/rsc.js.map +0 -1
  398. package/dist/fieldTypes-B8jkNRob.d.ts +0 -188
  399. package/dist/fieldTypes-CzhhJXjg.js.map +0 -1
  400. package/dist/index-DfFYGbVF.d.ts +0 -481
  401. package/dist/keys-N5xGiUsh.js.map +0 -1
  402. package/dist/registry-CoCyhtvB.js +0 -282
  403. package/dist/registry-CoCyhtvB.js.map +0 -1
  404. package/dist/resolver-OeQyVH2N.js +0 -665
  405. package/dist/resolver-OeQyVH2N.js.map +0 -1
  406. package/dist/translations-edMqq_2e.js.map +0 -1
@@ -0,0 +1,157 @@
1
+ import { keys } from "../translations/keys.js";
2
+ import { labelForKey } from "../translations/server.js";
3
+ import { isLoggedIn } from "../plugin/access.js";
4
+ import { dispatchActions } from "../actions/dispatch.js";
5
+ import { resolveEventSink } from "../events/resolveEventSink.js";
6
+ import { buildSpamGuard } from "../spam/spamGuard.js";
7
+ import { FORMS_SLUG } from "./forms.js";
8
+ import { validateSubmission } from "../submissions/validateSubmission.js";
9
+ //#region src/collections/formSubmissions.ts
10
+ const FORM_SUBMISSIONS_SLUG = "form-submissions";
11
+ const formIdOf = (form) => {
12
+ if (typeof form === "number" || typeof form === "string") return form;
13
+ if (form && typeof form === "object" && "id" in form) {
14
+ const id = form.id;
15
+ if (typeof id === "number" || typeof id === "string") return id;
16
+ }
17
+ };
18
+ /**
19
+ * On a completed submission create, dispatch the form's post-submit actions and emit `submission.created`.
20
+ * Both are side effects on an already-written row, so the whole body is wrapped: nothing it does can throw
21
+ * past the hook (a failed action or sink must never fail the submission write). Dispatch is itself bounded
22
+ * and non-throwing; the inline fallback is awaited so the bound caps the added latency, while the queued
23
+ * path returns immediately. The form's `actions` are null-guarded for legacy rows created before the field
24
+ * existed.
25
+ */
26
+ const makeAfterChange = (args) => async ({ doc, operation, req }) => {
27
+ if (operation !== "create" || doc.status != null && doc.status !== "complete") return doc;
28
+ const { payload } = req;
29
+ try {
30
+ const formId = formIdOf(doc.form);
31
+ if (formId == null) return doc;
32
+ await dispatchActions({
33
+ actions: (await payload.findByID({
34
+ collection: "forms",
35
+ id: formId,
36
+ depth: 0,
37
+ overrideAccess: true,
38
+ req
39
+ }).catch(() => null))?.actions ?? null,
40
+ formId,
41
+ submissionId: doc.id,
42
+ registry: args.actionRegistry,
43
+ payload,
44
+ req,
45
+ hasRunner: args.hasRunner
46
+ });
47
+ try {
48
+ await resolveEventSink(args.events).emit({
49
+ type: "submission.created",
50
+ formId: String(formId),
51
+ submissionId: String(doc.id),
52
+ at: (/* @__PURE__ */ new Date()).toISOString()
53
+ });
54
+ } catch (error) {
55
+ payload.logger?.error(`@10x-media/form-builder: submission.created sink threw: ${error instanceof Error ? error.message : String(error)}`);
56
+ }
57
+ } catch (error) {
58
+ payload.logger?.error(`@10x-media/form-builder: afterChange dispatch failed for submission ${String(doc.id)}: ${error instanceof Error ? error.message : String(error)}`);
59
+ }
60
+ return doc;
61
+ };
62
+ const buildSubmissionsCollection = ({ registry, ruleRegistry, consentRegistry, actionRegistry = /* @__PURE__ */ new Map(), events, hasRunner = false, uploadSlug, spam, showRawFields = false, overrides }) => {
63
+ const defaultFields = [
64
+ {
65
+ name: "form",
66
+ type: "relationship",
67
+ relationTo: FORMS_SLUG,
68
+ required: true
69
+ },
70
+ {
71
+ name: "status",
72
+ type: "select",
73
+ defaultValue: "complete",
74
+ options: [{
75
+ label: labelForKey(keys.statusComplete),
76
+ value: "complete"
77
+ }, {
78
+ label: labelForKey(keys.statusPartial),
79
+ value: "partial"
80
+ }],
81
+ access: {
82
+ create: isLoggedIn,
83
+ update: isLoggedIn
84
+ }
85
+ },
86
+ {
87
+ name: "answers",
88
+ type: "ui",
89
+ admin: { components: { Field: "@10x-media/form-builder/rsc#SubmissionAnswers" } }
90
+ },
91
+ {
92
+ name: "locale",
93
+ type: "text"
94
+ },
95
+ {
96
+ name: "values",
97
+ type: "json",
98
+ admin: { hidden: !showRawFields }
99
+ },
100
+ {
101
+ name: "descriptors",
102
+ type: "json",
103
+ admin: { hidden: !showRawFields }
104
+ },
105
+ {
106
+ name: "consent",
107
+ type: "json",
108
+ admin: { hidden: !showRawFields }
109
+ },
110
+ {
111
+ name: "meta",
112
+ type: "json"
113
+ }
114
+ ];
115
+ return {
116
+ ...overrides ?? {},
117
+ slug: FORM_SUBMISSIONS_SLUG,
118
+ labels: {
119
+ singular: labelForKey(keys.collectionSubmissionSingular),
120
+ plural: labelForKey(keys.collectionSubmissionPlural),
121
+ ...overrides?.labels ?? {}
122
+ },
123
+ admin: {
124
+ group: "Forms",
125
+ ...overrides?.admin ?? {}
126
+ },
127
+ access: {
128
+ create: () => true,
129
+ read: isLoggedIn,
130
+ update: () => false,
131
+ ...overrides?.access ?? {}
132
+ },
133
+ hooks: {
134
+ ...overrides?.hooks ?? {},
135
+ beforeValidate: [
136
+ ...spam ? [buildSpamGuard(spam)] : [],
137
+ validateSubmission({
138
+ registry,
139
+ ruleRegistry,
140
+ consentRegistry,
141
+ uploadSlug
142
+ }),
143
+ ...overrides?.hooks?.beforeValidate ?? []
144
+ ],
145
+ afterChange: [makeAfterChange({
146
+ actionRegistry,
147
+ events,
148
+ hasRunner
149
+ }), ...overrides?.hooks?.afterChange ?? []]
150
+ },
151
+ fields: overrides?.fields ? overrides.fields({ defaultFields }) : defaultFields
152
+ };
153
+ };
154
+ //#endregion
155
+ export { FORM_SUBMISSIONS_SLUG, buildSubmissionsCollection };
156
+
157
+ //# sourceMappingURL=formSubmissions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formSubmissions.js","names":[],"sources":["../../src/collections/formSubmissions.ts"],"sourcesContent":["import type { CollectionAfterChangeHook, CollectionConfig, Field } from 'payload'\nimport { dispatchActions } from '../actions/dispatch'\nimport type { ActionRegistry } from '../actions/registry'\nimport type { ActionInstance } from '../actions/runActions'\nimport type { ConsentSourceRegistry } from '../consent/registry'\nimport { resolveEventSink } from '../events/resolveEventSink'\nimport type { FormEventSink } from '../events/types'\nimport type { FieldTypeRegistry } from '../fields/registry'\nimport { isLoggedIn } from '../plugin/access'\nimport type { CollectionOverrides } from '../plugin/collectionOverrides'\nimport { buildSpamGuard } from '../spam/spamGuard'\nimport type { ResolvedSpamConfig } from '../spam/types'\nimport { validateSubmission } from '../submissions/validateSubmission'\nimport { keys } from '../translations/keys'\nimport { labelForKey } from '../translations/server'\nimport type { ValidationRuleRegistry } from '../validation/registry'\nimport { FORMS_SLUG } from './forms'\n\nexport const FORM_SUBMISSIONS_SLUG = 'form-submissions'\n\ntype BuildSubmissionsCollectionArgs = {\n\tregistry: FieldTypeRegistry\n\truleRegistry: ValidationRuleRegistry\n\tconsentRegistry: ConsentSourceRegistry\n\tactionRegistry?: ActionRegistry\n\tevents?: FormEventSink\n\t/** Whether a job runner is likely present; gates the queued vs bounded-inline dispatch path. */\n\thasRunner?: boolean\n\t/** Upload collection slug for file fields without an explicit `relationTo`. */\n\tuploadSlug?: string\n\t/** Resolved spam config; when active, prepends the spam guard before validation. `false` disables it. */\n\tspam?: ResolvedSpamConfig | false\n\t/**\n\t * When `true`, shows the raw `values`, `descriptors`, and `consent` JSON fields in the admin UI.\n\t * Default `false` — they are fully represented by the `SubmissionAnswers` UI component.\n\t */\n\tshowRawFields?: boolean\n\toverrides?: CollectionOverrides\n}\n\nconst formIdOf = (form: unknown): number | string | undefined => {\n\tif (typeof form === 'number' || typeof form === 'string') {\n\t\treturn form\n\t}\n\tif (form && typeof form === 'object' && 'id' in form) {\n\t\tconst id = (form as { id: unknown }).id\n\t\tif (typeof id === 'number' || typeof id === 'string') {\n\t\t\treturn id\n\t\t}\n\t}\n\treturn undefined\n}\n\n/**\n * On a completed submission create, dispatch the form's post-submit actions and emit `submission.created`.\n * Both are side effects on an already-written row, so the whole body is wrapped: nothing it does can throw\n * past the hook (a failed action or sink must never fail the submission write). Dispatch is itself bounded\n * and non-throwing; the inline fallback is awaited so the bound caps the added latency, while the queued\n * path returns immediately. The form's `actions` are null-guarded for legacy rows created before the field\n * existed.\n */\nconst makeAfterChange =\n\t(args: {\n\t\tactionRegistry: ActionRegistry\n\t\tevents?: FormEventSink\n\t\thasRunner: boolean\n\t}): CollectionAfterChangeHook =>\n\tasync ({ doc, operation, req }) => {\n\t\tif (operation !== 'create' || (doc.status != null && doc.status !== 'complete')) {\n\t\t\treturn doc\n\t\t}\n\t\tconst { payload } = req\n\t\ttry {\n\t\t\tconst formId = formIdOf(doc.form)\n\t\t\tif (formId == null) {\n\t\t\t\treturn doc\n\t\t\t}\n\t\t\tconst form = await payload\n\t\t\t\t.findByID({ collection: FORMS_SLUG, id: formId, depth: 0, overrideAccess: true, req })\n\t\t\t\t.catch(() => null)\n\n\t\t\tawait dispatchActions({\n\t\t\t\tactions: (form?.actions ?? null) as ActionInstance[] | null,\n\t\t\t\tformId,\n\t\t\t\tsubmissionId: doc.id as number | string,\n\t\t\t\tregistry: args.actionRegistry,\n\t\t\t\tpayload,\n\t\t\t\treq,\n\t\t\t\thasRunner: args.hasRunner,\n\t\t\t})\n\n\t\t\ttry {\n\t\t\t\tawait resolveEventSink(args.events).emit({\n\t\t\t\t\ttype: 'submission.created',\n\t\t\t\t\tformId: String(formId),\n\t\t\t\t\tsubmissionId: String(doc.id),\n\t\t\t\t\tat: new Date().toISOString(),\n\t\t\t\t})\n\t\t\t} catch (error) {\n\t\t\t\tpayload.logger?.error(\n\t\t\t\t\t`@10x-media/form-builder: submission.created sink threw: ${\n\t\t\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t\t\t}`\n\t\t\t\t)\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tpayload.logger?.error(\n\t\t\t\t`@10x-media/form-builder: afterChange dispatch failed for submission ${String(doc.id)}: ${\n\t\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t\t}`\n\t\t\t)\n\t\t}\n\t\treturn doc\n\t}\n\nexport const buildSubmissionsCollection = ({\n\tregistry,\n\truleRegistry,\n\tconsentRegistry,\n\tactionRegistry = new Map(),\n\tevents,\n\thasRunner = false,\n\tuploadSlug,\n\tspam,\n\tshowRawFields = false,\n\toverrides,\n}: BuildSubmissionsCollectionArgs): CollectionConfig => {\n\tconst defaultFields: Field[] = [\n\t\t{ name: 'form', type: 'relationship', relationTo: FORMS_SLUG, required: true },\n\t\t{\n\t\t\tname: 'status',\n\t\t\ttype: 'select',\n\t\t\tdefaultValue: 'complete',\n\t\t\toptions: [\n\t\t\t\t{ label: labelForKey(keys.statusComplete), value: 'complete' },\n\t\t\t\t{ label: labelForKey(keys.statusPartial), value: 'partial' },\n\t\t\t],\n\t\t\t// Defense-in-depth at the REST layer: anonymous clients cannot set status via the API.\n\t\t\t// The validateSubmission hook also forces 'complete' server-side, so this covers both paths.\n\t\t\taccess: { create: isLoggedIn, update: isLoggedIn },\n\t\t},\n\t\t// answers UI appears first so it is the dominant view when opening a submission document.\n\t\t{\n\t\t\tname: 'answers',\n\t\t\ttype: 'ui',\n\t\t\tadmin: {\n\t\t\t\tcomponents: { Field: '@10x-media/form-builder/rsc#SubmissionAnswers' },\n\t\t\t},\n\t\t},\n\t\t{ name: 'locale', type: 'text' },\n\t\t{ name: 'values', type: 'json', admin: { hidden: !showRawFields } },\n\t\t{ name: 'descriptors', type: 'json', admin: { hidden: !showRawFields } },\n\t\t{ name: 'consent', type: 'json', admin: { hidden: !showRawFields } },\n\t\t{ name: 'meta', type: 'json' },\n\t]\n\n\treturn {\n\t\t...(overrides ?? {}),\n\t\tslug: FORM_SUBMISSIONS_SLUG,\n\t\tlabels: {\n\t\t\tsingular: labelForKey(keys.collectionSubmissionSingular),\n\t\t\tplural: labelForKey(keys.collectionSubmissionPlural),\n\t\t\t...(overrides?.labels ?? {}),\n\t\t},\n\t\tadmin: { group: 'Forms', ...(overrides?.admin ?? {}) },\n\t\taccess: {\n\t\t\tcreate: () => true,\n\t\t\tread: isLoggedIn,\n\t\t\tupdate: () => false,\n\t\t\t...(overrides?.access ?? {}),\n\t\t},\n\t\thooks: {\n\t\t\t...(overrides?.hooks ?? {}),\n\t\t\t// Spam guard + validateSubmission must remain first: they enforce the security invariant\n\t\t\t// that anonymous callers cannot bypass post-submit actions or supply a forged status.\n\t\t\t// Consumer beforeValidate hooks are appended after so they run on already-validated data.\n\t\t\tbeforeValidate: [\n\t\t\t\t...(spam ? [buildSpamGuard(spam)] : []),\n\t\t\t\tvalidateSubmission({ registry, ruleRegistry, consentRegistry, uploadSlug }),\n\t\t\t\t...(overrides?.hooks?.beforeValidate ?? []),\n\t\t\t],\n\t\t\tafterChange: [\n\t\t\t\tmakeAfterChange({ actionRegistry, events, hasRunner }),\n\t\t\t\t...(overrides?.hooks?.afterChange ?? []),\n\t\t\t],\n\t\t},\n\t\tfields: overrides?.fields ? overrides.fields({ defaultFields }) : defaultFields,\n\t}\n}\n"],"mappings":"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"}
@@ -0,0 +1,198 @@
1
+ import { keys } from "../translations/keys.js";
2
+ import { labelFor, labelForKey } from "../translations/server.js";
3
+ import { isLoggedIn } from "../plugin/access.js";
4
+ import { buildActionBlocks } from "../actions/buildActionBlocks.js";
5
+ import { resolveFormResultsRequest } from "../aggregation/resolveResultsRequest.js";
6
+ import { normalizeCalc } from "../calc/normalizeCalc.js";
7
+ import { buildConditionTypeMap } from "../conditions/conditionType.js";
8
+ import { normalizeFormConditions } from "../conditions/normalizeConditions.js";
9
+ import { buildFieldBlocks } from "../fields/buildFieldBlocks.js";
10
+ import { normalizeFlow } from "../flow/normalizeFlow.js";
11
+ import { DEFAULT_PRESENTATION_NAME, defaultPresentationDescriptors } from "../presentations/defaults.js";
12
+ import { ValidationError } from "payload";
13
+ //#region src/collections/forms.ts
14
+ const FORMS_SLUG = "forms";
15
+ const validateFlow = (raw) => {
16
+ if (raw === null || raw === void 0) return true;
17
+ const r = raw;
18
+ if (!Array.isArray(r.steps)) return true;
19
+ const steps = r.steps;
20
+ if (steps.find((s) => typeof s?.id !== "string" || s.id.length === 0)) return "Flow: every step must have a non-empty ID";
21
+ const ids = steps.map((s) => s.id);
22
+ if (new Set(ids).size !== ids.length) return "Flow: duplicate step IDs found";
23
+ const idSet = new Set(ids);
24
+ for (const step of steps) {
25
+ const id = step.id;
26
+ if (typeof step.next === "string" && step.next.length > 0 && !idSet.has(step.next)) return `Flow: step "${id}" references unknown next step "${step.next}"`;
27
+ if (Array.isArray(step.transitions)) {
28
+ for (const t of step.transitions) if (typeof t?.to === "string" && t.to.length > 0 && !idSet.has(t.to)) return `Flow: step "${id}" has a transition to unknown step "${t.to}"`;
29
+ }
30
+ }
31
+ return true;
32
+ };
33
+ /** How many steps the caller actually submitted, before normalization strips/collapses the flow. */
34
+ const providedFlowStepCount = (raw) => {
35
+ if (raw === null || typeof raw !== "object") return 0;
36
+ const steps = raw.steps;
37
+ return Array.isArray(steps) ? steps.length : 0;
38
+ };
39
+ const buildFormsCollection = ({ overrides, registry, ruleRegistry, consentRegistry, presentationRegistry = new Map(Object.entries(defaultPresentationDescriptors)), actionRegistry = /* @__PURE__ */ new Map() }) => {
40
+ const conditionTypes = buildConditionTypeMap(registry);
41
+ const FLOW_BUILDER_REF = "@10x-media/form-builder/client#FlowBuilder";
42
+ const beforeValidate = ({ data, req }) => {
43
+ if (data && typeof data.defaultPresentation === "string" && !presentationRegistry.has(data.defaultPresentation)) data.defaultPresentation = DEFAULT_PRESENTATION_NAME;
44
+ if (data && Array.isArray(data.fields)) {
45
+ const normalized = normalizeFormConditions(data.fields, conditionTypes);
46
+ for (const field of normalized) if ("expression" in field) field.expression = normalizeCalc(field.expression);
47
+ data.fields = normalized;
48
+ const fieldNames = normalized.map((field) => typeof field.name === "string" ? field.name : void 0).filter((name) => name !== void 0);
49
+ const normalizedFlow = normalizeFlow(data.flow, fieldNames);
50
+ if (providedFlowStepCount(data.flow) > 0 && normalizedFlow === void 0) throw new ValidationError({
51
+ collection: FORMS_SLUG,
52
+ errors: [{
53
+ path: "flow",
54
+ message: "A flow needs at least two steps with unique, non-empty IDs. Add another step or remove the flow."
55
+ }]
56
+ }, req.t);
57
+ data.flow = normalizedFlow;
58
+ }
59
+ return data;
60
+ };
61
+ const defaultFields = [
62
+ {
63
+ name: "title",
64
+ type: "text",
65
+ required: true,
66
+ label: labelForKey(keys.fieldTitle)
67
+ },
68
+ {
69
+ name: "fields",
70
+ type: "blocks",
71
+ blocks: buildFieldBlocks(registry, ruleRegistry, consentRegistry)
72
+ },
73
+ {
74
+ name: "flow",
75
+ type: "json",
76
+ validate: validateFlow,
77
+ admin: { components: { Field: {
78
+ path: FLOW_BUILDER_REF,
79
+ clientProps: { conditionTypes }
80
+ } } },
81
+ typescriptSchema: [() => ({
82
+ type: "object",
83
+ required: ["steps"],
84
+ additionalProperties: false,
85
+ properties: { steps: {
86
+ type: "array",
87
+ items: {
88
+ type: "object",
89
+ required: ["id"],
90
+ additionalProperties: true,
91
+ properties: {
92
+ id: { type: "string" },
93
+ title: { type: "string" },
94
+ fields: {
95
+ type: "array",
96
+ items: { type: "string" }
97
+ },
98
+ next: { type: "string" },
99
+ transitions: {
100
+ type: "array",
101
+ items: {
102
+ type: "object",
103
+ required: ["to"],
104
+ additionalProperties: true,
105
+ properties: {
106
+ to: { type: "string" },
107
+ when: {
108
+ type: "object",
109
+ additionalProperties: true
110
+ }
111
+ }
112
+ }
113
+ }
114
+ }
115
+ }
116
+ } }
117
+ })]
118
+ },
119
+ {
120
+ name: "actions",
121
+ type: "blocks",
122
+ blocks: buildActionBlocks(actionRegistry),
123
+ label: labelForKey(keys.configActions),
124
+ access: { read: isLoggedIn }
125
+ },
126
+ {
127
+ name: "defaultPresentation",
128
+ type: "select",
129
+ defaultValue: DEFAULT_PRESENTATION_NAME,
130
+ options: [...presentationRegistry.values()].map((descriptor) => ({
131
+ label: labelFor(descriptor.label),
132
+ value: descriptor.name
133
+ })),
134
+ label: labelForKey(keys.configDefaultPresentation),
135
+ admin: { position: "sidebar" }
136
+ },
137
+ {
138
+ name: "showResults",
139
+ type: "checkbox",
140
+ defaultValue: false,
141
+ label: labelForKey(keys.configShowResults),
142
+ admin: { position: "sidebar" }
143
+ },
144
+ {
145
+ name: "resultsField",
146
+ type: "text",
147
+ label: labelForKey(keys.configResultsField),
148
+ admin: {
149
+ position: "sidebar",
150
+ description: "Field whose aggregate results are public when \"Show results publicly\" is on. Use a choice field, never a free-text or PII field.",
151
+ condition: (data) => Boolean(data?.showResults)
152
+ }
153
+ }
154
+ ];
155
+ const defaultEndpoints = [{
156
+ path: "/:id/results",
157
+ method: "get",
158
+ handler: async (req) => {
159
+ const field = typeof req.query?.field === "string" ? req.query.field : void 0;
160
+ const { status, body } = await resolveFormResultsRequest({
161
+ payload: req.payload,
162
+ formId: req.routeParams?.id,
163
+ field,
164
+ isAuthed: Boolean(req.user),
165
+ req
166
+ });
167
+ return Response.json(body, { status });
168
+ }
169
+ }];
170
+ return {
171
+ ...overrides ?? {},
172
+ slug: FORMS_SLUG,
173
+ labels: {
174
+ singular: labelForKey(keys.collectionFormSingular),
175
+ plural: labelForKey(keys.collectionFormPlural),
176
+ ...overrides?.labels ?? {}
177
+ },
178
+ admin: {
179
+ group: "Forms",
180
+ useAsTitle: "title",
181
+ ...overrides?.admin ?? {}
182
+ },
183
+ access: {
184
+ read: () => true,
185
+ ...overrides?.access ?? {}
186
+ },
187
+ hooks: {
188
+ ...overrides?.hooks ?? {},
189
+ beforeValidate: [beforeValidate, ...overrides?.hooks?.beforeValidate ?? []]
190
+ },
191
+ endpoints: [...defaultEndpoints, ...Array.isArray(overrides?.endpoints) ? overrides.endpoints : []],
192
+ fields: overrides?.fields ? overrides.fields({ defaultFields }) : defaultFields
193
+ };
194
+ };
195
+ //#endregion
196
+ export { FORMS_SLUG, buildFormsCollection };
197
+
198
+ //# sourceMappingURL=forms.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forms.js","names":[],"sources":["../../src/collections/forms.ts"],"sourcesContent":["import {\n\ttype CollectionBeforeValidateHook,\n\ttype CollectionConfig,\n\ttype Field,\n\ttype PayloadRequest,\n\tValidationError,\n} from 'payload'\nimport { buildActionBlocks } from '../actions/buildActionBlocks'\nimport type { ActionRegistry } from '../actions/registry'\nimport { resolveFormResultsRequest } from '../aggregation/resolveResultsRequest'\nimport { normalizeCalc } from '../calc/normalizeCalc'\nimport { buildConditionTypeMap } from '../conditions/conditionType'\nimport { type FieldRow, normalizeFormConditions } from '../conditions/normalizeConditions'\nimport type { ConsentSourceRegistry } from '../consent/registry'\nimport { buildFieldBlocks } from '../fields/buildFieldBlocks'\nimport type { FieldTypeRegistry } from '../fields/registry'\nimport { normalizeFlow } from '../flow/normalizeFlow'\nimport { isLoggedIn } from '../plugin/access'\nimport type { CollectionOverrides } from '../plugin/collectionOverrides'\nimport {\n\tDEFAULT_PRESENTATION_NAME,\n\tdefaultPresentationDescriptors,\n} from '../presentations/defaults'\nimport type { PresentationDescriptorRegistry } from '../presentations/registry'\nimport { keys } from '../translations/keys'\nimport { labelFor, labelForKey } from '../translations/server'\nimport type { ValidationRuleRegistry } from '../validation/registry'\n\nexport const FORMS_SLUG = 'forms'\n\nconst validateFlow = (raw: unknown): string | true => {\n\tif (raw === null || raw === undefined) return true\n\tconst r = raw as Record<string, unknown>\n\tif (!Array.isArray(r.steps)) return true\n\tconst steps = r.steps as Array<Record<string, unknown>>\n\tconst emptyIdStep = steps.find((s) => typeof s?.id !== 'string' || s.id.length === 0)\n\tif (emptyIdStep) return 'Flow: every step must have a non-empty ID'\n\tconst ids = steps.map((s) => s.id as string)\n\tif (new Set(ids).size !== ids.length) {\n\t\treturn 'Flow: duplicate step IDs found'\n\t}\n\tconst idSet = new Set(ids)\n\tfor (const step of steps) {\n\t\tconst id = step.id as string\n\t\tif (typeof step.next === 'string' && step.next.length > 0 && !idSet.has(step.next)) {\n\t\t\treturn `Flow: step \"${id}\" references unknown next step \"${step.next}\"`\n\t\t}\n\t\tif (Array.isArray(step.transitions)) {\n\t\t\tfor (const t of step.transitions as Array<Record<string, unknown>>) {\n\t\t\t\tif (typeof t?.to === 'string' && t.to.length > 0 && !idSet.has(t.to)) {\n\t\t\t\t\treturn `Flow: step \"${id}\" has a transition to unknown step \"${t.to}\"`\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn true\n}\n\n/** How many steps the caller actually submitted, before normalization strips/collapses the flow. */\nconst providedFlowStepCount = (raw: unknown): number => {\n\tif (raw === null || typeof raw !== 'object') return 0\n\tconst steps = (raw as { steps?: unknown }).steps\n\treturn Array.isArray(steps) ? steps.length : 0\n}\n\ntype BuildFormsCollectionArgs = {\n\tregistry: FieldTypeRegistry\n\truleRegistry: ValidationRuleRegistry\n\tconsentRegistry?: ConsentSourceRegistry\n\tpresentationRegistry?: PresentationDescriptorRegistry\n\tactionRegistry?: ActionRegistry\n\toverrides?: CollectionOverrides\n}\n\nexport const buildFormsCollection = ({\n\toverrides,\n\tregistry,\n\truleRegistry,\n\tconsentRegistry,\n\tpresentationRegistry = new Map(Object.entries(defaultPresentationDescriptors)),\n\tactionRegistry = new Map(),\n}: BuildFormsCollectionArgs): CollectionConfig => {\n\tconst conditionTypes = buildConditionTypeMap(registry)\n\tconst FLOW_BUILDER_REF = '@10x-media/form-builder/client#FlowBuilder'\n\n\tconst beforeValidate: CollectionBeforeValidateHook = ({ data, req }) => {\n\t\tif (\n\t\t\tdata &&\n\t\t\ttypeof data.defaultPresentation === 'string' &&\n\t\t\t!presentationRegistry.has(data.defaultPresentation)\n\t\t) {\n\t\t\tdata.defaultPresentation = DEFAULT_PRESENTATION_NAME\n\t\t}\n\t\tif (data && Array.isArray(data.fields)) {\n\t\t\tconst normalized: FieldRow[] = normalizeFormConditions(\n\t\t\t\tdata.fields as FieldRow[],\n\t\t\t\tconditionTypes\n\t\t\t)\n\t\t\tfor (const field of normalized) {\n\t\t\t\tif ('expression' in field) {\n\t\t\t\t\tfield.expression = normalizeCalc(field.expression)\n\t\t\t\t}\n\t\t\t}\n\t\t\tdata.fields = normalized\n\t\t\tconst fieldNames = normalized\n\t\t\t\t.map((field: FieldRow) => (typeof field.name === 'string' ? field.name : undefined))\n\t\t\t\t.filter((name): name is string => name !== undefined)\n\t\t\tconst normalizedFlow = normalizeFlow(data.flow, fieldNames)\n\t\t\t// A flow the author built but that collapses to fewer than two valid steps would\n\t\t\t// otherwise vanish silently. Surface it instead of discarding their work.\n\t\t\tif (providedFlowStepCount(data.flow) > 0 && normalizedFlow === undefined) {\n\t\t\t\tthrow new ValidationError(\n\t\t\t\t\t{\n\t\t\t\t\t\tcollection: FORMS_SLUG,\n\t\t\t\t\t\terrors: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tpath: 'flow',\n\t\t\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\t\t'A flow needs at least two steps with unique, non-empty IDs. Add another step or remove the flow.',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t\treq.t\n\t\t\t\t)\n\t\t\t}\n\t\t\tdata.flow = normalizedFlow\n\t\t}\n\t\treturn data\n\t}\n\n\tconst defaultFields: Field[] = [\n\t\t{ name: 'title', type: 'text', required: true, label: labelForKey(keys.fieldTitle) },\n\t\t{\n\t\t\tname: 'fields',\n\t\t\ttype: 'blocks',\n\t\t\tblocks: buildFieldBlocks(registry, ruleRegistry, consentRegistry),\n\t\t},\n\t\t{\n\t\t\tname: 'flow',\n\t\t\ttype: 'json',\n\t\t\tvalidate: validateFlow,\n\t\t\tadmin: {\n\t\t\t\tcomponents: {\n\t\t\t\t\tField: { path: FLOW_BUILDER_REF, clientProps: { conditionTypes } },\n\t\t\t\t},\n\t\t\t},\n\t\t\t// Narrows the generated TypeScript type from opaque JSON to FormFlow so callers\n\t\t\t// don't need a cast. Keep this in sync with src/flow/types.ts.\n\t\t\ttypescriptSchema: [\n\t\t\t\t() => ({\n\t\t\t\t\ttype: 'object' as const,\n\t\t\t\t\trequired: ['steps'],\n\t\t\t\t\tadditionalProperties: false,\n\t\t\t\t\tproperties: {\n\t\t\t\t\t\tsteps: {\n\t\t\t\t\t\t\ttype: 'array' as const,\n\t\t\t\t\t\t\titems: {\n\t\t\t\t\t\t\t\ttype: 'object' as const,\n\t\t\t\t\t\t\t\trequired: ['id'],\n\t\t\t\t\t\t\t\tadditionalProperties: true,\n\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\tid: { type: 'string' as const },\n\t\t\t\t\t\t\t\t\ttitle: { type: 'string' as const },\n\t\t\t\t\t\t\t\t\tfields: { type: 'array' as const, items: { type: 'string' as const } },\n\t\t\t\t\t\t\t\t\tnext: { type: 'string' as const },\n\t\t\t\t\t\t\t\t\ttransitions: {\n\t\t\t\t\t\t\t\t\t\ttype: 'array' as const,\n\t\t\t\t\t\t\t\t\t\titems: {\n\t\t\t\t\t\t\t\t\t\t\ttype: 'object' as const,\n\t\t\t\t\t\t\t\t\t\t\trequired: ['to'],\n\t\t\t\t\t\t\t\t\t\t\tadditionalProperties: true,\n\t\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\t\tto: { type: 'string' as const },\n\t\t\t\t\t\t\t\t\t\t\t\twhen: { type: 'object' as const, additionalProperties: true },\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t],\n\t\t},\n\t\t{\n\t\t\tname: 'actions',\n\t\t\ttype: 'blocks',\n\t\t\tblocks: buildActionBlocks(actionRegistry),\n\t\t\tlabel: labelForKey(keys.configActions),\n\t\t\t// Action config can contain secrets (e.g. signedWebhook.secret). The collection\n\t\t\t// itself is publicly readable so forms can be rendered by anonymous clients, but\n\t\t\t// action config must never be exposed to anonymous callers.\n\t\t\taccess: { read: isLoggedIn },\n\t\t},\n\t\t{\n\t\t\tname: 'defaultPresentation',\n\t\t\ttype: 'select',\n\t\t\tdefaultValue: DEFAULT_PRESENTATION_NAME,\n\t\t\toptions: [...presentationRegistry.values()].map((descriptor) => ({\n\t\t\t\tlabel: labelFor(descriptor.label),\n\t\t\t\tvalue: descriptor.name,\n\t\t\t})),\n\t\t\tlabel: labelForKey(keys.configDefaultPresentation),\n\t\t\tadmin: { position: 'sidebar' },\n\t\t},\n\t\t{\n\t\t\tname: 'showResults',\n\t\t\ttype: 'checkbox',\n\t\t\tdefaultValue: false,\n\t\t\tlabel: labelForKey(keys.configShowResults),\n\t\t\tadmin: { position: 'sidebar' },\n\t\t},\n\t\t{\n\t\t\tname: 'resultsField',\n\t\t\ttype: 'text',\n\t\t\tlabel: labelForKey(keys.configResultsField),\n\t\t\tadmin: {\n\t\t\t\tposition: 'sidebar',\n\t\t\t\tdescription:\n\t\t\t\t\t'Field whose aggregate results are public when \"Show results publicly\" is on. Use a choice field, never a free-text or PII field.',\n\t\t\t\tcondition: (data) => Boolean(data?.showResults),\n\t\t\t},\n\t\t},\n\t]\n\n\tconst defaultEndpoints: CollectionConfig['endpoints'] = [\n\t\t{\n\t\t\tpath: '/:id/results',\n\t\t\tmethod: 'get',\n\t\t\thandler: async (req: PayloadRequest) => {\n\t\t\t\tconst field = typeof req.query?.field === 'string' ? req.query.field : undefined\n\t\t\t\tconst { status, body } = await resolveFormResultsRequest({\n\t\t\t\t\tpayload: req.payload,\n\t\t\t\t\tformId: req.routeParams?.id as number | string | undefined,\n\t\t\t\t\tfield,\n\t\t\t\t\tisAuthed: Boolean(req.user),\n\t\t\t\t\treq,\n\t\t\t\t})\n\t\t\t\treturn Response.json(body, { status })\n\t\t\t},\n\t\t},\n\t]\n\n\treturn {\n\t\t...(overrides ?? {}),\n\t\tslug: FORMS_SLUG,\n\t\tlabels: {\n\t\t\tsingular: labelForKey(keys.collectionFormSingular),\n\t\t\tplural: labelForKey(keys.collectionFormPlural),\n\t\t\t...(overrides?.labels ?? {}),\n\t\t},\n\t\tadmin: { group: 'Forms', useAsTitle: 'title', ...(overrides?.admin ?? {}) },\n\t\taccess: { read: () => true, ...(overrides?.access ?? {}) },\n\t\thooks: {\n\t\t\t...(overrides?.hooks ?? {}),\n\t\t\t// beforeValidate normalizes conditions and flow; consumer hooks run after\n\t\t\tbeforeValidate: [beforeValidate, ...(overrides?.hooks?.beforeValidate ?? [])],\n\t\t},\n\t\tendpoints: [\n\t\t\t...defaultEndpoints,\n\t\t\t...(Array.isArray(overrides?.endpoints) ? overrides.endpoints : []),\n\t\t],\n\t\tfields: overrides?.fields ? overrides.fields({ defaultFields }) : defaultFields,\n\t}\n}\n"],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { CollectionOverrides } from "../plugin/collectionOverrides.js";
2
+ import { CollectionConfig } from "payload";
3
+
4
+ //#region src/collections/uploads.d.ts
5
+ declare const FORM_UPLOADS_SLUG = "form-uploads";
6
+ /** Override surface for the built-in upload collection. */
7
+ type UploadsCollectionConfig = {
8
+ slug?: string; /** Merged onto the collection's `upload` config (e.g. `staticDir`, `mimeTypes`). `true` uses Payload defaults. */
9
+ upload?: NonNullable<CollectionConfig['upload']> | true; /** Replace access (defaults: anonymous create, authed read/update/delete). */
10
+ access?: CollectionConfig['access']; /** Append extra fields. */
11
+ fields?: CollectionConfig['fields'];
12
+ };
13
+ type UploadsOption = boolean | UploadsCollectionConfig;
14
+ /**
15
+ * The built-in upload collection backing the `file` field. Anonymous create (public forms upload here),
16
+ * authed read/update/delete (only admins read stored files; submitters cannot enumerate others' uploads).
17
+ * Per-field MIME/size is re-enforced at submit, so the collection stays permissive by default. No
18
+ * `imageSizes`, so it needs no `sharp`. Projects with their own upload collection set `uploads: false` and
19
+ * point the file field's `relationTo` at theirs.
20
+ */
21
+ declare const buildUploadsCollection: (config?: UploadsCollectionConfig, overrides?: CollectionOverrides) => CollectionConfig;
22
+ /** Resolve the `uploads` plugin option: `false` disables, `true`/object enables the built-in collection. */
23
+ declare const resolveUploads: (option: UploadsOption | undefined) => {
24
+ enabled: boolean;
25
+ slug: string;
26
+ collection?: CollectionConfig;
27
+ };
28
+ //#endregion
29
+ export { FORM_UPLOADS_SLUG, UploadsCollectionConfig, UploadsOption, buildUploadsCollection, resolveUploads };
30
+ //# sourceMappingURL=uploads.d.ts.map
@@ -0,0 +1,55 @@
1
+ import { isLoggedIn } from "../plugin/access.js";
2
+ //#region src/collections/uploads.ts
3
+ const FORM_UPLOADS_SLUG = "form-uploads";
4
+ /**
5
+ * The built-in upload collection backing the `file` field. Anonymous create (public forms upload here),
6
+ * authed read/update/delete (only admins read stored files; submitters cannot enumerate others' uploads).
7
+ * Per-field MIME/size is re-enforced at submit, so the collection stays permissive by default. No
8
+ * `imageSizes`, so it needs no `sharp`. Projects with their own upload collection set `uploads: false` and
9
+ * point the file field's `relationTo` at theirs.
10
+ */
11
+ const buildUploadsCollection = (config = {}, overrides) => {
12
+ const defaultFields = [{
13
+ name: "owner",
14
+ type: "text",
15
+ admin: {
16
+ readOnly: true,
17
+ hidden: true
18
+ }
19
+ }, ...config.fields ?? []];
20
+ return {
21
+ ...overrides ?? {},
22
+ slug: config.slug ?? "form-uploads",
23
+ access: {
24
+ create: () => true,
25
+ read: isLoggedIn,
26
+ update: isLoggedIn,
27
+ delete: isLoggedIn,
28
+ ...config.access ?? {},
29
+ ...overrides?.access ?? {}
30
+ },
31
+ admin: {
32
+ group: "Forms",
33
+ ...overrides?.admin ?? {}
34
+ },
35
+ upload: config.upload && config.upload !== true ? config.upload : true,
36
+ fields: overrides?.fields ? overrides.fields({ defaultFields }) : defaultFields
37
+ };
38
+ };
39
+ /** Resolve the `uploads` plugin option: `false` disables, `true`/object enables the built-in collection. */
40
+ const resolveUploads = (option) => {
41
+ if (option === false) return {
42
+ enabled: false,
43
+ slug: FORM_UPLOADS_SLUG
44
+ };
45
+ const collection = buildUploadsCollection(option && option !== true ? option : {});
46
+ return {
47
+ enabled: true,
48
+ slug: collection.slug,
49
+ collection
50
+ };
51
+ };
52
+ //#endregion
53
+ export { FORM_UPLOADS_SLUG, buildUploadsCollection, resolveUploads };
54
+
55
+ //# sourceMappingURL=uploads.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uploads.js","names":[],"sources":["../../src/collections/uploads.ts"],"sourcesContent":["import type { CollectionConfig, Field } from 'payload'\nimport { isLoggedIn } from '../plugin/access'\nimport type { CollectionOverrides } from '../plugin/collectionOverrides'\n\nexport const FORM_UPLOADS_SLUG = 'form-uploads'\n\n/** Override surface for the built-in upload collection. */\nexport type UploadsCollectionConfig = {\n\tslug?: string\n\t/** Merged onto the collection's `upload` config (e.g. `staticDir`, `mimeTypes`). `true` uses Payload defaults. */\n\tupload?: NonNullable<CollectionConfig['upload']> | true\n\t/** Replace access (defaults: anonymous create, authed read/update/delete). */\n\taccess?: CollectionConfig['access']\n\t/** Append extra fields. */\n\tfields?: CollectionConfig['fields']\n}\n\nexport type UploadsOption = boolean | UploadsCollectionConfig\n\n/**\n * The built-in upload collection backing the `file` field. Anonymous create (public forms upload here),\n * authed read/update/delete (only admins read stored files; submitters cannot enumerate others' uploads).\n * Per-field MIME/size is re-enforced at submit, so the collection stays permissive by default. No\n * `imageSizes`, so it needs no `sharp`. Projects with their own upload collection set `uploads: false` and\n * point the file field's `relationTo` at theirs.\n */\nexport const buildUploadsCollection = (\n\tconfig: UploadsCollectionConfig = {},\n\toverrides?: CollectionOverrides\n): CollectionConfig => {\n\tconst defaultFields: Field[] = [\n\t\t{ name: 'owner', type: 'text', admin: { readOnly: true, hidden: true } },\n\t\t...(config.fields ?? []),\n\t]\n\n\treturn {\n\t\t...(overrides ?? {}),\n\t\tslug: config.slug ?? FORM_UPLOADS_SLUG,\n\t\taccess: {\n\t\t\tcreate: () => true,\n\t\t\tread: isLoggedIn,\n\t\t\tupdate: isLoggedIn,\n\t\t\tdelete: isLoggedIn,\n\t\t\t...(config.access ?? {}),\n\t\t\t...(overrides?.access ?? {}),\n\t\t},\n\t\tadmin: { group: 'Forms', ...(overrides?.admin ?? {}) },\n\t\tupload: config.upload && config.upload !== true ? config.upload : true,\n\t\tfields: overrides?.fields ? overrides.fields({ defaultFields }) : defaultFields,\n\t}\n}\n\n/** Resolve the `uploads` plugin option: `false` disables, `true`/object enables the built-in collection. */\nexport const resolveUploads = (\n\toption: UploadsOption | undefined\n): { enabled: boolean; slug: string; collection?: CollectionConfig } => {\n\tif (option === false) {\n\t\treturn { enabled: false, slug: FORM_UPLOADS_SLUG }\n\t}\n\tconst config = option && option !== true ? option : {}\n\tconst collection = buildUploadsCollection(config)\n\treturn { enabled: true, slug: collection.slug as string, collection }\n}\n"],"mappings":";;AAIA,MAAa,oBAAoB;;;;;;;;AAsBjC,MAAa,0BACZ,SAAkC,CAAC,GACnC,cACsB;CACtB,MAAM,gBAAyB,CAC9B;EAAE,MAAM;EAAS,MAAM;EAAQ,OAAO;GAAE,UAAU;GAAM,QAAQ;EAAK;CAAE,GACvE,GAAI,OAAO,UAAU,CAAC,CACvB;CAEA,OAAO;EACN,GAAI,aAAa,CAAC;EAClB,MAAM,OAAO,QAAA;EACb,QAAQ;GACP,cAAc;GACd,MAAM;GACN,QAAQ;GACR,QAAQ;GACR,GAAI,OAAO,UAAU,CAAC;GACtB,GAAI,WAAW,UAAU,CAAC;EAC3B;EACA,OAAO;GAAE,OAAO;GAAS,GAAI,WAAW,SAAS,CAAC;EAAG;EACrD,QAAQ,OAAO,UAAU,OAAO,WAAW,OAAO,OAAO,SAAS;EAClE,QAAQ,WAAW,SAAS,UAAU,OAAO,EAAE,cAAc,CAAC,IAAI;CACnE;AACD;;AAGA,MAAa,kBACZ,WACuE;CACvE,IAAI,WAAW,OACd,OAAO;EAAE,SAAS;EAAO,MAAM;CAAkB;CAGlD,MAAM,aAAa,uBADJ,UAAU,WAAW,OAAO,SAAS,CAAC,CACL;CAChD,OAAO;EAAE,SAAS;EAAM,MAAM,WAAW;EAAgB;CAAW;AACrE"}
@@ -0,0 +1,14 @@
1
+ import { defaultConditionType } from "./fieldTypes.js";
2
+ //#region src/conditions/conditionType.ts
3
+ /** The condition input a field type uses in the builder: its declared `conditionType` or the value-kind default. */
4
+ const conditionTypeForDefinition = (definition) => definition.conditionType ?? defaultConditionType(definition.value);
5
+ /** A serializable slug -> condition type map for every registered field type, handed to the client builder. */
6
+ const buildConditionTypeMap = (registry) => {
7
+ const map = {};
8
+ for (const definition of registry.values()) map[definition.type] = conditionTypeForDefinition(definition);
9
+ return map;
10
+ };
11
+ //#endregion
12
+ export { buildConditionTypeMap };
13
+
14
+ //# sourceMappingURL=conditionType.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conditionType.js","names":[],"sources":["../../src/conditions/conditionType.ts"],"sourcesContent":["import type { AnyFormFieldDefinition } from '../fields/types'\nimport { type ConditionFieldType, defaultConditionType } from './fieldTypes'\n\n/** The condition input a field type uses in the builder: its declared `conditionType` or the value-kind default. */\nexport const conditionTypeForDefinition = (\n\tdefinition: Pick<AnyFormFieldDefinition, 'value' | 'conditionType'>\n): ConditionFieldType => definition.conditionType ?? defaultConditionType(definition.value)\n\n/** A serializable slug -> condition type map for every registered field type, handed to the client builder. */\nexport const buildConditionTypeMap = (\n\tregistry: Map<string, AnyFormFieldDefinition>\n): Record<string, ConditionFieldType> => {\n\tconst map: Record<string, ConditionFieldType> = {}\n\tfor (const definition of registry.values()) {\n\t\tmap[definition.type] = conditionTypeForDefinition(definition)\n\t}\n\treturn map\n}\n"],"mappings":";;;AAIA,MAAa,8BACZ,eACwB,WAAW,iBAAiB,qBAAqB,WAAW,KAAK;;AAG1F,MAAa,yBACZ,aACwC;CACxC,MAAM,MAA0C,CAAC;CACjD,KAAK,MAAM,cAAc,SAAS,OAAO,GACxC,IAAI,WAAW,QAAQ,2BAA2B,UAAU;CAE7D,OAAO;AACR"}
@@ -0,0 +1,17 @@
1
+ import { Where } from "payload";
2
+
3
+ //#region src/conditions/evaluate.d.ts
4
+ /**
5
+ * Evaluate a serializable `Where`-shaped condition against a flat map of (already coerced) form answers.
6
+ * An absent or empty condition matches (returns true). Operator semantics mirror Payload's query
7
+ * adapters: coerce then compare; `not_equals`/`not_in` are null-inclusive; `exists` treats `''`/absent
8
+ * as not-existing; `like` is case-insensitive and space-splits (every word must be a substring), and
9
+ * `not_like` is its logical negation (at least one word absent); `contains` is a single case-insensitive
10
+ * substring; comma-delimited `in`/`not_in` string values are split and trimmed. Geo (`near`/`within`/
11
+ * `intersects`) and `all` are out of scope and evaluate to false. Isomorphic: no `req`/DB access, so the
12
+ * renderer reuses it client-side.
13
+ */
14
+ declare const evaluateCondition: (where: Where | null | undefined, answers: Record<string, unknown>) => boolean;
15
+ //#endregion
16
+ export { evaluateCondition };
17
+ //# sourceMappingURL=evaluate.d.ts.map
@@ -0,0 +1,94 @@
1
+ import { transformWhereQuery } from "payload/shared";
2
+ //#region src/conditions/evaluate.ts
3
+ const isNil = (value) => value === null || value === void 0;
4
+ const toNumber = (value) => {
5
+ if (typeof value === "number") return Number.isFinite(value) ? value : void 0;
6
+ if (typeof value === "string" && value.trim() !== "") {
7
+ const next = Number(value);
8
+ return Number.isNaN(next) ? void 0 : next;
9
+ }
10
+ };
11
+ const toTime = (value) => {
12
+ if (value instanceof Date) return value.getTime();
13
+ if (typeof value === "string" && value.trim() !== "") {
14
+ const time = Date.parse(value);
15
+ return Number.isNaN(time) ? void 0 : time;
16
+ }
17
+ };
18
+ /** Strict, then numeric, then string equality, mirroring Payload's coerce-by-type-then-compare. */
19
+ const valuesEqual = (answer, value) => {
20
+ if (answer === value) return true;
21
+ if (isNil(answer) || isNil(value)) return false;
22
+ const a = toNumber(answer);
23
+ const b = toNumber(value);
24
+ if (a !== void 0 && b !== void 0) return a === b;
25
+ return String(answer) === String(value);
26
+ };
27
+ const toList = (value) => {
28
+ if (Array.isArray(value)) return value;
29
+ if (typeof value === "string") return value.split(",").map((entry) => entry.trim());
30
+ return [value];
31
+ };
32
+ const ordered = (answer, value, compare) => {
33
+ const a = toNumber(answer) ?? toTime(answer);
34
+ const b = toNumber(value) ?? toTime(value);
35
+ if (a === void 0 || b === void 0) return false;
36
+ return compare(a, b);
37
+ };
38
+ /** Case-insensitive: every space-separated word in `value` is a substring of `answer` (Payload `like`). */
39
+ const everyWord = (answer, value) => {
40
+ const haystack = String(answer).toLowerCase();
41
+ return String(value).toLowerCase().split(" ").filter((word) => word.length > 0).every((word) => haystack.includes(word));
42
+ };
43
+ const evaluateOperator = (operator, answer, value) => {
44
+ switch (operator) {
45
+ case "equals": return isNil(value) ? isNil(answer) : valuesEqual(answer, value);
46
+ case "not_equals": return isNil(value) ? !isNil(answer) : isNil(answer) || !valuesEqual(answer, value);
47
+ case "in": return toList(value).some((entry) => valuesEqual(answer, entry));
48
+ case "not_in": return isNil(answer) || !toList(value).some((entry) => valuesEqual(answer, entry));
49
+ case "exists": {
50
+ const present = !isNil(answer) && answer !== "";
51
+ return value === true || value === "true" ? present : !present;
52
+ }
53
+ case "greater_than": return ordered(answer, value, (a, b) => a > b);
54
+ case "greater_than_equal": return ordered(answer, value, (a, b) => a >= b);
55
+ case "less_than": return ordered(answer, value, (a, b) => a < b);
56
+ case "less_than_equal": return ordered(answer, value, (a, b) => a <= b);
57
+ case "like": return isNil(answer) ? false : everyWord(answer, value);
58
+ case "not_like": return isNil(answer) ? true : !everyWord(answer, value);
59
+ case "contains": return isNil(answer) ? false : String(answer).toLowerCase().includes(String(value).toLowerCase());
60
+ default: return false;
61
+ }
62
+ };
63
+ /**
64
+ * Evaluate one `Where` node: every top-level key is ANDed. `or` is a disjunction of sub-conditions
65
+ * (an empty `or` matches), `and` is a conjunction, and any other key is a field path whose
66
+ * `{ operator: value }` constraints are ANDed. Recurses, so nested `or`/`and` groups are supported.
67
+ */
68
+ const evaluateWhere = (where, answers) => Object.entries(where).every(([key, constraint]) => {
69
+ if (key === "or") {
70
+ const groups = Array.isArray(constraint) ? constraint : [];
71
+ return groups.length === 0 || groups.some((group) => evaluateWhere(group, answers));
72
+ }
73
+ if (key === "and") return (Array.isArray(constraint) ? constraint : []).every((group) => evaluateWhere(group, answers));
74
+ if (constraint == null || typeof constraint !== "object" || Array.isArray(constraint)) return false;
75
+ return Object.entries(constraint).every(([operator, value]) => evaluateOperator(operator, answers[key], value));
76
+ });
77
+ /**
78
+ * Evaluate a serializable `Where`-shaped condition against a flat map of (already coerced) form answers.
79
+ * An absent or empty condition matches (returns true). Operator semantics mirror Payload's query
80
+ * adapters: coerce then compare; `not_equals`/`not_in` are null-inclusive; `exists` treats `''`/absent
81
+ * as not-existing; `like` is case-insensitive and space-splits (every word must be a substring), and
82
+ * `not_like` is its logical negation (at least one word absent); `contains` is a single case-insensitive
83
+ * substring; comma-delimited `in`/`not_in` string values are split and trimmed. Geo (`near`/`within`/
84
+ * `intersects`) and `all` are out of scope and evaluate to false. Isomorphic: no `req`/DB access, so the
85
+ * renderer reuses it client-side.
86
+ */
87
+ const evaluateCondition = (where, answers) => {
88
+ if (!where || Object.keys(where).length === 0) return true;
89
+ return evaluateWhere(transformWhereQuery(where), answers);
90
+ };
91
+ //#endregion
92
+ export { evaluateCondition };
93
+
94
+ //# sourceMappingURL=evaluate.js.map