@mionjs/client 0.8.8 → 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,2 +1,3 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const core=require("@mionjs/core"),src_constants=require("../constants.cjs"),src_lib_storage=require("./storage.cjs"),METHOD_DATA_PREFIX=`${src_constants.STORAGE_KEY}:method-data:`,JIT_FN_PREFIX=`${src_constants.STORAGE_KEY}:jit-fn:`,PURE_FN_PREFIX=`${src_constants.STORAGE_KEY}:pure-fn:`;function extractAndProcessMetadata(routeKey,parsedBody,options){if(typeof parsedBody!="object"||!(routeKey in parsedBody))return;const rawMetadata=parsedBody[routeKey];if(delete parsedBody[routeKey],!rawMetadata)return;const metadataValue=Array.isArray(rawMetadata)?rawMetadata[1]:rawMetadata;metadataValue&&!core.isRpcError(metadataValue)&&metadataValue.methods&&processMethodsMetadata(metadataValue,options)}function processMethodsMetadata(serializableMethodsData,options){storeDependencies(serializableMethodsData.deps,serializableMethodsData.purFnDeps,options),storeMethodsMetadata(serializableMethodsData.methods,options),addToCaches(serializableMethodsData)}function getSerializedMethodDataKey(methodId,options){return`${METHOD_DATA_PREFIX}${methodId}:${options.baseURL}`}function getJitCompiledFnKey(jitFnHash,options){return`${JIT_FN_PREFIX}${jitFnHash}:${options.baseURL}`}function getJitPureFnKey(namespace,pureFnHash,options){return`${PURE_FN_PREFIX}${namespace}:${pureFnHash}:${options.baseURL}`}function storeDependencies(deps,pureFnDeps,options){Object.entries(deps).forEach(([hash,jitFnData])=>{const key=getJitCompiledFnKey(hash,options);try{src_lib_storage.getStorage().setItem(key,JSON.stringify(jitFnData))}catch(error){console.warn(`Failed to store JIT function dependency ${hash}:`,error)}}),Object.entries(pureFnDeps).forEach(([namespace,nsPureFns])=>{Object.entries(nsPureFns).forEach(([fnHash,pureFnData])=>{const key=getJitPureFnKey(namespace,fnHash,options);try{src_lib_storage.getStorage().setItem(key,JSON.stringify(pureFnData))}catch(error){console.warn(`Failed to store pure function dependency ${namespace}::${fnHash}:`,error)}})})}function storeMethodsMetadata(methods,options){Object.entries(methods).forEach(([methodId,methodData])=>{const key=getSerializedMethodDataKey(methodId,options);try{src_lib_storage.getStorage().setItem(key,JSON.stringify(methodData))}catch(error){console.warn(`Failed to store method metadata ${methodId}:`,error)}})}function restoreAllDependencies(options){const deps={},pureFnDeps={},baseURLSuffix=`:${options.baseURL}`;for(let i=0;i<src_lib_storage.getStorage().length;i++){const key=src_lib_storage.getStorage().key(i);if(key?.startsWith(JIT_FN_PREFIX)&&key.endsWith(baseURLSuffix))try{const data=src_lib_storage.getStorage().getItem(key);if(data){const parsedData=JSON.parse(data);deps[parsedData.jitFnHash]=parsedData}}catch(error){console.warn(`Failed to restore JIT function from key ${key}:`,error)}}for(let i=0;i<src_lib_storage.getStorage().length;i++){const key=src_lib_storage.getStorage().key(i);if(key?.startsWith(PURE_FN_PREFIX)&&key.endsWith(baseURLSuffix))try{const data=src_lib_storage.getStorage().getItem(key);if(data){const parsedData=JSON.parse(data),namespace=key.slice(PURE_FN_PREFIX.length,key.length-baseURLSuffix.length).split(":")[0]||parsedData.namespace;pureFnDeps[namespace]||(pureFnDeps[namespace]={}),pureFnDeps[namespace][parsedData.fnName]=parsedData}}catch(error){console.warn(`Failed to restore pure function from key ${key}:`,error)}}(Object.keys(deps).length>0||Object.keys(pureFnDeps).length>0)&&core.addSerializedJitCaches(deps,pureFnDeps)}function createMetadataSubRequest(methodIds){return{pointer:[core.MION_ROUTES.methodsMetadata],id:core.MION_ROUTES.methodsMetadata,isResolved:!1,params:[methodIds]}}function restoreFromLocalStorage(methodIds,options){restoreAllDependencies(options);const methods={};let anyMethodsRestored=!1;methodIds.forEach(id=>{if(core.routesCache.hasMetadata(id))return;const methodKey=getSerializedMethodDataKey(id,options),methodMetaJson=src_lib_storage.getStorage().getItem(methodKey);if(methodMetaJson)try{const methodMeta=JSON.parse(methodMetaJson);methods[id]=methodMeta,anyMethodsRestored=!0}catch(error){console.warn(`Failed to restore method metadata for ${id}:`,error),src_lib_storage.getStorage().removeItem(methodKey)}}),anyMethodsRestored&&addToCaches({methods,deps:{},purFnDeps:{}})}function addToCaches(serializableMethodsData){core.addSerializedJitCaches(serializableMethodsData.deps,serializableMethodsData.purFnDeps),core.addRoutesToCache(serializableMethodsData.methods)}exports.createMetadataSubRequest=createMetadataSubRequest;exports.extractAndProcessMetadata=extractAndProcessMetadata;exports.restoreAllDependencies=restoreAllDependencies;exports.restoreFromLocalStorage=restoreFromLocalStorage;exports.storeDependencies=storeDependencies;exports.storeMethodsMetadata=storeMethodsMetadata;
2
- //# sourceMappingURL=clientMethodsMetadata.cjs.map
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const require_src_constants=require("../constants.cjs"),require_src_lib_metadataStore=require("./metadataStore.cjs"),require_src_lib_persistentStorage=require("./persistentStorage.cjs"),require_src_lib_methods=require("./methods.cjs"),require_src_lib_metadataEviction=require("./metadataEviction.cjs");let _mionjs_core=require("@mionjs/core");var states=new Map,writeQueue=[],flushHandle,flushChain=Promise.resolve(),persistenceAsked=!1,pendingCacheError;function getState(options){const baseURL=options.baseURL;let state=states.get(baseURL);return state||(state={baseURL,storageEngine:options.storageEngine,hydratedIds:new Set,stored:new Map,bytes:0,graph:{methods:Object.create(null),deps:Object.create(null),pureFns:Object.create(null)},sweepScheduled:!1},states.set(baseURL,state)),state}function storedKey(kind,id){return`${kind} ${id}`}function processMethodsMetadata(serializableMethodsData,options){addToCaches(serializableMethodsData),queuePersist(serializableMethodsData,options)}function isStorableName(name){return!(0,_mionjs_core.isUnsafePropertyName)(name)&&!name.includes(":")}function queuePersist(data,options){writeQueue.push({data,options}),scheduleFlush()}function scheduleFlush(){if(flushHandle!==void 0)return;const run=()=>{flushHandle=void 0,flushChain=flushChain.then(flushQueue)},idle=globalThis.requestIdleCallback;flushHandle=typeof idle=="function"?idle(run,{timeout:200}):setTimeout(run,0)}function flushMetadataCache(){if(flushHandle!==void 0){const cancelIdle=globalThis.cancelIdleCallback;typeof cancelIdle=="function"?cancelIdle(flushHandle):clearTimeout(flushHandle),flushHandle=void 0}return flushChain=flushChain.then(flushQueue),flushChain}async function flushQueue(){if(!writeQueue.length)return;const batch=writeQueue;writeQueue=[];const byBaseURL=new Map;for(const item of batch){const group=byBaseURL.get(item.options.baseURL);group?group.payloads.push(item.data):byBaseURL.set(item.options.baseURL,{options:item.options,payloads:[item.data]})}for(const group of byBaseURL.values())await persistPayloads(group.options,group.payloads)}async function persistPayloads(options,payloads){const baseURL=options.baseURL,state=getState(options),ts=Date.now(),records=new Map,add=(kind,id,value)=>{const key=storedKey(kind,id);if(!(kind!=="m"&&state.stored.has(key)))try{records.set(key,{baseURL,kind,id,json:JSON.stringify(value),ts})}catch(error){console.warn(`Failed to serialize metadata cache entry ${id}:`,error)}};for(const payload of payloads){for(const[hash,jitFnData]of Object.entries(payload.deps??{})){if(!isStorableName(hash)){console.warn(`Refused to store JIT function dependency under '${hash}'`);continue}add("j",hash,jitFnData)}for(const[id,pureFnData]of Object.entries(payload.purFnDeps??{})){if(!isStorableName(id)){console.warn(`Refused to store pure function '${id}'`);continue}add("p",id,pureFnData)}for(const[methodId,methodData]of Object.entries(payload.methods??{})){if(!isStorableName(methodId)){console.warn(`Refused to store metadata for method '${methodId}'`);continue}require_src_lib_methods.isBundledMethod(methodId)||add("m",methodId,methodData)}}records.size&&await writeRecords(state,[...records.values()])}function recordBytes(record){return record.json.length+record.id.length}async function writeRecords(state,records){const store=await require_src_lib_metadataStore.getMetadataStore(state.storageEngine),incoming=records.reduce((total,record)=>total+recordBytes(record),0);await evictOldest(state,store,state.bytes+incoming-require_src_constants.METADATA_CACHE_MAX_BYTES);for(let round=0;;round++)try{await store.write(records);for(const record of records){const key=storedKey(record.kind,record.id),previous=state.stored.get(key);previous&&(state.bytes-=previous.bytes);const bytes=recordBytes(record);state.stored.set(key,{kind:record.kind,id:record.id,ts:record.ts,bytes}),state.bytes+=bytes}askForPersistenceOnce();return}catch(error){if(round>=5||!await evictOldest(state,store,Math.max(state.bytes/4,incoming)))return reportCacheError(error)}}async function evictOldest(state,store,targetBytes){if(targetBytes<=0||!state.stored.size)return 0;const oldestFirst=[...state.stored.values()].sort((a,b)=>a.ts-b.ts),keys=[];let freed=0;for(const entry of oldestFirst)if(keys.push([entry.kind,entry.id]),freed+=entry.bytes,freed>=targetBytes)break;try{await store.remove(state.baseURL,keys)}catch{return 0}for(const[kind,id]of keys){const key=storedKey(kind,id);state.bytes-=state.stored.get(key)?.bytes??0,state.stored.delete(key),kind==="j"?delete state.graph.deps[id]:kind==="p"?delete state.graph.pureFns[id]:delete state.graph.methods[id]}return freed}function reportCacheError(error){const rpcError=new _mionjs_core.RpcError({type:"metadata-cache-error",publicMessage:"Could not store the remote method metadata cache",originalError:error instanceof Error?error:void 0});console.error("[mion] metadata cache write failed:",error),pendingCacheError=rpcError}function takeMetadataCacheError(){const error=pendingCacheError;return pendingCacheError=void 0,error}function askForPersistenceOnce(){persistenceAsked||(persistenceAsked=!0,require_src_lib_persistentStorage.requestPersistenceWhenSilent())}function hydrateMetadataCache(options){const state=getState(options);return state.hydration||(state.hydration=hydrate(state).catch(error=>{console.warn("Failed to restore the remote method metadata cache:",error)})),state.hydration}async function hydrate(state){const records=await(await require_src_lib_metadataStore.getMetadataStore(state.storageEngine)).readAll(state.baseURL);if(!records.length)return;const deps=Object.create(null),pureFnDeps=Object.create(null),methods=Object.create(null);for(const record of records){if(!isStorableName(record.id))continue;let parsed;try{parsed=JSON.parse(record.json)}catch(error){console.warn(`Failed to restore metadata cache entry ${record.id}:`,error);continue}const key=storedKey(record.kind,record.id);if(state.stored.set(key,{kind:record.kind,id:record.id,ts:record.ts,bytes:recordBytes(record)}),state.bytes+=recordBytes(record),record.kind==="j")deps[record.id]=parsed,state.graph.deps[record.id]=parsed;else if(record.kind==="p"){if(typeof parsed?.code!="string"){console.warn(`Ignoring cached pure function ${record.id}: it carries no code`);continue}pureFnDeps[record.id]=parsed,state.graph.pureFns[record.id]=parsed}else methods[record.id]=parsed,state.graph.methods[record.id]=parsed}(0,_mionjs_core.addSerializedJitCaches)(deps,pureFnDeps);const restorable={},unusable=[];for(const[id,metadata]of Object.entries(methods))(0,_mionjs_core.hasJitFnsForMethod)(metadata)?(restorable[id]=metadata,state.hydratedIds.add(id)):(unusable.push(["m",id]),delete state.graph.methods[id]);(0,_mionjs_core.addRoutesToCache)(restorable),scheduleSweep(state,unusable)}function wasHydratedFromCache(id,options){return states.get(options.baseURL)?.hydratedIds.has(id)===!0}async function purgeHydratedMetadata(ids,options){const state=states.get(options.baseURL);if(!state)return;const hydrated=ids.filter(id=>state.hydratedIds.has(id));for(const id of hydrated)_mionjs_core.routesCache.removeMetadata(id);await dropStoredMethods(state,hydrated)}async function forgetFetchedMetadata(ids,options){const fetchedIds=ids.filter(id=>!require_src_lib_methods.isBundledMethod(id));for(const id of fetchedIds)_mionjs_core.routesCache.removeMetadata(id);for(const queued of writeQueue)if(queued.options.baseURL===options.baseURL)for(const id of fetchedIds)delete queued.data.methods[id];const state=states.get(options.baseURL);state&&await dropStoredMethods(state,fetchedIds)}async function dropStoredMethods(state,ids){const keys=[];for(const id of ids)state.hydratedIds.delete(id),delete state.graph.methods[id],keys.push(["m",id]);if(keys.length){await(await require_src_lib_metadataStore.getMetadataStore(state.storageEngine)).remove(state.baseURL,keys).catch(()=>{});for(const[kind,id]of keys){const key=storedKey(kind,id);state.bytes-=state.stored.get(key)?.bytes??0,state.stored.delete(key)}await sweepOrphans(state)}}function scheduleSweep(state,alsoDelete){if(state.sweepScheduled)return;state.sweepScheduled=!0;const run=()=>{sweepOrphans(state,alsoDelete)},idle=globalThis.requestIdleCallback;typeof idle=="function"?idle(run,{timeout:2e3}):setTimeout(run,0)}async function sweepOrphans(state,alsoDelete=[]){const keys=[...alsoDelete,...require_src_lib_metadataEviction.findOrphans(state.graph)];if(keys.length){await(await require_src_lib_metadataStore.getMetadataStore(state.storageEngine)).remove(state.baseURL,keys).catch(()=>{});for(const[kind,id]of keys){const key=storedKey(kind,id);state.bytes-=state.stored.get(key)?.bytes??0,state.stored.delete(key),kind==="j"?delete state.graph.deps[id]:kind==="p"?delete state.graph.pureFns[id]:delete state.graph.methods[id]}}}function resetMetadataCacheState(){states.clear(),writeQueue=[],persistenceAsked=!1,pendingCacheError=void 0}function installMethodRows(serializableMethodsData,options,replaceIds=[]){for(const id of replaceIds)_mionjs_core.routesCache.removeMetadata(id);processMethodsMetadata(serializableMethodsData,options)}function addToCaches(serializableMethodsData){(0,_mionjs_core.addSerializedJitCaches)(serializableMethodsData.deps,serializableMethodsData.purFnDeps),(0,_mionjs_core.addRoutesToCache)(serializableMethodsData.methods)}require_src_lib_methods.setFetchedMethods(_mionjs_core.routesCache);exports.flushMetadataCache=flushMetadataCache;exports.forgetFetchedMetadata=forgetFetchedMetadata;exports.hydrateMetadataCache=hydrateMetadataCache;exports.installMethodRows=installMethodRows;exports.purgeHydratedMetadata=purgeHydratedMetadata;exports.resetMetadataCacheState=resetMetadataCacheState;exports.takeMetadataCacheError=takeMetadataCacheError;exports.wasHydratedFromCache=wasHydratedFromCache;
2
+
3
+ //# sourceMappingURL=clientMethodsMetadata.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"clientMethodsMetadata.cjs","sources":["../../../../src/lib/clientMethodsMetadata.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 {isRpcError, addRoutesToCache} from '@mionjs/core';\nimport {MION_ROUTES} from '@mionjs/core';\nimport {ClientOptions, SubRequest} from '../types.ts';\nimport type {\n JitCompiledFnData,\n MethodsCache,\n MethodWithOptions,\n PureFunctionData,\n SerializableMethodsData,\n PureFnsDataCache,\n} from '@mionjs/core';\nimport {routesCache, addSerializedJitCaches} from '@mionjs/core';\nimport {STORAGE_KEY} from '../constants.ts';\nimport {getStorage} from './storage.ts';\n\nconst METHOD_DATA_PREFIX = `${STORAGE_KEY}:method-data:`;\nconst JIT_FN_PREFIX = `${STORAGE_KEY}:jit-fn:`;\nconst PURE_FN_PREFIX = `${STORAGE_KEY}:pure-fn:`;\n\ntype MetadataRouteKey = typeof MION_ROUTES.methodsMetadata | typeof MION_ROUTES.methodsMetadataById;\n\n/** Extracts raw metadata from a parsed response body, unwraps the JIT union discriminator, and processes it. */\nexport function extractAndProcessMetadata(routeKey: MetadataRouteKey, parsedBody: any, options: ClientOptions): void {\n if (typeof parsedBody !== 'object' || !(routeKey in parsedBody)) return;\n const rawMetadata = parsedBody[routeKey];\n delete parsedBody[routeKey];\n if (!rawMetadata) return;\n const metadataValue = Array.isArray(rawMetadata) ? rawMetadata[1] : rawMetadata;\n if (metadataValue && !isRpcError(metadataValue) && metadataValue.methods) {\n processMethodsMetadata(metadataValue as SerializableMethodsData, options);\n }\n}\n\n/** Processes metadata from an optimistic response and caches it */\nfunction processMethodsMetadata(serializableMethodsData: SerializableMethodsData, options: ClientOptions): void {\n storeDependencies(serializableMethodsData.deps, serializableMethodsData.purFnDeps, options);\n storeMethodsMetadata(serializableMethodsData.methods, options);\n addToCaches(serializableMethodsData);\n}\n\nfunction getSerializedMethodDataKey(methodId: string, options: ClientOptions) {\n return `${METHOD_DATA_PREFIX}${methodId}:${options.baseURL}`;\n}\n\nfunction getJitCompiledFnKey(jitFnHash: string, options: ClientOptions) {\n return `${JIT_FN_PREFIX}${jitFnHash}:${options.baseURL}`;\n}\n\nfunction getJitPureFnKey(namespace: string, pureFnHash: string, options: ClientOptions) {\n return `${PURE_FN_PREFIX}${namespace}:${pureFnHash}:${options.baseURL}`;\n}\n\n/** Stores JIT compiled functions and pure functions globally in localStorage */\nexport function storeDependencies(deps: Record<string, JitCompiledFnData>, pureFnDeps: PureFnsDataCache, options: ClientOptions) {\n Object.entries(deps).forEach(([hash, jitFnData]: [string, JitCompiledFnData]) => {\n const key = getJitCompiledFnKey(hash, options);\n try {\n getStorage().setItem(key, JSON.stringify(jitFnData));\n } catch (error) {\n console.warn(`Failed to store JIT function dependency ${hash}:`, error);\n }\n });\n\n // Store namespaced pure functions\n Object.entries(pureFnDeps).forEach(([namespace, nsPureFns]) => {\n Object.entries(nsPureFns).forEach(([fnHash, pureFnData]: [string, PureFunctionData]) => {\n const key = getJitPureFnKey(namespace, fnHash, options);\n try {\n getStorage().setItem(key, JSON.stringify(pureFnData));\n } catch (error) {\n console.warn(`Failed to store pure function dependency ${namespace}::${fnHash}:`, error);\n }\n });\n });\n}\n\n/** Stores method metadata in localStorage using the new storage format */\nexport function storeMethodsMetadata(methods: MethodsCache, options: ClientOptions) {\n Object.entries(methods).forEach(([methodId, methodData]) => {\n const key = getSerializedMethodDataKey(methodId, options);\n try {\n getStorage().setItem(key, JSON.stringify(methodData));\n } catch (error) {\n console.warn(`Failed to store method metadata ${methodId}:`, error);\n }\n });\n}\n\n/** Restores all JIT compiled functions and pure functions from localStorage and deserializes them */\nexport function restoreAllDependencies(options: ClientOptions) {\n const deps: Record<string, JitCompiledFnData> = {};\n const pureFnDeps: PureFnsDataCache = {};\n const baseURLSuffix = `:${options.baseURL}`;\n\n for (let i = 0; i < getStorage().length; i++) {\n const key = getStorage().key(i);\n if (key?.startsWith(JIT_FN_PREFIX) && key.endsWith(baseURLSuffix)) {\n try {\n const data = getStorage().getItem(key);\n if (data) {\n const parsedData = JSON.parse(data);\n deps[parsedData.jitFnHash] = parsedData;\n }\n } catch (error) {\n console.warn(`Failed to restore JIT function from key ${key}:`, error);\n }\n }\n }\n\n for (let i = 0; i < getStorage().length; i++) {\n const key = getStorage().key(i);\n if (key?.startsWith(PURE_FN_PREFIX) && key.endsWith(baseURLSuffix)) {\n try {\n const data = getStorage().getItem(key);\n if (data) {\n const parsedData = JSON.parse(data);\n // Extract namespace from key: \"mion:pure-fn:namespace:fnHash:baseURL\"\n const inner = key.slice(PURE_FN_PREFIX.length, key.length - baseURLSuffix.length);\n const namespace = inner.split(':')[0] || parsedData.namespace;\n if (!pureFnDeps[namespace]) pureFnDeps[namespace] = {};\n pureFnDeps[namespace][parsedData.fnName] = parsedData;\n }\n } catch (error) {\n console.warn(`Failed to restore pure function from key ${key}:`, error);\n }\n }\n }\n\n if (Object.keys(deps).length > 0 || Object.keys(pureFnDeps).length > 0) {\n addSerializedJitCaches(deps, pureFnDeps);\n }\n}\n\n/** Creates a SubRequest for the metadata middleware to piggyback on an optimistic request */\nexport function createMetadataSubRequest(methodIds: string[]): SubRequest<any> {\n return {\n pointer: [MION_ROUTES.methodsMetadata],\n id: MION_ROUTES.methodsMetadata,\n isResolved: false,\n params: [methodIds],\n };\n}\n\n/** Restores method metadata from localStorage using the new storage format */\nexport function restoreFromLocalStorage(methodIds: string[], options: ClientOptions) {\n restoreAllDependencies(options);\n\n const methods: MethodsCache = {};\n let anyMethodsRestored = false;\n\n methodIds.forEach((id) => {\n if (routesCache.hasMetadata(id)) return;\n const methodKey = getSerializedMethodDataKey(id, options);\n const methodMetaJson = getStorage().getItem(methodKey);\n if (methodMetaJson) {\n try {\n const methodMeta: MethodWithOptions = JSON.parse(methodMetaJson);\n methods[id] = methodMeta;\n anyMethodsRestored = true;\n } catch (error) {\n console.warn(`Failed to restore method metadata for ${id}:`, error);\n getStorage().removeItem(methodKey);\n }\n }\n });\n\n if (anyMethodsRestored) {\n const serializableMethodsData: SerializableMethodsData = {\n methods,\n deps: {},\n purFnDeps: {},\n };\n addToCaches(serializableMethodsData);\n }\n}\n\nfunction addToCaches(serializableMethodsData: SerializableMethodsData) {\n addSerializedJitCaches(serializableMethodsData.deps, serializableMethodsData.purFnDeps);\n addRoutesToCache(serializableMethodsData.methods);\n}\n"],"names":["STORAGE_KEY","isRpcError","getStorage","addSerializedJitCaches","MION_ROUTES","routesCache","addRoutesToCache"],"mappings":"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"}
1
+ {"version":3,"file":"clientMethodsMetadata.cjs","names":[],"sources":["../../../../src/lib/clientMethodsMetadata.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 {addRoutesToCache, isUnsafePropertyName, hasJitFnsForMethod, RpcError} from '@mionjs/core';\nimport {ClientOptions} from '../types.ts';\nimport type {\n CompiledFnData,\n MethodsCache,\n MethodWithOptions,\n PureFunctionData,\n SerializablePureFunction,\n SerializableMethodsData,\n PureFnsDataCache,\n} from '@mionjs/core';\nimport {addSerializedJitCaches, routesCache} from '@mionjs/core';\nimport {METADATA_CACHE_EVICTION_ROUNDS, METADATA_CACHE_MAX_BYTES} from '../constants.ts';\nimport {getMetadataStore} from './metadataStore.ts';\nimport type {MetadataKind, MetadataRecord, MetadataRecordKey, MetadataStore, StorageEngine} from './storage.ts';\nimport {findOrphans, type CacheGraph} from './metadataEviction.ts';\nimport {requestPersistenceWhenSilent} from './persistentStorage.ts';\nimport {isBundledMethod, setFetchedMethods} from './methods.ts';\n\n/** What the cache knows about one stored record, without holding its text. Enough to pick the\n * oldest rows when room is needed, and to skip re-writing an entry that is already down. */\ninterface StoredEntry {\n kind: MetadataKind;\n id: string;\n ts: number;\n bytes: number;\n}\n\n/** Everything the cache tracks for one server. One instance per baseURL, for the page's lifetime. */\ninterface CacheState {\n baseURL: string;\n /** the engine this server's cache lives on, so every read and write goes to the same store */\n storageEngine: StorageEngine | undefined;\n hydration?: Promise<void>;\n /** method ids this page restored from the store rather than from the server */\n hydratedIds: Set<string>;\n /** what is on disk, keyed `${kind} ${id}` */\n stored: Map<string, StoredEntry>;\n bytes: number;\n graph: CacheGraph;\n sweepScheduled: boolean;\n}\n\nconst states = new Map<string, CacheState>();\n/** Payloads waiting to be written; the response path only pushes here and returns */\nlet writeQueue: {data: SerializableMethodsData; options: ClientOptions}[] = [];\nlet flushHandle: ReturnType<typeof setTimeout> | number | undefined;\nlet flushChain: Promise<void> = Promise.resolve();\nlet persistenceAsked = false;\nlet pendingCacheError: RpcError<string> | undefined;\n\nfunction getState(options: ClientOptions): CacheState {\n const baseURL = options.baseURL;\n let state = states.get(baseURL);\n if (!state) {\n state = {\n baseURL,\n storageEngine: options.storageEngine,\n hydratedIds: new Set(),\n stored: new Map(),\n bytes: 0,\n // Null-prototype maps: every key comes off the store, which any script on the page can write,\n // so a plain object would let a `__proto__` key reach Object.prototype.\n graph: {methods: Object.create(null), deps: Object.create(null), pureFns: Object.create(null)},\n sweepScheduled: false,\n };\n states.set(baseURL, state);\n }\n return state;\n}\n\nfunction storedKey(kind: MetadataKind, id: string): string {\n return `${kind} ${id}`;\n}\n\n/** Fills the in-memory caches now and leaves the store for later: the caller is a sync deserializer on the\n * response path, where every throw becomes a parse error. */\nfunction processMethodsMetadata(serializableMethodsData: SerializableMethodsData, options: ClientOptions): void {\n addToCaches(serializableMethodsData);\n queuePersist(serializableMethodsData, options);\n}\n\n/** A name that reaches an object key on restore is checked even though the server is trusted: `__proto__` as\n * a namespace would land the next write on Object.prototype, page-wide. A refused entry is only warned about. */\nfunction isStorableName(name: string): boolean {\n return !isUnsafePropertyName(name) && !name.includes(':');\n}\n\n// ############# WRITE PATH #############\n\nfunction queuePersist(data: SerializableMethodsData, options: ClientOptions): void {\n writeQueue.push({data, options});\n scheduleFlush();\n}\n\nfunction scheduleFlush(): void {\n if (flushHandle !== undefined) return;\n const run = () => {\n flushHandle = undefined;\n flushChain = flushChain.then(flushQueue);\n };\n // idle time is exactly right for this: nothing waits on the write, and a big metadata payload\n // costs a real JSON.stringify per entry\n const idle = (globalThis as any).requestIdleCallback;\n flushHandle = typeof idle === 'function' ? idle(run, {timeout: 200}) : setTimeout(run, 0);\n}\n\n/** Resolves once every queued write has reached the store. The write path is deferred on purpose,\n * so a test that wants to read back what a response cached must await this first. */\nexport function flushMetadataCache(): Promise<void> {\n if (flushHandle !== undefined) {\n const cancelIdle = (globalThis as any).cancelIdleCallback;\n if (typeof cancelIdle === 'function') cancelIdle(flushHandle);\n else clearTimeout(flushHandle as ReturnType<typeof setTimeout>);\n flushHandle = undefined;\n }\n flushChain = flushChain.then(flushQueue);\n return flushChain;\n}\n\nasync function flushQueue(): Promise<void> {\n if (!writeQueue.length) return;\n const batch = writeQueue;\n writeQueue = [];\n const byBaseURL = new Map<string, {options: ClientOptions; payloads: SerializableMethodsData[]}>();\n for (const item of batch) {\n const group = byBaseURL.get(item.options.baseURL);\n if (group) group.payloads.push(item.data);\n else byBaseURL.set(item.options.baseURL, {options: item.options, payloads: [item.data]});\n }\n for (const group of byBaseURL.values()) await persistPayloads(group.options, group.payloads);\n}\n\n/** Turns the payloads into records, dropping anything already down, then writes them as one unit. */\nasync function persistPayloads(options: ClientOptions, payloads: SerializableMethodsData[]): Promise<void> {\n const baseURL = options.baseURL;\n const state = getState(options);\n const ts = Date.now();\n const records = new Map<string, MetadataRecord>();\n const add = (kind: MetadataKind, id: string, value: unknown) => {\n const key = storedKey(kind, id);\n // hashes are content addresses, so a compiled function already down is byte for byte this one.\n // A method row is keyed by its id instead, so it is always rewritten.\n if (kind !== 'm' && state.stored.has(key)) return;\n try {\n records.set(key, {baseURL, kind, id, json: JSON.stringify(value), ts});\n } catch (error) {\n console.warn(`Failed to serialize metadata cache entry ${id}:`, error);\n }\n };\n\n for (const payload of payloads) {\n for (const [hash, jitFnData] of Object.entries<CompiledFnData>(payload.deps ?? {})) {\n if (!isStorableName(hash)) {\n console.warn(`Refused to store JIT function dependency under '${hash}'`);\n continue;\n }\n add('j', hash, jitFnData);\n }\n for (const [id, pureFnData] of Object.entries<PureFunctionData>(payload.purFnDeps ?? {})) {\n if (!isStorableName(id)) {\n console.warn(`Refused to store pure function '${id}'`);\n continue;\n }\n add('p', id, pureFnData);\n }\n for (const [methodId, methodData] of Object.entries<MethodWithOptions>(payload.methods ?? {})) {\n if (!isStorableName(methodId)) {\n console.warn(`Refused to store metadata for method '${methodId}'`);\n continue;\n }\n // The server answers for a route's whole chain, so a bundled middleware rides a fetched route's\n // answer; its row would only be read back to be ignored. Orphaned compiled functions are swept.\n if (isBundledMethod(methodId)) continue;\n add('m', methodId, methodData);\n }\n }\n\n if (!records.size) return;\n await writeRecords(state, [...records.values()]);\n}\n\nfunction recordBytes(record: MetadataRecord): number {\n return record.json.length + record.id.length;\n}\n\n/** Writes the records, making room as many times as it takes: the new data always wins. The size cap trims\n * first, and a browser that refuses anyway gets more old rows dropped and the write retried. Only an empty\n * store that still cannot take the write is reported. */\nasync function writeRecords(state: CacheState, records: MetadataRecord[]): Promise<void> {\n const store = await getMetadataStore(state.storageEngine);\n const incoming = records.reduce((total, record) => total + recordBytes(record), 0);\n await evictOldest(state, store, state.bytes + incoming - METADATA_CACHE_MAX_BYTES);\n\n for (let round = 0; ; round++) {\n try {\n await store.write(records);\n for (const record of records) {\n const key = storedKey(record.kind, record.id);\n const previous = state.stored.get(key);\n if (previous) state.bytes -= previous.bytes;\n const bytes = recordBytes(record);\n state.stored.set(key, {kind: record.kind, id: record.id, ts: record.ts, bytes});\n state.bytes += bytes;\n }\n askForPersistenceOnce();\n return;\n } catch (error) {\n if (round >= METADATA_CACHE_EVICTION_ROUNDS) return reportCacheError(error);\n // nothing freed means nothing is left to give up, so the store cannot take this write: tell the app\n const freed = await evictOldest(state, store, Math.max(state.bytes / 4, incoming));\n if (!freed) return reportCacheError(error);\n }\n }\n}\n\n/** Drops the oldest rows until at least `targetBytes` have been freed. Returns the bytes freed.\n * Safe at any granularity: a method whose compiled functions went with it is refused on the next\n * hydration and simply refetched. */\nasync function evictOldest(state: CacheState, store: MetadataStore, targetBytes: number): Promise<number> {\n if (targetBytes <= 0 || !state.stored.size) return 0;\n const oldestFirst = [...state.stored.values()].sort((a, b) => a.ts - b.ts);\n const keys: MetadataRecordKey[] = [];\n let freed = 0;\n for (const entry of oldestFirst) {\n keys.push([entry.kind, entry.id]);\n freed += entry.bytes;\n if (freed >= targetBytes) break;\n }\n try {\n await store.remove(state.baseURL, keys);\n } catch {\n // a store that cannot delete cannot be trimmed; the caller reports the write failure instead\n return 0;\n }\n for (const [kind, id] of keys) {\n const key = storedKey(kind, id);\n state.bytes -= state.stored.get(key)?.bytes ?? 0;\n state.stored.delete(key);\n if (kind === 'j') delete state.graph.deps[id];\n else if (kind === 'p') delete state.graph.pureFns[id];\n else delete state.graph.methods[id];\n }\n return freed;\n}\n\nfunction reportCacheError(error: unknown): void {\n const rpcError = new RpcError({\n type: 'metadata-cache-error',\n publicMessage: 'Could not store the remote method metadata cache',\n originalError: error instanceof Error ? error : undefined,\n });\n // loud now for whoever is watching the console, and again on the next call for the app itself\n console.error('[mion] metadata cache write failed:', error);\n pendingCacheError = rpcError;\n}\n\n/** Takes the last unrecoverable cache error, if any, so a call can report it once. */\nexport function takeMetadataCacheError(): RpcError<string> | undefined {\n const error = pendingCacheError;\n pendingCacheError = undefined;\n return error;\n}\n\nfunction askForPersistenceOnce(): void {\n if (persistenceAsked) return;\n persistenceAsked = true;\n // never awaited, and never in a browser where it could prompt (see persistentStorage.ts)\n void requestPersistenceWhenSilent();\n}\n\n// ############# READ PATH #############\n\n/** Restores everything this server cached, once per page. One indexed read, never a scan.\n * Never rejects: a missing or blocked store is a cache miss, not an error. */\nexport function hydrateMetadataCache(options: ClientOptions): Promise<void> {\n const state = getState(options);\n if (!state.hydration) {\n state.hydration = hydrate(state).catch((error) => {\n console.warn('Failed to restore the remote method metadata cache:', error);\n });\n }\n return state.hydration;\n}\n\nasync function hydrate(state: CacheState): Promise<void> {\n const store = await getMetadataStore(state.storageEngine);\n const records = await store.readAll(state.baseURL);\n if (!records.length) return;\n\n const deps: Record<string, CompiledFnData> = Object.create(null);\n const pureFnDeps: PureFnsDataCache = Object.create(null);\n const methods: MethodsCache = Object.create(null);\n\n for (const record of records) {\n // the entry is keyed by the id in ITS OWN record, never by what the payload claims\n if (!isStorableName(record.id)) continue;\n let parsed: any;\n try {\n parsed = JSON.parse(record.json);\n } catch (error) {\n console.warn(`Failed to restore metadata cache entry ${record.id}:`, error);\n continue;\n }\n const key = storedKey(record.kind, record.id);\n state.stored.set(key, {kind: record.kind, id: record.id, ts: record.ts, bytes: recordBytes(record)});\n state.bytes += recordBytes(record);\n if (record.kind === 'j') {\n deps[record.id] = parsed;\n state.graph.deps[record.id] = parsed;\n } else if (record.kind === 'p') {\n // the factory is rebuilt from `code`, so an entry without one restores to nothing callable\n if (typeof parsed?.code !== 'string') {\n console.warn(`Ignoring cached pure function ${record.id}: it carries no code`);\n continue;\n }\n pureFnDeps[record.id] = parsed as SerializablePureFunction;\n state.graph.pureFns[record.id] = parsed;\n } else {\n methods[record.id] = parsed as MethodWithOptions;\n state.graph.methods[record.id] = parsed;\n }\n }\n\n addSerializedJitCaches(deps, pureFnDeps);\n\n // A method whose compiled functions are gone (eviction, an aborted write, a newer server build) would\n // throw at call time, not here: refuse it and let the server be asked again.\n const restorable: MethodsCache = {};\n const unusable: MetadataRecordKey[] = [];\n for (const [id, metadata] of Object.entries(methods)) {\n if (hasJitFnsForMethod(metadata)) {\n restorable[id] = metadata;\n state.hydratedIds.add(id);\n } else {\n unusable.push(['m', id]);\n delete state.graph.methods[id];\n }\n }\n addRoutesToCache(restorable);\n scheduleSweep(state, unusable);\n}\n\n/** True when this page took the method's metadata off the store rather than from the server. */\nexport function wasHydratedFromCache(id: string, options: ClientOptions): boolean {\n return states.get(options.baseURL)?.hydratedIds.has(id) === true;\n}\n\n/** Drops restored rows the server no longer matches from memory and the store, so the next call relearns them. */\nexport async function purgeHydratedMetadata(ids: string[], options: ClientOptions): Promise<void> {\n const state = states.get(options.baseURL);\n if (!state) return;\n const hydrated = ids.filter((id) => state.hydratedIds.has(id));\n for (const id of hydrated) routesCache.removeMetadata(id);\n await dropStoredMethods(state, hydrated);\n}\n\n/** Forgets fetched rows from memory, the store and any queued write, so the next call relearns them.\n * A bundled row stays: the calling code was built against it. */\nexport async function forgetFetchedMetadata(ids: string[], options: ClientOptions): Promise<void> {\n const fetchedIds = ids.filter((id) => !isBundledMethod(id));\n for (const id of fetchedIds) routesCache.removeMetadata(id);\n // a queued write would put the forgotten row back after the delete below\n for (const queued of writeQueue) {\n if (queued.options.baseURL !== options.baseURL) continue;\n for (const id of fetchedIds) delete queued.data.methods[id];\n }\n const state = states.get(options.baseURL);\n if (state) await dropStoredMethods(state, fetchedIds);\n}\n\nasync function dropStoredMethods(state: CacheState, ids: string[]): Promise<void> {\n const keys: MetadataRecordKey[] = [];\n for (const id of ids) {\n state.hydratedIds.delete(id);\n delete state.graph.methods[id];\n keys.push(['m', id]);\n }\n if (!keys.length) return;\n const store = await getMetadataStore(state.storageEngine);\n await store.remove(state.baseURL, keys).catch(() => undefined);\n for (const [kind, id] of keys) {\n const key = storedKey(kind, id);\n state.bytes -= state.stored.get(key)?.bytes ?? 0;\n state.stored.delete(key);\n }\n // the compiled functions those methods pointed at have nothing left pointing at them\n await sweepOrphans(state);\n}\n\n/** Deletes rows nothing can reach any more. Costs no extra reads: it walks the records hydration\n * already parsed. Once per server per page, on idle. */\nfunction scheduleSweep(state: CacheState, alsoDelete: MetadataRecordKey[]): void {\n if (state.sweepScheduled) return;\n state.sweepScheduled = true;\n const run = () => void sweepOrphans(state, alsoDelete);\n const idle = (globalThis as any).requestIdleCallback;\n if (typeof idle === 'function') idle(run, {timeout: 2000});\n else setTimeout(run, 0);\n}\n\nasync function sweepOrphans(state: CacheState, alsoDelete: MetadataRecordKey[] = []): Promise<void> {\n const keys = [...alsoDelete, ...findOrphans(state.graph)];\n if (!keys.length) return;\n const store = await getMetadataStore(state.storageEngine);\n await store.remove(state.baseURL, keys).catch(() => undefined);\n for (const [kind, id] of keys) {\n const key = storedKey(kind, id);\n state.bytes -= state.stored.get(key)?.bytes ?? 0;\n state.stored.delete(key);\n if (kind === 'j') delete state.graph.deps[id];\n else if (kind === 'p') delete state.graph.pureFns[id];\n else delete state.graph.methods[id];\n }\n}\n\n/** Forgets everything this page learned about the store. Only for testing — simulates a new page. */\nexport function resetMetadataCacheState(): void {\n states.clear();\n writeQueue = [];\n persistenceAsked = false;\n pendingCacheError = undefined;\n}\n\n/** Saves rows answered outside the metadata route: a stored row that later disagrees with its server is relearned.\n * `replaceIds` go first: the fetched shelf never overwrites a row. */\nexport function installMethodRows(\n serializableMethodsData: SerializableMethodsData,\n options: ClientOptions,\n replaceIds: string[] = []\n): void {\n for (const id of replaceIds) routesCache.removeMetadata(id);\n processMethodsMetadata(serializableMethodsData, options);\n}\n\nfunction addToCaches(serializableMethodsData: SerializableMethodsData) {\n addSerializedJitCaches(serializableMethodsData.deps, serializableMethodsData.purFnDeps);\n addRoutesToCache(serializableMethodsData.methods);\n}\n\n// Registered here rather than in metadataFromServer.ts: its pieces are public API and a consumer\n// can import one directly, so this module evaluating IS the moment the fetched lane exists.\nsetFetchedMethods(routesCache);\n"],"mappings":"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"}
@@ -1,11 +1,11 @@
1
- import { MION_ROUTES, JitCompiledFnData, MethodsCache, PureFnsDataCache } from '@mionjs/core';
2
- import { ClientOptions, SubRequest } from '../types.ts';
3
- type MetadataRouteKey = typeof MION_ROUTES.methodsMetadata | typeof MION_ROUTES.methodsMetadataById;
4
- export declare function extractAndProcessMetadata(routeKey: MetadataRouteKey, parsedBody: any, options: ClientOptions): void;
5
- export declare function storeDependencies(deps: Record<string, JitCompiledFnData>, pureFnDeps: PureFnsDataCache, options: ClientOptions): void;
6
- export declare function storeMethodsMetadata(methods: MethodsCache, options: ClientOptions): void;
7
- export declare function restoreAllDependencies(options: ClientOptions): void;
8
- export declare function createMetadataSubRequest(methodIds: string[]): SubRequest<any>;
9
- export declare function restoreFromLocalStorage(methodIds: string[], options: ClientOptions): void;
10
- export {};
1
+ import { RpcError, SerializableMethodsData } from '@mionjs/core';
2
+ import { ClientOptions } from '../types.ts';
3
+ export declare function flushMetadataCache(): Promise<void>;
4
+ export declare function takeMetadataCacheError(): RpcError<string> | undefined;
5
+ export declare function hydrateMetadataCache(options: ClientOptions): Promise<void>;
6
+ export declare function wasHydratedFromCache(id: string, options: ClientOptions): boolean;
7
+ export declare function purgeHydratedMetadata(ids: string[], options: ClientOptions): Promise<void>;
8
+ export declare function forgetFetchedMetadata(ids: string[], options: ClientOptions): Promise<void>;
9
+ export declare function resetMetadataCacheState(): void;
10
+ export declare function installMethodRows(serializableMethodsData: SerializableMethodsData, options: ClientOptions, replaceIds?: string[]): void;
11
11
  //# sourceMappingURL=clientMethodsMetadata.d.ts.map
