{"version":3,"sources":["jsdelivr-header.js","/npm/vercel-integration-demo@0.0.49/index.ts"],"names":[],"mappings":"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","file":"/npm/vercel-integration-demo@0.0.49/dist/index.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/vercel-integration-demo@0.0.49/dist/index.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","import { HookdeckConfig } from './hookdeck.config';\nimport { next } from '@vercel/edge';\n\nconst AUTHENTICATED_ENTRY_POINT = 'https://hkdk.events/publish';\nconst HOOKDECK_PROCESSED_HEADER = 'x-hookdeck-signature';\nconst HOOKDECK_SIGNATURE_HEADER_1 = 'x-hookdeck-signature';\nconst HOOKDECK_SIGNATURE_HEADER_2 = 'x-hookdeck-signature-2';\n\nexport function withHookdeck(config: HookdeckConfig, f?: Function): (args) => Promise<Response> {\n  return async function (...args) {\n    const request = args[0];\n\n    try {\n      const pathname = getPathnameWithFallback(request);\n      const cleanPath = pathname.split('&')[0];\n\n      const connections: Array<any> = [];\n      for (const e of Object.entries(config.match)) {\n        const key = e[0];\n        const value = e[1] as any;\n\n        const conn = Object.assign(value, {\n          matcher: key,\n          source_name: value.name || (await vercelHash(key)),\n        });\n\n        connections.push(conn);\n      }\n\n      const matching = connections.filter(\n        (conn_config) => (cleanPath.match(conn_config.matcher) ?? []).length > 0,\n      );\n\n      if (matching.length === 0) {\n        console.debug(\n          `[Hookdeck] No match for path '${cleanPath}'... calling ${f ? 'user middleware' : 'next'}`,\n        );\n        return Promise.resolve(f ? f.apply(this, args) : next());\n      }\n\n      const api_key = config.api_key || process.env.HOOKDECK_API_KEY;\n      if (!api_key) {\n        console.warn(\n          \"[Hookdeck] Hookdeck API key doesn't found. You must set it as a env variable named HOOKDECK_API_KEY or include it in your hookdeck.config.js file.\",\n        );\n        return Promise.resolve(f ? f.apply(this, args) : next());\n      }\n\n      // Check if vercel or next env is develoment\n      const is_development =\n        process &&\n        (process.env.VERCEL_ENV === 'development' || process.env.NODE_ENV === 'development');\n      if (is_development) {\n        console.warn(\n          '[Hookdeck] Local development environment detected. Hookdeck middleware is disabled locally. Bypassing the middleware...',\n        );\n        return Promise.resolve(f ? f.apply(this, args) : next());\n      }\n\n      const contains_proccesed_header = !!request.headers.get(HOOKDECK_PROCESSED_HEADER);\n      if (contains_proccesed_header) {\n        // Optional Hookdeck webhook signature verification\n        let verified = true;\n\n        const secret = config.signing_secret || process.env.HOOKDECK_SIGNING_SECRET;\n        if (!!secret) {\n          verified = await verifyHookdeckSignature(request, secret);\n        }\n\n        if (!verified) {\n          const msg = '[Hookdeck] Invalid Hookdeck Signature in request.';\n          console.error(msg);\n          return new Response(msg, { status: 401 });\n        }\n\n        // Go to next (Edge function or regular page) in the chain\n        return next();\n      }\n\n      const middlewareResponse = await Promise.resolve(f ? f.apply(this, args) : next());\n      // invoke middleware if it returns something different to `next()`\n      if (\n        middlewareResponse &&\n        middlewareResponse.headers.get('x-middleware-next') !== '1' &&\n        middlewareResponse.headers.get('x-from-middleware') !== '1'\n      ) {\n        return middlewareResponse;\n      }\n\n      // Forward to Hookdeck\n\n      if (matching.length === 1) {\n        // single source\n        const source_name = matching[0].source_name;\n        return await forwardToHookdeck(request, api_key, source_name, pathname);\n      }\n\n      // multiple sources: check if there are multiple matches with the same api_key and source_name\n\n      const used = new Map<string, [any]>();\n\n      for (const result of matching) {\n        const source_name = result.source_name;\n        if (!source_name) {\n          console.error(\n            \"Hookdeck Source name doesn't found. You must include it in your hookdeck.config.js file.\",\n          );\n          return middlewareResponse;\n        }\n\n        const match_key = `${api_key}/${source_name}`;\n        const array = used[match_key] ?? [];\n        array.push(result);\n        used[match_key] = array;\n      }\n\n      const promises: Promise<any>[] = [];\n\n      for (const array of Object.values(used)) {\n        const used_connection_ids: string[] = [];\n\n        if ((array as [any]).length > 1) {\n          // If there is more than one similar match, we need the connection_id\n          // to pick out the right connection\n          for (const entry of array) {\n            if (!!entry.id && !used_connection_ids.includes(entry.id)) {\n              const source_name = entry.source_name;\n              promises.push(forwardToHookdeck(request, api_key, source_name, pathname));\n              used_connection_ids.push(entry.id);\n            }\n          }\n\n          if (promises.length === 0) {\n            console.warn(\n              '[Hookdeck] Found indistinguishable source names, could not process',\n              array[0].source_name,\n            );\n          }\n        }\n      }\n\n      // If several promises were fullfilled, return the first one as required by the middleware definition\n      return Promise.all(promises).then((val) => val[0]);\n    } catch (e) {\n      // If an error is thrown here, it's better not to continue\n      // with default middleware function, as it could lead to more errors\n      console.error('[Hookdeck] Exception on withHookdeck', e);\n      return new Response(JSON.stringify(e), { status: 500 });\n    }\n  };\n}\n\nfunction getPathnameWithFallback(request: any): string {\n  if (request.nextUrl) {\n    // NextJS url\n    return request.nextUrl.pathname;\n  }\n\n  if (request.url) {\n    // vanilla object\n    return new URL(request.url).pathname;\n  }\n\n  // unknown\n  return '';\n}\n\nasync function verifyHookdeckSignature(request, secret: string | undefined): Promise<boolean> {\n  const signature1 = (request.headers ?? {})[HOOKDECK_SIGNATURE_HEADER_1];\n  const signature2 = (request.headers ?? {})[HOOKDECK_SIGNATURE_HEADER_2];\n\n  if (secret && (signature1 || signature2)) {\n    // TODO: assumed string body\n    const body = await new Response(request.body).text();\n    const encoder = new TextEncoder();\n    const keyData = encoder.encode(secret);\n    const bodyData = encoder.encode(body);\n    const cryptoKey = await crypto.subtle.importKey(\n      'raw',\n      keyData,\n      { name: 'HMAC', hash: { name: 'SHA-256' } },\n      false,\n      ['sign'],\n    );\n    const hmac = await crypto.subtle.sign('HMAC', cryptoKey, bodyData);\n    const hash = btoa(String.fromCharCode(...new Uint8Array(hmac)));\n\n    return hash === signature1 || hash === signature2;\n  }\n\n  return true;\n}\n\nasync function forwardToHookdeck(\n  request: Request,\n  api_key: string,\n  source_name: string,\n  pathname: string,\n): Promise<any> {\n  const request_headers = {};\n  // iterate using forEach because this can be either a Headers object or a plain object\n  request.headers.forEach((value, key) => {\n    if (!key.startsWith('x-vercel-')) {\n      request_headers[key] = value;\n    }\n  });\n\n  const headers = {\n    ...request_headers,\n    connection: 'close',\n    authorization: `Bearer ${api_key}`,\n    'x-hookdeck-source-name': source_name,\n  };\n\n  // TODO: assumed string body\n  const body = await new Response(request.body).text();\n\n  const options = {\n    method: request.method,\n    headers,\n  };\n\n  if (!!body) {\n    options['body'] = body;\n  }\n\n  console.debug(\n    `[Hookdeck] Forwarding to hookdeck (${!!body ? 'with' : 'without'} body)...`,\n    options,\n  );\n\n  return fetch(`${AUTHENTICATED_ENTRY_POINT}${pathname}`, options);\n}\n\nasync function vercelHash(key) {\n  // can't use NPM crypto library in Edge Runtime, must\n  // use crypto.subtle\n  const hash = await sha1(key);\n  return `vercel-${hash.slice(0, 9)}`;\n}\n\nasync function sha1(str) {\n  // credits to: https://gist.github.com/GaspardP/fffdd54f563f67be8944\n  // Get the string as arraybuffer.\n  const buffer = new TextEncoder().encode(str);\n  const hash = await crypto.subtle.digest('SHA-1', buffer);\n  return hex(hash);\n}\n\nfunction hex(buffer) {\n  let digest = '';\n  const view = new DataView(buffer);\n  for (let i = 0; i < view.byteLength; i += 4) {\n    // We use getUint32 to reduce the number of iterations (notice the `i += 4`)\n    const value = view.getUint32(i);\n    // toString(16) will transform the integer into the corresponding hex string\n    // but will remove any initial \"0\"\n    const stringValue = value.toString(16);\n    // One Uint32 element is 4 bytes or 8 hex chars (it would also work with 4\n    // chars for Uint16 and 2 chars for Uint8)\n    const padding = '00000000';\n    const paddedValue = (padding + stringValue).slice(-padding.length);\n    digest += paddedValue;\n  }\n\n  return digest;\n}\n"]}