@mionjs/client 0.8.10 → 0.13.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -0,0 +1,52 @@
1
+ import { isBundledMethod, resetBundledMethods, setBundledMethod } from "./methods.js";
2
+ import { HandlerType, RpcError, getHeadersReflectionFromMarkers, getReflectionFromMarkers } from "@mionjs/core";
3
+ var pendingPayloadError;
4
+ function registerBundledApi(payload) {
5
+ if (!isBundledApiPayload(payload)) {
6
+ pendingPayloadError = new RpcError({
7
+ type: "bundle-api-invalid-payload",
8
+ publicMessage: "The bundled API metadata injected at this call is not what the build writes; rebuild with a matching @mionjs/devtools."
9
+ }), console.error("[mion] bundled API payload rejected at a dispatch point; rebuild with a matching @mionjs/devtools");
10
+ return;
11
+ }
12
+ for (const method of payload.methods)
13
+ isBundledMethod(method.id) || setBundledMethod(method.id, bundledMethodToCacheEntry(method));
14
+ }
15
+ function takeBundledApiError() {
16
+ const error = pendingPayloadError;
17
+ return pendingPayloadError = void 0, error;
18
+ }
19
+ function resetBundledApi() {
20
+ resetBundledMethods(), pendingPayloadError = void 0;
21
+ }
22
+ function isBundledApiPayload(value) {
23
+ if (typeof value != "object" || value === null) return !1;
24
+ const methods = value.methods;
25
+ return Array.isArray(methods) && methods.every(isBundledMethodRow);
26
+ }
27
+ function isBundledMethodRow(value) {
28
+ if (typeof value != "object" || value === null) return !1;
29
+ const method = value;
30
+ return typeof method.id == "string" && typeof method.type == "number" && typeof method.nestLevel == "number" && typeof method.isAsync == "boolean" && Array.isArray(method.pointer) && typeof method.options == "object" && method.options !== null && typeof method.rtFns == "object" && method.rtFns !== null;
31
+ }
32
+ var noHandler = () => {
33
+ };
34
+ function bundledMethodToCacheEntry(method) {
35
+ const entry = {
36
+ ...method.type === HandlerType.headersMiddleware ? getHeadersReflectionFromMarkers(method.rtFns, noHandler, method.id) : getReflectionFromMarkers(method.rtFns, noHandler, method.id),
37
+ type: method.type,
38
+ id: method.id,
39
+ pointer: method.pointer,
40
+ nestLevel: method.nestLevel,
41
+ isAsync: method.isAsync,
42
+ options: method.options
43
+ };
44
+ return delete entry.paramsJsonMaxBytes, method.middlewareIds && method.middlewareIds.length && (entry.middlewareIds = method.middlewareIds), entry;
45
+ }
46
+ export {
47
+ registerBundledApi,
48
+ resetBundledApi,
49
+ takeBundledApiError
50
+ };
51
+
52
+ //# sourceMappingURL=bundledApi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundledApi.js","names":[],"sources":["../../../../src/lib/bundledApi.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 {\n HandlerType,\n RpcError,\n getHeadersReflectionFromMarkers,\n getReflectionFromMarkers,\n type MethodWithOptions,\n type MethodWithOptsAndJitFns,\n type RtMarkerPayload,\n} from '@mionjs/core';\nimport type {InjectedApiMetadata} from '../types.ts';\nimport {isBundledMethod, resetBundledMethods, setBundledMethod} from './methods.ts';\n\n// With bundled routes the build injects, at each dispatch point, the route and its middlewares with the server's\n// compiled functions. Registering one runs the router's initRoutes reflection, so it looks exactly like a fetched one.\n\n/** One method of a bundled payload: the `MethodWithOptions` members the build can answer from the API type,\n * plus the marker payload. The rest (jit hashes, arity, header names) comes from the reflection instead. */\nexport interface BundledMethod extends Pick<\n MethodWithOptions,\n 'id' | 'pointer' | 'nestLevel' | 'type' | 'isAsync' | 'options' | 'middlewareIds'\n> {\n rtFns: RtMarkerPayload;\n}\n\n/** What the build injects at a dispatch point: the method called plus every middleware in its chain. */\nexport interface BundledApiPayload {\n methods: BundledMethod[];\n}\n\n/** A payload the build did not write, held until a call can report it once. */\nlet pendingPayloadError: RpcError<string> | undefined;\n\n/** Registers a bundled payload, once per method id; a dispatch point passes the same module on every call.\n * The guard runs despite the declared type because a `<genDir>/api/` tree from another @mionjs/devtools\n * version can disagree; a payload it did not write is recorded, never thrown, since `call()` never throws. */\nexport function registerBundledApi(payload: InjectedApiMetadata): void {\n if (!isBundledApiPayload(payload)) {\n pendingPayloadError = new RpcError({\n type: 'bundle-api-invalid-payload',\n publicMessage:\n 'The bundled API metadata injected at this call is not what the build writes; rebuild with a matching @mionjs/devtools.',\n });\n console.error('[mion] bundled API payload rejected at a dispatch point; rebuild with a matching @mionjs/devtools');\n return;\n }\n for (const method of payload.methods) {\n if (isBundledMethod(method.id)) continue;\n setBundledMethod(method.id, bundledMethodToCacheEntry(method));\n }\n}\n\n/** Takes the last rejected payload, if any, so a call can report it once. */\nexport function takeBundledApiError(): RpcError<string> | undefined {\n const error = pendingPayloadError;\n pendingPayloadError = undefined;\n return error;\n}\n\n/** Forgets which ids came from a bundle. Tests only. */\nexport function resetBundledApi(): void {\n resetBundledMethods();\n pendingPayloadError = undefined;\n // the bundled flag stays: the build's module sets it once at import, and a cache reset cannot change the build\n}\n\nfunction isBundledApiPayload(value: unknown): value is BundledApiPayload {\n if (typeof value !== 'object' || value === null) return false;\n const methods = (value as BundledApiPayload).methods;\n return Array.isArray(methods) && methods.every(isBundledMethodRow);\n}\n\n/** Every member the cache entry reads, so a stale module fails the guard instead of a later access. */\nfunction isBundledMethodRow(value: unknown): value is BundledMethod {\n if (typeof value !== 'object' || value === null) return false;\n const method = value as BundledMethod;\n return (\n typeof method.id === 'string' &&\n typeof method.type === 'number' &&\n typeof method.nestLevel === 'number' &&\n typeof method.isAsync === 'boolean' &&\n Array.isArray(method.pointer) &&\n typeof method.options === 'object' &&\n method.options !== null &&\n typeof method.rtFns === 'object' &&\n method.rtFns !== null\n );\n}\n\n/** A bundled method never carries a handler; the reflection reads everything off the marker payload\n * and the row, so the placeholder is never called. */\nconst noHandler = () => undefined;\n\nfunction bundledMethodToCacheEntry(method: BundledMethod): MethodWithOptsAndJitFns {\n const reflection =\n method.type === HandlerType.headersMiddleware\n ? getHeadersReflectionFromMarkers(method.rtFns, noHandler, method.id)\n : getReflectionFromMarkers(method.rtFns, noHandler, method.id);\n // spread, like `registerRoutes` does on the server, so a member added to the reflection reaches\n // a bundled method too; only the row's own answers are written over it\n const entry: MethodWithOptsAndJitFns = {\n ...reflection,\n type: method.type,\n id: method.id,\n pointer: method.pointer,\n nestLevel: method.nestLevel,\n // the build answered this off the server handler's declared return; the placeholder above cannot\n isAsync: method.isAsync,\n // `options.maxBodySize` is the route's own declared limit or nothing: the number the server\n // settles for a chain that declares none (its types times the router factor, else the platform\n // adapter's) is only known at the server's registration, and the client never enforces it\n options: method.options,\n };\n // the params byte ceiling is the SERVER's: it settles a chain's request limit once at\n // registration. The client enforces no limit, and the fetched lane is never sent it either\n delete entry.paramsJsonMaxBytes;\n if (method.middlewareIds && method.middlewareIds.length) entry.middlewareIds = method.middlewareIds;\n return entry;\n}\n"],"mappings":";;AAqCA,IAAI;AAKJ,SAAgB,mBAAmB,SAAoC;AACrE,MAAI,CAAC,oBAAoB,OAAO,GAAG;AACjC,0BAAsB,IAAI,SAAS;AAAA,MACjC,MAAM;AAAA,MACN,eACE;AAAA,IACJ,CAAC,GACD,QAAQ,MAAM,mGAAmG;AACjH;AAAA,EACF;AACA,aAAW,UAAU,QAAQ;AAC3B,IAAI,gBAAgB,OAAO,EAAE,KAC7B,iBAAiB,OAAO,IAAI,0BAA0B,MAAM,CAAC;AAEjE;AAGA,SAAgB,sBAAoD;AAClE,QAAM,QAAQ;AACd,+BAAsB,QACf;AACT;AAGA,SAAgB,kBAAwB;AACtC,sBAAoB,GACpB,sBAAsB;AAExB;AAEA,SAAS,oBAAoB,OAA4C;AACvE,MAAI,OAAO,SAAU,YAAY,UAAU,KAAM,QAAO;AACxD,QAAM,UAAW,MAA4B;AAC7C,SAAO,MAAM,QAAQ,OAAO,KAAK,QAAQ,MAAM,kBAAkB;AACnE;AAGA,SAAS,mBAAmB,OAAwC;AAClE,MAAI,OAAO,SAAU,YAAY,UAAU,KAAM,QAAO;AACxD,QAAM,SAAS;AACf,SACE,OAAO,OAAO,MAAO,YACrB,OAAO,OAAO,QAAS,YACvB,OAAO,OAAO,aAAc,YAC5B,OAAO,OAAO,WAAY,aAC1B,MAAM,QAAQ,OAAO,OAAO,KAC5B,OAAO,OAAO,WAAY,YAC1B,OAAO,YAAY,QACnB,OAAO,OAAO,SAAU,YACxB,OAAO,UAAU;AAErB;AAIA,IAAM,YAAA,MAAA;AAAA;AAEN,SAAS,0BAA0B,QAAgD;AAOjF,QAAM,QAAiC;AAAA,IACrC,GANA,OAAO,SAAS,YAAY,oBACxB,gCAAgC,OAAO,OAAO,WAAW,OAAO,EAAE,IAClE,yBAAyB,OAAO,OAAO,WAAW,OAAO,EAAE;AAAA,IAK/D,MAAM,OAAO;AAAA,IACb,IAAI,OAAO;AAAA,IACX,SAAS,OAAO;AAAA,IAChB,WAAW,OAAO;AAAA,IAElB,SAAS,OAAO;AAAA,IAIhB,SAAS,OAAO;AAAA,EAClB;AAGA,gBAAO,MAAM,oBACT,OAAO,iBAAiB,OAAO,cAAc,WAAQ,MAAM,gBAAgB,OAAO,gBAC/E;AACT"}
@@ -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
@@ -1,125 +1,281 @@
1
- import { MION_ROUTES, isRpcError, addSerializedJitCaches, routesCache, addRoutesToCache } from "@mionjs/core";
2
- import { STORAGE_KEY } from "../constants.js";
3
- import { getStorage } from "./storage.js";
4
- const METHOD_DATA_PREFIX = `${STORAGE_KEY}:method-data:`, JIT_FN_PREFIX = `${STORAGE_KEY}:jit-fn:`, PURE_FN_PREFIX = `${STORAGE_KEY}:pure-fn:`;
5
- function extractAndProcessMetadata(routeKey, parsedBody, options) {
6
- if (typeof parsedBody != "object" || !(routeKey in parsedBody))
7
- return;
8
- const rawMetadata = parsedBody[routeKey];
9
- if (delete parsedBody[routeKey], !rawMetadata)
10
- return;
11
- const metadataValue = Array.isArray(rawMetadata) ? rawMetadata[1] : rawMetadata;
12
- metadataValue && !isRpcError(metadataValue) && metadataValue.methods && processMethodsMetadata(metadataValue, options);
1
+ import { METADATA_CACHE_MAX_BYTES } from "../constants.js";
2
+ import { getMetadataStore } from "./metadataStore.js";
3
+ import { requestPersistenceWhenSilent } from "./persistentStorage.js";
4
+ import { isBundledMethod, setFetchedMethods } from "./methods.js";
5
+ import { findOrphans } from "./metadataEviction.js";
6
+ import { RpcError, addRoutesToCache, addSerializedJitCaches, hasJitFnsForMethod, isUnsafePropertyName, routesCache } from "@mionjs/core";
7
+ var states = /* @__PURE__ */ new Map(), writeQueue = [], flushHandle, flushChain = Promise.resolve(), persistenceAsked = !1, pendingCacheError;
8
+ function getState(options) {
9
+ const baseURL = options.baseURL;
10
+ let state = states.get(baseURL);
11
+ return state || (state = {
12
+ baseURL,
13
+ storageEngine: options.storageEngine,
14
+ hydratedIds: /* @__PURE__ */ new Set(),
15
+ stored: /* @__PURE__ */ new Map(),
16
+ bytes: 0,
17
+ graph: {
18
+ methods: /* @__PURE__ */ Object.create(null),
19
+ deps: /* @__PURE__ */ Object.create(null),
20
+ pureFns: /* @__PURE__ */ Object.create(null)
21
+ },
22
+ sweepScheduled: !1
23
+ }, states.set(baseURL, state)), state;
24
+ }
25
+ function storedKey(kind, id) {
26
+ return `${kind} ${id}`;
13
27
  }
14
28
  function processMethodsMetadata(serializableMethodsData, options) {
15
- storeDependencies(serializableMethodsData.deps, serializableMethodsData.purFnDeps, options), storeMethodsMetadata(serializableMethodsData.methods, options), addToCaches(serializableMethodsData);
29
+ addToCaches(serializableMethodsData), queuePersist(serializableMethodsData, options);
16
30
  }
17
- function getSerializedMethodDataKey(methodId, options) {
18
- return `${METHOD_DATA_PREFIX}${methodId}:${options.baseURL}`;
31
+ function isStorableName(name) {
32
+ return !isUnsafePropertyName(name) && !name.includes(":");
19
33
  }
20
- function getJitCompiledFnKey(jitFnHash, options) {
21
- return `${JIT_FN_PREFIX}${jitFnHash}:${options.baseURL}`;
34
+ function queuePersist(data, options) {
35
+ writeQueue.push({
36
+ data,
37
+ options
38
+ }), scheduleFlush();
22
39
  }
23
- function getJitPureFnKey(namespace, pureFnHash, options) {
24
- return `${PURE_FN_PREFIX}${namespace}:${pureFnHash}:${options.baseURL}`;
40
+ function scheduleFlush() {
41
+ if (flushHandle !== void 0) return;
42
+ const run = () => {
43
+ flushHandle = void 0, flushChain = flushChain.then(flushQueue);
44
+ }, idle = globalThis.requestIdleCallback;
45
+ flushHandle = typeof idle == "function" ? idle(run, { timeout: 200 }) : setTimeout(run, 0);
25
46
  }
26
- function storeDependencies(deps, pureFnDeps, options) {
27
- Object.entries(deps).forEach(([hash, jitFnData]) => {
28
- const key = getJitCompiledFnKey(hash, options);
29
- try {
30
- getStorage().setItem(key, JSON.stringify(jitFnData));
31
- } catch (error) {
32
- console.warn(`Failed to store JIT function dependency ${hash}:`, error);
33
- }
34
- }), Object.entries(pureFnDeps).forEach(([namespace, nsPureFns]) => {
35
- Object.entries(nsPureFns).forEach(([fnHash, pureFnData]) => {
36
- const key = getJitPureFnKey(namespace, fnHash, options);
47
+ function flushMetadataCache() {
48
+ if (flushHandle !== void 0) {
49
+ const cancelIdle = globalThis.cancelIdleCallback;
50
+ typeof cancelIdle == "function" ? cancelIdle(flushHandle) : clearTimeout(flushHandle), flushHandle = void 0;
51
+ }
52
+ return flushChain = flushChain.then(flushQueue), flushChain;
53
+ }
54
+ async function flushQueue() {
55
+ if (!writeQueue.length) return;
56
+ const batch = writeQueue;
57
+ writeQueue = [];
58
+ const byBaseURL = /* @__PURE__ */ new Map();
59
+ for (const item of batch) {
60
+ const group = byBaseURL.get(item.options.baseURL);
61
+ group ? group.payloads.push(item.data) : byBaseURL.set(item.options.baseURL, {
62
+ options: item.options,
63
+ payloads: [item.data]
64
+ });
65
+ }
66
+ for (const group of byBaseURL.values()) await persistPayloads(group.options, group.payloads);
67
+ }
68
+ async function persistPayloads(options, payloads) {
69
+ const baseURL = options.baseURL, state = getState(options), ts = Date.now(), records = /* @__PURE__ */ new Map(), add = (kind, id, value) => {
70
+ const key = storedKey(kind, id);
71
+ if (!(kind !== "m" && state.stored.has(key)))
37
72
  try {
38
- getStorage().setItem(key, JSON.stringify(pureFnData));
73
+ records.set(key, {
74
+ baseURL,
75
+ kind,
76
+ id,
77
+ json: JSON.stringify(value),
78
+ ts
79
+ });
39
80
  } catch (error) {
40
- console.warn(`Failed to store pure function dependency ${namespace}::${fnHash}:`, error);
81
+ console.warn(`Failed to serialize metadata cache entry ${id}:`, error);
41
82
  }
42
- });
83
+ };
84
+ for (const payload of payloads) {
85
+ for (const [hash, jitFnData] of Object.entries(payload.deps ?? {})) {
86
+ if (!isStorableName(hash)) {
87
+ console.warn(`Refused to store JIT function dependency under '${hash}'`);
88
+ continue;
89
+ }
90
+ add("j", hash, jitFnData);
91
+ }
92
+ for (const [id, pureFnData] of Object.entries(payload.purFnDeps ?? {})) {
93
+ if (!isStorableName(id)) {
94
+ console.warn(`Refused to store pure function '${id}'`);
95
+ continue;
96
+ }
97
+ add("p", id, pureFnData);
98
+ }
99
+ for (const [methodId, methodData] of Object.entries(payload.methods ?? {})) {
100
+ if (!isStorableName(methodId)) {
101
+ console.warn(`Refused to store metadata for method '${methodId}'`);
102
+ continue;
103
+ }
104
+ isBundledMethod(methodId) || add("m", methodId, methodData);
105
+ }
106
+ }
107
+ records.size && await writeRecords(state, [...records.values()]);
108
+ }
109
+ function recordBytes(record) {
110
+ return record.json.length + record.id.length;
111
+ }
112
+ async function writeRecords(state, records) {
113
+ const store = await getMetadataStore(state.storageEngine), incoming = records.reduce((total, record) => total + recordBytes(record), 0);
114
+ await evictOldest(state, store, state.bytes + incoming - METADATA_CACHE_MAX_BYTES);
115
+ for (let round = 0; ; round++) try {
116
+ await store.write(records);
117
+ for (const record of records) {
118
+ const key = storedKey(record.kind, record.id), previous = state.stored.get(key);
119
+ previous && (state.bytes -= previous.bytes);
120
+ const bytes = recordBytes(record);
121
+ state.stored.set(key, {
122
+ kind: record.kind,
123
+ id: record.id,
124
+ ts: record.ts,
125
+ bytes
126
+ }), state.bytes += bytes;
127
+ }
128
+ askForPersistenceOnce();
129
+ return;
130
+ } catch (error) {
131
+ if (round >= 5 || !await evictOldest(state, store, Math.max(state.bytes / 4, incoming))) return reportCacheError(error);
132
+ }
133
+ }
134
+ async function evictOldest(state, store, targetBytes) {
135
+ if (targetBytes <= 0 || !state.stored.size) return 0;
136
+ const oldestFirst = [...state.stored.values()].sort((a, b) => a.ts - b.ts), keys = [];
137
+ let freed = 0;
138
+ for (const entry of oldestFirst)
139
+ if (keys.push([entry.kind, entry.id]), freed += entry.bytes, freed >= targetBytes) break;
140
+ try {
141
+ await store.remove(state.baseURL, keys);
142
+ } catch {
143
+ return 0;
144
+ }
145
+ for (const [kind, id] of keys) {
146
+ const key = storedKey(kind, id);
147
+ 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];
148
+ }
149
+ return freed;
150
+ }
151
+ function reportCacheError(error) {
152
+ const rpcError = new RpcError({
153
+ type: "metadata-cache-error",
154
+ publicMessage: "Could not store the remote method metadata cache",
155
+ originalError: error instanceof Error ? error : void 0
43
156
  });
157
+ console.error("[mion] metadata cache write failed:", error), pendingCacheError = rpcError;
158
+ }
159
+ function takeMetadataCacheError() {
160
+ const error = pendingCacheError;
161
+ return pendingCacheError = void 0, error;
162
+ }
163
+ function askForPersistenceOnce() {
164
+ persistenceAsked || (persistenceAsked = !0, requestPersistenceWhenSilent());
165
+ }
166
+ function hydrateMetadataCache(options) {
167
+ const state = getState(options);
168
+ return state.hydration || (state.hydration = hydrate(state).catch((error) => {
169
+ console.warn("Failed to restore the remote method metadata cache:", error);
170
+ })), state.hydration;
44
171
  }
45
- function storeMethodsMetadata(methods, options) {
46
- Object.entries(methods).forEach(([methodId, methodData]) => {
47
- const key = getSerializedMethodDataKey(methodId, options);
172
+ async function hydrate(state) {
173
+ const records = await (await getMetadataStore(state.storageEngine)).readAll(state.baseURL);
174
+ if (!records.length) return;
175
+ const deps = /* @__PURE__ */ Object.create(null), pureFnDeps = /* @__PURE__ */ Object.create(null), methods = /* @__PURE__ */ Object.create(null);
176
+ for (const record of records) {
177
+ if (!isStorableName(record.id)) continue;
178
+ let parsed;
48
179
  try {
49
- getStorage().setItem(key, JSON.stringify(methodData));
180
+ parsed = JSON.parse(record.json);
50
181
  } catch (error) {
51
- console.warn(`Failed to store method metadata ${methodId}:`, error);
182
+ console.warn(`Failed to restore metadata cache entry ${record.id}:`, error);
183
+ continue;
52
184
  }
53
- });
54
- }
55
- function restoreAllDependencies(options) {
56
- const deps = {}, pureFnDeps = {}, baseURLSuffix = `:${options.baseURL}`;
57
- for (let i = 0; i < getStorage().length; i++) {
58
- const key = getStorage().key(i);
59
- if (key?.startsWith(JIT_FN_PREFIX) && key.endsWith(baseURLSuffix))
60
- try {
61
- const data = getStorage().getItem(key);
62
- if (data) {
63
- const parsedData = JSON.parse(data);
64
- deps[parsedData.jitFnHash] = parsedData;
65
- }
66
- } catch (error) {
67
- console.warn(`Failed to restore JIT function from key ${key}:`, error);
185
+ const key = storedKey(record.kind, record.id);
186
+ if (state.stored.set(key, {
187
+ kind: record.kind,
188
+ id: record.id,
189
+ ts: record.ts,
190
+ bytes: recordBytes(record)
191
+ }), state.bytes += recordBytes(record), record.kind === "j")
192
+ deps[record.id] = parsed, state.graph.deps[record.id] = parsed;
193
+ else if (record.kind === "p") {
194
+ if (typeof parsed?.code != "string") {
195
+ console.warn(`Ignoring cached pure function ${record.id}: it carries no code`);
196
+ continue;
68
197
  }
198
+ pureFnDeps[record.id] = parsed, state.graph.pureFns[record.id] = parsed;
199
+ } else
200
+ methods[record.id] = parsed, state.graph.methods[record.id] = parsed;
69
201
  }
70
- for (let i = 0; i < getStorage().length; i++) {
71
- const key = getStorage().key(i);
72
- if (key?.startsWith(PURE_FN_PREFIX) && key.endsWith(baseURLSuffix))
73
- try {
74
- const data = getStorage().getItem(key);
75
- if (data) {
76
- const parsedData = JSON.parse(data), namespace = key.slice(PURE_FN_PREFIX.length, key.length - baseURLSuffix.length).split(":")[0] || parsedData.namespace;
77
- pureFnDeps[namespace] || (pureFnDeps[namespace] = {}), pureFnDeps[namespace][parsedData.fnName] = parsedData;
78
- }
79
- } catch (error) {
80
- console.warn(`Failed to restore pure function from key ${key}:`, error);
81
- }
202
+ addSerializedJitCaches(deps, pureFnDeps);
203
+ const restorable = {}, unusable = [];
204
+ for (const [id, metadata] of Object.entries(methods)) hasJitFnsForMethod(metadata) ? (restorable[id] = metadata, state.hydratedIds.add(id)) : (unusable.push(["m", id]), delete state.graph.methods[id]);
205
+ addRoutesToCache(restorable), scheduleSweep(state, unusable);
206
+ }
207
+ function wasHydratedFromCache(id, options) {
208
+ return states.get(options.baseURL)?.hydratedIds.has(id) === !0;
209
+ }
210
+ async function purgeHydratedMetadata(ids, options) {
211
+ const state = states.get(options.baseURL);
212
+ if (!state) return;
213
+ const hydrated = ids.filter((id) => state.hydratedIds.has(id));
214
+ for (const id of hydrated) routesCache.removeMetadata(id);
215
+ await dropStoredMethods(state, hydrated);
216
+ }
217
+ async function forgetFetchedMetadata(ids, options) {
218
+ const fetchedIds = ids.filter((id) => !isBundledMethod(id));
219
+ for (const id of fetchedIds) routesCache.removeMetadata(id);
220
+ for (const queued of writeQueue)
221
+ if (queued.options.baseURL === options.baseURL)
222
+ for (const id of fetchedIds) delete queued.data.methods[id];
223
+ const state = states.get(options.baseURL);
224
+ state && await dropStoredMethods(state, fetchedIds);
225
+ }
226
+ async function dropStoredMethods(state, ids) {
227
+ const keys = [];
228
+ for (const id of ids)
229
+ state.hydratedIds.delete(id), delete state.graph.methods[id], keys.push(["m", id]);
230
+ if (keys.length) {
231
+ await (await getMetadataStore(state.storageEngine)).remove(state.baseURL, keys).catch(() => {
232
+ });
233
+ for (const [kind, id] of keys) {
234
+ const key = storedKey(kind, id);
235
+ state.bytes -= state.stored.get(key)?.bytes ?? 0, state.stored.delete(key);
236
+ }
237
+ await sweepOrphans(state);
82
238
  }
83
- (Object.keys(deps).length > 0 || Object.keys(pureFnDeps).length > 0) && addSerializedJitCaches(deps, pureFnDeps);
84
- }
85
- function createMetadataSubRequest(methodIds) {
86
- return {
87
- pointer: [MION_ROUTES.methodsMetadata],
88
- id: MION_ROUTES.methodsMetadata,
89
- isResolved: !1,
90
- params: [methodIds]
91
- };
92
239
  }
93
- function restoreFromLocalStorage(methodIds, options) {
94
- restoreAllDependencies(options);
95
- const methods = {};
96
- let anyMethodsRestored = !1;
97
- methodIds.forEach((id) => {
98
- if (routesCache.hasMetadata(id))
99
- return;
100
- const methodKey = getSerializedMethodDataKey(id, options), methodMetaJson = getStorage().getItem(methodKey);
101
- if (methodMetaJson)
102
- try {
103
- const methodMeta = JSON.parse(methodMetaJson);
104
- methods[id] = methodMeta, anyMethodsRestored = !0;
105
- } catch (error) {
106
- console.warn(`Failed to restore method metadata for ${id}:`, error), getStorage().removeItem(methodKey);
107
- }
108
- }), anyMethodsRestored && addToCaches({
109
- methods,
110
- deps: {},
111
- purFnDeps: {}
112
- });
240
+ function scheduleSweep(state, alsoDelete) {
241
+ if (state.sweepScheduled) return;
242
+ state.sweepScheduled = !0;
243
+ const run = () => {
244
+ sweepOrphans(state, alsoDelete);
245
+ }, idle = globalThis.requestIdleCallback;
246
+ typeof idle == "function" ? idle(run, { timeout: 2e3 }) : setTimeout(run, 0);
247
+ }
248
+ async function sweepOrphans(state, alsoDelete = []) {
249
+ const keys = [...alsoDelete, ...findOrphans(state.graph)];
250
+ if (keys.length) {
251
+ await (await getMetadataStore(state.storageEngine)).remove(state.baseURL, keys).catch(() => {
252
+ });
253
+ for (const [kind, id] of keys) {
254
+ const key = storedKey(kind, id);
255
+ 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];
256
+ }
257
+ }
258
+ }
259
+ function resetMetadataCacheState() {
260
+ states.clear(), writeQueue = [], persistenceAsked = !1, pendingCacheError = void 0;
261
+ }
262
+ function installMethodRows(serializableMethodsData, options, replaceIds = []) {
263
+ for (const id of replaceIds) routesCache.removeMetadata(id);
264
+ processMethodsMetadata(serializableMethodsData, options);
113
265
  }
114
266
  function addToCaches(serializableMethodsData) {
115
267
  addSerializedJitCaches(serializableMethodsData.deps, serializableMethodsData.purFnDeps), addRoutesToCache(serializableMethodsData.methods);
116
268
  }
269
+ setFetchedMethods(routesCache);
117
270
  export {
118
- createMetadataSubRequest,
119
- extractAndProcessMetadata,
120
- restoreAllDependencies,
121
- restoreFromLocalStorage,
122
- storeDependencies,
123
- storeMethodsMetadata
271
+ flushMetadataCache,
272
+ forgetFetchedMetadata,
273
+ hydrateMetadataCache,
274
+ installMethodRows,
275
+ purgeHydratedMetadata,
276
+ resetMetadataCacheState,
277
+ takeMetadataCacheError,
278
+ wasHydratedFromCache
124
279
  };
125
- //# sourceMappingURL=clientMethodsMetadata.js.map
280
+
281
+ //# sourceMappingURL=clientMethodsMetadata.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"clientMethodsMetadata.js","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":[],"mappings":"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"}
1
+ {"version":3,"file":"clientMethodsMetadata.js","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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"}
@@ -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
@@ -0,0 +1,53 @@
1
+ import { MION_ROUTES, ROUTER_ITEM_SEPARATOR_CHAR } from "@mionjs/core";
2
+ function addThrownError(response, error) {
3
+ const thrownErrors = response[MION_ROUTES.thrownErrors];
4
+ Array.isArray(thrownErrors) ? thrownErrors.push(error) : response[MION_ROUTES.thrownErrors] = [error];
5
+ }
6
+ function hasResponseValue(response, id) {
7
+ const { parent, key } = findParent(response, id);
8
+ return !!parent && Object.hasOwn(parent, key);
9
+ }
10
+ function getResponseValue(response, id) {
11
+ const { parent, key } = findParent(response, id);
12
+ return parent && Object.hasOwn(parent, key) ? parent[key] : void 0;
13
+ }
14
+ function setResponseValue(response, id, value) {
15
+ const { parent, key } = findParent(response, id, !0);
16
+ return parent && (parent[key] = value), !!parent;
17
+ }
18
+ function deleteResponseValue(response, id) {
19
+ const pointer = id.split(ROUTER_ITEM_SEPARATOR_CHAR);
20
+ for (let depth = pointer.length; depth > 0; depth--) {
21
+ const { parent, key } = findParent(response, pointer.slice(0, depth).join(ROUTER_ITEM_SEPARATOR_CHAR));
22
+ if (!parent || !Object.hasOwn(parent, key)) return;
23
+ const child = parent[key];
24
+ if (depth < pointer.length && !(isNode(child) && !Object.keys(child).length)) return;
25
+ delete parent[key];
26
+ }
27
+ }
28
+ function findParent(response, id, create = !1) {
29
+ const pointer = id.split(ROUTER_ITEM_SEPARATOR_CHAR), key = pointer[pointer.length - 1];
30
+ if (pointer.includes("__proto__") || pointer[0] === MION_ROUTES.thrownErrors) return { key };
31
+ let node = response;
32
+ for (let i = 0; i < pointer.length - 1; i++) {
33
+ let next = Object.hasOwn(node, pointer[i]) ? node[pointer[i]] : void 0;
34
+ if (next === void 0 && create && (next = node[pointer[i]] = {}), !isNode(next)) return { key };
35
+ node = next;
36
+ }
37
+ return {
38
+ parent: node,
39
+ key
40
+ };
41
+ }
42
+ function isNode(value) {
43
+ return typeof value == "object" && value !== null && !Array.isArray(value);
44
+ }
45
+ export {
46
+ addThrownError,
47
+ deleteResponseValue,
48
+ getResponseValue,
49
+ hasResponseValue,
50
+ setResponseValue
51
+ };
52
+
53
+ //# sourceMappingURL=clientResponse.js.map