@raxonltd/raxon-core 1.1.8 → 1.1.14

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.
Files changed (44) hide show
  1. package/core/context/security.context.tsx +9 -5
  2. package/core/feature/address/api/places.api.ts +20 -4
  3. package/core/feature/auth/hook/use.auth.tsx +7 -6
  4. package/core/feature/cart/hook/use.cart.tsx +3 -0
  5. package/core/raxon.context.tsx +7 -0
  6. package/core/server/places.proxy.ts +35 -0
  7. package/core/server/raxon.bootstrap.route.ts +39 -0
  8. package/core/server/raxon.server.ts +80 -0
  9. package/core/util/nexine.axios.tsx +3 -2
  10. package/core/util/storage.keys.ts +39 -0
  11. package/dist/core/context/security.context.d.ts.map +1 -1
  12. package/dist/core/context/security.context.js +8 -5
  13. package/dist/core/feature/address/api/places.api.d.ts.map +1 -1
  14. package/dist/core/feature/address/api/places.api.js +18 -4
  15. package/dist/core/feature/auth/hook/use.auth.d.ts.map +1 -1
  16. package/dist/core/feature/auth/hook/use.auth.js +7 -6
  17. package/dist/core/raxon.context.d.ts +3 -1
  18. package/dist/core/raxon.context.d.ts.map +1 -1
  19. package/dist/core/raxon.context.js +5 -3
  20. package/dist/core/server/places.proxy.d.ts +10 -0
  21. package/dist/core/server/places.proxy.d.ts.map +1 -0
  22. package/dist/core/server/places.proxy.js +24 -0
  23. package/dist/core/server/raxon.bootstrap.route.d.ts +7 -0
  24. package/dist/core/server/raxon.bootstrap.route.d.ts.map +1 -0
  25. package/dist/core/server/raxon.bootstrap.route.js +27 -0
  26. package/dist/core/server/raxon.server.d.ts +24 -0
  27. package/dist/core/server/raxon.server.d.ts.map +1 -0
  28. package/dist/core/server/raxon.server.js +59 -0
  29. package/dist/core/util/nexine.axios.d.ts.map +1 -1
  30. package/dist/core/util/nexine.axios.js +3 -2
  31. package/dist/core/util/storage.keys.d.ts +9 -0
  32. package/dist/core/util/storage.keys.d.ts.map +1 -0
  33. package/dist/core/util/storage.keys.js +35 -0
  34. package/dist/middleware.d.ts +6 -0
  35. package/dist/middleware.d.ts.map +1 -0
  36. package/dist/middleware.js +5 -0
  37. package/dist/server-bootstrap.d.ts +2 -0
  38. package/dist/server-bootstrap.d.ts.map +1 -0
  39. package/dist/server-bootstrap.js +1 -0
  40. package/dist/server.d.ts +3 -0
  41. package/dist/server.d.ts.map +1 -0
  42. package/dist/server.js +1 -0
  43. package/dist/tsconfig.tsbuildinfo +1 -1
  44. package/package.json +11 -1
@@ -5,6 +5,7 @@ import { useRouter, usePathname } from 'next/navigation';
5
5
  import { LoginType, User } from '@/core/interface/prisma.interface';
6
6
  import { useAuth } from '@/core/feature/auth/hook/use.auth';
7
7
  import { useProfile } from '@/core/feature/profile/hook/use.profile';
8
+ import { getToken, getTokenChangedEventName, getTokenStorageKey, removeToken } from '@/core/util/storage.keys';
8
9
 
