@n-dx/web 0.1.0
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 +96 -0
- package/README.md +5 -0
- package/build.js +243 -0
- package/dist/cli/index.d.ts +8 -0
- package/dist/cli/index.js +50 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/landing/index.html +325 -0
- package/dist/landing/landing.d.ts +38 -0
- package/dist/landing/landing.js +299 -0
- package/dist/landing/landing.js.map +1 -0
- package/dist/public.d.ts +55 -0
- package/dist/public.js +51 -0
- package/dist/public.js.map +1 -0
- package/dist/schema/features.d.ts +28 -0
- package/dist/schema/features.js +9 -0
- package/dist/schema/features.js.map +1 -0
- package/dist/schema/v1.d.ts +317 -0
- package/dist/schema/v1.js +3 -0
- package/dist/schema/v1.js.map +1 -0
- package/dist/server/aggregation-cache.d.ts +105 -0
- package/dist/server/aggregation-cache.js +163 -0
- package/dist/server/aggregation-cache.js.map +1 -0
- package/dist/server/concurrent-execution-metrics.d.ts +103 -0
- package/dist/server/concurrent-execution-metrics.js +253 -0
- package/dist/server/concurrent-execution-metrics.js.map +1 -0
- package/dist/server/domain-gateway.d.ts +18 -0
- package/dist/server/domain-gateway.js +19 -0
- package/dist/server/domain-gateway.js.map +1 -0
- package/dist/server/incremental-task-usage.d.ts +92 -0
- package/dist/server/incremental-task-usage.js +251 -0
- package/dist/server/incremental-task-usage.js.map +1 -0
- package/dist/server/index.d.ts +39 -0
- package/dist/server/index.js +36 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/port.d.ts +96 -0
- package/dist/server/port.js +134 -0
- package/dist/server/port.js.map +1 -0
- package/dist/server/pr-markdown-refresh-diagnostics.d.ts +59 -0
- package/dist/server/pr-markdown-refresh-diagnostics.js +429 -0
- package/dist/server/pr-markdown-refresh-diagnostics.js.map +1 -0
- package/dist/server/prd-io.d.ts +40 -0
- package/dist/server/prd-io.js +66 -0
- package/dist/server/prd-io.js.map +1 -0
- package/dist/server/process-memory-tracker.d.ts +79 -0
- package/dist/server/process-memory-tracker.js +194 -0
- package/dist/server/process-memory-tracker.js.map +1 -0
- package/dist/server/register-scheduler.d.ts +53 -0
- package/dist/server/register-scheduler.js +36 -0
- package/dist/server/register-scheduler.js.map +1 -0
- package/dist/server/rex-gateway.d.ts +39 -0
- package/dist/server/rex-gateway.js +47 -0
- package/dist/server/rex-gateway.js.map +1 -0
- package/dist/server/routes-adaptive.d.ts +21 -0
- package/dist/server/routes-adaptive.js +659 -0
- package/dist/server/routes-adaptive.js.map +1 -0
- package/dist/server/routes-config.d.ts +47 -0
- package/dist/server/routes-config.js +222 -0
- package/dist/server/routes-config.js.map +1 -0
- package/dist/server/routes-data.d.ts +14 -0
- package/dist/server/routes-data.js +129 -0
- package/dist/server/routes-data.js.map +1 -0
- package/dist/server/routes-features.d.ts +14 -0
- package/dist/server/routes-features.js +245 -0
- package/dist/server/routes-features.js.map +1 -0
- package/dist/server/routes-hench.d.ts +116 -0
- package/dist/server/routes-hench.js +2016 -0
- package/dist/server/routes-hench.js.map +1 -0
- package/dist/server/routes-integrations.d.ts +23 -0
- package/dist/server/routes-integrations.js +277 -0
- package/dist/server/routes-integrations.js.map +1 -0
- package/dist/server/routes-mcp.d.ts +31 -0
- package/dist/server/routes-mcp.js +175 -0
- package/dist/server/routes-mcp.js.map +1 -0
- package/dist/server/routes-notion.d.ts +23 -0
- package/dist/server/routes-notion.js +723 -0
- package/dist/server/routes-notion.js.map +1 -0
- package/dist/server/routes-project.d.ts +47 -0
- package/dist/server/routes-project.js +128 -0
- package/dist/server/routes-project.js.map +1 -0
- package/dist/server/routes-rex/analysis.d.ts +11 -0
- package/dist/server/routes-rex/analysis.js +583 -0
- package/dist/server/routes-rex/analysis.js.map +1 -0
- package/dist/server/routes-rex/execution.d.ts +37 -0
- package/dist/server/routes-rex/execution.js +355 -0
- package/dist/server/routes-rex/execution.js.map +1 -0
- package/dist/server/routes-rex/health.d.ts +8 -0
- package/dist/server/routes-rex/health.js +136 -0
- package/dist/server/routes-rex/health.js.map +1 -0
- package/dist/server/routes-rex/index.d.ts +35 -0
- package/dist/server/routes-rex/index.js +72 -0
- package/dist/server/routes-rex/index.js.map +1 -0
- package/dist/server/routes-rex/items.d.ts +8 -0
- package/dist/server/routes-rex/items.js +359 -0
- package/dist/server/routes-rex/items.js.map +1 -0
- package/dist/server/routes-rex/prune.d.ts +11 -0
- package/dist/server/routes-rex/prune.js +379 -0
- package/dist/server/routes-rex/prune.js.map +1 -0
- package/dist/server/routes-rex/reads.d.ts +9 -0
- package/dist/server/routes-rex/reads.js +119 -0
- package/dist/server/routes-rex/reads.js.map +1 -0
- package/dist/server/routes-rex/requirements.d.ts +10 -0
- package/dist/server/routes-rex/requirements.js +408 -0
- package/dist/server/routes-rex/requirements.js.map +1 -0
- package/dist/server/routes-rex/shared.d.ts +37 -0
- package/dist/server/routes-rex/shared.js +73 -0
- package/dist/server/routes-rex/shared.js.map +1 -0
- package/dist/server/routes-search.d.ts +26 -0
- package/dist/server/routes-search.js +82 -0
- package/dist/server/routes-search.js.map +1 -0
- package/dist/server/routes-sourcevision.d.ts +18 -0
- package/dist/server/routes-sourcevision.js +444 -0
- package/dist/server/routes-sourcevision.js.map +1 -0
- package/dist/server/routes-static.d.ts +20 -0
- package/dist/server/routes-static.js +168 -0
- package/dist/server/routes-static.js.map +1 -0
- package/dist/server/routes-status.d.ts +58 -0
- package/dist/server/routes-status.js +191 -0
- package/dist/server/routes-status.js.map +1 -0
- package/dist/server/routes-token-usage.d.ts +63 -0
- package/dist/server/routes-token-usage.js +720 -0
- package/dist/server/routes-token-usage.js.map +1 -0
- package/dist/server/routes-validation.d.ts +10 -0
- package/dist/server/routes-validation.js +365 -0
- package/dist/server/routes-validation.js.map +1 -0
- package/dist/server/routes-workflow.d.ts +15 -0
- package/dist/server/routes-workflow.js +498 -0
- package/dist/server/routes-workflow.js.map +1 -0
- package/dist/server/search-index.d.ts +111 -0
- package/dist/server/search-index.js +348 -0
- package/dist/server/search-index.js.map +1 -0
- package/dist/server/shared-types.d.ts +65 -0
- package/dist/server/shared-types.js +31 -0
- package/dist/server/shared-types.js.map +1 -0
- package/dist/server/start.d.ts +68 -0
- package/dist/server/start.js +568 -0
- package/dist/server/start.js.map +1 -0
- package/dist/server/task-usage.d.ts +17 -0
- package/dist/server/task-usage.js +20 -0
- package/dist/server/task-usage.js.map +1 -0
- package/dist/server/types.d.ts +27 -0
- package/dist/server/types.js +26 -0
- package/dist/server/types.js.map +1 -0
- package/dist/server/usage-cleanup-scheduler.d.ts +107 -0
- package/dist/server/usage-cleanup-scheduler.js +232 -0
- package/dist/server/usage-cleanup-scheduler.js.map +1 -0
- package/dist/server/websocket.d.ts +131 -0
- package/dist/server/websocket.js +512 -0
- package/dist/server/websocket.js.map +1 -0
- package/dist/shared/data-files.d.ts +17 -0
- package/dist/shared/data-files.js +18 -0
- package/dist/shared/data-files.js.map +1 -0
- package/dist/shared/index.d.ts +9 -0
- package/dist/shared/index.js +9 -0
- package/dist/shared/index.js.map +1 -0
- package/dist/shared/view-id.d.ts +8 -0
- package/dist/shared/view-id.js +9 -0
- package/dist/shared/view-id.js.map +1 -0
- package/dist/viewer/Hench-F.png +0 -0
- package/dist/viewer/Rex-F.png +0 -0
- package/dist/viewer/SourceVision-F.png +0 -0
- package/dist/viewer/SourceVision.png +0 -0
- package/dist/viewer/api.d.ts +19 -0
- package/dist/viewer/api.js +17 -0
- package/dist/viewer/api.js.map +1 -0
- package/dist/viewer/bootstrap.d.ts +13 -0
- package/dist/viewer/bootstrap.js +40 -0
- package/dist/viewer/bootstrap.js.map +1 -0
- package/dist/viewer/components/active-tasks-panel.d.ts +36 -0
- package/dist/viewer/components/active-tasks-panel.js +183 -0
- package/dist/viewer/components/active-tasks-panel.js.map +1 -0
- package/dist/viewer/components/breadcrumb.d.ts +21 -0
- package/dist/viewer/components/breadcrumb.js +117 -0
- package/dist/viewer/components/breadcrumb.js.map +1 -0
- package/dist/viewer/components/concurrency-panel.d.ts +18 -0
- package/dist/viewer/components/concurrency-panel.js +175 -0
- package/dist/viewer/components/concurrency-panel.js.map +1 -0
- package/dist/viewer/components/config-footer.d.ts +11 -0
- package/dist/viewer/components/config-footer.js +132 -0
- package/dist/viewer/components/config-footer.js.map +1 -0
- package/dist/viewer/components/constants.d.ts +10 -0
- package/dist/viewer/components/constants.js +11 -0
- package/dist/viewer/components/constants.js.map +1 -0
- package/dist/viewer/components/copy-link-button.d.ts +30 -0
- package/dist/viewer/components/copy-link-button.js +74 -0
- package/dist/viewer/components/copy-link-button.js.map +1 -0
- package/dist/viewer/components/crash-recovery-banner.d.ts +28 -0
- package/dist/viewer/components/crash-recovery-banner.js +47 -0
- package/dist/viewer/components/crash-recovery-banner.js.map +1 -0
- package/dist/viewer/components/data-display/collapsible-section.d.ts +14 -0
- package/dist/viewer/components/data-display/collapsible-section.js +66 -0
- package/dist/viewer/components/data-display/collapsible-section.js.map +1 -0
- package/dist/viewer/components/data-display/findings-list.d.ts +13 -0
- package/dist/viewer/components/data-display/findings-list.js +136 -0
- package/dist/viewer/components/data-display/findings-list.js.map +1 -0
- package/dist/viewer/components/data-display/health-gauge.d.ts +37 -0
- package/dist/viewer/components/data-display/health-gauge.js +62 -0
- package/dist/viewer/components/data-display/health-gauge.js.map +1 -0
- package/dist/viewer/components/data-display/mini-charts.d.ts +36 -0
- package/dist/viewer/components/data-display/mini-charts.js +124 -0
- package/dist/viewer/components/data-display/mini-charts.js.map +1 -0
- package/dist/viewer/components/data-display/tree-view.d.ts +18 -0
- package/dist/viewer/components/data-display/tree-view.js +107 -0
- package/dist/viewer/components/data-display/tree-view.js.map +1 -0
- package/dist/viewer/components/data-display/zone-map.d.ts +28 -0
- package/dist/viewer/components/data-display/zone-map.js +197 -0
- package/dist/viewer/components/data-display/zone-map.js.map +1 -0
- package/dist/viewer/components/degradation-banner.d.ts +28 -0
- package/dist/viewer/components/degradation-banner.js +47 -0
- package/dist/viewer/components/degradation-banner.js.map +1 -0
- package/dist/viewer/components/detail-panel.d.ts +12 -0
- package/dist/viewer/components/detail-panel.js +166 -0
- package/dist/viewer/components/detail-panel.js.map +1 -0
- package/dist/viewer/components/elapsed-time.d.ts +38 -0
- package/dist/viewer/components/elapsed-time.js +35 -0
- package/dist/viewer/components/elapsed-time.js.map +1 -0
- package/dist/viewer/components/faq.d.ts +12 -0
- package/dist/viewer/components/faq.js +237 -0
- package/dist/viewer/components/faq.js.map +1 -0
- package/dist/viewer/components/favicon.d.ts +30 -0
- package/dist/viewer/components/favicon.js +90 -0
- package/dist/viewer/components/favicon.js.map +1 -0
- package/dist/viewer/components/guide.d.ts +5 -0
- package/dist/viewer/components/guide.js +116 -0
- package/dist/viewer/components/guide.js.map +1 -0
- package/dist/viewer/components/index.d.ts +37 -0
- package/dist/viewer/components/index.js +46 -0
- package/dist/viewer/components/index.js.map +1 -0
- package/dist/viewer/components/logos.d.ts +42 -0
- package/dist/viewer/components/logos.js +46 -0
- package/dist/viewer/components/logos.js.map +1 -0
- package/dist/viewer/components/memory-panel.d.ts +19 -0
- package/dist/viewer/components/memory-panel.js +181 -0
- package/dist/viewer/components/memory-panel.js.map +1 -0
- package/dist/viewer/components/memory-warning.d.ts +23 -0
- package/dist/viewer/components/memory-warning.js +42 -0
- package/dist/viewer/components/memory-warning.js.map +1 -0
- package/dist/viewer/components/notion-schema-wizard.d.ts +16 -0
- package/dist/viewer/components/notion-schema-wizard.js +263 -0
- package/dist/viewer/components/notion-schema-wizard.js.map +1 -0
- package/dist/viewer/components/polling-suspension-indicator.d.ts +24 -0
- package/dist/viewer/components/polling-suspension-indicator.js +31 -0
- package/dist/viewer/components/polling-suspension-indicator.js.map +1 -0
- package/dist/viewer/components/prd-tree/add-item-form.d.ts +31 -0
- package/dist/viewer/components/prd-tree/add-item-form.js +231 -0
- package/dist/viewer/components/prd-tree/add-item-form.js.map +1 -0
- package/dist/viewer/components/prd-tree/analyze-panel.d.ts +13 -0
- package/dist/viewer/components/prd-tree/analyze-panel.js +245 -0
- package/dist/viewer/components/prd-tree/analyze-panel.js.map +1 -0
- package/dist/viewer/components/prd-tree/batch-import-panel.d.ts +34 -0
- package/dist/viewer/components/prd-tree/batch-import-panel.js +415 -0
- package/dist/viewer/components/prd-tree/batch-import-panel.js.map +1 -0
- package/dist/viewer/components/prd-tree/bulk-actions.d.ts +19 -0
- package/dist/viewer/components/prd-tree/bulk-actions.js +90 -0
- package/dist/viewer/components/prd-tree/bulk-actions.js.map +1 -0
- package/dist/viewer/components/prd-tree/compute.d.ts +32 -0
- package/dist/viewer/components/prd-tree/compute.js +129 -0
- package/dist/viewer/components/prd-tree/compute.js.map +1 -0
- package/dist/viewer/components/prd-tree/delete-confirmation.d.ts +23 -0
- package/dist/viewer/components/prd-tree/delete-confirmation.js +83 -0
- package/dist/viewer/components/prd-tree/delete-confirmation.js.map +1 -0
- package/dist/viewer/components/prd-tree/execution-panel.d.ts +14 -0
- package/dist/viewer/components/prd-tree/execution-panel.js +291 -0
- package/dist/viewer/components/prd-tree/execution-panel.js.map +1 -0
- package/dist/viewer/components/prd-tree/facet-filter.d.ts +40 -0
- package/dist/viewer/components/prd-tree/facet-filter.js +188 -0
- package/dist/viewer/components/prd-tree/facet-filter.js.map +1 -0
- package/dist/viewer/components/prd-tree/index.d.ts +24 -0
- package/dist/viewer/components/prd-tree/index.js +16 -0
- package/dist/viewer/components/prd-tree/index.js.map +1 -0
- package/dist/viewer/components/prd-tree/inline-add-form.d.ts +32 -0
- package/dist/viewer/components/prd-tree/inline-add-form.js +175 -0
- package/dist/viewer/components/prd-tree/inline-add-form.js.map +1 -0
- package/dist/viewer/components/prd-tree/inline-status-picker.d.ts +31 -0
- package/dist/viewer/components/prd-tree/inline-status-picker.js +110 -0
- package/dist/viewer/components/prd-tree/inline-status-picker.js.map +1 -0
- package/dist/viewer/components/prd-tree/lazy-children.d.ts +40 -0
- package/dist/viewer/components/prd-tree/lazy-children.js +73 -0
- package/dist/viewer/components/prd-tree/lazy-children.js.map +1 -0
- package/dist/viewer/components/prd-tree/levels.d.ts +31 -0
- package/dist/viewer/components/prd-tree/levels.js +72 -0
- package/dist/viewer/components/prd-tree/levels.js.map +1 -0
- package/dist/viewer/components/prd-tree/listener-lifecycle.d.ts +105 -0
- package/dist/viewer/components/prd-tree/listener-lifecycle.js +173 -0
- package/dist/viewer/components/prd-tree/listener-lifecycle.js.map +1 -0
- package/dist/viewer/components/prd-tree/merge-preview.d.ts +25 -0
- package/dist/viewer/components/prd-tree/merge-preview.js +181 -0
- package/dist/viewer/components/prd-tree/merge-preview.js.map +1 -0
- package/dist/viewer/components/prd-tree/prd-tree.d.ts +91 -0
- package/dist/viewer/components/prd-tree/prd-tree.js +565 -0
- package/dist/viewer/components/prd-tree/prd-tree.js.map +1 -0
- package/dist/viewer/components/prd-tree/proposal-editor.d.ts +44 -0
- package/dist/viewer/components/prd-tree/proposal-editor.js +438 -0
- package/dist/viewer/components/prd-tree/proposal-editor.js.map +1 -0
- package/dist/viewer/components/prd-tree/prune-confirmation.d.ts +25 -0
- package/dist/viewer/components/prd-tree/prune-confirmation.js +336 -0
- package/dist/viewer/components/prd-tree/prune-confirmation.js.map +1 -0
- package/dist/viewer/components/prd-tree/prune-diff-tree.d.ts +39 -0
- package/dist/viewer/components/prd-tree/prune-diff-tree.js +319 -0
- package/dist/viewer/components/prd-tree/prune-diff-tree.js.map +1 -0
- package/dist/viewer/components/prd-tree/reorganize-panel.d.ts +16 -0
- package/dist/viewer/components/prd-tree/reorganize-panel.js +213 -0
- package/dist/viewer/components/prd-tree/reorganize-panel.js.map +1 -0
- package/dist/viewer/components/prd-tree/smart-add-input.d.ts +19 -0
- package/dist/viewer/components/prd-tree/smart-add-input.js +383 -0
- package/dist/viewer/components/prd-tree/smart-add-input.js.map +1 -0
- package/dist/viewer/components/prd-tree/status-filter.d.ts +40 -0
- package/dist/viewer/components/prd-tree/status-filter.js +131 -0
- package/dist/viewer/components/prd-tree/status-filter.js.map +1 -0
- package/dist/viewer/components/prd-tree/task-detail.d.ts +41 -0
- package/dist/viewer/components/prd-tree/task-detail.js +1205 -0
- package/dist/viewer/components/prd-tree/task-detail.js.map +1 -0
- package/dist/viewer/components/prd-tree/task-utilization.d.ts +7 -0
- package/dist/viewer/components/prd-tree/task-utilization.js +25 -0
- package/dist/viewer/components/prd-tree/task-utilization.js.map +1 -0
- package/dist/viewer/components/prd-tree/tree-differ.d.ts +59 -0
- package/dist/viewer/components/prd-tree/tree-differ.js +200 -0
- package/dist/viewer/components/prd-tree/tree-differ.js.map +1 -0
- package/dist/viewer/components/prd-tree/tree-event-delegate.d.ts +70 -0
- package/dist/viewer/components/prd-tree/tree-event-delegate.js +176 -0
- package/dist/viewer/components/prd-tree/tree-event-delegate.js.map +1 -0
- package/dist/viewer/components/prd-tree/tree-search.d.ts +65 -0
- package/dist/viewer/components/prd-tree/tree-search.js +178 -0
- package/dist/viewer/components/prd-tree/tree-search.js.map +1 -0
- package/dist/viewer/components/prd-tree/tree-utils.d.ts +38 -0
- package/dist/viewer/components/prd-tree/tree-utils.js +107 -0
- package/dist/viewer/components/prd-tree/tree-utils.js.map +1 -0
- package/dist/viewer/components/prd-tree/types.d.ts +93 -0
- package/dist/viewer/components/prd-tree/types.js +16 -0
- package/dist/viewer/components/prd-tree/types.js.map +1 -0
- package/dist/viewer/components/prd-tree/virtual-scroll.d.ts +119 -0
- package/dist/viewer/components/prd-tree/virtual-scroll.js +169 -0
- package/dist/viewer/components/prd-tree/virtual-scroll.js.map +1 -0
- package/dist/viewer/components/progressive-loader.d.ts +114 -0
- package/dist/viewer/components/progressive-loader.js +225 -0
- package/dist/viewer/components/progressive-loader.js.map +1 -0
- package/dist/viewer/components/refresh-queue-status.d.ts +20 -0
- package/dist/viewer/components/refresh-queue-status.js +65 -0
- package/dist/viewer/components/refresh-queue-status.js.map +1 -0
- package/dist/viewer/components/rex-task-link.d.ts +50 -0
- package/dist/viewer/components/rex-task-link.js +218 -0
- package/dist/viewer/components/rex-task-link.js.map +1 -0
- package/dist/viewer/components/search-filter.d.ts +20 -0
- package/dist/viewer/components/search-filter.js +28 -0
- package/dist/viewer/components/search-filter.js.map +1 -0
- package/dist/viewer/components/search-overlay.d.ts +31 -0
- package/dist/viewer/components/search-overlay.js +472 -0
- package/dist/viewer/components/search-overlay.js.map +1 -0
- package/dist/viewer/components/sidebar.d.ts +18 -0
- package/dist/viewer/components/sidebar.js +357 -0
- package/dist/viewer/components/sidebar.js.map +1 -0
- package/dist/viewer/components/status-indicators.d.ts +63 -0
- package/dist/viewer/components/status-indicators.js +136 -0
- package/dist/viewer/components/status-indicators.js.map +1 -0
- package/dist/viewer/components/theme-toggle.d.ts +8 -0
- package/dist/viewer/components/theme-toggle.js +28 -0
- package/dist/viewer/components/theme-toggle.js.map +1 -0
- package/dist/viewer/components/throttle-controls.d.ts +18 -0
- package/dist/viewer/components/throttle-controls.js +304 -0
- package/dist/viewer/components/throttle-controls.js.map +1 -0
- package/dist/viewer/components/ws-health-panel.d.ts +18 -0
- package/dist/viewer/components/ws-health-panel.js +250 -0
- package/dist/viewer/components/ws-health-panel.js.map +1 -0
- package/dist/viewer/components/zone-slideout.d.ts +17 -0
- package/dist/viewer/components/zone-slideout.js +162 -0
- package/dist/viewer/components/zone-slideout.js.map +1 -0
- package/dist/viewer/crash/crash-detector.d.ts +69 -0
- package/dist/viewer/crash/crash-detector.js +239 -0
- package/dist/viewer/crash/crash-detector.js.map +1 -0
- package/dist/viewer/crash/index.d.ts +7 -0
- package/dist/viewer/crash/index.js +8 -0
- package/dist/viewer/crash/index.js.map +1 -0
- package/dist/viewer/deployed-mode.d.ts +37 -0
- package/dist/viewer/deployed-mode.js +94 -0
- package/dist/viewer/deployed-mode.js.map +1 -0
- package/dist/viewer/external.d.ts +17 -0
- package/dist/viewer/external.js +17 -0
- package/dist/viewer/external.js.map +1 -0
- package/dist/viewer/graph/index.d.ts +9 -0
- package/dist/viewer/graph/index.js +12 -0
- package/dist/viewer/graph/index.js.map +1 -0
- package/dist/viewer/graph/physics.d.ts +96 -0
- package/dist/viewer/graph/physics.js +366 -0
- package/dist/viewer/graph/physics.js.map +1 -0
- package/dist/viewer/graph/renderer.d.ts +184 -0
- package/dist/viewer/graph/renderer.js +1438 -0
- package/dist/viewer/graph/renderer.js.map +1 -0
- package/dist/viewer/hooks/index.d.ts +27 -0
- package/dist/viewer/hooks/index.js +28 -0
- package/dist/viewer/hooks/index.js.map +1 -0
- package/dist/viewer/hooks/use-app-data.d.ts +31 -0
- package/dist/viewer/hooks/use-app-data.js +152 -0
- package/dist/viewer/hooks/use-app-data.js.map +1 -0
- package/dist/viewer/hooks/use-crash-recovery.d.ts +50 -0
- package/dist/viewer/hooks/use-crash-recovery.js +76 -0
- package/dist/viewer/hooks/use-crash-recovery.js.map +1 -0
- package/dist/viewer/hooks/use-delete-actions.d.ts +48 -0
- package/dist/viewer/hooks/use-delete-actions.js +103 -0
- package/dist/viewer/hooks/use-delete-actions.js.map +1 -0
- package/dist/viewer/hooks/use-dom-performance-monitor.d.ts +68 -0
- package/dist/viewer/hooks/use-dom-performance-monitor.js +71 -0
- package/dist/viewer/hooks/use-dom-performance-monitor.js.map +1 -0
- package/dist/viewer/hooks/use-facet-state.d.ts +32 -0
- package/dist/viewer/hooks/use-facet-state.js +119 -0
- package/dist/viewer/hooks/use-facet-state.js.map +1 -0
- package/dist/viewer/hooks/use-feature-toggle.d.ts +18 -0
- package/dist/viewer/hooks/use-feature-toggle.js +57 -0
- package/dist/viewer/hooks/use-feature-toggle.js.map +1 -0
- package/dist/viewer/hooks/use-file-edges.d.ts +23 -0
- package/dist/viewer/hooks/use-file-edges.js +221 -0
- package/dist/viewer/hooks/use-file-edges.js.map +1 -0
- package/dist/viewer/hooks/use-graceful-degradation.d.ts +30 -0
- package/dist/viewer/hooks/use-graceful-degradation.js +45 -0
- package/dist/viewer/hooks/use-graceful-degradation.js.map +1 -0
- package/dist/viewer/hooks/use-item-selection.d.ts +49 -0
- package/dist/viewer/hooks/use-item-selection.js +117 -0
- package/dist/viewer/hooks/use-item-selection.js.map +1 -0
- package/dist/viewer/hooks/use-memory-monitor.d.ts +39 -0
- package/dist/viewer/hooks/use-memory-monitor.js +73 -0
- package/dist/viewer/hooks/use-memory-monitor.js.map +1 -0
- package/dist/viewer/hooks/use-pan-zoom.d.ts +33 -0
- package/dist/viewer/hooks/use-pan-zoom.js +110 -0
- package/dist/viewer/hooks/use-pan-zoom.js.map +1 -0
- package/dist/viewer/hooks/use-persistent-filter.d.ts +24 -0
- package/dist/viewer/hooks/use-persistent-filter.js +37 -0
- package/dist/viewer/hooks/use-persistent-filter.js.map +1 -0
- package/dist/viewer/hooks/use-polling-suspension.d.ts +32 -0
- package/dist/viewer/hooks/use-polling-suspension.js +41 -0
- package/dist/viewer/hooks/use-polling-suspension.js.map +1 -0
- package/dist/viewer/hooks/use-polling.d.ts +39 -0
- package/dist/viewer/hooks/use-polling.js +55 -0
- package/dist/viewer/hooks/use-polling.js.map +1 -0
- package/dist/viewer/hooks/use-prd-actions.d.ts +126 -0
- package/dist/viewer/hooks/use-prd-actions.js +250 -0
- package/dist/viewer/hooks/use-prd-actions.js.map +1 -0
- package/dist/viewer/hooks/use-prd-data.d.ts +45 -0
- package/dist/viewer/hooks/use-prd-data.js +159 -0
- package/dist/viewer/hooks/use-prd-data.js.map +1 -0
- package/dist/viewer/hooks/use-prd-deep-link.d.ts +45 -0
- package/dist/viewer/hooks/use-prd-deep-link.js +60 -0
- package/dist/viewer/hooks/use-prd-deep-link.js.map +1 -0
- package/dist/viewer/hooks/use-prd-websocket.d.ts +47 -0
- package/dist/viewer/hooks/use-prd-websocket.js +139 -0
- package/dist/viewer/hooks/use-prd-websocket.js.map +1 -0
- package/dist/viewer/hooks/use-project-metadata.d.ts +25 -0
- package/dist/viewer/hooks/use-project-metadata.js +55 -0
- package/dist/viewer/hooks/use-project-metadata.js.map +1 -0
- package/dist/viewer/hooks/use-project-status.d.ts +60 -0
- package/dist/viewer/hooks/use-project-status.js +133 -0
- package/dist/viewer/hooks/use-project-status.js.map +1 -0
- package/dist/viewer/hooks/use-refresh-throttle.d.ts +45 -0
- package/dist/viewer/hooks/use-refresh-throttle.js +52 -0
- package/dist/viewer/hooks/use-refresh-throttle.js.map +1 -0
- package/dist/viewer/hooks/use-route-state.d.ts +18 -0
- package/dist/viewer/hooks/use-route-state.js +115 -0
- package/dist/viewer/hooks/use-route-state.js.map +1 -0
- package/dist/viewer/hooks/use-subzone-edges.d.ts +21 -0
- package/dist/viewer/hooks/use-subzone-edges.js +147 -0
- package/dist/viewer/hooks/use-subzone-edges.js.map +1 -0
- package/dist/viewer/hooks/use-tab-visibility.d.ts +31 -0
- package/dist/viewer/hooks/use-tab-visibility.js +43 -0
- package/dist/viewer/hooks/use-tab-visibility.js.map +1 -0
- package/dist/viewer/hooks/use-tick.d.ts +43 -0
- package/dist/viewer/hooks/use-tick.js +76 -0
- package/dist/viewer/hooks/use-tick.js.map +1 -0
- package/dist/viewer/hooks/use-toast.d.ts +24 -0
- package/dist/viewer/hooks/use-toast.js +26 -0
- package/dist/viewer/hooks/use-toast.js.map +1 -0
- package/dist/viewer/hooks/use-zone-drag.d.ts +30 -0
- package/dist/viewer/hooks/use-zone-drag.js +60 -0
- package/dist/viewer/hooks/use-zone-drag.js.map +1 -0
- package/dist/viewer/index.html +36 -0
- package/dist/viewer/loader.d.ts +33 -0
- package/dist/viewer/loader.js +195 -0
- package/dist/viewer/loader.js.map +1 -0
- package/dist/viewer/main.d.ts +1 -0
- package/dist/viewer/main.js +121 -0
- package/dist/viewer/main.js.map +1 -0
- package/dist/viewer/messaging/call-rate-limiter.d.ts +50 -0
- package/dist/viewer/messaging/call-rate-limiter.js +103 -0
- package/dist/viewer/messaging/call-rate-limiter.js.map +1 -0
- package/dist/viewer/messaging/fetch-pipeline.d.ts +58 -0
- package/dist/viewer/messaging/fetch-pipeline.js +58 -0
- package/dist/viewer/messaging/fetch-pipeline.js.map +1 -0
- package/dist/viewer/messaging/index.d.ts +43 -0
- package/dist/viewer/messaging/index.js +46 -0
- package/dist/viewer/messaging/index.js.map +1 -0
- package/dist/viewer/messaging/message-coalescer.d.ts +96 -0
- package/dist/viewer/messaging/message-coalescer.js +121 -0
- package/dist/viewer/messaging/message-coalescer.js.map +1 -0
- package/dist/viewer/messaging/message-throttle.d.ts +95 -0
- package/dist/viewer/messaging/message-throttle.js +147 -0
- package/dist/viewer/messaging/message-throttle.js.map +1 -0
- package/dist/viewer/messaging/request-dedup.d.ts +43 -0
- package/dist/viewer/messaging/request-dedup.js +55 -0
- package/dist/viewer/messaging/request-dedup.js.map +1 -0
- package/dist/viewer/messaging/ws-pipeline.d.ts +85 -0
- package/dist/viewer/messaging/ws-pipeline.js +68 -0
- package/dist/viewer/messaging/ws-pipeline.js.map +1 -0
- package/dist/viewer/n-dx.png +0 -0
- package/dist/viewer/performance/dom-performance-monitor.d.ts +157 -0
- package/dist/viewer/performance/dom-performance-monitor.js +341 -0
- package/dist/viewer/performance/dom-performance-monitor.js.map +1 -0
- package/dist/viewer/performance/dom-update-gate.d.ts +122 -0
- package/dist/viewer/performance/dom-update-gate.js +229 -0
- package/dist/viewer/performance/dom-update-gate.js.map +1 -0
- package/dist/viewer/performance/graceful-degradation.d.ts +73 -0
- package/dist/viewer/performance/graceful-degradation.js +152 -0
- package/dist/viewer/performance/graceful-degradation.js.map +1 -0
- package/dist/viewer/performance/index.d.ts +14 -0
- package/dist/viewer/performance/index.js +20 -0
- package/dist/viewer/performance/index.js.map +1 -0
- package/dist/viewer/performance/memory-monitor.d.ts +78 -0
- package/dist/viewer/performance/memory-monitor.js +218 -0
- package/dist/viewer/performance/memory-monitor.js.map +1 -0
- package/dist/viewer/performance/refresh-throttle.d.ts +90 -0
- package/dist/viewer/performance/refresh-throttle.js +266 -0
- package/dist/viewer/performance/refresh-throttle.js.map +1 -0
- package/dist/viewer/performance/response-buffer-gate.d.ts +108 -0
- package/dist/viewer/performance/response-buffer-gate.js +170 -0
- package/dist/viewer/performance/response-buffer-gate.js.map +1 -0
- package/dist/viewer/performance/update-batcher.d.ts +79 -0
- package/dist/viewer/performance/update-batcher.js +119 -0
- package/dist/viewer/performance/update-batcher.js.map +1 -0
- package/dist/viewer/polling/batched-tick-dispatcher.d.ts +83 -0
- package/dist/viewer/polling/batched-tick-dispatcher.js +183 -0
- package/dist/viewer/polling/batched-tick-dispatcher.js.map +1 -0
- package/dist/viewer/polling/index.d.ts +13 -0
- package/dist/viewer/polling/index.js +16 -0
- package/dist/viewer/polling/index.js.map +1 -0
- package/dist/viewer/polling/polling-manager.d.ts +82 -0
- package/dist/viewer/polling/polling-manager.js +254 -0
- package/dist/viewer/polling/polling-manager.js.map +1 -0
- package/dist/viewer/polling/polling-restart.d.ts +45 -0
- package/dist/viewer/polling/polling-restart.js +98 -0
- package/dist/viewer/polling/polling-restart.js.map +1 -0
- package/dist/viewer/polling/polling-state.d.ts +182 -0
- package/dist/viewer/polling/polling-state.js +306 -0
- package/dist/viewer/polling/polling-state.js.map +1 -0
- package/dist/viewer/polling/tab-visibility.d.ts +112 -0
- package/dist/viewer/polling/tab-visibility.js +276 -0
- package/dist/viewer/polling/tab-visibility.js.map +1 -0
- package/dist/viewer/polling/tick-timer.d.ts +70 -0
- package/dist/viewer/polling/tick-timer.js +168 -0
- package/dist/viewer/polling/tick-timer.js.map +1 -0
- package/dist/viewer/polling/tick-visibility-gate.d.ts +92 -0
- package/dist/viewer/polling/tick-visibility-gate.js +146 -0
- package/dist/viewer/polling/tick-visibility-gate.js.map +1 -0
- package/dist/viewer/route-state.d.ts +8 -0
- package/dist/viewer/route-state.js +77 -0
- package/dist/viewer/route-state.js.map +1 -0
- package/dist/viewer/schema-compat.d.ts +17 -0
- package/dist/viewer/schema-compat.js +49 -0
- package/dist/viewer/schema-compat.js.map +1 -0
- package/dist/viewer/types.d.ts +66 -0
- package/dist/viewer/types.js +2 -0
- package/dist/viewer/types.js.map +1 -0
- package/dist/viewer/usage/constants.d.ts +14 -0
- package/dist/viewer/usage/constants.js +14 -0
- package/dist/viewer/usage/constants.js.map +1 -0
- package/dist/viewer/usage/index.d.ts +7 -0
- package/dist/viewer/usage/index.js +8 -0
- package/dist/viewer/usage/index.js.map +1 -0
- package/dist/viewer/utils.d.ts +25 -0
- package/dist/viewer/utils.js +48 -0
- package/dist/viewer/utils.js.map +1 -0
- package/dist/viewer/validate.d.ts +23 -0
- package/dist/viewer/validate.js +275 -0
- package/dist/viewer/validate.js.map +1 -0
- package/dist/viewer/views/analysis.d.ts +10 -0
- package/dist/viewer/views/analysis.js +109 -0
- package/dist/viewer/views/analysis.js.map +1 -0
- package/dist/viewer/views/architecture.d.ts +10 -0
- package/dist/viewer/views/architecture.js +44 -0
- package/dist/viewer/views/architecture.js.map +1 -0
- package/dist/viewer/views/domain-hench.d.ts +13 -0
- package/dist/viewer/views/domain-hench.js +14 -0
- package/dist/viewer/views/domain-hench.js.map +1 -0
- package/dist/viewer/views/domain-rex.d.ts +17 -0
- package/dist/viewer/views/domain-rex.js +18 -0
- package/dist/viewer/views/domain-rex.js.map +1 -0
- package/dist/viewer/views/domain-settings.d.ts +12 -0
- package/dist/viewer/views/domain-settings.js +13 -0
- package/dist/viewer/views/domain-settings.js.map +1 -0
- package/dist/viewer/views/domain-sourcevision.d.ts +20 -0
- package/dist/viewer/views/domain-sourcevision.js +21 -0
- package/dist/viewer/views/domain-sourcevision.js.map +1 -0
- package/dist/viewer/views/enrichment-thresholds.d.ts +11 -0
- package/dist/viewer/views/enrichment-thresholds.js +12 -0
- package/dist/viewer/views/enrichment-thresholds.js.map +1 -0
- package/dist/viewer/views/feature-toggles.d.ts +13 -0
- package/dist/viewer/views/feature-toggles.js +185 -0
- package/dist/viewer/views/feature-toggles.js.map +1 -0
- package/dist/viewer/views/files.d.ts +13 -0
- package/dist/viewer/views/files.js +174 -0
- package/dist/viewer/views/files.js.map +1 -0
- package/dist/viewer/views/graph.d.ts +12 -0
- package/dist/viewer/views/graph.js +316 -0
- package/dist/viewer/views/graph.js.map +1 -0
- package/dist/viewer/views/hench-config.d.ts +39 -0
- package/dist/viewer/views/hench-config.js +473 -0
- package/dist/viewer/views/hench-config.js.map +1 -0
- package/dist/viewer/views/hench-runs.d.ts +19 -0
- package/dist/viewer/views/hench-runs.js +460 -0
- package/dist/viewer/views/hench-runs.js.map +1 -0
- package/dist/viewer/views/hench-templates.d.ts +17 -0
- package/dist/viewer/views/hench-templates.js +262 -0
- package/dist/viewer/views/hench-templates.js.map +1 -0
- package/dist/viewer/views/integration-config.d.ts +73 -0
- package/dist/viewer/views/integration-config.js +524 -0
- package/dist/viewer/views/integration-config.js.map +1 -0
- package/dist/viewer/views/notion-config.d.ts +16 -0
- package/dist/viewer/views/notion-config.js +357 -0
- package/dist/viewer/views/notion-config.js.map +1 -0
- package/dist/viewer/views/overview.d.ts +10 -0
- package/dist/viewer/views/overview.js +187 -0
- package/dist/viewer/views/overview.js.map +1 -0
- package/dist/viewer/views/pr-markdown.d.ts +3 -0
- package/dist/viewer/views/pr-markdown.js +350 -0
- package/dist/viewer/views/pr-markdown.js.map +1 -0
- package/dist/viewer/views/prd.d.ts +34 -0
- package/dist/viewer/views/prd.js +257 -0
- package/dist/viewer/views/prd.js.map +1 -0
- package/dist/viewer/views/problems.d.ts +8 -0
- package/dist/viewer/views/problems.js +50 -0
- package/dist/viewer/views/problems.js.map +1 -0
- package/dist/viewer/views/rex-dashboard.d.ts +14 -0
- package/dist/viewer/views/rex-dashboard.js +334 -0
- package/dist/viewer/views/rex-dashboard.js.map +1 -0
- package/dist/viewer/views/routes.d.ts +8 -0
- package/dist/viewer/views/routes.js +216 -0
- package/dist/viewer/views/routes.js.map +1 -0
- package/dist/viewer/views/sourcevision-tabs.d.ts +18 -0
- package/dist/viewer/views/sourcevision-tabs.js +14 -0
- package/dist/viewer/views/sourcevision-tabs.js.map +1 -0
- package/dist/viewer/views/suggestions.d.ts +8 -0
- package/dist/viewer/views/suggestions.js +36 -0
- package/dist/viewer/views/suggestions.js.map +1 -0
- package/dist/viewer/views/task-audit.d.ts +18 -0
- package/dist/viewer/views/task-audit.js +413 -0
- package/dist/viewer/views/task-audit.js.map +1 -0
- package/dist/viewer/views/token-usage.d.ts +10 -0
- package/dist/viewer/views/token-usage.js +410 -0
- package/dist/viewer/views/token-usage.js.map +1 -0
- package/dist/viewer/views/validation.d.ts +11 -0
- package/dist/viewer/views/validation.js +475 -0
- package/dist/viewer/views/validation.js.map +1 -0
- package/dist/viewer/views/view-registry.d.ts +27 -0
- package/dist/viewer/views/view-registry.js +70 -0
- package/dist/viewer/views/view-registry.js.map +1 -0
- package/dist/viewer/views/workflow-optimization.d.ts +12 -0
- package/dist/viewer/views/workflow-optimization.js +311 -0
- package/dist/viewer/views/workflow-optimization.js.map +1 -0
- package/dist/viewer/views/zone-types.d.ts +69 -0
- package/dist/viewer/views/zone-types.js +5 -0
- package/dist/viewer/views/zone-types.js.map +1 -0
- package/dist/viewer/views/zones.d.ts +50 -0
- package/dist/viewer/views/zones.js +1438 -0
- package/dist/viewer/views/zones.js.map +1 -0
- package/dist/viewer/visualization/colors.d.ts +16 -0
- package/dist/viewer/visualization/colors.js +31 -0
- package/dist/viewer/visualization/colors.js.map +1 -0
- package/dist/viewer/visualization/flow.d.ts +54 -0
- package/dist/viewer/visualization/flow.js +123 -0
- package/dist/viewer/visualization/flow.js.map +1 -0
- package/dist/viewer/visualization/index.d.ts +34 -0
- package/dist/viewer/visualization/index.js +40 -0
- package/dist/viewer/visualization/index.js.map +1 -0
- package/dist/viewer/visualization/metrics.d.ts +8 -0
- package/dist/viewer/visualization/metrics.js +16 -0
- package/dist/viewer/visualization/metrics.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,723 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Notion integration configuration API routes.
|
|
3
|
+
*
|
|
4
|
+
* Manages Notion API credentials (token + database ID) through the
|
|
5
|
+
* adapter registry, validates connection health, validates the database
|
|
6
|
+
* schema, and provides configuration endpoints for the dashboard UI.
|
|
7
|
+
*
|
|
8
|
+
* Credentials are stored via the adapter registry's redaction mechanism:
|
|
9
|
+
* sensitive fields (token) are replaced with `{ __redacted, envVar, hint }`
|
|
10
|
+
* in `.rex/adapters.json`, and the real value must be provided via
|
|
11
|
+
* environment variable at runtime.
|
|
12
|
+
*
|
|
13
|
+
* GET /api/notion/config — current Notion adapter config (masked)
|
|
14
|
+
* PUT /api/notion/config — save/update Notion adapter config
|
|
15
|
+
* POST /api/notion/test — test connection to Notion API
|
|
16
|
+
* POST /api/notion/schema — validate database schema for PRD mapping
|
|
17
|
+
* POST /api/notion/schema/fix — create missing properties in database
|
|
18
|
+
* DELETE /api/notion/config — remove Notion adapter config
|
|
19
|
+
*/
|
|
20
|
+
import { existsSync } from "node:fs";
|
|
21
|
+
import { jsonResponse, errorResponse, readBody } from "./types.js";
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Validation helpers
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
/**
|
|
26
|
+
* Validate Notion API key format.
|
|
27
|
+
*
|
|
28
|
+
* Notion integration tokens start with `secret_` or `ntn_` and are
|
|
29
|
+
* typically 50+ characters long.
|
|
30
|
+
*/
|
|
31
|
+
function validateApiKeyFormat(token) {
|
|
32
|
+
if (!token || token.trim().length === 0) {
|
|
33
|
+
return "API key is required";
|
|
34
|
+
}
|
|
35
|
+
const trimmed = token.trim();
|
|
36
|
+
if (!trimmed.startsWith("secret_") && !trimmed.startsWith("ntn_")) {
|
|
37
|
+
return "API key must start with 'secret_' or 'ntn_'";
|
|
38
|
+
}
|
|
39
|
+
if (trimmed.length < 20) {
|
|
40
|
+
return "API key appears too short";
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Validate Notion database ID format.
|
|
46
|
+
*
|
|
47
|
+
* Database IDs are UUIDs (with or without hyphens), 32 hex chars.
|
|
48
|
+
*/
|
|
49
|
+
function validateDatabaseIdFormat(id) {
|
|
50
|
+
if (!id || id.trim().length === 0) {
|
|
51
|
+
return "Database ID is required";
|
|
52
|
+
}
|
|
53
|
+
const trimmed = id.trim().replace(/-/g, "");
|
|
54
|
+
if (!/^[0-9a-f]{32}$/i.test(trimmed)) {
|
|
55
|
+
return "Database ID must be a valid UUID (32 hex characters)";
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Mask an API key for display: show first 8 and last 4 chars.
|
|
61
|
+
*/
|
|
62
|
+
function maskApiKey(token) {
|
|
63
|
+
if (token.length <= 12)
|
|
64
|
+
return "****";
|
|
65
|
+
return token.slice(0, 8) + "****" + token.slice(-4);
|
|
66
|
+
}
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
// Notion API test helper
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
const NOTION_API = "https://api.notion.com/v1";
|
|
71
|
+
const NOTION_VERSION = "2022-06-28";
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
// Schema validation types
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
/**
|
|
76
|
+
* Expected database properties for PRD mapping.
|
|
77
|
+
*
|
|
78
|
+
* Mirrors DATABASE_SCHEMA from rex's notion-map.ts. Defined here locally
|
|
79
|
+
* to avoid a compile-time import (rex is dynamically imported only for
|
|
80
|
+
* the adapter registry).
|
|
81
|
+
*/
|
|
82
|
+
const REQUIRED_PROPERTIES = {
|
|
83
|
+
Name: "title",
|
|
84
|
+
Status: "status",
|
|
85
|
+
Level: "select",
|
|
86
|
+
"PRD ID": "rich_text",
|
|
87
|
+
};
|
|
88
|
+
const OPTIONAL_PROPERTIES = {
|
|
89
|
+
Description: "rich_text",
|
|
90
|
+
Priority: "select",
|
|
91
|
+
Tags: "multi_select",
|
|
92
|
+
Source: "rich_text",
|
|
93
|
+
"Blocked By": "rich_text",
|
|
94
|
+
"Started At": "rich_text",
|
|
95
|
+
"Completed At": "rich_text",
|
|
96
|
+
};
|
|
97
|
+
/** All expected properties (required + optional). */
|
|
98
|
+
const ALL_PROPERTIES = {
|
|
99
|
+
...REQUIRED_PROPERTIES,
|
|
100
|
+
...OPTIONAL_PROPERTIES,
|
|
101
|
+
};
|
|
102
|
+
/** Properties that can be created via the Notion API (Status cannot). */
|
|
103
|
+
const CREATABLE_TYPES = new Set(["rich_text", "select", "multi_select"]);
|
|
104
|
+
/**
|
|
105
|
+
* Validate a Notion database's property schema against the expected
|
|
106
|
+
* PRD property structure. Returns per-property diagnostics.
|
|
107
|
+
*/
|
|
108
|
+
async function validateNotionSchema(token, databaseId) {
|
|
109
|
+
// Fetch the database to inspect its properties
|
|
110
|
+
let dbData;
|
|
111
|
+
try {
|
|
112
|
+
const dbRes = await fetch(`${NOTION_API}/databases/${databaseId}`, {
|
|
113
|
+
headers: {
|
|
114
|
+
Authorization: `Bearer ${token}`,
|
|
115
|
+
"Notion-Version": NOTION_VERSION,
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
if (!dbRes.ok) {
|
|
119
|
+
if (dbRes.status === 401) {
|
|
120
|
+
return {
|
|
121
|
+
status: "red",
|
|
122
|
+
message: "Invalid API key. Check your Notion integration token.",
|
|
123
|
+
details: { authValid: false, databaseAccessible: false },
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
if (dbRes.status === 404) {
|
|
127
|
+
return {
|
|
128
|
+
status: "red",
|
|
129
|
+
message: "Database not found. Check the database ID and ensure your integration has access.",
|
|
130
|
+
details: { authValid: true, databaseAccessible: false },
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
const text = await dbRes.text().catch(() => "");
|
|
134
|
+
return {
|
|
135
|
+
status: "red",
|
|
136
|
+
message: `Cannot access database (${dbRes.status}): ${text.slice(0, 200)}`,
|
|
137
|
+
details: { authValid: true, databaseAccessible: false },
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
dbData = await dbRes.json();
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
return {
|
|
144
|
+
status: "red",
|
|
145
|
+
message: `Cannot reach Notion API: ${err instanceof Error ? err.message : String(err)}`,
|
|
146
|
+
details: { authValid: false, databaseAccessible: false },
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
const databaseTitle = dbData.title?.[0]?.plain_text ?? "Untitled";
|
|
150
|
+
const dbProps = dbData.properties ?? {};
|
|
151
|
+
const properties = [];
|
|
152
|
+
let ok = 0;
|
|
153
|
+
let missing = 0;
|
|
154
|
+
let wrongType = 0;
|
|
155
|
+
let fixable = 0;
|
|
156
|
+
for (const [name, expectedType] of Object.entries(ALL_PROPERTIES)) {
|
|
157
|
+
const isRequired = name in REQUIRED_PROPERTIES;
|
|
158
|
+
const dbProp = dbProps[name];
|
|
159
|
+
if (!dbProp) {
|
|
160
|
+
const canAutoCreate = CREATABLE_TYPES.has(expectedType);
|
|
161
|
+
let guidance;
|
|
162
|
+
if (expectedType === "status") {
|
|
163
|
+
guidance = "The Status property must be created manually in Notion. Open your database, click + to add a property, and select \"Status\" as the type.";
|
|
164
|
+
}
|
|
165
|
+
else if (expectedType === "title") {
|
|
166
|
+
guidance = "Every Notion database has a Title property. It may have been renamed. Ensure a property named \"Name\" exists with type \"Title\".";
|
|
167
|
+
}
|
|
168
|
+
else if (canAutoCreate) {
|
|
169
|
+
guidance = "This property can be created automatically using the \"Fix Missing Properties\" button.";
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
guidance = `Add a property named "${name}" with type "${expectedType}" in your Notion database.`;
|
|
173
|
+
}
|
|
174
|
+
properties.push({
|
|
175
|
+
name,
|
|
176
|
+
expectedType,
|
|
177
|
+
actualType: null,
|
|
178
|
+
required: isRequired,
|
|
179
|
+
status: "missing",
|
|
180
|
+
canAutoCreate,
|
|
181
|
+
guidance,
|
|
182
|
+
});
|
|
183
|
+
missing++;
|
|
184
|
+
if (canAutoCreate)
|
|
185
|
+
fixable++;
|
|
186
|
+
}
|
|
187
|
+
else if (dbProp.type !== expectedType) {
|
|
188
|
+
properties.push({
|
|
189
|
+
name,
|
|
190
|
+
expectedType,
|
|
191
|
+
actualType: dbProp.type,
|
|
192
|
+
required: isRequired,
|
|
193
|
+
status: "wrong_type",
|
|
194
|
+
canAutoCreate: false,
|
|
195
|
+
guidance: `Property "${name}" has type "${dbProp.type}" but should be "${expectedType}". Delete the property and recreate it with the correct type in Notion.`,
|
|
196
|
+
});
|
|
197
|
+
wrongType++;
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
properties.push({
|
|
201
|
+
name,
|
|
202
|
+
expectedType,
|
|
203
|
+
actualType: dbProp.type,
|
|
204
|
+
required: isRequired,
|
|
205
|
+
status: "ok",
|
|
206
|
+
canAutoCreate: false,
|
|
207
|
+
});
|
|
208
|
+
ok++;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// Sort: required first, then by status (missing → wrong_type → ok), then by name
|
|
212
|
+
const statusOrder = { missing: 0, wrong_type: 1, ok: 2 };
|
|
213
|
+
properties.sort((a, b) => {
|
|
214
|
+
if (a.required !== b.required)
|
|
215
|
+
return a.required ? -1 : 1;
|
|
216
|
+
const sa = statusOrder[a.status];
|
|
217
|
+
const sb = statusOrder[b.status];
|
|
218
|
+
if (sa !== sb)
|
|
219
|
+
return sa - sb;
|
|
220
|
+
return a.name.localeCompare(b.name);
|
|
221
|
+
});
|
|
222
|
+
const valid = properties
|
|
223
|
+
.filter((p) => p.required)
|
|
224
|
+
.every((p) => p.status === "ok");
|
|
225
|
+
return {
|
|
226
|
+
valid,
|
|
227
|
+
databaseTitle,
|
|
228
|
+
properties,
|
|
229
|
+
summary: {
|
|
230
|
+
total: properties.length,
|
|
231
|
+
ok,
|
|
232
|
+
missing,
|
|
233
|
+
wrongType,
|
|
234
|
+
fixable,
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Create missing properties in the Notion database.
|
|
240
|
+
*
|
|
241
|
+
* Only creates properties whose type is in CREATABLE_TYPES.
|
|
242
|
+
* Status and Title properties cannot be created via the API.
|
|
243
|
+
*/
|
|
244
|
+
async function createMissingProperties(token, databaseId, propertyNames) {
|
|
245
|
+
const created = [];
|
|
246
|
+
const failed = [];
|
|
247
|
+
// Build a single update payload with all properties to create
|
|
248
|
+
const propertiesToCreate = {};
|
|
249
|
+
for (const name of propertyNames) {
|
|
250
|
+
const expectedType = ALL_PROPERTIES[name];
|
|
251
|
+
if (!expectedType) {
|
|
252
|
+
failed.push({ name, error: `Unknown property "${name}"` });
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
if (!CREATABLE_TYPES.has(expectedType)) {
|
|
256
|
+
failed.push({
|
|
257
|
+
name,
|
|
258
|
+
error: `Property type "${expectedType}" cannot be created via the API. Create it manually in Notion.`,
|
|
259
|
+
});
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
// Build the property schema for the Notion API
|
|
263
|
+
if (expectedType === "rich_text") {
|
|
264
|
+
propertiesToCreate[name] = { rich_text: {} };
|
|
265
|
+
}
|
|
266
|
+
else if (expectedType === "select") {
|
|
267
|
+
// Pre-populate select options where applicable
|
|
268
|
+
if (name === "Level") {
|
|
269
|
+
propertiesToCreate[name] = {
|
|
270
|
+
select: {
|
|
271
|
+
options: [
|
|
272
|
+
{ name: "epic", color: "purple" },
|
|
273
|
+
{ name: "feature", color: "blue" },
|
|
274
|
+
{ name: "task", color: "green" },
|
|
275
|
+
{ name: "subtask", color: "gray" },
|
|
276
|
+
],
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
else if (name === "Priority") {
|
|
281
|
+
propertiesToCreate[name] = {
|
|
282
|
+
select: {
|
|
283
|
+
options: [
|
|
284
|
+
{ name: "Critical", color: "red" },
|
|
285
|
+
{ name: "High", color: "orange" },
|
|
286
|
+
{ name: "Medium", color: "yellow" },
|
|
287
|
+
{ name: "Low", color: "gray" },
|
|
288
|
+
],
|
|
289
|
+
},
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
propertiesToCreate[name] = { select: {} };
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
else if (expectedType === "multi_select") {
|
|
297
|
+
propertiesToCreate[name] = { multi_select: {} };
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
if (Object.keys(propertiesToCreate).length === 0) {
|
|
301
|
+
return { created, failed };
|
|
302
|
+
}
|
|
303
|
+
try {
|
|
304
|
+
const updateRes = await fetch(`${NOTION_API}/databases/${databaseId}`, {
|
|
305
|
+
method: "PATCH",
|
|
306
|
+
headers: {
|
|
307
|
+
Authorization: `Bearer ${token}`,
|
|
308
|
+
"Notion-Version": NOTION_VERSION,
|
|
309
|
+
"Content-Type": "application/json",
|
|
310
|
+
},
|
|
311
|
+
body: JSON.stringify({ properties: propertiesToCreate }),
|
|
312
|
+
});
|
|
313
|
+
if (!updateRes.ok) {
|
|
314
|
+
const text = await updateRes.text().catch(() => "");
|
|
315
|
+
// All properties failed
|
|
316
|
+
for (const name of Object.keys(propertiesToCreate)) {
|
|
317
|
+
failed.push({
|
|
318
|
+
name,
|
|
319
|
+
error: `Notion API error (${updateRes.status}): ${text.slice(0, 200)}`,
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
created.push(...Object.keys(propertiesToCreate));
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
catch (err) {
|
|
328
|
+
for (const name of Object.keys(propertiesToCreate)) {
|
|
329
|
+
failed.push({
|
|
330
|
+
name,
|
|
331
|
+
error: err instanceof Error ? err.message : String(err),
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return { created, failed };
|
|
336
|
+
}
|
|
337
|
+
async function testNotionConnection(token, databaseId) {
|
|
338
|
+
// Step 1: Test API key validity by fetching the bot user
|
|
339
|
+
try {
|
|
340
|
+
const userRes = await fetch(`${NOTION_API}/users/me`, {
|
|
341
|
+
headers: {
|
|
342
|
+
Authorization: `Bearer ${token}`,
|
|
343
|
+
"Notion-Version": NOTION_VERSION,
|
|
344
|
+
},
|
|
345
|
+
});
|
|
346
|
+
if (!userRes.ok) {
|
|
347
|
+
const text = await userRes.text().catch(() => "");
|
|
348
|
+
if (userRes.status === 401) {
|
|
349
|
+
return {
|
|
350
|
+
status: "red",
|
|
351
|
+
message: "Invalid API key. Check your Notion integration token.",
|
|
352
|
+
details: { authValid: false, databaseAccessible: false },
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
return {
|
|
356
|
+
status: "red",
|
|
357
|
+
message: `Notion API error (${userRes.status}): ${text.slice(0, 200)}`,
|
|
358
|
+
details: { authValid: false, databaseAccessible: false },
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
catch (err) {
|
|
363
|
+
return {
|
|
364
|
+
status: "red",
|
|
365
|
+
message: `Cannot reach Notion API: ${err instanceof Error ? err.message : String(err)}`,
|
|
366
|
+
details: { authValid: false, databaseAccessible: false },
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
// Step 2: Test database access
|
|
370
|
+
try {
|
|
371
|
+
const dbRes = await fetch(`${NOTION_API}/databases/${databaseId}`, {
|
|
372
|
+
headers: {
|
|
373
|
+
Authorization: `Bearer ${token}`,
|
|
374
|
+
"Notion-Version": NOTION_VERSION,
|
|
375
|
+
},
|
|
376
|
+
});
|
|
377
|
+
if (!dbRes.ok) {
|
|
378
|
+
if (dbRes.status === 404) {
|
|
379
|
+
return {
|
|
380
|
+
status: "yellow",
|
|
381
|
+
message: "API key is valid, but the database was not found. Check the database ID and ensure your integration has access.",
|
|
382
|
+
details: { authValid: true, databaseAccessible: false },
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
const text = await dbRes.text().catch(() => "");
|
|
386
|
+
return {
|
|
387
|
+
status: "yellow",
|
|
388
|
+
message: `API key is valid, but database access failed (${dbRes.status}): ${text.slice(0, 200)}`,
|
|
389
|
+
details: { authValid: true, databaseAccessible: false },
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
const db = await dbRes.json();
|
|
393
|
+
const dbTitle = db.title?.[0]?.plain_text ?? "Untitled";
|
|
394
|
+
// Step 3: Quick query to verify read access and get page count
|
|
395
|
+
let pageCount = 0;
|
|
396
|
+
try {
|
|
397
|
+
const queryRes = await fetch(`${NOTION_API}/databases/${databaseId}/query`, {
|
|
398
|
+
method: "POST",
|
|
399
|
+
headers: {
|
|
400
|
+
Authorization: `Bearer ${token}`,
|
|
401
|
+
"Notion-Version": NOTION_VERSION,
|
|
402
|
+
"Content-Type": "application/json",
|
|
403
|
+
},
|
|
404
|
+
body: JSON.stringify({ page_size: 1 }),
|
|
405
|
+
});
|
|
406
|
+
if (queryRes.ok) {
|
|
407
|
+
const queryData = await queryRes.json();
|
|
408
|
+
pageCount = queryData.results?.length ?? 0;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
catch {
|
|
412
|
+
// Non-fatal: we already confirmed database access
|
|
413
|
+
}
|
|
414
|
+
return {
|
|
415
|
+
status: "green",
|
|
416
|
+
message: `Connected to "${dbTitle}"`,
|
|
417
|
+
details: {
|
|
418
|
+
authValid: true,
|
|
419
|
+
databaseAccessible: true,
|
|
420
|
+
databaseTitle: dbTitle,
|
|
421
|
+
pageCount,
|
|
422
|
+
},
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
catch (err) {
|
|
426
|
+
return {
|
|
427
|
+
status: "yellow",
|
|
428
|
+
message: `API key is valid, but database check failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
429
|
+
details: { authValid: true, databaseAccessible: false },
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
// ---------------------------------------------------------------------------
|
|
434
|
+
// Adapter registry interaction (dynamic import to avoid coupling)
|
|
435
|
+
// ---------------------------------------------------------------------------
|
|
436
|
+
/**
|
|
437
|
+
* Dynamically load the adapter registry from the rex package.
|
|
438
|
+
*
|
|
439
|
+
* This avoids a hard compile-time dependency on rex from the web package.
|
|
440
|
+
* The web package's gateway (domain-gateway.ts) handles MCP server factories;
|
|
441
|
+
* for adapter config we use a lightweight dynamic import.
|
|
442
|
+
*/
|
|
443
|
+
async function loadRegistry() {
|
|
444
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
445
|
+
const mod = await import("@n-dx/rex/dist/store/adapter-registry.js");
|
|
446
|
+
return mod;
|
|
447
|
+
}
|
|
448
|
+
// ---------------------------------------------------------------------------
|
|
449
|
+
// Route handler
|
|
450
|
+
// ---------------------------------------------------------------------------
|
|
451
|
+
/** Handle Notion config API requests. Returns true if the request was handled. */
|
|
452
|
+
export async function handleNotionRoute(req, res, ctx) {
|
|
453
|
+
const url = req.url || "/";
|
|
454
|
+
const method = req.method || "GET";
|
|
455
|
+
// Only handle /api/notion/* routes
|
|
456
|
+
if (!url.startsWith("/api/notion/"))
|
|
457
|
+
return false;
|
|
458
|
+
// Check .rex/ exists
|
|
459
|
+
if (!existsSync(ctx.rexDir)) {
|
|
460
|
+
errorResponse(res, 404, "No .rex/ directory found. Run 'rex init' first.");
|
|
461
|
+
return true;
|
|
462
|
+
}
|
|
463
|
+
// ── GET /api/notion/config ──────────────────────────────────────────
|
|
464
|
+
if (method === "GET" && url === "/api/notion/config") {
|
|
465
|
+
try {
|
|
466
|
+
const { getDefaultRegistry, isRedactedField } = await loadRegistry();
|
|
467
|
+
const registry = getDefaultRegistry();
|
|
468
|
+
const adapterConfig = await registry.getAdapterConfig(ctx.rexDir, "notion");
|
|
469
|
+
if (!adapterConfig) {
|
|
470
|
+
jsonResponse(res, 200, {
|
|
471
|
+
configured: false,
|
|
472
|
+
token: null,
|
|
473
|
+
databaseId: null,
|
|
474
|
+
tokenMasked: null,
|
|
475
|
+
tokenEnvVar: null,
|
|
476
|
+
});
|
|
477
|
+
return true;
|
|
478
|
+
}
|
|
479
|
+
// Extract config, masking sensitive fields
|
|
480
|
+
const config = adapterConfig.config;
|
|
481
|
+
let tokenMasked = null;
|
|
482
|
+
let tokenEnvVar = null;
|
|
483
|
+
let databaseId = null;
|
|
484
|
+
if (isRedactedField(config.token)) {
|
|
485
|
+
tokenMasked = config.token.hint;
|
|
486
|
+
tokenEnvVar = config.token.envVar;
|
|
487
|
+
}
|
|
488
|
+
else if (typeof config.token === "string") {
|
|
489
|
+
tokenMasked = maskApiKey(config.token);
|
|
490
|
+
}
|
|
491
|
+
if (typeof config.databaseId === "string") {
|
|
492
|
+
databaseId = config.databaseId;
|
|
493
|
+
}
|
|
494
|
+
jsonResponse(res, 200, {
|
|
495
|
+
configured: true,
|
|
496
|
+
token: null, // Never expose raw token
|
|
497
|
+
databaseId,
|
|
498
|
+
tokenMasked,
|
|
499
|
+
tokenEnvVar,
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
catch (err) {
|
|
503
|
+
errorResponse(res, 500, err instanceof Error ? err.message : "Failed to load config");
|
|
504
|
+
}
|
|
505
|
+
return true;
|
|
506
|
+
}
|
|
507
|
+
// ── PUT /api/notion/config ──────────────────────────────────────────
|
|
508
|
+
if (method === "PUT" && url === "/api/notion/config") {
|
|
509
|
+
try {
|
|
510
|
+
const body = await readBody(req);
|
|
511
|
+
const data = JSON.parse(body);
|
|
512
|
+
// Validate fields
|
|
513
|
+
const errors = {};
|
|
514
|
+
if (data.token !== undefined) {
|
|
515
|
+
const tokenErr = validateApiKeyFormat(data.token);
|
|
516
|
+
if (tokenErr)
|
|
517
|
+
errors.token = tokenErr;
|
|
518
|
+
}
|
|
519
|
+
if (data.databaseId !== undefined) {
|
|
520
|
+
const dbErr = validateDatabaseIdFormat(data.databaseId);
|
|
521
|
+
if (dbErr)
|
|
522
|
+
errors.databaseId = dbErr;
|
|
523
|
+
}
|
|
524
|
+
if (Object.keys(errors).length > 0) {
|
|
525
|
+
jsonResponse(res, 400, { error: "Validation failed", errors });
|
|
526
|
+
return true;
|
|
527
|
+
}
|
|
528
|
+
// Load existing config and merge
|
|
529
|
+
const { getDefaultRegistry } = await loadRegistry();
|
|
530
|
+
const registry = getDefaultRegistry();
|
|
531
|
+
const existing = await registry.getAdapterConfig(ctx.rexDir, "notion");
|
|
532
|
+
const existingConfig = existing?.config ?? {};
|
|
533
|
+
const newConfig = { ...existingConfig };
|
|
534
|
+
if (data.token !== undefined)
|
|
535
|
+
newConfig.token = data.token.trim();
|
|
536
|
+
if (data.databaseId !== undefined)
|
|
537
|
+
newConfig.databaseId = data.databaseId.trim().replace(/-/g, "");
|
|
538
|
+
// Save via adapter registry (handles redaction automatically)
|
|
539
|
+
await registry.saveAdapterConfig(ctx.rexDir, {
|
|
540
|
+
name: "notion",
|
|
541
|
+
config: newConfig,
|
|
542
|
+
});
|
|
543
|
+
jsonResponse(res, 200, {
|
|
544
|
+
saved: true,
|
|
545
|
+
tokenMasked: typeof newConfig.token === "string" ? maskApiKey(newConfig.token) : null,
|
|
546
|
+
databaseId: newConfig.databaseId ?? null,
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
catch (err) {
|
|
550
|
+
errorResponse(res, 500, err instanceof Error ? err.message : "Failed to save config");
|
|
551
|
+
}
|
|
552
|
+
return true;
|
|
553
|
+
}
|
|
554
|
+
// ── DELETE /api/notion/config ───────────────────────────────────────
|
|
555
|
+
if (method === "DELETE" && url === "/api/notion/config") {
|
|
556
|
+
try {
|
|
557
|
+
const { getDefaultRegistry } = await loadRegistry();
|
|
558
|
+
const registry = getDefaultRegistry();
|
|
559
|
+
await registry.removeAdapterConfig(ctx.rexDir, "notion");
|
|
560
|
+
jsonResponse(res, 200, { removed: true });
|
|
561
|
+
}
|
|
562
|
+
catch (err) {
|
|
563
|
+
errorResponse(res, 500, err instanceof Error ? err.message : "Failed to remove config");
|
|
564
|
+
}
|
|
565
|
+
return true;
|
|
566
|
+
}
|
|
567
|
+
// ── POST /api/notion/test ───────────────────────────────────────────
|
|
568
|
+
if (method === "POST" && url === "/api/notion/test") {
|
|
569
|
+
try {
|
|
570
|
+
const body = await readBody(req);
|
|
571
|
+
const data = JSON.parse(body);
|
|
572
|
+
// If no token provided, try to use the stored one
|
|
573
|
+
let token = data.token?.trim();
|
|
574
|
+
let databaseId = data.databaseId?.trim();
|
|
575
|
+
if (!token || !databaseId) {
|
|
576
|
+
// Try to load from config + env
|
|
577
|
+
const { getDefaultRegistry, isRedactedField } = await loadRegistry();
|
|
578
|
+
const registry = getDefaultRegistry();
|
|
579
|
+
const existing = await registry.getAdapterConfig(ctx.rexDir, "notion");
|
|
580
|
+
if (existing) {
|
|
581
|
+
if (!token) {
|
|
582
|
+
const storedToken = existing.config.token;
|
|
583
|
+
if (isRedactedField(storedToken)) {
|
|
584
|
+
const envVal = process.env[storedToken.envVar];
|
|
585
|
+
if (envVal)
|
|
586
|
+
token = envVal;
|
|
587
|
+
}
|
|
588
|
+
else if (typeof storedToken === "string") {
|
|
589
|
+
token = storedToken;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
if (!databaseId && typeof existing.config.databaseId === "string") {
|
|
593
|
+
databaseId = existing.config.databaseId;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
if (!token) {
|
|
598
|
+
jsonResponse(res, 200, {
|
|
599
|
+
status: "red",
|
|
600
|
+
message: "No API key provided or configured. Enter a token to test.",
|
|
601
|
+
details: { authValid: false, databaseAccessible: false },
|
|
602
|
+
});
|
|
603
|
+
return true;
|
|
604
|
+
}
|
|
605
|
+
if (!databaseId) {
|
|
606
|
+
jsonResponse(res, 200, {
|
|
607
|
+
status: "red",
|
|
608
|
+
message: "No database ID provided or configured.",
|
|
609
|
+
details: { authValid: false, databaseAccessible: false },
|
|
610
|
+
});
|
|
611
|
+
return true;
|
|
612
|
+
}
|
|
613
|
+
const result = await testNotionConnection(token, databaseId);
|
|
614
|
+
jsonResponse(res, 200, result);
|
|
615
|
+
}
|
|
616
|
+
catch (err) {
|
|
617
|
+
errorResponse(res, 500, err instanceof Error ? err.message : "Test failed");
|
|
618
|
+
}
|
|
619
|
+
return true;
|
|
620
|
+
}
|
|
621
|
+
// ── POST /api/notion/schema ─────────────────────────────────────────
|
|
622
|
+
if (method === "POST" && url === "/api/notion/schema") {
|
|
623
|
+
try {
|
|
624
|
+
const body = await readBody(req);
|
|
625
|
+
const data = JSON.parse(body);
|
|
626
|
+
// Resolve credentials (same pattern as /test)
|
|
627
|
+
let token = data.token?.trim();
|
|
628
|
+
let databaseId = data.databaseId?.trim();
|
|
629
|
+
if (!token || !databaseId) {
|
|
630
|
+
const { getDefaultRegistry, isRedactedField } = await loadRegistry();
|
|
631
|
+
const registry = getDefaultRegistry();
|
|
632
|
+
const existing = await registry.getAdapterConfig(ctx.rexDir, "notion");
|
|
633
|
+
if (existing) {
|
|
634
|
+
if (!token) {
|
|
635
|
+
const storedToken = existing.config.token;
|
|
636
|
+
if (isRedactedField(storedToken)) {
|
|
637
|
+
const envVal = process.env[storedToken.envVar];
|
|
638
|
+
if (envVal)
|
|
639
|
+
token = envVal;
|
|
640
|
+
}
|
|
641
|
+
else if (typeof storedToken === "string") {
|
|
642
|
+
token = storedToken;
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
if (!databaseId && typeof existing.config.databaseId === "string") {
|
|
646
|
+
databaseId = existing.config.databaseId;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
if (!token) {
|
|
651
|
+
jsonResponse(res, 200, {
|
|
652
|
+
status: "red",
|
|
653
|
+
message: "No API key provided or configured. Save credentials first.",
|
|
654
|
+
details: { authValid: false, databaseAccessible: false },
|
|
655
|
+
});
|
|
656
|
+
return true;
|
|
657
|
+
}
|
|
658
|
+
if (!databaseId) {
|
|
659
|
+
jsonResponse(res, 200, {
|
|
660
|
+
status: "red",
|
|
661
|
+
message: "No database ID provided or configured.",
|
|
662
|
+
details: { authValid: false, databaseAccessible: false },
|
|
663
|
+
});
|
|
664
|
+
return true;
|
|
665
|
+
}
|
|
666
|
+
const result = await validateNotionSchema(token, databaseId);
|
|
667
|
+
jsonResponse(res, 200, result);
|
|
668
|
+
}
|
|
669
|
+
catch (err) {
|
|
670
|
+
errorResponse(res, 500, err instanceof Error ? err.message : "Schema validation failed");
|
|
671
|
+
}
|
|
672
|
+
return true;
|
|
673
|
+
}
|
|
674
|
+
// ── POST /api/notion/schema/fix ─────────────────────────────────────
|
|
675
|
+
if (method === "POST" && url === "/api/notion/schema/fix") {
|
|
676
|
+
try {
|
|
677
|
+
const body = await readBody(req);
|
|
678
|
+
const data = JSON.parse(body);
|
|
679
|
+
// Validate properties input before resolving credentials
|
|
680
|
+
const propertyNames = data.properties;
|
|
681
|
+
if (!propertyNames || propertyNames.length === 0) {
|
|
682
|
+
errorResponse(res, 400, "No properties specified to create.");
|
|
683
|
+
return true;
|
|
684
|
+
}
|
|
685
|
+
// Resolve credentials
|
|
686
|
+
let token = data.token?.trim();
|
|
687
|
+
let databaseId = data.databaseId?.trim();
|
|
688
|
+
if (!token || !databaseId) {
|
|
689
|
+
const { getDefaultRegistry, isRedactedField } = await loadRegistry();
|
|
690
|
+
const registry = getDefaultRegistry();
|
|
691
|
+
const existing = await registry.getAdapterConfig(ctx.rexDir, "notion");
|
|
692
|
+
if (existing) {
|
|
693
|
+
if (!token) {
|
|
694
|
+
const storedToken = existing.config.token;
|
|
695
|
+
if (isRedactedField(storedToken)) {
|
|
696
|
+
const envVal = process.env[storedToken.envVar];
|
|
697
|
+
if (envVal)
|
|
698
|
+
token = envVal;
|
|
699
|
+
}
|
|
700
|
+
else if (typeof storedToken === "string") {
|
|
701
|
+
token = storedToken;
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
if (!databaseId && typeof existing.config.databaseId === "string") {
|
|
705
|
+
databaseId = existing.config.databaseId;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
if (!token || !databaseId) {
|
|
710
|
+
errorResponse(res, 400, "Credentials not configured. Save token and database ID first.");
|
|
711
|
+
return true;
|
|
712
|
+
}
|
|
713
|
+
const result = await createMissingProperties(token, databaseId, propertyNames);
|
|
714
|
+
jsonResponse(res, 200, result);
|
|
715
|
+
}
|
|
716
|
+
catch (err) {
|
|
717
|
+
errorResponse(res, 500, err instanceof Error ? err.message : "Property creation failed");
|
|
718
|
+
}
|
|
719
|
+
return true;
|
|
720
|
+
}
|
|
721
|
+
return false;
|
|
722
|
+
}
|
|
723
|
+
//# sourceMappingURL=routes-notion.js.map
|