@nvs-pinia/common
Version:
NVS Pinia collection shared logic
324 lines (310 loc) • 11.4 kB
JavaScript
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