New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

@mints/request

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@mints/request - npm Package Compare versions

Comparing version
2.0.0
to
2.1.0
+24
-0
CHANGELOG.md
# Changelog
## [2.1.0] - 2025-08-25
⚠️ **Note:** version `2.0.0` was essentially broken due to severe bugs.
Upgrade to `2.1.0` immediately.
### ✨ Features
- Added `login()` and `logout()` helpers to manage tokens automatically.
- Added `init()` and `reset()` methods to `request` for probe/reset flows.
- Added `tokenField` option in `createCookieStrategy` and `createTokenStrategy`.
- Added default handling for HTTP `419` / `440`.
### 🐛 Fixes
- Fixed missing `storage` export.
- Fixed infinite loop in `ensureRefreshed` (refresh never exited).
- Fixed `mountedRef.current` not reset (broke `useRequest` under React Strict Mode).
### 🛠 Refactors
- Removed `isAccessTokenValid` param from `AuthStrategy` (backend decides validity).
- Removed `useRequest` throwing on cancellation errors (`AbortError`, `ERR_CANCELED`, `CanceledError`).
- Internally refactored `useRequest` to rely on `status` instead of `loading`.
## [2.0.0] - 2025-08-22

@@ -4,0 +28,0 @@

+90
-31

@@ -36,2 +36,6 @@ "use strict";

getGlobalRequestConfig: () => getGlobalRequestConfig,
localStorageStorage: () => localStorageStorage,
login: () => login,
logout: () => logout,
memoryStorage: () => memoryStorage,
operator: () => operator,

@@ -50,3 +54,3 @@ request: () => request,

retryAfterRefresh: 1,
shouldRefreshOnStatus: (s) => s === 401
shouldRefreshOnStatus: (s) => s === 401 || s === 419 || s === 440
};

@@ -87,5 +91,3 @@ var setupRequest = (config) => {

} finally {
const p = refreshPromise;
refreshPromise = null;
await (p == null ? void 0 : p.catch(() => void 0));
}

@@ -117,3 +119,3 @@ })();

