@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,355 +0,0 @@
|
|
|
1
|
-
import { Action, type ActionContext, type DownloadEnvelope, type NotificationLike } from '../actions/Action.js'
|
|
2
|
-
import type { Element } from '../schema/Element.js'
|
|
3
|
-
import { isRepeaterField, RepeaterField } from '../fields/RepeaterField.js'
|
|
4
|
-
import { isBuilderField, BuilderField } from '../fields/BuilderField.js'
|
|
5
|
-
import { validateSchema, type ValidationErrors } from '../validation/index.js'
|
|
6
|
-
import { coerceFormValues } from './dispatchForm.js'
|
|
7
|
-
import { Notification, type NotificationMeta } from '../notifications/Notification.js'
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Walk an Element tree and return every `Action` instance in document
|
|
11
|
-
* order. Mirrors `findForms`. Uses a structural `getType()` check
|
|
12
|
-
* instead of `instanceof Action` for the same reason as `findForms` —
|
|
13
|
-
* Vite's SSR module cache can load the package via two paths during a
|
|
14
|
-
* single dev session, and `instanceof` returns false across module
|
|
15
|
-
* copies.
|
|
16
|
-
*/
|
|
17
|
-
export function findActions(elements: ReadonlyArray<Element>): Action[] {
|
|
18
|
-
const actions: Action[] = []
|
|
19
|
-
const walk = (els: ReadonlyArray<Element>): void => {
|
|
20
|
-
for (const el of els) {
|
|
21
|
-
if (el.getType() === 'action') actions.push(el as Action)
|
|
22
|
-
// Plan #14 — actions inside a Repeater / Builder row aren't
|
|
23
|
-
// supported for dispatch in v1 (no row context on the handler).
|
|
24
|
-
// Stop the walk at the array-row boundary so a misplaced action
|
|
25
|
-
// doesn't mis-route to the parent dispatcher.
|
|
26
|
-
if (isRepeaterField(el)) continue
|
|
27
|
-
if (isBuilderField(el)) continue
|
|
28
|
-
const children = el.getChildren()
|
|
29
|
-
if (children && children.length > 0) walk(children)
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
walk(elements)
|
|
33
|
-
return actions
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Walk an Element tree and return every `Action` registered as an
|
|
38
|
-
* `extraItemActions(...)` button on a Repeater or Builder field. Used by
|
|
39
|
-
* the action-dispatch route handler when the submit body carries
|
|
40
|
-
* `_rowPath`: at that point we need to look up the action *inside* a row
|
|
41
|
-
* scope rather than at page level (the regular `findActions` walker
|
|
42
|
-
* deliberately stops at array-row boundaries).
|
|
43
|
-
*
|
|
44
|
-
* Each returned entry carries the parent field reference so the
|
|
45
|
-
* dispatcher can validate that the body's `_rowPath` matches an
|
|
46
|
-
* actually-registered field (and not e.g. a fabricated path pointing at
|
|
47
|
-
* an unrelated repeater that happens to have an action with the same
|
|
48
|
-
* name). The entry's `field.name` is used to namespace dispatch.
|
|
49
|
-
*/
|
|
50
|
-
export interface FoundRowAction {
|
|
51
|
-
action: Action
|
|
52
|
-
field: RepeaterField | BuilderField
|
|
53
|
-
fieldName: string
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function findRowExtraActions(
|
|
57
|
-
elements: ReadonlyArray<Element>,
|
|
58
|
-
): FoundRowAction[] {
|
|
59
|
-
const out: FoundRowAction[] = []
|
|
60
|
-
const walk = (els: ReadonlyArray<Element>): void => {
|
|
61
|
-
for (const el of els) {
|
|
62
|
-
if (isRepeaterField(el) || isBuilderField(el)) {
|
|
63
|
-
const f = el as RepeaterField | BuilderField
|
|
64
|
-
for (const action of f.getExtraItemActions()) {
|
|
65
|
-
out.push({ action, field: f, fieldName: f.name })
|
|
66
|
-
}
|
|
67
|
-
// Don't recurse INTO the row schema (page-level walker semantics
|
|
68
|
-
// already cover those — and inner Repeater/Builder fields can
|
|
69
|
-
// carry their own extraItemActions, addressed via deeper paths).
|
|
70
|
-
const inner = el instanceof RepeaterField ? el.getInnerSchema() : []
|
|
71
|
-
if (inner.length > 0) walk(inner)
|
|
72
|
-
if (el instanceof BuilderField) {
|
|
73
|
-
for (const block of el.getBlocks()) walk(block.getSchema())
|
|
74
|
-
}
|
|
75
|
-
continue
|
|
76
|
-
}
|
|
77
|
-
const children = el.getChildren()
|
|
78
|
-
if (children && children.length > 0) walk(children)
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
walk(elements)
|
|
82
|
-
return out
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Body shape parsed off a `POST {base}/.../_action/{name}` request.
|
|
87
|
-
* `ids` carries the records the action operates on (one element for row
|
|
88
|
-
* actions, many for bulk, none for header). `values` is everything else
|
|
89
|
-
* the client sent — typically dialog-form fields.
|
|
90
|
-
*
|
|
91
|
-
* `rowPath` is set only when this submit was triggered from a Repeater
|
|
92
|
-
* or Builder `extraItemActions` button. The format mirrors the wire
|
|
93
|
-
* shape used elsewhere — `<fieldName>.<index>` for top-level array-row
|
|
94
|
-
* fields. Nested array fields aren't supported in v1; the dispatcher
|
|
95
|
-
* rejects deeper paths.
|
|
96
|
-
*/
|
|
97
|
-
export interface ActionRequestInput {
|
|
98
|
-
ids: string[]
|
|
99
|
-
values: Record<string, unknown>
|
|
100
|
-
rowPath?: string
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/** Parse a posted body into `{ ids, values, rowPath? }`. */
|
|
104
|
-
export function parseActionBody(body: Record<string, unknown>): ActionRequestInput {
|
|
105
|
-
const idsRaw = body['ids']
|
|
106
|
-
let ids: string[] = []
|
|
107
|
-
if (Array.isArray(idsRaw)) {
|
|
108
|
-
ids = idsRaw.map(v => String(v))
|
|
109
|
-
} else if (typeof idsRaw === 'string') {
|
|
110
|
-
// form-encoded "ids=a&ids=b" can collapse to a single string; allow CSV.
|
|
111
|
-
ids = idsRaw.includes(',') ? idsRaw.split(',').map(s => s.trim()).filter(Boolean) : [idsRaw]
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const rowPathRaw = body['_rowPath']
|
|
115
|
-
const rowPath = typeof rowPathRaw === 'string' && rowPathRaw.length > 0 ? rowPathRaw : undefined
|
|
116
|
-
|
|
117
|
-
const values: Record<string, unknown> = { ...body }
|
|
118
|
-
delete values['ids']
|
|
119
|
-
delete values['_actionName']
|
|
120
|
-
delete values['_rowPath']
|
|
121
|
-
const out: ActionRequestInput = { ids, values }
|
|
122
|
-
if (rowPath !== undefined) out.rowPath = rowPath
|
|
123
|
-
return out
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export type ResolveRecord = (id: string) => Promise<unknown> | unknown
|
|
127
|
-
|
|
128
|
-
export interface DispatchActionInput extends ActionRequestInput {
|
|
129
|
-
request?: unknown
|
|
130
|
-
/**
|
|
131
|
-
* For row-scoped extraItemActions dispatch: the parent Repeater/Builder
|
|
132
|
-
* field that owns this action, plus the form's full Element schema.
|
|
133
|
-
* The dispatcher uses these to (a) coerce the submit body so row paths
|
|
134
|
-
* resolve, (b) pluck the row from the parent field's array, and (c)
|
|
135
|
-
* stamp `ctx.row` on the handler context.
|
|
136
|
-
*
|
|
137
|
-
* When omitted, `rowPath` is treated as "no row scope" even if set on
|
|
138
|
-
* the body — the dispatcher won't blindly trust client-supplied row
|
|
139
|
-
* paths for non-row actions.
|
|
140
|
-
*/
|
|
141
|
-
rowField?: RepeaterField | BuilderField
|
|
142
|
-
formSchema?: Element[]
|
|
143
|
-
/**
|
|
144
|
-
* For relation-manager-scoped dispatch: the loaded parent record + ids.
|
|
145
|
-
* Stamped onto `ctx.relation` so M2M handlers (`relationAttach /
|
|
146
|
-
* relationBulkDetach`) can call `parent.related(rel).attach / detach`
|
|
147
|
-
* without re-loading the parent or threading it through closures.
|
|
148
|
-
* Always set by the manager-scoped `_action` route; absent everywhere
|
|
149
|
-
* else.
|
|
150
|
-
*/
|
|
151
|
-
relation?: {
|
|
152
|
-
parent: unknown
|
|
153
|
-
parentId: string
|
|
154
|
-
relationship: string
|
|
155
|
-
}
|
|
156
|
-
/** When set, supplied user is stamped on `ctx.user`. Routes that
|
|
157
|
-
* already resolved the user (auth prelude) pass it through so handlers
|
|
158
|
-
* see the same user the route gated on. */
|
|
159
|
-
user?: unknown
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
export interface DispatchActionSuccess {
|
|
163
|
-
ok: true
|
|
164
|
-
redirect?: string
|
|
165
|
-
/** Notifications the handler emitted via the return shape `{ notify }`.
|
|
166
|
-
* Forwarded by the route layer either inline (JSON dispatch) or as
|
|
167
|
-
* a flash payload through the redirect (HTML dispatch). */
|
|
168
|
-
notifications?: NotificationMeta[]
|
|
169
|
-
/** File-download envelope the handler emitted via `{ download }`.
|
|
170
|
-
* The route layer writes `Content-Disposition: attachment` + the
|
|
171
|
-
* payload body and ignores `redirect` when this is set. */
|
|
172
|
-
download?: DownloadEnvelope
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
export interface DispatchActionFailure {
|
|
176
|
-
ok: false
|
|
177
|
-
error: string
|
|
178
|
-
/** Per-field validation errors when the action's modal-form schema
|
|
179
|
-
* rejected the submitted values. Populated only on validation failure;
|
|
180
|
-
* absent for handler exceptions. */
|
|
181
|
-
errors?: ValidationErrors
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
export type DispatchActionResult = DispatchActionSuccess | DispatchActionFailure
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Run an Action's server-side handler with a built-up `ActionContext`.
|
|
188
|
-
*
|
|
189
|
-
* - `ids.length === 0` → no `record`/`records` (header action)
|
|
190
|
-
* - `ids.length === 1` → `ctx.record` (row / single-target action)
|
|
191
|
-
* - `ids.length > 1` → `ctx.records` (bulk action)
|
|
192
|
-
*
|
|
193
|
-
* When `resolveRecord` is supplied (e.g. a `Resource.model.find` adapter
|
|
194
|
-
* the route handler builds), each id is hydrated through it. Otherwise
|
|
195
|
-
* `ctx.record` / `ctx.records` carry bare `{ id }` stubs so the handler
|
|
196
|
-
* still has *something* to key off.
|
|
197
|
-
*
|
|
198
|
-
* Returns a `DispatchActionResult` rather than throwing so the caller can
|
|
199
|
-
* map it onto an HTTP response uniformly. Errors thrown by the handler
|
|
200
|
-
* are caught and wrapped into `{ ok: false, error }`.
|
|
201
|
-
*/
|
|
202
|
-
export async function dispatchAction(
|
|
203
|
-
action: Action,
|
|
204
|
-
input: DispatchActionInput,
|
|
205
|
-
resolveRecord?: ResolveRecord,
|
|
206
|
-
): Promise<DispatchActionResult> {
|
|
207
|
-
const handler = action.getHandler()
|
|
208
|
-
if (!handler) {
|
|
209
|
-
return {
|
|
210
|
-
ok: false,
|
|
211
|
-
error: `[Pilotiq] Action "${action.name}" has no handler. Set Action.handler(...) to enable dispatch.`,
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
const ctx: ActionContext = { values: input.values }
|
|
216
|
-
if (input.request !== undefined) ctx.request = input.request
|
|
217
|
-
if (input.relation !== undefined) ctx.relation = input.relation
|
|
218
|
-
if (input.user !== undefined) ctx.user = input.user
|
|
219
|
-
|
|
220
|
-
if (input.ids.length === 1) {
|
|
221
|
-
const id = input.ids[0]!
|
|
222
|
-
ctx.record = resolveRecord ? await resolveRecord(id) : { id }
|
|
223
|
-
} else if (input.ids.length > 1) {
|
|
224
|
-
ctx.records = resolveRecord
|
|
225
|
-
? await Promise.all(input.ids.map(id => Promise.resolve(resolveRecord(id))))
|
|
226
|
-
: input.ids.map(id => ({ id }))
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Row-scoped dispatch (Repeater / Builder `extraItemActions`). Coerce
|
|
230
|
-
// the form body once via the form's own schema, navigate to the row
|
|
231
|
-
// identified by `rowPath`, and stamp `ctx.row`. The handler still sees
|
|
232
|
-
// `ctx.values` (top-level fields) and `ctx.record` (parent record);
|
|
233
|
-
// `ctx.row.values` carries the row's fields specifically.
|
|
234
|
-
if (input.rowPath && input.rowField && input.formSchema) {
|
|
235
|
-
const parsed = parseRowPath(input.rowPath, input.rowField.name)
|
|
236
|
-
if (parsed) {
|
|
237
|
-
const coerced = coerceFormValues(input.formSchema, input.values)
|
|
238
|
-
const arr = coerced[input.rowField.name]
|
|
239
|
-
const rowEntry = Array.isArray(arr) ? (arr as Array<unknown>)[parsed.index] : undefined
|
|
240
|
-
const rowData = extractRowData(rowEntry, input.rowField)
|
|
241
|
-
const rowId = rowData['__id']
|
|
242
|
-
ctx.row = {
|
|
243
|
-
index: parsed.index,
|
|
244
|
-
id: typeof rowId === 'string' ? rowId : `${input.rowField.name}-${parsed.index}`,
|
|
245
|
-
values: rowData,
|
|
246
|
-
fieldName: input.rowField.name,
|
|
247
|
-
}
|
|
248
|
-
if (input.rowField instanceof BuilderField && rowEntry && typeof rowEntry === 'object') {
|
|
249
|
-
const t = (rowEntry as { type?: unknown }).type
|
|
250
|
-
if (typeof t === 'string') ctx.row.blockType = t
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// Form-modal action — validate the submitted values against the action's
|
|
256
|
-
// schema, then coerce strings into runtime types (booleans/numbers/Dates)
|
|
257
|
-
// before invoking the handler. Action without `.schema()` skips both
|
|
258
|
-
// (degenerate confirm-only / no-modal cases).
|
|
259
|
-
if (action.hasModal()) {
|
|
260
|
-
const schema = action.getSchema()
|
|
261
|
-
if (schema.length > 0) {
|
|
262
|
-
const errors = await validateSchema(schema, input.values, ctx.record)
|
|
263
|
-
if (Object.keys(errors).length > 0) {
|
|
264
|
-
return { ok: false, error: 'validation', errors }
|
|
265
|
-
}
|
|
266
|
-
ctx.values = coerceFormValues(schema, input.values)
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
try {
|
|
271
|
-
const result = await handler(ctx)
|
|
272
|
-
const success: DispatchActionSuccess = { ok: true }
|
|
273
|
-
if (result && typeof result === 'object') {
|
|
274
|
-
if (typeof result.redirect === 'string') success.redirect = result.redirect
|
|
275
|
-
if (result.notify !== undefined) {
|
|
276
|
-
const notifs = normalizeNotifications(result.notify)
|
|
277
|
-
if (notifs.length > 0) success.notifications = notifs
|
|
278
|
-
}
|
|
279
|
-
if (isDownloadEnvelope(result.download)) success.download = result.download
|
|
280
|
-
}
|
|
281
|
-
return success
|
|
282
|
-
} catch (err) {
|
|
283
|
-
return {
|
|
284
|
-
ok: false,
|
|
285
|
-
error: err instanceof Error ? err.message : 'Action failed',
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* Parse `_rowPath` body field into `{ index }`. v1 supports only
|
|
292
|
-
* top-level array-row fields (`<fieldName>.<index>`); deeper paths
|
|
293
|
-
* (nested Repeaters) are rejected — return null.
|
|
294
|
-
*
|
|
295
|
-
* `expectedField` guards against client-supplied paths pointing at the
|
|
296
|
-
* wrong field for the named action. Returns null on mismatch so the
|
|
297
|
-
* dispatcher silently treats the request as non-row-scoped (the action
|
|
298
|
-
* still runs at page level).
|
|
299
|
-
*/
|
|
300
|
-
function parseRowPath(
|
|
301
|
-
raw: string,
|
|
302
|
-
expectedField: string,
|
|
303
|
-
): { index: number } | null {
|
|
304
|
-
const parts = raw.split('.')
|
|
305
|
-
if (parts.length !== 2) return null
|
|
306
|
-
if (parts[0] !== expectedField) return null
|
|
307
|
-
const index = Number.parseInt(parts[1] ?? '', 10)
|
|
308
|
-
if (!Number.isInteger(index) || index < 0) return null
|
|
309
|
-
return { index }
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
/**
|
|
313
|
-
* Pull the row's data envelope from a coerced row entry. RepeaterField
|
|
314
|
-
* stores rows as flat `{ [field]: value, __id? }` objects; BuilderField
|
|
315
|
-
* stores them as `{ __id, type, data: {…} }`. The handler always sees
|
|
316
|
-
* a flat row-fields map, so we unwrap Builder's `.data`.
|
|
317
|
-
*/
|
|
318
|
-
function extractRowData(
|
|
319
|
-
entry: unknown,
|
|
320
|
-
field: RepeaterField | BuilderField,
|
|
321
|
-
): Record<string, unknown> {
|
|
322
|
-
if (!entry || typeof entry !== 'object' || Array.isArray(entry)) return {}
|
|
323
|
-
if (field instanceof BuilderField) {
|
|
324
|
-
const data = (entry as { data?: unknown }).data
|
|
325
|
-
if (data && typeof data === 'object' && !Array.isArray(data)) {
|
|
326
|
-
return { ...(data as Record<string, unknown>) }
|
|
327
|
-
}
|
|
328
|
-
return {}
|
|
329
|
-
}
|
|
330
|
-
const out = { ...(entry as Record<string, unknown>) }
|
|
331
|
-
return out
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
/** Coerce the loose `NotificationLike` shape (single / array / built /
|
|
335
|
-
* meta) into a flat `NotificationMeta[]`. */
|
|
336
|
-
function normalizeNotifications(input: NotificationLike): NotificationMeta[] {
|
|
337
|
-
const arr = Array.isArray(input) ? input : [input]
|
|
338
|
-
const out: NotificationMeta[] = []
|
|
339
|
-
for (const n of arr) {
|
|
340
|
-
if (n instanceof Notification) out.push(n.toMeta())
|
|
341
|
-
else if (n && typeof n === 'object') out.push(n as NotificationMeta)
|
|
342
|
-
}
|
|
343
|
-
return out
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
/** Structural shape check for the `{ download }` envelope. Defends the
|
|
347
|
-
* route layer from a handler that returns a partial / wrong-typed
|
|
348
|
-
* download object. */
|
|
349
|
-
function isDownloadEnvelope(value: unknown): value is DownloadEnvelope {
|
|
350
|
-
if (!value || typeof value !== 'object') return false
|
|
351
|
-
const v = value as Record<string, unknown>
|
|
352
|
-
return typeof v.filename === 'string'
|
|
353
|
-
&& typeof v.contentType === 'string'
|
|
354
|
-
&& typeof v.body === 'string'
|
|
355
|
-
}
|