@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.
- package/CHANGELOG.md +91 -0
- package/boost/guidelines.md +566 -0
- package/boost/skills/pilotiq-fields/SKILL.md +47 -0
- package/boost/skills/pilotiq-fields/rules/field-catalog.md +288 -0
- package/boost/skills/pilotiq-fields/rules/reactive-fields.md +199 -0
- package/boost/skills/pilotiq-fields/rules/validation.md +198 -0
- package/boost/skills/pilotiq-relations/SKILL.md +47 -0
- package/boost/skills/pilotiq-relations/rules/relation-managers.md +256 -0
- package/boost/skills/pilotiq-relations/rules/repeater-relationship.md +177 -0
- package/boost/skills/pilotiq-resource/SKILL.md +61 -0
- package/boost/skills/pilotiq-resource/rules/authorization.md +242 -0
- package/boost/skills/pilotiq-resource/rules/defining-resources.md +228 -0
- package/boost/skills/pilotiq-resource/rules/page-overrides.md +296 -0
- package/dist/actions/exportFactory.d.ts +10 -0
- package/dist/actions/exportFactory.d.ts.map +1 -1
- package/dist/actions/exportFactory.js +10 -0
- package/dist/actions/exportFactory.js.map +1 -1
- package/dist/react/CollabRoomContext.d.ts +5 -5
- package/dist/react/index.d.ts +0 -1
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +0 -1
- package/dist/react/index.js.map +1 -1
- package/dist/routes/helpers.d.ts.map +1 -1
- package/dist/routes/helpers.js +6 -2
- package/dist/routes/helpers.js.map +1 -1
- package/dist/routes/relations.d.ts.map +1 -1
- package/dist/routes/relations.js +12 -0
- package/dist/routes/relations.js.map +1 -1
- package/package.json +6 -1
- package/.turbo/turbo-build.log +0 -8
- package/CLAUDE.md +0 -265
- package/dist/react/useCollabSeed.d.ts +0 -23
- package/dist/react/useCollabSeed.d.ts.map +0 -1
- package/dist/react/useCollabSeed.js +0 -82
- package/dist/react/useCollabSeed.js.map +0 -1
- package/src/Cluster.test.ts +0 -283
- package/src/Cluster.ts +0 -83
- package/src/Column.test.ts +0 -199
- package/src/Column.ts +0 -710
- package/src/Global.test.ts +0 -367
- package/src/Global.ts +0 -169
- package/src/Page.test.ts +0 -114
- package/src/Page.ts +0 -208
- package/src/Pilotiq.perf.test.ts +0 -252
- package/src/Pilotiq.test.ts +0 -129
- package/src/Pilotiq.ts +0 -1158
- package/src/PilotiqRegistry.ts +0 -36
- package/src/PilotiqServiceProvider.ts +0 -121
- package/src/RelationManager.test.ts +0 -400
- package/src/RelationManager.ts +0 -527
- package/src/RenderHook.test.ts +0 -252
- package/src/RenderHook.ts +0 -242
- package/src/Resource.test.ts +0 -284
- package/src/Resource.ts +0 -526
- package/src/RightPanel.test.ts +0 -202
- package/src/RightPanel.ts +0 -132
- package/src/Tab.test.ts +0 -91
- package/src/Tab.ts +0 -156
- package/src/UserMenuItem.ts +0 -145
- package/src/actions/Action.test.ts +0 -2526
- package/src/actions/Action.ts +0 -1515
- package/src/actions/ActionGroup.test.ts +0 -112
- package/src/actions/ActionGroup.ts +0 -173
- package/src/actions/attachFactory.ts +0 -172
- package/src/actions/bulkFactories.ts +0 -168
- package/src/actions/crudFactories.ts +0 -220
- package/src/actions/exportFactory.ts +0 -215
- package/src/actions/factoryHelpers.ts +0 -177
- package/src/actions/importFactory.ts +0 -243
- package/src/actions/index.ts +0 -17
- package/src/actions/m2mFactories.ts +0 -193
- package/src/actions/relationFactories.ts +0 -372
- package/src/applyPageHooks.test.ts +0 -463
- package/src/applyPageHooks.ts +0 -330
- package/src/authorization.test.ts +0 -483
- package/src/breadcrumbs.test.ts +0 -238
- package/src/cells/coerce.test.ts +0 -85
- package/src/cells/coerce.ts +0 -84
- package/src/clusterPaths.ts +0 -35
- package/src/columns/BadgeColumn.test.ts +0 -54
- package/src/columns/BadgeColumn.ts +0 -32
- package/src/columns/BooleanColumn.test.ts +0 -41
- package/src/columns/BooleanColumn.ts +0 -18
- package/src/columns/ColorColumn.test.ts +0 -37
- package/src/columns/ColorColumn.ts +0 -38
- package/src/columns/IconColumn.test.ts +0 -54
- package/src/columns/IconColumn.ts +0 -37
- package/src/columns/ImageColumn.test.ts +0 -41
- package/src/columns/ImageColumn.ts +0 -28
- package/src/columns/SelectColumn.ts +0 -98
- package/src/columns/TextColumn.test.ts +0 -190
- package/src/columns/TextColumn.ts +0 -20
- package/src/columns/TextInputColumn.ts +0 -68
- package/src/columns/ToggleColumn.ts +0 -46
- package/src/columns/editableColumns.test.ts +0 -238
- package/src/columns/index.ts +0 -9
- package/src/defaultGlobalPages.ts +0 -95
- package/src/defaultPages.test.ts +0 -634
- package/src/defaultPages.ts +0 -617
- package/src/defaultViewPage.test.ts +0 -147
- package/src/elements/Form.test.ts +0 -223
- package/src/elements/Form.ts +0 -416
- package/src/elements/ListTabs.ts +0 -28
- package/src/elements/Table.test.ts +0 -422
- package/src/elements/Table.ts +0 -850
- package/src/elements/TableGroup.test.ts +0 -260
- package/src/elements/TableGroup.ts +0 -334
- package/src/elements/dispatchAction.test.ts +0 -463
- package/src/elements/dispatchAction.ts +0 -355
- package/src/elements/dispatchForm.test.ts +0 -477
- package/src/elements/dispatchForm.ts +0 -1993
- package/src/elements/dispatchTable.test.ts +0 -1514
- package/src/elements/dispatchTable.ts +0 -745
- package/src/elements/index.ts +0 -21
- package/src/entries/BadgeEntry.ts +0 -39
- package/src/entries/CodeEntry.test.ts +0 -40
- package/src/entries/CodeEntry.ts +0 -52
- package/src/entries/ColorEntry.ts +0 -63
- package/src/entries/ComponentEntry.test.ts +0 -173
- package/src/entries/ComponentEntry.ts +0 -95
- package/src/entries/Entry.ts +0 -304
- package/src/entries/IconEntry.ts +0 -49
- package/src/entries/ImageEntry.ts +0 -61
- package/src/entries/KeyValueEntry.ts +0 -47
- package/src/entries/RepeatableEntry.test.ts +0 -239
- package/src/entries/RepeatableEntry.ts +0 -173
- package/src/entries/TextEntry.test.ts +0 -394
- package/src/entries/TextEntry.ts +0 -60
- package/src/entries/index.ts +0 -12
- package/src/entries/leaves.test.ts +0 -306
- package/src/entries/registry.ts +0 -54
- package/src/fields/BuilderField.test.ts +0 -1188
- package/src/fields/BuilderField.ts +0 -605
- package/src/fields/BuilderRelationship.test.ts +0 -811
- package/src/fields/CheckboxField.test.ts +0 -44
- package/src/fields/CheckboxField.ts +0 -27
- package/src/fields/CheckboxListField.test.ts +0 -99
- package/src/fields/CheckboxListField.ts +0 -66
- package/src/fields/ColorPickerField.test.ts +0 -33
- package/src/fields/ColorPickerField.ts +0 -25
- package/src/fields/DateField.ts +0 -54
- package/src/fields/DateTimeField.test.ts +0 -55
- package/src/fields/EmailField.ts +0 -16
- package/src/fields/Field.test.ts +0 -654
- package/src/fields/Field.ts +0 -817
- package/src/fields/FileUploadField.test.ts +0 -143
- package/src/fields/FileUploadField.ts +0 -159
- package/src/fields/HiddenField.test.ts +0 -27
- package/src/fields/HiddenField.ts +0 -28
- package/src/fields/KeyValueField.test.ts +0 -105
- package/src/fields/KeyValueField.ts +0 -55
- package/src/fields/MarkdownField.test.ts +0 -167
- package/src/fields/MarkdownField.ts +0 -162
- package/src/fields/NumberField.ts +0 -33
- package/src/fields/RadioField.test.ts +0 -94
- package/src/fields/RadioField.ts +0 -67
- package/src/fields/RepeaterField.test.ts +0 -1806
- package/src/fields/RepeaterField.ts +0 -939
- package/src/fields/RepeaterRelationship.test.ts +0 -1923
- package/src/fields/RepeaterSimple.test.ts +0 -248
- package/src/fields/RowButton.test.ts +0 -219
- package/src/fields/RowButton.ts +0 -135
- package/src/fields/SelectField.test.ts +0 -192
- package/src/fields/SelectField.ts +0 -235
- package/src/fields/SliderField.test.ts +0 -50
- package/src/fields/SliderField.ts +0 -53
- package/src/fields/SlugField.ts +0 -24
- package/src/fields/TagsInputField.test.ts +0 -154
- package/src/fields/TagsInputField.ts +0 -133
- package/src/fields/TextField.test.ts +0 -213
- package/src/fields/TextField.ts +0 -177
- package/src/fields/TextareaField.test.ts +0 -58
- package/src/fields/TextareaField.ts +0 -59
- package/src/fields/ToggleButtonsField.test.ts +0 -106
- package/src/fields/ToggleButtonsField.ts +0 -59
- package/src/fields/ToggleField.ts +0 -16
- package/src/fields/disableOptionsWhenSelectedInSiblingRepeaterItems.test.ts +0 -319
- package/src/fields/optionsResolver.ts +0 -95
- package/src/fields/resolveField.ts +0 -28
- package/src/filters/BooleanFilter.ts +0 -35
- package/src/filters/DateRangeFilter.test.ts +0 -194
- package/src/filters/DateRangeFilter.ts +0 -148
- package/src/filters/Filter.test.ts +0 -268
- package/src/filters/Filter.ts +0 -184
- package/src/filters/FormFilter.test.ts +0 -238
- package/src/filters/FormFilter.ts +0 -215
- package/src/filters/MultiSelectFilter.test.ts +0 -119
- package/src/filters/MultiSelectFilter.ts +0 -78
- package/src/filters/QueryBuilderFilter.test.ts +0 -662
- package/src/filters/QueryBuilderFilter.ts +0 -398
- package/src/filters/SelectFilter.ts +0 -46
- package/src/filters/TernaryFilter.test.ts +0 -160
- package/src/filters/TernaryFilter.ts +0 -72
- package/src/filters/TrashedFilter.test.ts +0 -149
- package/src/filters/TrashedFilter.ts +0 -55
- package/src/filters/queryBuilder/BooleanConstraint.ts +0 -31
- package/src/filters/queryBuilder/Constraint.ts +0 -115
- package/src/filters/queryBuilder/DateConstraint.ts +0 -69
- package/src/filters/queryBuilder/NumberConstraint.ts +0 -66
- package/src/filters/queryBuilder/SelectConstraint.ts +0 -72
- package/src/filters/queryBuilder/TextConstraint.ts +0 -64
- package/src/filters/queryBuilder/index.ts +0 -12
- package/src/icons/index.ts +0 -2
- package/src/icons/lucide.ts +0 -204
- package/src/icons/registry.test.ts +0 -56
- package/src/icons/registry.ts +0 -41
- package/src/icons/types.ts +0 -47
- package/src/index.ts +0 -525
- package/src/io/csv.test.ts +0 -142
- package/src/io/csv.ts +0 -170
- package/src/nestedRelationManagerData.test.ts +0 -547
- package/src/notifications/Notification.test.ts +0 -210
- package/src/notifications/Notification.ts +0 -354
- package/src/notifications/broadcast.test.ts +0 -110
- package/src/notifications/broadcast.ts +0 -95
- package/src/notifications/database.test.ts +0 -383
- package/src/notifications/database.ts +0 -398
- package/src/notifications/databaseNotifications.test.ts +0 -187
- package/src/notifications/dispatchNotificationAction.test.ts +0 -341
- package/src/notifications/dispatchNotificationAction.ts +0 -142
- package/src/notifications/flash.test.ts +0 -89
- package/src/notifications/flash.ts +0 -71
- package/src/notifications/index.ts +0 -45
- package/src/notifications/registerBroadcastAuth.test.ts +0 -134
- package/src/notifications/registerBroadcastAuth.ts +0 -100
- package/src/notifications/resolveSavedNotification.test.ts +0 -82
- package/src/notifications/resolveSavedNotification.ts +0 -59
- package/src/notifications/types.ts +0 -93
- package/src/orm/m2mAccessor.ts +0 -66
- package/src/orm/modelDefaults.test.ts +0 -633
- package/src/orm/modelDefaults.ts +0 -666
- package/src/pageData/breadcrumbs.ts +0 -288
- package/src/pageData/forms.ts +0 -578
- package/src/pageData/helpers.ts +0 -857
- package/src/pageData/misc.ts +0 -347
- package/src/pageData/navigation.ts +0 -842
- package/src/pageData/relationPages.ts +0 -1248
- package/src/pageData/relationTabs.ts +0 -286
- package/src/pageData/resourcePages.ts +0 -609
- package/src/pageData.test.ts +0 -1545
- package/src/pageData.ts +0 -341
- package/src/plugins/index.ts +0 -8
- package/src/plugins/themeEditor.test.ts +0 -36
- package/src/plugins/themeEditor.ts +0 -45
- package/src/react/AppShell.tsx +0 -251
- package/src/react/CollabExtensionFactoryRegistry.ts +0 -55
- package/src/react/CollabRoomContext.ts +0 -98
- package/src/react/CollabTextRendererRegistry.ts +0 -102
- package/src/react/CommandPalette.tsx +0 -375
- package/src/react/CurrentUserContext.tsx +0 -50
- package/src/react/CustomPageWrapperGate.tsx +0 -69
- package/src/react/CustomPageWrapperRegistry.ts +0 -45
- package/src/react/FieldFocusReporterRegistry.ts +0 -37
- package/src/react/FieldLabelSlotRegistry.ts +0 -30
- package/src/react/FieldPresenceRegistry.ts +0 -46
- package/src/react/FormCollabBindingRegistry.ts +0 -242
- package/src/react/FormStateContext.tsx +0 -591
- package/src/react/HeadHooks.tsx +0 -126
- package/src/react/MarkdownEditorRegistry.test.ts +0 -38
- package/src/react/MarkdownEditorRegistry.ts +0 -107
- package/src/react/NotificationActionStrip.tsx +0 -263
- package/src/react/NotificationBell.tsx +0 -426
- package/src/react/PendingSuggestionApplierRegistry.test.ts +0 -97
- package/src/react/PendingSuggestionApplierRegistry.ts +0 -98
- package/src/react/PendingSuggestionOverlayRegistry.ts +0 -54
- package/src/react/PendingSuggestionsContext.tsx +0 -172
- package/src/react/RecordWrapperGate.tsx +0 -58
- package/src/react/RecordWrapperRegistry.ts +0 -39
- package/src/react/RenderHookSlot.tsx +0 -32
- package/src/react/RightSidebar.tsx +0 -257
- package/src/react/RightSidebarContext.tsx +0 -234
- package/src/react/RightSidebarTrigger.tsx +0 -53
- package/src/react/RowCoordsContext.tsx +0 -23
- package/src/react/SchemaRenderer.tsx +0 -549
- package/src/react/SearchTrigger.tsx +0 -46
- package/src/react/ThemeProvider.tsx +0 -93
- package/src/react/ThemeSettingsPage.tsx +0 -579
- package/src/react/ThemeToggle.tsx +0 -20
- package/src/react/Toaster.tsx +0 -158
- package/src/react/UserMenu.tsx +0 -196
- package/src/react/WidgetDataContext.tsx +0 -157
- package/src/react/cells/EditableCell.tsx +0 -389
- package/src/react/component-slots.test.ts +0 -103
- package/src/react/component-slots.ts +0 -116
- package/src/react/fieldJsHandler.test.ts +0 -166
- package/src/react/fieldJsHandler.ts +0 -79
- package/src/react/fields/BuilderInput.tsx +0 -1078
- package/src/react/fields/CheckboxInput.tsx +0 -39
- package/src/react/fields/CheckboxListInput.tsx +0 -102
- package/src/react/fields/ColorInput.tsx +0 -71
- package/src/react/fields/DateFieldInput.tsx +0 -70
- package/src/react/fields/DateTimeInput.tsx +0 -62
- package/src/react/fields/FieldShell.tsx +0 -348
- package/src/react/fields/FileUploadInput.tsx +0 -639
- package/src/react/fields/HiddenInput.tsx +0 -17
- package/src/react/fields/KeyValueInput.tsx +0 -230
- package/src/react/fields/MarkdownInput.tsx +0 -560
- package/src/react/fields/RadioInput.tsx +0 -81
- package/src/react/fields/RepeaterInput.test.ts +0 -116
- package/src/react/fields/RepeaterInput.tsx +0 -1420
- package/src/react/fields/SelectFieldInput.tsx +0 -280
- package/src/react/fields/SliderInput.tsx +0 -81
- package/src/react/fields/TagsInput.tsx +0 -283
- package/src/react/fields/TextLikeInput.tsx +0 -256
- package/src/react/fields/ToggleButtonsInput.tsx +0 -60
- package/src/react/fields/ToggleFieldInput.tsx +0 -56
- package/src/react/fields/relationshipRenameDispatch.test.ts +0 -106
- package/src/react/fields/relationshipRenameDispatch.ts +0 -97
- package/src/react/fields/repeaterReconcile.test.ts +0 -114
- package/src/react/fields/repeaterReconcile.ts +0 -104
- package/src/react/fields/rowChromeButton.tsx +0 -336
- package/src/react/fields/rowState.ts +0 -106
- package/src/react/fields/syncRowGates.test.ts +0 -202
- package/src/react/fields/syncRowGates.ts +0 -66
- package/src/react/fields/textInputControls.tsx +0 -238
- package/src/react/fields/useRowReorderDnd.ts +0 -78
- package/src/react/formStateHelpers.test.ts +0 -508
- package/src/react/formStateHelpers.ts +0 -381
- package/src/react/hooks/use-mobile.ts +0 -19
- package/src/react/icon-context.tsx +0 -60
- package/src/react/index.ts +0 -195
- package/src/react/layouts/SidebarLayout.tsx +0 -250
- package/src/react/layouts/TopbarLayout.tsx +0 -258
- package/src/react/navigate.tsx +0 -37
- package/src/react/onProviderSynced.test.ts +0 -90
- package/src/react/parseRecordEditUrl.test.ts +0 -122
- package/src/react/parseRecordEditUrl.ts +0 -94
- package/src/react/persistedState.ts +0 -40
- package/src/react/registry.ts +0 -48
- package/src/react/right-panel-registry.tsx +0 -47
- package/src/react/schemaRenderer/AlertRenderer.tsx +0 -112
- package/src/react/schemaRenderer/EntryRenderer.tsx +0 -501
- package/src/react/schemaRenderer/SectionRenderer.tsx +0 -120
- package/src/react/schemaRenderer/SimpleElements.tsx +0 -306
- package/src/react/schemaRenderer/TabsRenderer.tsx +0 -62
- package/src/react/schemaRenderer/WizardRenderer.tsx +0 -338
- package/src/react/schemaRenderer/action/ActionGroupTrigger.tsx +0 -177
- package/src/react/schemaRenderer/action/ActionModalDialog.tsx +0 -273
- package/src/react/schemaRenderer/action/ConfirmActionDialog.tsx +0 -61
- package/src/react/schemaRenderer/action/HandlerActionButton.tsx +0 -43
- package/src/react/schemaRenderer/action/MethodActionButton.tsx +0 -64
- package/src/react/schemaRenderer/action/buttons.tsx +0 -99
- package/src/react/schemaRenderer/action/helpers.ts +0 -140
- package/src/react/schemaRenderer/action/renderAction.tsx +0 -245
- package/src/react/schemaRenderer/columnFormat.ts +0 -65
- package/src/react/schemaRenderer/constants.ts +0 -50
- package/src/react/schemaRenderer/form/FormRenderer.tsx +0 -274
- package/src/react/schemaRenderer/form/renderField.tsx +0 -511
- package/src/react/schemaRenderer/helpers.tsx +0 -81
- package/src/react/schemaRenderer/table/CardsLayoutBody.tsx +0 -308
- package/src/react/schemaRenderer/table/TableRenderer.tsx +0 -123
- package/src/react/schemaRenderer/table/TableRendererBody.tsx +0 -974
- package/src/react/schemaRenderer/table/filters.tsx +0 -1233
- package/src/react/schemaRenderer/table/formatCell.tsx +0 -264
- package/src/react/schemaRenderer/table/links.tsx +0 -112
- package/src/react/schemaRenderer/table/renderRowActions.tsx +0 -52
- package/src/react/schemaRenderer/table/url.tsx +0 -143
- package/src/react/theme-preview/apply.ts +0 -99
- package/src/react/theme-preview/build-html.ts +0 -436
- package/src/react/ui/button.tsx +0 -51
- package/src/react/ui/calendar.tsx +0 -67
- package/src/react/ui/checkbox.tsx +0 -29
- package/src/react/ui/dialog.tsx +0 -108
- package/src/react/ui/dropdown-menu.tsx +0 -97
- package/src/react/ui/input.tsx +0 -20
- package/src/react/ui/label.tsx +0 -21
- package/src/react/ui/popover.tsx +0 -50
- package/src/react/ui/select.tsx +0 -169
- package/src/react/ui/separator.tsx +0 -25
- package/src/react/ui/sheet.tsx +0 -136
- package/src/react/ui/sidebar.tsx +0 -723
- package/src/react/ui/skeleton.tsx +0 -13
- package/src/react/ui/slider.tsx +0 -34
- package/src/react/ui/switch.tsx +0 -28
- package/src/react/ui/table.tsx +0 -105
- package/src/react/ui/tabs.tsx +0 -63
- package/src/react/ui/textarea.tsx +0 -18
- package/src/react/ui/tooltip.tsx +0 -64
- package/src/react/useCollabSeed.ts +0 -86
- package/src/react/useResizableWidth.ts +0 -139
- package/src/react/utils.ts +0 -6
- package/src/react/widgetRegistry.test.ts +0 -43
- package/src/react/widgetRegistry.ts +0 -50
- package/src/react/widgets/StatsOverviewRenderer.tsx +0 -232
- package/src/react/widgets/TableWidgetRenderer.tsx +0 -231
- package/src/react/widgets/ViewRenderer.tsx +0 -71
- package/src/relationManagerData.test.ts +0 -1595
- package/src/richtext/index.ts +0 -8
- package/src/richtext/registry.ts +0 -89
- package/src/routes/globals.ts +0 -148
- package/src/routes/guard.test.ts +0 -325
- package/src/routes/helpers.ts +0 -700
- package/src/routes/pages.ts +0 -175
- package/src/routes/panel.ts +0 -204
- package/src/routes/relations.ts +0 -1227
- package/src/routes/resources.ts +0 -781
- package/src/routes/theme.ts +0 -91
- package/src/routes-nested-relations.test.ts +0 -676
- package/src/routes-relations.test.ts +0 -972
- package/src/routes.test.ts +0 -2027
- package/src/routes.ts +0 -303
- package/src/schema/Alert.test.ts +0 -109
- package/src/schema/Alert.ts +0 -131
- package/src/schema/Block.ts +0 -169
- package/src/schema/Breadcrumbs.ts +0 -40
- package/src/schema/Card.ts +0 -35
- package/src/schema/Divider.ts +0 -20
- package/src/schema/Element.ts +0 -219
- package/src/schema/EmptyState.test.ts +0 -37
- package/src/schema/EmptyState.ts +0 -63
- package/src/schema/Fieldset.ts +0 -43
- package/src/schema/Grid.ts +0 -43
- package/src/schema/Group.ts +0 -30
- package/src/schema/Heading.ts +0 -39
- package/src/schema/Html.ts +0 -67
- package/src/schema/Icon.ts +0 -54
- package/src/schema/Image.ts +0 -57
- package/src/schema/LinkTag.ts +0 -41
- package/src/schema/Markdown.ts +0 -85
- package/src/schema/MetaTag.ts +0 -41
- package/src/schema/RelationTabs.ts +0 -71
- package/src/schema/ScriptTag.ts +0 -55
- package/src/schema/Section.ts +0 -160
- package/src/schema/ServerDataElement.test.ts +0 -140
- package/src/schema/ServerDataElement.ts +0 -156
- package/src/schema/SlotComponent.test.ts +0 -77
- package/src/schema/SlotComponent.ts +0 -71
- package/src/schema/Split.ts +0 -50
- package/src/schema/Stat.test.ts +0 -118
- package/src/schema/Stat.ts +0 -154
- package/src/schema/StatsOverview.test.ts +0 -141
- package/src/schema/StatsOverview.ts +0 -119
- package/src/schema/StyleTag.ts +0 -35
- package/src/schema/TableWidget.test.ts +0 -297
- package/src/schema/TableWidget.ts +0 -289
- package/src/schema/Tabs.ts +0 -79
- package/src/schema/Text.ts +0 -58
- package/src/schema/UnorderedList.ts +0 -49
- package/src/schema/View.test.ts +0 -111
- package/src/schema/View.ts +0 -127
- package/src/schema/Wizard.ts +0 -220
- package/src/schema/containers.test.ts +0 -564
- package/src/schema/headTags.test.ts +0 -134
- package/src/schema/index.ts +0 -40
- package/src/schema/primes.test.ts +0 -269
- package/src/schema/resolveSchema.test.ts +0 -379
- package/src/schema/resolveSchema.ts +0 -917
- package/src/schema/sanitize.ts +0 -58
- package/src/search.test.ts +0 -446
- package/src/search.ts +0 -178
- package/src/sessionFilters.test.ts +0 -375
- package/src/sessionFilters.ts +0 -143
- package/src/slot-components/index.ts +0 -10
- package/src/slot-components/registry.ts +0 -56
- package/src/styles/file-upload.css +0 -13
- package/src/summarizers/Summarizer.test.ts +0 -84
- package/src/summarizers/Summarizer.ts +0 -123
- package/src/summarizers/index.ts +0 -11
- package/src/theme/base-colors.ts +0 -68
- package/src/theme/chart-colors.ts +0 -50
- package/src/theme/colors.ts +0 -447
- package/src/theme/generate-css.test.ts +0 -139
- package/src/theme/generate-css.ts +0 -44
- package/src/theme/generate-scale.test.ts +0 -106
- package/src/theme/generate-scale.ts +0 -97
- package/src/theme/icon-map.ts +0 -42
- package/src/theme/index.ts +0 -34
- package/src/theme/migrate.test.ts +0 -178
- package/src/theme/migrate.ts +0 -81
- package/src/theme/presets.ts +0 -135
- package/src/theme/radius.ts +0 -18
- package/src/theme/resolve.test.ts +0 -238
- package/src/theme/resolve.ts +0 -96
- package/src/theme/spacing.ts +0 -18
- package/src/theme/storage.test.ts +0 -126
- package/src/theme/storage.ts +0 -106
- package/src/theme/theme-colors.ts +0 -88
- package/src/theme/types.ts +0 -125
- package/src/uploads/UploadAdapter.ts +0 -35
- package/src/uploads/index.ts +0 -2
- package/src/uploads/localUpload.test.ts +0 -70
- package/src/uploads/localUpload.ts +0 -84
- package/src/validation/Validator.ts +0 -49
- package/src/validation/index.ts +0 -28
- package/src/validation/rules.ts +0 -78
- package/src/validation/runValidators.ts +0 -435
- package/src/validation/uniqueValidator.test.ts +0 -196
- package/src/validation/uniqueValidator.ts +0 -133
- package/src/validation/validators.test.ts +0 -268
- package/src/vite.test.ts +0 -184
- package/src/vite.ts +0 -787
- package/src/widgets/index.ts +0 -10
- package/src/widgets/registry.ts +0 -45
- package/src/widgets.test.ts +0 -592
- package/tsconfig.build.json +0 -11
- package/tsconfig.json +0 -4
- package/tsconfig.test.json +0 -10
- package/views/react/Dashboard.tsx +0 -27
- package/views/react/Resources/Form.tsx +0 -102
- package/views/react/Resources/Index.tsx +0 -49
|
@@ -1,483 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plan #10 — authorization.
|
|
3
|
-
*
|
|
4
|
-
* Covers:
|
|
5
|
-
* - `Pilotiq.user(fn)` resolver + `resolveUser(req)` helper.
|
|
6
|
-
* - `Resource` / `Global` / `Page` `canX` defaults + override behavior.
|
|
7
|
-
* - Auto-attached visibility on `Action.create / edit / view / delete`
|
|
8
|
-
* factories (consults `R.canX`, opts out via explicit `.visible(...)`).
|
|
9
|
-
* - `panelInfo()` nav-tree filter — items dropped when `canAccess`
|
|
10
|
-
* returns false.
|
|
11
|
-
* - 403 forbidden response shape (HTML vs JSON).
|
|
12
|
-
* - Async `Action.evaluate()` — promise rules, throwing rules.
|
|
13
|
-
*/
|
|
14
|
-
import { describe, it, beforeEach } from 'node:test'
|
|
15
|
-
import assert from 'node:assert/strict'
|
|
16
|
-
|
|
17
|
-
import { Pilotiq } from './Pilotiq.js'
|
|
18
|
-
import { Resource } from './Resource.js'
|
|
19
|
-
import { Global } from './Global.js'
|
|
20
|
-
import { Page } from './Page.js'
|
|
21
|
-
import { Action } from './actions/Action.js'
|
|
22
|
-
import { panelInfo } from './pageData.js'
|
|
23
|
-
import { _resetResolverRegistry } from './schema/resolveSchema.js'
|
|
24
|
-
import { Router } from '@rudderjs/router'
|
|
25
|
-
import { registerPilotiqRoutes } from './routes.js'
|
|
26
|
-
|
|
27
|
-
beforeEach(() => _resetResolverRegistry())
|
|
28
|
-
|
|
29
|
-
// ─── Pilotiq.user(fn) resolver ────────────────────────────────
|
|
30
|
-
|
|
31
|
-
describe('Pilotiq.user(fn)', () => {
|
|
32
|
-
it('resolveUser returns null when no resolver is configured', async () => {
|
|
33
|
-
const p = Pilotiq.make('admin')
|
|
34
|
-
assert.equal(await p.resolveUser({}), null)
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
it('forwards the request and returns the resolved user', async () => {
|
|
38
|
-
const p = Pilotiq.make('admin').user((req) => ({ id: '1', from: (req as { tag: string }).tag }))
|
|
39
|
-
const out = await p.resolveUser({ tag: 'req-x' })
|
|
40
|
-
assert.deepEqual(out, { id: '1', from: 'req-x' })
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
it('awaits async resolvers', async () => {
|
|
44
|
-
const p = Pilotiq.make('admin').user(async () => ({ id: '7' }))
|
|
45
|
-
assert.deepEqual(await p.resolveUser({}), { id: '7' })
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
it('swallows resolver throws and returns null (fail closed)', async () => {
|
|
49
|
-
const p = Pilotiq.make('admin').user(() => { throw new Error('auth down') })
|
|
50
|
-
assert.equal(await p.resolveUser({}), null)
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
it('coerces returned undefined to null', async () => {
|
|
54
|
-
const p = Pilotiq.make('admin').user(() => undefined)
|
|
55
|
-
assert.equal(await p.resolveUser({}), null)
|
|
56
|
-
})
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
// ─── Resource / Global / Page can* defaults ───────────────────
|
|
60
|
-
|
|
61
|
-
describe('Resource policy defaults', () => {
|
|
62
|
-
it('all six predicates default to true', async () => {
|
|
63
|
-
class R extends Resource {
|
|
64
|
-
static override label = 'Things'
|
|
65
|
-
}
|
|
66
|
-
assert.equal(await R.canAccess(null), true)
|
|
67
|
-
assert.equal(await R.canViewAny(null), true)
|
|
68
|
-
assert.equal(await R.canView(null, {}), true)
|
|
69
|
-
assert.equal(await R.canCreate(null), true)
|
|
70
|
-
assert.equal(await R.canEdit(null, {}), true)
|
|
71
|
-
assert.equal(await R.canDelete(null, {}), true)
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
it('override checks the user', async () => {
|
|
75
|
-
class R extends Resource {
|
|
76
|
-
static override label = 'Articles'
|
|
77
|
-
static override async canDelete(user: unknown, _record: unknown) {
|
|
78
|
-
return (user as { role?: string })?.role === 'admin'
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
assert.equal(await R.canDelete({ role: 'admin' }, {}), true)
|
|
82
|
-
assert.equal(await R.canDelete({ role: 'editor' }, {}), false)
|
|
83
|
-
assert.equal(await R.canDelete(null, {}), false)
|
|
84
|
-
})
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
describe('Global policy defaults', () => {
|
|
88
|
-
it('exposes only canAccess + canView + canEdit', async () => {
|
|
89
|
-
class G extends Global {
|
|
90
|
-
static override label = 'Site'
|
|
91
|
-
}
|
|
92
|
-
assert.equal(await G.canAccess(null), true)
|
|
93
|
-
assert.equal(await G.canView(null, {}), true)
|
|
94
|
-
assert.equal(await G.canEdit(null, {}), true)
|
|
95
|
-
// Globals don't expose canViewAny / canCreate / canDelete — these
|
|
96
|
-
// are not on the static interface.
|
|
97
|
-
assert.equal((G as unknown as { canCreate?: unknown }).canCreate, undefined)
|
|
98
|
-
assert.equal((G as unknown as { canDelete?: unknown }).canDelete, undefined)
|
|
99
|
-
})
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
describe('Page policy default', () => {
|
|
103
|
-
it('exposes a canAccess gate that defaults to true', async () => {
|
|
104
|
-
class P extends Page {}
|
|
105
|
-
assert.equal(await P.canAccess(null), true)
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
it('override gates by user', async () => {
|
|
109
|
-
class P extends Page {
|
|
110
|
-
static override async canAccess(user: unknown) {
|
|
111
|
-
return (user as { role?: string })?.role === 'admin'
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
assert.equal(await P.canAccess({ role: 'admin' }), true)
|
|
115
|
-
assert.equal(await P.canAccess({ role: 'guest' }), false)
|
|
116
|
-
})
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
// ─── Action factory auto-visibility ───────────────────────────
|
|
120
|
-
|
|
121
|
-
describe('Action factory auto-visibility', () => {
|
|
122
|
-
it('Action.create is hidden when R.canCreate returns false', async () => {
|
|
123
|
-
class R extends Resource {
|
|
124
|
-
static override label = 'Articles'
|
|
125
|
-
static override labelSingular = 'Article'
|
|
126
|
-
static override async canCreate() { return false }
|
|
127
|
-
}
|
|
128
|
-
const a = Action.create(R, '/admin')
|
|
129
|
-
const result = await a.evaluate({ user: null })
|
|
130
|
-
assert.equal(result.visible, false)
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
it('Action.edit consults R.canEdit with user + record', async () => {
|
|
134
|
-
class R extends Resource {
|
|
135
|
-
static override label = 'Articles'
|
|
136
|
-
static override async canEdit(_user: unknown, record: unknown) {
|
|
137
|
-
return (record as { ownerId?: string })?.ownerId === 'me'
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
const a = Action.edit(R, '/admin')
|
|
141
|
-
assert.equal((await a.evaluate({ record: { ownerId: 'me' } })).visible, true)
|
|
142
|
-
assert.equal((await a.evaluate({ record: { ownerId: 'other' } })).visible, false)
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
it('Action.delete consults R.canDelete', async () => {
|
|
146
|
-
class R extends Resource {
|
|
147
|
-
static override label = 'Articles'
|
|
148
|
-
static override labelSingular = 'Article'
|
|
149
|
-
static override async canDelete(user: unknown) {
|
|
150
|
-
return (user as { admin?: boolean })?.admin === true
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
const a = Action.delete(R, '/admin')
|
|
154
|
-
assert.equal((await a.evaluate({ user: { admin: true } })).visible, true)
|
|
155
|
-
assert.equal((await a.evaluate({ user: { admin: false } })).visible, false)
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
it('Action.view consults R.canView', async () => {
|
|
159
|
-
class R extends Resource {
|
|
160
|
-
static override label = 'Articles'
|
|
161
|
-
static override async canView(_user: unknown, record: unknown) {
|
|
162
|
-
return (record as { published?: boolean })?.published === true
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
const a = Action.view(R, '/admin')
|
|
166
|
-
assert.equal((await a.evaluate({ record: { published: true } })).visible, true)
|
|
167
|
-
assert.equal((await a.evaluate({ record: { published: false } })).visible, false)
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
it('explicit .visible(true) after the factory wins', async () => {
|
|
171
|
-
class R extends Resource {
|
|
172
|
-
static override label = 'Articles'
|
|
173
|
-
static override labelSingular = 'Article'
|
|
174
|
-
static override async canDelete() { return false }
|
|
175
|
-
}
|
|
176
|
-
const a = Action.delete(R, '/admin').visible(true)
|
|
177
|
-
assert.equal((await a.evaluate()).visible, true)
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
it('factories carry hasVisibilityRules() = true', () => {
|
|
181
|
-
class R extends Resource {
|
|
182
|
-
static override label = 'Articles'
|
|
183
|
-
static override labelSingular = 'Article'
|
|
184
|
-
}
|
|
185
|
-
assert.equal(Action.create(R, '/x').hasVisibilityRules(), true)
|
|
186
|
-
assert.equal(Action.edit(R, '/x').hasVisibilityRules(), true)
|
|
187
|
-
assert.equal(Action.view(R, '/x').hasVisibilityRules(), true)
|
|
188
|
-
assert.equal(Action.delete(R, '/x').hasVisibilityRules(), true)
|
|
189
|
-
})
|
|
190
|
-
|
|
191
|
-
it('factory visibility on a Resource without overrides defaults to allowed', async () => {
|
|
192
|
-
// No override → static can* returns true → factory action visible.
|
|
193
|
-
class R extends Resource {
|
|
194
|
-
static override label = 'Articles'
|
|
195
|
-
static override labelSingular = 'Article'
|
|
196
|
-
}
|
|
197
|
-
assert.equal((await Action.create(R, '/x').evaluate({ user: null })).visible, true)
|
|
198
|
-
assert.equal((await Action.edit(R, '/x').evaluate({ user: null, record: {} })).visible, true)
|
|
199
|
-
})
|
|
200
|
-
})
|
|
201
|
-
|
|
202
|
-
// ─── Nav-tree filter (panelInfo) ──────────────────────────────
|
|
203
|
-
|
|
204
|
-
describe('panelInfo navigation filter', () => {
|
|
205
|
-
it('drops resources whose canAccess returns false', async () => {
|
|
206
|
-
class Allowed extends Resource {
|
|
207
|
-
static override label = 'Allowed'
|
|
208
|
-
}
|
|
209
|
-
class Denied extends Resource {
|
|
210
|
-
static override label = 'Denied'
|
|
211
|
-
static override async canAccess() { return false }
|
|
212
|
-
}
|
|
213
|
-
const p = Pilotiq.make('admin').resources([Allowed, Denied])
|
|
214
|
-
const info = await panelInfo(p, {})
|
|
215
|
-
const names = info.navigation.map(n => n.name)
|
|
216
|
-
assert.ok(names.includes('Allowed'), 'Allowed resource should appear in nav')
|
|
217
|
-
assert.ok(!names.includes('Denied'), 'Denied resource should not appear in nav')
|
|
218
|
-
})
|
|
219
|
-
|
|
220
|
-
it('threads the user into canAccess via the resolver', async () => {
|
|
221
|
-
const seen: unknown[] = []
|
|
222
|
-
class R extends Resource {
|
|
223
|
-
static override label = 'Articles'
|
|
224
|
-
static override async canAccess(user: unknown) {
|
|
225
|
-
seen.push(user)
|
|
226
|
-
return Boolean((user as { admin?: boolean })?.admin)
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
const adminPanel = Pilotiq.make('admin')
|
|
230
|
-
.resources([R])
|
|
231
|
-
.user(req => (req as { user?: unknown })?.user ?? null)
|
|
232
|
-
|
|
233
|
-
const adminNav = await panelInfo(adminPanel, { user: { admin: true } })
|
|
234
|
-
assert.equal(adminNav.navigation.length, 1)
|
|
235
|
-
|
|
236
|
-
const guestNav = await panelInfo(adminPanel, { user: { admin: false } })
|
|
237
|
-
assert.equal(guestNav.navigation.length, 0)
|
|
238
|
-
|
|
239
|
-
assert.deepEqual(seen, [{ admin: true }, { admin: false }])
|
|
240
|
-
})
|
|
241
|
-
|
|
242
|
-
it('drops globals + custom pages on canAccess fail', async () => {
|
|
243
|
-
class G extends Global {
|
|
244
|
-
static override label = 'Settings'
|
|
245
|
-
static override async canAccess() { return false }
|
|
246
|
-
}
|
|
247
|
-
class P extends Page {
|
|
248
|
-
static override slug = 'analytics'
|
|
249
|
-
static override async canAccess() { return false }
|
|
250
|
-
}
|
|
251
|
-
const p = Pilotiq.make('admin').globals([G]).pages([P])
|
|
252
|
-
const info = await panelInfo(p)
|
|
253
|
-
assert.equal(info.navigation.length, 0)
|
|
254
|
-
})
|
|
255
|
-
|
|
256
|
-
it('a throwing canAccess fails closed (item dropped)', async () => {
|
|
257
|
-
class R extends Resource {
|
|
258
|
-
static override label = 'Boom'
|
|
259
|
-
static override async canAccess(): Promise<boolean> { throw new Error('boom') }
|
|
260
|
-
}
|
|
261
|
-
const p = Pilotiq.make('admin').resources([R])
|
|
262
|
-
const info = await panelInfo(p)
|
|
263
|
-
assert.equal(info.navigation.length, 0)
|
|
264
|
-
})
|
|
265
|
-
})
|
|
266
|
-
|
|
267
|
-
// ─── Async Action.evaluate — already covered in Action.test.ts;
|
|
268
|
-
// these focus on the policy-style interaction.
|
|
269
|
-
|
|
270
|
-
describe('Action.evaluate async with policy', () => {
|
|
271
|
-
it('a Promise<boolean> visibility rule resolves correctly', async () => {
|
|
272
|
-
const a = Action.make('x').visible(async () => true)
|
|
273
|
-
assert.equal((await a.evaluate()).visible, true)
|
|
274
|
-
})
|
|
275
|
-
|
|
276
|
-
it('a throwing visibility rule fails closed', async () => {
|
|
277
|
-
const a = Action.make('x').visible(async () => { throw new Error('x') })
|
|
278
|
-
assert.equal((await a.evaluate()).visible, false)
|
|
279
|
-
})
|
|
280
|
-
})
|
|
281
|
-
|
|
282
|
-
// ─── Routes / 403 wiring ──────────────────────────────────────
|
|
283
|
-
|
|
284
|
-
interface FakeRes {
|
|
285
|
-
statusCode: number
|
|
286
|
-
sentBody?: unknown
|
|
287
|
-
status(code: number): FakeRes
|
|
288
|
-
send(body: unknown): FakeRes
|
|
289
|
-
json(body: unknown): FakeRes
|
|
290
|
-
redirect(url: string, code?: number): FakeRes
|
|
291
|
-
}
|
|
292
|
-
// Cast to any when passing into route handlers: AppResponse demands
|
|
293
|
-
// `header` + `raw`, neither of which the policy gate touches.
|
|
294
|
-
function fakeRes(): any {
|
|
295
|
-
const r: FakeRes = {
|
|
296
|
-
statusCode: 200,
|
|
297
|
-
status(code) { this.statusCode = code; return this },
|
|
298
|
-
send(body) { this.sentBody = body; return this },
|
|
299
|
-
json(body) { this.sentBody = body; return this },
|
|
300
|
-
redirect() { return this },
|
|
301
|
-
}
|
|
302
|
-
return r
|
|
303
|
-
}
|
|
304
|
-
// Cast to any: routes.ts handler signatures want a full AppRequest,
|
|
305
|
-
// but for policy-check tests we only need a tiny subset. Same pattern
|
|
306
|
-
// as routes.test.ts.
|
|
307
|
-
function fakeReq(overrides: Record<string, unknown> = {}): any {
|
|
308
|
-
return {
|
|
309
|
-
params: {},
|
|
310
|
-
body: null,
|
|
311
|
-
query: {},
|
|
312
|
-
raw: {},
|
|
313
|
-
headers: {},
|
|
314
|
-
...overrides,
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
function getRoute(router: Router, method: string, path: string) {
|
|
319
|
-
const route = router.list().find(r => r.method === method && r.path === path)
|
|
320
|
-
if (!route) throw new Error(`route not found: ${method} ${path}`)
|
|
321
|
-
return route
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
describe('routes 403 forbidden wiring', () => {
|
|
325
|
-
it('GET /:slug returns 403 JSON when canAccess returns false', async () => {
|
|
326
|
-
class R extends Resource {
|
|
327
|
-
static override label = 'Articles'
|
|
328
|
-
static override labelSingular = 'Article'
|
|
329
|
-
static override slug = 'articles'
|
|
330
|
-
static override async canAccess() { return false }
|
|
331
|
-
}
|
|
332
|
-
const router = new Router()
|
|
333
|
-
registerPilotiqRoutes(router, Pilotiq.make('admin').path('/admin').resources([R]))
|
|
334
|
-
const route = getRoute(router, 'GET', '/admin/articles')
|
|
335
|
-
|
|
336
|
-
const res = fakeRes()
|
|
337
|
-
await route.handler(fakeReq({ headers: { accept: 'application/json' } }), res)
|
|
338
|
-
assert.equal(res.statusCode, 403)
|
|
339
|
-
assert.deepEqual(res.sentBody, { ok: false, error: 'Forbidden' })
|
|
340
|
-
})
|
|
341
|
-
|
|
342
|
-
it('GET /:slug returns 403 HTML when no JSON Accept header', async () => {
|
|
343
|
-
class R extends Resource {
|
|
344
|
-
static override label = 'Articles'
|
|
345
|
-
static override labelSingular = 'Article'
|
|
346
|
-
static override slug = 'articles'
|
|
347
|
-
static override async canAccess() { return false }
|
|
348
|
-
}
|
|
349
|
-
const router = new Router()
|
|
350
|
-
registerPilotiqRoutes(router, Pilotiq.make('admin').path('/admin').resources([R]))
|
|
351
|
-
const route = getRoute(router, 'GET', '/admin/articles')
|
|
352
|
-
|
|
353
|
-
const res = fakeRes()
|
|
354
|
-
await route.handler(fakeReq(), res)
|
|
355
|
-
assert.equal(res.statusCode, 403)
|
|
356
|
-
assert.equal(res.sentBody, 'Forbidden')
|
|
357
|
-
})
|
|
358
|
-
|
|
359
|
-
it('GET /:slug returns 403 when canViewAny returns false', async () => {
|
|
360
|
-
class R extends Resource {
|
|
361
|
-
static override label = 'Articles'
|
|
362
|
-
static override labelSingular = 'Article'
|
|
363
|
-
static override slug = 'articles'
|
|
364
|
-
static override async canViewAny() { return false }
|
|
365
|
-
}
|
|
366
|
-
const router = new Router()
|
|
367
|
-
registerPilotiqRoutes(router, Pilotiq.make('admin').path('/admin').resources([R]))
|
|
368
|
-
const route = getRoute(router, 'GET', '/admin/articles')
|
|
369
|
-
|
|
370
|
-
const res = fakeRes()
|
|
371
|
-
await route.handler(fakeReq({ headers: { accept: 'application/json' } }), res)
|
|
372
|
-
assert.equal(res.statusCode, 403)
|
|
373
|
-
})
|
|
374
|
-
|
|
375
|
-
it('POST :id/delete returns 403 when canDelete returns false', async () => {
|
|
376
|
-
class R extends Resource {
|
|
377
|
-
static override label = 'Articles'
|
|
378
|
-
static override labelSingular = 'Article'
|
|
379
|
-
static override slug = 'articles'
|
|
380
|
-
static override async canDelete(_user: unknown, _record: unknown) { return false }
|
|
381
|
-
}
|
|
382
|
-
const router = new Router()
|
|
383
|
-
registerPilotiqRoutes(router, Pilotiq.make('admin').path('/admin').resources([R]))
|
|
384
|
-
const route = getRoute(router, 'POST', '/admin/articles/:id/delete')
|
|
385
|
-
|
|
386
|
-
const res = fakeRes()
|
|
387
|
-
await route.handler(fakeReq({
|
|
388
|
-
params: { id: '42' },
|
|
389
|
-
headers: { accept: 'application/json' },
|
|
390
|
-
}), res)
|
|
391
|
-
assert.equal(res.statusCode, 403)
|
|
392
|
-
})
|
|
393
|
-
|
|
394
|
-
it('GET :id/edit returns 403 when canEdit returns false', async () => {
|
|
395
|
-
class R extends Resource {
|
|
396
|
-
static override label = 'Articles'
|
|
397
|
-
static override labelSingular = 'Article'
|
|
398
|
-
static override slug = 'articles'
|
|
399
|
-
static override async canEdit(_user: unknown, _record: unknown) { return false }
|
|
400
|
-
}
|
|
401
|
-
const router = new Router()
|
|
402
|
-
registerPilotiqRoutes(router, Pilotiq.make('admin').path('/admin').resources([R]))
|
|
403
|
-
const route = getRoute(router, 'GET', '/admin/articles/:id/edit')
|
|
404
|
-
|
|
405
|
-
const res = fakeRes()
|
|
406
|
-
await route.handler(fakeReq({
|
|
407
|
-
params: { id: '42' },
|
|
408
|
-
headers: { accept: 'application/json' },
|
|
409
|
-
}), res)
|
|
410
|
-
assert.equal(res.statusCode, 403)
|
|
411
|
-
})
|
|
412
|
-
|
|
413
|
-
it('GET /:slug/create returns 403 when canCreate returns false', async () => {
|
|
414
|
-
class R extends Resource {
|
|
415
|
-
static override label = 'Articles'
|
|
416
|
-
static override labelSingular = 'Article'
|
|
417
|
-
static override slug = 'articles'
|
|
418
|
-
static override async canCreate() { return false }
|
|
419
|
-
}
|
|
420
|
-
const router = new Router()
|
|
421
|
-
registerPilotiqRoutes(router, Pilotiq.make('admin').path('/admin').resources([R]))
|
|
422
|
-
const route = getRoute(router, 'GET', '/admin/articles/create')
|
|
423
|
-
|
|
424
|
-
const res = fakeRes()
|
|
425
|
-
await route.handler(fakeReq({ headers: { accept: 'application/json' } }), res)
|
|
426
|
-
assert.equal(res.statusCode, 403)
|
|
427
|
-
})
|
|
428
|
-
|
|
429
|
-
it('predicates receive the user from Pilotiq.user(req => …)', async () => {
|
|
430
|
-
let seenUser: unknown = undefined
|
|
431
|
-
class R extends Resource {
|
|
432
|
-
static override label = 'Articles'
|
|
433
|
-
static override labelSingular = 'Article'
|
|
434
|
-
static override slug = 'articles'
|
|
435
|
-
static override async canAccess(user: unknown) {
|
|
436
|
-
seenUser = user
|
|
437
|
-
return (user as { ok?: boolean })?.ok === true
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
const panel = Pilotiq.make('admin').path('/admin').resources([R])
|
|
441
|
-
.user(() => ({ ok: true, name: 'Sam' }))
|
|
442
|
-
const router = new Router()
|
|
443
|
-
registerPilotiqRoutes(router, panel)
|
|
444
|
-
const route = getRoute(router, 'GET', '/admin/articles')
|
|
445
|
-
|
|
446
|
-
const res = fakeRes()
|
|
447
|
-
await route.handler(fakeReq(), res)
|
|
448
|
-
// No 403 — handler proceeded past the gate; that's our success signal.
|
|
449
|
-
assert.notEqual(res.statusCode, 403)
|
|
450
|
-
assert.deepEqual(seenUser, { ok: true, name: 'Sam' })
|
|
451
|
-
})
|
|
452
|
-
|
|
453
|
-
it('Global edit returns 403 when canAccess fails', async () => {
|
|
454
|
-
class G extends Global {
|
|
455
|
-
static override label = 'Settings'
|
|
456
|
-
static override slug = 'settings'
|
|
457
|
-
static override async canAccess() { return false }
|
|
458
|
-
}
|
|
459
|
-
const panel = Pilotiq.make('admin').path('/admin').globals([G])
|
|
460
|
-
const router = new Router()
|
|
461
|
-
registerPilotiqRoutes(router, panel)
|
|
462
|
-
const route = getRoute(router, 'GET', '/admin/settings')
|
|
463
|
-
|
|
464
|
-
const res = fakeRes()
|
|
465
|
-
await route.handler(fakeReq({ headers: { accept: 'application/json' } }), res)
|
|
466
|
-
assert.equal(res.statusCode, 403)
|
|
467
|
-
})
|
|
468
|
-
|
|
469
|
-
it('custom Page returns 403 when canAccess fails', async () => {
|
|
470
|
-
class P extends Page {
|
|
471
|
-
static override slug = 'analytics'
|
|
472
|
-
static override async canAccess() { return false }
|
|
473
|
-
}
|
|
474
|
-
const panel = Pilotiq.make('admin').path('/admin').pages([P])
|
|
475
|
-
const router = new Router()
|
|
476
|
-
registerPilotiqRoutes(router, panel)
|
|
477
|
-
const route = getRoute(router, 'GET', '/admin/analytics')
|
|
478
|
-
|
|
479
|
-
const res = fakeRes()
|
|
480
|
-
await route.handler(fakeReq({ headers: { accept: 'application/json' } }), res)
|
|
481
|
-
assert.equal(res.statusCode, 403)
|
|
482
|
-
})
|
|
483
|
-
})
|