@aiquants/daily-report 0.5.0 → 0.6.0
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/dist/client.d.mts +2 -2
- package/dist/client.d.ts +2 -2
- 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/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/server.d.mts +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.js +3 -3
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +2 -2
- package/dist/server.mjs.map +1 -1
- package/dist/sse-schema-eXcMG-Ej.d.ts +2025 -0
- package/dist/sse-schema-rbG114od.d.mts +2025 -0
- package/dist/{types-BNhYC2j9.d.mts → types-D1PKubyo.d.mts} +26 -26
- package/dist/{types-BNhYC2j9.d.ts → types-D1PKubyo.d.ts} +26 -26
- package/package.json +3 -3
- package/src/client/components/daily-report-detail-list.tsx +1 -1
- package/src/client/components/daily-report-list.tsx +1 -1
- package/src/client/contexts/daily-report-action-context.tsx +1 -1
- package/src/client/hooks/use-daily-report-sse-connection.ts +1 -1
- package/src/client/hooks/use-daily-report.ts +2 -2
- package/src/shared/comment-adapter.ts +3 -3
- package/src/shared/sse-schema.ts +27 -26
- package/src/shared/types.ts +26 -26
- package/dist/sse-schema-ChCypDPj.d.ts +0 -2019
- package/dist/sse-schema-Cs1oC2DP.d.mts +0 -2019
package/dist/server.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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(),affiliation:i.string().nullable()}),pt=i.object({name:i.string().nullable(),text:i.string().nullable(),color:i.string().nullable()}),mt=i.object({id:i.number(),name:i.string(),color:i.string().nullable()}),Oe=i.object({id:i.number(),userId:i.string(),userName:i.string(),content:i.string(),createdAt:i.string(),isMine:i.boolean()}),ve=i.object({reportHubId:i.number(),date:i.string().nullable(),createdAt:i.string().nullable(),author:i.string(),userId:i.string(),sourceType:i.string().nullable(),employeeName:i.string().nullable(),updatedBy:i.string().nullable(),updatedAt:i.string().nullable(),category:i.string().nullable(),creationCategory:i.string().nullable(),visitTimeFrom:i.string().nullable(),visitTimeTo:i.string().nullable(),customerName:i.string().nullable(),interviewers:i.array(ct),subject:i.string().nullable(),content:i.string().nullable(),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()}),$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 ft=ne(1,"[Response]"),ae=(n,t,a,o=200,g=ft)=>{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 ht}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 ht;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}
|
|
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
2
|
data: ${ge}
|
|
3
3
|
|
|
4
4
|
`))}catch(T){u.error(`[SSE:${$}] processEntry error:`,T)}},k=new ReadableStream({async start(A){M=A,D=setInterval(()=>{try{M&&M.desiredSize!==null?M.enqueue(P.encode(`: keep-alive
|
|
@@ -6,5 +6,5 @@ data: ${ge}
|
|
|
6
6
|
`)):x()}catch{x()}},5e3),C.signal.addEventListener("abort",()=>{x()});let K=w||"0-0";if(q=y.subscribe(T=>{Ce(T.id,K)||(K=T.id,c(T.id,T.message))},T=>{u.error(`[SSE:${$}] Fan-Out reader error:`,T),x()}),!w)try{let T=await g?.getClient();if(T){let W=await T.xRevRange(O,"+","-",{COUNT:1});W.length>0&&!Ce(W[0].id,K)&&(K=W[0].id)}}catch{}if(M&&M.desiredSize!==null){let T=`data: ${JSON.stringify({type:"connected"})}
|
|
7
7
|
|
|
8
8
|
`,W=K!=="0-0"?`id: ${K}
|
|
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 f=Date.now()-l;f>1e3&&S.warn(`[SSE] Slow publish (${r}): ${f}ms`)}catch(f){S.error(`[SSE] Redis publish failed (${r}):`,f)}},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,f=s.summary,h=[],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&&(f=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&&(h=R.interviewers),R.comments!==void 0&&(ie=R.comments)}else s.sourceType==="Internal"&&l&&(f=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:h,subject:s.title,content:f,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 f=await Re(e);if(!f)return[];let h=`${$}:user:${f}`;return d.getOrFetch({cacheKey:h,fetcher:async()=>await de(f),forceRefresh:r,snapshot:s,ttlMsOverride:l??_,epochKey:w})},et=(e,{forceRefresh:r=!1,snapshot:s=!1,ttlMsOverride:l}={})=>{let f=V(e);return f?d.getOrFetch({cacheKey:Pe(f),fetcher:()=>ge(f),forceRefresh:r,snapshot:s,ttlMsOverride:l??M}):Promise.resolve([])},fe=null,ce=async()=>{if(fe!==null)return fe;let[e]=await t.select({id:F.id}).top(1).from(F).where(p(F.name,L));return e?(fe=e.id,fe):null},tt=async(e,r,{forceRefresh:s=!1,snapshot:l=!1,ttlMsOverride:f}={})=>{let h=await Re(r);if(!h)return[];let b=V(e);if(!b)return[];let I=`daily-report:date:${b}:user:${h}`;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,h))).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,h),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)||[]},h)})},forceRefresh:s,snapshot:l,ttlMsOverride:f??M,epochKey:`${D}${b}`})},he=async(e,r,{forceRefresh:s=!1,snapshot:l=!1,ttlMsOverride:f}={})=>{let h=`daily-report:detail:${e}:user:${r}`;return(await d.getOrFetch({cacheKey:h,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:f??M,epochKey:`${q}${e}`}))[0]??null},rt=async(e,r,s={})=>{let l=await Re(r);return l?he(e,l,s):null},nt=async(e,r,s,l,f)=>{let h=await t.select().top(1).from(N).where(G(p(N.hubId,r),p(N.userId,e))),b;if(h.length>0?h[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=h[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:f}),"setStarStatus"),b},at=async(e,r,s,l,f)=>{let h=await t.select().top(1).from(N).where(G(p(N.hubId,r),p(N.userId,e))),b;if(h.length>0?h[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=h[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:f}),"setReadStatus"),b},it=async(e,r,s,l,f)=>{let[h]=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:h.id,userId:y(h.userId),userName:I,content:h.body,createdAt:A(h.createdAt,"YYYY-MM-DD HH:mm:ss")??"",isMine:!0};return await k(Me.parse({type:"comment-add",reportHubId:r,comment:U,clientTempId:f}),"addComment"),U},st=async(e,r)=>await e.select().top(1).from(E).where(p(E.id,r)),ot=async(e,r,s,l,f)=>{let h=await st(t,s);if(h.length===0)throw new Error("Not Found");if(h[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:f}),"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)),f=l?.displayName??y(e);try{let h=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:f,userId:y(e),sourceType:"Internal",employeeName:f,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 he(h.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??h}catch(h){throw S.error("Error in createDailyReport",h),h}},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(),fe=null,j&&await c(w),S.info("[DailyReportService] Server-side DB/SQL caches cleared successfully.")},getUserIdByExternalId:Re,getDailyReportIdsByExternalId:Ze,getDailyReportsByBusinessDate:et,getDailyReportsByBusinessDateByExternalId:tt,getDailyReportDetailById:he,getDailyReportDetailByIdByExternalId:rt,getDraftLabelId:ce,setStarStatus:nt,setReadStatus:at,addComment:it,deleteComment:ot,createDailyReport:lt,updateDailyReport:async(e,r,s,l)=>{let f=await De(t,e);if(!f.length||f[0].deletedAt)throw new Error("Not Found");if(f[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 h=await he(e,r,{forceRefresh:!0});if(h){let b=await ce(),I=b?h.labels.some(U=>U.id===b):!1;await k(Ee.parse({type:"report-update",reportHubId:h.reportHubId,report:h,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 f=await ce();if(!f)return null;if(await Ue(t,e,f),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 h=V(A(l[0].businessDate,"YYYY-MM-DD"));h&&d.invalidate(`daily-report:date:${h}:user:${r}`);let b=await he(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 f=V(A(l[0].businessDate,"YYYY-MM-DD"));f&&await c(`${D}${f}`)}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};
|
|
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};
|
|
10
10
|
//# sourceMappingURL=server.mjs.map
|