{"record":{"id":"cde886542947f0bb","repo":"jackwener/OpenCLI","slug":"jd-com","errorCode":null,"errorMessage":"jd.com","messagePattern":"jd\\.com","errorType":"exception","errorClass":"AuthRequiredError","httpStatus":null,"severity":"error","filePath":"clis/jd/auth.js","lineNumber":12,"sourceCode":"import { AuthRequiredError, CommandExecutionError } from '@jackwener/opencli/errors';\nimport { registerSiteAuthCommands } from '../_shared/site-auth.js';\n\nasync function hasJdSessionCookie(page) {\n  const cookies = await page.getCookies({ url: 'https://www.jd.com' });\n  const names = new Set(cookies.map(c => c.name));\n  return names.has('pin') || names.has('thor');\n}\n\nasync function verifyJdIdentity(page) {\n  if (!await hasJdSessionCookie(page)) {\n    throw new AuthRequiredError('jd.com', 'JD pin / thor cookie missing');\n  }\n  await page.goto('https://home.jd.com/');\n  await page.wait(3);\n  const probe = await page.evaluate(`\n    (() => {\n      const pinCookie = (document.cookie.split('; ').find(c => c.startsWith('pin=')) || '').split('=')[1] || '';\n      const decoded = pinCookie ? decodeURIComponent(pinCookie) : '';\n      if (!decoded) {\n        return { kind: 'auth', detail: 'JD pin cookie empty after decode' };\n      }\n      const nickEl = document.querySelector('.user-info, #aliveUserName, .name, .user-name');\n      const nickname = (nickEl && nickEl.textContent && nickEl.textContent.trim()) || '';\n      return { ok: true, pin: decoded, nickname };\n    })()\n  `);\n  if (probe?.kind === 'auth') throw new AuthRequiredError('jd.com', probe.detail);\n  if (!probe?.ok) throw new CommandExecutionError(`Unexpected JD probe: ${JSON.stringify(probe)}`);\n  return { pin: probe.pin, nickname: probe.nickname };","sourceCodeStart":1,"sourceCodeEnd":30,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/jd/auth.js#L1-L30","documentation":"verifyJdIdentity throws AuthRequiredError('jd.com') when the browser's cookie jar for JD contains neither the 'pin' nor 'thor' cookie, meaning no logged-in JD session exists. This is the library's pre-flight identity check before probing account details on home.jd.com.","triggerScenarios":"Any jd auth verify / whoami / login poll invocation where page.getCookies() for JD returns no 'pin' and no 'thor' cookie — anonymous profile, logged-out browser, or cookies cleared.","commonSituations":"Fresh automation profile never logged in to JD; user logged out manually; JD expired/cleared the session cookie; wrong Chrome profile connected (cookies live in another profile).","solutions":["Log in to https://www.jd.com in the Chrome profile the CLI is connected to","Run `jd auth login` and complete the browser login flow","Verify the CLI is attached to the intended browser profile (one with JD cookies)","After login, re-run the verify/whoami command"],"exampleFix":"// before\nconst me = await jdWhoami();\n// after\nif (!(await jdHasSessionCookie())) {\n  await jdAuthLogin();\n}\nconst me = await jdWhoami();","handlingStrategy":"validation","validationCode":"const cookies = await page.getCookies({ url: 'https://www.jd.com' });\nconst names = new Set(cookies.map(c => c.name));\nif (!names.has('pin') && !names.has('thor')) {\n  await jdAuthLogin(); // pre-flight login before verify\n}","typeGuard":"function hasJdSession(cookies) {\n  const names = new Set(cookies.map(c => c.name));\n  return names.has('pin') || names.has('thor');\n}","tryCatchPattern":"try {\n  const me = await jdVerify();\n} catch (e) {\n  if (e.code === 'AUTH_REQUIRED') return loginAndRetry();\n  throw e;\n}","preventionTips":["Check for pin/thor cookies before JD calls","Always complete the jd auth login flow before scripted JD usage","Confirm the correct Chrome profile is connected","Treat AUTH_REQUIRED (exit NOPERM) as 'log in', not a bug"],"tags":["auth","jd","cookies","login-required"],"backgroundTag":"site-session-not-logged-in","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}