@mionjs/client 0.8.10 → 0.13.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 (248) hide show
  1. package/.dist/cjs/index.cjs +1 -2
  2. package/.dist/cjs/index.d.ts +5 -2
  3. package/.dist/cjs/middlewares.cjs +1 -0
  4. package/.dist/cjs/middlewares.d.ts +3 -0
  5. package/.dist/cjs/src/batch.cjs +3 -0
  6. package/.dist/cjs/src/batch.cjs.map +1 -0
  7. package/.dist/cjs/src/batch.d.ts +7 -0
  8. package/.dist/cjs/src/callContext.cjs +3 -0
  9. package/.dist/cjs/src/callContext.cjs.map +1 -0
  10. package/.dist/cjs/src/callContext.d.ts +6 -0
  11. package/.dist/cjs/src/client.cjs +3 -2
  12. package/.dist/cjs/src/client.cjs.map +1 -1
  13. package/.dist/cjs/src/client.d.ts +8 -13
  14. package/.dist/cjs/src/constants.cjs +3 -2
  15. package/.dist/cjs/src/constants.cjs.map +1 -1
  16. package/.dist/cjs/src/constants.d.ts +7 -3
  17. package/.dist/cjs/src/dispatch.cjs +3 -0
  18. package/.dist/cjs/src/dispatch.cjs.map +1 -0
  19. package/.dist/cjs/src/dispatch.d.ts +8 -0
  20. package/.dist/cjs/src/lib/apiBuildVersion.cjs +3 -0
  21. package/.dist/cjs/src/lib/apiBuildVersion.cjs.map +1 -0
  22. package/.dist/cjs/src/lib/apiBuildVersion.d.ts +10 -0
  23. package/.dist/cjs/src/lib/apiVersionRecovery.cjs +3 -0
  24. package/.dist/cjs/src/lib/apiVersionRecovery.cjs.map +1 -0
  25. package/.dist/cjs/src/lib/apiVersionRecovery.d.ts +7 -0
  26. package/.dist/cjs/src/lib/bundledApi.cjs +3 -0
  27. package/.dist/cjs/src/lib/bundledApi.cjs.map +1 -0
  28. package/.dist/cjs/src/lib/bundledApi.d.ts +12 -0
  29. package/.dist/cjs/src/lib/clientMethodsMetadata.cjs +3 -2
  30. package/.dist/cjs/src/lib/clientMethodsMetadata.cjs.map +1 -1
  31. package/.dist/cjs/src/lib/clientMethodsMetadata.d.ts +10 -10
  32. package/.dist/cjs/src/lib/clientResponse.cjs +3 -0
  33. package/.dist/cjs/src/lib/clientResponse.cjs.map +1 -0
  34. package/.dist/cjs/src/lib/clientResponse.d.ts +9 -0
  35. package/.dist/cjs/src/lib/fetchRemoteMethodsMetadata.cjs +3 -2
  36. package/.dist/cjs/src/lib/fetchRemoteMethodsMetadata.cjs.map +1 -1
  37. package/.dist/cjs/src/lib/fetchRemoteMethodsMetadata.d.ts +1 -1
  38. package/.dist/cjs/src/lib/handlersRegistry.cjs +3 -2
  39. package/.dist/cjs/src/lib/handlersRegistry.cjs.map +1 -1
  40. package/.dist/cjs/src/lib/handlersRegistry.d.ts +18 -9
  41. package/.dist/cjs/src/lib/headers.cjs +3 -0
  42. package/.dist/cjs/src/lib/headers.cjs.map +1 -0
  43. package/.dist/cjs/src/lib/headers.d.ts +7 -0
  44. package/.dist/cjs/src/lib/metadataEviction.cjs +3 -0
  45. package/.dist/cjs/src/lib/metadataEviction.cjs.map +1 -0
  46. package/.dist/cjs/src/lib/metadataEviction.d.ts +9 -0
  47. package/.dist/cjs/src/lib/metadataFetcher.cjs +3 -0
  48. package/.dist/cjs/src/lib/metadataFetcher.cjs.map +1 -0
  49. package/.dist/cjs/src/lib/metadataFetcher.d.ts +29 -0
  50. package/.dist/cjs/src/lib/metadataFromServer.cjs +1 -0
  51. package/.dist/cjs/src/lib/metadataFromServer.d.ts +4 -0
  52. package/.dist/cjs/src/lib/metadataFromServerLoader.cjs +3 -0
  53. package/.dist/cjs/src/lib/metadataFromServerLoader.cjs.map +1 -0
  54. package/.dist/cjs/src/lib/metadataFromServerLoader.d.ts +6 -0
  55. package/.dist/cjs/src/lib/metadataStore.cjs +3 -0
  56. package/.dist/cjs/src/lib/metadataStore.cjs.map +1 -0
  57. package/.dist/cjs/src/lib/metadataStore.d.ts +23 -0
  58. package/.dist/cjs/src/lib/methods.cjs +3 -0
  59. package/.dist/cjs/src/lib/methods.cjs.map +1 -0
  60. package/.dist/cjs/src/lib/methods.d.ts +15 -0
  61. package/.dist/cjs/src/lib/persistentStorage.cjs +3 -0
  62. package/.dist/cjs/src/lib/persistentStorage.cjs.map +1 -0
  63. package/.dist/cjs/src/lib/persistentStorage.d.ts +3 -0
  64. package/.dist/cjs/src/lib/sanitize.cjs +3 -0
  65. package/.dist/cjs/src/lib/sanitize.cjs.map +1 -0
  66. package/.dist/cjs/src/lib/sanitize.d.ts +3 -0
  67. package/.dist/cjs/src/lib/serializer.cjs +3 -2
  68. package/.dist/cjs/src/lib/serializer.cjs.map +1 -1
  69. package/.dist/cjs/src/lib/serializer.d.ts +8 -6
  70. package/.dist/cjs/src/lib/storage.cjs +0 -2
  71. package/.dist/cjs/src/lib/storage.d.ts +17 -10
  72. package/.dist/cjs/src/lib/typedEvent.cjs +3 -2
  73. package/.dist/cjs/src/lib/typedEvent.cjs.map +1 -1
  74. package/.dist/cjs/src/lib/typedEvent.d.ts +12 -10
  75. package/.dist/cjs/src/lib/validation.cjs +3 -2
  76. package/.dist/cjs/src/lib/validation.cjs.map +1 -1
  77. package/.dist/cjs/src/lib/validation.d.ts +4 -3
  78. package/.dist/cjs/src/middlewares/fetchMetadata.cjs +3 -0
  79. package/.dist/cjs/src/middlewares/fetchMetadata.cjs.map +1 -0
  80. package/.dist/cjs/src/middlewares/fetchMetadata.d.ts +4 -0
  81. package/.dist/cjs/src/middlewares/syncRoutes.cjs +3 -0
  82. package/.dist/cjs/src/middlewares/syncRoutes.cjs.map +1 -0
  83. package/.dist/cjs/src/middlewares/syncRoutes.d.ts +4 -0
  84. package/.dist/cjs/src/subRequest.cjs +3 -2
  85. package/.dist/cjs/src/subRequest.cjs.map +1 -1
  86. package/.dist/cjs/src/subRequest.d.ts +6 -10
  87. package/.dist/cjs/src/types.cjs +0 -2
  88. package/.dist/cjs/src/types.d.ts +91 -80
  89. package/.dist/esm/index.d.ts +5 -2
  90. package/.dist/esm/index.js +47 -28
  91. package/.dist/esm/middlewares.d.ts +3 -0
  92. package/.dist/esm/middlewares.js +6 -0
  93. package/.dist/esm/src/batch.d.ts +7 -0
  94. package/.dist/esm/src/batch.js +50 -0
  95. package/.dist/esm/src/batch.js.map +1 -0
  96. package/.dist/esm/src/callContext.d.ts +6 -0
  97. package/.dist/esm/src/callContext.js +34 -0
  98. package/.dist/esm/src/callContext.js.map +1 -0
  99. package/.dist/esm/src/client.d.ts +8 -13
  100. package/.dist/esm/src/client.js +54 -108
  101. package/.dist/esm/src/client.js.map +1 -1
  102. package/.dist/esm/src/constants.d.ts +7 -3
  103. package/.dist/esm/src/constants.js +21 -17
  104. package/.dist/esm/src/constants.js.map +1 -1
  105. package/.dist/esm/src/dispatch.d.ts +8 -0
  106. package/.dist/esm/src/dispatch.js +390 -0
  107. package/.dist/esm/src/dispatch.js.map +1 -0
  108. package/.dist/esm/src/lib/apiBuildVersion.d.ts +10 -0
  109. package/.dist/esm/src/lib/apiBuildVersion.js +43 -0
  110. package/.dist/esm/src/lib/apiBuildVersion.js.map +1 -0
  111. package/.dist/esm/src/lib/apiVersionRecovery.d.ts +7 -0
  112. package/.dist/esm/src/lib/apiVersionRecovery.js +43 -0
  113. package/.dist/esm/src/lib/apiVersionRecovery.js.map +1 -0
  114. package/.dist/esm/src/lib/bundledApi.d.ts +12 -0
  115. package/.dist/esm/src/lib/bundledApi.js +52 -0
  116. package/.dist/esm/src/lib/bundledApi.js.map +1 -0
  117. package/.dist/esm/src/lib/clientMethodsMetadata.d.ts +10 -10
  118. package/.dist/esm/src/lib/clientMethodsMetadata.js +257 -101
  119. package/.dist/esm/src/lib/clientMethodsMetadata.js.map +1 -1
  120. package/.dist/esm/src/lib/clientResponse.d.ts +9 -0
  121. package/.dist/esm/src/lib/clientResponse.js +53 -0
  122. package/.dist/esm/src/lib/clientResponse.js.map +1 -0
  123. package/.dist/esm/src/lib/fetchRemoteMethodsMetadata.d.ts +1 -1
  124. package/.dist/esm/src/lib/fetchRemoteMethodsMetadata.js +20 -17
  125. package/.dist/esm/src/lib/fetchRemoteMethodsMetadata.js.map +1 -1
  126. package/.dist/esm/src/lib/handlersRegistry.d.ts +18 -9
  127. package/.dist/esm/src/lib/handlersRegistry.js +53 -38
  128. package/.dist/esm/src/lib/handlersRegistry.js.map +1 -1
  129. package/.dist/esm/src/lib/headers.d.ts +7 -0
  130. package/.dist/esm/src/lib/headers.js +47 -0
  131. package/.dist/esm/src/lib/headers.js.map +1 -0
  132. package/.dist/esm/src/lib/metadataEviction.d.ts +9 -0
  133. package/.dist/esm/src/lib/metadataEviction.js +33 -0
  134. package/.dist/esm/src/lib/metadataEviction.js.map +1 -0
  135. package/.dist/esm/src/lib/metadataFetcher.d.ts +29 -0
  136. package/.dist/esm/src/lib/metadataFetcher.js +24 -0
  137. package/.dist/esm/src/lib/metadataFetcher.js.map +1 -0
  138. package/.dist/esm/src/lib/metadataFromServer.d.ts +4 -0
  139. package/.dist/esm/src/lib/metadataFromServer.js +15 -0
  140. package/.dist/esm/src/lib/metadataFromServerLoader.d.ts +6 -0
  141. package/.dist/esm/src/lib/metadataFromServerLoader.js +27 -0
  142. package/.dist/esm/src/lib/metadataFromServerLoader.js.map +1 -0
  143. package/.dist/esm/src/lib/metadataStore.d.ts +23 -0
  144. package/.dist/esm/src/lib/metadataStore.js +152 -0
  145. package/.dist/esm/src/lib/metadataStore.js.map +1 -0
  146. package/.dist/esm/src/lib/methods.d.ts +15 -0
  147. package/.dist/esm/src/lib/methods.js +41 -0
  148. package/.dist/esm/src/lib/methods.js.map +1 -0
  149. package/.dist/esm/src/lib/persistentStorage.d.ts +3 -0
  150. package/.dist/esm/src/lib/persistentStorage.js +26 -0
  151. package/.dist/esm/src/lib/persistentStorage.js.map +1 -0
  152. package/.dist/esm/src/lib/sanitize.d.ts +3 -0
  153. package/.dist/esm/src/lib/sanitize.js +25 -0
  154. package/.dist/esm/src/lib/sanitize.js.map +1 -0
  155. package/.dist/esm/src/lib/serializer.d.ts +8 -6
  156. package/.dist/esm/src/lib/serializer.js +75 -110
  157. package/.dist/esm/src/lib/serializer.js.map +1 -1
  158. package/.dist/esm/src/lib/storage.d.ts +17 -10
  159. package/.dist/esm/src/lib/storage.js +0 -43
  160. package/.dist/esm/src/lib/typedEvent.d.ts +12 -10
  161. package/.dist/esm/src/lib/typedEvent.js +25 -20
  162. package/.dist/esm/src/lib/typedEvent.js.map +1 -1
  163. package/.dist/esm/src/lib/validation.d.ts +4 -3
  164. package/.dist/esm/src/lib/validation.js +38 -33
  165. package/.dist/esm/src/lib/validation.js.map +1 -1
  166. package/.dist/esm/src/middlewares/fetchMetadata.d.ts +4 -0
  167. package/.dist/esm/src/middlewares/fetchMetadata.js +85 -0
  168. package/.dist/esm/src/middlewares/fetchMetadata.js.map +1 -0
  169. package/.dist/esm/src/middlewares/syncRoutes.d.ts +4 -0
  170. package/.dist/esm/src/middlewares/syncRoutes.js +20 -0
  171. package/.dist/esm/src/middlewares/syncRoutes.js.map +1 -0
  172. package/.dist/esm/src/subRequest.d.ts +6 -10
  173. package/.dist/esm/src/subRequest.js +11 -32
  174. package/.dist/esm/src/subRequest.js.map +1 -1
  175. package/.dist/esm/src/types.d.ts +91 -80
  176. package/.dist/esm/src/types.js +0 -2
  177. package/LICENSE +1 -1
  178. package/README.md +6 -6
  179. package/package.json +38 -26
  180. package/.dist/cjs/index.cjs.map +0 -1
  181. package/.dist/cjs/index.d.ts.map +0 -1
  182. package/.dist/cjs/src/client.d.ts.map +0 -1
  183. package/.dist/cjs/src/constants.d.ts.map +0 -1
  184. package/.dist/cjs/src/lib/clientMethodsMetadata.d.ts.map +0 -1
  185. package/.dist/cjs/src/lib/fetchRemoteMethodsMetadata.d.ts.map +0 -1
  186. package/.dist/cjs/src/lib/handlersRegistry.d.ts.map +0 -1
  187. package/.dist/cjs/src/lib/serializer.d.ts.map +0 -1
  188. package/.dist/cjs/src/lib/storage.cjs.map +0 -1
  189. package/.dist/cjs/src/lib/storage.d.ts.map +0 -1
  190. package/.dist/cjs/src/lib/testUtils.cjs +0 -2
  191. package/.dist/cjs/src/lib/testUtils.cjs.map +0 -1
  192. package/.dist/cjs/src/lib/testUtils.d.ts +0 -2
  193. package/.dist/cjs/src/lib/testUtils.d.ts.map +0 -1
  194. package/.dist/cjs/src/lib/typedEvent.d.ts.map +0 -1
  195. package/.dist/cjs/src/lib/validation.d.ts.map +0 -1
  196. package/.dist/cjs/src/request.cjs +0 -2
  197. package/.dist/cjs/src/request.cjs.map +0 -1
  198. package/.dist/cjs/src/request.d.ts +0 -37
  199. package/.dist/cjs/src/request.d.ts.map +0 -1
  200. package/.dist/cjs/src/routesFlow.cjs +0 -2
  201. package/.dist/cjs/src/routesFlow.cjs.map +0 -1
  202. package/.dist/cjs/src/routesFlow.d.ts +0 -7
  203. package/.dist/cjs/src/routesFlow.d.ts.map +0 -1
  204. package/.dist/cjs/src/subRequest.d.ts.map +0 -1
  205. package/.dist/cjs/src/types.cjs.map +0 -1
  206. package/.dist/cjs/src/types.d.ts.map +0 -1
  207. package/.dist/esm/index.d.ts.map +0 -1
  208. package/.dist/esm/index.js.map +0 -1
  209. package/.dist/esm/src/client.d.ts.map +0 -1
  210. package/.dist/esm/src/constants.d.ts.map +0 -1
  211. package/.dist/esm/src/lib/clientMethodsMetadata.d.ts.map +0 -1
  212. package/.dist/esm/src/lib/fetchRemoteMethodsMetadata.d.ts.map +0 -1
  213. package/.dist/esm/src/lib/handlersRegistry.d.ts.map +0 -1
  214. package/.dist/esm/src/lib/serializer.d.ts.map +0 -1
  215. package/.dist/esm/src/lib/storage.d.ts.map +0 -1
  216. package/.dist/esm/src/lib/storage.js.map +0 -1
  217. package/.dist/esm/src/lib/testUtils.d.ts +0 -2
  218. package/.dist/esm/src/lib/testUtils.d.ts.map +0 -1
  219. package/.dist/esm/src/lib/testUtils.js +0 -11
  220. package/.dist/esm/src/lib/testUtils.js.map +0 -1
  221. package/.dist/esm/src/lib/typedEvent.d.ts.map +0 -1
  222. package/.dist/esm/src/lib/validation.d.ts.map +0 -1
  223. package/.dist/esm/src/request.d.ts +0 -37
  224. package/.dist/esm/src/request.d.ts.map +0 -1
  225. package/.dist/esm/src/request.js +0 -334
  226. package/.dist/esm/src/request.js.map +0 -1
  227. package/.dist/esm/src/routesFlow.d.ts +0 -7
  228. package/.dist/esm/src/routesFlow.d.ts.map +0 -1
  229. package/.dist/esm/src/routesFlow.js +0 -60
  230. package/.dist/esm/src/routesFlow.js.map +0 -1
  231. package/.dist/esm/src/subRequest.d.ts.map +0 -1
  232. package/.dist/esm/src/types.d.ts.map +0 -1
  233. package/.dist/esm/src/types.js.map +0 -1
  234. package/index.ts +0 -19
  235. package/src/client.ts +0 -290
  236. package/src/constants.ts +0 -37
  237. package/src/lib/clientMethodsMetadata.ts +0 -187
  238. package/src/lib/fetchRemoteMethodsMetadata.ts +0 -44
  239. package/src/lib/handlersRegistry.ts +0 -101
  240. package/src/lib/serializer.ts +0 -245
  241. package/src/lib/storage.ts +0 -57
  242. package/src/lib/testUtils.ts +0 -16
  243. package/src/lib/typedEvent.ts +0 -57
  244. package/src/lib/validation.ts +0 -72
  245. package/src/request.ts +0 -563
  246. package/src/routesFlow.ts +0 -101
  247. package/src/subRequest.ts +0 -111
  248. package/src/types.ts +0 -237
