@korioinc/next-core 1.0.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/LICENSE +21 -0
- package/README.md +90 -0
- package/dist/ads/components/AdContainer.d.ts +12 -0
- package/dist/ads/components/AdContainer.d.ts.map +1 -0
- package/dist/ads/components/AdContainer.js +287 -0
- package/dist/ads/components/GoogleAdSense.d.ts +6 -0
- package/dist/ads/components/GoogleAdSense.d.ts.map +1 -0
- package/dist/ads/components/GoogleAdSense.js +6 -0
- package/dist/ads/components/MockAdDisplay.d.ts +8 -0
- package/dist/ads/components/MockAdDisplay.d.ts.map +1 -0
- package/dist/ads/components/MockAdDisplay.js +13 -0
- package/dist/ads/config.d.ts +3 -0
- package/dist/ads/config.d.ts.map +1 -0
- package/dist/ads/config.js +134 -0
- package/dist/ads/index.d.ts +6 -0
- package/dist/ads/index.d.ts.map +1 -0
- package/dist/ads/index.js +7 -0
- package/dist/ads/types.d.ts +15 -0
- package/dist/ads/types.d.ts.map +1 -0
- package/dist/ads/types.js +1 -0
- package/dist/api-client/index.d.ts +31 -0
- package/dist/api-client/index.d.ts.map +1 -0
- package/dist/api-client/index.js +90 -0
- package/dist/auth/auth-manager.d.ts +45 -0
- package/dist/auth/auth-manager.d.ts.map +1 -0
- package/dist/auth/auth-manager.js +75 -0
- package/dist/auth/index.client.d.ts +7 -0
- package/dist/auth/index.client.d.ts.map +1 -0
- package/dist/auth/index.client.js +5 -0
- package/dist/auth/index.d.ts +8 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +11 -0
- package/dist/auth/index.server.d.ts +7 -0
- package/dist/auth/index.server.d.ts.map +1 -0
- package/dist/auth/index.server.js +5 -0
- package/dist/auth/providers/auth-context-provider.d.ts +21 -0
- package/dist/auth/providers/auth-context-provider.d.ts.map +1 -0
- package/dist/auth/providers/auth-context-provider.js +74 -0
- package/dist/auth/routing.d.ts +3 -0
- package/dist/auth/routing.d.ts.map +1 -0
- package/dist/auth/routing.js +40 -0
- package/dist/auth/types/auth.d.ts +23 -0
- package/dist/auth/types/auth.d.ts.map +1 -0
- package/dist/auth/types/auth.js +1 -0
- package/dist/auth/types/user.d.ts +6 -0
- package/dist/auth/types/user.d.ts.map +1 -0
- package/dist/auth/types/user.js +1 -0
- package/dist/auth/utils/auth.d.ts +32 -0
- package/dist/auth/utils/auth.d.ts.map +1 -0
- package/dist/auth/utils/auth.js +116 -0
- package/dist/auth/utils/permission.d.ts +29 -0
- package/dist/auth/utils/permission.d.ts.map +1 -0
- package/dist/auth/utils/permission.js +44 -0
- package/dist/components/head-manifest/index.d.ts +6 -0
- package/dist/components/head-manifest/index.d.ts.map +1 -0
- package/dist/components/head-manifest/index.js +4 -0
- package/dist/components/index.d.ts +6 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +7 -0
- package/dist/components/json-ld/index.d.ts +7 -0
- package/dist/components/json-ld/index.d.ts.map +1 -0
- package/dist/components/json-ld/index.js +6 -0
- package/dist/components/locale-switcher/_components/china-flag.d.ts +2 -0
- package/dist/components/locale-switcher/_components/china-flag.d.ts.map +1 -0
- package/dist/components/locale-switcher/_components/china-flag.js +4 -0
- package/dist/components/locale-switcher/_components/japan-flag.d.ts +2 -0
- package/dist/components/locale-switcher/_components/japan-flag.d.ts.map +1 -0
- package/dist/components/locale-switcher/_components/japan-flag.js +4 -0
- package/dist/components/locale-switcher/_components/korea-flag.d.ts +4 -0
- package/dist/components/locale-switcher/_components/korea-flag.d.ts.map +1 -0
- package/dist/components/locale-switcher/_components/korea-flag.js +4 -0
- package/dist/components/locale-switcher/_components/taiwan-flag.d.ts +2 -0
- package/dist/components/locale-switcher/_components/taiwan-flag.d.ts.map +1 -0
- package/dist/components/locale-switcher/_components/taiwan-flag.js +4 -0
- package/dist/components/locale-switcher/_components/usa-flag.d.ts +4 -0
- package/dist/components/locale-switcher/_components/usa-flag.d.ts.map +1 -0
- package/dist/components/locale-switcher/_components/usa-flag.js +4 -0
- package/dist/components/locale-switcher/index.d.ts +11 -0
- package/dist/components/locale-switcher/index.d.ts.map +1 -0
- package/dist/components/locale-switcher/index.js +69 -0
- package/dist/components/theme-switcher/index.d.ts +3 -0
- package/dist/components/theme-switcher/index.d.ts.map +1 -0
- package/dist/components/theme-switcher/index.js +20 -0
- package/dist/components/tooltip/index.d.ts +8 -0
- package/dist/components/tooltip/index.d.ts.map +1 -0
- package/dist/components/tooltip/index.js +40 -0
- package/dist/i18n/init-lingui.d.ts +7 -0
- package/dist/i18n/init-lingui.d.ts.map +1 -0
- package/dist/i18n/init-lingui.js +7 -0
- package/dist/i18n/lingui.setup.d.ts +15 -0
- package/dist/i18n/lingui.setup.d.ts.map +1 -0
- package/dist/i18n/lingui.setup.js +29 -0
- package/dist/i18n/providers/lingui-client-provider.d.ts +9 -0
- package/dist/i18n/providers/lingui-client-provider.d.ts.map +1 -0
- package/dist/i18n/providers/lingui-client-provider.js +14 -0
- package/dist/i18n/routing.d.ts +25 -0
- package/dist/i18n/routing.d.ts.map +1 -0
- package/dist/i18n/routing.js +252 -0
- package/dist/local-storage/index.d.ts +4 -0
- package/dist/local-storage/index.d.ts.map +1 -0
- package/dist/local-storage/index.js +4 -0
- package/dist/local-storage/local-storage-manager.d.ts +41 -0
- package/dist/local-storage/local-storage-manager.d.ts.map +1 -0
- package/dist/local-storage/local-storage-manager.js +200 -0
- package/dist/local-storage/valtio-persist.d.ts +31 -0
- package/dist/local-storage/valtio-persist.d.ts.map +1 -0
- package/dist/local-storage/valtio-persist.js +84 -0
- package/dist/navigation/index.d.ts +4 -0
- package/dist/navigation/index.d.ts.map +1 -0
- package/dist/navigation/index.js +4 -0
- package/dist/navigation/permissions.d.ts +25 -0
- package/dist/navigation/permissions.d.ts.map +1 -0
- package/dist/navigation/permissions.js +97 -0
- package/dist/navigation/types.d.ts +57 -0
- package/dist/navigation/types.d.ts.map +1 -0
- package/dist/navigation/types.js +1 -0
- package/dist/navigation/utils.d.ts +42 -0
- package/dist/navigation/utils.d.ts.map +1 -0
- package/dist/navigation/utils.js +107 -0
- package/dist/utils/cookie.d.ts +3 -0
- package/dist/utils/cookie.d.ts.map +1 -0
- package/dist/utils/cookie.js +22 -0
- package/dist/utils/helpers.d.ts +5 -0
- package/dist/utils/helpers.d.ts.map +1 -0
- package/dist/utils/helpers.js +18 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/sitemap.d.ts +13 -0
- package/dist/utils/sitemap.d.ts.map +1 -0
- package/dist/utils/sitemap.js +19 -0
- package/package.json +126 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ReadonlyURLSearchParams } from 'next/navigation';
|
|
2
|
+
import { type NextRequest, NextResponse } from 'next/server';
|
|
3
|
+
/**
|
|
4
|
+
* Get all available locales
|
|
5
|
+
*/
|
|
6
|
+
export declare function getLocales(): string[];
|
|
7
|
+
/**
|
|
8
|
+
* Get default locale
|
|
9
|
+
*/
|
|
10
|
+
export declare function getDefaultLocale(): string;
|
|
11
|
+
export declare function handleLocaleRouting(request: NextRequest): NextResponse<unknown>;
|
|
12
|
+
export declare function getRequestLocale(requestHeaders: Headers): string;
|
|
13
|
+
export declare function getCookieLocale(requestHeaders: Headers, pathname?: string): string | undefined;
|
|
14
|
+
export declare function getChangeLocalePath(pathname: string, currentLocale: string, nextLocale: string): string;
|
|
15
|
+
export declare function getPathname({ locale, href }: {
|
|
16
|
+
locale: string;
|
|
17
|
+
href: string;
|
|
18
|
+
}): string;
|
|
19
|
+
export declare function getLanguageAlternates(pathname?: string): Record<string, string>;
|
|
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;
|
|
25
|
+
//# sourceMappingURL=routing.d.ts.map
|
|
@@ -0,0 +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;AAgB7D;;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"}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { getCookieFromHeaders } from '../utils/cookie';
|
|
3
|
+
import { match } from '@formatjs/intl-localematcher';
|
|
4
|
+
import linguiConfig from 'lingui.config';
|
|
5
|
+
import Negotiator from 'negotiator';
|
|
6
|
+
const { locales, fallbackLocales } = linguiConfig;
|
|
7
|
+
const DEFAULT_FALLBACK = () => fallbackLocales && typeof fallbackLocales === 'object' ? fallbackLocales.default || 'en' : 'en';
|
|
8
|
+
const LOCALE_COOKIE_NAME = 'NEXT_LOCALE';
|
|
9
|
+
const LOCALE_PREFIX = 'as-needed';
|
|
10
|
+
/**
|
|
11
|
+
* Get all available locales
|
|
12
|
+
*/
|
|
13
|
+
export function getLocales() {
|
|
14
|
+
return locales;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Get default locale
|
|
18
|
+
*/
|
|
19
|
+
export function getDefaultLocale() {
|
|
20
|
+
return DEFAULT_FALLBACK();
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* 쿠키를 설정하는 헬퍼 함수
|
|
24
|
+
*/
|
|
25
|
+
const setCookie = (response, locale) => {
|
|
26
|
+
response.cookies.set(LOCALE_COOKIE_NAME, locale, {
|
|
27
|
+
path: '/',
|
|
28
|
+
sameSite: 'lax',
|
|
29
|
+
});
|
|
30
|
+
return response;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* URL에서 locale 부분을 제거하는 헬퍼 함수
|
|
34
|
+
*/
|
|
35
|
+
const removeLocaleFromPath = (pathname, locale) => {
|
|
36
|
+
return pathname.replace(`/${locale}`, '') || '/';
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* URL에서 locale을 제거하고 리다이렉트하는 함수
|
|
40
|
+
*/
|
|
41
|
+
const redirectWithoutLocale = (request, pathname, locale, shouldSetCookie = false) => {
|
|
42
|
+
const newPathname = removeLocaleFromPath(pathname, locale);
|
|
43
|
+
const url = new URL(newPathname, request.url);
|
|
44
|
+
url.search = request.nextUrl.search;
|
|
45
|
+
url.hash = request.nextUrl.hash;
|
|
46
|
+
const response = NextResponse.redirect(url, 302);
|
|
47
|
+
response.headers.set('x-pathname', newPathname);
|
|
48
|
+
if (shouldSetCookie) {
|
|
49
|
+
setCookie(response, locale);
|
|
50
|
+
}
|
|
51
|
+
return response;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* 내부적으로 locale을 처리하는 rewrite 함수
|
|
55
|
+
*/
|
|
56
|
+
const rewriteWithLocale = (request, pathname, locale) => {
|
|
57
|
+
const internalUrl = new URL(`/${locale}${pathname}`, request.url);
|
|
58
|
+
internalUrl.search = request.nextUrl.search;
|
|
59
|
+
internalUrl.hash = request.nextUrl.hash;
|
|
60
|
+
const response = NextResponse.rewrite(internalUrl);
|
|
61
|
+
response.headers.set('x-pathname', pathname);
|
|
62
|
+
return response;
|
|
63
|
+
};
|
|
64
|
+
export function handleLocaleRouting(request) {
|
|
65
|
+
const { pathname } = request.nextUrl;
|
|
66
|
+
const cookies = request.cookies;
|
|
67
|
+
const localeCookie = cookies.get(LOCALE_COOKIE_NAME);
|
|
68
|
+
const defaultFallback = DEFAULT_FALLBACK();
|
|
69
|
+
// 1. URL에서 locale 감지
|
|
70
|
+
let pathLocale;
|
|
71
|
+
const pathnameHasLocale = locales.some((locale) => {
|
|
72
|
+
if (pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`) {
|
|
73
|
+
pathLocale = locale;
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
});
|
|
78
|
+
// 2. URL에 locale이 포함된 경우
|
|
79
|
+
if (pathnameHasLocale) {
|
|
80
|
+
// 이미 path에 locale이 있을 때
|
|
81
|
+
const response = NextResponse.next();
|
|
82
|
+
response.headers.set('x-pathname', pathname);
|
|
83
|
+
// 쿠키 값이 path locale과 다를 경우
|
|
84
|
+
if (localeCookie?.value !== pathLocale) {
|
|
85
|
+
// 기본 locale인 경우 URL에서 제거
|
|
86
|
+
if (LOCALE_PREFIX === 'as-needed' && pathLocale === defaultFallback) {
|
|
87
|
+
return redirectWithoutLocale(request, pathname, pathLocale, true);
|
|
88
|
+
}
|
|
89
|
+
// 다른 locale의 경우 쿠키 설정
|
|
90
|
+
return setCookie(response, pathLocale);
|
|
91
|
+
}
|
|
92
|
+
// locale은 같지만 기본 locale이고 as-needed 설정인 경우
|
|
93
|
+
if (LOCALE_PREFIX === 'as-needed' && pathLocale === defaultFallback) {
|
|
94
|
+
return redirectWithoutLocale(request, pathname, pathLocale);
|
|
95
|
+
}
|
|
96
|
+
return response;
|
|
97
|
+
}
|
|
98
|
+
// 3. URL에 locale이 없는 경우
|
|
99
|
+
// 쿠키가 기본 locale이고, as-needed 설정일 때 내부적으로만 locale 처리
|
|
100
|
+
if (LOCALE_PREFIX === 'as-needed' && localeCookie?.value === defaultFallback) {
|
|
101
|
+
return rewriteWithLocale(request, pathname, defaultFallback);
|
|
102
|
+
}
|
|
103
|
+
// 4. 적절한 locale 감지 및 적용
|
|
104
|
+
const defaultLocale = getRequestLocale(request.headers);
|
|
105
|
+
let locale = getCookieLocale(request.headers, pathname) || defaultLocale;
|
|
106
|
+
const findLocale = match([locale], locales, defaultLocale);
|
|
107
|
+
if (locale !== findLocale) {
|
|
108
|
+
locale = findLocale;
|
|
109
|
+
}
|
|
110
|
+
// 기본 locale이고 as-needed 설정인 경우 URL에는 포함하지 않음
|
|
111
|
+
if (LOCALE_PREFIX === 'as-needed' && locale === defaultFallback) {
|
|
112
|
+
return rewriteWithLocale(request, pathname, locale);
|
|
113
|
+
}
|
|
114
|
+
// 다른 locale은 URL에 표시
|
|
115
|
+
const newPathname = getChangeLocalePath(pathname, defaultFallback, locale);
|
|
116
|
+
request.nextUrl.pathname = newPathname;
|
|
117
|
+
const response = NextResponse.redirect(request.nextUrl);
|
|
118
|
+
response.headers.set('x-pathname', newPathname);
|
|
119
|
+
// 쿠키가 없는 경우 설정
|
|
120
|
+
if (localeCookie?.value === undefined) {
|
|
121
|
+
setCookie(response, locale);
|
|
122
|
+
}
|
|
123
|
+
return response;
|
|
124
|
+
}
|
|
125
|
+
export function getRequestLocale(requestHeaders) {
|
|
126
|
+
const langHeader = requestHeaders.get('accept-language') || undefined;
|
|
127
|
+
const languages = new Negotiator({
|
|
128
|
+
headers: { 'accept-language': langHeader },
|
|
129
|
+
}).languages(locales.slice());
|
|
130
|
+
const activeLocale = languages[0] || DEFAULT_FALLBACK();
|
|
131
|
+
return activeLocale;
|
|
132
|
+
}
|
|
133
|
+
export function getCookieLocale(requestHeaders, pathname) {
|
|
134
|
+
const cookieLocale = getCookieFromHeaders(requestHeaders, LOCALE_COOKIE_NAME);
|
|
135
|
+
if (cookieLocale) {
|
|
136
|
+
return cookieLocale;
|
|
137
|
+
}
|
|
138
|
+
let pathLocale = undefined;
|
|
139
|
+
if (pathname) {
|
|
140
|
+
const pathMatch = pathname.match(/^\/([^\\/]+)(?:\/|$)/);
|
|
141
|
+
if (pathMatch && pathMatch[1]) {
|
|
142
|
+
const potentialLocale = pathMatch[1];
|
|
143
|
+
if (Array.isArray(locales) && locales.includes(potentialLocale)) {
|
|
144
|
+
pathLocale = potentialLocale;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return pathLocale;
|
|
149
|
+
}
|
|
150
|
+
export function getChangeLocalePath(pathname, currentLocale, nextLocale) {
|
|
151
|
+
// Create the new path based on whether the current path has a locale segment or not
|
|
152
|
+
let pathNameWithoutLocale;
|
|
153
|
+
// Check if pathname starts with current locale
|
|
154
|
+
if (pathname === `/${currentLocale}` || pathname.startsWith(`/${currentLocale}/`)) {
|
|
155
|
+
// Path has locale: /ko or /ko/something
|
|
156
|
+
pathNameWithoutLocale = pathname.slice(currentLocale.length + 1); // Remove /locale part
|
|
157
|
+
if (pathNameWithoutLocale.startsWith('/')) {
|
|
158
|
+
pathNameWithoutLocale = pathNameWithoutLocale.slice(1); // Remove leading slash if any
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
else if (pathname === '/') {
|
|
162
|
+
// Root path
|
|
163
|
+
pathNameWithoutLocale = '';
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
// Path doesn't have locale prefix: /something
|
|
167
|
+
pathNameWithoutLocale = pathname.startsWith('/') ? pathname.slice(1) : pathname;
|
|
168
|
+
}
|
|
169
|
+
return `/${nextLocale}${pathNameWithoutLocale ? '/' + pathNameWithoutLocale : ''}`;
|
|
170
|
+
}
|
|
171
|
+
export function getPathname({ locale, href }) {
|
|
172
|
+
const defaultFallback = DEFAULT_FALLBACK();
|
|
173
|
+
if (href === '/' || href === '') {
|
|
174
|
+
return LOCALE_PREFIX === 'as-needed' && locale === defaultFallback ? '/' : `/${locale}`;
|
|
175
|
+
}
|
|
176
|
+
if (LOCALE_PREFIX === 'as-needed' && locale === defaultFallback) {
|
|
177
|
+
return href.startsWith('/') ? href : `/${href}`;
|
|
178
|
+
}
|
|
179
|
+
return href.startsWith('/') ? `/${locale}${href}` : `/${locale}/${href}`;
|
|
180
|
+
}
|
|
181
|
+
export function getLanguageAlternates(pathname = '/') {
|
|
182
|
+
const defaultFallback = DEFAULT_FALLBACK();
|
|
183
|
+
// Remove any existing locale from the pathname to get the base path
|
|
184
|
+
let basePath = pathname;
|
|
185
|
+
locales.forEach((locale) => {
|
|
186
|
+
const localePattern = new RegExp(`^/${locale}(/|$)`);
|
|
187
|
+
if (localePattern.test(basePath)) {
|
|
188
|
+
basePath = basePath.replace(localePattern, '/');
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
// Normalize path
|
|
192
|
+
basePath = basePath.replace(/\/+/g, '/');
|
|
193
|
+
const alternates = {};
|
|
194
|
+
// Set x-default based on LOCALE_PREFIX and defaultFallback
|
|
195
|
+
if (LOCALE_PREFIX === 'as-needed') {
|
|
196
|
+
alternates['x-default'] = basePath;
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
alternates['x-default'] = `/${defaultFallback}${basePath === '/' ? '' : basePath}`;
|
|
200
|
+
}
|
|
201
|
+
locales
|
|
202
|
+
.filter((locale) => locale !== 'pseudo')
|
|
203
|
+
.forEach((locale) => {
|
|
204
|
+
if (LOCALE_PREFIX === 'as-needed' && locale === defaultFallback) {
|
|
205
|
+
alternates[locale] = basePath;
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
alternates[locale] = `/${locale}${basePath === '/' ? '' : basePath}`;
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
return alternates;
|
|
212
|
+
}
|
|
213
|
+
export async function getCurrentPathname() {
|
|
214
|
+
const { headers } = await import('next/headers');
|
|
215
|
+
const headersList = await headers();
|
|
216
|
+
return headersList.get('x-pathname') || '';
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* pathname과 params를 조합하여 전체 URL을 생성하는 함수
|
|
220
|
+
*/
|
|
221
|
+
export function getFullUrl(pathname, params) {
|
|
222
|
+
const baseUrl = process.env.NEXT_PUBLIC_APP_URL || '';
|
|
223
|
+
if (!params) {
|
|
224
|
+
return `${baseUrl}${pathname}`;
|
|
225
|
+
}
|
|
226
|
+
const searchParams = new URLSearchParams();
|
|
227
|
+
// ReadonlyURLSearchParams인 경우
|
|
228
|
+
if (params instanceof URLSearchParams) {
|
|
229
|
+
params.forEach((value, key) => {
|
|
230
|
+
// locale 파라미터는 제외
|
|
231
|
+
if (key !== 'locale') {
|
|
232
|
+
searchParams.append(key, value);
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
// Record<string, string | string[] | undefined>인 경우
|
|
238
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
239
|
+
// undefined 값은 건너뛰기
|
|
240
|
+
if (value === undefined)
|
|
241
|
+
return;
|
|
242
|
+
if (Array.isArray(value)) {
|
|
243
|
+
value.forEach((v) => searchParams.append(key, v));
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
searchParams.append(key, value);
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
const queryString = searchParams.toString();
|
|
251
|
+
return `${baseUrl}${pathname}${queryString ? `?${queryString}` : ''}`;
|
|
252
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/local-storage/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAG9F,OAAO,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAGjE,YAAY,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
interface LocalForageOptions {
|
|
2
|
+
driver?: string | string[];
|
|
3
|
+
name?: string;
|
|
4
|
+
storeName?: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
}
|
|
7
|
+
interface LocalForageInstance {
|
|
8
|
+
setItem<T>(key: string, value: T): Promise<T>;
|
|
9
|
+
getItem<T>(key: string): Promise<T | null>;
|
|
10
|
+
removeItem(key: string): Promise<void>;
|
|
11
|
+
clear(): Promise<void>;
|
|
12
|
+
keys(): Promise<string[]>;
|
|
13
|
+
createInstance(options: LocalForageOptions): LocalForageInstance;
|
|
14
|
+
}
|
|
15
|
+
export declare const createStorageInstance: (storeName: string) => Promise<LocalForageInstance | null>;
|
|
16
|
+
export declare class LocalStorageManager<T = unknown> {
|
|
17
|
+
private storageKey;
|
|
18
|
+
private instanceName?;
|
|
19
|
+
private instance;
|
|
20
|
+
private initialized;
|
|
21
|
+
constructor(key: string, instanceName?: string);
|
|
22
|
+
private ensureInitialized;
|
|
23
|
+
setItem(value: T): Promise<T>;
|
|
24
|
+
getItem(): Promise<T | null>;
|
|
25
|
+
removeItem(): Promise<void>;
|
|
26
|
+
hasItem(): Promise<boolean>;
|
|
27
|
+
updateItem(updateFn: (current: T | null) => T): Promise<T>;
|
|
28
|
+
}
|
|
29
|
+
export declare const storage: {
|
|
30
|
+
setMultiple(items: Record<string, unknown>): Promise<void>;
|
|
31
|
+
getMultiple(keys: string[]): Promise<Record<string, unknown>>;
|
|
32
|
+
removeMultiple(keys: string[]): Promise<void>;
|
|
33
|
+
clearAll(): Promise<void>;
|
|
34
|
+
getAllKeys(): Promise<string[]>;
|
|
35
|
+
getStorageInfo(): Promise<{
|
|
36
|
+
keys: string[];
|
|
37
|
+
size: number;
|
|
38
|
+
}>;
|
|
39
|
+
};
|
|
40
|
+
export {};
|
|
41
|
+
//# sourceMappingURL=local-storage-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-storage-manager.d.ts","sourceRoot":"","sources":["../../src/local-storage/local-storage-manager.ts"],"names":[],"mappings":"AAIA,UAAU,kBAAkB;IAC1B,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,UAAU,mBAAmB;IAC3B,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC9C,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAC3C,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC1B,cAAc,CAAC,OAAO,EAAE,kBAAkB,GAAG,mBAAmB,CAAC;CAClE;AAoCD,eAAO,MAAM,qBAAqB,GAAU,WAAW,MAAM,KAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAUjG,CAAC;AAGF,qBAAa,mBAAmB,CAAC,CAAC,GAAG,OAAO;IAC1C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,YAAY,CAAC,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAoC;IACpD,OAAO,CAAC,WAAW,CAAS;gBAEhB,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM;YAKhC,iBAAiB;IA2BzB,OAAO,CAAC,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAU7B,OAAO,IAAI,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAe5B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAU3B,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAiB3B,UAAU,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAMjE;AAGD,eAAO,MAAM,OAAO;uBAEO,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;sBAWxC,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;yBAwBxC,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;gBAWjC,OAAO,CAAC,IAAI,CAAC;kBAUX,OAAO,CAAC,MAAM,EAAE,CAAC;sBAUb,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAmBlE,CAAC"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { isBrowser } from '../utils/helpers';
|
|
2
|
+
import { getConfig } from '@korioinc/next-conf';
|
|
3
|
+
// Lazy-loaded localforage instance
|
|
4
|
+
let localforageInstance = null;
|
|
5
|
+
// Get localforage instance (dynamic import)
|
|
6
|
+
async function getLocalforage() {
|
|
7
|
+
if (!isBrowser()) {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
if (!localforageInstance) {
|
|
11
|
+
try {
|
|
12
|
+
const localforageModule = await import('localforage');
|
|
13
|
+
const localforage = localforageModule.default;
|
|
14
|
+
const config = await getConfig();
|
|
15
|
+
// Configure localforage with config values
|
|
16
|
+
localforage.config({
|
|
17
|
+
driver: config.storage?.driver || localforage.LOCALSTORAGE, // LOCALSTORAGE, WEBSQL, INDEXEDDB
|
|
18
|
+
name: config.storage?.name || 'app-storage',
|
|
19
|
+
storeName: config.storage?.storeName || 'default-store',
|
|
20
|
+
});
|
|
21
|
+
localforageInstance = localforage;
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
console.error('Failed to load localforage:', error);
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return localforageInstance;
|
|
29
|
+
}
|
|
30
|
+
// Create a custom instance for specific data types
|
|
31
|
+
export const createStorageInstance = async (storeName) => {
|
|
32
|
+
const localforage = await getLocalforage();
|
|
33
|
+
if (!localforage)
|
|
34
|
+
return null;
|
|
35
|
+
const config = await getConfig();
|
|
36
|
+
return localforage.createInstance({
|
|
37
|
+
name: config.storage?.name || 'app-storage',
|
|
38
|
+
storeName: storeName,
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
// Type-safe storage manager
|
|
42
|
+
export class LocalStorageManager {
|
|
43
|
+
storageKey;
|
|
44
|
+
instanceName;
|
|
45
|
+
instance = null;
|
|
46
|
+
initialized = false;
|
|
47
|
+
constructor(key, instanceName) {
|
|
48
|
+
this.storageKey = key;
|
|
49
|
+
this.instanceName = instanceName;
|
|
50
|
+
}
|
|
51
|
+
async ensureInitialized() {
|
|
52
|
+
if (this.initialized && this.instance) {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
if (!isBrowser()) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
if (this.instanceName) {
|
|
60
|
+
this.instance = await createStorageInstance(this.instanceName);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
this.instance = await getLocalforage();
|
|
64
|
+
}
|
|
65
|
+
this.initialized = true;
|
|
66
|
+
return this.instance !== null;
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
console.error('Failed to initialize storage:', error);
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Save item to storage
|
|
74
|
+
async setItem(value) {
|
|
75
|
+
const ready = await this.ensureInitialized();
|
|
76
|
+
if (!ready || !this.instance) {
|
|
77
|
+
throw new Error('Storage not available');
|
|
78
|
+
}
|
|
79
|
+
return await this.instance.setItem(this.storageKey, value);
|
|
80
|
+
}
|
|
81
|
+
// Get item from storage
|
|
82
|
+
async getItem() {
|
|
83
|
+
const ready = await this.ensureInitialized();
|
|
84
|
+
if (!ready || !this.instance) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
return await this.instance.getItem(this.storageKey);
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
// Error getting item
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Remove item from storage
|
|
96
|
+
async removeItem() {
|
|
97
|
+
const ready = await this.ensureInitialized();
|
|
98
|
+
if (!ready || !this.instance) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
await this.instance.removeItem(this.storageKey);
|
|
102
|
+
}
|
|
103
|
+
// Check if item exists
|
|
104
|
+
async hasItem() {
|
|
105
|
+
const ready = await this.ensureInitialized();
|
|
106
|
+
if (!ready || !this.instance) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
const value = await this.instance.getItem(this.storageKey);
|
|
111
|
+
return value !== null;
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
// Error checking item
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Update item (merge with existing data)
|
|
119
|
+
async updateItem(updateFn) {
|
|
120
|
+
const current = await this.getItem();
|
|
121
|
+
const updated = updateFn(current);
|
|
122
|
+
return await this.setItem(updated);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Utility functions for common operations
|
|
126
|
+
export const storage = {
|
|
127
|
+
// Set multiple items at once
|
|
128
|
+
async setMultiple(items) {
|
|
129
|
+
if (!isBrowser())
|
|
130
|
+
return;
|
|
131
|
+
const localforage = await getLocalforage();
|
|
132
|
+
if (!localforage)
|
|
133
|
+
return;
|
|
134
|
+
const promises = Object.entries(items).map(([key, value]) => localforage.setItem(key, value));
|
|
135
|
+
await Promise.all(promises);
|
|
136
|
+
},
|
|
137
|
+
// Get multiple items at once
|
|
138
|
+
async getMultiple(keys) {
|
|
139
|
+
if (!isBrowser())
|
|
140
|
+
return {};
|
|
141
|
+
const localforage = await getLocalforage();
|
|
142
|
+
if (!localforage)
|
|
143
|
+
return {};
|
|
144
|
+
const promises = keys.map(async (key) => {
|
|
145
|
+
const value = await localforage.getItem(key);
|
|
146
|
+
return { key, value };
|
|
147
|
+
});
|
|
148
|
+
const results = await Promise.all(promises);
|
|
149
|
+
return results.reduce((acc, { key, value }) => {
|
|
150
|
+
acc[key] = value;
|
|
151
|
+
return acc;
|
|
152
|
+
}, {});
|
|
153
|
+
},
|
|
154
|
+
// Remove multiple items at once
|
|
155
|
+
async removeMultiple(keys) {
|
|
156
|
+
if (!isBrowser())
|
|
157
|
+
return;
|
|
158
|
+
const localforage = await getLocalforage();
|
|
159
|
+
if (!localforage)
|
|
160
|
+
return;
|
|
161
|
+
const promises = keys.map((key) => localforage.removeItem(key));
|
|
162
|
+
await Promise.all(promises);
|
|
163
|
+
},
|
|
164
|
+
// Clear all storage
|
|
165
|
+
async clearAll() {
|
|
166
|
+
if (!isBrowser())
|
|
167
|
+
return;
|
|
168
|
+
const localforage = await getLocalforage();
|
|
169
|
+
if (!localforage)
|
|
170
|
+
return;
|
|
171
|
+
await localforage.clear();
|
|
172
|
+
},
|
|
173
|
+
// Get all keys
|
|
174
|
+
async getAllKeys() {
|
|
175
|
+
if (!isBrowser())
|
|
176
|
+
return [];
|
|
177
|
+
const localforage = await getLocalforage();
|
|
178
|
+
if (!localforage)
|
|
179
|
+
return [];
|
|
180
|
+
return await localforage.keys();
|
|
181
|
+
},
|
|
182
|
+
// Get storage size info
|
|
183
|
+
async getStorageInfo() {
|
|
184
|
+
if (!isBrowser())
|
|
185
|
+
return { keys: [], size: 0 };
|
|
186
|
+
const localforage = await getLocalforage();
|
|
187
|
+
if (!localforage)
|
|
188
|
+
return { keys: [], size: 0 };
|
|
189
|
+
const keys = await localforage.keys();
|
|
190
|
+
let totalSize = 0;
|
|
191
|
+
for (const key of keys) {
|
|
192
|
+
const value = await localforage.getItem(key);
|
|
193
|
+
if (value) {
|
|
194
|
+
// Rough estimation of size
|
|
195
|
+
totalSize += JSON.stringify(value).length;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return { keys, size: totalSize };
|
|
199
|
+
},
|
|
200
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface PersistOptions<T> {
|
|
2
|
+
key: string;
|
|
3
|
+
storage?: Storage;
|
|
4
|
+
serialize?: (value: T) => string;
|
|
5
|
+
deserialize?: (value: string) => T;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Valtio persistence helper for Next.js with SSR support
|
|
9
|
+
* Automatically syncs Valtio state with localStorage/sessionStorage
|
|
10
|
+
*/
|
|
11
|
+
export declare function persist<T extends object>(store: T, options: PersistOptions<T>): {
|
|
12
|
+
hydrate: () => Promise<void>;
|
|
13
|
+
clearStorage: () => Promise<void>;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Create a persisted Valtio store with TypeScript support
|
|
17
|
+
* Example usage:
|
|
18
|
+
*
|
|
19
|
+
* const todoStore = createPersistedStore(
|
|
20
|
+
* 'todos',
|
|
21
|
+
* {
|
|
22
|
+
* todos: [] as Todo[],
|
|
23
|
+
* addTodo(text: string) { ... }
|
|
24
|
+
* }
|
|
25
|
+
* );
|
|
26
|
+
*/
|
|
27
|
+
export declare function createPersistedStore<T extends object>(key: string, initialState: T, options?: Omit<PersistOptions<T>, 'key'>): T & {
|
|
28
|
+
hydrate: () => Promise<void>;
|
|
29
|
+
clearStorage: () => Promise<void>;
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=valtio-persist.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"valtio-persist.d.ts","sourceRoot":"","sources":["../../src/local-storage/valtio-persist.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,MAAM,CAAC;IACjC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,CAAC,CAAC;CACpC;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,MAAM,EACtC,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,GACzB;IACD,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACnC,CA8DA;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,MAAM,EACnD,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,CAAC,EACf,OAAO,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,GACvC,CAAC,GAAG;IACL,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACnC,CAWA"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { isBrowser } from '../utils/helpers';
|
|
2
|
+
import { subscribe } from 'valtio';
|
|
3
|
+
/**
|
|
4
|
+
* Valtio persistence helper for Next.js with SSR support
|
|
5
|
+
* Automatically syncs Valtio state with localStorage/sessionStorage
|
|
6
|
+
*/
|
|
7
|
+
export function persist(store, options) {
|
|
8
|
+
const { key, storage = typeof window !== 'undefined' ? localStorage : undefined, serialize = JSON.stringify, deserialize = JSON.parse, } = options;
|
|
9
|
+
let isHydrated = false;
|
|
10
|
+
let unsubscribe = null;
|
|
11
|
+
// Hydrate store from storage
|
|
12
|
+
const hydrate = async () => {
|
|
13
|
+
if (!isBrowser() || !storage || isHydrated) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
const storedValue = storage.getItem(key);
|
|
18
|
+
if (storedValue !== null) {
|
|
19
|
+
const parsed = deserialize(storedValue);
|
|
20
|
+
// Merge stored values into the store
|
|
21
|
+
Object.assign(store, parsed);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
console.error(`Failed to hydrate store from key "${key}":`, error);
|
|
26
|
+
}
|
|
27
|
+
finally {
|
|
28
|
+
isHydrated = true;
|
|
29
|
+
}
|
|
30
|
+
// Set up persistence after hydration
|
|
31
|
+
if (!unsubscribe) {
|
|
32
|
+
unsubscribe = subscribe(store, () => {
|
|
33
|
+
if (!storage)
|
|
34
|
+
return;
|
|
35
|
+
try {
|
|
36
|
+
const serialized = serialize(store);
|
|
37
|
+
storage.setItem(key, serialized);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
console.error(`Failed to persist store to key "${key}":`, error);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
// Clear storage
|
|
46
|
+
const clearStorage = async () => {
|
|
47
|
+
if (!isBrowser() || !storage) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
storage.removeItem(key);
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
console.error(`Failed to clear storage for key "${key}":`, error);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
return {
|
|
58
|
+
hydrate,
|
|
59
|
+
clearStorage,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Create a persisted Valtio store with TypeScript support
|
|
64
|
+
* Example usage:
|
|
65
|
+
*
|
|
66
|
+
* const todoStore = createPersistedStore(
|
|
67
|
+
* 'todos',
|
|
68
|
+
* {
|
|
69
|
+
* todos: [] as Todo[],
|
|
70
|
+
* addTodo(text: string) { ... }
|
|
71
|
+
* }
|
|
72
|
+
* );
|
|
73
|
+
*/
|
|
74
|
+
export function createPersistedStore(key, initialState, options) {
|
|
75
|
+
const { hydrate, clearStorage } = persist(initialState, {
|
|
76
|
+
key,
|
|
77
|
+
...options,
|
|
78
|
+
});
|
|
79
|
+
return {
|
|
80
|
+
...initialState,
|
|
81
|
+
hydrate,
|
|
82
|
+
clearStorage,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type { NavigationMenuItem, NavigationUserContext, PermissionCheckFn, FilteredNavigation, NavigationConfig, } from '../navigation/types';
|
|
2
|
+
export { defaultPermissionCheck, hasPermission, filterNavigationByPermissions, getAccessiblePaths, isPathAccessible, } from '../navigation/permissions';
|
|
3
|
+
export { getNavigationUserContext, getFilteredNavigation, NavigationBuilder } from '../navigation/utils';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/navigation/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,kBAAkB,EAClB,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EACL,sBAAsB,EACtB,aAAa,EACb,6BAA6B,EAC7B,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// Permission utilities
|
|
2
|
+
export { defaultPermissionCheck, hasPermission, filterNavigationByPermissions, getAccessiblePaths, isPathAccessible, } from '../navigation/permissions';
|
|
3
|
+
// Main utilities
|
|
4
|
+
export { getNavigationUserContext, getFilteredNavigation, NavigationBuilder } from '../navigation/utils';
|