store.ts
1 /** 2 * Injected script for discovering Pinia or Vuex stores and their actions/state representations. 3 * 4 * This function is serialized via `.toString()` and evaluated inside the page context, 5 * so the types below only exist at the TS boundary — the runtime shapes are whatever 6 * Pinia/Vuex put on the Vue app. We use narrow structural types for the fields we touch. 7 */ 8 9 // Minimal structural types describing just the fields we access. 10 type PiniaStore = Record<string, unknown>; 11 interface VuexModule { 12 _rawModule?: { actions?: Record<string, unknown> }; 13 state?: Record<string, unknown>; 14 } 15 interface VueApp { 16 __vue_app__?: { 17 config?: { 18 globalProperties?: { 19 $pinia?: { _s?: Map<string, PiniaStore> }; 20 $store?: { _modules?: { root?: { _children?: Record<string, VuexModule> } } }; 21 }; 22 }; 23 }; 24 } 25 26 export function discoverStores() { 27 const stores: Array<{ type: string; id: string; actions: string[]; stateKeys: string[] }> = []; 28 try { 29 const app = document.querySelector('#app') as unknown as VueApp | null; 30 if (!app?.__vue_app__) return stores; 31 const gp = app.__vue_app__.config?.globalProperties; 32 33 // Pinia stores 34 const pinia = gp?.$pinia; 35 if (pinia?._s) { 36 pinia._s.forEach((store, id) => { 37 const actions: string[] = []; 38 const stateKeys: string[] = []; 39 for (const k in store) { 40 try { 41 if (k.startsWith('$') || k.startsWith('_')) continue; 42 if (typeof store[k] === 'function') actions.push(k); 43 else stateKeys.push(k); 44 } catch {} 45 } 46 stores.push({ type: 'pinia', id, actions: actions.slice(0, 20), stateKeys: stateKeys.slice(0, 15) }); 47 }); 48 } 49 50 // Vuex store modules 51 const vuex = gp?.$store; 52 if (vuex?._modules?.root?._children) { 53 const children = vuex._modules.root._children; 54 for (const [modName, mod] of Object.entries(children)) { 55 const actions = Object.keys(mod._rawModule?.actions ?? {}).slice(0, 20); 56 const stateKeys = Object.keys(mod.state ?? {}).slice(0, 15); 57 stores.push({ type: 'vuex', id: modName, actions, stateKeys }); 58 } 59 } 60 } catch {} 61 return stores; 62 }