@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,126 +0,0 @@
1
- import { describe, it, beforeEach } from 'node:test'
2
- import assert from 'node:assert/strict'
3
- import { prismaThemeStorage } from './storage.js'
4
- import type { PanelGlobalDelegate } from './storage.js'
5
-
6
- /**
7
- * Per-test stub for the prisma panelGlobal delegate. Captures the args
8
- * each method was called with so tests can assert the exact wire shape
9
- * we send Prisma (slug, JSON-encoded data, etc).
10
- */
11
- interface PrismaStub extends PanelGlobalDelegate {
12
- rows: Map<string, { data: string | object | null }>
13
- calls: { method: string; args: unknown }[]
14
- /** When set, the next call to this method throws this error. */
15
- throwOnce?: { method: 'findUnique' | 'upsert' | 'delete'; error: unknown }
16
- }
17
-
18
- function makeStub(initial: Record<string, unknown> = {}): PrismaStub {
19
- const rows = new Map<string, { data: string | object | null }>()
20
- for (const [slug, data] of Object.entries(initial)) {
21
- rows.set(slug, { data: typeof data === 'string' ? data : JSON.stringify(data) })
22
- }
23
- const calls: { method: string; args: unknown }[] = []
24
- const stub: PrismaStub = {
25
- rows,
26
- calls,
27
- panelGlobal: {
28
- async findUnique(args) {
29
- calls.push({ method: 'findUnique', args })
30
- if (stub.throwOnce?.method === 'findUnique') {
31
- const e = stub.throwOnce.error; delete stub.throwOnce; throw e
32
- }
33
- return rows.get(args.where.slug) ?? null
34
- },
35
- async upsert(args) {
36
- calls.push({ method: 'upsert', args })
37
- if (stub.throwOnce?.method === 'upsert') {
38
- const e = stub.throwOnce.error; delete stub.throwOnce; throw e
39
- }
40
- rows.set(args.where.slug, { data: args.update.data })
41
- return undefined
42
- },
43
- async delete(args) {
44
- calls.push({ method: 'delete', args })
45
- if (stub.throwOnce?.method === 'delete') {
46
- const e = stub.throwOnce.error; delete stub.throwOnce; throw e
47
- }
48
- if (!rows.has(args.where.slug)) {
49
- const e: Error & { code?: string } = new Error('Record not found')
50
- e.code = 'P2025'
51
- throw e
52
- }
53
- rows.delete(args.where.slug)
54
- return undefined
55
- },
56
- },
57
- }
58
- return stub
59
- }
60
-
61
- describe('prismaThemeStorage', () => {
62
- let prisma: PrismaStub
63
-
64
- beforeEach(() => { prisma = makeStub() })
65
-
66
- it('load() returns null when no row exists', async () => {
67
- const storage = prismaThemeStorage(prisma, { slug: 'admin__theme' })
68
- assert.equal(await storage.load(), null)
69
- assert.deepEqual(prisma.calls, [{ method: 'findUnique', args: { where: { slug: 'admin__theme' } } }])
70
- })
71
-
72
- it('load() parses JSON-string data', async () => {
73
- prisma.rows.set('admin__theme', { data: JSON.stringify({ preset: 'nova' }) })
74
- const storage = prismaThemeStorage(prisma, { slug: 'admin__theme' })
75
- assert.deepEqual(await storage.load(), { preset: 'nova' })
76
- })
77
-
78
- it('load() passes through pre-parsed object data', async () => {
79
- prisma.rows.set('admin__theme', { data: { preset: 'maia' } })
80
- const storage = prismaThemeStorage(prisma, { slug: 'admin__theme' })
81
- assert.deepEqual(await storage.load(), { preset: 'maia' })
82
- })
83
-
84
- it('save() JSON-encodes the overrides via upsert', async () => {
85
- const storage = prismaThemeStorage(prisma, { slug: 'admin__theme' })
86
- await storage.save({ preset: 'lyra', radius: 'medium' })
87
- const stored = prisma.rows.get('admin__theme')
88
- assert.ok(stored)
89
- assert.equal(typeof stored.data, 'string')
90
- assert.deepEqual(JSON.parse(stored.data as string), { preset: 'lyra', radius: 'medium' })
91
- const upsertCall = prisma.calls.find(c => c.method === 'upsert')
92
- assert.ok(upsertCall, 'expected upsert call')
93
- })
94
-
95
- it('clear() deletes the row', async () => {
96
- prisma.rows.set('admin__theme', { data: '{}' })
97
- const storage = prismaThemeStorage(prisma, { slug: 'admin__theme' })
98
- await storage.clear()
99
- assert.equal(prisma.rows.has('admin__theme'), false)
100
- })
101
-
102
- it('clear() tolerates "row not found" (P2025)', async () => {
103
- const storage = prismaThemeStorage(prisma, { slug: 'admin__theme' })
104
- // Row does not exist — stub throws P2025 — clear() must not propagate.
105
- await storage.clear()
106
- })
107
-
108
- it('clear() rethrows non-P2025 errors', async () => {
109
- prisma.rows.set('admin__theme', { data: '{}' })
110
- prisma.throwOnce = { method: 'delete', error: new Error('connection lost') }
111
- const storage = prismaThemeStorage(prisma, { slug: 'admin__theme' })
112
- await assert.rejects(() => storage.clear(), /connection lost/)
113
- })
114
-
115
- it('save() bubbles non-P2025 errors', async () => {
116
- prisma.throwOnce = { method: 'upsert', error: new Error('connection lost') }
117
- const storage = prismaThemeStorage(prisma, { slug: 'admin__theme' })
118
- await assert.rejects(() => storage.save({ preset: 'nova' }), /connection lost/)
119
- })
120
-
121
- it('load() bubbles errors (callers swallow if they want back-compat)', async () => {
122
- prisma.throwOnce = { method: 'findUnique', error: new Error('connection lost') }
123
- const storage = prismaThemeStorage(prisma, { slug: 'admin__theme' })
124
- await assert.rejects(() => storage.load(), /connection lost/)
125
- })
126
- })
@@ -1,106 +0,0 @@
1
- import type { ThemeConfig } from './types.js'
2
-
3
- /**
4
- * Adapter that persists a panel's theme overrides — the JSON blob
5
- * written when a user edits theme settings via the `themeEditor()`
6
- * plugin and reloaded on next boot.
7
- *
8
- * The shipped implementation is `prismaThemeStorage`, which writes to
9
- * the `panelGlobal` row created by `@rudderjs/orm-prisma`. Apps on a
10
- * different ORM, key-value store, or filesystem can implement the
11
- * three methods themselves.
12
- *
13
- * Contract:
14
- *
15
- * - `load()` returns `null` when no overrides have been persisted yet
16
- * (fresh install). Throwing surfaces a configuration error to the
17
- * caller — pilotiq does not swallow.
18
- * - `save(overrides)` writes the blob verbatim. The next `load()` must
19
- * return a deep-equal copy. Throwing surfaces to the route handler
20
- * as a 500.
21
- * - `clear()` deletes the row. Tolerating "not found" is the adapter's
22
- * responsibility — `clear()` on an empty store is a no-op.
23
- */
24
- export interface ThemeStorageAdapter {
25
- load(): Promise<Partial<ThemeConfig> | null>
26
- save(overrides: Partial<ThemeConfig>): Promise<void>
27
- clear(): Promise<void>
28
- }
29
-
30
- /**
31
- * Minimal Prisma surface used by `prismaThemeStorage`. Narrow enough
32
- * to keep the import surface decoupled from `PrismaClient`'s generated
33
- * types — apps swap in any client whose `panelGlobal` delegate matches
34
- * this shape.
35
- */
36
- export interface PanelGlobalDelegate {
37
- panelGlobal: {
38
- findUnique(args: { where: { slug: string } }): Promise<{ data: string | object | null } | null>
39
- upsert(args: {
40
- where: { slug: string }
41
- update: { data: string }
42
- create: { slug: string; data: string }
43
- }): Promise<unknown>
44
- delete(args: { where: { slug: string } }): Promise<unknown>
45
- }
46
- }
47
-
48
- export interface PrismaThemeStorageOptions {
49
- /** Row key written to `panelGlobal.slug`. Pass per-panel so multiple
50
- * panels in the same app don't clobber each other. Typically
51
- * `${panel.name}__theme`. */
52
- slug: string
53
- }
54
-
55
- /**
56
- * Default storage adapter — writes JSON to the `panelGlobal` row keyed
57
- * by `opts.slug`. The Prisma delegate is dependency-injected so consumers
58
- * pick how to resolve it (e.g. `app.make('prisma')`, a direct import, a
59
- * test stub).
60
- *
61
- * @example
62
- * ```ts
63
- * import { Pilotiq } from '@pilotiq/pilotiq'
64
- * import { themeEditor, prismaThemeStorage } from '@pilotiq/pilotiq/plugins'
65
- *
66
- * const adminPanel = Pilotiq.make('Admin')
67
- * .use(themeEditor({
68
- * storage: prismaThemeStorage(prisma, { slug: 'admin__theme' }),
69
- * }))
70
- * ```
71
- */
72
- export function prismaThemeStorage(
73
- prisma: PanelGlobalDelegate,
74
- opts: PrismaThemeStorageOptions,
75
- ): ThemeStorageAdapter {
76
- const { slug } = opts
77
- return {
78
- async load() {
79
- const row = await prisma.panelGlobal.findUnique({ where: { slug } })
80
- if (!row?.data) return null
81
- const raw = typeof row.data === 'string' ? JSON.parse(row.data) : row.data
82
- return raw as Partial<ThemeConfig>
83
- },
84
- async save(overrides) {
85
- const data = JSON.stringify(overrides)
86
- await prisma.panelGlobal.upsert({
87
- where: { slug },
88
- update: { data },
89
- create: { slug, data },
90
- })
91
- },
92
- async clear() {
93
- try {
94
- await prisma.panelGlobal.delete({ where: { slug } })
95
- } catch (e) {
96
- if (!isRecordNotFound(e)) throw e
97
- }
98
- },
99
- }
100
- }
101
-
102
- function isRecordNotFound(e: unknown): boolean {
103
- return typeof e === 'object'
104
- && e !== null
105
- && (e as { code?: string }).code === 'P2025'
106
- }
@@ -1,88 +0,0 @@
1
- import { colors, HUE_NAMES, type ColorScale } from './colors.js'
2
- import type { BaseColor, HueColor, ThemeColor, PresetDefinition } from './types.js'
3
- import { parseSeedToScale } from './generate-scale.js'
4
-
5
- /**
6
- * Theme (primary) color resolution.
7
- *
8
- * The theme color drives `--primary`, `--primary-foreground`, `--ring`, and
9
- * the matching sidebar variants. Built from a `ColorScale` so adding a new
10
- * hue is just adding an entry to `colors.ts`.
11
- *
12
- * The `'base'` sentinel means "use the current base color" — resolution
13
- * pulls the matching scale from `colors[baseColor]` at call time.
14
- *
15
- * Custom seeds (raw hex / oklch strings outside the `HueColor` union) are
16
- * parsed into a synthetic 50…950 scale via `parseSeedToScale`.
17
- */
18
-
19
- /**
20
- * Build the primary/ring overrides for a given color scale.
21
- *
22
- * `isBase` toggles between two strategies:
23
- * - **base sentinel** (e.g. Theme = "Neutral"): use the strongest contrast
24
- * *within the same scale* — primary is scale[900] in light, scale[50] in
25
- * dark. Matches shadcn's neutral theme behavior (very dark/light primary).
26
- * - **hue** (e.g. Theme = "Blue"): use scale[600] in BOTH light and dark so
27
- * the brand color stays consistent across modes (instead of lifting to
28
- * scale[400] in dark, which dilutes brand identity). Foreground stays the
29
- * near-white neutral[50] for AA contrast against the saturated mid-tone.
30
- */
31
- function buildTheme(scale: ColorScale, isBase = false): PresetDefinition {
32
- if (isBase) {
33
- return {
34
- light: {
35
- '--primary': scale[900],
36
- '--primary-foreground': scale[50],
37
- '--ring': scale[400],
38
- '--sidebar-primary': scale[900],
39
- '--sidebar-primary-foreground': scale[50],
40
- '--sidebar-ring': scale[400],
41
- },
42
- dark: {
43
- '--primary': scale[50],
44
- '--primary-foreground': scale[900],
45
- '--ring': scale[600],
46
- '--sidebar-primary': scale[50],
47
- '--sidebar-primary-foreground': scale[900],
48
- '--sidebar-ring': scale[600],
49
- },
50
- }
51
- }
52
- return {
53
- light: {
54
- '--primary': scale[600],
55
- '--primary-foreground': colors.neutral[50],
56
- '--ring': scale[600],
57
- '--sidebar-primary': scale[600],
58
- '--sidebar-primary-foreground': colors.neutral[50],
59
- '--sidebar-ring': scale[600],
60
- },
61
- dark: {
62
- '--primary': scale[600],
63
- '--primary-foreground': colors.neutral[50],
64
- '--ring': scale[600],
65
- '--sidebar-primary': scale[600],
66
- '--sidebar-primary-foreground': colors.neutral[50],
67
- '--sidebar-ring': scale[600],
68
- },
69
- }
70
- }
71
-
72
- const themeColorMap: Record<HueColor, PresetDefinition> = Object.fromEntries(
73
- HUE_NAMES.map(name => [name, buildTheme(colors[name])]),
74
- ) as Record<HueColor, PresetDefinition>
75
-
76
- /**
77
- * Resolve a theme color value to its CSS variable overrides.
78
- *
79
- * @param themeColor selected value — `'base'`, a known hue, or a raw seed string
80
- * @param baseColor current base color (used to resolve `'base'` sentinel)
81
- */
82
- export function resolveThemeColor(themeColor: ThemeColor, baseColor: BaseColor): PresetDefinition {
83
- if (themeColor === 'base') return buildTheme(colors[baseColor], true)
84
- if (themeColor in themeColorMap) return themeColorMap[themeColor as HueColor]
85
- // Custom seed — parse and synthesize a scale.
86
- const synthetic = parseSeedToScale(themeColor)
87
- return synthetic ? buildTheme(synthetic) : buildTheme(colors[baseColor], true)
88
- }
@@ -1,125 +0,0 @@
1
- import { BASE_COLOR_NAMES, HUE_NAMES } from './colors.js'
2
-
3
- // ─── Style Presets ─────────────────────────────────────────
4
-
5
- /** Built-in style presets — each defines a complete set of OKLCH CSS variables.
6
- * `vega` is the Pilotiq brand (terracotta on cream, Satoshi). The other six are
7
- * placeholder neutrals awaiting visual differentiation. */
8
- export type StylePreset = 'vega' | 'nova' | 'maia' | 'lyra' | 'mira' | 'luma' | 'sera'
9
-
10
- // ─── Base Colors (gray/neutral scales) ─────────────────────
11
-
12
- /** Base color scale — controls the neutral/gray tones across the UI. */
13
- export type BaseColor = typeof BASE_COLOR_NAMES[number]
14
-
15
- // ─── Theme + Chart Colors ──────────────────────────────────
16
-
17
- /** Hue tokens shared by both the Theme color and Chart color pickers. */
18
- export type HueColor = typeof HUE_NAMES[number]
19
-
20
- /** Theme (primary) color — drives buttons, links, active states, ring.
21
- * `'base'` means "use the current base color's hue". Strings outside the
22
- * union are treated as raw hex/oklch seeds (custom color escape hatch). */
23
- export type ThemeColor = 'base' | HueColor | (string & {})
24
-
25
- /** Chart palette color — drives `--chart-1..5` as a single-hue ramp.
26
- * Same shape as `ThemeColor`. */
27
- export type ChartColor = ThemeColor
28
-
29
- // ─── Radius ────────────────────────────────────────────────
30
-
31
- /** Border radius preset. */
32
- export type RadiusPreset = 'none' | 'small' | 'default' | 'medium' | 'large' | 'xlarge'
33
-
34
- // ─── Spacing (UI density) ──────────────────────────────────
35
-
36
- /** Spacing density preset — drives Tailwind's `--spacing` multiplier so every
37
- * `p-*`, `gap-*`, `m-*` utility scales uniformly across the panel. */
38
- export type SpacingPreset = 'default' | 'compact' | 'comfortable'
39
-
40
- // ─── Icon Library ──────────────────────────────────────────
41
-
42
- /** Icon library identifier — controls which icon set is resolved. */
43
- export type IconLibrary = 'lucide' | 'tabler' | 'remix' | 'phosphor'
44
-
45
- // ─── Fonts ─────────────────────────────────────────────────
46
-
47
- export interface ThemeFonts {
48
- /** Google Fonts family name for headings, e.g. 'Space Grotesk'. */
49
- heading?: string
50
- /** Google Fonts family name for body text, e.g. 'Inter'. */
51
- body?: string
52
- }
53
-
54
- // ─── Theme Config (user-facing) ────────────────────────────
55
-
56
- /**
57
- * Theme configuration — passed to `Pilotiq.theme()`.
58
- *
59
- * @example
60
- * ```ts
61
- * Pilotiq.make('admin').theme({
62
- * preset: 'vega',
63
- * baseColor: 'taupe',
64
- * themeColor: 'orange',
65
- * chartColor: 'base',
66
- * radius: 'medium',
67
- * fonts: { heading: 'Space Grotesk', body: 'Inter' },
68
- * })
69
- * ```
70
- */
71
- export interface ThemeConfig {
72
- /** Style preset — sets all CSS variables at once. Defaults to `'vega'`. */
73
- preset?: StylePreset
74
- /** Base color scale — overrides neutral/gray tones from the preset. */
75
- baseColor?: BaseColor
76
- /** Theme (primary) color. `'base'` = derive from current base color. */
77
- themeColor?: ThemeColor
78
- /** Chart color. `'base'` = derive ramp from current base color. */
79
- chartColor?: ChartColor
80
- /** Border radius preset. Defaults to `'medium'` (Pilotiq brand). */
81
- radius?: RadiusPreset
82
- /** Spacing density preset. `'default'` falls through to the per-style value
83
- * in `PRESET_SPACING` (e.g. Mira → compact, Vega → comfortable). */
84
- spacing?: SpacingPreset
85
- /** Font families (loaded from Google Fonts / Fontshare). */
86
- fonts?: ThemeFonts
87
- /** Icon library. */
88
- iconLibrary?: IconLibrary
89
- /** Escape hatch: raw CSS variable overrides in OKLCH. Applied last, highest priority. */
90
- cssVariables?: {
91
- light?: Record<string, string>
92
- dark?: Record<string, string>
93
- }
94
- }
95
-
96
- // ─── Theme Meta (serialized, server → client) ──────────────
97
-
98
- /** Resolved theme data sent from server to client via viewProps. */
99
- export interface ThemeMeta {
100
- /** CSS variable map for :root (light mode). Keys are CSS custom property names. */
101
- light: Record<string, string>
102
- /** CSS variable map for .dark (dark mode). */
103
- dark: Record<string, string>
104
- /** Border radius value (e.g. '0.625rem'). */
105
- radius: string
106
- /** Spacing multiplier for Tailwind's `--spacing` token (e.g. '0.25rem'). */
107
- spacing: string
108
- /** Google Fonts families to load via <link> tag. */
109
- fonts?: ThemeFonts
110
- /** Font family CSS values with fallbacks (e.g. "'Inter', sans-serif"). */
111
- fontFamily?: {
112
- heading?: string
113
- body?: string
114
- }
115
- /** Icon library identifier for frontend icon resolution. */
116
- iconLibrary: IconLibrary
117
- }
118
-
119
- // ─── Preset Definition ─────────────────────────────────────
120
-
121
- /** A complete set of CSS variable values for light and dark modes (OKLCH strings). */
122
- export interface PresetDefinition {
123
- light: Record<string, string>
124
- dark: Record<string, string>
125
- }
@@ -1,35 +0,0 @@
1
- /**
2
- * Pilotiq's upload contract. Apps register an adapter via
3
- * `Pilotiq.uploads({ adapter })`; the `_uploads` route hands every
4
- * incoming file to it. Pilotiq stays storage-agnostic — disk, S3,
5
- * R2, GCS, or a custom storage backend all implement the same shape.
6
- */
7
- export interface UploadAdapter {
8
- /**
9
- * Persist the file. Receive `{ file, directory? }`; return the
10
- * URL the field should store. Throw to fail the upload — the
11
- * route handler converts thrown errors into a 500 + toast.
12
- */
13
- put(req: UploadRequest): Promise<UploadResult>
14
- }
15
-
16
- export interface UploadRequest {
17
- /** The browser-supplied File. Has `.name`, `.size`, `.type`, `.arrayBuffer()`. */
18
- file: File
19
- /** Optional sub-directory hint set by `FileUpload.directory(...)`. */
20
- directory?: string
21
- /** The source field name — useful for adapter routing or audit logs. */
22
- fieldName: string
23
- }
24
-
25
- export interface UploadResult {
26
- /** The public URL the field stores in the form value. */
27
- url: string
28
- /**
29
- * Optional metadata to round-trip alongside the URL — file size,
30
- * content type, etc. Renderers that show previews may use this.
31
- * Not part of the form value; can be used by `afterStateUpdated`
32
- * hooks server-side.
33
- */
34
- meta?: Record<string, unknown>
35
- }
@@ -1,2 +0,0 @@
1
- export type { UploadAdapter, UploadRequest, UploadResult } from './UploadAdapter.js'
2
- export { localUpload, type LocalUploadConfig } from './localUpload.js'
@@ -1,70 +0,0 @@
1
- import { describe, it, before, after } from 'node:test'
2
- import assert from 'node:assert/strict'
3
- import { mkdtempSync, existsSync, readFileSync, rmSync } from 'node:fs'
4
- import { tmpdir } from 'node:os'
5
- import { join } from 'node:path'
6
-
7
- import { localUpload } from './localUpload.js'
8
-
9
- describe('localUpload adapter', () => {
10
- let dir: string
11
-
12
- before(() => {
13
- dir = mkdtempSync(join(tmpdir(), 'pilotiq-uploads-'))
14
- })
15
-
16
- after(() => {
17
- rmSync(dir, { recursive: true, force: true })
18
- })
19
-
20
- it('writes the file under root + returns a URL', async () => {
21
- const adapter = localUpload({ root: dir, urlPrefix: '/uploads' })
22
- const file = new File([new Uint8Array([1, 2, 3, 4])], 'photo.png', { type: 'image/png' })
23
- const result = await adapter.put({ file, fieldName: 'cover' })
24
-
25
- assert.match(result.url, /^\/uploads\/[a-f0-9]{32}\.png$/)
26
- assert.deepEqual(result.meta, { name: 'photo.png', size: 4, type: 'image/png' })
27
-
28
- const filename = result.url.replace('/uploads/', '')
29
- const fullPath = join(dir, filename)
30
- assert.ok(existsSync(fullPath), 'file was written to disk')
31
- const written = readFileSync(fullPath)
32
- assert.deepEqual(Array.from(written), [1, 2, 3, 4])
33
- })
34
-
35
- it('honors the directory option', async () => {
36
- const adapter = localUpload({ root: dir, urlPrefix: '/uploads' })
37
- const file = new File([new Uint8Array([0])], 'img.jpg', { type: 'image/jpeg' })
38
- const result = await adapter.put({ file, fieldName: 'avatar', directory: 'avatars/2026' })
39
- assert.match(result.url, /^\/uploads\/avatars\/2026\/[a-f0-9]{32}\.jpg$/)
40
- })
41
-
42
- it('strips path-traversal segments from directory', async () => {
43
- const adapter = localUpload({ root: dir, urlPrefix: '/uploads' })
44
- const file = new File([new Uint8Array([0])], 'x.png', { type: 'image/png' })
45
- const result = await adapter.put({ file, fieldName: 'x', directory: '../../../etc/passwd' })
46
- assert.match(result.url, /^\/uploads\/etc\/passwd\/[a-f0-9]{32}\.png$/)
47
- })
48
-
49
- it('drops over-long extensions (anti-traversal)', async () => {
50
- const adapter = localUpload({ root: dir, urlPrefix: '/uploads' })
51
- const file = new File([new Uint8Array([0])], 'note.thisisaverylongext', { type: 'text/plain' })
52
- const result = await adapter.put({ file, fieldName: 'x' })
53
- // Disallowed ext (>10 chars) → file written without extension
54
- assert.match(result.url, /^\/uploads\/[a-f0-9]{32}$/)
55
- })
56
-
57
- it('drops extensions with non-alphanumeric chars', async () => {
58
- const adapter = localUpload({ root: dir, urlPrefix: '/uploads' })
59
- const file = new File([new Uint8Array([0])], 'note.png; rm -rf', { type: 'text/plain' })
60
- const result = await adapter.put({ file, fieldName: 'x' })
61
- assert.match(result.url, /^\/uploads\/[a-f0-9]{32}$/)
62
- })
63
-
64
- it('strips trailing slash from urlPrefix', async () => {
65
- const adapter = localUpload({ root: dir, urlPrefix: '/uploads/' })
66
- const file = new File([new Uint8Array([0])], 'x.png', { type: 'image/png' })
67
- const result = await adapter.put({ file, fieldName: 'x' })
68
- assert.match(result.url, /^\/uploads\/[a-f0-9]{32}\.png$/)
69
- })
70
- })
@@ -1,84 +0,0 @@
1
- import { mkdir, writeFile } from 'node:fs/promises'
2
- import { join, extname } from 'node:path'
3
- import { randomBytes } from 'node:crypto'
4
-
5
- import type { UploadAdapter, UploadRequest, UploadResult } from './UploadAdapter.js'
6
-
7
- export interface LocalUploadConfig {
8
- /**
9
- * Filesystem directory where files are written. Resolved relative to
10
- * `process.cwd()` if not absolute. The app's static-file middleware
11
- * must serve this directory at `urlPrefix`.
12
- *
13
- * Example: `{ root: 'public/uploads', urlPrefix: '/uploads' }` writes
14
- * to `<cwd>/public/uploads/<dir>/<id>.<ext>` and returns
15
- * `/uploads/<dir>/<id>.<ext>`.
16
- */
17
- root: string
18
- /** URL prefix the file is served from. Without trailing slash. */
19
- urlPrefix: string
20
- }
21
-
22
- /**
23
- * Disk-backed upload adapter. Writes incoming files under
24
- * `config.root/<directory>/<random-id>.<ext>` and returns the public
25
- * URL `<urlPrefix>/<directory>/<random-id>.<ext>`.
26
- *
27
- * v1: synchronous-ish (single `writeFile` per upload). No chunking,
28
- * no resumable uploads, no image processing.
29
- */
30
- export function localUpload(config: LocalUploadConfig): UploadAdapter {
31
- return {
32
- async put(req: UploadRequest): Promise<UploadResult> {
33
- const { file, directory } = req
34
- const ext = sanitizeExt(extname(file.name))
35
- const id = randomId()
36
- const subDir = sanitizeDir(directory)
37
- const fullDir = subDir
38
- ? join(config.root, subDir)
39
- : config.root
40
-
41
- await mkdir(fullDir, { recursive: true })
42
-
43
- const filename = `${id}${ext}`
44
- const fullPath = join(fullDir, filename)
45
- const buffer = Buffer.from(await file.arrayBuffer())
46
- await writeFile(fullPath, buffer)
47
-
48
- const urlParts = [config.urlPrefix.replace(/\/$/, '')]
49
- if (subDir) urlParts.push(subDir)
50
- urlParts.push(filename)
51
- return {
52
- url: urlParts.join('/'),
53
- meta: {
54
- name: file.name,
55
- size: file.size,
56
- type: file.type,
57
- },
58
- }
59
- },
60
- }
61
- }
62
-
63
- function sanitizeDir(d: string | undefined): string {
64
- if (!d) return ''
65
- // Strip leading/trailing slashes and any ../ segments to avoid path
66
- // traversal. Adapters are responsible for their own input validation.
67
- return d
68
- .replace(/^[/\\]+/, '')
69
- .replace(/[/\\]+$/, '')
70
- .split(/[/\\]/)
71
- .filter(s => s !== '' && s !== '..' && s !== '.')
72
- .join('/')
73
- }
74
-
75
- function sanitizeExt(ext: string): string {
76
- // Extension comes from a user-uploaded filename — keep it conservative.
77
- if (!ext || ext.length > 10) return ''
78
- if (!/^\.[A-Za-z0-9]+$/.test(ext)) return ''
79
- return ext.toLowerCase()
80
- }
81
-
82
- function randomId(): string {
83
- return randomBytes(16).toString('hex')
84
- }