@mionjs/client 0.13.0 → 0.14.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 (96) hide show
  1. package/.dist/esm/src/batch.js +1 -1
  2. package/.dist/esm/src/batch.js.map +1 -1
  3. package/.dist/esm/src/client.js +1 -0
  4. package/.dist/esm/src/client.js.map +1 -1
  5. package/.dist/esm/src/lib/clientMethodsMetadata.js +1 -1
  6. package/.dist/esm/src/lib/clientMethodsMetadata.js.map +1 -1
  7. package/package.json +10 -12
  8. package/.dist/cjs/index.cjs +0 -1
  9. package/.dist/cjs/index.d.ts +0 -16
  10. package/.dist/cjs/middlewares.cjs +0 -1
  11. package/.dist/cjs/middlewares.d.ts +0 -3
  12. package/.dist/cjs/package.json +0 -1
  13. package/.dist/cjs/src/batch.cjs +0 -3
  14. package/.dist/cjs/src/batch.cjs.map +0 -1
  15. package/.dist/cjs/src/batch.d.ts +0 -7
  16. package/.dist/cjs/src/callContext.cjs +0 -3
  17. package/.dist/cjs/src/callContext.cjs.map +0 -1
  18. package/.dist/cjs/src/callContext.d.ts +0 -6
  19. package/.dist/cjs/src/client.cjs +0 -3
  20. package/.dist/cjs/src/client.cjs.map +0 -1
  21. package/.dist/cjs/src/client.d.ts +0 -26
  22. package/.dist/cjs/src/constants.cjs +0 -3
  23. package/.dist/cjs/src/constants.cjs.map +0 -1
  24. package/.dist/cjs/src/constants.d.ts +0 -11
  25. package/.dist/cjs/src/dispatch.cjs +0 -3
  26. package/.dist/cjs/src/dispatch.cjs.map +0 -1
  27. package/.dist/cjs/src/dispatch.d.ts +0 -8
  28. package/.dist/cjs/src/lib/apiBuildVersion.cjs +0 -3
  29. package/.dist/cjs/src/lib/apiBuildVersion.cjs.map +0 -1
  30. package/.dist/cjs/src/lib/apiBuildVersion.d.ts +0 -10
  31. package/.dist/cjs/src/lib/apiVersionRecovery.cjs +0 -3
  32. package/.dist/cjs/src/lib/apiVersionRecovery.cjs.map +0 -1
  33. package/.dist/cjs/src/lib/apiVersionRecovery.d.ts +0 -7
  34. package/.dist/cjs/src/lib/bundledApi.cjs +0 -3
  35. package/.dist/cjs/src/lib/bundledApi.cjs.map +0 -1
  36. package/.dist/cjs/src/lib/bundledApi.d.ts +0 -12
  37. package/.dist/cjs/src/lib/clientMethodsMetadata.cjs +0 -3
  38. package/.dist/cjs/src/lib/clientMethodsMetadata.cjs.map +0 -1
  39. package/.dist/cjs/src/lib/clientMethodsMetadata.d.ts +0 -11
  40. package/.dist/cjs/src/lib/clientResponse.cjs +0 -3
  41. package/.dist/cjs/src/lib/clientResponse.cjs.map +0 -1
  42. package/.dist/cjs/src/lib/clientResponse.d.ts +0 -9
  43. package/.dist/cjs/src/lib/fetchRemoteMethodsMetadata.cjs +0 -3
  44. package/.dist/cjs/src/lib/fetchRemoteMethodsMetadata.cjs.map +0 -1
  45. package/.dist/cjs/src/lib/fetchRemoteMethodsMetadata.d.ts +0 -3
  46. package/.dist/cjs/src/lib/handlersRegistry.cjs +0 -3
  47. package/.dist/cjs/src/lib/handlersRegistry.cjs.map +0 -1
  48. package/.dist/cjs/src/lib/handlersRegistry.d.ts +0 -28
  49. package/.dist/cjs/src/lib/headers.cjs +0 -3
  50. package/.dist/cjs/src/lib/headers.cjs.map +0 -1
  51. package/.dist/cjs/src/lib/headers.d.ts +0 -7
  52. package/.dist/cjs/src/lib/metadataEviction.cjs +0 -3
  53. package/.dist/cjs/src/lib/metadataEviction.cjs.map +0 -1
  54. package/.dist/cjs/src/lib/metadataEviction.d.ts +0 -9
  55. package/.dist/cjs/src/lib/metadataFetcher.cjs +0 -3
  56. package/.dist/cjs/src/lib/metadataFetcher.cjs.map +0 -1
  57. package/.dist/cjs/src/lib/metadataFetcher.d.ts +0 -29
  58. package/.dist/cjs/src/lib/metadataFromServer.cjs +0 -1
  59. package/.dist/cjs/src/lib/metadataFromServer.d.ts +0 -4
  60. package/.dist/cjs/src/lib/metadataFromServerLoader.cjs +0 -3
  61. package/.dist/cjs/src/lib/metadataFromServerLoader.cjs.map +0 -1
  62. package/.dist/cjs/src/lib/metadataFromServerLoader.d.ts +0 -6
  63. package/.dist/cjs/src/lib/metadataStore.cjs +0 -3
  64. package/.dist/cjs/src/lib/metadataStore.cjs.map +0 -1
  65. package/.dist/cjs/src/lib/metadataStore.d.ts +0 -23
  66. package/.dist/cjs/src/lib/methods.cjs +0 -3
  67. package/.dist/cjs/src/lib/methods.cjs.map +0 -1
  68. package/.dist/cjs/src/lib/methods.d.ts +0 -15
  69. package/.dist/cjs/src/lib/persistentStorage.cjs +0 -3
  70. package/.dist/cjs/src/lib/persistentStorage.cjs.map +0 -1
  71. package/.dist/cjs/src/lib/persistentStorage.d.ts +0 -3
  72. package/.dist/cjs/src/lib/sanitize.cjs +0 -3
  73. package/.dist/cjs/src/lib/sanitize.cjs.map +0 -1
  74. package/.dist/cjs/src/lib/sanitize.d.ts +0 -3
  75. package/.dist/cjs/src/lib/serializer.cjs +0 -3
  76. package/.dist/cjs/src/lib/serializer.cjs.map +0 -1
  77. package/.dist/cjs/src/lib/serializer.d.ts +0 -14
  78. package/.dist/cjs/src/lib/storage.cjs +0 -0
  79. package/.dist/cjs/src/lib/storage.d.ts +0 -19
  80. package/.dist/cjs/src/lib/typedEvent.cjs +0 -3
  81. package/.dist/cjs/src/lib/typedEvent.cjs.map +0 -1
  82. package/.dist/cjs/src/lib/typedEvent.d.ts +0 -20
  83. package/.dist/cjs/src/lib/validation.cjs +0 -3
  84. package/.dist/cjs/src/lib/validation.cjs.map +0 -1
  85. package/.dist/cjs/src/lib/validation.d.ts +0 -6
  86. package/.dist/cjs/src/middlewares/fetchMetadata.cjs +0 -3
  87. package/.dist/cjs/src/middlewares/fetchMetadata.cjs.map +0 -1
  88. package/.dist/cjs/src/middlewares/fetchMetadata.d.ts +0 -4
  89. package/.dist/cjs/src/middlewares/syncRoutes.cjs +0 -3
  90. package/.dist/cjs/src/middlewares/syncRoutes.cjs.map +0 -1
  91. package/.dist/cjs/src/middlewares/syncRoutes.d.ts +0 -4
  92. package/.dist/cjs/src/subRequest.cjs +0 -3
  93. package/.dist/cjs/src/subRequest.cjs.map +0 -1
  94. package/.dist/cjs/src/subRequest.d.ts +0 -19
  95. package/.dist/cjs/src/types.cjs +0 -0
  96. package/.dist/cjs/src/types.d.ts +0 -155
@@ -6,7 +6,7 @@ function batch(routes, batchId) {
6
6
  });
7
7
  if (!batchId) throw new RpcError({
8
8
  type: "batch-missing-id",
9
- publicMessage: "batch() needs the mion build plugin (vite or next preset) to inject the batch id. Batches are compiled into the server at build time, so a client without the build cannot send one."
9
+ publicMessage: "batch() needs the mion build plugin (the vite preset or the mion CLI) to inject the batch id. Batches are compiled into the server at build time, so a client without the build cannot send one."
10
10
  });
11
11
  const firstSubRequest = routes[0];
