āĻāĻ•āĻŸāĻŋ āĻ¨āĻŋāĻ°āĻžāĻĒāĻĻ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ˛ā§‡āĻ–āĻž

āĻāĻ•āĻŸāĻŋ āĻ¨āĻŋāĻ°āĻžāĻĒāĻĻ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ˛ā§‡āĻ–āĻž

āĻ¸āĻžāĻ§āĻžāĻ°āĻŖ "āĻ•ā§āĻ˛āĻžāĻ¯āĻŧā§‡āĻ¨ā§āĻŸ-āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ°" āĻ†āĻ°ā§āĻ•āĻŋāĻŸā§‡āĻ•āĻšāĻžāĻ°ā§‡āĻ° āĻŦāĻŋāĻĒāĻ°ā§€āĻ¤ā§‡, āĻŦāĻŋāĻ•ā§‡āĻ¨ā§āĻĻā§āĻ°ā§€āĻ­ā§‚āĻ¤ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨āĻ—ā§āĻ˛āĻŋ āĻĻā§āĻŦāĻžāĻ°āĻž āĻšāĻŋāĻšā§āĻ¨āĻŋāĻ¤ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧ:

  • āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻ˛āĻ—āĻ‡āĻ¨ āĻāĻŦāĻ‚ āĻĒāĻžāĻ¸āĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻĄ āĻ¸āĻš āĻāĻ•āĻŸāĻŋ āĻĄāĻžāĻŸāĻžāĻŦā§‡āĻ¸ āĻ¸āĻ‚āĻ°āĻ•ā§āĻˇāĻŖ āĻ•āĻ°āĻžāĻ° āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ āĻ¨ā§‡āĻ‡āĨ¤ āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻ¤āĻĨā§āĻ¯ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻĻā§āĻŦāĻžāĻ°āĻž āĻāĻ•āĻšā§‡āĻŸāĻŋāĻ¯āĻŧāĻžāĻ­āĻžāĻŦā§‡ āĻ¸āĻ‚āĻ°āĻ•ā§āĻˇāĻŖ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧ, āĻāĻŦāĻ‚ āĻ¤āĻžāĻĻā§‡āĻ° āĻ¸āĻ¤ā§āĻ¯āĻ¤āĻž āĻ¨āĻŋāĻļā§āĻšāĻŋāĻ¤āĻ•āĻ°āĻŖ āĻĒā§āĻ°ā§‹āĻŸā§‹āĻ•āĻ˛ āĻ¸ā§āĻ¤āĻ°ā§‡ āĻ˜āĻŸā§‡āĨ¤
  • āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ° āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻžāĻ° āĻĻāĻ°āĻ•āĻžāĻ° āĻ¨ā§‡āĻ‡āĨ¤ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ āĻ˛āĻœāĻŋāĻ• āĻāĻ•āĻŸāĻŋ āĻŦā§āĻ˛āĻ•āĻšā§‡āĻ‡āĻ¨ āĻ¨ā§‡āĻŸāĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻ•ā§‡ āĻ•āĻžāĻ°ā§āĻ¯āĻ•āĻ° āĻ•āĻ°āĻž āĻ¯ā§‡āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡, āĻ¯ā§‡āĻ–āĻžāĻ¨ā§‡ āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ā§€āĻ¯āĻŧ āĻĒāĻ°āĻŋāĻŽāĻžāĻŖ āĻĄā§‡āĻŸāĻž āĻ¸āĻ‚āĻ°āĻ•ā§āĻˇāĻŖ āĻ•āĻ°āĻž āĻ¸āĻŽā§āĻ­āĻŦāĨ¤

āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€ āĻ•ā§€āĻ—ā§āĻ˛āĻŋāĻ° āĻœāĻ¨ā§āĻ¯ 2āĻŸāĻŋ āĻ¤ā§āĻ˛āĻ¨āĻžāĻŽā§‚āĻ˛āĻ•āĻ­āĻžāĻŦā§‡ āĻ¨āĻŋāĻ°āĻžāĻĒāĻĻ āĻ¸ā§āĻŸā§‹āĻ°ā§‡āĻœ āĻ°āĻ¯āĻŧā§‡āĻ›ā§‡ - āĻšāĻžāĻ°ā§āĻĄāĻ“āĻ¯āĻŧā§āĻ¯āĻžāĻ° āĻ“āĻ¯āĻŧāĻžāĻ˛ā§‡āĻŸ āĻāĻŦāĻ‚ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨āĨ¤ āĻšāĻžāĻ°ā§āĻĄāĻ“āĻ¯āĻŧā§āĻ¯āĻžāĻ° āĻ“āĻ¯āĻŧāĻžāĻ˛ā§‡āĻŸāĻ—ā§āĻ˛āĻŋ āĻŦā§‡āĻļāĻŋāĻ°āĻ­āĻžāĻ—āĻ‡ āĻ…āĻ¤ā§āĻ¯āĻ¨ā§āĻ¤ āĻ¸ā§āĻ°āĻ•ā§āĻˇāĻŋāĻ¤, āĻ¤āĻŦā§‡ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻž āĻ•āĻ āĻŋāĻ¨ āĻāĻŦāĻ‚ āĻŦāĻŋāĻ¨āĻžāĻŽā§‚āĻ˛ā§āĻ¯ā§‡ āĻĨā§‡āĻ•ā§‡ āĻ…āĻ¨ā§‡āĻ• āĻĻā§‚āĻ°ā§‡, āĻ¤āĻŦā§‡ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨āĻ—ā§āĻ˛āĻŋ āĻ¨āĻŋāĻ°āĻžāĻĒāĻ¤ā§āĻ¤āĻž āĻāĻŦāĻ‚ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°ā§‡āĻ° āĻ¸āĻšāĻœāĻ¤āĻžāĻ° āĻ¨āĻŋāĻ–ā§āĻāĻ¤ āĻ¸āĻŽāĻ¨ā§āĻŦāĻ¯āĻŧ, āĻāĻŦāĻ‚ āĻļā§‡āĻˇ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻ¸āĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āĻŦāĻŋāĻ¨āĻžāĻŽā§‚āĻ˛ā§āĻ¯ā§‡āĻ“ āĻšāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡ā§ˇ

āĻāĻ‡ āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻ•āĻŋāĻ›ā§ āĻŦāĻŋāĻŦā§‡āĻšāĻ¨āĻžāĻ¯āĻŧ āĻ¨āĻŋāĻ¯āĻŧā§‡, āĻ†āĻŽāĻ°āĻž āĻ˛ā§‡āĻ¨āĻĻā§‡āĻ¨ āĻāĻŦāĻ‚ āĻ¸ā§āĻŦāĻžāĻ•ā§āĻˇāĻ°ā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻ•āĻžāĻœ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻāĻ•āĻŸāĻŋ āĻ¸āĻžāĻ§āĻžāĻ°āĻŖ API āĻĒā§āĻ°āĻĻāĻžāĻ¨ āĻ•āĻ°ā§‡ āĻŦāĻŋāĻ•ā§‡āĻ¨ā§āĻĻā§āĻ°ā§€āĻ­ā§‚āĻ¤ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨āĻ—ā§āĻ˛āĻŋāĻ° āĻŦāĻŋāĻ•āĻžāĻļāĻ•ā§‡ āĻ¸āĻšāĻœāĻ¤āĻ° āĻ•āĻ°ā§‡ āĻ¸āĻŦāĻšā§‡āĻ¯āĻŧā§‡ āĻ¸ā§āĻ°āĻ•ā§āĻˇāĻŋāĻ¤ āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻ¤ā§‡ āĻšā§‡āĻ¯āĻŧā§‡āĻ›āĻŋāĻ˛āĻžāĻŽāĨ¤
āĻ†āĻŽāĻ°āĻž āĻ¨ā§€āĻšā§‡ āĻāĻ‡ āĻ…āĻ­āĻŋāĻœā§āĻžāĻ¤āĻž āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ•ā§‡ āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻŦāĻ˛āĻŦāĨ¤

āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§āĻŸāĻŋāĻ¤ā§‡ āĻ•ā§‹āĻĄ āĻ‰āĻĻāĻžāĻšāĻ°āĻŖ āĻāĻŦāĻ‚ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻ¨āĻļāĻŸ āĻ¸āĻš āĻāĻ•āĻŸāĻŋ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ•ā§€āĻ­āĻžāĻŦā§‡ āĻ˛āĻŋāĻ–āĻ¤ā§‡ āĻšāĻ¯āĻŧ āĻ¸ā§‡ āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ•ā§‡ āĻ§āĻžāĻĒā§‡ āĻ§āĻžāĻĒā§‡ āĻ¨āĻŋāĻ°ā§āĻĻā§‡āĻļāĻžāĻŦāĻ˛ā§€ āĻĨāĻžāĻ•āĻŦā§‡āĨ¤ āĻ†āĻĒāĻ¨āĻŋ āĻ¸āĻŦ āĻ•ā§‹āĻĄ āĻ–ā§āĻāĻœā§‡ āĻĒā§‡āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨ āĻ¸āĻ‚āĻ—ā§āĻ°āĻšāĻ¸ā§āĻĨāĻ˛. āĻĒā§āĻ°āĻ¤āĻŋāĻŸāĻŋ āĻĒā§āĻ°āĻ¤āĻŋāĻļā§āĻ°ā§āĻ¤āĻŋ āĻ¯ā§ŒāĻ•ā§āĻ¤āĻŋāĻ•āĻ­āĻžāĻŦā§‡ āĻāĻ‡ āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§ā§‡āĻ° āĻāĻ•āĻŸāĻŋ āĻŦāĻŋāĻ­āĻžāĻ—ā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻŽāĻŋāĻ˛ā§‡ āĻ¯āĻžāĻ¯āĻŧāĨ¤

āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ā§‡āĻ° āĻ¸āĻ‚āĻ•ā§āĻˇāĻŋāĻĒā§āĻ¤ āĻ‡āĻ¤āĻŋāĻšāĻžāĻ¸

āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨āĻ—ā§āĻ˛āĻŋ āĻĻā§€āĻ°ā§āĻ˜āĻ•āĻžāĻ˛ āĻ§āĻ°ā§‡ āĻ°āĻ¯āĻŧā§‡āĻ›ā§‡āĨ¤ āĻ¤āĻžāĻ°āĻž 1999 āĻ¸āĻžāĻ˛ā§‡ āĻ‡āĻ¨ā§āĻŸāĻžāĻ°āĻ¨ā§‡āĻŸ āĻāĻ•ā§āĻ¸āĻĒā§āĻ˛ā§‹āĻ°āĻžāĻ°ā§‡, 2004 āĻ¸āĻžāĻ˛ā§‡ āĻĢāĻžāĻ¯āĻŧāĻžāĻ°āĻĢāĻ•ā§āĻ¸ā§‡ āĻšāĻžāĻœāĻŋāĻ° āĻšāĻ¯āĻŧā§‡āĻ›āĻŋāĻ˛āĨ¤ āĻ¯āĻžāĻ‡āĻšā§‹āĻ•, āĻ–ā§āĻŦ āĻĻā§€āĻ°ā§āĻ˜ āĻ¸āĻŽāĻ¯āĻŧā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻ•ā§‹āĻ¨ āĻāĻ•āĻ• āĻŽāĻžāĻ¨ āĻ›āĻŋāĻ˛ āĻ¨āĻžāĨ¤

āĻ†āĻŽāĻ°āĻž āĻŦāĻ˛āĻ¤ā§‡ āĻĒāĻžāĻ°āĻŋ āĻ¯ā§‡ āĻāĻŸāĻŋ āĻ—ā§āĻ—āĻ˛ āĻ•ā§āĻ°ā§‹āĻŽā§‡āĻ° āĻšāĻ¤ā§āĻ°ā§āĻĨ āĻ¸āĻ‚āĻ¸ā§āĻ•āĻ°āĻŖā§‡ āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻ‰āĻĒāĻ¸ā§āĻĨāĻŋāĻ¤ āĻšāĻ¯āĻŧā§‡āĻ›āĻŋāĻ˛āĨ¤ āĻ…āĻŦāĻļā§āĻ¯āĻ‡, āĻ¤āĻ–āĻ¨ āĻ•ā§‹āĻ¨ āĻ¸ā§āĻĒā§‡āĻ¸āĻŋāĻĢāĻŋāĻ•ā§‡āĻļāĻ¨ āĻ›āĻŋāĻ˛ āĻ¨āĻž, āĻ•āĻŋāĻ¨ā§āĻ¤ā§ āĻāĻŸāĻŋ āĻ›āĻŋāĻ˛ āĻ•ā§āĻ°ā§‹āĻŽ āĻāĻĒāĻŋāĻ†āĻ‡ āĻ¯āĻž āĻāĻ° āĻ­āĻŋāĻ¤ā§āĻ¤āĻŋ āĻšāĻ¯āĻŧā§‡ āĻ‰āĻ ā§‡āĻ›ā§‡: āĻŦā§‡āĻļāĻŋāĻ°āĻ­āĻžāĻ— āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻŦāĻžāĻœāĻžāĻ° āĻœāĻ¯āĻŧ āĻ•āĻ°ā§‡ āĻāĻŦāĻ‚ āĻāĻ•āĻŸāĻŋ āĻ…āĻ¨ā§āĻ¤āĻ°ā§āĻ¨āĻŋāĻ°ā§āĻŽāĻŋāĻ¤ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ āĻ¸ā§āĻŸā§‹āĻ° āĻĨāĻžāĻ•āĻžāĻ° āĻĒāĻ°ā§‡, āĻ•ā§āĻ°ā§‹āĻŽ āĻ†āĻ¸āĻ˛ā§‡ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻŽāĻžāĻ¨ āĻ¨āĻŋāĻ°ā§āĻ§āĻžāĻ°āĻŖ āĻ•āĻ°ā§‡āĨ¤

āĻŽāĻœāĻŋāĻ˛āĻžāĻ° āĻ¨āĻŋāĻœāĻ¸ā§āĻŦ āĻŽāĻžāĻ¨ āĻ›āĻŋāĻ˛, āĻ•āĻŋāĻ¨ā§āĻ¤ā§ āĻ•ā§āĻ°ā§‹āĻŽ āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ā§‡āĻ° āĻœāĻ¨āĻĒā§āĻ°āĻŋāĻ¯āĻŧāĻ¤āĻž āĻĻā§‡āĻ–ā§‡ āĻ•ā§‹āĻŽā§āĻĒāĻžāĻ¨āĻŋ āĻāĻ•āĻŸāĻŋ āĻ¸āĻžāĻŽāĻžā§āĻœāĻ¸ā§āĻ¯āĻĒā§‚āĻ°ā§āĻŖ API āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻžāĻ° āĻ¸āĻŋāĻĻā§āĻ§āĻžāĻ¨ā§āĻ¤ āĻ¨āĻŋāĻ¯āĻŧā§‡āĻ›ā§‡āĨ¤ 2015 āĻ¸āĻžāĻ˛ā§‡, āĻŽāĻœāĻŋāĻ˛āĻžāĻ° āĻ‰āĻĻā§āĻ¯ā§‹āĻ—ā§‡, āĻ•ā§āĻ°āĻ¸-āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ¸ā§āĻĒā§‡āĻ¸āĻŋāĻĢāĻŋāĻ•ā§‡āĻļāĻ¨āĻ—ā§āĻ˛āĻŋāĻ¤ā§‡ āĻ•āĻžāĻœ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻ˛ā§āĻĄ āĻ“āĻ¯āĻŧāĻžāĻ‡āĻĄ āĻ“āĻ¯āĻŧā§‡āĻŦ āĻ•āĻ¨āĻ¸ā§‹āĻ°ā§āĻŸāĻŋāĻ¯āĻŧāĻžāĻŽ (W3C) āĻāĻ° āĻŽāĻ§ā§āĻ¯ā§‡ āĻāĻ•āĻŸāĻŋ āĻŦāĻŋāĻļā§‡āĻˇ āĻ—ā§āĻ°ā§āĻĒ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧā§‡āĻ›āĻŋāĻ˛āĨ¤

āĻ•ā§āĻ°ā§‹āĻŽā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻŦāĻŋāĻĻā§āĻ¯āĻŽāĻžāĻ¨ API āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨āĻ—ā§āĻ˛āĻŋāĻ•ā§‡ āĻ­āĻŋāĻ¤ā§āĻ¤āĻŋ āĻšāĻŋāĻ¸āĻžāĻŦā§‡ āĻ¨ā§‡āĻ“āĻ¯āĻŧāĻž āĻšāĻ¯āĻŧā§‡āĻ›āĻŋāĻ˛ā§ˇ āĻ•āĻžāĻœāĻŸāĻŋ āĻŽāĻžāĻ‡āĻ•ā§āĻ°ā§‹āĻ¸āĻĢā§āĻŸā§‡āĻ° āĻ¸āĻŽāĻ°ā§āĻĨāĻ¨ā§‡ āĻĒāĻ°āĻŋāĻšāĻžāĻ˛āĻŋāĻ¤ āĻšāĻ¯āĻŧā§‡āĻ›āĻŋāĻ˛ (āĻ—ā§āĻ—āĻ˛ āĻ¸ā§āĻŸā§āĻ¯āĻžāĻ¨ā§āĻĄāĻžāĻ°ā§āĻĄā§‡āĻ° āĻŦāĻŋāĻ•āĻžāĻļā§‡ āĻ…āĻ‚āĻļ āĻ¨āĻŋāĻ¤ā§‡ āĻ…āĻ¸ā§āĻŦā§€āĻ•āĻžāĻ° āĻ•āĻ°ā§‡āĻ›āĻŋāĻ˛), āĻāĻŦāĻ‚ āĻĢāĻ˛āĻ¸ā§āĻŦāĻ°ā§‚āĻĒ āĻāĻ•āĻŸāĻŋ āĻ–āĻ¸āĻĄāĻŧāĻž āĻ‰āĻĒāĻ¸ā§āĻĨāĻŋāĻ¤ āĻšāĻ¯āĻŧā§‡āĻ›āĻŋāĻ˛ āĻŦāĻŋāĻļā§‡āĻˇ āĻ‰āĻ˛ā§āĻ˛ā§‡āĻ–.

āĻ†āĻ¨ā§āĻˇā§āĻ āĻžāĻ¨āĻŋāĻ•āĻ­āĻžāĻŦā§‡, āĻ¸ā§āĻĒā§‡āĻ¸āĻŋāĻĢāĻŋāĻ•ā§‡āĻļāĻ¨ āĻāĻœ, āĻĢāĻžāĻ¯āĻŧāĻžāĻ°āĻĢāĻ•ā§āĻ¸ āĻāĻŦāĻ‚ āĻ…āĻĒā§‡āĻ°āĻž āĻĻā§āĻŦāĻžāĻ°āĻž āĻ¸āĻŽāĻ°ā§āĻĨāĻŋāĻ¤ (āĻŽāĻ¨ā§‡ āĻ°āĻžāĻ–āĻŦā§‡āĻ¨ āĻ¯ā§‡ Chrome āĻāĻ‡ āĻ¤āĻžāĻ˛āĻŋāĻ•āĻžāĻ¯āĻŧ āĻ¨ā§‡āĻ‡)āĨ¤ āĻ•āĻŋāĻ¨ā§āĻ¤ā§ āĻ†āĻ¸āĻ˛ā§‡, āĻ¸ā§āĻŸā§āĻ¯āĻžāĻ¨ā§āĻĄāĻžāĻ°ā§āĻĄāĻŸāĻŋ āĻŽā§‚āĻ˛āĻ¤ āĻ•ā§āĻ°ā§‹āĻŽā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻ¸āĻžāĻŽāĻžā§āĻœāĻ¸ā§āĻ¯āĻĒā§‚āĻ°ā§āĻŖ, āĻ¯ā§‡āĻšā§‡āĻ¤ā§ āĻāĻŸāĻŋ āĻ†āĻ¸āĻ˛ā§‡ āĻāĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ā§‡āĻ° āĻ‰āĻĒāĻ° āĻ­āĻŋāĻ¤ā§āĻ¤āĻŋ āĻ•āĻ°ā§‡ āĻ˛ā§‡āĻ–āĻž āĻšāĻ¯āĻŧā§‡āĻ›ā§‡āĨ¤ āĻ†āĻĒāĻ¨āĻŋ WebExtensions API āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ•ā§‡ āĻ†āĻ°āĻ“ āĻĒāĻĄāĻŧāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨ āĻāĻ–āĻžāĻ¨ā§‡.

āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ•āĻžāĻ āĻžāĻŽā§‹

āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ā§€āĻ¯āĻŧ āĻāĻ•āĻŽāĻžāĻ¤ā§āĻ° āĻĢāĻžāĻ‡āĻ˛āĻŸāĻŋ āĻšāĻ˛ āĻŽā§āĻ¯āĻžāĻ¨āĻŋāĻĢā§‡āĻ¸ā§āĻŸ (manifest.json)āĨ¤ āĻāĻŸāĻŋ āĻ¸āĻŽā§āĻĒā§āĻ°āĻ¸āĻžāĻ°āĻŖā§‡āĻ° "āĻāĻ¨ā§āĻŸā§āĻ°āĻŋ āĻĒāĻ¯āĻŧā§‡āĻ¨ā§āĻŸ"āĻ“āĨ¤

āĻŽā§āĻ¯āĻžāĻ¨āĻŋāĻĢā§‡āĻ¸ā§āĻŸā§‹

āĻ¸ā§āĻĒā§‡āĻ¸āĻŋāĻĢāĻŋāĻ•ā§‡āĻļāĻ¨ āĻ…āĻ¨ā§āĻ¯āĻžāĻ¯āĻŧā§€, āĻŽā§āĻ¯āĻžāĻ¨āĻŋāĻĢā§‡āĻ¸ā§āĻŸ āĻĢāĻžāĻ‡āĻ˛āĻŸāĻŋ āĻāĻ•āĻŸāĻŋ āĻŦā§ˆāĻ§ JSON āĻĢāĻžāĻ‡āĻ˛āĨ¤ āĻ•ā§‹āĻ¨ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ°ā§‡ āĻĻā§‡āĻ–āĻž āĻ¯āĻžāĻŦā§‡ āĻ•ā§‹āĻ¨ āĻ•ā§€ āĻ¸āĻŽāĻ°ā§āĻĨāĻŋāĻ¤ āĻ¸ā§‡ āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ•ā§‡ āĻ¤āĻĨā§āĻ¯ āĻ¸āĻš āĻŽā§āĻ¯āĻžāĻ¨āĻŋāĻĢā§‡āĻ¸ā§āĻŸ āĻ•ā§€āĻ—ā§āĻ˛āĻŋāĻ° āĻāĻ•āĻŸāĻŋ āĻ¸āĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āĻŦāĻŋāĻŦāĻ°āĻŖā§ˇ āĻāĻ–āĻžāĻ¨ā§‡.

āĻ¯ā§‡ āĻ•ā§€āĻ—ā§āĻ˛āĻŋ āĻ¸ā§āĻĒā§‡āĻ¸āĻŋāĻĢāĻŋāĻ•ā§‡āĻļāĻ¨ā§‡ āĻ¨ā§‡āĻ‡ āĻ¸ā§‡āĻ—ā§āĻ˛āĻŋāĻ•ā§‡ āĻ‰āĻĒā§‡āĻ•ā§āĻˇāĻž āĻ•āĻ°āĻž āĻ¯ā§‡āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡ (āĻ•ā§āĻ°ā§‹āĻŽ āĻāĻŦāĻ‚ āĻĢāĻžāĻ¯āĻŧāĻžāĻ°āĻĢāĻ•ā§āĻ¸ āĻ‰āĻ­āĻ¯āĻŧāĻ‡ āĻ¤ā§āĻ°ā§āĻŸāĻŋāĻ° āĻĒā§āĻ°āĻ¤āĻŋāĻŦā§‡āĻĻāĻ¨ āĻ•āĻ°ā§‡, āĻ¤āĻŦā§‡ āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨āĻ—ā§āĻ˛āĻŋ āĻ•āĻžāĻœ āĻ•āĻ°āĻ¤ā§‡ āĻĨāĻžāĻ•ā§‡)āĨ¤

