@cosmicdrift/kumiko-dispatcher-live 0.211.0 → 0.213.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-dispatcher-live",
3
- "version": "0.211.0",
3
+ "version": "0.213.0",
4
4
  "description": "HTTP-only Dispatcher for Kumiko UIs. Always-online; failures surface immediately. Default client for web admin/cockpit apps.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -24,7 +24,7 @@
24
24
  }
25
25
  },
26
26
  "dependencies": {
27
- "@cosmicdrift/kumiko-headless": "0.211.0"
27
+ "@cosmicdrift/kumiko-headless": "0.213.0"
28
28
  },
29
29
  "publishConfig": {
30
30
  "registry": "https://registry.npmjs.org",
@@ -15,6 +15,7 @@ import {
15
15
  } from "@cosmicdrift/kumiko-headless";
16
16
  import { CSRF_HEADER_NAME, readCsrfToken } from "./csrf";
17
17
  import { buildAbortError, buildNetworkError, mapServerError } from "./error-mapping";
18
+ import { LOCALE_HEADER_NAME, readActiveLocale } from "./locale";
18
19
  import { iterateSseChunks } from "./sse-stream";
19
20
 
20
21
  // HTTP-only dispatcher. Maps Kumiko's client-side Dispatcher contract to
@@ -103,6 +104,8 @@ export function createLiveDispatcher(options: LiveDispatcherOptions = {}): Dispa
103
104
  };
104
105
  const csrf = readCsrf();
105
106
  if (csrf !== undefined) headers[CSRF_HEADER_NAME] = csrf;
107
+ const locale = readActiveLocale();
108
+ if (locale !== undefined) headers[LOCALE_HEADER_NAME] = locale;
106
109
  // If no CSRF token, still send the request — public / pre-login
107
110
  // routes like /auth/login don't require CSRF, and POST /write/query/
108
111
  // batch against a logged-out client returns 401 via auth-middleware
@@ -204,6 +207,8 @@ export function createLiveDispatcher(options: LiveDispatcherOptions = {}): Dispa
204
207
  };
205
208
  const csrf = readCsrf();
206
209
  if (csrf !== undefined) headers[CSRF_HEADER_NAME] = csrf;
210
+ const locale = readActiveLocale();
211
+ if (locale !== undefined) headers[LOCALE_HEADER_NAME] = locale;
207
212
 
208
213
  let response: Response;
209
214
  try {
package/src/index.ts CHANGED
@@ -2,5 +2,6 @@ export { CSRF_COOKIE_NAME, CSRF_HEADER_NAME, readCsrfToken } from "./csrf";
2
2
  export type { LiveDispatcherOptions } from "./dispatcher-live";
3
3
  export { createLiveDispatcher } from "./dispatcher-live";
4
4
  export { buildAbortError, buildNetworkError, mapServerError } from "./error-mapping";
5
+ export { LOCALE_HEADER_NAME, readActiveLocale } from "./locale";
5
6
  export type { SseFrame } from "./sse-stream";
6
7
  export { iterateSseChunks, parseSseBlock, parseSseFrames } from "./sse-stream";
package/src/locale.ts ADDED
@@ -0,0 +1,22 @@
1
+ // Active-locale header transport for the live dispatcher.
2
+ //
3
+ // @cosmicdrift/kumiko-renderer-web's DocumentLangSync (mounted by
4
+ // createKumikoApp/createPublicSurface) keeps document.documentElement.lang in
5
+ // sync with the app's LocaleResolver. This module reads that value back so
6
+ // every outgoing request carries the language the user is ACTUALLY using —
7
+ // not the app's hardcoded boot language — with zero app-side wiring.
8
+
9
+ // Kept in sync with LOCALE_HEADER_NAME in api-constants.ts by hand rather
10
+ // than imported from @cosmicdrift/kumiko-framework — this package must
11
+ // remain server-dep-free (runs in browsers and React Native).
12
+ export const LOCALE_HEADER_NAME = "X-Locale";
13
+
14
+ // Reads document.documentElement.lang. Returns undefined for non-browser
15
+ // environments (SSR, Web Worker, React Native) or before any provider has
16
+ // set a lang yet — callers skip the header in that case and the server
17
+ // falls back to Accept-Language, then its boot default.
18
+ export function readActiveLocale(): string | undefined {
19
+ const g = globalThis as { document?: { documentElement?: { lang?: string } } };
20
+ const lang = g.document?.documentElement?.lang;
21
+ return lang !== undefined && lang.length > 0 ? lang : undefined;
22
+ }