@kindgi/api 0.1.4 → 0.1.5
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/agent-binding.d.ts +13 -0
- package/dist/agent-binding.d.ts.map +1 -1
- package/dist/agent-pins.d.ts.map +1 -1
- package/dist/agent-pins.js +18 -2
- package/dist/agent-pins.js.map +1 -1
- package/dist/app.d.ts +110 -17
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +163 -35
- package/dist/app.js.map +1 -1
- package/dist/block-publish.d.ts +56 -0
- package/dist/block-publish.d.ts.map +1 -0
- package/dist/block-publish.js +132 -0
- package/dist/block-publish.js.map +1 -0
- package/dist/caller.d.ts +24 -0
- package/dist/caller.d.ts.map +1 -0
- package/dist/caller.js +47 -0
- package/dist/caller.js.map +1 -0
- package/dist/capability-binding.d.ts +11 -0
- package/dist/capability-binding.d.ts.map +1 -1
- package/dist/cost-binding.d.ts +19 -0
- package/dist/cost-binding.d.ts.map +1 -1
- package/dist/cost-binding.js.map +1 -1
- package/dist/derive-agent-version.d.ts +7 -0
- package/dist/derive-agent-version.d.ts.map +1 -1
- package/dist/derive-agent-version.js +4 -0
- package/dist/derive-agent-version.js.map +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +75 -7
- package/dist/errors.js.map +1 -1
- package/dist/eval-case-binding.d.ts +16 -4
- package/dist/eval-case-binding.d.ts.map +1 -1
- package/dist/eval-run-binding.d.ts +31 -0
- package/dist/eval-run-binding.d.ts.map +1 -1
- package/dist/eval-run-dispatcher.d.ts +7 -0
- package/dist/eval-run-dispatcher.d.ts.map +1 -1
- package/dist/eval-run-dispatcher.js.map +1 -1
- package/dist/eval-sample.d.ts +11 -0
- package/dist/eval-sample.d.ts.map +1 -0
- package/dist/eval-sample.js +34 -0
- package/dist/eval-sample.js.map +1 -0
- package/dist/eval-suite-binding.d.ts +13 -0
- package/dist/eval-suite-binding.d.ts.map +1 -1
- package/dist/eval-suite-binding.js.map +1 -1
- package/dist/flow-binding.d.ts +18 -0
- package/dist/flow-binding.d.ts.map +1 -1
- package/dist/flow-pins.d.ts.map +1 -1
- package/dist/flow-pins.js +18 -2
- package/dist/flow-pins.js.map +1 -1
- package/dist/gate.d.ts.map +1 -1
- package/dist/gate.js +25 -0
- package/dist/gate.js.map +1 -1
- package/dist/handler-binding.d.ts +32 -0
- package/dist/handler-binding.d.ts.map +1 -1
- package/dist/hitl-binding.d.ts +23 -0
- package/dist/hitl-binding.d.ts.map +1 -1
- package/dist/identity-directory-binding.d.ts +82 -4
- package/dist/identity-directory-binding.d.ts.map +1 -1
- package/dist/identity-provider-binding.d.ts +197 -17
- package/dist/identity-provider-binding.d.ts.map +1 -1
- package/dist/improvement-pass-binding.d.ts +196 -0
- package/dist/improvement-pass-binding.d.ts.map +1 -0
- package/dist/improvement-pass-binding.js +9 -0
- package/dist/improvement-pass-binding.js.map +1 -0
- package/dist/index.d.ts +35 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -3
- package/dist/index.js.map +1 -1
- package/dist/judged-dispatcher.d.ts +25 -4
- package/dist/judged-dispatcher.d.ts.map +1 -1
- package/dist/judged-dispatcher.js +43 -6
- package/dist/judged-dispatcher.js.map +1 -1
- package/dist/judgment-binding.d.ts +25 -1
- package/dist/judgment-binding.d.ts.map +1 -1
- package/dist/mcp-endpoint-binding.d.ts +7 -0
- package/dist/mcp-endpoint-binding.d.ts.map +1 -1
- package/dist/memory-binding.d.ts +124 -17
- package/dist/memory-binding.d.ts.map +1 -1
- package/dist/memory-erasure-binding.d.ts +145 -0
- package/dist/memory-erasure-binding.d.ts.map +1 -0
- package/dist/memory-erasure-binding.js +4 -0
- package/dist/memory-erasure-binding.js.map +1 -0
- package/dist/middleware/auth.d.ts +66 -13
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +150 -50
- package/dist/middleware/auth.js.map +1 -1
- package/dist/middleware/authorize.d.ts +9 -0
- package/dist/middleware/authorize.d.ts.map +1 -1
- package/dist/middleware/authorize.js +122 -4
- package/dist/middleware/authorize.js.map +1 -1
- package/dist/middleware/error-mapper.d.ts +5 -0
- package/dist/middleware/error-mapper.d.ts.map +1 -1
- package/dist/middleware/error-mapper.js +14 -1
- package/dist/middleware/error-mapper.js.map +1 -1
- package/dist/middleware/idempotency.d.ts +70 -5
- package/dist/middleware/idempotency.d.ts.map +1 -1
- package/dist/middleware/idempotency.js +174 -41
- package/dist/middleware/idempotency.js.map +1 -1
- package/dist/middleware/key-project.d.ts +17 -0
- package/dist/middleware/key-project.d.ts.map +1 -0
- package/dist/middleware/key-project.js +75 -0
- package/dist/middleware/key-project.js.map +1 -0
- package/dist/middleware/principal.d.ts.map +1 -1
- package/dist/middleware/principal.js +9 -5
- package/dist/middleware/principal.js.map +1 -1
- package/dist/middleware/project-ref.d.ts.map +1 -1
- package/dist/middleware/project-ref.js +3 -0
- package/dist/middleware/project-ref.js.map +1 -1
- package/dist/openapi/generate.d.ts.map +1 -1
- package/dist/openapi/generate.js +5 -2
- package/dist/openapi/generate.js.map +1 -1
- package/dist/openapi/operations.d.ts.map +1 -1
- package/dist/openapi/operations.js +919 -140
- package/dist/openapi/operations.js.map +1 -1
- package/dist/openapi/schemas.d.ts +90 -13
- package/dist/openapi/schemas.d.ts.map +1 -1
- package/dist/openapi/schemas.js +2081 -359
- package/dist/openapi/schemas.js.map +1 -1
- package/dist/person-grants-binding.d.ts +77 -0
- package/dist/person-grants-binding.d.ts.map +1 -0
- package/dist/person-grants-binding.js +4 -0
- package/dist/person-grants-binding.js.map +1 -0
- package/dist/proposal-service.d.ts +121 -0
- package/dist/proposal-service.d.ts.map +1 -0
- package/dist/proposal-service.js +447 -0
- package/dist/proposal-service.js.map +1 -0
- package/dist/proposal-status.d.ts +60 -0
- package/dist/proposal-status.d.ts.map +1 -0
- package/dist/proposal-status.js +109 -0
- package/dist/proposal-status.js.map +1 -0
- package/dist/provider-binding.d.ts +10 -0
- package/dist/provider-binding.d.ts.map +1 -1
- package/dist/publish-refused.d.ts +28 -3
- package/dist/publish-refused.d.ts.map +1 -1
- package/dist/publish-refused.js +24 -3
- package/dist/publish-refused.js.map +1 -1
- package/dist/routes/adapters.d.ts +2 -1
- package/dist/routes/adapters.d.ts.map +1 -1
- package/dist/routes/adapters.js +3 -1
- package/dist/routes/adapters.js.map +1 -1
- package/dist/routes/agent-releases.d.ts +55 -3
- package/dist/routes/agent-releases.d.ts.map +1 -1
- package/dist/routes/agent-releases.js +85 -55
- package/dist/routes/agent-releases.js.map +1 -1
- package/dist/routes/agents.d.ts +12 -1
- package/dist/routes/agents.d.ts.map +1 -1
- package/dist/routes/agents.js +100 -2
- package/dist/routes/agents.js.map +1 -1
- package/dist/routes/approvals.d.ts +15 -3
- package/dist/routes/approvals.d.ts.map +1 -1
- package/dist/routes/approvals.js +133 -122
- package/dist/routes/approvals.js.map +1 -1
- package/dist/routes/artifacts.d.ts +25 -3
- package/dist/routes/artifacts.d.ts.map +1 -1
- package/dist/routes/artifacts.js +116 -7
- package/dist/routes/artifacts.js.map +1 -1
- package/dist/routes/auth.d.ts +25 -1
- package/dist/routes/auth.d.ts.map +1 -1
- package/dist/routes/auth.js +655 -281
- package/dist/routes/auth.js.map +1 -1
- package/dist/routes/blocks.d.ts.map +1 -1
- package/dist/routes/blocks.js +2 -42
- package/dist/routes/blocks.js.map +1 -1
- package/dist/routes/capabilities.d.ts +2 -1
- package/dist/routes/capabilities.d.ts.map +1 -1
- package/dist/routes/capabilities.js +6 -1
- package/dist/routes/capabilities.js.map +1 -1
- package/dist/routes/compliance.d.ts +9 -10
- package/dist/routes/compliance.d.ts.map +1 -1
- package/dist/routes/compliance.js +42 -61
- package/dist/routes/compliance.js.map +1 -1
- package/dist/routes/conversations.d.ts +8 -1
- package/dist/routes/conversations.d.ts.map +1 -1
- package/dist/routes/conversations.js +87 -8
- package/dist/routes/conversations.js.map +1 -1
- package/dist/routes/cost.d.ts +12 -1
- package/dist/routes/cost.d.ts.map +1 -1
- package/dist/routes/cost.js +74 -3
- package/dist/routes/cost.js.map +1 -1
- package/dist/routes/denied.d.ts +11 -0
- package/dist/routes/denied.d.ts.map +1 -0
- package/dist/routes/denied.js +17 -0
- package/dist/routes/denied.js.map +1 -0
- package/dist/routes/deployments.d.ts +10 -1
- package/dist/routes/deployments.d.ts.map +1 -1
- package/dist/routes/deployments.js +171 -13
- package/dist/routes/deployments.js.map +1 -1
- package/dist/routes/eval-comparison.d.ts.map +1 -1
- package/dist/routes/eval-comparison.js +69 -1
- package/dist/routes/eval-comparison.js.map +1 -1
- package/dist/routes/eval-overrides.d.ts +18 -0
- package/dist/routes/eval-overrides.d.ts.map +1 -0
- package/dist/routes/eval-overrides.js +81 -0
- package/dist/routes/eval-overrides.js.map +1 -0
- package/dist/routes/eval-runs.d.ts +10 -1
- package/dist/routes/eval-runs.d.ts.map +1 -1
- package/dist/routes/eval-runs.js +66 -7
- package/dist/routes/eval-runs.js.map +1 -1
- package/dist/routes/eval-suites.d.ts.map +1 -1
- package/dist/routes/eval-suites.js +28 -2
- package/dist/routes/eval-suites.js.map +1 -1
- package/dist/routes/event-triggers.d.ts +5 -1
- package/dist/routes/event-triggers.d.ts.map +1 -1
- package/dist/routes/event-triggers.js +26 -3
- package/dist/routes/event-triggers.js.map +1 -1
- package/dist/routes/export-signing-keys.d.ts +12 -0
- package/dist/routes/export-signing-keys.d.ts.map +1 -0
- package/dist/routes/export-signing-keys.js +24 -0
- package/dist/routes/export-signing-keys.js.map +1 -0
- package/dist/routes/flows.d.ts.map +1 -1
- package/dist/routes/flows.js +9 -1
- package/dist/routes/flows.js.map +1 -1
- package/dist/routes/gate-policies.d.ts +4 -1
- package/dist/routes/gate-policies.d.ts.map +1 -1
- package/dist/routes/gate-policies.js +29 -5
- package/dist/routes/gate-policies.js.map +1 -1
- package/dist/routes/guardrails.d.ts +16 -14
- package/dist/routes/guardrails.d.ts.map +1 -1
- package/dist/routes/guardrails.js +39 -3
- package/dist/routes/guardrails.js.map +1 -1
- package/dist/routes/identity.d.ts +20 -4
- package/dist/routes/identity.d.ts.map +1 -1
- package/dist/routes/identity.js +246 -6
- package/dist/routes/identity.js.map +1 -1
- package/dist/routes/improvement-passes.d.ts +52 -0
- package/dist/routes/improvement-passes.d.ts.map +1 -0
- package/dist/routes/improvement-passes.js +449 -0
- package/dist/routes/improvement-passes.js.map +1 -0
- package/dist/routes/judged-suites.d.ts +50 -0
- package/dist/routes/judged-suites.d.ts.map +1 -1
- package/dist/routes/judged-suites.js +66 -27
- package/dist/routes/judged-suites.js.map +1 -1
- package/dist/routes/judgment-context.d.ts +18 -2
- package/dist/routes/judgment-context.d.ts.map +1 -1
- package/dist/routes/judgment-context.js +63 -5
- package/dist/routes/judgment-context.js.map +1 -1
- package/dist/routes/judgment-flow-context.d.ts.map +1 -1
- package/dist/routes/judgment-flow-context.js +14 -2
- package/dist/routes/judgment-flow-context.js.map +1 -1
- package/dist/routes/judgments.d.ts.map +1 -1
- package/dist/routes/judgments.js +8 -1
- package/dist/routes/judgments.js.map +1 -1
- package/dist/routes/mcp.d.ts.map +1 -1
- package/dist/routes/mcp.js +26 -1
- package/dist/routes/mcp.js.map +1 -1
- package/dist/routes/memory-access.d.ts +43 -0
- package/dist/routes/memory-access.d.ts.map +1 -0
- package/dist/routes/memory-access.js +114 -0
- package/dist/routes/memory-access.js.map +1 -0
- package/dist/routes/memory-erasures.d.ts +25 -0
- package/dist/routes/memory-erasures.d.ts.map +1 -0
- package/dist/routes/memory-erasures.js +214 -0
- package/dist/routes/memory-erasures.js.map +1 -0
- package/dist/routes/memory-parse.d.ts +38 -0
- package/dist/routes/memory-parse.d.ts.map +1 -0
- package/dist/routes/memory-parse.js +199 -0
- package/dist/routes/memory-parse.js.map +1 -0
- package/dist/routes/memory.d.ts +9 -4
- package/dist/routes/memory.d.ts.map +1 -1
- package/dist/routes/memory.js +226 -234
- package/dist/routes/memory.js.map +1 -1
- package/dist/routes/observations.d.ts +4 -1
- package/dist/routes/observations.d.ts.map +1 -1
- package/dist/routes/observations.js +8 -2
- package/dist/routes/observations.js.map +1 -1
- package/dist/routes/pagination.d.ts +7 -0
- package/dist/routes/pagination.d.ts.map +1 -1
- package/dist/routes/pagination.js +10 -0
- package/dist/routes/pagination.js.map +1 -1
- package/dist/routes/policies.d.ts +2 -1
- package/dist/routes/policies.d.ts.map +1 -1
- package/dist/routes/policies.js +3 -1
- package/dist/routes/policies.js.map +1 -1
- package/dist/routes/project-mismatch.d.ts +22 -0
- package/dist/routes/project-mismatch.d.ts.map +1 -0
- package/dist/routes/project-mismatch.js +34 -0
- package/dist/routes/project-mismatch.js.map +1 -0
- package/dist/routes/projects.d.ts +15 -4
- package/dist/routes/projects.d.ts.map +1 -1
- package/dist/routes/projects.js +100 -9
- package/dist/routes/projects.js.map +1 -1
- package/dist/routes/proposals.d.ts +25 -17
- package/dist/routes/proposals.d.ts.map +1 -1
- package/dist/routes/proposals.js +340 -507
- package/dist/routes/proposals.js.map +1 -1
- package/dist/routes/provenance.d.ts +17 -3
- package/dist/routes/provenance.d.ts.map +1 -1
- package/dist/routes/provenance.js +79 -103
- package/dist/routes/provenance.js.map +1 -1
- package/dist/routes/providers.d.ts +17 -1
- package/dist/routes/providers.d.ts.map +1 -1
- package/dist/routes/providers.js +110 -3
- package/dist/routes/providers.js.map +1 -1
- package/dist/routes/public-run-tokens.d.ts.map +1 -1
- package/dist/routes/public-run-tokens.js +3 -0
- package/dist/routes/public-run-tokens.js.map +1 -1
- package/dist/routes/readable-projects.d.ts +26 -0
- package/dist/routes/readable-projects.d.ts.map +1 -0
- package/dist/routes/readable-projects.js +39 -0
- package/dist/routes/readable-projects.js.map +1 -0
- package/dist/routes/runs.d.ts +10 -0
- package/dist/routes/runs.d.ts.map +1 -1
- package/dist/routes/runs.js +92 -42
- package/dist/routes/runs.js.map +1 -1
- package/dist/routes/schedules.d.ts +21 -13
- package/dist/routes/schedules.d.ts.map +1 -1
- package/dist/routes/schedules.js +416 -55
- package/dist/routes/schedules.js.map +1 -1
- package/dist/routes/segments.d.ts +2 -0
- package/dist/routes/segments.d.ts.map +1 -1
- package/dist/routes/segments.js +5 -0
- package/dist/routes/segments.js.map +1 -1
- package/dist/routes/service-accounts.d.ts +17 -0
- package/dist/routes/service-accounts.d.ts.map +1 -0
- package/dist/routes/service-accounts.js +212 -0
- package/dist/routes/service-accounts.js.map +1 -0
- package/dist/routes/sign-in-options.d.ts +50 -0
- package/dist/routes/sign-in-options.d.ts.map +1 -0
- package/dist/routes/sign-in-options.js +98 -0
- package/dist/routes/sign-in-options.js.map +1 -0
- package/dist/routes/signing-keys.d.ts +2 -1
- package/dist/routes/signing-keys.d.ts.map +1 -1
- package/dist/routes/signing-keys.js +3 -1
- package/dist/routes/signing-keys.js.map +1 -1
- package/dist/routes/tenant-access.d.ts +13 -0
- package/dist/routes/tenant-access.d.ts.map +1 -0
- package/dist/routes/tenant-access.js +26 -0
- package/dist/routes/tenant-access.js.map +1 -0
- package/dist/routes/tenant.d.ts.map +1 -1
- package/dist/routes/tenant.js +4 -0
- package/dist/routes/tenant.js.map +1 -1
- package/dist/routes/token-sign-in.d.ts +36 -0
- package/dist/routes/token-sign-in.d.ts.map +1 -0
- package/dist/routes/token-sign-in.js +101 -0
- package/dist/routes/token-sign-in.js.map +1 -0
- package/dist/routes/tokens.d.ts +15 -5
- package/dist/routes/tokens.d.ts.map +1 -1
- package/dist/routes/tokens.js +162 -43
- package/dist/routes/tokens.js.map +1 -1
- package/dist/routes/tools.d.ts.map +1 -1
- package/dist/routes/tools.js +9 -1
- package/dist/routes/tools.js.map +1 -1
- package/dist/routes/trigger-access.d.ts +29 -0
- package/dist/routes/trigger-access.d.ts.map +1 -0
- package/dist/routes/trigger-access.js +33 -0
- package/dist/routes/trigger-access.js.map +1 -0
- package/dist/routes/webhook-endpoints.d.ts +2 -1
- package/dist/routes/webhook-endpoints.d.ts.map +1 -1
- package/dist/routes/webhook-endpoints.js +11 -3
- package/dist/routes/webhook-endpoints.js.map +1 -1
- package/dist/routes/webhooks.d.ts +5 -1
- package/dist/routes/webhooks.d.ts.map +1 -1
- package/dist/routes/webhooks.js +25 -2
- package/dist/routes/webhooks.js.map +1 -1
- package/dist/run-failure.d.ts +21 -0
- package/dist/run-failure.d.ts.map +1 -0
- package/dist/run-failure.js +29 -0
- package/dist/run-failure.js.map +1 -0
- package/dist/service-account-binding.d.ts +108 -0
- package/dist/service-account-binding.d.ts.map +1 -0
- package/dist/service-account-binding.js +4 -0
- package/dist/service-account-binding.js.map +1 -0
- package/dist/session-store-binding.d.ts +61 -13
- package/dist/session-store-binding.d.ts.map +1 -1
- package/dist/signed-export.d.ts +89 -0
- package/dist/signed-export.d.ts.map +1 -0
- package/dist/signed-export.js +149 -0
- package/dist/signed-export.js.map +1 -0
- package/dist/supervisor-binding.d.ts +186 -413
- package/dist/supervisor-binding.d.ts.map +1 -1
- package/dist/testing/app-bindings.d.ts +33 -0
- package/dist/testing/app-bindings.d.ts.map +1 -0
- package/dist/testing/app-bindings.js +112 -0
- package/dist/testing/app-bindings.js.map +1 -0
- package/dist/testing/index.d.ts +11 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +13 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/stub-binding.d.ts +34 -0
- package/dist/testing/stub-binding.d.ts.map +1 -0
- package/dist/testing/stub-binding.js +42 -0
- package/dist/testing/stub-binding.js.map +1 -0
- package/dist/testing/trigger-registry.d.ts +21 -0
- package/dist/testing/trigger-registry.d.ts.map +1 -0
- package/dist/testing/trigger-registry.js +206 -0
- package/dist/testing/trigger-registry.js.map +1 -0
- package/dist/token-admin.d.ts +46 -8
- package/dist/token-admin.d.ts.map +1 -1
- package/dist/token-admin.js.map +1 -1
- package/dist/tool-binding.d.ts +13 -0
- package/dist/tool-binding.d.ts.map +1 -1
- package/dist/trigger-binding.d.ts +2 -2
- package/dist/trigger-binding.d.ts.map +1 -1
- package/dist/trigger-binding.js +1 -1
- package/dist/trigger-binding.js.map +1 -1
- package/dist/types.d.ts +16 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/webhook-endpoint-binding.d.ts +19 -3
- package/dist/webhook-endpoint-binding.d.ts.map +1 -1
- package/dist/webhook-endpoint-binding.js +1 -1
- package/dist/webhook-endpoint-binding.js.map +1 -1
- package/openapi.json +15387 -8789
- package/package.json +26 -22
- package/src/agent-binding.ts +14 -0
- package/src/agent-pins.ts +18 -2
- package/src/app.ts +366 -80
- package/src/block-publish.ts +181 -0
- package/src/caller.ts +62 -0
- package/src/capability-binding.ts +12 -0
- package/src/cost-binding.ts +19 -0
- package/src/derive-agent-version.ts +9 -1
- package/src/errors.ts +75 -7
- package/src/eval-case-binding.ts +17 -1
- package/src/eval-run-binding.ts +31 -0
- package/src/eval-run-dispatcher.ts +7 -0
- package/src/eval-sample.ts +42 -0
- package/src/eval-suite-binding.ts +14 -0
- package/src/flow-binding.ts +19 -0
- package/src/flow-pins.ts +18 -2
- package/src/gate.ts +26 -0
- package/src/handler-binding.ts +36 -1
- package/src/hitl-binding.ts +24 -0
- package/src/identity-directory-binding.ts +85 -4
- package/src/identity-provider-binding.ts +216 -21
- package/src/improvement-pass-binding.ts +193 -0
- package/src/index.ts +153 -31
- package/src/judged-dispatcher.ts +78 -11
- package/src/judgment-binding.ts +25 -1
- package/src/mcp-endpoint-binding.ts +7 -0
- package/src/memory-binding.ts +121 -17
- package/src/memory-erasure-binding.ts +156 -0
- package/src/middleware/auth.ts +228 -62
- package/src/middleware/authorize.ts +155 -3
- package/src/middleware/error-mapper.ts +15 -1
- package/src/middleware/idempotency.ts +230 -43
- package/src/middleware/key-project.ts +86 -0
- package/src/middleware/principal.ts +9 -5
- package/src/middleware/project-ref.ts +3 -0
- package/src/openapi/generate.ts +11 -2
- package/src/openapi/operations.ts +1060 -143
- package/src/openapi/schemas.ts +2387 -469
- package/src/person-grants-binding.ts +76 -0
- package/src/proposal-service.ts +640 -0
- package/src/proposal-status.ts +176 -0
- package/src/provider-binding.ts +10 -0
- package/src/publish-refused.ts +56 -9
- package/src/routes/adapters.ts +4 -0
- package/src/routes/agent-releases.ts +121 -69
- package/src/routes/agents.ts +128 -1
- package/src/routes/approvals.ts +164 -154
- package/src/routes/artifacts.ts +181 -11
- package/src/routes/auth.ts +804 -336
- package/src/routes/blocks.ts +2 -53
- package/src/routes/capabilities.ts +10 -1
- package/src/routes/compliance.ts +60 -99
- package/src/routes/conversations.ts +101 -7
- package/src/routes/cost.ts +110 -4
- package/src/routes/denied.ts +28 -0
- package/src/routes/deployments.ts +210 -17
- package/src/routes/eval-comparison.ts +81 -2
- package/src/routes/eval-overrides.ts +108 -0
- package/src/routes/eval-runs.ts +89 -6
- package/src/routes/eval-suites.ts +32 -2
- package/src/routes/event-triggers.ts +27 -3
- package/src/routes/export-signing-keys.ts +31 -0
- package/src/routes/flows.ts +12 -1
- package/src/routes/gate-policies.ts +37 -6
- package/src/routes/guardrails.ts +61 -2
- package/src/routes/identity.ts +328 -10
- package/src/routes/improvement-passes.ts +541 -0
- package/src/routes/judged-suites.ts +113 -43
- package/src/routes/judgment-context.ts +76 -5
- package/src/routes/judgment-flow-context.ts +16 -2
- package/src/routes/judgments.ts +17 -3
- package/src/routes/mcp.ts +29 -1
- package/src/routes/memory-access.ts +160 -0
- package/src/routes/memory-erasures.ts +240 -0
- package/src/routes/memory-parse.ts +250 -0
- package/src/routes/memory.ts +244 -286
- package/src/routes/observations.ts +15 -2
- package/src/routes/pagination.ts +12 -0
- package/src/routes/policies.ts +7 -1
- package/src/routes/project-mismatch.ts +56 -0
- package/src/routes/projects.ts +107 -13
- package/src/routes/proposals.ts +370 -611
- package/src/routes/provenance.ts +99 -133
- package/src/routes/providers.ts +142 -3
- package/src/routes/public-run-tokens.ts +3 -0
- package/src/routes/readable-projects.ts +66 -0
- package/src/routes/runs.ts +119 -39
- package/src/routes/schedules.ts +472 -60
- package/src/routes/segments.ts +11 -0
- package/src/routes/service-accounts.ts +262 -0
- package/src/routes/sign-in-options.ts +168 -0
- package/src/routes/signing-keys.ts +7 -1
- package/src/routes/tenant-access.ts +37 -0
- package/src/routes/tenant.ts +6 -0
- package/src/routes/token-sign-in.ts +161 -0
- package/src/routes/tokens.ts +172 -46
- package/src/routes/tools.ts +12 -1
- package/src/routes/trigger-access.ts +72 -0
- package/src/routes/webhook-endpoints.ts +15 -3
- package/src/routes/webhooks.ts +26 -2
- package/src/run-failure.ts +42 -0
- package/src/service-account-binding.ts +113 -0
- package/src/session-store-binding.ts +65 -13
- package/src/signed-export.ts +250 -0
- package/src/supervisor-binding.ts +169 -409
- package/src/testing/app-bindings.ts +142 -0
- package/src/testing/index.ts +21 -0
- package/src/testing/stub-binding.ts +53 -0
- package/src/testing/trigger-registry.ts +259 -0
- package/src/token-admin.ts +40 -8
- package/src/tool-binding.ts +14 -0
- package/src/trigger-binding.ts +8 -1
- package/src/types.ts +16 -0
- package/src/webhook-endpoint-binding.ts +18 -3
package/src/routes/tokens.ts
CHANGED
|
@@ -4,31 +4,44 @@
|
|
|
4
4
|
import type { Context, MiddlewareHandler } from 'hono';
|
|
5
5
|
import { Hono } from 'hono';
|
|
6
6
|
|
|
7
|
-
import { ref } from '@kindgi/authz';
|
|
8
7
|
import type { ApiTokenId, ProjectId, TenantId } from '@kindgi/types';
|
|
9
8
|
|
|
9
|
+
import { callerPrincipal, callerRef, isTenantAdmin, principalToWire } from '../caller.js';
|
|
10
|
+
|
|
10
11
|
import { statusFor, toWireError } from '../errors.js';
|
|
11
12
|
import type { Authorizer } from '../middleware/authorize.js';
|
|
13
|
+
import { withholdFromReplay } from '../middleware/idempotency.js';
|
|
12
14
|
import {
|
|
13
15
|
API_TOKEN_ROLES,
|
|
14
16
|
type ApiTokenRecord,
|
|
15
17
|
type ApiTokenRole,
|
|
16
18
|
type TokenAdmin,
|
|
19
|
+
type TokenPrincipal,
|
|
17
20
|
} from '../token-admin.js';
|
|
18
21
|
import type { AppEnv } from '../types.js';
|
|
19
22
|
import { clampLimit, decodeCursor, encodeCursor } from './pagination.js';
|
|
20
23
|
|
|
21
24
|
/**
|
|
22
|
-
* API keys: mint, list, read, revoke.
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
+
* API keys: mint, list, read, revoke. A key acts for one principal (a
|
|
26
|
+
* person or a service account) with that principal's grants; its role is
|
|
27
|
+
* a ceiling under them and its project a narrowing.
|
|
25
28
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
29
|
+
* - **Your own keys:** a person, or a service account's key, may mint,
|
|
30
|
+
* list, read and revoke the keys that act for them.
|
|
31
|
+
* - **Someone else's:** only a tenant admin (`admin` on the tenant when
|
|
32
|
+
* authorization is on, otherwise the `tenant-admin` scope) mints keys
|
|
33
|
+
* for another principal, and sees and revokes every key. A tenant admin
|
|
34
|
+
* whose token names no principal mints, as before principals, keys
|
|
35
|
+
* that are their own service account.
|
|
36
|
+
* - **What a new key may hold:** an `admin` key needs a tenant admin
|
|
37
|
+
* minting it (and, for someone else, a principal that is one: the store
|
|
38
|
+
* refuses `role-exceeds-principal`). Every capability granted must be
|
|
39
|
+
* one the minter holds. A minter narrowed to a project mints only keys
|
|
40
|
+
* narrowed to the same project.
|
|
28
41
|
*/
|
|
29
42
|
export function tokensRouter(admin: TokenAdmin, authorizer?: Authorizer): Hono<AppEnv> {
|
|
30
43
|
const r = new Hono<AppEnv>();
|
|
31
|
-
r.use('/*',
|
|
44
|
+
r.use('/*', requireOwnerOrAdmin(authorizer));
|
|
32
45
|
|
|
33
46
|
// ---------- POST / (mint) ----------
|
|
34
47
|
r.post('/', async (c) => {
|
|
@@ -40,22 +53,15 @@ export function tokensRouter(admin: TokenAdmin, authorizer?: Authorizer): Hono<A
|
|
|
40
53
|
const parsed = parseMintBody(body.value);
|
|
41
54
|
if (parsed.kind === 'err') return fail(c, parsed.error, requestId);
|
|
42
55
|
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
c,
|
|
48
|
-
{
|
|
49
|
-
code: 'permission-denied',
|
|
50
|
-
message: `A key can only be given capabilities its minter holds; you don't hold: ${notHeld.join(', ')}`,
|
|
51
|
-
},
|
|
52
|
-
requestId,
|
|
53
|
-
);
|
|
54
|
-
}
|
|
56
|
+
const owner = keyOwner(c);
|
|
57
|
+
const principal = parsed.value.for ?? owner;
|
|
58
|
+
const refused = await mintRefusal(c, authorizer, owner, principal, parsed.value);
|
|
59
|
+
if (refused !== undefined) return fail(c, refused, requestId);
|
|
55
60
|
|
|
56
61
|
const createdBy = callerRef(c);
|
|
57
62
|
const minted = await admin.mint({
|
|
58
63
|
tenantId,
|
|
64
|
+
...(principal !== undefined && { principal }),
|
|
59
65
|
role: parsed.value.role,
|
|
60
66
|
capabilities: parsed.value.capabilities,
|
|
61
67
|
...(parsed.value.label !== undefined && { label: parsed.value.label }),
|
|
@@ -63,6 +69,11 @@ export function tokensRouter(admin: TokenAdmin, authorizer?: Authorizer): Hono<A
|
|
|
63
69
|
...(parsed.value.projectId !== undefined && { projectId: parsed.value.projectId }),
|
|
64
70
|
...(createdBy !== undefined && { createdBy }),
|
|
65
71
|
});
|
|
72
|
+
if (!('token' in minted)) {
|
|
73
|
+
return fail(c, { code: minted.kind, message: minted.message }, requestId);
|
|
74
|
+
}
|
|
75
|
+
// The key's secret is shown once: an Idempotency-Key repeat doesn't get it.
|
|
76
|
+
withholdFromReplay(c);
|
|
66
77
|
c.status(201);
|
|
67
78
|
return c.json({ ...toWire(minted.record), token: minted.token });
|
|
68
79
|
});
|
|
@@ -81,7 +92,16 @@ export function tokensRouter(admin: TokenAdmin, authorizer?: Authorizer): Hono<A
|
|
|
81
92
|
}
|
|
82
93
|
after = { createdAt: new Date(decoded.createdAt), tokenId: decoded.id as ApiTokenId };
|
|
83
94
|
}
|
|
84
|
-
const
|
|
95
|
+
const filter = parsePrincipalQuery(c.req.query('principal'));
|
|
96
|
+
if (filter.kind === 'err') return fail(c, filter.error, requestId);
|
|
97
|
+
// An admin sees every key (or one principal's); anyone else, their own.
|
|
98
|
+
const principal = (await isTenantAdmin(c, authorizer)) ? filter.value : keyOwner(c);
|
|
99
|
+
const records = await admin.list({
|
|
100
|
+
tenantId,
|
|
101
|
+
limit: limit + 1,
|
|
102
|
+
...(principal !== undefined && { principal }),
|
|
103
|
+
...(after && { after }),
|
|
104
|
+
});
|
|
85
105
|
const hasMore = records.length > limit;
|
|
86
106
|
const page = hasMore ? records.slice(0, limit) : records;
|
|
87
107
|
const last = page[page.length - 1];
|
|
@@ -101,9 +121,8 @@ export function tokensRouter(admin: TokenAdmin, authorizer?: Authorizer): Hono<A
|
|
|
101
121
|
// ---------- GET /:tokenId ----------
|
|
102
122
|
r.get('/:tokenId', async (c) => {
|
|
103
123
|
const requestId = c.get('requestId');
|
|
104
|
-
const tenantId = c.get('tenantId') as TenantId;
|
|
105
124
|
const tokenId = c.req.param('tokenId') as ApiTokenId;
|
|
106
|
-
const record = await
|
|
125
|
+
const record = await visibleKey(c, admin, authorizer, tokenId);
|
|
107
126
|
if (record === undefined) return notFound(c, tokenId, requestId);
|
|
108
127
|
return c.json(toWire(record));
|
|
109
128
|
});
|
|
@@ -113,8 +132,16 @@ export function tokensRouter(admin: TokenAdmin, authorizer?: Authorizer): Hono<A
|
|
|
113
132
|
const requestId = c.get('requestId');
|
|
114
133
|
const tenantId = c.get('tenantId') as TenantId;
|
|
115
134
|
const tokenId = c.req.param('tokenId') as ApiTokenId;
|
|
116
|
-
|
|
117
|
-
|
|
135
|
+
// Someone else's key reads as missing, as it does for `get`.
|
|
136
|
+
if ((await visibleKey(c, admin, authorizer, tokenId)) === undefined) {
|
|
137
|
+
return notFound(c, tokenId, requestId);
|
|
138
|
+
}
|
|
139
|
+
const revokedBy = callerRef(c);
|
|
140
|
+
const outcome = await admin.revoke({
|
|
141
|
+
tenantId,
|
|
142
|
+
tokenId,
|
|
143
|
+
...(revokedBy !== undefined && { revokedBy }),
|
|
144
|
+
});
|
|
118
145
|
if (outcome.kind === 'not-found') return notFound(c, tokenId, requestId);
|
|
119
146
|
return c.json({ tokenId: tokenId as unknown as string, revoked: true });
|
|
120
147
|
});
|
|
@@ -122,18 +149,10 @@ export function tokensRouter(admin: TokenAdmin, authorizer?: Authorizer): Hono<A
|
|
|
122
149
|
return r;
|
|
123
150
|
}
|
|
124
151
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
return async (c, next) => {
|
|
128
|
-
const tenantId = c.get('tenantId') as TenantId;
|
|
129
|
-
const mw = authorizer.authorize('admin', async () =>
|
|
130
|
-
ref('tenant', tenantId as unknown as string),
|
|
131
|
-
);
|
|
132
|
-
return mw(c, next);
|
|
133
|
-
};
|
|
134
|
-
}
|
|
152
|
+
/** A caller with keys of their own, or a tenant admin. */
|
|
153
|
+
function requireOwnerOrAdmin(authorizer: Authorizer | undefined): MiddlewareHandler<AppEnv> {
|
|
135
154
|
return async (c, next) => {
|
|
136
|
-
if (
|
|
155
|
+
if (keyOwner(c) === undefined && !(await isTenantAdmin(c, authorizer))) {
|
|
137
156
|
return fail(
|
|
138
157
|
c,
|
|
139
158
|
{ code: 'permission-denied', message: 'Managing API keys needs a tenant admin' },
|
|
@@ -145,18 +164,80 @@ function requireTenantAdmin(authorizer: Authorizer | undefined): MiddlewareHandl
|
|
|
145
164
|
};
|
|
146
165
|
}
|
|
147
166
|
|
|
148
|
-
/**
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
167
|
+
/**
|
|
168
|
+
* Whom the caller's own keys act for: the person, or the service account
|
|
169
|
+
* the caller's key acts for. A token naming neither (a key from before
|
|
170
|
+
* principals, a static token) has no keys of its own.
|
|
171
|
+
*/
|
|
172
|
+
function keyOwner(c: Context<AppEnv>): TokenPrincipal | undefined {
|
|
173
|
+
const caller = callerPrincipal(c);
|
|
174
|
+
if (caller?.kind === 'service-account' && c.get('serviceAccountId') === undefined) {
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
return caller;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function samePrincipal(a: TokenPrincipal, b: TokenPrincipal | undefined): boolean {
|
|
181
|
+
if (b === undefined) return false;
|
|
182
|
+
if (a.kind === 'user') return b.kind === 'user' && b.userId === a.userId;
|
|
183
|
+
return b.kind === 'service-account' && b.serviceAccountId === a.serviceAccountId;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** Why the route refuses this mint before the store sees it, if it does. */
|
|
187
|
+
async function mintRefusal(
|
|
188
|
+
c: Context<AppEnv>,
|
|
189
|
+
authorizer: Authorizer | undefined,
|
|
190
|
+
owner: TokenPrincipal | undefined,
|
|
191
|
+
principal: TokenPrincipal | undefined,
|
|
192
|
+
body: ParsedMintBody,
|
|
193
|
+
): Promise<WireError | undefined> {
|
|
194
|
+
const forSomeoneElse = principal !== undefined && !samePrincipal(principal, owner);
|
|
195
|
+
if ((forSomeoneElse || body.role === 'admin') && !(await isTenantAdmin(c, authorizer))) {
|
|
196
|
+
return {
|
|
197
|
+
code: 'permission-denied',
|
|
198
|
+
message: forSomeoneElse
|
|
199
|
+
? 'Only a tenant admin mints keys for someone else'
|
|
200
|
+
: 'Only a tenant admin mints an admin key',
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
const held = new Set(c.get('capabilities') ?? []);
|
|
204
|
+
const notHeld = body.capabilities.filter((cap) => !held.has(cap));
|
|
205
|
+
if (notHeld.length > 0) {
|
|
206
|
+
return {
|
|
207
|
+
code: 'permission-denied',
|
|
208
|
+
message: `A key can only be given capabilities its minter holds; you don't hold: ${notHeld.join(', ')}`,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
const narrowedTo = c.get('tokenProjectId');
|
|
212
|
+
if (narrowedTo !== undefined && body.projectId !== (narrowedTo as unknown as ProjectId)) {
|
|
213
|
+
return {
|
|
214
|
+
code: 'key-project-mismatch',
|
|
215
|
+
message: `Your key is limited to project ${narrowedTo}: a key it mints must be limited to it too`,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
154
218
|
return undefined;
|
|
155
219
|
}
|
|
156
220
|
|
|
221
|
+
/** A key the caller may see: any, for a tenant admin; otherwise only their own. */
|
|
222
|
+
async function visibleKey(
|
|
223
|
+
c: Context<AppEnv>,
|
|
224
|
+
admin: TokenAdmin,
|
|
225
|
+
authorizer: Authorizer | undefined,
|
|
226
|
+
tokenId: ApiTokenId,
|
|
227
|
+
): Promise<ApiTokenRecord | undefined> {
|
|
228
|
+
const tenantId = c.get('tenantId') as TenantId;
|
|
229
|
+
const record = await admin.get({ tenantId, tokenId });
|
|
230
|
+
if (record === undefined) return undefined;
|
|
231
|
+
if (await isTenantAdmin(c, authorizer)) return record;
|
|
232
|
+
return record.principal !== undefined && samePrincipal(record.principal, keyOwner(c))
|
|
233
|
+
? record
|
|
234
|
+
: undefined;
|
|
235
|
+
}
|
|
236
|
+
|
|
157
237
|
function toWire(record: ApiTokenRecord): Record<string, unknown> {
|
|
158
238
|
return {
|
|
159
239
|
tokenId: record.tokenId as unknown as string,
|
|
240
|
+
...(record.principal !== undefined && { principal: principalToWire(record.principal) }),
|
|
160
241
|
role: record.role,
|
|
161
242
|
capabilities: record.capabilities,
|
|
162
243
|
...(record.label !== undefined && { label: record.label }),
|
|
@@ -207,6 +288,7 @@ async function readJsonBody(
|
|
|
207
288
|
}
|
|
208
289
|
|
|
209
290
|
type ParsedMintBody = {
|
|
291
|
+
readonly for?: TokenPrincipal;
|
|
210
292
|
readonly role: ApiTokenRole;
|
|
211
293
|
readonly capabilities: readonly string[];
|
|
212
294
|
readonly label?: string;
|
|
@@ -232,23 +314,29 @@ function parseMintBody(body: unknown): Parsed<ParsedMintBody> {
|
|
|
232
314
|
if (role.kind === 'err') return role;
|
|
233
315
|
const capabilities = parseCapabilities(b.capabilities);
|
|
234
316
|
if (capabilities.kind === 'err') return capabilities;
|
|
317
|
+
const principal = parseFor(b.for);
|
|
318
|
+
if (principal.kind === 'err') return principal;
|
|
235
319
|
const out: {
|
|
320
|
+
for?: TokenPrincipal;
|
|
236
321
|
role: ApiTokenRole;
|
|
237
322
|
capabilities: readonly string[];
|
|
238
323
|
label?: string;
|
|
239
324
|
expiresAt?: Date;
|
|
240
325
|
projectId?: ProjectId;
|
|
241
|
-
} = {
|
|
326
|
+
} = {
|
|
327
|
+
...(principal.value !== undefined && { for: principal.value }),
|
|
328
|
+
role: role.value,
|
|
329
|
+
capabilities: capabilities.value,
|
|
330
|
+
};
|
|
242
331
|
|
|
243
332
|
if (b.label !== undefined) {
|
|
244
333
|
if (typeof b.label !== 'string') return badInput('`label` must be a string');
|
|
245
334
|
out.label = b.label;
|
|
246
335
|
}
|
|
247
336
|
if (b.expiresAt !== undefined) {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
out.expiresAt = parsed;
|
|
337
|
+
const expiresAt = parseExpiresAt(b.expiresAt);
|
|
338
|
+
if (expiresAt.kind === 'err') return expiresAt;
|
|
339
|
+
out.expiresAt = expiresAt.value;
|
|
252
340
|
}
|
|
253
341
|
if (b.projectId !== undefined) {
|
|
254
342
|
if (typeof b.projectId !== 'string') {
|
|
@@ -259,6 +347,14 @@ function parseMintBody(body: unknown): Parsed<ParsedMintBody> {
|
|
|
259
347
|
return { kind: 'ok', value: out };
|
|
260
348
|
}
|
|
261
349
|
|
|
350
|
+
/** `expiresAt`: an ISO date string. */
|
|
351
|
+
function parseExpiresAt(raw: unknown): Parsed<Date> {
|
|
352
|
+
if (typeof raw !== 'string') return badInput('`expiresAt` must be an ISO date string');
|
|
353
|
+
const parsed = new Date(raw);
|
|
354
|
+
if (Number.isNaN(parsed.getTime())) return badInput('`expiresAt` is not a valid ISO date');
|
|
355
|
+
return { kind: 'ok', value: parsed };
|
|
356
|
+
}
|
|
357
|
+
|
|
262
358
|
/** `role`: `admin` | `member`; `member` when absent (least privilege). */
|
|
263
359
|
function parseRole(raw: unknown): Parsed<ApiTokenRole> {
|
|
264
360
|
if (raw === undefined) return { kind: 'ok', value: 'member' };
|
|
@@ -283,3 +379,33 @@ function parseCapabilities(raw: unknown): Parsed<readonly string[]> {
|
|
|
283
379
|
}
|
|
284
380
|
return { kind: 'ok', value: out };
|
|
285
381
|
}
|
|
382
|
+
|
|
383
|
+
/** `for`, when present: whom the key acts for. */
|
|
384
|
+
function parseFor(raw: unknown): Parsed<TokenPrincipal | undefined> {
|
|
385
|
+
return raw === undefined ? { kind: 'ok', value: undefined } : parsePrincipalBody(raw);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/** `for`: `{kind: 'user' | 'service-account', id}`. */
|
|
389
|
+
function parsePrincipalBody(raw: unknown): Parsed<TokenPrincipal> {
|
|
390
|
+
const b = (raw ?? {}) as { kind?: unknown; id?: unknown };
|
|
391
|
+
if (typeof b.id !== 'string' || b.id.length === 0) {
|
|
392
|
+
return badInput('`for.id` must be the id of a person or a service account');
|
|
393
|
+
}
|
|
394
|
+
if (b.kind === 'user') return { kind: 'ok', value: { kind: 'user', userId: b.id } };
|
|
395
|
+
if (b.kind === 'service-account') {
|
|
396
|
+
return { kind: 'ok', value: { kind: 'service-account', serviceAccountId: b.id } };
|
|
397
|
+
}
|
|
398
|
+
return badInput("`for.kind` must be 'user' or 'service-account'");
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/** `?principal=user:<id>` or `?principal=service-account:<id>`: one principal's keys (admins). */
|
|
402
|
+
function parsePrincipalQuery(raw: string | undefined): Parsed<TokenPrincipal | undefined> {
|
|
403
|
+
if (raw === undefined || raw === '') return { kind: 'ok', value: undefined };
|
|
404
|
+
const colon = raw.indexOf(':');
|
|
405
|
+
const kind = raw.slice(0, colon);
|
|
406
|
+
const id = raw.slice(colon + 1);
|
|
407
|
+
if (colon <= 0 || id === '') {
|
|
408
|
+
return badInput('`principal` is `user:<id>` or `service-account:<id>`');
|
|
409
|
+
}
|
|
410
|
+
return parsePrincipalBody({ kind, id });
|
|
411
|
+
}
|
package/src/routes/tools.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { refuseWritesWhenReadOnly } from '../registry-read-only.js';
|
|
|
13
13
|
import type { ToolRegistryBinding } from '../tool-binding.js';
|
|
14
14
|
import type { AppEnv } from '../types.js';
|
|
15
15
|
import { clampLimit } from './pagination.js';
|
|
16
|
+
import { projectMismatch } from './project-mismatch.js';
|
|
16
17
|
import { parseScopeParams } from './scope-params.js';
|
|
17
18
|
|
|
18
19
|
/**
|
|
@@ -127,8 +128,15 @@ export function toolsRouter(
|
|
|
127
128
|
...(scopeParsed.scope !== undefined && { scope: scopeParsed.scope }),
|
|
128
129
|
...(scopeParsed.inherit !== undefined && { inherit: scopeParsed.inherit }),
|
|
129
130
|
});
|
|
131
|
+
// Only what the caller may read (T243 A), as `GET …/:id` asks.
|
|
132
|
+
const visible =
|
|
133
|
+
authorizer === undefined
|
|
134
|
+
? page.data
|
|
135
|
+
: await authorizer.filterByCan(c, 'read', page.data, (a) =>
|
|
136
|
+
ref('tool', a.id as unknown as string),
|
|
137
|
+
);
|
|
130
138
|
return c.json({
|
|
131
|
-
data:
|
|
139
|
+
data: visible.map(serializeTool),
|
|
132
140
|
hasMore: page.nextCursor !== undefined,
|
|
133
141
|
...(page.nextCursor !== undefined && { nextCursor: page.nextCursor as unknown as string }),
|
|
134
142
|
});
|
|
@@ -329,6 +337,9 @@ export function toolsRouter(
|
|
|
329
337
|
),
|
|
330
338
|
);
|
|
331
339
|
}
|
|
340
|
+
if (outcome.kind === 'project-mismatch') {
|
|
341
|
+
return projectMismatch(c, 'tool', outcome.toolId as unknown as string, outcome.projectId);
|
|
342
|
+
}
|
|
332
343
|
if (outcome.kind === 'project-not-found') {
|
|
333
344
|
// Caller supplied a `projectId` that does not resolve within
|
|
334
345
|
// this tenant. Distinct signal from `already-registered` so the
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (C) 2026 Kindgi Inc.
|
|
3
|
+
|
|
4
|
+
import type { Context } from 'hono';
|
|
5
|
+
|
|
6
|
+
import { type Action, ref } from '@kindgi/authz';
|
|
7
|
+
import type { TenantId, TriggerId } from '@kindgi/types';
|
|
8
|
+
|
|
9
|
+
import type { Authorizer } from '../middleware/authorize.js';
|
|
10
|
+
import type { TriggerRecord, TriggerRegistryBinding } from '../trigger-binding.js';
|
|
11
|
+
import type { AppEnv } from '../types.js';
|
|
12
|
+
import { deniedBy } from './denied.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Who may manage an event or webhook trigger (T243 A): the flow it fires.
|
|
16
|
+
* A trigger has no parent tuple of its own, so every check names its
|
|
17
|
+
* flow: `read` to see it; `write` to pause, resume or unregister it; and
|
|
18
|
+
* `write` plus `execute` to register it or change what it runs, since it
|
|
19
|
+
* starts runs of the flow as its registrant would. With no authorizer,
|
|
20
|
+
* nothing is checked.
|
|
21
|
+
*/
|
|
22
|
+
export interface TriggerAccess {
|
|
23
|
+
/** Registering a trigger for `flowId`: the refusal, if any. */
|
|
24
|
+
onRegister(c: Context<AppEnv>, flowId: string): Promise<Response | undefined>;
|
|
25
|
+
/**
|
|
26
|
+
* A route on one trigger: the refusal, if any. A trigger that isn't
|
|
27
|
+
* there, or is of another kind, passes on to the handler's 404.
|
|
28
|
+
*/
|
|
29
|
+
onTrigger(
|
|
30
|
+
c: Context<AppEnv>,
|
|
31
|
+
triggerId: TriggerId,
|
|
32
|
+
actions: readonly Action[],
|
|
33
|
+
): Promise<Response | undefined>;
|
|
34
|
+
/** The rows of a list whose flow the caller may read. */
|
|
35
|
+
visible<T extends { readonly flowId: string }>(
|
|
36
|
+
c: Context<AppEnv>,
|
|
37
|
+
rows: readonly T[],
|
|
38
|
+
): Promise<readonly T[]>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function triggerAccess(
|
|
42
|
+
binding: TriggerRegistryBinding,
|
|
43
|
+
kind: Exclude<TriggerRecord['kind'], 'cron'>,
|
|
44
|
+
authorizer: Authorizer | undefined,
|
|
45
|
+
): TriggerAccess {
|
|
46
|
+
const onFlow = async (
|
|
47
|
+
c: Context<AppEnv>,
|
|
48
|
+
flowId: string,
|
|
49
|
+
actions: readonly Action[],
|
|
50
|
+
): Promise<Response | undefined> => {
|
|
51
|
+
for (const action of actions) {
|
|
52
|
+
const refused = await deniedBy(authorizer, c, action, ref('flow', flowId));
|
|
53
|
+
if (refused !== undefined) return refused;
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
};
|
|
57
|
+
return {
|
|
58
|
+
onRegister: (c, flowId) => onFlow(c, flowId, ['write', 'execute']),
|
|
59
|
+
async onTrigger(c, triggerId, actions) {
|
|
60
|
+
if (authorizer === undefined) return undefined;
|
|
61
|
+
const tenantId = c.get('tenantId') as TenantId;
|
|
62
|
+
const rec = await binding.get({ tenantId, triggerId });
|
|
63
|
+
// A schedule's access is the schedules router's own (it may run an agent).
|
|
64
|
+
if (rec === null || rec.kind === 'cron' || rec.kind !== kind) return undefined;
|
|
65
|
+
return onFlow(c, rec.flowId, actions);
|
|
66
|
+
},
|
|
67
|
+
async visible(c, rows) {
|
|
68
|
+
if (authorizer === undefined) return rows;
|
|
69
|
+
return authorizer.filterByCan(c, 'read', rows, (row) => ref('flow', row.flowId));
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
@@ -14,6 +14,8 @@ import type {
|
|
|
14
14
|
} from '@kindgi/types';
|
|
15
15
|
|
|
16
16
|
import { statusFor, toWireError } from '../errors.js';
|
|
17
|
+
import type { Authorizer } from '../middleware/authorize.js';
|
|
18
|
+
import { withholdFromReplay } from '../middleware/idempotency.js';
|
|
17
19
|
import type { AppEnv } from '../types.js';
|
|
18
20
|
import {
|
|
19
21
|
WEBHOOK_DELIVERY_STATUSES,
|
|
@@ -30,6 +32,7 @@ import {
|
|
|
30
32
|
} from '../webhook-endpoint-binding.js';
|
|
31
33
|
import { clampLimit } from './pagination.js';
|
|
32
34
|
import { parseSecretRef } from './secret-ref.js';
|
|
35
|
+
import { tenantAdminAccess } from './tenant-access.js';
|
|
33
36
|
|
|
34
37
|
const MAX_URL_LENGTH = 2048;
|
|
35
38
|
const MAX_DESCRIPTION_LENGTH = 500;
|
|
@@ -41,8 +44,13 @@ const MAX_FLOW_ID_LENGTH = 200;
|
|
|
41
44
|
* the platform sends signed events to, read their delivery log, redeliver
|
|
42
45
|
* and send a test event. See `WebhookEndpointBinding`.
|
|
43
46
|
*/
|
|
44
|
-
export function webhookEndpointsRouter(
|
|
47
|
+
export function webhookEndpointsRouter(
|
|
48
|
+
binding: WebhookEndpointBinding,
|
|
49
|
+
authorizer?: Authorizer,
|
|
50
|
+
): Hono<AppEnv> {
|
|
45
51
|
const r = new Hono<AppEnv>();
|
|
52
|
+
// Deliveries carry every project's runs: all of it is an admin's.
|
|
53
|
+
r.use('*', tenantAdminAccess(authorizer));
|
|
46
54
|
|
|
47
55
|
// ---------- POST / (create) ----------
|
|
48
56
|
r.post('/', async (c) => {
|
|
@@ -71,8 +79,12 @@ export function webhookEndpointsRouter(binding: WebhookEndpointBinding): Hono<Ap
|
|
|
71
79
|
});
|
|
72
80
|
|
|
73
81
|
// ---------- POST /generate-secret ----------
|
|
74
|
-
// A strong signing secret to store before registering; nothing is kept
|
|
75
|
-
|
|
82
|
+
// A strong signing secret to store before registering; nothing is kept,
|
|
83
|
+
// and an Idempotency-Key repeat doesn't get it.
|
|
84
|
+
r.post('/generate-secret', (c) => {
|
|
85
|
+
withholdFromReplay(c);
|
|
86
|
+
return c.json({ secret: generateWebhookSecret() });
|
|
87
|
+
});
|
|
76
88
|
|
|
77
89
|
// ---------- GET / (list) ----------
|
|
78
90
|
r.get('/', async (c) => {
|
package/src/routes/webhooks.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type { Context } from 'hono';
|
|
|
9
9
|
import type { Cursor, TenantId, TriggerId } from '@kindgi/types';
|
|
10
10
|
|
|
11
11
|
import { statusFor, toWireError } from '../errors.js';
|
|
12
|
+
import type { Authorizer } from '../middleware/authorize.js';
|
|
12
13
|
import type {
|
|
13
14
|
RegisterWebhookTriggerInput,
|
|
14
15
|
TriggerRegistryBinding,
|
|
@@ -17,6 +18,7 @@ import type {
|
|
|
17
18
|
} from '../trigger-binding.js';
|
|
18
19
|
import type { AppEnv } from '../types.js';
|
|
19
20
|
import { clampLimit } from './pagination.js';
|
|
21
|
+
import { triggerAccess } from './trigger-access.js';
|
|
20
22
|
|
|
21
23
|
/**
|
|
22
24
|
* Webhook triggers — fire a flow run when an HMAC-signed request
|
|
@@ -33,9 +35,16 @@ import { clampLimit } from './pagination.js';
|
|
|
33
35
|
* carries `hmacSecretName`, a handle into the tenant secrets store the
|
|
34
36
|
* caller wrote to first via `POST /v1/secrets`. Rotation flows through
|
|
35
37
|
* `POST /v1/secrets/:name/rotate` — trigger row untouched.
|
|
38
|
+
*
|
|
39
|
+
* With an authorizer (T243 A), the trigger's flow decides who may see or
|
|
40
|
+
* change it (`trigger-access.ts`).
|
|
36
41
|
*/
|
|
37
|
-
export function webhooksRouter(
|
|
42
|
+
export function webhooksRouter(
|
|
43
|
+
binding: TriggerRegistryBinding,
|
|
44
|
+
authorizer?: Authorizer,
|
|
45
|
+
): Hono<AppEnv> {
|
|
38
46
|
const r = new Hono<AppEnv>();
|
|
47
|
+
const access = triggerAccess(binding, 'webhook', authorizer);
|
|
39
48
|
|
|
40
49
|
// ---------- POST / (register) ----------
|
|
41
50
|
r.post('/', async (c) => {
|
|
@@ -53,6 +62,9 @@ export function webhooksRouter(binding: TriggerRegistryBinding): Hono<AppEnv> {
|
|
|
53
62
|
if (flowVersion.kind === 'err') return bad(c, requestId, flowVersion.message);
|
|
54
63
|
if (hmacSecretName.kind === 'err') return bad(c, requestId, hmacSecretName.message);
|
|
55
64
|
|
|
65
|
+
const refused = await access.onRegister(c, flowId.value);
|
|
66
|
+
if (refused !== undefined) return refused;
|
|
67
|
+
|
|
56
68
|
const rawConfig = (body.config ?? {}) as Record<string, unknown>;
|
|
57
69
|
// Route mints the webhookId — a random UUID, returned so the caller
|
|
58
70
|
// learns the receiver URL from the response.
|
|
@@ -100,7 +112,9 @@ export function webhooksRouter(binding: TriggerRegistryBinding): Hono<AppEnv> {
|
|
|
100
112
|
...(statusFilter !== undefined && { status: statusFilter }),
|
|
101
113
|
});
|
|
102
114
|
return c.json({
|
|
103
|
-
data: page.data
|
|
115
|
+
data: (await access.visible(c, page.data as readonly WebhookTriggerRecord[])).map(
|
|
116
|
+
serializeWebhook,
|
|
117
|
+
),
|
|
104
118
|
hasMore: page.nextCursor !== undefined,
|
|
105
119
|
...(page.nextCursor !== undefined && { nextCursor: page.nextCursor as unknown as string }),
|
|
106
120
|
});
|
|
@@ -111,6 +125,8 @@ export function webhooksRouter(binding: TriggerRegistryBinding): Hono<AppEnv> {
|
|
|
111
125
|
const requestId = c.get('requestId');
|
|
112
126
|
const tenantId = c.get('tenantId') as TenantId;
|
|
113
127
|
const triggerId = c.req.param('triggerId') as TriggerId;
|
|
128
|
+
const refused = await access.onTrigger(c, triggerId, ['read']);
|
|
129
|
+
if (refused !== undefined) return refused;
|
|
114
130
|
|
|
115
131
|
const rec = await binding.get({ tenantId, triggerId });
|
|
116
132
|
if (rec === null || rec.kind !== 'webhook') return notFound(c, requestId, triggerId);
|
|
@@ -122,6 +138,8 @@ export function webhooksRouter(binding: TriggerRegistryBinding): Hono<AppEnv> {
|
|
|
122
138
|
const requestId = c.get('requestId');
|
|
123
139
|
const tenantId = c.get('tenantId') as TenantId;
|
|
124
140
|
const triggerId = c.req.param('triggerId') as TriggerId;
|
|
141
|
+
const refused = await access.onTrigger(c, triggerId, ['write', 'execute']);
|
|
142
|
+
if (refused !== undefined) return refused;
|
|
125
143
|
|
|
126
144
|
const parsed = await parseJsonObject(c, requestId);
|
|
127
145
|
if (parsed.kind === 'err') return parsed.response;
|
|
@@ -162,6 +180,8 @@ export function webhooksRouter(binding: TriggerRegistryBinding): Hono<AppEnv> {
|
|
|
162
180
|
const requestId = c.get('requestId');
|
|
163
181
|
const tenantId = c.get('tenantId') as TenantId;
|
|
164
182
|
const triggerId = c.req.param('triggerId') as TriggerId;
|
|
183
|
+
const refused = await access.onTrigger(c, triggerId, ['write']);
|
|
184
|
+
if (refused !== undefined) return refused;
|
|
165
185
|
const result = await binding.pause({ tenantId, triggerId });
|
|
166
186
|
if (result.kind === 'err') return lifecycleError(c, requestId, result.error, triggerId);
|
|
167
187
|
return c.json(serializeWebhook(result.value as WebhookTriggerRecord));
|
|
@@ -172,6 +192,8 @@ export function webhooksRouter(binding: TriggerRegistryBinding): Hono<AppEnv> {
|
|
|
172
192
|
const requestId = c.get('requestId');
|
|
173
193
|
const tenantId = c.get('tenantId') as TenantId;
|
|
174
194
|
const triggerId = c.req.param('triggerId') as TriggerId;
|
|
195
|
+
const refused = await access.onTrigger(c, triggerId, ['write']);
|
|
196
|
+
if (refused !== undefined) return refused;
|
|
175
197
|
const result = await binding.resume({ tenantId, triggerId });
|
|
176
198
|
if (result.kind === 'err') return lifecycleError(c, requestId, result.error, triggerId);
|
|
177
199
|
return c.json(serializeWebhook(result.value as WebhookTriggerRecord));
|
|
@@ -181,6 +203,8 @@ export function webhooksRouter(binding: TriggerRegistryBinding): Hono<AppEnv> {
|
|
|
181
203
|
r.post('/:triggerId/unregister', async (c) => {
|
|
182
204
|
const tenantId = c.get('tenantId') as TenantId;
|
|
183
205
|
const triggerId = c.req.param('triggerId') as TriggerId;
|
|
206
|
+
const refused = await access.onTrigger(c, triggerId, ['write']);
|
|
207
|
+
if (refused !== undefined) return refused;
|
|
184
208
|
const outcome = await binding.unregister({ tenantId, triggerId });
|
|
185
209
|
return c.json({
|
|
186
210
|
triggerId: triggerId as unknown as string,
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (C) 2026 Kindgi Inc.
|
|
3
|
+
|
|
4
|
+
import { parseFailureMessage } from '@kindgi/agents';
|
|
5
|
+
|
|
6
|
+
/** Why a run failed, on the wire (`Run.failure`). */
|
|
7
|
+
export interface RunFailure {
|
|
8
|
+
/** The error's own code (`budget-exceeded`, `capability-routing-failed`, …), or `run-failed`. */
|
|
9
|
+
readonly code: string;
|
|
10
|
+
readonly message: string;
|
|
11
|
+
/** What the error came from, when it says (e.g. the router's reasons, by provider). */
|
|
12
|
+
readonly cause?: unknown;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A failed run's error, so a caller needn't parse `failureMessage`. An
|
|
17
|
+
* agent turn's failure reads back as its typed error, the way
|
|
18
|
+
* `invokeAgent` reads a run (`parseFailureMessage`; with several joined,
|
|
19
|
+
* the first). Any other is `run-failed`, in the run's own words.
|
|
20
|
+
* Absent unless the run is `failed`.
|
|
21
|
+
*/
|
|
22
|
+
export function runFailure(row: {
|
|
23
|
+
readonly runId: unknown;
|
|
24
|
+
readonly status: string;
|
|
25
|
+
readonly failureMessage?: string | null;
|
|
26
|
+
}): RunFailure | undefined {
|
|
27
|
+
if (row.status !== 'failed') return undefined;
|
|
28
|
+
const raw = row.failureMessage ?? undefined;
|
|
29
|
+
const error = parseFailureMessage(raw);
|
|
30
|
+
if (error !== undefined) {
|
|
31
|
+
const cause = (error as { readonly cause?: unknown }).cause;
|
|
32
|
+
return {
|
|
33
|
+
code: error.code,
|
|
34
|
+
message: error.message,
|
|
35
|
+
...(cause !== undefined && cause !== null && { cause }),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
code: 'run-failed',
|
|
40
|
+
message: raw !== undefined && raw !== '' ? raw : `Run ${String(row.runId)} failed`,
|
|
41
|
+
};
|
|
42
|
+
}
|