akanjs 2.2.3 → 2.2.4-rc.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # akanjs
2
2
 
3
+ ## 2.2.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 587cc68: fix dictionary loading
8
+ - 587cc68: fix fetchClient for setting origin with clone or fetchPolicy
9
+
3
10
  ## 2.2.0
4
11
 
5
12
  ### Minor Changes
@@ -25,8 +25,11 @@ const getPageInfo = (): { locale: string; path: string } => {
25
25
  const localeSet = new Set(locales);
26
26
  if (getEnv().side !== "server") {
27
27
  const [, firstSegment = "", ...rest] = window.location.pathname.split("/");
28
- if (localeSet.has(firstSegment)) return { locale: firstSegment, path: `/${rest.join("/")}` };
29
- return { locale: defaultLocale, path: window.location.pathname };
28
+ const hasLocalePrefix = localeSet.has(firstSegment);
29
+
30
+ const activeLocale = Translator.getActiveLocale();
31
+ const locale = activeLocale ?? (hasLocalePrefix ? firstSegment : defaultLocale);
32
+ return { locale, path: hasLocalePrefix ? `/${rest.join("/")}` : window.location.pathname };
30
33
  }
31
34
  const h = headers();
32
35
 
@@ -13,6 +13,14 @@ export class Translator {
13
13
  static #langDictionaryMap = new Map<string, Dictionary>();
14
14
 
15
15
  static #seededDicts = new WeakSet<object>();
16
+
17
+ static #activeLocale: string | undefined;
18
+ static setActiveLocale(lang: string | undefined) {
19
+ if (lang) Translator.#activeLocale = lang;
20
+ }
21
+ static getActiveLocale(): string | undefined {
22
+ return Translator.#activeLocale;
23
+ }
16
24
  constructor(dictionary: Record<string, Record<string, Record<string, unknown>>>) {
17
25
  Object.entries(dictionary).forEach(([lang, dictionary]) => {
18
26
  this.#setDictionary(lang, dictionary);
@@ -10,6 +10,7 @@ import type {
10
10
  SerializedSlice,
11
11
  ServiceSignal,
12
12
  } from "akanjs/signal";
13
+ import { fileUploadContract, resolveFileUploadCapability } from "akanjs/signal/fileUpload";
13
14
  import type { ClientSignal, MergeAllFetchTypes, SliceMeta } from "../fetchType";
14
15
  import { memoizeRequestQuery, cookies as requestCookies, headers as requestHeaders } from "../requestStorage";
15
16
  import type { GetSliceMetaObjFromDatabaseSignals } from "../types";
@@ -362,18 +363,20 @@ export class FetchClient {
362
363
 
363
364
  Object.assign(this.handler, {
364
365
  [names.addModelFiles]: async (fileList: FileList, parentId?: string, option?: FetchPolicy) => {
366
+ const cap = resolveFileUploadCapability(this.serializedSignal);
367
+ const endpoint = cap ? this.serializedSignal[cap.refName]?.endpoint[cap.endpointKey] : undefined;
368
+ if (!cap || !endpoint)
369
+ throw new Error(
370
+ "File upload is not configured. Mark an upload mutation with { fileUpload: true } (e.g. shared FileEndpoint.addFiles).",
371
+ );
372
+ const { fields, buildMetas } = fileUploadContract;
365
373
  const formData = new FormData();
366
- for (let i = 0; i < fileList.length; i++) formData.append("files", fileList[i]);
367
- const metas = Array.from(fileList).map((f) => ({
368
- lastModifiedAt: new Date(f.lastModified).toISOString(),
369
- size: f.size,
370
- }));
371
- formData.append("metas", JSON.stringify(metas));
372
- formData.append("type", refName);
373
- if (parentId) formData.append("parentId", parentId);
374
- return await this.http.post(`/file/addFilesRestApi`, formData, {
375
- headers: { ...(this.jwt ? { Authorization: `Bearer ${this.jwt}` } : {}) },
376
- });
374
+ for (let i = 0; i < fileList.length; i++) formData.append(fields.files, fileList[i]);
375
+ formData.append(fields.metas, JSON.stringify(buildMetas(fileList)));
376
+ formData.append(fields.type, refName);
377
+ if (parentId) formData.append(fields.parentId, parentId);
378
+ const url = FetchClient.makeHttpUrl(cap.endpointKey, endpoint, cap.prefix, new Map());
379
+ return await this.http.post(url, formData, { headers: this.#makeAuthHeaders(option) });
377
380
  },
378
381
  });
379
382
  }
@@ -67,6 +67,7 @@ export class FetchSerializer {
67
67
  ...(endpointInfo.signalOption.globalPrefix !== undefined
68
68
  ? { globalPrefix: endpointInfo.signalOption.globalPrefix }
69
69
  : {}),
70
+ ...(endpointInfo.signalOption.fileUpload ? { fileUpload: true } : {}),
70
71
  ...(guards?.length ? { guards } : {}),
71
72
  };
72
73
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akanjs",
3
- "version": "2.2.3",
3
+ "version": "2.2.4-rc.1",
4
4
  "sourceType": "module",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -259,7 +259,7 @@ export class InjectInfo<
259
259
  get: async (key: string) => {
260
260
  const getter = injectInfo.get as unknown as (value: unknown) => unknown;
261
261
  const value = await cacheAdaptor.hget(`akan:memory:${injectInfo.parentRefName}`, propKey, key);
262
- return value === null ? value : getter(value);
262
+ return value === null ? undefined : getter(value);
263
263
  },
264
264
  set: async (key: string, value: unknown) => {
265
265
  const setter = injectInfo.set as unknown as (value: unknown) => string | number | Buffer;
@@ -346,6 +346,7 @@ export const injectionBuilder = (parentRefName: string) => ({
346
346
  const isMap = modelRef === Map;
347
347
  if (isMap && !opts.of) throw new Error("of should be provided when modelRef is Map");
348
348
  type FieldValue = never extends GetFn ? GetFieldValue<ValueRef, ExplicitType, MapValue> : ReturnType<GetFn>;
349
+ type MapFieldValue = never extends GetFn ? FieldToValue<MapValue> : ReturnType<GetFn>;
349
350
  type IsNullable = DefaultValue extends never ? true : false;
350
351
  type UseValue = IsNullable extends true ? FieldValue | null : FieldValue;
351
352
  return new InjectInfo<
@@ -356,8 +357,8 @@ export const injectionBuilder = (parentRefName: string) => ({
356
357
  : UseValue
357
358
  : MapConstructor extends ValueRef
358
359
  ? {
359
- get: (key: string) => Promise<FieldToValue<MapValue>>;
360
- set: (key: string, value: FieldToValue<MapValue>) => Promise<void>;
360
+ get: (key: string) => Promise<MapFieldValue | undefined>;
361
+ set: (key: string, value: MapFieldValue) => Promise<void>;
361
362
  delete: (key: string) => Promise<void>;
362
363
  }
363
364
  : { get: () => Promise<UseValue>; set: (value: UseValue) => Promise<void>; delete: () => Promise<void> },
@@ -0,0 +1,35 @@
1
+ import type { SerializedSignal } from "./types";
2
+
3
+ /**
4
+ * Framework-owned file-upload contract. A plugin opts in by marking exactly one
5
+ * upload mutation with `{ fileUpload: true }`; the multipart form must use these
6
+ * field names and the metas shape below.
7
+ */
8
+ export const fileUploadContract = {
9
+ fields: { files: "files", metas: "metas", type: "type", parentId: "parentId" },
10
+ buildMetas: (fileList: FileList) =>
11
+ Array.from(fileList).map((f) => ({ lastModifiedAt: new Date(f.lastModified).toISOString(), size: f.size })),
12
+ } as const;
13
+
14
+ export interface FileUploadCapability {
15
+ refName: string;
16
+ endpointKey: string;
17
+ prefix?: string;
18
+ }
19
+
20
+ /** Discovers the upload endpoint marked with `{ fileUpload: true }` from the serialized signal. */
21
+ export const resolveFileUploadCapability = (serializedSignal: {
22
+ [key: string]: SerializedSignal;
23
+ }): FileUploadCapability | null => {
24
+ const matches: FileUploadCapability[] = [];
25
+ for (const [refName, signal] of Object.entries(serializedSignal))
26
+ for (const [endpointKey, endpoint] of Object.entries(signal.endpoint))
27
+ if (endpoint.fileUpload) matches.push({ refName, endpointKey, prefix: signal.prefix });
28
+ if (matches.length > 1)
29
+ console.warn(
30
+ `[akan] Multiple fileUpload endpoints found (${matches
31
+ .map((m) => `${m.refName}.${m.endpointKey}`)
32
+ .join(", ")}). Using the first; mark only one mutation with { fileUpload: true }.`,
33
+ );
34
+ return matches[0] ?? null;
35
+ };
package/signal/index.ts CHANGED
@@ -2,6 +2,7 @@ export * from "./base.signal";
2
2
  export * from "./endpoint";
3
3
  export * from "./endpointInfo";
4
4
  export * from "./exception";
5
+ export * from "./fileUpload";
5
6
  export * from "./guard";
6
7
  export * from "./guards";
7
8
  export * from "./intercept";
@@ -64,6 +64,7 @@ export class FetchSerializer {
64
64
  args: endpointInfo.args.map(FetchSerializer.#serializeArg),
65
65
  returns: FetchSerializer.#serializeReturns(endpointInfo),
66
66
  ...(endpointInfo.signalOption.path ? { path: endpointInfo.signalOption.path } : {}),
67
+ ...(endpointInfo.signalOption.fileUpload ? { fileUpload: true } : {}),
67
68
  ...(guards?.length ? { guards } : {}),
68
69
  };
69
70
  }
package/signal/types.ts CHANGED
@@ -70,6 +70,8 @@ export interface SignalOption<Response = any, Nullable extends boolean = false,
70
70
  middlewares?: MiddlewareCls[];
71
71
  prefix?: false | string;
72
72
  globalPrefix?: false;
73
+ /** Marks this mutation as the framework file-upload endpoint (see resolveFileUploadCapability). */
74
+ fileUpload?: boolean;
73
75
 
74
76
  scheduleType?: "init" | "destroy" | "cron" | "interval" | "timeout";
75
77
  scheduleCron?: string;
@@ -84,6 +86,7 @@ interface SerializedSignalOption {
84
86
  prefix?: false | string;
85
87
  globalPrefix?: false;
86
88
  guards?: string[];
89
+ fileUpload?: boolean;
87
90
  }
88
91
  export interface SerializedSlice extends SerializedSignalOption {}
89
92
 
package/store/action.ts CHANGED
@@ -12,6 +12,7 @@ import {
12
12
  import type { BaseFilterSortKey, ExtractSort, FilterInstance } from "akanjs/document";
13
13
  import type { FetchInitForm, FetchProxy } from "akanjs/fetch";
14
14
  import type { SerializedSlice, SliceCls, SliceInfoArgs } from "akanjs/signal";
15
+ import { resolveFileUploadCapability } from "akanjs/signal/fileUpload";
15
16
  import type { SliceStateKey } from "./state";
16
17
  import type { SetGet } from "./types";
17
18
 
@@ -277,6 +278,7 @@ export const makeFormSetter = (refName: string, fetch: FetchProxy<any>) => {
277
278
  type Light = BaseObject;
278
279
  const [fieldName, className] = [refName, capitalize(refName)];
279
280
  const modelRef = ConstantRegistry.getDatabase(refName).full;
281
+ const fileUploadRefName = resolveFileUploadCapability(fetch.serializedSignal)?.refName;
280
282
 
281
283
  const names = {
282
284
  model: fieldName,
@@ -356,7 +358,7 @@ export const makeFormSetter = (refName: string, fetch: FetchProxy<any>) => {
356
358
  },
357
359
  }
358
360
  : {}),
359
- ...(field.isClass && ConstantRegistry.getRefName(field.modelRef) === "file"
361
+ ...(field.isClass && !!fileUploadRefName && ConstantRegistry.getRefName(field.modelRef) === fileUploadRefName
360
362
  ? {
361
363
  [namesOfField.uploadFieldOnModel]: async function (this: SetGet, fileList: FileList, index?: number) {
362
364
  const form = (this.get() as { [key: string]: any })[names.modelForm] as { [key: string]: any };
@@ -383,7 +385,9 @@ export const makeFormSetter = (refName: string, fetch: FetchProxy<any>) => {
383
385
  const intervalKey = setInterval(() => {
384
386
  void (async () => {
385
387
  const currentFile = await (
386
- (fetch as { [key: string]: any }).file as (id: string) => Promise<ProtoFile>
388
+ (fetch as { [key: string]: any })[fileUploadRefName as string] as (
389
+ id: string,
390
+ ) => Promise<ProtoFile>
387
391
  )(file.id);
388
392
  if (field.isArray)
389
393
  this.set((state: { [key: string]: { [key: string]: ProtoFile[] } }) => {
@@ -8,6 +8,8 @@ export interface AllDictionary {
8
8
  }
9
9
  export declare class Translator {
10
10
  #private;
11
+ static setActiveLocale(lang: string | undefined): void;
12
+ static getActiveLocale(): string | undefined;
11
13
  constructor(dictionary: Record<string, Record<string, Record<string, unknown>>>);
12
14
  hasDictionary(lang: string): boolean;
13
15
  static seed(lang: string, dict: Dictionary | undefined): void;
@@ -76,8 +76,8 @@ export declare const injectionBuilder: (parentRefName: string) => {
76
76
  get?: GetFn;
77
77
  set?: (value: ReturnType<GetFn>) => GetFieldValue<ValueRef, ExplicitType>;
78
78
  }) => InjectInfo<"memory", Local extends true ? MapConstructor extends ValueRef ? Map<string, FieldToValue<MapValue>> : (DefaultValue extends never ? true : false) extends true ? (never extends GetFn ? GetFieldValue<ValueRef, ExplicitType, MapValue> : ReturnType<GetFn>) | null : never extends GetFn ? GetFieldValue<ValueRef, ExplicitType, MapValue> : ReturnType<GetFn> : MapConstructor extends ValueRef ? {
79
- get: (key: string) => Promise<FieldToValue<MapValue>>;
80
- set: (key: string, value: FieldToValue<MapValue>) => Promise<void>;
79
+ get: (key: string) => Promise<(never extends GetFn ? FieldToValue<MapValue> : ReturnType<GetFn>) | undefined>;
80
+ set: (key: string, value: never extends GetFn ? FieldToValue<MapValue> : ReturnType<GetFn>) => Promise<void>;
81
81
  delete: (key: string) => Promise<void>;
82
82
  } : {
83
83
  get: () => Promise<(DefaultValue extends never ? true : false) extends true ? (never extends GetFn ? GetFieldValue<ValueRef, ExplicitType, MapValue> : ReturnType<GetFn>) | null : never extends GetFn ? GetFieldValue<ValueRef, ExplicitType, MapValue> : ReturnType<GetFn>>;
@@ -0,0 +1,27 @@
1
+ import type { SerializedSignal } from "./types.d.ts";
2
+ /**
3
+ * Framework-owned file-upload contract. A plugin opts in by marking exactly one
4
+ * upload mutation with `{ fileUpload: true }`; the multipart form must use these
5
+ * field names and the metas shape below.
6
+ */
7
+ export declare const fileUploadContract: {
8
+ readonly fields: {
9
+ readonly files: "files";
10
+ readonly metas: "metas";
11
+ readonly type: "type";
12
+ readonly parentId: "parentId";
13
+ };
14
+ readonly buildMetas: (fileList: FileList) => {
15
+ lastModifiedAt: string;
16
+ size: number;
17
+ }[];
18
+ };
19
+ export interface FileUploadCapability {
20
+ refName: string;
21
+ endpointKey: string;
22
+ prefix?: string;
23
+ }
24
+ /** Discovers the upload endpoint marked with `{ fileUpload: true }` from the serialized signal. */
25
+ export declare const resolveFileUploadCapability: (serializedSignal: {
26
+ [key: string]: SerializedSignal;
27
+ }) => FileUploadCapability | null;
@@ -2,6 +2,7 @@ export * from "./base.signal";
2
2
  export * from "./endpoint.d.ts";
3
3
  export * from "./endpointInfo.d.ts";
4
4
  export * from "./exception.d.ts";
5
+ export * from "./fileUpload.d.ts";
5
6
  export * from "./guard.d.ts";
6
7
  export * from "./guards.d.ts";
7
8
  export * from "./intercept.d.ts";
@@ -60,6 +60,8 @@ export interface SignalOption<Response = any, Nullable extends boolean = false,
60
60
  middlewares?: MiddlewareCls[];
61
61
  prefix?: false | string;
62
62
  globalPrefix?: false;
63
+ /** Marks this mutation as the framework file-upload endpoint (see resolveFileUploadCapability). */
64
+ fileUpload?: boolean;
63
65
  scheduleType?: "init" | "destroy" | "cron" | "interval" | "timeout";
64
66
  scheduleCron?: string;
65
67
  scheduleTime?: number;
@@ -72,6 +74,7 @@ interface SerializedSignalOption {
72
74
  prefix?: false | string;
73
75
  globalPrefix?: false;
74
76
  guards?: string[];
77
+ fileUpload?: boolean;
75
78
  }
76
79
  export interface SerializedSlice extends SerializedSignalOption {
77
80
  }
@@ -6,9 +6,9 @@ import { type HTMLAttributes, type ReactNode, type RefObject } from "react";
6
6
  export declare const Client: {
7
7
  (): import("react/jsx-runtime").JSX.Element;
8
8
  Wrapper: ({ children, theme, lang, dictionary, signals, reconnect, }: ClientWrapperProps) => import("react/jsx-runtime").JSX.Element;
9
- Bridge: ({ env, lang, theme, prefix, gaTrackingId, }: ClientBridgeProps) => "" | import("react/jsx-runtime").JSX.Element | undefined;
9
+ Bridge: ({ env, lang, theme, prefix, gaTrackingId }: ClientBridgeProps) => "" | import("react/jsx-runtime").JSX.Element | undefined;
10
10
  Inner: () => import("react/jsx-runtime").JSX.Element;
11
- SsrBridge: ({ lang, prefix, }: ClientSsrBridgeProps) => null;
11
+ SsrBridge: ({ lang, prefix }: ClientSsrBridgeProps) => null;
12
12
  };
13
13
  interface ClientWrapperProps {
14
14
  children: ReactNode;
@@ -37,11 +37,11 @@ interface ClientBridgeProps {
37
37
  prefix?: string;
38
38
  gaTrackingId?: string;
39
39
  }
40
- export declare const ClientBridge: ({ env, lang, theme, prefix, gaTrackingId, }: ClientBridgeProps) => "" | import("react/jsx-runtime").JSX.Element | undefined;
40
+ export declare const ClientBridge: ({ env, lang, theme, prefix, gaTrackingId }: ClientBridgeProps) => "" | import("react/jsx-runtime").JSX.Element | undefined;
41
41
  export declare const ClientInner: () => import("react/jsx-runtime").JSX.Element;
42
42
  interface ClientSsrBridgeProps {
43
43
  lang: string;
44
44
  prefix?: string;
45
45
  }
46
- export declare const ClientSsrBridge: ({ lang, prefix, }: ClientSsrBridgeProps) => null;
46
+ export declare const ClientSsrBridge: ({ lang, prefix }: ClientSsrBridgeProps) => null;
47
47
  export {};
@@ -55,8 +55,10 @@ export const ClientWrapper = ({
55
55
  reconnect = true,
56
56
  }: ClientWrapperProps) => {
57
57
 
58
- if (dictionary) Translator.seed(lang, dictionary);
59
- if (getEnv().renderMode === "ssr") {
58
+ if (dictionary) {
59
+ Translator.seed(lang, dictionary);
60
+
61
+ if (typeof window !== "undefined") Translator.setActiveLocale(lang);
60
62
  }
61
63
  useLayoutEffect(() => {
62
64
  Logger.rawLog(logo);
@@ -71,8 +73,7 @@ export const ClientWrapper = ({
71
73
  };
72
74
  Client.Wrapper = ClientWrapper;
73
75
 
74
- interface ClientPathWrapperProps
75
- extends Omit<HTMLAttributes<HTMLDivElement>, "style"> {
76
+ interface ClientPathWrapperProps extends Omit<HTMLAttributes<HTMLDivElement>, "style"> {
76
77
  bind?: () => HTMLAttributes<HTMLDivElement>;
77
78
  wrapperRef?: RefObject<HTMLDivElement | null> | null;
78
79
  pageType?: "current" | "prev" | "cached";
@@ -93,18 +94,12 @@ export const ClientPathWrapper = ({
93
94
  layoutStyle = "web",
94
95
  ...props
95
96
  }: ClientPathWrapperProps) => {
96
- const href =
97
- location?.href ??
98
- (typeof window !== "undefined" ? window.location.href : "");
99
- const hash =
100
- location?.hash ??
101
- (typeof window !== "undefined" ? window.location.hash : "");
97
+ const href = location?.href ?? (typeof window !== "undefined" ? window.location.href : "");
98
+ const hash = location?.hash ?? (typeof window !== "undefined" ? window.location.hash : "");
102
99
  const pathname = location?.pathname ?? "/";
103
100
  const params = location?.params ?? {};
104
101
  const searchParams = location?.searchParams ?? {};
105
- const search =
106
- location?.search ??
107
- (typeof window !== "undefined" ? window.location.search : "");
102
+ const search = location?.search ?? (typeof window !== "undefined" ? window.location.search : "");
108
103
  const lang = params.lang;
109
104
  const firstPath = pathname.split("/")[2];
110
105
  const pathRoute: PathRoute = location?.pathRoute ?? {
@@ -137,9 +132,7 @@ export const ClientPathWrapper = ({
137
132
  }}
138
133
  >
139
134
  <animated.div
140
- {...(bind && pathRoute.pageState.gesture && gestureEnabled
141
- ? bind()
142
- : {})}
135
+ {...(bind && pathRoute.pageState.gesture && gestureEnabled ? bind() : {})}
143
136
  className={clsx("group/path", className)}
144
137
  ref={wrapperRef}
145
138
  {...props}
@@ -161,13 +154,7 @@ interface ClientBridgeProps {
161
154
  gaTrackingId?: string;
162
155
  }
163
156
 
164
- export const ClientBridge = ({
165
- env,
166
- lang,
167
- theme,
168
- prefix,
169
- gaTrackingId,
170
- }: ClientBridgeProps) => {
157
+ export const ClientBridge = ({ env, lang, theme, prefix, gaTrackingId }: ClientBridgeProps) => {
171
158
  const uiOperation = st.use.uiOperation();
172
159
  const pathname = st.use.pathname();
173
160
  const params = st.use.params();
@@ -234,26 +221,18 @@ function applyThemePolicy(theme: AkanTheme): void {
234
221
  }
235
222
  if (theme === "system") {
236
223
  const dark = window.matchMedia("(prefers-color-scheme: dark)").matches;
237
- document.documentElement.setAttribute(
238
- "data-theme",
239
- dark ? "dark" : "light",
240
- );
224
+ document.documentElement.setAttribute("data-theme", dark ? "dark" : "light");
241
225
  return;
242
226
  }
243
227
  document.documentElement.setAttribute("data-theme", theme);
244
228
  }
245
229
 
246
- function buildSearchParams(
247
- entries: Iterable<[string, string]>,
248
- ): Record<string, string | string[]> {
230
+ function buildSearchParams(entries: Iterable<[string, string]>): Record<string, string | string[]> {
249
231
  const params: Record<string, string | string[]> = {};
250
232
  for (const [key, value] of entries) {
251
233
  const current = params[key];
252
234
  if (current === undefined) params[key] = value;
253
- else
254
- params[key] = Array.isArray(current)
255
- ? [...current, value]
256
- : [current, value];
235
+ else params[key] = Array.isArray(current) ? [...current, value] : [current, value];
257
236
  }
258
237
  return params;
259
238
  }
@@ -273,10 +252,7 @@ interface ClientSsrBridgeProps {
273
252
  lang: string;
274
253
  prefix?: string;
275
254
  }
276
- export const ClientSsrBridge = ({
277
- lang,
278
- prefix = "",
279
- }: ClientSsrBridgeProps) => {
255
+ export const ClientSsrBridge = ({ lang, prefix = "" }: ClientSsrBridgeProps) => {
280
256
  useEffect(() => {
281
257
  const visiblePrefix = getEnv().operationMode === "local" ? prefix : "";
282
258
  const navigateRscWithFallback = (
@@ -290,19 +266,13 @@ export const ClientSsrBridge = ({
290
266
  return;
291
267
  }
292
268
  void navigation.catch((error) => {
293
- Logger.warn(
294
- `RSC navigation failed, falling back to document navigation: ${String(error)}`,
295
- );
269
+ Logger.warn(`RSC navigation failed, falling back to document navigation: ${String(error)}`);
296
270
  fallback();
297
271
  });
298
272
  };
299
273
  const syncHref = (href: string) => {
300
274
  const url = new URL(href, window.location.origin);
301
- const { path } = getPathInfo(
302
- `${url.pathname}${url.search}${url.hash}`,
303
- lang,
304
- visiblePrefix,
305
- );
275
+ const { path } = getPathInfo(`${url.pathname}${url.search}${url.hash}`, lang, visiblePrefix);
306
276
  const searchParams = buildSearchParams(url.searchParams.entries());
307
277
  st.set({ pathname: url.pathname, path, searchParams });
308
278
  };
@@ -314,17 +284,11 @@ export const ClientSsrBridge = ({
314
284
  router: {
315
285
  push: (href, routeOptions) => {
316
286
  syncHref(href);
317
- navigateRscWithFallback(href, routeOptions, () =>
318
- window.location.assign(href),
319
- );
287
+ navigateRscWithFallback(href, routeOptions, () => window.location.assign(href));
320
288
  },
321
289
  replace: (href, routeOptions) => {
322
290
  syncHref(href);
323
- navigateRscWithFallback(
324
- href,
325
- { ...routeOptions, replace: true },
326
- () => window.location.replace(href),
327
- );
291
+ navigateRscWithFallback(href, { ...routeOptions, replace: true }, () => window.location.replace(href));
328
292
  },
329
293
  back: () => {
330
294
  window.history.back();
@@ -346,14 +310,8 @@ export const ClientSsrBridge = ({
346
310
  const visiblePrefix = getEnv().operationMode === "local" ? prefix : "";
347
311
  const sync = () => {
348
312
  const { pathname, search, hash } = window.location;
349
- const { path } = getPathInfo(
350
- `${pathname}${search}${hash}`,
351
- lang,
352
- visiblePrefix,
353
- );
354
- const searchParams = buildSearchParams(
355
- new URLSearchParams(search).entries(),
356
- );
313
+ const { path } = getPathInfo(`${pathname}${search}${hash}`, lang, visiblePrefix);
314
+ const searchParams = buildSearchParams(new URLSearchParams(search).entries());
357
315
  st.set({ pathname: window.location.pathname, path, searchParams });
358
316
  };
359
317
  sync();