'use strict'; const ofetch = require('ofetch'); const hookable = require('hookable'); const defu = require('defu'); function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; } const defu__default = /*#__PURE__*/_interopDefaultCompat(defu); function createHeaders(init, hookCallback) { const _headers = { "Content-Type": "application/json" }; const handler = { get: (target, prop) => { if (prop === "apply") { return apply; } return Reflect.get(target, prop); }, set: (target, prop, value) => { if (prop === "apply") { throw new Error("Cannot override apply method"); } hookCallback?.(prop, value); return Reflect.set(target, prop, value); }, deleteProperty: (target, prop) => { hookCallback?.(prop); return Reflect.deleteProperty(target, prop); } }; const headersProxy = new Proxy( _headers, handler ); function apply(headers) { for (const [key, value] of Object.entries(headers)) { if (value) { headersProxy[key] = value; } else { delete headersProxy[key]; } } } headersProxy.apply({ ...init }); return headersProxy; } var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; class ApiClientError extends Error { constructor(response) { let message = "Failed request"; const errorDetails = response._data || { errors: [ { title: "Unknown error", detail: "API did not return errors, but request failed. Please check the network tab." } ] }; message += errorDetails.errors?.reduce((message2, error) => { let pointer = ""; if (error.source?.pointer) { pointer = `[${error.source.pointer}]`; } const details = error.detail ?? "No error details provided."; return `${message2} - [${error.title}]${pointer} ${details}`; }, "") ?? ""; super(message); /** * Flag to indicate if the request was successful. */ __publicField(this, "ok"); /** * HTTP status code of the response. */ __publicField(this, "status"); /** * HTTP status text of the response. */ __publicField(this, "statusText"); /** * URL of the request. */ __publicField(this, "url"); /** * Details of the error. */ __publicField(this, "details"); /** * Headers of the response. */ __publicField(this, "headers"); this.name = "ApiClientError"; this.details = errorDetails; this.ok = response.ok; this.status = response.status; this.statusText = response.statusText; this.url = response.url; this.headers = response.headers; } } function errorInterceptor(response) { throw new ApiClientError(response); } function createPathWithParams(requestPath, pathParams) { return Object.keys(pathParams || {}).reduce((acc, paramName) => { return acc.replace(`{${paramName}}`, pathParams[paramName]); }, requestPath); } function createAPIClient(params) { const apiClientHooks = hookable.createHooks(); const defaultHeaders = createHeaders( { "sw-access-key": params.accessToken, accept: "application/json", "sw-context-token": params.contextToken, ...params.defaultHeaders }, (key, value) => { apiClientHooks.callHook("onDefaultHeaderChanged", key, value); if (key === "sw-context-token") { apiClientHooks.callHook("onContextChanged", value); } } ); const apiFetch = ofetch.ofetch.create({ baseURL: params.baseURL, // async onRequest({ request, options }) {}, // async onRequestError({ request, options, error }) {}, async onResponse(context) { apiClientHooks.callHook("onSuccessResponse", context.response); if (context.response.headers.has("sw-context-token") && defaultHeaders["sw-context-token"] !== context.response.headers.get("sw-context-token")) { const newContextToken = context.response.headers.get( "sw-context-token" ); defaultHeaders["sw-context-token"] = newContextToken; } }, async onResponseError({ response }) { apiClientHooks.callHook("onResponseError", response); errorInterceptor(response); } }); async function invoke(pathParam, ...params2) { const [, method, requestPath] = pathParam.split(" "); const currentParams = params2[0] || {}; const requestPathWithParams = createPathWithParams( requestPath, currentParams.pathParams ); const fetchOptions = { ...currentParams.fetchOptions || {} }; let mergedHeaders = defu__default(currentParams.headers, defaultHeaders); if (mergedHeaders?.["Content-Type"]?.includes("multipart/form-data") && typeof window !== "undefined") { delete mergedHeaders["Content-Type"]; } const resp = await apiFetch.raw(requestPathWithParams, { ...fetchOptions, method, body: currentParams.body, headers: mergedHeaders, query: currentParams.query }); return { data: resp._data, status: resp.status }; } return { invoke, /** * Default headers used in every client request (if not overriden in specific request). */ defaultHeaders, hook: apiClientHooks.hook }; } function createAuthorizationHeader(token) { if (!token) return ""; if (token.startsWith("Bearer ")) return token; return `Bearer ${token}`; } function createAdminAPIClient(params) { const isTokenBasedAuth = params.credentials?.grant_type === "client_credentials"; const apiClientHooks = hookable.createHooks(); const sessionData = { accessToken: params.sessionData?.accessToken || "", refreshToken: params.sessionData?.refreshToken || "", expirationTime: Number(params.sessionData?.expirationTime || 0) }; const defaultHeaders = createHeaders( { Authorization: createAuthorizationHeader(sessionData.accessToken), Accept: "application/json" }, (key, value) => { apiClientHooks.callHook("onDefaultHeaderChanged", key, value); } ); function getSessionData() { return { ...sessionData }; } function setSessionData(data) { sessionData.accessToken = data.accessToken; sessionData.refreshToken = data.refreshToken || ""; sessionData.expirationTime = data.expirationTime; return getSessionData(); } function updateSessionData(responseData) { if (responseData?.access_token) { defaultHeaders.Authorization = createAuthorizationHeader( responseData.access_token ); const dataCopy = setSessionData({ accessToken: responseData.access_token, refreshToken: responseData.refresh_token, expirationTime: Date.now() + responseData.expires_in * 1e3 }); apiClientHooks.callHook("onAuthChange", dataCopy); } } const apiFetch = ofetch.ofetch.create({ baseURL: params.baseURL, async onRequest({ request, options }) { const isExpired = sessionData.expirationTime <= Date.now(); if (isExpired && !request.toString().includes("/oauth/token")) { if (!params.credentials && !isTokenBasedAuth && !sessionData.refreshToken) { console.warn( "[ApiClientWarning] No `credentials` or `sessionData` provided. Provide at least one of them to ensure authentication." ); } const body = params.credentials && !sessionData.refreshToken ? params.credentials : { grant_type: "refresh_token", client_id: "administration", refresh_token: sessionData.refreshToken }; await ofetch.ofetch("/oauth/token", { baseURL: params.baseURL, method: "POST", body, headers: defaultHeaders, onResponseError({ response }) { errorInterceptor(response); }, onResponse(context) { if (!context.response._data) return; updateSessionData(context.response._data); options.headers.set( "Authorization", createAuthorizationHeader(sessionData.accessToken) ); } }); } }, async onResponse(context) { apiClientHooks.callHook("onSuccessResponse", context.response); updateSessionData(context.response._data); }, async onResponseError({ response }) { apiClientHooks.callHook("onResponseError", response); errorInterceptor(response); } }); async function invoke(pathParam, ...params2) { const [, method, requestPath] = pathParam.split(" "); const currentParams = params2[0] || {}; const requestPathWithParams = createPathWithParams( requestPath, currentParams.pathParams ); const fetchOptions = { ...currentParams.fetchOptions || {} }; const resp = await apiFetch.raw(requestPathWithParams, { ...fetchOptions, method, body: currentParams.body, headers: defu__default(currentParams.headers, defaultHeaders), query: currentParams.query }); return { data: resp._data, status: resp.status }; } return { invoke, /** * Enables to change session data in runtime. Useful for testing purposes. * Setting session data with this method will **not** fire `onAuthChange` hook. */ setSessionData, /** * Returns current session data. Useful for testing purposes, as in most cases you'll want to use `onAuthChange` hook for that. */ getSessionData, /** * Default headers used in every client request (if not overriden in specific request). */ defaultHeaders, /** * Available hooks for the client. */ hook: apiClientHooks.hook }; } exports.ApiClientError = ApiClientError; exports.createAPIClient = createAPIClient; exports.createAdminAPIClient = createAdminAPIClient;