āĻāĻŦāĻ‚ āĻ†āĻŽāĻŋ āĻ•āĻŋāĻ›ā§ āĻĒāĻ¯āĻŧā§‡āĻ¨ā§āĻŸ āĻŽāĻ¨ā§‹āĻ¯ā§‹āĻ— āĻ†āĻ•āĻ°ā§āĻˇāĻŖ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻžāĻ‡.

  1. āĻĒāĻŸāĻ­ā§‚āĻŽāĻŋ - āĻāĻ•āĻŸāĻŋ āĻŦāĻ¸ā§āĻ¤ā§ āĻ¯āĻž āĻ¨āĻŋāĻŽā§āĻ¨āĻ˛āĻŋāĻ–āĻŋāĻ¤ āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°āĻ—ā§āĻ˛āĻŋ āĻ…āĻ¨ā§āĻ¤āĻ°ā§āĻ­ā§āĻ•ā§āĻ¤ āĻ•āĻ°ā§‡:
    1. āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸ — āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸāĻ—ā§āĻ˛āĻŋāĻ° āĻāĻ•āĻŸāĻŋ āĻ…ā§āĻ¯āĻžāĻ°ā§‡ āĻ¯āĻž āĻĒāĻŸāĻ­ā§‚āĻŽāĻŋ āĻĒā§āĻ°āĻ¸āĻ™ā§āĻ—ā§‡ āĻ•āĻžāĻ°ā§āĻ¯āĻ•āĻ° āĻ•āĻ°āĻž āĻšāĻŦā§‡ (āĻ†āĻŽāĻ°āĻž āĻāĻ‡ āĻŦāĻŋāĻˇāĻ¯āĻŧā§‡ āĻāĻ•āĻŸā§ āĻĒāĻ°ā§‡ āĻ•āĻĨāĻž āĻŦāĻ˛āĻŦ);
    2. āĻĒā§ƒāĻˇā§āĻ āĻž - āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸāĻ—ā§āĻ˛āĻŋāĻ° āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤ā§‡ āĻ¯āĻž āĻāĻ•āĻŸāĻŋ āĻ–āĻžāĻ˛āĻŋ āĻĒā§ƒāĻˇā§āĻ āĻžāĻ¯āĻŧ āĻ•āĻžāĻ°ā§āĻ¯āĻ•āĻ° āĻ•āĻ°āĻž āĻšāĻŦā§‡, āĻ†āĻĒāĻ¨āĻŋ āĻŦāĻŋāĻˇāĻ¯āĻŧāĻŦāĻ¸ā§āĻ¤ā§āĻ° āĻ¸āĻžāĻĨā§‡ html āĻ‰āĻ˛ā§āĻ˛ā§‡āĻ– āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨āĨ¤ āĻāĻ‡ āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°ā§‡, āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸ āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°āĻŸāĻŋ āĻ‰āĻĒā§‡āĻ•ā§āĻˇāĻž āĻ•āĻ°āĻž āĻšāĻŦā§‡, āĻāĻŦāĻ‚ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸāĻ—ā§āĻ˛āĻŋāĻ•ā§‡ āĻŦāĻŋāĻˇāĻ¯āĻŧāĻŦāĻ¸ā§āĻ¤ā§ āĻĒā§ƒāĻˇā§āĻ āĻžāĻ¯āĻŧ āĻ¸āĻ¨ā§āĻ¨āĻŋāĻŦā§‡āĻļ āĻ•āĻ°āĻžāĻ¤ā§‡ āĻšāĻŦā§‡;
    3. āĻœāĻŋāĻĻ āĻ•āĻ°āĻž — āĻāĻ•āĻŸāĻŋ āĻŦāĻžāĻ‡āĻ¨āĻžāĻ°āĻŋ āĻĒāĻ¤āĻžāĻ•āĻž, āĻ¯āĻĻāĻŋ āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻ¨āĻž āĻ•āĻ°āĻž āĻšāĻ¯āĻŧ, āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ°āĻŸāĻŋ āĻĒāĻŸāĻ­ā§‚āĻŽāĻŋ āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻŸāĻŋāĻ•ā§‡ "āĻšāĻ¤ā§āĻ¯āĻž" āĻ•āĻ°āĻŦā§‡ āĻ¯āĻ–āĻ¨ āĻāĻŸāĻŋ āĻŦāĻŋāĻŦā§‡āĻšāĻ¨āĻž āĻ•āĻ°āĻŦā§‡ āĻ¯ā§‡ āĻāĻŸāĻŋ āĻ•āĻŋāĻ›ā§ āĻ•āĻ°āĻ›ā§‡ āĻ¨āĻž āĻāĻŦāĻ‚ āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ā§‡ āĻāĻŸāĻŋ āĻĒā§āĻ¨āĻ°āĻžāĻ¯āĻŧ āĻšāĻžāĻ˛ā§ āĻ•āĻ°āĻŦā§‡āĨ¤ āĻ…āĻ¨ā§āĻ¯āĻĨāĻžāĻ¯āĻŧ, āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻŦāĻ¨ā§āĻ§ āĻšāĻ˛ā§‡āĻ‡ āĻĒā§ƒāĻˇā§āĻ āĻžāĻŸāĻŋ āĻ†āĻ¨āĻ˛ā§‹āĻĄ āĻ•āĻ°āĻž āĻšāĻŦā§‡āĨ¤ āĻĢāĻžāĻ¯āĻŧāĻžāĻ°āĻĢāĻ•ā§āĻ¸ā§‡ āĻ¸āĻŽāĻ°ā§āĻĨāĻŋāĻ¤ āĻ¨āĻ¯āĻŧāĨ¤
  2. content_scripts — āĻŦāĻ¸ā§āĻ¤ā§āĻ° āĻāĻ•āĻŸāĻŋ āĻ…ā§āĻ¯āĻžāĻ°ā§‡ āĻ¯āĻž āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻŦāĻŋāĻ­āĻŋāĻ¨ā§āĻ¨ āĻ“āĻ¯āĻŧā§‡āĻŦ āĻĒā§‡āĻœā§‡ āĻŦāĻŋāĻ­āĻŋāĻ¨ā§āĻ¨ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸ āĻ˛ā§‹āĻĄ āĻ•āĻ°āĻ¤ā§‡ āĻĻā§‡āĻ¯āĻŧāĨ¤ āĻĒā§āĻ°āĻ¤āĻŋāĻŸāĻŋ āĻŦāĻ¸ā§āĻ¤ā§āĻ° āĻ¨āĻŋāĻŽā§āĻ¨āĻ˛āĻŋāĻ–āĻŋāĻ¤ āĻ—ā§āĻ°ā§āĻ¤ā§āĻŦāĻĒā§‚āĻ°ā§āĻŖ āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ° āĻ°āĻ¯āĻŧā§‡āĻ›ā§‡:
    1. āĻŽā§āĻ¯āĻžāĻš - āĻĒā§āĻ¯āĻžāĻŸāĻžāĻ°ā§āĻ¨ āĻ‡āĻ‰āĻ†āĻ°āĻāĻ˛, āĻ¯āĻž āĻāĻ•āĻŸāĻŋ āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻŦāĻŋāĻˇāĻ¯āĻŧāĻŦāĻ¸ā§āĻ¤ā§ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸ āĻ…āĻ¨ā§āĻ¤āĻ°ā§āĻ­ā§āĻ•ā§āĻ¤ āĻ•āĻ°āĻž āĻšāĻŦā§‡ āĻ•āĻŋ āĻ¨āĻž āĻ¤āĻž āĻ¨āĻŋāĻ°ā§āĻ§āĻžāĻ°āĻŖ āĻ•āĻ°ā§‡āĨ¤
    2. js — āĻāĻ‡ āĻŽā§āĻ¯āĻžāĻšā§‡ āĻ˛ā§‹āĻĄ āĻ•āĻ°āĻž āĻšāĻŦā§‡ āĻāĻŽāĻ¨ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸāĻ—ā§āĻ˛āĻŋāĻ° āĻāĻ•āĻŸāĻŋ āĻ¤āĻžāĻ˛āĻŋāĻ•āĻž;
    3. āĻŦāĻžāĻĻ āĻĻāĻŋāĻ¨ - āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ° āĻĨā§‡āĻ•ā§‡ āĻŦāĻžāĻĻ match āĻāĻ‡ āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°ā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻŽā§‡āĻ˛ā§‡ āĻāĻŽāĻ¨ URL
  3. āĻĒā§ƒāĻˇā§āĻ āĻž_āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻž - āĻ†āĻ¸āĻ˛ā§‡ āĻāĻ•āĻŸāĻŋ āĻŦāĻ¸ā§āĻ¤ā§ āĻ¯āĻž āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ°ā§‡ āĻ āĻŋāĻ•āĻžāĻ¨āĻž āĻŦāĻžāĻ°ā§‡āĻ° āĻĒāĻžāĻļā§‡ āĻĒā§āĻ°āĻĻāĻ°ā§āĻļāĻŋāĻ¤ āĻ†āĻ‡āĻ•āĻ¨ā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻĻāĻžāĻ¯āĻŧā§€ āĻāĻŦāĻ‚ āĻāĻŸāĻŋāĻ° āĻ¸āĻžāĻĨā§‡ āĻŽāĻŋāĻĨāĻ¸ā§āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĨ¤ āĻāĻŸāĻŋ āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻāĻ•āĻŸāĻŋ āĻĒāĻĒāĻ†āĻĒ āĻ‰āĻ‡āĻ¨ā§āĻĄā§‹ āĻĒā§āĻ°āĻĻāĻ°ā§āĻļāĻ¨ āĻ•āĻ°āĻžāĻ° āĻ…āĻ¨ā§āĻŽāĻ¤āĻŋ āĻĻā§‡āĻ¯āĻŧ, āĻ¯āĻž āĻ†āĻĒāĻ¨āĻžāĻ° āĻ¨āĻŋāĻœāĻ¸ā§āĻŦ HTML, CSS āĻāĻŦāĻ‚ JS āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡ āĻ¸āĻ‚āĻœā§āĻžāĻžāĻ¯āĻŧāĻŋāĻ¤ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧāĨ¤
    1. āĻĄāĻŋāĻĢāĻ˛ā§āĻŸ_āĻĒāĻĒāĻ†āĻĒ — āĻĒāĻĒāĻ†āĻĒ āĻ‡āĻ¨ā§āĻŸāĻžāĻ°āĻĢā§‡āĻ¸ āĻ¸āĻš HTML āĻĢāĻžāĻ‡āĻ˛ā§‡āĻ° āĻĒāĻžāĻĨ, CSS āĻāĻŦāĻ‚ JS āĻĨāĻžāĻ•āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĨ¤
  4. āĻ…āĻ¨ā§āĻŽāĻ¤āĻŋ — āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ…āĻ§āĻŋāĻ•āĻžāĻ° āĻĒāĻ°āĻŋāĻšāĻžāĻ˛āĻ¨āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻāĻ•āĻŸāĻŋ āĻ…ā§āĻ¯āĻžāĻ°ā§‡āĨ¤ 3 āĻĒā§āĻ°āĻ•āĻžāĻ°ā§‡āĻ° āĻ…āĻ§āĻŋāĻ•āĻžāĻ° āĻ°āĻ¯āĻŧā§‡āĻ›ā§‡, āĻ¯āĻž āĻŦāĻŋāĻ¸ā§āĻ¤āĻžāĻ°āĻŋāĻ¤āĻ­āĻžāĻŦā§‡ āĻŦāĻ°ā§āĻŖāĻ¨āĻž āĻ•āĻ°āĻž āĻšāĻ¯āĻŧā§‡āĻ›ā§‡ āĻāĻ–āĻžāĻ¨ā§‡
  5. āĻ“āĻ¯āĻŧā§‡āĻŦ_āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸āĻ¯ā§‹āĻ—ā§āĻ¯_āĻ¸āĻŽā§āĻĒāĻĻ — āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ¸āĻŽā§āĻĒāĻĻ āĻ¯āĻž āĻāĻ•āĻŸāĻŋ āĻ“āĻ¯āĻŧā§‡āĻŦ āĻĒā§ƒāĻˇā§āĻ āĻž āĻ…āĻ¨ā§āĻ°ā§‹āĻ§ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡, āĻ‰āĻĻāĻžāĻšāĻ°āĻŖāĻ¸ā§āĻŦāĻ°ā§‚āĻĒ, āĻ›āĻŦāĻŋ, JS, CSS, HTML āĻĢāĻžāĻ‡āĻ˛āĨ¤
  6. āĻŦāĻžāĻšā§āĻ¯āĻŋāĻ•āĻ­āĻžāĻŦā§‡_āĻ¸āĻ‚āĻ¯ā§‹āĻ—āĻ¯ā§‹āĻ—ā§āĻ¯ — āĻāĻ–āĻžāĻ¨ā§‡ āĻ†āĻĒāĻ¨āĻŋ āĻ¸ā§āĻĒāĻˇā§āĻŸāĻ­āĻžāĻŦā§‡ āĻ…āĻ¨ā§āĻ¯āĻžāĻ¨ā§āĻ¯ āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ā§‡āĻ° ID āĻāĻŦāĻ‚ āĻ“āĻ¯āĻŧā§‡āĻŦ āĻĒā§ƒāĻˇā§āĻ āĻžāĻ—ā§āĻ˛āĻŋāĻ° āĻĄā§‹āĻŽā§‡āĻ¨āĻ—ā§āĻ˛āĻŋ āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨ āĻ¯ā§‡āĻ–āĻžāĻ¨ āĻĨā§‡āĻ•ā§‡ āĻ†āĻĒāĻ¨āĻŋ āĻ¸āĻ‚āĻ¯ā§‹āĻ— āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨ā§ˇ āĻāĻ•āĻŸāĻŋ āĻĄā§‹āĻŽā§‡āĻ‡āĻ¨ āĻĻā§āĻŦāĻŋāĻ¤ā§€āĻ¯āĻŧ āĻ¸ā§āĻ¤āĻ° āĻŦāĻž āĻ‰āĻšā§āĻšāĻ¤āĻ° āĻšāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĨ¤ āĻĢāĻžāĻ¯āĻŧāĻžāĻ°āĻĢāĻ•ā§āĻ¸ā§‡ āĻ•āĻžāĻœ āĻ•āĻ°ā§‡ āĻ¨āĻžāĨ¤

āĻŽā§ƒāĻ¤ā§āĻ¯ā§āĻĻāĻ¨ā§āĻĄ āĻĒā§āĻ°āĻ¸āĻ™ā§āĻ—

āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨āĻŸāĻŋāĻ¤ā§‡ āĻ¤āĻŋāĻ¨āĻŸāĻŋ āĻ•ā§‹āĻĄ āĻāĻ•ā§āĻ¸āĻŋāĻ•āĻŋāĻ‰āĻļāĻ¨ āĻĒā§āĻ°āĻ¸āĻ™ā§āĻ— āĻ°āĻ¯āĻŧā§‡āĻ›ā§‡, āĻ…āĻ°ā§āĻĨāĻžā§Ž, āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° API-āĻ āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ā§‡āĻ° āĻŦāĻŋāĻ­āĻŋāĻ¨ā§āĻ¨ āĻ¸ā§āĻ¤āĻ° āĻ¸āĻš āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨āĻŸāĻŋāĻ¤ā§‡ āĻ¤āĻŋāĻ¨āĻŸāĻŋ āĻ…āĻ‚āĻļ āĻ°āĻ¯āĻŧā§‡āĻ›ā§‡āĨ¤

āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻĒā§āĻ°āĻ¸āĻ™ā§āĻ—

āĻŦā§‡āĻļāĻŋāĻ°āĻ­āĻžāĻ— API āĻāĻ–āĻžāĻ¨ā§‡ āĻ‰āĻĒāĻ˛āĻŦā§āĻ§āĨ¤ āĻāĻ‡ āĻĒā§āĻ°ā§‡āĻ•ā§āĻˇāĻžāĻĒāĻŸā§‡ āĻ¤āĻžāĻ°āĻž "āĻ˛āĻžāĻ‡āĻ­":

  1. āĻĒāĻŸāĻ­ā§‚āĻŽāĻŋ āĻĒāĻžāĻ¤āĻž - āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ā§‡āĻ° "āĻŦā§āĻ¯āĻžāĻ•āĻāĻ¨ā§āĻĄ" āĻ…āĻ‚āĻļāĨ¤ āĻĢāĻžāĻ‡āĻ˛āĻŸāĻŋ "āĻŦā§āĻ¯āĻžāĻ•āĻ—ā§āĻ°āĻžāĻ‰āĻ¨ā§āĻĄ" āĻ•ā§€ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡ āĻŽā§āĻ¯āĻžāĻ¨āĻŋāĻĢā§‡āĻ¸ā§āĻŸā§‡ āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧā§‡āĻ›ā§‡āĨ¤
  2. āĻĒāĻĒāĻ†āĻĒ āĻĒā§ƒāĻˇā§āĻ āĻž - āĻāĻ•āĻŸāĻŋ āĻĒāĻĒāĻ†āĻĒ āĻĒā§ƒāĻˇā§āĻ āĻž āĻ¯āĻž āĻ†āĻĒāĻ¨āĻŋ āĻ¯āĻ–āĻ¨ āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ†āĻ‡āĻ•āĻ¨ā§‡ āĻ•ā§āĻ˛āĻŋāĻ• āĻ•āĻ°ā§‡āĻ¨ āĻ¤āĻ–āĻ¨ āĻĒā§āĻ°āĻĻāĻ°ā§āĻļāĻŋāĻ¤ āĻšāĻ¯āĻŧā§ˇ āĻ‡āĻļāĻ¤ā§‡āĻšāĻžāĻ°ā§‡ browser_action -> default_popup.
  3. āĻ•āĻžāĻ¸ā§āĻŸāĻŽ āĻĒā§ƒāĻˇā§āĻ āĻž — āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻĒā§ƒāĻˇā§āĻ āĻž, āĻĻā§ƒāĻļā§āĻ¯ā§‡āĻ° āĻāĻ•āĻŸāĻŋ āĻĒā§ƒāĻĨāĻ• āĻŸā§āĻ¯āĻžāĻŦā§‡ "āĻ˛āĻŋāĻ­āĻŋāĻ‚" chrome-extension://<id_Ņ€Đ°ŅŅˆĐ¸Ņ€ĐĩĐŊиŅ>/customPage.html.

āĻāĻ‡ āĻĒā§āĻ°āĻ¸āĻ™ā§āĻ—āĻŸāĻŋ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻ‰āĻ‡āĻ¨ā§āĻĄā§‹ āĻāĻŦāĻ‚ āĻŸā§āĻ¯āĻžāĻŦ āĻĨā§‡āĻ•ā§‡ āĻ¸ā§āĻŦāĻžāĻ§ā§€āĻ¨āĻ­āĻžāĻŦā§‡ āĻŦāĻŋāĻĻā§āĻ¯āĻŽāĻžāĻ¨āĨ¤ āĻĒāĻŸāĻ­ā§‚āĻŽāĻŋ āĻĒāĻžāĻ¤āĻž āĻāĻ•āĻŸāĻŋ āĻāĻ•āĻ• āĻ…āĻ¨ā§āĻ˛āĻŋāĻĒāĻŋāĻ¤ā§‡ āĻŦāĻŋāĻĻā§āĻ¯āĻŽāĻžāĻ¨ āĻāĻŦāĻ‚ āĻ¸āĻ°ā§āĻŦāĻĻāĻž āĻ•āĻžāĻœ āĻ•āĻ°ā§‡ (āĻŦā§āĻ¯āĻ¤āĻŋāĻ•ā§āĻ°āĻŽ āĻšāĻ˛ āĻ‡āĻ­ā§‡āĻ¨ā§āĻŸ āĻĒā§ƒāĻˇā§āĻ āĻž, āĻ¯āĻ–āĻ¨ āĻŦā§āĻ¯āĻžāĻ•āĻ—ā§āĻ°āĻžāĻ‰āĻ¨ā§āĻĄ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸ āĻāĻ•āĻŸāĻŋ āĻ‡āĻ­ā§‡āĻ¨ā§āĻŸ āĻĻā§āĻŦāĻžāĻ°āĻž āĻšāĻžāĻ˛ā§ āĻšāĻ¯āĻŧ āĻāĻŦāĻ‚ āĻāĻŸāĻŋ āĻ•āĻžāĻ°ā§āĻ¯āĻ•āĻ° āĻšāĻ“āĻ¯āĻŧāĻžāĻ° āĻĒāĻ°ā§‡ "āĻŽā§ƒāĻ¤ā§āĻ¯ā§" āĻšāĻ¯āĻŧ)āĨ¤ āĻĒāĻĒāĻ†āĻĒ āĻĒā§ƒāĻˇā§āĻ āĻž āĻĒāĻĒāĻ†āĻĒ āĻ‰āĻ‡āĻ¨ā§āĻĄā§‹ āĻ–ā§‹āĻ˛āĻž āĻĨāĻžāĻ•āĻ˛ā§‡ āĻŦāĻŋāĻĻā§āĻ¯āĻŽāĻžāĻ¨, āĻāĻŦāĻ‚ āĻ•āĻžāĻ¸ā§āĻŸāĻŽ āĻĒā§ƒāĻˇā§āĻ āĻž — āĻ¯āĻ–āĻ¨ āĻāĻŸāĻŋāĻ° āĻ¸āĻžāĻĨā§‡ āĻŸā§āĻ¯āĻžāĻŦāĻŸāĻŋ āĻ–ā§‹āĻ˛āĻž āĻĨāĻžāĻ•ā§‡āĨ¤ āĻāĻ‡ āĻĒā§āĻ°āĻ¸āĻ™ā§āĻ—ā§‡ āĻ…āĻ¨ā§āĻ¯ āĻŸā§āĻ¯āĻžāĻŦ āĻāĻŦāĻ‚ āĻ¤āĻžāĻĻā§‡āĻ° āĻŦāĻŋāĻˇāĻ¯āĻŧāĻŦāĻ¸ā§āĻ¤ā§āĻ¤ā§‡ āĻ•ā§‹āĻ¨ āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻ¨ā§‡āĻ‡āĨ¤

āĻŦāĻŋāĻˇāĻ¯āĻŧāĻŦāĻ¸ā§āĻ¤ā§ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸ āĻĒā§āĻ°āĻ¸āĻ™ā§āĻ—

āĻĒā§āĻ°āĻ¤āĻŋāĻŸāĻŋ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻŸā§āĻ¯āĻžāĻŦā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻ•āĻ¨ā§āĻŸā§‡āĻ¨ā§āĻŸ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸ āĻĢāĻžāĻ‡āĻ˛ āĻšāĻžāĻ˛ā§ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧāĨ¤ āĻāĻŸāĻŋāĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ā§‡āĻ° API āĻāĻ° āĻ…āĻ‚āĻļ āĻāĻŦāĻ‚ āĻ“āĻ¯āĻŧā§‡āĻŦ āĻĒā§ƒāĻˇā§āĻ āĻžāĻ° DOM āĻŸā§āĻ°āĻŋāĻ¤ā§‡ āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻ°āĻ¯āĻŧā§‡āĻ›ā§‡āĨ¤ āĻāĻŸāĻŋ āĻ•āĻ¨ā§āĻŸā§‡āĻ¨ā§āĻŸ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸ āĻ¯āĻž āĻĒā§ƒāĻˇā§āĻ āĻžāĻ° āĻ¸āĻžāĻĨā§‡ āĻŽāĻŋāĻĨāĻ¸ā§āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻž āĻœāĻ¨ā§āĻ¯ āĻĻāĻžāĻ¯āĻŧā§€āĨ¤ āĻ¯ā§‡ āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨āĻ—ā§āĻ˛āĻŋ DOM āĻŸā§āĻ°āĻŋāĻ•ā§‡ āĻŽā§āĻ¯āĻžāĻ¨āĻŋāĻĒā§āĻ˛ā§‡āĻŸ āĻ•āĻ°ā§‡ āĻ¤āĻžāĻ°āĻž āĻŦāĻŋāĻˇāĻ¯āĻŧāĻŦāĻ¸ā§āĻ¤ā§ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸā§‡ āĻāĻŸāĻŋ āĻ•āĻ°ā§‡ - āĻ‰āĻĻāĻžāĻšāĻ°āĻŖāĻ¸ā§āĻŦāĻ°ā§‚āĻĒ, āĻ…ā§āĻ¯āĻžāĻĄ āĻŦā§āĻ˛āĻ•āĻžāĻ° āĻŦāĻž āĻ…āĻ¨ā§āĻŦāĻžāĻĻāĻ•ā§ˇ āĻāĻ›āĻžāĻĄāĻŧāĻžāĻ“, āĻŦāĻŋāĻˇāĻ¯āĻŧāĻŦāĻ¸ā§āĻ¤ā§ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸ āĻ¸ā§āĻŸā§āĻ¯āĻžāĻ¨ā§āĻĄāĻžāĻ°ā§āĻĄ āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ āĻĒā§ƒāĻˇā§āĻ āĻžāĻ° āĻ¸āĻžāĻĨā§‡ āĻ¯ā§‹āĻ—āĻžāĻ¯ā§‹āĻ— āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡ postMessage.

āĻ“āĻ¯āĻŧā§‡āĻŦ āĻĒā§‡āĻœ āĻĒā§āĻ°āĻ¸āĻ™ā§āĻ—

āĻāĻŸāĻŋ āĻĒā§āĻ°āĻ•ā§ƒāĻ¤ āĻ“āĻ¯āĻŧā§‡āĻŦ āĻĒā§‡āĻœ āĻ¨āĻŋāĻœā§‡āĻ‡. āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻāĻ° āĻ•ā§‹āĻ¨ā§‹ āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ• āĻ¨ā§‡āĻ‡ āĻāĻŦāĻ‚ āĻ¸ā§‡āĻ–āĻžāĻ¨ā§‡ āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻ¨ā§‡āĻ‡, āĻāĻ‡ āĻĒā§ƒāĻˇā§āĻ āĻžāĻ° āĻĄā§‹āĻŽā§‡āĻ¨āĻŸāĻŋ āĻŽā§āĻ¯āĻžāĻ¨āĻŋāĻĢā§‡āĻ¸ā§āĻŸā§‡ āĻ¸ā§āĻĒāĻˇā§āĻŸāĻ­āĻžāĻŦā§‡ āĻ¨āĻŋāĻ°ā§āĻĻā§‡āĻļāĻŋāĻ¤ āĻ¨āĻž āĻĨāĻžāĻ•āĻ˛ā§‡ (āĻ¨ā§€āĻšā§‡ āĻāĻ‡ āĻŦāĻŋāĻˇāĻ¯āĻŧā§‡ āĻ†āĻ°āĻ“)āĨ¤

