@pilotiq/pilotiq 0.23.1 → 0.24.2

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