@korioinc/next-core 2.0.16 → 2.0.18

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.
@@ -18,8 +18,12 @@ export declare function getPathname({ locale, href }: {
18
18
  }): string;
19
19
  export declare function getLanguageAlternates(pathname?: string): Record<string, string>;
20
20
  export declare function getCurrentPathname(): Promise<string>;
21
- /**
22
- * pathname과 params를 조합하여 전체 URL을 생성하는 함수
23
- */
24
- export declare function getFullUrl(pathname: string, params?: Record<string, string | string[] | undefined> | ReadonlyURLSearchParams | undefined): string;
21
+ export declare function getCurrentSearchParams(): Promise<URLSearchParams>;
22
+ export declare function getDefaultPathname(): Promise<string>;
23
+ export declare function getCurrentLanguageAlternates(): Promise<Record<string, string>>;
24
+ type FullUrlParams = Record<string, string | string[] | undefined> | URLSearchParams | ReadonlyURLSearchParams | undefined;
25
+ export declare function getFullUrlByPathname(pathname: string, params?: FullUrlParams): string;
26
+ export declare function getFullUrl(params?: FullUrlParams): Promise<string>;
27
+ export declare function getFullUrlWithCurrentParams(): Promise<string>;
28
+ export {};
25
29
  //# sourceMappingURL=routing.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/i18n/routing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,KAAK,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA6B7D;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,EAAE,CAErC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AA2DD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,WAAW,yBA2EvD;AAED,wBAAgB,gBAAgB,CAAC,cAAc,EAAE,OAAO,GAAG,MAAM,CAShE;AAED,wBAAgB,eAAe,CAAC,cAAc,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAkB9F;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAoBvG;AAED,wBAAgB,WAAW,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,UAY7E;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,GAAE,MAAY,0BAmC3D;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAK1D;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,GAAG,uBAAuB,GAAG,SAAS,GAC3F,MAAM,CAkCR"}
1
+ {"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/i18n/routing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,KAAK,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAsC7D;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,EAAE,CAErC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAyDD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,WAAW,yBAyEvD;AAED,wBAAgB,gBAAgB,CAAC,cAAc,EAAE,OAAO,GAAG,MAAM,CAShE;AAED,wBAAgB,eAAe,CAAC,cAAc,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAkB9F;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAoBvG;AAED,wBAAgB,WAAW,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,UAY7E;AAsBD,wBAAgB,qBAAqB,CAAC,QAAQ,GAAE,MAAY,0BAwB3D;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAK1D;AAED,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,eAAe,CAAC,CAMvE;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAU1D;AAED,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAIpF;AAED,KAAK,aAAa,GACd,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,GAC7C,eAAe,GACf,uBAAuB,GACvB,SAAS,CAAC;AAiDd,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,MAAM,CAErF;AAED,wBAAsB,UAAU,CAAC,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAIxE;AAED,wBAAsB,2BAA2B,IAAI,OAAO,CAAC,MAAM,CAAC,CAKnE"}
@@ -18,6 +18,13 @@ const DEFAULT_FALLBACK = () => {
18
18
  };
19
19
  const LOCALE_COOKIE_NAME = 'NEXT_LOCALE';
20
20
  const LOCALE_PREFIX = 'as-needed';
21
+ const PATHNAME_HEADER_NAME = 'x-pathname';
22
+ const SEARCH_PARAMS_HEADER_NAME = 'x-search-params';
23
+ const setRoutingHeaders = (response, pathname, search) => {
24
+ response.headers.set(PATHNAME_HEADER_NAME, pathname);
25
+ response.headers.set(SEARCH_PARAMS_HEADER_NAME, search.replace(/^\?/, ''));
26
+ return response;
27
+ };
21
28
  /**
22
29
  * Get all available locales
23
30
  */
