@agile-team/mach-report 2.12.0 → 2.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -3
- package/dist/ExcelBindingWizard-CLT2p7P3.cjs +1 -0
- package/dist/ExcelBindingWizard-CvsWR8Ga.js +1485 -0
- package/dist/{ParamEditor-BLaE5q5W.js → ParamEditor-CflQV3eQ.js} +191 -187
- package/dist/ParamEditor-vIDzvpPV.cjs +1 -0
- package/dist/ReportBatchPanel-DkxTzBkD.cjs +1 -0
- package/dist/{ReportBatchPanel-B5ClP9tm.js → ReportBatchPanel-LqVgiqp7.js} +3 -3
- package/dist/ReportPreview-CvbqLUzM.cjs +6 -0
- package/dist/ReportPreview-D_ywJ_-H.js +4533 -0
- package/dist/{ReportTemplateLibrary-BZB-XWjj.js → ReportTemplateLibrary-MjWEtc7X.js} +1 -1
- package/dist/ReportTemplateLibrary-cQ1sqNYo.cjs +1 -0
- package/dist/RuleEditor-BaR6xUiI.cjs +1 -0
- package/dist/RuleEditor-ChuXMlei.js +2037 -0
- package/dist/TemplateOutlinePanel-BHKP89Xz.cjs +1 -0
- package/dist/TemplateOutlinePanel-Dci6aRn1.js +96 -0
- package/dist/TemplateReusePanel-B7Gmyc1z.js +388 -0
- package/dist/TemplateReusePanel-CY5eO2Sh.cjs +1 -0
- package/dist/TemplateReviewPanel-DjlX3xpt.js +592 -0
- package/dist/TemplateReviewPanel-JvZe9_4G.cjs +1 -0
- package/dist/{batch-mRqhhhjt.js → batch-DzaTNLWI.js} +23 -16
- package/dist/batch-xMkqYiTr.cjs +1 -0
- package/dist/config-0UIohTS7.cjs +1 -0
- package/dist/{config-B612mw0x.js → config-Dt9NtCPl.js} +227 -186
- package/dist/data-explanation-BktvER5B.cjs +1 -0
- package/dist/data-explanation-C_J6jYNi.js +16 -0
- package/dist/designer-Ci1LizA9.js +5020 -0
- package/dist/designer-rtmVIIdN.cjs +2 -0
- package/dist/designer.cjs +1 -2
- package/dist/designer.d.cts +306 -3
- package/dist/designer.d.ts +306 -3
- package/dist/designer.js +21 -4266
- package/dist/font-loader-DHto6Lra.js +297 -0
- package/dist/font-loader-vhCT8znW.cjs +1 -0
- package/dist/index.cjs +8 -8
- package/dist/index.d.cts +182 -1
- package/dist/index.d.ts +182 -1
- package/dist/index.js +728 -628
- package/dist/{template-review-BzpcI-tR.js → json-snapshot-BeFT3Tso.js} +867 -637
- package/dist/json-snapshot-D1NTP2oI.cjs +2 -0
- package/dist/pdf-8UPQebOE.js +36288 -0
- package/dist/pdf-AyJGb22z.cjs +101 -0
- package/dist/pdf.cjs +1 -101
- package/dist/pdf.js +9 -36579
- package/dist/plugin-BGKf-Tqg.js +22 -0
- package/dist/{plugin-BDTU4D94.cjs → plugin-CktLH_Iy.cjs} +1 -1
- package/dist/{region-binding-workflow-CcUq8W2Q.js → region-binding-workflow-DEJbhpCv.js} +1 -1
- package/dist/server/node.d.cts +46 -11
- package/dist/server/node.d.ts +46 -11
- package/dist/server-node.cjs +1 -1
- package/dist/server-node.js +294 -280
- package/dist/server.cjs +1 -1
- package/dist/server.d.cts +107 -12
- package/dist/server.d.ts +107 -12
- package/dist/server.js +713 -453
- package/dist/style.css +1 -1
- package/dist/template-bindings-BJR4k7qZ.cjs +1 -0
- package/dist/template-bindings-Daui7hLF.js +252 -0
- package/dist/template-fragments-CLkGo6To.js +187 -0
- package/dist/template-fragments-DFUpq5QM.cjs +1 -0
- package/dist/template-outline-B3xVkzSv.cjs +1 -0
- package/dist/template-outline-CFenM1PV.js +88 -0
- package/dist/{template-registry-BjE1VS6g.js → template-registry-COXDEJEM.js} +1 -1
- package/dist/{useLocalDraft-C07SYRnC.js → useLocalDraft-BnhcxXk_.js} +1 -1
- package/dist/{useLocalDraft-Yiw1wFgI.cjs → useLocalDraft-CioIfDb6.cjs} +1 -1
- package/dist/{validate-DbgEM1Hh.js → validate-CkQBWCeg.js} +3 -3
- package/dist/vue/async.d.cts +72 -2
- package/dist/vue/async.d.ts +72 -2
- package/dist/vue/index.d.cts +124 -5
- package/dist/vue/index.d.ts +124 -5
- package/dist/vue-async.cjs +1 -1
- package/dist/vue-async.js +5 -5
- package/dist/vue.cjs +1 -1
- package/dist/vue.js +78 -71
- package/dist/{workbook-session-BPb3TMnT.js → workbook-session-BfK1yHOO.js} +1 -1
- package/dist/worker.cjs +1 -1
- package/dist/worker.d.cts +46 -11
- package/dist/worker.d.ts +46 -11
- package/dist/worker.js +59 -55
- package/dist/xlsx.js +3 -3
- package/package.json +1 -1
- package/dist/ExcelBindingWizard-CeAf4QSE.js +0 -1465
- package/dist/ExcelBindingWizard-y0mT-AHR.cjs +0 -1
- package/dist/ParamEditor-MBBC7lUE.cjs +0 -1
- package/dist/ReportBatchPanel-Dc-SDkYA.cjs +0 -1
- package/dist/ReportPreview-DWXROHBP.cjs +0 -6
- package/dist/ReportPreview-DiNXhQI0.js +0 -4138
- package/dist/ReportTemplateLibrary-5fk5CQBO.cjs +0 -1
- package/dist/RuleEditor-ChRzNQuF.cjs +0 -1
- package/dist/RuleEditor-DzAmW5YH.js +0 -2024
- package/dist/TemplateReviewPanel-BKofGrV9.js +0 -222
- package/dist/TemplateReviewPanel-DwtOcLue.cjs +0 -1
- package/dist/batch-Bt3Fd27Z.cjs +0 -1
- package/dist/config-BRoLo2oj.cjs +0 -1
- package/dist/plugin-Cd5G2QQn.js +0 -22
- package/dist/record-bindings-By_UKZ2g.cjs +0 -1
- package/dist/record-bindings-D-5jQlTj.js +0 -196
- package/dist/template-review-BfCC8Ng9.cjs +0 -2
package/dist/server.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
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;
|
|
1
|
+
"use strict";var ge=Object.create;var H=Object.defineProperty;var me=Object.getOwnPropertyDescriptor;var ye=Object.getOwnPropertyNames;var he=Object.getPrototypeOf,be=Object.prototype.hasOwnProperty;var ve=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of ye(t))!be.call(e,s)&&s!==r&&H(e,s,{get:()=>t[s],enumerable:!(o=me(t,s))||o.enumerable});return e};var M=(e,t,r)=>(r=e!=null?ge(he(e)):{},ve(t||!e||!e.__esModule?H(r,"default",{value:e,enumerable:!0}):r,e));Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const R=require("./json-snapshot-D1NTP2oI.cjs"),_=require("./report-params-SJfhKgaX.cjs"),j=require("./param-validation-DCK039V1.cjs"),a=require("./batch-xMkqYiTr.cjs"),oe=require("./validate-BJ5HIWY8.cjs"),A=require("./task-events-DQ276fn2.cjs"),Re=require("./tree-BX380Rr7.cjs"),K=require("./assets-C2U-e-Sz.cjs"),xe=require("./data-explanation-BktvER5B.cjs"),ne=require("./template-registry-D3SjENi6.cjs"),ae=require("./template-bindings-BJR4k7qZ.cjs");function D(e=[]){return e.map(({code:t,message:r,severity:o,pageIndex:s,componentIndex:n})=>({code:t,message:r,severity:o,path:`$.pages.${s}.components.${n}`}))}async function Q(e,t,r=Date.now()){const o=e.prepared,s=e.format==="pdf"?await import("@agile-team/mach-report/pdf"):void 0;a.throwIfAborted(e.signal);const n=e.pdf?.customFontFaces??(e.pdf?.customFontBytes?{regular:e.pdf.customFontBytes}:void 0),i=s&&n?s.createFontBytesMeasurer(n):void 0,l=A.createReportTaskReporter(e),u=await l.run("encode",async()=>{let d;if(e.format==="pdf"){a.throwIfAborted(e.signal);const f=await s.renderPlanToPdf(o.plan,{...e.pdf,...i?{measurer:i}:{},fidelity:e.fidelity,signal:e.signal,onProgress:(g,w)=>l.progress("encode",g,w)});d=f.bytes,o.diagnostics.push(...D(f.diagnostics)),o.diagnostics.push(...f.fidelityWarnings.map(g=>({code:"pdf-fidelity",message:g,severity:"warning"})),...f.pageErrors.map(g=>({code:"pdf-page",message:g,severity:"error"}))),f.unsupportedTextCount&&o.diagnostics.push({code:"pdf-font",message:`${f.unsupportedTextCount} 段文本包含当前字体不支持的字符`,severity:"warning"})}else{const{renderPlanToXlsx:f}=await import("@agile-team/mach-report/xlsx");a.throwIfAborted(e.signal);const g=await f(o.plan,{...e.xlsx,fidelity:e.fidelity,signal:e.signal,onProgress:(w,m)=>l.progress("encode",w,m)});d=new Uint8Array(g.buffer),o.diagnostics.push(...D(g.diagnostics)),o.diagnostics.push(...g.warnings.map(w=>({code:"xlsx-fidelity",message:w,severity:"warning"})))}return a.throwIfAborted(e.signal),d});a.assertBudget(t,"maxOutputBytes",u.byteLength);const{plan:c,...p}=o;return{...p,bytes:u,format:e.format,contentType:e.format==="pdf"?"application/pdf":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",stats:{...p.stats,durationMs:Date.now()-r,outputBytes:u.byteLength}}}function U(e){return e&&{...e}}function N(e){if(!e)return;const t=r=>{if(!(r instanceof Uint8Array)&&!(r instanceof ArrayBuffer))throw new R.ReportSourceError("validate","字体应为 Uint8Array 或 ArrayBuffer");if(r.byteLength>32e6)throw new a.ReportRuntimeError("budget","单份字体超过 32 MB","$.pdf");return new Uint8Array(r instanceof Uint8Array?r:new Uint8Array(r))};if(e.customFontFaces){const r=e.customFontFaces;return{customFontName:e.customFontName,customFontFaces:{regular:t(r.regular),...r.bold?{bold:t(r.bold)}:{},...r.italic?{italic:t(r.italic)}:{},...r.boldItalic?{boldItalic:t(r.boldItalic)}:{}}}}return{customFontName:e.customFontName,...e.customFontBytes?{customFontBytes:t(e.customFontBytes)}:{}}}function ie(e){const t=e?.customFontFaces??(e?.customFontBytes?{regular:e.customFontBytes}:void 0);if(!t)return;const r=["regular","bold","italic","boldItalic"].map(o=>{const s=t[o];if(!s)return[o,null];const n=s instanceof Uint8Array?s:new Uint8Array(s);if(n.byteLength>32e6)throw new a.ReportRuntimeError("budget","单份字体超过 32 MB","$.pdf");return[o,a.portableSha256Hex(n)]});return a.portableSha256Hex(new TextEncoder().encode(JSON.stringify(r)))}function Se(e,t,r){const o=R.snapshotReportJson(e,{maxBytes:t,check:()=>a.throwIfAborted(r),error:(s,n)=>s==="budget"?new a.ReportRuntimeError("budget",n,"$.budget.maxPreparedBytes"):new R.ReportSourceError("validate",n)});return ce(o),o}function ce(e){if(!e?.stats||["rows","pages","cells"].some(t=>!Number.isSafeInteger(e.stats[t])||e.stats[t]<0)||!Number.isFinite(e.stats.durationMs)||e.stats.durationMs<0)throw new R.ReportSourceError("validate","准备结果统计无效");if(!Array.isArray(e.diagnostics)||e.diagnostics.some(t=>!t||typeof t.code!="string"||typeof t.message!="string"||!["info","warning","error"].includes(t.severity)||!xe.hasValidDataExplanation(t)))throw new R.ReportSourceError("validate","准备结果诊断无效");if(!e.revisions||typeof e.revisions!="object"||Array.isArray(e.revisions)||Object.values(e.revisions).some(t=>!t||typeof t!="object"||t.revision!==void 0&&typeof t.revision!="string"||t.sourceToken!==void 0&&typeof t.sourceToken!="string"))throw new R.ReportSourceError("validate","准备结果修订无效");if(e.layout&&(!["heuristic","provided","font-bytes"].includes(e.layout.textMetrics)||e.layout.fontFingerprint!==void 0&&!/^[a-f0-9]{64}$/.test(e.layout.fontFingerprint)))throw new R.ReportSourceError("validate","准备结果字体度量标识无效")}function Ie(e){if(e.format!=="pdf")return;const t=e.prepared.layout?.fontFingerprint,r=ie(e.pdf);if(t===r&&(t!==void 0||e.prepared.layout?.textMetrics==="heuristic"&&!r))return;const o="已准备计划的字体度量无法与本次 PDF 字体确认一致;保持现有分页,未重新查询或排版。请在 prepare 和 exportPrepared 提供相同字体字节。";if(e.fidelity==="strict")throw new R.ReportSourceError("validate",o);e.prepared.diagnostics.push({code:"prepared-font-metrics",severity:"warning",message:o})}function ue(e,t){if(t.length===0)throw new R.ReportSourceError("config","缺少报表 ID");return t.map(r=>{if(!Object.prototype.hasOwnProperty.call(e,r))throw new R.ReportSourceError("config",`未注册报表 ${r}`);return e[r]})}function z(e){return e.grid?.cells.reduce((t,r)=>t+r.reduce((o,s)=>o+(s?1+(s.children?.reduce((n,i)=>n+z(i),0)??0):0),0),0)??0}function Ee(e,t,r){return e.pages.reduce((o,s)=>o+s.components.reduce((n,i)=>i.kind!=="list"?n+z(i):n+R.estimateListLayoutCells(i,t,r),0),0)}function Je(e,t=Object.keys(e)){return ue(e,t).map((r,o)=>{const s=t[o],n=_.getReportParamDefs(e,[s]);return{id:s,params:JSON.parse(JSON.stringify(n)),paramsSchema:j.reportParamsJsonSchema(n),datasetsSchema:Object.fromEntries(Object.entries(r.dataSchema??{}).map(([i,l])=>[i,R.templateDatasetJsonSchema(typeof r.template=="function"?void 0:r.template,i,l)])),capabilities:{save:!!r.provider?.save,export:!!r.provider?.export,templates:!!r.provider?.templates}}})}function de(e,t){ue(e,t.reportIds);const r=j.validateReportParams(_.getReportParamDefs(e,t.reportIds),t.params),o=t.reportIds.flatMap(n=>j.validateReportParams(_.getReportParamDefs(e,[n]),t.params).issues),s=new Map(o.map(n=>[JSON.stringify(n),n]));return{...r,ok:s.size===0,issues:[...s.values()]}}function X(e,t){const r=oe.validateRenderPlan(e.plan);if(!r.ok)throw new R.ReportSourceError("validate",`执行器返回无效计划:${r.errors[0]?.path}`);const o=e.plan.pages.length,s=e.plan.pages.reduce((n,i)=>n+i.components.reduce((l,u)=>l+z(u),0),0);return a.assertBudget(t,"maxRows",e.stats.rows),a.assertBudget(t,"maxPages",o),a.assertBudget(t,"maxCells",s),{...e,stats:{...e.stats,pages:o,cells:s}}}function G(e,t){const r=de(e.reports,t);if(!r.ok)throw new j.ReportParamValidationError(r.issues)}function V(e){const t={maxRows:1e5,maxPages:1e4,maxCells:2e6,maxOutputBytes:1e8,maxPreparedBytes:64e6,maxDurationMs:12e4,...e.budget};a.validateBudget(t);const r=async(s,n)=>{const i=Date.now();let l=0,u=0;const c=[],p={},d=Object.fromEntries(Object.entries(e.reports).map(([v,S])=>[v,{...S,pagination:{...e.pagination,...S.pagination,...n?{measurer:n}:{}},dataValidation:{...S.dataValidation,maxRows:Math.min(t.maxRows??1e5,S.dataValidation?.maxRows??1/0),maxCells:Math.min(t.maxCells??2e6,S.dataValidation?.maxCells??1/0)}}])),g=await R.createReportSource(d,{maxPages:t.maxPages,maxCells:t.maxCells,onDatasets:(v,S,I)=>{try{l+=R.templateDatasetRowCount(I,S,{maxRows:t.maxRows,signal:s.signal})}catch(k){throw k instanceof Re.TreeRowLimitError?new a.ReportRuntimeError("budget",k.message,"$.budget.maxRows"):k}a.assertBudget(t,"maxRows",l),u+=Ee(I,S,d[v]?.pagination),a.assertBudget(t,"maxCells",u)}})({...s,params:s.params??{},onWarning:v=>c.push({code:"layout",message:v,severity:"warning"}),onQueryResult:(v,S)=>{Object.defineProperty(p,v,{value:{revision:S.revision,sourceToken:S.sourceToken},enumerable:!0,writable:!0}),c.push(...S.diagnostics??[])}}).catch(v=>{throw v instanceof R.ReportSourceError&&v.cause instanceof R.PaginatePageLimitError?new a.ReportRuntimeError("budget",v.cause.message,"$.budget.maxPages"):v instanceof R.ReportSourceError&&v.cause instanceof R.PaginateCellLimitError?new a.ReportRuntimeError("budget",v.cause.message,"$.budget.maxCells"):v});a.throwIfAborted(s.signal);const w=e.assets?await A.createReportTaskReporter(s).run("assets",()=>K.resolvePlanAssets(g,{...e.assets,signal:s.signal})):{plan:g,diagnostics:[]},m=w.plan;c.push(...D(w.diagnostics));const y=m.pages.reduce((v,S)=>v+S.components.reduce((I,k)=>I+z(k),0),0);a.assertBudget(t,"maxPages",m.pages.length),a.assertBudget(t,"maxCells",y);const b=ie(s.pdf),E=e.pagination?.measurer||Object.values(e.reports).some(v=>v.pagination?.measurer);return{plan:m,diagnostics:c,revisions:p,layout:{textMetrics:b?"font-bytes":E?"provided":"heuristic",...b?{fontFingerprint:b}:{}},stats:{rows:l,pages:m.pages.length,cells:y,durationMs:Date.now()-i}}},o=async s=>{const n=Date.now();if(s.format!=="pdf"&&s.format!=="xlsx")throw new R.ReportSourceError("config","不支持的报表导出格式");const i=s.format==="pdf"?await import("@agile-team/mach-report/pdf"):void 0;a.throwIfAborted(s.signal);const l=s.pdf?.customFontFaces??(s.pdf?.customFontBytes?{regular:s.pdf.customFontBytes}:void 0),u=i&&l?i.createFontBytesMeasurer(l):void 0,c=await r(s,u);return a.throwIfAborted(s.signal),Q({...s,prepared:c},t,n)};return{describe:s=>Je(e.reports,s),validate:s=>de(e.reports,s),prepare:s=>a.controlled(s.signal,t.maxDurationMs,async n=>{const{signal:i,onEvent:l,...u}=s,c={...u,...u.pdf?{pdf:N(u.pdf)}:{},taskId:u.taskId??A.reportTaskId()},p=l?m=>A.notifyReportTaskEvent(l,m,n):void 0,d={...c,signal:n,onEvent:p};A.createReportTaskReporter(d).runSync("validate",()=>G(e,c));let f;const g=c.pdf?.customFontFaces??(c.pdf?.customFontBytes?{regular:c.pdf.customFontBytes}:void 0);if(!e.executor&&g){const m=await import("@agile-team/mach-report/pdf");a.throwIfAborted(n),f=m.createFontBytesMeasurer(g)}const w=e.executor?await e.executor.prepare(c,n,p):await r(d,f);return X(w,t)}),exportPrepared:s=>a.controlled(s.signal,t.maxDurationMs,async n=>{const i=Date.now(),{signal:l,onEvent:u,...c}=s,p=X(Se(s.prepared,t.maxPreparedBytes??64e6,n),t),d={...c,xlsx:U(c.xlsx),prepared:p,...c.pdf?{pdf:N(c.pdf)}:{},taskId:c.taskId??A.reportTaskId()};if(d.format!=="pdf"&&d.format!=="xlsx")throw new R.ReportSourceError("config","不支持的报表导出格式");const f=u?w=>A.notifyReportTaskEvent(u,w,n):void 0;if(e.executor){if(!e.executor.exportPrepared)throw new R.ReportSourceError("config","执行器未实现 exportPrepared;请升级执行器或显式使用本地运行时");const w=await e.executor.exportPrepared(d,n,f);return a.assertBudget(t,"maxRows",w.stats.rows),a.assertBudget(t,"maxPages",w.stats.pages),a.assertBudget(t,"maxCells",w.stats.cells),a.assertBudget(t,"maxOutputBytes",w.bytes.byteLength),{...w,stats:{...w.stats,outputBytes:w.bytes.byteLength}}}const g={...d,signal:n,onEvent:f};if(A.createReportTaskReporter(g).runSync("validate",()=>Ie(g)),e.assets){const w=await A.createReportTaskReporter(g).run("assets",()=>K.resolvePlanAssets(p.plan,{...e.assets,signal:n}));p.plan=w.plan,p.diagnostics.push(...D(w.diagnostics))}return Q(g,t,i)}),export:s=>a.controlled(s.signal,t.maxDurationMs,async n=>{const{signal:i,onEvent:l,...u}=s,c={...u,xlsx:U(u.xlsx),...u.pdf?{pdf:N(u.pdf)}:{},taskId:u.taskId??A.reportTaskId()},p=l?g=>A.notifyReportTaskEvent(l,g,n):void 0,d={...c,signal:n,onEvent:p};if(A.createReportTaskReporter(d).runSync("validate",()=>G(e,c)),c.format!=="pdf"&&c.format!=="xlsx")throw new R.ReportSourceError("config","不支持的报表导出格式");const f=e.executor?await e.executor.export(c,n,p):await o(d);return a.assertBudget(t,"maxRows",f.stats.rows),a.assertBudget(t,"maxPages",f.stats.pages),a.assertBudget(t,"maxCells",f.stats.cells),a.assertBudget(t,"maxOutputBytes",f.bytes.byteLength),{...f,stats:{...f.stats,outputBytes:f.bytes.byteLength}}})}}function Ae(e={}){const t=e.concurrency??1,r=e.maxQueued??20;if(!Number.isSafeInteger(t)||t<1||!Number.isSafeInteger(r)||r<0)throw new a.ReportRuntimeError("budget","队列并发应为正整数,排队上限应为非负整数");const o=[],s=new Set,n=new Set;let i=!1,l=0;const u=()=>{for(;!i&&s.size<t&&o.length;)o.shift().start()};return{get active(){return s.size},get pending(){return o.length},enqueue:(p,d={})=>{if(i)throw new a.ReportRuntimeError("closed","任务队列已关闭");if(a.throwIfAborted(d.signal),s.size>=t&&o.length>=r)throw new a.ReportRuntimeError("queue-full","报表任务队列已满");const f=d.id??`report-${++l}`;if(n.has(f))throw new a.ReportRuntimeError("queue-full","任务 ID 正在执行或排队");const g=new AbortController;let w="queued",m,y,b,E;const v=new Promise((x,P)=>{b=x,E=P}),S=()=>{d.signal?.removeEventListener("abort",k),n.delete(f)},I=x=>{if(w!=="queued"&&w!=="running")return;const P=w==="queued";w="cancelled",g.abort(x);try{a.throwIfAborted(g.signal)}catch(T){E(T)}if(P){const T=o.indexOf(J);T>=0&&o.splice(T,1),S(),u()}},k=()=>I(d.signal?.reason),L=(x,P)=>{w==="running"&&(!Number.isFinite(x)||x<0||P!==void 0&&(!Number.isFinite(P)||P<x)||(m={completed:x,...P===void 0?{}:{total:P}}))},O=x=>{w!=="running"||g.signal.aborted||(y={...x,taskId:f},x.completed!==void 0&&L(x.completed,x.total),A.notifyReportTaskEvent(d.onEvent,y,g.signal))},J={cancel:I,start:()=>{w==="queued"&&(w="running",s.add(J),Promise.resolve().then(()=>(a.throwIfAborted(g.signal),p({taskId:f,signal:g.signal,reportProgress:L,onEvent:O}))).then(x=>{w==="running"&&(w="completed",b(x))},x=>{w==="running"&&(w="failed",E(x))}).finally(()=>{s.delete(J),S(),u()}))}};return n.add(f),d.signal?.addEventListener("abort",k,{once:!0}),d.signal?.aborted?I(d.signal.reason):s.size<t?J.start():o.push(J),{id:f,get status(){return w},get progress(){return m},get event(){return y},result:v,cancel:I}},close:(p={})=>{i=!0;for(const d of[...o])d.cancel(new a.ReportRuntimeError("closed","任务队列已关闭"));if(p.cancelRunning)for(const d of s)d.cancel(new a.ReportRuntimeError("closed","任务队列已关闭"))}}}function ke(e){let t,r;const o=new Promise((s,n)=>{t=s,r=n});return o.catch(()=>{}),{progress:e,promise:o,resolve:t,reject:r}}function W(e){const t=Promise.reject(e);return t.catch(()=>{}),t}function Pe(e,t){let r,o,s=!0,n;function i(c){n??=c??new Error("任务心跳更新失败"),o?.reject(n),o=void 0,t(n)}function l(c){const p=Promise.resolve().then(()=>e(c?.progress)).then(()=>c?.resolve(),d=>{c?.reject(d),i(d)}).finally(()=>{r=void 0;const d=o;o=void 0,d&&n===void 0&&l(d)});r=p,p.catch(d=>{i(d)})}function u(c){if(!s)return W(new a.ReportJobError("closed","任务进度上报已结束"));if(n!==void 0)return W(n);o?o.progress=c:o=ke(c);const p=o;return r||(o=void 0,l(p)),p.promise}return{progress:u,pulse(){s&&!r&&n===void 0&&l()},async finish(){for(s=!1;r;)await r;if(n!==void 0)throw n}}}class Z extends a.ReportJobError{constructor(){super("capacity","任务结果超过独立预算,请保存文件引用")}}function Oe(e){const t=e.concurrency??1,r=e.leaseMs??3e4,o=e.heartbeatMs??1e4,s=e.maxResultBytes??256*1024;if(![t,r,o,s].every(i=>Number.isSafeInteger(i)&&i>0)||o*2>r)throw new a.ReportJobError("input","并发、租约、心跳应为正整数,租约至少为心跳的两倍");if(o>2147483647)throw new a.ReportJobError("input","心跳间隔超过平台定时器上限(2147483647毫秒)");return{concurrency:t,leaseMs:r,heartbeatMs:o,maxResultBytes:s,now:()=>{const i=(e.now??Date.now)();if(!Number.isSafeInteger(i)||i<0)throw new a.ReportJobError("input","任务时钟应返回非负整数毫秒");return i}}}async function C(e,t,r){a.checkJobIdentity(t,r);const o=await e.read(t,r);if(!o)throw new a.ReportJobError("missing","报表任务不存在");return o}async function F(e,t,r,o=[]){const s={...t,...r,revision:t.revision+1};for(const n of o)delete s[n];if(!await e.compareAndSwap(t.scope,t.id,t.revision,s))throw new a.ReportJobError("conflict","报表任务已被其他请求更新");return a.cloneJob(s)}async function Be(e,t,r,o){if(!t.trim()||t.length>128)throw new a.ReportJobError("input","workerId应为1–128位标识");for(const s of await e.store.candidates(o,100)){const n=s.cancelRequested?{...s,revision:s.revision+1,status:"cancelled",updatedAt:o}:{...s,revision:s.revision+1,status:"running",attempt:s.attempt+1,updatedAt:o,lease:{owner:t,expiresAt:o+r}};if(n.status==="cancelled"&&delete n.lease,await e.store.compareAndSwap(s.scope,s.id,s.revision,n))return n}}function Y(e,t,r,o){return e.status==="running"&&e.attempt===o&&e.lease?.owner===t&&e.lease.expiresAt>r}async function Ne(e,t,r,o){const{scope:s,id:n}=r,i=r.lease.owner;let l;const u=Pe(async y=>{const b=await C(e.store,s,n),E=t.now();if(!Y(b,i,E,r.attempt))throw new a.ReportJobError("lease","报表任务租约已失效");if(b.cancelRequested){o.abort(new a.ReportJobError("closed","任务已请求取消"));return}await F(e.store,b,{updatedAt:E,lease:{owner:i,expiresAt:E+t.leaseMs},...y?{progress:y}:{}})},y=>{l=y,o.abort(y)}),c=(y,b)=>!Number.isFinite(y)||y<0||b!==void 0&&(!Number.isFinite(b)||b<y)?Promise.reject(new a.ReportJobError("input","任务进度无效")):u.progress({completed:y,...b===void 0?{}:{total:b}}),p=setInterval(()=>{u.pulse()},t.heartbeatMs);let d,f;try{const y=Object.prototype.hasOwnProperty.call(e.handlers,r.request.kind)?e.handlers[r.request.kind]:void 0;if(!y)throw new a.ReportJobError("input","报表任务处理器未注册");if(!o.signal.aborted){const b=await y(a.cloneJob(r.request.payload),{scope:s,taskId:n,signal:o.signal,reportProgress:c});if(d=JSON.parse(a.serializeJobJson(b)),a.jobByteLength(d)>t.maxResultBytes)throw new Z}}catch(y){f=y??new Error("报表任务执行失败")}finally{clearInterval(p),await u.finish().catch(()=>{})}const g=await C(e.store,s,n),w=t.now();if(!Y(g,i,w,r.attempt))throw new a.ReportJobError("lease","任务租约已失效,迟到结果不会写回");const m={...g,updatedAt:w};delete m.lease,f??=l,g.cancelRequested||o.signal.aborted&&l===void 0?m.status="cancelled":f!==void 0?(m.status="failed",m.error={code:f instanceof Z?"result-budget":f instanceof a.ReportJobError?f.code:"execution",message:f instanceof Error?f.message.slice(0,500):"报表任务执行失败"}):(m.status="completed",m.result=d);try{a.serializeJobJson(m)}catch{delete m.result,m.status="failed",m.error={code:"result-budget",message:"任务结果与请求的组合超过存储预算,请保存文件引用而非文件内容"}}return je(e.store,g,m)}async function je(e,t,r){try{return await F(e,t,r,["lease"])}catch(o){if(!(o instanceof a.ReportJobError)||o.code!=="capacity"||r.status!=="completed")throw o;return delete r.result,r.status="failed",r.error={code:"result-budget",message:"任务结果超过存储剩余预算,请保存文件引用而非文件内容"},F(e,t,r,["lease","result"])}}async function ee(e,t,r,o){const s=await e.readTombstone?.(t,r);if(s){if(s.requestHash!==await a.jobRequestHash(o))throw new a.ReportJobError("conflict","相同任务ID不能提交不同内容(幂等保留期内)");return{scope:t,id:r,revision:s.revision,request:a.cloneJob(o),status:s.status,createdAt:s.createdAt,updatedAt:s.updatedAt,attempt:s.attempt,archived:!0}}}function Fe(e){e={...e,handlers:{...e.handlers}};const t=Oe(e),r=new Set,o=new Set;let s=!1,n=0;const i=(c,p)=>(a.checkJobIdentity(c,p),e.store.read(c,p));return{submit:async c=>{if(c={...c},a.checkJobIdentity(c.scope,c.id),!Object.prototype.hasOwnProperty.call(e.handlers,c.kind)||typeof e.handlers[c.kind]!="function")throw new a.ReportJobError("input","报表任务处理器未注册");const p={kind:c.kind,payload:JSON.parse(a.serializeJobJson(c.payload,{maxNodes:19e3,maxCharacters:75e4}))},d=await i(c.scope,c.id);if(d){if(a.serializeJobJson(d.request)!==a.serializeJobJson(p))throw new a.ReportJobError("conflict","相同任务ID不能提交不同内容");return d}const f=await ee(e.store,c.scope,c.id,p);if(f)return f;const g=t.now(),w={scope:c.scope,id:c.id,revision:1,request:p,status:"queued",createdAt:g,updatedAt:g,attempt:0};if(!await e.store.compareAndSwap(c.scope,c.id,null,w)){const m=await i(c.scope,c.id);if(m&&a.serializeJobJson(m.request)===a.serializeJobJson(p))return m;const y=await ee(e.store,c.scope,c.id,p);if(y)return y;throw new a.ReportJobError("conflict","报表任务提交发生冲突")}return a.cloneJob(w)},get:i,runNext:c=>{if(s)return Promise.reject(new a.ReportJobError("closed","报表任务服务已关闭"));if(n>=t.concurrency)return Promise.reject(new a.ReportJobError("capacity","报表任务执行槽位已满"));n++;const p=new AbortController;r.add(p);const d=(async()=>{try{const f=await Be(e,c,t.leaseMs,t.now());return f?.status==="running"?await Ne(e,t,f,p):f}finally{n--,r.delete(p)}})();return o.add(d),d.then(()=>o.delete(d),()=>o.delete(d)),d},get active(){return n},cancel:async(c,p)=>{const d=await C(e.store,c,p);return d.status!=="queued"&&d.status!=="running"?d:F(e.store,d,{updatedAt:t.now(),...d.status==="queued"?{status:"cancelled"}:{cancelRequested:!0}})},retry:async(c,p,d)=>{const f=await C(e.store,c,p);if(f.revision!==d||f.status!=="failed")throw new a.ReportJobError("conflict","仅可重试当前修订的失败任务");const g={...f,status:"queued",updatedAt:t.now()};return delete g.error,delete g.progress,F(e.store,f,g,["error","progress"])},prune:async c=>{if(!e.store.prune||!e.store.readTombstone)throw new a.ReportJobError("input","当前任务适配器未实现可选终态保留能力");return e.store.prune({...c,now:t.now()})},close:async()=>{s=!0;for(const c of r)c.abort(new a.ReportJobError("closed","任务服务正在关闭"));await Promise.allSettled([...o])}}}function le(e,t){const r=e.assets,o=e[t];if(!(!r&&!o?.assetRenderers))return{...r,...o?.assetFailure===void 0?{}:{assetFailure:o.assetFailure},...o?.onDiagnostic===void 0?{}:{onDiagnostic:o.onDiagnostic},assetRenderers:{...r?.assetRenderers,...o?.assetRenderers},assetBudget:{...r?.assetBudget,...o?.assetBudget}}}function te(e,t){return!e||e.code!=="missing-image"||e.format!=="pdf"&&e.format!=="xlsx"?!1:typeof le(t,e.format)?.assetRenderers?.[e.kind]=="function"}function Te(e,t){const r=R.reviewReportTemplate(e,t),o=r.issues.filter(n=>!te(n.diagnostic,t)),s=r.samples.map(n=>({...n,diagnostics:n.diagnostics.filter(i=>!te(i,t))}));return{...r,issues:o,samples:s,ok:o.every(n=>n.severity!=="error"),artifacts:[]}}async function Me(e,t,r,o,s){const n=V({reports:{sample:{template:r,datasets:e.datasets}},assets:le(o,t),budget:{maxRows:o.maxSampleRows??1e3,maxPages:o.maxPages??100,maxCells:o.maxCells??25e4,maxOutputBytes:o.maxOutputBytes??2e7,maxDurationMs:o.maxDurationMs??3e4}});try{const{result:i,digest:l}=await a.controlled(o.signal,o.maxDurationMs??3e4,async u=>{const c=await n.export({reportIds:["sample"],params:e.params,format:t,signal:u,fidelity:o.strictOutputs?"strict":"warn",pdf:o.pdf,xlsx:o.xlsx}),p=c.diagnostics.filter(f=>f.severity!=="info");if(o.strictOutputs&&p.length)throw new Error(`Strict ${t} encoding found fidelity issues: ${p.slice(0,3).map(f=>f.message).join("; ")}`);const d=await o.digest?.(c.bytes);return a.throwIfAborted(u),await o.onArtifact?.(e.name,c),a.throwIfAborted(u),{result:c,digest:d}});s.artifacts.push({fixture:e.name,format:t,bytes:i.bytes.byteLength,pages:i.stats.pages,...l?{digest:l}:{}}),s.issues.push(...i.diagnostics.map(u=>({code:"output",severity:o.strictOutputs||u.severity==="error"?"error":"warning",path:"$.template",fixture:e.name,message:`${t}: ${u.message}`})))}catch(i){a.throwIfAborted(o.signal),s.issues.push({code:"output",severity:"error",path:"$.template",fixture:e.name,message:`${t}: ${i instanceof Error?i.message:String(i)}`})}}async function $e(e,t={}){a.throwIfAborted(t.signal);const r=Te(e,t);if(!r.ok)return r;const o=ne.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 i of s)a.throwIfAborted(t.signal),!(i!=="pdf"&&i!=="xlsx")&&await Me(n,i,o,t,r);return r.ok=r.issues.every(n=>n.severity!=="error"),r}class h extends Error{constructor(t,r){super(r),this.code=t,this.name="ReportInstanceError"}}function B(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 h("input","实例范围应非空,ID 应为安全标识")}function De(e,t){const r=Object.getPrototypeOf(e);if(r!==(t?Array.prototype:Object.prototype)&&!(r===null&&!t)||Object.getOwnPropertySymbols(e).length)throw new h("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 h("input","实例数组不能包含额外属性");if(Object.getOwnPropertyNames(e).filter(s=>!(t&&s==="length")).length!==Object.keys(e).length)throw new h("input","实例不能包含不可枚举属性")}function Ce(e){if(!Number.isSafeInteger(e.revision)||e.revision<1||typeof e.title!="string"||!e.title.trim()||e.title.length>512)throw new h("input","实例修订或标题无效");if(typeof e.generatedAt!="string"||!Number.isFinite(Date.parse(e.generatedAt))||new Date(e.generatedAt).toISOString()!==e.generatedAt)throw new h("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 h("input","实例报表 ID 应非空且唯一")}function qe(e){return e===null||typeof e=="boolean"||typeof e=="string"||typeof e=="number"&&Number.isFinite(e)}function fe(e,t){if(!Number.isSafeInteger(t)||t<1)throw new h("input","实例快照字节预算应为正安全整数");let r=0,o=0;const s=new Set;function n(l,u){if(++r>1e6||u>64)throw new h("capacity","实例节点或嵌套深度超过预算");if(typeof l=="string"&&(o+=l.length,o>t))throw new h("capacity","实例文本超过预算");if(qe(l))return l;if(!l||typeof l!="object"||s.has(l))throw new h("input","实例只允许无循环的有限 JSON 值");const c=Array.isArray(l);De(l,c),s.add(l);const p=Object.create(null);for(const d of Object.keys(l)){if(o+=d.length,o>t)throw new h("capacity","实例文本超过预算");const f=Object.getOwnPropertyDescriptor(l,d);if(f.get||f.set||["__proto__","constructor","prototype"].includes(d))throw new h("input","实例不能包含访问器或危险键");f.value!==void 0&&(p[d]=n(f.value,u+1))}if(s.delete(l),c){if(Object.keys(p).length!==l.length)throw new h("input","实例数组不能稀疏或包含额外属性");return Array.from({length:l.length},(d,f)=>p[String(f)])}return p}const i=JSON.stringify(n(e,0));if(new TextEncoder().encode(i).byteLength>t)throw new h("capacity","实例快照超过单条字节预算");return i}function q(e,t=8e6){const r=JSON.parse(fe(e,t));B(r.scope,r.id);const o=new Set(["scope","id","revision","title","generatedAt","reportIds","params","templateRevisions","sourceRevisions","plan","artifacts","output"]);if(Object.keys(r).some(n=>!o.has(n)))throw new h("input","实例包含未知字段");Ce(r);for(const n of[r.params,r.templateRevisions,r.sourceRevisions])if(!n||typeof n!="object"||Array.isArray(n)||Object.values(n).some(i=>typeof i!="string"))throw new h("input","实例参数和修订应为字符串字典");if(r.reportIds.some(n=>!r.templateRevisions[n]))throw new h("input","每张报表都应记录生成时的模板修订");const s=oe.validateRenderPlan(r.plan);if(!s.ok)throw new h("input",`实例渲染计划无效:${s.errors[0]?.path}`);if(r.output!==void 0){if(!r.output||Object.keys(r.output).some(n=>!["stats","diagnostics","layout"].includes(n)))throw new h("input","实例输出元数据只允许统计、诊断和字体度量;不保存来源令牌");ce({...r.output,plan:r.plan,revisions:{}})}return r.artifacts!==void 0&&ze(r.artifacts),r}function ze(e){if(!Array.isArray(e)||e.length>100)throw new h("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 h("input","实例文件应包含唯一存储键、格式、大小和可选 SHA256");t.add(r.key)}}function pe(e){const{scope:t,id:r,revision:o,title:s,generatedAt:n,reportIds:i,params:l,templateRevisions:u,sourceRevisions:c}=e;return JSON.parse(JSON.stringify({scope:t,id:r,revision:o,title:s,generatedAt:n,reportIds:i,params:l,templateRevisions:u,sourceRevisions:c}))}function Le(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 h("input","实例存储预算应为正安全整数");return t}function _e(e={}){const t=Le(e),r=new Map;let o=0;return{read:async(s,n,i,l)=>{a.throwIfAborted(l),B(s,n);const u=r.get(JSON.stringify([s,n])),c=u?.get(i??u.size);return c?q(c,t.maxSnapshotBytes):void 0},list:async(s,n={})=>{a.throwIfAborted(n.signal),B(s,"list");const i=n.limit??25;if(!Number.isSafeInteger(i)||i<1||i>100)throw new h("input","实例每页数量应为 1–100");const l=Array.from(r.values(),u=>u.get(u.size)).filter(u=>u.scope===s&&(!n.after||u.id>n.after)&&(!n.reportId||u.reportIds.includes(n.reportId))).sort((u,c)=>u.id<c.id?-1:1).slice(0,i+1);return{items:l.slice(0,i).map(pe),...l.length>i?{next:l[i-1].id}:{}}},compareAndSwap:async(s,n,i,l,u)=>{a.throwIfAborted(u),B(s,n);const c=q(l,t.maxSnapshotBytes);if(c.scope!==s||c.id!==n||c.revision!==(i??0)+1)throw new h("input","实例身份或修订不一致");const p=JSON.stringify([s,n]),d=r.get(p)??new Map;if((d.size||null)!==i)return!1;const f=new TextEncoder().encode(JSON.stringify(c)).byteLength;if(d.size>=t.maxRevisions||o+f>t.maxBytes||!d.size&&r.size>=t.maxInstances)throw new h("capacity","实例存储达到预算,请使用持久化归档策略或显式调整容量");return d.set(c.revision,c),r.set(p,d),o+=f,!0}}}function we(e,t={}){const r=t.maxSnapshotBytes??8e6;if(!Number.isSafeInteger(r)||r<1)throw new h("input","实例快照字节预算应为正安全整数");return{read:e.read.bind(e),list:e.list.bind(e),save:async(o,s)=>{const n=s.expectedRevision;if(n!==null&&(!Number.isSafeInteger(n)||n<1||n>=Number.MAX_SAFE_INTEGER))throw new h("input","实例预期修订无效");const i=JSON.parse(fe(o,r)),l=q({...i,revision:(n??0)+1},r);if(a.throwIfAborted(s.signal),!await e.compareAndSwap(l.scope,l.id,n,l,s.signal))throw new h("conflict","实例已存在或已变化,请显式确认修订后保存");return l}}}function Ue(e,t){return a.serializeJobJson({reportIds:e,params:t})}function Ve(e){if(!e||typeof e!="object"||Object.getOwnPropertySymbols(e).length)throw new h("input","生成请求应为普通对象");const t=Object.create(null);let r;const o=new Set(["scope","id","title","reportIds","params","expectedRevision","signal"]);for(const s of Object.getOwnPropertyNames(e)){const n=Object.getOwnPropertyDescriptor(e,s);if(!o.has(s)||!n.enumerable||n.get||n.set)throw new h("input","生成请求不能包含未知字段或访问器");s==="signal"?r=n.value:n.value!==void 0&&(t[s]=n.value)}return{signal:r,request:JSON.parse(a.serializeJobJson(t))}}function He(e){const t=JSON.parse(a.serializeJobJson(e.templateRevisions)),r=N(e.pdf),o=we(e.instances,{maxSnapshotBytes:e.maxSnapshotBytes});return{async generate(s){const{signal:n,request:i}=Ve(s);if(B(i.scope,i.id),i.expectedRevision!==null&&(!Number.isSafeInteger(i.expectedRevision)||i.expectedRevision<1))throw new h("input","实例预期修订无效");const l=e.runtime.validate(i);if(!l.ok)throw new j.ReportParamValidationError(l.issues);const u=Object.create(null);for(const m of i.reportIds){if(typeof t[m]!="string"||!t[m])throw new TypeError(`报表 ${m} 缺少生成时的模板修订`);u[m]=t[m]}if(a.throwIfAborted(n),((await e.instances.read(i.scope,i.id,void 0,n))?.revision??null)!==i.expectedRevision)throw new h("conflict","实例已存在或已变化,请显式确认修订后生成");const p=await e.runtime.prepare({reportIds:i.reportIds,params:l.values,pdf:r,signal:n});a.throwIfAborted(n);const d=Object.create(null);for(const[m,y]of Object.entries(p.revisions))y.revision!==void 0&&(d[m]=y.revision);const{plan:f,revisions:g,...w}=p;return o.save({scope:i.scope,id:i.id,title:i.title,reportIds:i.reportIds,params:l.values,templateRevisions:u,sourceRevisions:d,generatedAt:(e.now?.()??new Date).toISOString(),plan:f,output:w},{expectedRevision:i.expectedRevision,signal:n})},read:o.read,list:o.list,async exportInstance(s){const{scope:n,id:i,revision:l,signal:u,format:c,fidelity:p,taskId:d,correlationId:f,onEvent:g}=s,w=N(s.pdf??r),m=U(s.xlsx);B(n,i),a.throwIfAborted(u);const y=await o.read(n,i,l,u);if(!y)throw new h("input","报表实例不存在");const b={plan:y.plan,revisions:Object.fromEntries(y.reportIds.map(E=>[E,{revision:y.sourceRevisions[E]}])),diagnostics:[{code:"instance-row-count",severity:"info",message:"历史实例未保存原始取数行数;本次 rows 统计为 0,页面及单元格数由已保存计划校验。"}],stats:{rows:0,pages:y.plan.pages.length,cells:0,durationMs:0},...y.output};return e.runtime.exportPrepared({prepared:b,format:c,fidelity:p,pdf:w,xlsx:m,signal:u,taskId:d,correlationId:f,onEvent:g})},save:o.save}}function $(e,t,r){if(!Number.isSafeInteger(e)||e<1||e>t)throw new RangeError(`${r} 应为 1–${t} 的安全整数`);return e}function re(e){if(!e||typeof e.key!="string"||!e.key.trim()||e.key.length>1024||!["pdf","xlsx"].includes(e.format)||!Number.isSafeInteger(e.bytes)||e.bytes<0||e.sha256!==void 0&&!/^[a-f0-9]{64}$/i.test(e.sha256))throw new TypeError("分批归档回执应包含存储键、格式、大小和可选 SHA256");return{key:e.key,format:e.format,bytes:e.bytes,...e.sha256?{sha256:e.sha256}:{}}}function Ke(e){if(!ne.validateReportTemplate(e).ok||!e.repeat)throw new TypeError("分批生成仅支持有效的逐记录固定标签模板");return JSON.parse(JSON.stringify(e))}function Qe(e){const t=new Set,r=e.repeat;r.rowKey&&t.add(r.rowKey),typeof r.copies=="object"&&t.add(r.copies.field);const o=s=>{s.binding&&t.add(s.binding.field);for(const n of s.grid?.cells??[])for(const i of n)i?.children?.forEach(o)};return e.pages.forEach(s=>s.components.forEach(n=>o(n))),[...t]}function Xe(e,t,r,o){if(!e||typeof e!="object"||Array.isArray(e))throw new TypeError(`标签记录 ${o} 应为对象`);const s=Object.create(null);for(const n of t){const i=ae.readRecordScalar(e,n,{dataset:r,rowIndex:o});if(typeof i=="string"&&i.length>1e6)throw new a.ReportRuntimeError("budget","标签字段超过 1 MB 字符预算",`$.datasets.${r}[${o}].${n}`);i!==void 0&&(s[n]=i)}return s}function Ge(e,t,r,o){const s=t.repeat;if(!s.rowKey)return;const n=ae.readRecordScalar(e,s.rowKey,{rowIndex:o,dataset:s.dataset});if(!(typeof n=="string"&&n.trim()||typeof n=="number"&&Number.isFinite(n)))throw new TypeError(`标签记录 ${o} 的业务主键无效`);const i=JSON.stringify([typeof n,n]);if(r.keys.has(i))throw new TypeError(`标签记录 ${o} 的业务主键重复(包含先前批次)`);r.bytes+=i.length*2+64,r.keys.add(i)}function We(e){return Object.entries(e).reduce((t,[r,o])=>t+64+r.length*2+(typeof o=="string"?o.length*2:8),0)}function Ze(e,t){if(!t)return e;for(const r of e.plan.pages){const o=r.meta?.record;o&&typeof o=="object"&&"rowIndex"in o&&typeof o.rowIndex=="number"&&(o.rowIndex+=t)}return e}async function Ye(e,t){if(!e.return)return;const r=Promise.resolve(e.return());if(t.aborted){r.catch(()=>{});return}await a.controlled(t,void 0,()=>r)}async function se(e,t,r){const o=Promise.resolve().then(()=>e.onReceipt?.(t,r));o.catch(()=>{}),await a.controlled(r.signal,void 0,()=>o)}function et(e,t,r){return new Promise((o,s)=>{let n=!1,i=!1,l;const u=()=>{clearTimeout(l),t.removeEventListener("abort",c)},c=()=>{n||l!==void 0||(l=setTimeout(()=>{if(!n){n=!0,i=!0,u();try{a.throwIfAborted(t)}catch(p){s(p)}}},0))};e.then(p=>{if(i){Promise.resolve().then(()=>r(p)).catch(()=>{});return}n||(n=!0,u(),o(p))},p=>{n||(n=!0,u(),s(p))}),t.addEventListener("abort",c,{once:!0}),t.aborted&&c()})}async function tt(e,t){const r=$(t.batchSize??100,1e3,"batchSize"),o=$(t.maxRows??1e5,1e6,"maxRows"),s=$(t.maxChunks??1e3,1e4,"maxChunks"),n=$(t.maxRetainedBytes??16e6,64e6,"maxRetainedBytes"),i=Ke(t.template),l=Qe(i);if(!e||typeof e[Symbol.asyncIterator]!="function")throw new TypeError("标签来源应为 AsyncIterable");return a.controlled(t.signal,t.runtime?.budget?.maxDurationMs??12e4,async u=>{const c={rows:0,chunks:[]},p={keys:new Set,bytes:0},d=e[Symbol.asyncIterator]();let f=!1,g=!1,w;const m=()=>w??=Ye(d,u),y=()=>{f||m().catch(()=>{})};u.addEventListener("abort",y,{once:!0});try{for(;!f;){a.throwIfAborted(u);const b=[];let E=0;for(;b.length<r;){const J=await a.controlled(u,void 0,()=>Promise.resolve(d.next()));if(J.done){f=!0;break}if(c.rows+b.length>=o)throw new a.ReportRuntimeError("budget","标签来源行数超过预算","$.maxRows");if(c.chunks.length>=s)throw new a.ReportRuntimeError("budget","标签分块数量超过预算","$.maxChunks");const x=Xe(J.value,l,i.repeat.dataset,c.rows+b.length);if(Ge(x,i,p,c.rows+b.length),E+=We(x),p.bytes+E>n)throw new a.ReportRuntimeError("budget","标签当前块字段与全局主键索引超过内存预算","$.maxRetainedBytes");b.push(x)}if(!b.length)break;const v=V({...t.runtime,reports:{labels:{template:i,datasets:{[i.repeat.dataset]:b}}}});let S;const I={index:c.chunks.length,rowOffset:c.rows,rowCount:b.length,signal:u,export:J=>v.exportPrepared({pdf:t.pdf,...J,prepared:S,signal:u})};let k;const O=(await a.runReportBatch([{id:`labels-${I.index}`,params:{}}],async()=>{try{S=Ze(await v.prepare({reportIds:["labels"],pdf:t.pdf,signal:u}),I.rowOffset),a.throwIfAborted(u);const J=Promise.resolve(t.execute(S,I)),x=await et(J,u,P=>se(t,re(P),I));return re(x)}catch(J){throw k=J,J}},{concurrency:1,signal:u,failure:"stop"}))[0];if(O.status==="cancelled")throw a.throwIfAborted(u),new Error("标签分批任务已取消");if(O.status==="failed")throw k??new Error(O.error.message);c.chunks.push({...O.value,index:I.index,rowOffset:I.rowOffset,rowCount:I.rowCount}),c.rows+=b.length,await se(t,O.value,I)}return c}catch(b){throw g=!0,b}finally{u.removeEventListener("abort",y),f||await m().catch(b=>{if(!g)throw b})}})}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=h;exports.checkInstanceIdentity=B;exports.createMemoryReportInstanceStore=_e;exports.createReportGenerationService=He;exports.createReportInstanceManager=we;exports.createReportJobService=Fe;exports.createReportRuntime=V;exports.createReportTaskQueue=Ae;exports.reportInstanceParameterKey=Ue;exports.reportInstanceSummary=pe;exports.reviewReportPublication=$e;exports.runLabelStream=tt;exports.snapshotReportInstance=q;
|
package/dist/server.d.cts
CHANGED
|
@@ -136,12 +136,19 @@ export declare function createReportGenerationService(options: {
|
|
|
136
136
|
runtime: ReportRuntime;
|
|
137
137
|
instances: ReportInstanceStore;
|
|
138
138
|
templateRevisions: Record<string, string>;
|
|
139
|
+
pdf?: ReportPdfFontOptions;
|
|
139
140
|
maxSnapshotBytes?: number;
|
|
140
141
|
now?: () => Date;
|
|
141
142
|
}): {
|
|
142
143
|
generate(input: ReportGenerationInput): Promise<ReportInstanceSnapshot>;
|
|
143
144
|
read: (scope: string, id: string, revision?: number, signal?: AbortSignal) => Promise<ReportInstanceSnapshot | undefined>;
|
|
144
145
|
list: (scope: string, options?: ReportInstanceListOptions) => Promise<ReportInstancePage>;
|
|
146
|
+
/** Read an immutable saved revision and encode its plan, never re-query the business source. */
|
|
147
|
+
exportInstance(input: {
|
|
148
|
+
scope: string;
|
|
149
|
+
id: string;
|
|
150
|
+
revision?: number;
|
|
151
|
+
} & Omit<ReportRuntimePreparedExportInput, "prepared">): Promise<ReportRuntimeExportResult>;
|
|
145
152
|
/** Instance edits are explicit snapshots; source business persistence remains the Provider.save responsibility. */
|
|
146
153
|
save: (input: Omit<ReportInstanceSnapshot, "revision">, options: {
|
|
147
154
|
expectedRevision: number | null;
|
|
@@ -229,6 +236,49 @@ declare interface GridCell {
|
|
|
229
236
|
|
|
230
237
|
declare type ImageComponentKind = "image" | "chart" | "barcode" | "qrcode";
|
|
231
238
|
|
|
239
|
+
export declare interface LabelStreamContext {
|
|
240
|
+
index: number;
|
|
241
|
+
rowOffset: number;
|
|
242
|
+
rowCount: number;
|
|
243
|
+
signal: AbortSignal;
|
|
244
|
+
/** Encode this chunk with the same runtime, resources, fonts, signal and budgets. */
|
|
245
|
+
export(input: Omit<ReportRuntimePreparedExportInput, "prepared" | "signal">): Promise<ReportRuntimeExportResult>;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export declare interface LabelStreamManifest {
|
|
249
|
+
rows: number;
|
|
250
|
+
chunks: Array<LabelStreamReceipt & {
|
|
251
|
+
index: number;
|
|
252
|
+
rowOffset: number;
|
|
253
|
+
rowCount: number;
|
|
254
|
+
}>;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export declare interface LabelStreamOptions {
|
|
258
|
+
template: ReportTemplate;
|
|
259
|
+
batchSize?: number;
|
|
260
|
+
maxRows?: number;
|
|
261
|
+
maxChunks?: number;
|
|
262
|
+
/** Conservative retained scalar/key size (UTF-16 + field overhead), default 16 MB. */
|
|
263
|
+
maxRetainedBytes?: number;
|
|
264
|
+
signal?: AbortSignal;
|
|
265
|
+
/** Shared existing runtime budgets/assets; callbacks never cross a Worker boundary. */
|
|
266
|
+
runtime?: Omit<ReportRuntimeOptions, "reports" | "executor">;
|
|
267
|
+
pdf?: ReportPdfFontOptions;
|
|
268
|
+
/** Persist each artifact here; retain only its small receipt in the manifest. */
|
|
269
|
+
execute(prepared: PreparedReport, context: LabelStreamContext): Promise<LabelStreamReceipt>;
|
|
270
|
+
/** Awaited after commit and before pulling more source rows. A failure stops consumption. */
|
|
271
|
+
onReceipt?(receipt: LabelStreamReceipt, context: LabelStreamContext): void | Promise<void>;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export declare interface LabelStreamReceipt {
|
|
275
|
+
/** Private artifact storage key, not a credential-bearing URL. */
|
|
276
|
+
key: string;
|
|
277
|
+
format: "pdf" | "xlsx";
|
|
278
|
+
bytes: number;
|
|
279
|
+
sha256?: string;
|
|
280
|
+
}
|
|
281
|
+
|
|
232
282
|
/** auto:真实数字/显式数值格式居右,日期与布尔居中,其他内容居左。 */
|
|
233
283
|
declare type ListAlignment = NonNullable<ComponentStyle["align"]> | "auto";
|
|
234
284
|
|
|
@@ -498,6 +548,11 @@ export declare interface PreparedReport {
|
|
|
498
548
|
revision?: string;
|
|
499
549
|
sourceToken?: string;
|
|
500
550
|
}>;
|
|
551
|
+
/** Captured metrics identity; absence on old saved instances remains supported with diagnostics. */
|
|
552
|
+
layout?: {
|
|
553
|
+
textMetrics: "heuristic" | "provided" | "font-bytes";
|
|
554
|
+
fontFingerprint?: string;
|
|
555
|
+
};
|
|
501
556
|
}
|
|
502
557
|
|
|
503
558
|
declare type PublicationAssets = Omit<AssetRenderOptions, "signal">;
|
|
@@ -583,6 +638,14 @@ declare interface ReportCellTableIdentity {
|
|
|
583
638
|
|
|
584
639
|
declare type ReportCellValue = string | number | boolean | null;
|
|
585
640
|
|
|
641
|
+
declare interface ReportDataTarget {
|
|
642
|
+
datasetId: string;
|
|
643
|
+
field: string;
|
|
644
|
+
rowKey?: string | number;
|
|
645
|
+
/** Use table identity when the same dataset appears in several tables. */
|
|
646
|
+
tableId?: string;
|
|
647
|
+
}
|
|
648
|
+
|
|
586
649
|
declare interface ReportDefinition {
|
|
587
650
|
/** 静态模板或宿主提供的异步模板加载器;动态模板默认每次重新读取,不缓存版本。 */
|
|
588
651
|
template: ReportTemplate | ReportTemplateLoader;
|
|
@@ -617,6 +680,9 @@ declare interface ReportDiagnostic {
|
|
|
617
680
|
message: string;
|
|
618
681
|
path?: string;
|
|
619
682
|
severity: "warning" | "error" | "info";
|
|
683
|
+
/** Optional explanation supplied by the business source, not inferred from blank cells. */
|
|
684
|
+
valueState?: ReportValueState;
|
|
685
|
+
target?: ReportDataTarget;
|
|
620
686
|
}
|
|
621
687
|
|
|
622
688
|
declare type ReportExpression = {
|
|
@@ -704,6 +770,8 @@ export declare interface ReportInstanceSnapshot {
|
|
|
704
770
|
templateRevisions: Record<string, string>;
|
|
705
771
|
sourceRevisions: Record<string, string>;
|
|
706
772
|
plan: RenderPlan;
|
|
773
|
+
/** Exact generation diagnostics, row statistics and font metrics; optional for legacy instances. */
|
|
774
|
+
output?: Omit<PreparedReport, "plan" | "revisions">;
|
|
707
775
|
/** Private storage keys; signed download URLs must be generated by the host after authorization. */
|
|
708
776
|
artifacts?: ReportInstanceArtifact[];
|
|
709
777
|
}
|
|
@@ -715,7 +783,7 @@ export declare interface ReportInstanceStore {
|
|
|
715
783
|
compareAndSwap(scope: string, id: string, expectedRevision: number | null, next: ReportInstanceSnapshot, signal?: AbortSignal): Promise<boolean>;
|
|
716
784
|
}
|
|
717
785
|
|
|
718
|
-
export declare type ReportInstanceSummary = Omit<ReportInstanceSnapshot, "plan" | "artifacts">;
|
|
786
|
+
export declare type ReportInstanceSummary = Omit<ReportInstanceSnapshot, "plan" | "artifacts" | "output">;
|
|
719
787
|
|
|
720
788
|
export declare function reportInstanceSummary(snapshot: ReportInstanceSnapshot): ReportInstanceSummary;
|
|
721
789
|
|
|
@@ -893,6 +961,18 @@ declare interface ReportParamValidation {
|
|
|
893
961
|
issues: ReportParamIssue[];
|
|
894
962
|
}
|
|
895
963
|
|
|
964
|
+
/** Licensed local font bytes; never downloaded implicitly by the runtime. */
|
|
965
|
+
export declare interface ReportPdfFontOptions {
|
|
966
|
+
customFontBytes?: Uint8Array | ArrayBuffer;
|
|
967
|
+
customFontName?: string;
|
|
968
|
+
customFontFaces?: {
|
|
969
|
+
regular: Uint8Array | ArrayBuffer;
|
|
970
|
+
bold?: Uint8Array | ArrayBuffer;
|
|
971
|
+
italic?: Uint8Array | ArrayBuffer;
|
|
972
|
+
boldItalic?: Uint8Array | ArrayBuffer;
|
|
973
|
+
};
|
|
974
|
+
}
|
|
975
|
+
|
|
896
976
|
/** 查询是唯一基础能力;权限、HTTP、数据库和事务都留在宿主适配器内。 */
|
|
897
977
|
declare interface ReportProvider {
|
|
898
978
|
query(context: ReportLoadContext): ReportQueryResult | Promise<ReportQueryResult>;
|
|
@@ -953,6 +1033,7 @@ export declare interface ReportRuntime {
|
|
|
953
1033
|
validate(input: Omit<ReportRuntimeInput, "signal">): ReportParamValidation;
|
|
954
1034
|
prepare(input: ReportRuntimeInput): Promise<PreparedReport>;
|
|
955
1035
|
export(input: ReportRuntimeExportInput): Promise<ReportRuntimeExportResult>;
|
|
1036
|
+
exportPrepared(input: ReportRuntimePreparedExportInput): Promise<ReportRuntimeExportResult>;
|
|
956
1037
|
}
|
|
957
1038
|
|
|
958
1039
|
export declare interface ReportRuntimeBudget {
|
|
@@ -960,6 +1041,8 @@ export declare interface ReportRuntimeBudget {
|
|
|
960
1041
|
maxPages?: number;
|
|
961
1042
|
maxCells?: number;
|
|
962
1043
|
maxOutputBytes?: number;
|
|
1044
|
+
/** Bound the plain JSON snapshot accepted by exportPrepared (default 64 MB). */
|
|
1045
|
+
maxPreparedBytes?: number;
|
|
963
1046
|
maxDurationMs?: number;
|
|
964
1047
|
}
|
|
965
1048
|
|
|
@@ -971,6 +1054,8 @@ export declare class ReportRuntimeError extends Error {
|
|
|
971
1054
|
|
|
972
1055
|
/** 可用 worker_threads/进程/RPC 实现;接收可序列化请求,signal 由桥接层映射为取消消息。 */
|
|
973
1056
|
export declare interface ReportRuntimeExecutor {
|
|
1057
|
+
/** Old custom executors may omit this; the runtime explicitly rejects unsupported prepared output. */
|
|
1058
|
+
exportPrepared?(input: Omit<ReportRuntimePreparedExportInput, "signal" | "onEvent">, signal?: AbortSignal, onEvent?: ReportTaskObserver): Promise<ReportRuntimeExportResult>;
|
|
974
1059
|
prepare(input: Omit<ReportRuntimeInput, "signal" | "onEvent">, signal?: AbortSignal, onEvent?: ReportTaskObserver): Promise<PreparedReport>;
|
|
975
1060
|
export(input: Omit<ReportRuntimeExportInput, "signal" | "onEvent">, signal?: AbortSignal, onEvent?: ReportTaskObserver): Promise<ReportRuntimeExportResult>;
|
|
976
1061
|
}
|
|
@@ -979,17 +1064,6 @@ export declare interface ReportRuntimeExportInput extends ReportRuntimeInput {
|
|
|
979
1064
|
format: "pdf" | "xlsx";
|
|
980
1065
|
/** strict 在编码前拒绝已识别的输出降级;默认保留诊断并继续。 */
|
|
981
1066
|
fidelity?: "warn" | "strict";
|
|
982
|
-
/** PDF 中文需宿主显式提供有授权的字体;不隐式下载字体或资源。 */
|
|
983
|
-
pdf?: {
|
|
984
|
-
customFontBytes?: Uint8Array | ArrayBuffer;
|
|
985
|
-
customFontName?: string;
|
|
986
|
-
customFontFaces?: {
|
|
987
|
-
regular: Uint8Array | ArrayBuffer;
|
|
988
|
-
bold?: Uint8Array | ArrayBuffer;
|
|
989
|
-
italic?: Uint8Array | ArrayBuffer;
|
|
990
|
-
boldItalic?: Uint8Array | ArrayBuffer;
|
|
991
|
-
};
|
|
992
|
-
};
|
|
993
1067
|
xlsx?: {
|
|
994
1068
|
sheetMode?: "auto" | "pages" | "continuous";
|
|
995
1069
|
valueMode?: "text" | "raw";
|
|
@@ -1007,6 +1081,8 @@ export declare interface ReportRuntimeInput extends ReportTaskMonitoring {
|
|
|
1007
1081
|
reportIds: string[];
|
|
1008
1082
|
params?: Record<string, string>;
|
|
1009
1083
|
signal?: AbortSignal;
|
|
1084
|
+
/** Prepare using the same licensed font bytes later supplied to PDF output. */
|
|
1085
|
+
pdf?: ReportPdfFontOptions;
|
|
1010
1086
|
}
|
|
1011
1087
|
|
|
1012
1088
|
export declare interface ReportRuntimeOptions {
|
|
@@ -1019,6 +1095,16 @@ export declare interface ReportRuntimeOptions {
|
|
|
1019
1095
|
executor?: ReportRuntimeExecutor;
|
|
1020
1096
|
}
|
|
1021
1097
|
|
|
1098
|
+
/** Encode an existing plan without querying providers or repaginating. */
|
|
1099
|
+
export declare interface ReportRuntimePreparedExportInput extends ReportTaskMonitoring {
|
|
1100
|
+
prepared: PreparedReport;
|
|
1101
|
+
format: ReportRuntimeExportInput["format"];
|
|
1102
|
+
fidelity?: ReportRuntimeExportInput["fidelity"];
|
|
1103
|
+
pdf?: ReportPdfFontOptions;
|
|
1104
|
+
xlsx?: ReportRuntimeExportInput["xlsx"];
|
|
1105
|
+
signal?: AbortSignal;
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1022
1108
|
export declare interface ReportRuntimeStats {
|
|
1023
1109
|
rows: number;
|
|
1024
1110
|
pages: number;
|
|
@@ -1202,6 +1288,9 @@ declare interface ReportTemplateReviewOptions {
|
|
|
1202
1288
|
|
|
1203
1289
|
declare type ReportTemplateSummary = Omit<ReportTemplateDocument, "template">;
|
|
1204
1290
|
|
|
1291
|
+
/** Optional business explanations never replace raw data or schema validation. */
|
|
1292
|
+
declare type ReportValueState = "missing-source" | "not-applicable" | "not-calculable";
|
|
1293
|
+
|
|
1205
1294
|
/** Publication gate with actual sequential PDF/XLSX encoding, no business query or implicit save. */
|
|
1206
1295
|
export declare function reviewReportPublication(input: unknown, options?: ReportPublicationOptions): Promise<ReportPublicationReview>;
|
|
1207
1296
|
|
|
@@ -1221,6 +1310,12 @@ declare interface RichSegment {
|
|
|
1221
1310
|
style?: ComponentStyle;
|
|
1222
1311
|
}
|
|
1223
1312
|
|
|
1313
|
+
/** Bounded fixed-label consumption, not cross-chunk aggregation or a new durable task queue.
|
|
1314
|
+
* The next source chunk is pulled only after execute + onReceipt complete. Earlier receipts
|
|
1315
|
+
* remain committed if a later chunk fails; use onReceipt for a durable incremental manifest.
|
|
1316
|
+
*/
|
|
1317
|
+
export declare function runLabelStream(source: AsyncIterable<object>, options: LabelStreamOptions): Promise<LabelStreamManifest>;
|
|
1318
|
+
|
|
1224
1319
|
export declare function runnableJob(record: ReportJobRecord, now: number): boolean;
|
|
1225
1320
|
|
|
1226
1321
|
/** Browser/Node shared bounded runner. Return small receipts; persist/export large artifacts inside execute. */
|
package/dist/server.d.ts
CHANGED
|
@@ -136,12 +136,19 @@ export declare function createReportGenerationService(options: {
|
|
|
136
136
|
runtime: ReportRuntime;
|
|
137
137
|
instances: ReportInstanceStore;
|
|
138
138
|
templateRevisions: Record<string, string>;
|
|
139
|
+
pdf?: ReportPdfFontOptions;
|
|
139
140
|
maxSnapshotBytes?: number;
|
|
140
141
|
now?: () => Date;
|
|
141
142
|
}): {
|
|
142
143
|
generate(input: ReportGenerationInput): Promise<ReportInstanceSnapshot>;
|
|
143
144
|
read: (scope: string, id: string, revision?: number, signal?: AbortSignal) => Promise<ReportInstanceSnapshot | undefined>;
|
|
144
145
|
list: (scope: string, options?: ReportInstanceListOptions) => Promise<ReportInstancePage>;
|
|
146
|
+
/** Read an immutable saved revision and encode its plan, never re-query the business source. */
|
|
147
|
+
exportInstance(input: {
|
|
148
|
+
scope: string;
|
|
149
|
+
id: string;
|
|
150
|
+
revision?: number;
|
|
151
|
+
} & Omit<ReportRuntimePreparedExportInput, "prepared">): Promise<ReportRuntimeExportResult>;
|
|
145
152
|
/** Instance edits are explicit snapshots; source business persistence remains the Provider.save responsibility. */
|
|
146
153
|
save: (input: Omit<ReportInstanceSnapshot, "revision">, options: {
|
|
147
154
|
expectedRevision: number | null;
|
|
@@ -229,6 +236,49 @@ declare interface GridCell {
|
|
|
229
236
|
|
|
230
237
|
declare type ImageComponentKind = "image" | "chart" | "barcode" | "qrcode";
|
|
231
238
|
|
|
239
|
+
export declare interface LabelStreamContext {
|
|
240
|
+
index: number;
|
|
241
|
+
rowOffset: number;
|
|
242
|
+
rowCount: number;
|
|
243
|
+
signal: AbortSignal;
|
|
244
|
+
/** Encode this chunk with the same runtime, resources, fonts, signal and budgets. */
|
|
245
|
+
export(input: Omit<ReportRuntimePreparedExportInput, "prepared" | "signal">): Promise<ReportRuntimeExportResult>;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export declare interface LabelStreamManifest {
|
|
249
|
+
rows: number;
|
|
250
|
+
chunks: Array<LabelStreamReceipt & {
|
|
251
|
+
index: number;
|
|
252
|
+
rowOffset: number;
|
|
253
|
+
rowCount: number;
|
|
254
|
+
}>;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export declare interface LabelStreamOptions {
|
|
258
|
+
template: ReportTemplate;
|
|
259
|
+
batchSize?: number;
|
|
260
|
+
maxRows?: number;
|
|
261
|
+
maxChunks?: number;
|
|
262
|
+
/** Conservative retained scalar/key size (UTF-16 + field overhead), default 16 MB. */
|
|
263
|
+
maxRetainedBytes?: number;
|
|
264
|
+
signal?: AbortSignal;
|
|
265
|
+
/** Shared existing runtime budgets/assets; callbacks never cross a Worker boundary. */
|
|
266
|
+
runtime?: Omit<ReportRuntimeOptions, "reports" | "executor">;
|
|
267
|
+
pdf?: ReportPdfFontOptions;
|
|
268
|
+
/** Persist each artifact here; retain only its small receipt in the manifest. */
|
|
269
|
+
execute(prepared: PreparedReport, context: LabelStreamContext): Promise<LabelStreamReceipt>;
|
|
270
|
+
/** Awaited after commit and before pulling more source rows. A failure stops consumption. */
|
|
271
|
+
onReceipt?(receipt: LabelStreamReceipt, context: LabelStreamContext): void | Promise<void>;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export declare interface LabelStreamReceipt {
|
|
275
|
+
/** Private artifact storage key, not a credential-bearing URL. */
|
|
276
|
+
key: string;
|
|
277
|
+
format: "pdf" | "xlsx";
|
|
278
|
+
bytes: number;
|
|
279
|
+
sha256?: string;
|
|
280
|
+
}
|
|
281
|
+
|
|
232
282
|
/** auto:真实数字/显式数值格式居右,日期与布尔居中,其他内容居左。 */
|
|
233
283
|
declare type ListAlignment = NonNullable<ComponentStyle["align"]> | "auto";
|
|
234
284
|
|
|
@@ -498,6 +548,11 @@ export declare interface PreparedReport {
|
|
|
498
548
|
revision?: string;
|
|
499
549
|
sourceToken?: string;
|
|
500
550
|
}>;
|
|
551
|
+
/** Captured metrics identity; absence on old saved instances remains supported with diagnostics. */
|
|
552
|
+
layout?: {
|
|
553
|
+
textMetrics: "heuristic" | "provided" | "font-bytes";
|
|
554
|
+
fontFingerprint?: string;
|
|
555
|
+
};
|
|
501
556
|
}
|
|
502
557
|
|
|
503
558
|
declare type PublicationAssets = Omit<AssetRenderOptions, "signal">;
|
|
@@ -583,6 +638,14 @@ declare interface ReportCellTableIdentity {
|
|
|
583
638
|
|
|
584
639
|
declare type ReportCellValue = string | number | boolean | null;
|
|
585
640
|
|
|
641
|
+
declare interface ReportDataTarget {
|
|
642
|
+
datasetId: string;
|
|
643
|
+
field: string;
|
|
644
|
+
rowKey?: string | number;
|
|
645
|
+
/** Use table identity when the same dataset appears in several tables. */
|
|
646
|
+
tableId?: string;
|
|
647
|
+
}
|
|
648
|
+
|
|
586
649
|
declare interface ReportDefinition {
|
|
587
650
|
/** 静态模板或宿主提供的异步模板加载器;动态模板默认每次重新读取,不缓存版本。 */
|
|
588
651
|
template: ReportTemplate | ReportTemplateLoader;
|
|
@@ -617,6 +680,9 @@ declare interface ReportDiagnostic {
|
|
|
617
680
|
message: string;
|
|
618
681
|
path?: string;
|
|
619
682
|
severity: "warning" | "error" | "info";
|
|
683
|
+
/** Optional explanation supplied by the business source, not inferred from blank cells. */
|
|
684
|
+
valueState?: ReportValueState;
|
|
685
|
+
target?: ReportDataTarget;
|
|
620
686
|
}
|
|
621
687
|
|
|
622
688
|
declare type ReportExpression = {
|
|
@@ -704,6 +770,8 @@ export declare interface ReportInstanceSnapshot {
|
|
|
704
770
|
templateRevisions: Record<string, string>;
|
|
705
771
|
sourceRevisions: Record<string, string>;
|
|
706
772
|
plan: RenderPlan;
|
|
773
|
+
/** Exact generation diagnostics, row statistics and font metrics; optional for legacy instances. */
|
|
774
|
+
output?: Omit<PreparedReport, "plan" | "revisions">;
|
|
707
775
|
/** Private storage keys; signed download URLs must be generated by the host after authorization. */
|
|
708
776
|
artifacts?: ReportInstanceArtifact[];
|
|
709
777
|
}
|
|
@@ -715,7 +783,7 @@ export declare interface ReportInstanceStore {
|
|
|
715
783
|
compareAndSwap(scope: string, id: string, expectedRevision: number | null, next: ReportInstanceSnapshot, signal?: AbortSignal): Promise<boolean>;
|
|
716
784
|
}
|
|
717
785
|
|
|
718
|
-
export declare type ReportInstanceSummary = Omit<ReportInstanceSnapshot, "plan" | "artifacts">;
|
|
786
|
+
export declare type ReportInstanceSummary = Omit<ReportInstanceSnapshot, "plan" | "artifacts" | "output">;
|
|
719
787
|
|
|
720
788
|
export declare function reportInstanceSummary(snapshot: ReportInstanceSnapshot): ReportInstanceSummary;
|
|
721
789
|
|
|
@@ -893,6 +961,18 @@ declare interface ReportParamValidation {
|
|
|
893
961
|
issues: ReportParamIssue[];
|
|
894
962
|
}
|
|
895
963
|
|
|
964
|
+
/** Licensed local font bytes; never downloaded implicitly by the runtime. */
|
|
965
|
+
export declare interface ReportPdfFontOptions {
|
|
966
|
+
customFontBytes?: Uint8Array | ArrayBuffer;
|
|
967
|
+
customFontName?: string;
|
|
968
|
+
customFontFaces?: {
|
|
969
|
+
regular: Uint8Array | ArrayBuffer;
|
|
970
|
+
bold?: Uint8Array | ArrayBuffer;
|
|
971
|
+
italic?: Uint8Array | ArrayBuffer;
|
|
972
|
+
boldItalic?: Uint8Array | ArrayBuffer;
|
|
973
|
+
};
|
|
974
|
+
}
|
|
975
|
+
|
|
896
976
|
/** 查询是唯一基础能力;权限、HTTP、数据库和事务都留在宿主适配器内。 */
|
|
897
977
|
declare interface ReportProvider {
|
|
898
978
|
query(context: ReportLoadContext): ReportQueryResult | Promise<ReportQueryResult>;
|
|
@@ -953,6 +1033,7 @@ export declare interface ReportRuntime {
|
|
|
953
1033
|
validate(input: Omit<ReportRuntimeInput, "signal">): ReportParamValidation;
|
|
954
1034
|
prepare(input: ReportRuntimeInput): Promise<PreparedReport>;
|
|
955
1035
|
export(input: ReportRuntimeExportInput): Promise<ReportRuntimeExportResult>;
|
|
1036
|
+
exportPrepared(input: ReportRuntimePreparedExportInput): Promise<ReportRuntimeExportResult>;
|
|
956
1037
|
}
|
|
957
1038
|
|
|
958
1039
|
export declare interface ReportRuntimeBudget {
|
|
@@ -960,6 +1041,8 @@ export declare interface ReportRuntimeBudget {
|
|
|
960
1041
|
maxPages?: number;
|
|
961
1042
|
maxCells?: number;
|
|
962
1043
|
maxOutputBytes?: number;
|
|
1044
|
+
/** Bound the plain JSON snapshot accepted by exportPrepared (default 64 MB). */
|
|
1045
|
+
maxPreparedBytes?: number;
|
|
963
1046
|
maxDurationMs?: number;
|
|
964
1047
|
}
|
|
965
1048
|
|
|
@@ -971,6 +1054,8 @@ export declare class ReportRuntimeError extends Error {
|
|
|
971
1054
|
|
|
972
1055
|
/** 可用 worker_threads/进程/RPC 实现;接收可序列化请求,signal 由桥接层映射为取消消息。 */
|
|
973
1056
|
export declare interface ReportRuntimeExecutor {
|
|
1057
|
+
/** Old custom executors may omit this; the runtime explicitly rejects unsupported prepared output. */
|
|
1058
|
+
exportPrepared?(input: Omit<ReportRuntimePreparedExportInput, "signal" | "onEvent">, signal?: AbortSignal, onEvent?: ReportTaskObserver): Promise<ReportRuntimeExportResult>;
|
|
974
1059
|
prepare(input: Omit<ReportRuntimeInput, "signal" | "onEvent">, signal?: AbortSignal, onEvent?: ReportTaskObserver): Promise<PreparedReport>;
|
|
975
1060
|
export(input: Omit<ReportRuntimeExportInput, "signal" | "onEvent">, signal?: AbortSignal, onEvent?: ReportTaskObserver): Promise<ReportRuntimeExportResult>;
|
|
976
1061
|
}
|
|
@@ -979,17 +1064,6 @@ export declare interface ReportRuntimeExportInput extends ReportRuntimeInput {
|
|
|
979
1064
|
format: "pdf" | "xlsx";
|
|
980
1065
|
/** strict 在编码前拒绝已识别的输出降级;默认保留诊断并继续。 */
|
|
981
1066
|
fidelity?: "warn" | "strict";
|
|
982
|
-
/** PDF 中文需宿主显式提供有授权的字体;不隐式下载字体或资源。 */
|
|
983
|
-
pdf?: {
|
|
984
|
-
customFontBytes?: Uint8Array | ArrayBuffer;
|
|
985
|
-
customFontName?: string;
|
|
986
|
-
customFontFaces?: {
|
|
987
|
-
regular: Uint8Array | ArrayBuffer;
|
|
988
|
-
bold?: Uint8Array | ArrayBuffer;
|
|
989
|
-
italic?: Uint8Array | ArrayBuffer;
|
|
990
|
-
boldItalic?: Uint8Array | ArrayBuffer;
|
|
991
|
-
};
|
|
992
|
-
};
|
|
993
1067
|
xlsx?: {
|
|
994
1068
|
sheetMode?: "auto" | "pages" | "continuous";
|
|
995
1069
|
valueMode?: "text" | "raw";
|
|
@@ -1007,6 +1081,8 @@ export declare interface ReportRuntimeInput extends ReportTaskMonitoring {
|
|
|
1007
1081
|
reportIds: string[];
|
|
1008
1082
|
params?: Record<string, string>;
|
|
1009
1083
|
signal?: AbortSignal;
|
|
1084
|
+
/** Prepare using the same licensed font bytes later supplied to PDF output. */
|
|
1085
|
+
pdf?: ReportPdfFontOptions;
|
|
1010
1086
|
}
|
|
1011
1087
|
|
|
1012
1088
|
export declare interface ReportRuntimeOptions {
|
|
@@ -1019,6 +1095,16 @@ export declare interface ReportRuntimeOptions {
|
|
|
1019
1095
|
executor?: ReportRuntimeExecutor;
|
|
1020
1096
|
}
|
|
1021
1097
|
|
|
1098
|
+
/** Encode an existing plan without querying providers or repaginating. */
|
|
1099
|
+
export declare interface ReportRuntimePreparedExportInput extends ReportTaskMonitoring {
|
|
1100
|
+
prepared: PreparedReport;
|
|
1101
|
+
format: ReportRuntimeExportInput["format"];
|
|
1102
|
+
fidelity?: ReportRuntimeExportInput["fidelity"];
|
|
1103
|
+
pdf?: ReportPdfFontOptions;
|
|
1104
|
+
xlsx?: ReportRuntimeExportInput["xlsx"];
|
|
1105
|
+
signal?: AbortSignal;
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1022
1108
|
export declare interface ReportRuntimeStats {
|
|
1023
1109
|
rows: number;
|
|
1024
1110
|
pages: number;
|
|
@@ -1202,6 +1288,9 @@ declare interface ReportTemplateReviewOptions {
|
|
|
1202
1288
|
|
|
1203
1289
|
declare type ReportTemplateSummary = Omit<ReportTemplateDocument, "template">;
|
|
1204
1290
|
|
|
1291
|
+
/** Optional business explanations never replace raw data or schema validation. */
|
|
1292
|
+
declare type ReportValueState = "missing-source" | "not-applicable" | "not-calculable";
|
|
1293
|
+
|
|
1205
1294
|
/** Publication gate with actual sequential PDF/XLSX encoding, no business query or implicit save. */
|
|
1206
1295
|
export declare function reviewReportPublication(input: unknown, options?: ReportPublicationOptions): Promise<ReportPublicationReview>;
|
|
1207
1296
|
|
|
@@ -1221,6 +1310,12 @@ declare interface RichSegment {
|
|
|
1221
1310
|
style?: ComponentStyle;
|
|
1222
1311
|
}
|
|
1223
1312
|
|
|
1313
|
+
/** Bounded fixed-label consumption, not cross-chunk aggregation or a new durable task queue.
|
|
1314
|
+
* The next source chunk is pulled only after execute + onReceipt complete. Earlier receipts
|
|
1315
|
+
* remain committed if a later chunk fails; use onReceipt for a durable incremental manifest.
|
|
1316
|
+
*/
|
|
1317
|
+
export declare function runLabelStream(source: AsyncIterable<object>, options: LabelStreamOptions): Promise<LabelStreamManifest>;
|
|
1318
|
+
|
|
1224
1319
|
export declare function runnableJob(record: ReportJobRecord, now: number): boolean;
|
|
1225
1320
|
|
|
1226
1321
|
/** Browser/Node shared bounded runner. Return small receipts; persist/export large artifacts inside execute. */
|