jitar 0.4.0 → 0.4.2
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/LICENCE +23 -0
- package/dist/client.js +1 -1
- package/dist/globals-a24096f0.js +1 -0
- package/dist/lib.d.ts +34 -3
- package/dist/server.js +1 -1
- package/package.json +20 -11
- package/dist/globals-d516de70.js +0 -1
package/LICENCE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
|
|
2
|
+
(The MIT License)
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2023 Masking Technology B.V. <https://masking.tech>
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
7
|
+
a copy of this software and associated documentation files (the
|
|
8
|
+
'Software'), to deal in the Software without restriction, including
|
|
9
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
10
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
11
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
12
|
+
the following conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be
|
|
15
|
+
included in all copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
|
18
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
19
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
20
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
21
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
22
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
23
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/dist/client.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{A as AccessLevel,
|
|
1
|
+
import{A as AccessLevel,w as Version,p as LocalNode,r as RemoteGateway,q as RemoteRepository}from"./globals-a24096f0.js";export{z as ArrayParameter,B as BadRequest,C as ClientNotFound,F as FileNotFound,t as Forbidden,E as ImplementationNotFound,a as InvalidClientId,G as InvalidParameterValue,I as InvalidSegmentFile,H as InvalidVersionNumber,J as MissingParameterValue,K as ModuleNotAccessible,Q as ModuleNotLoaded,y as NamedParameter,W as NoNodeAvailable,u as NotFound,v as NotImplemented,O as ObjectParameter,s as PaymentRequired,X as ProcedureNotAccessible,Y as ProcedureNotFound,Z as RepositoryNotAvailable,_ as RuntimeNotAvailable,$ as SegmentNotFound,D as ServerError,T as Teapot,U as Unauthorized,a0 as UnknownParameter}from"./globals-a24096f0.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===AccessLevel.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=[]){const node=new LocalNode,gateway=new RemoteGateway(remoteUrl),repository=new RemoteRepository(remoteUrl);return await node.setGateway(gateway),await node.setRepository(repository,segmentNames),client=node,resolvers.forEach((resolve=>resolve(node))),node}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 AccessLevel={PRIVATE:"private",PUBLIC:"public"};Object.freeze(AccessLevel);const AccessLevels=Object.values(AccessLevel);Object.freeze(AccessLevels);const Files={MODULE_PATTERN:"**/*.js",SEGMENT_PATTERN:"**/*.segment.json",NODE_SEGMENT_PATTERN:"**/*.segment.node.js",REPOSITORY_SEGMENT_PATTERN:"**/*.segment.repository.js"};function convertToLocalFilename(filename){return filename.replace(".js",".local.js")}function convertToRemoteFilename(filename){return filename.replace(".js",".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.")}Object.freeze(Files);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 Runtime{#url;#healthChecks=new Map;constructor(url){this.#url=url}get url(){return this.#url}addHealthCheck(name,healthCheck){this.#healthChecks.set(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#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 ProcedureRunner{#runner;constructor(runner){this.#runner=runner}async handle(fqn,version,args,headers,next){const result=await this.#runner.run(fqn,version,args,headers);return headers.clear(),result}}class ProcedureRuntime extends Runtime{#middlewares=[];constructor(url){super(url),this.#middlewares.push(new ProcedureRunner(this))}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(fqn,version,args,headers){return this.#getNextHandler(fqn,version,args,headers,0)()}#getNextHandler(fqn,version,args,headers,index){const next=this.#middlewares[index];if(void 0===next)return async()=>{};const nextHandler=this.#getNextHandler(fqn,version,args,headers,index+1);return async()=>next.handle(fqn,version,args,headers,nextHandler)}}class Gateway extends ProcedureRuntime{}class UrlRewriter{static addBase(url,base){return url=this.#ensureStartsWithoutSlash(url),base=this.#assureEndWithSlash(base),this.#translateRelativeParts(`${base}${url}`)}static#ensureStartsWithoutSlash(url){return url.startsWith("/")?url.substring(1):url}static#assureEndWithSlash(base){return base.endsWith("/")?base:`${base}/`}static#translateRelativeParts(url){const parts=url.split("/"),translated=[];translated.push(parts[0]);for(let index=1;index<parts.length;index++){const part=parts[index].trim();"."!==part&&(".."!==part?translated.push(part):translated.pop())}return translated.join("/")}}const NON_SYSTEM_INDICATORS=[".","/","http:","https:"];let _baseUrl,_import=async name=>import(name);class ModuleLoader{static setBaseUrl(baseUrl){_baseUrl=baseUrl}static setImporter(importer){_import=importer}static assureExtension(specifier){return this.#isSystemModule(specifier)||specifier.endsWith(".js")?specifier:`${specifier}.js`}static async load(specifier){let url=this.assureExtension(specifier);if(url.startsWith("/jitar"))return specifier="jitar",this.#import(specifier,specifier);if(void 0!==_baseUrl&&!1===url.startsWith(_baseUrl)&&(url=UrlRewriter.addBase(url,_baseUrl),!1===url.startsWith(_baseUrl)))throw new ModuleNotAccessible(specifier);return this.#import(url,specifier)}static async import(specifier){return this.#import(specifier,specifier)}static async#import(absolute,relative){try{return await _import(absolute)}catch(error){const message=error instanceof Error?error.message:String(error);throw new ModuleNotLoaded(relative,message)}}static#isSystemModule(specifier){return!1===NON_SYSTEM_INDICATORS.some((indicator=>specifier.startsWith(indicator)))}}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(fqn,version,args,headers){const node=this.getNextNode();if(void 0===node)throw new NoNodeAvailable(fqn);return node.run(fqn,version,args,headers)}}const NO_SEGMENTS=[];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)}}async setBaseUrl(repository){const clientId=await repository.registerClient(NO_SEGMENTS),moduleLocation=await repository.getModuleLocation(clientId);ModuleLoader.setBaseUrl(moduleLocation)}#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(fqn,version,args,headers){const balancer=this.#getBalancer(fqn);if(void 0===balancer)throw new ProcedureNotFound(fqn);return balancer.run(fqn,version,args,headers)}}class Context{#headers=new Map;constructor(headers){this.#headers=headers}get headers(){return this.#headers}}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 RUNS_IN_BROWSER="undefined"!=typeof window;let _runtime,_loader=name=>ModuleLoader.import(name);class VersionParser{static parse(number){if(0===number.trim().length)return Version.DEFAULT;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]));case 3:return new Version(Number.parseInt(parts[0]),Number.parseInt(parts[1]),Number.parseInt(parts[2]));default:throw new InvalidVersionNumber(number)}}}class LocalNode extends Node{#argumentConstructor;#segments=new Map;#gateway;#repository;#clientId="";constructor(url,argumentConstructor=new ArgumentExtractor){super(url),this.#argumentConstructor=argumentConstructor}getProcedureNames(){const names=new Set;for(const segment of this.#segments.values()){segment.getPublicProcedures().forEach((procedure=>names.add(procedure.fqn)))}return[...names.values()]}async loadSegment(name){const filename=createNodeFilename(name),segment=(await this.import(filename)).segment;this.addSegment(segment)}addSegment(segment){this.#segments.set(segment.id,segment)}hasProcedure(fqn){return this.getProcedureNames().includes(fqn)}#getProcedure(fqn){for(const segment of this.#segments.values())if(segment.hasProcedure(fqn))return segment.getProcedure(fqn)}async setGateway(gateway){(gateway instanceof LocalGateway||void 0!==this.url)&&await gateway.addNode(this),this.#gateway=gateway}async setRepository(repository,segmentNames){this.#clientId=await repository.registerClient(segmentNames),_runtime=this,_loader=name=>ModuleLoader.import(name);const moduleLocation=await repository.getModuleLocation(this.#clientId);ModuleLoader.setBaseUrl(moduleLocation),this.#repository=repository}import(url,base){if(void 0===this.#repository)throw new RepositoryNotAvailable;return void 0!==base&&(url=UrlRewriter.addBase(url,base)),this.#repository.importModule(this.#clientId,url)}run(fqn,version,args,headers){const procedure=this.#getProcedure(fqn);return void 0===procedure?this.#runGateway(fqn,version,args,headers):this.#runProcedure(procedure,version,args,headers)}#runGateway(fqn,version,args,headers){if(void 0===this.#gateway)throw new ProcedureNotFound(fqn);return this.#gateway.run(fqn,version,args,headers)}#runProcedure(procedure,version,args,headers){const implementation=procedure.getImplementation(version);if(void 0===implementation)throw new ImplementationNotFound(procedure.fqn,version.toString());const context=new Context(headers),values=this.#argumentConstructor.extract(implementation.parameters,args);return implementation.executable.call(context,...values)}}class Repository extends Runtime{}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)}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))return token.hasValue(Keyword.ASYNC)?(tokenList.step(),this.#parseNext(tokenList,!0)):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=token.isType(TokenType.IDENTIFIER)?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()),token.isType(TokenType.IDENTIFIER)&&(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(token.isType(TokenType.IDENTIFIER)&&(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)}}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)}importFile(filename){const url=`${this.#url}/${filename}`;return ModuleLoader.load(url)}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(fqn,version,args,headers){headers.set("content-type","application/json");const versionString=version.toString(),argsObject=Object.fromEntries(args),headersObject=Object.fromEntries(headers),url=`${this.#url}/rpc/${fqn}?version=${versionString}&serialize=true`,options={method:"POST",headers:headersObject,body:await this.#createRequestBody(argsObject)},response=await this.#callRemote(url,options,200);return this.#createResponseResult(response)}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()}}class RemoteGateway extends Gateway{#remote;constructor(url){super(url),this.#remote=new Remote(url)}getProcedureNames(){throw new NotImplemented}hasProcedure(name){throw new NotImplemented}addNode(node){return this.#remote.addNode(node)}run(fqn,version,args,headers){return this.#remote.run(fqn,version,args,headers)}}class RemoteRepository extends Repository{#remote;constructor(url){super(url),this.#remote=new Remote(url)}registerClient(segmentFiles){return this.#remote.registerClient(segmentFiles)}loadAsset(filename){return this.#remote.loadFile(filename)}async getModuleLocation(clientId){return`${this.url}/modules/${clientId}`}async loadModule(clientId,filename){return this.#remote.loadFile(`modules/${clientId}/${filename}`)}async importModule(clientId,filename){return this.#remote.importFile(`modules/${clientId}/${filename}`)}}const globals=globalThis;globals.__getDependency=async function(name){RUNS_IN_BROWSER&&"jitar"===name&&(name="/jitar/client.js");const module=await _loader(name);return void 0!==module.default?module.default:module},globals.__runProcedure=async function(fqn,versionNumber,args,context){if(void 0===_runtime)throw new RuntimeNotAvailable;const version=VersionParser.parse(versionNumber),argsMap=new Map(Object.entries(args)),headersMap=context instanceof Context?context.headers:new Map;return _runtime.run(fqn,version,argsMap,headersMap)},globals.ProcedureNotAccessible=ProcedureNotAccessible;export{SegmentNotFound as $,AccessLevel as A,BadRequest as B,ClientNotFound as C,ServerError as D,ImplementationNotFound as E,FileNotFound as F,InvalidParameterValue as G,InvalidVersionNumber as H,InvalidSegmentFile as I,MissingParameterValue as J,ModuleNotAccessible as K,LocalGateway as L,ModuleLoader as M,Node as N,ObjectParameter as O,ProcedureRuntime as P,ModuleNotLoaded as Q,Repository as R,SerializerBuilder as S,Teapot as T,Unauthorized as U,VersionParser as V,NoNodeAvailable as W,ProcedureNotAccessible as X,ProcedureNotFound as Y,RepositoryNotAvailable as Z,RuntimeNotAvailable as _,InvalidClientId as a,UnknownParameter as a0,File as b,convertToLocalFilename as c,convertToRemoteFilename as d,createRepositoryFilename as e,Remote as f,Reflector as g,ReflectionField as h,isSegmentFilename as i,ReflectionDestructuredArray as j,ReflectionDestructuredObject as k,ReflectionDestructuredValue as l,createNodeFilename as m,ReflectionFunction as n,Files as o,LocalNode as p,RemoteRepository as q,RemoteGateway as r,PaymentRequired as s,Forbidden as t,NotFound as u,NotImplemented as v,Version as w,RemoteClassLoader as x,NamedParameter as y,ArrayParameter as z};
|
package/dist/lib.d.ts
CHANGED
|
@@ -142,6 +142,7 @@ declare class File {
|
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
interface HealthCheck {
|
|
145
|
+
get timeout(): number | undefined;
|
|
145
146
|
isHealthy(): Promise<boolean>;
|
|
146
147
|
}
|
|
147
148
|
|
|
@@ -273,6 +274,33 @@ declare class LocalNode extends Node {
|
|
|
273
274
|
run(fqn: string, version: Version, args: Map<string, unknown>, headers: Map<string, string>): Promise<unknown>;
|
|
274
275
|
}
|
|
275
276
|
|
|
277
|
+
type Loadable = {
|
|
278
|
+
name: string;
|
|
279
|
+
source?: string;
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
interface ClassLoader {
|
|
283
|
+
loadClass(loadable: Loadable): Promise<Function>;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
declare abstract class ValueSerializer {
|
|
287
|
+
#private;
|
|
288
|
+
set parent(parent: Serializer);
|
|
289
|
+
abstract canSerialize(value: unknown): boolean;
|
|
290
|
+
abstract canDeserialize(value: unknown): boolean;
|
|
291
|
+
abstract serialize(value: unknown): Promise<unknown>;
|
|
292
|
+
abstract deserialize(value: unknown): Promise<unknown>;
|
|
293
|
+
serializeOther(value: unknown): Promise<unknown>;
|
|
294
|
+
deserializeOther(value: unknown): Promise<unknown>;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
declare class Serializer {
|
|
298
|
+
#private;
|
|
299
|
+
addSerializer(serializer: ValueSerializer): void;
|
|
300
|
+
serialize(value: unknown): Promise<unknown>;
|
|
301
|
+
deserialize(value: unknown): Promise<unknown>;
|
|
302
|
+
}
|
|
303
|
+
|
|
276
304
|
type ModuleImporter = (name: string) => Promise<Module>;
|
|
277
305
|
|
|
278
306
|
declare function startClient(remoteUrl: string, segmentNames?: string[]): Promise<LocalNode>;
|
|
@@ -299,11 +327,14 @@ declare class CorsMiddleware implements Middleware {
|
|
|
299
327
|
declare class JitarServer {
|
|
300
328
|
#private;
|
|
301
329
|
constructor();
|
|
330
|
+
get classLoader(): ClassLoader;
|
|
331
|
+
build(): Promise<void>;
|
|
302
332
|
start(): Promise<void>;
|
|
303
|
-
|
|
333
|
+
registerHealthCheck(name: string, healthCheck: HealthCheck): void;
|
|
334
|
+
addSerializer(serializer: ValueSerializer): void;
|
|
304
335
|
addMiddleware(middleware: Middleware): void;
|
|
305
336
|
}
|
|
306
337
|
|
|
307
|
-
declare function
|
|
338
|
+
declare function buildServer(moduleImporter: ModuleImporter): Promise<JitarServer>;
|
|
308
339
|
|
|
309
|
-
export { ArrayParameter, BadRequest, ClientNotFound, CorsMiddleware, FileNotFound, Forbidden, HealthCheck, Implementation, ImplementationNotFound, InvalidClientId, InvalidParameterValue, InvalidSegmentFile, InvalidVersionNumber, Middleware, MissingParameterValue, ModuleNotAccessible, ModuleNotLoaded, NamedParameter, NextHandler, NoNodeAvailable, NotFound, NotImplemented, ObjectParameter, PaymentRequired, Procedure, ProcedureNotAccessible, ProcedureNotFound, RepositoryNotAvailable, RuntimeNotAvailable, Segment, SegmentNotFound, ServerError, Teapot, Unauthorized, UnknownParameter, Version, getClient, startClient
|
|
340
|
+
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, RuntimeNotAvailable, Segment, SegmentNotFound, ServerError, Teapot, Unauthorized, UnknownParameter, Version, buildServer, getClient, startClient };
|
package/dist/server.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{R as Repository,M as ModuleLoader,I as InvalidSegmentFile,F as FileNotFound,a as InvalidClientId,C as ClientNotFound,i as isSegmentFilename,c as convertToLocalFilename,b as File,d as convertToRemoteFilename,e as createRepositoryFilename,P as ProcedureRuntime,f as ProcedureRunner,N as Node,g as Remote,h as Reflector,A as AccessLevel,j as ReflectionField,k as ReflectionDestructuredArray,l as ReflectionDestructuredObject,m as ReflectionDestructuredValue,n as createNodeFilename,V as VersionParser,o as ReflectionFunction,p as Files,L as LocalGateway,q as LocalNode,r as RemoteRepository,s as RemoteGateway,B as BadRequest,U as Unauthorized,t as PaymentRequired,u as Forbidden,v as NotFound,T as Teapot,w as NotImplemented,x as Version,S as SerializerBuilder,y as RemoteClassLoader}from"./globals-d516de70.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(fqn,version,args,headers,next){const result=await next();return this.#setHeaders(headers),result}#setHeaders(headers){headers.set("Access-Control-Allow-Origin",this.#allowOrigin),headers.set("Access-Control-Allow-Methods",this.#allowMethods),headers.set("Access-Control-Allow-Headers",this.#allowHeaders)}}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;#assets;constructor(fileManager,assets,url){super(url),this.#fileManager=fileManager,this.#assets=assets}async loadSegment(name){const filename=`./${createRepositoryFilename(name)}`,location=this.#fileManager.getAbsoluteLocation(filename),files=(await ModuleLoader.load(location)).files;if(void 0===files)throw new InvalidSegmentFile(location);this.registerSegment(name,files)}async registerSegment(name,files){files.forEach((file=>this.#segments.set(file,name)))}async registerClient(segmentFilenames){const clientId=clientIdHelper$1.generate();return this.#clients.set(clientId,segmentFilenames),clientId}loadAsset(filename){if(!1===this.#assets.includes(filename))throw new FileNotFound(filename);return this.#readFile(filename)}async getModuleLocation(clientId){return this.#fileManager.getRootLocation()}loadModule(clientId,filename){this.#validateClientId(clientId);const segmentFilename=this.#segments.get(filename);return void 0===segmentFilename||this.#hasClientSegmentFile(clientId,segmentFilename)?this.#getNodeModule(filename):this.#getRemoteModule(filename)}importModule(clientId,filename){filename=ModuleLoader.assureExtension(filename);const location=this.#fileManager.getAbsoluteLocation(filename);return ModuleLoader.import(location)}#validateClientId(clientId){if(!1===clientIdHelper$1.validate(clientId))throw new InvalidClientId(clientId);if(!1===this.#clients.has(clientId))throw new ClientNotFound(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#getNodeModule(filename){const localFilename=isSegmentFilename(filename)?filename:convertToLocalFilename(filename),code=(await this.#readFile(localFilename)).content.toString();return new File(filename,"application/javascript",code)}#getRemoteModule(filename){const remoteFilename=convertToRemoteFilename(filename);return this.#readFile(remoteFilename)}#readFile(filename){return this.#fileManager.read(filename)}}class NodeMonitor{#gateway;#frequency;#interval=null;constructor(gateway,frequency=5e3){this.#gateway=gateway,this.#frequency=frequency}start(){this.#interval=setInterval((async()=>await this.#monitor()),this.#frequency)}stop(){null!==this.#interval&&clearInterval(this.#interval)}async#monitor(){const promises=this.#gateway.nodes.map((async node=>await this.#monitorNode(node)));await Promise.all(promises)}async#monitorNode(node){!1===await this.#checkNodeAvailable(node)&&this.#gateway.removeNode(node)}async#checkNodeAvailable(node){try{return await node.isHealthy()}catch(error){return!1}}}class Proxy extends ProcedureRuntime{#repository;#runner;constructor(repository,runner,url){super(url),this.#repository=repository,this.#runner=runner,this.addMiddleware(new ProcedureRunner(this))}get repository(){return this.#repository}get runner(){return this.#runner}getProcedureNames(){return this.#runner.getProcedureNames()}hasProcedure(fqn){return this.getProcedureNames().includes(fqn)}loadAsset(filename){return this.#repository.loadAsset(filename)}registerClient(segmentFiles){return this.#repository.registerClient(segmentFiles)}loadModule(clientId,filename){return this.#repository.loadModule(clientId,filename)}run(name,version,args,headers){return this.#runner.run(name,version,args,headers)}}class RemoteNode extends Node{#remote;#procedureNames=new Set;constructor(url,procedureNames){super(url),this.#remote=new Remote(url,!1),this.registerProcedures(procedureNames)}getProcedureNames(){return[...this.#procedureNames.values()]}registerProcedures(procedureNames){procedureNames.forEach((procedureName=>this.#procedureNames.add(procedureName)))}hasProcedure(name){return this.#procedureNames.has(name)}isHealthy(){return this.#remote.isHealthy()}getHealth(){return this.#remote.getHealth()}run(fqn,version,args,headers){return this.#remote.run(fqn,version,args,headers)}}const gatewaySchema=z.object({monitor:z.number().optional(),repository:z.string().url().optional()}).strict().transform((value=>new GatewayConfiguration(value.monitor,value.repository)));class GatewayConfiguration{#monitor;#repository;constructor(monitor,repository){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()}).strict().transform((value=>new NodeConfiguration(value.gateway,value.repository,value.segments)));class NodeConfiguration{#gateway;#repository;#segments;constructor(gateway,repository,segments){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()}).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)));class ProxyConfiguration{#node;#gateway;#repository;constructor(node,gateway,repository){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()}).strict().transform((value=>new RepositoryConfiguration(value.source,value.cache,value.index,value.assets)));class RepositoryConfiguration{#source;#cache;#index;#assets;constructor(source,cache,index,assets){this.#source=source,this.#cache=cache,this.#index=index,this.#assets=assets}get source(){return this.#source}get cache(){return this.#cache}get index(){return this.#index}get assets(){return this.#assets}}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()}).strict().transform((value=>new StandaloneConfiguration(value.source,value.cache,value.index,value.segments,value.assets)));class StandaloneConfiguration{#source;#cache;#index;#segments;#assets;constructor(source,cache,index,segments,assets){this.#source=source,this.#cache=cache,this.#index=index,this.#segments=segments,this.#assets=assets}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}}const runtimeSchema=z.object({url: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.standalone,value.repository,value.gateway,value.node,value.proxy)));class RuntimeConfiguration{#url;#standalone;#repository;#gateway;#node;#proxy;constructor(url,standalone,repository,gateway,node,proxy){this.#url=url,this.#standalone=standalone,this.#repository=repository,this.#gateway=gateway,this.#node=node,this.#proxy=proxy}get url(){return this.#url}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 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 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} as ${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()]}}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,NON_SYSTEM_INDICATORS=[".","/","http:","https:"],reflector$2=new Reflector;const importRewriter=new class{rewrite(code,includeSystem){return code.replaceAll(IMPORT_PATTERN,(statement=>this.#replaceImport(statement,includeSystem)))}#replaceImport(statement,includeSystem){const dependency=reflector$2.parseImport(statement);return this.#isSystemDependency(dependency)?includeSystem?this.#rewriteSystemImport(dependency):statement:this.#rewriteApplicationImport(dependency)}#isSystemDependency(dependency){return!1===NON_SYSTEM_INDICATORS.some((indicator=>dependency.from.startsWith(indicator,1)))}#rewriteSystemImport(dependency){const from=this.#rewriteImportFrom(dependency);if(0===dependency.members.length)return`await __getDependency('${from}');`;return`const ${this.#rewriteImportMembers(dependency,":")} = await __getDependency('${from}');`}#rewriteApplicationImport(dependency){return`import ${this.#rewriteImportMembers(dependency,"as")} from '${this.#rewriteImportFrom(dependency)}';`}#rewriteImportMembers(dependency,aliasSpecifier){if(this.#mustUseAs(dependency))return dependency.members[0].as;return`{ ${dependency.members.map((member=>member.name!==member.as?`${member.name} ${aliasSpecifier} ${member.as}`:member.name)).join(", ")} }`}#rewriteImportFrom(dependency){const from=dependency.from.substring(1,dependency.from.length-1);return NON_SYSTEM_INDICATORS.some((indicator=>from.startsWith(indicator)))?from.endsWith(".js")?from:`${from}.js`:from}#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===AccessLevel.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 __runProcedure('${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.#writeOriginal(cache),this.#writeLocal(cache),this.#writeRemote(cache)]).then((()=>{}))}async#writeOriginal(cache){const importCode=this.#rewriteApplicationImports(cache.module),sourceCode=this.#createSourceCode(cache.module),filename=cache.module.filename,code=`${importCode}\n${sourceCode}`;return this.#fileManager.write(filename,code.trim())}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())}#rewriteApplicationImports(module){return importRewriter.rewrite(module.code,!1)}#rewriteAllImports(module){return importRewriter.rewrite(module.code,!0)}#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(`import { ${members.join(", ")} } from "./${from}";`);return codes.join("\n")}#createSegmentCode(name,procedures){const codes=[];codes.push('const { Segment, Procedure, Implementation, Version, NamedParameter, ArrayParameter, ObjectParameter } = await __getDependency("jitar");'),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=>await this.#segmentWriter.write(segment)))).then((()=>{}))}async#writeModuleCache(modules){return Promise.all(modules.map((async module=>await 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=>await this.#segmentReader.read(segmentFile))))}async#readModules(moduleFiles){return Promise.all(moduleFiles.map((async moduleFile=>await 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)}}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 type=await this.getType(filename),content=await this.getContent(filename);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 await 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")}}var RuntimeDefaults;!function(RuntimeDefaults){RuntimeDefaults.URL="http://localhost:3000",RuntimeDefaults.SOURCE="./dist",RuntimeDefaults.CACHE="./.jitar",RuntimeDefaults.INDEX="index.html"}(RuntimeDefaults||(RuntimeDefaults={}));var LogLevel,RuntimeDefaults$1=RuntimeDefaults;class UnknownRuntimeMode extends Error{constructor(){super("Unknown runtime mode")}}class RuntimeConfigurator{static async configure(configuration){const url=configuration.url??RuntimeDefaults$1.URL;if(void 0!==configuration.standalone)return this.#configureStandAlone(url,configuration.standalone);if(void 0!==configuration.repository)return this.#configureRepository(url,configuration.repository);if(void 0!==configuration.gateway)return this.#configureGateway(url,configuration.gateway);if(void 0!==configuration.node)return this.#configureNode(url,configuration.node);if(void 0!==configuration.proxy)return this.#configureProxy(url,configuration.proxy);throw new UnknownRuntimeMode}static async#configureStandAlone(url,configuration){const sourceLocation=configuration.source??RuntimeDefaults$1.SOURCE,cacheLocation=configuration.cache??RuntimeDefaults$1.CACHE,assetFilePatterns=configuration.assets;await this.#buildCache(sourceLocation,cacheLocation);const segmentNames=void 0===configuration.segments?await this.#getSegmentNames(cacheLocation):configuration.segments,repository=await this.#buildRepository(url,cacheLocation,assetFilePatterns),node=await this.#buildNode(url,segmentNames,repository);return this.#buildProxy(url,repository,node)}static async#configureRepository(url,configuration){const sourceLocation=configuration.source??RuntimeDefaults$1.SOURCE,cacheLocation=configuration.cache??RuntimeDefaults$1.CACHE,assetFilePatterns=configuration.assets??[];return await this.#buildCache(sourceLocation,cacheLocation),this.#buildRepository(url,cacheLocation,assetFilePatterns)}static async#configureGateway(url,configuration){const repository=this.#getRemoteRepository(configuration.repository);return this.#buildGateway(url,configuration.monitor,repository)}static async#configureNode(url,configuration){const segmentNames=configuration.segments??[],repository=this.#getRemoteRepository(configuration.repository),gateway=this.#getRemoteGateway(configuration.gateway);return this.#buildNode(url,segmentNames,repository,gateway)}static async#configureProxy(url,configuration){const repository=this.#getRemoteRepository(configuration.repository),gateway=this.#getRemoteGateway(configuration.gateway),node=void 0!==configuration.node?new RemoteNode(configuration.node,[]):void 0,runner=gateway??node;return this.#buildProxy(url,repository,runner)}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#getSegmentNames(cacheLocation){const fileManager=new LocalFileManager(cacheLocation);return(await fileManager.getNodeSegmentFiles()).map((filename=>this.#extractSegmentName(filename)))}static#extractSegmentName(filename){const name=filename.split("/").pop()??"",endIndex=name.indexOf(".segment");return name.substring(0,endIndex)}static async#buildRepository(url,cacheLocation,assetFilePatterns){const fileManager=new LocalFileManager(cacheLocation),assetFiles=void 0!==assetFilePatterns?await fileManager.getAssetFiles(assetFilePatterns):[],repository=new LocalRepository(fileManager,assetFiles,url),segmentNames=(await fileManager.getRepositorySegmentFiles()).map((filename=>this.#extractSegmentName(filename)));for(const name of segmentNames)await repository.loadSegment(name);return repository}static async#buildGateway(url,monitorInterval,repository){const gateway=new LocalGateway(url);void 0!==repository&&await gateway.setBaseUrl(repository);return new NodeMonitor(gateway,monitorInterval).start(),gateway}static async#buildNode(url,segmentNames,repository,gateway){const node=new LocalNode(url);void 0!==repository&&await node.setRepository(repository,segmentNames);for(const segmentName of segmentNames)await node.loadSegment(segmentName);return void 0!==gateway&&node.setGateway(gateway),node}static async#buildProxy(url,repository,runner){return new Proxy(repository,runner,url)}static#getRemoteRepository(url){return void 0!==url?new RemoteRepository(url):void 0}static#getRemoteGateway(url){return void 0!==url?new RemoteGateway(url):void 0}}!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)}}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){this.#logger.info(`Got asset -> '${request.path}'`);const path=request.path.substring(1).trim(),filename=0===path.length?this.#indexFile:path;try{const file=await this.#repository.loadAsset(filename);response.set("Content-Type",file.type),response.set("Content-Length",String(file.size)),response.status(200).send(file.content)}catch(error){if(error instanceof FileNotFound)return this.#logger.warn(`Failed to get asset -> '${filename}' | ${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 -> '${filename}' | ${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("Content-Type","text/plain"),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){this.#logger.info("Register client"),request.body;const segmentFiles=request.body,clientId=await this.#repository.registerClient(segmentFiles);return this.#logger.info(`Registered client -> ${clientId} [${segmentFiles.join(",")}]`),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.loadModule(clientId,filename);return this.#logger.info(`Got module -> '${filename}' (${clientId})`),response.set("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("Content-Type","application/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.status(200).send(nodes)}async add(request,response){try{const nodeDto=DataConverter.convert(nodeDtoSchema,request.body),node=new RemoteNode(nodeDto.url,nodeDto.procedureNames);return 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.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.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;#useSerializer;#logger;constructor(app,runtime,serializer,useSerializer,logger){this.#runtime=runtime,this.#serializer=serializer,this.#useSerializer=useSerializer,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)})),this.#showProcedureInfo()}#showProcedureInfo(){const procedureNames=this.#runtime.getProcedureNames();0!==procedureNames.length&&(procedureNames.sort(),this.#logger.info("Registered RPC entries",procedureNames))}async runGet(request,response){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)}async runPost(request,response){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)}async runOptions(request,response){return this.#setCors(response)}#extractFqn(request){return request.path.substring(5)}#extractVersion(request){return void 0!==request.query.version?VersionParser.parse(request.query.version.toString()):Version.DEFAULT}#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.status(404).send(`Procedure not found -> ${fqn}`);try{this.#useSerializer&&(args=await this.#serializer.deserialize(args));const argsMap=new Map(Object.entries(args)),result=await this.#runtime.handle(fqn,version,argsMap,headers);return this.#logger.info(`Ran procedure -> ${fqn} (v${version.toString()})`),this.#setResponseHeaders(response,headers),this.#createResultResponse(result,response,this.#useSerializer&&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="text/plain"===contentType?String(content):content;return response.setHeader("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("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?"application/json":"text/plain"}#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 MiddlewareNotSupported extends Error{constructor(){super("Middleware is not supported")}}class JitarServer{#app;#runtime;#serializer;constructor(){this.#serializer=SerializerBuilder.build(new RemoteClassLoader),this.#app=express(),this.#app.use(express.json()),this.#app.use(express.urlencoded({extended:!0})),this.#app.disable("x-powered-by")}async start(){console.log("\n ██ ██ ████████ █████ ██████ \n ██ ██ ██ ██ ██ ██ ██ \n ██ ██ ██ ███████ ██████ \n ██ ██ ██ ██ ██ ██ ██ ██ \n █████ ██ ██ ██ ██ ██ ██\n ____________________________________\n By Masking Technology (masking.tech)\n");const options=ServerOptionsReader.read(),configuration=RuntimeConfigurationLoader.load(options.config),runtime=await RuntimeConfigurator.configure(configuration),logger=LogBuilder.build(options.loglevel);this.#addControllers(configuration,runtime,logger);const url=new URL(configuration.url??RuntimeDefaults$1.URL);await this.#startServer(url.port),this.#runtime=runtime,logger.info(`Server started and listening at port ${url.port}`)}addHealthCheck(name,healthCheck){if(void 0===this.#runtime)throw new RuntimeNotAvailable;this.#runtime.addHealthCheck(name,healthCheck)}addMiddleware(middleware){if(void 0===this.#runtime)throw new RuntimeNotAvailable;if(!(this.#runtime instanceof ProcedureRuntime))throw new MiddlewareNotSupported;this.#runtime.addMiddleware(middleware)}#addControllers(configuration,runtime,logger){if(void 0!==configuration.standalone&&runtime instanceof Proxy){const index=configuration.standalone.index??RuntimeDefaults$1.INDEX;this.#addStandAloneControllers(runtime,logger,index)}else if(void 0!==configuration.repository&&runtime instanceof LocalRepository){const index=configuration.repository.index??RuntimeDefaults$1.INDEX;this.#addRepositoryControllers(runtime,logger,index)}else void 0!==configuration.gateway&&runtime instanceof LocalGateway?this.#addGatewayControllers(runtime,logger):void 0!==configuration.node&&runtime instanceof LocalNode?this.#addNodeControllers(runtime,logger):void 0!==configuration.proxy&&runtime instanceof Proxy&&this.#addProxyControllers(runtime,logger)}#addStandAloneControllers(proxy,logger,index){new HealthController(this.#app,proxy,logger),new JitarController(this.#app),new ModulesController(this.#app,proxy,this.#serializer,logger),new ProceduresController(this.#app,proxy,logger),new RPCController(this.#app,proxy,this.#serializer,!0,logger),new AssetsController(this.#app,proxy,index,logger)}#addRepositoryControllers(repository,logger,index){new JitarController(this.#app),new ModulesController(this.#app,repository,this.#serializer,logger),new AssetsController(this.#app,repository,index,logger)}#addGatewayControllers(gateway,logger){new NodesController(this.#app,gateway,logger),new ProceduresController(this.#app,gateway,logger),new RPCController(this.#app,gateway,this.#serializer,!1,logger)}#addNodeControllers(node,logger){new HealthController(this.#app,node,logger),new ProceduresController(this.#app,node,logger),new RPCController(this.#app,node,this.#serializer,!0,logger)}#addProxyControllers(proxy,logger){new ProxyController(this.#app,proxy,logger)}async#startServer(port){return new Promise((resolve=>{this.#app.listen(port,resolve)}))}}async function startServer(moduleImporter){ModuleLoader.setImporter(moduleImporter);const server=new JitarServer;return await server.start(),server}export{CorsMiddleware,startServer};
|
|
1
|
+
import{R as Repository,M as ModuleLoader,I as InvalidSegmentFile,F as FileNotFound,a as InvalidClientId,C as ClientNotFound,i as isSegmentFilename,c as convertToLocalFilename,b as File,d as convertToRemoteFilename,e as createRepositoryFilename,P as ProcedureRuntime,N as Node,f as Remote,g as Reflector,A as AccessLevel,h as ReflectionField,j as ReflectionDestructuredArray,k as ReflectionDestructuredObject,l as ReflectionDestructuredValue,m as createNodeFilename,V as VersionParser,n as ReflectionFunction,o as Files,L as LocalGateway,p as LocalNode,q as RemoteRepository,r as RemoteGateway,B as BadRequest,U as Unauthorized,s as PaymentRequired,t as Forbidden,u as NotFound,T as Teapot,v as NotImplemented,w as Version,x as RemoteClassLoader,S as SerializerBuilder}from"./globals-a24096f0.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(fqn,version,args,headers,next){const result=await next();return this.#setHeaders(headers),result}#setHeaders(headers){headers.set("Access-Control-Allow-Origin",this.#allowOrigin),headers.set("Access-Control-Allow-Methods",this.#allowMethods),headers.set("Access-Control-Allow-Headers",this.#allowHeaders)}}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;#assets;constructor(fileManager,assets,url){super(url),this.#fileManager=fileManager,this.#assets=assets}async loadSegment(name){const filename=`./${createRepositoryFilename(name)}`,location=this.#fileManager.getAbsoluteLocation(filename),files=(await ModuleLoader.load(location)).files;if(void 0===files)throw new InvalidSegmentFile(location);this.registerSegment(name,files)}async registerSegment(name,files){files.forEach((file=>this.#segments.set(file,name)))}async registerClient(segmentFilenames){const clientId=clientIdHelper$1.generate();return this.#clients.set(clientId,segmentFilenames),clientId}loadAsset(filename){if(!1===this.#assets.includes(filename))throw new FileNotFound(filename);return this.#readFile(filename)}async getModuleLocation(clientId){return this.#fileManager.getRootLocation()}loadModule(clientId,filename){this.#validateClientId(clientId);const segmentFilename=this.#segments.get(filename);return void 0===segmentFilename||this.#hasClientSegmentFile(clientId,segmentFilename)?this.#getNodeModule(filename):this.#getRemoteModule(filename)}importModule(clientId,filename){filename=ModuleLoader.assureExtension(filename);const location=this.#fileManager.getAbsoluteLocation(filename);return ModuleLoader.import(location)}#validateClientId(clientId){if(!1===clientIdHelper$1.validate(clientId))throw new InvalidClientId(clientId);if(!1===this.#clients.has(clientId))throw new ClientNotFound(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#getNodeModule(filename){const localFilename=isSegmentFilename(filename)?filename:convertToLocalFilename(filename),code=(await this.#readFile(localFilename)).content.toString();return new File(filename,"application/javascript",code)}#getRemoteModule(filename){const remoteFilename=convertToRemoteFilename(filename);return this.#readFile(remoteFilename)}#readFile(filename){return this.#fileManager.read(filename)}}class NodeMonitor{#gateway;#frequency;#interval=null;constructor(gateway,frequency=5e3){this.#gateway=gateway,this.#frequency=frequency}start(){this.#interval=setInterval((async()=>this.#monitor()),this.#frequency)}stop(){null!==this.#interval&&clearInterval(this.#interval)}async#monitor(){const promises=this.#gateway.nodes.map((async node=>this.#monitorNode(node)));await Promise.all(promises)}async#monitorNode(node){!1===await this.#checkNodeAvailable(node)&&this.#gateway.removeNode(node)}async#checkNodeAvailable(node){try{return await node.isHealthy()}catch(error){return!1}}}class Proxy extends ProcedureRuntime{#repository;#runner;constructor(repository,runner,url){super(url),this.#repository=repository,this.#runner=runner}get repository(){return this.#repository}get runner(){return this.#runner}getProcedureNames(){return this.#runner.getProcedureNames()}hasProcedure(fqn){return this.getProcedureNames().includes(fqn)}loadAsset(filename){return this.#repository.loadAsset(filename)}registerClient(segmentFiles){return this.#repository.registerClient(segmentFiles)}loadModule(clientId,filename){return this.#repository.loadModule(clientId,filename)}run(name,version,args,headers){return this.#runner.run(name,version,args,headers)}}class RemoteNode extends Node{#remote;#procedureNames=new Set;constructor(url,procedureNames){super(url),this.#remote=new Remote(url),this.registerProcedures(procedureNames)}getProcedureNames(){return[...this.#procedureNames.values()]}registerProcedures(procedureNames){procedureNames.forEach((procedureName=>this.#procedureNames.add(procedureName)))}hasProcedure(name){return this.#procedureNames.has(name)}isHealthy(){return this.#remote.isHealthy()}getHealth(){return this.#remote.getHealth()}run(fqn,version,args,headers){return this.#remote.run(fqn,version,args,headers)}}const gatewaySchema=z.object({monitor:z.number().optional(),repository:z.string().url().optional()}).strict().transform((value=>new GatewayConfiguration(value.monitor,value.repository)));class GatewayConfiguration{#monitor;#repository;constructor(monitor,repository){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()}).strict().transform((value=>new NodeConfiguration(value.gateway,value.repository,value.segments)));class NodeConfiguration{#gateway;#repository;#segments;constructor(gateway,repository,segments){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()}).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)));class ProxyConfiguration{#node;#gateway;#repository;constructor(node,gateway,repository){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()}).strict().transform((value=>new RepositoryConfiguration(value.source,value.cache,value.index,value.assets)));class RepositoryConfiguration{#source;#cache;#index;#assets;constructor(source,cache,index,assets){this.#source=source,this.#cache=cache,this.#index=index,this.#assets=assets}get source(){return this.#source}get cache(){return this.#cache}get index(){return this.#index}get assets(){return this.#assets}}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()}).strict().transform((value=>new StandaloneConfiguration(value.source,value.cache,value.index,value.segments,value.assets)));class StandaloneConfiguration{#source;#cache;#index;#segments;#assets;constructor(source,cache,index,segments,assets){this.#source=source,this.#cache=cache,this.#index=index,this.#segments=segments,this.#assets=assets}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}}const runtimeSchema=z.object({url: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.healthChecks,value.standalone,value.repository,value.gateway,value.node,value.proxy)));class RuntimeConfiguration{#url;#healthChecks;#standalone;#repository;#gateway;#node;#proxy;constructor(url,healthChecks,standalone,repository,gateway,node,proxy){this.#url=url,this.#healthChecks=healthChecks,this.#standalone=standalone,this.#repository=repository,this.#gateway=gateway,this.#node=node,this.#proxy=proxy}get url(){return this.#url}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} as ${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,NON_SYSTEM_INDICATORS=[".","/","http:","https:"],reflector$2=new Reflector;const importRewriter=new class{rewrite(code,includeSystem){return code.replaceAll(IMPORT_PATTERN,(statement=>this.#replaceImport(statement,includeSystem)))}#replaceImport(statement,includeSystem){const dependency=reflector$2.parseImport(statement);return this.#isSystemDependency(dependency)?includeSystem?this.#rewriteSystemImport(dependency):statement:this.#rewriteApplicationImport(dependency)}#isSystemDependency(dependency){return!1===NON_SYSTEM_INDICATORS.some((indicator=>dependency.from.startsWith(indicator,1)))}#rewriteSystemImport(dependency){const from=this.#rewriteImportFrom(dependency);if(0===dependency.members.length)return`await __getDependency('${from}');`;return`const ${this.#rewriteImportMembers(dependency,":")} = await __getDependency('${from}');`}#rewriteApplicationImport(dependency){return`import ${this.#rewriteImportMembers(dependency,"as")} from '${this.#rewriteImportFrom(dependency)}';`}#rewriteImportMembers(dependency,aliasSpecifier){if(this.#mustUseAs(dependency))return dependency.members[0].as;return`{ ${dependency.members.map((member=>member.name!==member.as?`${member.name} ${aliasSpecifier} ${member.as}`:member.name)).join(", ")} }`}#rewriteImportFrom(dependency){const from=dependency.from.substring(1,dependency.from.length-1);return NON_SYSTEM_INDICATORS.some((indicator=>from.startsWith(indicator)))?from.endsWith(".js")?from:`${from}.js`:from}#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===AccessLevel.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 __runProcedure('${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.#writeOriginal(cache),this.#writeLocal(cache),this.#writeRemote(cache)]).then((()=>{}))}async#writeOriginal(cache){const importCode=this.#rewriteApplicationImports(cache.module),sourceCode=this.#createSourceCode(cache.module),filename=cache.module.filename,code=`${importCode}\n${sourceCode}`;return this.#fileManager.write(filename,code.trim())}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())}#rewriteApplicationImports(module){return importRewriter.rewrite(module.code,!1)}#rewriteAllImports(module){return importRewriter.rewrite(module.code,!0)}#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(`import { ${members.join(", ")} } from "./${from}";`);return codes.join("\n")}#createSegmentCode(name,procedures){const codes=[];codes.push('const { Segment, Procedure, Implementation, Version, NamedParameter, ArrayParameter, ObjectParameter } = await __getDependency("jitar");'),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)}}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 type=await this.getType(filename),content=await this.getContent(filename);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")}}var RuntimeDefaults;!function(RuntimeDefaults){RuntimeDefaults.URL="http://localhost:3000",RuntimeDefaults.SOURCE="./dist",RuntimeDefaults.CACHE="./.jitar",RuntimeDefaults.INDEX="index.html"}(RuntimeDefaults||(RuntimeDefaults={}));var LogLevel,RuntimeDefaults$1=RuntimeDefaults;class UnknownRuntimeMode extends Error{constructor(){super("Unknown runtime mode")}}class RuntimeConfigurator{static async configure(configuration){const url=configuration.url??RuntimeDefaults$1.URL;if(void 0!==configuration.standalone)return this.#configureStandAlone(url,configuration.standalone);if(void 0!==configuration.repository)return this.#configureRepository(url,configuration.repository);if(void 0!==configuration.gateway)return this.#configureGateway(url,configuration.gateway);if(void 0!==configuration.node)return this.#configureNode(url,configuration.node);if(void 0!==configuration.proxy)return this.#configureProxy(url,configuration.proxy);throw new UnknownRuntimeMode}static async#configureStandAlone(url,configuration){const sourceLocation=configuration.source??RuntimeDefaults$1.SOURCE,cacheLocation=configuration.cache??RuntimeDefaults$1.CACHE,assetFilePatterns=configuration.assets;await this.#buildCache(sourceLocation,cacheLocation);const segmentNames=void 0===configuration.segments?await this.#getSegmentNames(cacheLocation):configuration.segments,repository=await this.#buildRepository(url,cacheLocation,assetFilePatterns),node=await this.#buildNode(url,segmentNames,repository);return this.#buildProxy(url,repository,node)}static async#configureRepository(url,configuration){const sourceLocation=configuration.source??RuntimeDefaults$1.SOURCE,cacheLocation=configuration.cache??RuntimeDefaults$1.CACHE,assetFilePatterns=configuration.assets??[];return await this.#buildCache(sourceLocation,cacheLocation),this.#buildRepository(url,cacheLocation,assetFilePatterns)}static async#configureGateway(url,configuration){const repository=this.#getRemoteRepository(configuration.repository);return this.#buildGateway(url,configuration.monitor,repository)}static async#configureNode(url,configuration){const segmentNames=configuration.segments??[],repository=this.#getRemoteRepository(configuration.repository),gateway=this.#getRemoteGateway(configuration.gateway);return this.#buildNode(url,segmentNames,repository,gateway)}static async#configureProxy(url,configuration){const repository=this.#getRemoteRepository(configuration.repository),gateway=this.#getRemoteGateway(configuration.gateway),node=void 0!==configuration.node?new RemoteNode(configuration.node,[]):void 0,runner=gateway??node;return this.#buildProxy(url,repository,runner)}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#getSegmentNames(cacheLocation){const fileManager=new LocalFileManager(cacheLocation);return(await fileManager.getNodeSegmentFiles()).map((filename=>this.#extractSegmentName(filename)))}static#extractSegmentName(filename){const name=filename.split("/").pop()??"",endIndex=name.indexOf(".segment");return name.substring(0,endIndex)}static async#buildRepository(url,cacheLocation,assetFilePatterns){const fileManager=new LocalFileManager(cacheLocation),assetFiles=void 0!==assetFilePatterns?await fileManager.getAssetFiles(assetFilePatterns):[],repository=new LocalRepository(fileManager,assetFiles,url),segmentNames=(await fileManager.getRepositorySegmentFiles()).map((filename=>this.#extractSegmentName(filename)));for(const name of segmentNames)await repository.loadSegment(name);return repository}static async#buildGateway(url,monitorInterval,repository){const gateway=new LocalGateway(url);void 0!==repository&&await gateway.setBaseUrl(repository);return new NodeMonitor(gateway,monitorInterval).start(),gateway}static async#buildNode(url,segmentNames,repository,gateway){const node=new LocalNode(url);void 0!==repository&&await node.setRepository(repository,segmentNames);for(const segmentName of segmentNames)await node.loadSegment(segmentName);return void 0!==gateway&&node.setGateway(gateway),node}static async#buildProxy(url,repository,runner){return new Proxy(repository,runner,url)}static#getRemoteRepository(url){return void 0!==url?new RemoteRepository(url):void 0}static#getRemoteGateway(url){return void 0!==url?new RemoteGateway(url):void 0}}!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)}}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){this.#logger.info(`Got asset -> '${request.path}'`);const path=request.path.substring(1).trim(),filename=0===path.length?this.#indexFile:path;try{const file=await this.#repository.loadAsset(filename);response.set("Content-Type",file.type),response.set("Content-Length",String(file.size)),response.status(200).send(file.content)}catch(error){if(error instanceof FileNotFound)return this.#logger.warn(`Failed to get asset -> '${filename}' | ${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 -> '${filename}' | ${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("Content-Type","text/plain"),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){this.#logger.info("Register client"),request.body;const segmentFiles=request.body,clientId=await this.#repository.registerClient(segmentFiles);return this.#logger.info(`Registered client -> ${clientId} [${segmentFiles.join(",")}]`),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.loadModule(clientId,filename);return this.#logger.info(`Got module -> '${filename}' (${clientId})`),response.set("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("Content-Type","application/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.status(200).send(nodes)}async add(request,response){try{const nodeDto=DataConverter.convert(nodeDtoSchema,request.body),node=new RemoteNode(nodeDto.url,nodeDto.procedureNames);return 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.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.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)})),this.#showProcedureInfo()}#showProcedureInfo(){const procedureNames=this.#runtime.getProcedureNames();0!==procedureNames.length&&(procedureNames.sort(),this.#logger.info("Registered RPC entries",procedureNames))}async runGet(request,response){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)}async runPost(request,response){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)}async runOptions(request,response){return this.#setCors(response)}#extractFqn(request){return request.path.substring(5)}#extractVersion(request){return void 0!==request.query.version?VersionParser.parse(request.query.version.toString()):Version.DEFAULT}#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.status(404).send(`Procedure not found -> ${fqn}`);try{const deserializedArgs=await this.#serializer.deserialize(args),argsMap=new Map(Object.entries(deserializedArgs)),result=await this.#runtime.handle(fqn,version,argsMap,headers);return this.#logger.info(`Ran procedure -> ${fqn} (v${version.toString()})`),this.#setResponseHeaders(response,headers),this.#createResultResponse(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="text/plain"===contentType?String(content):content;return response.setHeader("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("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?"application/json":"text/plain"}#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 UnknownHealthCheck extends Error{constructor(name){super(`Health check '${name}' is not registered.`)}}class DuplicateHealthCheck extends Error{constructor(name){super(`Health check '${name}' is already registered.`)}}class RuntimeNotAvailable extends Error{constructor(){super("Runtime is not available")}}class MiddlewareNotSupported extends Error{constructor(){super("Middleware is not supported")}}class JitarServer{#app;#runtime;#serializer;#classLoader;#options;#configuration;#logger;#registeredHealthChecks=new Map;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.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$1.URL);this.#addHealthChecks(),await this.#startServer(url.port),this.#logger.info(`Server started and listening at port ${url.port}`)}registerHealthCheck(name,healthCheck){if(this.#registeredHealthChecks.has(name))throw new DuplicateHealthCheck(name);this.#registeredHealthChecks.set(name,healthCheck)}addSerializer(serializer){this.#serializer.addSerializer(serializer)}addMiddleware(middleware){if(void 0===this.#runtime)throw new RuntimeNotAvailable;if(!(this.#runtime instanceof ProcedureRuntime))throw new MiddlewareNotSupported;this.#runtime.addMiddleware(middleware)}#addHealthChecks(){if(void 0===this.#runtime)throw new RuntimeNotAvailable;if(void 0!==this.#configuration.healthChecks)for(const name of this.#configuration.healthChecks){const healthCheck=this.#registeredHealthChecks.get(name);if(void 0===healthCheck)throw new UnknownHealthCheck(name);this.#runtime.addHealthCheck(name,healthCheck)}}#addControllers(){if(void 0!==this.#configuration.standalone&&this.#runtime instanceof Proxy){const index=this.#configuration.standalone.index??RuntimeDefaults$1.INDEX;this.#addStandAloneControllers(this.#runtime,index)}else if(void 0!==this.#configuration.repository&&this.#runtime instanceof LocalRepository){const index=this.#configuration.repository.index??RuntimeDefaults$1.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(proxy,index){new HealthController(this.#app,proxy,this.#logger),new JitarController(this.#app),new ModulesController(this.#app,proxy,this.#serializer,this.#logger),new ProceduresController(this.#app,proxy,this.#logger),new RPCController(this.#app,proxy,this.#serializer,this.#logger),new AssetsController(this.#app,proxy,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#startServer(port){return new Promise((resolve=>{this.#app.listen(port,resolve)}))}#printStartupMessage(){console.log("\n ██ ██ ████████ █████ ██████ \n ██ ██ ██ ██ ██ ██ ██ \n ██ ██ ██ ███████ ██████ \n ██ ██ ██ ██ ██ ██ ██ ██ \n █████ ██ ██ ██ ██ ██ ██\n ____________________________________\n By Masking Technology (masking.tech)\n")}}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.4.
|
|
3
|
+
"version": "0.4.2",
|
|
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",
|
|
@@ -12,31 +12,39 @@
|
|
|
12
12
|
"./server": "./dist/server.js",
|
|
13
13
|
"./client": "./dist/client.js"
|
|
14
14
|
},
|
|
15
|
+
"files": [
|
|
16
|
+
"CHANGELOG.md",
|
|
17
|
+
"README.md",
|
|
18
|
+
"dist",
|
|
19
|
+
"!dist/types"
|
|
20
|
+
],
|
|
15
21
|
"scripts": {
|
|
16
22
|
"lint": "eslint . --ext .ts",
|
|
17
23
|
"validate": "tsc -p tsconfig.json --noEmit",
|
|
18
24
|
"build": "npm run clean && rollup -c",
|
|
19
25
|
"clean": "rm -rf dist",
|
|
20
|
-
"
|
|
26
|
+
"prepublishOnly": "npm run clean && npm run build"
|
|
21
27
|
},
|
|
22
28
|
"dependencies": {
|
|
23
|
-
"@jitar/runtime": "^0.4.0",
|
|
24
|
-
"@jitar/server-nodejs": "^0.4.0",
|
|
25
29
|
"express": "^4.18.2",
|
|
26
|
-
"express-http-proxy": "^
|
|
30
|
+
"express-http-proxy": "^2.0.0",
|
|
27
31
|
"fs-extra": "^11.1.1",
|
|
28
|
-
"glob-promise": "6.0.
|
|
32
|
+
"glob-promise": "6.0.5",
|
|
29
33
|
"mime-types": "^2.1.35",
|
|
30
|
-
"tslog": "^4.
|
|
34
|
+
"tslog": "^4.9.2",
|
|
31
35
|
"yargs": "^17.7.2",
|
|
32
|
-
"zod": "^3.
|
|
36
|
+
"zod": "^3.22.4"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@jitar/runtime": "^0.4.2",
|
|
40
|
+
"@jitar/server-nodejs": "^0.4.2"
|
|
33
41
|
},
|
|
34
42
|
"engines": {
|
|
35
43
|
"node": ">=18.7"
|
|
36
44
|
},
|
|
37
45
|
"repository": {
|
|
38
46
|
"type": "git",
|
|
39
|
-
"url": "https://github.com/MaskingTechnology/jitar"
|
|
47
|
+
"url": "git+https://github.com/MaskingTechnology/jitar.git"
|
|
40
48
|
},
|
|
41
49
|
"bugs": {
|
|
42
50
|
"url": "https://github.com/MaskingTechnology/jitar/issues"
|
|
@@ -51,5 +59,6 @@
|
|
|
51
59
|
"monolith",
|
|
52
60
|
"full stack",
|
|
53
61
|
"web applications"
|
|
54
|
-
]
|
|
55
|
-
|
|
62
|
+
],
|
|
63
|
+
"gitHead": "d97e6378eae3cbf33c8b79a6ccbb29b5dfb41793"
|
|
64
|
+
}
|
package/dist/globals-d516de70.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const AccessLevel={PRIVATE:"private",PUBLIC:"public"};Object.freeze(AccessLevel);const AccessLevels=Object.values(AccessLevel);Object.freeze(AccessLevels);const Files={MODULE_PATTERN:"**/*.js",SEGMENT_PATTERN:"**/*.segment.json",NODE_SEGMENT_PATTERN:"**/*.segment.node.js",REPOSITORY_SEGMENT_PATTERN:"**/*.segment.repository.js"};function convertToLocalFilename(filename){return filename.replace(".js",".local.js")}function convertToRemoteFilename(filename){return filename.replace(".js",".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.")}Object.freeze(Files);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 Runtime{#url;#healthChecks=new Map;constructor(url){this.#url=url}get url(){return this.#url}addHealthCheck(name,healthCheck){this.#healthChecks.set(name,healthCheck)}async isHealthy(){for(const healthCheck of this.#healthChecks.values())if(!1===await healthCheck.isHealthy())return!1;return!0}async getHealth(){const health=new Map;for(const[name,healthCheck]of this.#healthChecks){const healthy=await healthCheck.isHealthy();health.set(name,healthy)}return health}}class ProcedureRunner{#runner;constructor(runner){this.#runner=runner}async handle(fqn,version,args,headers,next){const result=await this.#runner.run(fqn,version,args,headers);return headers.clear(),result}}class ProcedureRuntime extends Runtime{#middlewares=[];constructor(url){super(url),this.#middlewares.push(new ProcedureRunner(this))}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(fqn,version,args,headers){return this.#getNextHandler(fqn,version,args,headers,0)()}#getNextHandler(fqn,version,args,headers,index){const next=this.#middlewares[index];if(void 0===next)return async()=>{};const nextHandler=this.#getNextHandler(fqn,version,args,headers,index+1);return async()=>next.handle(fqn,version,args,headers,nextHandler)}}class Gateway extends ProcedureRuntime{}class UrlRewriter{static addBase(url,base){return url=this.#ensureStartsWithoutSlash(url),base=this.#assureEndWithSlash(base),this.#translateRelativeParts(`${base}${url}`)}static#ensureStartsWithoutSlash(url){return url.startsWith("/")?url.substring(1):url}static#assureEndWithSlash(base){return base.endsWith("/")?base:`${base}/`}static#translateRelativeParts(url){const parts=url.split("/"),translated=[];translated.push(parts[0]);for(let index=1;index<parts.length;index++){const part=parts[index].trim();"."!==part&&(".."!==part?translated.push(part):translated.pop())}return translated.join("/")}}const NON_SYSTEM_INDICATORS=[".","/","http:","https:"];let _baseUrl,_import=async name=>import(name);class ModuleLoader{static setBaseUrl(baseUrl){_baseUrl=baseUrl}static setImporter(importer){_import=importer}static assureExtension(specifier){return this.#isSystemModule(specifier)||specifier.endsWith(".js")?specifier:`${specifier}.js`}static async load(specifier){let url=this.assureExtension(specifier);if(url.startsWith("/jitar"))return specifier="jitar",this.#import(specifier,specifier);if(void 0!==_baseUrl&&!1===url.startsWith(_baseUrl)&&(url=UrlRewriter.addBase(url,_baseUrl),!1===url.startsWith(_baseUrl)))throw new ModuleNotAccessible(specifier);return this.#import(url,specifier)}static async import(specifier){return this.#import(specifier,specifier)}static async#import(absolute,relative){try{return await _import(absolute)}catch(error){const message=error instanceof Error?error.message:String(error);throw new ModuleNotLoaded(relative,message)}}static#isSystemModule(specifier){return!1===NON_SYSTEM_INDICATORS.some((indicator=>specifier.startsWith(indicator)))}}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(fqn,version,args,headers){const node=this.getNextNode();if(void 0===node)throw new NoNodeAvailable(fqn);return node.run(fqn,version,args,headers)}}const NO_SEGMENTS=[];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)}}async setBaseUrl(repository){const clientId=await repository.registerClient(NO_SEGMENTS),moduleLocation=await repository.getModuleLocation(clientId);ModuleLoader.setBaseUrl(moduleLocation)}#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(fqn,version,args,headers){const balancer=this.#getBalancer(fqn);if(void 0===balancer)throw new ProcedureNotFound(fqn);return balancer.run(fqn,version,args,headers)}}class Context{#headers=new Map;constructor(headers){this.#headers=headers}get headers(){return this.#headers}}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 RUNS_IN_BROWSER="undefined"!=typeof window;let _runtime,_loader=name=>ModuleLoader.import(name);class VersionParser{static parse(number){if(0===number.trim().length)return Version.DEFAULT;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]));case 3:return new Version(Number.parseInt(parts[0]),Number.parseInt(parts[1]),Number.parseInt(parts[2]));default:throw new InvalidVersionNumber(number)}}}class LocalNode extends Node{#argumentConstructor;#segments=new Map;#gateway;#repository;#clientId="";constructor(url,argumentConstructor=new ArgumentExtractor){super(url),this.#argumentConstructor=argumentConstructor}getProcedureNames(){const names=new Set;for(const segment of this.#segments.values()){segment.getPublicProcedures().forEach((procedure=>names.add(procedure.fqn)))}return[...names.values()]}async loadSegment(name){const filename=createNodeFilename(name),segment=(await this.import(filename)).segment;this.addSegment(segment)}addSegment(segment){this.#segments.set(segment.id,segment)}hasProcedure(fqn){return this.getProcedureNames().includes(fqn)}#getProcedure(fqn){for(const segment of this.#segments.values())if(segment.hasProcedure(fqn))return segment.getProcedure(fqn)}async setGateway(gateway){(gateway instanceof LocalGateway||void 0!==this.url)&&await gateway.addNode(this),this.#gateway=gateway}async setRepository(repository,segmentNames){this.#clientId=await repository.registerClient(segmentNames),_runtime=this,_loader=name=>ModuleLoader.import(name);const moduleLocation=await repository.getModuleLocation(this.#clientId);ModuleLoader.setBaseUrl(moduleLocation),this.#repository=repository}import(url,base){if(void 0===this.#repository)throw new RepositoryNotAvailable;return void 0!==base&&(url=UrlRewriter.addBase(url,base)),this.#repository.importModule(this.#clientId,url)}run(fqn,version,args,headers){const procedure=this.#getProcedure(fqn);return void 0===procedure?this.#runGateway(fqn,version,args,headers):this.#runProcedure(procedure,version,args,headers)}#runGateway(fqn,version,args,headers){if(void 0===this.#gateway)throw new ProcedureNotFound(fqn);return this.#gateway.run(fqn,version,args,headers)}#runProcedure(procedure,version,args,headers){const implementation=procedure.getImplementation(version);if(void 0===implementation)throw new ImplementationNotFound(procedure.fqn,version.toString());const context=new Context(headers),values=this.#argumentConstructor.extract(implementation.parameters,args);return implementation.executable.call(context,...values)}}class Repository extends Runtime{}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 await Promise.all(array.map((async value=>await this.deserializeOther(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(){return`class ${this.name}${void 0!==this.#parentName?` extends ${this.#parentName}`:""} { ${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(){return`export { ${this.#members.join(", ")} }${this.#from?` from '${this.#from}'`:""}`}}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={COMMA:",",COLON:":",SEMICOLON:";",DOT:".",QUESTION_MARK:"?",EXCLAMATION_MARK:"!",LEFT_PARENTHESIS:"(",RIGHT_PARENTHESIS:")",LEFT_BRACKET:"[",RIGHT_BRACKET:"]",LEFT_BRACE:"{",RIGHT_BRACE:"}",SINGLE_QUOTE:"'",DOUBLE_QUOTE:'"',BACKTICK:"`"};Object.values(Punctuation);const Divider={SCOPE:Punctuation.COLON,SEPARATOR:Punctuation.COMMA,TERMINATOR:Punctuation.SEMICOLON},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)}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,omitWhitespace=!0,omitComments=!0){const charList=new CharList(code),tokens=[];let last;for(;charList.notAtEnd();){const token=this.#getNextToken(charList,last);if(void 0===token)break;omitWhitespace&&token.isType(TokenType.WHITESPACE)?charList.step():(omitComments&&token.isType(TokenType.COMMENT)||(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))return token.hasValue(Keyword.ASYNC)?(tokenList.step(),this.#parseNext(tokenList,!0)):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=token.isType(TokenType.IDENTIFIER)?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()),token.isType(TokenType.IDENTIFIER)&&(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(token.isType(TokenType.IDENTIFIER)&&(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)}}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=>await 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 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=>await 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 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;#useSerializer;#serializer;constructor(url,useSerializer,serializer=defaultSerializer){this.#url=url,this.#useSerializer=useSerializer,this.#serializer=serializer}async registerClient(segmentFiles){const url=`${this.#url}/modules`,options={method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(segmentFiles)},response=await this.#callRemote(url,options,200);return await response.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)}importFile(filename){const url=`${this.#url}/${filename}`;return ModuleLoader.load(url)}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(fqn,version,args,headers){headers.set("content-type","application/json");const versionString=version.toString(),argsObject=Object.fromEntries(args),headersObject=Object.fromEntries(headers),url=`${this.#url}/rpc/${fqn}?version=${versionString}&serialize=true`,options={method:"POST",headers:headersObject,body:await this.#createRequestBody(argsObject,this.#useSerializer)},response=await this.#callRemote(url,options,200);return this.#createResponseResult(response,this.#useSerializer)}async#callRemote(url,options,expectedStatus){const response=await fetch(url,options);if(response.status!==expectedStatus){throw await this.#createResponseResult(response,!0)}return response}async#createRequestBody(body,serialize){const data=serialize?await this.#serializer.serialize(body):body;return JSON.stringify(data)}async#createResponseResult(response,serialize){const result=await this.#getResponseResult(response);return serialize?this.#serializer.deserialize(result):result}#getResponseResult(response){const contentType=response.headers.get("Content-Type");return null!==contentType&&contentType.includes("json")?response.json():response.text()}}class RemoteGateway extends Gateway{#remote;constructor(url){super(url),this.#remote=new Remote(url,!0)}getProcedureNames(){throw new NotImplemented}hasProcedure(name){throw new NotImplemented}addNode(node){return this.#remote.addNode(node)}run(fqn,version,args,headers){return this.#remote.run(fqn,version,args,headers)}}class RemoteRepository extends Repository{#remote;constructor(url){super(url),this.#remote=new Remote(url,!0)}registerClient(segmentFiles){return this.#remote.registerClient(segmentFiles)}loadAsset(filename){return this.#remote.loadFile(filename)}async getModuleLocation(clientId){return`${this.url}/modules/${clientId}`}async loadModule(clientId,filename){return this.#remote.loadFile(`modules/${clientId}/${filename}`)}async importModule(clientId,filename){return this.#remote.importFile(`modules/${clientId}/${filename}`)}}const globals=globalThis;globals.__getDependency=async function(name){RUNS_IN_BROWSER&&"jitar"===name&&(name="/jitar/client.js");const module=await _loader(name);return void 0!==module.default?module.default:module},globals.__runProcedure=async function(fqn,versionNumber,args,context){if(void 0===_runtime)throw new RuntimeNotAvailable;const version=VersionParser.parse(versionNumber),argsMap=new Map(Object.entries(args)),headersMap=context instanceof Context?context.headers:new Map;return _runtime.run(fqn,version,argsMap,headersMap)},globals.ProcedureNotAccessible=ProcedureNotAccessible;export{RuntimeNotAvailable as $,AccessLevel as A,BadRequest as B,ClientNotFound as C,ArrayParameter as D,ServerError as E,FileNotFound as F,ImplementationNotFound as G,InvalidParameterValue as H,InvalidSegmentFile as I,InvalidVersionNumber as J,MissingParameterValue as K,LocalGateway as L,ModuleLoader as M,Node as N,ObjectParameter as O,ProcedureRuntime as P,ModuleNotAccessible as Q,Repository as R,SerializerBuilder as S,Teapot as T,Unauthorized as U,VersionParser as V,ModuleNotLoaded as W,NoNodeAvailable as X,ProcedureNotAccessible as Y,ProcedureNotFound as Z,RepositoryNotAvailable as _,InvalidClientId as a,SegmentNotFound as a0,UnknownParameter as a1,File as b,convertToLocalFilename as c,convertToRemoteFilename as d,createRepositoryFilename as e,ProcedureRunner as f,Remote as g,Reflector as h,isSegmentFilename as i,ReflectionField as j,ReflectionDestructuredArray as k,ReflectionDestructuredObject as l,ReflectionDestructuredValue as m,createNodeFilename as n,ReflectionFunction as o,Files as p,LocalNode as q,RemoteRepository as r,RemoteGateway as s,PaymentRequired as t,Forbidden as u,NotFound as v,NotImplemented as w,Version as x,RemoteClassLoader as y,NamedParameter as z};
|