@aiquants/daily-report 0.20.0 → 0.20.1

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.
Files changed (115) hide show
  1. package/dist/client.d.mts +11 -706
  2. package/dist/client.d.ts +11 -706
  3. package/dist/client.js +0 -1
  4. package/dist/client.mjs +0 -1
  5. package/dist/index.d.mts +5 -197
  6. package/dist/index.d.ts +5 -197
  7. package/dist/index.js +0 -1
  8. package/dist/index.mjs +0 -1
  9. package/dist/logger-D3krZrNK.d.mts +0 -14
  10. package/dist/logger-D3krZrNK.d.ts +0 -14
  11. package/dist/server.d.mts +114 -744
  12. package/dist/server.d.ts +114 -744
  13. package/dist/server.js +0 -1
  14. package/dist/server.mjs +0 -1
  15. package/dist/sse-schema-BdUGThiz.d.ts +1025 -1009
  16. package/dist/sse-schema-ChSFm-4q.d.mts +1025 -1009
  17. package/dist/types-CqgYQgbH.d.mts +0 -34
  18. package/dist/types-CqgYQgbH.d.ts +0 -34
  19. package/package.json +7 -8
  20. package/dist/client.js.map +0 -1
  21. package/dist/client.mjs.map +0 -1
  22. package/dist/index.js.map +0 -1
  23. package/dist/index.mjs.map +0 -1
  24. package/dist/server.js.map +0 -1
  25. package/dist/server.mjs.map +0 -1
  26. package/src/client/components/business-day-thumb-overlay.tsx +0 -19
  27. package/src/client/components/daily-report-attachment-indicator.spec.tsx +0 -51
  28. package/src/client/components/daily-report-attachment-indicator.tsx +0 -45
  29. package/src/client/components/daily-report-attachment-list.spec.tsx +0 -94
  30. package/src/client/components/daily-report-attachment-list.tsx +0 -112
  31. package/src/client/components/daily-report-comment-item.tsx +0 -89
  32. package/src/client/components/daily-report-comment-section.tsx +0 -166
  33. package/src/client/components/daily-report-detail-list.tsx +0 -842
  34. package/src/client/components/daily-report-edit-form.tsx +0 -87
  35. package/src/client/components/daily-report-ids-stream-status.spec.tsx +0 -93
  36. package/src/client/components/daily-report-ids-stream-status.tsx +0 -67
  37. package/src/client/components/daily-report-list.tsx +0 -1232
  38. package/src/client/components/daily-report-page.spec.tsx +0 -119
  39. package/src/client/components/daily-report-page.tsx +0 -140
  40. package/src/client/components/daily-report-resize-panels.spec.tsx +0 -307
  41. package/src/client/components/daily-report-resolved-content.tsx +0 -207
  42. package/src/client/components/daily-report-scroll-restoration.spec.tsx +0 -422
  43. package/src/client/components/report-views.spec.tsx +0 -375
  44. package/src/client/components/unread-indicator.tsx +0 -13
  45. package/src/client/config-context.tsx +0 -184
  46. package/src/client/contexts/daily-report-action-context.spec.tsx +0 -433
  47. package/src/client/contexts/daily-report-action-context.tsx +0 -1147
  48. package/src/client/contexts/daily-report-error-context.spec.tsx +0 -66
  49. package/src/client/contexts/daily-report-error-context.tsx +0 -98
  50. package/src/client/hooks/use-animated-number.spec.ts +0 -103
  51. package/src/client/hooks/use-animated-number.ts +0 -69
  52. package/src/client/hooks/use-daily-report-comments.ts +0 -73
  53. package/src/client/hooks/use-daily-report-sse-connection.ts +0 -86
  54. package/src/client/hooks/use-daily-report.spec.ts +0 -546
  55. package/src/client/hooks/use-daily-report.ts +0 -549
  56. package/src/client/hooks/use-dynamic-viewport-height.ts +0 -127
  57. package/src/client/hooks/use-responsive-layout.spec.ts +0 -74
  58. package/src/client/hooks/use-responsive-layout.ts +0 -63
  59. package/src/client/route-helpers.spec.ts +0 -100
  60. package/src/client/route-helpers.ts +0 -61
  61. package/src/client/streaming/daily-report-ids-stream-client.spec.ts +0 -910
  62. package/src/client/streaming/daily-report-ids-stream-client.ts +0 -730
  63. package/src/client/streaming/daily-report-ids-stream-session.spec.ts +0 -401
  64. package/src/client/streaming/daily-report-ids-stream-session.ts +0 -319
  65. package/src/client/ui/button.tsx +0 -42
  66. package/src/client/ui/cn.ts +0 -14
  67. package/src/client/ui/input.tsx +0 -21
  68. package/src/client/ui/label.tsx +0 -16
  69. package/src/client/ui/switch.tsx +0 -19
  70. package/src/client/ui/tabs.tsx +0 -40
  71. package/src/client/ui/textarea.tsx +0 -19
  72. package/src/client/utils/constants.spec.ts +0 -96
  73. package/src/client/utils/constants.ts +0 -84
  74. package/src/client.ts +0 -28
  75. package/src/index.ts +0 -11
  76. package/src/lucide-icons.d.ts +0 -6
  77. package/src/server/authz.spec.ts +0 -57
  78. package/src/server/authz.ts +0 -99
  79. package/src/server/cache.spec.ts +0 -556
  80. package/src/server/cache.ts +0 -303
  81. package/src/server/etag.ts +0 -18
  82. package/src/server/external-source.ts +0 -60
  83. package/src/server/handlers.action.spec.ts +0 -44
  84. package/src/server/handlers.attachment.spec.ts +0 -470
  85. package/src/server/handlers.ids-stream.spec.ts +0 -618
  86. package/src/server/handlers.ts +0 -1638
  87. package/src/server/handlers.unauthorized-cookie.spec.ts +0 -187
  88. package/src/server/handlers.visibility.spec.ts +0 -774
  89. package/src/server/ports.ts +0 -222
  90. package/src/server/response.ts +0 -37
  91. package/src/server/schema.spec.ts +0 -30
  92. package/src/server/schema.ts +0 -344
  93. package/src/server/service.spec.ts +0 -1130
  94. package/src/server/service.ts +0 -2045
  95. package/src/server/sse-reader.spec.ts +0 -302
  96. package/src/server/sse-reader.ts +0 -267
  97. package/src/server/test-helpers/handlers-config.ts +0 -321
  98. package/src/server/transaction-retry.spec.ts +0 -63
  99. package/src/server/visibility.spec.ts +0 -403
  100. package/src/server/visibility.ts +0 -373
  101. package/src/server.spec.ts +0 -160
  102. package/src/server.ts +0 -131
  103. package/src/shared/business-date.spec.ts +0 -82
  104. package/src/shared/business-date.ts +0 -104
  105. package/src/shared/comment-adapter.spec.ts +0 -38
  106. package/src/shared/comment-adapter.ts +0 -80
  107. package/src/shared/ids-stream.spec.ts +0 -154
  108. package/src/shared/ids-stream.ts +0 -279
  109. package/src/shared/logger.ts +0 -47
  110. package/src/shared/sse-schema.spec.ts +0 -50
  111. package/src/shared/sse-schema.ts +0 -198
  112. package/src/shared/text-utils.spec.ts +0 -42
  113. package/src/shared/text-utils.ts +0 -65
  114. package/src/shared/types.ts +0 -109
  115. package/src/styles/standalone.entry.css +0 -51
package/dist/server.js CHANGED
@@ -13,4 +13,3 @@ data: ${fe}
13
13
 
14
14
  `,J=ee!=="0-0"?`id: ${ee}
