next-api-layer 0.1.5 → 0.1.6
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/dist/api.cjs +1 -1
- package/dist/api.d.cts +6 -6
- package/dist/api.d.ts +6 -6
- package/dist/api.js +1 -1
- package/dist/chunk-JEEL6S4O.cjs +2 -0
- package/dist/chunk-JEEL6S4O.cjs.map +1 -0
- package/dist/chunk-NDZA32WH.js +2 -0
- package/dist/chunk-NDZA32WH.js.map +1 -0
- package/dist/{createApiClient-CIDYcpNI.d.cts → createApiClient-BliWeW4X.d.cts} +5 -1
- package/dist/{createApiClient-CIDYcpNI.d.ts → createApiClient-BliWeW4X.d.ts} +5 -1
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-NBYI46RO.js +0 -2
- package/dist/chunk-NBYI46RO.js.map +0 -1
- package/dist/chunk-OXXKU4OM.cjs +0 -2
- package/dist/chunk-OXXKU4OM.cjs.map +0 -1
package/dist/api.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';var
|
|
1
|
+
'use strict';var chunkJEEL6S4O_cjs=require('./chunk-JEEL6S4O.cjs');require('./chunk-6ENVQMWQ.cjs');Object.defineProperty(exports,"createApiClient",{enumerable:true,get:function(){return chunkJEEL6S4O_cjs.d}});Object.defineProperty(exports,"createSanitizer",{enumerable:true,get:function(){return chunkJEEL6S4O_cjs.a}});Object.defineProperty(exports,"defaultSanitizer",{enumerable:true,get:function(){return chunkJEEL6S4O_cjs.b}});Object.defineProperty(exports,"sanitize",{enumerable:true,get:function(){return chunkJEEL6S4O_cjs.c}});//# sourceMappingURL=api.cjs.map
|
|
2
2
|
//# sourceMappingURL=api.cjs.map
|
package/dist/api.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as SanitizationConfig } from './createApiClient-
|
|
2
|
-
export { f as ApiClient, g as ApiClientConfig, s as RequestOptions, r as createApiClient } from './createApiClient-
|
|
1
|
+
import { S as SanitizationConfig } from './createApiClient-BliWeW4X.cjs';
|
|
2
|
+
export { f as ApiClient, g as ApiClientConfig, s as RequestOptions, r as createApiClient } from './createApiClient-BliWeW4X.cjs';
|
|
3
3
|
import 'next/server';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -19,20 +19,20 @@ interface SanitizeOptions {
|
|
|
19
19
|
* Creates a sanitization function based on config
|
|
20
20
|
*/
|
|
21
21
|
declare function createSanitizer(config?: SanitizationConfig): {
|
|
22
|
-
sanitize: <T>(data: T) => T;
|
|
22
|
+
sanitize: <T>(data: T, perRequestSkipFields?: string[]) => T;
|
|
23
23
|
sanitizeString: (value: string) => string;
|
|
24
24
|
sanitizeValue: (value: unknown, path?: string) => unknown;
|
|
25
|
-
sanitizeFormData: (formData: FormData) => FormData;
|
|
25
|
+
sanitizeFormData: (formData: FormData, perRequestSkipFields?: string[]) => FormData;
|
|
26
26
|
};
|
|
27
27
|
type Sanitizer = ReturnType<typeof createSanitizer>;
|
|
28
28
|
/**
|
|
29
29
|
* Default sanitizer with escape mode (enabled by default)
|
|
30
30
|
*/
|
|
31
31
|
declare const defaultSanitizer: {
|
|
32
|
-
sanitize: <T>(data: T) => T;
|
|
32
|
+
sanitize: <T>(data: T, perRequestSkipFields?: string[]) => T;
|
|
33
33
|
sanitizeString: (value: string) => string;
|
|
34
34
|
sanitizeValue: (value: unknown, path?: string) => unknown;
|
|
35
|
-
sanitizeFormData: (formData: FormData) => FormData;
|
|
35
|
+
sanitizeFormData: (formData: FormData, perRequestSkipFields?: string[]) => FormData;
|
|
36
36
|
};
|
|
37
37
|
/**
|
|
38
38
|
* Quick sanitize function with default config
|
package/dist/api.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as SanitizationConfig } from './createApiClient-
|
|
2
|
-
export { f as ApiClient, g as ApiClientConfig, s as RequestOptions, r as createApiClient } from './createApiClient-
|
|
1
|
+
import { S as SanitizationConfig } from './createApiClient-BliWeW4X.js';
|
|
2
|
+
export { f as ApiClient, g as ApiClientConfig, s as RequestOptions, r as createApiClient } from './createApiClient-BliWeW4X.js';
|
|
3
3
|
import 'next/server';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -19,20 +19,20 @@ interface SanitizeOptions {
|
|
|
19
19
|
* Creates a sanitization function based on config
|
|
20
20
|
*/
|
|
21
21
|
declare function createSanitizer(config?: SanitizationConfig): {
|
|
22
|
-
sanitize: <T>(data: T) => T;
|
|
22
|
+
sanitize: <T>(data: T, perRequestSkipFields?: string[]) => T;
|
|
23
23
|
sanitizeString: (value: string) => string;
|
|
24
24
|
sanitizeValue: (value: unknown, path?: string) => unknown;
|
|
25
|
-
sanitizeFormData: (formData: FormData) => FormData;
|
|
25
|
+
sanitizeFormData: (formData: FormData, perRequestSkipFields?: string[]) => FormData;
|
|
26
26
|
};
|
|
27
27
|
type Sanitizer = ReturnType<typeof createSanitizer>;
|
|
28
28
|
/**
|
|
29
29
|
* Default sanitizer with escape mode (enabled by default)
|
|
30
30
|
*/
|
|
31
31
|
declare const defaultSanitizer: {
|
|
32
|
-
sanitize: <T>(data: T) => T;
|
|
32
|
+
sanitize: <T>(data: T, perRequestSkipFields?: string[]) => T;
|
|
33
33
|
sanitizeString: (value: string) => string;
|
|
34
34
|
sanitizeValue: (value: unknown, path?: string) => unknown;
|
|
35
|
-
sanitizeFormData: (formData: FormData) => FormData;
|
|
35
|
+
sanitizeFormData: (formData: FormData, perRequestSkipFields?: string[]) => FormData;
|
|
36
36
|
};
|
|
37
37
|
/**
|
|
38
38
|
* Quick sanitize function with default config
|
package/dist/api.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export{d as createApiClient,a as createSanitizer,b as defaultSanitizer,c as sanitize}from'./chunk-
|
|
1
|
+
export{d as createApiClient,a as createSanitizer,b as defaultSanitizer,c as sanitize}from'./chunk-NDZA32WH.js';import'./chunk-XBAO7FJN.js';//# sourceMappingURL=api.js.map
|
|
2
2
|
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
'use strict';var chunk6ENVQMWQ_cjs=require('./chunk-6ENVQMWQ.cjs'),headers=require('next/headers');var j={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="},H=/[&<>"'`=/]/g,P=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,b=/\s*on\w+\s*=\s*["'][^"']*["']/gi,x=/javascript\s*:/gi,D=/data\s*:[^;]*;base64/gi;function O(a){return a.replace(H,c=>j[c]||c)}function M(a){return a.replace(P,"").replace(/<[^>]*>/g,"").replace(b,"").replace(x,"").replace(D,"")}function q(a,c){let g=a.replace(P,"").replace(b,"").replace(x,"").replace(D,"");if(c.length===0)return O(g);let l=c.join("|"),f=new RegExp(`<(?!/?(?:${l})\\b)[^>]*>`,"gi");return g=g.replace(f,""),g}function T(a){let c=a?.mode??"escape",g=a?.allowedTags??[],l=a?.enabled!==false,f=a?.skipFields??[];function u(n){if(!l)return n;switch(c){case "strip":return M(n);case "allowList":return q(n,g);default:return O(n)}}function m(n,s=""){if(f.some(o=>s.endsWith(o))||n==null)return n;if(typeof n=="string")return u(n);if(typeof n=="number"||typeof n=="boolean")return n;if(Array.isArray(n))return n.map((o,t)=>m(o,`${s}[${t}]`));if(typeof n=="object"){let o={};for(let[t,e]of Object.entries(n)){let i=s?`${s}.${t}`:t;o[t]=m(e,i);}return o}return n}function k(n,s){if(!l)return n;let o=s?[...f,...s]:f;return R(n,"",o)}function R(n,s,o){if(o.some(t=>s.endsWith(t)||s===t)||n==null)return n;if(typeof n=="string")return u(n);if(typeof n=="number"||typeof n=="boolean")return n;if(Array.isArray(n))return n.map((t,e)=>R(t,`${s}[${e}]`,o));if(typeof n=="object"){let t={};for(let[e,i]of Object.entries(n)){let r=s?`${s}.${e}`:e;t[e]=R(i,r,o);}return t}return n}function z(n,s){if(!l)return n;let o=s?[...f,...s]:f,t=new FormData;for(let[e,i]of n.entries()){let r=o.some(p=>e===p||e.endsWith(p));i instanceof File?t.append(e,i):typeof i=="string"?t.append(e,r?i:u(i)):t.append(e,i);}return t}return {sanitize:k,sanitizeString:u,sanitizeValue:m,sanitizeFormData:z}}var L=T({enabled:true,mode:"escape",skipFields:[]});function I(a){return L.sanitize(a)}function W(a){let{apiBaseUrl:c,cookies:g,methodSpoofing:l=false,errorMessages:f={},i18n:u}=a,m=c.endsWith("/")?c:`${c}/`,k=T(a.sanitization),R=f.noToken??"Token bulunamad\u0131. L\xFCtfen giri\u015F yap\u0131n.",z=f.connectionError??"Ba\u011Flant\u0131 hatas\u0131 olu\u015Ftu.";async function n(){let i=(await headers.headers()).get(chunk6ENVQMWQ_cjs.e.REFRESHED_TOKEN);if(i)return i;let r=await headers.cookies();return r.get(g.user)?.value||r.get(g.guest)?.value||null}function s(e,i=500){return Response.json({success:false,message:e},{status:i})}function o(){return s(R,401)}async function t(e,i,r,p={}){let y=p.skipAuth?null:await n();if(!p.skipAuth&&!y)return o();try{let S={};y&&(S.Authorization=`Bearer ${y}`);let d,E=e;r&&(p.isFormData&&r instanceof FormData?(p.skipSanitize?d=r:d=k.sanitizeFormData(r,p.skipSanitizeFields),(p.methodSpoofing??l)&&(e==="PUT"||e==="PATCH")&&(d.append("_method",e),E="POST")):r instanceof FormData||(S["Content-Type"]="application/json",p.skipSanitize?d=JSON.stringify(r):d=JSON.stringify(k.sanitize(r,p.skipSanitizeFields))));let h=`${m}${i}`;if(u?.enabled){let A=(await headers.headers()).get(chunk6ENVQMWQ_cjs.e.LOCALE);if(A&&(!u.locales||u.locales.includes(A))){let F=new URL(h);F.searchParams.set(u.paramName||"lang",A),h=F.toString();}}let C=await fetch(h,{method:E,headers:S,body:d,cache:"no-store"}),$=await C.json();return Response.json($,{status:C.status})}catch(S){return console.error(`API ${e} Error:`,S),s(z)}}return {get:e=>t("GET",e),post:(e,i,r)=>t("POST",e,i,r),put:(e,i,r)=>t("PUT",e,i,r),patch:(e,i,r)=>t("PATCH",e,i,r),delete:e=>t("DELETE",e)}}exports.a=T;exports.b=L;exports.c=I;exports.d=W;//# sourceMappingURL=chunk-JEEL6S4O.cjs.map
|
|
2
|
+
//# sourceMappingURL=chunk-JEEL6S4O.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/api/sanitize.ts","../src/api/createApiClient.ts"],"names":["HTML_ENTITIES","HTML_ENTITY_REGEX","SCRIPT_PATTERN","EVENT_HANDLER_PATTERN","JAVASCRIPT_URL_PATTERN","DATA_URL_PATTERN","escapeHtml","str","char","stripHtml","sanitizeWithAllowList","allowedTags","result","allowedPattern","allowedRegex","createSanitizer","config","mode","enabled","skipFields","sanitizeString","value","sanitizeValue","path","field","item","index","sanitized","key","val","newPath","sanitize","data","perRequestSkipFields","allSkipFields","sanitizeValueWithSkip","fieldsToSkip","sanitizeFormData","formData","shouldSkip","defaultSanitizer","createApiClient","apiBaseUrl","cookieNames","globalMethodSpoofing","errorMessages","i18n","baseUrl","sanitizer","noTokenMessage","connectionErrorMessage","getToken","refreshedToken","headers","HEADERS","cookieStore","cookies","errorResponse","message","status","noTokenResponse","makeRequest","method","endpoint","body","options","token","fetchHeaders","fetchBody","actualMethod","url","locale","urlObj","res","error"],"mappings":"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","file":"chunk-JEEL6S4O.cjs","sourcesContent":["/**\r\n * XSS Sanitization utilities\r\n * Zero-dependency, lightweight sanitizer for API responses\r\n * \r\n * Modes:\r\n * - 'escape' (default): Escapes HTML entities (<script>)\r\n * - 'strip': Removes all HTML tags completely\r\n * - 'allowList': Only allows specified tags (advanced)\r\n */\r\n\r\nimport type { SanitizationConfig } from '../shared/types';\r\n\r\nexport interface SanitizeOptions {\r\n config: SanitizationConfig;\r\n}\r\n\r\n// HTML entities to escape\r\nconst HTML_ENTITIES: Record<string, string> = {\r\n '&': '&',\r\n '<': '<',\r\n '>': '>',\r\n '\"': '"',\r\n \"'\": ''',\r\n '/': '/',\r\n '`': '`',\r\n '=': '=',\r\n};\r\n\r\n// Regex patterns\r\nconst HTML_ENTITY_REGEX = /[&<>\"'`=/]/g;\r\nconst SCRIPT_PATTERN = /<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi;\r\nconst EVENT_HANDLER_PATTERN = /\\s*on\\w+\\s*=\\s*[\"'][^\"']*[\"']/gi;\r\nconst JAVASCRIPT_URL_PATTERN = /javascript\\s*:/gi;\r\nconst DATA_URL_PATTERN = /data\\s*:[^;]*;base64/gi;\r\n\r\n/**\r\n * Escapes HTML entities in a string\r\n */\r\nfunction escapeHtml(str: string): string {\r\n return str.replace(HTML_ENTITY_REGEX, (char) => HTML_ENTITIES[char] || char);\r\n}\r\n\r\n/**\r\n * Strips all HTML tags from a string\r\n */\r\nfunction stripHtml(str: string): string {\r\n return str\r\n .replace(SCRIPT_PATTERN, '') // Remove script tags first\r\n .replace(/<[^>]*>/g, '') // Remove all HTML tags\r\n .replace(EVENT_HANDLER_PATTERN, '') // Remove any remaining event handlers\r\n .replace(JAVASCRIPT_URL_PATTERN, '') // Remove javascript: URLs\r\n .replace(DATA_URL_PATTERN, ''); // Remove suspicious data URLs\r\n}\r\n\r\n/**\r\n * Sanitizes HTML while allowing specific tags\r\n */\r\nfunction sanitizeWithAllowList(str: string, allowedTags: string[]): string {\r\n // First, remove dangerous content\r\n let result = str\r\n .replace(SCRIPT_PATTERN, '')\r\n .replace(EVENT_HANDLER_PATTERN, '')\r\n .replace(JAVASCRIPT_URL_PATTERN, '')\r\n .replace(DATA_URL_PATTERN, '');\r\n \r\n // Build regex for allowed tags\r\n if (allowedTags.length === 0) {\r\n return escapeHtml(result);\r\n }\r\n \r\n const allowedPattern = allowedTags.join('|');\r\n const allowedRegex = new RegExp(`<(?!\\/?(?:${allowedPattern})\\\\b)[^>]*>`, 'gi');\r\n \r\n // Remove non-allowed tags\r\n result = result.replace(allowedRegex, '');\r\n \r\n return result;\r\n}\r\n\r\n/**\r\n * Creates a sanitization function based on config\r\n */\r\nexport function createSanitizer(config?: SanitizationConfig) {\r\n const mode = config?.mode ?? 'escape';\r\n const allowedTags = config?.allowedTags ?? [];\r\n const enabled = config?.enabled !== false; // default: true\r\n const skipFields = config?.skipFields ?? [];\r\n\r\n /**\r\n * Sanitizes a single string value\r\n */\r\n function sanitizeString(value: string): string {\r\n if (!enabled) return value;\r\n \r\n switch (mode) {\r\n case 'strip':\r\n return stripHtml(value);\r\n case 'allowList':\r\n return sanitizeWithAllowList(value, allowedTags);\r\n case 'escape':\r\n default:\r\n return escapeHtml(value);\r\n }\r\n }\r\n\r\n /**\r\n * Recursively sanitizes an object, array, or primitive value\r\n */\r\n function sanitizeValue(value: unknown, path: string = ''): unknown {\r\n // Skip fields in skipFields list\r\n if (skipFields.some(field => path.endsWith(field))) {\r\n return value;\r\n }\r\n\r\n // Null/undefined pass through\r\n if (value === null || value === undefined) {\r\n return value;\r\n }\r\n\r\n // Strings get sanitized\r\n if (typeof value === 'string') {\r\n return sanitizeString(value);\r\n }\r\n\r\n // Numbers, booleans pass through\r\n if (typeof value === 'number' || typeof value === 'boolean') {\r\n return value;\r\n }\r\n\r\n // Arrays - sanitize each element\r\n if (Array.isArray(value)) {\r\n return value.map((item, index) => sanitizeValue(item, `${path}[${index}]`));\r\n }\r\n\r\n // Objects - sanitize each property\r\n if (typeof value === 'object') {\r\n const sanitized: Record<string, unknown> = {};\r\n for (const [key, val] of Object.entries(value)) {\r\n const newPath = path ? `${path}.${key}` : key;\r\n sanitized[key] = sanitizeValue(val, newPath);\r\n }\r\n return sanitized;\r\n }\r\n\r\n // Everything else passes through\r\n return value;\r\n }\r\n\r\n /**\r\n * Main sanitize function\r\n * @param data - Data to sanitize\r\n * @param perRequestSkipFields - Additional fields to skip for this request only\r\n */\r\n function sanitize<T>(data: T, perRequestSkipFields?: string[]): T {\r\n if (!enabled) {\r\n return data;\r\n }\r\n const allSkipFields = perRequestSkipFields \r\n ? [...skipFields, ...perRequestSkipFields]\r\n : skipFields;\r\n return sanitizeValueWithSkip(data, '', allSkipFields) as T;\r\n }\r\n\r\n /**\r\n * Sanitize with custom skip fields\r\n */\r\n function sanitizeValueWithSkip(value: unknown, path: string, fieldsToSkip: string[]): unknown {\r\n // Skip fields in skip list\r\n if (fieldsToSkip.some(field => path.endsWith(field) || path === field)) {\r\n return value;\r\n }\r\n\r\n // Null/undefined pass through\r\n if (value === null || value === undefined) {\r\n return value;\r\n }\r\n\r\n // Strings get sanitized\r\n if (typeof value === 'string') {\r\n return sanitizeString(value);\r\n }\r\n\r\n // Numbers, booleans pass through\r\n if (typeof value === 'number' || typeof value === 'boolean') {\r\n return value;\r\n }\r\n\r\n // Arrays - sanitize each element\r\n if (Array.isArray(value)) {\r\n return value.map((item, index) => sanitizeValueWithSkip(item, `${path}[${index}]`, fieldsToSkip));\r\n }\r\n\r\n // Objects - sanitize each property\r\n if (typeof value === 'object') {\r\n const sanitized: Record<string, unknown> = {};\r\n for (const [key, val] of Object.entries(value)) {\r\n const newPath = path ? `${path}.${key}` : key;\r\n sanitized[key] = sanitizeValueWithSkip(val, newPath, fieldsToSkip);\r\n }\r\n return sanitized;\r\n }\r\n\r\n // Everything else passes through\r\n return value;\r\n }\r\n\r\n /**\r\n * Sanitize FormData values (returns new FormData with sanitized values)\r\n * @param formData - FormData to sanitize\r\n * @param perRequestSkipFields - Additional fields to skip for this request only\r\n */\r\n function sanitizeFormData(formData: FormData, perRequestSkipFields?: string[]): FormData {\r\n if (!enabled) {\r\n return formData;\r\n }\r\n \r\n const allSkipFields = perRequestSkipFields \r\n ? [...skipFields, ...perRequestSkipFields]\r\n : skipFields;\r\n \r\n const sanitized = new FormData();\r\n \r\n for (const [key, value] of formData.entries()) {\r\n // Check if this field should be skipped\r\n const shouldSkip = allSkipFields.some(field => key === field || key.endsWith(field));\r\n \r\n if (value instanceof File) {\r\n // Files pass through unchanged\r\n sanitized.append(key, value);\r\n } else if (typeof value === 'string') {\r\n // Strings get sanitized (unless skipped)\r\n sanitized.append(key, shouldSkip ? value : sanitizeString(value));\r\n } else {\r\n // Everything else passes through\r\n sanitized.append(key, value);\r\n }\r\n }\r\n \r\n return sanitized;\r\n }\r\n\r\n return {\r\n sanitize,\r\n sanitizeString,\r\n sanitizeValue,\r\n sanitizeFormData,\r\n };\r\n}\r\n\r\nexport type Sanitizer = ReturnType<typeof createSanitizer>;\r\n\r\n/**\r\n * Default sanitizer with escape mode (enabled by default)\r\n */\r\nexport const defaultSanitizer = createSanitizer({\r\n enabled: true,\r\n mode: 'escape',\r\n skipFields: [],\r\n});\r\n\r\n/**\r\n * Quick sanitize function with default config\r\n */\r\nexport function sanitize<T>(data: T): T {\r\n return defaultSanitizer.sanitize(data);\r\n}\r\n\r\n/**\r\n * Quick escape function for single strings\r\n */\r\nexport function escapeString(str: string): string {\r\n return escapeHtml(str);\r\n}\r\n\r\n/**\r\n * Quick strip function for single strings\r\n */\r\nexport function stripString(str: string): string {\r\n return stripHtml(str);\r\n}\r\n","/**\r\n * createApiClient\r\n * Server-side API client for Route Handlers\r\n * \r\n * Makes requests directly to backend with auth token from cookies/headers.\r\n * Returns Response objects that can be directly returned from route handlers.\r\n */\r\n\r\nimport { cookies, headers } from 'next/headers';\r\nimport { createSanitizer } from './sanitize';\r\nimport type { SanitizationConfig, I18nConfig } from '../shared/types';\r\nimport { HEADERS } from '../shared/constants';\r\n\r\n// ==================== Types ====================\r\n\r\nexport interface ApiClientConfig {\r\n /** Backend API base URL */\r\n apiBaseUrl: string;\r\n \r\n /** Cookie names for token retrieval */\r\n cookies: {\r\n user: string;\r\n guest: string;\r\n };\r\n \r\n /** Sanitization options */\r\n sanitization?: SanitizationConfig;\r\n \r\n /** Enable Laravel method spoofing for PUT/PATCH */\r\n methodSpoofing?: boolean;\r\n \r\n /** Custom error messages */\r\n errorMessages?: {\r\n noToken?: string;\r\n connectionError?: string;\r\n };\r\n \r\n /** i18n configuration - auto-append locale to API requests */\r\n i18n?: I18nConfig & {\r\n /** Query parameter name (default: 'lang') */\r\n paramName?: string;\r\n };\r\n}\r\n\r\nexport interface RequestOptions {\r\n /** Form data mode (use FormData, skip Content-Type header) */\r\n isFormData?: boolean;\r\n /** Use method spoofing for this request */\r\n methodSpoofing?: boolean;\r\n /** Skip authentication for this request */\r\n skipAuth?: boolean;\r\n /** Skip all sanitization for this request */\r\n skipSanitize?: boolean;\r\n /** Skip sanitization for specific fields only */\r\n skipSanitizeFields?: string[];\r\n}\r\n\r\nexport interface ApiClient {\r\n get: (endpoint: string) => Promise<Response>;\r\n post: (endpoint: string, body?: Record<string, unknown> | FormData, options?: RequestOptions) => Promise<Response>;\r\n put: (endpoint: string, body?: Record<string, unknown> | FormData, options?: RequestOptions) => Promise<Response>;\r\n patch: (endpoint: string, body?: Record<string, unknown>, options?: RequestOptions) => Promise<Response>;\r\n delete: (endpoint: string) => Promise<Response>;\r\n}\r\n\r\n// ==================== Factory ====================\r\n\r\n/**\r\n * Creates a server-side API client for Next.js Route Handlers\r\n * \r\n * @example\r\n * ```ts\r\n * // lib/api.ts\r\n * import { createApiClient } from 'next-api-layer';\r\n * \r\n * export const api = createApiClient({\r\n * apiBaseUrl: process.env.API_BASE_URL!,\r\n * cookies: {\r\n * user: process.env.COOKIE_USER_AUTH_TOKEN_NAME!,\r\n * guest: process.env.COOKIE_PUBLIC_AUTH_TOKEN_NAME!,\r\n * },\r\n * });\r\n * \r\n * // Usage in route handler - direct return!\r\n * export async function GET() {\r\n * return api.get('superadmin/home/list');\r\n * }\r\n * \r\n * export async function POST(request: Request) {\r\n * const body = await request.json();\r\n * return api.post('donations/create', body);\r\n * }\r\n * ```\r\n */\r\nexport function createApiClient(config: ApiClientConfig): ApiClient {\r\n const {\r\n apiBaseUrl,\r\n cookies: cookieNames,\r\n methodSpoofing: globalMethodSpoofing = false,\r\n errorMessages = {},\r\n i18n,\r\n } = config;\r\n \r\n // Ensure baseUrl ends with /\r\n const baseUrl = apiBaseUrl.endsWith('/') ? apiBaseUrl : `${apiBaseUrl}/`;\r\n \r\n // Create sanitizer\r\n const sanitizer = createSanitizer(config.sanitization);\r\n \r\n // Error messages\r\n const noTokenMessage = errorMessages.noToken ?? 'Token bulunamadı. Lütfen giriş yapın.';\r\n const connectionErrorMessage = errorMessages.connectionError ?? 'Bağlantı hatası oluştu.';\r\n\r\n /**\r\n * Get auth token from headers (refreshed) or cookies\r\n */\r\n async function getToken(): Promise<string | null> {\r\n // Check for refreshed token from proxy\r\n const headersList = await headers();\r\n const refreshedToken = headersList.get(HEADERS.REFRESHED_TOKEN);\r\n if (refreshedToken) {\r\n return refreshedToken;\r\n }\r\n \r\n // Get from cookies\r\n const cookieStore = await cookies();\r\n return (\r\n cookieStore.get(cookieNames.user)?.value ||\r\n cookieStore.get(cookieNames.guest)?.value ||\r\n null\r\n );\r\n }\r\n\r\n /**\r\n * Create error response\r\n */\r\n function errorResponse(message: string, status = 500): Response {\r\n return Response.json(\r\n { success: false, message },\r\n { status }\r\n );\r\n }\r\n\r\n /**\r\n * Create no-token response\r\n */\r\n function noTokenResponse(): Response {\r\n return errorResponse(noTokenMessage, 401);\r\n }\r\n\r\n /**\r\n * Make a fetch request to backend\r\n */\r\n async function makeRequest(\r\n method: string,\r\n endpoint: string,\r\n body?: Record<string, unknown> | FormData | null,\r\n options: RequestOptions = {}\r\n ): Promise<Response> {\r\n // Skip auth check if requested\r\n const token = options.skipAuth ? null : await getToken();\r\n \r\n if (!options.skipAuth && !token) {\r\n return noTokenResponse();\r\n }\r\n\r\n try {\r\n const fetchHeaders: HeadersInit = {};\r\n \r\n // Add auth header if we have a token\r\n if (token) {\r\n fetchHeaders['Authorization'] = `Bearer ${token}`;\r\n }\r\n\r\n let fetchBody: string | FormData | undefined;\r\n let actualMethod = method;\r\n\r\n // Handle body\r\n if (body) {\r\n if (options.isFormData && body instanceof FormData) {\r\n // FormData - sanitize (unless skipped) and optionally add method spoofing\r\n if (options.skipSanitize) {\r\n fetchBody = body;\r\n } else {\r\n fetchBody = sanitizer.sanitizeFormData(body, options.skipSanitizeFields);\r\n }\r\n \r\n const useMethodSpoofing = options.methodSpoofing ?? globalMethodSpoofing;\r\n if (useMethodSpoofing && (method === 'PUT' || method === 'PATCH')) {\r\n (fetchBody as FormData).append('_method', method);\r\n actualMethod = 'POST';\r\n }\r\n } else if (!(body instanceof FormData)) {\r\n // JSON body\r\n fetchHeaders['Content-Type'] = 'application/json';\r\n if (options.skipSanitize) {\r\n fetchBody = JSON.stringify(body);\r\n } else {\r\n fetchBody = JSON.stringify(sanitizer.sanitize(body, options.skipSanitizeFields));\r\n }\r\n }\r\n }\r\n\r\n // Build URL with optional locale parameter\r\n let url = `${baseUrl}${endpoint}`;\r\n if (i18n?.enabled) {\r\n const headersList = await headers();\r\n const locale = headersList.get(HEADERS.LOCALE);\r\n if (locale && (!i18n.locales || i18n.locales.includes(locale))) {\r\n const urlObj = new URL(url);\r\n urlObj.searchParams.set(i18n.paramName || 'lang', locale);\r\n url = urlObj.toString();\r\n }\r\n }\r\n\r\n const res = await fetch(url, {\r\n method: actualMethod,\r\n headers: fetchHeaders,\r\n body: fetchBody,\r\n cache: 'no-store',\r\n });\r\n\r\n // Clone response data (stream can only be read once)\r\n const data = await res.json();\r\n return Response.json(data, { status: res.status });\r\n } catch (error) {\r\n console.error(`API ${method} Error:`, error);\r\n return errorResponse(connectionErrorMessage);\r\n }\r\n }\r\n\r\n // Return API client interface\r\n return {\r\n get: (endpoint: string) => makeRequest('GET', endpoint),\r\n \r\n post: (endpoint: string, body?: Record<string, unknown> | FormData, options?: RequestOptions) =>\r\n makeRequest('POST', endpoint, body, options),\r\n \r\n put: (endpoint: string, body?: Record<string, unknown> | FormData, options?: RequestOptions) =>\r\n makeRequest('PUT', endpoint, body, options),\r\n \r\n patch: (endpoint: string, body?: Record<string, unknown>, options?: RequestOptions) =>\r\n makeRequest('PATCH', endpoint, body, options),\r\n \r\n delete: (endpoint: string) => makeRequest('DELETE', endpoint),\r\n };\r\n}\r\n"]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import {e}from'./chunk-XBAO7FJN.js';import {headers,cookies}from'next/headers';var j={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="},H=/[&<>"'`=/]/g,P=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,b=/\s*on\w+\s*=\s*["'][^"']*["']/gi,x=/javascript\s*:/gi,D=/data\s*:[^;]*;base64/gi;function O(a){return a.replace(H,c=>j[c]||c)}function M(a){return a.replace(P,"").replace(/<[^>]*>/g,"").replace(b,"").replace(x,"").replace(D,"")}function q(a,c){let g=a.replace(P,"").replace(b,"").replace(x,"").replace(D,"");if(c.length===0)return O(g);let l=c.join("|"),f=new RegExp(`<(?!/?(?:${l})\\b)[^>]*>`,"gi");return g=g.replace(f,""),g}function T(a){let c=a?.mode??"escape",g=a?.allowedTags??[],l=a?.enabled!==false,f=a?.skipFields??[];function u(n){if(!l)return n;switch(c){case "strip":return M(n);case "allowList":return q(n,g);default:return O(n)}}function m(n,s=""){if(f.some(o=>s.endsWith(o))||n==null)return n;if(typeof n=="string")return u(n);if(typeof n=="number"||typeof n=="boolean")return n;if(Array.isArray(n))return n.map((o,t)=>m(o,`${s}[${t}]`));if(typeof n=="object"){let o={};for(let[t,e]of Object.entries(n)){let i=s?`${s}.${t}`:t;o[t]=m(e,i);}return o}return n}function k(n,s){if(!l)return n;let o=s?[...f,...s]:f;return R(n,"",o)}function R(n,s,o){if(o.some(t=>s.endsWith(t)||s===t)||n==null)return n;if(typeof n=="string")return u(n);if(typeof n=="number"||typeof n=="boolean")return n;if(Array.isArray(n))return n.map((t,e)=>R(t,`${s}[${e}]`,o));if(typeof n=="object"){let t={};for(let[e,i]of Object.entries(n)){let r=s?`${s}.${e}`:e;t[e]=R(i,r,o);}return t}return n}function z(n,s){if(!l)return n;let o=s?[...f,...s]:f,t=new FormData;for(let[e,i]of n.entries()){let r=o.some(p=>e===p||e.endsWith(p));i instanceof File?t.append(e,i):typeof i=="string"?t.append(e,r?i:u(i)):t.append(e,i);}return t}return {sanitize:k,sanitizeString:u,sanitizeValue:m,sanitizeFormData:z}}var L=T({enabled:true,mode:"escape",skipFields:[]});function I(a){return L.sanitize(a)}function W(a){let{apiBaseUrl:c,cookies:g,methodSpoofing:l=false,errorMessages:f={},i18n:u}=a,m=c.endsWith("/")?c:`${c}/`,k=T(a.sanitization),R=f.noToken??"Token bulunamad\u0131. L\xFCtfen giri\u015F yap\u0131n.",z=f.connectionError??"Ba\u011Flant\u0131 hatas\u0131 olu\u015Ftu.";async function n(){let i=(await headers()).get(e.REFRESHED_TOKEN);if(i)return i;let r=await cookies();return r.get(g.user)?.value||r.get(g.guest)?.value||null}function s(e,i=500){return Response.json({success:false,message:e},{status:i})}function o(){return s(R,401)}async function t(e$1,i,r,p={}){let y=p.skipAuth?null:await n();if(!p.skipAuth&&!y)return o();try{let S={};y&&(S.Authorization=`Bearer ${y}`);let d,E=e$1;r&&(p.isFormData&&r instanceof FormData?(p.skipSanitize?d=r:d=k.sanitizeFormData(r,p.skipSanitizeFields),(p.methodSpoofing??l)&&(e$1==="PUT"||e$1==="PATCH")&&(d.append("_method",e$1),E="POST")):r instanceof FormData||(S["Content-Type"]="application/json",p.skipSanitize?d=JSON.stringify(r):d=JSON.stringify(k.sanitize(r,p.skipSanitizeFields))));let h=`${m}${i}`;if(u?.enabled){let A=(await headers()).get(e.LOCALE);if(A&&(!u.locales||u.locales.includes(A))){let F=new URL(h);F.searchParams.set(u.paramName||"lang",A),h=F.toString();}}let C=await fetch(h,{method:E,headers:S,body:d,cache:"no-store"}),$=await C.json();return Response.json($,{status:C.status})}catch(S){return console.error(`API ${e$1} Error:`,S),s(z)}}return {get:e=>t("GET",e),post:(e,i,r)=>t("POST",e,i,r),put:(e,i,r)=>t("PUT",e,i,r),patch:(e,i,r)=>t("PATCH",e,i,r),delete:e=>t("DELETE",e)}}export{T as a,L as b,I as c,W as d};//# sourceMappingURL=chunk-NDZA32WH.js.map
|
|
2
|
+
//# sourceMappingURL=chunk-NDZA32WH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/api/sanitize.ts","../src/api/createApiClient.ts"],"names":["HTML_ENTITIES","HTML_ENTITY_REGEX","SCRIPT_PATTERN","EVENT_HANDLER_PATTERN","JAVASCRIPT_URL_PATTERN","DATA_URL_PATTERN","escapeHtml","str","char","stripHtml","sanitizeWithAllowList","allowedTags","result","allowedPattern","allowedRegex","createSanitizer","config","mode","enabled","skipFields","sanitizeString","value","sanitizeValue","path","field","item","index","sanitized","key","val","newPath","sanitize","data","perRequestSkipFields","allSkipFields","sanitizeValueWithSkip","fieldsToSkip","sanitizeFormData","formData","shouldSkip","defaultSanitizer","createApiClient","apiBaseUrl","cookieNames","globalMethodSpoofing","errorMessages","i18n","baseUrl","sanitizer","noTokenMessage","connectionErrorMessage","getToken","refreshedToken","headers","HEADERS","cookieStore","cookies","errorResponse","message","status","noTokenResponse","makeRequest","method","endpoint","body","options","token","fetchHeaders","fetchBody","actualMethod","url","locale","urlObj","res","error"],"mappings":"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","file":"chunk-NDZA32WH.js","sourcesContent":["/**\r\n * XSS Sanitization utilities\r\n * Zero-dependency, lightweight sanitizer for API responses\r\n * \r\n * Modes:\r\n * - 'escape' (default): Escapes HTML entities (<script>)\r\n * - 'strip': Removes all HTML tags completely\r\n * - 'allowList': Only allows specified tags (advanced)\r\n */\r\n\r\nimport type { SanitizationConfig } from '../shared/types';\r\n\r\nexport interface SanitizeOptions {\r\n config: SanitizationConfig;\r\n}\r\n\r\n// HTML entities to escape\r\nconst HTML_ENTITIES: Record<string, string> = {\r\n '&': '&',\r\n '<': '<',\r\n '>': '>',\r\n '\"': '"',\r\n \"'\": ''',\r\n '/': '/',\r\n '`': '`',\r\n '=': '=',\r\n};\r\n\r\n// Regex patterns\r\nconst HTML_ENTITY_REGEX = /[&<>\"'`=/]/g;\r\nconst SCRIPT_PATTERN = /<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi;\r\nconst EVENT_HANDLER_PATTERN = /\\s*on\\w+\\s*=\\s*[\"'][^\"']*[\"']/gi;\r\nconst JAVASCRIPT_URL_PATTERN = /javascript\\s*:/gi;\r\nconst DATA_URL_PATTERN = /data\\s*:[^;]*;base64/gi;\r\n\r\n/**\r\n * Escapes HTML entities in a string\r\n */\r\nfunction escapeHtml(str: string): string {\r\n return str.replace(HTML_ENTITY_REGEX, (char) => HTML_ENTITIES[char] || char);\r\n}\r\n\r\n/**\r\n * Strips all HTML tags from a string\r\n */\r\nfunction stripHtml(str: string): string {\r\n return str\r\n .replace(SCRIPT_PATTERN, '') // Remove script tags first\r\n .replace(/<[^>]*>/g, '') // Remove all HTML tags\r\n .replace(EVENT_HANDLER_PATTERN, '') // Remove any remaining event handlers\r\n .replace(JAVASCRIPT_URL_PATTERN, '') // Remove javascript: URLs\r\n .replace(DATA_URL_PATTERN, ''); // Remove suspicious data URLs\r\n}\r\n\r\n/**\r\n * Sanitizes HTML while allowing specific tags\r\n */\r\nfunction sanitizeWithAllowList(str: string, allowedTags: string[]): string {\r\n // First, remove dangerous content\r\n let result = str\r\n .replace(SCRIPT_PATTERN, '')\r\n .replace(EVENT_HANDLER_PATTERN, '')\r\n .replace(JAVASCRIPT_URL_PATTERN, '')\r\n .replace(DATA_URL_PATTERN, '');\r\n \r\n // Build regex for allowed tags\r\n if (allowedTags.length === 0) {\r\n return escapeHtml(result);\r\n }\r\n \r\n const allowedPattern = allowedTags.join('|');\r\n const allowedRegex = new RegExp(`<(?!\\/?(?:${allowedPattern})\\\\b)[^>]*>`, 'gi');\r\n \r\n // Remove non-allowed tags\r\n result = result.replace(allowedRegex, '');\r\n \r\n return result;\r\n}\r\n\r\n/**\r\n * Creates a sanitization function based on config\r\n */\r\nexport function createSanitizer(config?: SanitizationConfig) {\r\n const mode = config?.mode ?? 'escape';\r\n const allowedTags = config?.allowedTags ?? [];\r\n const enabled = config?.enabled !== false; // default: true\r\n const skipFields = config?.skipFields ?? [];\r\n\r\n /**\r\n * Sanitizes a single string value\r\n */\r\n function sanitizeString(value: string): string {\r\n if (!enabled) return value;\r\n \r\n switch (mode) {\r\n case 'strip':\r\n return stripHtml(value);\r\n case 'allowList':\r\n return sanitizeWithAllowList(value, allowedTags);\r\n case 'escape':\r\n default:\r\n return escapeHtml(value);\r\n }\r\n }\r\n\r\n /**\r\n * Recursively sanitizes an object, array, or primitive value\r\n */\r\n function sanitizeValue(value: unknown, path: string = ''): unknown {\r\n // Skip fields in skipFields list\r\n if (skipFields.some(field => path.endsWith(field))) {\r\n return value;\r\n }\r\n\r\n // Null/undefined pass through\r\n if (value === null || value === undefined) {\r\n return value;\r\n }\r\n\r\n // Strings get sanitized\r\n if (typeof value === 'string') {\r\n return sanitizeString(value);\r\n }\r\n\r\n // Numbers, booleans pass through\r\n if (typeof value === 'number' || typeof value === 'boolean') {\r\n return value;\r\n }\r\n\r\n // Arrays - sanitize each element\r\n if (Array.isArray(value)) {\r\n return value.map((item, index) => sanitizeValue(item, `${path}[${index}]`));\r\n }\r\n\r\n // Objects - sanitize each property\r\n if (typeof value === 'object') {\r\n const sanitized: Record<string, unknown> = {};\r\n for (const [key, val] of Object.entries(value)) {\r\n const newPath = path ? `${path}.${key}` : key;\r\n sanitized[key] = sanitizeValue(val, newPath);\r\n }\r\n return sanitized;\r\n }\r\n\r\n // Everything else passes through\r\n return value;\r\n }\r\n\r\n /**\r\n * Main sanitize function\r\n * @param data - Data to sanitize\r\n * @param perRequestSkipFields - Additional fields to skip for this request only\r\n */\r\n function sanitize<T>(data: T, perRequestSkipFields?: string[]): T {\r\n if (!enabled) {\r\n return data;\r\n }\r\n const allSkipFields = perRequestSkipFields \r\n ? [...skipFields, ...perRequestSkipFields]\r\n : skipFields;\r\n return sanitizeValueWithSkip(data, '', allSkipFields) as T;\r\n }\r\n\r\n /**\r\n * Sanitize with custom skip fields\r\n */\r\n function sanitizeValueWithSkip(value: unknown, path: string, fieldsToSkip: string[]): unknown {\r\n // Skip fields in skip list\r\n if (fieldsToSkip.some(field => path.endsWith(field) || path === field)) {\r\n return value;\r\n }\r\n\r\n // Null/undefined pass through\r\n if (value === null || value === undefined) {\r\n return value;\r\n }\r\n\r\n // Strings get sanitized\r\n if (typeof value === 'string') {\r\n return sanitizeString(value);\r\n }\r\n\r\n // Numbers, booleans pass through\r\n if (typeof value === 'number' || typeof value === 'boolean') {\r\n return value;\r\n }\r\n\r\n // Arrays - sanitize each element\r\n if (Array.isArray(value)) {\r\n return value.map((item, index) => sanitizeValueWithSkip(item, `${path}[${index}]`, fieldsToSkip));\r\n }\r\n\r\n // Objects - sanitize each property\r\n if (typeof value === 'object') {\r\n const sanitized: Record<string, unknown> = {};\r\n for (const [key, val] of Object.entries(value)) {\r\n const newPath = path ? `${path}.${key}` : key;\r\n sanitized[key] = sanitizeValueWithSkip(val, newPath, fieldsToSkip);\r\n }\r\n return sanitized;\r\n }\r\n\r\n // Everything else passes through\r\n return value;\r\n }\r\n\r\n /**\r\n * Sanitize FormData values (returns new FormData with sanitized values)\r\n * @param formData - FormData to sanitize\r\n * @param perRequestSkipFields - Additional fields to skip for this request only\r\n */\r\n function sanitizeFormData(formData: FormData, perRequestSkipFields?: string[]): FormData {\r\n if (!enabled) {\r\n return formData;\r\n }\r\n \r\n const allSkipFields = perRequestSkipFields \r\n ? [...skipFields, ...perRequestSkipFields]\r\n : skipFields;\r\n \r\n const sanitized = new FormData();\r\n \r\n for (const [key, value] of formData.entries()) {\r\n // Check if this field should be skipped\r\n const shouldSkip = allSkipFields.some(field => key === field || key.endsWith(field));\r\n \r\n if (value instanceof File) {\r\n // Files pass through unchanged\r\n sanitized.append(key, value);\r\n } else if (typeof value === 'string') {\r\n // Strings get sanitized (unless skipped)\r\n sanitized.append(key, shouldSkip ? value : sanitizeString(value));\r\n } else {\r\n // Everything else passes through\r\n sanitized.append(key, value);\r\n }\r\n }\r\n \r\n return sanitized;\r\n }\r\n\r\n return {\r\n sanitize,\r\n sanitizeString,\r\n sanitizeValue,\r\n sanitizeFormData,\r\n };\r\n}\r\n\r\nexport type Sanitizer = ReturnType<typeof createSanitizer>;\r\n\r\n/**\r\n * Default sanitizer with escape mode (enabled by default)\r\n */\r\nexport const defaultSanitizer = createSanitizer({\r\n enabled: true,\r\n mode: 'escape',\r\n skipFields: [],\r\n});\r\n\r\n/**\r\n * Quick sanitize function with default config\r\n */\r\nexport function sanitize<T>(data: T): T {\r\n return defaultSanitizer.sanitize(data);\r\n}\r\n\r\n/**\r\n * Quick escape function for single strings\r\n */\r\nexport function escapeString(str: string): string {\r\n return escapeHtml(str);\r\n}\r\n\r\n/**\r\n * Quick strip function for single strings\r\n */\r\nexport function stripString(str: string): string {\r\n return stripHtml(str);\r\n}\r\n","/**\r\n * createApiClient\r\n * Server-side API client for Route Handlers\r\n * \r\n * Makes requests directly to backend with auth token from cookies/headers.\r\n * Returns Response objects that can be directly returned from route handlers.\r\n */\r\n\r\nimport { cookies, headers } from 'next/headers';\r\nimport { createSanitizer } from './sanitize';\r\nimport type { SanitizationConfig, I18nConfig } from '../shared/types';\r\nimport { HEADERS } from '../shared/constants';\r\n\r\n// ==================== Types ====================\r\n\r\nexport interface ApiClientConfig {\r\n /** Backend API base URL */\r\n apiBaseUrl: string;\r\n \r\n /** Cookie names for token retrieval */\r\n cookies: {\r\n user: string;\r\n guest: string;\r\n };\r\n \r\n /** Sanitization options */\r\n sanitization?: SanitizationConfig;\r\n \r\n /** Enable Laravel method spoofing for PUT/PATCH */\r\n methodSpoofing?: boolean;\r\n \r\n /** Custom error messages */\r\n errorMessages?: {\r\n noToken?: string;\r\n connectionError?: string;\r\n };\r\n \r\n /** i18n configuration - auto-append locale to API requests */\r\n i18n?: I18nConfig & {\r\n /** Query parameter name (default: 'lang') */\r\n paramName?: string;\r\n };\r\n}\r\n\r\nexport interface RequestOptions {\r\n /** Form data mode (use FormData, skip Content-Type header) */\r\n isFormData?: boolean;\r\n /** Use method spoofing for this request */\r\n methodSpoofing?: boolean;\r\n /** Skip authentication for this request */\r\n skipAuth?: boolean;\r\n /** Skip all sanitization for this request */\r\n skipSanitize?: boolean;\r\n /** Skip sanitization for specific fields only */\r\n skipSanitizeFields?: string[];\r\n}\r\n\r\nexport interface ApiClient {\r\n get: (endpoint: string) => Promise<Response>;\r\n post: (endpoint: string, body?: Record<string, unknown> | FormData, options?: RequestOptions) => Promise<Response>;\r\n put: (endpoint: string, body?: Record<string, unknown> | FormData, options?: RequestOptions) => Promise<Response>;\r\n patch: (endpoint: string, body?: Record<string, unknown>, options?: RequestOptions) => Promise<Response>;\r\n delete: (endpoint: string) => Promise<Response>;\r\n}\r\n\r\n// ==================== Factory ====================\r\n\r\n/**\r\n * Creates a server-side API client for Next.js Route Handlers\r\n * \r\n * @example\r\n * ```ts\r\n * // lib/api.ts\r\n * import { createApiClient } from 'next-api-layer';\r\n * \r\n * export const api = createApiClient({\r\n * apiBaseUrl: process.env.API_BASE_URL!,\r\n * cookies: {\r\n * user: process.env.COOKIE_USER_AUTH_TOKEN_NAME!,\r\n * guest: process.env.COOKIE_PUBLIC_AUTH_TOKEN_NAME!,\r\n * },\r\n * });\r\n * \r\n * // Usage in route handler - direct return!\r\n * export async function GET() {\r\n * return api.get('superadmin/home/list');\r\n * }\r\n * \r\n * export async function POST(request: Request) {\r\n * const body = await request.json();\r\n * return api.post('donations/create', body);\r\n * }\r\n * ```\r\n */\r\nexport function createApiClient(config: ApiClientConfig): ApiClient {\r\n const {\r\n apiBaseUrl,\r\n cookies: cookieNames,\r\n methodSpoofing: globalMethodSpoofing = false,\r\n errorMessages = {},\r\n i18n,\r\n } = config;\r\n \r\n // Ensure baseUrl ends with /\r\n const baseUrl = apiBaseUrl.endsWith('/') ? apiBaseUrl : `${apiBaseUrl}/`;\r\n \r\n // Create sanitizer\r\n const sanitizer = createSanitizer(config.sanitization);\r\n \r\n // Error messages\r\n const noTokenMessage = errorMessages.noToken ?? 'Token bulunamadı. Lütfen giriş yapın.';\r\n const connectionErrorMessage = errorMessages.connectionError ?? 'Bağlantı hatası oluştu.';\r\n\r\n /**\r\n * Get auth token from headers (refreshed) or cookies\r\n */\r\n async function getToken(): Promise<string | null> {\r\n // Check for refreshed token from proxy\r\n const headersList = await headers();\r\n const refreshedToken = headersList.get(HEADERS.REFRESHED_TOKEN);\r\n if (refreshedToken) {\r\n return refreshedToken;\r\n }\r\n \r\n // Get from cookies\r\n const cookieStore = await cookies();\r\n return (\r\n cookieStore.get(cookieNames.user)?.value ||\r\n cookieStore.get(cookieNames.guest)?.value ||\r\n null\r\n );\r\n }\r\n\r\n /**\r\n * Create error response\r\n */\r\n function errorResponse(message: string, status = 500): Response {\r\n return Response.json(\r\n { success: false, message },\r\n { status }\r\n );\r\n }\r\n\r\n /**\r\n * Create no-token response\r\n */\r\n function noTokenResponse(): Response {\r\n return errorResponse(noTokenMessage, 401);\r\n }\r\n\r\n /**\r\n * Make a fetch request to backend\r\n */\r\n async function makeRequest(\r\n method: string,\r\n endpoint: string,\r\n body?: Record<string, unknown> | FormData | null,\r\n options: RequestOptions = {}\r\n ): Promise<Response> {\r\n // Skip auth check if requested\r\n const token = options.skipAuth ? null : await getToken();\r\n \r\n if (!options.skipAuth && !token) {\r\n return noTokenResponse();\r\n }\r\n\r\n try {\r\n const fetchHeaders: HeadersInit = {};\r\n \r\n // Add auth header if we have a token\r\n if (token) {\r\n fetchHeaders['Authorization'] = `Bearer ${token}`;\r\n }\r\n\r\n let fetchBody: string | FormData | undefined;\r\n let actualMethod = method;\r\n\r\n // Handle body\r\n if (body) {\r\n if (options.isFormData && body instanceof FormData) {\r\n // FormData - sanitize (unless skipped) and optionally add method spoofing\r\n if (options.skipSanitize) {\r\n fetchBody = body;\r\n } else {\r\n fetchBody = sanitizer.sanitizeFormData(body, options.skipSanitizeFields);\r\n }\r\n \r\n const useMethodSpoofing = options.methodSpoofing ?? globalMethodSpoofing;\r\n if (useMethodSpoofing && (method === 'PUT' || method === 'PATCH')) {\r\n (fetchBody as FormData).append('_method', method);\r\n actualMethod = 'POST';\r\n }\r\n } else if (!(body instanceof FormData)) {\r\n // JSON body\r\n fetchHeaders['Content-Type'] = 'application/json';\r\n if (options.skipSanitize) {\r\n fetchBody = JSON.stringify(body);\r\n } else {\r\n fetchBody = JSON.stringify(sanitizer.sanitize(body, options.skipSanitizeFields));\r\n }\r\n }\r\n }\r\n\r\n // Build URL with optional locale parameter\r\n let url = `${baseUrl}${endpoint}`;\r\n if (i18n?.enabled) {\r\n const headersList = await headers();\r\n const locale = headersList.get(HEADERS.LOCALE);\r\n if (locale && (!i18n.locales || i18n.locales.includes(locale))) {\r\n const urlObj = new URL(url);\r\n urlObj.searchParams.set(i18n.paramName || 'lang', locale);\r\n url = urlObj.toString();\r\n }\r\n }\r\n\r\n const res = await fetch(url, {\r\n method: actualMethod,\r\n headers: fetchHeaders,\r\n body: fetchBody,\r\n cache: 'no-store',\r\n });\r\n\r\n // Clone response data (stream can only be read once)\r\n const data = await res.json();\r\n return Response.json(data, { status: res.status });\r\n } catch (error) {\r\n console.error(`API ${method} Error:`, error);\r\n return errorResponse(connectionErrorMessage);\r\n }\r\n }\r\n\r\n // Return API client interface\r\n return {\r\n get: (endpoint: string) => makeRequest('GET', endpoint),\r\n \r\n post: (endpoint: string, body?: Record<string, unknown> | FormData, options?: RequestOptions) =>\r\n makeRequest('POST', endpoint, body, options),\r\n \r\n put: (endpoint: string, body?: Record<string, unknown> | FormData, options?: RequestOptions) =>\r\n makeRequest('PUT', endpoint, body, options),\r\n \r\n patch: (endpoint: string, body?: Record<string, unknown>, options?: RequestOptions) =>\r\n makeRequest('PATCH', endpoint, body, options),\r\n \r\n delete: (endpoint: string) => makeRequest('DELETE', endpoint),\r\n };\r\n}\r\n"]}
|
|
@@ -343,12 +343,16 @@ interface RequestOptions {
|
|
|
343
343
|
methodSpoofing?: boolean;
|
|
344
344
|
/** Skip authentication for this request */
|
|
345
345
|
skipAuth?: boolean;
|
|
346
|
+
/** Skip all sanitization for this request */
|
|
347
|
+
skipSanitize?: boolean;
|
|
348
|
+
/** Skip sanitization for specific fields only */
|
|
349
|
+
skipSanitizeFields?: string[];
|
|
346
350
|
}
|
|
347
351
|
interface ApiClient {
|
|
348
352
|
get: (endpoint: string) => Promise<Response>;
|
|
349
353
|
post: (endpoint: string, body?: Record<string, unknown> | FormData, options?: RequestOptions) => Promise<Response>;
|
|
350
354
|
put: (endpoint: string, body?: Record<string, unknown> | FormData, options?: RequestOptions) => Promise<Response>;
|
|
351
|
-
patch: (endpoint: string, body?: Record<string, unknown
|
|
355
|
+
patch: (endpoint: string, body?: Record<string, unknown>, options?: RequestOptions) => Promise<Response>;
|
|
352
356
|
delete: (endpoint: string) => Promise<Response>;
|
|
353
357
|
}
|
|
354
358
|
/**
|
|
@@ -343,12 +343,16 @@ interface RequestOptions {
|
|
|
343
343
|
methodSpoofing?: boolean;
|
|
344
344
|
/** Skip authentication for this request */
|
|
345
345
|
skipAuth?: boolean;
|
|
346
|
+
/** Skip all sanitization for this request */
|
|
347
|
+
skipSanitize?: boolean;
|
|
348
|
+
/** Skip sanitization for specific fields only */
|
|
349
|
+
skipSanitizeFields?: string[];
|
|
346
350
|
}
|
|
347
351
|
interface ApiClient {
|
|
348
352
|
get: (endpoint: string) => Promise<Response>;
|
|
349
353
|
post: (endpoint: string, body?: Record<string, unknown> | FormData, options?: RequestOptions) => Promise<Response>;
|
|
350
354
|
put: (endpoint: string, body?: Record<string, unknown> | FormData, options?: RequestOptions) => Promise<Response>;
|
|
351
|
-
patch: (endpoint: string, body?: Record<string, unknown
|
|
355
|
+
patch: (endpoint: string, body?: Record<string, unknown>, options?: RequestOptions) => Promise<Response>;
|
|
352
356
|
delete: (endpoint: string) => Promise<Response>;
|
|
353
357
|
}
|
|
354
358
|
/**
|
package/dist/index.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
'use strict';var chunkOXXKU4OM_cjs=require('./chunk-OXXKU4OM.cjs'),chunk6ENVQMWQ_cjs=require('./chunk-6ENVQMWQ.cjs'),server=require('next/server');function ie(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID()+crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).substring(2)}`}function ue(e){return `rl:${e.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||e.headers.get("x-real-ip")||"unknown"}`}function Q(e){if(!e.apiBaseUrl)throw new Error("next-api-layer: apiBaseUrl is required");if(!e.cookies?.user||!e.cookies?.guest)throw new Error("next-api-layer: cookies.user and cookies.guest are required");let t=e.apiBaseUrl.endsWith("/")?e.apiBaseUrl:`${e.apiBaseUrl}/`,f={...chunk6ENVQMWQ_cjs.a,...e.cookies.options},l={...chunk6ENVQMWQ_cjs.b,...e.endpoints},m={enabled:e.csrf?.enabled??false,strategy:e.csrf?.strategy??chunk6ENVQMWQ_cjs.g.strategy,secret:e.csrf?.secret??ie(),cookieName:e.csrf?.cookieName??chunk6ENVQMWQ_cjs.g.cookieName,headerName:e.csrf?.headerName??chunk6ENVQMWQ_cjs.g.headerName,ignoreMethods:e.csrf?.ignoreMethods??chunk6ENVQMWQ_cjs.g.ignoreMethods,trustSameSite:e.csrf?.trustSameSite??chunk6ENVQMWQ_cjs.g.trustSameSite},R={enabled:e.rateLimit?.enabled??false,windowMs:e.rateLimit?.windowMs??chunk6ENVQMWQ_cjs.h.windowMs,maxRequests:e.rateLimit?.maxRequests??chunk6ENVQMWQ_cjs.h.maxRequests,keyFn:e.rateLimit?.keyFn??ue,skipRoutes:e.rateLimit?.skipRoutes??chunk6ENVQMWQ_cjs.h.skipRoutes,onRateLimited:e.rateLimit?.onRateLimited},u={enabled:e.audit?.enabled??false,events:e.audit?.events??[...chunk6ENVQMWQ_cjs.i.events],logger:e.audit?.logger};return {...e,apiBaseUrl:t,_resolved:{cookieOptions:f,endpoints:l,csrf:m,rateLimit:R,audit:u}}}var $={parseAuthMe:e=>{let t=e;return !t?.success||!t?.data?null:{isValid:true,tokenType:t.data.type||"user",exp:t.data.exp||null,userData:t.data}},parseRefreshToken:e=>{let t=e;return t?.success&&t?.data?.accessToken?t.data.accessToken:null},parseGuestToken:e=>e?.data?.accessToken||null};function j(e){let{apiBaseUrl:t,_resolved:f,responseMappers:l}=e,{endpoints:m}=f,R={parseAuthMe:l?.parseAuthMe||$.parseAuthMe,parseRefreshToken:l?.parseRefreshToken||$.parseRefreshToken,parseGuestToken:l?.parseGuestToken||$.parseGuestToken};async function u(a){let i={isValid:false,tokenType:null,exp:null,userData:null};try{let n=await fetch(`${t}${m.validate}`,{headers:{Authorization:`Bearer ${a}`,"Content-Type":"application/json"},cache:"no-store"});if(!n.ok)return i;let s=await n.json().catch(()=>null),d=R.parseAuthMe(s);return !d||!d.isValid?i:d}catch{return i}}async function c(a){return u(a)}async function p(a){try{let i=await fetch(`${t}${m.refresh}`,{method:"POST",headers:{Authorization:`Bearer ${a}`,"Content-Type":"application/json"},cache:"no-store"});if(!i.ok)return {success:!1,newToken:null};let n=await i.json().catch(()=>null),s=R.parseRefreshToken(n);return s?{success:!0,newToken:s}:{success:!1,newToken:null}}catch{return {success:false,newToken:null}}}async function o(){let a=e.guestToken;if(!a?.enabled||!a.credentials)return null;try{let i=await fetch(`${t}${m.guest}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:a.credentials.username,password:a.credentials.password}),cache:"no-store"});if(!i.ok)return null;let n=await i.json().catch(()=>null);return R.parseGuestToken(n)}catch{return null}}return {validateToken:u,getTokenInfo:c,refreshToken:p,createGuestToken:o}}function ee(e,t){if(!t?.enabled)return null;let f=t.locales??[],l=t.defaultLocale,R=e.split("/").filter(Boolean)[0];return R&&f.includes(R)?R:l??null}function z(e,t){let{cookies:f,guestToken:l,access:m,i18n:R,_resolved:u}=e,{cookieOptions:c}=u;function p(r,x,h){r.cookies.get(h)?.value&&x.cookies.delete(h);}function o(r,x){return p(r,x,f.guest),p(r,x,f.user),x}function a(r,x=500){return new server.NextResponse(JSON.stringify({success:false,message:r}),{status:x,headers:{"Content-Type":"application/json"}})}function i(r){return (m?.authRoutes??[]).some(h=>r===h||r.startsWith(`${h}/`))}function n(r){return m?.protectedByDefault?!s(r)&&!i(r):(m?.protectedRoutes??[]).some(h=>r===h||r.startsWith(`${h}/`))}function s(r){return (m?.publicRoutes??[]).some(h=>r===h||r.startsWith(`${h}/`))}function d(r){let x=m?.allowedTokenTypes;return !x||x.length===0?true:r?x.includes(r):false}async function C(r,x){let{origin:h}=r.nextUrl;if(l?.enabled){let y=await t.createGuestToken();if(y){let N;return x?N=server.NextResponse.next():n(r.nextUrl.pathname)?N=server.NextResponse.redirect(new URL("/login",h)):N=server.NextResponse.next(),N.cookies.set(f.guest,y,{...c,maxAge:3600}),N}}return x?a("Token bulunamad\u0131",401):n(r.nextUrl.pathname)?server.NextResponse.redirect(new URL("/login",h)):server.NextResponse.next()}async function v(r,x,h,y,N){let{pathname:k,origin:g}=r.nextUrl,{isValid:S,tokenType:T,userData:A}=x,E=T===chunk6ENVQMWQ_cjs.c.GUEST;if(!S){if(h&&y){let D=await t.refreshToken(y);if(D.success&&D.newToken){let O=await t.getTokenInfo(D.newToken);if(O.isValid){let _=new Headers(r.headers);O.userData&&_.set(chunk6ENVQMWQ_cjs.e.AUTH_USER,JSON.stringify(O.userData)),_.set(chunk6ENVQMWQ_cjs.e.REFRESHED_TOKEN,D.newToken);let Z=ee(k,R);Z&&_.set(chunk6ENVQMWQ_cjs.e.LOCALE,Z);let I;return i(k)?I=server.NextResponse.redirect(new URL("/",g)):I=server.NextResponse.next({request:{headers:_}}),I.cookies.set(f.user,D.newToken,{...c,maxAge:c.maxAge}),p(r,I,f.guest),I}}}let P=await C(r,N);return P.cookies.get(f.guest)?.value?p(r,P,f.user):o(r,P),P}let U=new Headers(r.headers);A&&U.set(chunk6ENVQMWQ_cjs.e.AUTH_USER,JSON.stringify(A));let J=ee(k,R);if(J&&U.set(chunk6ENVQMWQ_cjs.e.LOCALE,J),!E&&!d(T)){if(N){let Y=a("Bu i\u015Flem i\xE7in yetkiniz yok",403);return o(r,Y)}let P=server.NextResponse.redirect(new URL("/login",g));return o(r,P)}if(E)return N?server.NextResponse.next({request:{headers:U}}):n(k)?server.NextResponse.redirect(new URL("/login",g)):server.NextResponse.next({request:{headers:U}});if(i(k))return server.NextResponse.redirect(new URL("/",g));let X=server.NextResponse.next({request:{headers:U}});return p(r,X,f.guest),X}return {deleteAllAuthCookies:o,jsonError:a,isAuthPage:i,isProtectedRoute:n,isPublicRoute:s,isTokenTypeAllowed:d,handleNoToken:C,handleValidationResult:v}}function K(e){async function t(u){let c=le();return `${await ce(e.secret,u,c)}.${c}`}function f(u){let c=u.method.toUpperCase();if(e.ignoreMethods.includes(c))return {valid:true};let p=e.strategy;if(p==="fetch-metadata"||p==="both"){let o=l(u);if(p==="fetch-metadata"||o.valid||o.reason!=="missing-headers")return o}return p==="double-submit"||p==="both"?m(u):{valid:true}}function l(u){let c=u.headers.get("sec-fetch-site");if(!c)return {valid:false,reason:"missing-headers"};if(c==="same-origin")return {valid:true};if(c==="none"){let p=u.method.toUpperCase();return e.ignoreMethods.includes(p)?{valid:true}:{valid:false,reason:"direct-navigation-unsafe-method"}}return c==="same-site"?e.trustSameSite?{valid:true}:{valid:false,reason:"same-site-not-trusted"}:c==="cross-site"?{valid:false,reason:"cross-site-request"}:{valid:false,reason:"unknown-sec-fetch-site"}}function m(u){let c=u.cookies.get(e.cookieName)?.value;if(!c)return {valid:false,reason:"missing-cookie-token"};let p=u.headers.get(e.headerName);return p?de(c,p)?c.split(".").length!==2?{valid:false,reason:"invalid-token-format"}:{valid:true}:{valid:false,reason:"token-mismatch"}:{valid:false,reason:"missing-header-token"}}async function R(u,c){let p=await t(c);return u.cookies.set(e.cookieName,p,{httpOnly:false,secure:process.env.NODE_ENV==="production",sameSite:"strict",path:"/"}),u}return {validateRequest:f,generateToken:t,attachCsrfCookie:R}}function le(){if(typeof crypto<"u"&&crypto.getRandomValues){let e=new Uint8Array(32);return crypto.getRandomValues(e),Array.from(e,t=>t.toString(16).padStart(2,"0")).join("")}return Math.random().toString(36).substring(2)+Date.now().toString(36)}async function ce(e,t,f){let l=`${t.length}!${t}!${f.length}!${f}`;if(typeof crypto<"u"&&crypto.subtle){let u=new TextEncoder,c=u.encode(e),p=u.encode(l),o=await crypto.subtle.importKey("raw",c,{name:"HMAC",hash:"SHA-256"},false,["sign"]),a=await crypto.subtle.sign("HMAC",o,p);return Array.from(new Uint8Array(a),i=>i.toString(16).padStart(2,"0")).join("")}let m=0,R=e+l;for(let u=0;u<R.length;u++){let c=R.charCodeAt(u);m=(m<<5)-m+c,m=m&m;}return Math.abs(m).toString(16)}function de(e,t){if(e.length!==t.length)return false;let f=0;for(let l=0;l<e.length;l++)f|=e.charCodeAt(l)^t.charCodeAt(l);return f===0}function W(e){let t=new Map,f=setInterval(()=>{let a=Date.now();for(let[i,n]of t)n.resetAt<=a&&t.delete(i);},e.windowMs);typeof process<"u"&&process.on&&process.on("beforeExit",()=>clearInterval(f));function l(a){return e.skipRoutes.some(i=>i.endsWith("*")?a.startsWith(i.slice(0,-1)):i.endsWith("**")?a.startsWith(i.slice(0,-2)):a===i)}function m(a){let i=a.nextUrl.pathname;if(l(i))return {allowed:true,remaining:e.maxRequests,resetAt:0,limit:e.maxRequests};let n=e.keyFn(a),s=Date.now(),d=t.get(n);if(!d||d.resetAt<=s)return d={count:1,resetAt:s+e.windowMs},t.set(n,d),{allowed:true,remaining:e.maxRequests-1,resetAt:d.resetAt,limit:e.maxRequests};d.count++;let C=Math.max(0,e.maxRequests-d.count);return {allowed:d.count<=e.maxRequests,remaining:C,resetAt:d.resetAt,limit:e.maxRequests}}function R(a,i){return a.headers.set("X-RateLimit-Limit",i.limit.toString()),a.headers.set("X-RateLimit-Remaining",i.remaining.toString()),a.headers.set("X-RateLimit-Reset",Math.ceil(i.resetAt/1e3).toString()),a}function u(a,i){if(e.onRateLimited){let s=e.onRateLimited(a);return R(s,i)}let n=server.NextResponse.json({success:false,message:"Too many requests. Please try again later.",retryAfter:Math.ceil((i.resetAt-Date.now())/1e3)},{status:429});return n.headers.set("Retry-After",Math.ceil((i.resetAt-Date.now())/1e3).toString()),R(n,i)}function c(a){t.delete(a);}function p(){t.clear();}function o(){return t.size}return {check:m,applyHeaders:R,createLimitedResponse:u,shouldSkip:l,reset:c,clear:p,size:o}}function q(e){function t(n){return e.enabled&&e.events.includes(n)}function f(n){return n.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||n.headers.get("x-real-ip")||null}async function l(n,s,d){if(!t(n))return;let C={type:n,timestamp:new Date,ip:f(s),userId:d.userId,path:s.nextUrl.pathname,method:s.method,success:d.success,metadata:d.metadata};if(e.logger)try{await e.logger(C);}catch(v){console.error("[next-api-layer] Audit logger error:",v);}}function m(n,s,d){return l("auth:success",n,{success:true,userId:s,metadata:d})}function R(n,s){return l("auth:fail",n,{success:false,metadata:s})}function u(n,s,d){return l("auth:refresh",n,{success:true,userId:s,metadata:d})}function c(n,s){return l("auth:guest",n,{success:true,metadata:s})}function p(n,s,d){return l("access:denied",n,{success:false,userId:s,metadata:d})}function o(n,s){return l("csrf:fail",n,{success:false,metadata:s})}function a(n,s){return l("rateLimit:exceeded",n,{success:false,metadata:s})}function i(n,s,d){return l("error",n,{success:false,metadata:{...d,error:s.message,stack:s.stack}})}return {emit:l,isEnabled:t,authSuccess:m,authFail:R,authRefresh:u,authGuest:c,accessDenied:p,csrfFail:o,rateLimitExceeded:a,error:i}}function te(e){let t=Q(e),f=j(t),l=z(t,f),m=K(t._resolved.csrf),R=W(t._resolved.rateLimit),u=q(t._resolved.audit);async function c(o){let{pathname:a,origin:i}=o.nextUrl,n=a.startsWith("/api");if(t._resolved.rateLimit.enabled){let g=R.check(o);if(!g.allowed)return await u.rateLimitExceeded(o,{limit:g.limit,resetAt:g.resetAt}),R.createLimitedResponse(o,g)}if(t._resolved.csrf.enabled){let g=m.validateRequest(o);if(!g.valid)return await u.csrfFail(o,{reason:g.reason}),server.NextResponse.json({success:false,message:"CSRF validation failed"},{status:403})}if(t.blockBrowserApiAccess&&n&&(o.headers.get("accept")||"").includes("text/html"))return server.NextResponse.redirect(new URL("/",i));if(t.beforeAuth){let g=await t.beforeAuth(o);if(g)return g}if((t.excludedPaths??[]).some(g=>a.startsWith(g)))return p(o,server.NextResponse.next(),{isAuthenticated:false,isGuest:false,tokenType:null,user:null});if(["/api/auth/login","/api/auth/logout","/api/auth/me","/api/auth/refresh","/api/auth/register"].includes(a))return p(o,server.NextResponse.next(),{isAuthenticated:false,isGuest:false,tokenType:null,user:null});let C=o.cookies?.get(t.cookies.user)?.value,v=o.cookies?.get(t.cookies.guest)?.value,r=C||v,x=!!C;if(!r){await u.authFail(o,{reason:"no-token"});let g=await l.handleNoToken(o,n);return p(o,g,{isAuthenticated:false,isGuest:false,tokenType:null,user:null})}let h=await f.getTokenInfo(r),y={isAuthenticated:h.isValid&&h.tokenType!=="guest",isGuest:h.isValid&&h.tokenType==="guest",tokenType:h.tokenType,user:h.userData};if(h.isValid)if(h.tokenType==="guest")await u.authGuest(o);else {let g=h.userData?.id?.toString();await u.authSuccess(o,g,{tokenType:h.tokenType});}else await u.authFail(o,{reason:"invalid-token"});let N=await l.handleValidationResult(o,h,x,r,n),k=await p(o,N,y);if(t._resolved.csrf.enabled&&y.isAuthenticated){let g=h.userData?.id?.toString()||r.slice(0,32);k=await m.attachCsrfCookie(k,g);}if(t._resolved.rateLimit.enabled){let g=R.check(o);k=R.applyHeaders(k,g);}return k}async function p(o,a,i){return t.afterAuth?t.afterAuth(o,a,i):a}return c.config=t,c.csrf=m,c.rateLimiter=R,c.audit=u,c}function pe(e,t){if(!t||t.length===0)return false;let f=e.replace(/^\/api\//,"").replace(/^\//,"");return t.some(l=>{if(l===f)return true;if(l.includes("*")){let m=l.replace(/\*\*/g,"<<<DOUBLE>>>").replace(/\*/g,"[^/]+").replace(/<<<DOUBLE>>>/g,".+");return new RegExp(`^${m}$`).test(f)}return false})}function ne(e){let{apiBaseUrl:t,userCookieName:f="auth_token",guestCookieName:l="guest_token",skipAuthByDefault:m=false,publicEndpoints:R=[],forwardHeaders:u=["content-type","accept","accept-language","x-requested-with"],excludeHeaders:c=["host","connection","cookie"],transformRequest:p,transformResponse:o}=e,a=t.replace(/\/$/,"");function i(s,d){return s.headers.get(chunk6ENVQMWQ_cjs.e.SKIP_AUTH)==="true"||pe(d,R)?true:m}async function n(s){try{let d=new URL(s.url),C=d.pathname.replace(/^\/api\/?/,""),v=new URL(`${a}/${C}`);v.search=d.search;let r=new Headers;if(u.forEach(T=>{let A=s.headers.get(T);A&&r.set(T,A);}),s.headers.forEach((T,A)=>{let E=A.toLowerCase();!c.includes(E)&&!r.has(A)&&r.set(A,T);}),!i(s,C)){let T=s.cookies.get(f)?.value,A=s.cookies.get(l)?.value,E=T||A;E&&r.set(chunk6ENVQMWQ_cjs.e.AUTHORIZATION,`Bearer ${E}`);}r.delete(chunk6ENVQMWQ_cjs.e.SKIP_AUTH);let x=p?await p(s,r):r,h=null;if(s.method!=="GET"&&s.method!=="HEAD"){let T=s.headers.get("content-type")||"";T.includes("application/json")?h=await s.text():T.includes("multipart/form-data")?h=await s.formData():h=await s.text();}let y=await fetch(v.toString(),{method:s.method,headers:x,body:h}),N=y.headers.get("content-type")||"",k;N.includes("application/json")?k=await y.text():k=await y.arrayBuffer();let g=new Headers;y.headers.forEach((T,A)=>{let E=A.toLowerCase();["transfer-encoding","connection","keep-alive"].includes(E)||g.set(A,T);});let S=new server.NextResponse(k,{status:y.status,statusText:y.statusText,headers:g});return o&&(S=await o(S)),S}catch(d){return console.error("[Proxy Error]",d),server.NextResponse.json({success:false,message:"Proxy error: Unable to connect to backend",error:d instanceof Error?d.message:"Unknown error"},{status:502})}}return n.config=e,n}
|
|
2
|
-
Object.defineProperty(exports,"createApiClient",{enumerable:true,get:function(){return
|
|
1
|
+
'use strict';var chunkJEEL6S4O_cjs=require('./chunk-JEEL6S4O.cjs'),chunk6ENVQMWQ_cjs=require('./chunk-6ENVQMWQ.cjs'),server=require('next/server');function ie(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID()+crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).substring(2)}`}function ue(e){return `rl:${e.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||e.headers.get("x-real-ip")||"unknown"}`}function Q(e){if(!e.apiBaseUrl)throw new Error("next-api-layer: apiBaseUrl is required");if(!e.cookies?.user||!e.cookies?.guest)throw new Error("next-api-layer: cookies.user and cookies.guest are required");let t=e.apiBaseUrl.endsWith("/")?e.apiBaseUrl:`${e.apiBaseUrl}/`,f={...chunk6ENVQMWQ_cjs.a,...e.cookies.options},l={...chunk6ENVQMWQ_cjs.b,...e.endpoints},m={enabled:e.csrf?.enabled??false,strategy:e.csrf?.strategy??chunk6ENVQMWQ_cjs.g.strategy,secret:e.csrf?.secret??ie(),cookieName:e.csrf?.cookieName??chunk6ENVQMWQ_cjs.g.cookieName,headerName:e.csrf?.headerName??chunk6ENVQMWQ_cjs.g.headerName,ignoreMethods:e.csrf?.ignoreMethods??chunk6ENVQMWQ_cjs.g.ignoreMethods,trustSameSite:e.csrf?.trustSameSite??chunk6ENVQMWQ_cjs.g.trustSameSite},R={enabled:e.rateLimit?.enabled??false,windowMs:e.rateLimit?.windowMs??chunk6ENVQMWQ_cjs.h.windowMs,maxRequests:e.rateLimit?.maxRequests??chunk6ENVQMWQ_cjs.h.maxRequests,keyFn:e.rateLimit?.keyFn??ue,skipRoutes:e.rateLimit?.skipRoutes??chunk6ENVQMWQ_cjs.h.skipRoutes,onRateLimited:e.rateLimit?.onRateLimited},u={enabled:e.audit?.enabled??false,events:e.audit?.events??[...chunk6ENVQMWQ_cjs.i.events],logger:e.audit?.logger};return {...e,apiBaseUrl:t,_resolved:{cookieOptions:f,endpoints:l,csrf:m,rateLimit:R,audit:u}}}var $={parseAuthMe:e=>{let t=e;return !t?.success||!t?.data?null:{isValid:true,tokenType:t.data.type||"user",exp:t.data.exp||null,userData:t.data}},parseRefreshToken:e=>{let t=e;return t?.success&&t?.data?.accessToken?t.data.accessToken:null},parseGuestToken:e=>e?.data?.accessToken||null};function j(e){let{apiBaseUrl:t,_resolved:f,responseMappers:l}=e,{endpoints:m}=f,R={parseAuthMe:l?.parseAuthMe||$.parseAuthMe,parseRefreshToken:l?.parseRefreshToken||$.parseRefreshToken,parseGuestToken:l?.parseGuestToken||$.parseGuestToken};async function u(a){let i={isValid:false,tokenType:null,exp:null,userData:null};try{let n=await fetch(`${t}${m.validate}`,{headers:{Authorization:`Bearer ${a}`,"Content-Type":"application/json"},cache:"no-store"});if(!n.ok)return i;let s=await n.json().catch(()=>null),d=R.parseAuthMe(s);return !d||!d.isValid?i:d}catch{return i}}async function c(a){return u(a)}async function p(a){try{let i=await fetch(`${t}${m.refresh}`,{method:"POST",headers:{Authorization:`Bearer ${a}`,"Content-Type":"application/json"},cache:"no-store"});if(!i.ok)return {success:!1,newToken:null};let n=await i.json().catch(()=>null),s=R.parseRefreshToken(n);return s?{success:!0,newToken:s}:{success:!1,newToken:null}}catch{return {success:false,newToken:null}}}async function o(){let a=e.guestToken;if(!a?.enabled||!a.credentials)return null;try{let i=await fetch(`${t}${m.guest}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:a.credentials.username,password:a.credentials.password}),cache:"no-store"});if(!i.ok)return null;let n=await i.json().catch(()=>null);return R.parseGuestToken(n)}catch{return null}}return {validateToken:u,getTokenInfo:c,refreshToken:p,createGuestToken:o}}function ee(e,t){if(!t?.enabled)return null;let f=t.locales??[],l=t.defaultLocale,R=e.split("/").filter(Boolean)[0];return R&&f.includes(R)?R:l??null}function z(e,t){let{cookies:f,guestToken:l,access:m,i18n:R,_resolved:u}=e,{cookieOptions:c}=u;function p(r,x,h){r.cookies.get(h)?.value&&x.cookies.delete(h);}function o(r,x){return p(r,x,f.guest),p(r,x,f.user),x}function a(r,x=500){return new server.NextResponse(JSON.stringify({success:false,message:r}),{status:x,headers:{"Content-Type":"application/json"}})}function i(r){return (m?.authRoutes??[]).some(h=>r===h||r.startsWith(`${h}/`))}function n(r){return m?.protectedByDefault?!s(r)&&!i(r):(m?.protectedRoutes??[]).some(h=>r===h||r.startsWith(`${h}/`))}function s(r){return (m?.publicRoutes??[]).some(h=>r===h||r.startsWith(`${h}/`))}function d(r){let x=m?.allowedTokenTypes;return !x||x.length===0?true:r?x.includes(r):false}async function C(r,x){let{origin:h}=r.nextUrl;if(l?.enabled){let y=await t.createGuestToken();if(y){let N;return x?N=server.NextResponse.next():n(r.nextUrl.pathname)?N=server.NextResponse.redirect(new URL("/login",h)):N=server.NextResponse.next(),N.cookies.set(f.guest,y,{...c,maxAge:3600}),N}}return x?a("Token bulunamad\u0131",401):n(r.nextUrl.pathname)?server.NextResponse.redirect(new URL("/login",h)):server.NextResponse.next()}async function v(r,x,h,y,N){let{pathname:k,origin:g}=r.nextUrl,{isValid:S,tokenType:T,userData:A}=x,E=T===chunk6ENVQMWQ_cjs.c.GUEST;if(!S){if(h&&y){let D=await t.refreshToken(y);if(D.success&&D.newToken){let O=await t.getTokenInfo(D.newToken);if(O.isValid){let _=new Headers(r.headers);O.userData&&_.set(chunk6ENVQMWQ_cjs.e.AUTH_USER,JSON.stringify(O.userData)),_.set(chunk6ENVQMWQ_cjs.e.REFRESHED_TOKEN,D.newToken);let Z=ee(k,R);Z&&_.set(chunk6ENVQMWQ_cjs.e.LOCALE,Z);let I;return i(k)?I=server.NextResponse.redirect(new URL("/",g)):I=server.NextResponse.next({request:{headers:_}}),I.cookies.set(f.user,D.newToken,{...c,maxAge:c.maxAge}),p(r,I,f.guest),I}}}let P=await C(r,N);return P.cookies.get(f.guest)?.value?p(r,P,f.user):o(r,P),P}let U=new Headers(r.headers);A&&U.set(chunk6ENVQMWQ_cjs.e.AUTH_USER,JSON.stringify(A));let J=ee(k,R);if(J&&U.set(chunk6ENVQMWQ_cjs.e.LOCALE,J),!E&&!d(T)){if(N){let Y=a("Bu i\u015Flem i\xE7in yetkiniz yok",403);return o(r,Y)}let P=server.NextResponse.redirect(new URL("/login",g));return o(r,P)}if(E)return N?server.NextResponse.next({request:{headers:U}}):n(k)?server.NextResponse.redirect(new URL("/login",g)):server.NextResponse.next({request:{headers:U}});if(i(k))return server.NextResponse.redirect(new URL("/",g));let X=server.NextResponse.next({request:{headers:U}});return p(r,X,f.guest),X}return {deleteAllAuthCookies:o,jsonError:a,isAuthPage:i,isProtectedRoute:n,isPublicRoute:s,isTokenTypeAllowed:d,handleNoToken:C,handleValidationResult:v}}function K(e){async function t(u){let c=le();return `${await ce(e.secret,u,c)}.${c}`}function f(u){let c=u.method.toUpperCase();if(e.ignoreMethods.includes(c))return {valid:true};let p=e.strategy;if(p==="fetch-metadata"||p==="both"){let o=l(u);if(p==="fetch-metadata"||o.valid||o.reason!=="missing-headers")return o}return p==="double-submit"||p==="both"?m(u):{valid:true}}function l(u){let c=u.headers.get("sec-fetch-site");if(!c)return {valid:false,reason:"missing-headers"};if(c==="same-origin")return {valid:true};if(c==="none"){let p=u.method.toUpperCase();return e.ignoreMethods.includes(p)?{valid:true}:{valid:false,reason:"direct-navigation-unsafe-method"}}return c==="same-site"?e.trustSameSite?{valid:true}:{valid:false,reason:"same-site-not-trusted"}:c==="cross-site"?{valid:false,reason:"cross-site-request"}:{valid:false,reason:"unknown-sec-fetch-site"}}function m(u){let c=u.cookies.get(e.cookieName)?.value;if(!c)return {valid:false,reason:"missing-cookie-token"};let p=u.headers.get(e.headerName);return p?de(c,p)?c.split(".").length!==2?{valid:false,reason:"invalid-token-format"}:{valid:true}:{valid:false,reason:"token-mismatch"}:{valid:false,reason:"missing-header-token"}}async function R(u,c){let p=await t(c);return u.cookies.set(e.cookieName,p,{httpOnly:false,secure:process.env.NODE_ENV==="production",sameSite:"strict",path:"/"}),u}return {validateRequest:f,generateToken:t,attachCsrfCookie:R}}function le(){if(typeof crypto<"u"&&crypto.getRandomValues){let e=new Uint8Array(32);return crypto.getRandomValues(e),Array.from(e,t=>t.toString(16).padStart(2,"0")).join("")}return Math.random().toString(36).substring(2)+Date.now().toString(36)}async function ce(e,t,f){let l=`${t.length}!${t}!${f.length}!${f}`;if(typeof crypto<"u"&&crypto.subtle){let u=new TextEncoder,c=u.encode(e),p=u.encode(l),o=await crypto.subtle.importKey("raw",c,{name:"HMAC",hash:"SHA-256"},false,["sign"]),a=await crypto.subtle.sign("HMAC",o,p);return Array.from(new Uint8Array(a),i=>i.toString(16).padStart(2,"0")).join("")}let m=0,R=e+l;for(let u=0;u<R.length;u++){let c=R.charCodeAt(u);m=(m<<5)-m+c,m=m&m;}return Math.abs(m).toString(16)}function de(e,t){if(e.length!==t.length)return false;let f=0;for(let l=0;l<e.length;l++)f|=e.charCodeAt(l)^t.charCodeAt(l);return f===0}function W(e){let t=new Map,f=setInterval(()=>{let a=Date.now();for(let[i,n]of t)n.resetAt<=a&&t.delete(i);},e.windowMs);typeof process<"u"&&process.on&&process.on("beforeExit",()=>clearInterval(f));function l(a){return e.skipRoutes.some(i=>i.endsWith("*")?a.startsWith(i.slice(0,-1)):i.endsWith("**")?a.startsWith(i.slice(0,-2)):a===i)}function m(a){let i=a.nextUrl.pathname;if(l(i))return {allowed:true,remaining:e.maxRequests,resetAt:0,limit:e.maxRequests};let n=e.keyFn(a),s=Date.now(),d=t.get(n);if(!d||d.resetAt<=s)return d={count:1,resetAt:s+e.windowMs},t.set(n,d),{allowed:true,remaining:e.maxRequests-1,resetAt:d.resetAt,limit:e.maxRequests};d.count++;let C=Math.max(0,e.maxRequests-d.count);return {allowed:d.count<=e.maxRequests,remaining:C,resetAt:d.resetAt,limit:e.maxRequests}}function R(a,i){return a.headers.set("X-RateLimit-Limit",i.limit.toString()),a.headers.set("X-RateLimit-Remaining",i.remaining.toString()),a.headers.set("X-RateLimit-Reset",Math.ceil(i.resetAt/1e3).toString()),a}function u(a,i){if(e.onRateLimited){let s=e.onRateLimited(a);return R(s,i)}let n=server.NextResponse.json({success:false,message:"Too many requests. Please try again later.",retryAfter:Math.ceil((i.resetAt-Date.now())/1e3)},{status:429});return n.headers.set("Retry-After",Math.ceil((i.resetAt-Date.now())/1e3).toString()),R(n,i)}function c(a){t.delete(a);}function p(){t.clear();}function o(){return t.size}return {check:m,applyHeaders:R,createLimitedResponse:u,shouldSkip:l,reset:c,clear:p,size:o}}function q(e){function t(n){return e.enabled&&e.events.includes(n)}function f(n){return n.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||n.headers.get("x-real-ip")||null}async function l(n,s,d){if(!t(n))return;let C={type:n,timestamp:new Date,ip:f(s),userId:d.userId,path:s.nextUrl.pathname,method:s.method,success:d.success,metadata:d.metadata};if(e.logger)try{await e.logger(C);}catch(v){console.error("[next-api-layer] Audit logger error:",v);}}function m(n,s,d){return l("auth:success",n,{success:true,userId:s,metadata:d})}function R(n,s){return l("auth:fail",n,{success:false,metadata:s})}function u(n,s,d){return l("auth:refresh",n,{success:true,userId:s,metadata:d})}function c(n,s){return l("auth:guest",n,{success:true,metadata:s})}function p(n,s,d){return l("access:denied",n,{success:false,userId:s,metadata:d})}function o(n,s){return l("csrf:fail",n,{success:false,metadata:s})}function a(n,s){return l("rateLimit:exceeded",n,{success:false,metadata:s})}function i(n,s,d){return l("error",n,{success:false,metadata:{...d,error:s.message,stack:s.stack}})}return {emit:l,isEnabled:t,authSuccess:m,authFail:R,authRefresh:u,authGuest:c,accessDenied:p,csrfFail:o,rateLimitExceeded:a,error:i}}function te(e){let t=Q(e),f=j(t),l=z(t,f),m=K(t._resolved.csrf),R=W(t._resolved.rateLimit),u=q(t._resolved.audit);async function c(o){let{pathname:a,origin:i}=o.nextUrl,n=a.startsWith("/api");if(t._resolved.rateLimit.enabled){let g=R.check(o);if(!g.allowed)return await u.rateLimitExceeded(o,{limit:g.limit,resetAt:g.resetAt}),R.createLimitedResponse(o,g)}if(t._resolved.csrf.enabled){let g=m.validateRequest(o);if(!g.valid)return await u.csrfFail(o,{reason:g.reason}),server.NextResponse.json({success:false,message:"CSRF validation failed"},{status:403})}if(t.blockBrowserApiAccess&&n&&(o.headers.get("accept")||"").includes("text/html"))return server.NextResponse.redirect(new URL("/",i));if(t.beforeAuth){let g=await t.beforeAuth(o);if(g)return g}if((t.excludedPaths??[]).some(g=>a.startsWith(g)))return p(o,server.NextResponse.next(),{isAuthenticated:false,isGuest:false,tokenType:null,user:null});if(["/api/auth/login","/api/auth/logout","/api/auth/me","/api/auth/refresh","/api/auth/register"].includes(a))return p(o,server.NextResponse.next(),{isAuthenticated:false,isGuest:false,tokenType:null,user:null});let C=o.cookies?.get(t.cookies.user)?.value,v=o.cookies?.get(t.cookies.guest)?.value,r=C||v,x=!!C;if(!r){await u.authFail(o,{reason:"no-token"});let g=await l.handleNoToken(o,n);return p(o,g,{isAuthenticated:false,isGuest:false,tokenType:null,user:null})}let h=await f.getTokenInfo(r),y={isAuthenticated:h.isValid&&h.tokenType!=="guest",isGuest:h.isValid&&h.tokenType==="guest",tokenType:h.tokenType,user:h.userData};if(h.isValid)if(h.tokenType==="guest")await u.authGuest(o);else {let g=h.userData?.id?.toString();await u.authSuccess(o,g,{tokenType:h.tokenType});}else await u.authFail(o,{reason:"invalid-token"});let N=await l.handleValidationResult(o,h,x,r,n),k=await p(o,N,y);if(t._resolved.csrf.enabled&&y.isAuthenticated){let g=h.userData?.id?.toString()||r.slice(0,32);k=await m.attachCsrfCookie(k,g);}if(t._resolved.rateLimit.enabled){let g=R.check(o);k=R.applyHeaders(k,g);}return k}async function p(o,a,i){return t.afterAuth?t.afterAuth(o,a,i):a}return c.config=t,c.csrf=m,c.rateLimiter=R,c.audit=u,c}function pe(e,t){if(!t||t.length===0)return false;let f=e.replace(/^\/api\//,"").replace(/^\//,"");return t.some(l=>{if(l===f)return true;if(l.includes("*")){let m=l.replace(/\*\*/g,"<<<DOUBLE>>>").replace(/\*/g,"[^/]+").replace(/<<<DOUBLE>>>/g,".+");return new RegExp(`^${m}$`).test(f)}return false})}function ne(e){let{apiBaseUrl:t,userCookieName:f="auth_token",guestCookieName:l="guest_token",skipAuthByDefault:m=false,publicEndpoints:R=[],forwardHeaders:u=["content-type","accept","accept-language","x-requested-with"],excludeHeaders:c=["host","connection","cookie"],transformRequest:p,transformResponse:o}=e,a=t.replace(/\/$/,"");function i(s,d){return s.headers.get(chunk6ENVQMWQ_cjs.e.SKIP_AUTH)==="true"||pe(d,R)?true:m}async function n(s){try{let d=new URL(s.url),C=d.pathname.replace(/^\/api\/?/,""),v=new URL(`${a}/${C}`);v.search=d.search;let r=new Headers;if(u.forEach(T=>{let A=s.headers.get(T);A&&r.set(T,A);}),s.headers.forEach((T,A)=>{let E=A.toLowerCase();!c.includes(E)&&!r.has(A)&&r.set(A,T);}),!i(s,C)){let T=s.cookies.get(f)?.value,A=s.cookies.get(l)?.value,E=T||A;E&&r.set(chunk6ENVQMWQ_cjs.e.AUTHORIZATION,`Bearer ${E}`);}r.delete(chunk6ENVQMWQ_cjs.e.SKIP_AUTH);let x=p?await p(s,r):r,h=null;if(s.method!=="GET"&&s.method!=="HEAD"){let T=s.headers.get("content-type")||"";T.includes("application/json")?h=await s.text():T.includes("multipart/form-data")?h=await s.formData():h=await s.text();}let y=await fetch(v.toString(),{method:s.method,headers:x,body:h}),N=y.headers.get("content-type")||"",k;N.includes("application/json")?k=await y.text():k=await y.arrayBuffer();let g=new Headers;y.headers.forEach((T,A)=>{let E=A.toLowerCase();["transfer-encoding","connection","keep-alive"].includes(E)||g.set(A,T);});let S=new server.NextResponse(k,{status:y.status,statusText:y.statusText,headers:g});return o&&(S=await o(S)),S}catch(d){return console.error("[Proxy Error]",d),server.NextResponse.json({success:false,message:"Proxy error: Unable to connect to backend",error:d instanceof Error?d.message:"Unknown error"},{status:502})}}return n.config=e,n}
|
|
2
|
+
Object.defineProperty(exports,"createApiClient",{enumerable:true,get:function(){return chunkJEEL6S4O_cjs.d}});Object.defineProperty(exports,"CSRF_SAFE_METHODS",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.f}});Object.defineProperty(exports,"DEFAULT_AUDIT_CONFIG",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.i}});Object.defineProperty(exports,"DEFAULT_COOKIE_OPTIONS",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.a}});Object.defineProperty(exports,"DEFAULT_CSRF_CONFIG",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.g}});Object.defineProperty(exports,"DEFAULT_ENDPOINTS",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.b}});Object.defineProperty(exports,"DEFAULT_RATE_LIMIT_CONFIG",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.h}});Object.defineProperty(exports,"ERROR_MESSAGES",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.d}});Object.defineProperty(exports,"HEADERS",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.e}});Object.defineProperty(exports,"TOKEN_TYPES",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.c}});exports.createAuditLogger=q;exports.createAuthProxy=te;exports.createCsrfValidator=K;exports.createHandlers=z;exports.createProxyHandler=ne;exports.createRateLimiter=W;exports.createTokenValidation=j;//# sourceMappingURL=index.cjs.map
|
|
3
3
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
-
import { R as ResolvedRateLimitConfig, a as ResolvedCsrfConfig, A as AuthProxyConfig, I as InternalProxyConfig, b as AuditEventType, c as ResolvedAuditConfig, T as TokenInfo, d as RefreshResult, C as CookieOptions, E as EndpointConfig } from './createApiClient-
|
|
3
|
-
export { e as AccessConfig, f as ApiClient, g as ApiClientConfig, h as ApiResponse, i as AuditConfig, j as AuditEvent, k as AuthData, l as AuthResult, m as CookieConfig, n as CsrfConfig, G as GuestTokenConfig, o as I18nConfig, p as RateLimitConfig, q as ResponseMappers, S as SanitizationConfig, U as UserData, r as createApiClient } from './createApiClient-
|
|
2
|
+
import { R as ResolvedRateLimitConfig, a as ResolvedCsrfConfig, A as AuthProxyConfig, I as InternalProxyConfig, b as AuditEventType, c as ResolvedAuditConfig, T as TokenInfo, d as RefreshResult, C as CookieOptions, E as EndpointConfig } from './createApiClient-BliWeW4X.cjs';
|
|
3
|
+
export { e as AccessConfig, f as ApiClient, g as ApiClientConfig, h as ApiResponse, i as AuditConfig, j as AuditEvent, k as AuthData, l as AuthResult, m as CookieConfig, n as CsrfConfig, G as GuestTokenConfig, o as I18nConfig, p as RateLimitConfig, q as ResponseMappers, S as SanitizationConfig, U as UserData, r as createApiClient } from './createApiClient-BliWeW4X.cjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Rate Limiting
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
-
import { R as ResolvedRateLimitConfig, a as ResolvedCsrfConfig, A as AuthProxyConfig, I as InternalProxyConfig, b as AuditEventType, c as ResolvedAuditConfig, T as TokenInfo, d as RefreshResult, C as CookieOptions, E as EndpointConfig } from './createApiClient-
|
|
3
|
-
export { e as AccessConfig, f as ApiClient, g as ApiClientConfig, h as ApiResponse, i as AuditConfig, j as AuditEvent, k as AuthData, l as AuthResult, m as CookieConfig, n as CsrfConfig, G as GuestTokenConfig, o as I18nConfig, p as RateLimitConfig, q as ResponseMappers, S as SanitizationConfig, U as UserData, r as createApiClient } from './createApiClient-
|
|
2
|
+
import { R as ResolvedRateLimitConfig, a as ResolvedCsrfConfig, A as AuthProxyConfig, I as InternalProxyConfig, b as AuditEventType, c as ResolvedAuditConfig, T as TokenInfo, d as RefreshResult, C as CookieOptions, E as EndpointConfig } from './createApiClient-BliWeW4X.js';
|
|
3
|
+
export { e as AccessConfig, f as ApiClient, g as ApiClientConfig, h as ApiResponse, i as AuditConfig, j as AuditEvent, k as AuthData, l as AuthResult, m as CookieConfig, n as CsrfConfig, G as GuestTokenConfig, o as I18nConfig, p as RateLimitConfig, q as ResponseMappers, S as SanitizationConfig, U as UserData, r as createApiClient } from './createApiClient-BliWeW4X.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Rate Limiting
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export{d as createApiClient}from'./chunk-NBYI46RO.js';import {c,e,a,b,g,h,i}from'./chunk-XBAO7FJN.js';export{f as CSRF_SAFE_METHODS,i as DEFAULT_AUDIT_CONFIG,a as DEFAULT_COOKIE_OPTIONS,g as DEFAULT_CSRF_CONFIG,b as DEFAULT_ENDPOINTS,h as DEFAULT_RATE_LIMIT_CONFIG,d as ERROR_MESSAGES,e as HEADERS,c as TOKEN_TYPES}from'./chunk-XBAO7FJN.js';import {NextResponse}from'next/server';function ie(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID()+crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).substring(2)}`}function ue(e){return `rl:${e.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||e.headers.get("x-real-ip")||"unknown"}`}function Q(e){if(!e.apiBaseUrl)throw new Error("next-api-layer: apiBaseUrl is required");if(!e.cookies?.user||!e.cookies?.guest)throw new Error("next-api-layer: cookies.user and cookies.guest are required");let t=e.apiBaseUrl.endsWith("/")?e.apiBaseUrl:`${e.apiBaseUrl}/`,f={...a,...e.cookies.options},l={...b,...e.endpoints},m={enabled:e.csrf?.enabled??false,strategy:e.csrf?.strategy??g.strategy,secret:e.csrf?.secret??ie(),cookieName:e.csrf?.cookieName??g.cookieName,headerName:e.csrf?.headerName??g.headerName,ignoreMethods:e.csrf?.ignoreMethods??g.ignoreMethods,trustSameSite:e.csrf?.trustSameSite??g.trustSameSite},R={enabled:e.rateLimit?.enabled??false,windowMs:e.rateLimit?.windowMs??h.windowMs,maxRequests:e.rateLimit?.maxRequests??h.maxRequests,keyFn:e.rateLimit?.keyFn??ue,skipRoutes:e.rateLimit?.skipRoutes??h.skipRoutes,onRateLimited:e.rateLimit?.onRateLimited},u={enabled:e.audit?.enabled??false,events:e.audit?.events??[...i.events],logger:e.audit?.logger};return {...e,apiBaseUrl:t,_resolved:{cookieOptions:f,endpoints:l,csrf:m,rateLimit:R,audit:u}}}var $={parseAuthMe:e=>{let t=e;return !t?.success||!t?.data?null:{isValid:true,tokenType:t.data.type||"user",exp:t.data.exp||null,userData:t.data}},parseRefreshToken:e=>{let t=e;return t?.success&&t?.data?.accessToken?t.data.accessToken:null},parseGuestToken:e=>e?.data?.accessToken||null};function j(e){let{apiBaseUrl:t,_resolved:f,responseMappers:l}=e,{endpoints:m}=f,R={parseAuthMe:l?.parseAuthMe||$.parseAuthMe,parseRefreshToken:l?.parseRefreshToken||$.parseRefreshToken,parseGuestToken:l?.parseGuestToken||$.parseGuestToken};async function u(a){let i={isValid:false,tokenType:null,exp:null,userData:null};try{let n=await fetch(`${t}${m.validate}`,{headers:{Authorization:`Bearer ${a}`,"Content-Type":"application/json"},cache:"no-store"});if(!n.ok)return i;let s=await n.json().catch(()=>null),d=R.parseAuthMe(s);return !d||!d.isValid?i:d}catch{return i}}async function c(a){return u(a)}async function p(a){try{let i=await fetch(`${t}${m.refresh}`,{method:"POST",headers:{Authorization:`Bearer ${a}`,"Content-Type":"application/json"},cache:"no-store"});if(!i.ok)return {success:!1,newToken:null};let n=await i.json().catch(()=>null),s=R.parseRefreshToken(n);return s?{success:!0,newToken:s}:{success:!1,newToken:null}}catch{return {success:false,newToken:null}}}async function o(){let a=e.guestToken;if(!a?.enabled||!a.credentials)return null;try{let i=await fetch(`${t}${m.guest}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:a.credentials.username,password:a.credentials.password}),cache:"no-store"});if(!i.ok)return null;let n=await i.json().catch(()=>null);return R.parseGuestToken(n)}catch{return null}}return {validateToken:u,getTokenInfo:c,refreshToken:p,createGuestToken:o}}function ee(e,t){if(!t?.enabled)return null;let f=t.locales??[],l=t.defaultLocale,R=e.split("/").filter(Boolean)[0];return R&&f.includes(R)?R:l??null}function z(e$1,t){let{cookies:f,guestToken:l,access:m,i18n:R,_resolved:u}=e$1,{cookieOptions:c$1}=u;function p(r,x,h){r.cookies.get(h)?.value&&x.cookies.delete(h);}function o(r,x){return p(r,x,f.guest),p(r,x,f.user),x}function a(r,x=500){return new NextResponse(JSON.stringify({success:false,message:r}),{status:x,headers:{"Content-Type":"application/json"}})}function i(r){return (m?.authRoutes??[]).some(h=>r===h||r.startsWith(`${h}/`))}function n(r){return m?.protectedByDefault?!s(r)&&!i(r):(m?.protectedRoutes??[]).some(h=>r===h||r.startsWith(`${h}/`))}function s(r){return (m?.publicRoutes??[]).some(h=>r===h||r.startsWith(`${h}/`))}function d(r){let x=m?.allowedTokenTypes;return !x||x.length===0?true:r?x.includes(r):false}async function C(r,x){let{origin:h}=r.nextUrl;if(l?.enabled){let y=await t.createGuestToken();if(y){let N;return x?N=NextResponse.next():n(r.nextUrl.pathname)?N=NextResponse.redirect(new URL("/login",h)):N=NextResponse.next(),N.cookies.set(f.guest,y,{...c$1,maxAge:3600}),N}}return x?a("Token bulunamad\u0131",401):n(r.nextUrl.pathname)?NextResponse.redirect(new URL("/login",h)):NextResponse.next()}async function v(r,x,h,y,N){let{pathname:k,origin:g}=r.nextUrl,{isValid:S,tokenType:T,userData:A}=x,E=T===c.GUEST;if(!S){if(h&&y){let D=await t.refreshToken(y);if(D.success&&D.newToken){let O=await t.getTokenInfo(D.newToken);if(O.isValid){let _=new Headers(r.headers);O.userData&&_.set(e.AUTH_USER,JSON.stringify(O.userData)),_.set(e.REFRESHED_TOKEN,D.newToken);let Z=ee(k,R);Z&&_.set(e.LOCALE,Z);let I;return i(k)?I=NextResponse.redirect(new URL("/",g)):I=NextResponse.next({request:{headers:_}}),I.cookies.set(f.user,D.newToken,{...c$1,maxAge:c$1.maxAge}),p(r,I,f.guest),I}}}let P=await C(r,N);return P.cookies.get(f.guest)?.value?p(r,P,f.user):o(r,P),P}let U=new Headers(r.headers);A&&U.set(e.AUTH_USER,JSON.stringify(A));let J=ee(k,R);if(J&&U.set(e.LOCALE,J),!E&&!d(T)){if(N){let Y=a("Bu i\u015Flem i\xE7in yetkiniz yok",403);return o(r,Y)}let P=NextResponse.redirect(new URL("/login",g));return o(r,P)}if(E)return N?NextResponse.next({request:{headers:U}}):n(k)?NextResponse.redirect(new URL("/login",g)):NextResponse.next({request:{headers:U}});if(i(k))return NextResponse.redirect(new URL("/",g));let X=NextResponse.next({request:{headers:U}});return p(r,X,f.guest),X}return {deleteAllAuthCookies:o,jsonError:a,isAuthPage:i,isProtectedRoute:n,isPublicRoute:s,isTokenTypeAllowed:d,handleNoToken:C,handleValidationResult:v}}function K(e){async function t(u){let c=le();return `${await ce(e.secret,u,c)}.${c}`}function f(u){let c=u.method.toUpperCase();if(e.ignoreMethods.includes(c))return {valid:true};let p=e.strategy;if(p==="fetch-metadata"||p==="both"){let o=l(u);if(p==="fetch-metadata"||o.valid||o.reason!=="missing-headers")return o}return p==="double-submit"||p==="both"?m(u):{valid:true}}function l(u){let c=u.headers.get("sec-fetch-site");if(!c)return {valid:false,reason:"missing-headers"};if(c==="same-origin")return {valid:true};if(c==="none"){let p=u.method.toUpperCase();return e.ignoreMethods.includes(p)?{valid:true}:{valid:false,reason:"direct-navigation-unsafe-method"}}return c==="same-site"?e.trustSameSite?{valid:true}:{valid:false,reason:"same-site-not-trusted"}:c==="cross-site"?{valid:false,reason:"cross-site-request"}:{valid:false,reason:"unknown-sec-fetch-site"}}function m(u){let c=u.cookies.get(e.cookieName)?.value;if(!c)return {valid:false,reason:"missing-cookie-token"};let p=u.headers.get(e.headerName);return p?de(c,p)?c.split(".").length!==2?{valid:false,reason:"invalid-token-format"}:{valid:true}:{valid:false,reason:"token-mismatch"}:{valid:false,reason:"missing-header-token"}}async function R(u,c){let p=await t(c);return u.cookies.set(e.cookieName,p,{httpOnly:false,secure:process.env.NODE_ENV==="production",sameSite:"strict",path:"/"}),u}return {validateRequest:f,generateToken:t,attachCsrfCookie:R}}function le(){if(typeof crypto<"u"&&crypto.getRandomValues){let e=new Uint8Array(32);return crypto.getRandomValues(e),Array.from(e,t=>t.toString(16).padStart(2,"0")).join("")}return Math.random().toString(36).substring(2)+Date.now().toString(36)}async function ce(e,t,f){let l=`${t.length}!${t}!${f.length}!${f}`;if(typeof crypto<"u"&&crypto.subtle){let u=new TextEncoder,c=u.encode(e),p=u.encode(l),o=await crypto.subtle.importKey("raw",c,{name:"HMAC",hash:"SHA-256"},false,["sign"]),a=await crypto.subtle.sign("HMAC",o,p);return Array.from(new Uint8Array(a),i=>i.toString(16).padStart(2,"0")).join("")}let m=0,R=e+l;for(let u=0;u<R.length;u++){let c=R.charCodeAt(u);m=(m<<5)-m+c,m=m&m;}return Math.abs(m).toString(16)}function de(e,t){if(e.length!==t.length)return false;let f=0;for(let l=0;l<e.length;l++)f|=e.charCodeAt(l)^t.charCodeAt(l);return f===0}function W(e){let t=new Map,f=setInterval(()=>{let a=Date.now();for(let[i,n]of t)n.resetAt<=a&&t.delete(i);},e.windowMs);typeof process<"u"&&process.on&&process.on("beforeExit",()=>clearInterval(f));function l(a){return e.skipRoutes.some(i=>i.endsWith("*")?a.startsWith(i.slice(0,-1)):i.endsWith("**")?a.startsWith(i.slice(0,-2)):a===i)}function m(a){let i=a.nextUrl.pathname;if(l(i))return {allowed:true,remaining:e.maxRequests,resetAt:0,limit:e.maxRequests};let n=e.keyFn(a),s=Date.now(),d=t.get(n);if(!d||d.resetAt<=s)return d={count:1,resetAt:s+e.windowMs},t.set(n,d),{allowed:true,remaining:e.maxRequests-1,resetAt:d.resetAt,limit:e.maxRequests};d.count++;let C=Math.max(0,e.maxRequests-d.count);return {allowed:d.count<=e.maxRequests,remaining:C,resetAt:d.resetAt,limit:e.maxRequests}}function R(a,i){return a.headers.set("X-RateLimit-Limit",i.limit.toString()),a.headers.set("X-RateLimit-Remaining",i.remaining.toString()),a.headers.set("X-RateLimit-Reset",Math.ceil(i.resetAt/1e3).toString()),a}function u(a,i){if(e.onRateLimited){let s=e.onRateLimited(a);return R(s,i)}let n=NextResponse.json({success:false,message:"Too many requests. Please try again later.",retryAfter:Math.ceil((i.resetAt-Date.now())/1e3)},{status:429});return n.headers.set("Retry-After",Math.ceil((i.resetAt-Date.now())/1e3).toString()),R(n,i)}function c(a){t.delete(a);}function p(){t.clear();}function o(){return t.size}return {check:m,applyHeaders:R,createLimitedResponse:u,shouldSkip:l,reset:c,clear:p,size:o}}function q(e){function t(n){return e.enabled&&e.events.includes(n)}function f(n){return n.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||n.headers.get("x-real-ip")||null}async function l(n,s,d){if(!t(n))return;let C={type:n,timestamp:new Date,ip:f(s),userId:d.userId,path:s.nextUrl.pathname,method:s.method,success:d.success,metadata:d.metadata};if(e.logger)try{await e.logger(C);}catch(v){console.error("[next-api-layer] Audit logger error:",v);}}function m(n,s,d){return l("auth:success",n,{success:true,userId:s,metadata:d})}function R(n,s){return l("auth:fail",n,{success:false,metadata:s})}function u(n,s,d){return l("auth:refresh",n,{success:true,userId:s,metadata:d})}function c(n,s){return l("auth:guest",n,{success:true,metadata:s})}function p(n,s,d){return l("access:denied",n,{success:false,userId:s,metadata:d})}function o(n,s){return l("csrf:fail",n,{success:false,metadata:s})}function a(n,s){return l("rateLimit:exceeded",n,{success:false,metadata:s})}function i(n,s,d){return l("error",n,{success:false,metadata:{...d,error:s.message,stack:s.stack}})}return {emit:l,isEnabled:t,authSuccess:m,authFail:R,authRefresh:u,authGuest:c,accessDenied:p,csrfFail:o,rateLimitExceeded:a,error:i}}function te(e){let t=Q(e),f=j(t),l=z(t,f),m=K(t._resolved.csrf),R=W(t._resolved.rateLimit),u=q(t._resolved.audit);async function c(o){let{pathname:a,origin:i}=o.nextUrl,n=a.startsWith("/api");if(t._resolved.rateLimit.enabled){let g=R.check(o);if(!g.allowed)return await u.rateLimitExceeded(o,{limit:g.limit,resetAt:g.resetAt}),R.createLimitedResponse(o,g)}if(t._resolved.csrf.enabled){let g=m.validateRequest(o);if(!g.valid)return await u.csrfFail(o,{reason:g.reason}),NextResponse.json({success:false,message:"CSRF validation failed"},{status:403})}if(t.blockBrowserApiAccess&&n&&(o.headers.get("accept")||"").includes("text/html"))return NextResponse.redirect(new URL("/",i));if(t.beforeAuth){let g=await t.beforeAuth(o);if(g)return g}if((t.excludedPaths??[]).some(g=>a.startsWith(g)))return p(o,NextResponse.next(),{isAuthenticated:false,isGuest:false,tokenType:null,user:null});if(["/api/auth/login","/api/auth/logout","/api/auth/me","/api/auth/refresh","/api/auth/register"].includes(a))return p(o,NextResponse.next(),{isAuthenticated:false,isGuest:false,tokenType:null,user:null});let C=o.cookies?.get(t.cookies.user)?.value,v=o.cookies?.get(t.cookies.guest)?.value,r=C||v,x=!!C;if(!r){await u.authFail(o,{reason:"no-token"});let g=await l.handleNoToken(o,n);return p(o,g,{isAuthenticated:false,isGuest:false,tokenType:null,user:null})}let h=await f.getTokenInfo(r),y={isAuthenticated:h.isValid&&h.tokenType!=="guest",isGuest:h.isValid&&h.tokenType==="guest",tokenType:h.tokenType,user:h.userData};if(h.isValid)if(h.tokenType==="guest")await u.authGuest(o);else {let g=h.userData?.id?.toString();await u.authSuccess(o,g,{tokenType:h.tokenType});}else await u.authFail(o,{reason:"invalid-token"});let N=await l.handleValidationResult(o,h,x,r,n),k=await p(o,N,y);if(t._resolved.csrf.enabled&&y.isAuthenticated){let g=h.userData?.id?.toString()||r.slice(0,32);k=await m.attachCsrfCookie(k,g);}if(t._resolved.rateLimit.enabled){let g=R.check(o);k=R.applyHeaders(k,g);}return k}async function p(o,a,i){return t.afterAuth?t.afterAuth(o,a,i):a}return c.config=t,c.csrf=m,c.rateLimiter=R,c.audit=u,c}function pe(e,t){if(!t||t.length===0)return false;let f=e.replace(/^\/api\//,"").replace(/^\//,"");return t.some(l=>{if(l===f)return true;if(l.includes("*")){let m=l.replace(/\*\*/g,"<<<DOUBLE>>>").replace(/\*/g,"[^/]+").replace(/<<<DOUBLE>>>/g,".+");return new RegExp(`^${m}$`).test(f)}return false})}function ne(e$1){let{apiBaseUrl:t,userCookieName:f="auth_token",guestCookieName:l="guest_token",skipAuthByDefault:m=false,publicEndpoints:R=[],forwardHeaders:u=["content-type","accept","accept-language","x-requested-with"],excludeHeaders:c=["host","connection","cookie"],transformRequest:p,transformResponse:o}=e$1,a=t.replace(/\/$/,"");function i(s,d){return s.headers.get(e.SKIP_AUTH)==="true"||pe(d,R)?true:m}async function n(s){try{let d=new URL(s.url),C=d.pathname.replace(/^\/api\/?/,""),v=new URL(`${a}/${C}`);v.search=d.search;let r=new Headers;if(u.forEach(T=>{let A=s.headers.get(T);A&&r.set(T,A);}),s.headers.forEach((T,A)=>{let E=A.toLowerCase();!c.includes(E)&&!r.has(A)&&r.set(A,T);}),!i(s,C)){let T=s.cookies.get(f)?.value,A=s.cookies.get(l)?.value,E=T||A;E&&r.set(e.AUTHORIZATION,`Bearer ${E}`);}r.delete(e.SKIP_AUTH);let x=p?await p(s,r):r,h=null;if(s.method!=="GET"&&s.method!=="HEAD"){let T=s.headers.get("content-type")||"";T.includes("application/json")?h=await s.text():T.includes("multipart/form-data")?h=await s.formData():h=await s.text();}let y=await fetch(v.toString(),{method:s.method,headers:x,body:h}),N=y.headers.get("content-type")||"",k;N.includes("application/json")?k=await y.text():k=await y.arrayBuffer();let g=new Headers;y.headers.forEach((T,A)=>{let E=A.toLowerCase();["transfer-encoding","connection","keep-alive"].includes(E)||g.set(A,T);});let S=new NextResponse(k,{status:y.status,statusText:y.statusText,headers:g});return o&&(S=await o(S)),S}catch(d){return console.error("[Proxy Error]",d),NextResponse.json({success:false,message:"Proxy error: Unable to connect to backend",error:d instanceof Error?d.message:"Unknown error"},{status:502})}}return n.config=e$1,n}
|
|
1
|
+
export{d as createApiClient}from'./chunk-NDZA32WH.js';import {c,e,a,b,g,h,i}from'./chunk-XBAO7FJN.js';export{f as CSRF_SAFE_METHODS,i as DEFAULT_AUDIT_CONFIG,a as DEFAULT_COOKIE_OPTIONS,g as DEFAULT_CSRF_CONFIG,b as DEFAULT_ENDPOINTS,h as DEFAULT_RATE_LIMIT_CONFIG,d as ERROR_MESSAGES,e as HEADERS,c as TOKEN_TYPES}from'./chunk-XBAO7FJN.js';import {NextResponse}from'next/server';function ie(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID()+crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).substring(2)}`}function ue(e){return `rl:${e.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||e.headers.get("x-real-ip")||"unknown"}`}function Q(e){if(!e.apiBaseUrl)throw new Error("next-api-layer: apiBaseUrl is required");if(!e.cookies?.user||!e.cookies?.guest)throw new Error("next-api-layer: cookies.user and cookies.guest are required");let t=e.apiBaseUrl.endsWith("/")?e.apiBaseUrl:`${e.apiBaseUrl}/`,f={...a,...e.cookies.options},l={...b,...e.endpoints},m={enabled:e.csrf?.enabled??false,strategy:e.csrf?.strategy??g.strategy,secret:e.csrf?.secret??ie(),cookieName:e.csrf?.cookieName??g.cookieName,headerName:e.csrf?.headerName??g.headerName,ignoreMethods:e.csrf?.ignoreMethods??g.ignoreMethods,trustSameSite:e.csrf?.trustSameSite??g.trustSameSite},R={enabled:e.rateLimit?.enabled??false,windowMs:e.rateLimit?.windowMs??h.windowMs,maxRequests:e.rateLimit?.maxRequests??h.maxRequests,keyFn:e.rateLimit?.keyFn??ue,skipRoutes:e.rateLimit?.skipRoutes??h.skipRoutes,onRateLimited:e.rateLimit?.onRateLimited},u={enabled:e.audit?.enabled??false,events:e.audit?.events??[...i.events],logger:e.audit?.logger};return {...e,apiBaseUrl:t,_resolved:{cookieOptions:f,endpoints:l,csrf:m,rateLimit:R,audit:u}}}var $={parseAuthMe:e=>{let t=e;return !t?.success||!t?.data?null:{isValid:true,tokenType:t.data.type||"user",exp:t.data.exp||null,userData:t.data}},parseRefreshToken:e=>{let t=e;return t?.success&&t?.data?.accessToken?t.data.accessToken:null},parseGuestToken:e=>e?.data?.accessToken||null};function j(e){let{apiBaseUrl:t,_resolved:f,responseMappers:l}=e,{endpoints:m}=f,R={parseAuthMe:l?.parseAuthMe||$.parseAuthMe,parseRefreshToken:l?.parseRefreshToken||$.parseRefreshToken,parseGuestToken:l?.parseGuestToken||$.parseGuestToken};async function u(a){let i={isValid:false,tokenType:null,exp:null,userData:null};try{let n=await fetch(`${t}${m.validate}`,{headers:{Authorization:`Bearer ${a}`,"Content-Type":"application/json"},cache:"no-store"});if(!n.ok)return i;let s=await n.json().catch(()=>null),d=R.parseAuthMe(s);return !d||!d.isValid?i:d}catch{return i}}async function c(a){return u(a)}async function p(a){try{let i=await fetch(`${t}${m.refresh}`,{method:"POST",headers:{Authorization:`Bearer ${a}`,"Content-Type":"application/json"},cache:"no-store"});if(!i.ok)return {success:!1,newToken:null};let n=await i.json().catch(()=>null),s=R.parseRefreshToken(n);return s?{success:!0,newToken:s}:{success:!1,newToken:null}}catch{return {success:false,newToken:null}}}async function o(){let a=e.guestToken;if(!a?.enabled||!a.credentials)return null;try{let i=await fetch(`${t}${m.guest}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:a.credentials.username,password:a.credentials.password}),cache:"no-store"});if(!i.ok)return null;let n=await i.json().catch(()=>null);return R.parseGuestToken(n)}catch{return null}}return {validateToken:u,getTokenInfo:c,refreshToken:p,createGuestToken:o}}function ee(e,t){if(!t?.enabled)return null;let f=t.locales??[],l=t.defaultLocale,R=e.split("/").filter(Boolean)[0];return R&&f.includes(R)?R:l??null}function z(e$1,t){let{cookies:f,guestToken:l,access:m,i18n:R,_resolved:u}=e$1,{cookieOptions:c$1}=u;function p(r,x,h){r.cookies.get(h)?.value&&x.cookies.delete(h);}function o(r,x){return p(r,x,f.guest),p(r,x,f.user),x}function a(r,x=500){return new NextResponse(JSON.stringify({success:false,message:r}),{status:x,headers:{"Content-Type":"application/json"}})}function i(r){return (m?.authRoutes??[]).some(h=>r===h||r.startsWith(`${h}/`))}function n(r){return m?.protectedByDefault?!s(r)&&!i(r):(m?.protectedRoutes??[]).some(h=>r===h||r.startsWith(`${h}/`))}function s(r){return (m?.publicRoutes??[]).some(h=>r===h||r.startsWith(`${h}/`))}function d(r){let x=m?.allowedTokenTypes;return !x||x.length===0?true:r?x.includes(r):false}async function C(r,x){let{origin:h}=r.nextUrl;if(l?.enabled){let y=await t.createGuestToken();if(y){let N;return x?N=NextResponse.next():n(r.nextUrl.pathname)?N=NextResponse.redirect(new URL("/login",h)):N=NextResponse.next(),N.cookies.set(f.guest,y,{...c$1,maxAge:3600}),N}}return x?a("Token bulunamad\u0131",401):n(r.nextUrl.pathname)?NextResponse.redirect(new URL("/login",h)):NextResponse.next()}async function v(r,x,h,y,N){let{pathname:k,origin:g}=r.nextUrl,{isValid:S,tokenType:T,userData:A}=x,E=T===c.GUEST;if(!S){if(h&&y){let D=await t.refreshToken(y);if(D.success&&D.newToken){let O=await t.getTokenInfo(D.newToken);if(O.isValid){let _=new Headers(r.headers);O.userData&&_.set(e.AUTH_USER,JSON.stringify(O.userData)),_.set(e.REFRESHED_TOKEN,D.newToken);let Z=ee(k,R);Z&&_.set(e.LOCALE,Z);let I;return i(k)?I=NextResponse.redirect(new URL("/",g)):I=NextResponse.next({request:{headers:_}}),I.cookies.set(f.user,D.newToken,{...c$1,maxAge:c$1.maxAge}),p(r,I,f.guest),I}}}let P=await C(r,N);return P.cookies.get(f.guest)?.value?p(r,P,f.user):o(r,P),P}let U=new Headers(r.headers);A&&U.set(e.AUTH_USER,JSON.stringify(A));let J=ee(k,R);if(J&&U.set(e.LOCALE,J),!E&&!d(T)){if(N){let Y=a("Bu i\u015Flem i\xE7in yetkiniz yok",403);return o(r,Y)}let P=NextResponse.redirect(new URL("/login",g));return o(r,P)}if(E)return N?NextResponse.next({request:{headers:U}}):n(k)?NextResponse.redirect(new URL("/login",g)):NextResponse.next({request:{headers:U}});if(i(k))return NextResponse.redirect(new URL("/",g));let X=NextResponse.next({request:{headers:U}});return p(r,X,f.guest),X}return {deleteAllAuthCookies:o,jsonError:a,isAuthPage:i,isProtectedRoute:n,isPublicRoute:s,isTokenTypeAllowed:d,handleNoToken:C,handleValidationResult:v}}function K(e){async function t(u){let c=le();return `${await ce(e.secret,u,c)}.${c}`}function f(u){let c=u.method.toUpperCase();if(e.ignoreMethods.includes(c))return {valid:true};let p=e.strategy;if(p==="fetch-metadata"||p==="both"){let o=l(u);if(p==="fetch-metadata"||o.valid||o.reason!=="missing-headers")return o}return p==="double-submit"||p==="both"?m(u):{valid:true}}function l(u){let c=u.headers.get("sec-fetch-site");if(!c)return {valid:false,reason:"missing-headers"};if(c==="same-origin")return {valid:true};if(c==="none"){let p=u.method.toUpperCase();return e.ignoreMethods.includes(p)?{valid:true}:{valid:false,reason:"direct-navigation-unsafe-method"}}return c==="same-site"?e.trustSameSite?{valid:true}:{valid:false,reason:"same-site-not-trusted"}:c==="cross-site"?{valid:false,reason:"cross-site-request"}:{valid:false,reason:"unknown-sec-fetch-site"}}function m(u){let c=u.cookies.get(e.cookieName)?.value;if(!c)return {valid:false,reason:"missing-cookie-token"};let p=u.headers.get(e.headerName);return p?de(c,p)?c.split(".").length!==2?{valid:false,reason:"invalid-token-format"}:{valid:true}:{valid:false,reason:"token-mismatch"}:{valid:false,reason:"missing-header-token"}}async function R(u,c){let p=await t(c);return u.cookies.set(e.cookieName,p,{httpOnly:false,secure:process.env.NODE_ENV==="production",sameSite:"strict",path:"/"}),u}return {validateRequest:f,generateToken:t,attachCsrfCookie:R}}function le(){if(typeof crypto<"u"&&crypto.getRandomValues){let e=new Uint8Array(32);return crypto.getRandomValues(e),Array.from(e,t=>t.toString(16).padStart(2,"0")).join("")}return Math.random().toString(36).substring(2)+Date.now().toString(36)}async function ce(e,t,f){let l=`${t.length}!${t}!${f.length}!${f}`;if(typeof crypto<"u"&&crypto.subtle){let u=new TextEncoder,c=u.encode(e),p=u.encode(l),o=await crypto.subtle.importKey("raw",c,{name:"HMAC",hash:"SHA-256"},false,["sign"]),a=await crypto.subtle.sign("HMAC",o,p);return Array.from(new Uint8Array(a),i=>i.toString(16).padStart(2,"0")).join("")}let m=0,R=e+l;for(let u=0;u<R.length;u++){let c=R.charCodeAt(u);m=(m<<5)-m+c,m=m&m;}return Math.abs(m).toString(16)}function de(e,t){if(e.length!==t.length)return false;let f=0;for(let l=0;l<e.length;l++)f|=e.charCodeAt(l)^t.charCodeAt(l);return f===0}function W(e){let t=new Map,f=setInterval(()=>{let a=Date.now();for(let[i,n]of t)n.resetAt<=a&&t.delete(i);},e.windowMs);typeof process<"u"&&process.on&&process.on("beforeExit",()=>clearInterval(f));function l(a){return e.skipRoutes.some(i=>i.endsWith("*")?a.startsWith(i.slice(0,-1)):i.endsWith("**")?a.startsWith(i.slice(0,-2)):a===i)}function m(a){let i=a.nextUrl.pathname;if(l(i))return {allowed:true,remaining:e.maxRequests,resetAt:0,limit:e.maxRequests};let n=e.keyFn(a),s=Date.now(),d=t.get(n);if(!d||d.resetAt<=s)return d={count:1,resetAt:s+e.windowMs},t.set(n,d),{allowed:true,remaining:e.maxRequests-1,resetAt:d.resetAt,limit:e.maxRequests};d.count++;let C=Math.max(0,e.maxRequests-d.count);return {allowed:d.count<=e.maxRequests,remaining:C,resetAt:d.resetAt,limit:e.maxRequests}}function R(a,i){return a.headers.set("X-RateLimit-Limit",i.limit.toString()),a.headers.set("X-RateLimit-Remaining",i.remaining.toString()),a.headers.set("X-RateLimit-Reset",Math.ceil(i.resetAt/1e3).toString()),a}function u(a,i){if(e.onRateLimited){let s=e.onRateLimited(a);return R(s,i)}let n=NextResponse.json({success:false,message:"Too many requests. Please try again later.",retryAfter:Math.ceil((i.resetAt-Date.now())/1e3)},{status:429});return n.headers.set("Retry-After",Math.ceil((i.resetAt-Date.now())/1e3).toString()),R(n,i)}function c(a){t.delete(a);}function p(){t.clear();}function o(){return t.size}return {check:m,applyHeaders:R,createLimitedResponse:u,shouldSkip:l,reset:c,clear:p,size:o}}function q(e){function t(n){return e.enabled&&e.events.includes(n)}function f(n){return n.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||n.headers.get("x-real-ip")||null}async function l(n,s,d){if(!t(n))return;let C={type:n,timestamp:new Date,ip:f(s),userId:d.userId,path:s.nextUrl.pathname,method:s.method,success:d.success,metadata:d.metadata};if(e.logger)try{await e.logger(C);}catch(v){console.error("[next-api-layer] Audit logger error:",v);}}function m(n,s,d){return l("auth:success",n,{success:true,userId:s,metadata:d})}function R(n,s){return l("auth:fail",n,{success:false,metadata:s})}function u(n,s,d){return l("auth:refresh",n,{success:true,userId:s,metadata:d})}function c(n,s){return l("auth:guest",n,{success:true,metadata:s})}function p(n,s,d){return l("access:denied",n,{success:false,userId:s,metadata:d})}function o(n,s){return l("csrf:fail",n,{success:false,metadata:s})}function a(n,s){return l("rateLimit:exceeded",n,{success:false,metadata:s})}function i(n,s,d){return l("error",n,{success:false,metadata:{...d,error:s.message,stack:s.stack}})}return {emit:l,isEnabled:t,authSuccess:m,authFail:R,authRefresh:u,authGuest:c,accessDenied:p,csrfFail:o,rateLimitExceeded:a,error:i}}function te(e){let t=Q(e),f=j(t),l=z(t,f),m=K(t._resolved.csrf),R=W(t._resolved.rateLimit),u=q(t._resolved.audit);async function c(o){let{pathname:a,origin:i}=o.nextUrl,n=a.startsWith("/api");if(t._resolved.rateLimit.enabled){let g=R.check(o);if(!g.allowed)return await u.rateLimitExceeded(o,{limit:g.limit,resetAt:g.resetAt}),R.createLimitedResponse(o,g)}if(t._resolved.csrf.enabled){let g=m.validateRequest(o);if(!g.valid)return await u.csrfFail(o,{reason:g.reason}),NextResponse.json({success:false,message:"CSRF validation failed"},{status:403})}if(t.blockBrowserApiAccess&&n&&(o.headers.get("accept")||"").includes("text/html"))return NextResponse.redirect(new URL("/",i));if(t.beforeAuth){let g=await t.beforeAuth(o);if(g)return g}if((t.excludedPaths??[]).some(g=>a.startsWith(g)))return p(o,NextResponse.next(),{isAuthenticated:false,isGuest:false,tokenType:null,user:null});if(["/api/auth/login","/api/auth/logout","/api/auth/me","/api/auth/refresh","/api/auth/register"].includes(a))return p(o,NextResponse.next(),{isAuthenticated:false,isGuest:false,tokenType:null,user:null});let C=o.cookies?.get(t.cookies.user)?.value,v=o.cookies?.get(t.cookies.guest)?.value,r=C||v,x=!!C;if(!r){await u.authFail(o,{reason:"no-token"});let g=await l.handleNoToken(o,n);return p(o,g,{isAuthenticated:false,isGuest:false,tokenType:null,user:null})}let h=await f.getTokenInfo(r),y={isAuthenticated:h.isValid&&h.tokenType!=="guest",isGuest:h.isValid&&h.tokenType==="guest",tokenType:h.tokenType,user:h.userData};if(h.isValid)if(h.tokenType==="guest")await u.authGuest(o);else {let g=h.userData?.id?.toString();await u.authSuccess(o,g,{tokenType:h.tokenType});}else await u.authFail(o,{reason:"invalid-token"});let N=await l.handleValidationResult(o,h,x,r,n),k=await p(o,N,y);if(t._resolved.csrf.enabled&&y.isAuthenticated){let g=h.userData?.id?.toString()||r.slice(0,32);k=await m.attachCsrfCookie(k,g);}if(t._resolved.rateLimit.enabled){let g=R.check(o);k=R.applyHeaders(k,g);}return k}async function p(o,a,i){return t.afterAuth?t.afterAuth(o,a,i):a}return c.config=t,c.csrf=m,c.rateLimiter=R,c.audit=u,c}function pe(e,t){if(!t||t.length===0)return false;let f=e.replace(/^\/api\//,"").replace(/^\//,"");return t.some(l=>{if(l===f)return true;if(l.includes("*")){let m=l.replace(/\*\*/g,"<<<DOUBLE>>>").replace(/\*/g,"[^/]+").replace(/<<<DOUBLE>>>/g,".+");return new RegExp(`^${m}$`).test(f)}return false})}function ne(e$1){let{apiBaseUrl:t,userCookieName:f="auth_token",guestCookieName:l="guest_token",skipAuthByDefault:m=false,publicEndpoints:R=[],forwardHeaders:u=["content-type","accept","accept-language","x-requested-with"],excludeHeaders:c=["host","connection","cookie"],transformRequest:p,transformResponse:o}=e$1,a=t.replace(/\/$/,"");function i(s,d){return s.headers.get(e.SKIP_AUTH)==="true"||pe(d,R)?true:m}async function n(s){try{let d=new URL(s.url),C=d.pathname.replace(/^\/api\/?/,""),v=new URL(`${a}/${C}`);v.search=d.search;let r=new Headers;if(u.forEach(T=>{let A=s.headers.get(T);A&&r.set(T,A);}),s.headers.forEach((T,A)=>{let E=A.toLowerCase();!c.includes(E)&&!r.has(A)&&r.set(A,T);}),!i(s,C)){let T=s.cookies.get(f)?.value,A=s.cookies.get(l)?.value,E=T||A;E&&r.set(e.AUTHORIZATION,`Bearer ${E}`);}r.delete(e.SKIP_AUTH);let x=p?await p(s,r):r,h=null;if(s.method!=="GET"&&s.method!=="HEAD"){let T=s.headers.get("content-type")||"";T.includes("application/json")?h=await s.text():T.includes("multipart/form-data")?h=await s.formData():h=await s.text();}let y=await fetch(v.toString(),{method:s.method,headers:x,body:h}),N=y.headers.get("content-type")||"",k;N.includes("application/json")?k=await y.text():k=await y.arrayBuffer();let g=new Headers;y.headers.forEach((T,A)=>{let E=A.toLowerCase();["transfer-encoding","connection","keep-alive"].includes(E)||g.set(A,T);});let S=new NextResponse(k,{status:y.status,statusText:y.statusText,headers:g});return o&&(S=await o(S)),S}catch(d){return console.error("[Proxy Error]",d),NextResponse.json({success:false,message:"Proxy error: Unable to connect to backend",error:d instanceof Error?d.message:"Unknown error"},{status:502})}}return n.config=e$1,n}
|
|
2
2
|
export{q as createAuditLogger,te as createAuthProxy,K as createCsrfValidator,z as createHandlers,ne as createProxyHandler,W as createRateLimiter,j as createTokenValidation};//# sourceMappingURL=index.js.map
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
package/dist/chunk-NBYI46RO.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import {e}from'./chunk-XBAO7FJN.js';import {headers,cookies}from'next/headers';var M={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="},$=/[&<>"'`=/]/g,x=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,F=/\s*on\w+\s*=\s*["'][^"']*["']/gi,D=/javascript\s*:/gi,b=/data\s*:[^;]*;base64/gi;function L(n){return n.replace($,a=>M[a]||a)}function j(n){return n.replace(x,"").replace(/<[^>]*>/g,"").replace(F,"").replace(D,"").replace(b,"")}function q(n,a){let c=n.replace(x,"").replace(F,"").replace(D,"").replace(b,"");if(a.length===0)return L(c);let f=a.join("|"),l=new RegExp(`<(?!/?(?:${f})\\b)[^>]*>`,"gi");return c=c.replace(l,""),c}function z(n){let a=n?.mode??"escape",c=n?.allowedTags??[],f=n?.enabled!==false,l=n?.skipFields??[];function g(e){if(!f)return e;switch(a){case "strip":return j(e);case "allowList":return q(e,c);default:return L(e)}}function d(e,p=""){if(l.some(i=>p.endsWith(i))||e==null)return e;if(typeof e=="string")return g(e);if(typeof e=="number"||typeof e=="boolean")return e;if(Array.isArray(e))return e.map((i,r)=>d(i,`${p}[${r}]`));if(typeof e=="object"){let i={};for(let[r,u]of Object.entries(e)){let t=p?`${p}.${r}`:r;i[r]=d(u,t);}return i}return e}function R(e){return f?d(e):e}function k(e){if(!f)return e;let p=new FormData;for(let[i,r]of e.entries())r instanceof File?p.append(i,r):typeof r=="string"?p.append(i,g(r)):p.append(i,r);return p}return {sanitize:R,sanitizeString:g,sanitizeValue:d,sanitizeFormData:k}}var O=z({enabled:true,mode:"escape",skipFields:[]});function I(n){return O.sanitize(n)}function B(n){let{apiBaseUrl:a,cookies:c,methodSpoofing:f=false,errorMessages:l={},i18n:g}=n,d=a.endsWith("/")?a:`${a}/`,R=z(n.sanitization),k=l.noToken??"Token bulunamad\u0131. L\xFCtfen giri\u015F yap\u0131n.",e$1=l.connectionError??"Ba\u011Flant\u0131 hatas\u0131 olu\u015Ftu.";async function p(){let o=(await headers()).get(e.REFRESHED_TOKEN);if(o)return o;let s=await cookies();return s.get(c.user)?.value||s.get(c.guest)?.value||null}function i(t,o=500){return Response.json({success:false,message:t},{status:o})}function r(){return i(k,401)}async function u(t,o,s,T={}){let h=T.skipAuth?null:await p();if(!T.skipAuth&&!h)return r();try{let m={};h&&(m.Authorization=`Bearer ${h}`);let S,y=t;s&&(T.isFormData&&s instanceof FormData?(S=R.sanitizeFormData(s),(T.methodSpoofing??f)&&(t==="PUT"||t==="PATCH")&&(S.append("_method",t),y="POST")):s instanceof FormData||(m["Content-Type"]="application/json",S=JSON.stringify(R.sanitize(s))));let A=`${d}${o}`;if(g?.enabled){let E=(await headers()).get(e.LOCALE);if(E&&(!g.locales||g.locales.includes(E))){let P=new URL(A);P.searchParams.set(g.paramName||"lang",E),A=P.toString();}}let C=await fetch(A,{method:y,headers:m,body:S,cache:"no-store"}),_=await C.json();return Response.json(_,{status:C.status})}catch(m){return console.error(`API ${t} Error:`,m),i(e$1)}}return {get:t=>u("GET",t),post:(t,o,s)=>u("POST",t,o,s),put:(t,o,s)=>u("PUT",t,o,s),patch:(t,o)=>u("PATCH",t,o),delete:t=>u("DELETE",t)}}export{z as a,O as b,I as c,B as d};//# sourceMappingURL=chunk-NBYI46RO.js.map
|
|
2
|
-
//# sourceMappingURL=chunk-NBYI46RO.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/api/sanitize.ts","../src/api/createApiClient.ts"],"names":["HTML_ENTITIES","HTML_ENTITY_REGEX","SCRIPT_PATTERN","EVENT_HANDLER_PATTERN","JAVASCRIPT_URL_PATTERN","DATA_URL_PATTERN","escapeHtml","str","char","stripHtml","sanitizeWithAllowList","allowedTags","result","allowedPattern","allowedRegex","createSanitizer","config","mode","enabled","skipFields","sanitizeString","value","sanitizeValue","path","field","item","index","sanitized","key","val","newPath","sanitize","data","sanitizeFormData","formData","defaultSanitizer","createApiClient","apiBaseUrl","cookieNames","globalMethodSpoofing","errorMessages","i18n","baseUrl","sanitizer","noTokenMessage","connectionErrorMessage","getToken","refreshedToken","headers","HEADERS","cookieStore","cookies","errorResponse","message","status","noTokenResponse","makeRequest","method","endpoint","body","options","token","fetchHeaders","fetchBody","actualMethod","url","locale","urlObj","res","error"],"mappings":"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","file":"chunk-NBYI46RO.js","sourcesContent":["/**\r\n * XSS Sanitization utilities\r\n * Zero-dependency, lightweight sanitizer for API responses\r\n * \r\n * Modes:\r\n * - 'escape' (default): Escapes HTML entities (<script>)\r\n * - 'strip': Removes all HTML tags completely\r\n * - 'allowList': Only allows specified tags (advanced)\r\n */\r\n\r\nimport type { SanitizationConfig } from '../shared/types';\r\n\r\nexport interface SanitizeOptions {\r\n config: SanitizationConfig;\r\n}\r\n\r\n// HTML entities to escape\r\nconst HTML_ENTITIES: Record<string, string> = {\r\n '&': '&',\r\n '<': '<',\r\n '>': '>',\r\n '\"': '"',\r\n \"'\": ''',\r\n '/': '/',\r\n '`': '`',\r\n '=': '=',\r\n};\r\n\r\n// Regex patterns\r\nconst HTML_ENTITY_REGEX = /[&<>\"'`=/]/g;\r\nconst SCRIPT_PATTERN = /<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi;\r\nconst EVENT_HANDLER_PATTERN = /\\s*on\\w+\\s*=\\s*[\"'][^\"']*[\"']/gi;\r\nconst JAVASCRIPT_URL_PATTERN = /javascript\\s*:/gi;\r\nconst DATA_URL_PATTERN = /data\\s*:[^;]*;base64/gi;\r\n\r\n/**\r\n * Escapes HTML entities in a string\r\n */\r\nfunction escapeHtml(str: string): string {\r\n return str.replace(HTML_ENTITY_REGEX, (char) => HTML_ENTITIES[char] || char);\r\n}\r\n\r\n/**\r\n * Strips all HTML tags from a string\r\n */\r\nfunction stripHtml(str: string): string {\r\n return str\r\n .replace(SCRIPT_PATTERN, '') // Remove script tags first\r\n .replace(/<[^>]*>/g, '') // Remove all HTML tags\r\n .replace(EVENT_HANDLER_PATTERN, '') // Remove any remaining event handlers\r\n .replace(JAVASCRIPT_URL_PATTERN, '') // Remove javascript: URLs\r\n .replace(DATA_URL_PATTERN, ''); // Remove suspicious data URLs\r\n}\r\n\r\n/**\r\n * Sanitizes HTML while allowing specific tags\r\n */\r\nfunction sanitizeWithAllowList(str: string, allowedTags: string[]): string {\r\n // First, remove dangerous content\r\n let result = str\r\n .replace(SCRIPT_PATTERN, '')\r\n .replace(EVENT_HANDLER_PATTERN, '')\r\n .replace(JAVASCRIPT_URL_PATTERN, '')\r\n .replace(DATA_URL_PATTERN, '');\r\n \r\n // Build regex for allowed tags\r\n if (allowedTags.length === 0) {\r\n return escapeHtml(result);\r\n }\r\n \r\n const allowedPattern = allowedTags.join('|');\r\n const allowedRegex = new RegExp(`<(?!\\/?(?:${allowedPattern})\\\\b)[^>]*>`, 'gi');\r\n \r\n // Remove non-allowed tags\r\n result = result.replace(allowedRegex, '');\r\n \r\n return result;\r\n}\r\n\r\n/**\r\n * Creates a sanitization function based on config\r\n */\r\nexport function createSanitizer(config?: SanitizationConfig) {\r\n const mode = config?.mode ?? 'escape';\r\n const allowedTags = config?.allowedTags ?? [];\r\n const enabled = config?.enabled !== false; // default: true\r\n const skipFields = config?.skipFields ?? [];\r\n\r\n /**\r\n * Sanitizes a single string value\r\n */\r\n function sanitizeString(value: string): string {\r\n if (!enabled) return value;\r\n \r\n switch (mode) {\r\n case 'strip':\r\n return stripHtml(value);\r\n case 'allowList':\r\n return sanitizeWithAllowList(value, allowedTags);\r\n case 'escape':\r\n default:\r\n return escapeHtml(value);\r\n }\r\n }\r\n\r\n /**\r\n * Recursively sanitizes an object, array, or primitive value\r\n */\r\n function sanitizeValue(value: unknown, path: string = ''): unknown {\r\n // Skip fields in skipFields list\r\n if (skipFields.some(field => path.endsWith(field))) {\r\n return value;\r\n }\r\n\r\n // Null/undefined pass through\r\n if (value === null || value === undefined) {\r\n return value;\r\n }\r\n\r\n // Strings get sanitized\r\n if (typeof value === 'string') {\r\n return sanitizeString(value);\r\n }\r\n\r\n // Numbers, booleans pass through\r\n if (typeof value === 'number' || typeof value === 'boolean') {\r\n return value;\r\n }\r\n\r\n // Arrays - sanitize each element\r\n if (Array.isArray(value)) {\r\n return value.map((item, index) => sanitizeValue(item, `${path}[${index}]`));\r\n }\r\n\r\n // Objects - sanitize each property\r\n if (typeof value === 'object') {\r\n const sanitized: Record<string, unknown> = {};\r\n for (const [key, val] of Object.entries(value)) {\r\n const newPath = path ? `${path}.${key}` : key;\r\n sanitized[key] = sanitizeValue(val, newPath);\r\n }\r\n return sanitized;\r\n }\r\n\r\n // Everything else passes through\r\n return value;\r\n }\r\n\r\n /**\r\n * Main sanitize function\r\n */\r\n function sanitize<T>(data: T): T {\r\n if (!enabled) {\r\n return data;\r\n }\r\n return sanitizeValue(data) as T;\r\n }\r\n\r\n /**\r\n * Sanitize FormData values (returns new FormData with sanitized values)\r\n */\r\n function sanitizeFormData(formData: FormData): FormData {\r\n if (!enabled) {\r\n return formData;\r\n }\r\n \r\n const sanitized = new FormData();\r\n \r\n for (const [key, value] of formData.entries()) {\r\n if (value instanceof File) {\r\n // Files pass through unchanged\r\n sanitized.append(key, value);\r\n } else if (typeof value === 'string') {\r\n // Strings get sanitized\r\n sanitized.append(key, sanitizeString(value));\r\n } else {\r\n // Everything else passes through\r\n sanitized.append(key, value);\r\n }\r\n }\r\n \r\n return sanitized;\r\n }\r\n\r\n return {\r\n sanitize,\r\n sanitizeString,\r\n sanitizeValue,\r\n sanitizeFormData,\r\n };\r\n}\r\n\r\nexport type Sanitizer = ReturnType<typeof createSanitizer>;\r\n\r\n/**\r\n * Default sanitizer with escape mode (enabled by default)\r\n */\r\nexport const defaultSanitizer = createSanitizer({\r\n enabled: true,\r\n mode: 'escape',\r\n skipFields: [],\r\n});\r\n\r\n/**\r\n * Quick sanitize function with default config\r\n */\r\nexport function sanitize<T>(data: T): T {\r\n return defaultSanitizer.sanitize(data);\r\n}\r\n\r\n/**\r\n * Quick escape function for single strings\r\n */\r\nexport function escapeString(str: string): string {\r\n return escapeHtml(str);\r\n}\r\n\r\n/**\r\n * Quick strip function for single strings\r\n */\r\nexport function stripString(str: string): string {\r\n return stripHtml(str);\r\n}\r\n","/**\r\n * createApiClient\r\n * Server-side API client for Route Handlers\r\n * \r\n * Makes requests directly to backend with auth token from cookies/headers.\r\n * Returns Response objects that can be directly returned from route handlers.\r\n */\r\n\r\nimport { cookies, headers } from 'next/headers';\r\nimport { createSanitizer } from './sanitize';\r\nimport type { SanitizationConfig, I18nConfig } from '../shared/types';\r\nimport { HEADERS } from '../shared/constants';\r\n\r\n// ==================== Types ====================\r\n\r\nexport interface ApiClientConfig {\r\n /** Backend API base URL */\r\n apiBaseUrl: string;\r\n \r\n /** Cookie names for token retrieval */\r\n cookies: {\r\n user: string;\r\n guest: string;\r\n };\r\n \r\n /** Sanitization options */\r\n sanitization?: SanitizationConfig;\r\n \r\n /** Enable Laravel method spoofing for PUT/PATCH */\r\n methodSpoofing?: boolean;\r\n \r\n /** Custom error messages */\r\n errorMessages?: {\r\n noToken?: string;\r\n connectionError?: string;\r\n };\r\n \r\n /** i18n configuration - auto-append locale to API requests */\r\n i18n?: I18nConfig & {\r\n /** Query parameter name (default: 'lang') */\r\n paramName?: string;\r\n };\r\n}\r\n\r\nexport interface RequestOptions {\r\n /** Form data mode (use FormData, skip Content-Type header) */\r\n isFormData?: boolean;\r\n /** Use method spoofing for this request */\r\n methodSpoofing?: boolean;\r\n /** Skip authentication for this request */\r\n skipAuth?: boolean;\r\n}\r\n\r\nexport interface ApiClient {\r\n get: (endpoint: string) => Promise<Response>;\r\n post: (endpoint: string, body?: Record<string, unknown> | FormData, options?: RequestOptions) => Promise<Response>;\r\n put: (endpoint: string, body?: Record<string, unknown> | FormData, options?: RequestOptions) => Promise<Response>;\r\n patch: (endpoint: string, body?: Record<string, unknown>) => Promise<Response>;\r\n delete: (endpoint: string) => Promise<Response>;\r\n}\r\n\r\n// ==================== Factory ====================\r\n\r\n/**\r\n * Creates a server-side API client for Next.js Route Handlers\r\n * \r\n * @example\r\n * ```ts\r\n * // lib/api.ts\r\n * import { createApiClient } from 'next-api-layer';\r\n * \r\n * export const api = createApiClient({\r\n * apiBaseUrl: process.env.API_BASE_URL!,\r\n * cookies: {\r\n * user: process.env.COOKIE_USER_AUTH_TOKEN_NAME!,\r\n * guest: process.env.COOKIE_PUBLIC_AUTH_TOKEN_NAME!,\r\n * },\r\n * });\r\n * \r\n * // Usage in route handler - direct return!\r\n * export async function GET() {\r\n * return api.get('superadmin/home/list');\r\n * }\r\n * \r\n * export async function POST(request: Request) {\r\n * const body = await request.json();\r\n * return api.post('donations/create', body);\r\n * }\r\n * ```\r\n */\r\nexport function createApiClient(config: ApiClientConfig): ApiClient {\r\n const {\r\n apiBaseUrl,\r\n cookies: cookieNames,\r\n methodSpoofing: globalMethodSpoofing = false,\r\n errorMessages = {},\r\n i18n,\r\n } = config;\r\n \r\n // Ensure baseUrl ends with /\r\n const baseUrl = apiBaseUrl.endsWith('/') ? apiBaseUrl : `${apiBaseUrl}/`;\r\n \r\n // Create sanitizer\r\n const sanitizer = createSanitizer(config.sanitization);\r\n \r\n // Error messages\r\n const noTokenMessage = errorMessages.noToken ?? 'Token bulunamadı. Lütfen giriş yapın.';\r\n const connectionErrorMessage = errorMessages.connectionError ?? 'Bağlantı hatası oluştu.';\r\n\r\n /**\r\n * Get auth token from headers (refreshed) or cookies\r\n */\r\n async function getToken(): Promise<string | null> {\r\n // Check for refreshed token from proxy\r\n const headersList = await headers();\r\n const refreshedToken = headersList.get(HEADERS.REFRESHED_TOKEN);\r\n if (refreshedToken) {\r\n return refreshedToken;\r\n }\r\n \r\n // Get from cookies\r\n const cookieStore = await cookies();\r\n return (\r\n cookieStore.get(cookieNames.user)?.value ||\r\n cookieStore.get(cookieNames.guest)?.value ||\r\n null\r\n );\r\n }\r\n\r\n /**\r\n * Create error response\r\n */\r\n function errorResponse(message: string, status = 500): Response {\r\n return Response.json(\r\n { success: false, message },\r\n { status }\r\n );\r\n }\r\n\r\n /**\r\n * Create no-token response\r\n */\r\n function noTokenResponse(): Response {\r\n return errorResponse(noTokenMessage, 401);\r\n }\r\n\r\n /**\r\n * Make a fetch request to backend\r\n */\r\n async function makeRequest(\r\n method: string,\r\n endpoint: string,\r\n body?: Record<string, unknown> | FormData | null,\r\n options: RequestOptions = {}\r\n ): Promise<Response> {\r\n // Skip auth check if requested\r\n const token = options.skipAuth ? null : await getToken();\r\n \r\n if (!options.skipAuth && !token) {\r\n return noTokenResponse();\r\n }\r\n\r\n try {\r\n const fetchHeaders: HeadersInit = {};\r\n \r\n // Add auth header if we have a token\r\n if (token) {\r\n fetchHeaders['Authorization'] = `Bearer ${token}`;\r\n }\r\n\r\n let fetchBody: string | FormData | undefined;\r\n let actualMethod = method;\r\n\r\n // Handle body\r\n if (body) {\r\n if (options.isFormData && body instanceof FormData) {\r\n // FormData - sanitize and optionally add method spoofing\r\n fetchBody = sanitizer.sanitizeFormData(body);\r\n \r\n const useMethodSpoofing = options.methodSpoofing ?? globalMethodSpoofing;\r\n if (useMethodSpoofing && (method === 'PUT' || method === 'PATCH')) {\r\n (fetchBody as FormData).append('_method', method);\r\n actualMethod = 'POST';\r\n }\r\n } else if (!(body instanceof FormData)) {\r\n // JSON body\r\n fetchHeaders['Content-Type'] = 'application/json';\r\n fetchBody = JSON.stringify(sanitizer.sanitize(body));\r\n }\r\n }\r\n\r\n // Build URL with optional locale parameter\r\n let url = `${baseUrl}${endpoint}`;\r\n if (i18n?.enabled) {\r\n const headersList = await headers();\r\n const locale = headersList.get(HEADERS.LOCALE);\r\n if (locale && (!i18n.locales || i18n.locales.includes(locale))) {\r\n const urlObj = new URL(url);\r\n urlObj.searchParams.set(i18n.paramName || 'lang', locale);\r\n url = urlObj.toString();\r\n }\r\n }\r\n\r\n const res = await fetch(url, {\r\n method: actualMethod,\r\n headers: fetchHeaders,\r\n body: fetchBody,\r\n cache: 'no-store',\r\n });\r\n\r\n // Clone response data (stream can only be read once)\r\n const data = await res.json();\r\n return Response.json(data, { status: res.status });\r\n } catch (error) {\r\n console.error(`API ${method} Error:`, error);\r\n return errorResponse(connectionErrorMessage);\r\n }\r\n }\r\n\r\n // Return API client interface\r\n return {\r\n get: (endpoint: string) => makeRequest('GET', endpoint),\r\n \r\n post: (endpoint: string, body?: Record<string, unknown> | FormData, options?: RequestOptions) =>\r\n makeRequest('POST', endpoint, body, options),\r\n \r\n put: (endpoint: string, body?: Record<string, unknown> | FormData, options?: RequestOptions) =>\r\n makeRequest('PUT', endpoint, body, options),\r\n \r\n patch: (endpoint: string, body?: Record<string, unknown>) =>\r\n makeRequest('PATCH', endpoint, body),\r\n \r\n delete: (endpoint: string) => makeRequest('DELETE', endpoint),\r\n };\r\n}\r\n"]}
|
package/dist/chunk-OXXKU4OM.cjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
'use strict';var chunk6ENVQMWQ_cjs=require('./chunk-6ENVQMWQ.cjs'),headers=require('next/headers');var M={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="},$=/[&<>"'`=/]/g,x=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,F=/\s*on\w+\s*=\s*["'][^"']*["']/gi,D=/javascript\s*:/gi,b=/data\s*:[^;]*;base64/gi;function L(n){return n.replace($,a=>M[a]||a)}function j(n){return n.replace(x,"").replace(/<[^>]*>/g,"").replace(F,"").replace(D,"").replace(b,"")}function q(n,a){let c=n.replace(x,"").replace(F,"").replace(D,"").replace(b,"");if(a.length===0)return L(c);let f=a.join("|"),l=new RegExp(`<(?!/?(?:${f})\\b)[^>]*>`,"gi");return c=c.replace(l,""),c}function z(n){let a=n?.mode??"escape",c=n?.allowedTags??[],f=n?.enabled!==false,l=n?.skipFields??[];function g(e){if(!f)return e;switch(a){case "strip":return j(e);case "allowList":return q(e,c);default:return L(e)}}function d(e,p=""){if(l.some(i=>p.endsWith(i))||e==null)return e;if(typeof e=="string")return g(e);if(typeof e=="number"||typeof e=="boolean")return e;if(Array.isArray(e))return e.map((i,r)=>d(i,`${p}[${r}]`));if(typeof e=="object"){let i={};for(let[r,u]of Object.entries(e)){let t=p?`${p}.${r}`:r;i[r]=d(u,t);}return i}return e}function R(e){return f?d(e):e}function k(e){if(!f)return e;let p=new FormData;for(let[i,r]of e.entries())r instanceof File?p.append(i,r):typeof r=="string"?p.append(i,g(r)):p.append(i,r);return p}return {sanitize:R,sanitizeString:g,sanitizeValue:d,sanitizeFormData:k}}var O=z({enabled:true,mode:"escape",skipFields:[]});function I(n){return O.sanitize(n)}function B(n){let{apiBaseUrl:a,cookies:c,methodSpoofing:f=false,errorMessages:l={},i18n:g}=n,d=a.endsWith("/")?a:`${a}/`,R=z(n.sanitization),k=l.noToken??"Token bulunamad\u0131. L\xFCtfen giri\u015F yap\u0131n.",e=l.connectionError??"Ba\u011Flant\u0131 hatas\u0131 olu\u015Ftu.";async function p(){let o=(await headers.headers()).get(chunk6ENVQMWQ_cjs.e.REFRESHED_TOKEN);if(o)return o;let s=await headers.cookies();return s.get(c.user)?.value||s.get(c.guest)?.value||null}function i(t,o=500){return Response.json({success:false,message:t},{status:o})}function r(){return i(k,401)}async function u(t,o,s,T={}){let h=T.skipAuth?null:await p();if(!T.skipAuth&&!h)return r();try{let m={};h&&(m.Authorization=`Bearer ${h}`);let S,y=t;s&&(T.isFormData&&s instanceof FormData?(S=R.sanitizeFormData(s),(T.methodSpoofing??f)&&(t==="PUT"||t==="PATCH")&&(S.append("_method",t),y="POST")):s instanceof FormData||(m["Content-Type"]="application/json",S=JSON.stringify(R.sanitize(s))));let A=`${d}${o}`;if(g?.enabled){let E=(await headers.headers()).get(chunk6ENVQMWQ_cjs.e.LOCALE);if(E&&(!g.locales||g.locales.includes(E))){let P=new URL(A);P.searchParams.set(g.paramName||"lang",E),A=P.toString();}}let C=await fetch(A,{method:y,headers:m,body:S,cache:"no-store"}),_=await C.json();return Response.json(_,{status:C.status})}catch(m){return console.error(`API ${t} Error:`,m),i(e)}}return {get:t=>u("GET",t),post:(t,o,s)=>u("POST",t,o,s),put:(t,o,s)=>u("PUT",t,o,s),patch:(t,o)=>u("PATCH",t,o),delete:t=>u("DELETE",t)}}exports.a=z;exports.b=O;exports.c=I;exports.d=B;//# sourceMappingURL=chunk-OXXKU4OM.cjs.map
|
|
2
|
-
//# sourceMappingURL=chunk-OXXKU4OM.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/api/sanitize.ts","../src/api/createApiClient.ts"],"names":["HTML_ENTITIES","HTML_ENTITY_REGEX","SCRIPT_PATTERN","EVENT_HANDLER_PATTERN","JAVASCRIPT_URL_PATTERN","DATA_URL_PATTERN","escapeHtml","str","char","stripHtml","sanitizeWithAllowList","allowedTags","result","allowedPattern","allowedRegex","createSanitizer","config","mode","enabled","skipFields","sanitizeString","value","sanitizeValue","path","field","item","index","sanitized","key","val","newPath","sanitize","data","sanitizeFormData","formData","defaultSanitizer","createApiClient","apiBaseUrl","cookieNames","globalMethodSpoofing","errorMessages","i18n","baseUrl","sanitizer","noTokenMessage","connectionErrorMessage","getToken","refreshedToken","headers","HEADERS","cookieStore","cookies","errorResponse","message","status","noTokenResponse","makeRequest","method","endpoint","body","options","token","fetchHeaders","fetchBody","actualMethod","url","locale","urlObj","res","error"],"mappings":"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","file":"chunk-OXXKU4OM.cjs","sourcesContent":["/**\r\n * XSS Sanitization utilities\r\n * Zero-dependency, lightweight sanitizer for API responses\r\n * \r\n * Modes:\r\n * - 'escape' (default): Escapes HTML entities (<script>)\r\n * - 'strip': Removes all HTML tags completely\r\n * - 'allowList': Only allows specified tags (advanced)\r\n */\r\n\r\nimport type { SanitizationConfig } from '../shared/types';\r\n\r\nexport interface SanitizeOptions {\r\n config: SanitizationConfig;\r\n}\r\n\r\n// HTML entities to escape\r\nconst HTML_ENTITIES: Record<string, string> = {\r\n '&': '&',\r\n '<': '<',\r\n '>': '>',\r\n '\"': '"',\r\n \"'\": ''',\r\n '/': '/',\r\n '`': '`',\r\n '=': '=',\r\n};\r\n\r\n// Regex patterns\r\nconst HTML_ENTITY_REGEX = /[&<>\"'`=/]/g;\r\nconst SCRIPT_PATTERN = /<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi;\r\nconst EVENT_HANDLER_PATTERN = /\\s*on\\w+\\s*=\\s*[\"'][^\"']*[\"']/gi;\r\nconst JAVASCRIPT_URL_PATTERN = /javascript\\s*:/gi;\r\nconst DATA_URL_PATTERN = /data\\s*:[^;]*;base64/gi;\r\n\r\n/**\r\n * Escapes HTML entities in a string\r\n */\r\nfunction escapeHtml(str: string): string {\r\n return str.replace(HTML_ENTITY_REGEX, (char) => HTML_ENTITIES[char] || char);\r\n}\r\n\r\n/**\r\n * Strips all HTML tags from a string\r\n */\r\nfunction stripHtml(str: string): string {\r\n return str\r\n .replace(SCRIPT_PATTERN, '') // Remove script tags first\r\n .replace(/<[^>]*>/g, '') // Remove all HTML tags\r\n .replace(EVENT_HANDLER_PATTERN, '') // Remove any remaining event handlers\r\n .replace(JAVASCRIPT_URL_PATTERN, '') // Remove javascript: URLs\r\n .replace(DATA_URL_PATTERN, ''); // Remove suspicious data URLs\r\n}\r\n\r\n/**\r\n * Sanitizes HTML while allowing specific tags\r\n */\r\nfunction sanitizeWithAllowList(str: string, allowedTags: string[]): string {\r\n // First, remove dangerous content\r\n let result = str\r\n .replace(SCRIPT_PATTERN, '')\r\n .replace(EVENT_HANDLER_PATTERN, '')\r\n .replace(JAVASCRIPT_URL_PATTERN, '')\r\n .replace(DATA_URL_PATTERN, '');\r\n \r\n // Build regex for allowed tags\r\n if (allowedTags.length === 0) {\r\n return escapeHtml(result);\r\n }\r\n \r\n const allowedPattern = allowedTags.join('|');\r\n const allowedRegex = new RegExp(`<(?!\\/?(?:${allowedPattern})\\\\b)[^>]*>`, 'gi');\r\n \r\n // Remove non-allowed tags\r\n result = result.replace(allowedRegex, '');\r\n \r\n return result;\r\n}\r\n\r\n/**\r\n * Creates a sanitization function based on config\r\n */\r\nexport function createSanitizer(config?: SanitizationConfig) {\r\n const mode = config?.mode ?? 'escape';\r\n const allowedTags = config?.allowedTags ?? [];\r\n const enabled = config?.enabled !== false; // default: true\r\n const skipFields = config?.skipFields ?? [];\r\n\r\n /**\r\n * Sanitizes a single string value\r\n */\r\n function sanitizeString(value: string): string {\r\n if (!enabled) return value;\r\n \r\n switch (mode) {\r\n case 'strip':\r\n return stripHtml(value);\r\n case 'allowList':\r\n return sanitizeWithAllowList(value, allowedTags);\r\n case 'escape':\r\n default:\r\n return escapeHtml(value);\r\n }\r\n }\r\n\r\n /**\r\n * Recursively sanitizes an object, array, or primitive value\r\n */\r\n function sanitizeValue(value: unknown, path: string = ''): unknown {\r\n // Skip fields in skipFields list\r\n if (skipFields.some(field => path.endsWith(field))) {\r\n return value;\r\n }\r\n\r\n // Null/undefined pass through\r\n if (value === null || value === undefined) {\r\n return value;\r\n }\r\n\r\n // Strings get sanitized\r\n if (typeof value === 'string') {\r\n return sanitizeString(value);\r\n }\r\n\r\n // Numbers, booleans pass through\r\n if (typeof value === 'number' || typeof value === 'boolean') {\r\n return value;\r\n }\r\n\r\n // Arrays - sanitize each element\r\n if (Array.isArray(value)) {\r\n return value.map((item, index) => sanitizeValue(item, `${path}[${index}]`));\r\n }\r\n\r\n // Objects - sanitize each property\r\n if (typeof value === 'object') {\r\n const sanitized: Record<string, unknown> = {};\r\n for (const [key, val] of Object.entries(value)) {\r\n const newPath = path ? `${path}.${key}` : key;\r\n sanitized[key] = sanitizeValue(val, newPath);\r\n }\r\n return sanitized;\r\n }\r\n\r\n // Everything else passes through\r\n return value;\r\n }\r\n\r\n /**\r\n * Main sanitize function\r\n */\r\n function sanitize<T>(data: T): T {\r\n if (!enabled) {\r\n return data;\r\n }\r\n return sanitizeValue(data) as T;\r\n }\r\n\r\n /**\r\n * Sanitize FormData values (returns new FormData with sanitized values)\r\n */\r\n function sanitizeFormData(formData: FormData): FormData {\r\n if (!enabled) {\r\n return formData;\r\n }\r\n \r\n const sanitized = new FormData();\r\n \r\n for (const [key, value] of formData.entries()) {\r\n if (value instanceof File) {\r\n // Files pass through unchanged\r\n sanitized.append(key, value);\r\n } else if (typeof value === 'string') {\r\n // Strings get sanitized\r\n sanitized.append(key, sanitizeString(value));\r\n } else {\r\n // Everything else passes through\r\n sanitized.append(key, value);\r\n }\r\n }\r\n \r\n return sanitized;\r\n }\r\n\r\n return {\r\n sanitize,\r\n sanitizeString,\r\n sanitizeValue,\r\n sanitizeFormData,\r\n };\r\n}\r\n\r\nexport type Sanitizer = ReturnType<typeof createSanitizer>;\r\n\r\n/**\r\n * Default sanitizer with escape mode (enabled by default)\r\n */\r\nexport const defaultSanitizer = createSanitizer({\r\n enabled: true,\r\n mode: 'escape',\r\n skipFields: [],\r\n});\r\n\r\n/**\r\n * Quick sanitize function with default config\r\n */\r\nexport function sanitize<T>(data: T): T {\r\n return defaultSanitizer.sanitize(data);\r\n}\r\n\r\n/**\r\n * Quick escape function for single strings\r\n */\r\nexport function escapeString(str: string): string {\r\n return escapeHtml(str);\r\n}\r\n\r\n/**\r\n * Quick strip function for single strings\r\n */\r\nexport function stripString(str: string): string {\r\n return stripHtml(str);\r\n}\r\n","/**\r\n * createApiClient\r\n * Server-side API client for Route Handlers\r\n * \r\n * Makes requests directly to backend with auth token from cookies/headers.\r\n * Returns Response objects that can be directly returned from route handlers.\r\n */\r\n\r\nimport { cookies, headers } from 'next/headers';\r\nimport { createSanitizer } from './sanitize';\r\nimport type { SanitizationConfig, I18nConfig } from '../shared/types';\r\nimport { HEADERS } from '../shared/constants';\r\n\r\n// ==================== Types ====================\r\n\r\nexport interface ApiClientConfig {\r\n /** Backend API base URL */\r\n apiBaseUrl: string;\r\n \r\n /** Cookie names for token retrieval */\r\n cookies: {\r\n user: string;\r\n guest: string;\r\n };\r\n \r\n /** Sanitization options */\r\n sanitization?: SanitizationConfig;\r\n \r\n /** Enable Laravel method spoofing for PUT/PATCH */\r\n methodSpoofing?: boolean;\r\n \r\n /** Custom error messages */\r\n errorMessages?: {\r\n noToken?: string;\r\n connectionError?: string;\r\n };\r\n \r\n /** i18n configuration - auto-append locale to API requests */\r\n i18n?: I18nConfig & {\r\n /** Query parameter name (default: 'lang') */\r\n paramName?: string;\r\n };\r\n}\r\n\r\nexport interface RequestOptions {\r\n /** Form data mode (use FormData, skip Content-Type header) */\r\n isFormData?: boolean;\r\n /** Use method spoofing for this request */\r\n methodSpoofing?: boolean;\r\n /** Skip authentication for this request */\r\n skipAuth?: boolean;\r\n}\r\n\r\nexport interface ApiClient {\r\n get: (endpoint: string) => Promise<Response>;\r\n post: (endpoint: string, body?: Record<string, unknown> | FormData, options?: RequestOptions) => Promise<Response>;\r\n put: (endpoint: string, body?: Record<string, unknown> | FormData, options?: RequestOptions) => Promise<Response>;\r\n patch: (endpoint: string, body?: Record<string, unknown>) => Promise<Response>;\r\n delete: (endpoint: string) => Promise<Response>;\r\n}\r\n\r\n// ==================== Factory ====================\r\n\r\n/**\r\n * Creates a server-side API client for Next.js Route Handlers\r\n * \r\n * @example\r\n * ```ts\r\n * // lib/api.ts\r\n * import { createApiClient } from 'next-api-layer';\r\n * \r\n * export const api = createApiClient({\r\n * apiBaseUrl: process.env.API_BASE_URL!,\r\n * cookies: {\r\n * user: process.env.COOKIE_USER_AUTH_TOKEN_NAME!,\r\n * guest: process.env.COOKIE_PUBLIC_AUTH_TOKEN_NAME!,\r\n * },\r\n * });\r\n * \r\n * // Usage in route handler - direct return!\r\n * export async function GET() {\r\n * return api.get('superadmin/home/list');\r\n * }\r\n * \r\n * export async function POST(request: Request) {\r\n * const body = await request.json();\r\n * return api.post('donations/create', body);\r\n * }\r\n * ```\r\n */\r\nexport function createApiClient(config: ApiClientConfig): ApiClient {\r\n const {\r\n apiBaseUrl,\r\n cookies: cookieNames,\r\n methodSpoofing: globalMethodSpoofing = false,\r\n errorMessages = {},\r\n i18n,\r\n } = config;\r\n \r\n // Ensure baseUrl ends with /\r\n const baseUrl = apiBaseUrl.endsWith('/') ? apiBaseUrl : `${apiBaseUrl}/`;\r\n \r\n // Create sanitizer\r\n const sanitizer = createSanitizer(config.sanitization);\r\n \r\n // Error messages\r\n const noTokenMessage = errorMessages.noToken ?? 'Token bulunamadı. Lütfen giriş yapın.';\r\n const connectionErrorMessage = errorMessages.connectionError ?? 'Bağlantı hatası oluştu.';\r\n\r\n /**\r\n * Get auth token from headers (refreshed) or cookies\r\n */\r\n async function getToken(): Promise<string | null> {\r\n // Check for refreshed token from proxy\r\n const headersList = await headers();\r\n const refreshedToken = headersList.get(HEADERS.REFRESHED_TOKEN);\r\n if (refreshedToken) {\r\n return refreshedToken;\r\n }\r\n \r\n // Get from cookies\r\n const cookieStore = await cookies();\r\n return (\r\n cookieStore.get(cookieNames.user)?.value ||\r\n cookieStore.get(cookieNames.guest)?.value ||\r\n null\r\n );\r\n }\r\n\r\n /**\r\n * Create error response\r\n */\r\n function errorResponse(message: string, status = 500): Response {\r\n return Response.json(\r\n { success: false, message },\r\n { status }\r\n );\r\n }\r\n\r\n /**\r\n * Create no-token response\r\n */\r\n function noTokenResponse(): Response {\r\n return errorResponse(noTokenMessage, 401);\r\n }\r\n\r\n /**\r\n * Make a fetch request to backend\r\n */\r\n async function makeRequest(\r\n method: string,\r\n endpoint: string,\r\n body?: Record<string, unknown> | FormData | null,\r\n options: RequestOptions = {}\r\n ): Promise<Response> {\r\n // Skip auth check if requested\r\n const token = options.skipAuth ? null : await getToken();\r\n \r\n if (!options.skipAuth && !token) {\r\n return noTokenResponse();\r\n }\r\n\r\n try {\r\n const fetchHeaders: HeadersInit = {};\r\n \r\n // Add auth header if we have a token\r\n if (token) {\r\n fetchHeaders['Authorization'] = `Bearer ${token}`;\r\n }\r\n\r\n let fetchBody: string | FormData | undefined;\r\n let actualMethod = method;\r\n\r\n // Handle body\r\n if (body) {\r\n if (options.isFormData && body instanceof FormData) {\r\n // FormData - sanitize and optionally add method spoofing\r\n fetchBody = sanitizer.sanitizeFormData(body);\r\n \r\n const useMethodSpoofing = options.methodSpoofing ?? globalMethodSpoofing;\r\n if (useMethodSpoofing && (method === 'PUT' || method === 'PATCH')) {\r\n (fetchBody as FormData).append('_method', method);\r\n actualMethod = 'POST';\r\n }\r\n } else if (!(body instanceof FormData)) {\r\n // JSON body\r\n fetchHeaders['Content-Type'] = 'application/json';\r\n fetchBody = JSON.stringify(sanitizer.sanitize(body));\r\n }\r\n }\r\n\r\n // Build URL with optional locale parameter\r\n let url = `${baseUrl}${endpoint}`;\r\n if (i18n?.enabled) {\r\n const headersList = await headers();\r\n const locale = headersList.get(HEADERS.LOCALE);\r\n if (locale && (!i18n.locales || i18n.locales.includes(locale))) {\r\n const urlObj = new URL(url);\r\n urlObj.searchParams.set(i18n.paramName || 'lang', locale);\r\n url = urlObj.toString();\r\n }\r\n }\r\n\r\n const res = await fetch(url, {\r\n method: actualMethod,\r\n headers: fetchHeaders,\r\n body: fetchBody,\r\n cache: 'no-store',\r\n });\r\n\r\n // Clone response data (stream can only be read once)\r\n const data = await res.json();\r\n return Response.json(data, { status: res.status });\r\n } catch (error) {\r\n console.error(`API ${method} Error:`, error);\r\n return errorResponse(connectionErrorMessage);\r\n }\r\n }\r\n\r\n // Return API client interface\r\n return {\r\n get: (endpoint: string) => makeRequest('GET', endpoint),\r\n \r\n post: (endpoint: string, body?: Record<string, unknown> | FormData, options?: RequestOptions) =>\r\n makeRequest('POST', endpoint, body, options),\r\n \r\n put: (endpoint: string, body?: Record<string, unknown> | FormData, options?: RequestOptions) =>\r\n makeRequest('PUT', endpoint, body, options),\r\n \r\n patch: (endpoint: string, body?: Record<string, unknown>) =>\r\n makeRequest('PATCH', endpoint, body),\r\n \r\n delete: (endpoint: string) => makeRequest('DELETE', endpoint),\r\n };\r\n}\r\n"]}
|