@pithy-sh/core 0.1.2 → 0.1.3
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,51 @@
|
|
|
1
|
+
import { messageDomain } from "./catalog.js";
|
|
2
|
+
import { ValidationError } from "../error/pithyError.js";
|
|
3
|
+
import "./translator.js";
|
|
4
|
+
//#region src/i18n/registry.ts
|
|
5
|
+
/**
|
|
6
|
+
* Every composed capability's `messages`, merged into one set of catalogs keyed by locale.
|
|
7
|
+
*
|
|
8
|
+
* **A capability may only declare keys under its own domain**, and the merge refuses anything else.
|
|
9
|
+
* That is the same rule as `pithy_<capability>_<table>` and `auth/invalid_token`, enforced for the same
|
|
10
|
+
* reason: the domain segment is what makes two capabilities' contributions incapable of colliding, so
|
|
11
|
+
* merge order stops being a thing anyone has to reason about. It applies to the adopter's own `app`
|
|
12
|
+
* capability exactly as it applies to a kit package — `board/nav.settings` is theirs to declare, and
|
|
13
|
+
* `auth/sign_in.title` is not.
|
|
14
|
+
*
|
|
15
|
+
* Library-before-app, like the migration registry: capabilities are merged in composition order, so a
|
|
16
|
+
* later contribution wins a key an earlier one wrote. With the domain rule in force that can only
|
|
17
|
+
* happen between two capabilities sharing a name, which `createBackend` already refuses.
|
|
18
|
+
*/
|
|
19
|
+
function composeMessages(capabilities) {
|
|
20
|
+
const contributions = [];
|
|
21
|
+
for (const capability of capabilities) if (capability.messages) contributions.push({
|
|
22
|
+
capability: capability.name,
|
|
23
|
+
catalogs: capability.messages
|
|
24
|
+
});
|
|
25
|
+
const merged = /* @__PURE__ */ new Map();
|
|
26
|
+
for (const { capability, catalogs } of contributions) for (const [locale, catalog] of Object.entries(catalogs)) {
|
|
27
|
+
const target = merged.get(locale) ?? /* @__PURE__ */ new Map();
|
|
28
|
+
for (const [key, message] of Object.entries(catalog)) {
|
|
29
|
+
const domain = messageDomain(key);
|
|
30
|
+
if (domain !== capability) throw new ValidationError({
|
|
31
|
+
message: "A capability may only contribute messages under its own domain.",
|
|
32
|
+
action: `Rename \`${key}\` to start with \`${capability}/\`, or move it to the capability that owns that domain.`,
|
|
33
|
+
detail: `\`${capability}\` contributed \`${key}\` in locale \`${locale}\`, whose domain is \`${domain}\`.`
|
|
34
|
+
});
|
|
35
|
+
target.set(key, message);
|
|
36
|
+
}
|
|
37
|
+
merged.set(locale, target);
|
|
38
|
+
}
|
|
39
|
+
return Object.fromEntries([...merged].map(([locale, catalog]) => [locale, Object.fromEntries(catalog)]));
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The catalog for `locale`, or the default locale's, or an empty one.
|
|
43
|
+
*
|
|
44
|
+
* The fallback that makes the seam optional: a Worker composing no i18n capability reads the baked
|
|
45
|
+
* English and behaves byte for byte as it did before any of this landed.
|
|
46
|
+
*/
|
|
47
|
+
function catalogFor(catalogs, locale) {
|
|
48
|
+
return catalogs[locale] ?? catalogs["en"] ?? {};
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { catalogFor, composeMessages };
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { type MessageCatalog, type MessageParams } from "./catalog";
|
|
2
|
+
import { type TextDirection } from "./locale";
|
|
3
|
+
/**
|
|
4
|
+
* The i18n seam. `@pithy-sh/core` defines this shape; `@pithy-sh/i18n` populates it from the resolved
|
|
5
|
+
* request locale. Every other capability, and every screen, depends only on this object — the same
|
|
6
|
+
* split `AuthContext` uses, and for the same reason: `@pithy-sh/email` and the error module both need
|
|
7
|
+
* a locale and neither may import an i18n capability.
|
|
8
|
+
*
|
|
9
|
+
* **The two locales are both here, as plain strings.** An adopter who already owns their date and
|
|
10
|
+
* number rendering needs the locale as a *value* to hand to `Intl`; forcing it through
|
|
11
|
+
* {@link Translator.formatDate} turns a one-line repair into an every-call-site one, against gates that
|
|
12
|
+
* exist to keep those calls in one place.
|
|
13
|
+
*/
|
|
14
|
+
export interface Translator {
|
|
15
|
+
/**
|
|
16
|
+
* The locale whose catalog answers {@link Translator.t} — the words the kit actually has.
|
|
17
|
+
*
|
|
18
|
+
* An `es-AR` reader gets `es` here, because `es` is what is written. See
|
|
19
|
+
* {@link Translator.formattingLocale} for the half that does not fall back.
|
|
20
|
+
*/
|
|
21
|
+
readonly catalogLocale: string;
|
|
22
|
+
/**
|
|
23
|
+
* The locale handed to `Intl` — what the reader asked for, region and all.
|
|
24
|
+
*
|
|
25
|
+
* An `es-AR` reader gets `es-AR` here, which `Intl` supports natively whether or not anyone wrote a
|
|
26
|
+
* string for it. Collapsing this into {@link Translator.catalogLocale} is the bug where an Argentine
|
|
27
|
+
* reads Spanish and sees `1,234.56`.
|
|
28
|
+
*/
|
|
29
|
+
readonly formattingLocale: string;
|
|
30
|
+
/** The catalog locale's text direction — what `lang`/`dir` on the document and the email shell get. */
|
|
31
|
+
readonly direction: TextDirection;
|
|
32
|
+
/**
|
|
33
|
+
* The message `key` names, with `{placeholder}` substitution.
|
|
34
|
+
*
|
|
35
|
+
* Returns the key itself when nothing has it. That is the honest answer — a blank reads like finished
|
|
36
|
+
* copy — and it is unreachable for a kit key, because catalog coverage is a CI gate.
|
|
37
|
+
*/
|
|
38
|
+
t(key: string, params?: MessageParams): string;
|
|
39
|
+
/**
|
|
40
|
+
* The message `key` names, or `null` when no layer has it.
|
|
41
|
+
*
|
|
42
|
+
* **The half {@link Translator.t} cannot express, and the error path needs.** `t` is total because a
|
|
43
|
+
* screen always has to render something, so a miss comes back as the key — which is the honest thing
|
|
44
|
+
* to show and is unusable as a signal. An error is the other case: the payload already carries an
|
|
45
|
+
* English `message`, and a client that could not translate the code must render *that*, not the code.
|
|
46
|
+
*
|
|
47
|
+
* So the documented client contract is `t.maybe(payload.code, payload.params) ?? payload.message`.
|
|
48
|
+
* Written against `t` it silently never falls back — `t` returns the key, `??` sees a string, and a
|
|
49
|
+
* caller in an uncovered locale reads `auth/invalid_token` on their screen instead of the sentence
|
|
50
|
+
* the server took care to send them.
|
|
51
|
+
*/
|
|
52
|
+
maybe(key: string, params?: MessageParams): string | null;
|
|
53
|
+
/**
|
|
54
|
+
* The message `key` names, in the plural form `count` calls for.
|
|
55
|
+
*
|
|
56
|
+
* Looks up `<key>.<category>` for the `Intl.PluralRules` category of `count` in the catalog locale,
|
|
57
|
+
* falling back to `<key>.other`. `count` is available to the message as `{count}` without being
|
|
58
|
+
* passed twice.
|
|
59
|
+
*
|
|
60
|
+
* Explicit rather than folded into {@link Translator.t}, because plural selection is the thing a
|
|
61
|
+
* second locale exposes: English has two forms, Spanish has two, Russian has three, and a call site
|
|
62
|
+
* that concatenated a number onto a noun has no form at all.
|
|
63
|
+
*/
|
|
64
|
+
plural(key: string, count: number, params?: MessageParams): string;
|
|
65
|
+
/** `value` as a number in the formatting locale. */
|
|
66
|
+
formatNumber(value: number, options?: Intl.NumberFormatOptions): string;
|
|
67
|
+
/** `value` as an amount of `currency` in the formatting locale. */
|
|
68
|
+
formatCurrency(value: number, currency: string, options?: Intl.NumberFormatOptions): string;
|
|
69
|
+
/** `value` as a date in the formatting locale. Accepts a `Date` or an epoch-milliseconds number. */
|
|
70
|
+
formatDate(value: Date | number, options?: Intl.DateTimeFormatOptions): string;
|
|
71
|
+
/** `values` as a list in the formatting locale — `a, b y c` in Spanish, `a, b, and c` in English. */
|
|
72
|
+
formatList(values: readonly string[], options?: Intl.ListFormatOptions): string;
|
|
73
|
+
/** `value` `unit`s from now, in the formatting locale — `ayer`, `in 3 days`. */
|
|
74
|
+
formatRelativeTime(value: number, unit: Intl.RelativeTimeFormatUnit, options?: Intl.RelativeTimeFormatOptions): string;
|
|
75
|
+
}
|
|
76
|
+
/** What a translator is built from: the locales it answers in, and the layers it looks messages up through. */
|
|
77
|
+
export interface TranslatorInput {
|
|
78
|
+
/** The locale whose catalog answers `t()`. */
|
|
79
|
+
readonly catalogLocale: string;
|
|
80
|
+
/** The locale handed to `Intl`; defaults to {@link TranslatorInput.catalogLocale}. */
|
|
81
|
+
readonly formattingLocale?: string;
|
|
82
|
+
/**
|
|
83
|
+
* The catalogs to walk, most-specific first. `@pithy-sh/i18n` passes adopter-locale, adopter-default,
|
|
84
|
+
* kit-locale, kit-default; a copied screen passes its own baked English and nothing else.
|
|
85
|
+
*/
|
|
86
|
+
readonly layers: readonly (MessageCatalog | undefined)[];
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* A translator over `layers`.
|
|
90
|
+
*
|
|
91
|
+
* The `Intl` formatters are constructed lazily and held for the life of the translator. A translator is
|
|
92
|
+
* per request (or per mounted screen), so nothing here outlives a locale — which is the whole reason
|
|
93
|
+
* `z.config()` is banned repo-wide and a per-request global is not an option.
|
|
94
|
+
*/
|
|
95
|
+
export declare function createTranslator(input: TranslatorInput): Translator;
|
|
96
|
+
/** The locale a project falls back to when nothing else answers, and the locale the kit writes in. */
|
|
97
|
+
export declare const DEFAULT_LOCALE = "en";
|
|
98
|
+
/**
|
|
99
|
+
* A translator over one baked catalog — **the seam's behavior when `@pithy-sh/i18n` is not composed.**
|
|
100
|
+
*
|
|
101
|
+
* This is what makes the capability optional. A project that never composes `i18n` renders the baked
|
|
102
|
+
* English fallback, byte for byte as it does today, with no negotiation, no merge and no config. A
|
|
103
|
+
* copied screen builds one from the English it was scaffolded with, which is the only catalog that
|
|
104
|
+
* survives being copied into an adopter's repository.
|
|
105
|
+
*/
|
|
106
|
+
export declare function bakedTranslator(catalog: MessageCatalog, locale?: string): Translator;
|
|
107
|
+
//# sourceMappingURL=translator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translator.d.ts","sourceRoot":"","sources":["../../src/i18n/translator.ts"],"names":[],"mappings":"AAGA,OAAO,EAA8B,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAChG,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AAE/D;;;;;;;;;;GAUG;AACH,MAAM,WAAW,UAAU;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B;;;;;;OAMG;IACH,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,uGAAuG;IACvG,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;IAClC;;;;;OAKG;IACH,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC;IAC/C;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAAC;IAC1D;;;;;;;;;;OAUG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC;IACnE,oDAAoD;IACpD,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,mBAAmB,GAAG,MAAM,CAAC;IACxE,mEAAmE;IACnE,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,mBAAmB,GAAG,MAAM,CAAC;IAC5F,oGAAoG;IACpG,UAAU,CAAC,KAAK,EAAE,IAAI,GAAG,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,qBAAqB,GAAG,MAAM,CAAC;IAC/E,qGAAqG;IACrG,UAAU,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,iBAAiB,GAAG,MAAM,CAAC;IAChF,gFAAgF;IAChF,kBAAkB,CAChB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,IAAI,CAAC,sBAAsB,EACjC,OAAO,CAAC,EAAE,IAAI,CAAC,yBAAyB,GACvC,MAAM,CAAC;CACX;AAED,+GAA+G;AAC/G,MAAM,WAAW,eAAe;IAC9B,8CAA8C;IAC9C,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,sFAAsF;IACtF,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,cAAc,GAAG,SAAS,CAAC,EAAE,CAAC;CAC1D;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,UAAU,CAgDnE;AAED,sGAAsG;AACtG,eAAO,MAAM,cAAc,OAAO,CAAC;AAEnC;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,cAAc,EAAE,MAAM,GAAE,MAAuB,GAAG,UAAU,CAEpG"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { localeDirection } from "./locale.js";
|
|
2
|
+
import { interpolate, lookupMessage } from "./catalog.js";
|
|
3
|
+
//#region src/i18n/translator.ts
|
|
4
|
+
/**
|
|
5
|
+
* A translator over `layers`.
|
|
6
|
+
*
|
|
7
|
+
* The `Intl` formatters are constructed lazily and held for the life of the translator. A translator is
|
|
8
|
+
* per request (or per mounted screen), so nothing here outlives a locale — which is the whole reason
|
|
9
|
+
* `z.config()` is banned repo-wide and a per-request global is not an option.
|
|
10
|
+
*/
|
|
11
|
+
function createTranslator(input) {
|
|
12
|
+
const catalogLocale = input.catalogLocale;
|
|
13
|
+
const formattingLocale = input.formattingLocale ?? catalogLocale;
|
|
14
|
+
const layers = input.layers;
|
|
15
|
+
let plurals;
|
|
16
|
+
const pluralRules = () => {
|
|
17
|
+
plurals ??= new Intl.PluralRules(catalogLocale);
|
|
18
|
+
return plurals;
|
|
19
|
+
};
|
|
20
|
+
const maybe = (key, params) => {
|
|
21
|
+
const message = lookupMessage(layers, key);
|
|
22
|
+
return message === null ? null : interpolate(message, params);
|
|
23
|
+
};
|
|
24
|
+
const translate = (key, params) => maybe(key, params) ?? key;
|
|
25
|
+
return {
|
|
26
|
+
catalogLocale,
|
|
27
|
+
formattingLocale,
|
|
28
|
+
direction: localeDirection(catalogLocale),
|
|
29
|
+
t: translate,
|
|
30
|
+
maybe,
|
|
31
|
+
plural(key, count, params) {
|
|
32
|
+
const category = pluralRules().select(count);
|
|
33
|
+
const withCount = {
|
|
34
|
+
count,
|
|
35
|
+
...params
|
|
36
|
+
};
|
|
37
|
+
const exact = lookupMessage(layers, `${key}.${category}`);
|
|
38
|
+
if (exact !== null) return interpolate(exact, withCount);
|
|
39
|
+
const other = lookupMessage(layers, `${key}.other`);
|
|
40
|
+
return other === null ? key : interpolate(other, withCount);
|
|
41
|
+
},
|
|
42
|
+
formatNumber(value, options) {
|
|
43
|
+
return new Intl.NumberFormat(formattingLocale, options).format(value);
|
|
44
|
+
},
|
|
45
|
+
formatCurrency(value, currency, options) {
|
|
46
|
+
return new Intl.NumberFormat(formattingLocale, {
|
|
47
|
+
...options,
|
|
48
|
+
style: "currency",
|
|
49
|
+
currency
|
|
50
|
+
}).format(value);
|
|
51
|
+
},
|
|
52
|
+
formatDate(value, options) {
|
|
53
|
+
return new Intl.DateTimeFormat(formattingLocale, options).format(value);
|
|
54
|
+
},
|
|
55
|
+
formatList(values, options) {
|
|
56
|
+
return new Intl.ListFormat(formattingLocale, options).format(values);
|
|
57
|
+
},
|
|
58
|
+
formatRelativeTime(value, unit, options) {
|
|
59
|
+
return new Intl.RelativeTimeFormat(formattingLocale, options).format(value, unit);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/** The locale a project falls back to when nothing else answers, and the locale the kit writes in. */
|
|
64
|
+
const DEFAULT_LOCALE = "en";
|
|
65
|
+
/**
|
|
66
|
+
* A translator over one baked catalog — **the seam's behavior when `@pithy-sh/i18n` is not composed.**
|
|
67
|
+
*
|
|
68
|
+
* This is what makes the capability optional. A project that never composes `i18n` renders the baked
|
|
69
|
+
* English fallback, byte for byte as it does today, with no negotiation, no merge and no config. A
|
|
70
|
+
* copied screen builds one from the English it was scaffolded with, which is the only catalog that
|
|
71
|
+
* survives being copied into an adopter's repository.
|
|
72
|
+
*/
|
|
73
|
+
function bakedTranslator(catalog, locale = "en") {
|
|
74
|
+
return createTranslator({
|
|
75
|
+
catalogLocale: locale,
|
|
76
|
+
layers: [catalog]
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
80
|
+
export { DEFAULT_LOCALE, bakedTranslator, createTranslator };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `pithy add controlplane` surface — **not a barrel over `@pithy-sh/core`.**
|
|
3
|
+
*
|
|
4
|
+
* `pithy add` writes `import { <name> } from "<package>/src/index";` into a Worker's `pithy.config.ts`,
|
|
5
|
+
* so a capability has to be reachable at its package's `src/index`. Core ships one capability — the
|
|
6
|
+
* `control-plane` seam — and this file exists to name it and nothing else.
|
|
7
|
+
*
|
|
8
|
+
* Everything else in core stays deep-imported (`@pithy-sh/core/src/error/pithyError`,
|
|
9
|
+
* `@pithy-sh/core/src/data/codecs`), which is the rule and which nothing here relaxes. The exports
|
|
10
|
+
* below are the ones an adopter's own code plausibly touches: the factory their config calls, the
|
|
11
|
+
* config schema behind it, the table and row schemas they may read against, the audit actions their
|
|
12
|
+
* queries filter on, and — because the seam is MIT and never gated — the minting side, so "build your
|
|
13
|
+
* own management client" is a real option rather than a slogan.
|
|
14
|
+
*
|
|
15
|
+
* `@pithy-sh/storage/src/index.ts` documents itself the same way, for the same reason.
|
|
16
|
+
*/
|
|
17
|
+
export { type ControlPlaneAuditAction, ControlPlaneAuditActions } from "./controlPlane/audit/actions";
|
|
18
|
+
export { CONTROL_PLANE_KV_BINDING, CONTROLPLANE_MIGRATION_ORDER, type ControlPlaneCapability, type ControlPlaneOptions, controlplane, isControlPlaneCapability, } from "./controlPlane/capability";
|
|
19
|
+
export { ControlPlaneConfig, type ControlPlaneConfigInput } from "./controlPlane/config/config";
|
|
20
|
+
export { ControlPlaneContext } from "./controlPlane/context";
|
|
21
|
+
export { ControlPlaneConnection, Ed25519PublicJwk, RegisteredKey } from "./controlPlane/data/connection";
|
|
22
|
+
export { CONTROL_PLANE_CONNECTIONS_TABLE, type ControlPlaneDatabase, controlPlaneDatabase, } from "./controlPlane/data/tables";
|
|
23
|
+
export { AdminRoute, type AdminRouteMethod, CapabilityDeclaration, CapabilityDescriptor, ControlPlaneManifest, type ControlPlaneManifestWire, } from "./controlPlane/discovery/adminRoute";
|
|
24
|
+
export { type CapabilityManifestConfig, type CapabilityManifestConfigInput, defineManifestConfig, ManifestConfigKey, ManifestConfigValue, ManifestConfigValues, type NamedConfigValue, namedConfigValues, } from "./controlPlane/discovery/configuration";
|
|
25
|
+
export { type AdminRouteDrift, missingAdminRoutes } from "./controlPlane/discovery/drift";
|
|
26
|
+
export { type CapabilityHealth, type CapabilityHealthInput, type CapabilityHealthSource, capabilityHealthSources, defineCapabilityHealth, readCapabilityHealth, } from "./controlPlane/discovery/health";
|
|
27
|
+
export { CapabilityHealthReport, type CapabilityHealthWire, HealthCountNominal, HealthNominal, type HealthStanding, HealthSummary, HealthSummaryKey, HealthSummaryValue, HealthValueCost, HealthValueKind, healthAttention, healthReport, healthWire, type NamedHealthValue, namedHealthValues, standingOf, } from "./controlPlane/discovery/healthSummary";
|
|
28
|
+
export { requireControlPlane } from "./controlPlane/http/guard";
|
|
29
|
+
export { ANY_VERIFIED_CALLER, type ControlPlaneRequirement, ControlPlaneScope, KEYS_ROTATE_SCOPE, MANIFEST_READ_SCOPE, SEAM_SCOPES, } from "./controlPlane/scope/scope";
|
|
30
|
+
export { exportPublicJwk, type MintControlPlaneToken, mintControlPlaneToken } from "./controlPlane/token/mint";
|
|
31
|
+
export { CONTROL_PLANE_HEADER, CONTROL_PLANE_VERSION_CREATED_HEADER, CONTROL_PLANE_VERSION_HEADER, type WorkerBuild, workerBuildChanged, } from "./controlPlane/wire";
|
|
32
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,KAAK,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACtG,OAAO,EACL,wBAAwB,EACxB,4BAA4B,EAC5B,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,YAAY,EACZ,wBAAwB,GACzB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAChG,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AACzG,OAAO,EACL,+BAA+B,EAC/B,KAAK,oBAAoB,EACzB,oBAAoB,GACrB,MAAM,4BAA4B,CAAC;AAIpC,OAAO,EACL,UAAU,EACV,KAAK,gBAAgB,EACrB,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,EACpB,KAAK,wBAAwB,GAC9B,MAAM,qCAAqC,CAAC;AAK7C,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,6BAA6B,EAClC,oBAAoB,EACpB,iBAAiB,EACjB,mBAAmB,EACnB,oBAAoB,EACpB,KAAK,gBAAgB,EACrB,iBAAiB,GAClB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,KAAK,eAAe,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAQ1F,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,uBAAuB,EACvB,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,sBAAsB,EACtB,KAAK,oBAAoB,EACzB,kBAAkB,EAClB,aAAa,EACb,KAAK,cAAc,EACnB,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,eAAe,EACf,eAAe,EACf,YAAY,EACZ,UAAU,EACV,KAAK,gBAAgB,EACrB,iBAAiB,EACjB,UAAU,GACX,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EACL,mBAAmB,EACnB,KAAK,uBAAuB,EAC5B,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,WAAW,GACZ,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,KAAK,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAI/G,OAAO,EACL,oBAAoB,EACpB,oCAAoC,EACpC,4BAA4B,EAC5B,KAAK,WAAW,EAChB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ANY_VERIFIED_CALLER, ControlPlaneScope, KEYS_ROTATE_SCOPE, MANIFEST_READ_SCOPE, SEAM_SCOPES } from "./controlPlane/scope/scope.js";
|
|
2
|
+
import { ControlPlaneConfig } from "./controlPlane/config/config.js";
|
|
3
|
+
import { ControlPlaneConnection, Ed25519PublicJwk, RegisteredKey } from "./controlPlane/data/connection.js";
|
|
4
|
+
import { CONTROL_PLANE_CONNECTIONS_TABLE, controlPlaneDatabase } from "./controlPlane/data/tables.js";
|
|
5
|
+
import { CapabilityHealthReport, HealthCountNominal, HealthNominal, HealthSummary, HealthSummaryKey, HealthSummaryValue, HealthValueCost, HealthValueKind, healthAttention, healthReport, healthWire, namedHealthValues, standingOf } from "./controlPlane/discovery/healthSummary.js";
|
|
6
|
+
import { capabilityHealthSources, defineCapabilityHealth, readCapabilityHealth } from "./controlPlane/discovery/health.js";
|
|
7
|
+
import { ControlPlaneAuditActions } from "./controlPlane/audit/actions.js";
|
|
8
|
+
import { CONTROL_PLANE_HEADER, CONTROL_PLANE_VERSION_CREATED_HEADER, CONTROL_PLANE_VERSION_HEADER, workerBuildChanged } from "./controlPlane/wire.js";
|
|
9
|
+
import { ControlPlaneContext } from "./controlPlane/context.js";
|
|
10
|
+
import { requireControlPlane } from "./controlPlane/http/guard.js";
|
|
11
|
+
import { CONTROL_PLANE_KV_BINDING } from "./controlPlane/replay/kvGuard.js";
|
|
12
|
+
import { CONTROLPLANE_MIGRATION_ORDER, controlplane, isControlPlaneCapability } from "./controlPlane/capability.js";
|
|
13
|
+
import { ManifestConfigKey, ManifestConfigValue, ManifestConfigValues, defineManifestConfig, namedConfigValues } from "./controlPlane/discovery/configuration.js";
|
|
14
|
+
import { AdminRoute, CapabilityDeclaration, CapabilityDescriptor, ControlPlaneManifest } from "./controlPlane/discovery/adminRoute.js";
|
|
15
|
+
import { missingAdminRoutes } from "./controlPlane/discovery/drift.js";
|
|
16
|
+
import { exportPublicJwk, mintControlPlaneToken } from "./controlPlane/token/mint.js";
|
|
17
|
+
export { ANY_VERIFIED_CALLER, AdminRoute, CONTROLPLANE_MIGRATION_ORDER, CONTROL_PLANE_CONNECTIONS_TABLE, CONTROL_PLANE_HEADER, CONTROL_PLANE_KV_BINDING, CONTROL_PLANE_VERSION_CREATED_HEADER, CONTROL_PLANE_VERSION_HEADER, CapabilityDeclaration, CapabilityDescriptor, CapabilityHealthReport, ControlPlaneAuditActions, ControlPlaneConfig, ControlPlaneConnection, ControlPlaneContext, ControlPlaneManifest, ControlPlaneScope, Ed25519PublicJwk, HealthCountNominal, HealthNominal, HealthSummary, HealthSummaryKey, HealthSummaryValue, HealthValueCost, HealthValueKind, KEYS_ROTATE_SCOPE, MANIFEST_READ_SCOPE, ManifestConfigKey, ManifestConfigValue, ManifestConfigValues, RegisteredKey, SEAM_SCOPES, capabilityHealthSources, controlPlaneDatabase, controlplane, defineCapabilityHealth, defineManifestConfig, exportPublicJwk, healthAttention, healthReport, healthWire, isControlPlaneCapability, mintControlPlaneToken, missingAdminRoutes, namedConfigValues, namedHealthValues, readCapabilityHealth, requireControlPlane, standingOf, workerBuildChanged };
|
package/dist/kv/kv.d.ts
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import type { KVNamespace } from "@cloudflare/workers-types";
|
|
2
|
+
import type { z } from "zod";
|
|
3
|
+
import type { Logger } from "../logger/logger";
|
|
4
|
+
/** Cloudflare's hard limit on a KV entry's metadata, in bytes. */
|
|
5
|
+
export declare const KV_METADATA_MAX_BYTES = 1024;
|
|
6
|
+
/**
|
|
7
|
+
* Wrap a metadata schema with KV's size limit.
|
|
8
|
+
*
|
|
9
|
+
* WARNING: metadata travels with **every** `list` entry and is capped at
|
|
10
|
+
* {@link KV_METADATA_MAX_BYTES} bytes serialized. It is for small, list-time
|
|
11
|
+
* fields you want without reading each value — a status flag, a type, a
|
|
12
|
+
* timestamp — never a payload. This refinement fails a value that would exceed
|
|
13
|
+
* the cap, turning a late KV rejection into an early, clear validation error.
|
|
14
|
+
*/
|
|
15
|
+
export declare function kvMetadata<T extends z.ZodType>(schema: T): T;
|
|
16
|
+
/** Configuration for a {@link TypedKv} store. */
|
|
17
|
+
export interface TypedKvConfig<V extends z.ZodType, K extends z.ZodObject, M extends z.ZodType> {
|
|
18
|
+
/** Capability namespace, the fixed first key segment (e.g. `auth`, `assets`). */
|
|
19
|
+
prefix: string;
|
|
20
|
+
/**
|
|
21
|
+
* The ordered key segments after the prefix, as a Zod object. Declared field
|
|
22
|
+
* order **is** key order, and each segment is validated before a key is built
|
|
23
|
+
* (e.g. `z.object({ assetType: z.enum([...]), uuid: z.uuid() })` →
|
|
24
|
+
* `assets:photo:<uuid>`). Segment values must serialize to a string that does
|
|
25
|
+
* not contain the separator.
|
|
26
|
+
*/
|
|
27
|
+
key: K;
|
|
28
|
+
/** Schema validating the stored value on every read and write. */
|
|
29
|
+
value: V;
|
|
30
|
+
/** Optional schema for metadata. Wrap with {@link kvMetadata} to bound its size. */
|
|
31
|
+
metadata?: M;
|
|
32
|
+
/**
|
|
33
|
+
* Derive metadata from the value, making the value the single source of truth.
|
|
34
|
+
*
|
|
35
|
+
* When set (requires `metadata`), `put` computes metadata from the value
|
|
36
|
+
* automatically — callers need not pass it — and `list` **self-heals**: any
|
|
37
|
+
* entry whose metadata is missing has its value read, metadata re-derived, and
|
|
38
|
+
* written back (value bytes and expiration preserved). This protects against
|
|
39
|
+
* external edits — notably the Cloudflare dashboard, which drops metadata when
|
|
40
|
+
* a value is hand-edited. Note: self-heal performs a read and a write per
|
|
41
|
+
* missing entry during `list`.
|
|
42
|
+
*/
|
|
43
|
+
deriveMetadata?: (value: z.output<V>) => z.input<M>;
|
|
44
|
+
/** Key segment separator. Defaults to `:`. */
|
|
45
|
+
separator?: string;
|
|
46
|
+
/** Default TTL, in seconds, applied to every `put` unless overridden. KV's floor is 60. */
|
|
47
|
+
ttlSeconds?: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Validate a {@link TypedKvConfig} at construction — config is a boundary, so it
|
|
51
|
+
* is checked, not trusted. Catches the misconfigurations the type system can't
|
|
52
|
+
* (or won't, for JS callers and casts): an empty namespace, a separator that
|
|
53
|
+
* collides with the prefix, a key with no segments, `deriveMetadata` without a
|
|
54
|
+
* `metadata` schema to validate against, or a non-positive default TTL.
|
|
55
|
+
*/
|
|
56
|
+
export declare function assertValidConfig(config: TypedKvConfig<z.ZodType, z.ZodObject, z.ZodType>): void;
|
|
57
|
+
/** Construction options for a {@link TypedKv} store beyond its config. */
|
|
58
|
+
export interface TypedKvOptions {
|
|
59
|
+
/**
|
|
60
|
+
* The logger a store routes its observable best-effort failures through — notably the `list`
|
|
61
|
+
* self-heal metadata write-back, which must not fail the surrounding list but should be seen.
|
|
62
|
+
* `createBackend` passes the per-request `c.var.log`; defaults to the no-op logger.
|
|
63
|
+
*/
|
|
64
|
+
logger?: Logger;
|
|
65
|
+
}
|
|
66
|
+
/** Per-call options for {@link TypedKv.put}. */
|
|
67
|
+
export interface PutOptions<M extends z.ZodType> {
|
|
68
|
+
/** TTL, in seconds, for this value. Overrides the store default. KV's floor is 60. */
|
|
69
|
+
ttlSeconds?: number;
|
|
70
|
+
/** Metadata to store. Validated against the schema; overrides `deriveMetadata` for this write. */
|
|
71
|
+
metadata?: z.input<M>;
|
|
72
|
+
}
|
|
73
|
+
/** Options for {@link TypedKv.list}. */
|
|
74
|
+
export interface ListOptions<K extends z.ZodObject> {
|
|
75
|
+
/**
|
|
76
|
+
* A leading run of key segments to scope the listing — `{ assetType: "photo" }`
|
|
77
|
+
* lists `assets:photo:*`. Must be contiguous from the first segment; omit to
|
|
78
|
+
* list the whole namespace.
|
|
79
|
+
*/
|
|
80
|
+
prefix?: Partial<z.input<K>>;
|
|
81
|
+
/** Maximum entries to return in this page. */
|
|
82
|
+
limit?: number;
|
|
83
|
+
/** Cursor from a previous page's result. */
|
|
84
|
+
cursor?: string;
|
|
85
|
+
}
|
|
86
|
+
/** One entry from {@link TypedKv.list}: the key, its parsed segments, and validated metadata. */
|
|
87
|
+
export interface ListEntry<K extends z.ZodObject, M extends z.ZodType> {
|
|
88
|
+
/** The full physical KV key. */
|
|
89
|
+
name: string;
|
|
90
|
+
/** The key's segments, split back out by name. */
|
|
91
|
+
key: Record<keyof z.input<K>, string>;
|
|
92
|
+
/** Validated metadata, or `null` when none was stored or no metadata schema is configured. */
|
|
93
|
+
metadata: z.output<M> | null;
|
|
94
|
+
/** Absolute expiration time (seconds since epoch), if the entry has a TTL. */
|
|
95
|
+
expiration?: number;
|
|
96
|
+
}
|
|
97
|
+
/** A page of {@link TypedKv.list} results. */
|
|
98
|
+
export interface ListResult<K extends z.ZodObject, M extends z.ZodType> {
|
|
99
|
+
/** The entries on this page. */
|
|
100
|
+
keys: ListEntry<K, M>[];
|
|
101
|
+
/** Cursor for the next page, or `undefined` when the listing is complete. */
|
|
102
|
+
cursor?: string;
|
|
103
|
+
/** Whether this page completed the listing. */
|
|
104
|
+
listComplete: boolean;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Typed, validated access to one Workers KV namespace.
|
|
108
|
+
*
|
|
109
|
+
* Keys are structured: a fixed capability `prefix` followed by ordered,
|
|
110
|
+
* Zod-validated segments — so a single store models `pages:<uuid>` or
|
|
111
|
+
* `assets:<assetType>:<uuid>` and `list` can scope by any leading run of those
|
|
112
|
+
* segments. Values are validated on the way in and out; there is no untyped
|
|
113
|
+
* `JSON.parse`. Metadata is validated too and rides along with `list`; with
|
|
114
|
+
* `deriveMetadata` the value is the source of truth and `list` rebuilds metadata
|
|
115
|
+
* that external edits have dropped.
|
|
116
|
+
*/
|
|
117
|
+
export declare class TypedKv<V extends z.ZodType, K extends z.ZodObject, M extends z.ZodType = z.ZodNever> {
|
|
118
|
+
#private;
|
|
119
|
+
constructor(namespace: KVNamespace, config: TypedKvConfig<V, K, M>, options?: TypedKvOptions);
|
|
120
|
+
/** Build the full physical KV key (name) from validated segments. */
|
|
121
|
+
name(key: z.input<K>): string;
|
|
122
|
+
/**
|
|
123
|
+
* Read and validate the value at `key`. Returns `null` on a miss. The stored
|
|
124
|
+
* JSON is parsed and validated against the schema before it is returned.
|
|
125
|
+
*/
|
|
126
|
+
get(key: z.input<K>): Promise<z.output<V> | null>;
|
|
127
|
+
/** Read the value at `key` together with its validated metadata. `null` on a miss. */
|
|
128
|
+
getWithMetadata(key: z.input<K>): Promise<{
|
|
129
|
+
value: z.output<V>;
|
|
130
|
+
metadata: z.output<M> | null;
|
|
131
|
+
} | null>;
|
|
132
|
+
/**
|
|
133
|
+
* Validate `value` (and any `metadata`) against their schemas, then store the
|
|
134
|
+
* value as JSON under the namespaced key. With `deriveMetadata`, metadata is
|
|
135
|
+
* computed from the value unless overridden per call. Throws (before writing)
|
|
136
|
+
* on an invalid value, invalid metadata, or metadata over
|
|
137
|
+
* {@link KV_METADATA_MAX_BYTES}. A per-call `ttlSeconds` overrides the default.
|
|
138
|
+
*/
|
|
139
|
+
put(key: z.input<K>, value: z.input<V>, options?: PutOptions<M>): Promise<void>;
|
|
140
|
+
/**
|
|
141
|
+
* Partially update the value at `key`: read it, merge `changes` over the
|
|
142
|
+
* current fields, validate the merged result, and write it back. Returns the
|
|
143
|
+
* merged value. Throws if the key does not exist — there is nothing to merge.
|
|
144
|
+
*
|
|
145
|
+
* Metadata stays correct: a `deriveMetadata` store recomputes it from the
|
|
146
|
+
* merged value; an explicit-metadata store preserves the current metadata
|
|
147
|
+
* (pass `metadata` to override). TTL resets to the store default unless
|
|
148
|
+
* `ttlSeconds` is given.
|
|
149
|
+
*
|
|
150
|
+
* WARNING: KV has no compare-and-set, so this read-modify-write is
|
|
151
|
+
* last-write-wins. Concurrent patches to the same key can lose updates — do
|
|
152
|
+
* not use it where atomicity matters.
|
|
153
|
+
*/
|
|
154
|
+
patch(key: z.input<K>, changes: Partial<z.output<V>>, options?: PutOptions<M>): Promise<z.output<V>>;
|
|
155
|
+
/** Delete the value at `key`. A miss is a no-op. */
|
|
156
|
+
delete(key: z.input<K>): Promise<void>;
|
|
157
|
+
/**
|
|
158
|
+
* List entries under a leading run of key segments. Each entry carries its
|
|
159
|
+
* parsed key segments and validated metadata — no value reads, unless
|
|
160
|
+
* `deriveMetadata` is configured and an entry's metadata is missing, in which
|
|
161
|
+
* case it is rebuilt from the value and written back. Pass `options.prefix` to
|
|
162
|
+
* scope (e.g. `{ assetType: "photo" }`); omit to list the whole namespace.
|
|
163
|
+
*/
|
|
164
|
+
list(options?: ListOptions<K>): Promise<ListResult<K, M>>;
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=kv.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kv.d.ts","sourceRoot":"","sources":["../../src/kv/kv.ts"],"names":[],"mappings":"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"}
|