@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
package/dist/logger/record.d.ts
CHANGED
|
@@ -107,6 +107,20 @@ export declare const LogRecord: z.ZodObject<{
|
|
|
107
107
|
detail: z.ZodOptional<z.ZodString>;
|
|
108
108
|
code: z.ZodLiteral<"auth/session_not_fresh">;
|
|
109
109
|
status: z.ZodLiteral<403>;
|
|
110
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
111
|
+
message: z.ZodString;
|
|
112
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
113
|
+
action: z.ZodOptional<z.ZodString>;
|
|
114
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
115
|
+
code: z.ZodLiteral<"auth/account_suspended">;
|
|
116
|
+
status: z.ZodLiteral<403>;
|
|
117
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
118
|
+
message: z.ZodString;
|
|
119
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
120
|
+
action: z.ZodOptional<z.ZodString>;
|
|
121
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
122
|
+
code: z.ZodLiteral<"auth/account_deleted">;
|
|
123
|
+
status: z.ZodLiteral<403>;
|
|
110
124
|
}, z.core.$strip>, z.ZodObject<{
|
|
111
125
|
message: z.ZodString;
|
|
112
126
|
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
@@ -310,6 +324,20 @@ export declare const LogRecord: z.ZodObject<{
|
|
|
310
324
|
detail: z.ZodOptional<z.ZodString>;
|
|
311
325
|
code: z.ZodLiteral<"turnstile/config">;
|
|
312
326
|
status: z.ZodLiteral<500>;
|
|
327
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
328
|
+
message: z.ZodString;
|
|
329
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
330
|
+
action: z.ZodOptional<z.ZodString>;
|
|
331
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
332
|
+
code: z.ZodLiteral<"turnstile/analytics_window">;
|
|
333
|
+
status: z.ZodLiteral<400>;
|
|
334
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
335
|
+
message: z.ZodString;
|
|
336
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
337
|
+
action: z.ZodOptional<z.ZodString>;
|
|
338
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
339
|
+
code: z.ZodLiteral<"turnstile/analytics_unavailable">;
|
|
340
|
+
status: z.ZodLiteral<409>;
|
|
313
341
|
}, z.core.$strip>, z.ZodObject<{
|
|
314
342
|
message: z.ZodString;
|
|
315
343
|
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
@@ -331,6 +359,13 @@ export declare const LogRecord: z.ZodObject<{
|
|
|
331
359
|
detail: z.ZodOptional<z.ZodString>;
|
|
332
360
|
code: z.ZodLiteral<"media/not_found">;
|
|
333
361
|
status: z.ZodLiteral<404>;
|
|
362
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
363
|
+
message: z.ZodString;
|
|
364
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
365
|
+
action: z.ZodOptional<z.ZodString>;
|
|
366
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
367
|
+
code: z.ZodLiteral<"media/forbidden">;
|
|
368
|
+
status: z.ZodLiteral<403>;
|
|
334
369
|
}, z.core.$strip>, z.ZodObject<{
|
|
335
370
|
message: z.ZodString;
|
|
336
371
|
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
@@ -352,6 +387,20 @@ export declare const LogRecord: z.ZodObject<{
|
|
|
352
387
|
detail: z.ZodOptional<z.ZodString>;
|
|
353
388
|
code: z.ZodLiteral<"media/enrichment_failed">;
|
|
354
389
|
status: z.ZodLiteral<500>;
|
|
390
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
391
|
+
message: z.ZodString;
|
|
392
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
393
|
+
action: z.ZodOptional<z.ZodString>;
|
|
394
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
395
|
+
code: z.ZodLiteral<"media/analytics_window">;
|
|
396
|
+
status: z.ZodLiteral<400>;
|
|
397
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
398
|
+
message: z.ZodString;
|
|
399
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
400
|
+
action: z.ZodOptional<z.ZodString>;
|
|
401
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
402
|
+
code: z.ZodLiteral<"media/analytics_unavailable">;
|
|
403
|
+
status: z.ZodLiteral<409>;
|
|
355
404
|
}, z.core.$strip>, z.ZodObject<{
|
|
356
405
|
message: z.ZodString;
|
|
357
406
|
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
@@ -786,6 +835,20 @@ export declare const LogRecord: z.ZodObject<{
|
|
|
786
835
|
detail: z.ZodOptional<z.ZodString>;
|
|
787
836
|
code: z.ZodLiteral<"payments/subscription_change_refused">;
|
|
788
837
|
status: z.ZodLiteral<409>;
|
|
838
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
839
|
+
message: z.ZodString;
|
|
840
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
841
|
+
action: z.ZodOptional<z.ZodString>;
|
|
842
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
843
|
+
code: z.ZodLiteral<"payments/override_stale">;
|
|
844
|
+
status: z.ZodLiteral<409>;
|
|
845
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
846
|
+
message: z.ZodString;
|
|
847
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
848
|
+
action: z.ZodOptional<z.ZodString>;
|
|
849
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
850
|
+
code: z.ZodLiteral<"payments/quota_exceeded">;
|
|
851
|
+
status: z.ZodLiteral<402>;
|
|
789
852
|
}, z.core.$strip>, z.ZodObject<{
|
|
790
853
|
message: z.ZodString;
|
|
791
854
|
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
@@ -870,6 +933,41 @@ export declare const LogRecord: z.ZodObject<{
|
|
|
870
933
|
detail: z.ZodOptional<z.ZodString>;
|
|
871
934
|
code: z.ZodLiteral<"organization/nomination_invalid">;
|
|
872
935
|
status: z.ZodLiteral<400>;
|
|
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/not_found">;
|
|
942
|
+
status: z.ZodLiteral<404>;
|
|
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/forbidden">;
|
|
949
|
+
status: z.ZodLiteral<403>;
|
|
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_name">;
|
|
956
|
+
status: z.ZodLiteral<400>;
|
|
957
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
958
|
+
message: z.ZodString;
|
|
959
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
960
|
+
action: z.ZodOptional<z.ZodString>;
|
|
961
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
962
|
+
code: z.ZodLiteral<"artifacts/name_taken">;
|
|
963
|
+
status: z.ZodLiteral<409>;
|
|
964
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
965
|
+
message: z.ZodString;
|
|
966
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
967
|
+
action: z.ZodOptional<z.ZodString>;
|
|
968
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
969
|
+
code: z.ZodLiteral<"artifacts/invalid_config">;
|
|
970
|
+
status: z.ZodLiteral<400>;
|
|
873
971
|
}, z.core.$strip>, z.ZodObject<{
|
|
874
972
|
message: z.ZodString;
|
|
875
973
|
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 };
|
|
@@ -25,6 +25,32 @@ export interface NamespacedMigrations {
|
|
|
25
25
|
*/
|
|
26
26
|
retained?: readonly string[];
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* The composed key for one of a set's migrations: `NNNN_<namespace>_<localKey>`. The one place the shape is
|
|
30
|
+
* written, so the registry and anything naming a declared migration's namespace build the same string.
|
|
31
|
+
*/
|
|
32
|
+
export declare function composedMigrationKey(set: Pick<NamespacedMigrations, "order" | "namespace">, localKey: string): string;
|
|
33
|
+
/** A composed key taken back apart: the three parts {@link createMigrationRegistry} joined. */
|
|
34
|
+
export interface ComposedMigrationKey {
|
|
35
|
+
/** The capability's `migrationOrder` — the zero-padded prefix, as a number. */
|
|
36
|
+
order: number;
|
|
37
|
+
/** The capability namespace — its `name`, which the manifest reports beside every capability. */
|
|
38
|
+
namespace: string;
|
|
39
|
+
/** The capability's own stable key, e.g. `0001_init`. */
|
|
40
|
+
localKey: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Take a composed key back apart — the inverse of the composition below.
|
|
44
|
+
*
|
|
45
|
+
* A declared migration's namespace is known from the set it came from. An **undeclared** one — applied in
|
|
46
|
+
* the database, carried by no provider this build composes — has nothing but its key, so this is the only
|
|
47
|
+
* way to say whose it was. **Null for a key no registry could have composed**, a migration written by hand
|
|
48
|
+
* or by another tool: guessing a namespace for it would be inventing one.
|
|
49
|
+
*
|
|
50
|
+
* The patterns are the same constants the composition enforces, so the two cannot disagree about what a
|
|
51
|
+
* key looks like.
|
|
52
|
+
*/
|
|
53
|
+
export declare function decomposeMigrationKey(key: string): ComposedMigrationKey | null;
|
|
28
54
|
/**
|
|
29
55
|
* Merge namespaced migration sets into one ordered `MigrationProvider` **per database** — matching
|
|
30
56
|
* multi-database D1, where each `c.var.db.<database>` is its own binding and schema. The result is
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/migrations/registry.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAOrE,4FAA4F;AAC5F,eAAO,MAAM,mBAAmB,QAAyB,CAAC;AAE1D,mGAAmG;AACnG,eAAO,MAAM,iBAAiB,QAAqB,CAAC;AAKpD,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,uFAAuF;IACvF,SAAS,EAAE,MAAM,CAAC;IAClB,wGAAwG;IACxG,KAAK,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACtC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9B;
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/migrations/registry.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAOrE,4FAA4F;AAC5F,eAAO,MAAM,mBAAmB,QAAyB,CAAC;AAE1D,mGAAmG;AACnG,eAAO,MAAM,iBAAiB,QAAqB,CAAC;AAKpD,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,uFAAuF;IACvF,SAAS,EAAE,MAAM,CAAC;IAClB,wGAAwG;IACxG,KAAK,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACtC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9B;AA0BD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,IAAI,CAAC,oBAAoB,EAAE,OAAO,GAAG,WAAW,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAErH;AAED,+FAA+F;AAC/F,MAAM,WAAW,oBAAoB;IACnC,+EAA+E;IAC/E,KAAK,EAAE,MAAM,CAAC;IACd,iGAAiG;IACjG,SAAS,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAUD;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,oBAAoB,GAAG,IAAI,CAM9E;AAuCD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,oBAAoB,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAavG"}
|
|
@@ -20,6 +20,40 @@ function assertValidOrder(order, namespace) {
|
|
|
20
20
|
function assertValidLocalKey(localKey, namespace) {
|
|
21
21
|
if (!LOCAL_KEY_PATTERN.test(localKey)) throw new InternalError({ message: `migration key "${localKey}" (namespace "${namespace}") must match ${LOCAL_KEY_PATTERN}` });
|
|
22
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* The composed key for one of a set's migrations: `NNNN_<namespace>_<localKey>`. The one place the shape is
|
|
25
|
+
* written, so the registry and anything naming a declared migration's namespace build the same string.
|
|
26
|
+
*/
|
|
27
|
+
function composedMigrationKey(set, localKey) {
|
|
28
|
+
return `${String(set.order).padStart(ORDER_DIGITS, "0")}_${set.namespace}_${localKey}`;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The composed key shape, anchored at both ends: the order prefix, a namespace (which admits no separator,
|
|
32
|
+
* so the first underscore after it is the boundary), then a local key, which may hold any number.
|
|
33
|
+
*/
|
|
34
|
+
const COMPOSED_KEY_PATTERN = new RegExp(`^(\\d{${ORDER_DIGITS}})_(${NAMESPACE_PATTERN.source.slice(1, -1)})_(${LOCAL_KEY_PATTERN.source.slice(1, -1)})$`);
|
|
35
|
+
/**
|
|
36
|
+
* Take a composed key back apart — the inverse of the composition below.
|
|
37
|
+
*
|
|
38
|
+
* A declared migration's namespace is known from the set it came from. An **undeclared** one — applied in
|
|
39
|
+
* the database, carried by no provider this build composes — has nothing but its key, so this is the only
|
|
40
|
+
* way to say whose it was. **Null for a key no registry could have composed**, a migration written by hand
|
|
41
|
+
* or by another tool: guessing a namespace for it would be inventing one.
|
|
42
|
+
*
|
|
43
|
+
* The patterns are the same constants the composition enforces, so the two cannot disagree about what a
|
|
44
|
+
* key looks like.
|
|
45
|
+
*/
|
|
46
|
+
function decomposeMigrationKey(key) {
|
|
47
|
+
const match = COMPOSED_KEY_PATTERN.exec(key);
|
|
48
|
+
if (!match) return null;
|
|
49
|
+
const [, order, namespace, localKey] = match;
|
|
50
|
+
if (order === void 0 || namespace === void 0 || localKey === void 0) return null;
|
|
51
|
+
return {
|
|
52
|
+
order: Number(order),
|
|
53
|
+
namespace,
|
|
54
|
+
localKey
|
|
55
|
+
};
|
|
56
|
+
}
|
|
23
57
|
/** Merge one database's sets into a provider, enforcing the per-database invariants. */
|
|
24
58
|
function composeDatabase(database, sets) {
|
|
25
59
|
const seenOrders = /* @__PURE__ */ new Set();
|
|
@@ -34,12 +68,9 @@ function composeDatabase(database, sets) {
|
|
|
34
68
|
seenNamespaces.add(set.namespace);
|
|
35
69
|
}
|
|
36
70
|
const composed = {};
|
|
37
|
-
for (const set of [...sets].sort((a, b) => a.order - b.order)) {
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
const migration = set.migrations[localKey];
|
|
41
|
-
if (migration) composed[`${prefix}_${set.namespace}_${localKey}`] = migration;
|
|
42
|
-
}
|
|
71
|
+
for (const set of [...sets].sort((a, b) => a.order - b.order)) for (const localKey of Object.keys(set.migrations).sort()) {
|
|
72
|
+
const migration = set.migrations[localKey];
|
|
73
|
+
if (migration) composed[composedMigrationKey(set, localKey)] = migration;
|
|
43
74
|
}
|
|
44
75
|
for (const set of sets) declareRetained(set.migrations, set.retained ?? []);
|
|
45
76
|
return { getMigrations: async () => composed };
|
|
@@ -71,4 +102,4 @@ function createMigrationRegistry(sets) {
|
|
|
71
102
|
return registry;
|
|
72
103
|
}
|
|
73
104
|
//#endregion
|
|
74
|
-
export { MAX_MIGRATION_ORDER, NAMESPACE_PATTERN, createMigrationRegistry };
|
|
105
|
+
export { MAX_MIGRATION_ORDER, NAMESPACE_PATTERN, composedMigrationKey, createMigrationRegistry, decomposeMigrationKey };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 Pithy
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
import type { D1Database } from "@cloudflare/workers-types";
|
|
4
|
+
import type { MigrationProvider } from "kysely/migration";
|
|
5
|
+
/**
|
|
6
|
+
* **Where one database stands, read in one place (#729).**
|
|
7
|
+
*
|
|
8
|
+
* The control-plane seam answers `GET {basePath}/migrations` from this: what is applied, what this build
|
|
9
|
+
* declares and the database lacks, what the database holds and this build no longer declares, and which
|
|
10
|
+
* run put it there. Each half already had a reader — {@link readMigrationLedger} for both directions,
|
|
11
|
+
* {@link readMigrationGroups} and {@link readGroupPosition} for the group (#694) — and this composes them
|
|
12
|
+
* rather than reading either table a second way.
|
|
13
|
+
*
|
|
14
|
+
* Read-only. It applies nothing, creates nothing, and reverses nothing: a screen somebody opened to *ask*
|
|
15
|
+
* must not be the thing that changes the schema.
|
|
16
|
+
*/
|
|
17
|
+
/** Whether the last group can still be taken back by name — {@link readGroupPosition}, minus `absent`. */
|
|
18
|
+
export type MigrationGroupStanding = {
|
|
19
|
+
/** The group's migrations are the contiguous tip of this ledger. The CLI's rollback has refusals of its own. */
|
|
20
|
+
state: "top";
|
|
21
|
+
} | {
|
|
22
|
+
/** Something sits over the group or inside it, so reversing it by name is refused. */
|
|
23
|
+
state: "buried";
|
|
24
|
+
/** The groups in the way, newest first. */
|
|
25
|
+
above: string[];
|
|
26
|
+
/** The migrations in the way that no group claims, newest first. */
|
|
27
|
+
ungrouped: string[];
|
|
28
|
+
};
|
|
29
|
+
/** The newest group with anything still applied here, and whether it is still reversible. */
|
|
30
|
+
export interface MigrationLastGroup {
|
|
31
|
+
/** The group's value — what `--rollback --group` takes. */
|
|
32
|
+
group: string;
|
|
33
|
+
/** When it last applied something here. */
|
|
34
|
+
appliedAt: Date;
|
|
35
|
+
/** What it applied here and is still applied, in application order. */
|
|
36
|
+
migrations: string[];
|
|
37
|
+
/** Whether it is the tip of the chain, or what is in its way. */
|
|
38
|
+
position: MigrationGroupStanding;
|
|
39
|
+
}
|
|
40
|
+
/** One database's migration state. */
|
|
41
|
+
export interface MigrationState {
|
|
42
|
+
/** Every applied migration, in the order the ledger applied them. */
|
|
43
|
+
applied: string[];
|
|
44
|
+
/** Declared and not yet applied, in the order they would run. */
|
|
45
|
+
pending: string[];
|
|
46
|
+
/** Applied and not declared by this build, sorted. Kysely refuses the whole chain on any one of these. */
|
|
47
|
+
undeclared: string[];
|
|
48
|
+
/** The newest group with anything applied here, or null when nothing applied here was ever grouped. */
|
|
49
|
+
lastGroup: MigrationLastGroup | null;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Read one database's migration state against the provider this build composes for it.
|
|
53
|
+
*
|
|
54
|
+
* **The last group is the newest one with something still applied.** Group rows are forgotten as their
|
|
55
|
+
* migrations come down, so this is ordinarily the newest group recorded. A group whose rows outlived their
|
|
56
|
+
* ledger rows reads as `absent` and is passed over: naming it as where the environment stands would name a
|
|
57
|
+
* release that is no longer in the database.
|
|
58
|
+
*/
|
|
59
|
+
export declare function readMigrationState(database: D1Database, provider: MigrationProvider): Promise<MigrationState>;
|
|
60
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/migrations/state.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAK1D;;;;;;;;;;;GAWG;AAEH,0GAA0G;AAC1G,MAAM,MAAM,sBAAsB,GAC9B;IACE,gHAAgH;IAChH,KAAK,EAAE,KAAK,CAAC;CACd,GACD;IACE,sFAAsF;IACtF,KAAK,EAAE,QAAQ,CAAC;IAChB,2CAA2C;IAC3C,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,oEAAoE;IACpE,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB,CAAC;AAEN,6FAA6F;AAC7F,MAAM,WAAW,kBAAkB;IACjC,2DAA2D;IAC3D,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,SAAS,EAAE,IAAI,CAAC;IAChB,uEAAuE;IACvE,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,iEAAiE;IACjE,QAAQ,EAAE,sBAAsB,CAAC;CAClC;AAED,sCAAsC;AACtC,MAAM,WAAW,cAAc;IAC7B,qEAAqE;IACrE,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,iEAAiE;IACjE,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,0GAA0G;IAC1G,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,uGAAuG;IACvG,SAAS,EAAE,kBAAkB,GAAG,IAAI,CAAC;CACtC;AAED;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,CAAC,CAInH"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 Pithy
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
import { appliedMigrationChain, migrationKysely } from "./bookkeeping.js";
|
|
4
|
+
import { readGroupPosition, readMigrationGroups } from "./groups.js";
|
|
5
|
+
import { readMigrationLedger } from "./runner.js";
|
|
6
|
+
//#region src/migrations/state.ts
|
|
7
|
+
/**
|
|
8
|
+
* Read one database's migration state against the provider this build composes for it.
|
|
9
|
+
*
|
|
10
|
+
* **The last group is the newest one with something still applied.** Group rows are forgotten as their
|
|
11
|
+
* migrations come down, so this is ordinarily the newest group recorded. A group whose rows outlived their
|
|
12
|
+
* ledger rows reads as `absent` and is passed over: naming it as where the environment stands would name a
|
|
13
|
+
* release that is no longer in the database.
|
|
14
|
+
*/
|
|
15
|
+
async function readMigrationState(database, provider) {
|
|
16
|
+
const { pending, undeclared } = await readMigrationLedger(database, provider);
|
|
17
|
+
const applied = await appliedMigrationChain(migrationKysely(database));
|
|
18
|
+
return {
|
|
19
|
+
applied,
|
|
20
|
+
pending,
|
|
21
|
+
undeclared,
|
|
22
|
+
lastGroup: await lastGroupOf(database, applied)
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/** Walk the groups newest first and stop at the first one this database still holds any of. */
|
|
26
|
+
async function lastGroupOf(database, applied) {
|
|
27
|
+
const held = new Set(applied);
|
|
28
|
+
const groups = await readMigrationGroups(database);
|
|
29
|
+
for (const group of [...groups].reverse()) {
|
|
30
|
+
const position = await readGroupPosition(database, group.group);
|
|
31
|
+
if (position.state === "absent") continue;
|
|
32
|
+
return {
|
|
33
|
+
group: group.group,
|
|
34
|
+
appliedAt: group.appliedAt,
|
|
35
|
+
migrations: group.migrations.filter((name) => held.has(name)),
|
|
36
|
+
position: position.state === "top" ? { state: "top" } : {
|
|
37
|
+
state: "buried",
|
|
38
|
+
above: position.above,
|
|
39
|
+
ungrouped: position.ungrouped
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
46
|
+
export { readMigrationState };
|
package/dist/naming/feature.d.ts
CHANGED
|
@@ -27,10 +27,19 @@
|
|
|
27
27
|
* It lives in `core`, beside the rest of the naming rule, so the CLI and the facade compose one
|
|
28
28
|
* implementation rather than two that drift.
|
|
29
29
|
*/
|
|
30
|
-
/** A Cloudflare resource kind
|
|
31
|
-
export type FeatureResourceKind = "d1" | "kv" | "r2";
|
|
30
|
+
/** A Cloudflare resource kind Pithy names and creates — in a feature, and in every declared environment. */
|
|
31
|
+
export type FeatureResourceKind = "d1" | "kv" | "r2" | "queue";
|
|
32
32
|
/** Every feature resource kind, for tests and for callers that enumerate. */
|
|
33
33
|
export declare const FEATURE_RESOURCE_KINDS: readonly FeatureResourceKind[];
|
|
34
|
+
/**
|
|
35
|
+
* **The segment each kind ends a feature resource's name with — never more than `MAX_FEATURE_KIND` (#662).**
|
|
36
|
+
*
|
|
37
|
+
* `d1`, `kv` and `r2` spell themselves. A queue is `q`, and that is load-bearing: `MAX_FEATURE_KIND` is a term in
|
|
38
|
+
* `FEATURE_DERIVED_PROJECT_NAME`, so spelling it `queue` would take the project budget from 26 to 23 — and a
|
|
39
|
+
* project name is stable forever once anything is provisioned, so a smaller budget orphans every resource of a
|
|
40
|
+
* project already named against the old one. `feature.test.ts` fails on a segment longer than the budget.
|
|
41
|
+
*/
|
|
42
|
+
export declare const FEATURE_KIND_SEGMENT: Readonly<Record<FeatureResourceKind, string>>;
|
|
34
43
|
/** The identity of a feature — everything a feature name is derived from. */
|
|
35
44
|
export interface FeatureIdentity {
|
|
36
45
|
/** The project name, from the root `pithy.config.ts` (e.g. `acme`). */
|
|
@@ -126,10 +135,11 @@ export declare function maxFeatureSlug(parts: FeatureHead, shapes: readonly Feat
|
|
|
126
135
|
*/
|
|
127
136
|
export declare function assertFeatureSlugFits(identity: FeatureIdentity, shapes: readonly FeatureNameShape[]): void;
|
|
128
137
|
/**
|
|
129
|
-
* The full Cloudflare resource name for a feature's binding — `<project>-f<issue>-<slug>--<binding>-<kind
|
|
138
|
+
* The full Cloudflare resource name for a feature's binding — `<project>-f<issue>-<slug>--<binding>-<kind>`, the
|
|
139
|
+
* kind spelled by {@link FEATURE_KIND_SEGMENT}.
|
|
130
140
|
*
|
|
131
|
-
* Held to **R2's 63**, the strictest of the
|
|
132
|
-
* all of them: lowercase, hyphenated, alphanumeric at both ends. A D1 or KV name could be longer, but a
|
|
141
|
+
* Held to **R2's 63**, the strictest of the kinds a feature provisions and a queue's number too, so one shape is
|
|
142
|
+
* legal for all of them: lowercase, hyphenated, alphanumeric at both ends. A D1 or KV name could be longer, but a
|
|
133
143
|
* feature that provisions a bucket and a database wants them recognizably the same name.
|
|
134
144
|
*/
|
|
135
145
|
export declare function featureResourceName(identity: FeatureIdentity, binding: string, kind: FeatureResourceKind): string;
|
|
@@ -168,6 +178,18 @@ export declare function featureSecretEntryName(identity: FeatureIdentity, secret
|
|
|
168
178
|
* and picks.
|
|
169
179
|
*/
|
|
170
180
|
export declare function featureWorkerName(identity: FeatureIdentity, app: string): string;
|
|
181
|
+
/** The `<thing>` a feature's Artifacts namespace ends with, after {@link FEATURE_TAIL_SEPARATOR} (#673). */
|
|
182
|
+
export declare const FEATURE_ARTIFACTS_THING = "artifacts";
|
|
183
|
+
/**
|
|
184
|
+
* A feature's **Artifacts namespace** — `<project>-f<issue>-<slug>--artifacts` (#673).
|
|
185
|
+
*
|
|
186
|
+
* A declared environment's namespace is `<project>-<env>` and has no `<thing>`. A feature's needs one, because the
|
|
187
|
+
* separator and what follows it are what make a name a feature name: {@link isFeatureOwnedName} reads this one back
|
|
188
|
+
* as this feature's, so `pithy feature destroy` reaps the repos of exactly this branch and of no sibling. Held to the
|
|
189
|
+
* namespace's 63, the same number the rest of a feature's names are derived against, and `artifacts` is shorter than
|
|
190
|
+
* the shortest binding tail, so it moves no slug budget.
|
|
191
|
+
*/
|
|
192
|
+
export declare function featureArtifactsNamespace(identity: FeatureIdentity): string;
|
|
171
193
|
/**
|
|
172
194
|
* The deployed name of one of a feature's **Workflows** — `<project>-f<issue>-<slug>--<capability>-<job>` (#643).
|
|
173
195
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature.d.ts","sourceRoot":"","sources":["../../src/naming/feature.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,
|
|
1
|
+
{"version":3,"file":"feature.d.ts","sourceRoot":"","sources":["../../src/naming/feature.ts"],"names":[],"mappings":"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"}
|
package/dist/naming/feature.js
CHANGED
|
@@ -9,9 +9,24 @@ import { assertValidProjectName, kebab } from "./resource.js";
|
|
|
9
9
|
const FEATURE_RESOURCE_KINDS = [
|
|
10
10
|
"d1",
|
|
11
11
|
"kv",
|
|
12
|
-
"r2"
|
|
12
|
+
"r2",
|
|
13
|
+
"queue"
|
|
13
14
|
];
|
|
14
15
|
/**
|
|
16
|
+
* **The segment each kind ends a feature resource's name with — never more than `MAX_FEATURE_KIND` (#662).**
|
|
17
|
+
*
|
|
18
|
+
* `d1`, `kv` and `r2` spell themselves. A queue is `q`, and that is load-bearing: `MAX_FEATURE_KIND` is a term in
|
|
19
|
+
* `FEATURE_DERIVED_PROJECT_NAME`, so spelling it `queue` would take the project budget from 26 to 23 — and a
|
|
20
|
+
* project name is stable forever once anything is provisioned, so a smaller budget orphans every resource of a
|
|
21
|
+
* project already named against the old one. `feature.test.ts` fails on a segment longer than the budget.
|
|
22
|
+
*/
|
|
23
|
+
const FEATURE_KIND_SEGMENT = {
|
|
24
|
+
d1: "d1",
|
|
25
|
+
kv: "kv",
|
|
26
|
+
r2: "r2",
|
|
27
|
+
queue: "q"
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
15
30
|
* Refuse an issue number the budgets were not derived against.
|
|
16
31
|
*
|
|
17
32
|
* `MAX_ISSUE_DIGITS` is a term in {@link FEATURE_DERIVED_PROJECT_NAME}, so an eight-digit issue would
|
|
@@ -193,14 +208,15 @@ function assertFeatureSlugFits(identity, shapes) {
|
|
|
193
208
|
});
|
|
194
209
|
}
|
|
195
210
|
/**
|
|
196
|
-
* The full Cloudflare resource name for a feature's binding — `<project>-f<issue>-<slug>--<binding>-<kind
|
|
211
|
+
* The full Cloudflare resource name for a feature's binding — `<project>-f<issue>-<slug>--<binding>-<kind>`, the
|
|
212
|
+
* kind spelled by {@link FEATURE_KIND_SEGMENT}.
|
|
197
213
|
*
|
|
198
|
-
* Held to **R2's 63**, the strictest of the
|
|
199
|
-
* all of them: lowercase, hyphenated, alphanumeric at both ends. A D1 or KV name could be longer, but a
|
|
214
|
+
* Held to **R2's 63**, the strictest of the kinds a feature provisions and a queue's number too, so one shape is
|
|
215
|
+
* legal for all of them: lowercase, hyphenated, alphanumeric at both ends. A D1 or KV name could be longer, but a
|
|
200
216
|
* feature that provisions a bucket and a database wants them recognizably the same name.
|
|
201
217
|
*/
|
|
202
218
|
function featureResourceName(identity, binding, kind) {
|
|
203
|
-
return composeFeatureName(identity, kebab(identity.slug), kebab(binding), `-${kind}`, NAMESPACE_LIMITS.r2.maxLength, NAMESPACE_LIMITS.r2.label);
|
|
219
|
+
return composeFeatureName(identity, kebab(identity.slug), kebab(binding), `-${FEATURE_KIND_SEGMENT[kind]}`, NAMESPACE_LIMITS.r2.maxLength, NAMESPACE_LIMITS.r2.label);
|
|
204
220
|
}
|
|
205
221
|
/**
|
|
206
222
|
* The CF Secrets Store entry name holding one of a feature's **environment-scoped** secrets —
|
|
@@ -241,6 +257,20 @@ function featureSecretEntryName(identity, secret) {
|
|
|
241
257
|
function featureWorkerName(identity, app) {
|
|
242
258
|
return composeFeatureName(identity, kebab(identity.slug), kebab(app), "", NAMESPACE_LIMITS.worker.maxLength, NAMESPACE_LIMITS.worker.label);
|
|
243
259
|
}
|
|
260
|
+
/** The `<thing>` a feature's Artifacts namespace ends with, after {@link FEATURE_TAIL_SEPARATOR} (#673). */
|
|
261
|
+
const FEATURE_ARTIFACTS_THING = "artifacts";
|
|
262
|
+
/**
|
|
263
|
+
* A feature's **Artifacts namespace** — `<project>-f<issue>-<slug>--artifacts` (#673).
|
|
264
|
+
*
|
|
265
|
+
* A declared environment's namespace is `<project>-<env>` and has no `<thing>`. A feature's needs one, because the
|
|
266
|
+
* separator and what follows it are what make a name a feature name: {@link isFeatureOwnedName} reads this one back
|
|
267
|
+
* as this feature's, so `pithy feature destroy` reaps the repos of exactly this branch and of no sibling. Held to the
|
|
268
|
+
* namespace's 63, the same number the rest of a feature's names are derived against, and `artifacts` is shorter than
|
|
269
|
+
* the shortest binding tail, so it moves no slug budget.
|
|
270
|
+
*/
|
|
271
|
+
function featureArtifactsNamespace(identity) {
|
|
272
|
+
return composeFeatureName(identity, kebab(identity.slug), FEATURE_ARTIFACTS_THING, "", NAMESPACE_LIMITS.artifactsNamespace.maxLength, NAMESPACE_LIMITS.artifactsNamespace.label);
|
|
273
|
+
}
|
|
244
274
|
/**
|
|
245
275
|
* The deployed name of one of a feature's **Workflows** — `<project>-f<issue>-<slug>--<capability>-<job>` (#643).
|
|
246
276
|
*
|
|
@@ -266,4 +296,4 @@ function featureVectorizeIndexName(identity, thing) {
|
|
|
266
296
|
return composeFeatureName(identity, kebab(identity.slug), kebab(thing), "", NAMESPACE_LIMITS.vectorizeIndex.maxLength, NAMESPACE_LIMITS.vectorizeIndex.label);
|
|
267
297
|
}
|
|
268
298
|
//#endregion
|
|
269
|
-
export { FEATURE_RESOURCE_KINDS, assertFeatureProject, assertFeatureSlugFits, canonicalIssue, featureMarkerInProjectName, featureResourceName, featureSecretEntryName, featureSlugRoom, featureVectorizeIndexName, featureWorkerName, featureWorkflowName, isFeatureOwnedName, maxFeatureSlug, parseFeatureName, tightestFeatureShape };
|
|
299
|
+
export { FEATURE_ARTIFACTS_THING, FEATURE_KIND_SEGMENT, FEATURE_RESOURCE_KINDS, assertFeatureProject, assertFeatureSlugFits, canonicalIssue, featureArtifactsNamespace, featureMarkerInProjectName, featureResourceName, featureSecretEntryName, featureSlugRoom, featureVectorizeIndexName, featureWorkerName, featureWorkflowName, isFeatureOwnedName, maxFeatureSlug, parseFeatureName, tightestFeatureShape };
|