jitar 0.6.0 → 0.7.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/client.js CHANGED
@@ -1 +1 @@
1
- import{A as AccessLevels,H as Version,j as RemoteRepository,k as RemoteGateway,L as LocalNode}from"./globals-8t6x98aZ.js";export{O as ArrayParameter,B as BadRequest,C as ClientNotFound,F as FileNotFound,v as Forbidden,X as ImplementationNotFound,a as InvalidClientId,Y as InvalidParameterValue,I as InvalidSegmentFile,Z as InvalidVersionNumber,_ as MissingParameterValue,$ as ModuleNotAccessible,a0 as ModuleNotLoaded,K as NamedParameter,N as NoNodeAvailable,w as NotFound,x as NotImplemented,Q as ObjectParameter,u as PaymentRequired,a1 as ProcedureNotAccessible,P as ProcedureNotFound,a2 as RepositoryNotAvailable,y as Request,J as Response,a3 as RuntimeNotAvailable,a4 as SegmentNotFound,W as ServerError,T as Teapot,U as Unauthorized,a5 as UnknownParameter}from"./globals-8t6x98aZ.js";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 parameters(){return this.#parameters}get executable(){return this.#executable}}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))}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 Segment{#id;#procedures=new Map;constructor(id){this.#id=id}get id(){return this.#id}addProcedure(procedure){return this.#procedures.set(procedure.fqn,procedure),this}hasProcedure(fqn){return void 0!==this.getProcedure(fqn)}getProcedure(fqn){return this.#procedures.get(fqn)}getPublicProcedures(){return[...this.#procedures.values()].filter((procedure=>procedure.public))}}let client;const resolvers=[];async function startClient(remoteUrl,segmentNames=[],middlewares=[]){const repository=new RemoteRepository(remoteUrl),gateway=new RemoteGateway(remoteUrl),node=new LocalNode(repository,gateway);return node.segmentNames=new Set(segmentNames),node.middlewareFiles=new Set(middlewares),await node.start(),client=node,resolvers.forEach((resolve=>resolve(node))),resolvers.length=0,node}async function getClient(){return void 0===client?new Promise((resolve=>{resolvers.push(resolve)})):client}export{Implementation,Procedure,Segment,Version,getClient,startClient};
1
+ import{A as AccessLevels,H as Version,j as RemoteRepository,k as RemoteGateway,L as LocalWorker}from"./globals-12ESPPwb.js";export{O as ArrayParameter,B as BadRequest,C as ClientNotFound,F as FileNotFound,v as Forbidden,Y as ImplementationNotFound,b as InvalidClientId,Z as InvalidParameterValue,a as InvalidSegmentFile,_ as InvalidVersionNumber,$ as MissingParameterValue,a0 as ModuleNotAccessible,a1 as ModuleNotLoaded,K as NamedParameter,N as NoWorkerAvailable,w as NotFound,x as NotImplemented,Q as ObjectParameter,u as PaymentRequired,a2 as ProcedureNotAccessible,P as ProcedureNotFound,a3 as RepositoryNotAvailable,y as Request,J as Response,a4 as RuntimeNotAvailable,a5 as SegmentNotFound,X as ServerError,T as Teapot,U as Unauthorized,a6 as UnknownParameter}from"./globals-12ESPPwb.js";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 parameters(){return this.#parameters}get executable(){return this.#executable}}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(){if(this.public)return!1;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 Segment{#id;#procedures=new Map;constructor(id){this.#id=id}get id(){return this.#id}addProcedure(procedure){return this.#procedures.set(procedure.fqn,procedure),this}hasProcedure(fqn){return void 0!==this.getProcedure(fqn)}getProcedure(fqn){return this.#procedures.get(fqn)}getExposedProcedures(){return[...this.#procedures.values()].filter((procedure=>procedure.public||procedure.protected))}}let client;const resolvers=[];async function startClient(remoteUrl,segmentNames=[],middlewares=[]){const repository=new RemoteRepository(remoteUrl),gateway=new RemoteGateway(remoteUrl),worker=new LocalWorker(repository,gateway);return worker.segmentNames=new Set(segmentNames),worker.middlewareFiles=new Set(middlewares),await worker.start(),client=worker,resolvers.forEach((resolve=>resolve(worker))),resolvers.length=0,worker}async function getClient(){return void 0===client?new Promise((resolve=>{resolvers.push(resolve)})):client}export{Implementation,Procedure,Segment,Version,getClient,startClient};
@@ -0,0 +1 @@
1
+ const AccessLevels={PRIVATE:"private",PROTECTED:"protected",PUBLIC:"public"};Object.freeze(AccessLevels);const Files={MODULE_PATTERN:"**/*.js",SEGMENT_PATTERN:"**/*.segment.json",WORKER_SEGMENT_PATTERN:"**/*.segment.worker.js",REPOSITORY_SEGMENT_PATTERN:"**/*.segment.repository.js"};Object.freeze(Files);const EXTENSION_PATTERN=/\.js$/;function convertToLocalFilename(filename){return filename.replace(EXTENSION_PATTERN,".local.js")}function convertToRemoteFilename(filename){return filename.replace(EXTENSION_PATTERN,".remote.js")}function createWorkerFilename(name){return`./${name}.segment.worker.js`}function createRepositoryFilename(name){return`./${name}.segment.repository.js`}function isSegmentFilename(filename){return filename.includes(".segment.")}const ExecutionScopes={APPLICATION:"application",RUNTIME:"runtime"};Object.freeze(ExecutionScopes);class BadRequest extends Error{constructor(message="Invalid request"){super(message)}}BadRequest.source="/jitar/client.js";class Forbidden extends Error{constructor(message="Forbidden"){super(message)}}Forbidden.source="/jitar/client.js";class NotFound extends Error{constructor(message="Not found"){super(message)}}NotFound.source="/jitar/client.js";class NotImplemented extends Error{constructor(message="Not implemented"){super(message)}}NotImplemented.source="/jitar/client.js";class PaymentRequired extends Error{constructor(message="Payment required"){super(message)}}PaymentRequired.source="/jitar/client.js";class ServerError extends Error{constructor(message="Server error"){super(message)}}ServerError.source="/jitar/client.js";class Teapot extends Error{constructor(){super("I'm a teapot")}}Teapot.source="/jitar/client.js";class Unauthorized extends Error{constructor(message="Unauthorized"){super(message)}}Unauthorized.source="/jitar/client.js";class ClientNotFound extends BadRequest{#clientId;constructor(clientId){super(`Client not found for id '${clientId}'`),this.#clientId=clientId}get clientId(){return this.#clientId}}ClientNotFound.source="/jitar/client.js";class FileNotFound extends NotFound{#filename;constructor(filename){super(`The file '${filename}' could not be found`),this.#filename=filename}get filename(){return this.#filename}}FileNotFound.source="/jitar/client.js";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}}ImplementationNotFound.source="/jitar/client.js";class InvalidClientId extends BadRequest{#clientId;constructor(clientId){super(`Invalid client id '${clientId}'`),this.#clientId=clientId}get clientId(){return this.#clientId}}InvalidClientId.source="/jitar/client.js";class InvalidParameterValue extends BadRequest{#parameterName;constructor(parameterName){super(`Invalid value for parameter '${parameterName}'`),this.#parameterName=parameterName}get parameterName(){return this.#parameterName}}InvalidParameterValue.source="/jitar/client.js";class InvalidSegmentFile extends ServerError{#filename;constructor(filename){super(`Missing files array in segment file '${filename}'`),this.#filename=filename}get filename(){return this.#filename}}InvalidSegmentFile.source="/jitar/client.js";class InvalidVersionNumber extends BadRequest{#number;constructor(number){super(`Invalid version number '${number}'`),this.#number=number}get number(){return this.#number}}InvalidVersionNumber.source="/jitar/client.js";class MissingParameterValue extends BadRequest{#parameterName;constructor(parameterName){super(`Missing value for parameter '${parameterName}'`),this.#parameterName=parameterName}get parameterName(){return this.#parameterName}}MissingParameterValue.source="/jitar/client.js";class ModuleNotAccessible extends Forbidden{#url;constructor(url){super(`Module '${url}' is not accessible`),this.#url=url}get url(){return this.#url}}ModuleNotAccessible.source="/jitar/client.js";class ModuleNotLoaded extends ServerError{#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}}ModuleNotLoaded.source="/jitar/client.js";class NoWorkerAvailable extends ServerError{#name;constructor(name){super(`No worker available for procedure '${name}'`),this.#name=name}get name(){return this.#name}}NoWorkerAvailable.source="/jitar/client.js";class ProcedureNotAccessible extends Forbidden{#fqn;#versionNumber;constructor(fqn,versionNumber){super(`Procedure '${fqn}' (v${versionNumber}) is not accessible`),this.#fqn=fqn,this.#versionNumber=versionNumber}get fqn(){return this.#fqn}get versionNumber(){return this.#versionNumber}}ProcedureNotAccessible.source="/jitar/client.js";class ProcedureNotFound extends NotFound{#fqn;constructor(fqn){super(`Procedure '${fqn}' not found`),this.#fqn=fqn}get fqn(){return this.#fqn}}ProcedureNotFound.source="/jitar/client.js";class RepositoryNotAvailable extends ServerError{constructor(){super("Repository not available")}}RepositoryNotAvailable.source="/jitar/client.js";class RuntimeNotAvailable extends ServerError{constructor(){super("Runtime not available")}}RuntimeNotAvailable.source="/jitar/client.js";class SegmentNotFound extends ServerError{#source;constructor(source){super(`Segment found for '${source}'`),this.#source=source}get source(){return this.#source}}SegmentNotFound.source="/jitar/client.js";class UnknownParameter extends BadRequest{#parameterName;constructor(parameterName){super(`Unknown parameter ${parameterName}`),this.#parameterName=parameterName}get parameterName(){return this.#parameterName}}UnknownParameter.source="/jitar/client.js";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 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 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 NamedParameter extends Parameter{}class ObjectParameter extends DestructuredParameter{}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 Request{#fqn;#version;#args;#headers=new Map;constructor(fqn,version,args,headers){this.#fqn=fqn,this.#version=version,this.#args=args,this.#headers=headers}get fqn(){return this.#fqn}get version(){return this.#version}get args(){return this.#args}get headers(){return this.#headers}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{#result;#headers;constructor(result=void 0,headers=new Map){this.#result=result,this.#headers=headers}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 InvalidMiddleware extends ServerError{#url;constructor(url){super(`Module '${url}' does not export valid middleware`),this.#url=url}get url(){return this.#url}}InvalidMiddleware.source="/jitar/client.js";class ProcedureRunner{#runner;constructor(runner){this.#runner=runner}async handle(request,next){return this.#runner.run(request)}}class InvalidHealthCheck extends ServerError{#url;constructor(url){super(`Module '${url}' does not export a valid health check`),this.#url=url}get url(){return this.#url}}InvalidHealthCheck.source="/jitar/client.js";class Runtime{#url;#healthCheckFiles=new Set;#healthChecks=new Map;constructor(url){this.#url=url}get url(){return this.#url}set healthCheckFiles(filenames){this.#healthCheckFiles=filenames}start(){return this.#importHealthChecks()}async stop(){this.#clearHealthChecks()}addHealthCheck(healthCheck){this.#healthChecks.set(healthCheck.name,healthCheck)}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=>{"fulfilled"===result.status?healthChecks.set(result.value.name,result.value.isHealthy):healthChecks.set(result.reason.name,!1)})))).then((()=>healthChecks))}async#importHealthChecks(){for(const filename of this.#healthCheckFiles)await this.#importHealthCheck(filename)}async#importHealthCheck(url){const healthCheck=(await this.import(url,ExecutionScopes.APPLICATION)).default;if(void 0===healthCheck?.isHealthy)throw new InvalidHealthCheck(url);this.addHealthCheck(healthCheck)}#clearHealthChecks(){this.#healthChecks.clear()}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])}}class ProcedureRuntime extends Runtime{#repository;#middlewareFiles=new Set;#middlewares=[];constructor(repository,url){super(url),this.#repository=repository,this.#middlewares.push(new ProcedureRunner(this))}get repository(){return this.#repository}set middlewareFiles(filenames){this.#middlewareFiles=filenames}async start(){await this.#repository.start(),await super.start(),await this.#importMiddlewares()}async stop(){this.#clearMiddlewares(),await this.#repository.stop(),await super.stop()}import(url,scope){return this.#repository.import(url,scope)}addMiddleware(middleware){const index=this.#middlewares.length-1;this.#middlewares.splice(index,0,middleware)}getMiddleware(type){return this.#middlewares.find((middleware=>middleware instanceof type))}handle(request){return this.#getNextHandler(request,0)()}#getNextHandler(request,index){const next=this.#middlewares[index];if(void 0===next)return async()=>new Response;const nextHandler=this.#getNextHandler(request,index+1);return async()=>next.handle(request,nextHandler)}async#importMiddlewares(){for(const url of this.#middlewareFiles)await this.#importMiddleware(url)}async#importMiddleware(url){const middleware=(await this.import(url,ExecutionScopes.APPLICATION)).default;if(void 0===middleware?.handle)throw new InvalidMiddleware(url);this.addMiddleware(middleware)}#clearMiddlewares(){this.#middlewares=[]}}class Gateway extends ProcedureRuntime{}class InvalidTrustKey extends Unauthorized{constructor(){super("Invalid trust key")}}InvalidTrustKey.source="/jitar/client.js";class ArgumentExtractor{extract(parameters,args){const argsCopy=new Map(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}#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 Worker extends ProcedureRuntime{}const VERSION_EXPRESSION=/^\d+(?:\.\d+){0,2}$/;class VersionParser{static 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]))}}}const RUNS_IN_BROWSER="undefined"!=typeof window;let _runtime;function getRuntime(){if(void 0===_runtime)throw new RuntimeNotAvailable;return _runtime}class LocalWorker extends Worker{#gateway;#trustKey;#argumentConstructor;#segmentNames=new Set;#segments=new Map;constructor(repository,gateway,url,trustKey,argumentConstructor=new ArgumentExtractor){super(repository,url),this.#gateway=gateway,this.#trustKey=trustKey,this.#argumentConstructor=argumentConstructor,_runtime=this}get trustKey(){return this.#trustKey}set segmentNames(names){this.#segmentNames=names}async start(){await super.start(),await this.#loadSegments(),void 0!==this.#gateway&&await this.#gateway.start()}async stop(){this.#unloadSegments(),void 0!==this.#gateway&&await this.#gateway.stop(),await super.stop()}getProcedureNames(){const names=new Set;for(const segment of this.#segments.values()){segment.getExposedProcedures().forEach((procedure=>names.add(procedure.fqn)))}return[...names.values()]}addSegment(segment){this.#segments.set(segment.id,segment)}hasProcedure(fqn){return this.getProcedureNames().includes(fqn)}run(request){const procedure=this.#getProcedure(request.fqn);return void 0===procedure?this.#useGateway(request):this.#runProcedure(procedure,request)}async#loadSegments(){for(const segmentName of this.#segmentNames)await this.#loadSegment(segmentName)}async#loadSegment(name){const filename=createWorkerFilename(name),segment=(await this.import(filename,ExecutionScopes.APPLICATION)).segment;this.addSegment(segment)}#unloadSegments(){this.#segments.clear()}#useGateway(request){if(void 0===this.#gateway)throw new ProcedureNotFound(request.fqn);if(void 0!==this.#trustKey){request.headers.set("X-Jitar-Trust-Key",this.#trustKey)}return this.#gateway.run(request)}async#runProcedure(procedure,request){const trustKey=request.getHeader("X-Jitar-Trust-Key");if(void 0!==trustKey&&this.#trustKey!==trustKey)throw new InvalidTrustKey;if(void 0===trustKey&&procedure.protected)throw new Unauthorized;const implementation=procedure.getImplementation(request.version);if(void 0===implementation)throw new ImplementationNotFound(procedure.fqn,request.version.toString());const values=this.#argumentConstructor.extract(implementation.parameters,request.args),result=await implementation.executable.call(request,...values);return new Response(result)}#getProcedure(fqn){for(const segment of this.#segments.values())if(segment.hasProcedure(fqn))return segment.getProcedure(fqn)}}class UrlRewriter{static addBase(url,base){if(url.startsWith(base))return url;const parts=`${base}/${url}`.split("://"),protocol=parts.length>1?`${parts[0]}://`:"",address=parts.length>1?parts[1]:parts[0];return`${protocol}${this.#translateAddress(address)}`}static removeBase(url,base){return!1===url.startsWith(base)?url:url.substring(base.length)}static#translateAddress(address){const parts=address.split("/"),translated=[];translated.push(parts[0]);for(let index=1;index<parts.length;index++){const part=parts[index].trim();switch(part){case"":case".":continue;case"..":translated.pop();continue}translated.push(part)}return translated.join("/")}}const APPLICATION_MODULE_INDICATORS=[".","/","http:","https:"];let _baseUrl="",_import=async name=>import(name);class ModuleLoader{static setBaseUrl(baseUrl){_baseUrl=baseUrl}static setImporter(importer){_import=importer}static async load(specifier){if(this.#isSystemModule(specifier))return this.#import(specifier);if(specifier.startsWith("/jitar"))return this.#import("jitar");const filename=this.assureExtension(specifier),url=UrlRewriter.addBase(filename,_baseUrl);if(!1===url.startsWith(_baseUrl))throw new ModuleNotAccessible(specifier);return this.#import(url)}static assureExtension(specifier){return specifier.endsWith(".js")?specifier:`${specifier}.js`}static#isSystemModule(specifier){return!1===APPLICATION_MODULE_INDICATORS.some((indicator=>specifier.startsWith(indicator)))}static async#import(specifier){try{return await _import(specifier)}catch(error){const safeUrl=UrlRewriter.removeBase(specifier,_baseUrl),message=error instanceof Error?error.message:String(error);throw new ModuleNotLoaded(safeUrl,message)}}}class Repository extends Runtime{async import(url,scope){return scope===ExecutionScopes.RUNTIME?ModuleLoader.load(url):this.loadModule(url)}}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(error){throw new InvalidBigIntString(object.value)}}}class ReflectionAlias{#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 ReflectionValue{#definition;constructor(definition){this.#definition=definition}get definition(){return this.#definition}toString(){return this.#definition}}class ReflectionArray extends ReflectionValue{}class ReflectionMember{#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 ReflectionClass extends ReflectionMember{#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 void 0!==declaration&&declaration.isPublic||this.hasGetter(name)}canWrite(name){const declaration=this.getDeclaration(name);return void 0!==declaration&&declaration.isPublic||this.hasSetter(name)}canCall(name){const funktion=this.getFunction(name);return void 0!==funktion&&funktion.isPublic}toString(){const infix=void 0!==this.#parentName?` extends ${this.#parentName}`:"";return`class ${this.name}${infix} { ${this.#scope.toString()} }`}}class ReflectionDeclaration extends ReflectionMember{#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 ReflectionDestructuredValue{#members;constructor(members){this.#members=members}get members(){return this.#members}toString(){return this.#members.map((member=>member.toString())).join(" , ")}}class ReflectionDestructuredArray extends ReflectionDestructuredValue{toString(){return`[ ${super.toString()} ]`}}class ReflectionDestructuredObject extends ReflectionDestructuredValue{toString(){return`{ ${super.toString()} }`}}class ReflectionExport extends ReflectionMember{#members;#from;constructor(members,from){super(""),this.#members=members,this.#from=from}get members(){return this.#members}get from(){return this.#from}toString(){const postfix=this.#from?` from '${this.#from}'`:"";return`export { ${this.#members.join(", ")} }${postfix}`}}class ReflectionExpression extends ReflectionValue{}class ReflectionField{#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 ReflectionFunction extends ReflectionMember{#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 ReflectionGenerator extends ReflectionFunction{toString(){const parameters=this.parameters.map((parameter=>parameter.toString()));return`${this.isAsync?"async ":""}${this.name}*(${parameters.join(", ")}) { ${this.body} }`}}class ReflectionGetter extends ReflectionFunction{toString(){return`get ${super.toString()}`}}class ReflectionImport extends ReflectionMember{#members;#from;constructor(members,from){super(""),this.#members=members,this.#from=from}get members(){return this.#members}get from(){return this.#from}toString(){return`import { ${this.#members.map((member=>member.toString())).join(", ")} } from '${this.#from}';`}}class ReflectionModule{#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)}isExported(member){for(const exportItem of this.exports)for(const alias of exportItem.members)if(alias.name===member.name)return!0;return!1}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 ReflectionObject extends ReflectionValue{}class ReflectionSetter extends ReflectionFunction{toString(){return`set ${super.toString()}`}}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{}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 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}`)}}const IMPORT_NAME=ReflectionImport.name,EXPORT_NAME=ReflectionExport.name,DECLARATION_NAME=ReflectionDeclaration.name,FUNCTION_NAME=ReflectionFunction.name,GETTER_NAME=ReflectionGetter.name,SETTER_NAME=ReflectionSetter.name,GENERATOR_NAME=ReflectionGenerator.name,CLASS_NAME=ReflectionClass.name;class ReflectionScope{#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")}}class Parser{#lexer;constructor(lexer=new Lexer){this.#lexer=lexer}parse(code){const tokenList=this.#lexer.tokenize(code),scope=this.#parseScope(tokenList);return new ReflectionModule(scope)}parseFirst(code){const tokenList=this.#lexer.tokenize(code);return this.#parseNext(tokenList)}parseValue(code){const model=this.parseFirst(code);if(model instanceof ReflectionValue==!1)throw new UnexpectedParseResult("a value definition");return model}parseImport(code){const model=this.parseFirst(code);if(model instanceof ReflectionImport==!1)throw new UnexpectedParseResult("an import definition");return model}parseExport(code){const model=this.parseFirst(code);if(model instanceof ReflectionExport==!1)throw new UnexpectedParseResult("an export definition");return model}parseDeclaration(code){const model=this.parseFirst(code);if(model instanceof ReflectionDeclaration==!1)throw new UnexpectedParseResult("a declaration definition");return model}parseFunction(code){const tokenList=this.#lexer.tokenize(code),model=this.#parseMember(tokenList);if(model instanceof ReflectionFunction==!1)throw new UnexpectedParseResult("a function definition");return model}parseClass(code){const tokenList=this.#lexer.tokenize(code),model=this.#parseMember(tokenList);if(model instanceof ReflectionClass==!1)throw new UnexpectedParseResult("a class definition");return model}#parseScope(tokenList){const members=[];for(;tokenList.notAtEnd();){const member=this.#parseNext(tokenList);member instanceof ReflectionMember&&members.push(member)}return new ReflectionScope(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 void 0!==next&&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 void 0!==next&&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 ReflectionImport(members,token.value);if(token.hasValue(Group.OPEN)){token=tokenList.step();const from=token.value;return tokenList.step(2),new ReflectionImport(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 ReflectionAlias(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 ReflectionImport(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(),void 0!==token&&token.hasValue(Keyword.FROM)&&(token=tokenList.step(),from=token.value),stepSize>0&&(stepSize++,tokenList.stepBack(stepSize));const alias=new ReflectionAlias(name,as);return new ReflectionExport([alias],from)}#parseMultiExport(tokenList){const members=this.#parseAliasList(tokenList);let from,token=tokenList.current;return void 0!==token&&token.hasValue(Keyword.FROM)&&(token=tokenList.step(),from=token.value),tokenList.step(),new ReflectionExport(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 ReflectionAlias(name,as)}#parseDeclaration(tokenList,isStatic,parseMultiple=!1){let value,token=tokenList.current,identifier="",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 ReflectionGenerator?new ReflectionGenerator(identifier.toString(),value.parameters,value.body,isStatic,value.isAsync,isPrivate):value instanceof ReflectionFunction?new ReflectionFunction(identifier.toString(),value.parameters,value.body,isStatic,value.isAsync,isPrivate):value instanceof ReflectionClass?new ReflectionClass(identifier.toString(),value.parentName,value.scope):new ReflectionDeclaration(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 ReflectionGenerator(name,parameters,body,isStatic,isAsync,isPrivate):isGetter?new ReflectionGetter(name,parameters,body,isStatic,isAsync,isPrivate):isSetter?new ReflectionSetter(name,parameters,body,isStatic,isAsync,isPrivate):new ReflectionFunction(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 ReflectionField(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 ReflectionFunction("",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 ReflectionClass(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 ReflectionScope(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 ReflectionArray(items)}#parseDestructuredArray(tokenList){const fields=this.#parseParameters(tokenList,List.CLOSE);return new ReflectionDestructuredArray(fields)}#parseObject(tokenList){const fields=this.#parseBlock(tokenList,Scope.OPEN,Scope.CLOSE);return new ReflectionObject(fields)}#parseDestructuredObject(tokenList){const fields=this.#parseParameters(tokenList,Scope.CLOSE);return new ReflectionDestructuredObject(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 ReflectionField(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 ReflectionExpression(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 ReflectionClass(model.name,parent.name,new ReflectionScope(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;#merger;constructor(parser=new Parser,merger=new ClassMerger){this.#parser=parser,this.#merger=merger}parse(code){return this.#parser.parse(code)}parseClass(code){return this.#parser.parseClass(code)}parseFunction(code){return this.#parser.parseFunction(code)}parseDeclaration(code){return this.#parser.parseDeclaration(code)}parseImport(code){return this.#parser.parseImport(code)}parseExport(code){return this.#parser.parseExport(code)}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 ReflectionExpression(code);members.push(new ReflectionDeclaration(key,expression))}}return new ReflectionModule(new ReflectionScope(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.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.parseClass(code)}#reflectDynamic(clazz){const object=this.createInstance(clazz),members=this.#getMembers(clazz,object),scope=new ReflectionScope(members);return new ReflectionClass(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 ReflectionValue(String(content)):void 0,model=new ReflectionDeclaration(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 ReflectionGetter(model.name,model.parameters,model.body,model.isStatic,model.isAsync,model.isPrivate)):void 0!==description.set?models.push(new ReflectionSetter(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{#classLoader;constructor(classLoader){super(),this.#classLoader=classLoader}canSerialize(value){return value instanceof Object&&reflector$1.isClassObject(value)}canDeserialize(value){const object=value;return object instanceof Object&&!0===object.serialized&&"string"==typeof object.name&&object.args instanceof Array&&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.#extractParameterNames(model);return{serialized:!0,name:clazz.name,source:clazz.source,args:await this.#extractArguments(model,parameterNames,object),fields:await this.#extractFields(model,parameterNames,object)}}#extractParameterNames(model){const constructor=model.getFunction("constructor");return(constructor?.parameters??[]).map((parameter=>parameter.name))}async#extractArguments(model,includeNames,object){const args=[];for(const name of includeNames){const objectValue=model.canRead(name)?await this.serializeOther(object[name]):void 0;args.push(objectValue)}return args}async#extractFields(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.name);if(clazz instanceof Function==!1)throw new InvalidClass(object.name);const args=await Promise.all(object.args.map((async value=>this.deserializeOther(value)))),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#getClass(clazz){return void 0===clazz.source?globalThis[clazz.name]:this.#classLoader.loadClass(clazz)}}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]);return error.stack=object.stack,error.message=object.message,error.cause=object.cause,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(error){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(error){throw new InvalidUrlString(object.value)}}}const defaultClassLoader=new class{async loadClass(loadable){if("string"!=typeof loadable.source)throw new ClassNotFound(loadable.name);const module=await import(loadable.source),clazz=module[loadable.name]??module.default;if(void 0===clazz)throw new ClassNotFound(loadable.name);if(clazz instanceof Function==!1)throw new InvalidClass(loadable.name);return clazz}};class SerializerBuilder{static build(loader=defaultClassLoader){const serializer=new Serializer;return serializer.addSerializer(new PrimitiveSerializer),serializer.addSerializer(new ObjectSerializer),serializer.addSerializer(new ClassSerializer(loader)),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),serializer}}class RemoteClassLoader{async loadClass(loadable){if("string"!=typeof loadable.source)throw new ClassNotFound(loadable.name);const module=await ModuleLoader.load(loadable.source),clazz=module[loadable.name]??module.default;if(void 0===clazz)throw new ClassNotFound(loadable.name);if(clazz instanceof Function==!1)throw new InvalidClass(loadable.name);return clazz}}const remoteClassLoader=new RemoteClassLoader,defaultSerializer=SerializerBuilder.build(remoteClassLoader);class Remote{#url;#serializer;constructor(url,serializer=defaultSerializer){this.#url=url,this.#serializer=serializer}async registerClient(segmentFiles){const url=`${this.#url}/modules`,options={method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(segmentFiles)};return(await this.#callRemote(url,options,200)).text()}async loadFile(filename){const url=`${this.#url}/${filename}`,response=await this.#callRemote(url,{method:"GET"},200),type=response.headers.get("Content-Type")||"application/octet-stream",content=await response.text();return new File(filename,type,content)}async isHealthy(){const url=`${this.#url}/health/status`,response=await this.#callRemote(url,{method:"GET"},200),healthy=await response.text();return Boolean(healthy)}async getHealth(){const url=`${this.#url}/health`,response=await this.#callRemote(url,{method:"GET"},200),health=await response.json();return new Map(Object.entries(health))}async addWorker(worker){const url=`${this.#url}/workers`,body={url:worker.url,procedureNames:worker.getProcedureNames(),trustKey:worker.trustKey},options={method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(body)};await this.#callRemote(url,options,201)}async run(request){request.setHeader("content-type","application/json");const versionString=request.version.toString(),argsObject=Object.fromEntries(request.args),headersObject=Object.fromEntries(request.headers),url=`${this.#url}/rpc/${request.fqn}?version=${versionString}&serialize=true`,options={method:"POST",headers:headersObject,body:await this.#createRequestBody(argsObject)},response=await this.#callRemote(url,options,200),result=await this.#createResponseResult(response),headers=this.#createResponseHeaders(response);return new Response(result,headers)}async#callRemote(url,options,expectedStatus){const response=await fetch(url,options);if(response.status!==expectedStatus)throw await this.#createResponseResult(response);return response}async#createRequestBody(body){const data=await this.#serializer.serialize(body);return JSON.stringify(data)}async#createResponseResult(response){const result=await this.#getResponseResult(response);return this.#serializer.deserialize(result)}async#getResponseResult(response){const contentType=response.headers.get("Content-Type");if(null!==contentType&&contentType.includes("json"))return response.json();const content=await response.text();return null!==contentType&&contentType.includes("boolean")?"true"===content:null!==contentType&&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 DummyRepository extends Repository{async start(){}async stop(){}async registerClient(segmentFiles){throw new RepositoryNotAvailable}async readAsset(filename){throw new RepositoryNotAvailable}async readModule(filename,clientId){throw new RepositoryNotAvailable}async loadModule(filename){throw new RepositoryNotAvailable}}class RemoteGateway extends Gateway{#remote;#worker;constructor(url){super(new DummyRepository,url),this.#remote=new Remote(url)}get worker(){return this.#worker}set worker(worker){this.#worker=worker}async start(){await super.start(),void 0!==this.#worker&&await this.addWorker(this.#worker)}getProcedureNames(){throw new NotImplemented}hasProcedure(name){throw new NotImplemented}addWorker(worker){return this.#remote.addWorker(worker)}run(request){return this.#remote.run(request)}}class RemoteRepository extends Repository{#remote;#segmentNames=new Set;constructor(url){super(url),this.#remote=new Remote(url)}get segmentNames(){return[...this.#segmentNames.values()]}set segmentNames(segmentNames){this.#segmentNames=segmentNames}async start(){const clientId=await this.registerClient(this.segmentNames),baseUrl=this.#getModuleBaseUrl(clientId);ModuleLoader.setBaseUrl(baseUrl),await super.start()}registerClient(segmentFiles){return this.#remote.registerClient(segmentFiles)}readAsset(filename){return this.#remote.loadFile(filename)}readModule(filename,clientId){return this.#remote.loadFile(`modules/${clientId}/${filename}`)}loadModule(filename){return ModuleLoader.load(filename)}#getModuleBaseUrl(clientId){return`${this.url}/modules/${clientId}`}}class RuntimeNotBuilt extends ServerError{constructor(reason){super(`Building the runtime failed: ${reason}`)}}RuntimeNotBuilt.source="/jitar/client.js";const globals=globalThis;globals.__import=async function(name,scope,extractDefault=!0){const runtime=getRuntime();RUNS_IN_BROWSER&&"jitar"===name&&(name="/jitar/client.js");const module=await runtime.import(name,scope);return extractDefault&&void 0!==module.default?module.default:module},globals.__run=async function(fqn,versionNumber,args,sourceRequest){const runtime=getRuntime(),version=VersionParser.parse(versionNumber),argsMap=new Map(Object.entries(args)),headersMap=sourceRequest instanceof Request?sourceRequest.headers:new Map,targetRequest=new Request(fqn,version,argsMap,headersMap);return(await runtime.handle(targetRequest)).result},globals.ProcedureNotAccessible=ProcedureNotAccessible;export{MissingParameterValue as $,AccessLevels as A,BadRequest as B,ClientNotFound as C,DummyRepository as D,ExecutionScopes as E,FileNotFound as F,Gateway as G,Version as H,InvalidTrustKey as I,Response as J,NamedParameter as K,LocalWorker as L,ModuleLoader as M,NoWorkerAvailable as N,ArrayParameter as O,ProcedureNotFound as P,ObjectParameter as Q,Repository as R,SerializerBuilder as S,Teapot as T,Unauthorized as U,VersionParser as V,Worker as W,ServerError as X,ImplementationNotFound as Y,InvalidParameterValue as Z,InvalidVersionNumber as _,InvalidSegmentFile as a,ModuleNotAccessible as a0,ModuleNotLoaded as a1,ProcedureNotAccessible as a2,RepositoryNotAvailable as a3,RuntimeNotAvailable as a4,SegmentNotFound as a5,UnknownParameter as a6,InvalidClientId as b,File as c,convertToRemoteFilename as d,convertToLocalFilename as e,createRepositoryFilename as f,ProcedureRuntime as g,Remote as h,isSegmentFilename as i,RemoteRepository as j,RemoteGateway as k,RuntimeNotBuilt as l,Reflector as m,ReflectionField as n,ReflectionDestructuredArray as o,ReflectionDestructuredObject as p,ReflectionDestructuredValue as q,createWorkerFilename as r,ReflectionFunction as s,Files as t,PaymentRequired as u,Forbidden as v,NotFound as w,NotImplemented as x,Request as y,RemoteClassLoader as z};
package/dist/lib.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  declare const AccessLevels: {
3
3
  readonly PRIVATE: "private";
4
+ readonly PROTECTED: "protected";
4
5
  readonly PUBLIC: "public";
5
6
  };
6
7
  type Keys$1 = keyof typeof AccessLevels;
@@ -107,7 +108,7 @@ declare class ModuleNotLoaded extends ServerError {
107
108
  get reason(): string | undefined;
108
109
  }
109
110
 
110
- declare class NoNodeAvailable extends ServerError {
111
+ declare class NoWorkerAvailable extends ServerError {
111
112
  #private;
112
113
  constructor(name: string);
113
114
  get name(): string;
@@ -181,12 +182,15 @@ declare class Request {
181
182
  get version(): Version;
182
183
  get args(): Map<string, unknown>;
183
184
  get headers(): Map<string, string>;
185
+ clearArguments(): void;
184
186
  setArgument(name: string, value: unknown): void;
185
187
  getArgument(name: string): unknown;
188
+ hasArgument(name: string): boolean;
186
189
  removeArgument(name: string): void;
187
190
  clearHeaders(): void;
188
191
  setHeader(name: string, value: string): void;
189
192
  getHeader(name: string): string | undefined;
193
+ hasHeader(name: string): boolean;
190
194
  removeHeader(name: string): void;
191
195
  }
192
196
 
@@ -199,6 +203,7 @@ declare class Response {
199
203
  clearHeaders(): void;
200
204
  setHeader(name: string, value: string): void;
201
205
  getHeader(name: string): string | undefined;
206
+ hasHeader(name: string): boolean;
202
207
  removeHeader(name: string): void;
203
208
  }
204
209
 
@@ -229,6 +234,7 @@ declare class Implementation {
229
234
  constructor(version: Version, access: AccessLevel, parameters: Parameter[], executable: Function);
230
235
  get version(): Version;
231
236
  get public(): boolean;
237
+ get protected(): boolean;
232
238
  get parameters(): Parameter[];
233
239
  get executable(): Function;
234
240
  }
@@ -244,6 +250,7 @@ declare class Procedure {
244
250
  constructor(fqn: string);
245
251
  get fqn(): string;
246
252
  get public(): boolean;
253
+ get protected(): boolean;
247
254
  addImplementation(implementation: Implementation): Procedure;
248
255
  getImplementation(version: Version): Implementation | undefined;
249
256
  }
@@ -255,7 +262,7 @@ declare class Segment {
255
262
  addProcedure(procedure: Procedure): Segment;
256
263
  hasProcedure(fqn: string): boolean;
257
264
  getProcedure(fqn: string): Procedure | undefined;
258
- getPublicProcedures(): Procedure[];
265
+ getExposedProcedures(): Procedure[];
259
266
  }
260
267
 
261
268
  interface Runner {
@@ -301,11 +308,12 @@ declare abstract class ProcedureRuntime extends Runtime implements Runner {
301
308
  handle(request: Request): Promise<Response>;
302
309
  }
303
310
 
304
- declare abstract class Node extends ProcedureRuntime {
311
+ declare abstract class Worker extends ProcedureRuntime {
312
+ abstract get trustKey(): string | undefined;
305
313
  }
306
314
 
307
315
  declare abstract class Gateway extends ProcedureRuntime {
308
- abstract addNode(node: Node): Promise<void>;
316
+ abstract addWorker(worker: Worker): Promise<void>;
309
317
  }
310
318
 
311
319
  declare class ArgumentExtractor {
@@ -313,9 +321,10 @@ declare class ArgumentExtractor {
313
321
  extract(parameters: Parameter[], args: Map<string, unknown>): unknown[];
314
322
  }
315
323
 
316
- declare class LocalNode extends Node {
324
+ declare class LocalWorker extends Worker {
317
325
  #private;
318
- constructor(repository: Repository, gateway?: Gateway, url?: string, argumentConstructor?: ArgumentExtractor);
326
+ constructor(repository: Repository, gateway?: Gateway, url?: string, trustKey?: string, argumentConstructor?: ArgumentExtractor);
327
+ get trustKey(): string | undefined;
319
328
  set segmentNames(names: Set<string>);
320
329
  start(): Promise<void>;
321
330
  stop(): Promise<void>;
@@ -354,8 +363,8 @@ declare class Serializer {
354
363
 
355
364
  type ModuleImporter = (name: string) => Promise<Module>;
356
365
 
357
- declare function startClient(remoteUrl: string, segmentNames?: string[], middlewares?: string[]): Promise<LocalNode>;
358
- declare function getClient(): Promise<LocalNode>;
366
+ declare function startClient(remoteUrl: string, segmentNames?: string[], middlewares?: string[]): Promise<LocalWorker>;
367
+ declare function getClient(): Promise<LocalWorker>;
359
368
 
360
369
  declare function importModule(name: string, scope: ExecutionScope, extractDefault?: boolean): Promise<unknown>;
361
370
  declare function runProcedure(fqn: string, versionNumber: string, args: object, sourceRequest?: Request): Promise<unknown>;
@@ -386,4 +395,4 @@ declare class JitarServer {
386
395
 
387
396
  declare function buildServer(moduleImporter: ModuleImporter): Promise<JitarServer>;
388
397
 
389
- export { ArrayParameter, BadRequest, ClientNotFound, CorsMiddleware, FileNotFound, Forbidden, type HealthCheck, Implementation, ImplementationNotFound, InvalidClientId, InvalidParameterValue, InvalidSegmentFile, InvalidVersionNumber, type Middleware, MissingParameterValue, ModuleNotAccessible, ModuleNotLoaded, NamedParameter, type NextHandler, NoNodeAvailable, NotFound, NotImplemented, ObjectParameter, PaymentRequired, Procedure, ProcedureNotAccessible, ProcedureNotFound, RepositoryNotAvailable, Request, Response, RuntimeNotAvailable, Segment, SegmentNotFound, ServerError, Teapot, Unauthorized, UnknownParameter, Version, buildServer, getClient, startClient };
398
+ export { ArrayParameter, BadRequest, ClientNotFound, CorsMiddleware, FileNotFound, Forbidden, type HealthCheck, Implementation, ImplementationNotFound, InvalidClientId, InvalidParameterValue, InvalidSegmentFile, InvalidVersionNumber, type Middleware, MissingParameterValue, ModuleNotAccessible, ModuleNotLoaded, NamedParameter, type NextHandler, NoWorkerAvailable, NotFound, NotImplemented, ObjectParameter, PaymentRequired, Procedure, ProcedureNotAccessible, ProcedureNotFound, RepositoryNotAvailable, Request, Response, RuntimeNotAvailable, Segment, SegmentNotFound, ServerError, Teapot, Unauthorized, UnknownParameter, Version, buildServer, getClient, startClient };
package/dist/server.js CHANGED
@@ -1 +1 @@
1
- import{N as NoNodeAvailable,G as Gateway,P as ProcedureNotFound,R as Repository,M as ModuleLoader,I as InvalidSegmentFile,F as FileNotFound,a as InvalidClientId,C as ClientNotFound,b as File,c as convertToRemoteFilename,i as isSegmentFilename,d as convertToLocalFilename,e as createRepositoryFilename,f as ProcedureRuntime,g as Node,D as DummyRepository,h as Remote,j as RemoteRepository,k as RemoteGateway,l as RuntimeNotBuilt,L as LocalNode,m as Reflector,A as AccessLevels,n as ReflectionField,o as ReflectionDestructuredArray,p as ReflectionDestructuredObject,q as ReflectionDestructuredValue,r as createNodeFilename,V as VersionParser,s as ReflectionFunction,t as Files,B as BadRequest,U as Unauthorized,u as PaymentRequired,v as Forbidden,w as NotFound,T as Teapot,x as NotImplemented,y as Request,z as RemoteClassLoader,S as SerializerBuilder,E as ExecutionScopes}from"./globals-8t6x98aZ.js";import express from"express";import{readFileSync}from"fs";import{z}from"zod";import fs from"fs-extra";import glob from"glob-promise";import mime from"mime-types";import path from"path";import yargs from"yargs";import{Logger}from"tslog";import{fileURLToPath}from"url";import expressProxy from"express-http-proxy";class CorsMiddleware{#allowOrigin;#allowMethods="GET, POST";#allowHeaders;constructor(origin="*",headers="*"){this.#allowOrigin=origin,this.#allowHeaders=headers}get allowOrigin(){return this.#allowOrigin}get allowMethods(){return this.#allowMethods}get allowHeaders(){return this.#allowHeaders}async handle(request,next){const response=await next();return this.#setHeaders(response),response}#setHeaders(response){response.setHeader("Access-Control-Allow-Origin",this.#allowOrigin),response.setHeader("Access-Control-Allow-Methods",this.#allowMethods),response.setHeader("Access-Control-Allow-Headers",this.#allowHeaders)}}class NodeBalancer{#nodes=[];#currentIndex=0;addNode(node){this.#nodes.includes(node)||this.#nodes.push(node)}removeNode(node){const index=this.#nodes.indexOf(node);-1!==index&&this.#nodes.splice(index,1)}getNextNode(){if(0!==this.#nodes.length)return this.#currentIndex>=this.#nodes.length&&(this.#currentIndex=0),this.#nodes[this.#currentIndex++]}run(request){const node=this.getNextNode();if(void 0===node)throw new NoNodeAvailable(request.fqn);return node.run(request)}}class LocalGateway extends Gateway{#nodes=new Set;#balancers=new Map;get nodes(){return[...this.#nodes.values()]}getProcedureNames(){const procedureNames=this.nodes.map((node=>node.getProcedureNames()));return[...new Set(procedureNames.flat()).values()]}hasProcedure(fqn){return this.getProcedureNames().includes(fqn)}async addNode(node){this.#nodes.add(node);for(const name of node.getProcedureNames()){this.#getOrCreateBalancer(name).addNode(node)}}removeNode(node){this.#nodes.delete(node);for(const name of node.getProcedureNames()){const balancer=this.#getBalancer(name);void 0!==balancer&&balancer.removeNode(node)}}#getBalancer(fqn){return this.#balancers.get(fqn)}#getOrCreateBalancer(fqn){let balancer=this.#getBalancer(fqn);return void 0===balancer&&(balancer=new NodeBalancer,this.#balancers.set(fqn,balancer)),balancer}run(request){const balancer=this.#getBalancer(request.fqn);if(void 0===balancer)throw new ProcedureNotFound(request.fqn);return balancer.run(request)}}const CLIENT_ID_REGEX=/^CLIENT_\d+$/;let lastClientId=0;class ClientIdHelper{generate(){return"CLIENT_"+lastClientId++}validate(clientId){return CLIENT_ID_REGEX.test(clientId)}}const clientIdHelper$1=new ClientIdHelper;class LocalRepository extends Repository{#fileManager;#segments=new Map;#clients=new Map;#segmentNames=new Set;#assets=new Set;#overrides=new Map;constructor(fileManager,url){super(url),this.#fileManager=fileManager,ModuleLoader.setBaseUrl(fileManager.getRootLocation())}set segmentNames(names){this.#segmentNames=new Set(names)}set assets(patterns){this.#assets=patterns}set overrides(overrides){this.#overrides=overrides}async start(){await super.start(),await this.#loadSegments(),this.#translateOverrides()}stop(){return this.#unregisterClients(),this.#unloadSegments(),super.stop()}async#loadSegments(){for(const name of this.#segmentNames)await this.#loadSegment(name)}async#loadSegment(name){const relativeFilename=`./${createRepositoryFilename(name)}`,absoluteFilename=this.#fileManager.getAbsoluteLocation(relativeFilename),files=(await ModuleLoader.load(absoluteFilename)).files;if(void 0===files)throw new InvalidSegmentFile(absoluteFilename);this.registerSegment(name,files)}#unloadSegments(){this.#segments.clear()}async registerSegment(name,filenames){filenames.forEach((filename=>this.#segments.set(filename,name)))}#translateOverrides(){const translated=new Map;for(const[targetName,destinationName]of this.#overrides){const relativeTargetFilename=ModuleLoader.assureExtension(targetName),relativeDestinationFilename=ModuleLoader.assureExtension(destinationName),absoluteTargetFilename=this.#fileManager.getAbsoluteLocation(relativeTargetFilename),absoluteDestinationFilename=this.#fileManager.getAbsoluteLocation(relativeDestinationFilename);translated.set(absoluteTargetFilename,absoluteDestinationFilename)}this.#overrides=translated}async registerClient(segmentFilenames){const clientId=clientIdHelper$1.generate();return this.#clients.set(clientId,segmentFilenames),clientId}#unregisterClients(){this.#clients.clear()}readAsset(filename){if(!1===this.#assets.has(filename))throw new FileNotFound(filename);return this.#readFile(filename)}readModule(name,clientId){clientId=this.#validateClientId(clientId);const segmentFilename=this.#segments.get(name);return void 0===segmentFilename||this.#hasClientSegmentFile(clientId,segmentFilename)?this.#readNodeModule(name):this.#readRemoteModule(name)}loadModule(name){const filename=this.#getModuleFilename(name);return ModuleLoader.load(filename)}#validateClientId(clientId){if(!1===clientIdHelper$1.validate(clientId))throw new InvalidClientId(clientId);if(!1===this.#clients.has(clientId))throw new ClientNotFound(clientId);return clientId}#hasClientSegmentFile(clientId,segmentFilename){const clientSegmentFiles=this.#clients.get(clientId);if(void 0===clientSegmentFiles)throw new ClientNotFound(clientId);return clientSegmentFiles.some((clientSegmentFilename=>segmentFilename.endsWith(clientSegmentFilename)))}async#readNodeModule(name){const filename=this.#getModuleFilename(name),code=(await this.#readFile(filename)).content.toString();return new File(filename,"application/javascript",code)}#readRemoteModule(name){const remoteFilename=convertToRemoteFilename(name);return this.#readFile(remoteFilename)}#getModuleFilename(name){const relativeFilename=ModuleLoader.assureExtension(name),absoluteFilename=this.#fileManager.getAbsoluteLocation(relativeFilename);if(isSegmentFilename(absoluteFilename))return absoluteFilename;const assignedFilename=this.#getAssignedFilename(absoluteFilename);return convertToLocalFilename(assignedFilename)}#getAssignedFilename(filename){return this.#overrides.get(filename)??filename}#readFile(filename){return this.#fileManager.read(filename)}}class Proxy extends ProcedureRuntime{#runner;constructor(repository,runner,url){super(repository,url),this.#runner=runner}get runner(){return this.#runner}async start(){await super.start(),await this.#runner.start()}async stop(){await this.#runner.stop(),await super.stop()}getProcedureNames(){return this.#runner.getProcedureNames()}hasProcedure(fqn){return this.getProcedureNames().includes(fqn)}readAsset(filename){return this.repository.readAsset(filename)}registerClient(segmentFiles){return this.repository.registerClient(segmentFiles)}readModule(filename,clientId){return this.repository.readModule(filename,clientId)}run(request){return this.#runner.run(request)}}class RemoteNode extends Node{#remote;#procedureNames=new Set;constructor(url){super(new DummyRepository,url),this.#remote=new Remote(url)}set procedureNames(names){this.#procedureNames=names}getProcedureNames(){return[...this.#procedureNames.values()]}hasProcedure(name){return this.#procedureNames.has(name)}isHealthy(){return this.#remote.isHealthy()}getHealth(){return this.#remote.getHealth()}run(request){return this.#remote.run(request)}}class Standalone extends ProcedureRuntime{#node;constructor(repository,node,url){super(repository,url),this.#node=node}get node(){return this.#node}async start(){await this.#node.start(),await super.start()}async stop(){await this.#node.stop(),await super.stop()}getProcedureNames(){return this.#node.getProcedureNames()}hasProcedure(fqn){return this.getProcedureNames().includes(fqn)}readAsset(filename){return this.repository.readAsset(filename)}registerClient(segmentFiles){return this.repository.registerClient(segmentFiles)}readModule(filename,clientId){return this.repository.readModule(filename,clientId)}run(request){return this.#node.run(request)}}class RuntimeBuilder{#url;#fileManager;#segments=new Set;#healthChecks=new Set;#middlewares=new Set;#assets=new Set;#overrides=new Map;#repository;#gateway;#node;url(url){return this.#url=url,this}fileManager(fileManager){return this.#fileManager=fileManager,this}segment(...names){return names.forEach((name=>this.#segments.add(name))),this}healthCheck(...filenames){return filenames.forEach((filename=>this.#healthChecks.add(filename))),this}middleware(...filenames){return filenames.forEach((filename=>this.#middlewares.add(filename))),this}asset(...patterns){return patterns.forEach((pattern=>this.#assets.add(pattern))),this}override(...mappings){for(const map of mappings)for(const[key,value]of Object.entries(map))this.#overrides.set(key,value);return this}repository(url){return this.#repository=void 0!==url?new RemoteRepository(url):void 0,this}gateway(url){return this.#gateway=void 0!==url?new RemoteGateway(url):void 0,this}node(url){return this.#node=void 0!==url?new RemoteNode(url):void 0,this}buildRepository(){if(void 0===this.#fileManager)throw new RuntimeNotBuilt("File manager is not set for the repository");const repository=new LocalRepository(this.#fileManager,this.#url);return repository.healthCheckFiles=this.#healthChecks,repository.segmentNames=this.#segments,repository.assets=this.#assets,repository.overrides=this.#overrides,repository}buildGateway(){if(void 0===this.#repository)throw new RuntimeNotBuilt("Repository is not set for the gateway");const gateway=new LocalGateway(this.#repository,this.#url);return gateway.healthCheckFiles=this.#healthChecks,gateway.middlewareFiles=this.#middlewares,gateway}buildNode(){if(void 0===this.#repository)throw new RuntimeNotBuilt("Repository is not set for the node");const node=new LocalNode(this.#repository,this.#gateway,this.#url);return node.segmentNames=this.#segments,node.healthCheckFiles=this.#healthChecks,node.middlewareFiles=this.#middlewares,this.#repository.segmentNames=this.#segments,void 0!==this.gateway&&(this.#gateway.node=node),node}buildProxy(){if(void 0===this.#repository)throw new RuntimeNotBuilt("Repository is not set for the proxy");const runner=this.#gateway??this.#node;if(void 0===runner)throw new RuntimeNotBuilt("Runner (gateway or node) is not set for the proxy");const proxy=new Proxy(this.#repository,runner,this.#url);return proxy.healthCheckFiles=this.#healthChecks,proxy.middlewareFiles=this.#middlewares,proxy}buildStandalone(){if(void 0===this.#fileManager)throw new RuntimeNotBuilt("File manager is not set for the standalone");const repository=new LocalRepository(this.#fileManager,this.#url);repository.segmentNames=this.#segments,repository.assets=this.#assets,repository.overrides=this.#overrides;const node=new LocalNode(repository,this.#gateway,this.#url);node.segmentNames=this.#segments;const standalone=new Standalone(repository,node,this.#url);return standalone.healthCheckFiles=this.#healthChecks,standalone.middlewareFiles=this.#middlewares,standalone}}class ProcedureRuntimeConfiguration{#middlewares;constructor(middlewares){this.#middlewares=middlewares}get middlewares(){return this.#middlewares}}const gatewaySchema=z.object({repository:z.string().url(),middlewares:z.array(z.string()).optional(),monitor:z.number().optional()}).strict().transform((value=>new GatewayConfiguration(value.repository,value.middlewares,value.monitor)));class GatewayConfiguration extends ProcedureRuntimeConfiguration{#monitor;#repository;constructor(repository,middlewares,monitor){super(middlewares),this.#monitor=monitor,this.#repository=repository}get monitor(){return this.#monitor}get repository(){return this.#repository}}const nodeSchema=z.object({gateway:z.string().url().optional(),repository:z.string().url().optional(),segments:z.array(z.string()).nonempty(),middlewares:z.array(z.string()).optional()}).strict().transform((value=>new NodeConfiguration(value.gateway,value.repository,value.segments,value.middlewares)));class NodeConfiguration extends ProcedureRuntimeConfiguration{#gateway;#repository;#segments;constructor(gateway,repository,segments,middlewares){super(middlewares),this.#gateway=gateway,this.#repository=repository,this.#segments=segments}get gateway(){return this.#gateway}get repository(){return this.#repository}get segments(){return this.#segments}}const proxySchema=z.object({node:z.string().url().optional(),gateway:z.string().url().optional(),repository:z.string().url(),middlewares:z.array(z.string()).optional()}).strict().superRefine(((value,ctx)=>{void 0===value.node&&void 0===value.gateway&&ctx.addIssue({code:z.ZodIssueCode.custom,message:"Either node or gateway must be defined",path:["node","gateway"]}),void 0!==value.node&&void 0!==value.gateway&&ctx.addIssue({code:z.ZodIssueCode.custom,message:"Only node or gateway must be defined",path:["node","gateway"]})})).transform((value=>new ProxyConfiguration(value.node,value.gateway,value.repository,value.middlewares)));class ProxyConfiguration extends ProcedureRuntimeConfiguration{#node;#gateway;#repository;constructor(node,gateway,repository,middlewares){super(middlewares),this.#node=node,this.#gateway=gateway,this.#repository=repository}get node(){return this.#node}get gateway(){return this.#gateway}get repository(){return this.#repository}}const repositorySchema=z.object({source:z.string().optional(),cache:z.string().optional(),index:z.string().optional(),assets:z.array(z.string()).optional(),overrides:z.record(z.string(),z.string()).optional()}).strict().transform((value=>new RepositoryConfiguration(value.source,value.cache,value.index,value.assets,value.overrides)));class RepositoryConfiguration{#source;#cache;#index;#assets;#overrides;constructor(source,cache,index,assets,overrides){this.#source=source,this.#cache=cache,this.#index=index,this.#assets=assets,this.#overrides=overrides}get source(){return this.#source}get cache(){return this.#cache}get index(){return this.#index}get assets(){return this.#assets}get overrides(){return this.#overrides}}const standaloneSchema=z.object({source:z.string().optional(),cache:z.string().optional(),index:z.string().optional(),segments:z.array(z.string()).optional(),assets:z.array(z.string()).optional(),middlewares:z.array(z.string()).optional(),overrides:z.record(z.string(),z.string()).optional()}).strict().transform((value=>new StandaloneConfiguration(value.source,value.cache,value.index,value.segments,value.assets,value.middlewares,value.overrides)));class StandaloneConfiguration extends ProcedureRuntimeConfiguration{#source;#cache;#index;#segments;#assets;#overrides;constructor(source,cache,index,segments,assets,middlewares,overrides){super(middlewares),this.#source=source,this.#cache=cache,this.#index=index,this.#segments=segments,this.#assets=assets,this.#overrides=overrides}get source(){return this.#source}get cache(){return this.#cache}get index(){return this.#index}get segments(){return this.#segments}get assets(){return this.#assets}get overrides(){return this.#overrides}}const runtimeSchema=z.object({url:z.string().optional(),setUp:z.array(z.string()).optional(),tearDown:z.array(z.string()).optional(),healthChecks:z.array(z.string()).optional(),standalone:standaloneSchema.optional(),repository:repositorySchema.optional(),gateway:gatewaySchema.optional(),node:nodeSchema.optional(),proxy:proxySchema.optional()}).strict().transform((value=>new RuntimeConfiguration(value.url,value.setUp,value.tearDown,value.healthChecks,value.standalone,value.repository,value.gateway,value.node,value.proxy)));class RuntimeConfiguration{#url;#setUp;#tearDown;#healthChecks;#standalone;#repository;#gateway;#node;#proxy;constructor(url,setUp,tearDown,healthChecks,standalone,repository,gateway,node,proxy){this.#url=url,this.#setUp=setUp,this.#tearDown=tearDown,this.#healthChecks=healthChecks,this.#standalone=standalone,this.#repository=repository,this.#gateway=gateway,this.#node=node,this.#proxy=proxy}get url(){return this.#url}get setUp(){return this.#setUp}get tearDown(){return this.#tearDown}get healthChecks(){return this.#healthChecks}get standalone(){return this.#standalone}get repository(){return this.#repository}get gateway(){return this.#gateway}get node(){return this.#node}get proxy(){return this.#proxy}}class DataConverter{static convert(schema,dataObject){return schema.parse(dataObject)}}class RuntimeConfigurationLoader{static load(filename){const plainContents=readFileSync(filename,"utf-8"),parsedContents=JSON.parse(plainContents);return DataConverter.convert(runtimeSchema,parsedContents)}}class ApplicationCache{#segments;#modules;constructor(segments,modules){this.#segments=segments,this.#modules=modules}get segments(){return this.#segments}get modules(){return this.#modules}}class ModuleCache{#module;#segment;constructor(module,segment){this.#module=module,this.#segment=segment}get module(){return this.#module}get segment(){return this.#segment}}class ModuleCacheBuilder{build(application,module){const segment=application.getSegmentModule(module.filename);return new ModuleCache(module,segment)}}class DuplicateImplementation extends Error{constructor(fqn,version){super(`Duplicate implementation found for '${fqn}' with version '${version}'.`)}}class SegmentCache{#name;#imports;#procedures;#files;constructor(name,files,imports,procedures){this.#name=name,this.#files=files,this.#imports=imports,this.#procedures=procedures}get name(){return this.#name}get files(){return this.#files}get imports(){return this.#imports}get procedures(){return this.#procedures}}class SegmentImport{#members;#from;constructor(members,from){this.#members=members,this.#from=from}get members(){return this.#members}get from(){return this.#from}}class SegmentProcedure{#fqn;#implementations=[];constructor(fqn,implementations=[]){this.#fqn=fqn,this.#implementations=implementations}get fqn(){return this.#fqn}get implementations(){return this.#implementations}addImplementation(implementation){this.#implementations.push(implementation)}}class SegmentCacheBuilder{build(segment){const files=this.#extractFiles(segment),imports=this.#createImports(segment),procedures=this.#mergeProcedures(segment);return this.#validateProcedures(procedures),new SegmentCache(segment.name,files,imports,procedures)}#extractFiles(segment){return segment.modules.map((module=>module.filename))}#createImports(segment){const imports=[];for(const module of segment.modules){let members=[];for(const procedure of module.procedures){const ids=procedure.implementations.map((implementation=>this.#createImportMember(implementation)));members=[...members,...ids]}imports.push(new SegmentImport(members,module.filename))}return imports}#createImportMember(implementation){return`${implementation.importKey} : ${implementation.id}`}#mergeProcedures(segment){const procedures=new Map;for(const module of segment.modules)for(const procedure of module.procedures){if(procedures.has(procedure.fqn)){const existingProcedure=procedures.get(procedure.fqn);for(const implementation of procedure.implementations)existingProcedure.addImplementation(implementation);continue}const procedureCopy=new SegmentProcedure(procedure.fqn,[...procedure.implementations]);procedures.set(procedure.fqn,procedureCopy)}return[...procedures.values()]}#validateProcedures(procedures){for(const procedure of procedures)this.#checkForDuplicateImplementations(procedure)}#checkForDuplicateImplementations(procedure){for(const implementation of procedure.implementations){if(void 0!==procedure.implementations.find((other=>other.id!==implementation.id&&other.version===implementation.version)))throw new DuplicateImplementation(procedure.fqn,implementation.version)}}}class ApplicationCacheBuilder{#moduleCacheBuilder;#segmentCacheBuilder;constructor(){this.#moduleCacheBuilder=new ModuleCacheBuilder,this.#segmentCacheBuilder=new SegmentCacheBuilder}build(application){const segments=this.#buildSegmentCaches(application),modules=this.#buildModuleCaches(application);return new ApplicationCache(segments,modules)}#buildSegmentCaches(application){return application.segments.map((segment=>this.#segmentCacheBuilder.build(segment)))}#buildModuleCaches(application){return application.modules.map((module=>this.#moduleCacheBuilder.build(application,module)))}}const Keyword={DEFAULT:"default"};Object.freeze(Keyword);const IMPORT_PATTERN=/import\s(?:["'\s]*([\w*{}\n, ]+)from\s*)?["'\s]*([@\w/._-]+)["'\s].*/g,APPLICATION_MODULE_INDICATORS=[".","/","http:","https:"],reflector$2=new Reflector;const importRewriter=new class{rewrite(code,filename){return code.replaceAll(IMPORT_PATTERN,(statement=>this.#replaceImport(statement,filename)))}#replaceImport(statement,filename){const dependency=reflector$2.parseImport(statement);return this.#isApplicationModule(dependency)?this.#rewriteApplicationImport(dependency,filename):this.#rewriteRuntimeImport(dependency,filename)}#isApplicationModule(dependency){return APPLICATION_MODULE_INDICATORS.some((indicator=>dependency.from.startsWith(indicator,1)))}#rewriteApplicationImport(dependency,filename){return this.#rewriteImport(dependency,"application",filename)}#rewriteRuntimeImport(dependency,filename){return this.#rewriteImport(dependency,"runtime",filename)}#rewriteImport(dependency,scope,filename){const from=this.#rewriteImportFrom(dependency,filename);if(0===dependency.members.length)return`await __import("${from}", "${scope}");`;return`const ${this.#rewriteImportMembers(dependency)} = await __import("${from}", "${scope}");`}#rewriteImportFrom(dependency,filename){const from=dependency.from.substring(1,dependency.from.length-1);return this.#isApplicationModule(dependency)?this.#mergeFilenames(filename,from):from}#rewriteImportMembers(dependency){if(this.#mustUseAs(dependency))return dependency.members[0].as;return`{ ${dependency.members.map((member=>member.name!==member.as?`${member.name} : ${member.as}`:member.name)).join(", ")} }`}#mergeFilenames(sourceFilename,importFilename){const concatenated=`${this.#extractFilepath(sourceFilename)}/${importFilename}`,translated=this.#translateFilename(concatenated),rooted=this.#ensureRoot(translated);return this.#ensureExtension(rooted)}#extractFilepath(filename){return filename.split("/").slice(0,-1).join("/")}#translateFilename(filename){const parts=filename.split("/"),translated=[];translated.push(parts[0]);for(let index=1;index<parts.length;index++){const part=parts[index].trim();switch(part){case"":case".":continue;case"..":translated.pop();continue}translated.push(part)}return translated.join("/")}#ensureRoot(filename){return filename.startsWith("./")?filename:(filename.startsWith("//")&&(filename=filename.substring(1)),filename.startsWith("/")?`.${filename}`:`./${filename}`)}#ensureExtension(filename){return filename.endsWith(".js")?filename:`${filename}.js`}#mustUseAs(dependency){return this.#doesImportAll(dependency)||this.#doesImportDefault(dependency)}#doesImportAll(dependency){return 1===dependency.members.length&&"*"===dependency.members[0].name}#doesImportDefault(dependency){return 1===dependency.members.length&&dependency.members[0].name===Keyword.DEFAULT}},remoteBuilder=new class{build(module){let code="";for(const procedure of module.procedures)for(const implementation of procedure.implementations){const asDefault=implementation.importKey===Keyword.DEFAULT;code+=implementation.access===AccessLevels.PRIVATE?this.#createPrivateCode(procedure.fqn,implementation,asDefault):this.#createPublicCode(procedure.fqn,implementation,asDefault)}return code.trim()}#createPrivateCode(fqn,implementation,asDefault){const version=implementation.version,declaration=this.#createDeclaration(implementation,asDefault),body=`throw new ProcedureNotAccessible('${fqn}', '${version}');`;return this.#createFunction(declaration,body)}#createPublicCode(fqn,implementation,asDefault){const version=implementation.version,args=this.#createArguments(implementation.executable.parameters),declaration=this.#createDeclaration(implementation,asDefault),body=`return __run('${fqn}', '${version}', { ${args} }, this);`;return this.#createFunction(declaration,body)}#createParameters(parameters){const result=[];for(const parameter of parameters)parameter instanceof ReflectionField?result.push(parameter.name):(parameter instanceof ReflectionDestructuredArray||parameter instanceof ReflectionDestructuredObject)&&result.push(parameter.toString());return result.join(", ")}#createArguments(parameters){return this.#extractArguments(parameters).join(", ")}#extractArguments(parameters){const result=[];for(const parameter of parameters)if(parameter instanceof ReflectionDestructuredValue){const argumentz=this.#extractArguments(parameter.members);result.push(...argumentz)}else if(parameter instanceof ReflectionField){const argument=this.#createNamedArgument(parameter);result.push(argument)}return result}#createNamedArgument(parameter){const key=parameter.name,value=key.startsWith("...")?key.substring(3):key;return`'${key}': ${value}`}#createDeclaration(implementation,asDefault){const name=implementation.executable.name,parameters=this.#createParameters(implementation.executable.parameters);return`\nexport ${asDefault?`${Keyword.DEFAULT} `:""}async function ${name}(${parameters})`}#createFunction(declaration,body){return`${declaration} {\n\t${body}\n}\n`}};class ModuleCacheWriter{#fileManager;constructor(fileManager){this.#fileManager=fileManager}async write(cache){return Promise.all([this.#writeLocal(cache),this.#writeRemote(cache)]).then((()=>{}))}async#writeLocal(cache){const importCode=this.#rewriteAllImports(cache.module),sourceCode=this.#createSourceCode(cache.module),filename=convertToLocalFilename(cache.module.filename),code=`${importCode}\n${sourceCode}`;return this.#fileManager.write(filename,code.trim())}#rewriteAllImports(module){return importRewriter.rewrite(module.code,module.filename)}#createSourceCode(module){const filename=module.filename;return module.content.exportedClasses.map((clazz=>clazz.name)).map((className=>`${className}.source = "./${filename}";`)).join("\n")}async#writeRemote(cache){if(void 0===cache.segment)return;const filename=convertToRemoteFilename(cache.module.filename),code=this.#createRemoteCode(cache.segment);return this.#fileManager.write(filename,code.trim())}#createRemoteCode(module){return remoteBuilder.build(module)}}class SegmentCacheWriter{#fileManager;constructor(fileManager){this.#fileManager=fileManager}async write(cache){return Promise.all([this.#writeNodeCache(cache),this.#writeRepositoryCache(cache)]).then((()=>{}))}async#writeNodeCache(cache){const importCode=this.#createImportCode(cache.imports),segmentCode=this.#createSegmentCode(cache.name,cache.procedures),filename=createNodeFilename(cache.name),code=`${importCode}\n${segmentCode}`;return this.#fileManager.write(filename,code)}async#writeRepositoryCache(cache){const filename=createRepositoryFilename(cache.name),code=`export const files = [\n\t"${[...cache.files].join('",\n\t"')}"\n];`;return this.#fileManager.write(filename,code)}#createImportCode(imports){const codes=[];for(const{members:members,from:from}of imports)codes.push(`const { ${members.join(", ")} } = await __import("./${from}", "application", false);`);return codes.join("\n")}#createSegmentCode(name,procedures){const codes=[];codes.push('const { Segment, Procedure, Implementation, Version, NamedParameter, ArrayParameter, ObjectParameter } = await __import("jitar", "runtime", false);'),codes.push(`export const segment = new Segment("${name}")`);for(const procedure of procedures){codes.push(`\t.addProcedure(new Procedure("${procedure.fqn}")`);for(const implementation of procedure.implementations){const version=this.#createVersionCode(implementation.version),parameters=this.#createParametersCode(implementation.executable);codes.push(`\t\t.addImplementation(new Implementation(${version}, "${implementation.access}", ${parameters}, ${implementation.id}))`)}codes.push("\t)")}return codes.join("\n")}#createVersionCode(versionString){const version=VersionParser.parse(versionString);return`new Version(${version.major}, ${version.minor}, ${version.patch})`}#createParametersCode(executable){return`[${this.#extractParameters(executable.parameters).join(", ")}]`}#extractParameters(parameters){const result=[];for(const parameter of parameters)result.push(this.#extractParameter(parameter));return result}#extractParameter(parameter){return parameter instanceof ReflectionDestructuredArray?this.#createArrayParameter(parameter):parameter instanceof ReflectionDestructuredObject?this.#createObjectParameter(parameter):this.#createNamedParameter(parameter)}#createNamedParameter(parameter){return`new NamedParameter("${parameter.name}", ${void 0!==parameter.value})`}#createArrayParameter(parameter){return`new ArrayParameter([${this.#extractParameters(parameter.members).join(", ")}])`}#createObjectParameter(parameter){return`new ObjectParameter([${this.#extractParameters(parameter.members).join(", ")}])`}}class ApplicationCacheWriter{#moduleWriter;#segmentWriter;constructor(fileManager){this.#moduleWriter=new ModuleCacheWriter(fileManager),this.#segmentWriter=new SegmentCacheWriter(fileManager)}async write(cache){return Promise.all([this.#writeSegmentCache(cache.segments),this.#writeModuleCache(cache.modules)]).then((()=>{}))}async#writeSegmentCache(segments){return Promise.all(segments.map((async segment=>this.#segmentWriter.write(segment)))).then((()=>{}))}async#writeModuleCache(modules){return Promise.all(modules.map((async module=>this.#moduleWriter.write(module)))).then((()=>{}))}}class Application{#segments;#modules;constructor(segments,modules){this.#segments=segments,this.#modules=modules}get segments(){return this.#segments}get modules(){return this.#modules}getSegmentModule(filename){const segment=this.#segments.find((segment=>segment.hasModule(filename)));if(void 0!==segment)return segment.getModule(filename)}}class ModuleFileNotLoaded extends Error{constructor(filename,message){super(`Failed to load module file '${filename}' because of: ${message}`)}}class Module{#filename;#code;#content;constructor(filename,code,content){this.#code=code,this.#filename=filename,this.#content=content}get filename(){return this.#filename}get code(){return this.#code}get content(){return this.#content}}const reflector$1=new Reflector;class ModuleReader{#fileManager;constructor(fileManager){this.#fileManager=fileManager}async read(filename){const relativeLocation=this.#fileManager.getRelativeLocation(filename),code=await this.#loadCode(filename),module=reflector$1.parse(code);return new Module(relativeLocation,code,module)}async#loadCode(filename){try{return(await this.#fileManager.getContent(filename)).toString()}catch(error){const message=error instanceof Error?error.message:String(error);throw new ModuleFileNotLoaded(filename,message)}}}class FunctionNotAsync extends Error{constructor(filename,functionName){super(`Function '${functionName}' from file '${filename}' is not async`)}}class InvalidSegmentFilename extends Error{constructor(filename){super(`Segment filename '${filename}' is invalid`)}}class MissingModuleExport extends Error{constructor(filename,key){super(`Module '${filename}' does not export '${key}'`)}}class SegmentFileNotLoaded extends Error{constructor(filename,message){super(`Failed to load segment file '${filename}' because of: ${message}`)}}class SegmentModuleNotLoaded extends Error{constructor(filename,message){super(`Segment module could not be loaded from '${filename}' because of: ${message}`)}}class Segment{#name;#modules;constructor(name,modules){this.#name=name,this.#modules=modules}get name(){return this.#name}get modules(){return this.#modules}hasModule(filename){return this.#modules.some((module=>module.filename===filename))}getModule(filename){return this.#modules.find((module=>module.filename===filename))}}class SegmentImplementation{#id;#importKey;#access;#version;#executable;constructor(id,importKey,access,version,executable){this.#id=id,this.#importKey=importKey,this.#access=access,this.#version=version,this.#executable=executable}get id(){return this.#id}get importKey(){return this.#importKey}get access(){return this.#access}get version(){return this.#version}get executable(){return this.#executable}}class SegmentModule{#filename;#procedures=[];constructor(filename,procedures){this.#filename=filename,this.#procedures=procedures}get filename(){return this.#filename}get procedures(){return this.#procedures}}class IdGenerator{#id=0;next(){return"$"+ ++this.#id}}const reflector=new Reflector;class SegmentReader{#fileManager;constructor(fileManager){this.#fileManager=fileManager}async read(filename){const name=this.#extractSegmentName(filename),definition=await this.#loadSegmentDefinition(filename),modules=await this.#createSegmentModules(definition);return new Segment(name,modules)}#extractSegmentName(filename){const file=filename.split("/").pop();if(void 0===file||""===file)throw new InvalidSegmentFilename(filename);return file.replace(".segment.json","")}async#loadSegmentDefinition(filename){try{const content=await this.#fileManager.getContent(filename);return JSON.parse(content.toString())}catch(error){const message=error instanceof Error?error.message:String(error);throw new SegmentFileNotLoaded(filename,message)}}async#createSegmentModules(definition){const modules=[],idGenerator=new IdGenerator;for(const[filename,moduleImports]of Object.entries(definition)){const fullFilename=filename.endsWith(".js")?filename:`${filename}.js`,absoluteFilename=this.#fileManager.getAbsoluteLocation(fullFilename),module=await this.#createSegmentModule(absoluteFilename,moduleImports,idGenerator);modules.push(module)}return modules}async#createSegmentModule(absoluteFilename,imports,idGenerator){const module=await this.#loadSegmentModule(absoluteFilename),relativeFilename=this.#fileManager.getRelativeLocation(absoluteFilename),moduleName=this.#extractModuleName(relativeFilename),procedures=this.#extractSegmentProcedures(module,moduleName,imports,idGenerator);return new SegmentModule(relativeFilename,procedures)}async#loadSegmentModule(absoluteLocation){try{const code=await this.#fileManager.getContent(absoluteLocation);return reflector.parse(code.toString())}catch(error){const message=error instanceof Error?error.message:String(error);throw new SegmentModuleNotLoaded(absoluteLocation,message)}}#extractModuleName(relativeFilename){const moduleParts=relativeFilename.split("/");return moduleParts.pop(),moduleParts.join("/")}#extractSegmentProcedures(module,moduleName,imports,idGenerator){const procedures=new Map;for(const[importKey,properties]of Object.entries(imports)){const executable=module.getExported(importKey);if(void 0===executable)throw new MissingModuleExport(moduleName,importKey);if(executable instanceof ReflectionFunction==!1)continue;if(!1===executable.isAsync)throw new FunctionNotAsync(moduleName,executable.name);const procedureName=properties.as??executable.name,access=properties.access??"private",version=properties.version??"0.0.0",id=idGenerator.next(),fqn=""!==moduleName?`${moduleName}/${procedureName}`:procedureName,implementation=new SegmentImplementation(id,importKey,access,version,executable),procedure=procedures.has(fqn)?procedures.get(fqn):new SegmentProcedure(fqn);procedure.addImplementation(implementation),procedures.set(fqn,procedure)}return[...procedures.values()]}}class ApplicationReader{#moduleReader;#segmentReader;constructor(fileManager){this.#moduleReader=new ModuleReader(fileManager),this.#segmentReader=new SegmentReader(fileManager)}async read(segmentFiles,moduleFiles){return Promise.all([this.#readSegments(segmentFiles),this.#readModules(moduleFiles)]).then((([segments,modules])=>new Application(segments,modules)))}async#readSegments(segmentFiles){return Promise.all(segmentFiles.map((async segmentFile=>this.#segmentReader.read(segmentFile))))}async#readModules(moduleFiles){return Promise.all(moduleFiles.map((async moduleFile=>this.#moduleReader.read(moduleFile))))}}class CacheManager{#projectFileManager;#appFileManager;#reader;#builder;#writer;constructor(projectFileManager,appFileManager){this.#projectFileManager=projectFileManager,this.#appFileManager=appFileManager,this.#reader=new ApplicationReader(appFileManager),this.#builder=new ApplicationCacheBuilder,this.#writer=new ApplicationCacheWriter(appFileManager)}async build(){const segmentFiles=await this.#projectFileManager.filter(Files.SEGMENT_PATTERN),moduleFiles=await this.#appFileManager.filter(Files.MODULE_PATTERN),application=await this.#reader.read(segmentFiles,moduleFiles),cache=this.#builder.build(application);return this.#writer.write(cache)}}const RuntimeDefaults={URL:"http://localhost:3000",SOURCE:"./dist",CACHE:"./.jitar",INDEX:"index.html"};Object.freeze(RuntimeDefaults);class UnknownRuntimeMode extends Error{constructor(){super("Unknown runtime mode")}}class LocalFileManager{#location;constructor(location){this.#location=location}getRootLocation(){return path.resolve(this.#location)}getAbsoluteLocation(filename){const location=filename.startsWith("/")?filename:path.join(this.#location,filename);return path.resolve(location)}getRelativeLocation(filename){return path.relative(this.#location,filename)}async getType(filename){const location=this.getAbsoluteLocation(filename);return mime.lookup(location)||"application/octet-stream"}async getContent(filename){const location=this.getAbsoluteLocation(filename);if(!1===fs.existsSync(location))throw new FileNotFound(filename);return fs.readFile(location)}async read(filename){const rootPath=this.getRootLocation(),absoluteFilename=this.getAbsoluteLocation(filename);if(!1===absoluteFilename.startsWith(rootPath))throw new FileNotFound(filename);const 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),directory=path.dirname(location);return await fs.mkdir(directory,{recursive:!0}),fs.writeFile(location,content)}async copy(source,destination){const sourceLocation=this.getAbsoluteLocation(source),destinationLocation=this.getAbsoluteLocation(destination);return fs.copy(sourceLocation,destinationLocation,{overwrite:!0})}async delete(filename){const location=this.getAbsoluteLocation(filename);return fs.remove(location)}async filter(pattern){const location=this.getAbsoluteLocation("./");return glob(`${location}/${pattern}`)}async getNodeSegmentFiles(){return this.filter("**/*.segment.node.js")}async getRepositorySegmentFiles(){return this.filter("**/*.segment.repository.js")}async getAssetFiles(patterns){const promises=patterns.map((pattern=>this.filter(pattern)));return(await Promise.all(promises)).flat().map((filename=>this.getRelativeLocation(filename))).filter((filename=>!1===this.#isGeneratedFile(filename)))}#isGeneratedFile(filename){return filename.endsWith(".local.js")||filename.endsWith(".node.js")||filename.endsWith(".repository.js")||filename.endsWith(".remote.js")}}class RuntimeConfigurator{static async configure(configuration){const url=configuration.url??RuntimeDefaults.URL,healthChecks=configuration.healthChecks??[];if(void 0!==configuration.standalone)return this.#configureStandAlone(url,healthChecks,configuration.standalone);if(void 0!==configuration.repository)return this.#configureRepository(url,healthChecks,configuration.repository);if(void 0!==configuration.gateway)return this.#configureGateway(url,healthChecks,configuration.gateway);if(void 0!==configuration.node)return this.#configureNode(url,healthChecks,configuration.node);if(void 0!==configuration.proxy)return this.#configureProxy(url,healthChecks,configuration.proxy);throw new UnknownRuntimeMode}static async#configureStandAlone(url,healthChecks,configuration){const sourceLocation=configuration.source??RuntimeDefaults.SOURCE,cacheLocation=configuration.cache??RuntimeDefaults.CACHE,overrides=configuration.overrides??{},middlewares=configuration.middlewares??[],fileManager=new LocalFileManager(cacheLocation);await this.#buildCache(sourceLocation,cacheLocation);const segmentNames=void 0===configuration.segments?await this.#getNodeSegmentNames(fileManager):configuration.segments,assets=void 0!==configuration.assets?await fileManager.getAssetFiles(configuration.assets):[];return(new RuntimeBuilder).url(url).healthCheck(...healthChecks).middleware(...middlewares).segment(...segmentNames).asset(...assets).override(overrides).fileManager(fileManager).buildStandalone()}static async#configureRepository(url,healthChecks,configuration){const sourceLocation=configuration.source??RuntimeDefaults.SOURCE,cacheLocation=configuration.cache??RuntimeDefaults.CACHE,overrides=configuration.overrides??{},fileManager=new LocalFileManager(cacheLocation);await this.#buildCache(sourceLocation,cacheLocation);const segmentNames=await this.#getRepositorySegmentNames(fileManager),assets=void 0!==configuration.assets?await fileManager.getAssetFiles(configuration.assets):[];return(new RuntimeBuilder).url(url).healthCheck(...healthChecks).segment(...segmentNames).asset(...assets).override(overrides).fileManager(fileManager).buildRepository()}static async#configureGateway(url,healthChecks,configuration){const repositoryUrl=configuration.repository,middlewares=configuration.middlewares??[];configuration.monitor;return(new RuntimeBuilder).url(url).healthCheck(...healthChecks).middleware(...middlewares).repository(repositoryUrl).buildGateway()}static async#configureNode(url,healthChecks,configuration){const repositoryUrl=configuration.repository,gatewayUrl=configuration.gateway,segmentNames=configuration.segments??[],middlewares=configuration.middlewares??[];return(new RuntimeBuilder).url(url).healthCheck(...healthChecks).middleware(...middlewares).repository(repositoryUrl).gateway(gatewayUrl).segment(...segmentNames).buildNode()}static async#configureProxy(url,healthChecks,configuration){const repositoryUrl=configuration.repository,gatewayUrl=configuration.gateway,nodeUrl=configuration.node,middlewares=configuration.middlewares??[];return(new RuntimeBuilder).url(url).healthCheck(...healthChecks).middleware(...middlewares).repository(repositoryUrl).gateway(gatewayUrl).node(nodeUrl).buildProxy()}static async#buildCache(sourceLocation,cacheLocation){const projectFileManager=new LocalFileManager("./");await projectFileManager.delete(cacheLocation),await projectFileManager.copy(sourceLocation,cacheLocation);const appFileManager=new LocalFileManager(cacheLocation),cacheManager=new CacheManager(projectFileManager,appFileManager);await cacheManager.build()}static async#getNodeSegmentNames(fileManager){return(await fileManager.getNodeSegmentFiles()).map((filename=>this.#extractSegmentName(filename)))}static async#getRepositorySegmentNames(fileManager){return(await fileManager.getRepositorySegmentFiles()).map((filename=>this.#extractSegmentName(filename)))}static#extractSegmentName(filename){const name=filename.split("/").pop()??"",endIndex=name.indexOf(".segment");return name.substring(0,endIndex)}}var LogLevel;!function(LogLevel){LogLevel.DEBUG="debug",LogLevel.INFO="info",LogLevel.WARN="warn",LogLevel.ERROR="error",LogLevel.FATAL="fatal"}(LogLevel||(LogLevel={}));class LogBuilder{static build(level){const logConfiguration=this.#getLogConfiguration(level);return new Logger(logConfiguration)}static#getLogConfiguration(level){return{prettyLogTemplate:"{{dateIsoStr}}\t{{logLevelName}}\t",minLevel:this.#getLogLevel(level)}}static#getLogLevel(level){switch(level){case LogLevel.FATAL:return 6;case LogLevel.ERROR:return 5;case LogLevel.WARN:return 4;case LogLevel.INFO:return 3;default:return 2}}}const serverOptionsSchema=z.object({loglevel:z.nativeEnum(LogLevel).optional(),config:z.string().endsWith(".json")}).transform((value=>new ServerOptions(value.config,value.loglevel)));class ServerOptions{#config;#loglevel;constructor(config,loglevel="info"){this.#config=config,this.#loglevel=loglevel}get config(){return this.#config}get loglevel(){return this.#loglevel}}class ServerOptionsReader{static read(){const args=yargs(process.argv).argv;return DataConverter.convert(serverOptionsSchema,args)}}const Headers={CONTENT_TYPE:"Content-Type",CONTENT_TYPE_OPTIONS:"X-Content-Type-Options",FRAME_OPTIONS:"X-Frame-Options"};Object.freeze(Headers);const ContentTypes={JSON:"application/json",TEXT:"text/plain",HTML:"text/html"};Object.freeze(ContentTypes);class AssetsController{#repository;#indexFile;#logger;constructor(app,repository,indexFile,logger){this.#repository=repository,this.#indexFile=indexFile,this.#logger=logger,app.get("*",((request,response)=>{this.#getContent(request,response)}))}async#getContent(request,response){try{const path=request.path.substring(1).trim(),decodedPath=decodeURIComponent(path),filename=0===decodedPath.length?this.#indexFile:decodedPath,file=await this.#repository.readAsset(filename);this.#logger.info(`Got asset -> '${request.path}'`),file.type===ContentTypes.HTML&&response.setHeader(Headers.FRAME_OPTIONS,"DENY"),response.setHeader(Headers.CONTENT_TYPE,file.type),response.status(200).send(file.content)}catch(error){if(error instanceof FileNotFound)return this.#logger.warn(`Failed to get asset -> ${error.message}`),void response.status(404).send(error.message);const message=error instanceof Error?error.message:String(error);this.#logger.error(`Failed to get file content -> ${message}`),response.status(500).send(message)}}}class HealthController{#node;#logger;constructor(app,node,logger){this.#node=node,this.#logger=logger,app.get("/health",((request,response)=>{this.getHealth(request,response)})),app.get("/health/status",((request,response)=>{this.isHealthy(request,response)}))}async getHealth(request,response){const health=await this.#node.getHealth(),data=Object.fromEntries(health);return this.#logger.debug("Got health"),response.status(200).send(data)}async isHealthy(request,response){const healthy=await this.#node.isHealthy();return this.#logger.debug("Got health status"),response.setHeader(Headers.CONTENT_TYPE,ContentTypes.TEXT),response.status(200).send(healthy)}}const filePath=fileURLToPath(import.meta.url),fileLocation=path.dirname(filePath);class JitarController{constructor(app){app.use("/jitar",express.static(fileLocation))}}const clientIdHelper=new ClientIdHelper;class ModulesController{#repository;#serializer;#logger;constructor(app,repository,serializer,logger){this.#repository=repository,this.#serializer=serializer,this.#logger=logger,app.post("/modules",((request,response)=>{this.registerClient(request,response)})),app.get("/modules/:clientId/*",((request,response)=>{this.getModule(request,response)}))}async registerClient(request,response){if(this.#logger.info("Register client"),request.body instanceof Array==!1)return response.status(400).send("Invalid segment file list.");const segmentFiles=request.body;for(const segmentFile of segmentFiles)if("string"!=typeof segmentFile)return response.status(400).send("Invalid segment file list.");const clientId=await this.#repository.registerClient(segmentFiles);return this.#logger.info(`Registered client -> ${clientId} [${segmentFiles.join(",")}]`),response.setHeader(Headers.CONTENT_TYPE,ContentTypes.TEXT),response.status(200).send(clientId)}async getModule(request,response){this.#logger.info(`Get module for -> '${request.params.clientId}'`);const clientId=request.params.clientId;if("string"!=typeof clientId||!1===clientIdHelper.validate(clientId))return response.status(400).send("Invalid client id.");const pathKey=`/${clientId}/`,pathIndex=request.path.indexOf(pathKey)+pathKey.length,filename=request.path.substring(pathIndex);try{const file=await this.#repository.readModule(filename,clientId);return this.#logger.info(`Got module -> '${filename}' (${clientId})`),response.setHeader(Headers.CONTENT_TYPE,file.type),response.status(200).send(file.content)}catch(error){const message=error instanceof Error?error.message:String(error);this.#logger.error(`Failed to get module -> '${filename}' (${clientId}) | ${message}`);const data=this.#serializer.serialize(error);return response.setHeader(Headers.CONTENT_TYPE,ContentTypes.JSON),response.status(500).send(data)}}}const nodeDtoSchema=z.object({url:z.string().url(),procedureNames:z.array(z.string()).optional()}).strict().transform((value=>new NodeDto(value.url,value.procedureNames)));class NodeDto{url;procedureNames;constructor(url,procedureNames=[]){this.url=url,this.procedureNames=procedureNames}}class NodesController{#gateway;#logger;constructor(app,gateway,logger){this.#gateway=gateway,this.#logger=logger,app.get("/nodes",((request,response)=>{this.getNodes(request,response)})),app.post("/nodes",((request,response)=>{this.add(request,response)}))}async getNodes(request,response){const nodes=this.#gateway.nodes.map((node=>({url:node.url,procedureNames:node.getProcedureNames()})));return this.#logger.info("Got nodes"),response.setHeader(Headers.CONTENT_TYPE,ContentTypes.JSON),response.status(200).send(nodes)}async add(request,response){try{const nodeDto=DataConverter.convert(nodeDtoSchema,request.body),node=new RemoteNode(nodeDto.url);return node.procedureNames=new Set(nodeDto.procedureNames),this.#gateway.addNode(node),this.#logger.info(`Added node -> ${node.url}`),response.status(201).send()}catch(error){const status=error instanceof Array?400:500,message=error instanceof Error?error.message:String(error);return this.#logger.error(`Failed to add node | ${message}`),response.setHeader(Headers.CONTENT_TYPE,ContentTypes.TEXT),response.status(status).send(error)}}}class ProceduresController{#runtime;#logger;constructor(app,runtime,logger){this.#runtime=runtime,this.#logger=logger,app.get("/procedures",((request,response)=>{this.getProcedureNames(request,response)}))}async getProcedureNames(request,response){const names=this.#runtime.getProcedureNames();return this.#logger.info("Got procedure names"),response.setHeader(Headers.CONTENT_TYPE,ContentTypes.JSON),response.status(200).send(names)}}class ProxyController{#logger;#repositoryUrl;#runnerUrl;constructor(app,proxy,logger){this.#logger=logger,this.#repositoryUrl=proxy.repository.url??"",this.#runnerUrl=proxy.runner.url??"",app.use("/",expressProxy((message=>this.#selectProxy(message))))}#selectProxy(message){const url=message.url??"";return this.#logger.info(`Forwarding -> ${url}`),url.startsWith("/rpc")?this.#runnerUrl:this.#repositoryUrl}}const RPC_PARAMETERS=["version","serialize"],IGNORED_HEADER_KEYS=["host","connection","content-length","accept-encoding","user-agent"],BAD_REQUEST_NAME=BadRequest.name,UNAUTHORIZED_NAME=Unauthorized.name,PAYMENT_REQUIRED_NAME=PaymentRequired.name,FORBIDDEN_NAME=Forbidden.name,NOT_FOUND_NAME=NotFound.name,TEAPOT_NAME=Teapot.name,NOT_IMPLEMENTED_NAME=NotImplemented.name;class RPCController{#runtime;#serializer;#logger;constructor(app,runtime,serializer,logger){this.#runtime=runtime,this.#serializer=serializer,this.#logger=logger,app.get("/rpc/*",((request,response)=>{this.runGet(request,response)})),app.post("/rpc/*",((request,response)=>{this.runPost(request,response)})),app.options("/rpc/*",((request,response)=>{this.runOptions(request,response)}))}async runGet(request,response){try{const fqn=this.#extractFqn(request),version=this.#extractVersion(request),args=this.#extractQueryArguments(request),headers=this.#extractHeaders(request),serialize=this.#extractSerialize(request);return this.#run(fqn,version,args,headers,response,serialize)}catch(error){const message=error instanceof Error?error.message:String(error);return this.#logger.warn(`Invalid request -> ${message}`),response.setHeader(Headers.CONTENT_TYPE,ContentTypes.TEXT),response.status(400).send(`Invalid request -> ${message}`)}}async runPost(request,response){try{const fqn=this.#extractFqn(request),version=this.#extractVersion(request),args=this.#extractBodyArguments(request),headers=this.#extractHeaders(request),serialize=this.#extractSerialize(request);return this.#run(fqn,version,args,headers,response,serialize)}catch(error){const message=error instanceof Error?error.message:String(error);return this.#logger.warn(`Invalid request -> ${message}`),response.setHeader(Headers.CONTENT_TYPE,ContentTypes.TEXT),response.status(400).send(`Invalid request -> ${message}`)}}async runOptions(request,response){return this.#setCors(response)}#extractFqn(request){const fqn=decodeURIComponent(request.path.trim()).substring(5).trim();if(0===fqn.length)throw new BadRequest("Missing procedure name");if(fqn.includes(".."))throw new BadRequest("Invalid procedure name");return fqn}#extractVersion(request){const version=void 0!==request.query.version?request.query.version:"";if("string"!=typeof version)throw new BadRequest("Invalid version number");return VersionParser.parse(version)}#extractSerialize(request){return"true"===request.query.serialize}#extractQueryArguments(request){const args={};for(const[key,value]of Object.entries(request.query))RPC_PARAMETERS.includes(key)||(args[key]=value);return args}#extractBodyArguments(request){return request.body}#extractHeaders(request){const headers=new Map;for(const[key,value]of Object.entries(request.headers)){if(void 0===value)continue;const lowerKey=key.toLowerCase(),stringValue=value.toString();IGNORED_HEADER_KEYS.includes(lowerKey)||headers.set(lowerKey,stringValue)}return headers}async#run(fqn,version,args,headers,response,serialize){if(!1===this.#runtime.hasProcedure(fqn))return response.setHeader(Headers.CONTENT_TYPE,ContentTypes.TEXT),response.status(404).send(`Procedure not found -> ${fqn}`);try{const deserializedArgs=await this.#serializer.deserialize(args),argsMap=new Map(Object.entries(deserializedArgs)),runtimeRequest=new Request(fqn,version,argsMap,headers),runtimeResponse=await this.#runtime.handle(runtimeRequest);return this.#logger.info(`Ran procedure -> ${fqn} (v${version.toString()})`),this.#setResponseHeaders(response,runtimeResponse.headers),this.#createResultResponse(runtimeResponse.result,response,serialize)}catch(error){const message=error instanceof Error?error.message:String(error),errorData=serialize?error:message;return this.#logger.error(`Failed to run procedure -> ${fqn} (v${version.toString()}) | ${message}`),this.#createErrorResponse(error,errorData,response,serialize)}}async#setCors(response){const cors=this.#runtime.getMiddleware(CorsMiddleware);return void 0===cors||(response.setHeader("Access-Control-Allow-Origin",cors.allowOrigin),response.setHeader("Access-Control-Allow-Methods",cors.allowMethods),response.setHeader("Access-Control-Allow-Headers",cors.allowHeaders),response.setHeader("Access-Control-Max-Age",86400)),response.status(204).send()}async#createResultResponse(result,response,serialize){const content=await this.#createResponseContent(result,serialize),contentType=this.#createResponseContentType(content),responseContent=contentType===ContentTypes.TEXT?String(content):content;return response.setHeader(Headers.CONTENT_TYPE,contentType),response.status(200).send(responseContent)}async#createErrorResponse(error,errorData,response,serialize){const content=await this.#createResponseContent(errorData,serialize),contentType=this.#createResponseContentType(content),statusCode=this.#createResponseStatusCode(error);return response.setHeader(Headers.CONTENT_TYPE,contentType),response.status(statusCode).send(content)}async#createResponseContent(data,serialize){return serialize?this.#serializer.serialize(data):data}#createResponseContentType(content){return"object"==typeof content?ContentTypes.JSON:ContentTypes.TEXT}#setResponseHeaders(response,headers){headers.forEach(((value,key)=>response.setHeader(key,value)))}#createResponseStatusCode(error){if(error instanceof Object==!1)return 500;const errorClass=error.constructor;return this.#isClassType(errorClass,BAD_REQUEST_NAME)?400:this.#isClassType(errorClass,UNAUTHORIZED_NAME)?401:this.#isClassType(errorClass,PAYMENT_REQUIRED_NAME)?402:this.#isClassType(errorClass,FORBIDDEN_NAME)?403:this.#isClassType(errorClass,NOT_FOUND_NAME)?404:this.#isClassType(errorClass,TEAPOT_NAME)?418:this.#isClassType(errorClass,NOT_IMPLEMENTED_NAME)?501:500}#isClassType(clazz,className){if(clazz.name===className)return!0;const parentClass=Object.getPrototypeOf(clazz);return""!==parentClass.name&&this.#isClassType(parentClass,className)}}class RuntimeNotAvailable extends Error{constructor(){super("Runtime is not available")}}class JitarServer{#app;#server;#runtime;#serializer;#classLoader;#options;#configuration;#logger;constructor(){this.#classLoader=new RemoteClassLoader,this.#serializer=SerializerBuilder.build(this.#classLoader),this.#app=express(),this.#app.use(express.json()),this.#app.use(express.urlencoded({extended:!0})),this.#app.use(((request,response,next)=>this.#addDefaultHeaders(request,response,next))),this.#app.disable("x-powered-by"),this.#options=ServerOptionsReader.read(),this.#configuration=RuntimeConfigurationLoader.load(this.#options.config),this.#logger=LogBuilder.build(this.#options.loglevel),this.#printStartupMessage()}get classLoader(){return this.#classLoader}async build(){this.#runtime=await RuntimeConfigurator.configure(this.#configuration),this.#addControllers()}async start(){const url=new URL(this.#configuration.url??RuntimeDefaults.URL);await this.#startApplication(),await this.#startServer(url.port),this.#printProcedureInfo(),this.#logger.info(`Server started and listening at port ${url.port}`)}async stop(){await this.#stopServer(),await this.#stopApplication(),this.#logger.info("Server stopped")}addSerializer(serializer){this.#serializer.addSerializer(serializer)}#getRuntime(){if(void 0===this.#runtime)throw new RuntimeNotAvailable;return this.#runtime}#addControllers(){if(void 0!==this.#configuration.standalone&&this.#runtime instanceof Standalone){const index=this.#configuration.standalone.index??RuntimeDefaults.INDEX;this.#addStandAloneControllers(this.#runtime,index)}else if(void 0!==this.#configuration.repository&&this.#runtime instanceof LocalRepository){const index=this.#configuration.repository.index??RuntimeDefaults.INDEX;this.#addRepositoryControllers(this.#runtime,index)}else void 0!==this.#configuration.gateway&&this.#runtime instanceof LocalGateway?this.#addGatewayControllers(this.#runtime):void 0!==this.#configuration.node&&this.#runtime instanceof LocalNode?this.#addNodeControllers(this.#runtime):void 0!==this.#configuration.proxy&&this.#runtime instanceof Proxy&&this.#addProxyControllers(this.#runtime)}#addStandAloneControllers(standalone,index){new HealthController(this.#app,standalone,this.#logger),new JitarController(this.#app),new ModulesController(this.#app,standalone,this.#serializer,this.#logger),new ProceduresController(this.#app,standalone,this.#logger),new RPCController(this.#app,standalone,this.#serializer,this.#logger),new AssetsController(this.#app,standalone,index,this.#logger)}#addRepositoryControllers(repository,index){new JitarController(this.#app),new ModulesController(this.#app,repository,this.#serializer,this.#logger),new AssetsController(this.#app,repository,index,this.#logger)}#addGatewayControllers(gateway){new NodesController(this.#app,gateway,this.#logger),new ProceduresController(this.#app,gateway,this.#logger),new RPCController(this.#app,gateway,this.#serializer,this.#logger)}#addNodeControllers(node){new HealthController(this.#app,node,this.#logger),new ProceduresController(this.#app,node,this.#logger),new RPCController(this.#app,node,this.#serializer,this.#logger)}#addProxyControllers(proxy){new ProxyController(this.#app,proxy,this.#logger)}async#startApplication(){const runtime=this.#getRuntime();await runtime.start();const setUpScripts=this.#configuration.setUp;if(void 0!==setUpScripts)for(const setUpScript of setUpScripts)await runtime.import(setUpScript,ExecutionScopes.APPLICATION)}async#stopApplication(){const runtime=this.#getRuntime();await runtime.stop();const tearDownScripts=this.#configuration.tearDown;if(void 0!==tearDownScripts)for(const tearDownScript of tearDownScripts)await runtime.import(tearDownScript,ExecutionScopes.APPLICATION)}#startServer(port){return void 0!==this.#server?Promise.resolve():new Promise((resolve=>{this.#server=this.#app.listen(port,resolve)}))}#stopServer(){return void 0===this.#server?Promise.resolve():new Promise((resolve=>{this.#server?.close((()=>resolve()))}))}#printStartupMessage(){console.log("\n ██ ██ ████████ █████ ██████ \n ██ ██ ██ ██ ██ ██ ██ \n ██ ██ ██ ███████ ██████ \n ██ ██ ██ ██ ██ ██ ██ ██ \n █████ ██ ██ ██ ██ ██ ██\n ____________________________________\n By Masking Technology (masking.tech)\n")}#printProcedureInfo(){const runtime=this.#getRuntime();if(runtime instanceof LocalNode==!1&&runtime instanceof Standalone==!1)return;const procedureNames=runtime.getProcedureNames();0!==procedureNames.length&&(procedureNames.sort(),this.#logger.info("Registered RPC entries",procedureNames))}#addDefaultHeaders(request,response,next){response.setHeader(Headers.CONTENT_TYPE_OPTIONS,"nosniff"),next()}}async function buildServer(moduleImporter){ModuleLoader.setImporter(moduleImporter);const server=new JitarServer;return await server.build(),server}export{CorsMiddleware,buildServer};
1
+ import{N as NoWorkerAvailable,G as Gateway,I as InvalidTrustKey,P as ProcedureNotFound,R as Repository,M as ModuleLoader,a as InvalidSegmentFile,F as FileNotFound,b as InvalidClientId,C as ClientNotFound,c as File,d as convertToRemoteFilename,i as isSegmentFilename,e as convertToLocalFilename,f as createRepositoryFilename,g as ProcedureRuntime,W as Worker,D as DummyRepository,h as Remote,j as RemoteRepository,k as RemoteGateway,l as RuntimeNotBuilt,L as LocalWorker,m as Reflector,A as AccessLevels,n as ReflectionField,o as ReflectionDestructuredArray,p as ReflectionDestructuredObject,q as ReflectionDestructuredValue,r as createWorkerFilename,V as VersionParser,s as ReflectionFunction,t as Files,B as BadRequest,U as Unauthorized,u as PaymentRequired,v as Forbidden,w as NotFound,T as Teapot,x as NotImplemented,y as Request,z as RemoteClassLoader,S as SerializerBuilder,E as ExecutionScopes}from"./globals-12ESPPwb.js";import express from"express";import{readFileSync}from"fs";import{z}from"zod";import fs from"fs-extra";import glob from"glob-promise";import mime from"mime-types";import path from"path";import yargs from"yargs";import{Logger}from"tslog";import{fileURLToPath}from"url";import expressProxy from"express-http-proxy";class CorsMiddleware{#allowOrigin;#allowMethods="GET, POST";#allowHeaders;constructor(origin="*",headers="*"){this.#allowOrigin=origin,this.#allowHeaders=headers}get allowOrigin(){return this.#allowOrigin}get allowMethods(){return this.#allowMethods}get allowHeaders(){return this.#allowHeaders}async handle(request,next){const response=await next();return this.#setHeaders(response),response}#setHeaders(response){response.setHeader("Access-Control-Allow-Origin",this.#allowOrigin),response.setHeader("Access-Control-Allow-Methods",this.#allowMethods),response.setHeader("Access-Control-Allow-Headers",this.#allowHeaders)}}class WorkerBalancer{#workers=[];#currentIndex=0;addWorker(worker){this.#workers.includes(worker)||this.#workers.push(worker)}removeWorker(worker){const index=this.#workers.indexOf(worker);-1!==index&&this.#workers.splice(index,1)}getNextWorker(){if(0!==this.#workers.length)return this.#currentIndex>=this.#workers.length&&(this.#currentIndex=0),this.#workers[this.#currentIndex++]}run(request){const worker=this.getNextWorker();if(void 0===worker)throw new NoWorkerAvailable(request.fqn);return worker.run(request)}}class LocalGateway extends Gateway{#workers=new Set;#balancers=new Map;#trustKey;constructor(repository,url,trustKey){super(repository,url),this.#trustKey=trustKey}get workers(){return[...this.#workers.values()]}getProcedureNames(){const procedureNames=this.workers.map((worker=>worker.getProcedureNames()));return[...new Set(procedureNames.flat()).values()]}hasProcedure(fqn){return this.getProcedureNames().includes(fqn)}async addWorker(worker,trustKey){if(void 0!==trustKey&&this.#trustKey!==trustKey)throw new InvalidTrustKey;this.#workers.add(worker);for(const name of worker.getProcedureNames()){this.#getOrCreateBalancer(name).addWorker(worker)}}removeWorker(worker){this.#workers.delete(worker);for(const name of worker.getProcedureNames()){const balancer=this.#getBalancer(name);void 0!==balancer&&balancer.removeWorker(worker)}}#getBalancer(fqn){return this.#balancers.get(fqn)}#getOrCreateBalancer(fqn){let balancer=this.#getBalancer(fqn);return void 0===balancer&&(balancer=new WorkerBalancer,this.#balancers.set(fqn,balancer)),balancer}run(request){const balancer=this.#getBalancer(request.fqn);if(void 0===balancer)throw new ProcedureNotFound(request.fqn);return balancer.run(request)}}const CLIENT_ID_REGEX=/^CLIENT_\d+$/;let lastClientId=0;class ClientIdHelper{generate(){return"CLIENT_"+lastClientId++}validate(clientId){return CLIENT_ID_REGEX.test(clientId)}}const clientIdHelper$1=new ClientIdHelper;class LocalRepository extends Repository{#fileManager;#segments=new Map;#clients=new Map;#segmentNames=new Set;#assets=new Set;#overrides=new Map;constructor(fileManager,url){super(url),this.#fileManager=fileManager,ModuleLoader.setBaseUrl(fileManager.getRootLocation())}set segmentNames(names){this.#segmentNames=new Set(names)}set assets(patterns){this.#assets=patterns}set overrides(overrides){this.#overrides=overrides}async start(){await super.start(),await this.#loadSegments(),this.#translateOverrides()}stop(){return this.#unregisterClients(),this.#unloadSegments(),super.stop()}async#loadSegments(){for(const name of this.#segmentNames)await this.#loadSegment(name)}async#loadSegment(name){const relativeFilename=`./${createRepositoryFilename(name)}`,absoluteFilename=this.#fileManager.getAbsoluteLocation(relativeFilename),files=(await ModuleLoader.load(absoluteFilename)).files;if(void 0===files)throw new InvalidSegmentFile(absoluteFilename);this.registerSegment(name,files)}#unloadSegments(){this.#segments.clear()}async registerSegment(name,filenames){filenames.forEach((filename=>this.#segments.set(filename,name)))}#translateOverrides(){const translated=new Map;for(const[targetName,destinationName]of this.#overrides){const relativeTargetFilename=ModuleLoader.assureExtension(targetName),relativeDestinationFilename=ModuleLoader.assureExtension(destinationName),absoluteTargetFilename=this.#fileManager.getAbsoluteLocation(relativeTargetFilename),absoluteDestinationFilename=this.#fileManager.getAbsoluteLocation(relativeDestinationFilename);translated.set(absoluteTargetFilename,absoluteDestinationFilename)}this.#overrides=translated}async registerClient(segmentFilenames){const clientId=clientIdHelper$1.generate();return this.#clients.set(clientId,segmentFilenames),clientId}#unregisterClients(){this.#clients.clear()}readAsset(filename){if(!1===this.#assets.has(filename))throw new FileNotFound(filename);return this.#readFile(filename)}readModule(name,clientId){clientId=this.#validateClientId(clientId);const segmentFilename=this.#segments.get(name);return void 0===segmentFilename||this.#hasClientSegmentFile(clientId,segmentFilename)?this.#readWorkerModule(name):this.#readRemoteModule(name)}loadModule(name){const filename=this.#getModuleFilename(name);return ModuleLoader.load(filename)}#validateClientId(clientId){if(!1===clientIdHelper$1.validate(clientId))throw new InvalidClientId(clientId);if(!1===this.#clients.has(clientId))throw new ClientNotFound(clientId);return clientId}#hasClientSegmentFile(clientId,segmentFilename){const clientSegmentFiles=this.#clients.get(clientId);if(void 0===clientSegmentFiles)throw new ClientNotFound(clientId);return clientSegmentFiles.some((clientSegmentFilename=>segmentFilename.endsWith(clientSegmentFilename)))}async#readWorkerModule(name){const filename=this.#getModuleFilename(name),code=(await this.#readFile(filename)).content.toString();return new File(filename,"application/javascript",code)}#readRemoteModule(name){const remoteFilename=convertToRemoteFilename(name);return this.#readFile(remoteFilename)}#getModuleFilename(name){const relativeFilename=ModuleLoader.assureExtension(name),absoluteFilename=this.#fileManager.getAbsoluteLocation(relativeFilename);if(isSegmentFilename(absoluteFilename))return absoluteFilename;const assignedFilename=this.#getAssignedFilename(absoluteFilename);return convertToLocalFilename(assignedFilename)}#getAssignedFilename(filename){return this.#overrides.get(filename)??filename}#readFile(filename){return this.#fileManager.read(filename)}}class Proxy extends ProcedureRuntime{#runner;constructor(repository,runner,url){super(repository,url),this.#runner=runner}get runner(){return this.#runner}async start(){await super.start(),await this.#runner.start()}async stop(){await this.#runner.stop(),await super.stop()}getProcedureNames(){return this.#runner.getProcedureNames()}hasProcedure(fqn){return this.getProcedureNames().includes(fqn)}readAsset(filename){return this.repository.readAsset(filename)}registerClient(segmentFiles){return this.repository.registerClient(segmentFiles)}readModule(filename,clientId){return this.repository.readModule(filename,clientId)}run(request){return this.#runner.run(request)}}class RemoteWorker extends Worker{#remote;#procedureNames=new Set;constructor(url){super(new DummyRepository,url),this.#remote=new Remote(url)}get trustKey(){}set procedureNames(names){this.#procedureNames=names}getProcedureNames(){return[...this.#procedureNames.values()]}hasProcedure(name){return this.#procedureNames.has(name)}isHealthy(){return this.#remote.isHealthy()}getHealth(){return this.#remote.getHealth()}run(request){return this.#remote.run(request)}}class Standalone extends ProcedureRuntime{#worker;constructor(repository,worker,url){super(repository,url),this.#worker=worker}get worker(){return this.#worker}async start(){await this.#worker.start(),await super.start()}async stop(){await this.#worker.stop(),await super.stop()}getProcedureNames(){return this.#worker.getProcedureNames()}hasProcedure(fqn){return this.getProcedureNames().includes(fqn)}readAsset(filename){return this.repository.readAsset(filename)}registerClient(segmentFiles){return this.repository.registerClient(segmentFiles)}readModule(filename,clientId){return this.repository.readModule(filename,clientId)}run(request){return this.#worker.run(request)}}class RuntimeBuilder{#url;#fileManager;#segments=new Set;#healthChecks=new Set;#middlewares=new Set;#assets=new Set;#overrides=new Map;#repository;#gateway;#worker;url(url){return this.#url=url,this}fileManager(fileManager){return this.#fileManager=fileManager,this}segment(...names){return names.forEach((name=>this.#segments.add(name))),this}healthCheck(...filenames){return filenames.forEach((filename=>this.#healthChecks.add(filename))),this}middleware(...filenames){return filenames.forEach((filename=>this.#middlewares.add(filename))),this}asset(...patterns){return patterns.forEach((pattern=>this.#assets.add(pattern))),this}override(...mappings){for(const map of mappings)for(const[key,value]of Object.entries(map))this.#overrides.set(key,value);return this}repository(url){return this.#repository=void 0!==url?new RemoteRepository(url):void 0,this}gateway(url){return this.#gateway=void 0!==url?new RemoteGateway(url):void 0,this}worker(url){return this.#worker=void 0!==url?new RemoteWorker(url):void 0,this}buildRepository(){if(void 0===this.#fileManager)throw new RuntimeNotBuilt("File manager is not set for the repository");const repository=new LocalRepository(this.#fileManager,this.#url);return repository.healthCheckFiles=this.#healthChecks,repository.segmentNames=this.#segments,repository.assets=this.#assets,repository.overrides=this.#overrides,repository}buildGateway(trustKey){if(void 0===this.#repository)throw new RuntimeNotBuilt("Repository is not set for the gateway");const gateway=new LocalGateway(this.#repository,this.#url,trustKey);return gateway.healthCheckFiles=this.#healthChecks,gateway.middlewareFiles=this.#middlewares,gateway}buildWorker(trustKey){if(void 0===this.#repository)throw new RuntimeNotBuilt("Repository is not set for the worker");const worker=new LocalWorker(this.#repository,this.#gateway,this.#url,trustKey);return worker.segmentNames=this.#segments,worker.healthCheckFiles=this.#healthChecks,worker.middlewareFiles=this.#middlewares,this.#repository.segmentNames=this.#segments,void 0!==this.gateway&&(this.#gateway.worker=worker),worker}buildProxy(){if(void 0===this.#repository)throw new RuntimeNotBuilt("Repository is not set for the proxy");const runner=this.#gateway??this.#worker;if(void 0===runner)throw new RuntimeNotBuilt("Runner (gateway or worker) is not set for the proxy");const proxy=new Proxy(this.#repository,runner,this.#url);return proxy.healthCheckFiles=this.#healthChecks,proxy.middlewareFiles=this.#middlewares,proxy}buildStandalone(trustKey){if(void 0===this.#fileManager)throw new RuntimeNotBuilt("File manager is not set for the standalone");const repository=new LocalRepository(this.#fileManager,this.#url);repository.segmentNames=this.#segments,repository.assets=this.#assets,repository.overrides=this.#overrides;const worker=new LocalWorker(repository,this.#gateway,this.#url,trustKey);worker.segmentNames=this.#segments;const standalone=new Standalone(repository,worker,this.#url);return standalone.healthCheckFiles=this.#healthChecks,standalone.middlewareFiles=this.#middlewares,standalone}}class ProcedureRuntimeConfiguration{#middlewares;constructor(middlewares){this.#middlewares=middlewares}get middlewares(){return this.#middlewares}}const gatewaySchema=z.object({repository:z.string().url(),middlewares:z.array(z.string()).optional(),monitor:z.number().optional(),trustKey:z.string().optional()}).strict().transform((value=>new GatewayConfiguration(value.repository,value.middlewares,value.monitor,value.trustKey)));class GatewayConfiguration extends ProcedureRuntimeConfiguration{#monitor;#repository;#trustKey;constructor(repository,middlewares,monitor,trustKey){super(middlewares),this.#monitor=monitor,this.#repository=repository,this.#trustKey=trustKey}get monitor(){return this.#monitor}get repository(){return this.#repository}get trustKey(){return this.#trustKey}}const workerSchema=z.object({gateway:z.string().url().optional(),repository:z.string().url().optional(),segments:z.array(z.string()).nonempty(),middlewares:z.array(z.string()).optional(),trustKey:z.string().optional()}).strict().transform((value=>new WorkerConfiguration(value.gateway,value.repository,value.segments,value.middlewares,value.trustKey)));class WorkerConfiguration extends ProcedureRuntimeConfiguration{#gateway;#repository;#segments;#trustKey;constructor(gateway,repository,segments,middlewares,trustKey){super(middlewares),this.#gateway=gateway,this.#repository=repository,this.#segments=segments,this.#trustKey=trustKey}get gateway(){return this.#gateway}get repository(){return this.#repository}get segments(){return this.#segments}get trustKey(){return this.#trustKey}}const proxySchema=z.object({worker:z.string().url().optional(),gateway:z.string().url().optional(),repository:z.string().url(),middlewares:z.array(z.string()).optional()}).strict().superRefine(((value,ctx)=>{void 0===value.worker&&void 0===value.gateway&&ctx.addIssue({code:z.ZodIssueCode.custom,message:"Either worker or gateway must be defined",path:["worker","gateway"]}),void 0!==value.worker&&void 0!==value.gateway&&ctx.addIssue({code:z.ZodIssueCode.custom,message:"Only worker or gateway must be defined",path:["worker","gateway"]})})).transform((value=>new ProxyConfiguration(value.worker,value.gateway,value.repository,value.middlewares)));class ProxyConfiguration extends ProcedureRuntimeConfiguration{#worker;#gateway;#repository;constructor(worker,gateway,repository,middlewares){super(middlewares),this.#worker=worker,this.#gateway=gateway,this.#repository=repository}get worker(){return this.#worker}get gateway(){return this.#gateway}get repository(){return this.#repository}}const repositorySchema=z.object({source:z.string().optional(),cache:z.string().optional(),index:z.string().optional(),assets:z.array(z.string()).optional(),overrides:z.record(z.string(),z.string()).optional()}).strict().transform((value=>new RepositoryConfiguration(value.source,value.cache,value.index,value.assets,value.overrides)));class RepositoryConfiguration{#source;#cache;#index;#assets;#overrides;constructor(source,cache,index,assets,overrides){this.#source=source,this.#cache=cache,this.#index=index,this.#assets=assets,this.#overrides=overrides}get source(){return this.#source}get cache(){return this.#cache}get index(){return this.#index}get assets(){return this.#assets}get overrides(){return this.#overrides}}const standaloneSchema=z.object({source:z.string().optional(),cache:z.string().optional(),index:z.string().optional(),segments:z.array(z.string()).optional(),assets:z.array(z.string()).optional(),middlewares:z.array(z.string()).optional(),overrides:z.record(z.string(),z.string()).optional(),trustKey:z.string().optional()}).strict().transform((value=>new StandaloneConfiguration(value.source,value.cache,value.index,value.segments,value.assets,value.middlewares,value.overrides,value.trustKey)));class StandaloneConfiguration extends ProcedureRuntimeConfiguration{#source;#cache;#index;#segments;#assets;#overrides;#trustKey;constructor(source,cache,index,segments,assets,middlewares,overrides,trustKey){super(middlewares),this.#source=source,this.#cache=cache,this.#index=index,this.#segments=segments,this.#assets=assets,this.#overrides=overrides,this.#trustKey=trustKey}get source(){return this.#source}get cache(){return this.#cache}get index(){return this.#index}get segments(){return this.#segments}get assets(){return this.#assets}get overrides(){return this.#overrides}get trustKey(){return this.#trustKey}}const runtimeSchema=z.object({url:z.string().optional(),setUp:z.array(z.string()).optional(),tearDown:z.array(z.string()).optional(),healthChecks:z.array(z.string()).optional(),standalone:standaloneSchema.optional(),repository:repositorySchema.optional(),gateway:gatewaySchema.optional(),worker:workerSchema.optional(),proxy:proxySchema.optional()}).strict().transform((value=>new RuntimeConfiguration(value.url,value.setUp,value.tearDown,value.healthChecks,value.standalone,value.repository,value.gateway,value.worker,value.proxy)));class RuntimeConfiguration{#url;#setUp;#tearDown;#healthChecks;#standalone;#repository;#gateway;#worker;#proxy;constructor(url,setUp,tearDown,healthChecks,standalone,repository,gateway,worker,proxy){this.#url=url,this.#setUp=setUp,this.#tearDown=tearDown,this.#healthChecks=healthChecks,this.#standalone=standalone,this.#repository=repository,this.#gateway=gateway,this.#worker=worker,this.#proxy=proxy}get url(){return this.#url}get setUp(){return this.#setUp}get tearDown(){return this.#tearDown}get healthChecks(){return this.#healthChecks}get standalone(){return this.#standalone}get repository(){return this.#repository}get gateway(){return this.#gateway}get worker(){return this.#worker}get proxy(){return this.#proxy}}class EnvironmentVariableNotFound extends Error{constructor(name){super(`The environment variable '${name}' is not found`)}}class ConversionError extends Error{constructor(message){super(message)}}class DataConverter{static convert(schema,dataObject){try{return schema.parse(dataObject)}catch(error){const errors=error.errors,message=JSON.stringify(errors);throw new ConversionError(message)}}}const ENVIRONMENT_VARIABLE_REGEX=/\${([^}]*)}/g;class RuntimeConfigurationLoader{static load(filename){const plainContents=readFileSync(filename,"utf-8"),replacedContents=this.#replaceEnvironmentVariables(plainContents),parsedContents=JSON.parse(replacedContents);return DataConverter.convert(runtimeSchema,parsedContents)}static#replaceEnvironmentVariables(contents){return contents.replace(ENVIRONMENT_VARIABLE_REGEX,((match,group)=>{const value=process.env[group];if(void 0===value)throw new EnvironmentVariableNotFound(group);return value}))}}class ApplicationCache{#segments;#modules;constructor(segments,modules){this.#segments=segments,this.#modules=modules}get segments(){return this.#segments}get modules(){return this.#modules}}class ModuleCache{#module;#segment;constructor(module,segment){this.#module=module,this.#segment=segment}get module(){return this.#module}get segment(){return this.#segment}}class ModuleCacheBuilder{build(application,module){const segment=application.getSegmentModule(module.filename);return new ModuleCache(module,segment)}}class DuplicateImplementation extends Error{constructor(fqn,version){super(`Duplicate implementation found for '${fqn}' with version '${version}'.`)}}class SegmentCache{#name;#imports;#procedures;#files;constructor(name,files,imports,procedures){this.#name=name,this.#files=files,this.#imports=imports,this.#procedures=procedures}get name(){return this.#name}get files(){return this.#files}get imports(){return this.#imports}get procedures(){return this.#procedures}}class SegmentImport{#members;#from;constructor(members,from){this.#members=members,this.#from=from}get members(){return this.#members}get from(){return this.#from}}class SegmentProcedure{#fqn;#implementations=[];constructor(fqn,implementations=[]){this.#fqn=fqn,this.#implementations=implementations}get fqn(){return this.#fqn}get implementations(){return this.#implementations}addImplementation(implementation){this.#implementations.push(implementation)}}class SegmentCacheBuilder{build(segment){const files=this.#extractFiles(segment),imports=this.#createImports(segment),procedures=this.#mergeProcedures(segment);return this.#validateProcedures(procedures),new SegmentCache(segment.name,files,imports,procedures)}#extractFiles(segment){return segment.modules.map((module=>module.filename))}#createImports(segment){const imports=[];for(const module of segment.modules){let members=[];for(const procedure of module.procedures){const ids=procedure.implementations.map((implementation=>this.#createImportMember(implementation)));members=[...members,...ids]}imports.push(new SegmentImport(members,module.filename))}return imports}#createImportMember(implementation){return`${implementation.importKey} : ${implementation.id}`}#mergeProcedures(segment){const procedures=new Map;for(const module of segment.modules)for(const procedure of module.procedures){if(procedures.has(procedure.fqn)){const existingProcedure=procedures.get(procedure.fqn);for(const implementation of procedure.implementations)existingProcedure.addImplementation(implementation);continue}const procedureCopy=new SegmentProcedure(procedure.fqn,[...procedure.implementations]);procedures.set(procedure.fqn,procedureCopy)}return[...procedures.values()]}#validateProcedures(procedures){for(const procedure of procedures)this.#checkForDuplicateImplementations(procedure)}#checkForDuplicateImplementations(procedure){for(const implementation of procedure.implementations){if(void 0!==procedure.implementations.find((other=>other.id!==implementation.id&&other.version===implementation.version)))throw new DuplicateImplementation(procedure.fqn,implementation.version)}}}class ApplicationCacheBuilder{#moduleCacheBuilder;#segmentCacheBuilder;constructor(){this.#moduleCacheBuilder=new ModuleCacheBuilder,this.#segmentCacheBuilder=new SegmentCacheBuilder}build(application){const segments=this.#buildSegmentCaches(application),modules=this.#buildModuleCaches(application);return new ApplicationCache(segments,modules)}#buildSegmentCaches(application){return application.segments.map((segment=>this.#segmentCacheBuilder.build(segment)))}#buildModuleCaches(application){return application.modules.map((module=>this.#moduleCacheBuilder.build(application,module)))}}const Keyword={DEFAULT:"default"};Object.freeze(Keyword);const IMPORT_PATTERN=/import\s(?:["'\s]*([\w*{}\n, ]+)from\s*)?["'\s]*([@\w/._-]+)["'\s].*/g,APPLICATION_MODULE_INDICATORS=[".","/","http:","https:"],reflector$2=new Reflector;const importRewriter=new class{rewrite(code,filename){return code.replaceAll(IMPORT_PATTERN,(statement=>this.#replaceImport(statement,filename)))}#replaceImport(statement,filename){const dependency=reflector$2.parseImport(statement);return this.#isApplicationModule(dependency)?this.#rewriteApplicationImport(dependency,filename):this.#rewriteRuntimeImport(dependency,filename)}#isApplicationModule(dependency){return APPLICATION_MODULE_INDICATORS.some((indicator=>dependency.from.startsWith(indicator,1)))}#rewriteApplicationImport(dependency,filename){return this.#rewriteImport(dependency,"application",filename)}#rewriteRuntimeImport(dependency,filename){return this.#rewriteImport(dependency,"runtime",filename)}#rewriteImport(dependency,scope,filename){const from=this.#rewriteImportFrom(dependency,filename);if(0===dependency.members.length)return`await __import("${from}", "${scope}");`;return`const ${this.#rewriteImportMembers(dependency)} = await __import("${from}", "${scope}");`}#rewriteImportFrom(dependency,filename){const from=dependency.from.substring(1,dependency.from.length-1);return this.#isApplicationModule(dependency)?this.#mergeFilenames(filename,from):from}#rewriteImportMembers(dependency){if(this.#mustUseAs(dependency))return dependency.members[0].as;return`{ ${dependency.members.map((member=>member.name!==member.as?`${member.name} : ${member.as}`:member.name)).join(", ")} }`}#mergeFilenames(sourceFilename,importFilename){const concatenated=`${this.#extractFilepath(sourceFilename)}/${importFilename}`,translated=this.#translateFilename(concatenated),rooted=this.#ensureRoot(translated);return this.#ensureExtension(rooted)}#extractFilepath(filename){return filename.split("/").slice(0,-1).join("/")}#translateFilename(filename){const parts=filename.split("/"),translated=[];translated.push(parts[0]);for(let index=1;index<parts.length;index++){const part=parts[index].trim();switch(part){case"":case".":continue;case"..":translated.pop();continue}translated.push(part)}return translated.join("/")}#ensureRoot(filename){return filename.startsWith("./")?filename:(filename.startsWith("//")&&(filename=filename.substring(1)),filename.startsWith("/")?`.${filename}`:`./${filename}`)}#ensureExtension(filename){return filename.endsWith(".js")?filename:`${filename}.js`}#mustUseAs(dependency){return this.#doesImportAll(dependency)||this.#doesImportDefault(dependency)}#doesImportAll(dependency){return 1===dependency.members.length&&"*"===dependency.members[0].name}#doesImportDefault(dependency){return 1===dependency.members.length&&dependency.members[0].name===Keyword.DEFAULT}},remoteBuilder=new class{build(module){let code="";for(const procedure of module.procedures)for(const implementation of procedure.implementations){const asDefault=implementation.importKey===Keyword.DEFAULT;code+=implementation.access===AccessLevels.PRIVATE?this.#createPrivateCode(procedure.fqn,implementation,asDefault):this.#createPublicCode(procedure.fqn,implementation,asDefault)}return code.trim()}#createPrivateCode(fqn,implementation,asDefault){const version=implementation.version,declaration=this.#createDeclaration(implementation,asDefault),body=`throw new ProcedureNotAccessible('${fqn}', '${version}');`;return this.#createFunction(declaration,body)}#createPublicCode(fqn,implementation,asDefault){const version=implementation.version,args=this.#createArguments(implementation.executable.parameters),declaration=this.#createDeclaration(implementation,asDefault),body=`return __run('${fqn}', '${version}', { ${args} }, this);`;return this.#createFunction(declaration,body)}#createParameters(parameters){const result=[];for(const parameter of parameters)parameter instanceof ReflectionField?result.push(parameter.name):(parameter instanceof ReflectionDestructuredArray||parameter instanceof ReflectionDestructuredObject)&&result.push(parameter.toString());return result.join(", ")}#createArguments(parameters){return this.#extractArguments(parameters).join(", ")}#extractArguments(parameters){const result=[];for(const parameter of parameters)if(parameter instanceof ReflectionDestructuredValue){const argumentz=this.#extractArguments(parameter.members);result.push(...argumentz)}else if(parameter instanceof ReflectionField){const argument=this.#createNamedArgument(parameter);result.push(argument)}return result}#createNamedArgument(parameter){const key=parameter.name,value=key.startsWith("...")?key.substring(3):key;return`'${key}': ${value}`}#createDeclaration(implementation,asDefault){const name=implementation.executable.name,parameters=this.#createParameters(implementation.executable.parameters);return`\nexport ${asDefault?`${Keyword.DEFAULT} `:""}async function ${name}(${parameters})`}#createFunction(declaration,body){return`${declaration} {\n\t${body}\n}\n`}};class ModuleCacheWriter{#fileManager;constructor(fileManager){this.#fileManager=fileManager}async write(cache){return Promise.all([this.#writeLocal(cache),this.#writeRemote(cache)]).then((()=>{}))}async#writeLocal(cache){const importCode=this.#rewriteAllImports(cache.module),sourceCode=this.#createSourceCode(cache.module),filename=convertToLocalFilename(cache.module.filename),code=`${importCode}\n${sourceCode}`;return this.#fileManager.write(filename,code.trim())}#rewriteAllImports(module){return importRewriter.rewrite(module.code,module.filename)}#createSourceCode(module){const filename=module.filename;return module.content.exportedClasses.map((clazz=>clazz.name)).map((className=>`${className}.source = "./${filename}";`)).join("\n")}async#writeRemote(cache){if(void 0===cache.segment)return;const filename=convertToRemoteFilename(cache.module.filename),code=this.#createRemoteCode(cache.segment);return this.#fileManager.write(filename,code.trim())}#createRemoteCode(module){return remoteBuilder.build(module)}}class SegmentCacheWriter{#fileManager;constructor(fileManager){this.#fileManager=fileManager}async write(cache){return Promise.all([this.#writeWorkerCache(cache),this.#writeRepositoryCache(cache)]).then((()=>{}))}async#writeWorkerCache(cache){const importCode=this.#createImportCode(cache.imports),segmentCode=this.#createSegmentCode(cache.name,cache.procedures),filename=createWorkerFilename(cache.name),code=`${importCode}\n${segmentCode}`;return this.#fileManager.write(filename,code)}async#writeRepositoryCache(cache){const filename=createRepositoryFilename(cache.name),code=`export const files = [\n\t"${[...cache.files].join('",\n\t"')}"\n];`;return this.#fileManager.write(filename,code)}#createImportCode(imports){const codes=[];for(const{members:members,from:from}of imports)codes.push(`const { ${members.join(", ")} } = await __import("./${from}", "application", false);`);return codes.join("\n")}#createSegmentCode(name,procedures){const codes=[];codes.push('const { Segment, Procedure, Implementation, Version, NamedParameter, ArrayParameter, ObjectParameter } = await __import("jitar", "runtime", false);'),codes.push(`export const segment = new Segment("${name}")`);for(const procedure of procedures){codes.push(`\t.addProcedure(new Procedure("${procedure.fqn}")`);for(const implementation of procedure.implementations){const version=this.#createVersionCode(implementation.version),parameters=this.#createParametersCode(implementation.executable);codes.push(`\t\t.addImplementation(new Implementation(${version}, "${implementation.access}", ${parameters}, ${implementation.id}))`)}codes.push("\t)")}return codes.join("\n")}#createVersionCode(versionString){const version=VersionParser.parse(versionString);return`new Version(${version.major}, ${version.minor}, ${version.patch})`}#createParametersCode(executable){return`[${this.#extractParameters(executable.parameters).join(", ")}]`}#extractParameters(parameters){const result=[];for(const parameter of parameters)result.push(this.#extractParameter(parameter));return result}#extractParameter(parameter){return parameter instanceof ReflectionDestructuredArray?this.#createArrayParameter(parameter):parameter instanceof ReflectionDestructuredObject?this.#createObjectParameter(parameter):this.#createNamedParameter(parameter)}#createNamedParameter(parameter){return`new NamedParameter("${parameter.name}", ${void 0!==parameter.value})`}#createArrayParameter(parameter){return`new ArrayParameter([${this.#extractParameters(parameter.members).join(", ")}])`}#createObjectParameter(parameter){return`new ObjectParameter([${this.#extractParameters(parameter.members).join(", ")}])`}}class ApplicationCacheWriter{#moduleWriter;#segmentWriter;constructor(fileManager){this.#moduleWriter=new ModuleCacheWriter(fileManager),this.#segmentWriter=new SegmentCacheWriter(fileManager)}async write(cache){return Promise.all([this.#writeSegmentCache(cache.segments),this.#writeModuleCache(cache.modules)]).then((()=>{}))}async#writeSegmentCache(segments){return Promise.all(segments.map((async segment=>this.#segmentWriter.write(segment)))).then((()=>{}))}async#writeModuleCache(modules){return Promise.all(modules.map((async module=>this.#moduleWriter.write(module)))).then((()=>{}))}}class Application{#segments;#modules;constructor(segments,modules){this.#segments=segments,this.#modules=modules}get segments(){return this.#segments}get modules(){return this.#modules}getSegmentModule(filename){const segment=this.#segments.find((segment=>segment.hasModule(filename)));if(void 0!==segment)return segment.getModule(filename)}}class ModuleFileNotLoaded extends Error{constructor(filename,message){super(`Failed to load module file '${filename}' because of: ${message}`)}}class Module{#filename;#code;#content;constructor(filename,code,content){this.#code=code,this.#filename=filename,this.#content=content}get filename(){return this.#filename}get code(){return this.#code}get content(){return this.#content}}const reflector$1=new Reflector;class ModuleReader{#fileManager;constructor(fileManager){this.#fileManager=fileManager}async read(filename){const relativeLocation=this.#fileManager.getRelativeLocation(filename),code=await this.#loadCode(filename),module=reflector$1.parse(code);return new Module(relativeLocation,code,module)}async#loadCode(filename){try{return(await this.#fileManager.getContent(filename)).toString()}catch(error){const message=error instanceof Error?error.message:String(error);throw new ModuleFileNotLoaded(filename,message)}}}class FunctionNotAsync extends Error{constructor(filename,functionName){super(`Function '${functionName}' from file '${filename}' is not async`)}}class InvalidSegmentFilename extends Error{constructor(filename){super(`Segment filename '${filename}' is invalid`)}}class MissingModuleExport extends Error{constructor(filename,key){super(`Module '${filename}' does not export '${key}'`)}}class SegmentFileNotLoaded extends Error{constructor(filename,message){super(`Failed to load segment file '${filename}' because of: ${message}`)}}class SegmentModuleNotLoaded extends Error{constructor(filename,message){super(`Segment module could not be loaded from '${filename}' because of: ${message}`)}}class Segment{#name;#modules;constructor(name,modules){this.#name=name,this.#modules=modules}get name(){return this.#name}get modules(){return this.#modules}hasModule(filename){return this.#modules.some((module=>module.filename===filename))}getModule(filename){return this.#modules.find((module=>module.filename===filename))}}class SegmentImplementation{#id;#importKey;#access;#version;#executable;constructor(id,importKey,access,version,executable){this.#id=id,this.#importKey=importKey,this.#access=access,this.#version=version,this.#executable=executable}get id(){return this.#id}get importKey(){return this.#importKey}get access(){return this.#access}get version(){return this.#version}get executable(){return this.#executable}}class SegmentModule{#filename;#procedures=[];constructor(filename,procedures){this.#filename=filename,this.#procedures=procedures}get filename(){return this.#filename}get procedures(){return this.#procedures}}class IdGenerator{#id=0;next(){return"$"+ ++this.#id}}const reflector=new Reflector;class SegmentReader{#fileManager;constructor(fileManager){this.#fileManager=fileManager}async read(filename){const name=this.#extractSegmentName(filename),definition=await this.#loadSegmentDefinition(filename),modules=await this.#createSegmentModules(definition);return new Segment(name,modules)}#extractSegmentName(filename){const file=filename.split("/").pop();if(void 0===file||""===file)throw new InvalidSegmentFilename(filename);return file.replace(".segment.json","")}async#loadSegmentDefinition(filename){try{const content=await this.#fileManager.getContent(filename);return JSON.parse(content.toString())}catch(error){const message=error instanceof Error?error.message:String(error);throw new SegmentFileNotLoaded(filename,message)}}async#createSegmentModules(definition){const modules=[],idGenerator=new IdGenerator;for(const[filename,moduleImports]of Object.entries(definition)){const fullFilename=filename.endsWith(".js")?filename:`${filename}.js`,absoluteFilename=this.#fileManager.getAbsoluteLocation(fullFilename),module=await this.#createSegmentModule(absoluteFilename,moduleImports,idGenerator);modules.push(module)}return modules}async#createSegmentModule(absoluteFilename,imports,idGenerator){const module=await this.#loadSegmentModule(absoluteFilename),relativeFilename=this.#fileManager.getRelativeLocation(absoluteFilename),moduleName=this.#extractModuleName(relativeFilename),procedures=this.#extractSegmentProcedures(module,moduleName,imports,idGenerator);return new SegmentModule(relativeFilename,procedures)}async#loadSegmentModule(absoluteLocation){try{const code=await this.#fileManager.getContent(absoluteLocation);return reflector.parse(code.toString())}catch(error){const message=error instanceof Error?error.message:String(error);throw new SegmentModuleNotLoaded(absoluteLocation,message)}}#extractModuleName(relativeFilename){const moduleParts=relativeFilename.split("/");return moduleParts.pop(),moduleParts.join("/")}#extractSegmentProcedures(module,moduleName,imports,idGenerator){const procedures=new Map;for(const[importKey,properties]of Object.entries(imports)){const executable=module.getExported(importKey);if(void 0===executable)throw new MissingModuleExport(moduleName,importKey);if(executable instanceof ReflectionFunction==!1)continue;if(!1===executable.isAsync)throw new FunctionNotAsync(moduleName,executable.name);const procedureName=properties.as??executable.name,access=properties.access??"private",version=properties.version??"0.0.0",id=idGenerator.next(),fqn=""!==moduleName?`${moduleName}/${procedureName}`:procedureName,implementation=new SegmentImplementation(id,importKey,access,version,executable),procedure=procedures.has(fqn)?procedures.get(fqn):new SegmentProcedure(fqn);procedure.addImplementation(implementation),procedures.set(fqn,procedure)}return[...procedures.values()]}}class ApplicationReader{#moduleReader;#segmentReader;constructor(fileManager){this.#moduleReader=new ModuleReader(fileManager),this.#segmentReader=new SegmentReader(fileManager)}async read(segmentFiles,moduleFiles){return Promise.all([this.#readSegments(segmentFiles),this.#readModules(moduleFiles)]).then((([segments,modules])=>new Application(segments,modules)))}async#readSegments(segmentFiles){return Promise.all(segmentFiles.map((async segmentFile=>this.#segmentReader.read(segmentFile))))}async#readModules(moduleFiles){return Promise.all(moduleFiles.map((async moduleFile=>this.#moduleReader.read(moduleFile))))}}class CacheManager{#projectFileManager;#appFileManager;#reader;#builder;#writer;constructor(projectFileManager,appFileManager){this.#projectFileManager=projectFileManager,this.#appFileManager=appFileManager,this.#reader=new ApplicationReader(appFileManager),this.#builder=new ApplicationCacheBuilder,this.#writer=new ApplicationCacheWriter(appFileManager)}async build(){const segmentFiles=await this.#projectFileManager.filter(Files.SEGMENT_PATTERN),moduleFiles=await this.#appFileManager.filter(Files.MODULE_PATTERN),application=await this.#reader.read(segmentFiles,moduleFiles),cache=this.#builder.build(application);return this.#writer.write(cache)}}const RuntimeDefaults={URL:"http://localhost:3000",SOURCE:"./dist",CACHE:"./.jitar",INDEX:"index.html"};Object.freeze(RuntimeDefaults);class UnknownRuntimeMode extends Error{constructor(){super("Unknown runtime mode")}}class LocalFileManager{#location;constructor(location){this.#location=location}getRootLocation(){return path.resolve(this.#location)}getAbsoluteLocation(filename){const location=filename.startsWith("/")?filename:path.join(this.#location,filename);return path.resolve(location)}getRelativeLocation(filename){return path.relative(this.#location,filename)}async getType(filename){const location=this.getAbsoluteLocation(filename);return mime.lookup(location)||"application/octet-stream"}async getContent(filename){const location=this.getAbsoluteLocation(filename);if(!1===fs.existsSync(location))throw new FileNotFound(filename);return fs.readFile(location)}async read(filename){const rootPath=this.getRootLocation(),absoluteFilename=this.getAbsoluteLocation(filename);if(!1===absoluteFilename.startsWith(rootPath))throw new FileNotFound(filename);const 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),directory=path.dirname(location);return await fs.mkdir(directory,{recursive:!0}),fs.writeFile(location,content)}async copy(source,destination){const sourceLocation=this.getAbsoluteLocation(source),destinationLocation=this.getAbsoluteLocation(destination);return fs.copy(sourceLocation,destinationLocation,{overwrite:!0})}async delete(filename){const location=this.getAbsoluteLocation(filename);return fs.remove(location)}async filter(pattern){const location=this.getAbsoluteLocation("./");return glob(`${location}/${pattern}`)}async getWorkerSegmentFiles(){return this.filter("**/*.segment.worker.js")}async getRepositorySegmentFiles(){return this.filter("**/*.segment.repository.js")}async getAssetFiles(patterns){const promises=patterns.map((pattern=>this.filter(pattern)));return(await Promise.all(promises)).flat().map((filename=>this.getRelativeLocation(filename))).filter((filename=>!1===this.#isGeneratedFile(filename)))}#isGeneratedFile(filename){return filename.endsWith(".local.js")||filename.endsWith(".worker.js")||filename.endsWith(".repository.js")||filename.endsWith(".remote.js")}}class RuntimeConfigurator{static async configure(configuration){const url=configuration.url??RuntimeDefaults.URL,healthChecks=configuration.healthChecks??[];if(void 0!==configuration.standalone)return this.#configureStandAlone(url,healthChecks,configuration.standalone);if(void 0!==configuration.repository)return this.#configureRepository(url,healthChecks,configuration.repository);if(void 0!==configuration.gateway)return this.#configureGateway(url,healthChecks,configuration.gateway);if(void 0!==configuration.worker)return this.#configureWorker(url,healthChecks,configuration.worker);if(void 0!==configuration.proxy)return this.#configureProxy(url,healthChecks,configuration.proxy);throw new UnknownRuntimeMode}static async#configureStandAlone(url,healthChecks,configuration){const sourceLocation=configuration.source??RuntimeDefaults.SOURCE,cacheLocation=configuration.cache??RuntimeDefaults.CACHE,overrides=configuration.overrides??{},middlewares=configuration.middlewares??[],fileManager=new LocalFileManager(cacheLocation),trustKey=configuration.trustKey;await this.#buildCache(sourceLocation,cacheLocation);const segmentNames=void 0===configuration.segments?await this.#getWorkerSegmentNames(fileManager):configuration.segments,assets=void 0!==configuration.assets?await fileManager.getAssetFiles(configuration.assets):[];return(new RuntimeBuilder).url(url).healthCheck(...healthChecks).middleware(...middlewares).segment(...segmentNames).asset(...assets).override(overrides).fileManager(fileManager).buildStandalone(trustKey)}static async#configureRepository(url,healthChecks,configuration){const sourceLocation=configuration.source??RuntimeDefaults.SOURCE,cacheLocation=configuration.cache??RuntimeDefaults.CACHE,overrides=configuration.overrides??{},fileManager=new LocalFileManager(cacheLocation);await this.#buildCache(sourceLocation,cacheLocation);const segmentNames=await this.#getRepositorySegmentNames(fileManager),assets=void 0!==configuration.assets?await fileManager.getAssetFiles(configuration.assets):[];return(new RuntimeBuilder).url(url).healthCheck(...healthChecks).segment(...segmentNames).asset(...assets).override(overrides).fileManager(fileManager).buildRepository()}static async#configureGateway(url,healthChecks,configuration){const repositoryUrl=configuration.repository,middlewares=configuration.middlewares??[];configuration.monitor;const trustKey=configuration.trustKey;return(new RuntimeBuilder).url(url).healthCheck(...healthChecks).middleware(...middlewares).repository(repositoryUrl).buildGateway(trustKey)}static async#configureWorker(url,healthChecks,configuration){const repositoryUrl=configuration.repository,gatewayUrl=configuration.gateway,segmentNames=configuration.segments??[],middlewares=configuration.middlewares??[],trustKey=configuration.trustKey;return(new RuntimeBuilder).url(url).healthCheck(...healthChecks).middleware(...middlewares).repository(repositoryUrl).gateway(gatewayUrl).segment(...segmentNames).buildWorker(trustKey)}static async#configureProxy(url,healthChecks,configuration){const repositoryUrl=configuration.repository,gatewayUrl=configuration.gateway,workerUrl=configuration.worker,middlewares=configuration.middlewares??[];return(new RuntimeBuilder).url(url).healthCheck(...healthChecks).middleware(...middlewares).repository(repositoryUrl).gateway(gatewayUrl).worker(workerUrl).buildProxy()}static async#buildCache(sourceLocation,cacheLocation){const projectFileManager=new LocalFileManager("./");await projectFileManager.delete(cacheLocation),await projectFileManager.copy(sourceLocation,cacheLocation);const appFileManager=new LocalFileManager(cacheLocation),cacheManager=new CacheManager(projectFileManager,appFileManager);await cacheManager.build()}static async#getWorkerSegmentNames(fileManager){return(await fileManager.getWorkerSegmentFiles()).map((filename=>this.#extractSegmentName(filename)))}static async#getRepositorySegmentNames(fileManager){return(await fileManager.getRepositorySegmentFiles()).map((filename=>this.#extractSegmentName(filename)))}static#extractSegmentName(filename){const name=filename.split("/").pop()??"",endIndex=name.indexOf(".segment");return name.substring(0,endIndex)}}var LogLevel;!function(LogLevel){LogLevel.DEBUG="debug",LogLevel.INFO="info",LogLevel.WARN="warn",LogLevel.ERROR="error",LogLevel.FATAL="fatal"}(LogLevel||(LogLevel={}));class LogBuilder{static build(level){const logConfiguration=this.#getLogConfiguration(level);return new Logger(logConfiguration)}static#getLogConfiguration(level){return{prettyLogTemplate:"{{dateIsoStr}}\t{{logLevelName}}\t",minLevel:this.#getLogLevel(level)}}static#getLogLevel(level){switch(level){case LogLevel.FATAL:return 6;case LogLevel.ERROR:return 5;case LogLevel.WARN:return 4;case LogLevel.INFO:return 3;default:return 2}}}const serverOptionsSchema=z.object({loglevel:z.nativeEnum(LogLevel).optional(),config:z.string().endsWith(".json")}).transform((value=>new ServerOptions(value.config,value.loglevel)));class ServerOptions{#config;#loglevel;constructor(config,loglevel="info"){this.#config=config,this.#loglevel=loglevel}get config(){return this.#config}get loglevel(){return this.#loglevel}}class ServerOptionsReader{static read(){const args=yargs(process.argv).argv;return DataConverter.convert(serverOptionsSchema,args)}}const Headers={CONTENT_TYPE:"Content-Type",CONTENT_TYPE_OPTIONS:"X-Content-Type-Options",FRAME_OPTIONS:"X-Frame-Options",LOCATION:"Location"};Object.freeze(Headers);const ContentTypes={BOOLEAN:"application/boolean",NUMBER:"application/number",JSON:"application/json",TEXT:"text/plain",HTML:"text/html"};Object.freeze(ContentTypes);class AssetsController{#repository;#indexFile;#logger;constructor(app,repository,indexFile,logger){this.#repository=repository,this.#indexFile=indexFile,this.#logger=logger,app.get("*",((request,response)=>{this.#getContent(request,response)}))}async#getContent(request,response){try{const path=request.path.substring(1).trim(),decodedPath=decodeURIComponent(path),filename=0===decodedPath.length?this.#indexFile:decodedPath,file=await this.#repository.readAsset(filename);this.#logger.info(`Got asset -> '${request.path}'`),file.type===ContentTypes.HTML&&response.setHeader(Headers.FRAME_OPTIONS,"DENY"),response.setHeader(Headers.CONTENT_TYPE,file.type),response.status(200).send(file.content)}catch(error){if(error instanceof FileNotFound)return this.#logger.warn(`Failed to get asset -> ${error.message}`),void response.status(404).type("text").send(error.message);const message=error instanceof Error?error.message:"Internal server error";this.#logger.error(`Failed to get file content -> ${message}`),response.status(500).type("text").send(message)}}}class HealthController{#worker;#logger;constructor(app,worker,logger){this.#worker=worker,this.#logger=logger,app.get("/health",((request,response)=>{this.getHealth(request,response)})),app.get("/health/status",((request,response)=>{this.isHealthy(request,response)}))}async getHealth(request,response){const health=await this.#worker.getHealth(),data=Object.fromEntries(health);return this.#logger.debug("Got health"),response.status(200).send(data)}async isHealthy(request,response){const healthy=await this.#worker.isHealthy();return this.#logger.debug("Got health status"),response.setHeader(Headers.CONTENT_TYPE,ContentTypes.TEXT),response.status(200).send(healthy)}}const filePath=fileURLToPath(import.meta.url),fileLocation=path.dirname(filePath);class JitarController{constructor(app){app.use("/jitar",express.static(fileLocation))}}const clientIdHelper=new ClientIdHelper;class ModulesController{#repository;#serializer;#logger;constructor(app,repository,serializer,logger){this.#repository=repository,this.#serializer=serializer,this.#logger=logger,app.post("/modules",((request,response)=>{this.registerClient(request,response)})),app.get("/modules/:clientId/*",((request,response)=>{this.getModule(request,response)}))}async registerClient(request,response){if(this.#logger.info("Register client"),request.body instanceof Array==!1)return response.status(400).send("Invalid segment file list.");const segmentFiles=request.body;for(const segmentFile of segmentFiles)if("string"!=typeof segmentFile)return response.status(400).send("Invalid segment file list.");const clientId=await this.#repository.registerClient(segmentFiles);return this.#logger.info(`Registered client -> ${clientId} [${segmentFiles.join(",")}]`),response.setHeader(Headers.CONTENT_TYPE,ContentTypes.TEXT),response.status(200).send(clientId)}async getModule(request,response){const clientId=request.params.clientId;if("string"!=typeof clientId||!1===clientIdHelper.validate(clientId))return response.status(400).send("Invalid client id.");this.#logger.info(`Get module for -> '${request.params.clientId}'`);const pathKey=`/${clientId}/`,pathIndex=request.path.indexOf(pathKey)+pathKey.length,filename=request.path.substring(pathIndex);try{const file=await this.#repository.readModule(filename,clientId);return this.#logger.info(`Got module -> '${filename}' (${clientId})`),response.setHeader(Headers.CONTENT_TYPE,file.type),response.status(200).send(file.content)}catch(error){const message=error instanceof Error?error.message:String(error);this.#logger.error(`Failed to get module -> '${filename}' (${clientId}) | ${message}`);const data=this.#serializer.serialize(error);return response.setHeader(Headers.CONTENT_TYPE,ContentTypes.JSON),response.status(500).send(data)}}}const workerDtoSchema=z.object({url:z.string().url(),procedureNames:z.array(z.string()).optional(),trustKey:z.string().optional()}).strict().transform((value=>new WorkerDto(value.url,value.procedureNames,value.trustKey)));class WorkerDto{url;procedureNames;trustKey;constructor(url,procedureNames=[],trustKey){this.url=url,this.procedureNames=procedureNames,this.trustKey=trustKey}}class WorkerController{#gateway;#logger;constructor(app,gateway,logger){this.#gateway=gateway,this.#logger=logger,app.get("/workers",((request,response)=>{this.getWorkers(request,response)})),app.post("/workers",((request,response)=>{this.addWorker(request,response)}))}async getWorkers(request,response){const workers=this.#gateway.workers.map((worker=>({url:worker.url,procedureNames:worker.getProcedureNames()})));return this.#logger.info("Got workers"),response.setHeader(Headers.CONTENT_TYPE,ContentTypes.JSON),response.status(200).send(workers)}async addWorker(request,response){try{const workerDto=DataConverter.convert(workerDtoSchema,request.body),worker=new RemoteWorker(workerDto.url);return worker.procedureNames=new Set(workerDto.procedureNames),await this.#gateway.addWorker(worker,workerDto.trustKey),this.#logger.info(`Added worker -> ${worker.url}`),response.status(201).send()}catch(error){if(error instanceof ConversionError){const message=error.message;return this.#logger.warn(`Failed to add worker | ${message}`),response.status(400).type("text").send(message)}const message=error instanceof Error?error.message:"Internal server error";return this.#logger.error(`Failed to add worker | ${message}`),response.status(500).type("text").send(message)}}}class ProceduresController{#runtime;#logger;constructor(app,runtime,logger){this.#runtime=runtime,this.#logger=logger,app.get("/procedures",((request,response)=>{this.getProcedureNames(request,response)}))}async getProcedureNames(request,response){const names=this.#runtime.getProcedureNames();return this.#logger.info("Got procedure names"),response.setHeader(Headers.CONTENT_TYPE,ContentTypes.JSON),response.status(200).send(names)}}class ProxyController{#logger;#repositoryUrl;#runnerUrl;constructor(app,proxy,logger){this.#logger=logger,this.#repositoryUrl=proxy.repository.url??"",this.#runnerUrl=proxy.runner.url??"",app.use("/",expressProxy((message=>this.#selectProxy(message))))}#selectProxy(message){const url=message.url??"";return this.#logger.info(`Forwarding -> ${url}`),url.startsWith("/rpc")?this.#runnerUrl:this.#repositoryUrl}}const RPC_PARAMETERS=["version","serialize"],IGNORED_HEADER_KEYS=["host","connection","content-length","accept-encoding","user-agent","keep-alive"],BAD_REQUEST_NAME=BadRequest.name,UNAUTHORIZED_NAME=Unauthorized.name,PAYMENT_REQUIRED_NAME=PaymentRequired.name,FORBIDDEN_NAME=Forbidden.name,NOT_FOUND_NAME=NotFound.name,TEAPOT_NAME=Teapot.name,NOT_IMPLEMENTED_NAME=NotImplemented.name;class RPCController{#runtime;#serializer;#logger;constructor(app,runtime,serializer,logger){this.#runtime=runtime,this.#serializer=serializer,this.#logger=logger,app.get("/rpc/*",((request,response)=>{this.runGet(request,response)})),app.post("/rpc/*",((request,response)=>{this.runPost(request,response)})),app.options("/rpc/*",((request,response)=>{this.runOptions(request,response)}))}async runGet(request,response){try{const fqn=this.#extractFqn(request),version=this.#extractVersion(request),args=this.#extractQueryArguments(request),headers=this.#extractHeaders(request),serialize=this.#extractSerialize(request);return this.#run(fqn,version,args,headers,response,serialize)}catch(error){const message=error instanceof Error?error.message:String(error);return this.#logger.warn(`Invalid request -> ${message}`),response.status(400).type("text").send(`Invalid request -> ${message}`)}}async runPost(request,response){try{const fqn=this.#extractFqn(request),version=this.#extractVersion(request),args=this.#extractBodyArguments(request),headers=this.#extractHeaders(request),serialize=this.#extractSerialize(request);return this.#run(fqn,version,args,headers,response,serialize)}catch(error){const message=error instanceof Error?error.message:String(error);return this.#logger.warn(`Invalid request -> ${message}`),response.status(400).type("text").send(`Invalid request -> ${message}`)}}async runOptions(request,response){return this.#setCors(response)}#extractFqn(request){const fqn=decodeURIComponent(request.path.trim()).substring(5).trim();if(0===fqn.length)throw new BadRequest("Missing procedure name");if(fqn.includes(".."))throw new BadRequest("Invalid procedure name");return fqn}#extractVersion(request){const version=void 0!==request.query.version?request.query.version:"";if("string"!=typeof version)throw new BadRequest("Invalid version number");return VersionParser.parse(version)}#extractSerialize(request){return"true"===request.query.serialize}#extractQueryArguments(request){const args={};for(const[key,value]of Object.entries(request.query))RPC_PARAMETERS.includes(key)||(args[key]=value);return args}#extractBodyArguments(request){return request.body}#extractHeaders(request){const headers=new Map;for(const[key,value]of Object.entries(request.headers)){if(void 0===value)continue;const lowerKey=key.toLowerCase(),stringValue=value.toString();IGNORED_HEADER_KEYS.includes(lowerKey)||headers.set(lowerKey,stringValue)}return headers}async#run(fqn,version,args,headers,response,serialize){if(!1===this.#runtime.hasProcedure(fqn))return response.setHeader(Headers.CONTENT_TYPE,ContentTypes.TEXT),response.status(404).send(`Procedure not found -> ${fqn}`);try{const deserializedArgs=await this.#serializer.deserialize(args),argsMap=new Map(Object.entries(deserializedArgs)),runtimeRequest=new Request(fqn,version,argsMap,headers),runtimeResponse=await this.#runtime.handle(runtimeRequest);return this.#logger.info(`Ran procedure -> ${fqn} (v${version.toString()})`),this.#setResponseHeaders(response,runtimeResponse.headers),this.#createResultResponse(runtimeResponse.result,response,serialize)}catch(error){const message=error instanceof Error?error.message:String(error),errorData=serialize?error:message;return this.#logger.error(`Failed to run procedure -> ${fqn} (v${version.toString()}) | ${message}`),this.#createErrorResponse(error,errorData,response,serialize)}}async#setCors(response){const cors=this.#runtime.getMiddleware(CorsMiddleware);return void 0===cors||(response.setHeader("Access-Control-Allow-Origin",cors.allowOrigin),response.setHeader("Access-Control-Allow-Methods",cors.allowMethods),response.setHeader("Access-Control-Allow-Headers",cors.allowHeaders),response.setHeader("Access-Control-Max-Age",86400)),response.status(204).send()}async#createResultResponse(result,response,serialize){const content=await this.#createResponseContent(result,serialize),contentType=this.#createResponseContentType(content),responseContent=contentType===ContentTypes.JSON?content:String(content),statusCode=this.#createResponseResultStatusCode(result,response);return response.setHeader(Headers.CONTENT_TYPE,contentType),response.status(statusCode).send(responseContent)}async#createErrorResponse(error,errorData,response,serialize){const content=await this.#createResponseContent(errorData,serialize),contentType=this.#createResponseContentType(content),statusCode=this.#createResponseErrorStatusCode(error);return response.setHeader(Headers.CONTENT_TYPE,contentType),response.status(statusCode).send(content)}async#createResponseContent(data,serialize){return serialize?this.#serializer.serialize(data):data}#createResponseContentType(content){switch(typeof content){case"boolean":return ContentTypes.BOOLEAN;case"number":return ContentTypes.NUMBER;case"object":return ContentTypes.JSON;default:return ContentTypes.TEXT}}#setResponseHeaders(response,headers){for(const[key,value]of headers.entries())void 0!==value&&(IGNORED_HEADER_KEYS.includes(key)||response.set(key,value))}#createResponseResultStatusCode(result,response){return response.hasHeader(Headers.LOCATION)?302:void 0===result?204:200}#createResponseErrorStatusCode(error){if(error instanceof Object==!1)return 500;const errorClass=error.constructor;return this.#isClassType(errorClass,BAD_REQUEST_NAME)?400:this.#isClassType(errorClass,UNAUTHORIZED_NAME)?401:this.#isClassType(errorClass,PAYMENT_REQUIRED_NAME)?402:this.#isClassType(errorClass,FORBIDDEN_NAME)?403:this.#isClassType(errorClass,NOT_FOUND_NAME)?404:this.#isClassType(errorClass,TEAPOT_NAME)?418:this.#isClassType(errorClass,NOT_IMPLEMENTED_NAME)?501:500}#isClassType(clazz,className){if(clazz.name===className)return!0;const parentClass=Object.getPrototypeOf(clazz);return""!==parentClass.name&&this.#isClassType(parentClass,className)}}class RuntimeNotAvailable extends Error{constructor(){super("Runtime is not available")}}class JitarServer{#app;#server;#runtime;#serializer;#classLoader;#options;#configuration;#logger;constructor(){this.#classLoader=new RemoteClassLoader,this.#serializer=SerializerBuilder.build(this.#classLoader),this.#app=express(),this.#app.use(express.json()),this.#app.use(express.urlencoded({extended:!0})),this.#app.use(((request,response,next)=>this.#addDefaultHeaders(request,response,next))),this.#app.disable("x-powered-by"),this.#options=ServerOptionsReader.read(),this.#configuration=RuntimeConfigurationLoader.load(this.#options.config),this.#logger=LogBuilder.build(this.#options.loglevel),this.#printStartupMessage()}get classLoader(){return this.#classLoader}async build(){this.#runtime=await RuntimeConfigurator.configure(this.#configuration),this.#addControllers()}async start(){const url=new URL(this.#configuration.url??RuntimeDefaults.URL);try{await this.#startApplication(),await this.#startServer(url.port)}catch(error){const message=error instanceof Error?error.message:String(error);return this.#logger.error(`Failed to start server -> ${message}`),void await this.stop()}this.#printProcedureInfo(),this.#logger.info(`Server started and listening at port ${url.port}`)}async stop(){try{await this.#stopServer(),await this.#stopApplication()}catch(error){const message=error instanceof Error?error.message:String(error);return void this.#logger.error(`Caught error while stopping server -> ${message}`)}this.#logger.info("Server stopped")}addSerializer(serializer){this.#serializer.addSerializer(serializer)}#getRuntime(){if(void 0===this.#runtime)throw new RuntimeNotAvailable;return this.#runtime}#addControllers(){if(void 0!==this.#configuration.standalone&&this.#runtime instanceof Standalone){const index=this.#configuration.standalone.index??RuntimeDefaults.INDEX;this.#addStandAloneControllers(this.#runtime,index)}else if(void 0!==this.#configuration.repository&&this.#runtime instanceof LocalRepository){const index=this.#configuration.repository.index??RuntimeDefaults.INDEX;this.#addRepositoryControllers(this.#runtime,index)}else void 0!==this.#configuration.gateway&&this.#runtime instanceof LocalGateway?this.#addGatewayControllers(this.#runtime):void 0!==this.#configuration.worker&&this.#runtime instanceof LocalWorker?this.#addWorkerControllers(this.#runtime):void 0!==this.#configuration.proxy&&this.#runtime instanceof Proxy&&this.#addProxyControllers(this.#runtime)}#addStandAloneControllers(standalone,index){new HealthController(this.#app,standalone,this.#logger),new JitarController(this.#app),new ModulesController(this.#app,standalone,this.#serializer,this.#logger),new ProceduresController(this.#app,standalone,this.#logger),new RPCController(this.#app,standalone,this.#serializer,this.#logger),new AssetsController(this.#app,standalone,index,this.#logger)}#addRepositoryControllers(repository,index){new JitarController(this.#app),new ModulesController(this.#app,repository,this.#serializer,this.#logger),new AssetsController(this.#app,repository,index,this.#logger)}#addGatewayControllers(gateway){new WorkerController(this.#app,gateway,this.#logger),new ProceduresController(this.#app,gateway,this.#logger),new RPCController(this.#app,gateway,this.#serializer,this.#logger)}#addWorkerControllers(worker){new HealthController(this.#app,worker,this.#logger),new ProceduresController(this.#app,worker,this.#logger),new RPCController(this.#app,worker,this.#serializer,this.#logger)}#addProxyControllers(proxy){new ProxyController(this.#app,proxy,this.#logger)}async#startApplication(){const runtime=this.#getRuntime();await runtime.start();const setUpScripts=this.#configuration.setUp;if(void 0!==setUpScripts)for(const setUpScript of setUpScripts)await runtime.import(setUpScript,ExecutionScopes.APPLICATION)}async#stopApplication(){const runtime=this.#getRuntime();await runtime.stop();const tearDownScripts=this.#configuration.tearDown;if(void 0!==tearDownScripts)for(const tearDownScript of tearDownScripts)await runtime.import(tearDownScript,ExecutionScopes.APPLICATION)}#startServer(port){return void 0!==this.#server?Promise.resolve():new Promise(((resolve,reject)=>{this.#server=this.#app.listen(port,resolve),this.#server.on("error",reject)}))}#stopServer(){return void 0===this.#server?Promise.resolve():new Promise((resolve=>{this.#server?.close((()=>resolve()))}))}#printStartupMessage(){console.log("\n ██ ██ ████████ █████ ██████ \n ██ ██ ██ ██ ██ ██ ██ \n ██ ██ ██ ███████ ██████ \n ██ ██ ██ ██ ██ ██ ██ ██ \n █████ ██ ██ ██ ██ ██ ██\n ____________________________________\n By Masking Technology (masking.tech)\n")}#printProcedureInfo(){const runtime=this.#getRuntime();if(runtime instanceof LocalWorker==!1&&runtime instanceof Standalone==!1)return;const procedureNames=runtime.getProcedureNames();0!==procedureNames.length&&(procedureNames.sort(),this.#logger.info("Registered RPC entries",procedureNames))}#addDefaultHeaders(request,response,next){response.setHeader(Headers.CONTENT_TYPE_OPTIONS,"nosniff"),next()}}async function buildServer(moduleImporter){ModuleLoader.setImporter(moduleImporter);const server=new JitarServer;return await server.build(),server}export{CorsMiddleware,buildServer};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jitar",
3
- "version": "0.6.0",
3
+ "version": "0.7.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",
@@ -28,7 +28,7 @@
28
28
  "dependencies": {
29
29
  "express": "^4.18.2",
30
30
  "express-http-proxy": "^2.0.0",
31
- "fs-extra": "^11.1.1",
31
+ "fs-extra": "^11.2.0",
32
32
  "glob-promise": "6.0.5",
33
33
  "mime-types": "^2.1.35",
34
34
  "tslog": "^4.9.2",
@@ -36,11 +36,11 @@
36
36
  "zod": "^3.22.4"
37
37
  },
38
38
  "devDependencies": {
39
- "@jitar/runtime": "^0.6.0",
40
- "@jitar/server-nodejs": "^0.6.0"
39
+ "@jitar/runtime": "^0.7.0",
40
+ "@jitar/server-nodejs": "^0.7.0"
41
41
  },
42
42
  "engines": {
43
- "node": ">=18.7"
43
+ "node": ">=20.0"
44
44
  },
45
45
  "repository": {
46
46
  "type": "git",
@@ -60,5 +60,5 @@
60
60
  "full stack",
61
61
  "web applications"
62
62
  ],
63
- "gitHead": "4aca9604744308e313f73e44623dc04989b2f570"
63
+ "gitHead": "8ebca36c9e264c1e0ea27c77557fc8cb6a62ee13"
64
64
  }
@@ -1 +0,0 @@
1
- const AccessLevels={PRIVATE:"private",PUBLIC:"public"};Object.freeze(AccessLevels);const Files={MODULE_PATTERN:"**/*.js",SEGMENT_PATTERN:"**/*.segment.json",NODE_SEGMENT_PATTERN:"**/*.segment.node.js",REPOSITORY_SEGMENT_PATTERN:"**/*.segment.repository.js"};Object.freeze(Files);const EXTENSION_PATTERN=/\.js$/;function convertToLocalFilename(filename){return filename.replace(EXTENSION_PATTERN,".local.js")}function convertToRemoteFilename(filename){return filename.replace(EXTENSION_PATTERN,".remote.js")}function createNodeFilename(name){return`./${name}.segment.node.js`}function createRepositoryFilename(name){return`./${name}.segment.repository.js`}function isSegmentFilename(filename){return filename.includes(".segment.")}const ExecutionScopes={APPLICATION:"application",RUNTIME:"runtime"};Object.freeze(ExecutionScopes);class BadRequest extends Error{constructor(message="Invalid request"){super(message)}}BadRequest.source="/jitar/client.js";class Forbidden extends Error{constructor(message="Forbidden"){super(message)}}Forbidden.source="/jitar/client.js";class NotFound extends Error{constructor(message="Not found"){super(message)}}NotFound.source="/jitar/client.js";class NotImplemented extends Error{constructor(message="Not implemented"){super(message)}}NotImplemented.source="/jitar/client.js";class PaymentRequired extends Error{constructor(message="Payment required"){super(message)}}PaymentRequired.source="/jitar/client.js";class ServerError extends Error{constructor(message="Server error"){super(message)}}ServerError.source="/jitar/client.js";class Teapot extends Error{constructor(){super("I'm a teapot")}}Teapot.source="/jitar/client.js";class Unauthorized extends Error{constructor(message="Unauthorized"){super(message)}}Unauthorized.source="/jitar/client.js";class ClientNotFound extends BadRequest{#clientId;constructor(clientId){super(`Client not found for id '${clientId}'`),this.#clientId=clientId}get clientId(){return this.#clientId}}ClientNotFound.source="/jitar/client.js";class FileNotFound extends NotFound{#filename;constructor(filename){super(`The file '${filename}' could not be found`),this.#filename=filename}get filename(){return this.#filename}}FileNotFound.source="/jitar/client.js";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}}ImplementationNotFound.source="/jitar/client.js";class InvalidClientId extends BadRequest{#clientId;constructor(clientId){super(`Invalid client id '${clientId}'`),this.#clientId=clientId}get clientId(){return this.#clientId}}InvalidClientId.source="/jitar/client.js";class InvalidParameterValue extends BadRequest{#parameterName;constructor(parameterName){super(`Invalid value for parameter '${parameterName}'`),this.#parameterName=parameterName}get parameterName(){return this.#parameterName}}InvalidParameterValue.source="/jitar/client.js";class InvalidSegmentFile extends ServerError{#filename;constructor(filename){super(`Missing files array in segment file '${filename}'`),this.#filename=filename}get filename(){return this.#filename}}InvalidSegmentFile.source="/jitar/client.js";class InvalidVersionNumber extends BadRequest{#number;constructor(number){super(`Invalid version number '${number}'`),this.#number=number}get number(){return this.#number}}InvalidVersionNumber.source="/jitar/client.js";class MissingParameterValue extends BadRequest{#parameterName;constructor(parameterName){super(`Missing value for parameter '${parameterName}'`),this.#parameterName=parameterName}get parameterName(){return this.#parameterName}}MissingParameterValue.source="/jitar/client.js";class ModuleNotAccessible extends Forbidden{#url;constructor(url){super(`Module '${url}' is not accessible`),this.#url=url}get url(){return this.#url}}ModuleNotAccessible.source="/jitar/client.js";class ModuleNotLoaded extends ServerError{#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}}ModuleNotLoaded.source="/jitar/client.js";class NoNodeAvailable extends ServerError{#name;constructor(name){super(`No node available for procedure '${name}'`),this.#name=name}get name(){return this.#name}}NoNodeAvailable.source="/jitar/client.js";class ProcedureNotAccessible extends Forbidden{#fqn;#versionNumber;constructor(fqn,versionNumber){super(`Procedure '${fqn}' (v${versionNumber}) is not accessible`),this.#fqn=fqn,this.#versionNumber=versionNumber}get fqn(){return this.#fqn}get versionNumber(){return this.#versionNumber}}ProcedureNotAccessible.source="/jitar/client.js";class ProcedureNotFound extends NotFound{#fqn;constructor(fqn){super(`Procedure '${fqn}' not found`),this.#fqn=fqn}get fqn(){return this.#fqn}}ProcedureNotFound.source="/jitar/client.js";class RepositoryNotAvailable extends ServerError{constructor(){super("Repository not available")}}RepositoryNotAvailable.source="/jitar/client.js";class RuntimeNotAvailable extends ServerError{constructor(){super("Runtime not available")}}RuntimeNotAvailable.source="/jitar/client.js";class SegmentNotFound extends ServerError{#source;constructor(source){super(`Segment found for '${source}'`),this.#source=source}get source(){return this.#source}}SegmentNotFound.source="/jitar/client.js";class UnknownParameter extends BadRequest{#parameterName;constructor(parameterName){super(`Unknown parameter ${parameterName}`),this.#parameterName=parameterName}get parameterName(){return this.#parameterName}}UnknownParameter.source="/jitar/client.js";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 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 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 NamedParameter extends Parameter{}class ObjectParameter extends DestructuredParameter{}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 Request{#fqn;#version;#args;#headers=new Map;constructor(fqn,version,args,headers){this.#fqn=fqn,this.#version=version,this.#args=args,this.#headers=headers}get fqn(){return this.#fqn}get version(){return this.#version}get args(){return this.#args}get headers(){return this.#headers}setArgument(name,value){this.#args.set(name,value)}getArgument(name){return this.#args.get(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())}removeHeader(name){this.#headers.delete(name.toLowerCase())}}class Response{#result;#headers;constructor(result=void 0,headers=new Map){this.#result=result,this.#headers=headers}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())}removeHeader(name){this.#headers.delete(name.toLowerCase())}}class InvalidMiddleware extends ServerError{#url;constructor(url){super(`Module '${url}' does not export valid middleware`),this.#url=url}get url(){return this.#url}}InvalidMiddleware.source="/jitar/client.js";class ProcedureRunner{#runner;constructor(runner){this.#runner=runner}async handle(request,next){return this.#runner.run(request)}}class InvalidHealthCheck extends ServerError{#url;constructor(url){super(`Module '${url}' does not export a valid health check`),this.#url=url}get url(){return this.#url}}InvalidHealthCheck.source="/jitar/client.js";class Runtime{#url;#healthCheckFiles=new Set;#healthChecks=new Map;constructor(url){this.#url=url}get url(){return this.#url}set healthCheckFiles(filenames){this.#healthCheckFiles=filenames}start(){return this.#importHealthChecks()}async stop(){this.#clearHealthChecks()}addHealthCheck(healthCheck){this.#healthChecks.set(healthCheck.name,healthCheck)}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=>{"fulfilled"===result.status?healthChecks.set(result.value.name,result.value.isHealthy):healthChecks.set(result.reason.name,!1)})))).then((()=>healthChecks))}async#importHealthChecks(){for(const filename of this.#healthCheckFiles)await this.#importHealthCheck(filename)}async#importHealthCheck(url){const healthCheck=(await this.import(url,ExecutionScopes.APPLICATION)).default;if(void 0===healthCheck?.isHealthy)throw new InvalidHealthCheck(url);this.addHealthCheck(healthCheck)}#clearHealthChecks(){this.#healthChecks.clear()}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])}}class ProcedureRuntime extends Runtime{#repository;#middlewareFiles=new Set;#middlewares=[];constructor(repository,url){super(url),this.#repository=repository,this.#middlewares.push(new ProcedureRunner(this))}get repository(){return this.#repository}set middlewareFiles(filenames){this.#middlewareFiles=filenames}async start(){await this.#repository.start(),await super.start(),await this.#importMiddlewares()}async stop(){this.#clearMiddlewares(),await this.#repository.stop(),await super.stop()}import(url,scope){return this.#repository.import(url,scope)}addMiddleware(middleware){const index=this.#middlewares.length-1;this.#middlewares.splice(index,0,middleware)}getMiddleware(type){return this.#middlewares.find((middleware=>middleware instanceof type))}handle(request){return this.#getNextHandler(request,0)()}#getNextHandler(request,index){const next=this.#middlewares[index];if(void 0===next)return async()=>new Response;const nextHandler=this.#getNextHandler(request,index+1);return async()=>next.handle(request,nextHandler)}async#importMiddlewares(){for(const url of this.#middlewareFiles)await this.#importMiddleware(url)}async#importMiddleware(url){const middleware=(await this.import(url,ExecutionScopes.APPLICATION)).default;if(void 0===middleware?.handle)throw new InvalidMiddleware(url);this.addMiddleware(middleware)}#clearMiddlewares(){this.#middlewares=[]}}class Gateway extends ProcedureRuntime{}class ArgumentExtractor{extract(parameters,args){const argsCopy=new Map(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}#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 Node extends ProcedureRuntime{}const VERSION_EXPRESSION=/^\d+(?:\.\d+){0,2}$/;class VersionParser{static 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]))}}}const RUNS_IN_BROWSER="undefined"!=typeof window;let _runtime;function getRuntime(){if(void 0===_runtime)throw new RuntimeNotAvailable;return _runtime}class LocalNode extends Node{#gateway;#argumentConstructor;#segmentNames=new Set;#segments=new Map;constructor(repository,gateway,url,argumentConstructor=new ArgumentExtractor){super(repository,url),this.#gateway=gateway,this.#argumentConstructor=argumentConstructor,_runtime=this}set segmentNames(names){this.#segmentNames=names}async start(){await super.start(),await this.#loadSegments(),void 0!==this.#gateway&&await this.#gateway.start()}async stop(){this.#unloadSegments(),void 0!==this.#gateway&&await this.#gateway.stop(),await super.stop()}getProcedureNames(){const names=new Set;for(const segment of this.#segments.values()){segment.getPublicProcedures().forEach((procedure=>names.add(procedure.fqn)))}return[...names.values()]}addSegment(segment){this.#segments.set(segment.id,segment)}hasProcedure(fqn){return this.getProcedureNames().includes(fqn)}run(request){const procedure=this.#getProcedure(request.fqn);return void 0===procedure?this.#useGateway(request):this.#runProcedure(procedure,request)}async#loadSegments(){for(const segmentName of this.#segmentNames)await this.#loadSegment(segmentName)}async#loadSegment(name){const filename=createNodeFilename(name),segment=(await this.import(filename,ExecutionScopes.APPLICATION)).segment;this.addSegment(segment)}#unloadSegments(){this.#segments.clear()}#useGateway(request){if(void 0===this.#gateway)throw new ProcedureNotFound(request.fqn);return this.#gateway.run(request)}async#runProcedure(procedure,request){const implementation=procedure.getImplementation(request.version);if(void 0===implementation)throw new ImplementationNotFound(procedure.fqn,request.version.toString());const values=this.#argumentConstructor.extract(implementation.parameters,request.args),result=await implementation.executable.call(request,...values);return new Response(result)}#getProcedure(fqn){for(const segment of this.#segments.values())if(segment.hasProcedure(fqn))return segment.getProcedure(fqn)}}class UrlRewriter{static addBase(url,base){if(url.startsWith(base))return url;const parts=`${base}/${url}`.split("://"),protocol=parts.length>1?`${parts[0]}://`:"",address=parts.length>1?parts[1]:parts[0];return`${protocol}${this.#translateAddress(address)}`}static removeBase(url,base){return!1===url.startsWith(base)?url:url.substring(base.length)}static#translateAddress(address){const parts=address.split("/"),translated=[];translated.push(parts[0]);for(let index=1;index<parts.length;index++){const part=parts[index].trim();switch(part){case"":case".":continue;case"..":translated.pop();continue}translated.push(part)}return translated.join("/")}}const APPLICATION_MODULE_INDICATORS=[".","/","http:","https:"];let _baseUrl="",_import=async name=>import(name);class ModuleLoader{static setBaseUrl(baseUrl){_baseUrl=baseUrl}static setImporter(importer){_import=importer}static async load(specifier){if(this.#isSystemModule(specifier))return this.#import(specifier);if(specifier.startsWith("/jitar"))return this.#import("jitar");const filename=this.assureExtension(specifier),url=UrlRewriter.addBase(filename,_baseUrl);if(!1===url.startsWith(_baseUrl))throw new ModuleNotAccessible(specifier);return this.#import(url)}static assureExtension(specifier){return specifier.endsWith(".js")?specifier:`${specifier}.js`}static#isSystemModule(specifier){return!1===APPLICATION_MODULE_INDICATORS.some((indicator=>specifier.startsWith(indicator)))}static async#import(specifier){try{return await _import(specifier)}catch(error){const safeUrl=UrlRewriter.removeBase(specifier,_baseUrl),message=error instanceof Error?error.message:String(error);throw new ModuleNotLoaded(safeUrl,message)}}}class Repository extends Runtime{async import(url,scope){return scope===ExecutionScopes.RUNTIME?ModuleLoader.load(url):this.loadModule(url)}}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(error){throw new InvalidBigIntString(object.value)}}}class ReflectionAlias{#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 ReflectionValue{#definition;constructor(definition){this.#definition=definition}get definition(){return this.#definition}toString(){return this.#definition}}class ReflectionArray extends ReflectionValue{}class ReflectionMember{#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 ReflectionClass extends ReflectionMember{#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 void 0!==declaration&&declaration.isPublic||this.hasGetter(name)}canWrite(name){const declaration=this.getDeclaration(name);return void 0!==declaration&&declaration.isPublic||this.hasSetter(name)}canCall(name){const funktion=this.getFunction(name);return void 0!==funktion&&funktion.isPublic}toString(){const infix=void 0!==this.#parentName?` extends ${this.#parentName}`:"";return`class ${this.name}${infix} { ${this.#scope.toString()} }`}}class ReflectionDeclaration extends ReflectionMember{#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 ReflectionDestructuredValue{#members;constructor(members){this.#members=members}get members(){return this.#members}toString(){return this.#members.map((member=>member.toString())).join(" , ")}}class ReflectionDestructuredArray extends ReflectionDestructuredValue{toString(){return`[ ${super.toString()} ]`}}class ReflectionDestructuredObject extends ReflectionDestructuredValue{toString(){return`{ ${super.toString()} }`}}class ReflectionExport extends ReflectionMember{#members;#from;constructor(members,from){super(""),this.#members=members,this.#from=from}get members(){return this.#members}get from(){return this.#from}toString(){const postfix=this.#from?` from '${this.#from}'`:"";return`export { ${this.#members.join(", ")} }${postfix}`}}class ReflectionExpression extends ReflectionValue{}class ReflectionField{#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 ReflectionFunction extends ReflectionMember{#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 ReflectionGenerator extends ReflectionFunction{toString(){const parameters=this.parameters.map((parameter=>parameter.toString()));return`${this.isAsync?"async ":""}${this.name}*(${parameters.join(", ")}) { ${this.body} }`}}class ReflectionGetter extends ReflectionFunction{toString(){return`get ${super.toString()}`}}class ReflectionImport extends ReflectionMember{#members;#from;constructor(members,from){super(""),this.#members=members,this.#from=from}get members(){return this.#members}get from(){return this.#from}toString(){return`import { ${this.#members.map((member=>member.toString())).join(", ")} } from '${this.#from}';`}}class ReflectionModule{#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)}isExported(member){for(const exportItem of this.exports)for(const alias of exportItem.members)if(alias.name===member.name)return!0;return!1}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 ReflectionObject extends ReflectionValue{}class ReflectionSetter extends ReflectionFunction{toString(){return`set ${super.toString()}`}}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{}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 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}`)}}const IMPORT_NAME=ReflectionImport.name,EXPORT_NAME=ReflectionExport.name,DECLARATION_NAME=ReflectionDeclaration.name,FUNCTION_NAME=ReflectionFunction.name,GETTER_NAME=ReflectionGetter.name,SETTER_NAME=ReflectionSetter.name,GENERATOR_NAME=ReflectionGenerator.name,CLASS_NAME=ReflectionClass.name;class ReflectionScope{#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")}}class Parser{#lexer;constructor(lexer=new Lexer){this.#lexer=lexer}parse(code){const tokenList=this.#lexer.tokenize(code),scope=this.#parseScope(tokenList);return new ReflectionModule(scope)}parseFirst(code){const tokenList=this.#lexer.tokenize(code);return this.#parseNext(tokenList)}parseValue(code){const model=this.parseFirst(code);if(model instanceof ReflectionValue==!1)throw new UnexpectedParseResult("a value definition");return model}parseImport(code){const model=this.parseFirst(code);if(model instanceof ReflectionImport==!1)throw new UnexpectedParseResult("an import definition");return model}parseExport(code){const model=this.parseFirst(code);if(model instanceof ReflectionExport==!1)throw new UnexpectedParseResult("an export definition");return model}parseDeclaration(code){const model=this.parseFirst(code);if(model instanceof ReflectionDeclaration==!1)throw new UnexpectedParseResult("a declaration definition");return model}parseFunction(code){const tokenList=this.#lexer.tokenize(code),model=this.#parseMember(tokenList);if(model instanceof ReflectionFunction==!1)throw new UnexpectedParseResult("a function definition");return model}parseClass(code){const tokenList=this.#lexer.tokenize(code),model=this.#parseMember(tokenList);if(model instanceof ReflectionClass==!1)throw new UnexpectedParseResult("a class definition");return model}#parseScope(tokenList){const members=[];for(;tokenList.notAtEnd();){const member=this.#parseNext(tokenList);member instanceof ReflectionMember&&members.push(member)}return new ReflectionScope(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 void 0!==next&&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 void 0!==next&&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 ReflectionImport(members,token.value);if(token.hasValue(Group.OPEN)){token=tokenList.step();const from=token.value;return tokenList.step(2),new ReflectionImport(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 ReflectionAlias(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 ReflectionImport(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(),void 0!==token&&token.hasValue(Keyword.FROM)&&(token=tokenList.step(),from=token.value),stepSize>0&&(stepSize++,tokenList.stepBack(stepSize));const alias=new ReflectionAlias(name,as);return new ReflectionExport([alias],from)}#parseMultiExport(tokenList){const members=this.#parseAliasList(tokenList);let from,token=tokenList.current;return void 0!==token&&token.hasValue(Keyword.FROM)&&(token=tokenList.step(),from=token.value),tokenList.step(),new ReflectionExport(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 ReflectionAlias(name,as)}#parseDeclaration(tokenList,isStatic,parseMultiple=!1){let value,token=tokenList.current,identifier="",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 ReflectionGenerator?new ReflectionGenerator(identifier.toString(),value.parameters,value.body,isStatic,value.isAsync,isPrivate):value instanceof ReflectionFunction?new ReflectionFunction(identifier.toString(),value.parameters,value.body,isStatic,value.isAsync,isPrivate):value instanceof ReflectionClass?new ReflectionClass(identifier.toString(),value.parentName,value.scope):new ReflectionDeclaration(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 ReflectionGenerator(name,parameters,body,isStatic,isAsync,isPrivate):isGetter?new ReflectionGetter(name,parameters,body,isStatic,isAsync,isPrivate):isSetter?new ReflectionSetter(name,parameters,body,isStatic,isAsync,isPrivate):new ReflectionFunction(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 ReflectionField(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 ReflectionFunction("",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 ReflectionClass(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 ReflectionScope(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 ReflectionArray(items)}#parseDestructuredArray(tokenList){const fields=this.#parseParameters(tokenList,List.CLOSE);return new ReflectionDestructuredArray(fields)}#parseObject(tokenList){const fields=this.#parseBlock(tokenList,Scope.OPEN,Scope.CLOSE);return new ReflectionObject(fields)}#parseDestructuredObject(tokenList){const fields=this.#parseParameters(tokenList,Scope.CLOSE);return new ReflectionDestructuredObject(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 ReflectionField(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 ReflectionExpression(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 ReflectionClass(model.name,parent.name,new ReflectionScope(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;#merger;constructor(parser=new Parser,merger=new ClassMerger){this.#parser=parser,this.#merger=merger}parse(code){return this.#parser.parse(code)}parseClass(code){return this.#parser.parseClass(code)}parseFunction(code){return this.#parser.parseFunction(code)}parseDeclaration(code){return this.#parser.parseDeclaration(code)}parseImport(code){return this.#parser.parseImport(code)}parseExport(code){return this.#parser.parseExport(code)}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 ReflectionExpression(code);members.push(new ReflectionDeclaration(key,expression))}}return new ReflectionModule(new ReflectionScope(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.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.parseClass(code)}#reflectDynamic(clazz){const object=this.createInstance(clazz),members=this.#getMembers(clazz,object),scope=new ReflectionScope(members);return new ReflectionClass(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 ReflectionValue(String(content)):void 0,model=new ReflectionDeclaration(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 ReflectionGetter(model.name,model.parameters,model.body,model.isStatic,model.isAsync,model.isPrivate)):void 0!==description.set?models.push(new ReflectionSetter(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{#classLoader;constructor(classLoader){super(),this.#classLoader=classLoader}canSerialize(value){return value instanceof Object&&reflector$1.isClassObject(value)}canDeserialize(value){const object=value;return object instanceof Object&&!0===object.serialized&&"string"==typeof object.name&&object.args instanceof Array&&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.#extractParameterNames(model);return{serialized:!0,name:clazz.name,source:clazz.source,args:await this.#extractArguments(model,parameterNames,object),fields:await this.#extractFields(model,parameterNames,object)}}#extractParameterNames(model){const constructor=model.getFunction("constructor");return(constructor?.parameters??[]).map((parameter=>parameter.name))}async#extractArguments(model,includeNames,object){const args=[];for(const name of includeNames){const objectValue=model.canRead(name)?await this.serializeOther(object[name]):void 0;args.push(objectValue)}return args}async#extractFields(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.name);if(clazz instanceof Function==!1)throw new InvalidClass(object.name);const args=await Promise.all(object.args.map((async value=>this.deserializeOther(value)))),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#getClass(clazz){return void 0===clazz.source?globalThis[clazz.name]:this.#classLoader.loadClass(clazz)}}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]);return error.stack=object.stack,error.message=object.message,error.cause=object.cause,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(error){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(error){throw new InvalidUrlString(object.value)}}}const defaultClassLoader=new class{async loadClass(loadable){if("string"!=typeof loadable.source)throw new ClassNotFound(loadable.name);const module=await import(loadable.source),clazz=module[loadable.name]??module.default;if(void 0===clazz)throw new ClassNotFound(loadable.name);if(clazz instanceof Function==!1)throw new InvalidClass(loadable.name);return clazz}};class SerializerBuilder{static build(loader=defaultClassLoader){const serializer=new Serializer;return serializer.addSerializer(new PrimitiveSerializer),serializer.addSerializer(new ObjectSerializer),serializer.addSerializer(new ClassSerializer(loader)),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),serializer}}class RemoteClassLoader{async loadClass(loadable){if("string"!=typeof loadable.source)throw new ClassNotFound(loadable.name);const module=await ModuleLoader.load(loadable.source),clazz=module[loadable.name]??module.default;if(void 0===clazz)throw new ClassNotFound(loadable.name);if(clazz instanceof Function==!1)throw new InvalidClass(loadable.name);return clazz}}const remoteClassLoader=new RemoteClassLoader,defaultSerializer=SerializerBuilder.build(remoteClassLoader);class Remote{#url;#serializer;constructor(url,serializer=defaultSerializer){this.#url=url,this.#serializer=serializer}async registerClient(segmentFiles){const url=`${this.#url}/modules`,options={method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(segmentFiles)};return(await this.#callRemote(url,options,200)).text()}async loadFile(filename){const url=`${this.#url}/${filename}`,response=await this.#callRemote(url,{method:"GET"},200),type=response.headers.get("Content-Type")||"application/octet-stream",content=await response.text();return new File(filename,type,content)}async isHealthy(){const url=`${this.#url}/health/status`,response=await this.#callRemote(url,{method:"GET"},200),healthy=await response.text();return Boolean(healthy)}async getHealth(){const url=`${this.#url}/health`,response=await this.#callRemote(url,{method:"GET"},200),health=await response.json();return new Map(Object.entries(health))}async addNode(node){const url=`${this.#url}/nodes`,body={url:node.url,procedureNames:node.getProcedureNames()},options={method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(body)};await this.#callRemote(url,options,201)}async run(request){request.setHeader("content-type","application/json");const versionString=request.version.toString(),argsObject=Object.fromEntries(request.args),headersObject=Object.fromEntries(request.headers),url=`${this.#url}/rpc/${request.fqn}?version=${versionString}&serialize=true`,options={method:"POST",headers:headersObject,body:await this.#createRequestBody(argsObject)},response=await this.#callRemote(url,options,200),result=await this.#createResponseResult(response),headers=this.#createResponseHeaders(response);return new Response(result,headers)}async#callRemote(url,options,expectedStatus){const response=await fetch(url,options);if(response.status!==expectedStatus)throw await this.#createResponseResult(response);return response}async#createRequestBody(body){const data=await this.#serializer.serialize(body);return JSON.stringify(data)}async#createResponseResult(response){const result=await this.#getResponseResult(response);return this.#serializer.deserialize(result)}#getResponseResult(response){const contentType=response.headers.get("Content-Type");return null!==contentType&&contentType.includes("json")?response.json():response.text()}#createResponseHeaders(response){const headers=new Map;for(const[name,value]of response.headers)headers.set(name,value);return headers}}class DummyRepository extends Repository{async start(){}async stop(){}async registerClient(segmentFiles){throw new RepositoryNotAvailable}async readAsset(filename){throw new RepositoryNotAvailable}async readModule(filename,clientId){throw new RepositoryNotAvailable}async loadModule(filename){throw new RepositoryNotAvailable}}class RemoteGateway extends Gateway{#remote;#node;constructor(url){super(new DummyRepository,url),this.#remote=new Remote(url)}get node(){return this.#node}set node(node){this.#node=node}async start(){await super.start(),void 0!==this.#node&&await this.addNode(this.#node)}getProcedureNames(){throw new NotImplemented}hasProcedure(name){throw new NotImplemented}addNode(node){return this.#remote.addNode(node)}run(request){return this.#remote.run(request)}}class RemoteRepository extends Repository{#remote;#segmentNames=new Set;constructor(url){super(url),this.#remote=new Remote(url)}get segmentNames(){return[...this.#segmentNames.values()]}set segmentNames(segmentNames){this.#segmentNames=segmentNames}async start(){const clientId=await this.registerClient(this.segmentNames),baseUrl=this.#getModuleBaseUrl(clientId);ModuleLoader.setBaseUrl(baseUrl),await super.start()}registerClient(segmentFiles){return this.#remote.registerClient(segmentFiles)}readAsset(filename){return this.#remote.loadFile(filename)}readModule(filename,clientId){return this.#remote.loadFile(`modules/${clientId}/${filename}`)}loadModule(filename){return ModuleLoader.load(filename)}#getModuleBaseUrl(clientId){return`${this.url}/modules/${clientId}`}}class RuntimeNotBuilt extends ServerError{constructor(reason){super(`Building the runtime failed: ${reason}`)}}RuntimeNotBuilt.source="/jitar/client.js";const globals=globalThis;globals.__import=async function(name,scope,extractDefault=!0){const runtime=getRuntime();RUNS_IN_BROWSER&&"jitar"===name&&(name="/jitar/client.js");const module=await runtime.import(name,scope);return extractDefault&&void 0!==module.default?module.default:module},globals.__run=async function(fqn,versionNumber,args,sourceRequest){const runtime=getRuntime(),version=VersionParser.parse(versionNumber),argsMap=new Map(Object.entries(args)),headersMap=sourceRequest instanceof Request?sourceRequest.headers:new Map,targetRequest=new Request(fqn,version,argsMap,headersMap);return(await runtime.handle(targetRequest)).result},globals.ProcedureNotAccessible=ProcedureNotAccessible;export{ModuleNotAccessible as $,AccessLevels as A,BadRequest as B,ClientNotFound as C,DummyRepository as D,ExecutionScopes as E,FileNotFound as F,Gateway as G,Version as H,InvalidSegmentFile as I,Response as J,NamedParameter as K,LocalNode as L,ModuleLoader as M,NoNodeAvailable as N,ArrayParameter as O,ProcedureNotFound as P,ObjectParameter as Q,Repository as R,SerializerBuilder as S,Teapot as T,Unauthorized as U,VersionParser as V,ServerError as W,ImplementationNotFound as X,InvalidParameterValue as Y,InvalidVersionNumber as Z,MissingParameterValue as _,InvalidClientId as a,ModuleNotLoaded as a0,ProcedureNotAccessible as a1,RepositoryNotAvailable as a2,RuntimeNotAvailable as a3,SegmentNotFound as a4,UnknownParameter as a5,File as b,convertToRemoteFilename as c,convertToLocalFilename as d,createRepositoryFilename as e,ProcedureRuntime as f,Node as g,Remote as h,isSegmentFilename as i,RemoteRepository as j,RemoteGateway as k,RuntimeNotBuilt as l,Reflector as m,ReflectionField as n,ReflectionDestructuredArray as o,ReflectionDestructuredObject as p,ReflectionDestructuredValue as q,createNodeFilename as r,ReflectionFunction as s,Files as t,PaymentRequired as u,Forbidden as v,NotFound as w,NotImplemented as x,Request as y,RemoteClassLoader as z};