@@ -0,0 +1,3 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let _mionjs_core=require("@mionjs/core");function addThrownError(response,error){const thrownErrors=response[_mionjs_core.MION_ROUTES.thrownErrors];Array.isArray(thrownErrors)?thrownErrors.push(error):response[_mionjs_core.MION_ROUTES.thrownErrors]=[error]}function hasResponseValue(response,id){const{parent,key}=findParent(response,id);return!!parent&&Object.hasOwn(parent,key)}function getResponseValue(response,id){const{parent,key}=findParent(response,id);return parent&&Object.hasOwn(parent,key)?parent[key]:void 0}function setResponseValue(response,id,value){const{parent,key}=findParent(response,id,!0);return parent&&(parent[key]=value),!!parent}function deleteResponseValue(response,id){const pointer=id.split(_mionjs_core.ROUTER_ITEM_SEPARATOR_CHAR);for(let depth=pointer.length;depth>0;depth--){const{parent,key}=findParent(response,pointer.slice(0,depth).join(_mionjs_core.ROUTER_ITEM_SEPARATOR_CHAR));if(!parent||!Object.hasOwn(parent,key))return;const child=parent[key];if(depth<pointer.length&&!(isNode(child)&&!Object.keys(child).length))return;delete parent[key]}}function findParent(response,id,create=!1){const pointer=id.split(_mionjs_core.ROUTER_ITEM_SEPARATOR_CHAR),key=pointer[pointer.length-1];if(pointer.includes("__proto__")||pointer[0]===_mionjs_core.MION_ROUTES.thrownErrors)return{key};let node=response;for(let i=0;i<pointer.length-1;i++){let next=Object.hasOwn(node,pointer[i])?node[pointer[i]]:void 0;if(next===void 0&&create&&(next=node[pointer[i]]={}),!isNode(next))return{key};node=next}return{parent:node,key}}function isNode(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}exports.addThrownError=addThrownError;exports.deleteResponseValue=deleteResponseValue;exports.getResponseValue=getResponseValue;exports.hasResponseValue=hasResponseValue;exports.setResponseValue=setResponseValue;
2
+
3
+ //# sourceMappingURL=clientResponse.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clientResponse.cjs","names":[],"sources":["../../../../src/lib/clientResponse.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 {MION_ROUTES, ROUTER_ITEM_SEPARATOR_CHAR} from '@mionjs/core';\nimport type {RpcError} from '@mionjs/core';\nimport type {RemoteApi} from '@mionjs/router';\nimport type {ClientResponse} from '../types.ts';\n\ntype ResponseNode = Record<string, unknown>;\n\nexport function addThrownError(response: ClientResponse<RemoteApi>, error: RpcError<string>): void {\n const thrownErrors = response[MION_ROUTES.thrownErrors];\n if (Array.isArray(thrownErrors)) thrownErrors.push(error);\n else response[MION_ROUTES.thrownErrors] = [error];\n}\n\nexport function hasResponseValue(response: ClientResponse<RemoteApi>, id: string): boolean {\n const {parent, key} = findParent(response, id);\n return !!parent && Object.hasOwn(parent, key);\n}\n\nexport function getResponseValue(response: ClientResponse<RemoteApi>, id: string): unknown {\n const {parent, key} = findParent(response, id);\n return parent && Object.hasOwn(parent, key) ? parent[key] : undefined;\n}\n\n/** False when the id has no safe path, so the caller keeps the value somewhere else */\nexport function setResponseValue(response: ClientResponse<RemoteApi>, id: string, value: unknown): boolean {\n const {parent, key} = findParent(response, id, true);\n if (parent) parent[key] = value;\n return !!parent;\n}\n\n/** Also drops every group it leaves empty: the response never holds what the body did not */\nexport function deleteResponseValue(response: ClientResponse<RemoteApi>, id: string): void {\n const pointer = id.split(ROUTER_ITEM_SEPARATOR_CHAR);\n for (let depth = pointer.length; depth > 0; depth--) {\n const {parent, key} = findParent(response, pointer.slice(0, depth).join(ROUTER_ITEM_SEPARATOR_CHAR));\n if (!parent || !Object.hasOwn(parent, key)) return;\n const child = parent[key];\n if (depth < pointer.length && !(isNode(child) && !Object.keys(child).length)) return;\n delete parent[key];\n }\n}\n\nfunction findParent(response: ClientResponse<RemoteApi>, id: string, create = false): {parent?: ResponseNode; key: string} {\n const pointer = id.split(ROUTER_ITEM_SEPARATOR_CHAR);\n const key = pointer[pointer.length - 1];\n // a response key is untrusted: `__proto__` would write the prototype, and the top-level thrown list is not a group\n if (pointer.includes('__proto__') || pointer[0] === MION_ROUTES.thrownErrors) return {key};\n let node: ResponseNode = response;\n for (let i = 0; i < pointer.length - 1; i++) {\n let next = Object.hasOwn(node, pointer[i]) ? node[pointer[i]] : undefined;\n if (next === undefined && create) next = node[pointer[i]] = {};\n if (!isNode(next)) return {key};\n node = next;\n }\n return {parent: node, key};\n}\n\nfunction isNode(value: unknown): value is ResponseNode {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n"],"mappings":"4GAcA,SAAgB,eAAe,SAAqC,MAA+B,CACjG,MAAM,aAAe,SAAS,aAAA,YAAY,YAAA,EACtC,MAAM,QAAQ,YAAY,EAAG,aAAa,KAAK,KAAK,EACnD,SAAS,aAAA,YAAY,YAAA,EAAgB,CAAC,KAAK,CAClD,CAEA,SAAgB,iBAAiB,SAAqC,GAAqB,CACzF,KAAM,CAAC,OAAQ,GAAA,EAAO,WAAW,SAAU,EAAE,EAC7C,MAAO,CAAC,CAAC,QAAU,OAAO,OAAO,OAAQ,GAAG,CAC9C,CAEA,SAAgB,iBAAiB,SAAqC,GAAqB,CACzF,KAAM,CAAC,OAAQ,GAAA,EAAO,WAAW,SAAU,EAAE,EAC7C,OAAO,QAAU,OAAO,OAAO,OAAQ,GAAG,EAAI,OAAO,GAAA,EAAO,MAC9D,CAGA,SAAgB,iBAAiB,SAAqC,GAAY,MAAyB,CACzG,KAAM,CAAC,OAAQ,GAAA,EAAO,WAAW,SAAU,GAAI,EAAI,EACnD,OAAI,SAAQ,OAAO,GAAA,EAAO,OACnB,CAAC,CAAC,MACX,CAGA,SAAgB,oBAAoB,SAAqC,GAAkB,CACzF,MAAM,QAAU,GAAG,MAAM,aAAA,0BAA0B,EACnD,QAAS,MAAQ,QAAQ,OAAQ,MAAQ,EAAG,QAAS,CACnD,KAAM,CAAC,OAAQ,GAAA,EAAO,WAAW,SAAU,QAAQ,MAAM,EAAG,KAAK,EAAE,KAAK,aAAA,0BAA0B,CAAC,EACnG,GAAI,CAAC,QAAU,CAAC,OAAO,OAAO,OAAQ,GAAG,EAAG,OAC5C,MAAM,MAAQ,OAAO,GAAA,EACrB,GAAI,MAAQ,QAAQ,QAAU,EAAE,OAAO,KAAK,GAAK,CAAC,OAAO,KAAK,KAAK,EAAE,QAAS,OAC9E,OAAO,OAAO,GAAA,CAChB,CACF,CAEA,SAAS,WAAW,SAAqC,GAAY,OAAS,GAA6C,CACzH,MAAM,QAAU,GAAG,MAAM,aAAA,0BAA0B,EAC7C,IAAM,QAAQ,QAAQ,OAAS,CAAA,EAErC,GAAI,QAAQ,SAAS,WAAW,GAAK,QAAQ,CAAA,IAAO,aAAA,YAAY,aAAc,MAAO,CAAC,GAAG,EACzF,IAAI,KAAqB,SACzB,QAAS,EAAI,EAAG,EAAI,QAAQ,OAAS,EAAG,IAAK,CAC3C,IAAI,KAAO,OAAO,OAAO,KAAM,QAAQ,CAAA,CAAE,EAAI,KAAK,QAAQ,CAAA,CAAA,EAAM,OAEhE,GADI,OAAS,QAAa,SAAQ,KAAO,KAAK,QAAQ,CAAA,CAAA,EAAM,CAAC,GACzD,CAAC,OAAO,IAAI,EAAG,MAAO,CAAC,GAAG,EAC9B,KAAO,IACT,CACA,MAAO,CAAC,OAAQ,KAAM,GAAG,CAC3B,CAEA,SAAS,OAAO,MAAuC,CACrD,OAAO,OAAO,OAAU,UAAY,QAAU,MAAQ,CAAC,MAAM,QAAQ,KAAK,CAC5E"}
@@ -0,0 +1,9 @@
1
+ import { RpcError } from '@mionjs/core';
2
+ import { RemoteApi } from '@mionjs/router';
3
+ import { ClientResponse } from '../types.ts';
4
+ export declare function addThrownError(response: ClientResponse<RemoteApi>, error: RpcError<string>): void;
5
+ export declare function hasResponseValue(response: ClientResponse<RemoteApi>, id: string): boolean;
6
+ export declare function getResponseValue(response: ClientResponse<RemoteApi>, id: string): unknown;
7
+ export declare function setResponseValue(response: ClientResponse<RemoteApi>, id: string, value: unknown): boolean;
8
+ export declare function deleteResponseValue(response: ClientResponse<RemoteApi>, id: string): void;
9
+ //# sourceMappingURL=clientResponse.d.ts.map
@@ -1,2 +1,3 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const core=require("@mionjs/core"),src_lib_clientMethodsMetadata=require("./clientMethodsMetadata.cjs"),src_lib_serializer=require("./serializer.cjs");async function fetchRemoteMethodsMetadata(methodIds,options,signal){src_lib_clientMethodsMetadata.restoreFromLocalStorage(methodIds,options);const missingAfterLocal=methodIds.filter(path=>!core.routesCache.hasMetadata(path));if(!missingAfterLocal.length)return;const body={[core.MION_ROUTES.methodsMetadataById]:[missingAfterLocal]};try{const path=core.getRoutePath([core.MION_ROUTES.methodsMetadataById],options),url=new URL(path,options.baseURL),response=await fetch(url,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(body),signal}),platformError=(await src_lib_serializer.deserializeResponseBody(response,options))[core.MION_ROUTES.platformError];if(core.isRpcError(platformError))throw platformError;const stillMissing=missingAfterLocal.filter(id=>!core.routesCache.hasMetadata(id));if(stillMissing.length)throw new Error(`Failed to fetch metadata for: ${stillMissing.join(", ")}`)}catch(error){throw signal?.aborted?error:new Error(`Error fetching validation and serialization metadata: ${error?.message}`)}}exports.fetchRemoteMethodsMetadata=fetchRemoteMethodsMetadata;
2
- //# sourceMappingURL=fetchRemoteMethodsMetadata.cjs.map
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const require_src_lib_methods=require("./methods.cjs"),require_src_lib_clientMethodsMetadata=require("./clientMethodsMetadata.cjs");let _mionjs_core=require("@mionjs/core");var FETCH_METADATA_ID="mionFetchMetadata";async function fetchRemoteMethodsMetadata(methodIds,routePointer,options,signal,middlewareId=FETCH_METADATA_ID){await require_src_lib_clientMethodsMetadata.hydrateMetadataCache(options);const missingAfterLocal=methodIds.filter(path=>!require_src_lib_methods.hasMethod(path));if(!missingAfterLocal.length)return;const body={[middlewareId]:[missingAfterLocal,"only"],[(0,_mionjs_core.getRouterItemId)(routePointer)]:"metadata-only"};try{const url=new URL((0,_mionjs_core.getRoutePath)(routePointer,options),options.baseURL),parsedBody=await(await fetch(url,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(body),signal})).json(),platformError=parsedBody?.[_mionjs_core.MION_ROUTES.thrownErrors]?.[_mionjs_core.MION_ROUTES.platformError];if((0,_mionjs_core.isRpcError)(platformError))throw new _mionjs_core.RpcError(platformError);const slot=parsedBody?.[middlewareId],answer=Array.isArray(slot)?slot[1]:slot;if(!(0,_mionjs_core.isRpcError)(answer)||answer.type!=="metadata-only"||!answer.errorData?.metadata)throw new Error(`the server answered no metadata; place ${middlewareId} first in its routes`);require_src_lib_clientMethodsMetadata.installMethodRows(answer.errorData.metadata,options);const stillMissing=missingAfterLocal.filter(id=>!require_src_lib_methods.hasMethod(id));if(stillMissing.length)throw new Error(`Failed to fetch metadata for: ${stillMissing.join(", ")}`)}catch(error){throw signal?.aborted?error:new Error(`Error fetching validation and serialization metadata: ${error?.message}`)}}exports.fetchRemoteMethodsMetadata=fetchRemoteMethodsMetadata;
2
+
3
+ //# sourceMappingURL=fetchRemoteMethodsMetadata.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"fetchRemoteMethodsMetadata.cjs","sources":["../../../../src/lib/fetchRemoteMethodsMetadata.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 {isRpcError, MION_ROUTES, getRoutePath, routesCache} from '@mionjs/core';\nimport {ClientOptions, RequestBody} from '../types.ts';\nimport {restoreFromLocalStorage} from './clientMethodsMetadata.ts';\nimport {deserializeResponseBody} from './serializer.ts';\n\n/** Manually calls mionGetRemoteMethodsInfoById to get Remote Api Metadata */\nexport async function fetchRemoteMethodsMetadata(\n methodIds: string[],\n options: ClientOptions,\n signal?: AbortSignal\n): Promise<void> {\n restoreFromLocalStorage(methodIds, options);\n const missingAfterLocal = methodIds.filter((path) => !routesCache.hasMetadata(path));\n if (!missingAfterLocal.length) return;\n const body: RequestBody = {\n [MION_ROUTES.methodsMetadataById]: [missingAfterLocal],\n };\n try {\n const path = getRoutePath([MION_ROUTES.methodsMetadataById], options);\n const url = new URL(path, options.baseURL);\n const response = await fetch(url, {\n method: 'POST',\n headers: {'Content-Type': 'application/json'},\n body: JSON.stringify(body),\n signal,\n });\n const deserialized = await deserializeResponseBody(response, options);\n const platformError = deserialized[MION_ROUTES.platformError];\n if (isRpcError(platformError)) throw platformError;\n const stillMissing = missingAfterLocal.filter((id) => !routesCache.hasMetadata(id));\n if (stillMissing.length) throw new Error(`Failed to fetch metadata for: ${stillMissing.join(', ')}`);\n } catch (error: any) {\n // Preserve abort/timeout DOMException so the caller's onError can classify it correctly\n if (signal?.aborted) throw error;\n throw new Error(`Error fetching validation and serialization metadata: ${error?.message}`);\n }\n}\n"],"names":["restoreFromLocalStorage","routesCache","MION_ROUTES","getRoutePath","deserializeResponseBody","isRpcError"],"mappings":"uOAaA,eAAsB,2BAClB,UACA,QACA,OAAoB,CAEpBA,8BAAAA,wBAAwB,UAAW,OAAO,EAC1C,MAAM,kBAAoB,UAAU,OAAQ,MAAS,CAACC,KAAAA,YAAY,YAAY,IAAI,CAAC,EACnF,GAAI,CAAC,kBAAkB,OAAQ,OAC/B,MAAM,KAAoB,CACtB,CAACC,KAAAA,YAAY,mBAAmB,EAAG,CAAC,iBAAiB,CAAA,EAEzD,GAAI,CACA,MAAM,KAAOC,KAAAA,aAAa,CAACD,KAAAA,YAAY,mBAAmB,EAAG,OAAO,EAC9D,IAAM,IAAI,IAAI,KAAM,QAAQ,OAAO,EACnC,SAAW,MAAM,MAAM,IAAK,CAC9B,OAAQ,OACR,QAAS,CAAC,eAAgB,kBAAA,EAC1B,KAAM,KAAK,UAAU,IAAI,EACzB,MAAA,CACH,EAEK,eADe,MAAME,2CAAwB,SAAU,OAAO,GACjCF,KAAAA,YAAY,aAAa,EAC5D,GAAIG,KAAAA,WAAW,aAAa,EAAG,MAAM,cACrC,MAAM,aAAe,kBAAkB,OAAQ,IAAO,CAACJ,KAAAA,YAAY,YAAY,EAAE,CAAC,EAClF,GAAI,aAAa,OAAQ,MAAM,IAAI,MAAM,iCAAiC,aAAa,KAAK,IAAI,CAAC,EAAE,CACvG,OAAS,MAAY,CAEjB,MAAI,QAAQ,QAAe,MACrB,IAAI,MAAM,yDAAyD,OAAO,OAAO,EAAE,CAC7F,CACJ"}
1
+ {"version":3,"file":"fetchRemoteMethodsMetadata.cjs","names":[],"sources":["../../../../src/lib/fetchRemoteMethodsMetadata.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 {isRpcError, MION_ROUTES, getRoutePath, RpcError, getRouterItemId} from '@mionjs/core';\nimport type {FetchMetadataOnlyData} from '@mionjs/core/middlewares';\nimport {ClientOptions} from '../types.ts';\nimport {hydrateMetadataCache, installMethodRows} from './clientMethodsMetadata.ts';\nimport {hasMethod} from './methods.ts';\n\n/** The key `mionFetchMetadata` sits under when placed by its own name. */\nconst FETCH_METADATA_ID = 'mionFetchMetadata';\n\n/** Sent to a route's path: the metadata middleware answers and stops the call before the route runs. */\nexport async function fetchRemoteMethodsMetadata(\n methodIds: string[],\n routePointer: string[],\n options: ClientOptions,\n signal?: AbortSignal,\n middlewareId: string = FETCH_METADATA_ID\n): Promise<void> {\n await hydrateMetadataCache(options);\n const missingAfterLocal = methodIds.filter((path) => !hasMethod(path));\n if (!missingAfterLocal.length) return;\n const body: Record<string, unknown> = {\n [middlewareId]: [missingAfterLocal, 'only'],\n // not params: a server without the middleware refuses this slot instead of running the route\n [getRouterItemId(routePointer)]: 'metadata-only',\n };\n try {\n const url = new URL(getRoutePath(routePointer, options), options.baseURL);\n const response = await fetch(url, {\n method: 'POST',\n headers: {'Content-Type': 'application/json'},\n body: JSON.stringify(body),\n signal,\n });\n // the middleware pins the built-in parser on both wires, so its answer is plain JSON\n const parsedBody = await response.json();\n const platformError = parsedBody?.[MION_ROUTES.thrownErrors]?.[MION_ROUTES.platformError];\n if (isRpcError(platformError)) throw new RpcError(platformError);\n const slot = parsedBody?.[middlewareId];\n // a union answer rides the `[index, value]` envelope\n const answer = (Array.isArray(slot) ? slot[1] : slot) as RpcError<string, FetchMetadataOnlyData> | undefined;\n if (!isRpcError(answer) || answer.type !== 'metadata-only' || !answer.errorData?.metadata)\n throw new Error(`the server answered no metadata; place ${middlewareId} first in its routes`);\n installMethodRows(answer.errorData.metadata, options);\n const stillMissing = missingAfterLocal.filter((id) => !hasMethod(id));\n if (stillMissing.length) throw new Error(`Failed to fetch metadata for: ${stillMissing.join(', ')}`);\n } catch (error: any) {\n // Preserve the abort/timeout DOMException so the caller's onError can classify it\n if (signal?.aborted) throw error;\n throw new Error(`Error fetching validation and serialization metadata: ${error?.message}`);\n }\n}\n"],"mappings":"gPAcA,IAAM,kBAAoB,oBAG1B,eAAsB,2BACpB,UACA,aACA,QACA,OACA,aAAuB,kBACR,CACf,MAAM,sCAAA,qBAAqB,OAAO,EAClC,MAAM,kBAAoB,UAAU,OAAQ,MAAS,CAAC,wBAAA,UAAU,IAAI,CAAC,EACrE,GAAI,CAAC,kBAAkB,OAAQ,OAC/B,MAAM,KAAgC,EACnC,YAAA,EAAe,CAAC,kBAAmB,MAAM,oCAEzB,YAAY,CAAA,EAAI,eACnC,EACA,GAAI,CACF,MAAM,IAAM,IAAI,OAAA,aAAA,cAAiB,aAAc,OAAO,EAAG,QAAQ,OAAO,EAQlE,WAAa,MAAM,MAPF,MAAM,IAAK,CAChC,OAAQ,OACR,QAAS,CAAC,eAAgB,kBAAkB,EAC5C,KAAM,KAAK,UAAU,IAAI,EACzB,MACF,CAAC,GAEiC,KAAK,EACjC,cAAgB,aAAa,aAAA,YAAY,YAAA,IAAgB,aAAA,YAAY,aAAA,EAC3E,MAAA,aAAA,YAAe,aAAa,EAAG,MAAM,IAAI,aAAA,SAAS,aAAa,EAC/D,MAAM,KAAO,aAAa,YAAA,EAEpB,OAAU,MAAM,QAAQ,IAAI,EAAI,KAAK,CAAA,EAAK,KAChD,GAAI,IAAA,aAAA,YAAY,MAAM,GAAK,OAAO,OAAS,iBAAmB,CAAC,OAAO,WAAW,SAC/E,MAAM,IAAI,MAAM,0CAA0C,YAAA,sBAAkC,EAC9F,sCAAA,kBAAkB,OAAO,UAAU,SAAU,OAAO,EACpD,MAAM,aAAe,kBAAkB,OAAQ,IAAO,CAAC,wBAAA,UAAU,EAAE,CAAC,EACpE,GAAI,aAAa,OAAQ,MAAM,IAAI,MAAM,iCAAiC,aAAa,KAAK,IAAI,CAAA,EAAG,CACrG,OAAS,MAAY,CAEnB,MAAI,QAAQ,QAAe,MACrB,IAAI,MAAM,yDAAyD,OAAO,OAAA,EAAS,CAC3F,CACF"}
@@ -1,3 +1,3 @@
1
1
  import { ClientOptions } from '../types.ts';
