{"record":{"id":"117d3e9a4de469e2","repo":"lyswhut/lx-music-desktop","slug":"source-no-match","errorCode":null,"errorMessage":"Source no match","messagePattern":"Source no match","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/renderer/core/useApp/useDeeplink/utils.js","lineNumber":18,"sourceCode":"import { useI18n } from '@renderer/plugins/i18n'\nimport { dialog } from '@renderer/plugins/Dialog'\n\nexport const useDialog = () => {\n  const t = useI18n()\n  const errorDialog = message => {\n    dialog({\n      message: `${t('deep_link__handle_error_tip', { message })}`,\n      confirmButtonText: t('ok'),\n    })\n  }\n\n  return errorDialog\n}\n\nexport const sources = ['kw', 'kg', 'tx', 'wy', 'mg']\nexport const sourceVerify = source => {\n  if (!sources.includes(source)) throw new Error('Source no match')\n}\n\nexport const qualitys = ['128k', '320k', 'flac', 'flac24bit']\nexport const qualityFilter = (source, types) => {\n  types = types.filter(({ type }) => qualitys.includes(type)).map(({ type, size, hash }) => {\n    if (size != null && typeof size != 'string') throw new Error(type + ' size type no match')\n    if (source == 'kg' && typeof hash != 'string') throw new Error(type + ' hash type no match')\n    return hash == null ? { type, size } : { type, size, hash }\n  })\n  if (!types.length) throw new Error('quality no match')\n  return types\n}\n\nexport const dataVerify = (rules, data) => {\n  const newData = {}\n  for (const rule of rules) {\n    const val = data[rule.key]\n    if (rule.required && val == null) throw new Error(rule.key + ' missing')","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/lyswhut/lx-music-desktop/blob/9c364b482e5621a1d38b50e8610d2fb974457e6e/src/renderer/core/useApp/useDeeplink/utils.js#L1-L36","documentation":"The centralized source allowlist check in utils.js:18. `sources` enumerates the five supported providers ['kw','kg','tx','wy','mg']; sourceVerify throws 'Source no match' when the deep link's source isn't on the list. It is called by both songlist handlers (useSonglistAction.js:46 and :82) before dataVerify runs.","triggerScenarios":"Any deep link that reaches sourceVerify with a source outside kw/kg/tx/wy/mg — including null, undefined, or '' (since the default songlistInfo initializes source to null and only assigns from paths/data).","commonSituations":"A new provider not yet registered in the allowlist; the source field not set during parsing (so it stays null); a test or placeholder link using a fake source code.","solutions":["If a new provider is genuinely supported, append it to the `sources` array in utils.js (the single source of truth).","Ensure the source field is populated from paths[0] or data.source before sourceVerify is called.","Catch the throw upstream and show a user-facing 'unsupported source' dialog via useDialog().","Reuse `sources` everywhere instead of re-declaring the list, so additions propagate."],"exampleFix":"// before\nexport const sourceVerify = source => {\n  if (!sources.includes(source)) throw new Error('Source no match')\n}\n\n// after - include the value and the allowed set in the message\nexport const sourceVerify = source => {\n  if (!sources.includes(source)) {\n    throw new Error(`Source no match: '${source}'. Supported: ${sources.join(', ')}`)\n  }\n}","handlingStrategy":"validation","validationCode":"import { sources } from './utils'\nif (!sources.includes(info?.source)) {\n  showErrorDialog(`Unsupported source: ${info?.source}. Must be one of ${sources.join(', ')}`)\n  return\n}","typeGuard":"import { sources } from './utils'\nconst isKnownSource = (s) => typeof s === 'string' && sources.includes(s)","tryCatchPattern":"try {\n  sourceVerify(info.source)\n  // ... proceed with handler\n} catch (e) {\n  errorDialog(e.message)\n}","preventionTips":["Treat utils.js `sources` as the single source of truth; never inline the list elsewhere.","Ensure source is assigned from paths[0]/data.source before sourceVerify runs (it defaults to null).","Add a provider in one place (`sources`) so all checks update together."],"tags":["deeplink","validation","allowlist","music-source"],"backgroundTag":null,"analyzedSha":"9c364b482e5621a1d38b50e8610d2fb974457e6e","analyzedAt":"2026-08-12T15:14:48.244Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}