@@ -54,8 +61,7 @@ const redirectWithoutLocale = (request, pathname, locale, shouldSetCookie = fals
54
61
  const url = new URL(newPathname, request.url);
55
62
  url.search = request.nextUrl.search;
56
63
  url.hash = request.nextUrl.hash;
57
- const response = NextResponse.redirect(url, 302);
58
- response.headers.set('x-pathname', newPathname);
64
+ const response = setRoutingHeaders(NextResponse.redirect(url, 302), newPathname, request.nextUrl.search);
59
65
  if (shouldSetCookie) {
60
66
  setCookie(response, locale);
61
67
  }
@@ -68,8 +74,7 @@ const rewriteWithLocale = (request, pathname, locale) => {
68
74
  const internalUrl = new URL(`/${locale}${pathname}`, request.url);
69
75
  internalUrl.search = request.nextUrl.search;
70
76
  internalUrl.hash = request.nextUrl.hash;
71
- const response = NextResponse.rewrite(internalUrl);
72
- response.headers.set('x-pathname', pathname);
77
+ const response = setRoutingHeaders(NextResponse.rewrite(internalUrl), pathname, request.nextUrl.search);
73
78
  return response;
74
79
  };
75
80
  export function handleLocaleRouting(request) {
@@ -89,8 +94,7 @@ export function handleLocaleRouting(request) {
89
94
  // 2. URL에 locale이 포함된 경우
90
95
  if (pathnameHasLocale) {
91
96
  // 이미 path에 locale이 있을 때
92
- const response = NextResponse.next();
93
- response.headers.set('x-pathname', pathname);
97
+ const response = setRoutingHeaders(NextResponse.next(), pathname, request.nextUrl.search);
94
98
  // 쿠키 값이 path locale과 다를 경우
95
99
  if (localeCookie?.value !== pathLocale) {
96
100
  // 기본 locale인 경우 URL에서 제거
@@ -125,8 +129,7 @@ export function handleLocaleRouting(request) {
125
129
  // 다른 locale은 URL에 표시
126
130
  const newPathname = getChangeLocalePath(pathname, defaultFallback, locale);
127
131
  request.nextUrl.pathname = newPathname;
128
- const response = NextResponse.redirect(request.nextUrl);
129
- response.headers.set('x-pathname', newPathname);
132
+ const response = setRoutingHeaders(NextResponse.redirect(request.nextUrl), newPathname, request.nextUrl.search);
130
133
  // 쿠키가 없는 경우 설정
131
134
  if (localeCookie?.value === undefined) {
132
135
  setCookie(response, locale);
@@ -189,18 +192,24 @@ export function getPathname({ locale, href }) {
189
192
  }
190
193
  return href.startsWith('/') ? `/${locale}${href}` : `/${locale}/${href}`;
191
194
  }
192
- export function getLanguageAlternates(pathname = '/') {
193
- const defaultFallback = DEFAULT_FALLBACK();
194
- // Remove any existing locale from the pathname to get the base path
195
- let basePath = pathname;
195
+ const getBasePathWithoutLocale = (pathname = '/') => {
196
+ let basePath = pathname || '/';
196
197
  locales.forEach((locale) => {
197
198
  const localePattern = new RegExp(`^/${locale}(/|$)`);
198
199
  if (localePattern.test(basePath)) {
199
200
  basePath = basePath.replace(localePattern, '/');
200
201
  }
201
202
  });
202
- // Normalize path
203
+ // Normalize path and ensure root fallback
203
204
  basePath = basePath.replace(/\/+/g, '/');
205
+ if (!basePath.startsWith('/')) {
206
+ basePath = `/${basePath}`;
207
+ }
208
+ return basePath || '/';
209
+ };
210
+ export function getLanguageAlternates(pathname = '/') {
211
+ const defaultFallback = DEFAULT_FALLBACK();
212
+ const basePath = getBasePathWithoutLocale(pathname);
204
213
  const alternates = {};
205
214
  // Set x-default based on LOCALE_PREFIX and defaultFallback
206
215
  if (LOCALE_PREFIX === 'as-needed') {
@@ -224,40 +233,73 @@ export function getLanguageAlternates(pathname = '/') {
224
233
  export async function getCurrentPathname() {
225
234
  const { headers } = await import('next/headers');
226
235
  const headersList = await headers();
227
- return headersList.get('x-pathname') || '';
236
+ return headersList.get(PATHNAME_HEADER_NAME) || '';
228
237
  }
229
- /**
230
- * pathname과 params를 조합하여 전체 URL을 생성하는 함수
231
- */
232
- export function getFullUrl(pathname, params) {
233
- const baseUrl = process.env.NEXT_PUBLIC_APP_URL || '';
234
- if (!params) {
235
- return `${baseUrl}${pathname}`;
238
+ export async function getCurrentSearchParams() {
239
+ const { headers } = await import('next/headers');
240
+ const headersList = await headers();
241
+ const rawSearchParams = headersList.get(SEARCH_PARAMS_HEADER_NAME) || '';
242
+ return new URLSearchParams(rawSearchParams);
243
+ }
244
+ export async function getDefaultPathname() {
245
+ const pathname = await getCurrentPathname();
246
+ const basePath = getBasePathWithoutLocale(pathname);
247
+ const defaultFallback = DEFAULT_FALLBACK();
248
+ if (LOCALE_PREFIX === 'as-needed') {
249
+ return basePath;
236
250
  }
251
+ return `/${defaultFallback}${basePath === '/' ? '' : basePath}`;
252
+ }
253
+ export async function getCurrentLanguageAlternates() {
254
+ const pathname = await getCurrentPathname();
255
+ return getLanguageAlternates(pathname);
256
+ }
257
+ const isSearchParamsLike = (params) => {
258
+ return typeof params.get === 'function' && typeof params.forEach === 'function';
259
+ };
260
+ const toSearchParams = (params) => {
237
261
  const searchParams = new URLSearchParams();
238
- // ReadonlyURLSearchParams인 경우
239
- if (params instanceof URLSearchParams) {
262
+ if (!params) {
263
+ return searchParams;
264
+ }
265
+ if (isSearchParamsLike(params)) {
240
266
  params.forEach((value, key) => {
241
- // locale 파라미터는 제외
242
267
  if (key !== 'locale') {
243
268
  searchParams.append(key, value);
244
269
  }
245
270
  });
271
+ return searchParams;
246
272
  }
247
- else {
248
- // Record<string, string | string[] | undefined>인 경우
249
- Object.entries(params).forEach(([key, value]) => {
250
- // undefined 값은 건너뛰기
251
- if (value === undefined)
252
- return;
253
- if (Array.isArray(value)) {
254
- value.forEach((v) => searchParams.append(key, v));
255
- }
256
- else {
257
- searchParams.append(key, value);
258
- }
259
- });
260
- }
273
+ Object.entries(params).forEach(([key, value]) => {
274
+ if (value === undefined)
275
+ return;
276
+ if (Array.isArray(value)) {
277
+ value.forEach((v) => searchParams.append(key, v));
278
+ }
279
+ else {
280
+ searchParams.append(key, value);
281
+ }
282
+ });
283
+ return searchParams;
284
+ };
285
+ /**
286
+ * pathname과 params를 조합하여 전체 URL을 생성하는 함수
287
+ */
288
+ const buildFullUrl = (pathname, params) => {
289
+ const baseUrl = process.env.NEXT_PUBLIC_APP_URL || '';
290
+ const searchParams = toSearchParams(params);
261
291
  const queryString = searchParams.toString();
262
292
  return `${baseUrl}${pathname}${queryString ? `?${queryString}` : ''}`;
293
+ };
294
+ export function getFullUrlByPathname(pathname, params) {
295
+ return buildFullUrl(pathname, params);
296
+ }
297
+ export async function getFullUrl(params) {
298
+ const pathname = await getCurrentPathname();
299
+ return buildFullUrl(pathname, params);
300
+ }
301
+ export async function getFullUrlWithCurrentParams() {
302
+ const pathname = await getCurrentPathname();
303
+ const currentParams = await getCurrentSearchParams();
304
+ return buildFullUrl(pathname, currentParams);
263
305
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@korioinc/next-core",
3
- "version": "2.0.16",
3
+ "version": "2.0.18",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./ads": {
@@ -79,11 +79,11 @@
79
79
  "tsc-alias": "^1.8.16",
80
80
  "tw-animate-css": "^1.4.0",
81
81
  "typescript": "^5.9.3",
82
- "@korioinc/next-configs": "2.0.16"
82
+ "@korioinc/next-configs": "2.0.18"
83
83
  },
84
84
  "dependencies": {
85
85
  "@floating-ui/react": "^0.27.17",
86
- "@formatjs/intl-localematcher": "^0.7.5",
86
+ "@formatjs/intl-localematcher": "^0.8.1",
87
87
  "clsx": "^2.1.1",
88
88
  "cookies-next": "^6.1.1",
89
89
  "cosmiconfig": "^9.0.0",
@@ -94,7 +94,7 @@
94
94
  "schema-dts": "^1.1.5",
95
95
  "tailwind-merge": "^3.4.0",
96
96
  "valtio": "^2.3.0",
97
- "@korioinc/next-conf": "2.0.16"
97
+ "@korioinc/next-conf": "2.0.18"
98
98
  },
99
99
  "publishConfig": {
100
100
  "access": "public",