@cosmicdrift/kumiko-dev-server 0.320.0 → 0.321.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-dev-server",
3
- "version": "0.320.0",
3
+ "version": "0.321.0",
4
4
  "description": "Dev-tooling for Kumiko apps: local dev-server bootstrap (runDevApp), scaffolding, codegen. Its compose-stacks/env-schema subpaths are consumed at prod boot too — see @cosmicdrift/kumiko-server-runtime for the prod runner itself.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -59,10 +59,10 @@
59
59
  "kumiko-upgrade": "./bin/kumiko-upgrade.ts"
60
60
  },
61
61
  "dependencies": {
62
- "@cosmicdrift/kumiko-bundled-features": "0.320.0",
63
- "@cosmicdrift/kumiko-framework": "0.320.0",
64
- "@cosmicdrift/kumiko-headless": "0.320.0",
65
- "@cosmicdrift/kumiko-server-runtime": "0.320.0",
62
+ "@cosmicdrift/kumiko-bundled-features": "0.321.0",
63
+ "@cosmicdrift/kumiko-framework": "0.321.0",
64
+ "@cosmicdrift/kumiko-headless": "0.321.0",
65
+ "@cosmicdrift/kumiko-server-runtime": "0.321.0",
66
66
  "ts-morph": "^28.0.0"
67
67
  },
68
68
  "publishConfig": {
@@ -14,6 +14,7 @@ import {
14
14
  TEXT_BLOCK_KIND,
15
15
  type TemplateResolverApi,
16
16
  } from "@cosmicdrift/kumiko-bundled-features/template-resolver";
17
+ import type { AnonymousExtraRoute } from "@cosmicdrift/kumiko-framework/api";
17
18
  import {
18
19
  createEntity,
19
20
  createTextField,
@@ -121,6 +122,46 @@ describe("runDevApp — auth allowedOrigins forwarding (#399/1)", () => {
121
122
  });
122
123
  });
123
124
 
