@agile-team/mach-report 2.11.1 → 2.12.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.
Files changed (73) hide show
  1. package/README.md +15 -6
  2. package/THIRD_PARTY_NOTICES.md +270 -0
  3. package/dist/{ExcelBindingWizard-LWX6G1A2.js → ExcelBindingWizard-CeAf4QSE.js} +2 -2
  4. package/dist/{ExcelBindingWizard-a4kslPHF.cjs → ExcelBindingWizard-y0mT-AHR.cjs} +1 -1
  5. package/dist/{RuleEditor-C2QsOHOs.cjs → RuleEditor-ChRzNQuF.cjs} +1 -1
  6. package/dist/{RuleEditor-D9wQHrkf.js → RuleEditor-DzAmW5YH.js} +1 -1
  7. package/dist/analytics.d.cts +28 -0
  8. package/dist/analytics.d.ts +28 -0
  9. package/dist/assets-C2U-e-Sz.cjs +4 -0
  10. package/dist/assets-Q0wUwNrV.js +217 -0
  11. package/dist/code-options-BKXXY7NI.js +18 -0
  12. package/dist/code-options-BUTChiZZ.cjs +1 -0
  13. package/dist/codes.cjs +9 -0
  14. package/dist/codes.d.cts +223 -0
  15. package/dist/codes.d.ts +223 -0
  16. package/dist/codes.js +26917 -0
  17. package/dist/designer.cjs +2 -2
  18. package/dist/designer.d.cts +267 -0
  19. package/dist/designer.d.ts +267 -0
  20. package/dist/designer.js +2737 -1941
  21. package/dist/grid-strokes-Cr7DwUux.cjs +1 -0
  22. package/dist/grid-strokes-DyyG1q_o.js +53 -0
  23. package/dist/index.cjs +7 -7
  24. package/dist/index.d.cts +80 -1
  25. package/dist/index.d.ts +80 -1
  26. package/dist/index.js +404 -374
  27. package/dist/pdf.cjs +76 -59
  28. package/dist/pdf.d.cts +51 -0
  29. package/dist/pdf.d.ts +51 -0
  30. package/dist/pdf.js +32193 -32102
  31. package/dist/record-bindings-By_UKZ2g.cjs +1 -0
  32. package/dist/{list-cell-ClFra1zS.js → record-bindings-D-5jQlTj.js} +67 -44
  33. package/dist/{region-binding-workflow-DhQvu1co.cjs → region-binding-workflow-BzfbxRiR.cjs} +1 -1
  34. package/dist/{region-binding-workflow-CXDmt9Bs.js → region-binding-workflow-CcUq8W2Q.js} +1 -1
  35. package/dist/server/node.d.cts +52 -1
  36. package/dist/server/node.d.ts +52 -1
  37. package/dist/server-node.cjs +1 -1
  38. package/dist/server-node.js +239 -210
  39. package/dist/server.cjs +1 -1
  40. package/dist/server.d.cts +95 -3
  41. package/dist/server.d.ts +95 -3
  42. package/dist/server.js +456 -433
  43. package/dist/style.css +1 -1
  44. package/dist/{template-registry-WNXdkiET.js → template-registry-BjE1VS6g.js} +221 -157
  45. package/dist/template-registry-D3SjENi6.cjs +1 -0
  46. package/dist/template-review-BfCC8Ng9.cjs +2 -0
  47. package/dist/{template-review-BdcXSYbx.js → template-review-BzpcI-tR.js} +772 -666
  48. package/dist/validate-BJ5HIWY8.cjs +1 -0
  49. package/dist/validate-DbgEM1Hh.js +163 -0
  50. package/dist/vue/async.d.cts +121 -2
  51. package/dist/vue/async.d.ts +121 -2
  52. package/dist/vue/index.d.cts +114 -6
  53. package/dist/vue/index.d.ts +114 -6
  54. package/dist/{workbook-session-BKOTwcoq.js → workbook-session-BPb3TMnT.js} +1 -1
  55. package/dist/{workbook-session-CLYLhZWu.cjs → workbook-session-DNa2RHNG.cjs} +1 -1
  56. package/dist/worker.cjs +1 -1
  57. package/dist/worker.d.cts +52 -1
  58. package/dist/worker.d.ts +52 -1
  59. package/dist/worker.js +2 -2
  60. package/dist/xlsx.cjs +1 -1
  61. package/dist/xlsx.d.cts +40 -0
  62. package/dist/xlsx.d.ts +40 -0
  63. package/dist/xlsx.js +3 -3
  64. package/package.json +16 -3
  65. package/dist/assets-Bu6UohJx.cjs +0 -1
  66. package/dist/assets-DegqDNqY.js +0 -160
  67. package/dist/list-cell-BuYn4tGF.cjs +0 -1
  68. package/dist/template-registry-ukBGlm8N.cjs +0 -1
  69. package/dist/template-review-BXp2oyqg.cjs +0 -1
  70. package/dist/textwrap-CWHyzkBH.cjs +0 -4
  71. package/dist/textwrap-DE1kgcJB.js +0 -110
  72. package/dist/validate-7s0yn6ii.js +0 -148
  73. package/dist/validate-DsRiNw8h.cjs +0 -1
