@metanodejs/file-module 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +3 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.mts +1276 -0
- package/dist/index.d.ts +1276 -0
- package/dist/index.mjs +3 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +46 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict";var pr=Object.create;var ge=Object.defineProperty;var ur=Object.getOwnPropertyDescriptor;var dr=Object.getOwnPropertyNames;var mr=Object.getPrototypeOf,fr=Object.prototype.hasOwnProperty;var Ct=t=>{throw TypeError(t)};var yr=(t,e)=>{for(var r in e)ge(t,r,{get:e[r],enumerable:!0})},qt=(t,e,r,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of dr(e))!fr.call(t,n)&&n!==r&&ge(t,n,{get:()=>e[n],enumerable:!(o=ur(e,n))||o.enumerable});return t};var S=(t,e,r)=>(r=t!=null?pr(mr(t)):{},qt(e||!t||!t.__esModule?ge(r,"default",{value:t,enumerable:!0}):r,t)),hr=t=>qt(ge({},"__esModule",{value:!0}),t);var Fe=(t,e,r)=>e.has(t)||Ct("Cannot "+r);var y=(t,e,r)=>(Fe(t,e,"read from private field"),r?r.call(t):e.get(t)),x=(t,e,r)=>e.has(t)?Ct("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(t):e.set(t,r),L=(t,e,r,o)=>(Fe(t,e,"write to private field"),o?o.call(t,r):e.set(t,r),r),O=(t,e,r)=>(Fe(t,e,"access private method"),r);var yo={};yr(yo,{ARGUMENT_INVALID:()=>Ee,ARGUMENT_NOT_PROVIDED:()=>Ie,ARGUMENT_OUT_OF_RANGE:()=>Oe,AddWhitelistRequestSchema:()=>at,AddWhitelistUseCase:()=>me,AddressSchema:()=>ee,AggregateRoot:()=>wt,ArgumentInvalidException:()=>U,ArgumentNotProvidedException:()=>P,ArgumentOutOfRangeException:()=>te,BaseRequestSchema:()=>f,BlockchainRepositoryBase:()=>H,Bytes32Schema:()=>gr,CONFLICT:()=>qe,CalculatePriceRequestSchema:()=>Ye,CalculatePriceResponseSchema:()=>wr,ConfirmServerDownloadRequestSchema:()=>rt,ConfirmServerDownloadResponseSchema:()=>Pr,ConflictException:()=>Ue,DEFAULT_PREFIX_ID_LENGTH:()=>Wt,DecodeAbiService:()=>be,DomainEvent:()=>ht,DownloadFileRequestSchema:()=>mo,DownloadFileResponseSchema:()=>fo,DownloadFileUseCase:()=>ue,DownloadKeyListenerService:()=>$,ENTITY_ID_LENGTH:()=>Ar,Entity:()=>ae,ExceptionBase:()=>R,FileActivatedListenerService:()=>G,FileBlockchainRepository:()=>De,FileModuleContainer:()=>he,GetFileInfoRequestSchema:()=>Ze,GetFileInfoResponseSchema:()=>Dr,GetRustServerAddressesAbi:()=>ze,GetRustServerAddressesRequestSchema:()=>nt,GetRustServerAddressesResponseSchema:()=>Tr,GetWhitelistRequestSchema:()=>lt,GetWhitelistUseCase:()=>fe,INTERNAL_SERVER_ERROR:()=>Ke,InternalServerErrorException:()=>re,IsPublicFileRequestSchema:()=>ct,IsPublicFileUseCase:()=>ye,Logger:()=>ve,NOT_FOUND:()=>Ce,NativeQuicError:()=>pe,NotFoundException:()=>Be,PayForDownloadRequestSchema:()=>et,PayForDownloadResponseSchema:()=>Rr,PublicKeySchema:()=>vr,PushFileInfoRequestSchema:()=>Je,PushFileInfoResponseSchema:()=>xr,SetPublicStatusRequestSchema:()=>st,SetPublicStatusUseCase:()=>de,TimestampSchema:()=>br,UniqueEntityID:()=>ie,UploadChunkRequestSchema:()=>Xe,UploadFileRequestSchema:()=>po,UploadFileResponseSchema:()=>uo,UploadFileUseCase:()=>ce,ValueObject:()=>Y,addWhitelistAbi:()=>je,appConfig:()=>g,buildMerkleTreePadded:()=>Dt,calculatePriceAbi:()=>Me,confirmServerDownloadAbi:()=>Le,convertPropsToObject:()=>se,createFileModule:()=>ar,createMittAsync:()=>Yt,decodeAbiService:()=>Bt,delay:()=>Vr,downloadAllChunks:()=>ir,downloadAndMergeFile:()=>kt,emitter:()=>Zr,eventLogs:()=>I,fileBlockchainRepository:()=>A,formatSize:()=>Xr,fulfilledPromises:()=>Jr,generateId:()=>Gt,generatePrefixId:()=>oe,generateRandomHex:()=>Yr,generateSignature:()=>Ft,getFileInfoAbi:()=>Ne,getMerkleProofPadded:()=>Rt,getWhitelistAbi:()=>He,humanFileSize:()=>Qr,invariant:()=>k,isAndroid:()=>Gr,isArray:()=>Ht,isBoolean:()=>Er,isBrowser:()=>ne,isCrawler:()=>Hr,isDate:()=>qr,isDef:()=>mt,isEmpties:()=>_r,isEmpty:()=>B,isFalsy:()=>Br,isFunction:()=>dt,isMap:()=>Ir,isMobile:()=>jr,isNotEmpties:()=>zr,isNotEmpty:()=>yt,isNotNull:()=>jt,isNumber:()=>Or,isObject:()=>ft,isPngImage:()=>$r,isPrimitive:()=>kr,isPromise:()=>Ur,isPublicFileAbi:()=>Ve,isSet:()=>Cr,isStream:()=>Lr,isString:()=>Vt,isSymbol:()=>Kr,isUndef:()=>Fr,isValidAddress:()=>to,isValidPublicKey:()=>ro,isWindow:()=>Mr,logger:()=>p,payForDownloadAbi:()=>_e,pushFileInfoAbi:()=>$e,requestChunk:()=>nr,setPublicStatusAbi:()=>We,uploadChunkAbi:()=>Ge,verifyMerkleProof:()=>Pt});module.exports=hr(yo);var g={file:"0x087cdab97d38a3bfFcDee170739E8C11Af651569"};var ve=class{constructor(e=""){this.isDev=!1,this.prefix=e}formatMessage(e,r){return[`[${new Date().toISOString()}] [${e.toUpperCase()}] ${this.prefix}`,...r]}debug(...e){this.isDev&&console.debug(...this.formatMessage("debug",e))}info(...e){this.isDev&&console.info(...this.formatMessage("info",e))}warn(...e){this.isDev&&console.warn(...this.formatMessage("warn",e))}error(...e){this.isDev&&console.error(...this.formatMessage("error",e))}log(...e){this.isDev&&console.log(...this.formatMessage("log",e))}},p=new ve("FILE-MODULE");var we=require("@metanodejs/system-core");var K,W,Kt,Ut,be=class{constructor(e){x(this,W);x(this,K,new Map);O(this,W,Kt).call(this,e)}get abiArray(){return[...y(this,K)]}getAbiData(e){if(y(this,K).size===0)return;let r=[...y(this,K).keys()].find(o=>e.startsWith(o));if(r)return y(this,K).get(r)}async handleDecodeAbi(e,r){let o=Bt.getAbiData(e);return o?{decodedData:await(0,we.decodeAbi)({...o,rawInput:r}),event:o.functionName}:void 0}};K=new WeakMap,W=new WeakSet,Kt=async function(e){return await Promise.all(e.map(async o=>{let n=await O(this,W,Ut).call(this,o);y(this,K).set(n,{functionName:o.name,outputs:o.inputs.filter(i=>!i.indexed)})}))},Ut=async function(e){if(!e.name||!Array.isArray(e.inputs))throw new Error("Invalid event ABI object.");let r=e.inputs.map(n=>n.type),o=`${e.name}(${r.join(",")})`;return await(0,we.createHash)(o,!1)};var Bt=new be([]);var j=require("zod"),gr=j.z.string(),ee=j.z.string().nonempty("\u0110\u1ECBa ch\u1EC9 kh\xF4ng \u0111\u01B0\u1EE3c \u0111\u1EC3 tr\u1ED1ng").refine(t=>{let e=t.startsWith("0x")?t.slice(2):t;return/^[0-9a-fA-F]{40}$/.test(e)},{message:'\u0110\u1ECBa ch\u1EC9 ph\u1EA3i l\xE0 chu\u1ED7i hex 20 bytes (40 k\xFD t\u1EF1 hex), c\xF3 th\u1EC3 b\u1EAFt \u0111\u1EA7u b\u1EB1ng "0x"'}),vr=j.z.string(),br=j.z.string().regex(/^\d+$/,'Timestamp ph\u1EA3i l\xE0 chu\u1ED7i s\u1ED1 nguy\xEAn kh\xF4ng \xE2m (v\xED d\u1EE5: "1698765432")').transform(t=>{let e=Number(t);if(isNaN(e))throw new Error("Kh\xF4ng th\u1EC3 chuy\u1EC3n \u0111\u1ED5i timestamp th\xE0nh s\u1ED1");return e}).refine(t=>Number.isInteger(t)&&t>=0,{message:"Timestamp ph\u1EA3i l\xE0 s\u1ED1 nguy\xEAn kh\xF4ng \xE2m"}),f=j.z.object({from:ee,to:ee.optional()});var R=class extends Error{constructor(r,o){super(r);this.message=r;this.metadata=o;Error.captureStackTrace(this,this.constructor);let n={requestId:"1"};this.correlationId=n.requestId}toJSON(){return{message:this.message,code:this.code,stack:this.stack,correlationId:this.correlationId,cause:JSON.stringify(this.cause),metadata:this.metadata}}};var Ee="GENERIC.ARGUMENT_INVALID",Oe="GENERIC.ARGUMENT_OUT_OF_RANGE",Ie="GENERIC.ARGUMENT_NOT_PROVIDED",Ce="GENERIC.NOT_FOUND",qe="GENERIC.CONFLICT",Ke="GENERIC.INTERNAL_SERVER_ERROR";var P=class extends R{constructor(){super(...arguments);this.code=Ie}},U=class extends R{constructor(){super(...arguments);this.code=Ee}},te=class extends R{constructor(){super(...arguments);this.code=Oe}},Ue=class extends R{constructor(){super(...arguments);this.code=qe}},Be=class extends R{constructor(){super(...arguments);this.code=Ce}},re=class extends R{constructor(){super(...arguments);this.code=Ke}};var Mt=S(require("zod"));var Lt=require("@metanodejs/mtn-contract"),H=class extends Lt.MtnContract{constructor(e,r){try{let o=ee.parse(e);super({to:o}),this.logger=r}catch(o){let n=o instanceof Error?o.message:"L\u1ED7i kh\xF4ng x\xE1c \u0111\u1ECBnh";throw r.error("Kh\u1EDFi t\u1EA1o BlockchainRepositoryBase th\u1EA5t b\u1EA1i",{error:o}),new U(`\u0110\u1ECBa ch\u1EC9 h\u1EE3p \u0111\u1ED3ng kh\xF4ng h\u1EE3p l\u1EC7: ${n}`)}}validateRequest(e,r){try{if(!r||typeof r=="object"&&Object.keys(r).length===0)throw this.logger.error("D\u1EEF li\u1EC7u y\xEAu c\u1EA7u kh\xF4ng \u0111\u01B0\u1EE3c cung c\u1EA5p",{data:r}),new P("D\u1EEF li\u1EC7u y\xEAu c\u1EA7u ph\u1EA3i \u0111\u01B0\u1EE3c cung c\u1EA5p");return e.parse(r)}catch(o){throw o instanceof Mt.default.ZodError?(this.logger.error("X\xE1c th\u1EF1c d\u1EEF li\u1EC7u th\u1EA5t b\u1EA1i",{error:o.errors}),new U(`D\u1EEF li\u1EC7u y\xEAu c\u1EA7u kh\xF4ng h\u1EE3p l\u1EC7: ${o.message}`)):(this.logger.error("L\u1ED7i x\xE1c th\u1EF1c kh\xF4ng x\xE1c \u0111\u1ECBnh",{error:o}),o)}}async executeTransaction(e){let{...r}=e;try{return await this.sendTransaction(r)}catch(o){this.logger.error("L\u1ED7i kh\xF4ng x\xE1c \u0111\u1ECBnh",o);let n=o instanceof R?o.message:o.message||o.description||"L\u1ED7i kh\xF4ng x\xE1c \u0111\u1ECBnh";throw new re(`Giao d\u1ECBch ${e.functionName} th\u1EA5t b\u1EA1i: ${n}`)}}};var Me=[{inputs:[{internalType:"uint256",name:"numChunks",type:"uint256"}],name:"calculatePrice",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function"}];var Le=[{inputs:[{internalType:"bytes32",name:"downloadKey",type:"bytes32"}],name:"confirmServerDownload",outputs:[],stateMutability:"nonpayable",type:"function"}];var Ne=[{inputs:[{internalType:"bytes32",name:"fileKey",type:"bytes32"}],name:"getFileInfo",outputs:[{components:[{internalType:"address",name:"owner",type:"address"},{internalType:"bytes32",name:"merkleRoot",type:"bytes32"},{internalType:"uint64",name:"contentLen",type:"uint64"},{internalType:"uint64",name:"totalChunks",type:"uint64"},{internalType:"uint64",name:"expireTime",type:"uint64"},{internalType:"string",name:"name",type:"string"},{internalType:"string",name:"ext",type:"string"},{internalType:"string",name:"contentDisposition",type:"string"},{internalType:"string",name:"contentID",type:"string"},{internalType:"enum FileStatus",name:"status",type:"uint8"}],internalType:"struct Info",name:"",type:"tuple"}],stateMutability:"view",type:"function"}];var ze=[{inputs:[],name:"getRustServerAddresses",outputs:[{internalType:"string[]",name:"",type:"string[]"}],stateMutability:"view",type:"function"}];var _e=[{inputs:[{internalType:"bytes32",name:"fileKey",type:"bytes32"},{internalType:"uint256",name:"downloadTimes",type:"uint256"}],name:"payForDownload",outputs:[],stateMutability:"payable",type:"function"}];var $e=[{inputs:[{components:[{internalType:"address",name:"owner",type:"address"},{internalType:"bytes32",name:"merkleRoot",type:"bytes32"},{internalType:"uint64",name:"contentLen",type:"uint64"},{internalType:"uint64",name:"totalChunks",type:"uint64"},{internalType:"uint64",name:"expireTime",type:"uint64"},{internalType:"string",name:"name",type:"string"},{internalType:"string",name:"ext",type:"string"},{internalType:"string",name:"contentDisposition",type:"string"},{internalType:"string",name:"contentID",type:"string"},{internalType:"enum FileStatus",name:"status",type:"uint8"}],internalType:"struct Info",name:"info",type:"tuple"}],name:"pushFileInfo",outputs:[{internalType:"bytes32",name:"fileKey",type:"bytes32"}],stateMutability:"payable",type:"function"}];var Ge=[{inputs:[{internalType:"bytes32",name:"fileKey",type:"bytes32"},{internalType:"bytes",name:"chunkData",type:"bytes"},{internalType:"uint256",name:"chunkIndex",type:"uint256"},{internalType:"bytes32[]",name:"merkleProof",type:"bytes32[]"}],name:"uploadChunk",outputs:[],stateMutability:"nonpayable",type:"function"}];var We=[{inputs:[{internalType:"bytes32",name:"fileKey",type:"bytes32"},{internalType:"bool",name:"status",type:"bool"}],name:"setPublicStatus",outputs:[],stateMutability:"nonpayable",type:"function"}];var je=[{inputs:[{internalType:"bytes32",name:"fileKey",type:"bytes32"},{internalType:"address[]",name:"users",type:"address[]"}],name:"addWhitelist",outputs:[],stateMutability:"nonpayable",type:"function"}];var He=[{inputs:[{internalType:"bytes32",name:"fileKey",type:"bytes32"}],name:"getWhitelist",outputs:[{internalType:"address[]",name:"",type:"address[]"}],stateMutability:"view",type:"function"}];var Ve=[{inputs:[{internalType:"bytes32",name:"fileKey",type:"bytes32"}],name:"isPublicFile",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function"}];var Qe=S(require("zod"));var Ye=f.extend({numChunks:Qe.default.number()}),wr=Qe.default.string();var v=S(require("zod")),Je=f.extend({info:v.default.object({owner:v.default.string(),merkleRoot:v.default.string(),contentLen:v.default.number(),totalChunks:v.default.number(),expireTime:v.default.number(),name:v.default.string(),ext:v.default.string(),contentDisposition:v.default.string(),contentID:v.default.string(),status:v.default.number()}),value:v.default.string()}),xr=v.default.object({fileKey:v.default.string()});var V=S(require("zod")),Xe=f.extend({fileKey:V.default.string(),chunkData:V.default.string(),chunkIndex:V.default.number(),merkleProof:V.default.array(V.default.string())});var D=S(require("zod")),Ze=f.extend({fileKey:D.default.string()}),Dr=D.default.object({owner:D.default.string(),merkleRoot:D.default.string(),contentLen:D.default.number(),totalChunks:D.default.number(),expireTime:D.default.number(),name:D.default.string(),ext:D.default.string(),contentDisposition:D.default.string(),contentID:D.default.string(),status:D.default.number()});var Q=S(require("zod")),et=f.extend({fileKey:Q.default.string(),downloadTimes:Q.default.number(),value:Q.default.string()}),Rr=Q.default.object({transactionHash:Q.default.string().optional()});var tt=S(require("zod"));var rt=f.extend({downloadKey:tt.default.string()}),Pr=tt.default.string();var ot=S(require("zod"));var nt=f.extend({}),Tr=ot.default.array(ot.default.string());var it=require("zod");var st=f.extend({fileKey:it.z.string(),status:it.z.boolean()});var xe=require("zod");var at=f.extend({fileKey:xe.z.string(),users:xe.z.array(xe.z.string())});var Nt=require("zod");var lt=f.extend({fileKey:Nt.z.string()});var zt=require("zod");var ct=f.extend({fileKey:zt.z.string()});var De=class extends H{constructor(){super(g.file,p)}async calculatePrice(e){console.log("calculatePrice request",e);let r=this.validateRequest(Ye,e),o={numChunks:r.numChunks};return this.executeTransaction({to:r.to||g.file,from:r.from,inputData:o,functionName:"calculatePrice",feeType:"read",abiData:Me})}async pushFileInfo(e){let r=this.validateRequest(Je,e),o={info:r.info};return this.executeTransaction({to:r.to||g.file,from:r.from,inputData:o,functionName:"pushFileInfo",feeType:"sc",value:r.value,abiData:$e})}async uploadChunk(e){let r=this.validateRequest(Xe,e),o={fileKey:r.fileKey,chunkData:r.chunkData,chunkIndex:r.chunkIndex,merkleProof:r.merkleProof};return this.executeTransaction({to:r.to||g.file,from:r.from,inputData:o,functionName:"uploadChunk",feeType:"sc",abiData:Ge})}async getFileInfo(e){let r=this.validateRequest(Ze,e),o={fileKey:r.fileKey};return this.executeTransaction({to:r.to||g.file,from:r.from,inputData:o,functionName:"getFileInfo",feeType:"read",abiData:Ne})}async payForDownload(e){let r=this.validateRequest(et,e),o={fileKey:r.fileKey,downloadTimes:r.downloadTimes};return this.executeTransaction({to:r.to||g.file,from:r.from,inputData:o,functionName:"payForDownload",feeType:"sc",value:r.value,abiData:_e})}async confirmServerDownload(e){let r=this.validateRequest(rt,e),o={downloadKey:r.downloadKey};return this.executeTransaction({to:r.to||g.file,from:r.from,inputData:o,functionName:"confirmServerDownload",feeType:"sc",abiData:Le})}async getRustServerAddresses(e){let r=this.validateRequest(nt,e),o={};return this.executeTransaction({to:r.to||g.file,from:r.from,inputData:o,functionName:"getRustServerAddresses",feeType:"read",abiData:ze})}async setPublicStatus(e){let r=this.validateRequest(st,e),o={fileKey:r.fileKey,status:r.status};return this.executeTransaction({to:r.to||g.file,from:r.from,inputData:o,functionName:"setPublicStatus",feeType:"sc",abiData:We})}async addWhitelist(e){let r=this.validateRequest(at,e),o={fileKey:r.fileKey,users:r.users};return this.executeTransaction({to:r.to||g.file,from:r.from,inputData:o,functionName:"addWhitelist",feeType:"sc",abiData:je})}async getWhitelist(e){let r=this.validateRequest(lt,e),o={fileKey:r.fileKey};return this.executeTransaction({to:r.to||g.file,from:r.from,inputData:o,functionName:"getWhitelist",feeType:"read",abiData:He})}async isPublicFile(e){let r=this.validateRequest(ct,e),o={fileKey:r.fileKey};return this.executeTransaction({to:r.to||g.file,from:r.from,inputData:o,functionName:"isPublicFile",feeType:"read",abiData:Ve})}},A=new De;var Re=require("@metanodejs/event-log");var _t=[{anonymous:!1,inputs:[{indexed:!1,internalType:"bytes32",name:"downloadKey",type:"bytes32"},{indexed:!1,internalType:"bytes32",name:"fileKey",type:"bytes32"},{indexed:!1,internalType:"address",name:"user",type:"address"},{indexed:!1,internalType:"uint256",name:"amount",type:"uint256"}],name:"DownloadKeyGenerated",type:"event"},{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"user",type:"address"},{indexed:!1,internalType:"bytes32",name:"fileKey",type:"bytes32"}],name:"FileActivated",type:"event"}];var pt=class t{constructor(){this._abiRegistrationPromise=null;this._registeredEvents=new Set;this._decodeAbi=new Re.DecodeAbi,this._eventLog=new Re.EventLog(this._decodeAbi)}static getInstance(){return t.instance||(t.instance=new t),t.instance}get eventLog(){return this._eventLog}get decodeAbi(){return this._decodeAbi}async registerAbi(){this._abiRegistrationPromise||(this._abiRegistrationPromise=this._decodeAbi.registerAbi(_t).catch(e=>{console.warn("EventLogs: ABI already registered or error",e)})),await this._abiRegistrationPromise}async registerEvent(e,r){let o=`${e.toLowerCase()}-${r.toLowerCase()}`;this._registeredEvents.has(o)||(this._registeredEvents.add(o),await this._eventLog.registerEvent(e,[r]))}},I=pt.getInstance();var $t=require("nanoid"),Gt=(0,$t.customAlphabet)("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"),Wt=22,Ar=25;function oe(t="tu",e=Wt){return`${t}_${Gt(e)}`}var ut="Invariant failed";function k(t,e){if(t)return;throw new Error(ut)}function jt(t){return t!==null}function Ht(t){return t&&Array.isArray(t)}function kr(t){return t===null?!0:!["array","function","object"].includes(typeof t)}var mt=t=>typeof t<"u",Fr=t=>!mt(t),Er=t=>typeof t=="boolean",dt=t=>typeof t=="function",Or=t=>toString.call(t)==="[object Number]",Vt=t=>typeof t=="string",ft=t=>toString.call(t)==="[object Object]",Ir=t=>toString.call(t)==="[object Map]",Cr=t=>toString.call(t)==="[object Set]",qr=t=>toString.call(t)==="[object Date]",Kr=t=>typeof t=="symbol",Ur=t=>ft(t)&&dt(t.then)&&dt(t.catch),Br=t=>jt(t)&&mt(t)&&yt(t),Mr=t=>typeof window<"u"&&toString.call(t)==="[object Window]",Lr=t=>t!==null&&typeof t=="object"&&typeof t.pipe=="function",ne=typeof window<"u",Nr=t=>t?.length===0;function B(t){return t?Ht(t)?Nr(t):Vt(t)?t.trim().length===0:t instanceof Map||t instanceof Set?t.size===0:ft(t)?Object.keys(t).length===0:!1:!0}function yt(t){return!B(t)}function zr(...t){return t.length>1?t.reduce((e,r)=>e&&yt(r),!0):!1}function _r(...t){return t.length>1?t.reduce((e,r)=>e&&B(r),!0):!1}function $r(t){return!t||t.length<8?!1:t[0]===137&&t[1]===80&&t[2]===78&&t[3]===71&&t[4]===13&&t[5]===10&&t[6]===26&&t[7]===10}var Gr=ne?/(android)/i.test(navigator.userAgent):!1,Wr=ne?window.matchMedia||window.msMatchMedia:void 0,jr=ne?Wr?.("(pointer:coarse)")?.matches:!1,Hr=ne&&(!("onscroll"in window)||/(gle|ing|ro)bot|crawl|spider/i.test(navigator.userAgent));function Vr(t){return new Promise(e=>setTimeout(e,t))}function Qr(t,e=!1,r=1){let o=e?1e3:1024;if(Math.abs(t)<o)return t+" B";let n=e?["kB","MB","GB","TB","PB","EB","ZB","YB"]:["KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"],i=-1,a=10**r;do t/=o,++i;while(Math.round(Math.abs(t)*a)/a>=o&&i<n.length-1);return t.toFixed(r)+" "+n[i]}function Yr(t){let e=[],r="abcdef0123456789";for(let o=0;o<t;o++)e.push(r[Math.floor(Math.random()*r.length)]);return e.join("")}var Jr=t=>Promise.allSettled(t).then(e=>e.filter(r=>r.status==="fulfilled").map(r=>r.value));function Xr(t){if(t===0)return"0 Bytes";let e=1024,r=["Bytes","KB","MB","GB","TB"],o=Math.floor(Math.log(t)/Math.log(e));return`${(t/Math.pow(e,o)).toFixed(2)} ${r[o]}`}var ie=class{constructor(e){this.id=e||oe("entity")}equals(e){return!e||!(e instanceof this.constructor)?!1:e.toValue()===this.id}toString(){return String(this.id)}toValue(){return this.id}};var ht=class{constructor(e){k(e,new P("Domain event props should not be empty")),k(e._metadata&&e._metadata.timestamp,new P("Timestamp should be provided in domain event metadata")),this.id=new ie(oe("de")),this.aggregateId=e.aggregateId,this._metadata={correlationId:e?._metadata?.correlationId,causationId:e?._metadata?.causationId,timestamp:e?._metadata?.timestamp}}};var Qt=S(require("mitt"));function Yt(t){let e=(0,Qt.default)(t);return e.emitAsync=async function(r,o){let n=this.all.get(r);if(n)for(let a of n)await a(o);let i=this.all.get("*");if(i)for(let a of i)await a(r,o)},e}var Zr=Yt();var N,Jt,gt,vt=class vt{constructor(e){x(this,N);O(this,N,Jt).call(this,e),this.validate(e),this.props=e}static isValueObject(e){return e instanceof vt}equals(e){return e?JSON.stringify(this)===JSON.stringify(e):!1}raw(){if(O(this,N,gt).call(this,this.props))return this.props.value;let e=se(this.props);return Object.freeze(e)}};N=new WeakSet,Jt=function(e){k(!(B(e)||O(this,N,gt).call(this,e)&&B(e)),new P("Property cannot be empty"))},gt=function(e){return!!Object.prototype.hasOwnProperty.call(e,"value")};var Y=vt;function eo(t){return t===null||typeof t!="object"?!1:Object.prototype.hasOwnProperty.call(t,"toObject")&&Object.prototype.hasOwnProperty.call(t,"id")&&Y.isValueObject(t.id)}function Xt(t){return Y.isValueObject(t)?t.raw():eo(t)?t.toObject():t}function se(t){let e=structuredClone(t);for(let r in e)Array.isArray(e[r])&&(e[r]=e[r].map(o=>Xt(o))),e[r]=Xt(e[r]);return e}var le,z,J,_,Pe,Zt,bt=class bt{constructor({id:e,props:r,createdAt:o,updatedAt:n}){x(this,Pe);x(this,le);x(this,z);x(this,J);x(this,_);L(this,le,e),O(this,Pe,Zt).call(this,r);let i=new Date;L(this,z,o||i),L(this,_,n||i),L(this,J,r),this.validate()}static isEntity(e){return e instanceof bt}get id(){return y(this,le)}get createdAt(){return y(this,z)}get updatedAt(){return y(this,_)}getProps(){let e={id:this.id,createdAt:y(this,z),updatedAt:y(this,_),...y(this,J)};return Object.freeze(e)}getMutableProps(){return y(this,J)}toObject(){let e=se(this.getProps()),r={id:this.id,createdAt:y(this,z),updatedAt:y(this,_),...e};return Object.freeze(r)}};le=new WeakMap,z=new WeakMap,J=new WeakMap,_=new WeakMap,Pe=new WeakSet,Zt=function(e){k(!B(e),new P("Entity props should not be empty")),k(typeof e=="object",new U("Entity props should be an object")),k(Object.keys(e).length<=32,new te("The entity props count must smaller than 32 properties"))};var ae=bt;var M,wt=class extends ae{constructor(){super(...arguments);x(this,M,[])}get domainEvents(){return y(this,M)}addEvent(r){Array.isArray(r)?y(this,M).push(...r):y(this,M).push(r)}clearEvents(){L(this,M,[])}async publishEvents(r,o){for(let n of y(this,M)){let i=n.eventName;r.debug(`[RequestID] "${i}" event published for aggregate ${this.constructor.name} : ${this.id}`),console.log(`[RequestID] "${i}" event published for aggregate ${this.constructor.name} : ${this.id}`),i?o.emit(i,n):r.debug(`[AggregateRoot] Event "${i}" kh\xF4ng c\xF3 eventName, b\u1ECF qua.`)}this.clearEvents()}};M=new WeakMap;function to(t){let e=t.startsWith("0x")?t.slice(2):t;return/^[a-fA-F0-9]{40}$/.test(e)}function ro(t){let e=t.startsWith("0x")?t.slice(2):t;return/^[a-fA-F0-9]{66,130}$/.test(e)}var er=require("@metanodejs/system-core"),oo="0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",Te=null,Se=async()=>Te||(Te=oo,Te),xt=async t=>{if(t.length===0)return await Se();let e=Array.from(t);try{let{hash:r}=await(0,er.createHashWithBuffer)({buffer:e});return r}catch(r){return console.error("sha256 error---",r),console.log("bufferAsNumberArray---",e),""}},X=t=>{let e=t.startsWith("0x")?t.slice(2):t;if(e.length===0)return new Uint8Array(0);let r=new Uint8Array(e.length/2);for(let o=0;o<e.length;o+=2)r[o/2]=parseInt(e.substr(o,2),16);return r},no=t=>t<=0?1:(t--,t|=t>>1,t|=t>>2,t|=t>>4,t|=t>>8,t|=t>>16,t+1),Dt=async t=>{let e=t.length;if(e===0){let s=await Se();return[[],s,[]]}let r=no(e),o=new Array(r),n=await Se(),i=await Promise.all(t.map(xt));for(let s=0;s<r;s++)o[s]=s<e?i[s]:n;let a=[o],l=o;for(;l.length>1;){let s=[];for(let c=0;c<l.length;c+=2){let d=l[c],u=l[c+1]??n,m=X(d),T=X(u),h=new Uint8Array(64);h.set(m,0),h.set(T,32);let E=await xt(h);s.push(E)}a.push(s),l=s}return[o,l[0],a]},Rt=async(t,e)=>{let r=[],o=e,n=await Se();for(let i=0;i<t.length-1;i++){let a=t[i],s=o%2===0?o+1:o-1,c=s<a.length?a[s]:n;r.push(c),o=Math.floor(o/2)}return r},Pt=async(t,e,r,o)=>{let n=t;for(let i=0;i<e.length;i++){let a=e[i],l=(o>>i)%2===0,s=X(l?n:a),c=X(l?a:n),d=new Uint8Array(64);d.set(s,0),d.set(c,32),n=await xt(d)}return n===r};var ce=class{constructor(e,r){this.fileBlockchainRepository=e;this.fileActivatedProvider=r}async execute(e){let{file:r,from:o,chunkSize:n=1024*250}=e;p.info("Starting file upload",{fileName:r.name,chunkSize:n,from:o});let i=await r.arrayBuffer(),a=new Uint8Array(i),l=[];for(let b=0;b<a.length;b+=n)l.push(a.slice(b,b+n));p.info(`File split into ${l.length} chunks`);let[s,c,d]=await Dt(l);p.info("Merkle Tree built",{merkleRoot:c,totalLeaves:s.length});let u=await this.fileBlockchainRepository.calculatePrice({from:o,numChunks:l.length});p.info("Price calculated",{price:u});let m=r.name.includes(".")?r.name.split(".").pop():"",T=Math.floor(Date.now()/1e3)+365*24*60*60,{fileKey:h}=await this.fileBlockchainRepository.pushFileInfo({from:o,info:{owner:o,merkleRoot:c,contentLen:a.length,totalChunks:l.length,expireTime:T,name:r.name,ext:m,contentDisposition:"inline",contentID:c,status:0},value:u});p.info("File registered on-chain",{fileKey:h});let E=l.map(async(b,w)=>{let Ot=s[w],It=await Rt(d,w);if(!await Pt(Ot,It,c,w))throw new Error(`PROOF INVALID FOR CHUNK ${w}! Leaf: ${Ot}, Root expected: ${c}`);let lr="0x"+Array.from(b).map(cr=>cr.toString(16).padStart(2,"0")).join("");return await this.fileBlockchainRepository.uploadChunk({from:o,fileKey:h,chunkData:lr,chunkIndex:w,merkleProof:It}),{chunkIndex:w,success:!0}});if(await Promise.all(E),p.info(`All ${l.length} chunks uploaded successfully`),this.fileActivatedProvider){p.info("Waiting for FileActivated event...",{fileKey:h});try{let b=await this.fileActivatedProvider.waitForFileActivated(h,6e4);p.info("FileActivated event received",{fileKey:b.fileKey,user:b.user})}catch(b){throw p.error("Timeout waiting for FileActivated event",b),new Error(`Upload completed but FileActivated event not received: ${b instanceof Error?b.message:"Unknown error"}`)}}else p.warn("FileActivatedProvider not provided, skipping FileActivated event wait");return{fileKey:h,merkleRoot:c,totalChunks:l.length}}};var Z=require("@metanodejs/system-core");var St="file-storage-v1",Ae=3,tr=200,Tt=class{constructor(){this.mutex=Promise.resolve()}lock(){let e=r=>{};return this.mutex=this.mutex.then(()=>new Promise(e)),new Promise(r=>{e=r})}},io=new Tt,pe=class extends Error{constructor(r,o,n,i){super(i||r);this.code=r;this.retryable=o;this.retryAfterMs=n}};function At(t){let[e,r]=t.split(":");if(!e||!r)throw new Error(`Invalid server address format: ${t}`);let o=parseInt(r,10);if(isNaN(o))throw new Error(`Invalid port in address: ${t}`);return{ip:e,port:o}}var F={};async function rr(t){let{ip:e,port:r}=At(t);F[t]?(F[t]++,console.log(`[Server ${t}] Reuse QUIC connection (ref = ${F[t]})`)):(await(0,Z.connectQuicServer)(e,r,St),F[t]=1,console.log(`[Server ${t}] Connected via QUIC (ref = 1)`))}async function or(t){let{ip:e,port:r}=At(t);try{F[t]&&F[t]>0&&(F[t]--,console.log(`[Server ${t}] Decrement QUIC connection (ref = ${F[t]})`),F[t]===0&&(console.log("handle disconnect server"),Promise.race([(0,Z.disconnectQuicServer)(e,r,St),new Promise(o=>setTimeout(o,2e3))]).catch(o=>console.warn(`[Server ${t}] Disconnect error:`,o)),delete F[t],console.log(`[Server ${t}] Disconnected`)))}catch(o){console.warn(`[Server ${t}] Disconnect error:`,o)}}async function so(t,e,r,o,n,i){let{ip:a,port:l}=At(t),c={command:"DownloadChunkRequest",requestId:`${e}_${o}_${Date.now()}`,chunkIndex:o,totalChunks:n,payload:{file_key:e,download_key:r,chunk_index:o,signature:i}},d=JSON.stringify(c)+`
|
|
2
|
+
`,u=await(0,Z.sendQuicMessage)(a,l,St,d);if(u&&typeof u=="object"&&"success"in u&&u.success===!1)throw new pe(u.code||"NATIVE_QUIC_ERROR",u.retryable===!0,u.retryAfterMs,u.message);let m;try{if(typeof u=="string")m=JSON.parse(u);else if(typeof u=="object"&&u!==null)m=u;else throw new Error(`Invalid response type: ${typeof u}`)}catch{throw new Error("Failed to parse server response")}if(console.log(`[Chunk ${o}] response status`,{status:m.status,hasData:!!m.chunk_data_base64}),m.status!=="SUCCESS"){let w=m.message||"Unknown error";throw new Error(w)}if(!m.chunk_data_base64)throw new Error("No chunk data in response");let T=m.chunk_data_base64,h=atob(T),E=new Uint8Array(h.length);for(let w=0;w<h.length;w++)E[w]=h.charCodeAt(w);return{chunkIndex:typeof m.chunkIndex=="number"?m.chunkIndex:o,bytes:E}}async function ao(t){try{let e=await A.getRustServerAddresses({from:t});if(!e||e.length===0)throw new Error("No Rust server addresses found on blockchain");if(e.length<2)throw new Error(`Insufficient Rust servers: found ${e.length}, need at least 2`);return console.log("Server addresses from blockchain:",e),e}catch(e){let r=e instanceof Error?e.message:String(e);throw new Error(`Failed to get Rust server addresses from blockchain: ${r}`)}}function lo(t,e){let r=t%2;if(!e[r])throw new Error(`Server address not found for chunk index ${t}`);return e[r]}async function nr(t,e,r,o,n,i){let a=lo(r,i),l=r%2===0;console.log(`[Chunk ${r}] Requesting from ${l?"Server 1":"Server 2"} (${a})`);let s=null;for(let c=0;c<Ae;c++)try{let d=await so(a,t,e,r,o,n);return{chunkIndex:d.chunkIndex,data:d.bytes}}catch(d){if(s=d instanceof Error?d:new Error(String(d)),s instanceof pe){if(!s.retryable)throw s;let m=s.retryAfterMs??tr;console.warn(`[Chunk ${r}] Native QUIC Error: ${s.code}. Retrying after ${m}ms...`),await new Promise(T=>setTimeout(T,m));continue}if(s.message.toLowerCase().includes("to store chunk on disk"))throw console.log(`[Chunk ${r}] Success (stored on disk), no retry needed`),s;console.warn(`[Chunk ${r}] Request attempt ${c+1}/${Ae} failed:`,s.message),c<Ae-1&&await new Promise(m=>setTimeout(m,tr))}throw new Error(`[Chunk ${r}] Request failed sau ${Ae} l\u1EA7n th\u1EED: ${s?.message}`)}async function ir(t,e,r,o,n,i){console.log(`Starting download of ${r} chunks...`);let a=await ao(n);if(a.length<2)throw new Error("Need at least 2 server addresses to download chunks");let l=a[0],s=a[1];console.log(`Using servers: ${l}, ${s}`),await Promise.all([rr(l),rr(s)]);let c=new Array(r),d=0,u=0,m=4;async function T(){for(;;){let h=d++;if(h>=r)return;let E=await nr(t,e,h,r,o,a);c[E.chunkIndex]=E.data,u++,i?.(u,r)}}try{return await Promise.all(Array.from({length:m},()=>T())),console.log(`Downloaded all ${u} chunks successfully`),c}finally{await Promise.all([or(l),or(s)])}}async function kt(t,e,r,o,n,i){let a=await io.lock();try{let l=await ir(t,e,r,o,n,i),s=l.reduce((u,m)=>u+m.length,0),c=new Uint8Array(s),d=0;for(let u of l)c.set(u,d),d+=u.length;return console.log(`Merged file size: ${c.length} bytes`),c}finally{a()}}var ke=require("@metanodejs/system-core");async function Ft(t,e){try{let o=`0x00${t.startsWith("0x")?t.slice(2):t}`,n=await(0,ke.createHash)(o,!1),{sign:i}=await(0,ke.createSignECDH)({message:n,privateKey:e,hash:n});return i}catch(r){throw console.error("Error generating signature:",r),new Error("Failed to generate signature for download key")}}var sr=require("@metanodejs/system-core"),Et=class{constructor(){this.mutex=Promise.resolve()}lock(){let e=r=>{};return this.mutex=this.mutex.then(()=>new Promise(e)),new Promise(r=>{e=r})}},co=new Et,ue=class{constructor(e,r){this.fileBlockchainRepository=e;this.downloadKeyProvider=r}async execute(e){let{fileKey:r,from:o,downloadTimes:n=1}=e;p.info("Starting file download",{fileKey:r,from:o});let i=await this.fileBlockchainRepository.getFileInfo({from:o,fileKey:r});p.info("File info retrieved",{name:i.name,totalChunks:i.totalChunks,status:i.status});let a=await this.fileBlockchainRepository.calculatePrice({from:o,numChunks:+i.totalChunks});p.info("Download price calculated",{price:a});let l=await co.lock();try{await this.fileBlockchainRepository.payForDownload({from:o,fileKey:r,downloadTimes:n,value:a})}finally{l()}p.info("Payment completed, waiting for download key...");let{downloadKey:s}=await this.downloadKeyProvider.getDownloadKey(r),c=await(0,sr.getPrivateKeyFromDb)(o);if(!c)throw new Error("Private key is required to generate signature for download");let d=await Ft(s,c),u=await kt(r,s,i.totalChunks,d,o,(m,T)=>{p.info(`Download progress: ${m}/${T}`)});return p.info("File downloaded and merged",{size:u.length}),{fileData:u,fileName:i.name,fileExt:i.ext||""}}};var de=class{constructor(e){this.fileBlockchainRepository=e}async execute(e){return p.info("Executing SetPublicStatusUseCase",{fileKey:e.fileKey,status:e.status}),this.fileBlockchainRepository.setPublicStatus({from:e.from,fileKey:e.fileKey,status:e.status})}};var me=class{constructor(e){this.fileBlockchainRepository=e}async execute(e){return p.info("Executing AddWhitelistUseCase",{fileKey:e.fileKey,usersCount:e.users.length}),this.fileBlockchainRepository.addWhitelist({from:e.from,fileKey:e.fileKey,users:e.users})}};var fe=class{constructor(e){this.fileBlockchainRepository=e}async execute(e){return p.info("Executing GetWhitelistUseCase",{fileKey:e.fileKey}),this.fileBlockchainRepository.getWhitelist({from:e.from,fileKey:e.fileKey})}};var ye=class{constructor(e){this.fileBlockchainRepository=e}async execute(e){return p.info("Executing IsPublicFileUseCase",{fileKey:e.fileKey}),this.fileBlockchainRepository.isPublicFile({from:e.from,fileKey:e.fileKey})}};var C=S(require("zod")),po=C.default.object({file:C.default.instanceof(File),from:C.default.string(),chunkSize:C.default.number().optional().default(1024*250)}),uo=C.default.object({fileKey:C.default.string(),merkleRoot:C.default.string(),totalChunks:C.default.number()});var q=S(require("zod")),mo=q.default.object({fileKey:q.default.string(),from:q.default.string(),downloadTimes:q.default.number().optional().default(1)}),fo=q.default.object({fileData:q.default.instanceof(Uint8Array),fileName:q.default.string(),fileExt:q.default.string()});var $=class{constructor(){this.downloadKeys=new Map;this.pendingRequests=new Map;this.unsubscribe=null;this.isInitialized=!1;this.startListening()}async initialize(e,r){if(this.isInitialized){p.info("DownloadKeyListenerService: Already initialized");return}try{await I.registerEvent(e,r),this.isInitialized=!0}catch(o){throw p.error("DownloadKeyListenerService: Failed to initialize",o),o}}startListening(){this.unsubscribe=I.eventLog.onEventLog(e=>{e.type==="DownloadKeyGenerated"&&this.handleDownloadKeyGenerated(e.payload)})}handleDownloadKeyGenerated(e){try{let r=this.normalizeFileKey(e?.fileKey),o=e?.downloadKey||null,n=e?.user||"",i=e?.amount||"0";if(!r||!o){p.warn("DownloadKeyGenerated event missing required fields",{payload:e});return}let a={downloadKey:o,fileKey:r,user:n,amount:i,timestamp:Date.now()};this.downloadKeys.set(r,a);let l=this.pendingRequests.get(r);l&&(l.forEach(({resolve:s,timeout:c})=>{clearTimeout(c),s(a)}),this.pendingRequests.delete(r))}catch(r){p.error("Error handling DownloadKeyGenerated event",r)}}normalizeFileKey(e){return e?(e.toLowerCase().startsWith("0x")?e.toLowerCase().slice(2):e.toLowerCase()).padStart(64,"0"):null}async getDownloadKey(e,r=3e4){let o=this.normalizeFileKey(e);if(!o)throw new Error("Invalid fileKey");let n=this.downloadKeys.get(o);return n?{downloadKey:n.downloadKey,user:n.user,amount:n.amount}:new Promise((i,a)=>{let l=setTimeout(()=>{let s=this.pendingRequests.get(o);if(s){let c=s.findIndex(d=>d.resolve===i);c>-1&&s.splice(c,1),s.length===0&&this.pendingRequests.delete(o)}a(new Error(`Timeout waiting for downloadKey for fileKey: ${e} after ${r}ms`))},r);this.pendingRequests.has(o)||this.pendingRequests.set(o,[]),this.pendingRequests.get(o).push({resolve:i,reject:a,timeout:l})})}stop(){this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=null),this.downloadKeys.clear(),this.pendingRequests.clear()}clearCache(){this.downloadKeys.clear()}};var G=class{constructor(){this.activatedFiles=new Map;this.pendingRequests=new Map;this.unsubscribe=null;this.isInitialized=!1;this.startListening()}async initialize(e,r){if(this.isInitialized){p.info("FileActivatedListenerService: Already initialized");return}try{await I.registerEvent(e,r),this.isInitialized=!0}catch(o){throw p.error("FileActivatedListenerService: Failed to initialize",o),o}}startListening(){this.unsubscribe=I.eventLog.onEventLog(e=>{e.type==="FileActivated"&&this.handleFileActivated(e.payload)})}handleFileActivated(e){try{let r=this.normalizeFileKey(e?.fileKey),o=e?.user||"";if(!r||!o){p.warn("FileActivated event missing required fields",{payload:e});return}let n={fileKey:r,user:o,timestamp:Date.now()};this.activatedFiles.set(r,n);let i=this.pendingRequests.get(r);i&&(i.forEach(({resolve:a,timeout:l})=>{clearTimeout(l),a(n)}),this.pendingRequests.delete(r))}catch(r){p.error("Error handling FileActivated event",r)}}normalizeFileKey(e){return e?(e.toLowerCase().startsWith("0x")?e.toLowerCase().slice(2):e.toLowerCase()).padStart(64,"0"):null}async waitForFileActivated(e,r=6e4){let o=this.normalizeFileKey(e);if(!o)throw new Error("Invalid fileKey");let n=this.activatedFiles.get(o);return n?{fileKey:n.fileKey,user:n.user}:new Promise((i,a)=>{let l=setTimeout(()=>{let s=this.pendingRequests.get(o);if(s){let c=s.findIndex(d=>d.resolve===i);c>-1&&s.splice(c,1),s.length===0&&this.pendingRequests.delete(o)}a(new Error(`Timeout waiting for FileActivated event for fileKey: ${e} after ${r}ms`))},r);this.pendingRequests.has(o)||this.pendingRequests.set(o,[]),this.pendingRequests.get(o).push({resolve:i,reject:a,timeout:l})})}stop(){this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=null),this.activatedFiles.clear(),this.pendingRequests.clear()}clearCache(){this.activatedFiles.clear()}};var he=class{constructor(e,r){this.downloadFileUseCase=null;this.downloadKeyListenerService=null;this.fileActivatedListenerService=null;this.initPromise=null;let o=this.createDefaultFileActivatedProvider();this.uploadFileUseCase=new ce(A,o||void 0),this.setPublicStatusUseCase=new de(A),this.addWhitelistUseCase=new me(A),this.getWhitelistUseCase=new fe(A),this.isPublicFileUseCase=new ye(A);let n=e||this.createDefaultDownloadKeyProvider();if(n&&(this.downloadFileUseCase=new ue(A,n)),r?.userAddress){let i=r.contractAddress||g.file;this.initialize(r.userAddress,i).catch(a=>{console.warn("Failed to auto-initialize FileModuleContainer:",a)})}}createDefaultDownloadKeyProvider(){try{return this.downloadKeyListenerService=new $,this.downloadKeyListenerService}catch(e){return console.warn("Failed to create DownloadKeyListenerService:",e),null}}createDefaultFileActivatedProvider(){try{return this.fileActivatedListenerService=new G,this.fileActivatedListenerService}catch(e){return console.warn("Failed to create FileActivatedListenerService:",e),null}}getUploadFileUseCase(){return this.uploadFileUseCase}getDownloadFileUseCase(){if(!this.downloadFileUseCase)throw new Error("DownloadKeyProvider is required for download functionality");return this.downloadFileUseCase}getSetPublicStatusUseCase(){return this.setPublicStatusUseCase}getAddWhitelistUseCase(){return this.addWhitelistUseCase}getGetWhitelistUseCase(){return this.getWhitelistUseCase}getIsPublicFileUseCase(){return this.isPublicFileUseCase}async initialize(e,r){return this.initPromise||(this.initPromise=(async()=>{await I.registerAbi(),this.downloadKeyListenerService instanceof $?await this.downloadKeyListenerService.initialize(e,r):console.warn("DownloadKeyListenerService not available, cannot initialize"),this.fileActivatedListenerService instanceof G?await this.fileActivatedListenerService.initialize(e,r):console.warn("FileActivatedListenerService not available, cannot initialize")})()),this.initPromise}cleanup(){this.downloadKeyListenerService&&(this.downloadKeyListenerService.stop(),this.downloadKeyListenerService=null),this.fileActivatedListenerService&&(this.fileActivatedListenerService.stop(),this.fileActivatedListenerService=null)}};function ar(t,e){return new he(t,e)}
|
|
3
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/config/app.config.ts","../src/core/Infrastructure-base/logger/logger.ts","../src/core/Infrastructure-base/contracts/decode/decode-abi.service.ts","../src/core/Infrastructure-base/blockchain/repositories/blockchain.type.ts","../src/core/exceptions/exception.base.ts","../src/core/exceptions/exception.codes.ts","../src/core/exceptions/exceptions.ts","../src/core/Infrastructure-base/blockchain/repositories/repository.blockchain.base.ts","../src/core/Infrastructure-base/blockchain/fileblockchain/abis/calculate-price.abi.ts","../src/core/Infrastructure-base/blockchain/fileblockchain/abis/confirm-server-download.abi.ts","../src/core/Infrastructure-base/blockchain/fileblockchain/abis/get-file-info.abi.ts","../src/core/Infrastructure-base/blockchain/fileblockchain/abis/get-rust-server-addresses.abi.ts","../src/core/Infrastructure-base/blockchain/fileblockchain/abis/pay-for-download.abi.ts","../src/core/Infrastructure-base/blockchain/fileblockchain/abis/push-file-info.abi.ts","../src/core/Infrastructure-base/blockchain/fileblockchain/abis/upload-chunk.abi.ts","../src/core/Infrastructure-base/blockchain/fileblockchain/abis/set-public-status.abi.ts","../src/core/Infrastructure-base/blockchain/fileblockchain/abis/add-whitelist.abi.ts","../src/core/Infrastructure-base/blockchain/fileblockchain/abis/get-whitelist.abi.ts","../src/core/Infrastructure-base/blockchain/fileblockchain/abis/is-public-file.abi.ts","../src/core/Infrastructure-base/blockchain/fileblockchain/dtos/calculate-price.dto.ts","../src/core/Infrastructure-base/blockchain/fileblockchain/dtos/push-file-info.dto.ts","../src/core/Infrastructure-base/blockchain/fileblockchain/dtos/upload-chunk.dto.ts","../src/core/Infrastructure-base/blockchain/fileblockchain/dtos/get-file-info.dto.ts","../src/core/Infrastructure-base/blockchain/fileblockchain/dtos/pay-for-download.dto.ts","../src/core/Infrastructure-base/blockchain/fileblockchain/dtos/confirm-server-download.dto.ts","../src/core/Infrastructure-base/blockchain/fileblockchain/dtos/get-rust-server-addresses.dto.ts","../src/core/Infrastructure-base/blockchain/fileblockchain/dtos/set-public-status.dto.ts","../src/core/Infrastructure-base/blockchain/fileblockchain/dtos/add-whitelist.dto.ts","../src/core/Infrastructure-base/blockchain/fileblockchain/dtos/get-whitelist.dto.ts","../src/core/Infrastructure-base/blockchain/fileblockchain/dtos/is-public-file.dto.ts","../src/core/Infrastructure-base/blockchain/fileblockchain/file-blockchain.repository.ts","../src/core/Infrastructure-base/eventLog/event-log.ts","../src/core/Infrastructure-base/eventLog/abi.json","../src/core/helpers/ids.ts","../src/core/utils/invariant.ts","../src/core/utils/is.ts","../src/core/utils/delay.ts","../src/core/utils/format.ts","../src/core/utils/random.ts","../src/core/utils/index.ts","../src/core/domain-base/entities/unique-entity.ts","../src/core/domain-base/events/domain-event.base.ts","../src/core/domain-base/events/domain-event.helper.ts","../src/core/domain-base/entities/value-object.base.ts","../src/core/helpers/object.ts","../src/core/domain-base/entities/entity.base.ts","../src/core/domain-base/entities/aggregate.base.ts","../src/core/helpers/crypto-validator.ts","../src/utils/merkle.ts","../src/modules/file/application/usecases/upload-file.use-case.ts","../src/modules/file/infrastructure/services/rust-server-client.service.ts","../src/utils/signature.ts","../src/modules/file/application/usecases/download-file.use-case.ts","../src/modules/file/application/usecases/set-public-status.use-case.ts","../src/modules/file/application/usecases/add-whitelist.use-case.ts","../src/modules/file/application/usecases/get-whitelist.use-case.ts","../src/modules/file/application/usecases/is-public-file.use-case.ts","../src/modules/file/application/dtos/upload-file.dto.ts","../src/modules/file/application/dtos/download-file.dto.ts","../src/modules/file/infrastructure/services/download-key-listener.service.ts","../src/modules/file/infrastructure/services/file-activated-listener.service.ts","../src/modules/file/container.ts"],"sourcesContent":["export * from './config/app.config'\nexport * from './core/Infrastructure-base'\nexport * from './core/domain-base'\nexport * from './core/exceptions/exception.base'\nexport * from './core/exceptions/exception.codes'\nexport * from './core/exceptions/exceptions'\nexport * from './core/helpers'\nexport * from './core/utils'\nexport * from './types'\nexport * from './modules/file'\nexport * from './modules/file/container'\nexport { createFileModule, FileModuleContainer } from './modules/file/container'\nexport type { DownloadKeyProvider } from './modules/file/application/usecases/download-file.use-case'\nexport { DownloadKeyListenerService } from './modules/file/infrastructure/services/download-key-listener.service'\nexport {\n FileActivatedListenerService,\n type FileActivatedProvider\n} from './modules/file/infrastructure/services/file-activated-listener.service'\nexport * from './utils'\n","export const appConfig = {\n file: '0x087cdab97d38a3bfFcDee170739E8C11Af651569'\n}\n","import type { LoggerPort } from './logger.port'\nimport type { LogLevel } from './logger.type'\n\nexport class Logger implements LoggerPort {\n private readonly isDev: boolean\n private readonly prefix: string\n\n constructor(prefix = '') {\n this.isDev = process.env.NODE_ENV !== 'production'\n this.prefix = prefix\n }\n\n private formatMessage(level: LogLevel, args: any[]): any[] {\n const timestamp = new Date().toISOString()\n return [`[${timestamp}] [${level.toUpperCase()}] ${this.prefix}`, ...args]\n }\n\n debug(...args: any[]) {\n if (this.isDev) {\n console.debug(...this.formatMessage('debug', args))\n }\n }\n\n info(...args: any[]) {\n if (this.isDev) {\n console.info(...this.formatMessage('info', args))\n }\n }\n\n warn(...args: any[]) {\n if (this.isDev) {\n console.warn(...this.formatMessage('warn', args))\n }\n }\n\n error(...args: any[]) {\n if (this.isDev) {\n console.error(...this.formatMessage('error', args))\n }\n }\n\n log(...args: any[]) {\n if (this.isDev) {\n console.log(...this.formatMessage('log', args))\n }\n }\n}\n\nexport const logger = new Logger('FILE-MODULE')\n","import { createHash, decodeAbi } from '@metanodejs/system-core'\n\ninterface IAbiItemBase {\n internalType: string\n name: string\n type: string\n indexed: boolean\n // thêm các field tùy ý cũng được:\n [key: string]: any\n}\n\ninterface IAbiBase {\n inputs: IAbiItemBase[]\n name: string\n stateMutability?: string\n type: string\n [key: string]: any // <- cho phép thêm field khác như `anonymous`, `indexed`, ...\n}\n\ninterface AbiData {\n functionName: string\n outputs: IAbiBase['outputs']\n}\n\nexport class DecodeAbiService {\n #map = new Map<string, AbiData>()\n\n constructor(abis: IAbiBase[]) {\n this.#initializeAbi(abis)\n }\n\n get abiArray() {\n return [...this.#map]\n }\n\n async #initializeAbi(abis: IAbiBase[]) {\n const result = await Promise.all(\n abis.map(async (abi) => {\n const hash = await this.#abiToHash(abi)\n this.#map.set(hash, {\n functionName: abi.name,\n outputs: abi.inputs.filter((i) => !i.indexed)\n })\n })\n )\n return result\n }\n\n async #abiToHash(abi: IAbiBase) {\n if (!abi.name || !Array.isArray(abi.inputs)) {\n throw new Error('Invalid event ABI object.')\n }\n\n const types = abi.inputs.map((input) => input.type)\n const signature = `${abi.name}(${types.join(',')})`\n return await createHash(signature, false)\n }\n\n getAbiData(raw: string) {\n if (this.#map.size === 0) return\n const matchHash = [...this.#map.keys()].find((i) => raw.startsWith(i))\n if (!matchHash) return\n return this.#map.get(matchHash)\n }\n\n async handleDecodeAbi(\n topic: string,\n raw: string\n ): Promise<{ decodedData: unknown; event: string } | undefined> {\n const abiData = decodeAbiService.getAbiData(topic)\n if (!abiData) return\n const decodedData = await decodeAbi({\n ...abiData,\n rawInput: raw\n })\n\n return { decodedData, event: abiData.functionName }\n }\n}\n\nexport const decodeAbiService = new DecodeAbiService([])\n","import { z } from 'zod'\n\n/**\n * Schema để xác thực một chuỗi hex 32 bytes (bytes32 trong Solidity).\n * Chuỗi phải chứa chính xác 64 ký tự hex (0-9, a-f, A-F), có thể có hoặc không có tiền tố \"0x\".\n *\n * @example\n * \"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef\" // Hợp lệ\n * \"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef\" // Hợp lệ\n * \"0x123\" // Không hợp lệ (quá ngắn)\n * \"0xGHI\" // Không hợp lệ (không phải hex)\n */\nexport const Bytes32Schema = z.string()\n\nexport type Bytes32DTO = z.infer<typeof Bytes32Schema>\n\n/**\n * Schema để xác thực địa chỉ Ethereum (40 ký tự hex, tùy chọn \"0x\").\n * Hỗ trợ kiểm tra checksum EIP-55 nếu cần.\n *\n * @example\n * \"0x1234567890abcdef1234567890abcdef12345678\" // Hợp lệ\n * \"1234567890abcdef1234567890abcdef12345678\" // Hợp lệ\n * \"0x123\" // Không hợp lệ (quá ngắn)\n * \"0xGHI\" // Không hợp lệ (không phải hex)\n */\nexport const AddressSchema = z\n .string()\n .nonempty('Địa chỉ không được để trống')\n .refine(\n (val) => {\n const cleaned = val.startsWith('0x') ? val.slice(2) : val\n return /^[0-9a-fA-F]{40}$/.test(cleaned)\n },\n {\n message: 'Địa chỉ phải là chuỗi hex 20 bytes (40 ký tự hex), có thể bắt đầu bằng \"0x\"'\n }\n )\n\nexport type AddressDTO = z.infer<typeof AddressSchema>\n\n/**\n * Schema để xác thực khóa công khai không nén (128 ký tự hex, tương ứng 64 bytes).\n *\n * @example\n * \"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef\" // Hợp lệ\n * \"0x123\" // Không hợp lệ (quá ngắn)\n * \"0xGHI\" // Không hợp lệ (không phải hex)\n */\nexport const PublicKeySchema = z.string()\n\nexport type PublicKeyDTO = z.infer<typeof PublicKeySchema>\n\n/**\n * Schema để xác thực và chuyển đổi timestamp từ chuỗi thành số nguyên không âm.\n * Dùng để xử lý các giá trị timestamp trả về từ hợp đồng thông minh (ví dụ: \"1698765432\").\n *\n * @example\n * ```typescript\n * TimestampSchema.parse(\"1698765432\") // Kết quả: 1698765432\n * TimestampSchema.parse(\"abc\") // Lỗi: \"Timestamp phải là chuỗi số nguyên không âm\"\n * ```\n */\nexport const TimestampSchema = z\n .string()\n .regex(/^\\d+$/, 'Timestamp phải là chuỗi số nguyên không âm (ví dụ: \"1698765432\")')\n .transform((val) => {\n const num = Number(val)\n if (isNaN(num)) {\n throw new Error('Không thể chuyển đổi timestamp thành số')\n }\n return num\n })\n .refine((val) => Number.isInteger(val) && val >= 0, {\n message: 'Timestamp phải là số nguyên không âm'\n })\n\nexport type TimestampDTO = z.infer<typeof TimestampSchema>\n\n/**\n * Schema cơ bản cho các yêu cầu blockchain, chứa địa chỉ người gửi và hợp đồng đích (tùy chọn).\n *\n * @example\n * ```typescript\n * {\n * from: \"0x1234567890abcdef1234567890abcdef12345678\",\n * to: \"0xabcdef1234567890abcdef1234567890abcdef12\" // Tùy chọn\n * }\n * ```\n */\nexport const BaseRequestSchema = z.object({\n from: AddressSchema,\n to: AddressSchema.optional()\n})\n\nexport type BaseRequestDTO = z.infer<typeof BaseRequestSchema>\n","export interface NormalizedException {\n message: string\n code: string\n correlationId: string\n stack?: string | undefined\n cause?: string | undefined\n /**\n * ^ Consider adding optional `metadata` object to\n * exceptions (if language doesn't support anything\n * similar by default) and pass some useful technical\n * information about the exception when throwing.\n * This will make debugging easier.\n */\n metadata?: Record<string, unknown> | undefined\n}\n\nexport abstract class ExceptionBase extends Error {\n abstract code: string\n readonly correlationId: string\n\n /**\n * @param {string} message\n * @param {ObjectLiteral} [metadata={}]\n * **BE CAREFUL** not to include sensitive info in 'metadata'\n * to prevent leaks since all exception's data will end up\n * in application's log files. Only include non-sensitive\n * info that may help with debugging.\n */\n constructor(\n readonly message: string,\n readonly metadata?: Record<string, unknown>\n ) {\n super(message)\n Error.captureStackTrace(this, this.constructor)\n const ctx = {\n requestId: '1'\n }\n this.correlationId = ctx.requestId\n }\n\n toJSON(): NormalizedException {\n return {\n message: this.message,\n code: this.code,\n stack: this.stack,\n correlationId: this.correlationId,\n cause: JSON.stringify((this as any).cause),\n metadata: this.metadata\n }\n }\n}\n","/**\n * Adding a `code` string with a custom status code for every\n * exception is a good practice.\n *\n * Since when that exception is transferred to another process `instanceof`\n * check cannot be performed anymore so a `code` string is used instead.\n *\n * Code constants can be stored in a separate file so they\n * can be shared and reused on a receiving side (code sharing is\n * useful when developing fullstack apps or microservices)\n */\nexport const ARGUMENT_INVALID = 'GENERIC.ARGUMENT_INVALID'\nexport const ARGUMENT_OUT_OF_RANGE = 'GENERIC.ARGUMENT_OUT_OF_RANGE'\nexport const ARGUMENT_NOT_PROVIDED = 'GENERIC.ARGUMENT_NOT_PROVIDED'\nexport const NOT_FOUND = 'GENERIC.NOT_FOUND'\nexport const CONFLICT = 'GENERIC.CONFLICT'\nexport const INTERNAL_SERVER_ERROR = 'GENERIC.INTERNAL_SERVER_ERROR'\n","import { ExceptionBase } from './exception.base'\nimport {\n ARGUMENT_INVALID,\n ARGUMENT_NOT_PROVIDED,\n ARGUMENT_OUT_OF_RANGE,\n CONFLICT,\n INTERNAL_SERVER_ERROR,\n NOT_FOUND\n} from './exception.codes'\n\n/**\n * Used to indicate that an argument was not provided (is empty object/array, null of undefined).\n *\n * @class ArgumentNotProvidedException\n * @extends {ExceptionBase}\n */\nexport class ArgumentNotProvidedException extends ExceptionBase {\n readonly code = ARGUMENT_NOT_PROVIDED\n}\n\n/**\n * Used to indicate that an incorrect argument was provided to a method/function/class constructor\n *\n * @class ArgumentInvalidException\n * @extends {ExceptionBase}\n */\nexport class ArgumentInvalidException extends ExceptionBase {\n readonly code = ARGUMENT_INVALID\n}\n\n/**\n * Used to indicate that an argument is out of allowed range\n * (for example: incorrect string/array length, number not in allowed min/max range etc)\n *\n * @class ArgumentOutOfRangeException\n * @extends {ExceptionBase}\n */\nexport class ArgumentOutOfRangeException extends ExceptionBase {\n readonly code = ARGUMENT_OUT_OF_RANGE\n}\n\n/**\n * Used to indicate conflicting entities (usually in the database)\n *\n * @class ConflictException\n * @extends {ExceptionBase}\n */\nexport class ConflictException extends ExceptionBase {\n readonly code = CONFLICT\n}\n\n/**\n * Used to indicate that entity is not found\n *\n * @class NotFoundException\n * @extends {ExceptionBase}\n */\nexport class NotFoundException extends ExceptionBase {\n readonly code = NOT_FOUND\n}\n\n/**\n * Used to indicate an internal server error that does not fall under all other errors\n *\n * @class InternalServerErrorException\n * @extends {ExceptionBase}\n */\nexport class InternalServerErrorException extends ExceptionBase {\n readonly code = INTERNAL_SERVER_ERROR\n}\n","import type { BlockchainRepositoryPort } from './blockchain.repository.port'\nimport { AddressSchema, type AddressDTO } from './blockchain.type'\nimport type { LoggerPort } from '../../logger'\nimport {\n ArgumentInvalidException,\n ArgumentNotProvidedException,\n InternalServerErrorException\n} from '../../../exceptions/exceptions'\nimport z from 'zod'\nimport { ExceptionBase } from '../../../exceptions/exception.base'\nimport { CallFunctionPayload } from '@metanodejs/system-core'\nimport { MtnContract } from '@metanodejs/mtn-contract'\n\n/**\n * Lớp cơ sở trừu tượng để xử lý các hoạt động blockchain, cung cấp các phương thức chung để xác thực,\n * thực thi giao dịch và ghi log. Các lớp con như FileBlockchainRepository\n * có thể kế thừa để triển khai các tác vụ cụ thể như upload file hoặc download file.\n *\n * @class BlockchainRepositoryBase\n * @extends {MtnContract}\n * @implements {BlockchainRepositoryPort}\n */\nexport abstract class BlockchainRepositoryBase\n extends MtnContract\n implements BlockchainRepositoryPort\n{\n protected readonly logger: LoggerPort\n\n /**\n * Khởi tạo BlockchainRepositoryBase với địa chỉ hợp đồng và logger.\n *\n * @param to - Địa chỉ hợp đồng blockchain.\n * @param logger - Đối tượng logger để ghi log các sự kiện và lỗi.\n * @throws {ArgumentInvalidException} Nếu địa chỉ hợp đồng không hợp lệ.\n */\n protected constructor(to: AddressDTO, logger: LoggerPort) {\n try {\n const validatedAddress = AddressSchema.parse(to)\n super({ to: validatedAddress })\n this.logger = logger\n } catch (error: unknown) {\n const errorMessage = error instanceof Error ? error.message : 'Lỗi không xác định'\n logger.error('Khởi tạo BlockchainRepositoryBase thất bại', { error })\n throw new ArgumentInvalidException(`Địa chỉ hợp đồng không hợp lệ: ${errorMessage}`)\n }\n }\n\n /**\n * Xác thực dữ liệu yêu cầu bằng schema Zod.\n *\n * @param schema - Schema Zod để xác thực dữ liệu.\n * @param data - Dữ liệu cần xác thực.\n * @returns Dữ liệu đã được xác thực.\n * @throws {ArgumentNotProvidedException} Nếu dữ liệu là null, undefined hoặc đối tượng rỗng.\n * @throws {ArgumentInvalidException} Nếu dữ liệu không thỏa mãn schema.\n */\n validateRequest<T>(schema: z.ZodSchema<T>, data: unknown): T {\n try {\n if (!data || (typeof data === 'object' && Object.keys(data as object).length === 0)) {\n this.logger.error('Dữ liệu yêu cầu không được cung cấp', { data })\n throw new ArgumentNotProvidedException('Dữ liệu yêu cầu phải được cung cấp')\n }\n return schema.parse(data)\n } catch (error: unknown) {\n if (error instanceof z.ZodError) {\n this.logger.error('Xác thực dữ liệu thất bại', { error: (error as any).errors })\n throw new ArgumentInvalidException(`Dữ liệu yêu cầu không hợp lệ: ${error.message}`)\n }\n this.logger.error('Lỗi xác thực không xác định', { error })\n throw error\n }\n }\n\n /**\n * Thực thi giao dịch blockchain với cơ chế retry.\n *\n * @param params - Tham số giao dịch bao gồm địa chỉ, dữ liệu đầu vào, tên hàm, ABI và số lần thử lại.\n * @returns Kết quả giao dịch.\n * @throws {InternalServerErrorException} Nếu giao dịch thất bại sau số lần thử lại.\n */\n async executeTransaction<T>(params: {\n to?: string\n from: string\n inputData?: unknown\n functionName: string\n feeType: string\n abiData: unknown\n value?: string | bigint\n }): Promise<T> {\n const { ...transactionParams } = params\n try {\n return await this.sendTransaction<T>(transactionParams as CallFunctionPayload)\n } catch (error: unknown) {\n this.logger.error('Lỗi không xác định', error)\n const errorMessage =\n error instanceof ExceptionBase\n ? error.message\n : (error as Error).message || (error as any).description || 'Lỗi không xác định'\n throw new InternalServerErrorException(\n `Giao dịch ${params.functionName} thất bại: ${errorMessage}`\n )\n }\n }\n}\n","export const calculatePriceAbi = [\n {\n inputs: [\n {\n internalType: 'uint256',\n name: 'numChunks',\n type: 'uint256'\n }\n ],\n name: 'calculatePrice',\n outputs: [\n {\n internalType: 'uint256',\n name: '',\n type: 'uint256'\n }\n ],\n stateMutability: 'view',\n type: 'function'\n }\n]\n","export const confirmServerDownloadAbi = [\n {\n inputs: [\n {\n internalType: 'bytes32',\n name: 'downloadKey',\n type: 'bytes32'\n }\n ],\n name: 'confirmServerDownload',\n outputs: [],\n stateMutability: 'nonpayable',\n type: 'function'\n }\n]\n","export const getFileInfoAbi = [\n {\n inputs: [\n {\n internalType: 'bytes32',\n name: 'fileKey',\n type: 'bytes32'\n }\n ],\n name: 'getFileInfo',\n outputs: [\n {\n components: [\n {\n internalType: 'address',\n name: 'owner',\n type: 'address'\n },\n {\n internalType: 'bytes32',\n name: 'merkleRoot',\n type: 'bytes32'\n },\n {\n internalType: 'uint64',\n name: 'contentLen',\n type: 'uint64'\n },\n {\n internalType: 'uint64',\n name: 'totalChunks',\n type: 'uint64'\n },\n {\n internalType: 'uint64',\n name: 'expireTime',\n type: 'uint64'\n },\n {\n internalType: 'string',\n name: 'name',\n type: 'string'\n },\n {\n internalType: 'string',\n name: 'ext',\n type: 'string'\n },\n {\n internalType: 'string',\n name: 'contentDisposition',\n type: 'string'\n },\n {\n internalType: 'string',\n name: 'contentID',\n type: 'string'\n },\n {\n internalType: 'enum FileStatus',\n name: 'status',\n type: 'uint8'\n }\n ],\n internalType: 'struct Info',\n name: '',\n type: 'tuple'\n }\n ],\n stateMutability: 'view',\n type: 'function'\n }\n]\n","export const GetRustServerAddressesAbi = [\n {\n inputs: [],\n name: 'getRustServerAddresses',\n outputs: [\n {\n internalType: 'string[]',\n name: '',\n type: 'string[]'\n }\n ],\n stateMutability: 'view',\n type: 'function'\n }\n]\n","export const payForDownloadAbi = [\n {\n inputs: [\n {\n internalType: 'bytes32',\n name: 'fileKey',\n type: 'bytes32'\n },\n {\n internalType: 'uint256',\n name: 'downloadTimes',\n type: 'uint256'\n }\n ],\n name: 'payForDownload',\n outputs: [],\n stateMutability: 'payable',\n type: 'function'\n }\n]\n","export const pushFileInfoAbi = [\n {\n inputs: [\n {\n components: [\n {\n internalType: 'address',\n name: 'owner',\n type: 'address'\n },\n {\n internalType: 'bytes32',\n name: 'merkleRoot',\n type: 'bytes32'\n },\n {\n internalType: 'uint64',\n name: 'contentLen',\n type: 'uint64'\n },\n {\n internalType: 'uint64',\n name: 'totalChunks',\n type: 'uint64'\n },\n {\n internalType: 'uint64',\n name: 'expireTime',\n type: 'uint64'\n },\n {\n internalType: 'string',\n name: 'name',\n type: 'string'\n },\n {\n internalType: 'string',\n name: 'ext',\n type: 'string'\n },\n {\n internalType: 'string',\n name: 'contentDisposition',\n type: 'string'\n },\n {\n internalType: 'string',\n name: 'contentID',\n type: 'string'\n },\n {\n internalType: 'enum FileStatus',\n name: 'status',\n type: 'uint8'\n }\n ],\n internalType: 'struct Info',\n name: 'info',\n type: 'tuple'\n }\n ],\n name: 'pushFileInfo',\n outputs: [\n {\n internalType: 'bytes32',\n name: 'fileKey',\n type: 'bytes32'\n }\n ],\n stateMutability: 'payable',\n type: 'function'\n }\n]\n","export const uploadChunkAbi = [\n {\n inputs: [\n {\n internalType: 'bytes32',\n name: 'fileKey',\n type: 'bytes32'\n },\n {\n internalType: 'bytes',\n name: 'chunkData',\n type: 'bytes'\n },\n {\n internalType: 'uint256',\n name: 'chunkIndex',\n type: 'uint256'\n },\n {\n internalType: 'bytes32[]',\n name: 'merkleProof',\n type: 'bytes32[]'\n }\n ],\n name: 'uploadChunk',\n outputs: [],\n stateMutability: 'nonpayable',\n type: 'function'\n }\n]\n","export const setPublicStatusAbi = [\n {\n inputs: [\n {\n internalType: 'bytes32',\n name: 'fileKey',\n type: 'bytes32'\n },\n {\n internalType: 'bool',\n name: 'status',\n type: 'bool'\n }\n ],\n name: 'setPublicStatus',\n outputs: [],\n stateMutability: 'nonpayable',\n type: 'function'\n }\n]\n","export const addWhitelistAbi = [\n {\n inputs: [\n {\n internalType: 'bytes32',\n name: 'fileKey',\n type: 'bytes32'\n },\n {\n internalType: 'address[]',\n name: 'users',\n type: 'address[]'\n }\n ],\n name: 'addWhitelist',\n outputs: [],\n stateMutability: 'nonpayable',\n type: 'function'\n }\n]\n","export const getWhitelistAbi = [\n {\n inputs: [\n {\n internalType: 'bytes32',\n name: 'fileKey',\n type: 'bytes32'\n }\n ],\n name: 'getWhitelist',\n outputs: [\n {\n internalType: 'address[]',\n name: '',\n type: 'address[]'\n }\n ],\n stateMutability: 'view',\n type: 'function'\n }\n]\n","export const isPublicFileAbi = [\n {\n inputs: [\n {\n internalType: 'bytes32',\n name: 'fileKey',\n type: 'bytes32'\n }\n ],\n name: 'isPublicFile',\n outputs: [\n {\n internalType: 'bool',\n name: '',\n type: 'bool'\n }\n ],\n stateMutability: 'view',\n type: 'function'\n }\n]\n","import z from 'zod'\nimport { BaseRequestSchema } from '../../repositories/blockchain.type'\n\nexport const CalculatePriceRequestSchema = BaseRequestSchema.extend({\n numChunks: z.number()\n})\n\nexport type CalculatePriceRequestDTO = z.infer<typeof CalculatePriceRequestSchema>\n\nexport const CalculatePriceResponseSchema = z.string()\n\nexport type CalculatePriceResponseDTO = z.infer<typeof CalculatePriceResponseSchema>\n","import { BaseRequestSchema } from '../../repositories/blockchain.type'\nimport z from 'zod'\n\nexport const PushFileInfoRequestSchema = BaseRequestSchema.extend({\n info: z.object({\n owner: z.string(),\n merkleRoot: z.string(),\n contentLen: z.number(),\n totalChunks: z.number(),\n expireTime: z.number(),\n name: z.string(),\n ext: z.string(),\n contentDisposition: z.string(),\n contentID: z.string(),\n status: z.number()\n }),\n value: z.string()\n})\n\nexport type PushFileInfoRequestDTO = z.infer<typeof PushFileInfoRequestSchema>\n\nexport const PushFileInfoResponseSchema = z.object({\n fileKey: z.string()\n})\n\nexport type PushFileInfoResponseDTO = z.infer<typeof PushFileInfoResponseSchema>\n","import { BaseRequestSchema } from '../../repositories/blockchain.type'\nimport z from 'zod'\n\nexport const UploadChunkRequestSchema = BaseRequestSchema.extend({\n fileKey: z.string(),\n chunkData: z.string(),\n chunkIndex: z.number(),\n merkleProof: z.array(z.string())\n})\n\nexport type UploadChunkRequestDTO = z.infer<typeof UploadChunkRequestSchema>\n\nexport type UploadChunkResponseDTO = void\n","import { BaseRequestSchema } from '../../repositories/blockchain.type'\nimport z from 'zod'\n\nexport const GetFileInfoRequestSchema = BaseRequestSchema.extend({\n fileKey: z.string()\n})\n\nexport type GetFileInfoRequestDTO = z.infer<typeof GetFileInfoRequestSchema>\n\nexport const GetFileInfoResponseSchema = z.object({\n owner: z.string(),\n merkleRoot: z.string(),\n contentLen: z.number(),\n totalChunks: z.number(),\n expireTime: z.number(),\n name: z.string(),\n ext: z.string(),\n contentDisposition: z.string(),\n contentID: z.string(),\n status: z.number()\n})\n\nexport type GetFileInfoResponseDTO = z.infer<typeof GetFileInfoResponseSchema>\n","import { BaseRequestSchema } from '../../repositories/blockchain.type'\nimport z from 'zod'\n\nexport const PayForDownloadRequestSchema = BaseRequestSchema.extend({\n fileKey: z.string(),\n downloadTimes: z.number(),\n value: z.string()\n})\n\nexport type PayForDownloadRequestDTO = z.infer<typeof PayForDownloadRequestSchema>\n\nexport const PayForDownloadResponseSchema = z.object({\n transactionHash: z.string().optional()\n})\n\nexport type PayForDownloadResponseDTO = z.infer<typeof PayForDownloadResponseSchema>\n","import z from 'zod'\nimport { BaseRequestSchema } from '../../repositories/blockchain.type'\n\nexport const ConfirmServerDownloadRequestSchema = BaseRequestSchema.extend({\n downloadKey: z.string()\n})\n\nexport type ConfirmServerDownloadRequestDTO = z.infer<typeof ConfirmServerDownloadRequestSchema>\n\nexport const ConfirmServerDownloadResponseSchema = z.string()\n\nexport type ConfirmServerDownloadResponseDTO = z.infer<typeof ConfirmServerDownloadResponseSchema>\n","import z from 'zod'\nimport { BaseRequestSchema } from '../../repositories/blockchain.type'\n\nexport const GetRustServerAddressesRequestSchema = BaseRequestSchema.extend({})\n\nexport type GetRustServerAddressesRequestDTO = z.infer<typeof GetRustServerAddressesRequestSchema>\n\nexport const GetRustServerAddressesResponseSchema = z.array(z.string())\n\nexport type GetRustServerAddressesResponseDTO = z.infer<typeof GetRustServerAddressesResponseSchema>\n","import { z } from 'zod'\nimport { BaseRequestSchema } from '../../repositories/blockchain.type'\n\nexport const SetPublicStatusRequestSchema = BaseRequestSchema.extend({\n fileKey: z.string(),\n status: z.boolean()\n})\n\nexport type SetPublicStatusRequestDTO = z.infer<typeof SetPublicStatusRequestSchema>\nexport type SetPublicStatusResponseDTO = void\n","import { z } from \"zod\";\nimport { BaseRequestSchema } from '../../repositories/blockchain.type';\n\nexport const AddWhitelistRequestSchema = BaseRequestSchema.extend({\n fileKey: z.string(),\n users: z.array(z.string()),\n});\n\nexport type AddWhitelistRequestDTO = z.infer<typeof AddWhitelistRequestSchema>;\nexport type AddWhitelistResponseDTO = void;\n","import { z } from 'zod'\nimport { BaseRequestSchema } from '../../repositories/blockchain.type'\n\nexport const GetWhitelistRequestSchema = BaseRequestSchema.extend({\n fileKey: z.string()\n})\n\nexport type GetWhitelistRequestDTO = z.infer<typeof GetWhitelistRequestSchema>\nexport type GetWhitelistResponseDTO = string[]\n","import { z } from 'zod'\nimport { BaseRequestSchema } from '../../repositories/blockchain.type'\n\nexport const IsPublicFileRequestSchema = BaseRequestSchema.extend({\n fileKey: z.string()\n})\n\nexport type IsPublicFileRequestDTO = z.infer<typeof IsPublicFileRequestSchema>\nexport type IsPublicFileResponseDTO = boolean\n","import { appConfig } from '../../../../config/app.config'\nimport { logger } from '../../logger'\nimport { BlockchainRepositoryBase } from '../repositories/repository.blockchain.base'\nimport {\n calculatePriceAbi,\n confirmServerDownloadAbi,\n getFileInfoAbi,\n GetRustServerAddressesAbi,\n payForDownloadAbi,\n pushFileInfoAbi,\n uploadChunkAbi,\n setPublicStatusAbi,\n addWhitelistAbi,\n getWhitelistAbi,\n isPublicFileAbi\n} from './abis'\nimport {\n CalculatePriceRequestSchema,\n ConfirmServerDownloadRequestDTO,\n ConfirmServerDownloadRequestSchema,\n ConfirmServerDownloadResponseDTO,\n GetFileInfoRequestSchema,\n GetRustServerAddressesRequestDTO,\n GetRustServerAddressesRequestSchema,\n GetRustServerAddressesResponseDTO,\n PayForDownloadRequestSchema,\n PushFileInfoRequestSchema,\n UploadChunkRequestSchema,\n type CalculatePriceRequestDTO,\n type CalculatePriceResponseDTO,\n type GetFileInfoRequestDTO,\n type GetFileInfoResponseDTO,\n type PayForDownloadRequestDTO,\n type PayForDownloadResponseDTO,\n type PushFileInfoRequestDTO,\n type PushFileInfoResponseDTO,\n type UploadChunkRequestDTO,\n type UploadChunkResponseDTO,\n SetPublicStatusRequestSchema,\n AddWhitelistRequestSchema,\n GetWhitelistRequestSchema,\n IsPublicFileRequestSchema,\n type SetPublicStatusRequestDTO,\n type SetPublicStatusResponseDTO,\n type AddWhitelistRequestDTO,\n type AddWhitelistResponseDTO,\n type GetWhitelistRequestDTO,\n type GetWhitelistResponseDTO,\n type IsPublicFileRequestDTO,\n type IsPublicFileResponseDTO\n} from './dtos'\nimport type { FileBlockchainRepositoryPort } from './file-blockchain.repository.port'\n\nexport class FileBlockchainRepository\n extends BlockchainRepositoryBase\n implements FileBlockchainRepositoryPort\n{\n constructor() {\n super(appConfig.file, logger)\n }\n\n async calculatePrice(request: CalculatePriceRequestDTO): Promise<CalculatePriceResponseDTO> {\n console.log('calculatePrice request', request)\n const validatedDTO = this.validateRequest(CalculatePriceRequestSchema, request)\n const inputData = { numChunks: validatedDTO.numChunks }\n return this.executeTransaction<CalculatePriceResponseDTO>({\n to: validatedDTO.to || appConfig.file,\n from: validatedDTO.from,\n inputData,\n functionName: 'calculatePrice',\n feeType: 'read',\n abiData: calculatePriceAbi\n })\n }\n\n async pushFileInfo(request: PushFileInfoRequestDTO): Promise<PushFileInfoResponseDTO> {\n const validatedDTO = this.validateRequest(PushFileInfoRequestSchema, request)\n const inputData = { info: validatedDTO.info }\n return this.executeTransaction<PushFileInfoResponseDTO>({\n to: validatedDTO.to || appConfig.file,\n from: validatedDTO.from,\n inputData,\n functionName: 'pushFileInfo',\n feeType: 'sc',\n value: validatedDTO.value,\n abiData: pushFileInfoAbi\n })\n }\n\n async uploadChunk(request: UploadChunkRequestDTO): Promise<UploadChunkResponseDTO> {\n const validatedDTO = this.validateRequest(UploadChunkRequestSchema, request)\n const inputData = {\n fileKey: validatedDTO.fileKey,\n chunkData: validatedDTO.chunkData,\n chunkIndex: validatedDTO.chunkIndex,\n merkleProof: validatedDTO.merkleProof\n }\n return this.executeTransaction<UploadChunkResponseDTO>({\n to: validatedDTO.to || appConfig.file,\n from: validatedDTO.from,\n inputData,\n functionName: 'uploadChunk',\n feeType: 'sc',\n abiData: uploadChunkAbi\n })\n }\n\n async getFileInfo(request: GetFileInfoRequestDTO): Promise<GetFileInfoResponseDTO> {\n const validatedDTO = this.validateRequest(GetFileInfoRequestSchema, request)\n const inputData = {\n fileKey: validatedDTO.fileKey\n }\n return this.executeTransaction<GetFileInfoResponseDTO>({\n to: validatedDTO.to || appConfig.file,\n from: validatedDTO.from,\n inputData,\n functionName: 'getFileInfo',\n feeType: 'read',\n abiData: getFileInfoAbi\n })\n }\n\n async payForDownload(request: PayForDownloadRequestDTO): Promise<PayForDownloadResponseDTO> {\n const validatedDTO = this.validateRequest(PayForDownloadRequestSchema, request)\n const inputData = {\n fileKey: validatedDTO.fileKey,\n downloadTimes: validatedDTO.downloadTimes\n }\n return this.executeTransaction<PayForDownloadResponseDTO>({\n to: validatedDTO.to || appConfig.file,\n from: validatedDTO.from,\n inputData,\n functionName: 'payForDownload',\n feeType: 'sc',\n value: validatedDTO.value,\n abiData: payForDownloadAbi\n })\n }\n\n async confirmServerDownload(\n request: ConfirmServerDownloadRequestDTO\n ): Promise<ConfirmServerDownloadResponseDTO> {\n const validatedDTO = this.validateRequest(ConfirmServerDownloadRequestSchema, request)\n const inputData = {\n downloadKey: validatedDTO.downloadKey\n }\n return this.executeTransaction<ConfirmServerDownloadResponseDTO>({\n to: validatedDTO.to || appConfig.file,\n from: validatedDTO.from,\n inputData,\n functionName: 'confirmServerDownload',\n feeType: 'sc',\n abiData: confirmServerDownloadAbi\n })\n }\n\n async getRustServerAddresses(\n request: GetRustServerAddressesRequestDTO\n ): Promise<GetRustServerAddressesResponseDTO> {\n const validatedDTO = this.validateRequest(GetRustServerAddressesRequestSchema, request)\n const inputData = {}\n return this.executeTransaction<GetRustServerAddressesResponseDTO>({\n to: validatedDTO.to || appConfig.file,\n from: validatedDTO.from,\n inputData,\n functionName: 'getRustServerAddresses',\n feeType: 'read',\n abiData: GetRustServerAddressesAbi\n })\n }\n\n async setPublicStatus(request: SetPublicStatusRequestDTO): Promise<SetPublicStatusResponseDTO> {\n const validatedDTO = this.validateRequest(SetPublicStatusRequestSchema, request)\n const inputData = {\n fileKey: validatedDTO.fileKey,\n status: validatedDTO.status\n }\n return this.executeTransaction<SetPublicStatusResponseDTO>({\n to: validatedDTO.to || appConfig.file,\n from: validatedDTO.from,\n inputData,\n functionName: 'setPublicStatus',\n feeType: 'sc',\n abiData: setPublicStatusAbi\n })\n }\n\n async addWhitelist(request: AddWhitelistRequestDTO): Promise<AddWhitelistResponseDTO> {\n const validatedDTO = this.validateRequest(AddWhitelistRequestSchema, request)\n const inputData = {\n fileKey: validatedDTO.fileKey,\n users: validatedDTO.users\n }\n return this.executeTransaction<AddWhitelistResponseDTO>({\n to: validatedDTO.to || appConfig.file,\n from: validatedDTO.from,\n inputData,\n functionName: 'addWhitelist',\n feeType: 'sc',\n abiData: addWhitelistAbi\n })\n }\n\n async getWhitelist(request: GetWhitelistRequestDTO): Promise<GetWhitelistResponseDTO> {\n const validatedDTO = this.validateRequest(GetWhitelistRequestSchema, request)\n const inputData = {\n fileKey: validatedDTO.fileKey\n }\n return this.executeTransaction<GetWhitelistResponseDTO>({\n to: validatedDTO.to || appConfig.file,\n from: validatedDTO.from,\n inputData,\n functionName: 'getWhitelist',\n feeType: 'read',\n abiData: getWhitelistAbi\n })\n }\n\n async isPublicFile(request: IsPublicFileRequestDTO): Promise<IsPublicFileResponseDTO> {\n const validatedDTO = this.validateRequest(IsPublicFileRequestSchema, request)\n const inputData = {\n fileKey: validatedDTO.fileKey\n }\n return this.executeTransaction<IsPublicFileResponseDTO>({\n to: validatedDTO.to || appConfig.file,\n from: validatedDTO.from,\n inputData,\n functionName: 'isPublicFile',\n feeType: 'read',\n abiData: isPublicFileAbi\n })\n }\n}\n\nexport const fileBlockchainRepository = new FileBlockchainRepository()\n","// @ts-ignore\nimport { DecodeAbi, EventLog } from '@metanodejs/event-log'\nimport abi from './abi.json'\nimport type { EventMap } from './event-map.type'\n\nclass EventLogs {\n private static instance: EventLogs\n\n private readonly _decodeAbi: DecodeAbi\n private readonly _eventLog: EventLog<EventMap>\n\n private _abiRegistrationPromise: Promise<void> | null = null\n private _registeredEvents = new Set<string>()\n\n private constructor() {\n this._decodeAbi = new DecodeAbi()\n this._eventLog = new EventLog<EventMap>(this._decodeAbi)\n }\n\n public static getInstance(): EventLogs {\n if (!EventLogs.instance) {\n EventLogs.instance = new EventLogs()\n }\n return EventLogs.instance\n }\n\n get eventLog(): EventLog<EventMap> {\n return this._eventLog\n }\n\n get decodeAbi(): DecodeAbi {\n return this._decodeAbi\n }\n\n public async registerAbi() {\n if (!this._abiRegistrationPromise) {\n this._abiRegistrationPromise = this._decodeAbi.registerAbi(abi as never).catch((err) => {\n console.warn('EventLogs: ABI already registered or error', err)\n })\n }\n await this._abiRegistrationPromise\n }\n\n public async registerEvent(userAddress: string, contractAddress: string) {\n const key = `${userAddress.toLowerCase()}-${contractAddress.toLowerCase()}`\n if (!this._registeredEvents.has(key)) {\n this._registeredEvents.add(key)\n await this._eventLog.registerEvent(userAddress, [contractAddress])\n }\n }\n}\n\nexport const eventLogs = EventLogs.getInstance()\n","[\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"bytes32\",\n \"name\": \"downloadKey\",\n \"type\": \"bytes32\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bytes32\",\n \"name\": \"fileKey\",\n \"type\": \"bytes32\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"user\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"DownloadKeyGenerated\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"user\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bytes32\",\n \"name\": \"fileKey\",\n \"type\": \"bytes32\"\n }\n ],\n \"name\": \"FileActivated\",\n \"type\": \"event\"\n }\n]\n","import { customAlphabet } from 'nanoid'\n\n/**\n * You just increase the length if necessary to improve performance\n * Attention to the security(id is key)\n *\n * Characters\tLength\tTotal States\n * UUID\t 16\t 32\t 16^32 = 3.4e+38\n * Base58\t 58\t 22\t 58^22 = 6.2e+38\n * ---------------------------------------------------------\n * Length\t Example\t Total States\n * nanoid(8)\tre6ZkUUV\t 1.3e+14\n * nanoid(12)\tpfpPYdZGbZvw\t 1.4e+21\n * nanoid(16)\tsFDUZScHfZTfkLwk\t 1.6e+28\n * nanoid(24)\tu7vzXJL9cGqUeabGPAZ5XUJ6\t 2.1e+42\n * nanoid(32)\tqkvPDeH6JyAsRhaZ3X4ZLDPSLFP7MnJz\t2.7e+56\n *\n * See @https://unkey.dev/blog/uuid-ux\n */\nexport const generateId = customAlphabet(\n '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'\n)\n\nexport const DEFAULT_PREFIX_ID_LENGTH = 22\nexport const ENTITY_ID_LENGTH = 25\n\nexport function generatePrefixId(prefix = 'tu', length = DEFAULT_PREFIX_ID_LENGTH): string {\n return `${prefix}_${generateId(length)}`\n}\n\n// Generic ID generator - can be used for any entity type\n// Example: generatePrefixId('file', length) for file IDs\n","const isProduction = process.env.NODE_ENV === 'production'\nconst prefix = 'Invariant failed'\n\ntype InvariantMessage = string | (() => string) | Error\n\nexport function invariant(condition: any, message?: InvariantMessage): asserts condition {\n if (condition) {\n return\n }\n\n if (isProduction) {\n throw new Error(prefix)\n }\n\n let provided: string | undefined\n\n if (typeof message === 'function') {\n provided = message()\n } else if (message instanceof Error) {\n provided = message.message\n } else {\n provided = message\n }\n\n const value: string = provided ? `${prefix}: ${provided}` : prefix\n throw new Error(value)\n}\n","export function isNotNull<T>(v: T | null): v is Exclude<T, null> {\n return v !== null\n}\n\nexport function isArray<T = unknown>(val: any): val is T[] {\n return val && Array.isArray(val)\n}\n\nexport function isPrimitive(value: unknown): boolean {\n if (value === null) {\n return true\n }\n\n return !['array', 'function', 'object'].includes(typeof value)\n}\n\nexport const isDef = <T = any>(val?: T): val is T => typeof val !== 'undefined'\nexport const isUndef = <T = any>(val?: T): val is T => !isDef(val)\nexport const isBoolean = (val: any): val is boolean => typeof val === 'boolean'\nexport const isFunction = (val: any): boolean => typeof val === 'function'\nexport const isNumber = (val: any): val is number => toString.call(val) === '[object Number]'\nexport const isString = (val: unknown): val is string => typeof val === 'string'\nexport const isObject = (val: any): val is object => toString.call(val) === '[object Object]'\nexport const isMap = (val: unknown): val is Map<any, any> => toString.call(val) === '[object Map]'\nexport const isSet = (val: unknown): val is Set<any> => toString.call(val) === '[object Set]'\nexport const isDate = (val: unknown): val is Date => toString.call(val) === '[object Date]'\nexport const isSymbol = (val: unknown): val is symbol => typeof val === 'symbol'\nexport const isPromise = <T = any>(val: unknown): val is Promise<T> => {\n // @ts-expect-error Ignore type checking\n return isObject(val) && isFunction(val.then) && isFunction(val.catch)\n}\n\nexport const isFalsy = (val: any): val is false | undefined | null =>\n isNotNull(val) && isDef(val) && isNotEmpty(val)\n\nexport const isWindow = (val: any): boolean =>\n typeof window !== 'undefined' && toString.call(val) === '[object Window]'\n\nexport const isStream = (val: any) =>\n val !== null && typeof val === 'object' && typeof val.pipe === 'function'\n\n// Using `typeof window !== 'undefined'` alone is not enough because some users use https://www.npmjs.com/package/ssr-window\nexport const isBrowser = typeof window !== 'undefined'\n\ntype EmptyArray<T> = readonly [T, ...ReadonlyArray<T>]\n\nconst isEmptyArr = <T>(array: ReadonlyArray<T> | undefined): array is EmptyArray<T> =>\n array?.length === 0\n\n/**\n * Check a value is empty or not\n * Currently not support check WeakMap/WeakSet/WeakRef\n */\nexport function isEmpty<T = unknown>(val: T): val is T {\n if (!val) {\n return true\n }\n if (isArray(val)) {\n return isEmptyArr(val)\n }\n\n if (isString(val)) {\n return val.trim().length === 0\n }\n\n if (val instanceof Map || val instanceof Set) {\n return val.size === 0\n }\n\n if (isObject(val)) {\n return Object.keys(val).length === 0\n }\n\n return false\n}\n\nexport function isNotEmpty<T = unknown>(val: T): val is T {\n return !isEmpty(val)\n}\n\n/**\n * Use for case you validate multiple values is not empty\n *\n * @param {any} args any arguments\n * @returns {boolean} will return true if all value is not empty\n */\nexport function isNotEmpties(...args: any[]): boolean {\n if (args.length > 1) {\n return args.reduce((a, b) => a && isNotEmpty(b), true)\n }\n return false\n}\n\n/**\n * Use for case you validate multiple values is not empty\n * @param args\n */\nexport function isEmpties(...args: any[]): boolean {\n if (args.length > 1) {\n return args.reduce((a, b) => a && isEmpty(b), true)\n }\n return false\n}\n\n/**\n * {@link} https://en.wikipedia.org/wiki/Portable_Network_Graphics\n *\n * @param {Buffer | Uint8Array} buffer Input is a buffer\n * @returns {boolean} return true if the input is a PNG Image\n */\nexport function isPngImage(buffer: Buffer | Uint8Array): boolean {\n if (!buffer || buffer.length < 8) {\n return false\n }\n\n return (\n buffer[0] === 0x89 &&\n buffer[1] === 0x50 &&\n buffer[2] === 0x4e &&\n buffer[3] === 0x47 &&\n buffer[4] === 0x0d &&\n buffer[5] === 0x0a &&\n buffer[6] === 0x1a &&\n buffer[7] === 0x0a\n )\n}\n\nexport const isAndroid = isBrowser ? /(android)/i.test(navigator.userAgent) : false\n\n// @ts-expect-error Ignore type check\nconst match = isBrowser ? window.matchMedia || window.msMatchMedia : undefined\n\nexport const isMobile = isBrowser ? match?.('(pointer:coarse)')?.matches : false\n\n// Crawl from https://github.com/johannschopplich/unlazy/blob/main/packages/core/src/utils/index.ts#LL4C1-L4C122\nexport const isCrawler =\n isBrowser &&\n (!('onscroll' in window) || /(gle|ing|ro)bot|crawl|spider/i.test(navigator.userAgent))\n","export function delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n","export function humanFileSize(bytes: number, si = false, dp = 1) {\n const thresh = si ? 1000 : 1024\n\n if (Math.abs(bytes) < thresh) {\n return bytes + ' B'\n }\n\n const units = si\n ? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']\n : ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']\n let u = -1\n const r = 10 ** dp\n\n do {\n bytes /= thresh\n ++u\n } while (Math.round(Math.abs(bytes) * r) / r >= thresh && u < units.length - 1)\n\n return bytes.toFixed(dp) + ' ' + units[u]\n}\n","export function generateRandomHex(length: number): string {\n const hex = []\n const chars = 'abcdef0123456789'\n for (let i = 0; i < length; i++) {\n hex.push(chars[Math.floor(Math.random() * chars.length)])\n }\n return hex.join('')\n}\n","export * from './invariant'\nexport * from './is'\nexport * from './delay'\nexport * from './format'\nexport * from './random'\n\nexport const fulfilledPromises = <T extends Promise<any>>(promises: T[]) =>\n Promise.allSettled(promises).then((results) =>\n results\n .filter((result) => result.status === 'fulfilled')\n .map((result) => (result as PromiseFulfilledResult<Awaited<T>>).value)\n )\nexport function formatSize(bytes: number): string {\n if (bytes === 0) return '0 Bytes'\n const k = 1024\n const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']\n const i = Math.floor(Math.log(bytes) / Math.log(k))\n const size = bytes / Math.pow(k, i)\n return `${size.toFixed(2)} ${sizes[i]}`\n}\n","import type { EntityId } from '../../../types'\nimport { generatePrefixId } from '../../helpers/ids'\n\nexport class UniqueEntityID {\n protected readonly id: EntityId\n\n constructor(_id?: EntityId) {\n this.id = _id || generatePrefixId('entity')\n }\n\n equals(_id?: UniqueEntityID): boolean {\n if (!_id) {\n return false\n }\n if (!(_id instanceof this.constructor)) {\n return false\n }\n return _id.toValue() === this.id\n }\n\n toString() {\n return String(this.id)\n }\n\n toValue(): EntityId {\n return this.id\n }\n}\n","import { ArgumentNotProvidedException } from '../../exceptions/exceptions'\nimport { generatePrefixId } from '../../helpers/ids'\nimport { invariant } from '../../utils'\nimport { UniqueEntityID } from '../entities/unique-entity'\n\ntype DomainEventMetadata = {\n /** Timestamp when this domain event occurred */\n readonly timestamp: number\n /** ID for correlation purposes (for Integration Events,logs correlation, etc).\n */\n readonly correlationId?: string | undefined\n\n /**\n * Causation id used to reconstruct execution order if needed\n */\n readonly causationId?: string | undefined\n}\n\nexport type IDomainEvent<T> = Omit<T, 'id' | '_metadata' | 'eventName'> & {\n _metadata: DomainEventMetadata\n aggregateId: UniqueEntityID\n}\n\nexport abstract class DomainEvent {\n readonly id: UniqueEntityID\n readonly aggregateId: UniqueEntityID\n readonly _metadata: DomainEventMetadata\n abstract eventName: string\n\n constructor(domainEvent: IDomainEvent<unknown>) {\n invariant(\n domainEvent,\n new ArgumentNotProvidedException('Domain event props should not be empty')\n )\n invariant(\n domainEvent._metadata && domainEvent._metadata.timestamp,\n new ArgumentNotProvidedException('Timestamp should be provided in domain event metadata')\n )\n this.id = new UniqueEntityID(generatePrefixId('de'))\n this.aggregateId = domainEvent.aggregateId\n this._metadata = {\n correlationId: domainEvent?._metadata?.correlationId,\n causationId: domainEvent?._metadata?.causationId,\n timestamp: domainEvent?._metadata?.timestamp\n }\n }\n}\n","import mitt, { type Emitter, type EventHandlerMap, type Handler, type WildcardHandler } from 'mitt'\nimport type { EmitDomainEvents } from './domain-event.types'\n\nexport interface AsyncEventBus extends Emitter<EmitDomainEvents> {\n emitAsync<Key extends keyof EmitDomainEvents>(\n type: Key,\n event: EmitDomainEvents[Key]\n ): Promise<void>\n}\n\nexport function createMittAsync(all?: EventHandlerMap<EmitDomainEvents>): AsyncEventBus {\n const emitter = mitt<EmitDomainEvents>(all) as AsyncEventBus\n\n emitter.emitAsync = async function (type, event) {\n const handlers = this.all.get(type) as Handler<any>[] | undefined\n if (handlers) {\n for (const handler of handlers) {\n await handler(event)\n }\n }\n\n const wildcardHandlers = this.all.get('*') as WildcardHandler<EmitDomainEvents>[] | undefined\n if (wildcardHandlers) {\n for (const handler of wildcardHandlers) {\n await handler(type, event)\n }\n }\n }\n\n return emitter\n}\n\nexport const emitter = createMittAsync()\n","import { ArgumentNotProvidedException } from '../../exceptions/exceptions'\nimport { convertPropsToObject } from '../../helpers/object'\nimport { invariant, isEmpty } from '../../utils'\n\n/**\n * Domain Primitive is an object that contains only a single value\n */\nexport type Primitives = string | number | boolean\nexport interface DomainPrimitive<T extends Primitives | Date> {\n value: T\n}\n\ntype ValueObjectProps<T> = T extends Primitives | Date ? DomainPrimitive<T> : T\n\nexport abstract class ValueObject<Props> {\n protected readonly props: ValueObjectProps<Props>\n\n constructor(props: ValueObjectProps<Props>) {\n this.#validateProps(props)\n this.validate(props)\n this.props = props\n }\n\n protected abstract validate(props: ValueObjectProps<Props>): void\n static isValueObject(obj: unknown): obj is ValueObject<unknown> {\n return obj instanceof ValueObject\n }\n\n equals(vo?: ValueObject<Props>) {\n if (!vo) return false\n return JSON.stringify(this) === JSON.stringify(vo)\n }\n\n /**\n * Convert value obj to get raw properties\n */\n raw() {\n if (this.#isDomainPrimitive(this.props)) {\n return this.props.value\n }\n const clone = convertPropsToObject(this.props)\n return Object.freeze(clone)\n }\n\n #validateProps(props: ValueObjectProps<Props>) {\n invariant(\n !(isEmpty(props) || (this.#isDomainPrimitive(props) && isEmpty(props))),\n new ArgumentNotProvidedException('Property cannot be empty')\n )\n }\n\n #isDomainPrimitive(obj: unknown): obj is DomainPrimitive<Props & (Primitives | Date)> {\n if (Object.prototype.hasOwnProperty.call(obj, 'value')) return true\n return false\n }\n}\n","import { Entity } from '../domain-base/entities/entity.base'\nimport { ValueObject } from '../domain-base/entities/value-object.base'\n\nfunction isEntity(obj: unknown): obj is Entity<unknown> {\n /**\n * 'instanceof Entity' causes error here for some reason.\n * Probably creates some circular dependency. This is a workaround\n * until I find a solution :)\n */\n if (obj === null || typeof obj !== 'object') {\n return false\n }\n\n return (\n Object.prototype.hasOwnProperty.call(obj, 'toObject') &&\n Object.prototype.hasOwnProperty.call(obj, 'id') &&\n ValueObject.isValueObject((obj as Entity<unknown>).id)\n )\n}\n\nfunction convertToPlainObject(item: any): any {\n if (ValueObject.isValueObject(item)) {\n return item.raw()\n }\n if (isEntity(item)) {\n return item.toObject()\n }\n return item\n}\n\n/**\n * Converts Entity/Value Objects props to a plain object.\n * Useful for testing and debugging.\n * @param props\n */\nexport function convertPropsToObject(props: any): any {\n const propsCopy = structuredClone(props)\n\n // eslint-disable-next-line guard-for-in\n for (const prop in propsCopy) {\n if (Array.isArray(propsCopy[prop])) {\n propsCopy[prop] = (propsCopy[prop] as Array<unknown>).map((item) => {\n return convertToPlainObject(item)\n })\n }\n propsCopy[prop] = convertToPlainObject(propsCopy[prop])\n }\n\n return propsCopy\n}\n","import type { MarkOptional } from 'ts-essentials'\nimport {\n ArgumentInvalidException,\n ArgumentNotProvidedException,\n ArgumentOutOfRangeException\n} from '../../exceptions/exceptions'\nimport { UniqueEntityID } from './unique-entity'\nimport { invariant, isEmpty } from '../../utils'\nimport { convertPropsToObject } from '../../helpers/object'\n\nexport interface BaseEntityProps {\n id: UniqueEntityID\n createdAt: Date\n updatedAt: Date\n}\n\nexport interface CreateEntityProps<T>\n extends MarkOptional<BaseEntityProps, 'createdAt' | 'updatedAt'> {\n props: T\n}\n\nexport abstract class Entity<Props> {\n #id: UniqueEntityID\n readonly #createdAt: Date\n readonly #props: Props\n #updatedAt: Date\n\n constructor({ id, props, createdAt, updatedAt }: CreateEntityProps<Props>) {\n this.#id = id\n this.#validateProps(props)\n const now = new Date()\n this.#createdAt = createdAt || now\n this.#updatedAt = updatedAt || now\n this.#props = props\n this.validate()\n }\n\n static isEntity(entity: unknown): entity is Entity<unknown> {\n return entity instanceof Entity\n }\n\n get id(): UniqueEntityID {\n return this.#id\n }\n\n get createdAt(): Date {\n return this.#createdAt\n }\n\n get updatedAt(): Date {\n return this.#updatedAt\n }\n\n getProps(): Props & BaseEntityProps {\n const clone = {\n id: this.id,\n createdAt: this.#createdAt,\n updatedAt: this.#updatedAt,\n ...this.#props\n }\n return Object.freeze(clone)\n }\n\n protected getMutableProps(): Props {\n return this.#props\n }\n\n /**\n * Convert an Entity and all sub-entities/Value Objects it\n * contains to a plain object with primitive types. Can be\n * useful when logging an entity during testing/debugging\n */\n toObject() {\n const clone = convertPropsToObject(this.getProps())\n\n const result = {\n id: this.id,\n createdAt: this.#createdAt,\n updatedAt: this.#updatedAt,\n ...clone\n }\n return Object.freeze(result)\n }\n /**\n * Each entity must have some validate/business rules\n * This method is called every time before save this entity to the database\n */\n abstract validate(): void\n\n #validateProps(props: Props) {\n const MAX_PROPS = 32\n invariant(!isEmpty(props), new ArgumentNotProvidedException('Entity props should not be empty'))\n invariant(\n typeof props === 'object',\n new ArgumentInvalidException('Entity props should be an object')\n )\n invariant(\n Object.keys(props as any).length <= MAX_PROPS,\n new ArgumentOutOfRangeException(\n `The entity props count must smaller than ${MAX_PROPS} properties`\n )\n )\n }\n}\n","import type { LoggerPort } from '../../Infrastructure-base'\nimport type { AsyncEventBus } from '../events'\nimport { DomainEvent } from '../events/domain-event.base'\nimport { Entity } from './entity.base'\n\nexport abstract class AggregateRoot<Props> extends Entity<Props> {\n // Private field để lưu domain events\n #domainEvents: DomainEvent[] = []\n\n get domainEvents(): readonly DomainEvent[] {\n return this.#domainEvents\n }\n\n protected addEvent(event: DomainEvent | DomainEvent[]): void {\n if (Array.isArray(event)) {\n this.#domainEvents.push(...event)\n } else {\n this.#domainEvents.push(event)\n }\n }\n\n clearEvents(): void {\n this.#domainEvents = []\n }\n\n /**\n * Publish tất cả domain events qua AsyncEventBus\n * - Logger để debug\n * - await cho từng handler async\n */\n async publishEvents(logger: LoggerPort, emitter: AsyncEventBus) {\n for (const event of this.#domainEvents) {\n // Dùng property eventName thay vì constructor.name\n const eventName = event.eventName\n logger.debug(\n `[RequestID] \"${eventName}\" event published for aggregate ${this.constructor.name} : ${this.id}`\n )\n console.log(\n `[RequestID] \"${eventName}\" event published for aggregate ${this.constructor.name} : ${this.id}`\n )\n\n if (eventName) {\n emitter.emit(eventName, event as any)\n } else {\n logger.debug(`[AggregateRoot] Event \"${eventName}\" không có eventName, bỏ qua.`)\n }\n }\n\n this.clearEvents()\n }\n}\n","export function isValidAddress(address: string): boolean {\n const cleaned = address.startsWith('0x') ? address.slice(2) : address\n return /^[a-fA-F0-9]{40}$/.test(cleaned)\n}\nexport function isValidPublicKey(publicKey: string): boolean {\n const cleaned = publicKey.startsWith('0x') ? publicKey.slice(2) : publicKey\n return /^[a-fA-F0-9]{66,130}$/.test(cleaned)\n}\n","import { createHashWithBuffer } from '@metanodejs/system-core'\n\nconst EMPTY_HASH = '0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'\n\nlet cachedEmptyHash: string | null = null\n\nconst getEmptyHash = async (): Promise<string> => {\n if (cachedEmptyHash) return cachedEmptyHash\n cachedEmptyHash = EMPTY_HASH\n return cachedEmptyHash\n}\n\nconst sha256 = async (data: Uint8Array): Promise<string> => {\n if (data.length === 0) {\n return await getEmptyHash()\n }\n\n const bufferAsNumberArray = Array.from(data)\n try {\n const { hash } = (await createHashWithBuffer({\n buffer: bufferAsNumberArray\n })) as { hash: string }\n return hash\n } catch (error) {\n console.error('sha256 error---', error)\n console.log('bufferAsNumberArray---', bufferAsNumberArray)\n return ''\n }\n}\n\nconst hexToBytes = (hex: string): Uint8Array => {\n const cleanHex = hex.startsWith('0x') ? hex.slice(2) : hex\n if (cleanHex.length === 0) return new Uint8Array(0)\n\n const bytes = new Uint8Array(cleanHex.length / 2)\n for (let i = 0; i < cleanHex.length; i += 2) {\n bytes[i / 2] = parseInt(cleanHex.substr(i, 2), 16)\n }\n return bytes\n}\n\nconst nextPowerOfTwo = (n: number): number => {\n if (n <= 0) return 1\n n--\n n |= n >> 1\n n |= n >> 2\n n |= n >> 4\n n |= n >> 8\n n |= n >> 16\n return n + 1\n}\n\nexport const buildMerkleTreePadded = async (\n chunks: Uint8Array[]\n): Promise<[string[], string, string[][]]> => {\n const numLeaves = chunks.length\n\n if (numLeaves === 0) {\n const empty = await getEmptyHash()\n return [[], empty, []]\n }\n\n const total = nextPowerOfTwo(numLeaves)\n const leaves: string[] = new Array(total)\n const emptyHash = await getEmptyHash()\n\n const realHashes = await Promise.all(chunks.map(sha256))\n\n for (let i = 0; i < total; i++) {\n leaves[i] = i < numLeaves ? realHashes[i]! : emptyHash\n }\n\n // Build tree và cache tất cả levels\n const levels: string[][] = [leaves]\n let level = leaves\n while (level.length > 1) {\n const nextLevel: string[] = []\n\n for (let i = 0; i < level.length; i += 2) {\n const leftHex = level[i]!\n const rightHex = level[i + 1] ?? emptyHash\n\n const leftBytes = hexToBytes(leftHex)\n const rightBytes = hexToBytes(rightHex)\n\n const combined = new Uint8Array(64)\n combined.set(leftBytes, 0)\n combined.set(rightBytes, 32)\n\n const parent = await sha256(combined)\n nextLevel.push(parent)\n }\n\n levels.push(nextLevel)\n level = nextLevel\n }\n\n return [leaves, level[0]!, levels]\n}\n\n/**\n * Get Merkle proof sử dụng cached tree levels (không rebuild tree)\n * @param levels Các levels của Merkle tree đã được build (từ buildMerkleTreePadded)\n * @param index Index của leaf cần lấy proof\n */\nexport const getMerkleProofPadded = async (\n levels: string[][],\n index: number\n): Promise<string[]> => {\n const proof: string[] = []\n let idx = index\n\n const emptyHash = await getEmptyHash()\n\n // Chỉ cần traverse levels đã build để lấy proof (không rebuild)\n for (let levelIdx = 0; levelIdx < levels.length - 1; levelIdx++) {\n const level = levels[levelIdx]!\n const isLeft = idx % 2 === 0\n const siblingIdx = isLeft ? idx + 1 : idx - 1\n\n const siblingHash = siblingIdx < level.length ? level[siblingIdx]! : emptyHash\n proof.push(siblingHash)\n\n idx = Math.floor(idx / 2)\n }\n\n return proof\n}\n\nexport const verifyMerkleProof = async (\n leafHash: string,\n proof: string[],\n root: string,\n index: number\n): Promise<boolean> => {\n let hash = leafHash\n\n for (let i = 0; i < proof.length; i++) {\n const sibling = proof[i]!\n const isLeft = (index >> i) % 2 === 0\n\n const leftBytes = isLeft ? hexToBytes(hash) : hexToBytes(sibling)\n const rightBytes = isLeft ? hexToBytes(sibling) : hexToBytes(hash)\n\n const combined = new Uint8Array(64)\n combined.set(leftBytes, 0)\n combined.set(rightBytes, 32)\n\n hash = await sha256(combined)\n }\n\n return hash === root\n}\n","import type { FileBlockchainRepositoryPort } from '../../../../core/Infrastructure-base/blockchain/fileblockchain/file-blockchain.repository.port'\nimport type { UploadFileRequestDTO, UploadFileResponseDTO } from '../dtos'\nimport {\n buildMerkleTreePadded,\n getMerkleProofPadded,\n verifyMerkleProof\n} from '../../../../utils/merkle'\nimport { logger } from '../../../../core/Infrastructure-base/logger'\nimport type { FileActivatedProvider } from '../../infrastructure/services/file-activated-listener.service'\n\nexport class UploadFileUseCase {\n constructor(\n private readonly fileBlockchainRepository: FileBlockchainRepositoryPort,\n private readonly fileActivatedProvider?: FileActivatedProvider\n ) {}\n\n async execute(request: UploadFileRequestDTO): Promise<UploadFileResponseDTO> {\n const { file, from, chunkSize = 1024 * 250 } = request\n\n logger.info('Starting file upload', { fileName: file.name, chunkSize, from })\n\n // 1. Đọc file và chia thành chunks\n const arrayBuffer = await file.arrayBuffer()\n const buffer = new Uint8Array(arrayBuffer)\n const chunks: Uint8Array[] = []\n\n for (let i = 0; i < buffer.length; i += chunkSize) {\n chunks.push(buffer.slice(i, i + chunkSize))\n }\n\n logger.info(`File split into ${chunks.length} chunks`)\n\n // 2. Build Merkle Tree (và cache levels để tái sử dụng)\n const [leaves, merkleRoot, treeLevels] = await buildMerkleTreePadded(chunks)\n logger.info('Merkle Tree built', { merkleRoot, totalLeaves: leaves.length })\n\n // 3. Tính giá\n const dataPrice = await this.fileBlockchainRepository.calculatePrice({\n from,\n numChunks: chunks.length\n })\n\n logger.info('Price calculated', { price: dataPrice })\n\n // 4. Đăng ký file info\n const fileExt = file.name.includes('.') ? file.name.split('.').pop()! : ''\n const expireTime = Math.floor(Date.now() / 1000) + 365 * 24 * 60 * 60\n\n const { fileKey } = await this.fileBlockchainRepository.pushFileInfo({\n from,\n info: {\n owner: from,\n merkleRoot,\n contentLen: buffer.length,\n totalChunks: chunks.length,\n expireTime,\n name: file.name,\n ext: fileExt,\n contentDisposition: 'inline',\n contentID: merkleRoot,\n status: 0\n },\n value: dataPrice\n })\n\n logger.info('File registered on-chain', { fileKey })\n\n // 5. Upload từng chunk với proof verification\n const uploadPromises = chunks.map(async (chunk, i) => {\n const leafHash = leaves[i]!\n // Sử dụng cached tree levels thay vì rebuild tree mỗi lần\n const proof = await getMerkleProofPadded(treeLevels, i)\n\n // Verify proof trước khi gửi\n const isProofValid = await verifyMerkleProof(leafHash, proof, merkleRoot, i)\n if (!isProofValid) {\n throw new Error(\n `PROOF INVALID FOR CHUNK ${i}! Leaf: ${leafHash}, Root expected: ${merkleRoot}`\n )\n }\n\n // Chuyển đổi chunk sang hex string\n const chunkDataHex =\n '0x' +\n Array.from(chunk)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n\n // Upload chunk\n await this.fileBlockchainRepository.uploadChunk({\n from,\n fileKey,\n chunkData: chunkDataHex,\n chunkIndex: i,\n merkleProof: proof\n })\n\n return { chunkIndex: i, success: true }\n })\n\n // Upload song song\n await Promise.all(uploadPromises)\n\n logger.info(`All ${chunks.length} chunks uploaded successfully`)\n\n // 6. Đợi FileActivated event để xác nhận file đã được activate\n if (this.fileActivatedProvider) {\n logger.info('Waiting for FileActivated event...', { fileKey })\n try {\n const activated = await this.fileActivatedProvider.waitForFileActivated(fileKey, 60000) // 60s timeout\n logger.info('FileActivated event received', {\n fileKey: activated.fileKey,\n user: activated.user\n })\n } catch (error) {\n logger.error('Timeout waiting for FileActivated event', error)\n throw new Error(\n `Upload completed but FileActivated event not received: ${error instanceof Error ? error.message : 'Unknown error'}`\n )\n }\n } else {\n logger.warn('FileActivatedProvider not provided, skipping FileActivated event wait')\n }\n\n return {\n fileKey,\n merkleRoot,\n totalChunks: chunks.length\n }\n }\n}\n","/**\n * Rust Server Client\n *\n * Kết nối và request chunks từ Rust Servers sử dụng Native QUIC Connection\n *\n * Implementation sử dụng native functions:\n * - connectQuicServer: Connect đến Rust server\n * - sendQuicMessage: Gửi message và nhận response\n * - disconnectQuicServer: Disconnect khi không dùng nữa\n * - Load Balancing: Chunk chẵn từ Server 1, chunk lẻ từ Server 2\n * - Retry logic khi request fail (max 3 lần)\n * - Không retry nếu lỗi chứa \"to store chunk on disk\" (đã thành công)\n */\n\nimport { connectQuicServer, disconnectQuicServer, sendQuicMessage } from \"@metanodejs/system-core\";\nimport { fileBlockchainRepository } from \"../../../../core/Infrastructure-base/blockchain/fileblockchain/file-blockchain.repository\";\n\n// ALPN protocol\nconst ALPN = \"file-storage-v1\";\n\n// Retry configuration\nconst MAX_RETRIES = 3;\nconst RETRY_DELAY_MS = 200;\n\n// Download Mutex to prevent multiple files from downloading over QUIC simultaneously\nclass Mutex {\n private mutex = Promise.resolve();\n\n lock(): Promise<() => void> {\n let begin: (unlock: () => void) => void = (_unlock) => {};\n this.mutex = this.mutex.then(() => new Promise(begin));\n return new Promise((res) => {\n begin = res;\n });\n }\n}\nconst downloadMutex = new Mutex();\n\n// Request/Response types\nexport interface DownloadChunkPayload {\n file_key: string;\n download_key: string;\n chunk_index: number;\n signature: string;\n}\n\nexport interface DownloadChunkRequest {\n command: string;\n requestId?: string;\n chunkIndex?: number;\n totalChunks?: number;\n payload: DownloadChunkPayload;\n}\n\nexport interface DownloadResponse {\n status: string;\n message: string;\n chunk_data_base64?: string;\n chunkIndex?: number;\n requestId?: string;\n}\n\nexport class NativeQuicError extends Error {\n constructor(\n public code: string,\n public retryable: boolean,\n public retryAfterMs?: number,\n message?: string,\n ) {\n super(message || code);\n }\n}\n\n/**\n * Parse IP và port từ address string (format: \"ip:port\")\n */\nfunction parseServerAddress(address: string): { ip: string; port: number } {\n const [ip, portStr] = address.split(\":\");\n if (!ip || !portStr) {\n throw new Error(`Invalid server address format: ${address}`);\n }\n const port = parseInt(portStr, 10);\n if (isNaN(port)) {\n throw new Error(`Invalid port in address: ${address}`);\n }\n return { ip, port };\n}\n\n// Reference counter for QUIC connections\nconst connectionRefs: Record<string, number> = {};\n\n/**\n * Connect đến server\n * Sử dụng reference counter để không connect lại hoặc ngắt kết nối sai lúc nếu có nhiều file tải song song\n */\nasync function ensureConnected(serverAddr: string): Promise<void> {\n const { ip, port } = parseServerAddress(serverAddr);\n if (!connectionRefs[serverAddr]) {\n await connectQuicServer(ip, port, ALPN);\n connectionRefs[serverAddr] = 1;\n console.log(`[Server ${serverAddr}] Connected via QUIC (ref = 1)`);\n } else {\n connectionRefs[serverAddr]++;\n console.log(\n `[Server ${serverAddr}] Reuse QUIC connection (ref = ${connectionRefs[serverAddr]})`,\n );\n }\n}\n\n/**\n * Disconnect từ server\n */\nasync function disconnectServer(serverAddr: string): Promise<void> {\n const { ip, port } = parseServerAddress(serverAddr);\n try {\n if (connectionRefs[serverAddr] && connectionRefs[serverAddr] > 0) {\n connectionRefs[serverAddr]--;\n console.log(\n `[Server ${serverAddr}] Decrement QUIC connection (ref = ${connectionRefs[serverAddr]})`,\n );\n if (connectionRefs[serverAddr] === 0) {\n console.log(\"handle disconnect server\");\n Promise.race([\n disconnectQuicServer(ip, port, ALPN),\n new Promise((resolve) => setTimeout(resolve, 2000)),\n ]).catch((err) => console.warn(`[Server ${serverAddr}] Disconnect error:`, err));\n\n delete connectionRefs[serverAddr];\n console.log(`[Server ${serverAddr}] Disconnected`);\n }\n }\n } catch (error) {\n console.warn(`[Server ${serverAddr}] Disconnect error:`, error);\n // Ignore disconnect errors\n }\n}\n\n/**\n * Request chunk từ server sử dụng native QUIC\n * Note: Server phải đã được connect trước đó (trong downloadAllChunks)\n */\nasync function requestChunkFromServer(\n serverAddr: string,\n fileKey: string,\n downloadKey: string,\n chunkIndex: number,\n totalChunks: number,\n signature: string,\n): Promise<{ chunkIndex: number; bytes: Uint8Array }> {\n const { ip, port } = parseServerAddress(serverAddr);\n\n const requestId = `${fileKey}_${chunkIndex}_${Date.now()}`;\n\n // Tạo request payload\n const request: DownloadChunkRequest = {\n command: \"DownloadChunkRequest\",\n requestId,\n chunkIndex,\n totalChunks,\n payload: {\n file_key: fileKey,\n download_key: downloadKey,\n chunk_index: chunkIndex,\n signature: signature,\n },\n };\n\n const requestMessage = JSON.stringify(request) + \"\\n\";\n\n const response: any = await sendQuicMessage(ip, port, ALPN, requestMessage);\n\n if (\n response &&\n typeof response === \"object\" &&\n \"success\" in response &&\n response.success === false\n ) {\n throw new NativeQuicError(\n response.code || \"NATIVE_QUIC_ERROR\",\n response.retryable === true,\n response.retryAfterMs,\n response.message,\n );\n }\n\n // Parse response - có thể là object hoặc string JSON\n let data: DownloadResponse;\n try {\n if (typeof response === \"string\") {\n data = JSON.parse(response);\n } else if (typeof response === \"object\" && response !== null) {\n data = response as DownloadResponse;\n } else {\n throw new Error(`Invalid response type: ${typeof response}`);\n }\n } catch (parseError) {\n throw new Error(`Failed to parse server response`);\n }\n\n console.log(`[Chunk ${chunkIndex}] response status`, {\n status: data.status,\n hasData: !!data.chunk_data_base64,\n });\n\n if (data.status !== \"SUCCESS\") {\n const errorMessage = data.message || \"Unknown error\";\n throw new Error(errorMessage);\n }\n\n if (!data.chunk_data_base64) {\n throw new Error(\"No chunk data in response\");\n }\n\n const base64Data = data.chunk_data_base64;\n const binaryString = atob(base64Data);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n\n const actualChunkIndex = typeof data.chunkIndex === \"number\" ? data.chunkIndex : chunkIndex;\n\n return { chunkIndex: actualChunkIndex, bytes };\n}\n\n/**\n * Lấy server addresses từ blockchain (fetch mới mỗi lần)\n * @throws Error nếu không lấy được hoặc không đủ 2 servers\n */\nasync function getServerAddresses(from: string): Promise<string[]> {\n try {\n const addresses = await fileBlockchainRepository.getRustServerAddresses({ from });\n\n if (!addresses || addresses.length === 0) {\n throw new Error(\"No Rust server addresses found on blockchain\");\n }\n\n if (addresses.length < 2) {\n throw new Error(`Insufficient Rust servers: found ${addresses.length}, need at least 2`);\n }\n\n console.log(\"Server addresses from blockchain:\", addresses);\n return addresses;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to get Rust server addresses from blockchain: ${errorMessage}`);\n }\n}\n\n/**\n * Determine which server to use based on chunk index\n * Chẵn → Server 1, Lẻ → Server 2\n */\nfunction getServerForChunk(chunkIndex: number, serverAddresses: string[]): string {\n const serverIndex = chunkIndex % 2;\n if (!serverAddresses[serverIndex]) {\n throw new Error(`Server address not found for chunk index ${chunkIndex}`);\n }\n return serverAddresses[serverIndex]!;\n}\n\n/**\n * Request chunk với automatic server selection và retry logic\n */\nexport async function requestChunk(\n fileKey: string,\n downloadKey: string,\n chunkIndex: number,\n totalChunks: number,\n signature: string,\n serverAddresses: string[],\n): Promise<{ chunkIndex: number; data: Uint8Array }> {\n const serverAddr = getServerForChunk(chunkIndex, serverAddresses);\n const isEven = chunkIndex % 2 === 0;\n\n console.log(\n `[Chunk ${chunkIndex}] Requesting from ${isEven ? \"Server 1\" : \"Server 2\"} (${serverAddr})`,\n );\n\n // Retry logic cho request (giống Go code)\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {\n try {\n const result = await requestChunkFromServer(\n serverAddr,\n fileKey,\n downloadKey,\n chunkIndex,\n totalChunks,\n signature,\n );\n return { chunkIndex: result.chunkIndex, data: result.bytes };\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n if (lastError instanceof NativeQuicError) {\n if (!lastError.retryable) {\n throw lastError;\n }\n\n const delay = lastError.retryAfterMs ?? RETRY_DELAY_MS;\n console.warn(\n `[Chunk ${chunkIndex}] Native QUIC Error: ${lastError.code}. Retrying after ${delay}ms...`,\n );\n await new Promise((resolve) => setTimeout(resolve, delay));\n continue;\n }\n\n const errorMessage = lastError.message.toLowerCase();\n\n // Không retry nếu lỗi chứa \"to store chunk on disk\" (đã thành công)\n if (errorMessage.includes(\"to store chunk on disk\")) {\n console.log(`[Chunk ${chunkIndex}] Success (stored on disk), no retry needed`);\n throw lastError;\n }\n\n console.warn(\n `[Chunk ${chunkIndex}] Request attempt ${attempt + 1}/${MAX_RETRIES} failed:`,\n lastError.message,\n );\n\n if (attempt < MAX_RETRIES - 1) {\n // Delay trước khi retry\n await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY_MS));\n }\n }\n }\n\n // Tất cả retry đều thất bại\n throw new Error(\n `[Chunk ${chunkIndex}] Request failed sau ${MAX_RETRIES} lần thử: ${lastError?.message}`,\n );\n}\n\n/**\n * Download all chunks using a worker pool concurrency model\n *\n * Chia chunks thành 2 nhóm (chẵn/lẻ) và download song song\n * - Chunks chẵn (0, 2, 4...) → Server 1\n * - Chunks lẻ (1, 3, 5...) → Server 2\n * - Tương tự Go code với Goroutines\n *\n * @param fileKey - File key\n * @param downloadKey - Download key from event\n * @param totalChunks - Total number of chunks\n * @param signature - Signature for authentication\n * @param onProgress - Callback for progress updates\n * @returns Array of chunks in correct order\n */\nexport async function downloadAllChunks(\n fileKey: string,\n downloadKey: string,\n totalChunks: number,\n signature: string,\n from: string,\n onProgress?: (downloaded: number, total: number) => void,\n): Promise<Uint8Array[]> {\n console.log(`Starting download of ${totalChunks} chunks...`);\n\n // Lấy server addresses từ blockchain\n const serverAddresses = await getServerAddresses(from);\n if (serverAddresses.length < 2) {\n throw new Error(\"Need at least 2 server addresses to download chunks\");\n }\n\n const server1Addr = serverAddresses[0]!;\n const server2Addr = serverAddresses[1]!;\n\n console.log(`Using servers: ${server1Addr}, ${server2Addr}`);\n\n // Connect đến cả 2 servers trước\n await Promise.all([ensureConnected(server1Addr), ensureConnected(server2Addr)]);\n\n const results = new Array<Uint8Array>(totalChunks);\n let nextIndex = 0;\n let downloaded = 0;\n\n const CONCURRENCY = 4;\n\n async function worker() {\n while (true) {\n const chunkIndex = nextIndex++;\n if (chunkIndex >= totalChunks) return;\n\n const result = await requestChunk(\n fileKey,\n downloadKey,\n chunkIndex,\n totalChunks,\n signature,\n serverAddresses,\n );\n\n results[result.chunkIndex] = result.data;\n downloaded++;\n\n onProgress?.(downloaded, totalChunks);\n }\n }\n\n try {\n await Promise.all(Array.from({ length: CONCURRENCY }, () => worker()));\n\n console.log(`Downloaded all ${downloaded} chunks successfully`);\n return results;\n } finally {\n // Luôn luôn disconnect khi download xong, hoặc kể cả khi lỗi\n await Promise.all([disconnectServer(server1Addr), disconnectServer(server2Addr)]);\n }\n}\n\n/**\n * Download all chunks and merge into single file\n *\n * @param fileKey - File key\n * @param downloadKey - Download key from event\n * @param totalChunks - Total number of chunks\n * @param signature - Signature for authentication\n * @param onProgress - Callback for progress updates\n * @returns Merged file as Uint8Array\n */\nexport async function downloadAndMergeFile(\n fileKey: string,\n downloadKey: string,\n totalChunks: number,\n signature: string,\n from: string,\n onProgress?: (downloaded: number, total: number) => void,\n): Promise<Uint8Array> {\n const unlock = await downloadMutex.lock();\n try {\n const chunks = await downloadAllChunks(\n fileKey,\n downloadKey,\n totalChunks,\n signature,\n from,\n onProgress,\n );\n\n // Merge all chunks\n const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);\n const merged = new Uint8Array(totalLength);\n\n let offset = 0;\n for (const chunk of chunks) {\n merged.set(chunk, offset);\n offset += chunk.length;\n }\n\n console.log(`Merged file size: ${merged.length} bytes`);\n\n return merged;\n } finally {\n unlock();\n }\n}\n","import { createHash, createSignECDH } from '@metanodejs/system-core'\n\n/**\n * Generate signature for downloadKey\n * Logic matches Go code: hash = Keccak256Hash(\"0x00\" + downloadKey bytes)\n */\nexport async function generateSignature(downloadKey: string, privateKey: string): Promise<string> {\n try {\n // Remove 0x prefix if present for consistent processing\n const cleanDownloadKey = downloadKey.startsWith('0x') ? downloadKey.slice(2) : downloadKey\n\n // Create message with prefix \"0x00\" + downloadKey (matching Go: []byte(\"0x00\") + messageBytes)\n // In Go: messageBytes = []byte(downloadKeyHex), so we concatenate \"0x00\" + downloadKey\n const messageWithPrefix = `0x00${cleanDownloadKey}`\n\n // Hash the message with prefix (matching Go: crypto.Keccak256Hash([]byte(\"0x00\"), messageBytes))\n // isHex: false because we're passing the full string \"0x00\" + hex, not treating it as hex\n const hash = await createHash(messageWithPrefix, false)\n\n // Sign the hash\n const { sign } = await createSignECDH({\n message: hash,\n privateKey,\n hash\n })\n return sign\n } catch (error) {\n console.error('Error generating signature:', error)\n throw new Error('Failed to generate signature for download key')\n }\n}\n","import type { FileBlockchainRepositoryPort } from '../../../../core/Infrastructure-base/blockchain/fileblockchain/file-blockchain.repository.port'\nimport type { DownloadFileRequestDTO, DownloadFileResponseDTO } from '../dtos'\nimport { downloadAndMergeFile } from '../../infrastructure/services/rust-server-client.service'\nimport { generateSignature } from '../../../../utils/signature'\nimport { logger } from '../../../../core/Infrastructure-base/logger'\nimport { getPrivateKeyFromDb } from '@metanodejs/system-core'\n\nclass Mutex {\n private mutex = Promise.resolve()\n\n lock(): Promise<() => void> {\n let begin: (unlock: () => void) => void = (_unlock) => {}\n\n this.mutex = this.mutex.then(() => {\n return new Promise(begin)\n })\n\n return new Promise((res) => {\n begin = res\n })\n }\n}\n\nconst paymentMutex = new Mutex()\n\nexport interface DownloadKeyProvider {\n getDownloadKey(\n fileKey: string,\n timeout?: number\n ): Promise<{\n downloadKey: string\n user: string\n amount: string\n }>\n}\n\nexport class DownloadFileUseCase {\n constructor(\n private readonly fileBlockchainRepository: FileBlockchainRepositoryPort,\n private readonly downloadKeyProvider: DownloadKeyProvider\n ) {}\n\n async execute(request: DownloadFileRequestDTO): Promise<DownloadFileResponseDTO> {\n const { fileKey, from, downloadTimes = 1 } = request\n\n logger.info('Starting file download', { fileKey, from })\n\n // 1. Get file info\n const fileInfo = await this.fileBlockchainRepository.getFileInfo({\n from,\n fileKey\n })\n\n logger.info('File info retrieved', {\n name: fileInfo.name,\n totalChunks: fileInfo.totalChunks,\n status: fileInfo.status\n })\n\n // 2. Calculate download price\n const downloadPrice = await this.fileBlockchainRepository.calculatePrice({\n from,\n numChunks: +fileInfo.totalChunks\n })\n\n logger.info('Download price calculated', { price: downloadPrice })\n\n // 3. Pay for download (Được đưa vào hàng đợi Mutex Queue để tránh xung đột Smart Contract)\n const unlock = await paymentMutex.lock()\n try {\n await this.fileBlockchainRepository.payForDownload({\n from,\n fileKey,\n downloadTimes,\n value: downloadPrice\n })\n } finally {\n unlock()\n }\n\n logger.info('Payment completed, waiting for download key...')\n\n // 4. Get download key from provider (event listener)\n const { downloadKey } = await this.downloadKeyProvider.getDownloadKey(fileKey)\n \n const privateKey = await getPrivateKeyFromDb(from)\n if (!privateKey) {\n throw new Error('Private key is required to generate signature for download')\n }\n\n const signature = await generateSignature(downloadKey, privateKey)\n\n const fileData = await downloadAndMergeFile(\n fileKey,\n downloadKey,\n fileInfo.totalChunks,\n signature,\n from,\n (downloaded, total) => {\n logger.info(`Download progress: ${downloaded}/${total}`)\n }\n )\n\n logger.info('File downloaded and merged', { size: fileData.length })\n\n return {\n fileData: fileData as any,\n fileName: fileInfo.name,\n fileExt: fileInfo.ext || ''\n }\n }\n}\n","import type { FileBlockchainRepositoryPort } from '../../../../core/Infrastructure-base/blockchain/fileblockchain/file-blockchain.repository.port'\nimport type { SetPublicStatusUseCaseRequestDTO, SetPublicStatusUseCaseResponseDTO } from '../dtos/permissions.dto'\nimport { logger } from '../../../../core/Infrastructure-base/logger'\n\nexport class SetPublicStatusUseCase {\n constructor(private readonly fileBlockchainRepository: FileBlockchainRepositoryPort) {}\n\n async execute(request: SetPublicStatusUseCaseRequestDTO): Promise<SetPublicStatusUseCaseResponseDTO> {\n logger.info('Executing SetPublicStatusUseCase', { fileKey: request.fileKey, status: request.status })\n return this.fileBlockchainRepository.setPublicStatus({\n from: request.from,\n fileKey: request.fileKey,\n status: request.status\n })\n }\n}\n","import type { FileBlockchainRepositoryPort } from '../../../../core/Infrastructure-base/blockchain/fileblockchain/file-blockchain.repository.port'\nimport type { AddWhitelistUseCaseRequestDTO, AddWhitelistUseCaseResponseDTO } from '../dtos/permissions.dto'\nimport { logger } from '../../../../core/Infrastructure-base/logger'\n\nexport class AddWhitelistUseCase {\n constructor(private readonly fileBlockchainRepository: FileBlockchainRepositoryPort) {}\n\n async execute(request: AddWhitelistUseCaseRequestDTO): Promise<AddWhitelistUseCaseResponseDTO> {\n logger.info('Executing AddWhitelistUseCase', { fileKey: request.fileKey, usersCount: request.users.length })\n return this.fileBlockchainRepository.addWhitelist({\n from: request.from,\n fileKey: request.fileKey,\n users: request.users\n })\n }\n}\n","import type { FileBlockchainRepositoryPort } from '../../../../core/Infrastructure-base/blockchain/fileblockchain/file-blockchain.repository.port'\nimport type { GetWhitelistUseCaseRequestDTO, GetWhitelistUseCaseResponseDTO } from '../dtos/permissions.dto'\nimport { logger } from '../../../../core/Infrastructure-base/logger'\n\nexport class GetWhitelistUseCase {\n constructor(private readonly fileBlockchainRepository: FileBlockchainRepositoryPort) {}\n\n async execute(request: GetWhitelistUseCaseRequestDTO): Promise<GetWhitelistUseCaseResponseDTO> {\n logger.info('Executing GetWhitelistUseCase', { fileKey: request.fileKey })\n return this.fileBlockchainRepository.getWhitelist({\n from: request.from,\n fileKey: request.fileKey\n })\n }\n}\n","import type { FileBlockchainRepositoryPort } from '../../../../core/Infrastructure-base/blockchain/fileblockchain/file-blockchain.repository.port'\nimport type { IsPublicFileUseCaseRequestDTO, IsPublicFileUseCaseResponseDTO } from '../dtos/permissions.dto'\nimport { logger } from '../../../../core/Infrastructure-base/logger'\n\nexport class IsPublicFileUseCase {\n constructor(private readonly fileBlockchainRepository: FileBlockchainRepositoryPort) {}\n\n async execute(request: IsPublicFileUseCaseRequestDTO): Promise<IsPublicFileUseCaseResponseDTO> {\n logger.info('Executing IsPublicFileUseCase', { fileKey: request.fileKey })\n return this.fileBlockchainRepository.isPublicFile({\n from: request.from,\n fileKey: request.fileKey\n })\n }\n}\n","import z from 'zod'\n\nexport const UploadFileRequestSchema = z.object({\n file: z.instanceof(File),\n from: z.string(),\n chunkSize: z\n .number()\n .optional()\n .default(1024 * 250) // 250KB default\n})\n\nexport type UploadFileRequestDTO = z.infer<typeof UploadFileRequestSchema>\n\nexport const UploadFileResponseSchema = z.object({\n fileKey: z.string(),\n merkleRoot: z.string(),\n totalChunks: z.number()\n})\n\nexport type UploadFileResponseDTO = z.infer<typeof UploadFileResponseSchema>\n","import z from 'zod'\n\nexport const DownloadFileRequestSchema = z.object({\n fileKey: z.string(),\n from: z.string(),\n downloadTimes: z.number().optional().default(1)\n})\n\nexport type DownloadFileRequestDTO = z.infer<typeof DownloadFileRequestSchema>\n\nexport const DownloadFileResponseSchema = z.object({\n fileData: z.instanceof(Uint8Array),\n fileName: z.string(),\n fileExt: z.string()\n})\n\nexport type DownloadFileResponseDTO = z.infer<typeof DownloadFileResponseSchema>\n","/**\n * Download Key Listener Service\n *\n * Service lắng nghe event DownloadKeyGenerated và cung cấp downloadKey\n * khi được yêu cầu\n */\n\nimport type { DownloadKeyProvider } from '../../application/usecases/download-file.use-case'\nimport { logger } from '../../../../core/Infrastructure-base/logger'\nimport { eventLogs } from '../../../../core/Infrastructure-base/eventLog'\n\ninterface DownloadKeyData {\n downloadKey: string\n fileKey: string\n user: string\n amount: string\n timestamp: number\n}\n\nexport class DownloadKeyListenerService implements DownloadKeyProvider {\n private downloadKeys: Map<string, DownloadKeyData> = new Map()\n private pendingRequests: Map<\n string,\n Array<{\n resolve: (value: DownloadKeyData) => void\n reject: (error: Error) => void\n timeout: ReturnType<typeof setTimeout>\n }>\n > = new Map()\n private unsubscribe: (() => void) | null = null\n private isInitialized: boolean = false\n\n constructor() {\n this.startListening()\n }\n\n async initialize(userAddress: string, contractAddress: string): Promise<void> {\n if (this.isInitialized) {\n logger.info('DownloadKeyListenerService: Already initialized')\n return\n }\n\n try {\n await eventLogs.registerEvent(userAddress, contractAddress)\n this.isInitialized = true\n } catch (error) {\n logger.error('DownloadKeyListenerService: Failed to initialize', error)\n throw error\n }\n }\n\n /**\n * Bắt đầu lắng nghe event DownloadKeyGenerated\n */\n private startListening(): void {\n this.unsubscribe = eventLogs.eventLog.onEventLog((event: any) => {\n if (event.type === 'DownloadKeyGenerated') {\n this.handleDownloadKeyGenerated(event.payload)\n }\n })\n }\n\n /**\n * Xử lý event DownloadKeyGenerated\n */\n private handleDownloadKeyGenerated(payload: any): void {\n try {\n const fileKey = this.normalizeFileKey(payload?.fileKey)\n const downloadKey = payload?.downloadKey || null\n const user = payload?.user || ''\n const amount = payload?.amount || '0'\n\n if (!fileKey || !downloadKey) {\n logger.warn('DownloadKeyGenerated event missing required fields', { payload })\n return\n }\n\n const data: DownloadKeyData = {\n downloadKey,\n fileKey,\n user,\n amount,\n timestamp: Date.now()\n }\n\n // Lưu downloadKey\n this.downloadKeys.set(fileKey, data)\n\n // Resolve tất cả pending requests cho fileKey này\n const pending = this.pendingRequests.get(fileKey)\n if (pending) {\n pending.forEach(({ resolve, timeout }) => {\n clearTimeout(timeout)\n resolve(data)\n })\n this.pendingRequests.delete(fileKey)\n }\n } catch (error) {\n logger.error('Error handling DownloadKeyGenerated event', error)\n }\n }\n\n /**\n * Normalize fileKey để so sánh (remove 0x prefix, lowercase, pad)\n */\n private normalizeFileKey(fileKey: string | null | undefined): string | null {\n if (!fileKey) return null\n const normalized = fileKey.toLowerCase().startsWith('0x')\n ? fileKey.toLowerCase().slice(2)\n : fileKey.toLowerCase()\n return normalized.padStart(64, '0') // Ensure 64 chars (32 bytes hex)\n }\n\n /**\n * Lấy downloadKey cho fileKey\n */\n async getDownloadKey(\n fileKey: string,\n timeout: number = 30000\n ): Promise<{\n downloadKey: string\n user: string\n amount: string\n }> {\n const normalizedFileKey = this.normalizeFileKey(fileKey)\n if (!normalizedFileKey) {\n throw new Error('Invalid fileKey')\n }\n\n // Kiểm tra xem đã có downloadKey chưa\n const existing = this.downloadKeys.get(normalizedFileKey)\n if (existing) {\n return {\n downloadKey: existing.downloadKey,\n user: existing.user,\n amount: existing.amount\n }\n }\n\n // Nếu chưa có, đợi event\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n // Remove from pending\n const pending = this.pendingRequests.get(normalizedFileKey)\n if (pending) {\n const index = pending.findIndex((p) => p.resolve === resolve)\n if (index > -1) {\n pending.splice(index, 1)\n }\n if (pending.length === 0) {\n this.pendingRequests.delete(normalizedFileKey)\n }\n }\n\n reject(\n new Error(`Timeout waiting for downloadKey for fileKey: ${fileKey} after ${timeout}ms`)\n )\n }, timeout) as ReturnType<typeof setTimeout>\n\n // Thêm vào pending requests\n if (!this.pendingRequests.has(normalizedFileKey)) {\n this.pendingRequests.set(normalizedFileKey, [])\n }\n this.pendingRequests.get(normalizedFileKey)!.push({ resolve, reject, timeout: timer })\n })\n }\n\n /**\n * Dọn dẹp và dừng lắng nghe\n */\n stop(): void {\n if (this.unsubscribe) {\n this.unsubscribe()\n this.unsubscribe = null\n }\n this.downloadKeys.clear()\n this.pendingRequests.clear()\n }\n\n /**\n * Clear cache (có thể dùng để test hoặc reset)\n */\n clearCache(): void {\n this.downloadKeys.clear()\n }\n}\n","/**\n * File Activated Listener Service\n *\n * Service lắng nghe event FileActivated và cung cấp confirmation\n * khi file đã được activate sau khi upload hết chunks\n */\n\nimport { logger } from '../../../../core/Infrastructure-base/logger'\nimport { eventLogs } from '../../../../core/Infrastructure-base/eventLog'\n\nexport interface FileActivatedProvider {\n waitForFileActivated(\n fileKey: string,\n timeout?: number\n ): Promise<{\n fileKey: string\n user: string\n }>\n}\n\ninterface FileActivatedData {\n fileKey: string\n user: string\n timestamp: number\n}\n\nexport class FileActivatedListenerService implements FileActivatedProvider {\n private activatedFiles: Map<string, FileActivatedData> = new Map()\n private pendingRequests: Map<\n string,\n Array<{\n resolve: (value: FileActivatedData) => void\n reject: (error: Error) => void\n timeout: ReturnType<typeof setTimeout>\n }>\n > = new Map()\n private unsubscribe: (() => void) | null = null\n private isInitialized: boolean = false\n\n constructor() {\n this.startListening()\n }\n\n async initialize(userAddress: string, contractAddress: string): Promise<void> {\n if (this.isInitialized) {\n logger.info('FileActivatedListenerService: Already initialized')\n return\n }\n\n try {\n await eventLogs.registerEvent(userAddress, contractAddress)\n this.isInitialized = true\n } catch (error) {\n logger.error('FileActivatedListenerService: Failed to initialize', error)\n throw error\n }\n }\n\n /**\n * Bắt đầu lắng nghe event FileActivated\n */\n private startListening(): void {\n this.unsubscribe = eventLogs.eventLog.onEventLog((event: any) => {\n if (event.type === 'FileActivated') {\n this.handleFileActivated(event.payload)\n }\n })\n }\n\n /**\n * Xử lý event FileActivated\n */\n private handleFileActivated(payload: any): void {\n try {\n const fileKey = this.normalizeFileKey(payload?.fileKey)\n const user = payload?.user || ''\n\n if (!fileKey || !user) {\n logger.warn('FileActivated event missing required fields', { payload })\n return\n }\n\n const data: FileActivatedData = {\n fileKey,\n user,\n timestamp: Date.now()\n }\n\n // Lưu activated file\n this.activatedFiles.set(fileKey, data)\n\n // Resolve tất cả pending requests cho fileKey này\n const pending = this.pendingRequests.get(fileKey)\n if (pending) {\n pending.forEach(({ resolve, timeout }) => {\n clearTimeout(timeout)\n resolve(data)\n })\n this.pendingRequests.delete(fileKey)\n }\n } catch (error) {\n logger.error('Error handling FileActivated event', error)\n }\n }\n\n /**\n * Normalize fileKey để so sánh (remove 0x prefix, lowercase, pad)\n */\n private normalizeFileKey(fileKey: string | null | undefined): string | null {\n if (!fileKey) return null\n const normalized = fileKey.toLowerCase().startsWith('0x')\n ? fileKey.toLowerCase().slice(2)\n : fileKey.toLowerCase()\n return normalized.padStart(64, '0') // Ensure 64 chars (32 bytes hex)\n }\n\n /**\n * Đợi FileActivated event cho fileKey\n */\n async waitForFileActivated(\n fileKey: string,\n timeout: number = 60000 // 60 seconds default\n ): Promise<{\n fileKey: string\n user: string\n }> {\n const normalizedFileKey = this.normalizeFileKey(fileKey)\n if (!normalizedFileKey) {\n throw new Error('Invalid fileKey')\n }\n\n // Kiểm tra xem đã có activated chưa\n const existing = this.activatedFiles.get(normalizedFileKey)\n if (existing) {\n return {\n fileKey: existing.fileKey,\n user: existing.user\n }\n }\n\n // Nếu chưa có, đợi event\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n // Remove from pending\n const pending = this.pendingRequests.get(normalizedFileKey)\n if (pending) {\n const index = pending.findIndex((p) => p.resolve === resolve)\n if (index > -1) {\n pending.splice(index, 1)\n }\n if (pending.length === 0) {\n this.pendingRequests.delete(normalizedFileKey)\n }\n }\n\n reject(\n new Error(\n `Timeout waiting for FileActivated event for fileKey: ${fileKey} after ${timeout}ms`\n )\n )\n }, timeout) as ReturnType<typeof setTimeout>\n\n // Thêm vào pending requests\n if (!this.pendingRequests.has(normalizedFileKey)) {\n this.pendingRequests.set(normalizedFileKey, [])\n }\n this.pendingRequests.get(normalizedFileKey)!.push({ resolve, reject, timeout: timer })\n })\n }\n\n /**\n * Dọn dẹp và dừng lắng nghe\n */\n stop(): void {\n if (this.unsubscribe) {\n this.unsubscribe()\n this.unsubscribe = null\n }\n this.activatedFiles.clear()\n this.pendingRequests.clear()\n }\n\n /**\n * Clear cache (có thể dùng để test hoặc reset)\n */\n clearCache(): void {\n this.activatedFiles.clear()\n }\n}\n","import { appConfig } from '../../config/app.config'\nimport { fileBlockchainRepository } from '../../core/Infrastructure-base/blockchain/fileblockchain/file-blockchain.repository'\nimport { eventLogs } from '../../core/Infrastructure-base/eventLog'\nimport { \n UploadFileUseCase, \n DownloadFileUseCase, \n SetPublicStatusUseCase,\n AddWhitelistUseCase,\n GetWhitelistUseCase,\n IsPublicFileUseCase,\n type DownloadKeyProvider \n} from './application'\nimport { DownloadKeyListenerService } from './infrastructure/services/download-key-listener.service'\nimport {\n FileActivatedListenerService,\n type FileActivatedProvider\n} from './infrastructure/services/file-activated-listener.service'\n\n/**\n * File Module Container\n * Dependency injection container cho file module\n */\nexport class FileModuleContainer {\n private uploadFileUseCase: UploadFileUseCase\n private downloadFileUseCase: DownloadFileUseCase | null = null\n private downloadKeyListenerService: DownloadKeyListenerService | null = null\n private fileActivatedListenerService: FileActivatedListenerService | null = null\n private setPublicStatusUseCase: SetPublicStatusUseCase\n private addWhitelistUseCase: AddWhitelistUseCase\n private getWhitelistUseCase: GetWhitelistUseCase\n private isPublicFileUseCase: IsPublicFileUseCase\n private initPromise: Promise<void> | null = null\n\n constructor(\n downloadKeyProvider?: DownloadKeyProvider,\n options?: {\n userAddress?: string\n contractAddress?: string\n }\n ) {\n // Tạo FileActivatedListenerService mặc định\n const fileActivatedProvider = this.createDefaultFileActivatedProvider()\n\n this.uploadFileUseCase = new UploadFileUseCase(\n fileBlockchainRepository,\n fileActivatedProvider || undefined\n )\n this.setPublicStatusUseCase = new SetPublicStatusUseCase(fileBlockchainRepository)\n this.addWhitelistUseCase = new AddWhitelistUseCase(fileBlockchainRepository)\n this.getWhitelistUseCase = new GetWhitelistUseCase(fileBlockchainRepository)\n this.isPublicFileUseCase = new IsPublicFileUseCase(fileBlockchainRepository)\n\n // Nếu không có provider được truyền vào, tự động tạo DownloadKeyListenerService\n const provider = downloadKeyProvider || this.createDefaultDownloadKeyProvider()\n\n if (provider) {\n this.downloadFileUseCase = new DownloadFileUseCase(fileBlockchainRepository, provider)\n }\n\n // Tự động đăng ký events nếu có userAddress\n if (options?.userAddress) {\n const contractAddress = options.contractAddress || appConfig.file\n this.initialize(options.userAddress, contractAddress).catch((error) => {\n console.warn('Failed to auto-initialize FileModuleContainer:', error)\n })\n }\n }\n\n /**\n * Tạo DownloadKeyProvider mặc định sử dụng EventLog\n */\n private createDefaultDownloadKeyProvider(): DownloadKeyProvider | null {\n try {\n this.downloadKeyListenerService = new DownloadKeyListenerService()\n return this.downloadKeyListenerService\n } catch (error) {\n console.warn('Failed to create DownloadKeyListenerService:', error)\n return null\n }\n }\n\n /**\n * Tạo FileActivatedProvider mặc định sử dụng EventLog\n */\n private createDefaultFileActivatedProvider(): FileActivatedProvider | null {\n try {\n this.fileActivatedListenerService = new FileActivatedListenerService()\n return this.fileActivatedListenerService\n } catch (error) {\n console.warn('Failed to create FileActivatedListenerService:', error)\n return null\n }\n }\n\n getUploadFileUseCase(): UploadFileUseCase {\n return this.uploadFileUseCase\n }\n\n getDownloadFileUseCase(): DownloadFileUseCase {\n if (!this.downloadFileUseCase) {\n throw new Error('DownloadKeyProvider is required for download functionality')\n }\n return this.downloadFileUseCase\n }\n\n getSetPublicStatusUseCase(): SetPublicStatusUseCase {\n return this.setPublicStatusUseCase\n }\n\n getAddWhitelistUseCase(): AddWhitelistUseCase {\n return this.addWhitelistUseCase\n }\n\n getGetWhitelistUseCase(): GetWhitelistUseCase {\n return this.getWhitelistUseCase\n }\n\n getIsPublicFileUseCase(): IsPublicFileUseCase {\n return this.isPublicFileUseCase\n }\n\n /**\n * Khởi tạo và đăng ký event với native\n * Cần gọi method này trước khi sử dụng download/upload để native biết gửi event về\n * @param userAddress Địa chỉ ví của user\n * @param contractAddress Địa chỉ contract file\n */\n async initialize(userAddress: string, contractAddress: string): Promise<void> {\n if (!this.initPromise) {\n this.initPromise = (async () => {\n await eventLogs.registerAbi()\n\n if (this.downloadKeyListenerService instanceof DownloadKeyListenerService) {\n await this.downloadKeyListenerService.initialize(userAddress, contractAddress)\n } else {\n console.warn('DownloadKeyListenerService not available, cannot initialize')\n }\n if (this.fileActivatedListenerService instanceof FileActivatedListenerService) {\n await this.fileActivatedListenerService.initialize(userAddress, contractAddress)\n } else {\n console.warn('FileActivatedListenerService not available, cannot initialize')\n }\n })()\n }\n return this.initPromise\n }\n\n /**\n * Dọn dẹp resources\n */\n cleanup(): void {\n if (this.downloadKeyListenerService) {\n this.downloadKeyListenerService.stop()\n this.downloadKeyListenerService = null\n }\n if (this.fileActivatedListenerService) {\n this.fileActivatedListenerService.stop()\n this.fileActivatedListenerService = null\n }\n }\n}\n\n/**\n * Factory function để tạo file module container\n * Nếu không truyền downloadKeyProvider, sẽ tự động tạo DownloadKeyListenerService\n * @param downloadKeyProvider Optional custom provider\n * @param options Optional configuration: userAddress để tự động đăng ký events, contractAddress\n */\nexport function createFileModule(\n downloadKeyProvider?: DownloadKeyProvider,\n options?: {\n userAddress?: string\n contractAddress?: string\n }\n): FileModuleContainer {\n return new FileModuleContainer(downloadKeyProvider, options)\n}\n"],"mappings":"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,UACd,KAAM,UACN,KAAM,SACR,CACF,EACA,KAAM,cACN,QAAS,CACP,CACE,WAAY,CACV,CACE,aAAc,UACd,KAAM,QACN,KAAM,SACR,EACA,CACE,aAAc,UACd,KAAM,aACN,KAAM,SACR,EACA,CACE,aAAc,SACd,KAAM,aACN,KAAM,QACR,EACA,CACE,aAAc,SACd,KAAM,cACN,KAAM,QACR,EACA,CACE,aAAc,SACd,KAAM,aACN,KAAM,QACR,EACA,CACE,aAAc,SACd,KAAM,OACN,KAAM,QACR,EACA,CACE,aAAc,SACd,KAAM,MACN,KAAM,QACR,EACA,CACE,aAAc,SACd,KAAM,qBACN,KAAM,QACR,EACA,CACE,aAAc,SACd,KAAM,YACN,KAAM,QACR,EACA,CACE,aAAc,kBACd,KAAM,SACN,KAAM,OACR,CACF,EACA,aAAc,cACd,KAAM,GACN,KAAM,OACR,CACF,EACA,gBAAiB,OACjB,KAAM,UACR,CACF,ECxEO,IAAMC,GAA4B,CACvC,CACE,OAAQ,CAAC,EACT,KAAM,yBACN,QAAS,CACP,CACE,aAAc,WACd,KAAM,GACN,KAAM,UACR,CACF,EACA,gBAAiB,OACjB,KAAM,UACR,CACF,ECdO,IAAMC,GAAoB,CAC/B,CACE,OAAQ,CACN,CACE,aAAc,UACd,KAAM,UACN,KAAM,SACR,EACA,CACE,aAAc,UACd,KAAM,gBACN,KAAM,SACR,CACF,EACA,KAAM,iBACN,QAAS,CAAC,EACV,gBAAiB,UACjB,KAAM,UACR,CACF,ECnBO,IAAMC,GAAkB,CAC7B,CACE,OAAQ,CACN,CACE,WAAY,CACV,CACE,aAAc,UACd,KAAM,QACN,KAAM,SACR,EACA,CACE,aAAc,UACd,KAAM,aACN,KAAM,SACR,EACA,CACE,aAAc,SACd,KAAM,aACN,KAAM,QACR,EACA,CACE,aAAc,SACd,KAAM,cACN,KAAM,QACR,EACA,CACE,aAAc,SACd,KAAM,aACN,KAAM,QACR,EACA,CACE,aAAc,SACd,KAAM,OACN,KAAM,QACR,EACA,CACE,aAAc,SACd,KAAM,MACN,KAAM,QACR,EACA,CACE,aAAc,SACd,KAAM,qBACN,KAAM,QACR,EACA,CACE,aAAc,SACd,KAAM,YACN,KAAM,QACR,EACA,CACE,aAAc,kBACd,KAAM,SACN,KAAM,OACR,CACF,EACA,aAAc,cACd,KAAM,OACN,KAAM,OACR,CACF,EACA,KAAM,eACN,QAAS,CACP,CACE,aAAc,UACd,KAAM,UACN,KAAM,SACR,CACF,EACA,gBAAiB,UACjB,KAAM,UACR,CACF,ECxEO,IAAMC,GAAiB,CAC5B,CACE,OAAQ,CACN,CACE,aAAc,UACd,KAAM,UACN,KAAM,SACR,EACA,CACE,aAAc,QACd,KAAM,YACN,KAAM,OACR,EACA,CACE,aAAc,UACd,KAAM,aACN,KAAM,SACR,EACA,CACE,aAAc,YACd,KAAM,cACN,KAAM,WACR,CACF,EACA,KAAM,cACN,QAAS,CAAC,EACV,gBAAiB,aACjB,KAAM,UACR,CACF,EC7BO,IAAMC,GAAqB,CAChC,CACE,OAAQ,CACN,CACE,aAAc,UACd,KAAM,UACN,KAAM,SACR,EACA,CACE,aAAc,OACd,KAAM,SACN,KAAM,MACR,CACF,EACA,KAAM,kBACN,QAAS,CAAC,EACV,gBAAiB,aACjB,KAAM,UACR,CACF,ECnBO,IAAMC,GAAkB,CAC7B,CACE,OAAQ,CACN,CACE,aAAc,UACd,KAAM,UACN,KAAM,SACR,EACA,CACE,aAAc,YACd,KAAM,QACN,KAAM,WACR,CACF,EACA,KAAM,eACN,QAAS,CAAC,EACV,gBAAiB,aACjB,KAAM,UACR,CACF,ECnBO,IAAMC,GAAkB,CAC7B,CACE,OAAQ,CACN,CACE,aAAc,UACd,KAAM,UACN,KAAM,SACR,CACF,EACA,KAAM,eACN,QAAS,CACP,CACE,aAAc,YACd,KAAM,GACN,KAAM,WACR,CACF,EACA,gBAAiB,OACjB,KAAM,UACR,CACF,ECpBO,IAAMC,GAAkB,CAC7B,CACE,OAAQ,CACN,CACE,aAAc,UACd,KAAM,UACN,KAAM,SACR,CACF,EACA,KAAM,eACN,QAAS,CACP,CACE,aAAc,OACd,KAAM,GACN,KAAM,MACR,CACF,EACA,gBAAiB,OACjB,KAAM,UACR,CACF,ECpBA,IAAAC,GAAc,kBAGP,IAAMC,GAA8BC,EAAkB,OAAO,CAClE,UAAW,GAAAC,QAAE,OAAO,CACtB,CAAC,EAIYC,GAA+B,GAAAD,QAAE,OAAO,ECRrD,IAAAE,EAAc,kBAEDC,GAA4BC,EAAkB,OAAO,CAChE,KAAM,EAAAC,QAAE,OAAO,CACb,MAAO,EAAAA,QAAE,OAAO,EAChB,WAAY,EAAAA,QAAE,OAAO,EACrB,WAAY,EAAAA,QAAE,OAAO,EACrB,YAAa,EAAAA,QAAE,OAAO,EACtB,WAAY,EAAAA,QAAE,OAAO,EACrB,KAAM,EAAAA,QAAE,OAAO,EACf,IAAK,EAAAA,QAAE,OAAO,EACd,mBAAoB,EAAAA,QAAE,OAAO,EAC7B,UAAW,EAAAA,QAAE,OAAO,EACpB,OAAQ,EAAAA,QAAE,OAAO,CACnB,CAAC,EACD,MAAO,EAAAA,QAAE,OAAO,CAClB,CAAC,EAIYC,GAA6B,EAAAD,QAAE,OAAO,CACjD,QAAS,EAAAA,QAAE,OAAO,CACpB,CAAC,ECtBD,IAAAE,EAAc,kBAEDC,GAA2BC,EAAkB,OAAO,CAC/D,QAAS,EAAAC,QAAE,OAAO,EAClB,UAAW,EAAAA,QAAE,OAAO,EACpB,WAAY,EAAAA,QAAE,OAAO,EACrB,YAAa,EAAAA,QAAE,MAAM,EAAAA,QAAE,OAAO,CAAC,CACjC,CAAC,ECPD,IAAAC,EAAc,kBAEDC,GAA2BC,EAAkB,OAAO,CAC/D,QAAS,EAAAC,QAAE,OAAO,CACpB,CAAC,EAIYC,GAA4B,EAAAD,QAAE,OAAO,CAChD,MAAO,EAAAA,QAAE,OAAO,EAChB,WAAY,EAAAA,QAAE,OAAO,EACrB,WAAY,EAAAA,QAAE,OAAO,EACrB,YAAa,EAAAA,QAAE,OAAO,EACtB,WAAY,EAAAA,QAAE,OAAO,EACrB,KAAM,EAAAA,QAAE,OAAO,EACf,IAAK,EAAAA,QAAE,OAAO,EACd,mBAAoB,EAAAA,QAAE,OAAO,EAC7B,UAAW,EAAAA,QAAE,OAAO,EACpB,OAAQ,EAAAA,QAAE,OAAO,CACnB,CAAC,ECnBD,IAAAE,EAAc,kBAEDC,GAA8BC,EAAkB,OAAO,CAClE,QAAS,EAAAC,QAAE,OAAO,EAClB,cAAe,EAAAA,QAAE,OAAO,EACxB,MAAO,EAAAA,QAAE,OAAO,CAClB,CAAC,EAIYC,GAA+B,EAAAD,QAAE,OAAO,CACnD,gBAAiB,EAAAA,QAAE,OAAO,EAAE,SAAS,CACvC,CAAC,ECbD,IAAAE,GAAc,kBAGP,IAAMC,GAAqCC,EAAkB,OAAO,CACzE,YAAa,GAAAC,QAAE,OAAO,CACxB,CAAC,EAIYC,GAAsC,GAAAD,QAAE,OAAO,ECT5D,IAAAE,GAAc,kBAGP,IAAMC,GAAsCC,EAAkB,OAAO,CAAC,CAAC,EAIjEC,GAAuC,GAAAC,QAAE,MAAM,GAAAA,QAAE,OAAO,CAAC,ECPtE,IAAAC,GAAkB,eAGX,IAAMC,GAA+BC,EAAkB,OAAO,CACnE,QAAS,KAAE,OAAO,EAClB,OAAQ,KAAE,QAAQ,CACpB,CAAC,ECND,IAAAC,GAAkB,eAGX,IAAMC,GAA4BC,EAAkB,OAAO,CAChE,QAAS,KAAE,OAAO,EAClB,MAAO,KAAE,MAAM,KAAE,OAAO,CAAC,CAC3B,CAAC,ECND,IAAAC,GAAkB,eAGX,IAAMC,GAA4BC,EAAkB,OAAO,CAChE,QAAS,KAAE,OAAO,CACpB,CAAC,ECLD,IAAAC,GAAkB,eAGX,IAAMC,GAA4BC,EAAkB,OAAO,CAChE,QAAS,KAAE,OAAO,CACpB,CAAC,ECgDM,IAAMC,GAAN,cACGC,CAEV,CACE,aAAc,CACZ,MAAMC,EAAU,KAAMC,CAAM,CAC9B,CAEA,MAAM,eAAeC,EAAuE,CAC1F,QAAQ,IAAI,yBAA0BA,CAAO,EAC7C,IAAMC,EAAe,KAAK,gBAAgBC,GAA6BF,CAAO,EACxEG,EAAY,CAAE,UAAWF,EAAa,SAAU,EACtD,OAAO,KAAK,mBAA8C,CACxD,GAAIA,EAAa,IAAMH,EAAU,KACjC,KAAMG,EAAa,KACnB,UAAAE,EACA,aAAc,iBACd,QAAS,OACT,QAASC,EACX,CAAC,CACH,CAEA,MAAM,aAAaJ,EAAmE,CACpF,IAAMC,EAAe,KAAK,gBAAgBI,GAA2BL,CAAO,EACtEG,EAAY,CAAE,KAAMF,EAAa,IAAK,EAC5C,OAAO,KAAK,mBAA4C,CACtD,GAAIA,EAAa,IAAMH,EAAU,KACjC,KAAMG,EAAa,KACnB,UAAAE,EACA,aAAc,eACd,QAAS,KACT,MAAOF,EAAa,MACpB,QAASK,EACX,CAAC,CACH,CAEA,MAAM,YAAYN,EAAiE,CACjF,IAAMC,EAAe,KAAK,gBAAgBM,GAA0BP,CAAO,EACrEG,EAAY,CAChB,QAASF,EAAa,QACtB,UAAWA,EAAa,UACxB,WAAYA,EAAa,WACzB,YAAaA,EAAa,WAC5B,EACA,OAAO,KAAK,mBAA2C,CACrD,GAAIA,EAAa,IAAMH,EAAU,KACjC,KAAMG,EAAa,KACnB,UAAAE,EACA,aAAc,cACd,QAAS,KACT,QAASK,EACX,CAAC,CACH,CAEA,MAAM,YAAYR,EAAiE,CACjF,IAAMC,EAAe,KAAK,gBAAgBQ,GAA0BT,CAAO,EACrEG,EAAY,CAChB,QAASF,EAAa,OACxB,EACA,OAAO,KAAK,mBAA2C,CACrD,GAAIA,EAAa,IAAMH,EAAU,KACjC,KAAMG,EAAa,KACnB,UAAAE,EACA,aAAc,cACd,QAAS,OACT,QAASO,EACX,CAAC,CACH,CAEA,MAAM,eAAeV,EAAuE,CAC1F,IAAMC,EAAe,KAAK,gBAAgBU,GAA6BX,CAAO,EACxEG,EAAY,CAChB,QAASF,EAAa,QACtB,cAAeA,EAAa,aAC9B,EACA,OAAO,KAAK,mBAA8C,CACxD,GAAIA,EAAa,IAAMH,EAAU,KACjC,KAAMG,EAAa,KACnB,UAAAE,EACA,aAAc,iBACd,QAAS,KACT,MAAOF,EAAa,MACpB,QAASW,EACX,CAAC,CACH,CAEA,MAAM,sBACJZ,EAC2C,CAC3C,IAAMC,EAAe,KAAK,gBAAgBY,GAAoCb,CAAO,EAC/EG,EAAY,CAChB,YAAaF,EAAa,WAC5B,EACA,OAAO,KAAK,mBAAqD,CAC/D,GAAIA,EAAa,IAAMH,EAAU,KACjC,KAAMG,EAAa,KACnB,UAAAE,EACA,aAAc,wBACd,QAAS,KACT,QAASW,EACX,CAAC,CACH,CAEA,MAAM,uBACJd,EAC4C,CAC5C,IAAMC,EAAe,KAAK,gBAAgBc,GAAqCf,CAAO,EAChFG,EAAY,CAAC,EACnB,OAAO,KAAK,mBAAsD,CAChE,GAAIF,EAAa,IAAMH,EAAU,KACjC,KAAMG,EAAa,KACnB,UAAAE,EACA,aAAc,yBACd,QAAS,OACT,QAASa,EACX,CAAC,CACH,CAEA,MAAM,gBAAgBhB,EAAyE,CAC7F,IAAMC,EAAe,KAAK,gBAAgBgB,GAA8BjB,CAAO,EACzEG,EAAY,CAChB,QAASF,EAAa,QACtB,OAAQA,EAAa,MACvB,EACA,OAAO,KAAK,mBAA+C,CACzD,GAAIA,EAAa,IAAMH,EAAU,KACjC,KAAMG,EAAa,KACnB,UAAAE,EACA,aAAc,kBACd,QAAS,KACT,QAASe,EACX,CAAC,CACH,CAEA,MAAM,aAAalB,EAAmE,CACpF,IAAMC,EAAe,KAAK,gBAAgBkB,GAA2BnB,CAAO,EACtEG,EAAY,CAChB,QAASF,EAAa,QACtB,MAAOA,EAAa,KACtB,EACA,OAAO,KAAK,mBAA4C,CACtD,GAAIA,EAAa,IAAMH,EAAU,KACjC,KAAMG,EAAa,KACnB,UAAAE,EACA,aAAc,eACd,QAAS,KACT,QAASiB,EACX,CAAC,CACH,CAEA,MAAM,aAAapB,EAAmE,CACpF,IAAMC,EAAe,KAAK,gBAAgBoB,GAA2BrB,CAAO,EACtEG,EAAY,CAChB,QAASF,EAAa,OACxB,EACA,OAAO,KAAK,mBAA4C,CACtD,GAAIA,EAAa,IAAMH,EAAU,KACjC,KAAMG,EAAa,KACnB,UAAAE,EACA,aAAc,eACd,QAAS,OACT,QAASmB,EACX,CAAC,CACH,CAEA,MAAM,aAAatB,EAAmE,CACpF,IAAMC,EAAe,KAAK,gBAAgBsB,GAA2BvB,CAAO,EACtEG,EAAY,CAChB,QAASF,EAAa,OACxB,EACA,OAAO,KAAK,mBAA4C,CACtD,GAAIA,EAAa,IAAMH,EAAU,KACjC,KAAMG,EAAa,KACnB,UAAAE,EACA,aAAc,eACd,QAAS,OACT,QAASqB,EACX,CAAC,CACH,CACF,EAEaC,EAA2B,IAAI7B,GCzO5C,IAAA8B,GAAoC,iCCDpC,IAAAC,GAAA,CACE,CACE,UAAa,GACb,OAAU,CACR,CACE,QAAW,GACX,aAAgB,UAChB,KAAQ,cACR,KAAQ,SACV,EACA,CACE,QAAW,GACX,aAAgB,UAChB,KAAQ,UACR,KAAQ,SACV,EACA,CACE,QAAW,GACX,aAAgB,UAChB,KAAQ,OACR,KAAQ,SACV,EACA,CACE,QAAW,GACX,aAAgB,UAChB,KAAQ,SACR,KAAQ,SACV,CACF,EACA,KAAQ,uBACR,KAAQ,OACV,EACA,CACE,UAAa,GACb,OAAU,CACR,CACE,QAAW,GACX,aAAgB,UAChB,KAAQ,OACR,KAAQ,SACV,EACA,CACE,QAAW,GACX,aAAgB,UAChB,KAAQ,UACR,KAAQ,SACV,CACF,EACA,KAAQ,gBACR,KAAQ,OACV,CACF,ED9CA,IAAMC,GAAN,MAAMC,CAAU,CASN,aAAc,CAHtB,KAAQ,wBAAgD,KACxD,KAAQ,kBAAoB,IAAI,IAG9B,KAAK,WAAa,IAAI,aACtB,KAAK,UAAY,IAAI,YAAmB,KAAK,UAAU,CACzD,CAEA,OAAc,aAAyB,CACrC,OAAKA,EAAU,WACbA,EAAU,SAAW,IAAIA,GAEpBA,EAAU,QACnB,CAEA,IAAI,UAA+B,CACjC,OAAO,KAAK,SACd,CAEA,IAAI,WAAuB,CACzB,OAAO,KAAK,UACd,CAEA,MAAa,aAAc,CACpB,KAAK,0BACR,KAAK,wBAA0B,KAAK,WAAW,YAAYC,EAAY,EAAE,MAAOC,GAAQ,CACtF,QAAQ,KAAK,6CAA8CA,CAAG,CAChE,CAAC,GAEH,MAAM,KAAK,uBACb,CAEA,MAAa,cAAcC,EAAqBC,EAAyB,CACvE,IAAMC,EAAM,GAAGF,EAAY,YAAY,CAAC,IAAIC,EAAgB,YAAY,CAAC,GACpE,KAAK,kBAAkB,IAAIC,CAAG,IACjC,KAAK,kBAAkB,IAAIA,CAAG,EAC9B,MAAM,KAAK,UAAU,cAAcF,EAAa,CAACC,CAAe,CAAC,EAErE,CACF,EAEaE,EAAYP,GAAU,YAAY,EEpD/C,IAAAQ,GAA+B,kBAmBlBC,MAAa,mBACxB,4DACF,EAEaC,GAA2B,GAC3BC,GAAmB,GAEzB,SAASC,GAAiBC,EAAS,KAAMC,EAASJ,GAAkC,CACzF,MAAO,GAAGG,CAAM,IAAIJ,GAAWK,CAAM,CAAC,EACxC,CC3BA,IAAMC,GAAS,mBAIR,SAASC,EAAUC,EAAgBC,EAA+C,CACvF,GAAID,EACF,OAIA,MAAM,IAAI,MAAMF,EAAM,CAe1B,CC1BO,SAASI,GAAaC,EAAoC,CAC/D,OAAOA,IAAM,IACf,CAEO,SAASC,GAAqBC,EAAsB,CACzD,OAAOA,GAAO,MAAM,QAAQA,CAAG,CACjC,CAEO,SAASC,GAAYC,EAAyB,CACnD,OAAIA,IAAU,KACL,GAGF,CAAC,CAAC,QAAS,WAAY,QAAQ,EAAE,SAAS,OAAOA,CAAK,CAC/D,CAEO,IAAMC,GAAkBH,GAAsB,OAAOA,EAAQ,IACvDI,GAAoBJ,GAAsB,CAACG,GAAMH,CAAG,EACpDK,GAAaL,GAA6B,OAAOA,GAAQ,UACzDM,GAAcN,GAAsB,OAAOA,GAAQ,WACnDO,GAAYP,GAA4B,SAAS,KAAKA,CAAG,IAAM,kBAC/DQ,GAAYR,GAAgC,OAAOA,GAAQ,SAC3DS,GAAYT,GAA4B,SAAS,KAAKA,CAAG,IAAM,kBAC/DU,GAASV,GAAuC,SAAS,KAAKA,CAAG,IAAM,eACvEW,GAASX,GAAkC,SAAS,KAAKA,CAAG,IAAM,eAClEY,GAAUZ,GAA8B,SAAS,KAAKA,CAAG,IAAM,gBAC/Da,GAAYb,GAAgC,OAAOA,GAAQ,SAC3Dc,GAAsBd,GAE1BS,GAAST,CAAG,GAAKM,GAAWN,EAAI,IAAI,GAAKM,GAAWN,EAAI,KAAK,EAGzDe,GAAWf,GACtBH,GAAUG,CAAG,GAAKG,GAAMH,CAAG,GAAKgB,GAAWhB,CAAG,EAEnCiB,GAAYjB,GACvB,OAAO,OAAW,KAAe,SAAS,KAAKA,CAAG,IAAM,kBAE7CkB,GAAYlB,GACvBA,IAAQ,MAAQ,OAAOA,GAAQ,UAAY,OAAOA,EAAI,MAAS,WAGpDmB,GAAY,OAAO,OAAW,IAIrCC,GAAiBC,GACrBA,GAAO,SAAW,EAMb,SAASC,EAAqBtB,EAAkB,CACrD,OAAKA,EAGDD,GAAQC,CAAG,EACNoB,GAAWpB,CAAG,EAGnBQ,GAASR,CAAG,EACPA,EAAI,KAAK,EAAE,SAAW,EAG3BA,aAAe,KAAOA,aAAe,IAChCA,EAAI,OAAS,EAGlBS,GAAST,CAAG,EACP,OAAO,KAAKA,CAAG,EAAE,SAAW,EAG9B,GAlBE,EAmBX,CAEO,SAASgB,GAAwBhB,EAAkB,CACxD,MAAO,CAACsB,EAAQtB,CAAG,CACrB,CAQO,SAASuB,MAAgBC,EAAsB,CACpD,OAAIA,EAAK,OAAS,EACTA,EAAK,OAAO,CAACC,EAAGC,IAAMD,GAAKT,GAAWU,CAAC,EAAG,EAAI,EAEhD,EACT,CAMO,SAASC,MAAaH,EAAsB,CACjD,OAAIA,EAAK,OAAS,EACTA,EAAK,OAAO,CAACC,EAAGC,IAAMD,GAAKH,EAAQI,CAAC,EAAG,EAAI,EAE7C,EACT,CAQO,SAASE,GAAWC,EAAsC,CAC/D,MAAI,CAACA,GAAUA,EAAO,OAAS,EACtB,GAIPA,EAAO,CAAC,IAAM,KACdA,EAAO,CAAC,IAAM,IACdA,EAAO,CAAC,IAAM,IACdA,EAAO,CAAC,IAAM,IACdA,EAAO,CAAC,IAAM,IACdA,EAAO,CAAC,IAAM,IACdA,EAAO,CAAC,IAAM,IACdA,EAAO,CAAC,IAAM,EAElB,CAEO,IAAMC,GAAYX,GAAY,aAAa,KAAK,UAAU,SAAS,EAAI,GAGxEY,GAAQZ,GAAY,OAAO,YAAc,OAAO,aAAe,OAExDa,GAAWb,GAAYY,KAAQ,kBAAkB,GAAG,QAAU,GAG9DE,GACXd,KACC,EAAE,aAAc,SAAW,gCAAgC,KAAK,UAAU,SAAS,GCzI/E,SAASe,GAAMC,EAA2B,CAC/C,OAAO,IAAI,QAASC,GAAY,WAAWA,EAASD,CAAE,CAAC,CACzD,CCFO,SAASE,GAAcC,EAAeC,EAAK,GAAOC,EAAK,EAAG,CAC/D,IAAMC,EAASF,EAAK,IAAO,KAE3B,GAAI,KAAK,IAAID,CAAK,EAAIG,EACpB,OAAOH,EAAQ,KAGjB,IAAMI,EAAQH,EACV,CAAC,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,IAAI,EAC/C,CAAC,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,KAAK,EACvDI,EAAI,GACFC,EAAI,IAAMJ,EAEhB,GACEF,GAASG,EACT,EAAEE,QACK,KAAK,MAAM,KAAK,IAAIL,CAAK,EAAIM,CAAC,EAAIA,GAAKH,GAAUE,EAAID,EAAM,OAAS,GAE7E,OAAOJ,EAAM,QAAQE,CAAE,EAAI,IAAME,EAAMC,CAAC,CAC1C,CCnBO,SAASE,GAAkBC,EAAwB,CACxD,IAAMC,EAAM,CAAC,EACPC,EAAQ,mBACd,QAASC,EAAI,EAAGA,EAAIH,EAAQG,IAC1BF,EAAI,KAAKC,EAAM,KAAK,MAAM,KAAK,OAAO,EAAIA,EAAM,MAAM,CAAC,CAAC,EAE1D,OAAOD,EAAI,KAAK,EAAE,CACpB,CCDO,IAAMG,GAA6CC,GACxD,QAAQ,WAAWA,CAAQ,EAAE,KAAMC,GACjCA,EACG,OAAQC,GAAWA,EAAO,SAAW,WAAW,EAChD,IAAKA,GAAYA,EAA8C,KAAK,CACzE,EACK,SAASC,GAAWC,EAAuB,CAChD,GAAIA,IAAU,EAAG,MAAO,UACxB,IAAMC,EAAI,KACJC,EAAQ,CAAC,QAAS,KAAM,KAAM,KAAM,IAAI,EACxCC,EAAI,KAAK,MAAM,KAAK,IAAIH,CAAK,EAAI,KAAK,IAAIC,CAAC,CAAC,EAElD,MAAO,IADMD,EAAQ,KAAK,IAAIC,EAAGE,CAAC,GACnB,QAAQ,CAAC,CAAC,IAAID,EAAMC,CAAC,CAAC,EACvC,CChBO,IAAMC,GAAN,KAAqB,CAG1B,YAAYC,EAAgB,CAC1B,KAAK,GAAKA,GAAOC,GAAiB,QAAQ,CAC5C,CAEA,OAAOD,EAA+B,CAIpC,MAHI,CAACA,GAGD,EAAEA,aAAe,KAAK,aACjB,GAEFA,EAAI,QAAQ,IAAM,KAAK,EAChC,CAEA,UAAW,CACT,OAAO,OAAO,KAAK,EAAE,CACvB,CAEA,SAAoB,CAClB,OAAO,KAAK,EACd,CACF,ECJO,IAAeE,GAAf,KAA2B,CAMhC,YAAYC,EAAoC,CAC9CC,EACED,EACA,IAAIE,EAA6B,wCAAwC,CAC3E,EACAD,EACED,EAAY,WAAaA,EAAY,UAAU,UAC/C,IAAIE,EAA6B,uDAAuD,CAC1F,EACA,KAAK,GAAK,IAAIC,GAAeC,GAAiB,IAAI,CAAC,EACnD,KAAK,YAAcJ,EAAY,YAC/B,KAAK,UAAY,CACf,cAAeA,GAAa,WAAW,cACvC,YAAaA,GAAa,WAAW,YACrC,UAAWA,GAAa,WAAW,SACrC,CACF,CACF,EC9CA,IAAAK,GAA6F,mBAUtF,SAASC,GAAgBC,EAAwD,CACtF,IAAMC,KAAU,GAAAC,SAAuBF,CAAG,EAE1C,OAAAC,EAAQ,UAAY,eAAgBE,EAAMC,EAAO,CAC/C,IAAMC,EAAW,KAAK,IAAI,IAAIF,CAAI,EAClC,GAAIE,EACF,QAAWC,KAAWD,EACpB,MAAMC,EAAQF,CAAK,EAIvB,IAAMG,EAAmB,KAAK,IAAI,IAAI,GAAG,EACzC,GAAIA,EACF,QAAWD,KAAWC,EACpB,MAAMD,EAAQH,EAAMC,CAAK,CAG/B,EAEOH,CACT,CAEO,IAAMA,GAAUF,GAAgB,EChCvC,IAAAS,EAAAC,GAAAC,GAcsBC,GAAf,MAAeA,EAAmB,CAGvC,YAAYC,EAAgC,CAHvCC,EAAA,KAAAL,GAIHM,EAAA,KAAKN,EAAAC,IAAL,UAAoBG,GACpB,KAAK,SAASA,CAAK,EACnB,KAAK,MAAQA,CACf,CAGA,OAAO,cAAcG,EAA2C,CAC9D,OAAOA,aAAeJ,EACxB,CAEA,OAAOK,EAAyB,CAC9B,OAAKA,EACE,KAAK,UAAU,IAAI,IAAM,KAAK,UAAUA,CAAE,EADjC,EAElB,CAKA,KAAM,CACJ,GAAIF,EAAA,KAAKN,EAAAE,IAAL,UAAwB,KAAK,OAC/B,OAAO,KAAK,MAAM,MAEpB,IAAMO,EAAQC,GAAqB,KAAK,KAAK,EAC7C,OAAO,OAAO,OAAOD,CAAK,CAC5B,CAaF,EAzCOT,EAAA,YA8BLC,GAAc,SAACG,EAAgC,CAC7CO,EACE,EAAEC,EAAQR,CAAK,GAAME,EAAA,KAAKN,EAAAE,IAAL,UAAwBE,IAAUQ,EAAQR,CAAK,GACpE,IAAIS,EAA6B,0BAA0B,CAC7D,CACF,EAEAX,GAAkB,SAACK,EAAmE,CACpF,MAAI,SAAO,UAAU,eAAe,KAAKA,EAAK,OAAO,CAEvD,EAxCK,IAAeO,EAAfX,GCXP,SAASY,GAASC,EAAsC,CAMtD,OAAIA,IAAQ,MAAQ,OAAOA,GAAQ,SAC1B,GAIP,OAAO,UAAU,eAAe,KAAKA,EAAK,UAAU,GACpD,OAAO,UAAU,eAAe,KAAKA,EAAK,IAAI,GAC9CC,EAAY,cAAeD,EAAwB,EAAE,CAEzD,CAEA,SAASE,GAAqBC,EAAgB,CAC5C,OAAIF,EAAY,cAAcE,CAAI,EACzBA,EAAK,IAAI,EAEdJ,GAASI,CAAI,EACRA,EAAK,SAAS,EAEhBA,CACT,CAOO,SAASC,GAAqBC,EAAiB,CACpD,IAAMC,EAAY,gBAAgBD,CAAK,EAGvC,QAAWE,KAAQD,EACb,MAAM,QAAQA,EAAUC,CAAI,CAAC,IAC/BD,EAAUC,CAAI,EAAKD,EAAUC,CAAI,EAAqB,IAAKJ,GAClDD,GAAqBC,CAAI,CACjC,GAEHG,EAAUC,CAAI,EAAIL,GAAqBI,EAAUC,CAAI,CAAC,EAGxD,OAAOD,CACT,CCjDA,IAAAE,GAAAC,EAAAC,EAAAC,EAAAC,GAAAC,GAqBsBC,GAAf,MAAeA,EAAc,CAMlC,YAAY,CAAE,GAAAC,EAAI,MAAAC,EAAO,UAAAC,EAAW,UAAAC,CAAU,EAA6B,CANtEC,EAAA,KAAAP,IACLO,EAAA,KAAAX,IACAW,EAAA,KAASV,GACTU,EAAA,KAAST,GACTS,EAAA,KAAAR,GAGES,EAAA,KAAKZ,GAAMO,GACXM,EAAA,KAAKT,GAAAC,IAAL,UAAoBG,GACpB,IAAMM,EAAM,IAAI,KAChBF,EAAA,KAAKX,EAAaQ,GAAaK,GAC/BF,EAAA,KAAKT,EAAaO,GAAaI,GAC/BF,EAAA,KAAKV,EAASM,GACd,KAAK,SAAS,CAChB,CAEA,OAAO,SAASO,EAA4C,CAC1D,OAAOA,aAAkBT,EAC3B,CAEA,IAAI,IAAqB,CACvB,OAAOU,EAAA,KAAKhB,GACd,CAEA,IAAI,WAAkB,CACpB,OAAOgB,EAAA,KAAKf,EACd,CAEA,IAAI,WAAkB,CACpB,OAAOe,EAAA,KAAKb,EACd,CAEA,UAAoC,CAClC,IAAMc,EAAQ,CACZ,GAAI,KAAK,GACT,UAAWD,EAAA,KAAKf,GAChB,UAAWe,EAAA,KAAKb,GAChB,GAAGa,EAAA,KAAKd,EACV,EACA,OAAO,OAAO,OAAOe,CAAK,CAC5B,CAEU,iBAAyB,CACjC,OAAOD,EAAA,KAAKd,EACd,CAOA,UAAW,CACT,IAAMe,EAAQC,GAAqB,KAAK,SAAS,CAAC,EAE5CC,EAAS,CACb,GAAI,KAAK,GACT,UAAWH,EAAA,KAAKf,GAChB,UAAWe,EAAA,KAAKb,GAChB,GAAGc,CACL,EACA,OAAO,OAAO,OAAOE,CAAM,CAC7B,CAqBF,EAjFEnB,GAAA,YACSC,EAAA,YACAC,EAAA,YACTC,EAAA,YAJKC,GAAA,YAoELC,GAAc,SAACG,EAAc,CAE3BY,EAAU,CAACC,EAAQb,CAAK,EAAG,IAAIc,EAA6B,kCAAkC,CAAC,EAC/FF,EACE,OAAOZ,GAAU,SACjB,IAAIe,EAAyB,kCAAkC,CACjE,EACAH,EACE,OAAO,KAAKZ,CAAY,EAAE,QAAU,GACpC,IAAIgB,GACF,wDACF,CACF,CACF,EAjFK,IAAeC,GAAfnB,GCrBP,IAAAoB,EAKsBC,GAAf,cAA4CC,EAAc,CAA1D,kCAELC,EAAA,KAAAH,EAA+B,CAAC,GAEhC,IAAI,cAAuC,CACzC,OAAOI,EAAA,KAAKJ,EACd,CAEU,SAASK,EAA0C,CACvD,MAAM,QAAQA,CAAK,EACrBD,EAAA,KAAKJ,GAAc,KAAK,GAAGK,CAAK,EAEhCD,EAAA,KAAKJ,GAAc,KAAKK,CAAK,CAEjC,CAEA,aAAoB,CAClBC,EAAA,KAAKN,EAAgB,CAAC,EACxB,CAOA,MAAM,cAAcO,EAAoBC,EAAwB,CAC9D,QAAWH,KAASD,EAAA,KAAKJ,GAAe,CAEtC,IAAMS,EAAYJ,EAAM,UACxBE,EAAO,MACL,gBAAgBE,CAAS,mCAAmC,KAAK,YAAY,IAAI,MAAM,KAAK,EAAE,EAChG,EACA,QAAQ,IACN,gBAAgBA,CAAS,mCAAmC,KAAK,YAAY,IAAI,MAAM,KAAK,EAAE,EAChG,EAEIA,EACFD,EAAQ,KAAKC,EAAWJ,CAAY,EAEpCE,EAAO,MAAM,0BAA0BE,CAAS,0CAA+B,CAEnF,CAEA,KAAK,YAAY,CACnB,CACF,EA3CET,EAAA,YCPK,SAASU,GAAeC,EAA0B,CACvD,IAAMC,EAAUD,EAAQ,WAAW,IAAI,EAAIA,EAAQ,MAAM,CAAC,EAAIA,EAC9D,MAAO,oBAAoB,KAAKC,CAAO,CACzC,CACO,SAASC,GAAiBC,EAA4B,CAC3D,IAAMF,EAAUE,EAAU,WAAW,IAAI,EAAIA,EAAU,MAAM,CAAC,EAAIA,EAClE,MAAO,wBAAwB,KAAKF,CAAO,CAC7C,CCPA,IAAAG,GAAqC,mCAE/BC,GAAa,qEAEfC,GAAiC,KAE/BC,GAAe,SACfD,KACJA,GAAkBD,GACXC,IAGHE,GAAS,MAAOC,GAAsC,CAC1D,GAAIA,EAAK,SAAW,EAClB,OAAO,MAAMF,GAAa,EAG5B,IAAMG,EAAsB,MAAM,KAAKD,CAAI,EAC3C,GAAI,CACF,GAAM,CAAE,KAAAE,CAAK,EAAK,QAAM,yBAAqB,CAC3C,OAAQD,CACV,CAAC,EACD,OAAOC,CACT,OAASC,EAAO,CACd,eAAQ,MAAM,kBAAmBA,CAAK,EACtC,QAAQ,IAAI,yBAA0BF,CAAmB,EAClD,EACT,CACF,EAEMG,EAAcC,GAA4B,CAC9C,IAAMC,EAAWD,EAAI,WAAW,IAAI,EAAIA,EAAI,MAAM,CAAC,EAAIA,EACvD,GAAIC,EAAS,SAAW,EAAG,OAAO,IAAI,WAAW,CAAC,EAElD,IAAMC,EAAQ,IAAI,WAAWD,EAAS,OAAS,CAAC,EAChD,QAASE,EAAI,EAAGA,EAAIF,EAAS,OAAQE,GAAK,EACxCD,EAAMC,EAAI,CAAC,EAAI,SAASF,EAAS,OAAOE,EAAG,CAAC,EAAG,EAAE,EAEnD,OAAOD,CACT,EAEME,GAAkBC,GAClBA,GAAK,EAAU,GACnBA,IACAA,GAAKA,GAAK,EACVA,GAAKA,GAAK,EACVA,GAAKA,GAAK,EACVA,GAAKA,GAAK,EACVA,GAAKA,GAAK,GACHA,EAAI,GAGAC,GAAwB,MACnCC,GAC4C,CAC5C,IAAMC,EAAYD,EAAO,OAEzB,GAAIC,IAAc,EAAG,CACnB,IAAMC,EAAQ,MAAMhB,GAAa,EACjC,MAAO,CAAC,CAAC,EAAGgB,EAAO,CAAC,CAAC,CACvB,CAEA,IAAMC,EAAQN,GAAeI,CAAS,EAChCG,EAAmB,IAAI,MAAMD,CAAK,EAClCE,EAAY,MAAMnB,GAAa,EAE/BoB,EAAa,MAAM,QAAQ,IAAIN,EAAO,IAAIb,EAAM,CAAC,EAEvD,QAASS,EAAI,EAAGA,EAAIO,EAAOP,IACzBQ,EAAOR,CAAC,EAAIA,EAAIK,EAAYK,EAAWV,CAAC,EAAKS,EAI/C,IAAME,EAAqB,CAACH,CAAM,EAC9BI,EAAQJ,EACZ,KAAOI,EAAM,OAAS,GAAG,CACvB,IAAMC,EAAsB,CAAC,EAE7B,QAASb,EAAI,EAAGA,EAAIY,EAAM,OAAQZ,GAAK,EAAG,CACxC,IAAMc,EAAUF,EAAMZ,CAAC,EACjBe,EAAWH,EAAMZ,EAAI,CAAC,GAAKS,EAE3BO,EAAYpB,EAAWkB,CAAO,EAC9BG,EAAarB,EAAWmB,CAAQ,EAEhCG,EAAW,IAAI,WAAW,EAAE,EAClCA,EAAS,IAAIF,EAAW,CAAC,EACzBE,EAAS,IAAID,EAAY,EAAE,EAE3B,IAAME,EAAS,MAAM5B,GAAO2B,CAAQ,EACpCL,EAAU,KAAKM,CAAM,CACvB,CAEAR,EAAO,KAAKE,CAAS,EACrBD,EAAQC,CACV,CAEA,MAAO,CAACL,EAAQI,EAAM,CAAC,EAAID,CAAM,CACnC,EAOaS,GAAuB,MAClCT,EACAU,IACsB,CACtB,IAAMC,EAAkB,CAAC,EACrBC,EAAMF,EAEJZ,EAAY,MAAMnB,GAAa,EAGrC,QAASkC,EAAW,EAAGA,EAAWb,EAAO,OAAS,EAAGa,IAAY,CAC/D,IAAMZ,EAAQD,EAAOa,CAAQ,EAEvBC,EADSF,EAAM,IAAM,EACCA,EAAM,EAAIA,EAAM,EAEtCG,EAAcD,EAAab,EAAM,OAASA,EAAMa,CAAU,EAAKhB,EACrEa,EAAM,KAAKI,CAAW,EAEtBH,EAAM,KAAK,MAAMA,EAAM,CAAC,CAC1B,CAEA,OAAOD,CACT,EAEaK,GAAoB,MAC/BC,EACAN,EACAO,EACAR,IACqB,CACrB,IAAI3B,EAAOkC,EAEX,QAAS,EAAI,EAAG,EAAIN,EAAM,OAAQ,IAAK,CACrC,IAAMQ,EAAUR,EAAM,CAAC,EACjBS,GAAUV,GAAS,GAAK,IAAM,EAE9BL,EAAqBpB,EAATmC,EAAoBrC,EAAmBoC,CAAf,EACpCb,EAAsBrB,EAATmC,EAAoBD,EAAsBpC,CAAf,EAExCwB,EAAW,IAAI,WAAW,EAAE,EAClCA,EAAS,IAAIF,EAAW,CAAC,EACzBE,EAAS,IAAID,EAAY,EAAE,EAE3BvB,EAAO,MAAMH,GAAO2B,CAAQ,CAC9B,CAEA,OAAOxB,IAASmC,CAClB,EC9IO,IAAMG,GAAN,KAAwB,CAC7B,YACmBC,EACAC,EACjB,CAFiB,8BAAAD,EACA,2BAAAC,CAChB,CAEH,MAAM,QAAQC,EAA+D,CAC3E,GAAM,CAAE,KAAAC,EAAM,KAAAC,EAAM,UAAAC,EAAY,KAAO,GAAI,EAAIH,EAE/CI,EAAO,KAAK,uBAAwB,CAAE,SAAUH,EAAK,KAAM,UAAAE,EAAW,KAAAD,CAAK,CAAC,EAG5E,IAAMG,EAAc,MAAMJ,EAAK,YAAY,EACrCK,EAAS,IAAI,WAAWD,CAAW,EACnCE,EAAuB,CAAC,EAE9B,QAASC,EAAI,EAAGA,EAAIF,EAAO,OAAQE,GAAKL,EACtCI,EAAO,KAAKD,EAAO,MAAME,EAAGA,EAAIL,CAAS,CAAC,EAG5CC,EAAO,KAAK,mBAAmBG,EAAO,MAAM,SAAS,EAGrD,GAAM,CAACE,EAAQC,EAAYC,CAAU,EAAI,MAAMC,GAAsBL,CAAM,EAC3EH,EAAO,KAAK,oBAAqB,CAAE,WAAAM,EAAY,YAAaD,EAAO,MAAO,CAAC,EAG3E,IAAMI,EAAY,MAAM,KAAK,yBAAyB,eAAe,CACnE,KAAAX,EACA,UAAWK,EAAO,MACpB,CAAC,EAEDH,EAAO,KAAK,mBAAoB,CAAE,MAAOS,CAAU,CAAC,EAGpD,IAAMC,EAAUb,EAAK,KAAK,SAAS,GAAG,EAAIA,EAAK,KAAK,MAAM,GAAG,EAAE,IAAI,EAAK,GAClEc,EAAa,KAAK,MAAM,KAAK,IAAI,EAAI,GAAI,EAAI,IAAM,GAAK,GAAK,GAE7D,CAAE,QAAAC,CAAQ,EAAI,MAAM,KAAK,yBAAyB,aAAa,CACnE,KAAAd,EACA,KAAM,CACJ,MAAOA,EACP,WAAAQ,EACA,WAAYJ,EAAO,OACnB,YAAaC,EAAO,OACpB,WAAAQ,EACA,KAAMd,EAAK,KACX,IAAKa,EACL,mBAAoB,SACpB,UAAWJ,EACX,OAAQ,CACV,EACA,MAAOG,CACT,CAAC,EAEDT,EAAO,KAAK,2BAA4B,CAAE,QAAAY,CAAQ,CAAC,EAGnD,IAAMC,EAAiBV,EAAO,IAAI,MAAOW,EAAOV,IAAM,CACpD,IAAMW,GAAWV,EAAOD,CAAC,EAEnBY,GAAQ,MAAMC,GAAqBV,EAAYH,CAAC,EAItD,GAAI,CADiB,MAAMc,GAAkBH,GAAUC,GAAOV,EAAYF,CAAC,EAEzE,MAAM,IAAI,MACR,2BAA2BA,CAAC,WAAWW,EAAQ,oBAAoBT,CAAU,EAC/E,EAIF,IAAMa,GACJ,KACA,MAAM,KAAKL,CAAK,EACb,IAAKM,IAAMA,GAAE,SAAS,EAAE,EAAE,SAAS,EAAG,GAAG,CAAC,EAC1C,KAAK,EAAE,EAGZ,aAAM,KAAK,yBAAyB,YAAY,CAC9C,KAAAtB,EACA,QAAAc,EACA,UAAWO,GACX,WAAYf,EACZ,YAAaY,EACf,CAAC,EAEM,CAAE,WAAYZ,EAAG,QAAS,EAAK,CACxC,CAAC,EAQD,GALA,MAAM,QAAQ,IAAIS,CAAc,EAEhCb,EAAO,KAAK,OAAOG,EAAO,MAAM,+BAA+B,EAG3D,KAAK,sBAAuB,CAC9BH,EAAO,KAAK,qCAAsC,CAAE,QAAAY,CAAQ,CAAC,EAC7D,GAAI,CACF,IAAMS,EAAY,MAAM,KAAK,sBAAsB,qBAAqBT,EAAS,GAAK,EACtFZ,EAAO,KAAK,+BAAgC,CAC1C,QAASqB,EAAU,QACnB,KAAMA,EAAU,IAClB,CAAC,CACH,OAASC,EAAO,CACd,MAAAtB,EAAO,MAAM,0CAA2CsB,CAAK,EACvD,IAAI,MACR,0DAA0DA,aAAiB,MAAQA,EAAM,QAAU,eAAe,EACpH,CACF,CACF,MACEtB,EAAO,KAAK,uEAAuE,EAGrF,MAAO,CACL,QAAAY,EACA,WAAAN,EACA,YAAaH,EAAO,MACtB,CACF,CACF,ECpHA,IAAAoB,EAAyE,mCAIzE,IAAMC,GAAO,kBAGPC,GAAc,EACdC,GAAiB,IAGjBC,GAAN,KAAY,CAAZ,cACE,KAAQ,MAAQ,QAAQ,QAAQ,EAEhC,MAA4B,CAC1B,IAAIC,EAAuCC,GAAY,CAAC,EACxD,YAAK,MAAQ,KAAK,MAAM,KAAK,IAAM,IAAI,QAAQD,CAAK,CAAC,EAC9C,IAAI,QAASE,GAAQ,CAC1BF,EAAQE,CACV,CAAC,CACH,CACF,EACMC,GAAgB,IAAIJ,GA0BbK,GAAN,cAA8B,KAAM,CACzC,YACSC,EACAC,EACAC,EACPC,EACA,CACA,MAAMA,GAAWH,CAAI,EALd,UAAAA,EACA,eAAAC,EACA,kBAAAC,CAIT,CACF,EAKA,SAASE,GAAmBC,EAA+C,CACzE,GAAM,CAACC,EAAIC,CAAO,EAAIF,EAAQ,MAAM,GAAG,EACvC,GAAI,CAACC,GAAM,CAACC,EACV,MAAM,IAAI,MAAM,kCAAkCF,CAAO,EAAE,EAE7D,IAAMG,EAAO,SAASD,EAAS,EAAE,EACjC,GAAI,MAAMC,CAAI,EACZ,MAAM,IAAI,MAAM,4BAA4BH,CAAO,EAAE,EAEvD,MAAO,CAAE,GAAAC,EAAI,KAAAE,CAAK,CACpB,CAGA,IAAMC,EAAyC,CAAC,EAMhD,eAAeC,GAAgBC,EAAmC,CAChE,GAAM,CAAE,GAAAL,EAAI,KAAAE,CAAK,EAAIJ,GAAmBO,CAAU,EAC7CF,EAAeE,CAAU,GAK5BF,EAAeE,CAAU,IACzB,QAAQ,IACN,WAAWA,CAAU,kCAAkCF,EAAeE,CAAU,CAAC,GACnF,IAPA,QAAM,qBAAkBL,EAAIE,EAAMjB,EAAI,EACtCkB,EAAeE,CAAU,EAAI,EAC7B,QAAQ,IAAI,WAAWA,CAAU,gCAAgC,EAOrE,CAKA,eAAeC,GAAiBD,EAAmC,CACjE,GAAM,CAAE,GAAAL,EAAI,KAAAE,CAAK,EAAIJ,GAAmBO,CAAU,EAClD,GAAI,CACEF,EAAeE,CAAU,GAAKF,EAAeE,CAAU,EAAI,IAC7DF,EAAeE,CAAU,IACzB,QAAQ,IACN,WAAWA,CAAU,sCAAsCF,EAAeE,CAAU,CAAC,GACvF,EACIF,EAAeE,CAAU,IAAM,IACjC,QAAQ,IAAI,0BAA0B,EACtC,QAAQ,KAAK,IACX,wBAAqBL,EAAIE,EAAMjB,EAAI,EACnC,IAAI,QAASsB,GAAY,WAAWA,EAAS,GAAI,CAAC,CACpD,CAAC,EAAE,MAAOC,GAAQ,QAAQ,KAAK,WAAWH,CAAU,sBAAuBG,CAAG,CAAC,EAE/E,OAAOL,EAAeE,CAAU,EAChC,QAAQ,IAAI,WAAWA,CAAU,gBAAgB,GAGvD,OAASI,EAAO,CACd,QAAQ,KAAK,WAAWJ,CAAU,sBAAuBI,CAAK,CAEhE,CACF,CAMA,eAAeC,GACbL,EACAM,EACAC,EACAC,EACAC,EACAC,EACoD,CACpD,GAAM,CAAE,GAAAf,EAAI,KAAAE,CAAK,EAAIJ,GAAmBO,CAAU,EAK5CW,EAAgC,CACpC,QAAS,uBACT,UALgB,GAAGL,CAAO,IAAIE,CAAU,IAAI,KAAK,IAAI,CAAC,GAMtD,WAAAA,EACA,YAAAC,EACA,QAAS,CACP,SAAUH,EACV,aAAcC,EACd,YAAaC,EACb,UAAWE,CACb,CACF,EAEME,EAAiB,KAAK,UAAUD,CAAO,EAAI;AAAA,EAE3CE,EAAgB,QAAM,mBAAgBlB,EAAIE,EAAMjB,GAAMgC,CAAc,EAE1E,GACEC,GACA,OAAOA,GAAa,UACpB,YAAaA,GACbA,EAAS,UAAY,GAErB,MAAM,IAAIzB,GACRyB,EAAS,MAAQ,oBACjBA,EAAS,YAAc,GACvBA,EAAS,aACTA,EAAS,OACX,EAIF,IAAIC,EACJ,GAAI,CACF,GAAI,OAAOD,GAAa,SACtBC,EAAO,KAAK,MAAMD,CAAQ,UACjB,OAAOA,GAAa,UAAYA,IAAa,KACtDC,EAAOD,MAEP,OAAM,IAAI,MAAM,0BAA0B,OAAOA,CAAQ,EAAE,CAE/D,MAAqB,CACnB,MAAM,IAAI,MAAM,iCAAiC,CACnD,CAOA,GALA,QAAQ,IAAI,UAAUL,CAAU,oBAAqB,CACnD,OAAQM,EAAK,OACb,QAAS,CAAC,CAACA,EAAK,iBAClB,CAAC,EAEGA,EAAK,SAAW,UAAW,CAC7B,IAAMC,EAAeD,EAAK,SAAW,gBACrC,MAAM,IAAI,MAAMC,CAAY,CAC9B,CAEA,GAAI,CAACD,EAAK,kBACR,MAAM,IAAI,MAAM,2BAA2B,EAG7C,IAAME,EAAaF,EAAK,kBAClBG,EAAe,KAAKD,CAAU,EAC9BE,EAAQ,IAAI,WAAWD,EAAa,MAAM,EAChD,QAASE,EAAI,EAAGA,EAAIF,EAAa,OAAQE,IACvCD,EAAMC,CAAC,EAAIF,EAAa,WAAWE,CAAC,EAKtC,MAAO,CAAE,WAFgB,OAAOL,EAAK,YAAe,SAAWA,EAAK,WAAaN,EAE1C,MAAAU,CAAM,CAC/C,CAMA,eAAeE,GAAmBC,EAAiC,CACjE,GAAI,CACF,IAAMC,EAAY,MAAMC,EAAyB,uBAAuB,CAAE,KAAAF,CAAK,CAAC,EAEhF,GAAI,CAACC,GAAaA,EAAU,SAAW,EACrC,MAAM,IAAI,MAAM,8CAA8C,EAGhE,GAAIA,EAAU,OAAS,EACrB,MAAM,IAAI,MAAM,oCAAoCA,EAAU,MAAM,mBAAmB,EAGzF,eAAQ,IAAI,oCAAqCA,CAAS,EACnDA,CACT,OAASlB,EAAO,CACd,IAAMW,EAAeX,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,EAC1E,MAAM,IAAI,MAAM,wDAAwDW,CAAY,EAAE,CACxF,CACF,CAMA,SAASS,GAAkBhB,EAAoBiB,EAAmC,CAChF,IAAMC,EAAclB,EAAa,EACjC,GAAI,CAACiB,EAAgBC,CAAW,EAC9B,MAAM,IAAI,MAAM,4CAA4ClB,CAAU,EAAE,EAE1E,OAAOiB,EAAgBC,CAAW,CACpC,CAKA,eAAsBC,GACpBrB,EACAC,EACAC,EACAC,EACAC,EACAe,EACmD,CACnD,IAAMzB,EAAawB,GAAkBhB,EAAYiB,CAAe,EAC1DG,EAASpB,EAAa,IAAM,EAElC,QAAQ,IACN,UAAUA,CAAU,qBAAqBoB,EAAS,WAAa,UAAU,KAAK5B,CAAU,GAC1F,EAGA,IAAI6B,EAA0B,KAE9B,QAASC,EAAU,EAAGA,EAAUjD,GAAaiD,IAC3C,GAAI,CACF,IAAMC,EAAS,MAAM1B,GACnBL,EACAM,EACAC,EACAC,EACAC,EACAC,CACF,EACA,MAAO,CAAE,WAAYqB,EAAO,WAAY,KAAMA,EAAO,KAAM,CAC7D,OAAS3B,EAAO,CAGd,GAFAyB,EAAYzB,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EAEhEyB,aAAqBzC,GAAiB,CACxC,GAAI,CAACyC,EAAU,UACb,MAAMA,EAGR,IAAMG,EAAQH,EAAU,cAAgB/C,GACxC,QAAQ,KACN,UAAU0B,CAAU,wBAAwBqB,EAAU,IAAI,oBAAoBG,CAAK,OACrF,EACA,MAAM,IAAI,QAAS9B,GAAY,WAAWA,EAAS8B,CAAK,CAAC,EACzD,QACF,CAKA,GAHqBH,EAAU,QAAQ,YAAY,EAGlC,SAAS,wBAAwB,EAChD,cAAQ,IAAI,UAAUrB,CAAU,6CAA6C,EACvEqB,EAGR,QAAQ,KACN,UAAUrB,CAAU,qBAAqBsB,EAAU,CAAC,IAAIjD,EAAW,WACnEgD,EAAU,OACZ,EAEIC,EAAUjD,GAAc,GAE1B,MAAM,IAAI,QAASqB,GAAY,WAAWA,EAASpB,EAAc,CAAC,CAEtE,CAIF,MAAM,IAAI,MACR,UAAU0B,CAAU,wBAAwB3B,EAAW,uBAAagD,GAAW,OAAO,EACxF,CACF,CAiBA,eAAsBI,GACpB3B,EACAC,EACAE,EACAC,EACAW,EACAa,EACuB,CACvB,QAAQ,IAAI,wBAAwBzB,CAAW,YAAY,EAG3D,IAAMgB,EAAkB,MAAML,GAAmBC,CAAI,EACrD,GAAII,EAAgB,OAAS,EAC3B,MAAM,IAAI,MAAM,qDAAqD,EAGvE,IAAMU,EAAcV,EAAgB,CAAC,EAC/BW,EAAcX,EAAgB,CAAC,EAErC,QAAQ,IAAI,kBAAkBU,CAAW,KAAKC,CAAW,EAAE,EAG3D,MAAM,QAAQ,IAAI,CAACrC,GAAgBoC,CAAW,EAAGpC,GAAgBqC,CAAW,CAAC,CAAC,EAE9E,IAAMC,EAAU,IAAI,MAAkB5B,CAAW,EAC7C6B,EAAY,EACZC,EAAa,EAEXC,EAAc,EAEpB,eAAeC,GAAS,CACtB,OAAa,CACX,IAAMjC,EAAa8B,IACnB,GAAI9B,GAAcC,EAAa,OAE/B,IAAMsB,EAAS,MAAMJ,GACnBrB,EACAC,EACAC,EACAC,EACAC,EACAe,CACF,EAEAY,EAAQN,EAAO,UAAU,EAAIA,EAAO,KACpCQ,IAEAL,IAAaK,EAAY9B,CAAW,CACtC,CACF,CAEA,GAAI,CACF,aAAM,QAAQ,IAAI,MAAM,KAAK,CAAE,OAAQ+B,CAAY,EAAG,IAAMC,EAAO,CAAC,CAAC,EAErE,QAAQ,IAAI,kBAAkBF,CAAU,sBAAsB,EACvDF,CACT,QAAE,CAEA,MAAM,QAAQ,IAAI,CAACpC,GAAiBkC,CAAW,EAAGlC,GAAiBmC,CAAW,CAAC,CAAC,CAClF,CACF,CAYA,eAAsBM,GACpBpC,EACAC,EACAE,EACAC,EACAW,EACAa,EACqB,CACrB,IAAMS,EAAS,MAAMxD,GAAc,KAAK,EACxC,GAAI,CACF,IAAMyD,EAAS,MAAMX,GACnB3B,EACAC,EACAE,EACAC,EACAW,EACAa,CACF,EAGMW,EAAcD,EAAO,OAAO,CAACE,EAAKC,IAAUD,EAAMC,EAAM,OAAQ,CAAC,EACjEC,EAAS,IAAI,WAAWH,CAAW,EAErCI,EAAS,EACb,QAAWF,KAASH,EAClBI,EAAO,IAAID,EAAOE,CAAM,EACxBA,GAAUF,EAAM,OAGlB,eAAQ,IAAI,qBAAqBC,EAAO,MAAM,QAAQ,EAE/CA,CACT,QAAE,CACAL,EAAO,CACT,CACF,CCzcA,IAAAO,GAA2C,mCAM3C,eAAsBC,GAAkBC,EAAqBC,EAAqC,CAChG,GAAI,CAMF,IAAMC,EAAoB,OAJDF,EAAY,WAAW,IAAI,EAAIA,EAAY,MAAM,CAAC,EAAIA,CAI9B,GAI3CG,EAAO,QAAM,eAAWD,EAAmB,EAAK,EAGhD,CAAE,KAAAE,CAAK,EAAI,QAAM,mBAAe,CACpC,QAASD,EACT,WAAAF,EACA,KAAAE,CACF,CAAC,EACD,OAAOC,CACT,OAASC,EAAO,CACd,cAAQ,MAAM,8BAA+BA,CAAK,EAC5C,IAAI,MAAM,+CAA+C,CACjE,CACF,CCzBA,IAAAC,GAAoC,mCAE9BC,GAAN,KAAY,CAAZ,cACE,KAAQ,MAAQ,QAAQ,QAAQ,EAEhC,MAA4B,CAC1B,IAAIC,EAAuCC,GAAY,CAAC,EAExD,YAAK,MAAQ,KAAK,MAAM,KAAK,IACpB,IAAI,QAAQD,CAAK,CACzB,EAEM,IAAI,QAASE,GAAQ,CAC1BF,EAAQE,CACV,CAAC,CACH,CACF,EAEMC,GAAe,IAAIJ,GAaZK,GAAN,KAA0B,CAC/B,YACmBC,EACAC,EACjB,CAFiB,8BAAAD,EACA,yBAAAC,CAChB,CAEH,MAAM,QAAQC,EAAmE,CAC/E,GAAM,CAAE,QAAAC,EAAS,KAAAC,EAAM,cAAAC,EAAgB,CAAE,EAAIH,EAE7CI,EAAO,KAAK,yBAA0B,CAAE,QAAAH,EAAS,KAAAC,CAAK,CAAC,EAGvD,IAAMG,EAAW,MAAM,KAAK,yBAAyB,YAAY,CAC/D,KAAAH,EACA,QAAAD,CACF,CAAC,EAEDG,EAAO,KAAK,sBAAuB,CACjC,KAAMC,EAAS,KACf,YAAaA,EAAS,YACtB,OAAQA,EAAS,MACnB,CAAC,EAGD,IAAMC,EAAgB,MAAM,KAAK,yBAAyB,eAAe,CACvE,KAAAJ,EACA,UAAW,CAACG,EAAS,WACvB,CAAC,EAEDD,EAAO,KAAK,4BAA6B,CAAE,MAAOE,CAAc,CAAC,EAGjE,IAAMC,EAAS,MAAMX,GAAa,KAAK,EACvC,GAAI,CACF,MAAM,KAAK,yBAAyB,eAAe,CACjD,KAAAM,EACA,QAAAD,EACA,cAAAE,EACA,MAAOG,CACT,CAAC,CACH,QAAE,CACAC,EAAO,CACT,CAEAH,EAAO,KAAK,gDAAgD,EAG5D,GAAM,CAAE,YAAAI,CAAY,EAAI,MAAM,KAAK,oBAAoB,eAAeP,CAAO,EAEvEQ,EAAa,QAAM,wBAAoBP,CAAI,EACjD,GAAI,CAACO,EACH,MAAM,IAAI,MAAM,4DAA4D,EAG9E,IAAMC,EAAY,MAAMC,GAAkBH,EAAaC,CAAU,EAE3DG,EAAW,MAAMC,GACrBZ,EACAO,EACAH,EAAS,YACTK,EACAR,EACA,CAACY,EAAYC,IAAU,CACrBX,EAAO,KAAK,sBAAsBU,CAAU,IAAIC,CAAK,EAAE,CACzD,CACF,EAEA,OAAAX,EAAO,KAAK,6BAA8B,CAAE,KAAMQ,EAAS,MAAO,CAAC,EAE5D,CACL,SAAUA,EACV,SAAUP,EAAS,KACnB,QAASA,EAAS,KAAO,EAC3B,CACF,CACF,EC3GO,IAAMW,GAAN,KAA6B,CAClC,YAA6BC,EAAwD,CAAxD,8BAAAA,CAAyD,CAEtF,MAAM,QAAQC,EAAuF,CACnG,OAAAC,EAAO,KAAK,mCAAoC,CAAE,QAASD,EAAQ,QAAS,OAAQA,EAAQ,MAAO,CAAC,EAC7F,KAAK,yBAAyB,gBAAgB,CACnD,KAAMA,EAAQ,KACd,QAASA,EAAQ,QACjB,OAAQA,EAAQ,MAClB,CAAC,CACH,CACF,ECXO,IAAME,GAAN,KAA0B,CAC/B,YAA6BC,EAAwD,CAAxD,8BAAAA,CAAyD,CAEtF,MAAM,QAAQC,EAAiF,CAC7F,OAAAC,EAAO,KAAK,gCAAiC,CAAE,QAASD,EAAQ,QAAS,WAAYA,EAAQ,MAAM,MAAO,CAAC,EACpG,KAAK,yBAAyB,aAAa,CAChD,KAAMA,EAAQ,KACd,QAASA,EAAQ,QACjB,MAAOA,EAAQ,KACjB,CAAC,CACH,CACF,ECXO,IAAME,GAAN,KAA0B,CAC/B,YAA6BC,EAAwD,CAAxD,8BAAAA,CAAyD,CAEtF,MAAM,QAAQC,EAAiF,CAC7F,OAAAC,EAAO,KAAK,gCAAiC,CAAE,QAASD,EAAQ,OAAQ,CAAC,EAClE,KAAK,yBAAyB,aAAa,CAChD,KAAMA,EAAQ,KACd,QAASA,EAAQ,OACnB,CAAC,CACH,CACF,ECVO,IAAME,GAAN,KAA0B,CAC/B,YAA6BC,EAAwD,CAAxD,8BAAAA,CAAyD,CAEtF,MAAM,QAAQC,EAAiF,CAC7F,OAAAC,EAAO,KAAK,gCAAiC,CAAE,QAASD,EAAQ,OAAQ,CAAC,EAClE,KAAK,yBAAyB,aAAa,CAChD,KAAMA,EAAQ,KACd,QAASA,EAAQ,OACnB,CAAC,CACH,CACF,ECdA,IAAAE,EAAc,kBAEDC,GAA0B,EAAAC,QAAE,OAAO,CAC9C,KAAM,EAAAA,QAAE,WAAW,IAAI,EACvB,KAAM,EAAAA,QAAE,OAAO,EACf,UAAW,EAAAA,QACR,OAAO,EACP,SAAS,EACT,QAAQ,KAAO,GAAG,CACvB,CAAC,EAIYC,GAA2B,EAAAD,QAAE,OAAO,CAC/C,QAAS,EAAAA,QAAE,OAAO,EAClB,WAAY,EAAAA,QAAE,OAAO,EACrB,YAAa,EAAAA,QAAE,OAAO,CACxB,CAAC,ECjBD,IAAAE,EAAc,kBAEDC,GAA4B,EAAAC,QAAE,OAAO,CAChD,QAAS,EAAAA,QAAE,OAAO,EAClB,KAAM,EAAAA,QAAE,OAAO,EACf,cAAe,EAAAA,QAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAC,CAChD,CAAC,EAIYC,GAA6B,EAAAD,QAAE,OAAO,CACjD,SAAU,EAAAA,QAAE,WAAW,UAAU,EACjC,SAAU,EAAAA,QAAE,OAAO,EACnB,QAAS,EAAAA,QAAE,OAAO,CACpB,CAAC,ECKM,IAAME,EAAN,KAAgE,CAarE,aAAc,CAZd,KAAQ,aAA6C,IAAI,IACzD,KAAQ,gBAOJ,IAAI,IACR,KAAQ,YAAmC,KAC3C,KAAQ,cAAyB,GAG/B,KAAK,eAAe,CACtB,CAEA,MAAM,WAAWC,EAAqBC,EAAwC,CAC5E,GAAI,KAAK,cAAe,CACtBC,EAAO,KAAK,iDAAiD,EAC7D,MACF,CAEA,GAAI,CACF,MAAMC,EAAU,cAAcH,EAAaC,CAAe,EAC1D,KAAK,cAAgB,EACvB,OAASG,EAAO,CACd,MAAAF,EAAO,MAAM,mDAAoDE,CAAK,EAChEA,CACR,CACF,CAKQ,gBAAuB,CAC7B,KAAK,YAAcD,EAAU,SAAS,WAAYE,GAAe,CAC3DA,EAAM,OAAS,wBACjB,KAAK,2BAA2BA,EAAM,OAAO,CAEjD,CAAC,CACH,CAKQ,2BAA2BC,EAAoB,CACrD,GAAI,CACF,IAAMC,EAAU,KAAK,iBAAiBD,GAAS,OAAO,EAChDE,EAAcF,GAAS,aAAe,KACtCG,EAAOH,GAAS,MAAQ,GACxBI,EAASJ,GAAS,QAAU,IAElC,GAAI,CAACC,GAAW,CAACC,EAAa,CAC5BN,EAAO,KAAK,qDAAsD,CAAE,QAAAI,CAAQ,CAAC,EAC7E,MACF,CAEA,IAAMK,EAAwB,CAC5B,YAAAH,EACA,QAAAD,EACA,KAAAE,EACA,OAAAC,EACA,UAAW,KAAK,IAAI,CACtB,EAGA,KAAK,aAAa,IAAIH,EAASI,CAAI,EAGnC,IAAMC,EAAU,KAAK,gBAAgB,IAAIL,CAAO,EAC5CK,IACFA,EAAQ,QAAQ,CAAC,CAAE,QAAAC,EAAS,QAAAC,CAAQ,IAAM,CACxC,aAAaA,CAAO,EACpBD,EAAQF,CAAI,CACd,CAAC,EACD,KAAK,gBAAgB,OAAOJ,CAAO,EAEvC,OAASH,EAAO,CACdF,EAAO,MAAM,4CAA6CE,CAAK,CACjE,CACF,CAKQ,iBAAiBG,EAAmD,CAC1E,OAAKA,GACcA,EAAQ,YAAY,EAAE,WAAW,IAAI,EACpDA,EAAQ,YAAY,EAAE,MAAM,CAAC,EAC7BA,EAAQ,YAAY,GACN,SAAS,GAAI,GAAG,EAJb,IAKvB,CAKA,MAAM,eACJA,EACAO,EAAkB,IAKjB,CACD,IAAMC,EAAoB,KAAK,iBAAiBR,CAAO,EACvD,GAAI,CAACQ,EACH,MAAM,IAAI,MAAM,iBAAiB,EAInC,IAAMC,EAAW,KAAK,aAAa,IAAID,CAAiB,EACxD,OAAIC,EACK,CACL,YAAaA,EAAS,YACtB,KAAMA,EAAS,KACf,OAAQA,EAAS,MACnB,EAIK,IAAI,QAAQ,CAACH,EAASI,IAAW,CACtC,IAAMC,EAAQ,WAAW,IAAM,CAE7B,IAAMN,EAAU,KAAK,gBAAgB,IAAIG,CAAiB,EAC1D,GAAIH,EAAS,CACX,IAAMO,EAAQP,EAAQ,UAAWQ,GAAMA,EAAE,UAAYP,CAAO,EACxDM,EAAQ,IACVP,EAAQ,OAAOO,EAAO,CAAC,EAErBP,EAAQ,SAAW,GACrB,KAAK,gBAAgB,OAAOG,CAAiB,CAEjD,CAEAE,EACE,IAAI,MAAM,gDAAgDV,CAAO,UAAUO,CAAO,IAAI,CACxF,CACF,EAAGA,CAAO,EAGL,KAAK,gBAAgB,IAAIC,CAAiB,GAC7C,KAAK,gBAAgB,IAAIA,EAAmB,CAAC,CAAC,EAEhD,KAAK,gBAAgB,IAAIA,CAAiB,EAAG,KAAK,CAAE,QAAAF,EAAS,OAAAI,EAAQ,QAASC,CAAM,CAAC,CACvF,CAAC,CACH,CAKA,MAAa,CACP,KAAK,cACP,KAAK,YAAY,EACjB,KAAK,YAAc,MAErB,KAAK,aAAa,MAAM,EACxB,KAAK,gBAAgB,MAAM,CAC7B,CAKA,YAAmB,CACjB,KAAK,aAAa,MAAM,CAC1B,CACF,EC/JO,IAAMG,EAAN,KAAoE,CAazE,aAAc,CAZd,KAAQ,eAAiD,IAAI,IAC7D,KAAQ,gBAOJ,IAAI,IACR,KAAQ,YAAmC,KAC3C,KAAQ,cAAyB,GAG/B,KAAK,eAAe,CACtB,CAEA,MAAM,WAAWC,EAAqBC,EAAwC,CAC5E,GAAI,KAAK,cAAe,CACtBC,EAAO,KAAK,mDAAmD,EAC/D,MACF,CAEA,GAAI,CACF,MAAMC,EAAU,cAAcH,EAAaC,CAAe,EAC1D,KAAK,cAAgB,EACvB,OAASG,EAAO,CACd,MAAAF,EAAO,MAAM,qDAAsDE,CAAK,EAClEA,CACR,CACF,CAKQ,gBAAuB,CAC7B,KAAK,YAAcD,EAAU,SAAS,WAAYE,GAAe,CAC3DA,EAAM,OAAS,iBACjB,KAAK,oBAAoBA,EAAM,OAAO,CAE1C,CAAC,CACH,CAKQ,oBAAoBC,EAAoB,CAC9C,GAAI,CACF,IAAMC,EAAU,KAAK,iBAAiBD,GAAS,OAAO,EAChDE,EAAOF,GAAS,MAAQ,GAE9B,GAAI,CAACC,GAAW,CAACC,EAAM,CACrBN,EAAO,KAAK,8CAA+C,CAAE,QAAAI,CAAQ,CAAC,EACtE,MACF,CAEA,IAAMG,EAA0B,CAC9B,QAAAF,EACA,KAAAC,EACA,UAAW,KAAK,IAAI,CACtB,EAGA,KAAK,eAAe,IAAID,EAASE,CAAI,EAGrC,IAAMC,EAAU,KAAK,gBAAgB,IAAIH,CAAO,EAC5CG,IACFA,EAAQ,QAAQ,CAAC,CAAE,QAAAC,EAAS,QAAAC,CAAQ,IAAM,CACxC,aAAaA,CAAO,EACpBD,EAAQF,CAAI,CACd,CAAC,EACD,KAAK,gBAAgB,OAAOF,CAAO,EAEvC,OAASH,EAAO,CACdF,EAAO,MAAM,qCAAsCE,CAAK,CAC1D,CACF,CAKQ,iBAAiBG,EAAmD,CAC1E,OAAKA,GACcA,EAAQ,YAAY,EAAE,WAAW,IAAI,EACpDA,EAAQ,YAAY,EAAE,MAAM,CAAC,EAC7BA,EAAQ,YAAY,GACN,SAAS,GAAI,GAAG,EAJb,IAKvB,CAKA,MAAM,qBACJA,EACAK,EAAkB,IAIjB,CACD,IAAMC,EAAoB,KAAK,iBAAiBN,CAAO,EACvD,GAAI,CAACM,EACH,MAAM,IAAI,MAAM,iBAAiB,EAInC,IAAMC,EAAW,KAAK,eAAe,IAAID,CAAiB,EAC1D,OAAIC,EACK,CACL,QAASA,EAAS,QAClB,KAAMA,EAAS,IACjB,EAIK,IAAI,QAAQ,CAACH,EAASI,IAAW,CACtC,IAAMC,EAAQ,WAAW,IAAM,CAE7B,IAAMN,EAAU,KAAK,gBAAgB,IAAIG,CAAiB,EAC1D,GAAIH,EAAS,CACX,IAAMO,EAAQP,EAAQ,UAAWQ,GAAMA,EAAE,UAAYP,CAAO,EACxDM,EAAQ,IACVP,EAAQ,OAAOO,EAAO,CAAC,EAErBP,EAAQ,SAAW,GACrB,KAAK,gBAAgB,OAAOG,CAAiB,CAEjD,CAEAE,EACE,IAAI,MACF,wDAAwDR,CAAO,UAAUK,CAAO,IAClF,CACF,CACF,EAAGA,CAAO,EAGL,KAAK,gBAAgB,IAAIC,CAAiB,GAC7C,KAAK,gBAAgB,IAAIA,EAAmB,CAAC,CAAC,EAEhD,KAAK,gBAAgB,IAAIA,CAAiB,EAAG,KAAK,CAAE,QAAAF,EAAS,OAAAI,EAAQ,QAASC,CAAM,CAAC,CACvF,CAAC,CACH,CAKA,MAAa,CACP,KAAK,cACP,KAAK,YAAY,EACjB,KAAK,YAAc,MAErB,KAAK,eAAe,MAAM,EAC1B,KAAK,gBAAgB,MAAM,CAC7B,CAKA,YAAmB,CACjB,KAAK,eAAe,MAAM,CAC5B,CACF,ECtKO,IAAMG,GAAN,KAA0B,CAW/B,YACEC,EACAC,EAIA,CAfF,KAAQ,oBAAkD,KAC1D,KAAQ,2BAAgE,KACxE,KAAQ,6BAAoE,KAK5E,KAAQ,YAAoC,KAU1C,IAAMC,EAAwB,KAAK,mCAAmC,EAEtE,KAAK,kBAAoB,IAAIC,GAC3BC,EACAF,GAAyB,MAC3B,EACA,KAAK,uBAAyB,IAAIG,GAAuBD,CAAwB,EACjF,KAAK,oBAAsB,IAAIE,GAAoBF,CAAwB,EAC3E,KAAK,oBAAsB,IAAIG,GAAoBH,CAAwB,EAC3E,KAAK,oBAAsB,IAAII,GAAoBJ,CAAwB,EAG3E,IAAMK,EAAWT,GAAuB,KAAK,iCAAiC,EAO9E,GALIS,IACF,KAAK,oBAAsB,IAAIC,GAAoBN,EAA0BK,CAAQ,GAInFR,GAAS,YAAa,CACxB,IAAMU,EAAkBV,EAAQ,iBAAmBW,EAAU,KAC7D,KAAK,WAAWX,EAAQ,YAAaU,CAAe,EAAE,MAAOE,GAAU,CACrE,QAAQ,KAAK,iDAAkDA,CAAK,CACtE,CAAC,CACH,CACF,CAKQ,kCAA+D,CACrE,GAAI,CACF,YAAK,2BAA6B,IAAIC,EAC/B,KAAK,0BACd,OAASD,EAAO,CACd,eAAQ,KAAK,+CAAgDA,CAAK,EAC3D,IACT,CACF,CAKQ,oCAAmE,CACzE,GAAI,CACF,YAAK,6BAA+B,IAAIE,EACjC,KAAK,4BACd,OAASF,EAAO,CACd,eAAQ,KAAK,iDAAkDA,CAAK,EAC7D,IACT,CACF,CAEA,sBAA0C,CACxC,OAAO,KAAK,iBACd,CAEA,wBAA8C,CAC5C,GAAI,CAAC,KAAK,oBACR,MAAM,IAAI,MAAM,4DAA4D,EAE9E,OAAO,KAAK,mBACd,CAEA,2BAAoD,CAClD,OAAO,KAAK,sBACd,CAEA,wBAA8C,CAC5C,OAAO,KAAK,mBACd,CAEA,wBAA8C,CAC5C,OAAO,KAAK,mBACd,CAEA,wBAA8C,CAC5C,OAAO,KAAK,mBACd,CAQA,MAAM,WAAWG,EAAqBL,EAAwC,CAC5E,OAAK,KAAK,cACR,KAAK,aAAe,SAAY,CAC9B,MAAMM,EAAU,YAAY,EAExB,KAAK,sCAAsCH,EAC7C,MAAM,KAAK,2BAA2B,WAAWE,EAAaL,CAAe,EAE7E,QAAQ,KAAK,6DAA6D,EAExE,KAAK,wCAAwCI,EAC/C,MAAM,KAAK,6BAA6B,WAAWC,EAAaL,CAAe,EAE/E,QAAQ,KAAK,+DAA+D,CAEhF,GAAG,GAEE,KAAK,WACd,CAKA,SAAgB,CACV,KAAK,6BACP,KAAK,2BAA2B,KAAK,EACrC,KAAK,2BAA6B,MAEhC,KAAK,+BACP,KAAK,6BAA6B,KAAK,EACvC,KAAK,6BAA+B,KAExC,CACF,EAQO,SAASO,GACdlB,EACAC,EAIqB,CACrB,OAAO,IAAIF,GAAoBC,EAAqBC,CAAO,CAC7D","names":["index_exports","__export","ARGUMENT_INVALID","ARGUMENT_NOT_PROVIDED","ARGUMENT_OUT_OF_RANGE","AddWhitelistRequestSchema","AddWhitelistUseCase","AddressSchema","AggregateRoot","ArgumentInvalidException","ArgumentNotProvidedException","ArgumentOutOfRangeException","BaseRequestSchema","BlockchainRepositoryBase","Bytes32Schema","CONFLICT","CalculatePriceRequestSchema","CalculatePriceResponseSchema","ConfirmServerDownloadRequestSchema","ConfirmServerDownloadResponseSchema","ConflictException","DEFAULT_PREFIX_ID_LENGTH","DecodeAbiService","DomainEvent","DownloadFileRequestSchema","DownloadFileResponseSchema","DownloadFileUseCase","DownloadKeyListenerService","ENTITY_ID_LENGTH","Entity","ExceptionBase","FileActivatedListenerService","FileBlockchainRepository","FileModuleContainer","GetFileInfoRequestSchema","GetFileInfoResponseSchema","GetRustServerAddressesAbi","GetRustServerAddressesRequestSchema","GetRustServerAddressesResponseSchema","GetWhitelistRequestSchema","GetWhitelistUseCase","INTERNAL_SERVER_ERROR","InternalServerErrorException","IsPublicFileRequestSchema","IsPublicFileUseCase","Logger","NOT_FOUND","NativeQuicError","NotFoundException","PayForDownloadRequestSchema","PayForDownloadResponseSchema","PublicKeySchema","PushFileInfoRequestSchema","PushFileInfoResponseSchema","SetPublicStatusRequestSchema","SetPublicStatusUseCase","TimestampSchema","UniqueEntityID","UploadChunkRequestSchema","UploadFileRequestSchema","UploadFileResponseSchema","UploadFileUseCase","ValueObject","addWhitelistAbi","appConfig","buildMerkleTreePadded","calculatePriceAbi","confirmServerDownloadAbi","convertPropsToObject","createFileModule","createMittAsync","decodeAbiService","delay","downloadAllChunks","downloadAndMergeFile","emitter","eventLogs","fileBlockchainRepository","formatSize","fulfilledPromises","generateId","generatePrefixId","generateRandomHex","generateSignature","getFileInfoAbi","getMerkleProofPadded","getWhitelistAbi","humanFileSize","invariant","isAndroid","isArray","isBoolean","isBrowser","isCrawler","isDate","isDef","isEmpties","isEmpty","isFalsy","isFunction","isMap","isMobile","isNotEmpties","isNotEmpty","isNotNull","isNumber","isObject","isPngImage","isPrimitive","isPromise","isPublicFileAbi","isSet","isStream","isString","isSymbol","isUndef","isValidAddress","isValidPublicKey","isWindow","logger","payForDownloadAbi","pushFileInfoAbi","requestChunk","setPublicStatusAbi","uploadChunkAbi","verifyMerkleProof","__toCommonJS","appConfig","Logger","prefix","level","args","logger","import_system_core","_map","_DecodeAbiService_instances","initializeAbi_fn","abiToHash_fn","DecodeAbiService","abis","__privateAdd","__privateMethod","__privateGet","raw","matchHash","i","topic","abiData","decodeAbiService","abi","hash","types","input","signature","import_zod","Bytes32Schema","AddressSchema","val","cleaned","PublicKeySchema","TimestampSchema","num","BaseRequestSchema","ExceptionBase","message","metadata","ctx","ARGUMENT_INVALID","ARGUMENT_OUT_OF_RANGE","ARGUMENT_NOT_PROVIDED","NOT_FOUND","CONFLICT","INTERNAL_SERVER_ERROR","ArgumentNotProvidedException","ExceptionBase","ARGUMENT_NOT_PROVIDED","ArgumentInvalidException","ARGUMENT_INVALID","ArgumentOutOfRangeException","ARGUMENT_OUT_OF_RANGE","ConflictException","CONFLICT","NotFoundException","NOT_FOUND","InternalServerErrorException","INTERNAL_SERVER_ERROR","import_zod","import_mtn_contract","BlockchainRepositoryBase","to","logger","validatedAddress","AddressSchema","error","errorMessage","ArgumentInvalidException","schema","data","ArgumentNotProvidedException","z","params","transactionParams","ExceptionBase","InternalServerErrorException","calculatePriceAbi","confirmServerDownloadAbi","getFileInfoAbi","GetRustServerAddressesAbi","payForDownloadAbi","pushFileInfoAbi","uploadChunkAbi","setPublicStatusAbi","addWhitelistAbi","getWhitelistAbi","isPublicFileAbi","import_zod","CalculatePriceRequestSchema","BaseRequestSchema","z","CalculatePriceResponseSchema","import_zod","PushFileInfoRequestSchema","BaseRequestSchema","z","PushFileInfoResponseSchema","import_zod","UploadChunkRequestSchema","BaseRequestSchema","z","import_zod","GetFileInfoRequestSchema","BaseRequestSchema","z","GetFileInfoResponseSchema","import_zod","PayForDownloadRequestSchema","BaseRequestSchema","z","PayForDownloadResponseSchema","import_zod","ConfirmServerDownloadRequestSchema","BaseRequestSchema","z","ConfirmServerDownloadResponseSchema","import_zod","GetRustServerAddressesRequestSchema","BaseRequestSchema","GetRustServerAddressesResponseSchema","z","import_zod","SetPublicStatusRequestSchema","BaseRequestSchema","import_zod","AddWhitelistRequestSchema","BaseRequestSchema","import_zod","GetWhitelistRequestSchema","BaseRequestSchema","import_zod","IsPublicFileRequestSchema","BaseRequestSchema","FileBlockchainRepository","BlockchainRepositoryBase","appConfig","logger","request","validatedDTO","CalculatePriceRequestSchema","inputData","calculatePriceAbi","PushFileInfoRequestSchema","pushFileInfoAbi","UploadChunkRequestSchema","uploadChunkAbi","GetFileInfoRequestSchema","getFileInfoAbi","PayForDownloadRequestSchema","payForDownloadAbi","ConfirmServerDownloadRequestSchema","confirmServerDownloadAbi","GetRustServerAddressesRequestSchema","GetRustServerAddressesAbi","SetPublicStatusRequestSchema","setPublicStatusAbi","AddWhitelistRequestSchema","addWhitelistAbi","GetWhitelistRequestSchema","getWhitelistAbi","IsPublicFileRequestSchema","isPublicFileAbi","fileBlockchainRepository","import_event_log","abi_default","EventLogs","_EventLogs","abi_default","err","userAddress","contractAddress","key","eventLogs","import_nanoid","generateId","DEFAULT_PREFIX_ID_LENGTH","ENTITY_ID_LENGTH","generatePrefixId","prefix","length","prefix","invariant","condition","message","isNotNull","v","isArray","val","isPrimitive","value","isDef","isUndef","isBoolean","isFunction","isNumber","isString","isObject","isMap","isSet","isDate","isSymbol","isPromise","isFalsy","isNotEmpty","isWindow","isStream","isBrowser","isEmptyArr","array","isEmpty","isNotEmpties","args","a","b","isEmpties","isPngImage","buffer","isAndroid","match","isMobile","isCrawler","delay","ms","resolve","humanFileSize","bytes","si","dp","thresh","units","u","r","generateRandomHex","length","hex","chars","i","fulfilledPromises","promises","results","result","formatSize","bytes","k","sizes","i","UniqueEntityID","_id","generatePrefixId","DomainEvent","domainEvent","invariant","ArgumentNotProvidedException","UniqueEntityID","generatePrefixId","import_mitt","createMittAsync","all","emitter","mitt","type","event","handlers","handler","wildcardHandlers","_ValueObject_instances","validateProps_fn","isDomainPrimitive_fn","_ValueObject","props","__privateAdd","__privateMethod","obj","vo","clone","convertPropsToObject","invariant","isEmpty","ArgumentNotProvidedException","ValueObject","isEntity","obj","ValueObject","convertToPlainObject","item","convertPropsToObject","props","propsCopy","prop","_id","_createdAt","_props","_updatedAt","_Entity_instances","validateProps_fn","_Entity","id","props","createdAt","updatedAt","__privateAdd","__privateSet","__privateMethod","now","entity","__privateGet","clone","convertPropsToObject","result","invariant","isEmpty","ArgumentNotProvidedException","ArgumentInvalidException","ArgumentOutOfRangeException","Entity","_domainEvents","AggregateRoot","Entity","__privateAdd","__privateGet","event","__privateSet","logger","emitter","eventName","isValidAddress","address","cleaned","isValidPublicKey","publicKey","import_system_core","EMPTY_HASH","cachedEmptyHash","getEmptyHash","sha256","data","bufferAsNumberArray","hash","error","hexToBytes","hex","cleanHex","bytes","i","nextPowerOfTwo","n","buildMerkleTreePadded","chunks","numLeaves","empty","total","leaves","emptyHash","realHashes","levels","level","nextLevel","leftHex","rightHex","leftBytes","rightBytes","combined","parent","getMerkleProofPadded","index","proof","idx","levelIdx","siblingIdx","siblingHash","verifyMerkleProof","leafHash","root","sibling","isLeft","UploadFileUseCase","fileBlockchainRepository","fileActivatedProvider","request","file","from","chunkSize","logger","arrayBuffer","buffer","chunks","i","leaves","merkleRoot","treeLevels","buildMerkleTreePadded","dataPrice","fileExt","expireTime","fileKey","uploadPromises","chunk","leafHash","proof","getMerkleProofPadded","verifyMerkleProof","chunkDataHex","b","activated","error","import_system_core","ALPN","MAX_RETRIES","RETRY_DELAY_MS","Mutex","begin","_unlock","res","downloadMutex","NativeQuicError","code","retryable","retryAfterMs","message","parseServerAddress","address","ip","portStr","port","connectionRefs","ensureConnected","serverAddr","disconnectServer","resolve","err","error","requestChunkFromServer","fileKey","downloadKey","chunkIndex","totalChunks","signature","request","requestMessage","response","data","errorMessage","base64Data","binaryString","bytes","i","getServerAddresses","from","addresses","fileBlockchainRepository","getServerForChunk","serverAddresses","serverIndex","requestChunk","isEven","lastError","attempt","result","delay","downloadAllChunks","onProgress","server1Addr","server2Addr","results","nextIndex","downloaded","CONCURRENCY","worker","downloadAndMergeFile","unlock","chunks","totalLength","sum","chunk","merged","offset","import_system_core","generateSignature","downloadKey","privateKey","messageWithPrefix","hash","sign","error","import_system_core","Mutex","begin","_unlock","res","paymentMutex","DownloadFileUseCase","fileBlockchainRepository","downloadKeyProvider","request","fileKey","from","downloadTimes","logger","fileInfo","downloadPrice","unlock","downloadKey","privateKey","signature","generateSignature","fileData","downloadAndMergeFile","downloaded","total","SetPublicStatusUseCase","fileBlockchainRepository","request","logger","AddWhitelistUseCase","fileBlockchainRepository","request","logger","GetWhitelistUseCase","fileBlockchainRepository","request","logger","IsPublicFileUseCase","fileBlockchainRepository","request","logger","import_zod","UploadFileRequestSchema","z","UploadFileResponseSchema","import_zod","DownloadFileRequestSchema","z","DownloadFileResponseSchema","DownloadKeyListenerService","userAddress","contractAddress","logger","eventLogs","error","event","payload","fileKey","downloadKey","user","amount","data","pending","resolve","timeout","normalizedFileKey","existing","reject","timer","index","p","FileActivatedListenerService","userAddress","contractAddress","logger","eventLogs","error","event","payload","fileKey","user","data","pending","resolve","timeout","normalizedFileKey","existing","reject","timer","index","p","FileModuleContainer","downloadKeyProvider","options","fileActivatedProvider","UploadFileUseCase","fileBlockchainRepository","SetPublicStatusUseCase","AddWhitelistUseCase","GetWhitelistUseCase","IsPublicFileUseCase","provider","DownloadFileUseCase","contractAddress","appConfig","error","DownloadKeyListenerService","FileActivatedListenerService","userAddress","eventLogs","createFileModule"]}
|