@pilotiq/pilotiq 0.23.1 → 0.24.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 (500) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/boost/guidelines.md +566 -0
  3. package/boost/skills/pilotiq-fields/SKILL.md +47 -0
  4. package/boost/skills/pilotiq-fields/rules/field-catalog.md +288 -0
  5. package/boost/skills/pilotiq-fields/rules/reactive-fields.md +199 -0
  6. package/boost/skills/pilotiq-fields/rules/validation.md +198 -0
  7. package/boost/skills/pilotiq-relations/SKILL.md +47 -0
  8. package/boost/skills/pilotiq-relations/rules/relation-managers.md +256 -0
  9. package/boost/skills/pilotiq-relations/rules/repeater-relationship.md +177 -0
  10. package/boost/skills/pilotiq-resource/SKILL.md +61 -0
  11. package/boost/skills/pilotiq-resource/rules/authorization.md +242 -0
  12. package/boost/skills/pilotiq-resource/rules/defining-resources.md +228 -0
  13. package/boost/skills/pilotiq-resource/rules/page-overrides.md +296 -0
  14. package/dist/actions/exportFactory.d.ts +10 -0
  15. package/dist/actions/exportFactory.d.ts.map +1 -1
  16. package/dist/actions/exportFactory.js +10 -0
  17. package/dist/actions/exportFactory.js.map +1 -1
  18. package/dist/react/CollabRoomContext.d.ts +5 -5
  19. package/dist/react/index.d.ts +0 -1
  20. package/dist/react/index.d.ts.map +1 -1
  21. package/dist/react/index.js +0 -1
  22. package/dist/react/index.js.map +1 -1
  23. package/dist/routes/helpers.d.ts.map +1 -1
  24. package/dist/routes/helpers.js +6 -2
  25. package/dist/routes/helpers.js.map +1 -1
  26. package/dist/routes/relations.d.ts.map +1 -1
  27. package/dist/routes/relations.js +12 -0
  28. package/dist/routes/relations.js.map +1 -1
  29. package/package.json +6 -1
  30. package/.turbo/turbo-build.log +0 -8
  31. package/CLAUDE.md +0 -265
  32. package/dist/react/useCollabSeed.d.ts +0 -23
  33. package/dist/react/useCollabSeed.d.ts.map +0 -1
  34. package/dist/react/useCollabSeed.js +0 -82
  35. package/dist/react/useCollabSeed.js.map +0 -1
  36. package/src/Cluster.test.ts +0 -283
  37. package/src/Cluster.ts +0 -83
  38. package/src/Column.test.ts +0 -199
  39. package/src/Column.ts +0 -710
  40. package/src/Global.test.ts +0 -367
  41. package/src/Global.ts +0 -169
  42. package/src/Page.test.ts +0 -114
  43. package/src/Page.ts +0 -208
  44. package/src/Pilotiq.perf.test.ts +0 -252
  45. package/src/Pilotiq.test.ts +0 -129
  46. package/src/Pilotiq.ts +0 -1158
  47. package/src/PilotiqRegistry.ts +0 -36
  48. package/src/PilotiqServiceProvider.ts +0 -121
  49. package/src/RelationManager.test.ts +0 -400
  50. package/src/RelationManager.ts +0 -527
  51. package/src/RenderHook.test.ts +0 -252
  52. package/src/RenderHook.ts +0 -242
  53. package/src/Resource.test.ts +0 -284
  54. package/src/Resource.ts +0 -526
  55. package/src/RightPanel.test.ts +0 -202
  56. package/src/RightPanel.ts +0 -132
  57. package/src/Tab.test.ts +0 -91
  58. package/src/Tab.ts +0 -156
  59. package/src/UserMenuItem.ts +0 -145
  60. package/src/actions/Action.test.ts +0 -2526
  61. package/src/actions/Action.ts +0 -1515
  62. package/src/actions/ActionGroup.test.ts +0 -112
  63. package/src/actions/ActionGroup.ts +0 -173
  64. package/src/actions/attachFactory.ts +0 -172
  65. package/src/actions/bulkFactories.ts +0 -168
  66. package/src/actions/crudFactories.ts +0 -220
  67. package/src/actions/exportFactory.ts +0 -215
  68. package/src/actions/factoryHelpers.ts +0 -177
  69. package/src/actions/importFactory.ts +0 -243
  70. package/src/actions/index.ts +0 -17
  71. package/src/actions/m2mFactories.ts +0 -193
  72. package/src/actions/relationFactories.ts +0 -372
  73. package/src/applyPageHooks.test.ts +0 -463
  74. package/src/applyPageHooks.ts +0 -330
  75. package/src/authorization.test.ts +0 -483
  76. package/src/breadcrumbs.test.ts +0 -238
  77. package/src/cells/coerce.test.ts +0 -85
  78. package/src/cells/coerce.ts +0 -84
  79. package/src/clusterPaths.ts +0 -35
  80. package/src/columns/BadgeColumn.test.ts +0 -54
  81. package/src/columns/BadgeColumn.ts +0 -32
  82. package/src/columns/BooleanColumn.test.ts +0 -41
  83. package/src/columns/BooleanColumn.ts +0 -18
  84. package/src/columns/ColorColumn.test.ts +0 -37
  85. package/src/columns/ColorColumn.ts +0 -38
  86. package/src/columns/IconColumn.test.ts +0 -54
  87. package/src/columns/IconColumn.ts +0 -37
  88. package/src/columns/ImageColumn.test.ts +0 -41
  89. package/src/columns/ImageColumn.ts +0 -28
  90. package/src/columns/SelectColumn.ts +0 -98
  91. package/src/columns/TextColumn.test.ts +0 -190
  92. package/src/columns/TextColumn.ts +0 -20
  93. package/src/columns/TextInputColumn.ts +0 -68
  94. package/src/columns/ToggleColumn.ts +0 -46
  95. package/src/columns/editableColumns.test.ts +0 -238
  96. package/src/columns/index.ts +0 -9
  97. package/src/defaultGlobalPages.ts +0 -95
  98. package/src/defaultPages.test.ts +0 -634
  99. package/src/defaultPages.ts +0 -617
  100. package/src/defaultViewPage.test.ts +0 -147
  101. package/src/elements/Form.test.ts +0 -223
  102. package/src/elements/Form.ts +0 -416
  103. package/src/elements/ListTabs.ts +0 -28
  104. package/src/elements/Table.test.ts +0 -422
  105. package/src/elements/Table.ts +0 -850
  106. package/src/elements/TableGroup.test.ts +0 -260
  107. package/src/elements/TableGroup.ts +0 -334
  108. package/src/elements/dispatchAction.test.ts +0 -463
  109. package/src/elements/dispatchAction.ts +0 -355
  110. package/src/elements/dispatchForm.test.ts +0 -477
  111. package/src/elements/dispatchForm.ts +0 -1993
  112. package/src/elements/dispatchTable.test.ts +0 -1514
  113. package/src/elements/dispatchTable.ts +0 -745
  114. package/src/elements/index.ts +0 -21
  115. package/src/entries/BadgeEntry.ts +0 -39
  116. package/src/entries/CodeEntry.test.ts +0 -40
  117. package/src/entries/CodeEntry.ts +0 -52
  118. package/src/entries/ColorEntry.ts +0 -63
  119. package/src/entries/ComponentEntry.test.ts +0 -173
  120. package/src/entries/ComponentEntry.ts +0 -95
  121. package/src/entries/Entry.ts +0 -304
  122. package/src/entries/IconEntry.ts +0 -49
  123. package/src/entries/ImageEntry.ts +0 -61
  124. package/src/entries/KeyValueEntry.ts +0 -47
  125. package/src/entries/RepeatableEntry.test.ts +0 -239
  126. package/src/entries/RepeatableEntry.ts +0 -173
  127. package/src/entries/TextEntry.test.ts +0 -394
  128. package/src/entries/TextEntry.ts +0 -60
  129. package/src/entries/index.ts +0 -12
  130. package/src/entries/leaves.test.ts +0 -306
  131. package/src/entries/registry.ts +0 -54
  132. package/src/fields/BuilderField.test.ts +0 -1188
  133. package/src/fields/BuilderField.ts +0 -605
  134. package/src/fields/BuilderRelationship.test.ts +0 -811
  135. package/src/fields/CheckboxField.test.ts +0 -44
  136. package/src/fields/CheckboxField.ts +0 -27
  137. package/src/fields/CheckboxListField.test.ts +0 -99
  138. package/src/fields/CheckboxListField.ts +0 -66
  139. package/src/fields/ColorPickerField.test.ts +0 -33
  140. package/src/fields/ColorPickerField.ts +0 -25
  141. package/src/fields/DateField.ts +0 -54
  142. package/src/fields/DateTimeField.test.ts +0 -55
  143. package/src/fields/EmailField.ts +0 -16
  144. package/src/fields/Field.test.ts +0 -654
  145. package/src/fields/Field.ts +0 -817
  146. package/src/fields/FileUploadField.test.ts +0 -143
  147. package/src/fields/FileUploadField.ts +0 -159
  148. package/src/fields/HiddenField.test.ts +0 -27
  149. package/src/fields/HiddenField.ts +0 -28
  150. package/src/fields/KeyValueField.test.ts +0 -105
  151. package/src/fields/KeyValueField.ts +0 -55
  152. package/src/fields/MarkdownField.test.ts +0 -167
  153. package/src/fields/MarkdownField.ts +0 -162
  154. package/src/fields/NumberField.ts +0 -33
  155. package/src/fields/RadioField.test.ts +0 -94
  156. package/src/fields/RadioField.ts +0 -67
  157. package/src/fields/RepeaterField.test.ts +0 -1806
  158. package/src/fields/RepeaterField.ts +0 -939
  159. package/src/fields/RepeaterRelationship.test.ts +0 -1923
  160. package/src/fields/RepeaterSimple.test.ts +0 -248
  161. package/src/fields/RowButton.test.ts +0 -219
  162. package/src/fields/RowButton.ts +0 -135
  163. package/src/fields/SelectField.test.ts +0 -192
  164. package/src/fields/SelectField.ts +0 -235
  165. package/src/fields/SliderField.test.ts +0 -50
  166. package/src/fields/SliderField.ts +0 -53
  167. package/src/fields/SlugField.ts +0 -24
  168. package/src/fields/TagsInputField.test.ts +0 -154
  169. package/src/fields/TagsInputField.ts +0 -133
  170. package/src/fields/TextField.test.ts +0 -213
  171. package/src/fields/TextField.ts +0 -177
  172. package/src/fields/TextareaField.test.ts +0 -58
  173. package/src/fields/TextareaField.ts +0 -59
  174. package/src/fields/ToggleButtonsField.test.ts +0 -106
  175. package/src/fields/ToggleButtonsField.ts +0 -59
  176. package/src/fields/ToggleField.ts +0 -16
  177. package/src/fields/disableOptionsWhenSelectedInSiblingRepeaterItems.test.ts +0 -319
  178. package/src/fields/optionsResolver.ts +0 -95
  179. package/src/fields/resolveField.ts +0 -28
  180. package/src/filters/BooleanFilter.ts +0 -35
  181. package/src/filters/DateRangeFilter.test.ts +0 -194
  182. package/src/filters/DateRangeFilter.ts +0 -148
  183. package/src/filters/Filter.test.ts +0 -268
  184. package/src/filters/Filter.ts +0 -184
  185. package/src/filters/FormFilter.test.ts +0 -238
  186. package/src/filters/FormFilter.ts +0 -215
  187. package/src/filters/MultiSelectFilter.test.ts +0 -119
  188. package/src/filters/MultiSelectFilter.ts +0 -78
  189. package/src/filters/QueryBuilderFilter.test.ts +0 -662
  190. package/src/filters/QueryBuilderFilter.ts +0 -398
  191. package/src/filters/SelectFilter.ts +0 -46
  192. package/src/filters/TernaryFilter.test.ts +0 -160
  193. package/src/filters/TernaryFilter.ts +0 -72
  194. package/src/filters/TrashedFilter.test.ts +0 -149
  195. package/src/filters/TrashedFilter.ts +0 -55
  196. package/src/filters/queryBuilder/BooleanConstraint.ts +0 -31
  197. package/src/filters/queryBuilder/Constraint.ts +0 -115
  198. package/src/filters/queryBuilder/DateConstraint.ts +0 -69
  199. package/src/filters/queryBuilder/NumberConstraint.ts +0 -66
  200. package/src/filters/queryBuilder/SelectConstraint.ts +0 -72
  201. package/src/filters/queryBuilder/TextConstraint.ts +0 -64
  202. package/src/filters/queryBuilder/index.ts +0 -12
  203. package/src/icons/index.ts +0 -2
  204. package/src/icons/lucide.ts +0 -204
  205. package/src/icons/registry.test.ts +0 -56
  206. package/src/icons/registry.ts +0 -41
  207. package/src/icons/types.ts +0 -47
  208. package/src/index.ts +0 -525
  209. package/src/io/csv.test.ts +0 -142
  210. package/src/io/csv.ts +0 -170
  211. package/src/nestedRelationManagerData.test.ts +0 -547
  212. package/src/notifications/Notification.test.ts +0 -210
  213. package/src/notifications/Notification.ts +0 -354
  214. package/src/notifications/broadcast.test.ts +0 -110
  215. package/src/notifications/broadcast.ts +0 -95
  216. package/src/notifications/database.test.ts +0 -383
  217. package/src/notifications/database.ts +0 -398
  218. package/src/notifications/databaseNotifications.test.ts +0 -187
  219. package/src/notifications/dispatchNotificationAction.test.ts +0 -341
  220. package/src/notifications/dispatchNotificationAction.ts +0 -142
  221. package/src/notifications/flash.test.ts +0 -89
  222. package/src/notifications/flash.ts +0 -71
  223. package/src/notifications/index.ts +0 -45
  224. package/src/notifications/registerBroadcastAuth.test.ts +0 -134
  225. package/src/notifications/registerBroadcastAuth.ts +0 -100
  226. package/src/notifications/resolveSavedNotification.test.ts +0 -82
  227. package/src/notifications/resolveSavedNotification.ts +0 -59
  228. package/src/notifications/types.ts +0 -93
  229. package/src/orm/m2mAccessor.ts +0 -66
  230. package/src/orm/modelDefaults.test.ts +0 -633
  231. package/src/orm/modelDefaults.ts +0 -666
  232. package/src/pageData/breadcrumbs.ts +0 -288
  233. package/src/pageData/forms.ts +0 -578
  234. package/src/pageData/helpers.ts +0 -857
  235. package/src/pageData/misc.ts +0 -347
  236. package/src/pageData/navigation.ts +0 -842
  237. package/src/pageData/relationPages.ts +0 -1248
  238. package/src/pageData/relationTabs.ts +0 -286
  239. package/src/pageData/resourcePages.ts +0 -609
  240. package/src/pageData.test.ts +0 -1545
  241. package/src/pageData.ts +0 -341
  242. package/src/plugins/index.ts +0 -8
  243. package/src/plugins/themeEditor.test.ts +0 -36
  244. package/src/plugins/themeEditor.ts +0 -45
  245. package/src/react/AppShell.tsx +0 -251
  246. package/src/react/CollabExtensionFactoryRegistry.ts +0 -55
  247. package/src/react/CollabRoomContext.ts +0 -98
  248. package/src/react/CollabTextRendererRegistry.ts +0 -102
  249. package/src/react/CommandPalette.tsx +0 -375
  250. package/src/react/CurrentUserContext.tsx +0 -50
  251. package/src/react/CustomPageWrapperGate.tsx +0 -69
  252. package/src/react/CustomPageWrapperRegistry.ts +0 -45
  253. package/src/react/FieldFocusReporterRegistry.ts +0 -37
  254. package/src/react/FieldLabelSlotRegistry.ts +0 -30
  255. package/src/react/FieldPresenceRegistry.ts +0 -46
  256. package/src/react/FormCollabBindingRegistry.ts +0 -242
  257. package/src/react/FormStateContext.tsx +0 -591
  258. package/src/react/HeadHooks.tsx +0 -126
  259. package/src/react/MarkdownEditorRegistry.test.ts +0 -38
  260. package/src/react/MarkdownEditorRegistry.ts +0 -107
  261. package/src/react/NotificationActionStrip.tsx +0 -263
  262. package/src/react/NotificationBell.tsx +0 -426
  263. package/src/react/PendingSuggestionApplierRegistry.test.ts +0 -97
  264. package/src/react/PendingSuggestionApplierRegistry.ts +0 -98
  265. package/src/react/PendingSuggestionOverlayRegistry.ts +0 -54
  266. package/src/react/PendingSuggestionsContext.tsx +0 -172
  267. package/src/react/RecordWrapperGate.tsx +0 -58
  268. package/src/react/RecordWrapperRegistry.ts +0 -39
  269. package/src/react/RenderHookSlot.tsx +0 -32
  270. package/src/react/RightSidebar.tsx +0 -257
  271. package/src/react/RightSidebarContext.tsx +0 -234
  272. package/src/react/RightSidebarTrigger.tsx +0 -53
  273. package/src/react/RowCoordsContext.tsx +0 -23
  274. package/src/react/SchemaRenderer.tsx +0 -549
  275. package/src/react/SearchTrigger.tsx +0 -46
  276. package/src/react/ThemeProvider.tsx +0 -93
  277. package/src/react/ThemeSettingsPage.tsx +0 -579
  278. package/src/react/ThemeToggle.tsx +0 -20
  279. package/src/react/Toaster.tsx +0 -158
  280. package/src/react/UserMenu.tsx +0 -196
  281. package/src/react/WidgetDataContext.tsx +0 -157
  282. package/src/react/cells/EditableCell.tsx +0 -389
  283. package/src/react/component-slots.test.ts +0 -103
  284. package/src/react/component-slots.ts +0 -116
  285. package/src/react/fieldJsHandler.test.ts +0 -166
  286. package/src/react/fieldJsHandler.ts +0 -79
  287. package/src/react/fields/BuilderInput.tsx +0 -1078
  288. package/src/react/fields/CheckboxInput.tsx +0 -39
  289. package/src/react/fields/CheckboxListInput.tsx +0 -102
  290. package/src/react/fields/ColorInput.tsx +0 -71
  291. package/src/react/fields/DateFieldInput.tsx +0 -70
  292. package/src/react/fields/DateTimeInput.tsx +0 -62
  293. package/src/react/fields/FieldShell.tsx +0 -348
  294. package/src/react/fields/FileUploadInput.tsx +0 -639
  295. package/src/react/fields/HiddenInput.tsx +0 -17
  296. package/src/react/fields/KeyValueInput.tsx +0 -230
  297. package/src/react/fields/MarkdownInput.tsx +0 -560
  298. package/src/react/fields/RadioInput.tsx +0 -81
  299. package/src/react/fields/RepeaterInput.test.ts +0 -116
  300. package/src/react/fields/RepeaterInput.tsx +0 -1420
  301. package/src/react/fields/SelectFieldInput.tsx +0 -280
  302. package/src/react/fields/SliderInput.tsx +0 -81
  303. package/src/react/fields/TagsInput.tsx +0 -283
  304. package/src/react/fields/TextLikeInput.tsx +0 -256
  305. package/src/react/fields/ToggleButtonsInput.tsx +0 -60
  306. package/src/react/fields/ToggleFieldInput.tsx +0 -56
  307. package/src/react/fields/relationshipRenameDispatch.test.ts +0 -106
  308. package/src/react/fields/relationshipRenameDispatch.ts +0 -97
  309. package/src/react/fields/repeaterReconcile.test.ts +0 -114
  310. package/src/react/fields/repeaterReconcile.ts +0 -104
  311. package/src/react/fields/rowChromeButton.tsx +0 -336
  312. package/src/react/fields/rowState.ts +0 -106
  313. package/src/react/fields/syncRowGates.test.ts +0 -202
  314. package/src/react/fields/syncRowGates.ts +0 -66
  315. package/src/react/fields/textInputControls.tsx +0 -238
  316. package/src/react/fields/useRowReorderDnd.ts +0 -78
  317. package/src/react/formStateHelpers.test.ts +0 -508
  318. package/src/react/formStateHelpers.ts +0 -381
  319. package/src/react/hooks/use-mobile.ts +0 -19
  320. package/src/react/icon-context.tsx +0 -60
  321. package/src/react/index.ts +0 -195
  322. package/src/react/layouts/SidebarLayout.tsx +0 -250
  323. package/src/react/layouts/TopbarLayout.tsx +0 -258
  324. package/src/react/navigate.tsx +0 -37
  325. package/src/react/onProviderSynced.test.ts +0 -90
  326. package/src/react/parseRecordEditUrl.test.ts +0 -122
  327. package/src/react/parseRecordEditUrl.ts +0 -94
  328. package/src/react/persistedState.ts +0 -40
  329. package/src/react/registry.ts +0 -48
  330. package/src/react/right-panel-registry.tsx +0 -47
  331. package/src/react/schemaRenderer/AlertRenderer.tsx +0 -112
  332. package/src/react/schemaRenderer/EntryRenderer.tsx +0 -501
  333. package/src/react/schemaRenderer/SectionRenderer.tsx +0 -120
  334. package/src/react/schemaRenderer/SimpleElements.tsx +0 -306
  335. package/src/react/schemaRenderer/TabsRenderer.tsx +0 -62
  336. package/src/react/schemaRenderer/WizardRenderer.tsx +0 -338
  337. package/src/react/schemaRenderer/action/ActionGroupTrigger.tsx +0 -177
  338. package/src/react/schemaRenderer/action/ActionModalDialog.tsx +0 -273
  339. package/src/react/schemaRenderer/action/ConfirmActionDialog.tsx +0 -61
  340. package/src/react/schemaRenderer/action/HandlerActionButton.tsx +0 -43
  341. package/src/react/schemaRenderer/action/MethodActionButton.tsx +0 -64
  342. package/src/react/schemaRenderer/action/buttons.tsx +0 -99
  343. package/src/react/schemaRenderer/action/helpers.ts +0 -140
  344. package/src/react/schemaRenderer/action/renderAction.tsx +0 -245
  345. package/src/react/schemaRenderer/columnFormat.ts +0 -65
  346. package/src/react/schemaRenderer/constants.ts +0 -50
  347. package/src/react/schemaRenderer/form/FormRenderer.tsx +0 -274
  348. package/src/react/schemaRenderer/form/renderField.tsx +0 -511
  349. package/src/react/schemaRenderer/helpers.tsx +0 -81
  350. package/src/react/schemaRenderer/table/CardsLayoutBody.tsx +0 -308
  351. package/src/react/schemaRenderer/table/TableRenderer.tsx +0 -123
  352. package/src/react/schemaRenderer/table/TableRendererBody.tsx +0 -974
  353. package/src/react/schemaRenderer/table/filters.tsx +0 -1233
  354. package/src/react/schemaRenderer/table/formatCell.tsx +0 -264
  355. package/src/react/schemaRenderer/table/links.tsx +0 -112
  356. package/src/react/schemaRenderer/table/renderRowActions.tsx +0 -52
  357. package/src/react/schemaRenderer/table/url.tsx +0 -143
  358. package/src/react/theme-preview/apply.ts +0 -99
  359. package/src/react/theme-preview/build-html.ts +0 -436
  360. package/src/react/ui/button.tsx +0 -51
  361. package/src/react/ui/calendar.tsx +0 -67
  362. package/src/react/ui/checkbox.tsx +0 -29
  363. package/src/react/ui/dialog.tsx +0 -108
  364. package/src/react/ui/dropdown-menu.tsx +0 -97
  365. package/src/react/ui/input.tsx +0 -20
  366. package/src/react/ui/label.tsx +0 -21
  367. package/src/react/ui/popover.tsx +0 -50
  368. package/src/react/ui/select.tsx +0 -169
  369. package/src/react/ui/separator.tsx +0 -25
  370. package/src/react/ui/sheet.tsx +0 -136
  371. package/src/react/ui/sidebar.tsx +0 -723
  372. package/src/react/ui/skeleton.tsx +0 -13
  373. package/src/react/ui/slider.tsx +0 -34
  374. package/src/react/ui/switch.tsx +0 -28
  375. package/src/react/ui/table.tsx +0 -105
  376. package/src/react/ui/tabs.tsx +0 -63
  377. package/src/react/ui/textarea.tsx +0 -18
  378. package/src/react/ui/tooltip.tsx +0 -64
  379. package/src/react/useCollabSeed.ts +0 -86
  380. package/src/react/useResizableWidth.ts +0 -139
  381. package/src/react/utils.ts +0 -6
  382. package/src/react/widgetRegistry.test.ts +0 -43
  383. package/src/react/widgetRegistry.ts +0 -50
  384. package/src/react/widgets/StatsOverviewRenderer.tsx +0 -232
  385. package/src/react/widgets/TableWidgetRenderer.tsx +0 -231
  386. package/src/react/widgets/ViewRenderer.tsx +0 -71
  387. package/src/relationManagerData.test.ts +0 -1595
  388. package/src/richtext/index.ts +0 -8
  389. package/src/richtext/registry.ts +0 -89
  390. package/src/routes/globals.ts +0 -148
  391. package/src/routes/guard.test.ts +0 -325
  392. package/src/routes/helpers.ts +0 -700
  393. package/src/routes/pages.ts +0 -175
  394. package/src/routes/panel.ts +0 -204
  395. package/src/routes/relations.ts +0 -1227
  396. package/src/routes/resources.ts +0 -781
  397. package/src/routes/theme.ts +0 -91
  398. package/src/routes-nested-relations.test.ts +0 -676
  399. package/src/routes-relations.test.ts +0 -972
  400. package/src/routes.test.ts +0 -2027
  401. package/src/routes.ts +0 -303
  402. package/src/schema/Alert.test.ts +0 -109
  403. package/src/schema/Alert.ts +0 -131
  404. package/src/schema/Block.ts +0 -169
  405. package/src/schema/Breadcrumbs.ts +0 -40
  406. package/src/schema/Card.ts +0 -35
  407. package/src/schema/Divider.ts +0 -20
  408. package/src/schema/Element.ts +0 -219
  409. package/src/schema/EmptyState.test.ts +0 -37
  410. package/src/schema/EmptyState.ts +0 -63
  411. package/src/schema/Fieldset.ts +0 -43
  412. package/src/schema/Grid.ts +0 -43
  413. package/src/schema/Group.ts +0 -30
  414. package/src/schema/Heading.ts +0 -39
  415. package/src/schema/Html.ts +0 -67
  416. package/src/schema/Icon.ts +0 -54
  417. package/src/schema/Image.ts +0 -57
  418. package/src/schema/LinkTag.ts +0 -41
  419. package/src/schema/Markdown.ts +0 -85
  420. package/src/schema/MetaTag.ts +0 -41
  421. package/src/schema/RelationTabs.ts +0 -71
  422. package/src/schema/ScriptTag.ts +0 -55
  423. package/src/schema/Section.ts +0 -160
  424. package/src/schema/ServerDataElement.test.ts +0 -140
  425. package/src/schema/ServerDataElement.ts +0 -156
  426. package/src/schema/SlotComponent.test.ts +0 -77
  427. package/src/schema/SlotComponent.ts +0 -71
  428. package/src/schema/Split.ts +0 -50
  429. package/src/schema/Stat.test.ts +0 -118
  430. package/src/schema/Stat.ts +0 -154
  431. package/src/schema/StatsOverview.test.ts +0 -141
  432. package/src/schema/StatsOverview.ts +0 -119
  433. package/src/schema/StyleTag.ts +0 -35
  434. package/src/schema/TableWidget.test.ts +0 -297
  435. package/src/schema/TableWidget.ts +0 -289
  436. package/src/schema/Tabs.ts +0 -79
  437. package/src/schema/Text.ts +0 -58
  438. package/src/schema/UnorderedList.ts +0 -49
  439. package/src/schema/View.test.ts +0 -111
  440. package/src/schema/View.ts +0 -127
  441. package/src/schema/Wizard.ts +0 -220
  442. package/src/schema/containers.test.ts +0 -564
  443. package/src/schema/headTags.test.ts +0 -134
  444. package/src/schema/index.ts +0 -40
  445. package/src/schema/primes.test.ts +0 -269
  446. package/src/schema/resolveSchema.test.ts +0 -379
  447. package/src/schema/resolveSchema.ts +0 -917
  448. package/src/schema/sanitize.ts +0 -58
  449. package/src/search.test.ts +0 -446
  450. package/src/search.ts +0 -178
  451. package/src/sessionFilters.test.ts +0 -375
  452. package/src/sessionFilters.ts +0 -143
  453. package/src/slot-components/index.ts +0 -10
  454. package/src/slot-components/registry.ts +0 -56
  455. package/src/styles/file-upload.css +0 -13
  456. package/src/summarizers/Summarizer.test.ts +0 -84
  457. package/src/summarizers/Summarizer.ts +0 -123
  458. package/src/summarizers/index.ts +0 -11
  459. package/src/theme/base-colors.ts +0 -68
  460. package/src/theme/chart-colors.ts +0 -50
  461. package/src/theme/colors.ts +0 -447
  462. package/src/theme/generate-css.test.ts +0 -139
  463. package/src/theme/generate-css.ts +0 -44
  464. package/src/theme/generate-scale.test.ts +0 -106
  465. package/src/theme/generate-scale.ts +0 -97
  466. package/src/theme/icon-map.ts +0 -42
  467. package/src/theme/index.ts +0 -34
  468. package/src/theme/migrate.test.ts +0 -178
  469. package/src/theme/migrate.ts +0 -81
  470. package/src/theme/presets.ts +0 -135
  471. package/src/theme/radius.ts +0 -18
  472. package/src/theme/resolve.test.ts +0 -238
  473. package/src/theme/resolve.ts +0 -96
  474. package/src/theme/spacing.ts +0 -18
  475. package/src/theme/storage.test.ts +0 -126
  476. package/src/theme/storage.ts +0 -106
  477. package/src/theme/theme-colors.ts +0 -88
  478. package/src/theme/types.ts +0 -125
  479. package/src/uploads/UploadAdapter.ts +0 -35
  480. package/src/uploads/index.ts +0 -2
  481. package/src/uploads/localUpload.test.ts +0 -70
  482. package/src/uploads/localUpload.ts +0 -84
  483. package/src/validation/Validator.ts +0 -49
  484. package/src/validation/index.ts +0 -28
  485. package/src/validation/rules.ts +0 -78
  486. package/src/validation/runValidators.ts +0 -435
  487. package/src/validation/uniqueValidator.test.ts +0 -196
  488. package/src/validation/uniqueValidator.ts +0 -133
  489. package/src/validation/validators.test.ts +0 -268
  490. package/src/vite.test.ts +0 -184
  491. package/src/vite.ts +0 -787
  492. package/src/widgets/index.ts +0 -10
  493. package/src/widgets/registry.ts +0 -45
  494. package/src/widgets.test.ts +0 -592
  495. package/tsconfig.build.json +0 -11
  496. package/tsconfig.json +0 -4
  497. package/tsconfig.test.json +0 -10
  498. package/views/react/Dashboard.tsx +0 -27
  499. package/views/react/Resources/Form.tsx +0 -102
  500. package/views/react/Resources/Index.tsx +0 -49
