刘光辉
5 小时以前 cf11e63b659afcc9792ab3e395f1b45d844431a8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import type { Pinia } from 'pinia';
 
import type { App } from 'vue';
 
import { createPinia } from 'pinia';
import SecureLS from 'secure-ls';
 
import { createSessionAuthStorage } from './session-auth';
 
let pinia: Pinia;
let sessionLogin: (<T>(action: (token: null | string) => Promise<T>) => Promise<T>) | undefined;
 
/** Serialize password login across tabs when the browser supports Web Locks. */
export async function withSessionAuthLogin<T>(action: (token: null | string) => Promise<T>): Promise<T> {
  return sessionLogin ? sessionLogin(action) : action(null);
}
 
export interface InitStoreOptions {
  // 子应用是否共用token
  isCommonToken?: boolean;
  /**
   * @zh_CN 应用名,由于 @vben/stores 是公用的,后续可能有多个app,为了防止多个app缓存冲突,可在这里配置应用名,应用名将被用于持久化的前缀
   */
  namespace: string;
  /** Keep authentication in the page session and share it with live tabs. */
  sessionAuth?: boolean;
}
 
/**
 * @zh_CN 初始化pinia
 */
export async function initStores(app: App, options: InitStoreOptions) {
  const { createPersistedState } = await import('pinia-plugin-persistedstate');
  pinia = createPinia();
  let { namespace } = options;
  const ls = new SecureLS({
    encodingType: 'aes',
    encryptionSecret: import.meta.env.VITE_APP_STORE_SECURE_KEY,
    isCompression: true,
    // @ts-ignore secure-ls does not have a type definition for this
    metaKey: `${namespace}-secure-meta`,
  });
  const authNamespace = options.isCommonToken ? namespace.split('_')[0]! : namespace;
  const authKey = `${authNamespace}-core-access`;
  let sessionAuth: ReturnType<typeof createSessionAuthStorage> | undefined;
  sessionLogin = undefined;
  if (options.sessionAuth) {
    const sessionLs = import.meta.env.DEV
      ? undefined
      : new SecureLS({
          encodingType: 'aes',
          encryptionSecret: import.meta.env.VITE_APP_STORE_SECURE_KEY,
          isCompression: true,
          // @ts-ignore secure-ls supports storage and metaKey at runtime.
          storage: sessionStorage,
          metaKey: `${authNamespace}-session-secure-meta`,
        });
    sessionAuth = createSessionAuthStorage({
      key: authKey,
      session: sessionLs
        ? {
            getItem: (key) => sessionLs.get(key),
            setItem: (key, value) => sessionLs.set(key, value),
          }
        : sessionStorage,
      persistent: localStorage,
      channel: typeof BroadcastChannel === 'undefined' ? undefined : new BroadcastChannel(`${authKey}-session`),
      events: window,
      // Rebuild user information, routes and permissions for the new identity.
      onRemoteChange: () => window.location.reload(),
    });
    await sessionAuth.start();
    const authentication = sessionAuth;
    sessionLogin = async (action) => {
      const run = async () => {
        await authentication.start();
        return action(authentication.getAccessToken());
      };
      return navigator.locks ? navigator.locks.request(`${authKey}-login`, run) : run();
    };
    app.onUnmount(() => sessionAuth?.dispose());
    import.meta.hot?.dispose(() => sessionAuth?.dispose());
  }
  pinia.use(
    createPersistedState({
      // key $appName-$store.id
      key: (storeKey) => {
        if (options.isCommonToken && storeKey == 'core-access' && namespace.indexOf('_') > 0) {
          namespace = namespace.slice(0, namespace.indexOf('_'));
        }
        return `${namespace}-${storeKey}`;
      },
      storage: {
        getItem(key) {
          if (sessionAuth && key === authKey) return sessionAuth.getItem();
          return import.meta.env.DEV ? localStorage.getItem(key) : ls.get(key);
        },
        setItem(key, value) {
          if (sessionAuth && key === authKey) {
            sessionAuth.setItem(key, value);
          } else if (import.meta.env.DEV) {
            localStorage.setItem(key, value);
          } else {
            ls.set(key, value);
          }
        },
      },
    }),
  );
  app.use(pinia);
  return pinia;
}
 
export function resetAllStores() {
  if (!pinia) {
    console.error('Pinia is not installed');
    return;
  }
  const allStores = (pinia as any)._s;
  for (const [_key, store] of allStores) {
    if (!_key.includes('jnpfUniver')) store?.$reset();
  }
}
 
export function getAllStores() {
  if (!pinia) {
    console.error('Pinia is not installed');
    return [];
  }
  const allStores = (pinia as any)._s;
  return allStores;
}