āĻŦāĻžāĻ°ā§āĻ¤āĻž āĻŦāĻŋāĻ¨āĻŋāĻŽāĻ¯āĻŧ

āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ā§‡āĻ° āĻŦāĻŋāĻ­āĻŋāĻ¨ā§āĻ¨ āĻ…āĻ‚āĻļ āĻāĻ•ā§‡ āĻ…āĻĒāĻ°ā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻŦāĻžāĻ°ā§āĻ¤āĻž āĻŦāĻŋāĻ¨āĻŋāĻŽāĻ¯āĻŧ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡āĨ¤ āĻāĻ‡ āĻœāĻ¨ā§āĻ¯ āĻāĻ•āĻŸāĻŋ API āĻ†āĻ›ā§‡ runtime.sendMessage āĻāĻ•āĻŸāĻŋ āĻŦāĻžāĻ°ā§āĻ¤āĻž āĻĒāĻžāĻ āĻžāĻ¤ā§‡ background и tabs.sendMessage āĻāĻ•āĻŸāĻŋ āĻĒā§ƒāĻˇā§āĻ āĻžāĻ¯āĻŧ āĻāĻ•āĻŸāĻŋ āĻŦāĻžāĻ°ā§āĻ¤āĻž āĻĒāĻžāĻ āĻžāĻ¤ā§‡ (āĻ¸āĻžāĻŽāĻ—ā§āĻ°ā§€ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸ, āĻĒāĻĒāĻ†āĻĒ āĻŦāĻž āĻ“āĻ¯āĻŧā§‡āĻŦ āĻĒā§ƒāĻˇā§āĻ āĻž āĻ¯āĻĻāĻŋ āĻ‰āĻĒāĻ˛āĻŦā§āĻ§ āĻĨāĻžāĻ•ā§‡ externally_connectable) Chrome API āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻ•āĻ°āĻžāĻ° āĻ¸āĻŽāĻ¯āĻŧ āĻ¨ā§€āĻšā§‡ āĻāĻ•āĻŸāĻŋ āĻ‰āĻĻāĻžāĻšāĻ°āĻŖ āĻĻā§‡āĻ“āĻ¯āĻŧāĻž āĻšāĻ˛ā§ˇ

// ХООйŅ‰ĐĩĐŊиĐĩĐŧ ĐŧĐžĐļĐĩŅ‚ ĐąŅ‹Ņ‚ŅŒ ĐģŅŽĐąĐžĐš JSON ŅĐĩŅ€Đ¸Đ°ĐģиСŅƒĐĩĐŧŅ‹Đš ОйŅŠĐĩĐēŅ‚
const msg = {a: 'foo', b: 'bar'};

// extensionId ĐŧĐžĐļĐŊĐž ĐŊĐĩ ŅƒĐēаСŅ‹Đ˛Đ°Ņ‚ŅŒ, ĐĩŅĐģи ĐŧŅ‹ Ņ…ĐžŅ‚иĐŧ ĐŋĐžŅĐģĐ°Ņ‚ŅŒ ŅĐžĐžĐąŅ‰ĐĩĐŊиĐĩ 'ŅĐ˛ĐžĐĩĐŧŅƒ' Ņ€Đ°ŅŅˆĐ¸Ņ€ĐĩĐŊиŅŽ (иС ui иĐģи ĐēĐžĐŊŅ‚ĐĩĐŊŅ‚ ŅĐēŅ€Đ¸ĐŋŅ‚Đ°)
chrome.runtime.sendMessage(extensionId, msg);

// ĐĸĐ°Đē вŅ‹ĐŗĐģŅĐ´Đ¸Ņ‚ ОйŅ€Đ°ĐąĐžŅ‚Ņ‡Đ¸Đē
chrome.runtime.onMessage.addListener((msg) => console.log(msg))

// МоĐļĐŊĐž ŅĐģĐ°Ņ‚ŅŒ ŅĐžĐžĐąŅ‰ĐĩĐŊиŅ вĐēĐģĐ°Đ´ĐēĐ°Đŧ СĐŊĐ°Ņ иŅ… id
chrome.tabs.sendMessage(tabId, msg)

// ПоĐģŅƒŅ‡Đ¸Ņ‚ŅŒ Đē вĐēĐģĐ°Đ´ĐēĐ°Đŧ и иŅ… id ĐŧĐžĐļĐŊĐž, ĐŊĐ°ĐŋŅ€Đ¸ĐŧĐĩŅ€, вОŅ‚ Ņ‚Đ°Đē
chrome.tabs.query(
    {currentWindow: true, active : true},
    function(tabArray){
      tabArray.forEach(tab => console.log(tab.id))
    }
)

āĻ¸āĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āĻ¯ā§‹āĻ—āĻžāĻ¯ā§‹āĻ—ā§‡āĻ° āĻœāĻ¨ā§āĻ¯, āĻ†āĻĒāĻ¨āĻŋ āĻāĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ āĻ¸āĻ‚āĻ¯ā§‹āĻ— āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨ runtime.connect. āĻœāĻŦāĻžāĻŦā§‡ āĻ†āĻŽāĻ°āĻž āĻ—ā§āĻ°āĻšāĻŖ āĻ•āĻ°āĻŦ runtime.Port, āĻ¯ā§‡āĻŸāĻŋāĻ¤ā§‡, āĻāĻŸāĻŋ āĻ–ā§‹āĻ˛āĻž āĻĨāĻžāĻ•āĻžāĻ•āĻžāĻ˛ā§€āĻ¨, āĻ†āĻĒāĻ¨āĻŋ āĻ¯ā§‡āĻ•ā§‹āĻ¨ā§‹ āĻ¸āĻ‚āĻ–ā§āĻ¯āĻ• āĻŦāĻžāĻ°ā§āĻ¤āĻž āĻĒāĻžāĻ āĻžāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨āĨ¤ āĻ•ā§āĻ˛āĻžāĻ¯āĻŧā§‡āĻ¨ā§āĻŸā§‡āĻ° āĻĻāĻŋāĻ•ā§‡, āĻ‰āĻĻāĻžāĻšāĻ°āĻŖāĻ¸ā§āĻŦāĻ°ā§‚āĻĒ, contentscript, āĻāĻŸāĻž āĻāĻ‡ āĻŽāĻ¤ āĻĻā§‡āĻ–āĻžāĻ¯āĻŧ:

