XBase-JS is a standardized utility library for more straightforward UI development with minimal configuration.
npm install @xtremax/xbase-js
or
yarn add @xtremax/xbase-js
XBase-JS consists of several modules that can be utilized based on the desired need:
Create API requests with configurable authorization settings and error handlers based on the returned HTTP response status codes.
axios request configuration.See the configuration detail here.
You can use API module anywhere in you project by importing it. And since the API module extends axios class, you can also run any operation an axios instance can run such as get, post, patch, etc.
import { API } from "@xtremax/xbase-js";
await API({
method: "get",
url: "https://jsonplaceholder.typicode.com/posts",
params: { language: "en" },
});
await API.get("https://jsonplaceholder.typicode.com/posts")
Simply put, API is an axios instance with default interceptors and error handlers. If you want to use your own interceptors, you can eject the default interceptors and replace it with the new one as shown in the code below.
import { API } from "@xtremax/xbase-js";
API.interceptors.request.eject(API.defaultRequestInterceptors);
API.interceptors.request.use(
function (config) {
// Do something before request is sent
return config;
},
function (error) {
// Do something with request error
return Promise.reject(error);
}
);
API.interceptors.response.eject(API.defaultResponseInterceptors);
API.interceptors.response.use(
function (response) {
// Any status code that lies within the range of 2xx cause this function to trigger
// Do something with response data
return response;
},
function (error) {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
return Promise.reject(error);
}
);
Detect inactive state of the user because there is no interaction in the client side, such as mouse movement, keyboard presses and etc., within the determined period of time.
callback (Optional): Function that will be executed when the waitingTime is reached.
waitingTime (Optional): The time period before a user is considered inactive (in milliseconds). The default value is 20 minutes.
activeState (Optional): Function that will be executed if the user is active and the callback hasn't been called.
otherOptions (Optional): Other object to configure InactiveDetector.
beforeCallbackTime: The time period (in milliseconds) before the callback function is executed. The default value is 1 minute.beforeCallback: Function to be executed when the beforeCallbackTime condition is reached.You can use the InactiveDetector feature independently by importing the module from XBase-JS then use it wherever you want to use it.
After importing the module, please provide the parameter value as already been mentioned above.
import { InactiveDetector } from "@xtremax/xbase-js"
function myCallbackFunction() {
// ...
console.log("User is inactive.")
}
function myBeforeCallbackFunction() {
// ...
console.log("User is 30 seconds left before considered as inactive.")
}
const waitingTime = 10 * 60 * 1000; // 10 minutes
const activeState = () => false;
const otherOptions = {
beforeCallbackTime: 30 * 1000 // 30 seconds,
beforeCallback: myBeforeCallbackFunction,
}
// initialize the inactive detector
const inactiveDetector = InactiveDetector(myCallbackFunction, waitingTime, activeState, otherOptions);
// start the inactive detector
inactiveDetector.start();
// stop the inactive detector
inactiveDetector.reset();
In the case of SPA (Single Page Application) or our Microfrontend architecture, the implementation differs slightly. Since inactivity detector is simply function that return two methods (start and reset) so that we can simply reuse the function to start and stop the counter directly on the place that suits the business process of the application.
import InactiveDetector from @xtremax/xbase-js/inactive-detector;
// index.js
// To start the counter of detector can be set in signinRedirectCallback after the login success //
Auth.signInRedirectCallback(() => {
InactiveDetector(callback, config.waitingtime).start()
})
// To end the counter of detector can be set once the logout process //
Auth.signOutRedirectCallback() {
InactiveDetector(callback, config.waitingtime).reset()
}
// App.vue (Root Component)
// This one to handle when the application reload //
onMounted(() => {
if(isSignIn) {
InactiveDetector(callback, config.waitingtime).start()
} else {
InactiveDetector(callback, config.waitingtime).reset()
}
})
Authenticate and authorize user with simplified flow on signing in, token renewal, and signing out.
By default, Auth module is integrated with the InactiveDetector module. You can change the configuration parameter or disable it completely through the settings.
oidc-client-ts' UserManager options except the userStore. Click here for more details. Important : specific case for our IDP service you must include fetchRequestCredentials='omit'false to disable the inactive detector. If you want to change the default behavior, provide the settings in here.inactiveCallback is executed (in milliseconds). Default value is 1 minutes.inactiveTimeout is up.preInactiveTimeout is up. Return resetTimer callback function to reset the idle time. Default value (using our developed dialog element) :(resetTimer) => {
dialog.open(
"Your session is about to expire. You will be signed out after you have been inactive for a while. Click Continue to stay signed in.",
(closeDialog) => {
closeDialog();
resetTimer();
}
);
};
See the configuration detail here.
Create /oidccallback page in your app (see the sample here), and execute this function:
import { Auth } from "@xtremax/xbase-js";
Auth.signInRedirectCallback();
Create /oidccallbacksilent page in your app (see the sample here), and execute this function:
import { Auth } from "@xtremax/xbase-js";
Auth.signInSilentCallback();
Register the /oidccallback path as the value of redirect_uri and the /oidccallbacksilent path as the value of silent_redirect_uri in your idpConfigs.
Now you can use the functionality of Auth module anywhere in you project by importing it.
import { Auth } from "@xtremax/xbase-js";
Auth.signIn(); // method to sign in, returns Promise
Auth.signOut(); // method to sign out, returns Promise
Auth.renewToken(); // method to renew the JWT, returns Promise of the user's object
Auth. getSignedInUser() // method to get the signed in user's object, returns Promise of the user'sobject
Auth module provides default function for oidc-client-ts' events.
By default, Auth module has a defined accessTokenExpiring, accessTokenExpired and silentRenewError callbacks.
accessTokenExpiring default callback: If the user is still active and the token is expiring, Auth module will call signinSilent. If the signinSilent process failed, it will proceed to call signinRedirect.accessTokenExpired default callback: If the user's token is expired, Auth module will open a dialog requiring the user to click a sign out button, calling signoutRedirect.silentRenewError default callback: If the silent token renewal failed, Auth module will call signoutRedirect.However, you can remove and replace them with your own callbacks as shown in the code below.
import { Auth } from "@xtremax/xbase-js";
function customAccessTokenExpiringCallback() {
// your custom access token expiring callback
// ...
}
Auth.events.removeAccessTokenExpiring(Auth.accessTokenExpiringCallback)
Auth.events.addAccessTokenExpiring(customAccessTokenExpiringCallback)
function customAccessTokenExpiredCallback() {
// your custom access token expired callback
// ...
}
Auth.events.removeAccessTokenExpired(Auth.accessTokenExpiredCallback)
Auth.events.addAccessTokenExpired(customAccessTokenExpiredCallback)
function customSilentRenewErrorCallback() {
// your custom silent renew error callback
// ...
}
Auth.events.removeSilentRenewError(Auth.silentRenewError)
Auth.events.addSilentRenewError(customSilentRenewErrorCallback)
Auth module is integrated with inactive detector by default. You can disable it by setting theinactiveDetectorConfigs as false.
{
inactiveDetectorConfigs: false,
idpConfigs: {
authority: "https://xticket.dev.xtremax.com/api/idp",
client_id: "auth-trial",
redirect_uri: "http://localhost:8080/oidccallback",
silent_redirect_uri: "http://localhost:8080/oidccallbacksilent",
post_logout_redirect_uri: "http://localhost:8080/login",
scope: "openid xbase_api",
silentRequestTimeoutInSeconds: 300000,
response_type: "code",
},
}
Provide utility that can be integrated with the application's navigation guard in order to validate the route's accessibility based on the gained user permission.
Promise returning it.See the configuration detail here.
You can use Permission module anywhere in your project by importing it. The Permission method receives 1 parameter in the form of string to validate a single permission key,
import { Permission } from "@xtremax/xbase-js";
if (await Permission("Xtremax.accessDashboardPage")) {
// user is allowed to access the /dasboard route
// if the "Xtremax.accessDashboardPage" value is true
window.location.redirect("/dashboard")
} else {
window.location.redirect("/not-authorized")
}
or an array of string to validate multiple permission keys.
import { Permission } from "@xtremax/xbase-js";
if (await Permission(["Xtremax.accessDashboardPage", "Xtremax.accessListingPage"])) {
// user is allowed to access the /dashboard route
// if the "Xtremax.accessDashboardPage" or "Xtremax.accessListingPage" value is true
window.location.redirect("/dashboard")
} else {
window.location.redirect("/not-authorized")
}
By extending the qiankun library, it supports your need to develop a microfrontend architecture application.
See the configuration detail here.
Call load method to load a micro app into the main app.
import { MicroFrontend } from "@xtremax/xbase-js";
const microApp = MicroFrontend.load("Service1")
Call unload method to unload a micro app from the main app.
MicroFrontend.unload(microApp)
Call renderAsMicroApp method to render the app as a micro app.
import XBaseJS, { MicroFrontend } from "@xtremax/xbase-js";
import XBaseJSConfig from "./xbasejs-config.js";
function render(props = {}) {
XBaseJS.configure(XBaseJSConfig)
const { container } = props;
instance = app.mount(
container
? container.querySelector(`#${SERVICE_CONTAINER_NAME}`)
: `#${SERVICE_CONTAINER_NAME}`
);
}
function unmount(){
instance.$destroy();
instance = null;
}
MicroFrontend.renderAsMicroApp(render, unmount)
If you use vite and vite-plugin-qiankun, use it this way :
import XBaseJS, { MicroFrontend } from "@xtremax/xbase-js";
import XBaseJSConfig from "./xbasejs-config.js";
import { renderWithQiankun } from "vite-plugin-qiankun/dist/helper";
function render(props = {}) {
XBaseJS.configure(XBaseJSConfig)
const { container } = props;
instance = app.mount(
container
? container.querySelector(`#${SERVICE_CONTAINER_NAME}`)
: `#${SERVICE_CONTAINER_NAME}`
);
}
function unmount(){
instance.$destroy();
instance = null;
}
renderWithQiankun(MicroFrontend.renderAsMicroApp(render, unmount))
A JavaScript implementation of a "publish-subscribe" messaging pattern. It is a utility that supports your need to create a communication model between decoupled, independent building blocks of UI application (micro apps).
See the configuration detail here.
You can use PubSub module anywhere in your project by importing it. This module provide functionality to publish, subscribe, and unsubscribe to custom events.
Use publish method to publish a custom event.
import { PubSub } from "@xtremax/xbase-js";
PubSub.publish("event_name", "Message you want to publish")
Use subscribe to subscribe to a custom event.
import { PubSub } from "@xtremax/xbase-js";
const listener = (e)=>{
// do something with the e.detail
const message = e.detail;
}
PubSub.subscribe("event_name", listener)
Use unsubscribe method to unsubscribe from a custom event.
import { PubSub } from "@xtremax/xbase-js";
const listener = (e)=>{
// do something with the e.detail
const message = e.detail;
}
const token = PubSub.subscribe("event_name", listener)
// unsubscribe using regular removeEventListener parameter
PubSub.unsubscribe("event_name", listener)
// unsubscribe using subscription token
PubSub.unsubscribe(token)
Cancel all current subscriptions with unsubscribeAll method.
import { PubSub } from "@xtremax/xbase-js";
PubSub.unsubscribeAll()
Use subscriptions method to get the subscription details.
import { PubSub } from "@xtremax/xbase-js";
const subscriptions = PubSub.subscriptions
XBaseJS configuration object consists of 5 optional settings : Auth, API, Permission, PubSub, and MicroFrontend.
Each setting will be used in the respective module. So, you only need to pass settings for any module you plan to use, and omit the others.
Here is a quick example of a complete configuration that uses all of the modules:
import XBaseJS from "@xtremax/xbase-js";
const configs = {
API: {
config: {
baseURL: "https://jsonplaceholder.typicode.com/",
timeout: 1000,
headers: { "X-Custom-Header": "foobar" }
},
errorHandler: [
{
statusCode: 400,
callback: (error) => {
// do custom function
console.log("getting 400 response");
},
},
{
statusCode: [401, 403],
callback: (error) => {
// do custom function
console.log("getting 401 or 403 response");
},
},
],
},
Auth: {
idpConfigs: {
authority: "https://xticket.dev.xtremax.com/api/idp",
client_id: "auth-trial",
redirect_uri: "http://localhost:8080/oidccallback",
silent_redirect_uri: "http://localhost:8080/oidccallbacksilent",
post_logout_redirect_uri: "http://localhost:8080/login",
scope: "openid xbase_api",
silentRequestTimeoutInSeconds: 300000,
response_type: "code",
},
inactiveDetectorConfigs: {
inactiveTimeout: 20 * 60 * 1000,
preInactiveCallback: (resetTimer) => {
const message = "Your session is about to expire. You will be signed out after you have been inactive for a while. Click Continue to stay signed in.";
// create your custom dialog element here
dialog.open(
message,
(closeDialog) => {
closeDialog();
resetTimer();
}
);
},
preInactiveTimeout: 60 * 1000,
},
},
Permission: {
permissionResolver: async () => {
try {
const apiResponse = await new Promise((resolve) =>
setTimeout(
// you can change this mechanism later with fetching a real API endpoint
// to get the permission data
() =>
resolve({
data: {
permission: {
"XBaseUiFramework.Home.View": true,
"XBaseUiFramework.About.View": false,
},
},
}),
3000
)
);
console.log(apiResponse);
return apiResponse.data.permission;
} catch (err) {
console.log(err?.response);
}
},
},
MicroFrontend: {
microApps: [
{
name: "Service1",
entry: "http://localhost:8080",
container: "#micro-service",
props: {
AuthConfigs: AuthConfigs
}
},
{
name: "Service2",
entry: "http://localhost:8081",
container: "#micro-service",
props: {
AuthConfigs: AuthConfigs
}
}
]
},
PubSub: {
validator: (message)=>{
const regex = /^[A-Za-z0-9 ]+$/
return regex.test(message)
}
},
}
XBaseJS.configure(configs)
Generated using TypeDoc