@pithy-sh/core 0.1.2 → 0.1.4
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/address/address.d.ts +57 -0
- package/dist/address/address.d.ts.map +1 -0
- package/dist/address/address.js +71 -0
- package/dist/audit/auditEvent.d.ts +89 -0
- package/dist/audit/auditEvent.d.ts.map +1 -0
- package/dist/audit/auditEvent.js +69 -0
- package/dist/audit/recorder.d.ts +18 -0
- package/dist/audit/recorder.d.ts.map +1 -0
- package/dist/audit/recorder.js +8 -0
- package/dist/capability/bindings.d.ts +62 -0
- package/dist/capability/bindings.d.ts.map +1 -0
- package/dist/capability/bindings.js +97 -0
- package/dist/capability/capability.d.ts +501 -0
- package/dist/capability/capability.d.ts.map +1 -0
- package/dist/capability/capability.js +16 -0
- package/dist/capability/client.d.ts +70 -0
- package/dist/capability/client.d.ts.map +1 -0
- package/dist/capability/client.js +86 -0
- package/dist/capability/compose.d.ts +25 -0
- package/dist/capability/compose.d.ts.map +1 -0
- package/dist/capability/compose.js +54 -0
- package/dist/capability/composition.d.ts +26 -0
- package/dist/capability/composition.d.ts.map +1 -0
- package/dist/capability/composition.js +84 -0
- package/dist/capability/config.d.ts +7 -0
- package/dist/capability/config.d.ts.map +1 -0
- package/dist/capability/config.js +14 -0
- package/dist/capability/devSecret.d.ts +32 -0
- package/dist/capability/devSecret.d.ts.map +1 -0
- package/dist/capability/devSecret.js +28 -0
- package/dist/capability/manifest.d.ts +298 -0
- package/dist/capability/manifest.d.ts.map +1 -0
- package/dist/capability/manifest.js +356 -0
- package/dist/capability/secretOrigin.d.ts +121 -0
- package/dist/capability/secretOrigin.d.ts.map +1 -0
- package/dist/capability/secretOrigin.js +134 -0
- package/dist/capability/settings.d.ts +119 -0
- package/dist/capability/settings.d.ts.map +1 -0
- package/dist/capability/settings.js +66 -0
- package/dist/capability/validateBindings.d.ts +4 -0
- package/dist/capability/validateBindings.d.ts.map +1 -0
- package/dist/capability/validateBindings.js +34 -0
- package/dist/capability/vanishingKey.d.ts +31 -0
- package/dist/capability/vanishingKey.d.ts.map +1 -0
- package/dist/capability/vanishingKey.js +79 -0
- package/dist/controlPlane/audit/actions.d.ts +70 -0
- package/dist/controlPlane/audit/actions.d.ts.map +1 -0
- package/dist/controlPlane/audit/actions.js +76 -0
- package/dist/controlPlane/capability.d.ts +47 -0
- package/dist/controlPlane/capability.d.ts.map +1 -0
- package/dist/controlPlane/capability.js +138 -0
- package/dist/controlPlane/config/config.d.ts +19 -0
- package/dist/controlPlane/config/config.d.ts.map +1 -0
- package/dist/controlPlane/config/config.js +85 -0
- package/dist/controlPlane/context.d.ts +27 -0
- package/dist/controlPlane/context.d.ts.map +1 -0
- package/dist/controlPlane/context.js +29 -0
- package/dist/controlPlane/data/connection.d.ts +79 -0
- package/dist/controlPlane/data/connection.d.ts.map +1 -0
- package/dist/controlPlane/data/connection.js +55 -0
- package/dist/controlPlane/data/keyLifecycle.d.ts +62 -0
- package/dist/controlPlane/data/keyLifecycle.d.ts.map +1 -0
- package/dist/controlPlane/data/keyLifecycle.js +126 -0
- package/dist/controlPlane/data/replay.d.ts +18 -0
- package/dist/controlPlane/data/replay.d.ts.map +1 -0
- package/dist/controlPlane/data/replay.js +20 -0
- package/dist/controlPlane/data/tables.d.ts +34 -0
- package/dist/controlPlane/data/tables.d.ts.map +1 -0
- package/dist/controlPlane/data/tables.js +37 -0
- package/dist/controlPlane/discovery/adminRoute.d.ts +313 -0
- package/dist/controlPlane/discovery/adminRoute.d.ts.map +1 -0
- package/dist/controlPlane/discovery/adminRoute.js +136 -0
- package/dist/controlPlane/discovery/configuration.d.ts +108 -0
- package/dist/controlPlane/discovery/configuration.d.ts.map +1 -0
- package/dist/controlPlane/discovery/configuration.js +187 -0
- package/dist/controlPlane/discovery/drift.d.ts +64 -0
- package/dist/controlPlane/discovery/drift.d.ts.map +1 -0
- package/dist/controlPlane/discovery/drift.js +58 -0
- package/dist/controlPlane/discovery/health.d.ts +99 -0
- package/dist/controlPlane/discovery/health.d.ts.map +1 -0
- package/dist/controlPlane/discovery/health.js +151 -0
- package/dist/controlPlane/discovery/healthSummary.d.ts +236 -0
- package/dist/controlPlane/discovery/healthSummary.d.ts.map +1 -0
- package/dist/controlPlane/discovery/healthSummary.js +278 -0
- package/dist/controlPlane/error/errors.d.ts +67 -0
- package/dist/controlPlane/error/errors.d.ts.map +1 -0
- package/dist/controlPlane/error/errors.js +79 -0
- package/dist/controlPlane/http/cors.d.ts +112 -0
- package/dist/controlPlane/http/cors.d.ts.map +1 -0
- package/dist/controlPlane/http/cors.js +192 -0
- package/dist/controlPlane/http/guard.d.ts +77 -0
- package/dist/controlPlane/http/guard.d.ts.map +1 -0
- package/dist/controlPlane/http/guard.js +142 -0
- package/dist/controlPlane/http/handlers.d.ts +179 -0
- package/dist/controlPlane/http/handlers.d.ts.map +1 -0
- package/dist/controlPlane/http/handlers.js +245 -0
- package/dist/controlPlane/http/responses.d.ts +99 -0
- package/dist/controlPlane/http/responses.d.ts.map +1 -0
- package/dist/controlPlane/http/responses.js +63 -0
- package/dist/controlPlane/http/routes.d.ts +40 -0
- package/dist/controlPlane/http/routes.d.ts.map +1 -0
- package/dist/controlPlane/http/routes.js +83 -0
- package/dist/controlPlane/http/schemas.d.ts +39 -0
- package/dist/controlPlane/http/schemas.d.ts.map +1 -0
- package/dist/controlPlane/http/schemas.js +31 -0
- package/dist/controlPlane/http/verify.d.ts +84 -0
- package/dist/controlPlane/http/verify.d.ts.map +1 -0
- package/dist/controlPlane/http/verify.js +65 -0
- package/dist/controlPlane/migrations/0001_init.d.ts +51 -0
- package/dist/controlPlane/migrations/0001_init.d.ts.map +1 -0
- package/dist/controlPlane/migrations/0001_init.js +65 -0
- package/dist/controlPlane/replay/d1Guard.d.ts +29 -0
- package/dist/controlPlane/replay/d1Guard.d.ts.map +1 -0
- package/dist/controlPlane/replay/d1Guard.js +39 -0
- package/dist/controlPlane/replay/guard.d.ts +52 -0
- package/dist/controlPlane/replay/guard.d.ts.map +1 -0
- package/dist/controlPlane/replay/guard.js +0 -0
- package/dist/controlPlane/replay/kvGuard.d.ts +99 -0
- package/dist/controlPlane/replay/kvGuard.d.ts.map +1 -0
- package/dist/controlPlane/replay/kvGuard.js +101 -0
- package/dist/controlPlane/scope/scope.d.ts +68 -0
- package/dist/controlPlane/scope/scope.d.ts.map +1 -0
- package/dist/controlPlane/scope/scope.js +63 -0
- package/dist/controlPlane/token/base64url.d.ts +10 -0
- package/dist/controlPlane/token/base64url.d.ts.map +1 -0
- package/dist/controlPlane/token/base64url.js +48 -0
- package/dist/controlPlane/token/claims.d.ts +83 -0
- package/dist/controlPlane/token/claims.d.ts.map +1 -0
- package/dist/controlPlane/token/claims.js +86 -0
- package/dist/controlPlane/token/digest.d.ts +44 -0
- package/dist/controlPlane/token/digest.d.ts.map +1 -0
- package/dist/controlPlane/token/digest.js +56 -0
- package/dist/controlPlane/token/jws.d.ts +52 -0
- package/dist/controlPlane/token/jws.d.ts.map +1 -0
- package/dist/controlPlane/token/jws.js +65 -0
- package/dist/controlPlane/token/mint.d.ts +56 -0
- package/dist/controlPlane/token/mint.d.ts.map +1 -0
- package/dist/controlPlane/token/mint.js +55 -0
- package/dist/controlPlane/wire.d.ts +122 -0
- package/dist/controlPlane/wire.d.ts.map +1 -0
- package/dist/controlPlane/wire.js +123 -0
- package/dist/createBackend.d.ts +58 -0
- package/dist/createBackend.d.ts.map +1 -0
- package/dist/createBackend.js +170 -0
- package/dist/createEntrypoint.d.ts +53 -0
- package/dist/createEntrypoint.d.ts.map +1 -0
- package/dist/createEntrypoint.js +52 -0
- package/dist/data/boundParameters.d.ts +83 -0
- package/dist/data/boundParameters.d.ts.map +1 -0
- package/dist/data/boundParameters.js +162 -0
- package/dist/data/codecs.d.ts +34 -0
- package/dist/data/codecs.d.ts.map +1 -0
- package/dist/data/codecs.js +135 -0
- package/dist/data/cursor.d.ts +81 -0
- package/dist/data/cursor.d.ts.map +1 -0
- package/dist/data/cursor.js +104 -0
- package/dist/data/databases.d.ts +55 -0
- package/dist/data/databases.d.ts.map +1 -0
- package/dist/data/databases.js +32 -0
- package/dist/data/db.d.ts +42 -0
- package/dist/data/db.d.ts.map +1 -0
- package/dist/data/db.js +24 -0
- package/dist/data/withD1Retry.d.ts +91 -0
- package/dist/data/withD1Retry.d.ts.map +1 -0
- package/dist/data/withD1Retry.js +152 -0
- package/dist/entitlement/entitlement.d.ts +118 -0
- package/dist/entitlement/entitlement.d.ts.map +1 -0
- package/dist/entitlement/entitlement.js +59 -0
- package/dist/entitlement/gateScan.d.ts +26 -0
- package/dist/entitlement/gateScan.d.ts.map +1 -0
- package/dist/entitlement/gateScan.js +96 -0
- package/dist/entitlement/require.d.ts +12 -0
- package/dist/entitlement/require.d.ts.map +1 -0
- package/dist/entitlement/require.js +123 -0
- package/dist/env/ambient.d.ts +52 -0
- package/dist/env/ambient.d.ts.map +1 -0
- package/dist/env/ambient.js +35 -0
- package/dist/env/ci.d.ts +36 -0
- package/dist/env/ci.d.ts.map +1 -0
- package/dist/env/ci.js +40 -0
- package/dist/env/stem.d.ts +23 -0
- package/dist/env/stem.d.ts.map +1 -0
- package/dist/env/stem.js +29 -0
- package/dist/error/cause.d.ts +143 -0
- package/dist/error/cause.d.ts.map +1 -0
- package/dist/error/cause.js +192 -0
- package/dist/error/client.d.ts +35 -0
- package/dist/error/client.d.ts.map +1 -0
- package/dist/error/client.js +38 -0
- package/dist/error/extend.d.ts +101 -0
- package/dist/error/extend.d.ts.map +1 -0
- package/dist/error/extend.js +76 -0
- package/dist/error/http.d.ts +1516 -0
- package/dist/error/http.d.ts.map +1 -0
- package/dist/error/http.js +72 -0
- package/dist/error/payload.d.ts +3034 -0
- package/dist/error/payload.d.ts.map +1 -0
- package/dist/error/payload.js +1110 -0
- package/dist/error/pithyError.d.ts +154 -0
- package/dist/error/pithyError.d.ts.map +1 -0
- package/dist/error/pithyError.js +197 -0
- package/dist/error/terminal.d.ts +28 -0
- package/dist/error/terminal.d.ts.map +1 -0
- package/dist/error/terminal.js +33 -0
- package/dist/http/authContext.d.ts +21 -0
- package/dist/http/authContext.d.ts.map +1 -0
- package/dist/http/authContext.js +23 -0
- package/dist/http/routeContract.d.ts +39 -0
- package/dist/http/routeContract.d.ts.map +1 -0
- package/dist/http/routeContract.js +82 -0
- package/dist/http/sameOrigin.d.ts +47 -0
- package/dist/http/sameOrigin.d.ts.map +1 -0
- package/dist/http/sameOrigin.js +24 -0
- package/dist/http/signedWebhook.d.ts +225 -0
- package/dist/http/signedWebhook.d.ts.map +1 -0
- package/dist/http/signedWebhook.js +247 -0
- package/dist/http/validation.d.ts +37 -0
- package/dist/http/validation.d.ts.map +1 -0
- package/dist/http/validation.js +14 -0
- package/dist/http/verification.d.ts +10 -0
- package/dist/http/verification.d.ts.map +1 -0
- package/dist/http/verification.js +17 -0
- package/dist/i18n/acceptLanguage.d.ts +22 -0
- package/dist/i18n/acceptLanguage.d.ts.map +1 -0
- package/dist/i18n/acceptLanguage.js +55 -0
- package/dist/i18n/catalog.d.ts +39 -0
- package/dist/i18n/catalog.d.ts.map +1 -0
- package/dist/i18n/catalog.js +57 -0
- package/dist/i18n/locale.d.ts +74 -0
- package/dist/i18n/locale.d.ts.map +1 -0
- package/dist/i18n/locale.js +109 -0
- package/dist/i18n/localeMarker.d.ts +29 -0
- package/dist/i18n/localeMarker.d.ts.map +1 -0
- package/dist/i18n/localeMarker.js +112 -0
- package/dist/i18n/match.d.ts +26 -0
- package/dist/i18n/match.d.ts.map +1 -0
- package/dist/i18n/match.js +88 -0
- package/dist/i18n/registry.d.ts +25 -0
- package/dist/i18n/registry.d.ts.map +1 -0
- package/dist/i18n/registry.js +51 -0
- package/dist/i18n/translator.d.ts +107 -0
- package/dist/i18n/translator.d.ts.map +1 -0
- package/dist/i18n/translator.js +80 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/kv/kv.d.ts +166 -0
- package/dist/kv/kv.d.ts.map +1 -0
- package/dist/kv/kv.js +261 -0
- package/dist/kv/namespaces.d.ts +58 -0
- package/dist/kv/namespaces.d.ts.map +1 -0
- package/dist/kv/namespaces.js +40 -0
- package/dist/logger/local.d.ts +41 -0
- package/dist/logger/local.d.ts.map +1 -0
- package/dist/logger/local.js +45 -0
- package/dist/logger/logger.d.ts +56 -0
- package/dist/logger/logger.d.ts.map +1 -0
- package/dist/logger/logger.js +83 -0
- package/dist/logger/record.d.ts +919 -0
- package/dist/logger/record.d.ts.map +1 -0
- package/dist/logger/record.js +79 -0
- package/dist/logger/worker.d.ts +74 -0
- package/dist/logger/worker.d.ts.map +1 -0
- package/dist/logger/worker.js +54 -0
- package/dist/migrations/batch.d.ts +10 -0
- package/dist/migrations/batch.d.ts.map +1 -0
- package/dist/migrations/batch.js +193 -0
- package/dist/migrations/bookkeeping.d.ts +24 -0
- package/dist/migrations/bookkeeping.d.ts.map +1 -0
- package/dist/migrations/bookkeeping.js +57 -0
- package/dist/migrations/owner.d.ts +41 -0
- package/dist/migrations/owner.d.ts.map +1 -0
- package/dist/migrations/owner.js +105 -0
- package/dist/migrations/registry.d.ts +36 -0
- package/dist/migrations/registry.d.ts.map +1 -0
- package/dist/migrations/registry.js +70 -0
- package/dist/migrations/runner.d.ts +67 -0
- package/dist/migrations/runner.d.ts.map +1 -0
- package/dist/migrations/runner.js +218 -0
- package/dist/naming/domains.d.ts +108 -0
- package/dist/naming/domains.d.ts.map +1 -0
- package/dist/naming/domains.js +156 -0
- package/dist/naming/environment.d.ts +118 -0
- package/dist/naming/environment.d.ts.map +1 -0
- package/dist/naming/environment.js +190 -0
- package/dist/naming/feature.d.ts +68 -0
- package/dist/naming/feature.d.ts.map +1 -0
- package/dist/naming/feature.js +106 -0
- package/dist/naming/limits.d.ts +229 -0
- package/dist/naming/limits.d.ts.map +1 -0
- package/dist/naming/limits.js +187 -0
- package/dist/naming/provisionScope.d.ts +91 -0
- package/dist/naming/provisionScope.d.ts.map +1 -0
- package/dist/naming/provisionScope.js +65 -0
- package/dist/naming/resource.d.ts +169 -0
- package/dist/naming/resource.d.ts.map +1 -0
- package/dist/naming/resource.js +220 -0
- package/dist/naming/resourceNames.d.ts +83 -0
- package/dist/naming/resourceNames.d.ts.map +1 -0
- package/dist/naming/resourceNames.js +102 -0
- package/dist/naming/segment.d.ts +29 -0
- package/dist/naming/segment.d.ts.map +1 -0
- package/dist/naming/segment.js +31 -0
- package/dist/projection/asRead.d.ts +72 -0
- package/dist/projection/asRead.d.ts.map +1 -0
- package/dist/projection/asRead.js +169 -0
- package/dist/projection/published.d.ts +95 -0
- package/dist/projection/published.d.ts.map +1 -0
- package/dist/projection/published.js +114 -0
- package/dist/schema/describedness.d.ts +55 -0
- package/dist/schema/describedness.d.ts.map +1 -0
- package/dist/schema/describedness.js +180 -0
- package/dist/seed/compose.d.ts +41 -0
- package/dist/seed/compose.d.ts.map +1 -0
- package/dist/seed/compose.js +51 -0
- package/dist/seed/devLogin.d.ts +50 -0
- package/dist/seed/devLogin.d.ts.map +1 -0
- package/dist/seed/devLogin.js +52 -0
- package/dist/seed/exampleIdentities.d.ts +58 -0
- package/dist/seed/exampleIdentities.d.ts.map +1 -0
- package/dist/seed/exampleIdentities.js +26 -0
- package/dist/seed/metadata.d.ts +20 -0
- package/dist/seed/metadata.d.ts.map +1 -0
- package/dist/seed/metadata.js +27 -0
- package/dist/seed/seed.d.ts +264 -0
- package/dist/seed/seed.d.ts.map +1 -0
- package/dist/seed/seed.js +37 -0
- package/dist/seed/seededRows.d.ts +26 -0
- package/dist/seed/seededRows.d.ts.map +1 -0
- package/dist/seed/seededRows.js +20 -0
- package/dist/seed/writeD1.d.ts +43 -0
- package/dist/seed/writeD1.d.ts.map +1 -0
- package/dist/seed/writeD1.js +73 -0
- package/dist/seed/writeKv.d.ts +29 -0
- package/dist/seed/writeKv.d.ts.map +1 -0
- package/dist/seed/writeKv.js +63 -0
- package/dist/semver/semver.d.ts +62 -0
- package/dist/semver/semver.d.ts.map +1 -0
- package/dist/semver/semver.js +137 -0
- package/dist/text/comments.d.ts +62 -0
- package/dist/text/comments.d.ts.map +1 -0
- package/dist/text/comments.js +161 -0
- package/dist/version.generated.d.ts +5 -0
- package/dist/version.generated.d.ts.map +1 -0
- package/dist/version.generated.js +7 -0
- package/dist/worker/health.d.ts +39 -0
- package/dist/worker/health.d.ts.map +1 -0
- package/dist/worker/health.js +41 -0
- package/dist/worker/identity.d.ts +191 -0
- package/dist/worker/identity.d.ts.map +1 -0
- package/dist/worker/identity.js +162 -0
- package/dist/workflow/bindings.d.ts +41 -0
- package/dist/workflow/bindings.d.ts.map +1 -0
- package/dist/workflow/bindings.js +53 -0
- package/dist/workflow/dispatch.d.ts +98 -0
- package/dist/workflow/dispatch.d.ts.map +1 -0
- package/dist/workflow/dispatch.js +148 -0
- package/dist/workflow/dispatchRoute.d.ts +80 -0
- package/dist/workflow/dispatchRoute.d.ts.map +1 -0
- package/dist/workflow/dispatchRoute.js +134 -0
- package/dist/workflow/faults.d.ts +97 -0
- package/dist/workflow/faults.d.ts.map +1 -0
- package/dist/workflow/faults.js +111 -0
- package/dist/workflow/host.d.ts +176 -0
- package/dist/workflow/host.d.ts.map +1 -0
- package/dist/workflow/host.js +116 -0
- package/dist/workflow/hostEntry.d.ts +50 -0
- package/dist/workflow/hostEntry.d.ts.map +1 -0
- package/dist/workflow/hostEntry.js +24 -0
- package/dist/workflow/hostEnv.d.ts +143 -0
- package/dist/workflow/hostEnv.d.ts.map +1 -0
- package/dist/workflow/hostEnv.js +170 -0
- package/dist/workflow/loopback.d.ts +52 -0
- package/dist/workflow/loopback.d.ts.map +1 -0
- package/dist/workflow/loopback.js +76 -0
- package/dist/workflow/naming.d.ts +79 -0
- package/dist/workflow/naming.d.ts.map +1 -0
- package/dist/workflow/naming.js +138 -0
- package/dist/workflow/register.d.ts +19 -0
- package/dist/workflow/register.d.ts.map +1 -0
- package/dist/workflow/register.js +40 -0
- package/dist/workflow/schemas.d.ts +44 -0
- package/dist/workflow/schemas.d.ts.map +1 -0
- package/dist/workflow/schemas.js +43 -0
- package/dist/workflow/spec.d.ts +81 -0
- package/dist/workflow/spec.d.ts.map +1 -0
- package/dist/workflow/spec.js +0 -0
- package/dist/workflow/stepMessage.d.ts +122 -0
- package/dist/workflow/stepMessage.d.ts.map +1 -0
- package/dist/workflow/stepMessage.js +152 -0
- package/package.json +20 -9
- package/src/capability/manifest.ts +21 -0
- package/src/version.generated.ts +1 -1
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { ControlPlaneKeyConflictError, ControlPlaneKeyNotFoundError } from "../error/errors.js";
|
|
2
|
+
//#region src/controlPlane/data/keyLifecycle.ts
|
|
3
|
+
/**
|
|
4
|
+
* The registered-key lifecycle: pure array logic over a connection's `keys` column.
|
|
5
|
+
*
|
|
6
|
+
* **Registering a key and expiring one are two operations, and folding them into a single `rotate()`
|
|
7
|
+
* is the one design mistake this module exists to prevent.** One call would make append-and-expire
|
|
8
|
+
* atomic, and atomic is precisely wrong here. The whole safety property is that the old key outlives
|
|
9
|
+
* the new one's first successful call: a mis-copied JWK, a private key the management client cannot
|
|
10
|
+
* actually sign with, or a Worker that never answers leaves the adopter holding a credential that
|
|
11
|
+
* still works. Fuse the two writes together and that same mistake locks them out of the seam with
|
|
12
|
+
* nothing left to authenticate the fix with. Kept apart, a broken rotation costs a stale key.
|
|
13
|
+
*
|
|
14
|
+
* So the safe ordering is enforced here rather than documented: {@link appendKey} may not touch an
|
|
15
|
+
* existing key's window, and {@link expireKey} refuses unless another key is already live.
|
|
16
|
+
*
|
|
17
|
+
* Nothing in this module reads a clock, a binding, or D1. `now` is injected on every call, which is
|
|
18
|
+
* what lets a test assert what a connection looks like a year into a failed rotation.
|
|
19
|
+
*/
|
|
20
|
+
/** Every key that may verify a call at `now`: not revoked, started, and not yet ended. */
|
|
21
|
+
function activeKeys(keys, now) {
|
|
22
|
+
return keys.filter((key) => !isRetired(key, now) && key.validFrom.getTime() <= now.getTime());
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The key that may verify this call, or null. Matching on `kid` alone would be the vulnerability —
|
|
26
|
+
* the window and the revocation are checked here so no caller can forget them.
|
|
27
|
+
*/
|
|
28
|
+
function findVerifyingKey(keys, keyId, now) {
|
|
29
|
+
return activeKeys(keys, now).find((key) => key.keyId === keyId) ?? null;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Register a key. Appends, and appends only — no existing key's `validUntil` moves, so a connection
|
|
33
|
+
* mid-rotation always has the key it arrived with.
|
|
34
|
+
*
|
|
35
|
+
* A key that is already retired at `now` is refused rather than stored: it could never be proven by a
|
|
36
|
+
* ping, so registering it would only offer a second step that can never safely be taken.
|
|
37
|
+
*/
|
|
38
|
+
function appendKey(keys, key, now) {
|
|
39
|
+
if (keys.some((existing) => existing.keyId === key.keyId)) throw new ControlPlaneKeyConflictError({
|
|
40
|
+
message: "That key id is already registered on this connection.",
|
|
41
|
+
action: "Register the replacement under a new key id.",
|
|
42
|
+
detail: `duplicate keyId ${key.keyId}`
|
|
43
|
+
});
|
|
44
|
+
if (isRetired(key, now)) throw new ControlPlaneKeyConflictError({
|
|
45
|
+
message: "That key has already expired or been revoked.",
|
|
46
|
+
action: "Register a key with an open-ended validity window.",
|
|
47
|
+
detail: `keyId ${key.keyId} is retired at registration`
|
|
48
|
+
});
|
|
49
|
+
return [...keys, key];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Close a key's window at `now`, once a replacement has proven itself.
|
|
53
|
+
*
|
|
54
|
+
* `provenKeyId` is the key that verified the request asking for this expiry — proof by use, and the
|
|
55
|
+
* reason the seam's `ping` scope is held implicitly by every connection. Two refusals guard the
|
|
56
|
+
* ordering: a prover that is not itself live has proven nothing, and an expiry that would leave no
|
|
57
|
+
* live key is the lockout, whatever the caller believes about their replacement.
|
|
58
|
+
*
|
|
59
|
+
* Re-expiring a key already closed is a no-op on its end date. The window a call was rejected under
|
|
60
|
+
* must not move retroactively.
|
|
61
|
+
*/
|
|
62
|
+
function expireKey(keys, keyId, options) {
|
|
63
|
+
const { provenKeyId, now } = options;
|
|
64
|
+
if (!keys.some((key) => key.keyId === keyId)) throw new ControlPlaneKeyNotFoundError({ detail: `keyId ${keyId} is not registered on this connection` });
|
|
65
|
+
if (findVerifyingKey(keys, provenKeyId, now) === null) throw new ControlPlaneKeyConflictError({
|
|
66
|
+
message: "The replacement key has not been proven on this connection.",
|
|
67
|
+
action: "Call the ping route with the replacement key, then expire this one.",
|
|
68
|
+
detail: `provenKeyId ${provenKeyId} is not live at ${now.toISOString()}`
|
|
69
|
+
});
|
|
70
|
+
const expired = keys.map((key) => key.keyId === keyId && key.validUntil === null ? {
|
|
71
|
+
...key,
|
|
72
|
+
validUntil: now
|
|
73
|
+
} : key);
|
|
74
|
+
if (activeKeys(expired, now).length === 0) throw new ControlPlaneKeyConflictError({
|
|
75
|
+
message: "Expiring that key would leave this connection with no live key.",
|
|
76
|
+
action: "Register a replacement key and prove it before expiring this one.",
|
|
77
|
+
detail: `expiring keyId ${keyId} would empty the connection's live set`
|
|
78
|
+
});
|
|
79
|
+
return expired;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Drop keys retired longer ago than `retentionMs`, then cap the array at `maxKeys`.
|
|
83
|
+
*
|
|
84
|
+
* The column is versioned, not a log — a superseded key is kept only long enough for the audit trail
|
|
85
|
+
* and a `GET /control-plane/keys` to explain a rotation. Two keys are never dropped: a live one, and
|
|
86
|
+
* one registered ahead of its `validFrom`, which is unretired rather than dead. So the cap is a
|
|
87
|
+
* target, not a guarantee; a connection with more live keys than `maxKeys` keeps all of them.
|
|
88
|
+
*/
|
|
89
|
+
function pruneKeys(keys, options) {
|
|
90
|
+
const { now, retentionMs, maxKeys } = options;
|
|
91
|
+
const live = new Set(activeKeys(keys, now).map((key) => key.keyId));
|
|
92
|
+
const kept = keys.filter((key) => {
|
|
93
|
+
if (live.has(key.keyId)) return true;
|
|
94
|
+
const retired = retiredAt(key);
|
|
95
|
+
if (retired === null) return true;
|
|
96
|
+
return now.getTime() - retired.getTime() <= retentionMs;
|
|
97
|
+
});
|
|
98
|
+
if (kept.length <= maxKeys) return kept;
|
|
99
|
+
const dropped = new Set(kept.flatMap((key) => {
|
|
100
|
+
const retired = live.has(key.keyId) ? null : retiredAt(key);
|
|
101
|
+
return retired === null ? [] : [{
|
|
102
|
+
keyId: key.keyId,
|
|
103
|
+
retiredAt: retired.getTime()
|
|
104
|
+
}];
|
|
105
|
+
}).sort((a, b) => a.retiredAt - b.retiredAt).slice(0, kept.length - maxKeys).map((entry) => entry.keyId));
|
|
106
|
+
return kept.filter((key) => !dropped.has(key.keyId));
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* When a key stopped being usable, or null while it is still in play. Revocation and expiry can both
|
|
110
|
+
* be set; the earlier one is when the key actually went cold.
|
|
111
|
+
*/
|
|
112
|
+
function retiredAt(key) {
|
|
113
|
+
const ends = [key.revokedAt, key.validUntil].filter((date) => date !== null);
|
|
114
|
+
if (ends.length === 0) return null;
|
|
115
|
+
return ends.reduce((earliest, date) => date.getTime() < earliest.getTime() ? date : earliest);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Is this key cold at `now`? Revocation counts whatever date it carries — it is the adopter's
|
|
119
|
+
* unilateral control and does not wait for a window to close. A `validUntil` still ahead is not
|
|
120
|
+
* retirement, and neither is a `validFrom` still ahead: that key is pending, not spent.
|
|
121
|
+
*/
|
|
122
|
+
function isRetired(key, now) {
|
|
123
|
+
return key.revokedAt !== null || key.validUntil !== null && key.validUntil.getTime() <= now.getTime();
|
|
124
|
+
}
|
|
125
|
+
//#endregion
|
|
126
|
+
export { activeKeys, appendKey, expireKey, findVerifyingKey, pruneKeys };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* One spent control-plane token, as a row.
|
|
4
|
+
*
|
|
5
|
+
* The row's **existence is the whole signal** — a claim is an insert that either wins the primary key or
|
|
6
|
+
* does not. The columns beside `jti` exist for two other jobs: `expiresAt` is what lets the table be
|
|
7
|
+
* pruned rather than grow forever, and `connectionId` is for the incident, not the decision. A replay is
|
|
8
|
+
* refused whatever connection presents it, because the `jti` alone is the key: scoping the uniqueness per
|
|
9
|
+
* connection would let a token captured from one connection be spent again against another, which is
|
|
10
|
+
* exactly the property being bought.
|
|
11
|
+
*/
|
|
12
|
+
export declare const ControlPlaneReplay: z.ZodObject<{
|
|
13
|
+
jti: z.ZodString;
|
|
14
|
+
connectionId: z.ZodString;
|
|
15
|
+
expiresAt: z.ZodCodec<z.ZodUnion<readonly [z.ZodNumber, z.ZodString, z.ZodDate]>, z.ZodDate>;
|
|
16
|
+
}, z.core.$strip>;
|
|
17
|
+
export type ControlPlaneReplay = z.output<typeof ControlPlaneReplay>;
|
|
18
|
+
//# sourceMappingURL=replay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/data/replay.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB;;;;iBAqB5B,CAAC;AACJ,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,kBAAkB,CAAC,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { SQLiteDate } from "../../data/codecs.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
//#region src/controlPlane/data/replay.ts
|
|
4
|
+
/**
|
|
5
|
+
* One spent control-plane token, as a row.
|
|
6
|
+
*
|
|
7
|
+
* The row's **existence is the whole signal** — a claim is an insert that either wins the primary key or
|
|
8
|
+
* does not. The columns beside `jti` exist for two other jobs: `expiresAt` is what lets the table be
|
|
9
|
+
* pruned rather than grow forever, and `connectionId` is for the incident, not the decision. A replay is
|
|
10
|
+
* refused whatever connection presents it, because the `jti` alone is the key: scoping the uniqueness per
|
|
11
|
+
* connection would let a token captured from one connection be spent again against another, which is
|
|
12
|
+
* exactly the property being bought.
|
|
13
|
+
*/
|
|
14
|
+
const ControlPlaneReplay = z.object({
|
|
15
|
+
jti: z.string().min(1).max(128).describe("The token's unique id, minted by the management client, and the primary key that decides the race. Bounded because it arrives from a caller and becomes a stored key — an unbounded id would be an unbounded write."),
|
|
16
|
+
connectionId: z.string().min(1).describe("The connection whose token claimed this jti. Recorded for forensics only — the claim is decided by the jti alone, so that a token cannot be replayed against a second connection."),
|
|
17
|
+
expiresAt: SQLiteDate.describe("When this record may be pruned — the instant past which no token carrying this jti could still be accepted. Rows are deleted after it, never before: forgetting a jti while its token is still live is precisely the replay this table exists to stop.")
|
|
18
|
+
}).describe("A spent control-plane token id. Its presence is the refusal; the other columns are for pruning and for the incident.");
|
|
19
|
+
//#endregion
|
|
20
|
+
export { ControlPlaneReplay };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { D1Database } from "@cloudflare/workers-types";
|
|
2
|
+
import type { Kysely } from "kysely";
|
|
3
|
+
import type { z } from "zod";
|
|
4
|
+
import { type DatabaseSchema } from "../../data/db";
|
|
5
|
+
import { ControlPlaneConnection } from "./connection";
|
|
6
|
+
import { ControlPlaneReplay } from "./replay";
|
|
7
|
+
/**
|
|
8
|
+
* The connections table. `CamelCasePlugin` snake-cases it to `pithy_controlplane_connections` — the
|
|
9
|
+
* namespace is the single word `controlplane`, matching the migration namespace and the
|
|
10
|
+
* `controlplane/*` error codes, because the prefix pattern admits no hyphen.
|
|
11
|
+
*/
|
|
12
|
+
export declare const CONTROL_PLANE_CONNECTIONS_TABLE = "pithyControlplaneConnections";
|
|
13
|
+
/**
|
|
14
|
+
* The replay table — spent token ids. Snake-cases to `pithy_controlplane_replays`.
|
|
15
|
+
*
|
|
16
|
+
* In the same database as the connections rather than beside the sessions in KV, because that is what
|
|
17
|
+
* makes the claim a primary-key insert and therefore strongly consistent. See `../replay/guard.ts`.
|
|
18
|
+
*/
|
|
19
|
+
export declare const CONTROL_PLANE_REPLAYS_TABLE = "pithyControlplaneReplays";
|
|
20
|
+
/**
|
|
21
|
+
* The control-plane tables map. Both are always present: a Worker that composes the seam and has never
|
|
22
|
+
* been connected still needs somewhere for the answer "nobody is connected" to come from, and the
|
|
23
|
+
* replay table must exist before the first management call rather than on first use.
|
|
24
|
+
*/
|
|
25
|
+
export declare function controlPlaneTables(): Record<string, z.ZodObject>;
|
|
26
|
+
/** The typed Kysely database over the control-plane tables. */
|
|
27
|
+
export type ControlPlaneTables = {
|
|
28
|
+
[CONTROL_PLANE_CONNECTIONS_TABLE]: typeof ControlPlaneConnection;
|
|
29
|
+
[CONTROL_PLANE_REPLAYS_TABLE]: typeof ControlPlaneReplay;
|
|
30
|
+
};
|
|
31
|
+
export type ControlPlaneDatabase = Kysely<DatabaseSchema<ControlPlaneTables>>;
|
|
32
|
+
/** Build the control-plane database from the `DB` binding (CamelCasePlugin installed). */
|
|
33
|
+
export declare function controlPlaneDatabase(d1: D1Database): ControlPlaneDatabase;
|
|
34
|
+
//# sourceMappingURL=tables.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tables.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/data/tables.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAE9C;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,iCAAiC,CAAC;AAE9E;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,6BAA6B,CAAC;AAEtE;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,CAKhE;AAED,+DAA+D;AAC/D,MAAM,MAAM,kBAAkB,GAAG;IAC/B,CAAC,+BAA+B,CAAC,EAAE,OAAO,sBAAsB,CAAC;IACjE,CAAC,2BAA2B,CAAC,EAAE,OAAO,kBAAkB,CAAC;CAC1D,CAAC;AACF,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC,cAAc,CAAC,kBAAkB,CAAC,CAAC,CAAC;AAE9E,0FAA0F;AAC1F,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,UAAU,GAAG,oBAAoB,CAKzE"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ControlPlaneConnection } from "./connection.js";
|
|
2
|
+
import { createDatabase } from "../../data/db.js";
|
|
3
|
+
import { ControlPlaneReplay } from "./replay.js";
|
|
4
|
+
//#region src/controlPlane/data/tables.ts
|
|
5
|
+
/**
|
|
6
|
+
* The connections table. `CamelCasePlugin` snake-cases it to `pithy_controlplane_connections` — the
|
|
7
|
+
* namespace is the single word `controlplane`, matching the migration namespace and the
|
|
8
|
+
* `controlplane/*` error codes, because the prefix pattern admits no hyphen.
|
|
9
|
+
*/
|
|
10
|
+
const CONTROL_PLANE_CONNECTIONS_TABLE = "pithyControlplaneConnections";
|
|
11
|
+
/**
|
|
12
|
+
* The replay table — spent token ids. Snake-cases to `pithy_controlplane_replays`.
|
|
13
|
+
*
|
|
14
|
+
* In the same database as the connections rather than beside the sessions in KV, because that is what
|
|
15
|
+
* makes the claim a primary-key insert and therefore strongly consistent. See `../replay/guard.ts`.
|
|
16
|
+
*/
|
|
17
|
+
const CONTROL_PLANE_REPLAYS_TABLE = "pithyControlplaneReplays";
|
|
18
|
+
/**
|
|
19
|
+
* The control-plane tables map. Both are always present: a Worker that composes the seam and has never
|
|
20
|
+
* been connected still needs somewhere for the answer "nobody is connected" to come from, and the
|
|
21
|
+
* replay table must exist before the first management call rather than on first use.
|
|
22
|
+
*/
|
|
23
|
+
function controlPlaneTables() {
|
|
24
|
+
return {
|
|
25
|
+
[CONTROL_PLANE_CONNECTIONS_TABLE]: ControlPlaneConnection,
|
|
26
|
+
[CONTROL_PLANE_REPLAYS_TABLE]: ControlPlaneReplay
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/** Build the control-plane database from the `DB` binding (CamelCasePlugin installed). */
|
|
30
|
+
function controlPlaneDatabase(d1) {
|
|
31
|
+
return createDatabase(d1, {
|
|
32
|
+
[CONTROL_PLANE_CONNECTIONS_TABLE]: ControlPlaneConnection,
|
|
33
|
+
[CONTROL_PLANE_REPLAYS_TABLE]: ControlPlaneReplay
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
export { CONTROL_PLANE_CONNECTIONS_TABLE, CONTROL_PLANE_REPLAYS_TABLE, controlPlaneDatabase, controlPlaneTables };
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* What a capability tells a management client about its own admin surface.
|
|
4
|
+
*
|
|
5
|
+
* **This exists because knowing a capability is installed is not enough to call it.** A management
|
|
6
|
+
* client that learns only names still has to hold a route table for every capability, guess that
|
|
7
|
+
* payments is mounted at `/payments`, and know out-of-band which scope each operation needs. Every one
|
|
8
|
+
* of those is a thing that can be wrong, and `basePath` is configurable — an adopter who mounts
|
|
9
|
+
* payments at `/billing` would silently 404 a client that hardcoded the default.
|
|
10
|
+
*
|
|
11
|
+
* So the capability declares the routes it actually registered, with the paths it actually used, and
|
|
12
|
+
* `GET /control-plane/manifest` reports them. That is what makes discovery-over-configuration real
|
|
13
|
+
* rather than aspirational: a client composes its navigation *and* its calls from what the Worker says
|
|
14
|
+
* about itself, and an adopter who moves a mount point or upgrades a capability changes what the client
|
|
15
|
+
* does without either side coordinating.
|
|
16
|
+
*
|
|
17
|
+
* **The declaration is checked against the router**, not trusted — see `missingAdminRoutes`. A manifest
|
|
18
|
+
* that drifts from the routes is worse than no manifest, because a client would believe it.
|
|
19
|
+
*/
|
|
20
|
+
/** The HTTP methods an admin route may use. */
|
|
21
|
+
export declare const AdminRouteMethod: z.ZodEnum<{
|
|
22
|
+
DELETE: "DELETE";
|
|
23
|
+
GET: "GET";
|
|
24
|
+
PATCH: "PATCH";
|
|
25
|
+
POST: "POST";
|
|
26
|
+
PUT: "PUT";
|
|
27
|
+
}>;
|
|
28
|
+
export type AdminRouteMethod = z.infer<typeof AdminRouteMethod>;
|
|
29
|
+
/** One admin route a capability contributes behind the `control-plane` strategy. */
|
|
30
|
+
export declare const AdminRoute: z.ZodObject<{
|
|
31
|
+
method: z.ZodEnum<{
|
|
32
|
+
DELETE: "DELETE";
|
|
33
|
+
GET: "GET";
|
|
34
|
+
PATCH: "PATCH";
|
|
35
|
+
POST: "POST";
|
|
36
|
+
PUT: "PUT";
|
|
37
|
+
}>;
|
|
38
|
+
path: z.ZodString;
|
|
39
|
+
scope: z.ZodNullable<z.ZodString>;
|
|
40
|
+
summary: z.ZodString;
|
|
41
|
+
}, z.core.$strip>;
|
|
42
|
+
export type AdminRoute = z.infer<typeof AdminRoute>;
|
|
43
|
+
/**
|
|
44
|
+
* One composed capability's declaration — everything about it that is the same for every caller.
|
|
45
|
+
*
|
|
46
|
+
* Split from {@link CapabilityDescriptor} because the health *values* are the one part of a manifest
|
|
47
|
+
* entry that depends on who is asking, and the seam holds this half from assembly (`compose`) while the
|
|
48
|
+
* other half is resolved per request.
|
|
49
|
+
*/
|
|
50
|
+
export declare const CapabilityDeclaration: z.ZodObject<{
|
|
51
|
+
name: z.ZodString;
|
|
52
|
+
version: z.ZodNullable<z.ZodString>;
|
|
53
|
+
adminRoutes: z.ZodArray<z.ZodObject<{
|
|
54
|
+
method: z.ZodEnum<{
|
|
55
|
+
DELETE: "DELETE";
|
|
56
|
+
GET: "GET";
|
|
57
|
+
PATCH: "PATCH";
|
|
58
|
+
POST: "POST";
|
|
59
|
+
PUT: "PUT";
|
|
60
|
+
}>;
|
|
61
|
+
path: z.ZodString;
|
|
62
|
+
scope: z.ZodNullable<z.ZodString>;
|
|
63
|
+
summary: z.ZodString;
|
|
64
|
+
}, z.core.$strip>>;
|
|
65
|
+
healthKeys: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
66
|
+
key: z.ZodString;
|
|
67
|
+
kind: z.ZodEnum<{
|
|
68
|
+
count: "count";
|
|
69
|
+
state: "state";
|
|
70
|
+
}>;
|
|
71
|
+
states: z.ZodNullable<z.ZodArray<z.ZodString>>;
|
|
72
|
+
scope: z.ZodString;
|
|
73
|
+
cost: z.ZodEnum<{
|
|
74
|
+
indexed: "indexed";
|
|
75
|
+
memory: "memory";
|
|
76
|
+
}>;
|
|
77
|
+
summary: z.ZodString;
|
|
78
|
+
nominal: z.ZodDefault<z.ZodNullable<z.ZodUnion<readonly [z.ZodObject<{
|
|
79
|
+
atMost: z.ZodOptional<z.ZodNumber>;
|
|
80
|
+
atLeast: z.ZodOptional<z.ZodNumber>;
|
|
81
|
+
}, z.core.$strip>, z.ZodArray<z.ZodString>]>>>;
|
|
82
|
+
}, z.core.$strip>>>;
|
|
83
|
+
configKeys: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
84
|
+
key: z.ZodString;
|
|
85
|
+
choices: z.ZodNullable<z.ZodArray<z.ZodString>>;
|
|
86
|
+
summary: z.ZodString;
|
|
87
|
+
}, z.core.$strip>>>;
|
|
88
|
+
config: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
89
|
+
}, z.core.$strip>;
|
|
90
|
+
export type CapabilityDeclaration = z.infer<typeof CapabilityDeclaration>;
|
|
91
|
+
export declare const CapabilityDescriptor: z.ZodCodec<z.ZodObject<{
|
|
92
|
+
name: z.ZodString;
|
|
93
|
+
version: z.ZodNullable<z.ZodString>;
|
|
94
|
+
adminRoutes: z.ZodArray<z.ZodObject<{
|
|
95
|
+
method: z.ZodEnum<{
|
|
96
|
+
DELETE: "DELETE";
|
|
97
|
+
GET: "GET";
|
|
98
|
+
PATCH: "PATCH";
|
|
99
|
+
POST: "POST";
|
|
100
|
+
PUT: "PUT";
|
|
101
|
+
}>;
|
|
102
|
+
path: z.ZodString;
|
|
103
|
+
scope: z.ZodNullable<z.ZodString>;
|
|
104
|
+
summary: z.ZodString;
|
|
105
|
+
}, z.core.$strip>>;
|
|
106
|
+
healthKeys: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
107
|
+
key: z.ZodString;
|
|
108
|
+
kind: z.ZodEnum<{
|
|
109
|
+
count: "count";
|
|
110
|
+
state: "state";
|
|
111
|
+
}>;
|
|
112
|
+
states: z.ZodNullable<z.ZodArray<z.ZodString>>;
|
|
113
|
+
scope: z.ZodString;
|
|
114
|
+
cost: z.ZodEnum<{
|
|
115
|
+
indexed: "indexed";
|
|
116
|
+
memory: "memory";
|
|
117
|
+
}>;
|
|
118
|
+
summary: z.ZodString;
|
|
119
|
+
nominal: z.ZodDefault<z.ZodNullable<z.ZodUnion<readonly [z.ZodObject<{
|
|
120
|
+
atMost: z.ZodOptional<z.ZodNumber>;
|
|
121
|
+
atLeast: z.ZodOptional<z.ZodNumber>;
|
|
122
|
+
}, z.core.$strip>, z.ZodArray<z.ZodString>]>>>;
|
|
123
|
+
}, z.core.$strip>>>;
|
|
124
|
+
configKeys: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
125
|
+
key: z.ZodString;
|
|
126
|
+
choices: z.ZodNullable<z.ZodArray<z.ZodString>>;
|
|
127
|
+
summary: z.ZodString;
|
|
128
|
+
}, z.core.$strip>>>;
|
|
129
|
+
config: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
130
|
+
health: z.ZodDefault<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>>>;
|
|
131
|
+
healthUnavailable: z.ZodDefault<z.ZodBoolean>;
|
|
132
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
133
|
+
name: z.ZodString;
|
|
134
|
+
version: z.ZodNullable<z.ZodString>;
|
|
135
|
+
adminRoutes: z.ZodArray<z.ZodObject<{
|
|
136
|
+
method: z.ZodEnum<{
|
|
137
|
+
DELETE: "DELETE";
|
|
138
|
+
GET: "GET";
|
|
139
|
+
PATCH: "PATCH";
|
|
140
|
+
POST: "POST";
|
|
141
|
+
PUT: "PUT";
|
|
142
|
+
}>;
|
|
143
|
+
path: z.ZodString;
|
|
144
|
+
scope: z.ZodNullable<z.ZodString>;
|
|
145
|
+
summary: z.ZodString;
|
|
146
|
+
}, z.core.$strip>>;
|
|
147
|
+
healthKeys: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
148
|
+
key: z.ZodString;
|
|
149
|
+
kind: z.ZodEnum<{
|
|
150
|
+
count: "count";
|
|
151
|
+
state: "state";
|
|
152
|
+
}>;
|
|
153
|
+
states: z.ZodNullable<z.ZodArray<z.ZodString>>;
|
|
154
|
+
scope: z.ZodString;
|
|
155
|
+
cost: z.ZodEnum<{
|
|
156
|
+
indexed: "indexed";
|
|
157
|
+
memory: "memory";
|
|
158
|
+
}>;
|
|
159
|
+
summary: z.ZodString;
|
|
160
|
+
nominal: z.ZodDefault<z.ZodNullable<z.ZodUnion<readonly [z.ZodObject<{
|
|
161
|
+
atMost: z.ZodOptional<z.ZodNumber>;
|
|
162
|
+
atLeast: z.ZodOptional<z.ZodNumber>;
|
|
163
|
+
}, z.core.$strip>, z.ZodArray<z.ZodString>]>>>;
|
|
164
|
+
}, z.core.$strip>>>;
|
|
165
|
+
configKeys: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
166
|
+
key: z.ZodString;
|
|
167
|
+
choices: z.ZodNullable<z.ZodArray<z.ZodString>>;
|
|
168
|
+
summary: z.ZodString;
|
|
169
|
+
}, z.core.$strip>>>;
|
|
170
|
+
config: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
171
|
+
health: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
172
|
+
state: z.ZodLiteral<"undeclared">;
|
|
173
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
174
|
+
state: z.ZodLiteral<"withheld">;
|
|
175
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
176
|
+
state: z.ZodLiteral<"reported">;
|
|
177
|
+
values: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>;
|
|
178
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
179
|
+
state: z.ZodLiteral<"unavailable">;
|
|
180
|
+
}, z.core.$strip>], "state">;
|
|
181
|
+
}, z.core.$strip>>;
|
|
182
|
+
export type CapabilityDescriptor = z.infer<typeof CapabilityDescriptor>;
|
|
183
|
+
/**
|
|
184
|
+
* The manifest a management client reads to build itself.
|
|
185
|
+
*
|
|
186
|
+
* **There is deliberately no manifest schema version, and that is a different thing from the two build
|
|
187
|
+
* identities below.** A client dispatches on the routes described here — what this Worker declares right
|
|
188
|
+
* now — so a capability that changed its paths or its scopes reports the change directly, and a schema
|
|
189
|
+
* version would be a second source of truth to keep in sync with the first. That reasoning is unchanged.
|
|
190
|
+
*
|
|
191
|
+
* What the manifest does carry is **identity**, not schema, and it carries two of them because they
|
|
192
|
+
* answer questions neither can answer alone. `version` is Cloudflare's opaque per-deploy id: it says
|
|
193
|
+
* *exactly which build* is running, which is what forensics needs, what reproduces a report, and what
|
|
194
|
+
* pins the code an audited action ran against. It carries no version semantics, so it says nothing about
|
|
195
|
+
* features. `capabilities[].version` is the npm version of each composed package: it says *which
|
|
196
|
+
* features*, which is what answers "should this customer upgrade", "which customers are exposed to what
|
|
197
|
+
* we just fixed", and "does this project predate the capability a pane needs". Reporting only one leaves
|
|
198
|
+
* half the questions unanswerable, and they are the halves people actually ask.
|
|
199
|
+
*
|
|
200
|
+
* **And each entry carries a third thing: the configured facts that capability states** (#422). Knowing
|
|
201
|
+
* where a route is and which scope it needs is not always enough to call it — `POST
|
|
202
|
+
* {base}/entitlements/grant` names a holder, and whether this project's holders are people or
|
|
203
|
+
* organizations is a decision the adopter made in config. A client that cannot read the decision guesses
|
|
204
|
+
* it, and a guess writes a row nothing reads. See `discovery/configuration.ts` for why a fact is not a
|
|
205
|
+
* health number, despite the two fields sitting side by side.
|
|
206
|
+
*/
|
|
207
|
+
export declare const ControlPlaneManifest: z.ZodObject<{
|
|
208
|
+
environment: z.ZodString;
|
|
209
|
+
connectionId: z.ZodString;
|
|
210
|
+
version: z.ZodNullable<z.ZodString>;
|
|
211
|
+
capabilities: z.ZodArray<z.ZodCodec<z.ZodObject<{
|
|
212
|
+
name: z.ZodString;
|
|
213
|
+
version: z.ZodNullable<z.ZodString>;
|
|
214
|
+
adminRoutes: z.ZodArray<z.ZodObject<{
|
|
215
|
+
method: z.ZodEnum<{
|
|
216
|
+
DELETE: "DELETE";
|
|
217
|
+
GET: "GET";
|
|
218
|
+
PATCH: "PATCH";
|
|
219
|
+
POST: "POST";
|
|
220
|
+
PUT: "PUT";
|
|
221
|
+
}>;
|
|
222
|
+
path: z.ZodString;
|
|
223
|
+
scope: z.ZodNullable<z.ZodString>;
|
|
224
|
+
summary: z.ZodString;
|
|
225
|
+
}, z.core.$strip>>;
|
|
226
|
+
healthKeys: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
227
|
+
key: z.ZodString;
|
|
228
|
+
kind: z.ZodEnum<{
|
|
229
|
+
count: "count";
|
|
230
|
+
state: "state";
|
|
231
|
+
}>;
|
|
232
|
+
states: z.ZodNullable<z.ZodArray<z.ZodString>>;
|
|
233
|
+
scope: z.ZodString;
|
|
234
|
+
cost: z.ZodEnum<{
|
|
235
|
+
indexed: "indexed";
|
|
236
|
+
memory: "memory";
|
|
237
|
+
}>;
|
|
238
|
+
summary: z.ZodString;
|
|
239
|
+
nominal: z.ZodDefault<z.ZodNullable<z.ZodUnion<readonly [z.ZodObject<{
|
|
240
|
+
atMost: z.ZodOptional<z.ZodNumber>;
|
|
241
|
+
atLeast: z.ZodOptional<z.ZodNumber>;
|
|
242
|
+
}, z.core.$strip>, z.ZodArray<z.ZodString>]>>>;
|
|
243
|
+
}, z.core.$strip>>>;
|
|
244
|
+
configKeys: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
245
|
+
key: z.ZodString;
|
|
246
|
+
choices: z.ZodNullable<z.ZodArray<z.ZodString>>;
|
|
247
|
+
summary: z.ZodString;
|
|
248
|
+
}, z.core.$strip>>>;
|
|
249
|
+
config: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
250
|
+
health: z.ZodDefault<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>>>;
|
|
251
|
+
healthUnavailable: z.ZodDefault<z.ZodBoolean>;
|
|
252
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
253
|
+
name: z.ZodString;
|
|
254
|
+
version: z.ZodNullable<z.ZodString>;
|
|
255
|
+
adminRoutes: z.ZodArray<z.ZodObject<{
|
|
256
|
+
method: z.ZodEnum<{
|
|
257
|
+
DELETE: "DELETE";
|
|
258
|
+
GET: "GET";
|
|
259
|
+
PATCH: "PATCH";
|
|
260
|
+
POST: "POST";
|
|
261
|
+
PUT: "PUT";
|
|
262
|
+
}>;
|
|
263
|
+
path: z.ZodString;
|
|
264
|
+
scope: z.ZodNullable<z.ZodString>;
|
|
265
|
+
summary: z.ZodString;
|
|
266
|
+
}, z.core.$strip>>;
|
|
267
|
+
healthKeys: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
268
|
+
key: z.ZodString;
|
|
269
|
+
kind: z.ZodEnum<{
|
|
270
|
+
count: "count";
|
|
271
|
+
state: "state";
|
|
272
|
+
}>;
|
|
273
|
+
states: z.ZodNullable<z.ZodArray<z.ZodString>>;
|
|
274
|
+
scope: z.ZodString;
|
|
275
|
+
cost: z.ZodEnum<{
|
|
276
|
+
indexed: "indexed";
|
|
277
|
+
memory: "memory";
|
|
278
|
+
}>;
|
|
279
|
+
summary: z.ZodString;
|
|
280
|
+
nominal: z.ZodDefault<z.ZodNullable<z.ZodUnion<readonly [z.ZodObject<{
|
|
281
|
+
atMost: z.ZodOptional<z.ZodNumber>;
|
|
282
|
+
atLeast: z.ZodOptional<z.ZodNumber>;
|
|
283
|
+
}, z.core.$strip>, z.ZodArray<z.ZodString>]>>>;
|
|
284
|
+
}, z.core.$strip>>>;
|
|
285
|
+
configKeys: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
286
|
+
key: z.ZodString;
|
|
287
|
+
choices: z.ZodNullable<z.ZodArray<z.ZodString>>;
|
|
288
|
+
summary: z.ZodString;
|
|
289
|
+
}, z.core.$strip>>>;
|
|
290
|
+
config: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
291
|
+
health: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
292
|
+
state: z.ZodLiteral<"undeclared">;
|
|
293
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
294
|
+
state: z.ZodLiteral<"withheld">;
|
|
295
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
296
|
+
state: z.ZodLiteral<"reported">;
|
|
297
|
+
values: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>;
|
|
298
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
299
|
+
state: z.ZodLiteral<"unavailable">;
|
|
300
|
+
}, z.core.$strip>], "state">;
|
|
301
|
+
}, z.core.$strip>>>;
|
|
302
|
+
grantedScopes: z.ZodArray<z.ZodString>;
|
|
303
|
+
}, z.core.$strip>;
|
|
304
|
+
export type ControlPlaneManifest = z.infer<typeof ControlPlaneManifest>;
|
|
305
|
+
/**
|
|
306
|
+
* The manifest as the Worker sends it, before a client decodes it.
|
|
307
|
+
*
|
|
308
|
+
* The handler builds this and is `satisfies`-checked against it, which keeps the response a compile-time
|
|
309
|
+
* contract rather than a validation pass over values this Worker just built. A client parses with
|
|
310
|
+
* {@link ControlPlaneManifest} and gets the four-state health value out the far side.
|
|
311
|
+
*/
|
|
312
|
+
export type ControlPlaneManifestWire = z.input<typeof ControlPlaneManifest>;
|
|
313
|
+
//# sourceMappingURL=adminRoute.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adminRoute.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/discovery/adminRoute.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB;;;;;;;;;;;;;;;;;GAiBG;AAEH,+CAA+C;AAC/C,eAAO,MAAM,gBAAgB;;;;;;EAE8B,CAAC;AAC5D,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE,oFAAoF;AACpF,eAAO,MAAM,UAAU;;;;;;;;;;;iBAmBpB,CAAC;AACJ,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAEpD;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA2C/B,CAAC;AACJ,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAiD1E,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAiC9B,CAAC;AACJ,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuBkE,CAAC;AACpG,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE;;;;;;GAMG;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC"}
|