@contractspec/lib.contracts-spec 2.0.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/README.md +3 -0
- package/dist/app-config/app-config.capability.d.ts +1 -0
- package/dist/app-config/app-config.capability.js +730 -0
- package/dist/app-config/app-config.contracts.d.ts +239 -0
- package/dist/app-config/app-config.contracts.js +713 -0
- package/dist/app-config/app-config.contracts.test.d.ts +1 -0
- package/dist/app-config/app-config.feature.d.ts +5 -0
- package/dist/app-config/app-config.feature.js +255 -0
- package/dist/app-config/branding.d.ts +52 -0
- package/dist/app-config/branding.js +1 -0
- package/dist/app-config/branding.test.d.ts +1 -0
- package/dist/app-config/docs/app-config.docblock.d.ts +2 -0
- package/dist/app-config/docs/app-config.docblock.js +383 -0
- package/dist/app-config/events.d.ts +115 -0
- package/dist/app-config/events.js +386 -0
- package/dist/app-config/events.test.d.ts +1 -0
- package/dist/app-config/index.d.ts +9 -0
- package/dist/app-config/index.js +2899 -0
- package/dist/app-config/lifecycle-contracts.d.ts +265 -0
- package/dist/app-config/lifecycle-contracts.js +870 -0
- package/dist/app-config/lifecycle-contracts.test.d.ts +1 -0
- package/dist/app-config/lifecycle.d.ts +23 -0
- package/dist/app-config/lifecycle.js +1 -0
- package/dist/app-config/lifecycle.test.d.ts +1 -0
- package/dist/app-config/runtime.d.ts +111 -0
- package/dist/app-config/runtime.js +734 -0
- package/dist/app-config/runtime.test.d.ts +1 -0
- package/dist/app-config/spec.d.ts +169 -0
- package/dist/app-config/spec.js +229 -0
- package/dist/app-config/spec.test.d.ts +1 -0
- package/dist/app-config/validation.d.ts +43 -0
- package/dist/app-config/validation.js +650 -0
- package/dist/app-config/validation.test.d.ts +1 -0
- package/dist/capabilities/capabilities.d.ts +96 -0
- package/dist/capabilities/capabilities.js +217 -0
- package/dist/capabilities/capabilities.test.d.ts +1 -0
- package/dist/capabilities/context.d.ts +110 -0
- package/dist/capabilities/context.js +101 -0
- package/dist/capabilities/context.test.d.ts +1 -0
- package/dist/capabilities/docs/capabilities.docblock.d.ts +2 -0
- package/dist/capabilities/docs/capabilities.docblock.js +353 -0
- package/dist/capabilities/guards.d.ts +121 -0
- package/dist/capabilities/guards.js +177 -0
- package/dist/capabilities/index.d.ts +6 -0
- package/dist/capabilities/index.js +739 -0
- package/dist/capabilities/meeting-recorder.d.ts +5 -0
- package/dist/capabilities/meeting-recorder.js +154 -0
- package/dist/capabilities/openbanking.d.ts +5 -0
- package/dist/capabilities/openbanking.js +166 -0
- package/dist/capabilities/validation.d.ts +79 -0
- package/dist/capabilities/validation.js +185 -0
- package/dist/capabilities/validation.test.d.ts +1 -0
- package/dist/contract-registry/index.d.ts +3 -0
- package/dist/contract-registry/index.js +129 -0
- package/dist/contract-registry/schemas.d.ts +120 -0
- package/dist/contract-registry/schemas.js +129 -0
- package/dist/contract-registry/schemas.test.d.ts +1 -0
- package/dist/contract-registry/types.d.ts +42 -0
- package/dist/contract-registry/types.js +1 -0
- package/dist/data-views/data-views.d.ts +4 -0
- package/dist/data-views/data-views.js +232 -0
- package/dist/data-views/data-views.test.d.ts +1 -0
- package/dist/data-views/docs/data-views.docblock.d.ts +2 -0
- package/dist/data-views/docs/data-views.docblock.js +164 -0
- package/dist/data-views/index.d.ts +4 -0
- package/dist/data-views/index.js +232 -0
- package/dist/data-views/query-generator.d.ts +35 -0
- package/dist/data-views/query-generator.js +89 -0
- package/dist/data-views/registry.d.ts +12 -0
- package/dist/data-views/registry.js +226 -0
- package/dist/data-views/registry.test.d.ts +1 -0
- package/dist/data-views/report/contractVerificationTable.d.ts +4 -0
- package/dist/data-views/report/contractVerificationTable.js +240 -0
- package/dist/data-views/report/contractVerificationTable.test.d.ts +1 -0
- package/dist/data-views/runtime.d.ts +25 -0
- package/dist/data-views/runtime.js +108 -0
- package/dist/data-views/runtime.test.d.ts +1 -0
- package/dist/data-views/spec.d.ts +22 -0
- package/dist/data-views/spec.js +38 -0
- package/dist/data-views/spec.test.d.ts +1 -0
- package/dist/data-views/types.d.ts +152 -0
- package/dist/data-views/types.js +1 -0
- package/dist/data-views/types.test.d.ts +1 -0
- package/dist/docs/accessibility_wcag_compliance_specs.docblock.d.ts +2 -0
- package/dist/docs/accessibility_wcag_compliance_specs.docblock.js +513 -0
- package/dist/docs/capabilities/documentationSystem.capability.d.ts +1 -0
- package/dist/docs/capabilities/documentationSystem.capability.js +784 -0
- package/dist/docs/capabilities/index.d.ts +1 -0
- package/dist/docs/capabilities/index.js +784 -0
- package/dist/docs/commands/docsGenerate.command.d.ts +88 -0
- package/dist/docs/commands/docsGenerate.command.js +802 -0
- package/dist/docs/commands/docsPublish.command.d.ts +57 -0
- package/dist/docs/commands/docsPublish.command.js +781 -0
- package/dist/docs/commands/index.d.ts +2 -0
- package/dist/docs/commands/index.js +906 -0
- package/dist/docs/constants.d.ts +4 -0
- package/dist/docs/constants.js +78 -0
- package/dist/docs/contracts.d.ts +430 -0
- package/dist/docs/contracts.js +1611 -0
- package/dist/docs/ensure-docblocks.d.ts +1 -0
- package/dist/docs/ensure-docblocks.js +264 -0
- package/dist/docs/events/docsGenerated.event.d.ts +56 -0
- package/dist/docs/events/docsGenerated.event.js +533 -0
- package/dist/docs/events/docsPublished.event.d.ts +64 -0
- package/dist/docs/events/docsPublished.event.js +534 -0
- package/dist/docs/events/index.d.ts +2 -0
- package/dist/docs/events/index.js +567 -0
- package/dist/docs/forms/docsSearch.form.d.ts +16 -0
- package/dist/docs/forms/docsSearch.form.js +676 -0
- package/dist/docs/forms/index.d.ts +1 -0
- package/dist/docs/forms/index.js +676 -0
- package/dist/docs/index.d.ts +40 -0
- package/dist/docs/index.js +4719 -0
- package/dist/docs/meta.docs.d.ts +2 -0
- package/dist/docs/meta.docs.js +176 -0
- package/dist/docs/presentations/docsLayout.presentation.d.ts +2 -0
- package/dist/docs/presentations/docsLayout.presentation.js +527 -0
- package/dist/docs/presentations/docsReferencePage.presentation.d.ts +2 -0
- package/dist/docs/presentations/docsReferencePage.presentation.js +527 -0
- package/dist/docs/presentations/index.d.ts +2 -0
- package/dist/docs/presentations/index.js +555 -0
- package/dist/docs/presentations.d.ts +27 -0
- package/dist/docs/presentations.js +97 -0
- package/dist/docs/presentations.test.d.ts +1 -0
- package/dist/docs/queries/contractReference.query.d.ts +211 -0
- package/dist/docs/queries/contractReference.query.js +752 -0
- package/dist/docs/queries/docsIndex.query.d.ts +266 -0
- package/dist/docs/queries/docsIndex.query.js +752 -0
- package/dist/docs/queries/index.d.ts +2 -0
- package/dist/docs/queries/index.js +827 -0
- package/dist/docs/registry.d.ts +19 -0
- package/dist/docs/registry.js +153 -0
- package/dist/docs/registry.test.d.ts +1 -0
- package/dist/docs/tech/auth/better-auth-nextjs.docblock.d.ts +2 -0
- package/dist/docs/tech/auth/better-auth-nextjs.docblock.js +221 -0
- package/dist/docs/tech/cli.docblock.d.ts +2 -0
- package/dist/docs/tech/cli.docblock.js +291 -0
- package/dist/docs/tech/contracts/README.docblock.d.ts +2 -0
- package/dist/docs/tech/contracts/README.docblock.js +164 -0
- package/dist/docs/tech/contracts/migrations.docblock.d.ts +2 -0
- package/dist/docs/tech/contracts/migrations.docblock.js +164 -0
- package/dist/docs/tech/contracts/openapi-export.docblock.d.ts +2 -0
- package/dist/docs/tech/contracts/openapi-export.docblock.js +201 -0
- package/dist/docs/tech/contracts/openapi-import.docblock.d.ts +2 -0
- package/dist/docs/tech/contracts/openapi-import.docblock.js +207 -0
- package/dist/docs/tech/contracts/ops-to-presentation-linking.docblock.d.ts +2 -0
- package/dist/docs/tech/contracts/ops-to-presentation-linking.docblock.js +225 -0
- package/dist/docs/tech/contracts/overlays.docblock.d.ts +2 -0
- package/dist/docs/tech/contracts/overlays.docblock.js +231 -0
- package/dist/docs/tech/contracts/tests.docblock.d.ts +2 -0
- package/dist/docs/tech/contracts/tests.docblock.js +164 -0
- package/dist/docs/tech/contracts/themes.docblock.d.ts +2 -0
- package/dist/docs/tech/contracts/themes.docblock.js +257 -0
- package/dist/docs/tech/contracts/vertical-pocket-family-office.docblock.d.ts +2 -0
- package/dist/docs/tech/contracts/vertical-pocket-family-office.docblock.js +269 -0
- package/dist/docs/tech/docs-system.docblock.d.ts +1 -0
- package/dist/docs/tech/docs-system.docblock.js +264 -0
- package/dist/docs/tech/lifecycle-stage-system.docblock.d.ts +2 -0
- package/dist/docs/tech/lifecycle-stage-system.docblock.js +376 -0
- package/dist/docs/tech/llm/llm-integration.docblock.d.ts +7 -0
- package/dist/docs/tech/llm/llm-integration.docblock.js +482 -0
- package/dist/docs/tech/mcp-endpoints.docblock.d.ts +2 -0
- package/dist/docs/tech/mcp-endpoints.docblock.js +185 -0
- package/dist/docs/tech/presentation-runtime.docblock.d.ts +2 -0
- package/dist/docs/tech/presentation-runtime.docblock.js +221 -0
- package/dist/docs/tech/report-verification-table.docblock.d.ts +1 -0
- package/dist/docs/tech/report-verification-table.docblock.js +191 -0
- package/dist/docs/tech/report-verification-table.test.d.ts +1 -0
- package/dist/docs/tech/schema/README.docblock.d.ts +2 -0
- package/dist/docs/tech/schema/README.docblock.js +164 -0
- package/dist/docs/tech/studio/learning-events.docblock.d.ts +2 -0
- package/dist/docs/tech/studio/learning-events.docblock.js +190 -0
- package/dist/docs/tech/studio/learning-journeys.docblock.d.ts +2 -0
- package/dist/docs/tech/studio/learning-journeys.docblock.js +227 -0
- package/dist/docs/tech/studio/platform-admin-panel.docblock.d.ts +2 -0
- package/dist/docs/tech/studio/platform-admin-panel.docblock.js +226 -0
- package/dist/docs/tech/studio/project-access-teams.docblock.d.ts +2 -0
- package/dist/docs/tech/studio/project-access-teams.docblock.js +200 -0
- package/dist/docs/tech/studio/project-routing.docblock.d.ts +2 -0
- package/dist/docs/tech/studio/project-routing.docblock.js +209 -0
- package/dist/docs/tech/studio/sandbox-unlogged.docblock.d.ts +2 -0
- package/dist/docs/tech/studio/sandbox-unlogged.docblock.js +183 -0
- package/dist/docs/tech/studio/team-invitations.docblock.d.ts +2 -0
- package/dist/docs/tech/studio/team-invitations.docblock.js +228 -0
- package/dist/docs/tech/studio/workspace-ops.docblock.d.ts +2 -0
- package/dist/docs/tech/studio/workspace-ops.docblock.js +189 -0
- package/dist/docs/tech/studio/workspaces.docblock.d.ts +2 -0
- package/dist/docs/tech/studio/workspaces.docblock.js +204 -0
- package/dist/docs/tech/telemetry-ingest.docblock.d.ts +2 -0
- package/dist/docs/tech/telemetry-ingest.docblock.js +305 -0
- package/dist/docs/tech/vscode-extension.docblock.d.ts +2 -0
- package/dist/docs/tech/vscode-extension.docblock.js +241 -0
- package/dist/docs/tech-contracts.docs.d.ts +2 -0
- package/dist/docs/tech-contracts.docs.js +239 -0
- package/dist/docs/types.d.ts +37 -0
- package/dist/docs/types.js +1 -0
- package/dist/docs/views/contractReference.dataView.d.ts +2 -0
- package/dist/docs/views/contractReference.dataView.js +838 -0
- package/dist/docs/views/docsIndex.dataView.d.ts +2 -0
- package/dist/docs/views/docsIndex.dataView.js +832 -0
- package/dist/docs/views/exampleCatalog.dataView.d.ts +2 -0
- package/dist/docs/views/exampleCatalog.dataView.js +816 -0
- package/dist/docs/views/index.d.ts +3 -0
- package/dist/docs/views/index.js +1031 -0
- package/dist/events.d.ts +142 -0
- package/dist/events.js +228 -0
- package/dist/events.test.d.ts +1 -0
- package/dist/examples/define.d.ts +5 -0
- package/dist/examples/define.js +36 -0
- package/dist/examples/docs/examples.docblock.d.ts +2 -0
- package/dist/examples/docs/examples.docblock.js +307 -0
- package/dist/examples/index.d.ts +7 -0
- package/dist/examples/index.js +604 -0
- package/dist/examples/registry.d.ts +38 -0
- package/dist/examples/registry.js +286 -0
- package/dist/examples/registry.test.d.ts +1 -0
- package/dist/examples/schema.d.ts +278 -0
- package/dist/examples/schema.js +166 -0
- package/dist/examples/schema.test.d.ts +1 -0
- package/dist/examples/types.d.ts +162 -0
- package/dist/examples/types.js +77 -0
- package/dist/examples/types.test.d.ts +1 -0
- package/dist/examples/validation.d.ts +61 -0
- package/dist/examples/validation.js +287 -0
- package/dist/examples/validation.test.d.ts +1 -0
- package/dist/experiments/docs/experiments.docblock.d.ts +2 -0
- package/dist/experiments/docs/experiments.docblock.js +291 -0
- package/dist/experiments/evaluator.d.ts +33 -0
- package/dist/experiments/evaluator.js +155 -0
- package/dist/experiments/evaluator.test.d.ts +1 -0
- package/dist/experiments/spec-resolver.d.ts +12 -0
- package/dist/experiments/spec-resolver.js +1 -0
- package/dist/experiments/spec.d.ts +79 -0
- package/dist/experiments/spec.js +227 -0
- package/dist/experiments/spec.test.d.ts +1 -0
- package/dist/features/index.d.ts +5 -0
- package/dist/features/index.js +275 -0
- package/dist/features/install.d.ts +14 -0
- package/dist/features/install.js +95 -0
- package/dist/features/install.test.d.ts +1 -0
- package/dist/features/registry.d.ts +21 -0
- package/dist/features/registry.js +192 -0
- package/dist/features/registry.test.d.ts +1 -0
- package/dist/features/types.d.ts +82 -0
- package/dist/features/types.js +36 -0
- package/dist/features/types.test.d.ts +1 -0
- package/dist/features/validation.d.ts +4 -0
- package/dist/features/validation.js +48 -0
- package/dist/features/validation.test.d.ts +1 -0
- package/dist/features.capabilities.test.d.ts +1 -0
- package/dist/forms/docs/forms.docblock.d.ts +2 -0
- package/dist/forms/docs/forms.docblock.js +164 -0
- package/dist/forms/forms.d.ts +264 -0
- package/dist/forms/forms.js +332 -0
- package/dist/forms/index.d.ts +1 -0
- package/dist/forms/index.js +332 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +2195 -0
- package/dist/install.d.ts +75 -0
- package/dist/install.js +60 -0
- package/dist/integrations/binding.d.ts +14 -0
- package/dist/integrations/binding.js +1 -0
- package/dist/integrations/connection.d.ts +47 -0
- package/dist/integrations/connection.js +1 -0
- package/dist/integrations/docs/integrations.docblock.d.ts +2 -0
- package/dist/integrations/docs/integrations.docblock.js +140 -0
- package/dist/integrations/health.d.ts +17 -0
- package/dist/integrations/health.js +103 -0
- package/dist/integrations/health.test.d.ts +1 -0
- package/dist/integrations/index.d.ts +11 -0
- package/dist/integrations/index.js +3293 -0
- package/dist/integrations/integrations.capability.d.ts +1 -0
- package/dist/integrations/integrations.capability.js +48 -0
- package/dist/integrations/integrations.feature.d.ts +5 -0
- package/dist/integrations/integrations.feature.js +63 -0
- package/dist/integrations/meeting-recorder/contracts/index.d.ts +7 -0
- package/dist/integrations/meeting-recorder/contracts/index.js +504 -0
- package/dist/integrations/meeting-recorder/contracts/meetings.d.ts +451 -0
- package/dist/integrations/meeting-recorder/contracts/meetings.js +249 -0
- package/dist/integrations/meeting-recorder/contracts/transcripts.d.ts +166 -0
- package/dist/integrations/meeting-recorder/contracts/transcripts.js +317 -0
- package/dist/integrations/meeting-recorder/contracts/webhooks.d.ts +85 -0
- package/dist/integrations/meeting-recorder/contracts/webhooks.js +202 -0
- package/dist/integrations/meeting-recorder/meeting-recorder.capability.d.ts +1 -0
- package/dist/integrations/meeting-recorder/meeting-recorder.capability.js +48 -0
- package/dist/integrations/meeting-recorder/meeting-recorder.feature.d.ts +5 -0
- package/dist/integrations/meeting-recorder/meeting-recorder.feature.js +63 -0
- package/dist/integrations/meeting-recorder/models.d.ts +402 -0
- package/dist/integrations/meeting-recorder/models.js +152 -0
- package/dist/integrations/meeting-recorder/telemetry.d.ts +13 -0
- package/dist/integrations/meeting-recorder/telemetry.js +84 -0
- package/dist/integrations/openbanking/contracts/accounts.d.ts +282 -0
- package/dist/integrations/openbanking/contracts/accounts.js +358 -0
- package/dist/integrations/openbanking/contracts/balances.d.ts +158 -0
- package/dist/integrations/openbanking/contracts/balances.js +322 -0
- package/dist/integrations/openbanking/contracts/index.d.ts +7 -0
- package/dist/integrations/openbanking/contracts/index.js +674 -0
- package/dist/integrations/openbanking/contracts/transactions.d.ts +206 -0
- package/dist/integrations/openbanking/contracts/transactions.js +328 -0
- package/dist/integrations/openbanking/guards.d.ts +8 -0
- package/dist/integrations/openbanking/guards.js +72 -0
- package/dist/integrations/openbanking/guards.test.d.ts +1 -0
- package/dist/integrations/openbanking/models.d.ts +223 -0
- package/dist/integrations/openbanking/models.js +140 -0
- package/dist/integrations/openbanking/openbanking.capability.d.ts +1 -0
- package/dist/integrations/openbanking/openbanking.capability.js +48 -0
- package/dist/integrations/openbanking/openbanking.feature.d.ts +5 -0
- package/dist/integrations/openbanking/openbanking.feature.js +65 -0
- package/dist/integrations/openbanking/telemetry.d.ts +12 -0
- package/dist/integrations/openbanking/telemetry.js +81 -0
- package/dist/integrations/operations.d.ts +430 -0
- package/dist/integrations/operations.js +327 -0
- package/dist/integrations/operations.test.d.ts +1 -0
- package/dist/integrations/providers/analytics-reader.d.ts +103 -0
- package/dist/integrations/providers/analytics-reader.js +1 -0
- package/dist/integrations/providers/analytics-writer.d.ts +6 -0
- package/dist/integrations/providers/analytics-writer.js +1 -0
- package/dist/integrations/providers/analytics.d.ts +47 -0
- package/dist/integrations/providers/analytics.js +1 -0
- package/dist/integrations/providers/calendar.d.ts +75 -0
- package/dist/integrations/providers/calendar.js +1 -0
- package/dist/integrations/providers/database.d.ts +12 -0
- package/dist/integrations/providers/database.js +1 -0
- package/dist/integrations/providers/elevenlabs.d.ts +3 -0
- package/dist/integrations/providers/elevenlabs.js +116 -0
- package/dist/integrations/providers/email.d.ts +83 -0
- package/dist/integrations/providers/email.js +1 -0
- package/dist/integrations/providers/embedding.d.ts +21 -0
- package/dist/integrations/providers/embedding.js +1 -0
- package/dist/integrations/providers/fal.d.ts +3 -0
- package/dist/integrations/providers/fal.js +142 -0
- package/dist/integrations/providers/fathom.d.ts +3 -0
- package/dist/integrations/providers/fathom.js +156 -0
- package/dist/integrations/providers/fireflies.d.ts +3 -0
- package/dist/integrations/providers/fireflies.js +136 -0
- package/dist/integrations/providers/gcs-storage.d.ts +3 -0
- package/dist/integrations/providers/gcs-storage.js +127 -0
- package/dist/integrations/providers/gmail.d.ts +3 -0
- package/dist/integrations/providers/gmail.js +139 -0
- package/dist/integrations/providers/google-calendar.d.ts +3 -0
- package/dist/integrations/providers/google-calendar.js +122 -0
- package/dist/integrations/providers/gradium.d.ts +3 -0
- package/dist/integrations/providers/gradium.js +140 -0
- package/dist/integrations/providers/granola.d.ts +3 -0
- package/dist/integrations/providers/granola.js +137 -0
- package/dist/integrations/providers/index.d.ts +38 -0
- package/dist/integrations/providers/index.js +2124 -0
- package/dist/integrations/providers/jira.d.ts +3 -0
- package/dist/integrations/providers/jira.js +138 -0
- package/dist/integrations/providers/linear.d.ts +3 -0
- package/dist/integrations/providers/linear.js +137 -0
- package/dist/integrations/providers/llm.d.ts +79 -0
- package/dist/integrations/providers/llm.js +1 -0
- package/dist/integrations/providers/meeting-recorder.d.ts +129 -0
- package/dist/integrations/providers/meeting-recorder.js +1 -0
- package/dist/integrations/providers/mistral.d.ts +3 -0
- package/dist/integrations/providers/mistral.js +124 -0
- package/dist/integrations/providers/notion.d.ts +3 -0
- package/dist/integrations/providers/notion.js +143 -0
- package/dist/integrations/providers/openbanking.d.ts +125 -0
- package/dist/integrations/providers/openbanking.js +1 -0
- package/dist/integrations/providers/payments.d.ts +106 -0
- package/dist/integrations/providers/payments.js +1 -0
- package/dist/integrations/providers/posthog-llm-telemetry.d.ts +51 -0
- package/dist/integrations/providers/posthog-llm-telemetry.js +206 -0
- package/dist/integrations/providers/posthog.d.ts +3 -0
- package/dist/integrations/providers/posthog.js +136 -0
- package/dist/integrations/providers/postmark.d.ts +3 -0
- package/dist/integrations/providers/postmark.js +128 -0
- package/dist/integrations/providers/powens.d.ts +3 -0
- package/dist/integrations/providers/powens.js +154 -0
- package/dist/integrations/providers/project-management.d.ts +32 -0
- package/dist/integrations/providers/project-management.js +1 -0
- package/dist/integrations/providers/providers.test.d.ts +1 -0
- package/dist/integrations/providers/qdrant.d.ts +3 -0
- package/dist/integrations/providers/qdrant.js +131 -0
- package/dist/integrations/providers/registry.d.ts +6 -0
- package/dist/integrations/providers/registry.js +1908 -0
- package/dist/integrations/providers/sms.d.ts +31 -0
- package/dist/integrations/providers/sms.js +1 -0
- package/dist/integrations/providers/storage.d.ts +57 -0
- package/dist/integrations/providers/storage.js +1 -0
- package/dist/integrations/providers/stripe.d.ts +3 -0
- package/dist/integrations/providers/stripe.js +135 -0
- package/dist/integrations/providers/supabase-postgres.d.ts +3 -0
- package/dist/integrations/providers/supabase-postgres.js +117 -0
- package/dist/integrations/providers/supabase-vector.d.ts +3 -0
- package/dist/integrations/providers/supabase-vector.js +137 -0
- package/dist/integrations/providers/tldv.d.ts +3 -0
- package/dist/integrations/providers/tldv.js +136 -0
- package/dist/integrations/providers/twilio-sms.d.ts +3 -0
- package/dist/integrations/providers/twilio-sms.js +121 -0
- package/dist/integrations/providers/vector-store.d.ts +39 -0
- package/dist/integrations/providers/vector-store.js +1 -0
- package/dist/integrations/providers/voice.d.ts +31 -0
- package/dist/integrations/providers/voice.js +1 -0
- package/dist/integrations/runtime.d.ts +95 -0
- package/dist/integrations/runtime.js +239 -0
- package/dist/integrations/runtime.test.d.ts +1 -0
- package/dist/integrations/secrets/aws-secret-manager.d.ts +28 -0
- package/dist/integrations/secrets/aws-secret-manager.js +376 -0
- package/dist/integrations/secrets/env-secret-provider.d.ts +28 -0
- package/dist/integrations/secrets/env-secret-provider.js +189 -0
- package/dist/integrations/secrets/gcp-secret-manager.d.ts +29 -0
- package/dist/integrations/secrets/gcp-secret-manager.js +377 -0
- package/dist/integrations/secrets/index.d.ts +6 -0
- package/dist/integrations/secrets/index.js +1159 -0
- package/dist/integrations/secrets/manager.d.ts +44 -0
- package/dist/integrations/secrets/manager.js +213 -0
- package/dist/integrations/secrets/provider.d.ts +49 -0
- package/dist/integrations/secrets/provider.js +104 -0
- package/dist/integrations/secrets/provider.test.d.ts +1 -0
- package/dist/integrations/secrets/scaleway-secret-manager.d.ts +35 -0
- package/dist/integrations/secrets/scaleway-secret-manager.js +405 -0
- package/dist/integrations/secrets-types.d.ts +14 -0
- package/dist/integrations/secrets-types.js +1 -0
- package/dist/integrations/spec.d.ts +72 -0
- package/dist/integrations/spec.js +52 -0
- package/dist/integrations/spec.test.d.ts +1 -0
- package/dist/jobs/define-job.d.ts +15 -0
- package/dist/jobs/define-job.js +41 -0
- package/dist/jobs/gcp-cloud-tasks.d.ts +38 -0
- package/dist/jobs/gcp-cloud-tasks.js +103 -0
- package/dist/jobs/gcp-pubsub.d.ts +22 -0
- package/dist/jobs/gcp-pubsub.js +91 -0
- package/dist/jobs/handlers/gmail-sync-handler.d.ts +5 -0
- package/dist/jobs/handlers/gmail-sync-handler.js +40 -0
- package/dist/jobs/handlers/handlers.test.d.ts +1 -0
- package/dist/jobs/handlers/index.d.ts +5 -0
- package/dist/jobs/handlers/index.js +83 -0
- package/dist/jobs/handlers/ping-handler.d.ts +6 -0
- package/dist/jobs/handlers/ping-handler.js +47 -0
- package/dist/jobs/handlers/storage-document-handler.d.ts +8 -0
- package/dist/jobs/handlers/storage-document-handler.js +47 -0
- package/dist/jobs/index.d.ts +2 -0
- package/dist/jobs/index.js +64 -0
- package/dist/jobs/memory-queue.d.ts +14 -0
- package/dist/jobs/memory-queue.js +129 -0
- package/dist/jobs/queue.d.ts +126 -0
- package/dist/jobs/queue.js +55 -0
- package/dist/jobs/queue.test.d.ts +1 -0
- package/dist/jobs/scaleway-sqs-queue.d.ts +27 -0
- package/dist/jobs/scaleway-sqs-queue.js +222 -0
- package/dist/jsonschema.d.ts +39 -0
- package/dist/jsonschema.js +73 -0
- package/dist/jsonschema.test.d.ts +1 -0
- package/dist/knowledge/binding.d.ts +22 -0
- package/dist/knowledge/binding.js +1 -0
- package/dist/knowledge/docs/knowledge.docblock.d.ts +2 -0
- package/dist/knowledge/docs/knowledge.docblock.js +301 -0
- package/dist/knowledge/index.d.ts +4 -0
- package/dist/knowledge/index.js +467 -0
- package/dist/knowledge/ingestion/document-processor.d.ts +22 -0
- package/dist/knowledge/ingestion/document-processor.js +95 -0
- package/dist/knowledge/ingestion/embedding-service.d.ts +8 -0
- package/dist/knowledge/ingestion/embedding-service.js +57 -0
- package/dist/knowledge/ingestion/gmail-adapter.d.ts +14 -0
- package/dist/knowledge/ingestion/gmail-adapter.js +103 -0
- package/dist/knowledge/ingestion/index.d.ts +5 -0
- package/dist/knowledge/ingestion/index.js +252 -0
- package/dist/knowledge/ingestion/ingestion.test.d.ts +1 -0
- package/dist/knowledge/ingestion/storage-adapter.d.ts +11 -0
- package/dist/knowledge/ingestion/storage-adapter.js +62 -0
- package/dist/knowledge/ingestion/vector-indexer.d.ts +14 -0
- package/dist/knowledge/ingestion/vector-indexer.js +63 -0
- package/dist/knowledge/knowledge.capability.d.ts +1 -0
- package/dist/knowledge/knowledge.capability.js +726 -0
- package/dist/knowledge/knowledge.feature.d.ts +5 -0
- package/dist/knowledge/knowledge.feature.js +300 -0
- package/dist/knowledge/operations.d.ts +311 -0
- package/dist/knowledge/operations.js +619 -0
- package/dist/knowledge/operations.test.d.ts +1 -0
- package/dist/knowledge/query/index.d.ts +1 -0
- package/dist/knowledge/query/index.js +110 -0
- package/dist/knowledge/query/service.d.ts +25 -0
- package/dist/knowledge/query/service.js +110 -0
- package/dist/knowledge/query/service.test.d.ts +1 -0
- package/dist/knowledge/runtime.d.ts +28 -0
- package/dist/knowledge/runtime.js +91 -0
- package/dist/knowledge/runtime.test.d.ts +1 -0
- package/dist/knowledge/source.d.ts +29 -0
- package/dist/knowledge/source.js +1 -0
- package/dist/knowledge/spaces/email-threads.d.ts +3 -0
- package/dist/knowledge/spaces/email-threads.js +102 -0
- package/dist/knowledge/spaces/financial-docs.d.ts +3 -0
- package/dist/knowledge/spaces/financial-docs.js +102 -0
- package/dist/knowledge/spaces/financial-overview.d.ts +3 -0
- package/dist/knowledge/spaces/financial-overview.js +102 -0
- package/dist/knowledge/spaces/index.d.ts +6 -0
- package/dist/knowledge/spaces/index.js +273 -0
- package/dist/knowledge/spaces/product-canon.d.ts +3 -0
- package/dist/knowledge/spaces/product-canon.js +102 -0
- package/dist/knowledge/spaces/spaces.test.d.ts +1 -0
- package/dist/knowledge/spaces/support-faq.d.ts +3 -0
- package/dist/knowledge/spaces/support-faq.js +103 -0
- package/dist/knowledge/spaces/uploaded-docs.d.ts +3 -0
- package/dist/knowledge/spaces/uploaded-docs.js +102 -0
- package/dist/knowledge/spec.d.ts +42 -0
- package/dist/knowledge/spec.js +228 -0
- package/dist/knowledge/spec.test.d.ts +1 -0
- package/dist/llm/exporters.d.ts +68 -0
- package/dist/llm/exporters.js +1011 -0
- package/dist/llm/index.d.ts +12 -0
- package/dist/llm/index.js +1465 -0
- package/dist/llm/prompts.d.ts +53 -0
- package/dist/llm/prompts.js +1456 -0
- package/dist/llm/types.d.ts +212 -0
- package/dist/llm/types.js +1 -0
- package/dist/markdown.d.ts +16 -0
- package/dist/markdown.js +529 -0
- package/dist/migrations.d.ts +48 -0
- package/dist/migrations.js +67 -0
- package/dist/migrations.test.d.ts +1 -0
- package/dist/model-registry.d.ts +9 -0
- package/dist/model-registry.js +64 -0
- package/dist/model-registry.test.d.ts +1 -0
- package/dist/node/app-config/app-config.capability.js +730 -0
- package/dist/node/app-config/app-config.contracts.js +713 -0
- package/dist/node/app-config/app-config.feature.js +255 -0
- package/dist/node/app-config/branding.js +0 -0
- package/dist/node/app-config/docs/app-config.docblock.js +383 -0
- package/dist/node/app-config/events.js +386 -0
- package/dist/node/app-config/index.js +2899 -0
- package/dist/node/app-config/lifecycle-contracts.js +870 -0
- package/dist/node/app-config/lifecycle.js +0 -0
- package/dist/node/app-config/runtime.js +734 -0
- package/dist/node/app-config/spec.js +229 -0
- package/dist/node/app-config/validation.js +650 -0
- package/dist/node/capabilities/capabilities.js +217 -0
- package/dist/node/capabilities/context.js +101 -0
- package/dist/node/capabilities/docs/capabilities.docblock.js +353 -0
- package/dist/node/capabilities/guards.js +177 -0
- package/dist/node/capabilities/index.js +739 -0
- package/dist/node/capabilities/meeting-recorder.js +154 -0
- package/dist/node/capabilities/openbanking.js +166 -0
- package/dist/node/capabilities/validation.js +185 -0
- package/dist/node/contract-registry/index.js +129 -0
- package/dist/node/contract-registry/schemas.js +129 -0
- package/dist/node/contract-registry/types.js +0 -0
- package/dist/node/data-views/data-views.js +232 -0
- package/dist/node/data-views/docs/data-views.docblock.js +164 -0
- package/dist/node/data-views/index.js +232 -0
- package/dist/node/data-views/query-generator.js +89 -0
- package/dist/node/data-views/registry.js +226 -0
- package/dist/node/data-views/report/contractVerificationTable.js +240 -0
- package/dist/node/data-views/runtime.js +108 -0
- package/dist/node/data-views/spec.js +38 -0
- package/dist/node/data-views/types.js +0 -0
- package/dist/node/docs/accessibility_wcag_compliance_specs.docblock.js +513 -0
- package/dist/node/docs/capabilities/documentationSystem.capability.js +784 -0
- package/dist/node/docs/capabilities/index.js +784 -0
- package/dist/node/docs/commands/docsGenerate.command.js +802 -0
- package/dist/node/docs/commands/docsPublish.command.js +781 -0
- package/dist/node/docs/commands/index.js +906 -0
- package/dist/node/docs/constants.js +78 -0
- package/dist/node/docs/contracts.js +1611 -0
- package/dist/node/docs/ensure-docblocks.js +264 -0
- package/dist/node/docs/events/docsGenerated.event.js +533 -0
- package/dist/node/docs/events/docsPublished.event.js +534 -0
- package/dist/node/docs/events/index.js +567 -0
- package/dist/node/docs/forms/docsSearch.form.js +676 -0
- package/dist/node/docs/forms/index.js +676 -0
- package/dist/node/docs/index.js +4719 -0
- package/dist/node/docs/meta.docs.js +176 -0
- package/dist/node/docs/presentations/docsLayout.presentation.js +527 -0
- package/dist/node/docs/presentations/docsReferencePage.presentation.js +527 -0
- package/dist/node/docs/presentations/index.js +555 -0
- package/dist/node/docs/presentations.js +97 -0
- package/dist/node/docs/queries/contractReference.query.js +752 -0
- package/dist/node/docs/queries/docsIndex.query.js +752 -0
- package/dist/node/docs/queries/index.js +827 -0
- package/dist/node/docs/registry.js +153 -0
- package/dist/node/docs/tech/auth/better-auth-nextjs.docblock.js +221 -0
- package/dist/node/docs/tech/cli.docblock.js +291 -0
- package/dist/node/docs/tech/contracts/README.docblock.js +164 -0
- package/dist/node/docs/tech/contracts/migrations.docblock.js +164 -0
- package/dist/node/docs/tech/contracts/openapi-export.docblock.js +201 -0
- package/dist/node/docs/tech/contracts/openapi-import.docblock.js +207 -0
- package/dist/node/docs/tech/contracts/ops-to-presentation-linking.docblock.js +225 -0
- package/dist/node/docs/tech/contracts/overlays.docblock.js +231 -0
- package/dist/node/docs/tech/contracts/tests.docblock.js +164 -0
- package/dist/node/docs/tech/contracts/themes.docblock.js +257 -0
- package/dist/node/docs/tech/contracts/vertical-pocket-family-office.docblock.js +269 -0
- package/dist/node/docs/tech/docs-system.docblock.js +264 -0
- package/dist/node/docs/tech/lifecycle-stage-system.docblock.js +376 -0
- package/dist/node/docs/tech/llm/llm-integration.docblock.js +482 -0
- package/dist/node/docs/tech/mcp-endpoints.docblock.js +185 -0
- package/dist/node/docs/tech/presentation-runtime.docblock.js +221 -0
- package/dist/node/docs/tech/report-verification-table.docblock.js +191 -0
- package/dist/node/docs/tech/schema/README.docblock.js +164 -0
- package/dist/node/docs/tech/studio/learning-events.docblock.js +190 -0
- package/dist/node/docs/tech/studio/learning-journeys.docblock.js +227 -0
- package/dist/node/docs/tech/studio/platform-admin-panel.docblock.js +226 -0
- package/dist/node/docs/tech/studio/project-access-teams.docblock.js +200 -0
- package/dist/node/docs/tech/studio/project-routing.docblock.js +209 -0
- package/dist/node/docs/tech/studio/sandbox-unlogged.docblock.js +183 -0
- package/dist/node/docs/tech/studio/team-invitations.docblock.js +228 -0
- package/dist/node/docs/tech/studio/workspace-ops.docblock.js +189 -0
- package/dist/node/docs/tech/studio/workspaces.docblock.js +204 -0
- package/dist/node/docs/tech/telemetry-ingest.docblock.js +305 -0
- package/dist/node/docs/tech/vscode-extension.docblock.js +241 -0
- package/dist/node/docs/tech-contracts.docs.js +239 -0
- package/dist/node/docs/types.js +0 -0
- package/dist/node/docs/views/contractReference.dataView.js +838 -0
- package/dist/node/docs/views/docsIndex.dataView.js +832 -0
- package/dist/node/docs/views/exampleCatalog.dataView.js +816 -0
- package/dist/node/docs/views/index.js +1031 -0
- package/dist/node/events.js +228 -0
- package/dist/node/examples/define.js +36 -0
- package/dist/node/examples/docs/examples.docblock.js +307 -0
- package/dist/node/examples/index.js +604 -0
- package/dist/node/examples/registry.js +286 -0
- package/dist/node/examples/schema.js +166 -0
- package/dist/node/examples/types.js +77 -0
- package/dist/node/examples/validation.js +287 -0
- package/dist/node/experiments/docs/experiments.docblock.js +291 -0
- package/dist/node/experiments/evaluator.js +155 -0
- package/dist/node/experiments/spec-resolver.js +0 -0
- package/dist/node/experiments/spec.js +227 -0
- package/dist/node/features/index.js +275 -0
- package/dist/node/features/install.js +95 -0
- package/dist/node/features/registry.js +192 -0
- package/dist/node/features/types.js +36 -0
- package/dist/node/features/validation.js +48 -0
- package/dist/node/forms/docs/forms.docblock.js +164 -0
- package/dist/node/forms/forms.js +332 -0
- package/dist/node/forms/index.js +332 -0
- package/dist/node/index.js +2195 -0
- package/dist/node/install.js +60 -0
- package/dist/node/integrations/binding.js +0 -0
- package/dist/node/integrations/connection.js +0 -0
- package/dist/node/integrations/docs/integrations.docblock.js +140 -0
- package/dist/node/integrations/health.js +103 -0
- package/dist/node/integrations/index.js +3293 -0
- package/dist/node/integrations/integrations.capability.js +48 -0
- package/dist/node/integrations/integrations.feature.js +63 -0
- package/dist/node/integrations/meeting-recorder/contracts/index.js +504 -0
- package/dist/node/integrations/meeting-recorder/contracts/meetings.js +249 -0
- package/dist/node/integrations/meeting-recorder/contracts/transcripts.js +317 -0
- package/dist/node/integrations/meeting-recorder/contracts/webhooks.js +202 -0
- package/dist/node/integrations/meeting-recorder/meeting-recorder.capability.js +48 -0
- package/dist/node/integrations/meeting-recorder/meeting-recorder.feature.js +63 -0
- package/dist/node/integrations/meeting-recorder/models.js +152 -0
- package/dist/node/integrations/meeting-recorder/telemetry.js +84 -0
- package/dist/node/integrations/openbanking/contracts/accounts.js +358 -0
- package/dist/node/integrations/openbanking/contracts/balances.js +322 -0
- package/dist/node/integrations/openbanking/contracts/index.js +674 -0
- package/dist/node/integrations/openbanking/contracts/transactions.js +328 -0
- package/dist/node/integrations/openbanking/guards.js +72 -0
- package/dist/node/integrations/openbanking/models.js +140 -0
- package/dist/node/integrations/openbanking/openbanking.capability.js +48 -0
- package/dist/node/integrations/openbanking/openbanking.feature.js +65 -0
- package/dist/node/integrations/openbanking/telemetry.js +81 -0
- package/dist/node/integrations/operations.js +327 -0
- package/dist/node/integrations/providers/analytics-reader.js +0 -0
- package/dist/node/integrations/providers/analytics-writer.js +0 -0
- package/dist/node/integrations/providers/analytics.js +0 -0
- package/dist/node/integrations/providers/calendar.js +0 -0
- package/dist/node/integrations/providers/database.js +0 -0
- package/dist/node/integrations/providers/elevenlabs.js +116 -0
- package/dist/node/integrations/providers/email.js +0 -0
- package/dist/node/integrations/providers/embedding.js +0 -0
- package/dist/node/integrations/providers/fal.js +142 -0
- package/dist/node/integrations/providers/fathom.js +156 -0
- package/dist/node/integrations/providers/fireflies.js +136 -0
- package/dist/node/integrations/providers/gcs-storage.js +127 -0
- package/dist/node/integrations/providers/gmail.js +139 -0
- package/dist/node/integrations/providers/google-calendar.js +122 -0
- package/dist/node/integrations/providers/gradium.js +140 -0
- package/dist/node/integrations/providers/granola.js +137 -0
- package/dist/node/integrations/providers/index.js +2124 -0
- package/dist/node/integrations/providers/jira.js +138 -0
- package/dist/node/integrations/providers/linear.js +137 -0
- package/dist/node/integrations/providers/llm.js +0 -0
- package/dist/node/integrations/providers/meeting-recorder.js +0 -0
- package/dist/node/integrations/providers/mistral.js +124 -0
- package/dist/node/integrations/providers/notion.js +143 -0
- package/dist/node/integrations/providers/openbanking.js +0 -0
- package/dist/node/integrations/providers/payments.js +0 -0
- package/dist/node/integrations/providers/posthog-llm-telemetry.js +206 -0
- package/dist/node/integrations/providers/posthog.js +136 -0
- package/dist/node/integrations/providers/postmark.js +128 -0
- package/dist/node/integrations/providers/powens.js +154 -0
- package/dist/node/integrations/providers/project-management.js +0 -0
- package/dist/node/integrations/providers/qdrant.js +131 -0
- package/dist/node/integrations/providers/registry.js +1908 -0
- package/dist/node/integrations/providers/sms.js +0 -0
- package/dist/node/integrations/providers/storage.js +0 -0
- package/dist/node/integrations/providers/stripe.js +135 -0
- package/dist/node/integrations/providers/supabase-postgres.js +117 -0
- package/dist/node/integrations/providers/supabase-vector.js +137 -0
- package/dist/node/integrations/providers/tldv.js +136 -0
- package/dist/node/integrations/providers/twilio-sms.js +121 -0
- package/dist/node/integrations/providers/vector-store.js +0 -0
- package/dist/node/integrations/providers/voice.js +0 -0
- package/dist/node/integrations/runtime.js +239 -0
- package/dist/node/integrations/secrets/aws-secret-manager.js +376 -0
- package/dist/node/integrations/secrets/env-secret-provider.js +189 -0
- package/dist/node/integrations/secrets/gcp-secret-manager.js +377 -0
- package/dist/node/integrations/secrets/index.js +1159 -0
- package/dist/node/integrations/secrets/manager.js +213 -0
- package/dist/node/integrations/secrets/provider.js +104 -0
- package/dist/node/integrations/secrets/scaleway-secret-manager.js +405 -0
- package/dist/node/integrations/secrets-types.js +0 -0
- package/dist/node/integrations/spec.js +52 -0
- package/dist/node/jobs/define-job.js +41 -0
- package/dist/node/jobs/gcp-cloud-tasks.js +103 -0
- package/dist/node/jobs/gcp-pubsub.js +91 -0
- package/dist/node/jobs/handlers/gmail-sync-handler.js +40 -0
- package/dist/node/jobs/handlers/index.js +83 -0
- package/dist/node/jobs/handlers/ping-handler.js +47 -0
- package/dist/node/jobs/handlers/storage-document-handler.js +47 -0
- package/dist/node/jobs/index.js +64 -0
- package/dist/node/jobs/memory-queue.js +129 -0
- package/dist/node/jobs/queue.js +55 -0
- package/dist/node/jobs/scaleway-sqs-queue.js +222 -0
- package/dist/node/jsonschema.js +73 -0
- package/dist/node/knowledge/binding.js +0 -0
- package/dist/node/knowledge/docs/knowledge.docblock.js +301 -0
- package/dist/node/knowledge/index.js +467 -0
- package/dist/node/knowledge/ingestion/document-processor.js +95 -0
- package/dist/node/knowledge/ingestion/embedding-service.js +57 -0
- package/dist/node/knowledge/ingestion/gmail-adapter.js +103 -0
- package/dist/node/knowledge/ingestion/index.js +252 -0
- package/dist/node/knowledge/ingestion/storage-adapter.js +62 -0
- package/dist/node/knowledge/ingestion/vector-indexer.js +63 -0
- package/dist/node/knowledge/knowledge.capability.js +726 -0
- package/dist/node/knowledge/knowledge.feature.js +300 -0
- package/dist/node/knowledge/operations.js +619 -0
- package/dist/node/knowledge/query/index.js +110 -0
- package/dist/node/knowledge/query/service.js +110 -0
- package/dist/node/knowledge/runtime.js +91 -0
- package/dist/node/knowledge/source.js +0 -0
- package/dist/node/knowledge/spaces/email-threads.js +102 -0
- package/dist/node/knowledge/spaces/financial-docs.js +102 -0
- package/dist/node/knowledge/spaces/financial-overview.js +102 -0
- package/dist/node/knowledge/spaces/index.js +273 -0
- package/dist/node/knowledge/spaces/product-canon.js +102 -0
- package/dist/node/knowledge/spaces/support-faq.js +103 -0
- package/dist/node/knowledge/spaces/uploaded-docs.js +102 -0
- package/dist/node/knowledge/spec.js +228 -0
- package/dist/node/llm/exporters.js +1011 -0
- package/dist/node/llm/index.js +1465 -0
- package/dist/node/llm/prompts.js +1456 -0
- package/dist/node/llm/types.js +0 -0
- package/dist/node/markdown.js +529 -0
- package/dist/node/migrations.js +67 -0
- package/dist/node/model-registry.js +64 -0
- package/dist/node/onboarding-base.js +597 -0
- package/dist/node/openapi.js +151 -0
- package/dist/node/operations/index.js +408 -0
- package/dist/node/operations/operation.js +51 -0
- package/dist/node/operations/registry.js +405 -0
- package/dist/node/operations/report/getContractVerificationStatus.js +170 -0
- package/dist/node/operations/report/index.js +305 -0
- package/dist/node/ownership.js +73 -0
- package/dist/node/policy/context.js +206 -0
- package/dist/node/policy/docs/policy.docblock.js +313 -0
- package/dist/node/policy/engine.js +325 -0
- package/dist/node/policy/guards.js +387 -0
- package/dist/node/policy/index.js +1313 -0
- package/dist/node/policy/opa-adapter.js +110 -0
- package/dist/node/policy/registry.js +221 -0
- package/dist/node/policy/spec.js +0 -0
- package/dist/node/policy/validation.js +391 -0
- package/dist/node/presentations/docs/presentations-conventions.docblock.js +171 -0
- package/dist/node/presentations/index.js +227 -0
- package/dist/node/presentations/presentations.js +38 -0
- package/dist/node/presentations/registry.js +221 -0
- package/dist/node/presentations/transform-engine.js +600 -0
- package/dist/node/product-intent/contract-patch-intent.js +68 -0
- package/dist/node/product-intent/contract-spec-patch.js +75 -0
- package/dist/node/product-intent/evidence.js +45 -0
- package/dist/node/product-intent/findings.js +81 -0
- package/dist/node/product-intent/impact-report.js +62 -0
- package/dist/node/product-intent/index.js +742 -0
- package/dist/node/product-intent/insights.js +63 -0
- package/dist/node/product-intent/opportunity-brief.js +106 -0
- package/dist/node/product-intent/problems.js +55 -0
- package/dist/node/product-intent/registry.js +242 -0
- package/dist/node/product-intent/runtime.js +320 -0
- package/dist/node/product-intent/spec.js +425 -0
- package/dist/node/product-intent/task-pack.js +69 -0
- package/dist/node/product-intent/tickets.js +57 -0
- package/dist/node/product-intent/types.js +378 -0
- package/dist/node/product-intent/ui-wireframe.js +73 -0
- package/dist/node/prompt.js +38 -0
- package/dist/node/promptRegistry.js +63 -0
- package/dist/node/regenerator/adapters.js +0 -0
- package/dist/node/regenerator/docs/regenerator.docblock.js +164 -0
- package/dist/node/regenerator/executor.js +157 -0
- package/dist/node/regenerator/index.js +341 -0
- package/dist/node/regenerator/service.js +183 -0
- package/dist/node/regenerator/sinks.js +64 -0
- package/dist/node/regenerator/types.js +0 -0
- package/dist/node/regenerator/utils.js +87 -0
- package/dist/node/registry-utils.js +163 -0
- package/dist/node/registry.js +215 -0
- package/dist/node/resources.js +83 -0
- package/dist/node/schema-to-markdown.js +278 -0
- package/dist/node/serialization/index.js +179 -0
- package/dist/node/serialization/serializers.js +180 -0
- package/dist/node/serialization/types.js +0 -0
- package/dist/node/telemetry/anomaly.js +91 -0
- package/dist/node/telemetry/docs/telemetry.docblock.js +164 -0
- package/dist/node/telemetry/index.js +417 -0
- package/dist/node/telemetry/spec.js +261 -0
- package/dist/node/telemetry/tracker.js +129 -0
- package/dist/node/tests/index.js +231 -0
- package/dist/node/tests/runner.js +189 -0
- package/dist/node/tests/spec.js +74 -0
- package/dist/node/themes.js +225 -0
- package/dist/node/translations/catalog.js +0 -0
- package/dist/node/translations/index.js +533 -0
- package/dist/node/translations/registry.js +170 -0
- package/dist/node/translations/spec.js +36 -0
- package/dist/node/translations/tenant.js +0 -0
- package/dist/node/translations/validation.js +392 -0
- package/dist/node/types.js +0 -0
- package/dist/node/versioning/index.js +274 -0
- package/dist/node/versioning/refs.js +99 -0
- package/dist/node/versioning/types.js +55 -0
- package/dist/node/versioning/utils.js +184 -0
- package/dist/node/workflow/adapters/db-adapter.js +127 -0
- package/dist/node/workflow/adapters/file-adapter.js +38 -0
- package/dist/node/workflow/adapters/index.js +194 -0
- package/dist/node/workflow/adapters/memory-store.js +93 -0
- package/dist/node/workflow/context.js +247 -0
- package/dist/node/workflow/expression.js +157 -0
- package/dist/node/workflow/index.js +1546 -0
- package/dist/node/workflow/overview.docblock.js +164 -0
- package/dist/node/workflow/runner.js +532 -0
- package/dist/node/workflow/sla-monitor.js +84 -0
- package/dist/node/workflow/spec.js +221 -0
- package/dist/node/workflow/state.js +0 -0
- package/dist/node/workflow/validation.js +425 -0
- package/dist/node/workspace-config/contractsrc-schema.js +344 -0
- package/dist/node/workspace-config/contractsrc-types.js +0 -0
- package/dist/node/workspace-config/index.js +325 -0
- package/dist/node/workspace-config/workspace-config.docblock.js +188 -0
- package/dist/onboarding-base.d.ts +131 -0
- package/dist/onboarding-base.js +597 -0
- package/dist/openapi.d.ts +33 -0
- package/dist/openapi.js +151 -0
- package/dist/operations/index.d.ts +2 -0
- package/dist/operations/index.js +408 -0
- package/dist/operations/operation.d.ts +191 -0
- package/dist/operations/operation.js +51 -0
- package/dist/operations/registry.d.ts +58 -0
- package/dist/operations/registry.js +405 -0
- package/dist/operations/report/getContractVerificationStatus.d.ts +68 -0
- package/dist/operations/report/getContractVerificationStatus.js +170 -0
- package/dist/operations/report/getContractVerificationStatus.test.d.ts +1 -0
- package/dist/operations/report/index.d.ts +10 -0
- package/dist/operations/report/index.js +305 -0
- package/dist/operations/report/index.test.d.ts +1 -0
- package/dist/ownership.d.ts +211 -0
- package/dist/ownership.js +73 -0
- package/dist/ownership.test.d.ts +1 -0
- package/dist/policy/context.d.ts +234 -0
- package/dist/policy/context.js +206 -0
- package/dist/policy/context.test.d.ts +1 -0
- package/dist/policy/docs/policy.docblock.d.ts +2 -0
- package/dist/policy/docs/policy.docblock.js +313 -0
- package/dist/policy/engine.d.ts +36 -0
- package/dist/policy/engine.js +325 -0
- package/dist/policy/engine.test.d.ts +1 -0
- package/dist/policy/guards.d.ts +156 -0
- package/dist/policy/guards.js +387 -0
- package/dist/policy/guards.test.d.ts +1 -0
- package/dist/policy/index.d.ts +12 -0
- package/dist/policy/index.js +1313 -0
- package/dist/policy/opa-adapter.d.ts +41 -0
- package/dist/policy/opa-adapter.js +110 -0
- package/dist/policy/opa-adapter.test.d.ts +1 -0
- package/dist/policy/registry.d.ts +5 -0
- package/dist/policy/registry.js +221 -0
- package/dist/policy/spec.d.ts +102 -0
- package/dist/policy/spec.js +1 -0
- package/dist/policy/validation.d.ts +84 -0
- package/dist/policy/validation.js +391 -0
- package/dist/policy/validation.test.d.ts +1 -0
- package/dist/presentations/docs/presentations-conventions.docblock.d.ts +2 -0
- package/dist/presentations/docs/presentations-conventions.docblock.js +171 -0
- package/dist/presentations/index.d.ts +2 -0
- package/dist/presentations/index.js +227 -0
- package/dist/presentations/presentations.d.ts +52 -0
- package/dist/presentations/presentations.js +38 -0
- package/dist/presentations/registry.d.ts +6 -0
- package/dist/presentations/registry.js +221 -0
- package/dist/presentations/transform-engine.d.ts +62 -0
- package/dist/presentations/transform-engine.js +600 -0
- package/dist/presentations/transform-engine.test.d.ts +1 -0
- package/dist/product-intent/contract-patch-intent.d.ts +100 -0
- package/dist/product-intent/contract-patch-intent.js +68 -0
- package/dist/product-intent/contract-spec-patch.d.ts +86 -0
- package/dist/product-intent/contract-spec-patch.js +75 -0
- package/dist/product-intent/evidence.d.ts +14 -0
- package/dist/product-intent/evidence.js +45 -0
- package/dist/product-intent/findings.d.ts +57 -0
- package/dist/product-intent/findings.js +81 -0
- package/dist/product-intent/impact-report.d.ts +57 -0
- package/dist/product-intent/impact-report.js +62 -0
- package/dist/product-intent/index.d.ts +13 -0
- package/dist/product-intent/index.js +742 -0
- package/dist/product-intent/insights.d.ts +62 -0
- package/dist/product-intent/insights.js +63 -0
- package/dist/product-intent/opportunity-brief.d.ts +192 -0
- package/dist/product-intent/opportunity-brief.js +106 -0
- package/dist/product-intent/problems.d.ts +59 -0
- package/dist/product-intent/problems.js +55 -0
- package/dist/product-intent/registry.d.ts +28 -0
- package/dist/product-intent/registry.js +242 -0
- package/dist/product-intent/registry.test.d.ts +1 -0
- package/dist/product-intent/runtime.d.ts +92 -0
- package/dist/product-intent/runtime.js +320 -0
- package/dist/product-intent/runtime.test.d.ts +1 -0
- package/dist/product-intent/spec.d.ts +664 -0
- package/dist/product-intent/spec.js +425 -0
- package/dist/product-intent/task-pack.d.ts +98 -0
- package/dist/product-intent/task-pack.js +69 -0
- package/dist/product-intent/tickets.d.ts +67 -0
- package/dist/product-intent/tickets.js +57 -0
- package/dist/product-intent/types.d.ts +11 -0
- package/dist/product-intent/types.js +378 -0
- package/dist/product-intent/ui-wireframe.d.ts +100 -0
- package/dist/product-intent/ui-wireframe.js +73 -0
- package/dist/prompt.d.ts +49 -0
- package/dist/prompt.js +38 -0
- package/dist/prompt.test.d.ts +1 -0
- package/dist/promptRegistry.d.ts +11 -0
- package/dist/promptRegistry.js +63 -0
- package/dist/promptRegistry.test.d.ts +1 -0
- package/dist/regenerator/adapters.d.ts +15 -0
- package/dist/regenerator/adapters.js +1 -0
- package/dist/regenerator/docs/regenerator.docblock.d.ts +2 -0
- package/dist/regenerator/docs/regenerator.docblock.js +164 -0
- package/dist/regenerator/executor.d.ts +66 -0
- package/dist/regenerator/executor.js +157 -0
- package/dist/regenerator/executor.test.d.ts +1 -0
- package/dist/regenerator/index.d.ts +6 -0
- package/dist/regenerator/index.js +341 -0
- package/dist/regenerator/service.d.ts +29 -0
- package/dist/regenerator/service.js +183 -0
- package/dist/regenerator/service.test.d.ts +1 -0
- package/dist/regenerator/sinks.d.ts +23 -0
- package/dist/regenerator/sinks.js +64 -0
- package/dist/regenerator/sinks.test.d.ts +1 -0
- package/dist/regenerator/types.d.ts +103 -0
- package/dist/regenerator/types.js +1 -0
- package/dist/regenerator/utils.d.ts +6 -0
- package/dist/regenerator/utils.js +87 -0
- package/dist/registry-utils.d.ts +105 -0
- package/dist/registry-utils.js +163 -0
- package/dist/registry-utils.test.d.ts +1 -0
- package/dist/registry.d.ts +27 -0
- package/dist/registry.js +215 -0
- package/dist/resources.d.ts +60 -0
- package/dist/resources.js +83 -0
- package/dist/schema-to-markdown.d.ts +56 -0
- package/dist/schema-to-markdown.js +278 -0
- package/dist/serialization/index.d.ts +10 -0
- package/dist/serialization/index.js +179 -0
- package/dist/serialization/serializers.d.ts +35 -0
- package/dist/serialization/serializers.js +180 -0
- package/dist/serialization/types.d.ts +100 -0
- package/dist/serialization/types.js +1 -0
- package/dist/telemetry/anomaly.d.ts +23 -0
- package/dist/telemetry/anomaly.js +91 -0
- package/dist/telemetry/anomaly.test.d.ts +1 -0
- package/dist/telemetry/docs/telemetry.docblock.d.ts +2 -0
- package/dist/telemetry/docs/telemetry.docblock.js +164 -0
- package/dist/telemetry/index.d.ts +3 -0
- package/dist/telemetry/index.js +417 -0
- package/dist/telemetry/spec.d.ts +87 -0
- package/dist/telemetry/spec.js +261 -0
- package/dist/telemetry/spec.test.d.ts +1 -0
- package/dist/telemetry/tracker.d.ts +48 -0
- package/dist/telemetry/tracker.js +129 -0
- package/dist/telemetry/tracker.test.d.ts +1 -0
- package/dist/tests/index.d.ts +2 -0
- package/dist/tests/index.js +231 -0
- package/dist/tests/runner.d.ts +38 -0
- package/dist/tests/runner.js +189 -0
- package/dist/tests/runner.test.d.ts +1 -0
- package/dist/tests/spec.d.ts +82 -0
- package/dist/tests/spec.js +74 -0
- package/dist/tests/spec.test.d.ts +1 -0
- package/dist/themes.d.ts +50 -0
- package/dist/themes.js +225 -0
- package/dist/themes.test.d.ts +1 -0
- package/dist/translations/catalog.d.ts +25 -0
- package/dist/translations/catalog.js +1 -0
- package/dist/translations/index.d.ts +44 -0
- package/dist/translations/index.js +533 -0
- package/dist/translations/registry.d.ts +172 -0
- package/dist/translations/registry.js +170 -0
- package/dist/translations/registry.test.d.ts +1 -0
- package/dist/translations/spec.d.ts +153 -0
- package/dist/translations/spec.js +36 -0
- package/dist/translations/spec.test.d.ts +1 -0
- package/dist/translations/tenant.d.ts +11 -0
- package/dist/translations/tenant.js +1 -0
- package/dist/translations/validation.d.ts +106 -0
- package/dist/translations/validation.js +392 -0
- package/dist/translations/validation.test.d.ts +1 -0
- package/dist/types.d.ts +212 -0
- package/dist/types.js +1 -0
- package/dist/versioning/index.d.ts +9 -0
- package/dist/versioning/index.js +274 -0
- package/dist/versioning/refs.d.ts +176 -0
- package/dist/versioning/refs.js +99 -0
- package/dist/versioning/refs.test.d.ts +4 -0
- package/dist/versioning/types.d.ts +130 -0
- package/dist/versioning/types.js +55 -0
- package/dist/versioning/utils.d.ts +93 -0
- package/dist/versioning/utils.js +184 -0
- package/dist/versioning/utils.test.d.ts +4 -0
- package/dist/workflow/adapters/db-adapter.d.ts +43 -0
- package/dist/workflow/adapters/db-adapter.js +127 -0
- package/dist/workflow/adapters/file-adapter.d.ts +10 -0
- package/dist/workflow/adapters/file-adapter.js +38 -0
- package/dist/workflow/adapters/index.d.ts +3 -0
- package/dist/workflow/adapters/index.js +194 -0
- package/dist/workflow/adapters/memory-store.d.ts +13 -0
- package/dist/workflow/adapters/memory-store.js +93 -0
- package/dist/workflow/context.d.ts +217 -0
- package/dist/workflow/context.js +247 -0
- package/dist/workflow/context.test.d.ts +1 -0
- package/dist/workflow/expression.d.ts +6 -0
- package/dist/workflow/expression.js +157 -0
- package/dist/workflow/expression.test.d.ts +1 -0
- package/dist/workflow/index.d.ts +13 -0
- package/dist/workflow/index.js +1546 -0
- package/dist/workflow/overview.docblock.d.ts +2 -0
- package/dist/workflow/overview.docblock.js +164 -0
- package/dist/workflow/runner.d.ts +71 -0
- package/dist/workflow/runner.js +532 -0
- package/dist/workflow/runner.test.d.ts +1 -0
- package/dist/workflow/sla-monitor.d.ts +16 -0
- package/dist/workflow/sla-monitor.js +84 -0
- package/dist/workflow/spec.d.ts +81 -0
- package/dist/workflow/spec.js +221 -0
- package/dist/workflow/state.d.ts +31 -0
- package/dist/workflow/state.js +1 -0
- package/dist/workflow/validation.d.ts +87 -0
- package/dist/workflow/validation.js +425 -0
- package/dist/workflow/validation.test.d.ts +1 -0
- package/dist/workspace-config/contractsrc-schema.d.ts +144 -0
- package/dist/workspace-config/contractsrc-schema.js +344 -0
- package/dist/workspace-config/contractsrc-schema.test.d.ts +1 -0
- package/dist/workspace-config/contractsrc-types.d.ts +342 -0
- package/dist/workspace-config/contractsrc-types.js +1 -0
- package/dist/workspace-config/index.d.ts +5 -0
- package/dist/workspace-config/index.js +325 -0
- package/dist/workspace-config/workspace-config.docblock.d.ts +2 -0
- package/dist/workspace-config/workspace-config.docblock.js +188 -0
- package/package.json +4426 -0
|
@@ -0,0 +1,2899 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
7
|
+
var __toCommonJS = (from) => {
|
|
8
|
+
var entry = __moduleCache.get(from), desc;
|
|
9
|
+
if (entry)
|
|
10
|
+
return entry;
|
|
11
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
13
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
14
|
+
get: () => from[key],
|
|
15
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
+
}));
|
|
17
|
+
__moduleCache.set(from, entry);
|
|
18
|
+
return entry;
|
|
19
|
+
};
|
|
20
|
+
var __export = (target, all) => {
|
|
21
|
+
for (var name in all)
|
|
22
|
+
__defProp(target, name, {
|
|
23
|
+
get: all[name],
|
|
24
|
+
enumerable: true,
|
|
25
|
+
configurable: true,
|
|
26
|
+
set: (newValue) => all[name] = () => newValue
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
30
|
+
var __require = import.meta.require;
|
|
31
|
+
|
|
32
|
+
// src/registry-utils.ts
|
|
33
|
+
var exports_registry_utils = {};
|
|
34
|
+
__export(exports_registry_utils, {
|
|
35
|
+
groupByToArray: () => groupByToArray,
|
|
36
|
+
groupByMultiple: () => groupByMultiple,
|
|
37
|
+
groupBy: () => groupBy,
|
|
38
|
+
getUniqueTags: () => getUniqueTags,
|
|
39
|
+
getUniqueOwners: () => getUniqueOwners,
|
|
40
|
+
getUniqueDomains: () => getUniqueDomains,
|
|
41
|
+
filterBy: () => filterBy,
|
|
42
|
+
GroupingStrategies: () => GroupingStrategies
|
|
43
|
+
});
|
|
44
|
+
function filterBy(items, filter) {
|
|
45
|
+
return items.filter((item) => {
|
|
46
|
+
if (filter.tags?.length) {
|
|
47
|
+
const hasMatchingTag = filter.tags.some((tag) => item.meta.tags?.includes(tag));
|
|
48
|
+
if (!hasMatchingTag)
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
if (filter.owners?.length) {
|
|
52
|
+
const hasMatchingOwner = filter.owners.some((owner) => item.meta.owners?.includes(owner));
|
|
53
|
+
if (!hasMatchingOwner)
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
if (filter.stability?.length) {
|
|
57
|
+
if (!filter.stability.includes(item.meta.stability ?? "stable")) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (filter.domain) {
|
|
62
|
+
const itemDomain = GroupingStrategies.byDomain(item);
|
|
63
|
+
if (itemDomain !== filter.domain)
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
if (filter.keyPattern) {
|
|
67
|
+
const name = item.meta.key ?? item.meta.key ?? "";
|
|
68
|
+
const pattern = filter.keyPattern.replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
69
|
+
const regex = new RegExp(`^${pattern}$`, "i");
|
|
70
|
+
if (!regex.test(name))
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
return true;
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
function groupBy(items, keyFn) {
|
|
77
|
+
const groups = new Map;
|
|
78
|
+
for (const item of items) {
|
|
79
|
+
const key = keyFn(item);
|
|
80
|
+
const existing = groups.get(key);
|
|
81
|
+
if (existing) {
|
|
82
|
+
existing.push(item);
|
|
83
|
+
} else {
|
|
84
|
+
groups.set(key, [item]);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return groups;
|
|
88
|
+
}
|
|
89
|
+
function groupByToArray(items, keyFn) {
|
|
90
|
+
const map = groupBy(items, keyFn);
|
|
91
|
+
return Array.from(map.entries()).map(([key, items2]) => ({ key, items: items2 }));
|
|
92
|
+
}
|
|
93
|
+
function groupByMultiple(items, keysFn) {
|
|
94
|
+
const groups = new Map;
|
|
95
|
+
for (const item of items) {
|
|
96
|
+
const keys = keysFn(item);
|
|
97
|
+
for (const key of keys) {
|
|
98
|
+
const existing = groups.get(key);
|
|
99
|
+
if (existing) {
|
|
100
|
+
existing.push(item);
|
|
101
|
+
} else {
|
|
102
|
+
groups.set(key, [item]);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return groups;
|
|
107
|
+
}
|
|
108
|
+
function getUniqueTags(items) {
|
|
109
|
+
const tags = new Set;
|
|
110
|
+
for (const item of items) {
|
|
111
|
+
for (const tag of item.meta.tags ?? []) {
|
|
112
|
+
tags.add(tag);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return Array.from(tags).sort();
|
|
116
|
+
}
|
|
117
|
+
function getUniqueOwners(items) {
|
|
118
|
+
const owners = new Set;
|
|
119
|
+
for (const item of items) {
|
|
120
|
+
for (const owner of item.meta.owners ?? []) {
|
|
121
|
+
owners.add(owner);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return Array.from(owners).sort();
|
|
125
|
+
}
|
|
126
|
+
function getUniqueDomains(items) {
|
|
127
|
+
const domains = new Set;
|
|
128
|
+
for (const item of items) {
|
|
129
|
+
domains.add(GroupingStrategies.byDomain(item));
|
|
130
|
+
}
|
|
131
|
+
return Array.from(domains).sort();
|
|
132
|
+
}
|
|
133
|
+
var GroupingStrategies;
|
|
134
|
+
var init_registry_utils = __esm(() => {
|
|
135
|
+
GroupingStrategies = {
|
|
136
|
+
byTag: (item) => item.meta.tags?.[0] ?? "untagged",
|
|
137
|
+
byAllTags: (item) => item.meta.tags?.length ? item.meta.tags : ["untagged"],
|
|
138
|
+
byOwner: (item) => item.meta.owners?.[0] ?? "unowned",
|
|
139
|
+
byDomain: (item) => {
|
|
140
|
+
const name = item.meta.key ?? item.meta.key ?? "";
|
|
141
|
+
return name.split(".")[0] ?? "default";
|
|
142
|
+
},
|
|
143
|
+
byStability: (item) => item.meta.stability ?? "stable",
|
|
144
|
+
byUrlPath: (level) => (item) => {
|
|
145
|
+
if (!item.path)
|
|
146
|
+
return "root";
|
|
147
|
+
const segments = item.path.split("/").filter(Boolean);
|
|
148
|
+
return segments.slice(0, level).join("/") || "root";
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// src/capabilities/capabilities.ts
|
|
154
|
+
import { compareVersions } from "compare-versions";
|
|
155
|
+
var capKey = (key, version) => `${key}.v${version}`;
|
|
156
|
+
|
|
157
|
+
class CapabilityRegistry {
|
|
158
|
+
items = new Map;
|
|
159
|
+
surfaceIndex = null;
|
|
160
|
+
register(spec) {
|
|
161
|
+
const key = capKey(spec.meta.key, spec.meta.version);
|
|
162
|
+
if (this.items.has(key))
|
|
163
|
+
throw new Error(`Duplicate capability ${key}`);
|
|
164
|
+
this.items.set(key, spec);
|
|
165
|
+
this.surfaceIndex = null;
|
|
166
|
+
return this;
|
|
167
|
+
}
|
|
168
|
+
list() {
|
|
169
|
+
return [...this.items.values()];
|
|
170
|
+
}
|
|
171
|
+
get(key, version) {
|
|
172
|
+
if (version != null)
|
|
173
|
+
return this.items.get(capKey(key, version));
|
|
174
|
+
let candidate;
|
|
175
|
+
for (const spec of this.items.values()) {
|
|
176
|
+
if (spec.meta.key !== key)
|
|
177
|
+
continue;
|
|
178
|
+
if (!candidate || compareVersions(spec.meta.version, candidate.meta.version) > 0) {
|
|
179
|
+
candidate = spec;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return candidate;
|
|
183
|
+
}
|
|
184
|
+
satisfies(requirement, additional) {
|
|
185
|
+
if (requirement.optional)
|
|
186
|
+
return true;
|
|
187
|
+
if (additional?.some((ref) => matchesRequirement(ref, requirement)))
|
|
188
|
+
return true;
|
|
189
|
+
const spec = requirement.version ? this.get(requirement.key, requirement.version) : this.get(requirement.key);
|
|
190
|
+
if (!spec)
|
|
191
|
+
return false;
|
|
192
|
+
if (requirement.kind && spec.meta.kind !== requirement.kind)
|
|
193
|
+
return false;
|
|
194
|
+
if (requirement.version != null && spec.meta.version !== requirement.version)
|
|
195
|
+
return false;
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
buildSurfaceIndex() {
|
|
199
|
+
if (this.surfaceIndex)
|
|
200
|
+
return this.surfaceIndex;
|
|
201
|
+
this.surfaceIndex = new Map;
|
|
202
|
+
for (const spec of this.items.values()) {
|
|
203
|
+
const capabilityKey = capKey(spec.meta.key, spec.meta.version);
|
|
204
|
+
for (const surface of spec.provides ?? []) {
|
|
205
|
+
const surfaceKey = `${surface.surface}:${surface.key}`;
|
|
206
|
+
if (!this.surfaceIndex.has(surfaceKey)) {
|
|
207
|
+
this.surfaceIndex.set(surfaceKey, new Set);
|
|
208
|
+
}
|
|
209
|
+
this.surfaceIndex.get(surfaceKey)?.add(capabilityKey);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return this.surfaceIndex;
|
|
213
|
+
}
|
|
214
|
+
getOperationsFor(capabilityKey, version) {
|
|
215
|
+
const spec = this.get(capabilityKey, version);
|
|
216
|
+
if (!spec)
|
|
217
|
+
return [];
|
|
218
|
+
return spec.provides?.filter((s) => s.surface === "operation").map((s) => s.key) ?? [];
|
|
219
|
+
}
|
|
220
|
+
getEventsFor(capabilityKey, version) {
|
|
221
|
+
const spec = this.get(capabilityKey, version);
|
|
222
|
+
if (!spec)
|
|
223
|
+
return [];
|
|
224
|
+
return spec.provides?.filter((s) => s.surface === "event").map((s) => s.key) ?? [];
|
|
225
|
+
}
|
|
226
|
+
getPresentationsFor(capabilityKey, version) {
|
|
227
|
+
const spec = this.get(capabilityKey, version);
|
|
228
|
+
if (!spec)
|
|
229
|
+
return [];
|
|
230
|
+
return spec.provides?.filter((s) => s.surface === "presentation").map((s) => s.key) ?? [];
|
|
231
|
+
}
|
|
232
|
+
getWorkflowsFor(capabilityKey, version) {
|
|
233
|
+
const spec = this.get(capabilityKey, version);
|
|
234
|
+
if (!spec)
|
|
235
|
+
return [];
|
|
236
|
+
return spec.provides?.filter((s) => s.surface === "workflow").map((s) => s.key) ?? [];
|
|
237
|
+
}
|
|
238
|
+
getResourcesFor(capabilityKey, version) {
|
|
239
|
+
const spec = this.get(capabilityKey, version);
|
|
240
|
+
if (!spec)
|
|
241
|
+
return [];
|
|
242
|
+
return spec.provides?.filter((s) => s.surface === "resource").map((s) => s.key) ?? [];
|
|
243
|
+
}
|
|
244
|
+
getCapabilitiesForOperation(operationKey) {
|
|
245
|
+
const index = this.buildSurfaceIndex();
|
|
246
|
+
const capKeys = index.get(`operation:${operationKey}`);
|
|
247
|
+
if (!capKeys)
|
|
248
|
+
return [];
|
|
249
|
+
return [...capKeys].map((k) => {
|
|
250
|
+
const spec = this.items.get(k);
|
|
251
|
+
return { key: spec?.meta.key ?? "", version: spec?.meta.version ?? "" };
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
getCapabilitiesForEvent(eventKey) {
|
|
255
|
+
const index = this.buildSurfaceIndex();
|
|
256
|
+
const capKeys = index.get(`event:${eventKey}`);
|
|
257
|
+
if (!capKeys)
|
|
258
|
+
return [];
|
|
259
|
+
return [...capKeys].map((k) => {
|
|
260
|
+
const spec = this.items.get(k);
|
|
261
|
+
return { key: spec?.meta.key ?? "", version: spec?.meta.version ?? "" };
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
getCapabilitiesForPresentation(presentationKey) {
|
|
265
|
+
const index = this.buildSurfaceIndex();
|
|
266
|
+
const capKeys = index.get(`presentation:${presentationKey}`);
|
|
267
|
+
if (!capKeys)
|
|
268
|
+
return [];
|
|
269
|
+
return [...capKeys].map((k) => {
|
|
270
|
+
const spec = this.items.get(k);
|
|
271
|
+
return { key: spec?.meta.key ?? "", version: spec?.meta.version ?? "" };
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
getAncestors(capabilityKey, version) {
|
|
275
|
+
const ancestors = [];
|
|
276
|
+
const visited = new Set;
|
|
277
|
+
let current = this.get(capabilityKey, version);
|
|
278
|
+
while (current?.extends) {
|
|
279
|
+
const parentKey = capKey(current.extends.key, current.extends.version);
|
|
280
|
+
if (visited.has(parentKey)) {
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
visited.add(parentKey);
|
|
284
|
+
const parent = this.get(current.extends.key, current.extends.version);
|
|
285
|
+
if (!parent)
|
|
286
|
+
break;
|
|
287
|
+
ancestors.push(parent);
|
|
288
|
+
current = parent;
|
|
289
|
+
}
|
|
290
|
+
return ancestors;
|
|
291
|
+
}
|
|
292
|
+
getEffectiveRequirements(capabilityKey, version) {
|
|
293
|
+
const spec = this.get(capabilityKey, version);
|
|
294
|
+
if (!spec)
|
|
295
|
+
return [];
|
|
296
|
+
const ancestors = this.getAncestors(capabilityKey, version);
|
|
297
|
+
const requirementMap = new Map;
|
|
298
|
+
for (const ancestor of [...ancestors].reverse()) {
|
|
299
|
+
for (const req of ancestor.requires ?? []) {
|
|
300
|
+
requirementMap.set(req.key, req);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
for (const req of spec.requires ?? []) {
|
|
304
|
+
requirementMap.set(req.key, req);
|
|
305
|
+
}
|
|
306
|
+
return [...requirementMap.values()];
|
|
307
|
+
}
|
|
308
|
+
getEffectiveSurfaces(capabilityKey, version) {
|
|
309
|
+
const spec = this.get(capabilityKey, version);
|
|
310
|
+
if (!spec)
|
|
311
|
+
return [];
|
|
312
|
+
const ancestors = this.getAncestors(capabilityKey, version);
|
|
313
|
+
const surfaces = [];
|
|
314
|
+
for (const ancestor of [...ancestors].reverse()) {
|
|
315
|
+
surfaces.push(...ancestor.provides ?? []);
|
|
316
|
+
}
|
|
317
|
+
surfaces.push(...spec.provides ?? []);
|
|
318
|
+
return surfaces;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
function matchesRequirement(ref, requirement) {
|
|
322
|
+
if (ref.key !== requirement.key)
|
|
323
|
+
return false;
|
|
324
|
+
if (requirement.version != null && ref.version !== requirement.version)
|
|
325
|
+
return false;
|
|
326
|
+
return true;
|
|
327
|
+
}
|
|
328
|
+
function capabilityKey(spec) {
|
|
329
|
+
return capKey(spec.meta.key, spec.meta.version);
|
|
330
|
+
}
|
|
331
|
+
function defineCapability(spec) {
|
|
332
|
+
return spec;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// src/capabilities/validation.ts
|
|
336
|
+
function validateCapabilityConsistency(deps) {
|
|
337
|
+
const errors = [];
|
|
338
|
+
const warnings = [];
|
|
339
|
+
for (const capability of deps.capabilities.list()) {
|
|
340
|
+
const capKey2 = `${capability.meta.key}.v${capability.meta.version}`;
|
|
341
|
+
for (const surface of capability.provides ?? []) {
|
|
342
|
+
const exists = checkSurfaceExists(deps, surface.surface, surface.key);
|
|
343
|
+
if (!exists) {
|
|
344
|
+
errors.push({
|
|
345
|
+
type: "missing_surface_spec",
|
|
346
|
+
message: `Capability "${capKey2}" provides ${surface.surface} "${surface.key}" but spec not found`,
|
|
347
|
+
capabilityKey: capKey2,
|
|
348
|
+
surface: surface.surface,
|
|
349
|
+
specKey: surface.key
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
if (deps.operations) {
|
|
355
|
+
for (const op of deps.operations.list()) {
|
|
356
|
+
if (op.capability) {
|
|
357
|
+
const capSpec = deps.capabilities.get(op.capability.key, op.capability.version);
|
|
358
|
+
if (!capSpec) {
|
|
359
|
+
errors.push({
|
|
360
|
+
type: "capability_not_found",
|
|
361
|
+
message: `Operation "${op.meta.key}" references capability "${op.capability.key}.v${op.capability.version}" but capability not found`,
|
|
362
|
+
specKey: op.meta.key,
|
|
363
|
+
capabilityKey: `${op.capability.key}.v${op.capability.version}`,
|
|
364
|
+
surface: "operation"
|
|
365
|
+
});
|
|
366
|
+
} else {
|
|
367
|
+
const inProvides = capSpec.provides?.some((p) => p.surface === "operation" && p.key === op.meta.key);
|
|
368
|
+
if (!inProvides) {
|
|
369
|
+
errors.push({
|
|
370
|
+
type: "surface_not_in_provides",
|
|
371
|
+
message: `Operation "${op.meta.key}" claims capability "${op.capability.key}.v${op.capability.version}" but not in capability's provides`,
|
|
372
|
+
specKey: op.meta.key,
|
|
373
|
+
capabilityKey: `${op.capability.key}.v${op.capability.version}`,
|
|
374
|
+
surface: "operation"
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
if (deps.events) {
|
|
382
|
+
for (const event of deps.events.list()) {
|
|
383
|
+
if (event.capability) {
|
|
384
|
+
const capSpec = deps.capabilities.get(event.capability.key, event.capability.version);
|
|
385
|
+
if (!capSpec) {
|
|
386
|
+
errors.push({
|
|
387
|
+
type: "capability_not_found",
|
|
388
|
+
message: `Event "${event.meta.key}" references capability "${event.capability.key}.v${event.capability.version}" but capability not found`,
|
|
389
|
+
specKey: event.meta.key,
|
|
390
|
+
capabilityKey: `${event.capability.key}.v${event.capability.version}`,
|
|
391
|
+
surface: "event"
|
|
392
|
+
});
|
|
393
|
+
} else {
|
|
394
|
+
const inProvides = capSpec.provides?.some((p) => p.surface === "event" && p.key === event.meta.key);
|
|
395
|
+
if (!inProvides) {
|
|
396
|
+
errors.push({
|
|
397
|
+
type: "surface_not_in_provides",
|
|
398
|
+
message: `Event "${event.meta.key}" claims capability "${event.capability.key}.v${event.capability.version}" but not in capability's provides`,
|
|
399
|
+
specKey: event.meta.key,
|
|
400
|
+
capabilityKey: `${event.capability.key}.v${event.capability.version}`,
|
|
401
|
+
surface: "event"
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
if (deps.presentations) {
|
|
409
|
+
for (const pres of deps.presentations.list()) {
|
|
410
|
+
if (pres.capability) {
|
|
411
|
+
const capSpec = deps.capabilities.get(pres.capability.key, pres.capability.version);
|
|
412
|
+
if (!capSpec) {
|
|
413
|
+
errors.push({
|
|
414
|
+
type: "capability_not_found",
|
|
415
|
+
message: `Presentation "${pres.meta.key}" references capability "${pres.capability.key}.v${pres.capability.version}" but capability not found`,
|
|
416
|
+
specKey: pres.meta.key,
|
|
417
|
+
capabilityKey: `${pres.capability.key}.v${pres.capability.version}`,
|
|
418
|
+
surface: "presentation"
|
|
419
|
+
});
|
|
420
|
+
} else {
|
|
421
|
+
const inProvides = capSpec.provides?.some((p) => p.surface === "presentation" && p.key === pres.meta.key);
|
|
422
|
+
if (!inProvides) {
|
|
423
|
+
errors.push({
|
|
424
|
+
type: "surface_not_in_provides",
|
|
425
|
+
message: `Presentation "${pres.meta.key}" claims capability "${pres.capability.key}.v${pres.capability.version}" but not in capability's provides`,
|
|
426
|
+
specKey: pres.meta.key,
|
|
427
|
+
capabilityKey: `${pres.capability.key}.v${pres.capability.version}`,
|
|
428
|
+
surface: "presentation"
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
return {
|
|
436
|
+
valid: errors.length === 0,
|
|
437
|
+
errors,
|
|
438
|
+
warnings
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
function checkSurfaceExists(deps, surface, key) {
|
|
442
|
+
switch (surface) {
|
|
443
|
+
case "operation":
|
|
444
|
+
return deps.operations?.has(key) ?? true;
|
|
445
|
+
case "event":
|
|
446
|
+
return deps.events?.has(key) ?? true;
|
|
447
|
+
case "presentation":
|
|
448
|
+
return deps.presentations?.has(key) ?? true;
|
|
449
|
+
case "workflow":
|
|
450
|
+
case "resource":
|
|
451
|
+
return true;
|
|
452
|
+
default:
|
|
453
|
+
return true;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
function findOrphanSpecs(deps) {
|
|
457
|
+
const result = {
|
|
458
|
+
operations: [],
|
|
459
|
+
events: [],
|
|
460
|
+
presentations: []
|
|
461
|
+
};
|
|
462
|
+
if (deps.operations) {
|
|
463
|
+
for (const op of deps.operations.list()) {
|
|
464
|
+
if (!op.capability) {
|
|
465
|
+
result.operations.push(op.meta.key);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
if (deps.events) {
|
|
470
|
+
for (const event of deps.events.list()) {
|
|
471
|
+
if (!event.capability) {
|
|
472
|
+
result.events.push(event.meta.key);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
if (deps.presentations) {
|
|
477
|
+
for (const pres of deps.presentations.list()) {
|
|
478
|
+
if (!pres.capability) {
|
|
479
|
+
result.presentations.push(pres.meta.key);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
return result;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// src/capabilities/context.ts
|
|
487
|
+
class CapabilityMissingError extends Error {
|
|
488
|
+
capabilityKey;
|
|
489
|
+
requiredVersion;
|
|
490
|
+
constructor(capabilityKey2, requiredVersion) {
|
|
491
|
+
const versionSuffix = requiredVersion ? `.v${requiredVersion}` : "";
|
|
492
|
+
super(`Missing required capability: ${capabilityKey2}${versionSuffix}`);
|
|
493
|
+
this.name = "CapabilityMissingError";
|
|
494
|
+
this.capabilityKey = capabilityKey2;
|
|
495
|
+
this.requiredVersion = requiredVersion;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
class CapabilityContextImpl {
|
|
500
|
+
capabilities;
|
|
501
|
+
capabilityVersions;
|
|
502
|
+
constructor(enabledCapabilities) {
|
|
503
|
+
const capSet = new Set;
|
|
504
|
+
const versionMap = new Map;
|
|
505
|
+
for (const cap of enabledCapabilities) {
|
|
506
|
+
capSet.add(cap.key);
|
|
507
|
+
versionMap.set(cap.key, cap.version);
|
|
508
|
+
}
|
|
509
|
+
this.capabilities = capSet;
|
|
510
|
+
this.capabilityVersions = versionMap;
|
|
511
|
+
}
|
|
512
|
+
hasCapability(key, version) {
|
|
513
|
+
if (!this.capabilities.has(key))
|
|
514
|
+
return false;
|
|
515
|
+
if (version != null) {
|
|
516
|
+
const enabledVersion = this.capabilityVersions.get(key);
|
|
517
|
+
return enabledVersion === version;
|
|
518
|
+
}
|
|
519
|
+
return true;
|
|
520
|
+
}
|
|
521
|
+
requireCapability(key, version) {
|
|
522
|
+
if (!this.hasCapability(key, version)) {
|
|
523
|
+
throw new CapabilityMissingError(key, version);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
hasAllCapabilities(keys) {
|
|
527
|
+
return keys.every((k) => this.capabilities.has(k));
|
|
528
|
+
}
|
|
529
|
+
hasAnyCapability(keys) {
|
|
530
|
+
return keys.some((k) => this.capabilities.has(k));
|
|
531
|
+
}
|
|
532
|
+
getMatchingCapabilities(pattern) {
|
|
533
|
+
if (!pattern.includes("*")) {
|
|
534
|
+
return this.capabilities.has(pattern) ? [pattern] : [];
|
|
535
|
+
}
|
|
536
|
+
const regexPattern = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
|
|
537
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
538
|
+
return [...this.capabilities].filter((key) => regex.test(key));
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
function createCapabilityContext(enabledCapabilities) {
|
|
542
|
+
return new CapabilityContextImpl(enabledCapabilities);
|
|
543
|
+
}
|
|
544
|
+
function createEmptyCapabilityContext() {
|
|
545
|
+
return new CapabilityContextImpl([]);
|
|
546
|
+
}
|
|
547
|
+
function createBypassCapabilityContext(allCapabilities) {
|
|
548
|
+
return new CapabilityContextImpl(allCapabilities);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// src/capabilities/guards.ts
|
|
552
|
+
function checkCapabilityForOperation(ctx, operation) {
|
|
553
|
+
if (!operation.capability) {
|
|
554
|
+
return { allowed: true };
|
|
555
|
+
}
|
|
556
|
+
const { key, version } = operation.capability;
|
|
557
|
+
if (ctx.hasCapability(key, version)) {
|
|
558
|
+
return { allowed: true };
|
|
559
|
+
}
|
|
560
|
+
return {
|
|
561
|
+
allowed: false,
|
|
562
|
+
missingCapability: { key, version },
|
|
563
|
+
reason: `Operation "${operation.meta.key}" requires capability "${key}.v${version}"`
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
function assertCapabilityForOperation(ctx, operation) {
|
|
567
|
+
const result = checkCapabilityForOperation(ctx, operation);
|
|
568
|
+
if (!result.allowed && result.missingCapability) {
|
|
569
|
+
throw new CapabilityMissingError(result.missingCapability.key, result.missingCapability.version);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
function checkCapabilityForEvent(ctx, event) {
|
|
573
|
+
if (!event.capability) {
|
|
574
|
+
return { allowed: true };
|
|
575
|
+
}
|
|
576
|
+
const { key, version } = event.capability;
|
|
577
|
+
if (ctx.hasCapability(key, version)) {
|
|
578
|
+
return { allowed: true };
|
|
579
|
+
}
|
|
580
|
+
return {
|
|
581
|
+
allowed: false,
|
|
582
|
+
missingCapability: { key, version },
|
|
583
|
+
reason: `Event "${event.meta.key}" requires capability "${key}.v${version}"`
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
function assertCapabilityForEvent(ctx, event) {
|
|
587
|
+
const result = checkCapabilityForEvent(ctx, event);
|
|
588
|
+
if (!result.allowed && result.missingCapability) {
|
|
589
|
+
throw new CapabilityMissingError(result.missingCapability.key, result.missingCapability.version);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
function checkCapabilityForPresentation(ctx, presentation) {
|
|
593
|
+
if (!presentation.capability) {
|
|
594
|
+
return { allowed: true };
|
|
595
|
+
}
|
|
596
|
+
const { key, version } = presentation.capability;
|
|
597
|
+
if (ctx.hasCapability(key, version)) {
|
|
598
|
+
return { allowed: true };
|
|
599
|
+
}
|
|
600
|
+
return {
|
|
601
|
+
allowed: false,
|
|
602
|
+
missingCapability: { key, version },
|
|
603
|
+
reason: `Presentation "${presentation.meta.key}" requires capability "${key}.v${version}"`
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
function assertCapabilityForPresentation(ctx, presentation) {
|
|
607
|
+
const result = checkCapabilityForPresentation(ctx, presentation);
|
|
608
|
+
if (!result.allowed && result.missingCapability) {
|
|
609
|
+
throw new CapabilityMissingError(result.missingCapability.key, result.missingCapability.version);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
function filterOperationsByCapability(ctx, operations) {
|
|
613
|
+
return operations.filter((op) => checkCapabilityForOperation(ctx, op).allowed);
|
|
614
|
+
}
|
|
615
|
+
function filterEventsByCapability(ctx, events) {
|
|
616
|
+
return events.filter((ev) => checkCapabilityForEvent(ctx, ev).allowed);
|
|
617
|
+
}
|
|
618
|
+
function filterPresentationsByCapability(ctx, presentations) {
|
|
619
|
+
return presentations.filter((pres) => checkCapabilityForPresentation(ctx, pres).allowed);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// src/ownership.ts
|
|
623
|
+
var StabilityEnum = {
|
|
624
|
+
Idea: "idea",
|
|
625
|
+
InCreation: "in_creation",
|
|
626
|
+
Experimental: "experimental",
|
|
627
|
+
Beta: "beta",
|
|
628
|
+
Stable: "stable",
|
|
629
|
+
Deprecated: "deprecated"
|
|
630
|
+
};
|
|
631
|
+
var OwnersEnum = {
|
|
632
|
+
PlatformCore: "platform.core",
|
|
633
|
+
PlatformSigil: "platform.sigil",
|
|
634
|
+
PlatformMarketplace: "platform.marketplace",
|
|
635
|
+
PlatformMessaging: "platform.messaging",
|
|
636
|
+
PlatformContent: "platform.content",
|
|
637
|
+
PlatformFeatureFlags: "platform.featureflags",
|
|
638
|
+
PlatformFinance: "platform.finance"
|
|
639
|
+
};
|
|
640
|
+
var Owners = OwnersEnum;
|
|
641
|
+
var TagsEnum = {
|
|
642
|
+
Spots: "spots",
|
|
643
|
+
Collectivity: "collectivity",
|
|
644
|
+
Marketplace: "marketplace",
|
|
645
|
+
Sellers: "sellers",
|
|
646
|
+
Auth: "auth",
|
|
647
|
+
Login: "login",
|
|
648
|
+
Signup: "signup",
|
|
649
|
+
Guide: "guide",
|
|
650
|
+
Docs: "docs",
|
|
651
|
+
I18n: "i18n",
|
|
652
|
+
Incident: "incident",
|
|
653
|
+
Automation: "automation",
|
|
654
|
+
Hygiene: "hygiene"
|
|
655
|
+
};
|
|
656
|
+
var Tags = TagsEnum;
|
|
657
|
+
|
|
658
|
+
// src/capabilities/openbanking.ts
|
|
659
|
+
var OWNERS = ["platform.finance"];
|
|
660
|
+
var TAGS = ["open-banking", "finance"];
|
|
661
|
+
var openBankingAccountsReadCapability = {
|
|
662
|
+
meta: {
|
|
663
|
+
key: "openbanking.accounts.read",
|
|
664
|
+
version: "1.0.0",
|
|
665
|
+
kind: "integration",
|
|
666
|
+
title: "Open Banking Accounts (Read)",
|
|
667
|
+
description: "Provides read-only access to linked bank accounts, including account summaries and metadata.",
|
|
668
|
+
domain: "finance",
|
|
669
|
+
owners: [...OWNERS],
|
|
670
|
+
tags: [...TAGS],
|
|
671
|
+
stability: StabilityEnum.Experimental
|
|
672
|
+
},
|
|
673
|
+
provides: [
|
|
674
|
+
{
|
|
675
|
+
surface: "operation",
|
|
676
|
+
key: "openbanking.accounts.list",
|
|
677
|
+
version: "1.0.0",
|
|
678
|
+
description: "List bank accounts linked to a Powens open banking connection."
|
|
679
|
+
},
|
|
680
|
+
{
|
|
681
|
+
surface: "operation",
|
|
682
|
+
key: "openbanking.accounts.get",
|
|
683
|
+
version: "1.0.0",
|
|
684
|
+
description: "Retrieve the canonical bank account record for a specific account."
|
|
685
|
+
},
|
|
686
|
+
{
|
|
687
|
+
surface: "operation",
|
|
688
|
+
key: "openbanking.accounts.sync",
|
|
689
|
+
version: "1.0.0",
|
|
690
|
+
description: "Trigger a refresh of bank account metadata from the open banking provider."
|
|
691
|
+
}
|
|
692
|
+
]
|
|
693
|
+
};
|
|
694
|
+
var openBankingTransactionsReadCapability = {
|
|
695
|
+
meta: {
|
|
696
|
+
key: "openbanking.transactions.read",
|
|
697
|
+
version: "1.0.0",
|
|
698
|
+
kind: "integration",
|
|
699
|
+
title: "Open Banking Transactions (Read)",
|
|
700
|
+
description: "Enables retrieval of transaction history for linked bank accounts via open banking providers.",
|
|
701
|
+
domain: "finance",
|
|
702
|
+
owners: [...OWNERS],
|
|
703
|
+
tags: [...TAGS, "transactions"],
|
|
704
|
+
stability: StabilityEnum.Experimental
|
|
705
|
+
},
|
|
706
|
+
provides: [
|
|
707
|
+
{
|
|
708
|
+
surface: "operation",
|
|
709
|
+
key: "openbanking.transactions.list",
|
|
710
|
+
version: "1.0.0",
|
|
711
|
+
description: "List transactions for a given bank account with optional date filtering."
|
|
712
|
+
},
|
|
713
|
+
{
|
|
714
|
+
surface: "operation",
|
|
715
|
+
key: "openbanking.transactions.sync",
|
|
716
|
+
version: "1.0.0",
|
|
717
|
+
description: "Synchronise transactions from the open banking provider into the canonical ledger."
|
|
718
|
+
}
|
|
719
|
+
]
|
|
720
|
+
};
|
|
721
|
+
var openBankingBalancesReadCapability = {
|
|
722
|
+
meta: {
|
|
723
|
+
key: "openbanking.balances.read",
|
|
724
|
+
version: "1.0.0",
|
|
725
|
+
kind: "integration",
|
|
726
|
+
title: "Open Banking Balances (Read)",
|
|
727
|
+
description: "Allows querying of current and available balances for linked bank accounts via open banking providers.",
|
|
728
|
+
domain: "finance",
|
|
729
|
+
owners: [...OWNERS],
|
|
730
|
+
tags: [...TAGS, "balances"],
|
|
731
|
+
stability: StabilityEnum.Experimental
|
|
732
|
+
},
|
|
733
|
+
provides: [
|
|
734
|
+
{
|
|
735
|
+
surface: "operation",
|
|
736
|
+
key: "openbanking.balances.get",
|
|
737
|
+
version: "1.0.0",
|
|
738
|
+
description: "Retrieve the latest known balances for a specified bank account."
|
|
739
|
+
},
|
|
740
|
+
{
|
|
741
|
+
surface: "operation",
|
|
742
|
+
key: "openbanking.balances.refresh",
|
|
743
|
+
version: "1.0.0",
|
|
744
|
+
description: "Force a balance refresh from the open banking provider."
|
|
745
|
+
}
|
|
746
|
+
]
|
|
747
|
+
};
|
|
748
|
+
function registerOpenBankingCapabilities(registry) {
|
|
749
|
+
return registry.register(openBankingAccountsReadCapability).register(openBankingTransactionsReadCapability).register(openBankingBalancesReadCapability);
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// src/capabilities/meeting-recorder.ts
|
|
753
|
+
var OWNERS2 = ["platform.integrations"];
|
|
754
|
+
var TAGS2 = ["meeting-recorder", "transcripts", "integrations"];
|
|
755
|
+
var meetingRecorderMeetingsReadCapability = {
|
|
756
|
+
meta: {
|
|
757
|
+
key: "meeting-recorder.meetings.read",
|
|
758
|
+
version: "1.0.0",
|
|
759
|
+
kind: "integration",
|
|
760
|
+
title: "Meeting Recorder Meetings (Read)",
|
|
761
|
+
description: "Provides read-only access to recorded meetings and their metadata.",
|
|
762
|
+
domain: "integrations",
|
|
763
|
+
owners: [...OWNERS2],
|
|
764
|
+
tags: [...TAGS2, "meetings"],
|
|
765
|
+
stability: StabilityEnum.Experimental
|
|
766
|
+
},
|
|
767
|
+
provides: [
|
|
768
|
+
{
|
|
769
|
+
surface: "operation",
|
|
770
|
+
key: "meeting-recorder.meetings.list",
|
|
771
|
+
version: "1.0.0",
|
|
772
|
+
description: "List meetings available from the recorder provider."
|
|
773
|
+
},
|
|
774
|
+
{
|
|
775
|
+
surface: "operation",
|
|
776
|
+
key: "meeting-recorder.meetings.get",
|
|
777
|
+
version: "1.0.0",
|
|
778
|
+
description: "Fetch detailed metadata for a specific meeting."
|
|
779
|
+
}
|
|
780
|
+
]
|
|
781
|
+
};
|
|
782
|
+
var meetingRecorderTranscriptsReadCapability = {
|
|
783
|
+
meta: {
|
|
784
|
+
key: "meeting-recorder.transcripts.read",
|
|
785
|
+
version: "1.0.0",
|
|
786
|
+
kind: "integration",
|
|
787
|
+
title: "Meeting Recorder Transcripts (Read)",
|
|
788
|
+
description: "Enables retrieval of transcripts for recorded meetings from external providers.",
|
|
789
|
+
domain: "integrations",
|
|
790
|
+
owners: [...OWNERS2],
|
|
791
|
+
tags: [...TAGS2, "transcripts"],
|
|
792
|
+
stability: StabilityEnum.Experimental
|
|
793
|
+
},
|
|
794
|
+
provides: [
|
|
795
|
+
{
|
|
796
|
+
surface: "operation",
|
|
797
|
+
key: "meeting-recorder.transcripts.get",
|
|
798
|
+
version: "1.0.0",
|
|
799
|
+
description: "Fetch the transcript for a specific meeting recording."
|
|
800
|
+
},
|
|
801
|
+
{
|
|
802
|
+
surface: "operation",
|
|
803
|
+
key: "meeting-recorder.transcripts.sync",
|
|
804
|
+
version: "1.0.0",
|
|
805
|
+
description: "Trigger a transcript sync from the recorder provider."
|
|
806
|
+
}
|
|
807
|
+
]
|
|
808
|
+
};
|
|
809
|
+
var meetingRecorderWebhooksCapability = {
|
|
810
|
+
meta: {
|
|
811
|
+
key: "meeting-recorder.webhooks",
|
|
812
|
+
version: "1.0.0",
|
|
813
|
+
kind: "integration",
|
|
814
|
+
title: "Meeting Recorder Webhooks",
|
|
815
|
+
description: "Allows processing of webhook events for meeting transcript readiness.",
|
|
816
|
+
domain: "integrations",
|
|
817
|
+
owners: [...OWNERS2],
|
|
818
|
+
tags: [...TAGS2, "webhooks"],
|
|
819
|
+
stability: StabilityEnum.Experimental
|
|
820
|
+
},
|
|
821
|
+
provides: [
|
|
822
|
+
{
|
|
823
|
+
surface: "operation",
|
|
824
|
+
key: "meeting-recorder.webhooks.ingest",
|
|
825
|
+
version: "1.0.0",
|
|
826
|
+
description: "Ingest and verify meeting recorder webhook payloads."
|
|
827
|
+
}
|
|
828
|
+
]
|
|
829
|
+
};
|
|
830
|
+
function registerMeetingRecorderCapabilities(registry) {
|
|
831
|
+
return registry.register(meetingRecorderMeetingsReadCapability).register(meetingRecorderTranscriptsReadCapability).register(meetingRecorderWebhooksCapability);
|
|
832
|
+
}
|
|
833
|
+
// src/app-config/app-config.capability.ts
|
|
834
|
+
var AppConfigCapability = defineCapability({
|
|
835
|
+
meta: {
|
|
836
|
+
key: "app-config",
|
|
837
|
+
version: "1.0.0",
|
|
838
|
+
title: "App Configuration Capability",
|
|
839
|
+
description: "Provides tenant app configuration lifecycle management.",
|
|
840
|
+
domain: "platform",
|
|
841
|
+
owners: [OwnersEnum.PlatformSigil],
|
|
842
|
+
tags: [TagsEnum.Hygiene],
|
|
843
|
+
kind: "api",
|
|
844
|
+
stability: StabilityEnum.Stable
|
|
845
|
+
},
|
|
846
|
+
provides: [],
|
|
847
|
+
requires: []
|
|
848
|
+
});
|
|
849
|
+
|
|
850
|
+
// src/operations/operation.ts
|
|
851
|
+
var isEmitDeclRef = (e) => ("ref" in e);
|
|
852
|
+
var defineCommand = (spec) => ({
|
|
853
|
+
...spec,
|
|
854
|
+
meta: { ...spec.meta, kind: "command" },
|
|
855
|
+
policy: {
|
|
856
|
+
...spec.policy,
|
|
857
|
+
idempotent: spec.policy?.["policy"]?.idempotent ?? false
|
|
858
|
+
}
|
|
859
|
+
});
|
|
860
|
+
var defineQuery = (spec) => ({
|
|
861
|
+
...spec,
|
|
862
|
+
meta: { ...spec.meta, kind: "query" },
|
|
863
|
+
policy: { ...spec.policy, idempotent: true }
|
|
864
|
+
});
|
|
865
|
+
|
|
866
|
+
// src/registry.ts
|
|
867
|
+
init_registry_utils();
|
|
868
|
+
import { compareVersions as compareVersions2 } from "compare-versions";
|
|
869
|
+
var keyOfSpecContract = (spec) => `${spec.meta.key}.v${spec.meta.version}`;
|
|
870
|
+
|
|
871
|
+
class SpecContractRegistry {
|
|
872
|
+
contractType;
|
|
873
|
+
items = new Map;
|
|
874
|
+
constructor(contractType, items) {
|
|
875
|
+
this.contractType = contractType;
|
|
876
|
+
if (items) {
|
|
877
|
+
items.forEach((p) => this.register(p));
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
register(p) {
|
|
881
|
+
const key = keyOfSpecContract(p);
|
|
882
|
+
if (this.items.has(key))
|
|
883
|
+
throw new Error(`Duplicate contract \`${this.contractType}\` ${key}`);
|
|
884
|
+
this.items.set(key, p);
|
|
885
|
+
return this;
|
|
886
|
+
}
|
|
887
|
+
count() {
|
|
888
|
+
return this.items.size;
|
|
889
|
+
}
|
|
890
|
+
list() {
|
|
891
|
+
return [...this.items.values()];
|
|
892
|
+
}
|
|
893
|
+
get(key, version) {
|
|
894
|
+
if (version != null)
|
|
895
|
+
return this.items.get(`${key}.v${version}`);
|
|
896
|
+
let candidate;
|
|
897
|
+
for (const [k, p] of this.items.entries()) {
|
|
898
|
+
if (!k.startsWith(`${key}.v`))
|
|
899
|
+
continue;
|
|
900
|
+
if (!candidate || compareVersions2(p.meta.version, candidate.meta.version) > 0) {
|
|
901
|
+
candidate = p;
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
return candidate;
|
|
905
|
+
}
|
|
906
|
+
has(key, version) {
|
|
907
|
+
return !!this.get(key, version);
|
|
908
|
+
}
|
|
909
|
+
filter(criteria) {
|
|
910
|
+
return filterBy(this.list(), criteria);
|
|
911
|
+
}
|
|
912
|
+
listByTag(tag) {
|
|
913
|
+
return this.list().filter((p) => p.meta.tags?.includes(tag));
|
|
914
|
+
}
|
|
915
|
+
listByOwner(owner) {
|
|
916
|
+
return this.list().filter((p) => p.meta.owners?.includes(owner));
|
|
917
|
+
}
|
|
918
|
+
groupBy(keyFn) {
|
|
919
|
+
return groupBy(this.list(), keyFn);
|
|
920
|
+
}
|
|
921
|
+
getUniqueTags() {
|
|
922
|
+
return getUniqueTags(this.list());
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
// src/events.ts
|
|
927
|
+
function defineEvent(e) {
|
|
928
|
+
return e;
|
|
929
|
+
}
|
|
930
|
+
var eventKey = (key, version) => `${key}.v${version}`;
|
|
931
|
+
|
|
932
|
+
class EventRegistry extends SpecContractRegistry {
|
|
933
|
+
constructor(items) {
|
|
934
|
+
super("event", items);
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
// src/operations/registry.ts
|
|
939
|
+
function opKey(key, version) {
|
|
940
|
+
return `${key}.v${version}`;
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
class OperationSpecRegistry extends SpecContractRegistry {
|
|
944
|
+
handlers = new Map;
|
|
945
|
+
constructor(items) {
|
|
946
|
+
super("operation", items);
|
|
947
|
+
}
|
|
948
|
+
bind(spec, handler) {
|
|
949
|
+
const key = opKey(spec.meta.key, spec.meta.version);
|
|
950
|
+
if (!this.items.has(key))
|
|
951
|
+
throw new Error(`Cannot bind; spec not found: ${key}`);
|
|
952
|
+
if (this.handlers.has(key))
|
|
953
|
+
throw new Error(`Handler already bound for ${key}`);
|
|
954
|
+
this.handlers.set(key, handler);
|
|
955
|
+
return this;
|
|
956
|
+
}
|
|
957
|
+
getHandler(key, version) {
|
|
958
|
+
const spec = this.get(key, version);
|
|
959
|
+
if (!spec)
|
|
960
|
+
return;
|
|
961
|
+
return this.handlers.get(opKey(spec.meta.key, spec.meta.version));
|
|
962
|
+
}
|
|
963
|
+
listBound() {
|
|
964
|
+
const out = [];
|
|
965
|
+
for (const [k, spec] of this.items.entries()) {
|
|
966
|
+
const h = this.handlers.get(k);
|
|
967
|
+
if (h)
|
|
968
|
+
out.push({ spec, handler: h });
|
|
969
|
+
}
|
|
970
|
+
return out;
|
|
971
|
+
}
|
|
972
|
+
async execute(key, version, rawInput, ctx) {
|
|
973
|
+
const baseSpec = this.get(key, version);
|
|
974
|
+
if (!baseSpec)
|
|
975
|
+
throw new Error(`Spec not found for ${key}${version ? `.v${version}` : ""}`);
|
|
976
|
+
const spec = await ctx.specVariantResolver?.resolve({
|
|
977
|
+
name: baseSpec.meta.key,
|
|
978
|
+
version: baseSpec.meta.version,
|
|
979
|
+
kind: baseSpec.meta.kind
|
|
980
|
+
}, ctx) ?? baseSpec;
|
|
981
|
+
let handlerKey = opKey(spec.meta.key, spec.meta.version);
|
|
982
|
+
let handler = this.handlers.get(handlerKey);
|
|
983
|
+
if (!handler) {
|
|
984
|
+
const fallbackKey = opKey(baseSpec.meta.key, baseSpec.meta.version);
|
|
985
|
+
handler = this.handlers.get(fallbackKey);
|
|
986
|
+
handlerKey = fallbackKey;
|
|
987
|
+
}
|
|
988
|
+
if (!handler)
|
|
989
|
+
throw new Error(`No handler bound for ${handlerKey}`);
|
|
990
|
+
const parsedInput = spec.io.input?.getZod().parse(rawInput);
|
|
991
|
+
if (ctx.decide) {
|
|
992
|
+
const [service, command] = spec.meta.key.split(".");
|
|
993
|
+
if (!service || !command)
|
|
994
|
+
throw new Error(`Invalid spec name: ${spec.meta.key}`);
|
|
995
|
+
const decision = await ctx.decide({
|
|
996
|
+
service,
|
|
997
|
+
command,
|
|
998
|
+
version: spec.meta.version,
|
|
999
|
+
actor: ctx.actor ?? "anonymous",
|
|
1000
|
+
channel: ctx.channel,
|
|
1001
|
+
roles: ctx.roles,
|
|
1002
|
+
organizationId: ctx.organizationId,
|
|
1003
|
+
userId: ctx.userId,
|
|
1004
|
+
flags: []
|
|
1005
|
+
});
|
|
1006
|
+
if (decision.effect === "deny") {
|
|
1007
|
+
throw new Error(`PolicyDenied: ${spec.meta.key}.v${spec.meta.version}`);
|
|
1008
|
+
}
|
|
1009
|
+
if (decision.rateLimit && ctx.rateLimit) {
|
|
1010
|
+
const key2 = decision.rateLimit.key ?? "default";
|
|
1011
|
+
const rpm = decision.rateLimit.rpm ?? 60;
|
|
1012
|
+
await ctx.rateLimit(key2, 1, rpm);
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
const allowedEvents = new Map;
|
|
1016
|
+
if (spec.sideEffects?.emits) {
|
|
1017
|
+
for (const e of spec.sideEffects.emits) {
|
|
1018
|
+
if (isEmitDeclRef(e)) {
|
|
1019
|
+
const eventSpec = ctx.eventSpecResolver?.get(e.ref.key, e.ref.version);
|
|
1020
|
+
if (eventSpec) {
|
|
1021
|
+
allowedEvents.set(`${e.ref.key}.v${e.ref.version}`, eventSpec.payload);
|
|
1022
|
+
}
|
|
1023
|
+
} else {
|
|
1024
|
+
allowedEvents.set(`${e.key}.v${e.version}`, e.payload);
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
const emitGuard = async (eventName, eventVersion, payload) => {
|
|
1029
|
+
const key2 = eventKey(eventName, eventVersion);
|
|
1030
|
+
const schema = allowedEvents.get(key2);
|
|
1031
|
+
if (!schema)
|
|
1032
|
+
throw new Error(`UndeclaredEvent: ${key2} not allowed by ${opKey(spec.meta.key, spec.meta.version)}`);
|
|
1033
|
+
const parsed = schema.getZod().parse(payload);
|
|
1034
|
+
await ctx.eventPublisher?.({
|
|
1035
|
+
key: eventName,
|
|
1036
|
+
version: eventVersion,
|
|
1037
|
+
payload: parsed,
|
|
1038
|
+
traceId: ctx.traceId
|
|
1039
|
+
});
|
|
1040
|
+
};
|
|
1041
|
+
if (ctx.appConfig) {
|
|
1042
|
+
if (!ctx.branding) {
|
|
1043
|
+
ctx.branding = ctx.appConfig.branding;
|
|
1044
|
+
}
|
|
1045
|
+
if (!ctx.translation) {
|
|
1046
|
+
ctx.translation = { config: ctx.appConfig.translation };
|
|
1047
|
+
} else if (!ctx.translation.config) {
|
|
1048
|
+
ctx.translation = {
|
|
1049
|
+
...ctx.translation,
|
|
1050
|
+
config: ctx.appConfig.translation
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
const telemetryContext = ctx.telemetry;
|
|
1055
|
+
const trackTelemetry = async (trigger, details) => {
|
|
1056
|
+
if (!telemetryContext || !trigger?.event)
|
|
1057
|
+
return;
|
|
1058
|
+
try {
|
|
1059
|
+
const props = trigger.properties?.(details) ?? {};
|
|
1060
|
+
await telemetryContext.track(trigger.event.key, trigger.event.version ?? "1.0.0", props, {
|
|
1061
|
+
tenantId: ctx.organizationId ?? undefined,
|
|
1062
|
+
organizationId: ctx.organizationId,
|
|
1063
|
+
userId: ctx.userId,
|
|
1064
|
+
actor: ctx.actor,
|
|
1065
|
+
channel: ctx.channel,
|
|
1066
|
+
metadata: ctx.traceId ? { traceId: ctx.traceId } : undefined
|
|
1067
|
+
});
|
|
1068
|
+
} catch (_error) {}
|
|
1069
|
+
};
|
|
1070
|
+
let result;
|
|
1071
|
+
try {
|
|
1072
|
+
result = await handler(parsedInput, {
|
|
1073
|
+
...ctx,
|
|
1074
|
+
__emitGuard__: emitGuard
|
|
1075
|
+
});
|
|
1076
|
+
} catch (error) {
|
|
1077
|
+
if (spec.telemetry?.failure) {
|
|
1078
|
+
await trackTelemetry(spec.telemetry.failure, {
|
|
1079
|
+
input: parsedInput ?? rawInput,
|
|
1080
|
+
error
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
throw error;
|
|
1084
|
+
}
|
|
1085
|
+
if (spec.telemetry?.success) {
|
|
1086
|
+
await trackTelemetry(spec.telemetry.success, {
|
|
1087
|
+
input: parsedInput ?? rawInput,
|
|
1088
|
+
output: result
|
|
1089
|
+
});
|
|
1090
|
+
}
|
|
1091
|
+
const outputModel = spec.io.output;
|
|
1092
|
+
if (outputModel?.getZod) {
|
|
1093
|
+
const parsedOutput = outputModel.getZod().parse(result);
|
|
1094
|
+
return parsedOutput;
|
|
1095
|
+
}
|
|
1096
|
+
return result;
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
// src/app-config/spec.ts
|
|
1100
|
+
var blueprintKey = (meta) => `${meta.key}.v${meta.version}`;
|
|
1101
|
+
|
|
1102
|
+
class AppBlueprintRegistry extends SpecContractRegistry {
|
|
1103
|
+
constructor(items) {
|
|
1104
|
+
super("app-config", items);
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
function makeAppBlueprintKey(meta) {
|
|
1108
|
+
return blueprintKey(meta);
|
|
1109
|
+
}
|
|
1110
|
+
var defineAppConfig = (spec) => spec;
|
|
1111
|
+
|
|
1112
|
+
// src/app-config/app-config.feature.ts
|
|
1113
|
+
var AppConfigFeature = defineAppConfig({
|
|
1114
|
+
meta: {
|
|
1115
|
+
key: "app-config",
|
|
1116
|
+
version: "1.0.0",
|
|
1117
|
+
title: "App Configuration",
|
|
1118
|
+
description: "Tenant app configuration lifecycle management with draft, preview, and publish stages",
|
|
1119
|
+
domain: "platform",
|
|
1120
|
+
owners: ["@platform.sigil"],
|
|
1121
|
+
tags: ["app-config", "lifecycle", "configuration", "tenant"],
|
|
1122
|
+
stability: "beta"
|
|
1123
|
+
},
|
|
1124
|
+
operations: [],
|
|
1125
|
+
events: [
|
|
1126
|
+
{ key: "app_config.draft_created", version: "1.0.0" },
|
|
1127
|
+
{ key: "app_config.promoted_to_preview", version: "1.0.0" },
|
|
1128
|
+
{ key: "app_config.published", version: "1.0.0" },
|
|
1129
|
+
{ key: "app_config.rolled_back", version: "1.0.0" }
|
|
1130
|
+
],
|
|
1131
|
+
presentations: [],
|
|
1132
|
+
opToPresentation: [],
|
|
1133
|
+
presentationsTargets: [],
|
|
1134
|
+
capabilities: {
|
|
1135
|
+
provides: [{ key: "app-config", version: "1.0.0" }],
|
|
1136
|
+
requires: []
|
|
1137
|
+
}
|
|
1138
|
+
});
|
|
1139
|
+
// src/app-config/events.ts
|
|
1140
|
+
import { SchemaModel, ScalarTypeEnum } from "@contractspec/lib.schema";
|
|
1141
|
+
var lifecycleOwnership = {
|
|
1142
|
+
title: "Tenant App Config Lifecycle",
|
|
1143
|
+
description: "Events emitted when tenant app configurations move through lifecycle stages.",
|
|
1144
|
+
domain: "app-config.lifecycle",
|
|
1145
|
+
owners: [OwnersEnum.PlatformSigil],
|
|
1146
|
+
tags: [TagsEnum.Hygiene],
|
|
1147
|
+
stability: StabilityEnum.Beta
|
|
1148
|
+
};
|
|
1149
|
+
var ConfigDraftCreatedEvent = defineEvent({
|
|
1150
|
+
meta: {
|
|
1151
|
+
...lifecycleOwnership,
|
|
1152
|
+
key: "app_config.draft_created",
|
|
1153
|
+
version: "1.0.0",
|
|
1154
|
+
description: "A new tenant config draft was created."
|
|
1155
|
+
},
|
|
1156
|
+
payload: new SchemaModel({
|
|
1157
|
+
name: "ConfigDraftCreatedPayload",
|
|
1158
|
+
fields: {
|
|
1159
|
+
tenantId: { type: ScalarTypeEnum.ID(), isOptional: false },
|
|
1160
|
+
appId: { type: ScalarTypeEnum.ID(), isOptional: false },
|
|
1161
|
+
version: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
1162
|
+
blueprintName: {
|
|
1163
|
+
type: ScalarTypeEnum.String_unsecure(),
|
|
1164
|
+
isOptional: false
|
|
1165
|
+
},
|
|
1166
|
+
blueprintVersion: {
|
|
1167
|
+
type: ScalarTypeEnum.String_unsecure(),
|
|
1168
|
+
isOptional: false
|
|
1169
|
+
},
|
|
1170
|
+
createdBy: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
1171
|
+
clonedFrom: { type: ScalarTypeEnum.Int_unsecure(), isOptional: true }
|
|
1172
|
+
}
|
|
1173
|
+
})
|
|
1174
|
+
});
|
|
1175
|
+
var ConfigPromotedToPreviewEvent = defineEvent({
|
|
1176
|
+
meta: {
|
|
1177
|
+
...lifecycleOwnership,
|
|
1178
|
+
key: "app_config.promoted_to_preview",
|
|
1179
|
+
version: "1.0.0",
|
|
1180
|
+
description: "A tenant config draft was promoted to preview."
|
|
1181
|
+
},
|
|
1182
|
+
payload: new SchemaModel({
|
|
1183
|
+
name: "ConfigPromotedToPreviewPayload",
|
|
1184
|
+
fields: {
|
|
1185
|
+
tenantId: { type: ScalarTypeEnum.ID(), isOptional: false },
|
|
1186
|
+
appId: { type: ScalarTypeEnum.ID(), isOptional: false },
|
|
1187
|
+
version: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
1188
|
+
promotedBy: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
1189
|
+
warnings: {
|
|
1190
|
+
type: ScalarTypeEnum.String_unsecure(),
|
|
1191
|
+
isOptional: true,
|
|
1192
|
+
isArray: true
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
})
|
|
1196
|
+
});
|
|
1197
|
+
var ConfigPublishedEvent = defineEvent({
|
|
1198
|
+
meta: {
|
|
1199
|
+
...lifecycleOwnership,
|
|
1200
|
+
key: "app_config.published",
|
|
1201
|
+
version: "1.0.0",
|
|
1202
|
+
description: "A tenant config version was published to production."
|
|
1203
|
+
},
|
|
1204
|
+
payload: new SchemaModel({
|
|
1205
|
+
name: "ConfigPublishedPayload",
|
|
1206
|
+
fields: {
|
|
1207
|
+
tenantId: { type: ScalarTypeEnum.ID(), isOptional: false },
|
|
1208
|
+
appId: { type: ScalarTypeEnum.ID(), isOptional: false },
|
|
1209
|
+
version: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
1210
|
+
previousVersion: {
|
|
1211
|
+
type: ScalarTypeEnum.String_unsecure(),
|
|
1212
|
+
isOptional: true
|
|
1213
|
+
},
|
|
1214
|
+
publishedBy: {
|
|
1215
|
+
type: ScalarTypeEnum.String_unsecure(),
|
|
1216
|
+
isOptional: false
|
|
1217
|
+
},
|
|
1218
|
+
changeSummary: {
|
|
1219
|
+
type: ScalarTypeEnum.String_unsecure(),
|
|
1220
|
+
isOptional: true
|
|
1221
|
+
},
|
|
1222
|
+
changedSections: {
|
|
1223
|
+
type: ScalarTypeEnum.String_unsecure(),
|
|
1224
|
+
isOptional: true,
|
|
1225
|
+
isArray: true
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
})
|
|
1229
|
+
});
|
|
1230
|
+
var ConfigRolledBackEvent = defineEvent({
|
|
1231
|
+
meta: {
|
|
1232
|
+
...lifecycleOwnership,
|
|
1233
|
+
key: "app_config.rolled_back",
|
|
1234
|
+
version: "1.0.0",
|
|
1235
|
+
description: "A tenant config was rolled back to a previous version."
|
|
1236
|
+
},
|
|
1237
|
+
payload: new SchemaModel({
|
|
1238
|
+
name: "ConfigRolledBackPayload",
|
|
1239
|
+
fields: {
|
|
1240
|
+
tenantId: { type: ScalarTypeEnum.ID(), isOptional: false },
|
|
1241
|
+
appId: { type: ScalarTypeEnum.ID(), isOptional: false },
|
|
1242
|
+
newVersion: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
1243
|
+
rolledBackFrom: {
|
|
1244
|
+
type: ScalarTypeEnum.String_unsecure(),
|
|
1245
|
+
isOptional: false
|
|
1246
|
+
},
|
|
1247
|
+
rolledBackTo: {
|
|
1248
|
+
type: ScalarTypeEnum.String_unsecure(),
|
|
1249
|
+
isOptional: false
|
|
1250
|
+
},
|
|
1251
|
+
rolledBackBy: {
|
|
1252
|
+
type: ScalarTypeEnum.String_unsecure(),
|
|
1253
|
+
isOptional: false
|
|
1254
|
+
},
|
|
1255
|
+
reason: { type: ScalarTypeEnum.String_unsecure(), isOptional: false }
|
|
1256
|
+
}
|
|
1257
|
+
})
|
|
1258
|
+
});
|
|
1259
|
+
|
|
1260
|
+
// src/app-config/runtime.ts
|
|
1261
|
+
function resolveAppConfig(blueprint, tenant, deps = {}) {
|
|
1262
|
+
const capabilities2 = mergeCapabilities(blueprint.capabilities, tenant.capabilities);
|
|
1263
|
+
const features = mergeFeatures(blueprint.features, tenant.features);
|
|
1264
|
+
const dataViews = mergeMappings(blueprint.dataViews ?? {}, tenant.dataViewOverrides);
|
|
1265
|
+
const workflows = mergeMappings(blueprint.workflows ?? {}, tenant.workflowOverrides);
|
|
1266
|
+
const policies = mergePolicies(blueprint.policies ?? [], tenant.additionalPolicies ?? []);
|
|
1267
|
+
const theme = mergeTheme(blueprint.theme, tenant.themeOverride);
|
|
1268
|
+
const telemetry = mergeTelemetry(blueprint.telemetry, tenant.telemetryOverride);
|
|
1269
|
+
const experiments = mergeExperiments(blueprint.experiments, tenant.experiments);
|
|
1270
|
+
const featureFlags = mergeFeatureFlags(blueprint.featureFlags ?? [], tenant.featureFlags ?? []);
|
|
1271
|
+
const routes = mergeRoutes(blueprint.routes ?? [], tenant.routeOverrides ?? []);
|
|
1272
|
+
const { resolved: integrations } = evaluateIntegrationSlots(blueprint.integrationSlots, tenant.integrations, deps.integrationConnections, deps.integrationSpecs);
|
|
1273
|
+
const knowledge = resolveKnowledgeBindings(tenant.knowledge, deps.knowledgeSpaces, deps.knowledgeSources);
|
|
1274
|
+
const branding = resolveBranding(blueprint.branding, tenant);
|
|
1275
|
+
const translation = resolveTranslation(blueprint.translationCatalog, tenant.locales, tenant.translationOverrides);
|
|
1276
|
+
return {
|
|
1277
|
+
appId: blueprint.meta.appId,
|
|
1278
|
+
tenantId: tenant.meta.tenantId,
|
|
1279
|
+
environment: tenant.meta.environment,
|
|
1280
|
+
blueprintName: blueprint.meta.key,
|
|
1281
|
+
blueprintVersion: blueprint.meta.version,
|
|
1282
|
+
configVersion: tenant.meta.version,
|
|
1283
|
+
capabilities: capabilities2,
|
|
1284
|
+
features,
|
|
1285
|
+
dataViews,
|
|
1286
|
+
workflows,
|
|
1287
|
+
policies,
|
|
1288
|
+
theme,
|
|
1289
|
+
telemetry,
|
|
1290
|
+
experiments,
|
|
1291
|
+
featureFlags,
|
|
1292
|
+
routes,
|
|
1293
|
+
integrations,
|
|
1294
|
+
knowledge,
|
|
1295
|
+
translation,
|
|
1296
|
+
branding,
|
|
1297
|
+
notes: tenant.notes ?? blueprint.notes
|
|
1298
|
+
};
|
|
1299
|
+
}
|
|
1300
|
+
function composeAppConfig(blueprint, tenant, deps, options = {}) {
|
|
1301
|
+
const resolved = resolveAppConfig(blueprint, tenant, deps);
|
|
1302
|
+
const missing = [];
|
|
1303
|
+
const integrationEvaluation = evaluateIntegrationSlots(blueprint.integrationSlots, tenant.integrations, deps.integrationConnections, deps.integrationSpecs);
|
|
1304
|
+
resolved.integrations = integrationEvaluation.resolved;
|
|
1305
|
+
missing.push(...integrationEvaluation.missing);
|
|
1306
|
+
missing.push(...collectMissingKnowledge(tenant.knowledge ?? [], deps.knowledgeSpaces, deps.knowledgeSources));
|
|
1307
|
+
const capabilities2 = resolveCapabilityRefs(resolved.capabilities.enabled, deps.capabilities, missing);
|
|
1308
|
+
const features = resolveFeatureRefs(resolved.features.include, deps.features, missing);
|
|
1309
|
+
const dataViews = resolvePointerRecord(resolved.dataViews, deps.dataViews, "dataView", missing);
|
|
1310
|
+
const workflows = resolvePointerRecord(resolved.workflows, deps.workflows, "workflow", missing);
|
|
1311
|
+
const policies = resolvePolicies(resolved.policies, deps.policies, missing);
|
|
1312
|
+
const { theme, fallbacks, themeMissing } = resolveThemeBinding(resolved.theme, deps.themes);
|
|
1313
|
+
missing.push(...themeMissing);
|
|
1314
|
+
const { telemetry, telemetryMissing } = resolveTelemetryBinding(resolved.telemetry, deps.telemetry);
|
|
1315
|
+
missing.push(...telemetryMissing);
|
|
1316
|
+
const experiments = resolveExperimentsSpecs(resolved.experiments, deps.experiments, missing);
|
|
1317
|
+
if (options.strict && missing.length > 0) {
|
|
1318
|
+
const reasons = missing.map((item) => `${item.type}:${item.identifier}`).join(", ");
|
|
1319
|
+
throw new Error(`composeAppConfig: missing references -> ${reasons}`);
|
|
1320
|
+
}
|
|
1321
|
+
return {
|
|
1322
|
+
resolved,
|
|
1323
|
+
capabilities: capabilities2,
|
|
1324
|
+
features,
|
|
1325
|
+
dataViews,
|
|
1326
|
+
workflows,
|
|
1327
|
+
policies,
|
|
1328
|
+
theme,
|
|
1329
|
+
themeFallbacks: fallbacks,
|
|
1330
|
+
telemetry,
|
|
1331
|
+
experiments,
|
|
1332
|
+
integrations: resolved.integrations,
|
|
1333
|
+
knowledge: resolved.knowledge,
|
|
1334
|
+
missing
|
|
1335
|
+
};
|
|
1336
|
+
}
|
|
1337
|
+
function mergeCapabilities(blueprint, tenant) {
|
|
1338
|
+
const enabled = dedupeRefs([...blueprint?.enabled ?? [], ...tenant?.enable ?? []], capabilityKey2);
|
|
1339
|
+
const disabled = dedupeRefs([...blueprint?.disabled ?? [], ...tenant?.disable ?? []], capabilityKey2);
|
|
1340
|
+
const disabledKeys = new Set(disabled.map(capabilityKey2));
|
|
1341
|
+
const filteredEnabled = enabled.filter((ref) => !disabledKeys.has(capabilityKey2(ref)));
|
|
1342
|
+
return { enabled: filteredEnabled, disabled };
|
|
1343
|
+
}
|
|
1344
|
+
function mergeFeatures(blueprint, tenant) {
|
|
1345
|
+
const include = dedupeRefs([...blueprint?.include ?? [], ...tenant?.include ?? []], featureKey);
|
|
1346
|
+
const exclude = dedupeRefs([...blueprint?.exclude ?? [], ...tenant?.exclude ?? []], featureKey);
|
|
1347
|
+
const excludeSet = new Set(exclude.map(featureKey));
|
|
1348
|
+
const filteredInclude = include.filter((ref) => !excludeSet.has(featureKey(ref)));
|
|
1349
|
+
return { include: filteredInclude, exclude };
|
|
1350
|
+
}
|
|
1351
|
+
function mergeMappings(blueprint, overrides) {
|
|
1352
|
+
const merged = { ...blueprint };
|
|
1353
|
+
if (!overrides)
|
|
1354
|
+
return merged;
|
|
1355
|
+
for (const override of overrides) {
|
|
1356
|
+
if (!override)
|
|
1357
|
+
continue;
|
|
1358
|
+
if (!override.pointer) {
|
|
1359
|
+
delete merged[override.slot];
|
|
1360
|
+
} else {
|
|
1361
|
+
merged[override.slot] = override.pointer;
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
return merged;
|
|
1365
|
+
}
|
|
1366
|
+
function mergePolicies(blueprint, additional) {
|
|
1367
|
+
return dedupeRefs([...blueprint, ...additional], policyKey);
|
|
1368
|
+
}
|
|
1369
|
+
function mergeTheme(blueprint, override) {
|
|
1370
|
+
if (!blueprint && !override)
|
|
1371
|
+
return;
|
|
1372
|
+
const primary = override?.primary ?? blueprint?.primary;
|
|
1373
|
+
if (!primary)
|
|
1374
|
+
return;
|
|
1375
|
+
const fallbacks = override?.fallbacks ?? blueprint?.fallbacks ?? [];
|
|
1376
|
+
return { primary, fallbacks };
|
|
1377
|
+
}
|
|
1378
|
+
function mergeTelemetry(blueprint, override) {
|
|
1379
|
+
if (!blueprint && !override)
|
|
1380
|
+
return;
|
|
1381
|
+
const binding = {
|
|
1382
|
+
spec: blueprint?.spec,
|
|
1383
|
+
disabledEvents: blueprint?.disabledEvents ? [...blueprint.disabledEvents] : undefined,
|
|
1384
|
+
samplingOverrides: blueprint?.samplingOverrides ? { ...blueprint.samplingOverrides } : undefined
|
|
1385
|
+
};
|
|
1386
|
+
if (override?.spec !== undefined) {
|
|
1387
|
+
binding.spec = override.spec ?? undefined;
|
|
1388
|
+
}
|
|
1389
|
+
if (override?.disabledEvents) {
|
|
1390
|
+
binding.disabledEvents = dedupeStrings([
|
|
1391
|
+
...binding.disabledEvents ?? [],
|
|
1392
|
+
...override.disabledEvents
|
|
1393
|
+
]);
|
|
1394
|
+
}
|
|
1395
|
+
if (override?.samplingOverrides) {
|
|
1396
|
+
binding.samplingOverrides = {
|
|
1397
|
+
...binding.samplingOverrides ?? {},
|
|
1398
|
+
...override.samplingOverrides
|
|
1399
|
+
};
|
|
1400
|
+
}
|
|
1401
|
+
if (!binding.spec && !binding.disabledEvents?.length) {
|
|
1402
|
+
return;
|
|
1403
|
+
}
|
|
1404
|
+
return binding;
|
|
1405
|
+
}
|
|
1406
|
+
function mergeExperiments(blueprint, tenant) {
|
|
1407
|
+
const defaultActive = blueprint?.active ?? [];
|
|
1408
|
+
const defaultPaused = blueprint?.paused ?? [];
|
|
1409
|
+
const tenantActive = tenant?.active;
|
|
1410
|
+
const tenantPaused = tenant?.paused;
|
|
1411
|
+
const activeSource = tenantActive && tenantActive.length > 0 ? tenantActive : defaultActive;
|
|
1412
|
+
const pausedSource = tenantPaused && tenantPaused.length > 0 ? tenantPaused : defaultPaused;
|
|
1413
|
+
const active = dedupeRefs(activeSource, experimentKey);
|
|
1414
|
+
let paused = dedupeRefs(pausedSource, experimentKey);
|
|
1415
|
+
const activeKeys = new Set(active.map(experimentKey));
|
|
1416
|
+
paused = paused.filter((ref) => !activeKeys.has(experimentKey(ref)));
|
|
1417
|
+
const catalog = dedupeRefs([
|
|
1418
|
+
...defaultActive,
|
|
1419
|
+
...defaultPaused,
|
|
1420
|
+
...tenantActive ?? [],
|
|
1421
|
+
...tenantPaused ?? []
|
|
1422
|
+
], experimentKey);
|
|
1423
|
+
return { catalog, active, paused };
|
|
1424
|
+
}
|
|
1425
|
+
function resolveBranding(defaults, tenant) {
|
|
1426
|
+
const override = tenant.branding;
|
|
1427
|
+
const tenantMeta = tenant.meta;
|
|
1428
|
+
const baseDomain = "app.localhost";
|
|
1429
|
+
const domain = override?.customDomain ?? (override?.subdomain ? `${override.subdomain}.${baseDomain}` : `${tenantMeta.tenantId}.${baseDomain}`);
|
|
1430
|
+
const localePreferenceOrder = [];
|
|
1431
|
+
if (tenant.locales?.defaultLocale) {
|
|
1432
|
+
localePreferenceOrder.push(tenant.locales.defaultLocale);
|
|
1433
|
+
}
|
|
1434
|
+
if (override?.appName) {
|
|
1435
|
+
localePreferenceOrder.push("default", "en");
|
|
1436
|
+
}
|
|
1437
|
+
let appName;
|
|
1438
|
+
if (override?.appName) {
|
|
1439
|
+
for (const key of localePreferenceOrder) {
|
|
1440
|
+
const candidate = override.appName[key];
|
|
1441
|
+
if (candidate) {
|
|
1442
|
+
appName = candidate;
|
|
1443
|
+
break;
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
if (!appName) {
|
|
1447
|
+
const [, firstValue] = Object.entries(override.appName)[0] ?? [];
|
|
1448
|
+
if (typeof firstValue === "string") {
|
|
1449
|
+
appName = firstValue;
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
if (!appName) {
|
|
1454
|
+
appName = defaults?.appNameKey ?? tenantMeta.appId;
|
|
1455
|
+
}
|
|
1456
|
+
const assetEntries = new Map;
|
|
1457
|
+
const applyAssets = (assets2) => {
|
|
1458
|
+
if (!assets2)
|
|
1459
|
+
return;
|
|
1460
|
+
for (const asset of assets2) {
|
|
1461
|
+
if (!asset?.type)
|
|
1462
|
+
continue;
|
|
1463
|
+
if ("url" in asset && asset.url) {
|
|
1464
|
+
assetEntries.set(asset.type, asset.url);
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
};
|
|
1468
|
+
applyAssets(defaults?.assets);
|
|
1469
|
+
applyAssets(override?.assets);
|
|
1470
|
+
const assets = {
|
|
1471
|
+
logo: assetEntries.get("logo"),
|
|
1472
|
+
logoDark: assetEntries.get("logo-dark"),
|
|
1473
|
+
favicon: assetEntries.get("favicon"),
|
|
1474
|
+
ogImage: assetEntries.get("og-image")
|
|
1475
|
+
};
|
|
1476
|
+
const colors = {
|
|
1477
|
+
primary: override?.colors?.primary ?? defaults?.colorTokens?.primary ?? "#1f2937",
|
|
1478
|
+
secondary: override?.colors?.secondary ?? defaults?.colorTokens?.secondary ?? "#4b5563"
|
|
1479
|
+
};
|
|
1480
|
+
return {
|
|
1481
|
+
appName,
|
|
1482
|
+
assets,
|
|
1483
|
+
colors,
|
|
1484
|
+
domain
|
|
1485
|
+
};
|
|
1486
|
+
}
|
|
1487
|
+
function resolveTranslation(catalogPointer, locales, overrides) {
|
|
1488
|
+
const defaultLocale = locales?.defaultLocale ?? "en";
|
|
1489
|
+
const enabled = locales?.enabledLocales ?? [];
|
|
1490
|
+
const supportedLocales = dedupeStrings([defaultLocale, ...enabled]);
|
|
1491
|
+
const entries = overrides?.entries ?? [];
|
|
1492
|
+
return {
|
|
1493
|
+
defaultLocale,
|
|
1494
|
+
supportedLocales,
|
|
1495
|
+
blueprintCatalog: catalogPointer,
|
|
1496
|
+
tenantOverrides: entries
|
|
1497
|
+
};
|
|
1498
|
+
}
|
|
1499
|
+
function mergeFeatureFlags(blueprint, overrides) {
|
|
1500
|
+
const merged = new Map;
|
|
1501
|
+
for (const flag of blueprint) {
|
|
1502
|
+
merged.set(flag.key, { ...flag });
|
|
1503
|
+
}
|
|
1504
|
+
for (const override of overrides) {
|
|
1505
|
+
merged.set(override.key, { ...override });
|
|
1506
|
+
}
|
|
1507
|
+
return [...merged.values()];
|
|
1508
|
+
}
|
|
1509
|
+
function mergeRoutes(blueprint, overrides) {
|
|
1510
|
+
const routes = new Map;
|
|
1511
|
+
for (const route of blueprint) {
|
|
1512
|
+
routes.set(route.path, { ...route });
|
|
1513
|
+
}
|
|
1514
|
+
for (const override of overrides) {
|
|
1515
|
+
const existing = routes.get(override.path) ?? { path: override.path };
|
|
1516
|
+
if (override.label !== undefined) {
|
|
1517
|
+
if (override.label === null)
|
|
1518
|
+
delete existing.label;
|
|
1519
|
+
else
|
|
1520
|
+
existing.label = override.label;
|
|
1521
|
+
}
|
|
1522
|
+
if (override.dataView !== undefined) {
|
|
1523
|
+
if (override.dataView === null)
|
|
1524
|
+
delete existing.dataView;
|
|
1525
|
+
else
|
|
1526
|
+
existing.dataView = override.dataView;
|
|
1527
|
+
}
|
|
1528
|
+
if (override.workflow !== undefined) {
|
|
1529
|
+
if (override.workflow === null)
|
|
1530
|
+
delete existing.workflow;
|
|
1531
|
+
else
|
|
1532
|
+
existing.workflow = override.workflow;
|
|
1533
|
+
}
|
|
1534
|
+
if (override.guard !== undefined) {
|
|
1535
|
+
if (override.guard === null)
|
|
1536
|
+
delete existing.guard;
|
|
1537
|
+
else
|
|
1538
|
+
existing.guard = override.guard;
|
|
1539
|
+
}
|
|
1540
|
+
if (override.featureFlag !== undefined) {
|
|
1541
|
+
if (override.featureFlag === null)
|
|
1542
|
+
delete existing.featureFlag;
|
|
1543
|
+
else
|
|
1544
|
+
existing.featureFlag = override.featureFlag;
|
|
1545
|
+
}
|
|
1546
|
+
if (override.experiment !== undefined) {
|
|
1547
|
+
if (override.experiment === null)
|
|
1548
|
+
delete existing.experiment;
|
|
1549
|
+
else
|
|
1550
|
+
existing.experiment = override.experiment;
|
|
1551
|
+
}
|
|
1552
|
+
routes.set(existing.path, existing);
|
|
1553
|
+
}
|
|
1554
|
+
return [...routes.values()];
|
|
1555
|
+
}
|
|
1556
|
+
function evaluateIntegrationSlots(slots, bindings, connections, specs) {
|
|
1557
|
+
const resolved = [];
|
|
1558
|
+
const missing = [];
|
|
1559
|
+
const missingKeys = new Set;
|
|
1560
|
+
const recordMissing = (entry) => {
|
|
1561
|
+
const key = `${entry.type}:${entry.identifier}`;
|
|
1562
|
+
if (missingKeys.has(key))
|
|
1563
|
+
return;
|
|
1564
|
+
missingKeys.add(key);
|
|
1565
|
+
missing.push(entry);
|
|
1566
|
+
};
|
|
1567
|
+
const slotList = slots ?? [];
|
|
1568
|
+
const slotById = new Map;
|
|
1569
|
+
for (const slot of slotList) {
|
|
1570
|
+
slotById.set(slot.slotId, slot);
|
|
1571
|
+
}
|
|
1572
|
+
const bindingsBySlot = new Map;
|
|
1573
|
+
for (const binding of bindings ?? []) {
|
|
1574
|
+
const slot = slotById.get(binding.slotId);
|
|
1575
|
+
if (!slot) {
|
|
1576
|
+
recordMissing({
|
|
1577
|
+
type: "integrationSlot",
|
|
1578
|
+
identifier: `slot:${binding.slotId}`
|
|
1579
|
+
});
|
|
1580
|
+
continue;
|
|
1581
|
+
}
|
|
1582
|
+
const entries = bindingsBySlot.get(binding.slotId);
|
|
1583
|
+
if (entries)
|
|
1584
|
+
entries.push(binding);
|
|
1585
|
+
else
|
|
1586
|
+
bindingsBySlot.set(binding.slotId, [binding]);
|
|
1587
|
+
}
|
|
1588
|
+
for (const slot of slotList) {
|
|
1589
|
+
const slotBindings = bindingsBySlot.get(slot.slotId) ?? [];
|
|
1590
|
+
if (slot.required && slotBindings.length === 0) {
|
|
1591
|
+
recordMissing({
|
|
1592
|
+
type: "integrationSlot",
|
|
1593
|
+
identifier: `slot:${slot.slotId}`
|
|
1594
|
+
});
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
if (!connections || !specs) {
|
|
1598
|
+
return { resolved, missing };
|
|
1599
|
+
}
|
|
1600
|
+
const connectionById = new Map;
|
|
1601
|
+
for (const connection of connections) {
|
|
1602
|
+
connectionById.set(connection.meta.id, connection);
|
|
1603
|
+
}
|
|
1604
|
+
for (const slot of slotList) {
|
|
1605
|
+
const slotBindings = bindingsBySlot.get(slot.slotId) ?? [];
|
|
1606
|
+
if (slotBindings.length === 0)
|
|
1607
|
+
continue;
|
|
1608
|
+
const orderedBindings = [...slotBindings].sort((a, b) => {
|
|
1609
|
+
const aPriority = a.priority ?? Number.MAX_SAFE_INTEGER;
|
|
1610
|
+
const bPriority = b.priority ?? Number.MAX_SAFE_INTEGER;
|
|
1611
|
+
if (aPriority === bPriority)
|
|
1612
|
+
return 0;
|
|
1613
|
+
return aPriority < bPriority ? -1 : 1;
|
|
1614
|
+
});
|
|
1615
|
+
let slotResolved = false;
|
|
1616
|
+
for (const binding of orderedBindings) {
|
|
1617
|
+
const connection = connectionById.get(binding.connectionId);
|
|
1618
|
+
if (!connection) {
|
|
1619
|
+
recordMissing({
|
|
1620
|
+
type: "integrationConnection",
|
|
1621
|
+
identifier: `connection:${binding.connectionId}`
|
|
1622
|
+
});
|
|
1623
|
+
continue;
|
|
1624
|
+
}
|
|
1625
|
+
const spec = specs.get(connection.meta.integrationKey, connection.meta.integrationVersion);
|
|
1626
|
+
if (!spec) {
|
|
1627
|
+
recordMissing({
|
|
1628
|
+
type: "integrationSpec",
|
|
1629
|
+
identifier: `spec:${connection.meta.integrationKey}.v${connection.meta.integrationVersion}`
|
|
1630
|
+
});
|
|
1631
|
+
continue;
|
|
1632
|
+
}
|
|
1633
|
+
if (spec.meta.category !== slot.requiredCategory) {
|
|
1634
|
+
recordMissing({
|
|
1635
|
+
type: "integrationSpec",
|
|
1636
|
+
identifier: `spec:${spec.meta.key}.category`
|
|
1637
|
+
});
|
|
1638
|
+
continue;
|
|
1639
|
+
}
|
|
1640
|
+
if (!spec.supportedModes.includes(connection.ownershipMode)) {
|
|
1641
|
+
recordMissing({
|
|
1642
|
+
type: "integrationSpec",
|
|
1643
|
+
identifier: `spec:${spec.meta.key}.mode:${connection.ownershipMode}`
|
|
1644
|
+
});
|
|
1645
|
+
continue;
|
|
1646
|
+
}
|
|
1647
|
+
if (slot.allowedModes && slot.allowedModes.length > 0 && !slot.allowedModes.includes(connection.ownershipMode)) {
|
|
1648
|
+
recordMissing({
|
|
1649
|
+
type: "integrationConnection",
|
|
1650
|
+
identifier: `connection:${connection.meta.id}:mode`
|
|
1651
|
+
});
|
|
1652
|
+
continue;
|
|
1653
|
+
}
|
|
1654
|
+
if (slot.requiredCapabilities && !slot.requiredCapabilities.every((requirement) => integrationProvidesCapability(spec, requirement))) {
|
|
1655
|
+
recordMissing({
|
|
1656
|
+
type: "integrationSpec",
|
|
1657
|
+
identifier: `spec:${spec.meta.key}.capabilities`
|
|
1658
|
+
});
|
|
1659
|
+
continue;
|
|
1660
|
+
}
|
|
1661
|
+
resolved.push({
|
|
1662
|
+
slot,
|
|
1663
|
+
binding,
|
|
1664
|
+
connection,
|
|
1665
|
+
spec
|
|
1666
|
+
});
|
|
1667
|
+
slotResolved = true;
|
|
1668
|
+
break;
|
|
1669
|
+
}
|
|
1670
|
+
if (!slotResolved && slot.required) {
|
|
1671
|
+
recordMissing({
|
|
1672
|
+
type: "integrationSlot",
|
|
1673
|
+
identifier: `slot:${slot.slotId}`
|
|
1674
|
+
});
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
return { resolved, missing };
|
|
1678
|
+
}
|
|
1679
|
+
function integrationProvidesCapability(spec, required) {
|
|
1680
|
+
return spec.capabilities.provides.some((capability) => {
|
|
1681
|
+
if (capability.key !== required.key)
|
|
1682
|
+
return false;
|
|
1683
|
+
if (required.version == null)
|
|
1684
|
+
return true;
|
|
1685
|
+
return capability.version === required.version;
|
|
1686
|
+
});
|
|
1687
|
+
}
|
|
1688
|
+
function resolveKnowledgeBindings(bindings, spaces, sources) {
|
|
1689
|
+
if (!bindings?.length || !spaces)
|
|
1690
|
+
return [];
|
|
1691
|
+
const sourceList = sources ?? [];
|
|
1692
|
+
return bindings.map((binding) => {
|
|
1693
|
+
const space = spaces.get(binding.spaceKey, binding.spaceVersion);
|
|
1694
|
+
if (!space)
|
|
1695
|
+
return null;
|
|
1696
|
+
const relevantSources = sourceList.filter((source) => {
|
|
1697
|
+
if (source.meta.spaceKey !== binding.spaceKey)
|
|
1698
|
+
return false;
|
|
1699
|
+
if (binding.spaceVersion != null) {
|
|
1700
|
+
return source.meta.spaceVersion === binding.spaceVersion;
|
|
1701
|
+
}
|
|
1702
|
+
return true;
|
|
1703
|
+
});
|
|
1704
|
+
return {
|
|
1705
|
+
binding,
|
|
1706
|
+
space,
|
|
1707
|
+
sources: relevantSources
|
|
1708
|
+
};
|
|
1709
|
+
}).filter((entry) => entry !== null);
|
|
1710
|
+
}
|
|
1711
|
+
function collectMissingKnowledge(bindings, spaces, sources) {
|
|
1712
|
+
if (!bindings.length || !spaces)
|
|
1713
|
+
return [];
|
|
1714
|
+
const missing = [];
|
|
1715
|
+
const sourceList = sources ?? [];
|
|
1716
|
+
for (const binding of bindings) {
|
|
1717
|
+
const space = spaces.get(binding.spaceKey, binding.spaceVersion);
|
|
1718
|
+
if (!space) {
|
|
1719
|
+
missing.push({
|
|
1720
|
+
type: "knowledgeSpace",
|
|
1721
|
+
identifier: binding.spaceVersion ? `${binding.spaceKey}@${binding.spaceVersion}` : binding.spaceKey
|
|
1722
|
+
});
|
|
1723
|
+
continue;
|
|
1724
|
+
}
|
|
1725
|
+
if (sources) {
|
|
1726
|
+
const relevantSources = sourceList.filter((source) => {
|
|
1727
|
+
if (source.meta.spaceKey !== binding.spaceKey)
|
|
1728
|
+
return false;
|
|
1729
|
+
if (binding.spaceVersion != null) {
|
|
1730
|
+
return source.meta.spaceVersion === binding.spaceVersion;
|
|
1731
|
+
}
|
|
1732
|
+
return true;
|
|
1733
|
+
});
|
|
1734
|
+
if (relevantSources.length === 0) {
|
|
1735
|
+
missing.push({
|
|
1736
|
+
type: "knowledgeSource",
|
|
1737
|
+
identifier: binding.spaceVersion ? `${binding.spaceKey}@${binding.spaceVersion}` : binding.spaceKey
|
|
1738
|
+
});
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
return missing;
|
|
1743
|
+
}
|
|
1744
|
+
function resolveCapabilityRefs(refs, registry2, missing) {
|
|
1745
|
+
if (!registry2) {
|
|
1746
|
+
if (refs.length > 0) {
|
|
1747
|
+
for (const ref of refs) {
|
|
1748
|
+
missing.push({
|
|
1749
|
+
type: "capability",
|
|
1750
|
+
identifier: capabilityKey2(ref)
|
|
1751
|
+
});
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
return [];
|
|
1755
|
+
}
|
|
1756
|
+
const resolved = [];
|
|
1757
|
+
for (const ref of refs) {
|
|
1758
|
+
const spec = registry2.get(ref.key, ref.version);
|
|
1759
|
+
if (!spec) {
|
|
1760
|
+
missing.push({
|
|
1761
|
+
type: "capability",
|
|
1762
|
+
identifier: capabilityKey2(ref)
|
|
1763
|
+
});
|
|
1764
|
+
continue;
|
|
1765
|
+
}
|
|
1766
|
+
resolved.push(spec);
|
|
1767
|
+
}
|
|
1768
|
+
return resolved;
|
|
1769
|
+
}
|
|
1770
|
+
function resolveFeatureRefs(refs, registry2, missing) {
|
|
1771
|
+
if (!registry2) {
|
|
1772
|
+
if (refs.length > 0) {
|
|
1773
|
+
for (const ref of refs) {
|
|
1774
|
+
missing.push({ type: "feature", identifier: ref.key });
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
return [];
|
|
1778
|
+
}
|
|
1779
|
+
const resolved = [];
|
|
1780
|
+
for (const ref of refs) {
|
|
1781
|
+
const spec = registry2.get(ref.key);
|
|
1782
|
+
if (!spec) {
|
|
1783
|
+
missing.push({ type: "feature", identifier: ref.key });
|
|
1784
|
+
continue;
|
|
1785
|
+
}
|
|
1786
|
+
resolved.push(spec);
|
|
1787
|
+
}
|
|
1788
|
+
return resolved;
|
|
1789
|
+
}
|
|
1790
|
+
function resolvePointerRecord(record, registry2, type, missing) {
|
|
1791
|
+
if (!registry2) {
|
|
1792
|
+
if (Object.keys(record).length > 0) {
|
|
1793
|
+
for (const [slot, pointer] of Object.entries(record)) {
|
|
1794
|
+
missing.push({
|
|
1795
|
+
type,
|
|
1796
|
+
identifier: `${slot} -> ${specPointerKey(pointer)}`
|
|
1797
|
+
});
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
return {};
|
|
1801
|
+
}
|
|
1802
|
+
const resolved = {};
|
|
1803
|
+
for (const [slot, pointer] of Object.entries(record)) {
|
|
1804
|
+
const spec = registry2.get(pointer.key, pointer.version);
|
|
1805
|
+
if (!spec) {
|
|
1806
|
+
missing.push({
|
|
1807
|
+
type,
|
|
1808
|
+
identifier: `${slot} -> ${specPointerKey(pointer)}`
|
|
1809
|
+
});
|
|
1810
|
+
continue;
|
|
1811
|
+
}
|
|
1812
|
+
resolved[slot] = spec;
|
|
1813
|
+
}
|
|
1814
|
+
return resolved;
|
|
1815
|
+
}
|
|
1816
|
+
function resolvePolicies(policies, registry2, missing) {
|
|
1817
|
+
if (!registry2) {
|
|
1818
|
+
if (policies.length > 0) {
|
|
1819
|
+
for (const policy of policies) {
|
|
1820
|
+
missing.push({
|
|
1821
|
+
type: "policy",
|
|
1822
|
+
identifier: policyKey(policy)
|
|
1823
|
+
});
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
return [];
|
|
1827
|
+
}
|
|
1828
|
+
const resolved = [];
|
|
1829
|
+
for (const policy of policies) {
|
|
1830
|
+
const spec = registry2.get(policy.key, policy.version);
|
|
1831
|
+
if (!spec) {
|
|
1832
|
+
missing.push({
|
|
1833
|
+
type: "policy",
|
|
1834
|
+
identifier: policyKey(policy)
|
|
1835
|
+
});
|
|
1836
|
+
continue;
|
|
1837
|
+
}
|
|
1838
|
+
resolved.push(spec);
|
|
1839
|
+
}
|
|
1840
|
+
return resolved;
|
|
1841
|
+
}
|
|
1842
|
+
function resolveThemeBinding(binding, registry2) {
|
|
1843
|
+
const themeMissing = [];
|
|
1844
|
+
if (!binding) {
|
|
1845
|
+
return { theme: undefined, fallbacks: [], themeMissing };
|
|
1846
|
+
}
|
|
1847
|
+
if (!registry2) {
|
|
1848
|
+
themeMissing.push({
|
|
1849
|
+
type: "theme",
|
|
1850
|
+
identifier: `${binding.primary.key}.v${binding.primary.version}`
|
|
1851
|
+
});
|
|
1852
|
+
for (const fallback of binding.fallbacks ?? []) {
|
|
1853
|
+
themeMissing.push({
|
|
1854
|
+
type: "theme",
|
|
1855
|
+
identifier: `${fallback.key}.v${fallback.version}`
|
|
1856
|
+
});
|
|
1857
|
+
}
|
|
1858
|
+
return { theme: undefined, fallbacks: [], themeMissing };
|
|
1859
|
+
}
|
|
1860
|
+
const theme = registry2.get(binding.primary.key, binding.primary.version);
|
|
1861
|
+
if (!theme) {
|
|
1862
|
+
themeMissing.push({
|
|
1863
|
+
type: "theme",
|
|
1864
|
+
identifier: `${binding.primary.key}.v${binding.primary.version}`
|
|
1865
|
+
});
|
|
1866
|
+
}
|
|
1867
|
+
const fallbacks = [];
|
|
1868
|
+
for (const fallback of binding.fallbacks ?? []) {
|
|
1869
|
+
const spec = registry2.get(fallback.key, fallback.version);
|
|
1870
|
+
if (!spec) {
|
|
1871
|
+
themeMissing.push({
|
|
1872
|
+
type: "theme",
|
|
1873
|
+
identifier: `${fallback.key}.v${fallback.version}`
|
|
1874
|
+
});
|
|
1875
|
+
continue;
|
|
1876
|
+
}
|
|
1877
|
+
fallbacks.push(spec);
|
|
1878
|
+
}
|
|
1879
|
+
return { theme: theme ?? undefined, fallbacks, themeMissing };
|
|
1880
|
+
}
|
|
1881
|
+
function resolveTelemetryBinding(binding, registry2) {
|
|
1882
|
+
const telemetryMissing = [];
|
|
1883
|
+
if (!binding?.spec) {
|
|
1884
|
+
return { telemetry: undefined, telemetryMissing };
|
|
1885
|
+
}
|
|
1886
|
+
if (!registry2) {
|
|
1887
|
+
telemetryMissing.push({
|
|
1888
|
+
type: "telemetry",
|
|
1889
|
+
identifier: specPointerKey(binding.spec)
|
|
1890
|
+
});
|
|
1891
|
+
return { telemetry: undefined, telemetryMissing };
|
|
1892
|
+
}
|
|
1893
|
+
const telemetry = registry2.get(binding.spec.key, binding.spec.version);
|
|
1894
|
+
if (!telemetry) {
|
|
1895
|
+
telemetryMissing.push({
|
|
1896
|
+
type: "telemetry",
|
|
1897
|
+
identifier: specPointerKey(binding.spec)
|
|
1898
|
+
});
|
|
1899
|
+
}
|
|
1900
|
+
return { telemetry: telemetry ?? undefined, telemetryMissing };
|
|
1901
|
+
}
|
|
1902
|
+
function resolveExperimentsSpecs(experiments, registry2, missing) {
|
|
1903
|
+
const resolveList = (refs) => {
|
|
1904
|
+
if (refs.length === 0)
|
|
1905
|
+
return [];
|
|
1906
|
+
if (!registry2) {
|
|
1907
|
+
for (const ref of refs) {
|
|
1908
|
+
missing.push({
|
|
1909
|
+
type: "experiment",
|
|
1910
|
+
identifier: experimentKey(ref)
|
|
1911
|
+
});
|
|
1912
|
+
}
|
|
1913
|
+
return [];
|
|
1914
|
+
}
|
|
1915
|
+
const resolved = [];
|
|
1916
|
+
for (const ref of refs) {
|
|
1917
|
+
const spec = registry2.get(ref.key, ref.version);
|
|
1918
|
+
if (!spec) {
|
|
1919
|
+
missing.push({
|
|
1920
|
+
type: "experiment",
|
|
1921
|
+
identifier: experimentKey(ref)
|
|
1922
|
+
});
|
|
1923
|
+
continue;
|
|
1924
|
+
}
|
|
1925
|
+
resolved.push(spec);
|
|
1926
|
+
}
|
|
1927
|
+
return resolved;
|
|
1928
|
+
};
|
|
1929
|
+
return {
|
|
1930
|
+
active: resolveList(experiments.active),
|
|
1931
|
+
paused: resolveList(experiments.paused)
|
|
1932
|
+
};
|
|
1933
|
+
}
|
|
1934
|
+
function capabilityKey2(ref) {
|
|
1935
|
+
return `${ref.key}${ref.version ? `.v${ref.version}` : ""}`;
|
|
1936
|
+
}
|
|
1937
|
+
function featureKey(ref) {
|
|
1938
|
+
return ref.key;
|
|
1939
|
+
}
|
|
1940
|
+
function specPointerKey(pointer) {
|
|
1941
|
+
return `${pointer.key}${pointer.version ? `.v${pointer.version}` : ""}`;
|
|
1942
|
+
}
|
|
1943
|
+
function policyKey(ref) {
|
|
1944
|
+
return `${ref.key}${ref.version ? `.v${ref.version}` : ""}`;
|
|
1945
|
+
}
|
|
1946
|
+
function experimentKey(ref) {
|
|
1947
|
+
return `${ref.key}${ref.version ? `.v${ref.version}` : ""}`;
|
|
1948
|
+
}
|
|
1949
|
+
function dedupeRefs(refs, keyFn) {
|
|
1950
|
+
const map = new Map;
|
|
1951
|
+
for (const ref of refs) {
|
|
1952
|
+
map.set(keyFn(ref), ref);
|
|
1953
|
+
}
|
|
1954
|
+
return [...map.values()];
|
|
1955
|
+
}
|
|
1956
|
+
function dedupeStrings(values) {
|
|
1957
|
+
return [...new Set(values)];
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1960
|
+
// src/app-config/validation.ts
|
|
1961
|
+
class ValidationRuleRegistry {
|
|
1962
|
+
blueprintRules = [];
|
|
1963
|
+
tenantRules = [];
|
|
1964
|
+
resolvedRules = [];
|
|
1965
|
+
register(rule) {
|
|
1966
|
+
if (rule.scope === "blueprint") {
|
|
1967
|
+
this.blueprintRules.push(rule);
|
|
1968
|
+
} else if (rule.scope === "tenant") {
|
|
1969
|
+
this.tenantRules.push(rule);
|
|
1970
|
+
} else {
|
|
1971
|
+
this.resolvedRules.push(rule);
|
|
1972
|
+
}
|
|
1973
|
+
return this;
|
|
1974
|
+
}
|
|
1975
|
+
validateBlueprint(blueprint, context2) {
|
|
1976
|
+
return dedupeIssues(this.blueprintRules.flatMap((rule) => rule.validate(blueprint, context2)));
|
|
1977
|
+
}
|
|
1978
|
+
validateTenant(blueprint, tenant, context2) {
|
|
1979
|
+
return dedupeIssues(this.tenantRules.flatMap((rule) => rule.validate(blueprint, tenant, context2)));
|
|
1980
|
+
}
|
|
1981
|
+
validateResolved(blueprint, resolved, context2) {
|
|
1982
|
+
return dedupeIssues(this.resolvedRules.flatMap((rule) => rule.validate(blueprint, resolved, context2)));
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
var DOMAIN_REGEX = /^(?!:\/\/)([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.[A-Za-z]{2,}$/;
|
|
1986
|
+
var HTTPS_URL_REGEX = /^https:\/\//i;
|
|
1987
|
+
var ALLOWED_ASSET_EXTENSIONS = {
|
|
1988
|
+
logo: ["png", "svg", "webp"],
|
|
1989
|
+
"logo-dark": ["png", "svg", "webp"],
|
|
1990
|
+
favicon: ["ico", "png", "svg"],
|
|
1991
|
+
"og-image": ["png", "jpg", "jpeg", "webp"]
|
|
1992
|
+
};
|
|
1993
|
+
var EMPTY_CONTEXT = {};
|
|
1994
|
+
var registryInstance;
|
|
1995
|
+
function getRegistry() {
|
|
1996
|
+
if (!registryInstance) {
|
|
1997
|
+
registryInstance = createDefaultRegistry();
|
|
1998
|
+
}
|
|
1999
|
+
return registryInstance;
|
|
2000
|
+
}
|
|
2001
|
+
function validateConfig(blueprint, tenant, context2 = EMPTY_CONTEXT) {
|
|
2002
|
+
const registry2 = getRegistry();
|
|
2003
|
+
const blueprintResult = buildResult(registry2.validateBlueprint(blueprint, context2));
|
|
2004
|
+
const tenantResult = buildResult(registry2.validateTenant(blueprint, tenant, context2));
|
|
2005
|
+
return mergeResults(blueprintResult, tenantResult);
|
|
2006
|
+
}
|
|
2007
|
+
function validateBlueprint(blueprint, context2 = EMPTY_CONTEXT) {
|
|
2008
|
+
const issues = getRegistry().validateBlueprint(blueprint, context2);
|
|
2009
|
+
return buildResult(issues);
|
|
2010
|
+
}
|
|
2011
|
+
function validateTenantConfig(blueprint, tenant, context2 = EMPTY_CONTEXT) {
|
|
2012
|
+
const issues = getRegistry().validateTenant(blueprint, tenant, context2);
|
|
2013
|
+
return buildResult(issues);
|
|
2014
|
+
}
|
|
2015
|
+
function validateResolvedConfig(blueprint, resolved, context2 = EMPTY_CONTEXT) {
|
|
2016
|
+
const issues = getRegistry().validateResolved(blueprint, resolved, context2);
|
|
2017
|
+
return buildResult(issues);
|
|
2018
|
+
}
|
|
2019
|
+
function buildResult(issues) {
|
|
2020
|
+
const errors = issues.filter((issue) => issue.severity === "error");
|
|
2021
|
+
const warnings = issues.filter((issue) => issue.severity === "warning");
|
|
2022
|
+
const info = issues.filter((issue) => issue.severity === "info");
|
|
2023
|
+
return {
|
|
2024
|
+
valid: errors.length === 0,
|
|
2025
|
+
errors,
|
|
2026
|
+
warnings,
|
|
2027
|
+
info
|
|
2028
|
+
};
|
|
2029
|
+
}
|
|
2030
|
+
function mergeResults(...results) {
|
|
2031
|
+
const errors = results.flatMap((result) => result.errors);
|
|
2032
|
+
const warnings = results.flatMap((result) => result.warnings);
|
|
2033
|
+
const info = results.flatMap((result) => result.info);
|
|
2034
|
+
return {
|
|
2035
|
+
valid: errors.length === 0,
|
|
2036
|
+
errors,
|
|
2037
|
+
warnings,
|
|
2038
|
+
info
|
|
2039
|
+
};
|
|
2040
|
+
}
|
|
2041
|
+
function createDefaultRegistry() {
|
|
2042
|
+
return new ValidationRuleRegistry().register(blueprintIntegrationSlotRule).register(blueprintCapabilityRegistryRule).register(tenantCapabilityRule).register(tenantIntegrationBindingRule).register(tenantKnowledgeRule).register(tenantBrandingRule).register(tenantTranslationRule).register(resolvedIntegrationRule).register(resolvedTranslationRule);
|
|
2043
|
+
}
|
|
2044
|
+
var blueprintIntegrationSlotRule = {
|
|
2045
|
+
scope: "blueprint",
|
|
2046
|
+
name: "integration.duplicate-slots",
|
|
2047
|
+
category: "integration",
|
|
2048
|
+
validate(blueprint) {
|
|
2049
|
+
const issues = [];
|
|
2050
|
+
const seen = new Set;
|
|
2051
|
+
for (const slot of blueprint.integrationSlots ?? []) {
|
|
2052
|
+
if (seen.has(slot.slotId)) {
|
|
2053
|
+
issues.push(issue({
|
|
2054
|
+
code: "DUPLICATE_SLOT",
|
|
2055
|
+
severity: "error",
|
|
2056
|
+
path: `integrationSlots.${slot.slotId}`,
|
|
2057
|
+
message: `Duplicate integration slot id "${slot.slotId}".`
|
|
2058
|
+
}));
|
|
2059
|
+
} else {
|
|
2060
|
+
seen.add(slot.slotId);
|
|
2061
|
+
}
|
|
2062
|
+
if (slot.allowedModes && slot.allowedModes.length === 0) {
|
|
2063
|
+
issues.push(issue({
|
|
2064
|
+
code: "EMPTY_ALLOWED_MODES",
|
|
2065
|
+
severity: "warning",
|
|
2066
|
+
path: `integrationSlots.${slot.slotId}.allowedModes`,
|
|
2067
|
+
message: "allowedModes is empty; the slot will accept any supported mode."
|
|
2068
|
+
}));
|
|
2069
|
+
}
|
|
2070
|
+
}
|
|
2071
|
+
if (blueprint.branding && !blueprint.branding.appNameKey.trim()) {
|
|
2072
|
+
issues.push(issue({
|
|
2073
|
+
code: "MISSING_APP_NAME_KEY",
|
|
2074
|
+
severity: "warning",
|
|
2075
|
+
path: "branding.appNameKey",
|
|
2076
|
+
message: "branding.appNameKey should reference a translation catalog key."
|
|
2077
|
+
}));
|
|
2078
|
+
}
|
|
2079
|
+
return issues;
|
|
2080
|
+
}
|
|
2081
|
+
};
|
|
2082
|
+
var blueprintCapabilityRegistryRule = {
|
|
2083
|
+
scope: "blueprint",
|
|
2084
|
+
name: "capability.registry-check",
|
|
2085
|
+
category: "capability",
|
|
2086
|
+
validate(blueprint, context2) {
|
|
2087
|
+
const issues = [];
|
|
2088
|
+
const registry2 = context2.capabilities;
|
|
2089
|
+
if (!registry2)
|
|
2090
|
+
return issues;
|
|
2091
|
+
const required = blueprint.capabilities?.enabled ?? [];
|
|
2092
|
+
required.forEach((ref, index) => {
|
|
2093
|
+
if (!registry2.get(ref.key, ref.version)) {
|
|
2094
|
+
issues.push(issue({
|
|
2095
|
+
code: "MISSING_CAPABILITY",
|
|
2096
|
+
severity: "error",
|
|
2097
|
+
path: `capabilities.enabled[${index}]`,
|
|
2098
|
+
message: `Capability "${ref.key}@${ref.version}" is not registered.`
|
|
2099
|
+
}));
|
|
2100
|
+
}
|
|
2101
|
+
});
|
|
2102
|
+
return issues;
|
|
2103
|
+
}
|
|
2104
|
+
};
|
|
2105
|
+
var tenantCapabilityRule = {
|
|
2106
|
+
scope: "tenant",
|
|
2107
|
+
name: "capability.required-enabled",
|
|
2108
|
+
category: "capability",
|
|
2109
|
+
validate(blueprint, tenant, context2) {
|
|
2110
|
+
const issues = [];
|
|
2111
|
+
const registry2 = context2.capabilities;
|
|
2112
|
+
const requiredKeys = new Set((blueprint.capabilities?.enabled ?? []).map(capabilityRefKey));
|
|
2113
|
+
const disabled = tenant.capabilities?.disable ?? [];
|
|
2114
|
+
disabled.forEach((ref, index) => {
|
|
2115
|
+
if (requiredKeys.has(capabilityRefKey(ref))) {
|
|
2116
|
+
issues.push(issue({
|
|
2117
|
+
code: "DISABLED_REQUIRED_CAPABILITY",
|
|
2118
|
+
severity: "error",
|
|
2119
|
+
path: `capabilities.disable[${index}]`,
|
|
2120
|
+
message: `Capability "${ref.key}@${ref.version}" is required by the blueprint and cannot be disabled.`
|
|
2121
|
+
}));
|
|
2122
|
+
}
|
|
2123
|
+
});
|
|
2124
|
+
if (registry2) {
|
|
2125
|
+
(tenant.capabilities?.enable ?? []).forEach((ref, index) => {
|
|
2126
|
+
if (!registry2.get(ref.key, ref.version)) {
|
|
2127
|
+
issues.push(issue({
|
|
2128
|
+
code: "UNKNOWN_CAPABILITY_ENABLE",
|
|
2129
|
+
severity: "error",
|
|
2130
|
+
path: `capabilities.enable[${index}]`,
|
|
2131
|
+
message: `Capability "${ref.key}@${ref.version}" is not registered.`
|
|
2132
|
+
}));
|
|
2133
|
+
}
|
|
2134
|
+
});
|
|
2135
|
+
disabled.forEach((ref, index) => {
|
|
2136
|
+
if (!registry2.get(ref.key, ref.version)) {
|
|
2137
|
+
issues.push(issue({
|
|
2138
|
+
code: "UNKNOWN_CAPABILITY_DISABLE",
|
|
2139
|
+
severity: "warning",
|
|
2140
|
+
path: `capabilities.disable[${index}]`,
|
|
2141
|
+
message: `Capability "${ref.key}@${ref.version}" is not registered.`
|
|
2142
|
+
}));
|
|
2143
|
+
}
|
|
2144
|
+
});
|
|
2145
|
+
}
|
|
2146
|
+
return issues;
|
|
2147
|
+
}
|
|
2148
|
+
};
|
|
2149
|
+
var tenantIntegrationBindingRule = {
|
|
2150
|
+
scope: "tenant",
|
|
2151
|
+
name: "integration.slot-binding",
|
|
2152
|
+
category: "integration",
|
|
2153
|
+
validate(blueprint, tenant, context2) {
|
|
2154
|
+
const issues = [];
|
|
2155
|
+
const slots = new Map((blueprint.integrationSlots ?? []).map((slot) => [slot.slotId, slot]));
|
|
2156
|
+
const bindings = tenant.integrations ?? [];
|
|
2157
|
+
const connections = context2.tenantConnections?.reduce((map, connection) => map.set(connection.meta.id, connection), new Map) ?? new Map;
|
|
2158
|
+
const satisfiedSlots = new Set;
|
|
2159
|
+
bindings.forEach((binding) => {
|
|
2160
|
+
const path = `integrations.${binding.slotId}`;
|
|
2161
|
+
const slot = slots.get(binding.slotId);
|
|
2162
|
+
if (!slot) {
|
|
2163
|
+
issues.push(issue({
|
|
2164
|
+
code: "UNKNOWN_SLOT_BINDING",
|
|
2165
|
+
severity: "error",
|
|
2166
|
+
path,
|
|
2167
|
+
message: `Integration slot "${binding.slotId}" is not defined in the blueprint.`
|
|
2168
|
+
}));
|
|
2169
|
+
return;
|
|
2170
|
+
}
|
|
2171
|
+
let slotValid = true;
|
|
2172
|
+
const connection = connections.get(binding.connectionId);
|
|
2173
|
+
if (!connection) {
|
|
2174
|
+
issues.push(issue({
|
|
2175
|
+
code: "MISSING_INTEGRATION_CONNECTION",
|
|
2176
|
+
severity: "error",
|
|
2177
|
+
path,
|
|
2178
|
+
message: `Integration connection "${binding.connectionId}" was not found for tenant "${tenant.meta.tenantId}".`
|
|
2179
|
+
}));
|
|
2180
|
+
slotValid = false;
|
|
2181
|
+
return;
|
|
2182
|
+
}
|
|
2183
|
+
if (connection.meta.tenantId !== tenant.meta.tenantId) {
|
|
2184
|
+
issues.push(issue({
|
|
2185
|
+
code: "FOREIGN_CONNECTION",
|
|
2186
|
+
severity: "error",
|
|
2187
|
+
path,
|
|
2188
|
+
message: `Connection "${binding.connectionId}" belongs to tenant "${connection.meta.tenantId}", not "${tenant.meta.tenantId}".`
|
|
2189
|
+
}));
|
|
2190
|
+
slotValid = false;
|
|
2191
|
+
}
|
|
2192
|
+
if (slot.allowedModes && slot.allowedModes.length > 0) {
|
|
2193
|
+
if (!slot.allowedModes.includes(connection.ownershipMode)) {
|
|
2194
|
+
issues.push(issue({
|
|
2195
|
+
code: "MODE_MISMATCH",
|
|
2196
|
+
severity: "error",
|
|
2197
|
+
path,
|
|
2198
|
+
message: `Slot "${slot.slotId}" only allows modes [${slot.allowedModes.join(", ")}] but connection is "${connection.ownershipMode}".`
|
|
2199
|
+
}));
|
|
2200
|
+
slotValid = false;
|
|
2201
|
+
}
|
|
2202
|
+
}
|
|
2203
|
+
if (connection.status === "disconnected" || connection.status === "error") {
|
|
2204
|
+
issues.push(issue({
|
|
2205
|
+
code: "CONNECTION_NOT_READY",
|
|
2206
|
+
severity: "error",
|
|
2207
|
+
path,
|
|
2208
|
+
message: `Connection "${connection.meta.label}" is in status "${connection.status}".`
|
|
2209
|
+
}));
|
|
2210
|
+
slotValid = false;
|
|
2211
|
+
} else if (connection.status === "unknown") {
|
|
2212
|
+
issues.push(issue({
|
|
2213
|
+
code: "CONNECTION_STATUS_UNKNOWN",
|
|
2214
|
+
severity: "warning",
|
|
2215
|
+
path,
|
|
2216
|
+
message: `Connection "${connection.meta.label}" has unknown health status.`
|
|
2217
|
+
}));
|
|
2218
|
+
}
|
|
2219
|
+
const spec = lookupIntegrationSpec(context2.integrationSpecs, connection);
|
|
2220
|
+
if (!spec) {
|
|
2221
|
+
issues.push(issue({
|
|
2222
|
+
code: "INTEGRATION_SPEC_NOT_FOUND",
|
|
2223
|
+
severity: "warning",
|
|
2224
|
+
path,
|
|
2225
|
+
message: `Integration spec "${connection.meta.integrationKey}@${connection.meta.integrationVersion}" is not registered.`
|
|
2226
|
+
}));
|
|
2227
|
+
slotValid = false;
|
|
2228
|
+
return;
|
|
2229
|
+
}
|
|
2230
|
+
if (spec.meta.category !== slot.requiredCategory) {
|
|
2231
|
+
issues.push(issue({
|
|
2232
|
+
code: "CATEGORY_MISMATCH",
|
|
2233
|
+
severity: "error",
|
|
2234
|
+
path,
|
|
2235
|
+
message: `Slot "${slot.slotId}" requires category "${slot.requiredCategory}" but connection provides "${spec.meta.category}".`
|
|
2236
|
+
}));
|
|
2237
|
+
slotValid = false;
|
|
2238
|
+
}
|
|
2239
|
+
if (!spec.supportedModes.includes(connection.ownershipMode)) {
|
|
2240
|
+
issues.push(issue({
|
|
2241
|
+
code: "UNSUPPORTED_OWNERSHIP_MODE",
|
|
2242
|
+
severity: "error",
|
|
2243
|
+
path,
|
|
2244
|
+
message: `Integration spec "${spec.meta.key}" does not support ownership mode "${connection.ownershipMode}".`
|
|
2245
|
+
}));
|
|
2246
|
+
slotValid = false;
|
|
2247
|
+
}
|
|
2248
|
+
for (const required of slot.requiredCapabilities ?? []) {
|
|
2249
|
+
if (!integrationProvidesCapability2(spec, required)) {
|
|
2250
|
+
issues.push(issue({
|
|
2251
|
+
code: "CAPABILITY_NOT_PROVIDED",
|
|
2252
|
+
severity: "error",
|
|
2253
|
+
path,
|
|
2254
|
+
message: `Integration "${spec.meta.key}" does not provide required capability "${required.key}@${required.version}".`
|
|
2255
|
+
}));
|
|
2256
|
+
slotValid = false;
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
if (slotValid) {
|
|
2260
|
+
satisfiedSlots.add(slot.slotId);
|
|
2261
|
+
}
|
|
2262
|
+
});
|
|
2263
|
+
for (const slot of slots.values()) {
|
|
2264
|
+
if (slot.required && !satisfiedSlots.has(slot.slotId)) {
|
|
2265
|
+
issues.push(issue({
|
|
2266
|
+
code: "MISSING_REQUIRED_SLOT",
|
|
2267
|
+
severity: "error",
|
|
2268
|
+
path: `integrations.${slot.slotId}`,
|
|
2269
|
+
message: `Required integration slot "${slot.slotId}" is not bound.`
|
|
2270
|
+
}));
|
|
2271
|
+
}
|
|
2272
|
+
}
|
|
2273
|
+
return issues;
|
|
2274
|
+
}
|
|
2275
|
+
};
|
|
2276
|
+
var tenantKnowledgeRule = {
|
|
2277
|
+
scope: "tenant",
|
|
2278
|
+
name: "knowledge.bindings",
|
|
2279
|
+
category: "knowledge",
|
|
2280
|
+
validate(_blueprint, tenant, context2) {
|
|
2281
|
+
const issues = [];
|
|
2282
|
+
const registry2 = context2.knowledgeSpaces;
|
|
2283
|
+
if (!registry2)
|
|
2284
|
+
return issues;
|
|
2285
|
+
const sources = context2.knowledgeSources ?? [];
|
|
2286
|
+
(tenant.knowledge ?? []).forEach((binding, index) => {
|
|
2287
|
+
const path = `knowledge[${index}]`;
|
|
2288
|
+
const space = registry2.get(binding.spaceKey, binding.spaceVersion);
|
|
2289
|
+
if (!space) {
|
|
2290
|
+
issues.push(issue({
|
|
2291
|
+
code: "UNKNOWN_KNOWLEDGE_SPACE",
|
|
2292
|
+
severity: "error",
|
|
2293
|
+
path: `${path}.spaceKey`,
|
|
2294
|
+
message: `Knowledge space "${binding.spaceKey}" is not registered.`
|
|
2295
|
+
}));
|
|
2296
|
+
return;
|
|
2297
|
+
}
|
|
2298
|
+
const hasSources = sources.some((source) => {
|
|
2299
|
+
if (source.meta.spaceKey !== binding.spaceKey)
|
|
2300
|
+
return false;
|
|
2301
|
+
if (binding.spaceVersion != null) {
|
|
2302
|
+
return source.meta.spaceVersion === binding.spaceVersion;
|
|
2303
|
+
}
|
|
2304
|
+
return true;
|
|
2305
|
+
});
|
|
2306
|
+
if (!hasSources) {
|
|
2307
|
+
issues.push(issue({
|
|
2308
|
+
code: "MISSING_KNOWLEDGE_SOURCES",
|
|
2309
|
+
severity: "error",
|
|
2310
|
+
path,
|
|
2311
|
+
message: `Knowledge space "${binding.spaceKey}" has no configured sources for tenant "${tenant.meta.tenantId}".`
|
|
2312
|
+
}));
|
|
2313
|
+
}
|
|
2314
|
+
if (space.meta.category === "external" || space.meta.category === "ephemeral") {
|
|
2315
|
+
issues.push(issue({
|
|
2316
|
+
code: "LOW_TRUST_KNOWLEDGE",
|
|
2317
|
+
severity: "warning",
|
|
2318
|
+
path,
|
|
2319
|
+
message: `Knowledge space "${binding.spaceKey}" has category "${space.meta.category}". Avoid using it for irreversible or policy decisions.`
|
|
2320
|
+
}));
|
|
2321
|
+
}
|
|
2322
|
+
});
|
|
2323
|
+
return issues;
|
|
2324
|
+
}
|
|
2325
|
+
};
|
|
2326
|
+
var tenantBrandingRule = {
|
|
2327
|
+
scope: "tenant",
|
|
2328
|
+
name: "branding.constraints",
|
|
2329
|
+
category: "branding",
|
|
2330
|
+
validate(_blueprint, tenant, context2) {
|
|
2331
|
+
const issues = [];
|
|
2332
|
+
const branding = tenant.branding;
|
|
2333
|
+
if (!branding)
|
|
2334
|
+
return issues;
|
|
2335
|
+
const domain = branding.customDomain?.trim();
|
|
2336
|
+
if (domain) {
|
|
2337
|
+
if (!DOMAIN_REGEX.test(domain)) {
|
|
2338
|
+
issues.push(issue({
|
|
2339
|
+
code: "INVALID_DOMAIN",
|
|
2340
|
+
severity: "error",
|
|
2341
|
+
path: "branding.customDomain",
|
|
2342
|
+
message: `Custom domain "${domain}" is not a valid hostname.`
|
|
2343
|
+
}));
|
|
2344
|
+
}
|
|
2345
|
+
const conflict = (context2.existingConfigs ?? []).find((config) => {
|
|
2346
|
+
if (config.meta.id === tenant.meta.id)
|
|
2347
|
+
return false;
|
|
2348
|
+
const otherDomain = config.branding?.customDomain?.trim();
|
|
2349
|
+
if (!otherDomain)
|
|
2350
|
+
return false;
|
|
2351
|
+
return otherDomain.toLowerCase() === domain.toLowerCase();
|
|
2352
|
+
});
|
|
2353
|
+
if (conflict) {
|
|
2354
|
+
issues.push(issue({
|
|
2355
|
+
code: "DUPLICATE_DOMAIN",
|
|
2356
|
+
severity: "error",
|
|
2357
|
+
path: "branding.customDomain",
|
|
2358
|
+
message: `Custom domain "${domain}" is already used by tenant "${conflict.meta.tenantId}".`
|
|
2359
|
+
}));
|
|
2360
|
+
}
|
|
2361
|
+
}
|
|
2362
|
+
(branding.assets ?? []).forEach((asset, index) => {
|
|
2363
|
+
const assetPath = `branding.assets[${index}]`;
|
|
2364
|
+
if (!HTTPS_URL_REGEX.test(asset.url)) {
|
|
2365
|
+
issues.push(issue({
|
|
2366
|
+
code: "INSECURE_ASSET_URL",
|
|
2367
|
+
severity: "error",
|
|
2368
|
+
path: `${assetPath}.url`,
|
|
2369
|
+
message: `Branding asset "${asset.type}" must use an HTTPS URL.`
|
|
2370
|
+
}));
|
|
2371
|
+
}
|
|
2372
|
+
const allowed = ALLOWED_ASSET_EXTENSIONS[asset.type] ?? ALLOWED_ASSET_EXTENSIONS.logo;
|
|
2373
|
+
const extension = extractExtension(asset.url);
|
|
2374
|
+
if (extension && allowed && !allowed.includes(extension)) {
|
|
2375
|
+
issues.push(issue({
|
|
2376
|
+
code: "UNEXPECTED_ASSET_TYPE",
|
|
2377
|
+
severity: "warning",
|
|
2378
|
+
path: `${assetPath}.url`,
|
|
2379
|
+
message: `Asset "${asset.type}" should use one of: ${(allowed ?? []).join(", ")}. Detected "${extension}".`
|
|
2380
|
+
}));
|
|
2381
|
+
}
|
|
2382
|
+
});
|
|
2383
|
+
return issues;
|
|
2384
|
+
}
|
|
2385
|
+
};
|
|
2386
|
+
var tenantTranslationRule = {
|
|
2387
|
+
scope: "tenant",
|
|
2388
|
+
name: "translation.consistency",
|
|
2389
|
+
category: "translation",
|
|
2390
|
+
validate(blueprint, tenant, context2) {
|
|
2391
|
+
const issues = [];
|
|
2392
|
+
const pointer = blueprint.translationCatalog;
|
|
2393
|
+
const catalogs = normalizeCatalogs(context2.translationCatalogs);
|
|
2394
|
+
const blueprintCatalog = pointer ? catalogs.blueprint.find((catalog) => catalog.meta.key === pointer.key && catalog.meta.version === pointer.version) : undefined;
|
|
2395
|
+
if (pointer && !blueprintCatalog) {
|
|
2396
|
+
issues.push(issue({
|
|
2397
|
+
code: "MISSING_BLUEPRINT_CATALOG",
|
|
2398
|
+
severity: "error",
|
|
2399
|
+
path: "translationCatalog",
|
|
2400
|
+
message: `Blueprint translation catalog "${pointer.key}@${pointer.version}" is not loaded in context.`
|
|
2401
|
+
}));
|
|
2402
|
+
}
|
|
2403
|
+
const requiredKeys = new Set;
|
|
2404
|
+
if (blueprint.branding?.appNameKey) {
|
|
2405
|
+
requiredKeys.add(blueprint.branding.appNameKey);
|
|
2406
|
+
if (blueprintCatalog && !hasTranslationEntry(blueprintCatalog.entries, blueprint.branding.appNameKey, blueprintCatalog.defaultLocale)) {
|
|
2407
|
+
issues.push(issue({
|
|
2408
|
+
code: "MISSING_TRANSLATION_KEY",
|
|
2409
|
+
severity: "error",
|
|
2410
|
+
path: "branding.appNameKey",
|
|
2411
|
+
message: `Translation key "${blueprint.branding.appNameKey}" is missing for locale "${blueprintCatalog.defaultLocale}".`
|
|
2412
|
+
}));
|
|
2413
|
+
}
|
|
2414
|
+
}
|
|
2415
|
+
const tenantLocales = tenant.locales;
|
|
2416
|
+
if (tenantLocales) {
|
|
2417
|
+
const { defaultLocale, enabledLocales } = tenantLocales;
|
|
2418
|
+
if (!enabledLocales.includes(defaultLocale)) {
|
|
2419
|
+
issues.push(issue({
|
|
2420
|
+
code: "LOCALE_NOT_ENABLED",
|
|
2421
|
+
severity: "warning",
|
|
2422
|
+
path: "locales.enabledLocales",
|
|
2423
|
+
message: `enabledLocales does not include defaultLocale "${defaultLocale}".`
|
|
2424
|
+
}));
|
|
2425
|
+
}
|
|
2426
|
+
if (blueprintCatalog) {
|
|
2427
|
+
const supported = new Set(blueprintCatalog.supportedLocales);
|
|
2428
|
+
for (const locale of [defaultLocale, ...enabledLocales]) {
|
|
2429
|
+
if (!supported.has(locale)) {
|
|
2430
|
+
issues.push(issue({
|
|
2431
|
+
code: "UNSUPPORTED_LOCALE",
|
|
2432
|
+
severity: "error",
|
|
2433
|
+
path: "locales.enabledLocales",
|
|
2434
|
+
message: `Locale "${locale}" is not supported by blueprint catalog "${blueprintCatalog.meta.key}".`
|
|
2435
|
+
}));
|
|
2436
|
+
}
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
2439
|
+
}
|
|
2440
|
+
const allowedKeys = new Set;
|
|
2441
|
+
for (const catalog of catalogs.blueprint) {
|
|
2442
|
+
for (const entry of catalog.entries) {
|
|
2443
|
+
allowedKeys.add(entry.key);
|
|
2444
|
+
}
|
|
2445
|
+
}
|
|
2446
|
+
for (const catalog of catalogs.platform) {
|
|
2447
|
+
for (const entry of catalog.entries) {
|
|
2448
|
+
allowedKeys.add(entry.key);
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
2451
|
+
const overrides = tenant.translationOverrides?.entries ?? [];
|
|
2452
|
+
overrides.forEach((entry, index) => {
|
|
2453
|
+
const path = `translationOverrides.entries[${index}]`;
|
|
2454
|
+
if (!allowedKeys.has(entry.key)) {
|
|
2455
|
+
issues.push(issue({
|
|
2456
|
+
code: "UNKNOWN_TRANSLATION_KEY",
|
|
2457
|
+
severity: "error",
|
|
2458
|
+
path,
|
|
2459
|
+
message: `Override references unknown key "${entry.key}".`
|
|
2460
|
+
}));
|
|
2461
|
+
}
|
|
2462
|
+
if (blueprintCatalog) {
|
|
2463
|
+
const supportedLocales = new Set([
|
|
2464
|
+
...blueprintCatalog.supportedLocales,
|
|
2465
|
+
...tenant.locales?.enabledLocales ?? [],
|
|
2466
|
+
tenant.locales?.defaultLocale ?? blueprintCatalog.defaultLocale
|
|
2467
|
+
]);
|
|
2468
|
+
if (!supportedLocales.has(entry.locale)) {
|
|
2469
|
+
issues.push(issue({
|
|
2470
|
+
code: "UNSUPPORTED_LOCALE_OVERRIDE",
|
|
2471
|
+
severity: "error",
|
|
2472
|
+
path,
|
|
2473
|
+
message: `Locale "${entry.locale}" is not enabled for tenant overrides.`
|
|
2474
|
+
}));
|
|
2475
|
+
}
|
|
2476
|
+
}
|
|
2477
|
+
});
|
|
2478
|
+
return issues;
|
|
2479
|
+
}
|
|
2480
|
+
};
|
|
2481
|
+
var resolvedIntegrationRule = {
|
|
2482
|
+
scope: "resolved",
|
|
2483
|
+
name: "integration.required-slots",
|
|
2484
|
+
category: "integration",
|
|
2485
|
+
validate(blueprint, resolved) {
|
|
2486
|
+
const issues = [];
|
|
2487
|
+
const requiredSlots = (blueprint.integrationSlots ?? []).filter((slot) => slot.required);
|
|
2488
|
+
for (const slot of requiredSlots) {
|
|
2489
|
+
const satisfied = resolved.integrations.some((integration) => integration.slot.slotId === slot.slotId);
|
|
2490
|
+
if (!satisfied) {
|
|
2491
|
+
issues.push(issue({
|
|
2492
|
+
code: "MISSING_REQUIRED_SLOT",
|
|
2493
|
+
severity: "error",
|
|
2494
|
+
path: `integrations.${slot.slotId}`,
|
|
2495
|
+
message: `Resolved config is missing integration slot "${slot.slotId}".`
|
|
2496
|
+
}));
|
|
2497
|
+
}
|
|
2498
|
+
}
|
|
2499
|
+
for (const integration of resolved.integrations) {
|
|
2500
|
+
if (integration.connection.status === "disconnected" || integration.connection.status === "error") {
|
|
2501
|
+
issues.push(issue({
|
|
2502
|
+
code: "CONNECTION_NOT_READY",
|
|
2503
|
+
severity: "error",
|
|
2504
|
+
path: `integrations.${integration.slot.slotId}`,
|
|
2505
|
+
message: `Resolved integration "${integration.slot.slotId}" uses a connection in status "${integration.connection.status}".`
|
|
2506
|
+
}));
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2509
|
+
return issues;
|
|
2510
|
+
}
|
|
2511
|
+
};
|
|
2512
|
+
var resolvedTranslationRule = {
|
|
2513
|
+
scope: "resolved",
|
|
2514
|
+
name: "translation.default-locale",
|
|
2515
|
+
category: "translation",
|
|
2516
|
+
validate(_blueprint, resolved) {
|
|
2517
|
+
const issues = [];
|
|
2518
|
+
const translation = resolved.translation;
|
|
2519
|
+
if (translation && !translation.supportedLocales.includes(translation.defaultLocale)) {
|
|
2520
|
+
issues.push(issue({
|
|
2521
|
+
code: "DEFAULT_LOCALE_NOT_SUPPORTED",
|
|
2522
|
+
severity: "warning",
|
|
2523
|
+
path: "translation.defaultLocale",
|
|
2524
|
+
message: "supportedLocales should include defaultLocale for consistent fallback behaviour."
|
|
2525
|
+
}));
|
|
2526
|
+
}
|
|
2527
|
+
return issues;
|
|
2528
|
+
}
|
|
2529
|
+
};
|
|
2530
|
+
function issue(input) {
|
|
2531
|
+
return input;
|
|
2532
|
+
}
|
|
2533
|
+
function dedupeIssues(issues) {
|
|
2534
|
+
const map = new Map;
|
|
2535
|
+
for (const current of issues) {
|
|
2536
|
+
const key = `${current.code}|${current.path}|${current.severity}`;
|
|
2537
|
+
if (!map.has(key)) {
|
|
2538
|
+
map.set(key, current);
|
|
2539
|
+
}
|
|
2540
|
+
}
|
|
2541
|
+
return [...map.values()];
|
|
2542
|
+
}
|
|
2543
|
+
function capabilityRefKey(ref) {
|
|
2544
|
+
return `${ref.key}@${ref.version}`;
|
|
2545
|
+
}
|
|
2546
|
+
function integrationProvidesCapability2(spec, required) {
|
|
2547
|
+
return spec.capabilities.provides.some((provided) => provided.key === required.key && provided.version === required.version);
|
|
2548
|
+
}
|
|
2549
|
+
function lookupIntegrationSpec(registry2, connection) {
|
|
2550
|
+
if (!registry2)
|
|
2551
|
+
return;
|
|
2552
|
+
return registry2.get(connection.meta.integrationKey, connection.meta.integrationVersion);
|
|
2553
|
+
}
|
|
2554
|
+
function extractExtension(url) {
|
|
2555
|
+
const [raw] = url.split("?");
|
|
2556
|
+
if (!raw)
|
|
2557
|
+
return;
|
|
2558
|
+
const lastDot = raw.lastIndexOf(".");
|
|
2559
|
+
if (lastDot === -1)
|
|
2560
|
+
return;
|
|
2561
|
+
return raw.slice(lastDot + 1).toLowerCase();
|
|
2562
|
+
}
|
|
2563
|
+
function normalizeCatalogs(catalogs) {
|
|
2564
|
+
if (!catalogs)
|
|
2565
|
+
return { platform: [], blueprint: [] };
|
|
2566
|
+
const platform = catalogs.platform ? Array.isArray(catalogs.platform) ? catalogs.platform : [catalogs.platform] : [];
|
|
2567
|
+
const blueprint = catalogs.blueprint ? Array.isArray(catalogs.blueprint) ? catalogs.blueprint : [catalogs.blueprint] : [];
|
|
2568
|
+
return { platform, blueprint };
|
|
2569
|
+
}
|
|
2570
|
+
function hasTranslationEntry(entries, key, locale) {
|
|
2571
|
+
return entries.some((entry) => entry.key === key && entry.locale === locale);
|
|
2572
|
+
}
|
|
2573
|
+
// src/app-config/lifecycle-contracts.ts
|
|
2574
|
+
import { ScalarTypeEnum as ScalarTypeEnum2, SchemaModel as SchemaModel2 } from "@contractspec/lib.schema";
|
|
2575
|
+
var LifecyclePolicy = {
|
|
2576
|
+
auth: "admin",
|
|
2577
|
+
policies: [{ key: "platform.app-config.manage", version: "1.0.0" }]
|
|
2578
|
+
};
|
|
2579
|
+
var LifecycleReadPolicy = {
|
|
2580
|
+
auth: "admin",
|
|
2581
|
+
policies: [{ key: "platform.app-config.read", version: "1.0.0" }]
|
|
2582
|
+
};
|
|
2583
|
+
var ConfigVersionRecord = new SchemaModel2({
|
|
2584
|
+
name: "ConfigVersionRecord",
|
|
2585
|
+
fields: {
|
|
2586
|
+
meta: { type: ScalarTypeEnum2.JSONObject(), isOptional: false },
|
|
2587
|
+
config: { type: ScalarTypeEnum2.JSONObject(), isOptional: false }
|
|
2588
|
+
}
|
|
2589
|
+
});
|
|
2590
|
+
var ConfigTransitionRecord = new SchemaModel2({
|
|
2591
|
+
name: "ConfigTransitionRecord",
|
|
2592
|
+
fields: {
|
|
2593
|
+
tenantId: { type: ScalarTypeEnum2.ID(), isOptional: false },
|
|
2594
|
+
appId: { type: ScalarTypeEnum2.ID(), isOptional: false },
|
|
2595
|
+
fromStatus: {
|
|
2596
|
+
type: ScalarTypeEnum2.String_unsecure(),
|
|
2597
|
+
isOptional: false
|
|
2598
|
+
},
|
|
2599
|
+
toStatus: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
2600
|
+
version: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
2601
|
+
timestamp: { type: ScalarTypeEnum2.DateTime(), isOptional: false },
|
|
2602
|
+
actor: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
2603
|
+
reason: { type: ScalarTypeEnum2.String_unsecure(), isOptional: true }
|
|
2604
|
+
}
|
|
2605
|
+
});
|
|
2606
|
+
var CreateDraftInput = new SchemaModel2({
|
|
2607
|
+
name: "CreateTenantConfigDraftInput",
|
|
2608
|
+
fields: {
|
|
2609
|
+
tenantId: { type: ScalarTypeEnum2.ID(), isOptional: false },
|
|
2610
|
+
appId: { type: ScalarTypeEnum2.ID(), isOptional: false },
|
|
2611
|
+
blueprintName: {
|
|
2612
|
+
type: ScalarTypeEnum2.String_unsecure(),
|
|
2613
|
+
isOptional: false
|
|
2614
|
+
},
|
|
2615
|
+
blueprintVersion: {
|
|
2616
|
+
type: ScalarTypeEnum2.Int_unsecure(),
|
|
2617
|
+
isOptional: false
|
|
2618
|
+
},
|
|
2619
|
+
environment: { type: ScalarTypeEnum2.String_unsecure(), isOptional: true },
|
|
2620
|
+
fromVersion: { type: ScalarTypeEnum2.String_unsecure(), isOptional: true },
|
|
2621
|
+
createdBy: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false }
|
|
2622
|
+
}
|
|
2623
|
+
});
|
|
2624
|
+
var CreateDraftOutput = new SchemaModel2({
|
|
2625
|
+
name: "CreateTenantConfigDraftOutput",
|
|
2626
|
+
fields: {
|
|
2627
|
+
version: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
2628
|
+
status: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
2629
|
+
createdAt: { type: ScalarTypeEnum2.DateTime(), isOptional: false }
|
|
2630
|
+
}
|
|
2631
|
+
});
|
|
2632
|
+
var CreateTenantConfigDraftCommand = defineCommand({
|
|
2633
|
+
meta: {
|
|
2634
|
+
key: "appConfig.lifecycle.createDraft",
|
|
2635
|
+
version: "1.0.0",
|
|
2636
|
+
description: "Creates a new draft tenant config version.",
|
|
2637
|
+
owners: [OwnersEnum.PlatformSigil],
|
|
2638
|
+
tags: [TagsEnum.Hygiene, "app-config"],
|
|
2639
|
+
stability: StabilityEnum.Experimental,
|
|
2640
|
+
goal: "Allow operators to start editing a new tenant config version.",
|
|
2641
|
+
context: "Invoked by the Studio or automation when starting a new configuration run."
|
|
2642
|
+
},
|
|
2643
|
+
io: {
|
|
2644
|
+
input: CreateDraftInput,
|
|
2645
|
+
output: CreateDraftOutput
|
|
2646
|
+
},
|
|
2647
|
+
policy: LifecyclePolicy,
|
|
2648
|
+
sideEffects: {
|
|
2649
|
+
emits: [
|
|
2650
|
+
{
|
|
2651
|
+
ref: ConfigDraftCreatedEvent.meta,
|
|
2652
|
+
when: "after successful draft creation"
|
|
2653
|
+
}
|
|
2654
|
+
]
|
|
2655
|
+
}
|
|
2656
|
+
});
|
|
2657
|
+
var PromotePreviewInput = new SchemaModel2({
|
|
2658
|
+
name: "PromoteTenantConfigPreviewInput",
|
|
2659
|
+
fields: {
|
|
2660
|
+
tenantId: { type: ScalarTypeEnum2.ID(), isOptional: false },
|
|
2661
|
+
appId: { type: ScalarTypeEnum2.ID(), isOptional: false },
|
|
2662
|
+
version: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
2663
|
+
promotedBy: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false }
|
|
2664
|
+
}
|
|
2665
|
+
});
|
|
2666
|
+
var PromotePreviewOutput = new SchemaModel2({
|
|
2667
|
+
name: "PromoteTenantConfigPreviewOutput",
|
|
2668
|
+
fields: {
|
|
2669
|
+
version: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
2670
|
+
status: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
2671
|
+
warnings: {
|
|
2672
|
+
type: ScalarTypeEnum2.String_unsecure(),
|
|
2673
|
+
isOptional: true,
|
|
2674
|
+
isArray: true
|
|
2675
|
+
}
|
|
2676
|
+
}
|
|
2677
|
+
});
|
|
2678
|
+
var PromoteTenantConfigToPreviewCommand = defineCommand({
|
|
2679
|
+
meta: {
|
|
2680
|
+
key: "appConfig.lifecycle.promoteToPreview",
|
|
2681
|
+
version: "1.0.0",
|
|
2682
|
+
description: "Promotes a draft tenant config to preview/testing state.",
|
|
2683
|
+
owners: [OwnersEnum.PlatformSigil],
|
|
2684
|
+
tags: [TagsEnum.Hygiene, "app-config"],
|
|
2685
|
+
stability: StabilityEnum.Experimental,
|
|
2686
|
+
goal: "Enable validation and testing of draft configurations.",
|
|
2687
|
+
context: "Called when a draft passes initial checks and should be exposed to preview environments."
|
|
2688
|
+
},
|
|
2689
|
+
io: {
|
|
2690
|
+
input: PromotePreviewInput,
|
|
2691
|
+
output: PromotePreviewOutput
|
|
2692
|
+
},
|
|
2693
|
+
policy: LifecyclePolicy,
|
|
2694
|
+
sideEffects: {
|
|
2695
|
+
emits: [
|
|
2696
|
+
{
|
|
2697
|
+
ref: ConfigPromotedToPreviewEvent.meta,
|
|
2698
|
+
when: "after promotion to preview"
|
|
2699
|
+
}
|
|
2700
|
+
]
|
|
2701
|
+
}
|
|
2702
|
+
});
|
|
2703
|
+
var PublishConfigInput = new SchemaModel2({
|
|
2704
|
+
name: "PublishTenantConfigInput",
|
|
2705
|
+
fields: {
|
|
2706
|
+
tenantId: { type: ScalarTypeEnum2.ID(), isOptional: false },
|
|
2707
|
+
appId: { type: ScalarTypeEnum2.ID(), isOptional: false },
|
|
2708
|
+
version: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
2709
|
+
environment: { type: ScalarTypeEnum2.String_unsecure(), isOptional: true },
|
|
2710
|
+
publishedBy: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
2711
|
+
changeSummary: {
|
|
2712
|
+
type: ScalarTypeEnum2.String_unsecure(),
|
|
2713
|
+
isOptional: true
|
|
2714
|
+
}
|
|
2715
|
+
}
|
|
2716
|
+
});
|
|
2717
|
+
var PublishConfigOutput = new SchemaModel2({
|
|
2718
|
+
name: "PublishTenantConfigOutput",
|
|
2719
|
+
fields: {
|
|
2720
|
+
version: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
2721
|
+
status: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
2722
|
+
previousVersion: {
|
|
2723
|
+
type: ScalarTypeEnum2.String_unsecure(),
|
|
2724
|
+
isOptional: true
|
|
2725
|
+
},
|
|
2726
|
+
publishedAt: { type: ScalarTypeEnum2.DateTime(), isOptional: false }
|
|
2727
|
+
}
|
|
2728
|
+
});
|
|
2729
|
+
var PublishTenantConfigCommand = defineCommand({
|
|
2730
|
+
meta: {
|
|
2731
|
+
key: "appConfig.lifecycle.publish",
|
|
2732
|
+
version: "1.0.0",
|
|
2733
|
+
description: "Publishes a preview tenant config to production.",
|
|
2734
|
+
owners: [OwnersEnum.PlatformSigil],
|
|
2735
|
+
tags: [TagsEnum.Hygiene, "app-config"],
|
|
2736
|
+
stability: StabilityEnum.Experimental,
|
|
2737
|
+
goal: "Promote tested configurations to production safely.",
|
|
2738
|
+
context: "Triggered after validation passes and change management approvals are complete."
|
|
2739
|
+
},
|
|
2740
|
+
io: {
|
|
2741
|
+
input: PublishConfigInput,
|
|
2742
|
+
output: PublishConfigOutput
|
|
2743
|
+
},
|
|
2744
|
+
policy: LifecyclePolicy,
|
|
2745
|
+
sideEffects: {
|
|
2746
|
+
emits: [
|
|
2747
|
+
{
|
|
2748
|
+
ref: ConfigPublishedEvent.meta,
|
|
2749
|
+
when: "after publish succeeds"
|
|
2750
|
+
}
|
|
2751
|
+
]
|
|
2752
|
+
}
|
|
2753
|
+
});
|
|
2754
|
+
var RollbackConfigInput = new SchemaModel2({
|
|
2755
|
+
name: "RollbackTenantConfigInput",
|
|
2756
|
+
fields: {
|
|
2757
|
+
tenantId: { type: ScalarTypeEnum2.ID(), isOptional: false },
|
|
2758
|
+
appId: { type: ScalarTypeEnum2.ID(), isOptional: false },
|
|
2759
|
+
toVersion: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
2760
|
+
environment: { type: ScalarTypeEnum2.String_unsecure(), isOptional: true },
|
|
2761
|
+
rolledBackBy: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
2762
|
+
reason: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false }
|
|
2763
|
+
}
|
|
2764
|
+
});
|
|
2765
|
+
var RollbackConfigOutput = new SchemaModel2({
|
|
2766
|
+
name: "RollbackTenantConfigOutput",
|
|
2767
|
+
fields: {
|
|
2768
|
+
newVersion: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
2769
|
+
status: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
2770
|
+
rolledBackFrom: { type: ScalarTypeEnum2.Int_unsecure(), isOptional: false }
|
|
2771
|
+
}
|
|
2772
|
+
});
|
|
2773
|
+
var RollbackTenantConfigCommand = defineCommand({
|
|
2774
|
+
meta: {
|
|
2775
|
+
key: "appConfig.lifecycle.rollback",
|
|
2776
|
+
version: "1.0.0",
|
|
2777
|
+
description: "Rolls back to a previously published tenant config version.",
|
|
2778
|
+
owners: [OwnersEnum.PlatformSigil],
|
|
2779
|
+
tags: [TagsEnum.Hygiene, "app-config"],
|
|
2780
|
+
stability: StabilityEnum.Experimental,
|
|
2781
|
+
goal: "Provide rapid recovery when new configs regress production.",
|
|
2782
|
+
context: "Called manually or automatically when monitoring detects regression and a rollback is required."
|
|
2783
|
+
},
|
|
2784
|
+
io: {
|
|
2785
|
+
input: RollbackConfigInput,
|
|
2786
|
+
output: RollbackConfigOutput
|
|
2787
|
+
},
|
|
2788
|
+
policy: LifecyclePolicy,
|
|
2789
|
+
sideEffects: {
|
|
2790
|
+
emits: [
|
|
2791
|
+
{
|
|
2792
|
+
ref: ConfigRolledBackEvent.meta,
|
|
2793
|
+
when: "after rollback completes"
|
|
2794
|
+
}
|
|
2795
|
+
]
|
|
2796
|
+
}
|
|
2797
|
+
});
|
|
2798
|
+
var ListVersionsInput = new SchemaModel2({
|
|
2799
|
+
name: "ListTenantConfigVersionsInput",
|
|
2800
|
+
fields: {
|
|
2801
|
+
tenantId: { type: ScalarTypeEnum2.ID(), isOptional: false },
|
|
2802
|
+
appId: { type: ScalarTypeEnum2.ID(), isOptional: false }
|
|
2803
|
+
}
|
|
2804
|
+
});
|
|
2805
|
+
var ListVersionsOutput = new SchemaModel2({
|
|
2806
|
+
name: "ListTenantConfigVersionsOutput",
|
|
2807
|
+
fields: {
|
|
2808
|
+
versions: { type: ConfigVersionRecord, isOptional: false, isArray: true },
|
|
2809
|
+
transitions: {
|
|
2810
|
+
type: ConfigTransitionRecord,
|
|
2811
|
+
isOptional: true,
|
|
2812
|
+
isArray: true
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
});
|
|
2816
|
+
var ListTenantConfigVersionsQuery = defineQuery({
|
|
2817
|
+
meta: {
|
|
2818
|
+
key: "appConfig.lifecycle.listVersions",
|
|
2819
|
+
version: "1.0.0",
|
|
2820
|
+
description: "Lists all versions of a tenant configuration.",
|
|
2821
|
+
owners: [OwnersEnum.PlatformSigil],
|
|
2822
|
+
tags: ["app-config", TagsEnum.Hygiene],
|
|
2823
|
+
stability: StabilityEnum.Experimental,
|
|
2824
|
+
goal: "Support lifecycle views and change audit tooling.",
|
|
2825
|
+
context: "Used by the Studio to render history timelines and by automation for change tracking."
|
|
2826
|
+
},
|
|
2827
|
+
io: {
|
|
2828
|
+
input: ListVersionsInput,
|
|
2829
|
+
output: ListVersionsOutput
|
|
2830
|
+
},
|
|
2831
|
+
policy: LifecycleReadPolicy
|
|
2832
|
+
});
|
|
2833
|
+
var GetVersionInput = new SchemaModel2({
|
|
2834
|
+
name: "GetTenantConfigVersionInput",
|
|
2835
|
+
fields: {
|
|
2836
|
+
tenantId: { type: ScalarTypeEnum2.ID(), isOptional: false },
|
|
2837
|
+
appId: { type: ScalarTypeEnum2.ID(), isOptional: false },
|
|
2838
|
+
version: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false }
|
|
2839
|
+
}
|
|
2840
|
+
});
|
|
2841
|
+
var GetVersionOutput = new SchemaModel2({
|
|
2842
|
+
name: "GetTenantConfigVersionOutput",
|
|
2843
|
+
fields: {
|
|
2844
|
+
version: { type: ConfigVersionRecord, isOptional: false }
|
|
2845
|
+
}
|
|
2846
|
+
});
|
|
2847
|
+
var GetTenantConfigVersionQuery = defineQuery({
|
|
2848
|
+
meta: {
|
|
2849
|
+
key: "appConfig.lifecycle.getVersion",
|
|
2850
|
+
version: "1.0.0",
|
|
2851
|
+
description: "Fetches a single tenant config version by id.",
|
|
2852
|
+
owners: [OwnersEnum.PlatformSigil],
|
|
2853
|
+
tags: ["app-config", TagsEnum.Hygiene],
|
|
2854
|
+
stability: StabilityEnum.Experimental,
|
|
2855
|
+
goal: "Allow detail drill-down for lifecycle entries.",
|
|
2856
|
+
context: "Used by automation to fetch config payloads for comparison or export."
|
|
2857
|
+
},
|
|
2858
|
+
io: {
|
|
2859
|
+
input: GetVersionInput,
|
|
2860
|
+
output: GetVersionOutput
|
|
2861
|
+
},
|
|
2862
|
+
policy: LifecycleReadPolicy
|
|
2863
|
+
});
|
|
2864
|
+
var lifecycleContracts = {
|
|
2865
|
+
CreateTenantConfigDraftCommand,
|
|
2866
|
+
PromoteTenantConfigToPreviewCommand,
|
|
2867
|
+
PublishTenantConfigCommand,
|
|
2868
|
+
RollbackTenantConfigCommand,
|
|
2869
|
+
ListTenantConfigVersionsQuery,
|
|
2870
|
+
GetTenantConfigVersionQuery
|
|
2871
|
+
};
|
|
2872
|
+
function registerAppConfigLifecycleContracts(registry2) {
|
|
2873
|
+
return registry2.register(CreateTenantConfigDraftCommand).register(PromoteTenantConfigToPreviewCommand).register(PublishTenantConfigCommand).register(RollbackTenantConfigCommand).register(ListTenantConfigVersionsQuery).register(GetTenantConfigVersionQuery);
|
|
2874
|
+
}
|
|
2875
|
+
export {
|
|
2876
|
+
validateTenantConfig,
|
|
2877
|
+
validateResolvedConfig,
|
|
2878
|
+
validateConfig,
|
|
2879
|
+
validateBlueprint,
|
|
2880
|
+
resolveAppConfig,
|
|
2881
|
+
registerAppConfigLifecycleContracts,
|
|
2882
|
+
makeAppBlueprintKey,
|
|
2883
|
+
lifecycleContracts,
|
|
2884
|
+
defineAppConfig,
|
|
2885
|
+
composeAppConfig,
|
|
2886
|
+
RollbackTenantConfigCommand,
|
|
2887
|
+
PublishTenantConfigCommand,
|
|
2888
|
+
PromoteTenantConfigToPreviewCommand,
|
|
2889
|
+
ListTenantConfigVersionsQuery,
|
|
2890
|
+
GetTenantConfigVersionQuery,
|
|
2891
|
+
CreateTenantConfigDraftCommand,
|
|
2892
|
+
ConfigRolledBackEvent,
|
|
2893
|
+
ConfigPublishedEvent,
|
|
2894
|
+
ConfigPromotedToPreviewEvent,
|
|
2895
|
+
ConfigDraftCreatedEvent,
|
|
2896
|
+
AppConfigFeature,
|
|
2897
|
+
AppConfigCapability,
|
|
2898
|
+
AppBlueprintRegistry
|
|
2899
|
+
};
|