{"version":3,"file":"notify.cjs","sourceRoot":"","sources":["../../src/restricted/notify.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n  PermissionSpecificationBuilder,\n  RestrictedMethodOptions,\n  ValidPermissionSpecification,\n} from '@metamask/permission-controller';\nimport { PermissionType, SubjectType } from '@metamask/permission-controller';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport type {\n  NotifyParams,\n  NotifyResult,\n  InterfaceContext,\n  ComponentOrElement,\n} from '@metamask/snaps-sdk';\nimport {\n  enumValue,\n  NotificationType,\n  union,\n  ContentType,\n  getErrorMessage,\n  ComponentOrElementStruct,\n} from '@metamask/snaps-sdk';\nimport {\n  createUnion,\n  validateLink,\n  validateTextLinks,\n} from '@metamask/snaps-utils';\nimport type { InferMatching, Snap } from '@metamask/snaps-utils';\nimport { object, string, optional } from '@metamask/superstruct';\nimport type { NonEmptyArray } from '@metamask/utils';\nimport { hasProperty, isObject } from '@metamask/utils';\n\nimport { type MethodHooksObject } from '../utils';\n\nconst methodName = 'snap_notify';\n\nconst NativeNotificationStruct = object({\n  type: enumValue(NotificationType.Native),\n  message: string(),\n});\n\nconst InAppNotificationStruct = object({\n  type: enumValue(NotificationType.InApp),\n  message: string(),\n});\n\nconst InAppNotificationWithDetailsStruct = object({\n  type: enumValue(NotificationType.InApp),\n  message: string(),\n  content: ComponentOrElementStruct,\n  title: string(),\n  footerLink: optional(\n    object({\n      href: string(),\n      text: string(),\n    }),\n  ),\n});\n\nconst NotificationParametersStruct = union([\n  InAppNotificationStruct,\n  InAppNotificationWithDetailsStruct,\n  NativeNotificationStruct,\n]);\n\nexport type NotificationArgs = InferMatching<\n  typeof NotificationParametersStruct,\n  NotifyParams\n>;\n\nexport type NotifyMethodHooks = {\n  /**\n   * @param snapId - The ID of the Snap that created the notification.\n   * @param args - The notification arguments.\n   */\n  showNativeNotification: (\n    snapId: string,\n    args: NotificationArgs,\n  ) => Promise<null>;\n\n  /**\n   * @param snapId - The ID of the Snap that created the notification.\n   * @param args - The notification arguments.\n   */\n  showInAppNotification: (\n    snapId: string,\n    args: NotificationArgs,\n  ) => Promise<null>;\n\n  isOnPhishingList: (url: string) => boolean;\n\n  maybeUpdatePhishingList: () => Promise<void>;\n\n  createInterface: (\n    origin: string,\n    content: ComponentOrElement,\n    context?: InterfaceContext,\n    contentType?: ContentType,\n  ) => Promise<string>;\n  getSnap: (snapId: string) => Snap | undefined;\n};\n\ntype SpecificationBuilderOptions = {\n  allowedCaveats?: Readonly<NonEmptyArray<string>> | null;\n  methodHooks: NotifyMethodHooks;\n};\n\ntype Specification = ValidPermissionSpecification<{\n  permissionType: PermissionType.RestrictedMethod;\n  targetName: typeof methodName;\n  methodImplementation: ReturnType<typeof getImplementation>;\n  allowedCaveats: Readonly<NonEmptyArray<string>> | null;\n}>;\n\n/**\n * The specification builder for the `snap_notify` permission.\n * `snap_notify` allows snaps to send multiple types of notifications to its users.\n *\n * @param options - The specification builder options.\n * @param options.allowedCaveats - The optional allowed caveats for the permission.\n * @param options.methodHooks - The RPC method hooks needed by the method implementation.\n * @returns The specification for the `snap_notify` permission.\n */\nexport const specificationBuilder: PermissionSpecificationBuilder<\n  PermissionType.RestrictedMethod,\n  SpecificationBuilderOptions,\n  Specification\n> = ({ allowedCaveats = null, methodHooks }: SpecificationBuilderOptions) => {\n  return {\n    permissionType: PermissionType.RestrictedMethod,\n    targetName: methodName,\n    allowedCaveats,\n    methodImplementation: getImplementation(methodHooks),\n    subjectTypes: [SubjectType.Snap],\n  };\n};\n\nconst methodHooks: MethodHooksObject<NotifyMethodHooks> = {\n  showNativeNotification: true,\n  showInAppNotification: true,\n  isOnPhishingList: true,\n  maybeUpdatePhishingList: true,\n  createInterface: true,\n  getSnap: true,\n};\n\nexport const notifyBuilder = Object.freeze({\n  targetName: methodName,\n  specificationBuilder,\n  methodHooks,\n} as const);\n\n/**\n * Builds the method implementation for `snap_notify`.\n *\n * @param hooks - The RPC method hooks.\n * @param hooks.showNativeNotification - A function that shows a native browser notification.\n * @param hooks.showInAppNotification - A function that shows a notification in the MetaMask UI.\n * @param hooks.isOnPhishingList - A function that checks for links against the phishing list.\n * @param hooks.maybeUpdatePhishingList - A function that updates the phishing list if needed.\n * @param hooks.createInterface - A function that creates the interface in SnapInterfaceController.\n * @param hooks.getSnap - A function that checks if a snap is installed.\n * @returns The method implementation which returns `null` on success.\n * @throws If the params are invalid.\n */\nexport function getImplementation({\n  showNativeNotification,\n  showInAppNotification,\n  isOnPhishingList,\n  maybeUpdatePhishingList,\n  createInterface,\n  getSnap,\n}: NotifyMethodHooks) {\n  return async function implementation(\n    args: RestrictedMethodOptions<NotifyParams>,\n  ): Promise<NotifyResult> {\n    const {\n      params,\n      context: { origin },\n    } = args;\n\n    await maybeUpdatePhishingList();\n\n    const validatedParams = getValidatedParams(\n      params,\n      isOnPhishingList,\n      getSnap,\n    );\n\n    if (hasProperty(validatedParams, 'content')) {\n      const id = await createInterface(\n        origin,\n        validatedParams.content as ComponentOrElement,\n        undefined,\n        ContentType.Notification,\n      );\n      validatedParams.content = id;\n    }\n\n    switch (validatedParams.type) {\n      case NotificationType.Native:\n        return await showNativeNotification(origin, validatedParams);\n      case NotificationType.InApp:\n        return await showInAppNotification(origin, validatedParams);\n      default:\n        throw rpcErrors.invalidParams({\n          message: 'Must specify a valid notification \"type\".',\n        });\n    }\n  };\n}\n\n/**\n * Validates the notify method `params` and returns them cast to the correct\n * type. Throws if validation fails.\n *\n * @param params - The unvalidated params object from the method request.\n * @param isOnPhishingList - The function that checks for links against the phishing list.\n * @param getSnap - A function that checks if a snap is installed.\n * @returns The validated method parameter object.\n * @throws If the params are invalid.\n */\nexport function getValidatedParams(\n  params: unknown,\n  isOnPhishingList: NotifyMethodHooks['isOnPhishingList'],\n  getSnap: NotifyMethodHooks['getSnap'],\n): NotifyParams {\n  if (!isObject(params)) {\n    throw rpcErrors.invalidParams({\n      message: 'Expected params to be a single object.',\n    });\n  }\n\n  const { type, message } = params;\n\n  if (\n    !type ||\n    typeof type !== 'string' ||\n    !Object.values(NotificationType).includes(type as NotificationType)\n  ) {\n    throw rpcErrors.invalidParams({\n      message: 'Must specify a valid notification \"type\".',\n    });\n  }\n\n  const isNotString = !message || typeof message !== 'string';\n  // Set to the max message length on a Mac notification for now.\n  if (\n    type === NotificationType.Native &&\n    (isNotString || message.length >= 50)\n  ) {\n    throw rpcErrors.invalidParams({\n      message:\n        'Must specify a non-empty string \"message\" less than 50 characters long.',\n    });\n  }\n\n  if (\n    type === NotificationType.InApp &&\n    (isNotString || message.length >= 500)\n  ) {\n    throw rpcErrors.invalidParams({\n      message:\n        'Must specify a non-empty string \"message\" less than 500 characters long.',\n    });\n  }\n\n  try {\n    const validatedParams = createUnion(\n      params,\n      NotificationParametersStruct,\n      'type',\n    );\n\n    validateTextLinks(validatedParams.message, isOnPhishingList, getSnap);\n\n    if (hasProperty(validatedParams, 'footerLink')) {\n      validateLink(validatedParams.footerLink.href, isOnPhishingList, getSnap);\n    }\n\n    return validatedParams;\n  } catch (error) {\n    throw rpcErrors.invalidParams({\n      message: `Invalid params: ${getErrorMessage(error)}`,\n    });\n  }\n}\n"]}