{"record":{"id":"595956d855a7f993","repo":"jackwener/OpenCLI","slug":"framework-changed","errorCode":"FRAMEWORK_CHANGED","errorMessage":"Could not access Vue Router on flk.npc.gov.cn — the site may have been restructured.","messagePattern":"Could not access Vue Router on flk\\.npc\\.gov\\.cn — the site may have been restructured\\.","errorType":"error_code","errorClass":"CliError","httpStatus":null,"severity":"error","filePath":"clis/gov-law/shared.js","lineNumber":18,"sourceCode":"import { CliError } from '@jackwener/opencli/errors';\n\nexport async function navigateViaVueRouter(page, query) {\n    await page.goto('https://flk.npc.gov.cn/index.html');\n    await page.wait(4);\n\n    const routerAvailable = await page.evaluate(`\n      (async () => {\n        const app = document.querySelector('#app');\n        const router = app?.__vue_app__?.config?.globalProperties?.$router;\n        if (!router) return false;\n        await router.push({ path: '/search', query: ${JSON.stringify(query)} });\n        return true;\n      })()\n    `);\n\n    if (!routerAvailable) {\n        throw new CliError(\n            'FRAMEWORK_CHANGED',\n            'Could not access Vue Router on flk.npc.gov.cn — the site may have been restructured.',\n            'Please report this issue so the adapter can be updated.',\n        );\n    }\n\n    await page.wait(5);\n}\n\nexport async function extractLawResults(page, limit) {\n    const data = await page.evaluate(`\n      (async () => {\n        const normalize = v => (v || '').replace(/\\\\s+/g, ' ').trim();\n        for (let i = 0; i < 40; i++) {\n          if (document.querySelectorAll('.result-item').length > 0) break;\n          await new Promise(r => setTimeout(r, 500));\n        }\n        const results = [];","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/gov-law/shared.js#L1-L36","documentation":"Thrown by navigateViaVueRouter when injected page JavaScript cannot locate the Vue Router instance on flk.npc.gov.cn (the National People's Congress law database). The site is a Vue SPA; the adapter drives its router programmatically, so an inaccessible router implies the site's frontend framework or bundle structure changed. It is raised as a CliError with code FRAMEWORK_CHANGED to signal the adapter — not the user — needs updating.","triggerScenarios":"Calling any gov-law command that navigates via navigateViaVueRouter when the injected script's router detection (`window.__VUE__`/router push) fails: the SPA no longer exposes the router on the expected global, the route '/search' was renamed, or the script evaluated before the app hydrated.","commonSituations":"flk.npc.gov.cn deploying a frontend redesign or framework migration, site temporarily serving an error/login page instead of the SPA, or slow page load so the script runs before Vue mounts.","solutions":["Retry later — the site may be down or slow to hydrate rather than restructured","Report the issue to the adapter maintainers with the date/time so the extraction script can be updated","Check manually in a browser whether flk.npc.gov.cn still loads its search SPA","Pin/patch the adapter to the site's new router global or switch to URL-based navigation"],"exampleFix":"// before\nawait navigateViaVueRouter(page, query);\n// after\ntry { await navigateViaVueRouter(page, query); }\ncatch (e) { if (e.code === 'FRAMEWORK_CHANGED') await page.goto(searchUrlFromQuery(query)); else throw e; }","handlingStrategy":"retry","validationCode":"// Probe the SPA before navigating\nconst ok = await page.evaluate(() => {\n  const app = document.querySelector('#app');\n  return !!(app && app.__vue_app__);\n});\nif (!ok) throw new Error('Vue app not mounted; adapter navigation would fail');","typeGuard":"function isVueRouterAvailable(win) { return !!(win && win.__VUE__ !== undefined || (win.document.querySelector('#app') || {}).__vue__); }","tryCatchPattern":"try {\n  await navigateViaVueRouter(page, query);\n} catch (err) {\n  if (err.code === 'FRAMEWORK_CHANGED') {\n    // site restructured: fall back to direct URL navigation or surface a user-facing notice\n    await page.goto(buildSearchUrl(query));\n  } else throw err;\n}","preventionTips":["Wait for Vue app hydration before injecting scripts","Monitor flk.npc.gov.cn for frontend changes; alert on router-detection failures","Fall back to direct URL navigation when router detection fails","Report persistent FRAMEWORK_CHANGED errors to adapter maintainers"],"tags":["web-scraping","framework-changed","browser","spa"],"backgroundTag":"site-structure-changed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}