@@ -1 +1 @@
1
- {"version":3,"file":"serializer.js","sources":["../../../../src/lib/serializer.ts"],"sourcesContent":["/* ########\n * 2023 mion\n * Author: Ma-jerez\n * License: MIT\n * The software is provided \"as is\", without warranty of any kind.\n * ######## */\n\nimport type {ResponseBody} from '@mionjs/router';\nimport {\n type MethodWithJitFns,\n RpcError,\n isRpcError,\n routesCache,\n MION_ROUTES,\n HandlerType,\n type SerializerMode,\n serializeBinaryBody as coreSerializeBinaryBody,\n deserializeBinaryBody as coreDeserializeBinaryBody,\n} from '@mionjs/core';\nimport type {MionClientRequest} from '../request.ts';\nimport {DEFAULT_PREFILL_OPTIONS} from '../constants.ts';\nimport {extractAndProcessMetadata} from './clientMethodsMetadata.ts';\nimport {ClientOptions} from '../types.ts';\n\n/** Result of serializing a request body - can be string (JSON) or Uint8Array (binary) */\nexport type SerializedBody = string | Uint8Array;\n\n/** Content-type header value for the serialized body */\nexport type ContentType = 'application/json; charset=utf-8' | 'application/octet-stream';\n\n/** Result of serializing a request body with its content type */\nexport interface SerializedRequest {\n body: SerializedBody;\n contentType: ContentType;\n}\n\n// ################################## SERIALIZE ##################################\n\n/** Serializes the request body and returns it with the appropriate content type */\nexport function serializeRequestBody(req: MionClientRequest<any, any>): SerializedRequest {\n const serializerMode = getSerializerMode(req);\n switch (serializerMode) {\n case 'json':\n case 'stringifyJson':\n return {\n body: serializeJsonBody(req),\n contentType: 'application/json; charset=utf-8',\n };\n case 'optimistic':\n return {\n body: serializeJSonBodyOptimistic(req),\n contentType: 'application/json; charset=utf-8',\n };\n case 'binary':\n return {\n body: serializeBinaryBody(req),\n contentType: 'application/octet-stream',\n };\n default:\n throw new Error(`Invalid serializer mode ${serializerMode}`);\n }\n}\n\nfunction serializeJsonBody(req: MionClientRequest<any, any>): string {\n const props: string[] = [];\n const subRequestIds = Object.keys(req.subRequestList);\n\n for (let i = 0; i < subRequestIds.length; i++) {\n const id = subRequestIds[i];\n const subRequest = req.subRequestList[id];\n if (!subRequest) continue;\n let params = subRequest.params;\n const method = routesCache.useMethodJitFns(id);\n if (method.type === HandlerType.headersMiddleFn && method.headersParam) {\n params = getParamsWithoutHeadersSubset(params);\n }\n try {\n const jsonValue = stringifyHandlerParams(method, params);\n if (!jsonValue) continue;\n props.push(`${JSON.stringify(id)}:${jsonValue}`);\n } catch (e: any) {\n const err = new RpcError({\n type: 'json-stringify-request-error',\n publicMessage: `Failed to stringify params for handler ${id}`,\n originalError: e,\n });\n throw err;\n }\n }\n\n return `{${props.join(',')}}`;\n}\n\n/** Serializes request body as plain JSON without JIT functions */\nfunction serializeJSonBodyOptimistic(req: MionClientRequest<any, any>): string {\n const body: Record<string, any> = {};\n const subRequestIds = Object.keys(req.subRequestList);\n for (const id of subRequestIds) {\n const subRequest = req.subRequestList[id];\n if (!subRequest) continue;\n body[id] = subRequest.params;\n }\n return JSON.stringify(body);\n}\n\n/** Serializes request body to binary format */\nfunction serializeBinaryBody(req: MionClientRequest<any, any>): Uint8Array {\n const subRequestIds = Object.keys(req.subRequestList);\n const body: Record<string, any> = {};\n const executionChain: MethodWithJitFns[] = [];\n\n for (const id of subRequestIds) {\n const subRequest = req.subRequestList[id];\n let params = subRequest.params;\n const method = routesCache.useMethodJitFns(id);\n\n if (method.type === HandlerType.headersMiddleFn && method.headersParam) {\n params = getParamsWithoutHeadersSubset(params);\n }\n\n body[id] = params;\n executionChain.push(method);\n }\n\n const workflowRouteIds = req.workflowSubRequests?.map((sr) => sr.id);\n const {buffer} = coreSerializeBinaryBody(req.path, executionChain, body, false, workflowRouteIds);\n return new Uint8Array(buffer);\n}\n\nfunction stringifyHandlerParams(method: MethodWithJitFns, params: any[]): string {\n if (!method.paramNames || method.paramNames.length === 0) return '';\n const paramsJit = method.paramsJitFns;\n if (paramsJit.prepareForJson.isNoop) return JSON.stringify(params);\n return paramsJit.stringifyJson.fn(params);\n}\n\n// ################################## DE-SERIALIZE ##################################\n\n/** Deserializes the response body from a fetch Response object. Handles routes metadata if present in json responses. */\nexport async function deserializeResponseBody(response: Response, options: ClientOptions): Promise<ResponseBody> {\n let parsedBody: any;\n const contentType = response.headers.get('content-type')?.toLowerCase();\n switch (true) {\n case !!contentType?.includes('application/json'):\n parsedBody = await deserializeJsonResponseBody(response, options);\n break;\n case !!contentType?.includes('application/octet-stream'):\n parsedBody = await deserializeBinaryResponseBody(response);\n break;\n default:\n throw new RpcError({\n type: 'unsupported-content-type',\n publicMessage: `Unsupported response content-type: '${contentType || 'none'}'`,\n });\n }\n return parsedBody;\n}\n\n/** Deserializes JSON response body, Also handles routes metadata if present */\nasync function deserializeJsonResponseBody(response: Response, options: ClientOptions) {\n try {\n const parsedBody = await response.json();\n // Extract & process metadata if present and delete entries after processing (does not use jit functions)\n extractAndProcessMetadata(MION_ROUTES.methodsMetadata, parsedBody, options);\n extractAndProcessMetadata(MION_ROUTES.methodsMetadataById, parsedBody, options);\n // Unwrap unexpected errors (move them from [MION_ROUTES.thrownErrors] to root)\n const platformError = unwrapUnexpectedErrors(parsedBody);\n if (platformError) return {[MION_ROUTES.platformError]: platformError};\n // Deserialize the body using jit functions\n const deserializedBody: ResponseBody = {};\n Object.entries(parsedBody).forEach(([methodId, returnValue]) => {\n const method = routesCache.useMethodJitFns(methodId);\n deserializedBody[methodId] = parseHandlerJsonReturnValue(method, returnValue);\n });\n return deserializedBody;\n } catch (err: any) {\n throw new RpcError({\n type: 'parsing-json-response-error',\n publicMessage: `Invalid json response body: ${err?.message || 'unknown parsing error.'}`,\n });\n }\n}\n\n/** Deserializes binary response body */\nasync function deserializeBinaryResponseBody(response: Response): Promise<ResponseBody> {\n const arrayBuffer = await response.arrayBuffer();\n const {body} = coreDeserializeBinaryBody('client-response', arrayBuffer, true);\n // Unwrap unexpected errors (move them from [MION_ROUTES.thrownErrors] to root)\n const platformError = unwrapUnexpectedErrors(body);\n if (platformError) return {[MION_ROUTES.platformError]: platformError};\n return body;\n}\n\n/** Unwraps unexpected errors from the response body into parsedBody. Returns a platformError if present as a special case. */\nfunction unwrapUnexpectedErrors(parsedBody: any): RpcError<string> | undefined {\n if (!(MION_ROUTES.thrownErrors in parsedBody)) return;\n const unexpectedErrors = parsedBody[MION_ROUTES.thrownErrors];\n // if platform error is present that means the router never executed (just the platform wrapper)\n if (MION_ROUTES.platformError in unexpectedErrors) {\n const globalErrorValue = unexpectedErrors[MION_ROUTES.platformError];\n return isRpcError(globalErrorValue) ? new RpcError<string>(globalErrorValue) : globalErrorValue;\n }\n Object.assign(parsedBody, unexpectedErrors);\n delete parsedBody[MION_ROUTES.thrownErrors];\n}\n\n/** Determines the serializer mode to use for a request */\nfunction getSerializerMode(req: MionClientRequest<any, any>): SerializerMode {\n if (req.options.serializer === 'optimistic') {\n // When metadata is cached (e.g. after retry), use JIT serialization\n const subRequestIds = Object.keys(req.subRequestList);\n const allCached = subRequestIds.every((id) => routesCache.hasMetadata(id));\n if (allCached) return 'stringifyJson';\n return 'optimistic';\n }\n const methodId = req.route?.id ?? req.workflowSubRequests?.[0]?.id;\n const method = routesCache.getMethodJitFns(methodId);\n const serializerMode = method?.options.serializer || DEFAULT_PREFILL_OPTIONS.serializer;\n if (serializerMode === 'json') return DEFAULT_PREFILL_OPTIONS.serializer;\n return serializerMode;\n}\n\n/** Returns params array without the HeadersSubset (first param) */\nfunction getParamsWithoutHeadersSubset(params: any[]): any[] {\n if (!params || params.length === 0) return [];\n return params.slice(1);\n}\n\nfunction parseHandlerJsonReturnValue(method: MethodWithJitFns, returnValue: any): any {\n if (!method.hasReturnData) return returnValue;\n const returnJit = method.returnJitFns;\n if (returnJit.restoreFromJson.isNoop || !returnValue) return returnValue;\n\n try {\n if (returnValue instanceof RpcError) return returnValue;\n if (isRpcError(returnValue)) return new RpcError(returnValue);\n return returnJit.restoreFromJson.fn(returnValue);\n } catch (e: any) {\n return new RpcError({\n type: 'deserialization-error',\n publicMessage: `Invalid response from Route or MiddleFn '${method.id}', can not deserialize return value: ${e.message}`,\n errorData: e?.errors,\n });\n }\n}\n"],"names":["coreSerializeBinaryBody","coreDeserializeBinaryBody"],"mappings":"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"}
1
+ {"version":3,"file":"serializer.js","names":[],"sources":["../../../../src/lib/serializer.ts"],"sourcesContent":["/* ########\n * 2023 mion\n * Author: Ma-jerez\n * License: MIT\n * The software is provided \"as is\", without warranty of any kind.\n * ######## */\n\nimport type {ResponseBody} from '@mionjs/router';\nimport {type MethodWithJitFns, RpcError, isRpcError, MION_ROUTES, HandlerType} from '@mionjs/core';\nimport type {CallContext} from '../types.ts';\nimport {useMethodFns} from './methods.ts';\nimport {hasHeadersSubsetParam} from './headers.ts';\nimport {ClientOptions} from '../types.ts';\n\nexport type SerializedBody = string;\n\nexport type ContentType = 'application/json; charset=utf-8';\n\n/** Runs on the parsed body before anything decodes, and may hand back entries to add untouched. */\ntype TakeRaw = (parsedBody: Record<string, unknown>) => Record<string, unknown> | undefined;\n\nexport interface SerializedRequest {\n body: SerializedBody;\n contentType: ContentType;\n}\n\n// ################################## SERIALIZE ##################################\n\n/** `optimistic`: the route's metadata is still being fetched, so no compiled encoders exist yet. */\nexport function serializeRequestBody(context: CallContext, optimistic = false): SerializedRequest {\n const body = optimistic ? serializeJSonBodyOptimistic(context) : serializeJsonBody(context);\n return {body, contentType: 'application/json; charset=utf-8'};\n}\n\nfunction serializeJsonBody(context: CallContext): string {\n const props: string[] = [];\n const subRequestIds = Object.keys(context.subRequestList);\n\n for (let i = 0; i < subRequestIds.length; i++) {\n const id = subRequestIds[i];\n const subRequest = context.subRequestList[id];\n if (!subRequest) continue;\n let params = subRequest.params;\n const method = useMethodFns(id);\n if (method.type === HandlerType.headersMiddleware && method.headersParam) {\n params = getParamsWithoutHeadersSubset(params);\n }\n try {\n const jsonValue = stringifyHandlerParams(method, params, context.options.validateParams);\n if (!jsonValue) continue;\n props.push(`${JSON.stringify(id)}:${jsonValue}`);\n } catch (e: any) {\n const err = new RpcError({\n type: 'json-stringify-request-error',\n publicMessage: `Failed to stringify params for handler ${id}`,\n originalError: e,\n });\n throw err;\n }\n }\n\n return `{${props.join(',')}}`;\n}\n\n/** Plain wire forms every server decoder accepts; a HeadersSubset goes out as HTTP headers, never in the body */\nfunction serializeJSonBodyOptimistic(context: CallContext): string {\n const body: Record<string, any> = {};\n const subRequestIds = Object.keys(context.subRequestList);\n for (const id of subRequestIds) {\n const subRequest = context.subRequestList[id];\n if (!subRequest) continue;\n const params = hasHeadersSubsetParam(id, subRequest.params)\n ? getParamsWithoutHeadersSubset(subRequest.params)\n : subRequest.params;\n if (params?.length) body[id] = params;\n }\n return JSON.stringify(body, wireFormReplacer);\n}\n\n/** Writes the params with the strategy the server compiled. */\nfunction stringifyHandlerParams(method: MethodWithJitFns, params: any[], validated: boolean): string {\n if (!method.paramsCount) return '';\n const {json, isType} = method.paramsJitFns;\n if (json.encode.isNoop) return JSON.stringify(params);\n // with local validation off a wrong-typed value must still reach the server's validation, and the\n // compiled encoders assume the type, so it rides the plain wire form instead\n if (!validated && !isType.isNoop && !isType.fn(params)) return JSON.stringify(params, wireFormReplacer);\n const write = (): string => JSON.stringify(json.encode.fn(params));\n // the compiled encoder rejects anything but the real params (a batch mapping's `null` placeholder,\n // a wrong-typed value), so those fall back to the plain wire forms the server decoders accept\n try {\n return write();\n } catch {\n return JSON.stringify(params, wireFormReplacer);\n }\n}\n\n/** The wire forms the server's JSON decoders accept; Date, URL and Temporal need no arm, their own toJSON writes it.\n * No union `[index, value]` envelope: the index needs metadata, so the server's guarded decoder refuses and the client retries. */\nexport function wireFormReplacer(this: unknown, key: string, value: unknown): unknown {\n if (value instanceof Map) return [...value];\n if (value instanceof Set) return [...value];\n if (typeof value === 'bigint') return value.toString();\n return value;\n}\n\n// ################################## DE-SERIALIZE ##################################\n\nexport async function deserializeResponseBody(\n response: Response,\n options: ClientOptions,\n takeRaw?: TakeRaw\n): Promise<ResponseBody> {\n let parsedBody: any;\n const contentType = response.headers.get('content-type')?.toLowerCase();\n switch (true) {\n case !!contentType?.includes('application/json'):\n parsedBody = await deserializeJsonResponseBody(response, takeRaw);\n break;\n default:\n throw new RpcError({\n type: 'unsupported-content-type',\n publicMessage: `Unsupported response content-type: '${contentType || 'none'}'`,\n });\n }\n return parsedBody;\n}\n\nasync function deserializeJsonResponseBody(response: Response, takeRaw: TakeRaw | undefined) {\n try {\n const parsedBody = await response.json();\n const rawEntries = parsedBody && typeof parsedBody === 'object' ? takeRaw?.(parsedBody) : undefined;\n // kept out of the body, so the wire's returned-vs-thrown split survives\n const extracted = extractThrownErrors(parsedBody);\n if (extracted.platformError) return {[MION_ROUTES.platformError]: extracted.platformError};\n let thrownErrors = extracted.thrownErrors;\n const deserializedBody: ResponseBody = {};\n Object.entries(parsedBody).forEach(([methodId, returnValue]) => {\n const method = useMethodFns(methodId);\n try {\n deserializedBody[methodId] = parseHandlerJsonReturnValue(method, returnValue);\n } catch (decodeError: any) {\n // an unreadable answer is untyped: thrown, never the method's declared value\n (thrownErrors ??= {})[methodId] = new RpcError({\n type: 'deserialization-error',\n publicMessage: `Invalid response from Route or Middleware '${method.id}', can not deserialize return value: ${decodeError.message}`,\n errorData: decodeError?.errors,\n });\n }\n });\n if (thrownErrors) deserializedBody[MION_ROUTES.thrownErrors] = thrownErrors;\n if (rawEntries) Object.assign(deserializedBody, rawEntries);\n return deserializedBody;\n } catch (err: any) {\n throw new RpcError({\n type: 'parsing-json-response-error',\n publicMessage: `Invalid json response body: ${err?.message || 'unknown parsing error.'}`,\n });\n }\n}\n\n/** Takes [MION_ROUTES.thrownErrors] out WITHOUT flattening it into the body, so the returned-vs-thrown split\n * survives for error classification. Thrown errors are not strongly typed and deserialize as RpcError<string>. */\nfunction extractThrownErrors(parsedBody: any): {\n platformError?: RpcError<string>;\n thrownErrors?: Record<string, RpcError<string>>;\n} {\n if (!(MION_ROUTES.thrownErrors in parsedBody)) return {};\n const rawThrownErrors = parsedBody[MION_ROUTES.thrownErrors];\n delete parsedBody[MION_ROUTES.thrownErrors];\n // if platform error is present that means the router never executed (just the platform wrapper)\n if (MION_ROUTES.platformError in rawThrownErrors) {\n const globalErrorValue = rawThrownErrors[MION_ROUTES.platformError];\n const platformError = isRpcError(globalErrorValue) ? new RpcError<string>(globalErrorValue) : globalErrorValue;\n return {platformError};\n }\n // keyed by whatever the response says, so a `__proto__` key stays a plain entry\n const thrownErrors: Record<string, RpcError<string>> = Object.create(null);\n Object.entries(rawThrownErrors).forEach(([id, value]) => {\n thrownErrors[id] = isRpcError(value) ? new RpcError<string>(value) : (value as RpcError<string>);\n });\n return {thrownErrors};\n}\n\nfunction getParamsWithoutHeadersSubset(params: any[]): any[] {\n if (!params || params.length === 0) return [];\n return params.slice(1);\n}\n\nfunction parseHandlerJsonReturnValue(method: MethodWithJitFns, returnValue: any): any {\n if (!method.hasReturnData) return returnValue;\n const {decode} = method.returnJitFns.json;\n if (decode.isNoop || !returnValue) return returnValue;\n\n if (returnValue instanceof RpcError) return returnValue;\n if (isRpcError(returnValue)) return new RpcError(returnValue);\n return decode.fn(returnValue);\n}\n"],"mappings":"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"}
@@ -1,12 +1,19 @@
1
- export declare class MemoryStorage {
2
- private data;
3
- get length(): number;
4
- getItem(key: string): string | null;
5
- setItem(key: string, value: string): void;
6
- removeItem(key: string): void;
7
- clear(): void;
8
- key(index: number): string | null;
1
+ export type MetadataKind = 'm' | 'j' | 'p';
2
+ export interface MetadataRecord {
3
+ baseURL: string;
4
+ kind: MetadataKind;
5
+ id: string;
6
+ json: string;
7
+ ts: number;
9
8
  }
10
- export declare function getStorage(): Storage | MemoryStorage;
11
- export declare function resetStorageInstance(): void;
9
+ export type MetadataRecordKey = [MetadataKind, string];
10
+ export interface MetadataStore {
11
+ readonly kind: string;
12
+ readAll(baseURL: string): Promise<MetadataRecord[]>;
13
+ write(records: MetadataRecord[]): Promise<void>;
14
+ remove(baseURL: string, keys: MetadataRecordKey[]): Promise<void>;
15
+ clear(baseURL?: string): Promise<void>;
16
+ }
17
+ export type MetadataStoreFactory = () => MetadataStore | undefined | Promise<MetadataStore | undefined>;
18
+ export type StorageEngine = 'indexeddb' | 'memory' | MetadataStoreFactory;
12
19
  //# sourceMappingURL=storage.d.ts.map
@@ -1,43 +0,0 @@
1
- const STORAGE_GLOBAL_KEY = "__mion_storage__";
2
- class MemoryStorage {
3
- data = /* @__PURE__ */ new Map();
4
- get length() {
5
- return this.data.size;
6
- }
7
- getItem(key) {
8
- return this.data.get(key) ?? null;
9
- }
10
- setItem(key, value) {
11
- this.data.set(key, value);
12
- }
13
- removeItem(key) {
14
- this.data.delete(key);
15
- }
16
- clear() {
17
- this.data.clear();
18
- }
19
- key(index) {
20
- return [...this.data.keys()][index] ?? null;
21
- }
22
- }
23
- function getStorage() {
24
- const existing = globalThis[STORAGE_GLOBAL_KEY];
25
- if (existing)
26
- return existing;
27
- let storage;
28
- try {
29
- typeof localStorage < "u" ? (localStorage.setItem("__mion_test__", "1"), localStorage.removeItem("__mion_test__"), storage = localStorage) : storage = new MemoryStorage();
30
- } catch {
31
- storage = new MemoryStorage();
32
- }
33
- return globalThis[STORAGE_GLOBAL_KEY] = storage, storage;
34
- }
35
- function resetStorageInstance() {
36
- delete globalThis[STORAGE_GLOBAL_KEY];
37
- }
38
- export {
39
- MemoryStorage,
40
- getStorage,
41
- resetStorageInstance
42
- };
43
- //# sourceMappingURL=storage.js.map
@@ -1,18 +1,20 @@
1
1
  import { RpcError } from '@mionjs/core';
2
2
  import { HandlersRegistry } from './handlersRegistry.ts';
3
- import { SuccessHandler } from '../types.ts';
4
- export declare class TypedEvent<S = void, E extends RpcError<string, any> = never> {
3
+ import { ErrorHandler, ErrorOfType, RequestHandler, ResponseHandler, SubRequest } from '../types.ts';
4
+ export declare class TypedEvent<S = void, E extends RpcError<string, any> = never, P extends any[] = any[]> {
5
5
  private readonly handlerId;
6
6
  private readonly registry;
7
- constructor(handlerId: string, registry: HandlersRegistry);
8
- onSuccess(handler: SuccessHandler<S>): TypedEvent<S, E>;
9
- offSuccess(): TypedEvent<S, E>;
10
- onError<T extends E['type']>(errorType: T, handler: (error: Extract<E, {
11
- type: T;
12
- }>) => void): TypedEvent<S, E>;
13
- offError<T extends E['type']>(errorType: T): TypedEvent<S, E>;
7
+ private readonly createSubRequest?;
8
+ constructor(handlerId: string, registry: HandlersRegistry, createSubRequest?: ((params: any[]) => SubRequest<any>) | undefined);
9
+ onRequest(handler: RequestHandler<P>): TypedEvent<S, E, P>;
10
+ offRequest(): TypedEvent<S, E, P>;
11
+ onResponse(handler: ResponseHandler<S>): TypedEvent<S, E, P>;
12
+ offResponse(handler: ResponseHandler<S>): TypedEvent<S, E, P>;
13
+ onError<T extends E['type']>(errorType: T, handler: ErrorHandler<ErrorOfType<E, T>>): TypedEvent<S, E, P>;
14
+ offError<T extends E['type']>(errorType: T, handler: ErrorHandler<ErrorOfType<E, T>>): TypedEvent<S, E, P>;
14
15
  getHandlerId(): string;
15
16
  hasErrorHandler(errorType: string): boolean;
16
- hasSuccessHandler(): boolean;
17
+ hasResponseHandler(): boolean;
18
+ hasRequestHandler(): boolean;
17
19
  }
18
20
  //# sourceMappingURL=typedEvent.d.ts.map
@@ -1,39 +1,44 @@
1
- class TypedEvent {
1
+ var TypedEvent = class {
2
2
  handlerId;
3
3
  registry;
4
- constructor(handlerId, registry) {
5
- this.handlerId = handlerId, this.registry = registry;
4
+ createSubRequest;
5
+ constructor(handlerId, registry, createSubRequest) {
6
+ this.handlerId = handlerId, this.registry = registry, this.createSubRequest = createSubRequest;
6
7
  }
7
- /** Register a persistent success handler for this middleFn */
8
- onSuccess(handler) {
9
- return this.registry.registerSuccess(this.handlerId, handler), this;
8
+ onRequest(handler) {
9
+ if (!this.createSubRequest) throw new Error(`onRequest needs the middleware from the client, '${this.handlerId}' has none`);
10
+ return this.registry.registerRequest(this.handlerId, handler, this.createSubRequest), this;
10
11
  }
11
- /** Remove a previously registered success handler from HandlersRegistry */
12
- offSuccess() {
13
- return this.registry.unregisterSuccess(this.handlerId), this;
12
+ offRequest() {
13
+ return this.registry.unregisterRequest(this.handlerId), this;
14
+ }
15
+ onResponse(handler) {
16
+ return this.registry.registerResponse(this.handlerId, handler), this;
17
+ }
18
+ offResponse(handler) {
19
+ return this.registry.unregisterResponse(this.handlerId, handler), this;
14
20
  }
15
- /** Register a persistent error handler for this middleFn */
16
21
  onError(errorType, handler) {
17
22
  return this.registry.register(this.handlerId, errorType, handler), this;
18
23
  }
19
- /** Remove a previously registered error handler from HandlersRegistry */
20
- offError(errorType) {
21
- return this.registry.unregister(this.handlerId, errorType), this;
24
+ offError(errorType, handler) {
25
+ return this.registry.unregister(this.handlerId, errorType, handler), this;
22
26
  }
23
- /** Get the handler ID this event is associated with */
24
27
  getHandlerId() {
25
28
  return this.handlerId;
26
29
  }
27
- /** Check if an error handler is registered for a specific error type */
28
30
  hasErrorHandler(errorType) {
29
31
  return this.registry.hasHandler(this.handlerId, errorType);
30
32
  }
31
- /** Check if a success handler is registered */
32
- hasSuccessHandler() {
33
- return this.registry.hasSuccessHandler(this.handlerId);
33
+ hasResponseHandler() {
34
+ return this.registry.hasResponseHandler(this.handlerId);
34
35
  }
35
- }
36
+ hasRequestHandler() {
37
+ return this.registry.hasRequestHandler(this.handlerId);
38
+ }
39
+ };
36
40
  export {
37
41
  TypedEvent
38
42
  };
39
- //# sourceMappingURL=typedEvent.js.map
43
+
44
+ //# sourceMappingURL=typedEvent.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"typedEvent.js","sources":["../../../../src/lib/typedEvent.ts"],"sourcesContent":["/* ########\n * 2025 mion\n * Author: Ma-jerez\n * License: MIT\n * The software is provided \"as is\", without warranty of any kind.\n * ######## */\n\nimport type {RpcError} from '@mionjs/core';\nimport type {HandlersRegistry} from './handlersRegistry.ts';\nimport type {ErrorHandler, SuccessHandler} from '../types.ts';\n\n/** Persistent event emitter for middleFn success and error handling */\nexport class TypedEvent<S = void, E extends RpcError<string, any> = never> {\n constructor(\n private readonly handlerId: string,\n private readonly registry: HandlersRegistry\n ) {}\n\n /** Register a persistent success handler for this middleFn */\n onSuccess(handler: SuccessHandler<S>): TypedEvent<S, E> {\n this.registry.registerSuccess(this.handlerId, handler);\n return this;\n }\n\n /** Remove a previously registered success handler from HandlersRegistry */\n offSuccess(): TypedEvent<S, E> {\n this.registry.unregisterSuccess(this.handlerId);\n return this;\n }\n\n /** Register a persistent error handler for this middleFn */\n onError<T extends E['type']>(errorType: T, handler: (error: Extract<E, {type: T}>) => void): TypedEvent<S, E> {\n this.registry.register(this.handlerId, errorType, handler as ErrorHandler<any>);\n return this;\n }\n\n /** Remove a previously registered error handler from HandlersRegistry */\n offError<T extends E['type']>(errorType: T): TypedEvent<S, E> {\n this.registry.unregister(this.handlerId, errorType);\n return this;\n }\n\n /** Get the handler ID this event is associated with */\n getHandlerId(): string {\n return this.handlerId;\n }\n\n /** Check if an error handler is registered for a specific error type */\n hasErrorHandler(errorType: string): boolean {\n return this.registry.hasHandler(this.handlerId, errorType);\n }\n\n /** Check if a success handler is registered */\n hasSuccessHandler(): boolean {\n return this.registry.hasSuccessHandler(this.handlerId);\n }\n}\n"],"names":[],"mappings":"MAYa,WAAU;AAAA,EAEE;AAAA,EACA;AAAA,EAFrB,YACqB,WACA,UAA0B;AAD1B,SAAA,YAAA,WACA,KAAA,WAAA;AAAA,EAClB;AAAA;AAAA,EAGH,UAAU,SAA0B;AAChC,gBAAK,SAAS,gBAAgB,KAAK,WAAW,OAAO,GAC9C;AAAA,EACX;AAAA;AAAA,EAGA,aAAU;AACN,gBAAK,SAAS,kBAAkB,KAAK,SAAS,GACvC;AAAA,EACX;AAAA;AAAA,EAGA,QAA6B,WAAc,SAA+C;AACtF,gBAAK,SAAS,SAAS,KAAK,WAAW,WAAW,OAA4B,GACvE;AAAA,EACX;AAAA;AAAA,EAGA,SAA8B,WAAY;AACtC,gBAAK,SAAS,WAAW,KAAK,WAAW,SAAS,GAC3C;AAAA,EACX;AAAA;AAAA,EAGA,eAAY;AACR,WAAO,KAAK;AAAA,EAChB;AAAA;AAAA,EAGA,gBAAgB,WAAiB;AAC7B,WAAO,KAAK,SAAS,WAAW,KAAK,WAAW,SAAS;AAAA,EAC7D;AAAA;AAAA,EAGA,oBAAiB;AACb,WAAO,KAAK,SAAS,kBAAkB,KAAK,SAAS;AAAA,EACzD;AACH;"}
1
+ {"version":3,"file":"typedEvent.js","names":[],"sources":["../../../../src/lib/typedEvent.ts"],"sourcesContent":["/* ########\n * 2025 mion\n * Author: Ma-jerez\n * License: MIT\n * The software is provided \"as is\", without warranty of any kind.\n * ######## */\n\nimport type {RpcError} from '@mionjs/core';\nimport type {HandlersRegistry} from './handlersRegistry.ts';\nimport type {ErrorHandler, ErrorOfType, RequestHandler, ResponseHandler, SubRequest} from '../types.ts';\n\n/** Persistent hooks of one middleware: its params before each request, its result or error after it */\nexport class TypedEvent<S = void, E extends RpcError<string, any> = never, P extends any[] = any[]> {\n constructor(\n private readonly handlerId: string,\n private readonly registry: HandlersRegistry,\n private readonly createSubRequest?: (params: any[]) => SubRequest<any>\n ) {}\n\n /** Register a persistent handler that gives this middleware its params before every request that runs it */\n onRequest(handler: RequestHandler<P>): TypedEvent<S, E, P> {\n if (!this.createSubRequest) throw new Error(`onRequest needs the middleware from the client, '${this.handlerId}' has none`);\n this.registry.registerRequest(this.handlerId, handler, this.createSubRequest);\n return this;\n }\n\n /** Remove a previously registered request handler from HandlersRegistry */\n offRequest(): TypedEvent<S, E, P> {\n this.registry.unregisterRequest(this.handlerId);\n return this;\n }\n\n /** Persistent handler for this middleware's successful result; every one registered runs, in order */\n onResponse(handler: ResponseHandler<S>): TypedEvent<S, E, P> {\n this.registry.registerResponse(this.handlerId, handler);\n return this;\n }\n\n /** Remove this response handler; the others on this middleware stay */\n offResponse(handler: ResponseHandler<S>): TypedEvent<S, E, P> {\n this.registry.unregisterResponse(this.handlerId, handler);\n return this;\n }\n\n /** Persistent error handler; every one registered for the type runs, in order */\n onError<T extends E['type']>(errorType: T, handler: ErrorHandler<ErrorOfType<E, T>>): TypedEvent<S, E, P> {\n this.registry.register(this.handlerId, errorType, handler as ErrorHandler<any>);\n return this;\n }\n\n /** Remove this error handler; the others for the type stay */\n offError<T extends E['type']>(errorType: T, handler: ErrorHandler<ErrorOfType<E, T>>): TypedEvent<S, E, P> {\n this.registry.unregister(this.handlerId, errorType, handler as ErrorHandler<any>);\n return this;\n }\n\n /** Get the handler ID this event is associated with */\n getHandlerId(): string {\n return this.handlerId;\n }\n\n /** Check if an error handler is registered for a specific error type */\n hasErrorHandler(errorType: string): boolean {\n return this.registry.hasHandler(this.handlerId, errorType);\n }\n\n /** Check if a response handler is registered */\n hasResponseHandler(): boolean {\n return this.registry.hasResponseHandler(this.handlerId);\n }\n\n /** Check if a request handler is registered */\n hasRequestHandler(): boolean {\n return this.registry.hasRequestHandler(this.handlerId);\n }\n}\n"],"mappings":"AAYA,IAAa,aAAb,MAAoG;AAAA,EAE/E;AAAA,EACA;AAAA,EACA;AAAA,EAHnB,YACE,WACA,UACA,kBACA;AAHiB,SAAA,YAAA,WACA,KAAA,WAAA,UACA,KAAA,mBAAA;AAAA,EAChB;AAAA,EAGH,UAAU,SAAiD;AACzD,QAAI,CAAC,KAAK,iBAAkB,OAAM,IAAI,MAAM,oDAAoD,KAAK,SAAA,YAAqB;AAC1H,gBAAK,SAAS,gBAAgB,KAAK,WAAW,SAAS,KAAK,gBAAgB,GACrE;AAAA,EACT;AAAA,EAGA,aAAkC;AAChC,gBAAK,SAAS,kBAAkB,KAAK,SAAS,GACvC;AAAA,EACT;AAAA,EAGA,WAAW,SAAkD;AAC3D,gBAAK,SAAS,iBAAiB,KAAK,WAAW,OAAO,GAC/C;AAAA,EACT;AAAA,EAGA,YAAY,SAAkD;AAC5D,gBAAK,SAAS,mBAAmB,KAAK,WAAW,OAAO,GACjD;AAAA,EACT;AAAA,EAGA,QAA6B,WAAc,SAA+D;AACxG,gBAAK,SAAS,SAAS,KAAK,WAAW,WAAW,OAA4B,GACvE;AAAA,EACT;AAAA,EAGA,SAA8B,WAAc,SAA+D;AACzG,gBAAK,SAAS,WAAW,KAAK,WAAW,WAAW,OAA4B,GACzE;AAAA,EACT;AAAA,EAGA,eAAuB;AACrB,WAAO,KAAK;AAAA,EACd;AAAA,EAGA,gBAAgB,WAA4B;AAC1C,WAAO,KAAK,SAAS,WAAW,KAAK,WAAW,SAAS;AAAA,EAC3D;AAAA,EAGA,qBAA8B;AAC5B,WAAO,KAAK,SAAS,mBAAmB,KAAK,SAAS;AAAA,EACxD;AAAA,EAGA,oBAA6B;AAC3B,WAAO,KAAK,SAAS,kBAAkB,KAAK,SAAS;AAAA,EACvD;AACF"}
@@ -1,5 +1,6 @@
1
- import { RequestErrors, SubRequest } from '../types.ts';
2
- import { MionClientRequest } from '../request.ts';
3
- export declare function validateSubRequests(subRequestIds: string[], req: MionClientRequest<any, any>, errors: RequestErrors, validateRouteMiddleFns?: boolean): void;
1
+ import { RpcError } from '@mionjs/core';
2
+ import { CallContext, RequestErrors, SubRequest } from '../types.ts';
3
+ export declare function validateSubRequests(subRequestIds: string[], context: CallContext, errors: RequestErrors, validateRouteMiddlewares?: boolean): void;
4
4
  export declare function validateSubRequest(id: string, subRequest: SubRequest<any>, errors: RequestErrors): void;
5
+ export declare function getResponseError(id: string, value: unknown): RpcError<"response-validation-error", any> | undefined;
5
6
  //# sourceMappingURL=validation.d.ts.map
@@ -1,50 +1,55 @@
1
- import { routesCache, RpcError } from "@mionjs/core";
2
- function validateSubRequests(subRequestIds, req, errors, validateRouteMiddleFns = !0) {
3
- req.options.validateParams && subRequestIds.forEach((id) => {
4
- const subRequest = req.subRequestList[id];
1
+ import { getMethod, useMethodFns } from "./methods.js";
2
+ import { HeadersSubset, RpcError } from "@mionjs/core";
3
+ function validateSubRequests(subRequestIds, context, errors, validateRouteMiddlewares = !0) {
4
+ context.options.validateParams && subRequestIds.forEach((id) => {
5
+ const subRequest = context.subRequestList[id];
5
6
  validateSubRequest(id, subRequest, errors);
6
- const methodMeta = routesCache.getMetadata(id);
7
- if (validateRouteMiddleFns && methodMeta?.middleFnIds?.length) {
8
- const validMiddleFnIds = methodMeta.middleFnIds.filter((middleFnId) => middleFnId != null);
9
- validateSubRequests(validMiddleFnIds, req, errors, validateRouteMiddleFns);
10
- }
7
+ const methodMeta = getMethod(id);
8
+ validateRouteMiddlewares && methodMeta?.middlewareIds?.length && validateSubRequests(methodMeta.middlewareIds.filter((middlewareId) => middlewareId != null), context, errors, validateRouteMiddlewares);
11
9
  });
12
10
  }
13
11
  function validateSubRequest(id, subRequest, errors) {
14
- if (subRequest?.error || subRequest?.isResolved)
15
- return;
16
- const mappings = subRequest?.mappings;
17
- if (Array.isArray(mappings) && mappings.length > 0)
18
- return;
19
- const params = subRequest?.params || [], validationResponse = getTypeErrors(id, params);
20
- if (!validationResponse)
21
- return;
12
+ if (subRequest?.error || subRequest?.isResolved || subRequest?.mappings && subRequest.mappings.length > 0) return;
13
+ const validationResponse = getTypeErrors(id, subRequest?.params || []);
14
+ if (!validationResponse) return;
22
15
  const error = validationResponse;
23
16
  errors.set(id, error), subRequest && (subRequest.error = error, subRequest.isResolved = !0);
24
17
  }
18
+ function getResponseError(id, value) {
19
+ const method = useMethodFns(id);
20
+ if (method.hasReturnData) {
21
+ if (method.headersReturn) {
22
+ if (!(value instanceof HeadersSubset)) return;
23
+ const jitFns = method.headersReturn.jitFns;
24
+ return checkValue(method.id, jitFns, value, "response-validation-error", "response-validation-error", "headers from");
25
+ }
26
+ return checkValue(method.id, method.returnJitFns, value, "response-validation-error", "response-validation-error", "response from");
27
+ }
28
+ }
25
29
  function getTypeErrors(id, params) {
26
- const method = routesCache.useMethodJitFns(id);
27
- if (!method.paramNames || method.paramNames.length === 0)
28
- return;
29
- const paramsJit = method.paramsJitFns;
30
- if (!paramsJit.typeErrors.isNoop)
30
+ const method = useMethodFns(id);
31
+ if (method.paramsCount)
32
+ return checkValue(method.id, method.paramsJitFns, params, "validation-error", "unexpected-validation-error", "params for");
33
+ }
34
+ function checkValue(methodId, jitFns, value, invalidType, failedType, subject) {
35
+ if (!jitFns.isType.isNoop)
31
36
  try {
32
- const validationsResponse = paramsJit.isType.fn(params) || paramsJit.typeErrors.fn(params);
33
- if (validationsResponse?.length)
34
- return new RpcError({
35
- type: "validation-error",
36
- publicMessage: `Invalid params for Route or MiddleFn '${method.id}', validation failed.`,
37
- errorData: validationsResponse
38
- });
39
- } catch (e) {
37
+ return jitFns.isType.fn(value) ? void 0 : new RpcError({
38
+ type: invalidType,
39
+ publicMessage: `Invalid ${subject} Route or Middleware '${methodId}', validation failed.`,
40
+ errorData: { typeErrors: jitFns.typeErrors.fn(value) }
41
+ });
42
+ } catch (err) {
40
43
  return new RpcError({
41
- type: "unexpected-validation-error",
42
- publicMessage: `Could not validate params for Route or MiddleFn '${method.id}': ${e.message} `
44
+ type: failedType,
45
+ publicMessage: `Could not validate ${subject} Route or Middleware '${methodId}': ${err.message}`
43
46
  });
44
47
  }
45
48
  }
46
49
  export {
50
+ getResponseError,
47
51
  validateSubRequest,
48
52
  validateSubRequests
49
53
  };
50
- //# sourceMappingURL=validation.js.map
54
+
55
+ //# sourceMappingURL=validation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"validation.js","sources":["../../../../src/lib/validation.ts"],"sourcesContent":["/* ########\n * 2023 mion\n * Author: Ma-jerez\n * License: MIT\n * The software is provided \"as is\", without warranty of any kind.\n * ######## */\n\nimport {RpcError, routesCache} from '@mionjs/core';\nimport {RequestErrors, SubRequest} from '../types.ts';\nimport type {MionClientRequest} from '../request.ts';\n\n/** Validate subRequests locally using existing RemoteApi metadata */\nexport function validateSubRequests(\n subRequestIds: string[],\n req: MionClientRequest<any, any>,\n errors: RequestErrors,\n validateRouteMiddleFns = true\n): void {\n if (!req.options.validateParams) return;\n subRequestIds.forEach((id) => {\n const subRequest = req.subRequestList[id];\n validateSubRequest(id, subRequest, errors);\n const methodMeta = routesCache.getMetadata(id);\n if (validateRouteMiddleFns && methodMeta?.middleFnIds?.length) {\n const validMiddleFnIds = methodMeta.middleFnIds.filter((middleFnId) => middleFnId != null);\n validateSubRequests(validMiddleFnIds, req, errors, validateRouteMiddleFns);\n }\n });\n return;\n}\n\n/** Validate subRequest locally using existing RemoteApi metadata */\nexport function validateSubRequest(id: string, subRequest: SubRequest<any>, errors: RequestErrors): void {\n if (subRequest?.error || subRequest?.isResolved) return;\n // Skip validation for subrequests with mapFrom mappings — params contain null placeholders\n // that will be filled by the server's mapping step after the source route executes\n const mappings = (subRequest as any)?.mappings;\n if (Array.isArray(mappings) && mappings.length > 0) return;\n\n const params = subRequest?.params || [];\n const validationResponse = getTypeErrors(id, params);\n if (!validationResponse) return;\n const error = validationResponse;\n errors.set(id, error);\n if (subRequest) {\n subRequest.error = error;\n subRequest.isResolved = true;\n }\n return;\n}\n\nfunction getTypeErrors(id: string, params: any[]): void | RpcError<'validation-error' | 'unexpected-validation-error'> {\n const method = routesCache.useMethodJitFns(id);\n if (!method.paramNames || method.paramNames.length === 0) return;\n const paramsJit = method.paramsJitFns;\n if (paramsJit.typeErrors.isNoop) return;\n try {\n const validationsResponse = paramsJit.isType.fn(params) || paramsJit.typeErrors.fn(params);\n if ((validationsResponse as [])?.length) {\n return new RpcError({\n type: 'validation-error',\n publicMessage: `Invalid params for Route or MiddleFn '${method.id}', validation failed.`,\n errorData: validationsResponse,\n });\n }\n } catch (e: any | Error) {\n return new RpcError({\n type: 'unexpected-validation-error',\n publicMessage: `Could not validate params for Route or MiddleFn '${method.id}': ${e.message} `,\n });\n }\n}\n"],"names":[],"mappings":";AAYM,SAAU,oBACZ,eACA,KACA,QACA,yBAAyB,IAAI;AAE7B,EAAK,IAAI,QAAQ,kBACjB,cAAc,QAAQ,CAAC,OAAM;AACzB,UAAM,aAAa,IAAI,eAAe,EAAE;AACxC,uBAAmB,IAAI,YAAY,MAAM;AACzC,UAAM,aAAa,YAAY,YAAY,EAAE;AAC7C,QAAI,0BAA0B,YAAY,aAAa,QAAQ;AAC3D,YAAM,mBAAmB,WAAW,YAAY,OAAO,CAAC,eAAe,cAAc,IAAI;AACzF,0BAAoB,kBAAkB,KAAK,QAAQ,sBAAsB;AAAA,IAC7E;AAAA,EACJ,CAAC;AAEL;SAGgB,mBAAmB,IAAY,YAA6B,QAAqB;AAC7F,MAAI,YAAY,SAAS,YAAY;AAAY;AAGjD,QAAM,WAAY,YAAoB;AACtC,MAAI,MAAM,QAAQ,QAAQ,KAAK,SAAS,SAAS;AAAG;AAEpD,QAAM,SAAS,YAAY,UAAU,CAAA,GAC/B,qBAAqB,cAAc,IAAI,MAAM;AACnD,MAAI,CAAC;AAAoB;AACzB,QAAM,QAAQ;AACd,SAAO,IAAI,IAAI,KAAK,GAChB,eACA,WAAW,QAAQ,OACnB,WAAW,aAAa;AAGhC;AAEA,SAAS,cAAc,IAAY,QAAa;AAC5C,QAAM,SAAS,YAAY,gBAAgB,EAAE;AAC7C,MAAI,CAAC,OAAO,cAAc,OAAO,WAAW,WAAW;AAAG;AAC1D,QAAM,YAAY,OAAO;AACzB,MAAI,WAAU,WAAW;AACzB,QAAI;AACA,YAAM,sBAAsB,UAAU,OAAO,GAAG,MAAM,KAAK,UAAU,WAAW,GAAG,MAAM;AACzF,UAAK,qBAA4B;AAC7B,eAAO,IAAI,SAAS;AAAA,UAChB,MAAM;AAAA,UACN,eAAe,yCAAyC,OAAO,EAAE;AAAA,UACjE,WAAW;AAAA,QAAA,CACd;AAAA,IAET,SAAS,GAAgB;AACrB,aAAO,IAAI,SAAS;AAAA,QAChB,MAAM;AAAA,QACN,eAAe,oDAAoD,OAAO,EAAE,MAAM,EAAE,OAAO;AAAA,MAAA,CAC9F;AAAA,IACL;AACJ;"}
1
+ {"version":3,"file":"validation.js","names":[],"sources":["../../../../src/lib/validation.ts"],"sourcesContent":["/* ########\n * 2023 mion\n * Author: Ma-jerez\n * License: MIT\n * The software is provided \"as is\", without warranty of any kind.\n * ######## */\n\nimport {HeadersSubset, RpcError} from '@mionjs/core';\nimport {getMethod, useMethodFns} from './methods.ts';\nimport type {JitCompiledFunctions, RunTypeError, ValidationErrorData} from '@mionjs/core';\nimport type {CallContext, RequestErrors, SubRequest} from '../types.ts';\n\nexport function validateSubRequests(\n subRequestIds: string[],\n context: CallContext,\n errors: RequestErrors,\n validateRouteMiddlewares = true\n): void {\n if (!context.options.validateParams) return;\n subRequestIds.forEach((id) => {\n const subRequest = context.subRequestList[id];\n validateSubRequest(id, subRequest, errors);\n const methodMeta = getMethod(id);\n if (validateRouteMiddlewares && methodMeta?.middlewareIds?.length) {\n const validMiddlewareIds = methodMeta.middlewareIds.filter((middlewareId) => middlewareId != null);\n validateSubRequests(validMiddlewareIds, context, errors, validateRouteMiddlewares);\n }\n });\n return;\n}\n\nexport function validateSubRequest(id: string, subRequest: SubRequest<any>, errors: RequestErrors): void {\n if (subRequest?.error || subRequest?.isResolved) return;\n // inputFrom params hold null placeholders the server fills after the source route runs\n if (subRequest?.mappings && subRequest.mappings.length > 0) return;\n\n const params = subRequest?.params || [];\n const validationResponse = getTypeErrors(id, params);\n if (!validationResponse) return;\n const error = validationResponse;\n errors.set(id, error);\n if (subRequest) {\n subRequest.error = error;\n subRequest.isResolved = true;\n }\n return;\n}\n\n/** An answer the return type does not describe; undefined when it matches or the method returns nothing. */\nexport function getResponseError(id: string, value: unknown) {\n const method = useMethodFns(id);\n if (!method.hasReturnData) return;\n if (method.headersReturn) {\n // no header on the wire can be a valid void return\n if (!(value instanceof HeadersSubset)) return;\n const jitFns = method.headersReturn.jitFns as JitCompiledFunctions;\n return checkValue(method.id, jitFns, value, 'response-validation-error', 'response-validation-error', 'headers from');\n }\n return checkValue(\n method.id,\n method.returnJitFns,\n value,\n 'response-validation-error',\n 'response-validation-error',\n 'response from'\n );\n}\n\nfunction getTypeErrors(id: string, params: any[]) {\n const method = useMethodFns(id);\n if (!method.paramsCount) return;\n // No separate strict pass: the parser strategy's key check is compiled into isType.\n return checkValue(method.id, method.paramsJitFns, params, 'validation-error', 'unexpected-validation-error', 'params for');\n}\n\n/** typeErrors runs only on a miss, and a validator that throws is reported, never raised. */\nfunction checkValue<Invalid extends string, Failed extends string>(\n methodId: string,\n jitFns: JitCompiledFunctions,\n value: unknown,\n invalidType: Invalid,\n failedType: Failed,\n subject: string\n): RpcError<Invalid, ValidationErrorData> | RpcError<Failed> | undefined {\n if (jitFns.isType.isNoop) return;\n try {\n if (jitFns.isType.fn(value)) return;\n return new RpcError<Invalid, ValidationErrorData>({\n type: invalidType,\n publicMessage: `Invalid ${subject} Route or Middleware '${methodId}', validation failed.`,\n errorData: {typeErrors: jitFns.typeErrors.fn(value) as RunTypeError[]},\n });\n } catch (err: any) {\n return new RpcError<Failed>({\n type: failedType,\n publicMessage: `Could not validate ${subject} Route or Middleware '${methodId}': ${err.message}`,\n });\n }\n}\n"],"mappings":";;AAYA,SAAgB,oBACd,eACA,SACA,QACA,2BAA2B,IACrB;AACN,EAAK,QAAQ,QAAQ,kBACrB,cAAc,QAAA,CAAS,OAAO;AAC5B,UAAM,aAAa,QAAQ,eAAe,EAAA;AAC1C,uBAAmB,IAAI,YAAY,MAAM;AACzC,UAAM,aAAa,UAAU,EAAE;AAC/B,IAAI,4BAA4B,YAAY,eAAe,UAEzD,oBAD2B,WAAW,cAAc,OAAA,CAAQ,iBAAiB,gBAAgB,IACzE,GAAoB,SAAS,QAAQ,wBAAwB;AAAA,EAErF,CAAC;AAEH;AAEA,SAAgB,mBAAmB,IAAY,YAA6B,QAA6B;AAGvG,MAFI,YAAY,SAAS,YAAY,cAEjC,YAAY,YAAY,WAAW,SAAS,SAAS,EAAG;AAG5D,QAAM,qBAAqB,cAAc,IAD1B,YAAY,UAAU,CAAC,CACa;AACnD,MAAI,CAAC,mBAAoB;AACzB,QAAM,QAAQ;AACd,SAAO,IAAI,IAAI,KAAK,GAChB,eACF,WAAW,QAAQ,OACnB,WAAW,aAAa;AAG5B;AAGA,SAAgB,iBAAiB,IAAY,OAAgB;AAC3D,QAAM,SAAS,aAAa,EAAE;AAC9B,MAAK,OAAO,eACZ;AAAA,QAAI,OAAO,eAAe;AAExB,UAAI,EAAE,iBAAiB,eAAgB;AACvC,YAAM,SAAS,OAAO,cAAc;AACpC,aAAO,WAAW,OAAO,IAAI,QAAQ,OAAO,6BAA6B,6BAA6B,cAAc;AAAA,IACtH;AACA,WAAO,WACL,OAAO,IACP,OAAO,cACP,OACA,6BACA,6BACA,eACF;AAAA;AACF;AAEA,SAAS,cAAc,IAAY,QAAe;AAChD,QAAM,SAAS,aAAa,EAAE;AAC9B,MAAK,OAAO;AAEZ,WAAO,WAAW,OAAO,IAAI,OAAO,cAAc,QAAQ,oBAAoB,+BAA+B,YAAY;AAC3H;AAGA,SAAS,WACP,UACA,QACA,OACA,aACA,YACA,SACuE;AACvE,MAAI,QAAO,OAAO;AAClB,QAAI;AACF,aAAI,OAAO,OAAO,GAAG,KAAK,IAAG,SACtB,IAAI,SAAuC;AAAA,QAChD,MAAM;AAAA,QACN,eAAe,WAAW,OAAA,yBAAgC,QAAA;AAAA,QAC1D,WAAW,EAAC,YAAY,OAAO,WAAW,GAAG,KAAK,EAAmB;AAAA,MACvE,CAAC;AAAA,IACH,SAAS,KAAU;AACjB,aAAO,IAAI,SAAiB;AAAA,QAC1B,MAAM;AAAA,QACN,eAAe,sBAAsB,OAAA,yBAAgC,QAAA,MAAc,IAAI,OAAA;AAAA,MACzF,CAAC;AAAA,IACH;AACF"}
@@ -0,0 +1,4 @@
1
+ import { FetchMetadataHandler as Handler } from '@mionjs/core/middlewares';
2
+ import { ClientMiddlewareOf } from '../types.ts';
3
+ export declare function useFetchMetadata(middleware: ClientMiddlewareOf<Handler>): void;
4
+ //# sourceMappingURL=fetchMetadata.d.ts.map
@@ -0,0 +1,85 @@
1
+ import { hasMethod } from "../lib/methods.js";
2
+ import { getRoutePointers } from "../callContext.js";
3
+ import { hasApiVersionMismatch } from "../lib/apiBuildVersion.js";
4
+ import { middlewareTargetOf, setMetadataFetcher } from "../lib/metadataFetcher.js";
5
+ import { loadMetadataFromServer, loadedMetadataFromServer } from "../lib/metadataFromServerLoader.js";
6
+ import { RpcError, isRpcError } from "@mionjs/core";
7
+ function useFetchMetadata(middleware) {
8
+ const { id, registry } = middlewareTargetOf(middleware);
9
+ setMetadataFetcher(registry, createFetcher(id));
10
+ }
11
+ function createFetcher(id) {
12
+ const fetchRows = async (ids, routePointer, options, signal) => {
13
+ await (await loadMetadataFromServer()).fetchRemoteMethodsMetadata(ids, routePointer, options, signal, id);
14
+ };
15
+ return {
16
+ fetchRows,
17
+ startCall: (context) => startCall(id, context, fetchRows)
18
+ };
19
+ }
20
+ function failedOnWire(errors) {
21
+ for (const error of errors.values()) {
22
+ const type = error?.type;
23
+ if (type === "serialization-error" || type === "validation-error" || type === "parsing-json-request-error") return !0;
24
+ }
25
+ return !1;
26
+ }
27
+ function startCall(id, context, fetchRows) {
28
+ const { options } = context;
29
+ let optimistic = !1, verifying, callIds = [];
30
+ const addRowsRequest = (ids) => {
31
+ context.subRequestList[id] = {
32
+ pointer: id.split("/"),
33
+ id,
34
+ isResolved: !1,
35
+ params: [ids]
36
+ };
37
+ };
38
+ return {
39
+ id,
40
+ async prepare(skipOptimistic) {
41
+ delete context.subRequestList[id];
42
+ const ids = Object.keys(context.subRequestList);
43
+ if (callIds = ids, verifying = void 0, optimistic = !1, !ids.every((methodId) => hasMethod(methodId)))
44
+ return await (await loadMetadataFromServer()).hydrateMetadataCache(options), optimistic = !skipOptimistic && !ids.every((methodId) => hasMethod(methodId)), {
45
+ ids,
46
+ optimistic
47
+ };
48
+ if (hasApiVersionMismatch(options.baseURL) && hasMethod(id)) {
49
+ const unverified = (await loadMetadataFromServer()).unverifiedIds(options.baseURL, ids);
50
+ unverified.length && (verifying = unverified, addRowsRequest(unverified));
51
+ }
52
+ return {
53
+ ids,
54
+ optimistic
55
+ };
56
+ },
57
+ askRows() {
58
+ addRowsRequest(Object.keys(context.subRequestList).filter((methodId) => !hasMethod(methodId)));
59
+ },
60
+ fetchRows(ids, signal) {
61
+ return fetchRows(ids, getRoutePointers(context)[0] ?? Object.values(context.subRequestList)[0].pointer, options, signal);
62
+ },
63
+ readRows(parsedBody) {
64
+ if (!(id in parsedBody)) return;
65
+ const slot = parsedBody[id];
66
+ delete parsedBody[id];
67
+ const value = Array.isArray(slot) ? slot[1] : slot;
68
+ if (isRpcError(value)) return { [id]: new RpcError(value) };
69
+ const rows = value, lane = loadedMetadataFromServer();
70
+ !rows?.methods || !lane || (verifying ? lane.verifyMethodRows(options, verifying, rows) : lane.installMethodRows(rows, options));
71
+ },
72
+ async shouldResend(errors) {
73
+ if (!failedOnWire(errors) || context.signal?.aborted) return !1;
74
+ if (optimistic) return !0;
75
+ const lane = loadedMetadataFromServer();
76
+ return lane && callIds.some((methodId) => lane.wasHydratedFromCache(methodId, options)) ? (await lane.purgeHydratedMetadata(callIds, options), !0) : hasApiVersionMismatch(options.baseURL);
77
+ },
78
+ takeError: () => loadedMetadataFromServer()?.takeMetadataCacheError()
79
+ };
80
+ }
81
+ export {
82
+ useFetchMetadata
83
+ };
84
+
85
+ //# sourceMappingURL=fetchMetadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetchMetadata.js","names":[],"sources":["../../../../src/middlewares/fetchMetadata.ts"],"sourcesContent":["/* ########\n * 2026 mion\n * Author: Ma-jerez\n * License: MIT\n * The software is provided \"as is\", without warranty of any kind.\n * ######## */\n\nimport {isRpcError, RpcError} from '@mionjs/core';\nimport type {SerializableMethodsData} from '@mionjs/core';\nimport type {FetchMetadataHandler as Handler} from '@mionjs/core/middlewares';\nimport type {ClientCallContext, ClientMiddlewareOf, RequestErrors, SubRequest} from '../types.ts';\nimport {getRoutePointers} from '../callContext.ts';\nimport {hasApiVersionMismatch} from '../lib/apiBuildVersion.ts';\nimport {hasMethod} from '../lib/methods.ts';\nimport {loadedMetadataFromServer, loadMetadataFromServer} from '../lib/metadataFromServerLoader.ts';\nimport {middlewareTargetOf, setMetadataFetcher, type MetadataCall, type MetadataFetcher} from '../lib/metadataFetcher.ts';\n\n/** Client half of `mionFetchMetadata`: fetches unbundled routes' rows on first use. */\nexport function useFetchMetadata(middleware: ClientMiddlewareOf<Handler>): void {\n const {id, registry} = middlewareTargetOf(middleware);\n setMetadataFetcher(registry, createFetcher(id));\n}\n\nfunction createFetcher(id: string): MetadataFetcher {\n const fetchRows: MetadataFetcher['fetchRows'] = async (ids, routePointer, options, signal) => {\n const lane = await loadMetadataFromServer();\n await lane.fetchRemoteMethodsMetadata(ids, routePointer, options, signal, id);\n };\n return {fetchRows, startCall: (context) => startCall(id, context, fetchRows)};\n}\n\n/** The errors plain wire forms or stale rows cause: the server could not read what the client wrote. */\nfunction failedOnWire(errors: RequestErrors): boolean {\n for (const error of errors.values()) {\n const type = error?.type;\n if (type === 'serialization-error' || type === 'validation-error' || type === 'parsing-json-request-error') return true;\n }\n return false;\n}\n\nfunction startCall(id: string, context: ClientCallContext, fetchRows: MetadataFetcher['fetchRows']): MetadataCall {\n const {options} = context;\n let optimistic = false;\n /** ids this attempt asked the server to confirm after a version mismatch */\n let verifying: string[] | undefined;\n let callIds: string[] = [];\n\n const addRowsRequest = (ids: string[]) => {\n context.subRequestList[id] = {pointer: id.split('/'), id, isResolved: false, params: [ids]} as SubRequest<any>;\n };\n\n return {\n id,\n\n async prepare(skipOptimistic) {\n delete context.subRequestList[id];\n const ids = Object.keys(context.subRequestList);\n callIds = ids;\n verifying = undefined;\n optimistic = false;\n if (!ids.every((methodId) => hasMethod(methodId))) {\n // One indexed read settles an id this page never heard of; guessing wrong costs a round trip AND its resend.\n await (await loadMetadataFromServer()).hydrateMetadataCache(options);\n optimistic = !skipOptimistic && !ids.every((methodId) => hasMethod(methodId));\n return {ids, optimistic};\n }\n // After a version mismatch each route is confirmed once, on first use, riding this request.\n // Needs the middleware's own row: it encodes the ids, and a server that never placed it cannot confirm.\n if (hasApiVersionMismatch(options.baseURL) && hasMethod(id)) {\n const unverified = (await loadMetadataFromServer()).unverifiedIds(options.baseURL, ids);\n if (unverified.length) {\n verifying = unverified;\n addRowsRequest(unverified);\n }\n }\n return {ids, optimistic};\n },\n\n askRows() {\n // Storing the server's copy over a BUNDLED method would let a later purge drop it for good.\n addRowsRequest(Object.keys(context.subRequestList).filter((methodId) => !hasMethod(methodId)));\n },\n\n fetchRows(ids, signal) {\n // sent to a route of this call, whose chain holds the metadata middleware\n const pointer = getRoutePointers(context)[0] ?? Object.values(context.subRequestList)[0].pointer;\n return fetchRows(ids, pointer, options, signal);\n },\n\n readRows(parsedBody) {\n if (!(id in parsedBody)) return;\n const slot = parsedBody[id];\n delete parsedBody[id];\n // a union answer rides the `[index, value]` envelope\n const value = Array.isArray(slot) ? slot[1] : slot;\n if (isRpcError(value)) return {[id]: new RpcError(value)};\n const rows = value as SerializableMethodsData | undefined;\n // only an attempt that loaded the lane asks for rows\n const lane = loadedMetadataFromServer();\n if (!rows?.methods || !lane) return;\n if (verifying) lane.verifyMethodRows(options, verifying, rows);\n else lane.installMethodRows(rows, options);\n },\n\n async shouldResend(errors) {\n if (!failedOnWire(errors) || context.signal?.aborted) return false;\n // the server read plain wire forms its decoders refused; the real encoders fix that\n if (optimistic) return true;\n // stored rows can predate the server's current build and nothing else would correct them\n const lane = loadedMetadataFromServer();\n if (lane && callIds.some((methodId) => lane.wasHydratedFromCache(methodId, options))) {\n await lane.purgeHydratedMetadata(callIds, options);\n return true;\n }\n // the server's build differs: the resend confirms the rows this call uses, and refreshes fetched ones\n return hasApiVersionMismatch(options.baseURL);\n },\n\n takeError: () => loadedMetadataFromServer()?.takeMetadataCacheError(),\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { SyncRoutesHandler } from '@mionjs/core/middlewares';
2
+ import { ClientMiddlewareOf } from '../types.ts';
3
+ export declare function useSyncRoutes(middleware: ClientMiddlewareOf<SyncRoutesHandler>): void;
4
+ //# sourceMappingURL=syncRoutes.d.ts.map
@@ -0,0 +1,20 @@
1
+ import { getMethod, isBundledMethod } from "../lib/methods.js";
2
+ import { metadataFetcherOf } from "../lib/metadataFetcher.js";
3
+ import { loadMetadataFromServer } from "../lib/metadataFromServerLoader.js";
4
+ function useSyncRoutes(middleware) {
5
+ middleware.onRequest((call, context) => call(routeSyncIds(context))), middleware.onError("route-sync-required", async (refusal, context) => {
6
+ const rows = refusal.errorData?.metadata;
7
+ rows?.methods && (await loadMetadataFromServer()).installMethodRows(rows, context.options, Object.keys(rows.methods)), context.retry();
8
+ }), middleware.onError("route-types-mismatch", async (refusal, context) => {
9
+ const refusedIds = refusal.errorData?.routeIds, fetcher = metadataFetcherOf(middleware);
10
+ !fetcher || !refusedIds?.length || refusedIds.some((id) => isBundledMethod(id)) || (await (await loadMetadataFromServer()).forgetFetchedMetadata(refusedIds, context.options), await fetcher.fetchRows(refusedIds, refusedIds[0].split("/"), context.options, context.signal), context.retry());
11
+ });
12
+ }
13
+ function routeSyncIds(context) {
14
+ return (context.batchSubRequests?.length ? context.batchSubRequests : context.route ? [context.route] : []).map((route) => getMethod(route.id)?.syncId ?? "");
15
+ }
16
+ export {
17
+ useSyncRoutes
18
+ };
19
+
20
+ //# sourceMappingURL=syncRoutes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syncRoutes.js","names":[],"sources":["../../../../src/middlewares/syncRoutes.ts"],"sourcesContent":["/* ########\n * 2026 mion\n * Author: Ma-jerez\n * License: MIT\n * The software is provided \"as is\", without warranty of any kind.\n * ######## */\n\nimport type {SyncRoutesHandler} from '@mionjs/core/middlewares';\nimport type {CallContext, ClientMiddlewareOf} from '../types.ts';\nimport {getMethod, isBundledMethod} from '../lib/methods.ts';\nimport {loadMetadataFromServer} from '../lib/metadataFromServerLoader.ts';\nimport {metadataFetcherOf} from '../lib/metadataFetcher.ts';\n\n/** Client half of `mionSyncRoutes`: sends each route's sync id, and resends once when the server asks for it. */\nexport function useSyncRoutes(middleware: ClientMiddlewareOf<SyncRoutesHandler>): void {\n middleware.onRequest((call, context) => call(routeSyncIds(context)));\n\n // no route ran, so a resend is always allowed\n middleware.onError('route-sync-required', async (refusal, context) => {\n const rows = refusal.errorData?.metadata;\n if (rows?.methods) (await loadMetadataFromServer()).installMethodRows(rows, context.options, Object.keys(rows.methods));\n context.retry();\n });\n\n // a fetched row is a cache of the server's and can be relearned; a bundled one needs a new build\n middleware.onError('route-types-mismatch', async (refusal, context) => {\n const refusedIds = refusal.errorData?.routeIds;\n const fetcher = metadataFetcherOf(middleware);\n if (!fetcher || !refusedIds?.length || refusedIds.some((id) => isBundledMethod(id))) return;\n await (await loadMetadataFromServer()).forgetFetchedMetadata(refusedIds, context.options);\n // fetched here rather than on a second refusal: a call gets one resend per middleware\n await fetcher.fetchRows(refusedIds, refusedIds[0].split('/'), context.options, context.signal);\n context.retry();\n });\n}\n\n/** In the server's batch order; the server answers an '' id with the rows. */\nfunction routeSyncIds(context: CallContext): string[] {\n const routes = context.batchSubRequests?.length ? context.batchSubRequests : context.route ? [context.route] : [];\n return routes.map((route) => getMethod(route.id)?.syncId ?? '');\n}\n"],"mappings":";;;AAcA,SAAgB,cAAc,YAAyD;AACrF,aAAW,UAAA,CAAW,MAAM,YAAY,KAAK,aAAa,OAAO,CAAC,CAAC,GAGnE,WAAW,QAAQ,uBAAuB,OAAO,SAAS,YAAY;AACpE,UAAM,OAAO,QAAQ,WAAW;AAChC,IAAI,MAAM,YAAU,MAAM,uBAAuB,GAAG,kBAAkB,MAAM,QAAQ,SAAS,OAAO,KAAK,KAAK,OAAO,CAAC,GACtH,QAAQ,MAAM;AAAA,EAChB,CAAC,GAGD,WAAW,QAAQ,wBAAwB,OAAO,SAAS,YAAY;AACrE,UAAM,aAAa,QAAQ,WAAW,UAChC,UAAU,kBAAkB,UAAU;AAC5C,IAAI,CAAC,WAAW,CAAC,YAAY,UAAU,WAAW,KAAA,CAAM,OAAO,gBAAgB,EAAE,CAAC,MAClF,OAAO,MAAM,uBAAuB,GAAG,sBAAsB,YAAY,QAAQ,OAAO,GAExF,MAAM,QAAQ,UAAU,YAAY,WAAW,CAAA,EAAG,MAAM,GAAG,GAAG,QAAQ,SAAS,QAAQ,MAAM,GAC7F,QAAQ,MAAM;AAAA,EAChB,CAAC;AACH;AAGA,SAAS,aAAa,SAAgC;AAEpD,UADe,QAAQ,kBAAkB,SAAS,QAAQ,mBAAmB,QAAQ,QAAQ,CAAC,QAAQ,KAAK,IAAI,CAAC,GAClG,IAAA,CAAK,UAAU,UAAU,MAAM,EAAE,GAAG,UAAU,EAAE;AAChE"}
@@ -1,8 +1,7 @@
1
- import { RpcError, RunTypeError, MapFromServerFnRef } from '@mionjs/core';
2
- import { CallSetup, MiddlewareSubRequest, RequestErrors, RouteSubRequest, SubRequest } from './types.ts';
1
+ import { RpcError, RunTypeError, InputFromRef } from '@mionjs/core';
2
+ import { CallSetup, RequestErrors, RouteSubRequest, SubRequest, InjectedApiMetadata } from './types.ts';
3
3
  import { MionClient } from './client.ts';
4
- import { TypedEvent } from './lib/typedEvent.ts';
5
- export declare class MionSubRequest<S = any, E extends RpcError<string, any> = any> implements RouteSubRequest<any>, MiddlewareSubRequest<any> {
4
+ export declare class MionSubRequest<S = any, E extends RpcError<string, any> = any> implements RouteSubRequest<any> {
6
5
  readonly client: MionClient;
7
6
  pointer: string[];
8
7
  id: string;
@@ -11,13 +10,10 @@ export declare class MionSubRequest<S = any, E extends RpcError<string, any> = a
11
10
  resolvedValue?: S;
12
11
  error?: E;
13
12
  serializedParams?: any[];
14
- mappings: MapFromServerFnRef[];
13
+ mappings: InputFromRef[];
15
14
  constructor(parentProps: string[], handlerId: string, argArray: any[], client: MionClient);
16
- prefill(): TypedEvent<S, E>;
17
- removePrefill(): Promise<void>;
18
- call(setup?: CallSetup<any, any>): Promise<any>;
19
- private executeWithOtherRoutes;
20
- typeErrors(): Promise<RunTypeError[]>;
15
+ call(setup?: CallSetup, apiMetadata?: InjectedApiMetadata): Promise<any>;
16
+ typeErrors(apiMetadata?: InjectedApiMetadata): Promise<RunTypeError[]>;
21
17
  }
22
18
  export declare function findSubRequestError(subRequest: SubRequest<any>, errors: RequestErrors): RpcError<string>;
23
19
  //# sourceMappingURL=subRequest.d.ts.map