@@ -1,578 +0,0 @@
1
- import type { Pilotiq } from '../Pilotiq.js'
2
- import type { Page } from '../Page.js'
3
- import { Element } from '../schema/Element.js'
4
- import { resolveSchema, type SchemaContext, type RenderContext } from '../schema/resolveSchema.js'
5
- import { Form } from '../elements/Form.js'
6
- import { applyStateUpdate, coerceFormValues, findForms, findWizardStep, selectFormById } from '../elements/dispatchForm.js'
7
- import { findRecord } from '../orm/modelDefaults.js'
8
- import { isRepeaterField, RepeaterField } from '../fields/RepeaterField.js'
9
- import { isBuilderField, BuilderField } from '../fields/BuilderField.js'
10
- import { SelectField } from '../fields/SelectField.js'
11
- import { validateSchema } from '../validation/index.js'
12
- import { callPageSchema, uploadCtx, userCtx } from './helpers.js'
13
-
14
- // ─── Shared scope → page+form+record resolver ────────────────
15
- //
16
- // Every form-subresource builder (`formStateData / formWizardData /
17
- // formCreateOptionData / mentionResolveData`) needs to: resolve the
18
- // `FormStateScope` to a concrete `PageClass`, build the upload/user-aware
19
- // `SchemaContext`, call the page's `schema()`, and pick the requested form
20
- // by id. `resolveScopeForm` does that whole prelude in one async step.
21
-
22
- interface ResolveScopeFormSuccess {
23
- ok: true
24
- PageClass: typeof Page
25
- baseCtx: SchemaContext
26
- elements: Element[]
27
- form: Form
28
- record: unknown
29
- mode: 'create' | 'edit'
30
- }
31
-
32
- interface ResolveScopeFormFormMissing {
33
- ok: false
34
- status: 404
35
- error: string
36
- }
37
-
38
- /**
39
- * Resolve `FormStateScope` → `{ PageClass, baseCtx, elements, form, record, mode }`.
40
- *
41
- * Returns `null` when the scope's slug doesn't resolve to a real
42
- * resource/global/page or the matching page-role (`create`/`edit`) isn't
43
- * registered — caller returns 404 to the client. Returns
44
- * `{ ok: false, status: 404, error }` when the page resolves but the
45
- * requested `formId` isn't on it.
46
- */
47
- async function resolveScopeForm(
48
- pilotiq: Pilotiq,
49
- scope: FormStateScope,
50
- formId: string,
51
- user: unknown,
52
- ): Promise<ResolveScopeFormSuccess | ResolveScopeFormFormMissing | null> {
53
- const cfg = pilotiq.getConfig()
54
-
55
- let PageClass: typeof Page | undefined
56
- let mode: 'create' | 'edit'
57
- let record: unknown = undefined
58
- let baseCtxExtras: Record<string, unknown> = {}
59
-
60
- if (scope.kind === 'resource-create' || scope.kind === 'resource-edit') {
61
- const R = pilotiq.findResource(scope.slug)
62
- if (!R) return null
63
- const pages = R.resolvePages()
64
- if (scope.kind === 'resource-create') {
65
- if (!pages.create) return null
66
- PageClass = pages.create
67
- mode = 'create'
68
- } else {
69
- if (!pages.edit) return null
70
- PageClass = pages.edit
71
- mode = 'edit'
72
- baseCtxExtras = { recordId: scope.recordId }
73
- if (R.model) {
74
- try { record = await findRecord(R, scope.recordId, { user }) } catch { /* ignore */ }
75
- } else {
76
- record = { id: scope.recordId }
77
- }
78
- }
79
- } else if (scope.kind === 'global-edit') {
80
- const G = pilotiq.findGlobal(scope.slug)
81
- if (!G) return null
82
- const pages = G.resolvePages()
83
- if (!pages.edit) return null
84
- PageClass = pages.edit
85
- mode = 'edit'
86
- } else {
87
- const P = pilotiq.findPage(scope.pageSlug)
88
- if (!P) return null
89
- PageClass = P
90
- // Custom pages don't have a record/edit-mode concept — pass mode
91
- // 'edit' so resolveSchema treats fields as form inputs (not table
92
- // cells / view-mode read-only).
93
- mode = 'edit'
94
- }
95
-
96
- const baseCtx: SchemaContext = uploadCtx(userCtx({ mode, basePath: cfg.path, ...baseCtxExtras }, user), cfg)
97
- const elements = await callPageSchema(PageClass, baseCtx)
98
- const form = selectFormById(findForms(elements), formId)
99
- if (!form) return { ok: false, status: 404, error: `Form "${formId}" not found on page` }
100
-
101
- return { ok: true, PageClass, baseCtx, elements, form, record, mode }
102
- }
103
-
104
- // ─── Form-related data builders ─────────────────────────────
105
- //
106
- // Plan #5 partial-resolve (formStateData), Plan #8 wizard step-validate
107
- // (formWizardData), inline-create-option (formCreateOptionData), and
108
- // async-mention resolve (mentionResolveData). All four sit downstream
109
- // of `resolveSchema` and re-run the form lifecycle in narrower modes
110
- // (just the changed field; just the requested step; etc.).
111
-
112
-
113
- // ─── Plan #5 partial-resolve data builder ────────────────────
114
-
115
- export type FormStateScope =
116
- | { kind: 'resource-create'; slug: string }
117
- | { kind: 'resource-edit'; slug: string; recordId: string }
118
- | { kind: 'global-edit'; slug: string }
119
- | { kind: 'page'; pageSlug: string }
120
-
121
- export interface FormStateRequest {
122
- formId: string
123
- changed: string
124
- values: Record<string, unknown>
125
- }
126
-
127
- export interface FormStateResult {
128
- ok: true
129
- form: Record<string, unknown> // resolved FormMeta
130
- dirty: string[]
131
- }
132
-
133
- export interface FormStateError {
134
- ok: false
135
- status: 404 | 422
136
- error: string
137
- }
138
-
139
- /**
140
- * Plan #5 — handle a partial-resolve roundtrip from a `live()` field.
141
- *
142
- * Locates the page's schema, finds the targeted form by `formId`, runs
143
- * `applyStateUpdate` to apply the changed value + run
144
- * `afterStateUpdated`, then re-resolves the form's children with the
145
- * mutated values + bound `$get / $set` so dependent options /
146
- * conditional visibility re-evaluate. Returns the resolved FormMeta the
147
- * client uses to replace its rendered form.
148
- *
149
- * Returns `null` when the route prefix doesn't resolve to a real
150
- * resource/global/page — the route handler turns this into a 404. The
151
- * inner `{ status: 422 }` failure is for "form found but `changed`
152
- * field doesn't exist on it" — also a client-side bug.
153
- */
154
- export async function formStateData(
155
- pilotiq: Pilotiq,
156
- scope: FormStateScope,
157
- body: FormStateRequest,
158
- req?: unknown,
159
- ): Promise<FormStateResult | FormStateError | null> {
160
- const user = await pilotiq.resolveUser(req)
161
- const loaded = await resolveScopeForm(pilotiq, scope, body.formId, user)
162
- if (!loaded) return null
163
- if (!loaded.ok) return loaded
164
- const { baseCtx, form, record } = loaded
165
-
166
- const update = await applyStateUpdate(form, body.values, body.changed, {
167
- ...(record !== undefined ? { record } : {}),
168
- ...(user !== null ? { user } : {}),
169
- request: req,
170
- })
171
- if (!update) {
172
- return { ok: false, status: 422, error: `Field "${body.changed}" not found on form "${body.formId}"` }
173
- }
174
-
175
- // Re-resolve the form with the mutated values bound. We bind
176
- // `$get / $set` against the post-update values map so further
177
- // resolve-time logic (SelectField.options(fn), reactive
178
- // visibility) reads current state.
179
- const $get = (name: string): unknown => update.values[name]
180
- // $set on the resolve pass is a no-op — only afterStateUpdated
181
- // mutations survive into the response. Resolve-time `$set` would
182
- // race against the client's view of the world.
183
- const $set = (_name: string, _v: unknown): void => { /* intentional no-op */ }
184
-
185
- const resolveCtx = {
186
- ...baseCtx,
187
- values: update.values,
188
- $get,
189
- $set,
190
- changed: body.changed,
191
- ...(record !== undefined ? { record } : {}),
192
- }
193
- // Snapshot values onto the form so its FormMeta carries them.
194
- form.withValues(update.values)
195
- const resolved = await resolveSchema([form], resolveCtx)
196
- const formMeta = resolved[0]
197
- if (!formMeta || formMeta.type !== 'form') {
198
- return { ok: false, status: 422, error: 'Form re-resolved to non-form meta' }
199
- }
200
-
201
- return { ok: true, form: formMeta, dirty: update.dirty }
202
- }
203
-
204
- // ─── Plan #8 wizard step-validate data builder ────────────────
205
-
206
- export interface FormWizardRequest {
207
- formId: string
208
- step: number
209
- values: Record<string, unknown>
210
- }
211
-
212
- export interface FormWizardSuccess {
213
- ok: true
214
- }
215
-
216
- export interface FormWizardFailure {
217
- ok: false
218
- status: 404 | 422
219
- error?: string
220
- errors?: Record<string, string[]>
221
- }
222
-
223
- /**
224
- * Plan #8 — handle a Wizard step-validate POST. Locates the form by id,
225
- * walks to the Wizard descendant, validates only the fields inside step
226
- * `step` against `values`. Returns `{ ok: true }` on success or
227
- * `{ ok: false, status: 422, errors }` when fields fail validation.
228
- *
229
- * Errors are keyed by field name, same shape as the form-submit 422 path,
230
- * so the client (`FormStateApi.applyErrors`) can surface them in-place.
231
- */
232
- export async function formWizardData(
233
- pilotiq: Pilotiq,
234
- scope: FormStateScope,
235
- body: FormWizardRequest,
236
- req?: unknown,
237
- ): Promise<FormWizardSuccess | FormWizardFailure | null> {
238
- const user = await pilotiq.resolveUser(req)
239
- const loaded = await resolveScopeForm(pilotiq, scope, body.formId, user)
240
- if (!loaded) return null
241
- if (!loaded.ok) return loaded
242
- const { form, record } = loaded
243
-
244
- const formChildren = form.getChildren() ?? []
245
- const step = findWizardStep(formChildren, body.step)
246
- if (!step) return { ok: false, status: 404, error: `Step ${body.step} not found on form "${body.formId}"` }
247
-
248
- // Step.beforeValidation — runs before validators. May mutate `body.values`
249
- // in place (the validator reads from the same object), or throw to halt
250
- // with a 422 stamped under the reserved `_step` key.
251
- type StepHook = (values: Record<string, unknown>, ctx: { record?: unknown; user?: unknown }) => void | Promise<void>
252
- const stepHooks = step as {
253
- getBeforeValidation?: () => StepHook | undefined
254
- getAfterValidation?: () => StepHook | undefined
255
- }
256
- const beforeHook = stepHooks.getBeforeValidation?.call(step)
257
- if (beforeHook) {
258
- try { await beforeHook(body.values, { record, user }) }
259
- catch (err) {
260
- return { ok: false, status: 422, errors: { _step: [stepHookErrorMessage(err)] } }
261
- }
262
- }
263
-
264
- const errors = await validateSchema(step.getChildren() ?? [], body.values, record)
265
- if (Object.keys(errors).length > 0) {
266
- return { ok: false, status: 422, errors }
267
- }
268
-
269
- // Step.afterValidation — fires only when validators pass. Same throw →
270
- // 422 contract as beforeValidation.
271
- const afterHook = stepHooks.getAfterValidation?.call(step)
272
- if (afterHook) {
273
- try { await afterHook(body.values, { record, user }) }
274
- catch (err) {
275
- return { ok: false, status: 422, errors: { _step: [stepHookErrorMessage(err)] } }
276
- }
277
- }
278
-
279
- return { ok: true }
280
- }
281
-
282
- function stepHookErrorMessage(err: unknown): string {
283
- if (err instanceof Error && err.message) return err.message
284
- if (typeof err === 'string' && err.length > 0) return err
285
- return 'Step validation failed'
286
- }
287
-
288
- // ─── SelectField inline-create-option data builder ───────────
289
-
290
- export interface FormCreateOptionRequest {
291
- formId: string
292
- fieldName: string
293
- values: Record<string, unknown>
294
- }
295
-
296
- export interface FormCreateOptionSuccess {
297
- ok: true
298
- option: { value: string; label: string }
299
- }
300
-
301
- export interface FormCreateOptionFailure {
302
- ok: false
303
- status: 403 | 404 | 422 | 500
304
- error?: string
305
- errors?: Record<string, string[]>
306
- }
307
-
308
- /** Find a `SelectField` by name inside a form's children, walking through
309
- * layout containers but stopping at Repeater / Builder boundaries
310
- * (parallel to `tagSelectCreateOptionUrls`'s walker). Returns the first
311
- * match or `undefined`. */
312
- function findSelectFieldByName(elements: Element[], name: string): SelectField | undefined {
313
- for (const el of elements) {
314
- if (el instanceof SelectField) {
315
- if (el.name === name) return el
316
- continue
317
- }
318
- if (el instanceof RepeaterField) continue
319
- if (el instanceof BuilderField) continue
320
- const children = el.getChildren()
321
- if (children && children.length > 0) {
322
- const found = findSelectFieldByName(children as Element[], name)
323
- if (found) return found
324
- }
325
- }
326
- return undefined
327
- }
328
-
329
- /**
330
- * Audit row 2026-05-07 cont'd⁸ — handle a `SelectField.createOptionForm()`
331
- * modal submit. Locates the parent form by `formId`, finds the SelectField
332
- * by `fieldName`, re-evaluates the `createOptionAuthorize` rule (so a
333
- * tampered URL can't bypass), coerces + validates the body against the
334
- * sub-form's fields, then calls `createOptionUsing(handler)` and returns
335
- * `{ option }` for the client to append + select.
336
- *
337
- * Returns `null` when the route prefix doesn't resolve to a real
338
- * resource/global/page (route handler turns into 404).
339
- */
340
- export async function formCreateOptionData(
341
- pilotiq: Pilotiq,
342
- scope: FormStateScope,
343
- body: FormCreateOptionRequest,
344
- req?: unknown,
345
- ): Promise<FormCreateOptionSuccess | FormCreateOptionFailure | null> {
346
- const user = await pilotiq.resolveUser(req)
347
- const loaded = await resolveScopeForm(pilotiq, scope, body.formId, user)
348
- if (!loaded) return null
349
- if (!loaded.ok) return loaded
350
- const { baseCtx, form, record } = loaded
351
-
352
- const field = findSelectFieldByName(form.getChildren() as Element[] ?? [], body.fieldName)
353
- if (!field) return { ok: false, status: 404, error: `SelectField "${body.fieldName}" not found on form "${body.formId}"` }
354
- if (!field.hasCreateOption()) return { ok: false, status: 404, error: `SelectField "${body.fieldName}" does not configure createOptionForm()` }
355
-
356
- const createForm = field.getCreateOptionForm()!
357
- const handler = field.getCreateOptionHandler()
358
- if (!handler) {
359
- return { ok: false, status: 500, error: `SelectField "${body.fieldName}" has createOptionForm() but no createOptionUsing() handler` }
360
- }
361
-
362
- // Re-evaluate authorize. Build the same ActionVisibilityContext shape
363
- // the field's `toMeta` did — keeps server / meta-build paths consistent.
364
- const authorize = field.getCreateOptionAuthorize()
365
- if (authorize !== undefined) {
366
- const authVisible = await (async () => {
367
- if (typeof authorize !== 'function') return authorize
368
- const visCtx: import('../actions/Action.js').ActionVisibilityContext = {}
369
- if (record !== undefined) visCtx.record = record
370
- if (user !== null ) visCtx.user = user
371
- try { return await authorize(visCtx) } catch { return false }
372
- })()
373
- if (!authVisible) return { ok: false, status: 403, error: 'createOptionAuthorize denied' }
374
- }
375
-
376
- // Coerce + validate body against the sub-form's fields. The createOption
377
- // sub-schema is detached from the parent form so we run it against its
378
- // own children only — coerceFormValues mutates `out` to normalize toggle
379
- // / number / date / etc. shapes (same shape parent forms use).
380
- const coerced = coerceFormValues(createForm, { ...body.values })
381
- const errors = await validateSchema(createForm, coerced, undefined)
382
- if (Object.keys(errors).length > 0) {
383
- return { ok: false, status: 422, errors }
384
- }
385
-
386
- const ctx: RenderContext = {
387
- ...baseCtx,
388
- values: coerced,
389
- ...(record !== undefined ? { record } : {}),
390
- }
391
- let option: { value: string; label: string }
392
- try {
393
- option = await handler(coerced, ctx)
394
- } catch (e) {
395
- return { ok: false, status: 500, error: e instanceof Error ? e.message : String(e) }
396
- }
397
-
398
- if (!option || typeof option.value !== 'string' || typeof option.label !== 'string') {
399
- return { ok: false, status: 500, error: `createOptionUsing must return { value: string, label: string }` }
400
- }
401
-
402
- return { ok: true, option }
403
- }
404
-
405
- // ─── Async-mention resolve data builder ──────────────────────
406
-
407
- export interface MentionResolveRequest {
408
- formId: string
409
- field: string
410
- trigger: string
411
- query: string
412
- }
413
-
414
- /** Wire-side shape for a single resolved item — mirrors `MentionItem` from
415
- * `@pilotiq/tiptap`. Pilotiq core doesn't import that package, so the
416
- * duck-typed shape lives here. */
417
- export interface MentionResolveItem {
418
- id: string
419
- label: string
420
- group?: string
421
- }
422
-
423
- export interface MentionResolveSuccess {
424
- ok: true
425
- items: MentionResolveItem[]
426
- }
427
-
428
- export interface MentionResolveError {
429
- ok: false
430
- status: 404 | 422
431
- error: string
432
- }
433
-
434
- interface AsyncMentionResolverField {
435
- resolveMention(
436
- trigger: string,
437
- query: string,
438
- ctx: { user?: unknown; record?: unknown; request?: unknown },
439
- ): Promise<MentionResolveItem[] | null>
440
- }
441
-
442
- function isMentionResolverField(el: Element): el is Element & AsyncMentionResolverField {
443
- if (el.getType() !== 'richtext') return false
444
- const candidate = el as unknown as Partial<AsyncMentionResolverField>
445
- return typeof candidate.resolveMention === 'function'
446
- }
447
-
448
- /**
449
- * Walk a form's tree looking for the named field. Descends into Repeater /
450
- * Builder rows when the requested name carries the row-prefix shape:
451
- *
452
- * - Repeater rows: `<repeaterName>.<index>.<innerPath>` — looks up
453
- * `<innerPath>` against the Repeater's template schema. Field config
454
- * (providers, async resolver) is shared across rows, so any row index
455
- * resolves to the same template field.
456
- * - Builder rows: `<builderName>.<index>.data.<innerPath>` — looks up
457
- * `<innerPath>` against every block's schema; first match wins. Block
458
- * schemas often share leaf names — if two blocks define a RichTextField
459
- * with the same name and different async-mention providers, only the
460
- * first block in declaration order is reachable here. Authors needing
461
- * per-block resolution should give the leaves distinct names.
462
- *
463
- * Mirrors the boundary-stopping posture of `findFieldByName` inside
464
- * `dispatchForm.ts` for top-level matches — only the dotted-prefix branch
465
- * crosses into row schemas.
466
- */
467
- function findRichTextFieldByName(
468
- elements: ReadonlyArray<Element>,
469
- name: string,
470
- ): (Element & AsyncMentionResolverField) | undefined {
471
- for (const el of elements) {
472
- if (isMentionResolverField(el) && (el as unknown as { name: string }).name === name) {
473
- return el
474
- }
475
- if (isRepeaterField(el)) {
476
- const inner = stripRepeaterRowPrefix(name, (el as RepeaterField).name)
477
- if (inner !== undefined) {
478
- const hit = findRichTextFieldByName((el as RepeaterField).getInnerSchema(), inner)
479
- if (hit) return hit
480
- }
481
- continue
482
- }
483
- if (isBuilderField(el)) {
484
- const inner = stripBuilderRowPrefix(name, (el as BuilderField).name)
485
- if (inner !== undefined) {
486
- for (const block of (el as BuilderField).getBlocks()) {
487
- const hit = findRichTextFieldByName(block.getSchema(), inner)
488
- if (hit) return hit
489
- }
490
- }
491
- continue
492
- }
493
- const children = el.getChildren()
494
- if (children && children.length > 0) {
495
- const hit = findRichTextFieldByName(children, name)
496
- if (hit) return hit
497
- }
498
- }
499
- return undefined
500
- }
501
-
502
- /**
503
- * `items.0.body` → `body`. Returns `undefined` when the path doesn't match
504
- * the `<repeaterName>.<digits>.<rest>` shape so the walker keeps searching
505
- * other branches instead of misinterpreting an unrelated dotted name.
506
- */
507
- function stripRepeaterRowPrefix(path: string, repeaterName: string): string | undefined {
508
- const parts = path.split('.')
509
- if (parts.length < 3) return undefined
510
- if (parts[0] !== repeaterName) return undefined
511
- if (!/^\d+$/.test(parts[1] ?? '')) return undefined
512
- return parts.slice(2).join('.')
513
- }
514
-
515
- /**
516
- * `blocks.0.data.heading` → `heading`. The literal `data` segment matches
517
- * Builder's wire shape (`{ __id, type, data: {…} }`) and distinguishes a
518
- * Builder leaf from a Repeater leaf at the same depth.
519
- */
520
- function stripBuilderRowPrefix(path: string, builderName: string): string | undefined {
521
- const parts = path.split('.')
522
- if (parts.length < 4) return undefined
523
- if (parts[0] !== builderName) return undefined
524
- if (!/^\d+$/.test(parts[1] ?? '')) return undefined
525
- if (parts[2] !== 'data') return undefined
526
- return parts.slice(3).join('.')
527
- }
528
-
529
- /**
530
- * Resolve one async-mention round-trip. Locates the page's schema, finds
531
- * the form by `formId` and the RichTextField by `field`, calls its
532
- * `resolveMention(trigger, query, ctx)`. Returns `{ ok, items }`, a 404
533
- * when the form / field / trigger isn't present, or `null` for a missing
534
- * page (the route handler turns `null` into a 404 too).
535
- *
536
- * The dispatcher is duck-typed against the contract in `@pilotiq/tiptap`'s
537
- * `RichTextField` — pilotiq core never imports the adapter. Any future
538
- * field-type that ships an async-resolve trigger can implement the same
539
- * shape and pick up routing for free.
540
- */
541
- export async function mentionResolveData(
542
- pilotiq: Pilotiq,
543
- scope: FormStateScope,
544
- body: MentionResolveRequest,
545
- req?: unknown,
546
- ): Promise<MentionResolveSuccess | MentionResolveError | null> {
547
- const user = await pilotiq.resolveUser(req)
548
- const loaded = await resolveScopeForm(pilotiq, scope, body.formId, user)
549
- if (!loaded) return null
550
- if (!loaded.ok) return loaded
551
- const { form, record } = loaded
552
-
553
- const field = findRichTextFieldByName(form.getChildren() ?? [], body.field)
554
- if (!field) {
555
- return { ok: false, status: 404, error: `Rich-text field "${body.field}" not found on form "${body.formId}"` }
556
- }
557
-
558
- let items: MentionResolveItem[] | null
559
- try {
560
- items = await field.resolveMention(body.trigger, body.query, {
561
- ...(record !== undefined ? { record } : {}),
562
- ...(user !== null ? { user } : {}),
563
- request: req,
564
- })
565
- } catch (err) {
566
- return {
567
- ok: false,
568
- status: 422,
569
- error: err instanceof Error ? err.message : 'Mention resolver threw',
570
- }
571
- }
572
-
573
- if (items === null) {
574
- return { ok: false, status: 404, error: `No mention provider for trigger "${body.trigger}" on field "${body.field}"` }
575
- }
576
-
577
- return { ok: true, items }
578
- }