{"record":{"id":"9dd072515c8214d9","repo":"jackwener/OpenCLI","slug":"invalid-1688-url","errorCode":null,"errorMessage":"Invalid 1688 URL","messagePattern":"Invalid 1688 URL","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/1688/shared.js","lineNumber":498,"sourceCode":"        .replace(/\\s*([~-])\\s*/g, '$1')\n        .trim();\n}\nfunction escapeForRegex(value) {\n    return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\nfunction parse1688Url(input) {\n    const normalized = cleanText(input);\n    try {\n        const url = new URL(normalized);\n        if (!url.hostname.endsWith('.1688.com') && url.hostname !== '1688.com' && url.hostname !== 'www.1688.com') {\n            throw new Error('invalid-host');\n        }\n        stripTrackingParams(url);\n        url.hash = '';\n        return url;\n    }\n    catch {\n        throw new ArgumentError('Invalid 1688 URL', 'Use a URL under 1688.com (for example: https://detail.1688.com/offer/887904326744.html)');\n    }\n}\nfunction parse1688UrlOrNull(input) {\n    try {\n        return parse1688Url(input);\n    }\n    catch {\n        return null;\n    }\n}\nfunction normalizeStoreHost(hostname) {\n    const lower = cleanText(hostname).toLowerCase();\n    if (!lower.endsWith('.1688.com'))\n        return null;\n    const [subdomain] = lower.split('.');\n    if (!subdomain || STORE_GENERIC_HOSTS.has(subdomain))\n        return null;\n    return lower;","sourceCodeStart":480,"sourceCodeEnd":516,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/1688/shared.js#L480-L516","documentation":"parse1688Url validates that an input is a URL under 1688.com; after cleaning tracking params and hash it throws ArgumentError('Invalid 1688 URL') when URL construction fails or the host is not a 1688.com domain. This is the low-level URL parser guard underpinning extractOfferId, extractMemberId, and canonicalization helpers.","triggerScenarios":"Passing a string that is not a valid absolute URL (new URL() throws) or a valid URL on a non-1688.com domain — e.g. 'item 887904326744' reached a parse path expecting a URL, 'https://taobao.com/x', 'www.1688.com' without scheme, or gibberish text.","commonSituations":"Copying a taobao/alibaba (non-1688) link; forgetting the https:// scheme; pasting text with surrounding quotes or markdown; calling parse helpers directly with IDs instead of URLs.","solutions":["Provide a full URL on the 1688.com domain, e.g. https://detail.1688.com/offer/887904326744.html.","Prepend the scheme if missing: 'www.1688.com' -> 'https://www.1688.com'.","If you have a bare offer ID, pass it to the item command directly rather than a URL-parsing path."],"exampleFix":"// before\nparse1688Url('detail.1688.com/offer/887904326744.html'); // no scheme\n// after\nparse1688Url('https://detail.1688.com/offer/887904326744.html');","handlingStrategy":"validation","validationCode":"function is1688Url(input) {\n  try {\n    const u = new URL(String(input).trim());\n    return /(^|\\.)1688\\.com$/i.test(u.hostname);\n  } catch {\n    return false;\n  }\n}\nif (!is1688Url(input)) throw new Error(`Not a 1688.com URL: ${input}`);","typeGuard":"function isValidAbsoluteUrl(input) {\n  try { new URL(String(input)); return true; } catch { return false; }\n}","tryCatchPattern":"try {\n  const parsed = parse1688Url(input);\n} catch (e) {\n  if (e.name === 'ArgumentError') {\n    console.error(`Invalid URL '${input}' — must be an absolute https URL under 1688.com.`);\n  } else throw e;\n}","preventionTips":["Always pass absolute URLs including the https:// scheme.","Reject non-1688 domains (taobao, alibaba.com) at input boundaries.","Trim surrounding whitespace/quotes from pasted URLs.","Prefer ID-based commands (offer ID) when you don't have a full URL."],"tags":["url-parsing","argument-validation","input-error"],"backgroundTag":"invalid-input-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}