15
15
  ${x}`:x;M.enqueue(N.encode(J))}if(P)try{let x=await d?.getClient();if(x){let J=await x.xRange(D,P,"+",{COUNT:1e3});for(let ue of J)ue.id!==P&&(G!==null&&Ce(G,ue.id)||(Ce(ue.id,ee)||(ee=ue.id),he(ue.id,ue.message)))}}catch(x){Y.error(`[SSE:${B}] catch-up xRange error:`,x)}},cancel(){O()}});return new Response(le,{headers:f({"Content-Type":"text/event-stream","Cache-Control":"no-cache, no-transform",Connection:"keep-alive"})})}},attachment:{loader:async({request:S,params:H})=>{let E=null,A=(f,B,q)=>{let v=new Headers({"Content-Type":"application/json"});return q!==void 0&&v.set("Retry-After",String(q)),E&&v.append("Set-Cookie",E),new Response(JSON.stringify({error:{message:B}}),{status:f,headers:v})};try{let{user:f,cookie:B}=await e(S,{failureRedirect:null});if(E=B??null,!f)return A(401,"Unauthorized");if(S.method!=="GET"&&S.method!=="HEAD")return A(405,"Method not allowed");let q=t.attachmentIdCodec,v=t.readAttachment;if(!(q&&v))return A(404,"Attachment not found");let I=H.token??"",C=q.decode(I);if(C===null||!Number.isSafeInteger(C)||C<=0)return A(400,"Invalid attachment token");let z=await r.getUserIdByExternalId(f.id);if(!z)return A(403,"Forbidden");if(!K(z,Date.now()))return h.error(`429 attachment=${C} viewer=${z} reason=rate_limit`),A(429,"Too many requests",kr);let ce=await ye(S),P=await r.getAttachmentForUser(ce,C,z);if(!P)return h.error(`404 attachment=${C} viewer=${z} reason=not_visible`),A(404,"Attachment not found");if(P.fileSize!=null&&P.fileSize>V)return h.error(`413 attachment=${C} viewer=${z} reason=db_size`),A(413,"Attachment too large");if(!F.tryAcquire())return h.error(`503 attachment=${C} viewer=${z} reason=concurrency`),A(503,"Too many concurrent downloads",Er);let N=!1,M=()=>{N||(N=!0,F.release())},$=!1;try{let L=S.method==="HEAD",w=await v(P.filePath,{maxBytes:V,head:L,principal:o(z)});if(!w.ok){let x=Pr(w.reason);return w.reason==="not_found"&&r.markAttachmentMissing(C).catch(J=>{h.error(`markAttachmentMissing failed attachment=${C} message=${J instanceof Error?J.message:"unknown"}`)}),h.error(`${x} attachment=${C} viewer=${z} reason=${w.reason} code=${w.code??"-"}`),A(x,$r[x]??"Attachment storage unavailable")}let O=ft(P.fileType)??ft(w.contentType)??"application/octet-stream",Z=Mr.has(O),he=new URL(S.url).searchParams.get("download")==="1",le=Z?O:"application/octet-stream",ne=Z&&!he?"inline":"attachment",ee=w.size??w.bytes.byteLength,G=new Headers({"Content-Type":le,"Content-Length":String(ee),"Content-Disposition":`${ne}; filename="${Ut(P.fileName)}"; filename*=UTF-8''${Bt(P.fileName)}`,"Cache-Control":"private, no-store","X-Content-Type-Options":"nosniff","Content-Security-Policy":"default-src 'none'; sandbox","X-Frame-Options":"SAMEORIGIN"});return E&&G.append("Set-Cookie",E),r.markAttachmentPresent(C).catch(x=>{h.error(`markAttachmentPresent failed attachment=${C} message=${x instanceof Error?x.message:"unknown"}`)}),h.info(`200 attachment=${C} viewer=${z} type=${le} disposition=${ne} bytes=${ee}`),L?new Response(null,{status:200,headers:G}):($=!0,new Response(Hr(w.bytes,M,vr),{status:200,headers:G}))}finally{$||M()}}catch(f){if(f instanceof Response)throw f;return h.error(`500 attachment=? viewer=? reason=unexpected message=${f instanceof Error?f.message:"unknown"}`),A(500,"Attachment request failed")}}}}}var Ht=require("@aiquants/mssql"),s=require("drizzle-orm");var Se=t=>(0,s.getColumns)(t),re=(t,e)=>{if(!t)return null;let r=t instanceof Date?t:new Date(t);if(Number.isNaN(r.getTime()))return typeof t=="string"?t:null;let o=r.getFullYear(),d=o<0?`-${String(-o).padStart(4,"0")}`:String(o).padStart(4,"0"),c=String(r.getMonth()+1).padStart(2,"0"),D=String(r.getDate()).padStart(2,"0");if(e==="YYYY-MM-DD")return`${d}-${c}-${D}`;let y=String(r.getHours()).padStart(2,"0"),k=String(r.getMinutes()).padStart(2,"0"),u=String(r.getSeconds()).padStart(2,"0");return`${d}-${c}-${D} ${y}:${k}:${u}`};function gt(t){let{db:e,tables:r,userTable:o,resolveUserId:d,encodeUserId:c,redis:D,cache:y,epochs:k}=t,{hub:u,internal:Y,comment:h,label:V,hubLabel:K,userStatus:F}=r,ye=t.externalSources??[],ke=t.draftLabelNames&&t.draftLabelNames.length>0?t.draftLabelNames:[t.draftLabelName??"\u4E0B\u66F8\u304D"],Ee=ke[0]??"\u4E0B\u66F8\u304D",te=t.logger??de(1,"[DailyReportService]"),Je=n=>(0,Ht.runWithTransactionRetry)(a=>e.transaction(i=>a(()=>n(i))),t.transactionRetry),Ie="daily-report:ids",Rt=t.idsTtlMs??18e4,S="daily-report:ids:epoch",H="daily-report:business-date:",E=t.businessDateTtlMs??3e5,A="daily-report:date-epoch:",f="daily-report:detail-epoch:",q=`${t.streamKey??"daily-report:sse-stream"}:v2`,v=t.streamMaxLen??1e4,I=n=>k.incrementEpoch(n),C=n=>ht(u.sourceType,n),z=(n,a)=>`${Ie}:user:${n}:st:${a}`,ce=n=>`${Ie}:user:${n}:`,P=(n,a,i)=>`daily-report:date:${n}:user:${a}:st:${i}`,N=(n,a)=>`daily-report:date:${n}:user:${a}:`,M=(n,a,i)=>`daily-report:detail:${n}:user:${a}:st:${i}`,$=(n,a)=>`daily-report:detail:${n}:user:${a}:`,L=async(n,a)=>{let i=await D?.getClient();if(!i){te.warn(`[SSE] Redis client unavailable (${a})`);return}let p=Date.now();try{await i.xAdd(q,"*",{data:JSON.stringify(n)},{TRIM:{strategy:"MAXLEN",strategyModifier:"~",threshold:v}});let b=Date.now()-p;b>1e3&&te.warn(`[SSE] Slow publish (${a}): ${b}ms`)}catch(b){te.error(`[SSE] Redis publish failed (${a}):`,b)}},w=n=>n==null||n===""?null:/^\d+$/.test(n)?c(Number(n)):n,O=()=>{let n={};for(let a of ye)n[`ext_${a.sourceType}`]=Se(a.table);return n},Z=n=>{let a=n;for(let i of ye)a=a.leftJoin(i.table,(0,s.and)((0,s.eq)(u.sourceType,i.sourceType),(0,s.eq)(u.sourceIdNum,i.idColumn)));return a},he=(n,a,i)=>{let{hub:p,internal:b}=a,g=p.summary,R=[],T=null,_=null,Q=null,j=null,W=null,ae=null,Te=[],De=ye.find(U=>U.sourceType===p.sourceType),Ae=De?a[`ext_${De.sourceType}`]:void 0;if(De&&Ae){let U=De.mapRow(Ae);U.content!==void 0&&(g=U.content),U.employeeName!==void 0&&(ae=U.employeeName),U.category!==void 0&&(T=U.category),U.creationCategory!==void 0&&(_=U.creationCategory),U.visitTimeFrom!==void 0&&(Q=U.visitTimeFrom),U.visitTimeTo!==void 0&&(j=U.visitTimeTo),U.customerName!==void 0&&(W=U.customerName),U.interviewers!==void 0&&(R=U.interviewers),U.externalComments!==void 0&&(Te=U.externalComments)}else p.sourceType==="Internal"&&b&&(g=b.body);let Re=(a.labels??[]).map(U=>({id:U.id,name:U.name,color:U.color})),se=a.postedCommentRows??[],X=be(n.commentable,p.sourceType),oe=_?ke.includes(_):!1,Ze=fe?.[0]??null;return oe&&Ze&&!Re.some(U=>U.id===Ze)&&Re.push({id:Ze,name:Ee,color:null}),{reportHubId:p.id,date:re(p.businessDate,"YYYY-MM-DD"),author:a.creatorName??w(p.createdBy)??"",userId:p.userId?c(p.userId):"",sourceType:p.sourceType??"Internal",createdAt:re(p.createdAt,"YYYY-MM-DD HH:mm:ss"),updatedAt:re(p.updatedAt,"YYYY-MM-DD HH:mm:ss"),updatedBy:w(p.updatedBy),employeeName:ae??a.creatorName??w(p.createdBy),category:T,creationCategory:_,visitTimeFrom:Q,visitTimeTo:j,customerName:W,interviewers:R,subject:p.title,content:g,externalComments:X?Te:[],isRead:a.isRead??!1,isStarred:a.isStarred??!1,labels:Re,postedComments:se.filter(U=>X||i!==void 0&&U.userId===i).map(U=>({...U,userId:c(U.userId),isMine:i?U.userId===i:!1})),attachments:a.attachments}},le=async(n,a)=>{let i=(0,s.aliasedTable)(K,"draft_label"),p=await ge();return(await e.select({reportHubId:u.id,businessDate:u.businessDate,sourceType:u.sourceType}).from(u).leftJoin(i,(0,s.and)((0,s.eq)(i.hubId,u.id),(0,s.inArray)(i.labelId,p))).where((0,s.and)((0,s.isNull)(u.deletedAt),(0,s.or)((0,s.eq)(u.userId,a),(0,s.isNull)(u.userId),(0,s.isNull)(i.hubId)),C(n.visible))).orderBy((0,s.desc)(u.businessDate),(0,s.desc)(u.id))).map(g=>({...g,businessDate:re(g.businessDate,"YYYY-MM-DD")}))},ne=async(n,a,i)=>{let p=await J(a);if(!p)return[];if(we(n.visible))return[];let b=(0,s.aliasedTable)(K,"draft_label"),g=await ge();return(await e.select({reportHubId:u.id,businessDate:u.businessDate,sourceType:u.sourceType}).top(i).from(u).leftJoin(b,(0,s.and)((0,s.eq)(b.hubId,u.id),(0,s.inArray)(b.labelId,g))).where((0,s.and)((0,s.isNull)(u.deletedAt),(0,s.or)((0,s.eq)(u.userId,p),(0,s.isNull)(u.userId),(0,s.isNull)(b.hubId)),C(n.visible))).orderBy((0,s.desc)(u.businessDate),(0,s.desc)(u.id))).map(T=>({...T,businessDate:re(T.businessDate,"YYYY-MM-DD")}))},ee=async(n,a)=>{let i=await Z(e.select({hub:Se(u),internal:Se(Y),creatorName:o.displayName,...O()}).from(u)).leftJoin(Y,(0,s.eq)(u.id,Y.hubId)).leftJoin(o,(0,s.eq)(u.userId,o.id)).where((0,s.and)((0,s.eq)(u.businessDate,s.sql`${a}`),(0,s.isNull)(u.deletedAt),C(n.visible))).orderBy((0,s.desc)(u.id)),p=await Ye(i.map(b=>b.hub.id));return i.map(b=>he(n,{...b,attachments:p.get(b.hub.id)??[]}))},G=n=>`${H}${n}`,x=new Map,J=async n=>{if(!t.disableUserIdCache&&x.has(n))return x.get(n)??null;let a=await d(n);return a!==null&&!t.disableUserIdCache&&x.set(n,a),a},ue=async(n,a,{forceRefresh:i=!1,snapshot:p=!1,ttlMsOverride:b,onFetchStart:g}={})=>{let R=await J(a);if(!R)return[];if(we(n.visible))return[];let T=z(R,xe(n));return y.getOrFetch({cacheKey:T,fetcher:async()=>{let _=await le(n,R);return _t(_)?_:(te.warn("[DailyReportService] ids array is not in stream order; re-sorting (check SQL ORDER BY vs compareIdsStreamOrder, or concurrent row movement during the scan)"),[..._].sort(qe))},onFetchStart:g,forceRefresh:i,snapshot:p,ttlMsOverride:b??Rt,epochKey:S,refreshAheadRatio:.5})},Ge=(n,a,{forceRefresh:i=!1,snapshot:p=!1,ttlMsOverride:b}={})=>{let g=ie(a);return g?we(n.visible)?Promise.resolve([]):y.getOrFetch({cacheKey:`${G(g)}:st:${xe(n)}`,fetcher:()=>ee(n,g),forceRefresh:i,snapshot:p,ttlMsOverride:b??E}):Promise.resolve([])},fe=null,Me=async()=>(fe!==null||(fe=(await e.select({id:V.id}).from(V).where((0,s.inArray)(V.name,ke)).orderBy(V.id)).map(a=>a.id)),fe),ge=async()=>{let n=await Me();return n.length>0?n:[-1]},Qe=async()=>{let n=await Me();if(n.length===0)return null;let[a]=await e.select({id:V.id}).top(1).from(V).where((0,s.eq)(V.name,Ee));return a?.id??n[0]},Yt=(n,a)=>a!=null?"absent":n!=null?"present":"unknown",Ye=async n=>{let a=new Map,i=r.attachment,p=t.attachmentIdCodec;if(n.length===0||!i||!p)return a;let b=await e.select({id:i.id,hubId:i.hubId,fileName:i.fileName,fileType:i.fileType,fileSize:i.fileSize,createdAt:i.createdAt,objectCheckedAt:i.objectCheckedAt,objectMissingAt:i.objectMissingAt}).from(i).where((0,s.inArray)(i.hubId,n)).orderBy((0,s.asc)(i.createdAt),(0,s.asc)(i.id));for(let g of b){let R={id:p.encode(Number(g.id)),fileName:String(g.fileName),fileType:g.fileType?String(g.fileType):null,fileSize:g.fileSize!=null?Number(g.fileSize):null,createdAt:re(g.createdAt,"YYYY-MM-DD HH:mm:ss"),state:Yt(g.objectCheckedAt,g.objectMissingAt)},T=a.get(Number(g.hubId));T?T.push(R):a.set(Number(g.hubId),[R])}return a},Ft=async(n,a,i)=>{let p=r.attachment;if(!p||we(n.visible))return null;let b=await ge(),g=(0,s.aliasedTable)(K,"draft_label");return(await e.select({fileName:p.fileName,filePath:p.filePath,fileType:p.fileType,fileSize:p.fileSize}).top(1).from(p).innerJoin(u,(0,s.eq)(u.id,p.hubId)).leftJoin(g,(0,s.and)((0,s.eq)(g.hubId,u.id),(0,s.inArray)(g.labelId,b))).where((0,s.and)((0,s.eq)(p.id,a),(0,s.isNull)(u.deletedAt),(0,s.or)((0,s.eq)(u.userId,i),(0,s.isNull)(g.hubId)),C(n.visible))))[0]??null},qt=async n=>{let a=r.attachment;if(!a)return;let i=new Date;try{await e.update(a).set({objectCheckedAt:i,objectMissingAt:i,updatedAt:i}).where((0,s.eq)(a.id,n))}catch(p){te.error("markAttachmentMissing failed",p)}},zt=async n=>{let a=r.attachment;if(!a)return;let i=new Date;try{await e.update(a).set({objectCheckedAt:i,objectMissingAt:null,updatedAt:i}).where((0,s.eq)(a.id,n))}catch(p){te.error("markAttachmentPresent failed",p)}},Vt=async(n,a,i,{forceRefresh:p=!1,snapshot:b=!1,ttlMsOverride:g}={})=>{let R=await J(i);if(!R)return[];let T=ie(a);if(!T)return[];if(we(n.visible))return[];let _=P(T,R,xe(n));return y.getOrFetch({cacheKey:_,fetcher:async()=>{let Q=await ge(),j=(0,s.aliasedTable)(K,"draft_label"),W=await Z(e.select({hub:Se(u),internal:Se(Y),isRead:F.isRead,isStarred:F.isStarred,creatorName:o.displayName,...O()}).from(u)).leftJoin(Y,(0,s.eq)(u.id,Y.hubId)).leftJoin(F,(0,s.and)((0,s.eq)(u.id,F.hubId),(0,s.eq)(F.userId,R))).leftJoin(j,(0,s.and)((0,s.eq)(j.hubId,u.id),(0,s.inArray)(j.labelId,Q))).leftJoin(o,(0,s.eq)(u.userId,o.id)).where((0,s.and)((0,s.eq)(u.businessDate,s.sql`${T}`),(0,s.isNull)(u.deletedAt),(0,s.or)((0,s.eq)(u.userId,R),(0,s.isNull)(j.hubId)),C(n.visible))).orderBy((0,s.desc)(u.id));if(W.length===0)return[];let ae=W.map(X=>X.hub.id),Te=await e.select({hubId:K.hubId,id:V.id,name:V.name,color:V.color}).from(K).innerJoin(V,(0,s.eq)(K.labelId,V.id)).where((0,s.inArray)(K.hubId,ae)),De=await e.select({hubId:h.hubId,id:h.id,body:h.body,createdAt:h.createdAt,userId:h.userId,userName:o.displayName}).from(h).leftJoin(o,(0,s.eq)(h.userId,o.id)).where((0,s.inArray)(h.hubId,ae)).orderBy((0,s.asc)(h.createdAt)),Ae=await Ye(ae),Re=new Map,se=new Map;for(let X of Te){let oe=Re.get(X.hubId);oe||(oe=[],Re.set(X.hubId,oe)),oe.push({id:X.id,name:X.name,color:X.color})}for(let X of De){let oe=se.get(X.hubId);oe||(oe=[],se.set(X.hubId,oe)),oe.push({id:X.id,content:X.body,createdAt:re(X.createdAt,"YYYY-MM-DD HH:mm:ss")||"",userId:X.userId,userName:X.userName||""})}return W.map(X=>{let oe=X.hub.id;return he(n,{...X,attachments:Ae.get(oe)??[],labels:Re.get(oe)||[],postedCommentRows:se.get(oe)||[]},R)})},forceRefresh:p,snapshot:b,ttlMsOverride:g??E,epochKey:`${A}${T}`})},Ne=async(n,a,i,{forceRefresh:p=!1,snapshot:b=!1,ttlMsOverride:g}={})=>{if(we(n.visible))return null;let R=M(a,i,xe(n));return(await y.getOrFetch({cacheKey:R,fetcher:async()=>{let _=await ge(),Q=(0,s.aliasedTable)(K,"draft_label"),j=await Z(e.select({hub:Se(u),internal:Se(Y),isRead:F.isRead,isStarred:F.isStarred,creatorName:o.displayName,...O()}).from(u)).leftJoin(Y,(0,s.eq)(u.id,Y.hubId)).leftJoin(F,(0,s.and)((0,s.eq)(u.id,F.hubId),(0,s.eq)(F.userId,i))).leftJoin(Q,(0,s.and)((0,s.eq)(Q.hubId,u.id),(0,s.inArray)(Q.labelId,_))).leftJoin(o,(0,s.eq)(u.userId,o.id)).where((0,s.and)((0,s.eq)(u.id,a),(0,s.isNull)(u.deletedAt),(0,s.or)((0,s.eq)(u.userId,i),(0,s.isNull)(Q.hubId)),C(n.visible)));if(j.length===0)return[];let W=j[0].hub.id,ae=await e.select({id:V.id,name:V.name,color:V.color}).from(K).innerJoin(V,(0,s.eq)(K.labelId,V.id)).where((0,s.eq)(K.hubId,W)),Te=await e.select({id:h.id,body:h.body,createdAt:h.createdAt,userId:h.userId,userName:o.displayName}).from(h).leftJoin(o,(0,s.eq)(h.userId,o.id)).where((0,s.eq)(h.hubId,W)).orderBy((0,s.asc)(h.createdAt)),De=await Ye([W]),Ae=ae.map(se=>({id:se.id,name:se.name,color:se.color})),Re=Te.map(se=>({id:se.id,content:se.body,createdAt:re(se.createdAt,"YYYY-MM-DD HH:mm:ss")||"",userId:se.userId,userName:se.userName||""}));return[he(n,{...j[0],attachments:De.get(W)??[],labels:Ae,postedCommentRows:Re},i)]},forceRefresh:p,snapshot:b,ttlMsOverride:g??E,epochKey:`${f}${a}`}))[0]??null},Kt=async(n,a,i,p={})=>{let b=await J(i);return b?Ne(n,a,b,p):null},jt=async(n,a)=>{let i=await ge(),p=(0,s.aliasedTable)(K,"draft_label"),[b]=await e.select({sourceType:u.sourceType,deletedAt:u.deletedAt}).top(1).from(u).leftJoin(p,(0,s.and)((0,s.eq)(p.hubId,u.id),(0,s.inArray)(p.labelId,i))).where((0,s.and)((0,s.eq)(u.id,n),(0,s.or)((0,s.eq)(u.userId,a),(0,s.isNull)(p.hubId))));return b??null},Xe=async(n,a,i)=>{let p=await jt(a,i);if(!p||p.deletedAt||!be(n.visible,p.sourceType))throw new Error("Not Found")},Jt=async(n,a,i,p,b,g)=>{await Xe(n,i,a);let R=await e.select().top(1).from(F).where((0,s.and)((0,s.eq)(F.hubId,i),(0,s.eq)(F.userId,a))),T;if(R.length>0?R[0].isStarred!==b?T=(await e.update(F).set({isStarred:b,updatedAt:new Date,updatedBy:String(a)}).output().where((0,s.and)((0,s.eq)(F.hubId,i),(0,s.eq)(F.userId,a))))[0]:T=R[0]:T=(await e.insert(F).output().values({hubId:i,userId:a,isStarred:b,isRead:!1,createdAt:new Date,createdBy:String(a),updatedAt:new Date,updatedBy:String(a)}))[0],p){let _=ie(p);_&&(y.invalidatePrefix(N(_,a)),await I(`${A}${_}`))}return y.invalidate(`daily-report:detail:${i}`),y.invalidatePrefix($(i,a)),await I(`${f}${i}`),await L(ze.parse({type:"status-update",reportHubId:i,recipientRawUserId:a,statusType:"star",value:b,clientTempId:g}),"setStarStatus"),T},Gt=async(n,a,i,p,b,g)=>{await Xe(n,i,a);let R=await e.select().top(1).from(F).where((0,s.and)((0,s.eq)(F.hubId,i),(0,s.eq)(F.userId,a))),T;if(R.length>0?R[0].isRead!==b?T=(await e.update(F).set({isRead:b,updatedAt:new Date,updatedBy:String(a)}).output().where((0,s.and)((0,s.eq)(F.hubId,i),(0,s.eq)(F.userId,a))))[0]:T=R[0]:T=(await e.insert(F).output().values({hubId:i,userId:a,isRead:b,isStarred:!1,createdAt:new Date,createdBy:String(a),updatedAt:new Date,updatedBy:String(a)}))[0],p){let _=ie(p);_&&(y.invalidatePrefix(N(_,a)),await I(`${A}${_}`))}return y.invalidate(`daily-report:detail:${i}`),y.invalidatePrefix($(i,a)),await I(`${f}${i}`),await L(ze.parse({type:"status-update",reportHubId:i,recipientRawUserId:a,statusType:"read",value:b,clientTempId:g}),"setReadStatus"),T},Dt=async(n,a)=>{if(a===null)return;let i=await ge(),[p]=await e.select({hubId:K.hubId}).top(1).from(K).where((0,s.and)((0,s.eq)(K.hubId,n),(0,s.inArray)(K.labelId,i)));return p?a:void 0},Qt=async(n,a,i,p,b,g)=>{let[R]=await e.select({sourceType:u.sourceType,deletedAt:u.deletedAt,userId:u.userId}).top(1).from(u).where((0,s.eq)(u.id,i));if(!R||R.deletedAt)throw new Error("Not Found");if(await Xe(n,i,a),!be(n.commentable,R.sourceType))throw new Error("Comments are restricted by the viewer's comment permission");if(R.sourceType.toLowerCase()!=="internal")throw new Error("Comments are restricted for external daily report sources");let T=await Dt(i,R.userId),[_]=await e.insert(h).output().values({hubId:i,userId:a,body:p,createdAt:new Date,createdBy:String(a),updatedAt:new Date,updatedBy:String(a)}),[Q]=await e.select({displayName:o.displayName}).top(1).from(o).where((0,s.eq)(o.id,a)),j=Q?.displayName??"Unknown";if(b){let ae=ie(b);ae&&(y.invalidatePrefix(`daily-report:date:${ae}:user:`),await I(`${A}${ae}`))}y.invalidate(`daily-report:detail:${i}`),y.invalidatePrefix(`daily-report:detail:${i}:user:`),await I(`${f}${i}`);let W={id:_.id,userId:c(_.userId),userName:j,content:_.body,createdAt:re(_.createdAt,"YYYY-MM-DD HH:mm:ss")??"",isMine:!0};return await L(it.parse({type:"comment-add",reportHubId:i,comment:W,clientTempId:g,recipientRawUserId:T,sourceType:R.sourceType}),"addComment"),W},Xt=async(n,a)=>await n.select().top(1).from(h).where((0,s.eq)(h.id,a)),Wt=async(n,a,i,p,b,g)=>{let R=await Xt(e,p);if(R.length===0)throw new Error("Not Found");if(R[0].hubId!==i)throw new Error("Not Found");let[T]=await e.select({userId:u.userId,sourceType:u.sourceType}).top(1).from(u).where((0,s.eq)(u.id,R[0].hubId));if(!(T&&be(n.visible,T.sourceType)))throw new Error("Not Found");if(R[0].userId!==a)throw new Error("Unauthorized");let _=await Dt(i,T.userId);if(await e.delete(h).where((0,s.eq)(h.id,p)),b){let Q=ie(b);Q&&(y.invalidatePrefix(`daily-report:date:${Q}:user:`),await I(`${A}${Q}`))}y.invalidate(`daily-report:detail:${i}`),y.invalidatePrefix(`daily-report:detail:${i}:user:`),await I(`${f}${i}`),await L(lt.parse({type:"comment-delete",reportHubId:i,commentId:p,clientTempId:g,recipientRawUserId:_,sourceType:T?.sourceType}),"deleteComment")},Zt=async(n,a,i)=>{te.info("createDailyReport called",{userId:n,businessDate:a});let[p]=await e.select({displayName:o.displayName}).from(o).where((0,s.eq)(o.id,n)),b=p?.displayName??c(n);try{let g=await Je(async _=>{te.info("Starting transaction");let Q=`internal-temp-${Date.now()}-${Math.random()}`,[j]=await _.insert(u).output().values({sourceType:"Internal",sourceId:Q,businessDate:new Date(a),userId:n,title:"(\u7121\u984C)",createdAt:new Date,createdBy:String(n),updatedAt:new Date,updatedBy:String(n)});await _.update(u).set({sourceId:String(j.id)}).where((0,s.eq)(u.id,j.id)),te.info("Hub created",j),await _.insert(Y).values({hubId:j.id,body:"",createdAt:new Date,createdBy:String(n),updatedAt:new Date,updatedBy:String(n)}),te.info("Internal created"),te.info("Calling getDraftLabelId");let W=await Qe();te.info("draftLabelId",W);let ae=[];return W&&(await _.insert(K).values({hubId:j.id,labelId:W,createdAt:new Date,createdBy:String(n)}),ae.push({id:W,name:Ee,color:null})),te.info("Label assigned"),{reportHubId:j.id,date:a,createdAt:re(j.createdAt,"YYYY-MM-DD HH:mm:ss"),author:b,userId:c(n),sourceType:"Internal",employeeName:b,updatedBy:c(n),updatedAt:re(j.updatedAt,"YYYY-MM-DD HH:mm:ss"),category:null,creationCategory:null,visitTimeFrom:null,visitTimeTo:null,customerName:null,interviewers:[],subject:j.title,content:"",externalComments:[],isRead:!0,isStarred:!1,labels:ae,postedComments:[],attachments:[]}}),R=ie(a);R&&y.invalidatePrefix(N(R,n)),y.invalidatePrefix(H),y.invalidatePrefix(ce(n)),await I(S),R&&await I(`${A}${R}`);let T=await Ne(me.unrestricted("post-write self read: the writer always sees the row they just wrote"),g.reportHubId,n,{forceRefresh:!0});if(T){let _=await Me(),Q=T.labels.some(j=>_.includes(j.id));await L(ut.parse({type:"report-create",reportHubId:T.reportHubId,report:T,clientTempId:i,recipientRawUserId:Q?n:void 0}),"createDailyReport")}return T??g}catch(g){throw te.error("Error in createDailyReport",g),g}},Fe=async(n,a)=>await n.select().top(1).from(u).where((0,s.eq)(u.id,a)),We=async(n,a,i)=>{await n.update(u).set(i).where((0,s.eq)(u.id,a))},wt=async(n,a,i)=>{await n.update(Y).set(i).where((0,s.eq)(Y.hubId,a))},St=async(n,a,i)=>{await n.delete(K).where((0,s.and)((0,s.eq)(K.hubId,a),(0,s.eq)(K.labelId,i)))};return{streamKey:q,streamMaxLen:v,clearCache:async()=>{y.clearAll(),x.clear(),fe=null,k&&await I(S),te.info("[DailyReportService] Server-side DB/SQL caches cleared successfully.")},invalidateHubReadCaches:async(n,a)=>{y.invalidatePrefix(H),y.invalidatePrefix(Ie),await I(S);for(let i of new Set(n))y.invalidatePrefix(`daily-report:detail:${i}:user:`),await I(`${f}${i}`);for(let i of new Set(a)){let p=ie(i);p&&await I(`${A}${p}`)}},getUserIdByExternalId:J,getDailyReportIdsByExternalId:ue,getDailyReportIdsFirstPageByExternalId:ne,getDailyReportsByBusinessDate:Ge,getDailyReportsByBusinessDateByExternalId:Vt,getDailyReportDetailById:Ne,getDailyReportDetailByIdByExternalId:Kt,getDraftLabelId:Qe,getAttachmentsByHubIds:Ye,getAttachmentForUser:Ft,markAttachmentMissing:qt,markAttachmentPresent:zt,setStarStatus:Jt,setReadStatus:Gt,addComment:Qt,deleteComment:Wt,createDailyReport:Zt,updateDailyReport:async(n,a,i,p)=>{let b=await Fe(e,n);if(!b.length||b[0].deletedAt)throw new Error("Not Found");if(b[0].userId!==a)throw new Error("Unauthorized");await Je(async T=>{i.title!==void 0&&await We(T,n,{title:i.title,updatedAt:new Date,updatedBy:String(a)}),i.content!==void 0&&await wt(T,n,{body:i.content,updatedAt:new Date,updatedBy:String(a)})}),y.invalidate(`daily-report:detail:${n}`),y.invalidatePrefix(`daily-report:detail:${n}:user:`),y.invalidatePrefix(H),await I(`${f}${n}`);let g=ie(re(b[0].businessDate,"YYYY-MM-DD"));g&&(y.invalidatePrefix(`daily-report:date:${g}:user:`),await I(`${A}${g}`));let R=await Ne(me.unrestricted("post-write self read: the writer always sees the row they just wrote"),n,a,{forceRefresh:!0});if(R){let T=await Me(),_=R.labels.some(Q=>T.includes(Q.id));await L(dt.parse({type:"report-update",reportHubId:R.reportHubId,report:R,clientTempId:p,recipientRawUserId:_?a:void 0}),"updateDailyReport")}},publishDailyReport:async(n,a,i)=>{let p=await Fe(e,n);if(!p.length)throw new Error("Not Found");if(p[0].userId!==a)throw new Error("Unauthorized");let b=await Qe();if(!b)return null;if(await St(e,n,b),y.invalidatePrefix(`daily-report:detail:${n}:user:`),y.invalidatePrefix(H),y.invalidatePrefix(Ie),await I(S),p[0].businessDate){let T=ie(re(p[0].businessDate,"YYYY-MM-DD"));T&&await I(`${A}${T}`)}let g=ie(re(p[0].businessDate,"YYYY-MM-DD"));g&&y.invalidatePrefix(N(g,a));let R=await Ne(me.unrestricted("post-write self read: the writer always sees the row they just wrote"),n,a,{forceRefresh:!0});return R&&await L(ct.parse({type:"report-publish",reportHubId:R.reportHubId,report:R,clientTempId:i}),"publishDailyReport"),R??null},deleteDailyReport:async(n,a,i)=>{let p=await Fe(e,n);if(!p.length||p[0].deletedAt)throw new Error("Not Found");if(p[0].userId!==a)throw new Error("Unauthorized");if(await We(e,n,{deletedAt:new Date,deletedBy:String(a),updatedAt:new Date,updatedBy:String(a)}),y.invalidatePrefix(`daily-report:detail:${n}:user:`),y.invalidatePrefix(H),y.invalidatePrefix(Ie),await I(S),p[0].businessDate){let b=ie(re(p[0].businessDate,"YYYY-MM-DD"));b&&await I(`${A}${b}`)}await L(pt.parse({type:"report-delete",reportHubId:n,clientTempId:i,sourceType:p[0].sourceType}),"deleteDailyReport")},findDailyReportHubById:Fe,updateDailyReportHub:We,updateDailyReportInternal:wt,deleteDailyReportLabel:St}}var He=require("drizzle-orm");function Ot(t){let e=[],r=t&&t.length>0?t:[{key:"internal",name:"Internal",description:"Internal daily reports"},{key:"external",name:"External",description:"External daily reports"}];for(let o of r){let c=`daily_report_${o.key.toLowerCase().replace(/[^a-z0-9_]/g,"_")}`;e.push({resourceKey:c,name:o.name,description:o.description??`${o.name} daily report access`}),o.includeCommentResource!==!1&&e.push({resourceKey:`${c}_comment`,name:`${o.name} Comment`,description:`${o.name} daily report comment access`})}return e}async function qr(t,e,r){let o=t,d=e.TMResource,c=r.appKey,D=r.actor??"system:daily-report",y=new Date,k=r.resources??Ot(r.sources);for(let u of k){let Y=await o.select().from(d).where((0,He.and)((0,He.eq)(d.appKey,c),(0,He.eq)(d.resourceKey,u.resourceKey)));(!Y||Y.length===0)&&await o.insert(d).values({appKey:c,resourceKey:u.resourceKey,name:u.name,description:u.description??null,createdAt:y,createdBy:D,updatedAt:y,updatedBy:D})}}var zr=de(1,"[DailyReportExternalSource]"),Vr=(t,e,r,o=zr)=>{if(!t)return[];try{let d=JSON.parse(t);return Array.isArray(d)?d.map(r).filter(c=>c!==null):(o.warn(`Unexpected ${e} format: not an array`),[])}catch(d){return o.warn(`Failed to parse ${e}:`,d),[]}};var Oe=require("drizzle-orm"),l=require("drizzle-orm/mssql-core");function Kr(t,e){let r=(0,l.mssqlSchema)(t),o=e.userTable,d=r.table("DailyReportHub",{id:(0,l.bigint)("id",{mode:"number"}).identity().notNull(),sourceType:(0,l.nvarchar)("source_type",{length:20}).notNull(),sourceId:(0,l.nvarchar)("source_id",{length:100}).notNull(),sourceIdNum:(0,l.bigint)("source_id_num",{mode:"number"}).generatedAlwaysAs(Oe.sql`TRY_CAST(source_id AS BIGINT)`),businessDate:(0,l.date)("business_date"),userId:(0,l.bigint)("user_id",{mode:"number"}),title:(0,l.nvarchar)("title",{length:200}),summary:(0,l.nvarchar)("summary",{length:"max"}),createdAt:(0,l.datetime2)("created_at").notNull(),createdBy:(0,l.nvarchar)("created_by",{length:50}).notNull(),updatedAt:(0,l.datetime2)("updated_at").notNull(),updatedBy:(0,l.nvarchar)("updated_by",{length:50}).notNull(),deletedAt:(0,l.datetime2)("deleted_at"),deletedBy:(0,l.nvarchar)("deleted_by",{length:50})},h=>[(0,l.primaryKey)({name:`${t}_DailyReportHub_pk`,columns:[h.id]}),(0,l.foreignKey)({name:`${t}_DailyReportHub_user_id_fk`,columns:[h.userId],foreignColumns:[o.id]}),(0,l.index)(`${t}_DailyReportHub_business_date_index`).on(h.businessDate),(0,l.index)(`${t}_DailyReportHub_updated_at_index`).on(h.updatedAt),(0,l.index)(`${t}_DailyReportHub_source_index`).on(h.sourceType,h.sourceId),(0,l.index)(`${t}_DailyReportHub_user_id_index`).on(h.userId),(0,l.index)(`${t}_DailyReportHub_business_date_id_index`).on((0,Oe.desc)(h.businessDate),(0,Oe.desc)(h.id)),(0,l.index)(`${t}_DailyReportHub_deleted_at_index`).on(h.deletedAt)]),c=r.table("DailyReportInternal",{hubId:(0,l.bigint)("hub_id",{mode:"number"}).notNull(),body:(0,l.nvarchar)("body",{length:"max"}),metadata:(0,l.nvarchar)("metadata",{length:"max"}),createdAt:(0,l.datetime2)("created_at").notNull(),createdBy:(0,l.nvarchar)("created_by",{length:50}).notNull(),updatedAt:(0,l.datetime2)("updated_at").notNull(),updatedBy:(0,l.nvarchar)("updated_by",{length:50}).notNull()},h=>[(0,l.primaryKey)({name:`${t}_DailyReportInternal_pk`,columns:[h.hubId]}),(0,l.foreignKey)({name:`${t}_DailyReportInternal_hub_id_fk`,columns:[h.hubId],foreignColumns:[d.id]})]),D=r.table("DailyReportComment",{id:(0,l.bigint)("id",{mode:"number"}).identity().notNull(),hubId:(0,l.bigint)("hub_id",{mode:"number"}).notNull(),userId:(0,l.bigint)("user_id",{mode:"number"}).notNull(),body:(0,l.nvarchar)("body",{length:"max"}).notNull(),createdAt:(0,l.datetime2)("created_at").notNull(),createdBy:(0,l.nvarchar)("created_by",{length:50}).notNull(),updatedAt:(0,l.datetime2)("updated_at").notNull(),updatedBy:(0,l.nvarchar)("updated_by",{length:50}).notNull()},h=>[(0,l.primaryKey)({name:`${t}_DailyReportComment_pk`,columns:[h.id]}),(0,l.foreignKey)({name:`${t}_DailyReportComment_hub_id_fk`,columns:[h.hubId],foreignColumns:[d.id]}),(0,l.foreignKey)({name:`${t}_DailyReportComment_user_id_fk`,columns:[h.userId],foreignColumns:[o.id]}),(0,l.index)(`${t}_DailyReportComment_hub_id_index`).on(h.hubId)]),y=r.table("DailyReportLabel",{id:(0,l.bigint)("id",{mode:"number"}).identity().notNull(),userId:(0,l.bigint)("user_id",{mode:"number"}),name:(0,l.nvarchar)("name",{length:50}).notNull(),color:(0,l.nvarchar)("color",{length:20}),sortOrder:(0,l.int)("sort_order"),createdAt:(0,l.datetime2)("created_at").notNull(),createdBy:(0,l.nvarchar)("created_by",{length:50}).notNull(),updatedAt:(0,l.datetime2)("updated_at").notNull(),updatedBy:(0,l.nvarchar)("updated_by",{length:50}).notNull()},h=>[(0,l.primaryKey)({name:`${t}_DailyReportLabel_pk`,columns:[h.id]}),(0,l.foreignKey)({name:`${t}_DailyReportLabel_user_id_fk`,columns:[h.userId],foreignColumns:[o.id]})]),k=r.table("DailyReportHub_Label",{hubId:(0,l.bigint)("hub_id",{mode:"number"}).notNull(),labelId:(0,l.bigint)("label_id",{mode:"number"}).notNull(),createdAt:(0,l.datetime2)("created_at").notNull(),createdBy:(0,l.nvarchar)("created_by",{length:50}).notNull()},h=>[(0,l.primaryKey)({name:`${t}_DailyReportHub_Label_pk`,columns:[h.hubId,h.labelId]}),(0,l.foreignKey)({name:`${t}_DailyReportHub_Label_hub_id_fk`,columns:[h.hubId],foreignColumns:[d.id]}),(0,l.foreignKey)({name:`${t}_DailyReportHub_Label_label_id_fk`,columns:[h.labelId],foreignColumns:[y.id]})]),u=r.table("DailyReportUserStatus",{hubId:(0,l.bigint)("hub_id",{mode:"number"}).notNull(),userId:(0,l.bigint)("user_id",{mode:"number"}).notNull(),isRead:(0,l.bit)("is_read").default(!1).notNull(),isStarred:(0,l.bit)("is_starred").default(!1).notNull(),createdAt:(0,l.datetime2)("created_at").notNull(),createdBy:(0,l.nvarchar)("created_by",{length:50}).notNull(),updatedAt:(0,l.datetime2)("updated_at").notNull(),updatedBy:(0,l.nvarchar)("updated_by",{length:50}).notNull()},h=>[(0,l.primaryKey)({name:`${t}_DailyReportUserStatus_pk`,columns:[h.hubId,h.userId]}),(0,l.foreignKey)({name:`${t}_DailyReportUserStatus_hub_id_fk`,columns:[h.hubId],foreignColumns:[d.id]}),(0,l.foreignKey)({name:`${t}_DailyReportUserStatus_user_id_fk`,columns:[h.userId],foreignColumns:[o.id]})]),Y=r.table("DailyReportAttachment",{id:(0,l.bigint)("id",{mode:"number"}).identity().notNull(),hubId:(0,l.bigint)("hub_id",{mode:"number"}).notNull(),uploadedBy:(0,l.bigint)("uploaded_by",{mode:"number"}),sourceKey:(0,l.nvarchar)("source_key",{length:200}).notNull(),fileName:(0,l.nvarchar)("file_name",{length:255}).notNull(),filePath:(0,l.nvarchar)("file_path",{length:"max"}).notNull(),fileType:(0,l.nvarchar)("file_type",{length:100}),fileSize:(0,l.bigint)("file_size",{mode:"number"}),objectCheckedAt:(0,l.datetime2)("object_checked_at"),objectMissingAt:(0,l.datetime2)("object_missing_at"),createdAt:(0,l.datetime2)("created_at").notNull(),createdBy:(0,l.nvarchar)("created_by",{length:50}).notNull(),updatedAt:(0,l.datetime2)("updated_at").notNull(),updatedBy:(0,l.nvarchar)("updated_by",{length:50}).notNull()},h=>[(0,l.primaryKey)({name:`${t}_DailyReportAttachment_pk`,columns:[h.id]}),(0,l.foreignKey)({name:`${t}_DailyReportAttachment_hub_id_fk`,columns:[h.hubId],foreignColumns:[d.id]}),(0,l.foreignKey)({name:`${t}_DailyReportAttachment_uploaded_by_fk`,columns:[h.uploadedBy],foreignColumns:[o.id]}),(0,l.uniqueIndex)(`${t}_DailyReportAttachment_source_unique`).on(h.hubId,h.sourceKey),(0,l.index)(`${t}_DailyReportAttachment_hub_id_index`).on(h.hubId,h.createdAt)]);return{hub:d,internal:c,comment:D,attachment:Y,label:y,hubLabel:k,userStatus:u}}function jr(t){t.redis||(t.logger??console).warn("[DailyReport] redis provider is not injected: cross-worker cache invalidation is disabled (staleness is bounded only by TTL) and SSE publishing is skipped.");let e=nt(t.redis),r=new Pe({defaultTtlMs:t.cacheDefaultTtlMs??6e4},e),o=gt({...t,cache:r,epochs:e}),d=new $e({redis:t.redis,streamKey:o.streamKey,cache:r,logger:t.logger}),c=bt({authenticate:t.authenticate,resolveVisibleSourceTypes:t.resolveVisibleSourceTypes,service:o,encodeUserId:t.encodeUserId,attachmentIdCodec:t.attachmentIdCodec,readAttachment:t.readAttachment,attachmentMaxBytes:t.attachmentMaxBytes,attachmentRateLimitPerMinute:t.attachmentRateLimitPerMinute,attachmentConcurrency:t.attachmentConcurrency,redis:t.redis,sseReader:d,streamKey:o.streamKey,loginRedirectPath:t.loginRedirectPath,enableDevCacheClear:t.enableDevCacheClear,logger:t.logger});return{service:o,cache:r,epochs:e,sseReader:d,streamKey:o.streamKey,knownSourceTypes:[...new Set(["Internal",...(t.externalSources??[]).map(D=>D.sourceType)])],...c}}0&&(module.exports={DailyReportSseReader,DailyReportViewerScope,SqlResultCache,asciiFallbackFileName,buildVisibleSourceTypeCondition,computeSourceTypeDigest,computeViewerScopeDigest,createDailyReportHandlers,createDailyReportServer,createDailyReportService,createEpochStore,defineDailyReportAuthzResources,defineDailyReportSchema,deniesEverySourceType,encodeRfc8187,formatDateValue,generateETag,isSourceTypeVisible,isStreamIdLte,jsonResponseWithETag,normalizeVisibleSourceTypes,sanitizeMediaType,seedDailyReportAuthzResources,transformJsonArray});
16
- //# sourceMappingURL=server.js.map
package/dist/server.mjs CHANGED
@@ -13,4 +13,3 @@ data: ${ge}
13
13
 
14
14
  `,J=te!=="0-0"?`id: ${te}
15
15
  ${v}`:v;E.enqueue(M.encode(J))}if(L)try{let v=await d?.getClient();if(v){let J=await v.xRange(R,L,"+",{COUNT:1e3});for(let me of J)me.id!==L&&(Q!==null&&ze(Q,me.id)||(ze(me.id,te)||(te=me.id),be(me.id,me.message)))}}catch(v){O.error(`[SSE:${$}] catch-up xRange error:`,v)}},cancel(){H()}});return new Response(pe,{headers:y({"Content-Type":"text/event-stream","Cache-Control":"no-cache, no-transform",Connection:"keep-alive"})})}},attachment:{loader:async({request:w,params:U})=>{let k=null,T=(y,$,F)=>{let _=new Headers({"Content-Type":"application/json"});return F!==void 0&&_.set("Retry-After",String(F)),k&&_.append("Set-Cookie",k),new Response(JSON.stringify({error:{message:$}}),{status:y,headers:_})};try{let{user:y,cookie:$}=await e(w,{failureRedirect:null});if(k=$??null,!y)return T(401,"Unauthorized");if(w.method!=="GET"&&w.method!=="HEAD")return T(405,"Method not allowed");let F=t.attachmentIdCodec,_=t.readAttachment;if(!(F&&_))return T(404,"Attachment not found");let S=U.token??"",A=F.decode(S);if(A===null||!Number.isSafeInteger(A)||A<=0)return T(400,"Invalid attachment token");let q=await r.getUserIdByExternalId(y.id);if(!q)return T(403,"Forbidden");if(!K(q,Date.now()))return m.error(`429 attachment=${A} viewer=${q} reason=rate_limit`),T(429,"Too many requests",Lr);let he=await fe(w),L=await r.getAttachmentForUser(he,A,q);if(!L)return m.error(`404 attachment=${A} viewer=${q} reason=not_visible`),T(404,"Attachment not found");if(L.fileSize!=null&&L.fileSize>V)return m.error(`413 attachment=${A} viewer=${q} reason=db_size`),T(413,"Attachment too large");if(!Y.tryAcquire())return m.error(`503 attachment=${A} viewer=${q} reason=concurrency`),T(503,"Too many concurrent downloads",Pr);let M=!1,E=()=>{M||(M=!0,Y.release())},P=!1;try{let N=w.method==="HEAD",D=await _(L.filePath,{maxBytes:V,head:N,principal:s(q)});if(!D.ok){let v=Yr(D.reason);return D.reason==="not_found"&&r.markAttachmentMissing(A).catch(J=>{m.error(`markAttachmentMissing failed attachment=${A} message=${J instanceof Error?J.message:"unknown"}`)}),m.error(`${v} attachment=${A} viewer=${q} reason=${D.reason} code=${D.code??"-"}`),T(v,Fr[v]??"Attachment storage unavailable")}let H=Ot(L.fileType)??Ot(D.contentType)??"application/octet-stream",ee=$r.has(H),be=new URL(w.url).searchParams.get("download")==="1",pe=ee?H:"application/octet-stream",se=ee&&!be?"inline":"attachment",te=D.size??D.bytes.byteLength,Q=new Headers({"Content-Type":pe,"Content-Length":String(te),"Content-Disposition":`${se}; filename="${Or(L.fileName)}"; filename*=UTF-8''${Hr(L.fileName)}`,"Cache-Control":"private, no-store","X-Content-Type-Options":"nosniff","Content-Security-Policy":"default-src 'none'; sandbox","X-Frame-Options":"SAMEORIGIN"});return k&&Q.append("Set-Cookie",k),r.markAttachmentPresent(A).catch(v=>{m.error(`markAttachmentPresent failed attachment=${A} message=${v instanceof Error?v.message:"unknown"}`)}),m.info(`200 attachment=${A} viewer=${q} type=${pe} disposition=${se} bytes=${te}`),N?new Response(null,{status:200,headers:Q}):(P=!0,new Response(Vr(D.bytes,E,Mr),{status:200,headers:Q}))}finally{P||E()}}catch(y){if(y instanceof Response)throw y;return m.error(`500 attachment=? viewer=? reason=unexpected message=${y instanceof Error?y.message:"unknown"}`),T(500,"Attachment request failed")}}}}}import{runWithTransactionRetry as Gr}from"@aiquants/mssql";import{aliasedTable as $e,and as G,asc as tt,desc as Be,eq as f,getColumns as Qr,inArray as we,isNull as ce,or as Ue,sql as qt}from"drizzle-orm";var xe=t=>Qr(t),de=(t,e)=>{if(!t)return null;let r=t instanceof Date?t:new Date(t);if(Number.isNaN(r.getTime()))return typeof t=="string"?t:null;let s=r.getFullYear(),d=s<0?`-${String(-s).padStart(4,"0")}`:String(s).padStart(4,"0"),l=String(r.getMonth()+1).padStart(2,"0"),R=String(r.getDate()).padStart(2,"0");if(e==="YYYY-MM-DD")return`${d}-${l}-${R}`;let p=String(r.getHours()).padStart(2,"0"),x=String(r.getMinutes()).padStart(2,"0"),i=String(r.getSeconds()).padStart(2,"0");return`${d}-${l}-${R} ${p}:${x}:${i}`};function zt(t){let{db:e,tables:r,userTable:s,resolveUserId:d,encodeUserId:l,redis:R,cache:p,epochs:x}=t,{hub:i,internal:O,comment:m,label:V,hubLabel:K,userStatus:Y}=r,fe=t.externalSources??[],He=t.draftLabelNames&&t.draftLabelNames.length>0?t.draftLabelNames:[t.draftLabelName??"\u4E0B\u66F8\u304D"],Oe=He[0]??"\u4E0B\u66F8\u304D",ne=t.logger??ye(1,"[DailyReportService]"),rt=n=>Gr(a=>e.transaction(o=>a(()=>n(o))),t.transactionRetry),Ee="daily-report:ids",Dt=t.idsTtlMs??18e4,w="daily-report:ids:epoch",U="daily-report:business-date:",k=t.businessDateTtlMs??3e5,T="daily-report:date-epoch:",y="daily-report:detail-epoch:",F=`${t.streamKey??"daily-report:sse-stream"}:v2`,_=t.streamMaxLen??1e4,S=n=>x.incrementEpoch(n),A=n=>$t(i.sourceType,n),q=(n,a)=>`${Ee}:user:${n}:st:${a}`,he=n=>`${Ee}:user:${n}:`,L=(n,a,o)=>`daily-report:date:${n}:user:${a}:st:${o}`,M=(n,a)=>`daily-report:date:${n}:user:${a}:`,E=(n,a,o)=>`daily-report:detail:${n}:user:${a}:st:${o}`,P=(n,a)=>`daily-report:detail:${n}:user:${a}:`,N=async(n,a)=>{let o=await R?.getClient();if(!o){ne.warn(`[SSE] Redis client unavailable (${a})`);return}let u=Date.now();try{await o.xAdd(F,"*",{data:JSON.stringify(n)},{TRIM:{strategy:"MAXLEN",strategyModifier:"~",threshold:_}});let h=Date.now()-u;h>1e3&&ne.warn(`[SSE] Slow publish (${a}): ${h}ms`)}catch(h){ne.error(`[SSE] Redis publish failed (${a}):`,h)}},D=n=>n==null||n===""?null:/^\d+$/.test(n)?l(Number(n)):n,H=()=>{let n={};for(let a of fe)n[`ext_${a.sourceType}`]=xe(a.table);return n},ee=n=>{let a=n;for(let o of fe)a=a.leftJoin(o.table,G(f(i.sourceType,o.sourceType),f(i.sourceIdNum,o.idColumn)));return a},be=(n,a,o)=>{let{hub:u,internal:h}=a,b=u.summary,g=[],I=null,C=null,X=null,j=null,Z=null,oe=null,Me=[],Ce=fe.find(B=>B.sourceType===u.sourceType),Ne=Ce?a[`ext_${Ce.sourceType}`]:void 0;if(Ce&&Ne){let B=Ce.mapRow(Ne);B.content!==void 0&&(b=B.content),B.employeeName!==void 0&&(oe=B.employeeName),B.category!==void 0&&(I=B.category),B.creationCategory!==void 0&&(C=B.creationCategory),B.visitTimeFrom!==void 0&&(X=B.visitTimeFrom),B.visitTimeTo!==void 0&&(j=B.visitTimeTo),B.customerName!==void 0&&(Z=B.customerName),B.interviewers!==void 0&&(g=B.interviewers),B.externalComments!==void 0&&(Me=B.externalComments)}else u.sourceType==="Internal"&&h&&(b=h.body);let Ae=(a.labels??[]).map(B=>({id:B.id,name:B.name,color:B.color})),ie=a.postedCommentRows??[],W=Ie(n.commentable,u.sourceType),le=C?He.includes(C):!1,it=ge?.[0]??null;return le&&it&&!Ae.some(B=>B.id===it)&&Ae.push({id:it,name:Oe,color:null}),{reportHubId:u.id,date:de(u.businessDate,"YYYY-MM-DD"),author:a.creatorName??D(u.createdBy)??"",userId:u.userId?l(u.userId):"",sourceType:u.sourceType??"Internal",createdAt:de(u.createdAt,"YYYY-MM-DD HH:mm:ss"),updatedAt:de(u.updatedAt,"YYYY-MM-DD HH:mm:ss"),updatedBy:D(u.updatedBy),employeeName:oe??a.creatorName??D(u.createdBy),category:I,creationCategory:C,visitTimeFrom:X,visitTimeTo:j,customerName:Z,interviewers:g,subject:u.title,content:b,externalComments:W?Me:[],isRead:a.isRead??!1,isStarred:a.isStarred??!1,labels:Ae,postedComments:ie.filter(B=>W||o!==void 0&&B.userId===o).map(B=>({...B,userId:l(B.userId),isMine:o?B.userId===o:!1})),attachments:a.attachments}},pe=async(n,a)=>{let o=$e(K,"draft_label"),u=await Te();return(await e.select({reportHubId:i.id,businessDate:i.businessDate,sourceType:i.sourceType}).from(i).leftJoin(o,G(f(o.hubId,i.id),we(o.labelId,u))).where(G(ce(i.deletedAt),Ue(f(i.userId,a),ce(i.userId),ce(o.hubId)),A(n.visible))).orderBy(Be(i.businessDate),Be(i.id))).map(b=>({...b,businessDate:de(b.businessDate,"YYYY-MM-DD")}))},se=async(n,a,o)=>{let u=await J(a);if(!u)return[];if(ve(n.visible))return[];let h=$e(K,"draft_label"),b=await Te();return(await e.select({reportHubId:i.id,businessDate:i.businessDate,sourceType:i.sourceType}).top(o).from(i).leftJoin(h,G(f(h.hubId,i.id),we(h.labelId,b))).where(G(ce(i.deletedAt),Ue(f(i.userId,u),ce(i.userId),ce(h.hubId)),A(n.visible))).orderBy(Be(i.businessDate),Be(i.id))).map(I=>({...I,businessDate:de(I.businessDate,"YYYY-MM-DD")}))},te=async(n,a)=>{let o=await ee(e.select({hub:xe(i),internal:xe(O),creatorName:s.displayName,...H()}).from(i)).leftJoin(O,f(i.id,O.hubId)).leftJoin(s,f(i.userId,s.id)).where(G(f(i.businessDate,qt`${a}`),ce(i.deletedAt),A(n.visible))).orderBy(Be(i.id)),u=await je(o.map(h=>h.hub.id));return o.map(h=>be(n,{...h,attachments:u.get(h.hub.id)??[]}))},Q=n=>`${U}${n}`,v=new Map,J=async n=>{if(!t.disableUserIdCache&&v.has(n))return v.get(n)??null;let a=await d(n);return a!==null&&!t.disableUserIdCache&&v.set(n,a),a},me=async(n,a,{forceRefresh:o=!1,snapshot:u=!1,ttlMsOverride:h,onFetchStart:b}={})=>{let g=await J(a);if(!g)return[];if(ve(n.visible))return[];let I=q(g,Ke(n));return p.getOrFetch({cacheKey:I,fetcher:async()=>{let C=await pe(n,g);return xt(C)?C:(ne.warn("[DailyReportService] ids array is not in stream order; re-sorting (check SQL ORDER BY vs compareIdsStreamOrder, or concurrent row movement during the scan)"),[...C].sort(Qe))},onFetchStart:b,forceRefresh:o,snapshot:u,ttlMsOverride:h??Dt,epochKey:w,refreshAheadRatio:.5})},nt=(n,a,{forceRefresh:o=!1,snapshot:u=!1,ttlMsOverride:h}={})=>{let b=ue(a);return b?ve(n.visible)?Promise.resolve([]):p.getOrFetch({cacheKey:`${Q(b)}:st:${Ke(n)}`,fetcher:()=>te(n,b),forceRefresh:o,snapshot:u,ttlMsOverride:h??k}):Promise.resolve([])},ge=null,Ye=async()=>(ge!==null||(ge=(await e.select({id:V.id}).from(V).where(we(V.name,He)).orderBy(V.id)).map(a=>a.id)),ge),Te=async()=>{let n=await Ye();return n.length>0?n:[-1]},at=async()=>{let n=await Ye();if(n.length===0)return null;let[a]=await e.select({id:V.id}).top(1).from(V).where(f(V.name,Oe));return a?.id??n[0]},Jt=(n,a)=>a!=null?"absent":n!=null?"present":"unknown",je=async n=>{let a=new Map,o=r.attachment,u=t.attachmentIdCodec;if(n.length===0||!o||!u)return a;let h=await e.select({id:o.id,hubId:o.hubId,fileName:o.fileName,fileType:o.fileType,fileSize:o.fileSize,createdAt:o.createdAt,objectCheckedAt:o.objectCheckedAt,objectMissingAt:o.objectMissingAt}).from(o).where(we(o.hubId,n)).orderBy(tt(o.createdAt),tt(o.id));for(let b of h){let g={id:u.encode(Number(b.id)),fileName:String(b.fileName),fileType:b.fileType?String(b.fileType):null,fileSize:b.fileSize!=null?Number(b.fileSize):null,createdAt:de(b.createdAt,"YYYY-MM-DD HH:mm:ss"),state:Jt(b.objectCheckedAt,b.objectMissingAt)},I=a.get(Number(b.hubId));I?I.push(g):a.set(Number(b.hubId),[g])}return a},Gt=async(n,a,o)=>{let u=r.attachment;if(!u||ve(n.visible))return null;let h=await Te(),b=$e(K,"draft_label");return(await e.select({fileName:u.fileName,filePath:u.filePath,fileType:u.fileType,fileSize:u.fileSize}).top(1).from(u).innerJoin(i,f(i.id,u.hubId)).leftJoin(b,G(f(b.hubId,i.id),we(b.labelId,h))).where(G(f(u.id,a),ce(i.deletedAt),Ue(f(i.userId,o),ce(b.hubId)),A(n.visible))))[0]??null},Qt=async n=>{let a=r.attachment;if(!a)return;let o=new Date;try{await e.update(a).set({objectCheckedAt:o,objectMissingAt:o,updatedAt:o}).where(f(a.id,n))}catch(u){ne.error("markAttachmentMissing failed",u)}},Xt=async n=>{let a=r.attachment;if(!a)return;let o=new Date;try{await e.update(a).set({objectCheckedAt:o,objectMissingAt:null,updatedAt:o}).where(f(a.id,n))}catch(u){ne.error("markAttachmentPresent failed",u)}},Wt=async(n,a,o,{forceRefresh:u=!1,snapshot:h=!1,ttlMsOverride:b}={})=>{let g=await J(o);if(!g)return[];let I=ue(a);if(!I)return[];if(ve(n.visible))return[];let C=L(I,g,Ke(n));return p.getOrFetch({cacheKey:C,fetcher:async()=>{let X=await Te(),j=$e(K,"draft_label"),Z=await ee(e.select({hub:xe(i),internal:xe(O),isRead:Y.isRead,isStarred:Y.isStarred,creatorName:s.displayName,...H()}).from(i)).leftJoin(O,f(i.id,O.hubId)).leftJoin(Y,G(f(i.id,Y.hubId),f(Y.userId,g))).leftJoin(j,G(f(j.hubId,i.id),we(j.labelId,X))).leftJoin(s,f(i.userId,s.id)).where(G(f(i.businessDate,qt`${I}`),ce(i.deletedAt),Ue(f(i.userId,g),ce(j.hubId)),A(n.visible))).orderBy(Be(i.id));if(Z.length===0)return[];let oe=Z.map(W=>W.hub.id),Me=await e.select({hubId:K.hubId,id:V.id,name:V.name,color:V.color}).from(K).innerJoin(V,f(K.labelId,V.id)).where(we(K.hubId,oe)),Ce=await e.select({hubId:m.hubId,id:m.id,body:m.body,createdAt:m.createdAt,userId:m.userId,userName:s.displayName}).from(m).leftJoin(s,f(m.userId,s.id)).where(we(m.hubId,oe)).orderBy(tt(m.createdAt)),Ne=await je(oe),Ae=new Map,ie=new Map;for(let W of Me){let le=Ae.get(W.hubId);le||(le=[],Ae.set(W.hubId,le)),le.push({id:W.id,name:W.name,color:W.color})}for(let W of Ce){let le=ie.get(W.hubId);le||(le=[],ie.set(W.hubId,le)),le.push({id:W.id,content:W.body,createdAt:de(W.createdAt,"YYYY-MM-DD HH:mm:ss")||"",userId:W.userId,userName:W.userName||""})}return Z.map(W=>{let le=W.hub.id;return be(n,{...W,attachments:Ne.get(le)??[],labels:Ae.get(le)||[],postedCommentRows:ie.get(le)||[]},g)})},forceRefresh:u,snapshot:h,ttlMsOverride:b??k,epochKey:`${T}${I}`})},Fe=async(n,a,o,{forceRefresh:u=!1,snapshot:h=!1,ttlMsOverride:b}={})=>{if(ve(n.visible))return null;let g=E(a,o,Ke(n));return(await p.getOrFetch({cacheKey:g,fetcher:async()=>{let C=await Te(),X=$e(K,"draft_label"),j=await ee(e.select({hub:xe(i),internal:xe(O),isRead:Y.isRead,isStarred:Y.isStarred,creatorName:s.displayName,...H()}).from(i)).leftJoin(O,f(i.id,O.hubId)).leftJoin(Y,G(f(i.id,Y.hubId),f(Y.userId,o))).leftJoin(X,G(f(X.hubId,i.id),we(X.labelId,C))).leftJoin(s,f(i.userId,s.id)).where(G(f(i.id,a),ce(i.deletedAt),Ue(f(i.userId,o),ce(X.hubId)),A(n.visible)));if(j.length===0)return[];let Z=j[0].hub.id,oe=await e.select({id:V.id,name:V.name,color:V.color}).from(K).innerJoin(V,f(K.labelId,V.id)).where(f(K.hubId,Z)),Me=await e.select({id:m.id,body:m.body,createdAt:m.createdAt,userId:m.userId,userName:s.displayName}).from(m).leftJoin(s,f(m.userId,s.id)).where(f(m.hubId,Z)).orderBy(tt(m.createdAt)),Ce=await je([Z]),Ne=oe.map(ie=>({id:ie.id,name:ie.name,color:ie.color})),Ae=Me.map(ie=>({id:ie.id,content:ie.body,createdAt:de(ie.createdAt,"YYYY-MM-DD HH:mm:ss")||"",userId:ie.userId,userName:ie.userName||""}));return[be(n,{...j[0],attachments:Ce.get(Z)??[],labels:Ne,postedCommentRows:Ae},o)]},forceRefresh:u,snapshot:h,ttlMsOverride:b??k,epochKey:`${y}${a}`}))[0]??null},Zt=async(n,a,o,u={})=>{let h=await J(o);return h?Fe(n,a,h,u):null},er=async(n,a)=>{let o=await Te(),u=$e(K,"draft_label"),[h]=await e.select({sourceType:i.sourceType,deletedAt:i.deletedAt}).top(1).from(i).leftJoin(u,G(f(u.hubId,i.id),we(u.labelId,o))).where(G(f(i.id,n),Ue(f(i.userId,a),ce(u.hubId))));return h??null},st=async(n,a,o)=>{let u=await er(a,o);if(!u||u.deletedAt||!Ie(n.visible,u.sourceType))throw new Error("Not Found")},tr=async(n,a,o,u,h,b)=>{await st(n,o,a);let g=await e.select().top(1).from(Y).where(G(f(Y.hubId,o),f(Y.userId,a))),I;if(g.length>0?g[0].isStarred!==h?I=(await e.update(Y).set({isStarred:h,updatedAt:new Date,updatedBy:String(a)}).output().where(G(f(Y.hubId,o),f(Y.userId,a))))[0]:I=g[0]:I=(await e.insert(Y).output().values({hubId:o,userId:a,isStarred:h,isRead:!1,createdAt:new Date,createdBy:String(a),updatedAt:new Date,updatedBy:String(a)}))[0],u){let C=ue(u);C&&(p.invalidatePrefix(M(C,a)),await S(`${T}${C}`))}return p.invalidate(`daily-report:detail:${o}`),p.invalidatePrefix(P(o,a)),await S(`${y}${o}`),await N(Xe.parse({type:"status-update",reportHubId:o,recipientRawUserId:a,statusType:"star",value:h,clientTempId:b}),"setStarStatus"),I},rr=async(n,a,o,u,h,b)=>{await st(n,o,a);let g=await e.select().top(1).from(Y).where(G(f(Y.hubId,o),f(Y.userId,a))),I;if(g.length>0?g[0].isRead!==h?I=(await e.update(Y).set({isRead:h,updatedAt:new Date,updatedBy:String(a)}).output().where(G(f(Y.hubId,o),f(Y.userId,a))))[0]:I=g[0]:I=(await e.insert(Y).output().values({hubId:o,userId:a,isRead:h,isStarred:!1,createdAt:new Date,createdBy:String(a),updatedAt:new Date,updatedBy:String(a)}))[0],u){let C=ue(u);C&&(p.invalidatePrefix(M(C,a)),await S(`${T}${C}`))}return p.invalidate(`daily-report:detail:${o}`),p.invalidatePrefix(P(o,a)),await S(`${y}${o}`),await N(Xe.parse({type:"status-update",reportHubId:o,recipientRawUserId:a,statusType:"read",value:h,clientTempId:b}),"setReadStatus"),I},wt=async(n,a)=>{if(a===null)return;let o=await Te(),[u]=await e.select({hubId:K.hubId}).top(1).from(K).where(G(f(K.hubId,n),we(K.labelId,o)));return u?a:void 0},nr=async(n,a,o,u,h,b)=>{let[g]=await e.select({sourceType:i.sourceType,deletedAt:i.deletedAt,userId:i.userId}).top(1).from(i).where(f(i.id,o));if(!g||g.deletedAt)throw new Error("Not Found");if(await st(n,o,a),!Ie(n.commentable,g.sourceType))throw new Error("Comments are restricted by the viewer's comment permission");if(g.sourceType.toLowerCase()!=="internal")throw new Error("Comments are restricted for external daily report sources");let I=await wt(o,g.userId),[C]=await e.insert(m).output().values({hubId:o,userId:a,body:u,createdAt:new Date,createdBy:String(a),updatedAt:new Date,updatedBy:String(a)}),[X]=await e.select({displayName:s.displayName}).top(1).from(s).where(f(s.id,a)),j=X?.displayName??"Unknown";if(h){let oe=ue(h);oe&&(p.invalidatePrefix(`daily-report:date:${oe}:user:`),await S(`${T}${oe}`))}p.invalidate(`daily-report:detail:${o}`),p.invalidatePrefix(`daily-report:detail:${o}:user:`),await S(`${y}${o}`);let Z={id:C.id,userId:l(C.userId),userName:j,content:C.body,createdAt:de(C.createdAt,"YYYY-MM-DD HH:mm:ss")??"",isMine:!0};return await N(mt.parse({type:"comment-add",reportHubId:o,comment:Z,clientTempId:b,recipientRawUserId:I,sourceType:g.sourceType}),"addComment"),Z},ar=async(n,a)=>await n.select().top(1).from(m).where(f(m.id,a)),sr=async(n,a,o,u,h,b)=>{let g=await ar(e,u);if(g.length===0)throw new Error("Not Found");if(g[0].hubId!==o)throw new Error("Not Found");let[I]=await e.select({userId:i.userId,sourceType:i.sourceType}).top(1).from(i).where(f(i.id,g[0].hubId));if(!(I&&Ie(n.visible,I.sourceType)))throw new Error("Not Found");if(g[0].userId!==a)throw new Error("Unauthorized");let C=await wt(o,I.userId);if(await e.delete(m).where(f(m.id,u)),h){let X=ue(h);X&&(p.invalidatePrefix(`daily-report:date:${X}:user:`),await S(`${T}${X}`))}p.invalidate(`daily-report:detail:${o}`),p.invalidatePrefix(`daily-report:detail:${o}:user:`),await S(`${y}${o}`),await N(yt.parse({type:"comment-delete",reportHubId:o,commentId:u,clientTempId:b,recipientRawUserId:C,sourceType:I?.sourceType}),"deleteComment")},or=async(n,a,o)=>{ne.info("createDailyReport called",{userId:n,businessDate:a});let[u]=await e.select({displayName:s.displayName}).from(s).where(f(s.id,n)),h=u?.displayName??l(n);try{let b=await rt(async C=>{ne.info("Starting transaction");let X=`internal-temp-${Date.now()}-${Math.random()}`,[j]=await C.insert(i).output().values({sourceType:"Internal",sourceId:X,businessDate:new Date(a),userId:n,title:"(\u7121\u984C)",createdAt:new Date,createdBy:String(n),updatedAt:new Date,updatedBy:String(n)});await C.update(i).set({sourceId:String(j.id)}).where(f(i.id,j.id)),ne.info("Hub created",j),await C.insert(O).values({hubId:j.id,body:"",createdAt:new Date,createdBy:String(n),updatedAt:new Date,updatedBy:String(n)}),ne.info("Internal created"),ne.info("Calling getDraftLabelId");let Z=await at();ne.info("draftLabelId",Z);let oe=[];return Z&&(await C.insert(K).values({hubId:j.id,labelId:Z,createdAt:new Date,createdBy:String(n)}),oe.push({id:Z,name:Oe,color:null})),ne.info("Label assigned"),{reportHubId:j.id,date:a,createdAt:de(j.createdAt,"YYYY-MM-DD HH:mm:ss"),author:h,userId:l(n),sourceType:"Internal",employeeName:h,updatedBy:l(n),updatedAt:de(j.updatedAt,"YYYY-MM-DD HH:mm:ss"),category:null,creationCategory:null,visitTimeFrom:null,visitTimeTo:null,customerName:null,interviewers:[],subject:j.title,content:"",externalComments:[],isRead:!0,isStarred:!1,labels:oe,postedComments:[],attachments:[]}}),g=ue(a);g&&p.invalidatePrefix(M(g,n)),p.invalidatePrefix(U),p.invalidatePrefix(he(n)),await S(w),g&&await S(`${T}${g}`);let I=await Fe(De.unrestricted("post-write self read: the writer always sees the row they just wrote"),b.reportHubId,n,{forceRefresh:!0});if(I){let C=await Ye(),X=I.labels.some(j=>C.includes(j.id));await N(ht.parse({type:"report-create",reportHubId:I.reportHubId,report:I,clientTempId:o,recipientRawUserId:X?n:void 0}),"createDailyReport")}return I??b}catch(b){throw ne.error("Error in createDailyReport",b),b}},Je=async(n,a)=>await n.select().top(1).from(i).where(f(i.id,a)),ot=async(n,a,o)=>{await n.update(i).set(o).where(f(i.id,a))},St=async(n,a,o)=>{await n.update(O).set(o).where(f(O.hubId,a))},It=async(n,a,o)=>{await n.delete(K).where(G(f(K.hubId,a),f(K.labelId,o)))};return{streamKey:F,streamMaxLen:_,clearCache:async()=>{p.clearAll(),v.clear(),ge=null,x&&await S(w),ne.info("[DailyReportService] Server-side DB/SQL caches cleared successfully.")},invalidateHubReadCaches:async(n,a)=>{p.invalidatePrefix(U),p.invalidatePrefix(Ee),await S(w);for(let o of new Set(n))p.invalidatePrefix(`daily-report:detail:${o}:user:`),await S(`${y}${o}`);for(let o of new Set(a)){let u=ue(o);u&&await S(`${T}${u}`)}},getUserIdByExternalId:J,getDailyReportIdsByExternalId:me,getDailyReportIdsFirstPageByExternalId:se,getDailyReportsByBusinessDate:nt,getDailyReportsByBusinessDateByExternalId:Wt,getDailyReportDetailById:Fe,getDailyReportDetailByIdByExternalId:Zt,getDraftLabelId:at,getAttachmentsByHubIds:je,getAttachmentForUser:Gt,markAttachmentMissing:Qt,markAttachmentPresent:Xt,setStarStatus:tr,setReadStatus:rr,addComment:nr,deleteComment:sr,createDailyReport:or,updateDailyReport:async(n,a,o,u)=>{let h=await Je(e,n);if(!h.length||h[0].deletedAt)throw new Error("Not Found");if(h[0].userId!==a)throw new Error("Unauthorized");await rt(async I=>{o.title!==void 0&&await ot(I,n,{title:o.title,updatedAt:new Date,updatedBy:String(a)}),o.content!==void 0&&await St(I,n,{body:o.content,updatedAt:new Date,updatedBy:String(a)})}),p.invalidate(`daily-report:detail:${n}`),p.invalidatePrefix(`daily-report:detail:${n}:user:`),p.invalidatePrefix(U),await S(`${y}${n}`);let b=ue(de(h[0].businessDate,"YYYY-MM-DD"));b&&(p.invalidatePrefix(`daily-report:date:${b}:user:`),await S(`${T}${b}`));let g=await Fe(De.unrestricted("post-write self read: the writer always sees the row they just wrote"),n,a,{forceRefresh:!0});if(g){let I=await Ye(),C=g.labels.some(X=>I.includes(X.id));await N(ft.parse({type:"report-update",reportHubId:g.reportHubId,report:g,clientTempId:u,recipientRawUserId:C?a:void 0}),"updateDailyReport")}},publishDailyReport:async(n,a,o)=>{let u=await Je(e,n);if(!u.length)throw new Error("Not Found");if(u[0].userId!==a)throw new Error("Unauthorized");let h=await at();if(!h)return null;if(await It(e,n,h),p.invalidatePrefix(`daily-report:detail:${n}:user:`),p.invalidatePrefix(U),p.invalidatePrefix(Ee),await S(w),u[0].businessDate){let I=ue(de(u[0].businessDate,"YYYY-MM-DD"));I&&await S(`${T}${I}`)}let b=ue(de(u[0].businessDate,"YYYY-MM-DD"));b&&p.invalidatePrefix(M(b,a));let g=await Fe(De.unrestricted("post-write self read: the writer always sees the row they just wrote"),n,a,{forceRefresh:!0});return g&&await N(bt.parse({type:"report-publish",reportHubId:g.reportHubId,report:g,clientTempId:o}),"publishDailyReport"),g??null},deleteDailyReport:async(n,a,o)=>{let u=await Je(e,n);if(!u.length||u[0].deletedAt)throw new Error("Not Found");if(u[0].userId!==a)throw new Error("Unauthorized");if(await ot(e,n,{deletedAt:new Date,deletedBy:String(a),updatedAt:new Date,updatedBy:String(a)}),p.invalidatePrefix(`daily-report:detail:${n}:user:`),p.invalidatePrefix(U),p.invalidatePrefix(Ee),await S(w),u[0].businessDate){let h=ue(de(u[0].businessDate,"YYYY-MM-DD"));h&&await S(`${T}${h}`)}await N(gt.parse({type:"report-delete",reportHubId:n,clientTempId:o,sourceType:u[0].sourceType}),"deleteDailyReport")},findDailyReportHubById:Je,updateDailyReportHub:ot,updateDailyReportInternal:St,deleteDailyReportLabel:It}}import{and as Xr,eq as Vt}from"drizzle-orm";function Wr(t){let e=[],r=t&&t.length>0?t:[{key:"internal",name:"Internal",description:"Internal daily reports"},{key:"external",name:"External",description:"External daily reports"}];for(let s of r){let l=`daily_report_${s.key.toLowerCase().replace(/[^a-z0-9_]/g,"_")}`;e.push({resourceKey:l,name:s.name,description:s.description??`${s.name} daily report access`}),s.includeCommentResource!==!1&&e.push({resourceKey:`${l}_comment`,name:`${s.name} Comment`,description:`${s.name} daily report comment access`})}return e}async function Kn(t,e,r){let s=t,d=e.TMResource,l=r.appKey,R=r.actor??"system:daily-report",p=new Date,x=r.resources??Wr(r.sources);for(let i of x){let O=await s.select().from(d).where(Xr(Vt(d.appKey,l),Vt(d.resourceKey,i.resourceKey)));(!O||O.length===0)&&await s.insert(d).values({appKey:l,resourceKey:i.resourceKey,name:i.name,description:i.description??null,createdAt:p,createdBy:R,updatedAt:p,updatedBy:R})}}var Zr=ye(1,"[DailyReportExternalSource]"),Gn=(t,e,r,s=Zr)=>{if(!t)return[];try{let d=JSON.parse(t);return Array.isArray(d)?d.map(r).filter(l=>l!==null):(s.warn(`Unexpected ${e} format: not an array`),[])}catch(d){return s.warn(`Failed to parse ${e}:`,d),[]}};import{desc as Kt,sql as en}from"drizzle-orm";import{bigint as re,bit as jt,date as tn,datetime2 as ae,foreignKey as Se,index as _e,int as rn,mssqlSchema as nn,nvarchar as z,primaryKey as ke,uniqueIndex as an}from"drizzle-orm/mssql-core";function Zn(t,e){let r=nn(t),s=e.userTable,d=r.table("DailyReportHub",{id:re("id",{mode:"number"}).identity().notNull(),sourceType:z("source_type",{length:20}).notNull(),sourceId:z("source_id",{length:100}).notNull(),sourceIdNum:re("source_id_num",{mode:"number"}).generatedAlwaysAs(en`TRY_CAST(source_id AS BIGINT)`),businessDate:tn("business_date"),userId:re("user_id",{mode:"number"}),title:z("title",{length:200}),summary:z("summary",{length:"max"}),createdAt:ae("created_at").notNull(),createdBy:z("created_by",{length:50}).notNull(),updatedAt:ae("updated_at").notNull(),updatedBy:z("updated_by",{length:50}).notNull(),deletedAt:ae("deleted_at"),deletedBy:z("deleted_by",{length:50})},m=>[ke({name:`${t}_DailyReportHub_pk`,columns:[m.id]}),Se({name:`${t}_DailyReportHub_user_id_fk`,columns:[m.userId],foreignColumns:[s.id]}),_e(`${t}_DailyReportHub_business_date_index`).on(m.businessDate),_e(`${t}_DailyReportHub_updated_at_index`).on(m.updatedAt),_e(`${t}_DailyReportHub_source_index`).on(m.sourceType,m.sourceId),_e(`${t}_DailyReportHub_user_id_index`).on(m.userId),_e(`${t}_DailyReportHub_business_date_id_index`).on(Kt(m.businessDate),Kt(m.id)),_e(`${t}_DailyReportHub_deleted_at_index`).on(m.deletedAt)]),l=r.table("DailyReportInternal",{hubId:re("hub_id",{mode:"number"}).notNull(),body:z("body",{length:"max"}),metadata:z("metadata",{length:"max"}),createdAt:ae("created_at").notNull(),createdBy:z("created_by",{length:50}).notNull(),updatedAt:ae("updated_at").notNull(),updatedBy:z("updated_by",{length:50}).notNull()},m=>[ke({name:`${t}_DailyReportInternal_pk`,columns:[m.hubId]}),Se({name:`${t}_DailyReportInternal_hub_id_fk`,columns:[m.hubId],foreignColumns:[d.id]})]),R=r.table("DailyReportComment",{id:re("id",{mode:"number"}).identity().notNull(),hubId:re("hub_id",{mode:"number"}).notNull(),userId:re("user_id",{mode:"number"}).notNull(),body:z("body",{length:"max"}).notNull(),createdAt:ae("created_at").notNull(),createdBy:z("created_by",{length:50}).notNull(),updatedAt:ae("updated_at").notNull(),updatedBy:z("updated_by",{length:50}).notNull()},m=>[ke({name:`${t}_DailyReportComment_pk`,columns:[m.id]}),Se({name:`${t}_DailyReportComment_hub_id_fk`,columns:[m.hubId],foreignColumns:[d.id]}),Se({name:`${t}_DailyReportComment_user_id_fk`,columns:[m.userId],foreignColumns:[s.id]}),_e(`${t}_DailyReportComment_hub_id_index`).on(m.hubId)]),p=r.table("DailyReportLabel",{id:re("id",{mode:"number"}).identity().notNull(),userId:re("user_id",{mode:"number"}),name:z("name",{length:50}).notNull(),color:z("color",{length:20}),sortOrder:rn("sort_order"),createdAt:ae("created_at").notNull(),createdBy:z("created_by",{length:50}).notNull(),updatedAt:ae("updated_at").notNull(),updatedBy:z("updated_by",{length:50}).notNull()},m=>[ke({name:`${t}_DailyReportLabel_pk`,columns:[m.id]}),Se({name:`${t}_DailyReportLabel_user_id_fk`,columns:[m.userId],foreignColumns:[s.id]})]),x=r.table("DailyReportHub_Label",{hubId:re("hub_id",{mode:"number"}).notNull(),labelId:re("label_id",{mode:"number"}).notNull(),createdAt:ae("created_at").notNull(),createdBy:z("created_by",{length:50}).notNull()},m=>[ke({name:`${t}_DailyReportHub_Label_pk`,columns:[m.hubId,m.labelId]}),Se({name:`${t}_DailyReportHub_Label_hub_id_fk`,columns:[m.hubId],foreignColumns:[d.id]}),Se({name:`${t}_DailyReportHub_Label_label_id_fk`,columns:[m.labelId],foreignColumns:[p.id]})]),i=r.table("DailyReportUserStatus",{hubId:re("hub_id",{mode:"number"}).notNull(),userId:re("user_id",{mode:"number"}).notNull(),isRead:jt("is_read").default(!1).notNull(),isStarred:jt("is_starred").default(!1).notNull(),createdAt:ae("created_at").notNull(),createdBy:z("created_by",{length:50}).notNull(),updatedAt:ae("updated_at").notNull(),updatedBy:z("updated_by",{length:50}).notNull()},m=>[ke({name:`${t}_DailyReportUserStatus_pk`,columns:[m.hubId,m.userId]}),Se({name:`${t}_DailyReportUserStatus_hub_id_fk`,columns:[m.hubId],foreignColumns:[d.id]}),Se({name:`${t}_DailyReportUserStatus_user_id_fk`,columns:[m.userId],foreignColumns:[s.id]})]),O=r.table("DailyReportAttachment",{id:re("id",{mode:"number"}).identity().notNull(),hubId:re("hub_id",{mode:"number"}).notNull(),uploadedBy:re("uploaded_by",{mode:"number"}),sourceKey:z("source_key",{length:200}).notNull(),fileName:z("file_name",{length:255}).notNull(),filePath:z("file_path",{length:"max"}).notNull(),fileType:z("file_type",{length:100}),fileSize:re("file_size",{mode:"number"}),objectCheckedAt:ae("object_checked_at"),objectMissingAt:ae("object_missing_at"),createdAt:ae("created_at").notNull(),createdBy:z("created_by",{length:50}).notNull(),updatedAt:ae("updated_at").notNull(),updatedBy:z("updated_by",{length:50}).notNull()},m=>[ke({name:`${t}_DailyReportAttachment_pk`,columns:[m.id]}),Se({name:`${t}_DailyReportAttachment_hub_id_fk`,columns:[m.hubId],foreignColumns:[d.id]}),Se({name:`${t}_DailyReportAttachment_uploaded_by_fk`,columns:[m.uploadedBy],foreignColumns:[s.id]}),an(`${t}_DailyReportAttachment_source_unique`).on(m.hubId,m.sourceKey),_e(`${t}_DailyReportAttachment_hub_id_index`).on(m.hubId,m.createdAt)]);return{hub:d,internal:l,comment:R,attachment:O,label:p,hubLabel:x,userStatus:i}}function sa(t){t.redis||(t.logger??console).warn("[DailyReport] redis provider is not injected: cross-worker cache invalidation is disabled (staleness is bounded only by TTL) and SSE publishing is skipped.");let e=Ct(t.redis),r=new Ge({defaultTtlMs:t.cacheDefaultTtlMs??6e4},e),s=zt({...t,cache:r,epochs:e}),d=new Ze({redis:t.redis,streamKey:s.streamKey,cache:r,logger:t.logger}),l=Ft({authenticate:t.authenticate,resolveVisibleSourceTypes:t.resolveVisibleSourceTypes,service:s,encodeUserId:t.encodeUserId,attachmentIdCodec:t.attachmentIdCodec,readAttachment:t.readAttachment,attachmentMaxBytes:t.attachmentMaxBytes,attachmentRateLimitPerMinute:t.attachmentRateLimitPerMinute,attachmentConcurrency:t.attachmentConcurrency,redis:t.redis,sseReader:d,streamKey:s.streamKey,loginRedirectPath:t.loginRedirectPath,enableDevCacheClear:t.enableDevCacheClear,logger:t.logger});return{service:s,cache:r,epochs:e,sseReader:d,streamKey:s.streamKey,knownSourceTypes:[...new Set(["Internal",...(t.externalSources??[]).map(R=>R.sourceType)])],...l}}export{Ze as DailyReportSseReader,De as DailyReportViewerScope,Ge as SqlResultCache,Or as asciiFallbackFileName,$t as buildVisibleSourceTypeCondition,Pt as computeSourceTypeDigest,Ke as computeViewerScopeDigest,Ft as createDailyReportHandlers,sa as createDailyReportServer,zt as createDailyReportService,Ct as createEpochStore,Wr as defineDailyReportAuthzResources,Zn as defineDailyReportSchema,ve as deniesEverySourceType,Hr as encodeRfc8187,de as formatDateValue,Rt as generateETag,Ie as isSourceTypeVisible,ze as isStreamIdLte,Re as jsonResponseWithETag,Lt as normalizeVisibleSourceTypes,Ot as sanitizeMediaType,Kn as seedDailyReportAuthzResources,Gn as transformJsonArray};
16
- //# sourceMappingURL=server.mjs.map