@pithy-sh/core 0.10.0 → 0.12.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/audit/recorder.d.ts +10 -2
- package/dist/audit/recorder.d.ts.map +1 -1
- 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 +110 -28
- package/dist/capability/capability.d.ts.map +1 -1
- package/dist/capability/capability.js +2 -0
- 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/purge.d.ts +80 -0
- package/dist/capability/purge.d.ts.map +1 -0
- package/dist/capability/purge.js +76 -0
- 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 +238 -24
- package/dist/cli/commandCatalog.generated.d.ts.map +1 -1
- package/dist/cli/commandCatalog.generated.js +251 -22
- package/dist/cli/commandFacts.d.ts +2 -1
- package/dist/cli/commandFacts.d.ts.map +1 -1
- package/dist/cli/commandFacts.js +2 -0
- package/dist/controlPlane/capability.d.ts.map +1 -1
- package/dist/controlPlane/capability.js +19 -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 +49 -12
- package/dist/controlPlane/data/connection.d.ts.map +1 -1
- package/dist/controlPlane/data/connection.js +56 -2
- package/dist/controlPlane/discovery/adminRoute.d.ts +29 -0
- package/dist/controlPlane/discovery/adminRoute.d.ts.map +1 -1
- package/dist/controlPlane/discovery/adminRoute.js +3 -0
- package/dist/controlPlane/error/errors.d.ts +4 -3
- package/dist/controlPlane/error/errors.d.ts.map +1 -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 +139 -0
- package/dist/controlPlane/http/handlers.d.ts.map +1 -1
- package/dist/controlPlane/http/handlers.js +67 -4
- 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 +245 -0
- package/dist/controlPlane/http/responses.d.ts.map +1 -1
- package/dist/controlPlane/http/responses.js +101 -4
- package/dist/controlPlane/http/routes.d.ts +2 -0
- package/dist/controlPlane/http/routes.d.ts.map +1 -1
- package/dist/controlPlane/http/routes.js +31 -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 +23 -2
- package/dist/controlPlane/scope/scope.d.ts.map +1 -1
- package/dist/controlPlane/scope/scope.js +24 -3
- package/dist/createBackend.d.ts.map +1 -1
- package/dist/createBackend.js +9 -2
- package/dist/createEntrypoint.d.ts.map +1 -1
- package/dist/createEntrypoint.js +5 -3
- package/dist/crypto/envelope.d.ts +86 -0
- package/dist/crypto/envelope.d.ts.map +1 -0
- package/dist/crypto/envelope.js +129 -0
- package/dist/crypto/fieldKeys.d.ts +41 -0
- package/dist/crypto/fieldKeys.d.ts.map +1 -0
- package/dist/crypto/fieldKeys.js +56 -0
- package/dist/data/codecs.d.ts +23 -10
- package/dist/data/codecs.d.ts.map +1 -1
- package/dist/data/codecs.js +50 -36
- 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/extend.d.ts +6 -5
- package/dist/error/extend.d.ts.map +1 -1
- package/dist/error/http.d.ts +168 -0
- package/dist/error/http.d.ts.map +1 -1
- package/dist/error/payload.d.ts +336 -0
- package/dist/error/payload.d.ts.map +1 -1
- package/dist/error/payload.js +116 -4
- package/dist/error/pithyError.d.ts +18 -7
- package/dist/error/pithyError.d.ts.map +1 -1
- package/dist/error/pithyError.js +6 -0
- 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/logger.d.ts +12 -5
- package/dist/logger/logger.d.ts.map +1 -1
- package/dist/logger/record.d.ts +98 -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/privacy/blindIndex.d.ts +27 -0
- package/dist/privacy/blindIndex.d.ts.map +1 -0
- package/dist/privacy/blindIndex.js +57 -0
- package/dist/privacy/classes.d.ts +142 -0
- package/dist/privacy/classes.d.ts.map +1 -0
- package/dist/privacy/classes.js +209 -0
- package/dist/privacy/classify.d.ts +336 -0
- package/dist/privacy/classify.d.ts.map +1 -0
- package/dist/privacy/classify.js +1024 -0
- package/dist/privacy/encrypted.d.ts +210 -0
- package/dist/privacy/encrypted.d.ts.map +1 -0
- package/dist/privacy/encrypted.js +350 -0
- package/dist/privacy/encryptedColumns.d.ts +64 -0
- package/dist/privacy/encryptedColumns.d.ts.map +1 -0
- package/dist/privacy/encryptedColumns.js +134 -0
- package/dist/privacy/fieldRotation.d.ts +34 -0
- package/dist/privacy/fieldRotation.d.ts.map +1 -0
- package/dist/privacy/fieldRotation.js +186 -0
- package/dist/privacy/inventory.d.ts +12 -0
- package/dist/privacy/inventory.d.ts.map +1 -0
- package/dist/privacy/inventory.js +154 -0
- package/dist/privacy/posture.d.ts +114 -0
- package/dist/privacy/posture.d.ts.map +1 -0
- package/dist/privacy/posture.js +136 -0
- package/dist/privacy/redact.d.ts +7 -0
- package/dist/privacy/redact.d.ts.map +1 -0
- package/dist/privacy/redact.js +404 -0
- package/dist/privacy/report.d.ts +58 -0
- package/dist/privacy/report.d.ts.map +1 -0
- package/dist/privacy/report.js +15 -0
- package/dist/privacy/retirement.d.ts +68 -0
- package/dist/privacy/retirement.d.ts.map +1 -0
- package/dist/privacy/retirement.js +72 -0
- package/dist/privacy/sealed.d.ts +87 -0
- package/dist/privacy/sealed.d.ts.map +1 -0
- package/dist/privacy/sealed.js +221 -0
- package/dist/privacy/types.d.ts +559 -0
- package/dist/privacy/types.d.ts.map +1 -0
- package/dist/privacy/types.js +2 -0
- 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/audit/recorder.ts +10 -2
- package/src/capability/bindings.ts +159 -13
- package/src/capability/capability.ts +114 -29
- package/src/capability/purge.ts +124 -0
- package/src/capability/settings.ts +146 -2
- package/src/cli/commandCatalog.generated.ts +271 -22
- package/src/cli/commandFacts.ts +2 -0
- package/src/controlPlane/capability.ts +36 -1
- package/src/controlPlane/context.ts +4 -0
- package/src/controlPlane/data/connection.ts +90 -0
- package/src/controlPlane/discovery/adminRoute.ts +11 -0
- package/src/controlPlane/error/errors.ts +4 -3
- package/src/controlPlane/http/cors.ts +4 -4
- package/src/controlPlane/http/guard.ts +21 -0
- package/src/controlPlane/http/handlers.ts +98 -4
- package/src/controlPlane/http/readiness.ts +50 -0
- package/src/controlPlane/http/responses.ts +240 -2
- package/src/controlPlane/http/routes.ts +55 -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 +25 -2
- package/src/controlPlane/token/base64url.ts +1 -1
- package/src/createBackend.ts +28 -6
- package/src/createEntrypoint.ts +9 -3
- package/src/crypto/envelope.ts +196 -0
- package/src/crypto/fieldKeys.ts +76 -0
- package/src/data/codecs.ts +69 -37
- package/src/entitlement/allowance.ts +85 -0
- package/src/entitlement/entitlement.ts +38 -0
- package/src/entitlement/meter.ts +69 -0
- package/src/error/extend.ts +6 -5
- package/src/error/payload.ts +253 -4
- package/src/error/pithyError.ts +21 -7
- package/src/http/authContext.ts +13 -1
- package/src/http/scopeGates.ts +34 -0
- package/src/index.ts +2 -0
- package/src/logger/logger.ts +12 -5
- 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/privacy/blindIndex.ts +81 -0
- package/src/privacy/classes.ts +277 -0
- package/src/privacy/classify.ts +1447 -0
- package/src/privacy/encrypted.ts +513 -0
- package/src/privacy/encryptedColumns.ts +185 -0
- package/src/privacy/fieldRotation.ts +234 -0
- package/src/privacy/inventory.ts +147 -0
- package/src/privacy/posture.ts +205 -0
- package/src/privacy/redact.ts +423 -0
- package/src/privacy/report.ts +64 -0
- package/src/privacy/retirement.ts +102 -0
- package/src/privacy/sealed.ts +323 -0
- package/src/privacy/types.ts +804 -0
- 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
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 Pithy
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
//#region src/controlPlane/http/readiness.ts
|
|
4
|
+
/**
|
|
5
|
+
* Mount every capability's readiness guard, exempting the admin surface.
|
|
6
|
+
*
|
|
7
|
+
* **The control plane answers whatever else is wrong with the Worker.** It is the diagnostic surface: a
|
|
8
|
+
* management client reads the manifest, migration state and drift through it. A guard that refuses every
|
|
9
|
+
* request because an index drifted would take that surface down on exactly the fault it exists to report,
|
|
10
|
+
* and the client could not tell drift from a Worker that is simply down.
|
|
11
|
+
*
|
|
12
|
+
* **The exemption is the guard, not the middleware.** The seam itself runs on capability middleware —
|
|
13
|
+
* `controlplane()` publishes the verifier and `audit()` publishes `emit` — so skipping middleware on a
|
|
14
|
+
* seam request would trade a 500 for a seam that denies everything, or one that stops auditing without a
|
|
15
|
+
* word. Readiness guards are the only middleware that refuses because the Worker is broken, so they are
|
|
16
|
+
* the only thing skipped.
|
|
17
|
+
*
|
|
18
|
+
* **Hono decides what is on the surface, not a matcher written here.** One `app.use` per admin path marks
|
|
19
|
+
* the request, so a `:segment` matches exactly as it does for the route and the CORS layer, and a literal
|
|
20
|
+
* path never matches what is beneath it. The surface is the one `corsSurface(all)` computes, which
|
|
21
|
+
* `routeContract.test.ts` already holds to the registered routes, so there is no second list to drift.
|
|
22
|
+
*
|
|
23
|
+
* The mark is a `WeakSet` over the raw `Request`, closed over here. A context variable would put an
|
|
24
|
+
* internal flag on `PithyVars`, where every capability could read it and one could set it.
|
|
25
|
+
*
|
|
26
|
+
* Call after every capability's `middleware` and before any capability's `routes`. Before the routes,
|
|
27
|
+
* because a terminal handler never calls `next()` and a guard mounted after it never runs.
|
|
28
|
+
*/
|
|
29
|
+
function registerReadinessGuards(app, surface, guards) {
|
|
30
|
+
if (guards.length === 0) return;
|
|
31
|
+
const onSurface = /* @__PURE__ */ new WeakSet();
|
|
32
|
+
for (const path of new Set(surface.map((entry) => entry.path))) app.use(path, async (c, next) => {
|
|
33
|
+
onSurface.add(c.req.raw);
|
|
34
|
+
await next();
|
|
35
|
+
});
|
|
36
|
+
for (const guard of guards) app.use("*", (c, next) => onSurface.has(c.req.raw) ? next() : guard(c, next));
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
export { registerReadinessGuards };
|
|
@@ -62,6 +62,13 @@ export declare const ControlPlaneKeysResponse: z.ZodObject<{
|
|
|
62
62
|
validUntil: z.ZodNullable<z.ZodISODateTime>;
|
|
63
63
|
revokedAt: z.ZodNullable<z.ZodISODateTime>;
|
|
64
64
|
}, z.core.$strip>>;
|
|
65
|
+
authorizedBy: z.ZodOptional<z.ZodNullable<z.ZodEmail>>;
|
|
66
|
+
actorKind: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
67
|
+
agent: "agent";
|
|
68
|
+
dashboard: "dashboard";
|
|
69
|
+
script: "script";
|
|
70
|
+
}>>>;
|
|
71
|
+
purpose: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
65
72
|
}, z.core.$strip>;
|
|
66
73
|
export type ControlPlaneKeysResponse = z.output<typeof ControlPlaneKeysResponse>;
|
|
67
74
|
/** `POST /control-plane/keys` — the appended key, and the set as it now stands. */
|
|
@@ -98,4 +105,242 @@ export declare const ExpireKeyResponse: z.ZodObject<{
|
|
|
98
105
|
}, z.core.$strip>>;
|
|
99
106
|
}, z.core.$strip>;
|
|
100
107
|
export type ExpireKeyResponse = z.output<typeof ExpireKeyResponse>;
|
|
108
|
+
/**
|
|
109
|
+
* One migration as `GET {basePath}/migrations` reports it: its composed name, and whose it is.
|
|
110
|
+
*
|
|
111
|
+
* The namespace is a capability's name, which the manifest already reports in `capabilities[]`. So a
|
|
112
|
+
* client tells an adopter's own migrations from a composed capability's by comparing the two — no
|
|
113
|
+
* convention, and no list kept anywhere.
|
|
114
|
+
*/
|
|
115
|
+
export declare const MigrationView: z.ZodObject<{
|
|
116
|
+
name: z.ZodString;
|
|
117
|
+
namespace: z.ZodNullable<z.ZodString>;
|
|
118
|
+
}, z.core.$strip>;
|
|
119
|
+
export type MigrationView = z.output<typeof MigrationView>;
|
|
120
|
+
/** Whether the last group is still reversible by name, or what is in its way. */
|
|
121
|
+
export declare const MigrationGroupPositionView: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
122
|
+
state: z.ZodLiteral<"top">;
|
|
123
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
124
|
+
state: z.ZodLiteral<"buried">;
|
|
125
|
+
above: z.ZodArray<z.ZodString>;
|
|
126
|
+
ungrouped: z.ZodArray<z.ZodObject<{
|
|
127
|
+
name: z.ZodString;
|
|
128
|
+
namespace: z.ZodNullable<z.ZodString>;
|
|
129
|
+
}, z.core.$strip>>;
|
|
130
|
+
}, z.core.$strip>], "state">;
|
|
131
|
+
export type MigrationGroupPositionView = z.output<typeof MigrationGroupPositionView>;
|
|
132
|
+
/** The run that last moved a database, and whether it can still be taken back. */
|
|
133
|
+
export declare const MigrationGroupView: z.ZodObject<{
|
|
134
|
+
group: z.ZodString;
|
|
135
|
+
appliedAt: z.ZodISODateTime;
|
|
136
|
+
migrations: z.ZodArray<z.ZodObject<{
|
|
137
|
+
name: z.ZodString;
|
|
138
|
+
namespace: z.ZodNullable<z.ZodString>;
|
|
139
|
+
}, z.core.$strip>>;
|
|
140
|
+
position: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
141
|
+
state: z.ZodLiteral<"top">;
|
|
142
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
143
|
+
state: z.ZodLiteral<"buried">;
|
|
144
|
+
above: z.ZodArray<z.ZodString>;
|
|
145
|
+
ungrouped: z.ZodArray<z.ZodObject<{
|
|
146
|
+
name: z.ZodString;
|
|
147
|
+
namespace: z.ZodNullable<z.ZodString>;
|
|
148
|
+
}, z.core.$strip>>;
|
|
149
|
+
}, z.core.$strip>], "state">;
|
|
150
|
+
}, z.core.$strip>;
|
|
151
|
+
export type MigrationGroupView = z.output<typeof MigrationGroupView>;
|
|
152
|
+
/**
|
|
153
|
+
* One database this Worker binds, read or not.
|
|
154
|
+
*
|
|
155
|
+
* **An unreadable database carries no list at all**, never empty ones. `pending: []` reads as up to date,
|
|
156
|
+
* and a database nobody read is not that. The state is on the value, so a client reaches a list only by
|
|
157
|
+
* narrowing.
|
|
158
|
+
*/
|
|
159
|
+
export declare const MigrationDatabaseView: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
160
|
+
state: z.ZodLiteral<"readable">;
|
|
161
|
+
database: z.ZodString;
|
|
162
|
+
binding: z.ZodString;
|
|
163
|
+
applied: z.ZodArray<z.ZodObject<{
|
|
164
|
+
name: z.ZodString;
|
|
165
|
+
namespace: z.ZodNullable<z.ZodString>;
|
|
166
|
+
}, z.core.$strip>>;
|
|
167
|
+
pending: z.ZodArray<z.ZodObject<{
|
|
168
|
+
name: z.ZodString;
|
|
169
|
+
namespace: z.ZodNullable<z.ZodString>;
|
|
170
|
+
}, z.core.$strip>>;
|
|
171
|
+
undeclared: z.ZodArray<z.ZodObject<{
|
|
172
|
+
name: z.ZodString;
|
|
173
|
+
namespace: z.ZodNullable<z.ZodString>;
|
|
174
|
+
}, z.core.$strip>>;
|
|
175
|
+
lastGroup: z.ZodNullable<z.ZodObject<{
|
|
176
|
+
group: z.ZodString;
|
|
177
|
+
appliedAt: z.ZodISODateTime;
|
|
178
|
+
migrations: z.ZodArray<z.ZodObject<{
|
|
179
|
+
name: z.ZodString;
|
|
180
|
+
namespace: z.ZodNullable<z.ZodString>;
|
|
181
|
+
}, z.core.$strip>>;
|
|
182
|
+
position: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
183
|
+
state: z.ZodLiteral<"top">;
|
|
184
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
185
|
+
state: z.ZodLiteral<"buried">;
|
|
186
|
+
above: z.ZodArray<z.ZodString>;
|
|
187
|
+
ungrouped: z.ZodArray<z.ZodObject<{
|
|
188
|
+
name: z.ZodString;
|
|
189
|
+
namespace: z.ZodNullable<z.ZodString>;
|
|
190
|
+
}, z.core.$strip>>;
|
|
191
|
+
}, z.core.$strip>], "state">;
|
|
192
|
+
}, z.core.$strip>>;
|
|
193
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
194
|
+
state: z.ZodLiteral<"unreadable">;
|
|
195
|
+
database: z.ZodString;
|
|
196
|
+
binding: z.ZodString;
|
|
197
|
+
}, z.core.$strip>], "state">;
|
|
198
|
+
export type MigrationDatabaseView = z.output<typeof MigrationDatabaseView>;
|
|
199
|
+
/**
|
|
200
|
+
* `GET /control-plane/migrations` — where every database this Worker binds stands.
|
|
201
|
+
*
|
|
202
|
+
* Asked of the Worker because the Worker *is* the deployed build. `pithy doctor` reads the project on disk,
|
|
203
|
+
* which is what the operator has and not necessarily what is deployed.
|
|
204
|
+
*/
|
|
205
|
+
export declare const ControlPlaneMigrationsResponse: z.ZodObject<{
|
|
206
|
+
environment: z.ZodString;
|
|
207
|
+
databases: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
208
|
+
state: z.ZodLiteral<"readable">;
|
|
209
|
+
database: z.ZodString;
|
|
210
|
+
binding: z.ZodString;
|
|
211
|
+
applied: z.ZodArray<z.ZodObject<{
|
|
212
|
+
name: z.ZodString;
|
|
213
|
+
namespace: z.ZodNullable<z.ZodString>;
|
|
214
|
+
}, z.core.$strip>>;
|
|
215
|
+
pending: z.ZodArray<z.ZodObject<{
|
|
216
|
+
name: z.ZodString;
|
|
217
|
+
namespace: z.ZodNullable<z.ZodString>;
|
|
218
|
+
}, z.core.$strip>>;
|
|
219
|
+
undeclared: z.ZodArray<z.ZodObject<{
|
|
220
|
+
name: z.ZodString;
|
|
221
|
+
namespace: z.ZodNullable<z.ZodString>;
|
|
222
|
+
}, z.core.$strip>>;
|
|
223
|
+
lastGroup: z.ZodNullable<z.ZodObject<{
|
|
224
|
+
group: z.ZodString;
|
|
225
|
+
appliedAt: z.ZodISODateTime;
|
|
226
|
+
migrations: z.ZodArray<z.ZodObject<{
|
|
227
|
+
name: z.ZodString;
|
|
228
|
+
namespace: z.ZodNullable<z.ZodString>;
|
|
229
|
+
}, z.core.$strip>>;
|
|
230
|
+
position: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
231
|
+
state: z.ZodLiteral<"top">;
|
|
232
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
233
|
+
state: z.ZodLiteral<"buried">;
|
|
234
|
+
above: z.ZodArray<z.ZodString>;
|
|
235
|
+
ungrouped: z.ZodArray<z.ZodObject<{
|
|
236
|
+
name: z.ZodString;
|
|
237
|
+
namespace: z.ZodNullable<z.ZodString>;
|
|
238
|
+
}, z.core.$strip>>;
|
|
239
|
+
}, z.core.$strip>], "state">;
|
|
240
|
+
}, z.core.$strip>>;
|
|
241
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
242
|
+
state: z.ZodLiteral<"unreadable">;
|
|
243
|
+
database: z.ZodString;
|
|
244
|
+
binding: z.ZodString;
|
|
245
|
+
}, z.core.$strip>], "state">>;
|
|
246
|
+
}, z.core.$strip>;
|
|
247
|
+
export type ControlPlaneMigrationsResponse = z.output<typeof ControlPlaneMigrationsResponse>;
|
|
248
|
+
/**
|
|
249
|
+
* One marked field, as `GET {basePath}/privacy` reports it (#132).
|
|
250
|
+
*
|
|
251
|
+
* **The per-field record.** Since #390 it says whether the field rests encrypted beside `class`, so "which of
|
|
252
|
+
* your PHI fields are encrypted" is a derivation over this list rather than a second inventory to keep.
|
|
253
|
+
*/
|
|
254
|
+
export declare const PrivacyFieldView: z.ZodObject<{
|
|
255
|
+
path: z.ZodString;
|
|
256
|
+
class: z.ZodString;
|
|
257
|
+
truncated: z.ZodOptional<z.ZodLiteral<true>>;
|
|
258
|
+
sameAs: z.ZodOptional<z.ZodString>;
|
|
259
|
+
encryptedAtRest: z.ZodOptional<z.ZodBoolean>;
|
|
260
|
+
unrotatable: z.ZodOptional<z.ZodLiteral<true>>;
|
|
261
|
+
}, z.core.$strip>;
|
|
262
|
+
export type PrivacyFieldView = z.output<typeof PrivacyFieldView>;
|
|
263
|
+
/** One storage schema holding at least one marked field. */
|
|
264
|
+
export declare const PrivacySchemaView: z.ZodObject<{
|
|
265
|
+
capability: z.ZodString;
|
|
266
|
+
storage: z.ZodEnum<{
|
|
267
|
+
d1: "d1";
|
|
268
|
+
kv: "kv";
|
|
269
|
+
}>;
|
|
270
|
+
container: z.ZodString;
|
|
271
|
+
name: z.ZodString;
|
|
272
|
+
fields: z.ZodArray<z.ZodObject<{
|
|
273
|
+
path: z.ZodString;
|
|
274
|
+
class: z.ZodString;
|
|
275
|
+
truncated: z.ZodOptional<z.ZodLiteral<true>>;
|
|
276
|
+
sameAs: z.ZodOptional<z.ZodString>;
|
|
277
|
+
encryptedAtRest: z.ZodOptional<z.ZodBoolean>;
|
|
278
|
+
unrotatable: z.ZodOptional<z.ZodLiteral<true>>;
|
|
279
|
+
}, z.core.$strip>>;
|
|
280
|
+
encrypted: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
281
|
+
path: z.ZodString;
|
|
282
|
+
unrotatable: z.ZodOptional<z.ZodLiteral<true>>;
|
|
283
|
+
}, z.core.$strip>>>;
|
|
284
|
+
}, z.core.$strip>;
|
|
285
|
+
export type PrivacySchemaView = z.output<typeof PrivacySchemaView>;
|
|
286
|
+
/**
|
|
287
|
+
* `GET /control-plane/privacy` — the full inventory, behind `privacy:read` (#132).
|
|
288
|
+
*
|
|
289
|
+
* Derived at runtime from the schemas this Worker composed, walked once per isolate. The manifest's `privacy`
|
|
290
|
+
* block is the headline; this is the detail, and it names fields, which is why it has a scope of its own.
|
|
291
|
+
*/
|
|
292
|
+
export declare const ControlPlanePrivacyResponse: z.ZodObject<{
|
|
293
|
+
environment: z.ZodString;
|
|
294
|
+
posture: z.ZodObject<{
|
|
295
|
+
declared: z.ZodNullable<z.ZodArray<z.ZodString>>;
|
|
296
|
+
observed: z.ZodNullable<z.ZodArray<z.ZodString>>;
|
|
297
|
+
counts: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodNumber>>;
|
|
298
|
+
observedNotDeclared: z.ZodNullable<z.ZodArray<z.ZodString>>;
|
|
299
|
+
declaredNotObserved: z.ZodNullable<z.ZodArray<z.ZodString>>;
|
|
300
|
+
consoleGate: z.ZodEnum<{
|
|
301
|
+
enforced: "enforced";
|
|
302
|
+
not_required: "not_required";
|
|
303
|
+
unattested: "unattested";
|
|
304
|
+
unverifiable: "unverifiable";
|
|
305
|
+
}>;
|
|
306
|
+
consoleGateReason: z.ZodNullable<z.ZodString>;
|
|
307
|
+
attestedAt: z.ZodNullable<z.ZodISODateTime>;
|
|
308
|
+
sources: z.ZodArray<z.ZodEnum<{
|
|
309
|
+
d1: "d1";
|
|
310
|
+
kv: "kv";
|
|
311
|
+
}>>;
|
|
312
|
+
retirement: z.ZodOptional<z.ZodObject<{
|
|
313
|
+
blocked: z.ZodBoolean;
|
|
314
|
+
reasons: z.ZodArray<z.ZodEnum<{
|
|
315
|
+
"incomplete-coverage": "incomplete-coverage";
|
|
316
|
+
stale: "stale";
|
|
317
|
+
unrotatable: "unrotatable";
|
|
318
|
+
}>>;
|
|
319
|
+
liveVersions: z.ZodNumber;
|
|
320
|
+
}, z.core.$strip>>;
|
|
321
|
+
}, z.core.$strip>;
|
|
322
|
+
schemasWalked: z.ZodNumber;
|
|
323
|
+
schemas: z.ZodArray<z.ZodObject<{
|
|
324
|
+
capability: z.ZodString;
|
|
325
|
+
storage: z.ZodEnum<{
|
|
326
|
+
d1: "d1";
|
|
327
|
+
kv: "kv";
|
|
328
|
+
}>;
|
|
329
|
+
container: z.ZodString;
|
|
330
|
+
name: z.ZodString;
|
|
331
|
+
fields: z.ZodArray<z.ZodObject<{
|
|
332
|
+
path: z.ZodString;
|
|
333
|
+
class: z.ZodString;
|
|
334
|
+
truncated: z.ZodOptional<z.ZodLiteral<true>>;
|
|
335
|
+
sameAs: z.ZodOptional<z.ZodString>;
|
|
336
|
+
encryptedAtRest: z.ZodOptional<z.ZodBoolean>;
|
|
337
|
+
unrotatable: z.ZodOptional<z.ZodLiteral<true>>;
|
|
338
|
+
}, z.core.$strip>>;
|
|
339
|
+
encrypted: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
340
|
+
path: z.ZodString;
|
|
341
|
+
unrotatable: z.ZodOptional<z.ZodLiteral<true>>;
|
|
342
|
+
}, z.core.$strip>>>;
|
|
343
|
+
}, z.core.$strip>>;
|
|
344
|
+
}, z.core.$strip>;
|
|
345
|
+
export type ControlPlanePrivacyResponse = z.output<typeof ControlPlanePrivacyResponse>;
|
|
101
346
|
//# sourceMappingURL=responses.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"responses.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/http/responses.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"responses.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/http/responses.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB;;;;;;;;;;;;;;;;;;GAkBG;AAEH,8EAA8E;AAC9E,eAAO,MAAM,aAAa;;;;;;;;;;iBAcmF,CAAC;AAC9G,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,aAAa,CAAC,CAAC;AAE3D;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB;;;;;;iBAQwB,CAAC;AAC9D,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAEjF,+FAA+F;AAC/F,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;iBAuBwE,CAAC;AAC9G,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAEjF,mFAAmF;AACnF,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;iBAQyB,CAAC;AAC1D,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEvE,gGAAgG;AAChG,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;iBAM6B,CAAC;AAC5D,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAEnE;;;;;;GAMG;AACH,eAAO,MAAM,aAAa;;;iBAU+C,CAAC;AAC1E,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,aAAa,CAAC,CAAC;AAE3D,iFAAiF;AACjF,eAAO,MAAM,0BAA0B;;;;;;;;;4BAyBkE,CAAC;AAC1G,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAErF,kFAAkF;AAClF,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;iBAW8C,CAAC;AAC9E,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAErE;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BA+BwE,CAAC;AAC3G,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAE3E;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAO+D,CAAC;AAC3G,MAAM,MAAM,8BAA8B,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,8BAA8B,CAAC,CAAC;AAE7F;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB;;;;;;;iBAmCiB,CAAC;AAC/C,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEjE,4DAA4D;AAC5D,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;iBA0BmC,CAAC;AAClE,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAEnE;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAerC,CAAC;AACJ,MAAM,MAAM,2BAA2B,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,2BAA2B,CAAC,CAAC"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2026 Pithy
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
|
-
import {
|
|
3
|
+
import { PRIVACY_SOURCES } from "../../privacy/report.js";
|
|
4
|
+
import { ConnectionPrincipal, ConnectionPurpose, ControlPlaneActorKind, Ed25519PublicJwk } from "../data/connection.js";
|
|
5
|
+
import { PrivacyPosture } from "../../privacy/posture.js";
|
|
4
6
|
import { z } from "zod";
|
|
5
7
|
//#region src/controlPlane/http/responses.ts
|
|
6
8
|
/**
|
|
@@ -47,8 +49,11 @@ const ControlPlanePingResponse = z.object({
|
|
|
47
49
|
const ControlPlaneKeysResponse = z.object({
|
|
48
50
|
connectionId: z.string().describe("The connection these keys belong to."),
|
|
49
51
|
environment: z.string().describe("The environment that connection is bound to."),
|
|
50
|
-
keys: z.array(PublicKeyView).describe("Every registered key, expired and revoked ones included.")
|
|
51
|
-
|
|
52
|
+
keys: z.array(PublicKeyView).describe("Every registered key, expired and revoked ones included."),
|
|
53
|
+
authorizedBy: ConnectionPrincipal.nullable().optional().describe("Who sanctioned this connection — the signed-in session's email at registration. Null for a connection registered before principals were recorded; absent from a Worker older than the field."),
|
|
54
|
+
actorKind: ControlPlaneActorKind.nullable().optional().describe("What kind of client this connection is for: `agent`, `dashboard` or `script`. Null for a connection registered before it was recorded; absent from an older Worker."),
|
|
55
|
+
purpose: ConnectionPurpose.nullable().optional().describe("What the client is for, in the registering operator's words. Untrusted text: render it escaped. Null for a connection registered before it was recorded; absent from an older Worker.")
|
|
56
|
+
}).describe("Every key registered against this connection, with its window, and who authorized it for what.");
|
|
52
57
|
/** `POST /control-plane/keys` — the appended key, and the set as it now stands. */
|
|
53
58
|
const RegisterKeyResponse = z.object({
|
|
54
59
|
keyId: z.string().describe("The key just registered."),
|
|
@@ -61,5 +66,97 @@ const ExpireKeyResponse = z.object({
|
|
|
61
66
|
validUntil: z.iso.datetime().describe("When its window closed, ISO-8601 — now, by construction."),
|
|
62
67
|
keys: z.array(PublicKeyView).describe("The connection's keys after the expiry.")
|
|
63
68
|
}).describe("The expired key, and the set it left behind.");
|
|
69
|
+
/**
|
|
70
|
+
* One migration as `GET {basePath}/migrations` reports it: its composed name, and whose it is.
|
|
71
|
+
*
|
|
72
|
+
* The namespace is a capability's name, which the manifest already reports in `capabilities[]`. So a
|
|
73
|
+
* client tells an adopter's own migrations from a composed capability's by comparing the two — no
|
|
74
|
+
* convention, and no list kept anywhere.
|
|
75
|
+
*/
|
|
76
|
+
const MigrationView = z.object({
|
|
77
|
+
name: z.string().describe("The composed migration name, exactly as the ledger records it: `0250_audit_0001_init`."),
|
|
78
|
+
namespace: z.string().nullable().describe("The capability this migration belongs to — its name, as `capabilities[]` in the manifest reports it. Null only for an undeclared migration whose name no Pithy registry could have composed.")
|
|
79
|
+
}).describe("One migration, and the capability namespace it belongs to.");
|
|
80
|
+
/** Whether the last group is still reversible by name, or what is in its way. */
|
|
81
|
+
const MigrationGroupPositionView = z.discriminatedUnion("state", [z.object({ state: z.literal("top").describe("The group's migrations are the contiguous tip of this database's chain. Not a promise that `pithy migrate --rollback --group <value>` runs: the CLI also refuses an undeclared migration in the ledger, and keeps back or refuses a database another environment binds.") }).describe("A group nothing on this database's ledger sits over."), z.object({
|
|
82
|
+
state: z.literal("buried").describe("Something sits over the group or inside it, so reversing it by name is refused."),
|
|
83
|
+
above: z.array(z.string()).describe("The groups in the way, newest first."),
|
|
84
|
+
ungrouped: z.array(MigrationView).describe("The migrations in the way that no group claims, newest first. Nothing can be reversed by group while one of them is at the tip.")
|
|
85
|
+
}).describe("A group with something in its way, and what that is.")]).describe("Where the last group sits in this database's chain: the top, or buried under named things.");
|
|
86
|
+
/** The run that last moved a database, and whether it can still be taken back. */
|
|
87
|
+
const MigrationGroupView = z.object({
|
|
88
|
+
group: z.string().describe("The group's value: the `--group` the run was given, or the ISO-8601 timestamp it generated."),
|
|
89
|
+
appliedAt: z.iso.datetime().describe("When this group last applied something here, ISO-8601."),
|
|
90
|
+
migrations: z.array(MigrationView).describe("What this group applied in this database and is still applied, in application order."),
|
|
91
|
+
position: MigrationGroupPositionView.describe("Whether the group is the top of the chain, or what is in its way.")
|
|
92
|
+
}).describe("The newest group with anything still applied in this database.");
|
|
93
|
+
/**
|
|
94
|
+
* One database this Worker binds, read or not.
|
|
95
|
+
*
|
|
96
|
+
* **An unreadable database carries no list at all**, never empty ones. `pending: []` reads as up to date,
|
|
97
|
+
* and a database nobody read is not that. The state is on the value, so a client reaches a list only by
|
|
98
|
+
* narrowing.
|
|
99
|
+
*/
|
|
100
|
+
const MigrationDatabaseView = z.discriminatedUnion("state", [z.object({
|
|
101
|
+
state: z.literal("readable").describe("This database's ledger was read."),
|
|
102
|
+
database: z.string().describe("The database name, as capabilities declare it in `databases`."),
|
|
103
|
+
binding: z.string().describe("The D1 binding it is read through, as `wrangler.jsonc` declares it."),
|
|
104
|
+
applied: z.array(MigrationView).describe("Every applied migration, in the order the ledger applied them."),
|
|
105
|
+
pending: z.array(MigrationView).describe("Declared by this build and not applied here, in the order they would run."),
|
|
106
|
+
undeclared: z.array(MigrationView).describe("Applied here and not declared by this Worker, sorted. Relative to this Worker: a database shared with another Worker lists that Worker's migrations here. Otherwise Kysely reads one as a corrupted chain and applies nothing."),
|
|
107
|
+
lastGroup: MigrationGroupView.nullable().describe("The newest group with anything applied here, or null when nothing applied here was ever grouped.")
|
|
108
|
+
}).describe("A database whose ledger was read."), z.object({
|
|
109
|
+
state: z.literal("unreadable").describe("This database's ledger could not be read on this call."),
|
|
110
|
+
database: z.string().describe("The database name, as capabilities declare it in `databases`."),
|
|
111
|
+
binding: z.string().describe("The D1 binding it would be read through.")
|
|
112
|
+
}).describe("A database that could not be read. No lists, so nothing about it reads as zero. The other databases still answer.")]).describe("One database this Worker binds: its migration state, or the fact that it could not be read.");
|
|
113
|
+
/**
|
|
114
|
+
* `GET /control-plane/migrations` — where every database this Worker binds stands.
|
|
115
|
+
*
|
|
116
|
+
* Asked of the Worker because the Worker *is* the deployed build. `pithy doctor` reads the project on disk,
|
|
117
|
+
* which is what the operator has and not necessarily what is deployed.
|
|
118
|
+
*/
|
|
119
|
+
const ControlPlaneMigrationsResponse = z.object({
|
|
120
|
+
environment: z.string().describe("The environment this Worker answers for."),
|
|
121
|
+
databases: z.array(MigrationDatabaseView).describe("One entry per database this Worker binds, sorted by database name. One unreadable costs only itself.")
|
|
122
|
+
}).describe("What is applied, pending and undeclared in each bound database, and which run put it there.");
|
|
123
|
+
/**
|
|
124
|
+
* One marked field, as `GET {basePath}/privacy` reports it (#132).
|
|
125
|
+
*
|
|
126
|
+
* **The per-field record.** Since #390 it says whether the field rests encrypted beside `class`, so "which of
|
|
127
|
+
* your PHI fields are encrypted" is a derivation over this list rather than a second inventory to keep.
|
|
128
|
+
*/
|
|
129
|
+
const PrivacyFieldView = z.object({
|
|
130
|
+
path: z.string().describe("Where the field sits. A D1 column path (`email`, `address.line1`, `profile.phone` inside a JSON column), or a KV entry's part first (`key.email`, `value.token`, `metadata.ip`, or `value` for a whole marked value). An array element is `[]`, a record's value `*`."),
|
|
131
|
+
class: z.string().describe("The privacy class it is marked with: `secret`, `pii`, `phi`, `pci`, or an adopter's own."),
|
|
132
|
+
truncated: z.literal(true).optional().describe("Set where the class is assumed rather than found: a read ran out of its budget there, or the schema could not be read at all, so any class may be marked below it. Absent where the schema was read to the end."),
|
|
133
|
+
sameAs: z.string().optional().describe("Set on a reference: the path this field's position was first listed under, once the list reached its cap on paths. The class is marked somewhere beneath both, and the paths beneath this one are those beneath that one."),
|
|
134
|
+
encryptedAtRest: z.boolean().optional().describe("Whether the field rests encrypted (#390). Absent where the core cannot say — an assumed class, a reference, or a core older than encrypted fields — and never defaulted to false."),
|
|
135
|
+
unrotatable: z.literal(true).optional().describe("Set on an encrypted field whose storage is not D1: it can never be rotated, and it blocks retirement.")
|
|
136
|
+
}).describe("One marked field and its class.");
|
|
137
|
+
/** One storage schema holding at least one marked field. */
|
|
138
|
+
const PrivacySchemaView = z.object({
|
|
139
|
+
capability: z.string().describe("The capability that declared the schema, as the manifest's `capabilities[]` names it."),
|
|
140
|
+
storage: z.enum(PRIVACY_SOURCES).describe("Where it is stored: a `d1` table or a `kv` store."),
|
|
141
|
+
container: z.string().describe("The D1 database name or the KV namespace name it lives in."),
|
|
142
|
+
name: z.string().describe("The table name, or the KV store name."),
|
|
143
|
+
fields: z.array(PrivacyFieldView).describe("Every marked field in it, in schema order."),
|
|
144
|
+
encrypted: z.array(z.object({
|
|
145
|
+
path: z.string().describe("Where the encrypted field sits, on the same paths as `fields[].path`."),
|
|
146
|
+
unrotatable: z.literal(true).optional().describe("Set where the storage is not D1, so the field can never be rotated.")
|
|
147
|
+
}).describe("One encrypted field.")).optional().describe("Every field marked encrypted at rest, classed or not (#390). Absent on a Worker whose core predates encrypted fields.")
|
|
148
|
+
}).describe("One storage schema and the marked fields it holds.");
|
|
149
|
+
/**
|
|
150
|
+
* `GET /control-plane/privacy` — the full inventory, behind `privacy:read` (#132).
|
|
151
|
+
*
|
|
152
|
+
* Derived at runtime from the schemas this Worker composed, walked once per isolate. The manifest's `privacy`
|
|
153
|
+
* block is the headline; this is the detail, and it names fields, which is why it has a scope of its own.
|
|
154
|
+
*/
|
|
155
|
+
const ControlPlanePrivacyResponse = z.object({
|
|
156
|
+
environment: z.string().describe("The environment this Worker answers for."),
|
|
157
|
+
posture: PrivacyPosture.describe("The declared and observed classes, the delta, and the console gate."),
|
|
158
|
+
schemasWalked: z.number().int().nonnegative().describe("How many storage schemas were walked, marked or not, across the sources `posture.sources` names."),
|
|
159
|
+
schemas: z.array(PrivacySchemaView).describe("Every schema holding a marked field, in composition order. A schema with none is not listed.")
|
|
160
|
+
}).describe("Every schema this Worker stores that holds a marked field, each field's path and class, and where it lives.");
|
|
64
161
|
//#endregion
|
|
65
|
-
export { ControlPlaneKeysResponse, ControlPlanePingResponse, ExpireKeyResponse, PublicKeyView, RegisterKeyResponse };
|
|
162
|
+
export { ControlPlaneKeysResponse, ControlPlaneMigrationsResponse, ControlPlanePingResponse, ControlPlanePrivacyResponse, ExpireKeyResponse, MigrationDatabaseView, MigrationGroupPositionView, MigrationGroupView, MigrationView, PrivacyFieldView, PrivacySchemaView, PublicKeyView, RegisterKeyResponse };
|
|
@@ -12,6 +12,8 @@ import { type ControlPlaneHandlerDeps } from "./handlers";
|
|
|
12
12
|
* GET /control-plane/keys → the registration state (keys:rotate)
|
|
13
13
|
* POST /control-plane/keys → register a key (keys:rotate)
|
|
14
14
|
* POST /control-plane/keys/:keyId/expire → retire a superseded key (keys:rotate)
|
|
15
|
+
* GET /control-plane/migrations → where each database stands (migrations:read)
|
|
16
|
+
* GET /control-plane/privacy → what each schema holds (privacy:read)
|
|
15
17
|
*
|
|
16
18
|
* Every one is `control-plane` and default-denied — with no connection registered they all answer 403,
|
|
17
19
|
* and that is the shipped state of a Worker nobody has connected.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/http/routes.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAGhE,OAAO,EAAE,KAAK,UAAU,EAAwB,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/http/routes.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAGhE,OAAO,EAAE,KAAK,UAAU,EAAwB,MAAM,yBAAyB,CAAC;AAShF,OAAO,EACL,KAAK,uBAAuB,EAQ7B,MAAM,YAAY,CAAC;AAWpB;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,EAAE,CA+C3E;AAED,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,IAAI,CAAC,YAAY,CAAC,EACvB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,uBAAuB,GAC5B,IAAI,CA2FN"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2026 Pithy
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
|
-
import { ANY_VERIFIED_CALLER, KEYS_ROTATE_SCOPE, MANIFEST_READ_SCOPE } from "../scope/scope.js";
|
|
3
|
+
import { ANY_VERIFIED_CALLER, KEYS_ROTATE_SCOPE, MANIFEST_READ_SCOPE, MIGRATIONS_READ_SCOPE, PRIVACY_READ_SCOPE } from "../scope/scope.js";
|
|
4
4
|
import { requireControlPlane } from "./guard.js";
|
|
5
5
|
import { describeRoute } from "../../http/routeSpec.js";
|
|
6
6
|
import { validate } from "../../http/validation.js";
|
|
7
7
|
import { ControlPlaneManifest } from "../discovery/adminRoute.js";
|
|
8
|
-
import { expireKeyHandler, listKeysHandler, manifestHandler, pingHandler, registerKeyHandler } from "./handlers.js";
|
|
9
|
-
import { ControlPlaneKeysResponse, ControlPlanePingResponse, ExpireKeyResponse, RegisterKeyResponse } from "./responses.js";
|
|
8
|
+
import { expireKeyHandler, listKeysHandler, manifestHandler, migrationsHandler, pingHandler, privacyHandler, registerKeyHandler } from "./handlers.js";
|
|
9
|
+
import { ControlPlaneKeysResponse, ControlPlaneMigrationsResponse, ControlPlanePingResponse, ControlPlanePrivacyResponse, ExpireKeyResponse, RegisterKeyResponse } from "./responses.js";
|
|
10
10
|
import { ExpireKeyParams, ExpireKeyRequest, RegisterKeyRequest } from "./schemas.js";
|
|
11
11
|
//#region src/controlPlane/http/routes.ts
|
|
12
12
|
/**
|
|
@@ -17,6 +17,8 @@ import { ExpireKeyParams, ExpireKeyRequest, RegisterKeyRequest } from "./schemas
|
|
|
17
17
|
* GET /control-plane/keys → the registration state (keys:rotate)
|
|
18
18
|
* POST /control-plane/keys → register a key (keys:rotate)
|
|
19
19
|
* POST /control-plane/keys/:keyId/expire → retire a superseded key (keys:rotate)
|
|
20
|
+
* GET /control-plane/migrations → where each database stands (migrations:read)
|
|
21
|
+
* GET /control-plane/privacy → what each schema holds (privacy:read)
|
|
20
22
|
*
|
|
21
23
|
* Every one is `control-plane` and default-denied — with no connection registered they all answer 403,
|
|
22
24
|
* and that is the shipped state of a Worker nobody has connected.
|
|
@@ -73,6 +75,18 @@ function controlPlaneRouteDescriptors(basePath) {
|
|
|
73
75
|
path: `${basePath}/keys/:keyId/expire`,
|
|
74
76
|
scope: KEYS_ROTATE_SCOPE,
|
|
75
77
|
summary: "Retire a superseded key. Must be signed with the successor it names as proven."
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
method: "GET",
|
|
81
|
+
path: `${basePath}/migrations`,
|
|
82
|
+
scope: MIGRATIONS_READ_SCOPE,
|
|
83
|
+
summary: "What each bound database has applied, what is pending, what is undeclared, and which run put it there. Undeclared is relative to this Worker."
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
method: "GET",
|
|
87
|
+
path: `${basePath}/privacy`,
|
|
88
|
+
scope: PRIVACY_READ_SCOPE,
|
|
89
|
+
summary: "Every stored schema holding a privacy-marked field, each field's path and class, and where it lives. Derived from the running code."
|
|
76
90
|
}
|
|
77
91
|
];
|
|
78
92
|
}
|
|
@@ -107,6 +121,20 @@ function registerControlPlaneRoutes(app, basePath, deps) {
|
|
|
107
121
|
scopes: [KEYS_ROTATE_SCOPE],
|
|
108
122
|
responses: { 200: ExpireKeyResponse }
|
|
109
123
|
}), requireControlPlane(KEYS_ROTATE_SCOPE), validate("param", ExpireKeyParams), validate("json", ExpireKeyRequest), (c) => expireKeyHandler(deps)(c, c.req.valid("param"), c.req.valid("json")));
|
|
124
|
+
app.get(`${basePath}/migrations`, describeRoute({
|
|
125
|
+
summary: "Report where each database this Worker binds stands.",
|
|
126
|
+
description: "Applied, pending and undeclared migrations per database, each naming its namespace, and the last group with whether it is still reversible. Undeclared is relative to this Worker: a database shared with another Worker lists that Worker's migrations there. Read-only.",
|
|
127
|
+
verification: "control-plane",
|
|
128
|
+
scopes: [MIGRATIONS_READ_SCOPE],
|
|
129
|
+
responses: { 200: ControlPlaneMigrationsResponse }
|
|
130
|
+
}), requireControlPlane(MIGRATIONS_READ_SCOPE), migrationsHandler(deps));
|
|
131
|
+
app.get(`${basePath}/privacy`, describeRoute({
|
|
132
|
+
summary: "Report every stored field marked with a privacy class.",
|
|
133
|
+
description: "Every D1 table and KV store this Worker composed that holds a privacy-marked field, with each field's path, its class and where it is stored, beside the declared-and-observed posture. Derived at runtime from the deployed schemas. Read-only.",
|
|
134
|
+
verification: "control-plane",
|
|
135
|
+
scopes: [PRIVACY_READ_SCOPE],
|
|
136
|
+
responses: { 200: ControlPlanePrivacyResponse }
|
|
137
|
+
}), requireControlPlane(PRIVACY_READ_SCOPE), privacyHandler(deps));
|
|
110
138
|
}
|
|
111
139
|
//#endregion
|
|
112
140
|
export { controlPlaneRouteDescriptors, registerControlPlaneRoutes };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/http/verify.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAOjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,KAAK,uBAAuB,EAAe,MAAM,gBAAgB,CAAC;AAI3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH;;;;;;;;;GASG;AACH,OAAO,EAAE,oBAAoB,EAAE,4BAA4B,EAAE,MAAM,SAAS,CAAC;AAE7E,0GAA0G;AAC1G,MAAM,WAAW,sBAAsB;IACrC,8FAA8F;IAC9F,cAAc,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAAC;IACjF;;;;;OAKG;IACH,gBAAgB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,sCAAsC;IACtC,MAAM,EAAE,WAAW,CAAC;IACpB,wEAAwE;IACxE,WAAW,EAAE,MAAM,CAAC;IACpB,mFAAmF;IACnF,MAAM,EAAE,kBAAkB,CAAC;IAC3B,8DAA8D;IAC9D,GAAG,EAAE,MAAM,IAAI,CAAC;CACjB;AAED,qEAAqE;AACrE,MAAM,WAAW,gBAAgB;IAC/B,iGAAiG;IACjG,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,4EAA4E;IAC5E,IAAI,EAAE,UAAU,CAAC;IACjB,4EAA4E;IAC5E,WAAW,EAAE,uBAAuB,CAAC;CACtC;AAOD;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,gBAAgB,EACtB,IAAI,EAAE,sBAAsB,GAC3B,OAAO,CAAC,mBAAmB,CAAC,
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/http/verify.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAOjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,KAAK,uBAAuB,EAAe,MAAM,gBAAgB,CAAC;AAI3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH;;;;;;;;;GASG;AACH,OAAO,EAAE,oBAAoB,EAAE,4BAA4B,EAAE,MAAM,SAAS,CAAC;AAE7E,0GAA0G;AAC1G,MAAM,WAAW,sBAAsB;IACrC,8FAA8F;IAC9F,cAAc,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAAC;IACjF;;;;;OAKG;IACH,gBAAgB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,sCAAsC;IACtC,MAAM,EAAE,WAAW,CAAC;IACpB,wEAAwE;IACxE,WAAW,EAAE,MAAM,CAAC;IACpB,mFAAmF;IACnF,MAAM,EAAE,kBAAkB,CAAC;IAC3B,8DAA8D;IAC9D,GAAG,EAAE,MAAM,IAAI,CAAC;CACjB;AAED,qEAAqE;AACrE,MAAM,WAAW,gBAAgB;IAC/B,iGAAiG;IACjG,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,4EAA4E;IAC5E,IAAI,EAAE,UAAU,CAAC;IACjB,4EAA4E;IAC5E,WAAW,EAAE,uBAAuB,CAAC;CACtC;AAOD;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,gBAAgB,EACtB,IAAI,EAAE,sBAAsB,GAC3B,OAAO,CAAC,mBAAmB,CAAC,CA6E9B"}
|
|
@@ -0,0 +1,102 @@
|
|
|
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 { HealthSummary } from "../discovery/healthSummary";
|
|
6
|
+
import type { MigrationDatabaseView, MigrationView } from "../http/responses";
|
|
7
|
+
/**
|
|
8
|
+
* **Migration state over the control plane (#729).**
|
|
9
|
+
*
|
|
10
|
+
* A management client could not answer what is applied where, or whether a deploy left something behind:
|
|
11
|
+
* the seam registered a ping, the manifest and key rotation, and not one field of it was about a database.
|
|
12
|
+
* The read already existed — {@link readMigrationLedger} answers both directions — and it needs a D1
|
|
13
|
+
* binding and the composed provider in one process. **The Worker is the only thing holding both**, and it
|
|
14
|
+
* is the deployed build, so asked from its side the answer cannot be stale the way the project on disk is.
|
|
15
|
+
*
|
|
16
|
+
* Two halves. At assembly, {@link composeMigrationDatabases} builds what this Worker declares per bound
|
|
17
|
+
* database, through `collectMigrationSets` — the function `pithy migrate` composes with, so the route and
|
|
18
|
+
* `pithy doctor` compose the same way. Not always from the same inputs: on a D1 two Workers share, the CLI
|
|
19
|
+
* merges both Workers' sets and the route holds only its own, so `pending` and `undeclared` can differ
|
|
20
|
+
* there. On a database one Worker binds alone they agree. Per request, {@link readDatabaseMigrations} reads
|
|
21
|
+
* one database for the route and {@link readMigrationHealth} totals all of them for the manifest.
|
|
22
|
+
*
|
|
23
|
+
* **Read-only.** Nothing here runs, reverses or resets a migration. A screen somebody opened to ask must
|
|
24
|
+
* not hand them the thing that changes the schema.
|
|
25
|
+
*
|
|
26
|
+
* **`undeclared` is relative to this Worker.** Two Workers can be bound to one physical D1, and the CLI
|
|
27
|
+
* composes across all of them. A Worker composes only its own capabilities and cannot learn a co-bound
|
|
28
|
+
* Worker's, so from inside one, every migration the other shipped to the shared database reads as
|
|
29
|
+
* undeclared. That is why `undeclaredMigrations` grades nothing.
|
|
30
|
+
*/
|
|
31
|
+
/** One database this Worker binds, with what this build declares for it. Built once, at assembly. */
|
|
32
|
+
export interface ComposedMigrationDatabase {
|
|
33
|
+
/** The database name, as capabilities declare it in `databases`. */
|
|
34
|
+
database: string;
|
|
35
|
+
/** The D1 binding it is read through. */
|
|
36
|
+
binding: string;
|
|
37
|
+
/** Every migration this build declares for it — empty for a database bound with none. */
|
|
38
|
+
provider: MigrationProvider;
|
|
39
|
+
/** Each declared migration's namespace, known from the set it came from. */
|
|
40
|
+
namespaces: ReadonlyMap<string, string>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Every database this Worker binds, with the provider this build composes for it, sorted by name.
|
|
44
|
+
*
|
|
45
|
+
* One entry per database `composeDatabases` maps to a binding — the same map the request registry is built
|
|
46
|
+
* from — so a database bound with no migrations is still reported. Leaving it out would read as not bound.
|
|
47
|
+
*/
|
|
48
|
+
export declare function composeMigrationDatabases(capabilities: readonly Capability[]): ComposedMigrationDatabase[];
|
|
49
|
+
/**
|
|
50
|
+
* One migration as the route reports it.
|
|
51
|
+
*
|
|
52
|
+
* A declared migration's namespace comes from the set it was declared in. An undeclared one has only its
|
|
53
|
+
* key, so it is decomposed — and a key no registry composed answers null rather than a guess.
|
|
54
|
+
*/
|
|
55
|
+
export declare function migrationView(name: string, namespaces: ReadonlyMap<string, string>): MigrationView;
|
|
56
|
+
/**
|
|
57
|
+
* Read one database's migration state for the route.
|
|
58
|
+
*
|
|
59
|
+
* **A database that cannot be read is `unreadable`, and costs only itself.** The cause goes to
|
|
60
|
+
* `onUnreadable` — the route logs it, where the operator's context stays the operator's — and never into
|
|
61
|
+
* the view: a D1 error can name a table or a query, and the view crosses to a management client.
|
|
62
|
+
*/
|
|
63
|
+
export declare function readDatabaseMigrations(env: Record<string, unknown>, entry: ComposedMigrationDatabase, onUnreadable?: (entry: ComposedMigrationDatabase, cause: unknown) => void): Promise<MigrationDatabaseView>;
|
|
64
|
+
/**
|
|
65
|
+
* The two health keys the seam contributes to its own manifest entry.
|
|
66
|
+
*
|
|
67
|
+
* Both `indexed`: one small select per bound database, bounded by the declared migration count rather
|
|
68
|
+
* than by the adopter's data. Both behind {@link MIGRATIONS_READ_SCOPE}, which the seam's own route
|
|
69
|
+
* requires, so a connection without it gets no value rather than a zero.
|
|
70
|
+
*
|
|
71
|
+
* **`undeclaredMigrations` declares no nominal, on purpose.** From inside one Worker, a database shared
|
|
72
|
+
* with another lists the other's migrations as undeclared, so `atMost: 0` would report a corrupted chain
|
|
73
|
+
* on a database that is entirely fine. Null is what a client reads as unknowable, never as healthy (#471).
|
|
74
|
+
*/
|
|
75
|
+
export declare const MIGRATION_HEALTH_KEYS: readonly [{
|
|
76
|
+
readonly key: "pendingMigrations";
|
|
77
|
+
readonly kind: "count";
|
|
78
|
+
readonly states: null;
|
|
79
|
+
readonly scope: string;
|
|
80
|
+
readonly cost: "indexed";
|
|
81
|
+
readonly summary: "Migrations this build declares that a bound database has not applied.";
|
|
82
|
+
readonly nominal: {
|
|
83
|
+
readonly atMost: 0;
|
|
84
|
+
};
|
|
85
|
+
}, {
|
|
86
|
+
readonly key: "undeclaredMigrations";
|
|
87
|
+
readonly kind: "count";
|
|
88
|
+
readonly states: null;
|
|
89
|
+
readonly scope: string;
|
|
90
|
+
readonly cost: "indexed";
|
|
91
|
+
readonly summary: "Migrations a bound database holds that this Worker does not declare. Relative to this Worker: a database shared with another lists that Worker's migrations here.";
|
|
92
|
+
readonly nominal: null;
|
|
93
|
+
}];
|
|
94
|
+
/**
|
|
95
|
+
* Total pending and undeclared across every bound database, for the manifest.
|
|
96
|
+
*
|
|
97
|
+
* **Throws rather than total a database it could not read.** A partial total is a zero for the database
|
|
98
|
+
* nobody read. The seam catches the throw and reports the summary `unavailable`, which a client reads as
|
|
99
|
+
* unknown — null is never zero.
|
|
100
|
+
*/
|
|
101
|
+
export declare function readMigrationHealth(env: Record<string, unknown>, databases: readonly ComposedMigrationDatabase[]): Promise<HealthSummary>;
|
|
102
|
+
//# sourceMappingURL=migrationState.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrationState.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/migrationState/migrationState.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAQ9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,qBAAqB,EAAsB,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGlG;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,qGAAqG;AACrG,MAAM,WAAW,yBAAyB;IACxC,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAC;IACjB,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,yFAAyF;IACzF,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,4EAA4E;IAC5E,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC;AAKD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,SAAS,UAAU,EAAE,GAAG,yBAAyB,EAAE,CAe1G;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,aAAa,CAElG;AA8BD;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,KAAK,EAAE,yBAAyB,EAChC,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,yBAAyB,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,GACxE,OAAO,CAAC,qBAAqB,CAAC,CAiBhC;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB;kBAEzB,mBAAmB;mBAClB,OAAO;;;mBAGP,SAAS;sBACN,uEAAuE;;iBACrE,MAAM,EAAE,CAAC;;;kBAGf,sBAAsB;mBACrB,OAAO;;;mBAGP,SAAS;sBAEb,mKAAmK;;EAGvH,CAAC;AAEnD;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,SAAS,EAAE,SAAS,yBAAyB,EAAE,GAC9C,OAAO,CAAC,aAAa,CAAC,CAQxB"}
|