package/dist/server.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var te=Object.create;var C=Object.defineProperty;var re=Object.getOwnPropertyDescriptor;var se=Object.getOwnPropertyNames;var ne=Object.getPrototypeOf,oe=Object.prototype.hasOwnProperty;var ae=(e,t,s,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of se(t))!oe.call(e,r)&&r!==s&&C(e,r,{get:()=>t[r],enumerable:!(o=re(t,r))||o.enumerable});return e};var z=(e,t,s)=>(s=e!=null?te(ne(e)):{},ae(t||!e||!e.__esModule?C(s,"default",{value:e,enumerable:!0}):s,e));Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const x=require("./template-review-BXp2oyqg.cjs"),M=require("./report-params-SJfhKgaX.cjs"),O=require("./param-validation-DCK039V1.cjs"),a=require("./batch-Bt3Fd27Z.cjs"),H=require("./validate-DsRiNw8h.cjs"),S=require("./task-events-DQ276fn2.cjs"),ie=require("./tree-BX380Rr7.cjs"),ce=require("./template-registry-ukBGlm8N.cjs");function X(e,t){if(t.length===0)throw new x.ReportSourceError("config","缺少报表 ID");return t.map(s=>{if(!Object.prototype.hasOwnProperty.call(e,s))throw new x.ReportSourceError("config",`未注册报表 ${s}`);return e[s]})}function B(e){return e.grid?.cells.reduce((t,s)=>t+s.reduce((o,r)=>o+(r?1+(r.children?.reduce((n,c)=>n+B(c),0)??0):0),0),0)??0}function le(e,t,s){return e.pages.reduce((o,r)=>o+r.components.reduce((n,c)=>c.kind!=="list"?n+B(c):n+x.estimateListLayoutCells(c,t,s),0),0)}function ue(e,t=Object.keys(e)){return X(e,t).map((s,o)=>{const r=t[o],n=M.getReportParamDefs(e,[r]);return{id:r,params:JSON.parse(JSON.stringify(n)),paramsSchema:O.reportParamsJsonSchema(n),datasetsSchema:Object.fromEntries(Object.entries(s.dataSchema??{}).map(([c,u])=>[c,x.templateDatasetJsonSchema(typeof s.template=="function"?void 0:s.template,c,u)])),capabilities:{save:!!s.provider?.save,export:!!s.provider?.export,templates:!!s.provider?.templates}}})}function G(e,t){X(e,t.reportIds);const s=O.validateReportParams(M.getReportParamDefs(e,t.reportIds),t.params),o=t.reportIds.flatMap(n=>O.validateReportParams(M.getReportParamDefs(e,[n]),t.params).issues),r=new Map(o.map(n=>[JSON.stringify(n),n]));return{...s,ok:r.size===0,issues:[...r.values()]}}function de(e,t){const s=H.validateRenderPlan(e.plan);if(!s.ok)throw new x.ReportSourceError("validate",`执行器返回无效计划:${s.errors[0]?.path}`);const o=e.plan.pages.length,r=e.plan.pages.reduce((n,c)=>n+c.components.reduce((u,f)=>u+B(f),0),0);return a.assertBudget(t,"maxRows",e.stats.rows),a.assertBudget(t,"maxPages",o),a.assertBudget(t,"maxCells",r),{...e,stats:{...e.stats,pages:o,cells:r}}}function $(e,t){const s=G(e.reports,t);if(!s.ok)throw new O.ReportParamValidationError(s.issues)}function L(e=[]){return e.map(({code:t,message:s,severity:o,pageIndex:r,componentIndex:n})=>({code:t,message:s,severity:o,path:`$.pages.${r}.components.${n}`}))}function K(e){const t={maxRows:1e5,maxPages:1e4,maxCells:2e6,maxOutputBytes:1e8,maxDurationMs:12e4,...e.budget};a.validateBudget(t);const s=async(r,n)=>{const c=Date.now();let u=0,f=0;const i=[],d={},l=Object.fromEntries(Object.entries(e.reports).map(([g,w])=>[g,{...w,pagination:{...e.pagination,...w.pagination,...n?{measurer:n}:{}},dataValidation:{...w.dataValidation,maxRows:Math.min(t.maxRows??1e5,w.dataValidation?.maxRows??1/0),maxCells:Math.min(t.maxCells??2e6,w.dataValidation?.maxCells??1/0)}}])),h=await x.createReportSource(l,{maxPages:t.maxPages,maxCells:t.maxCells,onDatasets:(g,w,b)=>{try{u+=x.templateDatasetRowCount(b,w,{maxRows:t.maxRows,signal:r.signal})}catch(R){throw R instanceof ie.TreeRowLimitError?new a.ReportRuntimeError("budget",R.message,"$.budget.maxRows"):R}a.assertBudget(t,"maxRows",u),f+=le(b,w,l[g]?.pagination),a.assertBudget(t,"maxCells",f)}})({...r,params:r.params??{},onWarning:g=>i.push({code:"layout",message:g,severity:"warning"}),onQueryResult:(g,w)=>{Object.defineProperty(d,g,{value:{revision:w.revision,sourceToken:w.sourceToken},enumerable:!0,writable:!0}),i.push(...w.diagnostics??[])}}).catch(g=>{throw g instanceof x.ReportSourceError&&g.cause instanceof x.PaginatePageLimitError?new a.ReportRuntimeError("budget",g.cause.message,"$.budget.maxPages"):g instanceof x.ReportSourceError&&g.cause instanceof x.PaginateCellLimitError?new a.ReportRuntimeError("budget",g.cause.message,"$.budget.maxCells"):g});a.throwIfAborted(r.signal);const y=h.pages.reduce((g,w)=>g+w.components.reduce((b,R)=>b+B(R),0),0);return a.assertBudget(t,"maxPages",h.pages.length),a.assertBudget(t,"maxCells",y),{plan:h,diagnostics:i,revisions:d,stats:{rows:u,pages:h.pages.length,cells:y,durationMs:Date.now()-c}}},o=async r=>{const n=Date.now();if(r.format!=="pdf"&&r.format!=="xlsx")throw new x.ReportSourceError("config","不支持的报表导出格式");const c=r.format==="pdf"?await import("@agile-team/mach-report/pdf"):void 0;a.throwIfAborted(r.signal);const u=r.pdf?.customFontFaces??(r.pdf?.customFontBytes?{regular:r.pdf.customFontBytes}:void 0),f=c&&u?c.createFontBytesMeasurer(u):void 0,i=await s(r,f);a.throwIfAborted(r.signal);const d=S.createReportTaskReporter(r),l=await d.run("encode",async()=>{let y;if(r.format==="pdf"){a.throwIfAborted(r.signal);const g=await c.renderPlanToPdf(i.plan,{...r.pdf,...f?{measurer:f}:{},fidelity:r.fidelity,signal:r.signal,onProgress:(w,b)=>d.progress("encode",w,b)});y=g.bytes,i.diagnostics.push(...L(g.diagnostics)),i.diagnostics.push(...g.fidelityWarnings.map(w=>({code:"pdf-fidelity",message:w,severity:"warning"})),...g.pageErrors.map(w=>({code:"pdf-page",message:w,severity:"error"}))),g.unsupportedTextCount&&i.diagnostics.push({code:"pdf-font",message:`${g.unsupportedTextCount} 段文本包含当前字体不支持的字符`,severity:"warning"})}else{const{renderPlanToXlsx:g}=await import("@agile-team/mach-report/xlsx");a.throwIfAborted(r.signal);const w=await g(i.plan,{...r.xlsx,fidelity:r.fidelity,signal:r.signal,onProgress:(b,R)=>d.progress("encode",b,R)});y=new Uint8Array(w.buffer),i.diagnostics.push(...L(w.diagnostics)),i.diagnostics.push(...w.warnings.map(b=>({code:"xlsx-fidelity",message:b,severity:"warning"})))}return a.throwIfAborted(r.signal),y});a.assertBudget(t,"maxOutputBytes",l.byteLength);const{plan:p,...h}=i;return{...h,bytes:l,format:r.format,contentType:r.format==="pdf"?"application/pdf":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",stats:{...h.stats,durationMs:Date.now()-n,outputBytes:l.byteLength}}};return{describe:r=>ue(e.reports,r),validate:r=>G(e.reports,r),prepare:r=>a.controlled(r.signal,t.maxDurationMs,async n=>{const{signal:c,onEvent:u,...f}=r,i={...f,taskId:f.taskId??S.reportTaskId()},d=u?h=>S.notifyReportTaskEvent(u,h,n):void 0,l={...i,signal:n,onEvent:d};S.createReportTaskReporter(l).runSync("validate",()=>$(e,i));const p=e.executor?await e.executor.prepare(i,n,d):await s(l);return de(p,t)}),export:r=>a.controlled(r.signal,t.maxDurationMs,async n=>{const{signal:c,onEvent:u,...f}=r,i={...f,taskId:f.taskId??S.reportTaskId()},d=u?h=>S.notifyReportTaskEvent(u,h,n):void 0,l={...i,signal:n,onEvent:d};if(S.createReportTaskReporter(l).runSync("validate",()=>$(e,i)),i.format!=="pdf"&&i.format!=="xlsx")throw new x.ReportSourceError("config","不支持的报表导出格式");const p=e.executor?await e.executor.export(i,n,d):await o(l);return a.assertBudget(t,"maxRows",p.stats.rows),a.assertBudget(t,"maxPages",p.stats.pages),a.assertBudget(t,"maxCells",p.stats.cells),a.assertBudget(t,"maxOutputBytes",p.bytes.byteLength),{...p,stats:{...p.stats,outputBytes:p.bytes.byteLength}}})}}function pe(e={}){const t=e.concurrency??1,s=e.maxQueued??20;if(!Number.isSafeInteger(t)||t<1||!Number.isSafeInteger(s)||s<0)throw new a.ReportRuntimeError("budget","队列并发应为正整数,排队上限应为非负整数");const o=[],r=new Set,n=new Set;let c=!1,u=0;const f=()=>{for(;!c&&r.size<t&&o.length;)o.shift().start()};return{get active(){return r.size},get pending(){return o.length},enqueue:(d,l={})=>{if(c)throw new a.ReportRuntimeError("closed","任务队列已关闭");if(a.throwIfAborted(l.signal),r.size>=t&&o.length>=s)throw new a.ReportRuntimeError("queue-full","报表任务队列已满");const p=l.id??`report-${++u}`;if(n.has(p))throw new a.ReportRuntimeError("queue-full","任务 ID 正在执行或排队");const h=new AbortController;let y="queued",g,w,b,R;const Y=new Promise((v,I)=>{b=v,R=I}),q=()=>{l.signal?.removeEventListener("abort",D),n.delete(p)},P=v=>{if(y!=="queued"&&y!=="running")return;const I=y==="queued";y="cancelled",h.abort(v);try{a.throwIfAborted(h.signal)}catch(k){R(k)}if(I){const k=o.indexOf(E);k>=0&&o.splice(k,1),q(),f()}},D=()=>P(l.signal?.reason),T=(v,I)=>{y==="running"&&(!Number.isFinite(v)||v<0||I!==void 0&&(!Number.isFinite(I)||I<v)||(g={completed:v,...I===void 0?{}:{total:I}}))},ee=v=>{y!=="running"||h.signal.aborted||(w={...v,taskId:p},v.completed!==void 0&&T(v.completed,v.total),S.notifyReportTaskEvent(l.onEvent,w,h.signal))},E={cancel:P,start:()=>{y==="queued"&&(y="running",r.add(E),Promise.resolve().then(()=>(a.throwIfAborted(h.signal),d({taskId:p,signal:h.signal,reportProgress:T,onEvent:ee}))).then(v=>{y==="running"&&(y="completed",b(v))},v=>{y==="running"&&(y="failed",R(v))}).finally(()=>{r.delete(E),q(),f()}))}};return n.add(p),l.signal?.addEventListener("abort",D,{once:!0}),l.signal?.aborted?P(l.signal.reason):r.size<t?E.start():o.push(E),{id:p,get status(){return y},get progress(){return g},get event(){return w},result:Y,cancel:P}},close:(d={})=>{c=!0;for(const l of[...o])l.cancel(new a.ReportRuntimeError("closed","任务队列已关闭"));if(d.cancelRunning)for(const l of r)l.cancel(new a.ReportRuntimeError("closed","任务队列已关闭"))}}}function fe(e){let t,s;const o=new Promise((r,n)=>{t=r,s=n});return o.catch(()=>{}),{progress:e,promise:o,resolve:t,reject:s}}function F(e){const t=Promise.reject(e);return t.catch(()=>{}),t}function we(e,t){let s,o,r=!0,n;function c(i){n??=i??new Error("任务心跳更新失败"),o?.reject(n),o=void 0,t(n)}function u(i){const d=Promise.resolve().then(()=>e(i?.progress)).then(()=>i?.resolve(),l=>{i?.reject(l),c(l)}).finally(()=>{s=void 0;const l=o;o=void 0,l&&n===void 0&&u(l)});s=d,d.catch(l=>{c(l)})}function f(i){if(!r)return F(new a.ReportJobError("closed","任务进度上报已结束"));if(n!==void 0)return F(n);o?o.progress=i:o=fe(i);const d=o;return s||(o=void 0,u(d)),d.promise}return{progress:f,pulse(){r&&!s&&n===void 0&&u()},async finish(){for(r=!1;s;)await s;if(n!==void 0)throw n}}}class _ extends a.ReportJobError{constructor(){super("capacity","任务结果超过独立预算,请保存文件引用")}}function ge(e){const t=e.concurrency??1,s=e.leaseMs??3e4,o=e.heartbeatMs??1e4,r=e.maxResultBytes??256*1024;if(![t,s,o,r].every(c=>Number.isSafeInteger(c)&&c>0)||o*2>s)throw new a.ReportJobError("input","并发、租约、心跳应为正整数,租约至少为心跳的两倍");if(o>2147483647)throw new a.ReportJobError("input","心跳间隔超过平台定时器上限(2147483647毫秒)");return{concurrency:t,leaseMs:s,heartbeatMs:o,maxResultBytes:r,now:()=>{const c=(e.now??Date.now)();if(!Number.isSafeInteger(c)||c<0)throw new a.ReportJobError("input","任务时钟应返回非负整数毫秒");return c}}}async function N(e,t,s){a.checkJobIdentity(t,s);const o=await e.read(t,s);if(!o)throw new a.ReportJobError("missing","报表任务不存在");return o}async function A(e,t,s,o=[]){const r={...t,...s,revision:t.revision+1};for(const n of o)delete r[n];if(!await e.compareAndSwap(t.scope,t.id,t.revision,r))throw new a.ReportJobError("conflict","报表任务已被其他请求更新");return a.cloneJob(r)}async function me(e,t,s,o){if(!t.trim()||t.length>128)throw new a.ReportJobError("input","workerId应为1–128位标识");for(const r of await e.store.candidates(o,100)){const n=r.cancelRequested?{...r,revision:r.revision+1,status:"cancelled",updatedAt:o}:{...r,revision:r.revision+1,status:"running",attempt:r.attempt+1,updatedAt:o,lease:{owner:t,expiresAt:o+s}};if(n.status==="cancelled"&&delete n.lease,await e.store.compareAndSwap(r.scope,r.id,r.revision,n))return n}}function V(e,t,s,o){return e.status==="running"&&e.attempt===o&&e.lease?.owner===t&&e.lease.expiresAt>s}async function he(e,t,s,o){const{scope:r,id:n}=s,c=s.lease.owner;let u;const f=we(async w=>{const b=await N(e.store,r,n),R=t.now();if(!V(b,c,R,s.attempt))throw new a.ReportJobError("lease","报表任务租约已失效");if(b.cancelRequested){o.abort(new a.ReportJobError("closed","任务已请求取消"));return}await A(e.store,b,{updatedAt:R,lease:{owner:c,expiresAt:R+t.leaseMs},...w?{progress:w}:{}})},w=>{u=w,o.abort(w)}),i=(w,b)=>!Number.isFinite(w)||w<0||b!==void 0&&(!Number.isFinite(b)||b<w)?Promise.reject(new a.ReportJobError("input","任务进度无效")):f.progress({completed:w,...b===void 0?{}:{total:b}}),d=setInterval(()=>{f.pulse()},t.heartbeatMs);let l,p;try{const w=Object.prototype.hasOwnProperty.call(e.handlers,s.request.kind)?e.handlers[s.request.kind]:void 0;if(!w)throw new a.ReportJobError("input","报表任务处理器未注册");if(!o.signal.aborted){const b=await w(a.cloneJob(s.request.payload),{scope:r,taskId:n,signal:o.signal,reportProgress:i});if(l=JSON.parse(a.serializeJobJson(b)),a.jobByteLength(l)>t.maxResultBytes)throw new _}}catch(w){p=w??new Error("报表任务执行失败")}finally{clearInterval(d),await f.finish().catch(()=>{})}const h=await N(e.store,r,n),y=t.now();if(!V(h,c,y,s.attempt))throw new a.ReportJobError("lease","任务租约已失效,迟到结果不会写回");const g={...h,updatedAt:y};delete g.lease,p??=u,h.cancelRequested||o.signal.aborted&&u===void 0?g.status="cancelled":p!==void 0?(g.status="failed",g.error={code:p instanceof _?"result-budget":p instanceof a.ReportJobError?p.code:"execution",message:p instanceof Error?p.message.slice(0,500):"报表任务执行失败"}):(g.status="completed",g.result=l);try{a.serializeJobJson(g)}catch{delete g.result,g.status="failed",g.error={code:"result-budget",message:"任务结果与请求的组合超过存储预算,请保存文件引用而非文件内容"}}return ye(e.store,h,g)}async function ye(e,t,s){try{return await A(e,t,s,["lease"])}catch(o){if(!(o instanceof a.ReportJobError)||o.code!=="capacity"||s.status!=="completed")throw o;return delete s.result,s.status="failed",s.error={code:"result-budget",message:"任务结果超过存储剩余预算,请保存文件引用而非文件内容"},A(e,t,s,["lease","result"])}}async function Q(e,t,s,o){const r=await e.readTombstone?.(t,s);if(r){if(r.requestHash!==await a.jobRequestHash(o))throw new a.ReportJobError("conflict","相同任务ID不能提交不同内容(幂等保留期内)");return{scope:t,id:s,revision:r.revision,request:a.cloneJob(o),status:r.status,createdAt:r.createdAt,updatedAt:r.updatedAt,attempt:r.attempt,archived:!0}}}function be(e){e={...e,handlers:{...e.handlers}};const t=ge(e),s=new Set,o=new Set;let r=!1,n=0;const c=(i,d)=>(a.checkJobIdentity(i,d),e.store.read(i,d));return{submit:async i=>{if(i={...i},a.checkJobIdentity(i.scope,i.id),!Object.prototype.hasOwnProperty.call(e.handlers,i.kind)||typeof e.handlers[i.kind]!="function")throw new a.ReportJobError("input","报表任务处理器未注册");const d={kind:i.kind,payload:JSON.parse(a.serializeJobJson(i.payload,{maxNodes:19e3,maxCharacters:75e4}))},l=await c(i.scope,i.id);if(l){if(a.serializeJobJson(l.request)!==a.serializeJobJson(d))throw new a.ReportJobError("conflict","相同任务ID不能提交不同内容");return l}const p=await Q(e.store,i.scope,i.id,d);if(p)return p;const h=t.now(),y={scope:i.scope,id:i.id,revision:1,request:d,status:"queued",createdAt:h,updatedAt:h,attempt:0};if(!await e.store.compareAndSwap(i.scope,i.id,null,y)){const g=await c(i.scope,i.id);if(g&&a.serializeJobJson(g.request)===a.serializeJobJson(d))return g;const w=await Q(e.store,i.scope,i.id,d);if(w)return w;throw new a.ReportJobError("conflict","报表任务提交发生冲突")}return a.cloneJob(y)},get:c,runNext:i=>{if(r)return Promise.reject(new a.ReportJobError("closed","报表任务服务已关闭"));if(n>=t.concurrency)return Promise.reject(new a.ReportJobError("capacity","报表任务执行槽位已满"));n++;const d=new AbortController;s.add(d);const l=(async()=>{try{const p=await me(e,i,t.leaseMs,t.now());return p?.status==="running"?await he(e,t,p,d):p}finally{n--,s.delete(d)}})();return o.add(l),l.then(()=>o.delete(l),()=>o.delete(l)),l},get active(){return n},cancel:async(i,d)=>{const l=await N(e.store,i,d);return l.status!=="queued"&&l.status!=="running"?l:A(e.store,l,{updatedAt:t.now(),...l.status==="queued"?{status:"cancelled"}:{cancelRequested:!0}})},retry:async(i,d,l)=>{const p=await N(e.store,i,d);if(p.revision!==l||p.status!=="failed")throw new a.ReportJobError("conflict","仅可重试当前修订的失败任务");const h={...p,status:"queued",updatedAt:t.now()};return delete h.error,delete h.progress,A(e.store,p,h,["error","progress"])},prune:async i=>{if(!e.store.prune||!e.store.readTombstone)throw new a.ReportJobError("input","当前任务适配器未实现可选终态保留能力");return e.store.prune({...i,now:t.now()})},close:async()=>{r=!0;for(const i of s)i.abort(new a.ReportJobError("closed","任务服务正在关闭"));await Promise.allSettled([...o])}}}async function ve(e,t,s,o,r){const n=K({reports:{sample:{template:s,datasets:e.datasets}},budget:{maxRows:o.maxSampleRows??1e3,maxPages:o.maxPages??100,maxCells:o.maxCells??25e4,maxOutputBytes:o.maxOutputBytes??2e7,maxDurationMs:o.maxDurationMs??3e4}});try{const{result:c,digest:u}=await a.controlled(o.signal,o.maxDurationMs??3e4,async f=>{const i=await n.export({reportIds:["sample"],params:e.params,format:t,signal:f,fidelity:o.strictOutputs?"strict":"warn",pdf:o.pdf,xlsx:o.xlsx}),d=await o.digest?.(i.bytes);return a.throwIfAborted(f),await o.onArtifact?.(e.name,i),a.throwIfAborted(f),{result:i,digest:d}});r.artifacts.push({fixture:e.name,format:t,bytes:c.bytes.byteLength,pages:c.stats.pages,...u?{digest:u}:{}}),r.issues.push(...c.diagnostics.map(f=>({code:"output",severity:o.strictOutputs||f.severity==="error"?"error":"warning",path:"$.template",fixture:e.name,message:`${t}: ${f.message}`})))}catch(c){a.throwIfAborted(o.signal),r.issues.push({code:"output",severity:"error",path:"$.template",fixture:e.name,message:`${t}: ${c instanceof Error?c.message:String(c)}`})}}async function Re(e,t={}){a.throwIfAborted(t.signal);const s={...x.reviewReportTemplate(e,t),artifacts:[]};if(!s.ok)return s;const o=ce.parseReportTemplate(e).template,r=[...new Set(t.formats??["pdf","xlsx"])];if(!r.length||r.some(n=>n!=="pdf"&&n!=="xlsx"))return s.issues.push({code:"output",severity:"error",path:"$.formats",message:"真实文件验收应至少选择PDF/XLSX之一"}),s.ok=!1,s;for(const n of t.fixtures??[])for(const c of r)a.throwIfAborted(t.signal),!(c!=="pdf"&&c!=="xlsx")&&await ve(n,c,o,t,s);return s.ok=s.issues.every(n=>n.severity!=="error"),s}class m extends Error{constructor(t,s){super(s),this.code=t,this.name="ReportInstanceError"}}function J(e,t){if(typeof e!="string"||!e.trim()||e.length>256||typeof t!="string"||t!==t.trim()||!/^[a-zA-Z0-9][a-zA-Z0-9_.:-]{0,127}$/.test(t))throw new m("input","实例范围应非空,ID 应为安全标识")}function xe(e,t){const s=Object.getPrototypeOf(e);if(s!==(t?Array.prototype:Object.prototype)&&!(s===null&&!t)||Object.getOwnPropertySymbols(e).length)throw new m("input","实例应为普通 JSON 对象");if(t&&Object.keys(e).some(r=>r!==String(Number(r))||!Number.isSafeInteger(Number(r))||Number(r)<0||Number(r)>=e.length))throw new m("input","实例数组不能包含额外属性");if(Object.getOwnPropertyNames(e).filter(r=>!(t&&r==="length")).length!==Object.keys(e).length)throw new m("input","实例不能包含不可枚举属性")}function Ie(e){if(!Number.isSafeInteger(e.revision)||e.revision<1||typeof e.title!="string"||!e.title.trim()||e.title.length>512)throw new m("input","实例修订或标题无效");if(typeof e.generatedAt!="string"||!Number.isFinite(Date.parse(e.generatedAt))||new Date(e.generatedAt).toISOString()!==e.generatedAt)throw new m("input","实例生成时间应为 ISO UTC 字符串");if(!Array.isArray(e.reportIds)||!e.reportIds.length||e.reportIds.length>100||e.reportIds.some(t=>typeof t!="string"||!t.trim())||new Set(e.reportIds).size!==e.reportIds.length)throw new m("input","实例报表 ID 应非空且唯一")}function Se(e){return e===null||typeof e=="boolean"||typeof e=="string"||typeof e=="number"&&Number.isFinite(e)}function U(e,t){if(!Number.isSafeInteger(t)||t<1)throw new m("input","实例快照字节预算应为正安全整数");let s=0,o=0;const r=new Set;function n(u,f){if(++s>1e6||f>64)throw new m("capacity","实例节点或嵌套深度超过预算");if(typeof u=="string"&&(o+=u.length,o>t))throw new m("capacity","实例文本超过预算");if(Se(u))return u;if(!u||typeof u!="object"||r.has(u))throw new m("input","实例只允许无循环的有限 JSON 值");const i=Array.isArray(u);xe(u,i),r.add(u);const d=Object.create(null);for(const l of Object.keys(u)){if(o+=l.length,o>t)throw new m("capacity","实例文本超过预算");const p=Object.getOwnPropertyDescriptor(u,l);if(p.get||p.set||["__proto__","constructor","prototype"].includes(l))throw new m("input","实例不能包含访问器或危险键");p.value!==void 0&&(d[l]=n(p.value,f+1))}if(r.delete(u),i){if(Object.keys(d).length!==u.length)throw new m("input","实例数组不能稀疏或包含额外属性");return Array.from({length:u.length},(l,p)=>d[String(p)])}return d}const c=JSON.stringify(n(e,0));if(new TextEncoder().encode(c).byteLength>t)throw new m("capacity","实例快照超过单条字节预算");return c}function j(e,t=8e6){const s=JSON.parse(U(e,t));J(s.scope,s.id);const o=new Set(["scope","id","revision","title","generatedAt","reportIds","params","templateRevisions","sourceRevisions","plan","artifacts"]);if(Object.keys(s).some(n=>!o.has(n)))throw new m("input","实例包含未知字段");Ie(s);for(const n of[s.params,s.templateRevisions,s.sourceRevisions])if(!n||typeof n!="object"||Array.isArray(n)||Object.values(n).some(c=>typeof c!="string"))throw new m("input","实例参数和修订应为字符串字典");if(s.reportIds.some(n=>!s.templateRevisions[n]))throw new m("input","每张报表都应记录生成时的模板修订");const r=H.validateRenderPlan(s.plan);if(!r.ok)throw new m("input",`实例渲染计划无效:${r.errors[0]?.path}`);return s.artifacts!==void 0&&Je(s.artifacts),s}function Je(e){if(!Array.isArray(e)||e.length>100)throw new m("input","实例文件列表无效");const t=new Set;for(const s of e){if(!s||typeof s.key!="string"||!s.key.trim()||s.key.length>1024||t.has(s.key)||!["pdf","xlsx"].includes(s.format)||!Number.isSafeInteger(s.bytes)||s.bytes<0||s.sha256!==void 0&&(typeof s.sha256!="string"||s.sha256.length!==64||!/^[a-f0-9]{64}$/i.test(s.sha256)))throw new m("input","实例文件应包含唯一存储键、格式、大小和可选 SHA256");t.add(s.key)}}function W(e){const{scope:t,id:s,revision:o,title:r,generatedAt:n,reportIds:c,params:u,templateRevisions:f,sourceRevisions:i}=e;return JSON.parse(JSON.stringify({scope:t,id:s,revision:o,title:r,generatedAt:n,reportIds:c,params:u,templateRevisions:f,sourceRevisions:i}))}function Ee(e){const t={maxInstances:100,maxRevisions:20,maxBytes:64e6,maxSnapshotBytes:8e6,...e};if(Object.values(t).some(s=>!Number.isSafeInteger(s)||s<1))throw new m("input","实例存储预算应为正安全整数");return t}function Oe(e={}){const t=Ee(e),s=new Map;let o=0;return{read:async(r,n,c,u)=>{a.throwIfAborted(u),J(r,n);const f=s.get(JSON.stringify([r,n])),i=f?.get(c??f.size);return i?j(i,t.maxSnapshotBytes):void 0},list:async(r,n={})=>{a.throwIfAborted(n.signal),J(r,"list");const c=n.limit??25;if(!Number.isSafeInteger(c)||c<1||c>100)throw new m("input","实例每页数量应为 1–100");const u=Array.from(s.values(),f=>f.get(f.size)).filter(f=>f.scope===r&&(!n.after||f.id>n.after)&&(!n.reportId||f.reportIds.includes(n.reportId))).sort((f,i)=>f.id<i.id?-1:1).slice(0,c+1);return{items:u.slice(0,c).map(W),...u.length>c?{next:u[c-1].id}:{}}},compareAndSwap:async(r,n,c,u,f)=>{a.throwIfAborted(f),J(r,n);const i=j(u,t.maxSnapshotBytes);if(i.scope!==r||i.id!==n||i.revision!==(c??0)+1)throw new m("input","实例身份或修订不一致");const d=JSON.stringify([r,n]),l=s.get(d)??new Map;if((l.size||null)!==c)return!1;const p=new TextEncoder().encode(JSON.stringify(i)).byteLength;if(l.size>=t.maxRevisions||o+p>t.maxBytes||!l.size&&s.size>=t.maxInstances)throw new m("capacity","实例存储达到预算,请使用持久化归档策略或显式调整容量");return l.set(i.revision,i),s.set(d,l),o+=p,!0}}}function Z(e,t={}){const s=t.maxSnapshotBytes??8e6;if(!Number.isSafeInteger(s)||s<1)throw new m("input","实例快照字节预算应为正安全整数");return{read:e.read.bind(e),list:e.list.bind(e),save:async(o,r)=>{const n=r.expectedRevision;if(n!==null&&(!Number.isSafeInteger(n)||n<1||n>=Number.MAX_SAFE_INTEGER))throw new m("input","实例预期修订无效");const c=JSON.parse(U(o,s)),u=j({...c,revision:(n??0)+1},s);if(a.throwIfAborted(r.signal),!await e.compareAndSwap(u.scope,u.id,n,u,r.signal))throw new m("conflict","实例已存在或已变化,请显式确认修订后保存");return u}}}function Ae(e,t){return a.serializeJobJson({reportIds:e,params:t})}function Pe(e){if(!e||typeof e!="object"||Object.getOwnPropertySymbols(e).length)throw new m("input","生成请求应为普通对象");const t=Object.create(null);let s;const o=new Set(["scope","id","title","reportIds","params","expectedRevision","signal"]);for(const r of Object.getOwnPropertyNames(e)){const n=Object.getOwnPropertyDescriptor(e,r);if(!o.has(r)||!n.enumerable||n.get||n.set)throw new m("input","生成请求不能包含未知字段或访问器");r==="signal"?s=n.value:n.value!==void 0&&(t[r]=n.value)}return{signal:s,request:JSON.parse(a.serializeJobJson(t))}}function ke(e){const t=JSON.parse(a.serializeJobJson(e.templateRevisions)),s=Z(e.instances,{maxSnapshotBytes:e.maxSnapshotBytes});return{async generate(o){const{signal:r,request:n}=Pe(o);if(J(n.scope,n.id),n.expectedRevision!==null&&(!Number.isSafeInteger(n.expectedRevision)||n.expectedRevision<1))throw new m("input","实例预期修订无效");const c=e.runtime.validate(n);if(!c.ok)throw new O.ReportParamValidationError(c.issues);const u=Object.create(null);for(const l of n.reportIds){if(typeof t[l]!="string"||!t[l])throw new TypeError(`报表 ${l} 缺少生成时的模板修订`);u[l]=t[l]}if(a.throwIfAborted(r),((await e.instances.read(n.scope,n.id,void 0,r))?.revision??null)!==n.expectedRevision)throw new m("conflict","实例已存在或已变化,请显式确认修订后生成");const i=await e.runtime.prepare({reportIds:n.reportIds,params:c.values,signal:r});a.throwIfAborted(r);const d=Object.create(null);for(const[l,p]of Object.entries(i.revisions))p.revision!==void 0&&(d[l]=p.revision);return s.save({scope:n.scope,id:n.id,title:n.title,reportIds:n.reportIds,params:c.values,templateRevisions:u,sourceRevisions:d,generatedAt:(e.now?.()??new Date).toISOString(),plan:i.plan},{expectedRevision:n.expectedRevision,signal:r})},read:s.read,list:s.list,save:s.save}}exports.ReportJobError=a.ReportJobError;exports.ReportRuntimeError=a.ReportRuntimeError;exports.checkJobIdentity=a.checkJobIdentity;exports.cloneJob=a.cloneJob;exports.createMemoryReportJobStore=a.createMemoryReportJobStore;exports.runReportBatch=a.runReportBatch;exports.runnableJob=a.runnableJob;exports.serializeJobJson=a.serializeJobJson;exports.snapshotReportBatchCases=a.snapshotReportBatchCases;exports.validateJobRecord=a.validateJobRecord;exports.validateJobTransition=a.validateJobTransition;exports.ReportInstanceError=m;exports.checkInstanceIdentity=J;exports.createMemoryReportInstanceStore=Oe;exports.createReportGenerationService=ke;exports.createReportInstanceManager=Z;exports.createReportJobService=be;exports.createReportRuntime=K;exports.createReportTaskQueue=pe;exports.reportInstanceParameterKey=Ae;exports.reportInstanceSummary=W;exports.reviewReportPublication=Re;exports.snapshotReportInstance=j;
1
+ "use strict";var se=Object.create;var $=Object.defineProperty;var ne=Object.getOwnPropertyDescriptor;var ae=Object.getOwnPropertyNames;var oe=Object.getPrototypeOf,ie=Object.prototype.hasOwnProperty;var ce=(e,t,r,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of ae(t))!ie.call(e,s)&&s!==r&&$(e,s,{get:()=>t[s],enumerable:!(a=ne(t,s))||a.enumerable});return e};var F=(e,t,r)=>(r=e!=null?se(oe(e)):{},ce(t||!e||!e.__esModule?$(r,"default",{value:e,enumerable:!0}):r,e));Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const x=require("./template-review-BfCC8Ng9.cjs"),T=require("./report-params-SJfhKgaX.cjs"),P=require("./param-validation-DCK039V1.cjs"),o=require("./batch-Bt3Fd27Z.cjs"),G=require("./validate-BJ5HIWY8.cjs"),S=require("./task-events-DQ276fn2.cjs"),le=require("./tree-BX380Rr7.cjs"),ue=require("./assets-C2U-e-Sz.cjs"),de=require("./template-registry-D3SjENi6.cjs");function K(e,t){if(t.length===0)throw new x.ReportSourceError("config","缺少报表 ID");return t.map(r=>{if(!Object.prototype.hasOwnProperty.call(e,r))throw new x.ReportSourceError("config",`未注册报表 ${r}`);return e[r]})}function q(e){return e.grid?.cells.reduce((t,r)=>t+r.reduce((a,s)=>a+(s?1+(s.children?.reduce((n,c)=>n+q(c),0)??0):0),0),0)??0}function fe(e,t,r){return e.pages.reduce((a,s)=>a+s.components.reduce((n,c)=>c.kind!=="list"?n+q(c):n+x.estimateListLayoutCells(c,t,r),0),0)}function pe(e,t=Object.keys(e)){return K(e,t).map((r,a)=>{const s=t[a],n=T.getReportParamDefs(e,[s]);return{id:s,params:JSON.parse(JSON.stringify(n)),paramsSchema:P.reportParamsJsonSchema(n),datasetsSchema:Object.fromEntries(Object.entries(r.dataSchema??{}).map(([c,u])=>[c,x.templateDatasetJsonSchema(typeof r.template=="function"?void 0:r.template,c,u)])),capabilities:{save:!!r.provider?.save,export:!!r.provider?.export,templates:!!r.provider?.templates}}})}function U(e,t){K(e,t.reportIds);const r=P.validateReportParams(T.getReportParamDefs(e,t.reportIds),t.params),a=t.reportIds.flatMap(n=>P.validateReportParams(T.getReportParamDefs(e,[n]),t.params).issues),s=new Map(a.map(n=>[JSON.stringify(n),n]));return{...r,ok:s.size===0,issues:[...s.values()]}}function ge(e,t){const r=G.validateRenderPlan(e.plan);if(!r.ok)throw new x.ReportSourceError("validate",`执行器返回无效计划:${r.errors[0]?.path}`);const a=e.plan.pages.length,s=e.plan.pages.reduce((n,c)=>n+c.components.reduce((u,p)=>u+q(p),0),0);return o.assertBudget(t,"maxRows",e.stats.rows),o.assertBudget(t,"maxPages",a),o.assertBudget(t,"maxCells",s),{...e,stats:{...e.stats,pages:a,cells:s}}}function L(e,t){const r=U(e.reports,t);if(!r.ok)throw new P.ReportParamValidationError(r.issues)}function M(e=[]){return e.map(({code:t,message:r,severity:a,pageIndex:s,componentIndex:n})=>({code:t,message:r,severity:a,path:`$.pages.${s}.components.${n}`}))}function W(e){const t={maxRows:1e5,maxPages:1e4,maxCells:2e6,maxOutputBytes:1e8,maxDurationMs:12e4,...e.budget};o.validateBudget(t);const r=async(s,n)=>{const c=Date.now();let u=0,p=0;const i=[],f={},l=Object.fromEntries(Object.entries(e.reports).map(([g,v])=>[g,{...v,pagination:{...e.pagination,...v.pagination,...n?{measurer:n}:{}},dataValidation:{...v.dataValidation,maxRows:Math.min(t.maxRows??1e5,v.dataValidation?.maxRows??1/0),maxCells:Math.min(t.maxCells??2e6,v.dataValidation?.maxCells??1/0)}}])),y=await x.createReportSource(l,{maxPages:t.maxPages,maxCells:t.maxCells,onDatasets:(g,v,E)=>{try{u+=x.templateDatasetRowCount(E,v,{maxRows:t.maxRows,signal:s.signal})}catch(J){throw J instanceof le.TreeRowLimitError?new o.ReportRuntimeError("budget",J.message,"$.budget.maxRows"):J}o.assertBudget(t,"maxRows",u),p+=fe(E,v,l[g]?.pagination),o.assertBudget(t,"maxCells",p)}})({...s,params:s.params??{},onWarning:g=>i.push({code:"layout",message:g,severity:"warning"}),onQueryResult:(g,v)=>{Object.defineProperty(f,g,{value:{revision:v.revision,sourceToken:v.sourceToken},enumerable:!0,writable:!0}),i.push(...v.diagnostics??[])}}).catch(g=>{throw g instanceof x.ReportSourceError&&g.cause instanceof x.PaginatePageLimitError?new o.ReportRuntimeError("budget",g.cause.message,"$.budget.maxPages"):g instanceof x.ReportSourceError&&g.cause instanceof x.PaginateCellLimitError?new o.ReportRuntimeError("budget",g.cause.message,"$.budget.maxCells"):g});o.throwIfAborted(s.signal);const b=e.assets?await S.createReportTaskReporter(s).run("assets",()=>ue.resolvePlanAssets(y,{...e.assets,signal:s.signal})):{plan:y,diagnostics:[]},h=b.plan;i.push(...M(b.diagnostics));const w=h.pages.reduce((g,v)=>g+v.components.reduce((E,J)=>E+q(J),0),0);return o.assertBudget(t,"maxPages",h.pages.length),o.assertBudget(t,"maxCells",w),{plan:h,diagnostics:i,revisions:f,stats:{rows:u,pages:h.pages.length,cells:w,durationMs:Date.now()-c}}},a=async s=>{const n=Date.now();if(s.format!=="pdf"&&s.format!=="xlsx")throw new x.ReportSourceError("config","不支持的报表导出格式");const c=s.format==="pdf"?await import("@agile-team/mach-report/pdf"):void 0;o.throwIfAborted(s.signal);const u=s.pdf?.customFontFaces??(s.pdf?.customFontBytes?{regular:s.pdf.customFontBytes}:void 0),p=c&&u?c.createFontBytesMeasurer(u):void 0,i=await r(s,p);o.throwIfAborted(s.signal);const f=S.createReportTaskReporter(s),l=await f.run("encode",async()=>{let b;if(s.format==="pdf"){o.throwIfAborted(s.signal);const h=await c.renderPlanToPdf(i.plan,{...s.pdf,...p?{measurer:p}:{},fidelity:s.fidelity,signal:s.signal,onProgress:(w,g)=>f.progress("encode",w,g)});b=h.bytes,i.diagnostics.push(...M(h.diagnostics)),i.diagnostics.push(...h.fidelityWarnings.map(w=>({code:"pdf-fidelity",message:w,severity:"warning"})),...h.pageErrors.map(w=>({code:"pdf-page",message:w,severity:"error"}))),h.unsupportedTextCount&&i.diagnostics.push({code:"pdf-font",message:`${h.unsupportedTextCount} 段文本包含当前字体不支持的字符`,severity:"warning"})}else{const{renderPlanToXlsx:h}=await import("@agile-team/mach-report/xlsx");o.throwIfAborted(s.signal);const w=await h(i.plan,{...s.xlsx,fidelity:s.fidelity,signal:s.signal,onProgress:(g,v)=>f.progress("encode",g,v)});b=new Uint8Array(w.buffer),i.diagnostics.push(...M(w.diagnostics)),i.diagnostics.push(...w.warnings.map(g=>({code:"xlsx-fidelity",message:g,severity:"warning"})))}return o.throwIfAborted(s.signal),b});o.assertBudget(t,"maxOutputBytes",l.byteLength);const{plan:d,...y}=i;return{...y,bytes:l,format:s.format,contentType:s.format==="pdf"?"application/pdf":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",stats:{...y.stats,durationMs:Date.now()-n,outputBytes:l.byteLength}}};return{describe:s=>pe(e.reports,s),validate:s=>U(e.reports,s),prepare:s=>o.controlled(s.signal,t.maxDurationMs,async n=>{const{signal:c,onEvent:u,...p}=s,i={...p,taskId:p.taskId??S.reportTaskId()},f=u?y=>S.notifyReportTaskEvent(u,y,n):void 0,l={...i,signal:n,onEvent:f};S.createReportTaskReporter(l).runSync("validate",()=>L(e,i));const d=e.executor?await e.executor.prepare(i,n,f):await r(l);return ge(d,t)}),export:s=>o.controlled(s.signal,t.maxDurationMs,async n=>{const{signal:c,onEvent:u,...p}=s,i={...p,taskId:p.taskId??S.reportTaskId()},f=u?y=>S.notifyReportTaskEvent(u,y,n):void 0,l={...i,signal:n,onEvent:f};if(S.createReportTaskReporter(l).runSync("validate",()=>L(e,i)),i.format!=="pdf"&&i.format!=="xlsx")throw new x.ReportSourceError("config","不支持的报表导出格式");const d=e.executor?await e.executor.export(i,n,f):await a(l);return o.assertBudget(t,"maxRows",d.stats.rows),o.assertBudget(t,"maxPages",d.stats.pages),o.assertBudget(t,"maxCells",d.stats.cells),o.assertBudget(t,"maxOutputBytes",d.bytes.byteLength),{...d,stats:{...d.stats,outputBytes:d.bytes.byteLength}}})}}function we(e={}){const t=e.concurrency??1,r=e.maxQueued??20;if(!Number.isSafeInteger(t)||t<1||!Number.isSafeInteger(r)||r<0)throw new o.ReportRuntimeError("budget","队列并发应为正整数,排队上限应为非负整数");const a=[],s=new Set,n=new Set;let c=!1,u=0;const p=()=>{for(;!c&&s.size<t&&a.length;)a.shift().start()};return{get active(){return s.size},get pending(){return a.length},enqueue:(f,l={})=>{if(c)throw new o.ReportRuntimeError("closed","任务队列已关闭");if(o.throwIfAborted(l.signal),s.size>=t&&a.length>=r)throw new o.ReportRuntimeError("queue-full","报表任务队列已满");const d=l.id??`report-${++u}`;if(n.has(d))throw new o.ReportRuntimeError("queue-full","任务 ID 正在执行或排队");const y=new AbortController;let b="queued",h,w,g,v;const E=new Promise((R,I)=>{g=R,v=I}),J=()=>{l.signal?.removeEventListener("abort",C),n.delete(d)},j=R=>{if(b!=="queued"&&b!=="running")return;const I=b==="queued";b="cancelled",y.abort(R);try{o.throwIfAborted(y.signal)}catch(N){v(N)}if(I){const N=a.indexOf(O);N>=0&&a.splice(N,1),J(),p()}},C=()=>j(l.signal?.reason),z=(R,I)=>{b==="running"&&(!Number.isFinite(R)||R<0||I!==void 0&&(!Number.isFinite(I)||I<R)||(h={completed:R,...I===void 0?{}:{total:I}}))},re=R=>{b!=="running"||y.signal.aborted||(w={...R,taskId:d},R.completed!==void 0&&z(R.completed,R.total),S.notifyReportTaskEvent(l.onEvent,w,y.signal))},O={cancel:j,start:()=>{b==="queued"&&(b="running",s.add(O),Promise.resolve().then(()=>(o.throwIfAborted(y.signal),f({taskId:d,signal:y.signal,reportProgress:z,onEvent:re}))).then(R=>{b==="running"&&(b="completed",g(R))},R=>{b==="running"&&(b="failed",v(R))}).finally(()=>{s.delete(O),J(),p()}))}};return n.add(d),l.signal?.addEventListener("abort",C,{once:!0}),l.signal?.aborted?j(l.signal.reason):s.size<t?O.start():a.push(O),{id:d,get status(){return b},get progress(){return h},get event(){return w},result:E,cancel:j}},close:(f={})=>{c=!0;for(const l of[...a])l.cancel(new o.ReportRuntimeError("closed","任务队列已关闭"));if(f.cancelRunning)for(const l of s)l.cancel(new o.ReportRuntimeError("closed","任务队列已关闭"))}}}function me(e){let t,r;const a=new Promise((s,n)=>{t=s,r=n});return a.catch(()=>{}),{progress:e,promise:a,resolve:t,reject:r}}function _(e){const t=Promise.reject(e);return t.catch(()=>{}),t}function he(e,t){let r,a,s=!0,n;function c(i){n??=i??new Error("任务心跳更新失败"),a?.reject(n),a=void 0,t(n)}function u(i){const f=Promise.resolve().then(()=>e(i?.progress)).then(()=>i?.resolve(),l=>{i?.reject(l),c(l)}).finally(()=>{r=void 0;const l=a;a=void 0,l&&n===void 0&&u(l)});r=f,f.catch(l=>{c(l)})}function p(i){if(!s)return _(new o.ReportJobError("closed","任务进度上报已结束"));if(n!==void 0)return _(n);a?a.progress=i:a=me(i);const f=a;return r||(a=void 0,u(f)),f.promise}return{progress:p,pulse(){s&&!r&&n===void 0&&u()},async finish(){for(s=!1;r;)await r;if(n!==void 0)throw n}}}class V extends o.ReportJobError{constructor(){super("capacity","任务结果超过独立预算,请保存文件引用")}}function ye(e){const t=e.concurrency??1,r=e.leaseMs??3e4,a=e.heartbeatMs??1e4,s=e.maxResultBytes??256*1024;if(![t,r,a,s].every(c=>Number.isSafeInteger(c)&&c>0)||a*2>r)throw new o.ReportJobError("input","并发、租约、心跳应为正整数,租约至少为心跳的两倍");if(a>2147483647)throw new o.ReportJobError("input","心跳间隔超过平台定时器上限(2147483647毫秒)");return{concurrency:t,leaseMs:r,heartbeatMs:a,maxResultBytes:s,now:()=>{const c=(e.now??Date.now)();if(!Number.isSafeInteger(c)||c<0)throw new o.ReportJobError("input","任务时钟应返回非负整数毫秒");return c}}}async function B(e,t,r){o.checkJobIdentity(t,r);const a=await e.read(t,r);if(!a)throw new o.ReportJobError("missing","报表任务不存在");return a}async function k(e,t,r,a=[]){const s={...t,...r,revision:t.revision+1};for(const n of a)delete s[n];if(!await e.compareAndSwap(t.scope,t.id,t.revision,s))throw new o.ReportJobError("conflict","报表任务已被其他请求更新");return o.cloneJob(s)}async function be(e,t,r,a){if(!t.trim()||t.length>128)throw new o.ReportJobError("input","workerId应为1–128位标识");for(const s of await e.store.candidates(a,100)){const n=s.cancelRequested?{...s,revision:s.revision+1,status:"cancelled",updatedAt:a}:{...s,revision:s.revision+1,status:"running",attempt:s.attempt+1,updatedAt:a,lease:{owner:t,expiresAt:a+r}};if(n.status==="cancelled"&&delete n.lease,await e.store.compareAndSwap(s.scope,s.id,s.revision,n))return n}}function Q(e,t,r,a){return e.status==="running"&&e.attempt===a&&e.lease?.owner===t&&e.lease.expiresAt>r}async function ve(e,t,r,a){const{scope:s,id:n}=r,c=r.lease.owner;let u;const p=he(async w=>{const g=await B(e.store,s,n),v=t.now();if(!Q(g,c,v,r.attempt))throw new o.ReportJobError("lease","报表任务租约已失效");if(g.cancelRequested){a.abort(new o.ReportJobError("closed","任务已请求取消"));return}await k(e.store,g,{updatedAt:v,lease:{owner:c,expiresAt:v+t.leaseMs},...w?{progress:w}:{}})},w=>{u=w,a.abort(w)}),i=(w,g)=>!Number.isFinite(w)||w<0||g!==void 0&&(!Number.isFinite(g)||g<w)?Promise.reject(new o.ReportJobError("input","任务进度无效")):p.progress({completed:w,...g===void 0?{}:{total:g}}),f=setInterval(()=>{p.pulse()},t.heartbeatMs);let l,d;try{const w=Object.prototype.hasOwnProperty.call(e.handlers,r.request.kind)?e.handlers[r.request.kind]:void 0;if(!w)throw new o.ReportJobError("input","报表任务处理器未注册");if(!a.signal.aborted){const g=await w(o.cloneJob(r.request.payload),{scope:s,taskId:n,signal:a.signal,reportProgress:i});if(l=JSON.parse(o.serializeJobJson(g)),o.jobByteLength(l)>t.maxResultBytes)throw new V}}catch(w){d=w??new Error("报表任务执行失败")}finally{clearInterval(f),await p.finish().catch(()=>{})}const y=await B(e.store,s,n),b=t.now();if(!Q(y,c,b,r.attempt))throw new o.ReportJobError("lease","任务租约已失效,迟到结果不会写回");const h={...y,updatedAt:b};delete h.lease,d??=u,y.cancelRequested||a.signal.aborted&&u===void 0?h.status="cancelled":d!==void 0?(h.status="failed",h.error={code:d instanceof V?"result-budget":d instanceof o.ReportJobError?d.code:"execution",message:d instanceof Error?d.message.slice(0,500):"报表任务执行失败"}):(h.status="completed",h.result=l);try{o.serializeJobJson(h)}catch{delete h.result,h.status="failed",h.error={code:"result-budget",message:"任务结果与请求的组合超过存储预算,请保存文件引用而非文件内容"}}return Re(e.store,y,h)}async function Re(e,t,r){try{return await k(e,t,r,["lease"])}catch(a){if(!(a instanceof o.ReportJobError)||a.code!=="capacity"||r.status!=="completed")throw a;return delete r.result,r.status="failed",r.error={code:"result-budget",message:"任务结果超过存储剩余预算,请保存文件引用而非文件内容"},k(e,t,r,["lease","result"])}}async function H(e,t,r,a){const s=await e.readTombstone?.(t,r);if(s){if(s.requestHash!==await o.jobRequestHash(a))throw new o.ReportJobError("conflict","相同任务ID不能提交不同内容(幂等保留期内)");return{scope:t,id:r,revision:s.revision,request:o.cloneJob(a),status:s.status,createdAt:s.createdAt,updatedAt:s.updatedAt,attempt:s.attempt,archived:!0}}}function xe(e){e={...e,handlers:{...e.handlers}};const t=ye(e),r=new Set,a=new Set;let s=!1,n=0;const c=(i,f)=>(o.checkJobIdentity(i,f),e.store.read(i,f));return{submit:async i=>{if(i={...i},o.checkJobIdentity(i.scope,i.id),!Object.prototype.hasOwnProperty.call(e.handlers,i.kind)||typeof e.handlers[i.kind]!="function")throw new o.ReportJobError("input","报表任务处理器未注册");const f={kind:i.kind,payload:JSON.parse(o.serializeJobJson(i.payload,{maxNodes:19e3,maxCharacters:75e4}))},l=await c(i.scope,i.id);if(l){if(o.serializeJobJson(l.request)!==o.serializeJobJson(f))throw new o.ReportJobError("conflict","相同任务ID不能提交不同内容");return l}const d=await H(e.store,i.scope,i.id,f);if(d)return d;const y=t.now(),b={scope:i.scope,id:i.id,revision:1,request:f,status:"queued",createdAt:y,updatedAt:y,attempt:0};if(!await e.store.compareAndSwap(i.scope,i.id,null,b)){const h=await c(i.scope,i.id);if(h&&o.serializeJobJson(h.request)===o.serializeJobJson(f))return h;const w=await H(e.store,i.scope,i.id,f);if(w)return w;throw new o.ReportJobError("conflict","报表任务提交发生冲突")}return o.cloneJob(b)},get:c,runNext:i=>{if(s)return Promise.reject(new o.ReportJobError("closed","报表任务服务已关闭"));if(n>=t.concurrency)return Promise.reject(new o.ReportJobError("capacity","报表任务执行槽位已满"));n++;const f=new AbortController;r.add(f);const l=(async()=>{try{const d=await be(e,i,t.leaseMs,t.now());return d?.status==="running"?await ve(e,t,d,f):d}finally{n--,r.delete(f)}})();return a.add(l),l.then(()=>a.delete(l),()=>a.delete(l)),l},get active(){return n},cancel:async(i,f)=>{const l=await B(e.store,i,f);return l.status!=="queued"&&l.status!=="running"?l:k(e.store,l,{updatedAt:t.now(),...l.status==="queued"?{status:"cancelled"}:{cancelRequested:!0}})},retry:async(i,f,l)=>{const d=await B(e.store,i,f);if(d.revision!==l||d.status!=="failed")throw new o.ReportJobError("conflict","仅可重试当前修订的失败任务");const y={...d,status:"queued",updatedAt:t.now()};return delete y.error,delete y.progress,k(e.store,d,y,["error","progress"])},prune:async i=>{if(!e.store.prune||!e.store.readTombstone)throw new o.ReportJobError("input","当前任务适配器未实现可选终态保留能力");return e.store.prune({...i,now:t.now()})},close:async()=>{s=!0;for(const i of r)i.abort(new o.ReportJobError("closed","任务服务正在关闭"));await Promise.allSettled([...a])}}}function Z(e,t){const r=e.assets,a=e[t];if(!(!r&&!a?.assetRenderers))return{...r,...a?.assetFailure===void 0?{}:{assetFailure:a.assetFailure},...a?.onDiagnostic===void 0?{}:{onDiagnostic:a.onDiagnostic},assetRenderers:{...r?.assetRenderers,...a?.assetRenderers},assetBudget:{...r?.assetBudget,...a?.assetBudget}}}function X(e,t){return!e||e.code!=="missing-image"||e.format!=="pdf"&&e.format!=="xlsx"?!1:typeof Z(t,e.format)?.assetRenderers?.[e.kind]=="function"}function Ie(e,t){const r=x.reviewReportTemplate(e,t),a=r.issues.filter(n=>!X(n.diagnostic,t)),s=r.samples.map(n=>({...n,diagnostics:n.diagnostics.filter(c=>!X(c,t))}));return{...r,issues:a,samples:s,ok:a.every(n=>n.severity!=="error"),artifacts:[]}}async function Se(e,t,r,a,s){const n=W({reports:{sample:{template:r,datasets:e.datasets}},assets:Z(a,t),budget:{maxRows:a.maxSampleRows??1e3,maxPages:a.maxPages??100,maxCells:a.maxCells??25e4,maxOutputBytes:a.maxOutputBytes??2e7,maxDurationMs:a.maxDurationMs??3e4}});try{const{result:c,digest:u}=await o.controlled(a.signal,a.maxDurationMs??3e4,async p=>{const i=await n.export({reportIds:["sample"],params:e.params,format:t,signal:p,fidelity:a.strictOutputs?"strict":"warn",pdf:a.pdf,xlsx:a.xlsx}),f=i.diagnostics.filter(d=>d.severity!=="info");if(a.strictOutputs&&f.length)throw new Error(`Strict ${t} encoding found fidelity issues: ${f.slice(0,3).map(d=>d.message).join("; ")}`);const l=await a.digest?.(i.bytes);return o.throwIfAborted(p),await a.onArtifact?.(e.name,i),o.throwIfAborted(p),{result:i,digest:l}});s.artifacts.push({fixture:e.name,format:t,bytes:c.bytes.byteLength,pages:c.stats.pages,...u?{digest:u}:{}}),s.issues.push(...c.diagnostics.map(p=>({code:"output",severity:a.strictOutputs||p.severity==="error"?"error":"warning",path:"$.template",fixture:e.name,message:`${t}: ${p.message}`})))}catch(c){o.throwIfAborted(a.signal),s.issues.push({code:"output",severity:"error",path:"$.template",fixture:e.name,message:`${t}: ${c instanceof Error?c.message:String(c)}`})}}async function Je(e,t={}){o.throwIfAborted(t.signal);const r=Ie(e,t);if(!r.ok)return r;const a=de.parseReportTemplate(e).template,s=[...new Set(t.formats??["pdf","xlsx"])];if(!s.length||s.some(n=>n!=="pdf"&&n!=="xlsx"))return r.issues.push({code:"output",severity:"error",path:"$.formats",message:"真实文件验收应至少选择PDF/XLSX之一"}),r.ok=!1,r;for(const n of t.fixtures??[])for(const c of s)o.throwIfAborted(t.signal),!(c!=="pdf"&&c!=="xlsx")&&await Se(n,c,a,t,r);return r.ok=r.issues.every(n=>n.severity!=="error"),r}class m extends Error{constructor(t,r){super(r),this.code=t,this.name="ReportInstanceError"}}function A(e,t){if(typeof e!="string"||!e.trim()||e.length>256||typeof t!="string"||t!==t.trim()||!/^[a-zA-Z0-9][a-zA-Z0-9_.:-]{0,127}$/.test(t))throw new m("input","实例范围应非空,ID 应为安全标识")}function Ee(e,t){const r=Object.getPrototypeOf(e);if(r!==(t?Array.prototype:Object.prototype)&&!(r===null&&!t)||Object.getOwnPropertySymbols(e).length)throw new m("input","实例应为普通 JSON 对象");if(t&&Object.keys(e).some(s=>s!==String(Number(s))||!Number.isSafeInteger(Number(s))||Number(s)<0||Number(s)>=e.length))throw new m("input","实例数组不能包含额外属性");if(Object.getOwnPropertyNames(e).filter(s=>!(t&&s==="length")).length!==Object.keys(e).length)throw new m("input","实例不能包含不可枚举属性")}function Ae(e){if(!Number.isSafeInteger(e.revision)||e.revision<1||typeof e.title!="string"||!e.title.trim()||e.title.length>512)throw new m("input","实例修订或标题无效");if(typeof e.generatedAt!="string"||!Number.isFinite(Date.parse(e.generatedAt))||new Date(e.generatedAt).toISOString()!==e.generatedAt)throw new m("input","实例生成时间应为 ISO UTC 字符串");if(!Array.isArray(e.reportIds)||!e.reportIds.length||e.reportIds.length>100||e.reportIds.some(t=>typeof t!="string"||!t.trim())||new Set(e.reportIds).size!==e.reportIds.length)throw new m("input","实例报表 ID 应非空且唯一")}function Oe(e){return e===null||typeof e=="boolean"||typeof e=="string"||typeof e=="number"&&Number.isFinite(e)}function Y(e,t){if(!Number.isSafeInteger(t)||t<1)throw new m("input","实例快照字节预算应为正安全整数");let r=0,a=0;const s=new Set;function n(u,p){if(++r>1e6||p>64)throw new m("capacity","实例节点或嵌套深度超过预算");if(typeof u=="string"&&(a+=u.length,a>t))throw new m("capacity","实例文本超过预算");if(Oe(u))return u;if(!u||typeof u!="object"||s.has(u))throw new m("input","实例只允许无循环的有限 JSON 值");const i=Array.isArray(u);Ee(u,i),s.add(u);const f=Object.create(null);for(const l of Object.keys(u)){if(a+=l.length,a>t)throw new m("capacity","实例文本超过预算");const d=Object.getOwnPropertyDescriptor(u,l);if(d.get||d.set||["__proto__","constructor","prototype"].includes(l))throw new m("input","实例不能包含访问器或危险键");d.value!==void 0&&(f[l]=n(d.value,p+1))}if(s.delete(u),i){if(Object.keys(f).length!==u.length)throw new m("input","实例数组不能稀疏或包含额外属性");return Array.from({length:u.length},(l,d)=>f[String(d)])}return f}const c=JSON.stringify(n(e,0));if(new TextEncoder().encode(c).byteLength>t)throw new m("capacity","实例快照超过单条字节预算");return c}function D(e,t=8e6){const r=JSON.parse(Y(e,t));A(r.scope,r.id);const a=new Set(["scope","id","revision","title","generatedAt","reportIds","params","templateRevisions","sourceRevisions","plan","artifacts"]);if(Object.keys(r).some(n=>!a.has(n)))throw new m("input","实例包含未知字段");Ae(r);for(const n of[r.params,r.templateRevisions,r.sourceRevisions])if(!n||typeof n!="object"||Array.isArray(n)||Object.values(n).some(c=>typeof c!="string"))throw new m("input","实例参数和修订应为字符串字典");if(r.reportIds.some(n=>!r.templateRevisions[n]))throw new m("input","每张报表都应记录生成时的模板修订");const s=G.validateRenderPlan(r.plan);if(!s.ok)throw new m("input",`实例渲染计划无效:${s.errors[0]?.path}`);return r.artifacts!==void 0&&Pe(r.artifacts),r}function Pe(e){if(!Array.isArray(e)||e.length>100)throw new m("input","实例文件列表无效");const t=new Set;for(const r of e){if(!r||typeof r.key!="string"||!r.key.trim()||r.key.length>1024||t.has(r.key)||!["pdf","xlsx"].includes(r.format)||!Number.isSafeInteger(r.bytes)||r.bytes<0||r.sha256!==void 0&&(typeof r.sha256!="string"||r.sha256.length!==64||!/^[a-f0-9]{64}$/i.test(r.sha256)))throw new m("input","实例文件应包含唯一存储键、格式、大小和可选 SHA256");t.add(r.key)}}function ee(e){const{scope:t,id:r,revision:a,title:s,generatedAt:n,reportIds:c,params:u,templateRevisions:p,sourceRevisions:i}=e;return JSON.parse(JSON.stringify({scope:t,id:r,revision:a,title:s,generatedAt:n,reportIds:c,params:u,templateRevisions:p,sourceRevisions:i}))}function ke(e){const t={maxInstances:100,maxRevisions:20,maxBytes:64e6,maxSnapshotBytes:8e6,...e};if(Object.values(t).some(r=>!Number.isSafeInteger(r)||r<1))throw new m("input","实例存储预算应为正安全整数");return t}function je(e={}){const t=ke(e),r=new Map;let a=0;return{read:async(s,n,c,u)=>{o.throwIfAborted(u),A(s,n);const p=r.get(JSON.stringify([s,n])),i=p?.get(c??p.size);return i?D(i,t.maxSnapshotBytes):void 0},list:async(s,n={})=>{o.throwIfAborted(n.signal),A(s,"list");const c=n.limit??25;if(!Number.isSafeInteger(c)||c<1||c>100)throw new m("input","实例每页数量应为 1–100");const u=Array.from(r.values(),p=>p.get(p.size)).filter(p=>p.scope===s&&(!n.after||p.id>n.after)&&(!n.reportId||p.reportIds.includes(n.reportId))).sort((p,i)=>p.id<i.id?-1:1).slice(0,c+1);return{items:u.slice(0,c).map(ee),...u.length>c?{next:u[c-1].id}:{}}},compareAndSwap:async(s,n,c,u,p)=>{o.throwIfAborted(p),A(s,n);const i=D(u,t.maxSnapshotBytes);if(i.scope!==s||i.id!==n||i.revision!==(c??0)+1)throw new m("input","实例身份或修订不一致");const f=JSON.stringify([s,n]),l=r.get(f)??new Map;if((l.size||null)!==c)return!1;const d=new TextEncoder().encode(JSON.stringify(i)).byteLength;if(l.size>=t.maxRevisions||a+d>t.maxBytes||!l.size&&r.size>=t.maxInstances)throw new m("capacity","实例存储达到预算,请使用持久化归档策略或显式调整容量");return l.set(i.revision,i),r.set(f,l),a+=d,!0}}}function te(e,t={}){const r=t.maxSnapshotBytes??8e6;if(!Number.isSafeInteger(r)||r<1)throw new m("input","实例快照字节预算应为正安全整数");return{read:e.read.bind(e),list:e.list.bind(e),save:async(a,s)=>{const n=s.expectedRevision;if(n!==null&&(!Number.isSafeInteger(n)||n<1||n>=Number.MAX_SAFE_INTEGER))throw new m("input","实例预期修订无效");const c=JSON.parse(Y(a,r)),u=D({...c,revision:(n??0)+1},r);if(o.throwIfAborted(s.signal),!await e.compareAndSwap(u.scope,u.id,n,u,s.signal))throw new m("conflict","实例已存在或已变化,请显式确认修订后保存");return u}}}function Ne(e,t){return o.serializeJobJson({reportIds:e,params:t})}function Be(e){if(!e||typeof e!="object"||Object.getOwnPropertySymbols(e).length)throw new m("input","生成请求应为普通对象");const t=Object.create(null);let r;const a=new Set(["scope","id","title","reportIds","params","expectedRevision","signal"]);for(const s of Object.getOwnPropertyNames(e)){const n=Object.getOwnPropertyDescriptor(e,s);if(!a.has(s)||!n.enumerable||n.get||n.set)throw new m("input","生成请求不能包含未知字段或访问器");s==="signal"?r=n.value:n.value!==void 0&&(t[s]=n.value)}return{signal:r,request:JSON.parse(o.serializeJobJson(t))}}function De(e){const t=JSON.parse(o.serializeJobJson(e.templateRevisions)),r=te(e.instances,{maxSnapshotBytes:e.maxSnapshotBytes});return{async generate(a){const{signal:s,request:n}=Be(a);if(A(n.scope,n.id),n.expectedRevision!==null&&(!Number.isSafeInteger(n.expectedRevision)||n.expectedRevision<1))throw new m("input","实例预期修订无效");const c=e.runtime.validate(n);if(!c.ok)throw new P.ReportParamValidationError(c.issues);const u=Object.create(null);for(const l of n.reportIds){if(typeof t[l]!="string"||!t[l])throw new TypeError(`报表 ${l} 缺少生成时的模板修订`);u[l]=t[l]}if(o.throwIfAborted(s),((await e.instances.read(n.scope,n.id,void 0,s))?.revision??null)!==n.expectedRevision)throw new m("conflict","实例已存在或已变化,请显式确认修订后生成");const i=await e.runtime.prepare({reportIds:n.reportIds,params:c.values,signal:s});o.throwIfAborted(s);const f=Object.create(null);for(const[l,d]of Object.entries(i.revisions))d.revision!==void 0&&(f[l]=d.revision);return r.save({scope:n.scope,id:n.id,title:n.title,reportIds:n.reportIds,params:c.values,templateRevisions:u,sourceRevisions:f,generatedAt:(e.now?.()??new Date).toISOString(),plan:i.plan},{expectedRevision:n.expectedRevision,signal:s})},read:r.read,list:r.list,save:r.save}}exports.ReportJobError=o.ReportJobError;exports.ReportRuntimeError=o.ReportRuntimeError;exports.checkJobIdentity=o.checkJobIdentity;exports.cloneJob=o.cloneJob;exports.createMemoryReportJobStore=o.createMemoryReportJobStore;exports.runReportBatch=o.runReportBatch;exports.runnableJob=o.runnableJob;exports.serializeJobJson=o.serializeJobJson;exports.snapshotReportBatchCases=o.snapshotReportBatchCases;exports.validateJobRecord=o.validateJobRecord;exports.validateJobTransition=o.validateJobTransition;exports.ReportInstanceError=m;exports.checkInstanceIdentity=A;exports.createMemoryReportInstanceStore=je;exports.createReportGenerationService=De;exports.createReportInstanceManager=te;exports.createReportJobService=xe;exports.createReportRuntime=W;exports.createReportTaskQueue=we;exports.reportInstanceParameterKey=Ne;exports.reportInstanceSummary=ee;exports.reviewReportPublication=Je;exports.snapshotReportInstance=D;
package/dist/server.d.cts CHANGED
@@ -10,12 +10,43 @@ declare interface AggregateDefinition {
10
10
 
11
11
  declare type AggregateOperation = "sum" | "count" | "avg" | "min" | "max" | "weightedAvg";
12
12
 
13
+ declare interface AssetRenderBudget {
14
+ /** Maximum newly rendered assets, default 1000. Existing imageData is kept unchanged. */
15
+ maxAssets?: number;
16
+ /** Maximum image payload bytes per new asset, default 32 MiB. */
17
+ maxImageBytes?: number;
18
+ /** Maximum total image payload bytes for new assets, default 128 MiB. */
19
+ maxTotalImageBytes?: number;
20
+ /** Wall-clock budget, including adapters that ignore AbortSignal. Default 30 seconds. */
21
+ maxDurationMs?: number;
22
+ }
23
+
24
+ declare interface AssetRenderOptions extends OutputDiagnosticOptions {
25
+ assetRenderers?: Partial<Record<ImageComponentKind, ComponentImageRenderer>>;
26
+ assetBudget?: AssetRenderBudget;
27
+ /** Default throw prevents an incomplete export; placeholder retains the component and emits diagnostics. */
28
+ assetFailure?: "throw" | "placeholder";
29
+ signal?: AbortSignal;
30
+ }
31
+
13
32
  export declare function checkInstanceIdentity(scope: string, id: string): void;
14
33
 
15
34
  export declare function checkJobIdentity(scope: string, id: string): void;
16
35
 
17
36
  export declare function cloneJob<T>(value: T): T;
18
37
 
38
+ /** Serializable symbol settings. Encoders remain in the optional /codes entry. */
39
+ declare interface CodeOptions {
40
+ /** Explicit content, including an empty value, takes precedence over legacy fallbackText. */
41
+ value?: string;
42
+ symbology?: "code128" | "code39" | "ean13" | "ean8";
43
+ errorCorrection?: "L" | "M" | "Q" | "H";
44
+ /** White modules around a symbol: QR >=4, linear >=10, EAN >=11. */
45
+ quietZoneModules?: number;
46
+ /** Human-readable content below a linear barcode. */
47
+ showText?: boolean;
48
+ }
49
+
19
50
  /**
20
51
  * 列值格式化(声明式、JSON 可序列化)。
21
52
  * 在 paginate 的 cellText 出口统一消费:格式化发生在进 RenderPlan 之前,
@@ -39,6 +70,25 @@ declare type ColumnFormat = {
39
70
  pattern?: string;
40
71
  };
41
72
 
73
+ /** A literal own field of the current label record; expressions and paths are not evaluated. */
74
+ declare interface ComponentBinding {
75
+ field: string;
76
+ format?: ValueFormat;
77
+ prefix?: string;
78
+ suffix?: string;
79
+ emptyText?: string;
80
+ }
81
+
82
+ declare interface ComponentImageContext {
83
+ readonly component: Readonly<PlanComponent>;
84
+ readonly pageIndex: number;
85
+ readonly componentIndex: number;
86
+ readonly componentPath: readonly number[];
87
+ readonly signal: AbortSignal;
88
+ }
89
+
90
+ declare type ComponentImageRenderer = (context: ComponentImageContext) => string | Promise<string>;
91
+
42
92
  declare type ComponentKind = "text" | "image" | "barcode" | "qrcode" | "chart" | "line" | "rect" | "ellipse";
43
93
 
44
94
  declare interface ComponentStyle {
@@ -177,6 +227,8 @@ declare interface GridCell {
177
227
  style?: ComponentStyle;
178
228
  }
179
229
 
230
+ declare type ImageComponentKind = "image" | "chart" | "barcode" | "qrcode";
231
+
180
232
  /** auto:真实数字/显式数值格式居右,日期与布尔居中,其他内容居左。 */
181
233
  declare type ListAlignment = NonNullable<ComponentStyle["align"]> | "auto";
182
234
 
@@ -337,8 +389,21 @@ declare interface OutputDiagnostic {
337
389
  message: string;
338
390
  }
339
391
 
392
+ declare interface OutputDiagnosticOptions extends OutputTaskOptions {
393
+ /** Structured fidelity diagnostics; rendering never silently invents missing content. */
394
+ onDiagnostic?: (diagnostic: OutputDiagnostic) => void;
395
+ /** Reject known unsupported content before creating an incomplete file. Default warn. */
396
+ fidelity?: "warn" | "strict";
397
+ }
398
+
340
399
  declare type OutputFormat = "dom" | "canvas" | "pdf" | "xlsx";
341
400
 
401
+ /** Stage counts are exact completed units; encoding libraries may remain indeterminate. */
402
+ declare interface OutputTaskOptions {
403
+ signal?: AbortSignal;
404
+ onProgress?: (completed: number, total: number) => void;
405
+ }
406
+
342
407
  declare interface PaginateOptions {
343
408
  /** 每行额外占高(mm),压测专用钩子 */
344
409
  mmPerRow?: number;
@@ -357,6 +422,10 @@ declare interface PaginateOptions {
357
422
  }
358
423
 
359
424
  declare interface PlanComponent {
425
+ /** Optional QR/barcode encoding configuration; no encoder is loaded by the core. */
426
+ code?: CodeOptions;
427
+ /** Template-only binding; resolved and removed before constructing the output plan. */
428
+ binding?: ComponentBinding;
360
429
  /** Template page furniture repeats per page and reserves its vertical band. */
361
430
  pageAnchor?: "header" | "footer";
362
431
  kind: ComponentKind;
@@ -431,6 +500,8 @@ export declare interface PreparedReport {
431
500
  }>;
432
501
  }
433
502
 
503
+ declare type PublicationAssets = Omit<AssetRenderOptions, "signal">;
504
+
434
505
  declare interface RenderPlan {
435
506
  schemaVersion: string;
436
507
  /** 编辑需要模板重算上下文;跨 Worker/JSON 保留要求,但不声明本地会话可用。 */
@@ -853,8 +924,10 @@ export declare interface ReportPublicationArtifact {
853
924
  export declare interface ReportPublicationOptions extends ReportTemplateReviewOptions {
854
925
  formats?: readonly ("pdf" | "xlsx")[];
855
926
  signal?: AbortSignal;
856
- pdf?: ReportRuntimeExportInput["pdf"];
857
- xlsx?: ReportRuntimeExportInput["xlsx"];
927
+ /** Trusted resource renderers shared by all requested file formats. */
928
+ assets?: PublicationAssets;
929
+ pdf?: ReportRuntimeExportInput["pdf"] & PublicationAssets;
930
+ xlsx?: ReportRuntimeExportInput["xlsx"] & PublicationAssets;
858
931
  maxOutputBytes?: number;
859
932
  maxDurationMs?: number;
860
933
  /** Explicit fixtures only. Host may archive these bytes; the result retains metadata only. */
@@ -938,6 +1011,8 @@ export declare interface ReportRuntimeInput extends ReportTaskMonitoring {
938
1011
 
939
1012
  export declare interface ReportRuntimeOptions {
940
1013
  reports: ReportRegistry;
1014
+ /** Trusted local renderers, shared by preview preparation and export; configure inside an executor's runtime. */
1015
+ assets?: Omit<AssetRenderOptions, "signal">;
941
1016
  budget?: ReportRuntimeBudget;
942
1017
  /** 各定义可覆盖默认分页配置;PDF自带字体时,自动使用字体字节度量以保持排版与输出一致。 */
943
1018
  pagination?: PaginateOptions;
@@ -994,7 +1069,7 @@ export declare interface ReportTaskContext {
994
1069
  declare interface ReportTaskEvent {
995
1070
  taskId: string;
996
1071
  correlationId?: string;
997
- stage: "query" | "validate" | "layout" | "encode";
1072
+ stage: "query" | "validate" | "layout" | "assets" | "encode";
998
1073
  status: "started" | "completed" | "failed";
999
1074
  reportId?: string;
1000
1075
  completed?: number;
@@ -1029,6 +1104,8 @@ declare interface ReportTemplate {
1029
1104
  schemaVersion?: string;
1030
1105
  /** 参数定义(可选;宿主也可经 ReportPreview 的 paramDefs prop 提供,prop 优先) */
1031
1106
  params?: ReportParamDef[];
1107
+ /** Fixed label pages repeat in record → copy → template-page order. */
1108
+ repeat?: ReportTemplateRepeat;
1032
1109
  pages: TemplatePage[];
1033
1110
  }
1034
1111
 
@@ -1076,6 +1153,16 @@ declare interface ReportTemplateProvider {
1076
1153
  }): Promise<ReportTemplateDocument | undefined>;
1077
1154
  }
1078
1155
 
1156
+ /** Every record emits its copies, each containing all template pages in their original order. */
1157
+ declare interface ReportTemplateRepeat {
1158
+ dataset: string;
1159
+ rowKey?: string;
1160
+ /** Whole copies per record, 1..1000. The field value must be a number, never a numeric string. */
1161
+ copies?: number | {
1162
+ field: string;
1163
+ };
1164
+ }
1165
+
1079
1166
  declare interface ReportTemplateReview {
1080
1167
  ok: boolean;
1081
1168
  changes?: ReportTemplateDiff;
@@ -1097,6 +1184,8 @@ declare interface ReportTemplateReviewIssue {
1097
1184
  pageIndex?: number;
1098
1185
  componentIndex?: number;
1099
1186
  field?: string;
1187
+ /** Original structured output finding, retained for trusted publication resource handling. */
1188
+ diagnostic?: OutputDiagnostic;
1100
1189
  }
1101
1190
 
1102
1191
  declare interface ReportTemplateReviewOptions {
@@ -1224,4 +1313,7 @@ export declare function validateJobRecord(record: ReportJobRecord, scope: string
1224
1313
 
1225
1314
  export declare function validateJobTransition(previous: ReportJobRecord | undefined, next: ReportJobRecord): void;
1226
1315
 
1316
+ /** The same declarative formatting used by list columns, before any output backend. */
1317
+ declare type ValueFormat = ColumnFormat;
1318
+
1227
1319
  export { }
package/dist/server.d.ts CHANGED
@@ -10,12 +10,43 @@ declare interface AggregateDefinition {
10
10
 
11
11
  declare type AggregateOperation = "sum" | "count" | "avg" | "min" | "max" | "weightedAvg";
12
12
 
13
+ declare interface AssetRenderBudget {
14
+ /** Maximum newly rendered assets, default 1000. Existing imageData is kept unchanged. */
15
+ maxAssets?: number;
16
+ /** Maximum image payload bytes per new asset, default 32 MiB. */
17
+ maxImageBytes?: number;
18
+ /** Maximum total image payload bytes for new assets, default 128 MiB. */
19
+ maxTotalImageBytes?: number;
20
+ /** Wall-clock budget, including adapters that ignore AbortSignal. Default 30 seconds. */
21
+ maxDurationMs?: number;
22
+ }
23
+
24
+ declare interface AssetRenderOptions extends OutputDiagnosticOptions {
25
+ assetRenderers?: Partial<Record<ImageComponentKind, ComponentImageRenderer>>;
26
+ assetBudget?: AssetRenderBudget;
27
+ /** Default throw prevents an incomplete export; placeholder retains the component and emits diagnostics. */
28
+ assetFailure?: "throw" | "placeholder";
29
+ signal?: AbortSignal;
30
+ }
31
+
13
32
  export declare function checkInstanceIdentity(scope: string, id: string): void;
14
33
 
15
34
  export declare function checkJobIdentity(scope: string, id: string): void;
16
35
 
17
36
  export declare function cloneJob<T>(value: T): T;
18
37
 
38
+ /** Serializable symbol settings. Encoders remain in the optional /codes entry. */
39
+ declare interface CodeOptions {
40
+ /** Explicit content, including an empty value, takes precedence over legacy fallbackText. */
41
+ value?: string;
42
+ symbology?: "code128" | "code39" | "ean13" | "ean8";
43
+ errorCorrection?: "L" | "M" | "Q" | "H";
44
+ /** White modules around a symbol: QR >=4, linear >=10, EAN >=11. */
45
+ quietZoneModules?: number;
46
+ /** Human-readable content below a linear barcode. */
47
+ showText?: boolean;
48
+ }
49
+
19
50
  /**
20
51
  * 列值格式化(声明式、JSON 可序列化)。
21
52
  * 在 paginate 的 cellText 出口统一消费:格式化发生在进 RenderPlan 之前,
@@ -39,6 +70,25 @@ declare type ColumnFormat = {
39
70
  pattern?: string;
40
71
  };
41
72
 
73
+ /** A literal own field of the current label record; expressions and paths are not evaluated. */
74
+ declare interface ComponentBinding {
75
+ field: string;
76
+ format?: ValueFormat;
77
+ prefix?: string;
78
+ suffix?: string;
79
+ emptyText?: string;
80
+ }
81
+
82
+ declare interface ComponentImageContext {
83
+ readonly component: Readonly<PlanComponent>;
84
+ readonly pageIndex: number;
85
+ readonly componentIndex: number;
86
+ readonly componentPath: readonly number[];
87
+ readonly signal: AbortSignal;
88
+ }
89
+
90
+ declare type ComponentImageRenderer = (context: ComponentImageContext) => string | Promise<string>;
91
+
42
92
  declare type ComponentKind = "text" | "image" | "barcode" | "qrcode" | "chart" | "line" | "rect" | "ellipse";
43
93
 
44
94
  declare interface ComponentStyle {
@@ -177,6 +227,8 @@ declare interface GridCell {
177
227
  style?: ComponentStyle;
178
228
  }
179
229
 
230
+ declare type ImageComponentKind = "image" | "chart" | "barcode" | "qrcode";
231
+
180
232
  /** auto:真实数字/显式数值格式居右,日期与布尔居中,其他内容居左。 */
181
233
  declare type ListAlignment = NonNullable<ComponentStyle["align"]> | "auto";
182
234
 
@@ -337,8 +389,21 @@ declare interface OutputDiagnostic {
337
389
  message: string;
338
390
  }
339
391
 
392
+ declare interface OutputDiagnosticOptions extends OutputTaskOptions {
393
+ /** Structured fidelity diagnostics; rendering never silently invents missing content. */
394
+ onDiagnostic?: (diagnostic: OutputDiagnostic) => void;
395
+ /** Reject known unsupported content before creating an incomplete file. Default warn. */
396
+ fidelity?: "warn" | "strict";
397
+ }
398
+
340
399
  declare type OutputFormat = "dom" | "canvas" | "pdf" | "xlsx";
341
400
 
401
+ /** Stage counts are exact completed units; encoding libraries may remain indeterminate. */
402
+ declare interface OutputTaskOptions {
403
+ signal?: AbortSignal;
404
+ onProgress?: (completed: number, total: number) => void;
405
+ }
406
+
342
407
  declare interface PaginateOptions {
343
408
  /** 每行额外占高(mm),压测专用钩子 */
344
409
  mmPerRow?: number;
@@ -357,6 +422,10 @@ declare interface PaginateOptions {
357
422
  }
358
423
 
359
424
  declare interface PlanComponent {
425
+ /** Optional QR/barcode encoding configuration; no encoder is loaded by the core. */
426
+ code?: CodeOptions;
427
+ /** Template-only binding; resolved and removed before constructing the output plan. */
428
+ binding?: ComponentBinding;
360
429
  /** Template page furniture repeats per page and reserves its vertical band. */
361
430
  pageAnchor?: "header" | "footer";
362
431
  kind: ComponentKind;
@@ -431,6 +500,8 @@ export declare interface PreparedReport {
431
500
  }>;
432
501
  }
433
502
 
503
+ declare type PublicationAssets = Omit<AssetRenderOptions, "signal">;
504
+
434
505
  declare interface RenderPlan {
435
506
  schemaVersion: string;
436
507
  /** 编辑需要模板重算上下文;跨 Worker/JSON 保留要求,但不声明本地会话可用。 */
@@ -853,8 +924,10 @@ export declare interface ReportPublicationArtifact {
853
924
  export declare interface ReportPublicationOptions extends ReportTemplateReviewOptions {
854
925
  formats?: readonly ("pdf" | "xlsx")[];
855
926
  signal?: AbortSignal;
856
- pdf?: ReportRuntimeExportInput["pdf"];
857
- xlsx?: ReportRuntimeExportInput["xlsx"];
927
+ /** Trusted resource renderers shared by all requested file formats. */
928
+ assets?: PublicationAssets;
929
+ pdf?: ReportRuntimeExportInput["pdf"] & PublicationAssets;
930
+ xlsx?: ReportRuntimeExportInput["xlsx"] & PublicationAssets;
858
931
  maxOutputBytes?: number;
859
932
  maxDurationMs?: number;
860
933
  /** Explicit fixtures only. Host may archive these bytes; the result retains metadata only. */
@@ -938,6 +1011,8 @@ export declare interface ReportRuntimeInput extends ReportTaskMonitoring {
938
1011
 
939
1012
  export declare interface ReportRuntimeOptions {
940
1013
  reports: ReportRegistry;
1014
+ /** Trusted local renderers, shared by preview preparation and export; configure inside an executor's runtime. */
1015
+ assets?: Omit<AssetRenderOptions, "signal">;
941
1016
  budget?: ReportRuntimeBudget;
942
1017
  /** 各定义可覆盖默认分页配置;PDF自带字体时,自动使用字体字节度量以保持排版与输出一致。 */
943
1018
  pagination?: PaginateOptions;
@@ -994,7 +1069,7 @@ export declare interface ReportTaskContext {
994
1069
  declare interface ReportTaskEvent {
995
1070
  taskId: string;
996
1071
  correlationId?: string;
997
- stage: "query" | "validate" | "layout" | "encode";
1072
+ stage: "query" | "validate" | "layout" | "assets" | "encode";
998
1073
  status: "started" | "completed" | "failed";
999
1074
  reportId?: string;
1000
1075
  completed?: number;
@@ -1029,6 +1104,8 @@ declare interface ReportTemplate {
1029
1104
  schemaVersion?: string;
1030
1105
  /** 参数定义(可选;宿主也可经 ReportPreview 的 paramDefs prop 提供,prop 优先) */
1031
1106
  params?: ReportParamDef[];
1107
+ /** Fixed label pages repeat in record → copy → template-page order. */
1108
+ repeat?: ReportTemplateRepeat;
1032
1109
  pages: TemplatePage[];
1033
1110
  }
1034
1111
 
@@ -1076,6 +1153,16 @@ declare interface ReportTemplateProvider {
1076
1153
  }): Promise<ReportTemplateDocument | undefined>;
1077
1154
  }
1078
1155
 
1156
+ /** Every record emits its copies, each containing all template pages in their original order. */
1157
+ declare interface ReportTemplateRepeat {
1158
+ dataset: string;
1159
+ rowKey?: string;
1160
+ /** Whole copies per record, 1..1000. The field value must be a number, never a numeric string. */
1161
+ copies?: number | {
1162
+ field: string;
1163
+ };
1164
+ }
1165
+
1079
1166
  declare interface ReportTemplateReview {
1080
1167
  ok: boolean;
1081
1168
  changes?: ReportTemplateDiff;
@@ -1097,6 +1184,8 @@ declare interface ReportTemplateReviewIssue {
1097
1184
  pageIndex?: number;
1098
1185
  componentIndex?: number;
1099
1186
  field?: string;
1187
+ /** Original structured output finding, retained for trusted publication resource handling. */
1188
+ diagnostic?: OutputDiagnostic;
1100
1189
  }
1101
1190
 
1102
1191
  declare interface ReportTemplateReviewOptions {
@@ -1224,4 +1313,7 @@ export declare function validateJobRecord(record: ReportJobRecord, scope: string
1224
1313
 
1225
1314
  export declare function validateJobTransition(previous: ReportJobRecord | undefined, next: ReportJobRecord): void;
1226
1315
 
1316
+ /** The same declarative formatting used by list columns, before any output backend. */
1317
+ declare type ValueFormat = ColumnFormat;
1318
+
1227
1319
  export { }