125
+ describe("runDevApp — trustedProxyHops env fallback (KUMIKO_TRUSTED_PROXY_HOPS)", () => {
126
+ const clientIpRoute: AnonymousExtraRoute = {
127
+ method: "GET",
128
+ path: "/client-ip-probe",
129
+ entry: "anonymous",
130
+ handler: async (c, deps) => c.json({ clientIp: deps.clientIp }),
131
+ };
132
+
133
+ test("no trustedProxyHops option, env var set → env value reaches the server's client-ip resolver", async () => {
134
+ handle = await runDevApp({
135
+ features: [validFeature()],
136
+ port: 0,
137
+ extraRoutes: [clientIpRoute],
138
+ envSource: { ...process.env, KUMIKO_TRUSTED_PROXY_HOPS: "1" },
139
+ });
140
+ const res = await handle.fetch(
141
+ new Request("http://test/client-ip-probe", {
142
+ headers: { "x-forwarded-for": "203.0.113.10" },
143
+ }),
144
+ );
145
+ expect(await res.json()).toEqual({ clientIp: "203.0.113.10" });
146
+ });
147
+
148
+ test("explicit trustedProxyHops option wins over the env var", async () => {
149
+ handle = await runDevApp({
150
+ features: [validFeature()],
151
+ port: 0,
152
+ trustedProxyHops: 0,
153
+ extraRoutes: [clientIpRoute],
154
+ envSource: { ...process.env, KUMIKO_TRUSTED_PROXY_HOPS: "1" },
155
+ });
156
+ const res = await handle.fetch(
157
+ new Request("http://test/client-ip-probe", {
158
+ headers: { "x-forwarded-for": "203.0.113.10" },
159
+ }),
160
+ );
161
+ expect(await res.json()).toEqual({ clientIp: "unknown" });
162
+ });
163
+ });
164
+
124
165
  describe("runDevApp — extraContext merge order: app values win over boot defaults (707/1)", () => {
125
166
  test("a caller-supplied extraContext.templateResolver wins over the auto-wired boot default", async () => {
126
167
  // runDevApp's extraContext factory does `{ ...boot, ...base }` — boot's
package/src/changes.json CHANGED
@@ -1,4 +1,18 @@
1
1
  [
2
+ {
3
+ "version": "0.321.0",
4
+ "type": "improvement",
5
+ "title": "kumiko-upgrade gained --help/-h",
6
+ "detail": "Prints usage and exits 0 without running the upgrade report.",
7
+ "migration": "No action needed."
8
+ },
9
+ {
10
+ "version": "0.321.0",
11
+ "type": "improvement",
12
+ "title": "runDevApp now also honors KUMIKO_TRUSTED_PROXY_HOPS as an env fallback, symmetric to runProdApp",
13
+ "detail": "Precedence: `options.trustedProxyHops ?? effectiveAuth?.trustedProxyHops\n?? parseTrustedProxyHopsEnv(envSource[TRUSTED_PROXY_HOPS_ENV], \"runDevApp\")`.",
14
+ "migration": "No action needed for the default (unproxied) dev setup."
15
+ },
2
16
  {
3
17
  "version": "0.320.0",
4
18
  "type": "breaking",
@@ -49,7 +49,11 @@ import type {
49
49
  SessionMetadata,
50
50
  TokenVerifier,
51
51
  } from "@cosmicdrift/kumiko-framework/api";
52
- import { createInMemoryLoginRateLimiter } from "@cosmicdrift/kumiko-framework/api";
52
+ import {
53
+ createInMemoryLoginRateLimiter,
54
+ parseTrustedProxyHopsEnv,
55
+ TRUSTED_PROXY_HOPS_ENV,
56
+ } from "@cosmicdrift/kumiko-framework/api";
53
57
  import {
54
58
  configureBlindIndexKey,
55
59
  configurePiiSubjectKms,
@@ -279,8 +283,9 @@ export type RunDevAppOptions = {
279
283
  /** Forwarded to createKumikoServer → setupTestStack's top-level
280
284
  * `trustedProxyHops` — symmetric to
281
285
  * RunProdAppOptions.trustedProxyHops. Wins over the deprecated
282
- * `auth.trustedProxyHops`. Dev usually runs unproxied, so this is
283
- * normally left unset (default 0). */
286
+ * `auth.trustedProxyHops`, which wins over the `KUMIKO_TRUSTED_PROXY_HOPS`
287
+ * env var. Dev usually runs unproxied, so this is normally left unset
288
+ * (default 0). */
284
289
  readonly trustedProxyHops?: number;
285
290
  };
286
291
 
@@ -486,6 +491,11 @@ export async function runDevApp(options: RunDevAppOptions): Promise<KumikoServer
486
491
  }
487
492
  : {};
488
493
 
494
+ const trustedProxyHops =
495
+ options.trustedProxyHops ??
496
+ effectiveAuth?.trustedProxyHops ??
497
+ parseTrustedProxyHopsEnv(envSource[TRUSTED_PROXY_HOPS_ENV], "runDevApp");
498
+
489
499
  const handle = await createKumikoServer({
490
500
  features,
491
501
  ...(options.clientEntry !== undefined && { clientEntry: options.clientEntry }),
@@ -505,9 +515,7 @@ export async function runDevApp(options: RunDevAppOptions): Promise<KumikoServer
505
515
  ...(options.files !== undefined && { files: options.files }),
506
516
  ...(options.extraRoutes !== undefined && { extraRoutes: options.extraRoutes }),
507
517
  ...(options.wire !== undefined && { wire: options.wire }),
508
- ...((options.trustedProxyHops ?? effectiveAuth?.trustedProxyHops) !== undefined && {
509
- trustedProxyHops: options.trustedProxyHops ?? effectiveAuth?.trustedProxyHops,
510
- }),
518
+ ...(trustedProxyHops !== undefined && { trustedProxyHops }),
511
519
  ...(finalEffectiveFeatures !== undefined && {
512
520
  effectiveFeatures: finalEffectiveFeatures,
513
521
  }),