jitar 0.9.4 → 0.10.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/cli.js +1 -1
- package/dist/client.js +1 -1
- package/package.json +1 -2
package/dist/client.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
class BadRequest extends Error{constructor(message="Invalid request"){super(message)}}class Forbidden extends Error{constructor(message="Forbidden"){super(message)}}class NotFound extends Error{constructor(message="Not found"){super(message)}}class NotImplemented extends Error{constructor(message="Not implemented"){super(message)}}class PaymentRequired extends Error{constructor(message="Payment required"){super(message)}}class ServerError extends Error{constructor(message="Server error"){super(message)}}class Teapot extends Error{constructor(message="I'm a teapot"){super(message)}}class Unauthorized extends Error{constructor(message="Unauthorized"){super(message)}}const AccessLevels_PRIVATE="private",AccessLevels_PROTECTED="protected",AccessLevels_PUBLIC="public",RunModes_NORMAL="normal",RunModes_DRY="dry",StatusCodes_OK=200,StatusCodes_BAD_REQUEST=400,StatusCodes_UNAUTHORIZED=401,StatusCodes_PAYMENT_REQUIRED=402,StatusCodes_FORBIDDEN=403,StatusCodes_NOT_FOUND=404,StatusCodes_TEAPOT=418,StatusCodes_SERVER_ERROR=500,StatusCodes_NOT_IMPLEMENTED=501;class InvalidVersionNumber extends BadRequest{#number;constructor(number){super(`Invalid version number '${number}'`),this.#number=number}get number(){return this.#number}}class ProcedureNotFound extends NotFound{#fqn;constructor(fqn){super(`Procedure '${fqn}' not found`),this.#fqn=fqn}get fqn(){return this.#fqn}}class ProcedureNotAccessible extends Forbidden{constructor(fqn,versionNumber){super(`Procedure '${fqn}' (v${versionNumber}) is not accessible`)}}class Segment{#id;#classes=new Map;#procedures=new Map;constructor(id){this.#id=id}get id(){return this.#id}addClass(clazz){return this.#classes.set(clazz.fqn,clazz),this}hasClass(fqn){return void 0!==this.getClass(fqn)}getClass(fqn){return this.#classes.get(fqn)}getClassByImplementation(implementation){return this.getClasses().find(clazz=>clazz.implementation===implementation)}getClasses(){return[...this.#classes.values()]}addProcedure(procedure){return this.#procedures.set(procedure.fqn,procedure),this}hasProcedure(fqn){return this.#procedures.has(fqn)}getProcedure(fqn){return this.#procedures.get(fqn)}getExposedProcedures(){return[...this.#procedures.values()].filter(procedure=>procedure.public||procedure.protected)}}class Class{#fqn;#implementation;constructor(fqn,implementation){this.#fqn=fqn,this.#implementation=implementation}get fqn(){return this.#fqn}get implementation(){return this.#implementation}}class Version{static get DEFAULT(){return new Version(0,0,0)}#major;#minor;#patch;constructor(major=0,minor=0,patch=0){this.#major=major,this.#minor=minor,this.#patch=patch}get major(){return this.#major}get minor(){return this.#minor}get patch(){return this.#patch}equals(version){return this.#major===version.major&&this.#minor===version.minor&&this.#patch===version.patch}greater(version){return this.#major!==version.major?this.#major>version.major:this.#minor!==version.minor?this.#minor>version.minor:this.#patch!==version.patch&&this.#patch>version.patch}less(version){return this.#major!==version.major?this.#major<version.major:this.#minor!==version.minor?this.#minor<version.minor:this.#patch!==version.patch&&this.#patch<version.patch}toString(){return`${this.#major}.${this.#minor}.${this.#patch}`}}class Procedure{#fqn;#implementations=new Map;#latestImplementation;constructor(fqn){this.#fqn=fqn}get fqn(){return this.#fqn}get public(){return[...this.#implementations.values()].some(implementation=>implementation.public)}get protected(){return[...this.#implementations.values()].some(implementation=>implementation.protected)}addImplementation(implementation){return this.#implementations.set(implementation.version,implementation),this.#isNewLatestImplementation(implementation)&&(this.#latestImplementation=implementation),this}#isNewLatestImplementation(implementation){return void 0===this.#latestImplementation||implementation.version.greater(this.#latestImplementation.version)}getImplementation(version){const selectedVersion=this.#selectAvailableVersion(version);return this.#implementations.get(selectedVersion)}#selectAvailableVersion(version){let selectedVersion=Version.DEFAULT;for(const implementationVersion of this.#implementations.keys()){if(implementationVersion.equals(version))return implementationVersion;implementationVersion.greater(version)||selectedVersion.less(implementationVersion)&&(selectedVersion=implementationVersion)}return selectedVersion}}class Implementation{#version;#access;#parameters;#executable;constructor(version,access,parameters,executable){this.#version=version,this.#access=access,this.#parameters=parameters,this.#executable=executable}get version(){return this.#version}get public(){return this.#access===AccessLevels_PUBLIC}get protected(){return this.#access===AccessLevels_PROTECTED}get private(){return this.#access===AccessLevels_PRIVATE}get parameters(){return this.#parameters}get executable(){return this.#executable}}class Parameter{#name;#isOptional;constructor(name,isOptional=!1){this.#name=name,this.#isOptional=isOptional}get name(){return this.#name}get isOptional(){return this.#isOptional}}class NamedParameter extends Parameter{}class DestructuredParameter extends Parameter{#variables;constructor(variables,name,isOptional){super(name??"(anonymous)",isOptional),this.#variables=variables}get variables(){return this.#variables}}class ArrayParameter extends DestructuredParameter{}class ObjectParameter extends DestructuredParameter{}class Request{#fqn;#version;#args;#headers=new Map;#mode;constructor(fqn,version,args,headers,mode){this.#fqn=fqn,this.#version=version,this.#args=args,this.#headers=headers,this.#mode=mode}get fqn(){return this.#fqn}get version(){return this.#version}get args(){return this.#args}get headers(){return this.#headers}get mode(){return this.#mode}clearArguments(){this.#args.clear()}setArgument(name,value){this.#args.set(name,value)}getArgument(name){return this.#args.get(name)}hasArgument(name){return this.#args.has(name)}removeArgument(name){this.#args.delete(name)}clearHeaders(){this.#headers.clear()}setHeader(name,value){this.#headers.set(name.toLowerCase(),value)}getHeader(name){return this.#headers.get(name.toLowerCase())}hasHeader(name){return this.#headers.has(name.toLowerCase())}removeHeader(name){this.#headers.delete(name.toLowerCase())}}class Response{#status;#result;#headers;constructor(status,result=void 0,headers=new Map){this.#status=status,this.#result=result,this.#headers=headers}get status(){return this.#status}get result(){return this.#result}set result(value){this.#result=value}get headers(){return this.#headers}clearHeaders(){this.#headers.clear()}setHeader(name,value){this.#headers.set(name.toLowerCase(),value)}getHeader(name){return this.#headers.get(name.toLowerCase())}hasHeader(name){return this.#headers.has(name.toLowerCase())}removeHeader(name){this.#headers.delete(name.toLowerCase())}}class UnknownParameter extends BadRequest{#parameterName;constructor(parameterName){super(`Unknown parameter ${parameterName}`),this.#parameterName=parameterName}get parameterName(){return this.#parameterName}}class MissingParameterValue extends BadRequest{#parameterName;constructor(parameterName){super(`Missing value for parameter '${parameterName}'`),this.#parameterName=parameterName}get parameterName(){return this.#parameterName}}class InvalidParameterValue extends BadRequest{#parameterName;constructor(parameterName){super(`Invalid value for parameter '${parameterName}'`),this.#parameterName=parameterName}get parameterName(){return this.#parameterName}}class ArgumentExtractor{extract(parameters,args){const argsCopy=this.#copyArguments(parameters,args),values=[];for(const parameter of parameters){const value=this.#extractArgumentValue(parameter,argsCopy);values.push(value)}if(argsCopy.size>0){const name=argsCopy.keys().next().value;throw new UnknownParameter(name)}return values}#copyArguments(parameters,args){const copy=new Map;for(const[key,value]of args){if(this.#isOptionalArgument(key)){const name=this.#getParameterName(key);!0===this.#containsParameter(parameters,name)&©.set(name,value);continue}copy.set(key,value)}return copy}#isOptionalArgument(argument){return argument.startsWith("*")}#getParameterName(argument){return argument.substring(1)}#containsParameter(parameters,name){return void 0!==parameters.find(parameter=>parameter.name===name)}#extractArgumentValue(parameter,args,parent){return parameter instanceof NamedParameter?this.#extractNamedArgumentValue(parameter,args,parent):this.#extractDestructedArgumentValue(parameter,args)}#extractNamedArgumentValue(parameter,args,parent){const value=args.get(parameter.name);if(this.#isMissingParameterValue(parameter,value,parent))throw new MissingParameterValue(parameter.name);if(this.#isInvalidRestParameter(parameter,value,parent))throw new InvalidParameterValue(parameter.name);return args.delete(parameter.name),value}#extractDestructedArgumentValue(parameter,args){return parameter instanceof ArrayParameter?this.#extractArrayArgumentValue(parameter,args):this.#extractObjectArgumentValue(parameter,args)}#extractArrayArgumentValue(parameter,args){const values=this.#extractVariableValues(parameter,args);return void 0!==values?Object.values(values):void 0}#extractObjectArgumentValue(parameter,args){return this.#extractVariableValues(parameter,args)}#extractVariableValues(parameter,args){const useIndex=parameter instanceof ArrayParameter,values={},missingValues=[];let containsValues=!1,index=0;for(const variable of parameter.variables){const key=useIndex?index++:variable.name,value=this.#extractArgumentValue(variable,args,parameter);void 0!==value?containsValues=!0:!1===variable.isOptional&&missingValues.push(variable.name),values[key]=value}if(!0===containsValues&&missingValues.length>0)throw new MissingParameterValue(missingValues[0]);return containsValues?values:void 0}#isMissingParameterValue(parameter,value,parent){return void 0===value&&(!0!==parameter.isOptional&&!0!==parent?.isOptional)}#isInvalidRestParameter(parameter,value,parent){return!1!==parameter.name.startsWith("...")&&(void 0===parent&&value instanceof Array==!1||parent instanceof ArrayParameter&&value instanceof Array==!1||parent instanceof ObjectParameter&&value instanceof Object==!1)}}class ErrorConverter{toStatus(error){return error instanceof BadRequest?StatusCodes_BAD_REQUEST:error instanceof Forbidden?StatusCodes_FORBIDDEN:error instanceof NotFound?StatusCodes_NOT_FOUND:error instanceof NotImplemented?StatusCodes_NOT_IMPLEMENTED:error instanceof PaymentRequired?StatusCodes_PAYMENT_REQUIRED:error instanceof Teapot?StatusCodes_TEAPOT:error instanceof Unauthorized?StatusCodes_UNAUTHORIZED:StatusCodes_SERVER_ERROR}fromStatus(status,message){switch(status){case StatusCodes_BAD_REQUEST:return new BadRequest(message);case StatusCodes_FORBIDDEN:return new Forbidden(message);case StatusCodes_NOT_FOUND:return new NotFound(message);case StatusCodes_NOT_IMPLEMENTED:return new NotImplemented(message);case StatusCodes_PAYMENT_REQUIRED:return new PaymentRequired(message);case StatusCodes_TEAPOT:return new Teapot(message);case StatusCodes_UNAUTHORIZED:return new Unauthorized(message);default:return new ServerError(message)}}}const VERSION_EXPRESSION=/^\d+(?:\.\d+){0,2}$/;class VersionParser{parse(number){if(0===number.trim().length)return Version.DEFAULT;if(!1===VERSION_EXPRESSION.test(number))throw new InvalidVersionNumber(number);const parts=number.split(".");switch(parts.length){case 1:return new Version(Number.parseInt(parts[0]));case 2:return new Version(Number.parseInt(parts[0]),Number.parseInt(parts[1]));default:return new Version(Number.parseInt(parts[0]),Number.parseInt(parts[1]),Number.parseInt(parts[2]))}}}class ImplementationNotFound extends NotFound{#fqn;#version;constructor(fqn,version){super(`No implementation found for procedure '${fqn}' with version '${version}'`),this.#fqn=fqn,this.#version=version}get fqn(){return this.#fqn}get version(){return this.#version}}class InvalidSegment extends ServerError{constructor(){super("Invalid segment")}}class Application{#segments=new Map;addSegment(segment){this.#segments.set(segment.id,segment)}clearSegments(){this.#segments.clear()}getClassNames(){const names=new Set;for(const segment of this.#segments.values()){segment.getClasses().forEach(clazz=>names.add(clazz.fqn))}return[...names.values()]}hasClass(fqn){return this.getClassNames().includes(fqn)}getClass(fqn){for(const segment of this.#segments.values())if(segment.hasClass(fqn))return segment.getClass(fqn)}getClassByImplementation(implementation){for(const segment of this.#segments.values()){const clazz=segment.getClassByImplementation(implementation);if(void 0!==clazz)return clazz}}getProcedureNames(){const names=new Set;for(const segment of this.#segments.values()){segment.getExposedProcedures().forEach(procedure=>names.add(procedure.fqn))}return[...names.values()]}hasProcedure(fqn){return this.getProcedureNames().includes(fqn)}getProcedure(fqn){for(const segment of this.#segments.values())if(segment.hasProcedure(fqn))return segment.getProcedure(fqn)}}class ExecutionManager{#moduleImporter;#segmentFiles;#argumentConstructor=new ArgumentExtractor;#errorConverter=new ErrorConverter;#application=new Application;constructor(moduleImporter,segmentFiles=[]){this.#moduleImporter=moduleImporter,this.#segmentFiles=segmentFiles}async start(){return this.#loadSegments()}async stop(){return this.#clearSegments()}async loadSegment(filename){const module=await this.#moduleImporter.import(filename);this.addSegment(module.default)}async addSegment(segment){if(segment instanceof Segment==!1)throw new InvalidSegment;this.#application.addSegment(segment)}getClassNames(){return this.#application.getClassNames()}hasClass(fqn){return this.#application.hasClass(fqn)}getClass(fqn){return this.#application.getClass(fqn)}getClassByImplementation(implementation){return this.#application.getClassByImplementation(implementation)}getProcedureNames(){return this.#application.getProcedureNames()}hasProcedure(fqn){return this.#application.hasProcedure(fqn)}getProcedure(fqn){return this.#application.getProcedure(fqn)}async run(request){const implementation=this.#getImplementation(request.fqn,request.version),args=this.#argumentConstructor.extract(implementation.parameters,request.args);return request.mode===RunModes_DRY?new Response(StatusCodes_OK,void 0):this.#runImplementation(request,implementation,args)}async#loadSegments(){await Promise.all(this.#segmentFiles.map(filename=>this.loadSegment(filename)))}#clearSegments(){this.#application.clearSegments()}#getImplementation(fqn,version){const procedure=this.#application.getProcedure(fqn);if(void 0===procedure)throw new ProcedureNotFound(fqn);const implementation=procedure.getImplementation(version);if(void 0===implementation)throw new ImplementationNotFound(procedure.fqn,version.toString());return implementation}async#runImplementation(request,implementation,args){try{const result=await implementation.executable.call(request,...args);return new Response(StatusCodes_OK,result)}catch(error){const status=this.#errorConverter.toStatus(error);return new Response(status,error)}}}class RemoteGateway{#url;#remote;constructor(configuration){this.#url=configuration.url,this.#remote=configuration.remote}get url(){return this.#url}get trustKey(){}start(){return this.#remote.connect()}stop(){return this.#remote.disconnect()}isHealthy(){return this.#remote.isHealthy()}getHealth(){return this.#remote.getHealth()}getProcedureNames(){throw new NotImplemented}hasProcedure(name){throw new NotImplemented}addWorker(worker){return this.#remote.addWorker(worker.url,worker.getProcedureNames(),worker.trustKey)}removeWorker(worker){return this.#remote.removeWorker(worker.id)}run(request){return this.#remote.run(request)}}class InvalidPath extends Error{#location;constructor(location){super(`Invalid location: ${location}`),this.#location=location}get location(){return this.#location}}class FileNotFound extends Error{#filename;constructor(filename){super(`The file '${filename}' could not be found`),this.#filename=filename}get filename(){return this.#filename}}class File{#location;#type;#content;constructor(location,type,content){this.#location=location,this.#type=type,this.#content=content}get location(){return this.#location}get type(){return this.#type}get content(){return this.#content}get size(){return this.#content.length}}class FileManager{#location;#rootLocation;#fileSystem;constructor(location,fileSystem){const rootLocation=fileSystem.resolve(location);this.#location=fileSystem.normalize(location),this.#rootLocation=fileSystem.normalize(rootLocation),this.#fileSystem=fileSystem}getAbsoluteLocation(filename){const location=this.#fileSystem.isAbsolute(filename)?filename:this.#fileSystem.join(this.#location,filename),absolutePath=this.#fileSystem.resolve(location),normalizedPath=this.#fileSystem.normalize(absolutePath);return this.#validateLocation(normalizedPath,filename),normalizedPath}getRelativeLocation(filename){const location=this.#fileSystem.relative(this.#location,filename);return this.#fileSystem.normalize(location)}normalizeLocation(location){return this.#fileSystem.normalize(location)}async getType(filename){const location=this.getAbsoluteLocation(filename);return await this.#fileSystem.mimeType(location)??"application/octet-stream"}async getContent(filename){const location=this.getAbsoluteLocation(filename);if(!1===await this.#fileSystem.exists(location))throw new FileNotFound(filename);return this.#fileSystem.read(location)}async exists(filename){const location=this.getAbsoluteLocation(filename);return this.#fileSystem.exists(location)}isDirectory(filename){const location=this.getAbsoluteLocation(filename);return this.#fileSystem.isDirectory(location)}async read(filename){const absoluteFilename=this.getAbsoluteLocation(filename),type=await this.getType(absoluteFilename),content=await this.getContent(absoluteFilename);return new File(filename,type,content)}async write(filename,content){const location=this.getAbsoluteLocation(filename);return this.#fileSystem.write(location,content)}async copy(source,destination){const sourceLocation=this.getAbsoluteLocation(source),destinationLocation=this.getAbsoluteLocation(destination);return this.#fileSystem.copy(sourceLocation,destinationLocation)}async delete(filename){const location=this.getAbsoluteLocation(filename);return this.#fileSystem.delete(location)}async filter(pattern){const location=this.getAbsoluteLocation("./"),normalizedPattern=this.#fileSystem.normalize(pattern);return(await this.#fileSystem.filter(location,normalizedPattern)).map(filename=>this.#fileSystem.normalize(filename))}#validateLocation(location,filename){if(!1===location.startsWith(this.#rootLocation))throw new InvalidPath(filename)}}class RemoteFilesNotSupported extends Error{constructor(){super("Remote files are not supported")}}class RemoteFileSystem{copy(source,destination){throw new RemoteFilesNotSupported}delete(location){throw new RemoteFilesNotSupported}exists(location){throw new RemoteFilesNotSupported}async filter(location,pattern){return[]}isAbsolute(location){return location.startsWith("/")}isDirectory(location){throw new RemoteFilesNotSupported}join(...paths){throw new RemoteFilesNotSupported}read(location){throw new RemoteFilesNotSupported}resolve(location){return location}relative(from,to){throw new RemoteFilesNotSupported}normalize(location){return location}mimeType(location){throw new RemoteFilesNotSupported}write(location,content){throw new RemoteFilesNotSupported}}class RemoteFileManager extends FileManager{constructor(location){super(location,new RemoteFileSystem)}}class ModuleNotLoaded extends Error{#url;#reason;constructor(url,reason){super(`Module '${url}' could not be loaded${void 0!==reason?` | ${reason}`:""}`),this.#url=url,this.#reason=reason}get url(){return this.#url}get reason(){return this.#reason}}class ImportManager{#moduleLocator;constructor(moduleLocator){this.#moduleLocator=moduleLocator}async import(filename){const location=this.#moduleLocator.locate(filename);try{return await import(location)}catch(error){const message=error instanceof Error?error.message:String(error);throw new ModuleNotLoaded(location,message)}}}class RemoteModuleLocator{constructor(location){}locate(filename){throw new ModuleNotLoaded(filename,"Remote module loading is not allowed")}}class RemoteImportManager extends ImportManager{constructor(location){super(new RemoteModuleLocator(location))}}class SourcingManager{#fileManager;#importManager;constructor(fileManager,importManager){this.#fileManager=fileManager,this.#importManager=importManager}async filter(...patterns){return(await Promise.all(patterns.map(pattern=>this.#fileManager.filter(pattern)))).flat().map(file=>this.#fileManager.getRelativeLocation(file))}exists(filename){return this.#fileManager.exists(filename)}read(filename){return this.#fileManager.read(filename)}import(filename){return this.#importManager.import(filename)}}class RemoteSourcingManager extends SourcingManager{constructor(location){super(new RemoteFileManager(location),new RemoteImportManager(location))}}class ClassNotFound extends Error{constructor(name){super(`The class '${name}' could not be found`)}}class InvalidClass extends Error{constructor(name){super(`The class '${name}' is invalid`)}}class NoDeserializerFound extends Error{constructor(type){super(`No deserializer found for value of type '${type}'`)}}class NoSerializerFound extends Error{constructor(type){super(`No serializer found for value of type '${type}'`)}}class Serializer{#serializers=[];addSerializer(serializer){serializer.parent=this,this.#serializers.unshift(serializer)}async serialize(value){const serializer=this.#serializers.find(serializer=>serializer.canSerialize(value));if(void 0===serializer)throw new NoSerializerFound(typeof value);return serializer.serialize(value)}async deserialize(value){const serializer=this.#serializers.find(serializer=>serializer.canDeserialize(value));if(void 0===serializer)throw new NoDeserializerFound(typeof value);return serializer.deserialize(value)}}class ParentSerializerNotSet extends Error{constructor(){super("Parent serializer not set")}}class ValueSerializer{#parent;set parent(parent){this.#parent=parent}serializeOther(value){if(void 0===this.#parent)throw new ParentSerializerNotSet;return this.#parent.serialize(value)}deserializeOther(value){if(void 0===this.#parent)throw new ParentSerializerNotSet;return this.#parent.deserialize(value)}}class ArraySerializer extends ValueSerializer{canSerialize(value){return value instanceof Array}canDeserialize(value){return value instanceof Array}async serialize(array){const values=[];for(const value of array)values.push(await this.serializeOther(value));return values}async deserialize(array){return Promise.all(array.map(async value=>this.deserializeOther(value)))}}class InvalidBigIntString extends Error{constructor(bigIntString){super(`Invalid BigInt string '${bigIntString}'`)}}class BigIntSerializer extends ValueSerializer{canSerialize(value){return"bigint"==typeof value}canDeserialize(value){const bigInt=value;return bigInt instanceof Object&&!0===bigInt.serialized&&"BigInt"===bigInt.name&&"string"==typeof bigInt.value}async serialize(bigInt){return{serialized:!0,name:"BigInt",value:bigInt.toString()}}async deserialize(object){try{return BigInt(object.value)}catch{throw new InvalidBigIntString(object.value)}}}class InvalidBufferString extends Error{constructor(bufferString){super(`Invalid Buffer string '${bufferString}'`)}}class BufferSerializer extends ValueSerializer{canSerialize(value){return value instanceof Buffer}canDeserialize(value){const buffer=value;return buffer instanceof Object&&!0===buffer.serialized&&"Buffer"===buffer.name&&"string"==typeof buffer.base64}async serialize(buffer){return{serialized:!0,name:"Buffer",base64:buffer.toString("base64")}}async deserialize(object){try{return Buffer.from(object.base64,"base64")}catch{throw new InvalidBufferString(object.base64)}}}class ESAlias{#name;#as;constructor(name,as){this.#name=name,this.#as=as}get name(){return this.#name}get as(){return this.#as}toString(){return`${this.#name} as ${this.#as}`}}class ESValue{#definition;constructor(definition){this.#definition=definition}get definition(){return this.#definition}toString(){return this.#definition}}class ESArray extends ESValue{}class ESMember{#name;#isStatic;#isPrivate;constructor(name,isStatic=!1,isPrivate=!1){this.#name=name,this.#isStatic=isStatic,this.#isPrivate=isPrivate}get name(){return this.#name}get isStatic(){return this.#isStatic}get isPrivate(){return this.#isPrivate}get isPublic(){return!1===this.#isPrivate}}class ESClass extends ESMember{#parentName;#scope;constructor(name,parentName,scope){super(name),this.#parentName=parentName,this.#scope=scope}get parentName(){return this.#parentName}get scope(){return this.#scope}get members(){return this.#scope.members}get declarations(){return this.#scope.declarations}get functions(){return this.#scope.functions}get getters(){return this.#scope.getters}get setters(){return this.#scope.setters}get generators(){return this.#scope.generators}get readable(){const members=new Map;return this.getters.forEach(getter=>{members.set(getter.name,getter)}),this.declarations.forEach(declaration=>{declaration.isPublic&&members.set(declaration.name,declaration)}),[...members.values()]}get writable(){const members=new Map;return this.setters.forEach(setter=>{members.set(setter.name,setter)}),this.declarations.forEach(declaration=>{declaration.isPublic&&members.set(declaration.name,declaration)}),[...members.values()]}get callable(){return this.functions.filter(funktion=>funktion.isPublic)}getMember(name){return this.#scope.getMember(name)}getDeclaration(name){return this.#scope.getDeclaration(name)}getFunction(name){return this.#scope.getFunction(name)}getGetter(name){return this.#scope.getGetter(name)}getSetter(name){return this.#scope.getSetter(name)}getGenerator(name){return this.#scope.getGenerator(name)}hasMember(name){return this.#scope.hasMember(name)}hasDeclaration(name){return this.#scope.hasDeclaration(name)}hasFunction(name){return this.#scope.hasFunction(name)}hasGetter(name){return this.#scope.hasGetter(name)}hasSetter(name){return this.#scope.hasSetter(name)}hasGenerator(name){return this.#scope.hasGenerator(name)}canRead(name){const declaration=this.getDeclaration(name);return declaration?.isPublic||this.hasGetter(name)}canWrite(name){const declaration=this.getDeclaration(name);return declaration?.isPublic||this.hasSetter(name)}canCall(name){const funktion=this.getFunction(name);return funktion?.isPublic??!1}toString(){const infix=void 0!==this.#parentName?` extends ${this.#parentName}`:"";return`class ${this.name}${infix} { ${this.#scope.toString()} }`}}class ESDeclaration extends ESMember{#identifier;#value;constructor(identifier,value,isStatic=!1,isPrivate=!1){super(identifier.toString(),isStatic,isPrivate),this.#identifier=identifier,this.#value=value}get identifier(){return this.#identifier}get value(){return this.#value}toString(){return`${this.name}${this.value?" = "+this.value.toString():""}`}}class ESDestructuredValue{#members;constructor(members){this.#members=members}get members(){return this.#members}toString(){return this.#members.map(member=>member.toString()).join(" , ")}}class ESDestructuredArray extends ESDestructuredValue{toString(){return`[ ${super.toString()} ]`}}class ESDestructuredObject extends ESDestructuredValue{toString(){return`{ ${super.toString()} }`}}class ESExport extends ESMember{#members;#from;constructor(members,from){super(""),this.#members=members,this.#from=from}get members(){return this.#members}get from(){return this.#from}hasMember(name){return this.#members.some(member=>member.as===name)}getMember(name){return this.#members.find(member=>member.as===name)}toString(){const postfix=this.#from?` from '${this.#from}'`:"";return`export { ${this.#members.join(", ")} }${postfix}`}}class ESExpression extends ESValue{}class ESField{#name;#value;constructor(name,value){this.#name=name,this.#value=value}get name(){return this.#name}get value(){return this.#value}toString(){return`${this.name}${this.value?" = "+this.value.toString():""}`}}class ESFunction extends ESMember{#parameters;#body;#isAsync;constructor(name,parameters,body,isStatic=!1,isAsync=!1,isPrivate=!1){super(name,isStatic,isPrivate),this.#parameters=parameters,this.#body=body,this.#isAsync=isAsync}get parameters(){return this.#parameters}get body(){return this.#body}get isAsync(){return this.#isAsync}toString(){const parameters=this.parameters.map(parameter=>parameter.toString());return`${this.isAsync?"async ":""}${this.name}(${parameters.join(", ")}) { ${this.body} }`}}class ESGenerator extends ESFunction{toString(){const parameters=this.parameters.map(parameter=>parameter.toString());return`${this.isAsync?"async ":""}${this.name}*(${parameters.join(", ")}) { ${this.body} }`}}class ESGetter extends ESFunction{toString(){return`get ${super.toString()}`}}class ESImport extends ESMember{#members;#from;constructor(members,from){super(""),this.#members=members,this.#from=from}get members(){return this.#members}get from(){return this.#from}hasMember(name){return this.#members.some(member=>member.as===name)}getMember(name){return this.#members.find(member=>member.as===name)}toString(){return`import { ${this.#members.map(member=>member.toString()).join(", ")} } from '${this.#from}';`}}class ESModule{#scope;constructor(scope){this.#scope=scope}get scope(){return this.#scope}get members(){return this.#scope.members}get exportedMembers(){return this.#filterExported(this.#scope.members)}get imports(){return this.#scope.imports}get exports(){return this.#scope.exports}get declarations(){return this.#scope.declarations}get exportedDeclarations(){return this.#filterExported(this.#scope.declarations)}get functions(){return this.#scope.functions}get exportedFunctions(){return this.#filterExported(this.#scope.functions)}get generators(){return this.#scope.generators}get exportedGenerators(){return this.#filterExported(this.#scope.generators)}get classes(){return this.#scope.classes}get exportedClasses(){return this.#filterExported(this.#scope.classes)}get exported(){const exported=new Map;for(const exportItem of this.exports)for(const alias of exportItem.members){const member=this.getMember(alias.name);void 0!==member&&exported.set(alias.as,member)}return exported}getMember(name){return this.#scope.getMember(name)}getDeclaration(name){return this.#scope.getDeclaration(name)}getFunction(name){return this.#scope.getFunction(name)}getGenerator(name){return this.#scope.getGenerator(name)}getClass(name){return this.#scope.getClass(name)}hasMember(name){return this.#scope.hasMember(name)}hasDeclaration(name){return this.#scope.hasDeclaration(name)}hasFunction(name){return this.#scope.hasFunction(name)}hasGenerator(name){return this.#scope.hasGenerator(name)}hasClass(name){return this.#scope.hasClass(name)}getImport(name){return this.imports.find(importItem=>importItem.hasMember(name))}getImported(name){for(const importItem of this.imports)for(const alias of importItem.members)if(alias.as===name)return this.getMember(alias.name)}isExported(member){for(const exportItem of this.exports)for(const alias of exportItem.members)if(alias.name===member.name)return!0;return!1}getExport(name){return this.exports.find(exportItem=>exportItem.hasMember(name))}getExported(name){for(const exportItem of this.exports)for(const alias of exportItem.members)if(alias.as===name)return this.getMember(alias.name)}#filterExported(members){return members.filter(member=>this.isExported(member))}}class ESObject extends ESValue{}class ESSetter extends ESFunction{toString(){return`set ${super.toString()}`}}const IMPORT_NAME=ESImport.name,EXPORT_NAME=ESExport.name,DECLARATION_NAME=ESDeclaration.name,FUNCTION_NAME=ESFunction.name,GETTER_NAME=ESGetter.name,SETTER_NAME=ESSetter.name,GENERATOR_NAME=ESGenerator.name,CLASS_NAME=ESClass.name;class ESScope{#members;constructor(members){this.#members=members}get members(){return this.#members}get imports(){return this.#members.filter(member=>member.constructor.name===IMPORT_NAME)}get exports(){return this.#members.filter(member=>member.constructor.name===EXPORT_NAME)}get declarations(){return this.#members.filter(member=>member.constructor.name===DECLARATION_NAME)}get functions(){return this.#members.filter(member=>member.constructor.name===FUNCTION_NAME)}get getters(){return this.#members.filter(member=>member.constructor.name===GETTER_NAME)}get setters(){return this.#members.filter(member=>member.constructor.name===SETTER_NAME)}get generators(){return this.#members.filter(member=>member.constructor.name===GENERATOR_NAME)}get classes(){return this.#members.filter(member=>member.constructor.name===CLASS_NAME)}getMember(name){return this.#members.find(member=>member.name===name)}getDeclaration(name){return this.declarations.find(member=>member.name===name)}getFunction(name){return this.functions.find(member=>member.name===name)}getGetter(name){return this.getters.find(member=>member.name===name)}getSetter(name){return this.setters.find(member=>member.name===name)}getGenerator(name){return this.generators.find(member=>member.name===name)}getClass(name){return this.classes.find(member=>member.name===name)}hasMember(name){return void 0!==this.getMember(name)}hasDeclaration(name){return void 0!==this.getDeclaration(name)}hasFunction(name){return void 0!==this.getFunction(name)}hasGetter(name){return void 0!==this.getGetter(name)}hasSetter(name){return void 0!==this.getSetter(name)}hasGenerator(name){return void 0!==this.getGenerator(name)}hasClass(name){return void 0!==this.getClass(name)}toString(){return this.#members.map(member=>member.toString()).join("\n")}}const Comment={SINGLE:"//",MULTI_START:"/*",MULTI_END:"*/"},Comments=Object.values(Comment);const Punctuation_DOT=".",Punctuation_LEFT_PARENTHESIS="(",Punctuation_RIGHT_PARENTHESIS=")",Punctuation_LEFT_BRACKET="[",Punctuation_RIGHT_BRACKET="]",Punctuation_LEFT_BRACE="{",Punctuation_RIGHT_BRACE="}",Divider={SCOPE:":",SEPARATOR:",",TERMINATOR:";"},Divisions=Object.values(Divider);function isDivider(value){return Divisions.includes(value)}const Empty={UNDEFINED:void 0,NULL:null,STRING:""},Empties=Object.values(Empty);function isEmpty(value){return Empties.includes(value)}const Group={OPEN:Punctuation_LEFT_PARENTHESIS,CLOSE:Punctuation_RIGHT_PARENTHESIS};function isGroup(value){return value===Group.OPEN||value===Group.CLOSE}const Keyword={EXPORT:"export",DEFAULT:"default",CLASS:"class",FUNCTION:"function",CONST:"const",LET:"let",VAR:"var",AS:"as",FROM:"from",IMPORT:"import",GET:"get",SET:"set",EXTENDS:"extends",STATIC:"static",ASYNC:"async",RETURN:"return"},Keywords=Object.values(Keyword);function isKeyword(value){return Keywords.includes(value)}function isNotReserved(value){return value===Keyword.AS||value===Keyword.ASYNC||value===Keyword.FROM||value===Keyword.GET||value===Keyword.SET}const List={OPEN:Punctuation_LEFT_BRACKET,CLOSE:Punctuation_RIGHT_BRACKET};function isList(value){return value===List.OPEN||value===List.CLOSE}const Literals=Object.values({SINGLE:"'",DOUBLE:'"',BACKTICK:"`"});function isLiteral(value){return Literals.includes(value)}const Operator={ADD:"+",ARROW:"=>",ASSIGN:"=",ASSIGN_ADD:"+=",ASSIGN_BITWISE_AND:"&=",ASSIGN_BITWISE_OR:"|=",ASSIGN_DIVIDE:"/=",ASSIGN_LEFT_SHIFT:"<<=",ASSIGN_LOGICAL_AND:"&&=",ASSIGN_LOGICAL_OR:"||=",ASSIGN_MODULO:"%=",ASSIGN_MULTIPLY:"*=",ASSIGN_RIGHT_SHIFT:">>=",ASSIGN_SUBTRACT:"-=",ASSIGN_XOR:"^=",BITWISE_AND:"&",BITWISE_OR:"|",DECREMENT:"--",DIVIDE:"/",EQUAL:"==",EQUAL_STRICT:"===",GREATER:">",GREATER_EQUAL:">=",INCREMENT:"++",LEFT_SHIFT:"<<",LESS:"<",LESS_EQUAL:"<=",LOGICAL_AND:"&&",LOGICAL_OR:"||",MODULO:"%",MULTIPLY:"*",NOT:"!",NOT_EQUAL:"!=",NOT_EQUAL_STRICT:"!==",RIGHT_SHIFT:">>",SUBTRACT:"-",TERNARY:"?",XOR:"^"},Operators=Object.values(Operator);function isOperator(value){return Operators.includes(value)}const Scope={OPEN:Punctuation_LEFT_BRACE,CLOSE:Punctuation_RIGHT_BRACE};function isScope(value){return value===Scope.OPEN||value===Scope.CLOSE}const TokenType={COMMENT:"comment",DIVIDER:"divider",GROUP:"group",IDENTIFIER:"identifier",KEYWORD:"keyword",LIST:"list",LITERAL:"literal",OPERATOR:"operator",REGEX:"regex",SCOPE:"scope",WHITESPACE:"whitespace"},Whitespace={SPACE:" ",TAB:"\t",NEWLINE:"\n",CARRIAGE_RETURN:"\r"},Whitespaces=Object.values(Whitespace);function isWhitespace(value){return Whitespaces.includes(value)}class ItemList{#items;#position;constructor(items){this.#items=items,this.#position=0}get items(){return this.#items}get position(){return this.#position}get size(){return this.#items.length}get eol(){return this.#position>=this.#items.length}get current(){return this.#items[this.#position]}get next(){return this.#items[this.#position+1]}get previous(){return this.#items[this.#position-1]}notAtEnd(){return!1===this.eol}get(index){return this.#items[index]}step(amount=1){return this.#position+=amount,this.current}stepBack(amount=1){return this.#position-=amount,this.current}hasNext(){return this.#position+1<this.#items.length}}class CharList extends ItemList{constructor(code){super(code.split(""))}}class Token{#type;#value;#start;#end;constructor(type,value,start,end){this.#type=type,this.#value=value,this.#start=start,this.#end=end}get type(){return this.#type}get value(){return this.#value}get start(){return this.#start}get end(){return this.#end}isType(type){return this.#type===type}hasValue(value){return this.#value===value}toString(){return`${this.#value}`}}class TokenList extends ItemList{}class Lexer{tokenize(code){const charList=new CharList(code),tokens=[];let last;for(;charList.notAtEnd();){const token=this.#getNextToken(charList,last);if(void 0===token)break;token.isType(TokenType.WHITESPACE)||token.isType(TokenType.COMMENT)?charList.step():(tokens.push(token),this.#isCodeToken(token)&&(last=token),charList.step())}return new TokenList(tokens)}#isCodeToken(token){return!1===[TokenType.WHITESPACE,TokenType.COMMENT].includes(token.type)}#getNextToken(charList,lastToken){const char=charList.current,start=charList.position;if(isWhitespace(char)){const end=charList.position;return new Token(TokenType.WHITESPACE,char,start,end)}if(function(value){return Comments.includes(value)}(char+charList.next)){const value=this.#readComment(charList),end=charList.position;return new Token(TokenType.COMMENT,value,start,end)}if(this.#startsRegex(char,lastToken)){const value=this.#readRegex(charList),end=charList.position;return new Token(TokenType.REGEX,value,start,end)}if(isLiteral(char)){const value=this.#readLiteral(charList),end=charList.position;return new Token(TokenType.LITERAL,value,start,end)}if(isOperator(char)){const value=this.#readOperation(charList),end=charList.position;return new Token(TokenType.OPERATOR,value,start,end)}if(isDivider(char)){const end=charList.position;return new Token(TokenType.DIVIDER,char,start,end)}if(isGroup(char)){const end=charList.position;return new Token(TokenType.GROUP,char,start,end)}if(isScope(char)){const end=charList.position;return new Token(TokenType.SCOPE,char,start,end)}if(isList(char)){const end=charList.position;return new Token(TokenType.LIST,char,start,end)}if(isEmpty(char))return;const value=this.#readIdentifier(charList),type=isKeyword(value)?TokenType.KEYWORD:TokenType.IDENTIFIER,end=charList.position;return new Token(type,value,start,end)}#readComment(charList){const isMulti=charList.current+charList.next===Comment.MULTI_START,terminator=isMulti?Comment.MULTI_END:Whitespace.NEWLINE;let value=isMulti?Comment.MULTI_START:Comment.SINGLE;for(charList.step(2);charList.notAtEnd();){const char=charList.current;if((isMulti?char+charList.next:char)===terminator){charList.step(terminator.length-1);break}value+=char,charList.step()}return isMulti?value+Comment.MULTI_END:value.trim()}#startsRegex(char,lastToken){return char===Operator.DIVIDE&&(void 0===lastToken||([TokenType.OPERATOR,TokenType.DIVIDER,TokenType.KEYWORD].includes(lastToken.type)||[Group.OPEN,List.OPEN].includes(lastToken.value)))}#endsRegex(char){return isWhitespace(char)||char==Punctuation_DOT||!1===this.#isIdentifier(char)}#readRegex(charList){let value=charList.current,closed=!1;for(charList.step();charList.notAtEnd();){const current=charList.current,previous=charList.previous;if(current===Operator.DIVIDE&&"\\"!==previous)closed=!0;else if(!0===closed&&this.#endsRegex(current)){charList.stepBack();break}value+=current,charList.step()}return value}#readLiteral(charList){const identifier=charList.current;let value=identifier,escaped=!1;for(charList.step();charList.notAtEnd();){const char=charList.current;if(!1===escaped){if(char===identifier){value+=char;break}"\\"===char&&(escaped=!0)}else escaped=!1;value+=char,charList.step()}return value}#isIdentifier(char){return!1===(isEmpty(char)||isWhitespace(char)||isOperator(char)||isLiteral(char)||isDivider(char)||isGroup(char)||isScope(char)||isList(char))}#readIdentifier(charList){let value="";for(;charList.notAtEnd();){const char=charList.current;if(!1===this.#isIdentifier(char)){charList.stepBack();break}value+=char,charList.step()}return value}#readOperation(charList){let value=charList.current;for(charList.step();charList.notAtEnd();){const char=charList.current;if(!1===isOperator(char)||!1===isOperator(value+char)){charList.stepBack();break}value+=char,charList.step()}return value}}class ExpectedKeyword extends Error{constructor(value,position){super(`Expected keyword '${value}' at position ${position}`)}}class ExpectedToken extends Error{constructor(value,position){super(`Expected token '${value}' at position ${position}`)}}class UnexpectedKeyword extends Error{constructor(keyword,position){super(`Unexpected keyword '${keyword}' at position ${position}`)}}class UnexpectedParseResult extends Error{constructor(expected){super(`The given code does not contain ${expected}`)}}class UnexpectedToken extends Error{constructor(value,position){super(`Unexpected token '${value}' at position ${position}`)}}class Parser{#lexer;constructor(lexer=new Lexer){this.#lexer=lexer}parse(code){const tokenList=this.#lexer.tokenize(code),scope=this.#parseScope(tokenList);return new ESModule(scope)}parseFirst(code){const tokenList=this.#lexer.tokenize(code);return this.#parseNext(tokenList)}parseValue(code){const model=this.parseFirst(code);if(model instanceof ESValue==!1)throw new UnexpectedParseResult("a value definition");return model}parseImport(code){const model=this.parseFirst(code);if(model instanceof ESImport==!1)throw new UnexpectedParseResult("an import definition");return model}parseExport(code){const model=this.parseFirst(code);if(model instanceof ESExport==!1)throw new UnexpectedParseResult("an export definition");return model}parseDeclaration(code){const model=this.parseFirst(code);if(model instanceof ESDeclaration==!1)throw new UnexpectedParseResult("a declaration definition");return model}parseFunction(code){const tokenList=this.#lexer.tokenize(code),model=this.#parseMember(tokenList);if(model instanceof ESFunction==!1)throw new UnexpectedParseResult("a function definition");return model}parseClass(code){const tokenList=this.#lexer.tokenize(code),model=this.#parseMember(tokenList);if(model instanceof ESClass==!1)throw new UnexpectedParseResult("a class definition");return model}#parseScope(tokenList){const members=[];for(;tokenList.notAtEnd();){const member=this.#parseNext(tokenList);member instanceof ESMember&&members.push(member)}return new ESScope(members)}#parseNext(tokenList,isAsync=!1){const token=tokenList.current;if(token.isType(TokenType.LITERAL))return this.#parseExpression(tokenList);if(token.isType(TokenType.IDENTIFIER)){const next=tokenList.next;return next?.hasValue(Operator.ARROW)?this.#parseArrowFunction(tokenList,isAsync):this.#parseExpression(tokenList)}if(token.isType(TokenType.KEYWORD)){if(isNotReserved(token.value)){const next=tokenList.next,nextIsFunction=void 0!==next&&(next.hasValue(Keyword.FUNCTION)||next.hasValue(Group.OPEN));if(token.hasValue(Keyword.ASYNC)&&nextIsFunction)return tokenList.step(),this.#parseNext(tokenList,!0);if(void 0===next||this.#atEndOfStatement(next))return this.#parseExpression(tokenList)}return token.hasValue(Keyword.RETURN)?this.#parseExpression(tokenList):this.#parseMember(tokenList,isAsync)}if(token.isType(TokenType.REGEX))return this.#parseExpression(tokenList);if(token.hasValue(Group.OPEN)){const next=this.#peekAfterBlock(tokenList,Group.OPEN,Group.CLOSE);return next?.hasValue(Operator.ARROW)?this.#parseArrowFunction(tokenList,isAsync):this.#parseExpression(tokenList)}if(token.hasValue(Scope.OPEN))return this.#parseObject(tokenList);if(token.hasValue(List.OPEN))return this.#parseArray(tokenList);if(token.hasValue(Operator.NOT)||token.hasValue(Operator.SUBTRACT))return this.#parseExpression(tokenList);if(!isDivider(token.value))throw new UnexpectedToken(token.value,token.start);tokenList.step()}#parseMember(tokenList,isAsync=!1){const token=tokenList.current;switch(tokenList.step(),token.value){case Keyword.IMPORT:return this.#parseImport(tokenList);case Keyword.EXPORT:return this.#parseExport(tokenList);case Keyword.CLASS:return this.#parseClass(tokenList);case Keyword.FUNCTION:return this.#parseFunction(tokenList,isAsync);case Keyword.VAR:case Keyword.LET:case Keyword.CONST:return this.#parseDeclaration(tokenList,!1,!0);case Keyword.ASYNC:return this.#parseMember(tokenList,!0);default:throw new UnexpectedKeyword(token.value,token.start)}}#parseImport(tokenList){const members=[];let token=tokenList.current;if(token.isType(TokenType.LITERAL))return new ESImport(members,token.value);if(token.hasValue(Group.OPEN)){token=tokenList.step();const from=token.value;return tokenList.step(2),new ESImport(members,from)}if(!1===token.hasValue(Scope.OPEN)){const name=token.hasValue(Operator.MULTIPLY)?Operator.MULTIPLY:"default";let as=token.value;token=tokenList.step(),token.hasValue(Keyword.AS)&&(token=tokenList.step(),as=token.value,token=tokenList.step()),members.push(new ESAlias(name,as))}if(token.hasValue(Divider.SEPARATOR)&&(token=tokenList.step()),token.hasValue(Scope.OPEN)){const aliases=this.#parseAliasList(tokenList);members.push(...aliases),token=tokenList.current}if(!1===token.hasValue(Keyword.FROM))throw new ExpectedKeyword(Keyword.FROM,token.start);token=tokenList.step();const from=token.value;return tokenList.step(),new ESImport(members,from)}#parseExport(tokenList){switch(tokenList.current.value){case Keyword.DEFAULT:return tokenList.step(),this.#parseSingleExport(tokenList,!0);case Scope.OPEN:return this.#parseMultiExport(tokenList);default:return this.#parseSingleExport(tokenList,!1)}}#parseSingleExport(tokenList,isDefault){let token=tokenList.current,stepSize=0;var value;token.hasValue(Keyword.ASYNC)&&(token=tokenList.step(),stepSize++),((value=token.value)===Keyword.CLASS||value===Keyword.FUNCTION||value===Keyword.CONST||value===Keyword.LET||value===Keyword.VAR)&&(token=tokenList.step(),stepSize++);const name=this.#isIdentifier(token)?token.value:"",as=isDefault?"default":name;let from;token=tokenList.step(),token?.hasValue(Keyword.FROM)&&(token=tokenList.step(),from=token.value),stepSize>0&&(stepSize++,tokenList.stepBack(stepSize));const alias=new ESAlias(name,as);return new ESExport([alias],from)}#parseMultiExport(tokenList){const members=this.#parseAliasList(tokenList);let from,token=tokenList.current;return token?.hasValue(Keyword.FROM)&&(token=tokenList.step(),from=token.value),tokenList.step(),new ESExport(members,from)}#parseAliasList(tokenList){const aliases=[];let token=tokenList.step();for(;tokenList.notAtEnd();){if(token.hasValue(Scope.CLOSE)){tokenList.step();break}if(token.hasValue(Divider.SEPARATOR)){token=tokenList.step();continue}const alias=this.#parseAlias(tokenList);aliases.push(alias),token=tokenList.step()}return aliases}#parseAlias(tokenList){let token=tokenList.current;const name=token.value;let as=name;return tokenList.next.hasValue(Keyword.AS)&&(token=tokenList.step(2),as=token.value),new ESAlias(name,as)}#parseDeclaration(tokenList,isStatic,parseMultiple=!1){let identifier,value,token=tokenList.current,isPrivate=!1;return token.hasValue(List.OPEN)?(identifier=this.#parseDestructuredArray(tokenList),token=tokenList.current):token.hasValue(Scope.OPEN)?(identifier=this.#parseDestructuredObject(tokenList),token=tokenList.current):(isPrivate=token.value.startsWith("#"),identifier=isPrivate?token.value.substring(1):token.value,token=tokenList.step()),token.hasValue(Operator.ASSIGN)&&(tokenList.step(),value=this.#parseNext(tokenList,!1),token=tokenList.current),void 0!==token&&(token.hasValue(Divider.TERMINATOR)?tokenList.step():!0===parseMultiple&&token.hasValue(Divider.SEPARATOR)&&(tokenList.step(),this.#parseDeclaration(tokenList,isStatic,!0))),value instanceof ESGenerator?new ESGenerator(identifier.toString(),value.parameters,value.body,isStatic,value.isAsync,isPrivate):value instanceof ESFunction?new ESFunction(identifier.toString(),value.parameters,value.body,isStatic,value.isAsync,isPrivate):value instanceof ESClass?new ESClass(identifier.toString(),value.parentName,value.scope):new ESDeclaration(identifier,value,isStatic,isPrivate)}#parseFunction(tokenList,isAsync,isStatic=!1,isGetter=!1,isSetter=!1){let token=tokenList.current,name="",isGenerator=!1,isPrivate=!1;token.hasValue(Operator.MULTIPLY)&&(isGenerator=!0,token=tokenList.step()),this.#isIdentifier(token)&&(isPrivate=token.value.startsWith("#"),name=isPrivate?token.value.substring(1):token.value,token=tokenList.step());const parameters=this.#parseParameters(tokenList,Group.CLOSE);if(token=tokenList.current,!1===token.hasValue(Scope.OPEN))throw new ExpectedToken(Scope.OPEN,token.start);const body=this.#parseBlock(tokenList,Scope.OPEN,Scope.CLOSE);return isGenerator?new ESGenerator(name,parameters,body,isStatic,isAsync,isPrivate):isGetter?new ESGetter(name,parameters,body,isStatic,isAsync,isPrivate):isSetter?new ESSetter(name,parameters,body,isStatic,isAsync,isPrivate):new ESFunction(name,parameters,body,isStatic,isAsync,isPrivate)}#parseArrowFunction(tokenList,isAsync){let parameters,token=tokenList.current;if(token.hasValue(Group.OPEN)?(parameters=this.#parseParameters(tokenList,Group.CLOSE),token=tokenList.current):(parameters=[new ESField(token.value,void 0)],token=tokenList.step()),!1===token.hasValue(Operator.ARROW))throw new ExpectedToken(Operator.ARROW,token.start);token=tokenList.step();const body=token.hasValue(Scope.OPEN)?this.#parseBlock(tokenList,Scope.OPEN,Scope.CLOSE):this.#parseExpression(tokenList).definition;return new ESFunction("",parameters,body,!1,isAsync,!1)}#parseParameters(tokenList,closeId){const parameters=[];for(tokenList.step();tokenList.notAtEnd();){const token=tokenList.current;if(token.hasValue(closeId)){tokenList.step();break}if(token.hasValue(Divider.SEPARATOR)){tokenList.step();continue}let parameter;parameter=token.hasValue(Scope.OPEN)?this.#parseDestructuredObject(tokenList):token.hasValue(List.OPEN)?this.#parseDestructuredArray(tokenList):this.#parseField(tokenList),parameters.push(parameter)}return parameters}#parseClass(tokenList){let parent,token=tokenList.current,name="";if(this.#isIdentifier(token)&&(name=token.value,token=tokenList.step()),token.hasValue(Keyword.EXTENDS)&&(token=tokenList.step(),parent=token.value,token=tokenList.step()),!1===token.hasValue(Scope.OPEN))throw new ExpectedToken(Scope.OPEN,token.start);const scope=this.#parseClassScope(tokenList);return new ESClass(name,parent,scope)}#parseClassScope(tokenList){let token=tokenList.step();const members=[];for(;tokenList.notAtEnd();){if(token.hasValue(Scope.CLOSE)){tokenList.step();break}const member=this.#parseClassMember(tokenList);members.push(member),token=tokenList.current}return new ESScope(members)}#parseClassMember(tokenList){let token=tokenList.current,isAsync=!1,isStatic=!1,isGetter=!1,isSetter=!1;for(;tokenList.notAtEnd();){if(token.hasValue(Keyword.STATIC))isStatic=!0;else if(token.hasValue(Keyword.ASYNC))isAsync=!0;else if(token.hasValue(Keyword.GET))isGetter=!0;else{if(!token.hasValue(Keyword.SET)){if(token.hasValue(Operator.MULTIPLY))return this.#parseFunction(tokenList,isAsync,isStatic,!1,!1);break}isSetter=!0}token=tokenList.step()}return tokenList.next.hasValue(Group.OPEN)?this.#parseFunction(tokenList,isAsync,isStatic,isGetter,isSetter):this.#parseDeclaration(tokenList,isStatic)}#parseArray(tokenList){const items=this.#parseBlock(tokenList,List.OPEN,List.CLOSE);return new ESArray(items)}#parseDestructuredArray(tokenList){const fields=this.#parseParameters(tokenList,List.CLOSE);return new ESDestructuredArray(fields)}#parseObject(tokenList){const fields=this.#parseBlock(tokenList,Scope.OPEN,Scope.CLOSE);return new ESObject(fields)}#parseDestructuredObject(tokenList){const fields=this.#parseParameters(tokenList,Scope.CLOSE);return new ESDestructuredObject(fields)}#parseField(tokenList){let token=tokenList.current;const name=token.value;let value;return token=tokenList.step(),token.hasValue(Operator.ASSIGN)&&(tokenList.step(),value=this.#parseNext(tokenList,!1)),new ESField(name,value)}#parseExpression(tokenList){let token=tokenList.current,code="";for(;tokenList.notAtEnd();){if(token.hasValue(List.OPEN)){code+=this.#parseBlock(tokenList,List.OPEN,List.CLOSE)+" ",token=tokenList.current}else if(token.hasValue(Group.OPEN)){code+=this.#parseBlock(tokenList,Group.OPEN,Group.CLOSE)+" ",token=tokenList.current}else if(token.hasValue(Scope.OPEN)){code+=this.#parseBlock(tokenList,Scope.OPEN,Scope.CLOSE)+" ",token=tokenList.current}else code+=token.toString()+" ",token=tokenList.step();if(void 0===token||this.#atEndOfStatement(token))break}return new ESExpression(code.trim())}#parseBlock(tokenList,openId,closeId){let token=tokenList.step(),code=openId+" ";for(;tokenList.notAtEnd();)if(token.hasValue(openId))code+=this.#parseBlock(tokenList,openId,closeId)+" ",token=tokenList.current;else{if(token.hasValue(closeId))return tokenList.step(),code+=closeId,code;code+=token.toString()+" ",token=tokenList.step()}return code}#peekAfterBlock(tokenList,openId,closeId){const start=tokenList.position;this.#parseBlock(tokenList,openId,closeId);const token=tokenList.current,end=tokenList.position;return tokenList.stepBack(end-start),token}#atEndOfStatement(token){return[Divider.TERMINATOR,Divider.SEPARATOR].includes(token.value)||[List.CLOSE,Group.CLOSE,Scope.CLOSE].includes(token.value)||isKeyword(token.value)}#isIdentifier(token){return token.isType(TokenType.IDENTIFIER)||token.isType(TokenType.KEYWORD)&&isNotReserved(token.value)}}class ClassMerger{merge(model,parent){const declarations=this.#mergeDeclarations(model.declarations,parent.declarations),functions=this.#mergeFunctions(model.functions,parent.functions),getters=this.#mergeFunctions(model.getters,parent.getters),setters=this.#mergeFunctions(model.setters,parent.setters),members=[...declarations.values(),...functions.values(),...getters.values(),...setters.values()];return new ESClass(model.name,parent.name,new ESScope(members))}#mergeDeclarations(model,parent){const declarations=new Map;return parent.forEach(declaration=>declarations.set(declaration.name,declaration)),model.forEach(declaration=>declarations.set(declaration.name,declaration)),[...declarations.values()]}#mergeFunctions(model,parent){const functions=new Map;return parent.forEach(funktion=>functions.set(funktion.name,funktion)),model.forEach(funktion=>functions.set(funktion.name,funktion)),[...functions.values()]}}class Reflector{#parser=new Parser;#merger=new ClassMerger;fromModule(module,inherit=!1){const entries=Object.entries(module),members=[];for(const[key,member]of entries){if("function"!=typeof member.toString)continue;const code=member.toString();if(code.startsWith("class"))members.push(this.fromClass(member,inherit));else if(code.startsWith("function"))members.push(this.fromFunction(member));else{const expression=new ESExpression(code);members.push(new ESDeclaration(key,expression))}}return new ESModule(new ESScope(members))}fromClass(clazz,inherit=!1){const model=this.isClass(clazz)?this.#reflectStatic(clazz):this.#reflectDynamic(clazz);if(!1===inherit)return model;const parentClazz=this.getParentClass(clazz);if(""===parentClazz.name)return model;const parentModel=this.fromClass(parentClazz,!0);return this.#merger.merge(model,parentModel)}fromObject(object,inherit=!0){const clazz=this.getClass(object);return this.fromClass(clazz,inherit)}fromFunction(funktion){const code=funktion.toString();return this.#parser.parseFunction(code)}createInstance(clazz,args=[]){return new clazz(...args)}getClass(object){return object.constructor}getParentClass(clazz){return Object.getPrototypeOf(clazz)}isClassObject(object){return this.isClass(object.constructor)}isFunctionObject(object){return this.isFunction(object.constructor)}isClass(clazz){return clazz.toString().startsWith("class")}isFunction(clazz){return clazz.toString().startsWith("function")||clazz.toString().startsWith("async function")}#reflectStatic(clazz){const code=clazz.toString();return this.#parser.parseClass(code)}#reflectDynamic(clazz){const object=this.createInstance(clazz),members=this.#getMembers(clazz,object),scope=new ESScope(members);return new ESClass(clazz.name,void 0,scope)}#getMembers(clazz,object){return[...this.#getDeclarations(object),...this.#getFunctions(clazz)]}#getDeclarations(object){const fieldNames=Object.getOwnPropertyNames(object),values=object,models=[];for(const fieldName of fieldNames){const content=values[fieldName],value=void 0!==content?new ESValue(String(content)):void 0,model=new ESDeclaration(fieldName,value);models.push(model)}return models}#getFunctions(clazz){const functionDescriptions=Object.getOwnPropertyDescriptors(clazz.prototype),models=[];for(const functionName in functionDescriptions){const description=functionDescriptions[functionName],funktion=description.value;if(funktion instanceof Function==!1)continue;const model=this.fromFunction(funktion);void 0!==description.get?models.push(new ESGetter(model.name,model.parameters,model.body,model.isStatic,model.isAsync,model.isPrivate)):void 0!==description.set?models.push(new ESSetter(model.name,model.parameters,model.body,model.isStatic,model.isAsync,model.isPrivate)):models.push(model)}return models}}const reflector$1=new Reflector;class ClassSerializer extends ValueSerializer{#classResolver;constructor(classResolver){super(),this.#classResolver=classResolver}canSerialize(value){return value instanceof Object&&reflector$1.isClassObject(value)}canDeserialize(value){const object=value;return object instanceof Object&&!0===object.serialized&&"class"===object.name&&"string"==typeof object.key&&object.args instanceof Object&&object.args.constructor===Object&&object.fields instanceof Object&&object.fields.constructor===Object}async serialize(object){const clazz=reflector$1.getClass(object),model=reflector$1.fromClass(clazz,!0),parameterNames=this.#extractConstructorParameters(model),key=this.#classResolver.resolveKey(clazz);if(void 0===key)throw new ClassNotFound(clazz.name);return{serialized:!0,key:key,name:"class",args:await this.#serializeConstructor(model,parameterNames,object),fields:await this.#serializeFields(model,parameterNames,object)}}#extractConstructorParameters(model){const constructor=model.getFunction("constructor");return(constructor?.parameters??[]).map(parameter=>parameter.name)}async#serializeConstructor(model,includeNames,object){const args={};for(const[index,name]of includeNames.entries()){const value=model.canRead(name)?await this.serializeOther(object[name]):void 0;args[index.toString()]=value}return args}async#serializeFields(model,excludeNames,object){const fields={};for(const property of model.writable){const name=property.name;excludeNames.includes(name)||!1===model.canRead(name)||(fields[name]=await this.serializeOther(object[name]))}return fields}async deserialize(object){const clazz=await this.#getClass(object);if(void 0===clazz)throw new ClassNotFound(object.key);if(clazz instanceof Function==!1)throw new InvalidClass(object.key);const args=await this.#deserializeConstructor(clazz,object.args),instance=reflector$1.createInstance(clazz,args);for(const name in object.fields){const fieldValue=object.fields[name];instance[name]=await this.deserializeOther(fieldValue)}return instance}async#deserializeConstructor(clazz,args){const constructor=reflector$1.fromClass(clazz,!0).getFunction("constructor"),values=(constructor?.parameters??[]).map((_,index)=>{const key=index.toString(),value=args[key];return this.deserializeOther(value)});return Promise.all(values)}async#getClass(resolvable){return globalThis[resolvable.key]??this.#classResolver.resolveClass(resolvable.key)}}class InvalidDateString extends Error{constructor(dateString){super(`Invalid date string '${dateString}'`)}}class DateSerializer extends ValueSerializer{canSerialize(value){return value instanceof Date}canDeserialize(value){const date=value;return date instanceof Object&&!0===date.serialized&&"Date"===date.name&&"string"==typeof date.value}async serialize(date){return{serialized:!0,name:"Date",value:date.toISOString()}}async deserialize(object){const date=new Date(object.value);if("Invalid Date"===date.toString())throw new InvalidDateString(object.value);return date}}class ErrorSerializer extends ValueSerializer{canSerialize(value){if(value instanceof Object==!1)return!1;const error=value;return error.constructor===Error||error.constructor===EvalError||error.constructor===RangeError||error.constructor===ReferenceError||error.constructor===SyntaxError||error.constructor===TypeError||error.constructor===URIError||error.constructor===AggregateError}canDeserialize(value){const error=value;return error instanceof Object&&!0===error.serialized&&"Error"===error.name&&error.type in globalThis}async serialize(error){return{serialized:!0,name:"Error",type:error.constructor.name,stack:error.stack,message:error.message,cause:error.cause}}async deserialize(object){const error=new(0,globalThis[object.type])(object.message,{cause:object.cause});return error.stack=object.stack,error}}class MapSerializer extends ValueSerializer{canSerialize(value){return value instanceof Map}canDeserialize(value){const map=value;return map instanceof Object&&!0===map.serialized&&"Map"===map.name&&map.entries instanceof Object&&map.entries.keys instanceof Array&&map.entries.values instanceof Array}async serialize(map){const keys=[],values=[];for(const[key,value]of map)keys.push(await this.serializeOther(key)),values.push(await this.serializeOther(value));return{serialized:!0,name:"Map",entries:{keys:keys,values:values}}}async deserialize(object){const keys=object.entries.keys,values=object.entries.values,result=new Map;for(let index=0;index<keys.length;index++){const key=await this.deserializeOther(keys[index]),value=await this.deserializeOther(values[index]);result.set(key,value)}return result}}class ObjectSerializer extends ValueSerializer{canSerialize(value){return value instanceof Object&&value.constructor===Object}canDeserialize(value){return value instanceof Object&&value.constructor===Object}async serialize(object){const result={};for(const key in object){const value=object[key];result[key]=await this.serializeOther(value)}return result}async deserialize(object){const result={};for(const key in object){const value=object[key];result[key]=await this.deserializeOther(value)}return result}}class PrimitiveSerializer extends ValueSerializer{canSerialize(value){return value instanceof Object==!1}canDeserialize(value){return value instanceof Object==!1}async serialize(primitive){return primitive}async deserialize(primitive){return primitive}}class InvalidRegExp extends Error{constructor(source,flags){super(`Invalid regular expression '${source}' with flags '${flags}'`)}}class RegExpSerializer extends ValueSerializer{canSerialize(value){return value instanceof RegExp}canDeserialize(value){const regExp=value;return regExp instanceof Object&&!0===regExp.serialized&&"RegExp"===regExp.name&&"string"==typeof regExp.source&&"string"==typeof regExp.flags}async serialize(regExp){return{serialized:!0,name:"RegExp",source:regExp.source,flags:regExp.flags}}async deserialize(object){try{return new RegExp(object.source,object.flags)}catch{throw new InvalidRegExp(object.source,object.flags)}}}class SetSerializer extends ValueSerializer{canSerialize(value){return value instanceof Set}canDeserialize(value){const set=value;return set instanceof Object&&!0===set.serialized&&"Set"===set.name&&set.values instanceof Array}async serialize(set){const values=[];for(const value of set.values())values.push(await this.serializeOther(value));return{serialized:!0,name:"Set",values:values}}async deserialize(object){const values=await Promise.all(object.values.map(async value=>this.deserializeOther(value)));return new Set([...values])}}const reflector=new Reflector;class ArrayBufferSerializer extends ValueSerializer{canSerialize(value){return value instanceof Int8Array||value instanceof Uint8Array||value instanceof Uint8ClampedArray||value instanceof Int16Array||value instanceof Uint16Array||value instanceof Int32Array||value instanceof Uint32Array||value instanceof Float32Array||value instanceof Float64Array||value instanceof BigInt64Array||value instanceof BigUint64Array}canDeserialize(value){const array=value;return array instanceof Object&&!0===array.serialized&&"TypedArray"===array.name&&array.type in globalThis&&array.bytes instanceof Array}async serialize(array){const type=array.constructor.name,view=new DataView(array.buffer),bytes=[];for(let index=0;index<view.byteLength;index++)bytes.push(view.getUint8(index));return{serialized:!0,name:"TypedArray",type:type,bytes:bytes}}async deserialize(object){const type=object.type,bytes=object.bytes,buffer=new ArrayBuffer(bytes.length),view=new DataView(buffer);for(let index=0;index<bytes.length;index++)view.setUint8(index,bytes[index]);const clazz=globalThis[type];return reflector.createInstance(clazz,[buffer])}}class InvalidUrlString extends Error{constructor(urlString){super(`Invalid url string '${urlString}'`)}}class UrlSerializer extends ValueSerializer{canSerialize(value){return value instanceof URL}canDeserialize(value){const url=value;return url instanceof Object&&!0===url.serialized&&"Url"===url.name&&"string"==typeof url.value}async serialize(url){return{serialized:!0,name:"Url",value:url.toString()}}async deserialize(object){try{return new URL(object.value)}catch{throw new InvalidUrlString(object.value)}}}class SerializerBuilder{static build(classResolver){const serializer=new Serializer;return serializer.addSerializer(new PrimitiveSerializer),serializer.addSerializer(new ObjectSerializer),void 0!==classResolver&&serializer.addSerializer(new ClassSerializer(classResolver)),serializer.addSerializer(new ErrorSerializer),serializer.addSerializer(new RegExpSerializer),serializer.addSerializer(new BigIntSerializer),serializer.addSerializer(new UrlSerializer),serializer.addSerializer(new DateSerializer),serializer.addSerializer(new SetSerializer),serializer.addSerializer(new MapSerializer),serializer.addSerializer(new ArraySerializer),serializer.addSerializer(new ArrayBufferSerializer),"undefined"!=typeof Buffer&&serializer.addSerializer(new BufferSerializer),serializer}}class ExecutionClassResolver{#executionManager;constructor(executionManager){this.#executionManager=executionManager}resolveKey(clazz){const model=this.#executionManager.getClassByImplementation(clazz);return model?.fqn}resolveClass(key){const model=this.#executionManager.getClass(key);return model?.implementation}}class RequestNotTrusted extends Unauthorized{constructor(){super("Request not trusted")}}class LocalWorker{#id;#url;#trustKey;#gateway;#registerAtGateway;#executionManager;#serializer;constructor(configuration){this.#url=configuration.url,this.#trustKey=configuration.trustKey,this.#gateway=configuration.gateway,this.#registerAtGateway=!0===configuration.registerAtGateway,this.#executionManager=configuration.executionManager;const classResolver=new ExecutionClassResolver(this.#executionManager);this.#serializer=SerializerBuilder.build(classResolver)}get id(){return this.#id}set id(id){this.#id=id}get url(){return this.#url}get trustKey(){return this.#trustKey}async start(){await this.#executionManager.start(),void 0!==this.#gateway&&(await this.#gateway.start(),this.#registerAtGateway&&(this.#id=await this.#gateway.addWorker(this)))}async stop(){void 0!==this.#gateway&&(void 0!==this.#id&&await this.#gateway.removeWorker(this),await this.#gateway.stop()),await this.#executionManager.stop()}getProcedureNames(){return this.#executionManager.getProcedureNames()}hasProcedure(name){return this.#executionManager.hasProcedure(name)}async isHealthy(){return!0}async getHealth(){return new Map}async run(request){return this.#mustRunLocal(request)?this.#runLocal(request):this.#runRemote(request)}#mustRunLocal(request){return void 0===this.#gateway||this.#executionManager.hasProcedure(request.fqn)}async#runLocal(request){const procedure=this.#executionManager.getProcedure(request.fqn),implementation=procedure?.getImplementation(request.version);if(this.#procedureNotFound(implementation))throw new ProcedureNotFound(request.fqn);if(this.#requestNotTrusted(request,implementation))throw new RequestNotTrusted;const dataEncoding=request.getHeader("X-Jitar-Data-Encoding");"serialized"===dataEncoding&&(request=await this.#deserializeRequest(request)),request.removeHeader("X-Jitar-Data-Encoding");const response=await this.#executionManager.run(request);return"serialized"===dataEncoding?this.#serializeResponse(response):response}#procedureNotFound(implementation){return void 0===implementation||implementation.private}#requestNotTrusted(request,implementation){if(implementation.public)return!1;const trustKey=request.getHeader("X-Jitar-Trust-Key");return this.#trustKey!==trustKey}async#runRemote(request){(request=await this.#serializeRequest(request)).setHeader("X-Jitar-Data-Encoding","serialized"),void 0!==this.#trustKey&&request.setHeader("X-Jitar-Trust-Key",this.#trustKey);const response=await this.#gateway.run(request);return this.#deserializeResponse(response)}async#serializeRequest(request){const serializedArgs=new Map;for(const[key,value]of request.args){const serializedValue=await this.#serializer.serialize(value);serializedArgs.set(key,serializedValue)}return new Request(request.fqn,request.version,serializedArgs,request.headers,request.mode)}async#deserializeRequest(request){const deserializedArgs=new Map;for(const[key,value]of request.args){const deserializedValue=await this.#serializer.deserialize(value);deserializedArgs.set(key,deserializedValue)}return new Request(request.fqn,request.version,deserializedArgs,request.headers,request.mode)}async#serializeResponse(response){const serializedResult=await this.#serializer.serialize(response.result);return new Response(response.status,serializedResult,response.headers)}async#deserializeResponse(response){const deserializedResult=await this.#serializer.deserialize(response.result);return new Response(response.status,deserializedResult,response.headers)}}class ProcedureRunner{#runner;constructor(runner){this.#runner=runner}async handle(request,next){return this.#runner.run(request)}}class Runtime{#versionParser=new VersionParser;constructor(){this.#initGlobals()}#initGlobals(){const globals=globalThis;globals.__run=this.#run.bind(this),globals.ProcedureNotAccessible=ProcedureNotAccessible}async#run(fqn,versionNumber,args,sourceRequest){const version=this.#versionParser.parse(versionNumber),argsMap=new Map(Object.entries(args)),headersMap=sourceRequest instanceof Request?sourceRequest.headers:new Map,targetRequest=new Request(fqn,version,argsMap,headersMap,RunModes_NORMAL),trustKey=this.getTrustKey();void 0!==trustKey&&targetRequest.setHeader("X-Jitar-Trust-Key",trustKey);const targetResponse=await this.runInternal(targetRequest);if(targetResponse.status!==StatusCodes_OK)throw targetResponse.result;return targetResponse.result}}class Client extends Runtime{#worker;#middlewareManager;constructor(configuration){super(),this.#worker=new LocalWorker({url:configuration.remoteUrl,gateway:new RemoteGateway({url:configuration.remoteUrl,remote:configuration.remote}),executionManager:configuration.executionManager}),this.#middlewareManager=configuration.middlewareManager}get worker(){return this.#worker}start(){return this.#setUp()}stop(){return this.#tearDown()}getTrustKey(){}run(request){return this.runInternal(request)}runInternal(request){return this.#middlewareManager.handle(request)}async#setUp(){await Promise.all([this.#worker.start(),this.#middlewareManager.start()]);const procedureRunner=new ProcedureRunner(this.#worker);this.#middlewareManager.addMiddleware(procedureRunner)}async#tearDown(){await Promise.all([this.#middlewareManager.stop(),this.#worker.stop()])}}class InvalidMiddleware extends ServerError{constructor(){super("Invalid middleware")}}class MiddlewareManager{#moduleImporter;#middlewareFiles;#middlewares=[];constructor(moduleImporter,middlewareFiles=[]){this.#moduleImporter=moduleImporter,this.#middlewareFiles=middlewareFiles}async start(){return this.#loadMiddlewares()}async stop(){return this.clearMiddlewares()}async loadMiddleware(filename){const middleware=await this.#loadMiddleware(filename);this.addMiddleware(middleware)}addMiddleware(middleware){if(void 0===middleware?.handle)throw new InvalidMiddleware;this.#middlewares.push(middleware)}getMiddleware(type){return this.#middlewares.find(middleware=>middleware instanceof type)}clearMiddlewares(){this.#middlewares=[]}handle(request){return this.#getNextHandler(request,0)()}async#loadMiddlewares(){(await Promise.all(this.#middlewareFiles.map(filename=>this.#loadMiddleware(filename)))).forEach(middleware=>this.addMiddleware(middleware))}async#loadMiddleware(filename){return(await this.#moduleImporter.import(filename)).default}#getNextHandler(request,index){const next=this.#middlewares[index];if(void 0===next)return async()=>new Response(StatusCodes_OK);const nextHandler=this.#getNextHandler(request,index+1);return async()=>next.handle(request,nextHandler)}}class ClientBuilder{#remoteBuilder;constructor(remoteBuilder){this.#remoteBuilder=remoteBuilder}build(configuration){const remoteUrl=configuration.remoteUrl,middleware=configuration.middleware,segments=configuration.segments,remote=this.#remoteBuilder.build(remoteUrl),sourcingManager=new RemoteSourcingManager(remoteUrl),middlewareManager=this.#buildMiddlewareManager(sourcingManager,middleware),executionManager=this.#buildExecutionManager(sourcingManager,segments);return new Client({remoteUrl:remoteUrl,remote:remote,middlewareManager:middlewareManager,executionManager:executionManager})}#buildMiddlewareManager(sourcingManager,middleware=[]){const manager=new MiddlewareManager(sourcingManager);return middleware.forEach(middleware=>manager.addMiddleware(middleware)),manager}#buildExecutionManager(sourcingManager,segments=[]){const manager=new ExecutionManager(sourcingManager);return segments.forEach(segment=>manager.addSegment(segment)),manager}}class Validator{#strict;constructor(strict=!0){this.#strict=strict}validate(data,scheme){const errors=[];this.#validateData("",data,scheme,errors);return{valid:0===errors.length,errors:errors}}#validateData(key,data,scheme,errors){this.#strict&&this.#validateKeys(key,data,scheme,errors),this.#validateValues(key,data,scheme,errors)}#validateKeys(key,data,scheme,errors){const dataKeys=Object.keys(data),schemeKeys=Object.keys(scheme);for(const dataKey of dataKeys)if(!1===schemeKeys.includes(dataKey)){const absoluteKey=this.#composeKey(key,dataKey);errors.push(`Unknown field '${absoluteKey}'`)}}#validateValues(key,data,scheme,errors){const valueKeys=Object.keys(scheme);for(const valueKey of valueKeys){const absoluteKey=this.#composeKey(key,valueKey),fieldScheme=scheme[valueKey],value=data[valueKey];this.#validateValue(absoluteKey,value,fieldScheme,errors)}}#validateValue(key,value,scheme,errors){if(void 0!==value)switch(scheme.type){case"string":return this.#validateString(key,value,scheme,errors);case"integer":return this.#validateInteger(key,value,scheme,errors);case"real":return this.#validateReal(key,value,scheme,errors);case"boolean":return this.#validateBoolean(key,value,scheme,errors);case"url":return this.#validateUrl(key,value,scheme,errors);case"group":return this.#validateGroup(key,value,scheme,errors);case"list":return this.#validateList(key,value,scheme,errors)}else!0===scheme.required&&errors.push(`Field '${key}' is required`)}#validateString(key,value,scheme,errors){"string"!=typeof value&&errors.push(`Field '${key}' is not a string`)}#validateInteger(key,value,scheme,errors){"number"==typeof value&&!1!==Number.isInteger(value)||errors.push(`Field '${key}' is not an integer`)}#validateReal(key,value,scheme,errors){"number"!=typeof value&&errors.push(`Field '${key}' is not a real number`)}#validateBoolean(key,value,scheme,errors){"boolean"!=typeof value&&errors.push(`Field '${key}' is not a boolean`)}#validateUrl(key,value,scheme,errors){"string"==typeof value&&!1!==value.startsWith("http")||errors.push(`Field '${key}' is not a valid URL`)}#validateGroup(key,value,scheme,errors){"object"==typeof value?this.#validateData(key,value,scheme.fields,errors):errors.push(`Field '${key}' is not an object`)}#validateList(key,value,scheme,errors){if(!Array.isArray(value))return void errors.push(`Field '${key}' is not a list`);const data=value;for(const itemIndex in data){const itemKey=this.#composeKey(key,itemIndex),itemValue=data[itemIndex];this.#validateValue(itemKey,itemValue,scheme.items,errors)}}#composeKey(parent,key){return""===parent?key:`${parent}.${key}`}}const HeaderKeys_CONTENT_TYPE="content-type",HeaderKeys_JITAR_CONTENT_TYPE="x-jitar-content-type",HeaderKeys_JITAR_PROCEDURE_VERSION="x-jitar-procedure-version",HeaderValues_APPLICATION_JSON="application/json",HeaderValues_APPLICATION_STREAM="application/octet-stream";class InvalidWorkerId extends Error{constructor(){super("Invalid worker id")}}class HttpRemote{#url;#httpClient;#errorConverter=new ErrorConverter;#validator=new Validator;constructor(url,httpClient){this.#url=url,this.#httpClient=httpClient}connect(){return Promise.resolve()}disconnect(){return Promise.resolve()}async provide(filename){const remoteUrl=`${this.#url}/${filename}`,response=await this.#callRemote(remoteUrl,{method:"GET"}),type=response.headers.get(HeaderKeys_CONTENT_TYPE)??HeaderValues_APPLICATION_STREAM,result=await response.arrayBuffer(),content=Buffer.from(result);return new File(filename,type,content)}async isHealthy(){const remoteUrl=`${this.#url}/health/status`,response=await this.#callRemote(remoteUrl,{method:"GET"});return"true"===await response.text()}async getHealth(){const remoteUrl=`${this.#url}/health`,response=await this.#callRemote(remoteUrl,{method:"GET"}),health=await response.json();return new Map(Object.entries(health))}async addWorker(url,procedureNames,trustKey){const remoteUrl=`${this.#url}/workers`,body={url:url,procedureNames:procedureNames,trustKey:trustKey},options={method:"POST",headers:{"Content-Type":HeaderValues_APPLICATION_JSON},body:JSON.stringify(body)},response=await this.#callRemote(remoteUrl,options),contentType=response.headers.get(HeaderKeys_CONTENT_TYPE);if(null===contentType||!1===contentType.includes(HeaderValues_APPLICATION_JSON))throw new InvalidWorkerId;const result=await response.json();if(!1===this.#validator.validate(result,{id:{type:"string",required:!0}}).valid)throw new InvalidWorkerId;return result.id}async removeWorker(id){const remoteUrl=`${this.#url}/workers/${id}`,options={method:"DELETE",headers:{"Content-Type":HeaderValues_APPLICATION_JSON}};await this.#callRemote(remoteUrl,options)}async run(request){request.setHeader(HeaderKeys_CONTENT_TYPE,HeaderValues_APPLICATION_JSON);const argsObject=Object.fromEntries(request.args),headersObject=Object.fromEntries(request.headers),versionString=request.version.toString();headersObject[HeaderKeys_JITAR_PROCEDURE_VERSION]=versionString;const remoteUrl=`${this.#url}/rpc/${request.fqn}`,options={method:"POST",redirect:"manual",headers:headersObject,body:await this.#createRequestBody(argsObject)},response=await this.#callRemote(remoteUrl,options,!1),status=response.status,result=await this.#getResponseResult(response),headers=this.#createResponseHeaders(response);return new Response(status,result,headers)}async#callRemote(remoteUrl,options,throwOnError=!0){const response=await this.#httpClient.execute(remoteUrl,options);if(throwOnError&&this.#isErrorResponse(response)){const result=await this.#getResponseResult(response);throw this.#errorConverter.fromStatus(response.status,String(result))}return response}#isErrorResponse(response){return response.status<200||response.status>399}async#createRequestBody(body){return JSON.stringify(body)}async#getResponseResult(response){const contentType=response.headers.get(HeaderKeys_JITAR_CONTENT_TYPE)??response.headers.get(HeaderKeys_CONTENT_TYPE);if(contentType?.includes("undefined"))return;if(contentType?.includes("null"))return null;if(contentType?.includes("json"))return response.json();const content=await response.text();return contentType?.includes("boolean")?"true"===content:contentType?.includes("number")?Number(content):content}#createResponseHeaders(response){const headers=new Map;for(const[name,value]of response.headers)headers.set(name,value);return headers}}class FetchHttpClient{async execute(url,options){return fetch(url,options)}}class HttpRemoteBuilder{#httpClient;constructor(httpClient=new FetchHttpClient){this.#httpClient=httpClient}build(url){return new HttpRemote(url,this.#httpClient)}}export{ArrayParameter,BadRequest,Class,ClientBuilder,Forbidden,HttpRemoteBuilder,Implementation,NamedParameter,NotFound,NotImplemented,ObjectParameter,PaymentRequired,Procedure,Request,Response,Segment,ServerError,Teapot,Unauthorized,Version};
|
|
1
|
+
class BadRequest extends Error{constructor(message="Invalid request"){super(message)}}class Forbidden extends Error{constructor(message="Forbidden"){super(message)}}class NotFound extends Error{constructor(message="Not found"){super(message)}}class NotImplemented extends Error{constructor(message="Not implemented"){super(message)}}class PaymentRequired extends Error{constructor(message="Payment required"){super(message)}}class ServerError extends Error{constructor(message="Server error"){super(message)}}class Teapot extends Error{constructor(message="I'm a teapot"){super(message)}}class Unauthorized extends Error{constructor(message="Unauthorized"){super(message)}}const AccessLevels_PRIVATE="private",AccessLevels_PROTECTED="protected",AccessLevels_PUBLIC="public",RunModes_NORMAL="normal",RunModes_DRY="dry",StatusCodes_OK=200,StatusCodes_BAD_REQUEST=400,StatusCodes_UNAUTHORIZED=401,StatusCodes_PAYMENT_REQUIRED=402,StatusCodes_FORBIDDEN=403,StatusCodes_NOT_FOUND=404,StatusCodes_TEAPOT=418,StatusCodes_SERVER_ERROR=500,StatusCodes_NOT_IMPLEMENTED=501;class InvalidVersionNumber extends BadRequest{#number;constructor(number){super(`Invalid version number '${number}'`),this.#number=number}get number(){return this.#number}}class ProcedureNotFound extends NotFound{#fqn;constructor(fqn){super(`Procedure '${fqn}' not found`),this.#fqn=fqn}get fqn(){return this.#fqn}}class ProcedureNotAccessible extends Forbidden{constructor(fqn,versionNumber){super(`Procedure '${fqn}' (v${versionNumber}) is not accessible`)}}class Segment{#id;#classes=new Map;#procedures=new Map;constructor(id){this.#id=id}get id(){return this.#id}addClass(clazz){return this.#classes.set(clazz.fqn,clazz),this}hasClass(fqn){return void 0!==this.getClass(fqn)}getClass(fqn){return this.#classes.get(fqn)}getClassByImplementation(implementation){return this.getClasses().find(clazz=>clazz.implementation===implementation)}getClasses(){return[...this.#classes.values()]}addProcedure(procedure){return this.#procedures.set(procedure.fqn,procedure),this}hasProcedure(fqn){return this.#procedures.has(fqn)}getProcedure(fqn){return this.#procedures.get(fqn)}getExposedProcedures(){return[...this.#procedures.values()].filter(procedure=>procedure.public||procedure.protected)}}class Class{#fqn;#implementation;constructor(fqn,implementation){this.#fqn=fqn,this.#implementation=implementation}get fqn(){return this.#fqn}get implementation(){return this.#implementation}}class Version{static get DEFAULT(){return new Version(0,0,0)}#major;#minor;#patch;constructor(major=0,minor=0,patch=0){this.#major=major,this.#minor=minor,this.#patch=patch}get major(){return this.#major}get minor(){return this.#minor}get patch(){return this.#patch}equals(version){return this.#major===version.major&&this.#minor===version.minor&&this.#patch===version.patch}greater(version){return this.#major!==version.major?this.#major>version.major:this.#minor!==version.minor?this.#minor>version.minor:this.#patch!==version.patch&&this.#patch>version.patch}less(version){return this.#major!==version.major?this.#major<version.major:this.#minor!==version.minor?this.#minor<version.minor:this.#patch!==version.patch&&this.#patch<version.patch}toString(){return`${this.#major}.${this.#minor}.${this.#patch}`}}class Procedure{#fqn;#implementations=new Map;#latestImplementation;constructor(fqn){this.#fqn=fqn}get fqn(){return this.#fqn}get public(){return[...this.#implementations.values()].some(implementation=>implementation.public)}get protected(){return[...this.#implementations.values()].some(implementation=>implementation.protected)}addImplementation(implementation){return this.#implementations.set(implementation.version,implementation),this.#isNewLatestImplementation(implementation)&&(this.#latestImplementation=implementation),this}#isNewLatestImplementation(implementation){return void 0===this.#latestImplementation||implementation.version.greater(this.#latestImplementation.version)}getImplementation(version){const selectedVersion=this.#selectAvailableVersion(version);return this.#implementations.get(selectedVersion)}#selectAvailableVersion(version){let selectedVersion=Version.DEFAULT;for(const implementationVersion of this.#implementations.keys()){if(implementationVersion.equals(version))return implementationVersion;implementationVersion.greater(version)||selectedVersion.less(implementationVersion)&&(selectedVersion=implementationVersion)}return selectedVersion}}class Implementation{#version;#access;#parameters;#executable;constructor(version,access,parameters,executable){this.#version=version,this.#access=access,this.#parameters=parameters,this.#executable=executable}get version(){return this.#version}get public(){return this.#access===AccessLevels_PUBLIC}get protected(){return this.#access===AccessLevels_PROTECTED}get private(){return this.#access===AccessLevels_PRIVATE}get parameters(){return this.#parameters}get executable(){return this.#executable}}class Parameter{#name;#isOptional;constructor(name,isOptional=!1){this.#name=name,this.#isOptional=isOptional}get name(){return this.#name}get isOptional(){return this.#isOptional}}class NamedParameter extends Parameter{}class DestructuredParameter extends Parameter{#variables;constructor(variables,name,isOptional){super(name??"(anonymous)",isOptional),this.#variables=variables}get variables(){return this.#variables}}class ArrayParameter extends DestructuredParameter{}class ObjectParameter extends DestructuredParameter{}class Request{#fqn;#version;#args;#headers=new Map;#mode;constructor(fqn,version,args,headers,mode){this.#fqn=fqn,this.#version=version,this.#args=args,this.#headers=headers,this.#mode=mode}get fqn(){return this.#fqn}get version(){return this.#version}get args(){return this.#args}get headers(){return this.#headers}get mode(){return this.#mode}clearArguments(){this.#args.clear()}setArgument(name,value){this.#args.set(name,value)}getArgument(name){return this.#args.get(name)}hasArgument(name){return this.#args.has(name)}removeArgument(name){this.#args.delete(name)}clearHeaders(){this.#headers.clear()}setHeader(name,value){this.#headers.set(name.toLowerCase(),value)}getHeader(name){return this.#headers.get(name.toLowerCase())}hasHeader(name){return this.#headers.has(name.toLowerCase())}removeHeader(name){this.#headers.delete(name.toLowerCase())}}class Response{#status;#result;#headers;constructor(status,result=void 0,headers=new Map){this.#status=status,this.#result=result,this.#headers=headers}get status(){return this.#status}get result(){return this.#result}set result(value){this.#result=value}get headers(){return this.#headers}clearHeaders(){this.#headers.clear()}setHeader(name,value){this.#headers.set(name.toLowerCase(),value)}getHeader(name){return this.#headers.get(name.toLowerCase())}hasHeader(name){return this.#headers.has(name.toLowerCase())}removeHeader(name){this.#headers.delete(name.toLowerCase())}}class UnknownParameter extends BadRequest{#parameterName;constructor(parameterName){super(`Unknown parameter ${parameterName}`),this.#parameterName=parameterName}get parameterName(){return this.#parameterName}}class MissingParameterValue extends BadRequest{#parameterName;constructor(parameterName){super(`Missing value for parameter '${parameterName}'`),this.#parameterName=parameterName}get parameterName(){return this.#parameterName}}class InvalidParameterValue extends BadRequest{#parameterName;constructor(parameterName){super(`Invalid value for parameter '${parameterName}'`),this.#parameterName=parameterName}get parameterName(){return this.#parameterName}}class ArgumentExtractor{extract(parameters,args){const argsCopy=this.#copyArguments(parameters,args),values=[];for(const parameter of parameters){const value=this.#extractArgumentValue(parameter,argsCopy);values.push(value)}if(argsCopy.size>0){const name=argsCopy.keys().next().value;throw new UnknownParameter(name)}return values}#copyArguments(parameters,args){const copy=new Map;for(const[key,value]of args){if(this.#isOptionalArgument(key)){const name=this.#getParameterName(key);!0===this.#containsParameter(parameters,name)&©.set(name,value);continue}copy.set(key,value)}return copy}#isOptionalArgument(argument){return argument.startsWith("*")}#getParameterName(argument){return argument.substring(1)}#containsParameter(parameters,name){return void 0!==parameters.find(parameter=>parameter.name===name)}#extractArgumentValue(parameter,args,parent){return parameter instanceof NamedParameter?this.#extractNamedArgumentValue(parameter,args,parent):this.#extractDestructedArgumentValue(parameter,args)}#extractNamedArgumentValue(parameter,args,parent){const value=args.get(parameter.name);if(this.#isMissingParameterValue(parameter,value,parent))throw new MissingParameterValue(parameter.name);if(this.#isInvalidRestParameter(parameter,value,parent))throw new InvalidParameterValue(parameter.name);return args.delete(parameter.name),value}#extractDestructedArgumentValue(parameter,args){return parameter instanceof ArrayParameter?this.#extractArrayArgumentValue(parameter,args):this.#extractObjectArgumentValue(parameter,args)}#extractArrayArgumentValue(parameter,args){const values=this.#extractVariableValues(parameter,args);return void 0!==values?Object.values(values):void 0}#extractObjectArgumentValue(parameter,args){return this.#extractVariableValues(parameter,args)}#extractVariableValues(parameter,args){const useIndex=parameter instanceof ArrayParameter,values={},missingValues=[];let containsValues=!1,index=0;for(const variable of parameter.variables){const key=useIndex?index++:variable.name,value=this.#extractArgumentValue(variable,args,parameter);void 0!==value?containsValues=!0:!1===variable.isOptional&&missingValues.push(variable.name),values[key]=value}if(!0===containsValues&&missingValues.length>0)throw new MissingParameterValue(missingValues[0]);return containsValues?values:void 0}#isMissingParameterValue(parameter,value,parent){return void 0===value&&(!0!==parameter.isOptional&&!0!==parent?.isOptional)}#isInvalidRestParameter(parameter,value,parent){return!1!==parameter.name.startsWith("...")&&(void 0===parent&&value instanceof Array==!1||parent instanceof ArrayParameter&&value instanceof Array==!1||parent instanceof ObjectParameter&&value instanceof Object==!1)}}class ErrorConverter{toStatus(error){return error instanceof BadRequest?StatusCodes_BAD_REQUEST:error instanceof Forbidden?StatusCodes_FORBIDDEN:error instanceof NotFound?StatusCodes_NOT_FOUND:error instanceof NotImplemented?StatusCodes_NOT_IMPLEMENTED:error instanceof PaymentRequired?StatusCodes_PAYMENT_REQUIRED:error instanceof Teapot?StatusCodes_TEAPOT:error instanceof Unauthorized?StatusCodes_UNAUTHORIZED:StatusCodes_SERVER_ERROR}fromStatus(status,message){switch(status){case StatusCodes_BAD_REQUEST:return new BadRequest(message);case StatusCodes_FORBIDDEN:return new Forbidden(message);case StatusCodes_NOT_FOUND:return new NotFound(message);case StatusCodes_NOT_IMPLEMENTED:return new NotImplemented(message);case StatusCodes_PAYMENT_REQUIRED:return new PaymentRequired(message);case StatusCodes_TEAPOT:return new Teapot(message);case StatusCodes_UNAUTHORIZED:return new Unauthorized(message);default:return new ServerError(message)}}}const VERSION_EXPRESSION=/^\d+(?:\.\d+){0,2}$/;class VersionParser{parse(number){if(0===number.trim().length)return Version.DEFAULT;if(!1===VERSION_EXPRESSION.test(number))throw new InvalidVersionNumber(number);const parts=number.split(".");switch(parts.length){case 1:return new Version(Number.parseInt(parts[0]));case 2:return new Version(Number.parseInt(parts[0]),Number.parseInt(parts[1]));default:return new Version(Number.parseInt(parts[0]),Number.parseInt(parts[1]),Number.parseInt(parts[2]))}}}class ImplementationNotFound extends NotFound{#fqn;#version;constructor(fqn,version){super(`No implementation found for procedure '${fqn}' with version '${version}'`),this.#fqn=fqn,this.#version=version}get fqn(){return this.#fqn}get version(){return this.#version}}class InvalidSegment extends ServerError{constructor(){super("Invalid segment")}}class Application{#segments=new Map;addSegment(segment){this.#segments.set(segment.id,segment)}clearSegments(){this.#segments.clear()}getClassNames(){const names=new Set;for(const segment of this.#segments.values()){segment.getClasses().forEach(clazz=>names.add(clazz.fqn))}return[...names.values()]}hasClass(fqn){return this.getClassNames().includes(fqn)}getClass(fqn){for(const segment of this.#segments.values())if(segment.hasClass(fqn))return segment.getClass(fqn)}getClassByImplementation(implementation){for(const segment of this.#segments.values()){const clazz=segment.getClassByImplementation(implementation);if(void 0!==clazz)return clazz}}getProcedureNames(){const names=new Set;for(const segment of this.#segments.values()){segment.getExposedProcedures().forEach(procedure=>names.add(procedure.fqn))}return[...names.values()]}hasProcedure(fqn){return this.getProcedureNames().includes(fqn)}getProcedure(fqn){for(const segment of this.#segments.values())if(segment.hasProcedure(fqn))return segment.getProcedure(fqn)}}class ExecutionManager{#moduleImporter;#segmentFiles;#argumentConstructor=new ArgumentExtractor;#errorConverter=new ErrorConverter;#application=new Application;constructor(moduleImporter,segmentFiles=[]){this.#moduleImporter=moduleImporter,this.#segmentFiles=segmentFiles}async start(){return this.#loadSegments()}async stop(){return this.#clearSegments()}async loadSegment(filename){const module=await this.#moduleImporter.import(filename);this.addSegment(module.default)}async addSegment(segment){if(segment instanceof Segment==!1)throw new InvalidSegment;this.#application.addSegment(segment)}getClassNames(){return this.#application.getClassNames()}hasClass(fqn){return this.#application.hasClass(fqn)}getClass(fqn){return this.#application.getClass(fqn)}getClassByImplementation(implementation){return this.#application.getClassByImplementation(implementation)}getProcedureNames(){return this.#application.getProcedureNames()}hasProcedure(fqn){return this.#application.hasProcedure(fqn)}getProcedure(fqn){return this.#application.getProcedure(fqn)}async run(request){const implementation=this.#getImplementation(request.fqn,request.version),args=this.#argumentConstructor.extract(implementation.parameters,request.args);return request.mode===RunModes_DRY?new Response(StatusCodes_OK,void 0):this.#runImplementation(request,implementation,args)}async#loadSegments(){await Promise.all(this.#segmentFiles.map(filename=>this.loadSegment(filename)))}#clearSegments(){this.#application.clearSegments()}#getImplementation(fqn,version){const procedure=this.#application.getProcedure(fqn);if(void 0===procedure)throw new ProcedureNotFound(fqn);const implementation=procedure.getImplementation(version);if(void 0===implementation)throw new ImplementationNotFound(procedure.fqn,version.toString());return implementation}async#runImplementation(request,implementation,args){try{const result=await implementation.executable.call(request,...args);return new Response(StatusCodes_OK,result)}catch(error){const status=this.#errorConverter.toStatus(error);return new Response(status,error)}}}class RequestCancelled extends ServerError{constructor(){super("Request cancelled")}}class RequestPool{#runner;#size;#queue=[];#started=!1;#activeCount=0;constructor(runner,size=20){this.#runner=runner,this.#size=size}start(){this.#started=!0,this.#update()}stop(){this.#started=!1,this.#cancelAll()}run(request){return new Promise((resolve,reject)=>{this.#queue.push({request:request,resolve:resolve,reject:reject}),this.#update()})}#update(){if(this.#noUpdateRequired())return;const queueSize=this.#queue.length,idleCount=this.#size-this.#activeCount,activationCount=Math.min(queueSize,idleCount);this.#activate(activationCount)}#noUpdateRequired(){return this.#isStopped()||this.#queueEmpty()||this.#allActive()}#isStopped(){return!1===this.#started}#queueEmpty(){return 0===this.#queue.length}#allActive(){return this.#activeCount>=this.#size}#activate(count){const items=this.#queue.splice(0,count);this.#activeCount+=count,items.forEach(item=>this.#perform(item))}async#perform(item){try{const response=await this.#runner.run(item.request);item.resolve(response)}catch(error){item.reject(error)}finally{this.#activeCount--,this.#update()}}#cancelAll(){for(;this.#queue.length>0;){const item=this.#queue.shift();void 0!==item&&this.#cancel(item)}}#cancel(item){item.reject(new RequestCancelled)}}const States$2_STARTING="starting",States$2_AVAILABLE="available",States$2_UNAVAILABLE="unavailable",States$2_STOPPING="stopping",States$2_STOPPED="stopped";class StateManager{#state=States$2_STOPPED;get state(){return this.#state}set state(state){this.#state=state}async start(task){if(!this.isStarted())try{this.setStarting(),await task()}catch(error){throw this.setStopped(),error}}async stop(task){this.isStopped()||(this.setStopping(),await task(),this.setStopped())}isStarted(){return this.#notHasState(States$2_STOPPED)}isStopped(){return this.#hasState(States$2_STOPPED)}isAvailable(){return this.#hasState(States$2_AVAILABLE)}setStarting(){this.#state=States$2_STARTING}setAvailable(){this.#state=States$2_AVAILABLE}setUnavailable(){this.#state=States$2_UNAVAILABLE}setAvailability(available){return this.#state=available?States$2_AVAILABLE:States$2_UNAVAILABLE,this.#state}setStopping(){this.#state=States$2_STOPPING}setStopped(){this.#state=States$2_STOPPED}#hasState(...states){return states.includes(this.#state)}#notHasState(...states){return!1===this.#hasState(...states)}}class RemoteGateway{#url;#remote;#stateManager=new StateManager;constructor(configuration){this.#url=configuration.url,this.#remote=configuration.remote}get url(){return this.#url}get state(){return this.#stateManager.state}get trustKey(){}async start(){return this.#stateManager.start(async()=>{await this.#remote.connect(),await this.updateState()})}async stop(){return this.#stateManager.stop(async()=>{await this.#remote.disconnect()})}isHealthy(){return this.#remote.isHealthy()}getHealth(){return this.#remote.getHealth()}async updateState(){const healthy=await this.isHealthy();return this.#stateManager.setAvailability(healthy)}getProcedureNames(){throw new NotImplemented}hasProcedure(name){throw new NotImplemented}addWorker(worker){return this.#remote.addWorker(worker.url,worker.getProcedureNames(),worker.trustKey)}reportWorker(id,state){return this.#remote.reportWorker(id,state)}removeWorker(id){return this.#remote.removeWorker(id)}run(request){return this.#remote.run(request)}}class InvalidPath extends Error{#location;constructor(location){super(`Invalid location: ${location}`),this.#location=location}get location(){return this.#location}}class FileNotFound extends Error{#filename;constructor(filename){super(`The file '${filename}' could not be found`),this.#filename=filename}get filename(){return this.#filename}}class File{#location;#type;#content;constructor(location,type,content){this.#location=location,this.#type=type,this.#content=content}get location(){return this.#location}get type(){return this.#type}get content(){return this.#content}get size(){return this.#content.length}}class FileManager{#location;#rootLocation;#fileSystem;constructor(location,fileSystem){const rootLocation=fileSystem.resolve(location);this.#location=fileSystem.normalize(location),this.#rootLocation=fileSystem.normalize(rootLocation),this.#fileSystem=fileSystem}getAbsoluteLocation(filename){const location=this.#fileSystem.isAbsolute(filename)?filename:this.#fileSystem.join(this.#location,filename),absolutePath=this.#fileSystem.resolve(location),normalizedPath=this.#fileSystem.normalize(absolutePath);return this.#validateLocation(normalizedPath,filename),normalizedPath}getRelativeLocation(filename){const location=this.#fileSystem.relative(this.#location,filename);return this.#fileSystem.normalize(location)}normalizeLocation(location){return this.#fileSystem.normalize(location)}async getType(filename){const location=this.getAbsoluteLocation(filename);return await this.#fileSystem.mimeType(location)??"application/octet-stream"}async getContent(filename){const location=this.getAbsoluteLocation(filename);if(!1===await this.#fileSystem.exists(location))throw new FileNotFound(filename);return this.#fileSystem.read(location)}async exists(filename){const location=this.getAbsoluteLocation(filename);return this.#fileSystem.exists(location)}isDirectory(filename){const location=this.getAbsoluteLocation(filename);return this.#fileSystem.isDirectory(location)}async read(filename){const absoluteFilename=this.getAbsoluteLocation(filename),type=await this.getType(absoluteFilename),content=await this.getContent(absoluteFilename);return new File(filename,type,content)}async write(filename,content){const location=this.getAbsoluteLocation(filename);return this.#fileSystem.write(location,content)}async copy(source,destination){const sourceLocation=this.getAbsoluteLocation(source),destinationLocation=this.getAbsoluteLocation(destination);return this.#fileSystem.copy(sourceLocation,destinationLocation)}async delete(filename){const location=this.getAbsoluteLocation(filename);return this.#fileSystem.delete(location)}async filter(pattern){const location=this.getAbsoluteLocation("./"),normalizedPattern=this.#fileSystem.normalize(pattern);return(await this.#fileSystem.filter(location,normalizedPattern)).map(filename=>this.#fileSystem.normalize(filename))}#validateLocation(location,filename){if(!1===location.startsWith(this.#rootLocation))throw new InvalidPath(filename)}}class RemoteFilesNotSupported extends Error{constructor(){super("Remote files are not supported")}}class RemoteFileSystem{copy(source,destination){throw new RemoteFilesNotSupported}delete(location){throw new RemoteFilesNotSupported}exists(location){throw new RemoteFilesNotSupported}async filter(location,pattern){return[]}isAbsolute(location){return location.startsWith("/")}isDirectory(location){throw new RemoteFilesNotSupported}join(...paths){throw new RemoteFilesNotSupported}read(location){throw new RemoteFilesNotSupported}resolve(location){return location}relative(from,to){throw new RemoteFilesNotSupported}normalize(location){return location}mimeType(location){throw new RemoteFilesNotSupported}write(location,content){throw new RemoteFilesNotSupported}}class RemoteFileManager extends FileManager{constructor(location){super(location,new RemoteFileSystem)}}class ModuleNotLoaded extends Error{#url;#reason;constructor(url,reason){super(`Module '${url}' could not be loaded${void 0!==reason?` | ${reason}`:""}`),this.#url=url,this.#reason=reason}get url(){return this.#url}get reason(){return this.#reason}}class ImportManager{#moduleLocator;constructor(moduleLocator){this.#moduleLocator=moduleLocator}async import(filename){const location=this.#moduleLocator.locate(filename);try{return await import(location)}catch(error){const message=error instanceof Error?error.message:String(error);throw new ModuleNotLoaded(location,message)}}}class RemoteModuleLocator{constructor(location){}locate(filename){throw new ModuleNotLoaded(filename,"Remote module loading is not allowed")}}class RemoteImportManager extends ImportManager{constructor(location){super(new RemoteModuleLocator(location))}}class SourcingManager{#fileManager;#importManager;constructor(fileManager,importManager){this.#fileManager=fileManager,this.#importManager=importManager}async filter(...patterns){return(await Promise.all(patterns.map(pattern=>this.#fileManager.filter(pattern)))).flat().map(file=>this.#fileManager.getRelativeLocation(file))}exists(filename){return this.#fileManager.exists(filename)}read(filename){return this.#fileManager.read(filename)}import(filename){return this.#importManager.import(filename)}}class RemoteSourcingManager extends SourcingManager{constructor(location){super(new RemoteFileManager(location),new RemoteImportManager(location))}}class ClassNotFound extends Error{constructor(name){super(`The class '${name}' could not be found`)}}class InvalidClass extends Error{constructor(name){super(`The class '${name}' is invalid`)}}class NoDeserializerFound extends Error{constructor(type){super(`No deserializer found for value of type '${type}'`)}}class NoSerializerFound extends Error{constructor(type){super(`No serializer found for value of type '${type}'`)}}class Serializer{#serializers=[];addSerializer(serializer){serializer.parent=this,this.#serializers.unshift(serializer)}async serialize(value){const serializer=this.#serializers.find(serializer=>serializer.canSerialize(value));if(void 0===serializer)throw new NoSerializerFound(typeof value);return serializer.serialize(value)}async deserialize(value){const serializer=this.#serializers.find(serializer=>serializer.canDeserialize(value));if(void 0===serializer)throw new NoDeserializerFound(typeof value);return serializer.deserialize(value)}}class ParentSerializerNotSet extends Error{constructor(){super("Parent serializer not set")}}class ValueSerializer{#parent;set parent(parent){this.#parent=parent}serializeOther(value){if(void 0===this.#parent)throw new ParentSerializerNotSet;return this.#parent.serialize(value)}deserializeOther(value){if(void 0===this.#parent)throw new ParentSerializerNotSet;return this.#parent.deserialize(value)}}class ArraySerializer extends ValueSerializer{canSerialize(value){return value instanceof Array}canDeserialize(value){return value instanceof Array}async serialize(array){const values=[];for(const value of array)values.push(await this.serializeOther(value));return values}async deserialize(array){return Promise.all(array.map(async value=>this.deserializeOther(value)))}}class InvalidBigIntString extends Error{constructor(bigIntString){super(`Invalid BigInt string '${bigIntString}'`)}}class BigIntSerializer extends ValueSerializer{canSerialize(value){return"bigint"==typeof value}canDeserialize(value){const bigInt=value;return bigInt instanceof Object&&!0===bigInt.serialized&&"BigInt"===bigInt.name&&"string"==typeof bigInt.value}async serialize(bigInt){return{serialized:!0,name:"BigInt",value:bigInt.toString()}}async deserialize(object){try{return BigInt(object.value)}catch{throw new InvalidBigIntString(object.value)}}}class InvalidBufferString extends Error{constructor(bufferString){super(`Invalid Buffer string '${bufferString}'`)}}class BufferSerializer extends ValueSerializer{canSerialize(value){return value instanceof Buffer}canDeserialize(value){const buffer=value;return buffer instanceof Object&&!0===buffer.serialized&&"Buffer"===buffer.name&&"string"==typeof buffer.base64}async serialize(buffer){return{serialized:!0,name:"Buffer",base64:buffer.toString("base64")}}async deserialize(object){try{return Buffer.from(object.base64,"base64")}catch{throw new InvalidBufferString(object.base64)}}}class ESAlias{#name;#as;constructor(name,as){this.#name=name,this.#as=as}get name(){return this.#name}get as(){return this.#as}toString(){return`${this.#name} as ${this.#as}`}}class ESValue{#definition;constructor(definition){this.#definition=definition}get definition(){return this.#definition}toString(){return this.#definition}}class ESArray extends ESValue{}class ESMember{#name;#isStatic;#isPrivate;constructor(name,isStatic=!1,isPrivate=!1){this.#name=name,this.#isStatic=isStatic,this.#isPrivate=isPrivate}get name(){return this.#name}get isStatic(){return this.#isStatic}get isPrivate(){return this.#isPrivate}get isPublic(){return!1===this.#isPrivate}}class ESClass extends ESMember{#parentName;#scope;constructor(name,parentName,scope){super(name),this.#parentName=parentName,this.#scope=scope}get parentName(){return this.#parentName}get scope(){return this.#scope}get members(){return this.#scope.members}get declarations(){return this.#scope.declarations}get functions(){return this.#scope.functions}get getters(){return this.#scope.getters}get setters(){return this.#scope.setters}get generators(){return this.#scope.generators}get readable(){const members=new Map;return this.getters.forEach(getter=>{members.set(getter.name,getter)}),this.declarations.forEach(declaration=>{declaration.isPublic&&members.set(declaration.name,declaration)}),[...members.values()]}get writable(){const members=new Map;return this.setters.forEach(setter=>{members.set(setter.name,setter)}),this.declarations.forEach(declaration=>{declaration.isPublic&&members.set(declaration.name,declaration)}),[...members.values()]}get callable(){return this.functions.filter(funktion=>funktion.isPublic)}getMember(name){return this.#scope.getMember(name)}getDeclaration(name){return this.#scope.getDeclaration(name)}getFunction(name){return this.#scope.getFunction(name)}getGetter(name){return this.#scope.getGetter(name)}getSetter(name){return this.#scope.getSetter(name)}getGenerator(name){return this.#scope.getGenerator(name)}hasMember(name){return this.#scope.hasMember(name)}hasDeclaration(name){return this.#scope.hasDeclaration(name)}hasFunction(name){return this.#scope.hasFunction(name)}hasGetter(name){return this.#scope.hasGetter(name)}hasSetter(name){return this.#scope.hasSetter(name)}hasGenerator(name){return this.#scope.hasGenerator(name)}canRead(name){const declaration=this.getDeclaration(name);return declaration?.isPublic||this.hasGetter(name)}canWrite(name){const declaration=this.getDeclaration(name);return declaration?.isPublic||this.hasSetter(name)}canCall(name){const funktion=this.getFunction(name);return funktion?.isPublic??!1}toString(){const infix=void 0!==this.#parentName?` extends ${this.#parentName}`:"";return`class ${this.name}${infix} { ${this.#scope.toString()} }`}}class ESDeclaration extends ESMember{#identifier;#value;constructor(identifier,value,isStatic=!1,isPrivate=!1){super(identifier.toString(),isStatic,isPrivate),this.#identifier=identifier,this.#value=value}get identifier(){return this.#identifier}get value(){return this.#value}toString(){return`${this.name}${this.value?" = "+this.value.toString():""}`}}class ESDestructuredValue{#members;constructor(members){this.#members=members}get members(){return this.#members}toString(){return this.#members.map(member=>member.toString()).join(" , ")}}class ESDestructuredArray extends ESDestructuredValue{toString(){return`[ ${super.toString()} ]`}}class ESDestructuredObject extends ESDestructuredValue{toString(){return`{ ${super.toString()} }`}}class ESExport extends ESMember{#members;#from;constructor(members,from){super(""),this.#members=members,this.#from=from}get members(){return this.#members}get from(){return this.#from}hasMember(name){return this.#members.some(member=>member.as===name)}getMember(name){return this.#members.find(member=>member.as===name)}toString(){const postfix=this.#from?` from '${this.#from}'`:"";return`export { ${this.#members.join(", ")} }${postfix}`}}class ESExpression extends ESValue{}class ESField{#name;#value;constructor(name,value){this.#name=name,this.#value=value}get name(){return this.#name}get value(){return this.#value}toString(){return`${this.name}${this.value?" = "+this.value.toString():""}`}}class ESFunction extends ESMember{#parameters;#body;#isAsync;constructor(name,parameters,body,isStatic=!1,isAsync=!1,isPrivate=!1){super(name,isStatic,isPrivate),this.#parameters=parameters,this.#body=body,this.#isAsync=isAsync}get parameters(){return this.#parameters}get body(){return this.#body}get isAsync(){return this.#isAsync}toString(){const parameters=this.parameters.map(parameter=>parameter.toString());return`${this.isAsync?"async ":""}${this.name}(${parameters.join(", ")}) { ${this.body} }`}}class ESGenerator extends ESFunction{toString(){const parameters=this.parameters.map(parameter=>parameter.toString());return`${this.isAsync?"async ":""}${this.name}*(${parameters.join(", ")}) { ${this.body} }`}}class ESGetter extends ESFunction{toString(){return`get ${super.toString()}`}}class ESImport extends ESMember{#members;#from;constructor(members,from){super(""),this.#members=members,this.#from=from}get members(){return this.#members}get from(){return this.#from}hasMember(name){return this.#members.some(member=>member.as===name)}getMember(name){return this.#members.find(member=>member.as===name)}toString(){return`import { ${this.#members.map(member=>member.toString()).join(", ")} } from '${this.#from}';`}}class ESModule{#scope;constructor(scope){this.#scope=scope}get scope(){return this.#scope}get members(){return this.#scope.members}get exportedMembers(){return this.#filterExported(this.#scope.members)}get imports(){return this.#scope.imports}get exports(){return this.#scope.exports}get declarations(){return this.#scope.declarations}get exportedDeclarations(){return this.#filterExported(this.#scope.declarations)}get functions(){return this.#scope.functions}get exportedFunctions(){return this.#filterExported(this.#scope.functions)}get generators(){return this.#scope.generators}get exportedGenerators(){return this.#filterExported(this.#scope.generators)}get classes(){return this.#scope.classes}get exportedClasses(){return this.#filterExported(this.#scope.classes)}get exported(){const exported=new Map;for(const exportItem of this.exports)for(const alias of exportItem.members){const member=this.getMember(alias.name);void 0!==member&&exported.set(alias.as,member)}return exported}getMember(name){return this.#scope.getMember(name)}getDeclaration(name){return this.#scope.getDeclaration(name)}getFunction(name){return this.#scope.getFunction(name)}getGenerator(name){return this.#scope.getGenerator(name)}getClass(name){return this.#scope.getClass(name)}hasMember(name){return this.#scope.hasMember(name)}hasDeclaration(name){return this.#scope.hasDeclaration(name)}hasFunction(name){return this.#scope.hasFunction(name)}hasGenerator(name){return this.#scope.hasGenerator(name)}hasClass(name){return this.#scope.hasClass(name)}getImport(name){return this.imports.find(importItem=>importItem.hasMember(name))}getImported(name){for(const importItem of this.imports)for(const alias of importItem.members)if(alias.as===name)return this.getMember(alias.name)}isExported(member){for(const exportItem of this.exports)for(const alias of exportItem.members)if(alias.name===member.name)return!0;return!1}getExport(name){return this.exports.find(exportItem=>exportItem.hasMember(name))}getExported(name){for(const exportItem of this.exports)for(const alias of exportItem.members)if(alias.as===name)return this.getMember(alias.name)}#filterExported(members){return members.filter(member=>this.isExported(member))}}class ESObject extends ESValue{}class ESSetter extends ESFunction{toString(){return`set ${super.toString()}`}}const IMPORT_NAME=ESImport.name,EXPORT_NAME=ESExport.name,DECLARATION_NAME=ESDeclaration.name,FUNCTION_NAME=ESFunction.name,GETTER_NAME=ESGetter.name,SETTER_NAME=ESSetter.name,GENERATOR_NAME=ESGenerator.name,CLASS_NAME=ESClass.name;class ESScope{#members;constructor(members){this.#members=members}get members(){return this.#members}get imports(){return this.#members.filter(member=>member.constructor.name===IMPORT_NAME)}get exports(){return this.#members.filter(member=>member.constructor.name===EXPORT_NAME)}get declarations(){return this.#members.filter(member=>member.constructor.name===DECLARATION_NAME)}get functions(){return this.#members.filter(member=>member.constructor.name===FUNCTION_NAME)}get getters(){return this.#members.filter(member=>member.constructor.name===GETTER_NAME)}get setters(){return this.#members.filter(member=>member.constructor.name===SETTER_NAME)}get generators(){return this.#members.filter(member=>member.constructor.name===GENERATOR_NAME)}get classes(){return this.#members.filter(member=>member.constructor.name===CLASS_NAME)}getMember(name){return this.#members.find(member=>member.name===name)}getDeclaration(name){return this.declarations.find(member=>member.name===name)}getFunction(name){return this.functions.find(member=>member.name===name)}getGetter(name){return this.getters.find(member=>member.name===name)}getSetter(name){return this.setters.find(member=>member.name===name)}getGenerator(name){return this.generators.find(member=>member.name===name)}getClass(name){return this.classes.find(member=>member.name===name)}hasMember(name){return void 0!==this.getMember(name)}hasDeclaration(name){return void 0!==this.getDeclaration(name)}hasFunction(name){return void 0!==this.getFunction(name)}hasGetter(name){return void 0!==this.getGetter(name)}hasSetter(name){return void 0!==this.getSetter(name)}hasGenerator(name){return void 0!==this.getGenerator(name)}hasClass(name){return void 0!==this.getClass(name)}toString(){return this.#members.map(member=>member.toString()).join("\n")}}const Comment={SINGLE:"//",MULTI_START:"/*",MULTI_END:"*/"},Comments=Object.values(Comment);const Punctuation_DOT=".",Punctuation_LEFT_PARENTHESIS="(",Punctuation_RIGHT_PARENTHESIS=")",Punctuation_LEFT_BRACKET="[",Punctuation_RIGHT_BRACKET="]",Punctuation_LEFT_BRACE="{",Punctuation_RIGHT_BRACE="}",Divider={SCOPE:":",SEPARATOR:",",TERMINATOR:";"},Divisions=Object.values(Divider);function isDivider(value){return Divisions.includes(value)}const Empty={UNDEFINED:void 0,NULL:null,STRING:""},Empties=Object.values(Empty);function isEmpty(value){return Empties.includes(value)}const Group={OPEN:Punctuation_LEFT_PARENTHESIS,CLOSE:Punctuation_RIGHT_PARENTHESIS};function isGroup(value){return value===Group.OPEN||value===Group.CLOSE}const Keyword={EXPORT:"export",DEFAULT:"default",CLASS:"class",FUNCTION:"function",CONST:"const",LET:"let",VAR:"var",AS:"as",FROM:"from",IMPORT:"import",GET:"get",SET:"set",EXTENDS:"extends",STATIC:"static",ASYNC:"async",RETURN:"return"},Keywords=Object.values(Keyword);function isKeyword(value){return Keywords.includes(value)}function isNotReserved(value){return value===Keyword.AS||value===Keyword.ASYNC||value===Keyword.FROM||value===Keyword.GET||value===Keyword.SET}const List={OPEN:Punctuation_LEFT_BRACKET,CLOSE:Punctuation_RIGHT_BRACKET};function isList(value){return value===List.OPEN||value===List.CLOSE}const Literals=Object.values({SINGLE:"'",DOUBLE:'"',BACKTICK:"`"});function isLiteral(value){return Literals.includes(value)}const Operator={ADD:"+",ARROW:"=>",ASSIGN:"=",ASSIGN_ADD:"+=",ASSIGN_BITWISE_AND:"&=",ASSIGN_BITWISE_OR:"|=",ASSIGN_DIVIDE:"/=",ASSIGN_LEFT_SHIFT:"<<=",ASSIGN_LOGICAL_AND:"&&=",ASSIGN_LOGICAL_OR:"||=",ASSIGN_MODULO:"%=",ASSIGN_MULTIPLY:"*=",ASSIGN_RIGHT_SHIFT:">>=",ASSIGN_SUBTRACT:"-=",ASSIGN_XOR:"^=",BITWISE_AND:"&",BITWISE_OR:"|",DECREMENT:"--",DIVIDE:"/",EQUAL:"==",EQUAL_STRICT:"===",GREATER:">",GREATER_EQUAL:">=",INCREMENT:"++",LEFT_SHIFT:"<<",LESS:"<",LESS_EQUAL:"<=",LOGICAL_AND:"&&",LOGICAL_OR:"||",MODULO:"%",MULTIPLY:"*",NOT:"!",NOT_EQUAL:"!=",NOT_EQUAL_STRICT:"!==",RIGHT_SHIFT:">>",SUBTRACT:"-",TERNARY:"?",XOR:"^"},Operators=Object.values(Operator);function isOperator(value){return Operators.includes(value)}const Scope={OPEN:Punctuation_LEFT_BRACE,CLOSE:Punctuation_RIGHT_BRACE};function isScope(value){return value===Scope.OPEN||value===Scope.CLOSE}const TokenType={COMMENT:"comment",DIVIDER:"divider",GROUP:"group",IDENTIFIER:"identifier",KEYWORD:"keyword",LIST:"list",LITERAL:"literal",OPERATOR:"operator",REGEX:"regex",SCOPE:"scope",WHITESPACE:"whitespace"},Whitespace={SPACE:" ",TAB:"\t",NEWLINE:"\n",CARRIAGE_RETURN:"\r"},Whitespaces=Object.values(Whitespace);function isWhitespace(value){return Whitespaces.includes(value)}class ItemList{#items;#position;constructor(items){this.#items=items,this.#position=0}get items(){return this.#items}get position(){return this.#position}get size(){return this.#items.length}get eol(){return this.#position>=this.#items.length}get current(){return this.#items[this.#position]}get next(){return this.#items[this.#position+1]}get previous(){return this.#items[this.#position-1]}notAtEnd(){return!1===this.eol}get(index){return this.#items[index]}step(amount=1){return this.#position+=amount,this.current}stepBack(amount=1){return this.#position-=amount,this.current}hasNext(){return this.#position+1<this.#items.length}}class CharList extends ItemList{constructor(code){super(code.split(""))}}class Token{#type;#value;#start;#end;constructor(type,value,start,end){this.#type=type,this.#value=value,this.#start=start,this.#end=end}get type(){return this.#type}get value(){return this.#value}get start(){return this.#start}get end(){return this.#end}isType(type){return this.#type===type}hasValue(value){return this.#value===value}toString(){return`${this.#value}`}}class TokenList extends ItemList{}class Lexer{tokenize(code){const charList=new CharList(code),tokens=[];let last;for(;charList.notAtEnd();){const token=this.#getNextToken(charList,last);if(void 0===token)break;token.isType(TokenType.WHITESPACE)||token.isType(TokenType.COMMENT)?charList.step():(tokens.push(token),this.#isCodeToken(token)&&(last=token),charList.step())}return new TokenList(tokens)}#isCodeToken(token){return!1===[TokenType.WHITESPACE,TokenType.COMMENT].includes(token.type)}#getNextToken(charList,lastToken){const char=charList.current,start=charList.position;if(isWhitespace(char)){const end=charList.position;return new Token(TokenType.WHITESPACE,char,start,end)}if(function(value){return Comments.includes(value)}(char+charList.next)){const value=this.#readComment(charList),end=charList.position;return new Token(TokenType.COMMENT,value,start,end)}if(this.#startsRegex(char,lastToken)){const value=this.#readRegex(charList),end=charList.position;return new Token(TokenType.REGEX,value,start,end)}if(isLiteral(char)){const value=this.#readLiteral(charList),end=charList.position;return new Token(TokenType.LITERAL,value,start,end)}if(isOperator(char)){const value=this.#readOperation(charList),end=charList.position;return new Token(TokenType.OPERATOR,value,start,end)}if(isDivider(char)){const end=charList.position;return new Token(TokenType.DIVIDER,char,start,end)}if(isGroup(char)){const end=charList.position;return new Token(TokenType.GROUP,char,start,end)}if(isScope(char)){const end=charList.position;return new Token(TokenType.SCOPE,char,start,end)}if(isList(char)){const end=charList.position;return new Token(TokenType.LIST,char,start,end)}if(isEmpty(char))return;const value=this.#readIdentifier(charList),type=isKeyword(value)?TokenType.KEYWORD:TokenType.IDENTIFIER,end=charList.position;return new Token(type,value,start,end)}#readComment(charList){const isMulti=charList.current+charList.next===Comment.MULTI_START,terminator=isMulti?Comment.MULTI_END:Whitespace.NEWLINE;let value=isMulti?Comment.MULTI_START:Comment.SINGLE;for(charList.step(2);charList.notAtEnd();){const char=charList.current;if((isMulti?char+charList.next:char)===terminator){charList.step(terminator.length-1);break}value+=char,charList.step()}return isMulti?value+Comment.MULTI_END:value.trim()}#startsRegex(char,lastToken){return char===Operator.DIVIDE&&(void 0===lastToken||([TokenType.OPERATOR,TokenType.DIVIDER,TokenType.KEYWORD].includes(lastToken.type)||[Group.OPEN,List.OPEN].includes(lastToken.value)))}#endsRegex(char){return isWhitespace(char)||char==Punctuation_DOT||!1===this.#isIdentifier(char)}#readRegex(charList){let value=charList.current,closed=!1;for(charList.step();charList.notAtEnd();){const current=charList.current,previous=charList.previous;if(current===Operator.DIVIDE&&"\\"!==previous)closed=!0;else if(!0===closed&&this.#endsRegex(current)){charList.stepBack();break}value+=current,charList.step()}return value}#readLiteral(charList){const identifier=charList.current;let value=identifier,escaped=!1;for(charList.step();charList.notAtEnd();){const char=charList.current;if(!1===escaped){if(char===identifier){value+=char;break}"\\"===char&&(escaped=!0)}else escaped=!1;value+=char,charList.step()}return value}#isIdentifier(char){return!1===(isEmpty(char)||isWhitespace(char)||isOperator(char)||isLiteral(char)||isDivider(char)||isGroup(char)||isScope(char)||isList(char))}#readIdentifier(charList){let value="";for(;charList.notAtEnd();){const char=charList.current;if(!1===this.#isIdentifier(char)){charList.stepBack();break}value+=char,charList.step()}return value}#readOperation(charList){let value=charList.current;for(charList.step();charList.notAtEnd();){const char=charList.current;if(!1===isOperator(char)||!1===isOperator(value+char)){charList.stepBack();break}value+=char,charList.step()}return value}}class ExpectedKeyword extends Error{constructor(value,position){super(`Expected keyword '${value}' at position ${position}`)}}class ExpectedToken extends Error{constructor(value,position){super(`Expected token '${value}' at position ${position}`)}}class UnexpectedKeyword extends Error{constructor(keyword,position){super(`Unexpected keyword '${keyword}' at position ${position}`)}}class UnexpectedParseResult extends Error{constructor(expected){super(`The given code does not contain ${expected}`)}}class UnexpectedToken extends Error{constructor(value,position){super(`Unexpected token '${value}' at position ${position}`)}}class Parser{#lexer;constructor(lexer=new Lexer){this.#lexer=lexer}parse(code){const tokenList=this.#lexer.tokenize(code),scope=this.#parseScope(tokenList);return new ESModule(scope)}parseFirst(code){const tokenList=this.#lexer.tokenize(code);return this.#parseNext(tokenList)}parseValue(code){const model=this.parseFirst(code);if(model instanceof ESValue==!1)throw new UnexpectedParseResult("a value definition");return model}parseImport(code){const model=this.parseFirst(code);if(model instanceof ESImport==!1)throw new UnexpectedParseResult("an import definition");return model}parseExport(code){const model=this.parseFirst(code);if(model instanceof ESExport==!1)throw new UnexpectedParseResult("an export definition");return model}parseDeclaration(code){const model=this.parseFirst(code);if(model instanceof ESDeclaration==!1)throw new UnexpectedParseResult("a declaration definition");return model}parseFunction(code){const tokenList=this.#lexer.tokenize(code),model=this.#parseMember(tokenList);if(model instanceof ESFunction==!1)throw new UnexpectedParseResult("a function definition");return model}parseClass(code){const tokenList=this.#lexer.tokenize(code),model=this.#parseMember(tokenList);if(model instanceof ESClass==!1)throw new UnexpectedParseResult("a class definition");return model}#parseScope(tokenList){const members=[];for(;tokenList.notAtEnd();){const member=this.#parseNext(tokenList);member instanceof ESMember&&members.push(member)}return new ESScope(members)}#parseNext(tokenList,isAsync=!1){const token=tokenList.current;if(token.isType(TokenType.LITERAL))return this.#parseExpression(tokenList);if(token.isType(TokenType.IDENTIFIER)){const next=tokenList.next;return next?.hasValue(Operator.ARROW)?this.#parseArrowFunction(tokenList,isAsync):this.#parseExpression(tokenList)}if(token.isType(TokenType.KEYWORD)){if(isNotReserved(token.value)){const next=tokenList.next,nextIsFunction=void 0!==next&&(next.hasValue(Keyword.FUNCTION)||next.hasValue(Group.OPEN));if(token.hasValue(Keyword.ASYNC)&&nextIsFunction)return tokenList.step(),this.#parseNext(tokenList,!0);if(void 0===next||this.#atEndOfStatement(next))return this.#parseExpression(tokenList)}return token.hasValue(Keyword.RETURN)?this.#parseExpression(tokenList):this.#parseMember(tokenList,isAsync)}if(token.isType(TokenType.REGEX))return this.#parseExpression(tokenList);if(token.hasValue(Group.OPEN)){const next=this.#peekAfterBlock(tokenList,Group.OPEN,Group.CLOSE);return next?.hasValue(Operator.ARROW)?this.#parseArrowFunction(tokenList,isAsync):this.#parseExpression(tokenList)}if(token.hasValue(Scope.OPEN))return this.#parseObject(tokenList);if(token.hasValue(List.OPEN))return this.#parseArray(tokenList);if(token.hasValue(Operator.NOT)||token.hasValue(Operator.SUBTRACT))return this.#parseExpression(tokenList);if(!isDivider(token.value))throw new UnexpectedToken(token.value,token.start);tokenList.step()}#parseMember(tokenList,isAsync=!1){const token=tokenList.current;switch(tokenList.step(),token.value){case Keyword.IMPORT:return this.#parseImport(tokenList);case Keyword.EXPORT:return this.#parseExport(tokenList);case Keyword.CLASS:return this.#parseClass(tokenList);case Keyword.FUNCTION:return this.#parseFunction(tokenList,isAsync);case Keyword.VAR:case Keyword.LET:case Keyword.CONST:return this.#parseDeclaration(tokenList,!1,!0);case Keyword.ASYNC:return this.#parseMember(tokenList,!0);default:throw new UnexpectedKeyword(token.value,token.start)}}#parseImport(tokenList){const members=[];let token=tokenList.current;if(token.isType(TokenType.LITERAL))return new ESImport(members,token.value);if(token.hasValue(Group.OPEN)){token=tokenList.step();const from=token.value;return tokenList.step(2),new ESImport(members,from)}if(!1===token.hasValue(Scope.OPEN)){const name=token.hasValue(Operator.MULTIPLY)?Operator.MULTIPLY:"default";let as=token.value;token=tokenList.step(),token.hasValue(Keyword.AS)&&(token=tokenList.step(),as=token.value,token=tokenList.step()),members.push(new ESAlias(name,as))}if(token.hasValue(Divider.SEPARATOR)&&(token=tokenList.step()),token.hasValue(Scope.OPEN)){const aliases=this.#parseAliasList(tokenList);members.push(...aliases),token=tokenList.current}if(!1===token.hasValue(Keyword.FROM))throw new ExpectedKeyword(Keyword.FROM,token.start);token=tokenList.step();const from=token.value;return tokenList.step(),new ESImport(members,from)}#parseExport(tokenList){switch(tokenList.current.value){case Keyword.DEFAULT:return tokenList.step(),this.#parseSingleExport(tokenList,!0);case Scope.OPEN:return this.#parseMultiExport(tokenList);default:return this.#parseSingleExport(tokenList,!1)}}#parseSingleExport(tokenList,isDefault){let token=tokenList.current,stepSize=0;var value;token.hasValue(Keyword.ASYNC)&&(token=tokenList.step(),stepSize++),((value=token.value)===Keyword.CLASS||value===Keyword.FUNCTION||value===Keyword.CONST||value===Keyword.LET||value===Keyword.VAR)&&(token=tokenList.step(),stepSize++);const name=this.#isIdentifier(token)?token.value:"",as=isDefault?"default":name;let from;token=tokenList.step(),token?.hasValue(Keyword.FROM)&&(token=tokenList.step(),from=token.value),stepSize>0&&(stepSize++,tokenList.stepBack(stepSize));const alias=new ESAlias(name,as);return new ESExport([alias],from)}#parseMultiExport(tokenList){const members=this.#parseAliasList(tokenList);let from,token=tokenList.current;return token?.hasValue(Keyword.FROM)&&(token=tokenList.step(),from=token.value),tokenList.step(),new ESExport(members,from)}#parseAliasList(tokenList){const aliases=[];let token=tokenList.step();for(;tokenList.notAtEnd();){if(token.hasValue(Scope.CLOSE)){tokenList.step();break}if(token.hasValue(Divider.SEPARATOR)){token=tokenList.step();continue}const alias=this.#parseAlias(tokenList);aliases.push(alias),token=tokenList.step()}return aliases}#parseAlias(tokenList){let token=tokenList.current;const name=token.value;let as=name;return tokenList.next.hasValue(Keyword.AS)&&(token=tokenList.step(2),as=token.value),new ESAlias(name,as)}#parseDeclaration(tokenList,isStatic,parseMultiple=!1){let identifier,value,token=tokenList.current,isPrivate=!1;return token.hasValue(List.OPEN)?(identifier=this.#parseDestructuredArray(tokenList),token=tokenList.current):token.hasValue(Scope.OPEN)?(identifier=this.#parseDestructuredObject(tokenList),token=tokenList.current):(isPrivate=token.value.startsWith("#"),identifier=isPrivate?token.value.substring(1):token.value,token=tokenList.step()),token.hasValue(Operator.ASSIGN)&&(tokenList.step(),value=this.#parseNext(tokenList,!1),token=tokenList.current),void 0!==token&&(token.hasValue(Divider.TERMINATOR)?tokenList.step():!0===parseMultiple&&token.hasValue(Divider.SEPARATOR)&&(tokenList.step(),this.#parseDeclaration(tokenList,isStatic,!0))),value instanceof ESGenerator?new ESGenerator(identifier.toString(),value.parameters,value.body,isStatic,value.isAsync,isPrivate):value instanceof ESFunction?new ESFunction(identifier.toString(),value.parameters,value.body,isStatic,value.isAsync,isPrivate):value instanceof ESClass?new ESClass(identifier.toString(),value.parentName,value.scope):new ESDeclaration(identifier,value,isStatic,isPrivate)}#parseFunction(tokenList,isAsync,isStatic=!1,isGetter=!1,isSetter=!1){let token=tokenList.current,name="",isGenerator=!1,isPrivate=!1;token.hasValue(Operator.MULTIPLY)&&(isGenerator=!0,token=tokenList.step()),this.#isIdentifier(token)&&(isPrivate=token.value.startsWith("#"),name=isPrivate?token.value.substring(1):token.value,token=tokenList.step());const parameters=this.#parseParameters(tokenList,Group.CLOSE);if(token=tokenList.current,!1===token.hasValue(Scope.OPEN))throw new ExpectedToken(Scope.OPEN,token.start);const body=this.#parseBlock(tokenList,Scope.OPEN,Scope.CLOSE);return isGenerator?new ESGenerator(name,parameters,body,isStatic,isAsync,isPrivate):isGetter?new ESGetter(name,parameters,body,isStatic,isAsync,isPrivate):isSetter?new ESSetter(name,parameters,body,isStatic,isAsync,isPrivate):new ESFunction(name,parameters,body,isStatic,isAsync,isPrivate)}#parseArrowFunction(tokenList,isAsync){let parameters,token=tokenList.current;if(token.hasValue(Group.OPEN)?(parameters=this.#parseParameters(tokenList,Group.CLOSE),token=tokenList.current):(parameters=[new ESField(token.value,void 0)],token=tokenList.step()),!1===token.hasValue(Operator.ARROW))throw new ExpectedToken(Operator.ARROW,token.start);token=tokenList.step();const body=token.hasValue(Scope.OPEN)?this.#parseBlock(tokenList,Scope.OPEN,Scope.CLOSE):this.#parseExpression(tokenList).definition;return new ESFunction("",parameters,body,!1,isAsync,!1)}#parseParameters(tokenList,closeId){const parameters=[];for(tokenList.step();tokenList.notAtEnd();){const token=tokenList.current;if(token.hasValue(closeId)){tokenList.step();break}if(token.hasValue(Divider.SEPARATOR)){tokenList.step();continue}let parameter;parameter=token.hasValue(Scope.OPEN)?this.#parseDestructuredObject(tokenList):token.hasValue(List.OPEN)?this.#parseDestructuredArray(tokenList):this.#parseField(tokenList),parameters.push(parameter)}return parameters}#parseClass(tokenList){let parent,token=tokenList.current,name="";if(this.#isIdentifier(token)&&(name=token.value,token=tokenList.step()),token.hasValue(Keyword.EXTENDS)&&(token=tokenList.step(),parent=token.value,token=tokenList.step()),!1===token.hasValue(Scope.OPEN))throw new ExpectedToken(Scope.OPEN,token.start);const scope=this.#parseClassScope(tokenList);return new ESClass(name,parent,scope)}#parseClassScope(tokenList){let token=tokenList.step();const members=[];for(;tokenList.notAtEnd();){if(token.hasValue(Scope.CLOSE)){tokenList.step();break}const member=this.#parseClassMember(tokenList);members.push(member),token=tokenList.current}return new ESScope(members)}#parseClassMember(tokenList){let token=tokenList.current,isAsync=!1,isStatic=!1,isGetter=!1,isSetter=!1;for(;tokenList.notAtEnd();){if(token.hasValue(Keyword.STATIC))isStatic=!0;else if(token.hasValue(Keyword.ASYNC))isAsync=!0;else if(token.hasValue(Keyword.GET))isGetter=!0;else{if(!token.hasValue(Keyword.SET)){if(token.hasValue(Operator.MULTIPLY))return this.#parseFunction(tokenList,isAsync,isStatic,!1,!1);break}isSetter=!0}token=tokenList.step()}return tokenList.next.hasValue(Group.OPEN)?this.#parseFunction(tokenList,isAsync,isStatic,isGetter,isSetter):this.#parseDeclaration(tokenList,isStatic)}#parseArray(tokenList){const items=this.#parseBlock(tokenList,List.OPEN,List.CLOSE);return new ESArray(items)}#parseDestructuredArray(tokenList){const fields=this.#parseParameters(tokenList,List.CLOSE);return new ESDestructuredArray(fields)}#parseObject(tokenList){const fields=this.#parseBlock(tokenList,Scope.OPEN,Scope.CLOSE);return new ESObject(fields)}#parseDestructuredObject(tokenList){const fields=this.#parseParameters(tokenList,Scope.CLOSE);return new ESDestructuredObject(fields)}#parseField(tokenList){let token=tokenList.current;const name=token.value;let value;return token=tokenList.step(),token.hasValue(Operator.ASSIGN)&&(tokenList.step(),value=this.#parseNext(tokenList,!1)),new ESField(name,value)}#parseExpression(tokenList){let token=tokenList.current,code="";for(;tokenList.notAtEnd();){if(token.hasValue(List.OPEN)){code+=this.#parseBlock(tokenList,List.OPEN,List.CLOSE)+" ",token=tokenList.current}else if(token.hasValue(Group.OPEN)){code+=this.#parseBlock(tokenList,Group.OPEN,Group.CLOSE)+" ",token=tokenList.current}else if(token.hasValue(Scope.OPEN)){code+=this.#parseBlock(tokenList,Scope.OPEN,Scope.CLOSE)+" ",token=tokenList.current}else code+=token.toString()+" ",token=tokenList.step();if(void 0===token||this.#atEndOfStatement(token))break}return new ESExpression(code.trim())}#parseBlock(tokenList,openId,closeId){let token=tokenList.step(),code=openId+" ";for(;tokenList.notAtEnd();)if(token.hasValue(openId))code+=this.#parseBlock(tokenList,openId,closeId)+" ",token=tokenList.current;else{if(token.hasValue(closeId))return tokenList.step(),code+=closeId,code;code+=token.toString()+" ",token=tokenList.step()}return code}#peekAfterBlock(tokenList,openId,closeId){const start=tokenList.position;this.#parseBlock(tokenList,openId,closeId);const token=tokenList.current,end=tokenList.position;return tokenList.stepBack(end-start),token}#atEndOfStatement(token){return[Divider.TERMINATOR,Divider.SEPARATOR].includes(token.value)||[List.CLOSE,Group.CLOSE,Scope.CLOSE].includes(token.value)||isKeyword(token.value)}#isIdentifier(token){return token.isType(TokenType.IDENTIFIER)||token.isType(TokenType.KEYWORD)&&isNotReserved(token.value)}}class ClassMerger{merge(model,parent){const declarations=this.#mergeDeclarations(model.declarations,parent.declarations),functions=this.#mergeFunctions(model.functions,parent.functions),getters=this.#mergeFunctions(model.getters,parent.getters),setters=this.#mergeFunctions(model.setters,parent.setters),members=[...declarations.values(),...functions.values(),...getters.values(),...setters.values()];return new ESClass(model.name,parent.name,new ESScope(members))}#mergeDeclarations(model,parent){const declarations=new Map;return parent.forEach(declaration=>declarations.set(declaration.name,declaration)),model.forEach(declaration=>declarations.set(declaration.name,declaration)),[...declarations.values()]}#mergeFunctions(model,parent){const functions=new Map;return parent.forEach(funktion=>functions.set(funktion.name,funktion)),model.forEach(funktion=>functions.set(funktion.name,funktion)),[...functions.values()]}}class Reflector{#parser=new Parser;#merger=new ClassMerger;fromModule(module,inherit=!1){const entries=Object.entries(module),members=[];for(const[key,member]of entries){if("function"!=typeof member.toString)continue;const code=member.toString();if(code.startsWith("class"))members.push(this.fromClass(member,inherit));else if(code.startsWith("function"))members.push(this.fromFunction(member));else{const expression=new ESExpression(code);members.push(new ESDeclaration(key,expression))}}return new ESModule(new ESScope(members))}fromClass(clazz,inherit=!1){const model=this.isClass(clazz)?this.#reflectStatic(clazz):this.#reflectDynamic(clazz);if(!1===inherit)return model;const parentClazz=this.getParentClass(clazz);if(""===parentClazz.name)return model;const parentModel=this.fromClass(parentClazz,!0);return this.#merger.merge(model,parentModel)}fromObject(object,inherit=!0){const clazz=this.getClass(object);return this.fromClass(clazz,inherit)}fromFunction(funktion){const code=funktion.toString();return this.#parser.parseFunction(code)}createInstance(clazz,args=[]){return new clazz(...args)}getClass(object){return object.constructor}getParentClass(clazz){return Object.getPrototypeOf(clazz)}isClassObject(object){return this.isClass(object.constructor)}isFunctionObject(object){return this.isFunction(object.constructor)}isClass(clazz){return clazz.toString().startsWith("class")}isFunction(clazz){return clazz.toString().startsWith("function")||clazz.toString().startsWith("async function")}#reflectStatic(clazz){const code=clazz.toString();return this.#parser.parseClass(code)}#reflectDynamic(clazz){const object=this.createInstance(clazz),members=this.#getMembers(clazz,object),scope=new ESScope(members);return new ESClass(clazz.name,void 0,scope)}#getMembers(clazz,object){return[...this.#getDeclarations(object),...this.#getFunctions(clazz)]}#getDeclarations(object){const fieldNames=Object.getOwnPropertyNames(object),values=object,models=[];for(const fieldName of fieldNames){const content=values[fieldName],value=void 0!==content?new ESValue(String(content)):void 0,model=new ESDeclaration(fieldName,value);models.push(model)}return models}#getFunctions(clazz){const functionDescriptions=Object.getOwnPropertyDescriptors(clazz.prototype),models=[];for(const functionName in functionDescriptions){const description=functionDescriptions[functionName],funktion=description.value;if(funktion instanceof Function==!1)continue;const model=this.fromFunction(funktion);void 0!==description.get?models.push(new ESGetter(model.name,model.parameters,model.body,model.isStatic,model.isAsync,model.isPrivate)):void 0!==description.set?models.push(new ESSetter(model.name,model.parameters,model.body,model.isStatic,model.isAsync,model.isPrivate)):models.push(model)}return models}}const reflector$1=new Reflector;class ClassSerializer extends ValueSerializer{#classResolver;constructor(classResolver){super(),this.#classResolver=classResolver}canSerialize(value){return value instanceof Object&&reflector$1.isClassObject(value)}canDeserialize(value){const object=value;return object instanceof Object&&!0===object.serialized&&"class"===object.name&&"string"==typeof object.key&&object.args instanceof Object&&object.args.constructor===Object&&object.fields instanceof Object&&object.fields.constructor===Object}async serialize(object){const clazz=reflector$1.getClass(object),model=reflector$1.fromClass(clazz,!0),parameterNames=this.#extractConstructorParameters(model),key=this.#classResolver.resolveKey(clazz);if(void 0===key)throw new ClassNotFound(clazz.name);return{serialized:!0,key:key,name:"class",args:await this.#serializeConstructor(model,parameterNames,object),fields:await this.#serializeFields(model,parameterNames,object)}}#extractConstructorParameters(model){const constructor=model.getFunction("constructor");return(constructor?.parameters??[]).map(parameter=>parameter.name)}async#serializeConstructor(model,includeNames,object){const args={};for(const[index,name]of includeNames.entries()){const value=model.canRead(name)?await this.serializeOther(object[name]):void 0;args[index.toString()]=value}return args}async#serializeFields(model,excludeNames,object){const fields={};for(const property of model.writable){const name=property.name;excludeNames.includes(name)||!1===model.canRead(name)||(fields[name]=await this.serializeOther(object[name]))}return fields}async deserialize(object){const clazz=await this.#getClass(object);if(void 0===clazz)throw new ClassNotFound(object.key);if(clazz instanceof Function==!1)throw new InvalidClass(object.key);const args=await this.#deserializeConstructor(clazz,object.args),instance=reflector$1.createInstance(clazz,args);for(const name in object.fields){const fieldValue=object.fields[name];instance[name]=await this.deserializeOther(fieldValue)}return instance}async#deserializeConstructor(clazz,args){const constructor=reflector$1.fromClass(clazz,!0).getFunction("constructor"),values=(constructor?.parameters??[]).map((_,index)=>{const key=index.toString(),value=args[key];return this.deserializeOther(value)});return Promise.all(values)}async#getClass(resolvable){return globalThis[resolvable.key]??this.#classResolver.resolveClass(resolvable.key)}}class InvalidDateString extends Error{constructor(dateString){super(`Invalid date string '${dateString}'`)}}class DateSerializer extends ValueSerializer{canSerialize(value){return value instanceof Date}canDeserialize(value){const date=value;return date instanceof Object&&!0===date.serialized&&"Date"===date.name&&"string"==typeof date.value}async serialize(date){return{serialized:!0,name:"Date",value:date.toISOString()}}async deserialize(object){const date=new Date(object.value);if("Invalid Date"===date.toString())throw new InvalidDateString(object.value);return date}}class ErrorSerializer extends ValueSerializer{canSerialize(value){if(value instanceof Object==!1)return!1;const error=value;return error.constructor===Error||error.constructor===EvalError||error.constructor===RangeError||error.constructor===ReferenceError||error.constructor===SyntaxError||error.constructor===TypeError||error.constructor===URIError||error.constructor===AggregateError}canDeserialize(value){const error=value;return error instanceof Object&&!0===error.serialized&&"Error"===error.name&&error.type in globalThis}async serialize(error){return{serialized:!0,name:"Error",type:error.constructor.name,stack:error.stack,message:error.message,cause:error.cause}}async deserialize(object){const error=new(0,globalThis[object.type])(object.message,{cause:object.cause});return error.stack=object.stack,error}}class MapSerializer extends ValueSerializer{canSerialize(value){return value instanceof Map}canDeserialize(value){const map=value;return map instanceof Object&&!0===map.serialized&&"Map"===map.name&&map.entries instanceof Object&&map.entries.keys instanceof Array&&map.entries.values instanceof Array}async serialize(map){const keys=[],values=[];for(const[key,value]of map)keys.push(await this.serializeOther(key)),values.push(await this.serializeOther(value));return{serialized:!0,name:"Map",entries:{keys:keys,values:values}}}async deserialize(object){const keys=object.entries.keys,values=object.entries.values,result=new Map;for(let index=0;index<keys.length;index++){const key=await this.deserializeOther(keys[index]),value=await this.deserializeOther(values[index]);result.set(key,value)}return result}}class ObjectSerializer extends ValueSerializer{canSerialize(value){return value instanceof Object&&value.constructor===Object}canDeserialize(value){return value instanceof Object&&value.constructor===Object}async serialize(object){const result={};for(const key in object){const value=object[key];result[key]=await this.serializeOther(value)}return result}async deserialize(object){const result={};for(const key in object){const value=object[key];result[key]=await this.deserializeOther(value)}return result}}class PrimitiveSerializer extends ValueSerializer{canSerialize(value){return value instanceof Object==!1}canDeserialize(value){return value instanceof Object==!1}async serialize(primitive){return primitive}async deserialize(primitive){return primitive}}class InvalidRegExp extends Error{constructor(source,flags){super(`Invalid regular expression '${source}' with flags '${flags}'`)}}class RegExpSerializer extends ValueSerializer{canSerialize(value){return value instanceof RegExp}canDeserialize(value){const regExp=value;return regExp instanceof Object&&!0===regExp.serialized&&"RegExp"===regExp.name&&"string"==typeof regExp.source&&"string"==typeof regExp.flags}async serialize(regExp){return{serialized:!0,name:"RegExp",source:regExp.source,flags:regExp.flags}}async deserialize(object){try{return new RegExp(object.source,object.flags)}catch{throw new InvalidRegExp(object.source,object.flags)}}}class SetSerializer extends ValueSerializer{canSerialize(value){return value instanceof Set}canDeserialize(value){const set=value;return set instanceof Object&&!0===set.serialized&&"Set"===set.name&&set.values instanceof Array}async serialize(set){const values=[];for(const value of set.values())values.push(await this.serializeOther(value));return{serialized:!0,name:"Set",values:values}}async deserialize(object){const values=await Promise.all(object.values.map(async value=>this.deserializeOther(value)));return new Set([...values])}}const reflector=new Reflector;class ArrayBufferSerializer extends ValueSerializer{canSerialize(value){return value instanceof Int8Array||value instanceof Uint8Array||value instanceof Uint8ClampedArray||value instanceof Int16Array||value instanceof Uint16Array||value instanceof Int32Array||value instanceof Uint32Array||value instanceof Float32Array||value instanceof Float64Array||value instanceof BigInt64Array||value instanceof BigUint64Array}canDeserialize(value){const array=value;return array instanceof Object&&!0===array.serialized&&"TypedArray"===array.name&&array.type in globalThis&&array.bytes instanceof Array}async serialize(array){const type=array.constructor.name,view=new DataView(array.buffer),bytes=[];for(let index=0;index<view.byteLength;index++)bytes.push(view.getUint8(index));return{serialized:!0,name:"TypedArray",type:type,bytes:bytes}}async deserialize(object){const type=object.type,bytes=object.bytes,buffer=new ArrayBuffer(bytes.length),view=new DataView(buffer);for(let index=0;index<bytes.length;index++)view.setUint8(index,bytes[index]);const clazz=globalThis[type];return reflector.createInstance(clazz,[buffer])}}class InvalidUrlString extends Error{constructor(urlString){super(`Invalid url string '${urlString}'`)}}class UrlSerializer extends ValueSerializer{canSerialize(value){return value instanceof URL}canDeserialize(value){const url=value;return url instanceof Object&&!0===url.serialized&&"Url"===url.name&&"string"==typeof url.value}async serialize(url){return{serialized:!0,name:"Url",value:url.toString()}}async deserialize(object){try{return new URL(object.value)}catch{throw new InvalidUrlString(object.value)}}}class SerializerBuilder{static build(classResolver){const serializer=new Serializer;return serializer.addSerializer(new PrimitiveSerializer),serializer.addSerializer(new ObjectSerializer),void 0!==classResolver&&serializer.addSerializer(new ClassSerializer(classResolver)),serializer.addSerializer(new ErrorSerializer),serializer.addSerializer(new RegExpSerializer),serializer.addSerializer(new BigIntSerializer),serializer.addSerializer(new UrlSerializer),serializer.addSerializer(new DateSerializer),serializer.addSerializer(new SetSerializer),serializer.addSerializer(new MapSerializer),serializer.addSerializer(new ArraySerializer),serializer.addSerializer(new ArrayBufferSerializer),"undefined"!=typeof Buffer&&serializer.addSerializer(new BufferSerializer),serializer}}class ExecutionClassResolver{#executionManager;constructor(executionManager){this.#executionManager=executionManager}resolveKey(clazz){const model=this.#executionManager.getClassByImplementation(clazz);return model?.fqn}resolveClass(key){const model=this.#executionManager.getClass(key);return model?.implementation}}class RequestNotTrusted extends Unauthorized{constructor(){super("Request not trusted")}}class LocalWorker{#id;#url;#trustKey;#gateway;#registerAtGateway;#executionManager;#healthManager;#reportTask;#serializer;#stateManager=new StateManager;constructor(configuration){this.#url=configuration.url,this.#trustKey=configuration.trustKey,this.#gateway=configuration.gateway,this.#registerAtGateway=!0===configuration.registerAtGateway,this.#executionManager=configuration.executionManager,this.#healthManager=configuration.healthManager;const scheduleManager=configuration.scheduleManager;this.#reportTask=scheduleManager.create(()=>this.#report(),configuration.reportInterval);const classResolver=new ExecutionClassResolver(this.#executionManager);this.#serializer=SerializerBuilder.build(classResolver)}get id(){return this.#id}set id(id){this.#id=id}get state(){return this.#stateManager.state}get url(){return this.#url}get trustKey(){return this.#trustKey}async start(){return this.#stateManager.start(async()=>{await Promise.all([this.#executionManager.start(),this.#healthManager.start()]),void 0!==this.#gateway&&(await this.#gateway.start(),this.#registerAtGateway&&(this.#id=await this.#gateway.addWorker(this),this.#reportTask.start())),await this.updateState()})}async stop(){return this.#stateManager.stop(async()=>{void 0!==this.#gateway&&(void 0!==this.#id&&(this.#reportTask.stop(),await this.#gateway.removeWorker(this.#id)),await this.#gateway.stop()),await Promise.all([this.#healthManager.stop(),this.#executionManager.stop()])})}getProcedureNames(){return this.#executionManager.getProcedureNames()}hasProcedure(name){return this.#executionManager.hasProcedure(name)}isHealthy(){return this.#healthManager.isHealthy()}getHealth(){return this.#healthManager.getHealth()}isAvailable(){return this.#stateManager.isAvailable()}async updateState(){const healthy=await this.isHealthy();return this.#stateManager.setAvailability(healthy)}async reportState(state){if(void 0!==this.#gateway&&void 0!==this.#id)return this.#gateway.reportWorker(this.#id,state)}async run(request){return this.#mustRunLocal(request)?this.#runLocal(request):this.#runRemote(request)}#mustRunLocal(request){return void 0===this.#gateway||this.#executionManager.hasProcedure(request.fqn)}async#runLocal(request){const procedure=this.#executionManager.getProcedure(request.fqn),implementation=procedure?.getImplementation(request.version);if(this.#procedureNotFound(implementation))throw new ProcedureNotFound(request.fqn);if(this.#requestNotTrusted(request,implementation))throw new RequestNotTrusted;const dataEncoding=request.getHeader("X-Jitar-Data-Encoding");"serialized"===dataEncoding&&(request=await this.#deserializeRequest(request)),request.removeHeader("X-Jitar-Data-Encoding");const response=await this.#executionManager.run(request);return"serialized"===dataEncoding?this.#serializeResponse(response):response}#procedureNotFound(implementation){return void 0===implementation||implementation.private}#requestNotTrusted(request,implementation){if(implementation.public)return!1;const trustKey=request.getHeader("X-Jitar-Trust-Key");return this.#trustKey!==trustKey}async#runRemote(request){(request=await this.#serializeRequest(request)).setHeader("X-Jitar-Data-Encoding","serialized"),void 0!==this.#trustKey&&request.setHeader("X-Jitar-Trust-Key",this.#trustKey);const response=await this.#gateway.run(request);return this.#deserializeResponse(response)}async#serializeRequest(request){const serializedArgs=new Map;for(const[key,value]of request.args){const serializedValue=await this.#serializer.serialize(value);serializedArgs.set(key,serializedValue)}return new Request(request.fqn,request.version,serializedArgs,request.headers,request.mode)}async#deserializeRequest(request){const deserializedArgs=new Map;for(const[key,value]of request.args){const deserializedValue=await this.#serializer.deserialize(value);deserializedArgs.set(key,deserializedValue)}return new Request(request.fqn,request.version,deserializedArgs,request.headers,request.mode)}async#serializeResponse(response){const serializedResult=await this.#serializer.serialize(response.result);return new Response(response.status,serializedResult,response.headers)}async#deserializeResponse(response){const deserializedResult=await this.#serializer.deserialize(response.result);return new Response(response.status,deserializedResult,response.headers)}async#report(){const state=await this.updateState();return this.reportState(state)}}class ProcedureRunner{#runner;constructor(runner){this.#runner=runner}async handle(request,next){return this.#runner.run(request)}}class Runtime{#versionParser=new VersionParser;constructor(){this.#initGlobals()}#initGlobals(){const globals=globalThis;globals.__run=this.#run.bind(this),globals.ProcedureNotAccessible=ProcedureNotAccessible}async#run(fqn,versionNumber,args,sourceRequest){const version=this.#versionParser.parse(versionNumber),argsMap=new Map(Object.entries(args)),headersMap=sourceRequest instanceof Request?sourceRequest.headers:new Map,targetRequest=new Request(fqn,version,argsMap,headersMap,RunModes_NORMAL),trustKey=this.getTrustKey();void 0!==trustKey&&targetRequest.setHeader("X-Jitar-Trust-Key",trustKey);const targetResponse=await this.runInternal(targetRequest);if(targetResponse.status!==StatusCodes_OK)throw targetResponse.result;return targetResponse.result}}class Client extends Runtime{#worker;#middlewareManager;#requestPool=new RequestPool(this);constructor(configuration){super(),this.#worker=new LocalWorker({url:configuration.remoteUrl,gateway:new RemoteGateway({url:configuration.remoteUrl,remote:configuration.remote}),healthManager:configuration.healthManager,executionManager:configuration.executionManager,scheduleManager:configuration.scheduleManager}),this.#middlewareManager=configuration.middlewareManager}get worker(){return this.#worker}async start(){await this.#setUp(),this.#requestPool.start()}async stop(){this.#requestPool.stop(),await this.#tearDown()}getTrustKey(){}run(request){return this.#middlewareManager.handle(request)}async runInternal(request){return this.#requestPool.run(request)}async#setUp(){await Promise.all([this.#worker.start(),this.#middlewareManager.start()]);const procedureRunner=new ProcedureRunner(this.#worker);this.#middlewareManager.addMiddleware(procedureRunner)}async#tearDown(){await Promise.all([this.#middlewareManager.stop(),this.#worker.stop()])}}const States$1_STARTING="starting",States$1_STARTED="started",States$1_STOPPING="stopping",States$1_STOPPED="stopped";class InvalidHealthCheck extends ServerError{constructor(){super("Invalid health check")}}class HealthManager{#state=States$1_STOPPED;#healthChecks=new Map;#moduleImporter;#healthCheckFiles;constructor(moduleImporter,healthCheckFiles=[]){this.#moduleImporter=moduleImporter,this.#healthCheckFiles=healthCheckFiles}get state(){return this.#state}async start(){if(this.#state===States$1_STOPPED)try{this.#state=States$1_STARTING,await this.#loadHealthChecks(),this.#state=States$1_STARTED}catch(error){throw this.#state=States$1_STOPPED,error}}async stop(){if(this.#state===States$1_STARTED)try{this.#state=States$1_STOPPING,this.clearHealthChecks(),this.#state=States$1_STOPPED}catch(error){throw this.#state=States$1_STARTED,error}}async loadHealthCheck(filename){const healthCheck=await this.#loadHealthCheck(filename);this.addHealthCheck(healthCheck)}addHealthCheck(healthCheck){if(void 0===healthCheck.isHealthy)throw new InvalidHealthCheck;this.#healthChecks.set(healthCheck.name,healthCheck)}clearHealthChecks(){this.#healthChecks.clear()}async isHealthy(){const promises=[];for(const healthCheck of this.#healthChecks.values()){const promise=this.#executeHealthCheck(healthCheck);promises.push(promise)}return Promise.all(promises).then(results=>results.every(result=>result)).catch(()=>!1)}async getHealth(){const promises=[];for(const[name,healthCheck]of this.#healthChecks){const promise=this.#executeHealthCheck(healthCheck).then(result=>({name:name,isHealthy:result})).catch(()=>({name:name,isHealthy:!1}));promises.push(promise)}const healthChecks=new Map;return Promise.allSettled(promises).then(results=>results.forEach(result=>this.#handleHealthCheckResult(result,healthChecks))).then(()=>healthChecks)}async#loadHealthChecks(){(await Promise.all(this.#healthCheckFiles.map(filename=>this.#loadHealthCheck(filename)))).forEach(healthCheck=>this.addHealthCheck(healthCheck))}async#loadHealthCheck(filename){return(await this.#moduleImporter.import(filename)).default}#handleHealthCheckResult(result,healthChecks){"fulfilled"===result.status?healthChecks.set(result.value.name,result.value.isHealthy):healthChecks.set(result.reason.name,!1)}async#executeHealthCheck(healthCheck){const health=healthCheck.isHealthy(),milliseconds=healthCheck.timeout;if(void 0===milliseconds)return health;const timeout=new Promise(resolve=>{setTimeout(resolve,milliseconds)}).then(()=>!1);return Promise.race([timeout,health])}}const LogLevels_DEBUG=0,LogLevels_INFO=1,LogLevels_WARN=2,LogLevels_ERROR=3;class Logger{#logLevel;#writer;constructor(logLevel=LogLevels_INFO,writer=console){this.#logLevel=logLevel,this.#writer=writer}debug(...message){if(this.#logLevel>LogLevels_DEBUG)return;const messageString=this.#createMessage("DEBUG",message);this.#writer.debug(messageString)}info(...message){if(this.#logLevel>LogLevels_INFO)return;const messageString=this.#createMessage("INFO",message);this.#writer.info(messageString)}warn(...message){if(this.#logLevel>LogLevels_WARN)return;const messageString=this.#createMessage("WARN",message);this.#writer.warn(messageString)}error(...message){if(this.#logLevel>LogLevels_ERROR)return;const messageString=this.#createMessage("ERROR",message);this.#writer.error(messageString)}fatal(...message){const messageString=this.#createMessage("FATAL",message);this.#writer.error(messageString)}#createMessage(logLevel,messages){return`[${logLevel}][${(new Date).toISOString()}] ${messages.map(value=>this.#interpretValue(value)).join(" ")}`}#interpretValue(value,level=0){let result;switch(typeof value){case"string":result=value;break;case"object":result=this.#interpretObject(value,level+1);break;case"undefined":result="undefined";break;case"function":result="function";break;default:result=String(value)}return`${this.#indent(level)}${result}`}#interpretObject(object,level){if(null===object)return"null";if(Array.isArray(object)){return`[\n${object.map(value=>this.#interpretValue(value,level)).join(",\n")}\n${this.#indent(level-1)}]`}return object instanceof Error?object.stack??object.message:JSON.stringify(object)}#indent(level){return" ".repeat(level)}}const States_STARTING="starting",States_STARTED="started",States_STOPPING="stopping",States_STOPPED="stopped";class InvalidMiddleware extends ServerError{constructor(){super("Invalid middleware")}}class MiddlewareManager{#state=States_STOPPED;#middlewares=[];#moduleImporter;#middlewareFiles;constructor(moduleImporter,middlewareFiles=[]){this.#moduleImporter=moduleImporter,this.#middlewareFiles=middlewareFiles}get state(){return this.#state}async start(){if(this.#state===States_STOPPED)try{this.#state=States_STARTING,await this.#loadMiddlewares(),this.#state=States_STARTED}catch(error){throw this.#state=States_STOPPED,error}}async stop(){if(this.#state===States_STARTED)try{this.#state=States_STOPPING,this.clearMiddlewares(),this.#state=States_STOPPED}catch(error){throw this.#state=States_STARTED,error}}async loadMiddleware(filename){const middleware=await this.#loadMiddleware(filename);this.addMiddleware(middleware)}addMiddleware(middleware){if(void 0===middleware?.handle)throw new InvalidMiddleware;this.#middlewares.push(middleware)}getMiddleware(type){return this.#middlewares.find(middleware=>middleware instanceof type)}clearMiddlewares(){this.#middlewares=[]}handle(request){return this.#getNextHandler(request,0)()}async#loadMiddlewares(){(await Promise.all(this.#middlewareFiles.map(filename=>this.#loadMiddleware(filename)))).forEach(middleware=>this.addMiddleware(middleware))}async#loadMiddleware(filename){return(await this.#moduleImporter.import(filename)).default}#getNextHandler(request,index){const next=this.#middlewares[index];if(void 0===next)return async()=>new Response(StatusCodes_OK);const nextHandler=this.#getNextHandler(request,index+1);return async()=>await next.handle(request,nextHandler)}}class ScheduledTask{#logger;#task;#interval;#timeout=null;constructor(logger,task,interval=5e3){this.#logger=logger,this.#task=task,this.#interval=interval}start(){this.#scheduleNextExecution()}stop(){null!==this.#timeout&&(clearTimeout(this.#timeout),this.#timeout=null)}#scheduleNextExecution(){this.#timeout=setTimeout(async()=>{null!==this.#timeout&&(await this.#executeTask(),this.#scheduleNextExecution())},this.#interval)}async#executeTask(){try{await this.#task()}catch(error){this.#logger.warn("Scheduled task failed",error)}}}class ScheduleManager{#scheduledTasks=[];#logger;constructor(logger){this.#logger=logger}create(task,interval){const scheduledTask=new ScheduledTask(this.#logger,task,interval);return this.#scheduledTasks.push(scheduledTask),scheduledTask}remove(scheduledTask){const index=this.#scheduledTasks.indexOf(scheduledTask);index<0||this.#scheduledTasks.splice(index,1)}startAll(){this.#scheduledTasks.forEach(scheduledTask=>scheduledTask.start())}stopAll(){this.#scheduledTasks.forEach(scheduledTask=>scheduledTask.stop())}}class ClientBuilder{#remoteBuilder;constructor(remoteBuilder){this.#remoteBuilder=remoteBuilder}build(configuration){const remoteUrl=configuration.remoteUrl,middleware=configuration.middleware,segments=configuration.segments,logger=new Logger(configuration.logLevel??LogLevels_WARN),remote=this.#remoteBuilder.build(remoteUrl),sourcingManager=new RemoteSourcingManager(remoteUrl),healthManager=this.#buildHealthManager(sourcingManager),middlewareManager=this.#buildMiddlewareManager(sourcingManager,middleware),executionManager=this.#buildExecutionManager(sourcingManager,segments),scheduleManager=this.#buildScheduleManager(logger);return new Client({remoteUrl:remoteUrl,remote:remote,healthManager:healthManager,middlewareManager:middlewareManager,executionManager:executionManager,scheduleManager:scheduleManager})}#buildHealthManager(sourcingManager){return new HealthManager(sourcingManager)}#buildMiddlewareManager(sourcingManager,middleware=[]){const manager=new MiddlewareManager(sourcingManager);return middleware.forEach(middleware=>manager.addMiddleware(middleware)),manager}#buildExecutionManager(sourcingManager,segments=[]){const manager=new ExecutionManager(sourcingManager);return segments.forEach(segment=>manager.addSegment(segment)),manager}#buildScheduleManager(logger){return new ScheduleManager(logger)}}class Validator{#strict;constructor(strict=!0){this.#strict=strict}validate(data,scheme){const errors=[];this.#validateData("",data,scheme,errors);return{valid:0===errors.length,errors:errors}}#validateData(key,data,scheme,errors){this.#strict&&this.#validateKeys(key,data,scheme,errors),this.#validateValues(key,data,scheme,errors)}#validateKeys(key,data,scheme,errors){const dataKeys=Object.keys(data),schemeKeys=Object.keys(scheme);for(const dataKey of dataKeys)if(!1===schemeKeys.includes(dataKey)){const absoluteKey=this.#composeKey(key,dataKey);errors.push(`Unknown field '${absoluteKey}'`)}}#validateValues(key,data,scheme,errors){const valueKeys=Object.keys(scheme);for(const valueKey of valueKeys){const absoluteKey=this.#composeKey(key,valueKey),fieldScheme=scheme[valueKey],value=data[valueKey];this.#validateValue(absoluteKey,value,fieldScheme,errors)}}#validateValue(key,value,scheme,errors){if(void 0!==value)switch(scheme.type){case"string":return this.#validateString(key,value,scheme,errors);case"integer":return this.#validateInteger(key,value,scheme,errors);case"real":return this.#validateReal(key,value,scheme,errors);case"boolean":return this.#validateBoolean(key,value,scheme,errors);case"url":return this.#validateUrl(key,value,scheme,errors);case"group":return this.#validateGroup(key,value,scheme,errors);case"list":return this.#validateList(key,value,scheme,errors)}else!0===scheme.required&&errors.push(`Field '${key}' is required`)}#validateString(key,value,scheme,errors){"string"!=typeof value&&errors.push(`Field '${key}' is not a string`)}#validateInteger(key,value,scheme,errors){"number"==typeof value&&!1!==Number.isInteger(value)||errors.push(`Field '${key}' is not an integer`)}#validateReal(key,value,scheme,errors){"number"!=typeof value&&errors.push(`Field '${key}' is not a real number`)}#validateBoolean(key,value,scheme,errors){"boolean"!=typeof value&&errors.push(`Field '${key}' is not a boolean`)}#validateUrl(key,value,scheme,errors){"string"==typeof value&&!1!==value.startsWith("http")||errors.push(`Field '${key}' is not a valid URL`)}#validateGroup(key,value,scheme,errors){"object"==typeof value?this.#validateData(key,value,scheme.fields,errors):errors.push(`Field '${key}' is not an object`)}#validateList(key,value,scheme,errors){if(!Array.isArray(value))return void errors.push(`Field '${key}' is not a list`);const data=value;for(const itemIndex in data){const itemKey=this.#composeKey(key,itemIndex),itemValue=data[itemIndex];this.#validateValue(itemKey,itemValue,scheme.items,errors)}}#composeKey(parent,key){return""===parent?key:`${parent}.${key}`}}const HeaderKeys_CONTENT_TYPE="content-type",HeaderKeys_JITAR_CONTENT_TYPE="x-jitar-content-type",HeaderKeys_JITAR_PROCEDURE_VERSION="x-jitar-procedure-version",HeaderValues_APPLICATION_JSON="application/json",HeaderValues_APPLICATION_STREAM="application/octet-stream";class InvalidWorkerId extends Error{constructor(){super("Invalid worker id")}}class HttpRemote{#url;#httpClient;#errorConverter=new ErrorConverter;#validator=new Validator;constructor(url,httpClient){this.#url=url,this.#httpClient=httpClient}connect(){return Promise.resolve()}disconnect(){return Promise.resolve()}async provide(filename){const remoteUrl=`${this.#url}/${filename}`,response=await this.#callRemote(remoteUrl,{method:"GET"}),type=response.headers.get(HeaderKeys_CONTENT_TYPE)??HeaderValues_APPLICATION_STREAM,result=await response.arrayBuffer(),content=Buffer.from(result);return new File(filename,type,content)}async isHealthy(){const remoteUrl=`${this.#url}/health/status`,response=await this.#callRemote(remoteUrl,{method:"GET"});return"true"===await response.text()}async getHealth(){const remoteUrl=`${this.#url}/health`,response=await this.#callRemote(remoteUrl,{method:"GET"}),health=await response.json();return new Map(Object.entries(health))}async addWorker(url,procedureNames,trustKey){const remoteUrl=`${this.#url}/workers`,body={url:url,procedureNames:procedureNames,trustKey:trustKey},options={method:"POST",headers:{"Content-Type":HeaderValues_APPLICATION_JSON},body:JSON.stringify(body)},response=await this.#callRemote(remoteUrl,options),contentType=response.headers.get(HeaderKeys_CONTENT_TYPE);if(null===contentType||!1===contentType.includes(HeaderValues_APPLICATION_JSON))throw new InvalidWorkerId;const result=await response.json();if(!1===this.#validator.validate(result,{id:{type:"string",required:!0}}).valid)throw new InvalidWorkerId;return result.id}async reportWorker(id,state){const remoteUrl=`${this.#url}/workers/${id}/report`,body={state:state},options={method:"POST",headers:{"Content-Type":HeaderValues_APPLICATION_JSON},body:JSON.stringify(body)};await this.#callRemote(remoteUrl,options)}async removeWorker(id){const remoteUrl=`${this.#url}/workers/${id}`,options={method:"DELETE",headers:{"Content-Type":HeaderValues_APPLICATION_JSON}};await this.#callRemote(remoteUrl,options)}async run(request){request.setHeader(HeaderKeys_CONTENT_TYPE,HeaderValues_APPLICATION_JSON);const argsObject=Object.fromEntries(request.args),headersObject=Object.fromEntries(request.headers),versionString=request.version.toString();headersObject[HeaderKeys_JITAR_PROCEDURE_VERSION]=versionString;const remoteUrl=`${this.#url}/rpc/${request.fqn}`,options={method:"POST",redirect:"manual",headers:headersObject,body:await this.#createRequestBody(argsObject)},response=await this.#callRemote(remoteUrl,options,!1),status=response.status,result=await this.#getResponseResult(response),headers=this.#createResponseHeaders(response);return new Response(status,result,headers)}async#callRemote(remoteUrl,options,throwOnError=!0){const response=await this.#httpClient.execute(remoteUrl,options);if(throwOnError&&this.#isErrorResponse(response)){const result=await this.#getResponseResult(response);throw this.#errorConverter.fromStatus(response.status,String(result))}return response}#isErrorResponse(response){return response.status<200||response.status>399}async#createRequestBody(body){return JSON.stringify(body)}async#getResponseResult(response){const contentType=response.headers.get(HeaderKeys_JITAR_CONTENT_TYPE)??response.headers.get(HeaderKeys_CONTENT_TYPE);if(contentType?.includes("undefined"))return;if(contentType?.includes("null"))return null;if(contentType?.includes("json"))return response.json();const content=await response.text();return contentType?.includes("boolean")?"true"===content:contentType?.includes("number")?Number(content):content}#createResponseHeaders(response){const headers=new Map;for(const[name,value]of response.headers)headers.set(name,value);return headers}}class FetchHttpClient{async execute(url,options){return fetch(url,options)}}class HttpRemoteBuilder{#httpClient;constructor(httpClient=new FetchHttpClient){this.#httpClient=httpClient}build(url){return new HttpRemote(url,this.#httpClient)}}export{ArrayParameter,BadRequest,Class,ClientBuilder,Forbidden,HttpRemoteBuilder,Implementation,NamedParameter,NotFound,NotImplemented,ObjectParameter,PaymentRequired,Procedure,Request,Response,Segment,ServerError,Teapot,Unauthorized,Version};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jitar",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Distributed runtime for JavaScript and TypeScript to chop monolithic applications into micros.",
|
|
5
5
|
"author": "Masking Technology <info@masking.tech> (https://jitar.dev)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -31,7 +31,6 @@
|
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"dotenv": "^17.0.1",
|
|
33
33
|
"express": "^5.1.0",
|
|
34
|
-
"fs-extra": "^11.3.0",
|
|
35
34
|
"glob": "11.0.3",
|
|
36
35
|
"mime-types": "^3.0.1"
|
|
37
36
|
},
|