@mionjs/client 0.8.4-alpha.0 → 0.8.4

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 (77) hide show
  1. package/.dist/cjs/index.cjs +1 -1
  2. package/.dist/cjs/index.d.ts +1 -1
  3. package/.dist/cjs/src/client.cjs +1 -1
  4. package/.dist/cjs/src/client.cjs.map +1 -1
  5. package/.dist/cjs/src/client.d.ts +8 -6
  6. package/.dist/cjs/src/constants.cjs +1 -1
  7. package/.dist/cjs/src/constants.cjs.map +1 -1
  8. package/.dist/cjs/src/constants.d.ts +1 -1
  9. package/.dist/cjs/src/lib/clientMethodsMetadata.cjs +1 -1
  10. package/.dist/cjs/src/lib/clientMethodsMetadata.cjs.map +1 -1
  11. package/.dist/cjs/src/lib/clientMethodsMetadata.d.ts +7 -3
  12. package/.dist/cjs/src/lib/fetchRemoteMethodsMetadata.cjs +2 -0
  13. package/.dist/cjs/src/lib/fetchRemoteMethodsMetadata.cjs.map +1 -0
  14. package/.dist/cjs/src/lib/fetchRemoteMethodsMetadata.d.ts +2 -0
  15. package/.dist/cjs/src/lib/serializer.cjs +1 -1
  16. package/.dist/cjs/src/lib/serializer.cjs.map +1 -1
  17. package/.dist/cjs/src/lib/serializer.d.ts +2 -1
  18. package/.dist/cjs/src/lib/testUtils.cjs +1 -1
  19. package/.dist/cjs/src/lib/testUtils.cjs.map +1 -1
  20. package/.dist/cjs/src/request.cjs +1 -1
  21. package/.dist/cjs/src/request.cjs.map +1 -1
  22. package/.dist/cjs/src/request.d.ts +10 -4
  23. package/.dist/cjs/src/routesFlow.cjs +1 -1
  24. package/.dist/cjs/src/routesFlow.cjs.map +1 -1
  25. package/.dist/cjs/src/routesFlow.d.ts +2 -2
  26. package/.dist/cjs/src/subRequest.cjs +1 -1
  27. package/.dist/cjs/src/subRequest.cjs.map +1 -1
  28. package/.dist/cjs/src/subRequest.d.ts +4 -5
  29. package/.dist/cjs/src/types.d.ts +54 -26
  30. package/.dist/esm/index.d.ts +1 -1
  31. package/.dist/esm/index.js +5 -4
  32. package/.dist/esm/src/client.d.ts +8 -6
  33. package/.dist/esm/src/client.js +22 -17
  34. package/.dist/esm/src/client.js.map +1 -1
  35. package/.dist/esm/src/constants.d.ts +1 -1
  36. package/.dist/esm/src/constants.js +1 -1
  37. package/.dist/esm/src/constants.js.map +1 -1
  38. package/.dist/esm/src/lib/clientMethodsMetadata.d.ts +7 -3
  39. package/.dist/esm/src/lib/clientMethodsMetadata.js +30 -47
  40. package/.dist/esm/src/lib/clientMethodsMetadata.js.map +1 -1
  41. package/.dist/esm/src/lib/fetchRemoteMethodsMetadata.d.ts +2 -0
  42. package/.dist/esm/src/lib/fetchRemoteMethodsMetadata.js +31 -0
  43. package/.dist/esm/src/lib/fetchRemoteMethodsMetadata.js.map +1 -0
  44. package/.dist/esm/src/lib/serializer.d.ts +2 -1
  45. package/.dist/esm/src/lib/serializer.js +87 -54
  46. package/.dist/esm/src/lib/serializer.js.map +1 -1
  47. package/.dist/esm/src/lib/testUtils.js +3 -37
  48. package/.dist/esm/src/lib/testUtils.js.map +1 -1
  49. package/.dist/esm/src/request.d.ts +10 -4
  50. package/.dist/esm/src/request.js +105 -48
  51. package/.dist/esm/src/request.js.map +1 -1
  52. package/.dist/esm/src/routesFlow.d.ts +2 -2
  53. package/.dist/esm/src/routesFlow.js +9 -5
  54. package/.dist/esm/src/routesFlow.js.map +1 -1
  55. package/.dist/esm/src/subRequest.d.ts +4 -5
  56. package/.dist/esm/src/subRequest.js +7 -13
  57. package/.dist/esm/src/subRequest.js.map +1 -1
  58. package/.dist/esm/src/types.d.ts +54 -26
  59. package/package.json +8 -8
  60. package/.dist/cjs/_virtual/jit-fns.cjs +0 -319
  61. package/.dist/cjs/_virtual/jit-fns.cjs.map +0 -1
  62. package/.dist/cjs/_virtual/pure-fns.cjs +0 -56
  63. package/.dist/cjs/_virtual/pure-fns.cjs.map +0 -1
  64. package/.dist/cjs/_virtual/router-cache.cjs +0 -2
  65. package/.dist/cjs/_virtual/router-cache.cjs.map +0 -1
  66. package/.dist/cjs/src/aot/aotCaches.cjs +0 -2
  67. package/.dist/cjs/src/aot/aotCaches.cjs.map +0 -1
  68. package/.dist/cjs/src/aot/aotCaches.d.ts +0 -5
  69. package/.dist/esm/_virtual/jit-fns.js +0 -1395
  70. package/.dist/esm/_virtual/jit-fns.js.map +0 -1
  71. package/.dist/esm/_virtual/pure-fns.js +0 -109
  72. package/.dist/esm/_virtual/pure-fns.js.map +0 -1
  73. package/.dist/esm/_virtual/router-cache.js +0 -5
  74. package/.dist/esm/_virtual/router-cache.js.map +0 -1
  75. package/.dist/esm/src/aot/aotCaches.d.ts +0 -5
  76. package/.dist/esm/src/aot/aotCaches.js +0 -16
  77. package/.dist/esm/src/aot/aotCaches.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","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_PREFILL_OPTIONS} from './constants.ts';\nimport {\n CallWithMiddleFnsResult,\n ClientOptions,\n HSubRequest,\n InitClientOptions,\n RSubRequest,\n SubRequest,\n RequestErrors,\n ClientRoutes,\n ClientMiddleFns,\n Result,\n WorkflowResult,\n} from './types.ts';\nimport type {RemoteApi} from '@mionjs/router';\nimport {registerErrorDeserializers} from '@mionjs/core';\nimport {getRouterItemId} from '@mionjs/core';\nimport {MionClientRequest} from './request.ts';\nimport type {RunTypeError} from '@mionjs/core';\nimport {HandlersRegistry} from './lib/handlersRegistry.ts';\nimport {MionSubRequest, findSubRequestError} from './subRequest.ts';\nimport {loadAOTCaches} from './aot/aotCaches.ts';\n\nexport function initClient<RM extends RemoteApi>(\n options: InitClientOptions\n): {client: MionClient; routes: ClientRoutes<RM>; middleFns: ClientMiddleFns<RM>} {\n loadAOTCaches();\n registerErrorDeserializers();\n const clientOptions = {\n ...DEFAULT_PREFILL_OPTIONS,\n ...options,\n };\n const client = new MionClient(clientOptions);\n const rootProxy = new MethodProxy([], client, clientOptions);\n return {\n client,\n routes: rootProxy.proxy as ClientRoutes<RM>,\n middleFns: rootProxy.proxy as ClientMiddleFns<RM>,\n };\n}\n\nexport class MionClient {\n /** Shared registry for persistent middleFn error handlers */\n readonly handlersRegistry = new HandlersRegistry();\n\n /** In-memory cache for prefilled middleFn subrequests (keyed by baseURL:middleFnId) */\n readonly prefilledMiddleFnsCache = new Map<string, SubRequest<any>>();\n\n /** Tracks in-flight prefill operations to avoid race conditions */\n private pendingPrefills: Promise<void>[] = [];\n\n constructor(private clientOptions: ClientOptions) {}\n\n /** Executes a route call and returns a Result 4-tuple */\n executeCall<RR extends RSubRequest<any>>(routeSubRequest: RR): Promise<Result<any, any>> {\n return this.executeRequest(routeSubRequest, undefined, undefined);\n }\n\n /** Executes a route call with middleFns and returns a typed result object */\n executeCallWithMiddleFns<H extends Record<string, HSubRequest<any>>>(\n routeSubRequest: RSubRequest<any>,\n middleFnsRecord: H\n ): Promise<CallWithMiddleFnsResult<any, any, H>> {\n return this.executeRequest(routeSubRequest, undefined, middleFnsRecord);\n }\n\n /** Executes a routesFlow call with multiple routes and optional middleFns */\n executeCallWithWorkflow<Routes extends RSubRequest<any>[], H extends Record<string, HSubRequest<any>>>(\n workflowSubRequests: Routes,\n middleFnsRecord: H\n ): Promise<WorkflowResult<Routes, H>> {\n return this.executeRequest(undefined, workflowSubRequests, middleFnsRecord);\n }\n\n private async executeRequest<Routes extends RSubRequest<any>[], H extends Record<string, HSubRequest<any>>>(\n routeSubRequest: RSubRequest<any> | undefined,\n workflowSubRequests: Routes | undefined,\n middleFnsRecord: H | undefined\n ): Promise<any> {\n // Wait for any in-flight prefill operations to complete before executing the request\n if (this.pendingPrefills.length > 0) await Promise.allSettled([...this.pendingPrefills]);\n\n const middleFnSubRequests = middleFnsRecord ? Object.values(middleFnsRecord) : [];\n const request = new MionClientRequest(\n this.clientOptions,\n this.prefilledMiddleFnsCache,\n routeSubRequest,\n middleFnSubRequests,\n workflowSubRequests\n );\n\n try {\n await request.call();\n const routeIds = this.getRouteIds(routeSubRequest, workflowSubRequests);\n const allMiddleFns = this.getAllMiddleFnsFromRequest(request, routeIds);\n this.processMiddleFnsResponses(allMiddleFns, undefined);\n return this.buildResult(routeSubRequest, workflowSubRequests, middleFnsRecord || allMiddleFns, undefined);\n } catch (errors: any) {\n const routeIds = this.getRouteIds(routeSubRequest, workflowSubRequests);\n const allMiddleFns = this.getAllMiddleFnsFromRequest(request, routeIds);\n this.processMiddleFnsResponses(allMiddleFns, errors);\n return this.buildResult(routeSubRequest, workflowSubRequests, middleFnsRecord || allMiddleFns, errors);\n }\n }\n\n /** Get route IDs from single route or routesFlow routes */\n private getRouteIds(\n routeSubRequest: RSubRequest<any> | undefined,\n workflowSubRequests: RSubRequest<any>[] | undefined\n ): Set<string> {\n const routeIds = new Set<string>();\n if (routeSubRequest) routeIds.add(routeSubRequest.id);\n if (workflowSubRequests) workflowSubRequests.forEach((sr) => routeIds.add(sr.id));\n return routeIds;\n }\n\n /** Get all middleFns from the request's subRequestList, excluding the route(s) */\n private getAllMiddleFnsFromRequest(request: MionClientRequest<any, any>, excludedIds: Set<string>): HSubRequest<any>[] {\n return Object.entries(request.subRequestList)\n .filter(([id]) => !excludedIds.has(id))\n .map(([, subRequest]) => subRequest as HSubRequest<any>);\n }\n\n /** Process all middleFn responses - call success or error handlers for each middleFn individually */\n private processMiddleFnsResponses(middleFnSubRequests: HSubRequest<any>[], errors: RequestErrors | undefined): void {\n for (const middleFn of middleFnSubRequests) {\n const middleFnError = errors?.get(middleFn.id);\n if (middleFnError) {\n this.handlersRegistry.executeHandler(middleFn.id, middleFnError);\n } else if (middleFn.resolvedValue !== undefined) {\n this.handlersRegistry.executeSuccessHandler(middleFn.id, middleFn.resolvedValue);\n }\n }\n }\n\n /** Build the result 4-tuple from the request results. middleFns can be a named record or an array of subrequests */\n private buildResult<Routes extends RSubRequest<any>[], H extends Record<string, HSubRequest<any>>>(\n routeSubRequest: RSubRequest<any> | undefined,\n workflowSubRequests: Routes | undefined,\n middleFns: H | HSubRequest<any>[],\n errors: RequestErrors | undefined\n ): CallWithMiddleFnsResult<any, any, H> | WorkflowResult<Routes, H> | Result<any, any> {\n const middleFnsResults = {} as Record<string, any>;\n const middleFnsErrors = {} as Record<string, any>;\n const processedIds = new Set<string>();\n\n let routeResultPart: any;\n let routeErrorPart: any;\n\n if (routeSubRequest) {\n processedIds.add(routeSubRequest.id);\n const routeError =\n errors?.get(routeSubRequest.id) || (errors ? findSubRequestError(routeSubRequest, errors) : undefined);\n routeResultPart = routeError ? undefined : routeSubRequest.resolvedValue;\n routeErrorPart = routeError;\n } else if (workflowSubRequests) {\n const routeResults: (any | undefined)[] = [];\n const routeErrors: (any | undefined)[] = [];\n for (const routeSubRequest of workflowSubRequests) {\n processedIds.add(routeSubRequest.id);\n const routeError = errors?.get(routeSubRequest.id);\n if (routeError) {\n routeResults.push(undefined);\n routeErrors.push(routeError);\n } else {\n routeResults.push(routeSubRequest.resolvedValue);\n routeErrors.push(undefined);\n }\n }\n const hasAnyResult = routeResults.some((r) => r !== undefined);\n const hasAnyError = routeErrors.some((e) => e !== undefined);\n routeResultPart = hasAnyResult ? routeResults : undefined;\n routeErrorPart = hasAnyError ? routeErrors : undefined;\n }\n\n // middleFns can be a named record (from callWithMiddleFns/routesFlow) or an array (from executeCall)\n if (Array.isArray(middleFns)) {\n // Array of subrequests - use IDs as keys\n for (const middleFn of middleFns) {\n processedIds.add(middleFn.id);\n const middleFnError = errors?.get(middleFn.id);\n if (middleFnError) {\n middleFnsErrors[middleFn.id] = middleFnError;\n } else if (middleFn.resolvedValue !== undefined) {\n middleFnsResults[middleFn.id] = middleFn.resolvedValue;\n }\n }\n } else {\n // Named record - use names as keys\n for (const [name, middleFn] of Object.entries(middleFns)) {\n processedIds.add(middleFn.id);\n const middleFnError = errors?.get(middleFn.id);\n if (middleFnError) {\n middleFnsErrors[name] = middleFnError;\n } else if (middleFn.resolvedValue !== undefined) {\n middleFnsResults[name] = middleFn.resolvedValue;\n }\n }\n }\n\n if (errors) {\n for (const [id, error] of errors) {\n if (!processedIds.has(id)) {\n middleFnsErrors[id] = error;\n }\n }\n }\n\n return [routeResultPart, routeErrorPart, middleFnsResults, middleFnsErrors] as any;\n }\n\n typeErrors<List extends SubRequest<any>[]>(...subRequest: List): Promise<RunTypeError[]> {\n const request = new MionClientRequest(this.clientOptions, this.prefilledMiddleFnsCache);\n return request.validateParams(subRequest);\n }\n\n prefill<List extends HSubRequest<any>[]>(...subRequest: List): Promise<void> {\n const request = new MionClientRequest(this.clientOptions, this.prefilledMiddleFnsCache);\n const promise = request.prefill(subRequest);\n this.pendingPrefills.push(promise);\n promise.finally(() => {\n const index = this.pendingPrefills.indexOf(promise);\n if (index >= 0) this.pendingPrefills.splice(index, 1);\n });\n return promise;\n }\n\n removePrefill<List extends HSubRequest<any>[]>(...subRequest: List): Promise<void> {\n const request = new MionClientRequest(this.clientOptions, this.prefilledMiddleFnsCache);\n return request.removePrefill(subRequest);\n }\n\n /** Clear all error handlers from the registry */\n destroy(): void {\n this.handlersRegistry.clearAll();\n }\n}\n\nclass MethodProxy {\n propsProxies: Record<string, MethodProxy> = {};\n handler = {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n apply: (_target: any, _thisArg: any, argArray?: any): RSubRequest<any> & HSubRequest<any> => {\n const handlerId = getRouterItemId(this.parentProps);\n return new MionSubRequest(this.parentProps, handlerId, argArray, this.client);\n },\n\n get: (_target: any, prop: string): typeof Proxy => {\n const existing = this.propsProxies[prop];\n if (existing) return existing.proxy;\n const newMethodProxy = new MethodProxy([...this.parentProps, prop], this.client, this.clientOptions);\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 clientOptions: ClientOptions\n ) {\n const target = () => null;\n this.proxy = new Proxy(target, this.handler);\n }\n}\n"],"names":["routeSubRequest"],"mappings":"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"}
1
+ {"version":3,"file":"client.js","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_PREFILL_OPTIONS} from './constants.ts';\nimport {\n ClientOptions,\n MiddlewareSubRequest,\n InitClientOptions,\n RouteSubRequest,\n SubRequest,\n RequestErrors,\n ClientRoutes,\n ClientMiddleFns,\n Result,\n WorkflowResult,\n} from './types.ts';\nimport type {RemoteApi} from '@mionjs/router';\nimport {registerErrorDeserializers} from '@mionjs/core';\nimport {getRouterItemId} from '@mionjs/core';\nimport {MionClientRequest} from './request.ts';\nimport type {RunTypeError} from '@mionjs/core';\nimport {HandlersRegistry} from './lib/handlersRegistry.ts';\nimport {MionSubRequest, findSubRequestError} from './subRequest.ts';\n\nexport function initClient<RM extends RemoteApi>(\n options: InitClientOptions\n): {client: MionClient; routes: ClientRoutes<RM>; middleFns: ClientMiddleFns<RM>} {\n registerErrorDeserializers();\n const clientOptions = {\n ...DEFAULT_PREFILL_OPTIONS,\n ...options,\n };\n const client = new MionClient(clientOptions);\n const rootProxy = new MethodProxy([], client, clientOptions);\n return {\n client,\n routes: rootProxy.proxy as ClientRoutes<RM>,\n middleFns: rootProxy.proxy as ClientMiddleFns<RM>,\n };\n}\n\nexport class MionClient {\n /** Shared registry for persistent middleFn error handlers */\n readonly handlersRegistry = new HandlersRegistry();\n\n /** In-memory cache for prefilled middleFn subrequests (keyed by baseURL:middleFnId) */\n readonly prefilledMiddleFnsCache = new Map<string, SubRequest<any>>();\n\n /** Tracks in-flight prefill operations to avoid race conditions */\n private pendingPrefills: Promise<void>[] = [];\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 /** 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 /** Composes a single AbortSignal from global, per-request, and timeout signals */\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 /** Executes a route call with optional workflow routes and middleFns */\n execute(\n routeSubRequest?: RouteSubRequest<any>,\n workflowSubRequests?: RouteSubRequest<any>[],\n middleFnsRecord?: Record<string, MiddlewareSubRequest<any>>,\n signal?: AbortSignal,\n timeout?: number\n ): Promise<any> {\n return this.executeRequest(routeSubRequest, workflowSubRequests, middleFnsRecord, signal, timeout);\n }\n\n private async executeRequest<Routes extends RouteSubRequest<any>[], H extends Record<string, MiddlewareSubRequest<any>>>(\n routeSubRequest: RouteSubRequest<any> | undefined,\n workflowSubRequests: Routes | undefined,\n middleFnsRecord: H | undefined,\n signal?: AbortSignal,\n timeout?: number\n ): Promise<any> {\n // Capture the signal before any async work so abort() during prefill await is respected\n const composedSignal = this.composeSignal(signal, timeout);\n\n // Wait for any in-flight prefill operations to complete before executing the request\n if (this.pendingPrefills.length > 0) await Promise.allSettled([...this.pendingPrefills]);\n\n const middleFnSubRequests = middleFnsRecord ? Object.values(middleFnsRecord) : [];\n const request = new MionClientRequest(\n this.clientOptions,\n this.prefilledMiddleFnsCache,\n routeSubRequest,\n middleFnSubRequests,\n workflowSubRequests,\n composedSignal\n );\n\n try {\n await request.call();\n const routeIds = this.getRouteIds(routeSubRequest, workflowSubRequests);\n const allMiddleFns = this.getAllMiddleFnsFromRequest(request, routeIds);\n this.processMiddleFnsResponses(allMiddleFns, undefined);\n return this.buildResult(routeSubRequest, workflowSubRequests, middleFnsRecord || allMiddleFns, undefined);\n } catch (errors: any) {\n const routeIds = this.getRouteIds(routeSubRequest, workflowSubRequests);\n const allMiddleFns = this.getAllMiddleFnsFromRequest(request, routeIds);\n this.processMiddleFnsResponses(allMiddleFns, errors);\n return this.buildResult(routeSubRequest, workflowSubRequests, middleFnsRecord || allMiddleFns, errors);\n }\n }\n\n /** Get route IDs from single route or routesFlow routes */\n private getRouteIds(\n routeSubRequest: RouteSubRequest<any> | undefined,\n workflowSubRequests: RouteSubRequest<any>[] | undefined\n ): Set<string> {\n const routeIds = new Set<string>();\n if (routeSubRequest) routeIds.add(routeSubRequest.id);\n if (workflowSubRequests) workflowSubRequests.forEach((sr) => routeIds.add(sr.id));\n return routeIds;\n }\n\n /** Get all middleFns from the request's subRequestList, excluding the route(s) */\n private getAllMiddleFnsFromRequest(\n request: MionClientRequest<any, any>,\n excludedIds: Set<string>\n ): MiddlewareSubRequest<any>[] {\n return Object.entries(request.subRequestList)\n .filter(([id]) => !excludedIds.has(id))\n .map(([, subRequest]) => subRequest as MiddlewareSubRequest<any>);\n }\n\n /** Process all middleFn responses - call success or error handlers for each middleFn individually */\n private processMiddleFnsResponses(middleFnSubRequests: MiddlewareSubRequest<any>[], errors: RequestErrors | undefined): void {\n for (const middleFn of middleFnSubRequests) {\n const middleFnError = errors?.get(middleFn.id);\n if (middleFnError) {\n this.handlersRegistry.executeHandler(middleFn.id, middleFnError);\n } else if (middleFn.resolvedValue !== undefined) {\n this.handlersRegistry.executeSuccessHandler(middleFn.id, middleFn.resolvedValue);\n }\n }\n }\n\n /** Build the result 4-tuple from the request results. middleFns can be a named record or an array of subrequests */\n private buildResult<Routes extends RouteSubRequest<any>[], H extends Record<string, MiddlewareSubRequest<any>>>(\n routeSubRequest: RouteSubRequest<any> | undefined,\n workflowSubRequests: Routes | undefined,\n middleFns: H | MiddlewareSubRequest<any>[],\n errors: RequestErrors | undefined\n ): WorkflowResult<Routes, H> | Result<any, any> {\n const middleFnsResults = {} as Record<string, any>;\n const middleFnsErrors = {} as Record<string, any>;\n const processedIds = new Set<string>();\n\n let routeResultPart: any;\n let routeErrorPart: any;\n\n if (routeSubRequest) {\n processedIds.add(routeSubRequest.id);\n const routeError =\n errors?.get(routeSubRequest.id) || (errors ? findSubRequestError(routeSubRequest, errors) : undefined);\n routeResultPart = routeError ? undefined : routeSubRequest.resolvedValue;\n routeErrorPart = routeError;\n } else if (workflowSubRequests) {\n const routeResults: (any | undefined)[] = [];\n const routeErrors: (any | undefined)[] = [];\n for (const routeSubRequest of workflowSubRequests) {\n processedIds.add(routeSubRequest.id);\n const routeError = errors?.get(routeSubRequest.id);\n if (routeError) {\n routeResults.push(undefined);\n routeErrors.push(routeError);\n } else {\n routeResults.push(routeSubRequest.resolvedValue);\n routeErrors.push(undefined);\n }\n }\n const hasAnyResult = routeResults.some((r) => r !== undefined);\n const hasAnyError = routeErrors.some((e) => e !== undefined);\n routeResultPart = hasAnyResult ? routeResults : undefined;\n routeErrorPart = hasAnyError ? routeErrors : undefined;\n }\n\n // middleFns can be a named record (from callWithMiddleFns/routesFlow) or an array (from executeCall)\n if (Array.isArray(middleFns)) {\n // Array of subrequests - use IDs as keys\n for (const middleFn of middleFns) {\n processedIds.add(middleFn.id);\n const middleFnError = errors?.get(middleFn.id);\n if (middleFnError) {\n middleFnsErrors[middleFn.id] = middleFnError;\n } else if (middleFn.resolvedValue !== undefined) {\n middleFnsResults[middleFn.id] = middleFn.resolvedValue;\n }\n }\n } else {\n // Named record - use names as keys\n for (const [name, middleFn] of Object.entries(middleFns)) {\n processedIds.add(middleFn.id);\n const middleFnError = errors?.get(middleFn.id);\n if (middleFnError) {\n middleFnsErrors[name] = middleFnError;\n } else if (middleFn.resolvedValue !== undefined) {\n middleFnsResults[name] = middleFn.resolvedValue;\n }\n }\n }\n\n if (errors) {\n for (const [id, error] of errors) {\n if (!processedIds.has(id)) {\n middleFnsErrors[id] = error;\n }\n }\n }\n\n return [routeResultPart, routeErrorPart, middleFnsResults, middleFnsErrors] as any;\n }\n\n typeErrors<List extends SubRequest<any>[]>(...subRequest: List): Promise<RunTypeError[]> {\n const request = new MionClientRequest(this.clientOptions, this.prefilledMiddleFnsCache);\n return request.validateParams(subRequest);\n }\n\n prefill<List extends MiddlewareSubRequest<any>[]>(...subRequest: List): Promise<void> {\n const request = new MionClientRequest(this.clientOptions, this.prefilledMiddleFnsCache);\n const promise = request.prefill(subRequest);\n this.pendingPrefills.push(promise);\n promise.finally(() => {\n const index = this.pendingPrefills.indexOf(promise);\n if (index >= 0) this.pendingPrefills.splice(index, 1);\n });\n return promise;\n }\n\n removePrefill<List extends MiddlewareSubRequest<any>[]>(...subRequest: List): Promise<void> {\n const request = new MionClientRequest(this.clientOptions, this.prefilledMiddleFnsCache);\n return request.removePrefill(subRequest);\n }\n\n /** Clear all error handlers from the registry and abort in-flight requests */\n destroy(): void {\n this.abort();\n this.handlersRegistry.clearAll();\n }\n}\n\nclass MethodProxy {\n propsProxies: Record<string, MethodProxy> = {};\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 get: (_target: any, prop: string): typeof Proxy => {\n const existing = this.propsProxies[prop];\n if (existing) return existing.proxy;\n const newMethodProxy = new MethodProxy([...this.parentProps, prop], this.client, this.clientOptions);\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 clientOptions: ClientOptions\n ) {\n const target = () => null;\n this.proxy = new Proxy(target, this.handler);\n }\n}\n"],"names":["routeSubRequest"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { ClientOptions } from './types.ts';
2
2
  export declare const DEFAULT_PREFILL_OPTIONS: ClientOptions;
3
3
  export declare const MAX_GET_URL_LENGTH = 4096;
4
- export declare const STORAGE_KEY = "mionkit:client";
4
+ export declare const STORAGE_KEY = "mion:client";
5
5
  export declare const ROUTES_FLOW_KEY = "mion-routes-flow";
6
6
  export declare const ROUTES_FLOW_PATH = "/mion-routes-flow";
@@ -14,7 +14,7 @@ const DEFAULT_PREFILL_OPTIONS = {
14
14
  autoGenerateErrorId: !1,
15
15
  /** Default serializer mode - stringifyJson as default native serializer */
16
16
  serializer: "stringifyJson"
17
- }, MAX_GET_URL_LENGTH = 4096, STORAGE_KEY = "mionkit:client", ROUTES_FLOW_KEY = "mion-routes-flow", ROUTES_FLOW_PATH = `/${ROUTES_FLOW_KEY}`;
17
+ }, MAX_GET_URL_LENGTH = 4096, STORAGE_KEY = "mion:client", ROUTES_FLOW_KEY = "mion-routes-flow", ROUTES_FLOW_PATH = `/${ROUTES_FLOW_KEY}`;
18
18
  export {
19
19
  DEFAULT_PREFILL_OPTIONS,
20
20
  MAX_GET_URL_LENGTH,
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","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';\n\nexport const DEFAULT_PREFILL_OPTIONS: ClientOptions = {\n baseURL: '',\n fetchOptions: {\n method: 'PUT',\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 /** Enables automatic parameter validation */\n validateParams: true,\n /** Set true to automatically generate and id for every error */\n autoGenerateErrorId: false,\n /** Default serializer mode - stringifyJson as default native serializer */\n serializer: 'stringifyJson',\n};\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 = 'mionkit:client';\n\n/** RoutesFlow route key - matches router constant */\nexport const ROUTES_FLOW_KEY = 'mion-routes-flow';\n\n/** RoutesFlow route path - matches router constant */\nexport const ROUTES_FLOW_PATH = `/${ROUTES_FLOW_KEY}`;\n"],"names":[],"mappings":"AASO,MAAM,0BAAyC;AAAA,EAClD,SAAS;AAAA,EACT,cAAc;AAAA,IACV,QAAQ;AAAA,IACR,SAAS,EAAC,gBAAgB,mBAAA;AAAA,EAAkB;AAAA;AAAA,EAGhD,UAAU;AAAA;AAAA,EAEV,QAAQ;AAAA;AAAA,EAER,gBAAgB;AAAA;AAAA,EAEhB,qBAAqB;AAAA;AAAA,EAErB,YAAY;GAIH,qBAAqB,MAErB,cAAc,kBAGd,kBAAkB,oBAGlB,mBAAmB,IAAI,eAAe;"}
1
+ {"version":3,"file":"constants.js","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';\n\nexport const DEFAULT_PREFILL_OPTIONS: ClientOptions = {\n baseURL: '',\n fetchOptions: {\n method: 'PUT',\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 /** Enables automatic parameter validation */\n validateParams: true,\n /** Set true to automatically generate and id for every error */\n autoGenerateErrorId: false,\n /** Default serializer mode - stringifyJson as default native serializer */\n serializer: 'stringifyJson',\n};\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/** RoutesFlow route key - matches router constant */\nexport const ROUTES_FLOW_KEY = 'mion-routes-flow';\n\n/** RoutesFlow route path - matches router constant */\nexport const ROUTES_FLOW_PATH = `/${ROUTES_FLOW_KEY}`;\n"],"names":[],"mappings":"AASO,MAAM,0BAAyC;AAAA,EAClD,SAAS;AAAA,EACT,cAAc;AAAA,IACV,QAAQ;AAAA,IACR,SAAS,EAAC,gBAAgB,mBAAA;AAAA,EAAkB;AAAA;AAAA,EAGhD,UAAU;AAAA;AAAA,EAEV,QAAQ;AAAA;AAAA,EAER,gBAAgB;AAAA;AAAA,EAEhB,qBAAqB;AAAA;AAAA,EAErB,YAAY;GAIH,qBAAqB,MAErB,cAAc,eAGd,kBAAkB,oBAGlB,mBAAmB,IAAI,eAAe;"}
@@ -1,6 +1,10 @@
1
- import { ClientOptions } from '../types.ts';
2
- import { JitCompiledFnData, MethodsCache, PureFnsDataCache } from '@mionjs/core';
3
- export declare function fetchRemoteMethodsMetadata(methodIds: string[], options: ClientOptions): Promise<void>;
1
+ import { MION_ROUTES, JitCompiledFnData, MethodsCache, PureFnsDataCache } from '@mionjs/core';
2
+ import { ClientOptions, SubRequest } from '../types.ts';
3
+ type MetadataRouteKey = typeof MION_ROUTES.methodsMetadata | typeof MION_ROUTES.methodsMetadataById;
4
+ export declare function extractAndProcessMetadata(routeKey: MetadataRouteKey, parsedBody: any, options: ClientOptions): void;
4
5
  export declare function storeDependencies(deps: Record<string, JitCompiledFnData>, pureFnDeps: PureFnsDataCache, options: ClientOptions): void;
5
6
  export declare function storeMethodsMetadata(methods: MethodsCache, options: ClientOptions): void;
6
7
  export declare function restoreAllDependencies(options: ClientOptions): void;
8
+ export declare function createMetadataSubRequest(methodIds: string[]): SubRequest<any>;
9
+ export declare function restoreFromLocalStorage(methodIds: string[], options: ClientOptions): void;
10
+ export {};
@@ -1,45 +1,27 @@
1
- import { routesCache, MION_ROUTES, getRoutePath, isRpcError, RpcError, addSerializedJitCaches, isTestEnv, addRoutesToCache } from "@mionjs/core";
2
- import { loadAOTCaches } from "../aot/aotCaches.js";
1
+ import { MION_ROUTES, isRpcError, addSerializedJitCaches, routesCache, addRoutesToCache } from "@mionjs/core";
3
2
  import { STORAGE_KEY } from "../constants.js";
4
- import { deserializeResponseBody } from "./serializer.js";
5
3
  import { getStorage } from "./storage.js";
6
- async function fetchRemoteMethodsMetadata(methodIds, options) {
7
- loadAOTCaches(), validateClientCaches(), restoreFromLocalStorage(methodIds, options);
8
- const missingAfterLocal = methodIds.filter((path) => !routesCache.hasMetadata(path));
9
- if (!missingAfterLocal.length)
4
+ const METHOD_DATA_PREFIX = `${STORAGE_KEY}:method-data:`, JIT_FN_PREFIX = `${STORAGE_KEY}:jit-fn:`, PURE_FN_PREFIX = `${STORAGE_KEY}:pure-fn:`;
5
+ function extractAndProcessMetadata(routeKey, parsedBody, options) {
6
+ if (typeof parsedBody != "object" || !(routeKey in parsedBody))
10
7
  return;
11
- const shouldReturnAllMethods = !0, body = {
12
- [MION_ROUTES.methodsMetadataById]: [missingAfterLocal, shouldReturnAllMethods]
13
- };
14
- try {
15
- const path = getRoutePath([MION_ROUTES.methodsMetadataById], options), url = new URL(path, options.baseURL), response = await fetch(url, {
16
- method: "POST",
17
- headers: { "Content-Type": "application/json" },
18
- body: JSON.stringify(body)
19
- }), deserialized = await deserializeResponseBody(response), platformError = deserialized[MION_ROUTES.platformError], serializableMethodsData = deserialized[MION_ROUTES.methodsMetadataById];
20
- if (isRpcError(platformError))
21
- throw platformError;
22
- if (isRpcError(serializableMethodsData))
23
- throw serializableMethodsData;
24
- if (!serializableMethodsData)
25
- throw new RpcError({
26
- type: "cant-fetch-remote-methods-metadata",
27
- publicMessage: "Failed to fetch remote methods metadata",
28
- errorData: { response }
29
- });
30
- storeDependencies(serializableMethodsData.deps, serializableMethodsData.purFnDeps, options), storeMethodsMetadata(serializableMethodsData.methods, options), addToCaches(serializableMethodsData);
31
- } catch (error) {
32
- throw new Error(`Error fetching validation and serialization metadata: ${error?.message}`);
33
- }
8
+ const rawMetadata = parsedBody[routeKey];
9
+ if (delete parsedBody[routeKey], !rawMetadata)
10
+ return;
11
+ const metadataValue = Array.isArray(rawMetadata) ? rawMetadata[1] : rawMetadata;
12
+ metadataValue && !isRpcError(metadataValue) && metadataValue.methods && processMethodsMetadata(metadataValue, options);
13
+ }
14
+ function processMethodsMetadata(serializableMethodsData, options) {
15
+ storeDependencies(serializableMethodsData.deps, serializableMethodsData.purFnDeps, options), storeMethodsMetadata(serializableMethodsData.methods, options), addToCaches(serializableMethodsData);
34
16
  }
35
17
  function getSerializedMethodDataKey(methodId, options) {
36
- return `${STORAGE_KEY}:serialized-method-data:${options.baseURL}:${methodId}`;
18
+ return `${METHOD_DATA_PREFIX}${methodId}:${options.baseURL}`;
37
19
  }
38
20
  function getJitCompiledFnKey(jitFnHash, options) {
39
- return `${STORAGE_KEY}:jit-compiled-fn:${options.baseURL}:${jitFnHash}`;
21
+ return `${JIT_FN_PREFIX}${jitFnHash}:${options.baseURL}`;
40
22
  }
41
23
  function getJitPureFnKey(namespace, pureFnHash, options) {
42
- return `${STORAGE_KEY}:jit-pure-fn:${options.baseURL}:${namespace}:${pureFnHash}`;
24
+ return `${PURE_FN_PREFIX}${namespace}:${pureFnHash}:${options.baseURL}`;
43
25
  }
44
26
  function storeDependencies(deps, pureFnDeps, options) {
45
27
  Object.entries(deps).forEach(([hash, jitFnData]) => {
@@ -71,10 +53,10 @@ function storeMethodsMetadata(methods, options) {
71
53
  });
72
54
  }
73
55
  function restoreAllDependencies(options) {
74
- const deps = {}, pureFnDeps = {}, pureFnKeyPrefix = `${STORAGE_KEY}:jit-pure-fn:${options.baseURL}:`;
56
+ const deps = {}, pureFnDeps = {}, baseURLSuffix = `:${options.baseURL}`;
75
57
  for (let i = 0; i < getStorage().length; i++) {
76
58
  const key = getStorage().key(i);
77
- if (key?.startsWith(`${STORAGE_KEY}:jit-compiled-fn:${options.baseURL}:`))
59
+ if (key?.startsWith(JIT_FN_PREFIX) && key.endsWith(baseURLSuffix))
78
60
  try {
79
61
  const data = getStorage().getItem(key);
80
62
  if (data) {
@@ -87,11 +69,11 @@ function restoreAllDependencies(options) {
87
69
  }
88
70
  for (let i = 0; i < getStorage().length; i++) {
89
71
  const key = getStorage().key(i);
90
- if (key?.startsWith(pureFnKeyPrefix))
72
+ if (key?.startsWith(PURE_FN_PREFIX) && key.endsWith(baseURLSuffix))
91
73
  try {
92
74
  const data = getStorage().getItem(key);
93
75
  if (data) {
94
- const parsedData = JSON.parse(data), namespace = key.slice(pureFnKeyPrefix.length).split(":")[0] || parsedData.namespace;
76
+ const parsedData = JSON.parse(data), namespace = key.slice(PURE_FN_PREFIX.length, key.length - baseURLSuffix.length).split(":")[0] || parsedData.namespace;
95
77
  pureFnDeps[namespace] || (pureFnDeps[namespace] = {}), pureFnDeps[namespace][parsedData.fnName] = parsedData;
96
78
  }
97
79
  } catch (error) {
@@ -100,6 +82,14 @@ function restoreAllDependencies(options) {
100
82
  }
101
83
  (Object.keys(deps).length > 0 || Object.keys(pureFnDeps).length > 0) && addSerializedJitCaches(deps, pureFnDeps);
102
84
  }
85
+ function createMetadataSubRequest(methodIds) {
86
+ return {
87
+ pointer: [MION_ROUTES.methodsMetadata],
88
+ id: MION_ROUTES.methodsMetadata,
89
+ isResolved: !1,
90
+ params: [methodIds]
91
+ };
92
+ }
103
93
  function restoreFromLocalStorage(methodIds, options) {
104
94
  restoreAllDependencies(options);
105
95
  const methods = {};
@@ -124,18 +114,11 @@ function restoreFromLocalStorage(methodIds, options) {
124
114
  function addToCaches(serializableMethodsData) {
125
115
  addSerializedJitCaches(serializableMethodsData.deps, serializableMethodsData.purFnDeps), addRoutesToCache(serializableMethodsData.methods);
126
116
  }
127
- let clientCachesValidated = !1;
128
- function validateClientCaches() {
129
- if (clientCachesValidated || isTestEnv())
130
- return;
131
- clientCachesValidated = !0;
132
- const missingRoutes = Object.values(MION_ROUTES).filter((routeId) => !routesCache.hasMetadata(routeId));
133
- if (missingRoutes.length > 0)
134
- throw new Error(`AOT cache not loaded: Required MION_ROUTES not found in router cache: ${missingRoutes.join(", ")}. Make sure the AOT caches are generated and bundled correctly.`);
135
- }
136
117
  export {
137
- fetchRemoteMethodsMetadata,
118
+ createMetadataSubRequest,
119
+ extractAndProcessMetadata,
138
120
  restoreAllDependencies,
121
+ restoreFromLocalStorage,
139
122
  storeDependencies,
140
123
  storeMethodsMetadata
141
124
  };
@@ -1 +1 @@
1
- {"version":3,"file":"clientMethodsMetadata.js","sources":["../../../../src/lib/clientMethodsMetadata.ts"],"sourcesContent":["/* ########\n * 2023 mion\n * Author: Ma-jerez\n * License: MIT\n * The software is provided \"as is\", without warranty of any kind.\n * ######## */\n\nimport {RpcError, isRpcError, addRoutesToCache, isTestEnv} from '@mionjs/core';\nimport {MION_ROUTES, getRoutePath} from '@mionjs/core';\nimport {loadAOTCaches} from '../aot/aotCaches.ts';\nimport {ClientOptions, RequestBody} from '../types.ts';\nimport type {\n JitCompiledFnData,\n MethodsCache,\n MethodWithOptions,\n PureFunctionData,\n SerializableMethodsData,\n PureFnsDataCache,\n} from '@mionjs/core';\nimport {routesCache, addSerializedJitCaches} from '@mionjs/core';\nimport {STORAGE_KEY} from '../constants.ts';\n\nimport {deserializeResponseBody} from './serializer.ts';\nimport {getStorage} from './storage.ts';\nimport type {MionRoutes} from '@mionjs/router';\n\ntype GetRemoteMethodsMetadataById = MionRoutes[typeof MION_ROUTES.methodsMetadataById]['handler'];\ntype MethodsMetadataResponse = Awaited<ReturnType<GetRemoteMethodsMetadataById>>;\ntype GlobalErrorRoute = MionRoutes[typeof MION_ROUTES.platformError]['handler'];\ntype GlobalErrorResponse = Awaited<ReturnType<GlobalErrorRoute>>;\n\n/** Manually calls mionGetRemoteMethodsInfoById to get Remote Api Metadata */\nexport async function fetchRemoteMethodsMetadata(methodIds: string[], options: ClientOptions) {\n loadAOTCaches();\n validateClientCaches();\n restoreFromLocalStorage(methodIds, options);\n const missingAfterLocal = methodIds.filter((path) => !routesCache.hasMetadata(path));\n if (!missingAfterLocal.length) return;\n const shouldReturnAllMethods = true;\n const body: RequestBody = {\n [MION_ROUTES.methodsMetadataById]: [missingAfterLocal, shouldReturnAllMethods],\n };\n try {\n const path = getRoutePath([MION_ROUTES.methodsMetadataById], options);\n const url = new URL(path, options.baseURL);\n const response = await fetch(url, {\n method: 'POST',\n headers: {'Content-Type': 'application/json'},\n body: JSON.stringify(body),\n });\n\n const deserialized = await deserializeResponseBody(response);\n const platformError = deserialized[MION_ROUTES.platformError] as GlobalErrorResponse | undefined;\n const serializableMethodsData = deserialized[MION_ROUTES.methodsMetadataById] as MethodsMetadataResponse;\n\n if (isRpcError(platformError)) throw platformError;\n if (isRpcError(serializableMethodsData)) throw serializableMethodsData;\n if (!serializableMethodsData)\n throw new RpcError({\n type: 'cant-fetch-remote-methods-metadata',\n publicMessage: 'Failed to fetch remote methods metadata',\n errorData: {response},\n });\n\n storeDependencies(serializableMethodsData.deps, serializableMethodsData.purFnDeps, options);\n storeMethodsMetadata(serializableMethodsData.methods, options);\n addToCaches(serializableMethodsData);\n } catch (error: any) {\n throw new Error(`Error fetching validation and serialization metadata: ${error?.message}`);\n }\n}\n\nfunction getSerializedMethodDataKey(methodId: string, options: ClientOptions) {\n return `${STORAGE_KEY}:serialized-method-data:${options.baseURL}:${methodId}`;\n}\n\nfunction getJitCompiledFnKey(jitFnHash: string, options: ClientOptions) {\n return `${STORAGE_KEY}:jit-compiled-fn:${options.baseURL}:${jitFnHash}`;\n}\n\nfunction getJitPureFnKey(namespace: string, pureFnHash: string, options: ClientOptions) {\n return `${STORAGE_KEY}:jit-pure-fn:${options.baseURL}:${namespace}:${pureFnHash}`;\n}\n\n/** Stores JIT compiled functions and pure functions globally in localStorage */\nexport function storeDependencies(deps: Record<string, JitCompiledFnData>, pureFnDeps: PureFnsDataCache, options: ClientOptions) {\n Object.entries(deps).forEach(([hash, jitFnData]: [string, JitCompiledFnData]) => {\n const key = getJitCompiledFnKey(hash, options);\n try {\n getStorage().setItem(key, JSON.stringify(jitFnData));\n } catch (error) {\n console.warn(`Failed to store JIT function dependency ${hash}:`, error);\n }\n });\n\n // Store namespaced pure functions\n Object.entries(pureFnDeps).forEach(([namespace, nsPureFns]) => {\n Object.entries(nsPureFns).forEach(([fnHash, pureFnData]: [string, PureFunctionData]) => {\n const key = getJitPureFnKey(namespace, fnHash, options);\n try {\n getStorage().setItem(key, JSON.stringify(pureFnData));\n } catch (error) {\n console.warn(`Failed to store pure function dependency ${namespace}::${fnHash}:`, error);\n }\n });\n });\n}\n\n/** Stores method metadata in localStorage using the new storage format */\nexport function storeMethodsMetadata(methods: MethodsCache, options: ClientOptions) {\n Object.entries(methods).forEach(([methodId, methodData]) => {\n const key = getSerializedMethodDataKey(methodId, options);\n try {\n getStorage().setItem(key, JSON.stringify(methodData));\n } catch (error) {\n console.warn(`Failed to store method metadata ${methodId}:`, error);\n }\n });\n}\n\n/** Restores all JIT compiled functions and pure functions from localStorage and deserializes them */\nexport function restoreAllDependencies(options: ClientOptions) {\n const deps: Record<string, JitCompiledFnData> = {};\n const pureFnDeps: PureFnsDataCache = {};\n const pureFnKeyPrefix = `${STORAGE_KEY}:jit-pure-fn:${options.baseURL}:`;\n\n for (let i = 0; i < getStorage().length; i++) {\n const key = getStorage().key(i);\n if (key?.startsWith(`${STORAGE_KEY}:jit-compiled-fn:${options.baseURL}:`)) {\n try {\n const data = getStorage().getItem(key);\n if (data) {\n const parsedData = JSON.parse(data);\n deps[parsedData.jitFnHash] = parsedData;\n }\n } catch (error) {\n console.warn(`Failed to restore JIT function from key ${key}:`, error);\n }\n }\n }\n\n for (let i = 0; i < getStorage().length; i++) {\n const key = getStorage().key(i);\n if (key?.startsWith(pureFnKeyPrefix)) {\n try {\n const data = getStorage().getItem(key);\n if (data) {\n const parsedData = JSON.parse(data);\n // Extract namespace from key: \"mion:jit-pure-fn:baseURL:namespace:fnHash\"\n const keyParts = key.slice(pureFnKeyPrefix.length).split(':');\n const namespace = keyParts[0] || parsedData.namespace;\n if (!pureFnDeps[namespace]) pureFnDeps[namespace] = {};\n pureFnDeps[namespace][parsedData.fnName] = parsedData;\n }\n } catch (error) {\n console.warn(`Failed to restore pure function from key ${key}:`, error);\n }\n }\n }\n\n if (Object.keys(deps).length > 0 || Object.keys(pureFnDeps).length > 0) {\n addSerializedJitCaches(deps, pureFnDeps);\n }\n}\n\n/** Restores method metadata from localStorage using the new storage format */\nfunction restoreFromLocalStorage(methodIds: string[], options: ClientOptions) {\n restoreAllDependencies(options);\n\n const methods: MethodsCache = {};\n let anyMethodsRestored = false;\n\n methodIds.forEach((id) => {\n if (routesCache.hasMetadata(id)) return;\n const methodKey = getSerializedMethodDataKey(id, options);\n const methodMetaJson = getStorage().getItem(methodKey);\n if (methodMetaJson) {\n try {\n const methodMeta: MethodWithOptions = JSON.parse(methodMetaJson);\n methods[id] = methodMeta;\n anyMethodsRestored = true;\n } catch (error) {\n console.warn(`Failed to restore method metadata for ${id}:`, error);\n getStorage().removeItem(methodKey);\n }\n }\n });\n\n if (anyMethodsRestored) {\n const serializableMethodsData: SerializableMethodsData = {\n methods,\n deps: {},\n purFnDeps: {},\n };\n addToCaches(serializableMethodsData);\n }\n}\n\nfunction addToCaches(serializableMethodsData: SerializableMethodsData) {\n addSerializedJitCaches(serializableMethodsData.deps, serializableMethodsData.purFnDeps);\n addRoutesToCache(serializableMethodsData.methods);\n}\n\n/** Validates that required MION_ROUTES are loaded in the cache. Skipped in test environments. */\nlet clientCachesValidated = false;\nfunction validateClientCaches() {\n if (clientCachesValidated || isTestEnv()) return;\n clientCachesValidated = true;\n\n const requiredRoutes = Object.values(MION_ROUTES);\n const missingRoutes = requiredRoutes.filter((routeId) => !routesCache.hasMetadata(routeId));\n if (missingRoutes.length > 0) {\n throw new Error(\n `AOT cache not loaded: Required MION_ROUTES not found in router cache: ${missingRoutes.join(', ')}. ` +\n `Make sure the AOT caches are generated and bundled correctly.`\n );\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"clientMethodsMetadata.js","sources":["../../../../src/lib/clientMethodsMetadata.ts"],"sourcesContent":["/* ########\n * 2023 mion\n * Author: Ma-jerez\n * License: MIT\n * The software is provided \"as is\", without warranty of any kind.\n * ######## */\n\nimport {isRpcError, addRoutesToCache} from '@mionjs/core';\nimport {MION_ROUTES} from '@mionjs/core';\nimport {ClientOptions, SubRequest} from '../types.ts';\nimport type {\n JitCompiledFnData,\n MethodsCache,\n MethodWithOptions,\n PureFunctionData,\n SerializableMethodsData,\n PureFnsDataCache,\n} from '@mionjs/core';\nimport {routesCache, addSerializedJitCaches} from '@mionjs/core';\nimport {STORAGE_KEY} from '../constants.ts';\nimport {getStorage} from './storage.ts';\n\nconst METHOD_DATA_PREFIX = `${STORAGE_KEY}:method-data:`;\nconst JIT_FN_PREFIX = `${STORAGE_KEY}:jit-fn:`;\nconst PURE_FN_PREFIX = `${STORAGE_KEY}:pure-fn:`;\n\ntype MetadataRouteKey = typeof MION_ROUTES.methodsMetadata | typeof MION_ROUTES.methodsMetadataById;\n\n/** Extracts raw metadata from a parsed response body, unwraps the JIT union discriminator, and processes it. */\nexport function extractAndProcessMetadata(routeKey: MetadataRouteKey, parsedBody: any, options: ClientOptions): void {\n if (typeof parsedBody !== 'object' || !(routeKey in parsedBody)) return;\n const rawMetadata = parsedBody[routeKey];\n delete parsedBody[routeKey];\n if (!rawMetadata) return;\n const metadataValue = Array.isArray(rawMetadata) ? rawMetadata[1] : rawMetadata;\n if (metadataValue && !isRpcError(metadataValue) && metadataValue.methods) {\n processMethodsMetadata(metadataValue as SerializableMethodsData, options);\n }\n}\n\n/** Processes metadata from an optimistic response and caches it */\nfunction processMethodsMetadata(serializableMethodsData: SerializableMethodsData, options: ClientOptions): void {\n storeDependencies(serializableMethodsData.deps, serializableMethodsData.purFnDeps, options);\n storeMethodsMetadata(serializableMethodsData.methods, options);\n addToCaches(serializableMethodsData);\n}\n\nfunction getSerializedMethodDataKey(methodId: string, options: ClientOptions) {\n return `${METHOD_DATA_PREFIX}${methodId}:${options.baseURL}`;\n}\n\nfunction getJitCompiledFnKey(jitFnHash: string, options: ClientOptions) {\n return `${JIT_FN_PREFIX}${jitFnHash}:${options.baseURL}`;\n}\n\nfunction getJitPureFnKey(namespace: string, pureFnHash: string, options: ClientOptions) {\n return `${PURE_FN_PREFIX}${namespace}:${pureFnHash}:${options.baseURL}`;\n}\n\n/** Stores JIT compiled functions and pure functions globally in localStorage */\nexport function storeDependencies(deps: Record<string, JitCompiledFnData>, pureFnDeps: PureFnsDataCache, options: ClientOptions) {\n Object.entries(deps).forEach(([hash, jitFnData]: [string, JitCompiledFnData]) => {\n const key = getJitCompiledFnKey(hash, options);\n try {\n getStorage().setItem(key, JSON.stringify(jitFnData));\n } catch (error) {\n console.warn(`Failed to store JIT function dependency ${hash}:`, error);\n }\n });\n\n // Store namespaced pure functions\n Object.entries(pureFnDeps).forEach(([namespace, nsPureFns]) => {\n Object.entries(nsPureFns).forEach(([fnHash, pureFnData]: [string, PureFunctionData]) => {\n const key = getJitPureFnKey(namespace, fnHash, options);\n try {\n getStorage().setItem(key, JSON.stringify(pureFnData));\n } catch (error) {\n console.warn(`Failed to store pure function dependency ${namespace}::${fnHash}:`, error);\n }\n });\n });\n}\n\n/** Stores method metadata in localStorage using the new storage format */\nexport function storeMethodsMetadata(methods: MethodsCache, options: ClientOptions) {\n Object.entries(methods).forEach(([methodId, methodData]) => {\n const key = getSerializedMethodDataKey(methodId, options);\n try {\n getStorage().setItem(key, JSON.stringify(methodData));\n } catch (error) {\n console.warn(`Failed to store method metadata ${methodId}:`, error);\n }\n });\n}\n\n/** Restores all JIT compiled functions and pure functions from localStorage and deserializes them */\nexport function restoreAllDependencies(options: ClientOptions) {\n const deps: Record<string, JitCompiledFnData> = {};\n const pureFnDeps: PureFnsDataCache = {};\n const baseURLSuffix = `:${options.baseURL}`;\n\n for (let i = 0; i < getStorage().length; i++) {\n const key = getStorage().key(i);\n if (key?.startsWith(JIT_FN_PREFIX) && key.endsWith(baseURLSuffix)) {\n try {\n const data = getStorage().getItem(key);\n if (data) {\n const parsedData = JSON.parse(data);\n deps[parsedData.jitFnHash] = parsedData;\n }\n } catch (error) {\n console.warn(`Failed to restore JIT function from key ${key}:`, error);\n }\n }\n }\n\n for (let i = 0; i < getStorage().length; i++) {\n const key = getStorage().key(i);\n if (key?.startsWith(PURE_FN_PREFIX) && key.endsWith(baseURLSuffix)) {\n try {\n const data = getStorage().getItem(key);\n if (data) {\n const parsedData = JSON.parse(data);\n // Extract namespace from key: \"mion:pure-fn:namespace:fnHash:baseURL\"\n const inner = key.slice(PURE_FN_PREFIX.length, key.length - baseURLSuffix.length);\n const namespace = inner.split(':')[0] || parsedData.namespace;\n if (!pureFnDeps[namespace]) pureFnDeps[namespace] = {};\n pureFnDeps[namespace][parsedData.fnName] = parsedData;\n }\n } catch (error) {\n console.warn(`Failed to restore pure function from key ${key}:`, error);\n }\n }\n }\n\n if (Object.keys(deps).length > 0 || Object.keys(pureFnDeps).length > 0) {\n addSerializedJitCaches(deps, pureFnDeps);\n }\n}\n\n/** Creates a SubRequest for the metadata middleware to piggyback on an optimistic request */\nexport function createMetadataSubRequest(methodIds: string[]): SubRequest<any> {\n return {\n pointer: [MION_ROUTES.methodsMetadata],\n id: MION_ROUTES.methodsMetadata,\n isResolved: false,\n params: [methodIds],\n };\n}\n\n/** Restores method metadata from localStorage using the new storage format */\nexport function restoreFromLocalStorage(methodIds: string[], options: ClientOptions) {\n restoreAllDependencies(options);\n\n const methods: MethodsCache = {};\n let anyMethodsRestored = false;\n\n methodIds.forEach((id) => {\n if (routesCache.hasMetadata(id)) return;\n const methodKey = getSerializedMethodDataKey(id, options);\n const methodMetaJson = getStorage().getItem(methodKey);\n if (methodMetaJson) {\n try {\n const methodMeta: MethodWithOptions = JSON.parse(methodMetaJson);\n methods[id] = methodMeta;\n anyMethodsRestored = true;\n } catch (error) {\n console.warn(`Failed to restore method metadata for ${id}:`, error);\n getStorage().removeItem(methodKey);\n }\n }\n });\n\n if (anyMethodsRestored) {\n const serializableMethodsData: SerializableMethodsData = {\n methods,\n deps: {},\n purFnDeps: {},\n };\n addToCaches(serializableMethodsData);\n }\n}\n\nfunction addToCaches(serializableMethodsData: SerializableMethodsData) {\n addSerializedJitCaches(serializableMethodsData.deps, serializableMethodsData.purFnDeps);\n addRoutesToCache(serializableMethodsData.methods);\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { ClientOptions } from '../types.ts';
2
+ export declare function fetchRemoteMethodsMetadata(methodIds: string[], options: ClientOptions, signal?: AbortSignal): Promise<void>;
@@ -0,0 +1,31 @@
1
+ import { routesCache, MION_ROUTES, getRoutePath, isRpcError } from "@mionjs/core";
2
+ import { restoreFromLocalStorage } from "./clientMethodsMetadata.js";
3
+ import { deserializeResponseBody } from "./serializer.js";
4
+ async function fetchRemoteMethodsMetadata(methodIds, options, signal) {
5
+ restoreFromLocalStorage(methodIds, options);
6
+ const missingAfterLocal = methodIds.filter((path) => !routesCache.hasMetadata(path));
7
+ if (!missingAfterLocal.length)
8
+ return;
9
+ const body = {
10
+ [MION_ROUTES.methodsMetadataById]: [missingAfterLocal]
11
+ };
12
+ try {
13
+ const path = getRoutePath([MION_ROUTES.methodsMetadataById], options), url = new URL(path, options.baseURL), response = await fetch(url, {
14
+ method: "POST",
15
+ headers: { "Content-Type": "application/json" },
16
+ body: JSON.stringify(body),
17
+ signal
18
+ }), platformError = (await deserializeResponseBody(response, options))[MION_ROUTES.platformError];
19
+ if (isRpcError(platformError))
20
+ throw platformError;
21
+ const stillMissing = missingAfterLocal.filter((id) => !routesCache.hasMetadata(id));
22
+ if (stillMissing.length)
23
+ throw new Error(`Failed to fetch metadata for: ${stillMissing.join(", ")}`);
24
+ } catch (error) {
25
+ throw signal?.aborted ? error : new Error(`Error fetching validation and serialization metadata: ${error?.message}`);
26
+ }
27
+ }
28
+ export {
29
+ fetchRemoteMethodsMetadata
30
+ };
31
+ //# sourceMappingURL=fetchRemoteMethodsMetadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetchRemoteMethodsMetadata.js","sources":["../../../../src/lib/fetchRemoteMethodsMetadata.ts"],"sourcesContent":["/* ########\n * 2023 mion\n * Author: Ma-jerez\n * License: MIT\n * The software is provided \"as is\", without warranty of any kind.\n * ######## */\n\nimport {isRpcError, MION_ROUTES, getRoutePath, routesCache} from '@mionjs/core';\nimport {ClientOptions, RequestBody} from '../types.ts';\nimport {restoreFromLocalStorage} from './clientMethodsMetadata.ts';\nimport {deserializeResponseBody} from './serializer.ts';\n\n/** Manually calls mionGetRemoteMethodsInfoById to get Remote Api Metadata */\nexport async function fetchRemoteMethodsMetadata(\n methodIds: string[],\n options: ClientOptions,\n signal?: AbortSignal\n): Promise<void> {\n restoreFromLocalStorage(methodIds, options);\n const missingAfterLocal = methodIds.filter((path) => !routesCache.hasMetadata(path));\n if (!missingAfterLocal.length) return;\n const body: RequestBody = {\n [MION_ROUTES.methodsMetadataById]: [missingAfterLocal],\n };\n try {\n const path = getRoutePath([MION_ROUTES.methodsMetadataById], options);\n const url = new URL(path, options.baseURL);\n const response = await fetch(url, {\n method: 'POST',\n headers: {'Content-Type': 'application/json'},\n body: JSON.stringify(body),\n signal,\n });\n const deserialized = await deserializeResponseBody(response, options);\n const platformError = deserialized[MION_ROUTES.platformError];\n if (isRpcError(platformError)) throw platformError;\n const stillMissing = missingAfterLocal.filter((id) => !routesCache.hasMetadata(id));\n if (stillMissing.length) throw new Error(`Failed to fetch metadata for: ${stillMissing.join(', ')}`);\n } catch (error: any) {\n // Preserve abort/timeout DOMException so the caller's onError can classify it correctly\n if (signal?.aborted) throw error;\n throw new Error(`Error fetching validation and serialization metadata: ${error?.message}`);\n }\n}\n"],"names":[],"mappings":";;;AAaA,eAAsB,2BAClB,WACA,SACA,QAAoB;AAEpB,0BAAwB,WAAW,OAAO;AAC1C,QAAM,oBAAoB,UAAU,OAAO,CAAC,SAAS,CAAC,YAAY,YAAY,IAAI,CAAC;AACnF,MAAI,CAAC,kBAAkB;AAAQ;AAC/B,QAAM,OAAoB;AAAA,IACtB,CAAC,YAAY,mBAAmB,GAAG,CAAC,iBAAiB;AAAA,EAAA;AAEzD,MAAI;AACA,UAAM,OAAO,aAAa,CAAC,YAAY,mBAAmB,GAAG,OAAO,GAC9D,MAAM,IAAI,IAAI,MAAM,QAAQ,OAAO,GACnC,WAAW,MAAM,MAAM,KAAK;AAAA,MAC9B,QAAQ;AAAA,MACR,SAAS,EAAC,gBAAgB,mBAAA;AAAA,MAC1B,MAAM,KAAK,UAAU,IAAI;AAAA,MACzB;AAAA,IAAA,CACH,GAEK,iBADe,MAAM,wBAAwB,UAAU,OAAO,GACjC,YAAY,aAAa;AAC5D,QAAI,WAAW,aAAa;AAAG,YAAM;AACrC,UAAM,eAAe,kBAAkB,OAAO,CAAC,OAAO,CAAC,YAAY,YAAY,EAAE,CAAC;AAClF,QAAI,aAAa;AAAQ,YAAM,IAAI,MAAM,iCAAiC,aAAa,KAAK,IAAI,CAAC,EAAE;AAAA,EACvG,SAAS,OAAY;AAEjB,UAAI,QAAQ,UAAe,QACrB,IAAI,MAAM,yDAAyD,OAAO,OAAO,EAAE;AAAA,EAC7F;AACJ;"}
@@ -1,5 +1,6 @@
1
1
  import { ResponseBody } from '@mionjs/router';
2
2
  import { MionClientRequest } from '../request.ts';
3
+ import { ClientOptions } from '../types.ts';
3
4
  export type SerializedBody = string | Uint8Array;
4
5
  export type ContentType = 'application/json; charset=utf-8' | 'application/octet-stream';
5
6
  export interface SerializedRequest {
@@ -7,4 +8,4 @@ export interface SerializedRequest {
7
8
  contentType: ContentType;
8
9
  }
9
10
  export declare function serializeRequestBody(req: MionClientRequest<any, any>): SerializedRequest;
10
- export declare function deserializeResponseBody(response: Response): Promise<ResponseBody>;
11
+ export declare function deserializeResponseBody(response: Response, options: ClientOptions): Promise<ResponseBody>;
@@ -1,16 +1,18 @@
1
- import { MION_ROUTES, isRpcError, RpcError, routesCache, deserializeBinaryBody, HandlerType, serializeBinaryBody as serializeBinaryBody$1 } from "@mionjs/core";
1
+ import { RpcError, deserializeBinaryBody, MION_ROUTES, routesCache, HandlerType, serializeBinaryBody as serializeBinaryBody$1, isRpcError } from "@mionjs/core";
2
2
  import { DEFAULT_PREFILL_OPTIONS } from "../constants.js";
3
- function getSerializerMode(req) {
4
- const methodId = req.route?.id ?? req.workflowSubRequests?.[0]?.id, serializerMode = routesCache.getMethodJitFns(methodId)?.options.serializer || DEFAULT_PREFILL_OPTIONS.serializer;
5
- return serializerMode === "json" ? DEFAULT_PREFILL_OPTIONS.serializer : serializerMode;
6
- }
3
+ import { extractAndProcessMetadata } from "./clientMethodsMetadata.js";
7
4
  function serializeRequestBody(req) {
8
5
  const serializerMode = getSerializerMode(req);
9
6
  switch (serializerMode) {
10
7
  case "json":
11
8
  case "stringifyJson":
12
9
  return {
13
- body: stringifyBody(req),
10
+ body: serializeJsonBody(req),
11
+ contentType: "application/json; charset=utf-8"
12
+ };
13
+ case "optimistic":
14
+ return {
15
+ body: serializeJSonBodyOptimistic(req),
14
16
  contentType: "application/json; charset=utf-8"
15
17
  };
16
18
  case "binary":
@@ -22,51 +24,7 @@ function serializeRequestBody(req) {
22
24
  throw new Error(`Invalid serializer mode ${serializerMode}`);
23
25
  }
24
26
  }
25
- function serializeBinaryBody(req) {
26
- const subRequestIds = Object.keys(req.subRequestList), body = {}, executionChain = [];
27
- for (const id of subRequestIds) {
28
- let params = req.subRequestList[id].params;
29
- const method = routesCache.useMethodJitFns(id);
30
- method.type === HandlerType.headersMiddleFn && method.headersParam && (params = getParamsWithoutHeadersSubset(params)), body[id] = params, executionChain.push(method);
31
- }
32
- const workflowRouteIds = req.workflowSubRequests?.map((sr) => sr.id), { buffer } = serializeBinaryBody$1(req.path, executionChain, body, !1, workflowRouteIds);
33
- return new Uint8Array(buffer);
34
- }
35
- async function deserializeResponseBody(response) {
36
- const contentType = response.headers.get("content-type"), isJson = contentType?.includes("application/json"), isBinary = contentType?.includes("application/octet-stream");
37
- let parsedBody;
38
- if (isJson ? parsedBody = await deserializeJsonResponseBody(response) : isBinary ? parsedBody = await deserializeBinaryResponseBody(response) : parsedBody = await deserializeJsonResponseBody(response), MION_ROUTES.thrownErrors in parsedBody) {
39
- const unexpectedErrors = parsedBody[MION_ROUTES.thrownErrors];
40
- if (MION_ROUTES.platformError in unexpectedErrors) {
41
- const globalErrorValue = unexpectedErrors[MION_ROUTES.platformError], platformError = isRpcError(globalErrorValue) ? new RpcError(globalErrorValue) : globalErrorValue;
42
- return { [MION_ROUTES.platformError]: platformError };
43
- }
44
- Object.assign(parsedBody, unexpectedErrors), delete parsedBody[MION_ROUTES.thrownErrors];
45
- }
46
- if (isJson || !isJson && !isBinary) {
47
- const deserializedBody = {};
48
- return Object.entries(parsedBody).forEach(([methodId, returnValue]) => {
49
- const method = routesCache.useMethodJitFns(methodId), deserialized = parseHandlerReturnValue(method, returnValue);
50
- deserializedBody[methodId] = deserialized;
51
- }), deserializedBody;
52
- }
53
- return parsedBody;
54
- }
55
- async function deserializeJsonResponseBody(response) {
56
- try {
57
- return await response.json();
58
- } catch (err) {
59
- throw new RpcError({
60
- type: "parsing-json-response-error",
61
- publicMessage: `Invalid json response body: ${err?.message || "unknown parsing error."}`
62
- });
63
- }
64
- }
65
- async function deserializeBinaryResponseBody(response) {
66
- const arrayBuffer = await response.arrayBuffer(), { body } = deserializeBinaryBody("client-response", arrayBuffer, !0);
67
- return body;
68
- }
69
- function stringifyBody(req) {
27
+ function serializeJsonBody(req) {
70
28
  const props = [], subRequestIds = Object.keys(req.subRequestList);
71
29
  for (let i = 0; i < subRequestIds.length; i++) {
72
30
  const id = subRequestIds[i], subRequest = req.subRequestList[id];
@@ -90,8 +48,23 @@ function stringifyBody(req) {
90
48
  }
91
49
  return `{${props.join(",")}}`;
92
50
  }
93
- function getParamsWithoutHeadersSubset(params) {
94
- return !params || params.length === 0 ? [] : params.slice(1);
51
+ function serializeJSonBodyOptimistic(req) {
52
+ const body = {}, subRequestIds = Object.keys(req.subRequestList);
53
+ for (const id of subRequestIds) {
54
+ const subRequest = req.subRequestList[id];
55
+ subRequest && (body[id] = subRequest.params);
56
+ }
57
+ return JSON.stringify(body);
58
+ }
59
+ function serializeBinaryBody(req) {
60
+ const subRequestIds = Object.keys(req.subRequestList), body = {}, executionChain = [];
61
+ for (const id of subRequestIds) {
62
+ let params = req.subRequestList[id].params;
63
+ const method = routesCache.useMethodJitFns(id);
64
+ method.type === HandlerType.headersMiddleFn && method.headersParam && (params = getParamsWithoutHeadersSubset(params)), body[id] = params, executionChain.push(method);
65
+ }
66
+ const workflowRouteIds = req.workflowSubRequests?.map((sr) => sr.id), { buffer } = serializeBinaryBody$1(req.path, executionChain, body, !1, workflowRouteIds);
67
+ return new Uint8Array(buffer);
95
68
  }
96
69
  function stringifyHandlerParams(method, params) {
97
70
  if (!method.paramNames || method.paramNames.length === 0)
@@ -99,7 +72,67 @@ function stringifyHandlerParams(method, params) {
99
72
  const paramsJit = method.paramsJitFns;
100
73
  return paramsJit.prepareForJson.isNoop ? JSON.stringify(params) : paramsJit.stringifyJson.fn(params);
101
74
  }
102
- function parseHandlerReturnValue(method, returnValue) {
75
+ async function deserializeResponseBody(response, options) {
76
+ let parsedBody;
77
+ const contentType = response.headers.get("content-type")?.toLowerCase();
78
+ switch (!0) {
79
+ case !!contentType?.includes("application/json"):
80
+ parsedBody = await deserializeJsonResponseBody(response, options);
81
+ break;
82
+ case !!contentType?.includes("application/octet-stream"):
83
+ parsedBody = await deserializeBinaryResponseBody(response);
84
+ break;
85
+ default:
86
+ throw new RpcError({
87
+ type: "unsupported-content-type",
88
+ publicMessage: `Unsupported response content-type: '${contentType || "none"}'`
89
+ });
90
+ }
91
+ return parsedBody;
92
+ }
93
+ async function deserializeJsonResponseBody(response, options) {
94
+ try {
95
+ const parsedBody = await response.json();
96
+ extractAndProcessMetadata(MION_ROUTES.methodsMetadata, parsedBody, options), extractAndProcessMetadata(MION_ROUTES.methodsMetadataById, parsedBody, options);
97
+ const platformError = unwrapUnexpectedErrors(parsedBody);
98
+ if (platformError)
99
+ return { [MION_ROUTES.platformError]: platformError };
100
+ const deserializedBody = {};
101
+ return Object.entries(parsedBody).forEach(([methodId, returnValue]) => {
102
+ const method = routesCache.useMethodJitFns(methodId);
103
+ deserializedBody[methodId] = parseHandlerJsonReturnValue(method, returnValue);
104
+ }), deserializedBody;
105
+ } catch (err) {
106
+ throw new RpcError({
107
+ type: "parsing-json-response-error",
108
+ publicMessage: `Invalid json response body: ${err?.message || "unknown parsing error."}`
109
+ });
110
+ }
111
+ }
112
+ async function deserializeBinaryResponseBody(response) {
113
+ const arrayBuffer = await response.arrayBuffer(), { body } = deserializeBinaryBody("client-response", arrayBuffer, !0), platformError = unwrapUnexpectedErrors(body);
114
+ return platformError ? { [MION_ROUTES.platformError]: platformError } : body;
115
+ }
116
+ function unwrapUnexpectedErrors(parsedBody) {
117
+ if (!(MION_ROUTES.thrownErrors in parsedBody))
118
+ return;
119
+ const unexpectedErrors = parsedBody[MION_ROUTES.thrownErrors];
120
+ if (MION_ROUTES.platformError in unexpectedErrors) {
121
+ const globalErrorValue = unexpectedErrors[MION_ROUTES.platformError];
122
+ return isRpcError(globalErrorValue) ? new RpcError(globalErrorValue) : globalErrorValue;
123
+ }
124
+ Object.assign(parsedBody, unexpectedErrors), delete parsedBody[MION_ROUTES.thrownErrors];
125
+ }
126
+ function getSerializerMode(req) {
127
+ if (req.options.serializer === "optimistic")
128
+ return Object.keys(req.subRequestList).every((id) => routesCache.hasMetadata(id)) ? "stringifyJson" : "optimistic";
129
+ const methodId = req.route?.id ?? req.workflowSubRequests?.[0]?.id, serializerMode = routesCache.getMethodJitFns(methodId)?.options.serializer || DEFAULT_PREFILL_OPTIONS.serializer;
130
+ return serializerMode === "json" ? DEFAULT_PREFILL_OPTIONS.serializer : serializerMode;
131
+ }
132
+ function getParamsWithoutHeadersSubset(params) {
133
+ return !params || params.length === 0 ? [] : params.slice(1);
134
+ }
135
+ function parseHandlerJsonReturnValue(method, returnValue) {
103
136
  if (!method.hasReturnData)
104
137
  return returnValue;
105
138
  const returnJit = method.returnJitFns;
@@ -1 +1 @@
1
- {"version":3,"file":"serializer.js","sources":["../../../../src/lib/serializer.ts"],"sourcesContent":["/* ########\n * 2023 mion\n * Author: Ma-jerez\n * License: MIT\n * The software is provided \"as is\", without warranty of any kind.\n * ######## */\n\nimport type {ResponseBody} from '@mionjs/router';\nimport {\n type MethodWithJitFns,\n RpcError,\n isRpcError,\n routesCache,\n MION_ROUTES,\n HandlerType,\n type SerializerMode,\n serializeBinaryBody as coreSerializeBinaryBody,\n deserializeBinaryBody as coreDeserializeBinaryBody,\n} from '@mionjs/core';\nimport type {MionClientRequest} from '../request.ts';\nimport {DEFAULT_PREFILL_OPTIONS} from '../constants.ts';\n\n/** Result of serializing a request body - can be string (JSON) or Uint8Array (binary) */\nexport type SerializedBody = string | Uint8Array;\n\n/** Content-type header value for the serialized body */\nexport type ContentType = 'application/json; charset=utf-8' | 'application/octet-stream';\n\n/** Result of serializing a request body with its content type */\nexport interface SerializedRequest {\n body: SerializedBody;\n contentType: ContentType;\n}\n\n/** Determines the serializer mode to use for a request */\nfunction getSerializerMode(req: MionClientRequest<any, any>): SerializerMode {\n const methodId = req.route?.id ?? req.workflowSubRequests?.[0]?.id;\n const method = routesCache.getMethodJitFns(methodId);\n const serializerMode = method?.options.serializer || DEFAULT_PREFILL_OPTIONS.serializer;\n if (serializerMode === 'json') return DEFAULT_PREFILL_OPTIONS.serializer;\n return serializerMode;\n}\n\n/** Serializes the request body and returns it with the appropriate content type */\nexport function serializeRequestBody(req: MionClientRequest<any, any>): SerializedRequest {\n const serializerMode = getSerializerMode(req);\n\n switch (serializerMode) {\n case 'json':\n case 'stringifyJson':\n return {\n body: stringifyBody(req),\n contentType: 'application/json; charset=utf-8',\n };\n case 'binary':\n return {\n body: serializeBinaryBody(req),\n contentType: 'application/octet-stream',\n };\n default:\n throw new Error(`Invalid serializer mode ${serializerMode}`);\n }\n}\n\n/** Serializes request body to binary format */\nfunction serializeBinaryBody(req: MionClientRequest<any, any>): Uint8Array {\n const subRequestIds = Object.keys(req.subRequestList);\n const body: Record<string, any> = {};\n const executionChain: MethodWithJitFns[] = [];\n\n for (const id of subRequestIds) {\n const subRequest = req.subRequestList[id];\n let params = subRequest.params;\n const method = routesCache.useMethodJitFns(id);\n\n if (method.type === HandlerType.headersMiddleFn && method.headersParam) {\n params = getParamsWithoutHeadersSubset(params);\n }\n\n body[id] = params;\n executionChain.push(method);\n }\n\n const workflowRouteIds = req.workflowSubRequests?.map((sr) => sr.id);\n const {buffer} = coreSerializeBinaryBody(req.path, executionChain, body, false, workflowRouteIds);\n return new Uint8Array(buffer);\n}\n\n/** Deserializes the response body from a fetch Response object */\nexport async function deserializeResponseBody(response: Response): Promise<ResponseBody> {\n const contentType = response.headers.get('content-type');\n const isJson = contentType?.includes('application/json');\n const isBinary = contentType?.includes('application/octet-stream');\n\n let parsedBody: any;\n\n if (isJson) {\n parsedBody = await deserializeJsonResponseBody(response);\n } else if (isBinary) {\n parsedBody = await deserializeBinaryResponseBody(response);\n } else {\n parsedBody = await deserializeJsonResponseBody(response);\n }\n\n if (MION_ROUTES.thrownErrors in parsedBody) {\n const unexpectedErrors = parsedBody[MION_ROUTES.thrownErrors];\n\n if (MION_ROUTES.platformError in unexpectedErrors) {\n const globalErrorValue = unexpectedErrors[MION_ROUTES.platformError];\n const platformError = isRpcError(globalErrorValue) ? new RpcError(globalErrorValue) : globalErrorValue;\n return {[MION_ROUTES.platformError]: platformError};\n }\n\n Object.assign(parsedBody, unexpectedErrors);\n delete parsedBody[MION_ROUTES.thrownErrors];\n }\n\n if (isJson || (!isJson && !isBinary)) {\n const deserializedBody: ResponseBody = {};\n Object.entries(parsedBody).forEach(([methodId, returnValue]) => {\n const method = routesCache.useMethodJitFns(methodId);\n const deserialized = parseHandlerReturnValue(method, returnValue);\n deserializedBody[methodId] = deserialized;\n });\n return deserializedBody;\n }\n\n return parsedBody;\n}\n\n/** Deserializes JSON response body */\nasync function deserializeJsonResponseBody(response: Response): Promise<any> {\n try {\n return await response.json();\n } catch (err: any) {\n throw new RpcError({\n type: 'parsing-json-response-error',\n publicMessage: `Invalid json response body: ${err?.message || 'unknown parsing error.'}`,\n });\n }\n}\n\n/** Deserializes binary response body */\nasync function deserializeBinaryResponseBody(response: Response): Promise<ResponseBody> {\n const arrayBuffer = await response.arrayBuffer();\n const {body} = coreDeserializeBinaryBody('client-response', arrayBuffer, true);\n return body;\n}\n\nfunction stringifyBody(req: MionClientRequest<any, any>): string {\n const props: string[] = [];\n const subRequestIds = Object.keys(req.subRequestList);\n\n for (let i = 0; i < subRequestIds.length; i++) {\n const id = subRequestIds[i];\n const subRequest = req.subRequestList[id];\n if (!subRequest) continue;\n let params = subRequest.params;\n const method = routesCache.useMethodJitFns(id);\n\n if (method.type === HandlerType.headersMiddleFn && method.headersParam) {\n params = getParamsWithoutHeadersSubset(params);\n }\n\n try {\n const jsonValue = stringifyHandlerParams(method, params);\n if (!jsonValue) continue;\n props.push(`${JSON.stringify(id)}:${jsonValue}`);\n } catch (e: any) {\n const err = new RpcError({\n type: 'json-stringify-request-error',\n publicMessage: `Failed to stringify params for handler ${id}`,\n originalError: e,\n });\n throw err;\n }\n }\n\n return `{${props.join(',')}}`;\n}\n\n/** Returns params array without the HeadersSubset (first param) */\nfunction getParamsWithoutHeadersSubset(params: any[]): any[] {\n if (!params || params.length === 0) return [];\n return params.slice(1);\n}\n\nfunction stringifyHandlerParams(method: MethodWithJitFns, params: any[]): string {\n if (!method.paramNames || method.paramNames.length === 0) return '';\n const paramsJit = method.paramsJitFns;\n if (paramsJit.prepareForJson.isNoop) return JSON.stringify(params);\n return paramsJit.stringifyJson.fn(params);\n}\n\nfunction parseHandlerReturnValue(method: MethodWithJitFns, returnValue: any): any {\n if (!method.hasReturnData) return returnValue;\n const returnJit = method.returnJitFns;\n if (returnJit.restoreFromJson.isNoop || !returnValue) return returnValue;\n\n try {\n if (returnValue instanceof RpcError) return returnValue;\n if (isRpcError(returnValue)) return new RpcError(returnValue);\n return returnJit.restoreFromJson.fn(returnValue);\n } catch (e: any) {\n return new RpcError({\n type: 'deserialization-error',\n publicMessage: `Invalid response from Route or MiddleFn '${method.id}', can not deserialize return value: ${e.message}`,\n errorData: e?.errors,\n });\n }\n}\n"],"names":["coreSerializeBinaryBody","coreDeserializeBinaryBody"],"mappings":";;AAmCA,SAAS,kBAAkB,KAAgC;AACvD,QAAM,WAAW,IAAI,OAAO,MAAM,IAAI,sBAAsB,CAAC,GAAG,IAE1D,iBADS,YAAY,gBAAgB,QAAQ,GACpB,QAAQ,cAAc,wBAAwB;AAC7E,SAAI,mBAAmB,SAAe,wBAAwB,aACvD;AACX;AAGM,SAAU,qBAAqB,KAAgC;AACjE,QAAM,iBAAiB,kBAAkB,GAAG;AAE5C,UAAQ,gBAAA;AAAA,IACJ,KAAK;AAAA,IACL,KAAK;AACD,aAAO;AAAA,QACH,MAAM,cAAc,GAAG;AAAA,QACvB,aAAa;AAAA,MAAA;AAAA,IAErB,KAAK;AACD,aAAO;AAAA,QACH,MAAM,oBAAoB,GAAG;AAAA,QAC7B,aAAa;AAAA,MAAA;AAAA,IAErB;AACI,YAAM,IAAI,MAAM,2BAA2B,cAAc,EAAE;AAAA,EAAA;AAEvE;AAGA,SAAS,oBAAoB,KAAgC;AACzD,QAAM,gBAAgB,OAAO,KAAK,IAAI,cAAc,GAC9C,OAA4B,CAAA,GAC5B,iBAAqC,CAAA;AAE3C,aAAW,MAAM,eAAe;AAE5B,QAAI,SADe,IAAI,eAAe,EAAE,EAChB;AACxB,UAAM,SAAS,YAAY,gBAAgB,EAAE;AAE7C,IAAI,OAAO,SAAS,YAAY,mBAAmB,OAAO,iBACtD,SAAS,8BAA8B,MAAM,IAGjD,KAAK,EAAE,IAAI,QACX,eAAe,KAAK,MAAM;AAAA,EAC9B;AAEA,QAAM,mBAAmB,IAAI,qBAAqB,IAAI,CAAC,OAAO,GAAG,EAAE,GAC7D,EAAC,WAAUA,sBAAwB,IAAI,MAAM,gBAAgB,MAAM,IAAO,gBAAgB;AAChG,SAAO,IAAI,WAAW,MAAM;AAChC;AAGA,eAAsB,wBAAwB,UAAkB;AAC5D,QAAM,cAAc,SAAS,QAAQ,IAAI,cAAc,GACjD,SAAS,aAAa,SAAS,kBAAkB,GACjD,WAAW,aAAa,SAAS,0BAA0B;AAEjE,MAAI;AAUJ,MARI,SACA,aAAa,MAAM,4BAA4B,QAAQ,IAChD,WACP,aAAa,MAAM,8BAA8B,QAAQ,IAEzD,aAAa,MAAM,4BAA4B,QAAQ,GAGvD,YAAY,gBAAgB,YAAY;AACxC,UAAM,mBAAmB,WAAW,YAAY,YAAY;AAE5D,QAAI,YAAY,iBAAiB,kBAAkB;AAC/C,YAAM,mBAAmB,iBAAiB,YAAY,aAAa,GAC7D,gBAAgB,WAAW,gBAAgB,IAAI,IAAI,SAAS,gBAAgB,IAAI;AACtF,aAAO,EAAC,CAAC,YAAY,aAAa,GAAG,cAAA;AAAA,IACzC;AAEA,WAAO,OAAO,YAAY,gBAAgB,GAC1C,OAAO,WAAW,YAAY,YAAY;AAAA,EAC9C;AAEA,MAAI,UAAW,CAAC,UAAU,CAAC,UAAW;AAClC,UAAM,mBAAiC,CAAA;AACvC,kBAAO,QAAQ,UAAU,EAAE,QAAQ,CAAC,CAAC,UAAU,WAAW,MAAK;AAC3D,YAAM,SAAS,YAAY,gBAAgB,QAAQ,GAC7C,eAAe,wBAAwB,QAAQ,WAAW;AAChE,uBAAiB,QAAQ,IAAI;AAAA,IACjC,CAAC,GACM;AAAA,EACX;AAEA,SAAO;AACX;AAGA,eAAe,4BAA4B,UAAkB;AACzD,MAAI;AACA,WAAO,MAAM,SAAS,KAAA;AAAA,EAC1B,SAAS,KAAU;AACf,UAAM,IAAI,SAAS;AAAA,MACf,MAAM;AAAA,MACN,eAAe,+BAA+B,KAAK,WAAW,wBAAwB;AAAA,IAAA,CACzF;AAAA,EACL;AACJ;AAGA,eAAe,8BAA8B,UAAkB;AAC3D,QAAM,cAAc,MAAM,SAAS,YAAA,GAC7B,EAAC,KAAA,IAAQC,sBAA0B,mBAAmB,aAAa,EAAI;AAC7E,SAAO;AACX;AAEA,SAAS,cAAc,KAAgC;AACnD,QAAM,QAAkB,CAAA,GAClB,gBAAgB,OAAO,KAAK,IAAI,cAAc;AAEpD,WAAS,IAAI,GAAG,IAAI,cAAc,QAAQ,KAAK;AAC3C,UAAM,KAAK,cAAc,CAAC,GACpB,aAAa,IAAI,eAAe,EAAE;AACxC,QAAI,CAAC;AAAY;AACjB,QAAI,SAAS,WAAW;AACxB,UAAM,SAAS,YAAY,gBAAgB,EAAE;AAE7C,IAAI,OAAO,SAAS,YAAY,mBAAmB,OAAO,iBACtD,SAAS,8BAA8B,MAAM;AAGjD,QAAI;AACA,YAAM,YAAY,uBAAuB,QAAQ,MAAM;AACvD,UAAI,CAAC;AAAW;AAChB,YAAM,KAAK,GAAG,KAAK,UAAU,EAAE,CAAC,IAAI,SAAS,EAAE;AAAA,IACnD,SAAS,GAAQ;AAMb,YALY,IAAI,SAAS;AAAA,QACrB,MAAM;AAAA,QACN,eAAe,0CAA0C,EAAE;AAAA,QAC3D,eAAe;AAAA,MAAA,CAClB;AAAA,IAEL;AAAA,EACJ;AAEA,SAAO,IAAI,MAAM,KAAK,GAAG,CAAC;AAC9B;AAGA,SAAS,8BAA8B,QAAa;AAChD,SAAI,CAAC,UAAU,OAAO,WAAW,IAAU,CAAA,IACpC,OAAO,MAAM,CAAC;AACzB;AAEA,SAAS,uBAAuB,QAA0B,QAAa;AACnE,MAAI,CAAC,OAAO,cAAc,OAAO,WAAW,WAAW;AAAG,WAAO;AACjE,QAAM,YAAY,OAAO;AACzB,SAAI,UAAU,eAAe,SAAe,KAAK,UAAU,MAAM,IAC1D,UAAU,cAAc,GAAG,MAAM;AAC5C;AAEA,SAAS,wBAAwB,QAA0B,aAAgB;AACvE,MAAI,CAAC,OAAO;AAAe,WAAO;AAClC,QAAM,YAAY,OAAO;AACzB,MAAI,UAAU,gBAAgB,UAAU,CAAC;AAAa,WAAO;AAE7D,MAAI;AACA,WAAI,uBAAuB,WAAiB,cACxC,WAAW,WAAW,IAAU,IAAI,SAAS,WAAW,IACrD,UAAU,gBAAgB,GAAG,WAAW;AAAA,EACnD,SAAS,GAAQ;AACb,WAAO,IAAI,SAAS;AAAA,MAChB,MAAM;AAAA,MACN,eAAe,4CAA4C,OAAO,EAAE,wCAAwC,EAAE,OAAO;AAAA,MACrH,WAAW,GAAG;AAAA,IAAA,CACjB;AAAA,EACL;AACJ;"}
1
+ {"version":3,"file":"serializer.js","sources":["../../../../src/lib/serializer.ts"],"sourcesContent":["/* ########\n * 2023 mion\n * Author: Ma-jerez\n * License: MIT\n * The software is provided \"as is\", without warranty of any kind.\n * ######## */\n\nimport type {ResponseBody} from '@mionjs/router';\nimport {\n type MethodWithJitFns,\n RpcError,\n isRpcError,\n routesCache,\n MION_ROUTES,\n HandlerType,\n type SerializerMode,\n serializeBinaryBody as coreSerializeBinaryBody,\n deserializeBinaryBody as coreDeserializeBinaryBody,\n} from '@mionjs/core';\nimport type {MionClientRequest} from '../request.ts';\nimport {DEFAULT_PREFILL_OPTIONS} from '../constants.ts';\nimport {extractAndProcessMetadata} from './clientMethodsMetadata.ts';\nimport {ClientOptions} from '../types.ts';\n\n/** Result of serializing a request body - can be string (JSON) or Uint8Array (binary) */\nexport type SerializedBody = string | Uint8Array;\n\n/** Content-type header value for the serialized body */\nexport type ContentType = 'application/json; charset=utf-8' | 'application/octet-stream';\n\n/** Result of serializing a request body with its content type */\nexport interface SerializedRequest {\n body: SerializedBody;\n contentType: ContentType;\n}\n\n// ################################## SERIALIZE ##################################\n\n/** Serializes the request body and returns it with the appropriate content type */\nexport function serializeRequestBody(req: MionClientRequest<any, any>): SerializedRequest {\n const serializerMode = getSerializerMode(req);\n switch (serializerMode) {\n case 'json':\n case 'stringifyJson':\n return {\n body: serializeJsonBody(req),\n contentType: 'application/json; charset=utf-8',\n };\n case 'optimistic':\n return {\n body: serializeJSonBodyOptimistic(req),\n contentType: 'application/json; charset=utf-8',\n };\n case 'binary':\n return {\n body: serializeBinaryBody(req),\n contentType: 'application/octet-stream',\n };\n default:\n throw new Error(`Invalid serializer mode ${serializerMode}`);\n }\n}\n\nfunction serializeJsonBody(req: MionClientRequest<any, any>): string {\n const props: string[] = [];\n const subRequestIds = Object.keys(req.subRequestList);\n\n for (let i = 0; i < subRequestIds.length; i++) {\n const id = subRequestIds[i];\n const subRequest = req.subRequestList[id];\n if (!subRequest) continue;\n let params = subRequest.params;\n const method = routesCache.useMethodJitFns(id);\n if (method.type === HandlerType.headersMiddleFn && method.headersParam) {\n params = getParamsWithoutHeadersSubset(params);\n }\n try {\n const jsonValue = stringifyHandlerParams(method, params);\n if (!jsonValue) continue;\n props.push(`${JSON.stringify(id)}:${jsonValue}`);\n } catch (e: any) {\n const err = new RpcError({\n type: 'json-stringify-request-error',\n publicMessage: `Failed to stringify params for handler ${id}`,\n originalError: e,\n });\n throw err;\n }\n }\n\n return `{${props.join(',')}}`;\n}\n\n/** Serializes request body as plain JSON without JIT functions */\nfunction serializeJSonBodyOptimistic(req: MionClientRequest<any, any>): string {\n const body: Record<string, any> = {};\n const subRequestIds = Object.keys(req.subRequestList);\n for (const id of subRequestIds) {\n const subRequest = req.subRequestList[id];\n if (!subRequest) continue;\n body[id] = subRequest.params;\n }\n return JSON.stringify(body);\n}\n\n/** Serializes request body to binary format */\nfunction serializeBinaryBody(req: MionClientRequest<any, any>): Uint8Array {\n const subRequestIds = Object.keys(req.subRequestList);\n const body: Record<string, any> = {};\n const executionChain: MethodWithJitFns[] = [];\n\n for (const id of subRequestIds) {\n const subRequest = req.subRequestList[id];\n let params = subRequest.params;\n const method = routesCache.useMethodJitFns(id);\n\n if (method.type === HandlerType.headersMiddleFn && method.headersParam) {\n params = getParamsWithoutHeadersSubset(params);\n }\n\n body[id] = params;\n executionChain.push(method);\n }\n\n const workflowRouteIds = req.workflowSubRequests?.map((sr) => sr.id);\n const {buffer} = coreSerializeBinaryBody(req.path, executionChain, body, false, workflowRouteIds);\n return new Uint8Array(buffer);\n}\n\nfunction stringifyHandlerParams(method: MethodWithJitFns, params: any[]): string {\n if (!method.paramNames || method.paramNames.length === 0) return '';\n const paramsJit = method.paramsJitFns;\n if (paramsJit.prepareForJson.isNoop) return JSON.stringify(params);\n return paramsJit.stringifyJson.fn(params);\n}\n\n// ################################## DE-SERIALIZE ##################################\n\n/** Deserializes the response body from a fetch Response object. Handles routes metadata if present in json responses. */\nexport async function deserializeResponseBody(response: Response, options: ClientOptions): Promise<ResponseBody> {\n let parsedBody: any;\n const contentType = response.headers.get('content-type')?.toLowerCase();\n switch (true) {\n case !!contentType?.includes('application/json'):\n parsedBody = await deserializeJsonResponseBody(response, options);\n break;\n case !!contentType?.includes('application/octet-stream'):\n parsedBody = await deserializeBinaryResponseBody(response);\n break;\n default:\n throw new RpcError({\n type: 'unsupported-content-type',\n publicMessage: `Unsupported response content-type: '${contentType || 'none'}'`,\n });\n }\n return parsedBody;\n}\n\n/** Deserializes JSON response body, Also handles routes metadata if present */\nasync function deserializeJsonResponseBody(response: Response, options: ClientOptions) {\n try {\n const parsedBody = await response.json();\n // Extract & process metadata if present and delete entries after processing (does not use jit functions)\n extractAndProcessMetadata(MION_ROUTES.methodsMetadata, parsedBody, options);\n extractAndProcessMetadata(MION_ROUTES.methodsMetadataById, parsedBody, options);\n // Unwrap unexpected errors (move them from [MION_ROUTES.thrownErrors] to root)\n const platformError = unwrapUnexpectedErrors(parsedBody);\n if (platformError) return {[MION_ROUTES.platformError]: platformError};\n // Deserialize the body using jit functions\n const deserializedBody: ResponseBody = {};\n Object.entries(parsedBody).forEach(([methodId, returnValue]) => {\n const method = routesCache.useMethodJitFns(methodId);\n deserializedBody[methodId] = parseHandlerJsonReturnValue(method, returnValue);\n });\n return deserializedBody;\n } catch (err: any) {\n throw new RpcError({\n type: 'parsing-json-response-error',\n publicMessage: `Invalid json response body: ${err?.message || 'unknown parsing error.'}`,\n });\n }\n}\n\n/** Deserializes binary response body */\nasync function deserializeBinaryResponseBody(response: Response): Promise<ResponseBody> {\n const arrayBuffer = await response.arrayBuffer();\n const {body} = coreDeserializeBinaryBody('client-response', arrayBuffer, true);\n // Unwrap unexpected errors (move them from [MION_ROUTES.thrownErrors] to root)\n const platformError = unwrapUnexpectedErrors(body);\n if (platformError) return {[MION_ROUTES.platformError]: platformError};\n return body;\n}\n\n/** Unwraps unexpected errors from the response body into parsedBody. Returns a platformError if present as a special case. */\nfunction unwrapUnexpectedErrors(parsedBody: any): RpcError<string> | undefined {\n if (!(MION_ROUTES.thrownErrors in parsedBody)) return;\n const unexpectedErrors = parsedBody[MION_ROUTES.thrownErrors];\n // if platform error is present that means the router never executed (just the platform wrapper)\n if (MION_ROUTES.platformError in unexpectedErrors) {\n const globalErrorValue = unexpectedErrors[MION_ROUTES.platformError];\n return isRpcError(globalErrorValue) ? new RpcError<string>(globalErrorValue) : globalErrorValue;\n }\n Object.assign(parsedBody, unexpectedErrors);\n delete parsedBody[MION_ROUTES.thrownErrors];\n}\n\n/** Determines the serializer mode to use for a request */\nfunction getSerializerMode(req: MionClientRequest<any, any>): SerializerMode {\n if (req.options.serializer === 'optimistic') {\n // When metadata is cached (e.g. after retry), use JIT serialization\n const subRequestIds = Object.keys(req.subRequestList);\n const allCached = subRequestIds.every((id) => routesCache.hasMetadata(id));\n if (allCached) return 'stringifyJson';\n return 'optimistic';\n }\n const methodId = req.route?.id ?? req.workflowSubRequests?.[0]?.id;\n const method = routesCache.getMethodJitFns(methodId);\n const serializerMode = method?.options.serializer || DEFAULT_PREFILL_OPTIONS.serializer;\n if (serializerMode === 'json') return DEFAULT_PREFILL_OPTIONS.serializer;\n return serializerMode;\n}\n\n/** Returns params array without the HeadersSubset (first param) */\nfunction getParamsWithoutHeadersSubset(params: any[]): any[] {\n if (!params || params.length === 0) return [];\n return params.slice(1);\n}\n\nfunction parseHandlerJsonReturnValue(method: MethodWithJitFns, returnValue: any): any {\n if (!method.hasReturnData) return returnValue;\n const returnJit = method.returnJitFns;\n if (returnJit.restoreFromJson.isNoop || !returnValue) return returnValue;\n\n try {\n if (returnValue instanceof RpcError) return returnValue;\n if (isRpcError(returnValue)) return new RpcError(returnValue);\n return returnJit.restoreFromJson.fn(returnValue);\n } catch (e: any) {\n return new RpcError({\n type: 'deserialization-error',\n publicMessage: `Invalid response from Route or MiddleFn '${method.id}', can not deserialize return value: ${e.message}`,\n errorData: e?.errors,\n });\n }\n}\n"],"names":["coreSerializeBinaryBody","coreDeserializeBinaryBody"],"mappings":"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"}