12
12
  if (!firstSubRequest.client) throw new RpcError({
@@ -1 +1 @@
1
- {"version":3,"file":"batch.js","names":[],"sources":["../../../src/batch.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 {RpcError} from '@mionjs/core';\nimport type {PureFunction, InjectPureFnId, InjectBatchId} from '@mionjs/run-types';\nimport type {CallSetup, RouteSubRequest, BatchBuilder, SubRequest} from './types.ts';\nimport type {InjectedApiMetadata} from './types.ts';\nimport type {MionSubRequest} from './subRequest.ts';\nimport type {InputFromRef} from '@mionjs/core';\n\n/** Runs several routes in ONE HTTP request. The build hashes the ordered route ids into `batchId`, which\n * names the batch in the table it compiled into the server; the request carries only that id. */\nexport function batch<Routes extends RouteSubRequest<any>[]>(\n routes: [...Routes],\n batchId?: InjectBatchId<Routes>\n): BatchBuilder<Routes> {\n if (!routes || routes.length === 0) {\n throw new RpcError({\n type: 'batch-empty-routes',\n publicMessage: 'batch() requires at least one route subrequest.',\n });\n }\n if (!batchId) {\n throw new RpcError({\n type: 'batch-missing-id',\n publicMessage:\n 'batch() needs the mion build plugin (vite or next preset) to inject the batch id. ' +\n 'Batches are compiled into the server at build time, so a client without the build cannot send one.',\n });\n }\n\n const firstSubRequest = routes[0] as MionSubRequest;\n if (!firstSubRequest.client) {\n throw new RpcError({\n type: 'batch-missing-client',\n publicMessage: 'Could not extract MionClient from subrequest. Ensure subrequests are created via routes proxy.',\n });\n }\n\n const client = firstSubRequest.client;\n\n for (let i = 1; i < routes.length; i++) {\n const subRequest = routes[i] as MionSubRequest;\n if (subRequest.client !== client) {\n throw new RpcError({\n type: 'batch-client-mismatch',\n publicMessage: `All subrequests in a batch must use the same client instance. Subrequest at index ${i} has a different client.`,\n });\n }\n }\n\n return {\n // `apiMetadata` is filled by the build when routes are bundled, never by hand\n async call(setup?: CallSetup, apiMetadata?: InjectedApiMetadata) {\n client.useBundledApi(apiMetadata);\n return client.execute(undefined, routes, batchId, setup?.signal, setup?.timeout);\n },\n };\n}\n\nconst inputFromSymbol = Symbol('InputFromRef');\n\n/** Feeds the output of one route SubRequest into the input of another within a batch. The mapper EXECUTES\n * ON THE SERVER, which only runs functions its own build baked in, so nothing about the mapper travels: the\n * build extracts the inline mapper, gives the call site its registration id and ships the body in the\n * batches manifest. */\nexport function inputFrom<FromSR extends SubRequest<any>, MappedInput = any>(\n source: FromSR,\n mapper: PureFunction<(value: FromSR['resolvedValue']) => MappedInput>,\n id?: InjectPureFnId<(value: FromSR['resolvedValue']) => MappedInput>\n): InputFromRef<(value: FromSR['resolvedValue']) => MappedInput> {\n // The build rewrites this argument into the mapper's generated entry tuple, not the function the caller wrote.\n if (mapper == null) throw new Error('inputFrom() requires an inline mapper function');\n if (!id)\n throw new Error(\n 'inputFrom() requires the mion build plugin: no pure-fn id was injected at build time, ' +\n 'so the server has no way to know which mapper to run.'\n );\n const ref = {\n inputFromSymbol,\n mapperKey: id,\n fromRequestId: source.id,\n toRequestId: '',\n paramIndex: -1, // set by MionSubRequest constructor when passed as a parameter\n asArg() {\n return ref as unknown as MappedInput;\n },\n } as unknown as InputFromRef<(value: FromSR['resolvedValue']) => MappedInput>;\n return ref;\n}\n\nexport function isInputFromRef(ref: any): ref is InputFromRef<any> {\n return ref && ref.inputFromSymbol === inputFromSymbol;\n}\n"],"mappings":";AAgBA,SAAgB,MACd,QACA,SACsB;AACtB,MAAI,CAAC,UAAU,OAAO,WAAW,EAC/B,OAAM,IAAI,SAAS;AAAA,IACjB,MAAM;AAAA,IACN,eAAe;AAAA,EACjB,CAAC;AAEH,MAAI,CAAC,QACH,OAAM,IAAI,SAAS;AAAA,IACjB,MAAM;AAAA,IACN,eACE;AAAA,EAEJ,CAAC;AAGH,QAAM,kBAAkB,OAAO,CAAA;AAC/B,MAAI,CAAC,gBAAgB,OACnB,OAAM,IAAI,SAAS;AAAA,IACjB,MAAM;AAAA,IACN,eAAe;AAAA,EACjB,CAAC;AAGH,QAAM,SAAS,gBAAgB;AAE/B,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,IAEjC,KADmB,OAAO,CAAA,EACX,WAAW,OACxB,OAAM,IAAI,SAAS;AAAA,IACjB,MAAM;AAAA,IACN,eAAe,qFAAqF,CAAA;AAAA,EACtG,CAAC;AAIL,SAAO,EAEL,MAAM,KAAK,OAAmB,aAAmC;AAC/D,kBAAO,cAAc,WAAW,GACzB,OAAO,QAAQ,QAAW,QAAQ,SAAS,OAAO,QAAQ,OAAO,OAAO;AAAA,EACjF,EACF;AACF;AAEA,IAAM,kBAAkB,uBAAO,cAAc;AAM7C,SAAgB,UACd,QACA,QACA,IAC+D;AAE/D,MAAI,UAAU,KAAM,OAAM,IAAI,MAAM,gDAAgD;AACpF,MAAI,CAAC,GACH,OAAM,IAAI,MACR,6IAEF;AACF,QAAM,MAAM;AAAA,IACV;AAAA,IACA,WAAW;AAAA,IACX,eAAe,OAAO;AAAA,IACtB,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAgB,eAAe,KAAoC;AACjE,SAAO,OAAO,IAAI,oBAAoB;AACxC"}
1
+ {"version":3,"file":"batch.js","names":[],"sources":["../../../src/batch.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 {RpcError} from '@mionjs/core';\nimport type {PureFunction, InjectPureFnId, InjectBatchId} from '@mionjs/run-types';\nimport type {CallSetup, RouteSubRequest, BatchBuilder, SubRequest} from './types.ts';\nimport type {InjectedApiMetadata} from './types.ts';\nimport type {MionSubRequest} from './subRequest.ts';\nimport type {InputFromRef} from '@mionjs/core';\n\n/** Runs several routes in ONE HTTP request. The build hashes the ordered route ids into `batchId`, which\n * names the batch in the table it compiled into the server; the request carries only that id. */\nexport function batch<Routes extends RouteSubRequest<any>[]>(\n routes: [...Routes],\n batchId?: InjectBatchId<Routes>\n): BatchBuilder<Routes> {\n if (!routes || routes.length === 0) {\n throw new RpcError({\n type: 'batch-empty-routes',\n publicMessage: 'batch() requires at least one route subrequest.',\n });\n }\n if (!batchId) {\n throw new RpcError({\n type: 'batch-missing-id',\n publicMessage:\n 'batch() needs the mion build plugin (the vite preset or the mion CLI) to inject the batch id. ' +\n 'Batches are compiled into the server at build time, so a client without the build cannot send one.',\n });\n }\n\n const firstSubRequest = routes[0] as MionSubRequest;\n if (!firstSubRequest.client) {\n throw new RpcError({\n type: 'batch-missing-client',\n publicMessage: 'Could not extract MionClient from subrequest. Ensure subrequests are created via routes proxy.',\n });\n }\n\n const client = firstSubRequest.client;\n\n for (let i = 1; i < routes.length; i++) {\n const subRequest = routes[i] as MionSubRequest;\n if (subRequest.client !== client) {\n throw new RpcError({\n type: 'batch-client-mismatch',\n publicMessage: `All subrequests in a batch must use the same client instance. Subrequest at index ${i} has a different client.`,\n });\n }\n }\n\n return {\n // `apiMetadata` is filled by the build when routes are bundled, never by hand\n async call(setup?: CallSetup, apiMetadata?: InjectedApiMetadata) {\n client.useBundledApi(apiMetadata);\n return client.execute(undefined, routes, batchId, setup?.signal, setup?.timeout);\n },\n };\n}\n\nconst inputFromSymbol = Symbol('InputFromRef');\n\n/** Feeds the output of one route SubRequest into the input of another within a batch. The mapper EXECUTES\n * ON THE SERVER, which only runs functions its own build baked in, so nothing about the mapper travels: the\n * build extracts the inline mapper, gives the call site its registration id and ships the body in the\n * batches manifest. */\nexport function inputFrom<FromSR extends SubRequest<any>, MappedInput = any>(\n source: FromSR,\n mapper: PureFunction<(value: FromSR['resolvedValue']) => MappedInput>,\n id?: InjectPureFnId<(value: FromSR['resolvedValue']) => MappedInput>\n): InputFromRef<(value: FromSR['resolvedValue']) => MappedInput> {\n // The build rewrites this argument into the mapper's generated entry tuple, not the function the caller wrote.\n if (mapper == null) throw new Error('inputFrom() requires an inline mapper function');\n if (!id)\n throw new Error(\n 'inputFrom() requires the mion build plugin: no pure-fn id was injected at build time, ' +\n 'so the server has no way to know which mapper to run.'\n );\n const ref = {\n inputFromSymbol,\n mapperKey: id,\n fromRequestId: source.id,\n toRequestId: '',\n paramIndex: -1, // set by MionSubRequest constructor when passed as a parameter\n asArg() {\n return ref as unknown as MappedInput;\n },\n } as unknown as InputFromRef<(value: FromSR['resolvedValue']) => MappedInput>;\n return ref;\n}\n\nexport function isInputFromRef(ref: any): ref is InputFromRef<any> {\n return ref && ref.inputFromSymbol === inputFromSymbol;\n}\n"],"mappings":";AAgBA,SAAgB,MACd,QACA,SACsB;AACtB,MAAI,CAAC,UAAU,OAAO,WAAW,EAC/B,OAAM,IAAI,SAAS;AAAA,IACjB,MAAM;AAAA,IACN,eAAe;AAAA,EACjB,CAAC;AAEH,MAAI,CAAC,QACH,OAAM,IAAI,SAAS;AAAA,IACjB,MAAM;AAAA,IACN,eACE;AAAA,EAEJ,CAAC;AAGH,QAAM,kBAAkB,OAAO,CAAA;AAC/B,MAAI,CAAC,gBAAgB,OACnB,OAAM,IAAI,SAAS;AAAA,IACjB,MAAM;AAAA,IACN,eAAe;AAAA,EACjB,CAAC;AAGH,QAAM,SAAS,gBAAgB;AAE/B,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,IAEjC,KADmB,OAAO,CAAA,EACX,WAAW,OACxB,OAAM,IAAI,SAAS;AAAA,IACjB,MAAM;AAAA,IACN,eAAe,qFAAqF,CAAA;AAAA,EACtG,CAAC;AAIL,SAAO,EAEL,MAAM,KAAK,OAAmB,aAAmC;AAC/D,kBAAO,cAAc,WAAW,GACzB,OAAO,QAAQ,QAAW,QAAQ,SAAS,OAAO,QAAQ,OAAO,OAAO;AAAA,EACjF,EACF;AACF;AAEA,IAAM,kBAAkB,uBAAO,cAAc;AAM7C,SAAgB,UACd,QACA,QACA,IAC+D;AAE/D,MAAI,UAAU,KAAM,OAAM,IAAI,MAAM,gDAAgD;AACpF,MAAI,CAAC,GACH,OAAM,IAAI,MACR,6IAEF;AACF,QAAM,MAAM;AAAA,IACV;AAAA,IACA,WAAW;AAAA,IACX,eAAe,OAAO;AAAA,IACtB,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAgB,eAAe,KAAoC;AACjE,SAAO,OAAO,IAAI,oBAAoB;AACxC"}
@@ -75,6 +75,7 @@ var MionClient = class {
75
75
  id: getRouterItemId(this.parentProps),
76
76
  registry: this.client.handlersRegistry
77
77
  };
78
+ if (prop === "then" || typeof prop == "symbol") return;
78
79
  if (this.isMiddleware && middlewareHooks.has(prop)) return this.getEvents()[prop].bind(this.events);
79
80
  const existing = this.propsProxies[prop];
80
81
  if (existing) return existing.proxy;
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":[],"sources":["../../../src/client.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 {DEFAULT_CLIENT_OPTIONS, MIDDLEWARE_HOOKS} from './constants.ts';\nimport {\n ClientOptions,\n InjectedApiMetadata,\n MiddlewareSubRequest,\n InitClientOptions,\n RouteSubRequest,\n SubRequest,\n ClientRoutes,\n ClientMiddlewares,\n} from './types.ts';\nimport type {RemoteApi} from '@mionjs/router';\nimport type {InjectBuildVersion} from '@mionjs/run-types';\nimport {getRouterItemId} from '@mionjs/core';\nimport {createCallContext} from './callContext.ts';\nimport {dispatchCall, dispatchTypeErrors} from './dispatch.ts';\nimport type {RunTypeError} from '@mionjs/core';\nimport {HandlersRegistry} from './lib/handlersRegistry.ts';\nimport {TypedEvent} from './lib/typedEvent.ts';\nimport {MionSubRequest} from './subRequest.ts';\nimport {setApiBuildVersion} from './lib/apiBuildVersion.ts';\nimport {registerBundledApi} from '#bundled-api';\nimport {MIDDLEWARE_TARGET, type MiddlewareTarget} from './lib/metadataFetcher.ts';\n\nlet apiBundled = false;\n\n/** Called by generated code, never by hand: bundling the API is a build option. */\nexport function setApiBundled(): void {\n apiBundled = true;\n}\n\n/** A bundled route needs nothing from the server; `buildVersion` is build-filled, never by hand. */\nexport function initClient<RM extends RemoteApi>(\n options: InitClientOptions,\n buildVersion?: InjectBuildVersion<RM>\n): {client: MionClient; routes: ClientRoutes<RM>; middlewares: ClientMiddlewares<RM>} {\n setApiBuildVersion(buildVersion);\n const clientOptions = {...DEFAULT_CLIENT_OPTIONS, ...options};\n const client = new MionClient(clientOptions);\n return {\n client,\n routes: new MethodProxy([], client, false).proxy as ClientRoutes<RM>,\n middlewares: new MethodProxy([], client, true).proxy as ClientMiddlewares<RM>,\n };\n}\n\nexport class MionClient {\n readonly handlersRegistry = new HandlersRegistry();\n\n private globalAbortController = new AbortController();\n private get globalSignal(): AbortSignal {\n return this.globalAbortController.signal;\n }\n\n constructor(private clientOptions: ClientOptions) {}\n\n /** False means the build did not bundle the API: every route is fetched. */\n get isApiBundled(): boolean {\n return apiBundled;\n }\n\n /** Registers the metadata and compiled functions a dispatch point received from the build. */\n useBundledApi(apiMetadata: InjectedApiMetadata | undefined): void {\n if (apiMetadata !== undefined) registerBundledApi(apiMetadata);\n }\n\n /** Aborts all in-flight requests. New requests after this call work normally. */\n abort(): void {\n this.globalAbortController.abort();\n this.globalAbortController = new AbortController();\n }\n\n private composeSignal(signal?: AbortSignal, timeout?: number): AbortSignal {\n const signals: AbortSignal[] = [this.globalSignal];\n if (signal) signals.push(signal);\n const effectiveTimeout = timeout ?? this.clientOptions.timeout;\n if (effectiveTimeout !== undefined) signals.push(AbortSignal.timeout(effectiveTimeout));\n return AbortSignal.any(signals);\n }\n\n async execute(\n routeSubRequest?: RouteSubRequest<any>,\n batchSubRequests?: RouteSubRequest<any>[],\n batchId?: string,\n signal?: AbortSignal,\n timeout?: number\n ): Promise<any> {\n // Before any await, so an abort() while onRequest runs is respected\n const composedSignal = this.composeSignal(signal, timeout);\n const context = createCallContext(this.clientOptions, routeSubRequest, batchSubRequests, batchId, composedSignal);\n return dispatchCall(context, this.handlersRegistry);\n }\n\n typeErrors<List extends SubRequest<any>[]>(...subRequest: List): Promise<RunTypeError[]> {\n return dispatchTypeErrors(this.clientOptions, subRequest, this.handlersRegistry);\n }\n\n destroy(): void {\n this.abort();\n this.handlersRegistry.clearAll();\n }\n}\n\nconst middlewareHooks = new Set<string>(MIDDLEWARE_HOOKS);\n\nclass MethodProxy {\n propsProxies: Record<string, MethodProxy> = {};\n private events?: TypedEvent<any, any>;\n handler = {\n apply: (_target: any, _thisArg: any, argArray?: any): RouteSubRequest<any> & MiddlewareSubRequest<any> => {\n const handlerId = getRouterItemId(this.parentProps);\n return new MionSubRequest(this.parentProps, handlerId, argArray, this.client);\n },\n\n // On the middlewares tree hook names win, so no middleware can be named after one\n get: (_target: any, prop: string): any => {\n if (this.isMiddleware && prop === (MIDDLEWARE_TARGET as unknown)) {\n return {id: getRouterItemId(this.parentProps), registry: this.client.handlersRegistry} satisfies MiddlewareTarget;\n }\n if (this.isMiddleware && middlewareHooks.has(prop)) return this.getEvents()[prop].bind(this.events);\n const existing = this.propsProxies[prop];\n if (existing) return existing.proxy;\n const newMethodProxy = new MethodProxy([...this.parentProps, prop], this.client, this.isMiddleware);\n this.propsProxies[prop] = newMethodProxy;\n return newMethodProxy.proxy;\n },\n };\n\n proxy: typeof Proxy;\n\n constructor(\n public parentProps: string[],\n private client: MionClient,\n private isMiddleware: boolean\n ) {\n const target = () => null;\n this.proxy = new Proxy(target, this.handler);\n }\n\n private getEvents(): TypedEvent<any, any> {\n if (!this.events) {\n const createSubRequest = (params: any[]) => this.handler.apply(null, null, params);\n this.events = new TypedEvent(getRouterItemId(this.parentProps), this.client.handlersRegistry, createSubRequest);\n }\n return this.events;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.js","names":[],"sources":["../../../src/client.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 {DEFAULT_CLIENT_OPTIONS, MIDDLEWARE_HOOKS} from './constants.ts';\nimport {\n ClientOptions,\n InjectedApiMetadata,\n MiddlewareSubRequest,\n InitClientOptions,\n RouteSubRequest,\n SubRequest,\n ClientRoutes,\n ClientMiddlewares,\n} from './types.ts';\nimport type {RemoteApi} from '@mionjs/router';\nimport type {InjectBuildVersion} from '@mionjs/run-types';\nimport {getRouterItemId} from '@mionjs/core';\nimport {createCallContext} from './callContext.ts';\nimport {dispatchCall, dispatchTypeErrors} from './dispatch.ts';\nimport type {RunTypeError} from '@mionjs/core';\nimport {HandlersRegistry} from './lib/handlersRegistry.ts';\nimport {TypedEvent} from './lib/typedEvent.ts';\nimport {MionSubRequest} from './subRequest.ts';\nimport {setApiBuildVersion} from './lib/apiBuildVersion.ts';\nimport {registerBundledApi} from '#bundled-api';\nimport {MIDDLEWARE_TARGET, type MiddlewareTarget} from './lib/metadataFetcher.ts';\n\nlet apiBundled = false;\n\n/** Called by generated code, never by hand: bundling the API is a build option. */\nexport function setApiBundled(): void {\n apiBundled = true;\n}\n\n/** A bundled route needs nothing from the server; `buildVersion` is build-filled, never by hand. */\nexport function initClient<RM extends RemoteApi>(\n options: InitClientOptions,\n buildVersion?: InjectBuildVersion<RM>\n): {client: MionClient; routes: ClientRoutes<RM>; middlewares: ClientMiddlewares<RM>} {\n setApiBuildVersion(buildVersion);\n const clientOptions = {...DEFAULT_CLIENT_OPTIONS, ...options};\n const client = new MionClient(clientOptions);\n return {\n client,\n routes: new MethodProxy([], client, false).proxy as ClientRoutes<RM>,\n middlewares: new MethodProxy([], client, true).proxy as ClientMiddlewares<RM>,\n };\n}\n\nexport class MionClient {\n readonly handlersRegistry = new HandlersRegistry();\n\n private globalAbortController = new AbortController();\n private get globalSignal(): AbortSignal {\n return this.globalAbortController.signal;\n }\n\n constructor(private clientOptions: ClientOptions) {}\n\n /** False means the build did not bundle the API: every route is fetched. */\n get isApiBundled(): boolean {\n return apiBundled;\n }\n\n /** Registers the metadata and compiled functions a dispatch point received from the build. */\n useBundledApi(apiMetadata: InjectedApiMetadata | undefined): void {\n if (apiMetadata !== undefined) registerBundledApi(apiMetadata);\n }\n\n /** Aborts all in-flight requests. New requests after this call work normally. */\n abort(): void {\n this.globalAbortController.abort();\n this.globalAbortController = new AbortController();\n }\n\n private composeSignal(signal?: AbortSignal, timeout?: number): AbortSignal {\n const signals: AbortSignal[] = [this.globalSignal];\n if (signal) signals.push(signal);\n const effectiveTimeout = timeout ?? this.clientOptions.timeout;\n if (effectiveTimeout !== undefined) signals.push(AbortSignal.timeout(effectiveTimeout));\n return AbortSignal.any(signals);\n }\n\n async execute(\n routeSubRequest?: RouteSubRequest<any>,\n batchSubRequests?: RouteSubRequest<any>[],\n batchId?: string,\n signal?: AbortSignal,\n timeout?: number\n ): Promise<any> {\n // Before any await, so an abort() while onRequest runs is respected\n const composedSignal = this.composeSignal(signal, timeout);\n const context = createCallContext(this.clientOptions, routeSubRequest, batchSubRequests, batchId, composedSignal);\n return dispatchCall(context, this.handlersRegistry);\n }\n\n typeErrors<List extends SubRequest<any>[]>(...subRequest: List): Promise<RunTypeError[]> {\n return dispatchTypeErrors(this.clientOptions, subRequest, this.handlersRegistry);\n }\n\n destroy(): void {\n this.abort();\n this.handlersRegistry.clearAll();\n }\n}\n\nconst middlewareHooks = new Set<string>(MIDDLEWARE_HOOKS);\n\nclass MethodProxy {\n propsProxies: Record<string, MethodProxy> = {};\n private events?: TypedEvent<any, any>;\n handler = {\n apply: (_target: any, _thisArg: any, argArray?: any): RouteSubRequest<any> & MiddlewareSubRequest<any> => {\n const handlerId = getRouterItemId(this.parentProps);\n return new MionSubRequest(this.parentProps, handlerId, argArray, this.client);\n },\n\n // On the middlewares tree hook names win, so no middleware can be named after one\n get: (_target: any, prop: string | symbol): any => {\n if (this.isMiddleware && prop === MIDDLEWARE_TARGET) {\n return {id: getRouterItemId(this.parentProps), registry: this.client.handlersRegistry} satisfies MiddlewareTarget;\n }\n // A callable `then` makes `await routes` wait forever, and no symbol names a route\n if (prop === 'then' || typeof prop === 'symbol') return undefined;\n if (this.isMiddleware && middlewareHooks.has(prop)) return this.getEvents()[prop].bind(this.events);\n const existing = this.propsProxies[prop];\n if (existing) return existing.proxy;\n const newMethodProxy = new MethodProxy([...this.parentProps, prop], this.client, this.isMiddleware);\n this.propsProxies[prop] = newMethodProxy;\n return newMethodProxy.proxy;\n },\n };\n\n proxy: typeof Proxy;\n\n constructor(\n public parentProps: string[],\n private client: MionClient,\n private isMiddleware: boolean\n ) {\n const target = () => null;\n this.proxy = new Proxy(target, this.handler);\n }\n\n private getEvents(): TypedEvent<any, any> {\n if (!this.events) {\n const createSubRequest = (params: any[]) => this.handler.apply(null, null, params);\n this.events = new TypedEvent(getRouterItemId(this.parentProps), this.client.handlersRegistry, createSubRequest);\n }\n return this.events;\n }\n}\n"],"mappings":"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"}
@@ -29,7 +29,7 @@ function processMethodsMetadata(serializableMethodsData, options) {
29
29
  addToCaches(serializableMethodsData), queuePersist(serializableMethodsData, options);
30
30
  }
31
31
  function isStorableName(name) {
32
- return !isUnsafePropertyName(name) && !name.includes(":");
32
+ return !isUnsafePropertyName(name);
33
33
  }
34
34
  function queuePersist(data, options) {
35
35
  writeQueue.push({
@@ -1 +1 @@
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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"}
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);\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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mionjs/client",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "Browser client for mion Apps.",
@@ -22,22 +22,18 @@
22
22
  "exports": {
23
23
  ".": {
24
24
  "types": "./.dist/esm/index.d.ts",
25
- "require": "./.dist/cjs/index.cjs",
26
25
  "default": "./.dist/esm/index.js"
27
26
  },
28
27
  "./middlewares": {
29
28
  "types": "./.dist/esm/middlewares.d.ts",
30
- "require": "./.dist/cjs/middlewares.cjs",
31
29
  "default": "./.dist/esm/middlewares.js"
32
30
  }
33
31
  },
34
32
  "imports": {
35
33
  "#metadata-from-server": {
36
- "require": "./.dist/cjs/src/lib/metadataFromServer.cjs",
37
34
  "default": "./.dist/esm/src/lib/metadataFromServer.js"
38
35
  },
39
36
  "#bundled-api": {
40
- "require": "./.dist/cjs/src/lib/bundledApi.cjs",
41
37
  "default": "./.dist/esm/src/lib/bundledApi.js"
42
38
  }
43
39
  },
@@ -61,14 +57,17 @@
61
57
  },
62
58
  "gitHead": "afd6e1d61525b4bf11bb84b3f85089038d70062d",
63
59
  "devDependencies": {
64
- "@mionjs/devtools": "0.13.0",
65
- "@mionjs/platform-node": "0.13.0",
66
- "@mionjs/router": "0.13.0",
67
- "@mionjs/test-server": "0.13.0"
60
+ "@mionjs/devtools": "0.14.0",
61
+ "@mionjs/platform-node": "0.14.0",
62
+ "@mionjs/router": "0.14.0",
63
+ "@mionjs/test-server": "0.14.0"
68
64
  },
69
65
  "dependencies": {
70
- "@mionjs/core": "0.13.0",
71
- "@mionjs/run-types": "0.13.0"
66
+ "@mionjs/core": "0.14.0",
67
+ "@mionjs/run-types": "0.14.0"
68
+ },
69
+ "engines": {
70
+ "node": ">=24"
72
71
  },
73
72
  "scripts": {
74
73
  "test": "vitest run",
@@ -76,7 +75,6 @@
76
75
  "dev:test": "vitest watch",
77
76
  "lint": "eslint src",
78
77
  "typecheck:test": "tsc -p tsconfig.json --noEmit",
79
- "format": "prettier --write src/**/*.ts",
80
78
  "build": "vite build",
81
79
  "clean": "rimraf .dist .coverage .mion .mion",
82
80
  "fresh-start": "pnpm run clean && rimraf node_modules"
@@ -1 +0,0 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const require_src_constants=require("./src/constants.cjs"),require_src_lib_metadataStore=require("./src/lib/metadataStore.cjs"),require_src_lib_persistentStorage=require("./src/lib/persistentStorage.cjs"),require_src_lib_validation=require("./src/lib/validation.cjs"),require_src_lib_serializer=require("./src/lib/serializer.cjs"),require_src_lib_clientMethodsMetadata=require("./src/lib/clientMethodsMetadata.cjs"),require_src_lib_fetchRemoteMethodsMetadata=require("./src/lib/fetchRemoteMethodsMetadata.cjs"),require_src_callContext=require("./src/callContext.cjs"),require_src_dispatch=require("./src/dispatch.cjs"),require_src_lib_handlersRegistry=require("./src/lib/handlersRegistry.cjs"),require_src_lib_typedEvent=require("./src/lib/typedEvent.cjs"),require_src_batch=require("./src/batch.cjs"),require_src_client=require("./src/client.cjs");exports.CLIENT_REQUEST_ERROR_ID=require_src_constants.CLIENT_REQUEST_ERROR_ID;exports.DEFAULT_CLIENT_OPTIONS=require_src_constants.DEFAULT_CLIENT_OPTIONS;exports.DEFAULT_STORAGE_ENGINE=require_src_constants.DEFAULT_STORAGE_ENGINE;exports.HandlersRegistry=require_src_lib_handlersRegistry.HandlersRegistry;exports.IdbMetadataStore=require_src_lib_metadataStore.IdbMetadataStore;exports.MAX_GET_URL_LENGTH=require_src_constants.MAX_GET_URL_LENGTH;exports.METADATA_CACHE_EVICTION_ROUNDS=require_src_constants.METADATA_CACHE_EVICTION_ROUNDS;exports.METADATA_CACHE_MAX_BYTES=require_src_constants.METADATA_CACHE_MAX_BYTES;exports.MIDDLEWARE_HOOKS=require_src_constants.MIDDLEWARE_HOOKS;exports.MemoryMetadataStore=require_src_lib_metadataStore.MemoryMetadataStore;exports.MionClient=require_src_client.MionClient;exports.STORAGE_KEY=require_src_constants.STORAGE_KEY;exports.TypedEvent=require_src_lib_typedEvent.TypedEvent;exports.addSubRequest=require_src_callContext.addSubRequest;exports.batch=require_src_batch.batch;exports.createCallContext=require_src_callContext.createCallContext;exports.deserializeResponseBody=require_src_lib_serializer.deserializeResponseBody;exports.dispatchCall=require_src_dispatch.dispatchCall;exports.dispatchTypeErrors=require_src_dispatch.dispatchTypeErrors;exports.fetchRemoteMethodsMetadata=require_src_lib_fetchRemoteMethodsMetadata.fetchRemoteMethodsMetadata;exports.flushMetadataCache=require_src_lib_clientMethodsMetadata.flushMetadataCache;exports.forgetFetchedMetadata=require_src_lib_clientMethodsMetadata.forgetFetchedMetadata;exports.getMetadataStore=require_src_lib_metadataStore.getMetadataStore;exports.getResponseError=require_src_lib_validation.getResponseError;exports.getRouteIds=require_src_callContext.getRouteIds;exports.getRoutePointers=require_src_callContext.getRoutePointers;exports.hydrateMetadataCache=require_src_lib_clientMethodsMetadata.hydrateMetadataCache;exports.initClient=require_src_client.initClient;exports.inputFrom=require_src_batch.inputFrom;exports.installMethodRows=require_src_lib_clientMethodsMetadata.installMethodRows;exports.isInputFromRef=require_src_batch.isInputFromRef;exports.isMiddlewareInScope=require_src_dispatch.isMiddlewareInScope;exports.purgeHydratedMetadata=require_src_lib_clientMethodsMetadata.purgeHydratedMetadata;exports.requestPersistenceWhenSilent=require_src_lib_persistentStorage.requestPersistenceWhenSilent;exports.requestPersistentStorage=require_src_lib_persistentStorage.requestPersistentStorage;exports.resetMetadataCacheState=require_src_lib_clientMethodsMetadata.resetMetadataCacheState;exports.resetMetadataStore=require_src_lib_metadataStore.resetMetadataStore;exports.routeSucceeded=require_src_dispatch.routeSucceeded;exports.serializeRequestBody=require_src_lib_serializer.serializeRequestBody;exports.setApiBundled=require_src_client.setApiBundled;exports.setMetadataStoreForTesting=require_src_lib_metadataStore.setMetadataStoreForTesting;exports.takeMetadataCacheError=require_src_lib_clientMethodsMetadata.takeMetadataCacheError;exports.validateSubRequest=require_src_lib_validation.validateSubRequest;exports.validateSubRequests=require_src_lib_validation.validateSubRequests;exports.wasHydratedFromCache=require_src_lib_clientMethodsMetadata.wasHydratedFromCache;exports.wireFormReplacer=require_src_lib_serializer.wireFormReplacer;
@@ -1,16 +0,0 @@
1
- export * from './src/types.ts';
2
- export * from './src/constants.ts';
3
- export * from './src/lib/storage.ts';
4
- export * from './src/lib/metadataStore.ts';
5
- export * from './src/lib/persistentStorage.ts';
6
- export * from './src/lib/validation.ts';
7
- export * from './src/lib/serializer.ts';
8
- export * from './src/lib/clientMethodsMetadata.ts';
9
- export * from './src/lib/fetchRemoteMethodsMetadata.ts';
10
- export * from './src/callContext.ts';
11
- export * from './src/dispatch.ts';
12
- export * from './src/client.ts';
13
- export * from './src/lib/typedEvent.ts';
14
- export * from './src/lib/handlersRegistry.ts';
15
- export * from './src/batch.ts';
16
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const require_src_middlewares_fetchMetadata=require("./src/middlewares/fetchMetadata.cjs"),require_src_middlewares_syncRoutes=require("./src/middlewares/syncRoutes.cjs");exports.useFetchMetadata=require_src_middlewares_fetchMetadata.useFetchMetadata;exports.useSyncRoutes=require_src_middlewares_syncRoutes.useSyncRoutes;
@@ -1,3 +0,0 @@
1
- export { useFetchMetadata } from './src/middlewares/fetchMetadata.ts';
2
- export { useSyncRoutes } from './src/middlewares/syncRoutes.ts';
3
- //# sourceMappingURL=middlewares.d.ts.map
@@ -1 +0,0 @@
1
- {"type":"commonjs"}
@@ -1,3 +0,0 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let _mionjs_core=require("@mionjs/core");function batch(routes,batchId){if(!routes||routes.length===0)throw new _mionjs_core.RpcError({type:"batch-empty-routes",publicMessage:"batch() requires at least one route subrequest."});if(!batchId)throw new _mionjs_core.RpcError({type:"batch-missing-id",publicMessage:"batch() needs the mion build plugin (vite or next preset) to inject the batch id. Batches are compiled into the server at build time, so a client without the build cannot send one."});const firstSubRequest=routes[0];if(!firstSubRequest.client)throw new _mionjs_core.RpcError({type:"batch-missing-client",publicMessage:"Could not extract MionClient from subrequest. Ensure subrequests are created via routes proxy."});const client=firstSubRequest.client;for(let i=1;i<routes.length;i++)if(routes[i].client!==client)throw new _mionjs_core.RpcError({type:"batch-client-mismatch",publicMessage:`All subrequests in a batch must use the same client instance. Subrequest at index ${i} has a different client.`});return{async call(setup,apiMetadata){return client.useBundledApi(apiMetadata),client.execute(void 0,routes,batchId,setup?.signal,setup?.timeout)}}}var inputFromSymbol=Symbol("InputFromRef");function inputFrom(source,mapper,id){if(mapper==null)throw new Error("inputFrom() requires an inline mapper function");if(!id)throw new Error("inputFrom() requires the mion build plugin: no pure-fn id was injected at build time, so the server has no way to know which mapper to run.");const ref={inputFromSymbol,mapperKey:id,fromRequestId:source.id,toRequestId:"",paramIndex:-1,asArg(){return ref}};return ref}function isInputFromRef(ref){return ref&&ref.inputFromSymbol===inputFromSymbol}exports.batch=batch;exports.inputFrom=inputFrom;exports.isInputFromRef=isInputFromRef;
2
-
3
- //# sourceMappingURL=batch.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"batch.cjs","names":[],"sources":["../../../src/batch.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 {RpcError} from '@mionjs/core';\nimport type {PureFunction, InjectPureFnId, InjectBatchId} from '@mionjs/run-types';\nimport type {CallSetup, RouteSubRequest, BatchBuilder, SubRequest} from './types.ts';\nimport type {InjectedApiMetadata} from './types.ts';\nimport type {MionSubRequest} from './subRequest.ts';\nimport type {InputFromRef} from '@mionjs/core';\n\n/** Runs several routes in ONE HTTP request. The build hashes the ordered route ids into `batchId`, which\n * names the batch in the table it compiled into the server; the request carries only that id. */\nexport function batch<Routes extends RouteSubRequest<any>[]>(\n routes: [...Routes],\n batchId?: InjectBatchId<Routes>\n): BatchBuilder<Routes> {\n if (!routes || routes.length === 0) {\n throw new RpcError({\n type: 'batch-empty-routes',\n publicMessage: 'batch() requires at least one route subrequest.',\n });\n }\n if (!batchId) {\n throw new RpcError({\n type: 'batch-missing-id',\n publicMessage:\n 'batch() needs the mion build plugin (vite or next preset) to inject the batch id. ' +\n 'Batches are compiled into the server at build time, so a client without the build cannot send one.',\n });\n }\n\n const firstSubRequest = routes[0] as MionSubRequest;\n if (!firstSubRequest.client) {\n throw new RpcError({\n type: 'batch-missing-client',\n publicMessage: 'Could not extract MionClient from subrequest. Ensure subrequests are created via routes proxy.',\n });\n }\n\n const client = firstSubRequest.client;\n\n for (let i = 1; i < routes.length; i++) {\n const subRequest = routes[i] as MionSubRequest;\n if (subRequest.client !== client) {\n throw new RpcError({\n type: 'batch-client-mismatch',\n publicMessage: `All subrequests in a batch must use the same client instance. Subrequest at index ${i} has a different client.`,\n });\n }\n }\n\n return {\n // `apiMetadata` is filled by the build when routes are bundled, never by hand\n async call(setup?: CallSetup, apiMetadata?: InjectedApiMetadata) {\n client.useBundledApi(apiMetadata);\n return client.execute(undefined, routes, batchId, setup?.signal, setup?.timeout);\n },\n };\n}\n\nconst inputFromSymbol = Symbol('InputFromRef');\n\n/** Feeds the output of one route SubRequest into the input of another within a batch. The mapper EXECUTES\n * ON THE SERVER, which only runs functions its own build baked in, so nothing about the mapper travels: the\n * build extracts the inline mapper, gives the call site its registration id and ships the body in the\n * batches manifest. */\nexport function inputFrom<FromSR extends SubRequest<any>, MappedInput = any>(\n source: FromSR,\n mapper: PureFunction<(value: FromSR['resolvedValue']) => MappedInput>,\n id?: InjectPureFnId<(value: FromSR['resolvedValue']) => MappedInput>\n): InputFromRef<(value: FromSR['resolvedValue']) => MappedInput> {\n // The build rewrites this argument into the mapper's generated entry tuple, not the function the caller wrote.\n if (mapper == null) throw new Error('inputFrom() requires an inline mapper function');\n if (!id)\n throw new Error(\n 'inputFrom() requires the mion build plugin: no pure-fn id was injected at build time, ' +\n 'so the server has no way to know which mapper to run.'\n );\n const ref = {\n inputFromSymbol,\n mapperKey: id,\n fromRequestId: source.id,\n toRequestId: '',\n paramIndex: -1, // set by MionSubRequest constructor when passed as a parameter\n asArg() {\n return ref as unknown as MappedInput;\n },\n } as unknown as InputFromRef<(value: FromSR['resolvedValue']) => MappedInput>;\n return ref;\n}\n\nexport function isInputFromRef(ref: any): ref is InputFromRef<any> {\n return ref && ref.inputFromSymbol === inputFromSymbol;\n}\n"],"mappings":"4GAgBA,SAAgB,MACd,OACA,QACsB,CACtB,GAAI,CAAC,QAAU,OAAO,SAAW,EAC/B,MAAM,IAAI,aAAA,SAAS,CACjB,KAAM,qBACN,cAAe,iDACjB,CAAC,EAEH,GAAI,CAAC,QACH,MAAM,IAAI,aAAA,SAAS,CACjB,KAAM,mBACN,cACE,sLAEJ,CAAC,EAGH,MAAM,gBAAkB,OAAO,CAAA,EAC/B,GAAI,CAAC,gBAAgB,OACnB,MAAM,IAAI,aAAA,SAAS,CACjB,KAAM,uBACN,cAAe,gGACjB,CAAC,EAGH,MAAM,OAAS,gBAAgB,OAE/B,QAAS,EAAI,EAAG,EAAI,OAAO,OAAQ,IAEjC,GADmB,OAAO,CAAA,EACX,SAAW,OACxB,MAAM,IAAI,aAAA,SAAS,CACjB,KAAM,wBACN,cAAe,qFAAqF,CAAA,0BACtG,CAAC,EAIL,MAAO,CAEL,MAAM,KAAK,MAAmB,YAAmC,CAC/D,cAAO,cAAc,WAAW,EACzB,OAAO,QAAQ,OAAW,OAAQ,QAAS,OAAO,OAAQ,OAAO,OAAO,CACjF,CACF,CACF,CAEA,IAAM,gBAAkB,OAAO,cAAc,EAM7C,SAAgB,UACd,OACA,OACA,GAC+D,CAE/D,GAAI,QAAU,KAAM,MAAM,IAAI,MAAM,gDAAgD,EACpF,GAAI,CAAC,GACH,MAAM,IAAI,MACR,6IAEF,EACF,MAAM,IAAM,CACV,gBACA,UAAW,GACX,cAAe,OAAO,GACtB,YAAa,GACb,WAAY,GACZ,OAAQ,CACN,OAAO,GACT,CACF,EACA,OAAO,GACT,CAEA,SAAgB,eAAe,IAAoC,CACjE,OAAO,KAAO,IAAI,kBAAoB,eACxC"}
@@ -1,7 +0,0 @@
1
- import { PureFunction, InjectPureFnId, InjectBatchId } from '@mionjs/run-types';
2
- import { RouteSubRequest, BatchBuilder, SubRequest } from './types.ts';
3
- import { InputFromRef } from '@mionjs/core';
4
- export declare function batch<Routes extends RouteSubRequest<any>[]>(routes: [...Routes], batchId?: InjectBatchId<Routes>): BatchBuilder<Routes>;
5
- export declare function inputFrom<FromSR extends SubRequest<any>, MappedInput = any>(source: FromSR, mapper: PureFunction<(value: FromSR['resolvedValue']) => MappedInput>, id?: InjectPureFnId<(value: FromSR['resolvedValue']) => MappedInput>): InputFromRef<(value: FromSR['resolvedValue']) => MappedInput>;
6
- export declare function isInputFromRef(ref: any): ref is InputFromRef<any>;
7
- //# sourceMappingURL=batch.d.ts.map
@@ -1,3 +0,0 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let _mionjs_core=require("@mionjs/core");function createCallContext(options,route,batchSubRequests,batchId,signal){const isBatch=!!batchSubRequests&&batchSubRequests.length>0,context={path:isBatch?`${(0,_mionjs_core.getRoutePath)([_mionjs_core.MION_BATCH_KEY],options)}?id=${encodeURIComponent(batchId??"")}`:route?(0,_mionjs_core.getRoutePath)(route.pointer,options):"no-route",requestId:isBatch?_mionjs_core.MION_BATCH_KEY:route?route.id:"no-route",route,batchSubRequests,subRequestList:{},options,signal,httpResponse:void 0,response:{},thrownErrorIds:new Set};return isBatch?batchSubRequests.forEach(subRequest=>addSubRequest(context,subRequest)):route&&addSubRequest(context,route),context}function addSubRequest(context,subRequest){if(subRequest.isResolved)throw new Error(`SubRequest ${subRequest.id} is already resolved`);context.subRequestList[subRequest.id]=subRequest}function getRouteIds(context){return context.batchSubRequests&&context.batchSubRequests.length>0?context.batchSubRequests.map(sr=>sr.id):[context.requestId]}function getRoutePointers(context){return context.batchSubRequests&&context.batchSubRequests.length>0?context.batchSubRequests.map(sr=>sr.pointer):context.route?[context.route.pointer]:[]}exports.addSubRequest=addSubRequest;exports.createCallContext=createCallContext;exports.getRouteIds=getRouteIds;exports.getRoutePointers=getRoutePointers;
2
-
3
- //# sourceMappingURL=callContext.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"callContext.cjs","names":[],"sources":["../../../src/callContext.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_BATCH_KEY, getRoutePath} from '@mionjs/core';\nimport type {ClientCallContext, ClientOptions, RouteSubRequest, SubRequest} from './types.ts';\n\n/** `batchId` is build-injected and only ends up in the batch path */\nexport function createCallContext(\n options: ClientOptions,\n route?: RouteSubRequest<any>,\n batchSubRequests?: RouteSubRequest<any>[],\n batchId?: string,\n signal?: AbortSignal\n): ClientCallContext {\n const isBatch = !!batchSubRequests && batchSubRequests.length > 0;\n const context: ClientCallContext = {\n path: isBatch\n ? `${getRoutePath([MION_BATCH_KEY], options)}?id=${encodeURIComponent(batchId ?? '')}`\n : route\n ? getRoutePath(route.pointer, options)\n : 'no-route',\n requestId: isBatch ? MION_BATCH_KEY : route ? route.id : 'no-route',\n route,\n batchSubRequests,\n subRequestList: {},\n options,\n signal,\n httpResponse: undefined,\n response: {},\n thrownErrorIds: new Set<string>(),\n };\n if (isBatch) batchSubRequests.forEach((subRequest) => addSubRequest(context, subRequest));\n else if (route) addSubRequest(context, route);\n return context;\n}\n\nexport function addSubRequest(context: ClientCallContext, subRequest: SubRequest<any>): void {\n if (subRequest.isResolved) throw new Error(`SubRequest ${subRequest.id} is already resolved`);\n context.subRequestList[subRequest.id] = subRequest;\n}\n\nexport function getRouteIds(context: ClientCallContext): string[] {\n if (context.batchSubRequests && context.batchSubRequests.length > 0) return context.batchSubRequests.map((sr) => sr.id);\n return [context.requestId];\n}\n\n/** Same order as getRouteIds() */\nexport function getRoutePointers(context: ClientCallContext): string[][] {\n if (context.batchSubRequests && context.batchSubRequests.length > 0) return context.batchSubRequests.map((sr) => sr.pointer);\n return context.route ? [context.route.pointer] : [];\n}\n"],"mappings":"4GAWA,SAAgB,kBACd,QACA,MACA,iBACA,QACA,OACmB,CACnB,MAAM,QAAU,CAAC,CAAC,kBAAoB,iBAAiB,OAAS,EAC1D,QAA6B,CACjC,KAAM,QACF,MAAA,aAAA,cAAgB,CAAC,aAAA,cAAc,EAAG,OAAO,CAAA,OAAQ,mBAAmB,SAAW,EAAE,CAAA,GACjF,SAAA,aAAA,cACe,MAAM,QAAS,OAAO,EACnC,WACN,UAAW,QAAU,aAAA,eAAiB,MAAQ,MAAM,GAAK,WACzD,MACA,iBACA,eAAgB,CAAC,EACjB,QACA,OACA,aAAc,OACd,SAAU,CAAC,EACX,eAAgB,IAAI,GACtB,EACA,OAAI,QAAS,iBAAiB,QAAS,YAAe,cAAc,QAAS,UAAU,CAAC,EAC/E,OAAO,cAAc,QAAS,KAAK,EACrC,OACT,CAEA,SAAgB,cAAc,QAA4B,WAAmC,CAC3F,GAAI,WAAW,WAAY,MAAM,IAAI,MAAM,cAAc,WAAW,EAAA,sBAAwB,EAC5F,QAAQ,eAAe,WAAW,EAAA,EAAM,UAC1C,CAEA,SAAgB,YAAY,QAAsC,CAChE,OAAI,QAAQ,kBAAoB,QAAQ,iBAAiB,OAAS,EAAU,QAAQ,iBAAiB,IAAK,IAAO,GAAG,EAAE,EAC/G,CAAC,QAAQ,SAAS,CAC3B,CAGA,SAAgB,iBAAiB,QAAwC,CACvE,OAAI,QAAQ,kBAAoB,QAAQ,iBAAiB,OAAS,EAAU,QAAQ,iBAAiB,IAAK,IAAO,GAAG,OAAO,EACpH,QAAQ,MAAQ,CAAC,QAAQ,MAAM,OAAO,EAAI,CAAC,CACpD"}
@@ -1,6 +0,0 @@
1
- import { ClientCallContext, ClientOptions, RouteSubRequest, SubRequest } from './types.ts';
2
- export declare function createCallContext(options: ClientOptions, route?: RouteSubRequest<any>, batchSubRequests?: RouteSubRequest<any>[], batchId?: string, signal?: AbortSignal): ClientCallContext;
3
- export declare function addSubRequest(context: ClientCallContext, subRequest: SubRequest<any>): void;
4
- export declare function getRouteIds(context: ClientCallContext): string[];
5
- export declare function getRoutePointers(context: ClientCallContext): string[][];
6
- //# sourceMappingURL=callContext.d.ts.map
@@ -1,3 +0,0 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const require_src_constants=require("./constants.cjs"),require_src_callContext=require("./callContext.cjs"),require_src_lib_apiBuildVersion=require("./lib/apiBuildVersion.cjs"),require_src_lib_metadataFetcher=require("./lib/metadataFetcher.cjs"),require_src_dispatch=require("./dispatch.cjs"),require_src_lib_handlersRegistry=require("./lib/handlersRegistry.cjs"),require_src_lib_typedEvent=require("./lib/typedEvent.cjs"),require_src_subRequest=require("./subRequest.cjs");let _mionjs_core=require("@mionjs/core"),_bundled_api=require("#bundled-api");var apiBundled=!1;function setApiBundled(){apiBundled=!0}function initClient(options,buildVersion){require_src_lib_apiBuildVersion.setApiBuildVersion(buildVersion);const client=new MionClient({...require_src_constants.DEFAULT_CLIENT_OPTIONS,...options});return{client,routes:new MethodProxy([],client,!1).proxy,middlewares:new MethodProxy([],client,!0).proxy}}var MionClient=class{clientOptions;handlersRegistry=new require_src_lib_handlersRegistry.HandlersRegistry;globalAbortController=new AbortController;get globalSignal(){return this.globalAbortController.signal}constructor(clientOptions){this.clientOptions=clientOptions}get isApiBundled(){return apiBundled}useBundledApi(apiMetadata){apiMetadata!==void 0&&(0,_bundled_api.registerBundledApi)(apiMetadata)}abort(){this.globalAbortController.abort(),this.globalAbortController=new AbortController}composeSignal(signal,timeout){const signals=[this.globalSignal];signal&&signals.push(signal);const effectiveTimeout=timeout??this.clientOptions.timeout;return effectiveTimeout!==void 0&&signals.push(AbortSignal.timeout(effectiveTimeout)),AbortSignal.any(signals)}async execute(routeSubRequest,batchSubRequests,batchId,signal,timeout){const composedSignal=this.composeSignal(signal,timeout);return require_src_dispatch.dispatchCall(require_src_callContext.createCallContext(this.clientOptions,routeSubRequest,batchSubRequests,batchId,composedSignal),this.handlersRegistry)}typeErrors(...subRequest){return require_src_dispatch.dispatchTypeErrors(this.clientOptions,subRequest,this.handlersRegistry)}destroy(){this.abort(),this.handlersRegistry.clearAll()}},middlewareHooks=new Set(require_src_constants.MIDDLEWARE_HOOKS),MethodProxy=class MethodProxy2{parentProps;client;isMiddleware;propsProxies={};events;handler={apply:(_target,_thisArg,argArray)=>{const handlerId=(0,_mionjs_core.getRouterItemId)(this.parentProps);return new require_src_subRequest.MionSubRequest(this.parentProps,handlerId,argArray,this.client)},get:(_target,prop)=>{if(this.isMiddleware&&prop===require_src_lib_metadataFetcher.MIDDLEWARE_TARGET)return{id:(0,_mionjs_core.getRouterItemId)(this.parentProps),registry:this.client.handlersRegistry};if(this.isMiddleware&&middlewareHooks.has(prop))return this.getEvents()[prop].bind(this.events);const existing=this.propsProxies[prop];if(existing)return existing.proxy;const newMethodProxy=new MethodProxy2([...this.parentProps,prop],this.client,this.isMiddleware);return this.propsProxies[prop]=newMethodProxy,newMethodProxy.proxy}};proxy;constructor(parentProps,client,isMiddleware){this.parentProps=parentProps,this.client=client,this.isMiddleware=isMiddleware;const target=()=>null;this.proxy=new Proxy(target,this.handler)}getEvents(){if(!this.events){const createSubRequest=params=>this.handler.apply(null,null,params);this.events=new require_src_lib_typedEvent.TypedEvent((0,_mionjs_core.getRouterItemId)(this.parentProps),this.client.handlersRegistry,createSubRequest)}return this.events}};exports.MionClient=MionClient;exports.initClient=initClient;exports.setApiBundled=setApiBundled;
2
-
3
- //# sourceMappingURL=client.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"client.cjs","names":[],"sources":["../../../src/client.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 {DEFAULT_CLIENT_OPTIONS, MIDDLEWARE_HOOKS} from './constants.ts';\nimport {\n ClientOptions,\n InjectedApiMetadata,\n MiddlewareSubRequest,\n InitClientOptions,\n RouteSubRequest,\n SubRequest,\n ClientRoutes,\n ClientMiddlewares,\n} from './types.ts';\nimport type {RemoteApi} from '@mionjs/router';\nimport type {InjectBuildVersion} from '@mionjs/run-types';\nimport {getRouterItemId} from '@mionjs/core';\nimport {createCallContext} from './callContext.ts';\nimport {dispatchCall, dispatchTypeErrors} from './dispatch.ts';\nimport type {RunTypeError} from '@mionjs/core';\nimport {HandlersRegistry} from './lib/handlersRegistry.ts';\nimport {TypedEvent} from './lib/typedEvent.ts';\nimport {MionSubRequest} from './subRequest.ts';\nimport {setApiBuildVersion} from './lib/apiBuildVersion.ts';\nimport {registerBundledApi} from '#bundled-api';\nimport {MIDDLEWARE_TARGET, type MiddlewareTarget} from './lib/metadataFetcher.ts';\n\nlet apiBundled = false;\n\n/** Called by generated code, never by hand: bundling the API is a build option. */\nexport function setApiBundled(): void {\n apiBundled = true;\n}\n\n/** A bundled route needs nothing from the server; `buildVersion` is build-filled, never by hand. */\nexport function initClient<RM extends RemoteApi>(\n options: InitClientOptions,\n buildVersion?: InjectBuildVersion<RM>\n): {client: MionClient; routes: ClientRoutes<RM>; middlewares: ClientMiddlewares<RM>} {\n setApiBuildVersion(buildVersion);\n const clientOptions = {...DEFAULT_CLIENT_OPTIONS, ...options};\n const client = new MionClient(clientOptions);\n return {\n client,\n routes: new MethodProxy([], client, false).proxy as ClientRoutes<RM>,\n middlewares: new MethodProxy([], client, true).proxy as ClientMiddlewares<RM>,\n };\n}\n\nexport class MionClient {\n readonly handlersRegistry = new HandlersRegistry();\n\n private globalAbortController = new AbortController();\n private get globalSignal(): AbortSignal {\n return this.globalAbortController.signal;\n }\n\n constructor(private clientOptions: ClientOptions) {}\n\n /** False means the build did not bundle the API: every route is fetched. */\n get isApiBundled(): boolean {\n return apiBundled;\n }\n\n /** Registers the metadata and compiled functions a dispatch point received from the build. */\n useBundledApi(apiMetadata: InjectedApiMetadata | undefined): void {\n if (apiMetadata !== undefined) registerBundledApi(apiMetadata);\n }\n\n /** Aborts all in-flight requests. New requests after this call work normally. */\n abort(): void {\n this.globalAbortController.abort();\n this.globalAbortController = new AbortController();\n }\n\n private composeSignal(signal?: AbortSignal, timeout?: number): AbortSignal {\n const signals: AbortSignal[] = [this.globalSignal];\n if (signal) signals.push(signal);\n const effectiveTimeout = timeout ?? this.clientOptions.timeout;\n if (effectiveTimeout !== undefined) signals.push(AbortSignal.timeout(effectiveTimeout));\n return AbortSignal.any(signals);\n }\n\n async execute(\n routeSubRequest?: RouteSubRequest<any>,\n batchSubRequests?: RouteSubRequest<any>[],\n batchId?: string,\n signal?: AbortSignal,\n timeout?: number\n ): Promise<any> {\n // Before any await, so an abort() while onRequest runs is respected\n const composedSignal = this.composeSignal(signal, timeout);\n const context = createCallContext(this.clientOptions, routeSubRequest, batchSubRequests, batchId, composedSignal);\n return dispatchCall(context, this.handlersRegistry);\n }\n\n typeErrors<List extends SubRequest<any>[]>(...subRequest: List): Promise<RunTypeError[]> {\n return dispatchTypeErrors(this.clientOptions, subRequest, this.handlersRegistry);\n }\n\n destroy(): void {\n this.abort();\n this.handlersRegistry.clearAll();\n }\n}\n\nconst middlewareHooks = new Set<string>(MIDDLEWARE_HOOKS);\n\nclass MethodProxy {\n propsProxies: Record<string, MethodProxy> = {};\n private events?: TypedEvent<any, any>;\n handler = {\n apply: (_target: any, _thisArg: any, argArray?: any): RouteSubRequest<any> & MiddlewareSubRequest<any> => {\n const handlerId = getRouterItemId(this.parentProps);\n return new MionSubRequest(this.parentProps, handlerId, argArray, this.client);\n },\n\n // On the middlewares tree hook names win, so no middleware can be named after one\n get: (_target: any, prop: string): any => {\n if (this.isMiddleware && prop === (MIDDLEWARE_TARGET as unknown)) {\n return {id: getRouterItemId(this.parentProps), registry: this.client.handlersRegistry} satisfies MiddlewareTarget;\n }\n if (this.isMiddleware && middlewareHooks.has(prop)) return this.getEvents()[prop].bind(this.events);\n const existing = this.propsProxies[prop];\n if (existing) return existing.proxy;\n const newMethodProxy = new MethodProxy([...this.parentProps, prop], this.client, this.isMiddleware);\n this.propsProxies[prop] = newMethodProxy;\n return newMethodProxy.proxy;\n },\n };\n\n proxy: typeof Proxy;\n\n constructor(\n public parentProps: string[],\n private client: MionClient,\n private isMiddleware: boolean\n ) {\n const target = () => null;\n this.proxy = new Proxy(target, this.handler);\n }\n\n private getEvents(): TypedEvent<any, any> {\n if (!this.events) {\n const createSubRequest = (params: any[]) => this.handler.apply(null, null, params);\n this.events = new TypedEvent(getRouterItemId(this.parentProps), this.client.handlersRegistry, createSubRequest);\n }\n return this.events;\n }\n}\n"],"mappings":"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"}
@@ -1,26 +0,0 @@
1
- import { ClientOptions, InjectedApiMetadata, InitClientOptions, RouteSubRequest, SubRequest, ClientRoutes, ClientMiddlewares } from './types.ts';
2
- import { RemoteApi } from '@mionjs/router';
3
- import { InjectBuildVersion } from '@mionjs/run-types';
4
- import { RunTypeError } from '@mionjs/core';
5
- import { HandlersRegistry } from './lib/handlersRegistry.ts';
6
- export declare function setApiBundled(): void;
7
- export declare function initClient<RM extends RemoteApi>(options: InitClientOptions, buildVersion?: InjectBuildVersion<RM>): {
8
- client: MionClient;
9
- routes: ClientRoutes<RM>;
10
- middlewares: ClientMiddlewares<RM>;
11
- };
12
- export declare class MionClient {
13
- private clientOptions;
14
- readonly handlersRegistry: HandlersRegistry;
15
- private globalAbortController;
16
- private get globalSignal();
17
- constructor(clientOptions: ClientOptions);
18
- get isApiBundled(): boolean;
19
- useBundledApi(apiMetadata: InjectedApiMetadata | undefined): void;
20
- abort(): void;
21
- private composeSignal;
22
- execute(routeSubRequest?: RouteSubRequest<any>, batchSubRequests?: RouteSubRequest<any>[], batchId?: string, signal?: AbortSignal, timeout?: number): Promise<any>;
23
- typeErrors<List extends SubRequest<any>[]>(...subRequest: List): Promise<RunTypeError[]>;
24
- destroy(): void;
25
- }
26
- //# sourceMappingURL=client.d.ts.map
@@ -1,3 +0,0 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});var DEFAULT_STORAGE_ENGINE="indexeddb",DEFAULT_CLIENT_OPTIONS={baseURL:"",fetchOptions:{headers:{"Content-Type":"application/json"}},basePath:"",suffix:"",validateParams:!0,validateServerResponses:!1,sanitizeParams:!0,storageEngine:DEFAULT_STORAGE_ENGINE},MIDDLEWARE_HOOKS=["onRequest","offRequest","onResponse","offResponse","onError","offError"],MAX_GET_URL_LENGTH=4096,STORAGE_KEY="mion:client",METADATA_CACHE_MAX_BYTES=8*1024*1024,METADATA_CACHE_EVICTION_ROUNDS=5,CLIENT_REQUEST_ERROR_ID="mion-client-request";exports.CLIENT_REQUEST_ERROR_ID=CLIENT_REQUEST_ERROR_ID;exports.DEFAULT_CLIENT_OPTIONS=DEFAULT_CLIENT_OPTIONS;exports.DEFAULT_STORAGE_ENGINE=DEFAULT_STORAGE_ENGINE;exports.MAX_GET_URL_LENGTH=MAX_GET_URL_LENGTH;exports.METADATA_CACHE_EVICTION_ROUNDS=METADATA_CACHE_EVICTION_ROUNDS;exports.METADATA_CACHE_MAX_BYTES=METADATA_CACHE_MAX_BYTES;exports.MIDDLEWARE_HOOKS=MIDDLEWARE_HOOKS;exports.STORAGE_KEY=STORAGE_KEY;
2
-
3
- //# sourceMappingURL=constants.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"constants.cjs","names":[],"sources":["../../../src/constants.ts"],"sourcesContent":["/* ########\n * 2022 mion\n * Author: Ma-jerez\n * License: MIT\n * The software is provided \"as is\", without warranty of any kind.\n * ######## */\n\nimport {ClientOptions} from './types.ts';\nimport type {StorageEngine} from './lib/storage.ts';\n\n/** The engine the client uses when an app does not name one. */\nexport const DEFAULT_STORAGE_ENGINE: StorageEngine = 'indexeddb';\n\nexport const DEFAULT_CLIENT_OPTIONS: ClientOptions = {\n baseURL: '',\n fetchOptions: {\n headers: {'Content-Type': 'application/json'},\n },\n /** Prefix for all routes, i.e: api/v1 */\n basePath: '',\n /** Suffix for all routes, i.e: .json */\n suffix: '',\n validateParams: true,\n validateServerResponses: false,\n sanitizeParams: true,\n /** Where the client keeps what it learned about the remote methods */\n storageEngine: DEFAULT_STORAGE_ENGINE,\n};\n\n/** The hook names a middleware function answers; a sub request carries none of them */\nexport const MIDDLEWARE_HOOKS = ['onRequest', 'offRequest', 'onResponse', 'offResponse', 'onError', 'offError'] as const;\n\n/** Maximum safe URL length for GET requests with ?data= query param */\nexport const MAX_GET_URL_LENGTH = 4096;\n\nexport const STORAGE_KEY = 'mion:client';\n\n/** What one server's metadata cache may hold before it drops its oldest entries; well under what a browser grants. */\nexport const METADATA_CACHE_MAX_BYTES = 8 * 1024 * 1024;\n\n/** How many times a refused write may drop more old entries and retry before the app is told. */\nexport const METADATA_CACHE_EVICTION_ROUNDS = 5;\n\n/** Key for request-scoped client errors (transport, platform, framework); deliberately NOT a route or\n * middleware id, so they can never land in a subrequest's slot. */\nexport const CLIENT_REQUEST_ERROR_ID = 'mion-client-request';\n"],"mappings":"mEAWA,IAAa,uBAAwC,YAExC,uBAAwC,CACnD,QAAS,GACT,aAAc,CACZ,QAAS,CAAC,eAAgB,kBAAkB,CAC9C,EAEA,SAAU,GAEV,OAAQ,GACR,eAAgB,GAChB,wBAAyB,GACzB,eAAgB,GAEhB,cAAe,sBACjB,EAGa,iBAAmB,CAAC,YAAa,aAAc,aAAc,cAAe,UAAW,UAAU,EAGjG,mBAAqB,KAErB,YAAc,cAGd,yBAA2B,EAAI,KAAO,KAGtC,+BAAiC,EAIjC,wBAA0B"}
@@ -1,11 +0,0 @@
1
- import { ClientOptions } from './types.ts';
2
- import { StorageEngine } from './lib/storage.ts';
3
- export declare const DEFAULT_STORAGE_ENGINE: StorageEngine;
4
- export declare const DEFAULT_CLIENT_OPTIONS: ClientOptions;
5
- export declare const MIDDLEWARE_HOOKS: readonly ["onRequest", "offRequest", "onResponse", "offResponse", "onError", "offError"];
6
- export declare const MAX_GET_URL_LENGTH = 4096;
7
- export declare const STORAGE_KEY = "mion:client";
8
- export declare const METADATA_CACHE_MAX_BYTES: number;
9
- export declare const METADATA_CACHE_EVICTION_ROUNDS = 5;
10
- export declare const CLIENT_REQUEST_ERROR_ID = "mion-client-request";
11
- //# sourceMappingURL=constants.d.ts.map
@@ -1,3 +0,0 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const require_src_constants=require("./constants.cjs"),require_src_lib_methods=require("./lib/methods.cjs"),require_src_lib_validation=require("./lib/validation.cjs"),require_src_lib_headers=require("./lib/headers.cjs"),require_src_lib_serializer=require("./lib/serializer.cjs"),require_src_callContext=require("./callContext.cjs"),require_src_lib_apiBuildVersion=require("./lib/apiBuildVersion.cjs"),require_src_lib_metadataFetcher=require("./lib/metadataFetcher.cjs"),require_src_lib_sanitize=require("./lib/sanitize.cjs"),require_src_lib_clientResponse=require("./lib/clientResponse.cjs");let _mionjs_core=require("@mionjs/core"),_bundled_api=require("#bundled-api");async function dispatchCall(context,handlersRegistry){const metadata=require_src_lib_metadataFetcher.getMetadataFetcher(handlersRegistry)?.startCall(context),state={context,handlersRegistry,metadata,askedRequestHandlers:new Set,sent:!1},retriedBy=new Set;for(;;){let errors;try{await runCall(state)}catch(requestErrors){errors=requestErrors}if(metadata&&await resendsForMetadata(state,metadata,errors,retriedBy)){retriedBy.add(metadata.id),resetAttempt(state);continue}const hooks=await runMiddlewareResponses(state,getMiddlewareSubRequests(context),errors,retriedBy);if(!hooks.retryIds.length)return buildResult(state,hooks.errors);hooks.retryIds.forEach(id=>retriedBy.add(id)),resetForMiddlewareRetry(state)}}async function dispatchTypeErrors(options,subRequests,handlersRegistry){const context=require_src_callContext.createCallContext(options);subRequests.forEach(subRequest=>require_src_callContext.addSubRequest(context,subRequest));const errors=new Map;try{const subRequestIds=Object.keys(context.subRequestList);return await loadMethodsMetadata(require_src_lib_metadataFetcher.getMetadataFetcher(handlersRegistry)?.startCall(context),subRequestIds),require_src_lib_sanitize.sanitizeSubRequests(subRequestIds,context),require_src_lib_validation.validateSubRequests(subRequestIds,context,errors,!1),Object.values(context.subRequestList).map(subRequest=>subRequest.error?.errorData?.typeErrors||[]).flat()}catch(error){return onError(context,error,"Error preparing request",errors),Promise.reject(errors)}}async function runCall(state){const{signal}=state.context;if(signal?.aborted){const errors=new Map;return onError(state.context,signal.reason??new DOMException("This operation was aborted","AbortError"),"Request aborted",errors),Promise.reject(errors)}return makeCall(state)}async function makeCall(state,skipOptimistic){const{context,metadata}=state,{options,signal}=context,errors=new Map;let isOptimistic=!1;try{const prepared=await metadata?.prepare(!!skipOptimistic),subRequestIds=prepared?.ids??Object.keys(context.subRequestList);if(isOptimistic=!!prepared?.optimistic,signal?.aborted)return onError(context,signal.reason??new DOMException("This operation was aborted","AbortError"),"Request aborted",errors),Promise.reject(errors);if(isOptimistic){const running=runRequestHandlers(state,getScopedRequestHandlerIds(state));if(running&&await running,signal?.aborted)return onError(context,signal.reason,"Request aborted",errors),Promise.reject(errors);metadata?.askRows()}else{await loadMethodsMetadata(metadata,subRequestIds,signal);const chainIds=getChainMiddlewareIds(context,errors);if(errors.size)return Promise.reject(errors);const beforeHandlers=new Set(Object.keys(context.subRequestList)),running=runRequestHandlers(state,chainIds);if(running&&await running,signal?.aborted)return onError(context,signal.reason,"Request aborted",errors),Promise.reject(errors);const addedIds=Object.keys(context.subRequestList).filter(id=>!beforeHandlers.has(id)),allIds=[...subRequestIds,...addedIds];if(await loadMethodsMetadata(metadata,allIds,signal),require_src_lib_sanitize.sanitizeSubRequests(allIds,context),require_src_lib_validation.validateSubRequests(allIds,context,errors),errors.forEach((error,id)=>require_src_lib_clientResponse.setResponseValue(context.response,id,error)),errors.size)return Promise.reject(errors)}}catch(error){return onError(context,error,"Error preparing request",errors),Promise.reject(errors)}let response;try{let serialized;try{serialized=require_src_lib_serializer.serializeRequestBody(context,isOptimistic)}catch(serializeError){if(isOptimistic)return makeCall(state,!0);throw serializeError}const headersFromParams=require_src_lib_headers.extractRequestHeaders(context),url=new URL(context.path,options.baseURL),fetchOptions=buildFetchOptions(url,serialized,headersFromParams,options,isOptimistic,isQueryRoute(context),signal);state.sent=!0,response=await fetch(url,fetchOptions),context.httpResponse=response}catch(error){return onError(context,error,"Error executing request",errors),Promise.reject(errors)}try{if(signal?.aborted)return onError(context,signal.reason,"Request aborted",errors),Promise.reject(errors);const deserialized=await require_src_lib_serializer.deserializeResponseBody(response,options,metadata&&(body=>metadata.readRows(body)));return handlePlatformError(context,deserialized,errors)||(require_src_lib_apiBuildVersion.noteServerApiVersion(options.baseURL,response.headers.get(_mionjs_core.BUILD_VERSION_HEADER))&&!metadata&&require_src_lib_apiBuildVersion.reportApiVersionMismatch(options.baseURL),addParamlessMiddlewares(context),resolveSubRequests(context,deserialized,errors),errors.size)?Promise.reject(errors):deserialized}catch(error){return onError(context,error,"Error parsing response",errors),Promise.reject(errors)}}async function loadMethodsMetadata(metadata,methodIds,signal){const missing=methodIds.filter(id=>!require_src_lib_methods.hasMethod(id));if(missing.length){if(metadata)return metadata.fetchRows(missing,signal);throw new _mionjs_core.RpcError({type:"route-metadata-not-found",publicMessage:`No metadata for ${missing.map(id=>`'${id}'`).join(", ")}: the build did not bundle it and the client does not fetch it. Call the route where the build can see it, or set up useFetchMetadata from '@mionjs/client/middlewares'.`})}}async function resendsForMetadata(state,metadata,errors,retriedBy){return!errors||!state.sent||retriedBy.has(metadata.id)?!1:await metadata.shouldResend(errors).catch(()=>!1)&&isRetrySafe(state,errors)}function handlePlatformError(context,deserialized,errors){if(!(_mionjs_core.MION_ROUTES.platformError in deserialized))return!1;const platformError=deserialized[_mionjs_core.MION_ROUTES.platformError];return Object.values(context.subRequestList).forEach(methodMeta=>methodMeta.isResolved=!0),setThrownError(context,require_src_constants.CLIENT_REQUEST_ERROR_ID,platformError,errors),!0}function setThrownError(context,id,error,errors){errors.set(id,error),context.thrownErrorIds.add(id),require_src_lib_clientResponse.addThrownError(context.response,error)}function addParamlessMiddlewares(context){for(const id of getChainMiddlewareIds(context)){const method=require_src_lib_methods.getMethod(id);context.subRequestList[id]||!method||method.paramsCount||method.headersParam||!method.hasReturnData||require_src_callContext.addSubRequest(context,{pointer:method.pointer,id,isResolved:!1,params:[]})}}function resolveSubRequests(context,deserialized,errors){const{response,subRequestList}=context;for(const[id,value]of Object.entries(deserialized))id!==_mionjs_core.MION_ROUTES.thrownErrors&&require_src_lib_clientResponse.setResponseValue(response,id,value);for(const[id,thrownError]of Object.entries(deserialized[_mionjs_core.MION_ROUTES.thrownErrors]??{})){const subRequest=Object.hasOwn(subRequestList,id)?subRequestList[id]:void 0;subRequest&&(subRequest.isResolved=!0,subRequest.error=thrownError),thrownError.type==="validation-error"&&require_src_lib_clientResponse.setResponseValue(response,id,thrownError)?errors.set(id,thrownError):setThrownError(context,id,thrownError,errors)}const checkAnswers=context.options.validateServerResponses,mayHaveStopped=checkAnswers&&(errors.size>0||Object.values(deserialized).some(value=>(0,_mionjs_core.isRpcError)(value)));Object.entries(subRequestList).forEach(([id,methodMeta])=>{if(errors.has(id))return;const headersSubset=require_src_lib_headers.reconstructHeadersSubsetFromResponse(id,context.httpResponse.headers);headersSubset&&require_src_lib_clientResponse.setResponseValue(response,id,headersSubset);const resp=headersSubset??require_src_lib_clientResponse.getResponseValue(response,id);if(methodMeta.isResolved=!0,(0,_mionjs_core.isRpcError)(resp)){methodMeta.error=resp,errors.set(id,resp);return}const responseError=checkAnswers&&(require_src_lib_clientResponse.hasResponseValue(response,id)||!mayHaveStopped)?require_src_lib_validation.getResponseError(id,resp):void 0;responseError?(methodMeta.error=responseError,require_src_lib_clientResponse.deleteResponseValue(response,id),setThrownError(context,id,responseError,errors)):methodMeta.resolvedValue=resp}),Object.entries(deserialized).forEach(([id,value])=>{id===_mionjs_core.MION_ROUTES.thrownErrors||Object.hasOwn(subRequestList,id)||(0,_mionjs_core.isRpcError)(value)&&errors.set(id,value)})}function onError(context,error,stageMessage,errors){const reason=context.signal?.aborted?context.signal.reason:void 0;if(reason instanceof DOMException){if(reason.name==="TimeoutError"){setThrownError(context,require_src_constants.CLIENT_REQUEST_ERROR_ID,new _mionjs_core.RpcError({type:"request-timeout",publicMessage:"Request timed out",originalError:error instanceof Error?error:void 0}),errors);return}if(reason.name==="AbortError"){setThrownError(context,require_src_constants.CLIENT_REQUEST_ERROR_ID,new _mionjs_core.RpcError({type:"request-aborted",publicMessage:"Request was aborted",originalError:error instanceof Error?error:void 0}),errors);return}}if((0,_mionjs_core.isRpcError)(error)){setThrownError(context,require_src_constants.CLIENT_REQUEST_ERROR_ID,error,errors);return}const message=error?.message?`${stageMessage}: ${error.message}`:`${stageMessage}: Unknown Error`;setThrownError(context,require_src_constants.CLIENT_REQUEST_ERROR_ID,new _mionjs_core.RpcError({type:error?.name||"unknown-error",publicMessage:message,originalError:error instanceof Error?error:void 0}),errors)}function isQueryRoute(context){return context.batchSubRequests?!1:require_src_lib_methods.getMethod(context.requestId)?.options?.isMutation===!1}function getChainMiddlewareIds(context,errors){const routeIds=new Set(require_src_callContext.getRouteIds(context)),chainIds=new Set;for(const routeId of routeIds){const methodMeta=require_src_lib_methods.getMethod(routeId);if(!methodMeta){errors&&setThrownError(context,routeId,new _mionjs_core.RpcError({type:"route-metadata-not-found",publicMessage:`Metadata for Route '${routeId}' not found.`}),errors);continue}methodMeta.middlewareIds?.forEach(id=>!!id&&!routeIds.has(id)&&chainIds.add(id))}return[...chainIds]}function getScopedRequestHandlerIds(state){const routeIds=new Set(require_src_callContext.getRouteIds(state.context)),routePointers=require_src_callContext.getRoutePointers(state.context);return state.handlersRegistry.getRequestHandlerIds().filter(id=>{if(routeIds.has(id))return!1;const middlewarePointer=id.split(_mionjs_core.ROUTER_ITEM_SEPARATOR_CHAR);return routePointers.some(routePointer=>isMiddlewareInScope(middlewarePointer,routePointer))})}function runRequestHandlers(state,ids){const pending=[];for(const id of ids){if(state.context.subRequestList[id]||state.askedRequestHandlers.has(id))continue;const entry=state.handlersRegistry.getRequestHandler(id);if(!entry)continue;state.askedRequestHandlers.add(id);const running=runRequestHandler(state.context,id,entry);running&&pending.push(running)}if(pending.length)return Promise.all(pending).then(()=>{})}function runRequestHandler(context,id,entry){let subRequest,isOpen=!0;const call=(...params)=>{isOpen&&(subRequest=entry.createSubRequest(params))},finish=()=>{isOpen=!1,subRequest&&require_src_callContext.addSubRequest(context,subRequest)},fail=error=>{throw isOpen=!1,requestHandlerError(id,error)};let returned;try{returned=entry.handler(call,context)}catch(error){return fail(error)}return isPromiseLike(returned)?Promise.resolve(returned).then(finish,fail):finish()}function isPromiseLike(value){return!!value&&typeof value.then=="function"}function requestHandlerError(id,error){return(0,_mionjs_core.isRpcError)(error)?error:new _mionjs_core.RpcError({type:"middleware-on-request-failed",publicMessage:`onRequest for middleware '${id}' failed: ${error instanceof Error?error.message:String(error)}`,originalError:error instanceof Error?error:void 0})}function isMiddlewareInScope(middlewarePointer,routePointer){const groupDepth=middlewarePointer.length-1;if(groupDepth>=routePointer.length)return!1;for(let i=0;i<groupDepth;i++)if(middlewarePointer[i]!==routePointer[i])return!1;return!0}function buildFetchOptions(url,serialized,headersFromParams,options,isOptimistic,isQuery,signal){if(!isOptimistic&&isQuery&&serialized.contentType.includes("json")){const encoded=(0,_mionjs_core.toBase64Url)(serialized.body),testUrl=new URL(url.pathname+url.search,url.origin);if(testUrl.searchParams.set("data",encoded),testUrl.toString().length<=4096)return url.searchParams.set("data",encoded),{...options.fetchOptions,method:"GET",headers:{...require_src_lib_headers.headersToRecord(options.fetchOptions.headers),...headersFromParams},body:void 0,signal}}return{...options.fetchOptions,method:"POST",headers:{...require_src_lib_headers.headersToRecord(options.fetchOptions.headers),...headersFromParams,"Content-Type":serialized.contentType},body:serialized.body,signal}}function getMiddlewareSubRequests(context){const routeIds=new Set;return context.route&&routeIds.add(context.route.id),context.batchSubRequests&&context.batchSubRequests.forEach(sr=>routeIds.add(sr.id)),Object.entries(context.subRequestList).filter(([id])=>!routeIds.has(id)).map(([,subRequest])=>subRequest)}async function runMiddlewareResponses(state,middlewareSubRequests,errors,retriedBy){const{context,handlersRegistry}=state,retryIds=[],pending=[];let retrySafe;const requestRetry=id=>retriedBy.has(id)||(retrySafe??=isRetrySafe(state,errors),!retrySafe)?!1:(retryIds.includes(id)||retryIds.push(id),!0),baseContext={route:context.route,batchSubRequests:context.batchSubRequests,subRequestList:context.subRequestList,options:context.options,signal:context.signal,retry:()=>!1};for(const middleware of middlewareSubRequests){const id=middleware.id,middlewareError=errors?.get(id),isErrorHandler=!!middlewareError;if(isErrorHandler&&context.thrownErrorIds.has(id)||!isErrorHandler&&middleware.resolvedValue===void 0)continue;const handlerName=isErrorHandler?"onError":"onResponse",handlers=isErrorHandler?handlersRegistry.getErrorHandlers(id,middlewareError.type):handlersRegistry.getResponseHandlers(id);for(const handler of handlers){let isOpen=!0;const middlewareContext={...baseContext,retry:()=>isOpen&&requestRetry(id)},fail=error=>{isOpen=!1,errors??=new Map,setThrownError(context,require_src_constants.CLIENT_REQUEST_ERROR_ID,middlewareHandlerError(handlerName,id,error),errors)};let returned;try{returned=handler(isErrorHandler?middlewareError:middleware.resolvedValue,middlewareContext)}catch(error){fail(error);continue}if(!isPromiseLike(returned)){isOpen=!1;continue}pending.push(Promise.resolve(returned).then(()=>{isOpen=!1},error=>fail(error)))}}return pending.length&&await Promise.all(pending),errors?.has("mion-client-request")&&retryIds.length&&(retryIds.length=0),{errors,retryIds}}function isRetrySafe(state,errors){return state.sent?require_src_callContext.getRouteIds(state.context).every(id=>require_src_lib_methods.getMethod(id)?.options?.isMutation===!1||!routeSucceeded(state.context,id,errors)):!0}function routeSucceeded(context,routeId,errors){const errorType=errors?.get(routeId)?.type;return errorType==="response-validation-error"||errorType==="headers-validation-error"?!0:errors?.has(routeId)?!1:context.subRequestList[routeId]?.resolvedValue!==void 0?!0:!errors?.size}function resetForMiddlewareRetry(state){const{context}=state,routeIds=new Set(require_src_callContext.getRouteIds(context));for(const id of Object.keys(context.subRequestList))routeIds.has(id)||delete context.subRequestList[id];state.askedRequestHandlers.clear(),resetAttempt(state)}function resetAttempt(state){const{context}=state;Object.values(context.subRequestList).forEach(subRequest=>{subRequest.isResolved=!1,subRequest.resolvedValue=void 0,subRequest.error=void 0}),context.thrownErrorIds.clear(),context.httpResponse=void 0,context.response={},state.sent=!1}function middlewareHandlerError(handlerName,id,error){if((0,_mionjs_core.isRpcError)(error))return error;const message=error instanceof Error?error.message:String(error);return new _mionjs_core.RpcError({type:handlerName==="onError"?"middleware-on-error-failed":"middleware-on-response-failed",publicMessage:`${handlerName} for middleware '${id}' failed: ${message}`,originalError:error instanceof Error?error:void 0})}function buildResult(state,errors){const{route:routeSubRequest,batchSubRequests,thrownErrorIds,response}=state.context,declaredErrorFor=id=>{const error=errors?.get(id);return error&&!thrownErrorIds.has(id)?error:void 0};return[(0,_bundled_api.takeBundledApiError)(),require_src_lib_apiBuildVersion.takeApiVersionError(),state.metadata?.takeError()].forEach(error=>error&&require_src_lib_clientResponse.addThrownError(response,error)),batchSubRequests?batchSubRequests.map(batchRoute=>[batchRoute.resolvedValue,declaredErrorFor(batchRoute.id),response]):[routeSubRequest?.resolvedValue,routeSubRequest&&declaredErrorFor(routeSubRequest.id),response]}exports.dispatchCall=dispatchCall;exports.dispatchTypeErrors=dispatchTypeErrors;exports.isMiddlewareInScope=isMiddlewareInScope;exports.routeSucceeded=routeSucceeded;
2
-
3
- //# sourceMappingURL=dispatch.cjs.map