{"version":3,"sources":["../../src/request.ts"],"sourcesContent":["import { MethodDescriptor } from './method-descriptor'\nimport { toQueryString, lowerCaseObjectKeys, assign } from './utils/index'\nimport type {\n  Auth,\n  Body,\n  Headers,\n  NestedParam,\n  NestedParamArray,\n  Primitive,\n  RequestParams,\n} from './types'\n\nconst REGEXP_DYNAMIC_SEGMENT = /{([^}?]+)\\??}/\nconst REGEXP_OPTIONAL_DYNAMIC_SEGMENT = /\\/?{([^}?]+)\\?}/g\nconst REGEXP_TRAILING_SLASH = /\\/$/\n\nexport type RequestContext = Record<string, unknown>\n\n/**\n * Removes the object type without removing Record types in the union\n */\nexport type ExcludeObject<T> = T extends object ? (object extends T ? never : T) : T\n\n/**\n * @typedef Request\n * @param {MethodDescriptor} methodDescriptor\n * @param {RequestParams} requestParams, defaults to an empty object ({})\n * @param {RequestContext} request context store, defaults to an empty object ({})\n */\nexport class Request {\n  public methodDescriptor: MethodDescriptor\n  public requestParams: RequestParams\n  private requestContext: RequestContext\n\n  constructor(\n    methodDescriptor: MethodDescriptor,\n    requestParams: RequestParams = {},\n    requestContext: RequestContext = {}\n  ) {\n    this.methodDescriptor = methodDescriptor\n    this.requestParams = requestParams\n    this.requestContext = requestContext\n  }\n\n  private isParam(key: string) {\n    return (\n      key !== this.methodDescriptor.headersAttr &&\n      key !== this.methodDescriptor.bodyAttr &&\n      key !== this.methodDescriptor.authAttr &&\n      key !== this.methodDescriptor.timeoutAttr &&\n      key !== this.methodDescriptor.hostAttr &&\n      key !== this.methodDescriptor.signalAttr &&\n      key !== this.methodDescriptor.pathAttr\n    )\n  }\n\n  public params() {\n    const params = assign({}, this.methodDescriptor.params, this.requestParams)\n\n    return Object.keys(params).reduce((obj, key) => {\n      if (this.isParam(key)) {\n        obj[key] = params[key]\n      }\n      return obj\n    }, {} as RequestParams)\n  }\n\n  /**\n   * Returns the request context; a key value object.\n   * Useful to pass information from upstream middleware to a downstream one.\n   */\n  public context<T extends RequestContext = RequestContext>() {\n    return this.requestContext as T\n  }\n\n  /**\n   * Returns the HTTP method in lowercase\n   */\n  public method() {\n    return this.methodDescriptor.method.toLowerCase()\n  }\n\n  /**\n   * Returns host name without trailing slash\n   * Example: 'http://example.org'\n   */\n  public host() {\n    const { allowResourceHostOverride, hostAttr, host } = this.methodDescriptor\n    const originalHost = allowResourceHostOverride\n      ? this.requestParams[hostAttr] || host || ''\n      : host || ''\n\n    if (typeof originalHost === 'string') {\n      return originalHost.replace(REGEXP_TRAILING_SLASH, '')\n    }\n\n    return ''\n  }\n\n  /**\n   * Returns path with parameters and leading slash.\n   * Example: '/some/path?param1=true'\n   *\n   * @throws {Error} if any dynamic segment is missing.\n   * Example:\n   *  Imagine the path '/some/{name}', the error will be similar to:\n   *    '[Mappersmith] required parameter missing (name), \"/some/{name}\" cannot be resolved'\n   */\n  public path() {\n    const { pathAttr: mdPathAttr, path: mdPath } = this.methodDescriptor\n    const originalPath = (this.requestParams[mdPathAttr] as RequestParams['path']) || mdPath || ''\n    const params = this.params()\n\n    let path: string\n    if (typeof originalPath === 'function') {\n      path = originalPath(params)\n      if (typeof path !== 'string') {\n        throw new Error(\n          `[Mappersmith] method descriptor function did not return a string, params=${JSON.stringify(\n            params\n          )}`\n        )\n      }\n    } else {\n      path = originalPath\n    }\n\n    // RegExp with 'g'-flag is stateful, therefore defining it locally\n    const regexp = new RegExp(REGEXP_DYNAMIC_SEGMENT, 'g')\n\n    const dynamicSegmentKeys = []\n    let match\n    while ((match = regexp.exec(path)) !== null) {\n      dynamicSegmentKeys.push(match[1])\n    }\n\n    for (const key of dynamicSegmentKeys) {\n      const pattern = new RegExp(`{${key}\\\\??}`, 'g')\n      const value = params[key]\n      if (value != null && typeof value !== 'object') {\n        path = path.replace(pattern, this.methodDescriptor.parameterEncoder(value))\n        delete params[key]\n      }\n    }\n\n    path = path.replace(REGEXP_OPTIONAL_DYNAMIC_SEGMENT, '')\n\n    const missingDynamicSegmentMatch = path.match(REGEXP_DYNAMIC_SEGMENT)\n    if (missingDynamicSegmentMatch) {\n      throw new Error(\n        `[Mappersmith] required parameter missing (${missingDynamicSegmentMatch[1]}), \"${path}\" cannot be resolved`\n      )\n    }\n\n    const aliasedParams = Object.keys(params).reduce(\n      (aliased, key) => {\n        const aliasedKey = this.methodDescriptor.queryParamAlias[key] || key\n        const value = params[key]\n        if (value != null) {\n          /**\n           * Here we use `ExcludeObject` to surgically remove the `object` type from `value`.\n           * We need it as `object` is too broad to be useful, whereas `value` is also typed\n           * as NestedParam, which is the correct shape for param objects.\n           */\n          aliased[aliasedKey] = value as ExcludeObject<typeof value>\n        }\n        return aliased\n      },\n      {} as Record<string, Primitive | NestedParam | NestedParamArray>\n    )\n\n    const queryString = toQueryString(aliasedParams, this.methodDescriptor.parameterEncoder)\n    if (typeof queryString === 'string' && queryString.length !== 0) {\n      const hasQuery = path.includes('?')\n      path += `${hasQuery ? '&' : '?'}${queryString}`\n    }\n\n    // https://www.rfc-editor.org/rfc/rfc1738#section-3.3\n    if (path[0] !== '/' && path.length > 0) {\n      path = `/${path}`\n    }\n\n    return path\n  }\n\n  /**\n   * Returns the template path, without params, before interpolation.\n   * If path is a function, returns the result of request.path()\n   * Example: '/some/{param}/path'\n   */\n  public pathTemplate() {\n    const path = this.methodDescriptor.path\n\n    const prependSlash = (str: string) => (str[0] !== '/' ? `/${str}` : str)\n\n    if (typeof path === 'function') {\n      return prependSlash(path(this.params()))\n    }\n\n    return prependSlash(path)\n  }\n\n  /**\n   * Returns the full URL\n   * Example: http://example.org/some/path?param1=true\n   *\n   */\n  public url() {\n    return `${this.host()}${this.path()}`\n  }\n\n  /**\n   * Returns an object with the headers. Header names are converted to\n   * lowercase\n   */\n  public headers() {\n    const headerAttr = this.methodDescriptor.headersAttr\n    const headers = (this.requestParams[headerAttr] || {}) as Headers\n\n    if (typeof headers === 'function') {\n      return headers\n    }\n\n    const mergedHeaders = { ...this.methodDescriptor.headers, ...headers } as Headers\n    return lowerCaseObjectKeys(mergedHeaders) as Headers\n  }\n\n  /**\n   * Utility method to get a header value by name\n   */\n  public header<T extends string | number | boolean>(name: string): T | undefined {\n    const key = name.toLowerCase()\n\n    if (key in this.headers()) {\n      return this.headers()[key] as T\n    }\n\n    return undefined\n  }\n\n  public body() {\n    return this.requestParams[this.methodDescriptor.bodyAttr] as Body | undefined\n  }\n\n  public auth() {\n    return this.requestParams[this.methodDescriptor.authAttr] as Auth | undefined\n  }\n\n  public timeout() {\n    return this.requestParams[this.methodDescriptor.timeoutAttr] as number | undefined\n  }\n\n  public signal() {\n    return this.requestParams[this.methodDescriptor.signalAttr] as AbortSignal | undefined\n  }\n\n  /**\n   * Enhances current request returning a new Request\n   * @param {RequestParams} extras\n   *   @param {Object} extras.auth - it will replace the current auth\n   *   @param {String|Object} extras.body - it will replace the current body\n   *   @param {Headers} extras.headers - it will be merged with current headers\n   *   @param {String} extras.host - it will replace the current timeout\n   *   @param {RequestParams} extras.params - it will be merged with current params\n   *   @param {Number} extras.timeout - it will replace the current timeout\n   * @param {Object} requestContext - Use to pass information between different middleware.\n   */\n  public enhance(extras: RequestParams, requestContext?: RequestContext) {\n    const authKey = this.methodDescriptor.authAttr\n    const bodyKey = this.methodDescriptor.bodyAttr\n    const headerKey = this.methodDescriptor.headersAttr\n    const hostKey = this.methodDescriptor.hostAttr\n    const timeoutKey = this.methodDescriptor.timeoutAttr\n    const pathKey = this.methodDescriptor.pathAttr\n    const signalKey = this.methodDescriptor.signalAttr\n\n    // Note: The result of merging an instance of RequestParams with instance of Params\n    // is simply a RequestParams with even more [param: string]'s on it.\n    const requestParams: RequestParams = assign({}, this.requestParams, extras.params)\n\n    const headers = this.requestParams[headerKey] as Headers | undefined\n    const mergedHeaders = assign({}, headers, extras.headers)\n    requestParams[headerKey] = mergedHeaders\n\n    extras.auth && (requestParams[authKey] = extras.auth)\n    extras.body && (requestParams[bodyKey] = extras.body)\n    extras.host && (requestParams[hostKey] = extras.host)\n    extras.timeout && (requestParams[timeoutKey] = extras.timeout)\n    extras.path && (requestParams[pathKey] = extras.path)\n    extras.signal && (requestParams[signalKey] = extras.signal)\n\n    const nextContext = { ...this.requestContext, ...requestContext }\n\n    return new Request(this.methodDescriptor, requestParams, nextContext)\n  }\n\n  /**\n   * Is the request expecting a binary response?\n   */\n  public isBinary() {\n    return this.methodDescriptor.binary\n  }\n}\n\nexport default Request\n"],"mappings":";AACA,SAAS,eAAe,qBAAqB,cAAc;AAW3D,IAAM,yBAAyB;AAC/B,IAAM,kCAAkC;AACxC,IAAM,wBAAwB;AAevB,IAAM,UAAN,MAAM,SAAQ;AAAA,EACZ;AAAA,EACA;AAAA,EACC;AAAA,EAER,YACE,kBACA,gBAA+B,CAAC,GAChC,iBAAiC,CAAC,GAClC;AACA,SAAK,mBAAmB;AACxB,SAAK,gBAAgB;AACrB,SAAK,iBAAiB;AAAA,EACxB;AAAA,EAEQ,QAAQ,KAAa;AAC3B,WACE,QAAQ,KAAK,iBAAiB,eAC9B,QAAQ,KAAK,iBAAiB,YAC9B,QAAQ,KAAK,iBAAiB,YAC9B,QAAQ,KAAK,iBAAiB,eAC9B,QAAQ,KAAK,iBAAiB,YAC9B,QAAQ,KAAK,iBAAiB,cAC9B,QAAQ,KAAK,iBAAiB;AAAA,EAElC;AAAA,EAEO,SAAS;AACd,UAAM,SAAS,OAAO,CAAC,GAAG,KAAK,iBAAiB,QAAQ,KAAK,aAAa;AAE1E,WAAO,OAAO,KAAK,MAAM,EAAE,OAAO,CAAC,KAAK,QAAQ;AAC9C,UAAI,KAAK,QAAQ,GAAG,GAAG;AACrB,YAAI,GAAG,IAAI,OAAO,GAAG;AAAA,MACvB;AACA,aAAO;AAAA,IACT,GAAG,CAAC,CAAkB;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,UAAqD;AAC1D,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKO,SAAS;AACd,WAAO,KAAK,iBAAiB,OAAO,YAAY;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,OAAO;AACZ,UAAM,EAAE,2BAA2B,UAAU,KAAK,IAAI,KAAK;AAC3D,UAAM,eAAe,4BACjB,KAAK,cAAc,QAAQ,KAAK,QAAQ,KACxC,QAAQ;AAEZ,QAAI,OAAO,iBAAiB,UAAU;AACpC,aAAO,aAAa,QAAQ,uBAAuB,EAAE;AAAA,IACvD;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWO,OAAO;AACZ,UAAM,EAAE,UAAU,YAAY,MAAM,OAAO,IAAI,KAAK;AACpD,UAAM,eAAgB,KAAK,cAAc,UAAU,KAA+B,UAAU;AAC5F,UAAM,SAAS,KAAK,OAAO;AAE3B,QAAI;AACJ,QAAI,OAAO,iBAAiB,YAAY;AACtC,aAAO,aAAa,MAAM;AAC1B,UAAI,OAAO,SAAS,UAAU;AAC5B,cAAM,IAAI;AAAA,UACR,4EAA4E,KAAK;AAAA,YAC/E;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF,OAAO;AACL,aAAO;AAAA,IACT;AAGA,UAAM,SAAS,IAAI,OAAO,wBAAwB,GAAG;AAErD,UAAM,qBAAqB,CAAC;AAC5B,QAAI;AACJ,YAAQ,QAAQ,OAAO,KAAK,IAAI,OAAO,MAAM;AAC3C,yBAAmB,KAAK,MAAM,CAAC,CAAC;AAAA,IAClC;AAEA,eAAW,OAAO,oBAAoB;AACpC,YAAM,UAAU,IAAI,OAAO,IAAI,GAAG,SAAS,GAAG;AAC9C,YAAM,QAAQ,OAAO,GAAG;AACxB,UAAI,SAAS,QAAQ,OAAO,UAAU,UAAU;AAC9C,eAAO,KAAK,QAAQ,SAAS,KAAK,iBAAiB,iBAAiB,KAAK,CAAC;AAC1E,eAAO,OAAO,GAAG;AAAA,MACnB;AAAA,IACF;AAEA,WAAO,KAAK,QAAQ,iCAAiC,EAAE;AAEvD,UAAM,6BAA6B,KAAK,MAAM,sBAAsB;AACpE,QAAI,4BAA4B;AAC9B,YAAM,IAAI;AAAA,QACR,6CAA6C,2BAA2B,CAAC,CAAC,OAAO,IAAI;AAAA,MACvF;AAAA,IACF;AAEA,UAAM,gBAAgB,OAAO,KAAK,MAAM,EAAE;AAAA,MACxC,CAAC,SAAS,QAAQ;AAChB,cAAM,aAAa,KAAK,iBAAiB,gBAAgB,GAAG,KAAK;AACjE,cAAM,QAAQ,OAAO,GAAG;AACxB,YAAI,SAAS,MAAM;AAMjB,kBAAQ,UAAU,IAAI;AAAA,QACxB;AACA,eAAO;AAAA,MACT;AAAA,MACA,CAAC;AAAA,IACH;AAEA,UAAM,cAAc,cAAc,eAAe,KAAK,iBAAiB,gBAAgB;AACvF,QAAI,OAAO,gBAAgB,YAAY,YAAY,WAAW,GAAG;AAC/D,YAAM,WAAW,KAAK,SAAS,GAAG;AAClC,cAAQ,GAAG,WAAW,MAAM,GAAG,GAAG,WAAW;AAAA,IAC/C;AAGA,QAAI,KAAK,CAAC,MAAM,OAAO,KAAK,SAAS,GAAG;AACtC,aAAO,IAAI,IAAI;AAAA,IACjB;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,eAAe;AACpB,UAAM,OAAO,KAAK,iBAAiB;AAEnC,UAAM,eAAe,CAAC,QAAiB,IAAI,CAAC,MAAM,MAAM,IAAI,GAAG,KAAK;AAEpE,QAAI,OAAO,SAAS,YAAY;AAC9B,aAAO,aAAa,KAAK,KAAK,OAAO,CAAC,CAAC;AAAA,IACzC;AAEA,WAAO,aAAa,IAAI;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,MAAM;AACX,WAAO,GAAG,KAAK,KAAK,CAAC,GAAG,KAAK,KAAK,CAAC;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,UAAU;AACf,UAAM,aAAa,KAAK,iBAAiB;AACzC,UAAM,UAAW,KAAK,cAAc,UAAU,KAAK,CAAC;AAEpD,QAAI,OAAO,YAAY,YAAY;AACjC,aAAO;AAAA,IACT;AAEA,UAAM,gBAAgB,EAAE,GAAG,KAAK,iBAAiB,SAAS,GAAG,QAAQ;AACrE,WAAO,oBAAoB,aAAa;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKO,OAA4C,MAA6B;AAC9E,UAAM,MAAM,KAAK,YAAY;AAE7B,QAAI,OAAO,KAAK,QAAQ,GAAG;AACzB,aAAO,KAAK,QAAQ,EAAE,GAAG;AAAA,IAC3B;AAEA,WAAO;AAAA,EACT;AAAA,EAEO,OAAO;AACZ,WAAO,KAAK,cAAc,KAAK,iBAAiB,QAAQ;AAAA,EAC1D;AAAA,EAEO,OAAO;AACZ,WAAO,KAAK,cAAc,KAAK,iBAAiB,QAAQ;AAAA,EAC1D;AAAA,EAEO,UAAU;AACf,WAAO,KAAK,cAAc,KAAK,iBAAiB,WAAW;AAAA,EAC7D;AAAA,EAEO,SAAS;AACd,WAAO,KAAK,cAAc,KAAK,iBAAiB,UAAU;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaO,QAAQ,QAAuB,gBAAiC;AACrE,UAAM,UAAU,KAAK,iBAAiB;AACtC,UAAM,UAAU,KAAK,iBAAiB;AACtC,UAAM,YAAY,KAAK,iBAAiB;AACxC,UAAM,UAAU,KAAK,iBAAiB;AACtC,UAAM,aAAa,KAAK,iBAAiB;AACzC,UAAM,UAAU,KAAK,iBAAiB;AACtC,UAAM,YAAY,KAAK,iBAAiB;AAIxC,UAAM,gBAA+B,OAAO,CAAC,GAAG,KAAK,eAAe,OAAO,MAAM;AAEjF,UAAM,UAAU,KAAK,cAAc,SAAS;AAC5C,UAAM,gBAAgB,OAAO,CAAC,GAAG,SAAS,OAAO,OAAO;AACxD,kBAAc,SAAS,IAAI;AAE3B,WAAO,SAAS,cAAc,OAAO,IAAI,OAAO;AAChD,WAAO,SAAS,cAAc,OAAO,IAAI,OAAO;AAChD,WAAO,SAAS,cAAc,OAAO,IAAI,OAAO;AAChD,WAAO,YAAY,cAAc,UAAU,IAAI,OAAO;AACtD,WAAO,SAAS,cAAc,OAAO,IAAI,OAAO;AAChD,WAAO,WAAW,cAAc,SAAS,IAAI,OAAO;AAEpD,UAAM,cAAc,EAAE,GAAG,KAAK,gBAAgB,GAAG,eAAe;AAEhE,WAAO,IAAI,SAAQ,KAAK,kBAAkB,eAAe,WAAW;AAAA,EACtE;AAAA;AAAA;AAAA;AAAA,EAKO,WAAW;AAChB,WAAO,KAAK,iBAAiB;AAAA,EAC/B;AACF;AAEA,IAAO,kBAAQ;","names":[]}