UNPKG

@nvs-pinia/common

Version:

NVS Pinia collection shared logic

324 lines (310 loc) 11.4 kB
import axios from 'axios'; import { ref, computed } from 'vue'; import { defineStore } from 'pinia'; var API_LOCALE_PLACEMENT; (function (API_LOCALE_PLACEMENT) { API_LOCALE_PLACEMENT["HEADER"] = "header"; API_LOCALE_PLACEMENT["PARAM"] = "param"; })(API_LOCALE_PLACEMENT || (API_LOCALE_PLACEMENT = {})); var REQUEST_TOKEN$1; (function (REQUEST_TOKEN) { REQUEST_TOKEN[REQUEST_TOKEN["ANONYMOUS"] = 0] = "ANONYMOUS"; REQUEST_TOKEN[REQUEST_TOKEN["OPTIONAL"] = 1] = "OPTIONAL"; REQUEST_TOKEN[REQUEST_TOKEN["SECURE"] = 2] = "SECURE"; })(REQUEST_TOKEN$1 || (REQUEST_TOKEN$1 = {})); var ROLE$1; (function (ROLE) { ROLE[ROLE["ANONYMOUS"] = 0] = "ANONYMOUS"; ROLE[ROLE["USER"] = 1] = "USER"; })(ROLE$1 || (ROLE$1 = {})); [REQUEST_TOKEN$1.OPTIONAL, REQUEST_TOKEN$1.SECURE]; const ACCESS_TOKEN_KEY = 'mDo7fVhH1uXP50GLhf'; const REFRESH_TOKEN_KEY = 'NYks3AnZSdMTbc5pOy'; const IMPERSONATING_KEY = '45881f327ea4'; const USER_KEY = 'user'; var ROLE; (function (ROLE) { ROLE[ROLE["ANONYMOUS"] = 0] = "ANONYMOUS"; ROLE[ROLE["USER"] = 1] = "USER"; })(ROLE || (ROLE = {})); var REQUEST_TOKEN; (function (REQUEST_TOKEN) { REQUEST_TOKEN[REQUEST_TOKEN["ANONYMOUS"] = 0] = "ANONYMOUS"; REQUEST_TOKEN[REQUEST_TOKEN["OPTIONAL"] = 1] = "OPTIONAL"; REQUEST_TOKEN[REQUEST_TOKEN["SECURE"] = 2] = "SECURE"; })(REQUEST_TOKEN || (REQUEST_TOKEN = {})); const SECURE_CONFIG_PARAM_VARIANTS = [REQUEST_TOKEN.OPTIONAL, REQUEST_TOKEN.SECURE]; // Vvendor const useApiSettings = defineStore('pc-api-settings', () => { const locale = ref(null); return { locale, }; }, { persist: true, }); // Vendor const useContextStore = defineStore('context', {}); // Vendor const useAuthentication = defineStore('authentication', () => { // Composable const { $api, $endpoints } = useContextStore(); // Refs const accessToken = ref(null); const refreshToken = ref(null); const role = ref(ROLE.ANONYMOUS); const impersonatedUser = ref(undefined); // Computed const isAuthenticated = computed(() => role.value > ROLE.ANONYMOUS); const isImpersonating = computed(() => !!impersonatedUser.value); // Methods async function authenticate(options) { const { password, userField = 'email', username } = options; const response = await $api .post($endpoints.LOGIN, { [userField]: username, password, }) .catch((error) => Promise.reject(error)); const { data } = response; if (data) { startSession(data, ROLE.USER); return data; } return null; } async function refreshAuthentication() { if (!refreshToken.value) { return Promise.reject({ message: 'No refresh token found', status: 401, }); } const response = await $api .post($endpoints.TOKEN_REFRESH, { refresh_token: refreshToken.value, }) .catch((error) => Promise.reject(error)); const { data } = response; if (data) { startSession(data, ROLE.USER); return data; } return null; } async function removeSession() { role.value = ROLE.ANONYMOUS; accessToken.value = null; refreshToken.value = null; stopImpersonating(); return role.value; } async function startSession(tokenData, userRole) { role.value = userRole; accessToken.value = tokenData.token; refreshToken.value = tokenData.refresh_token; return role.value; } function startImpersonating(userName) { impersonatedUser.value = userName; } function stopImpersonating() { impersonatedUser.value = undefined; } return { [ACCESS_TOKEN_KEY]: accessToken, [REFRESH_TOKEN_KEY]: refreshToken, [IMPERSONATING_KEY]: impersonatedUser, authenticate, isAuthenticated, isImpersonating, refreshAuthentication, removeSession, role, startSession, startImpersonating, stopImpersonating, }; }, { persist: { key: 'a', paths: [ACCESS_TOKEN_KEY, REFRESH_TOKEN_KEY, IMPERSONATING_KEY, 'role'], }, }); // Vendor function localeSettings(locale) { const _defaultKey = 'locale'; if (!locale) { return null; } if (locale === true) { return { key: _defaultKey, placement: API_LOCALE_PLACEMENT.PARAM, }; } return { key: locale.key || _defaultKey, placement: locale.placement || API_LOCALE_PLACEMENT.PARAM, }; } function createAPI(options) { // Options const { baseURL, impersonateHeader = 'x-switch-user', locale, onSessionExpired, tokenType = 'Bearer', } = options || {}; const _locale = localeSettings(locale); const api = axios.create({ baseURL, }); /** * Interceptors */ api.interceptors.request.use(async (config) => { // Composable const auth = useAuthentication(); const apiSettings = useApiSettings(); const token = auth[ACCESS_TOKEN_KEY]; if ([REQUEST_TOKEN$1.SECURE, REQUEST_TOKEN$1.OPTIONAL].indexOf((config === null || config === void 0 ? void 0 : config.tokenLevel) || 0) !== -1 && token) { config.headers.Authorization = `${tokenType} ${token}`; if (auth.isAuthenticated && auth[IMPERSONATING_KEY]) { config.headers[impersonateHeader] = auth[IMPERSONATING_KEY]; } } if (apiSettings.locale && _locale) { if (_locale.placement === API_LOCALE_PLACEMENT.HEADER) { config.headers[_locale.key] = apiSettings.locale; } if (_locale.placement === API_LOCALE_PLACEMENT.PARAM) { config.params = Object.assign(Object.assign({}, config.params), { [_locale.key]: apiSettings.locale }); } } return config; }); api.interceptors.response.use(async (response) => { return response; }, async (error) => { var _c, _d; // Composable const auth = useAuthentication(); const _impersonatedUserHeaders = {}; if (auth.isAuthenticated && (error.request.status === 401 || false) && ((_d = (_c = error.config) === null || _c === void 0 ? void 0 : _c.headers) === null || _d === void 0 ? void 0 : _d.Authorization)) { const response = await auth.refreshAuthentication().catch(async (data) => { await auth.removeSession(); if (onSessionExpired) { onSessionExpired(); } return Promise.reject(Object.assign(Object.assign({}, data), _impersonatedUserHeaders)); }); if (response === null || response === void 0 ? void 0 : response.token) { error.config.headers.Authorization = `${tokenType} ${response.token}`; return api.request(error.config); } } return Promise.reject(Object.assign(Object.assign({}, error.response), _impersonatedUserHeaders)); }); return api; } const useAPI = (options) => (_context) => { _context.store.$api = options.api; _context.store.$endpoints = options.endpoints; }; /* eslint-disable @typescript-eslint/no-explicit-any */ const normalizeOptions = (options, globalOptions) => { options = typeof options === 'object' ? options : Object.create(null); return new Proxy(options, { get(target, key, receiver) { return Reflect.get(target, key, receiver) || Reflect.get(globalOptions, key, receiver); }, }); }; // Utils const get = (state, path) => { return path.reduce((obj, p) => { return obj === null || obj === void 0 ? void 0 : obj[p]; }, state); }; const set = (state, path, val) => { return ((path.slice(0, -1).reduce((obj, p) => { if (!/^(__proto__)$/.test(p)) return (obj[p] = obj[p] || {}); else return {}; }, state)[path[path.length - 1]] = val), state); }; const pick = (baseState, paths) => { return paths.reduce((substate, path) => { const pathArray = path.split('.'); return set(substate, pathArray, get(baseState, pathArray)); }, {}); }; const usePersistedState = (_options) => (_context) => { const { options: { persist }, store, } = _context; if (!persist) { return; } const { afterStoreHydration = null, beforeStoreHydration = null, key = store.$id, namespace = 'nvs', paths = null, serializer = { serialize: JSON.stringify, deserialize: JSON.parse, }, storage, } = normalizeOptions(persist, _options || {}); const _storeName = `${namespace}_${key}`; const _init = async () => { store.$subscribe(async (_mutation, state) => { try { const toStore = Array.isArray(paths) ? pick(state, paths) : state; await storage.setItem(_storeName, serializer.serialize(toStore)); } catch (_error) { // Void } }, { detached: true }); if (beforeStoreHydration) { await beforeStoreHydration(_context); } const _storageData = await storage.getItem(_storeName); if (_storageData) { await store.$patch(serializer.deserialize(_storageData)); } if (afterStoreHydration) { await afterStoreHydration(_context); } }; _init(); }; const useStoreByName = (_context) => { _context.store.$storeByName = (name) => { var _a; const stores = _context.pinia; return ((_a = stores === null || stores === void 0 ? void 0 : stores._s) === null || _a === void 0 ? void 0 : _a.get(name)) || undefined; }; }; const API_BASE = 'api'; const authenticationRoutes = { LOGIN: '/authentication-token', RESET_PASSWORD_REQUEST: '/reset-password-requests', RESET_PASSWORD: '/reset-password-requests/{token}', TOKEN_REFRESH: '/token/refresh', }; const syliusApiRoutes = { ADDRESSES: '/addresses', APPLY_COUPON: '/orders/{token}/apply-coupon', CHANGE_ITEM_QUANTITY_BY_ORDER_TOKEN: '/orders/{token}/change-quantity', COMPLETE_ORDER_BY_TOKEN: '/orders/{token}/complete', COMPLETION_INFORMATION: '/orders/{token}/completion-information?id={id}', COUNTRIES: '/countries', CUSTOMERS: '/customers', ITEM_BY_ID: '/items/{itemId}', ORDER_BY_TOKEN: '/orders/{token}', PATCH_ORDER_ADDRESS: '/orders/{token}/address', PAYMENT_METHODS_BY_ORDER: '/orders/{token}/payment-methods', PAYMENT_METHOD_BY_ID: '/payments/{paymentId}', TAXONS: '/taxons', TAXON_BY_CODE: '/taxons/{code}', }; const ENDPOINTS = Object.assign(Object.assign({ API_BASE_URL: `/${API_BASE}` }, syliusApiRoutes), authenticationRoutes); const BUNDLE_NAME = '🍍 NVS Pinia Collection'; export { ACCESS_TOKEN_KEY, API_BASE, API_LOCALE_PLACEMENT, BUNDLE_NAME, ENDPOINTS, IMPERSONATING_KEY, REFRESH_TOKEN_KEY, REQUEST_TOKEN, ROLE, SECURE_CONFIG_PARAM_VARIANTS, USER_KEY, authenticationRoutes, createAPI, syliusApiRoutes, useAPI, useApiSettings, useAuthentication, useContextStore, usePersistedState, useStoreByName }; //# sourceMappingURL=index.esm.js.map