jitar 0.3.8 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/CHANGELOG.md +1 -84
  2. package/dist/client.js +1 -24
  3. package/dist/globals-d516de70.js +1 -0
  4. package/dist/lib.d.ts +309 -35
  5. package/dist/lib.js +1 -29
  6. package/dist/server.js +1 -0
  7. package/package.json +19 -12
  8. package/LICENCE +0 -23
  9. package/dist/client.d.ts +0 -3
  10. package/dist/core/Context.d.ts +0 -5
  11. package/dist/core/Context.js +0 -7
  12. package/dist/core/ErrorManager.d.ts +0 -3
  13. package/dist/core/ErrorManager.js +0 -11
  14. package/dist/core/Implementation.d.ts +0 -10
  15. package/dist/core/Implementation.js +0 -44
  16. package/dist/core/Procedure.d.ts +0 -13
  17. package/dist/core/Procedure.js +0 -58
  18. package/dist/core/Segment.d.ts +0 -13
  19. package/dist/core/Segment.js +0 -36
  20. package/dist/core/SegmentBuilder.d.ts +0 -6
  21. package/dist/core/SegmentBuilder.js +0 -32
  22. package/dist/core/Version.d.ts +0 -13
  23. package/dist/core/Version.js +0 -50
  24. package/dist/core/definitions/AccessLevel.d.ts +0 -2
  25. package/dist/core/definitions/AccessLevel.js +0 -2
  26. package/dist/core/errors/BadRequest.d.ts +0 -3
  27. package/dist/core/errors/BadRequest.js +0 -6
  28. package/dist/core/errors/Forbidden.d.ts +0 -3
  29. package/dist/core/errors/Forbidden.js +0 -6
  30. package/dist/core/errors/ImplementationNotFound.d.ts +0 -4
  31. package/dist/core/errors/ImplementationNotFound.js +0 -7
  32. package/dist/core/errors/InvalidVersionNumber.d.ts +0 -4
  33. package/dist/core/errors/InvalidVersionNumber.js +0 -7
  34. package/dist/core/errors/MissingParameterValue.d.ts +0 -4
  35. package/dist/core/errors/MissingParameterValue.js +0 -7
  36. package/dist/core/errors/NotFound.d.ts +0 -3
  37. package/dist/core/errors/NotFound.js +0 -6
  38. package/dist/core/errors/NotImplemented.d.ts +0 -3
  39. package/dist/core/errors/NotImplemented.js +0 -6
  40. package/dist/core/errors/PaymentRequired.d.ts +0 -3
  41. package/dist/core/errors/PaymentRequired.js +0 -6
  42. package/dist/core/errors/ProcedureNotFound.d.ts +0 -4
  43. package/dist/core/errors/ProcedureNotFound.js +0 -7
  44. package/dist/core/errors/Teapot.d.ts +0 -3
  45. package/dist/core/errors/Teapot.js +0 -6
  46. package/dist/core/errors/Unauthorized.d.ts +0 -3
  47. package/dist/core/errors/Unauthorized.js +0 -6
  48. package/dist/core/errors/UnknownParameter.d.ts +0 -4
  49. package/dist/core/errors/UnknownParameter.js +0 -7
  50. package/dist/core/interfaces/Runner.d.ts +0 -4
  51. package/dist/core/interfaces/Runner.js +0 -1
  52. package/dist/core/reflection/ParameterParser.d.ts +0 -5
  53. package/dist/core/reflection/ParameterParser.js +0 -51
  54. package/dist/core/reflection/ReflectionHelper.d.ts +0 -13
  55. package/dist/core/reflection/ReflectionHelper.js +0 -69
  56. package/dist/core/reflection/models/ReflectionField.d.ts +0 -8
  57. package/dist/core/reflection/models/ReflectionField.js +0 -14
  58. package/dist/core/reflection/models/ReflectionParameter.d.ts +0 -7
  59. package/dist/core/reflection/models/ReflectionParameter.js +0 -11
  60. package/dist/core/types/Component.d.ts +0 -5
  61. package/dist/core/types/Component.js +0 -1
  62. package/dist/core/types/FlexObject.d.ts +0 -4
  63. package/dist/core/types/FlexObject.js +0 -1
  64. package/dist/core/types/Module.d.ts +0 -3
  65. package/dist/core/types/Module.js +0 -1
  66. package/dist/core/types/SegmentImplementation.d.ts +0 -6
  67. package/dist/core/types/SegmentImplementation.js +0 -1
  68. package/dist/core/types/SegmentModule.d.ts +0 -5
  69. package/dist/core/types/SegmentModule.js +0 -1
  70. package/dist/core/types/SegmentProcedure.d.ts +0 -7
  71. package/dist/core/types/SegmentProcedure.js +0 -1
  72. package/dist/core/utils/FqnBuilder.d.ts +0 -3
  73. package/dist/core/utils/FqnBuilder.js +0 -5
  74. package/dist/hooks.d.ts +0 -2
  75. package/dist/hooks.js +0 -2
  76. package/dist/runtime/ClientId.d.ts +0 -4
  77. package/dist/runtime/ClientId.js +0 -11
  78. package/dist/runtime/Gateway.d.ts +0 -5
  79. package/dist/runtime/Gateway.js +0 -3
  80. package/dist/runtime/LocalGateway.d.ts +0 -14
  81. package/dist/runtime/LocalGateway.js +0 -61
  82. package/dist/runtime/LocalNode.d.ts +0 -18
  83. package/dist/runtime/LocalNode.js +0 -75
  84. package/dist/runtime/LocalRepository.d.ts +0 -17
  85. package/dist/runtime/LocalRepository.js +0 -94
  86. package/dist/runtime/Node.d.ts +0 -3
  87. package/dist/runtime/Node.js +0 -3
  88. package/dist/runtime/NodeBalancer.d.ts +0 -9
  89. package/dist/runtime/NodeBalancer.js +0 -34
  90. package/dist/runtime/NodeMonitor.d.ts +0 -7
  91. package/dist/runtime/NodeMonitor.js +0 -38
  92. package/dist/runtime/ProcedureRunner.d.ts +0 -9
  93. package/dist/runtime/ProcedureRunner.js +0 -11
  94. package/dist/runtime/ProcedureRuntime.d.ts +0 -13
  95. package/dist/runtime/ProcedureRuntime.js +0 -25
  96. package/dist/runtime/Proxy.d.ts +0 -18
  97. package/dist/runtime/Proxy.js +0 -33
  98. package/dist/runtime/Remote.d.ts +0 -15
  99. package/dist/runtime/Remote.js +0 -102
  100. package/dist/runtime/RemoteGateway.d.ts +0 -11
  101. package/dist/runtime/RemoteGateway.js +0 -22
  102. package/dist/runtime/RemoteNode.d.ts +0 -12
  103. package/dist/runtime/RemoteNode.js +0 -29
  104. package/dist/runtime/RemoteRepository.d.ts +0 -14
  105. package/dist/runtime/RemoteRepository.js +0 -34
  106. package/dist/runtime/Repository.d.ts +0 -11
  107. package/dist/runtime/Repository.js +0 -3
  108. package/dist/runtime/Runtime.d.ts +0 -9
  109. package/dist/runtime/Runtime.js +0 -27
  110. package/dist/runtime/caching/CacheBuilder.d.ts +0 -6
  111. package/dist/runtime/caching/CacheBuilder.js +0 -246
  112. package/dist/runtime/caching/ImportRewriter.d.ts +0 -4
  113. package/dist/runtime/caching/ImportRewriter.js +0 -58
  114. package/dist/runtime/caching/RemoteBuilder.d.ts +0 -5
  115. package/dist/runtime/caching/RemoteBuilder.js +0 -31
  116. package/dist/runtime/caching/SourceAppender.d.ts +0 -5
  117. package/dist/runtime/caching/SourceAppender.js +0 -30
  118. package/dist/runtime/caching/definitions/Keywords.d.ts +0 -2
  119. package/dist/runtime/caching/definitions/Keywords.js +0 -2
  120. package/dist/runtime/caching/errors/InvalidSegmentFilename.d.ts +0 -3
  121. package/dist/runtime/caching/errors/InvalidSegmentFilename.js +0 -5
  122. package/dist/runtime/caching/errors/MissingModuleExport.d.ts +0 -3
  123. package/dist/runtime/caching/errors/MissingModuleExport.js +0 -5
  124. package/dist/runtime/caching/errors/SegmentFileNotLoaded.d.ts +0 -3
  125. package/dist/runtime/caching/errors/SegmentFileNotLoaded.js +0 -5
  126. package/dist/runtime/caching/errors/SegmentModuleNotLoaded.d.ts +0 -3
  127. package/dist/runtime/caching/errors/SegmentModuleNotLoaded.js +0 -5
  128. package/dist/runtime/caching/models/ApplicationModule.d.ts +0 -10
  129. package/dist/runtime/caching/models/ApplicationModule.js +0 -19
  130. package/dist/runtime/caching/models/Implementation.d.ts +0 -12
  131. package/dist/runtime/caching/models/Implementation.js +0 -27
  132. package/dist/runtime/caching/models/Procedure.d.ts +0 -9
  133. package/dist/runtime/caching/models/Procedure.js +0 -15
  134. package/dist/runtime/caching/models/Segment.d.ts +0 -10
  135. package/dist/runtime/caching/models/Segment.js +0 -16
  136. package/dist/runtime/caching/models/SegmentModule.d.ts +0 -10
  137. package/dist/runtime/caching/models/SegmentModule.js +0 -14
  138. package/dist/runtime/caching/types/SegmentFile.d.ts +0 -5
  139. package/dist/runtime/caching/types/SegmentFile.js +0 -1
  140. package/dist/runtime/caching/types/SegmentImportProperties.d.ts +0 -6
  141. package/dist/runtime/caching/types/SegmentImportProperties.js +0 -1
  142. package/dist/runtime/caching/types/SegmentImports.d.ts +0 -5
  143. package/dist/runtime/caching/types/SegmentImports.js +0 -1
  144. package/dist/runtime/errors/ClientNotFound.d.ts +0 -3
  145. package/dist/runtime/errors/ClientNotFound.js +0 -6
  146. package/dist/runtime/errors/FileNotFound.d.ts +0 -3
  147. package/dist/runtime/errors/FileNotFound.js +0 -6
  148. package/dist/runtime/errors/InvalidClientId.d.ts +0 -3
  149. package/dist/runtime/errors/InvalidClientId.js +0 -6
  150. package/dist/runtime/errors/InvalidJitarHooks.d.ts +0 -3
  151. package/dist/runtime/errors/InvalidJitarHooks.js +0 -6
  152. package/dist/runtime/errors/InvalidSegmentFile.d.ts +0 -3
  153. package/dist/runtime/errors/InvalidSegmentFile.js +0 -6
  154. package/dist/runtime/errors/ModuleNotLoaded.d.ts +0 -3
  155. package/dist/runtime/errors/ModuleNotLoaded.js +0 -6
  156. package/dist/runtime/errors/NoNodeAvailable.d.ts +0 -3
  157. package/dist/runtime/errors/NoNodeAvailable.js +0 -6
  158. package/dist/runtime/errors/RepositoryNotAvaiable.d.ts +0 -3
  159. package/dist/runtime/errors/RepositoryNotAvaiable.js +0 -6
  160. package/dist/runtime/errors/RuntimeNotAvailable.d.ts +0 -3
  161. package/dist/runtime/errors/RuntimeNotAvailable.js +0 -6
  162. package/dist/runtime/errors/SegmentNotFound.d.ts +0 -3
  163. package/dist/runtime/errors/SegmentNotFound.js +0 -6
  164. package/dist/runtime/hooks/dependencies.d.ts +0 -2
  165. package/dist/runtime/hooks/dependencies.js +0 -9
  166. package/dist/runtime/hooks/runtime.d.ts +0 -3
  167. package/dist/runtime/hooks/runtime.js +0 -16
  168. package/dist/runtime/interfaces/FileManager.d.ts +0 -11
  169. package/dist/runtime/interfaces/FileManager.js +0 -1
  170. package/dist/runtime/interfaces/HealthCheck.d.ts +0 -3
  171. package/dist/runtime/interfaces/HealthCheck.js +0 -1
  172. package/dist/runtime/interfaces/Middleware.d.ts +0 -5
  173. package/dist/runtime/interfaces/Middleware.js +0 -1
  174. package/dist/runtime/middleware/CorsMiddleware.d.ts +0 -8
  175. package/dist/runtime/middleware/CorsMiddleware.js +0 -19
  176. package/dist/runtime/models/File.d.ts +0 -9
  177. package/dist/runtime/models/File.js +0 -14
  178. package/dist/runtime/serialization/ArrayBufferSerializer.d.ts +0 -10
  179. package/dist/runtime/serialization/ArrayBufferSerializer.js +0 -54
  180. package/dist/runtime/serialization/ArraySerializer.d.ts +0 -7
  181. package/dist/runtime/serialization/ArraySerializer.js +0 -15
  182. package/dist/runtime/serialization/ClassSerializer.d.ts +0 -10
  183. package/dist/runtime/serialization/ClassSerializer.js +0 -74
  184. package/dist/runtime/serialization/DateSerializer.d.ts +0 -9
  185. package/dist/runtime/serialization/DateSerializer.js +0 -21
  186. package/dist/runtime/serialization/MapSerializer.d.ts +0 -9
  187. package/dist/runtime/serialization/MapSerializer.js +0 -35
  188. package/dist/runtime/serialization/ObjectSerializer.d.ts +0 -9
  189. package/dist/runtime/serialization/ObjectSerializer.js +0 -21
  190. package/dist/runtime/serialization/SetSerializer.d.ts +0 -9
  191. package/dist/runtime/serialization/SetSerializer.js +0 -23
  192. package/dist/runtime/serialization/ValueSerializer.d.ts +0 -8
  193. package/dist/runtime/serialization/ValueSerializer.js +0 -69
  194. package/dist/runtime/serialization/errors/ClassNotFound.d.ts +0 -3
  195. package/dist/runtime/serialization/errors/ClassNotFound.js +0 -6
  196. package/dist/runtime/serialization/errors/InvalidClass.d.ts +0 -3
  197. package/dist/runtime/serialization/errors/InvalidClass.js +0 -6
  198. package/dist/runtime/serialization/errors/InvalidPropertyType.d.ts +0 -4
  199. package/dist/runtime/serialization/errors/InvalidPropertyType.js +0 -7
  200. package/dist/runtime/serialization/interfaces/Serializer.d.ts +0 -4
  201. package/dist/runtime/serialization/interfaces/Serializer.js +0 -1
  202. package/dist/runtime/serialization/types/SerializableObject.d.ts +0 -3
  203. package/dist/runtime/serialization/types/SerializableObject.js +0 -1
  204. package/dist/runtime/serialization/types/Serialized.d.ts +0 -5
  205. package/dist/runtime/serialization/types/Serialized.js +0 -1
  206. package/dist/runtime/serialization/types/SerializedArrayBuffer.d.ts +0 -6
  207. package/dist/runtime/serialization/types/SerializedArrayBuffer.js +0 -1
  208. package/dist/runtime/serialization/types/SerializedClass.d.ts +0 -8
  209. package/dist/runtime/serialization/types/SerializedClass.js +0 -1
  210. package/dist/runtime/serialization/types/SerializedDate.d.ts +0 -5
  211. package/dist/runtime/serialization/types/SerializedDate.js +0 -1
  212. package/dist/runtime/serialization/types/SerializedMap.d.ts +0 -8
  213. package/dist/runtime/serialization/types/SerializedMap.js +0 -1
  214. package/dist/runtime/serialization/types/SerializedObject.d.ts +0 -4
  215. package/dist/runtime/serialization/types/SerializedObject.js +0 -1
  216. package/dist/runtime/serialization/types/SerializedSet.d.ts +0 -5
  217. package/dist/runtime/serialization/types/SerializedSet.js +0 -1
  218. package/dist/runtime/serialization/types/TypedArray.d.ts +0 -2
  219. package/dist/runtime/serialization/types/TypedArray.js +0 -1
  220. package/dist/runtime/types/JitarHooks.d.ts +0 -6
  221. package/dist/runtime/types/JitarHooks.js +0 -1
  222. package/dist/runtime/types/ModuleImporter.d.ts +0 -3
  223. package/dist/runtime/types/ModuleImporter.js +0 -1
  224. package/dist/runtime/types/NextHandler.d.ts +0 -2
  225. package/dist/runtime/types/NextHandler.js +0 -1
  226. package/dist/runtime/utils/ModuleAnalyser.d.ts +0 -7
  227. package/dist/runtime/utils/ModuleAnalyser.js +0 -23
  228. package/dist/runtime/utils/ModuleLoader.d.ts +0 -8
  229. package/dist/runtime/utils/ModuleLoader.js +0 -30
  230. package/dist/runtime/utils/UrlRewriter.d.ts +0 -4
  231. package/dist/runtime/utils/UrlRewriter.js +0 -36
