{"record":{"id":"2dc4cd597f9f3941","repo":"BigPizzaV3/CodexPlusPlus","slug":"https-api","errorCode":null,"errorMessage":"请输入完整的 HTTPS API 地址","messagePattern":"请输入完整的 HTTPS API 地址","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"tools/conversation-canvas/public/canvas.user.js","lineNumber":622,"sourceCode":"  // resume reads the existing response instead of launching duplicate work.\n  for(;;){\n    signal?.throwIfAborted();\n    const conversation=manager.getConversation(session.sideId);\n    if(!conversation)throw Error('后台整理会话已失效，已完成批次仍保留；点击继续可重新处理本批');\n    const turn=nativeTurns(conversation).find(t=>t.turnId===session.turnId);\n    if(turn&&turn.status!=='inProgress'){\n      if(turn.status!=='completed'||turn.error){session.requestId=null;session.turnId=null;session.phase='ready';await save();throw Error('本批整理中断，已完成批次已保存，可点击继续');}\n      if(session.phase!=='completed')session.batches=(session.batches||0)+1;\n      session.phase='completed';await save();\n      return turn.items.filter(i=>i.type==='agentMessage'&&(i.phase==null||i.phase==='final_answer')).map(i=>i.text??'').join('\\n');\n    }\n    await new Promise(resolve=>setTimeout(resolve,1000));\n  }\n}\n\n  // OpenAI-compatible Chat Completions. Never persist credentials in tree checkpoints.\nfunction apiEndpoint(raw){\n  let url;try{url=new URL(String(raw).trim());}catch{throw Error('请输入完整的 HTTPS API 地址');}\n  if(url.protocol!=='https:'||url.username||url.password||url.search||url.hash)throw Error('API 地址须使用 HTTPS，且不含账号、密码、查询参数或片段');\n  const path=url.pathname.replace(/\\/+$/,'');\n  url.pathname=path.endsWith('/chat/completions')?path:(path||'/v1')+'/chat/completions';\n  return url.href;\n}\n\nfunction apiConfig(input){\n  const channel=input?.channel==='external'?'external':'native';\n  const value={channel,baseUrl:String(input?.baseUrl||'').trim(),model:String(input?.model||'').trim(),key:String(input?.key||'').trim(),remember:input?.remember===true,speed:input?.speed==='provider'?'provider':'fast',revision:input?.revision||crypto.randomUUID()};\n  if(channel==='external'){\n    value.endpoint=apiEndpoint(value.baseUrl);\n    if(!value.model||value.model.length>200)throw Error('请填写 API 的模型名称');\n    if(!value.key||/[\\r\\n]/.test(value.key))throw Error('请在设置中填写有效 API Key');\n  }\n  return value;\n}\n\nfunction storedApiConfig(config){","sourceCodeStart":604,"sourceCodeEnd":640,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/tools/conversation-canvas/public/canvas.user.js#L604-L640","documentation":"apiEndpoint() parses the user-supplied base URL for external Chat Completions mode with new URL(). If the string cannot be parsed into a valid absolute URL (missing scheme, empty, malformed), it throws this error demanding a complete HTTPS API address.","triggerScenarios":"Saving external-API settings where baseUrl is empty, lacks a scheme (e.g. 'api.example.com/v1' without https://), or is otherwise not an absolute URL.","commonSituations":"User pasted a host without https://; left the field blank; pasted a relative path; copy/paste introduced whitespace or a broken URL.","solutions":["Enter a full absolute URL including scheme, e.g. https://api.openai.com/v1 (the /chat/completions suffix is appended automatically).","Trim stray whitespace/newlines from the field.","Use the provider's documented base URL, not a page URL or relative path."],"exampleFix":"// before\nbaseUrl = 'api.example.com/v1';\n// after\nbaseUrl = 'https://api.example.com/v1';","handlingStrategy":"validation","validationCode":"function validBaseUrl(raw){ try { const u = new URL(String(raw).trim()); return u.protocol === 'http:' || u.protocol === 'https:'; } catch { return false; } }","typeGuard":"const isAbsoluteUrl = (s) => { try { new URL(s); return true; } catch { return false; } };","tryCatchPattern":"try { saveExternalApiSettings(input); } catch (e) { if (e.message.includes('HTTPS API 地址')) showFieldError('baseUrl', '必须为完整 https:// 地址'); }","preventionTips":["Always include the https:// scheme when entering the base URL.","Normalize/trim input before validation.","Show an inline hint with an example URL (https://api.example.com/v1) next to the field."],"tags":["url","validation","configuration"],"backgroundTag":"invalid-url-format","analyzedSha":"b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6","analyzedAt":"2026-09-19T23:35:21.129Z","contentChangedAt":"2026-09-19T23:35:21.129Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}