@cohesivesystems/presentation-core 0.1.0-alpha.1
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/LICENSE +55 -0
- package/dist/api-scope-request.d.ts +43 -0
- package/dist/api-scope-request.d.ts.map +1 -0
- package/dist/api-scope-request.js +96 -0
- package/dist/api-scope-request.js.map +1 -0
- package/dist/collection-chrome-icons.d.ts +18 -0
- package/dist/collection-chrome-icons.d.ts.map +1 -0
- package/dist/collection-chrome-icons.js +57 -0
- package/dist/collection-chrome-icons.js.map +1 -0
- package/dist/collection-chrome-runtime.d.ts +25 -0
- package/dist/collection-chrome-runtime.d.ts.map +1 -0
- package/dist/collection-chrome-runtime.js +72 -0
- package/dist/collection-chrome-runtime.js.map +1 -0
- package/dist/collection-chrome-slot-renderer-registry.d.ts +110 -0
- package/dist/collection-chrome-slot-renderer-registry.d.ts.map +1 -0
- package/dist/collection-chrome-slot-renderer-registry.js +136 -0
- package/dist/collection-chrome-slot-renderer-registry.js.map +1 -0
- package/dist/collection-selection-state.d.ts +18 -0
- package/dist/collection-selection-state.d.ts.map +1 -0
- package/dist/collection-selection-state.js +2 -0
- package/dist/collection-selection-state.js.map +1 -0
- package/dist/data-source-projection.d.ts +475 -0
- package/dist/data-source-projection.d.ts.map +1 -0
- package/dist/data-source-projection.js +880 -0
- package/dist/data-source-projection.js.map +1 -0
- package/dist/data-source-query-lowering.d.ts +35 -0
- package/dist/data-source-query-lowering.d.ts.map +1 -0
- package/dist/data-source-query-lowering.js +104 -0
- package/dist/data-source-query-lowering.js.map +1 -0
- package/dist/date-time-filter-model.d.ts +20 -0
- package/dist/date-time-filter-model.d.ts.map +1 -0
- package/dist/date-time-filter-model.js +115 -0
- package/dist/date-time-filter-model.js.map +1 -0
- package/dist/document-badge-icons.d.ts +4 -0
- package/dist/document-badge-icons.d.ts.map +1 -0
- package/dist/document-badge-icons.js +4 -0
- package/dist/document-badge-icons.js.map +1 -0
- package/dist/document-module.d.ts +268 -0
- package/dist/document-module.d.ts.map +1 -0
- package/dist/document-module.js +347 -0
- package/dist/document-module.js.map +1 -0
- package/dist/document-summary-model.d.ts +2 -0
- package/dist/document-summary-model.d.ts.map +1 -0
- package/dist/document-summary-model.js +2 -0
- package/dist/document-summary-model.js.map +1 -0
- package/dist/document-workspace-chrome-projection.d.ts +18 -0
- package/dist/document-workspace-chrome-projection.d.ts.map +1 -0
- package/dist/document-workspace-chrome-projection.js +35 -0
- package/dist/document-workspace-chrome-projection.js.map +1 -0
- package/dist/document-workspace-surface-slots.d.ts +75 -0
- package/dist/document-workspace-surface-slots.d.ts.map +1 -0
- package/dist/document-workspace-surface-slots.js +268 -0
- package/dist/document-workspace-surface-slots.js.map +1 -0
- package/dist/endpoint-executor.d.ts +62 -0
- package/dist/endpoint-executor.d.ts.map +1 -0
- package/dist/endpoint-executor.js +35 -0
- package/dist/endpoint-executor.js.map +1 -0
- package/dist/field-display-resolution.d.ts +5 -0
- package/dist/field-display-resolution.d.ts.map +1 -0
- package/dist/field-display-resolution.js +50 -0
- package/dist/field-display-resolution.js.map +1 -0
- package/dist/index.d.ts +90 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +89 -0
- package/dist/index.js.map +1 -0
- package/dist/module.d.ts +48 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +108 -0
- package/dist/module.js.map +1 -0
- package/dist/navigation-shell-frame-renderer-registry.d.ts +12 -0
- package/dist/navigation-shell-frame-renderer-registry.d.ts.map +1 -0
- package/dist/navigation-shell-frame-renderer-registry.js +29 -0
- package/dist/navigation-shell-frame-renderer-registry.js.map +1 -0
- package/dist/navigation-shell-layout-runtime.d.ts +29 -0
- package/dist/navigation-shell-layout-runtime.d.ts.map +1 -0
- package/dist/navigation-shell-layout-runtime.js +50 -0
- package/dist/navigation-shell-layout-runtime.js.map +1 -0
- package/dist/navigation-shell-region-component-registry.d.ts +96 -0
- package/dist/navigation-shell-region-component-registry.d.ts.map +1 -0
- package/dist/navigation-shell-region-component-registry.js +108 -0
- package/dist/navigation-shell-region-component-registry.js.map +1 -0
- package/dist/navigation-shell-runtime.d.ts +48 -0
- package/dist/navigation-shell-runtime.d.ts.map +1 -0
- package/dist/navigation-shell-runtime.js +457 -0
- package/dist/navigation-shell-runtime.js.map +1 -0
- package/dist/navigation-shell-slot-renderer-registry.d.ts +15 -0
- package/dist/navigation-shell-slot-renderer-registry.d.ts.map +1 -0
- package/dist/navigation-shell-slot-renderer-registry.js +48 -0
- package/dist/navigation-shell-slot-renderer-registry.js.map +1 -0
- package/dist/navigation.d.ts +84 -0
- package/dist/navigation.d.ts.map +1 -0
- package/dist/navigation.js +167 -0
- package/dist/navigation.js.map +1 -0
- package/dist/object-path.d.ts +23 -0
- package/dist/object-path.d.ts.map +1 -0
- package/dist/object-path.js +63 -0
- package/dist/object-path.js.map +1 -0
- package/dist/page-host-renderer-registry.d.ts +119 -0
- package/dist/page-host-renderer-registry.d.ts.map +1 -0
- package/dist/page-host-renderer-registry.js +305 -0
- package/dist/page-host-renderer-registry.js.map +1 -0
- package/dist/presentation-action-endpoint-request-projection.d.ts +23 -0
- package/dist/presentation-action-endpoint-request-projection.d.ts.map +1 -0
- package/dist/presentation-action-endpoint-request-projection.js +117 -0
- package/dist/presentation-action-endpoint-request-projection.js.map +1 -0
- package/dist/presentation-action-endpoint.d.ts +24 -0
- package/dist/presentation-action-endpoint.d.ts.map +1 -0
- package/dist/presentation-action-endpoint.js +56 -0
- package/dist/presentation-action-endpoint.js.map +1 -0
- package/dist/presentation-action-icons.d.ts +4 -0
- package/dist/presentation-action-icons.d.ts.map +1 -0
- package/dist/presentation-action-icons.js +4 -0
- package/dist/presentation-action-icons.js.map +1 -0
- package/dist/presentation-action-result-state.d.ts +48 -0
- package/dist/presentation-action-result-state.d.ts.map +1 -0
- package/dist/presentation-action-result-state.js +109 -0
- package/dist/presentation-action-result-state.js.map +1 -0
- package/dist/presentation-action-runtime-binding.d.ts +48 -0
- package/dist/presentation-action-runtime-binding.d.ts.map +1 -0
- package/dist/presentation-action-runtime-binding.js +52 -0
- package/dist/presentation-action-runtime-binding.js.map +1 -0
- package/dist/presentation-action-runtime-diagnostics.d.ts +18 -0
- package/dist/presentation-action-runtime-diagnostics.d.ts.map +1 -0
- package/dist/presentation-action-runtime-diagnostics.js +69 -0
- package/dist/presentation-action-runtime-diagnostics.js.map +1 -0
- package/dist/presentation-action-runtime-labels.d.ts +15 -0
- package/dist/presentation-action-runtime-labels.d.ts.map +1 -0
- package/dist/presentation-action-runtime-labels.js +28 -0
- package/dist/presentation-action-runtime-labels.js.map +1 -0
- package/dist/presentation-action-runtime-projection.d.ts +17 -0
- package/dist/presentation-action-runtime-projection.d.ts.map +1 -0
- package/dist/presentation-action-runtime-projection.js +31 -0
- package/dist/presentation-action-runtime-projection.js.map +1 -0
- package/dist/presentation-badge-resolution.d.ts +8 -0
- package/dist/presentation-badge-resolution.d.ts.map +1 -0
- package/dist/presentation-badge-resolution.js +73 -0
- package/dist/presentation-badge-resolution.js.map +1 -0
- package/dist/presentation-collection-pagination.d.ts +32 -0
- package/dist/presentation-collection-pagination.d.ts.map +1 -0
- package/dist/presentation-collection-pagination.js +275 -0
- package/dist/presentation-collection-pagination.js.map +1 -0
- package/dist/presentation-content-diagnostics.d.ts +17 -0
- package/dist/presentation-content-diagnostics.d.ts.map +1 -0
- package/dist/presentation-content-diagnostics.js +61 -0
- package/dist/presentation-content-diagnostics.js.map +1 -0
- package/dist/presentation-content-resolution.d.ts +9 -0
- package/dist/presentation-content-resolution.d.ts.map +1 -0
- package/dist/presentation-content-resolution.js +19 -0
- package/dist/presentation-content-resolution.js.map +1 -0
- package/dist/presentation-data-source-binding-model.d.ts +81 -0
- package/dist/presentation-data-source-binding-model.d.ts.map +1 -0
- package/dist/presentation-data-source-binding-model.js +56 -0
- package/dist/presentation-data-source-binding-model.js.map +1 -0
- package/dist/presentation-data-source-runtime.d.ts +62 -0
- package/dist/presentation-data-source-runtime.d.ts.map +1 -0
- package/dist/presentation-data-source-runtime.js +80 -0
- package/dist/presentation-data-source-runtime.js.map +1 -0
- package/dist/presentation-design-intent-diagnostics.d.ts +25 -0
- package/dist/presentation-design-intent-diagnostics.d.ts.map +1 -0
- package/dist/presentation-design-intent-diagnostics.js +55 -0
- package/dist/presentation-design-intent-diagnostics.js.map +1 -0
- package/dist/presentation-icon-diagnostics.d.ts +45 -0
- package/dist/presentation-icon-diagnostics.d.ts.map +1 -0
- package/dist/presentation-icon-diagnostics.js +235 -0
- package/dist/presentation-icon-diagnostics.js.map +1 -0
- package/dist/presentation-icon-registry.d.ts +36 -0
- package/dist/presentation-icon-registry.d.ts.map +1 -0
- package/dist/presentation-icon-registry.js +81 -0
- package/dist/presentation-icon-registry.js.map +1 -0
- package/dist/presentation-navigation-action-runtime-bindings.d.ts +13 -0
- package/dist/presentation-navigation-action-runtime-bindings.d.ts.map +1 -0
- package/dist/presentation-navigation-action-runtime-bindings.js +29 -0
- package/dist/presentation-navigation-action-runtime-bindings.js.map +1 -0
- package/dist/presentation-pagination.d.ts +98 -0
- package/dist/presentation-pagination.d.ts.map +1 -0
- package/dist/presentation-pagination.js +427 -0
- package/dist/presentation-pagination.js.map +1 -0
- package/dist/presentation-projection-coverage.d.ts +38 -0
- package/dist/presentation-projection-coverage.d.ts.map +1 -0
- package/dist/presentation-projection-coverage.js +2429 -0
- package/dist/presentation-projection-coverage.js.map +1 -0
- package/dist/presentation-projection-diagnostics.d.ts +33 -0
- package/dist/presentation-projection-diagnostics.d.ts.map +1 -0
- package/dist/presentation-projection-diagnostics.js +17 -0
- package/dist/presentation-projection-diagnostics.js.map +1 -0
- package/dist/presentation-projection-trace.d.ts +97 -0
- package/dist/presentation-projection-trace.d.ts.map +1 -0
- package/dist/presentation-projection-trace.js +110 -0
- package/dist/presentation-projection-trace.js.map +1 -0
- package/dist/presentation-query-form-state.d.ts +15 -0
- package/dist/presentation-query-form-state.d.ts.map +1 -0
- package/dist/presentation-query-form-state.js +20 -0
- package/dist/presentation-query-form-state.js.map +1 -0
- package/dist/presentation-renderer-registry.d.ts +86 -0
- package/dist/presentation-renderer-registry.d.ts.map +1 -0
- package/dist/presentation-renderer-registry.js +108 -0
- package/dist/presentation-renderer-registry.js.map +1 -0
- package/dist/presentation-semantics.d.ts +288 -0
- package/dist/presentation-semantics.d.ts.map +1 -0
- package/dist/presentation-semantics.js +560 -0
- package/dist/presentation-semantics.js.map +1 -0
- package/dist/presentation-standards.d.ts +8 -0
- package/dist/presentation-standards.d.ts.map +1 -0
- package/dist/presentation-standards.js +9 -0
- package/dist/presentation-standards.js.map +1 -0
- package/dist/presentation-test-selectors.d.ts +146 -0
- package/dist/presentation-test-selectors.d.ts.map +1 -0
- package/dist/presentation-test-selectors.js +113 -0
- package/dist/presentation-test-selectors.js.map +1 -0
- package/dist/presentation-value-formatting.d.ts +12 -0
- package/dist/presentation-value-formatting.d.ts.map +1 -0
- package/dist/presentation-value-formatting.js +33 -0
- package/dist/presentation-value-formatting.js.map +1 -0
- package/dist/presentation-value-resolution.d.ts +7 -0
- package/dist/presentation-value-resolution.d.ts.map +1 -0
- package/dist/presentation-value-resolution.js +69 -0
- package/dist/presentation-value-resolution.js.map +1 -0
- package/dist/presentation-view-tree.d.ts +6 -0
- package/dist/presentation-view-tree.d.ts.map +1 -0
- package/dist/presentation-view-tree.js +15 -0
- package/dist/presentation-view-tree.js.map +1 -0
- package/dist/process-task-model.d.ts +80 -0
- package/dist/process-task-model.d.ts.map +1 -0
- package/dist/process-task-model.js +52 -0
- package/dist/process-task-model.js.map +1 -0
- package/dist/process-task-projection.d.ts +46 -0
- package/dist/process-task-projection.d.ts.map +1 -0
- package/dist/process-task-projection.js +233 -0
- package/dist/process-task-projection.js.map +1 -0
- package/dist/projected-action-status-projection.d.ts +18 -0
- package/dist/projected-action-status-projection.d.ts.map +1 -0
- package/dist/projected-action-status-projection.js +19 -0
- package/dist/projected-action-status-projection.js.map +1 -0
- package/dist/projected-activity-state-model.d.ts +22 -0
- package/dist/projected-activity-state-model.d.ts.map +1 -0
- package/dist/projected-activity-state-model.js +87 -0
- package/dist/projected-activity-state-model.js.map +1 -0
- package/dist/projected-collection-action-runtime-bindings.d.ts +12 -0
- package/dist/projected-collection-action-runtime-bindings.d.ts.map +1 -0
- package/dist/projected-collection-action-runtime-bindings.js +37 -0
- package/dist/projected-collection-action-runtime-bindings.js.map +1 -0
- package/dist/projected-collection-action-runtime-diagnostics.d.ts +23 -0
- package/dist/projected-collection-action-runtime-diagnostics.d.ts.map +1 -0
- package/dist/projected-collection-action-runtime-diagnostics.js +168 -0
- package/dist/projected-collection-action-runtime-diagnostics.js.map +1 -0
- package/dist/projected-collection-runtime.d.ts +475 -0
- package/dist/projected-collection-runtime.d.ts.map +1 -0
- package/dist/projected-collection-runtime.js +832 -0
- package/dist/projected-collection-runtime.js.map +1 -0
- package/dist/projected-document-action-diagnostics.d.ts +16 -0
- package/dist/projected-document-action-diagnostics.d.ts.map +1 -0
- package/dist/projected-document-action-diagnostics.js +113 -0
- package/dist/projected-document-action-diagnostics.js.map +1 -0
- package/dist/projected-document-action-enablements.d.ts +25 -0
- package/dist/projected-document-action-enablements.d.ts.map +1 -0
- package/dist/projected-document-action-enablements.js +38 -0
- package/dist/projected-document-action-enablements.js.map +1 -0
- package/dist/projected-document-action-projection.d.ts +45 -0
- package/dist/projected-document-action-projection.d.ts.map +1 -0
- package/dist/projected-document-action-projection.js +201 -0
- package/dist/projected-document-action-projection.js.map +1 -0
- package/dist/projected-document-action-runtime-profile-diagnostics.d.ts +16 -0
- package/dist/projected-document-action-runtime-profile-diagnostics.d.ts.map +1 -0
- package/dist/projected-document-action-runtime-profile-diagnostics.js +168 -0
- package/dist/projected-document-action-runtime-profile-diagnostics.js.map +1 -0
- package/dist/projected-document-action-runtime-profile.d.ts +64 -0
- package/dist/projected-document-action-runtime-profile.d.ts.map +1 -0
- package/dist/projected-document-action-runtime-profile.js +33 -0
- package/dist/projected-document-action-runtime-profile.js.map +1 -0
- package/dist/projected-document-action-status-notice-diagnostics.d.ts +10 -0
- package/dist/projected-document-action-status-notice-diagnostics.d.ts.map +1 -0
- package/dist/projected-document-action-status-notice-diagnostics.js +64 -0
- package/dist/projected-document-action-status-notice-diagnostics.js.map +1 -0
- package/dist/projected-document-badge-formatting.d.ts +2 -0
- package/dist/projected-document-badge-formatting.d.ts.map +1 -0
- package/dist/projected-document-badge-formatting.js +7 -0
- package/dist/projected-document-badge-formatting.js.map +1 -0
- package/dist/projected-document-editor-model.d.ts +4 -0
- package/dist/projected-document-editor-model.d.ts.map +1 -0
- package/dist/projected-document-editor-model.js +2 -0
- package/dist/projected-document-editor-model.js.map +1 -0
- package/dist/projected-document-field-navigation.d.ts +72 -0
- package/dist/projected-document-field-navigation.d.ts.map +1 -0
- package/dist/projected-document-field-navigation.js +143 -0
- package/dist/projected-document-field-navigation.js.map +1 -0
- package/dist/projected-document-field-semantics.d.ts +5 -0
- package/dist/projected-document-field-semantics.d.ts.map +1 -0
- package/dist/projected-document-field-semantics.js +16 -0
- package/dist/projected-document-field-semantics.js.map +1 -0
- package/dist/projected-document-workspace-data-source-bindings.d.ts +69 -0
- package/dist/projected-document-workspace-data-source-bindings.d.ts.map +1 -0
- package/dist/projected-document-workspace-data-source-bindings.js +81 -0
- package/dist/projected-document-workspace-data-source-bindings.js.map +1 -0
- package/dist/projected-document-workspace-notice-diagnostics.d.ts +12 -0
- package/dist/projected-document-workspace-notice-diagnostics.d.ts.map +1 -0
- package/dist/projected-document-workspace-notice-diagnostics.js +13 -0
- package/dist/projected-document-workspace-notice-diagnostics.js.map +1 -0
- package/dist/projected-input-form-runtime.d.ts +62 -0
- package/dist/projected-input-form-runtime.d.ts.map +1 -0
- package/dist/projected-input-form-runtime.js +2 -0
- package/dist/projected-input-form-runtime.js.map +1 -0
- package/dist/projected-process-task-notice-diagnostics.d.ts +13 -0
- package/dist/projected-process-task-notice-diagnostics.d.ts.map +1 -0
- package/dist/projected-process-task-notice-diagnostics.js +170 -0
- package/dist/projected-process-task-notice-diagnostics.js.map +1 -0
- package/dist/projected-query-form-runtime.d.ts +46 -0
- package/dist/projected-query-form-runtime.d.ts.map +1 -0
- package/dist/projected-query-form-runtime.js +2 -0
- package/dist/projected-query-form-runtime.js.map +1 -0
- package/dist/prompt-document-preview-projection.d.ts +46 -0
- package/dist/prompt-document-preview-projection.d.ts.map +1 -0
- package/dist/prompt-document-preview-projection.js +173 -0
- package/dist/prompt-document-preview-projection.js.map +1 -0
- package/dist/prompt-icons.d.ts +4 -0
- package/dist/prompt-icons.d.ts.map +1 -0
- package/dist/prompt-icons.js +4 -0
- package/dist/prompt-icons.js.map +1 -0
- package/dist/prompt-status-message-resolution.d.ts +18 -0
- package/dist/prompt-status-message-resolution.d.ts.map +1 -0
- package/dist/prompt-status-message-resolution.js +83 -0
- package/dist/prompt-status-message-resolution.js.map +1 -0
- package/dist/query-form-lowering.d.ts +16 -0
- package/dist/query-form-lowering.d.ts.map +1 -0
- package/dist/query-form-lowering.js +38 -0
- package/dist/query-form-lowering.js.map +1 -0
- package/dist/query-form-url-state.d.ts +44 -0
- package/dist/query-form-url-state.d.ts.map +1 -0
- package/dist/query-form-url-state.js +197 -0
- package/dist/query-form-url-state.js.map +1 -0
- package/dist/query-offset-page.d.ts +13 -0
- package/dist/query-offset-page.d.ts.map +1 -0
- package/dist/query-offset-page.js +24 -0
- package/dist/query-offset-page.js.map +1 -0
- package/dist/relation-query-input-form-target.d.ts +10 -0
- package/dist/relation-query-input-form-target.d.ts.map +1 -0
- package/dist/relation-query-input-form-target.js +30 -0
- package/dist/relation-query-input-form-target.js.map +1 -0
- package/dist/scope-selection.d.ts +94 -0
- package/dist/scope-selection.d.ts.map +1 -0
- package/dist/scope-selection.js +95 -0
- package/dist/scope-selection.js.map +1 -0
- package/dist/target-bindings.d.ts +39 -0
- package/dist/target-bindings.d.ts.map +1 -0
- package/dist/target-bindings.js +40 -0
- package/dist/target-bindings.js.map +1 -0
- package/dist/view-chrome-content-diagnostics.d.ts +8 -0
- package/dist/view-chrome-content-diagnostics.d.ts.map +1 -0
- package/dist/view-chrome-content-diagnostics.js +84 -0
- package/dist/view-chrome-content-diagnostics.js.map +1 -0
- package/dist/view-chrome-icons.d.ts +12 -0
- package/dist/view-chrome-icons.d.ts.map +1 -0
- package/dist/view-chrome-icons.js +50 -0
- package/dist/view-chrome-icons.js.map +1 -0
- package/dist/view-chrome-slot-renderer-registry.d.ts +19 -0
- package/dist/view-chrome-slot-renderer-registry.d.ts.map +1 -0
- package/dist/view-chrome-slot-renderer-registry.js +62 -0
- package/dist/view-chrome-slot-renderer-registry.js.map +1 -0
- package/package.json +53 -0
- package/src/api-scope-request.ts +186 -0
- package/src/collection-chrome-icons.ts +89 -0
- package/src/collection-chrome-runtime.ts +151 -0
- package/src/collection-chrome-slot-renderer-registry.ts +227 -0
- package/src/collection-selection-state.ts +32 -0
- package/src/data-source-projection.ts +2149 -0
- package/src/data-source-query-lowering.ts +217 -0
- package/src/date-time-filter-model.ts +156 -0
- package/src/document-badge-icons.ts +3 -0
- package/src/document-module.ts +741 -0
- package/src/document-summary-model.ts +1 -0
- package/src/document-workspace-chrome-projection.ts +62 -0
- package/src/document-workspace-surface-slots.ts +458 -0
- package/src/endpoint-executor.ts +122 -0
- package/src/field-display-resolution.ts +99 -0
- package/src/index.ts +104 -0
- package/src/module.ts +281 -0
- package/src/navigation-shell-frame-renderer-registry.ts +65 -0
- package/src/navigation-shell-layout-runtime.ts +124 -0
- package/src/navigation-shell-region-component-registry.ts +242 -0
- package/src/navigation-shell-runtime.ts +579 -0
- package/src/navigation-shell-slot-renderer-registry.ts +94 -0
- package/src/navigation.ts +364 -0
- package/src/object-path.ts +99 -0
- package/src/page-host-renderer-registry.ts +615 -0
- package/src/presentation-action-endpoint-request-projection.ts +223 -0
- package/src/presentation-action-endpoint.ts +130 -0
- package/src/presentation-action-icons.ts +3 -0
- package/src/presentation-action-result-state.ts +189 -0
- package/src/presentation-action-runtime-binding.ts +177 -0
- package/src/presentation-action-runtime-diagnostics.ts +120 -0
- package/src/presentation-action-runtime-labels.ts +57 -0
- package/src/presentation-action-runtime-projection.ts +67 -0
- package/src/presentation-badge-resolution.ts +138 -0
- package/src/presentation-collection-pagination.ts +436 -0
- package/src/presentation-content-diagnostics.ts +121 -0
- package/src/presentation-content-resolution.ts +46 -0
- package/src/presentation-data-source-binding-model.ts +140 -0
- package/src/presentation-data-source-runtime.ts +190 -0
- package/src/presentation-design-intent-diagnostics.ts +104 -0
- package/src/presentation-icon-diagnostics.ts +368 -0
- package/src/presentation-icon-registry.ts +181 -0
- package/src/presentation-navigation-action-runtime-bindings.ts +54 -0
- package/src/presentation-pagination.ts +694 -0
- package/src/presentation-projection-coverage.ts +3257 -0
- package/src/presentation-projection-diagnostics.ts +71 -0
- package/src/presentation-projection-trace.ts +293 -0
- package/src/presentation-query-form-state.ts +54 -0
- package/src/presentation-renderer-registry.ts +269 -0
- package/src/presentation-semantics.ts +1028 -0
- package/src/presentation-standards.ts +14 -0
- package/src/presentation-test-selectors.ts +312 -0
- package/src/presentation-value-formatting.ts +65 -0
- package/src/presentation-value-resolution.ts +100 -0
- package/src/presentation-view-tree.ts +33 -0
- package/src/process-task-model.ts +158 -0
- package/src/process-task-projection.ts +398 -0
- package/src/projected-action-status-projection.ts +43 -0
- package/src/projected-activity-state-model.ts +123 -0
- package/src/projected-collection-action-runtime-bindings.ts +76 -0
- package/src/projected-collection-action-runtime-diagnostics.ts +289 -0
- package/src/projected-collection-runtime.ts +1772 -0
- package/src/projected-document-action-diagnostics.ts +196 -0
- package/src/projected-document-action-enablements.ts +99 -0
- package/src/projected-document-action-projection.ts +464 -0
- package/src/projected-document-action-runtime-profile-diagnostics.ts +250 -0
- package/src/projected-document-action-runtime-profile.ts +133 -0
- package/src/projected-document-action-status-notice-diagnostics.ts +116 -0
- package/src/projected-document-badge-formatting.ts +7 -0
- package/src/projected-document-editor-model.ts +7 -0
- package/src/projected-document-field-navigation.ts +300 -0
- package/src/projected-document-field-semantics.ts +27 -0
- package/src/projected-document-workspace-data-source-bindings.ts +182 -0
- package/src/projected-document-workspace-notice-diagnostics.ts +41 -0
- package/src/projected-input-form-runtime.ts +86 -0
- package/src/projected-process-task-notice-diagnostics.ts +283 -0
- package/src/projected-query-form-runtime.ts +62 -0
- package/src/prompt-document-preview-projection.ts +345 -0
- package/src/prompt-icons.ts +3 -0
- package/src/prompt-status-message-resolution.ts +158 -0
- package/src/query-form-lowering.ts +77 -0
- package/src/query-form-url-state.ts +346 -0
- package/src/query-offset-page.ts +50 -0
- package/src/relation-query-input-form-target.ts +61 -0
- package/src/scope-selection.ts +201 -0
- package/src/target-bindings.ts +123 -0
- package/src/view-chrome-content-diagnostics.ts +139 -0
- package/src/view-chrome-icons.ts +81 -0
- package/src/view-chrome-slot-renderer-registry.ts +128 -0
|
@@ -0,0 +1,2149 @@
|
|
|
1
|
+
import {
|
|
2
|
+
findPresentationDataSource,
|
|
3
|
+
type PresentationBindingDefinition,
|
|
4
|
+
type DataSourceDefinition,
|
|
5
|
+
type PresentationModuleDefinition,
|
|
6
|
+
} from './module'
|
|
7
|
+
import {
|
|
8
|
+
isTanStackQueryBinding,
|
|
9
|
+
presentationDataSourceBindings,
|
|
10
|
+
presentationDataSourceAuthorization,
|
|
11
|
+
type PresentationLocalValueDataSourceBinding,
|
|
12
|
+
type PresentationLocalValueDataSourceBindingInput,
|
|
13
|
+
type PresentationDataSourceAuthorizationRequirement,
|
|
14
|
+
type PresentationDataSourceBinding,
|
|
15
|
+
type PresentationTanStackQueryDataSourceBindingInput,
|
|
16
|
+
type PresentationTanStackQueryDataSourceBinding,
|
|
17
|
+
} from './presentation-data-source-binding-model'
|
|
18
|
+
import {
|
|
19
|
+
createDataSourceEndpointQueryRequest,
|
|
20
|
+
createDataSourcePaginationRequest,
|
|
21
|
+
findDataSourceQueryEndpointBinding,
|
|
22
|
+
type DataSourceQueryLoweringTransform,
|
|
23
|
+
} from './data-source-query-lowering'
|
|
24
|
+
import {
|
|
25
|
+
aggregateOperators,
|
|
26
|
+
cachePolicyKinds,
|
|
27
|
+
dataSourceAggregateMaterializationKinds,
|
|
28
|
+
dataSourceAggregatePredicateKinds,
|
|
29
|
+
dataSourceKindLabels,
|
|
30
|
+
dataSourceKinds,
|
|
31
|
+
presentationBindingKinds,
|
|
32
|
+
type AggregateOperator,
|
|
33
|
+
type DataSourceAggregatePredicate,
|
|
34
|
+
type DataSourceAggregateQuery,
|
|
35
|
+
type DataSourceKind,
|
|
36
|
+
type ParameterDefinition,
|
|
37
|
+
} from '@cohesivesystems/presentation-contracts'
|
|
38
|
+
import {
|
|
39
|
+
readPresentationQueryFormAppliedValue,
|
|
40
|
+
type PresentationQueryFormStateMap,
|
|
41
|
+
} from './presentation-query-form-state'
|
|
42
|
+
import {
|
|
43
|
+
readObjectPath,
|
|
44
|
+
writeObjectPath,
|
|
45
|
+
} from './object-path'
|
|
46
|
+
import type {
|
|
47
|
+
PresentationActionResultStateValues,
|
|
48
|
+
} from './presentation-action-result-state'
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Runtime inputs available while projecting semantic data-source definitions
|
|
52
|
+
* into concrete frontend bindings.
|
|
53
|
+
*/
|
|
54
|
+
export interface PresentationDataSourceProjectionContext {
|
|
55
|
+
/** Current query-form states keyed by query form or data-source state id. */
|
|
56
|
+
readonly queryFormStates?: PresentationQueryFormStateMap
|
|
57
|
+
|
|
58
|
+
/** Route parameters supplied by the active presentation/navigation host. */
|
|
59
|
+
readonly routeParameters?: Readonly<Record<string, string | undefined>>
|
|
60
|
+
|
|
61
|
+
/** Additional cache-key fragments supplied by the app or route host. */
|
|
62
|
+
readonly queryKeyParts?: readonly unknown[]
|
|
63
|
+
|
|
64
|
+
/** Workspace id used to scope local state or cache identity, when available. */
|
|
65
|
+
readonly workspaceId?: string | null
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Context passed to a registry factory while interpreting one semantic
|
|
70
|
+
* data-source definition.
|
|
71
|
+
*/
|
|
72
|
+
export interface PresentationDataSourceBindingFactoryContext {
|
|
73
|
+
/** Backend target binding attached to the data source, when one is declared. */
|
|
74
|
+
readonly binding: PresentationBindingDefinition | null
|
|
75
|
+
|
|
76
|
+
/** Projection context shared by all data sources in the current host. */
|
|
77
|
+
readonly context: PresentationDataSourceProjectionContext
|
|
78
|
+
|
|
79
|
+
/** Data-source definition being projected. */
|
|
80
|
+
readonly dataSource: DataSourceDefinition
|
|
81
|
+
|
|
82
|
+
/** Presentation module that owns the data source and related query metadata. */
|
|
83
|
+
readonly module: PresentationModuleDefinition | null
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Factory that projects one data source into a frontend binding.
|
|
88
|
+
*
|
|
89
|
+
* Returning `null` or `undefined` lets later registry fallbacks attempt the
|
|
90
|
+
* projection.
|
|
91
|
+
*/
|
|
92
|
+
export type PresentationDataSourceBindingFactory = (
|
|
93
|
+
context: PresentationDataSourceBindingFactoryContext,
|
|
94
|
+
) => PresentationDataSourceBinding | null | undefined
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Factory that produces TanStack Query binding input before target-level
|
|
98
|
+
* authorization is applied.
|
|
99
|
+
*/
|
|
100
|
+
export type PresentationTanStackQueryDataSourceBindingFactory = (
|
|
101
|
+
context: PresentationDataSourceBindingFactoryContext,
|
|
102
|
+
) => PresentationTargetInterpretedTanStackQueryDataSourceBindingInput | null | undefined
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Executes a backend endpoint id with the already-projected route/query
|
|
106
|
+
* request payload.
|
|
107
|
+
*
|
|
108
|
+
* @typeParam TResult - Result shape returned by the endpoint executor.
|
|
109
|
+
*/
|
|
110
|
+
export type PresentationDataSourceEndpointExecutor = <TResult = unknown>(
|
|
111
|
+
endpointId: string,
|
|
112
|
+
request: PresentationDataSourceEndpointExecutionRequest,
|
|
113
|
+
) => Promise<TResult>
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Request envelope passed to endpoint executors from projected data-source
|
|
117
|
+
* bindings.
|
|
118
|
+
*
|
|
119
|
+
* @typeParam TQuery - Query payload shape produced by query lowering.
|
|
120
|
+
*/
|
|
121
|
+
export interface PresentationDataSourceEndpointExecutionRequest<TQuery = unknown> {
|
|
122
|
+
/** Lowered query payload for endpoint-query data sources. */
|
|
123
|
+
readonly query?: TQuery | null
|
|
124
|
+
|
|
125
|
+
/** Route parameters for endpoint-fetch data sources. */
|
|
126
|
+
readonly routeParameters?: Readonly<Record<string, string | null | undefined>>
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Options read from backend target bindings that steer frontend endpoint and
|
|
131
|
+
* authorization interpretation.
|
|
132
|
+
*/
|
|
133
|
+
export interface PresentationDataSourceTargetBindingOptions {
|
|
134
|
+
/** Authorization policy id resolved by the target interpretation. */
|
|
135
|
+
readonly authorizationPolicyId?: string | null
|
|
136
|
+
|
|
137
|
+
/** Endpoint executor target id resolved by the API endpoint interpretation. */
|
|
138
|
+
readonly executionTargetId?: string | null
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Runtime behavior defaults read from data-source annotations and applied to
|
|
143
|
+
* query bindings.
|
|
144
|
+
*/
|
|
145
|
+
export interface PresentationDataSourceBindingRuntimeOptions {
|
|
146
|
+
/** Message shown when a successful query returns no presentable items. */
|
|
147
|
+
readonly emptyMessage?: string
|
|
148
|
+
|
|
149
|
+
/** Data used before a query resolves or when a source cannot be materialized. */
|
|
150
|
+
readonly fallbackData?: unknown
|
|
151
|
+
|
|
152
|
+
/** Loading label shown while the binding is pending. */
|
|
153
|
+
readonly pendingLabel?: string
|
|
154
|
+
|
|
155
|
+
/** TanStack Query refetch interval in milliseconds, or `false` to disable it. */
|
|
156
|
+
readonly refetchInterval?: number | false
|
|
157
|
+
|
|
158
|
+
/** TanStack Query retry setting. */
|
|
159
|
+
readonly retry?: boolean | number
|
|
160
|
+
|
|
161
|
+
/** TanStack Query stale time in milliseconds. */
|
|
162
|
+
readonly staleTime?: number
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Local-value binding input whose authorization can be supplied by the active
|
|
167
|
+
* target interpretation instead of every feature-owned binding factory.
|
|
168
|
+
*/
|
|
169
|
+
export type PresentationTargetInterpretedLocalValueDataSourceBindingInput = Omit<
|
|
170
|
+
PresentationLocalValueDataSourceBindingInput,
|
|
171
|
+
'authorization'
|
|
172
|
+
> & {
|
|
173
|
+
readonly authorization?: PresentationDataSourceAuthorizationRequirement
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// TODO: extract
|
|
177
|
+
/**
|
|
178
|
+
* TanStack Query binding input whose authorization can be supplied by the
|
|
179
|
+
* target interpretation. Feature registries still own request/query shaping.
|
|
180
|
+
*/
|
|
181
|
+
export type PresentationTargetInterpretedTanStackQueryDataSourceBindingInput = Omit<
|
|
182
|
+
PresentationTanStackQueryDataSourceBindingInput,
|
|
183
|
+
'authorization'
|
|
184
|
+
> & {
|
|
185
|
+
readonly authorization?: PresentationDataSourceAuthorizationRequirement
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** Resolves a data-source authorization requirement for a target binding. */
|
|
189
|
+
export type PresentationDataSourceAuthorizationFactory = (
|
|
190
|
+
context: PresentationDataSourceBindingFactoryContext,
|
|
191
|
+
) => PresentationDataSourceAuthorizationRequirement
|
|
192
|
+
|
|
193
|
+
/** Endpoint executors keyed by backend-declared execution target id. */
|
|
194
|
+
export type PresentationDataSourceEndpointExecutorMap = Readonly<Record<
|
|
195
|
+
string,
|
|
196
|
+
PresentationDataSourceEndpointExecutor
|
|
197
|
+
>>
|
|
198
|
+
|
|
199
|
+
/** Authorization factories keyed by backend-declared authorization policy id. */
|
|
200
|
+
export type PresentationDataSourceAuthorizationPolicyMap = Readonly<Record<
|
|
201
|
+
string,
|
|
202
|
+
PresentationDataSourceAuthorizationFactory
|
|
203
|
+
>>
|
|
204
|
+
|
|
205
|
+
/** Target-specific interpretation shared by all data sources of one binding kind. */
|
|
206
|
+
export interface PresentationDataSourceBindingTargetInterpretation {
|
|
207
|
+
/** Default authorization policy for this target binding kind. */
|
|
208
|
+
readonly authorization?: PresentationDataSourceAuthorizationFactory
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Target interpretation for API endpoint data sources. This owns endpoint
|
|
213
|
+
* execution and cross-cutting query defaults; semantic registries can still
|
|
214
|
+
* provide per-source query payloads, labels, and cache keys.
|
|
215
|
+
*/
|
|
216
|
+
export interface PresentationDataSourceApiEndpointTargetInterpretation
|
|
217
|
+
extends PresentationDataSourceBindingTargetInterpretation {
|
|
218
|
+
/** Creates a query key for endpoint-backed data sources. */
|
|
219
|
+
readonly createQueryKey?: (context: PresentationDataSourceApiEndpointFactoryContext) => readonly unknown[]
|
|
220
|
+
|
|
221
|
+
/** Default executor for API endpoint data sources. */
|
|
222
|
+
readonly executeEndpoint?: PresentationDataSourceEndpointExecutor
|
|
223
|
+
|
|
224
|
+
/** Executors keyed by target binding `executionTargetId`. */
|
|
225
|
+
readonly executeEndpointByTargetId?: PresentationDataSourceEndpointExecutorMap
|
|
226
|
+
|
|
227
|
+
/** Enables or disables endpoint-backed query execution. */
|
|
228
|
+
readonly isEnabled?: (context: PresentationDataSourceApiEndpointFactoryContext) => boolean
|
|
229
|
+
|
|
230
|
+
/** Default pending label for endpoint-backed query bindings. */
|
|
231
|
+
readonly pendingLabel?:
|
|
232
|
+
| string
|
|
233
|
+
| ((context: PresentationDataSourceApiEndpointFactoryContext) => string)
|
|
234
|
+
|
|
235
|
+
/** Default retry behavior for endpoint-backed query bindings. */
|
|
236
|
+
readonly retry?: boolean
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/** Target interpretation for backend-declared query lowering transform ids. */
|
|
240
|
+
export interface PresentationDataSourceQueryLoweringTargetInterpretation {
|
|
241
|
+
/** Query-lowering transforms keyed by backend-declared transform id. */
|
|
242
|
+
readonly transformsById?: Readonly<Record<string, DataSourceQueryLoweringTransform>>
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Frontend interpretation of backend data-source target bindings for one
|
|
247
|
+
* concrete presentation target.
|
|
248
|
+
*/
|
|
249
|
+
export interface PresentationDataSourceTargetInterpretation {
|
|
250
|
+
/** Interpretation for API endpoint data-source bindings. */
|
|
251
|
+
readonly apiEndpoint?: PresentationDataSourceApiEndpointTargetInterpretation
|
|
252
|
+
|
|
253
|
+
/** Named authorization policies available to target bindings. */
|
|
254
|
+
readonly authorizationPoliciesById?: PresentationDataSourceAuthorizationPolicyMap
|
|
255
|
+
|
|
256
|
+
/** Fallback authorization policy for bindings without a narrower policy. */
|
|
257
|
+
readonly defaultAuthorization?: PresentationDataSourceAuthorizationFactory
|
|
258
|
+
|
|
259
|
+
/** Interpretation for frontend-owned local state data-source bindings. */
|
|
260
|
+
readonly localState?: PresentationDataSourceBindingTargetInterpretation
|
|
261
|
+
|
|
262
|
+
/** Interpretation for backend-declared query-lowering transforms. */
|
|
263
|
+
readonly queryLowering?: PresentationDataSourceQueryLoweringTargetInterpretation
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/** Options used when invoking a projected endpoint through the target. */
|
|
267
|
+
export interface ExecutePresentationDataSourceTargetEndpointOptions {
|
|
268
|
+
/** Binding whose target options select endpoint executor and authorization policy. */
|
|
269
|
+
readonly binding?: PresentationBindingDefinition | null
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Registry of data-source binding factories used to project semantic data
|
|
274
|
+
* sources onto frontend runtime bindings.
|
|
275
|
+
*/
|
|
276
|
+
export interface PresentationDataSourceBindingProjectionRegistry {
|
|
277
|
+
/** Generic factory for API endpoint bindings. */
|
|
278
|
+
readonly apiEndpoint?: PresentationDataSourceBindingFactory
|
|
279
|
+
|
|
280
|
+
/** Exact factories keyed by data-source id. */
|
|
281
|
+
readonly byDataSourceId?: Readonly<Record<string, PresentationDataSourceBindingFactory>>
|
|
282
|
+
|
|
283
|
+
/** Exact factories keyed by endpoint id. */
|
|
284
|
+
readonly byEndpointId?: Readonly<Record<string, PresentationDataSourceBindingFactory>>
|
|
285
|
+
|
|
286
|
+
/** Default authorization policy used by unbound or projected bindings. */
|
|
287
|
+
readonly defaultAuthorization?: (
|
|
288
|
+
context: PresentationDataSourceBindingFactoryContext,
|
|
289
|
+
) => PresentationDataSourceAuthorizationRequirement
|
|
290
|
+
|
|
291
|
+
/** Last-resort factory when no exact or generic API factory matches. */
|
|
292
|
+
readonly fallback?: PresentationDataSourceBindingFactory
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Options for adapting target-interpreted TanStack Query binding factories into
|
|
297
|
+
* a full data-source projection registry.
|
|
298
|
+
*/
|
|
299
|
+
export interface TanStackQueryDataSourceBindingProjectionRegistryOptions {
|
|
300
|
+
/** Generic endpoint factory returning TanStack Query binding input. */
|
|
301
|
+
readonly apiEndpoint?: PresentationTanStackQueryDataSourceBindingFactory
|
|
302
|
+
|
|
303
|
+
/** Exact factories keyed by data-source id. */
|
|
304
|
+
readonly byDataSourceId?: Readonly<Record<string, PresentationDataSourceBindingFactory>>
|
|
305
|
+
|
|
306
|
+
/** Exact endpoint factories keyed by endpoint id. */
|
|
307
|
+
readonly byEndpointId?: Readonly<Record<string, PresentationTanStackQueryDataSourceBindingFactory>>
|
|
308
|
+
|
|
309
|
+
/** Authorization policy applied when a factory does not provide one. */
|
|
310
|
+
readonly defaultAuthorization?: (
|
|
311
|
+
context: PresentationDataSourceBindingFactoryContext,
|
|
312
|
+
) => PresentationDataSourceAuthorizationRequirement
|
|
313
|
+
|
|
314
|
+
/** Active target interpretation that supplies authorization and execution defaults. */
|
|
315
|
+
readonly targetInterpretation?: PresentationDataSourceTargetInterpretation
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Options for the generic API endpoint TanStack Query projector.
|
|
320
|
+
*/
|
|
321
|
+
export interface ApiEndpointTanStackQueryDataSourceBindingProjectionRegistryOptions {
|
|
322
|
+
/** Optional target-specific cache key builder. */
|
|
323
|
+
readonly createQueryKey?: (
|
|
324
|
+
context: PresentationDataSourceApiEndpointFactoryContext,
|
|
325
|
+
) => readonly unknown[]
|
|
326
|
+
|
|
327
|
+
/** Optional endpoint executor overriding the active target interpretation. */
|
|
328
|
+
readonly executeEndpoint?: PresentationDataSourceEndpointExecutor
|
|
329
|
+
|
|
330
|
+
/** Optional query enablement guard. */
|
|
331
|
+
readonly isEnabled?: (context: PresentationDataSourceApiEndpointFactoryContext) => boolean
|
|
332
|
+
|
|
333
|
+
/** Pending label or label factory for generated query bindings. */
|
|
334
|
+
readonly pendingLabel?: string | ((context: PresentationDataSourceApiEndpointFactoryContext) => string)
|
|
335
|
+
|
|
336
|
+
/** Retry behavior for generated query bindings. */
|
|
337
|
+
readonly retry?: boolean
|
|
338
|
+
|
|
339
|
+
/** Default authorization policy applied to generated query bindings. */
|
|
340
|
+
readonly defaultAuthorization?: (
|
|
341
|
+
context: PresentationDataSourceBindingFactoryContext,
|
|
342
|
+
) => PresentationDataSourceAuthorizationRequirement
|
|
343
|
+
|
|
344
|
+
/** Active target interpretation that supplies defaults not provided here. */
|
|
345
|
+
readonly targetInterpretation?: PresentationDataSourceTargetInterpretation
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Factory context for API endpoint data-source bindings after endpoint id and
|
|
350
|
+
* route parameters have been resolved.
|
|
351
|
+
*/
|
|
352
|
+
export interface PresentationDataSourceApiEndpointFactoryContext
|
|
353
|
+
extends PresentationDataSourceBindingFactoryContext {
|
|
354
|
+
/** Resolved API endpoint id. */
|
|
355
|
+
readonly endpointId: string
|
|
356
|
+
|
|
357
|
+
/** Route parameters projected for this data source. */
|
|
358
|
+
readonly routeParameters: Readonly<Record<string, string | null | undefined>>
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/** Options for projecting a list of semantic data-source ids. */
|
|
362
|
+
export interface ProjectPresentationDataSourceBindingsOptions {
|
|
363
|
+
/** Shared runtime projection context. */
|
|
364
|
+
readonly context?: PresentationDataSourceProjectionContext
|
|
365
|
+
|
|
366
|
+
/** Fallback data-source definitions when the module does not contain an id. */
|
|
367
|
+
readonly dataSourceDefinitions?: readonly DataSourceDefinition[]
|
|
368
|
+
|
|
369
|
+
/** Data-source ids to project, de-duplicated before projection. */
|
|
370
|
+
readonly dataSourceIds: readonly string[]
|
|
371
|
+
|
|
372
|
+
/** Presentation module that owns data-source definitions and target bindings. */
|
|
373
|
+
readonly module: PresentationModuleDefinition | null
|
|
374
|
+
|
|
375
|
+
/** Projection registry used to resolve concrete frontend bindings. */
|
|
376
|
+
readonly registry: PresentationDataSourceBindingProjectionRegistry
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Options for creating endpoint-query binding input from backend query
|
|
381
|
+
* lowering.
|
|
382
|
+
*
|
|
383
|
+
* @typeParam TRequest - Lowered endpoint query request shape.
|
|
384
|
+
*/
|
|
385
|
+
export interface CreateDataSourceEndpointQueryBindingInputOptions<
|
|
386
|
+
TRequest extends object,
|
|
387
|
+
> {
|
|
388
|
+
/** Factory context for the data source being projected. */
|
|
389
|
+
readonly context: PresentationDataSourceBindingFactoryContext
|
|
390
|
+
|
|
391
|
+
/** Base request values merged into the lowered query request. */
|
|
392
|
+
readonly defaultRequest?: Partial<TRequest>
|
|
393
|
+
|
|
394
|
+
/** Empty-state message for the generated query binding. */
|
|
395
|
+
readonly emptyMessage?: string
|
|
396
|
+
|
|
397
|
+
/** Query enablement override. */
|
|
398
|
+
readonly enabled?: boolean
|
|
399
|
+
|
|
400
|
+
/** Endpoint id to execute. */
|
|
401
|
+
readonly endpointId: string
|
|
402
|
+
|
|
403
|
+
/** Fallback data for the generated query binding. */
|
|
404
|
+
readonly fallbackData?: unknown
|
|
405
|
+
|
|
406
|
+
/** Pagination request merged into the lowered query request. */
|
|
407
|
+
readonly paginationRequest?: object | null
|
|
408
|
+
|
|
409
|
+
/** Pending label for the generated query binding. */
|
|
410
|
+
readonly pendingLabel?: string
|
|
411
|
+
|
|
412
|
+
/** Additional query-key fragments. */
|
|
413
|
+
readonly queryKeyParts?: readonly unknown[]
|
|
414
|
+
|
|
415
|
+
/** Refetch interval in milliseconds, or `false` to disable it. */
|
|
416
|
+
readonly refetchInterval?: number | false
|
|
417
|
+
|
|
418
|
+
/** Retry behavior for the generated query binding. */
|
|
419
|
+
readonly retry?: boolean | number
|
|
420
|
+
|
|
421
|
+
/** Stale time in milliseconds. */
|
|
422
|
+
readonly staleTime?: number
|
|
423
|
+
|
|
424
|
+
/** Target interpretation used for endpoint execution and authorization. */
|
|
425
|
+
readonly targetInterpretation: PresentationDataSourceTargetInterpretation
|
|
426
|
+
|
|
427
|
+
/** Per-source query lowering transforms. */
|
|
428
|
+
readonly transforms?: Readonly<Record<string, DataSourceQueryLoweringTransform>>
|
|
429
|
+
|
|
430
|
+
/** Source value used by query lowering. */
|
|
431
|
+
readonly value?: unknown
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/** Options for creating endpoint-fetch binding input from a data source. */
|
|
435
|
+
export interface CreateDataSourceEndpointFetchBindingInputOptions {
|
|
436
|
+
/** Factory context for the data source being projected. */
|
|
437
|
+
readonly context: PresentationDataSourceBindingFactoryContext
|
|
438
|
+
|
|
439
|
+
/** Empty-state message for the generated query binding. */
|
|
440
|
+
readonly emptyMessage?: string
|
|
441
|
+
|
|
442
|
+
/** Query enablement override. */
|
|
443
|
+
readonly enabled?: boolean
|
|
444
|
+
|
|
445
|
+
/** Endpoint id to execute, defaulting to the data-source binding endpoint. */
|
|
446
|
+
readonly endpointId?: string
|
|
447
|
+
|
|
448
|
+
/** Fallback data for the generated query binding. */
|
|
449
|
+
readonly fallbackData?: unknown
|
|
450
|
+
|
|
451
|
+
/** Pending label for the generated query binding. */
|
|
452
|
+
readonly pendingLabel?: string
|
|
453
|
+
|
|
454
|
+
/** Additional query-key fragments. */
|
|
455
|
+
readonly queryKeyParts?: readonly unknown[]
|
|
456
|
+
|
|
457
|
+
/** Refetch interval in milliseconds, or `false` to disable it. */
|
|
458
|
+
readonly refetchInterval?: number | false
|
|
459
|
+
|
|
460
|
+
/** Retry behavior for the generated query binding. */
|
|
461
|
+
readonly retry?: boolean | number
|
|
462
|
+
|
|
463
|
+
/** Route parameters to pass to the endpoint executor. */
|
|
464
|
+
readonly routeParameters?: Readonly<Record<string, string | null | undefined>>
|
|
465
|
+
|
|
466
|
+
/** Stale time in milliseconds. */
|
|
467
|
+
readonly staleTime?: number
|
|
468
|
+
|
|
469
|
+
/** Target interpretation used for endpoint execution and authorization. */
|
|
470
|
+
readonly targetInterpretation: PresentationDataSourceTargetInterpretation
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/** Options for projecting an aggregate-query data source. */
|
|
474
|
+
export interface CreateDataSourceAggregateQueryBindingOptions {
|
|
475
|
+
/** Factory context for the aggregate data source being projected. */
|
|
476
|
+
readonly context: PresentationDataSourceBindingFactoryContext
|
|
477
|
+
|
|
478
|
+
/** Additional query-key fragments. */
|
|
479
|
+
readonly queryKeyParts?: readonly unknown[]
|
|
480
|
+
|
|
481
|
+
/** Target interpretation used to materialize source data. */
|
|
482
|
+
readonly targetInterpretation: PresentationDataSourceTargetInterpretation
|
|
483
|
+
|
|
484
|
+
/** Per-source query lowering transforms used to query the source data source. */
|
|
485
|
+
readonly transforms?: Readonly<Record<string, DataSourceQueryLoweringTransform>>
|
|
486
|
+
|
|
487
|
+
/** Source value used by query lowering. */
|
|
488
|
+
readonly value?: unknown
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/** Options for creating a collection-query projection registry. */
|
|
492
|
+
export interface CreateCollectionQueryDataSourceBindingProjectionRegistryOptions {
|
|
493
|
+
/** Pagination requests keyed by data-source id. */
|
|
494
|
+
readonly paginationRequestsByDataSourceId?: Readonly<Record<string, object | null | undefined>>
|
|
495
|
+
|
|
496
|
+
/** Static or computed query-key fragments. */
|
|
497
|
+
readonly queryKeyParts?:
|
|
498
|
+
| readonly unknown[]
|
|
499
|
+
| ((context: PresentationDataSourceBindingFactoryContext) => readonly unknown[])
|
|
500
|
+
|
|
501
|
+
/** Optional local-value override for collection data sources. */
|
|
502
|
+
readonly resolveLocalValue?: (
|
|
503
|
+
context: PresentationDataSourceBindingFactoryContext,
|
|
504
|
+
) => PresentationTargetInterpretedLocalValueDataSourceBindingInput | null | undefined
|
|
505
|
+
|
|
506
|
+
/** Optional per-source query-lowering transform resolver. */
|
|
507
|
+
readonly resolveTransforms?: (
|
|
508
|
+
context: PresentationDataSourceBindingFactoryContext,
|
|
509
|
+
) => Readonly<Record<string, DataSourceQueryLoweringTransform>> | undefined
|
|
510
|
+
|
|
511
|
+
/** Optional source value resolver for query lowering. */
|
|
512
|
+
readonly resolveValue?: (
|
|
513
|
+
context: PresentationDataSourceBindingFactoryContext,
|
|
514
|
+
) => unknown
|
|
515
|
+
|
|
516
|
+
/** Target interpretation used for generated bindings. */
|
|
517
|
+
readonly targetInterpretation: PresentationDataSourceTargetInterpretation
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/** Options for creating an aggregate-query projection registry. */
|
|
521
|
+
export interface CreateAggregateQueryDataSourceBindingProjectionRegistryOptions {
|
|
522
|
+
/** Static or computed query-key fragments. */
|
|
523
|
+
readonly queryKeyParts?:
|
|
524
|
+
| readonly unknown[]
|
|
525
|
+
| ((context: PresentationDataSourceBindingFactoryContext) => readonly unknown[])
|
|
526
|
+
|
|
527
|
+
/** Optional per-source query-lowering transform resolver. */
|
|
528
|
+
readonly resolveTransforms?: (
|
|
529
|
+
context: PresentationDataSourceBindingFactoryContext,
|
|
530
|
+
) => Readonly<Record<string, DataSourceQueryLoweringTransform>> | undefined
|
|
531
|
+
|
|
532
|
+
/** Optional source value resolver for query lowering. */
|
|
533
|
+
readonly resolveValue?: (
|
|
534
|
+
context: PresentationDataSourceBindingFactoryContext,
|
|
535
|
+
) => unknown
|
|
536
|
+
|
|
537
|
+
/** Target interpretation used for generated bindings. */
|
|
538
|
+
readonly targetInterpretation: PresentationDataSourceTargetInterpretation
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/** Options for creating endpoint-fetch projection registries. */
|
|
542
|
+
export interface CreateApiEndpointFetchDataSourceBindingProjectionRegistryOptions {
|
|
543
|
+
/** Static or computed query-key fragments. */
|
|
544
|
+
readonly queryKeyParts?:
|
|
545
|
+
| readonly unknown[]
|
|
546
|
+
| ((context: PresentationDataSourceBindingFactoryContext) => readonly unknown[])
|
|
547
|
+
|
|
548
|
+
/** Target interpretation used for generated bindings. */
|
|
549
|
+
readonly targetInterpretation: PresentationDataSourceTargetInterpretation
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/** Options for creating local-state projection registries. */
|
|
553
|
+
export interface CreateLocalStateDataSourceBindingProjectionRegistryOptions {
|
|
554
|
+
/** Resolves a local-value binding input for a local-state data source. */
|
|
555
|
+
readonly resolveLocalValue: (
|
|
556
|
+
context: PresentationDataSourceBindingFactoryContext,
|
|
557
|
+
) => PresentationTargetInterpretedLocalValueDataSourceBindingInput | null | undefined
|
|
558
|
+
|
|
559
|
+
/** Target interpretation used for authorization defaults. */
|
|
560
|
+
readonly targetInterpretation: PresentationDataSourceTargetInterpretation
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/** Options for projecting action-result state values as data-source bindings. */
|
|
564
|
+
export interface CreateActionResultStateDataSourceBindingProjectionRegistryOptions {
|
|
565
|
+
/** Route-scoped data-source values written by action result policies. */
|
|
566
|
+
readonly values?: PresentationActionResultStateValues
|
|
567
|
+
|
|
568
|
+
/** Target interpretation used for authorization defaults. */
|
|
569
|
+
readonly targetInterpretation: PresentationDataSourceTargetInterpretation
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/** Static or factory-produced query-key fragments used by binding projectors. */
|
|
573
|
+
export type DataSourceQueryKeyParts =
|
|
574
|
+
| readonly unknown[]
|
|
575
|
+
| ((context: PresentationDataSourceBindingFactoryContext) => readonly unknown[])
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* Per-data-source interpretation hooks used by collection and aggregate query
|
|
579
|
+
* projectors.
|
|
580
|
+
*/
|
|
581
|
+
export interface DataSourceQueryInterpretation {
|
|
582
|
+
/** Optional local-value override for the data source. */
|
|
583
|
+
readonly localValue?: (context: PresentationDataSourceBindingFactoryContext) => PresentationTargetInterpretedLocalValueDataSourceBindingInput | null | undefined
|
|
584
|
+
|
|
585
|
+
/** Normalizes a source value before query lowering. */
|
|
586
|
+
readonly normalizeValue?: (value: unknown, context: PresentationDataSourceBindingFactoryContext) => unknown
|
|
587
|
+
|
|
588
|
+
/** Query-key fragments for this data source. */
|
|
589
|
+
readonly queryKeyParts?: DataSourceQueryKeyParts
|
|
590
|
+
|
|
591
|
+
/** Reads the source value used by query lowering. */
|
|
592
|
+
readonly readValue?: (context: PresentationDataSourceBindingFactoryContext) => unknown
|
|
593
|
+
|
|
594
|
+
/** Per-data-source query lowering transforms or transform resolver. */
|
|
595
|
+
readonly transforms?:
|
|
596
|
+
| Readonly<Record<string, DataSourceQueryLoweringTransform>>
|
|
597
|
+
| ((context: PresentationDataSourceBindingFactoryContext) => Readonly<Record<string, DataSourceQueryLoweringTransform>> | undefined)
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
/** Registry of query interpretation hooks keyed by data-source id. */
|
|
601
|
+
export interface DataSourceQueryInterpretationRegistry {
|
|
602
|
+
/** Per-source interpretation hooks keyed by data-source id. */
|
|
603
|
+
readonly byDataSourceId?: Readonly<Record<string, DataSourceQueryInterpretation>>
|
|
604
|
+
|
|
605
|
+
/** Default query-key fragments when a source has no override. */
|
|
606
|
+
readonly defaultQueryKeyParts?: DataSourceQueryKeyParts
|
|
607
|
+
|
|
608
|
+
/** Shared query lowering transforms or transform resolver. */
|
|
609
|
+
readonly transforms?:
|
|
610
|
+
| Readonly<Record<string, DataSourceQueryLoweringTransform>>
|
|
611
|
+
| ((context: PresentationDataSourceBindingFactoryContext) => Readonly<Record<string, DataSourceQueryLoweringTransform>> | undefined)
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
/**
|
|
615
|
+
* Resolvers adapted from a query interpretation registry to the option shape
|
|
616
|
+
* consumed by collection and aggregate binding registry factories.
|
|
617
|
+
*/
|
|
618
|
+
export type DataSourceQueryInterpretationResolvers = Pick<
|
|
619
|
+
CreateCollectionQueryDataSourceBindingProjectionRegistryOptions,
|
|
620
|
+
'queryKeyParts' | 'resolveLocalValue' | 'resolveTransforms' | 'resolveValue'
|
|
621
|
+
> &
|
|
622
|
+
Pick<
|
|
623
|
+
CreateAggregateQueryDataSourceBindingProjectionRegistryOptions,
|
|
624
|
+
'queryKeyParts' | 'resolveTransforms' | 'resolveValue'
|
|
625
|
+
>
|
|
626
|
+
|
|
627
|
+
/** Preserves target interpretation objects as a named projection concept. */
|
|
628
|
+
export function createPresentationDataSourceTargetInterpretation(
|
|
629
|
+
interpretation: PresentationDataSourceTargetInterpretation,
|
|
630
|
+
): PresentationDataSourceTargetInterpretation {
|
|
631
|
+
return interpretation
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* Resolves authorization from the target interpretation based on the backend
|
|
636
|
+
* binding kind declared for the data source.
|
|
637
|
+
*/
|
|
638
|
+
export function resolvePresentationDataSourceTargetAuthorization(
|
|
639
|
+
targetInterpretation: PresentationDataSourceTargetInterpretation | undefined,
|
|
640
|
+
context: PresentationDataSourceBindingFactoryContext,
|
|
641
|
+
): PresentationDataSourceAuthorizationRequirement {
|
|
642
|
+
const options = readPresentationDataSourceTargetBindingOptions(context.binding)
|
|
643
|
+
if (options.authorizationPolicyId) {
|
|
644
|
+
return (
|
|
645
|
+
targetInterpretation?.authorizationPoliciesById?.[options.authorizationPolicyId]?.(context) ??
|
|
646
|
+
presentationDataSourceAuthorization.required({
|
|
647
|
+
blockedLabel: `No frontend authorization policy is registered for '${options.authorizationPolicyId}'.`,
|
|
648
|
+
isAuthorized: false,
|
|
649
|
+
})
|
|
650
|
+
)
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
if (isApiEndpointBinding(context.binding)) {
|
|
654
|
+
return (
|
|
655
|
+
targetInterpretation?.apiEndpoint?.authorization?.(context) ??
|
|
656
|
+
targetInterpretation?.defaultAuthorization?.(context) ??
|
|
657
|
+
presentationDataSourceAuthorization.none()
|
|
658
|
+
)
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
if (isLocalStateBinding(context.binding)) {
|
|
662
|
+
return (
|
|
663
|
+
targetInterpretation?.localState?.authorization?.(context) ??
|
|
664
|
+
targetInterpretation?.defaultAuthorization?.(context) ??
|
|
665
|
+
presentationDataSourceAuthorization.none()
|
|
666
|
+
)
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
return (
|
|
670
|
+
targetInterpretation?.defaultAuthorization?.(context) ??
|
|
671
|
+
presentationDataSourceAuthorization.none()
|
|
672
|
+
)
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
/** Creates a local-value binding with authorization supplied by the target. */
|
|
676
|
+
export function createTargetInterpretedLocalValueDataSourceBinding(
|
|
677
|
+
context: PresentationDataSourceBindingFactoryContext,
|
|
678
|
+
targetInterpretation: PresentationDataSourceTargetInterpretation | undefined,
|
|
679
|
+
binding: PresentationTargetInterpretedLocalValueDataSourceBindingInput,
|
|
680
|
+
): PresentationLocalValueDataSourceBinding {
|
|
681
|
+
const { authorization, ...bindingWithoutAuthorization } = binding
|
|
682
|
+
return presentationDataSourceBindings.localValue({
|
|
683
|
+
...bindingWithoutAuthorization,
|
|
684
|
+
authorization:
|
|
685
|
+
authorization ??
|
|
686
|
+
resolvePresentationDataSourceTargetAuthorization(targetInterpretation, context),
|
|
687
|
+
})
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
/** Creates a TanStack Query binding with authorization supplied by the target. */
|
|
691
|
+
export function createTargetInterpretedTanStackQueryDataSourceBinding(
|
|
692
|
+
context: PresentationDataSourceBindingFactoryContext,
|
|
693
|
+
targetInterpretation: PresentationDataSourceTargetInterpretation | undefined,
|
|
694
|
+
binding: PresentationTargetInterpretedTanStackQueryDataSourceBindingInput,
|
|
695
|
+
defaultAuthorization?: PresentationDataSourceAuthorizationFactory,
|
|
696
|
+
): PresentationTanStackQueryDataSourceBinding {
|
|
697
|
+
const { authorization, ...bindingWithoutAuthorization } = binding
|
|
698
|
+
return presentationDataSourceBindings.tanstackQuery({
|
|
699
|
+
...bindingWithoutAuthorization,
|
|
700
|
+
authorization:
|
|
701
|
+
authorization ??
|
|
702
|
+
defaultAuthorization?.(context) ??
|
|
703
|
+
resolvePresentationDataSourceTargetAuthorization(targetInterpretation, context),
|
|
704
|
+
})
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
/** Creates endpoint-query binding input from backend-declared query lowering. */
|
|
708
|
+
export function createDataSourceEndpointQueryBindingInput<
|
|
709
|
+
TRequest extends object = Record<string, unknown>,
|
|
710
|
+
TResult = unknown,
|
|
711
|
+
>({
|
|
712
|
+
context,
|
|
713
|
+
defaultRequest,
|
|
714
|
+
emptyMessage,
|
|
715
|
+
enabled,
|
|
716
|
+
endpointId,
|
|
717
|
+
fallbackData,
|
|
718
|
+
paginationRequest,
|
|
719
|
+
pendingLabel,
|
|
720
|
+
queryKeyParts = [],
|
|
721
|
+
refetchInterval,
|
|
722
|
+
retry,
|
|
723
|
+
staleTime,
|
|
724
|
+
targetInterpretation,
|
|
725
|
+
transforms,
|
|
726
|
+
value,
|
|
727
|
+
}: CreateDataSourceEndpointQueryBindingInputOptions<TRequest>): PresentationTargetInterpretedTanStackQueryDataSourceBindingInput {
|
|
728
|
+
const loweredTransforms = mergeDataSourceQueryLoweringTransforms(
|
|
729
|
+
targetInterpretation.queryLowering?.transformsById,
|
|
730
|
+
transforms,
|
|
731
|
+
)
|
|
732
|
+
const query = createDataSourceEndpointQueryRequest<TRequest>({
|
|
733
|
+
dataSource: context.dataSource,
|
|
734
|
+
defaultRequest,
|
|
735
|
+
endpointId,
|
|
736
|
+
paginationRequest,
|
|
737
|
+
transforms: loweredTransforms,
|
|
738
|
+
value,
|
|
739
|
+
})
|
|
740
|
+
const runtimeOptions = readDataSourceBindingRuntimeOptions(context.dataSource)
|
|
741
|
+
|
|
742
|
+
return {
|
|
743
|
+
dataSourceId: context.dataSource.Id,
|
|
744
|
+
emptyMessage: emptyMessage ?? runtimeOptions.emptyMessage,
|
|
745
|
+
enabled,
|
|
746
|
+
fallbackData: fallbackData === undefined ? runtimeOptions.fallbackData : fallbackData,
|
|
747
|
+
pendingLabel: pendingLabel ?? runtimeOptions.pendingLabel,
|
|
748
|
+
queryFn: () =>
|
|
749
|
+
executePresentationDataSourceTargetEndpoint<TResult>(
|
|
750
|
+
targetInterpretation,
|
|
751
|
+
endpointId,
|
|
752
|
+
{ query },
|
|
753
|
+
{ binding: context.binding },
|
|
754
|
+
),
|
|
755
|
+
queryKey: [
|
|
756
|
+
'presentation-data-source-endpoint-query',
|
|
757
|
+
context.dataSource.Id,
|
|
758
|
+
endpointId,
|
|
759
|
+
query,
|
|
760
|
+
...queryKeyParts,
|
|
761
|
+
],
|
|
762
|
+
refetchInterval: refetchInterval ?? runtimeOptions.refetchInterval,
|
|
763
|
+
retry: retry ?? runtimeOptions.retry,
|
|
764
|
+
staleTime: staleTime ?? runtimeOptions.staleTime,
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
/** Creates a fully wrapped endpoint-query binding from backend query lowering. */
|
|
769
|
+
export function createDataSourceEndpointQueryBinding<
|
|
770
|
+
TRequest extends object = Record<string, unknown>,
|
|
771
|
+
TResult = unknown,
|
|
772
|
+
>(
|
|
773
|
+
options: CreateDataSourceEndpointQueryBindingInputOptions<TRequest>,
|
|
774
|
+
): PresentationTanStackQueryDataSourceBinding {
|
|
775
|
+
return createTargetInterpretedTanStackQueryDataSourceBinding(
|
|
776
|
+
options.context,
|
|
777
|
+
options.targetInterpretation,
|
|
778
|
+
createDataSourceEndpointQueryBindingInput<TRequest, TResult>(options),
|
|
779
|
+
)
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
/** Creates a default binding registry for backend-declared collection-query data sources. */
|
|
783
|
+
export function createCollectionQueryDataSourceBindingProjectionRegistry({
|
|
784
|
+
paginationRequestsByDataSourceId = {},
|
|
785
|
+
queryKeyParts = [],
|
|
786
|
+
resolveLocalValue,
|
|
787
|
+
resolveTransforms,
|
|
788
|
+
resolveValue,
|
|
789
|
+
targetInterpretation,
|
|
790
|
+
}: CreateCollectionQueryDataSourceBindingProjectionRegistryOptions): PresentationDataSourceBindingProjectionRegistry {
|
|
791
|
+
return {
|
|
792
|
+
apiEndpoint: (context) => {
|
|
793
|
+
if (
|
|
794
|
+
!isCollectionQueryDataSource(context.dataSource) ||
|
|
795
|
+
!context.dataSource.Query
|
|
796
|
+
) {
|
|
797
|
+
return null
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
const localValue = resolveLocalValue?.(context)
|
|
801
|
+
if (localValue) {
|
|
802
|
+
return createTargetInterpretedLocalValueDataSourceBinding(
|
|
803
|
+
context,
|
|
804
|
+
targetInterpretation,
|
|
805
|
+
localValue,
|
|
806
|
+
)
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
const endpointId = readPresentationDataSourceEndpointId(context.binding)
|
|
810
|
+
if (!endpointId) {
|
|
811
|
+
return null
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
return createDataSourceEndpointQueryBinding({
|
|
815
|
+
context,
|
|
816
|
+
endpointId,
|
|
817
|
+
paginationRequest: paginationRequestsByDataSourceId[context.dataSource.Id],
|
|
818
|
+
queryKeyParts: resolveQueryKeyParts(queryKeyParts, context),
|
|
819
|
+
targetInterpretation,
|
|
820
|
+
transforms: resolveTransforms?.(context),
|
|
821
|
+
value:
|
|
822
|
+
resolveValue?.(context) ??
|
|
823
|
+
readPresentationQueryFormAppliedValue(context.context, context.dataSource.Id),
|
|
824
|
+
})
|
|
825
|
+
},
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
/** Creates a default binding registry for backend-declared aggregate-query data sources. */
|
|
830
|
+
export function createAggregateQueryDataSourceBindingProjectionRegistry({
|
|
831
|
+
queryKeyParts = [],
|
|
832
|
+
resolveTransforms,
|
|
833
|
+
resolveValue,
|
|
834
|
+
targetInterpretation,
|
|
835
|
+
}: CreateAggregateQueryDataSourceBindingProjectionRegistryOptions): PresentationDataSourceBindingProjectionRegistry {
|
|
836
|
+
return {
|
|
837
|
+
fallback: (context) => {
|
|
838
|
+
if (
|
|
839
|
+
!isAggregateQueryDataSource(context.dataSource) ||
|
|
840
|
+
!context.dataSource.Aggregation
|
|
841
|
+
) {
|
|
842
|
+
return null
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
return createDataSourceAggregateQueryBinding({
|
|
846
|
+
context,
|
|
847
|
+
queryKeyParts: resolveQueryKeyParts(queryKeyParts, context),
|
|
848
|
+
targetInterpretation,
|
|
849
|
+
transforms: resolveTransforms?.(context),
|
|
850
|
+
value: resolveValue?.(context),
|
|
851
|
+
})
|
|
852
|
+
},
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
/** Creates a default fetch binding registry for endpoint-backed data sources. */
|
|
857
|
+
export function createApiEndpointFetchDataSourceBindingProjectionRegistry({
|
|
858
|
+
queryKeyParts = [],
|
|
859
|
+
targetInterpretation,
|
|
860
|
+
}: CreateApiEndpointFetchDataSourceBindingProjectionRegistryOptions): PresentationDataSourceBindingProjectionRegistry {
|
|
861
|
+
return {
|
|
862
|
+
apiEndpoint: (context) => {
|
|
863
|
+
if (context.dataSource.Query || isPromptPreviewDataSource(context.dataSource)) {
|
|
864
|
+
return null
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
const endpointId = readPresentationDataSourceEndpointId(context.binding)
|
|
868
|
+
if (!endpointId) {
|
|
869
|
+
return null
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
return createDataSourceEndpointFetchBinding({
|
|
873
|
+
context,
|
|
874
|
+
endpointId,
|
|
875
|
+
queryKeyParts: resolveQueryKeyParts(queryKeyParts, context),
|
|
876
|
+
targetInterpretation,
|
|
877
|
+
})
|
|
878
|
+
},
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
/** Creates a default binding registry for frontend-owned local-state data sources. */
|
|
883
|
+
export function createLocalStateDataSourceBindingProjectionRegistry({
|
|
884
|
+
resolveLocalValue,
|
|
885
|
+
targetInterpretation,
|
|
886
|
+
}: CreateLocalStateDataSourceBindingProjectionRegistryOptions): PresentationDataSourceBindingProjectionRegistry {
|
|
887
|
+
return {
|
|
888
|
+
fallback: (context) => {
|
|
889
|
+
if (!isLocalStateDataSource(context.dataSource)) {
|
|
890
|
+
return null
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
const localValue = resolveLocalValue(context)
|
|
894
|
+
return localValue
|
|
895
|
+
? createTargetInterpretedLocalValueDataSourceBinding(
|
|
896
|
+
context,
|
|
897
|
+
targetInterpretation,
|
|
898
|
+
localValue,
|
|
899
|
+
)
|
|
900
|
+
: null
|
|
901
|
+
},
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
/**
|
|
906
|
+
* Creates a binding registry that exposes action-result state writes as local
|
|
907
|
+
* values for their target data sources.
|
|
908
|
+
*/
|
|
909
|
+
export function createActionResultStateDataSourceBindingProjectionRegistry({
|
|
910
|
+
targetInterpretation,
|
|
911
|
+
values = {},
|
|
912
|
+
}: CreateActionResultStateDataSourceBindingProjectionRegistryOptions): PresentationDataSourceBindingProjectionRegistry {
|
|
913
|
+
return {
|
|
914
|
+
fallback: (context) => {
|
|
915
|
+
if (!hasOwn(values, context.dataSource.Id)) {
|
|
916
|
+
return null
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
return createTargetInterpretedLocalValueDataSourceBinding(
|
|
920
|
+
context,
|
|
921
|
+
targetInterpretation,
|
|
922
|
+
{
|
|
923
|
+
data: values[context.dataSource.Id],
|
|
924
|
+
dataSourceId: context.dataSource.Id,
|
|
925
|
+
},
|
|
926
|
+
)
|
|
927
|
+
},
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
/** Adapts data-source query interpretation metadata to collection/aggregate projector hooks. */
|
|
932
|
+
export function createDataSourceQueryInterpretationResolvers({
|
|
933
|
+
byDataSourceId = {},
|
|
934
|
+
defaultQueryKeyParts = [],
|
|
935
|
+
transforms,
|
|
936
|
+
}: DataSourceQueryInterpretationRegistry): DataSourceQueryInterpretationResolvers {
|
|
937
|
+
return {
|
|
938
|
+
queryKeyParts: (context) =>
|
|
939
|
+
resolveQueryKeyParts(
|
|
940
|
+
byDataSourceId[context.dataSource.Id]?.queryKeyParts ?? defaultQueryKeyParts,
|
|
941
|
+
context,
|
|
942
|
+
),
|
|
943
|
+
resolveLocalValue: (context) =>
|
|
944
|
+
byDataSourceId[context.dataSource.Id]?.localValue?.(context),
|
|
945
|
+
resolveTransforms: (context) =>
|
|
946
|
+
resolveDataSourceQueryInterpretationTransforms(
|
|
947
|
+
byDataSourceId[context.dataSource.Id],
|
|
948
|
+
transforms,
|
|
949
|
+
context,
|
|
950
|
+
),
|
|
951
|
+
resolveValue: (context) =>
|
|
952
|
+
resolveDataSourceQueryInterpretationValue(
|
|
953
|
+
byDataSourceId[context.dataSource.Id],
|
|
954
|
+
context,
|
|
955
|
+
),
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
/** Creates endpoint-fetch binding input from an API endpoint data source. */
|
|
960
|
+
export function createDataSourceEndpointFetchBindingInput<TResult = unknown>({
|
|
961
|
+
context,
|
|
962
|
+
emptyMessage,
|
|
963
|
+
enabled,
|
|
964
|
+
endpointId,
|
|
965
|
+
fallbackData,
|
|
966
|
+
pendingLabel,
|
|
967
|
+
queryKeyParts = [],
|
|
968
|
+
refetchInterval,
|
|
969
|
+
retry,
|
|
970
|
+
routeParameters,
|
|
971
|
+
staleTime,
|
|
972
|
+
targetInterpretation,
|
|
973
|
+
}: CreateDataSourceEndpointFetchBindingInputOptions): PresentationTargetInterpretedTanStackQueryDataSourceBindingInput {
|
|
974
|
+
const runtimeOptions = readDataSourceBindingRuntimeOptions(context.dataSource)
|
|
975
|
+
const resolvedEndpointId = endpointId ?? readPresentationDataSourceEndpointId(context.binding)
|
|
976
|
+
const resolvedRouteParameters =
|
|
977
|
+
routeParameters ??
|
|
978
|
+
projectDataSourceRouteParameters(
|
|
979
|
+
context.dataSource.Parameters,
|
|
980
|
+
context.context.routeParameters,
|
|
981
|
+
)
|
|
982
|
+
const hasRequiredRouteParameters = hasRequiredDataSourceRouteParameters(
|
|
983
|
+
context.dataSource.Parameters,
|
|
984
|
+
resolvedRouteParameters,
|
|
985
|
+
)
|
|
986
|
+
|
|
987
|
+
return {
|
|
988
|
+
dataSourceId: context.dataSource.Id,
|
|
989
|
+
emptyMessage: emptyMessage ?? runtimeOptions.emptyMessage,
|
|
990
|
+
enabled: Boolean(resolvedEndpointId) && (enabled ?? true) && hasRequiredRouteParameters,
|
|
991
|
+
fallbackData: fallbackData === undefined ? runtimeOptions.fallbackData : fallbackData,
|
|
992
|
+
pendingLabel: pendingLabel ?? runtimeOptions.pendingLabel,
|
|
993
|
+
queryFn: () =>
|
|
994
|
+
resolvedEndpointId
|
|
995
|
+
? executePresentationDataSourceTargetEndpoint<TResult>(
|
|
996
|
+
targetInterpretation,
|
|
997
|
+
resolvedEndpointId,
|
|
998
|
+
{ routeParameters: resolvedRouteParameters },
|
|
999
|
+
{ binding: context.binding },
|
|
1000
|
+
)
|
|
1001
|
+
: Promise.reject(
|
|
1002
|
+
new Error(`Data source '${context.dataSource.Id}' is not bound to an API endpoint.`),
|
|
1003
|
+
),
|
|
1004
|
+
queryKey: [
|
|
1005
|
+
'presentation-data-source-endpoint-fetch',
|
|
1006
|
+
context.dataSource.Id,
|
|
1007
|
+
resolvedEndpointId,
|
|
1008
|
+
resolvedRouteParameters,
|
|
1009
|
+
...queryKeyParts,
|
|
1010
|
+
],
|
|
1011
|
+
refetchInterval: refetchInterval ?? runtimeOptions.refetchInterval,
|
|
1012
|
+
retry: retry ?? runtimeOptions.retry,
|
|
1013
|
+
staleTime: staleTime ?? runtimeOptions.staleTime,
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
/** Creates a fully wrapped endpoint-fetch binding from an API endpoint data source. */
|
|
1018
|
+
export function createDataSourceEndpointFetchBinding<TResult = unknown>(
|
|
1019
|
+
options: CreateDataSourceEndpointFetchBindingInputOptions,
|
|
1020
|
+
): PresentationTanStackQueryDataSourceBinding {
|
|
1021
|
+
return createTargetInterpretedTanStackQueryDataSourceBinding(
|
|
1022
|
+
options.context,
|
|
1023
|
+
options.targetInterpretation,
|
|
1024
|
+
createDataSourceEndpointFetchBindingInput<TResult>(options),
|
|
1025
|
+
)
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
/** Creates a binding that materializes a source data source and evaluates aggregate measures. */
|
|
1029
|
+
export function createDataSourceAggregateQueryBinding({
|
|
1030
|
+
context,
|
|
1031
|
+
queryKeyParts = [],
|
|
1032
|
+
targetInterpretation,
|
|
1033
|
+
transforms,
|
|
1034
|
+
value,
|
|
1035
|
+
}: CreateDataSourceAggregateQueryBindingOptions): PresentationTanStackQueryDataSourceBinding | null {
|
|
1036
|
+
const aggregation = context.dataSource.Aggregation
|
|
1037
|
+
if (!aggregation) {
|
|
1038
|
+
return null
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
const sourceDataSource = findPresentationDataSource(
|
|
1042
|
+
context.module,
|
|
1043
|
+
aggregation.SourceDataSourceId,
|
|
1044
|
+
)
|
|
1045
|
+
const sourceEndpointId = readPresentationDataSourceEndpointId(sourceDataSource?.Binding)
|
|
1046
|
+
if (!sourceDataSource || !sourceEndpointId) {
|
|
1047
|
+
return createTargetInterpretedTanStackQueryDataSourceBinding(
|
|
1048
|
+
context,
|
|
1049
|
+
targetInterpretation,
|
|
1050
|
+
{
|
|
1051
|
+
authorization: presentationDataSourceAuthorization.required({
|
|
1052
|
+
blockedLabel: `Aggregate data source '${context.dataSource.Id}' cannot resolve source '${aggregation.SourceDataSourceId}'.`,
|
|
1053
|
+
isAuthorized: false,
|
|
1054
|
+
}),
|
|
1055
|
+
dataSourceId: context.dataSource.Id,
|
|
1056
|
+
queryFn: () => Promise.resolve(evaluateDataSourceAggregateQuery(aggregation, [])),
|
|
1057
|
+
queryKey: [
|
|
1058
|
+
'presentation-data-source-aggregate-query',
|
|
1059
|
+
context.dataSource.Id,
|
|
1060
|
+
aggregation.SourceDataSourceId,
|
|
1061
|
+
'missing-source',
|
|
1062
|
+
...queryKeyParts,
|
|
1063
|
+
],
|
|
1064
|
+
},
|
|
1065
|
+
)
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
const appliedValue =
|
|
1069
|
+
value ?? readPresentationQueryFormAppliedValue(context.context, context.dataSource.Id)
|
|
1070
|
+
const runtimeOptions = readDataSourceBindingRuntimeOptions(context.dataSource)
|
|
1071
|
+
const fallbackData =
|
|
1072
|
+
runtimeOptions.fallbackData === undefined
|
|
1073
|
+
? evaluateDataSourceAggregateQuery(aggregation, [])
|
|
1074
|
+
: runtimeOptions.fallbackData
|
|
1075
|
+
const sourceAuthorization = resolvePresentationDataSourceTargetAuthorization(
|
|
1076
|
+
targetInterpretation,
|
|
1077
|
+
{
|
|
1078
|
+
...context,
|
|
1079
|
+
binding: sourceDataSource.Binding ?? null,
|
|
1080
|
+
dataSource: sourceDataSource,
|
|
1081
|
+
},
|
|
1082
|
+
)
|
|
1083
|
+
const loweredTransforms = mergeDataSourceQueryLoweringTransforms(
|
|
1084
|
+
targetInterpretation.queryLowering?.transformsById,
|
|
1085
|
+
transforms,
|
|
1086
|
+
)
|
|
1087
|
+
|
|
1088
|
+
return createTargetInterpretedTanStackQueryDataSourceBinding(
|
|
1089
|
+
context,
|
|
1090
|
+
targetInterpretation,
|
|
1091
|
+
{
|
|
1092
|
+
authorization: sourceAuthorization,
|
|
1093
|
+
dataSourceId: context.dataSource.Id,
|
|
1094
|
+
fallbackData,
|
|
1095
|
+
pendingLabel: runtimeOptions.pendingLabel,
|
|
1096
|
+
queryFn: async () => {
|
|
1097
|
+
const items = await materializeDataSourceAggregateItems({
|
|
1098
|
+
aggregation,
|
|
1099
|
+
sourceDataSource,
|
|
1100
|
+
sourceEndpointId,
|
|
1101
|
+
targetInterpretation,
|
|
1102
|
+
transforms: loweredTransforms,
|
|
1103
|
+
value: appliedValue,
|
|
1104
|
+
})
|
|
1105
|
+
return evaluateDataSourceAggregateQuery(aggregation, items)
|
|
1106
|
+
},
|
|
1107
|
+
queryKey: [
|
|
1108
|
+
'presentation-data-source-aggregate-query',
|
|
1109
|
+
context.dataSource.Id,
|
|
1110
|
+
sourceDataSource.Id,
|
|
1111
|
+
appliedValue ?? {},
|
|
1112
|
+
aggregation,
|
|
1113
|
+
...queryKeyParts,
|
|
1114
|
+
],
|
|
1115
|
+
refetchInterval: runtimeOptions.refetchInterval,
|
|
1116
|
+
retry: runtimeOptions.retry,
|
|
1117
|
+
staleTime: runtimeOptions.staleTime,
|
|
1118
|
+
},
|
|
1119
|
+
)
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
/** Executes an API endpoint through the active target interpretation. */
|
|
1123
|
+
export function executePresentationDataSourceTargetEndpoint<TResult = unknown>(
|
|
1124
|
+
targetInterpretation: PresentationDataSourceTargetInterpretation,
|
|
1125
|
+
endpointId: string,
|
|
1126
|
+
request: PresentationDataSourceEndpointExecutionRequest = {},
|
|
1127
|
+
options: ExecutePresentationDataSourceTargetEndpointOptions = {},
|
|
1128
|
+
): Promise<TResult> {
|
|
1129
|
+
const executeEndpoint = resolvePresentationDataSourceTargetEndpointExecutor(
|
|
1130
|
+
targetInterpretation,
|
|
1131
|
+
options.binding,
|
|
1132
|
+
)
|
|
1133
|
+
if (!executeEndpoint) {
|
|
1134
|
+
const executionTargetId = readPresentationDataSourceTargetBindingOptions(
|
|
1135
|
+
options.binding,
|
|
1136
|
+
).executionTargetId
|
|
1137
|
+
return Promise.reject(
|
|
1138
|
+
new Error(
|
|
1139
|
+
executionTargetId
|
|
1140
|
+
? `No API endpoint executor is registered for presentation data-source execution target '${executionTargetId}'.`
|
|
1141
|
+
: `No API endpoint executor is registered for presentation data-source endpoint '${endpointId}'.`,
|
|
1142
|
+
),
|
|
1143
|
+
)
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
return executeEndpoint<TResult>(endpointId, request)
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
/**
|
|
1150
|
+
* Composes independently owned data-source binding registries into one
|
|
1151
|
+
* projection registry. Later registries override earlier factories for the same
|
|
1152
|
+
* data-source or endpoint id so app-level composition can replace defaults at
|
|
1153
|
+
* narrower ownership boundaries.
|
|
1154
|
+
*/
|
|
1155
|
+
export function mergePresentationDataSourceBindingProjectionRegistries(
|
|
1156
|
+
...registries: readonly PresentationDataSourceBindingProjectionRegistry[]
|
|
1157
|
+
): PresentationDataSourceBindingProjectionRegistry {
|
|
1158
|
+
let defaultAuthorization: PresentationDataSourceBindingProjectionRegistry['defaultAuthorization']
|
|
1159
|
+
for (const registry of registries) {
|
|
1160
|
+
defaultAuthorization = registry.defaultAuthorization ?? defaultAuthorization
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
return {
|
|
1164
|
+
apiEndpoint: resolveApiEndpointFactory(registries),
|
|
1165
|
+
byDataSourceId: Object.assign(
|
|
1166
|
+
{},
|
|
1167
|
+
...registries.map((registry) => registry.byDataSourceId ?? {}),
|
|
1168
|
+
),
|
|
1169
|
+
byEndpointId: Object.assign(
|
|
1170
|
+
{},
|
|
1171
|
+
...registries.map((registry) => registry.byEndpointId ?? {}),
|
|
1172
|
+
),
|
|
1173
|
+
defaultAuthorization,
|
|
1174
|
+
fallback: resolveFallbackFactory(registries),
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
/**
|
|
1179
|
+
* Projects semantic data-source definitions onto concrete frontend binding
|
|
1180
|
+
* plans. React hooks are deliberately not used here; hook-backed realization is
|
|
1181
|
+
* handled later by PresentationDataSourceBinder.
|
|
1182
|
+
*/
|
|
1183
|
+
export function projectPresentationDataSourceBindings({
|
|
1184
|
+
context = {},
|
|
1185
|
+
dataSourceDefinitions = [],
|
|
1186
|
+
dataSourceIds,
|
|
1187
|
+
module,
|
|
1188
|
+
registry,
|
|
1189
|
+
}: ProjectPresentationDataSourceBindingsOptions): readonly PresentationDataSourceBinding[] {
|
|
1190
|
+
const uniqueDataSourceIds = Array.from(new Set(dataSourceIds))
|
|
1191
|
+
const fallbackDataSourcesById = new Map(
|
|
1192
|
+
dataSourceDefinitions.map((dataSource) => [dataSource.Id, dataSource] as const),
|
|
1193
|
+
)
|
|
1194
|
+
|
|
1195
|
+
return uniqueDataSourceIds.flatMap((dataSourceId) => {
|
|
1196
|
+
const dataSource =
|
|
1197
|
+
findPresentationDataSource(module, dataSourceId) ??
|
|
1198
|
+
fallbackDataSourcesById.get(dataSourceId) ??
|
|
1199
|
+
null
|
|
1200
|
+
if (!dataSource) {
|
|
1201
|
+
return []
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
const binding = dataSource.Binding ?? null
|
|
1205
|
+
const factoryContext = {
|
|
1206
|
+
binding,
|
|
1207
|
+
context,
|
|
1208
|
+
dataSource,
|
|
1209
|
+
module,
|
|
1210
|
+
} satisfies PresentationDataSourceBindingFactoryContext
|
|
1211
|
+
const factory = resolveDataSourceBindingFactory(registry, dataSource)
|
|
1212
|
+
const projectedBinding =
|
|
1213
|
+
factory?.(factoryContext) ??
|
|
1214
|
+
createUnboundDataSourceBinding(dataSource, registry.defaultAuthorization?.(factoryContext))
|
|
1215
|
+
|
|
1216
|
+
return [applyDataSourceDefaults(projectedBinding, dataSource)]
|
|
1217
|
+
})
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
/**
|
|
1221
|
+
* Adapts TanStack Query binding-input factories into a full projection
|
|
1222
|
+
* registry by applying target-level authorization to every produced binding.
|
|
1223
|
+
*/
|
|
1224
|
+
export function createTanStackQueryDataSourceBindingProjectionRegistry({
|
|
1225
|
+
apiEndpoint,
|
|
1226
|
+
byDataSourceId,
|
|
1227
|
+
byEndpointId,
|
|
1228
|
+
defaultAuthorization,
|
|
1229
|
+
targetInterpretation,
|
|
1230
|
+
}: TanStackQueryDataSourceBindingProjectionRegistryOptions): PresentationDataSourceBindingProjectionRegistry {
|
|
1231
|
+
return {
|
|
1232
|
+
apiEndpoint: apiEndpoint
|
|
1233
|
+
? (context) => {
|
|
1234
|
+
const binding = apiEndpoint(context)
|
|
1235
|
+
return binding
|
|
1236
|
+
? createTargetInterpretedTanStackQueryDataSourceBinding(
|
|
1237
|
+
context,
|
|
1238
|
+
targetInterpretation,
|
|
1239
|
+
binding,
|
|
1240
|
+
defaultAuthorization,
|
|
1241
|
+
)
|
|
1242
|
+
: binding
|
|
1243
|
+
}
|
|
1244
|
+
: undefined,
|
|
1245
|
+
byDataSourceId,
|
|
1246
|
+
byEndpointId: mapFactories(byEndpointId, (factory) => (context) => {
|
|
1247
|
+
const binding = factory(context)
|
|
1248
|
+
return binding
|
|
1249
|
+
? createTargetInterpretedTanStackQueryDataSourceBinding(
|
|
1250
|
+
context,
|
|
1251
|
+
targetInterpretation,
|
|
1252
|
+
binding,
|
|
1253
|
+
defaultAuthorization,
|
|
1254
|
+
)
|
|
1255
|
+
: binding
|
|
1256
|
+
}),
|
|
1257
|
+
defaultAuthorization,
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
/**
|
|
1262
|
+
* Creates a generic TanStack Query projection registry for API endpoint data
|
|
1263
|
+
* sources. The registry resolves endpoint ids from backend bindings, projects
|
|
1264
|
+
* route parameters, applies runtime annotations, and executes through the
|
|
1265
|
+
* active target interpretation.
|
|
1266
|
+
*/
|
|
1267
|
+
export function createApiEndpointTanStackQueryDataSourceBindingProjectionRegistry({
|
|
1268
|
+
createQueryKey,
|
|
1269
|
+
defaultAuthorization,
|
|
1270
|
+
executeEndpoint,
|
|
1271
|
+
isEnabled,
|
|
1272
|
+
pendingLabel,
|
|
1273
|
+
retry,
|
|
1274
|
+
targetInterpretation,
|
|
1275
|
+
}: ApiEndpointTanStackQueryDataSourceBindingProjectionRegistryOptions): PresentationDataSourceBindingProjectionRegistry {
|
|
1276
|
+
return createTanStackQueryDataSourceBindingProjectionRegistry({
|
|
1277
|
+
apiEndpoint: (context) => {
|
|
1278
|
+
const endpointId = readPresentationDataSourceEndpointId(context.binding)
|
|
1279
|
+
if (!endpointId) {
|
|
1280
|
+
return null
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
const endpointExecutor =
|
|
1284
|
+
executeEndpoint ??
|
|
1285
|
+
resolvePresentationDataSourceTargetEndpointExecutor(
|
|
1286
|
+
targetInterpretation,
|
|
1287
|
+
context.binding,
|
|
1288
|
+
)
|
|
1289
|
+
if (!endpointExecutor) {
|
|
1290
|
+
return null
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
const routeParameters = projectDataSourceRouteParameters(
|
|
1294
|
+
context.dataSource.Parameters,
|
|
1295
|
+
context.context.routeParameters,
|
|
1296
|
+
)
|
|
1297
|
+
const apiContext = {
|
|
1298
|
+
...context,
|
|
1299
|
+
endpointId,
|
|
1300
|
+
routeParameters,
|
|
1301
|
+
} satisfies PresentationDataSourceApiEndpointFactoryContext
|
|
1302
|
+
const runtimeOptions = readDataSourceBindingRuntimeOptions(context.dataSource)
|
|
1303
|
+
const targetIsEnabled = targetInterpretation?.apiEndpoint?.isEnabled?.(apiContext)
|
|
1304
|
+
const projectedIsEnabled = isEnabled?.(apiContext)
|
|
1305
|
+
return {
|
|
1306
|
+
dataSourceId: context.dataSource.Id,
|
|
1307
|
+
enabled:
|
|
1308
|
+
(targetIsEnabled ?? true) &&
|
|
1309
|
+
(projectedIsEnabled ?? true) &&
|
|
1310
|
+
hasRequiredDataSourceRouteParameters(context.dataSource.Parameters, routeParameters),
|
|
1311
|
+
emptyMessage: runtimeOptions.emptyMessage,
|
|
1312
|
+
fallbackData: runtimeOptions.fallbackData,
|
|
1313
|
+
pendingLabel: resolveApiEndpointDataSourcePendingLabel(
|
|
1314
|
+
pendingLabel ??
|
|
1315
|
+
runtimeOptions.pendingLabel ??
|
|
1316
|
+
targetInterpretation?.apiEndpoint?.pendingLabel,
|
|
1317
|
+
apiContext,
|
|
1318
|
+
),
|
|
1319
|
+
queryFn: () => endpointExecutor(endpointId, { routeParameters }),
|
|
1320
|
+
queryKey:
|
|
1321
|
+
createQueryKey?.(apiContext) ??
|
|
1322
|
+
targetInterpretation?.apiEndpoint?.createQueryKey?.(apiContext) ??
|
|
1323
|
+
createDefaultApiEndpointDataSourceQueryKey(apiContext),
|
|
1324
|
+
refetchInterval: runtimeOptions.refetchInterval,
|
|
1325
|
+
retry: retry ?? runtimeOptions.retry ?? targetInterpretation?.apiEndpoint?.retry ?? false,
|
|
1326
|
+
staleTime: runtimeOptions.staleTime,
|
|
1327
|
+
}
|
|
1328
|
+
},
|
|
1329
|
+
defaultAuthorization,
|
|
1330
|
+
targetInterpretation,
|
|
1331
|
+
})
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
function resolveApiEndpointFactory(
|
|
1335
|
+
registries: readonly PresentationDataSourceBindingProjectionRegistry[],
|
|
1336
|
+
): PresentationDataSourceBindingFactory | undefined {
|
|
1337
|
+
const factories = registries.flatMap((registry) =>
|
|
1338
|
+
registry.apiEndpoint ? [registry.apiEndpoint] : [],
|
|
1339
|
+
)
|
|
1340
|
+
if (factories.length === 0) {
|
|
1341
|
+
return undefined
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
return (context) => {
|
|
1345
|
+
for (let i = factories.length - 1; i >= 0; i -= 1) {
|
|
1346
|
+
const binding = factories[i]?.(context)
|
|
1347
|
+
if (binding) {
|
|
1348
|
+
return binding
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
return null
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
function resolveFallbackFactory(
|
|
1357
|
+
registries: readonly PresentationDataSourceBindingProjectionRegistry[],
|
|
1358
|
+
): PresentationDataSourceBindingFactory | undefined {
|
|
1359
|
+
const factories = registries.flatMap((registry) =>
|
|
1360
|
+
registry.fallback ? [registry.fallback] : [],
|
|
1361
|
+
)
|
|
1362
|
+
if (factories.length === 0) {
|
|
1363
|
+
return undefined
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
return (context) => {
|
|
1367
|
+
for (let i = factories.length - 1; i >= 0; i -= 1) {
|
|
1368
|
+
const binding = factories[i]?.(context)
|
|
1369
|
+
if (binding) {
|
|
1370
|
+
return binding
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
return null
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
function resolveDataSourceBindingFactory(
|
|
1379
|
+
registry: PresentationDataSourceBindingProjectionRegistry,
|
|
1380
|
+
dataSource: DataSourceDefinition,
|
|
1381
|
+
): PresentationDataSourceBindingFactory | undefined {
|
|
1382
|
+
const endpointId = isApiEndpointBinding(dataSource.Binding)
|
|
1383
|
+
? dataSource.Binding?.EndpointId
|
|
1384
|
+
: null
|
|
1385
|
+
const exactFactory =
|
|
1386
|
+
registry.byDataSourceId?.[dataSource.Id] ??
|
|
1387
|
+
(endpointId ? registry.byEndpointId?.[endpointId] : undefined)
|
|
1388
|
+
if (exactFactory) {
|
|
1389
|
+
return exactFactory
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
const genericFactories = [
|
|
1393
|
+
endpointId ? registry.apiEndpoint : undefined,
|
|
1394
|
+
registry.fallback,
|
|
1395
|
+
].filter((factory): factory is PresentationDataSourceBindingFactory => Boolean(factory))
|
|
1396
|
+
if (genericFactories.length === 0) {
|
|
1397
|
+
return undefined
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
return (context) => {
|
|
1401
|
+
for (const factory of genericFactories) {
|
|
1402
|
+
const binding = factory(context)
|
|
1403
|
+
if (binding) {
|
|
1404
|
+
return binding
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
return null
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
function isAggregateQueryDataSource(
|
|
1413
|
+
dataSource: Pick<DataSourceDefinition, 'Kind'>,
|
|
1414
|
+
) {
|
|
1415
|
+
return matchesDataSourceKind(
|
|
1416
|
+
dataSource.Kind,
|
|
1417
|
+
dataSourceKinds.aggregateQuery,
|
|
1418
|
+
'aggregateQuery',
|
|
1419
|
+
)
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
function isCollectionQueryDataSource(
|
|
1423
|
+
dataSource: Pick<DataSourceDefinition, 'Kind'>,
|
|
1424
|
+
) {
|
|
1425
|
+
return matchesDataSourceKind(
|
|
1426
|
+
dataSource.Kind,
|
|
1427
|
+
dataSourceKinds.collectionQuery,
|
|
1428
|
+
'collectionQuery',
|
|
1429
|
+
)
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
function isLocalStateDataSource(
|
|
1433
|
+
dataSource: Pick<DataSourceDefinition, 'Kind'>,
|
|
1434
|
+
) {
|
|
1435
|
+
return matchesDataSourceKind(
|
|
1436
|
+
dataSource.Kind,
|
|
1437
|
+
dataSourceKinds.localState,
|
|
1438
|
+
'localState',
|
|
1439
|
+
)
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
function isPromptPreviewDataSource(
|
|
1443
|
+
dataSource: Pick<DataSourceDefinition, 'Kind'>,
|
|
1444
|
+
) {
|
|
1445
|
+
return matchesDataSourceKind(
|
|
1446
|
+
dataSource.Kind,
|
|
1447
|
+
dataSourceKinds.promptPreview,
|
|
1448
|
+
'promptPreview',
|
|
1449
|
+
)
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
function matchesDataSourceKind(
|
|
1453
|
+
value: unknown,
|
|
1454
|
+
numericValue: DataSourceKind,
|
|
1455
|
+
camelLabel: string,
|
|
1456
|
+
) {
|
|
1457
|
+
const pascalLabel = dataSourceKindLabels[numericValue]
|
|
1458
|
+
return (
|
|
1459
|
+
value === numericValue ||
|
|
1460
|
+
String(value) === String(numericValue) ||
|
|
1461
|
+
String(value) === pascalLabel ||
|
|
1462
|
+
String(value).toLocaleLowerCase() === camelLabel.toLocaleLowerCase()
|
|
1463
|
+
)
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
function resolveQueryKeyParts(
|
|
1467
|
+
queryKeyParts:
|
|
1468
|
+
| readonly unknown[]
|
|
1469
|
+
| ((context: PresentationDataSourceBindingFactoryContext) => readonly unknown[]),
|
|
1470
|
+
context: PresentationDataSourceBindingFactoryContext,
|
|
1471
|
+
) {
|
|
1472
|
+
return typeof queryKeyParts === 'function'
|
|
1473
|
+
? queryKeyParts(context)
|
|
1474
|
+
: queryKeyParts
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
function resolveDataSourceQueryInterpretationTransforms(
|
|
1478
|
+
interpretation: DataSourceQueryInterpretation | undefined,
|
|
1479
|
+
registryTransforms: DataSourceQueryInterpretationRegistry['transforms'],
|
|
1480
|
+
context: PresentationDataSourceBindingFactoryContext,
|
|
1481
|
+
) {
|
|
1482
|
+
const resolvedRegistryTransforms = resolveDataSourceQueryTransforms(
|
|
1483
|
+
registryTransforms,
|
|
1484
|
+
context,
|
|
1485
|
+
)
|
|
1486
|
+
const resolvedInterpretationTransforms = resolveDataSourceQueryTransforms(
|
|
1487
|
+
interpretation?.transforms,
|
|
1488
|
+
context,
|
|
1489
|
+
)
|
|
1490
|
+
|
|
1491
|
+
if (!resolvedRegistryTransforms) {
|
|
1492
|
+
return resolvedInterpretationTransforms
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
if (!resolvedInterpretationTransforms) {
|
|
1496
|
+
return resolvedRegistryTransforms
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
return {
|
|
1500
|
+
...resolvedRegistryTransforms,
|
|
1501
|
+
...resolvedInterpretationTransforms,
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
function resolveDataSourceQueryTransforms(
|
|
1506
|
+
transforms: DataSourceQueryInterpretationRegistry['transforms'],
|
|
1507
|
+
context: PresentationDataSourceBindingFactoryContext,
|
|
1508
|
+
) {
|
|
1509
|
+
return typeof transforms === 'function'
|
|
1510
|
+
? transforms(context)
|
|
1511
|
+
: transforms
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
function mergeDataSourceQueryLoweringTransforms(
|
|
1515
|
+
targetTransforms:
|
|
1516
|
+
| Readonly<Record<string, DataSourceQueryLoweringTransform>>
|
|
1517
|
+
| undefined,
|
|
1518
|
+
localTransforms:
|
|
1519
|
+
| Readonly<Record<string, DataSourceQueryLoweringTransform>>
|
|
1520
|
+
| undefined,
|
|
1521
|
+
) {
|
|
1522
|
+
if (!targetTransforms) {
|
|
1523
|
+
return localTransforms
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
if (!localTransforms) {
|
|
1527
|
+
return targetTransforms
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
return {
|
|
1531
|
+
...targetTransforms,
|
|
1532
|
+
...localTransforms,
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
function resolveDataSourceQueryInterpretationValue(
|
|
1537
|
+
interpretation: DataSourceQueryInterpretation | undefined,
|
|
1538
|
+
context: PresentationDataSourceBindingFactoryContext,
|
|
1539
|
+
) {
|
|
1540
|
+
if (!interpretation?.normalizeValue && !interpretation?.readValue) {
|
|
1541
|
+
return undefined
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
const value = interpretation.readValue
|
|
1545
|
+
? interpretation.readValue(context)
|
|
1546
|
+
: readPresentationQueryFormAppliedValue(context.context, context.dataSource.Id)
|
|
1547
|
+
return interpretation.normalizeValue
|
|
1548
|
+
? interpretation.normalizeValue(value, context)
|
|
1549
|
+
: value
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
/**
|
|
1553
|
+
* Reads target binding options from a backend presentation binding.
|
|
1554
|
+
*
|
|
1555
|
+
* Option names are matched case-insensitively and may use either camelCase or
|
|
1556
|
+
* PascalCase.
|
|
1557
|
+
*/
|
|
1558
|
+
export function readPresentationDataSourceTargetBindingOptions(
|
|
1559
|
+
binding: PresentationBindingDefinition | null | undefined,
|
|
1560
|
+
): PresentationDataSourceTargetBindingOptions {
|
|
1561
|
+
return {
|
|
1562
|
+
authorizationPolicyId: readPresentationBindingStringOption(
|
|
1563
|
+
binding?.Options,
|
|
1564
|
+
'authorizationPolicyId',
|
|
1565
|
+
),
|
|
1566
|
+
executionTargetId: readPresentationBindingStringOption(
|
|
1567
|
+
binding?.Options,
|
|
1568
|
+
'executionTargetId',
|
|
1569
|
+
),
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
/**
|
|
1574
|
+
* Reads runtime query defaults from the standard
|
|
1575
|
+
* `cohesive.presentation.data-source.runtime` data-source annotation.
|
|
1576
|
+
*/
|
|
1577
|
+
export function readDataSourceBindingRuntimeOptions(
|
|
1578
|
+
dataSource: Pick<DataSourceDefinition, 'Annotations'> | null | undefined,
|
|
1579
|
+
): PresentationDataSourceBindingRuntimeOptions {
|
|
1580
|
+
const annotation = dataSource?.Annotations.find(
|
|
1581
|
+
(candidate) =>
|
|
1582
|
+
candidate.Name === 'cohesive.presentation.data-source.runtime' ||
|
|
1583
|
+
candidate.Name.toLocaleLowerCase() === 'cohesive.presentation.data-source.runtime',
|
|
1584
|
+
)
|
|
1585
|
+
if (!annotation || !annotation.Value || typeof annotation.Value !== 'object') {
|
|
1586
|
+
return {}
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
const options = annotation.Value as Readonly<Record<string, unknown>>
|
|
1590
|
+
const refetchInterval =
|
|
1591
|
+
readNumberOption(options, 'refetchIntervalMs') ??
|
|
1592
|
+
readSecondsOptionAsMilliseconds(options, 'refetchIntervalSeconds')
|
|
1593
|
+
const staleTime =
|
|
1594
|
+
readNumberOption(options, 'staleTimeMs') ??
|
|
1595
|
+
readSecondsOptionAsMilliseconds(options, 'staleTimeSeconds')
|
|
1596
|
+
|
|
1597
|
+
return {
|
|
1598
|
+
emptyMessage: readStringOption(options, 'emptyMessage'),
|
|
1599
|
+
fallbackData: readObjectOption(options, 'fallbackData'),
|
|
1600
|
+
pendingLabel: readStringOption(options, 'pendingLabel'),
|
|
1601
|
+
refetchInterval,
|
|
1602
|
+
retry: readRetryOption(options, 'retry'),
|
|
1603
|
+
staleTime,
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
/**
|
|
1608
|
+
* Resolves the endpoint executor selected by a binding's `executionTargetId`,
|
|
1609
|
+
* falling back to the default API endpoint executor on the target
|
|
1610
|
+
* interpretation.
|
|
1611
|
+
*/
|
|
1612
|
+
export function resolvePresentationDataSourceTargetEndpointExecutor(
|
|
1613
|
+
targetInterpretation: PresentationDataSourceTargetInterpretation | undefined,
|
|
1614
|
+
binding: PresentationBindingDefinition | null | undefined,
|
|
1615
|
+
): PresentationDataSourceEndpointExecutor | undefined {
|
|
1616
|
+
const executionTargetId = readPresentationDataSourceTargetBindingOptions(
|
|
1617
|
+
binding,
|
|
1618
|
+
).executionTargetId
|
|
1619
|
+
if (executionTargetId) {
|
|
1620
|
+
return targetInterpretation?.apiEndpoint?.executeEndpointByTargetId?.[executionTargetId]
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
return targetInterpretation?.apiEndpoint?.executeEndpoint
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1626
|
+
async function materializeDataSourceAggregateItems({
|
|
1627
|
+
aggregation,
|
|
1628
|
+
sourceDataSource,
|
|
1629
|
+
sourceEndpointId,
|
|
1630
|
+
targetInterpretation,
|
|
1631
|
+
transforms,
|
|
1632
|
+
value,
|
|
1633
|
+
}: {
|
|
1634
|
+
readonly aggregation: DataSourceAggregateQuery
|
|
1635
|
+
readonly sourceDataSource: DataSourceDefinition
|
|
1636
|
+
readonly sourceEndpointId: string
|
|
1637
|
+
readonly targetInterpretation: PresentationDataSourceTargetInterpretation
|
|
1638
|
+
readonly transforms?: Readonly<Record<string, DataSourceQueryLoweringTransform>>
|
|
1639
|
+
readonly value: unknown
|
|
1640
|
+
}): Promise<readonly unknown[]> {
|
|
1641
|
+
const materializeAllPages = matchesDataSourceAggregateMaterializationKind(
|
|
1642
|
+
aggregation.Materialization.Kind,
|
|
1643
|
+
dataSourceAggregateMaterializationKinds.allPages,
|
|
1644
|
+
'allPages',
|
|
1645
|
+
)
|
|
1646
|
+
const pageSize =
|
|
1647
|
+
aggregation.Materialization.PageSize ??
|
|
1648
|
+
sourceDataSource.Query?.Pagination?.DefaultPageSize ??
|
|
1649
|
+
100
|
|
1650
|
+
const endpointBinding = findDataSourceQueryEndpointBinding(
|
|
1651
|
+
sourceDataSource,
|
|
1652
|
+
sourceEndpointId,
|
|
1653
|
+
)
|
|
1654
|
+
const items: unknown[] = []
|
|
1655
|
+
const seenCursors = new Set<string>()
|
|
1656
|
+
let cursor: string | null | undefined = null
|
|
1657
|
+
|
|
1658
|
+
do {
|
|
1659
|
+
const paginationRequest = materializeAllPages
|
|
1660
|
+
? createDataSourcePaginationRequest(sourceDataSource, {
|
|
1661
|
+
cursor,
|
|
1662
|
+
limit: pageSize,
|
|
1663
|
+
})
|
|
1664
|
+
: null
|
|
1665
|
+
const query = createDataSourceEndpointQueryRequest<Record<string, unknown>>({
|
|
1666
|
+
dataSource: sourceDataSource,
|
|
1667
|
+
endpointId: sourceEndpointId,
|
|
1668
|
+
paginationRequest,
|
|
1669
|
+
transforms,
|
|
1670
|
+
value,
|
|
1671
|
+
})
|
|
1672
|
+
const response = await executePresentationDataSourceTargetEndpoint(
|
|
1673
|
+
targetInterpretation,
|
|
1674
|
+
sourceEndpointId,
|
|
1675
|
+
{ query },
|
|
1676
|
+
{ binding: sourceDataSource.Binding ?? null },
|
|
1677
|
+
)
|
|
1678
|
+
const pageItems = readAggregateResponseItems(response, endpointBinding?.ItemsPath)
|
|
1679
|
+
items.push(...pageItems)
|
|
1680
|
+
|
|
1681
|
+
const nextCursor = readStringObjectPath(
|
|
1682
|
+
response,
|
|
1683
|
+
sourceDataSource.Query?.Pagination?.Response.CursorField,
|
|
1684
|
+
)
|
|
1685
|
+
cursor = materializeAllPages && nextCursor && !seenCursors.has(nextCursor)
|
|
1686
|
+
? nextCursor
|
|
1687
|
+
: null
|
|
1688
|
+
if (cursor) {
|
|
1689
|
+
seenCursors.add(cursor)
|
|
1690
|
+
}
|
|
1691
|
+
} while (cursor)
|
|
1692
|
+
|
|
1693
|
+
return items
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
function evaluateDataSourceAggregateQuery(
|
|
1697
|
+
aggregation: DataSourceAggregateQuery,
|
|
1698
|
+
items: readonly unknown[],
|
|
1699
|
+
) {
|
|
1700
|
+
const result: Record<string, unknown> = {}
|
|
1701
|
+
for (const measure of aggregation.Measures) {
|
|
1702
|
+
const predicate = measure.Predicate
|
|
1703
|
+
const matchingItems = predicate
|
|
1704
|
+
? items.filter((item) => evaluateDataSourceAggregatePredicate(predicate, item))
|
|
1705
|
+
: items
|
|
1706
|
+
writeObjectPath(
|
|
1707
|
+
result,
|
|
1708
|
+
measure.TargetPath,
|
|
1709
|
+
evaluateDataSourceAggregateMeasure(measure.Operator, measure.SourceField, matchingItems),
|
|
1710
|
+
)
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
return result
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
function evaluateDataSourceAggregateMeasure(
|
|
1717
|
+
operator: AggregateOperator,
|
|
1718
|
+
sourceField: DataSourceAggregateQuery['Measures'][number]['SourceField'],
|
|
1719
|
+
items: readonly unknown[],
|
|
1720
|
+
) {
|
|
1721
|
+
if (matchesAggregateOperator(operator, aggregateOperators.count, 'count')) {
|
|
1722
|
+
return items.length
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
const values: readonly unknown[] = sourceField
|
|
1726
|
+
? items.map((item) => readObjectPath(item, fieldPathToString(sourceField)))
|
|
1727
|
+
: items
|
|
1728
|
+
|
|
1729
|
+
if (matchesAggregateOperator(operator, aggregateOperators.sum, 'sum')) {
|
|
1730
|
+
return values.reduce<number>(
|
|
1731
|
+
(sum, value) => sum + (typeof value === 'number' ? value : 0),
|
|
1732
|
+
0,
|
|
1733
|
+
)
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
if (matchesAggregateOperator(operator, aggregateOperators.min, 'min')) {
|
|
1737
|
+
return values
|
|
1738
|
+
.filter((value): value is number => typeof value === 'number')
|
|
1739
|
+
.reduce<number | null>((min, value) => min === null ? value : Math.min(min, value), null)
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
if (matchesAggregateOperator(operator, aggregateOperators.max, 'max')) {
|
|
1743
|
+
return values
|
|
1744
|
+
.filter((value): value is number => typeof value === 'number')
|
|
1745
|
+
.reduce<number | null>((max, value) => max === null ? value : Math.max(max, value), null)
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
if (matchesAggregateOperator(operator, aggregateOperators.any, 'any')) {
|
|
1749
|
+
return values.some(Boolean)
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
if (matchesAggregateOperator(operator, aggregateOperators.all, 'all')) {
|
|
1753
|
+
return values.every(Boolean)
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
return null
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1759
|
+
function evaluateDataSourceAggregatePredicate(
|
|
1760
|
+
predicate: DataSourceAggregatePredicate,
|
|
1761
|
+
item: unknown,
|
|
1762
|
+
): boolean {
|
|
1763
|
+
if (
|
|
1764
|
+
matchesDataSourceAggregatePredicateKind(
|
|
1765
|
+
predicate.Kind,
|
|
1766
|
+
dataSourceAggregatePredicateKinds.and,
|
|
1767
|
+
'and',
|
|
1768
|
+
)
|
|
1769
|
+
) {
|
|
1770
|
+
return (predicate.Terms ?? []).every((term) =>
|
|
1771
|
+
evaluateDataSourceAggregatePredicate(term, item))
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
if (
|
|
1775
|
+
matchesDataSourceAggregatePredicateKind(
|
|
1776
|
+
predicate.Kind,
|
|
1777
|
+
dataSourceAggregatePredicateKinds.or,
|
|
1778
|
+
'or',
|
|
1779
|
+
)
|
|
1780
|
+
) {
|
|
1781
|
+
return (predicate.Terms ?? []).some((term) =>
|
|
1782
|
+
evaluateDataSourceAggregatePredicate(term, item))
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
if (
|
|
1786
|
+
matchesDataSourceAggregatePredicateKind(
|
|
1787
|
+
predicate.Kind,
|
|
1788
|
+
dataSourceAggregatePredicateKinds.not,
|
|
1789
|
+
'not',
|
|
1790
|
+
)
|
|
1791
|
+
) {
|
|
1792
|
+
const [term] = predicate.Terms ?? []
|
|
1793
|
+
return term ? !evaluateDataSourceAggregatePredicate(term, item) : true
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1796
|
+
const value = readObjectPath(item, fieldPathToString(predicate.Field))
|
|
1797
|
+
if (
|
|
1798
|
+
matchesDataSourceAggregatePredicateKind(
|
|
1799
|
+
predicate.Kind,
|
|
1800
|
+
dataSourceAggregatePredicateKinds.fieldEquals,
|
|
1801
|
+
'fieldEquals',
|
|
1802
|
+
)
|
|
1803
|
+
) {
|
|
1804
|
+
return String(value) === predicate.Value
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
if (
|
|
1808
|
+
matchesDataSourceAggregatePredicateKind(
|
|
1809
|
+
predicate.Kind,
|
|
1810
|
+
dataSourceAggregatePredicateKinds.fieldNotEquals,
|
|
1811
|
+
'fieldNotEquals',
|
|
1812
|
+
)
|
|
1813
|
+
) {
|
|
1814
|
+
return String(value) !== predicate.Value
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
if (
|
|
1818
|
+
matchesDataSourceAggregatePredicateKind(
|
|
1819
|
+
predicate.Kind,
|
|
1820
|
+
dataSourceAggregatePredicateKinds.fieldHasValue,
|
|
1821
|
+
'fieldHasValue',
|
|
1822
|
+
)
|
|
1823
|
+
) {
|
|
1824
|
+
return hasAggregateValue(value)
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
return false
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1830
|
+
function readPresentationDataSourceEndpointId(
|
|
1831
|
+
binding: PresentationBindingDefinition | null | undefined,
|
|
1832
|
+
) {
|
|
1833
|
+
return isApiEndpointBinding(binding) && binding?.EndpointId
|
|
1834
|
+
? binding.EndpointId
|
|
1835
|
+
: null
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
function applyDataSourceDefaults(
|
|
1839
|
+
binding: PresentationDataSourceBinding,
|
|
1840
|
+
dataSource: DataSourceDefinition,
|
|
1841
|
+
): PresentationDataSourceBinding {
|
|
1842
|
+
if (!isTanStackQueryBinding(binding)) {
|
|
1843
|
+
return binding
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1846
|
+
return {
|
|
1847
|
+
...binding,
|
|
1848
|
+
staleTime: binding.staleTime ?? readDataSourceStaleTime(dataSource),
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
function createUnboundDataSourceBinding(
|
|
1853
|
+
dataSource: DataSourceDefinition,
|
|
1854
|
+
authorization: PresentationDataSourceAuthorizationRequirement | undefined,
|
|
1855
|
+
): PresentationDataSourceBinding {
|
|
1856
|
+
return presentationDataSourceBindings.localValue({
|
|
1857
|
+
authorization:
|
|
1858
|
+
authorization ??
|
|
1859
|
+
presentationDataSourceAuthorization.required({
|
|
1860
|
+
blockedLabel: `No frontend binding is registered for '${dataSource.Name}'.`,
|
|
1861
|
+
isAuthorized: false,
|
|
1862
|
+
}),
|
|
1863
|
+
data: undefined,
|
|
1864
|
+
dataSourceId: dataSource.Id,
|
|
1865
|
+
})
|
|
1866
|
+
}
|
|
1867
|
+
|
|
1868
|
+
function readDataSourceStaleTime(dataSource: DataSourceDefinition) {
|
|
1869
|
+
const cache = dataSource.Cache
|
|
1870
|
+
if (!cache) {
|
|
1871
|
+
return undefined
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1874
|
+
if (
|
|
1875
|
+
cache.Kind === cachePolicyKinds.reactQuery ||
|
|
1876
|
+
String(cache.Kind).toLocaleLowerCase() === 'reactquery'
|
|
1877
|
+
) {
|
|
1878
|
+
return cache.StaleAfterSeconds === null ||
|
|
1879
|
+
cache.StaleAfterSeconds === undefined
|
|
1880
|
+
? undefined
|
|
1881
|
+
: cache.StaleAfterSeconds * 1000
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1884
|
+
return undefined
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
function isApiEndpointBinding(
|
|
1888
|
+
binding: PresentationBindingDefinition | null | undefined,
|
|
1889
|
+
) {
|
|
1890
|
+
return (
|
|
1891
|
+
binding?.Kind === presentationBindingKinds.apiEndpoint ||
|
|
1892
|
+
String(binding?.Kind).toLocaleLowerCase() === 'apiendpoint'
|
|
1893
|
+
)
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1896
|
+
function isLocalStateBinding(
|
|
1897
|
+
binding: PresentationBindingDefinition | null | undefined,
|
|
1898
|
+
) {
|
|
1899
|
+
return (
|
|
1900
|
+
binding?.Kind === presentationBindingKinds.localState ||
|
|
1901
|
+
String(binding?.Kind).toLocaleLowerCase() === 'localstate'
|
|
1902
|
+
)
|
|
1903
|
+
}
|
|
1904
|
+
|
|
1905
|
+
function readPresentationBindingStringOption(
|
|
1906
|
+
options: unknown,
|
|
1907
|
+
key: string,
|
|
1908
|
+
): string | null {
|
|
1909
|
+
if (!options || typeof options !== 'object') {
|
|
1910
|
+
return null
|
|
1911
|
+
}
|
|
1912
|
+
|
|
1913
|
+
const record = options as Readonly<Record<string, unknown>>
|
|
1914
|
+
const value =
|
|
1915
|
+
record[key] ??
|
|
1916
|
+
record[capitalizeFirstCharacter(key)] ??
|
|
1917
|
+
readCaseInsensitiveProperty(record, key)
|
|
1918
|
+
return typeof value === 'string' && value.trim().length > 0
|
|
1919
|
+
? value
|
|
1920
|
+
: null
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
function readAggregateResponseItems(response: unknown, itemsPath: string | null | undefined) {
|
|
1924
|
+
const value = itemsPath ? readObjectPath(response, itemsPath) : response
|
|
1925
|
+
if (Array.isArray(value)) {
|
|
1926
|
+
return value
|
|
1927
|
+
}
|
|
1928
|
+
|
|
1929
|
+
const items = readObjectPath(response, 'Items')
|
|
1930
|
+
return Array.isArray(items) ? items : []
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
function readStringObjectPath(value: unknown, path: string | null | undefined) {
|
|
1934
|
+
const raw = readObjectPath(value, path)
|
|
1935
|
+
return typeof raw === 'string' && raw.trim().length > 0 ? raw.trim() : null
|
|
1936
|
+
}
|
|
1937
|
+
|
|
1938
|
+
function fieldPathToString(
|
|
1939
|
+
field: DataSourceAggregatePredicate['Field'] | NonNullable<DataSourceAggregateQuery['Measures'][number]['SourceField']>,
|
|
1940
|
+
) {
|
|
1941
|
+
return field?.Segments.map((segment) => segment.Segment).filter(Boolean).join('.') ?? ''
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1944
|
+
function hasAggregateValue(value: unknown) {
|
|
1945
|
+
if (value === null || value === undefined) {
|
|
1946
|
+
return false
|
|
1947
|
+
}
|
|
1948
|
+
|
|
1949
|
+
if (typeof value === 'string') {
|
|
1950
|
+
return value.trim().length > 0
|
|
1951
|
+
}
|
|
1952
|
+
|
|
1953
|
+
if (Array.isArray(value)) {
|
|
1954
|
+
return value.length > 0
|
|
1955
|
+
}
|
|
1956
|
+
|
|
1957
|
+
return true
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1960
|
+
function matchesAggregateOperator(
|
|
1961
|
+
value: unknown,
|
|
1962
|
+
numericValue: AggregateOperator,
|
|
1963
|
+
camelLabel: string,
|
|
1964
|
+
) {
|
|
1965
|
+
return matchesGeneratedEnum(value, numericValue, camelLabel)
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1968
|
+
function matchesDataSourceAggregateMaterializationKind(
|
|
1969
|
+
value: unknown,
|
|
1970
|
+
numericValue: number,
|
|
1971
|
+
camelLabel: string,
|
|
1972
|
+
) {
|
|
1973
|
+
return matchesGeneratedEnum(value, numericValue, camelLabel)
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
function matchesDataSourceAggregatePredicateKind(
|
|
1977
|
+
value: unknown,
|
|
1978
|
+
numericValue: number,
|
|
1979
|
+
camelLabel: string,
|
|
1980
|
+
) {
|
|
1981
|
+
return matchesGeneratedEnum(value, numericValue, camelLabel)
|
|
1982
|
+
}
|
|
1983
|
+
|
|
1984
|
+
function matchesGeneratedEnum(
|
|
1985
|
+
value: unknown,
|
|
1986
|
+
numericValue: number,
|
|
1987
|
+
camelLabel: string,
|
|
1988
|
+
) {
|
|
1989
|
+
return (
|
|
1990
|
+
value === numericValue ||
|
|
1991
|
+
String(value) === String(numericValue) ||
|
|
1992
|
+
String(value).toLocaleLowerCase() === camelLabel.toLocaleLowerCase()
|
|
1993
|
+
)
|
|
1994
|
+
}
|
|
1995
|
+
|
|
1996
|
+
function readStringOption(
|
|
1997
|
+
options: Readonly<Record<string, unknown>>,
|
|
1998
|
+
key: string,
|
|
1999
|
+
) {
|
|
2000
|
+
const value = readObjectOption(options, key)
|
|
2001
|
+
return typeof value === 'string' && value.trim().length > 0
|
|
2002
|
+
? value
|
|
2003
|
+
: undefined
|
|
2004
|
+
}
|
|
2005
|
+
|
|
2006
|
+
function readObjectOption(
|
|
2007
|
+
options: Readonly<Record<string, unknown>>,
|
|
2008
|
+
key: string,
|
|
2009
|
+
) {
|
|
2010
|
+
return Object.prototype.hasOwnProperty.call(options, key)
|
|
2011
|
+
? options[key]
|
|
2012
|
+
: readCaseInsensitiveProperty(options, key)
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
function readNumberOption(
|
|
2016
|
+
options: Readonly<Record<string, unknown>>,
|
|
2017
|
+
key: string,
|
|
2018
|
+
) {
|
|
2019
|
+
const value = readObjectOption(options, key)
|
|
2020
|
+
return typeof value === 'number' && Number.isFinite(value)
|
|
2021
|
+
? value
|
|
2022
|
+
: undefined
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
function readSecondsOptionAsMilliseconds(
|
|
2026
|
+
options: Readonly<Record<string, unknown>>,
|
|
2027
|
+
key: string,
|
|
2028
|
+
) {
|
|
2029
|
+
const seconds = readNumberOption(options, key)
|
|
2030
|
+
return seconds === undefined ? undefined : seconds * 1000
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
function readRetryOption(
|
|
2034
|
+
options: Readonly<Record<string, unknown>>,
|
|
2035
|
+
key: string,
|
|
2036
|
+
) {
|
|
2037
|
+
const value = readObjectOption(options, key)
|
|
2038
|
+
return typeof value === 'boolean' || typeof value === 'number'
|
|
2039
|
+
? value
|
|
2040
|
+
: undefined
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2043
|
+
function readCaseInsensitiveProperty(
|
|
2044
|
+
record: Readonly<Record<string, unknown>>,
|
|
2045
|
+
key: string,
|
|
2046
|
+
) {
|
|
2047
|
+
const normalizedKey = key.toLocaleLowerCase()
|
|
2048
|
+
const match = Object.keys(record).find(
|
|
2049
|
+
(candidate) => candidate.toLocaleLowerCase() === normalizedKey,
|
|
2050
|
+
)
|
|
2051
|
+
return match ? record[match] : undefined
|
|
2052
|
+
}
|
|
2053
|
+
|
|
2054
|
+
function capitalizeFirstCharacter(value: string) {
|
|
2055
|
+
return value.length > 0
|
|
2056
|
+
? `${value.slice(0, 1).toLocaleUpperCase()}${value.slice(1)}`
|
|
2057
|
+
: value
|
|
2058
|
+
}
|
|
2059
|
+
|
|
2060
|
+
function projectDataSourceRouteParameters(
|
|
2061
|
+
parameters: readonly ParameterDefinition[],
|
|
2062
|
+
routeParameters: Readonly<Record<string, string | undefined>> | undefined,
|
|
2063
|
+
) {
|
|
2064
|
+
return Object.fromEntries(
|
|
2065
|
+
parameters.map((parameter) => [
|
|
2066
|
+
parameter.Name,
|
|
2067
|
+
readRouteParameterValue(routeParameters, parameter.Name),
|
|
2068
|
+
]),
|
|
2069
|
+
)
|
|
2070
|
+
}
|
|
2071
|
+
|
|
2072
|
+
function hasRequiredDataSourceRouteParameters(
|
|
2073
|
+
parameters: readonly ParameterDefinition[],
|
|
2074
|
+
routeParameters: Readonly<Record<string, string | null | undefined>>,
|
|
2075
|
+
) {
|
|
2076
|
+
return parameters.every(
|
|
2077
|
+
(parameter) =>
|
|
2078
|
+
!parameter.IsRequired ||
|
|
2079
|
+
typeof routeParameters[parameter.Name] === 'string' &&
|
|
2080
|
+
routeParameters[parameter.Name]!.length > 0,
|
|
2081
|
+
)
|
|
2082
|
+
}
|
|
2083
|
+
|
|
2084
|
+
function readRouteParameterValue(
|
|
2085
|
+
routeParameters: Readonly<Record<string, string | undefined>> | undefined,
|
|
2086
|
+
parameterName: string,
|
|
2087
|
+
) {
|
|
2088
|
+
if (!routeParameters) {
|
|
2089
|
+
return undefined
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
if (Object.prototype.hasOwnProperty.call(routeParameters, parameterName)) {
|
|
2093
|
+
return routeParameters[parameterName]
|
|
2094
|
+
}
|
|
2095
|
+
|
|
2096
|
+
const match = Object.keys(routeParameters).find(
|
|
2097
|
+
(candidate) => candidate.toLocaleLowerCase() === parameterName.toLocaleLowerCase(),
|
|
2098
|
+
)
|
|
2099
|
+
return match ? routeParameters[match] : undefined
|
|
2100
|
+
}
|
|
2101
|
+
|
|
2102
|
+
function hasOwn<TValue>(
|
|
2103
|
+
values: Readonly<Record<string, TValue>>,
|
|
2104
|
+
key: string,
|
|
2105
|
+
) {
|
|
2106
|
+
return Object.prototype.hasOwnProperty.call(values, key)
|
|
2107
|
+
}
|
|
2108
|
+
|
|
2109
|
+
function resolveApiEndpointDataSourcePendingLabel(
|
|
2110
|
+
label: ApiEndpointTanStackQueryDataSourceBindingProjectionRegistryOptions['pendingLabel'],
|
|
2111
|
+
context: PresentationDataSourceApiEndpointFactoryContext,
|
|
2112
|
+
) {
|
|
2113
|
+
if (typeof label === 'function') {
|
|
2114
|
+
return label(context)
|
|
2115
|
+
}
|
|
2116
|
+
|
|
2117
|
+
return label ?? `Loading ${context.dataSource.Name.toLocaleLowerCase()}...`
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2120
|
+
function createDefaultApiEndpointDataSourceQueryKey({
|
|
2121
|
+
context,
|
|
2122
|
+
dataSource,
|
|
2123
|
+
endpointId,
|
|
2124
|
+
routeParameters,
|
|
2125
|
+
}: PresentationDataSourceApiEndpointFactoryContext) {
|
|
2126
|
+
return [
|
|
2127
|
+
'presentation-data-source',
|
|
2128
|
+
dataSource.Id,
|
|
2129
|
+
endpointId,
|
|
2130
|
+
routeParameters,
|
|
2131
|
+
...(context.queryKeyParts ?? []),
|
|
2132
|
+
] as const
|
|
2133
|
+
}
|
|
2134
|
+
|
|
2135
|
+
function mapFactories<TFactory, TMappedFactory>(
|
|
2136
|
+
factories: Readonly<Record<string, TFactory>> | undefined,
|
|
2137
|
+
mapFactory: (factory: TFactory) => TMappedFactory,
|
|
2138
|
+
) {
|
|
2139
|
+
if (!factories) {
|
|
2140
|
+
return undefined
|
|
2141
|
+
}
|
|
2142
|
+
|
|
2143
|
+
return Object.fromEntries(
|
|
2144
|
+
Object.entries(factories).map(([key, factory]) => [
|
|
2145
|
+
key,
|
|
2146
|
+
mapFactory(factory as TFactory),
|
|
2147
|
+
]),
|
|
2148
|
+
)
|
|
2149
|
+
}
|