@towerai/web-foundation
v1.0.4
Published
TowerAI web foundation
Downloads
66
Readme
@towerai/web-foundation
TowerAI web foundation. It is aligned with the TowerAI backend contracts:
POST /api/v1/auth/loginPOST /api/v1/auth/refresh-tokenGET /api/v1/users/meGET /api/v1/menus/routesGET /api/v1/menusPOST /api/v1/files/upload-sessionPOST /api/v1/files/access-urlPOST /api/v1/files/uploadPOST /api/v1/files/completeGET /api/v1/files/chunk/{uploadId}POST /api/v1/files/chunkDELETE /api/v1/files/chunk/{uploadId}
pnpm add @towerai/web-foundationThe Web Foundation package is framework agnostic. It does not depend on Vue, Pinia, Vue Router, Element Plus, or any app module.
Docs
Auth + HTTP
import {
createAuthClient,
createAuthSession,
createAuthStore,
createAuthTokenStorage,
createCurrentUserClient,
createHttpClient,
} from "@towerai/web-foundation";
const tokenStorage = createAuthTokenStorage({
accessToken: "access_token",
refreshToken: "refresh_token",
rememberMe: "remember_me",
username: "username",
password: "password",
});
// By default, tokenStorage only persists the username for remembered login.
// If a project must persist password, pass { persistPassword: true } and
// provide its own encryption/storage policy at the application layer.
const request = createHttpClient({
baseURL: "/api",
appId: "tower-admin",
deviceId: () => deviceId,
resultCodes: {
success: 200,
accessTokenInvalid: 40101,
refreshTokenInvalid: 40102,
},
tokenStorage,
refreshToken: async () => authSession.refreshToken(),
onAuthExpired: async () => {
tokenStorage.clearAllAuth();
},
logger: {
request(ctx) {
console.debug("[request]", ctx.method, ctx.url);
},
response(ctx) {
console.debug("[response]", ctx.method, ctx.url, ctx.status, ctx.duration);
},
error(ctx) {
console.warn("[request:error]", ctx.method, ctx.url, ctx.status, ctx.msg);
},
},
});
const passwordSecretParts = [
import.meta.env.VITE_APP_BIZ_SECRET_P1,
import.meta.env.VITE_APP_BIZ_SECRET_P2,
];
const authClient = createAuthClient({
request,
passwordSecretParts,
});
const authSession = createAuthSession({ authClient, tokenStorage });
const currentUserClient = createCurrentUserClient({
request,
passwordSecretParts,
});
const user = await currentUserClient.getInfo();
const authStore = createAuthStore({
authClient,
currentUserClient,
tokenStorage,
});
authStore.subscribe((state) => {
console.log(state.currentUser, state.rememberMe);
});
await authStore.login({
username: "admin",
password: "123456",
rememberMe: true,
});Permission
import { hasPermission, hasRole } from "@towerai/web-foundation";
hasPermission(user, "sys:user:add");
hasRole(user, ["ADMIN", "TENANT_ADMIN"]);Menu
import {
createMenuClient,
createModuleViewPathResolver,
filterMenuTree,
filterMenuTreeByPermission,
flattenMenuTree,
transformMenuRoutes,
} from "@towerai/web-foundation";
const menuClient = createMenuClient({ request });
const serverRoutes = await menuClient.getRoutes();
const visibleMenus = filterMenuTree(menus, (menu) => !menu.meta?.hidden);
const authorizedMenus = filterMenuTreeByPermission(visibleMenus, user);
const flatMenus = flattenMenuTree(visibleMenus);
const resolveComponentPath = createModuleViewPathResolver({
moduleRoot: "/src/modules",
viewDir: "views",
mobileDir: "mobile",
routeComponentPathMap: {
"system/tenant/index": "tenant/tenant-manage/index",
},
});
const routes = transformMenuRoutes(serverRoutes, {
isMobile,
layoutComponent,
notFoundComponent,
resolveComponentPath,
resolveComponent: (path) => modules[path],
});File
import {
createFileClient,
createFileUploader,
downloadFile,
resolvePreviewUrl,
type FileInfo,
type PageResult,
} from "@towerai/web-foundation";
const fileClient = createFileClient({
request,
baseUrl: "/api/v1/files",
});
const fileUploader = createFileUploader(fileClient, {
defaultUploadMode: "direct",
chunkedUploadThresholdMb: 50,
});
const uploaded = await fileUploader.uploadFile(file, {
businessType: "avatar",
onProgress: (percent) => console.log(percent),
});
const uploadResult = await fileClient.uploadFile(file, "design-source");
console.log(uploadResult.fileInfo, uploadResult.processResult);
const url = await resolvePreviewUrl("tenant/logo.png", fileClient);
await downloadFile({ objectKey: "tenant/logo.png", name: "logo.png" }, fileClient);
const page: PageResult<FileInfo[]> = {
list: [uploaded],
total: 1,
};Watermark
import { createWatermark } from "@towerai/web-foundation";
const watermark = createWatermark({
text: ["TowerAI", "tenant / username"],
});
watermark.update({ text: "new text" });
watermark.remove();