{"version":3,"sources":["../../src/keys/get-management-token.ts","../../src/utils/http.ts","../../src/utils/logger.ts"],"sourcesContent":["import * as jwtImpl from 'jsonwebtoken'\nimport type { SignOptions } from 'jsonwebtoken'\nimport { LRUCache } from 'lru-cache'\nimport {\n  createLogger,\n  Logger,\n  createHttpClient,\n  createValidateStatusCode,\n  HttpClient,\n} from '../utils'\n\nconst jwt = 'default' in jwtImpl ? jwtImpl.default : jwtImpl\nconst { sign, decode } = jwt as typeof jwtImpl\nexport interface GetManagementTokenOptions {\n  appInstallationId: string\n  spaceId: string\n  environmentId: string\n  keyId?: string\n  reuseToken?: boolean\n  host?: string\n}\n\nlet defaultCache: LRUCache<string, string> | undefined\n\n/**\n * Synchronously sign the given privateKey into a JSON Web Token string\n * @internal\n */\nconst generateOneTimeToken = (\n  privateKey: string,\n  { appId, keyId }: { appId: string; keyId?: string },\n  { log }: { log: Logger },\n): string => {\n  log('Signing a JWT token with private key')\n  try {\n    const baseSignOptions: SignOptions = { algorithm: 'RS256', issuer: appId, expiresIn: '10m' }\n    const signOptions: SignOptions = keyId ? { ...baseSignOptions, keyid: keyId } : baseSignOptions\n\n    const token = sign({}, privateKey, signOptions)\n    log('Successfully signed token')\n    return token\n  } catch (e) {\n    log('Unable to sign token')\n    throw e\n  }\n}\n\nconst getTokenFromOneTimeToken = async (\n  appToken: string,\n  {\n    appInstallationId,\n    spaceId,\n    environmentId,\n  }: { appInstallationId: string; spaceId: string; environmentId: string },\n  { log, http }: { log: Logger; http: HttpClient },\n): Promise<string> => {\n  const validateStatusCode = createValidateStatusCode([201])\n\n  log(`Requesting CMA Token with given App Token`)\n\n  const response = await http.post(\n    `spaces/${spaceId}/environments/${environmentId}/app_installations/${appInstallationId}/access_tokens`,\n    {\n      headers: {\n        Authorization: `Bearer ${appToken}`,\n      },\n      hooks: {\n        afterResponse: [validateStatusCode],\n      },\n    },\n  )\n\n  log(\n    `Successfully retrieved CMA Token for app ${appInstallationId} in space ${spaceId} and environment ${environmentId}`,\n  )\n\n  return JSON.parse(response.body).token\n}\n\n/**\n * Factory method for GetManagementToken\n * @internal\n */\nexport const createGetManagementToken = (\n  log: Logger,\n  http: HttpClient,\n  cache: LRUCache<string, string>,\n) => {\n  return async (privateKey: unknown, opts: GetManagementTokenOptions): Promise<string> => {\n    if (!(typeof privateKey === 'string')) {\n      throw new ReferenceError('Invalid privateKey: expected a string representing a private key')\n    }\n\n    if (opts.reuseToken === undefined) {\n      opts.reuseToken = true\n    }\n\n    const cacheKey =\n      opts.appInstallationId + opts.spaceId + opts.environmentId + privateKey.slice(32, 132)\n    if (opts.reuseToken) {\n      const existing = cache.get(cacheKey) as string\n      if (existing) {\n        return existing as string\n      }\n    }\n\n    const appToken = generateOneTimeToken(\n      privateKey,\n      { appId: opts.appInstallationId, keyId: opts.keyId },\n      { log },\n    )\n    const ott = await getTokenFromOneTimeToken(appToken, opts, { log, http })\n    if (opts.reuseToken) {\n      const decoded = decode(ott)\n      if (decoded && typeof decoded === 'object' && decoded.exp) {\n        // Internally expire cached tokens a bit earlier to make sure token isn't expired on arrival\n        const safetyMargin = 10\n        const ttlSeconds = decoded.exp - Math.floor(Date.now() / 1000) - safetyMargin\n        cache.set(cacheKey, ott, { ttl: ttlSeconds })\n      }\n    }\n\n    return ott\n  }\n}\n\n/**\n * Returns a Contentful Management API token from private key\n * Management tokens are cached internally until until they expire.\n * Pass `reuseToken: false` in the options for `getManagementToken` to disable this feature.\n *\n * NodeJS Contentful Apps need a management token to interact with Contentful's APIs.\n * Creating a management token requires a key pair to be registered for the app, follow\n * [this link](http://contentful./developers/docs/references/content-management-api/#/reference/app-keys/app-keys)\n * for more information on key pairs.\n *\n * Once a key pair is registered the getManagementToken function can be used to generate a valid token.\n *\n * ~~~\n * const {getManagementToken} = require('contentful-node-apps-toolkit')\n *\n * getManagementToken(PRIVATE_KEY, {appInstallationId, spaceId, environmentId})\n *    .then( (token) => {\n *      console.log('Here is your token')\n *      console.log(token)\n *    })\n * ~~~\n * @category Keys\n */\nexport const getManagementToken = (privateKey: string, opts: GetManagementTokenOptions) => {\n  if ((opts.reuseToken || opts.reuseToken === undefined) && !defaultCache) {\n    defaultCache = new LRUCache({ max: 10 })\n  }\n  const httpClientOpts = typeof opts.host !== 'undefined' ? { prefixUrl: opts.host } : {}\n\n  return createGetManagementToken(\n    createLogger({ namespace: 'get-management-token.js' }),\n    createHttpClient(httpClientOpts),\n    defaultCache!,\n  )(privateKey, opts)\n}\n","import got, { ExtendOptions, Got, HTTPError, Response as GotResponse } from 'got'\n\nconst config = {\n  prefixUrl: process.env.BASE_URL || 'https://api.contentful.com',\n  retry: { limit: 3 },\n}\n\nexport const createHttpClient = (configOverride: ExtendOptions = {}) => {\n  return got.extend({ ...config, ...configOverride })\n}\n\nexport const createValidateStatusCode = (allowedStatusCodes: number[]) => (response: Response) => {\n  if (!allowedStatusCodes.includes(response.statusCode)) {\n    console.log(response.body)\n    throw new HTTPError(response)\n  }\n  return response\n}\n\nexport { HTTPError as HttpError }\n\nexport type HttpClient = Got\nexport type Response = GotResponse\n","import debug from 'debug'\n\nconst APP_NAME = '@contentful/node-apps-toolkit'\n\nconst getNamespaceFromFilename = (filename: string) => {\n  return filename.slice(0, -3)\n}\n\n/**\n * @internal\n */\nexport const createLogger = (opts: { namespace: string } | { filename: string }) => {\n  const ns = 'namespace' in opts ? opts.namespace : getNamespaceFromFilename(opts.filename)\n\n  return debug(APP_NAME).extend(ns)\n}\n\nexport type Logger = debug.Debugger\n"],"mappings":"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","names":[]}