package/dist/lib.js CHANGED
@@ -1,30 +1,2 @@
1
- export { default as Version } from './core/Version.js';
2
- export { default as Forbidden } from './core/errors/Forbidden.js';
3
- export { default as BadRequest } from './core/errors/BadRequest.js';
4
- export { default as NotFound } from './core/errors/NotFound.js';
5
- export { default as NotImplemented } from './core/errors/NotImplemented.js';
6
- export { default as PaymentRequired } from './core/errors/PaymentRequired.js';
7
- export { default as Teapot } from './core/errors/Teapot.js';
8
- export { default as Unauthorized } from './core/errors/Unauthorized.js';
9
- export { default as FileNotFound } from './runtime/errors/FileNotFound.js';
10
- export { default as LocalRepository } from './runtime/LocalRepository.js';
11
- export { default as LocalNode } from './runtime/LocalNode.js';
12
- export { default as Proxy } from './runtime/Proxy.js';
13
- export { default as ValueSerializer } from './runtime/serialization/ValueSerializer.js';
14
- export { default as ClientId } from './runtime/ClientId.js';
15
- export { default as RemoteNode } from './runtime/RemoteNode.js';
16
- export { default as LocalGateway } from './runtime/LocalGateway.js';
17
- export { default as ProcedureRuntime } from './runtime/ProcedureRuntime.js';
18
- export { default as File } from './runtime/models/File.js';
19
- export { default as CacheBuilder } from './runtime/caching/CacheBuilder.js';
20
- export { default as Gateway } from './runtime/Gateway.js';
21
- export { default as Node } from './runtime/Node.js';
22
- export { default as NodeMonitor } from './runtime/NodeMonitor.js';
23
- export { default as RemoteGateway } from './runtime/RemoteGateway.js';
24
- export { default as Repository } from './runtime/Repository.js';
25
- export { default as Runtime } from './runtime/Runtime.js';
26
- export { default as RemoteRepository } from './runtime/RemoteRepository.js';
27
- export { default as CorsMiddleware } from './runtime/middleware/CorsMiddleware.js';
28
- export { default as ModuleLoader } from './runtime/utils/ModuleLoader.js';
29
1
  export * from './client.js';
