{"version":3,"file":"Caveat.cjs","sourceRoot":"","sources":["../src/Caveat.ts"],"names":[],"mappings":";;;AACA,2CAA8C;AAE9C,yCAGkB;AAOlB,iDAA8C;AA+Q9C;;;;;GAKG;AACH,SAAgB,qCAAqC,CACnD,aAA4C;IAE5C,OAAO,IAAA,mBAAW,EAAC,aAAa,EAAE,WAAW,CAAC,CAAC;AACjD,CAAC;AAJD,sFAIC;AAED;;;;;;;;;;GAUG;AACH,SAAgB,mBAAmB,CAGjC,oBAAwE,EACxE,UAA0C,EAAE,iCAAiC;AAC7E,oBAAkE;IAElE,MAAM,EAAE,OAAO,EAAE,GAAG,UAAU,CAAC;IAC/B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,oBAAoB,CAAC;IAC9B,CAAC;IAED,IAAI,SAAS,GAAG,KAAK,EACnB,IAAuE,EACxD,EAAE,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC;IAE/C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,aAAa,GACjB,oBAAoB,CAAC,MAAM,CAAC,IAAoC,CAAC,CAAC;QACpE,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,MAAM,IAAI,oCAA2B,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACrD,CAAC;QAED,IAAI,CAAC,qCAAqC,CAAC,aAAa,CAAC,EAAE,CAAC;YAC1D,MAAM,IAAI,yCAAgC,CACxC,aAAa,EACb,2BAAc,CAAC,gBAAgB,CAChC,CAAC;QACJ,CAAC;QACD,SAAS,GAAG,aAAa,CAAC,SAAS,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACzD,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAjCD,kDAiCC","sourcesContent":["import type { Json } from '@metamask/utils';\nimport { hasProperty } from '@metamask/utils';\n\nimport {\n  CaveatSpecificationMismatchError,\n  UnrecognizedCaveatTypeError,\n} from './errors';\nimport type {\n  AsyncRestrictedMethod,\n  RestrictedMethod,\n  PermissionConstraint,\n  RestrictedMethodParameters,\n} from './Permission';\nimport { PermissionType } from './Permission';\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport type { PermissionController } from './PermissionController';\n\nexport type CaveatConstraint = {\n  /**\n   * The type of the caveat. The type is presumed to be meaningful in the\n   * context of the capability it is associated with.\n   *\n   * In MetaMask, every permission can only have one caveat of each type.\n   */\n  readonly type: string;\n\n  /**\n   * Any additional data necessary to enforce the caveat.\n   */\n  readonly value: Json;\n};\n\n/**\n * A `ZCAP-LD`-like caveat object. A caveat is associated with a particular\n * permission, and stored in its `caveats` array. Conceptually, a caveat is\n * an arbitrary attenuation of the authority granted by its associated\n * permission. It is the responsibility of the host to interpret and apply\n * the restriction represented by a caveat.\n *\n * @template Type - The type of the caveat.\n * @template Value - The value associated with the caveat.\n */\nexport type Caveat<Type extends string, Value extends Json> = {\n  /**\n   * The type of the caveat. The type is presumed to be meaningful in the\n   * context of the capability it is associated with.\n   *\n   * In MetaMask, every permission can only have one caveat of each type.\n   */\n  readonly type: Type;\n\n  /**\n   * Any additional data necessary to enforce the caveat.\n   */\n  readonly value: Value;\n};\n\n// Next, we define types used for specifying caveats at the consumer layer,\n// and a function for applying caveats to a restricted method request. This is\n// Accomplished by decorating the restricted method implementation with the\n// the corresponding caveat functions.\n\n/**\n * A function for applying caveats to a restricted method request.\n *\n * @template ParentCaveat - The caveat type associated with this decorator.\n * @param decorated - The restricted method implementation to be decorated.\n * The method may have already been decorated with other caveats.\n * @param caveat - The caveat object.\n * @returns The decorated restricted method implementation.\n */\nexport type CaveatDecorator<ParentCaveat extends CaveatConstraint> = (\n  decorated: AsyncRestrictedMethod<RestrictedMethodParameters, Json>,\n  caveat: ParentCaveat,\n) => AsyncRestrictedMethod<RestrictedMethodParameters, Json>;\n\n/**\n * Extracts a caveat value type from a caveat decorator.\n *\n * @template Decorator - The {@link CaveatDecorator} to extract a caveat value\n * type from.\n */\ntype ExtractCaveatValueFromDecorator<\n  Decorator extends CaveatDecorator<CaveatConstraint>,\n> = Decorator extends (\n  decorated: AsyncRestrictedMethod<RestrictedMethodParameters, Json>,\n  caveat: infer ParentCaveat,\n) => AsyncRestrictedMethod<RestrictedMethodParameters, Json>\n  ? ParentCaveat extends CaveatConstraint\n    ? ParentCaveat['value']\n    : never\n  : never;\n\n/**\n * A function for validating caveats of a particular type.\n *\n * @see `validator` in {@link CaveatSpecificationBase} for more details.\n * @template ParentCaveat - The caveat type associated with this validator.\n * @param caveat - The caveat object to validate.\n * @param origin - The origin associated with the parent permission.\n * @param target - The target of the parent permission.\n */\nexport type CaveatValidator<ParentCaveat extends CaveatConstraint> = (\n  caveat: { type: ParentCaveat['type']; value: unknown },\n  origin?: string,\n  target?: string,\n) => void;\n\n/**\n * A map of caveat type strings to {@link CaveatDiff} values.\n */\nexport type CaveatDiffMap<ParentCaveat extends CaveatConstraint> = {\n  [CaveatType in ParentCaveat['type']]: ParentCaveat['value'];\n};\n\n/**\n * A function that merges two caveat values of the same type. The values must be\n * merged in the fashion of a right-biased union.\n *\n * @see `ARCHITECTURE.md` for more details.\n * @template Value - The type of the values to merge.\n * @param leftValue - The left-hand value.\n * @param rightValue - The right-hand value.\n * @returns `[newValue, diff]`, i.e. the merged value and the diff between the left value\n * and the new value. The diff must be expressed in the same type as the value itself.\n */\nexport type CaveatValueMerger<Value extends Json> = (\n  leftValue: Value,\n  rightValue: Value,\n) => [Value, Value] | [];\n\nexport type CaveatSpecificationBase = {\n  /**\n   * The string type of the caveat.\n   */\n  type: string;\n\n  /**\n   * The validator function used to validate caveats of the associated type\n   * whenever they are constructed or mutated.\n   *\n   * The validator should throw an appropriate JSON-RPC error if validation fails.\n   *\n   * If no validator is specified, no validation of caveat values will be\n   * performed. In instances where caveats are mutated but a permission's caveat\n   * array has not changed, any corresponding permission validator will not be\n   * called. For this reason, permission validators **must not** be relied upon\n   * to validate caveats.\n   */\n  // TODO: Replace `any` with type\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  validator?: CaveatValidator<any>;\n\n  /**\n   * The merger function used to merge a pair of values of the associated caveat type\n   * during incremental permission requests. The values must be merged in the fashion\n   * of a right-biased union.\n   *\n   * @see `ARCHITECTURE.md` for more details.\n   */\n  // TODO: Replace `any` with type\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  merger?: CaveatValueMerger<any>;\n};\n\nexport type RestrictedMethodCaveatSpecificationConstraint =\n  CaveatSpecificationBase & {\n    /**\n     * The decorator function used to apply the caveat to restricted method\n     * requests.\n     */\n    decorator: CaveatDecorator<CaveatConstraint>;\n  };\n\nexport type EndowmentCaveatSpecificationConstraint = CaveatSpecificationBase;\n\n/**\n * The constraint for caveat specification objects. Every {@link Caveat}\n * supported by a {@link PermissionController} must have an associated\n * specification, which is the source of truth for all caveat-related types.\n * In addition, a caveat specification may include a decorator function used\n * to apply the caveat's attenuation to a restricted method. It may also include\n * a validator function specified by the consumer.\n *\n * See the README for more details.\n */\nexport type CaveatSpecificationConstraint =\n  | RestrictedMethodCaveatSpecificationConstraint\n  | EndowmentCaveatSpecificationConstraint;\n\n/**\n * Options for {@link CaveatSpecificationBuilder} functions.\n */\ntype CaveatSpecificationBuilderOptions<\n  DecoratorHooks extends Record<string, unknown>,\n  ValidatorHooks extends Record<string, unknown>,\n> = {\n  type?: string;\n  decoratorHooks?: DecoratorHooks;\n  validatorHooks?: ValidatorHooks;\n};\n\n/**\n * A function that builds caveat specifications. Modules that specify caveats\n * for external consumption should make this their primary / default export so\n * that host applications can use them to generate concrete specifications\n * tailored to their requirements.\n */\nexport type CaveatSpecificationBuilder<\n  Options extends CaveatSpecificationBuilderOptions<\n    Record<string, unknown>,\n    Record<string, unknown>\n  >,\n  Specification extends CaveatSpecificationConstraint,\n> = (options: Options) => Specification;\n\n/**\n * A caveat specification export object, containing the\n * {@link CaveatSpecificationBuilder} function and \"hook name\" objects.\n */\nexport type CaveatSpecificationBuilderExportConstraint = {\n  specificationBuilder: CaveatSpecificationBuilder<\n    CaveatSpecificationBuilderOptions<\n      Record<string, unknown>,\n      Record<string, unknown>\n    >,\n    CaveatSpecificationConstraint\n  >;\n  decoratorHookNames?: Record<string, true>;\n  validatorHookNames?: Record<string, true>;\n};\n\n/**\n * The specifications for all caveats supported by a particular\n * {@link PermissionController}.\n *\n * @template Specifications - The union of all {@link CaveatSpecificationConstraint} types.\n */\nexport type CaveatSpecificationMap<\n  CaveatSpecification extends CaveatSpecificationConstraint,\n> = Record<CaveatSpecification['type'], CaveatSpecification>;\n\n/**\n * Extracts the union of all caveat types specified by the given\n * {@link CaveatSpecificationConstraint} type.\n *\n * @template CaveatSpecification - The {@link CaveatSpecificationConstraint} to extract a\n * caveat type union from.\n */\nexport type ExtractCaveats<\n  CaveatSpecification extends CaveatSpecificationConstraint,\n> = CaveatSpecification extends RestrictedMethodCaveatSpecificationConstraint\n  ? Caveat<\n      CaveatSpecification['type'],\n      ExtractCaveatValueFromDecorator<\n        RestrictedMethodCaveatSpecificationConstraint['decorator']\n      >\n    >\n  : Caveat<CaveatSpecification['type'], Json>;\n\n/**\n * Extracts the type of a specific {@link Caveat} from a union of caveat\n * specifications.\n *\n * @template CaveatSpecifications - The union of all caveat specifications.\n * @template CaveatType - The type of the caveat to extract.\n */\nexport type ExtractCaveat<\n  CaveatSpecifications extends CaveatSpecificationConstraint,\n  CaveatType extends string,\n> = Extract<ExtractCaveats<CaveatSpecifications>, { type: CaveatType }>;\n\n/**\n * Extracts the value type of a specific {@link Caveat} from a union of caveat\n * specifications.\n *\n * @template CaveatSpecifications - The union of all caveat specifications.\n * @template CaveatType - The type of the caveat whose value to extract.\n */\nexport type ExtractCaveatValue<\n  CaveatSpecifications extends CaveatSpecificationConstraint,\n  CaveatType extends string,\n> = ExtractCaveat<CaveatSpecifications, CaveatType>['value'];\n\n/**\n * Determines whether a caveat specification is a restricted method caveat specification.\n *\n * @param specification - The caveat specification.\n * @returns True if the caveat specification is a restricted method caveat specification, otherwise false.\n */\nexport function isRestrictedMethodCaveatSpecification(\n  specification: CaveatSpecificationConstraint,\n): specification is RestrictedMethodCaveatSpecificationConstraint {\n  return hasProperty(specification, 'decorator');\n}\n\n/**\n * Decorate a restricted method implementation with its caveats.\n *\n * Note that all caveat functions (i.e. the argument and return value of the\n * decorator) must be awaited.\n *\n * @param methodImplementation - The restricted method implementation\n * @param permission - The origin's potential permission\n * @param caveatSpecifications - All caveat implementations\n * @returns The decorated method implementation\n */\nexport function decorateWithCaveats<\n  CaveatSpecifications extends CaveatSpecificationConstraint,\n>(\n  methodImplementation: RestrictedMethod<RestrictedMethodParameters, Json>,\n  permission: Readonly<PermissionConstraint>, // bound to the requesting origin\n  caveatSpecifications: CaveatSpecificationMap<CaveatSpecifications>, // all caveat implementations\n): RestrictedMethod<RestrictedMethodParameters, Json> {\n  const { caveats } = permission;\n  if (!caveats) {\n    return methodImplementation;\n  }\n\n  let decorated = async (\n    args: Parameters<RestrictedMethod<RestrictedMethodParameters, Json>>[0],\n  ): Promise<Json> => methodImplementation(args);\n\n  for (const caveat of caveats) {\n    const specification =\n      caveatSpecifications[caveat.type as CaveatSpecifications['type']];\n    if (!specification) {\n      throw new UnrecognizedCaveatTypeError(caveat.type);\n    }\n\n    if (!isRestrictedMethodCaveatSpecification(specification)) {\n      throw new CaveatSpecificationMismatchError(\n        specification,\n        PermissionType.RestrictedMethod,\n      );\n    }\n    decorated = specification.decorator(decorated, caveat);\n  }\n\n  return decorated;\n}\n"]}