@medplum/cli 5.1.8 → 5.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs +1 -1
- package/dist/cjs/index.cjs.map +3 -3
- package/dist/esm/index.mjs +1 -1
- package/dist/esm/index.mjs.map +3 -3
- package/package.json +14 -14
package/dist/esm/index.mjs
CHANGED
|
@@ -11,7 +11,7 @@ Configuration values come from a file named **medplum.<tag>.config.server.json**
|
|
|
11
11
|
`+ee.yellow("**Services must be restarted to apply changes.**"))).argument("<tag>","The Medplum stack tag").option("--file [file]",_t("File to provide overrides for **apiPort**, **baseUrl**, **appDomainName** and **storageDomainName** values that appear in the config file.")).option("--dryrun","Displays the operations that would be performed using the specified command without actually running them.").option("--yes","Automatically confirm the update").action(gn),y(e,new g("update-server").alias("deploy-server").description("Update the server image").argument("<tag>","The Medplum stack tag").option("--file [file]","Specifies the config file to use. If not specified, the file is based on the tag.").option("--to-version [version]","Specifies the version of the configuration to update. If not specified, the latest version is updated.").action(wn)),e.command("update-app").alias("deploy-app").description("Update the app site").argument("<tag>","The Medplum stack tag").option("--file [file]","Specifies the config file to use. If not specified, the file is based on the tag.").option("--to-version [version]","Specifies the version of the configuration to update. If not specified, the latest version is updated.").option("--dryrun","Displays the operations that would be performed using the specified command without actually running them.").option("--tar-path [tarPath]","Specifies the path to the extracted tarball of the @medplum/app package.").action(dn),e.command("update-bucket-policies").description("Update S3 bucket policies").argument("<tag>","The Medplum stack tag").option("--file [file]","Specifies the config file to use. If not specified, the file is based on the tag.").option("--dryrun","Displays the operations that would be performed using the specified command without actually running them.").action(hn),e}var Sn=new g("save"),Rn=new g("deploy"),An=new g("create"),Ce=new g("bot");y(Ce,Sn);y(Ce,Rn);y(Ce,An);var ir=new g("save-bot"),ar=new g("deploy-bot"),cr=new g("create-bot");Sn.description("Saving the bot").argument("<botName>").action(async(e,t)=>{let r=await A(t);await lt(r,e)});Rn.description("Deploy the app to AWS").argument("<botName>").action(async(e,t)=>{let r=await A(t);await lt(r,e,!0)});An.arguments("<botName> <projectId> <sourceFile> <distFile>").description("Creating a bot").option("--runtime-version <runtimeVersion>","Runtime version (awslambda, vmcontext)").option("--no-write-config","Do not write bot to config").action(async(e,t,r,o,s)=>{let n=await A(s);await xt(n,e,t,r,o,s.runtimeVersion,!!s.writeConfig)});async function lt(e,t,r=!1){let o=Xr(t),s=[],n=[],i=0,a=0;for(let l of o)try{let u=await e.readResource("Bot",l.id);await Tt(e,l,u),i++,r&&(await Ot(e,l,u),a++)}catch(u){s.push(u),n.push(`${l.name} [${l.id}]`)}if(console.log(`Number of bots saved: ${i}`),console.log(`Number of bots deployed: ${a}`),console.log(`Number of errors: ${s.length}`),s.length)throw new Error(`${s.length} bot(s) had failures. Bots with failures:
|
|
12
12
|
|
|
13
13
|
${n.join(`
|
|
14
|
-
`)}`,{cause:s})}ir.description("Saves the bot").argument("<botName>").action(async(e,t)=>{let r=await A(t);await lt(r,e)});ar.description("Deploy the bot to AWS").argument("<botName>").action(async(e,t)=>{let r=await A(t);await lt(r,e,!0)});cr.arguments("<botName> <projectId> <sourceFile> <distFile>").description("Creates and saves the bot").action(async(e,t,r,o,s)=>{let n=await A(s);await xt(n,e,t,r,o)});import{EMPTY as vn}from"@medplum/core";import{createReadStream as yp,createWriteStream as wp}from"node:fs";import{resolve as bn}from"node:path";import{createInterface as Ep}from"node:readline";import{Readable as Sp}from"node:stream";import{pipeline as Rp}from"node:stream/promises";var In=new g("export"),Cn=new g("import"),ut=new g("bulk");y(ut,In);y(ut,Cn);In.option("-e, --export-level <exportLevel>",'Optional export level. Defaults to system level export. "Group/:id" - Group of Patients, "Patient" - All Patients.').option("-t, --types <types>","optional resource types to export").option("-s, --since <since>","optional Resources will be included in the response if their state has changed after the supplied time (e.g. if Resource.meta.lastUpdated is later than the supplied _since time).").option("-d, --target-directory <targetDirectory>","optional target directory to save files from the bulk export operations.").action(async e=>{let{exportLevel:t,types:r,since:o,targetDirectory:s}=e,n=await A(e),i=await n.bulkExport(t,r,o,{pollStatusOnAccepted:!0});for(let{type:a,url:l}of i.output??vn){let u=new URL(l),h=`${a}_${u.pathname}`.replaceAll(/[^a-zA-Z0-9]+/g,"_")+".ndjson",m=bn(s??"",h),S=await n.downloadResponse(l);if(!S.ok)throw new Error(`Download failed: ${S.status} ${S.statusText}`);if(!S.body)throw new Error("Download response missing body");let f=Sp.fromWeb(S.body);await Rp(f,wp(m)),console.log(`${m} is created`)}});Cn.argument("<filename>","File Name").option("--num-resources-per-request <numResourcesPerRequest>","optional number of resources to import per batch request. Defaults to 25.","25").option("--add-extensions-for-missing-values","optional flag to add extensions for missing values in a resource",!1).option("-d, --target-directory <targetDirectory>","optional target directory of file to be imported").action(async(e,t)=>{let{numResourcesPerRequest:r,addExtensionsForMissingValues:o,targetDirectory:s}=t,n=bn(s??process.cwd(),e),i=await A(t);await Ap(n,Number.parseInt(r,10),i,o)});async function Ap(e,t,r,o){let s=[],n=yp(e),i=Ep({input:n});for await(let a of i){let l=Pp(a,o);s.push({resource:l,request:{method:"POST",url:l.resourceType}}),s.length%t===0&&(await Pn(s,r),s=[])}s.length>0&&await Pn(s,r)}async function Pn(e,t){let r=await t.executeBatch({resourceType:"Bundle",type:"transaction",entry:e});for(let o of r.entry??vn)H(o.response)}function Pp(e,t){let r=JSON.parse(e);return t?vp(r):r}function vp(e){return e.resourceType==="ExplanationOfBenefit"?bp(e):e}function bp(e){return e.provider||(e.provider=$t()),e.item?.forEach(t=>{t?.productOrService||(t.productOrService=$t())}),e}import{formatHl7DateTime as jp,Hl7Message as Fp}from"@medplum/core";import pt from"node:assert";import{connect as Tp}from"node:net";import{Hl7Message as Op,OperationOutcomeError as le,ReturnAckCategory as Tn,sleep as xp,validationError as $p}from"@medplum/core";import On from"iconv-lite";import{ReturnAckCategory as Tg}from"@medplum/core";import{sleep as Dp}from"@medplum/core";import _p from"node:net";var Ip=Object.defineProperty,Cp=(e,t,r)=>t in e?Ip(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,R=(e,t,r)=>Cp(e,typeof t!="symbol"?t+"":t,r),$n=class extends EventTarget{addEventListener(e,t,r){super.addEventListener(e,t,r)}removeEventListener(e,t,r){super.removeEventListener(e,t,r)}};var Np=class extends Event{constructor(e,t){super("message"),R(this,"connection"),R(this,"message"),this.connection=e,this.message=t}},Lp=class extends Event{constructor(e,t){super("enhancedAckSent"),R(this,"connection"),R(this,"message"),this.connection=e,this.message=t}},Te=class extends Event{constructor(e){super("error"),R(this,"error"),this.error=e}},lr=class extends Event{constructor(e){super("warning"),R(this,"error"),this.error=e}},ur=class extends Event{constructor(){super("close")}},xn="utf-8",kp=5e3,Mp=60*1e3,Nn=class extends $n{constructor(e,t=xn,r,o={}){super(),R(this,"socket"),R(this,"encoding"),R(this,"enhancedMode"),R(this,"messagesPerMin"),R(this,"gracefulCloseTimeoutMs"),R(this,"chunks",[]),R(this,"pendingMessages",new Map),R(this,"responseQueue",[]),R(this,"lastMessageDispatchedTime",0),R(this,"responseQueueProcessing",!1),R(this,"closing",!1),this.socket=e,this.encoding=t,this.enhancedMode=r,this.messagesPerMin=o.messagesPerMin,this.gracefulCloseTimeoutMs=o.gracefulCloseTimeoutMs??kp,e.on("data",s=>{if(this.closing){this.dispatchEvent(new lr(new le({resourceType:"OperationOutcome",issue:[{severity:"warning",code:"transient",details:{text:"Data received after close was initiated"}}]})));return}try{this.appendData(s);let n=this.parseMessages();for(let i of n)this.responseQueue.push(new Np(this,i));this.processResponseQueue().catch(i=>{this.dispatchEvent(new Te(i))})}catch(n){this.dispatchEvent(new Te(n))}}),e.on("error",s=>{this.resetBuffer(),this.dispatchEvent(new Te(s))}),e.on("close",()=>{this.drainPendingMessages(),this.dispatchEvent(new ur)}),this.addEventListener("message",s=>{let n;this.enhancedMode==="standard"?n=s.message.buildAck({ackCode:"CA"}):this.enhancedMode==="aaMode"&&(n=s.message.buildAck({ackCode:"AA"})),n&&(this.send(n),this.dispatchEvent(new Lp(this,n)));let i=s.message.getSegment("MSA")?.getField(2)?.toString();if(!i)return;let a=this.pendingMessages.get(i);if(!a){this.dispatchEvent(new lr(new le({resourceType:"OperationOutcome",issue:[{severity:"warning",code:"not-found",details:{text:"Response received for unknown message control ID"},diagnostics:`Received ACK for message control ID '${i}' but there was no pending message with this control ID`}]})));return}let l=s.message.getSegment("MSA")?.getField(1)?.toString()?.toUpperCase();l&&(a.returnAck===Tn.APPLICATION&&l==="CA"||(a.resolve(s.message),this.pendingMessages.delete(i)))})}isClosed(){return this.socket.closed}sendImpl(e){let t=e.toString(),r=On.encode(t,this.encoding),o=Buffer.alloc(r.length+3);o.writeInt8(11,0),r.copy(o,1),o.writeInt8(28,r.length+1),o.writeInt8(13,r.length+2),this.socket.write(o)}async processResponseQueue(){if(!this.responseQueueProcessing){for(this.responseQueueProcessing=!0;this.responseQueue.length;){if(this.messagesPerMin){let t=Mp/this.messagesPerMin,r=Date.now()-this.lastMessageDispatchedTime;t>r&&await xp(t-r)}let e=this.responseQueue.shift();e&&this.dispatchEvent(e),this.lastMessageDispatchedTime=Date.now()}this.responseQueueProcessing=!1}}parseMessages(){let e=[],t=Buffer.concat(this.chunks);if(this.resetBuffer(),t.length===0)return e;let r=0;for(;r<t.length;){for(;t[r]!==11&&r<t.length;)r++;let o=-1;for(let a=r+1;a<t.length-1;a++)if(t[a]===28&&t[a+1]===13){o=a+1;break}if(o===-1)break;let s=t.subarray(r,o+1).subarray(1,-2),n=On.decode(s,this.encoding),i=Op.parse(n);e.push(i),r=o+1}return this.chunks=r<t.length?[t.subarray(r)]:[],e}send(e){this.sendImpl(e)}async sendAndWait(e,t){return new Promise((r,o)=>{let s=e.getSegment("MSH")?.getField(10)?.toString();if(!s){o(new le($p("Required field missing: MSH.10")));return}let n;t?.timeoutMs&&(n=setTimeout(()=>{this.pendingMessages.delete(s),o(new le({resourceType:"OperationOutcome",issue:[{severity:"error",code:"timeout",details:{text:"Client timeout"},diagnostics:`Request timed out after waiting ${t.timeoutMs} milliseconds for response`}]}))},t.timeoutMs)),this.pendingMessages.set(s,{message:e,resolve:r,reject:o,returnAck:t?.returnAck??Tn.APPLICATION,timer:n}),this.sendImpl(e)})}async close(){this.isClosed()||(this.closing=!0,this.socket.end(),this.drainPendingMessages(),await new Promise(e=>{let t=setTimeout(()=>{this.socket.destroy()},this.gracefulCloseTimeoutMs);this.socket.once("close",()=>{clearTimeout(t),e()})}))}drainPendingMessages(){if(!this.pendingMessages.size)return;let e=this.pendingMessages.size;for(let t of this.pendingMessages.values())t.timer&&clearTimeout(t.timer),t.reject(new le({resourceType:"OperationOutcome",issue:[{severity:"warning",code:"incomplete",details:{text:"Message was still pending when connection closed"}}]}));this.dispatchEvent(new Te(new le({resourceType:"OperationOutcome",issue:[{severity:"warning",code:"incomplete",details:{text:"Messages were still pending when connection closed"},diagnostics:`Hl7Connection closed while ${e} messages were pending`}]}))),this.pendingMessages.clear()}appendData(e){this.chunks.push(e)}resetBuffer(){this.chunks=[]}setEncoding(e){this.encoding=e??xn}getEncoding(){return this.encoding}setEnhancedMode(e){this.enhancedMode=e}getEnhancedMode(){return this.enhancedMode}setMessagesPerMin(e){this.messagesPerMin=e}getMessagesPerMin(){return this.messagesPerMin}getPendingMessageCount(){return this.pendingMessages.size}},Ln=class extends $n{constructor(e){super(),R(this,"options"),R(this,"host"),R(this,"port"),R(this,"encoding"),R(this,"connection"),R(this,"keepAlive"),R(this,"socket"),R(this,"connectTimeout"),R(this,"deferredConnectionPromise"),this.options=e,this.host=this.options.host,this.port=this.options.port,this.encoding=this.options.encoding,this.keepAlive=this.options.keepAlive??!1,this.connectTimeout=this.options.connectTimeout??3e4}connect(){if(this.deferredConnectionPromise)return this.deferredConnectionPromise.promise;let e=this.deferredConnectionPromise=this.createDeferredConnectionPromise();return this.socket=Tp({host:this.host,port:this.port,keepAlive:this.keepAlive}),this.connectTimeout>0&&(this.socket.setTimeout(this.connectTimeout),this.registerSocketTimeoutListener(e)),this.registerSocketConnectListener(e),this.registerSocketErrorListener(e),this.registerSocketCloseListener(e),e.promise}registerSocketTimeoutListener(e){pt(this.socket);let t=this.socket,r=()=>{this.cleanupSocket(t);let o=new Error(`Connection timeout after ${this.connectTimeout}ms`);this.rejectDeferredPromise(e,o)};t.on("timeout",r)}registerSocketConnectListener(e){pt(this.socket);let t=this.socket,r=()=>{if(t!==this.socket){this.cleanupSocket(t);return}let o;this.connection=o=new Nn(t,this.encoding),t.setTimeout(0),this.registerHl7ConnectionListeners(o),e.resolve(o)};t.on("connect",r)}registerSocketErrorListener(e){pt(this.socket);let t=this.socket,r=o=>{this.cleanupSocket(t),o.constructor.name==="AggregateError"?this.rejectDeferredPromise(e,o.errors[0]):this.rejectDeferredPromise(e,o)};t.on("error",r)}registerSocketCloseListener(e){pt(this.socket);let t=this.socket,r=()=>{this.cleanupSocket(t),this.rejectDeferredPromise(e,new Error("Socket closed before connection finished"))};t.on("close",r)}registerHl7ConnectionListeners(e){e.addEventListener("close",()=>{this.socket=void 0,this.connection=void 0,this.deferredConnectionPromise=void 0,this.dispatchEvent(new ur)}),e.addEventListener("error",t=>{this.dispatchEvent(new Te(t.error))}),e.addEventListener("warning",t=>{this.dispatchEvent(new lr(t.error))})}createDeferredConnectionPromise(){let e,t;return{promise:new Promise((r,o)=>{e=r,t=o}),resolve:e,reject:t}}rejectDeferredPromise(e,t){e.reject(t),this.deferredConnectionPromise===e&&(this.deferredConnectionPromise=void 0)}cleanupSocket(e){e.destroyed||e.destroy(),e===this.socket&&(this.socket=void 0)}async send(e){return(await this.connect()).send(e)}async sendAndWait(e,t){return(await this.connect()).sendAndWait(e,t)}async close(){if(this.deferredConnectionPromise&&this.rejectDeferredPromise(this.deferredConnectionPromise,new Error("Client closed while connecting")),this.connection){let e=this.connection;delete this.connection,await e.close()}else this.dispatchEvent(new ur);this.socket&&(this.socket.removeAllListeners(),this.socket.destroy(),this.socket=void 0)}},Up=1e4,kn=class{constructor(e){R(this,"handler"),R(this,"server"),R(this,"encoding"),R(this,"enhancedMode"),R(this,"messagesPerMin"),R(this,"connections",new Set),this.handler=e}async start(e,t,r,o){t&&this.setEncoding(t),r!==void 0&&this.setEnhancedMode(r),o?.messagesPerMin!==void 0&&this.setMessagesPerMin(o.messagesPerMin);let s=_p.createServer(n=>{let i=new Nn(n,this.encoding,this.enhancedMode,{messagesPerMin:this.messagesPerMin});this.handler(i),this.connections.add(i),i.addEventListener("close",()=>{this.connections.delete(i)})});return new Promise((n,i)=>{let a=u=>{s.listen(u,()=>{let h=s.address().port;n(h)})},l=u=>{u?.code==="EADDRINUSE"?s.close(()=>Dp(50).then(()=>a(e))):i(u)};s.on("error",l),s.once("listening",()=>{s.off("error",l)}),a(e),this.server=s})}async stop(e){return new Promise((t,r)=>{if(!this.server){r(new Error("Stop was called but there is no server running"));return}let o;e?.forceDrainTimeoutMs!==-1&&(o=setTimeout(()=>{for(let s of this.connections)s.close().catch(console.error)},e?.forceDrainTimeoutMs??Up)),this.server.close(s=>{if(s){r(s);return}o&&clearTimeout(o),this.connections.clear(),this.server=void 0,t()})})}setEnhancedMode(e){this.enhancedMode=e}getEnhancedMode(){return this.enhancedMode}setEncoding(e){this.encoding=e}getEncoding(){return this.encoding}setMessagesPerMin(e){this.messagesPerMin=e}getMessagesPerMin(){return this.messagesPerMin}};import{readFileSync as Bp}from"node:fs";var Wp=new g("send").description("Send an HL7 v2 message via MLLP").argument("<host>","The destination host name or IP address").argument("<port>","The destination port number").argument("[body]","Optional HL7 message body").option("--generate-example","Generate a sample HL7 message").option("--file <file>","Read the HL7 message from a file").option("--encoding <encoding>","The encoding to use").action(async(e,t,r,o)=>{if(o.generateExample?r=qp():o.file&&(r=Bp(o.file,"utf8")),!r)throw new Error("Missing HL7 message body");let s=new Ln({host:e,port:Number.parseInt(t,10),encoding:o.encoding});try{let n=await s.sendAndWait(Fp.parse(r));console.log(n.toString().replaceAll("\r",`
|
|
14
|
+
`)}`,{cause:s})}ir.description("Saves the bot").argument("<botName>").action(async(e,t)=>{let r=await A(t);await lt(r,e)});ar.description("Deploy the bot to AWS").argument("<botName>").action(async(e,t)=>{let r=await A(t);await lt(r,e,!0)});cr.arguments("<botName> <projectId> <sourceFile> <distFile>").description("Creates and saves the bot").action(async(e,t,r,o,s)=>{let n=await A(s);await xt(n,e,t,r,o)});import{EMPTY as vn}from"@medplum/core";import{createReadStream as yp,createWriteStream as wp}from"node:fs";import{resolve as bn}from"node:path";import{createInterface as Ep}from"node:readline";import{Readable as Sp}from"node:stream";import{pipeline as Rp}from"node:stream/promises";var In=new g("export"),Cn=new g("import"),ut=new g("bulk");y(ut,In);y(ut,Cn);In.option("-e, --export-level <exportLevel>",'Optional export level. Defaults to system level export. "Group/:id" - Group of Patients, "Patient" - All Patients.').option("-t, --types <types>","optional resource types to export").option("-s, --since <since>","optional Resources will be included in the response if their state has changed after the supplied time (e.g. if Resource.meta.lastUpdated is later than the supplied _since time).").option("-d, --target-directory <targetDirectory>","optional target directory to save files from the bulk export operations.").action(async e=>{let{exportLevel:t,types:r,since:o,targetDirectory:s}=e,n=await A(e),i=await n.bulkExport(t,r,o,{pollStatusOnAccepted:!0});for(let{type:a,url:l}of i.output??vn){let u=new URL(l),h=`${a}_${u.pathname}`.replaceAll(/[^a-zA-Z0-9]+/g,"_")+".ndjson",m=bn(s??"",h),S=await n.downloadResponse(l);if(!S.ok)throw new Error(`Download failed: ${S.status} ${S.statusText}`);if(!S.body)throw new Error("Download response missing body");let f=Sp.fromWeb(S.body);await Rp(f,wp(m)),console.log(`${m} is created`)}});Cn.argument("<filename>","File Name").option("--num-resources-per-request <numResourcesPerRequest>","optional number of resources to import per batch request. Defaults to 25.","25").option("--add-extensions-for-missing-values","optional flag to add extensions for missing values in a resource",!1).option("-d, --target-directory <targetDirectory>","optional target directory of file to be imported").action(async(e,t)=>{let{numResourcesPerRequest:r,addExtensionsForMissingValues:o,targetDirectory:s}=t,n=bn(s??process.cwd(),e),i=await A(t);await Ap(n,Number.parseInt(r,10),i,o)});async function Ap(e,t,r,o){let s=[],n=yp(e),i=Ep({input:n});for await(let a of i){let l=Pp(a,o);s.push({resource:l,request:{method:"POST",url:l.resourceType}}),s.length%t===0&&(await Pn(s,r),s=[])}s.length>0&&await Pn(s,r)}async function Pn(e,t){let r=await t.executeBatch({resourceType:"Bundle",type:"transaction",entry:e});for(let o of r.entry??vn)H(o.response)}function Pp(e,t){let r=JSON.parse(e);return t?vp(r):r}function vp(e){return e.resourceType==="ExplanationOfBenefit"?bp(e):e}function bp(e){return e.provider||(e.provider=$t()),e.item?.forEach(t=>{t?.productOrService||(t.productOrService=$t())}),e}import{formatHl7DateTime as jp,Hl7Message as Fp}from"@medplum/core";import pt from"node:assert";import{connect as Tp}from"node:net";import{Hl7Message as Op,OperationOutcomeError as le,ReturnAckCategory as Tn,sleep as xp,validationError as $p}from"@medplum/core";import On from"iconv-lite";import{ReturnAckCategory as Tg}from"@medplum/core";import{sleep as Dp}from"@medplum/core";import _p from"node:net";var Ip=Object.defineProperty,Cp=(e,t,r)=>t in e?Ip(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,R=(e,t,r)=>Cp(e,typeof t!="symbol"?t+"":t,r),$n=class extends EventTarget{addEventListener(e,t,r){super.addEventListener(e,t,r)}removeEventListener(e,t,r){super.removeEventListener(e,t,r)}};var Np=class extends Event{constructor(e,t){super("message"),R(this,"connection"),R(this,"message"),this.connection=e,this.message=t}},Lp=class extends Event{constructor(e,t){super("enhancedAckSent"),R(this,"connection"),R(this,"message"),this.connection=e,this.message=t}},Te=class extends Event{constructor(e){super("error"),R(this,"error"),this.error=e}},lr=class extends Event{constructor(e){super("warning"),R(this,"error"),this.error=e}},ur=class extends Event{constructor(){super("close")}},xn="utf-8",kp=5e3,Mp=60*1e3,Nn=class extends $n{constructor(e,t=xn,r,o={}){super(),R(this,"socket"),R(this,"encoding"),R(this,"enhancedMode"),R(this,"messagesPerMin"),R(this,"gracefulCloseTimeoutMs"),R(this,"chunks",[]),R(this,"pendingMessages",new Map),R(this,"responseQueue",[]),R(this,"lastMessageDispatchedTime",0),R(this,"responseQueueProcessing",!1),R(this,"closing",!1),this.socket=e,this.encoding=t,this.enhancedMode=r,this.messagesPerMin=o.messagesPerMin,this.gracefulCloseTimeoutMs=o.gracefulCloseTimeoutMs??kp,e.on("data",s=>{if(this.closing){this.dispatchEvent(new lr(new le({resourceType:"OperationOutcome",issue:[{severity:"warning",code:"transient",details:{text:"Data received after close was initiated"}}]})));return}try{this.appendData(s);let n=this.parseMessages();for(let i of n)this.responseQueue.push(new Np(this,i));this.processResponseQueue().catch(i=>{this.dispatchEvent(new Te(i))})}catch(n){this.dispatchEvent(new Te(n))}}),e.on("error",s=>{this.resetBuffer(),this.dispatchEvent(new Te(s))}),e.on("close",()=>{this.drainPendingMessages(),this.dispatchEvent(new ur)}),this.addEventListener("message",s=>{let n;this.enhancedMode==="standard"?n=s.message.buildAck({ackCode:"CA"}):this.enhancedMode==="aaMode"&&(n=s.message.buildAck({ackCode:"AA"})),n&&(this.send(n),this.dispatchEvent(new Lp(this,n)));let i=s.message.getSegment("MSA")?.getField(2)?.toString();if(!i)return;let a=this.getPendingMessage(i);if(!a){this.dispatchEvent(new lr(new le({resourceType:"OperationOutcome",issue:[{severity:"warning",code:"not-found",details:{text:"Response received for unknown message control ID"},diagnostics:`Received ACK for message control ID '${i}' but there was no pending message with this control ID`}]})));return}let l=s.message.getSegment("MSA")?.getField(1)?.toString()?.toUpperCase();l&&(a.returnAck===Tn.APPLICATION&&l==="CA"||(a.timer&&clearTimeout(a.timer),a.resolve(s.message),this.deletePendingMessage(i)))})}isClosed(){return this.socket.closed}sendImpl(e){let t=e.toString(),r=On.encode(t,this.encoding),o=Buffer.alloc(r.length+3);o.writeInt8(11,0),r.copy(o,1),o.writeInt8(28,r.length+1),o.writeInt8(13,r.length+2),this.socket.write(o)}async processResponseQueue(){if(!this.responseQueueProcessing){for(this.responseQueueProcessing=!0;this.responseQueue.length;){if(this.messagesPerMin){let t=Mp/this.messagesPerMin,r=Date.now()-this.lastMessageDispatchedTime;t>r&&await xp(t-r)}let e=this.responseQueue.shift();e&&this.dispatchEvent(e),this.lastMessageDispatchedTime=Date.now()}this.responseQueueProcessing=!1}}parseMessages(){let e=[],t=Buffer.concat(this.chunks);if(this.resetBuffer(),t.length===0)return e;let r=0;for(;r<t.length;){for(;t[r]!==11&&r<t.length;)r++;let o=-1;for(let a=r+1;a<t.length-1;a++)if(t[a]===28&&t[a+1]===13){o=a+1;break}if(o===-1)break;let s=t.subarray(r,o+1).subarray(1,-2),n=On.decode(s,this.encoding),i=Op.parse(n);e.push(i),r=o+1}return this.chunks=r<t.length?[t.subarray(r)]:[],e}send(e){this.sendImpl(e)}async sendAndWait(e,t){return new Promise((r,o)=>{let s=e.getSegment("MSH")?.getField(10)?.toString();if(!s){o(new le($p("Required field missing: MSH.10")));return}let n;t?.timeoutMs&&(n=setTimeout(()=>{this.deletePendingMessage(s),o(new le({resourceType:"OperationOutcome",issue:[{severity:"error",code:"timeout",details:{text:"Client timeout"},diagnostics:`Request timed out after waiting ${t.timeoutMs} milliseconds for response`}]}))},t.timeoutMs)),this.setPendingMessage(s,{message:e,resolve:r,reject:o,returnAck:t?.returnAck??Tn.APPLICATION,timer:n}),this.sendImpl(e)})}async close(){this.isClosed()||(this.closing=!0,this.socket.end(),this.drainPendingMessages(),await new Promise(e=>{let t=setTimeout(()=>{this.socket.destroy()},this.gracefulCloseTimeoutMs);this.socket.once("close",()=>{clearTimeout(t),e()})}))}drainPendingMessages(){if(!this.pendingMessages.size)return;let e=this.pendingMessages.size;for(let t of this.pendingMessages.values())t.timer&&clearTimeout(t.timer),t.reject(new le({resourceType:"OperationOutcome",issue:[{severity:"warning",code:"incomplete",details:{text:"Message was still pending when connection closed"}}]}));this.dispatchEvent(new Te(new le({resourceType:"OperationOutcome",issue:[{severity:"warning",code:"incomplete",details:{text:"Messages were still pending when connection closed"},diagnostics:`Hl7Connection closed while ${e} messages were pending`}]}))),this.pendingMessages.clear()}appendData(e){this.chunks.push(e)}resetBuffer(){this.chunks=[]}setEncoding(e){this.encoding=e??xn}getEncoding(){return this.encoding}setEnhancedMode(e){this.enhancedMode=e}getEnhancedMode(){return this.enhancedMode}setMessagesPerMin(e){this.messagesPerMin=e}getMessagesPerMin(){return this.messagesPerMin}getPendingMessageCount(){return this.pendingMessages.size}getPendingMessage(e){return this.pendingMessages.get(e)}setPendingMessage(e,t){this.pendingMessages.set(e,t)}deletePendingMessage(e){this.pendingMessages.delete(e)}},Ln=class extends $n{constructor(e){super(),R(this,"options"),R(this,"host"),R(this,"port"),R(this,"encoding"),R(this,"connection"),R(this,"keepAlive"),R(this,"socket"),R(this,"connectTimeout"),R(this,"deferredConnectionPromise"),this.options=e,this.host=this.options.host,this.port=this.options.port,this.encoding=this.options.encoding,this.keepAlive=this.options.keepAlive??!1,this.connectTimeout=this.options.connectTimeout??3e4}connect(){if(this.deferredConnectionPromise)return this.deferredConnectionPromise.promise;let e=this.deferredConnectionPromise=this.createDeferredConnectionPromise();return this.socket=Tp({host:this.host,port:this.port,keepAlive:this.keepAlive}),this.connectTimeout>0&&(this.socket.setTimeout(this.connectTimeout),this.registerSocketTimeoutListener(e)),this.registerSocketConnectListener(e),this.registerSocketErrorListener(e),this.registerSocketCloseListener(e),e.promise}registerSocketTimeoutListener(e){pt(this.socket);let t=this.socket,r=()=>{this.cleanupSocket(t);let o=new Error(`Connection timeout after ${this.connectTimeout}ms`);this.rejectDeferredPromise(e,o)};t.on("timeout",r)}registerSocketConnectListener(e){pt(this.socket);let t=this.socket,r=()=>{if(t!==this.socket){this.cleanupSocket(t);return}let o;this.connection=o=this.createConnection(t,this.encoding),t.setTimeout(0),this.registerHl7ConnectionListeners(o),e.resolve(o)};t.on("connect",r)}registerSocketErrorListener(e){pt(this.socket);let t=this.socket,r=o=>{this.cleanupSocket(t),o.constructor.name==="AggregateError"?this.rejectDeferredPromise(e,o.errors[0]):this.rejectDeferredPromise(e,o)};t.on("error",r)}registerSocketCloseListener(e){pt(this.socket);let t=this.socket,r=()=>{this.cleanupSocket(t),this.rejectDeferredPromise(e,new Error("Socket closed before connection finished"))};t.on("close",r)}registerHl7ConnectionListeners(e){e.addEventListener("close",()=>{this.socket=void 0,this.connection=void 0,this.deferredConnectionPromise=void 0,this.dispatchEvent(new ur)}),e.addEventListener("error",t=>{this.dispatchEvent(new Te(t.error))}),e.addEventListener("warning",t=>{this.dispatchEvent(new lr(t.error))})}createDeferredConnectionPromise(){let e,t;return{promise:new Promise((r,o)=>{e=r,t=o}),resolve:e,reject:t}}rejectDeferredPromise(e,t){e.reject(t),this.deferredConnectionPromise===e&&(this.deferredConnectionPromise=void 0)}cleanupSocket(e){e.destroyed||e.destroy(),e===this.socket&&(this.socket=void 0)}createConnection(e,t,r,o){return new Nn(e,t,r,o)}async send(e){return(await this.connect()).send(e)}async sendAndWait(e,t){return(await this.connect()).sendAndWait(e,t)}async close(){if(this.deferredConnectionPromise&&this.rejectDeferredPromise(this.deferredConnectionPromise,new Error("Client closed while connecting")),this.connection){let e=this.connection;delete this.connection,await e.close()}else this.dispatchEvent(new ur);this.socket&&(this.socket.removeAllListeners(),this.socket.destroy(),this.socket=void 0)}},Up=1e4,kn=class{constructor(e){R(this,"handler"),R(this,"server"),R(this,"encoding"),R(this,"enhancedMode"),R(this,"messagesPerMin"),R(this,"connections",new Set),this.handler=e}async start(e,t,r,o){t&&this.setEncoding(t),r!==void 0&&this.setEnhancedMode(r),o?.messagesPerMin!==void 0&&this.setMessagesPerMin(o.messagesPerMin);let s=_p.createServer(n=>{let i=new Nn(n,this.encoding,this.enhancedMode,{messagesPerMin:this.messagesPerMin});this.handler(i),this.connections.add(i),i.addEventListener("close",()=>{this.connections.delete(i)})});return new Promise((n,i)=>{let a=u=>{s.listen(u,()=>{let h=s.address().port;n(h)})},l=u=>{u?.code==="EADDRINUSE"?s.close(()=>Dp(50).then(()=>a(e))):i(u)};s.on("error",l),s.once("listening",()=>{s.off("error",l)}),a(e),this.server=s})}async stop(e){return new Promise((t,r)=>{if(!this.server){r(new Error("Stop was called but there is no server running"));return}let o;e?.forceDrainTimeoutMs!==-1&&(o=setTimeout(()=>{for(let s of this.connections)s.close().catch(console.error)},e?.forceDrainTimeoutMs??Up)),this.server.close(s=>{if(s){r(s);return}o&&clearTimeout(o),this.connections.clear(),this.server=void 0,t()})})}setEnhancedMode(e){this.enhancedMode=e}getEnhancedMode(){return this.enhancedMode}setEncoding(e){this.encoding=e}getEncoding(){return this.encoding}setMessagesPerMin(e){this.messagesPerMin=e}getMessagesPerMin(){return this.messagesPerMin}};import{readFileSync as Bp}from"node:fs";var Wp=new g("send").description("Send an HL7 v2 message via MLLP").argument("<host>","The destination host name or IP address").argument("<port>","The destination port number").argument("[body]","Optional HL7 message body").option("--generate-example","Generate a sample HL7 message").option("--file <file>","Read the HL7 message from a file").option("--encoding <encoding>","The encoding to use").action(async(e,t,r,o)=>{if(o.generateExample?r=qp():o.file&&(r=Bp(o.file,"utf8")),!r)throw new Error("Missing HL7 message body");let s=new Ln({host:e,port:Number.parseInt(t,10),encoding:o.encoding});try{let n=await s.sendAndWait(Fp.parse(r));console.log(n.toString().replaceAll("\r",`
|
|
15
15
|
`))}finally{await s.close()}}),Kp=new g("listen").description("Starts an HL7 v2 MLLP server").argument("<port>").option("--encoding <encoding>","The encoding to use").action(async(e,t)=>{await new kn(o=>{o.addEventListener("message",({message:s})=>{console.log(s.toString().replaceAll("\r",`
|
|
16
16
|
`)),o.send(s.buildAck())})}).start(Number.parseInt(e,10),t.encoding),console.log("Listening on port "+e)}),dt=new g("hl7");y(dt,Wp);y(dt,Kp);function qp(){let e=jp(new Date),t=Date.now().toString();return`MSH|^~\\&|ADTSYS|HOSPITAL|RECEIVER|DEST|${e}||ADT^A01|${t}|P|2.5|
|
|
17
17
|
EVN|A01|${e}||
|