{"version":3,"sources":["../src/context.ts"],"sourcesContent":["/**\n * Copyright 2024 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { runInActionRuntimeContext } from './action.js';\nimport { UserFacingError } from './error.js';\nimport { HasRegistry, Registry } from './registry.js';\n\nconst contextAlsKey = 'core.auth.context';\n\n/**\n * Action side channel data, like auth and other invocation context infromation provided by the invoker.\n */\nexport interface ActionContext {\n  /** Information about the currently authenticated user if provided. */\n  auth?: Record<string, any>;\n  [additionalContext: string]: any;\n}\n\n/**\n * Execute the provided function in the runtime context. Call {@link getFlowContext()} anywhere\n * within the async call stack to retrieve the context. If context object is undefined, this function\n * is a no op passthrough, the function will be invoked as is.\n */\nexport function runWithContext<R>(\n  registry: Registry,\n  context: ActionContext | undefined,\n  fn: () => R\n): R {\n  if (context === undefined) {\n    return fn();\n  }\n  return registry.asyncStore.run(contextAlsKey, context, () =>\n    runInActionRuntimeContext(registry, fn)\n  );\n}\n\n/**\n * Gets the runtime context of the current flow.\n */\nexport function getContext(\n  registry: Registry | HasRegistry\n): ActionContext | undefined {\n  if ((registry as HasRegistry).registry) {\n    registry = (registry as HasRegistry).registry;\n  }\n  registry = registry as Registry;\n  return registry.asyncStore.getStore<ActionContext>(contextAlsKey);\n}\n\n/**\n * A universal type that request handling extensions (e.g. express, next) can map their request to.\n * This allows ContextProviders to build consistent interfacese on any web framework.\n * Headers must be lowercase to ensure portability.\n */\nexport interface RequestData<T = any> {\n  method: 'GET' | 'PUT' | 'POST' | 'DELETE' | 'OPTIONS' | 'QUERY';\n  headers: Record<string, string>;\n  input: T;\n}\n\n/**\n * Middleware can read request data and add information to the context that will\n * be passed to the Action. If middleware throws an error, that error will fail\n * the request and the Action will not be invoked. Expected cases should return a\n * UserFacingError, which allows the request handler to know what data is safe to\n * return to end users.\n *\n * Middleware can provide validation in addition to parsing. For example, an auth\n * middleware can have policies for validating auth in addition to passing auth context\n * to the Action.\n */\nexport type ContextProvider<\n  C extends ActionContext = ActionContext,\n  T = any,\n> = (request: RequestData<T>) => C | Promise<C>;\n\nexport interface ApiKeyContext extends ActionContext {\n  auth: {\n    apiKey: string | undefined;\n  };\n}\n\nexport function apiKey(\n  policy: (context: ApiKeyContext) => void | Promise<void>\n): ContextProvider<ApiKeyContext>;\nexport function apiKey(value?: string): ContextProvider<ApiKeyContext>;\nexport function apiKey(\n  valueOrPolicy?: ((context: ApiKeyContext) => void | Promise<void>) | string\n): ContextProvider<ApiKeyContext> {\n  return async function (request: RequestData): Promise<ApiKeyContext> {\n    const context: ApiKeyContext = {\n      auth: { apiKey: request.headers['authorization'] },\n    };\n    if (typeof valueOrPolicy === 'string') {\n      if (!context.auth?.apiKey) {\n        console.error('THROWING UNAUTHENTICATED');\n        throw new UserFacingError('UNAUTHENTICATED', 'Unauthenticated');\n      }\n      if (context.auth?.apiKey != valueOrPolicy) {\n        console.error('Throwing PERMISSION_DENIED');\n        throw new UserFacingError('PERMISSION_DENIED', 'Permission Denied');\n      }\n    } else if (typeof valueOrPolicy === 'function') {\n      await valueOrPolicy(context);\n    } else if (typeof valueOrPolicy !== 'undefined') {\n      throw new Error(\n        `Invalid type ${typeof valueOrPolicy} passed to apiKey()`\n      );\n    }\n    return context;\n  };\n}\n"],"mappings":"AAgBA,SAAS,iCAAiC;AAC1C,SAAS,uBAAuB;AAGhC,MAAM,gBAAgB;AAgBf,SAAS,eACd,UACA,SACA,IACG;AACH,MAAI,YAAY,QAAW;AACzB,WAAO,GAAG;AAAA,EACZ;AACA,SAAO,SAAS,WAAW;AAAA,IAAI;AAAA,IAAe;AAAA,IAAS,MACrD,0BAA0B,UAAU,EAAE;AAAA,EACxC;AACF;AAKO,SAAS,WACd,UAC2B;AAC3B,MAAK,SAAyB,UAAU;AACtC,eAAY,SAAyB;AAAA,EACvC;AACA,aAAW;AACX,SAAO,SAAS,WAAW,SAAwB,aAAa;AAClE;AAuCO,SAAS,OACd,eACgC;AAChC,SAAO,eAAgB,SAA8C;AACnE,UAAM,UAAyB;AAAA,MAC7B,MAAM,EAAE,QAAQ,QAAQ,QAAQ,eAAe,EAAE;AAAA,IACnD;AACA,QAAI,OAAO,kBAAkB,UAAU;AACrC,UAAI,CAAC,QAAQ,MAAM,QAAQ;AACzB,gBAAQ,MAAM,0BAA0B;AACxC,cAAM,IAAI,gBAAgB,mBAAmB,iBAAiB;AAAA,MAChE;AACA,UAAI,QAAQ,MAAM,UAAU,eAAe;AACzC,gBAAQ,MAAM,4BAA4B;AAC1C,cAAM,IAAI,gBAAgB,qBAAqB,mBAAmB;AAAA,MACpE;AAAA,IACF,WAAW,OAAO,kBAAkB,YAAY;AAC9C,YAAM,cAAc,OAAO;AAAA,IAC7B,WAAW,OAAO,kBAAkB,aAAa;AAC/C,YAAM,IAAI;AAAA,QACR,gBAAgB,OAAO,aAAa;AAAA,MACtC;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;","names":[]}