@pithy-sh/core 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/access/access.d.ts +172 -0
- package/dist/access/access.d.ts.map +1 -0
- package/dist/access/access.js +147 -0
- package/dist/access/acting.d.ts +49 -0
- package/dist/access/acting.d.ts.map +1 -0
- package/dist/access/acting.js +21 -0
- package/dist/access/policyCheck.d.ts +33 -0
- package/dist/access/policyCheck.d.ts.map +1 -0
- package/dist/access/policyCheck.js +48 -0
- package/dist/access/usage.d.ts +83 -0
- package/dist/access/usage.d.ts.map +1 -0
- package/dist/access/usage.js +104 -0
- package/dist/access/visibility.d.ts +66 -0
- package/dist/access/visibility.d.ts.map +1 -0
- package/dist/access/visibility.js +86 -0
- package/dist/audit/auditEvent.d.ts +5 -0
- package/dist/audit/auditEvent.d.ts.map +1 -1
- package/dist/audit/auditEvent.js +2 -0
- package/dist/capability/bindings.d.ts +47 -2
- package/dist/capability/bindings.d.ts.map +1 -1
- package/dist/capability/bindings.js +117 -7
- package/dist/capability/capability.d.ts +98 -28
- package/dist/capability/capability.d.ts.map +1 -1
- package/dist/capability/manifest.d.ts +2 -1
- package/dist/capability/manifest.d.ts.map +1 -1
- package/dist/capability/manifest.js +1 -1
- package/dist/capability/settings.d.ts +86 -2
- package/dist/capability/settings.d.ts.map +1 -1
- package/dist/capability/settings.js +80 -1
- package/dist/cli/commandCatalog.generated.d.ts +184 -22
- package/dist/cli/commandCatalog.generated.d.ts.map +1 -1
- package/dist/cli/commandCatalog.generated.js +196 -22
- package/dist/cli/commandFacts.d.ts +1 -1
- package/dist/cli/commandFacts.d.ts.map +1 -1
- package/dist/cli/commandFacts.js +1 -0
- package/dist/controlPlane/capability.d.ts.map +1 -1
- package/dist/controlPlane/capability.js +12 -2
- package/dist/controlPlane/context.d.ts +5 -0
- package/dist/controlPlane/context.d.ts.map +1 -1
- package/dist/controlPlane/context.js +3 -1
- package/dist/controlPlane/data/connection.d.ts +47 -0
- package/dist/controlPlane/data/connection.d.ts.map +1 -1
- package/dist/controlPlane/data/connection.js +55 -1
- package/dist/controlPlane/http/cors.d.ts +4 -4
- package/dist/controlPlane/http/cors.js +4 -4
- package/dist/controlPlane/http/guard.d.ts +11 -0
- package/dist/controlPlane/http/guard.d.ts.map +1 -1
- package/dist/controlPlane/http/guard.js +17 -1
- package/dist/controlPlane/http/handlers.d.ts +60 -0
- package/dist/controlPlane/http/handlers.d.ts.map +1 -1
- package/dist/controlPlane/http/handlers.js +31 -2
- package/dist/controlPlane/http/readiness.d.ts +33 -0
- package/dist/controlPlane/http/readiness.d.ts.map +1 -0
- package/dist/controlPlane/http/readiness.js +39 -0
- package/dist/controlPlane/http/responses.d.ts +147 -0
- package/dist/controlPlane/http/responses.d.ts.map +1 -1
- package/dist/controlPlane/http/responses.js +61 -4
- package/dist/controlPlane/http/routes.d.ts +1 -0
- package/dist/controlPlane/http/routes.d.ts.map +1 -1
- package/dist/controlPlane/http/routes.js +17 -3
- package/dist/controlPlane/http/verify.d.ts.map +1 -1
- package/dist/controlPlane/http/verify.js +2 -1
- package/dist/controlPlane/migrationState/migrationState.d.ts +102 -0
- package/dist/controlPlane/migrationState/migrationState.d.ts.map +1 -0
- package/dist/controlPlane/migrationState/migrationState.js +142 -0
- package/dist/controlPlane/migrations/0003_connection_principal.d.ts +21 -0
- package/dist/controlPlane/migrations/0003_connection_principal.d.ts.map +1 -0
- package/dist/controlPlane/migrations/0003_connection_principal.js +33 -0
- package/dist/controlPlane/scope/scope.d.ts +13 -2
- package/dist/controlPlane/scope/scope.d.ts.map +1 -1
- package/dist/controlPlane/scope/scope.js +14 -3
- package/dist/createBackend.d.ts.map +1 -1
- package/dist/createBackend.js +7 -2
- package/dist/createEntrypoint.d.ts.map +1 -1
- package/dist/createEntrypoint.js +5 -3
- package/dist/entitlement/allowance.d.ts +25 -0
- package/dist/entitlement/allowance.d.ts.map +1 -0
- package/dist/entitlement/allowance.js +80 -0
- package/dist/entitlement/entitlement.d.ts +41 -0
- package/dist/entitlement/entitlement.d.ts.map +1 -1
- package/dist/entitlement/meter.d.ts +57 -0
- package/dist/entitlement/meter.d.ts.map +1 -0
- package/dist/entitlement/meter.js +13 -0
- package/dist/error/http.d.ts +144 -0
- package/dist/error/http.d.ts.map +1 -1
- package/dist/error/payload.d.ts +288 -0
- package/dist/error/payload.d.ts.map +1 -1
- package/dist/error/payload.js +100 -4
- package/dist/http/authContext.d.ts +7 -0
- package/dist/http/authContext.d.ts.map +1 -1
- package/dist/http/authContext.js +8 -1
- package/dist/http/scopeGates.d.ts +20 -0
- package/dist/http/scopeGates.d.ts.map +1 -0
- package/dist/http/scopeGates.js +36 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/logger/record.d.ts +84 -0
- package/dist/logger/record.d.ts.map +1 -1
- package/dist/migrations/capabilitySets.d.ts +23 -0
- package/dist/migrations/capabilitySets.d.ts.map +1 -0
- package/dist/migrations/capabilitySets.js +74 -0
- package/dist/migrations/registry.d.ts +26 -0
- package/dist/migrations/registry.d.ts.map +1 -1
- package/dist/migrations/registry.js +38 -7
- package/dist/migrations/state.d.ts +60 -0
- package/dist/migrations/state.d.ts.map +1 -0
- package/dist/migrations/state.js +46 -0
- package/dist/naming/feature.d.ts +27 -5
- package/dist/naming/feature.d.ts.map +1 -1
- package/dist/naming/feature.js +36 -6
- package/dist/naming/limits.d.ts +47 -3
- package/dist/naming/limits.d.ts.map +1 -1
- package/dist/naming/limits.js +47 -3
- package/dist/naming/provisionScope.d.ts +6 -0
- package/dist/naming/provisionScope.d.ts.map +1 -1
- package/dist/naming/provisionScope.js +8 -3
- package/dist/naming/resourceNames.d.ts +21 -2
- package/dist/naming/resourceNames.d.ts.map +1 -1
- package/dist/naming/resourceNames.js +21 -3
- package/dist/seed/writeD1.d.ts +7 -1
- package/dist/seed/writeD1.d.ts.map +1 -1
- package/dist/seed/writeD1.js +9 -3
- package/dist/seed/writeKv.d.ts +2 -0
- package/dist/seed/writeKv.d.ts.map +1 -1
- package/dist/seed/writeKv.js +6 -2
- package/dist/version.generated.d.ts +1 -1
- package/dist/version.generated.js +1 -1
- package/dist/worker/serviceLoopback.d.ts +36 -0
- package/dist/worker/serviceLoopback.d.ts.map +1 -0
- package/dist/worker/serviceLoopback.js +74 -0
- package/dist/workflow/faults.d.ts +12 -1
- package/dist/workflow/faults.d.ts.map +1 -1
- package/dist/workflow/faults.js +22 -15
- package/package.json +2 -2
- package/src/access/access.ts +298 -0
- package/src/access/acting.ts +59 -0
- package/src/access/policyCheck.ts +77 -0
- package/src/access/usage.ts +141 -0
- package/src/access/visibility.ts +109 -0
- package/src/audit/auditEvent.ts +4 -0
- package/src/capability/bindings.ts +159 -13
- package/src/capability/capability.ts +99 -29
- package/src/capability/settings.ts +146 -2
- package/src/cli/commandCatalog.generated.ts +212 -22
- package/src/cli/commandFacts.ts +1 -0
- package/src/controlPlane/capability.ts +25 -1
- package/src/controlPlane/context.ts +4 -0
- package/src/controlPlane/data/connection.ts +90 -0
- package/src/controlPlane/http/cors.ts +4 -4
- package/src/controlPlane/http/guard.ts +21 -0
- package/src/controlPlane/http/handlers.ts +41 -0
- package/src/controlPlane/http/readiness.ts +50 -0
- package/src/controlPlane/http/responses.ts +140 -2
- package/src/controlPlane/http/routes.ts +25 -1
- package/src/controlPlane/http/verify.ts +2 -0
- package/src/controlPlane/migrationState/migrationState.ts +200 -0
- package/src/controlPlane/migrations/0003_connection_principal.ts +37 -0
- package/src/controlPlane/scope/scope.ts +14 -2
- package/src/createBackend.ts +24 -6
- package/src/createEntrypoint.ts +9 -3
- package/src/entitlement/allowance.ts +85 -0
- package/src/entitlement/entitlement.ts +38 -0
- package/src/entitlement/meter.ts +69 -0
- package/src/error/payload.ts +211 -4
- package/src/http/authContext.ts +13 -1
- package/src/http/scopeGates.ts +34 -0
- package/src/index.ts +1 -0
- package/src/migrations/capabilitySets.ts +87 -0
- package/src/migrations/registry.ts +46 -2
- package/src/migrations/state.ts +94 -0
- package/src/naming/feature.ts +46 -7
- package/src/naming/limits.ts +35 -3
- package/src/naming/provisionScope.ts +19 -1
- package/src/naming/resourceNames.ts +52 -5
- package/src/seed/writeD1.ts +13 -4
- package/src/seed/writeKv.ts +6 -2
- package/src/version.generated.ts +1 -1
- package/src/worker/serviceLoopback.ts +105 -0
- package/src/workflow/faults.ts +51 -24
package/dist/error/payload.js
CHANGED
|
@@ -242,6 +242,16 @@ const TurnstileConfigPublic = z.object({
|
|
|
242
242
|
status: z.literal(500).describe("Internal Server Error — a configuration fault, not a client request."),
|
|
243
243
|
...publicFields
|
|
244
244
|
}).describe("The Turnstile middleware is misconfigured (500).");
|
|
245
|
+
const TurnstileAnalyticsWindowPublic = z.object({
|
|
246
|
+
code: z.literal("turnstile/analytics_window").describe("The requested challenge window reaches past what Cloudflare keeps, or is wider than one read may ask for."),
|
|
247
|
+
status: z.literal(400).describe("Bad Request — narrow the window or move it later."),
|
|
248
|
+
...publicFields
|
|
249
|
+
}).describe("A Turnstile-analytics window outside Cloudflare's retention or range (400).");
|
|
250
|
+
const TurnstileAnalyticsUnavailablePublic = z.object({
|
|
251
|
+
code: z.literal("turnstile/analytics_unavailable").describe("Cloudflare does not serve Turnstile analytics to this account, so no outcome can be read."),
|
|
252
|
+
status: z.literal(409).describe("Conflict — the account's configuration rules the read out."),
|
|
253
|
+
...publicFields
|
|
254
|
+
}).describe("Turnstile analytics are not served to this account (409).");
|
|
245
255
|
const AuditInvalidEventPublic = z.object({
|
|
246
256
|
code: z.literal("audit/invalid_event").describe("An audit event failed validation against the AuditEvent schema (bad action, outcome, or actor)."),
|
|
247
257
|
status: z.literal(400).describe("Bad Request — the event did not match its schema."),
|
|
@@ -257,6 +267,11 @@ const MediaNotFoundPublic = z.object({
|
|
|
257
267
|
status: z.literal(404).describe("Not Found."),
|
|
258
268
|
...publicFields
|
|
259
269
|
}).describe("A requested media record does not exist (404).");
|
|
270
|
+
const MediaForbiddenPublic = z.object({
|
|
271
|
+
code: z.literal("media/forbidden").describe("The caller may read the media record but not change it: only its owner, acting for the record's organization, or a role holding `media:manage` there may edit, delete or re-scope it."),
|
|
272
|
+
status: z.literal(403).describe("Forbidden."),
|
|
273
|
+
...publicFields
|
|
274
|
+
}).describe("The caller may read the record but not change it (403).");
|
|
260
275
|
const MediaUnsupportedPublic = z.object({
|
|
261
276
|
code: z.literal("media/unsupported").describe("The media type, extension, or backend is not supported for the requested operation."),
|
|
262
277
|
status: z.literal(400).describe("Bad Request — the operation does not apply to this media."),
|
|
@@ -272,6 +287,16 @@ const MediaEnrichmentFailedPublic = z.object({
|
|
|
272
287
|
status: z.literal(500).describe("Internal Server Error — an enrichment step could not complete."),
|
|
273
288
|
...publicFields
|
|
274
289
|
}).describe("A media AI-enrichment step failed (500).");
|
|
290
|
+
const MediaAnalyticsWindowPublic = z.object({
|
|
291
|
+
code: z.literal("media/analytics_window").describe("The requested delivery window reaches past what Cloudflare keeps, or is wider than one read may ask for."),
|
|
292
|
+
status: z.literal(400).describe("Bad Request — narrow the window or move it later."),
|
|
293
|
+
...publicFields
|
|
294
|
+
}).describe("A delivery-analytics window outside Cloudflare's retention or range (400).");
|
|
295
|
+
const MediaAnalyticsUnavailablePublic = z.object({
|
|
296
|
+
code: z.literal("media/analytics_unavailable").describe("Cloudflare does not serve the delivery analytics this read needs to this account — a Customer Metadata Boundary outside the US carries none of them."),
|
|
297
|
+
status: z.literal(409).describe("Conflict — the account's configuration rules the read out."),
|
|
298
|
+
...publicFields
|
|
299
|
+
}).describe("Delivery analytics are not served to this account (409).");
|
|
275
300
|
const LeaderboardBoardNotFoundPublic = z.object({
|
|
276
301
|
code: z.literal("leaderboard/board_not_found").describe("No board with that key is configured. Board keys come from `pithy.config.ts`, not from the database."),
|
|
277
302
|
status: z.literal(404).describe("Not Found."),
|
|
@@ -438,17 +463,17 @@ const MatchmakingNotQueuedPublic = z.object({
|
|
|
438
463
|
...publicFields
|
|
439
464
|
}).describe("The player is not in the queue (404).");
|
|
440
465
|
const StorageNotFoundPublic = z.object({
|
|
441
|
-
code: z.literal("storage/not_found").describe("No object row matches, or the object exists but
|
|
466
|
+
code: z.literal("storage/not_found").describe("No object row matches, or the object exists but this caller may not read it."),
|
|
442
467
|
status: z.literal(404).describe("Not Found."),
|
|
443
468
|
...publicFields
|
|
444
469
|
}).describe("The object does not exist, or is not visible to the caller (404).");
|
|
445
470
|
const StorageForbiddenPublic = z.object({
|
|
446
|
-
code: z.literal("storage/forbidden").describe("The caller
|
|
471
|
+
code: z.literal("storage/forbidden").describe("The caller may read the object but not change it: only its owner, acting for the object's organization, or a role holding `storage:manage` there may."),
|
|
447
472
|
status: z.literal(403).describe("Forbidden."),
|
|
448
473
|
...publicFields
|
|
449
|
-
}).describe("The caller
|
|
474
|
+
}).describe("The caller may read the object but not change it (403).");
|
|
450
475
|
const StorageQuotaExceededPublic = z.object({
|
|
451
|
-
code: z.literal("storage/quota_exceeded").describe("The declared upload size would push the owner past
|
|
476
|
+
code: z.literal("storage/quota_exceeded").describe("The declared upload size would push the owner past the configured `bytesPerOwner` quota. Checked at init against pending and stored rows together, so concurrent inits cannot race past the limit. Where the `storageBytes` meter is enforced, the same refusal is `payments/quota_exceeded` (402)."),
|
|
452
477
|
status: z.literal(413).describe("Content Too Large."),
|
|
453
478
|
...publicFields
|
|
454
479
|
}).describe("The upload would exceed the owner's byte quota (413).");
|
|
@@ -582,6 +607,16 @@ const PaymentsSubscriptionChangeRefusedPublic = z.object({
|
|
|
582
607
|
status: z.literal(409).describe("Conflict — the subscription's present state forbids the change asked of it."),
|
|
583
608
|
...publicFields
|
|
584
609
|
}).describe("A subscription's state forbids the change asked of it (409).");
|
|
610
|
+
const PaymentsOverrideStalePublic = z.object({
|
|
611
|
+
code: z.literal("payments/override_stale").describe("A control-plane override write named a version behind the subject's override row. Two operators share one customer: both opened the same allowance, and the second would silently overwrite the first while the first believed they had succeeded. So the write is refused and nothing is written. 409, because the request is well-formed and the same request against the version it now holds would be accepted — the caller re-reads, and tries again."),
|
|
612
|
+
status: z.literal(409).describe("Conflict — the override changed since the caller read it."),
|
|
613
|
+
...publicFields
|
|
614
|
+
}).describe("An override write named a stale version (409).");
|
|
615
|
+
const PaymentsQuotaExceededPublic = z.object({
|
|
616
|
+
code: z.literal("payments/quota_exceeded").describe("An enforced kit meter — emails enqueued, bytes stored, media items held — would pass the subject's effective quota for the period. Nothing was written. 402 Payment Required, because it is the honest status: the plan does not allow more and the remedy is a purchase, a bigger tier, or a number pinned for this subject from the control plane. A meter refuses and never bills — the kit does not sell overage."),
|
|
617
|
+
status: z.literal(402).describe("Payment Required — the plan's allowance for this period is used up."),
|
|
618
|
+
...publicFields
|
|
619
|
+
}).describe("An enforced meter is at its quota for this period (402).");
|
|
585
620
|
const ControlPlaneNotConnectedPublic = z.object({
|
|
586
621
|
code: z.literal("controlplane/not_connected").describe("No management-client connection is registered for this environment. The shipped default: the seam is present and denies everything until the adopter provisions a credential. There is no backdoor."),
|
|
587
622
|
status: z.literal(403).describe("Forbidden."),
|
|
@@ -642,6 +677,31 @@ const OrganizationNominationInvalidPublic = z.object({
|
|
|
642
677
|
status: z.literal(400).describe("Bad Request — no offer this caller may accept."),
|
|
643
678
|
...publicFields
|
|
644
679
|
}).describe("No standing ownership offer this caller may accept (400).");
|
|
680
|
+
const ArtifactsNotFoundPublic = z.object({
|
|
681
|
+
code: z.literal("artifacts/not_found").describe("No such repository, **or** one the caller holds no grant on and does not own. One code for both, byte for byte: a repository's name is in its clone URL, and a refusal that told the two apart would hand it over. Also what the credential route answers for a repository with remote access off. Which it was survives in `detail`, which the HTTP codec strips."),
|
|
682
|
+
status: z.literal(404).describe("Not Found."),
|
|
683
|
+
...publicFields
|
|
684
|
+
}).describe("No such repository, or none this caller may see — the same answer for both (404).");
|
|
685
|
+
const ArtifactsForbiddenPublic = z.object({
|
|
686
|
+
code: z.literal("artifacts/forbidden").describe("The caller can see the repository and may not do this to it: a grant holder asking for what only an owner may do, or a member of an organization whose role lacks the configured `managePower`. A 403 rather than the 404 above, because by then the caller already knows the repository exists."),
|
|
687
|
+
status: z.literal(403).describe("Forbidden."),
|
|
688
|
+
...publicFields
|
|
689
|
+
}).describe("The caller may see this repository and may not do this (403).");
|
|
690
|
+
const ArtifactsInvalidNamePublic = z.object({
|
|
691
|
+
code: z.literal("artifacts/invalid_name").describe("A supplied repository name is outside Cloudflare's charset or the 2-to-63 cap. Refused and never shortened: a name somebody chose is in every clone URL, and a silently different one is a repository nobody can find."),
|
|
692
|
+
status: z.literal(400).describe("Bad Request."),
|
|
693
|
+
...publicFields
|
|
694
|
+
}).describe("A repository name breaks the naming rule (400).");
|
|
695
|
+
const ArtifactsNameTakenPublic = z.object({
|
|
696
|
+
code: z.literal("artifacts/name_taken").describe("The owner already holds a repository with that display name, or a supplied physical name is already in the namespace. The second happens only where the adopter supplies names, so uniqueness is theirs."),
|
|
697
|
+
status: z.literal(409).describe("Conflict."),
|
|
698
|
+
...publicFields
|
|
699
|
+
}).describe("That repository name is already in use (409).");
|
|
700
|
+
const ArtifactsInvalidConfigPublic = z.object({
|
|
701
|
+
code: z.literal("artifacts/invalid_config").describe("The capability's configuration cannot be honored: a `tokenTtlSeconds` above the ceiling, or `organization` composed with no `managePower` named. Raised at boot, so a mistake fails on deploy rather than at the first mint."),
|
|
702
|
+
status: z.literal(400).describe("Bad Request — the configuration is malformed."),
|
|
703
|
+
...publicFields
|
|
704
|
+
}).describe("The artifacts configuration is invalid (400).");
|
|
645
705
|
const SupportNotFoundPublic = z.object({
|
|
646
706
|
code: z.literal("support/not_found").describe("A requested support thread, message, or attachment does not exist."),
|
|
647
707
|
status: z.literal(404).describe("Not Found."),
|
|
@@ -766,12 +826,17 @@ const KitPublicErrorPayload = z.discriminatedUnion("code", [
|
|
|
766
826
|
TurnstileMissingTokenPublic,
|
|
767
827
|
TurnstileFailedPublic,
|
|
768
828
|
TurnstileConfigPublic,
|
|
829
|
+
TurnstileAnalyticsWindowPublic,
|
|
830
|
+
TurnstileAnalyticsUnavailablePublic,
|
|
769
831
|
AuditInvalidEventPublic,
|
|
770
832
|
AuditWriteFailedPublic,
|
|
771
833
|
MediaNotFoundPublic,
|
|
834
|
+
MediaForbiddenPublic,
|
|
772
835
|
MediaUnsupportedPublic,
|
|
773
836
|
MediaStorageFailedPublic,
|
|
774
837
|
MediaEnrichmentFailedPublic,
|
|
838
|
+
MediaAnalyticsWindowPublic,
|
|
839
|
+
MediaAnalyticsUnavailablePublic,
|
|
775
840
|
LeaderboardBoardNotFoundPublic,
|
|
776
841
|
LeaderboardEntryNotFoundPublic,
|
|
777
842
|
LeaderboardScoreRejectedPublic,
|
|
@@ -834,6 +899,8 @@ const KitPublicErrorPayload = z.discriminatedUnion("code", [
|
|
|
834
899
|
PaymentsEntitlementNotInCatalogPublic,
|
|
835
900
|
PaymentsSubjectUnresolvedPublic,
|
|
836
901
|
PaymentsSubscriptionChangeRefusedPublic,
|
|
902
|
+
PaymentsOverrideStalePublic,
|
|
903
|
+
PaymentsQuotaExceededPublic,
|
|
837
904
|
ControlPlaneNotConnectedPublic,
|
|
838
905
|
ControlPlaneInvalidCredentialPublic,
|
|
839
906
|
ControlPlaneInsufficientScopePublic,
|
|
@@ -846,6 +913,11 @@ const KitPublicErrorPayload = z.discriminatedUnion("code", [
|
|
|
846
913
|
OrganizationLastAdministratorPublic,
|
|
847
914
|
OrganizationSlugTakenPublic,
|
|
848
915
|
OrganizationNominationInvalidPublic,
|
|
916
|
+
ArtifactsNotFoundPublic,
|
|
917
|
+
ArtifactsForbiddenPublic,
|
|
918
|
+
ArtifactsInvalidNamePublic,
|
|
919
|
+
ArtifactsNameTakenPublic,
|
|
920
|
+
ArtifactsInvalidConfigPublic,
|
|
849
921
|
SupportNotFoundPublic,
|
|
850
922
|
SupportInvalidCategoryPublic,
|
|
851
923
|
SupportUnparseableMessagePublic,
|
|
@@ -900,12 +972,17 @@ const EmailSendFailed = EmailSendFailedPublic.extend(internalFields).describe(Em
|
|
|
900
972
|
const TurnstileMissingToken = TurnstileMissingTokenPublic.extend(internalFields).describe(TurnstileMissingTokenPublic.description ?? "");
|
|
901
973
|
const TurnstileFailed = TurnstileFailedPublic.extend(internalFields).describe(TurnstileFailedPublic.description ?? "");
|
|
902
974
|
const TurnstileConfig = TurnstileConfigPublic.extend(internalFields).describe(TurnstileConfigPublic.description ?? "");
|
|
975
|
+
const TurnstileAnalyticsWindow = TurnstileAnalyticsWindowPublic.extend(internalFields).describe(TurnstileAnalyticsWindowPublic.description ?? "");
|
|
976
|
+
const TurnstileAnalyticsUnavailable = TurnstileAnalyticsUnavailablePublic.extend(internalFields).describe(TurnstileAnalyticsUnavailablePublic.description ?? "");
|
|
903
977
|
const AuditInvalidEvent = AuditInvalidEventPublic.extend(internalFields).describe(AuditInvalidEventPublic.description ?? "");
|
|
904
978
|
const AuditWriteFailed = AuditWriteFailedPublic.extend(internalFields).describe(AuditWriteFailedPublic.description ?? "");
|
|
905
979
|
const MediaNotFound = MediaNotFoundPublic.extend(internalFields).describe(MediaNotFoundPublic.description ?? "");
|
|
980
|
+
const MediaForbidden = MediaForbiddenPublic.extend(internalFields).describe(MediaForbiddenPublic.description ?? "");
|
|
906
981
|
const MediaUnsupported = MediaUnsupportedPublic.extend(internalFields).describe(MediaUnsupportedPublic.description ?? "");
|
|
907
982
|
const MediaStorageFailed = MediaStorageFailedPublic.extend(internalFields).describe(MediaStorageFailedPublic.description ?? "");
|
|
908
983
|
const MediaEnrichmentFailed = MediaEnrichmentFailedPublic.extend(internalFields).describe(MediaEnrichmentFailedPublic.description ?? "");
|
|
984
|
+
const MediaAnalyticsWindow = MediaAnalyticsWindowPublic.extend(internalFields).describe(MediaAnalyticsWindowPublic.description ?? "");
|
|
985
|
+
const MediaAnalyticsUnavailable = MediaAnalyticsUnavailablePublic.extend(internalFields).describe(MediaAnalyticsUnavailablePublic.description ?? "");
|
|
909
986
|
const LeaderboardBoardNotFound = LeaderboardBoardNotFoundPublic.extend(internalFields).describe(LeaderboardBoardNotFoundPublic.description ?? "");
|
|
910
987
|
const LeaderboardEntryNotFound = LeaderboardEntryNotFoundPublic.extend(internalFields).describe(LeaderboardEntryNotFoundPublic.description ?? "");
|
|
911
988
|
const LeaderboardScoreRejected = LeaderboardScoreRejectedPublic.extend(internalFields).describe(LeaderboardScoreRejectedPublic.description ?? "");
|
|
@@ -968,6 +1045,8 @@ const PaymentsDiscountInvalid = PaymentsDiscountInvalidPublic.extend(internalFie
|
|
|
968
1045
|
const PaymentsEntitlementNotInCatalog = PaymentsEntitlementNotInCatalogPublic.extend(internalFields).describe(PaymentsEntitlementNotInCatalogPublic.description ?? "");
|
|
969
1046
|
const PaymentsSubjectUnresolved = PaymentsSubjectUnresolvedPublic.extend(internalFields).describe(PaymentsSubjectUnresolvedPublic.description ?? "");
|
|
970
1047
|
const PaymentsSubscriptionChangeRefused = PaymentsSubscriptionChangeRefusedPublic.extend(internalFields).describe(PaymentsSubscriptionChangeRefusedPublic.description ?? "");
|
|
1048
|
+
const PaymentsOverrideStale = PaymentsOverrideStalePublic.extend(internalFields).describe(PaymentsOverrideStalePublic.description ?? "");
|
|
1049
|
+
const PaymentsQuotaExceeded = PaymentsQuotaExceededPublic.extend(internalFields).describe(PaymentsQuotaExceededPublic.description ?? "");
|
|
971
1050
|
const ControlPlaneNotConnected = ControlPlaneNotConnectedPublic.extend(internalFields).describe(ControlPlaneNotConnectedPublic.description ?? "");
|
|
972
1051
|
const ControlPlaneInvalidCredential = ControlPlaneInvalidCredentialPublic.extend(internalFields).describe(ControlPlaneInvalidCredentialPublic.description ?? "");
|
|
973
1052
|
const ControlPlaneInsufficientScope = ControlPlaneInsufficientScopePublic.extend(internalFields).describe(ControlPlaneInsufficientScopePublic.description ?? "");
|
|
@@ -990,6 +1069,11 @@ const OrganizationInvitationInvalid = OrganizationInvitationInvalidPublic.extend
|
|
|
990
1069
|
const OrganizationLastAdministrator = OrganizationLastAdministratorPublic.extend(internalFields).describe(OrganizationLastAdministratorPublic.description ?? "");
|
|
991
1070
|
const OrganizationSlugTaken = OrganizationSlugTakenPublic.extend(internalFields).describe(OrganizationSlugTakenPublic.description ?? "");
|
|
992
1071
|
const OrganizationNominationInvalid = OrganizationNominationInvalidPublic.extend(internalFields).describe(OrganizationNominationInvalidPublic.description ?? "");
|
|
1072
|
+
const ArtifactsNotFound = ArtifactsNotFoundPublic.extend(internalFields).describe(ArtifactsNotFoundPublic.description ?? "");
|
|
1073
|
+
const ArtifactsForbidden = ArtifactsForbiddenPublic.extend(internalFields).describe(ArtifactsForbiddenPublic.description ?? "");
|
|
1074
|
+
const ArtifactsInvalidName = ArtifactsInvalidNamePublic.extend(internalFields).describe(ArtifactsInvalidNamePublic.description ?? "");
|
|
1075
|
+
const ArtifactsNameTaken = ArtifactsNameTakenPublic.extend(internalFields).describe(ArtifactsNameTakenPublic.description ?? "");
|
|
1076
|
+
const ArtifactsInvalidConfig = ArtifactsInvalidConfigPublic.extend(internalFields).describe(ArtifactsInvalidConfigPublic.description ?? "");
|
|
993
1077
|
const SupportNotFound = SupportNotFoundPublic.extend(internalFields).describe(SupportNotFoundPublic.description ?? "");
|
|
994
1078
|
const SupportInvalidCategory = SupportInvalidCategoryPublic.extend(internalFields).describe(SupportInvalidCategoryPublic.description ?? "");
|
|
995
1079
|
const SupportUnparseableMessage = SupportUnparseableMessagePublic.extend(internalFields).describe(SupportUnparseableMessagePublic.description ?? "");
|
|
@@ -1039,12 +1123,17 @@ const KitErrorPayload = z.discriminatedUnion("code", [
|
|
|
1039
1123
|
TurnstileMissingToken,
|
|
1040
1124
|
TurnstileFailed,
|
|
1041
1125
|
TurnstileConfig,
|
|
1126
|
+
TurnstileAnalyticsWindow,
|
|
1127
|
+
TurnstileAnalyticsUnavailable,
|
|
1042
1128
|
AuditInvalidEvent,
|
|
1043
1129
|
AuditWriteFailed,
|
|
1044
1130
|
MediaNotFound,
|
|
1131
|
+
MediaForbidden,
|
|
1045
1132
|
MediaUnsupported,
|
|
1046
1133
|
MediaStorageFailed,
|
|
1047
1134
|
MediaEnrichmentFailed,
|
|
1135
|
+
MediaAnalyticsWindow,
|
|
1136
|
+
MediaAnalyticsUnavailable,
|
|
1048
1137
|
LeaderboardBoardNotFound,
|
|
1049
1138
|
LeaderboardEntryNotFound,
|
|
1050
1139
|
LeaderboardScoreRejected,
|
|
@@ -1107,6 +1196,8 @@ const KitErrorPayload = z.discriminatedUnion("code", [
|
|
|
1107
1196
|
PaymentsEntitlementNotInCatalog,
|
|
1108
1197
|
PaymentsSubjectUnresolved,
|
|
1109
1198
|
PaymentsSubscriptionChangeRefused,
|
|
1199
|
+
PaymentsOverrideStale,
|
|
1200
|
+
PaymentsQuotaExceeded,
|
|
1110
1201
|
ControlPlaneNotConnected,
|
|
1111
1202
|
ControlPlaneInvalidCredential,
|
|
1112
1203
|
ControlPlaneInsufficientScope,
|
|
@@ -1119,6 +1210,11 @@ const KitErrorPayload = z.discriminatedUnion("code", [
|
|
|
1119
1210
|
OrganizationLastAdministrator,
|
|
1120
1211
|
OrganizationSlugTaken,
|
|
1121
1212
|
OrganizationNominationInvalid,
|
|
1213
|
+
ArtifactsNotFound,
|
|
1214
|
+
ArtifactsForbidden,
|
|
1215
|
+
ArtifactsInvalidName,
|
|
1216
|
+
ArtifactsNameTaken,
|
|
1217
|
+
ArtifactsInvalidConfig,
|
|
1122
1218
|
SupportNotFound,
|
|
1123
1219
|
SupportInvalidCategory,
|
|
1124
1220
|
SupportUnparseableMessage,
|
|
@@ -12,6 +12,13 @@ import { z } from "zod";
|
|
|
12
12
|
* stored choice outrank their device's `Accept-Language`. That link read `c.var.locale` at first,
|
|
13
13
|
* which nothing ever wrote, so it silently contributed nothing and the chain degraded to
|
|
14
14
|
* `param → cookie → header → default` while the docs said otherwise.
|
|
15
|
+
*
|
|
16
|
+
* **`scopes` answers one question: did this request come from the adopter's own trusted backend, or from a
|
|
17
|
+
* device?** The name reads like a grant to the user, and it is not one. Tenancy roles went to `c.var.acting`
|
|
18
|
+
* with `@pithy-sh/organization`; management access is the control plane's, with its own credential and its
|
|
19
|
+
* own scope type. What is left is an attestation about the caller, which `@pithy-sh/auth`'s `resolveScopes`
|
|
20
|
+
* makes on every request from something the request proves — a service binding, a verified client
|
|
21
|
+
* certificate, a short-lived token bound to this origin — and never from anything it merely says (#560).
|
|
15
22
|
*/
|
|
16
23
|
export declare const AuthContext: z.ZodObject<{
|
|
17
24
|
userId: z.ZodString;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authContext.d.ts","sourceRoot":"","sources":["../../src/http/authContext.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB
|
|
1
|
+
{"version":3,"file":"authContext.d.ts","sourceRoot":"","sources":["../../src/http/authContext.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,WAAW;;;;;;iBAoBiE,CAAC;AAC1F,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC"}
|
package/dist/http/authContext.js
CHANGED
|
@@ -14,11 +14,18 @@ import { z } from "zod";
|
|
|
14
14
|
* stored choice outrank their device's `Accept-Language`. That link read `c.var.locale` at first,
|
|
15
15
|
* which nothing ever wrote, so it silently contributed nothing and the chain degraded to
|
|
16
16
|
* `param → cookie → header → default` while the docs said otherwise.
|
|
17
|
+
*
|
|
18
|
+
* **`scopes` answers one question: did this request come from the adopter's own trusted backend, or from a
|
|
19
|
+
* device?** The name reads like a grant to the user, and it is not one. Tenancy roles went to `c.var.acting`
|
|
20
|
+
* with `@pithy-sh/organization`; management access is the control plane's, with its own credential and its
|
|
21
|
+
* own scope type. What is left is an attestation about the caller, which `@pithy-sh/auth`'s `resolveScopes`
|
|
22
|
+
* makes on every request from something the request proves — a service binding, a verified client
|
|
23
|
+
* certificate, a short-lived token bound to this origin — and never from anything it merely says (#560).
|
|
17
24
|
*/
|
|
18
25
|
const AuthContext = z.object({
|
|
19
26
|
userId: z.string().describe("ID of the authenticated user (populated by @pithy-sh/auth)."),
|
|
20
27
|
sessionId: z.string().describe("ID of the active session this request belongs to."),
|
|
21
|
-
scopes: z.array(z.string()).default([]).describe("
|
|
28
|
+
scopes: z.array(z.string()).default([]).describe("Attestations about the caller, not permissions granted to the user: what this request's caller was established to be — the adopter's own trusted backend, say — by the `resolveScopes` seam on `@pithy-sh/auth`, resolved per request and never cached. Empty when no resolver is configured. Tenancy roles are not here; they are `c.var.acting`."),
|
|
22
29
|
locale: Locale.nullish().describe("The reader's own stored language, from `pithy_auth_users.locale`; null or absent when they have never chosen."),
|
|
23
30
|
authenticatedAt: z.date().nullish().describe("When the holder of this session last actually authenticated — a sign-in, never a rotation, which carries the value forward unchanged. It rides here for the same reason `locale` does: the session lookup has already loaded the row, so a gate that needs it should not pay for a second read. Distinct from the session's own `createdAt`, which `/token/rotate` stamps fresh and is therefore resettable by anyone holding a stolen refresh token. Null or absent for a session written before the column existed, and for a Worker whose auth capability predates it.")
|
|
24
31
|
}).describe("Per-request authenticated identity; the seam other capabilities depend on.");
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 Pithy
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
import { Hono } from "hono";
|
|
4
|
+
import type { PithyHonoEnv, ScopeGate } from "../capability/capability";
|
|
5
|
+
/**
|
|
6
|
+
* **A capability's scope gates, read off its own routes rather than listed beside them (#560).**
|
|
7
|
+
*
|
|
8
|
+
* `Capability.scopeGates` is what `pithy doctor` names when nothing composed fills `AuthContext.scopes`.
|
|
9
|
+
* A list written out by hand next to the routes is a second copy of something the routes already say: every
|
|
10
|
+
* gated route carries `describeRoute({ scopes })`, because that is how the OpenAPI contract learns it. So the
|
|
11
|
+
* registrar is run against a throwaway app and the specs are read back — the same walk `openApiDocument`
|
|
12
|
+
* makes over a composed app, and a route whose scope changes changes what this returns with it.
|
|
13
|
+
*
|
|
14
|
+
* **Only `bearer` and `session` routes.** Those are the strategies `requireAuth()` takes, so a scope on one
|
|
15
|
+
* is an `AuthContext` scope. A `control-plane` route also names scopes, and they are a different credential
|
|
16
|
+
* entirely — a signed management token with its own type, never `c.var.auth` — so naming one here would tell
|
|
17
|
+
* an adopter to configure a resolver that could never open it.
|
|
18
|
+
*/
|
|
19
|
+
export declare function scopeGatesOf(register: (app: Hono<PithyHonoEnv>) => void): ScopeGate[];
|
|
20
|
+
//# sourceMappingURL=scopeGates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scopeGates.d.ts","sourceRoot":"","sources":["../../src/http/scopeGates.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAGxE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,YAAY,CAAC,KAAK,IAAI,GAAG,SAAS,EAAE,CAYrF"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 Pithy
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
import { routeSpecOf } from "./routeSpec.js";
|
|
4
|
+
import { Hono } from "hono";
|
|
5
|
+
//#region src/http/scopeGates.ts
|
|
6
|
+
/**
|
|
7
|
+
* **A capability's scope gates, read off its own routes rather than listed beside them (#560).**
|
|
8
|
+
*
|
|
9
|
+
* `Capability.scopeGates` is what `pithy doctor` names when nothing composed fills `AuthContext.scopes`.
|
|
10
|
+
* A list written out by hand next to the routes is a second copy of something the routes already say: every
|
|
11
|
+
* gated route carries `describeRoute({ scopes })`, because that is how the OpenAPI contract learns it. So the
|
|
12
|
+
* registrar is run against a throwaway app and the specs are read back — the same walk `openApiDocument`
|
|
13
|
+
* makes over a composed app, and a route whose scope changes changes what this returns with it.
|
|
14
|
+
*
|
|
15
|
+
* **Only `bearer` and `session` routes.** Those are the strategies `requireAuth()` takes, so a scope on one
|
|
16
|
+
* is an `AuthContext` scope. A `control-plane` route also names scopes, and they are a different credential
|
|
17
|
+
* entirely — a signed management token with its own type, never `c.var.auth` — so naming one here would tell
|
|
18
|
+
* an adopter to configure a resolver that could never open it.
|
|
19
|
+
*/
|
|
20
|
+
function scopeGatesOf(register) {
|
|
21
|
+
const app = new Hono();
|
|
22
|
+
register(app);
|
|
23
|
+
const gates = [];
|
|
24
|
+
for (const route of app.routes) {
|
|
25
|
+
const spec = routeSpecOf(route.handler);
|
|
26
|
+
if (!spec?.scopes || spec.scopes.length === 0) continue;
|
|
27
|
+
if (![spec.verification].flat().some((strategy) => strategy === "bearer" || strategy === "session")) continue;
|
|
28
|
+
for (const scope of spec.scopes) gates.push({
|
|
29
|
+
scope,
|
|
30
|
+
route: `${route.method} ${route.path}`
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return gates;
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { scopeGatesOf };
|
package/dist/index.d.ts
CHANGED
|
@@ -28,7 +28,7 @@ export { type AdminRouteDrift, missingAdminRoutes } from "./controlPlane/discove
|
|
|
28
28
|
export { type CapabilityHealth, type CapabilityHealthInput, type CapabilityHealthSource, capabilityHealthSources, defineCapabilityHealth, readCapabilityHealth, } from "./controlPlane/discovery/health";
|
|
29
29
|
export { CapabilityHealthReport, type CapabilityHealthWire, HealthCountNominal, HealthNominal, type HealthStanding, HealthSummary, HealthSummaryKey, HealthSummaryValue, HealthValueCost, HealthValueKind, healthAttention, healthReport, healthWire, type NamedHealthValue, namedHealthValues, standingOf, } from "./controlPlane/discovery/healthSummary";
|
|
30
30
|
export { requireControlPlane } from "./controlPlane/http/guard";
|
|
31
|
-
export { ANY_VERIFIED_CALLER, type ControlPlaneRequirement, ControlPlaneScope, KEYS_ROTATE_SCOPE, MANIFEST_READ_SCOPE, SEAM_SCOPES, } from "./controlPlane/scope/scope";
|
|
31
|
+
export { ANY_VERIFIED_CALLER, type ControlPlaneRequirement, ControlPlaneScope, KEYS_ROTATE_SCOPE, MANIFEST_READ_SCOPE, MIGRATIONS_READ_SCOPE, SEAM_SCOPES, } from "./controlPlane/scope/scope";
|
|
32
32
|
export { exportPublicJwk, type MintControlPlaneToken, mintControlPlaneToken } from "./controlPlane/token/mint";
|
|
33
33
|
export { CONTROL_PLANE_HEADER, CONTROL_PLANE_VERSION_CREATED_HEADER, CONTROL_PLANE_VERSION_HEADER, type WorkerBuild, workerBuildChanged, } from "./controlPlane/wire";
|
|
34
34
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +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"}
|
|
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,qBAAqB,EACrB,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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2026 Pithy
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
|
-
import { ANY_VERIFIED_CALLER, ControlPlaneScope, KEYS_ROTATE_SCOPE, MANIFEST_READ_SCOPE, SEAM_SCOPES } from "./controlPlane/scope/scope.js";
|
|
3
|
+
import { ANY_VERIFIED_CALLER, ControlPlaneScope, KEYS_ROTATE_SCOPE, MANIFEST_READ_SCOPE, MIGRATIONS_READ_SCOPE, SEAM_SCOPES } from "./controlPlane/scope/scope.js";
|
|
4
4
|
import { ControlPlaneConfig } from "./controlPlane/config/config.js";
|
|
5
5
|
import { ControlPlaneConnection, Ed25519PublicJwk, RegisteredKey } from "./controlPlane/data/connection.js";
|
|
6
6
|
import { CONTROL_PLANE_CONNECTIONS_TABLE, controlPlaneDatabase } from "./controlPlane/data/tables.js";
|
|
@@ -16,4 +16,4 @@ import { CONTROL_PLANE_KV_BINDING } from "./controlPlane/replay/kvGuard.js";
|
|
|
16
16
|
import { CONTROLPLANE_MIGRATION_ORDER, controlplane, isControlPlaneCapability } from "./controlPlane/capability.js";
|
|
17
17
|
import { missingAdminRoutes } from "./controlPlane/discovery/drift.js";
|
|
18
18
|
import { exportPublicJwk, mintControlPlaneToken } from "./controlPlane/token/mint.js";
|
|
19
|
-
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 };
|
|
19
|
+
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, MIGRATIONS_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/logger/record.d.ts
CHANGED
|
@@ -310,6 +310,20 @@ export declare const LogRecord: z.ZodObject<{
|
|
|
310
310
|
detail: z.ZodOptional<z.ZodString>;
|
|
311
311
|
code: z.ZodLiteral<"turnstile/config">;
|
|
312
312
|
status: z.ZodLiteral<500>;
|
|
313
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
314
|
+
message: z.ZodString;
|
|
315
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
316
|
+
action: z.ZodOptional<z.ZodString>;
|
|
317
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
318
|
+
code: z.ZodLiteral<"turnstile/analytics_window">;
|
|
319
|
+
status: z.ZodLiteral<400>;
|
|
320
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
321
|
+
message: z.ZodString;
|
|
322
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
323
|
+
action: z.ZodOptional<z.ZodString>;
|
|
324
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
325
|
+
code: z.ZodLiteral<"turnstile/analytics_unavailable">;
|
|
326
|
+
status: z.ZodLiteral<409>;
|
|
313
327
|
}, z.core.$strip>, z.ZodObject<{
|
|
314
328
|
message: z.ZodString;
|
|
315
329
|
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
@@ -331,6 +345,13 @@ export declare const LogRecord: z.ZodObject<{
|
|
|
331
345
|
detail: z.ZodOptional<z.ZodString>;
|
|
332
346
|
code: z.ZodLiteral<"media/not_found">;
|
|
333
347
|
status: z.ZodLiteral<404>;
|
|
348
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
349
|
+
message: z.ZodString;
|
|
350
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
351
|
+
action: z.ZodOptional<z.ZodString>;
|
|
352
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
353
|
+
code: z.ZodLiteral<"media/forbidden">;
|
|
354
|
+
status: z.ZodLiteral<403>;
|
|
334
355
|
}, z.core.$strip>, z.ZodObject<{
|
|
335
356
|
message: z.ZodString;
|
|
336
357
|
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
@@ -352,6 +373,20 @@ export declare const LogRecord: z.ZodObject<{
|
|
|
352
373
|
detail: z.ZodOptional<z.ZodString>;
|
|
353
374
|
code: z.ZodLiteral<"media/enrichment_failed">;
|
|
354
375
|
status: z.ZodLiteral<500>;
|
|
376
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
377
|
+
message: z.ZodString;
|
|
378
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
379
|
+
action: z.ZodOptional<z.ZodString>;
|
|
380
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
381
|
+
code: z.ZodLiteral<"media/analytics_window">;
|
|
382
|
+
status: z.ZodLiteral<400>;
|
|
383
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
384
|
+
message: z.ZodString;
|
|
385
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
386
|
+
action: z.ZodOptional<z.ZodString>;
|
|
387
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
388
|
+
code: z.ZodLiteral<"media/analytics_unavailable">;
|
|
389
|
+
status: z.ZodLiteral<409>;
|
|
355
390
|
}, z.core.$strip>, z.ZodObject<{
|
|
356
391
|
message: z.ZodString;
|
|
357
392
|
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
@@ -786,6 +821,20 @@ export declare const LogRecord: z.ZodObject<{
|
|
|
786
821
|
detail: z.ZodOptional<z.ZodString>;
|
|
787
822
|
code: z.ZodLiteral<"payments/subscription_change_refused">;
|
|
788
823
|
status: z.ZodLiteral<409>;
|
|
824
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
825
|
+
message: z.ZodString;
|
|
826
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
827
|
+
action: z.ZodOptional<z.ZodString>;
|
|
828
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
829
|
+
code: z.ZodLiteral<"payments/override_stale">;
|
|
830
|
+
status: z.ZodLiteral<409>;
|
|
831
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
832
|
+
message: z.ZodString;
|
|
833
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
834
|
+
action: z.ZodOptional<z.ZodString>;
|
|
835
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
836
|
+
code: z.ZodLiteral<"payments/quota_exceeded">;
|
|
837
|
+
status: z.ZodLiteral<402>;
|
|
789
838
|
}, z.core.$strip>, z.ZodObject<{
|
|
790
839
|
message: z.ZodString;
|
|
791
840
|
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
@@ -870,6 +919,41 @@ export declare const LogRecord: z.ZodObject<{
|
|
|
870
919
|
detail: z.ZodOptional<z.ZodString>;
|
|
871
920
|
code: z.ZodLiteral<"organization/nomination_invalid">;
|
|
872
921
|
status: z.ZodLiteral<400>;
|
|
922
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
923
|
+
message: z.ZodString;
|
|
924
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
925
|
+
action: z.ZodOptional<z.ZodString>;
|
|
926
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
927
|
+
code: z.ZodLiteral<"artifacts/not_found">;
|
|
928
|
+
status: z.ZodLiteral<404>;
|
|
929
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
930
|
+
message: z.ZodString;
|
|
931
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
932
|
+
action: z.ZodOptional<z.ZodString>;
|
|
933
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
934
|
+
code: z.ZodLiteral<"artifacts/forbidden">;
|
|
935
|
+
status: z.ZodLiteral<403>;
|
|
936
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
937
|
+
message: z.ZodString;
|
|
938
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
939
|
+
action: z.ZodOptional<z.ZodString>;
|
|
940
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
941
|
+
code: z.ZodLiteral<"artifacts/invalid_name">;
|
|
942
|
+
status: z.ZodLiteral<400>;
|
|
943
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
944
|
+
message: z.ZodString;
|
|
945
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
946
|
+
action: z.ZodOptional<z.ZodString>;
|
|
947
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
948
|
+
code: z.ZodLiteral<"artifacts/name_taken">;
|
|
949
|
+
status: z.ZodLiteral<409>;
|
|
950
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
951
|
+
message: z.ZodString;
|
|
952
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
953
|
+
action: z.ZodOptional<z.ZodString>;
|
|
954
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
955
|
+
code: z.ZodLiteral<"artifacts/invalid_config">;
|
|
956
|
+
status: z.ZodLiteral<400>;
|
|
873
957
|
}, z.core.$strip>, z.ZodObject<{
|
|
874
958
|
message: z.ZodString;
|
|
875
959
|
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../src/logger/record.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;;;GAKG;AAEH,4GAA4G;AAC5G,eAAO,MAAM,QAAQ;;;;;EAE4F,CAAC;AAClH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,QAAQ,CAAC,CAAC;AAEjD;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAgD,CAAC;AAEtG;;;;GAIG;AACH,eAAO,MAAM,SAAS,wCAEsF,CAAC;AAC7G,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,SAAS,CAAC,CAAC;AAEnD;;;;;GAKG;AACH,eAAO,MAAM,SAAS
|
|
1
|
+
{"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../src/logger/record.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;;;GAKG;AAEH,4GAA4G;AAC5G,eAAO,MAAM,QAAQ;;;;;EAE4F,CAAC;AAClH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,QAAQ,CAAC,CAAC;AAEjD;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAgD,CAAC;AAEtG;;;;GAIG;AACH,eAAO,MAAM,SAAS,wCAEsF,CAAC;AAC7G,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,SAAS,CAAC,CAAC;AAEnD;;;;;GAKG;AACH,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAW+E,CAAC;AACtG,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,SAAS,CAAC,CAAC;AAmBnD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAMzD"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 Pithy
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
import type { MigrationProvider } from "kysely/migration";
|
|
4
|
+
import type { Capability } from "../capability/capability";
|
|
5
|
+
import { type NamespacedMigrations } from "./registry";
|
|
6
|
+
/**
|
|
7
|
+
* Every capability's per-database migration set (`DatabaseSpec.migrations`, namespaced by capability
|
|
8
|
+
* name), in composition order — the raw material {@link buildRegistryFromCapabilities}, the CLI's
|
|
9
|
+
* fan-out runner and the control-plane seam all build on. The runner needs the sets rather than a
|
|
10
|
+
* finished provider because two Workers can be bound to one physical D1: their sets merge into a single
|
|
11
|
+
* ordered provider so that database migrates once, with every Worker's capabilities in it. A Worker
|
|
12
|
+
* composes only its own, which is why the seam's `undeclared` is relative to that Worker. Migrations
|
|
13
|
+
* without a `migrationOrder` fail here, attributed to their capability.
|
|
14
|
+
*/
|
|
15
|
+
export declare function collectMigrationSets(capabilities: Capability[]): NamespacedMigrations[];
|
|
16
|
+
/**
|
|
17
|
+
* Compose every capability's per-database migration sets (`DatabaseSpec.migrations`,
|
|
18
|
+
* namespaced by capability name) into one ordered provider per database. A database
|
|
19
|
+
* nobody migrates gets no provider; migrations without a `migrationOrder` fail here,
|
|
20
|
+
* attributed to their capability.
|
|
21
|
+
*/
|
|
22
|
+
export declare function buildRegistryFromCapabilities(capabilities: Capability[]): Record<string, MigrationProvider>;
|
|
23
|
+
//# sourceMappingURL=capabilitySets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilitySets.d.ts","sourceRoot":"","sources":["../../src/migrations/capabilitySets.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAG3D,OAAO,EAA2B,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAsChF;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,UAAU,EAAE,GAAG,oBAAoB,EAAE,CAsBvF;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,YAAY,EAAE,UAAU,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAE3G"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 Pithy
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
import { InternalError } from "../error/pithyError.js";
|
|
4
|
+
import { createMigrationRegistry } from "./registry.js";
|
|
5
|
+
//#region src/migrations/capabilitySets.ts
|
|
6
|
+
/**
|
|
7
|
+
* **Where a capability's migrations become a registry's sets — one function, composed twice (#729).**
|
|
8
|
+
*
|
|
9
|
+
* `pithy migrate` and `pithy doctor` compose these sets from the project on disk; the Worker composes them
|
|
10
|
+
* from the capabilities it was built with, to answer `GET {basePath}/migrations`. It lived in the CLI until
|
|
11
|
+
* the Worker needed it too. It reads nothing but `Capability.databases`, so it belongs in core — and if
|
|
12
|
+
* the two sides composed with two functions, `pithy doctor` and the route could disagree about one
|
|
13
|
+
* environment with nothing to say which was wrong.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* A retained declaration must name a table this slice declares, beside the migrations that create it.
|
|
17
|
+
*
|
|
18
|
+
* A misspelled key would count a table that does not exist, find no rows, and let the `down` through —
|
|
19
|
+
* the refusal quietly off for the one table it was written for. And retention on a slice with no
|
|
20
|
+
* migrations has no `down` to be recorded on, so nothing would ever enforce it. Both are an author's mistake,
|
|
21
|
+
* caught where the declaration is read rather than discovered when a vault is empty (#588).
|
|
22
|
+
*/
|
|
23
|
+
function assertRetainedDeclared(capability, database, spec) {
|
|
24
|
+
const retained = spec.retained ?? [];
|
|
25
|
+
if (retained.length === 0) return;
|
|
26
|
+
const unknown = retained.filter((table) => !(table in spec.tables));
|
|
27
|
+
if (unknown.length > 0) throw new InternalError({
|
|
28
|
+
message: `Capability "${capability}" retains ${unknown.map((table) => `"${table}"`).join(", ")} in database "${database}", which its tables do not declare.`,
|
|
29
|
+
action: "Name tables from that database spec's tables in retained."
|
|
30
|
+
});
|
|
31
|
+
if (!spec.migrations || Object.keys(spec.migrations).length === 0) throw new InternalError({
|
|
32
|
+
message: `Capability "${capability}" retains tables in database "${database}" but ships no migrations for it.`,
|
|
33
|
+
action: "Declare retained beside the migrations that create those tables."
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Every capability's per-database migration set (`DatabaseSpec.migrations`, namespaced by capability
|
|
38
|
+
* name), in composition order — the raw material {@link buildRegistryFromCapabilities}, the CLI's
|
|
39
|
+
* fan-out runner and the control-plane seam all build on. The runner needs the sets rather than a
|
|
40
|
+
* finished provider because two Workers can be bound to one physical D1: their sets merge into a single
|
|
41
|
+
* ordered provider so that database migrates once, with every Worker's capabilities in it. A Worker
|
|
42
|
+
* composes only its own, which is why the seam's `undeclared` is relative to that Worker. Migrations
|
|
43
|
+
* without a `migrationOrder` fail here, attributed to their capability.
|
|
44
|
+
*/
|
|
45
|
+
function collectMigrationSets(capabilities) {
|
|
46
|
+
const sets = [];
|
|
47
|
+
for (const capability of capabilities) for (const [database, spec] of Object.entries(capability.databases ?? {})) {
|
|
48
|
+
assertRetainedDeclared(capability.name, database, spec);
|
|
49
|
+
if (!spec.migrations) continue;
|
|
50
|
+
if (spec.migrationOrder === void 0) throw new InternalError({
|
|
51
|
+
message: `Capability "${capability.name}" has migrations for database "${database}" but no migrationOrder.`,
|
|
52
|
+
action: "Set migrationOrder on that database spec (core low, app high)."
|
|
53
|
+
});
|
|
54
|
+
sets.push({
|
|
55
|
+
database,
|
|
56
|
+
namespace: capability.name,
|
|
57
|
+
order: spec.migrationOrder,
|
|
58
|
+
migrations: spec.migrations,
|
|
59
|
+
...spec.retained && spec.retained.length > 0 ? { retained: spec.retained } : {}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
return sets;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Compose every capability's per-database migration sets (`DatabaseSpec.migrations`,
|
|
66
|
+
* namespaced by capability name) into one ordered provider per database. A database
|
|
67
|
+
* nobody migrates gets no provider; migrations without a `migrationOrder` fail here,
|
|
68
|
+
* attributed to their capability.
|
|
69
|
+
*/
|
|
70
|
+
function buildRegistryFromCapabilities(capabilities) {
|
|
71
|
+
return createMigrationRegistry(collectMigrationSets(capabilities));
|
|
72
|
+
}
|
|
73
|
+
//#endregion
|
|
74
|
+
export { buildRegistryFromCapabilities, collectMigrationSets };
|