2
- export declare function fetchRemoteMethodsMetadata(methodIds: string[], options: ClientOptions, signal?: AbortSignal): Promise<void>;
2
+ export declare function fetchRemoteMethodsMetadata(methodIds: string[], routePointer: string[], options: ClientOptions, signal?: AbortSignal, middlewareId?: string): Promise<void>;
3
3
  //# sourceMappingURL=fetchRemoteMethodsMetadata.d.ts.map
@@ -1,2 +1,3 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class HandlersRegistry{errorHandlers=new Map;successHandlers=new Map;register(handlerId,errorType,handler){let handlerMap=this.errorHandlers.get(handlerId);handlerMap||(handlerMap=new Map,this.errorHandlers.set(handlerId,handlerMap)),handlerMap.set(errorType,handler)}unregister(handlerId,errorType){const handlerMap=this.errorHandlers.get(handlerId);handlerMap&&(handlerMap.delete(errorType),handlerMap.size===0&&this.errorHandlers.delete(handlerId))}hasHandler(handlerId,errorType){return this.errorHandlers.get(handlerId)?.has(errorType)??!1}executeHandler(handlerId,error){const handlerMap=this.errorHandlers.get(handlerId);if(!handlerMap)return!1;const handler=handlerMap.get(error.type);return handler?(handler(error),!0):!1}registerSuccess(handlerId,handler){this.successHandlers.set(handlerId,handler)}unregisterSuccess(handlerId){this.successHandlers.delete(handlerId)}hasSuccessHandler(handlerId){return this.successHandlers.has(handlerId)}executeSuccessHandler(handlerId,result){const handler=this.successHandlers.get(handlerId);return handler?(handler(result),!0):!1}clearHandlers(handlerId){this.errorHandlers.delete(handlerId),this.successHandlers.delete(handlerId)}clearAll(){this.errorHandlers.clear(),this.successHandlers.clear()}getHandlerIds(){const errorIds=Array.from(this.errorHandlers.keys()),successIds=Array.from(this.successHandlers.keys());return[...new Set([...errorIds,...successIds])]}getErrorTypes(handlerId){const handlerMap=this.errorHandlers.get(handlerId);return handlerMap?Array.from(handlerMap.keys()):[]}}exports.HandlersRegistry=HandlersRegistry;
2
- //# sourceMappingURL=handlersRegistry.cjs.map
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});var HandlersRegistry=class{errorHandlers=new Map;responseHandlers=new Map;requestHandlers=new Map;register(handlerId,errorType,handler){let handlerMap=this.errorHandlers.get(handlerId);handlerMap||(handlerMap=new Map,this.errorHandlers.set(handlerId,handlerMap));const handlers=handlerMap.get(errorType);handlers?handlers.push(handler):handlerMap.set(errorType,[handler])}unregister(handlerId,errorType,handler){const handlerMap=this.errorHandlers.get(handlerId),handlers=handlerMap?.get(errorType);!handlerMap||!handlers||(removeFrom(handlers,handler),handlers.length||handlerMap.delete(errorType),handlerMap.size===0&&this.errorHandlers.delete(handlerId))}hasHandler(handlerId,errorType){return this.errorHandlers.get(handlerId)?.has(errorType)??!1}getErrorHandlers(handlerId,errorType){return[...this.errorHandlers.get(handlerId)?.get(errorType)??[]]}registerResponse(handlerId,handler){const handlers=this.responseHandlers.get(handlerId);handlers?handlers.push(handler):this.responseHandlers.set(handlerId,[handler])}unregisterResponse(handlerId,handler){const handlers=this.responseHandlers.get(handlerId);handlers&&(removeFrom(handlers,handler),handlers.length||this.responseHandlers.delete(handlerId))}hasResponseHandler(handlerId){return this.responseHandlers.has(handlerId)}getResponseHandlers(handlerId){return[...this.responseHandlers.get(handlerId)??[]]}registerRequest(handlerId,handler,createSubRequest){this.requestHandlers.set(handlerId,{handler,createSubRequest})}unregisterRequest(handlerId){this.requestHandlers.delete(handlerId)}hasRequestHandler(handlerId){return this.requestHandlers.has(handlerId)}getRequestHandler(handlerId){return this.requestHandlers.get(handlerId)}getRequestHandlerIds(){return Array.from(this.requestHandlers.keys())}clearHandlers(handlerId){this.errorHandlers.delete(handlerId),this.responseHandlers.delete(handlerId),this.requestHandlers.delete(handlerId)}clearAll(){this.errorHandlers.clear(),this.responseHandlers.clear(),this.requestHandlers.clear()}getHandlerIds(){const errorIds=Array.from(this.errorHandlers.keys()),responseIds=Array.from(this.responseHandlers.keys()),requestIds=Array.from(this.requestHandlers.keys());return[...new Set([...errorIds,...responseIds,...requestIds])]}getErrorTypes(handlerId){const handlerMap=this.errorHandlers.get(handlerId);return handlerMap?Array.from(handlerMap.keys()):[]}};function removeFrom(handlers,handler){const index=handlers.indexOf(handler);index!==-1&&handlers.splice(index,1)}exports.HandlersRegistry=HandlersRegistry;
2
+
3
+ //# sourceMappingURL=handlersRegistry.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"handlersRegistry.cjs","sources":["../../../../src/lib/handlersRegistry.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 {ErrorHandler, SuccessHandler} from '../types.ts';\n\n/** Central registry for persistent middleFn handlers (both success and error) */\nexport class HandlersRegistry {\n private errorHandlers: Map<string, Map<string, ErrorHandler<any>>> = new Map();\n private successHandlers: Map<string, SuccessHandler<any>> = new Map();\n\n /** Register an error handler for a specific handler (middleFn) and error type */\n register(handlerId: string, errorType: string, handler: ErrorHandler<any>): void {\n let handlerMap = this.errorHandlers.get(handlerId);\n if (!handlerMap) {\n handlerMap = new Map();\n this.errorHandlers.set(handlerId, handlerMap);\n }\n handlerMap.set(errorType, handler);\n }\n\n /** Unregister an error handler for a specific handler and error type */\n unregister(handlerId: string, errorType: string): void {\n const handlerMap = this.errorHandlers.get(handlerId);\n if (handlerMap) {\n handlerMap.delete(errorType);\n if (handlerMap.size === 0) this.errorHandlers.delete(handlerId);\n }\n }\n\n /** Check if an error handler exists for a specific handler ID and error type */\n hasHandler(handlerId: string, errorType: string): boolean {\n const handlerMap = this.errorHandlers.get(handlerId);\n return handlerMap?.has(errorType) ?? false;\n }\n\n /** Get and execute the handler for an error, if it exists */\n executeHandler(handlerId: string, error: RpcError<string>): boolean {\n const handlerMap = this.errorHandlers.get(handlerId);\n if (!handlerMap) return false;\n\n const handler = handlerMap.get(error.type);\n if (!handler) return false;\n\n handler(error);\n return true;\n }\n\n /** Register a success handler for a specific middleFn */\n registerSuccess(handlerId: string, handler: SuccessHandler<any>): void {\n this.successHandlers.set(handlerId, handler);\n }\n\n /** Unregister a success handler for a specific middleFn */\n unregisterSuccess(handlerId: string): void {\n this.successHandlers.delete(handlerId);\n }\n\n /** Check if a success handler exists for a specific handler ID */\n hasSuccessHandler(handlerId: string): boolean {\n return this.successHandlers.has(handlerId);\n }\n\n /** Get and execute the success handler for a middleFn result, if it exists */\n executeSuccessHandler(handlerId: string, result: any): boolean {\n const handler = this.successHandlers.get(handlerId);\n if (!handler) return false;\n\n handler(result);\n return true;\n }\n\n /** Clear all handlers (both error and success) for a specific handler ID */\n clearHandlers(handlerId: string): void {\n this.errorHandlers.delete(handlerId);\n this.successHandlers.delete(handlerId);\n }\n\n /** Clear all registered handlers (both error and success) */\n clearAll(): void {\n this.errorHandlers.clear();\n this.successHandlers.clear();\n }\n\n /** Get all registered handler IDs */\n getHandlerIds(): string[] {\n const errorIds = Array.from(this.errorHandlers.keys());\n const successIds = Array.from(this.successHandlers.keys());\n return [...new Set([...errorIds, ...successIds])];\n }\n\n /** Get all error types registered for a handler ID */\n getErrorTypes(handlerId: string): string[] {\n const handlerMap = this.errorHandlers.get(handlerId);\n return handlerMap ? Array.from(handlerMap.keys()) : [];\n }\n}\n"],"names":[],"mappings":"sFAWa,gBAAgB,CACjB,kBAAiE,IACjE,oBAAwD,IAGhE,SAAS,UAAmB,UAAmB,QAA0B,CACrE,IAAI,WAAa,KAAK,cAAc,IAAI,SAAS,EAC5C,aACD,eAAiB,IACjB,KAAK,cAAc,IAAI,UAAW,UAAU,GAEhD,WAAW,IAAI,UAAW,OAAO,CACrC,CAGA,WAAW,UAAmB,UAAiB,CAC3C,MAAM,WAAa,KAAK,cAAc,IAAI,SAAS,EAC/C,aACA,WAAW,OAAO,SAAS,EACvB,WAAW,OAAS,GAAG,KAAK,cAAc,OAAO,SAAS,EAEtE,CAGA,WAAW,UAAmB,UAAiB,CAE3C,OADmB,KAAK,cAAc,IAAI,SAAS,GAChC,IAAI,SAAS,GAAK,EACzC,CAGA,eAAe,UAAmB,MAAuB,CACrD,MAAM,WAAa,KAAK,cAAc,IAAI,SAAS,EACnD,GAAI,CAAC,WAAY,MAAO,GAExB,MAAM,QAAU,WAAW,IAAI,MAAM,IAAI,EACzC,OAAK,SAEL,QAAQ,KAAK,EACN,IAHc,EAIzB,CAGA,gBAAgB,UAAmB,QAA4B,CAC3D,KAAK,gBAAgB,IAAI,UAAW,OAAO,CAC/C,CAGA,kBAAkB,UAAiB,CAC/B,KAAK,gBAAgB,OAAO,SAAS,CACzC,CAGA,kBAAkB,UAAiB,CAC/B,OAAO,KAAK,gBAAgB,IAAI,SAAS,CAC7C,CAGA,sBAAsB,UAAmB,OAAW,CAChD,MAAM,QAAU,KAAK,gBAAgB,IAAI,SAAS,EAClD,OAAK,SAEL,QAAQ,MAAM,EACP,IAHc,EAIzB,CAGA,cAAc,UAAiB,CAC3B,KAAK,cAAc,OAAO,SAAS,EACnC,KAAK,gBAAgB,OAAO,SAAS,CACzC,CAGA,UAAQ,CACJ,KAAK,cAAc,MAAA,EACnB,KAAK,gBAAgB,MAAA,CACzB,CAGA,eAAa,CACT,MAAM,SAAW,MAAM,KAAK,KAAK,cAAc,MAAM,EAC/C,WAAa,MAAM,KAAK,KAAK,gBAAgB,MAAM,EACzD,MAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,SAAU,GAAG,UAAU,CAAC,CAAC,CACpD,CAGA,cAAc,UAAiB,CAC3B,MAAM,WAAa,KAAK,cAAc,IAAI,SAAS,EACnD,OAAO,WAAa,MAAM,KAAK,WAAW,KAAA,CAAM,EAAI,CAAA,CACxD,CACH"}
1
+ {"version":3,"file":"handlersRegistry.cjs","names":[],"sources":["../../../../src/lib/handlersRegistry.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 {ErrorHandler, RequestHandler, ResponseHandler, SubRequest} from '../types.ts';\n\n/** A request handler plus the middleware function that turns its params into a sub request */\nexport interface RequestHandlerEntry {\n handler: RequestHandler<any>;\n createSubRequest: (params: any[]) => SubRequest<any>;\n}\n\n/** Central registry for persistent middleware handlers: request, response and error */\nexport class HandlersRegistry {\n private errorHandlers: Map<string, Map<string, ErrorHandler<any>[]>> = new Map();\n private responseHandlers: Map<string, ResponseHandler<any>[]> = new Map();\n private requestHandlers: Map<string, RequestHandlerEntry> = new Map();\n\n register(handlerId: string, errorType: string, handler: ErrorHandler<any>): void {\n let handlerMap = this.errorHandlers.get(handlerId);\n if (!handlerMap) {\n handlerMap = new Map();\n this.errorHandlers.set(handlerId, handlerMap);\n }\n const handlers = handlerMap.get(errorType);\n if (handlers) handlers.push(handler);\n else handlerMap.set(errorType, [handler]);\n }\n\n unregister(handlerId: string, errorType: string, handler: ErrorHandler<any>): void {\n const handlerMap = this.errorHandlers.get(handlerId);\n const handlers = handlerMap?.get(errorType);\n if (!handlerMap || !handlers) return;\n removeFrom(handlers, handler);\n if (!handlers.length) handlerMap.delete(errorType);\n if (handlerMap.size === 0) this.errorHandlers.delete(handlerId);\n }\n\n hasHandler(handlerId: string, errorType: string): boolean {\n const handlerMap = this.errorHandlers.get(handlerId);\n return handlerMap?.has(errorType) ?? false;\n }\n\n /** A copy, so a handler that adds or removes one leaves this run unchanged */\n getErrorHandlers(handlerId: string, errorType: string): ErrorHandler<any>[] {\n return [...(this.errorHandlers.get(handlerId)?.get(errorType) ?? [])];\n }\n\n registerResponse(handlerId: string, handler: ResponseHandler<any>): void {\n const handlers = this.responseHandlers.get(handlerId);\n if (handlers) handlers.push(handler);\n else this.responseHandlers.set(handlerId, [handler]);\n }\n\n unregisterResponse(handlerId: string, handler: ResponseHandler<any>): void {\n const handlers = this.responseHandlers.get(handlerId);\n if (!handlers) return;\n removeFrom(handlers, handler);\n if (!handlers.length) this.responseHandlers.delete(handlerId);\n }\n\n hasResponseHandler(handlerId: string): boolean {\n return this.responseHandlers.has(handlerId);\n }\n\n /** A copy, so a handler that adds or removes one leaves this run unchanged */\n getResponseHandlers(handlerId: string): ResponseHandler<any>[] {\n return [...(this.responseHandlers.get(handlerId) ?? [])];\n }\n\n registerRequest(\n handlerId: string,\n handler: RequestHandler<any>,\n createSubRequest: RequestHandlerEntry['createSubRequest']\n ): void {\n this.requestHandlers.set(handlerId, {handler, createSubRequest});\n }\n\n unregisterRequest(handlerId: string): void {\n this.requestHandlers.delete(handlerId);\n }\n\n hasRequestHandler(handlerId: string): boolean {\n return this.requestHandlers.has(handlerId);\n }\n\n getRequestHandler(handlerId: string): RequestHandlerEntry | undefined {\n return this.requestHandlers.get(handlerId);\n }\n\n getRequestHandlerIds(): string[] {\n return Array.from(this.requestHandlers.keys());\n }\n\n clearHandlers(handlerId: string): void {\n this.errorHandlers.delete(handlerId);\n this.responseHandlers.delete(handlerId);\n this.requestHandlers.delete(handlerId);\n }\n\n clearAll(): void {\n this.errorHandlers.clear();\n this.responseHandlers.clear();\n this.requestHandlers.clear();\n }\n\n getHandlerIds(): string[] {\n const errorIds = Array.from(this.errorHandlers.keys());\n const responseIds = Array.from(this.responseHandlers.keys());\n const requestIds = Array.from(this.requestHandlers.keys());\n return [...new Set([...errorIds, ...responseIds, ...requestIds])];\n }\n\n getErrorTypes(handlerId: string): string[] {\n const handlerMap = this.errorHandlers.get(handlerId);\n return handlerMap ? Array.from(handlerMap.keys()) : [];\n }\n}\n\n/** A handler registered twice needs two removals */\nfunction removeFrom<H>(handlers: H[], handler: H): void {\n const index = handlers.indexOf(handler);\n if (index !== -1) handlers.splice(index, 1);\n}\n"],"mappings":"mEAgBA,IAAa,iBAAb,KAA8B,CAC5B,cAAuE,IAAI,IAC3E,iBAAgE,IAAI,IACpE,gBAA4D,IAAI,IAEhE,SAAS,UAAmB,UAAmB,QAAkC,CAC/E,IAAI,WAAa,KAAK,cAAc,IAAI,SAAS,EAC5C,aACH,WAAa,IAAI,IACjB,KAAK,cAAc,IAAI,UAAW,UAAU,GAE9C,MAAM,SAAW,WAAW,IAAI,SAAS,EACrC,SAAU,SAAS,KAAK,OAAO,EAC9B,WAAW,IAAI,UAAW,CAAC,OAAO,CAAC,CAC1C,CAEA,WAAW,UAAmB,UAAmB,QAAkC,CACjF,MAAM,WAAa,KAAK,cAAc,IAAI,SAAS,EAC7C,SAAW,YAAY,IAAI,SAAS,EACtC,CAAC,YAAc,CAAC,WACpB,WAAW,SAAU,OAAO,EACvB,SAAS,QAAQ,WAAW,OAAO,SAAS,EAC7C,WAAW,OAAS,GAAG,KAAK,cAAc,OAAO,SAAS,EAChE,CAEA,WAAW,UAAmB,UAA4B,CAExD,OADmB,KAAK,cAAc,IAAI,SACnC,GAAY,IAAI,SAAS,GAAK,EACvC,CAGA,iBAAiB,UAAmB,UAAwC,CAC1E,MAAO,CAAC,GAAI,KAAK,cAAc,IAAI,SAAS,GAAG,IAAI,SAAS,GAAK,CAAC,CAAE,CACtE,CAEA,iBAAiB,UAAmB,QAAqC,CACvE,MAAM,SAAW,KAAK,iBAAiB,IAAI,SAAS,EAChD,SAAU,SAAS,KAAK,OAAO,EAC9B,KAAK,iBAAiB,IAAI,UAAW,CAAC,OAAO,CAAC,CACrD,CAEA,mBAAmB,UAAmB,QAAqC,CACzE,MAAM,SAAW,KAAK,iBAAiB,IAAI,SAAS,EAC/C,WACL,WAAW,SAAU,OAAO,EACvB,SAAS,QAAQ,KAAK,iBAAiB,OAAO,SAAS,EAC9D,CAEA,mBAAmB,UAA4B,CAC7C,OAAO,KAAK,iBAAiB,IAAI,SAAS,CAC5C,CAGA,oBAAoB,UAA2C,CAC7D,MAAO,CAAC,GAAI,KAAK,iBAAiB,IAAI,SAAS,GAAK,CAAC,CAAE,CACzD,CAEA,gBACE,UACA,QACA,iBACM,CACN,KAAK,gBAAgB,IAAI,UAAW,CAAC,QAAS,gBAAgB,CAAC,CACjE,CAEA,kBAAkB,UAAyB,CACzC,KAAK,gBAAgB,OAAO,SAAS,CACvC,CAEA,kBAAkB,UAA4B,CAC5C,OAAO,KAAK,gBAAgB,IAAI,SAAS,CAC3C,CAEA,kBAAkB,UAAoD,CACpE,OAAO,KAAK,gBAAgB,IAAI,SAAS,CAC3C,CAEA,sBAAiC,CAC/B,OAAO,MAAM,KAAK,KAAK,gBAAgB,KAAK,CAAC,CAC/C,CAEA,cAAc,UAAyB,CACrC,KAAK,cAAc,OAAO,SAAS,EACnC,KAAK,iBAAiB,OAAO,SAAS,EACtC,KAAK,gBAAgB,OAAO,SAAS,CACvC,CAEA,UAAiB,CACf,KAAK,cAAc,MAAM,EACzB,KAAK,iBAAiB,MAAM,EAC5B,KAAK,gBAAgB,MAAM,CAC7B,CAEA,eAA0B,CACxB,MAAM,SAAW,MAAM,KAAK,KAAK,cAAc,KAAK,CAAC,EAC/C,YAAc,MAAM,KAAK,KAAK,iBAAiB,KAAK,CAAC,EACrD,WAAa,MAAM,KAAK,KAAK,gBAAgB,KAAK,CAAC,EACzD,MAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,SAAU,GAAG,YAAa,GAAG,UAAU,CAAC,CAAC,CAClE,CAEA,cAAc,UAA6B,CACzC,MAAM,WAAa,KAAK,cAAc,IAAI,SAAS,EACnD,OAAO,WAAa,MAAM,KAAK,WAAW,KAAK,CAAC,EAAI,CAAC,CACvD,CACF,EAGA,SAAS,WAAc,SAAe,QAAkB,CACtD,MAAM,MAAQ,SAAS,QAAQ,OAAO,EAClC,QAAU,IAAI,SAAS,OAAO,MAAO,CAAC,CAC5C"}
@@ -1,16 +1,25 @@
1
- import { RpcError } from '@mionjs/core';
2
- import { ErrorHandler, SuccessHandler } from '../types.ts';
1
+ import { ErrorHandler, RequestHandler, ResponseHandler, SubRequest } from '../types.ts';
2
+ export interface RequestHandlerEntry {
3
+ handler: RequestHandler<any>;
4
+ createSubRequest: (params: any[]) => SubRequest<any>;
5
+ }
3
6
  export declare class HandlersRegistry {
4
7
  private errorHandlers;
5
- private successHandlers;
8
+ private responseHandlers;
9
+ private requestHandlers;
6
10
  register(handlerId: string, errorType: string, handler: ErrorHandler<any>): void;
7
- unregister(handlerId: string, errorType: string): void;
11
+ unregister(handlerId: string, errorType: string, handler: ErrorHandler<any>): void;
8
12
  hasHandler(handlerId: string, errorType: string): boolean;
9
- executeHandler(handlerId: string, error: RpcError<string>): boolean;
10
- registerSuccess(handlerId: string, handler: SuccessHandler<any>): void;
11
- unregisterSuccess(handlerId: string): void;
12
- hasSuccessHandler(handlerId: string): boolean;
13
- executeSuccessHandler(handlerId: string, result: any): boolean;
13
+ getErrorHandlers(handlerId: string, errorType: string): ErrorHandler<any>[];
14
+ registerResponse(handlerId: string, handler: ResponseHandler<any>): void;
15
+ unregisterResponse(handlerId: string, handler: ResponseHandler<any>): void;
16
+ hasResponseHandler(handlerId: string): boolean;
17
+ getResponseHandlers(handlerId: string): ResponseHandler<any>[];
18
+ registerRequest(handlerId: string, handler: RequestHandler<any>, createSubRequest: RequestHandlerEntry['createSubRequest']): void;
19
+ unregisterRequest(handlerId: string): void;
20
+ hasRequestHandler(handlerId: string): boolean;
21
+ getRequestHandler(handlerId: string): RequestHandlerEntry | undefined;
22
+ getRequestHandlerIds(): string[];
14
23
  clearHandlers(handlerId: string): void;
15
24
  clearAll(): void;
16
25
  getHandlerIds(): string[];
@@ -0,0 +1,3 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const require_src_lib_methods=require("./methods.cjs");let _mionjs_core=require("@mionjs/core");function hasHeadersSubsetParam(id,params){const method=require_src_lib_methods.getMethod(id);return method?method.type===_mionjs_core.HandlerType.headersMiddleware&&!!method.headersParam:params?.[0]instanceof _mionjs_core.HeadersSubset}function headersToRecord(headers){return headers?typeof Headers<"u"&&headers instanceof Headers?Object.fromEntries(headers.entries()):typeof headers[Symbol.iterator]=="function"?Object.fromEntries(headers):{...headers}:{}}function extractRequestHeaders(context){const headers={},subRequestIds=Object.keys(context.subRequestList);for(let i=0;i<subRequestIds.length;i++){const id=subRequestIds[i],subRequest=context.subRequestList[id];!subRequest||!hasHeadersSubsetParam(id,subRequest.params)||Object.assign(headers,extractHeadersFromParams(subRequest.params))}return headers}function extractHeadersFromParams(params){if(!params||params.length===0)throw new _mionjs_core.RpcError({type:"missing-headers-param",publicMessage:"HeadersMiddleware requires a HeadersSubset parameter."});const firstParam=params[0];if(firstParam instanceof _mionjs_core.HeadersSubset||firstParam&&typeof firstParam=="object"&&"headers"in firstParam&&typeof firstParam.headers=="object")return firstParam.headers;throw new _mionjs_core.RpcError({type:"invalid-headers-param",publicMessage:"HeadersMiddleware first parameter must be a HeadersSubset instance or object with headers property."})}function reconstructHeadersSubsetFromResponse(methodId,responseHeaders){const method=require_src_lib_methods.getMethod(methodId);if(!method?.headersReturn?.headerNames||method.headersReturn.headerNames.length===0)return;const headerNames=method.headersReturn.headerNames,headersMap={};for(const name of headerNames){const value=responseHeaders.get(name);value!=null&&(headersMap[name]=value)}if(Object.keys(headersMap).length>0)return(0,_mionjs_core.trustedHeadersSubset)(headersMap)}exports.extractRequestHeaders=extractRequestHeaders;exports.hasHeadersSubsetParam=hasHeadersSubsetParam;exports.headersToRecord=headersToRecord;exports.reconstructHeadersSubsetFromResponse=reconstructHeadersSubsetFromResponse;
2
+
3
+ //# sourceMappingURL=headers.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headers.cjs","names":[],"sources":["../../../../src/lib/headers.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 {HandlerType, HeadersSubset, RpcError, trustedHeadersSubset} from '@mionjs/core';\nimport {getMethod} from './methods.ts';\nimport type {CallContext} from '../types.ts';\n\n/** True when a subrequest's first param travels as HTTP headers rather than in the body; with no\n * cached metadata yet (a route's FIRST optimistic call) the value itself answers. */\nexport function hasHeadersSubsetParam(id: string, params: any[] | undefined): boolean {\n const method = getMethod(id);\n if (method) return method.type === HandlerType.headersMiddleware && !!method.headersParam;\n return params?.[0] instanceof HeadersSubset;\n}\n\n/** Spreading a `HeadersInit` only works for the plain-object form: a `Headers` instance has no own\n * enumerable properties and the `[name, value][]` form spreads as numeric indices. Internal, never exported. */\nexport function headersToRecord(headers: HeadersInit | undefined): Record<string, string> {\n if (!headers) return {};\n if (typeof Headers !== 'undefined' && headers instanceof Headers) return Object.fromEntries(headers.entries());\n // Any iterable of pairs (the `[name, value][]` form, a Map): spreading gives numeric indices, not headers.\n if (typeof (headers as Iterable<readonly [string, string]>)[Symbol.iterator] === 'function') {\n return Object.fromEntries(headers as Iterable<readonly [string, string]>);\n }\n return {...(headers as Record<string, string>)};\n}\n\nexport function extractRequestHeaders(context: CallContext): Record<string, string> {\n const headers: Record<string, 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 || !hasHeadersSubsetParam(id, subRequest.params)) continue;\n Object.assign(headers, extractHeadersFromParams(subRequest.params));\n }\n\n return headers;\n}\n\nfunction extractHeadersFromParams(params: any[]): Record<string, string> {\n if (!params || params.length === 0) {\n throw new RpcError({\n type: 'missing-headers-param',\n publicMessage: 'HeadersMiddleware requires a HeadersSubset parameter.',\n });\n }\n\n const firstParam = params[0];\n\n if (firstParam instanceof HeadersSubset) {\n return firstParam.headers as Record<string, string>;\n }\n\n if (firstParam && typeof firstParam === 'object' && 'headers' in firstParam && typeof firstParam.headers === 'object') {\n return firstParam.headers as Record<string, string>;\n }\n\n throw new RpcError({\n type: 'invalid-headers-param',\n publicMessage: 'HeadersMiddleware first parameter must be a HeadersSubset instance or object with headers property.',\n });\n}\n\nexport function reconstructHeadersSubsetFromResponse(\n methodId: string,\n responseHeaders: Headers\n): HeadersSubset<string, string> | undefined {\n const method = getMethod(methodId);\n\n if (!method?.headersReturn?.headerNames || method.headersReturn.headerNames.length === 0) {\n return undefined;\n }\n\n const headerNames = method.headersReturn.headerNames;\n const headersMap: Record<string, string> = {};\n\n for (const name of headerNames) {\n const value = responseHeaders.get(name);\n if (value !== undefined && value !== null) {\n headersMap[name] = value;\n }\n }\n\n if (Object.keys(headersMap).length > 0) {\n return trustedHeadersSubset(headersMap);\n }\n\n return undefined;\n}\n"],"mappings":"mKAaA,SAAgB,sBAAsB,GAAY,OAAoC,CACpF,MAAM,OAAS,wBAAA,UAAU,EAAE,EAC3B,OAAI,OAAe,OAAO,OAAS,aAAA,YAAY,mBAAqB,CAAC,CAAC,OAAO,aACtE,SAAS,CAAA,YAAc,aAAA,aAChC,CAIA,SAAgB,gBAAgB,QAA0D,CACxF,OAAK,QACD,OAAO,QAAY,KAAe,mBAAmB,QAAgB,OAAO,YAAY,QAAQ,QAAQ,CAAC,EAEzG,OAAQ,QAAgD,OAAO,QAAA,GAAc,WACxE,OAAO,YAAY,OAA8C,EAEnE,CAAC,GAAI,OAAkC,EANzB,CAAC,CAOxB,CAEA,SAAgB,sBAAsB,QAA8C,CAClF,MAAM,QAAkC,CAAC,EACnC,cAAgB,OAAO,KAAK,QAAQ,cAAc,EAExD,QAAS,EAAI,EAAG,EAAI,cAAc,OAAQ,IAAK,CAC7C,MAAM,GAAK,cAAc,CAAA,EACnB,WAAa,QAAQ,eAAe,EAAA,EACtC,CAAC,YAAc,CAAC,sBAAsB,GAAI,WAAW,MAAM,GAC/D,OAAO,OAAO,QAAS,yBAAyB,WAAW,MAAM,CAAC,CACpE,CAEA,OAAO,OACT,CAEA,SAAS,yBAAyB,OAAuC,CACvE,GAAI,CAAC,QAAU,OAAO,SAAW,EAC/B,MAAM,IAAI,aAAA,SAAS,CACjB,KAAM,wBACN,cAAe,uDACjB,CAAC,EAGH,MAAM,WAAa,OAAO,CAAA,EAM1B,GAJI,sBAAsB,aAAA,eAItB,YAAc,OAAO,YAAe,UAAY,YAAa,YAAc,OAAO,WAAW,SAAY,SAC3G,OAAO,WAAW,QAGpB,MAAM,IAAI,aAAA,SAAS,CACjB,KAAM,wBACN,cAAe,qGACjB,CAAC,CACH,CAEA,SAAgB,qCACd,SACA,gBAC2C,CAC3C,MAAM,OAAS,wBAAA,UAAU,QAAQ,EAEjC,GAAI,CAAC,QAAQ,eAAe,aAAe,OAAO,cAAc,YAAY,SAAW,EACrF,OAGF,MAAM,YAAc,OAAO,cAAc,YACnC,WAAqC,CAAC,EAE5C,UAAW,QAAQ,YAAa,CAC9B,MAAM,MAAQ,gBAAgB,IAAI,IAAI,EACX,OAAU,OACnC,WAAW,IAAA,EAAQ,MAEvB,CAEA,GAAI,OAAO,KAAK,UAAU,EAAE,OAAS,EACnC,SAAA,aAAA,sBAA4B,UAAU,CAI1C"}
@@ -0,0 +1,7 @@
1
+ import { HeadersSubset } from '@mionjs/core';
2
+ import { CallContext } from '../types.ts';
3
+ export declare function hasHeadersSubsetParam(id: string, params: any[] | undefined): boolean;
4
+ export declare function headersToRecord(headers: HeadersInit | undefined): Record<string, string>;
5
+ export declare function extractRequestHeaders(context: CallContext): Record<string, string>;
6
+ export declare function reconstructHeadersSubsetFromResponse(methodId: string, responseHeaders: Headers): HeadersSubset<string, string> | undefined;
7
+ //# sourceMappingURL=headers.d.ts.map
@@ -0,0 +1,3 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let _mionjs_core=require("@mionjs/core");function methodRootHashes(metadata){const parser=metadata.options?.parser??_mionjs_core.DEFAULT_PARSER,roots=[],addSet=(jitHash,strategy)=>{if(!(!jitHash||jitHash===_mionjs_core.EMPTY_HASH))for(const hash of Object.values((0,_mionjs_core.getJitFnHashes)(jitHash,strategy)))typeof hash=="string"&&roots.push(hash)};return addSet(metadata.paramsJitHash,parser.params),addSet(metadata.returnJitHash,parser.return),metadata.headersParam&&addSet(metadata.headersParam.jitHash,"mutate"),metadata.headersReturn&&addSet(metadata.headersReturn.jitHash,"mutate"),roots}function findOrphans(graph){const reachedDeps=new Set,reachedPureFns=new Set,pending=[];for(const metadata of Object.values(graph.methods))for(const hash of methodRootHashes(metadata))graph.deps[hash]&&!reachedDeps.has(hash)&&(reachedDeps.add(hash),pending.push(hash));const reachPureFn=key=>{if(!reachedPureFns.has(key)){reachedPureFns.add(key);for(const nested of graph.pureFns[key]?.pureFnDependencies??[])reachPureFn(nested)}};for(;pending.length;){const entry=graph.deps[pending.pop()];for(const hash of entry?.rtDependencies??[])!graph.deps[hash]||reachedDeps.has(hash)||(reachedDeps.add(hash),pending.push(hash));for(const key of entry?.pureFnDependencies??[])reachPureFn(key)}const orphans=[];for(const hash of Object.keys(graph.deps))reachedDeps.has(hash)||orphans.push(["j",hash]);for(const key of Object.keys(graph.pureFns))reachedPureFns.has(key)||orphans.push(["p",key]);return orphans}exports.findOrphans=findOrphans;
2
+
3
+ //# sourceMappingURL=metadataEviction.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadataEviction.cjs","names":[],"sources":["../../../../src/lib/metadataEviction.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 {DEFAULT_PARSER, EMPTY_HASH, getJitFnHashes} from '@mionjs/core';\nimport type {CompiledFnData, MethodWithOptions, PureFunctionData} from '@mionjs/core';\nimport type {MetadataRecordKey} from './storage.ts';\n\n/** The stored cache as one graph: methods point at compiled functions by hash, and those point at\n * each other. Everything already parsed by the hydrator, so the sweep costs no extra reads. */\nexport interface CacheGraph {\n /** by methodId */\n methods: Record<string, MethodWithOptions>;\n /** by compiled function hash */\n deps: Record<string, CompiledFnData>;\n /** by `${namespace}::${fnName}` */\n pureFns: Record<string, PureFunctionData>;\n}\n\n/** Every compiled function hash the method itself names, across both wires and both header sets. */\nfunction methodRootHashes(metadata: MethodWithOptions): string[] {\n const parser = metadata.options?.parser ?? DEFAULT_PARSER;\n const roots: string[] = [];\n // a root is anything the method COULD reach; a hash it never uses is simply absent from the store\n const addSet = (jitHash: string, strategy: Parameters<typeof getJitFnHashes>[1]) => {\n if (!jitHash || jitHash === EMPTY_HASH) return;\n // the optional hashes are absent on the returned shape, so only the real strings become roots\n for (const hash of Object.values(getJitFnHashes(jitHash, strategy)) as (string | undefined)[]) {\n if (typeof hash === 'string') roots.push(hash);\n }\n };\n addSet(metadata.paramsJitHash, parser.params);\n addSet(metadata.returnJitHash, parser.return);\n if (metadata.headersParam) addSet(metadata.headersParam.jitHash, 'mutate');\n if (metadata.headersReturn) addSet(metadata.headersReturn.jitHash, 'mutate');\n return roots;\n}\n\n/** The compiled functions no stored method can reach any more. Hashes are content addresses, so an entry is\n * never stale, only unreachable: a deploy rewrites a method's row and leaves the old hashes behind. */\nexport function findOrphans(graph: CacheGraph): MetadataRecordKey[] {\n const reachedDeps = new Set<string>();\n const reachedPureFns = new Set<string>();\n const pending: string[] = [];\n\n for (const metadata of Object.values(graph.methods)) {\n for (const hash of methodRootHashes(metadata)) {\n if (graph.deps[hash] && !reachedDeps.has(hash)) {\n reachedDeps.add(hash);\n pending.push(hash);\n }\n }\n }\n\n const reachPureFn = (key: string) => {\n if (reachedPureFns.has(key)) return;\n reachedPureFns.add(key);\n for (const nested of graph.pureFns[key]?.pureFnDependencies ?? []) reachPureFn(nested);\n };\n\n while (pending.length) {\n const entry = graph.deps[pending.pop() as string];\n for (const hash of entry?.rtDependencies ?? []) {\n if (!graph.deps[hash] || reachedDeps.has(hash)) continue;\n reachedDeps.add(hash);\n pending.push(hash);\n }\n for (const key of entry?.pureFnDependencies ?? []) reachPureFn(key);\n }\n\n const orphans: MetadataRecordKey[] = [];\n for (const hash of Object.keys(graph.deps)) if (!reachedDeps.has(hash)) orphans.push(['j', hash]);\n for (const key of Object.keys(graph.pureFns)) if (!reachedPureFns.has(key)) orphans.push(['p', key]);\n return orphans;\n}\n"],"mappings":"4GAuBA,SAAS,iBAAiB,SAAuC,CAC/D,MAAM,OAAS,SAAS,SAAS,QAAU,aAAA,eACrC,MAAkB,CAAC,EAEnB,OAAA,CAAU,QAAiB,WAAmD,CAClF,GAAI,GAAC,SAAW,UAAY,aAAA,YAE5B,UAAW,QAAQ,OAAO,UAAA,aAAA,gBAAsB,QAAS,QAAQ,CAAC,EAC5D,OAAO,MAAS,UAAU,MAAM,KAAK,IAAI,CAEjD,EACA,cAAO,SAAS,cAAe,OAAO,MAAM,EAC5C,OAAO,SAAS,cAAe,OAAO,MAAM,EACxC,SAAS,cAAc,OAAO,SAAS,aAAa,QAAS,QAAQ,EACrE,SAAS,eAAe,OAAO,SAAS,cAAc,QAAS,QAAQ,EACpE,KACT,CAIA,SAAgB,YAAY,MAAwC,CAClE,MAAM,YAAc,IAAI,IAClB,eAAiB,IAAI,IACrB,QAAoB,CAAC,EAE3B,UAAW,YAAY,OAAO,OAAO,MAAM,OAAO,EAChD,UAAW,QAAQ,iBAAiB,QAAQ,EACtC,MAAM,KAAK,IAAA,GAAS,CAAC,YAAY,IAAI,IAAI,IAC3C,YAAY,IAAI,IAAI,EACpB,QAAQ,KAAK,IAAI,GAKvB,MAAM,YAAe,KAAgB,CACnC,GAAI,gBAAe,IAAI,GAAG,EAC1B,gBAAe,IAAI,GAAG,EACtB,UAAW,UAAU,MAAM,QAAQ,GAAA,GAAM,oBAAsB,CAAC,EAAG,YAAY,MAAM,EACvF,EAEA,KAAO,QAAQ,QAAQ,CACrB,MAAM,MAAQ,MAAM,KAAK,QAAQ,IAAI,CAAA,EACrC,UAAW,QAAQ,OAAO,gBAAkB,CAAC,EACvC,CAAC,MAAM,KAAK,IAAA,GAAS,YAAY,IAAI,IAAI,IAC7C,YAAY,IAAI,IAAI,EACpB,QAAQ,KAAK,IAAI,GAEnB,UAAW,OAAO,OAAO,oBAAsB,CAAC,EAAG,YAAY,GAAG,CACpE,CAEA,MAAM,QAA+B,CAAC,EACtC,UAAW,QAAQ,OAAO,KAAK,MAAM,IAAI,EAAQ,YAAY,IAAI,IAAI,GAAG,QAAQ,KAAK,CAAC,IAAK,IAAI,CAAC,EAChG,UAAW,OAAO,OAAO,KAAK,MAAM,OAAO,EAAQ,eAAe,IAAI,GAAG,GAAG,QAAQ,KAAK,CAAC,IAAK,GAAG,CAAC,EACnG,OAAO,OACT"}
@@ -0,0 +1,9 @@
1
+ import { CompiledFnData, MethodWithOptions, PureFunctionData } from '@mionjs/core';
2
+ import { MetadataRecordKey } from './storage.ts';
3
+ export interface CacheGraph {
4
+ methods: Record<string, MethodWithOptions>;
5
+ deps: Record<string, CompiledFnData>;
6
+ pureFns: Record<string, PureFunctionData>;
7
+ }
8
+ export declare function findOrphans(graph: CacheGraph): MetadataRecordKey[];
9
+ //# sourceMappingURL=metadataEviction.d.ts.map
@@ -0,0 +1,3 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});var MIDDLEWARE_TARGET=Symbol("mion.middlewareTarget"),fetchers=new WeakMap,readTarget=middleware=>middleware[MIDDLEWARE_TARGET];function middlewareTargetOf(middleware){const target=readTarget(middleware);if(!target)throw new Error("Expected a middleware from the client, like middlewares.mionFetchMetadata");return target}function setMetadataFetcher(registry,fetcher){fetchers.set(registry,fetcher)}function getMetadataFetcher(registry){return registry&&fetchers.get(registry)}function metadataFetcherOf(middleware){return getMetadataFetcher(readTarget(middleware)?.registry)}exports.MIDDLEWARE_TARGET=MIDDLEWARE_TARGET;exports.getMetadataFetcher=getMetadataFetcher;exports.metadataFetcherOf=metadataFetcherOf;exports.middlewareTargetOf=middlewareTargetOf;exports.setMetadataFetcher=setMetadataFetcher;
2
+
3
+ //# sourceMappingURL=metadataFetcher.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadataFetcher.cjs","names":[],"sources":["../../../../src/lib/metadataFetcher.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\n// Internal hooks between the dispatch and `useFetchMetadata`. Never exported from the package: the public\n// middleware type stays hooks only, and a client that never sets metadata fetching up ships none of it.\n\nimport type {RpcError} from '@mionjs/core';\nimport type {ClientCallContext, ClientOptions, RequestErrors} from '../types.ts';\nimport type {HandlersRegistry} from './handlersRegistry.ts';\n\n/** What `useFetchMetadata` hands the dispatch, once per client. */\nexport interface MetadataFetcher {\n /** Rows for the given ids without running any route; route sync refetches through it. */\n fetchRows(ids: string[], routePointer: string[], options: ClientOptions, signal?: AbortSignal): Promise<void>;\n startCall(context: ClientCallContext): MetadataCall;\n}\n\n/** One call's metadata state, driven by the dispatch attempt by attempt. */\nexport interface MetadataCall {\n /** the metadata middleware's id: the rows a call asks for ride the request under it */\n readonly id: string;\n /** Before the chain is read. `ids` omits its own entry; `optimistic`: sent before rows are known, in plain wire forms. */\n prepare(skipOptimistic: boolean): Promise<{ids: string[]; optimistic: boolean}>;\n /** Optimistic attempt: asks the server for the rows of every id in the call. */\n askRows(): void;\n /** Rows for the given ids without running any route: `typeErrors()`, a body that cannot go out plain. */\n fetchRows(ids: string[], signal?: AbortSignal): Promise<void>;\n /** Takes this call's rows out of the raw body before anything is decoded; returns a refusal to put back. */\n readRows(parsedBody: Record<string, unknown>): Record<string, RpcError<string>> | undefined;\n /** After a failed attempt: true when a resend with fresh rows can fix it. Called at most once per call. */\n shouldResend(errors: RequestErrors): Promise<boolean>;\n /** a store write the browser refused, reported once in a later call's @thrownErrors */\n takeError(): RpcError<string> | undefined;\n}\n\n/** A middleware's client and id, read off `middlewares.<name>` through a key no public type names. */\nexport const MIDDLEWARE_TARGET = Symbol('mion.middlewareTarget');\n\nexport interface MiddlewareTarget {\n id: string;\n registry: HandlersRegistry;\n}\n\nconst fetchers = new WeakMap<HandlersRegistry, MetadataFetcher>();\n\nconst readTarget = (middleware: object) => (middleware as {[MIDDLEWARE_TARGET]?: MiddlewareTarget})[MIDDLEWARE_TARGET];\n\nexport function middlewareTargetOf(middleware: object): MiddlewareTarget {\n const target = readTarget(middleware);\n if (!target) throw new Error('Expected a middleware from the client, like middlewares.mionFetchMetadata');\n return target;\n}\n\nexport function setMetadataFetcher(registry: HandlersRegistry, fetcher: MetadataFetcher): void {\n fetchers.set(registry, fetcher);\n}\n\nexport function getMetadataFetcher(registry: HandlersRegistry | undefined): MetadataFetcher | undefined {\n return registry && fetchers.get(registry);\n}\n\n/** The fetcher of the client a middleware belongs to, if it set one up; route sync refetches through it. */\nexport function metadataFetcherOf(middleware: object): MetadataFetcher | undefined {\n return getMetadataFetcher(readTarget(middleware)?.registry);\n}\n"],"mappings":"mEAwCA,IAAa,kBAAoB,OAAO,uBAAuB,EAOzD,SAAW,IAAI,QAEf,WAAc,YAAwB,WAAwD,iBAAA,EAEpG,SAAgB,mBAAmB,WAAsC,CACvE,MAAM,OAAS,WAAW,UAAU,EACpC,GAAI,CAAC,OAAQ,MAAM,IAAI,MAAM,2EAA2E,EACxG,OAAO,MACT,CAEA,SAAgB,mBAAmB,SAA4B,QAAgC,CAC7F,SAAS,IAAI,SAAU,OAAO,CAChC,CAEA,SAAgB,mBAAmB,SAAqE,CACtG,OAAO,UAAY,SAAS,IAAI,QAAQ,CAC1C,CAGA,SAAgB,kBAAkB,WAAiD,CACjF,OAAO,mBAAmB,WAAW,UAAU,GAAG,QAAQ,CAC5D"}
@@ -0,0 +1,29 @@
1
+ import { RpcError } from '@mionjs/core';
2
+ import { ClientCallContext, ClientOptions, RequestErrors } from '../types.ts';
3
+ import { HandlersRegistry } from './handlersRegistry.ts';
4
+ export interface MetadataFetcher {
5
+ fetchRows(ids: string[], routePointer: string[], options: ClientOptions, signal?: AbortSignal): Promise<void>;
6
+ startCall(context: ClientCallContext): MetadataCall;
7
+ }
8
+ export interface MetadataCall {
9
+ readonly id: string;
10
+ prepare(skipOptimistic: boolean): Promise<{
11
+ ids: string[];
12
+ optimistic: boolean;
13
+ }>;
14
+ askRows(): void;
15
+ fetchRows(ids: string[], signal?: AbortSignal): Promise<void>;
16
+ readRows(parsedBody: Record<string, unknown>): Record<string, RpcError<string>> | undefined;
17
+ shouldResend(errors: RequestErrors): Promise<boolean>;
18
+ takeError(): RpcError<string> | undefined;
19
+ }
20
+ export declare const MIDDLEWARE_TARGET: unique symbol;
21
+ export interface MiddlewareTarget {
22
+ id: string;
23
+ registry: HandlersRegistry;
24
+ }
25
+ export declare function middlewareTargetOf(middleware: object): MiddlewareTarget;
26
+ export declare function setMetadataFetcher(registry: HandlersRegistry, fetcher: MetadataFetcher): void;
27
+ export declare function getMetadataFetcher(registry: HandlersRegistry | undefined): MetadataFetcher | undefined;
28
+ export declare function metadataFetcherOf(middleware: object): MetadataFetcher | undefined;
29
+ //# sourceMappingURL=metadataFetcher.d.ts.map
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const require_src_lib_clientMethodsMetadata=require("./clientMethodsMetadata.cjs"),require_src_lib_fetchRemoteMethodsMetadata=require("./fetchRemoteMethodsMetadata.cjs"),require_src_lib_apiVersionRecovery=require("./apiVersionRecovery.cjs");require("@mionjs/run-types/formats");exports.fetchRemoteMethodsMetadata=require_src_lib_fetchRemoteMethodsMetadata.fetchRemoteMethodsMetadata;exports.forgetFetchedMetadata=require_src_lib_clientMethodsMetadata.forgetFetchedMetadata;exports.hydrateMetadataCache=require_src_lib_clientMethodsMetadata.hydrateMetadataCache;exports.installMethodRows=require_src_lib_clientMethodsMetadata.installMethodRows;exports.purgeHydratedMetadata=require_src_lib_clientMethodsMetadata.purgeHydratedMetadata;exports.takeMetadataCacheError=require_src_lib_clientMethodsMetadata.takeMetadataCacheError;exports.unverifiedIds=require_src_lib_apiVersionRecovery.unverifiedIds;exports.verifyMethodRows=require_src_lib_apiVersionRecovery.verifyMethodRows;exports.wasHydratedFromCache=require_src_lib_clientMethodsMetadata.wasHydratedFromCache;
@@ -0,0 +1,4 @@
1
+ export { forgetFetchedMetadata, hydrateMetadataCache, installMethodRows, purgeHydratedMetadata, takeMetadataCacheError, wasHydratedFromCache, } from './clientMethodsMetadata.ts';
2
+ export { fetchRemoteMethodsMetadata } from './fetchRemoteMethodsMetadata.ts';
3
+ export { unverifiedIds, verifyMethodRows } from './apiVersionRecovery.ts';
4
+ //# sourceMappingURL=metadataFromServer.d.ts.map
@@ -0,0 +1,3 @@
1
+ var __create=Object.create;var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __getProtoOf=Object.getPrototypeOf,__hasOwnProp=Object.prototype.hasOwnProperty;var __copyProps=(to,from,except,desc)=>{if(from&&typeof from=="object"||typeof from=="function")for(let key of __getOwnPropNames(from))!__hasOwnProp.call(to,key)&&key!==except&&__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to};var __toESM=(mod,isNodeMode,target)=>(target=mod!=null?__create(__getProtoOf(mod)):{},__copyProps(isNodeMode||!mod||!mod.__esModule?__defProp(target,"default",{value:mod,enumerable:!0}):target,mod));Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let _mionjs_core=require("@mionjs/core");var laneModule,loading;function loadMetadataFromServer(){return laneModule?Promise.resolve(laneModule):(loading??=import("#metadata-from-server").then(loaded=>(laneModule=loaded,loaded)).catch(error=>{throw loading=void 0,laneLoadError(error)}),loading)}function loadedMetadataFromServer(){return laneModule}function resetMetadataFromServer(){laneModule=void 0,loading=void 0}function laneLoadError(error){return new _mionjs_core.RpcError({type:"metadata-load-error",publicMessage:"Could not load the code that asks the server how a route works. Build with client routes bundled to ship every route the client calls, or check that the app can load its own chunks.",originalError:error instanceof Error?error:void 0})}exports.loadMetadataFromServer=loadMetadataFromServer;exports.loadedMetadataFromServer=loadedMetadataFromServer;exports.resetMetadataFromServer=resetMetadataFromServer;
2
+
3
+ //# sourceMappingURL=metadataFromServerLoader.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadataFromServerLoader.cjs","names":[],"sources":["../../../../src/lib/metadataFromServerLoader.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 {RpcError} from '@mionjs/core';\n\n// Reaches the lane through `#metadata-from-server`, an @mionjs/client `imports` entry no consumer alias can collide with.\n\ntype MetadataFromServer = typeof import('./metadataFromServer.ts');\n\nlet laneModule: MetadataFromServer | undefined;\nlet loading: Promise<MetadataFromServer> | undefined;\n\n/** Awaited inside the request's own try, so a failed load reaches @thrownErrors; it is forgotten for a retry. */\nexport function loadMetadataFromServer(): Promise<MetadataFromServer> {\n if (laneModule) return Promise.resolve(laneModule);\n loading ??= (import('#metadata-from-server') as Promise<MetadataFromServer>)\n .then((loaded) => {\n laneModule = loaded;\n return loaded;\n })\n .catch((error) => {\n loading = undefined;\n throw laneLoadError(error);\n });\n return loading;\n}\n\n/** The lane if a call already loaded it, never loading it. */\nexport function loadedMetadataFromServer(): MetadataFromServer | undefined {\n return laneModule;\n}\n\n/** Forgets the loaded lane. Tests only: simulates a process that never reached it. */\nexport function resetMetadataFromServer(): void {\n laneModule = undefined;\n loading = undefined;\n}\n\nfunction laneLoadError(error: unknown): RpcError<'metadata-load-error'> {\n return new RpcError({\n type: 'metadata-load-error',\n publicMessage:\n 'Could not load the code that asks the server how a route works. Build with client routes bundled to ship every route the client calls, or check that the app can load its own chunks.',\n originalError: error instanceof Error ? error : undefined,\n });\n}\n"],"mappings":"60BAaA,IAAI,WACA,QAGJ,SAAgB,wBAAsD,CACpE,OAAI,WAAmB,QAAQ,QAAQ,UAAU,GACjD,UAAa,OAAO,uBAAA,EACjB,KAAM,SACL,WAAa,OACN,OACR,EACA,MAAO,OAAU,CAChB,cAAU,OACJ,cAAc,KAAK,CAC3B,CAAC,EACI,QACT,CAGA,SAAgB,0BAA2D,CACzE,OAAO,UACT,CAGA,SAAgB,yBAAgC,CAC9C,WAAa,OACb,QAAU,MACZ,CAEA,SAAS,cAAc,MAAiD,CACtE,OAAO,IAAI,aAAA,SAAS,CAClB,KAAM,sBACN,cACE,wLACF,cAAe,iBAAiB,MAAQ,MAAQ,MAClD,CAAC,CACH"}
@@ -0,0 +1,6 @@
1
+ type MetadataFromServer = typeof import('./metadataFromServer.ts');
2
+ export declare function loadMetadataFromServer(): Promise<MetadataFromServer>;
3
+ export declare function loadedMetadataFromServer(): MetadataFromServer | undefined;
4
+ export declare function resetMetadataFromServer(): void;
5
+ export {};
6
+ //# sourceMappingURL=metadataFromServerLoader.d.ts.map
@@ -0,0 +1,3 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const require_src_constants=require("../constants.cjs");var STORE_GLOBAL_KEY="__mion_metadata_store__",OBJECT_STORE="metadata",DB_VERSION=1,OPEN_TIMEOUT_MS=3e3,MemoryMetadataStore=class{kind="memory";records=new Map;async readAll(baseURL){const result=[];for(const record of this.records.values())record.baseURL===baseURL&&result.push(record);return result}async write(records){for(const record of records)this.records.set(recordMapKey(record.baseURL,record.kind,record.id),record)}async remove(baseURL,keys){for(const[kind,id]of keys)this.records.delete(recordMapKey(baseURL,kind,id))}async clear(baseURL){if(baseURL===void 0){this.records.clear();return}for(const[key,record]of this.records)record.baseURL===baseURL&&this.records.delete(key)}};function recordMapKey(baseURL,kind,id){return`${baseURL}\0${kind}\0${id}`}var IdbMetadataStore=class{db;kind="indexeddb";constructor(db){this.db=db}readAll(baseURL){return this.transact("readonly",store=>{const range=IDBKeyRange.bound([baseURL],[baseURL,[]],!1,!0);return store.getAll(range)})}write(records){return records.length?this.transact("readwrite",store=>{let last=store.put(records[0]);for(let i=1;i<records.length;i++)last=store.put(records[i]);return last}).then(()=>{}):Promise.resolve()}remove(baseURL,keys){return keys.length?this.transact("readwrite",store=>{let last=store.delete([baseURL,keys[0][0],keys[0][1]]);for(let i=1;i<keys.length;i++)last=store.delete([baseURL,keys[i][0],keys[i][1]]);return last}).then(()=>{}):Promise.resolve()}clear(baseURL){return this.transact("readwrite",store=>baseURL===void 0?store.clear():store.delete(IDBKeyRange.bound([baseURL],[baseURL,[]],!1,!0))).then(()=>{})}transact(mode,run){return new Promise((resolve,reject)=>{let transaction;try{transaction=this.db.transaction(OBJECT_STORE,mode)}catch(error){return reject(error)}let result;try{const request=run(transaction.objectStore(OBJECT_STORE));request.onsuccess=()=>result=request.result}catch(error){return transaction.abort(),reject(error)}transaction.oncomplete=()=>resolve(result),transaction.onabort=()=>reject(transaction.error??new Error("mion metadata cache transaction aborted")),transaction.onerror=()=>reject(transaction.error??new Error("mion metadata cache transaction failed"))})}};function openDatabase(){return typeof indexedDB>"u"?Promise.resolve(void 0):new Promise(resolve=>{let settled=!1;const settle=db=>{settled||(settled=!0,resolve(db))},timer=setTimeout(()=>settle(void 0),OPEN_TIMEOUT_MS),done=db=>{clearTimeout(timer),settle(db)};let request;try{request=indexedDB.open(require_src_constants.STORAGE_KEY,DB_VERSION)}catch{return clearTimeout(timer),settle(void 0)}request.onupgradeneeded=()=>{const db=request.result;db.objectStoreNames.contains(OBJECT_STORE)&&db.deleteObjectStore(OBJECT_STORE),db.createObjectStore(OBJECT_STORE,{keyPath:["baseURL","kind","id"]})},request.onsuccess=()=>{const db=request.result;db.onversionchange=()=>db.close(),done(db)},request.onerror=()=>done(void 0),request.onblocked=()=>done(void 0)})}async function openEngine(engine){if(engine==="memory")return new MemoryMetadataStore;if(engine==="indexeddb"){const db=await openDatabase();return db?new IdbMetadataStore(db):new MemoryMetadataStore}return await engine()??new MemoryMetadataStore}function getRegistry(){let registry=globalThis[STORE_GLOBAL_KEY];return registry||(registry={byEngine:new Map},globalThis[STORE_GLOBAL_KEY]=registry),registry}function getMetadataStore(engine=require_src_constants.DEFAULT_STORAGE_ENGINE){const registry=getRegistry();if(registry.override)return registry.override;const existing=registry.byEngine.get(engine);if(existing)return existing;const pending=openEngine(engine).catch(()=>new MemoryMetadataStore);return registry.byEngine.set(engine,pending),pending}function setMetadataStoreForTesting(store){getRegistry().override=Promise.resolve(store)}async function resetMetadataStore(){const registry=globalThis[STORE_GLOBAL_KEY];if(delete globalThis[STORE_GLOBAL_KEY],!registry)return;const pending=[registry.override,...registry.byEngine.values()].filter(entry=>entry!==void 0);for(const entry of pending)await(await entry.catch(()=>{}))?.clear().catch(()=>{})}exports.IdbMetadataStore=IdbMetadataStore;exports.MemoryMetadataStore=MemoryMetadataStore;exports.getMetadataStore=getMetadataStore;exports.resetMetadataStore=resetMetadataStore;exports.setMetadataStoreForTesting=setMetadataStoreForTesting;
2
+
3
+ //# sourceMappingURL=metadataStore.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadataStore.cjs","names":[],"sources":["../../../../src/lib/metadataStore.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\n// The engines mion ships, and the one place an engine is chosen. The contract they implement, and\n// that an app's own engine implements, is in storage.ts.\n\nimport {DEFAULT_STORAGE_ENGINE, STORAGE_KEY} from '../constants.ts';\nimport type {MetadataKind, MetadataRecord, MetadataRecordKey, MetadataStore, StorageEngine} from './storage.ts';\n\nconst STORE_GLOBAL_KEY = '__mion_metadata_store__';\nconst OBJECT_STORE = 'metadata';\nconst DB_VERSION = 1;\n/** A store that never answers (private mode has historically hung on open) must not hang the client */\nconst OPEN_TIMEOUT_MS = 3000;\n\n/** In-memory store for SSR, Node, and any browser where IndexedDB is missing or blocked. */\nexport class MemoryMetadataStore implements MetadataStore {\n readonly kind = 'memory' as const;\n private readonly records = new Map<string, MetadataRecord>();\n\n async readAll(baseURL: string): Promise<MetadataRecord[]> {\n const result: MetadataRecord[] = [];\n for (const record of this.records.values()) if (record.baseURL === baseURL) result.push(record);\n return result;\n }\n\n async write(records: MetadataRecord[]): Promise<void> {\n for (const record of records) this.records.set(recordMapKey(record.baseURL, record.kind, record.id), record);\n }\n\n async remove(baseURL: string, keys: MetadataRecordKey[]): Promise<void> {\n for (const [kind, id] of keys) this.records.delete(recordMapKey(baseURL, kind, id));\n }\n\n async clear(baseURL?: string): Promise<void> {\n if (baseURL === undefined) {\n this.records.clear();\n return;\n }\n for (const [key, record] of this.records) if (record.baseURL === baseURL) this.records.delete(key);\n }\n}\n\nfunction recordMapKey(baseURL: string, kind: MetadataKind, id: string): string {\n // \\u0000 as the escape, never a raw NUL byte: a source file carrying one is a repo contract break\n return `${baseURL}\\u0000${kind}\\u0000${id}`;\n}\n\n/** IndexedDB store: one object store keyed by the compound `[baseURL, kind, id]`, so every entry of\n * one server sits in one contiguous key range and a cold load is a single `getAll` over it. */\nexport class IdbMetadataStore implements MetadataStore {\n readonly kind = 'indexeddb' as const;\n constructor(private readonly db: IDBDatabase) {}\n\n readAll(baseURL: string): Promise<MetadataRecord[]> {\n return this.transact('readonly', (store) => {\n // IndexedDB orders keys by type and an array sorts after every string, so `[baseURL, []]` is a\n // valid open upper bound: strictly greater than every `[baseURL, kind, id]` and less than the\n // next baseURL. That is what keeps this ONE request instead of a cursor walk or a full scan.\n const range = IDBKeyRange.bound([baseURL], [baseURL, []], false, true);\n return store.getAll(range) as IDBRequest<MetadataRecord[]>;\n });\n }\n\n write(records: MetadataRecord[]): Promise<void> {\n if (!records.length) return Promise.resolve();\n return this.transact('readwrite', (store) => {\n let last: IDBRequest = store.put(records[0]);\n for (let i = 1; i < records.length; i++) last = store.put(records[i]);\n return last;\n }).then(() => undefined);\n }\n\n remove(baseURL: string, keys: MetadataRecordKey[]): Promise<void> {\n if (!keys.length) return Promise.resolve();\n return this.transact('readwrite', (store) => {\n let last: IDBRequest = store.delete([baseURL, keys[0][0], keys[0][1]]);\n for (let i = 1; i < keys.length; i++) last = store.delete([baseURL, keys[i][0], keys[i][1]]);\n return last;\n }).then(() => undefined);\n }\n\n clear(baseURL?: string): Promise<void> {\n return this.transact('readwrite', (store) => {\n if (baseURL === undefined) return store.clear();\n return store.delete(IDBKeyRange.bound([baseURL], [baseURL, []], false, true));\n }).then(() => undefined);\n }\n\n /** Resolves on transaction COMPLETE, not on request success: a put that succeeded inside a\n * transaction the browser then aborts (quota) must reject, or a caller would count it as stored. */\n private transact<T>(mode: IDBTransactionMode, run: (store: IDBObjectStore) => IDBRequest<T>): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n let transaction: IDBTransaction;\n try {\n transaction = this.db.transaction(OBJECT_STORE, mode);\n } catch (error) {\n return reject(error);\n }\n let result: T;\n try {\n const request = run(transaction.objectStore(OBJECT_STORE));\n request.onsuccess = () => (result = request.result);\n } catch (error) {\n transaction.abort();\n return reject(error);\n }\n transaction.oncomplete = () => resolve(result);\n transaction.onabort = () => reject(transaction.error ?? new Error('mion metadata cache transaction aborted'));\n transaction.onerror = () => reject(transaction.error ?? new Error('mion metadata cache transaction failed'));\n });\n }\n}\n\n/** Opens the database, or resolves undefined for every reason a browser can refuse one. */\nfunction openDatabase(): Promise<IDBDatabase | undefined> {\n if (typeof indexedDB === 'undefined') return Promise.resolve(undefined);\n return new Promise<IDBDatabase | undefined>((resolve) => {\n let settled = false;\n const settle = (db?: IDBDatabase) => {\n if (settled) return;\n settled = true;\n resolve(db);\n };\n // an open that never answers falls back rather than hanging the first call behind it\n const timer = setTimeout(() => settle(undefined), OPEN_TIMEOUT_MS);\n const done = (db?: IDBDatabase) => {\n clearTimeout(timer);\n settle(db);\n };\n let request: IDBOpenDBRequest;\n try {\n request = indexedDB.open(STORAGE_KEY, DB_VERSION);\n } catch {\n clearTimeout(timer);\n return settle(undefined);\n }\n request.onupgradeneeded = () => {\n const db = request.result;\n // the cache holds nothing that is not refetchable, so a schema bump is the invalidation lever\n if (db.objectStoreNames.contains(OBJECT_STORE)) db.deleteObjectStore(OBJECT_STORE);\n db.createObjectStore(OBJECT_STORE, {keyPath: ['baseURL', 'kind', 'id']});\n };\n request.onsuccess = () => {\n const db = request.result;\n // another tab upgrading must not deadlock this one: close and let the next call fall back\n db.onversionchange = () => db.close();\n done(db);\n };\n request.onerror = () => done(undefined);\n request.onblocked = () => done(undefined);\n });\n}\n\n/** Opens one engine. Anything it cannot give us here is a cache miss, never a failed call, so every\n * refusal lands on the same fallback: keep the cache in memory for the life of the process. */\nasync function openEngine(engine: StorageEngine): Promise<MetadataStore> {\n if (engine === 'memory') return new MemoryMetadataStore();\n if (engine === 'indexeddb') {\n const db = await openDatabase();\n return db ? new IdbMetadataStore(db) : new MemoryMetadataStore();\n }\n // an app's own engine\n return (await engine()) ?? new MemoryMetadataStore();\n}\n\n/** One resolved store per engine, plus a stand-in that wins over all of them while testing.\n * Memoized on globalThis so every module instance shares one connection. */\ninterface StoreRegistry {\n override?: Promise<MetadataStore>;\n byEngine: Map<StorageEngine, Promise<MetadataStore>>;\n}\n\nfunction getRegistry(): StoreRegistry {\n let registry = (globalThis as any)[STORE_GLOBAL_KEY] as StoreRegistry | undefined;\n if (!registry) {\n registry = {byEngine: new Map()};\n (globalThis as any)[STORE_GLOBAL_KEY] = registry;\n }\n return registry;\n}\n\n/** Returns the store for one engine, opening it on first use. */\nexport function getMetadataStore(engine: StorageEngine = DEFAULT_STORAGE_ENGINE): Promise<MetadataStore> {\n const registry = getRegistry();\n if (registry.override) return registry.override;\n const existing = registry.byEngine.get(engine);\n if (existing) return existing;\n const pending = openEngine(engine).catch(() => new MemoryMetadataStore());\n registry.byEngine.set(engine, pending);\n return pending;\n}\n\n/** Puts a stand-in behind every engine. Only for testing — the browser's own limits (a full disk, a\n * refused write) cannot be produced any other way. */\nexport function setMetadataStoreForTesting(store: MetadataStore): void {\n getRegistry().override = Promise.resolve(store);\n}\n\n/** Drops every store instance and everything they hold. Only for testing — simulates a new page. */\nexport async function resetMetadataStore(): Promise<void> {\n const registry = (globalThis as any)[STORE_GLOBAL_KEY] as StoreRegistry | undefined;\n delete (globalThis as any)[STORE_GLOBAL_KEY];\n if (!registry) return;\n const pending = [registry.override, ...registry.byEngine.values()].filter((entry) => entry !== undefined);\n for (const entry of pending) {\n const store = await entry.catch(() => undefined);\n await store?.clear().catch(() => undefined);\n }\n}\n"],"mappings":"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"}