30
- export * from './hooks.js';
2
+ export * from './server.js';
package/dist/server.js ADDED
@@ -0,0 +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};
package/package.json CHANGED
@@ -1,27 +1,35 @@
1
1
  {
2
2
  "name": "jitar",
3
- "version": "0.3.8",
3
+ "version": "0.4.0",
4
4
  "description": "Distributed runtime for JavaScript and TypeScript to chop monolithic applications into micros.",
5
5
  "author": "Masking Technology <info@masking.tech> (https://jitar.dev)",
6
6
  "license": "MIT",
7
7
  "type": "module",
8
- "types": "dist/lib.d.ts",
8
+ "types": "./dist/lib.d.ts",
9
9
  "sideEffects": true,
10
10
  "exports": {
11
11
  ".": "./dist/lib.js",
12
- "./client.js": "./dist/client.js",
13
- "./hooks.js": "./dist/hooks.js"
12
+ "./server": "./dist/server.js",
13
+ "./client": "./dist/client.js"
14
14
  },
15
15
  "scripts": {
16
- "test": "vitest run",
17
- "test-coverage": "vitest run --coverage",
18
16
  "lint": "eslint . --ext .ts",
19
- "build": "tsc -p tsconfig.json",
20
- "clean": "rm -rf dist build",
17
+ "validate": "tsc -p tsconfig.json --noEmit",
18
+ "build": "npm run clean && rollup -c",
19
+ "clean": "rm -rf dist",
21
20
  "release": "npm run clean && npm run build && npm publish"
22
21
  },
23
22
  "dependencies": {
24
- "jitar-reflection": "^0.3.7"
23
+ "@jitar/runtime": "^0.4.0",
24
+ "@jitar/server-nodejs": "^0.4.0",
25
+ "express": "^4.18.2",
26
+ "express-http-proxy": "^1.6.3",
27
+ "fs-extra": "^11.1.1",
28
+ "glob-promise": "6.0.2",
29
+ "mime-types": "^2.1.35",
30
+ "tslog": "^4.8.2",
31
+ "yargs": "^17.7.2",
32
+ "zod": "^3.21.4"
25
33
  },
26
34
  "engines": {
27
35
  "node": ">=18.7"
@@ -43,6 +51,5 @@
43
51
  "monolith",
44
52
  "full stack",
45
53
  "web applications"
46
- ],
47
- "gitHead": "8eafe79ce9317964f843301bc2fbf6278a4fb88f"
48
- }
54
+ ]
55
+ }
package/LICENCE DELETED
@@ -1,23 +0,0 @@
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.d.ts DELETED
@@ -1,3 +0,0 @@
1
- import LocalNode from './runtime/LocalNode.js';
2
- export declare function startClient(...segmentFiles: string[]): Promise<LocalNode>;
3
- export declare function getClient(): Promise<LocalNode>;
@@ -1,5 +0,0 @@
1
- export default class Context {
2
- #private;
3
- constructor(headers: Map<string, string>);
4
- get headers(): Map<string, string>;
5
- }
@@ -1,7 +0,0 @@
1
- export default class Context {
2
- #headers = new Map();
3
- constructor(headers) {
4
- this.#headers = headers;
5
- }
6
- get headers() { return this.#headers; }
7
- }
@@ -1,3 +0,0 @@
1
- export default class ErrorManager {
2
- static handle(error: unknown, name: string, version: string): Error;
3
- }
@@ -1,11 +0,0 @@
1
- export default class ErrorManager {
2
- static handle(error, name, version) {
3
- const parentMessage = error instanceof Error ? error.message : String(error);
4
- const newMessage = `${parentMessage}\n[${name} | v${version}]`;
5
- if (error instanceof Error) {
6
- error.message = newMessage;
7
- return error;
8
- }
9
- return new Error(newMessage);
10
- }
11
- }
@@ -1,10 +0,0 @@
1
- import ReflectionParameter from './reflection/models/ReflectionParameter.js';
2
- import Version from './Version.js';
3
- export default class Implementation {
4
- #private;
5
- constructor(version: Version, access: string, parameters: ReflectionParameter[], executable: Function);
6
- get version(): Version;
7
- get public(): boolean;
8
- get parameters(): ReflectionParameter[];
9
- run(args: Map<string, unknown>, headers: Map<string, string>): Promise<unknown>;
10
- }
@@ -1,44 +0,0 @@
1
- import MissingParameterValue from './errors/MissingParameterValue.js';
2
- import UnknownParameter from './errors/UnknownParameter.js';
3
- import * as AccessLevel from './definitions/AccessLevel.js';
4
- import Context from './Context.js';
5
- export default class Implementation {
6
- #version;
7
- #access;
8
- #parameters;
9
- #executable;
10
- constructor(version, access, parameters, executable) {
11
- this.#version = version;
12
- this.#access = access;
13
- this.#parameters = parameters;
14
- this.#executable = executable;
15
- }
16
- get version() { return this.#version; }
17
- get public() { return this.#access === AccessLevel.PUBLIC; }
18
- get parameters() { return this.#parameters; }
19
- async run(args, headers) {
20
- const context = this.#createContext(headers);
21
- const values = this.#extractParameterValues(args);
22
- return await this.#executable.call(context, ...values);
23
- }
24
- #createContext(headers) {
25
- return new Context(headers);
26
- }
27
- #extractParameterValues(parameters) {
28
- const values = [];
29
- const incommingKeys = Array.from(parameters.keys());
30
- const knownKeys = this.#parameters.map(parameter => parameter.name);
31
- const additionalKeys = incommingKeys.filter(key => knownKeys.includes(key) === false);
32
- if (additionalKeys.length !== 0) {
33
- throw new UnknownParameter(additionalKeys[0]);
34
- }
35
- for (const parameter of this.#parameters) {
36
- const value = parameters.get(parameter.name);
37
- if (value === undefined && parameter.isOptional === false) {
38
- throw new MissingParameterValue(parameter.name);
39
- }
40
- values.push(value);
41
- }
42
- return values;
43
- }
44
- }
@@ -1,13 +0,0 @@
1
- import Implementation from './Implementation.js';
2
- import Version from './Version.js';
3
- export default class Procedure {
4
- #private;
5
- constructor(module: string, name: string);
6
- get module(): string;
7
- get name(): string;
8
- get fqn(): string;
9
- get public(): boolean;
10
- addImplementation(implementation: Implementation): void;
11
- getImplementation(version: Version): Implementation | undefined;
12
- run(version: Version, args: Map<string, unknown>, headers: Map<string, string>): Promise<unknown>;
13
- }
@@ -1,58 +0,0 @@
1
- import ImplementationNotFound from './errors/ImplementationNotFound.js';
2
- import FqnBuilder from './utils/FqnBuilder.js';
3
- import Version from './Version.js';
4
- export default class Procedure {
5
- #module;
6
- #name;
7
- #fqn;
8
- #implementations = new Map();
9
- #latestImplementation;
10
- constructor(module, name) {
11
- this.#module = module;
12
- this.#name = name;
13
- this.#fqn = FqnBuilder.build(module, name);
14
- }
15
- get module() { return this.#module; }
16
- get name() { return this.#name; }
17
- get fqn() { return this.#fqn; }
18
- get public() {
19
- const implementations = [...this.#implementations.values()];
20
- return implementations.some(implementation => implementation.public);
21
- }
22
- addImplementation(implementation) {
23
- this.#implementations.set(implementation.version, implementation);
24
- if (this.#isNewLatestImplementation(implementation)) {
25
- this.#latestImplementation = implementation;
26
- }
27
- }
28
- #isNewLatestImplementation(implementation) {
29
- return this.#latestImplementation === undefined
30
- || implementation.version.greater(this.#latestImplementation.version);
31
- }
32
- getImplementation(version) {
33
- const selectedVersion = this.#selectAvailableVersion(version);
34
- return this.#implementations.get(selectedVersion);
35
- }
36
- #selectAvailableVersion(version) {
37
- let selectedVersion = Version.DEFAULT;
38
- for (const implementationVersion of this.#implementations.keys()) {
39
- if (implementationVersion.equals(version)) {
40
- return implementationVersion;
41
- }
42
- if (implementationVersion.greater(version)) {
43
- continue;
44
- }
45
- if (selectedVersion.less(implementationVersion)) {
46
- selectedVersion = implementationVersion;
47
- }
48
- }
49
- return selectedVersion;
50
- }
51
- async run(version, args, headers) {
52
- const implementation = this.getImplementation(version);
53
- if (implementation === undefined) {
54
- throw new ImplementationNotFound(this.fqn, version.toString());
55
- }
56
- return implementation.run(args, headers);
57
- }
58
- }
@@ -1,13 +0,0 @@
1
- import Runner from './interfaces/Runner.js';
2
- import Procedure from './Procedure.js';
3
- import Version from './Version.js';
4
- export default class Segment implements Runner {
5
- #private;
6
- constructor(id: string);
7
- get id(): string;
8
- addProcedure(procedure: Procedure): void;
9
- hasProcedure(fqn: string): boolean;
10
- getProcedure(fqn: string): Procedure | undefined;
11
- getPublicProcedures(): Procedure[];
12
- run(fqn: string, version: Version, args: Map<string, unknown>, headers: Map<string, string>): Promise<unknown>;
13
- }
@@ -1,36 +0,0 @@
1
- import ErrorManager from './ErrorManager.js';
2
- import ProcedureNotFound from './errors/ProcedureNotFound.js';
3
- export default class Segment {
4
- #id;
5
- #procedures = new Map();
6
- constructor(id) {
7
- this.#id = id;
8
- }
9
- get id() { return this.#id; }
10
- addProcedure(procedure) {
11
- this.#procedures.set(procedure.fqn, procedure);
12
- }
13
- hasProcedure(fqn) {
14
- const procedure = this.getProcedure(fqn);
15
- return procedure !== undefined;
16
- }
17
- getProcedure(fqn) {
18
- return this.#procedures.get(fqn);
19
- }
20
- getPublicProcedures() {
21
- const procedures = [...this.#procedures.values()];
22
- return procedures.filter(procedure => procedure.public);
23
- }
24
- async run(fqn, version, args, headers) {
25
- const procedure = this.getProcedure(fqn);
26
- if (procedure === undefined) {
27
- throw new ProcedureNotFound(fqn);
28
- }
29
- try {
30
- return await procedure.run(version, args, headers);
31
- }
32
- catch (error) {
33
- throw ErrorManager.handle(error, fqn, version.toString());
34
- }
35
- }
36
- }
@@ -1,6 +0,0 @@
1
- import SegmentModule from './types/SegmentModule.js';
2
- import Segment from './Segment.js';
3
- export default class SegmentBuilder {
4
- #private;
5
- static build(id: string, module: SegmentModule): Segment;
6
- }
@@ -1,32 +0,0 @@
1
- import ReflectionHelper from './reflection/ReflectionHelper.js';
2
- import Implementation from './Implementation.js';
3
- import Procedure from './Procedure.js';
4
- import Segment from './Segment.js';
5
- import Version from './Version.js';
6
- export default class SegmentBuilder {
7
- static build(id, module) {
8
- const segment = new Segment(id);
9
- for (const definition of module.procedures) {
10
- const procedure = this.#buildProcedure(definition);
11
- segment.addProcedure(procedure);
12
- }
13
- return segment;
14
- }
15
- static #buildProcedure(definition) {
16
- const module = definition.module;
17
- const name = definition.name;
18
- const procedure = new Procedure(module, name);
19
- for (const implementationDefinition of definition.implementations) {
20
- const implementation = this.#buildImplementation(implementationDefinition);
21
- procedure.addImplementation(implementation);
22
- }
23
- return procedure;
24
- }
25
- static #buildImplementation(definition) {
26
- const version = Version.parse(definition.version);
27
- const access = definition.access;
28
- const executable = definition.executable;
29
- const parameters = ReflectionHelper.getFunctionParameters(executable);
30
- return new Implementation(version, access, parameters, executable);
31
- }
32
- }
@@ -1,13 +0,0 @@
1
- export default class Version {
2
- #private;
3
- static get DEFAULT(): Version;
4
- constructor(major?: number, minor?: number, patch?: number);
5
- get major(): number;
6
- get minor(): number;
7
- get patch(): number;
8
- equals(version: Version): boolean;
9
- greater(version: Version): boolean;
10
- less(version: Version): boolean;
11
- toString(): string;
12
- static parse(number: string): Version;
13
- }
@@ -1,50 +0,0 @@
1
- import InvalidVersionNumber from './errors/InvalidVersionNumber.js';
2
- export default class Version {
3
- static get DEFAULT() { return new Version(0, 0, 0); }
4
- #major;
5
- #minor;
6
- #patch;
7
- constructor(major = 0, minor = 0, patch = 0) {
8
- this.#major = major;
9
- this.#minor = minor;
10
- this.#patch = patch;
11
- }
12
- get major() { return this.#major; }
13
- get minor() { return this.#minor; }
14
- get patch() { return this.#patch; }
15
- equals(version) {
16
- return this.#major === version.major
17
- && this.#minor === version.minor
18
- && this.#patch === version.patch;
19
- }
20
- greater(version) {
21
- if (this.#major !== version.major)
22
- return this.#major > version.major;
23
- if (this.#minor !== version.minor)
24
- return this.#minor > version.minor;
25
- if (this.#patch !== version.patch)
26
- return this.#patch > version.patch;
27
- return false;
28
- }
29
- less(version) {
30
- if (this.#major !== version.major)
31
- return this.#major < version.major;
32
- if (this.#minor !== version.minor)
33
- return this.#minor < version.minor;
34
- if (this.#patch !== version.patch)
35
- return this.#patch < version.patch;
36
- return false;
37
- }
38
- toString() {
39
- return `${this.#major}.${this.#minor}.${this.#patch}`;
40
- }
41
- static parse(number) {
42
- const parts = number.split('.');
43
- switch (parts.length) {
44
- case 1: return new Version(Number.parseInt(parts[0]));
45
- case 2: return new Version(Number.parseInt(parts[0]), Number.parseInt(parts[1]));
46
- case 3: return new Version(Number.parseInt(parts[0]), Number.parseInt(parts[1]), Number.parseInt(parts[2]));
47
- default: throw new InvalidVersionNumber(number);
48
- }
49
- }
50
- }
@@ -1,2 +0,0 @@
1
- export declare const PRIVATE = "private";
2
- export declare const PUBLIC = "public";
@@ -1,2 +0,0 @@
1
- export const PRIVATE = 'private';
2
- export const PUBLIC = 'public';
@@ -1,3 +0,0 @@
1
- export default class BadRequest extends Error {
2
- constructor(message?: string);
3
- }
@@ -1,6 +0,0 @@
1
- export default class BadRequest extends Error {
2
- constructor(message = 'Invalid request') {
3
- super(message);
4
- }
5
- }
6
- BadRequest.source = '/jitar/core/errors/BadRequest.js';
@@ -1,3 +0,0 @@
1
- export default class Forbidden extends Error {
2
- constructor(message?: string);
3
- }
@@ -1,6 +0,0 @@
1
- export default class Forbidden extends Error {
2
- constructor(message = 'Forbidden') {
3
- super(message);
4
- }
5
- }
6
- Forbidden.source = '/jitar/core/errors/Forbidden.js';
@@ -1,4 +0,0 @@
1
- import NotFound from './NotFound.js';
2
- export default class ImplementationNotFound extends NotFound {
3
- constructor(fqn: string, version: string);
4
- }
@@ -1,7 +0,0 @@
1
- import NotFound from './NotFound.js';
2
- export default class ImplementationNotFound extends NotFound {
3
- constructor(fqn, version) {
4
- super(`No implementation found for procedure '${fqn}' with version '${version}'`);
5
- }
6
- }
7
- ImplementationNotFound.source = '/jitar/core/errors/ImplementationNotFound.js';
@@ -1,4 +0,0 @@
1
- import BadRequest from './BadRequest.js';
2
- export default class InvalidVersionNumber extends BadRequest {
3
- constructor(number: string);
4
- }
@@ -1,7 +0,0 @@
1
- import BadRequest from './BadRequest.js';
2
- export default class InvalidVersionNumber extends BadRequest {
3
- constructor(number) {
4
- super(`Invalid version number '${number}'`);
5
- }
6
- }
7
- InvalidVersionNumber.source = '/jitar/core/errors/InvalidVersionNumber.js';
@@ -1,4 +0,0 @@
1
- import BadRequest from './BadRequest.js';
2
- export default class MissingParameterValue extends BadRequest {
3
- constructor(parameterName: string);
4
- }