Fix: Send Authorization header to /auth/me

This commit is contained in:
Hiro
2026-03-31 00:02:06 +00:00
parent f758927848
commit ae324352a4
13 changed files with 191 additions and 2 deletions
+1
View File
@@ -0,0 +1 @@
import{d as l,c as n,q as c,b as i,Q as r,o}from"./index-D2fAAQJ2.js";const u=["type","disabled"],f={key:0,class:"btn__spinner"},b=l({__name:"Button",props:{variant:{default:"primary"},size:{default:"md"},disabled:{type:Boolean,default:!1},loading:{type:Boolean,default:!1},type:{default:"button"}},setup(e){return(t,a)=>(o(),n("button",{type:e.type,disabled:e.disabled||e.loading,class:c(["btn",`btn--${e.variant}`,`btn--${e.size}`])},[e.loading?(o(),n("span",f)):i("",!0),r(t.$slots,"default",{},void 0)],10,u))}}),m=(e,t)=>{const a=e.__vccOpts||e;for(const[s,d]of t)a[s]=d;return a},y=m(b,[["__scopeId","data-v-a1ef9cca"]]);export{y as B,m as _};
+1
View File
@@ -0,0 +1 @@
import{d as b,k as x,c as a,a as t,t as u,l as c,f as p,g as i,F as P,m as B,r as f,o as n,h as m,e as y,v as g,w as N,j as D,b as M}from"./index-D2fAAQJ2.js";import{u as V}from"./projects-CWhQXAJL.js";import{B as _,_ as S}from"./Button-D-QrZfPJ.js";import{M as $}from"./Modal-C7dh6Uqe.js";const F={class:"dashboard"},U={class:"dashboard__header"},z={class:"dashboard__subtitle"},L={key:0,class:"dashboard__loading"},H={key:1,class:"dashboard__empty"},R={key:2,class:"dashboard__grid"},T=["onClick"],E={class:"project-card__content"},I={class:"project-card__name"},Y={key:0,class:"project-card__desc"},q={class:"project-card__date"},A={class:"form__field"},G={class:"form__field"},J=b({__name:"Dashboard",setup(K){const k=D(),s=V(),l=f(!1),d=f(""),v=f(""),j=f(!1);x(async()=>{await s.fetchProjects()});function h(r){k.push(`/projects/${r}`)}async function w(){if(d.value.trim()){j.value=!0;try{const r=await s.createProject(d.value.trim(),v.value.trim());l.value=!1,d.value="",v.value="",h(r.id)}catch(r){console.error("Failed to create project:",r)}finally{j.value=!1}}}function C(r){return new Date(r).toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric"})}return(r,e)=>(n(),a("div",F,[t("div",U,[t("div",null,[e[6]||(e[6]=t("h1",{class:"dashboard__title"},"Your Projects",-1)),t("p",z,u(c(s).projects.length)+" project"+u(c(s).projects.length!==1?"s":""),1)]),p(_,{variant:"primary",onClick:e[0]||(e[0]=o=>l.value=!0)},{default:i(()=>[...e[7]||(e[7]=[t("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"},[t("line",{x1:"12",y1:"5",x2:"12",y2:"19"}),t("line",{x1:"5",y1:"12",x2:"19",y2:"12"})],-1),m(" New Project ",-1)])]),_:1})]),c(s).loading?(n(),a("div",L,[...e[8]||(e[8]=[t("div",{class:"dashboard__spinner"},null,-1),t("p",null,"Loading projects...",-1)])])):c(s).projects.length===0?(n(),a("div",H,[e[10]||(e[10]=t("svg",{width:"64",height:"64",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"1.5"},[t("path",{d:"M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"})],-1)),e[11]||(e[11]=t("h2",null,"No projects yet",-1)),e[12]||(e[12]=t("p",null,"Create your first project to start organizing your documents",-1)),p(_,{variant:"primary",onClick:e[1]||(e[1]=o=>l.value=!0)},{default:i(()=>[...e[9]||(e[9]=[m(" Create First Project ",-1)])]),_:1})])):(n(),a("div",R,[(n(!0),a(P,null,B(c(s).projects,o=>(n(),a("article",{key:o.id,class:"project-card",onClick:O=>h(o.id)},[e[13]||(e[13]=t("div",{class:"project-card__icon"},[t("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"},[t("path",{d:"M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"})])],-1)),t("div",E,[t("h3",I,u(o.name),1),o.description?(n(),a("p",Y,u(o.description),1)):M("",!0),t("p",q," Updated "+u(C(o.updated_at)),1)]),e[14]||(e[14]=t("svg",{class:"project-card__arrow",width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"},[t("path",{d:"m9 18 6-6-6-6"})],-1))],8,T))),128))])),p($,{show:l.value,title:"Create New Project",onClose:e[5]||(e[5]=o=>l.value=!1)},{footer:i(()=>[p(_,{variant:"secondary",onClick:e[4]||(e[4]=o=>l.value=!1)},{default:i(()=>[...e[17]||(e[17]=[m("Cancel",-1)])]),_:1}),p(_,{variant:"primary",loading:j.value,onClick:w},{default:i(()=>[...e[18]||(e[18]=[m("Create Project",-1)])]),_:1},8,["loading"])]),default:i(()=>[t("form",{onSubmit:N(w,["prevent"])},[t("div",A,[e[15]||(e[15]=t("label",{for:"project-name",class:"form__label"},"Project Name",-1)),y(t("input",{id:"project-name","onUpdate:modelValue":e[2]||(e[2]=o=>d.value=o),type:"text",class:"form__input",placeholder:"My Research Project",autofocus:""},null,512),[[g,d.value]])]),t("div",G,[e[16]||(e[16]=t("label",{for:"project-desc",class:"form__label"},"Description (optional)",-1)),y(t("textarea",{id:"project-desc","onUpdate:modelValue":e[3]||(e[3]=o=>v.value=o),class:"form__textarea",placeholder:"Brief description of your project...",rows:"3"},null,512),[[g,v.value]])])],32)]),_:1},8,["show"])]))}}),ee=S(J,[["__scopeId","data-v-a5d62dba"]]);export{ee as default};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
import{d as C,u as k,c as _,a as e,t as n,w as S,b as A,e as v,v as g,f as B,g as M,h as p,r as i,i as m,j as V,o as f}from"./index-D2fAAQJ2.js";import{B as D,_ as E}from"./Button-D-QrZfPJ.js";const N={class:"login"},I={class:"login__card"},L={class:"login__header"},T={class:"login__title"},U={class:"login__subtitle"},P={key:0,class:"login__error"},R={class:"login__field"},j={class:"login__field"},z={class:"login__toggle"},W=C({__name:"Login",setup(q){const h=V(),r=k(),o=i(""),s=i(""),a=i(!1),u=i(!1),l=i(""),w=m(()=>a.value?"Create Account":"Welcome Back"),y=m(()=>a.value?"Create Account":"Sign In");async function b(){if(!o.value||!s.value){l.value="Please fill in all fields";return}u.value=!0,l.value="";try{a.value?(await r.register(o.value,s.value),await r.login(o.value,s.value)):await r.login(o.value,s.value),h.push("/dashboard")}catch(d){l.value=d instanceof Error?d.message:"Authentication failed"}finally{u.value=!1}}function x(){a.value=!a.value,l.value=""}return(d,t)=>(f(),_("div",N,[e("div",I,[e("div",L,[t[2]||(t[2]=e("svg",{width:"40",height:"40",viewBox:"0 0 28 28",fill:"none"},[e("rect",{width:"28",height:"28",rx:"6",fill:"var(--accent)"}),e("path",{d:"M8 10h12M8 14h8M8 18h10",stroke:"white","stroke-width":"2","stroke-linecap":"round"})],-1)),e("h1",T,n(w.value),1),e("p",U,n(a.value?"Create your account to get started":"Sign in to access your documents"),1)]),e("form",{class:"login__form",onSubmit:S(b,["prevent"])},[l.value?(f(),_("div",P,n(l.value),1)):A("",!0),e("div",R,[t[3]||(t[3]=e("label",{for:"username",class:"login__label"},"Username",-1)),v(e("input",{id:"username","onUpdate:modelValue":t[0]||(t[0]=c=>o.value=c),type:"text",class:"login__input",placeholder:"Enter your username",autocomplete:"username"},null,512),[[g,o.value]])]),e("div",j,[t[4]||(t[4]=e("label",{for:"password",class:"login__label"},"Password",-1)),v(e("input",{id:"password","onUpdate:modelValue":t[1]||(t[1]=c=>s.value=c),type:"password",class:"login__input",placeholder:"Enter your password",autocomplete:"current-password"},null,512),[[g,s.value]])]),B(D,{type:"submit",variant:"primary",size:"lg",loading:u.value,style:{width:"100%"}},{default:M(()=>[p(n(y.value),1)]),_:1},8,["loading"]),e("p",z,[p(n(a.value?"Already have an account?":"Don't have an account?")+" ",1),e("button",{type:"button",class:"login__toggle-btn",onClick:x},n(a.value?"Sign in":"Create one"),1)])],32)]),t[5]||(t[5]=e("p",{class:"login__footer"}," Claudia Docs — Document Management for AI Agents ",-1))]))}}),H=E(W,[["__scopeId","data-v-d1a9e623"]]);export{H as default};
+1
View File
@@ -0,0 +1 @@
import{d as _,n as f,x as u,s as k,f as h,T as v,g as p,O as y,o as s,c as l,a,t as C,b as n,Q as i,q as B}from"./index-D2fAAQJ2.js";import{_ as w}from"./Button-D-QrZfPJ.js";const $={key:0,class:"modal__header"},b={class:"modal__title"},E={class:"modal__body"},g={key:1,class:"modal__footer"},z=_({__name:"Modal",props:{show:{type:Boolean},title:{},size:{default:"md"}},emits:["close"],setup(o,{emit:c}){const t=c;function r(e){e.target.classList.contains("modal")&&t("close")}function m(e){e.key==="Escape"&&t("close")}return f(()=>t,()=>{},{immediate:!0}),u(()=>{document.removeEventListener("keydown",m)}),(e,d)=>(s(),k(y,{to:"body"},[h(v,{name:"modal"},{default:p(()=>[o.show?(s(),l("div",{key:0,class:"modal",onClick:r},[a("div",{class:B(["modal__content",`modal__content--${o.size}`])},[o.title?(s(),l("div",$,[a("h2",b,C(o.title),1),a("button",{class:"modal__close",onClick:d[0]||(d[0]=M=>t("close"))},"×")])):n("",!0),a("div",E,[i(e.$slots,"default",{},void 0,!0)]),e.$slots.footer?(s(),l("div",g,[i(e.$slots,"footer",{},void 0,!0)])):n("",!0)],2)])):n("",!0)]),_:3})]))}}),V=w(z,[["__scopeId","data-v-f5a1757e"]]);export{V as M};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+30
View File
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
import{z as F,r as s,A as B,B as R}from"./index-D2fAAQJ2.js";const b=F("projects",()=>{const c=s([]),n=s(null),d=s([]),f=s([]),h=s([]),i=s(!1),l=s(null),a=R();async function j(){i.value=!0,l.value=null;try{const e=await a.get("/projects");c.value=e.projects}catch(e){throw l.value=e instanceof Error?e.message:"Failed to fetch projects",e}finally{i.value=!1}}async function w(e){i.value=!0,l.value=null;try{n.value=await a.get(`/projects/${e}`),await p(e)}catch(o){throw l.value=o instanceof Error?o.message:"Failed to fetch project",o}finally{i.value=!1}}async function p(e){try{const[o,t]=await Promise.all([a.get(`/projects/${e}/folders`),a.get(`/projects/${e}/documents`)]);d.value=o.folders,f.value=t.documents,y()}catch(o){throw l.value=o instanceof Error?o.message:"Failed to fetch project tree",o}}function y(){const e=new Map,o=[];for(const t of d.value){const r={id:t.id,name:t.name,type:"folder",children:[],parent_id:t.parent_id};e.set(t.id,r)}for(const t of f.value)if(!t.folder_id){const r={id:t.id,name:t.title,type:"document",parent_id:null};e.set(t.id,r)}for(const t of f.value)if(t.folder_id){const r=e.get(t.folder_id);r&&r.children&&r.children.push({id:t.id,name:t.title,type:"document",parent_id:t.folder_id})}for(const t of e.values())if(t.parent_id===null)o.push(t);else{const r=e.get(t.parent_id);r&&r.children&&r.children.push(t)}h.value=o}async function m(e,o){const t=await a.post("/projects",{name:e,description:o});return c.value.push(t),t}async function _(e,o,t){var v;const r=await a.put(`/projects/${e}`,{name:o,description:t}),u=c.value.findIndex(A=>A.id===e);return u!==-1&&(c.value[u]=r),((v=n.value)==null?void 0:v.id)===e&&(n.value=r),r}async function $(e){var o;await a.delete(`/projects/${e}`),c.value=c.value.filter(t=>t.id!==e),((o=n.value)==null?void 0:o.id)===e&&(n.value=null)}async function g(e,o,t=null){const r=await a.post(`/projects/${e}/folders`,{name:o,parent_id:t});return d.value.push(r),await p(e),r}async function P(e){await a.delete(`/folders/${e}`),n.value&&await p(n.value.id)}async function E(e,o=2){return await a.get(`/projects/${e}/graph?depth=${o}`)}async function x(e,o,t=!0){const u=await fetch(`http://localhost:8000/api/v1/projects/${e}/export?format=${o}&include_metadata=${t}`,{headers:{Authorization:`Bearer ${B()}`},credentials:"include"});if(!u.ok)throw new Error("Export failed");return await u.blob()}return{projects:c,currentProject:n,folders:d,documents:f,treeNodes:h,loading:i,error:l,fetchProjects:j,fetchProject:w,fetchProjectTree:p,createProject:m,updateProject:_,deleteProject:$,createFolder:g,deleteFolder:P,fetchProjectGraph:E,exportProject:x}});export{b as u};
+4 -2
View File
@@ -46,11 +46,13 @@ export function useApi() {
console.log(`[useApi] ${method} ${endpoint} - token: ${token ? 'present' : 'null'}`)
// Only add Authorization header for non-auth endpoints
if (token && !endpoint.includes('/auth/')) {
// NOTE: /auth/me DOES need the token to identify the user
const noAuthEndpoints = ['/auth/login', '/auth/register', '/auth/logout', '/auth/refresh']
if (token && !noAuthEndpoints.includes(endpoint)) {
headers['Authorization'] = `Bearer ${token}`
console.log(`[useApi] Added Authorization header: Bearer ${token.substring(0, 10)}...`)
} else {
console.log(`[useApi] NO Authorization header - token=${token}, isAuthEndpoint=${endpoint.includes('/auth/')}`)
console.log(`[useApi] NO Authorization header - token=${token ? 'present' : 'null'}, endpoint=${endpoint}`)
}
const response = await fetch(`${BASE_URL}${endpoint}`, {