async (error) => {
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
var _a, _b, _c, _d, _e, _f, _g;
const global = getGlobalRequestConfig();

@@ -127,5 +129,2 @@ const cfg = error.config || {};

}
if ((_e = (_d = global.auth).isAccessTokenValid) == null ? void 0 : _e.call(_d)) {
return Promise.reject(error);
}
try {

@@ -136,5 +135,5 @@ await ensureRefreshed(cfg.signal);

} catch (refreshErr) {
(_g = (_f = global.auth).onRefreshFailed) == null ? void 0 : _g.call(_f, refreshErr);
if (!((_h = cfg.meta) == null ? void 0 : _h.skipUnauthorizedHandler)) {
(_i = global.onUnauthorized) == null ? void 0 : _i.call(global);
(_e = (_d = global.auth).onRefreshFailed) == null ? void 0 : _e.call(_d, refreshErr);
if (!((_f = cfg.meta) == null ? void 0 : _f.skipUnauthorizedHandler)) {
(_g = global.onUnauthorized) == null ? void 0 : _g.call(global);
}

@@ -176,2 +175,36 @@ return Promise.reject(error);

};
var didInitSoftRefresh = false;
async function probe(url, config) {
return request.auth(url, {
...config,
noRefresh: true,
meta: {
...(config == null ? void 0 : config.meta) || {},
skipUnauthorizedHandler: true
}
});
}
request.init = async function(url, config) {
var _a;
try {
return await probe(url, config);
} catch (e) {
const soft = (_a = config == null ? void 0 : config.soft) != null ? _a : true;
if (!soft || didInitSoftRefresh)
return null;
const auth = getGlobalRequestConfig().auth;
if (!auth)
return null;
try {
await auth.refresh(config == null ? void 0 : config.signal);
didInitSoftRefresh = true;
return await probe(url, config);
} catch (e2) {
return null;
}
}
};
request.reset = function() {
didInitSoftRefresh = false;
};

@@ -289,16 +322,6 @@ // src/core/operator.ts

}
function isJwtValid(t, leewaySec = 30) {
if (!t)
return false;
const [, payload] = t.split(".");
try {
const { exp } = JSON.parse(atob(payload));
return typeof exp === "number" && Date.now() / 1e3 < exp - leewaySec;
} catch (e) {
return false;
}
}
function createCookieStrategy(opts) {
var _a, _b;
const storage = (_a = opts.storage) != null ? _a : memoryStorage;
const accessKey = (_b = opts == null ? void 0 : opts.tokenField) != null ? _b : "access_token";
return {

@@ -308,3 +331,2 @@ addAuthToRequest(config) {

},
isAccessTokenValid: (_b = opts.isTokenValid) != null ? _b : () => isJwtValid(storage.getAccessToken()),
async refresh(signal) {

@@ -323,4 +345,4 @@ const res = await fetch(opts.refreshPath, {

const json = await res.json();
if (json == null ? void 0 : json.access_token) {
storage.setAccessToken(json.access_token);
if (json == null ? void 0 : json[accessKey]) {
storage.setAccessToken(json[accessKey]);
}

@@ -330,5 +352,13 @@ } catch (e) {

},
onRefreshFailed(reason) {
setToken({ accessToken, refreshToken }) {
var _a2;
if (accessToken)
storage.setAccessToken(accessToken);
if (refreshToken)
(_a2 = storage.setRefreshToken) == null ? void 0 : _a2.call(storage, refreshToken);
},
clearToken() {
var _a2;
storage.setAccessToken(null);
console.warn("Refresh failed", reason);
(_a2 = storage.setRefreshToken) == null ? void 0 : _a2.call(storage, null);
}

@@ -340,2 +370,3 @@ };

const storage = (_a = opts.storage) != null ? _a : localStorageStorage;
const accessKey = (_b = opts == null ? void 0 : opts.tokenField) != null ? _b : "access_token";
return {

@@ -345,3 +376,2 @@ addAuthToRequest(config) {

},
isAccessTokenValid: (_b = opts.isTokenValid) != null ? _b : () => isJwtValid(storage.getAccessToken()),
async refresh(signal) {

@@ -364,16 +394,41 @@ var _a2, _b2;

const json = await res.json();
if (!(json == null ? void 0 : json.access_token))
if (!(json == null ? void 0 : json[accessKey]))
throw new Error("Malformed refresh response");
storage.setAccessToken(json.access_token);
storage.setAccessToken(json[accessKey]);
if (json.refresh_token)
(_b2 = storage.setRefreshToken) == null ? void 0 : _b2.call(storage, json.refresh_token);
},
onRefreshFailed(reason) {
setToken({ accessToken, refreshToken }) {
var _a2;
if (accessToken)
storage.setAccessToken(accessToken);
if (refreshToken)
(_a2 = storage.setRefreshToken) == null ? void 0 : _a2.call(storage, refreshToken);
},
clearToken() {
var _a2;
storage.setAccessToken(null);
(_a2 = storage.setRefreshToken) == null ? void 0 : _a2.call(storage, null);
console.warn("Refresh failed", reason);
}
};
}
// src/core/auth-helper.ts
async function login(perform) {
var _a;
const auth = getGlobalRequestConfig().auth;
const json = await perform();
(_a = auth == null ? void 0 : auth.setToken) == null ? void 0 : _a.call(auth, json);
return json;
}
async function logout(perform) {
var _a;
const auth = getGlobalRequestConfig().auth;
try {
if (perform)
await perform();
} finally {
(_a = auth == null ? void 0 : auth.clearToken) == null ? void 0 : _a.call(auth);
}
}
// Annotate the CommonJS export names for ESM import in node:

@@ -384,2 +439,6 @@ 0 && (module.exports = {

getGlobalRequestConfig,
localStorageStorage,
login,
logout,
memoryStorage,
operator,

@@ -386,0 +445,0 @@ request,

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/core/index.ts","../src/core/request.ts","../src/core/config.ts","../src/core/operator.ts","../src/core/auth.ts","../src/core/storage.ts"],"sourcesContent":["export { request } from './request';\nexport {\n setupRequest,\n updateRequestConfig,\n getGlobalRequestConfig,\n type AuthStrategy,\n type GlobalRequestConfig,\n} from './config';\nexport { operator, type OperateConfig } from './operator';\nexport { createCookieStrategy, createTokenStrategy } from './auth';\n","import axios, {\n AxiosHeaders,\n type InternalAxiosRequestConfig,\n type AxiosError,\n type AxiosRequestConfig,\n type AxiosResponse,\n} from 'axios';\n\nimport { getGlobalRequestConfig } from './config';\n\n/** Per-request behavior toggles */\nexport type RequestMeta = {\n /** Do not attach credentials (skip strategy.addAuthToRequest) */\n skipAuth?: boolean;\n /** Do not attempt refresh on 401/419 */\n skipRefresh?: boolean;\n /** Do not call global onUnauthorized when unauthorized */\n skipUnauthorizedHandler?: boolean;\n /** Internal guard to avoid infinite retry loops */\n _retried?: number;\n};\n\n// Axios module augmentation to allow config.meta\ndeclare module 'axios' {\n export interface AxiosRequestConfig {\n meta?: RequestMeta;\n }\n}\n\nconst instance = axios.create();\n\n// ---- request interceptor: baseURL, headers, auth attachment ----\ninstance.interceptors.request.use((config: InternalAxiosRequestConfig) => {\n const global = getGlobalRequestConfig();\n\n // Merge headers (defaultHeaders first so explicit config wins)\n const mergedHeaders = {\n ...(global.defaultHeaders?.() || {}),\n ...(config.headers || {}),\n };\n\n config.headers = AxiosHeaders.from(mergedHeaders);\n config.baseURL = config.baseURL || global.baseURL || '/api';\n\n // Attach Authorization (or other credentials) if strategy is present and not skipped\n if (!config.meta?.skipAuth && global.auth) {\n config = global.auth.addAuthToRequest(config);\n }\n\n return config;\n});\n\n// ---- refresh de-duplication ----\nlet refreshPromise: Promise<void> | null = null;\n\nasync function ensureRefreshed(signal?: AbortSignal) {\n const { auth } = getGlobalRequestConfig();\n if (!auth) return;\n\n if (!refreshPromise) {\n refreshPromise = (async () => {\n try {\n await auth.refresh(signal);\n } finally {\n // Reset promise regardless of success/failure\n const p = refreshPromise;\n refreshPromise = null;\n await (p as Promise<void> | null)?.catch(() => undefined);\n }\n })();\n }\n return refreshPromise;\n}\n\nfunction shouldAttemptRefresh(error: AxiosError): boolean {\n const { shouldRefreshOnStatus } = getGlobalRequestConfig();\n const status = error.response?.status;\n return typeof status === 'number' && !!shouldRefreshOnStatus?.(status);\n}\n\nasync function retryOnce<T>(\n original: InternalAxiosRequestConfig,\n): Promise<AxiosResponse<T>> {\n const global = getGlobalRequestConfig();\n const retryMax = Math.max(1, global.retryAfterRefresh ?? 1);\n\n const meta = original.meta || (original.meta = {});\n const count = meta._retried ?? 0;\n\n if (count >= retryMax) {\n throw new Error('Max retries after refresh exceeded');\n }\n\n meta._retried = count + 1;\n return instance.request<T>(original);\n}\n\n// ---- response interceptor: 401 -> refresh -> retry ----\ninstance.interceptors.response.use(\n (res) => res,\n async (error: AxiosError) => {\n const global = getGlobalRequestConfig();\n const cfg = (error.config || {}) as InternalAxiosRequestConfig;\n\n // If no strategy or refresh is skipped, do not handle here\n if (cfg.meta?.skipRefresh || !global.auth || !shouldAttemptRefresh(error)) {\n if (shouldAttemptRefresh(error) && !cfg.meta?.skipUnauthorizedHandler) {\n global.onUnauthorized?.();\n }\n return Promise.reject(error);\n }\n\n // Optional proactive validity check (if provided)\n if (global.auth.isAccessTokenValid?.()) {\n // Token claims still \"valid\" but server says unauthorized -> bubble up\n return Promise.reject(error);\n }\n\n try {\n await ensureRefreshed(cfg.signal as AbortSignal | undefined);\n const retried = await retryOnce(cfg);\n return retried;\n } catch (refreshErr) {\n global.auth.onRefreshFailed?.(refreshErr);\n if (!cfg.meta?.skipUnauthorizedHandler) {\n global.onUnauthorized?.();\n }\n return Promise.reject(error);\n }\n },\n);\n\n// ---- public/auth helpers on top of base request() ----\n\ntype CredentialsMode = 'auto' | 'always' | 'never';\n\nexport type PublicOptions = { credentials?: CredentialsMode };\nexport type AuthOptions = {\n noRefresh?: boolean;\n credentials?: CredentialsMode;\n};\n\n// Core callable function (default = public)\nexport type RequestFn = <T = unknown>(\n url: string,\n config?: AxiosRequestConfig,\n) => Promise<T>;\n\nasync function baseRequest<T = unknown>(\n url: string,\n config?: AxiosRequestConfig,\n): Promise<T> {\n const res = await instance.request<T>({ url, ...config });\n return res.data;\n}\n\n/**\n * The exported request is both callable and has .public/.auth shortcuts.\n * Calling request(url, config) equals request.public(url, config).\n */\nconst request = ((url: string, config?: AxiosRequestConfig) => {\n return request.public(url, config);\n}) as RequestFn & {\n public: <T = unknown>(\n url: string,\n config?: AxiosRequestConfig & PublicOptions,\n ) => Promise<T>;\n auth: <T = unknown>(\n url: string,\n config?: AxiosRequestConfig & AuthOptions,\n ) => Promise<T>;\n};\n\nrequest.public = async function <T = unknown>(\n url: string,\n config?: AxiosRequestConfig & PublicOptions,\n): Promise<T> {\n const withCredentials = config?.credentials === 'always' ? true : undefined;\n return baseRequest<T>(url, {\n ...config,\n withCredentials,\n meta: {\n ...(config?.meta || {}),\n skipAuth: true,\n skipRefresh: true,\n skipUnauthorizedHandler: true,\n },\n });\n};\n\nrequest.auth = async function <T = unknown>(\n url: string,\n config?: AxiosRequestConfig & AuthOptions,\n): Promise<T> {\n const withCredentials = config?.credentials === 'always' ? true : undefined;\n return baseRequest<T>(url, {\n ...config,\n withCredentials,\n meta: {\n ...(config?.meta || {}),\n ...(config?.noRefresh ? { skipRefresh: true } : {}),\n },\n });\n};\n\nexport { request };\nexport type { AxiosRequestConfig } from 'axios';\n","import type { AxiosRequestConfig, InternalAxiosRequestConfig } from 'axios';\n\nexport type ToastFn = (msg: string) => void;\n\nexport interface AuthStrategy {\n /** Attach credentials (e.g., Authorization header) */\n addAuthToRequest: <T extends AxiosRequestConfig | InternalAxiosRequestConfig>(\n config: T,\n ) => T;\n\n /** Optional: return true if access token is still valid */\n isAccessTokenValid?: () => boolean;\n\n /** Refresh credentials; may rely on http-only cookie or token exchange */\n refresh: (signal?: AbortSignal) => Promise<void>;\n\n /** Optional: called when refresh ultimately fails */\n onRefreshFailed?: (reason: unknown) => void;\n}\n\nexport interface GlobalRequestConfig {\n toast?: {\n success?: ToastFn;\n error?: ToastFn;\n };\n baseURL?: string;\n defaultHeaders?: () => Record<string, string>;\n onUnauthorized?: () => void;\n\n /** Pluggable authentication behavior */\n auth?: AuthStrategy;\n\n /** Max retries after a successful refresh (default: 1) */\n retryAfterRefresh?: number;\n\n /** Status codes that should trigger a refresh attempt (default: 401) */\n shouldRefreshOnStatus?: (status: number) => boolean;\n}\n\nconst globalConfig: GlobalRequestConfig = {\n retryAfterRefresh: 1,\n shouldRefreshOnStatus: (s) => s === 401,\n};\n\nexport const setupRequest = (config: GlobalRequestConfig) => {\n Object.assign(globalConfig, config);\n};\n\nexport const updateRequestConfig = (patch: Partial<GlobalRequestConfig>) => {\n Object.assign(globalConfig, patch);\n};\n\nexport const getGlobalRequestConfig = () => globalConfig;\n","import axios, { type AxiosError } from 'axios';\n\nimport { getGlobalRequestConfig, type ToastFn } from './config';\n\nexport type OperateConfig<E> = {\n setOperating?: (loading: boolean) => void;\n formatMessage?: () => string;\n formatReason?: (err: E) => string;\n hideToast?: boolean;\n toast?: {\n success?: ToastFn;\n error?: ToastFn;\n };\n};\n\ntype ApiErrorBody = {\n message?: string;\n error?: string;\n detail?: string;\n errors?: string | string[];\n};\n\nfunction extractAxiosMessage(err: AxiosError<ApiErrorBody>): string {\n const data = err.response?.data;\n\n if (typeof data === 'string') return data;\n\n if (data && typeof data === 'object') {\n const { message, error, detail, errors } = data;\n const merged =\n message ??\n error ??\n detail ??\n (Array.isArray(errors) ? errors.join(', ') : errors);\n if (merged) return merged;\n }\n\n return err.message || 'Unknown error';\n}\n\nexport async function operator<T, E = unknown>(\n request: () => Promise<T>,\n config: OperateConfig<E> = {},\n): Promise<[true, T?] | [false, E?]> {\n const global = getGlobalRequestConfig();\n const {\n setOperating,\n formatMessage,\n formatReason = (err: E) => {\n if (axios.isAxiosError<ApiErrorBody>(err)) {\n return extractAxiosMessage(err);\n }\n if (err instanceof Error) return err.message;\n return String(err ?? 'Unknown error');\n },\n hideToast,\n toast: localToast,\n } = config;\n\n const toast = localToast ?? global.toast;\n\n try {\n setOperating?.(true);\n const res = await request();\n if (!hideToast) toast?.success?.(formatMessage?.() ?? 'Success');\n return [true, res];\n } catch (err) {\n const typed = err as E;\n if (!hideToast) toast?.error?.(formatReason(typed));\n return [false, typed];\n } finally {\n setOperating?.(false);\n }\n}\n","import { AxiosHeaders, type AxiosRequestConfig } from 'axios';\n\nimport type { AuthStrategy } from './config';\nimport {\n memoryStorage,\n localStorageStorage,\n type TokenStorage,\n} from './storage';\n\nfunction addAuthHeader<T extends AxiosRequestConfig>(\n config: T,\n token: string | null,\n): T {\n if (token) {\n config.headers = AxiosHeaders.from({\n ...(config.headers || {}),\n Authorization: `Bearer ${token}`,\n });\n }\n return config;\n}\n\nfunction isJwtValid(t: string | null, leewaySec = 30) {\n if (!t) return false;\n const [, payload] = t.split('.');\n try {\n const { exp } = JSON.parse(atob(payload));\n return typeof exp === 'number' && Date.now() / 1000 < exp - leewaySec;\n } catch {\n return false;\n }\n}\n\n/**\n * Cookie-based strategy:\n * - Access token lives in app state (memory/storage).\n * - Refresh relies on http-only cookie via a server endpoint.\n */\nexport function createCookieStrategy(opts: {\n storage?: TokenStorage;\n refreshPath: string; // e.g., '/auth/refresh'\n isTokenValid?: () => boolean;\n}): AuthStrategy {\n const storage = opts.storage ?? memoryStorage;\n\n return {\n addAuthToRequest<T extends AxiosRequestConfig>(config: T): T {\n return addAuthHeader(config, storage.getAccessToken());\n },\n isAccessTokenValid:\n opts.isTokenValid ?? (() => isJwtValid(storage.getAccessToken())),\n async refresh(signal?: AbortSignal) {\n const res = await fetch(opts.refreshPath, {\n method: 'POST',\n credentials: 'include',\n headers: {\n Accept: 'application/json',\n },\n signal,\n });\n if (!res.ok) throw new Error(`Refresh failed: ${res.status}`);\n try {\n const json = await res.json();\n if (json?.access_token) {\n storage.setAccessToken(json.access_token);\n }\n } catch {\n // Some backends may not return JSON; cookie-only session is fine.\n }\n },\n onRefreshFailed(reason) {\n storage.setAccessToken(null);\n console.warn('Refresh failed', reason);\n },\n };\n}\n\n/**\n * Token-exchange strategy:\n * - Both access and refresh tokens are readable by JS (NOT http-only).\n */\nexport function createTokenStrategy(opts: {\n storage?: TokenStorage;\n refreshPath: string;\n isTokenValid?: () => boolean;\n}): AuthStrategy {\n const storage = opts.storage ?? localStorageStorage;\n\n return {\n addAuthToRequest<T extends AxiosRequestConfig>(config: T): T {\n return addAuthHeader(config, storage.getAccessToken());\n },\n isAccessTokenValid:\n opts.isTokenValid ?? (() => isJwtValid(storage.getAccessToken())),\n async refresh(signal?: AbortSignal) {\n const rt = storage.getRefreshToken?.();\n if (!rt) throw new Error('No refresh token');\n const res = await fetch(opts.refreshPath, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n },\n body: JSON.stringify({ refresh_token: rt }),\n signal,\n });\n if (!res.ok) throw new Error(`Refresh failed: ${res.status}`);\n const json = await res.json();\n if (!json?.access_token) throw new Error('Malformed refresh response');\n storage.setAccessToken(json.access_token);\n if (json.refresh_token) storage.setRefreshToken?.(json.refresh_token);\n },\n onRefreshFailed(reason) {\n storage.setAccessToken(null);\n storage.setRefreshToken?.(null);\n console.warn('Refresh failed', reason);\n },\n };\n}\n","export interface TokenStorage {\n getAccessToken(): string | null;\n setAccessToken(token: string | null): void;\n getRefreshToken?(): string | null;\n setRefreshToken?(token: string | null): void;\n}\n\nexport const memoryStorage: TokenStorage = (() => {\n let access: string | null = null;\n let refresh: string | null = null;\n return {\n getAccessToken: () => access,\n setAccessToken: (t) => (access = t),\n getRefreshToken: () => refresh,\n setRefreshToken: (t) => (refresh = t),\n };\n})();\n\nconst safeLocal = () => {\n try {\n return typeof window !== 'undefined' ? window.localStorage : null;\n } catch {\n return null;\n }\n};\n\nexport const localStorageStorage: TokenStorage = {\n getAccessToken: () => safeLocal()?.getItem('access_token') ?? null,\n setAccessToken: (t) => {\n const ls = safeLocal();\n if (!ls) return;\n if (t) {\n ls.setItem('access_token', t);\n } else {\n ls.removeItem('access_token');\n }\n },\n getRefreshToken: () => safeLocal()?.getItem('refresh_token') ?? null,\n setRefreshToken: (t) => {\n const ls = safeLocal();\n if (!ls) return;\n if (t) {\n ls.setItem('refresh_token', t);\n } else {\n ls.removeItem('refresh_token');\n }\n },\n};\n"],"mappings":"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","names":["axios","import_axios","request","axios","import_axios","_a","_b"]}
{"version":3,"sources":["../src/core/index.ts","../src/core/request.ts","../src/core/config.ts","../src/core/operator.ts","../src/core/auth.ts","../src/core/storage.ts","../src/core/auth-helper.ts"],"sourcesContent":["export { request } from './request';\nexport {\n setupRequest,\n updateRequestConfig,\n getGlobalRequestConfig,\n type AuthStrategy,\n type GlobalRequestConfig,\n} from './config';\nexport { operator, type OperateConfig } from './operator';\nexport { createCookieStrategy, createTokenStrategy } from './auth';\nexport { memoryStorage, localStorageStorage } from './storage';\nexport { login, logout } from './auth-helper';\n","import axios, {\n AxiosHeaders,\n type InternalAxiosRequestConfig,\n type AxiosError,\n type AxiosRequestConfig,\n type AxiosResponse,\n} from 'axios';\n\nimport { getGlobalRequestConfig } from './config';\n\n/** Per-request behavior toggles */\nexport type RequestMeta = {\n /** Do not attach credentials (skip strategy.addAuthToRequest) */\n skipAuth?: boolean;\n /** Do not attempt refresh on 401/419 */\n skipRefresh?: boolean;\n /** Do not call global onUnauthorized when unauthorized */\n skipUnauthorizedHandler?: boolean;\n /** Internal guard to avoid infinite retry loops */\n _retried?: number;\n};\n\n// Axios module augmentation to allow config.meta\ndeclare module 'axios' {\n export interface AxiosRequestConfig {\n meta?: RequestMeta;\n }\n}\n\nconst instance = axios.create();\n\n// ---- request interceptor: baseURL, headers, auth attachment ----\ninstance.interceptors.request.use((config: InternalAxiosRequestConfig) => {\n const global = getGlobalRequestConfig();\n\n // Merge headers (defaultHeaders first so explicit config wins)\n const mergedHeaders = {\n ...(global.defaultHeaders?.() || {}),\n ...(config.headers || {}),\n };\n\n config.headers = AxiosHeaders.from(mergedHeaders);\n config.baseURL = config.baseURL || global.baseURL || '/api';\n\n // Attach Authorization (or other credentials) if strategy is present and not skipped\n if (!config.meta?.skipAuth && global.auth) {\n config = global.auth.addAuthToRequest(config);\n }\n\n return config;\n});\n\n// ---- refresh de-duplication ----\nlet refreshPromise: Promise<void> | null = null;\n\nasync function ensureRefreshed(signal?: AbortSignal) {\n const { auth } = getGlobalRequestConfig();\n if (!auth) return;\n\n if (!refreshPromise) {\n refreshPromise = (async () => {\n try {\n await auth.refresh(signal);\n } finally {\n refreshPromise = null;\n }\n })();\n }\n return refreshPromise;\n}\n\nfunction shouldAttemptRefresh(error: AxiosError): boolean {\n const { shouldRefreshOnStatus } = getGlobalRequestConfig();\n const status = error.response?.status;\n return typeof status === 'number' && !!shouldRefreshOnStatus?.(status);\n}\n\nasync function retryOnce<T>(\n original: InternalAxiosRequestConfig,\n): Promise<AxiosResponse<T>> {\n const global = getGlobalRequestConfig();\n const retryMax = Math.max(1, global.retryAfterRefresh ?? 1);\n\n const meta = original.meta || (original.meta = {});\n const count = meta._retried ?? 0;\n\n if (count >= retryMax) {\n throw new Error('Max retries after refresh exceeded');\n }\n\n meta._retried = count + 1;\n return instance.request<T>(original);\n}\n\n// ---- response interceptor: 401 -> refresh -> retry ----\ninstance.interceptors.response.use(\n (res) => res,\n async (error: AxiosError) => {\n const global = getGlobalRequestConfig();\n const cfg = (error.config || {}) as InternalAxiosRequestConfig;\n\n // If no strategy or refresh is skipped, do not handle here\n if (cfg.meta?.skipRefresh || !global.auth || !shouldAttemptRefresh(error)) {\n if (shouldAttemptRefresh(error) && !cfg.meta?.skipUnauthorizedHandler) {\n global.onUnauthorized?.();\n }\n return Promise.reject(error);\n }\n\n try {\n await ensureRefreshed(cfg.signal as AbortSignal | undefined);\n const retried = await retryOnce(cfg);\n return retried;\n } catch (refreshErr) {\n global.auth.onRefreshFailed?.(refreshErr);\n if (!cfg.meta?.skipUnauthorizedHandler) {\n global.onUnauthorized?.();\n }\n return Promise.reject(error);\n }\n },\n);\n\n// ---- public/auth helpers on top of base request() ----\n\ntype CredentialsMode = 'auto' | 'always' | 'never';\n\nexport type PublicOptions = { credentials?: CredentialsMode };\nexport type AuthOptions = {\n noRefresh?: boolean;\n credentials?: CredentialsMode;\n};\n\n// Core callable function (default = public)\nexport type RequestFn = <T = unknown>(\n url: string,\n config?: AxiosRequestConfig,\n) => Promise<T>;\n\nasync function baseRequest<T = unknown>(\n url: string,\n config?: AxiosRequestConfig,\n): Promise<T> {\n const res = await instance.request<T>({ url, ...config });\n return res.data;\n}\n\n/**\n * The exported request is both callable and has .public/.auth shortcuts.\n * Calling request(url, config) equals request.public(url, config).\n */\nconst request = ((url: string, config?: AxiosRequestConfig) => {\n return request.public(url, config);\n}) as RequestFn & {\n public: <T = unknown>(\n url: string,\n config?: AxiosRequestConfig & PublicOptions,\n ) => Promise<T>;\n auth: <T = unknown>(\n url: string,\n config?: AxiosRequestConfig & AuthOptions,\n ) => Promise<T>;\n init: <T = unknown>(\n url: string,\n config?: AxiosRequestConfig,\n ) => Promise<T | null>;\n reset: () => void;\n};\n\nrequest.public = async function <T = unknown>(\n url: string,\n config?: AxiosRequestConfig & PublicOptions,\n): Promise<T> {\n const withCredentials = config?.credentials === 'always' ? true : undefined;\n return baseRequest<T>(url, {\n ...config,\n withCredentials,\n meta: {\n ...(config?.meta || {}),\n skipAuth: true,\n skipRefresh: true,\n skipUnauthorizedHandler: true,\n },\n });\n};\n\nrequest.auth = async function <T = unknown>(\n url: string,\n config?: AxiosRequestConfig & AuthOptions,\n): Promise<T> {\n const withCredentials = config?.credentials === 'always' ? true : undefined;\n return baseRequest<T>(url, {\n ...config,\n withCredentials,\n meta: {\n ...(config?.meta || {}),\n ...(config?.noRefresh ? { skipRefresh: true } : {}),\n },\n });\n};\n\nlet didInitSoftRefresh = false;\n\nasync function probe<T>(\n url: string,\n config?: AxiosRequestConfig,\n): Promise<T | null> {\n return request.auth<T>(url, {\n ...config,\n noRefresh: true,\n meta: {\n ...(config?.meta || {}),\n skipUnauthorizedHandler: true,\n },\n });\n}\n\nrequest.init = async function <T = unknown>(\n url: string,\n config?: AxiosRequestConfig & { soft?: boolean },\n): Promise<T | null> {\n try {\n return await probe<T>(url, config);\n } catch {\n const soft = config?.soft ?? true; // default: allow one soft refresh this load\n if (!soft || didInitSoftRefresh) return null;\n\n const auth = getGlobalRequestConfig().auth;\n if (!auth) return null;\n\n try {\n await auth.refresh(config?.signal as AbortSignal | undefined);\n didInitSoftRefresh = true;\n return await probe<T>(url, config);\n } catch {\n return null;\n }\n }\n};\n\nrequest.reset = function () {\n didInitSoftRefresh = false;\n};\n\nexport { request };\nexport type { AxiosRequestConfig } from 'axios';\n","import type { AxiosRequestConfig, InternalAxiosRequestConfig } from 'axios';\n\nexport type ToastFn = (msg: string) => void;\n\nexport interface AuthStrategy {\n /** Attach credentials (e.g., Authorization header) */\n addAuthToRequest: <T extends AxiosRequestConfig | InternalAxiosRequestConfig>(\n config: T,\n ) => T;\n\n /** Refresh credentials; may rely on http-only cookie or token exchange */\n refresh: (signal?: AbortSignal) => Promise<void>;\n\n /** Optional: called when refresh ultimately fails */\n onRefreshFailed?: (reason: unknown) => void;\n\n /** Optional: persist tokens to local storage or app state */\n setToken?: (json: { accessToken?: string; refreshToken?: string }) => void;\n\n /** Optional: clear local credentials */\n clearToken?: () => void;\n}\n\nexport interface GlobalRequestConfig {\n toast?: {\n success?: ToastFn;\n error?: ToastFn;\n };\n baseURL?: string;\n defaultHeaders?: () => Record<string, string>;\n onUnauthorized?: () => void;\n\n /** Pluggable authentication behavior */\n auth?: AuthStrategy;\n\n /** Max retries after a successful refresh (default: 1) */\n retryAfterRefresh?: number;\n\n /** Status codes that should trigger a refresh attempt (default: 401) */\n shouldRefreshOnStatus?: (status: number) => boolean;\n}\n\nconst globalConfig: GlobalRequestConfig = {\n retryAfterRefresh: 1,\n shouldRefreshOnStatus: (s) => s === 401 || s === 419 || s === 440,\n};\n\nexport const setupRequest = (config: GlobalRequestConfig) => {\n Object.assign(globalConfig, config);\n};\n\nexport const updateRequestConfig = (patch: Partial<GlobalRequestConfig>) => {\n Object.assign(globalConfig, patch);\n};\n\nexport const getGlobalRequestConfig = () => globalConfig;\n","import axios, { type AxiosError } from 'axios';\n\nimport { getGlobalRequestConfig, type ToastFn } from './config';\n\nexport type OperateConfig<E> = {\n setOperating?: (loading: boolean) => void;\n formatMessage?: () => string;\n formatReason?: (err: E) => string;\n hideToast?: boolean;\n toast?: {\n success?: ToastFn;\n error?: ToastFn;\n };\n};\n\ntype ApiErrorBody = {\n message?: string;\n error?: string;\n detail?: string;\n errors?: string | string[];\n};\n\nfunction extractAxiosMessage(err: AxiosError<ApiErrorBody>): string {\n const data = err.response?.data;\n\n if (typeof data === 'string') return data;\n\n if (data && typeof data === 'object') {\n const { message, error, detail, errors } = data;\n const merged =\n message ??\n error ??\n detail ??\n (Array.isArray(errors) ? errors.join(', ') : errors);\n if (merged) return merged;\n }\n\n return err.message || 'Unknown error';\n}\n\nexport async function operator<T, E = unknown>(\n request: () => Promise<T>,\n config: OperateConfig<E> = {},\n): Promise<[true, T?] | [false, E?]> {\n const global = getGlobalRequestConfig();\n const {\n setOperating,\n formatMessage,\n formatReason = (err: E) => {\n if (axios.isAxiosError<ApiErrorBody>(err)) {\n return extractAxiosMessage(err);\n }\n if (err instanceof Error) return err.message;\n return String(err ?? 'Unknown error');\n },\n hideToast,\n toast: localToast,\n } = config;\n\n const toast = localToast ?? global.toast;\n\n try {\n setOperating?.(true);\n const res = await request();\n if (!hideToast) toast?.success?.(formatMessage?.() ?? 'Success');\n return [true, res];\n } catch (err) {\n const typed = err as E;\n if (!hideToast) toast?.error?.(formatReason(typed));\n return [false, typed];\n } finally {\n setOperating?.(false);\n }\n}\n","import { AxiosHeaders, type AxiosRequestConfig } from 'axios';\n\nimport type { AuthStrategy } from './config';\nimport {\n memoryStorage,\n localStorageStorage,\n type TokenStorage,\n} from './storage';\n\nfunction addAuthHeader<T extends AxiosRequestConfig>(\n config: T,\n token: string | null,\n): T {\n if (token) {\n config.headers = AxiosHeaders.from({\n ...(config.headers || {}),\n Authorization: `Bearer ${token}`,\n });\n }\n return config;\n}\n\n/**\n * Cookie-based strategy:\n * - Access token lives in app state (memory/storage).\n * - Refresh relies on http-only cookie via a server endpoint.\n */\nexport function createCookieStrategy(opts: {\n storage?: TokenStorage;\n tokenField?: string; // default: \"access_token\"\n refreshPath: string; // e.g., '/auth/refresh'\n}): AuthStrategy {\n const storage = opts.storage ?? memoryStorage;\n const accessKey = opts?.tokenField ?? 'access_token';\n\n return {\n addAuthToRequest<T extends AxiosRequestConfig>(config: T): T {\n return addAuthHeader(config, storage.getAccessToken());\n },\n async refresh(signal?: AbortSignal) {\n const res = await fetch(opts.refreshPath, {\n method: 'POST',\n credentials: 'include',\n headers: {\n Accept: 'application/json',\n },\n signal,\n });\n if (!res.ok) throw new Error(`Refresh failed: ${res.status}`);\n try {\n const json = await res.json();\n if (json?.[accessKey]) {\n storage.setAccessToken(json[accessKey]);\n }\n } catch {\n // Some backends may not return JSON; cookie-only session is fine.\n }\n },\n setToken({ accessToken, refreshToken }) {\n if (accessToken) storage.setAccessToken(accessToken);\n if (refreshToken) storage.setRefreshToken?.(refreshToken);\n },\n clearToken() {\n storage.setAccessToken(null);\n storage.setRefreshToken?.(null);\n },\n };\n}\n\n/**\n * Token-exchange strategy:\n * - Both access and refresh tokens are readable by JS (NOT http-only).\n */\nexport function createTokenStrategy(opts: {\n storage?: TokenStorage;\n tokenField?: string; // default: \"access_token\"\n refreshPath: string;\n}): AuthStrategy {\n const storage = opts.storage ?? localStorageStorage;\n const accessKey = opts?.tokenField ?? 'access_token';\n\n return {\n addAuthToRequest<T extends AxiosRequestConfig>(config: T): T {\n return addAuthHeader(config, storage.getAccessToken());\n },\n async refresh(signal?: AbortSignal) {\n const rt = storage.getRefreshToken?.();\n if (!rt) throw new Error('No refresh token');\n const res = await fetch(opts.refreshPath, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n },\n body: JSON.stringify({ refresh_token: rt }),\n signal,\n });\n if (!res.ok) throw new Error(`Refresh failed: ${res.status}`);\n const json = await res.json();\n if (!json?.[accessKey]) throw new Error('Malformed refresh response');\n storage.setAccessToken(json[accessKey]);\n if (json.refresh_token) storage.setRefreshToken?.(json.refresh_token);\n },\n setToken({ accessToken, refreshToken }) {\n if (accessToken) storage.setAccessToken(accessToken);\n if (refreshToken) storage.setRefreshToken?.(refreshToken);\n },\n clearToken() {\n storage.setAccessToken(null);\n storage.setRefreshToken?.(null);\n },\n };\n}\n","export interface TokenStorage {\n getAccessToken(): string | null;\n setAccessToken(token: string | null): void;\n getRefreshToken?(): string | null;\n setRefreshToken?(token: string | null): void;\n}\n\nexport const memoryStorage: TokenStorage = (() => {\n let access: string | null = null;\n let refresh: string | null = null;\n return {\n getAccessToken: () => access,\n setAccessToken: (t) => (access = t),\n getRefreshToken: () => refresh,\n setRefreshToken: (t) => (refresh = t),\n };\n})();\n\nconst safeLocal = () => {\n try {\n return typeof window !== 'undefined' ? window.localStorage : null;\n } catch {\n return null;\n }\n};\n\nexport const localStorageStorage: TokenStorage = {\n getAccessToken: () => safeLocal()?.getItem('access_token') ?? null,\n setAccessToken: (t) => {\n const ls = safeLocal();\n if (!ls) return;\n if (t) {\n ls.setItem('access_token', t);\n } else {\n ls.removeItem('access_token');\n }\n },\n getRefreshToken: () => safeLocal()?.getItem('refresh_token') ?? null,\n setRefreshToken: (t) => {\n const ls = safeLocal();\n if (!ls) return;\n if (t) {\n ls.setItem('refresh_token', t);\n } else {\n ls.removeItem('refresh_token');\n }\n },\n};\n","import { getGlobalRequestConfig } from './config';\n\nexport async function login(\n perform: () => Promise<{ accessToken?: string; refreshToken?: string }>,\n) {\n const auth = getGlobalRequestConfig().auth;\n const json = await perform();\n auth?.setToken?.(json);\n return json;\n}\n\nexport async function logout<T>(perform?: () => Promise<T>) {\n const auth = getGlobalRequestConfig().auth;\n try {\n if (perform) await perform();\n } finally {\n auth?.clearToken?.();\n }\n}\n"],"mappings":"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","names":["axios","e","import_axios","request","axios","import_axios","_a","_b"]}

@@ -35,2 +35,4 @@ import { AxiosRequestConfig, InternalAxiosRequestConfig } from 'axios';

auth: <T = unknown>(url: string, config?: AxiosRequestConfig & AuthOptions) => Promise<T>;
init: <T = unknown>(url: string, config?: AxiosRequestConfig) => Promise<T | null>;
reset: () => void;
};

@@ -42,4 +44,2 @@

addAuthToRequest: <T extends AxiosRequestConfig | InternalAxiosRequestConfig>(config: T) => T;
/** Optional: return true if access token is still valid */
isAccessTokenValid?: () => boolean;
/** Refresh credentials; may rely on http-only cookie or token exchange */

@@ -49,2 +49,9 @@ refresh: (signal?: AbortSignal) => Promise<void>;

onRefreshFailed?: (reason: unknown) => void;
/** Optional: persist tokens to local storage or app state */
setToken?: (json: {
accessToken?: string;
refreshToken?: string;
}) => void;
/** Optional: clear local credentials */
clearToken?: () => void;
}

@@ -88,2 +95,4 @@ interface GlobalRequestConfig {

}
declare const memoryStorage: TokenStorage;
declare const localStorageStorage: TokenStorage;

@@ -97,4 +106,4 @@ /**

storage?: TokenStorage;
tokenField?: string;
refreshPath: string;
isTokenValid?: () => boolean;
}): AuthStrategy;

@@ -107,6 +116,15 @@ /**

storage?: TokenStorage;
tokenField?: string;
refreshPath: string;
isTokenValid?: () => boolean;
}): AuthStrategy;
export { AuthStrategy, GlobalRequestConfig, OperateConfig, createCookieStrategy, createTokenStrategy, getGlobalRequestConfig, operator, request, setupRequest, updateRequestConfig };
declare function login(perform: () => Promise<{
accessToken?: string;
refreshToken?: string;
}>): Promise<{
accessToken?: string;
refreshToken?: string;
}>;
declare function logout<T>(perform?: () => Promise<T>): Promise<void>;
export { AuthStrategy, GlobalRequestConfig, OperateConfig, createCookieStrategy, createTokenStrategy, getGlobalRequestConfig, localStorageStorage, login, logout, memoryStorage, operator, request, setupRequest, updateRequestConfig };

@@ -35,2 +35,4 @@ import { AxiosRequestConfig, InternalAxiosRequestConfig } from 'axios';

auth: <T = unknown>(url: string, config?: AxiosRequestConfig & AuthOptions) => Promise<T>;
init: <T = unknown>(url: string, config?: AxiosRequestConfig) => Promise<T | null>;
reset: () => void;
};

@@ -42,4 +44,2 @@

addAuthToRequest: <T extends AxiosRequestConfig | InternalAxiosRequestConfig>(config: T) => T;
/** Optional: return true if access token is still valid */
isAccessTokenValid?: () => boolean;
/** Refresh credentials; may rely on http-only cookie or token exchange */

@@ -49,2 +49,9 @@ refresh: (signal?: AbortSignal) => Promise<void>;

onRefreshFailed?: (reason: unknown) => void;
/** Optional: persist tokens to local storage or app state */
setToken?: (json: {
accessToken?: string;
refreshToken?: string;
}) => void;
/** Optional: clear local credentials */
clearToken?: () => void;
}

@@ -88,2 +95,4 @@ interface GlobalRequestConfig {

}
declare const memoryStorage: TokenStorage;
declare const localStorageStorage: TokenStorage;

@@ -97,4 +106,4 @@ /**

storage?: TokenStorage;
tokenField?: string;
refreshPath: string;
isTokenValid?: () => boolean;
}): AuthStrategy;

@@ -107,6 +116,15 @@ /**

storage?: TokenStorage;
tokenField?: string;
refreshPath: string;
isTokenValid?: () => boolean;
}): AuthStrategy;
export { AuthStrategy, GlobalRequestConfig, OperateConfig, createCookieStrategy, createTokenStrategy, getGlobalRequestConfig, operator, request, setupRequest, updateRequestConfig };
declare function login(perform: () => Promise<{
accessToken?: string;
refreshToken?: string;
}>): Promise<{
accessToken?: string;
refreshToken?: string;
}>;
declare function logout<T>(perform?: () => Promise<T>): Promise<void>;
export { AuthStrategy, GlobalRequestConfig, OperateConfig, createCookieStrategy, createTokenStrategy, getGlobalRequestConfig, localStorageStorage, login, logout, memoryStorage, operator, request, setupRequest, updateRequestConfig };

@@ -9,3 +9,3 @@ // src/core/request.ts

retryAfterRefresh: 1,
shouldRefreshOnStatus: (s) => s === 401
shouldRefreshOnStatus: (s) => s === 401 || s === 419 || s === 440
};

@@ -46,5 +46,3 @@ var setupRequest = (config) => {

} finally {
const p = refreshPromise;
refreshPromise = null;
await (p == null ? void 0 : p.catch(() => void 0));
}

@@ -76,3 +74,3 @@ })();

async (error) => {
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
var _a, _b, _c, _d, _e, _f, _g;
const global = getGlobalRequestConfig();

@@ -86,5 +84,2 @@ const cfg = error.config || {};

}
if ((_e = (_d = global.auth).isAccessTokenValid) == null ? void 0 : _e.call(_d)) {
return Promise.reject(error);
}
try {

@@ -95,5 +90,5 @@ await ensureRefreshed(cfg.signal);

} catch (refreshErr) {
(_g = (_f = global.auth).onRefreshFailed) == null ? void 0 : _g.call(_f, refreshErr);
if (!((_h = cfg.meta) == null ? void 0 : _h.skipUnauthorizedHandler)) {
(_i = global.onUnauthorized) == null ? void 0 : _i.call(global);
(_e = (_d = global.auth).onRefreshFailed) == null ? void 0 : _e.call(_d, refreshErr);
if (!((_f = cfg.meta) == null ? void 0 : _f.skipUnauthorizedHandler)) {
(_g = global.onUnauthorized) == null ? void 0 : _g.call(global);
}

@@ -135,2 +130,36 @@ return Promise.reject(error);

};
var didInitSoftRefresh = false;
async function probe(url, config) {
return request.auth(url, {
...config,
noRefresh: true,
meta: {
...(config == null ? void 0 : config.meta) || {},
skipUnauthorizedHandler: true
}
});
}
request.init = async function(url, config) {
var _a;
try {
return await probe(url, config);
} catch (e) {
const soft = (_a = config == null ? void 0 : config.soft) != null ? _a : true;
if (!soft || didInitSoftRefresh)
return null;
const auth = getGlobalRequestConfig().auth;
if (!auth)
return null;
try {
await auth.refresh(config == null ? void 0 : config.signal);
didInitSoftRefresh = true;
return await probe(url, config);
} catch (e2) {
return null;
}
}
};
request.reset = function() {
didInitSoftRefresh = false;
};

@@ -248,16 +277,6 @@ // src/core/operator.ts

}
function isJwtValid(t, leewaySec = 30) {
if (!t)
return false;
const [, payload] = t.split(".");
try {
const { exp } = JSON.parse(atob(payload));
return typeof exp === "number" && Date.now() / 1e3 < exp - leewaySec;
} catch (e) {
return false;
}
}
function createCookieStrategy(opts) {
var _a, _b;
const storage = (_a = opts.storage) != null ? _a : memoryStorage;
const accessKey = (_b = opts == null ? void 0 : opts.tokenField) != null ? _b : "access_token";
return {

@@ -267,3 +286,2 @@ addAuthToRequest(config) {

},
isAccessTokenValid: (_b = opts.isTokenValid) != null ? _b : () => isJwtValid(storage.getAccessToken()),
async refresh(signal) {

@@ -282,4 +300,4 @@ const res = await fetch(opts.refreshPath, {

const json = await res.json();
if (json == null ? void 0 : json.access_token) {
storage.setAccessToken(json.access_token);
if (json == null ? void 0 : json[accessKey]) {
storage.setAccessToken(json[accessKey]);
}

@@ -289,5 +307,13 @@ } catch (e) {

},
onRefreshFailed(reason) {
setToken({ accessToken, refreshToken }) {
var _a2;
if (accessToken)
storage.setAccessToken(accessToken);
if (refreshToken)
(_a2 = storage.setRefreshToken) == null ? void 0 : _a2.call(storage, refreshToken);
},
clearToken() {
var _a2;
storage.setAccessToken(null);
console.warn("Refresh failed", reason);
(_a2 = storage.setRefreshToken) == null ? void 0 : _a2.call(storage, null);
}

@@ -299,2 +325,3 @@ };

const storage = (_a = opts.storage) != null ? _a : localStorageStorage;
const accessKey = (_b = opts == null ? void 0 : opts.tokenField) != null ? _b : "access_token";
return {

@@ -304,3 +331,2 @@ addAuthToRequest(config) {

},
isAccessTokenValid: (_b = opts.isTokenValid) != null ? _b : () => isJwtValid(storage.getAccessToken()),
async refresh(signal) {

@@ -323,16 +349,41 @@ var _a2, _b2;

const json = await res.json();
if (!(json == null ? void 0 : json.access_token))
if (!(json == null ? void 0 : json[accessKey]))
throw new Error("Malformed refresh response");
storage.setAccessToken(json.access_token);
storage.setAccessToken(json[accessKey]);
if (json.refresh_token)
(_b2 = storage.setRefreshToken) == null ? void 0 : _b2.call(storage, json.refresh_token);
},
onRefreshFailed(reason) {
setToken({ accessToken, refreshToken }) {
var _a2;
if (accessToken)
storage.setAccessToken(accessToken);
if (refreshToken)
(_a2 = storage.setRefreshToken) == null ? void 0 : _a2.call(storage, refreshToken);
},
clearToken() {
var _a2;
storage.setAccessToken(null);
(_a2 = storage.setRefreshToken) == null ? void 0 : _a2.call(storage, null);
console.warn("Refresh failed", reason);
}
};
}
// src/core/auth-helper.ts
async function login(perform) {
var _a;
const auth = getGlobalRequestConfig().auth;
const json = await perform();
(_a = auth == null ? void 0 : auth.setToken) == null ? void 0 : _a.call(auth, json);
return json;
}
async function logout(perform) {
var _a;
const auth = getGlobalRequestConfig().auth;
try {
if (perform)
await perform();
} finally {
(_a = auth == null ? void 0 : auth.clearToken) == null ? void 0 : _a.call(auth);
}
}
export {

@@ -342,2 +393,6 @@ createCookieStrategy,

getGlobalRequestConfig,
localStorageStorage,
login,
logout,
memoryStorage,
operator,

@@ -344,0 +399,0 @@ request,

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/core/request.ts","../src/core/config.ts","../src/core/operator.ts","../src/core/auth.ts","../src/core/storage.ts"],"sourcesContent":["import axios, {\n AxiosHeaders,\n type InternalAxiosRequestConfig,\n type AxiosError,\n type AxiosRequestConfig,\n type AxiosResponse,\n} from 'axios';\n\nimport { getGlobalRequestConfig } from './config';\n\n/** Per-request behavior toggles */\nexport type RequestMeta = {\n /** Do not attach credentials (skip strategy.addAuthToRequest) */\n skipAuth?: boolean;\n /** Do not attempt refresh on 401/419 */\n skipRefresh?: boolean;\n /** Do not call global onUnauthorized when unauthorized */\n skipUnauthorizedHandler?: boolean;\n /** Internal guard to avoid infinite retry loops */\n _retried?: number;\n};\n\n// Axios module augmentation to allow config.meta\ndeclare module 'axios' {\n export interface AxiosRequestConfig {\n meta?: RequestMeta;\n }\n}\n\nconst instance = axios.create();\n\n// ---- request interceptor: baseURL, headers, auth attachment ----\ninstance.interceptors.request.use((config: InternalAxiosRequestConfig) => {\n const global = getGlobalRequestConfig();\n\n // Merge headers (defaultHeaders first so explicit config wins)\n const mergedHeaders = {\n ...(global.defaultHeaders?.() || {}),\n ...(config.headers || {}),\n };\n\n config.headers = AxiosHeaders.from(mergedHeaders);\n config.baseURL = config.baseURL || global.baseURL || '/api';\n\n // Attach Authorization (or other credentials) if strategy is present and not skipped\n if (!config.meta?.skipAuth && global.auth) {\n config = global.auth.addAuthToRequest(config);\n }\n\n return config;\n});\n\n// ---- refresh de-duplication ----\nlet refreshPromise: Promise<void> | null = null;\n\nasync function ensureRefreshed(signal?: AbortSignal) {\n const { auth } = getGlobalRequestConfig();\n if (!auth) return;\n\n if (!refreshPromise) {\n refreshPromise = (async () => {\n try {\n await auth.refresh(signal);\n } finally {\n // Reset promise regardless of success/failure\n const p = refreshPromise;\n refreshPromise = null;\n await (p as Promise<void> | null)?.catch(() => undefined);\n }\n })();\n }\n return refreshPromise;\n}\n\nfunction shouldAttemptRefresh(error: AxiosError): boolean {\n const { shouldRefreshOnStatus } = getGlobalRequestConfig();\n const status = error.response?.status;\n return typeof status === 'number' && !!shouldRefreshOnStatus?.(status);\n}\n\nasync function retryOnce<T>(\n original: InternalAxiosRequestConfig,\n): Promise<AxiosResponse<T>> {\n const global = getGlobalRequestConfig();\n const retryMax = Math.max(1, global.retryAfterRefresh ?? 1);\n\n const meta = original.meta || (original.meta = {});\n const count = meta._retried ?? 0;\n\n if (count >= retryMax) {\n throw new Error('Max retries after refresh exceeded');\n }\n\n meta._retried = count + 1;\n return instance.request<T>(original);\n}\n\n// ---- response interceptor: 401 -> refresh -> retry ----\ninstance.interceptors.response.use(\n (res) => res,\n async (error: AxiosError) => {\n const global = getGlobalRequestConfig();\n const cfg = (error.config || {}) as InternalAxiosRequestConfig;\n\n // If no strategy or refresh is skipped, do not handle here\n if (cfg.meta?.skipRefresh || !global.auth || !shouldAttemptRefresh(error)) {\n if (shouldAttemptRefresh(error) && !cfg.meta?.skipUnauthorizedHandler) {\n global.onUnauthorized?.();\n }\n return Promise.reject(error);\n }\n\n // Optional proactive validity check (if provided)\n if (global.auth.isAccessTokenValid?.()) {\n // Token claims still \"valid\" but server says unauthorized -> bubble up\n return Promise.reject(error);\n }\n\n try {\n await ensureRefreshed(cfg.signal as AbortSignal | undefined);\n const retried = await retryOnce(cfg);\n return retried;\n } catch (refreshErr) {\n global.auth.onRefreshFailed?.(refreshErr);\n if (!cfg.meta?.skipUnauthorizedHandler) {\n global.onUnauthorized?.();\n }\n return Promise.reject(error);\n }\n },\n);\n\n// ---- public/auth helpers on top of base request() ----\n\ntype CredentialsMode = 'auto' | 'always' | 'never';\n\nexport type PublicOptions = { credentials?: CredentialsMode };\nexport type AuthOptions = {\n noRefresh?: boolean;\n credentials?: CredentialsMode;\n};\n\n// Core callable function (default = public)\nexport type RequestFn = <T = unknown>(\n url: string,\n config?: AxiosRequestConfig,\n) => Promise<T>;\n\nasync function baseRequest<T = unknown>(\n url: string,\n config?: AxiosRequestConfig,\n): Promise<T> {\n const res = await instance.request<T>({ url, ...config });\n return res.data;\n}\n\n/**\n * The exported request is both callable and has .public/.auth shortcuts.\n * Calling request(url, config) equals request.public(url, config).\n */\nconst request = ((url: string, config?: AxiosRequestConfig) => {\n return request.public(url, config);\n}) as RequestFn & {\n public: <T = unknown>(\n url: string,\n config?: AxiosRequestConfig & PublicOptions,\n ) => Promise<T>;\n auth: <T = unknown>(\n url: string,\n config?: AxiosRequestConfig & AuthOptions,\n ) => Promise<T>;\n};\n\nrequest.public = async function <T = unknown>(\n url: string,\n config?: AxiosRequestConfig & PublicOptions,\n): Promise<T> {\n const withCredentials = config?.credentials === 'always' ? true : undefined;\n return baseRequest<T>(url, {\n ...config,\n withCredentials,\n meta: {\n ...(config?.meta || {}),\n skipAuth: true,\n skipRefresh: true,\n skipUnauthorizedHandler: true,\n },\n });\n};\n\nrequest.auth = async function <T = unknown>(\n url: string,\n config?: AxiosRequestConfig & AuthOptions,\n): Promise<T> {\n const withCredentials = config?.credentials === 'always' ? true : undefined;\n return baseRequest<T>(url, {\n ...config,\n withCredentials,\n meta: {\n ...(config?.meta || {}),\n ...(config?.noRefresh ? { skipRefresh: true } : {}),\n },\n });\n};\n\nexport { request };\nexport type { AxiosRequestConfig } from 'axios';\n","import type { AxiosRequestConfig, InternalAxiosRequestConfig } from 'axios';\n\nexport type ToastFn = (msg: string) => void;\n\nexport interface AuthStrategy {\n /** Attach credentials (e.g., Authorization header) */\n addAuthToRequest: <T extends AxiosRequestConfig | InternalAxiosRequestConfig>(\n config: T,\n ) => T;\n\n /** Optional: return true if access token is still valid */\n isAccessTokenValid?: () => boolean;\n\n /** Refresh credentials; may rely on http-only cookie or token exchange */\n refresh: (signal?: AbortSignal) => Promise<void>;\n\n /** Optional: called when refresh ultimately fails */\n onRefreshFailed?: (reason: unknown) => void;\n}\n\nexport interface GlobalRequestConfig {\n toast?: {\n success?: ToastFn;\n error?: ToastFn;\n };\n baseURL?: string;\n defaultHeaders?: () => Record<string, string>;\n onUnauthorized?: () => void;\n\n /** Pluggable authentication behavior */\n auth?: AuthStrategy;\n\n /** Max retries after a successful refresh (default: 1) */\n retryAfterRefresh?: number;\n\n /** Status codes that should trigger a refresh attempt (default: 401) */\n shouldRefreshOnStatus?: (status: number) => boolean;\n}\n\nconst globalConfig: GlobalRequestConfig = {\n retryAfterRefresh: 1,\n shouldRefreshOnStatus: (s) => s === 401,\n};\n\nexport const setupRequest = (config: GlobalRequestConfig) => {\n Object.assign(globalConfig, config);\n};\n\nexport const updateRequestConfig = (patch: Partial<GlobalRequestConfig>) => {\n Object.assign(globalConfig, patch);\n};\n\nexport const getGlobalRequestConfig = () => globalConfig;\n","import axios, { type AxiosError } from 'axios';\n\nimport { getGlobalRequestConfig, type ToastFn } from './config';\n\nexport type OperateConfig<E> = {\n setOperating?: (loading: boolean) => void;\n formatMessage?: () => string;\n formatReason?: (err: E) => string;\n hideToast?: boolean;\n toast?: {\n success?: ToastFn;\n error?: ToastFn;\n };\n};\n\ntype ApiErrorBody = {\n message?: string;\n error?: string;\n detail?: string;\n errors?: string | string[];\n};\n\nfunction extractAxiosMessage(err: AxiosError<ApiErrorBody>): string {\n const data = err.response?.data;\n\n if (typeof data === 'string') return data;\n\n if (data && typeof data === 'object') {\n const { message, error, detail, errors } = data;\n const merged =\n message ??\n error ??\n detail ??\n (Array.isArray(errors) ? errors.join(', ') : errors);\n if (merged) return merged;\n }\n\n return err.message || 'Unknown error';\n}\n\nexport async function operator<T, E = unknown>(\n request: () => Promise<T>,\n config: OperateConfig<E> = {},\n): Promise<[true, T?] | [false, E?]> {\n const global = getGlobalRequestConfig();\n const {\n setOperating,\n formatMessage,\n formatReason = (err: E) => {\n if (axios.isAxiosError<ApiErrorBody>(err)) {\n return extractAxiosMessage(err);\n }\n if (err instanceof Error) return err.message;\n return String(err ?? 'Unknown error');\n },\n hideToast,\n toast: localToast,\n } = config;\n\n const toast = localToast ?? global.toast;\n\n try {\n setOperating?.(true);\n const res = await request();\n if (!hideToast) toast?.success?.(formatMessage?.() ?? 'Success');\n return [true, res];\n } catch (err) {\n const typed = err as E;\n if (!hideToast) toast?.error?.(formatReason(typed));\n return [false, typed];\n } finally {\n setOperating?.(false);\n }\n}\n","import { AxiosHeaders, type AxiosRequestConfig } from 'axios';\n\nimport type { AuthStrategy } from './config';\nimport {\n memoryStorage,\n localStorageStorage,\n type TokenStorage,\n} from './storage';\n\nfunction addAuthHeader<T extends AxiosRequestConfig>(\n config: T,\n token: string | null,\n): T {\n if (token) {\n config.headers = AxiosHeaders.from({\n ...(config.headers || {}),\n Authorization: `Bearer ${token}`,\n });\n }\n return config;\n}\n\nfunction isJwtValid(t: string | null, leewaySec = 30) {\n if (!t) return false;\n const [, payload] = t.split('.');\n try {\n const { exp } = JSON.parse(atob(payload));\n return typeof exp === 'number' && Date.now() / 1000 < exp - leewaySec;\n } catch {\n return false;\n }\n}\n\n/**\n * Cookie-based strategy:\n * - Access token lives in app state (memory/storage).\n * - Refresh relies on http-only cookie via a server endpoint.\n */\nexport function createCookieStrategy(opts: {\n storage?: TokenStorage;\n refreshPath: string; // e.g., '/auth/refresh'\n isTokenValid?: () => boolean;\n}): AuthStrategy {\n const storage = opts.storage ?? memoryStorage;\n\n return {\n addAuthToRequest<T extends AxiosRequestConfig>(config: T): T {\n return addAuthHeader(config, storage.getAccessToken());\n },\n isAccessTokenValid:\n opts.isTokenValid ?? (() => isJwtValid(storage.getAccessToken())),\n async refresh(signal?: AbortSignal) {\n const res = await fetch(opts.refreshPath, {\n method: 'POST',\n credentials: 'include',\n headers: {\n Accept: 'application/json',\n },\n signal,\n });\n if (!res.ok) throw new Error(`Refresh failed: ${res.status}`);\n try {\n const json = await res.json();\n if (json?.access_token) {\n storage.setAccessToken(json.access_token);\n }\n } catch {\n // Some backends may not return JSON; cookie-only session is fine.\n }\n },\n onRefreshFailed(reason) {\n storage.setAccessToken(null);\n console.warn('Refresh failed', reason);\n },\n };\n}\n\n/**\n * Token-exchange strategy:\n * - Both access and refresh tokens are readable by JS (NOT http-only).\n */\nexport function createTokenStrategy(opts: {\n storage?: TokenStorage;\n refreshPath: string;\n isTokenValid?: () => boolean;\n}): AuthStrategy {\n const storage = opts.storage ?? localStorageStorage;\n\n return {\n addAuthToRequest<T extends AxiosRequestConfig>(config: T): T {\n return addAuthHeader(config, storage.getAccessToken());\n },\n isAccessTokenValid:\n opts.isTokenValid ?? (() => isJwtValid(storage.getAccessToken())),\n async refresh(signal?: AbortSignal) {\n const rt = storage.getRefreshToken?.();\n if (!rt) throw new Error('No refresh token');\n const res = await fetch(opts.refreshPath, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n },\n body: JSON.stringify({ refresh_token: rt }),\n signal,\n });\n if (!res.ok) throw new Error(`Refresh failed: ${res.status}`);\n const json = await res.json();\n if (!json?.access_token) throw new Error('Malformed refresh response');\n storage.setAccessToken(json.access_token);\n if (json.refresh_token) storage.setRefreshToken?.(json.refresh_token);\n },\n onRefreshFailed(reason) {\n storage.setAccessToken(null);\n storage.setRefreshToken?.(null);\n console.warn('Refresh failed', reason);\n },\n };\n}\n","export interface TokenStorage {\n getAccessToken(): string | null;\n setAccessToken(token: string | null): void;\n getRefreshToken?(): string | null;\n setRefreshToken?(token: string | null): void;\n}\n\nexport const memoryStorage: TokenStorage = (() => {\n let access: string | null = null;\n let refresh: string | null = null;\n return {\n getAccessToken: () => access,\n setAccessToken: (t) => (access = t),\n getRefreshToken: () => refresh,\n setRefreshToken: (t) => (refresh = t),\n };\n})();\n\nconst safeLocal = () => {\n try {\n return typeof window !== 'undefined' ? window.localStorage : null;\n } catch {\n return null;\n }\n};\n\nexport const localStorageStorage: TokenStorage = {\n getAccessToken: () => safeLocal()?.getItem('access_token') ?? null,\n setAccessToken: (t) => {\n const ls = safeLocal();\n if (!ls) return;\n if (t) {\n ls.setItem('access_token', t);\n } else {\n ls.removeItem('access_token');\n }\n },\n getRefreshToken: () => safeLocal()?.getItem('refresh_token') ?? null,\n setRefreshToken: (t) => {\n const ls = safeLocal();\n if (!ls) return;\n if (t) {\n ls.setItem('refresh_token', t);\n } else {\n ls.removeItem('refresh_token');\n }\n },\n};\n"],"mappings":"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","names":["axios","request","axios","AxiosHeaders","AxiosHeaders","_a","_b"]}
{"version":3,"sources":["../src/core/request.ts","../src/core/config.ts","../src/core/operator.ts","../src/core/auth.ts","../src/core/storage.ts","../src/core/auth-helper.ts"],"sourcesContent":["import axios, {\n AxiosHeaders,\n type InternalAxiosRequestConfig,\n type AxiosError,\n type AxiosRequestConfig,\n type AxiosResponse,\n} from 'axios';\n\nimport { getGlobalRequestConfig } from './config';\n\n/** Per-request behavior toggles */\nexport type RequestMeta = {\n /** Do not attach credentials (skip strategy.addAuthToRequest) */\n skipAuth?: boolean;\n /** Do not attempt refresh on 401/419 */\n skipRefresh?: boolean;\n /** Do not call global onUnauthorized when unauthorized */\n skipUnauthorizedHandler?: boolean;\n /** Internal guard to avoid infinite retry loops */\n _retried?: number;\n};\n\n// Axios module augmentation to allow config.meta\ndeclare module 'axios' {\n export interface AxiosRequestConfig {\n meta?: RequestMeta;\n }\n}\n\nconst instance = axios.create();\n\n// ---- request interceptor: baseURL, headers, auth attachment ----\ninstance.interceptors.request.use((config: InternalAxiosRequestConfig) => {\n const global = getGlobalRequestConfig();\n\n // Merge headers (defaultHeaders first so explicit config wins)\n const mergedHeaders = {\n ...(global.defaultHeaders?.() || {}),\n ...(config.headers || {}),\n };\n\n config.headers = AxiosHeaders.from(mergedHeaders);\n config.baseURL = config.baseURL || global.baseURL || '/api';\n\n // Attach Authorization (or other credentials) if strategy is present and not skipped\n if (!config.meta?.skipAuth && global.auth) {\n config = global.auth.addAuthToRequest(config);\n }\n\n return config;\n});\n\n// ---- refresh de-duplication ----\nlet refreshPromise: Promise<void> | null = null;\n\nasync function ensureRefreshed(signal?: AbortSignal) {\n const { auth } = getGlobalRequestConfig();\n if (!auth) return;\n\n if (!refreshPromise) {\n refreshPromise = (async () => {\n try {\n await auth.refresh(signal);\n } finally {\n refreshPromise = null;\n }\n })();\n }\n return refreshPromise;\n}\n\nfunction shouldAttemptRefresh(error: AxiosError): boolean {\n const { shouldRefreshOnStatus } = getGlobalRequestConfig();\n const status = error.response?.status;\n return typeof status === 'number' && !!shouldRefreshOnStatus?.(status);\n}\n\nasync function retryOnce<T>(\n original: InternalAxiosRequestConfig,\n): Promise<AxiosResponse<T>> {\n const global = getGlobalRequestConfig();\n const retryMax = Math.max(1, global.retryAfterRefresh ?? 1);\n\n const meta = original.meta || (original.meta = {});\n const count = meta._retried ?? 0;\n\n if (count >= retryMax) {\n throw new Error('Max retries after refresh exceeded');\n }\n\n meta._retried = count + 1;\n return instance.request<T>(original);\n}\n\n// ---- response interceptor: 401 -> refresh -> retry ----\ninstance.interceptors.response.use(\n (res) => res,\n async (error: AxiosError) => {\n const global = getGlobalRequestConfig();\n const cfg = (error.config || {}) as InternalAxiosRequestConfig;\n\n // If no strategy or refresh is skipped, do not handle here\n if (cfg.meta?.skipRefresh || !global.auth || !shouldAttemptRefresh(error)) {\n if (shouldAttemptRefresh(error) && !cfg.meta?.skipUnauthorizedHandler) {\n global.onUnauthorized?.();\n }\n return Promise.reject(error);\n }\n\n try {\n await ensureRefreshed(cfg.signal as AbortSignal | undefined);\n const retried = await retryOnce(cfg);\n return retried;\n } catch (refreshErr) {\n global.auth.onRefreshFailed?.(refreshErr);\n if (!cfg.meta?.skipUnauthorizedHandler) {\n global.onUnauthorized?.();\n }\n return Promise.reject(error);\n }\n },\n);\n\n// ---- public/auth helpers on top of base request() ----\n\ntype CredentialsMode = 'auto' | 'always' | 'never';\n\nexport type PublicOptions = { credentials?: CredentialsMode };\nexport type AuthOptions = {\n noRefresh?: boolean;\n credentials?: CredentialsMode;\n};\n\n// Core callable function (default = public)\nexport type RequestFn = <T = unknown>(\n url: string,\n config?: AxiosRequestConfig,\n) => Promise<T>;\n\nasync function baseRequest<T = unknown>(\n url: string,\n config?: AxiosRequestConfig,\n): Promise<T> {\n const res = await instance.request<T>({ url, ...config });\n return res.data;\n}\n\n/**\n * The exported request is both callable and has .public/.auth shortcuts.\n * Calling request(url, config) equals request.public(url, config).\n */\nconst request = ((url: string, config?: AxiosRequestConfig) => {\n return request.public(url, config);\n}) as RequestFn & {\n public: <T = unknown>(\n url: string,\n config?: AxiosRequestConfig & PublicOptions,\n ) => Promise<T>;\n auth: <T = unknown>(\n url: string,\n config?: AxiosRequestConfig & AuthOptions,\n ) => Promise<T>;\n init: <T = unknown>(\n url: string,\n config?: AxiosRequestConfig,\n ) => Promise<T | null>;\n reset: () => void;\n};\n\nrequest.public = async function <T = unknown>(\n url: string,\n config?: AxiosRequestConfig & PublicOptions,\n): Promise<T> {\n const withCredentials = config?.credentials === 'always' ? true : undefined;\n return baseRequest<T>(url, {\n ...config,\n withCredentials,\n meta: {\n ...(config?.meta || {}),\n skipAuth: true,\n skipRefresh: true,\n skipUnauthorizedHandler: true,\n },\n });\n};\n\nrequest.auth = async function <T = unknown>(\n url: string,\n config?: AxiosRequestConfig & AuthOptions,\n): Promise<T> {\n const withCredentials = config?.credentials === 'always' ? true : undefined;\n return baseRequest<T>(url, {\n ...config,\n withCredentials,\n meta: {\n ...(config?.meta || {}),\n ...(config?.noRefresh ? { skipRefresh: true } : {}),\n },\n });\n};\n\nlet didInitSoftRefresh = false;\n\nasync function probe<T>(\n url: string,\n config?: AxiosRequestConfig,\n): Promise<T | null> {\n return request.auth<T>(url, {\n ...config,\n noRefresh: true,\n meta: {\n ...(config?.meta || {}),\n skipUnauthorizedHandler: true,\n },\n });\n}\n\nrequest.init = async function <T = unknown>(\n url: string,\n config?: AxiosRequestConfig & { soft?: boolean },\n): Promise<T | null> {\n try {\n return await probe<T>(url, config);\n } catch {\n const soft = config?.soft ?? true; // default: allow one soft refresh this load\n if (!soft || didInitSoftRefresh) return null;\n\n const auth = getGlobalRequestConfig().auth;\n if (!auth) return null;\n\n try {\n await auth.refresh(config?.signal as AbortSignal | undefined);\n didInitSoftRefresh = true;\n return await probe<T>(url, config);\n } catch {\n return null;\n }\n }\n};\n\nrequest.reset = function () {\n didInitSoftRefresh = false;\n};\n\nexport { request };\nexport type { AxiosRequestConfig } from 'axios';\n","import type { AxiosRequestConfig, InternalAxiosRequestConfig } from 'axios';\n\nexport type ToastFn = (msg: string) => void;\n\nexport interface AuthStrategy {\n /** Attach credentials (e.g., Authorization header) */\n addAuthToRequest: <T extends AxiosRequestConfig | InternalAxiosRequestConfig>(\n config: T,\n ) => T;\n\n /** Refresh credentials; may rely on http-only cookie or token exchange */\n refresh: (signal?: AbortSignal) => Promise<void>;\n\n /** Optional: called when refresh ultimately fails */\n onRefreshFailed?: (reason: unknown) => void;\n\n /** Optional: persist tokens to local storage or app state */\n setToken?: (json: { accessToken?: string; refreshToken?: string }) => void;\n\n /** Optional: clear local credentials */\n clearToken?: () => void;\n}\n\nexport interface GlobalRequestConfig {\n toast?: {\n success?: ToastFn;\n error?: ToastFn;\n };\n baseURL?: string;\n defaultHeaders?: () => Record<string, string>;\n onUnauthorized?: () => void;\n\n /** Pluggable authentication behavior */\n auth?: AuthStrategy;\n\n /** Max retries after a successful refresh (default: 1) */\n retryAfterRefresh?: number;\n\n /** Status codes that should trigger a refresh attempt (default: 401) */\n shouldRefreshOnStatus?: (status: number) => boolean;\n}\n\nconst globalConfig: GlobalRequestConfig = {\n retryAfterRefresh: 1,\n shouldRefreshOnStatus: (s) => s === 401 || s === 419 || s === 440,\n};\n\nexport const setupRequest = (config: GlobalRequestConfig) => {\n Object.assign(globalConfig, config);\n};\n\nexport const updateRequestConfig = (patch: Partial<GlobalRequestConfig>) => {\n Object.assign(globalConfig, patch);\n};\n\nexport const getGlobalRequestConfig = () => globalConfig;\n","import axios, { type AxiosError } from 'axios';\n\nimport { getGlobalRequestConfig, type ToastFn } from './config';\n\nexport type OperateConfig<E> = {\n setOperating?: (loading: boolean) => void;\n formatMessage?: () => string;\n formatReason?: (err: E) => string;\n hideToast?: boolean;\n toast?: {\n success?: ToastFn;\n error?: ToastFn;\n };\n};\n\ntype ApiErrorBody = {\n message?: string;\n error?: string;\n detail?: string;\n errors?: string | string[];\n};\n\nfunction extractAxiosMessage(err: AxiosError<ApiErrorBody>): string {\n const data = err.response?.data;\n\n if (typeof data === 'string') return data;\n\n if (data && typeof data === 'object') {\n const { message, error, detail, errors } = data;\n const merged =\n message ??\n error ??\n detail ??\n (Array.isArray(errors) ? errors.join(', ') : errors);\n if (merged) return merged;\n }\n\n return err.message || 'Unknown error';\n}\n\nexport async function operator<T, E = unknown>(\n request: () => Promise<T>,\n config: OperateConfig<E> = {},\n): Promise<[true, T?] | [false, E?]> {\n const global = getGlobalRequestConfig();\n const {\n setOperating,\n formatMessage,\n formatReason = (err: E) => {\n if (axios.isAxiosError<ApiErrorBody>(err)) {\n return extractAxiosMessage(err);\n }\n if (err instanceof Error) return err.message;\n return String(err ?? 'Unknown error');\n },\n hideToast,\n toast: localToast,\n } = config;\n\n const toast = localToast ?? global.toast;\n\n try {\n setOperating?.(true);\n const res = await request();\n if (!hideToast) toast?.success?.(formatMessage?.() ?? 'Success');\n return [true, res];\n } catch (err) {\n const typed = err as E;\n if (!hideToast) toast?.error?.(formatReason(typed));\n return [false, typed];\n } finally {\n setOperating?.(false);\n }\n}\n","import { AxiosHeaders, type AxiosRequestConfig } from 'axios';\n\nimport type { AuthStrategy } from './config';\nimport {\n memoryStorage,\n localStorageStorage,\n type TokenStorage,\n} from './storage';\n\nfunction addAuthHeader<T extends AxiosRequestConfig>(\n config: T,\n token: string | null,\n): T {\n if (token) {\n config.headers = AxiosHeaders.from({\n ...(config.headers || {}),\n Authorization: `Bearer ${token}`,\n });\n }\n return config;\n}\n\n/**\n * Cookie-based strategy:\n * - Access token lives in app state (memory/storage).\n * - Refresh relies on http-only cookie via a server endpoint.\n */\nexport function createCookieStrategy(opts: {\n storage?: TokenStorage;\n tokenField?: string; // default: \"access_token\"\n refreshPath: string; // e.g., '/auth/refresh'\n}): AuthStrategy {\n const storage = opts.storage ?? memoryStorage;\n const accessKey = opts?.tokenField ?? 'access_token';\n\n return {\n addAuthToRequest<T extends AxiosRequestConfig>(config: T): T {\n return addAuthHeader(config, storage.getAccessToken());\n },\n async refresh(signal?: AbortSignal) {\n const res = await fetch(opts.refreshPath, {\n method: 'POST',\n credentials: 'include',\n headers: {\n Accept: 'application/json',\n },\n signal,\n });\n if (!res.ok) throw new Error(`Refresh failed: ${res.status}`);\n try {\n const json = await res.json();\n if (json?.[accessKey]) {\n storage.setAccessToken(json[accessKey]);\n }\n } catch {\n // Some backends may not return JSON; cookie-only session is fine.\n }\n },\n setToken({ accessToken, refreshToken }) {\n if (accessToken) storage.setAccessToken(accessToken);\n if (refreshToken) storage.setRefreshToken?.(refreshToken);\n },\n clearToken() {\n storage.setAccessToken(null);\n storage.setRefreshToken?.(null);\n },\n };\n}\n\n/**\n * Token-exchange strategy:\n * - Both access and refresh tokens are readable by JS (NOT http-only).\n */\nexport function createTokenStrategy(opts: {\n storage?: TokenStorage;\n tokenField?: string; // default: \"access_token\"\n refreshPath: string;\n}): AuthStrategy {\n const storage = opts.storage ?? localStorageStorage;\n const accessKey = opts?.tokenField ?? 'access_token';\n\n return {\n addAuthToRequest<T extends AxiosRequestConfig>(config: T): T {\n return addAuthHeader(config, storage.getAccessToken());\n },\n async refresh(signal?: AbortSignal) {\n const rt = storage.getRefreshToken?.();\n if (!rt) throw new Error('No refresh token');\n const res = await fetch(opts.refreshPath, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n },\n body: JSON.stringify({ refresh_token: rt }),\n signal,\n });\n if (!res.ok) throw new Error(`Refresh failed: ${res.status}`);\n const json = await res.json();\n if (!json?.[accessKey]) throw new Error('Malformed refresh response');\n storage.setAccessToken(json[accessKey]);\n if (json.refresh_token) storage.setRefreshToken?.(json.refresh_token);\n },\n setToken({ accessToken, refreshToken }) {\n if (accessToken) storage.setAccessToken(accessToken);\n if (refreshToken) storage.setRefreshToken?.(refreshToken);\n },\n clearToken() {\n storage.setAccessToken(null);\n storage.setRefreshToken?.(null);\n },\n };\n}\n","export interface TokenStorage {\n getAccessToken(): string | null;\n setAccessToken(token: string | null): void;\n getRefreshToken?(): string | null;\n setRefreshToken?(token: string | null): void;\n}\n\nexport const memoryStorage: TokenStorage = (() => {\n let access: string | null = null;\n let refresh: string | null = null;\n return {\n getAccessToken: () => access,\n setAccessToken: (t) => (access = t),\n getRefreshToken: () => refresh,\n setRefreshToken: (t) => (refresh = t),\n };\n})();\n\nconst safeLocal = () => {\n try {\n return typeof window !== 'undefined' ? window.localStorage : null;\n } catch {\n return null;\n }\n};\n\nexport const localStorageStorage: TokenStorage = {\n getAccessToken: () => safeLocal()?.getItem('access_token') ?? null,\n setAccessToken: (t) => {\n const ls = safeLocal();\n if (!ls) return;\n if (t) {\n ls.setItem('access_token', t);\n } else {\n ls.removeItem('access_token');\n }\n },\n getRefreshToken: () => safeLocal()?.getItem('refresh_token') ?? null,\n setRefreshToken: (t) => {\n const ls = safeLocal();\n if (!ls) return;\n if (t) {\n ls.setItem('refresh_token', t);\n } else {\n ls.removeItem('refresh_token');\n }\n },\n};\n","import { getGlobalRequestConfig } from './config';\n\nexport async function login(\n perform: () => Promise<{ accessToken?: string; refreshToken?: string }>,\n) {\n const auth = getGlobalRequestConfig().auth;\n const json = await perform();\n auth?.setToken?.(json);\n return json;\n}\n\nexport async function logout<T>(perform?: () => Promise<T>) {\n const auth = getGlobalRequestConfig().auth;\n try {\n if (perform) await perform();\n } finally {\n auth?.clearToken?.();\n }\n}\n"],"mappings":"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","names":["e","axios","request","axios","AxiosHeaders","AxiosHeaders","_a","_b"]}

@@ -32,6 +32,9 @@ "use strict";

const [error, setError] = (0, import_react.useState)(null);
const [loading, setLoading] = (0, import_react.useState)(false);
const [status, setStatus] = (0, import_react.useState)(
(opts == null ? void 0 : opts.lazy) ? "idle" : initialValue === void 0 ? "loading" : "idle"
);
const abortRef = (0, import_react.useRef)(null);
const mountedRef = (0, import_react.useRef)(true);
(0, import_react.useEffect)(() => {
mountedRef.current = true;
return () => {

@@ -49,3 +52,3 @@ var _a;

if (mountedRef.current) {
setLoading(true);
setStatus("loading");
setError(null);

@@ -55,16 +58,17 @@ }

const res = await request(ctrl.signal);
if (!mountedRef.current || ctrl.signal.aborted)
const isStale = !mountedRef.current || ctrl.signal.aborted || abortRef.current !== ctrl;
if (isStale)
return res;
setData(res);
setStatus("success");
return res;
} catch (e) {
const isCanceled = (e == null ? void 0 : e.name) === "AbortError" || (e == null ? void 0 : e.name) === "CanceledError" || (e == null ? void 0 : e.code) === "ERR_CANCELED";
if (!isCanceled && mountedRef.current && !ctrl.signal.aborted) {
setError(e);
const isStale = !mountedRef.current || ctrl.signal.aborted || abortRef.current !== ctrl;
if (isCanceled || isStale) {
return void 0;
}
setError(e);
setStatus("error");
throw e;
} finally {
if (mountedRef.current && !ctrl.signal.aborted) {
setLoading(false);
}
}

@@ -81,6 +85,12 @@ }, deps);

}, [run]);
return { data, error, loading, run, abort: () => {
var _a;
return (_a = abortRef.current) == null ? void 0 : _a.abort();
} };
return {
data,
error,
loading: status === "loading",
run,
abort: () => {
var _a;
return (_a = abortRef.current) == null ? void 0 : _a.abort();
}
};
}

@@ -87,0 +97,0 @@ // Annotate the CommonJS export names for ESM import in node:

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/react/index.ts","../src/react/use-request.ts"],"sourcesContent":["export * from './use-request';\n","import { useState, useRef, useEffect, useCallback } from 'react';\n\nexport function useRequest<T, E = unknown>(\n request: (signal: AbortSignal) => Promise<T>,\n deps: React.DependencyList = [],\n initialValue?: T,\n opts?: { lazy?: boolean },\n) {\n const [data, setData] = useState<T | undefined>(initialValue);\n const [error, setError] = useState<E | null>(null);\n const [loading, setLoading] = useState(false);\n\n const abortRef = useRef<AbortController | null>(null);\n const mountedRef = useRef(true);\n\n // Track mounted state to avoid state updates after unmount\n useEffect(() => {\n return () => {\n mountedRef.current = false;\n abortRef.current?.abort();\n };\n }, []);\n\n const run = useCallback(async () => {\n abortRef.current?.abort();\n const ctrl = new AbortController();\n abortRef.current = ctrl;\n\n if (mountedRef.current) {\n setLoading(true);\n setError(null);\n }\n\n try {\n const res = await request(ctrl.signal);\n\n // Guard: do not update state if aborted or unmounted\n if (!mountedRef.current || ctrl.signal.aborted) return res;\n\n setData(res);\n return res;\n } catch (e) {\n const isCanceled =\n (e as { name: string })?.name === 'AbortError' ||\n (e as { name: string })?.name === 'CanceledError' ||\n (e as { code: string })?.code === 'ERR_CANCELED';\n\n if (!isCanceled && mountedRef.current && !ctrl.signal.aborted) {\n setError(e as E);\n }\n throw e;\n } finally {\n if (mountedRef.current && !ctrl.signal.aborted) {\n setLoading(false);\n }\n }\n }, deps);\n\n useEffect(() => {\n if (!opts?.lazy) {\n run();\n return () => abortRef.current?.abort();\n }\n }, [run]);\n\n return { data, error, loading, run, abort: () => abortRef.current?.abort() };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAAyD;AAElD,SAAS,WACd,SACA,OAA6B,CAAC,GAC9B,cACA,MACA;AACA,QAAM,CAAC,MAAM,OAAO,QAAI,uBAAwB,YAAY;AAC5D,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAmB,IAAI;AACjD,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAS,KAAK;AAE5C,QAAM,eAAW,qBAA+B,IAAI;AACpD,QAAM,iBAAa,qBAAO,IAAI;AAG9B,8BAAU,MAAM;AACd,WAAO,MAAM;AAjBjB;AAkBM,iBAAW,UAAU;AACrB,qBAAS,YAAT,mBAAkB;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,UAAM,0BAAY,YAAY;AAvBtC;AAwBI,mBAAS,YAAT,mBAAkB;AAClB,UAAM,OAAO,IAAI,gBAAgB;AACjC,aAAS,UAAU;AAEnB,QAAI,WAAW,SAAS;AACtB,iBAAW,IAAI;AACf,eAAS,IAAI;AAAA,IACf;AAEA,QAAI;AACF,YAAM,MAAM,MAAM,QAAQ,KAAK,MAAM;AAGrC,UAAI,CAAC,WAAW,WAAW,KAAK,OAAO;AAAS,eAAO;AAEvD,cAAQ,GAAG;AACX,aAAO;AAAA,IACT,SAAS,GAAG;AACV,YAAM,cACH,uBAAwB,UAAS,iBACjC,uBAAwB,UAAS,oBACjC,uBAAwB,UAAS;AAEpC,UAAI,CAAC,cAAc,WAAW,WAAW,CAAC,KAAK,OAAO,SAAS;AAC7D,iBAAS,CAAM;AAAA,MACjB;AACA,YAAM;AAAA,IACR,UAAE;AACA,UAAI,WAAW,WAAW,CAAC,KAAK,OAAO,SAAS;AAC9C,mBAAW,KAAK;AAAA,MAClB;AAAA,IACF;AAAA,EACF,GAAG,IAAI;AAEP,8BAAU,MAAM;AACd,QAAI,EAAC,6BAAM,OAAM;AACf,UAAI;AACJ,aAAO,MAAG;AA7DhB;AA6DmB,8BAAS,YAAT,mBAAkB;AAAA;AAAA,IACjC;AAAA,EACF,GAAG,CAAC,GAAG,CAAC;AAER,SAAO,EAAE,MAAM,OAAO,SAAS,KAAK,OAAO,MAAG;AAjEhD;AAiEmD,0BAAS,YAAT,mBAAkB;AAAA,IAAQ;AAC7E;","names":[]}
{"version":3,"sources":["../src/react/index.ts","../src/react/use-request.ts"],"sourcesContent":["export { useRequest } from './use-request';\n","import { useState, useRef, useEffect, useCallback } from 'react';\n\ntype Status = 'idle' | 'loading' | 'success' | 'error';\n\nexport function useRequest<T, E = unknown>(\n request: (signal: AbortSignal) => Promise<T>,\n deps: React.DependencyList = [],\n initialValue?: T,\n opts?: { lazy?: boolean },\n) {\n const [data, setData] = useState<T | undefined>(initialValue);\n const [error, setError] = useState<E | null>(null);\n const [status, setStatus] = useState<Status>(\n opts?.lazy ? 'idle' : initialValue === undefined ? 'loading' : 'idle',\n );\n\n const abortRef = useRef<AbortController | null>(null);\n const mountedRef = useRef(true);\n\n // Track mounted state to avoid state updates after unmount\n useEffect(() => {\n mountedRef.current = true;\n\n return () => {\n mountedRef.current = false;\n abortRef.current?.abort();\n };\n }, []);\n\n const run = useCallback(async () => {\n abortRef.current?.abort();\n const ctrl = new AbortController();\n abortRef.current = ctrl;\n\n if (mountedRef.current) {\n setStatus('loading');\n setError(null);\n }\n\n try {\n const res = await request(ctrl.signal);\n\n // stale or canceled -> do not write\n const isStale =\n !mountedRef.current || ctrl.signal.aborted || abortRef.current !== ctrl;\n if (isStale) return res;\n\n setData(res);\n setStatus('success');\n return res;\n } catch (e) {\n const isCanceled =\n (e as { name?: string })?.name === 'AbortError' ||\n (e as { name?: string })?.name === 'CanceledError' ||\n (e as { code?: string })?.code === 'ERR_CANCELED';\n\n const isStale =\n !mountedRef.current || ctrl.signal.aborted || abortRef.current !== ctrl;\n\n if (isCanceled || isStale) {\n // swallow cancellations/stale completions; keep current status\n return undefined as unknown as T;\n }\n\n // real error (current generation)\n setError(e as E);\n setStatus('error');\n throw e;\n }\n }, deps);\n\n useEffect(() => {\n if (!opts?.lazy) {\n run();\n return () => abortRef.current?.abort();\n }\n }, [run]);\n\n return {\n data,\n error,\n loading: status === 'loading',\n run,\n abort: () => abortRef.current?.abort(),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAAyD;AAIlD,SAAS,WACd,SACA,OAA6B,CAAC,GAC9B,cACA,MACA;AACA,QAAM,CAAC,MAAM,OAAO,QAAI,uBAAwB,YAAY;AAC5D,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAmB,IAAI;AACjD,QAAM,CAAC,QAAQ,SAAS,QAAI;AAAA,KAC1B,6BAAM,QAAO,SAAS,iBAAiB,SAAY,YAAY;AAAA,EACjE;AAEA,QAAM,eAAW,qBAA+B,IAAI;AACpD,QAAM,iBAAa,qBAAO,IAAI;AAG9B,8BAAU,MAAM;AACd,eAAW,UAAU;AAErB,WAAO,MAAM;AAvBjB;AAwBM,iBAAW,UAAU;AACrB,qBAAS,YAAT,mBAAkB;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,UAAM,0BAAY,YAAY;AA7BtC;AA8BI,mBAAS,YAAT,mBAAkB;AAClB,UAAM,OAAO,IAAI,gBAAgB;AACjC,aAAS,UAAU;AAEnB,QAAI,WAAW,SAAS;AACtB,gBAAU,SAAS;AACnB,eAAS,IAAI;AAAA,IACf;AAEA,QAAI;AACF,YAAM,MAAM,MAAM,QAAQ,KAAK,MAAM;AAGrC,YAAM,UACJ,CAAC,WAAW,WAAW,KAAK,OAAO,WAAW,SAAS,YAAY;AACrE,UAAI;AAAS,eAAO;AAEpB,cAAQ,GAAG;AACX,gBAAU,SAAS;AACnB,aAAO;AAAA,IACT,SAAS,GAAG;AACV,YAAM,cACH,uBAAyB,UAAS,iBAClC,uBAAyB,UAAS,oBAClC,uBAAyB,UAAS;AAErC,YAAM,UACJ,CAAC,WAAW,WAAW,KAAK,OAAO,WAAW,SAAS,YAAY;AAErE,UAAI,cAAc,SAAS;AAEzB,eAAO;AAAA,MACT;AAGA,eAAS,CAAM;AACf,gBAAU,OAAO;AACjB,YAAM;AAAA,IACR;AAAA,EACF,GAAG,IAAI;AAEP,8BAAU,MAAM;AACd,QAAI,EAAC,6BAAM,OAAM;AACf,UAAI;AACJ,aAAO,MAAG;AA1EhB;AA0EmB,8BAAS,YAAT,mBAAkB;AAAA;AAAA,IACjC;AAAA,EACF,GAAG,CAAC,GAAG,CAAC;AAER,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,SAAS,WAAW;AAAA,IACpB;AAAA,IACA,OAAO,MAAG;AAnFd;AAmFiB,4BAAS,YAAT,mBAAkB;AAAA;AAAA,EACjC;AACF;","names":[]}

@@ -6,6 +6,9 @@ // src/react/use-request.ts

const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
const [status, setStatus] = useState(
(opts == null ? void 0 : opts.lazy) ? "idle" : initialValue === void 0 ? "loading" : "idle"
);
const abortRef = useRef(null);
const mountedRef = useRef(true);
useEffect(() => {
mountedRef.current = true;
return () => {

@@ -23,3 +26,3 @@ var _a;

if (mountedRef.current) {
setLoading(true);
setStatus("loading");
setError(null);

@@ -29,16 +32,17 @@ }

const res = await request(ctrl.signal);
if (!mountedRef.current || ctrl.signal.aborted)
const isStale = !mountedRef.current || ctrl.signal.aborted || abortRef.current !== ctrl;
if (isStale)
return res;
setData(res);
setStatus("success");
return res;
} catch (e) {
const isCanceled = (e == null ? void 0 : e.name) === "AbortError" || (e == null ? void 0 : e.name) === "CanceledError" || (e == null ? void 0 : e.code) === "ERR_CANCELED";
if (!isCanceled && mountedRef.current && !ctrl.signal.aborted) {
setError(e);
const isStale = !mountedRef.current || ctrl.signal.aborted || abortRef.current !== ctrl;
if (isCanceled || isStale) {
return void 0;
}
setError(e);
setStatus("error");
throw e;
} finally {
if (mountedRef.current && !ctrl.signal.aborted) {
setLoading(false);
}
}

@@ -55,6 +59,12 @@ }, deps);

}, [run]);
return { data, error, loading, run, abort: () => {
var _a;
return (_a = abortRef.current) == null ? void 0 : _a.abort();
} };
return {
data,
error,
loading: status === "loading",
run,
abort: () => {
var _a;
return (_a = abortRef.current) == null ? void 0 : _a.abort();
}
};
}

@@ -61,0 +71,0 @@ export {

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/react/use-request.ts"],"sourcesContent":["import { useState, useRef, useEffect, useCallback } from 'react';\n\nexport function useRequest<T, E = unknown>(\n request: (signal: AbortSignal) => Promise<T>,\n deps: React.DependencyList = [],\n initialValue?: T,\n opts?: { lazy?: boolean },\n) {\n const [data, setData] = useState<T | undefined>(initialValue);\n const [error, setError] = useState<E | null>(null);\n const [loading, setLoading] = useState(false);\n\n const abortRef = useRef<AbortController | null>(null);\n const mountedRef = useRef(true);\n\n // Track mounted state to avoid state updates after unmount\n useEffect(() => {\n return () => {\n mountedRef.current = false;\n abortRef.current?.abort();\n };\n }, []);\n\n const run = useCallback(async () => {\n abortRef.current?.abort();\n const ctrl = new AbortController();\n abortRef.current = ctrl;\n\n if (mountedRef.current) {\n setLoading(true);\n setError(null);\n }\n\n try {\n const res = await request(ctrl.signal);\n\n // Guard: do not update state if aborted or unmounted\n if (!mountedRef.current || ctrl.signal.aborted) return res;\n\n setData(res);\n return res;\n } catch (e) {\n const isCanceled =\n (e as { name: string })?.name === 'AbortError' ||\n (e as { name: string })?.name === 'CanceledError' ||\n (e as { code: string })?.code === 'ERR_CANCELED';\n\n if (!isCanceled && mountedRef.current && !ctrl.signal.aborted) {\n setError(e as E);\n }\n throw e;\n } finally {\n if (mountedRef.current && !ctrl.signal.aborted) {\n setLoading(false);\n }\n }\n }, deps);\n\n useEffect(() => {\n if (!opts?.lazy) {\n run();\n return () => abortRef.current?.abort();\n }\n }, [run]);\n\n return { data, error, loading, run, abort: () => abortRef.current?.abort() };\n}\n"],"mappings":";AAAA,SAAS,UAAU,QAAQ,WAAW,mBAAmB;AAElD,SAAS,WACd,SACA,OAA6B,CAAC,GAC9B,cACA,MACA;AACA,QAAM,CAAC,MAAM,OAAO,IAAI,SAAwB,YAAY;AAC5D,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAmB,IAAI;AACjD,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAE5C,QAAM,WAAW,OAA+B,IAAI;AACpD,QAAM,aAAa,OAAO,IAAI;AAG9B,YAAU,MAAM;AACd,WAAO,MAAM;AAjBjB;AAkBM,iBAAW,UAAU;AACrB,qBAAS,YAAT,mBAAkB;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,MAAM,YAAY,YAAY;AAvBtC;AAwBI,mBAAS,YAAT,mBAAkB;AAClB,UAAM,OAAO,IAAI,gBAAgB;AACjC,aAAS,UAAU;AAEnB,QAAI,WAAW,SAAS;AACtB,iBAAW,IAAI;AACf,eAAS,IAAI;AAAA,IACf;AAEA,QAAI;AACF,YAAM,MAAM,MAAM,QAAQ,KAAK,MAAM;AAGrC,UAAI,CAAC,WAAW,WAAW,KAAK,OAAO;AAAS,eAAO;AAEvD,cAAQ,GAAG;AACX,aAAO;AAAA,IACT,SAAS,GAAG;AACV,YAAM,cACH,uBAAwB,UAAS,iBACjC,uBAAwB,UAAS,oBACjC,uBAAwB,UAAS;AAEpC,UAAI,CAAC,cAAc,WAAW,WAAW,CAAC,KAAK,OAAO,SAAS;AAC7D,iBAAS,CAAM;AAAA,MACjB;AACA,YAAM;AAAA,IACR,UAAE;AACA,UAAI,WAAW,WAAW,CAAC,KAAK,OAAO,SAAS;AAC9C,mBAAW,KAAK;AAAA,MAClB;AAAA,IACF;AAAA,EACF,GAAG,IAAI;AAEP,YAAU,MAAM;AACd,QAAI,EAAC,6BAAM,OAAM;AACf,UAAI;AACJ,aAAO,MAAG;AA7DhB;AA6DmB,8BAAS,YAAT,mBAAkB;AAAA;AAAA,IACjC;AAAA,EACF,GAAG,CAAC,GAAG,CAAC;AAER,SAAO,EAAE,MAAM,OAAO,SAAS,KAAK,OAAO,MAAG;AAjEhD;AAiEmD,0BAAS,YAAT,mBAAkB;AAAA,IAAQ;AAC7E;","names":[]}
{"version":3,"sources":["../src/react/use-request.ts"],"sourcesContent":["import { useState, useRef, useEffect, useCallback } from 'react';\n\ntype Status = 'idle' | 'loading' | 'success' | 'error';\n\nexport function useRequest<T, E = unknown>(\n request: (signal: AbortSignal) => Promise<T>,\n deps: React.DependencyList = [],\n initialValue?: T,\n opts?: { lazy?: boolean },\n) {\n const [data, setData] = useState<T | undefined>(initialValue);\n const [error, setError] = useState<E | null>(null);\n const [status, setStatus] = useState<Status>(\n opts?.lazy ? 'idle' : initialValue === undefined ? 'loading' : 'idle',\n );\n\n const abortRef = useRef<AbortController | null>(null);\n const mountedRef = useRef(true);\n\n // Track mounted state to avoid state updates after unmount\n useEffect(() => {\n mountedRef.current = true;\n\n return () => {\n mountedRef.current = false;\n abortRef.current?.abort();\n };\n }, []);\n\n const run = useCallback(async () => {\n abortRef.current?.abort();\n const ctrl = new AbortController();\n abortRef.current = ctrl;\n\n if (mountedRef.current) {\n setStatus('loading');\n setError(null);\n }\n\n try {\n const res = await request(ctrl.signal);\n\n // stale or canceled -> do not write\n const isStale =\n !mountedRef.current || ctrl.signal.aborted || abortRef.current !== ctrl;\n if (isStale) return res;\n\n setData(res);\n setStatus('success');\n return res;\n } catch (e) {\n const isCanceled =\n (e as { name?: string })?.name === 'AbortError' ||\n (e as { name?: string })?.name === 'CanceledError' ||\n (e as { code?: string })?.code === 'ERR_CANCELED';\n\n const isStale =\n !mountedRef.current || ctrl.signal.aborted || abortRef.current !== ctrl;\n\n if (isCanceled || isStale) {\n // swallow cancellations/stale completions; keep current status\n return undefined as unknown as T;\n }\n\n // real error (current generation)\n setError(e as E);\n setStatus('error');\n throw e;\n }\n }, deps);\n\n useEffect(() => {\n if (!opts?.lazy) {\n run();\n return () => abortRef.current?.abort();\n }\n }, [run]);\n\n return {\n data,\n error,\n loading: status === 'loading',\n run,\n abort: () => abortRef.current?.abort(),\n };\n}\n"],"mappings":";AAAA,SAAS,UAAU,QAAQ,WAAW,mBAAmB;AAIlD,SAAS,WACd,SACA,OAA6B,CAAC,GAC9B,cACA,MACA;AACA,QAAM,CAAC,MAAM,OAAO,IAAI,SAAwB,YAAY;AAC5D,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAmB,IAAI;AACjD,QAAM,CAAC,QAAQ,SAAS,IAAI;AAAA,KAC1B,6BAAM,QAAO,SAAS,iBAAiB,SAAY,YAAY;AAAA,EACjE;AAEA,QAAM,WAAW,OAA+B,IAAI;AACpD,QAAM,aAAa,OAAO,IAAI;AAG9B,YAAU,MAAM;AACd,eAAW,UAAU;AAErB,WAAO,MAAM;AAvBjB;AAwBM,iBAAW,UAAU;AACrB,qBAAS,YAAT,mBAAkB;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,MAAM,YAAY,YAAY;AA7BtC;AA8BI,mBAAS,YAAT,mBAAkB;AAClB,UAAM,OAAO,IAAI,gBAAgB;AACjC,aAAS,UAAU;AAEnB,QAAI,WAAW,SAAS;AACtB,gBAAU,SAAS;AACnB,eAAS,IAAI;AAAA,IACf;AAEA,QAAI;AACF,YAAM,MAAM,MAAM,QAAQ,KAAK,MAAM;AAGrC,YAAM,UACJ,CAAC,WAAW,WAAW,KAAK,OAAO,WAAW,SAAS,YAAY;AACrE,UAAI;AAAS,eAAO;AAEpB,cAAQ,GAAG;AACX,gBAAU,SAAS;AACnB,aAAO;AAAA,IACT,SAAS,GAAG;AACV,YAAM,cACH,uBAAyB,UAAS,iBAClC,uBAAyB,UAAS,oBAClC,uBAAyB,UAAS;AAErC,YAAM,UACJ,CAAC,WAAW,WAAW,KAAK,OAAO,WAAW,SAAS,YAAY;AAErE,UAAI,cAAc,SAAS;AAEzB,eAAO;AAAA,MACT;AAGA,eAAS,CAAM;AACf,gBAAU,OAAO;AACjB,YAAM;AAAA,IACR;AAAA,EACF,GAAG,IAAI;AAEP,YAAU,MAAM;AACd,QAAI,EAAC,6BAAM,OAAM;AACf,UAAI;AACJ,aAAO,MAAG;AA1EhB;AA0EmB,8BAAS,YAAT,mBAAkB;AAAA;AAAA,IACjC;AAAA,EACF,GAAG,CAAC,GAAG,CAAC;AAER,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,SAAS,WAAW;AAAA,IACpB;AAAA,IACA,OAAO,MAAG;AAnFd;AAmFiB,4BAAS,YAAT,mBAAkB;AAAA;AAAA,EACjC;AACF;","names":[]}
{
"name": "@mints/request",
"packageManager": "yarn@4.9.2",
"version": "2.0.0",
"version": "2.1.0",
"type": "module",

@@ -6,0 +6,0 @@ "description": "A lightweight Axios + operation wrapper with global config and toast integration",

@@ -16,2 +16,3 @@ # @mints/request

- ✅ **React hook `useRequest`** for automatic requests with cancellation
- ✅ Helper functions `login` / `logout` for auto token management
- ✅ Minimal dependencies, framework agnostic (core) + optional React add-on

@@ -48,2 +49,3 @@

refreshPath: '/auth/refresh',
tokenField: 'jwt', // default: "access_token"
}),

@@ -56,4 +58,5 @@ onUnauthorized: () => {

- By default `createCookieStrategy` stores `access_token` in memory (`memoryStorage`).
- By default `createCookieStrategy` stores `token` in memory (`memoryStorage`).
- You can pass a custom `storage` (e.g. `localStorageStorage`) if persistence is needed.
- Default refresh status codes: `401, 419, 440`.

@@ -71,2 +74,4 @@ ---

const users = await request('/users');
// or
const users = await request.public('/users');

@@ -79,2 +84,4 @@ // Authenticated API

- `request.auth(url, config)` → includes auth, retries after refresh if needed.
- `request.init(url, { soft?: boolean })` → probe request, optional `soft=true` skips refresh.
- `request.reset(url)` → reset probe state.

@@ -95,2 +102,13 @@ ---

### 🔹 Token management helpers
```ts
import { login, logout } from '@mints/request/auth';
await login(() => API.auth.login(form));
await logout(() => API.auth.logout());
```
---
## 🚀 Usage (React Add-on)

@@ -138,3 +156,3 @@

retryAfterRefresh?: number; // default 1
shouldRefreshOnStatus?: (status: number) => boolean; // default: 401
shouldRefreshOnStatus?: (status: number) => boolean; // default: 401, 419, 440
};

@@ -208,2 +226,3 @@ ```

- Use `request.init` for probe token
- Use `request.public` for endpoints that don't require auth.

@@ -210,0 +229,0 @@ - Use `request.auth` for APIs with tokens; retries are automatic.