@cosmicdrift/kumiko-server-runtime 0.200.1 → 0.201.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-server-runtime",
3
- "version": "0.200.1",
3
+ "version": "0.201.0",
4
4
  "description": "Production server-boot runtime for Kumiko apps: connections, schema-drift-gate, seeds, lifecycle, graceful shutdown. Symmetric to kumiko-dev-server's runDevApp, without dev/scaffold/codegen tooling.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -80,8 +80,8 @@
80
80
  }
81
81
  },
82
82
  "dependencies": {
83
- "@cosmicdrift/kumiko-bundled-features": "0.200.1",
84
- "@cosmicdrift/kumiko-framework": "0.200.1",
83
+ "@cosmicdrift/kumiko-bundled-features": "0.201.0",
84
+ "@cosmicdrift/kumiko-framework": "0.201.0",
85
85
  "temporal-polyfill": "^0.3.2"
86
86
  },
87
87
  "publishConfig": {
@@ -1,6 +1,9 @@
1
1
  import { makeAuthPaths } from "@cosmicdrift/kumiko-bundled-features/auth-email-password";
2
2
  import { resolveSessionStore } from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
3
- import { bindMfaRevokeAllOtherSessionsFromFeature } from "@cosmicdrift/kumiko-bundled-features/auth-mfa";
3
+ import {
4
+ bindMfaRevokeAllOtherSessionsFromFeature,
5
+ bindRevokeAllPatTokensFromFeature,
6
+ } from "@cosmicdrift/kumiko-bundled-features/auth-mfa";
4
7
  import { createSmtpTransportFromEnv } from "@cosmicdrift/kumiko-bundled-features/channel-email";
5
8
  import {
6
9
  buildEnvConfigOverrides,
@@ -12,6 +15,10 @@ import {
12
15
  createDeliveryService,
13
16
  DELIVERY_FEATURE,
14
17
  } from "@cosmicdrift/kumiko-bundled-features/delivery";
18
+ import {
19
+ bindPatAutoRevokeOnPasswordChangeFromFeature,
20
+ revokeAllPatTokensForUser,
21
+ } from "@cosmicdrift/kumiko-bundled-features/personal-access-tokens";
15
22
  import {
16
23
  createSecretsContext,
17
24
  SECRETS_FEATURE_NAME,
@@ -215,6 +222,7 @@ export async function buildProdSessionAuth(
215
222
  registry: Registry,
216
223
  sessionsFeature: FeatureDefinition | undefined,
217
224
  mfaFeature: FeatureDefinition | undefined,
225
+ patFeature: FeatureDefinition | undefined,
218
226
  ): Promise<{
219
227
  readonly sessionCreator: Awaited<ReturnType<typeof resolveSessionStore>>["creator"];
220
228
  readonly sessionRevoker: Awaited<ReturnType<typeof resolveSessionStore>>["revoker"];
@@ -228,9 +236,26 @@ export async function buildProdSessionAuth(
228
236
  if (mfaFeature) {
229
237
  bindMfaRevokeAllOtherSessionsFromFeature(mfaFeature)?.(store.revokeAllOthers);
230
238
  }
239
+ if (mfaFeature && patFeature) {
240
+ bindRevokeAllPatTokensFromFeature(mfaFeature)?.((userId) =>
241
+ revokeAllPatTokensForUser(db, userId),
242
+ );
243
+ }
231
244
  return {
232
245
  sessionCreator: store.creator,
233
246
  sessionRevoker: store.revoker,
234
247
  sessionChecker: store.checker,
235
248
  };
236
249
  }
250
+
251
+ // Password-change → PAT-revoke, independent of sessions/MFA being mounted
252
+ // (unlike buildProdSessionAuth, which only runs when a sessionStore provider
253
+ // is registered). Call unconditionally whenever personal-access-tokens is
254
+ // mounted — a no-op if it isn't (bindPatAutoRevokeOnPasswordChangeFromFeature
255
+ // returns undefined for an unmounted feature.exports shape, but callers
256
+ // should still gate on patFeature being defined at all).
257
+ export function wireProdPatAutoRevoke(db: DbConnection, patFeature: FeatureDefinition): void {
258
+ bindPatAutoRevokeOnPasswordChangeFromFeature(patFeature)?.((userId) =>
259
+ revokeAllPatTokensForUser(db, userId),
260
+ );
261
+ }
@@ -148,6 +148,7 @@ import {
148
148
  buildBootExtraContext,
149
149
  buildProdSessionAuth,
150
150
  resolveAuthMail,
151
+ wireProdPatAutoRevoke,
151
152
  } from "./run-prod-app-boot-context";
152
153
  import { buildStaticFallback } from "./run-prod-app-static-files";
153
154
  import { type SecurityHeadersOption, withSecurityHeaders } from "./security-headers";
@@ -955,20 +956,30 @@ export async function runProdApp(options: RunProdAppOptions): Promise<ProdAppHan
955
956
  // über die auth-routes.
956
957
  // Secure-by-default (#1372): sessionStore provider → resolveSessionStore.
957
958
  const mfaFeature = features.find((f) => f.name === AUTH_MFA_FEATURE);
959
+ // Hoisted above buildProdSessionAuth: that call also wires MFA-enable/
960
+ // disable → PAT-revoke (bindRevokeAllPatTokensFromFeature), so it needs
961
+ // patFeature too.
962
+ const patFeature = features.find((f) => f.name === PAT_FEATURE);
958
963
  const sessionAuthFragment = shouldWireProdSessions(
959
964
  Boolean(effectiveAuth),
960
965
  registry.getExtensionUsages(EXT_SESSION_STORE).length > 0,
961
966
  )
962
- ? await buildProdSessionAuth(db, registry, sessionsFeature, mfaFeature)
967
+ ? await buildProdSessionAuth(db, registry, sessionsFeature, mfaFeature, patFeature)
963
968
  : undefined;
964
969
 
970
+ // Password-change → PAT-revoke: independent of sessions/MFA being mounted
971
+ // (buildProdSessionAuth only runs when a sessionStore provider is
972
+ // registered), so wired unconditionally here whenever PAT itself is.
973
+ if (patFeature) {
974
+ wireProdPatAutoRevoke(db, patFeature);
975
+ }
976
+
965
977
  // Token-verifier opt-in: any provider feature (personal-access-tokens, a
966
978
  // future auth-provider-jwt, ...) self-registers via
967
979
  // r.useExtension(EXT_TOKEN_VERIFIER, ...) — wire one generic resolver
968
980
  // whenever at least one is mounted, resolved by shape at request-time.
969
981
  // PAT keeps its own per-token rate limiter (patRateLimiter), unrelated to
970
982
  // verification.
971
- const patFeature = features.find((f) => f.name === PAT_FEATURE);
972
983
  const hasTokenVerifierProviders = registry.getExtensionUsages(EXT_TOKEN_VERIFIER).length > 0;
973
984
  let patAuthFragment:
974
985
  | {