@aiquants/daily-report 0.6.0 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -38
- package/dist/client.d.mts +9 -3
- package/dist/client.d.ts +9 -3
- package/dist/client.js +4 -4
- package/dist/client.js.map +1 -1
- package/dist/client.mjs +4 -4
- package/dist/client.mjs.map +1 -1
- package/dist/server.d.mts +34 -4
- package/dist/server.d.ts +34 -4
- package/dist/server.js +6 -6
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +6 -6
- package/dist/server.mjs.map +1 -1
- package/package.json +3 -3
- package/src/client/components/daily-report-detail-list.tsx +28 -6
- package/src/client/components/daily-report-list.tsx +25 -4
- package/src/client/components/daily-report-resolved-content.tsx +28 -4
- package/src/client/config-context.tsx +2 -0
- package/src/client/contexts/daily-report-action-context.tsx +5 -1
- package/src/client/route-helpers.ts +8 -2
- package/src/server/authz.spec.ts +57 -0
- package/src/server/authz.ts +99 -0
- package/src/server/handlers.ts +5 -4
- package/src/server/service.ts +31 -13
- package/src/server.ts +1 -0
package/dist/server.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
var He=n=>({async getEpoch(t){try{let a=await n?.getClient();if(!a)return 0;let o=await a.get(t);return o?Number(o):0}catch{return 0}},async incrementEpoch(t){try{let a=await n?.getClient();if(!a)return;await a.incr(t)}catch{}}}),we=class{constructor(t,a){this.config=t;this.epochStore=a;this.buckets=new Map;this.inFlight=new Map;this.invalidate=t=>{this.buckets.delete(t),this.inFlight.delete(t)};this.getOrFetch=async t=>{let{cacheKey:a,forceRefresh:o,snapshot:g}=t,y=this.buckets.get(a);if(o&&(this.buckets.delete(a),this.inFlight.delete(a)),!o&&y&&y.expireAt>Date.now())if(t.epochKey){let d=await this.epochStore.getEpoch(t.epochKey);if(y.epoch===d)return g?y.records.map(j=>structuredClone(j)):y.records;this.buckets.delete(a)}else return g?y.records.map(d=>structuredClone(d)):y.records;if(!o&&this.inFlight.has(a)){let d=await this.inFlight.get(a);return g?d.map(j=>structuredClone(j)):d}let O;O=(async()=>{let d=await t.fetcher();if(o||this.inFlight.get(a)===O){let j=Date.now()+(t.ttlMsOverride??this.config.defaultTtlMs),u=t.epochKey?await this.epochStore.getEpoch(t.epochKey):0;this.buckets.set(a,{records:d,expireAt:j,epoch:u}),this.buckets.size>500&&this.cleanExpired()}return d})(),o||this.inFlight.set(a,O);try{let d=await O;return g?d.map(j=>structuredClone(j)):d}finally{this.inFlight.delete(a)}};this.flush=t=>{this.buckets.delete(t),this.inFlight.delete(t)};this.clearAll=()=>{this.buckets.clear(),this.inFlight.clear()};this.invalidatePrefix=t=>{for(let a of this.buckets.keys())a.startsWith(t)&&this.buckets.delete(a);for(let a of this.inFlight.keys())a.startsWith(t)&&this.inFlight.delete(a)}}cleanExpired(){let t=Date.now();for(let[a,o]of this.buckets.entries())o.expireAt<=t&&this.buckets.delete(a)}};var dt=/^\d{4}-\d{2}-\d{2}$/,ut=/^\d{4}\/\d{2}\/\d{2}$/,Ye=n=>n<10?`0${n}`:`${n}`,qe=n=>{if(Number.isNaN(n.getTime()))return null;let t=n.getFullYear(),a=Ye(n.getMonth()+1),o=Ye(n.getDate());return`${t}-${a}-${o}`},V=n=>{if(n==null)return null;if(n instanceof Date)return qe(n);let t=n.trim();if(t==="")return null;if(dt.test(t))return t;if(ut.test(t))return t.replaceAll("/","-");let a=new Date(t);return qe(a)};var ne=(n,t,a=console)=>{let o=g=>typeof g=="string"?[`${t} ${g}`]:[t,g];return{debug:(g,...y)=>{n<=0&&a.debug(...o(g),...y)},info:(g,...y)=>{n<=1&&a.info(...o(g),...y)},warn:(g,...y)=>{n<=2&&a.warn(...o(g),...y)},error:(g,...y)=>{n<=3&&a.error(...o(g),...y)}}};import{z as i}from"zod";var ct=i.object({name:i.string().nullish(),affiliation:i.string().nullish()}),pt=i.object({name:i.string().nullish(),text:i.string().nullish(),color:i.string().nullish()}),mt=i.object({id:i.number(),name:i.string().nullish(),color:i.string().nullish()}),Oe=i.object({id:i.number(),userId:i.string().nullish(),userName:i.string().nullish(),content:i.string().nullish(),createdAt:i.string().nullish(),isMine:i.boolean()}),ve=i.object({reportHubId:i.number(),date:i.string().nullish(),createdAt:i.string().nullish(),author:i.string().nullish(),userId:i.string().nullish(),sourceType:i.string().nullish(),employeeName:i.string().nullish(),updatedBy:i.string().nullish(),updatedAt:i.string().nullish(),category:i.string().nullish(),creationCategory:i.string().nullish(),visitTimeFrom:i.string().nullish(),visitTimeTo:i.string().nullish(),customerName:i.string().nullish(),interviewers:i.array(ct),subject:i.string().nullish(),content:i.string().nullish(),comments:i.array(pt),isRead:i.boolean(),isStarred:i.boolean(),labels:i.array(mt),commentItems:i.array(Oe)}),yt=i.object({type:i.literal("connected")}),Se=i.object({type:i.literal("status-update"),reportHubId:i.number(),statusType:i.enum(["star","read"]),value:i.boolean(),clientTempId:i.string(),recipientRawUserId:i.number().optional()}),Me=i.object({type:i.literal("comment-add"),reportHubId:i.number(),comment:Oe,clientTempId:i.string()}),xe=i.object({type:i.literal("comment-delete"),reportHubId:i.number(),commentId:i.number(),clientTempId:i.string()}),Ne=i.object({type:i.literal("report-create"),reportHubId:i.number(),report:ve,clientTempId:i.string(),recipientRawUserId:i.number().optional()}),Ee=i.object({type:i.literal("report-update"),reportHubId:i.number(),report:ve,clientTempId:i.string(),recipientRawUserId:i.number().optional()}),ke=i.object({type:i.literal("report-publish"),reportHubId:i.number(),report:ve,clientTempId:i.string(),recipientRawUserId:i.number().optional()}),$e=i.object({type:i.literal("report-delete"),reportHubId:i.number(),clientTempId:i.string()}),Fe=i.discriminatedUnion("type",[yt,Se,Me,xe,Ne,Ee,ke,$e]);import{createHash as gt}from"crypto";var Le=n=>{let t=JSON.stringify(n);return`"${gt("sha256").update(t).digest("hex")}"`};var ht=ne(1,"[Response]"),ae=(n,t,a,o=200,g=ht)=>{let y=Le(a),O=n.headers.get("If-None-Match");g.info(`[jsonResponseWithETag] ETag: ${y}, If-None-Match: ${O}`);let d=new Headers({"Content-Type":"application/json","Cache-Control":"private, max-age=0, must-revalidate","X-Content-Type-Options":"nosniff","X-Frame-Options":"DENY","Content-Security-Policy":"default-src 'none'",ETag:y});return t&&d.append("Set-Cookie",t),n.method==="GET"&&o===200&&O===y?new Response(null,{status:304,headers:d}):new Response(JSON.stringify(a),{status:o,headers:d})};import{EventEmitter as ft}from"events";var Ce=(n,t)=>{let[a,o]=n.split("-").map(Number),[g,y]=t.split("-").map(Number);return a!==g?a<g:o<=y},_e=class{constructor(t){this.config=t;this._emitter=new ft;this._state="idle";this._refCount=0;this._lastId="0-0";this._emitter.setMaxListeners(0),this._logger=t.logger??ne(1,"[SSE Reader]")}subscribe(t,a){return this._emitter.on("entry",t),a&&this._emitter.on("error",a),this._refCount++,this._refCount===1&&this._startLoop(),()=>{this._emitter.removeListener("entry",t),a&&this._emitter.removeListener("error",a),this._refCount--,this._refCount<=0&&(this._refCount=0,this._stopLoop())}}async destroy(){this._refCount=0,await this._stopLoop(),this._emitter.removeAllListeners(),this._lastId="0-0"}async _startLoop(){for(;this._state==="stopping";)await new Promise(t=>setTimeout(t,50));if(this._state!=="running"){this._state="running";try{this._client=await this.config.redis?.createClient()}catch(t){this._state="idle",this._emitter.emit("error",t instanceof Error?t:new Error("Failed to create Redis client for SSE reader"));return}if(!this._client){this._state="idle",this._emitter.emit("error",new Error("Failed to create Redis client for SSE reader"));return}this._client.on("error",t=>{this._logger.error("Redis client error:",t)});try{for(;this._state==="running"&&this._client?.isOpen;){let t=await this._client.xRead([{key:this.config.streamKey,id:this._lastId}],{BLOCK:5e3,COUNT:100});if(t)for(let a of t)for(let o of a.messages){this._lastId=o.id;try{let g=o.message?.data?JSON.parse(o.message.data):null,y=g?.type;if((y==="report-create"||y==="report-delete"||y==="report-publish")&&this.config.cache.invalidatePrefix("daily-report:ids"),y==="comment-add"||y==="comment-delete"||y==="status-update"){let O=g?.reportHubId;typeof O=="number"&&(this.config.cache.invalidate(`daily-report:detail:${O}`),this.config.cache.invalidatePrefix(`daily-report:detail:${O}:user:`))}}catch{}this._emitter.emit("entry",{id:o.id,message:o.message})}}}catch(t){!(t?.constructor?.name==="ClientClosedError")&&this._state==="running"&&(this._logger.error("xRead loop error:",t),this._emitter.emit("error",t))}finally{if(this._client?.isOpen)try{await this._client.quit()}catch{}this._client=void 0,this._state="idle",this._refCount>0&&this._startLoop()}}}async _stopLoop(){if(this._state==="running"){if(this._state="stopping",this._client?.isOpen)try{await this._client.quit()}catch{}for(;this._state!=="idle";)await new Promise(t=>setTimeout(t,50))}}};var v=(n,t)=>new Response(JSON.stringify(n),{status:t?.status??200,headers:{"Content-Type":"application/json"}});function ze(n){let{authenticate:t,service:a,encodeUserId:o,redis:g,sseReader:y,streamKey:O}=n,d=n.loginRedirectPath??"/auth/login",j=n.logger??ne(3,"[DailyReportAPI]"),u=n.logger??ne(1,"[DailyReportSSE]"),m=async({request:C})=>{let{user:L,cookie:S}=await t(C,{failureRedirect:d}),$=new Headers;S&&$.append("Set-Cookie",S);let _=null;L&&(_=await a.getUserIdByExternalId(L.id));let w=_?o(_):null;return{data:{user:L,userId:w},headers:$}},E={"business-date":async(C,L,S,$)=>{let _=V(C.searchParams.get("businessDate")),w=C.searchParams.get("forceRefresh")==="true";if(!_)return ae(S,L,{error:{message:"Invalid business date"}},400);let P=await a.getDailyReportsByBusinessDateByExternalId(_,$.id,{forceRefresh:w});return ae(S,L,{businessDate:_,reports:P},200)},ids:async(C,L,S,$)=>{let _=C.searchParams.get("forceRefresh")==="true",w=await a.getDailyReportIdsByExternalId($.id,{forceRefresh:_});return ae(S,L,{ids:w},200)},report:async(C,L,S,$)=>{let _=C.searchParams.get("reportHubId"),w=C.searchParams.get("forceRefresh")==="true",P=_?Number.parseInt(_,10):NaN;if(!Number.isFinite(P)||P<=0)return ae(S,L,{error:{message:"Invalid reportHubId"}},400);let M=await a.getDailyReportDetailByIdByExternalId(P,$.id,{snapshot:!0,forceRefresh:w});return M?ae(S,L,{report:M},200):ae(S,L,{error:{message:"Report not found"}},404)}};return{index:{loader:m},api:{loader:async({request:C,params:L})=>{let{user:S,cookie:$}=await t(C,{failureRedirect:null}),_=$??null;if(!S)return ae(C,_,{error:{message:"Unauthorized"}},401);if(C.method!=="GET")return ae(C,_,{error:{message:"Method not allowed"}},405);let w=L.endpoint??"",P=E[w];if(!P)return ae(C,_,{error:{message:"Unknown endpoint"}},404);let M=Date.now();try{let D=new URL(C.url);return await P(D,_,C,S)}catch(D){let q=Date.now()-M,Q=D instanceof Error?D:new Error(String(D));return j.error(`500 endpoint=${w} elapsed=${q}ms name=${Q.name} code=${"code"in Q?Q.code:"N/A"} message=${Q.message}`),j.error("Stack:",Q.stack),ae(C,_,{error:{message:"Internal Server Error"}},500)}},action:async({request:C,params:L})=>{let{user:S}=await t(C,{failureRedirect:null});if(!S)return v({error:"Unauthorized"},{status:401});if(L.endpoint!=="action")return v({error:"Unknown endpoint"},{status:404});let _=await a.getUserIdByExternalId(S.id);if(!_)return v({error:"User not found"},{status:404});let w=await C.formData(),P=w.get("intent"),M=w.get("reportHubId"),D=M?Number(M):NaN,q=w.get("businessDate"),Q=Number(w.get("operationTimestamp")),x=w.get("clientTempId");if(!x)return v({error:"clientTempId required"},{status:400});if(P!=="create"&&(!D||Number.isNaN(D)))return v({error:"Invalid reportHubId"},{status:400});switch(P){case"create":{if(!q)return v({error:"businessDate required"},{status:400});let c=await a.createDailyReport(_,q,x);return v({status:"OK",intent:"create",report:c,reportHubId:String(c.reportHubId),clientTempId:x})}case"update":{let c=w.get("title"),k=w.get("content");try{return await a.updateDailyReport(D,_,{title:c,content:k},x),v({status:"OK",intent:"update",reportHubId:String(D),clientTempId:x})}catch(A){if(A instanceof Error){if(A.message==="Unauthorized")return v({error:"Unauthorized"},{status:403});if(A.message==="Not Found")return v({error:"Report not found"},{status:404})}throw A}}case"publish":try{let c=await a.publishDailyReport(D,_,x);return v({status:"OK",intent:"publish",reportHubId:String(D),clientTempId:x,report:c})}catch(c){if(c instanceof Error){if(c.message==="Unauthorized")return v({error:"Unauthorized"},{status:403});if(c.message==="Not Found")return v({error:"Report not found"},{status:404})}throw c}case"delete":try{return await a.deleteDailyReport(D,_,x),v({status:"OK",intent:"delete",reportHubId:String(D),clientTempId:x})}catch(c){if(c instanceof Error){if(c.message==="Unauthorized")return v({error:"Unauthorized"},{status:403});if(c.message==="Not Found")return v({error:"Report not found"},{status:404})}throw c}case"toggleStar":{let c=w.get("isStarred");if(c===null)return v({error:"isStarred required"},{status:400});let k=c==="true",A=await a.setStarStatus(_,D,q,k,x);return v({status:"OK",intent:"toggleStar",updatedStatus:{isStarred:A.isStarred,isRead:A.isRead},operationTimestamp:Q,reportHubId:String(D),clientTempId:x})}case"toggleRead":{let c=w.get("isRead");if(c===null)return v({error:"isRead required"},{status:400});let k=c==="true",A=await a.setReadStatus(_,D,q,k,x);return v({status:"OK",intent:"toggleRead",updatedStatus:{isStarred:A.isStarred,isRead:A.isRead},operationTimestamp:Q,reportHubId:String(D),clientTempId:x})}case"addComment":{let c=w.get("content");if(!c)return v({error:"Content required"},{status:400});let k=await a.addComment(_,D,c,q,x),A={...k,userId:k.userId};return v({status:"OK",intent:"addComment",newComment:A,reportHubId:String(D),clientTempId:x})}case"deleteComment":{let c=Number(w.get("commentId"));if(!c||Number.isNaN(c))return v({error:"Invalid commentId"},{status:400});try{return await a.deleteComment(_,D,c,q,x),v({status:"OK",reportHubId:String(D),deletedCommentId:String(c),clientTempId:x})}catch(k){if(k instanceof Error){if(k.message==="Unauthorized")return v({error:"Unauthorized"},{status:403});if(k.message==="Not Found")return v({error:"Comment not found"},{status:404})}throw k}}case"clearCache":return await a.clearCache(),v({status:"OK",intent:"clearCache"});default:return v({error:"Invalid intent"},{status:400})}}},sse:{loader:async({request:C,params:L})=>{let{user:S}=await t(C,{failureRedirect:null});if(!S)return new Response("Unauthorized",{status:401});let $=await a.getUserIdByExternalId(S.id);if(!$)return new Response("Forbidden",{status:403});if(L.endpoint!=="updates")return new Response("Not Found",{status:404});let w=new URL(C.url).searchParams.get("lastEventId")||C.headers.get("Last-Event-ID"),P=new TextEncoder,M=null,D=null,q=null,Q=!1,x=()=>{if(!Q){if(Q=!0,D&&(clearInterval(D),D=null),q&&(q(),q=null),M)try{M.desiredSize!==null&&M.close()}catch{}finally{M=null}Q=!1}},c=(A,K)=>{if(K.data)try{let T=JSON.parse(K.data),W=Fe.safeParse(T);if(!W.success){u.error("SSE message validation failed:",W.error.format());return}let re=W.data,de=typeof T.recipientRawUserId=="number"?T.recipientRawUserId:void 0;if(re.type==="status-update"){if(de===void 0||de!==$)return}else if(de!==void 0&&de!==$)return;let ge;if("recipientRawUserId"in T){let{recipientRawUserId:Pe,...ue}=T;ge=JSON.stringify(ue)}else ge=K.data;M&&M.desiredSize!==null&&M.enqueue(P.encode(`id: ${A}
|
|
2
|
-
data: ${
|
|
1
|
+
var Oe=r=>({async getEpoch(t){try{let a=await r?.getClient();if(!a)return 0;let o=await a.get(t);return o?Number(o):0}catch{return 0}},async incrementEpoch(t){try{let a=await r?.getClient();if(!a)return;await a.incr(t)}catch{}}}),Se=class{constructor(t,a){this.config=t;this.epochStore=a;this.buckets=new Map;this.inFlight=new Map;this.invalidate=t=>{this.buckets.delete(t),this.inFlight.delete(t)};this.getOrFetch=async t=>{let{cacheKey:a,forceRefresh:o,snapshot:p}=t,c=this.buckets.get(a);if(o&&(this.buckets.delete(a),this.inFlight.delete(a)),!o&&c&&c.expireAt>Date.now())if(t.epochKey){let d=await this.epochStore.getEpoch(t.epochKey);if(c.epoch===d)return p?c.records.map(z=>structuredClone(z)):c.records;this.buckets.delete(a)}else return p?c.records.map(d=>structuredClone(d)):c.records;if(!o&&this.inFlight.has(a)){let d=await this.inFlight.get(a);return p?d.map(z=>structuredClone(z)):d}let Y;Y=(async()=>{let d=await t.fetcher();if(o||this.inFlight.get(a)===Y){let z=Date.now()+(t.ttlMsOverride??this.config.defaultTtlMs),l=t.epochKey?await this.epochStore.getEpoch(t.epochKey):0;this.buckets.set(a,{records:d,expireAt:z,epoch:l}),this.buckets.size>500&&this.cleanExpired()}return d})(),o||this.inFlight.set(a,Y);try{let d=await Y;return p?d.map(z=>structuredClone(z)):d}finally{this.inFlight.delete(a)}};this.flush=t=>{this.buckets.delete(t),this.inFlight.delete(t)};this.clearAll=()=>{this.buckets.clear(),this.inFlight.clear()};this.invalidatePrefix=t=>{for(let a of this.buckets.keys())a.startsWith(t)&&this.buckets.delete(a);for(let a of this.inFlight.keys())a.startsWith(t)&&this.inFlight.delete(a)}}cleanExpired(){let t=Date.now();for(let[a,o]of this.buckets.entries())o.expireAt<=t&&this.buckets.delete(a)}};var pt=/^\d{4}-\d{2}-\d{2}$/,mt=/^\d{4}\/\d{2}\/\d{2}$/,Ke=r=>r<10?`0${r}`:`${r}`,Fe=r=>{if(Number.isNaN(r.getTime()))return null;let t=r.getFullYear(),a=Ke(r.getMonth()+1),o=Ke(r.getDate());return`${t}-${a}-${o}`},Z=r=>{if(r==null)return null;if(r instanceof Date)return Fe(r);let t=r.trim();if(t==="")return null;if(pt.test(t))return t;if(mt.test(t))return t.replaceAll("/","-");let a=new Date(t);return Fe(a)};var ae=(r,t,a=console)=>{let o=p=>typeof p=="string"?[`${t} ${p}`]:[t,p];return{debug:(p,...c)=>{r<=0&&a.debug(...o(p),...c)},info:(p,...c)=>{r<=1&&a.info(...o(p),...c)},warn:(p,...c)=>{r<=2&&a.warn(...o(p),...c)},error:(p,...c)=>{r<=3&&a.error(...o(p),...c)}}};import{z as s}from"zod";var yt=s.object({name:s.string().nullish(),affiliation:s.string().nullish()}),gt=s.object({name:s.string().nullish(),text:s.string().nullish(),color:s.string().nullish()}),ht=s.object({id:s.number(),name:s.string().nullish(),color:s.string().nullish()}),ze=s.object({id:s.number(),userId:s.string().nullish(),userName:s.string().nullish(),content:s.string().nullish(),createdAt:s.string().nullish(),isMine:s.boolean()}),xe=s.object({reportHubId:s.number(),date:s.string().nullish(),createdAt:s.string().nullish(),author:s.string().nullish(),userId:s.string().nullish(),sourceType:s.string().nullish(),employeeName:s.string().nullish(),updatedBy:s.string().nullish(),updatedAt:s.string().nullish(),category:s.string().nullish(),creationCategory:s.string().nullish(),visitTimeFrom:s.string().nullish(),visitTimeTo:s.string().nullish(),customerName:s.string().nullish(),interviewers:s.array(yt),subject:s.string().nullish(),content:s.string().nullish(),comments:s.array(gt),isRead:s.boolean(),isStarred:s.boolean(),labels:s.array(ht),commentItems:s.array(ze)}),ft=s.object({type:s.literal("connected")}),Ie=s.object({type:s.literal("status-update"),reportHubId:s.number(),statusType:s.enum(["star","read"]),value:s.boolean(),clientTempId:s.string(),recipientRawUserId:s.number().optional()}),Ne=s.object({type:s.literal("comment-add"),reportHubId:s.number(),comment:ze,clientTempId:s.string()}),Ee=s.object({type:s.literal("comment-delete"),reportHubId:s.number(),commentId:s.number(),clientTempId:s.string()}),ke=s.object({type:s.literal("report-create"),reportHubId:s.number(),report:xe,clientTempId:s.string(),recipientRawUserId:s.number().optional()}),Le=s.object({type:s.literal("report-update"),reportHubId:s.number(),report:xe,clientTempId:s.string(),recipientRawUserId:s.number().optional()}),$e=s.object({type:s.literal("report-publish"),reportHubId:s.number(),report:xe,clientTempId:s.string(),recipientRawUserId:s.number().optional()}),Pe=s.object({type:s.literal("report-delete"),reportHubId:s.number(),clientTempId:s.string()}),Je=s.discriminatedUnion("type",[ft,Ie,Ne,Ee,ke,Le,$e,Pe]);import{createHash as bt}from"crypto";var Be=r=>{let t=JSON.stringify(r);return`"${bt("sha256").update(t).digest("hex")}"`};var Rt=ae(1,"[Response]"),se=(r,t,a,o=200,p=Rt)=>{let c=Be(a),Y=r.headers.get("If-None-Match");p.info(`[jsonResponseWithETag] ETag: ${c}, If-None-Match: ${Y}`);let d=new Headers({"Content-Type":"application/json","Cache-Control":"private, max-age=0, must-revalidate","X-Content-Type-Options":"nosniff","X-Frame-Options":"DENY","Content-Security-Policy":"default-src 'none'",ETag:c});return t&&d.append("Set-Cookie",t),r.method==="GET"&&o===200&&Y===c?new Response(null,{status:304,headers:d}):new Response(JSON.stringify(a),{status:o,headers:d})};import{EventEmitter as Dt}from"events";var Ae=(r,t)=>{let[a,o]=r.split("-").map(Number),[p,c]=t.split("-").map(Number);return a!==p?a<p:o<=c},_e=class{constructor(t){this.config=t;this._emitter=new Dt;this._state="idle";this._refCount=0;this._lastId="0-0";this._emitter.setMaxListeners(0),this._logger=t.logger??ae(1,"[SSE Reader]")}subscribe(t,a){return this._emitter.on("entry",t),a&&this._emitter.on("error",a),this._refCount++,this._refCount===1&&this._startLoop(),()=>{this._emitter.removeListener("entry",t),a&&this._emitter.removeListener("error",a),this._refCount--,this._refCount<=0&&(this._refCount=0,this._stopLoop())}}async destroy(){this._refCount=0,await this._stopLoop(),this._emitter.removeAllListeners(),this._lastId="0-0"}async _startLoop(){for(;this._state==="stopping";)await new Promise(t=>setTimeout(t,50));if(this._state!=="running"){this._state="running";try{this._client=await this.config.redis?.createClient()}catch(t){this._state="idle",this._emitter.emit("error",t instanceof Error?t:new Error("Failed to create Redis client for SSE reader"));return}if(!this._client){this._state="idle",this._emitter.emit("error",new Error("Failed to create Redis client for SSE reader"));return}this._client.on("error",t=>{this._logger.error("Redis client error:",t)});try{for(;this._state==="running"&&this._client?.isOpen;){let t=await this._client.xRead([{key:this.config.streamKey,id:this._lastId}],{BLOCK:5e3,COUNT:100});if(t)for(let a of t)for(let o of a.messages){this._lastId=o.id;try{let p=o.message?.data?JSON.parse(o.message.data):null,c=p?.type;if((c==="report-create"||c==="report-delete"||c==="report-publish")&&this.config.cache.invalidatePrefix("daily-report:ids"),c==="comment-add"||c==="comment-delete"||c==="status-update"){let Y=p?.reportHubId;typeof Y=="number"&&(this.config.cache.invalidate(`daily-report:detail:${Y}`),this.config.cache.invalidatePrefix(`daily-report:detail:${Y}:user:`))}}catch{}this._emitter.emit("entry",{id:o.id,message:o.message})}}}catch(t){!(t?.constructor?.name==="ClientClosedError")&&this._state==="running"&&(this._logger.error("xRead loop error:",t),this._emitter.emit("error",t))}finally{if(this._client?.isOpen)try{await this._client.quit()}catch{}this._client=void 0,this._state="idle",this._refCount>0&&this._startLoop()}}}async _stopLoop(){if(this._state==="running"){if(this._state="stopping",this._client?.isOpen)try{await this._client.quit()}catch{}for(;this._state!=="idle";)await new Promise(t=>setTimeout(t,50))}}};var M=(r,t)=>new Response(JSON.stringify(r),{status:t?.status??200,headers:{"Content-Type":"application/json"}});function je(r){let{authenticate:t,service:a,encodeUserId:o,redis:p,sseReader:c,streamKey:Y}=r,d=r.loginRedirectPath??"/auth/login",z=r.logger??ae(3,"[DailyReportAPI]"),l=r.logger??ae(1,"[DailyReportSSE]"),m=async({request:C})=>{let{user:B,cookie:P}=await t(C,{failureRedirect:d}),w=new Headers;P&&w.append("Set-Cookie",P);let D=null;B&&(D=await a.getUserIdByExternalId(B.id));let _=D?o(D):null;return{data:{user:B,userId:_},headers:w}},L={"business-date":async(C,B,P,w)=>{let D=Z(C.searchParams.get("businessDate")),_=C.searchParams.get("forceRefresh")==="true";if(!D)return se(P,B,{error:{message:"Invalid business date"}},400);let U=await a.getDailyReportsByBusinessDateByExternalId(D,w.id,{forceRefresh:_});return se(P,B,{businessDate:D,reports:U},200)},ids:async(C,B,P,w)=>{let D=C.searchParams.get("forceRefresh")==="true",_=await a.getDailyReportIdsByExternalId(w.id,{forceRefresh:D});return se(P,B,{ids:_},200)},report:async(C,B,P,w)=>{let D=C.searchParams.get("reportHubId"),_=C.searchParams.get("forceRefresh")==="true",U=D?Number.parseInt(D,10):NaN;if(!Number.isFinite(U)||U<=0)return se(P,B,{error:{message:"Invalid reportHubId"}},400);let v=await a.getDailyReportDetailByIdByExternalId(U,w.id,{snapshot:!0,forceRefresh:_});return v?se(P,B,{report:v},200):se(P,B,{error:{message:"Report not found"}},404)}};return{index:{loader:m},api:{loader:async({request:C,params:B})=>{let{user:P,cookie:w}=await t(C,{failureRedirect:null}),D=w??null;if(!P)return se(C,D,{error:{message:"Unauthorized"}},401);if(C.method!=="GET")return se(C,D,{error:{message:"Method not allowed"}},405);let _=B.endpoint??"",U=L[_];if(!U)return se(C,D,{error:{message:"Unknown endpoint"}},404);let v=Date.now();try{let S=new URL(C.url);return await U(S,D,C,P)}catch(S){let H=Date.now()-v,F=S instanceof Error?S:new Error(String(S));return z.error(`500 endpoint=${_} elapsed=${H}ms name=${F.name} code=${"code"in F?F.code:"N/A"} message=${F.message}`),z.error("Stack:",F.stack),se(C,D,{error:{message:"Internal Server Error"}},500)}},action:async({request:C,params:B})=>{let{user:P}=await t(C,{failureRedirect:null});if(!P)return M({error:"Unauthorized"},{status:401});if(B.endpoint!=="action")return M({error:"Unknown endpoint"},{status:404});let D=await a.getUserIdByExternalId(P.id);if(!D)return M({error:"User not found"},{status:404});let _=await C.formData(),U=_.get("intent"),v=_.get("reportHubId"),S=v?Number(v):NaN,H=_.get("businessDate"),F=Number(_.get("operationTimestamp")),x=_.get("clientTempId");if(U==="clearCache")return await a.clearCache(),M({status:"OK",intent:"clearCache"});if(!x)return M({error:"clientTempId required"},{status:400});if(U!=="create"&&(!S||Number.isNaN(S)))return M({error:"Invalid reportHubId"},{status:400});switch(U){case"create":{if(!H)return M({error:"businessDate required"},{status:400});let b=await a.createDailyReport(D,H,x);return M({status:"OK",intent:"create",report:b,reportHubId:String(b.reportHubId),clientTempId:x})}case"update":{let b=_.get("title"),I=_.get("content");try{return await a.updateDailyReport(S,D,{title:b,content:I},x),M({status:"OK",intent:"update",reportHubId:String(S),clientTempId:x})}catch(N){if(N instanceof Error){if(N.message==="Unauthorized")return M({error:"Unauthorized"},{status:403});if(N.message==="Not Found")return M({error:"Report not found"},{status:404})}throw N}}case"publish":try{let b=await a.publishDailyReport(S,D,x);return M({status:"OK",intent:"publish",reportHubId:String(S),clientTempId:x,report:b})}catch(b){if(b instanceof Error){if(b.message==="Unauthorized")return M({error:"Unauthorized"},{status:403});if(b.message==="Not Found")return M({error:"Report not found"},{status:404})}throw b}case"delete":try{return await a.deleteDailyReport(S,D,x),M({status:"OK",intent:"delete",reportHubId:String(S),clientTempId:x})}catch(b){if(b instanceof Error){if(b.message==="Unauthorized")return M({error:"Unauthorized"},{status:403});if(b.message==="Not Found")return M({error:"Report not found"},{status:404})}throw b}case"toggleStar":{let b=_.get("isStarred");if(b===null)return M({error:"isStarred required"},{status:400});let I=b==="true",N=await a.setStarStatus(D,S,H,I,x);return M({status:"OK",intent:"toggleStar",updatedStatus:{isStarred:N.isStarred,isRead:N.isRead},operationTimestamp:F,reportHubId:String(S),clientTempId:x})}case"toggleRead":{let b=_.get("isRead");if(b===null)return M({error:"isRead required"},{status:400});let I=b==="true",N=await a.setReadStatus(D,S,H,I,x);return M({status:"OK",intent:"toggleRead",updatedStatus:{isStarred:N.isStarred,isRead:N.isRead},operationTimestamp:F,reportHubId:String(S),clientTempId:x})}case"addComment":{let b=_.get("content");if(!b)return M({error:"Content required"},{status:400});let I=await a.addComment(D,S,b,H,x),N={...I,userId:I.userId};return M({status:"OK",intent:"addComment",newComment:N,reportHubId:String(S),clientTempId:x})}case"deleteComment":{let b=Number(_.get("commentId"));if(!b||Number.isNaN(b))return M({error:"Invalid commentId"},{status:400});try{return await a.deleteComment(D,S,b,H,x),M({status:"OK",reportHubId:String(S),deletedCommentId:String(b),clientTempId:x})}catch(I){if(I instanceof Error){if(I.message==="Unauthorized")return M({error:"Unauthorized"},{status:403});if(I.message==="Not Found")return M({error:"Comment not found"},{status:404})}throw I}}default:return M({error:"Invalid intent"},{status:400})}}},sse:{loader:async({request:C,params:B})=>{let{user:P}=await t(C,{failureRedirect:null});if(!P)return new Response("Unauthorized",{status:401});let w=await a.getUserIdByExternalId(P.id);if(!w)return new Response("Forbidden",{status:403});if(B.endpoint!=="updates")return new Response("Not Found",{status:404});let _=new URL(C.url).searchParams.get("lastEventId")||C.headers.get("Last-Event-ID"),U=new TextEncoder,v=null,S=null,H=null,F=!1,x=()=>{if(!F){if(F=!0,S&&(clearInterval(S),S=null),H&&(H(),H=null),v)try{v.desiredSize!==null&&v.close()}catch{}finally{v=null}F=!1}},b=(N,k)=>{if(k.data)try{let A=JSON.parse(k.data),Q=Je.safeParse(A);if(!Q.success){l.error("SSE message validation failed:",Q.error.format());return}let ne=Q.data,le=typeof A.recipientRawUserId=="number"?A.recipientRawUserId:void 0;if(ne.type==="status-update"){if(le===void 0||le!==w)return}else if(le!==void 0&&le!==w)return;let fe;if("recipientRawUserId"in A){let{recipientRawUserId:He,...ve}=A;fe=JSON.stringify(ve)}else fe=k.data;v&&v.desiredSize!==null&&v.enqueue(U.encode(`id: ${N}
|
|
2
|
+
data: ${fe}
|
|
3
3
|
|
|
4
|
-
`))}catch(
|
|
4
|
+
`))}catch(A){l.error(`[SSE:${w}] processEntry error:`,A)}},I=new ReadableStream({async start(N){v=N,S=setInterval(()=>{try{v&&v.desiredSize!==null?v.enqueue(U.encode(`: keep-alive
|
|
5
5
|
|
|
6
|
-
`)):x()}catch{x()}},5e3),C.signal.addEventListener("abort",()=>{x()});let
|
|
6
|
+
`)):x()}catch{x()}},5e3),C.signal.addEventListener("abort",()=>{x()});let k=_||"0-0";if(H=c.subscribe(A=>{Ae(A.id,k)||(k=A.id,b(A.id,A.message))},A=>{l.error(`[SSE:${w}] Fan-Out reader error:`,A),x()}),!_)try{let A=await p?.getClient();if(A){let Q=await A.xRevRange(Y,"+","-",{COUNT:1});Q.length>0&&!Ae(Q[0].id,k)&&(k=Q[0].id)}}catch{}if(v&&v.desiredSize!==null){let A=`data: ${JSON.stringify({type:"connected"})}
|
|
7
7
|
|
|
8
|
-
`,
|
|
9
|
-
${T}`:T;M.enqueue(P.encode(W))}if(w)try{let T=await g?.getClient();if(T){let W=await T.xRange(O,w,"+",{COUNT:1e3});for(let re of W)re.id!==w&&(Ce(re.id,K)||(K=re.id,c(re.id,re.message)))}}catch(T){u.error(`[SSE:${$}] catch-up xRange error:`,T)}},cancel(){x()}});return new Response(k,{headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache, no-transform",Connection:"keep-alive"}})}}}}import{aliasedTable as Ke,and as G,asc as Je,desc as Ae,eq as p,getColumns as bt,inArray as je,isNull as me,or as Qe,sql as We}from"drizzle-orm";var oe=n=>bt(n);function Xe(n){let{db:t,tables:a,userTable:o,resolveUserId:g,encodeUserId:y,redis:O,cache:d,epochs:j}=n,{hub:u,internal:m,comment:E,label:F,hubLabel:X,userStatus:N}=a,C=n.externalSources??[],L=n.draftLabelName,S=n.logger??ne(1,"[DailyReportService]"),$="daily-report:ids",_=n.idsTtlMs??18e4,w="daily-report:ids:epoch",P="daily-report:business-date:",M=n.businessDateTtlMs??3e5,D="daily-report:date-epoch:",q="daily-report:detail-epoch:",Q=n.streamKey??"daily-report:sse-stream",x=n.streamMaxLen??1e4,c=e=>j.incrementEpoch(e),k=async(e,r)=>{let s=await O?.getClient();if(!s){S.warn(`[SSE] Redis client unavailable (${r})`);return}let l=Date.now();try{await s.xAdd(Q,"*",{data:JSON.stringify(e)},{TRIM:{strategy:"MAXLEN",strategyModifier:"~",threshold:x}});let h=Date.now()-l;h>1e3&&S.warn(`[SSE] Slow publish (${r}): ${h}ms`)}catch(h){S.error(`[SSE] Redis publish failed (${r}):`,h)}},A=(e,r)=>{if(!e)return null;let s=e instanceof Date?e:new Date(e);if(Number.isNaN(s.getTime()))return typeof e=="string"?e:null;let l=r==="YYYY-MM-DD HH:mm:ss"?{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"}:{year:"numeric",month:"2-digit",day:"2-digit"};return(r==="YYYY-MM-DD HH:mm:ss"?s.toLocaleString("ja-JP",l):s.toLocaleDateString("ja-JP",l)).replace(/\//g,"-")},K=e=>e==null||e===""?null:/^\d+$/.test(e)?y(Number(e)):e,T=()=>{let e={};for(let r of C)e[`ext_${r.sourceType}`]=oe(r.table);return e},W=e=>{let r=e;for(let s of C)r=r.leftJoin(s.table,G(p(u.sourceType,s.sourceType),p(u.sourceIdNum,s.idColumn)));return r},re=(e,r)=>{let{hub:s,internal:l}=e,h=s.summary,f=[],b=null,I=null,U=null,z=null,H=null,ee=null,ie=[],J=C.find(R=>R.sourceType===s.sourceType),pe=J?e[`ext_${J.sourceType}`]:void 0;if(J&&pe){let R=J.mapRow(pe);R.content!==void 0&&(h=R.content),R.employeeName!==void 0&&(ee=R.employeeName),R.category!==void 0&&(b=R.category),R.creationCategory!==void 0&&(I=R.creationCategory),R.visitTimeFrom!==void 0&&(U=R.visitTimeFrom),R.visitTimeTo!==void 0&&(z=R.visitTimeTo),R.customerName!==void 0&&(H=R.customerName),R.interviewers!==void 0&&(f=R.interviewers),R.comments!==void 0&&(ie=R.comments)}else s.sourceType==="Internal"&&l&&(h=l.body);let be=e.labels??[],Y=e.comments??[];return{reportHubId:s.id,date:A(s.businessDate,"YYYY-MM-DD"),author:e.creatorName??K(s.createdBy)??"",userId:s.userId?y(s.userId):"",sourceType:s.sourceType??"Internal",createdAt:A(s.createdAt,"YYYY-MM-DD HH:mm:ss"),updatedAt:A(s.updatedAt,"YYYY-MM-DD HH:mm:ss"),updatedBy:K(s.updatedBy),employeeName:ee??e.creatorName??K(s.createdBy),category:b,creationCategory:I,visitTimeFrom:U,visitTimeTo:z,customerName:H,interviewers:f,subject:s.title,content:h,comments:ie,isRead:e.isRead??!1,isStarred:e.isStarred??!1,labels:be.map(R=>({id:R.id,name:R.name,color:R.color})),commentItems:Y.map(R=>({...R,userId:y(R.userId),isMine:r?R.userId===r:!1}))}},de=async e=>{let r=Ke(X,"draft_label");return(await t.select({reportHubId:u.id,businessDate:u.businessDate,sourceType:u.sourceType}).from(u).leftJoin(r,G(p(r.hubId,u.id),p(r.labelId,t.select({id:F.id}).top(1).from(F).where(p(F.name,L))))).where(G(me(u.deletedAt),Qe(p(u.userId,e),me(r.hubId)))).orderBy(Ae(u.businessDate),Ae(u.id))).map(l=>({...l,businessDate:A(l.businessDate,"YYYY-MM-DD")}))},ge=async e=>(await W(t.select({hub:oe(u),internal:oe(m),creatorName:o.displayName,...T()}).from(u)).leftJoin(m,p(u.id,m.hubId)).leftJoin(o,p(u.userId,o.id)).where(G(p(u.businessDate,We`${e}`),me(u.deletedAt))).orderBy(Ae(u.id))).map(s=>re(s)),Pe=e=>`${P}${e}`,ue=new Map,Re=async e=>{if(!n.disableUserIdCache&&ue.has(e))return ue.get(e)??null;let r=await g(e);return r!==null&&!n.disableUserIdCache&&ue.set(e,r),r},Ze=async(e,{forceRefresh:r=!1,snapshot:s=!1,ttlMsOverride:l}={})=>{let h=await Re(e);if(!h)return[];let f=`${$}:user:${h}`;return d.getOrFetch({cacheKey:f,fetcher:async()=>await de(h),forceRefresh:r,snapshot:s,ttlMsOverride:l??_,epochKey:w})},et=(e,{forceRefresh:r=!1,snapshot:s=!1,ttlMsOverride:l}={})=>{let h=V(e);return h?d.getOrFetch({cacheKey:Pe(h),fetcher:()=>ge(h),forceRefresh:r,snapshot:s,ttlMsOverride:l??M}):Promise.resolve([])},he=null,ce=async()=>{if(he!==null)return he;let[e]=await t.select({id:F.id}).top(1).from(F).where(p(F.name,L));return e?(he=e.id,he):null},tt=async(e,r,{forceRefresh:s=!1,snapshot:l=!1,ttlMsOverride:h}={})=>{let f=await Re(r);if(!f)return[];let b=V(e);if(!b)return[];let I=`daily-report:date:${b}:user:${f}`;return d.getOrFetch({cacheKey:I,fetcher:async()=>{let U=await ce(),z=Ke(X,"draft_label"),H=await W(t.select({hub:oe(u),internal:oe(m),isRead:N.isRead,isStarred:N.isStarred,creatorName:o.displayName,...T()}).from(u)).leftJoin(m,p(u.id,m.hubId)).leftJoin(N,G(p(u.id,N.hubId),p(N.userId,f))).leftJoin(z,G(p(z.hubId,u.id),p(z.labelId,U??-1))).leftJoin(o,p(u.userId,o.id)).where(G(p(u.businessDate,We`${b}`),me(u.deletedAt),Qe(p(u.userId,f),me(z.hubId)))).orderBy(Ae(u.id));if(H.length===0)return[];let ee=H.map(Y=>Y.hub.id),ie=await t.select({hubId:X.hubId,id:F.id,name:F.name,color:F.color}).from(X).innerJoin(F,p(X.labelId,F.id)).where(je(X.hubId,ee)),J=await t.select({hubId:E.hubId,id:E.id,body:E.body,createdAt:E.createdAt,userId:E.userId,userName:o.displayName}).from(E).leftJoin(o,p(E.userId,o.id)).where(je(E.hubId,ee)).orderBy(Je(E.createdAt)),pe=new Map,be=new Map;for(let Y of ie){let R=pe.get(Y.hubId);R||(R=[],pe.set(Y.hubId,R)),R.push({id:Y.id,name:Y.name,color:Y.color})}for(let Y of J){let R=be.get(Y.hubId);R||(R=[],be.set(Y.hubId,R)),R.push({id:Y.id,content:Y.body,createdAt:A(Y.createdAt,"YYYY-MM-DD HH:mm:ss")||"",userId:Y.userId,userName:Y.userName||""})}return H.map(Y=>{let R=Y.hub.id;return re({...Y,labels:pe.get(R)||[],comments:be.get(R)||[]},f)})},forceRefresh:s,snapshot:l,ttlMsOverride:h??M,epochKey:`${D}${b}`})},fe=async(e,r,{forceRefresh:s=!1,snapshot:l=!1,ttlMsOverride:h}={})=>{let f=`daily-report:detail:${e}:user:${r}`;return(await d.getOrFetch({cacheKey:f,fetcher:async()=>{let I=await W(t.select({hub:oe(u),internal:oe(m),isRead:N.isRead,isStarred:N.isStarred,creatorName:o.displayName,...T()}).from(u)).leftJoin(m,p(u.id,m.hubId)).leftJoin(N,G(p(u.id,N.hubId),p(N.userId,r))).leftJoin(o,p(u.userId,o.id)).where(G(p(u.id,e),me(u.deletedAt)));if(I.length===0)return[];let U=I[0].hub.id,z=await t.select({id:F.id,name:F.name,color:F.color}).from(X).innerJoin(F,p(X.labelId,F.id)).where(p(X.hubId,U)),H=await t.select({id:E.id,body:E.body,createdAt:E.createdAt,userId:E.userId,userName:o.displayName}).from(E).leftJoin(o,p(E.userId,o.id)).where(p(E.hubId,U)).orderBy(Je(E.createdAt)),ee=z.map(J=>({id:J.id,name:J.name,color:J.color})),ie=H.map(J=>({id:J.id,content:J.body,createdAt:A(J.createdAt,"YYYY-MM-DD HH:mm:ss")||"",userId:J.userId,userName:J.userName||""}));return[re({...I[0],labels:ee,comments:ie},r)]},forceRefresh:s,snapshot:l,ttlMsOverride:h??M,epochKey:`${q}${e}`}))[0]??null},rt=async(e,r,s={})=>{let l=await Re(r);return l?fe(e,l,s):null},nt=async(e,r,s,l,h)=>{let f=await t.select().top(1).from(N).where(G(p(N.hubId,r),p(N.userId,e))),b;if(f.length>0?f[0].isStarred!==l?b=(await t.update(N).set({isStarred:l,updatedAt:new Date,updatedBy:String(e)}).output().where(G(p(N.hubId,r),p(N.userId,e))))[0]:b=f[0]:b=(await t.insert(N).output().values({hubId:r,userId:e,isStarred:l,isRead:!1,createdAt:new Date,createdBy:String(e),updatedAt:new Date,updatedBy:String(e)}))[0],s){let I=V(s);I&&(d.invalidate(`daily-report:date:${I}:user:${e}`),await c(`${D}${I}`))}return d.invalidate(`daily-report:detail:${r}`),d.invalidate(`daily-report:detail:${r}:user:${e}`),await c(`${q}${r}`),await k(Se.parse({type:"status-update",reportHubId:r,recipientRawUserId:e,statusType:"star",value:l,clientTempId:h}),"setStarStatus"),b},at=async(e,r,s,l,h)=>{let f=await t.select().top(1).from(N).where(G(p(N.hubId,r),p(N.userId,e))),b;if(f.length>0?f[0].isRead!==l?b=(await t.update(N).set({isRead:l,updatedAt:new Date,updatedBy:String(e)}).output().where(G(p(N.hubId,r),p(N.userId,e))))[0]:b=f[0]:b=(await t.insert(N).output().values({hubId:r,userId:e,isRead:l,isStarred:!1,createdAt:new Date,createdBy:String(e),updatedAt:new Date,updatedBy:String(e)}))[0],s){let I=V(s);I&&(d.invalidate(`daily-report:date:${I}:user:${e}`),await c(`${D}${I}`))}return d.invalidate(`daily-report:detail:${r}`),d.invalidate(`daily-report:detail:${r}:user:${e}`),await c(`${q}${r}`),await k(Se.parse({type:"status-update",reportHubId:r,recipientRawUserId:e,statusType:"read",value:l,clientTempId:h}),"setReadStatus"),b},it=async(e,r,s,l,h)=>{let[f]=await t.insert(E).output().values({hubId:r,userId:e,body:s,createdAt:new Date,createdBy:String(e),updatedAt:new Date,updatedBy:String(e)}),[b]=await t.select({displayName:o.displayName}).top(1).from(o).where(p(o.id,e)),I=b?.displayName??"Unknown";if(l){let z=V(l);z&&(d.invalidatePrefix(`daily-report:date:${z}:user:`),await c(`${D}${z}`))}d.invalidate(`daily-report:detail:${r}`),d.invalidatePrefix(`daily-report:detail:${r}:user:`),await c(`${q}${r}`);let U={id:f.id,userId:y(f.userId),userName:I,content:f.body,createdAt:A(f.createdAt,"YYYY-MM-DD HH:mm:ss")??"",isMine:!0};return await k(Me.parse({type:"comment-add",reportHubId:r,comment:U,clientTempId:h}),"addComment"),U},st=async(e,r)=>await e.select().top(1).from(E).where(p(E.id,r)),ot=async(e,r,s,l,h)=>{let f=await st(t,s);if(f.length===0)throw new Error("Not Found");if(f[0].userId!==e)throw new Error("Unauthorized");if(await t.delete(E).where(p(E.id,s)),l){let b=V(l);b&&(d.invalidatePrefix(`daily-report:date:${b}:user:`),await c(`${D}${b}`))}d.invalidate(`daily-report:detail:${r}`),d.invalidatePrefix(`daily-report:detail:${r}:user:`),await c(`${q}${r}`),await k(xe.parse({type:"comment-delete",reportHubId:r,commentId:s,clientTempId:h}),"deleteComment")},lt=async(e,r,s)=>{S.info("createDailyReport called",{userId:e,businessDate:r});let[l]=await t.select({displayName:o.displayName}).from(o).where(p(o.id,e)),h=l?.displayName??y(e);try{let f=await t.transaction(async U=>{S.info("Starting transaction");let z=`internal-temp-${Date.now()}-${Math.random()}`,[H]=await U.insert(u).output().values({sourceType:"Internal",sourceId:z,businessDate:new Date(r),userId:e,title:"(\u7121\u984C)",createdAt:new Date,createdBy:String(e),updatedAt:new Date,updatedBy:String(e)});await U.update(u).set({sourceId:String(H.id)}).where(p(u.id,H.id)),S.info("Hub created",H),await U.insert(m).values({hubId:H.id,body:"",createdAt:new Date,createdBy:String(e),updatedAt:new Date,updatedBy:String(e)}),S.info("Internal created"),S.info("Calling getDraftLabelId");let ee=await ce();S.info("draftLabelId",ee);let ie=[];return ee&&(await U.insert(X).values({hubId:H.id,labelId:ee,createdAt:new Date,createdBy:String(e)}),ie.push({id:ee,name:L,color:null})),S.info("Label assigned"),{reportHubId:H.id,date:r,createdAt:A(H.createdAt,"YYYY-MM-DD HH:mm:ss"),author:h,userId:y(e),sourceType:"Internal",employeeName:h,updatedBy:y(e),updatedAt:A(H.updatedAt,"YYYY-MM-DD HH:mm:ss"),category:null,creationCategory:null,visitTimeFrom:null,visitTimeTo:null,customerName:null,interviewers:[],subject:H.title,content:"",comments:[],isRead:!0,isStarred:!1,labels:ie,commentItems:[]}}),b=V(r);b&&d.invalidate(`daily-report:date:${b}:user:${e}`),d.invalidatePrefix(P),d.invalidate(`${$}:user:${e}`),await c(w),b&&await c(`${D}${b}`);let I=await fe(f.reportHubId,e,{forceRefresh:!0});if(I){let U=await ce(),z=U?I.labels.some(H=>H.id===U):!1;await k(Ne.parse({type:"report-create",reportHubId:I.reportHubId,report:I,clientTempId:s,recipientRawUserId:z?e:void 0}),"createDailyReport")}return I??f}catch(f){throw S.error("Error in createDailyReport",f),f}},De=async(e,r)=>await e.select().top(1).from(u).where(p(u.id,r)),Te=async(e,r,s)=>{await e.update(u).set(s).where(p(u.id,r))},Be=async(e,r,s)=>{await e.update(m).set(s).where(p(m.hubId,r))},Ue=async(e,r,s)=>{await e.delete(X).where(G(p(X.hubId,r),p(X.labelId,s)))};return{streamKey:Q,streamMaxLen:x,clearCache:async()=>{d.clearAll(),ue.clear(),he=null,j&&await c(w),S.info("[DailyReportService] Server-side DB/SQL caches cleared successfully.")},getUserIdByExternalId:Re,getDailyReportIdsByExternalId:Ze,getDailyReportsByBusinessDate:et,getDailyReportsByBusinessDateByExternalId:tt,getDailyReportDetailById:fe,getDailyReportDetailByIdByExternalId:rt,getDraftLabelId:ce,setStarStatus:nt,setReadStatus:at,addComment:it,deleteComment:ot,createDailyReport:lt,updateDailyReport:async(e,r,s,l)=>{let h=await De(t,e);if(!h.length||h[0].deletedAt)throw new Error("Not Found");if(h[0].userId!==r)throw new Error("Unauthorized");await t.transaction(async b=>{s.title!==void 0&&await Te(b,e,{title:s.title,updatedAt:new Date,updatedBy:String(r)}),s.content!==void 0&&await Be(b,e,{body:s.content,updatedAt:new Date,updatedBy:String(r)})}),d.invalidatePrefix(`daily-report:detail:${e}:user:`),d.invalidatePrefix(P);let f=await fe(e,r,{forceRefresh:!0});if(f){let b=await ce(),I=b?f.labels.some(U=>U.id===b):!1;await k(Ee.parse({type:"report-update",reportHubId:f.reportHubId,report:f,clientTempId:l,recipientRawUserId:I?r:void 0}),"updateDailyReport")}},publishDailyReport:async(e,r,s)=>{let l=await De(t,e);if(!l.length)throw new Error("Not Found");if(l[0].userId!==r)throw new Error("Unauthorized");let h=await ce();if(!h)return null;if(await Ue(t,e,h),d.invalidatePrefix(`daily-report:detail:${e}:user:`),d.invalidatePrefix(P),d.invalidatePrefix($),await c(w),l[0].businessDate){let I=V(A(l[0].businessDate,"YYYY-MM-DD"));I&&await c(`${D}${I}`)}let f=V(A(l[0].businessDate,"YYYY-MM-DD"));f&&d.invalidate(`daily-report:date:${f}:user:${r}`);let b=await fe(e,r,{forceRefresh:!0});return b&&await k(ke.parse({type:"report-publish",reportHubId:b.reportHubId,report:b,clientTempId:s}),"publishDailyReport"),b??null},deleteDailyReport:async(e,r,s)=>{let l=await De(t,e);if(!l.length||l[0].deletedAt)throw new Error("Not Found");if(l[0].userId!==r)throw new Error("Unauthorized");if(await Te(t,e,{deletedAt:new Date,deletedBy:String(r),updatedAt:new Date,updatedBy:String(r)}),d.invalidatePrefix(`daily-report:detail:${e}:user:`),d.invalidatePrefix(P),d.invalidatePrefix($),await c(w),l[0].businessDate){let h=V(A(l[0].businessDate,"YYYY-MM-DD"));h&&await c(`${D}${h}`)}await k($e.parse({type:"report-delete",reportHubId:e,clientTempId:s}),"deleteDailyReport")},findDailyReportHubById:De,updateDailyReportHub:Te,updateDailyReportInternal:Be,deleteDailyReportLabel:Ue}}var Rt=ne(1,"[DailyReportExternalSource]"),Zt=(n,t,a,o=Rt)=>{if(!n)return[];try{let g=JSON.parse(n);return Array.isArray(g)?g.map(a).filter(y=>y!==null):(o.warn(`Unexpected ${t} format: not an array`),[])}catch(g){return o.warn(`Failed to parse ${t}:`,g),[]}};import{desc as Ge,sql as Dt}from"drizzle-orm";import{bigint as Z,bit as Ve,date as wt,datetime2 as te,foreignKey as se,index as le,int as St,mssqlSchema as It,nvarchar as B,primaryKey as ye}from"drizzle-orm/mssql-core";function nr(n,t){let a=It(n),o=t.userTable,g=a.table("DailyReportHub",{id:Z("id",{mode:"number"}).identity().notNull(),sourceType:B("source_type",{length:20}).notNull(),sourceId:B("source_id",{length:100}).notNull(),sourceIdNum:Z("source_id_num",{mode:"number"}).generatedAlwaysAs(Dt`TRY_CAST(source_id AS BIGINT)`),businessDate:wt("business_date"),userId:Z("user_id",{mode:"number"}),title:B("title",{length:200}),summary:B("summary",{length:"max"}),createdAt:te("created_at").notNull(),createdBy:B("created_by",{length:50}).notNull(),updatedAt:te("updated_at").notNull(),updatedBy:B("updated_by",{length:50}).notNull(),deletedAt:te("deleted_at"),deletedBy:B("deleted_by",{length:50})},m=>[ye({name:`${n}_DailyReportHub_pk`,columns:[m.id]}),se({name:`${n}_DailyReportHub_user_id_fk`,columns:[m.userId],foreignColumns:[o.id]}),le(`${n}_DailyReportHub_business_date_index`).on(m.businessDate),le(`${n}_DailyReportHub_updated_at_index`).on(m.updatedAt),le(`${n}_DailyReportHub_source_index`).on(m.sourceType,m.sourceId),le(`${n}_DailyReportHub_user_id_index`).on(m.userId),le(`${n}_DailyReportHub_business_date_id_index`).on(Ge(m.businessDate),Ge(m.id)),le(`${n}_DailyReportHub_deleted_at_index`).on(m.deletedAt)]),y=a.table("DailyReportInternal",{hubId:Z("hub_id",{mode:"number"}).notNull(),body:B("body",{length:"max"}),metadata:B("metadata",{length:"max"}),createdAt:te("created_at").notNull(),createdBy:B("created_by",{length:50}).notNull(),updatedAt:te("updated_at").notNull(),updatedBy:B("updated_by",{length:50}).notNull()},m=>[ye({name:`${n}_DailyReportInternal_pk`,columns:[m.hubId]}),se({name:`${n}_DailyReportInternal_hub_id_fk`,columns:[m.hubId],foreignColumns:[g.id]})]),O=a.table("DailyReportComment",{id:Z("id",{mode:"number"}).identity().notNull(),hubId:Z("hub_id",{mode:"number"}).notNull(),userId:Z("user_id",{mode:"number"}).notNull(),body:B("body",{length:"max"}).notNull(),createdAt:te("created_at").notNull(),createdBy:B("created_by",{length:50}).notNull(),updatedAt:te("updated_at").notNull(),updatedBy:B("updated_by",{length:50}).notNull()},m=>[ye({name:`${n}_DailyReportComment_pk`,columns:[m.id]}),se({name:`${n}_DailyReportComment_hub_id_fk`,columns:[m.hubId],foreignColumns:[g.id]}),se({name:`${n}_DailyReportComment_user_id_fk`,columns:[m.userId],foreignColumns:[o.id]}),le(`${n}_DailyReportComment_hub_id_index`).on(m.hubId)]),d=a.table("DailyReportLabel",{id:Z("id",{mode:"number"}).identity().notNull(),userId:Z("user_id",{mode:"number"}),name:B("name",{length:50}).notNull(),color:B("color",{length:20}),sortOrder:St("sort_order"),createdAt:te("created_at").notNull(),createdBy:B("created_by",{length:50}).notNull(),updatedAt:te("updated_at").notNull(),updatedBy:B("updated_by",{length:50}).notNull()},m=>[ye({name:`${n}_DailyReportLabel_pk`,columns:[m.id]}),se({name:`${n}_DailyReportLabel_user_id_fk`,columns:[m.userId],foreignColumns:[o.id]})]),j=a.table("DailyReportHub_Label",{hubId:Z("hub_id",{mode:"number"}).notNull(),labelId:Z("label_id",{mode:"number"}).notNull(),createdAt:te("created_at").notNull(),createdBy:B("created_by",{length:50}).notNull()},m=>[ye({name:`${n}_DailyReportHub_Label_pk`,columns:[m.hubId,m.labelId]}),se({name:`${n}_DailyReportHub_Label_hub_id_fk`,columns:[m.hubId],foreignColumns:[g.id]}),se({name:`${n}_DailyReportHub_Label_label_id_fk`,columns:[m.labelId],foreignColumns:[d.id]})]),u=a.table("DailyReportUserStatus",{hubId:Z("hub_id",{mode:"number"}).notNull(),userId:Z("user_id",{mode:"number"}).notNull(),isRead:Ve("is_read").default(!1).notNull(),isStarred:Ve("is_starred").default(!1).notNull(),createdAt:te("created_at").notNull(),createdBy:B("created_by",{length:50}).notNull(),updatedAt:te("updated_at").notNull(),updatedBy:B("updated_by",{length:50}).notNull()},m=>[ye({name:`${n}_DailyReportUserStatus_pk`,columns:[m.hubId,m.userId]}),se({name:`${n}_DailyReportUserStatus_hub_id_fk`,columns:[m.hubId],foreignColumns:[g.id]}),se({name:`${n}_DailyReportUserStatus_user_id_fk`,columns:[m.userId],foreignColumns:[o.id]})]);return{hub:g,internal:y,comment:O,label:d,hubLabel:j,userStatus:u}}function dr(n){let t=He(n.redis),a=new we({defaultTtlMs:n.cacheDefaultTtlMs??6e4},t),o=Xe({...n,cache:a,epochs:t}),g=new _e({redis:n.redis,streamKey:o.streamKey,cache:a,logger:n.logger}),y=ze({authenticate:n.authenticate,service:o,encodeUserId:n.encodeUserId,redis:n.redis,sseReader:g,streamKey:o.streamKey,loginRedirectPath:n.loginRedirectPath,logger:n.logger});return{service:o,cache:a,epochs:t,sseReader:g,streamKey:o.streamKey,...y}}export{_e as DailyReportSseReader,we as SqlResultCache,ze as createDailyReportHandlers,dr as createDailyReportServer,Xe as createDailyReportService,He as createEpochStore,nr as defineDailyReportSchema,Le as generateETag,Ce as isStreamIdLte,ae as jsonResponseWithETag,Zt as transformJsonArray};
|
|
8
|
+
`,Q=k!=="0-0"?`id: ${k}
|
|
9
|
+
${A}`:A;v.enqueue(U.encode(Q))}if(_)try{let A=await p?.getClient();if(A){let Q=await A.xRange(Y,_,"+",{COUNT:1e3});for(let ne of Q)ne.id!==_&&(Ae(ne.id,k)||(k=ne.id,b(ne.id,ne.message)))}}catch(A){l.error(`[SSE:${w}] catch-up xRange error:`,A)}},cancel(){x()}});return new Response(I,{headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache, no-transform",Connection:"keep-alive"}})}}}}import{aliasedTable as Qe,and as G,asc as We,desc as Te,eq as y,getColumns as wt,inArray as Ue,isNull as pe,or as Xe,sql as Ge}from"drizzle-orm";var me=r=>wt(r);function Ve(r){let{db:t,tables:a,userTable:o,resolveUserId:p,encodeUserId:c,redis:Y,cache:d,epochs:z}=r,{hub:l,internal:m,comment:L,label:W,hubLabel:X,userStatus:E}=a,C=r.externalSources??[],B=r.draftLabelNames&&r.draftLabelNames.length>0?r.draftLabelNames:[r.draftLabelName??"\u4E0B\u66F8\u304D"],P=B[0]??"\u4E0B\u66F8\u304D",w=r.logger??ae(1,"[DailyReportService]"),D="daily-report:ids",_=r.idsTtlMs??18e4,U="daily-report:ids:epoch",v="daily-report:business-date:",S=r.businessDateTtlMs??3e5,H="daily-report:date-epoch:",F="daily-report:detail-epoch:",x=r.streamKey??"daily-report:sse-stream",b=r.streamMaxLen??1e4,I=e=>z.incrementEpoch(e),N=async(e,n)=>{let i=await Y?.getClient();if(!i){w.warn(`[SSE] Redis client unavailable (${n})`);return}let u=Date.now();try{await i.xAdd(x,"*",{data:JSON.stringify(e)},{TRIM:{strategy:"MAXLEN",strategyModifier:"~",threshold:b}});let g=Date.now()-u;g>1e3&&w.warn(`[SSE] Slow publish (${n}): ${g}ms`)}catch(g){w.error(`[SSE] Redis publish failed (${n}):`,g)}},k=(e,n)=>{if(!e)return null;let i=e instanceof Date?e:new Date(e);if(Number.isNaN(i.getTime()))return typeof e=="string"?e:null;let u=n==="YYYY-MM-DD HH:mm:ss"?{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"}:{year:"numeric",month:"2-digit",day:"2-digit"};return(n==="YYYY-MM-DD HH:mm:ss"?i.toLocaleString("ja-JP",u):i.toLocaleDateString("ja-JP",u)).replace(/\//g,"-")},A=e=>e==null||e===""?null:/^\d+$/.test(e)?c(Number(e)):e,Q=()=>{let e={};for(let n of C)e[`ext_${n.sourceType}`]=me(n.table);return e},ne=e=>{let n=e;for(let i of C)n=n.leftJoin(i.table,G(y(l.sourceType,i.sourceType),y(l.sourceIdNum,i.idColumn)));return n},le=(e,n)=>{let{hub:i,internal:u}=e,g=i.summary,f=[],h=null,R=null,K=null,J=null,$=null,te=null,oe=[],j=C.find(T=>T.sourceType===i.sourceType),ge=j?e[`ext_${j.sourceType}`]:void 0;if(j&&ge){let T=j.mapRow(ge);T.content!==void 0&&(g=T.content),T.employeeName!==void 0&&(te=T.employeeName),T.category!==void 0&&(h=T.category),T.creationCategory!==void 0&&(R=T.creationCategory),T.visitTimeFrom!==void 0&&(K=T.visitTimeFrom),T.visitTimeTo!==void 0&&(J=T.visitTimeTo),T.customerName!==void 0&&($=T.customerName),T.interviewers!==void 0&&(f=T.interviewers),T.comments!==void 0&&(oe=T.comments)}else i.sourceType==="Internal"&&u&&(g=u.body);let ce=(e.labels??[]).map(T=>({id:T.id,name:T.name,color:T.color})),O=e.comments??[];return R&&B.includes(R)&&de&&!ce.some(T=>T.id===de)&&ce.push({id:de,name:P,color:null}),{reportHubId:i.id,date:k(i.businessDate,"YYYY-MM-DD"),author:e.creatorName??A(i.createdBy)??"",userId:i.userId?c(i.userId):"",sourceType:i.sourceType??"Internal",createdAt:k(i.createdAt,"YYYY-MM-DD HH:mm:ss"),updatedAt:k(i.updatedAt,"YYYY-MM-DD HH:mm:ss"),updatedBy:A(i.updatedBy),employeeName:te??e.creatorName??A(i.createdBy),category:h,creationCategory:R,visitTimeFrom:K,visitTimeTo:J,customerName:$,interviewers:f,subject:i.title,content:g,comments:oe,isRead:e.isRead??!1,isStarred:e.isStarred??!1,labels:ce,commentItems:O.map(T=>({...T,userId:c(T.userId),isMine:n?T.userId===n:!1}))}},fe=async e=>{let n=Qe(X,"draft_label"),i=await ue();return(await t.select({reportHubId:l.id,businessDate:l.businessDate,sourceType:l.sourceType}).from(l).leftJoin(n,G(y(n.hubId,l.id),y(n.labelId,i??-1))).where(G(pe(l.deletedAt),Xe(y(l.userId,e),pe(l.userId),pe(n.hubId)))).orderBy(Te(l.businessDate),Te(l.id))).map(g=>({...g,businessDate:k(g.businessDate,"YYYY-MM-DD")}))},He=async e=>(await ne(t.select({hub:me(l),internal:me(m),creatorName:o.displayName,...Q()}).from(l)).leftJoin(m,y(l.id,m.hubId)).leftJoin(o,y(l.userId,o.id)).where(G(y(l.businessDate,Ge`${e}`),pe(l.deletedAt))).orderBy(Te(l.id))).map(i=>le(i)),ve=e=>`${v}${e}`,Re=new Map,De=async e=>{if(!r.disableUserIdCache&&Re.has(e))return Re.get(e)??null;let n=await p(e);return n!==null&&!r.disableUserIdCache&&Re.set(e,n),n},rt=async(e,{forceRefresh:n=!1,snapshot:i=!1,ttlMsOverride:u}={})=>{let g=await De(e);if(!g)return[];let f=`${D}:user:${g}`;return d.getOrFetch({cacheKey:f,fetcher:async()=>await fe(g),forceRefresh:n,snapshot:i,ttlMsOverride:u??_,epochKey:U})},nt=(e,{forceRefresh:n=!1,snapshot:i=!1,ttlMsOverride:u}={})=>{let g=Z(e);return g?d.getOrFetch({cacheKey:ve(g),fetcher:()=>He(g),forceRefresh:n,snapshot:i,ttlMsOverride:u??S}):Promise.resolve([])},de=null,ue=async()=>{if(de!==null)return de;let[e]=await t.select({id:W.id}).top(1).from(W).where(Ue(W.name,B));return e?(de=e.id,de):null},at=async(e,n,{forceRefresh:i=!1,snapshot:u=!1,ttlMsOverride:g}={})=>{let f=await De(n);if(!f)return[];let h=Z(e);if(!h)return[];let R=`daily-report:date:${h}:user:${f}`;return d.getOrFetch({cacheKey:R,fetcher:async()=>{let K=await ue(),J=Qe(X,"draft_label"),$=await ne(t.select({hub:me(l),internal:me(m),isRead:E.isRead,isStarred:E.isStarred,creatorName:o.displayName,...Q()}).from(l)).leftJoin(m,y(l.id,m.hubId)).leftJoin(E,G(y(l.id,E.hubId),y(E.userId,f))).leftJoin(J,G(y(J.hubId,l.id),y(J.labelId,K??-1))).leftJoin(o,y(l.userId,o.id)).where(G(y(l.businessDate,Ge`${h}`),pe(l.deletedAt),Xe(y(l.userId,f),pe(J.hubId)))).orderBy(Te(l.id));if($.length===0)return[];let te=$.map(O=>O.hub.id),oe=await t.select({hubId:X.hubId,id:W.id,name:W.name,color:W.color}).from(X).innerJoin(W,y(X.labelId,W.id)).where(Ue(X.hubId,te)),j=await t.select({hubId:L.hubId,id:L.id,body:L.body,createdAt:L.createdAt,userId:L.userId,userName:o.displayName}).from(L).leftJoin(o,y(L.userId,o.id)).where(Ue(L.hubId,te)).orderBy(We(L.createdAt)),ge=new Map,ce=new Map;for(let O of oe){let V=ge.get(O.hubId);V||(V=[],ge.set(O.hubId,V)),V.push({id:O.id,name:O.name,color:O.color})}for(let O of j){let V=ce.get(O.hubId);V||(V=[],ce.set(O.hubId,V)),V.push({id:O.id,content:O.body,createdAt:k(O.createdAt,"YYYY-MM-DD HH:mm:ss")||"",userId:O.userId,userName:O.userName||""})}return $.map(O=>{let V=O.hub.id;return le({...O,labels:ge.get(V)||[],comments:ce.get(V)||[]},f)})},forceRefresh:i,snapshot:u,ttlMsOverride:g??S,epochKey:`${H}${h}`})},be=async(e,n,{forceRefresh:i=!1,snapshot:u=!1,ttlMsOverride:g}={})=>{let f=`daily-report:detail:${e}:user:${n}`;return(await d.getOrFetch({cacheKey:f,fetcher:async()=>{let R=await ne(t.select({hub:me(l),internal:me(m),isRead:E.isRead,isStarred:E.isStarred,creatorName:o.displayName,...Q()}).from(l)).leftJoin(m,y(l.id,m.hubId)).leftJoin(E,G(y(l.id,E.hubId),y(E.userId,n))).leftJoin(o,y(l.userId,o.id)).where(G(y(l.id,e),pe(l.deletedAt)));if(R.length===0)return[];let K=R[0].hub.id,J=await t.select({id:W.id,name:W.name,color:W.color}).from(X).innerJoin(W,y(X.labelId,W.id)).where(y(X.hubId,K)),$=await t.select({id:L.id,body:L.body,createdAt:L.createdAt,userId:L.userId,userName:o.displayName}).from(L).leftJoin(o,y(L.userId,o.id)).where(y(L.hubId,K)).orderBy(We(L.createdAt)),te=J.map(j=>({id:j.id,name:j.name,color:j.color})),oe=$.map(j=>({id:j.id,content:j.body,createdAt:k(j.createdAt,"YYYY-MM-DD HH:mm:ss")||"",userId:j.userId,userName:j.userName||""}));return[le({...R[0],labels:te,comments:oe},n)]},forceRefresh:i,snapshot:u,ttlMsOverride:g??S,epochKey:`${F}${e}`}))[0]??null},st=async(e,n,i={})=>{let u=await De(n);return u?be(e,u,i):null},ot=async(e,n,i,u,g)=>{let f=await t.select().top(1).from(E).where(G(y(E.hubId,n),y(E.userId,e))),h;if(f.length>0?f[0].isStarred!==u?h=(await t.update(E).set({isStarred:u,updatedAt:new Date,updatedBy:String(e)}).output().where(G(y(E.hubId,n),y(E.userId,e))))[0]:h=f[0]:h=(await t.insert(E).output().values({hubId:n,userId:e,isStarred:u,isRead:!1,createdAt:new Date,createdBy:String(e),updatedAt:new Date,updatedBy:String(e)}))[0],i){let R=Z(i);R&&(d.invalidate(`daily-report:date:${R}:user:${e}`),await I(`${H}${R}`))}return d.invalidate(`daily-report:detail:${n}`),d.invalidate(`daily-report:detail:${n}:user:${e}`),await I(`${F}${n}`),await N(Ie.parse({type:"status-update",reportHubId:n,recipientRawUserId:e,statusType:"star",value:u,clientTempId:g}),"setStarStatus"),h},it=async(e,n,i,u,g)=>{let f=await t.select().top(1).from(E).where(G(y(E.hubId,n),y(E.userId,e))),h;if(f.length>0?f[0].isRead!==u?h=(await t.update(E).set({isRead:u,updatedAt:new Date,updatedBy:String(e)}).output().where(G(y(E.hubId,n),y(E.userId,e))))[0]:h=f[0]:h=(await t.insert(E).output().values({hubId:n,userId:e,isRead:u,isStarred:!1,createdAt:new Date,createdBy:String(e),updatedAt:new Date,updatedBy:String(e)}))[0],i){let R=Z(i);R&&(d.invalidate(`daily-report:date:${R}:user:${e}`),await I(`${H}${R}`))}return d.invalidate(`daily-report:detail:${n}`),d.invalidate(`daily-report:detail:${n}:user:${e}`),await I(`${F}${n}`),await N(Ie.parse({type:"status-update",reportHubId:n,recipientRawUserId:e,statusType:"read",value:u,clientTempId:g}),"setReadStatus"),h},lt=async(e,n,i,u,g)=>{let[f]=await t.select({sourceType:l.sourceType}).top(1).from(l).where(y(l.id,n));if(f&&f.sourceType.toLowerCase()!=="internal")throw new Error("Comments are restricted for external daily report sources");let[h]=await t.insert(L).output().values({hubId:n,userId:e,body:i,createdAt:new Date,createdBy:String(e),updatedAt:new Date,updatedBy:String(e)}),[R]=await t.select({displayName:o.displayName}).top(1).from(o).where(y(o.id,e)),K=R?.displayName??"Unknown";if(u){let $=Z(u);$&&(d.invalidatePrefix(`daily-report:date:${$}:user:`),await I(`${H}${$}`))}d.invalidate(`daily-report:detail:${n}`),d.invalidatePrefix(`daily-report:detail:${n}:user:`),await I(`${F}${n}`);let J={id:h.id,userId:c(h.userId),userName:K,content:h.body,createdAt:k(h.createdAt,"YYYY-MM-DD HH:mm:ss")??"",isMine:!0};return await N(Ne.parse({type:"comment-add",reportHubId:n,comment:J,clientTempId:g}),"addComment"),J},dt=async(e,n)=>await e.select().top(1).from(L).where(y(L.id,n)),ut=async(e,n,i,u,g)=>{let f=await dt(t,i);if(f.length===0)throw new Error("Not Found");if(f[0].userId!==e)throw new Error("Unauthorized");if(await t.delete(L).where(y(L.id,i)),u){let h=Z(u);h&&(d.invalidatePrefix(`daily-report:date:${h}:user:`),await I(`${H}${h}`))}d.invalidate(`daily-report:detail:${n}`),d.invalidatePrefix(`daily-report:detail:${n}:user:`),await I(`${F}${n}`),await N(Ee.parse({type:"comment-delete",reportHubId:n,commentId:i,clientTempId:g}),"deleteComment")},ct=async(e,n,i)=>{w.info("createDailyReport called",{userId:e,businessDate:n});let[u]=await t.select({displayName:o.displayName}).from(o).where(y(o.id,e)),g=u?.displayName??c(e);try{let f=await t.transaction(async K=>{w.info("Starting transaction");let J=`internal-temp-${Date.now()}-${Math.random()}`,[$]=await K.insert(l).output().values({sourceType:"Internal",sourceId:J,businessDate:new Date(n),userId:e,title:"(\u7121\u984C)",createdAt:new Date,createdBy:String(e),updatedAt:new Date,updatedBy:String(e)});await K.update(l).set({sourceId:String($.id)}).where(y(l.id,$.id)),w.info("Hub created",$),await K.insert(m).values({hubId:$.id,body:"",createdAt:new Date,createdBy:String(e),updatedAt:new Date,updatedBy:String(e)}),w.info("Internal created"),w.info("Calling getDraftLabelId");let te=await ue();w.info("draftLabelId",te);let oe=[];return te&&(await K.insert(X).values({hubId:$.id,labelId:te,createdAt:new Date,createdBy:String(e)}),oe.push({id:te,name:P,color:null})),w.info("Label assigned"),{reportHubId:$.id,date:n,createdAt:k($.createdAt,"YYYY-MM-DD HH:mm:ss"),author:g,userId:c(e),sourceType:"Internal",employeeName:g,updatedBy:c(e),updatedAt:k($.updatedAt,"YYYY-MM-DD HH:mm:ss"),category:null,creationCategory:null,visitTimeFrom:null,visitTimeTo:null,customerName:null,interviewers:[],subject:$.title,content:"",comments:[],isRead:!0,isStarred:!1,labels:oe,commentItems:[]}}),h=Z(n);h&&d.invalidate(`daily-report:date:${h}:user:${e}`),d.invalidatePrefix(v),d.invalidate(`${D}:user:${e}`),await I(U),h&&await I(`${H}${h}`);let R=await be(f.reportHubId,e,{forceRefresh:!0});if(R){let K=await ue(),J=K?R.labels.some($=>$.id===K):!1;await N(ke.parse({type:"report-create",reportHubId:R.reportHubId,report:R,clientTempId:i,recipientRawUserId:J?e:void 0}),"createDailyReport")}return R??f}catch(f){throw w.error("Error in createDailyReport",f),f}},we=async(e,n)=>await e.select().top(1).from(l).where(y(l.id,n)),Me=async(e,n,i)=>{await e.update(l).set(i).where(y(l.id,n))},Ye=async(e,n,i)=>{await e.update(m).set(i).where(y(m.hubId,n))},qe=async(e,n,i)=>{await e.delete(X).where(G(y(X.hubId,n),y(X.labelId,i)))};return{streamKey:x,streamMaxLen:b,clearCache:async()=>{d.clearAll(),Re.clear(),de=null,z&&await I(U),w.info("[DailyReportService] Server-side DB/SQL caches cleared successfully.")},getUserIdByExternalId:De,getDailyReportIdsByExternalId:rt,getDailyReportsByBusinessDate:nt,getDailyReportsByBusinessDateByExternalId:at,getDailyReportDetailById:be,getDailyReportDetailByIdByExternalId:st,getDraftLabelId:ue,setStarStatus:ot,setReadStatus:it,addComment:lt,deleteComment:ut,createDailyReport:ct,updateDailyReport:async(e,n,i,u)=>{let g=await we(t,e);if(!g.length||g[0].deletedAt)throw new Error("Not Found");if(g[0].userId!==n)throw new Error("Unauthorized");await t.transaction(async h=>{i.title!==void 0&&await Me(h,e,{title:i.title,updatedAt:new Date,updatedBy:String(n)}),i.content!==void 0&&await Ye(h,e,{body:i.content,updatedAt:new Date,updatedBy:String(n)})}),d.invalidatePrefix(`daily-report:detail:${e}:user:`),d.invalidatePrefix(v);let f=await be(e,n,{forceRefresh:!0});if(f){let h=await ue(),R=h?f.labels.some(K=>K.id===h):!1;await N(Le.parse({type:"report-update",reportHubId:f.reportHubId,report:f,clientTempId:u,recipientRawUserId:R?n:void 0}),"updateDailyReport")}},publishDailyReport:async(e,n,i)=>{let u=await we(t,e);if(!u.length)throw new Error("Not Found");if(u[0].userId!==n)throw new Error("Unauthorized");let g=await ue();if(!g)return null;if(await qe(t,e,g),d.invalidatePrefix(`daily-report:detail:${e}:user:`),d.invalidatePrefix(v),d.invalidatePrefix(D),await I(U),u[0].businessDate){let R=Z(k(u[0].businessDate,"YYYY-MM-DD"));R&&await I(`${H}${R}`)}let f=Z(k(u[0].businessDate,"YYYY-MM-DD"));f&&d.invalidate(`daily-report:date:${f}:user:${n}`);let h=await be(e,n,{forceRefresh:!0});return h&&await N($e.parse({type:"report-publish",reportHubId:h.reportHubId,report:h,clientTempId:i}),"publishDailyReport"),h??null},deleteDailyReport:async(e,n,i)=>{let u=await we(t,e);if(!u.length||u[0].deletedAt)throw new Error("Not Found");if(u[0].userId!==n)throw new Error("Unauthorized");if(await Me(t,e,{deletedAt:new Date,deletedBy:String(n),updatedAt:new Date,updatedBy:String(n)}),d.invalidatePrefix(`daily-report:detail:${e}:user:`),d.invalidatePrefix(v),d.invalidatePrefix(D),await I(U),u[0].businessDate){let g=Z(k(u[0].businessDate,"YYYY-MM-DD"));g&&await I(`${H}${g}`)}await N(Pe.parse({type:"report-delete",reportHubId:e,clientTempId:i}),"deleteDailyReport")},findDailyReportHubById:we,updateDailyReportHub:Me,updateDailyReportInternal:Ye,deleteDailyReportLabel:qe}}import{and as St,eq as Ze}from"drizzle-orm";function It(r){let t=[],a=r&&r.length>0?r:[{key:"internal",name:"Internal",description:"Internal daily reports"},{key:"external",name:"External",description:"External daily reports"}];for(let o of a){let c=`daily_report_${o.key.toLowerCase().replace(/[^a-z0-9_]/g,"_")}`;t.push({resourceKey:c,name:o.name,description:o.description??`${o.name} daily report access`}),o.includeCommentResource!==!1&&t.push({resourceKey:`${c}_comment`,name:`${o.name} Comment`,description:`${o.name} daily report comment access`})}return t}async function ar(r,t,a){let o=r,p=t.TMResource,c=a.appKey,Y=a.actor??"system:daily-report",d=new Date,z=a.resources??It(a.sources);for(let l of z){let m=await o.select().from(p).where(St(Ze(p.appKey,c),Ze(p.resourceKey,l.resourceKey)));(!m||m.length===0)&&await o.insert(p).values({appKey:c,resourceKey:l.resourceKey,name:l.name,description:l.description??null,createdAt:d,createdBy:Y,updatedAt:d,updatedBy:Y})}}var Ct=ae(1,"[DailyReportExternalSource]"),ir=(r,t,a,o=Ct)=>{if(!r)return[];try{let p=JSON.parse(r);return Array.isArray(p)?p.map(a).filter(c=>c!==null):(o.warn(`Unexpected ${t} format: not an array`),[])}catch(p){return o.warn(`Failed to parse ${t}:`,p),[]}};import{desc as et,sql as _t}from"drizzle-orm";import{bigint as ee,bit as tt,date as At,datetime2 as re,foreignKey as ie,index as ye,int as Tt,mssqlSchema as vt,nvarchar as q,primaryKey as he}from"drizzle-orm/mssql-core";function cr(r,t){let a=vt(r),o=t.userTable,p=a.table("DailyReportHub",{id:ee("id",{mode:"number"}).identity().notNull(),sourceType:q("source_type",{length:20}).notNull(),sourceId:q("source_id",{length:100}).notNull(),sourceIdNum:ee("source_id_num",{mode:"number"}).generatedAlwaysAs(_t`TRY_CAST(source_id AS BIGINT)`),businessDate:At("business_date"),userId:ee("user_id",{mode:"number"}),title:q("title",{length:200}),summary:q("summary",{length:"max"}),createdAt:re("created_at").notNull(),createdBy:q("created_by",{length:50}).notNull(),updatedAt:re("updated_at").notNull(),updatedBy:q("updated_by",{length:50}).notNull(),deletedAt:re("deleted_at"),deletedBy:q("deleted_by",{length:50})},m=>[he({name:`${r}_DailyReportHub_pk`,columns:[m.id]}),ie({name:`${r}_DailyReportHub_user_id_fk`,columns:[m.userId],foreignColumns:[o.id]}),ye(`${r}_DailyReportHub_business_date_index`).on(m.businessDate),ye(`${r}_DailyReportHub_updated_at_index`).on(m.updatedAt),ye(`${r}_DailyReportHub_source_index`).on(m.sourceType,m.sourceId),ye(`${r}_DailyReportHub_user_id_index`).on(m.userId),ye(`${r}_DailyReportHub_business_date_id_index`).on(et(m.businessDate),et(m.id)),ye(`${r}_DailyReportHub_deleted_at_index`).on(m.deletedAt)]),c=a.table("DailyReportInternal",{hubId:ee("hub_id",{mode:"number"}).notNull(),body:q("body",{length:"max"}),metadata:q("metadata",{length:"max"}),createdAt:re("created_at").notNull(),createdBy:q("created_by",{length:50}).notNull(),updatedAt:re("updated_at").notNull(),updatedBy:q("updated_by",{length:50}).notNull()},m=>[he({name:`${r}_DailyReportInternal_pk`,columns:[m.hubId]}),ie({name:`${r}_DailyReportInternal_hub_id_fk`,columns:[m.hubId],foreignColumns:[p.id]})]),Y=a.table("DailyReportComment",{id:ee("id",{mode:"number"}).identity().notNull(),hubId:ee("hub_id",{mode:"number"}).notNull(),userId:ee("user_id",{mode:"number"}).notNull(),body:q("body",{length:"max"}).notNull(),createdAt:re("created_at").notNull(),createdBy:q("created_by",{length:50}).notNull(),updatedAt:re("updated_at").notNull(),updatedBy:q("updated_by",{length:50}).notNull()},m=>[he({name:`${r}_DailyReportComment_pk`,columns:[m.id]}),ie({name:`${r}_DailyReportComment_hub_id_fk`,columns:[m.hubId],foreignColumns:[p.id]}),ie({name:`${r}_DailyReportComment_user_id_fk`,columns:[m.userId],foreignColumns:[o.id]}),ye(`${r}_DailyReportComment_hub_id_index`).on(m.hubId)]),d=a.table("DailyReportLabel",{id:ee("id",{mode:"number"}).identity().notNull(),userId:ee("user_id",{mode:"number"}),name:q("name",{length:50}).notNull(),color:q("color",{length:20}),sortOrder:Tt("sort_order"),createdAt:re("created_at").notNull(),createdBy:q("created_by",{length:50}).notNull(),updatedAt:re("updated_at").notNull(),updatedBy:q("updated_by",{length:50}).notNull()},m=>[he({name:`${r}_DailyReportLabel_pk`,columns:[m.id]}),ie({name:`${r}_DailyReportLabel_user_id_fk`,columns:[m.userId],foreignColumns:[o.id]})]),z=a.table("DailyReportHub_Label",{hubId:ee("hub_id",{mode:"number"}).notNull(),labelId:ee("label_id",{mode:"number"}).notNull(),createdAt:re("created_at").notNull(),createdBy:q("created_by",{length:50}).notNull()},m=>[he({name:`${r}_DailyReportHub_Label_pk`,columns:[m.hubId,m.labelId]}),ie({name:`${r}_DailyReportHub_Label_hub_id_fk`,columns:[m.hubId],foreignColumns:[p.id]}),ie({name:`${r}_DailyReportHub_Label_label_id_fk`,columns:[m.labelId],foreignColumns:[d.id]})]),l=a.table("DailyReportUserStatus",{hubId:ee("hub_id",{mode:"number"}).notNull(),userId:ee("user_id",{mode:"number"}).notNull(),isRead:tt("is_read").default(!1).notNull(),isStarred:tt("is_starred").default(!1).notNull(),createdAt:re("created_at").notNull(),createdBy:q("created_by",{length:50}).notNull(),updatedAt:re("updated_at").notNull(),updatedBy:q("updated_by",{length:50}).notNull()},m=>[he({name:`${r}_DailyReportUserStatus_pk`,columns:[m.hubId,m.userId]}),ie({name:`${r}_DailyReportUserStatus_hub_id_fk`,columns:[m.hubId],foreignColumns:[p.id]}),ie({name:`${r}_DailyReportUserStatus_user_id_fk`,columns:[m.userId],foreignColumns:[o.id]})]);return{hub:p,internal:c,comment:Y,label:d,hubLabel:z,userStatus:l}}function fr(r){let t=Oe(r.redis),a=new Se({defaultTtlMs:r.cacheDefaultTtlMs??6e4},t),o=Ve({...r,cache:a,epochs:t}),p=new _e({redis:r.redis,streamKey:o.streamKey,cache:a,logger:r.logger}),c=je({authenticate:r.authenticate,service:o,encodeUserId:r.encodeUserId,redis:r.redis,sseReader:p,streamKey:o.streamKey,loginRedirectPath:r.loginRedirectPath,logger:r.logger});return{service:o,cache:a,epochs:t,sseReader:p,streamKey:o.streamKey,...c}}export{_e as DailyReportSseReader,Se as SqlResultCache,je as createDailyReportHandlers,fr as createDailyReportServer,Ve as createDailyReportService,Oe as createEpochStore,It as defineDailyReportAuthzResources,cr as defineDailyReportSchema,Be as generateETag,Ae as isStreamIdLte,se as jsonResponseWithETag,ar as seedDailyReportAuthzResources,ir as transformJsonArray};
|
|
10
10
|
//# sourceMappingURL=server.mjs.map
|