9
10
  export interface SecurityState {
10
11
  profile: User | null | undefined;
@@ -58,7 +59,7 @@ export const useSecurityState = (): SecurityState => {
58
59
 
59
60
  const checkToken = useCallback(() => {
60
61
  if (typeof window !== 'undefined') {
61
- const token = localStorage.getItem('koksal-token');
62
+ const token = getToken();
62
63
  if (token && token.trim() !== '' && token.length > 3) {
63
64
  setAuthLoading(true);
64
65
  tokenCheck(undefined, {
@@ -76,7 +77,7 @@ export const useSecurityState = (): SecurityState => {
76
77
  }
77
78
 
78
79
  if (isInvalidTokenError(error)) {
79
- localStorage.removeItem('koksal-token');
80
+ removeToken();
80
81
  ensureGuestLogin();
81
82
  return;
82
83
  }
@@ -97,8 +98,11 @@ export const useSecurityState = (): SecurityState => {
97
98
 
98
99
  useEffect(() => {
99
100
  if (typeof window !== 'undefined') {
101
+ const tokenStorageKey = getTokenStorageKey();
102
+ const tokenChangedEvent = getTokenChangedEventName();
103
+
100
104
  const handleStorageChange = (e: StorageEvent) => {
101
- if (e.key === 'koksal-token') {
105
+ if (e.key === tokenStorageKey) {
102
106
  checkToken();
103
107
  }
104
108
  };
@@ -108,11 +112,11 @@ export const useSecurityState = (): SecurityState => {
108
112
  };
109
113
 
110
114
  window.addEventListener('storage', handleStorageChange);
111
- window.addEventListener('koksal-token-changed', handleCustomStorageChange);
115
+ window.addEventListener(tokenChangedEvent, handleCustomStorageChange);
112
116
 
113
117
  return () => {
114
118
  window.removeEventListener('storage', handleStorageChange);
115
- window.removeEventListener('koksal-token-changed', handleCustomStorageChange);
119
+ window.removeEventListener(tokenChangedEvent, handleCustomStorageChange);
116
120
  };
117
121
  }
118
122
  }, [checkToken]);
@@ -24,11 +24,19 @@ export async function fetchPlaceAutocomplete(
24
24
  throw new Error('Google Maps API key not configured');
25
25
  }
26
26
 
27
- const url = new URL('https://maps.googleapis.com/maps/api/place/autocomplete/json');
27
+ const isBrowser = typeof window !== 'undefined';
28
+ let url: URL;
29
+
30
+ if (isBrowser) {
31
+ url = new URL('/api/places/autocomplete', window.location.origin);
32
+ } else {
33
+ url = new URL('https://maps.googleapis.com/maps/api/place/autocomplete/json');
34
+ url.searchParams.set('key', apiKey);
35
+ }
36
+
28
37
  url.searchParams.set('input', input);
29
38
  url.searchParams.set('components', components);
30
39
  url.searchParams.set('language', language);
31
- url.searchParams.set('key', apiKey);
32
40
 
33
41
  const response = await fetch(url.toString(), { signal });
34
42
 
@@ -54,11 +62,19 @@ export async function fetchPlaceDetails(
54
62
  throw new Error('Google Maps API key not configured');
55
63
  }
56
64
 
57
- const url = new URL('https://maps.googleapis.com/maps/api/place/details/json');
65
+ const isBrowser = typeof window !== 'undefined';
66
+ let url: URL;
67
+
68
+ if (isBrowser) {
69
+ url = new URL('/api/places/details', window.location.origin);
70
+ } else {
71
+ url = new URL('https://maps.googleapis.com/maps/api/place/details/json');
72
+ url.searchParams.set('key', apiKey);
73
+ }
74
+
58
75
  url.searchParams.set('place_id', placeId);
59
76
  url.searchParams.set('fields', 'geometry,address_components,formatted_address');
60
77
  url.searchParams.set('language', language);
61
- url.searchParams.set('key', apiKey);
62
78
 
63
79
  const response = await fetch(url.toString(), { signal });
64
80
 
@@ -1,4 +1,5 @@
1
1
  import { nexineAxios } from "@/core/util/nexine.axios";
2
+ import { dispatchTokenChanged, removeToken, setToken } from "@/core/util/storage.keys";
2
3
  import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
3
4
  import { useEffect, useState } from "react";
4
5
  import toast from "react-hot-toast";
@@ -40,7 +41,7 @@ export const useAuth = () => {
40
41
  return nexineAxios.post('/auth/login/email', data)
41
42
  },
42
43
  onSuccess: (response: any) => {
43
- localStorage.setItem("koksal-token", response.data.token);
44
+ setToken(response.data.token);
44
45
  queryClient.invalidateQueries({ queryKey: ["user"] });
45
46
  queryClient.invalidateQueries({ queryKey: ["profile"] });
46
47
  queryClient.invalidateQueries({ queryKey: ["cart"] });
@@ -48,7 +49,7 @@ export const useAuth = () => {
48
49
  // Login success event'ini tetikle
49
50
  if (typeof window !== 'undefined') {
50
51
  window.dispatchEvent(new Event(LOGIN_SUCCESS_EVENT));
51
- window.dispatchEvent(new Event('koksal-token-changed'));
52
+ dispatchTokenChanged();
52
53
  }
53
54
  },
54
55
  })
@@ -59,7 +60,7 @@ export const useAuth = () => {
59
60
  return nexineAxios.post('/auth/login/guest')
60
61
  },
61
62
  onSuccess: (response: any) => {
62
- localStorage.setItem("koksal-token", response.data.token);
63
+ setToken(response.data.token);
63
64
  queryClient.invalidateQueries({ queryKey: ["user"] });
64
65
  queryClient.invalidateQueries({ queryKey: ["profile"] });
65
66
  queryClient.invalidateQueries({ queryKey: ["cart"] });
@@ -68,7 +69,7 @@ export const useAuth = () => {
68
69
  // Login success event'ini tetikle
69
70
  if (typeof window !== 'undefined') {
70
71
  window.dispatchEvent(new Event(LOGIN_SUCCESS_EVENT));
71
- window.dispatchEvent(new Event('koksal-token-changed'));
72
+ dispatchTokenChanged();
72
73
  }
73
74
  },
74
75
  })
@@ -126,14 +127,14 @@ export const useAuth = () => {
126
127
  })
127
128
  },
128
129
  logout: () => {
129
- localStorage.removeItem("koksal-token");
130
+ removeToken();
130
131
  queryClient.invalidateQueries({ queryKey: ["user"] });
131
132
  queryClient.invalidateQueries({ queryKey: ["profile"] });
132
133
 
133
134
  // Logout event'ini tetikle
134
135
  if (typeof window !== 'undefined') {
135
136
  window.dispatchEvent(new Event(LOGOUT_EVENT));
136
- window.dispatchEvent(new Event('koksal-token-changed'));
137
+ dispatchTokenChanged();
137
138
  window.location.reload();
138
139
  }
139
140
  }
@@ -79,6 +79,9 @@ export const useCart = () => {
79
79
  const response = await nexineAxios.post('/customer/basket/me/item', data);
80
80
  return response.data;
81
81
  },
82
+ onSuccess: () => {
83
+ queryClient.invalidateQueries({ queryKey: CART_QUERY_KEY });
84
+ },
82
85
  onError: (error, _newData, context: any) => {
83
86
  if (context?.previousCarts) {
84
87
  context.previousCarts.forEach(([key, value]: any) => {
@@ -29,6 +29,7 @@ import { useCartState, CartState } from "@/core/context/cart.context";
29
29
  import { AnalyticEventProvider } from "@/core/feature/analytic-event/analytic.event.context";
30
30
  import { RaxonContextBrand } from "./interface/context.interface";
31
31
  import { RaxonBootstrapPayload } from "./interface/bootstrap.interface";
32
+ import { DEFAULT_STORAGE_PREFIX } from "./util/storage.keys";
32
33
 
33
34
  export const RaxonContext = createContext<RaxonContextType | undefined>(undefined);
34
35
 
@@ -72,6 +73,8 @@ export interface RaxonProviderProps {
72
73
  children: React.ReactNode;
73
74
  apiKey: string;
74
75
  apiUrl: string;
76
+ /** localStorage anahtarları için önek. Varsayılan: `raxon` (ör. `raxon-token`) */
77
+ storagePrefix?: string;
75
78
  productPathPrefix?: string;
76
79
  analyticAutoTrack?: boolean;
77
80
  /** Varsayılan: `/api/bootstrap` — Next.js BFF veya özel proxy */
@@ -120,6 +123,7 @@ const RaxonProviderInner = ({
120
123
  children,
121
124
  apiKey,
122
125
  apiUrl,
126
+ storagePrefix = DEFAULT_STORAGE_PREFIX,
123
127
  productPathPrefix,
124
128
  analyticAutoTrack,
125
129
  bootstrapUrl = "/api/bootstrap",
@@ -142,6 +146,7 @@ const RaxonProviderInner = ({
142
146
  if (typeof window !== "undefined") {
143
147
  (window as any).__RAXON_API_KEY__ = apiKey;
144
148
  (window as any).__RAXON_API_URL__ = apiUrl;
149
+ (window as any).__RAXON_STORAGE_PREFIX__ = storagePrefix;
145
150
  nexineAxios.defaults.baseURL = apiUrl;
146
151
  nexineAxios.defaults.headers.common["x-api-key"] = apiKey;
147
152
  }
@@ -224,6 +229,7 @@ export const RaxonProvider = ({
224
229
  children,
225
230
  apiKey,
226
231
  apiUrl,
232
+ storagePrefix,
227
233
  productPathPrefix,
228
234
  analyticAutoTrack,
229
235
  bootstrapUrl,
@@ -236,6 +242,7 @@ export const RaxonProvider = ({
236
242
  <RaxonProviderInner
237
243
  apiKey={apiKey}
238
244
  apiUrl={apiUrl}
245
+ storagePrefix={storagePrefix}
239
246
  productPathPrefix={productPathPrefix}
240
247
  analyticAutoTrack={analyticAutoTrack}
241
248
  bootstrapUrl={bootstrapUrl}
@@ -0,0 +1,35 @@
1
+ import { NextResponse } from 'next/server';
2
+ import type { NextRequest } from 'next/server';
3
+
4
+ const GOOGLE_PLACES_URL = {
5
+ autocomplete: 'https://maps.googleapis.com/maps/api/place/autocomplete/json',
6
+ details: 'https://maps.googleapis.com/maps/api/place/details/json',
7
+ } as const;
8
+
9
+ export type GooglePlacesEndpoint = keyof typeof GOOGLE_PLACES_URL;
10
+
11
+ export async function proxyGooglePlaces(
12
+ request: NextRequest,
13
+ endpoint: GooglePlacesEndpoint,
14
+ googleMapsApiKey?: string,
15
+ ) {
16
+ const googleUrl = new URL(GOOGLE_PLACES_URL[endpoint]);
17
+
18
+ request.nextUrl.searchParams.forEach((value, key) => {
19
+ googleUrl.searchParams.set(key, value);
20
+ });
21
+
22
+ const apiKey = googleMapsApiKey ?? process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY ?? '';
23
+ if (!googleUrl.searchParams.has('key') && apiKey) {
24
+ googleUrl.searchParams.set('key', apiKey);
25
+ }
26
+
27
+ try {
28
+ const response = await fetch(googleUrl.toString());
29
+ const data = await response.json();
30
+ return NextResponse.json(data);
31
+ } catch (error) {
32
+ console.error('[raxonServer/places]', error);
33
+ return NextResponse.json({ error: 'Google Places API isteği başarısız' }, { status: 500 });
34
+ }
35
+ }
@@ -0,0 +1,39 @@
1
+ import { NextResponse } from 'next/server';
2
+ import { unstable_cache } from 'next/cache';
3
+ import { fetchRaxonBootstrap } from '@/core/util/fetch.bootstrap';
4
+ import {
5
+ BOOTSTRAP_REVALIDATE_SECONDS,
6
+ bootstrapCacheHeaders,
7
+ } from '@/core/server/raxon.server';
8
+
9
+ async function fetchBootstrapData() {
10
+ const apiUrl = process.env.NEXT_PUBLIC_API_URL;
11
+ const apiKey = process.env.NEXT_PUBLIC_API_KEY;
12
+
13
+ if (!apiUrl || !apiKey) {
14
+ throw new Error('[raxonServer] NEXT_PUBLIC_API_URL veya NEXT_PUBLIC_API_KEY tanımlı değil');
15
+ }
16
+
17
+ return fetchRaxonBootstrap(apiUrl, apiKey);
18
+ }
19
+
20
+ const getCachedBootstrap = unstable_cache(
21
+ fetchBootstrapData,
22
+ ['raxon-bootstrap'],
23
+ { revalidate: BOOTSTRAP_REVALIDATE_SECONDS },
24
+ );
25
+
26
+ /** API route kullanmak isteyenler için: export { GET, revalidate } from '@raxonltd/raxon-core/server/bootstrap' */
27
+ export const revalidate = BOOTSTRAP_REVALIDATE_SECONDS;
28
+
29
+ export async function GET() {
30
+ try {
31
+ const data = await getCachedBootstrap();
32
+ return NextResponse.json(data, {
33
+ headers: bootstrapCacheHeaders(revalidate),
34
+ });
35
+ } catch (error) {
36
+ console.error('[raxonServer]', error);
37
+ return NextResponse.json({ error: 'Bootstrap verisi alınamadı' }, { status: 502 });
38
+ }
39
+ }
@@ -0,0 +1,80 @@
1
+ import { NextResponse } from 'next/server';
2
+ import type { NextRequest } from 'next/server';
3
+ import { fetchRaxonBootstrap } from '@/core/util/fetch.bootstrap';
4
+ import { proxyGooglePlaces } from '@/core/server/places.proxy';
5
+
6
+ const DEFAULT_REVALIDATE_SECONDS = 300;
7
+
8
+ const RAXON_SERVER_PATHS = {
9
+ bootstrap: '/api/bootstrap',
10
+ placesAutocomplete: '/api/places/autocomplete',
11
+ placesDetails: '/api/places/details',
12
+ } as const;
13
+
14
+ export interface RaxonServerOptions {
15
+ apiUrl?: string;
16
+ apiKey?: string;
17
+ googleMapsApiKey?: string;
18
+ revalidate?: number;
19
+ }
20
+
21
+ function resolveCredentials(options: RaxonServerOptions = {}) {
22
+ const apiUrl = options.apiUrl ?? process.env.NEXT_PUBLIC_API_URL;
23
+ const apiKey = options.apiKey ?? process.env.NEXT_PUBLIC_API_KEY;
24
+ return { apiUrl, apiKey };
25
+ }
26
+
27
+ async function fetchBootstrapData(options: RaxonServerOptions = {}) {
28
+ const { apiUrl, apiKey } = resolveCredentials(options);
29
+
30
+ if (!apiUrl || !apiKey) {
31
+ throw new Error('[raxonServer] NEXT_PUBLIC_API_URL veya NEXT_PUBLIC_API_KEY tanımlı değil');
32
+ }
33
+
34
+ return fetchRaxonBootstrap(apiUrl, apiKey);
35
+ }
36
+
37
+ function bootstrapCacheHeaders(revalidate = DEFAULT_REVALIDATE_SECONDS) {
38
+ return {
39
+ 'Cache-Control': `public, s-maxage=${revalidate}, stale-while-revalidate=${revalidate * 2}`,
40
+ };
41
+ }
42
+
43
+ /**
44
+ * Next.js middleware — bootstrap ve Google Places BFF isteklerini karşılar.
45
+ *
46
+ * @example
47
+ * // proxy.ts — config Next.js tarafından statik parse edilmeli, import edilemez
48
+ * import { raxonServer } from '@raxonltd/raxon-core/server';
49
+ * export default raxonServer();
50
+ * export const config = { matcher: ['/api/bootstrap', '/api/places/:path'] };
51
+ */
52
+ export function raxonServer(options: RaxonServerOptions = {}) {
53
+ const revalidate = options.revalidate ?? DEFAULT_REVALIDATE_SECONDS;
54
+
55
+ return async function raxonMiddleware(request: NextRequest) {
56
+ const { pathname } = request.nextUrl;
57
+
58
+ if (pathname === RAXON_SERVER_PATHS.bootstrap) {
59
+ try {
60
+ const data = await fetchBootstrapData(options);
61
+ return NextResponse.json(data, { headers: bootstrapCacheHeaders(revalidate) });
62
+ } catch (error) {
63
+ console.error('[raxonServer/bootstrap]', error);
64
+ return NextResponse.json({ error: 'Bootstrap verisi alınamadı' }, { status: 502 });
65
+ }
66
+ }
67
+
68
+ if (pathname === RAXON_SERVER_PATHS.placesAutocomplete) {
69
+ return proxyGooglePlaces(request, 'autocomplete', options.googleMapsApiKey);
70
+ }
71
+
72
+ if (pathname === RAXON_SERVER_PATHS.placesDetails) {
73
+ return proxyGooglePlaces(request, 'details', options.googleMapsApiKey);
74
+ }
75
+
76
+ return NextResponse.next();
77
+ };
78
+ }
79
+
80
+ export { DEFAULT_REVALIDATE_SECONDS as BOOTSTRAP_REVALIDATE_SECONDS, bootstrapCacheHeaders };
@@ -1,5 +1,6 @@
1
1
  import axios from 'axios';
2
2
  import { toast } from 'react-hot-toast';
3
+ import { getToken, removeToken } from '@/core/util/storage.keys';
3
4
 
4
5
  export const nexineAxios = axios.create({
5
6
  baseURL: typeof window !== 'undefined' ? (window as any).__RAXON_API_URL__ : process.env.NEXT_PUBLIC_API_URL,
@@ -39,7 +40,7 @@ nexineAxios.interceptors.request.use(config => {
39
40
  }
40
41
 
41
42
  if (typeof window !== 'undefined') {
42
- const token = localStorage.getItem('koksal-token');
43
+ const token = getToken();
43
44
  if (token) {
44
45
  config.headers.Authorization = `Bearer ${token}`;
45
46
  }
@@ -83,7 +84,7 @@ nexineAxios.interceptors.response.use(
83
84
 
84
85
  // Token'ı temizle
85
86
  if (typeof window !== 'undefined') {
86
- localStorage.removeItem('koksal-token');
87
+ removeToken();
87
88
  }
88
89
 
89
90
  // /auth/me endpoint'inde toast gösterme (SecurityContext yönetiyor)
@@ -0,0 +1,39 @@
1
+ export const DEFAULT_STORAGE_PREFIX = 'raxon';
2
+
3
+ const TOKEN_SUFFIX = '-token';
4
+ const TOKEN_CHANGED_SUFFIX = '-token-changed';
5
+
6
+ export const getStoragePrefix = (): string => {
7
+ if (typeof window !== 'undefined') {
8
+ return (window as any).__RAXON_STORAGE_PREFIX__ || DEFAULT_STORAGE_PREFIX;
9
+ }
10
+ return DEFAULT_STORAGE_PREFIX;
11
+ };
12
+
13
+ export const getTokenStorageKey = (): string => {
14
+ return `${getStoragePrefix()}${TOKEN_SUFFIX}`;
15
+ };
16
+
17
+ export const getTokenChangedEventName = (): string => {
18
+ return `${getStoragePrefix()}${TOKEN_CHANGED_SUFFIX}`;
19
+ };
20
+
21
+ export const getToken = (): string | null => {
22
+ if (typeof window === 'undefined') return null;
23
+ return localStorage.getItem(getTokenStorageKey());
24
+ };
25
+
26
+ export const setToken = (token: string): void => {
27
+ if (typeof window === 'undefined') return;
28
+ localStorage.setItem(getTokenStorageKey(), token);
29
+ };
30
+
31
+ export const removeToken = (): void => {
32
+ if (typeof window === 'undefined') return;
33
+ localStorage.removeItem(getTokenStorageKey());
34
+ };
35
+
36
+ export const dispatchTokenChanged = (): void => {
37
+ if (typeof window === 'undefined') return;
38
+ window.dispatchEvent(new Event(getTokenChangedEventName()));
39
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"security.context.d.ts","sourceRoot":"","sources":["../../../core/context/security.context.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAa,IAAI,EAAE,MAAM,mCAAmC,CAAC;AAIpE,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC;IACjC,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe,EAAE,OAAO,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,gBAAgB,QAAO,aAuInC,CAAC"}
1
+ {"version":3,"file":"security.context.d.ts","sourceRoot":"","sources":["../../../core/context/security.context.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAa,IAAI,EAAE,MAAM,mCAAmC,CAAC;AAKpE,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC;IACjC,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe,EAAE,OAAO,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,gBAAgB,QAAO,aA0InC,CAAC"}
@@ -4,6 +4,7 @@ import { useRouter, usePathname } from 'next/navigation';
4
4
  import { LoginType } from '../interface/prisma.interface';
5
5
  import { useAuth } from '../feature/auth/hook/use.auth';
6
6
  import { useProfile } from '../feature/profile/hook/use.profile';
7
+ import { getToken, getTokenChangedEventName, getTokenStorageKey, removeToken } from '../util/storage.keys';
7
8
  export const useSecurityState = () => {
8
9
  const router = useRouter();
9
10
  const pathname = usePathname();
@@ -41,7 +42,7 @@ export const useSecurityState = () => {
41
42
  }, [loginGuest]);
42
43
  const checkToken = useCallback(() => {
43
44
  if (typeof window !== 'undefined') {
44
- const token = localStorage.getItem('koksal-token');
45
+ const token = getToken();
45
46
  if (token && token.trim() !== '' && token.length > 3) {
46
47
  setAuthLoading(true);
47
48
  tokenCheck(undefined, {
@@ -58,7 +59,7 @@ export const useSecurityState = () => {
58
59
  return;
59
60
  }
60
61
  if (isInvalidTokenError(error)) {
61
- localStorage.removeItem('koksal-token');
62
+ removeToken();
62
63
  ensureGuestLogin();
63
64
  return;
64
65
  }
@@ -77,8 +78,10 @@ export const useSecurityState = () => {
77
78
  }, [checkToken]);
78
79
  useEffect(() => {
79
80
  if (typeof window !== 'undefined') {
81
+ const tokenStorageKey = getTokenStorageKey();
82
+ const tokenChangedEvent = getTokenChangedEventName();
80
83
  const handleStorageChange = (e) => {
81
- if (e.key === 'koksal-token') {
84
+ if (e.key === tokenStorageKey) {
82
85
  checkToken();
83
86
  }
84
87
  };
@@ -86,10 +89,10 @@ export const useSecurityState = () => {
86
89
  checkToken();
87
90
  };
88
91
  window.addEventListener('storage', handleStorageChange);
89
- window.addEventListener('koksal-token-changed', handleCustomStorageChange);
92
+ window.addEventListener(tokenChangedEvent, handleCustomStorageChange);
90
93
  return () => {
91
94
  window.removeEventListener('storage', handleStorageChange);
92
- window.removeEventListener('koksal-token-changed', handleCustomStorageChange);
95
+ window.removeEventListener(tokenChangedEvent, handleCustomStorageChange);
93
96
  };
94
97
  }
95
98
  }, [checkToken]);
@@ -1 +1 @@
1
- {"version":3,"file":"places.api.d.ts","sourceRoot":"","sources":["../../../../../core/feature/address/api/places.api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,2CAA2C,CAAC;AAMtG,UAAU,yBAAyB;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,MAAM,EACb,EAAE,UAAyB,EAAE,QAAe,EAAE,MAAM,EAAE,GAAE,yBAA8B,GACrF,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAyBlC;AAED,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,MAAM,EACf,EAAE,QAAe,EAAE,MAAM,EAAE,GAAE,oBAAyB,GACrD,OAAO,CAAC,kBAAkB,CAAC,CAyB7B"}
1
+ {"version":3,"file":"places.api.d.ts","sourceRoot":"","sources":["../../../../../core/feature/address/api/places.api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,2CAA2C,CAAC;AAMtG,UAAU,yBAAyB;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,MAAM,EACb,EAAE,UAAyB,EAAE,QAAe,EAAE,MAAM,EAAE,GAAE,yBAA8B,GACrF,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAiClC;AAED,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,MAAM,EACf,EAAE,QAAe,EAAE,MAAM,EAAE,GAAE,oBAAyB,GACrD,OAAO,CAAC,kBAAkB,CAAC,CAiC7B"}
@@ -6,11 +6,18 @@ export async function fetchPlaceAutocomplete(input, { components = 'country:tr',
6
6
  if (!apiKey) {
7
7
  throw new Error('Google Maps API key not configured');
8
8
  }
9
- const url = new URL('https://maps.googleapis.com/maps/api/place/autocomplete/json');
9
+ const isBrowser = typeof window !== 'undefined';
10
+ let url;
11
+ if (isBrowser) {
12
+ url = new URL('/api/places/autocomplete', window.location.origin);
13
+ }
14
+ else {
15
+ url = new URL('https://maps.googleapis.com/maps/api/place/autocomplete/json');
16
+ url.searchParams.set('key', apiKey);
17
+ }
10
18
  url.searchParams.set('input', input);
11
19
  url.searchParams.set('components', components);
12
20
  url.searchParams.set('language', language);
13
- url.searchParams.set('key', apiKey);
14
21
  const response = await fetch(url.toString(), { signal });
15
22
  if (!response.ok) {
16
23
  throw new Error(`Google Places API error: ${response.status}`);
@@ -26,11 +33,18 @@ export async function fetchPlaceDetails(placeId, { language = 'tr', signal } = {
26
33
  if (!apiKey) {
27
34
  throw new Error('Google Maps API key not configured');
28
35
  }
29
- const url = new URL('https://maps.googleapis.com/maps/api/place/details/json');
36
+ const isBrowser = typeof window !== 'undefined';
37
+ let url;
38
+ if (isBrowser) {
39
+ url = new URL('/api/places/details', window.location.origin);
40
+ }
41
+ else {
42
+ url = new URL('https://maps.googleapis.com/maps/api/place/details/json');
43
+ url.searchParams.set('key', apiKey);
44
+ }
30
45
  url.searchParams.set('place_id', placeId);
31
46
  url.searchParams.set('fields', 'geometry,address_components,formatted_address');
32
47
  url.searchParams.set('language', language);
33
- url.searchParams.set('key', apiKey);
34
48
  const response = await fetch(url.toString(), { signal });
35
49
  if (!response.ok) {
36
50
  throw new Error(`Google Places API error: ${response.status}`);
@@ -1 +1 @@
1
- {"version":3,"file":"use.auth.d.ts","sourceRoot":"","sources":["../../../../../core/feature/auth/hook/use.auth.tsx"],"names":[],"mappings":"AAMA,eAAO,MAAM,YAAY,sBAAsB,CAAC;AAChD,eAAO,MAAM,mBAAmB,6BAA6B,CAAC;AAE9D,eAAO,MAAM,OAAO;;;;;;;;kBAoEiC,MAAM;oBAAc,MAAM;;;;eAmBnC,MAAM;;;eAWN,MAAM;cAAQ,MAAM;;;eAYpB,MAAM;cAAQ,MAAM;kBAAY,MAAM;;;CAqBjF,CAAC"}
1
+ {"version":3,"file":"use.auth.d.ts","sourceRoot":"","sources":["../../../../../core/feature/auth/hook/use.auth.tsx"],"names":[],"mappings":"AAOA,eAAO,MAAM,YAAY,sBAAsB,CAAC;AAChD,eAAO,MAAM,mBAAmB,6BAA6B,CAAC;AAE9D,eAAO,MAAM,OAAO;;;;;;;;kBAoEiC,MAAM;oBAAc,MAAM;;;;eAmBnC,MAAM;;;eAWN,MAAM;cAAQ,MAAM;;;eAYpB,MAAM;cAAQ,MAAM;kBAAY,MAAM;;;CAqBjF,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { nexineAxios } from "../../../util/nexine.axios";
2
+ import { dispatchTokenChanged, removeToken, setToken } from "../../../util/storage.keys";
2
3
  import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
3
4
  // Auth event'leri için custom eventler
4
5
  export const LOGOUT_EVENT = 'intermarkt-logout';
@@ -30,14 +31,14 @@ export const useAuth = () => {
30
31
  return nexineAxios.post('/auth/login/email', data);
31
32
  },
32
33
  onSuccess: (response) => {
33
- localStorage.setItem("koksal-token", response.data.token);
34
+ setToken(response.data.token);
34
35
  queryClient.invalidateQueries({ queryKey: ["user"] });
35
36
  queryClient.invalidateQueries({ queryKey: ["profile"] });
36
37
  queryClient.invalidateQueries({ queryKey: ["cart"] });
37
38
  // Login success event'ini tetikle
38
39
  if (typeof window !== 'undefined') {
39
40
  window.dispatchEvent(new Event(LOGIN_SUCCESS_EVENT));
40
- window.dispatchEvent(new Event('koksal-token-changed'));
41
+ dispatchTokenChanged();
41
42
  }
42
43
  },
43
44
  });
@@ -48,14 +49,14 @@ export const useAuth = () => {
48
49
  return nexineAxios.post('/auth/login/guest');
49
50
  },
50
51
  onSuccess: (response) => {
51
- localStorage.setItem("koksal-token", response.data.token);
52
+ setToken(response.data.token);
52
53
  queryClient.invalidateQueries({ queryKey: ["user"] });
53
54
  queryClient.invalidateQueries({ queryKey: ["profile"] });
54
55
  queryClient.invalidateQueries({ queryKey: ["cart"] });
55
56
  // Login success event'ini tetikle
56
57
  if (typeof window !== 'undefined') {
57
58
  window.dispatchEvent(new Event(LOGIN_SUCCESS_EVENT));
58
- window.dispatchEvent(new Event('koksal-token-changed'));
59
+ dispatchTokenChanged();
59
60
  }
60
61
  },
61
62
  });
@@ -108,13 +109,13 @@ export const useAuth = () => {
108
109
  });
109
110
  },
110
111
  logout: () => {
111
- localStorage.removeItem("koksal-token");
112
+ removeToken();
112
113
  queryClient.invalidateQueries({ queryKey: ["user"] });
113
114
  queryClient.invalidateQueries({ queryKey: ["profile"] });
114
115
  // Logout event'ini tetikle
115
116
  if (typeof window !== 'undefined') {
116
117
  window.dispatchEvent(new Event(LOGOUT_EVENT));
117
- window.dispatchEvent(new Event('koksal-token-changed'));
118
+ dispatchTokenChanged();
118
119
  window.location.reload();
119
120
  }
120
121
  }
@@ -43,6 +43,8 @@ export interface RaxonProviderProps {
43
43
  children: React.ReactNode;
44
44
  apiKey: string;
45
45
  apiUrl: string;
46
+ /** localStorage anahtarları için önek. Varsayılan: `raxon` (ör. `raxon-token`) */
47
+ storagePrefix?: string;
46
48
  productPathPrefix?: string;
47
49
  analyticAutoTrack?: boolean;
48
50
  /** Varsayılan: `/api/bootstrap` — Next.js BFF veya özel proxy */
@@ -50,7 +52,7 @@ export interface RaxonProviderProps {
50
52
  /** SSR ile layout'tan geçirilen bootstrap verisi */
51
53
  initialBootstrapData?: RaxonBootstrapPayload | null;
52
54
  }
53
- export declare const RaxonProvider: ({ children, apiKey, apiUrl, productPathPrefix, analyticAutoTrack, bootstrapUrl, initialBootstrapData, }: RaxonProviderProps) => import("react").JSX.Element;
55
+ export declare const RaxonProvider: ({ children, apiKey, apiUrl, storagePrefix, productPathPrefix, analyticAutoTrack, bootstrapUrl, initialBootstrapData, }: RaxonProviderProps) => import("react").JSX.Element;
54
56
  export declare const useRaxon: () => RaxonContextType;
55
57
  export {};
56
58
  //# sourceMappingURL=raxon.context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"raxon.context.d.ts","sourceRoot":"","sources":["../../core/raxon.context.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,OAAO,EACP,WAAW,EACX,MAAM,EACN,QAAQ,EAER,QAAQ,EACR,UAAU,EACV,cAAc,EACd,WAAW,EACX,GAAG,EACH,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,aAAa,EACb,MAAM,EACN,IAAI,EACL,MAAM,mCAAmC,CAAC;AAG3C,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,oCAAoC,CAAC;AAC9E,OAAO,EAAa,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAC/E,OAAO,EAAiC,gCAAgC,EAAE,MAAM,0DAA0D,CAAC;AAG3I,OAAO,EAAgB,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAEtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAExE,eAAO,MAAM,YAAY,2CAAyD,CAAC;AAGnF,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,QAAQ,EAAE,CAAC;IACrB,cAAc,EAAE,QAAQ,EAAE,CAAC;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,UAAU,EAAE,UAAU,EAAE,CAAC;IACzB,iBAAiB,EAAE,UAAU,EAAE,CAAC;IAChC,QAAQ,EAAE,QAAQ,EAAE,CAAC;IACrB,YAAY,EAAE,QAAQ,EAAE,CAAC;IACzB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,OAAO,EAAE,CAAC;IACnB,GAAG,EAAE,GAAG,EAAE,CAAC;IACX,IAAI,EAAE,IAAI,EAAE,CAAC;IACb,QAAQ,EAAE,QAAQ,EAAE,CAAC;IACrB,OAAO,EAAE,OAAO,EAAE,CAAC;IACnB,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,WAAW,EAAE,WAAW,EAAE,CAAC;IAC3B,UAAU,EAAE,aAAa,EAAE,CAAC;IAC5B,WAAW,EAAE,WAAW,EAAE,CAAC;IAC3B,cAAc,EAAE,cAAc,EAAE,CAAC;IACjC,aAAa,EAAE,aAAa,EAAE,CAAC;IAC/B,qBAAqB,EAAE,cAAc,GAAG,IAAI,CAAC;IAC7C,KAAK,EAAE,iBAAiB,EAAE,CAAC;IAC3B,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;IACnD,gCAAgC,EAAE,KAAK,CAAC,SAAS,CAAC,gCAAgC,GAAG,IAAI,CAAC,CAAC;CAC5F;AAED,MAAM,WAAW,gBAAiB,SAAQ,kBAAkB,EAAE,SAAS;IACrE,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC;IACjC,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe,EAAE,OAAO,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,iEAAiE;IACjE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,oBAAoB,CAAC,EAAE,qBAAqB,GAAG,IAAI,CAAC;CACrD;AA8ID,eAAO,MAAM,aAAa,GAAI,yGAQ3B,kBAAkB,gCAiBpB,CAAC;AAEF,eAAO,MAAM,QAAQ,QAAO,gBAM3B,CAAC"}
1
+ {"version":3,"file":"raxon.context.d.ts","sourceRoot":"","sources":["../../core/raxon.context.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,OAAO,EACP,WAAW,EACX,MAAM,EACN,QAAQ,EAER,QAAQ,EACR,UAAU,EACV,cAAc,EACd,WAAW,EACX,GAAG,EACH,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,aAAa,EACb,MAAM,EACN,IAAI,EACL,MAAM,mCAAmC,CAAC;AAG3C,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,oCAAoC,CAAC;AAC9E,OAAO,EAAa,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAC/E,OAAO,EAAiC,gCAAgC,EAAE,MAAM,0DAA0D,CAAC;AAG3I,OAAO,EAAgB,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAEtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAGxE,eAAO,MAAM,YAAY,2CAAyD,CAAC;AAGnF,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,QAAQ,EAAE,CAAC;IACrB,cAAc,EAAE,QAAQ,EAAE,CAAC;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,UAAU,EAAE,UAAU,EAAE,CAAC;IACzB,iBAAiB,EAAE,UAAU,EAAE,CAAC;IAChC,QAAQ,EAAE,QAAQ,EAAE,CAAC;IACrB,YAAY,EAAE,QAAQ,EAAE,CAAC;IACzB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,OAAO,EAAE,CAAC;IACnB,GAAG,EAAE,GAAG,EAAE,CAAC;IACX,IAAI,EAAE,IAAI,EAAE,CAAC;IACb,QAAQ,EAAE,QAAQ,EAAE,CAAC;IACrB,OAAO,EAAE,OAAO,EAAE,CAAC;IACnB,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,WAAW,EAAE,WAAW,EAAE,CAAC;IAC3B,UAAU,EAAE,aAAa,EAAE,CAAC;IAC5B,WAAW,EAAE,WAAW,EAAE,CAAC;IAC3B,cAAc,EAAE,cAAc,EAAE,CAAC;IACjC,aAAa,EAAE,aAAa,EAAE,CAAC;IAC/B,qBAAqB,EAAE,cAAc,GAAG,IAAI,CAAC;IAC7C,KAAK,EAAE,iBAAiB,EAAE,CAAC;IAC3B,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;IACnD,gCAAgC,EAAE,KAAK,CAAC,SAAS,CAAC,gCAAgC,GAAG,IAAI,CAAC,CAAC;CAC5F;AAED,MAAM,WAAW,gBAAiB,SAAQ,kBAAkB,EAAE,SAAS;IACrE,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC;IACjC,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe,EAAE,OAAO,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,kFAAkF;IAClF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,iEAAiE;IACjE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,oBAAoB,CAAC,EAAE,qBAAqB,GAAG,IAAI,CAAC;CACrD;AAgJD,eAAO,MAAM,aAAa,GAAI,wHAS3B,kBAAkB,gCAkBpB,CAAC;AAEF,eAAO,MAAM,QAAQ,QAAO,gBAM3B,CAAC"}