@pilotiq/pilotiq 0.24.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 (480) hide show
  1. package/CHANGELOG.md +33 -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/package.json +6 -1
  15. package/.turbo/turbo-build.log +0 -8
  16. package/CLAUDE.md +0 -265
  17. package/src/Cluster.test.ts +0 -283
  18. package/src/Cluster.ts +0 -83
  19. package/src/Column.test.ts +0 -199
  20. package/src/Column.ts +0 -710
  21. package/src/Global.test.ts +0 -367
  22. package/src/Global.ts +0 -169
  23. package/src/Page.test.ts +0 -114
  24. package/src/Page.ts +0 -208
  25. package/src/Pilotiq.perf.test.ts +0 -252
  26. package/src/Pilotiq.test.ts +0 -129
  27. package/src/Pilotiq.ts +0 -1158
  28. package/src/PilotiqRegistry.ts +0 -36
  29. package/src/PilotiqServiceProvider.ts +0 -121
  30. package/src/RelationManager.test.ts +0 -400
  31. package/src/RelationManager.ts +0 -527
  32. package/src/RenderHook.test.ts +0 -252
  33. package/src/RenderHook.ts +0 -242
  34. package/src/Resource.test.ts +0 -284
  35. package/src/Resource.ts +0 -526
  36. package/src/RightPanel.test.ts +0 -202
  37. package/src/RightPanel.ts +0 -132
  38. package/src/Tab.test.ts +0 -91
  39. package/src/Tab.ts +0 -156
  40. package/src/UserMenuItem.ts +0 -145
  41. package/src/actions/Action.test.ts +0 -2526
  42. package/src/actions/Action.ts +0 -1515
  43. package/src/actions/ActionGroup.test.ts +0 -112
  44. package/src/actions/ActionGroup.ts +0 -173
  45. package/src/actions/attachFactory.ts +0 -172
  46. package/src/actions/bulkFactories.ts +0 -168
  47. package/src/actions/crudFactories.ts +0 -220
  48. package/src/actions/exportFactory.ts +0 -225
  49. package/src/actions/factoryHelpers.ts +0 -177
  50. package/src/actions/importFactory.ts +0 -243
  51. package/src/actions/index.ts +0 -17
  52. package/src/actions/m2mFactories.ts +0 -193
  53. package/src/actions/relationFactories.ts +0 -372
  54. package/src/applyPageHooks.test.ts +0 -463
  55. package/src/applyPageHooks.ts +0 -330
  56. package/src/authorization.test.ts +0 -483
  57. package/src/breadcrumbs.test.ts +0 -238
  58. package/src/cells/coerce.test.ts +0 -85
  59. package/src/cells/coerce.ts +0 -84
  60. package/src/clusterPaths.ts +0 -35
  61. package/src/columns/BadgeColumn.test.ts +0 -54
  62. package/src/columns/BadgeColumn.ts +0 -32
  63. package/src/columns/BooleanColumn.test.ts +0 -41
  64. package/src/columns/BooleanColumn.ts +0 -18
  65. package/src/columns/ColorColumn.test.ts +0 -37
  66. package/src/columns/ColorColumn.ts +0 -38
  67. package/src/columns/IconColumn.test.ts +0 -54
  68. package/src/columns/IconColumn.ts +0 -37
  69. package/src/columns/ImageColumn.test.ts +0 -41
  70. package/src/columns/ImageColumn.ts +0 -28
  71. package/src/columns/SelectColumn.ts +0 -98
  72. package/src/columns/TextColumn.test.ts +0 -190
  73. package/src/columns/TextColumn.ts +0 -20
  74. package/src/columns/TextInputColumn.ts +0 -68
  75. package/src/columns/ToggleColumn.ts +0 -46
  76. package/src/columns/editableColumns.test.ts +0 -238
  77. package/src/columns/index.ts +0 -9
  78. package/src/defaultGlobalPages.ts +0 -95
  79. package/src/defaultPages.test.ts +0 -634
  80. package/src/defaultPages.ts +0 -617
  81. package/src/defaultViewPage.test.ts +0 -147
  82. package/src/elements/Form.test.ts +0 -223
  83. package/src/elements/Form.ts +0 -416
  84. package/src/elements/ListTabs.ts +0 -28
  85. package/src/elements/Table.test.ts +0 -422
  86. package/src/elements/Table.ts +0 -850
  87. package/src/elements/TableGroup.test.ts +0 -260
  88. package/src/elements/TableGroup.ts +0 -334
  89. package/src/elements/dispatchAction.test.ts +0 -463
  90. package/src/elements/dispatchAction.ts +0 -355
  91. package/src/elements/dispatchForm.test.ts +0 -477
  92. package/src/elements/dispatchForm.ts +0 -1993
  93. package/src/elements/dispatchTable.test.ts +0 -1514
  94. package/src/elements/dispatchTable.ts +0 -745
  95. package/src/elements/index.ts +0 -21
  96. package/src/entries/BadgeEntry.ts +0 -39
  97. package/src/entries/CodeEntry.test.ts +0 -40
  98. package/src/entries/CodeEntry.ts +0 -52
  99. package/src/entries/ColorEntry.ts +0 -63
  100. package/src/entries/ComponentEntry.test.ts +0 -173
  101. package/src/entries/ComponentEntry.ts +0 -95
  102. package/src/entries/Entry.ts +0 -304
  103. package/src/entries/IconEntry.ts +0 -49
  104. package/src/entries/ImageEntry.ts +0 -61
  105. package/src/entries/KeyValueEntry.ts +0 -47
  106. package/src/entries/RepeatableEntry.test.ts +0 -239
  107. package/src/entries/RepeatableEntry.ts +0 -173
  108. package/src/entries/TextEntry.test.ts +0 -394
  109. package/src/entries/TextEntry.ts +0 -60
  110. package/src/entries/index.ts +0 -12
  111. package/src/entries/leaves.test.ts +0 -306
  112. package/src/entries/registry.ts +0 -54
  113. package/src/fields/BuilderField.test.ts +0 -1188
  114. package/src/fields/BuilderField.ts +0 -605
  115. package/src/fields/BuilderRelationship.test.ts +0 -811
  116. package/src/fields/CheckboxField.test.ts +0 -44
  117. package/src/fields/CheckboxField.ts +0 -27
  118. package/src/fields/CheckboxListField.test.ts +0 -99
  119. package/src/fields/CheckboxListField.ts +0 -66
  120. package/src/fields/ColorPickerField.test.ts +0 -33
  121. package/src/fields/ColorPickerField.ts +0 -25
  122. package/src/fields/DateField.ts +0 -54
  123. package/src/fields/DateTimeField.test.ts +0 -55
  124. package/src/fields/EmailField.ts +0 -16
  125. package/src/fields/Field.test.ts +0 -654
  126. package/src/fields/Field.ts +0 -817
  127. package/src/fields/FileUploadField.test.ts +0 -143
  128. package/src/fields/FileUploadField.ts +0 -159
  129. package/src/fields/HiddenField.test.ts +0 -27
  130. package/src/fields/HiddenField.ts +0 -28
  131. package/src/fields/KeyValueField.test.ts +0 -105
  132. package/src/fields/KeyValueField.ts +0 -55
  133. package/src/fields/MarkdownField.test.ts +0 -167
  134. package/src/fields/MarkdownField.ts +0 -162
  135. package/src/fields/NumberField.ts +0 -33
  136. package/src/fields/RadioField.test.ts +0 -94
  137. package/src/fields/RadioField.ts +0 -67
  138. package/src/fields/RepeaterField.test.ts +0 -1806
  139. package/src/fields/RepeaterField.ts +0 -939
  140. package/src/fields/RepeaterRelationship.test.ts +0 -1923
  141. package/src/fields/RepeaterSimple.test.ts +0 -248
  142. package/src/fields/RowButton.test.ts +0 -219
  143. package/src/fields/RowButton.ts +0 -135
  144. package/src/fields/SelectField.test.ts +0 -192
  145. package/src/fields/SelectField.ts +0 -235
  146. package/src/fields/SliderField.test.ts +0 -50
  147. package/src/fields/SliderField.ts +0 -53
  148. package/src/fields/SlugField.ts +0 -24
  149. package/src/fields/TagsInputField.test.ts +0 -154
  150. package/src/fields/TagsInputField.ts +0 -133
  151. package/src/fields/TextField.test.ts +0 -213
  152. package/src/fields/TextField.ts +0 -177
  153. package/src/fields/TextareaField.test.ts +0 -58
  154. package/src/fields/TextareaField.ts +0 -59
  155. package/src/fields/ToggleButtonsField.test.ts +0 -106
  156. package/src/fields/ToggleButtonsField.ts +0 -59
  157. package/src/fields/ToggleField.ts +0 -16
  158. package/src/fields/disableOptionsWhenSelectedInSiblingRepeaterItems.test.ts +0 -319
  159. package/src/fields/optionsResolver.ts +0 -95
  160. package/src/fields/resolveField.ts +0 -28
  161. package/src/filters/BooleanFilter.ts +0 -35
  162. package/src/filters/DateRangeFilter.test.ts +0 -194
  163. package/src/filters/DateRangeFilter.ts +0 -148
  164. package/src/filters/Filter.test.ts +0 -268
  165. package/src/filters/Filter.ts +0 -184
  166. package/src/filters/FormFilter.test.ts +0 -238
  167. package/src/filters/FormFilter.ts +0 -215
  168. package/src/filters/MultiSelectFilter.test.ts +0 -119
  169. package/src/filters/MultiSelectFilter.ts +0 -78
  170. package/src/filters/QueryBuilderFilter.test.ts +0 -662
  171. package/src/filters/QueryBuilderFilter.ts +0 -398
  172. package/src/filters/SelectFilter.ts +0 -46
  173. package/src/filters/TernaryFilter.test.ts +0 -160
  174. package/src/filters/TernaryFilter.ts +0 -72
  175. package/src/filters/TrashedFilter.test.ts +0 -149
  176. package/src/filters/TrashedFilter.ts +0 -55
  177. package/src/filters/queryBuilder/BooleanConstraint.ts +0 -31
  178. package/src/filters/queryBuilder/Constraint.ts +0 -115
  179. package/src/filters/queryBuilder/DateConstraint.ts +0 -69
  180. package/src/filters/queryBuilder/NumberConstraint.ts +0 -66
  181. package/src/filters/queryBuilder/SelectConstraint.ts +0 -72
  182. package/src/filters/queryBuilder/TextConstraint.ts +0 -64
  183. package/src/filters/queryBuilder/index.ts +0 -12
  184. package/src/icons/index.ts +0 -2
  185. package/src/icons/lucide.ts +0 -204
  186. package/src/icons/registry.test.ts +0 -56
  187. package/src/icons/registry.ts +0 -41
  188. package/src/icons/types.ts +0 -47
  189. package/src/index.ts +0 -525
  190. package/src/io/csv.test.ts +0 -142
  191. package/src/io/csv.ts +0 -170
  192. package/src/nestedRelationManagerData.test.ts +0 -547
  193. package/src/notifications/Notification.test.ts +0 -210
  194. package/src/notifications/Notification.ts +0 -354
  195. package/src/notifications/broadcast.test.ts +0 -110
  196. package/src/notifications/broadcast.ts +0 -95
  197. package/src/notifications/database.test.ts +0 -383
  198. package/src/notifications/database.ts +0 -398
  199. package/src/notifications/databaseNotifications.test.ts +0 -187
  200. package/src/notifications/dispatchNotificationAction.test.ts +0 -341
  201. package/src/notifications/dispatchNotificationAction.ts +0 -142
  202. package/src/notifications/flash.test.ts +0 -89
  203. package/src/notifications/flash.ts +0 -71
  204. package/src/notifications/index.ts +0 -45
  205. package/src/notifications/registerBroadcastAuth.test.ts +0 -134
  206. package/src/notifications/registerBroadcastAuth.ts +0 -100
  207. package/src/notifications/resolveSavedNotification.test.ts +0 -82
  208. package/src/notifications/resolveSavedNotification.ts +0 -59
  209. package/src/notifications/types.ts +0 -93
  210. package/src/orm/m2mAccessor.ts +0 -66
  211. package/src/orm/modelDefaults.test.ts +0 -633
  212. package/src/orm/modelDefaults.ts +0 -666
  213. package/src/pageData/breadcrumbs.ts +0 -288
  214. package/src/pageData/forms.ts +0 -578
  215. package/src/pageData/helpers.ts +0 -857
  216. package/src/pageData/misc.ts +0 -347
  217. package/src/pageData/navigation.ts +0 -842
  218. package/src/pageData/relationPages.ts +0 -1248
  219. package/src/pageData/relationTabs.ts +0 -286
  220. package/src/pageData/resourcePages.ts +0 -609
  221. package/src/pageData.test.ts +0 -1545
  222. package/src/pageData.ts +0 -341
  223. package/src/plugins/index.ts +0 -8
  224. package/src/plugins/themeEditor.test.ts +0 -36
  225. package/src/plugins/themeEditor.ts +0 -45
  226. package/src/react/AppShell.tsx +0 -251
  227. package/src/react/CollabExtensionFactoryRegistry.ts +0 -55
  228. package/src/react/CollabRoomContext.ts +0 -98
  229. package/src/react/CollabTextRendererRegistry.ts +0 -102
  230. package/src/react/CommandPalette.tsx +0 -375
  231. package/src/react/CurrentUserContext.tsx +0 -50
  232. package/src/react/CustomPageWrapperGate.tsx +0 -69
  233. package/src/react/CustomPageWrapperRegistry.ts +0 -45
  234. package/src/react/FieldFocusReporterRegistry.ts +0 -37
  235. package/src/react/FieldLabelSlotRegistry.ts +0 -30
  236. package/src/react/FieldPresenceRegistry.ts +0 -46
  237. package/src/react/FormCollabBindingRegistry.ts +0 -242
  238. package/src/react/FormStateContext.tsx +0 -591
  239. package/src/react/HeadHooks.tsx +0 -126
  240. package/src/react/MarkdownEditorRegistry.test.ts +0 -38
  241. package/src/react/MarkdownEditorRegistry.ts +0 -107
  242. package/src/react/NotificationActionStrip.tsx +0 -263
  243. package/src/react/NotificationBell.tsx +0 -426
  244. package/src/react/PendingSuggestionApplierRegistry.test.ts +0 -97
  245. package/src/react/PendingSuggestionApplierRegistry.ts +0 -98
  246. package/src/react/PendingSuggestionOverlayRegistry.ts +0 -54
  247. package/src/react/PendingSuggestionsContext.tsx +0 -172
  248. package/src/react/RecordWrapperGate.tsx +0 -58
  249. package/src/react/RecordWrapperRegistry.ts +0 -39
  250. package/src/react/RenderHookSlot.tsx +0 -32
  251. package/src/react/RightSidebar.tsx +0 -257
  252. package/src/react/RightSidebarContext.tsx +0 -234
  253. package/src/react/RightSidebarTrigger.tsx +0 -53
  254. package/src/react/RowCoordsContext.tsx +0 -23
  255. package/src/react/SchemaRenderer.tsx +0 -549
  256. package/src/react/SearchTrigger.tsx +0 -46
  257. package/src/react/ThemeProvider.tsx +0 -93
  258. package/src/react/ThemeSettingsPage.tsx +0 -579
  259. package/src/react/ThemeToggle.tsx +0 -20
  260. package/src/react/Toaster.tsx +0 -158
  261. package/src/react/UserMenu.tsx +0 -196
  262. package/src/react/WidgetDataContext.tsx +0 -157
  263. package/src/react/cells/EditableCell.tsx +0 -389
  264. package/src/react/component-slots.test.ts +0 -103
  265. package/src/react/component-slots.ts +0 -116
  266. package/src/react/fieldJsHandler.test.ts +0 -166
  267. package/src/react/fieldJsHandler.ts +0 -79
  268. package/src/react/fields/BuilderInput.tsx +0 -1078
  269. package/src/react/fields/CheckboxInput.tsx +0 -39
  270. package/src/react/fields/CheckboxListInput.tsx +0 -102
  271. package/src/react/fields/ColorInput.tsx +0 -71
  272. package/src/react/fields/DateFieldInput.tsx +0 -70
  273. package/src/react/fields/DateTimeInput.tsx +0 -62
  274. package/src/react/fields/FieldShell.tsx +0 -348
  275. package/src/react/fields/FileUploadInput.tsx +0 -639
  276. package/src/react/fields/HiddenInput.tsx +0 -17
  277. package/src/react/fields/KeyValueInput.tsx +0 -230
  278. package/src/react/fields/MarkdownInput.tsx +0 -560
  279. package/src/react/fields/RadioInput.tsx +0 -81
  280. package/src/react/fields/RepeaterInput.test.ts +0 -116
  281. package/src/react/fields/RepeaterInput.tsx +0 -1420
  282. package/src/react/fields/SelectFieldInput.tsx +0 -280
  283. package/src/react/fields/SliderInput.tsx +0 -81
  284. package/src/react/fields/TagsInput.tsx +0 -283
  285. package/src/react/fields/TextLikeInput.tsx +0 -256
  286. package/src/react/fields/ToggleButtonsInput.tsx +0 -60
  287. package/src/react/fields/ToggleFieldInput.tsx +0 -56
  288. package/src/react/fields/relationshipRenameDispatch.test.ts +0 -106
  289. package/src/react/fields/relationshipRenameDispatch.ts +0 -97
  290. package/src/react/fields/repeaterReconcile.test.ts +0 -114
  291. package/src/react/fields/repeaterReconcile.ts +0 -104
  292. package/src/react/fields/rowChromeButton.tsx +0 -336
  293. package/src/react/fields/rowState.ts +0 -106
  294. package/src/react/fields/syncRowGates.test.ts +0 -202
  295. package/src/react/fields/syncRowGates.ts +0 -66
  296. package/src/react/fields/textInputControls.tsx +0 -238
  297. package/src/react/fields/useRowReorderDnd.ts +0 -78
  298. package/src/react/formStateHelpers.test.ts +0 -508
  299. package/src/react/formStateHelpers.ts +0 -381
  300. package/src/react/hooks/use-mobile.ts +0 -19
  301. package/src/react/icon-context.tsx +0 -60
  302. package/src/react/index.ts +0 -194
  303. package/src/react/layouts/SidebarLayout.tsx +0 -250
  304. package/src/react/layouts/TopbarLayout.tsx +0 -258
  305. package/src/react/navigate.tsx +0 -37
  306. package/src/react/onProviderSynced.test.ts +0 -90
  307. package/src/react/parseRecordEditUrl.test.ts +0 -122
  308. package/src/react/parseRecordEditUrl.ts +0 -94
  309. package/src/react/persistedState.ts +0 -40
  310. package/src/react/registry.ts +0 -48
  311. package/src/react/right-panel-registry.tsx +0 -47
  312. package/src/react/schemaRenderer/AlertRenderer.tsx +0 -112
  313. package/src/react/schemaRenderer/EntryRenderer.tsx +0 -501
  314. package/src/react/schemaRenderer/SectionRenderer.tsx +0 -120
  315. package/src/react/schemaRenderer/SimpleElements.tsx +0 -306
  316. package/src/react/schemaRenderer/TabsRenderer.tsx +0 -62
  317. package/src/react/schemaRenderer/WizardRenderer.tsx +0 -338
  318. package/src/react/schemaRenderer/action/ActionGroupTrigger.tsx +0 -177
  319. package/src/react/schemaRenderer/action/ActionModalDialog.tsx +0 -273
  320. package/src/react/schemaRenderer/action/ConfirmActionDialog.tsx +0 -61
  321. package/src/react/schemaRenderer/action/HandlerActionButton.tsx +0 -43
  322. package/src/react/schemaRenderer/action/MethodActionButton.tsx +0 -64
  323. package/src/react/schemaRenderer/action/buttons.tsx +0 -99
  324. package/src/react/schemaRenderer/action/helpers.ts +0 -140
  325. package/src/react/schemaRenderer/action/renderAction.tsx +0 -245
  326. package/src/react/schemaRenderer/columnFormat.ts +0 -65
  327. package/src/react/schemaRenderer/constants.ts +0 -50
  328. package/src/react/schemaRenderer/form/FormRenderer.tsx +0 -274
  329. package/src/react/schemaRenderer/form/renderField.tsx +0 -511
  330. package/src/react/schemaRenderer/helpers.tsx +0 -81
  331. package/src/react/schemaRenderer/table/CardsLayoutBody.tsx +0 -308
  332. package/src/react/schemaRenderer/table/TableRenderer.tsx +0 -123
  333. package/src/react/schemaRenderer/table/TableRendererBody.tsx +0 -974
  334. package/src/react/schemaRenderer/table/filters.tsx +0 -1233
  335. package/src/react/schemaRenderer/table/formatCell.tsx +0 -264
  336. package/src/react/schemaRenderer/table/links.tsx +0 -112
  337. package/src/react/schemaRenderer/table/renderRowActions.tsx +0 -52
  338. package/src/react/schemaRenderer/table/url.tsx +0 -143
  339. package/src/react/theme-preview/apply.ts +0 -99
  340. package/src/react/theme-preview/build-html.ts +0 -436
  341. package/src/react/ui/button.tsx +0 -51
  342. package/src/react/ui/calendar.tsx +0 -67
  343. package/src/react/ui/checkbox.tsx +0 -29
  344. package/src/react/ui/dialog.tsx +0 -108
  345. package/src/react/ui/dropdown-menu.tsx +0 -97
  346. package/src/react/ui/input.tsx +0 -20
  347. package/src/react/ui/label.tsx +0 -21
  348. package/src/react/ui/popover.tsx +0 -50
  349. package/src/react/ui/select.tsx +0 -169
  350. package/src/react/ui/separator.tsx +0 -25
  351. package/src/react/ui/sheet.tsx +0 -136
  352. package/src/react/ui/sidebar.tsx +0 -723
  353. package/src/react/ui/skeleton.tsx +0 -13
  354. package/src/react/ui/slider.tsx +0 -34
  355. package/src/react/ui/switch.tsx +0 -28
  356. package/src/react/ui/table.tsx +0 -105
  357. package/src/react/ui/tabs.tsx +0 -63
  358. package/src/react/ui/textarea.tsx +0 -18
  359. package/src/react/ui/tooltip.tsx +0 -64
  360. package/src/react/useResizableWidth.ts +0 -139
  361. package/src/react/utils.ts +0 -6
  362. package/src/react/widgetRegistry.test.ts +0 -43
  363. package/src/react/widgetRegistry.ts +0 -50
  364. package/src/react/widgets/StatsOverviewRenderer.tsx +0 -232
  365. package/src/react/widgets/TableWidgetRenderer.tsx +0 -231
  366. package/src/react/widgets/ViewRenderer.tsx +0 -71
  367. package/src/relationManagerData.test.ts +0 -1595
  368. package/src/richtext/index.ts +0 -8
  369. package/src/richtext/registry.ts +0 -89
  370. package/src/routes/globals.ts +0 -148
  371. package/src/routes/guard.test.ts +0 -325
  372. package/src/routes/helpers.ts +0 -704
  373. package/src/routes/pages.ts +0 -175
  374. package/src/routes/panel.ts +0 -204
  375. package/src/routes/relations.ts +0 -1243
  376. package/src/routes/resources.ts +0 -781
  377. package/src/routes/theme.ts +0 -91
  378. package/src/routes-nested-relations.test.ts +0 -676
  379. package/src/routes-relations.test.ts +0 -972
  380. package/src/routes.test.ts +0 -2027
  381. package/src/routes.ts +0 -303
  382. package/src/schema/Alert.test.ts +0 -109
  383. package/src/schema/Alert.ts +0 -131
  384. package/src/schema/Block.ts +0 -169
  385. package/src/schema/Breadcrumbs.ts +0 -40
  386. package/src/schema/Card.ts +0 -35
  387. package/src/schema/Divider.ts +0 -20
  388. package/src/schema/Element.ts +0 -219
  389. package/src/schema/EmptyState.test.ts +0 -37
  390. package/src/schema/EmptyState.ts +0 -63
  391. package/src/schema/Fieldset.ts +0 -43
  392. package/src/schema/Grid.ts +0 -43
  393. package/src/schema/Group.ts +0 -30
  394. package/src/schema/Heading.ts +0 -39
  395. package/src/schema/Html.ts +0 -67
  396. package/src/schema/Icon.ts +0 -54
  397. package/src/schema/Image.ts +0 -57
  398. package/src/schema/LinkTag.ts +0 -41
  399. package/src/schema/Markdown.ts +0 -85
  400. package/src/schema/MetaTag.ts +0 -41
  401. package/src/schema/RelationTabs.ts +0 -71
  402. package/src/schema/ScriptTag.ts +0 -55
  403. package/src/schema/Section.ts +0 -160
  404. package/src/schema/ServerDataElement.test.ts +0 -140
  405. package/src/schema/ServerDataElement.ts +0 -156
  406. package/src/schema/SlotComponent.test.ts +0 -77
  407. package/src/schema/SlotComponent.ts +0 -71
  408. package/src/schema/Split.ts +0 -50
  409. package/src/schema/Stat.test.ts +0 -118
  410. package/src/schema/Stat.ts +0 -154
  411. package/src/schema/StatsOverview.test.ts +0 -141
  412. package/src/schema/StatsOverview.ts +0 -119
  413. package/src/schema/StyleTag.ts +0 -35
  414. package/src/schema/TableWidget.test.ts +0 -297
  415. package/src/schema/TableWidget.ts +0 -289
  416. package/src/schema/Tabs.ts +0 -79
  417. package/src/schema/Text.ts +0 -58
  418. package/src/schema/UnorderedList.ts +0 -49
  419. package/src/schema/View.test.ts +0 -111
  420. package/src/schema/View.ts +0 -127
  421. package/src/schema/Wizard.ts +0 -220
  422. package/src/schema/containers.test.ts +0 -564
  423. package/src/schema/headTags.test.ts +0 -134
  424. package/src/schema/index.ts +0 -40
  425. package/src/schema/primes.test.ts +0 -269
  426. package/src/schema/resolveSchema.test.ts +0 -379
  427. package/src/schema/resolveSchema.ts +0 -917
  428. package/src/schema/sanitize.ts +0 -58
  429. package/src/search.test.ts +0 -446
  430. package/src/search.ts +0 -178
  431. package/src/sessionFilters.test.ts +0 -375
  432. package/src/sessionFilters.ts +0 -143
  433. package/src/slot-components/index.ts +0 -10
  434. package/src/slot-components/registry.ts +0 -56
  435. package/src/styles/file-upload.css +0 -13
  436. package/src/summarizers/Summarizer.test.ts +0 -84
  437. package/src/summarizers/Summarizer.ts +0 -123
  438. package/src/summarizers/index.ts +0 -11
  439. package/src/theme/base-colors.ts +0 -68
  440. package/src/theme/chart-colors.ts +0 -50
  441. package/src/theme/colors.ts +0 -447
  442. package/src/theme/generate-css.test.ts +0 -139
  443. package/src/theme/generate-css.ts +0 -44
  444. package/src/theme/generate-scale.test.ts +0 -106
  445. package/src/theme/generate-scale.ts +0 -97
  446. package/src/theme/icon-map.ts +0 -42
  447. package/src/theme/index.ts +0 -34
  448. package/src/theme/migrate.test.ts +0 -178
  449. package/src/theme/migrate.ts +0 -81
  450. package/src/theme/presets.ts +0 -135
  451. package/src/theme/radius.ts +0 -18
  452. package/src/theme/resolve.test.ts +0 -238
  453. package/src/theme/resolve.ts +0 -96
  454. package/src/theme/spacing.ts +0 -18
  455. package/src/theme/storage.test.ts +0 -126
  456. package/src/theme/storage.ts +0 -106
  457. package/src/theme/theme-colors.ts +0 -88
  458. package/src/theme/types.ts +0 -125
  459. package/src/uploads/UploadAdapter.ts +0 -35
  460. package/src/uploads/index.ts +0 -2
  461. package/src/uploads/localUpload.test.ts +0 -70
  462. package/src/uploads/localUpload.ts +0 -84
  463. package/src/validation/Validator.ts +0 -49
  464. package/src/validation/index.ts +0 -28
  465. package/src/validation/rules.ts +0 -78
  466. package/src/validation/runValidators.ts +0 -435
  467. package/src/validation/uniqueValidator.test.ts +0 -196
  468. package/src/validation/uniqueValidator.ts +0 -133
  469. package/src/validation/validators.test.ts +0 -268
  470. package/src/vite.test.ts +0 -184
  471. package/src/vite.ts +0 -787
  472. package/src/widgets/index.ts +0 -10
  473. package/src/widgets/registry.ts +0 -45
  474. package/src/widgets.test.ts +0 -592
  475. package/tsconfig.build.json +0 -11
  476. package/tsconfig.json +0 -4
  477. package/tsconfig.test.json +0 -10
  478. package/views/react/Dashboard.tsx +0 -27
  479. package/views/react/Resources/Form.tsx +0 -102
  480. 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
- }