@noodleseed/one 0.161.2 → 0.163.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/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +3 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/billing-catalog-ops.d.ts +4 -0
- package/dist/commands/billing-catalog-ops.d.ts.map +1 -0
- package/dist/commands/billing-catalog-ops.js +58 -0
- package/dist/commands/billing-catalog-ops.js.map +1 -0
- package/dist/commands/billing-ops.d.ts.map +1 -1
- package/dist/commands/billing-ops.js +3 -0
- package/dist/commands/billing-ops.js.map +1 -1
- package/dist/commands/catalog.d.ts.map +1 -1
- package/dist/commands/catalog.js +3 -0
- package/dist/commands/catalog.js.map +1 -1
- package/dist/commands/config-values.d.ts.map +1 -1
- package/dist/commands/config-values.js +16 -0
- package/dist/commands/config-values.js.map +1 -1
- package/dist/commands/installation-variables.d.ts +26 -0
- package/dist/commands/installation-variables.d.ts.map +1 -0
- package/dist/commands/installation-variables.js +171 -0
- package/dist/commands/installation-variables.js.map +1 -0
- package/dist/commands/solutions-activity.d.ts +5 -0
- package/dist/commands/solutions-activity.d.ts.map +1 -0
- package/dist/commands/solutions-activity.js +116 -0
- package/dist/commands/solutions-activity.js.map +1 -0
- package/dist/commands/solutions-connections.d.ts +7 -0
- package/dist/commands/solutions-connections.d.ts.map +1 -0
- package/dist/commands/solutions-connections.js +88 -0
- package/dist/commands/solutions-connections.js.map +1 -0
- package/dist/commands/solutions-installation-options.d.ts +5 -0
- package/dist/commands/solutions-installation-options.d.ts.map +1 -0
- package/dist/commands/solutions-installation-options.js +52 -0
- package/dist/commands/solutions-installation-options.js.map +1 -0
- package/dist/commands/solutions-onboarding.d.ts +5 -0
- package/dist/commands/solutions-onboarding.d.ts.map +1 -0
- package/dist/commands/solutions-onboarding.js +113 -0
- package/dist/commands/solutions-onboarding.js.map +1 -0
- package/dist/commands/solutions-ops.d.ts +7 -0
- package/dist/commands/solutions-ops.d.ts.map +1 -0
- package/dist/commands/solutions-ops.js +544 -0
- package/dist/commands/solutions-ops.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/node_modules/@noodle-borg/admission-limits/dist/counter-store.d.ts +21 -2
- package/node_modules/@noodle-borg/admission-limits/dist/counter-store.js +10 -1
- package/node_modules/@noodle-borg/admission-limits/dist/in-memory-counter-store.d.ts +5 -1
- package/node_modules/@noodle-borg/admission-limits/dist/in-memory-counter-store.js +31 -2
- package/node_modules/@noodle-borg/admission-limits/dist/portable.d.ts +3 -0
- package/node_modules/@noodle-borg/admission-limits/dist/portable.js +3 -0
- package/node_modules/@noodle-borg/admission-limits/dist/public-admission-assertion.d.ts +28 -0
- package/node_modules/@noodle-borg/admission-limits/dist/public-admission-assertion.js +124 -0
- package/node_modules/@noodle-borg/admission-limits/dist/public-record-admission.d.ts +54 -0
- package/node_modules/@noodle-borg/admission-limits/dist/public-record-admission.js +74 -0
- package/node_modules/@noodle-borg/admission-limits/dist/request-attribution.d.ts +11 -0
- package/node_modules/@noodle-borg/admission-limits/dist/request-attribution.js +19 -0
- package/node_modules/@noodle-borg/agent-kit/dist/curated/command-groups.js +4 -0
- package/node_modules/@noodle-borg/agent-kit/dist/curated/error-fixes.js +4 -1
- package/node_modules/@noodle-borg/agent-kit/dist/generated/example-files.js +5 -5
- package/node_modules/@noodle-borg/agent-kit/dist/generated/surface.js +6 -0
- package/node_modules/@noodle-borg/agent-kit/dist/skill-authoring-refs.js +21 -2
- package/node_modules/@noodle-borg/agent-kit/dist/skill-content.js +1 -1
- package/node_modules/@noodle-borg/agent-kit/package.json +1 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-configuration.d.ts +9 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-configuration.js +33 -2
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-execution-bound.d.ts +3 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-execution-bound.js +29 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-interaction-state.d.ts +5 -3
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-interaction-state.js +21 -10
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-store.d.ts +1 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-store.js +3 -3
- package/node_modules/@noodle-borg/assistant-gateway/dist/portable.d.ts +1 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/portable.js +1 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/session-target.js +5 -4
- package/node_modules/@noodle-borg/authoring/dist/config.d.ts +20 -0
- package/node_modules/@noodle-borg/authoring/dist/config.js +29 -2
- package/node_modules/@noodle-borg/authoring/dist/connectors.d.ts +6 -1
- package/node_modules/@noodle-borg/authoring/dist/connectors.js +5 -0
- package/node_modules/@noodle-borg/authoring/dist/index.d.ts +2 -1
- package/node_modules/@noodle-borg/authoring/dist/index.js +1 -0
- package/node_modules/@noodle-borg/authoring/dist/json-schema.d.ts +1 -1
- package/node_modules/@noodle-borg/authoring/dist/json-schema.js +15 -2
- package/node_modules/@noodle-borg/authoring/dist/load-authored.js +1 -1
- package/node_modules/@noodle-borg/authoring/dist/managed-collection.d.ts +40 -0
- package/node_modules/@noodle-borg/authoring/dist/managed-collection.js +39 -0
- package/node_modules/@noodle-borg/authoring/dist/platform.d.ts +3 -0
- package/node_modules/@noodle-borg/authoring/dist/platform.js +4 -0
- package/node_modules/@noodle-borg/authoring/dist/server-presentation.js +43 -0
- package/node_modules/@noodle-borg/authoring/dist/server.d.ts +6 -1
- package/node_modules/@noodle-borg/authoring/dist/server.js +5 -43
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-billing.js +18 -0
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-config.js +31 -4
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-solutions.js +778 -0
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-types.js +7 -0
- package/node_modules/@noodle-borg/cli-catalog/dist/index.js +20 -0
- package/node_modules/@noodle-borg/compiler/dist/artifact/assemble.js +5 -1
- package/node_modules/@noodle-borg/compiler/dist/artifact/catalog-emission.js +3 -1
- package/node_modules/@noodle-borg/compiler/dist/artifact/config.js +3 -0
- package/node_modules/@noodle-borg/compiler/dist/artifact/types.d.ts +26 -0
- package/node_modules/@noodle-borg/compiler/dist/artifact/version.d.ts +9 -1
- package/node_modules/@noodle-borg/compiler/dist/artifact/version.js +9 -1
- package/node_modules/@noodle-borg/compiler/dist/business-variables.d.ts +27 -0
- package/node_modules/@noodle-borg/compiler/dist/business-variables.js +230 -0
- package/node_modules/@noodle-borg/compiler/dist/compile.js +9 -0
- package/node_modules/@noodle-borg/compiler/dist/errors.d.ts +1 -1
- package/node_modules/@noodle-borg/compiler/dist/index.d.ts +5 -1
- package/node_modules/@noodle-borg/compiler/dist/index.js +4 -0
- package/node_modules/@noodle-borg/compiler/dist/managed-collection-controls.d.ts +52 -0
- package/node_modules/@noodle-borg/compiler/dist/managed-collection-controls.js +92 -0
- package/node_modules/@noodle-borg/compiler/dist/managed-collections.d.ts +50 -0
- package/node_modules/@noodle-borg/compiler/dist/managed-collections.js +373 -0
- package/node_modules/@noodle-borg/compiler/dist/manifest/schema.d.ts +114 -36
- package/node_modules/@noodle-borg/compiler/dist/manifest/schema.js +5 -0
- package/node_modules/@noodle-borg/compiler/dist/native-record-operations.d.ts +7 -0
- package/node_modules/@noodle-borg/compiler/dist/native-record-operations.js +59 -0
- package/node_modules/@noodle-borg/connector-defs/dist/compile-http.js +83 -8
- package/node_modules/@noodle-borg/connector-defs/dist/schema.d.ts +31 -1
- package/node_modules/@noodle-borg/connector-defs/dist/schema.js +16 -0
- package/node_modules/@noodle-borg/connector-http/dist/http-connector.d.ts +12 -3
- package/node_modules/@noodle-borg/connector-http/dist/http-connector.js +41 -2
- package/node_modules/@noodle-borg/connector-http/dist/http-response.js +3 -2
- package/node_modules/@noodle-borg/connector-http/dist/mcp/config.js +1 -1
- package/node_modules/@noodle-borg/connector-http/dist/url-resolution.js +1 -1
- package/node_modules/@noodle-borg/control-plane/dist/contracts.d.ts +2 -1
- package/node_modules/@noodle-borg/control-plane/dist/in-memory-organization-store.d.ts +3 -0
- package/node_modules/@noodle-borg/control-plane/dist/in-memory-organization-store.js +11 -0
- package/node_modules/@noodle-borg/control-plane/dist/organization-agreements.d.ts +45 -0
- package/node_modules/@noodle-borg/control-plane/dist/organization-agreements.js +74 -0
- package/node_modules/@noodle-borg/control-plane/dist/portable.d.ts +1 -0
- package/node_modules/@noodle-borg/control-plane/dist/portable.js +1 -0
- package/node_modules/@noodle-borg/module/dist/contract.d.ts +20 -0
- package/node_modules/@noodle-borg/module/dist/platform-human-identity.d.ts +2 -0
- package/node_modules/@noodle-borg/protocol/dist/request-deps.js +1 -0
- package/node_modules/@noodle-borg/protocol/dist/request-state.d.ts +1 -0
- package/node_modules/@noodle-borg/protocol/dist/request-state.js +11 -2
- package/node_modules/@noodle-borg/protocol/dist/sdk-server.d.ts +2 -0
- package/node_modules/@noodle-borg/protocol/dist/v2/input-required.js +2 -1
- package/node_modules/@noodle-borg/protocol/dist/v2/server.js +2 -1
- package/node_modules/@noodle-borg/runtime/dist/ambient-context.js +6 -1
- package/node_modules/@noodle-borg/runtime/dist/broker/types.d.ts +2 -0
- package/node_modules/@noodle-borg/runtime/dist/business-variables.d.ts +15 -0
- package/node_modules/@noodle-borg/runtime/dist/business-variables.js +75 -0
- package/node_modules/@noodle-borg/runtime/dist/confirmation-continuation.js +2 -1
- package/node_modules/@noodle-borg/runtime/dist/confirmation.js +23 -3
- package/node_modules/@noodle-borg/runtime/dist/connector/types.d.ts +17 -1
- package/node_modules/@noodle-borg/runtime/dist/connector-snapshot.js +6 -0
- package/node_modules/@noodle-borg/runtime/dist/execute.d.ts +18 -3
- package/node_modules/@noodle-borg/runtime/dist/execute.js +13 -3
- package/node_modules/@noodle-borg/runtime/dist/index.d.ts +2 -0
- package/node_modules/@noodle-borg/runtime/dist/index.js +1 -0
- package/node_modules/@noodle-borg/runtime/dist/interactive.js +11 -0
- package/node_modules/@noodle-borg/runtime/dist/managed-origins.d.ts +3 -1
- package/node_modules/@noodle-borg/runtime/dist/managed-origins.js +32 -7
- package/node_modules/@noodle-borg/runtime/dist/operation-credential.js +6 -0
- package/node_modules/@noodle-borg/runtime/dist/operation-evidence.d.ts +30 -0
- package/node_modules/@noodle-borg/runtime/dist/operation-evidence.js +68 -0
- package/node_modules/@noodle-borg/runtime/dist/operation-execution.d.ts +2 -2
- package/node_modules/@noodle-borg/runtime/dist/operation-execution.js +142 -71
- package/node_modules/@noodle-borg/runtime/dist/result.d.ts +6 -4
- package/node_modules/@noodle-borg/runtime/dist/tool-dispatch.d.ts +7 -0
- package/node_modules/@noodle-borg/runtime/dist/tool-dispatch.js +48 -4
- package/node_modules/@noodle-borg/service/dist/admission.js +2 -1
- package/node_modules/@noodle-borg/service/dist/application-activity.js +236 -0
- package/node_modules/@noodle-borg/service/dist/application-business-notice.js +28 -0
- package/node_modules/@noodle-borg/service/dist/application-runtime-target.js +141 -0
- package/node_modules/@noodle-borg/service/dist/application-settings-targets.js +72 -0
- package/node_modules/@noodle-borg/service/dist/application-settings.js +210 -0
- package/node_modules/@noodle-borg/service/dist/business-api-admission.js +121 -0
- package/node_modules/@noodle-borg/service/dist/business-information/activity-pagination.js +73 -0
- package/node_modules/@noodle-borg/service/dist/business-information/business-notice.d.ts +24 -0
- package/node_modules/@noodle-borg/service/dist/business-information/business-notice.js +18 -0
- package/node_modules/@noodle-borg/service/dist/business-information/collection-controls.js +51 -0
- package/node_modules/@noodle-borg/service/dist/business-information/contracts.d.ts +439 -0
- package/node_modules/@noodle-borg/service/dist/business-information/contracts.js +5 -0
- package/node_modules/@noodle-borg/service/dist/business-information/definition-resolver.js +94 -0
- package/node_modules/@noodle-borg/service/dist/business-information/in-memory-installation-lifecycle.js +136 -0
- package/node_modules/@noodle-borg/service/dist/business-information/in-memory-invitations.js +160 -0
- package/node_modules/@noodle-borg/service/dist/business-information/in-memory-locks.js +23 -0
- package/node_modules/@noodle-borg/service/dist/business-information/in-memory-store.js +557 -0
- package/node_modules/@noodle-borg/service/dist/business-information/installation-capacity.js +10 -0
- package/node_modules/@noodle-borg/service/dist/business-information/invitations.js +68 -0
- package/node_modules/@noodle-borg/service/dist/business-information/legacy-request-migration.js +60 -0
- package/node_modules/@noodle-borg/service/dist/business-information/managed-releases.js +245 -0
- package/node_modules/@noodle-borg/service/dist/business-information/managed-solution-blueprints.js +51 -0
- package/node_modules/@noodle-borg/service/dist/business-information/managed-solution-executable.js +76 -0
- package/node_modules/@noodle-borg/service/dist/business-information/model.js +393 -0
- package/node_modules/@noodle-borg/service/dist/business-information/native-query.js +162 -0
- package/node_modules/@noodle-borg/service/dist/business-information/native-storage-budget.js +60 -0
- package/node_modules/@noodle-borg/service/dist/business-information/pagination.js +78 -0
- package/node_modules/@noodle-borg/service/dist/business-information/portable.js +15 -0
- package/node_modules/@noodle-borg/service/dist/business-information/principal-authority.d.ts +11 -0
- package/node_modules/@noodle-borg/service/dist/business-information/principal-authority.js +42 -0
- package/node_modules/@noodle-borg/service/dist/business-information/profiles.js +252 -0
- package/node_modules/@noodle-borg/service/dist/business-information/reader-floor.js +26 -0
- package/node_modules/@noodle-borg/service/dist/business-information/source-credential-fence.js +79 -0
- package/node_modules/@noodle-borg/service/dist/business-information/source-custody-budget.js +30 -0
- package/node_modules/@noodle-borg/service/dist/business-information/source-custody-memory.js +122 -0
- package/node_modules/@noodle-borg/service/dist/business-information/source-executor.js +191 -0
- package/node_modules/@noodle-borg/service/dist/business-information/source-ingestion-contracts.js +2 -0
- package/node_modules/@noodle-borg/service/dist/business-information/source-ingestion-coordinator.js +136 -0
- package/node_modules/@noodle-borg/service/dist/business-information/source-ingestion-failures.js +32 -0
- package/node_modules/@noodle-borg/service/dist/business-information/source-ingestion-memory-state.js +154 -0
- package/node_modules/@noodle-borg/service/dist/business-information/source-ingestion-memory-store.js +568 -0
- package/node_modules/@noodle-borg/service/dist/business-information/source-ingestion-memory-types.js +26 -0
- package/node_modules/@noodle-borg/service/dist/business-information/source-ingestion-memory-values.js +59 -0
- package/node_modules/@noodle-borg/service/dist/business-information/source-ingestion-pagination.js +54 -0
- package/node_modules/@noodle-borg/service/dist/business-information/source-ingestion-validation.js +163 -0
- package/node_modules/@noodle-borg/service/dist/business-information/source-refresh-retention.js +29 -0
- package/node_modules/@noodle-borg/service/dist/business-information/validation.js +200 -0
- package/node_modules/@noodle-borg/service/dist/business-information-runtime.js +80 -0
- package/node_modules/@noodle-borg/service/dist/business-onboarding.js +73 -0
- package/node_modules/@noodle-borg/service/dist/connections/types.js +8 -0
- package/node_modules/@noodle-borg/service/dist/credential-binding-index.js +38 -33
- package/node_modules/@noodle-borg/service/dist/deployment-execution.js +275 -0
- package/node_modules/@noodle-borg/service/dist/external-credential-binding-broker.js +19 -1
- package/node_modules/@noodle-borg/service/dist/external-credential-exchange.d.ts +16 -1
- package/node_modules/@noodle-borg/service/dist/modules/host.js +4 -1
- package/node_modules/@noodle-borg/service/dist/native-record-connector.d.ts +20 -0
- package/node_modules/@noodle-borg/service/dist/native-record-connector.js +206 -0
- package/node_modules/@noodle-borg/service/dist/oauth/store.d.ts +5 -2
- package/node_modules/@noodle-borg/service/dist/operation-evidence.js +89 -0
- package/node_modules/@noodle-borg/service/dist/recovery-quarantine.js +49 -0
- package/node_modules/@noodle-borg/service/dist/registry-compile.js +60 -11
- package/node_modules/@noodle-borg/service/dist/registry-deploy-transaction.js +18 -0
- package/node_modules/@noodle-borg/service/dist/registry-rollback.js +2 -1
- package/node_modules/@noodle-borg/service/dist/registry-state.d.ts +1 -1
- package/node_modules/@noodle-borg/service/dist/registry-state.js +6 -3
- package/node_modules/@noodle-borg/service/dist/registry-targets.js +49 -0
- package/node_modules/@noodle-borg/service/dist/registry-types.d.ts +2 -0
- package/node_modules/@noodle-borg/service/dist/registry.d.ts +15 -3
- package/node_modules/@noodle-borg/service/dist/registry.js +177 -137
- package/node_modules/@noodle-borg/service/dist/routes/assistant-appearance.js +3 -2
- package/node_modules/@noodle-borg/service/dist/routes/assistant-clients.js +2 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant-doctor.js +2 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant-embeds.js +8 -3
- package/node_modules/@noodle-borg/service/dist/routes/assistant-interaction-replay.js +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant-interactions.js +48 -36
- package/node_modules/@noodle-borg/service/dist/routes/assistant-public-configuration.js +3 -2
- package/node_modules/@noodle-borg/service/dist/routes/assistant-public-session.js +10 -10
- package/node_modules/@noodle-borg/service/dist/routes/assistant-session-target.js +32 -3
- package/node_modules/@noodle-borg/service/dist/routes/assistant-suggestions.js +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant-transcript.js +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant.js +10 -10
- package/node_modules/@noodle-borg/service/dist/routes/business-information-activity.js +83 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-information-admission.js +26 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-information-channels.js +153 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-information-connections.js +107 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-information-dispatch.js +131 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-information-external.js +79 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-information-installation.js +24 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-information-notice.js +69 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-information-onboarding.js +58 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-information-paths.js +168 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-information-public.js +151 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-information-reader-floor.js +15 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-information-record-create.js +29 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-information-record-reads.js +36 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-information-request.js +64 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-information-settings.js +64 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-information-source.js +249 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-information-staff.js +258 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-information-wire.js +317 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-information.js +592 -0
- package/node_modules/@noodle-borg/service/dist/routes/config-values-dispatch.js +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/config-values.js +26 -4
- package/node_modules/@noodle-borg/service/dist/routes/control-plane.js +19 -233
- package/node_modules/@noodle-borg/service/dist/routes/deployment-activation-response.js +13 -4
- package/node_modules/@noodle-borg/service/dist/service-resource-cleanup.js +6 -0
- package/node_modules/@noodle-borg/service/dist/service.js +77 -6
- package/node_modules/@noodle-borg/service/dist/solution-installation-activation.js +149 -0
- package/node_modules/@noodle-borg/service/dist/source-configuration-authority.js +94 -0
- package/node_modules/@noodle-borg/service/dist/state-catalog.js +6 -5
- package/node_modules/@noodle-borg/service/dist/store/config-values.d.ts +42 -17
- package/node_modules/@noodle-borg/service/dist/store/config-values.js +123 -24
- package/node_modules/@noodle-borg/service/dist/store/in-memory.d.ts +1 -0
- package/node_modules/@noodle-borg/service/dist/store/in-memory.js +3 -0
- package/node_modules/@noodle-borg/service/dist/store/json-file.d.ts +1 -0
- package/node_modules/@noodle-borg/service/dist/store/json-file.js +3 -0
- package/node_modules/@noodle-borg/service/dist/store.d.ts +3 -1
- package/node_modules/@noodle-borg/service/package.json +2 -2
- package/node_modules/@noodle-borg/transport-http/dist/serve-request.js +9 -0
- package/node_modules/@noodle-borg/transport-http/package.json +1 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/application-activity.d.ts +143 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/application-activity.js +90 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/application-channels.d.ts +130 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/application-channels.js +77 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/application-connections.d.ts +105 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/application-connections.js +67 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/application-onboarding.d.ts +27 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/application-onboarding.js +28 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/application-settings.d.ts +112 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/application-settings.js +88 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/assistant.d.ts +1 -1
- package/node_modules/@noodle-borg/wire-contracts/dist/billing-catalog.d.ts +62 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/billing-catalog.js +57 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/billing-enforcement.d.ts +12 -12
- package/node_modules/@noodle-borg/wire-contracts/dist/billing-metering.d.ts +4 -4
- package/node_modules/@noodle-borg/wire-contracts/dist/billing-org-transfer.d.ts +3 -3
- package/node_modules/@noodle-borg/wire-contracts/dist/business-information-query.d.ts +25 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/business-information-query.js +37 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/business-information.d.ts +2241 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/business-information.js +580 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/control-plane.d.ts +2 -2
- package/node_modules/@noodle-borg/wire-contracts/dist/distribution.d.ts +5 -5
- package/node_modules/@noodle-borg/wire-contracts/dist/index.d.ts +12 -3
- package/node_modules/@noodle-borg/wire-contracts/dist/index.js +9 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/knowledge.d.ts +6 -6
- package/node_modules/@noodle-borg/wire-contracts/dist/managed-assistant-sponsorship.d.ts +15 -15
- package/node_modules/@noodle-borg/wire-contracts/dist/platform-account-reset.d.ts +5 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/platform-account-reset.js +1 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/platform-auth.d.ts +66 -66
- package/node_modules/@noodle-borg/wire-contracts/dist/solution-onboarding.d.ts +143 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/solution-onboarding.js +94 -0
- package/node_modules/@noodleseed/assistant/README.md +5 -0
- package/package.json +2 -2
|
@@ -0,0 +1,592 @@
|
|
|
1
|
+
import { readJsonBody, sendJson } from '@noodle-borg/transport-http';
|
|
2
|
+
import { BusinessGrantCreateRequestSchema, formatWireError, ManagedRecordCreateRequestSchema, ManagedRecordMutationRequestSchema, ManagedRecordStatusSchema, SolutionInstallationCreateRequestSchema, SolutionInstallationIntakeRequestSchema, } from '@noodle-borg/wire-contracts';
|
|
3
|
+
import { admitBusinessMutation, admitBusinessTarget, authorizeBusinessApi, } from '../business-api-admission.js';
|
|
4
|
+
import { BUILT_IN_SOLUTION_PROFILES, businessGrantAllows, MANAGED_SOLUTION_PROFILE_KEYS, PayloadValidationError, validateCollectionEnabled, } from '../business-information/portable.js';
|
|
5
|
+
import { sendForbidden } from '../http-util.js';
|
|
6
|
+
import { loadExternalRecord, sendExternalRecordPage, sourceBindingKey, unsupportedExternalOperation, } from './business-information-external.js';
|
|
7
|
+
import { resolveInstallDefinition, stableInstallationId, } from './business-information-installation.js';
|
|
8
|
+
import { createNativeRecord } from './business-information-record-create.js';
|
|
9
|
+
import { cursorRequest, sendNativeRecordActivity } from './business-information-record-reads.js';
|
|
10
|
+
import { expectedRevision, mutationPermission, parseNativeRecordQuery, parseBusinessPaging as parsePaging, requestIdempotencyKey, } from './business-information-request.js';
|
|
11
|
+
import { collectionToWire, externalRecordToWire, grantToWire, installationToWire, profileToWire, recordDetailToWire, recordToWire, } from './business-information-wire.js';
|
|
12
|
+
import { canManageMembers } from './org-admin.js';
|
|
13
|
+
export function handleSolutionCatalog(req, res) {
|
|
14
|
+
if (req.method !== 'GET') {
|
|
15
|
+
methodNotAllowed(res);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
sendJson(res, 200, {
|
|
19
|
+
ok: true,
|
|
20
|
+
data: {
|
|
21
|
+
profiles: MANAGED_SOLUTION_PROFILE_KEYS.map((key) => profileToWire(BUILT_IN_SOLUTION_PROFILES[key])),
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
export async function handleSolutionInstallations(req, res, ref, deps) {
|
|
26
|
+
const identity = await requireIdentity(req, res, deps);
|
|
27
|
+
if (identity === false)
|
|
28
|
+
return;
|
|
29
|
+
if (req.method === 'POST' && ref.installationId === undefined) {
|
|
30
|
+
if (!(await canManageMembers(deps.controlPlane, ref.org, identity))) {
|
|
31
|
+
return sendForbidden(res, 'organization owner required');
|
|
32
|
+
}
|
|
33
|
+
if (!(await admitBusinessTarget(res, ref)))
|
|
34
|
+
return;
|
|
35
|
+
const body = await readJsonBody(req, deps.maxBody);
|
|
36
|
+
if (!body.ok)
|
|
37
|
+
return sendJson(res, body.status, { error: body.error });
|
|
38
|
+
const parsed = SolutionInstallationCreateRequestSchema.safeParse(body.value);
|
|
39
|
+
if (!parsed.success)
|
|
40
|
+
return invalid(res, parsed.error);
|
|
41
|
+
const definition = await resolveInstallDefinition(parsed.data.definition, ref.org, deps.resolvePrivateDefinition);
|
|
42
|
+
if (definition === undefined) {
|
|
43
|
+
return sendJson(res, 404, {
|
|
44
|
+
error: 'solution definition is unavailable',
|
|
45
|
+
code: 'definition_unavailable',
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
const installationId = stableInstallationId(ref.org, parsed.data.appSlug, parsed.data.environment);
|
|
49
|
+
const result = await deps.store.createInstallation({
|
|
50
|
+
scope: {
|
|
51
|
+
org: ref.org,
|
|
52
|
+
app: parsed.data.appSlug,
|
|
53
|
+
env: parsed.data.environment,
|
|
54
|
+
installationId,
|
|
55
|
+
},
|
|
56
|
+
...(parsed.data.definition.kind === 'managed'
|
|
57
|
+
? { profileKey: parsed.data.definition.profileId }
|
|
58
|
+
: { definition }),
|
|
59
|
+
managedCollections: definition.collections.map((collection) => collection.key),
|
|
60
|
+
retentionDays: parsed.data.retentionDays,
|
|
61
|
+
actorSubject: identity.subject,
|
|
62
|
+
actorEmail: identity.email,
|
|
63
|
+
});
|
|
64
|
+
if (result.disposition === 'conflict') {
|
|
65
|
+
return sendJson(res, 409, {
|
|
66
|
+
error: 'a different solution is already installed for this app and environment',
|
|
67
|
+
code: 'installation_conflict',
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
const grant = await deps.store.getGrant(result.installation.scope, identity.subject);
|
|
71
|
+
if (grant === undefined || grant.revokedAt !== undefined) {
|
|
72
|
+
return sendForbidden(res, 'business grant required');
|
|
73
|
+
}
|
|
74
|
+
if (parsed.data.businessNotice &&
|
|
75
|
+
!(await deps.store.getBusinessNotice(result.installation.scope))) {
|
|
76
|
+
await deps.store.setBusinessNotice({
|
|
77
|
+
scope: result.installation.scope,
|
|
78
|
+
expectedRevision: 0,
|
|
79
|
+
notice: parsed.data.businessNotice,
|
|
80
|
+
actorSubject: identity.subject,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
const activated = await deps.activateInstallation?.({
|
|
84
|
+
installation: result.installation,
|
|
85
|
+
actor: identity,
|
|
86
|
+
});
|
|
87
|
+
if (activated === undefined || !activated.ok) {
|
|
88
|
+
return sendJson(res, activated?.status ?? 503, {
|
|
89
|
+
ok: false,
|
|
90
|
+
code: activated?.code ?? 'installation_activation_unavailable',
|
|
91
|
+
error: activated?.message ??
|
|
92
|
+
'The installation is saved, but application activation is unavailable. Retry installation when the service is ready.',
|
|
93
|
+
installationId: result.installation.scope.installationId,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
return sendJson(res, result.disposition === 'created' ? 201 : 200, {
|
|
97
|
+
ok: true,
|
|
98
|
+
data: {
|
|
99
|
+
installation: installationToWire(result.installation, grant.role),
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
if (req.method === 'GET' && ref.installationId === undefined) {
|
|
104
|
+
const installations = await deps.store.listInstallations(ref.org);
|
|
105
|
+
const permitted = [];
|
|
106
|
+
for (const installation of installations) {
|
|
107
|
+
const grant = await deps.store.getGrant(installation.scope, identity.subject);
|
|
108
|
+
if (grant !== undefined && grant.revokedAt === undefined) {
|
|
109
|
+
permitted.push({ installation, role: grant.role });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (permitted.length > 0 && !(await admitBusinessTarget(res, ref)))
|
|
113
|
+
return;
|
|
114
|
+
return sendJson(res, 200, {
|
|
115
|
+
ok: true,
|
|
116
|
+
data: {
|
|
117
|
+
installations: permitted.map(({ installation, role }) => installationToWire(installation, role)),
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
if (req.method === 'GET' && ref.installationId !== undefined) {
|
|
122
|
+
const authorized = await requireInstallationGrant(res, ref, identity, deps);
|
|
123
|
+
if (authorized === undefined)
|
|
124
|
+
return;
|
|
125
|
+
return sendJson(res, 200, {
|
|
126
|
+
ok: true,
|
|
127
|
+
data: {
|
|
128
|
+
installation: installationToWire(authorized.installation, authorized.grant.role),
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
if (req.method === 'PATCH' && ref.installationId !== undefined) {
|
|
133
|
+
const authorized = await requireInstallationPermission(res, ref, identity, 'installation:administer', deps);
|
|
134
|
+
if (authorized === undefined)
|
|
135
|
+
return;
|
|
136
|
+
const body = await readJsonBody(req, deps.maxBody);
|
|
137
|
+
if (!body.ok)
|
|
138
|
+
return sendJson(res, body.status, { error: body.error });
|
|
139
|
+
const parsed = SolutionInstallationIntakeRequestSchema.safeParse(body.value);
|
|
140
|
+
if (!parsed.success)
|
|
141
|
+
return invalid(res, parsed.error);
|
|
142
|
+
const result = await deps.store.setIntakeState({
|
|
143
|
+
scope: authorized.scope,
|
|
144
|
+
expectedRevision: parsed.data.expectedRevision,
|
|
145
|
+
active: parsed.data.active,
|
|
146
|
+
actorSubject: identity.subject,
|
|
147
|
+
});
|
|
148
|
+
if (!result.ok)
|
|
149
|
+
return mutationFailure(res, result);
|
|
150
|
+
return sendJson(res, 200, {
|
|
151
|
+
ok: true,
|
|
152
|
+
data: { installation: installationToWire(result.installation, authorized.grant.role) },
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
return methodNotAllowed(res);
|
|
156
|
+
}
|
|
157
|
+
export async function handleBusinessGrants(req, res, ref, deps) {
|
|
158
|
+
const identity = await requireIdentity(req, res, deps);
|
|
159
|
+
if (identity === false)
|
|
160
|
+
return;
|
|
161
|
+
const authorized = await requireInstallationPermission(res, ref, identity, 'grants:manage', deps);
|
|
162
|
+
if (authorized === undefined)
|
|
163
|
+
return;
|
|
164
|
+
const { scope } = authorized.installation;
|
|
165
|
+
if (req.method === 'GET' && ref.subject === undefined) {
|
|
166
|
+
const grants = await deps.store.listGrants(scope);
|
|
167
|
+
return sendJson(res, 200, { ok: true, data: { grants: grants.map(grantToWire) } });
|
|
168
|
+
}
|
|
169
|
+
if (req.method === 'POST' && ref.subject === undefined) {
|
|
170
|
+
const body = await readJsonBody(req, deps.maxBody);
|
|
171
|
+
if (!body.ok)
|
|
172
|
+
return sendJson(res, body.status, { error: body.error });
|
|
173
|
+
const parsed = BusinessGrantCreateRequestSchema.safeParse(body.value);
|
|
174
|
+
if (!parsed.success)
|
|
175
|
+
return invalid(res, parsed.error);
|
|
176
|
+
const result = await deps.store.setGrant({
|
|
177
|
+
scope,
|
|
178
|
+
subject: parsed.data.subject,
|
|
179
|
+
email: parsed.data.email,
|
|
180
|
+
role: parsed.data.role,
|
|
181
|
+
expectedRevision: parsed.data.expectedRevision ?? 0,
|
|
182
|
+
actorSubject: identity.subject,
|
|
183
|
+
});
|
|
184
|
+
if (!result.ok)
|
|
185
|
+
return mutationFailure(res, result);
|
|
186
|
+
return sendJson(res, result.grant.revision === 1 ? 201 : 200, {
|
|
187
|
+
ok: true,
|
|
188
|
+
data: { grant: grantToWire(result.grant) },
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
if (req.method === 'DELETE' && ref.subject !== undefined) {
|
|
192
|
+
const body = await readJsonBody(req, deps.maxBody);
|
|
193
|
+
if (!body.ok)
|
|
194
|
+
return sendJson(res, body.status, { error: body.error });
|
|
195
|
+
const revision = expectedRevision(body.value);
|
|
196
|
+
if (revision === undefined) {
|
|
197
|
+
return sendJson(res, 400, { error: 'expectedRevision must be a positive integer' });
|
|
198
|
+
}
|
|
199
|
+
const result = await deps.store.revokeGrant({
|
|
200
|
+
scope,
|
|
201
|
+
subject: ref.subject,
|
|
202
|
+
expectedRevision: revision,
|
|
203
|
+
actorSubject: identity.subject,
|
|
204
|
+
});
|
|
205
|
+
if (!result.ok)
|
|
206
|
+
return mutationFailure(res, result);
|
|
207
|
+
return sendJson(res, 200, { ok: true, data: { grant: grantToWire(result.grant) } });
|
|
208
|
+
}
|
|
209
|
+
return methodNotAllowed(res);
|
|
210
|
+
}
|
|
211
|
+
export async function handleManagedRecords(req, res, url, ref, deps) {
|
|
212
|
+
const identity = await requireIdentity(req, res, deps);
|
|
213
|
+
if (identity === false)
|
|
214
|
+
return;
|
|
215
|
+
if (ref.collection === undefined)
|
|
216
|
+
return sendJson(res, 404, { error: 'not found' });
|
|
217
|
+
const collection = ref.collection;
|
|
218
|
+
if (ref.action === 'activity' && req.method === 'GET' && ref.recordId !== undefined) {
|
|
219
|
+
const authorized = await requireInstallationPermission(res, ref, identity, 'records:read', deps);
|
|
220
|
+
if (authorized === undefined)
|
|
221
|
+
return;
|
|
222
|
+
const definition = enabledCollection(res, authorized.installation, collection);
|
|
223
|
+
if (definition === undefined)
|
|
224
|
+
return;
|
|
225
|
+
if (definition.authority.authority === 'external') {
|
|
226
|
+
return sendJson(res, 200, { ok: true, data: { activities: [] } });
|
|
227
|
+
}
|
|
228
|
+
return sendNativeRecordActivity(res, url, authorized.installation.scope, collection, ref.recordId, deps.store);
|
|
229
|
+
}
|
|
230
|
+
if (ref.action === 'export' && req.method === 'GET') {
|
|
231
|
+
const authorized = await requireInstallationPermission(res, ref, identity, 'records:export', deps);
|
|
232
|
+
if (authorized === undefined)
|
|
233
|
+
return;
|
|
234
|
+
const definition = enabledCollection(res, authorized.installation, collection);
|
|
235
|
+
if (definition === undefined)
|
|
236
|
+
return;
|
|
237
|
+
const paging = parsePaging(url, 500);
|
|
238
|
+
if (!paging.ok)
|
|
239
|
+
return sendJson(res, 400, { error: paging.error });
|
|
240
|
+
if (definition.authority.authority === 'external') {
|
|
241
|
+
return sendExternalRecordPage(res, authorized.installation, definition, { ...paging.value, limit: paging.value.limit ?? 500 }, deps);
|
|
242
|
+
}
|
|
243
|
+
const page = await cursorRequest(res, () => deps.store.exportRequests({
|
|
244
|
+
scope: authorized.installation.scope,
|
|
245
|
+
collectionKey: collection,
|
|
246
|
+
...paging.value,
|
|
247
|
+
includeDeleted: url.searchParams.get('includeDeleted') === 'true',
|
|
248
|
+
}));
|
|
249
|
+
if (page === undefined)
|
|
250
|
+
return;
|
|
251
|
+
return sendJson(res, 200, {
|
|
252
|
+
ok: true,
|
|
253
|
+
data: {
|
|
254
|
+
records: page.records.map((record) => ({
|
|
255
|
+
...recordToWire(record),
|
|
256
|
+
...(record.content ? { notes: record.content.notes } : {}),
|
|
257
|
+
})),
|
|
258
|
+
...(page.nextCursor === undefined ? {} : { nextCursor: page.nextCursor }),
|
|
259
|
+
},
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
if (ref.recordId === undefined && req.method === 'GET') {
|
|
263
|
+
const authorized = await requireInstallationPermission(res, ref, identity, 'records:read', deps);
|
|
264
|
+
if (authorized === undefined)
|
|
265
|
+
return;
|
|
266
|
+
const definition = enabledCollection(res, authorized.installation, collection);
|
|
267
|
+
if (definition === undefined)
|
|
268
|
+
return;
|
|
269
|
+
const paging = parsePaging(url, 100);
|
|
270
|
+
if (!paging.ok)
|
|
271
|
+
return sendJson(res, 400, { error: paging.error });
|
|
272
|
+
const query = parseNativeRecordQuery(url);
|
|
273
|
+
if (!query.ok)
|
|
274
|
+
return sendJson(res, 400, { error: query.error, code: 'invalid_query' });
|
|
275
|
+
if (definition.authority.authority === 'external') {
|
|
276
|
+
if (Object.keys(query.value).length > 0)
|
|
277
|
+
return sendJson(res, 400, {
|
|
278
|
+
error: 'Field and date queries currently require a native collection.',
|
|
279
|
+
code: 'invalid_query',
|
|
280
|
+
});
|
|
281
|
+
return sendExternalRecordPage(res, authorized.installation, definition, paging.value, deps);
|
|
282
|
+
}
|
|
283
|
+
const statusValue = url.searchParams.get('status');
|
|
284
|
+
const status = statusValue === null ? undefined : ManagedRecordStatusSchema.safeParse(statusValue);
|
|
285
|
+
if (status !== undefined && !status.success)
|
|
286
|
+
return sendJson(res, 400, { error: 'invalid status' });
|
|
287
|
+
const assigneeSubject = url.searchParams.get('assigneeSubject') ?? undefined;
|
|
288
|
+
const page = await cursorRequest(res, () => deps.store.listRequests({
|
|
289
|
+
scope: authorized.installation.scope,
|
|
290
|
+
collectionKey: collection,
|
|
291
|
+
...paging.value,
|
|
292
|
+
...query.value,
|
|
293
|
+
...(status === undefined ? {} : { status: status.data }),
|
|
294
|
+
...(assigneeSubject === undefined ? {} : { assigneeSubject }),
|
|
295
|
+
includeDeleted: url.searchParams.get('includeDeleted') === 'true',
|
|
296
|
+
}));
|
|
297
|
+
if (page === undefined)
|
|
298
|
+
return;
|
|
299
|
+
return sendJson(res, 200, {
|
|
300
|
+
ok: true,
|
|
301
|
+
data: {
|
|
302
|
+
records: page.records.map(recordToWire),
|
|
303
|
+
...(page.nextCursor === undefined ? {} : { nextCursor: page.nextCursor }),
|
|
304
|
+
},
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
if (ref.recordId === undefined && req.method === 'POST') {
|
|
308
|
+
const authorized = await requireInstallationPermission(res, ref, identity, 'records:create', deps);
|
|
309
|
+
if (authorized === undefined)
|
|
310
|
+
return;
|
|
311
|
+
const definition = enabledCollection(res, authorized.installation, collection);
|
|
312
|
+
if (definition === undefined)
|
|
313
|
+
return;
|
|
314
|
+
if (definition.authority.authority === 'external') {
|
|
315
|
+
return unsupportedExternalOperation(res, 'create');
|
|
316
|
+
}
|
|
317
|
+
const idempotencyKey = requestIdempotencyKey(req);
|
|
318
|
+
if (idempotencyKey === undefined) {
|
|
319
|
+
return sendJson(res, 400, { error: 'Idempotency-Key header is required (1-128 characters)' });
|
|
320
|
+
}
|
|
321
|
+
const body = await readJsonBody(req, deps.maxBody);
|
|
322
|
+
if (!body.ok)
|
|
323
|
+
return sendJson(res, body.status, { error: body.error });
|
|
324
|
+
const parsed = ManagedRecordCreateRequestSchema.safeParse(body.value);
|
|
325
|
+
if (!parsed.success)
|
|
326
|
+
return invalid(res, parsed.error);
|
|
327
|
+
const result = await createNativeRecord(res, deps, {
|
|
328
|
+
installation: authorized.installation,
|
|
329
|
+
collection,
|
|
330
|
+
idempotencyKey,
|
|
331
|
+
payload: parsed.data.payload,
|
|
332
|
+
origin: { kind: 'portal' },
|
|
333
|
+
actorSubject: identity.subject,
|
|
334
|
+
admit: () => admitBusinessMutation(res, authorized.scope),
|
|
335
|
+
});
|
|
336
|
+
if (result === undefined)
|
|
337
|
+
return;
|
|
338
|
+
if (result.disposition === 'conflict')
|
|
339
|
+
return idempotencyConflict(res);
|
|
340
|
+
if (result.disposition === 'paused') {
|
|
341
|
+
return sendJson(res, 503, {
|
|
342
|
+
error: 'Record creation requires an active application.',
|
|
343
|
+
code: 'application_unavailable',
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
return sendJson(res, result.disposition === 'created' ? 201 : 200, {
|
|
347
|
+
ok: true,
|
|
348
|
+
data: { record: recordToWire(result.record) },
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
if (ref.recordId !== undefined && req.method === 'GET') {
|
|
352
|
+
const authorized = await requireInstallationPermission(res, ref, identity, 'records:read', deps);
|
|
353
|
+
if (authorized === undefined)
|
|
354
|
+
return;
|
|
355
|
+
const definition = enabledCollection(res, authorized.installation, collection);
|
|
356
|
+
if (definition === undefined)
|
|
357
|
+
return;
|
|
358
|
+
if (definition.authority.authority === 'external') {
|
|
359
|
+
const loaded = await loadExternalRecord(authorized.installation, definition, ref.recordId, deps);
|
|
360
|
+
if (loaded === undefined)
|
|
361
|
+
return sendJson(res, 503, { error: 'collection source unavailable' });
|
|
362
|
+
if (loaded.record === undefined)
|
|
363
|
+
return sendJson(res, 404, { error: 'record not found' });
|
|
364
|
+
return sendJson(res, 200, {
|
|
365
|
+
ok: true,
|
|
366
|
+
data: {
|
|
367
|
+
record: externalRecordToWire(loaded.record, loaded.binding),
|
|
368
|
+
collection: collectionToWire(definition),
|
|
369
|
+
},
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
const record = await deps.store.getRequest(authorized.installation.scope, collection, ref.recordId);
|
|
373
|
+
if (record === undefined)
|
|
374
|
+
return sendJson(res, 404, { error: 'record not found' });
|
|
375
|
+
return sendJson(res, 200, {
|
|
376
|
+
ok: true,
|
|
377
|
+
data: recordDetailToWire(authorized.installation, record),
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
if (ref.recordId !== undefined && req.method === 'PATCH') {
|
|
381
|
+
const body = await readJsonBody(req, deps.maxBody);
|
|
382
|
+
if (!body.ok)
|
|
383
|
+
return sendJson(res, body.status, { error: body.error });
|
|
384
|
+
const parsed = ManagedRecordMutationRequestSchema.safeParse(body.value);
|
|
385
|
+
if (!parsed.success)
|
|
386
|
+
return invalid(res, parsed.error);
|
|
387
|
+
const permission = mutationPermission(parsed.data.operation);
|
|
388
|
+
const authorized = await requireInstallationPermission(res, ref, identity, permission, deps);
|
|
389
|
+
if (authorized === undefined)
|
|
390
|
+
return;
|
|
391
|
+
const definition = enabledCollection(res, authorized.installation, collection);
|
|
392
|
+
if (definition === undefined)
|
|
393
|
+
return;
|
|
394
|
+
if (definition.authority.authority === 'external') {
|
|
395
|
+
return unsupportedExternalOperation(res, parsed.data.operation);
|
|
396
|
+
}
|
|
397
|
+
if (parsed.data.operation === 'migrate-schema') {
|
|
398
|
+
const result = await deps.store.migrateLegacyRequest({
|
|
399
|
+
scope: authorized.installation.scope,
|
|
400
|
+
collectionKey: collection,
|
|
401
|
+
id: ref.recordId,
|
|
402
|
+
expectedRevision: parsed.data.expectedRevision,
|
|
403
|
+
actorSubject: identity.subject,
|
|
404
|
+
});
|
|
405
|
+
if (!result.ok)
|
|
406
|
+
return mutationFailure(res, result);
|
|
407
|
+
return sendJson(res, 200, { ok: true, data: { record: recordToWire(result.record) } });
|
|
408
|
+
}
|
|
409
|
+
let operation;
|
|
410
|
+
if (parsed.data.operation === 'update') {
|
|
411
|
+
operation = {
|
|
412
|
+
kind: 'update',
|
|
413
|
+
payload: parsed.data.patch,
|
|
414
|
+
...(parsed.data.unset ? { unset: parsed.data.unset } : {}),
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
else if (parsed.data.operation === 'assign') {
|
|
418
|
+
if (parsed.data.assigneeSubject !== null) {
|
|
419
|
+
const assigneeGrant = await deps.store.getGrant(authorized.installation.scope, parsed.data.assigneeSubject);
|
|
420
|
+
if (assigneeGrant === undefined ||
|
|
421
|
+
assigneeGrant.revokedAt !== undefined ||
|
|
422
|
+
assigneeGrant.role === 'viewer') {
|
|
423
|
+
return sendJson(res, 422, {
|
|
424
|
+
error: 'assignee must have an active operator grant',
|
|
425
|
+
code: 'invalid_assignee',
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
operation = {
|
|
430
|
+
kind: 'assign',
|
|
431
|
+
assigneeSubject: parsed.data.assigneeSubject ?? undefined,
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
else if (parsed.data.operation === 'set-status') {
|
|
435
|
+
operation = { kind: 'set_status', status: parsed.data.status };
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
operation = { kind: 'add_note', note: parsed.data.note };
|
|
439
|
+
}
|
|
440
|
+
let result;
|
|
441
|
+
try {
|
|
442
|
+
result = await deps.store.mutateRequest({
|
|
443
|
+
scope: authorized.installation.scope,
|
|
444
|
+
collectionKey: collection,
|
|
445
|
+
id: ref.recordId,
|
|
446
|
+
expectedRevision: parsed.data.expectedRevision,
|
|
447
|
+
actorSubject: identity.subject,
|
|
448
|
+
operation,
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
catch (error) {
|
|
452
|
+
if (error instanceof PayloadValidationError) {
|
|
453
|
+
return sendJson(res, 400, { error: error.message, code: error.code });
|
|
454
|
+
}
|
|
455
|
+
throw error;
|
|
456
|
+
}
|
|
457
|
+
if (!result.ok)
|
|
458
|
+
return mutationFailure(res, result);
|
|
459
|
+
return sendJson(res, 200, { ok: true, data: { record: recordToWire(result.record) } });
|
|
460
|
+
}
|
|
461
|
+
if (ref.recordId !== undefined && req.method === 'DELETE') {
|
|
462
|
+
const authorized = await requireInstallationPermission(res, ref, identity, 'records:delete', deps);
|
|
463
|
+
if (authorized === undefined)
|
|
464
|
+
return;
|
|
465
|
+
const definition = enabledCollection(res, authorized.installation, collection);
|
|
466
|
+
if (definition === undefined)
|
|
467
|
+
return;
|
|
468
|
+
const body = await readJsonBody(req, deps.maxBody);
|
|
469
|
+
if (!body.ok)
|
|
470
|
+
return sendJson(res, body.status, { error: body.error });
|
|
471
|
+
const revision = expectedRevision(body.value);
|
|
472
|
+
if (revision === undefined) {
|
|
473
|
+
return sendJson(res, 400, { error: 'expectedRevision must be a positive integer' });
|
|
474
|
+
}
|
|
475
|
+
if (definition.authority.authority === 'external') {
|
|
476
|
+
const loaded = await loadExternalRecord(authorized.installation, definition, ref.recordId, deps);
|
|
477
|
+
if (loaded === undefined)
|
|
478
|
+
return sendJson(res, 503, { error: 'collection source unavailable' });
|
|
479
|
+
if (loaded.record === undefined)
|
|
480
|
+
return sendJson(res, 404, { error: 'record not found' });
|
|
481
|
+
const { record } = loaded;
|
|
482
|
+
if (record.revision !== revision) {
|
|
483
|
+
return sendJson(res, 409, {
|
|
484
|
+
error: 'record revision conflict',
|
|
485
|
+
code: 'revision_conflict',
|
|
486
|
+
currentRevision: record.revision,
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
await deps.sourceStore?.suppressExternalRecord({
|
|
490
|
+
...sourceBindingKey(authorized.installation, definition),
|
|
491
|
+
sourceId: record.source.id,
|
|
492
|
+
reason: 'customer_request',
|
|
493
|
+
now: now(deps),
|
|
494
|
+
});
|
|
495
|
+
const deletedAt = now(deps).toISOString();
|
|
496
|
+
return sendJson(res, 200, {
|
|
497
|
+
ok: true,
|
|
498
|
+
data: {
|
|
499
|
+
recordId: record.id,
|
|
500
|
+
authority: 'external',
|
|
501
|
+
disposition: 'suppressed',
|
|
502
|
+
deletedAt,
|
|
503
|
+
},
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
const result = await deps.store.deleteRequest({
|
|
507
|
+
scope: authorized.installation.scope,
|
|
508
|
+
collectionKey: collection,
|
|
509
|
+
id: ref.recordId,
|
|
510
|
+
expectedRevision: revision,
|
|
511
|
+
actorSubject: identity.subject,
|
|
512
|
+
reason: 'customer_request',
|
|
513
|
+
});
|
|
514
|
+
if (!result.ok)
|
|
515
|
+
return mutationFailure(res, result);
|
|
516
|
+
return sendJson(res, 200, {
|
|
517
|
+
ok: true,
|
|
518
|
+
data: {
|
|
519
|
+
recordId: result.record.id,
|
|
520
|
+
authority: 'native',
|
|
521
|
+
disposition: 'deleted',
|
|
522
|
+
deletedAt: result.record.deletedAt,
|
|
523
|
+
},
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
return methodNotAllowed(res);
|
|
527
|
+
}
|
|
528
|
+
export async function requireIdentity(req, res, deps) {
|
|
529
|
+
return authorizeBusinessApi(req, res, deps);
|
|
530
|
+
}
|
|
531
|
+
export async function requireInstallationGrant(res, ref, identity, deps, permission) {
|
|
532
|
+
if (ref.installationId === undefined)
|
|
533
|
+
return undefined;
|
|
534
|
+
const installation = await deps.store.getInstallationById(ref.org, ref.installationId);
|
|
535
|
+
if (installation === undefined) {
|
|
536
|
+
sendJson(res, 404, { error: 'installation not found' });
|
|
537
|
+
return undefined;
|
|
538
|
+
}
|
|
539
|
+
const grant = await deps.store.getGrant(installation.scope, identity.subject);
|
|
540
|
+
if (grant?.revokedAt !== undefined || grant === undefined) {
|
|
541
|
+
sendForbidden(res, 'business grant required');
|
|
542
|
+
return undefined;
|
|
543
|
+
}
|
|
544
|
+
if (permission && !businessGrantAllows(grant, permission)) {
|
|
545
|
+
sendForbidden(res, `business permission required: ${permission}`);
|
|
546
|
+
return undefined;
|
|
547
|
+
}
|
|
548
|
+
if (!(await admitBusinessTarget(res, installation.scope)))
|
|
549
|
+
return undefined;
|
|
550
|
+
return { installation, scope: installation.scope, grant };
|
|
551
|
+
}
|
|
552
|
+
export async function requireInstallationPermission(res, ref, identity, permission, deps) {
|
|
553
|
+
return requireInstallationGrant(res, ref, identity, deps, permission);
|
|
554
|
+
}
|
|
555
|
+
export function mutationFailure(res, result) {
|
|
556
|
+
const status = result.reason === 'not_found'
|
|
557
|
+
? 404
|
|
558
|
+
: ['conflict', 'last_administrator', 'application_unavailable'].includes(result.reason)
|
|
559
|
+
? 409
|
|
560
|
+
: 422;
|
|
561
|
+
sendJson(res, status, {
|
|
562
|
+
error: result.reason.replaceAll('_', ' '),
|
|
563
|
+
code: result.reason,
|
|
564
|
+
currentRevision: result.currentRevision,
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
export function enabledCollection(res, installation, collection) {
|
|
568
|
+
try {
|
|
569
|
+
return validateCollectionEnabled(installation, collection);
|
|
570
|
+
}
|
|
571
|
+
catch {
|
|
572
|
+
sendJson(res, 404, { error: 'collection not found' });
|
|
573
|
+
return undefined;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
export function now(deps) {
|
|
577
|
+
return deps.now?.() ?? new Date();
|
|
578
|
+
}
|
|
579
|
+
export function invalid(res, error) {
|
|
580
|
+
sendJson(res, 400, { error: formatWireError(error) });
|
|
581
|
+
}
|
|
582
|
+
export function idempotencyConflict(res) {
|
|
583
|
+
sendJson(res, 409, {
|
|
584
|
+
error: 'the idempotency key was already used with different content',
|
|
585
|
+
code: 'idempotency_conflict',
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
export function methodNotAllowed(res) {
|
|
589
|
+
sendJson(res, 405, { error: 'method not allowed' });
|
|
590
|
+
}
|
|
591
|
+
export { createNativeRecord } from './business-information-record-create.js';
|
|
592
|
+
//# sourceMappingURL=business-information.js.map
|
|
@@ -25,7 +25,7 @@ export function dispatchConfigValueRequest(req, res, url, deps) {
|
|
|
25
25
|
deps.applySecurityHeaders(res, deps.tls);
|
|
26
26
|
if (deps.enforceHttps(req, res, deps.tls))
|
|
27
27
|
return true;
|
|
28
|
-
handleConfigValues(req, res, deps.gate, deps.controlPlane, deps.configStore, deps.registry, deps.maxBody, ref, deps.audit, deps.developerGrants).catch(() => {
|
|
28
|
+
handleConfigValues(req, res, deps.gate, deps.controlPlane, deps.configStore, deps.registry, deps.maxBody, ref, deps.audit, deps.developerGrants, deps.installations).catch(() => {
|
|
29
29
|
if (!res.headersSent)
|
|
30
30
|
deps.sendJson(res, 500, { error: 'internal error' });
|
|
31
31
|
});
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { DEVELOPER_CLI_PATH } from '@noodle-borg/developer-mcp';
|
|
2
2
|
import { readJsonBody, sendJson } from '@noodle-borg/transport-http';
|
|
3
3
|
import { configValueSetRequestSchema, EffectiveConfigResponseSchema, formatWireError, RevealSecretResponseSchema, } from '@noodle-borg/wire-contracts';
|
|
4
|
+
import { ApplicationSettings, SettingsError } from '../application-settings.js';
|
|
5
|
+
import { resolveSettingsTargets } from '../application-settings-targets.js';
|
|
4
6
|
import { projectEffectiveConfig, } from '../config-value-projection.js';
|
|
5
7
|
import { sendForbidden } from '../http-util.js';
|
|
6
8
|
import { authorizeControlPlane } from './control-plane.js';
|
|
7
|
-
export async function handleConfigValues(req, res, gate, controlPlane, configStore, registry, maxBody, ref, audit, developerGrants) {
|
|
9
|
+
export async function handleConfigValues(req, res, gate, controlPlane, configStore, registry, maxBody, ref, audit, developerGrants, installations) {
|
|
8
10
|
const identity = await authorizeControlPlane(req, res, gate, {
|
|
9
11
|
requireIdentity: true,
|
|
10
12
|
...developerConfigAccess(developerGrants, controlPlane, ref, req.method),
|
|
@@ -51,14 +53,17 @@ export async function handleConfigValues(req, res, gate, controlPlane, configSto
|
|
|
51
53
|
return sendJson(res, 400, { error: formatWireError(parsed.error) });
|
|
52
54
|
}
|
|
53
55
|
try {
|
|
54
|
-
const
|
|
56
|
+
const input = {
|
|
55
57
|
kind: ref.kind,
|
|
56
58
|
scope: ref.scope,
|
|
57
59
|
name: ref.name,
|
|
58
60
|
value: parsed.data.value,
|
|
59
61
|
...(identity !== undefined ? { updatedBySubject: identity.subject } : {}),
|
|
60
62
|
...(identity?.email !== undefined ? { updatedByEmail: identity.email } : {}),
|
|
61
|
-
}
|
|
63
|
+
};
|
|
64
|
+
const value = ref.kind === 'secret'
|
|
65
|
+
? await configStore.setConfigValue(input)
|
|
66
|
+
: await new ApplicationSettings(configStore).writeTechnical(() => resolveSettingsTargets(registry, ref.scope, installations), input);
|
|
62
67
|
// Durable audit: config name + scope + actor only — the value is NEVER recorded.
|
|
63
68
|
await emitConfigAudit(audit, `config.${ref.kind}.set`, ref, identity);
|
|
64
69
|
return sendJson(res, 200, { ok: true, value });
|
|
@@ -68,7 +73,24 @@ export async function handleConfigValues(req, res, gate, controlPlane, configSto
|
|
|
68
73
|
}
|
|
69
74
|
}
|
|
70
75
|
if (req.method === 'DELETE' && ref.name !== undefined) {
|
|
71
|
-
|
|
76
|
+
try {
|
|
77
|
+
if (ref.kind === 'secret')
|
|
78
|
+
await configStore.deleteConfigValue(ref.kind, ref.scope, ref.name);
|
|
79
|
+
else
|
|
80
|
+
await new ApplicationSettings(configStore).writeTechnical(() => resolveSettingsTargets(registry, ref.scope, installations), {
|
|
81
|
+
kind: ref.kind,
|
|
82
|
+
scope: ref.scope,
|
|
83
|
+
name: ref.name,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
if (!(error instanceof SettingsError))
|
|
88
|
+
throw error;
|
|
89
|
+
return sendJson(res, error.code === 'settings_unavailable' ? 503 : 400, {
|
|
90
|
+
code: error.code,
|
|
91
|
+
error: error.message,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
72
94
|
await emitConfigAudit(audit, `config.${ref.kind}.deleted`, ref, identity);
|
|
73
95
|
res.writeHead(204);
|
|
74
96
|
res.end();
|