// ОĐŋŅŅ‚ŅŒ ĐļĐĩ extensionId ĐŧĐžĐļĐŊĐž ĐŊĐĩ ŅƒĐēаСŅ‹Đ˛Đ°Ņ‚ŅŒ ĐŋŅ€Đ¸ ĐēĐžĐŧĐŧŅƒĐŊиĐēĐ°Ņ†Đ¸Đ¸ вĐŊŅƒŅ‚Ņ€Đ¸ ОдĐŊĐžĐŗĐž Ņ€Đ°ŅŅˆĐ¸Ņ€ĐĩĐŊиŅ. ПодĐēĐģŅŽŅ‡ĐĩĐŊиĐĩ ĐŧĐžĐļĐŊĐž иĐŧĐĩĐŊОваŅ‚ŅŒ
const port = chrome.runtime.connect({name: "knockknock"});
port.postMessage({joke: "Knock knock"});
port.onMessage.addListener(function(msg) {
    if (msg.question === "Who's there?")
        port.postMessage({answer: "Madame"});
    else if (msg.question === "Madame who?")
        port.postMessage({answer: "Madame... Bovary"});

āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ° āĻŦāĻž āĻĒāĻŸāĻ­ā§‚āĻŽāĻŋ:

// ОбŅ€Đ°ĐąĐžŅ‚Ņ‡Đ¸Đē Đ´ĐģŅ ĐŋОдĐēĐģŅŽŅ‡ĐĩĐŊиŅ 'ŅĐ˛ĐžĐ¸Ņ…' вĐēĐģĐ°Đ´ĐžĐē. КоĐŊŅ‚ĐĩĐŊŅ‚ ŅĐēŅ€Đ¸ĐŋŅ‚Ов, popup иĐģи ŅŅ‚Ņ€Đ°ĐŊиŅ† Ņ€Đ°ŅŅˆĐ¸Ņ€ĐĩĐŊиŅ
chrome.runtime.onConnect.addListener(function(port) {
    console.assert(port.name === "knockknock");
    port.onMessage.addListener(function(msg) {
        if (msg.joke === "Knock knock")
            port.postMessage({question: "Who's there?"});
        else if (msg.answer === "Madame")
            port.postMessage({question: "Madame who?"});
        else if (msg.answer === "Madame... Bovary")
            port.postMessage({question: "I don't get it."});
    });
});

// ОбŅ€Đ°ĐąĐžŅ‚Ņ‡Đ¸Đē Đ´ĐģŅ ĐŋОдĐēĐģŅŽŅ‡ĐĩĐŊиŅ вĐŊĐĩŅˆĐŊиŅ… вĐēĐģĐ°Đ´ĐžĐē. ДŅ€ŅƒĐŗиŅ… Ņ€Đ°ŅŅˆĐ¸Ņ€ĐĩĐŊиК иĐģи вĐĩĐą ŅŅ‚Ņ€Đ°ĐŊиŅ†, ĐēĐžŅ‚ĐžŅ€Ņ‹Đŧ Ņ€Đ°ĐˇŅ€ĐĩŅˆĐĩĐŊ Đ´ĐžŅŅ‚ŅƒĐŋ в ĐŧĐ°ĐŊиŅ„ĐĩŅŅ‚Đĩ
chrome.runtime.onConnectExternal.addListener(function(port) {
    ...
});

āĻāĻ•āĻŸāĻŋ āĻ…āĻ¨ā§āĻˇā§āĻ āĻžāĻ¨āĻ“ āĻ†āĻ›ā§‡ onDisconnect āĻāĻŦāĻ‚ āĻĒāĻĻā§āĻ§āĻ¤āĻŋ disconnect.

āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ āĻĄāĻžāĻ¯āĻŧāĻžāĻ—ā§āĻ°āĻžāĻŽ

āĻ†āĻ¸ā§āĻ¨ āĻāĻ•āĻŸāĻŋ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻŋ āĻ¯āĻž āĻŦā§āĻ¯āĻ•ā§āĻ¤āĻŋāĻ—āĻ¤ āĻ•ā§€ āĻ¸āĻ‚āĻ°āĻ•ā§āĻˇāĻŖ āĻ•āĻ°ā§‡, āĻ¸āĻ°ā§āĻŦāĻœāĻ¨ā§€āĻ¨ āĻ¤āĻĨā§āĻ¯ā§‡ āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻ¸āĻ°āĻŦāĻ°āĻžāĻš āĻ•āĻ°ā§‡ (āĻ āĻŋāĻ•āĻžāĻ¨āĻž, āĻ¸āĻ°ā§āĻŦāĻœāĻ¨ā§€āĻ¨ āĻ•ā§€ āĻĒā§ƒāĻˇā§āĻ āĻžāĻ° āĻ¸āĻžāĻĨā§‡ āĻ¯ā§‹āĻ—āĻžāĻ¯ā§‹āĻ— āĻ•āĻ°ā§‡ āĻāĻŦāĻ‚ āĻ¤ā§ƒāĻ¤ā§€āĻ¯āĻŧ āĻĒāĻ•ā§āĻˇā§‡āĻ° āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨āĻ—ā§āĻ˛āĻŋāĻ•ā§‡ āĻ˛ā§‡āĻ¨āĻĻā§‡āĻ¨ā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻāĻ•āĻŸāĻŋ āĻ¸ā§āĻŦāĻžāĻ•ā§āĻˇāĻ°ā§‡āĻ° āĻ…āĻ¨ā§āĻ°ā§‹āĻ§ āĻ•āĻ°āĻžāĻ° āĻ…āĻ¨ā§āĻŽāĻ¤āĻŋ āĻĻā§‡āĻ¯āĻŧā§ˇ

āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ āĻĄā§‡āĻ­ā§‡āĻ˛āĻĒāĻŽā§‡āĻ¨ā§āĻŸ

āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ āĻ‰āĻ­āĻ¯āĻŧāĻ‡ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻ¸āĻžāĻĨā§‡ āĻ‡āĻ¨ā§āĻŸāĻžāĻ°āĻ…ā§āĻ¯āĻžāĻ•ā§āĻŸ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡ āĻāĻŦāĻ‚ āĻĒā§ƒāĻˇā§āĻ āĻžāĻŸāĻŋāĻ•ā§‡ āĻ•āĻ˛ āĻ•āĻ°āĻžāĻ° āĻĒāĻĻā§āĻ§āĻ¤āĻŋāĻ—ā§āĻ˛āĻŋ (āĻ‰āĻĻāĻžāĻšāĻ°āĻŖāĻ¸ā§āĻŦāĻ°ā§‚āĻĒ, āĻ˛ā§‡āĻ¨āĻĻā§‡āĻ¨ āĻ¸ā§āĻŦāĻžāĻ•ā§āĻˇāĻ° āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯) āĻāĻ•āĻŸāĻŋ API āĻĻāĻŋāĻ¯āĻŧā§‡ āĻ¸āĻ°āĻŦāĻ°āĻžāĻš āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡āĨ¤ āĻļā§āĻ§ā§ āĻāĻ•āĻŸāĻŋ āĻĻāĻŋāĻ¯āĻŧā§‡ āĻ•āĻ°āĻž contentscript āĻ•āĻžāĻœ āĻ•āĻ°āĻŦā§‡ āĻ¨āĻž, āĻ¯ā§‡āĻšā§‡āĻ¤ā§ āĻāĻŸāĻŋāĻ° āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° DOM-āĻ āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻ†āĻ›ā§‡, āĻ•āĻŋāĻ¨ā§āĻ¤ā§ āĻĒā§ƒāĻˇā§āĻ āĻžāĻ° JS-āĻ āĻ¨āĻ¯āĻŧāĨ¤ āĻāĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ āĻ¸āĻ‚āĻ¯ā§‹āĻ— āĻ•āĻ°ā§āĻ¨ runtime.connect āĻ†āĻŽāĻ°āĻž āĻĒāĻžāĻ°āĻŋ āĻ¨āĻž, āĻ•āĻžāĻ°āĻŖ āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻĄā§‹āĻŽā§‡āĻ¨ā§‡ API āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨, āĻāĻŦāĻ‚ āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸāĻ—ā§āĻ˛āĻŋ āĻŽā§āĻ¯āĻžāĻ¨āĻŋāĻĢā§‡āĻ¸ā§āĻŸā§‡ āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻ•āĻ°āĻž āĻ¯ā§‡āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĨ¤ āĻĢāĻ˛āĻ¸ā§āĻŦāĻ°ā§‚āĻĒ, āĻšāĻŋāĻ¤ā§āĻ°āĻŸāĻŋ āĻāĻ‡āĻ°āĻ•āĻŽ āĻĻā§‡āĻ–āĻžāĻŦā§‡:

āĻāĻ•āĻŸāĻŋ āĻ¨āĻŋāĻ°āĻžāĻĒāĻĻ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ˛ā§‡āĻ–āĻž

āĻ†āĻ°ā§‡āĻ•āĻŸāĻŋ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸ āĻĨāĻžāĻ•āĻŦā§‡ - inpage, āĻ¯āĻž āĻ†āĻŽāĻ°āĻž āĻĒā§‡āĻœā§‡ āĻ‡āĻ¨āĻœā§‡āĻ•ā§āĻŸ āĻ•āĻ°āĻŦāĨ¤ āĻāĻŸāĻŋ āĻ¤āĻžāĻ° āĻĒā§āĻ°āĻ¸āĻ™ā§āĻ—ā§‡ āĻšāĻ˛āĻŦā§‡ āĻāĻŦāĻ‚ āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻ•āĻžāĻœ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻāĻ•āĻŸāĻŋ API āĻĒā§āĻ°āĻĻāĻžāĻ¨ āĻ•āĻ°āĻŦā§‡āĨ¤

НаŅ‡Đ°ĐģĐž

āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ•ā§‹āĻĄ āĻĒāĻžāĻ“āĻ¯āĻŧāĻž āĻ¯āĻžāĻ¯āĻŧ GitHub. āĻŦāĻ°ā§āĻŖāĻ¨āĻžāĻ° āĻ¸āĻŽāĻ¯āĻŧ āĻ•āĻŽāĻŋāĻŸā§‡āĻ° āĻ˛āĻŋāĻ™ā§āĻ• āĻĨāĻžāĻ•āĻŦā§‡āĨ¤

āĻāĻ° āĻ‡āĻļāĻ¤ā§‡āĻšāĻžāĻ° āĻĻāĻŋāĻ¯āĻŧā§‡ āĻļā§āĻ°ā§ āĻ•āĻ°āĻž āĻ¯āĻžāĻ•:

{
  // ИĐŧŅ и ĐžĐŋиŅĐ°ĐŊиĐĩ, вĐĩŅ€ŅĐ¸Ņ. ВŅĐĩ ŅŅ‚Đž ĐąŅƒĐ´ĐĩŅ‚ видĐŊĐž в ĐąŅ€Đ°ŅƒĐˇĐĩŅ€Đĩ в chrome://extensions/?id=<id Ņ€Đ°ŅŅˆĐ¸Ņ€ĐĩĐŊиŅ>
  "name": "Signer",
  "description": "Extension demo",
  "version": "0.0.1",
  "manifest_version": 2,

  // ĐĄĐēŅ€Đ¸ĐŋŅ‚Ņ‹, ĐēĐžŅ‚ĐžŅ€Ņ‹Đĩ ĐąŅƒĐ´ŅƒŅ‚ иŅĐŋĐžĐģĐŊŅŅ‚ŅŅ в background, иŅ… ĐŧĐžĐļĐĩŅ‚ ĐąŅ‹Ņ‚ŅŒ ĐŊĐĩŅĐēĐžĐģŅŒĐēĐž
  "background": {
    "scripts": ["background.js"]
  },

  // КаĐēОК html иŅĐŋĐžĐģŅŒĐˇĐžĐ˛Đ°Ņ‚ŅŒ Đ´ĐģŅ popup
  "browser_action": {
    "default_title": "My Extension",
    "default_popup": "popup.html"
  },

  // КоĐŊŅ‚ĐĩĐŊŅ‚ ŅĐēŅ€Đ¸ĐŋŅ‚Ņ‹.
  // ĐŖ ĐŊĐ°Ņ ОдиĐŊ ОйŅŠĐĩĐēŅ‚: Đ´ĐģŅ вŅĐĩŅ… url ĐŊĐ°Ņ‡Đ¸ĐŊĐ°ŅŽŅ‰Đ¸Ņ…ŅŅ Ņ http иĐģи https ĐŧŅ‹ СаĐŋŅƒŅĐēĐ°ĐĩĐŧ
  // contenscript context ŅĐž ŅĐēŅ€Đ¸ĐŋŅ‚ĐžĐŧ contentscript.js. ЗаĐŋŅƒŅĐēĐ°Ņ‚ŅŒ ŅŅ€Đ°ĐˇŅƒ ĐŋĐž ĐŋĐžĐģŅƒŅ‡ĐĩĐŊии Đ´ĐžĐēŅƒĐŧĐĩĐŊŅ‚Đ° Đ´ĐģŅ вŅĐĩŅ… Ņ„Ņ€ĐĩĐšĐŧОв
  "content_scripts": [
    {
      "matches": [
        "http://*/*",
        "https://*/*"
      ],
      "js": [
        "contentscript.js"
      ],
      "run_at": "document_start",
      "all_frames": true
    }
  ],
  // РаСŅ€ĐĩŅˆĐĩĐŊ Đ´ĐžŅŅ‚ŅƒĐŋ Đē localStorage и idle api
  "permissions": [
    "storage",
    // "unlimitedStorage",
    //"clipboardWrite",
    "idle"
    //"activeTab",
    //"webRequest",
    //"notifications",
    //"tabs"
  ],
  // ЗдĐĩŅŅŒ ŅƒĐēаСŅ‹Đ˛Đ°ŅŽŅ‚ŅŅ Ņ€ĐĩŅŅƒŅ€ŅŅ‹, Đē ĐēĐžŅ‚ĐžŅ€Ņ‹Đŧ ĐąŅƒĐ´ĐĩŅ‚ иĐŧĐĩŅ‚ŅŒ Đ´ĐžŅŅ‚ŅƒĐŋ вĐĩĐą ŅŅ‚Ņ€Đ°ĐŊиŅ†Đ°. ĐĸĐžĐĩŅŅ‚ŅŒ иŅ… ĐŧĐžĐļĐŊĐž ĐąŅƒĐ´ĐĩŅ‚ СаĐŋŅ€Đ°ŅˆĐ¸Đ˛Đ°Ņ‚ŅŒ fetche'Đŧ иĐģи ĐŋŅ€ĐžŅŅ‚Đž xhr
  "web_accessible_resources": ["inpage.js"]
}

āĻ–āĻžāĻ˛āĻŋ background.js, popup.js, inpage.js āĻāĻŦāĻ‚ contentscript.js āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°ā§āĻ¨āĨ¤ āĻ†āĻŽāĻ°āĻž popup.html āĻ¯ā§‹āĻ— āĻ•āĻ°āĻŋ - āĻāĻŦāĻ‚ āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ āĻ‡āĻ¤āĻŋāĻŽāĻ§ā§āĻ¯ā§‡āĻ‡ Google Chrome āĻ āĻ˛ā§‹āĻĄ āĻ•āĻ°āĻž āĻ¯ā§‡āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡ āĻāĻŦāĻ‚ āĻ¨āĻŋāĻļā§āĻšāĻŋāĻ¤ āĻ•āĻ°ā§āĻ¨ āĻ¯ā§‡ āĻāĻŸāĻŋ āĻ•āĻžāĻœ āĻ•āĻ°ā§‡āĨ¤

āĻāĻŸāĻŋ āĻ¯āĻžāĻšāĻžāĻ‡ āĻ•āĻ°āĻ¤ā§‡, āĻ†āĻĒāĻ¨āĻŋ āĻ•ā§‹āĻĄāĻŸāĻŋ āĻ¨āĻŋāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨ āĻāĻ–āĻžāĻ¨ā§‡ āĻĨā§‡āĻ•ā§‡. āĻ†āĻŽāĻ°āĻž āĻ¯āĻž āĻ•āĻ°ā§‡āĻ›āĻŋ āĻ¤āĻž āĻ›āĻžāĻĄāĻŧāĻžāĻ“, āĻ˛āĻŋāĻ™ā§āĻ•āĻŸāĻŋ āĻ“āĻ¯āĻŧā§‡āĻŦāĻĒā§āĻ¯āĻžāĻ• āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡ āĻĒā§āĻ°āĻ•āĻ˛ā§āĻĒā§‡āĻ° āĻ¸āĻŽāĻžāĻŦā§‡āĻļ āĻ•āĻ¨āĻĢāĻŋāĻ—āĻžāĻ° āĻ•āĻ°ā§‡āĻ›ā§‡āĨ¤ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ°ā§‡ āĻāĻ•āĻŸāĻŋ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ āĻ¯ā§āĻ•ā§āĻ¤ āĻ•āĻ°āĻ¤ā§‡, chrome://extensions-āĻ āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻ˛ā§‹āĻĄ āĻ†āĻ¨āĻĒā§āĻ¯āĻžāĻ• āĻ•āĻ°āĻž āĻāĻŦāĻ‚ āĻ¸āĻ‚āĻļā§āĻ˛āĻŋāĻˇā§āĻŸ āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ¸āĻš āĻĢā§‹āĻ˛ā§āĻĄāĻžāĻ° āĻ¨āĻŋāĻ°ā§āĻŦāĻžāĻšāĻ¨ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡ - āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°ā§‡ dist.

āĻāĻ•āĻŸāĻŋ āĻ¨āĻŋāĻ°āĻžāĻĒāĻĻ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ˛ā§‡āĻ–āĻž

āĻāĻ–āĻ¨ āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ‡āĻ¨āĻ¸ā§āĻŸāĻ˛ āĻāĻŦāĻ‚ āĻ•āĻžāĻœ āĻ•āĻ°āĻ›ā§‡āĨ¤ āĻ†āĻĒāĻ¨āĻŋ āĻ¨āĻŋāĻŽā§āĻ¨āĻ°ā§‚āĻĒ āĻŦāĻŋāĻ­āĻŋāĻ¨ā§āĻ¨ āĻĒā§āĻ°āĻ¸āĻ™ā§āĻ—ā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻŦāĻŋāĻ•āĻžāĻļāĻ•āĻžāĻ°ā§€ āĻ¸āĻ°āĻžā§āĻœāĻžāĻŽāĻ—ā§āĻ˛āĻŋ āĻšāĻžāĻ˛āĻžāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨:

āĻĒāĻĒāĻ†āĻĒ ->

āĻāĻ•āĻŸāĻŋ āĻ¨āĻŋāĻ°āĻžāĻĒāĻĻ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ˛ā§‡āĻ–āĻž

āĻ•āĻ¨ā§āĻŸā§‡āĻ¨ā§āĻŸ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸ āĻ•āĻ¨āĻ¸ā§‹āĻ˛ā§‡ āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻ¸ā§‡āĻ‡ āĻĒā§ƒāĻˇā§āĻ āĻžāĻ° āĻ•āĻ¨āĻ¸ā§‹āĻ˛ā§‡āĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧ āĻ¯ā§‡āĻ–āĻžāĻ¨ā§‡ āĻāĻŸāĻŋ āĻšāĻžāĻ˛ā§ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧā§‡āĻ›ā§‡āĨ¤āĻāĻ•āĻŸāĻŋ āĻ¨āĻŋāĻ°āĻžāĻĒāĻĻ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ˛ā§‡āĻ–āĻž

āĻŦāĻžāĻ°ā§āĻ¤āĻž āĻŦāĻŋāĻ¨āĻŋāĻŽāĻ¯āĻŧ

āĻ¸ā§āĻ¤āĻ°āĻžāĻ‚, āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻĻā§āĻŸāĻŋ āĻ¯ā§‹āĻ—āĻžāĻ¯ā§‹āĻ—ā§‡āĻ° āĻšā§āĻ¯āĻžāĻ¨ā§‡āĻ˛ āĻ¸ā§āĻĨāĻžāĻĒāĻ¨ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡: āĻ‡āĻ¨āĻĒā§‡āĻœ <-> āĻŦā§āĻ¯āĻžāĻ•āĻ—ā§āĻ°āĻžāĻ‰āĻ¨ā§āĻĄ āĻāĻŦāĻ‚ āĻĒāĻĒāĻ†āĻĒ <-> āĻŦā§āĻ¯āĻžāĻ•āĻ—ā§āĻ°āĻžāĻ‰āĻ¨ā§āĻĄāĨ¤ āĻ†āĻĒāĻ¨āĻŋ āĻ…āĻŦāĻļā§āĻ¯āĻ‡ āĻĒā§‹āĻ°ā§āĻŸā§‡ āĻŦāĻžāĻ°ā§āĻ¤āĻž āĻĒāĻžāĻ āĻžāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨ āĻāĻŦāĻ‚ āĻ†āĻĒāĻ¨āĻžāĻ° āĻ¨āĻŋāĻœāĻ¸ā§āĻŦ āĻĒā§āĻ°ā§‹āĻŸā§‹āĻ•āĻ˛ āĻ‰āĻĻā§āĻ­āĻžāĻŦāĻ¨ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨, āĻ¤āĻŦā§‡ āĻ†āĻŽāĻŋ āĻŽā§‡āĻŸāĻžāĻŽāĻžāĻ¸ā§āĻ• āĻ“āĻĒā§‡āĻ¨ āĻ¸ā§‹āĻ°ā§āĻ¸ āĻĒā§āĻ°āĻ•āĻ˛ā§āĻĒā§‡ āĻ¯ā§‡ āĻĒāĻĻā§āĻ§āĻ¤āĻŋāĻŸāĻŋ āĻĻā§‡āĻ–ā§‡āĻ›āĻŋ āĻ¤āĻž āĻĒāĻ›āĻ¨ā§āĻĻ āĻ•āĻ°āĻŋāĨ¤

āĻāĻŸāĻŋ Ethereum āĻ¨ā§‡āĻŸāĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻ•ā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻ•āĻžāĻœ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻāĻ•āĻŸāĻŋ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨āĨ¤ āĻāĻ¤ā§‡, āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ā§‡āĻ° āĻŦāĻŋāĻ­āĻŋāĻ¨ā§āĻ¨ āĻ…āĻ‚āĻļ dnode āĻ˛āĻžāĻ‡āĻŦā§āĻ°ā§‡āĻ°āĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡ RPC āĻāĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ āĻ¯ā§‹āĻ—āĻžāĻ¯ā§‹āĻ— āĻ•āĻ°ā§‡āĨ¤ āĻāĻŸāĻŋ āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻ–ā§āĻŦ āĻĻā§āĻ°ā§āĻ¤ āĻāĻŦāĻ‚ āĻ¸ā§āĻŦāĻŋāĻ§āĻžāĻœāĻ¨āĻ•āĻ­āĻžāĻŦā§‡ āĻāĻ•āĻŸāĻŋ āĻŦāĻŋāĻ¨āĻŋāĻŽāĻ¯āĻŧ āĻ¸āĻ‚āĻ—āĻ āĻŋāĻ¤ āĻ•āĻ°āĻžāĻ° āĻ…āĻ¨ā§āĻŽāĻ¤āĻŋ āĻĻā§‡āĻ¯āĻŧ āĻ¯āĻĻāĻŋ āĻ†āĻĒāĻ¨āĻŋ āĻāĻŸāĻŋāĻ•ā§‡ āĻāĻ•āĻŸāĻŋ āĻĒāĻ°āĻŋāĻŦāĻšāĻ¨ āĻšāĻŋāĻ¸āĻžāĻŦā§‡ āĻāĻ•āĻŸāĻŋ āĻ¨ā§‹āĻĄā§‡āĻœ āĻ¸ā§āĻŸā§āĻ°āĻŋāĻŽ āĻĒā§āĻ°āĻĻāĻžāĻ¨ āĻ•āĻ°ā§‡āĻ¨ (āĻ…āĻ°ā§āĻĨāĻžā§Ž āĻāĻ•āĻŸāĻŋ āĻŦāĻ¸ā§āĻ¤ā§ āĻ¯āĻž āĻāĻ•āĻ‡ āĻ‡āĻ¨ā§āĻŸāĻžāĻ°āĻĢā§‡āĻ¸ āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻ— āĻ•āĻ°ā§‡):

import Dnode from "dnode/browser";

// В ŅŅ‚ĐžĐŧ ĐŋŅ€Đ¸ĐŧĐĩŅ€Đĩ ŅƒŅĐģОвиĐŧŅŅ Ņ‡Ņ‚Đž ĐēĐģиĐĩĐŊŅ‚ ŅƒĐ´Đ°ĐģĐĩĐŊĐŊĐž вŅ‹ĐˇŅ‹Đ˛Đ°ĐĩŅ‚ Ņ„ŅƒĐŊĐēŅ†Đ¸Đ¸ ĐŊĐ° ŅĐĩŅ€Đ˛ĐĩŅ€Đĩ, Ņ…ĐžŅ‚Ņ ĐŊиŅ‡ĐĩĐŗĐž ĐŊĐ°Đŧ ĐŊĐĩ ĐŧĐĩŅˆĐ°ĐĩŅ‚ ŅĐ´ĐĩĐģĐ°Ņ‚ŅŒ ŅŅ‚Đž двŅƒĐŊĐ°ĐŋŅ€Đ°Đ˛ĐģĐĩĐŊĐŊŅ‹Đŧ

// CĐĩŅ€Đ˛ĐĩŅ€
// API, ĐēĐžŅ‚ĐžŅ€ĐžĐĩ ĐŧŅ‹ Ņ…ĐžŅ‚иĐŧ ĐŋŅ€ĐĩĐ´ĐžŅŅ‚авиŅ‚ŅŒ
const dnode = Dnode({
    hello: (cb) => cb(null, "world")
})
// ĐĸŅ€Đ°ĐŊŅĐŋĐžŅ€Ņ‚, ĐŋОвĐĩŅ€Ņ… ĐēĐžŅ‚ĐžŅ€ĐžĐŗĐž ĐąŅƒĐ´ĐĩŅ‚ Ņ€Đ°ĐąĐžŅ‚Đ°Ņ‚ŅŒ dnode. ЛŅŽĐąĐžĐš nodejs ŅŅ‚Ņ€Đ¸Đŧ. В ĐąŅ€Đ°ŅƒĐˇĐĩŅ€Đĩ ĐĩŅŅ‚ŅŒ йийиĐģиОŅ‚ĐĩĐēĐ° 'readable-stream'
connectionStream.pipe(dnode).pipe(connectionStream)

// КĐģиĐĩĐŊŅ‚
const dnodeClient = Dnode() // ВŅ‹ĐˇĐžĐ˛ ĐąĐĩС Đ°ĐŗŅ€ŅƒĐŧĐĩĐŊŅ‚Đ° СĐŊĐ°Ņ‡Đ¸Ņ‚ Ņ‡Ņ‚Đž ĐŧŅ‹ ĐŊĐĩ ĐŋŅ€ĐĩĐ´ĐžŅŅ‚авĐģŅĐĩĐŧ API ĐŊĐ° Đ´Ņ€ŅƒĐŗОК ŅŅ‚ĐžŅ€ĐžĐŊĐĩ

// ВŅ‹Đ˛ĐĩĐ´ĐĩŅ‚ в ĐēĐžĐŊŅĐžĐģŅŒ world
dnodeClient.once('remote', remote => {
    remote.hello(((err, value) => console.log(value)))
})

āĻāĻ–āĻ¨ āĻ†āĻŽāĻ°āĻž āĻāĻ•āĻŸāĻŋ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ āĻ•ā§āĻ˛āĻžāĻ¸ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻŦāĨ¤ āĻāĻŸāĻŋ āĻĒāĻĒāĻ†āĻĒ āĻāĻŦāĻ‚ āĻ“āĻ¯āĻŧā§‡āĻŦ āĻĒā§ƒāĻˇā§āĻ āĻžāĻ° āĻœāĻ¨ā§āĻ¯ API āĻ…āĻŦāĻœā§‡āĻ•ā§āĻŸ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻŦā§‡ āĻāĻŦāĻ‚ āĻ¤āĻžāĻĻā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻāĻ•āĻŸāĻŋ dnode āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻŦā§‡:

import Dnode from 'dnode/browser';

export class SignerApp {

    // ВозвŅ€Đ°Ņ‰Đ°ĐĩŅ‚ ОйŅŠĐĩĐēŅ‚ API Đ´ĐģŅ ui
    popupApi(){
        return {
            hello: cb => cb(null, 'world')
        }
    }

    // ВозвŅ€Đ°Ņ‰Đ°ĐĩŅ‚ ОйŅŠĐĩŅ‚ API Đ´ĐģŅ ŅŅ‚Ņ€Đ°ĐŊиŅ†Ņ‹
    pageApi(){
        return {
            hello: cb => cb(null, 'world')
        }
    }

    // ПодĐēĐģŅŽŅ‡Đ°ĐĩŅ‚ popup ui
    connectPopup(connectionStream){
        const api = this.popupApi();
        const dnode = Dnode(api);

        connectionStream.pipe(dnode).pipe(connectionStream);

        dnode.on('remote', (remote) => {
            console.log(remote)
        })
    }

    // ПодĐēĐģŅŽŅ‡Đ°ĐĩŅ‚ ŅŅ‚Ņ€Đ°ĐŊиŅ†Ņƒ
    connectPage(connectionStream, origin){
        const api = this.popupApi();
        const dnode = Dnode(api);

        connectionStream.pipe(dnode).pipe(connectionStream);

        dnode.on('remote', (remote) => {
            console.log(origin);
            console.log(remote)
        })
    }
}

āĻāĻ–āĻžāĻ¨ā§‡ āĻāĻŦāĻ‚ āĻ¨ā§€āĻšā§‡, āĻ—ā§āĻ˛ā§‹āĻŦāĻžāĻ˛ āĻ•ā§āĻ°ā§‹āĻŽ āĻ…āĻŦāĻœā§‡āĻ•ā§āĻŸā§‡āĻ° āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤ā§‡, āĻ†āĻŽāĻ°āĻž āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨āĻāĻĒāĻŋāĻ†āĻ‡ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻŋ, āĻ¯āĻž Google āĻāĻ° āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ°ā§‡ āĻāĻŦāĻ‚ āĻ…āĻ¨ā§āĻ¯āĻĻā§‡āĻ° āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ°ā§‡ Chrome āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻ•āĻ°ā§‡āĨ¤ āĻāĻŸāĻŋ āĻ•ā§āĻ°āĻ¸-āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻ¸āĻžāĻŽāĻžā§āĻœāĻ¸ā§āĻ¯ā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧā§‡āĻ›ā§‡, āĻ¤āĻŦā§‡ āĻāĻ‡ āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§āĻŸāĻŋāĻ° āĻ‰āĻĻā§āĻĻā§‡āĻļā§āĻ¯ā§‡ āĻ•ā§‡āĻ‰ āĻ•ā§‡āĻŦāĻ˛ 'chrome.runtime.connect' āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĨ¤

āĻŦā§āĻ¯āĻžāĻ•āĻ—ā§āĻ°āĻžāĻ‰āĻ¨ā§āĻĄ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸā§‡ āĻāĻ•āĻŸāĻŋ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ āĻ‡āĻ¨ā§āĻ¸āĻŸā§āĻ¯āĻžāĻ¨ā§āĻ¸ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻž āĻ¯āĻžāĻ•:

import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import {SignerApp} from "./SignerApp";

const app = new SignerApp();

// onConnect ŅŅ€Đ°ĐąĐ°Ņ‚Ņ‹Đ˛Đ°ĐĩŅ‚ ĐŋŅ€Đ¸ ĐŋОдĐēĐģŅŽŅ‡ĐĩĐŊии 'ĐŋŅ€ĐžŅ†ĐĩŅŅĐžĐ˛' (contentscript, popup, иĐģи ŅŅ‚Ņ€Đ°ĐŊиŅ†Đ° Ņ€Đ°ŅŅˆĐ¸Ņ€ĐĩĐŊиŅ)
extensionApi.runtime.onConnect.addListener(connectRemote);

function connectRemote(remotePort) {
    const processName = remotePort.name;
    const portStream = new PortStream(remotePort);
    // ПŅ€Đ¸ ŅƒŅŅ‚Đ°ĐŊОвĐēĐĩ ŅĐžĐĩдиĐŊĐĩĐŊиŅ ĐŧĐžĐļĐŊĐž ŅƒĐēаСŅ‹Đ˛Đ°Ņ‚ŅŒ иĐŧŅ, ĐŋĐž ŅŅ‚ĐžĐŧŅƒ иĐŧĐĩĐŊи ĐŧŅ‹ и ĐžĐŋĐŋŅ€ĐĩĐ´ĐĩĐģŅĐĩĐŧ ĐēŅ‚Đž Đē ĐŊĐ°Đŧ ĐŋОдĐģŅŽŅ‡Đ¸ĐģŅŅ, ĐēĐžĐŊŅ‚ĐĩĐŊŅ‚ŅĐēŅ€Đ¸ĐŋŅ‚ иĐģи ui
    if (processName === 'contentscript'){
        const origin = remotePort.sender.url
        app.connectPage(portStream, origin)
    }else{
        app.connectPopup(portStream)
    }
}

āĻ¯ā§‡āĻšā§‡āĻ¤ā§ dnode āĻ¸ā§āĻŸā§āĻ°āĻŋāĻŽāĻ—ā§āĻ˛āĻŋāĻ° āĻ¸āĻžāĻĨā§‡ āĻ•āĻžāĻœ āĻ•āĻ°ā§‡, āĻāĻŦāĻ‚ āĻ†āĻŽāĻ°āĻž āĻāĻ•āĻŸāĻŋ āĻĒā§‹āĻ°ā§āĻŸ āĻĒāĻžāĻ‡, āĻāĻ•āĻŸāĻŋ āĻ…ā§āĻ¯āĻžāĻĄāĻžāĻĒā§āĻŸāĻžāĻ° āĻ•ā§āĻ˛āĻžāĻ¸ āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨āĨ¤ āĻāĻŸāĻŋ āĻĒāĻ āĻ¨āĻ¯ā§‹āĻ—ā§āĻ¯-āĻ¸ā§āĻŸā§āĻ°āĻŋāĻŽ āĻ˛āĻžāĻ‡āĻŦā§āĻ°ā§‡āĻ°āĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧā§‡āĻ›ā§‡, āĻ¯āĻž āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ°ā§‡ āĻ¨ā§‹āĻĄāĻœ āĻ¸ā§āĻŸā§āĻ°ā§€āĻŽ āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻ— āĻ•āĻ°ā§‡:

import {Duplex} from 'readable-stream';

export class PortStream extends Duplex{
    constructor(port){
        super({objectMode: true});
        this._port = port;
        port.onMessage.addListener(this._onMessage.bind(this));
        port.onDisconnect.addListener(this._onDisconnect.bind(this))
    }

    _onMessage(msg) {
        if (Buffer.isBuffer(msg)) {
            delete msg._isBuffer;
            const data = new Buffer(msg);
            this.push(data)
        } else {
            this.push(msg)
        }
    }

    _onDisconnect() {
        this.destroy()
    }

    _read(){}

    _write(msg, encoding, cb) {
        try {
            if (Buffer.isBuffer(msg)) {
                const data = msg.toJSON();
                data._isBuffer = true;
                this._port.postMessage(data)
            } else {
                this._port.postMessage(msg)
            }
        } catch (err) {
            return cb(new Error('PortStream - disconnected'))
        }
        cb()
    }
}

āĻāĻ–āĻ¨ UI āĻ āĻāĻ•āĻŸāĻŋ āĻ¸āĻ‚āĻ¯ā§‹āĻ— āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻž āĻ¯āĻžāĻ•:

import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import Dnode from 'dnode/browser';

const DEV_MODE = process.env.NODE_ENV !== 'production';

setupUi().catch(console.error);

async function setupUi(){
    // ĐĸĐ°ĐēĐļĐĩ, ĐēĐ°Đē и в ĐēĐģĐ°ŅŅĐĩ ĐŋŅ€Đ¸ĐģĐžĐļĐĩĐŊиŅ ŅĐžĐˇĐ´Đ°ĐĩĐŧ ĐŋĐžŅ€Ņ‚, ОйОŅ€Đ°Ņ‡Đ¸Đ˛Đ°ĐĩĐŧ в stream, Đ´ĐĩĐģĐ°ĐĩĐŧ  dnode
    const backgroundPort = extensionApi.runtime.connect({name: 'popup'});
    const connectionStream = new PortStream(backgroundPort);

    const dnode = Dnode();

    connectionStream.pipe(dnode).pipe(connectionStream);

    const background = await new Promise(resolve => {
        dnode.once('remote', api => {
            resolve(api)
        })
    });

    // ДĐĩĐģĐ°ĐĩĐŧ ОйŅŠĐĩĐēŅ‚ API Đ´ĐžŅŅ‚ŅƒĐŋĐŊŅ‹Đŧ иС ĐēĐžĐŊŅĐžĐģи
    if (DEV_MODE){
        global.background = background;
    }
}

āĻ¤āĻžāĻ°āĻĒāĻ°ā§‡ āĻ†āĻŽāĻ°āĻž āĻ•āĻ¨ā§āĻŸā§‡āĻ¨ā§āĻŸ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸā§‡ āĻ¸āĻ‚āĻ¯ā§‹āĻ— āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻŋ:

import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import PostMessageStream from 'post-message-stream';

setupConnection();
injectScript();

function setupConnection(){
    const backgroundPort = extensionApi.runtime.connect({name: 'contentscript'});
    const backgroundStream = new PortStream(backgroundPort);

    const pageStream = new PostMessageStream({
        name: 'content',
        target: 'page',
    });

    pageStream.pipe(backgroundStream).pipe(pageStream);
}

function injectScript(){
    try {
        // inject in-page script
        let script = document.createElement('script');
        script.src = extensionApi.extension.getURL('inpage.js');
        const container = document.head || document.documentElement;
        container.insertBefore(script, container.children[0]);
        script.onload = () => script.remove();
    } catch (e) {
        console.error('Injection failed.', e);
    }
}

āĻ¯ā§‡āĻšā§‡āĻ¤ā§ āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ•āĻ¨ā§āĻŸā§‡āĻ¨ā§āĻŸ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸā§‡ āĻ¨āĻ¯āĻŧ, āĻ¸āĻ°āĻžāĻ¸āĻ°āĻŋ āĻĒā§ƒāĻˇā§āĻ āĻžāĻ¯āĻŧ API āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨, āĻ†āĻŽāĻ°āĻž āĻĻā§āĻŸāĻŋ āĻœāĻŋāĻ¨āĻŋāĻ¸ āĻ•āĻ°āĻŋ:

  1. āĻ†āĻŽāĻ°āĻž āĻĻā§āĻŸāĻŋ āĻ¸ā§āĻŸā§āĻ°āĻŋāĻŽ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻŋāĨ¤ āĻāĻ•āĻŸāĻŋ - āĻĒā§ƒāĻˇā§āĻ āĻžāĻ° āĻĻāĻŋāĻ•ā§‡, āĻĒā§‹āĻ¸ā§āĻŸāĻŽā§‡āĻ¸ā§‡āĻœā§‡āĻ° āĻ‰āĻĒāĻ°ā§‡āĨ¤ āĻāĻ‡ āĻœāĻ¨ā§āĻ¯ āĻ†āĻŽāĻ°āĻž āĻāĻ‡ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻāĻ‡ āĻĒā§āĻ¯āĻžāĻ•ā§‡āĻœ āĻŽā§‡āĻŸāĻžāĻŽāĻžāĻ¸ā§āĻ•ā§‡āĻ° āĻ¨āĻŋāĻ°ā§āĻŽāĻžāĻ¤āĻžāĻĻā§‡āĻ° āĻ•āĻžāĻ› āĻĨā§‡āĻ•ā§‡āĨ¤ āĻĻā§āĻŦāĻŋāĻ¤ā§€āĻ¯āĻŧ āĻ¸ā§āĻŸā§āĻ°ā§€āĻŽ āĻĒā§‹āĻ°ā§āĻŸ āĻĨā§‡āĻ•ā§‡ āĻĒā§āĻ°āĻžāĻĒā§āĻ¤ āĻ‰āĻĒāĻ° āĻŦā§āĻ¯āĻžāĻ•āĻ—ā§āĻ°āĻžāĻ‰āĻ¨ā§āĻĄ āĻšāĻ¯āĻŧ runtime.connect. āĻšāĻ˛ā§āĻ¨ āĻ¤āĻžāĻĻā§‡āĻ° āĻ•āĻŋāĻ¨ā§āĻ¨. āĻāĻ–āĻ¨ āĻĒā§ƒāĻˇā§āĻ āĻžāĻŸāĻŋāĻ° āĻĒāĻŸāĻ­ā§‚āĻŽāĻŋāĻ¤ā§‡ āĻāĻ•āĻŸāĻŋ āĻ¸ā§āĻŸā§āĻ°āĻŋāĻŽ āĻĨāĻžāĻ•āĻŦā§‡āĨ¤
  2. DOM-āĻ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸāĻŸāĻŋ āĻ‡āĻ¨āĻœā§‡āĻ•ā§āĻŸ āĻ•āĻ°ā§āĻ¨āĨ¤ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸāĻŸāĻŋ āĻĄāĻžāĻ‰āĻ¨āĻ˛ā§‹āĻĄ āĻ•āĻ°ā§āĻ¨ (āĻāĻŸāĻŋ āĻŽā§āĻ¯āĻžāĻ¨āĻŋāĻĢā§‡āĻ¸ā§āĻŸā§‡ āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ā§‡āĻ° āĻ…āĻ¨ā§āĻŽāĻ¤āĻŋ āĻĻā§‡āĻ“āĻ¯āĻŧāĻž āĻšāĻ¯āĻŧā§‡āĻ›āĻŋāĻ˛) āĻāĻŦāĻ‚ āĻāĻ•āĻŸāĻŋ āĻŸā§āĻ¯āĻžāĻ— āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°ā§āĻ¨ā§ˇ script āĻ­āĻŋāĻ¤āĻ°ā§‡ āĻāĻ° āĻŦāĻŋāĻˇāĻ¯āĻŧāĻŦāĻ¸ā§āĻ¤ā§ āĻ¸āĻš:

import PostMessageStream from 'post-message-stream';
import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";

setupConnection();
injectScript();

function setupConnection(){
    // ĐĄŅ‚Ņ€Đ¸Đŧ Đē ĐąĐĩĐēĐŗŅ€Đ°ŅƒĐŊĐ´Ņƒ
    const backgroundPort = extensionApi.runtime.connect({name: 'contentscript'});
    const backgroundStream = new PortStream(backgroundPort);

    // ĐĄŅ‚Ņ€Đ¸Đŧ Đē ŅŅ‚Ņ€Đ°ĐŊиŅ†Đĩ
    const pageStream = new PostMessageStream({
        name: 'content',
        target: 'page',
    });

    pageStream.pipe(backgroundStream).pipe(pageStream);
}

function injectScript(){
    try {
        // inject in-page script
        let script = document.createElement('script');
        script.src = extensionApi.extension.getURL('inpage.js');
        const container = document.head || document.documentElement;
        container.insertBefore(script, container.children[0]);
        script.onload = () => script.remove();
    } catch (e) {
        console.error('Injection failed.', e);
    }
}

āĻāĻ–āĻ¨ āĻ†āĻŽāĻ°āĻž āĻ‡āĻ¨āĻĒā§‡āĻœā§‡ āĻāĻ•āĻŸāĻŋ āĻāĻĒāĻŋāĻ†āĻ‡ āĻ…āĻŦāĻœā§‡āĻ•ā§āĻŸ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻŋ āĻāĻŦāĻ‚ āĻāĻŸāĻŋāĻ•ā§‡ āĻŦāĻŋāĻļā§āĻŦāĻŦā§āĻ¯āĻžāĻĒā§€ āĻ¸ā§‡āĻŸ āĻ•āĻ°āĻŋ:

import PostMessageStream from 'post-message-stream';
import Dnode from 'dnode/browser';

setupInpageApi().catch(console.error);

async function setupInpageApi() {
    // ĐĄŅ‚Ņ€Đ¸Đŧ Đē ĐēĐžĐŊŅ‚ĐĩĐŊŅ‚ŅĐēŅ€Đ¸ĐŋŅ‚Ņƒ
    const connectionStream = new PostMessageStream({
        name: 'page',
        target: 'content',
    });

    const dnode = Dnode();

    connectionStream.pipe(dnode).pipe(connectionStream);

    // ПоĐģŅƒŅ‡Đ°ĐĩĐŧ ОйŅŠĐĩĐēŅ‚ API
    const pageApi = await new Promise(resolve => {
        dnode.once('remote', api => {
            resolve(api)
        })
    });

    // ДоŅŅ‚ŅƒĐŋ Ņ‡ĐĩŅ€ĐĩС window
    global.SignerApp = pageApi;
}

āĻ†āĻŽāĻ°āĻž āĻĒā§āĻ°āĻ¸ā§āĻ¤ā§āĻ¤ āĻĒā§ƒāĻˇā§āĻ āĻž āĻāĻŦāĻ‚ UI āĻāĻ° āĻœāĻ¨ā§āĻ¯ āĻĒā§ƒāĻĨāĻ• API āĻ¸āĻš āĻĻā§‚āĻ°āĻŦāĻ°ā§āĻ¤ā§€ āĻĒāĻĻā§āĻ§āĻ¤āĻŋ āĻ•āĻ˛ (RPC). āĻĒāĻŸāĻ­ā§‚āĻŽāĻŋāĻ¤ā§‡ āĻāĻ•āĻŸāĻŋ āĻ¨āĻ¤ā§āĻ¨ āĻĒā§ƒāĻˇā§āĻ āĻž āĻ¸āĻ‚āĻ¯ā§‹āĻ— āĻ•āĻ°āĻžāĻ° āĻ¸āĻŽāĻ¯āĻŧ āĻ†āĻŽāĻ°āĻž āĻāĻŸāĻŋ āĻĻā§‡āĻ–āĻ¤ā§‡ āĻĒāĻžāĻ°āĻŋ:

āĻāĻ•āĻŸāĻŋ āĻ¨āĻŋāĻ°āĻžāĻĒāĻĻ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ˛ā§‡āĻ–āĻž

āĻ–āĻžāĻ˛āĻŋ API āĻāĻŦāĻ‚ āĻŽā§‚āĻ˛āĨ¤ āĻĒā§ƒāĻˇā§āĻ āĻžāĻ° āĻĒāĻžāĻļā§‡, āĻ†āĻŽāĻ°āĻž āĻšā§āĻ¯āĻžāĻ˛ā§‹ āĻĢāĻžāĻ‚āĻļāĻ¨āĻŸāĻŋāĻ•ā§‡ āĻāĻ­āĻžāĻŦā§‡ āĻ•āĻ˛ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°āĻŋ:

āĻāĻ•āĻŸāĻŋ āĻ¨āĻŋāĻ°āĻžāĻĒāĻĻ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ˛ā§‡āĻ–āĻž

āĻ†āĻ§ā§āĻ¨āĻŋāĻ• JS-āĻ āĻ•āĻ˛āĻŦā§āĻ¯āĻžāĻ• āĻĢāĻžāĻ‚āĻļāĻ¨āĻ—ā§āĻ˛āĻŋāĻ° āĻ¸āĻžāĻĨā§‡ āĻ•āĻžāĻœ āĻ•āĻ°āĻž āĻ–āĻžāĻ°āĻžāĻĒ āĻ†āĻšāĻ°āĻŖ, āĻ¤āĻžāĻ‡ āĻ†āĻ¸ā§āĻ¨ āĻāĻ•āĻŸāĻŋ dnode āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻ¤ā§‡ āĻāĻ•āĻŸāĻŋ āĻ›ā§‹āĻŸ āĻ¸āĻžāĻšāĻžāĻ¯ā§āĻ¯āĻ•āĻžāĻ°ā§€ āĻ˛āĻŋāĻ–āĻŋ āĻ¯āĻž āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻāĻ•āĻŸāĻŋ API āĻ…āĻŦāĻœā§‡āĻ•ā§āĻŸāĻ•ā§‡ āĻ‡āĻ‰āĻŸāĻŋāĻ˛ā§‡ āĻĒāĻžāĻ¸ āĻ•āĻ°āĻ¤ā§‡ āĻĻā§‡āĻ¯āĻŧāĨ¤

API āĻ…āĻŦāĻœā§‡āĻ•ā§āĻŸāĻ—ā§āĻ˛āĻŋ āĻāĻ–āĻ¨ āĻāĻ‡āĻ°āĻ•āĻŽ āĻĻā§‡āĻ–āĻžāĻŦā§‡:

export class SignerApp {

    popupApi() {
        return {
            hello: async () => "world"
        }
    }

...

}

āĻāĻ‡ āĻŽāĻ¤ āĻĻā§‚āĻ°āĻŦāĻ°ā§āĻ¤ā§€ āĻĨā§‡āĻ•ā§‡ āĻāĻ•āĻŸāĻŋ āĻŦāĻ¸ā§āĻ¤ā§ āĻĒāĻžāĻ“āĻ¯āĻŧāĻž:

import {cbToPromise, transformMethods} from "../../src/utils/setupDnode";

const pageApi = await new Promise(resolve => {
    dnode.once('remote', remoteApi => {
        // ĐĄ ĐŋĐžĐŧĐžŅ‰ŅŒŅŽ ŅƒŅ‚иĐģиŅ‚ ĐŧĐĩĐŊŅĐĩĐŧ вŅĐĩ callback ĐŊĐ° promise
        resolve(transformMethods(cbToPromise, remoteApi))
    })
});

āĻāĻŦāĻ‚ āĻ•āĻ˛āĻŋāĻ‚ āĻĢāĻžāĻ‚āĻļāĻ¨ āĻāĻ•āĻŸāĻŋ āĻĒā§āĻ°āĻ¤āĻŋāĻļā§āĻ°ā§āĻ¤āĻŋ āĻĒā§āĻ°āĻĻāĻžāĻ¨ āĻ•āĻ°ā§‡:

āĻāĻ•āĻŸāĻŋ āĻ¨āĻŋāĻ°āĻžāĻĒāĻĻ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ˛ā§‡āĻ–āĻž

āĻ…ā§āĻ¯āĻžāĻ¸āĻŋāĻ™ā§āĻ•ā§āĻ°ā§‹āĻ¨āĻžāĻ¸ āĻĢāĻžāĻ‚āĻļāĻ¨ āĻ¸āĻš āĻ¸āĻ‚āĻ¸ā§āĻ•āĻ°āĻŖ āĻ‰āĻĒāĻ˛āĻŦā§āĻ§ āĻāĻ–āĻžāĻ¨ā§‡.

āĻ¸āĻžāĻŽāĻ—ā§āĻ°āĻŋāĻ•āĻ­āĻžāĻŦā§‡, RPC āĻāĻŦāĻ‚ āĻ¸ā§āĻŸā§āĻ°āĻŋāĻŽ āĻĒāĻĻā§āĻ§āĻ¤āĻŋāĻŸāĻŋ āĻŦā§‡āĻļ āĻ¨āĻŽāĻ¨ā§€āĻ¯āĻŧ āĻŦāĻ˛ā§‡ āĻŽāĻ¨ā§‡ āĻšāĻšā§āĻ›ā§‡: āĻ†āĻŽāĻ°āĻž āĻ¸ā§āĻŸāĻŋāĻŽ āĻŽāĻžāĻ˛ā§āĻŸāĻŋāĻĒā§āĻ˛ā§‡āĻ•ā§āĻ¸āĻŋāĻ‚ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°āĻŋ āĻāĻŦāĻ‚ āĻŦāĻŋāĻ­āĻŋāĻ¨ā§āĻ¨ āĻ•āĻžāĻœā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻŦāĻŋāĻ­āĻŋāĻ¨ā§āĻ¨ āĻ­āĻŋāĻ¨ā§āĻ¨ API āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°āĻŋāĨ¤ āĻ¨ā§€āĻ¤āĻŋāĻ—āĻ¤āĻ­āĻžāĻŦā§‡, dnode āĻ¯ā§‡ āĻ•ā§‹āĻ¨ āĻœāĻžāĻ¯āĻŧāĻ—āĻžāĻ¯āĻŧ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻž āĻ¯ā§‡āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡, āĻĒā§āĻ°āĻ§āĻžāĻ¨ āĻœāĻŋāĻ¨āĻŋāĻ¸ āĻāĻ•āĻŸāĻŋ nodejs āĻ¸ā§āĻŸā§āĻ°āĻŋāĻŽ āĻ†āĻ•āĻžāĻ°ā§‡ āĻĒāĻ°āĻŋāĻŦāĻšāĻ¨ āĻŽā§‹āĻĄāĻŧāĻžāĻ¨ā§‹ āĻšāĻ¯āĻŧāĨ¤

āĻāĻ•āĻŸāĻŋ āĻŦāĻŋāĻ•āĻ˛ā§āĻĒ āĻšāĻ˛ JSON āĻĢāĻ°āĻŽā§āĻ¯āĻžāĻŸ, āĻ¯āĻž JSON RPC 2 āĻĒā§āĻ°ā§‹āĻŸā§‹āĻ•āĻ˛ āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻ— āĻ•āĻ°ā§‡āĨ¤ āĻ¯āĻžāĻ‡āĻšā§‹āĻ•, āĻāĻŸāĻŋ āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻĒāĻ°āĻŋāĻŦāĻšāĻ¨ā§‡āĻ° (TCP āĻāĻŦāĻ‚ HTTP(S)) āĻ¸āĻžāĻĨā§‡ āĻ•āĻžāĻœ āĻ•āĻ°ā§‡, āĻ¯āĻž āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°ā§‡ āĻĒā§āĻ°āĻ¯ā§‹āĻœā§āĻ¯ āĻ¨āĻ¯āĻŧāĨ¤

āĻ…āĻ­ā§āĻ¯āĻ¨ā§āĻ¤āĻ°ā§€āĻŖ āĻ°āĻžāĻˇā§āĻŸā§āĻ° āĻāĻŦāĻ‚ āĻ¸ā§āĻĨāĻžāĻ¨ā§€āĻ¯āĻŧ āĻ¸ā§āĻŸā§‹āĻ°ā§‡āĻœ

āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ā§‡āĻ° āĻ…āĻ­ā§āĻ¯āĻ¨ā§āĻ¤āĻ°ā§€āĻŖ āĻ…āĻŦāĻ¸ā§āĻĨāĻž āĻ¸āĻžā§āĻšāĻ¯āĻŧ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡ - āĻ…āĻ¨ā§āĻ¤āĻ¤ āĻ¸āĻžāĻ‡āĻ¨āĻŋāĻ‚ āĻ•ā§€āĻ—ā§āĻ˛āĻŋāĨ¤ āĻ†āĻŽāĻ°āĻž āĻĒāĻĒāĻ†āĻĒ API āĻ āĻāĻŸāĻŋ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ āĻāĻŦāĻ‚ āĻĒāĻĻā§āĻ§āĻ¤āĻŋāĻ¤ā§‡ āĻ–ā§āĻŦ āĻ¸āĻšāĻœā§‡āĻ‡ āĻāĻ•āĻŸāĻŋ āĻ°āĻžāĻœā§āĻ¯ āĻ¯ā§‹āĻ— āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°āĻŋ:

import {setupDnode} from "./utils/setupDnode";

export class SignerApp {

    constructor(){
        this.store = {
            keys: [],
        };
    }

    addKey(key){
        this.store.keys.push(key)
    }

    removeKey(index){
        this.store.keys.splice(index,1)
    }

    popupApi(){
        return {
            addKey: async (key) => this.addKey(key),
            removeKey: async (index) => this.removeKey(index)
        }
    }

    ...

} 

āĻĒāĻŸāĻ­ā§‚āĻŽāĻŋāĻ¤ā§‡, āĻ†āĻŽāĻ°āĻž āĻāĻ•āĻŸāĻŋ āĻĢāĻžāĻ‚āĻļāĻ¨ā§‡ āĻ¸āĻŦāĻ•āĻŋāĻ›ā§ āĻŽā§āĻĄāĻŧā§‡ āĻĻā§‡āĻŦ āĻāĻŦāĻ‚ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ āĻ…āĻŦāĻœā§‡āĻ•ā§āĻŸāĻŸāĻŋāĻ•ā§‡ āĻ‰āĻ‡āĻ¨ā§āĻĄā§‹āĻ¤ā§‡ āĻ˛āĻŋāĻ–āĻŦ āĻ¯āĻžāĻ¤ā§‡ āĻ†āĻŽāĻ°āĻž āĻ•āĻ¨āĻ¸ā§‹āĻ˛ āĻĨā§‡āĻ•ā§‡ āĻāĻŸāĻŋāĻ° āĻ¸āĻžāĻĨā§‡ āĻ•āĻžāĻœ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°āĻŋ:

import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import {SignerApp} from "./SignerApp";

const DEV_MODE = process.env.NODE_ENV !== 'production';

setupApp();

function setupApp() {
    const app = new SignerApp();

    if (DEV_MODE) {
        global.app = app;
    }

    extensionApi.runtime.onConnect.addListener(connectRemote);

    function connectRemote(remotePort) {
        const processName = remotePort.name;
        const portStream = new PortStream(remotePort);
        if (processName === 'contentscript') {
            const origin = remotePort.sender.url;
            app.connectPage(portStream, origin)
        } else {
            app.connectPopup(portStream)
        }
    }
}

āĻ†āĻ¸ā§āĻ¨ UI āĻ•āĻ¨āĻ¸ā§‹āĻ˛ āĻĨā§‡āĻ•ā§‡ āĻ•āĻ¯āĻŧā§‡āĻ•āĻŸāĻŋ āĻ•ā§€ āĻ¯ā§‹āĻ— āĻ•āĻ°āĻŋ āĻāĻŦāĻ‚ āĻ°āĻžāĻœā§āĻ¯ā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻ•ā§€ āĻ˜āĻŸā§‡ āĻ¤āĻž āĻĻā§‡āĻ–ā§āĻ¨:

āĻāĻ•āĻŸāĻŋ āĻ¨āĻŋāĻ°āĻžāĻĒāĻĻ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ˛ā§‡āĻ–āĻž

āĻ°āĻžāĻˇā§āĻŸā§āĻ°āĻ•ā§‡ āĻ•ā§āĻ°āĻŽāĻžāĻ—āĻ¤ āĻ•āĻ°āĻž āĻĻāĻ°āĻ•āĻžāĻ° āĻ¯āĻžāĻ¤ā§‡ āĻĒā§āĻ¨āĻ°āĻžāĻ¯āĻŧ āĻšāĻžāĻ˛ā§ āĻ•āĻ°āĻžāĻ° āĻ¸āĻŽāĻ¯āĻŧ āĻ•ā§€āĻ—ā§āĻ˛āĻŋ āĻšāĻžāĻ°āĻŋāĻ¯āĻŧā§‡ āĻ¨āĻž āĻ¯āĻžāĻ¯āĻŧāĨ¤

āĻ†āĻŽāĻ°āĻž āĻĒā§āĻ°āĻ¤āĻŋāĻŸāĻŋ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻāĻŸāĻŋāĻ•ā§‡ āĻ“āĻ­āĻžāĻ°āĻ°āĻžāĻ‡āĻŸ āĻ•āĻ°ā§‡ āĻ¸ā§āĻĨāĻžāĻ¨ā§€āĻ¯āĻŧ āĻ¸ā§āĻŸā§‹āĻ°ā§‡āĻœ āĻ āĻ¸āĻ‚āĻ°āĻ•ā§āĻˇāĻŖ āĻ•āĻ°āĻŦāĨ¤ āĻĒāĻ°āĻŦāĻ°ā§āĻ¤ā§€āĻ•āĻžāĻ˛ā§‡, āĻāĻŸāĻŋāĻ¤ā§‡ āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ UI āĻāĻ° āĻœāĻ¨ā§āĻ¯āĻ“ āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ā§€āĻ¯āĻŧ āĻšāĻŦā§‡ āĻāĻŦāĻ‚ āĻ†āĻŽāĻŋ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨āĻ—ā§āĻ˛āĻŋāĻ¤ā§‡ āĻ¸āĻĻāĻ¸ā§āĻ¯āĻ¤āĻž āĻ¨āĻŋāĻ¤ā§‡ āĻšāĻžāĻ‡āĨ¤ āĻāĻ° āĻ‰āĻĒāĻ° āĻ­āĻŋāĻ¤ā§āĻ¤āĻŋ āĻ•āĻ°ā§‡, āĻāĻ•āĻŸāĻŋ āĻĒāĻ°ā§āĻ¯āĻŦā§‡āĻ•ā§āĻˇāĻŖāĻ¯ā§‹āĻ—ā§āĻ¯ āĻ¸ā§āĻŸā§‹āĻ°ā§‡āĻœ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻž āĻāĻŦāĻ‚ āĻāĻ° āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨āĻ—ā§āĻ˛āĻŋāĻ¤ā§‡ āĻ¸āĻžāĻŦāĻ¸ā§āĻ•ā§āĻ°āĻžāĻ‡āĻŦ āĻ•āĻ°āĻž āĻ¸ā§āĻŦāĻŋāĻ§āĻžāĻœāĻ¨āĻ• āĻšāĻŦā§‡āĨ¤

āĻ†āĻŽāĻ°āĻž mobx āĻ˛āĻžāĻ‡āĻŦā§āĻ°ā§‡āĻ°āĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻŦ (https://github.com/mobxjs/mobx) āĻĒāĻ›āĻ¨ā§āĻĻāĻŸāĻŋ āĻāĻŸāĻŋāĻ° āĻ‰āĻĒāĻ° āĻĒāĻĄāĻŧā§‡āĻ›āĻŋāĻ˛ āĻ•āĻžāĻ°āĻŖ āĻ†āĻŽāĻžāĻ•ā§‡ āĻāĻŸāĻŋāĻ° āĻ¸āĻžāĻĨā§‡ āĻ•āĻžāĻœ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻ¯āĻŧāĻ¨āĻŋ, āĻ¤āĻŦā§‡ āĻ†āĻŽāĻŋ āĻ¸āĻ¤ā§āĻ¯āĻŋāĻ‡ āĻāĻŸāĻŋ āĻ…āĻ§ā§āĻ¯āĻ¯āĻŧāĻ¨ āĻ•āĻ°āĻ¤ā§‡ āĻšā§‡āĻ¯āĻŧā§‡āĻ›āĻŋāĻ˛āĻžāĻŽāĨ¤

āĻ†āĻ¸ā§āĻ¨ āĻĒā§āĻ°āĻžāĻĨāĻŽāĻŋāĻ• āĻ…āĻŦāĻ¸ā§āĻĨāĻžāĻ° āĻ¸ā§‚āĻšāĻ¨āĻž āĻ¯ā§‹āĻ— āĻ•āĻ°āĻŋ āĻāĻŦāĻ‚ āĻ¸ā§āĻŸā§‹āĻ°āĻŸāĻŋāĻ•ā§‡ āĻĒāĻ°ā§āĻ¯āĻŦā§‡āĻ•ā§āĻˇāĻŖāĻ¯ā§‹āĻ—ā§āĻ¯ āĻ•āĻ°ā§‡ āĻ¤ā§āĻ˛ā§āĻ¨:

import {observable, action} from 'mobx';
import {setupDnode} from "./utils/setupDnode";

export class SignerApp {

    constructor(initState = {}) {
        // ВĐŊĐĩŅˆĐŊĐĩ store Ņ‚Đ°Đē и ĐžŅŅ‚Đ°ĐŊĐĩŅ‚ŅŅ Ņ‚ĐĩĐŧ ĐļĐĩ ОйŅŠĐĩĐēŅ‚ĐžĐŧ, Ņ‚ĐžĐģŅŒĐēĐž Ņ‚ĐĩĐŋĐĩŅ€ŅŒ вŅĐĩ ĐĩĐŗĐž ĐŋĐžĐģŅ ŅŅ‚Đ°Đģи proxy, ĐēĐžŅ‚ĐžŅ€Ņ‹Đĩ ĐžŅ‚ŅĐģĐĩĐļиваŅŽŅ‚ Đ´ĐžŅŅ‚ŅƒĐŋ Đē ĐŊиĐŧ
        this.store =  observable.object({
            keys: initState.keys || [],
        });
    }

    // МĐĩŅ‚ОдŅ‹, ĐēĐžŅ‚ĐžŅ€Ņ‹Đĩ ĐŧĐĩĐŊŅŅŽŅ‚ observable ĐŋŅ€Đ¸ĐŊŅŅ‚Đž ОйОŅ€Đ°Ņ‡Đ¸Đ˛Đ°Ņ‚ŅŒ Đ´ĐĩĐēĐžŅ€Đ°Ņ‚ĐžŅ€ĐžĐŧ
    @action
    addKey(key) {
        this.store.keys.push(key)
    }

    @action
    removeKey(index) {
        this.store.keys.splice(index, 1)
    }

    ...

}

"āĻšā§āĻĄā§‡āĻ° āĻ¨ā§€āĻšā§‡," mobx āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻ¸ā§āĻŸā§‹āĻ° āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°āĻ—ā§āĻ˛āĻŋāĻ•ā§‡ āĻĒā§āĻ°āĻ•ā§āĻ¸āĻŋ āĻĻāĻŋāĻ¯āĻŧā§‡ āĻĒā§āĻ°āĻ¤āĻŋāĻ¸ā§āĻĨāĻžāĻĒāĻ¨ āĻ•āĻ°ā§‡āĻ›ā§‡ āĻāĻŦāĻ‚ āĻ¤āĻžāĻĻā§‡āĻ° āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻ•āĻ˛āĻ•ā§‡ āĻŦāĻžāĻ§āĻž āĻĻā§‡āĻ¯āĻŧā§ˇ āĻāĻ‡ āĻŦāĻžāĻ°ā§āĻ¤āĻžāĻ—ā§āĻ˛āĻŋāĻ¤ā§‡ āĻ¸āĻĻāĻ¸ā§āĻ¯āĻ¤āĻž āĻ¨ā§‡āĻ“āĻ¯āĻŧāĻž āĻ¸āĻŽā§āĻ­āĻŦ āĻšāĻŦā§‡āĨ¤

āĻ¨ā§€āĻšā§‡ āĻ†āĻŽāĻŋ āĻĒā§āĻ°āĻžāĻ¯āĻŧāĻ‡ "āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°āĻžāĻ° āĻ¸āĻŽāĻ¯āĻŧ" āĻļāĻŦā§āĻĻāĻŸāĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻŦ, āĻ¯āĻĻāĻŋāĻ“ āĻāĻŸāĻŋ āĻ¸āĻŽā§āĻĒā§‚āĻ°ā§āĻŖāĻ°ā§‚āĻĒā§‡ āĻ¸āĻ āĻŋāĻ• āĻ¨āĻ¯āĻŧāĨ¤ Mobx āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°ā§‡āĻ° āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻŸā§āĻ°ā§āĻ¯āĻžāĻ• āĻ•āĻ°ā§‡āĨ¤ āĻ˛āĻžāĻ‡āĻŦā§āĻ°ā§‡āĻ°āĻŋ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°ā§‡ āĻāĻŽāĻ¨ āĻĒā§āĻ°āĻ•ā§āĻ¸āĻŋ āĻ…āĻŦāĻœā§‡āĻ•ā§āĻŸā§‡āĻ° āĻ—ā§‡āĻŸāĻžāĻ° āĻāĻŦāĻ‚ āĻ¸ā§‡āĻŸāĻžāĻ° āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻž āĻšāĻ¯āĻŧāĨ¤

āĻ…ā§āĻ¯āĻžāĻ•āĻļāĻ¨ āĻĄā§‡āĻ•ā§‹āĻ°ā§‡āĻŸāĻ° āĻĻā§āĻŸāĻŋ āĻ‰āĻĻā§āĻĻā§‡āĻļā§āĻ¯ āĻĒāĻ°āĻŋāĻŦā§‡āĻļāĻ¨ āĻ•āĻ°ā§‡:

  1. enforceActions āĻĒāĻ¤āĻžāĻ•āĻžāĻ° āĻ¸āĻžāĻĨā§‡ āĻ•āĻ ā§‹āĻ° āĻŽā§‹āĻĄā§‡, mobx āĻ¸āĻ°āĻžāĻ¸āĻ°āĻŋ āĻ°āĻžāĻˇā§āĻŸā§āĻ° āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°āĻž āĻ¨āĻŋāĻˇāĻŋāĻĻā§āĻ§ āĻ•āĻ°ā§‡āĨ¤ āĻ•āĻ ā§‹āĻ° āĻļāĻ°ā§āĻ¤ā§‡ āĻ•āĻžāĻœ āĻ•āĻ°āĻž āĻ­āĻžāĻ˛ āĻ…āĻ­ā§āĻ¯āĻžāĻ¸ āĻŦāĻ˛ā§‡ āĻŽāĻ¨ā§‡ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧāĨ¤
  2. āĻāĻŽāĻ¨āĻ•āĻŋ āĻ¯āĻĻāĻŋ āĻāĻ•āĻŸāĻŋ āĻĢāĻžāĻ‚āĻļāĻ¨ āĻŦā§‡āĻļ āĻ•āĻ¯āĻŧā§‡āĻ•āĻŦāĻžāĻ° āĻ¸ā§āĻĨāĻŋāĻ¤āĻŋ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°ā§‡ - āĻ‰āĻĻāĻžāĻšāĻ°āĻŖāĻ¸ā§āĻŦāĻ°ā§‚āĻĒ, āĻ†āĻŽāĻ°āĻž āĻ•ā§‹āĻĄā§‡āĻ° āĻ•āĻ¯āĻŧā§‡āĻ•āĻŸāĻŋ āĻ˛āĻžāĻ‡āĻ¨ā§‡ āĻŦā§‡āĻļ āĻ•āĻ¯āĻŧā§‡āĻ•āĻŸāĻŋ āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ° āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°āĻŋ - āĻĒāĻ°ā§āĻ¯āĻŦā§‡āĻ•ā§āĻˇāĻ•āĻĻā§‡āĻ° āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻ¯āĻ–āĻ¨ āĻāĻŸāĻŋ āĻ¸āĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āĻšāĻ¯āĻŧ āĻ¤āĻ–āĻ¨āĻ‡ āĻ…āĻŦāĻšāĻŋāĻ¤ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧāĨ¤ āĻāĻŸāĻŋ āĻĢā§āĻ°āĻ¨ā§āĻŸāĻāĻ¨ā§āĻĄā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻŦāĻŋāĻļā§‡āĻˇāĻ­āĻžāĻŦā§‡ āĻ—ā§āĻ°ā§āĻ¤ā§āĻŦāĻĒā§‚āĻ°ā§āĻŖ, āĻ¯ā§‡āĻ–āĻžāĻ¨ā§‡ āĻ…āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ā§€āĻ¯āĻŧ āĻ¸ā§āĻŸā§‡āĻŸ āĻ†āĻĒāĻĄā§‡āĻŸāĻ—ā§āĻ˛āĻŋ āĻ‰āĻĒāĻžāĻĻāĻžāĻ¨āĻ—ā§āĻ˛āĻŋāĻ° āĻ…āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ā§€āĻ¯āĻŧ āĻ°ā§‡āĻ¨ā§āĻĄāĻžāĻ°āĻŋāĻ‚āĻ¯āĻŧā§‡āĻ° āĻĻāĻŋāĻ•ā§‡ āĻĒāĻ°āĻŋāĻšāĻžāĻ˛āĻŋāĻ¤ āĻ•āĻ°ā§‡āĨ¤ āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°ā§‡, āĻĒā§āĻ°āĻĨāĻŽ āĻŦāĻž āĻĻā§āĻŦāĻŋāĻ¤ā§€āĻ¯āĻŧāĻŸāĻŋ āĻŦāĻŋāĻļā§‡āĻˇāĻ­āĻžāĻŦā§‡ āĻĒā§āĻ°āĻžāĻ¸āĻ™ā§āĻ—āĻŋāĻ• āĻ¨āĻ¯āĻŧ, āĻ¤āĻŦā§‡ āĻ†āĻŽāĻ°āĻž āĻ¸ā§‡āĻ°āĻž āĻ…āĻ¨ā§āĻļā§€āĻ˛āĻ¨āĻ—ā§āĻ˛āĻŋ āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻŦā§ˇ āĻĒāĻ°āĻŋāĻ˛āĻ•ā§āĻˇāĻŋāĻ¤ āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°āĻ—ā§āĻ˛āĻŋāĻ° āĻ…āĻŦāĻ¸ā§āĻĨāĻž āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°ā§‡ āĻāĻŽāĻ¨ āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻĢāĻžāĻ‚āĻļāĻ¨ā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻ¸āĻœā§āĻœāĻžāĻ¸āĻ‚āĻļā§āĻ˛āĻŋāĻˇā§āĻŸāĻĻā§‡āĻ° āĻ¸āĻ‚āĻ¯ā§āĻ•ā§āĻ¤ āĻ•āĻ°āĻžāĻ° āĻĒā§āĻ°āĻĨāĻžāĻ—āĻ¤āĨ¤

āĻŦā§āĻ¯āĻžāĻ•āĻ—ā§āĻ°āĻžāĻ‰āĻ¨ā§āĻĄā§‡ āĻ†āĻŽāĻ°āĻž āĻ¸ā§āĻĨāĻžāĻ¨ā§€āĻ¯āĻŧ āĻ¸ā§āĻŸā§‹āĻ°ā§‡āĻœā§‡ āĻ¸ā§āĻŸā§‡āĻŸāĻ•ā§‡ āĻĒā§āĻ°āĻžāĻ°āĻŽā§āĻ­āĻŋāĻ•āĻ¤āĻž āĻāĻŦāĻ‚ āĻ¸ā§‡āĻ­ āĻ•āĻ°āĻŦ:

import {reaction, toJS} from 'mobx';
import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import {SignerApp} from "./SignerApp";
// ВŅĐŋĐžĐŧĐžĐŗĐ°Ņ‚ĐĩĐģŅŒĐŊŅ‹Đĩ ĐŧĐĩŅ‚ОдŅ‹. ЗаĐŋиŅŅ‹Đ˛Đ°ŅŽŅ‚/Ņ‡Đ¸Ņ‚Đ°ŅŽŅ‚ ОйŅŠĐĩĐēŅ‚ в/иС localStorage видĐĩ JSON ŅŅ‚Ņ€ĐžĐēи ĐŋĐž ĐēĐģŅŽŅ‡Ņƒ 'store'
import {loadState, saveState} from "./utils/localStorage";

const DEV_MODE = process.env.NODE_ENV !== 'production';

setupApp();

function setupApp() {
    const initState = loadState();
    const app = new SignerApp(initState);

    if (DEV_MODE) {
        global.app = app;
    }

    // Setup state persistence

    // Đ ĐĩСŅƒĐģŅŒŅ‚Đ°Ņ‚ reaction ĐŋŅ€Đ¸ŅĐ˛Đ°Đ¸Đ˛Đ°ĐĩŅ‚ŅŅ ĐŋĐĩŅ€ĐĩĐŧĐĩĐŊĐŊОК, Ņ‡Ņ‚ОйŅ‹ ĐŋОдĐŋиŅĐēŅƒ ĐŧĐžĐļĐŊĐž ĐąŅ‹ĐģĐž ĐžŅ‚ĐŧĐĩĐŊиŅ‚ŅŒ. НаĐŧ ŅŅ‚Đž ĐŊĐĩ ĐŊŅƒĐļĐŊĐž, ĐžŅŅ‚авĐģĐĩĐŊĐž Đ´ĐģŅ ĐŋŅ€Đ¸ĐŧĐĩŅ€Đ°
    const localStorageReaction = reaction(
        () => toJS(app.store), // ФŅƒĐŊĐēŅ†Đ¸Ņ-ŅĐĩĐģĐĩĐēŅ‚ĐžŅ€ Đ´Đ°ĐŊĐŊŅ‹Ņ…
        saveState // ФŅƒĐŊĐēŅ†Đ¸Ņ, ĐēĐžŅ‚ĐžŅ€Đ°Ņ ĐąŅƒĐ´ĐĩŅ‚ вŅ‹ĐˇĐ˛Đ°ĐŊĐ° ĐŋŅ€Đ¸ иСĐŧĐĩĐŊĐĩĐŊии Đ´Đ°ĐŊĐŊŅ‹Ņ…, ĐēĐžŅ‚ĐžŅ€Ņ‹Đĩ вОСвŅ€Đ°Ņ‰Đ°ĐĩŅ‚ ŅĐĩĐģĐĩĐēŅ‚ĐžŅ€
    );

    extensionApi.runtime.onConnect.addListener(connectRemote);

    function connectRemote(remotePort) {
        const processName = remotePort.name;
        const portStream = new PortStream(remotePort);
        if (processName === 'contentscript') {
            const origin = remotePort.sender.url
            app.connectPage(portStream, origin)
        } else {
            app.connectPopup(portStream)
        }
    }
}

āĻĒā§āĻ°āĻ¤āĻŋāĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻž āĻĢāĻžāĻ‚āĻļāĻ¨ āĻāĻ–āĻžāĻ¨ā§‡ āĻ†āĻ•āĻ°ā§āĻˇāĻŖā§€āĻ¯āĻŧ. āĻāĻ° āĻĻā§āĻŸāĻŋ āĻ¯ā§āĻ•ā§āĻ¤āĻŋ āĻ°āĻ¯āĻŧā§‡āĻ›ā§‡:

  1. āĻĄā§‡āĻŸāĻž āĻ¨āĻŋāĻ°ā§āĻŦāĻžāĻšāĻ•āĨ¤
  2. āĻāĻ•āĻŸāĻŋ āĻšā§āĻ¯āĻžāĻ¨ā§āĻĄāĻ˛āĻžāĻ° āĻ¯āĻž āĻĒā§āĻ°āĻ¤āĻŋāĻŦāĻžāĻ° āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°āĻžāĻ° āĻ¸āĻŽāĻ¯āĻŧ āĻāĻ‡ āĻĄā§‡āĻŸāĻž āĻ¸āĻš āĻ•āĻ˛ ​​āĻ•āĻ°āĻž āĻšāĻŦā§‡āĨ¤

āĻ°ā§‡āĻĄāĻ•ā§āĻ¸ā§‡āĻ° āĻŦāĻŋāĻĒāĻ°ā§€āĻ¤ā§‡, āĻ¯ā§‡āĻ–āĻžāĻ¨ā§‡ āĻ†āĻŽāĻ°āĻž āĻ¸ā§āĻĒāĻˇā§āĻŸāĻ­āĻžāĻŦā§‡ āĻāĻ•āĻŸāĻŋ āĻ¯ā§āĻ•ā§āĻ¤āĻŋ āĻšāĻŋāĻ¸āĻžāĻŦā§‡ āĻ¸ā§āĻŸā§‡āĻŸ āĻ—ā§āĻ°āĻšāĻŖ āĻ•āĻ°āĻŋ, mobx āĻŽāĻ¨ā§‡ āĻ°āĻžāĻ–ā§‡ āĻ¯ā§‡ āĻ†āĻŽāĻ°āĻž āĻ¨āĻŋāĻ°ā§āĻŦāĻžāĻšāĻ•ā§‡āĻ° āĻ­āĻŋāĻ¤āĻ°ā§‡ āĻ•ā§‹āĻ¨ āĻĒāĻ°ā§āĻ¯āĻŦā§‡āĻ•ā§āĻˇāĻŖāĻ¯ā§‹āĻ—ā§āĻ¯āĻ—ā§āĻ˛āĻŋ āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻ•āĻ°āĻŋ āĻāĻŦāĻ‚ āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻšā§āĻ¯āĻžāĻ¨ā§āĻĄāĻ˛āĻžāĻ°āĻ•ā§‡ āĻ•āĻ˛ āĻ•āĻ°ā§‡ āĻ¯āĻ–āĻ¨ āĻ¤āĻžāĻ°āĻž āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°ā§‡āĨ¤

āĻāĻŸāĻž āĻŦā§‹āĻāĻž āĻ—ā§āĻ°ā§āĻ¤ā§āĻŦāĻĒā§‚āĻ°ā§āĻŖ āĻ¯ā§‡ āĻ āĻŋāĻ• āĻ•āĻŋāĻ­āĻžāĻŦā§‡ mobx āĻ¸āĻŋāĻĻā§āĻ§āĻžāĻ¨ā§āĻ¤ āĻ¨ā§‡āĻ¯āĻŧ āĻ•ā§‹āĻ¨ āĻĒāĻ°ā§āĻ¯āĻŦā§‡āĻ•ā§āĻˇāĻŖāĻ¯ā§‹āĻ—ā§āĻ¯ āĻ†āĻŽāĻ°āĻž āĻ¸āĻžāĻŦāĻ¸ā§āĻ•ā§āĻ°āĻžāĻ‡āĻŦ āĻ•āĻ°āĻŦāĨ¤ āĻ¯āĻĻāĻŋ āĻ†āĻŽāĻŋ āĻāĻ‡ āĻŽāĻ¤ āĻ•ā§‹āĻĄ āĻāĻ•āĻŸāĻŋ āĻ¨āĻŋāĻ°ā§āĻŦāĻžāĻšāĻ• āĻ˛āĻŋāĻ–ā§‡āĻ›āĻŋāĻ˛āĻžāĻŽ() => app.store, āĻ¤āĻžāĻšāĻ˛ā§‡ āĻĒā§āĻ°āĻ¤āĻŋāĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻž āĻ•āĻ–āĻ¨āĻ‡ āĻŦāĻ˛āĻž āĻšāĻŦā§‡ āĻ¨āĻž, āĻ¯ā§‡āĻšā§‡āĻ¤ā§ āĻ¸ā§āĻŸā§‹āĻ°ā§‡āĻœ āĻ¨āĻŋāĻœā§‡āĻ‡ āĻĒāĻ°ā§āĻ¯āĻŦā§‡āĻ•ā§āĻˇāĻŖāĻ¯ā§‹āĻ—ā§āĻ¯ āĻ¨āĻ¯āĻŧ, āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻāĻ° āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°āĻ—ā§āĻ˛āĻŋāĨ¤

āĻ¯āĻĻāĻŋ āĻāĻ­āĻžāĻŦā§‡ āĻ˛āĻŋāĻ–āĻ¤āĻžāĻŽ () => app.store.keys, āĻ¤āĻžāĻ°āĻĒāĻ° āĻ†āĻŦāĻžāĻ° āĻ•āĻŋāĻ›ā§āĻ‡ āĻ˜āĻŸāĻŦā§‡ āĻ¨āĻž, āĻ¯ā§‡āĻšā§‡āĻ¤ā§ āĻ…ā§āĻ¯āĻžāĻ°ā§‡ āĻ‰āĻĒāĻžāĻĻāĻžāĻ¨āĻ—ā§āĻ˛āĻŋ āĻ¯ā§‹āĻ—/āĻ¸āĻ°āĻžāĻ¨ā§‹āĻ° āĻ¸āĻŽāĻ¯āĻŧ, āĻāĻŸāĻŋāĻ° āĻ°ā§‡āĻĢāĻžāĻ°ā§‡āĻ¨ā§āĻ¸ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻšāĻŦā§‡ āĻ¨āĻžāĨ¤

Mobx āĻĒā§āĻ°āĻĨāĻŽāĻŦāĻžāĻ°ā§‡āĻ° āĻŽāĻ¤ā§‹ āĻāĻ•āĻœāĻ¨ āĻ¨āĻŋāĻ°ā§āĻŦāĻžāĻšāĻ• āĻšāĻŋāĻ¸ā§‡āĻŦā§‡ āĻ•āĻžāĻœ āĻ•āĻ°ā§‡ āĻāĻŦāĻ‚ āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻ†āĻŽāĻ°āĻž āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻ•āĻ°ā§‡āĻ›āĻŋ āĻāĻŽāĻ¨ āĻĒāĻ°ā§āĻ¯āĻŦā§‡āĻ•ā§āĻˇāĻŖā§‡āĻ° āĻŸā§āĻ°ā§āĻ¯āĻžāĻ• āĻ°āĻžāĻ–ā§‡āĨ¤ āĻāĻŸāĻŋ āĻĒā§āĻ°āĻ•ā§āĻ¸āĻŋ āĻ—ā§‡āĻŸāĻžāĻ°ā§‡āĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧāĨ¤ āĻ¤āĻžāĻ‡ āĻāĻ–āĻžāĻ¨ā§‡ āĻŦāĻŋāĻ˛ā§āĻŸ-āĻ‡āĻ¨ āĻĢāĻžāĻ‚āĻļāĻ¨ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻž āĻšāĻ¯āĻŧā§‡āĻ›ā§‡ toJS. āĻāĻŸāĻŋ āĻŽā§‚āĻ˛ āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°āĻ—ā§āĻ˛āĻŋāĻ° āĻ¸āĻžāĻĨā§‡ āĻĒā§āĻ°āĻ¤āĻŋāĻ¸ā§āĻĨāĻžāĻĒāĻŋāĻ¤ āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻĒā§āĻ°āĻ•ā§āĻ¸āĻŋ āĻ¸āĻš āĻāĻ•āĻŸāĻŋ āĻ¨āĻ¤ā§āĻ¨ āĻŦāĻ¸ā§āĻ¤ā§ āĻĒā§āĻ°āĻĻāĻžāĻ¨ āĻ•āĻ°ā§‡āĨ¤ āĻ•āĻžāĻ°ā§āĻ¯āĻ•āĻ° āĻ•āĻ°āĻžāĻ° āĻ¸āĻŽāĻ¯āĻŧ, āĻāĻŸāĻŋ āĻŦāĻ¸ā§āĻ¤ā§āĻ° āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ° āĻĒāĻĄāĻŧā§‡ - āĻ¤āĻžāĻ‡ āĻ—ā§‡āĻŸāĻžāĻ°āĻ—ā§āĻ˛āĻŋ āĻŸā§āĻ°āĻŋāĻ—āĻžāĻ° āĻšāĻ¯āĻŧāĨ¤

āĻĒāĻĒāĻ†āĻĒ āĻ•āĻ¨āĻ¸ā§‹āĻ˛ā§‡ āĻ†āĻŽāĻ°āĻž āĻ†āĻŦāĻžāĻ° āĻ•āĻ¯āĻŧā§‡āĻ•āĻŸāĻŋ āĻ•ā§€ āĻ¯ā§‹āĻ— āĻ•āĻ°āĻŦāĨ¤ āĻāĻ‡ āĻ¸āĻŽāĻ¯āĻŧ āĻ¤āĻžāĻ°āĻž āĻ¸ā§āĻĨāĻžāĻ¨ā§€āĻ¯āĻŧ āĻ¸ā§āĻŸā§‹āĻ°ā§‡āĻœ āĻāĻ“ āĻļā§‡āĻˇ āĻšāĻ¯āĻŧā§‡āĻ›ā§‡:

āĻāĻ•āĻŸāĻŋ āĻ¨āĻŋāĻ°āĻžāĻĒāĻĻ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ˛ā§‡āĻ–āĻž

āĻ¯āĻ–āĻ¨ āĻŦā§āĻ¯āĻžāĻ•āĻ—ā§āĻ°āĻžāĻ‰āĻ¨ā§āĻĄ āĻĒā§ƒāĻˇā§āĻ āĻžāĻŸāĻŋ āĻĒā§āĻ¨āĻ°āĻžāĻ¯āĻŧ āĻ˛ā§‹āĻĄ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧ, āĻ¤āĻĨā§āĻ¯āĻŸāĻŋ āĻœāĻžāĻ¯āĻŧāĻ—āĻžāĻ¯āĻŧ āĻĨāĻžāĻ•ā§‡āĨ¤

āĻāĻ‡ āĻŦāĻŋāĻ¨ā§āĻĻā§ āĻĒāĻ°ā§āĻ¯āĻ¨ā§āĻ¤ āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ āĻ•ā§‹āĻĄ āĻĻā§‡āĻ–āĻž āĻ¯āĻžāĻŦā§‡ āĻāĻ–āĻžāĻ¨ā§‡.

āĻŦā§āĻ¯āĻ•ā§āĻ¤āĻŋāĻ—āĻ¤ āĻ•ā§€āĻ—ā§āĻ˛āĻŋāĻ° āĻ¸ā§āĻ°āĻ•ā§āĻˇāĻŋāĻ¤ āĻ¸āĻžā§āĻšāĻ¯āĻŧāĻ¸ā§āĻĨāĻžāĻ¨

āĻ¸ā§āĻĒāĻˇā§āĻŸ āĻĒāĻžāĻ ā§āĻ¯ā§‡ āĻŦā§āĻ¯āĻ•ā§āĻ¤āĻŋāĻ—āĻ¤ āĻ•ā§€āĻ—ā§āĻ˛āĻŋ āĻ¸āĻ‚āĻ°āĻ•ā§āĻˇāĻŖ āĻ•āĻ°āĻž āĻ…āĻ¨āĻŋāĻ°āĻžāĻĒāĻĻ: āĻ¸āĻŦāĻ¸āĻŽāĻ¯āĻŧ āĻāĻ•āĻŸāĻŋ āĻ¸āĻŽā§āĻ­āĻžāĻŦāĻ¨āĻž āĻĨāĻžāĻ•ā§‡ āĻ¯ā§‡ āĻ†āĻĒāĻ¨āĻŋ āĻšā§āĻ¯āĻžāĻ• āĻšāĻŦā§‡āĻ¨, āĻ†āĻĒāĻ¨āĻžāĻ° āĻ•āĻŽā§āĻĒāĻŋāĻ‰āĻŸāĻžāĻ°ā§‡ āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻĒāĻžāĻŦā§‡āĻ¨ āĻāĻŦāĻ‚ āĻ†āĻ°āĻ“ āĻ…āĻ¨ā§‡āĻ• āĻ•āĻŋāĻ›ā§āĨ¤ āĻ…āĻ¤āĻāĻŦ, āĻ˛ā§‹āĻ•āĻžāĻ˛ āĻ¸ā§āĻŸā§‹āĻ°ā§‡āĻœ-āĻ āĻ†āĻŽāĻ°āĻž āĻ•ā§€āĻ—ā§āĻ˛āĻŋ āĻāĻ•āĻŸāĻŋ āĻĒāĻžāĻ¸āĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻĄ-āĻāĻ¨āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸ āĻ•āĻ°āĻž āĻ†āĻ•āĻžāĻ°ā§‡ āĻ¸āĻ‚āĻ°āĻ•ā§āĻˇāĻŖ āĻ•āĻ°āĻŦāĨ¤

āĻŦā§ƒāĻšāĻ¤ā§āĻ¤āĻ° āĻ¨āĻŋāĻ°āĻžāĻĒāĻ¤ā§āĻ¤āĻžāĻ° āĻœāĻ¨ā§āĻ¯, āĻ†āĻŽāĻ°āĻž āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨āĻŸāĻŋāĻ¤ā§‡ āĻāĻ•āĻŸāĻŋ āĻ˛āĻ• āĻ•āĻ°āĻž āĻ…āĻŦāĻ¸ā§āĻĨāĻž āĻ¯ā§‹āĻ— āĻ•āĻ°āĻŦ, āĻ¯ā§‡āĻ–āĻžāĻ¨ā§‡ āĻšāĻžāĻŦāĻŋāĻ—ā§āĻ˛āĻŋāĻ¤ā§‡ āĻ•ā§‹āĻ¨āĻ“ āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻĨāĻžāĻ•āĻŦā§‡ āĻ¨āĻžāĨ¤ āĻ¸āĻŽāĻ¯āĻŧāĻ¸ā§€āĻŽāĻžāĻ° āĻ•āĻžāĻ°āĻŖā§‡ āĻ†āĻŽāĻ°āĻž āĻ¸ā§āĻŦāĻ¯āĻŧāĻ‚āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻ­āĻžāĻŦā§‡ āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨āĻŸāĻŋāĻ•ā§‡ āĻ˛āĻ• āĻ•āĻ°āĻž āĻ…āĻŦāĻ¸ā§āĻĨāĻžāĻ¯āĻŧ āĻ¸ā§āĻĨāĻžāĻ¨āĻžāĻ¨ā§āĻ¤āĻ° āĻ•āĻ°āĻŦāĨ¤

Mobx āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻāĻ•āĻŸāĻŋ āĻ¨ā§āĻ¯ā§‚āĻ¨āĻ¤āĻŽ āĻ¸ā§‡āĻŸ āĻĄā§‡āĻŸāĻž āĻ¸āĻžā§āĻšāĻ¯āĻŧ āĻ•āĻ°āĻ¤ā§‡ āĻĻā§‡āĻ¯āĻŧ āĻāĻŦāĻ‚ āĻŦāĻžāĻ•āĻŋāĻ—ā§āĻ˛āĻŋ āĻ¸ā§āĻŦāĻ¯āĻŧāĻ‚āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻ­āĻžāĻŦā§‡ āĻāĻ° āĻ‰āĻĒāĻ° āĻ­āĻŋāĻ¤ā§āĻ¤āĻŋ āĻ•āĻ°ā§‡ āĻ—āĻŖāĻ¨āĻž āĻ•āĻ°āĻž āĻšāĻ¯āĻŧāĨ¤ āĻāĻ‡ āĻ¤āĻĨāĻžāĻ•āĻĨāĻŋāĻ¤ āĻ—āĻŖāĻ¨āĻž āĻŦā§ˆāĻļāĻŋāĻˇā§āĻŸā§āĻ¯. āĻāĻ—ā§āĻ˛āĻŋāĻ•ā§‡ āĻĄāĻžāĻŸāĻžāĻŦā§‡āĻ¸ā§‡āĻ° āĻ­āĻŋāĻ‰āĻ¯āĻŧā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻ¤ā§āĻ˛āĻ¨āĻž āĻ•āĻ°āĻž āĻ¯ā§‡āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡:

import {observable, action} from 'mobx';
import {setupDnode} from "./utils/setupDnode";
// ĐŖŅ‚иĐģиŅ‚Ņ‹ Đ´ĐģŅ ĐąĐĩСОĐŋĐ°ŅĐŊĐžĐŗĐž ŅˆĐ¸Ņ„Ņ€ĐžĐ˛Đ°ĐŊиŅ ŅŅ‚Ņ€ĐžĐē. ИŅĐŋĐžĐģŅŒĐˇŅƒŅŽŅ‚ crypto-js
import {encrypt, decrypt} from "./utils/cryptoUtils";

export class SignerApp {
    constructor(initState = {}) {
        this.store = observable.object({
            // ĐĨŅ€Đ°ĐŊиĐŧ ĐŋĐ°Ņ€ĐžĐģŅŒ и СаŅˆĐ¸Ņ„Ņ€ĐžĐ˛Đ°ĐŊĐŊŅ‹Đĩ ĐēĐģŅŽŅ‡Đ¸. ЕŅĐģи ĐŋĐ°Ņ€ĐžĐģŅŒ null - ĐŋŅ€Đ¸ĐģĐžĐļĐĩĐŊиĐĩ locked
            password: null,
            vault: initState.vault,

            // ГĐĩŅ‚Ņ‚ĐĩŅ€Ņ‹ Đ´ĐģŅ вŅ‹Ņ‡Đ¸ŅĐģиĐŧŅ‹Ņ… ĐŋĐžĐģĐĩĐš. МоĐļĐŊĐž ĐŋŅ€ĐžĐ˛ĐĩŅŅ‚и Đ°ĐŊĐ°ĐģĐžĐŗиŅŽ Ņ view в йд.
            get locked(){
                return this.password == null
            },
            get keys(){
                return this.locked ?
                    undefined :
                    SignerApp._decryptVault(this.vault, this.password)
            },
            get initialized(){
                return this.vault !== undefined
            }
        })
    }
    // ИĐŊиŅ†Đ¸Đ°ĐģиСаŅ†Đ¸Ņ ĐŋŅƒŅŅ‚ĐžĐŗĐž Ņ…Ņ€Đ°ĐŊиĐģиŅ‰Đ° ĐŊОвŅ‹Đŧ ĐŋĐ°Ņ€ĐžĐģĐĩĐŧ
    @action
    initVault(password){
        this.store.vault = SignerApp._encryptVault([], password)
    }
    @action
    lock() {
        this.store.password = null
    }
    @action
    unlock(password) {
        this._checkPassword(password);
        this.store.password = password
    }
    @action
    addKey(key) {
        this._checkLocked();
        this.store.vault = SignerApp._encryptVault(this.store.keys.concat(key), this.store.password)
    }
    @action
    removeKey(index) {
        this._checkLocked();
        this.store.vault = SignerApp._encryptVault([
                ...this.store.keys.slice(0, index),
                ...this.store.keys.slice(index + 1)
            ],
            this.store.password
        )
    }

    ... // ĐēОд ĐŋОдĐēĐģŅŽŅ‡ĐĩĐŊиŅ и api

    // private
    _checkPassword(password) {
        SignerApp._decryptVault(this.store.vault, password);
    }

    _checkLocked() {
        if (this.store.locked){
            throw new Error('App is locked')
        }
    }

    // МĐĩŅ‚ОдŅ‹ Đ´ĐģŅ ŅˆĐ¸Ņ„Ņ€ĐžĐ˛Đēи/Đ´ĐĩŅˆĐ¸Ņ„Ņ€ĐžĐ˛Đēи Ņ…Ņ€Đ°ĐŊиĐģиŅ‰Đ°
    static _encryptVault(obj, pass){
        const jsonString = JSON.stringify(obj)
        return encrypt(jsonString, pass)
    }

    static _decryptVault(str, pass){
        if (str === undefined){
            throw new Error('Vault not initialized')
        }
        try {
            const jsonString = decrypt(str, pass)
            return JSON.parse(jsonString)
        }catch (e) {
            throw new Error('Wrong password')
        }
    }
}

āĻāĻ–āĻ¨ āĻ†āĻŽāĻ°āĻž āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻāĻ¨āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸ āĻ•āĻ°āĻž āĻ•ā§€ āĻāĻŦāĻ‚ āĻĒāĻžāĻ¸āĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻĄ āĻ¸āĻ‚āĻ°āĻ•ā§āĻˇāĻŖ āĻ•āĻ°āĻŋāĨ¤ āĻŦāĻžāĻ•āĻŋ āĻ¸āĻŦ āĻšāĻŋāĻ¸āĻžāĻŦ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧāĨ¤ āĻ†āĻŽāĻ°āĻž āĻ°āĻžāĻœā§āĻ¯ āĻĨā§‡āĻ•ā§‡ āĻĒāĻžāĻ¸āĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻĄ āĻ¸āĻ°āĻŋāĻ¯āĻŧā§‡ āĻāĻ•āĻŸāĻŋ āĻ˛āĻ• āĻ…āĻŦāĻ¸ā§āĻĨāĻžāĻ¯āĻŧ āĻ¸ā§āĻĨāĻžāĻ¨āĻžāĻ¨ā§āĻ¤āĻ° āĻ•āĻ°āĻŋāĨ¤ āĻĒāĻžāĻŦāĻ˛āĻŋāĻ• API-āĻ āĻāĻ–āĻ¨ āĻ¸ā§āĻŸā§‹āĻ°ā§‡āĻœ āĻļā§āĻ°ā§ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻāĻ•āĻŸāĻŋ āĻĒāĻĻā§āĻ§āĻ¤āĻŋ āĻ°āĻ¯āĻŧā§‡āĻ›ā§‡āĨ¤

āĻāĻ¨āĻ•ā§āĻ°āĻŋāĻĒāĻļāĻ¨ā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻ˛ā§‡āĻ–āĻž āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸā§‹-āĻœā§‡āĻāĻ¸ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡ āĻ‡āĻ‰āĻŸāĻŋāĻ˛āĻŋāĻŸāĻŋ:

import CryptoJS from 'crypto-js'

// ИŅĐŋĐžĐģŅŒĐˇŅƒĐĩŅ‚ŅŅ Đ´ĐģŅ ĐžŅĐģĐžĐļĐŊĐĩĐŊиŅ ĐŋОдйОŅ€Đ° ĐŋĐ°Ņ€ĐžĐģŅ ĐŋĐĩŅ€ĐĩйОŅ€ĐžĐŧ. На ĐēĐ°ĐļĐ´Ņ‹Đš ваŅ€Đ¸Đ°ĐŊŅ‚ ĐŋĐ°Ņ€ĐžĐģŅ СĐģĐžŅƒĐŧŅ‹ŅˆĐģĐĩĐŊĐŊиĐēŅƒ ĐŋŅ€Đ¸Đ´ĐĩŅ‚ŅŅ ŅĐ´ĐĩĐģĐ°Ņ‚ŅŒ 5000 Ņ…ĐĩŅˆĐĩĐš
function strengthenPassword(pass, rounds = 5000) {
    while (rounds-- > 0){
        pass = CryptoJS.SHA256(pass).toString()
    }
    return pass
}

export function encrypt(str, pass){
    const strongPass = strengthenPassword(pass);
    return CryptoJS.AES.encrypt(str, strongPass).toString()
}

export function decrypt(str, pass){
    const strongPass = strengthenPassword(pass)
    const decrypted = CryptoJS.AES.decrypt(str, strongPass);
    return decrypted.toString(CryptoJS.enc.Utf8)
}

āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ°āĻŸāĻŋāĻ¤ā§‡ āĻāĻ•āĻŸāĻŋ āĻ¨āĻŋāĻˇā§āĻ•ā§āĻ°āĻŋāĻ¯āĻŧ API āĻ°āĻ¯āĻŧā§‡āĻ›ā§‡ āĻ¯āĻžāĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ āĻ†āĻĒāĻ¨āĻŋ āĻāĻ•āĻŸāĻŋ āĻ‡āĻ­ā§‡āĻ¨ā§āĻŸā§‡ āĻ¸āĻĻāĻ¸ā§āĻ¯āĻ¤āĻž āĻ¨āĻŋāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨ - āĻ…āĻŦāĻ¸ā§āĻĨāĻž āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨āĨ¤ āĻ°āĻžāĻˇā§āĻŸā§āĻ°, āĻ¸ā§‡āĻ‡ āĻ…āĻ¨ā§āĻ¯āĻžāĻ¯āĻŧā§€, āĻšāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡ idle, active и locked. āĻ¨āĻŋāĻˇā§āĻ•ā§āĻ°āĻŋāĻ¯āĻŧ āĻœāĻ¨ā§āĻ¯ āĻ†āĻĒāĻ¨āĻŋ āĻāĻ•āĻŸāĻŋ āĻŸāĻžāĻ‡āĻŽāĻ†āĻ‰āĻŸ āĻ¸ā§‡āĻŸ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨, āĻāĻŦāĻ‚ OS āĻ¨āĻŋāĻœā§‡āĻ‡ āĻŦā§āĻ˛āĻ• āĻšāĻ¯āĻŧā§‡ āĻ—ā§‡āĻ˛ā§‡ āĻ˛āĻ• āĻ¸ā§‡āĻŸ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧāĨ¤ āĻ†āĻŽāĻ°āĻž āĻ¸ā§āĻĨāĻžāĻ¨ā§€āĻ¯āĻŧ āĻ¸ā§āĻŸā§‹āĻ°ā§‡āĻœā§‡ āĻ¸āĻ‚āĻ°āĻ•ā§āĻˇāĻŖ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ¨āĻŋāĻ°ā§āĻŦāĻžāĻšāĻ•āĻ•ā§‡āĻ“ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°āĻŦ:

import {reaction, toJS} from 'mobx';
import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import {SignerApp} from "./SignerApp";
import {loadState, saveState} from "./utils/localStorage";

const DEV_MODE = process.env.NODE_ENV !== 'production';
const IDLE_INTERVAL = 30;

setupApp();

function setupApp() {
    const initState = loadState();
    const app = new SignerApp(initState);

    if (DEV_MODE) {
        global.app = app;
    }

    // ĐĸĐĩĐŋĐĩŅ€ŅŒ ĐŧŅ‹ ŅĐ˛ĐŊĐž ŅƒĐˇŅ‹Đ˛Đ°ĐĩĐŧ ĐŋĐžĐģĐĩ, ĐēĐžŅ‚ĐžŅ€ĐžĐŧŅƒ ĐąŅƒĐ´ĐĩŅ‚ ĐŋŅ€ĐžĐ¸ŅŅ…ОдиŅ‚ŅŒ Đ´ĐžŅŅ‚ŅƒĐŋ, reaction ĐžŅ‚Ņ€Đ°ĐąĐžŅ‚Đ°ĐĩŅ‚ ĐŊĐžŅ€ĐŧĐ°ĐģŅŒĐŊĐž
    reaction(
        () => ({
            vault: app.store.vault
        }),
        saveState
    );

    // ĐĸĐ°ĐšĐŧĐ°ŅƒŅ‚ ĐąĐĩСдĐĩĐšŅŅ‚виŅ, ĐēĐžĐŗĐ´Đ° ŅŅ€Đ°ĐąĐžŅ‚Đ°ĐĩŅ‚ ŅĐžĐąŅ‹Ņ‚иĐĩ
    extensionApi.idle.setDetectionInterval(IDLE_INTERVAL);
    // ЕŅĐģи ĐŋĐžĐģŅŒĐˇĐžĐ˛Đ°Ņ‚ĐĩĐģŅŒ СаĐģĐžŅ‡Đ¸Đģ ŅĐēŅ€Đ°ĐŊ иĐģи ĐąĐĩСдĐĩĐšŅŅ‚вОваĐģ в Ņ‚ĐĩŅ‡ĐĩĐŊиĐĩ ŅƒĐēаСаĐŊĐŊĐžĐŗĐž иĐŊŅ‚ĐĩŅ€Đ˛Đ°ĐģĐ° ĐģĐžŅ‡Đ¸Đŧ ĐŋŅ€Đ¸ĐģĐžĐļĐĩĐŊиĐĩ
    extensionApi.idle.onStateChanged.addListener(state => {
        if (['locked', 'idle'].indexOf(state) > -1) {
            app.lock()
        }
    });

    // Connect to other contexts
    extensionApi.runtime.onConnect.addListener(connectRemote);

    function connectRemote(remotePort) {
        const processName = remotePort.name;
        const portStream = new PortStream(remotePort);
        if (processName === 'contentscript') {
            const origin = remotePort.sender.url
            app.connectPage(portStream, origin)
        } else {
            app.connectPopup(portStream)
        }
    }
}

āĻāĻ‡ āĻ§āĻžāĻĒ āĻ†āĻ—ā§‡ āĻ•ā§‹āĻĄ āĻāĻ–āĻžāĻ¨ā§‡.

āĻ˛ā§‡āĻ¨āĻĻā§‡āĻ¨

āĻ¸ā§āĻ¤āĻ°āĻžāĻ‚, āĻ†āĻŽāĻ°āĻž āĻ¸āĻŦāĻšā§‡āĻ¯āĻŧā§‡ āĻ—ā§āĻ°ā§āĻ¤ā§āĻŦāĻĒā§‚āĻ°ā§āĻŖ āĻŦāĻŋāĻˇāĻ¯āĻŧā§‡ āĻ†āĻ¸āĻŋ: āĻŦā§āĻ˛āĻ•āĻšā§‡āĻ‡āĻ¨ā§‡ āĻ˛ā§‡āĻ¨āĻĻā§‡āĻ¨ āĻ¤ā§ˆāĻ°āĻŋ āĻāĻŦāĻ‚ āĻ¸ā§āĻŦāĻžāĻ•ā§āĻˇāĻ° āĻ•āĻ°āĻžāĨ¤ āĻ†āĻŽāĻ°āĻž WAVES āĻŦā§āĻ˛āĻ•āĻšā§‡āĻ‡āĻ¨ āĻāĻŦāĻ‚ āĻ˛āĻžāĻ‡āĻŦā§āĻ°ā§‡āĻ°āĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻŦ āĻ¤āĻ°āĻ™ā§āĻ—-āĻ˛ā§‡āĻ¨āĻĻā§‡āĻ¨.

āĻĒā§āĻ°āĻĨāĻŽā§‡, āĻ†āĻ¸ā§āĻ¨ āĻ°āĻžāĻœā§āĻ¯ā§‡ āĻŦāĻžāĻ°ā§āĻ¤āĻžāĻ—ā§āĻ˛āĻŋāĻ° āĻāĻ•āĻŸāĻŋ āĻ…ā§āĻ¯āĻžāĻ°ā§‡ āĻ¯ā§āĻ•ā§āĻ¤ āĻ•āĻ°āĻŋ āĻ¯āĻž āĻ¸ā§āĻŦāĻžāĻ•ā§āĻˇāĻ° āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡, āĻ¤āĻžāĻ°āĻĒāĻ°ā§‡ āĻāĻ•āĻŸāĻŋ āĻ¨āĻ¤ā§āĻ¨ āĻŦāĻžāĻ°ā§āĻ¤āĻž āĻ¯ā§‹āĻ— āĻ•āĻ°āĻžāĻ°, āĻ¸ā§āĻŦāĻžāĻ•ā§āĻˇāĻ° āĻ¨āĻŋāĻļā§āĻšāĻŋāĻ¤ āĻ•āĻ°āĻž āĻāĻŦāĻ‚ āĻĒā§āĻ°āĻ¤ā§āĻ¯āĻžāĻ–ā§āĻ¯āĻžāĻ¨ āĻ•āĻ°āĻžāĻ° āĻĒāĻĻā§āĻ§āĻ¤āĻŋāĻ—ā§āĻ˛āĻŋ āĻ¯ā§āĻ•ā§āĻ¤ āĻ•āĻ°ā§āĻ¨:

import {action, observable, reaction} from 'mobx';
import uuid from 'uuid/v4';
import {signTx} from '@waves/waves-transactions'
import {setupDnode} from "./utils/setupDnode";
import {decrypt, encrypt} from "./utils/cryptoUtils";

export class SignerApp {

    ...

    @action
    newMessage(data, origin) {
        // ДĐģŅ ĐēĐ°ĐļĐ´ĐžĐŗĐž ŅĐžĐžĐąŅ‰ĐĩĐŊиŅ ŅĐžĐˇĐ´Đ°ĐĩĐŧ ĐŧĐĩŅ‚Đ°Đ´Đ°ĐŊĐŊŅ‹Đĩ Ņ id, ŅŅ‚Đ°Ņ‚ŅƒŅĐžĐŧ, вŅ‹Ņ€ĐĩĐŧĐĩĐŊĐĩĐŧ ŅĐžĐˇĐ´Đ°ĐŊиŅ и Ņ‚Đ´.
        const message = observable.object({
            id: uuid(), // ИдĐĩĐŊŅ‚иŅ„иĐēĐ°Ņ‚ĐžŅ€, иŅĐŋĐžĐģŅŒĐˇŅƒŅŽŅŽ uuid
            origin, // Origin ĐąŅƒĐ´ĐĩĐŧ вĐŋĐžŅĐģĐĩĐ´ŅŅ‚вии ĐŋĐžĐēаСŅ‹Đ˛Đ°Ņ‚ŅŒ в иĐŊŅ‚ĐĩŅ€Ņ„ĐĩĐšŅĐĩ
            data, //
            status: 'new', // ĐĄŅ‚Đ°Ņ‚ŅƒŅĐžĐ˛ ĐąŅƒĐ´ĐĩŅ‚ Ņ‡ĐĩŅ‚Ņ‹Ņ€Đĩ: new, signed, rejected и failed
            timestamp: Date.now()
        });
        console.log(`new message: ${JSON.stringify(message, null, 2)}`);

        this.store.messages.push(message);

        // ВозвŅ€Đ°Ņ‰Đ°ĐĩĐŧ ĐŋŅ€ĐžĐŧиŅ вĐŊŅƒŅ‚Ņ€Đ¸ ĐēĐžŅ‚ĐžŅ€ĐžĐŗĐž mobx ĐŧĐžĐŊиŅ‚ĐžŅ€Đ¸Ņ‚ иСĐŧĐĩĐŊĐĩĐŊиŅ ŅĐžĐžĐąŅ‰ĐĩĐŊиŅ. КаĐē Ņ‚ĐžĐģŅŒĐēĐž ŅŅ‚Đ°Ņ‚ŅƒŅ ĐŋĐžĐŧĐĩĐŊŅĐĩŅ‚ŅŅ ĐŧŅ‹ СаŅ€ĐĩСОĐģвиĐŧ ĐĩĐŗĐž
        return new Promise((resolve, reject) => {
            reaction(
                () => message.status, //БŅƒĐ´ĐĩĐŧ ОйŅĐĩŅ€Đ˛Đ¸Ņ‚ŅŒ ŅŅ‚Đ°Ņ‚ŅƒŅ ŅĐžĐžĐąŅ‰ĐĩĐŊŅ
                (status, reaction) => { // вŅ‚ĐžŅ€ĐžĐš Đ°Ņ€ĐŗŅƒĐŧĐĩĐŊŅ‚ ŅŅ‚Đž ŅŅŅ‹ĐģĐēĐ° ĐŊĐ° ŅĐ°Đŧ reaction, Ņ‡Ņ‚ОйŅ‹ ĐĩĐŗĐž ĐŧĐžĐļĐŊĐž ĐąŅ‹ĐģĐž ŅƒĐŊиŅ‡Ņ‚ĐžĐļŅ‚ŅŒ вĐŊŅƒŅ‚Ņ€Đ¸ вŅ‹ĐˇĐžĐ˛Đ°
                    switch (status) {
                        case 'signed':
                            resolve(message.data);
                            break;
                        case 'rejected':
                            reject(new Error('User rejected message'));
                            break;
                        case 'failed':
                            reject(new Error(message.err.message));
                            break;
                        default:
                            return
                    }
                    reaction.dispose()
                }
            )
        })
    }
    @action
    approve(id, keyIndex = 0) {
        const message = this.store.messages.find(msg => msg.id === id);
        if (message == null) throw new Error(`No msg with id:${id}`);
        try {
            message.data = signTx(message.data, this.store.keys[keyIndex]);
            message.status = 'signed'
        } catch (e) {
            message.err = {
                stack: e.stack,
                message: e.message
            };
            message.status = 'failed'
            throw e
        }
    }
    @action
    reject(id) {
        const message = this.store.messages.find(msg => msg.id === id);
        if (message == null) throw new Error(`No msg with id:${id}`);
        message.status = 'rejected'
    }

    ...
}

āĻ¯āĻ–āĻ¨ āĻ†āĻŽāĻ°āĻž āĻāĻ•āĻŸāĻŋ āĻ¨āĻ¤ā§āĻ¨ āĻŦāĻžāĻ°ā§āĻ¤āĻž āĻĒāĻžāĻ‡, āĻ†āĻŽāĻ°āĻž āĻāĻ¤ā§‡ āĻŽā§‡āĻŸāĻžāĻĄā§‡āĻŸāĻž āĻ¯ā§‹āĻ— āĻ•āĻ°āĻŋ, āĻ•āĻ°āĻŋ observable āĻāĻŦāĻ‚ āĻ¯ā§‹āĻ— āĻ•āĻ°ā§āĻ¨ store.messages.

āĻ¯āĻĻāĻŋ āĻ†āĻĒāĻ¨āĻŋ āĻ¨āĻž āĻ•āĻ°ā§‡āĻ¨ observable āĻŽā§āĻ¯āĻžāĻ¨ā§āĻ¯āĻŧāĻžāĻ˛āĻŋ, āĻ¤āĻžāĻ°āĻĒāĻ° āĻ…ā§āĻ¯āĻžāĻ°ā§‡āĻ¤ā§‡ āĻŦāĻžāĻ°ā§āĻ¤āĻž āĻ¯ā§‹āĻ— āĻ•āĻ°āĻžāĻ° āĻ¸āĻŽāĻ¯āĻŧ mobx āĻ¨āĻŋāĻœā§‡āĻ‡ āĻāĻŸāĻŋ āĻ•āĻ°āĻŦā§‡āĨ¤ āĻ¯āĻžāĻ‡āĻšā§‹āĻ•, āĻāĻŸāĻŋ āĻāĻ•āĻŸāĻŋ āĻ¨āĻ¤ā§āĻ¨ āĻ…āĻŦāĻœā§‡āĻ•ā§āĻŸ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻŦā§‡ āĻ¯āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ•āĻžāĻ›ā§‡ āĻ°ā§‡āĻĢāĻžāĻ°ā§‡āĻ¨ā§āĻ¸ āĻĨāĻžāĻ•āĻŦā§‡ āĻ¨āĻž, āĻ¤āĻŦā§‡ āĻĒāĻ°āĻŦāĻ°ā§āĻ¤ā§€ āĻ§āĻžāĻĒā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻāĻŸāĻŋāĻ° āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ āĻšāĻŦā§‡āĨ¤

āĻāĻ° āĻĒāĻ°ā§‡, āĻ†āĻŽāĻ°āĻž āĻāĻ•āĻŸāĻŋ āĻĒā§āĻ°āĻ¤āĻŋāĻļā§āĻ°ā§āĻ¤āĻŋ āĻĢāĻŋāĻ°āĻŋāĻ¯āĻŧā§‡ āĻĻāĻŋāĻ‡ āĻ¯āĻž āĻŦāĻžāĻ°ā§āĻ¤āĻžāĻ° āĻ¸ā§āĻĨāĻŋāĻ¤āĻŋ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻŋāĻ¤ āĻšāĻ˛ā§‡ āĻ¸āĻŽāĻžāĻ§āĻžāĻ¨ āĻšāĻ¯āĻŧāĨ¤ āĻĒā§āĻ°āĻ¤āĻŋāĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻž āĻĻā§āĻŦāĻžāĻ°āĻž āĻ¸ā§āĻŸā§āĻ¯āĻžāĻŸāĻžāĻ¸ āĻ¨āĻŋāĻ°ā§€āĻ•ā§āĻˇāĻŖ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧ, āĻ¯āĻž āĻ¸ā§āĻŸā§āĻ¯āĻžāĻŸāĻžāĻ¸ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻŋāĻ¤ āĻšāĻ˛ā§‡ "āĻ¨āĻŋāĻœā§‡āĻ•ā§‡ āĻŽā§‡āĻ°ā§‡ āĻĢā§‡āĻ˛āĻŦā§‡"āĨ¤

āĻĒāĻĻā§āĻ§āĻ¤āĻŋ āĻ•ā§‹āĻĄ approve и reject āĻ–ā§āĻŦ āĻ¸āĻšāĻœ: āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ā§‡ āĻ¸ā§āĻŦāĻžāĻ•ā§āĻˇāĻ° āĻ•āĻ°āĻžāĻ° āĻĒāĻ°ā§‡ āĻ†āĻŽāĻ°āĻž āĻ•ā§‡āĻŦāĻ˛ āĻŦāĻžāĻ°ā§āĻ¤āĻžāĻŸāĻŋāĻ° āĻ¸ā§āĻĨāĻŋāĻ¤āĻŋ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°āĻŋāĨ¤

āĻ†āĻŽāĻ°āĻž UI API-āĻ āĻ…āĻ¨ā§āĻŽā§‹āĻĻāĻ¨ āĻāĻŦāĻ‚ āĻĒā§āĻ°āĻ¤ā§āĻ¯āĻžāĻ–ā§āĻ¯āĻžāĻ¨, āĻĒā§ƒāĻˇā§āĻ āĻž API-āĻ newMessage āĻ°āĻžāĻ–āĻŋ:

export class SignerApp {
    ...
    popupApi() {
        return {
            addKey: async (key) => this.addKey(key),
            removeKey: async (index) => this.removeKey(index),

            lock: async () => this.lock(),
            unlock: async (password) => this.unlock(password),
            initVault: async (password) => this.initVault(password),

            approve: async (id, keyIndex) => this.approve(id, keyIndex),
            reject: async (id) => this.reject(id)
        }
    }

    pageApi(origin) {
        return {
            signTransaction: async (txParams) => this.newMessage(txParams, origin)
        }
    }

    ...
}

āĻāĻ–āĻ¨ āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻ˛ā§‡āĻ¨āĻĻā§‡āĻ¨ āĻ¸ā§āĻŦāĻžāĻ•ā§āĻˇāĻ° āĻ•āĻ°āĻžāĻ° āĻšā§‡āĻˇā§āĻŸāĻž āĻ•āĻ°āĻž āĻ¯āĻžāĻ•:

āĻāĻ•āĻŸāĻŋ āĻ¨āĻŋāĻ°āĻžāĻĒāĻĻ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ˛ā§‡āĻ–āĻž

āĻ¸āĻžāĻ§āĻžāĻ°āĻŖāĻ­āĻžāĻŦā§‡, āĻ¸āĻŦāĻ•āĻŋāĻ›ā§ āĻĒā§āĻ°āĻ¸ā§āĻ¤ā§āĻ¤, āĻ¯āĻž āĻ…āĻŦāĻļāĻŋāĻˇā§āĻŸ āĻĨāĻžāĻ•ā§‡ āĻ¤āĻž āĻšāĻ˛ āĻ¸āĻšāĻœ UI āĻ¯ā§‹āĻ— āĻ•āĻ°ā§āĻ¨.

UI

āĻ‡āĻ¨ā§āĻŸāĻžāĻ°āĻĢā§‡āĻ¸ā§‡āĻ° āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻžāĻ¨ āĻ¸ā§āĻŸā§‡āĻŸā§‡ āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨āĨ¤ UI āĻ¸āĻžāĻ‡āĻĄā§‡ āĻ†āĻŽāĻ°āĻž āĻ•āĻ°āĻŦ observable āĻ¸ā§āĻŸā§‡āĻŸ āĻ•āĻ°ā§āĻ¨ āĻāĻŦāĻ‚ āĻāĻĒāĻŋāĻ†āĻ‡āĻ¤ā§‡ āĻāĻ•āĻŸāĻŋ āĻĢāĻžāĻ‚āĻļāĻ¨ āĻ¯ā§‹āĻ— āĻ•āĻ°ā§āĻ¨ āĻ¯āĻž āĻāĻ‡ āĻ…āĻŦāĻ¸ā§āĻĨāĻž āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°āĻŦā§‡āĨ¤ āĻāĻ° āĻ¯ā§‹āĻ— āĻ•āĻ°āĻž āĻ¯āĻžāĻ• observable āĻĒāĻŸāĻ­ā§‚āĻŽāĻŋ āĻĨā§‡āĻ•ā§‡ āĻĒā§āĻ°āĻžāĻĒā§āĻ¤ API āĻ…āĻŦāĻœā§‡āĻ•ā§āĻŸā§‡:

import {observable} from 'mobx'
import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import {cbToPromise, setupDnode, transformMethods} from "./utils/setupDnode";
import {initApp} from "./ui/index";

const DEV_MODE = process.env.NODE_ENV !== 'production';

setupUi().catch(console.error);

async function setupUi() {
    // ПодĐēĐģŅŽŅ‡Đ°ĐĩĐŧŅŅ Đē ĐŋĐžŅ€Ņ‚Ņƒ, ŅĐžĐˇĐ´Đ°ĐĩĐŧ иС ĐŊĐĩĐŗĐž ŅŅ‚Ņ€Đ¸Đŧ
    const backgroundPort = extensionApi.runtime.connect({name: 'popup'});
    const connectionStream = new PortStream(backgroundPort);

    // ХОСдаĐĩĐŧ ĐŋŅƒŅŅ‚ОК observable Đ´ĐģŅ ŅĐžŅŅ‚ĐžŅĐŊиŅ background'a
    let backgroundState = observable.object({});
    const api = {
        //ОŅ‚Đ´Đ°ĐĩĐŧ ĐąĐĩĐēĐŗŅ€Đ°ŅƒĐŊĐ´Ņƒ Ņ„ŅƒĐŊĐēŅ†Đ¸ŅŽ, ĐēĐžŅ‚ĐžŅ€Đ°Ņ ĐąŅƒĐ´ĐĩŅ‚ ОйĐŊОвĐģŅŅ‚ŅŒ observable
        updateState: async state => {
            Object.assign(backgroundState, state)
        }
    };

    // ДĐĩĐģĐ°ĐĩĐŧ RPC ОйŅŠĐĩĐēŅ‚
    const dnode = setupDnode(connectionStream, api);
    const background = await new Promise(resolve => {
        dnode.once('remote', remoteApi => {
            resolve(transformMethods(cbToPromise, remoteApi))
        })
    });

    // ДобавĐģŅĐĩĐŧ в background observable ŅĐž ŅŅ‚ĐĩĐšŅ‚ĐžĐŧ
    background.state = backgroundState;

    if (DEV_MODE) {
        global.background = background;
    }

    // ЗаĐŋŅƒŅĐē иĐŊŅ‚ĐĩŅ€Ņ„ĐĩĐšŅĐ°
    await initApp(background)
}

āĻļā§‡āĻˇā§‡ āĻ†āĻŽāĻ°āĻž āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ āĻ‡āĻ¨ā§āĻŸāĻžāĻ°āĻĢā§‡āĻ¸ āĻ°ā§‡āĻ¨ā§āĻĄāĻžāĻ° āĻ•āĻ°āĻž āĻļā§āĻ°ā§ āĻ•āĻ°āĻŋāĨ¤ āĻāĻŸāĻŋ āĻāĻ•āĻŸāĻŋ āĻĒā§āĻ°āĻ¤āĻŋāĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻž āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨. āĻĒāĻŸāĻ­ā§‚āĻŽāĻŋ āĻŦāĻ¸ā§āĻ¤ā§ āĻ¸āĻšāĻœāĻ­āĻžāĻŦā§‡ āĻĒā§āĻ°āĻĒāĻ¸ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡ āĻĒāĻžāĻ¸ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧ. āĻ…āĻŦāĻļā§āĻ¯āĻ‡, āĻĒāĻĻā§āĻ§āĻ¤āĻŋāĻ—ā§āĻ˛āĻŋāĻ° āĻœāĻ¨ā§āĻ¯ āĻāĻ•āĻŸāĻŋ āĻĒā§ƒāĻĨāĻ• āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻž āĻāĻŦāĻ‚ āĻ°āĻžāĻœā§āĻ¯ā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻāĻ•āĻŸāĻŋ āĻ¸ā§āĻŸā§‹āĻ° āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻž āĻ¸āĻ āĻŋāĻ• āĻšāĻŦā§‡, āĻ¤āĻŦā§‡ āĻāĻ‡ āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§āĻŸāĻŋāĻ° āĻ‰āĻĻā§āĻĻā§‡āĻļā§āĻ¯ā§‡ āĻāĻŸāĻŋ āĻ¯āĻĨā§‡āĻˇā§āĻŸ:

import {render} from 'react-dom'
import App from './App'
import React from "react";

// ИĐŊиŅ†Đ¸Đ°ĐģиСиŅ€ŅƒĐĩĐŧ ĐŋŅ€Đ¸ĐģĐžĐļĐĩĐŊиĐĩ Ņ background ОйŅŠĐĩĐēŅ‚ĐžĐŧ в ĐēĐ°Ņ‡ĐĩŅŅ‚ вĐĩ props
export async function initApp(background){
    render(
        <App background={background}/>,
        document.getElementById('app-content')
    );
}

Mobx-āĻāĻ° āĻ¸āĻžāĻšāĻžāĻ¯ā§āĻ¯ā§‡ āĻĄā§‡āĻŸāĻž āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻšāĻ˛ā§‡ āĻ°ā§‡āĻ¨ā§āĻĄāĻžāĻ°āĻŋāĻ‚ āĻļā§āĻ°ā§ āĻ•āĻ°āĻž āĻ–ā§āĻŦ āĻ¸āĻšāĻœāĨ¤ āĻ†āĻŽāĻ°āĻž āĻ•ā§‡āĻŦāĻ˛ āĻĒā§āĻ¯āĻžāĻ•ā§‡āĻœ āĻĨā§‡āĻ•ā§‡ āĻĒāĻ°ā§āĻ¯āĻŦā§‡āĻ•ā§āĻˇāĻ• āĻĄā§‡āĻ•ā§‹āĻ°ā§‡āĻŸāĻ°āĻ•ā§‡ āĻā§āĻ˛āĻŋāĻ¯āĻŧā§‡ āĻ°āĻžāĻ–āĻŋ mobx- āĻĒā§āĻ°āĻ¤āĻŋāĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻž āĻ‰āĻĒāĻžāĻĻāĻžāĻ¨ā§‡āĻ° āĻ‰āĻĒāĻ°, āĻāĻŦāĻ‚ āĻ°ā§‡āĻ¨ā§āĻĄāĻžāĻ° āĻ¸ā§āĻŦāĻ¯āĻŧāĻ‚āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻ­āĻžāĻŦā§‡ āĻ•āĻ˛ āĻ•āĻ°āĻž āĻšāĻŦā§‡ āĻ¯āĻ–āĻ¨ āĻ‰āĻĒāĻžāĻĻāĻžāĻ¨ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻĻā§āĻŦāĻžāĻ°āĻž āĻ‰āĻ˛ā§āĻ˛ā§‡āĻ– āĻ•āĻ°āĻž āĻ•ā§‹āĻ¨ā§‹ āĻĒāĻ°ā§āĻ¯āĻŦā§‡āĻ•ā§āĻˇāĻŖāĻ¯ā§‹āĻ—ā§āĻ¯āĨ¤ āĻ†āĻĒāĻ¨āĻžāĻ° āĻ•ā§‹āĻ¨ā§‹ mapStateToProps āĻŦāĻž redux-āĻāĻ° āĻŽāĻ¤ā§‹ āĻ¸āĻ‚āĻ¯ā§‹āĻ—ā§‡āĻ° āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ āĻ¨ā§‡āĻ‡ā§ˇ āĻ¸āĻŦāĻ•āĻŋāĻ›ā§ āĻ āĻŋāĻ• āĻŦāĻžāĻ•ā§āĻ¸ā§‡āĻ° āĻŦāĻžāĻ‡āĻ°ā§‡ āĻ•āĻžāĻœ āĻ•āĻ°ā§‡:

import React, {Component, Fragment} from 'react'
import {observer} from "mobx-react";
import Init from './components/Initialize'
import Keys from './components/Keys'
import Sign from './components/Sign'
import Unlock from './components/Unlock'

@observer // ĐŖ КоĐŧĐŋĐžĐŊĐĩŅ‚Đ° Ņ ŅŅ‚иĐŧ Đ´ĐĩĐēĐžŅ€Đ°Ņ‚ĐžĐŧ ĐąŅƒĐ´ĐĩŅ‚ авŅ‚ĐžĐŧĐ°Ņ‚иŅ‡ĐĩŅĐēи вŅ‹ĐˇĐ˛Đ°ĐŊ ĐŧĐĩŅ‚Од render, ĐĩŅĐģи ĐąŅƒĐ´ŅƒŅ‚ иСĐŧĐĩĐŊĐĩĐŊŅ‹ observable ĐŊĐ° ĐēĐžŅ‚ĐžŅ€Ņ‹Đĩ ĐžĐŊ ŅŅŅ‹ĐģĐ°ĐĩŅ‚ŅŅ
export default class App extends Component {

    // ПŅ€Đ°Đ˛Đ¸ĐģŅŒĐŊĐž ĐēĐžĐŊĐĩŅ‡ĐŊĐž вŅ‹ĐŊĐĩŅŅ‚и ĐģĐžĐŗиĐēŅƒ Ņ€ĐĩĐŊĐ´ĐĩŅ€Đ° ŅŅ‚Ņ€Đ°ĐŊиŅ† в Ņ€ĐžŅƒŅ‚иĐŊĐŗ и ĐŊĐĩ иŅĐŋĐžĐģŅŒĐˇĐžĐ˛Đ°Ņ‚ŅŒ вĐģĐžĐļĐĩĐŊĐŊŅ‹Đĩ Ņ‚ĐĩŅ€ĐŊĐ°Ņ€ĐŊŅ‹Đĩ ĐžĐŋĐĩŅ€Đ°Ņ‚ĐžŅ€Ņ‹,
    // и ĐŋŅ€Đ¸Đ˛ŅĐˇŅ‹Đ˛Đ°Ņ‚ŅŒ observable и ĐŧĐĩŅ‚ОдŅ‹ background ĐŊĐĩĐŋĐžŅŅ€ĐĩĐ´ŅŅ‚вĐĩĐŊĐŊĐž Đē Ņ‚ĐĩĐŧ ĐēĐžĐŧĐŋĐžĐŊĐĩĐŊŅ‚Đ°Đŧ, ĐēĐžŅ‚ĐžŅ€Ņ‹Đĩ иŅ… иŅĐŋĐžĐģŅŒĐˇŅƒŅŽŅ‚
    render() {
        const {keys, messages, initialized, locked} = this.props.background.state;
        const {lock, unlock, addKey, removeKey, initVault, deleteVault, approve, reject} = this.props.background;

        return <Fragment>
            {!initialized
                ?
                <Init onInit={initVault}/>
                :
                locked
                    ?
                    <Unlock onUnlock={unlock}/>
                    :
                    messages.length > 0
                        ?
                        <Sign keys={keys} message={messages[messages.length - 1]} onApprove={approve} onReject={reject}/>
                        :
                        <Keys keys={keys} onAdd={addKey} onRemove={removeKey}/>
            }
            <div>
                {!locked && <button onClick={() => lock()}>Lock App</button>}
                {initialized && <button onClick={() => deleteVault()}>Delete all keys and init</button>}
            </div>
        </Fragment>
    }
}

āĻ…āĻŦāĻļāĻŋāĻˇā§āĻŸ āĻ‰āĻĒāĻžāĻĻāĻžāĻ¨ āĻ•ā§‹āĻĄ āĻĻā§‡āĻ–āĻž āĻ¯āĻžāĻŦā§‡ UI āĻĢā§‹āĻ˛ā§āĻĄāĻžāĻ°ā§‡.

āĻāĻ–āĻ¨ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ āĻ•ā§āĻ˛āĻžāĻ¸ā§‡ āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ UI-āĻāĻ° āĻœāĻ¨ā§āĻ¯ āĻāĻ•āĻŸāĻŋ āĻ°āĻžāĻœā§āĻ¯ āĻ¨āĻŋāĻ°ā§āĻŦāĻžāĻšāĻ• āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡ āĻāĻŦāĻ‚ UI āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻšāĻ˛ā§‡ āĻ¤āĻž āĻ…āĻŦāĻšāĻŋāĻ¤ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡āĨ¤ āĻāĻŸāĻŋ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯, āĻāĻ° āĻāĻ•āĻŸāĻŋ āĻĒāĻĻā§āĻ§āĻ¤āĻŋ āĻ¯ā§‹āĻ— āĻ•āĻ°āĻž āĻ¯āĻžāĻ• getState и reactionāĻ•āĻ˛āĻŋāĻ‚ remote.updateState:

import {action, observable, reaction} from 'mobx';
import uuid from 'uuid/v4';
import {signTx} from '@waves/waves-transactions'
import {setupDnode} from "./utils/setupDnode";
import {decrypt, encrypt} from "./utils/cryptoUtils";

export class SignerApp {

    ...

    // public
    getState() {
        return {
            keys: this.store.keys,
            messages: this.store.newMessages,
            initialized: this.store.initialized,
            locked: this.store.locked
        }
    }

    ...

    //
    connectPopup(connectionStream) {
        const api = this.popupApi();
        const dnode = setupDnode(connectionStream, api);

        dnode.once('remote', (remote) => {
            // ХОСдаĐĩĐŧ reaction ĐŊĐ° иСĐŧĐĩĐŊĐĩĐŊиŅ ŅŅ‚ĐĩĐšŅ‚Đ°, ĐēĐžŅ‚ĐžŅ€Ņ‹Đš ŅĐ´ĐĩĐģĐ°ĐĩŅ‚ вŅ‹ĐˇĐžĐ˛ĐĩŅ‚ ŅƒĐ´Đ°ĐģĐĩĐŊĐŊŅƒ ĐŋŅ€ĐžŅ†ĐĩĐ´ŅƒŅ€Ņƒ и ОйĐŊОвиŅ‚ ŅŅ‚ĐĩĐšŅ‚ в ui ĐŋŅ€ĐžŅ†ĐĩŅŅĐĩ
            const updateStateReaction = reaction(
                () => this.getState(),
                (state) => remote.updateState(state),
                // ĐĸŅ€ĐĩŅ‚ŅŒĐ¸Đŧ Đ°Ņ€ĐŗŅƒĐŧĐĩĐŊŅ‚ĐžĐŧ ĐŧĐžĐļĐŊĐž ĐŋĐĩŅ€ĐĩдаваŅ‚ŅŒ ĐŋĐ°Ņ€Đ°ĐŧĐĩŅ‚Ņ€Ņ‹. fireImmediatly СĐŊĐ°Ņ‡Đ¸Ņ‚ Ņ‡Ņ‚Đž reaction вŅ‹ĐŋĐžĐģĐŊиŅ‚ŅŒŅŅ ĐŋĐĩŅ€Đ˛Ņ‹Đš Ņ€Đ°Đˇ ŅŅ€Đ°ĐˇŅƒ.
                // Đ­Ņ‚Đž ĐŊĐĩОйŅ…ОдиĐŧĐž, Ņ‡Ņ‚ОйŅ‹ ĐŋĐžĐģŅƒŅ‡Đ¸Ņ‚ŅŒ ĐŊĐ°Ņ‡Đ°ĐģŅŒĐŊĐžĐĩ ŅĐžŅŅ‚ĐžŅĐŊиĐĩ. Delay ĐŋОСвОĐģŅĐĩŅ‚ ŅƒŅŅ‚Đ°ĐŊОвиŅ‚ŅŒ debounce
                {fireImmediately: true, delay: 500}
            );
            // ĐŖĐ´Đ°ĐģиĐŧ ĐŋОдĐŋиŅĐēŅƒ ĐŋŅ€Đ¸ ĐžŅ‚ĐēĐģŅŽŅ‡ĐĩĐŊии ĐēĐģиĐĩĐŊŅ‚Đ°
            dnode.once('end', () => updateStateReaction.dispose())

        })
    }

    ...
}

āĻ¯āĻ–āĻ¨ āĻāĻ•āĻŸāĻŋ āĻŦāĻ¸ā§āĻ¤ā§ āĻ—ā§āĻ°āĻšāĻŖ remote āĻ¤ā§ˆāĻ°āĻŋ āĻšāĻšā§āĻ›ā§‡ reaction UI āĻĒāĻžāĻļā§‡āĻ° āĻĢāĻžāĻ‚āĻļāĻ¨āĻŸāĻŋāĻ•ā§‡ āĻ•āĻ˛ āĻ•āĻ°ā§‡ āĻāĻŽāĻ¨ āĻ…āĻŦāĻ¸ā§āĻĨāĻž āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°āĻ¤ā§‡āĨ¤

āĻšā§‚āĻĄāĻŧāĻžāĻ¨ā§āĻ¤ āĻ¸ā§āĻĒāĻ°ā§āĻļ āĻšāĻ˛ āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ†āĻ‡āĻ•āĻ¨ā§‡ āĻ¨āĻ¤ā§āĻ¨ āĻŦāĻžāĻ°ā§āĻ¤āĻžāĻ—ā§āĻ˛āĻŋāĻ° āĻĒā§āĻ°āĻĻāĻ°ā§āĻļāĻ¨ āĻ¯ā§‹āĻ— āĻ•āĻ°āĻž:

function setupApp() {
...

    // Reaction ĐŊĐ° вŅ‹ŅŅ‚авĐģĐĩĐŊиĐĩ Ņ‚ĐĩĐēŅŅ‚Đ° ĐąĐĩĐ´ĐļĐ°.
    reaction(
        () => app.store.newMessages.length > 0 ? app.store.newMessages.length.toString() : '',
        text => extensionApi.browserAction.setBadgeText({text}),
        {fireImmediately: true}
    );

...
}

āĻ¸ā§āĻ¤āĻ°āĻžāĻ‚, āĻ†āĻŦā§‡āĻĻāĻ¨ āĻĒā§āĻ°āĻ¸ā§āĻ¤ā§āĻ¤. āĻ“āĻ¯āĻŧā§‡āĻŦ āĻĒā§ƒāĻˇā§āĻ āĻžāĻ—ā§āĻ˛āĻŋ āĻ˛ā§‡āĻ¨āĻĻā§‡āĻ¨ā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻāĻ•āĻŸāĻŋ āĻ¸ā§āĻŦāĻžāĻ•ā§āĻˇāĻ°ā§‡āĻ° āĻ…āĻ¨ā§āĻ°ā§‹āĻ§ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡:

āĻāĻ•āĻŸāĻŋ āĻ¨āĻŋāĻ°āĻžāĻĒāĻĻ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ˛ā§‡āĻ–āĻž

āĻāĻ•āĻŸāĻŋ āĻ¨āĻŋāĻ°āĻžāĻĒāĻĻ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ˛ā§‡āĻ–āĻž

āĻ•ā§‹āĻĄ āĻāĻ–āĻžāĻ¨ā§‡ āĻ‰āĻĒāĻ˛āĻŦā§āĻ§ āĻ˛āĻŋāĻ‚āĻ•.

āĻ‰āĻĒāĻ¸āĻ‚āĻšāĻžāĻ°

āĻ†āĻĒāĻ¨āĻŋ āĻ¯āĻĻāĻŋ āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§āĻŸāĻŋ āĻļā§‡āĻˇ āĻĒāĻ°ā§āĻ¯āĻ¨ā§āĻ¤ āĻĒāĻĄāĻŧā§‡ āĻĨāĻžāĻ•ā§‡āĻ¨, āĻ•āĻŋāĻ¨ā§āĻ¤ā§ āĻāĻ–āĻ¨āĻ“ āĻĒā§āĻ°āĻļā§āĻ¨ āĻĨāĻžāĻ•ā§‡, āĻ†āĻĒāĻ¨āĻŋ āĻ¤āĻžāĻĻā§‡āĻ° āĻœāĻŋāĻœā§āĻžāĻžāĻ¸āĻž āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨ āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻ¸āĻš āĻ¸āĻ‚āĻ—ā§āĻ°āĻšāĻ¸ā§āĻĨāĻ˛. āĻ¸ā§‡āĻ–āĻžāĻ¨ā§‡ āĻ†āĻĒāĻ¨āĻŋ āĻĒā§āĻ°āĻ¤āĻŋāĻŸāĻŋ āĻŽāĻ¨ā§‹āĻ¨ā§€āĻ¤ āĻĒāĻĻāĻ•ā§āĻˇā§‡āĻĒā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻĒā§āĻ°āĻ¤āĻŋāĻļā§āĻ°ā§āĻ¤āĻŋāĻ“ āĻĒāĻžāĻŦā§‡āĻ¨āĨ¤

āĻāĻŦāĻ‚ āĻ†āĻĒāĻ¨āĻŋ āĻ¯āĻĻāĻŋ āĻĒā§āĻ°āĻ•ā§ƒāĻ¤ āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻ•ā§‹āĻĄāĻŸāĻŋ āĻĻā§‡āĻ–āĻ¤ā§‡ āĻ†āĻ—ā§āĻ°āĻšā§€ āĻšāĻ¨ āĻ¤āĻŦā§‡ āĻ†āĻĒāĻ¨āĻŋ āĻāĻŸāĻŋ āĻ–ā§āĻāĻœā§‡ āĻĒā§‡āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨ āĻāĻ–āĻžāĻ¨ā§‡.

āĻĨā§‡āĻ•ā§‡ āĻ•ā§‹āĻĄ, āĻ­āĻžāĻ¨ā§āĻĄāĻžāĻ° āĻāĻŦāĻ‚ āĻ•āĻžāĻœā§‡āĻ° āĻŦāĻŋāĻŦāĻ°āĻŖ āĻ¸āĻŋāĻŽāĻžāĻ°ā§‡āĻ˛

āĻ‰āĻ¤ā§āĻ¸: www.habr.com

āĻāĻ•āĻŸāĻŋ āĻŽāĻ¨ā§āĻ¤āĻŦā§āĻ¯ āĻœā§āĻĄāĻŧā§āĻ¨