{"record":{"id":"534a59387d85a264","repo":"jackwener/OpenCLI","slug":"youdao-note-url-must-be-under-note-youdao-com-or-n","errorCode":null,"errorMessage":"Youdao Note URL must be under note.youdao.com or note.youdao.cn","messagePattern":"Youdao Note URL must be under note\\.youdao\\.com or note\\.youdao\\.cn","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/youdao/note.js","lineNumber":33,"sourceCode":"  return payload;\n}\n\nfunction normalizeShareUrl(raw) {\n  const value = String(raw ?? '').trim();\n  if (!value) {\n    throw new ArgumentError('youdao note url cannot be empty', 'Pass a full public share URL from Youdao Notes.');\n  }\n  let parsed;\n  try {\n    parsed = new URL(value);\n  } catch {\n    throw new ArgumentError('Invalid Youdao Note URL', 'Example: https://share.note.youdao.com/ynoteshare/index.html?id=...&type=note');\n  }\n  if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {\n    throw new ArgumentError('Youdao Note URL must use http or https');\n  }\n  if (!ALLOWED_HOSTS.has(parsed.hostname)) {\n    throw new ArgumentError('Youdao Note URL must be under note.youdao.com or note.youdao.cn');\n  }\n  if (!parsed.searchParams.get('id')) {\n    throw new ArgumentError('Youdao Note URL must include an id query parameter');\n  }\n  const type = parsed.searchParams.get('type');\n  if (type && type !== 'note') {\n    throw new ArgumentError('youdao note only accepts shared note URLs', 'Shared notebooks are not implemented yet.');\n  }\n  return parsed.toString();\n}\n\nfunction formatYoudaoTimestamp(value) {\n  if (value == null || value === '') return '';\n  const numeric = Number(value);\n  if (!Number.isFinite(numeric) || numeric <= 0) return String(value);\n  const millis = numeric < 10_000_000_000 ? numeric * 1000 : numeric;\n  const date = new Date(millis);\n  if (Number.isNaN(date.getTime())) return String(value);","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/youdao/note.js#L15-L51","documentation":"ArgumentError thrown by normalizeShareUrl when the URL hostname is not in ALLOWED_HOSTS (share.note.youdao.com, note.youdao.com, share.note.youdao.cn, note.youdao.cn). The extractor is written against Youdao's specific page structure, so arbitrary hosts would fail; the library rejects them up front.","triggerScenarios":"Passing URLs from other domains (e.g. 'www.youdao.com/...', 'youdao.com', 'you.163.com', 'example.com/index.html?id=...') or a subdomain not in the allowlist such as 'share.note.youdao.com.evil.io'.","commonSituations":"Confusing Youdao's main site with its note-sharing host; using a translated/proxied mirror of the share page; typos in the domain (e.g. 'notes.youdao.com'); passing an entirely different notes service URL.","solutions":["Use a URL whose host is exactly share.note.youdao.com, note.youdao.com, share.note.youdao.cn, or note.youdao.cn","Re-copy the share link via Youdao Notes' 'Share' feature, which always emits a share.note.youdao.com(/.cn) URL","Fix typos in the hostname and drop any extra subdomains or suffixes"],"exampleFix":"// before\nawait youdaoNote('https://www.youdao.com/ynoteshare/index.html?id=abc');\n// after\nawait youdaoNote('https://share.note.youdao.com/ynoteshare/index.html?id=abc');","handlingStrategy":"validation","validationCode":"const ALLOWED = new Set(['share.note.youdao.com','note.youdao.com','share.note.youdao.cn','note.youdao.cn']);\nfunction isYoudaoShareHost(u) {\n  try { return ALLOWED.has(new URL(u).hostname); } catch { return false; }\n}\nif (!isYoudaoShareHost(inputUrl)) throw new Error('URL must be a youdao note share link');","typeGuard":"function isYoudaoShareUrl(v) {\n  const hosts = ['share.note.youdao.com','note.youdao.com','share.note.youdao.cn','note.youdao.cn'];\n  try { return hosts.includes(new URL(v).hostname); } catch { return false; }\n}","tryCatchPattern":"try {\n  await youdaoNote(url);\n} catch (e) {\n  if (String(e.message).includes('note.youdao.com or note.youdao.cn')) {\n    // re-copy the correct share.note.youdao.com link\n  } else throw e;\n}","preventionTips":["Keep an allowlist check on hostname before invoking Youdao commands","Always obtain share links from Youdao Notes' official Share dialog","Watch for typos and spoofed suffix hosts like share.note.youdao.com.evil.io"],"tags":["argument-error","url-hostname","validation","allowlist"],"backgroundTag":"url-host-allowlist-violation","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}