เจ‡เฉฑเจ• เจธเฉเจฐเฉฑเจ–เจฟเจ…เจค เจฌเจฐเจพเจŠเจœเจผเจฐ เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจ เจฒเจฟเจ–เจฃเจพ

เจ‡เฉฑเจ• เจธเฉเจฐเฉฑเจ–เจฟเจ…เจค เจฌเจฐเจพเจŠเจœเจผเจฐ เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจ เจฒเจฟเจ–เจฃเจพ

เจ†เจฎ "เจ•เจฒเจพเจ‡เฉฐเจŸ-เจธเจฐเจตเจฐ" เจ†เจฐเจ•เฉ€เจŸเฉˆเจ•เจšเจฐ เจฆเฉ‡ เจ‰เจฒเจŸ, เจตเจฟเจ•เฉ‡เจ‚เจฆเจฐเฉ€เจ•เฉเจฐเจฟเจค เจเจชเจฒเฉ€เจ•เฉ‡เจธเจผเจจเจพเจ‚ เจฆเฉ€ เจตเจฟเจธเจผเฉ‡เจธเจผเจคเจพ เจนเฉˆ:

  • เจ‰เจชเจญเฉ‹เจ—เจคเจพ เจฒเฉŒเจ—เจฟเจจ เจ…เจคเฉ‡ เจชเจพเจธเจตเจฐเจกเจพเจ‚ เจฆเฉ‡ เจจเจพเจฒ เจ‡เฉฑเจ• เจกเฉ‡เจŸเจพเจฌเฉ‡เจธ เจจเฉ‚เฉฐ เจธเจŸเฉ‹เจฐ เจ•เจฐเจจ เจฆเฉ€ เจ•เฉ‹เจˆ เจฒเฉ‹เฉœ เจจเจนเฉ€เจ‚ เจนเฉˆ. เจชเจนเฉเฉฐเจš เจœเจพเจฃเจ•เจพเจฐเฉ€ เจจเฉ‚เฉฐ เจธเจฟเจฐเจซเจผ เจ‰เจชเจญเฉ‹เจ—เจคเจพเจตเจพเจ‚ เจฆเฉเจ†เจฐเจพ เจนเฉ€ เจธเจŸเฉ‹เจฐ เจ•เฉ€เจคเจพ เจœเจพเจ‚เจฆเจพ เจนเฉˆ, เจ…เจคเฉ‡ เจ‰เจนเจจเจพเจ‚ เจฆเฉ€ เจชเฉเจฐเจฎเจพเจฃเจฟเจ•เจคเจพ เจฆเฉ€ เจชเฉเจธเจผเจŸเฉ€ เจชเฉเจฐเฉ‹เจŸเฉ‹เจ•เฉ‹เจฒ เจชเฉฑเจงเจฐ 'เจคเฉ‡ เจนเฉเฉฐเจฆเฉ€ เจนเฉˆเฅค
  • เจธเจฐเจตเจฐ เจตเจฐเจคเจฃ เจฆเฉ€ เจ•เฉ‹เจˆ เจฒเฉ‹เฉœ เจจเจนเฉ€เจ‚เฅค เจเจชเจฒเฉ€เจ•เฉ‡เจธเจผเจจ เจคเจฐเจ• เจจเฉ‚เฉฐ เจ‡เฉฑเจ• เจฌเจฒเจพเจ•เจšเฉˆเจจ เจจเฉˆเจŸเจตเจฐเจ• เจคเฉ‡ เจšเจฒเจพเจ‡เจ† เจœเจพ เจธเจ•เจฆเจพ เจนเฉˆ, เจœเจฟเฉฑเจฅเฉ‡ เจฒเฉ‹เฉœเฉ€เจ‚เจฆเฉ€ เจฎเจพเจคเจฐเจพ เจตเจฟเฉฑเจš เจกเฉ‡เจŸเจพ เจจเฉ‚เฉฐ เจธเจŸเฉ‹เจฐ เจ•เจฐเจจเจพ เจธเฉฐเจญเจต เจนเฉˆเฅค

เจ‰เจชเจญเฉ‹เจ—เจคเจพ เจ•เฉเฉฐเจœเฉ€เจ†เจ‚ เจฒเจˆ 2 เจฎเฉเจ•เจพเจฌเจฒเจคเจจ เจธเฉเจฐเฉฑเจ–เจฟเจ…เจค เจธเจŸเฉ‹เจฐเฉ‡เจœ เจนเจจ - เจนเจพเจฐเจกเจตเฉ‡เจ…เจฐ เจตเจพเจฒเจฟเจŸ เจ…เจคเฉ‡ เจฌเฉเจฐเจพเจŠเจœเจผเจฐ เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจเฅค เจนเจพเจฐเจกเจตเฉ‡เจ…เจฐ เจตเจพเจฒเจฟเจŸ เจœเจผเจฟเจ†เจฆเจพเจคเจฐ เจฌเจนเฉเจค เจธเฉเจฐเฉฑเจ–เจฟเจ…เจค เจนเฉเฉฐเจฆเฉ‡ เจนเจจ, เจชเจฐ เจตเจฐเจคเจฃ เจตเจฟเฉฑเจš เจฎเฉเจธเจผเจ•เจฒ เจนเฉเฉฐเจฆเฉ‡ เจนเจจ เจ…เจคเฉ‡ เจฎเฉเจซเจค เจคเฉ‹เจ‚ เจฆเฉ‚เจฐ เจนเฉเฉฐเจฆเฉ‡ เจนเจจ, เจชเจฐ เจฌเฉเจฐเจพเจŠเจœเจผเจฐ เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจ เจธเฉเจฐเฉฑเจ–เจฟเจ† เจ…เจคเฉ‡ เจตเจฐเจคเฉ‹เจ‚ เจตเจฟเฉฑเจš เจ†เจธเจพเจจเฉ€ เจฆเจพ เจธเฉฐเจชเฉ‚เจฐเจจ เจธเฉเจฎเฉ‡เจฒ เจนเจจ, เจ…เจคเฉ‡ เจ…เฉฐเจคเจฎ เจ‰เจชเจญเฉ‹เจ—เจคเจพเจตเจพเจ‚ เจฒเจˆ เจชเฉ‚เจฐเฉ€ เจคเจฐเฉเจนเจพเจ‚ เจฎเฉเจซเจค เจตเฉ€ เจนเฉ‹ เจธเจ•เจฆเฉ‡ เจนเจจเฅค

เจ‡เจธ เจธเจญ เจจเฉ‚เฉฐ เจงเจฟเจ†เจจ เจตเจฟเฉฑเจš เจฐเฉฑเจ–เจฆเฉ‡ เจนเฉ‹เจ, เจ…เจธเฉ€เจ‚ เจธเจญ เจคเฉ‹เจ‚ เจธเฉเจฐเฉฑเจ–เจฟเจ…เจค เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจ เจฌเจฃเจพเจ‰เจฃเจพ เจšเจพเจนเฉเฉฐเจฆเฉ‡ เจธเฉ€ เจœเฉ‹ เจŸเฉเจฐเจพเจ‚เจœเฉˆเจ•เจธเจผเจจเจพเจ‚ เจ…เจคเฉ‡ เจฆเจธเจคเจ–เจคเจพเจ‚ เจจเจพเจฒ เจ•เฉฐเจฎ เจ•เจฐเจจ เจฒเจˆ เจ‡เฉฑเจ• เจธเจงเจพเจฐเจจ API เจชเฉเจฐเจฆเจพเจจ เจ•เจฐเจ•เฉ‡ เจตเจฟเจ•เฉ‡เจ‚เจฆเจฐเฉ€เจ•เฉเจฐเจฟเจค เจเจชเจฒเฉ€เจ•เฉ‡เจธเจผเจจเจพเจ‚ เจฆเฉ‡ เจตเจฟเจ•เจพเจธ เจจเฉ‚เฉฐ เจธเจฐเจฒ เจฌเจฃเจพเจ‰เจ‚เจฆเจพ เจนเฉˆเฅค
เจ…เจธเฉ€เจ‚ เจคเฉเจนเจพเจจเฉ‚เฉฐ เจนเฉ‡เจ เจพเจ‚ เจ‡เจธ เจ…เจจเฉเจญเจต เจฌเจพเจฐเฉ‡ เจฆเฉฑเจธเจพเจ‚เจ—เฉ‡เฅค

เจฒเฉ‡เจ– เจตเจฟเฉฑเจš เจ•เฉ‹เจก เจ‰เจฆเจพเจนเจฐเจจเจพเจ‚ เจ…เจคเฉ‡ เจธเจ•เฉเจฐเฉ€เจจเจธเจผเฉŒเจŸเจธ เจฆเฉ‡ เจจเจพเจฒ เจ‡เฉฑเจ• เจฌเฉเจฐเจพเจŠเจœเจผเจฐ เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจ เจ•เจฟเจตเฉ‡เจ‚ เจฒเจฟเจ–เจฃเจพ เจนเฉˆ เจ‡เจธ เจฌเจพเจฐเฉ‡ เจ•เจฆเจฎ-เจฆเจฐ-เจ•เจฆเจฎ เจจเจฟเจฐเจฆเฉ‡เจธเจผ เจธเจผเจพเจฎเจฒ เจนเฉ‹เจฃเจ—เฉ‡เฅค เจตเจฟเฉฑเจš เจคเฉเจธเฉ€เจ‚ เจธเจพเจฐเจพ เจ•เฉ‹เจก เจฒเฉฑเจญ เจธเจ•เจฆเฉ‡ เจนเฉ‹ เจฐเจฟเจชเฉ‹เจœเจผเจŸเจฐเฉ€เจ†เจ‚. เจนเจฐเฉ‡เจ• เจตเจšเจจเจฌเฉฑเจงเจคเจพ เจ‡เจธ เจฒเฉ‡เจ– เจฆเฉ‡ เจ‡เฉฑเจ• เจญเจพเจ— เจจเจพเจฒ เจฎเฉ‡เจฒ เจ–เจพเจ‚เจฆเฉ€ เจนเฉˆเฅค

เจฌเฉเจฐเจพเจŠเจœเจผเจฐ เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจเจพเจ‚ เจฆเจพ เจธเฉฐเจ–เฉ‡เจช เจ‡เจคเจฟเจนเจพเจธ

เจฌเฉเจฐเจพเจŠเจœเจผเจฐ เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจ เจฒเฉฐเจฌเฉ‡ เจธเจฎเฉ‡เจ‚ เจคเฉ‹เจ‚ เจ†เจฒเฉ‡-เจฆเฉเจ†เจฒเฉ‡ เจนเจจเฅค เจ‰เจน 1999 เจตเจฟเฉฑเจš เจ‡เฉฐเจŸเจฐเจจเฉˆเฉฑเจŸ เจเจ•เจธเจชเจฒเฉ‹เจฐเจฐ เจตเจฟเฉฑเจš, 2004 เจตเจฟเฉฑเจš เจซเจพเจ‡เจฐเจซเจพเจ•เจธ เจตเจฟเฉฑเจš เจชเฉเจฐเจ—เจŸ เจนเฉ‹เจเฅค เจนเจพเจฒเจพเจ‚เจ•เจฟ, เจฌเจนเฉเจค เจฒเฉฐเจฌเฉ‡ เจธเจฎเฉ‡เจ‚ เจฒเจˆ เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจเจพเจ‚ เจฒเจˆ เจ•เฉ‹เจˆ เจ‡เฉฑเจ• เจฎเจพเจชเจฆเฉฐเจก เจจเจนเฉ€เจ‚ เจธเฉ€.

เจ…เจธเฉ€เจ‚ เจ•เจนเจฟ เจธเจ•เจฆเฉ‡ เจนเจพเจ‚ เจ•เจฟ เจ‡เจน เจ—เฉ‚เจ—เจฒ เจ•เจฐเฉ‹เจฎ เจฆเฉ‡ เจšเฉŒเจฅเฉ‡ เจธเฉฐเจธเจ•เจฐเจฃ เจตเจฟเฉฑเจš เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจเจพเจ‚ เจฆเฉ‡ เจจเจพเจฒ เจชเฉเจฐเจ—เจŸ เจนเฉ‹เจ‡เจ† เจนเฉˆเฅค เจฌเฉ‡เจธเจผเฉฑเจ•, เจ‰เจฆเฉ‹เจ‚ เจ•เฉ‹เจˆ เจจเจฟเจฐเจงเจพเจฐเจจ เจจเจนเฉ€เจ‚ เจธเฉ€, เจชเจฐ เจ‡เจน เจ•เฉเจฐเฉ‹เจฎ API เจธเฉ€ เจœเฉ‹ เจ‡เจธเจฆเจพ เจ…เจงเจพเจฐ เจฌเจฃ เจ—เจฟเจ†: เจœเจผเจฟเจ†เจฆเจพเจคเจฐ เจฌเฉเจฐเจพเจŠเจœเจผเจฐ เจฎเจพเจฐเจ•เฉ€เจŸ เจจเฉ‚เฉฐ เจœเจฟเฉฑเจคเจฃ เจ…เจคเฉ‡ เจ‡เฉฑเจ• เจฌเจฟเจฒเจŸ-เจ‡เจจ เจเจชเจฒเฉ€เจ•เฉ‡เจธเจผเจจ เจธเจŸเฉ‹เจฐ เจนเฉ‹เจฃ เจฆเฉ‡ เจฌเจพเจ…เจฆ, เจ•เฉเจฐเฉ‹เจฎ เจจเฉ‡ เจ…เจธเจฒ เจตเจฟเฉฑเจš เจฌเฉเจฐเจพเจŠเจœเจผเจฐ เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจเจพเจ‚ เจฒเจˆ เจธเจŸเฉˆเจ‚เจกเจฐเจก เจธเฉˆเฉฑเจŸ เจ•เฉ€เจคเจพเฅค

เจฎเฉ‹เจœเจผเฉ€เจฒเจพ เจฆเจพ เจ†เจชเจฃเจพ เจธเจŸเฉˆเจ‚เจกเจฐเจก เจธเฉ€, เจชเจฐ เจ•เฉเจฐเฉ‹เจฎ เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจเจพเจ‚ เจฆเฉ€ เจชเฉเจฐเจธเจฟเฉฑเจงเฉ€ เจจเฉ‚เฉฐ เจฆเฉ‡เจ–เจฆเฉ‡ เจนเฉ‹เจ, เจ•เฉฐเจชเจจเฉ€ เจจเฉ‡ เจ‡เฉฑเจ• เจ…เจจเฉเจ•เฉ‚เจฒ API เจฌเจฃเจพเจ‰เจฃ เจฆเจพ เจซเฉˆเจธเจฒเจพ เจ•เฉ€เจคเจพเฅค 2015 เจตเจฟเฉฑเจš, เจฎเฉ‹เจœเจผเฉ€เจฒเจพ เจฆเฉ€ เจชเจนเจฟเจฒเจ•เจฆเจฎเฉ€ 'เจคเฉ‡, เจ•เจฐเจพเจธ-เจฌเฉเจฐเจพเจŠเจœเจผเจฐ เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจ เจตเจฟเจธเจผเฉ‡เจธเจผเจคเจพเจตเจพเจ‚ 'เจคเฉ‡ เจ•เฉฐเจฎ เจ•เจฐเจจ เจฒเจˆ เจตเจฐเจฒเจก เจตเจพเจˆเจก เจตเฉˆเฉฑเจฌ เจ•เฉฐเจธเฉ‹เจฐเจŸเฉ€เจ…เจฎ (W3C) เจฆเฉ‡ เจ…เฉฐเจฆเจฐ เจ‡เฉฑเจ• เจตเจฟเจธเจผเฉ‡เจธเจผ เจธเจฎเฉ‚เจน เจฌเจฃเจพเจ‡เจ† เจ—เจฟเจ† เจธเฉ€เฅค

Chrome เจฒเจˆ เจฎเฉŒเจœเฉ‚เจฆเจพ API เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจเจพเจ‚ เจจเฉ‚เฉฐ เจ†เจงเจพเจฐ เจตเจœเฉ‹เจ‚ เจฒเจฟเจ† เจ—เจฟเจ† เจธเฉ€เฅค เจ‡เจน เจ•เฉฐเจฎ เจฎเจพเจˆเจ•เจฐเฉ‹เจธเจพเจซเจŸ เจฆเฉ‡ เจธเจฎเจฐเจฅเจจ เจจเจพเจฒ เจ•เฉ€เจคเจพ เจ—เจฟเจ† เจธเฉ€ (เจ—เฉ‚เจ—เจฒ เจจเฉ‡ เจธเจŸเฉˆเจ‚เจกเจฐเจก เจฆเฉ‡ เจตเจฟเจ•เจพเจธ เจตเจฟเฉฑเจš เจนเจฟเฉฑเจธเจพ เจฒเฉˆเจฃ เจคเฉ‹เจ‚ เจ‡เจจเจ•เจพเจฐ เจ•เจฐ เจฆเจฟเฉฑเจคเจพ), เจ…เจคเฉ‡ เจจเจคเฉ€เจœเฉ‡ เจตเจœเฉ‹เจ‚ เจ‡เฉฑเจ• เจกเจฐเจพเจซเจŸ เจชเฉเจฐเจ—เจŸ เจนเฉ‹เจ‡เจ† เจจเจฟเจฐเจงเจพเจฐเจจ.

เจฐเจธเจฎเฉ€ เจคเฉŒเจฐ 'เจคเฉ‡, เจธเจชเฉˆเจธเฉ€เจซเจฟเจ•เฉ‡เจธเจผเจจ เจเจœ, เจซเจพเจ‡เจฐเจซเจพเจ•เจธ เจ…เจคเฉ‡ เจ“เจชเฉ‡เจฐเจพ เจฆเฉเจ†เจฐเจพ เจธเจฎเจฐเจฅเจฟเจค เจนเฉˆ (เจจเฉ‹เจŸ เจ•เจฐเฉ‹ เจ•เจฟ เจ•เฉเจฐเฉ‹เจฎ เจ‡เจธ เจธเฉ‚เจšเฉ€ เจตเจฟเฉฑเจš เจจเจนเฉ€เจ‚ เจนเฉˆ)เฅค เจชเจฐ เจตเจพเจธเจคเจต เจตเจฟเฉฑเจš, เจธเจŸเฉˆเจ‚เจกเจฐเจก เจตเฉฑเจกเฉ‡ เจชเฉฑเจงเจฐ 'เจคเฉ‡ Chrome เจจเจพเจฒ เจ…เจจเฉเจ•เฉ‚เจฒ เจนเฉˆ, เจ•เจฟเจ‰เจ‚เจ•เจฟ เจ‡เจน เจ…เจธเจฒ เจตเจฟเฉฑเจš เจ‡เจธเจฆเฉ‡ เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจเจพเจ‚ เจฆเฉ‡ เจ…เจงเจพเจฐ เจคเฉ‡ เจฒเจฟเจ–เจฟเจ† เจ—เจฟเจ† เจนเฉˆเฅค เจคเฉเจธเฉ€เจ‚ WebExtensions API เจฌเจพเจฐเฉ‡ เจนเฉ‹เจฐ เจชเฉœเฉเจน เจธเจ•เจฆเฉ‡ เจนเฉ‹ เจ‡เฉฑเจฅเฉ‡.

เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจ เจฌเจฃเจคเจฐ

เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจ เจฒเจˆ เจฒเฉ‹เฉœเฉ€เจ‚เจฆเฉ€ เจ•เฉ‡เจตเจฒ เจซเจพเจˆเจฒ เจฎเฉˆเจจเฉ€เจซเฉˆเจธเจŸ (manifest.json) เจนเฉˆเฅค เจ‡เจน เจตเจฟเจธเจฅเจพเจฐ เจฒเจˆ "เจเจ‚เจŸเจฐเฉ€ เจชเฉเจ†เจ‡เฉฐเจŸ" เจตเฉ€ เจนเฉˆเฅค

เจชเฉเจฐเจ—เจŸ

เจจเจฟเจฐเจงเจพเจฐเจจ เจฆเฉ‡ เจ…เจจเฉเจธเจพเจฐ, เจฎเฉˆเจจเฉ€เจซเฉˆเจธเจŸ เจซเจพเจˆเจฒ เจ‡เฉฑเจ• เจตเฉˆเจง JSON เจซเจพเจˆเจฒ เจนเฉˆเฅค เจฎเฉˆเจจเฉ€เจซเฉˆเจธเจŸ เจ•เฉเฉฐเจœเฉ€เจ†เจ‚ เจฆเจพ เจชเฉ‚เจฐเจพ เจตเฉ‡เจฐเจตเจพ เจ‡เจธ เจฌเจพเจฐเฉ‡ เจœเจพเจฃเจ•เจพเจฐเฉ€ เจฆเฉ‡ เจจเจพเจฒ เจ•เจฟ เจ•เจฟเจนเฉœเฉ€เจ†เจ‚ เจ•เฉเฉฐเจœเฉ€เจ†เจ‚ เจธเจฎเจฐเจฅเจฟเจค เจนเจจ เจœเจฟเจธ เจตเจฟเฉฑเจš เจฌเฉเจฐเจพเจŠเจœเจผเจฐ เจฆเฉ‡เจ–เจฟเจ† เจœเจพ เจธเจ•เจฆเจพ เจนเฉˆ เจ‡เฉฑเจฅเฉ‡.

เจ•เฉเฉฐเจœเฉ€เจ†เจ‚ เจœเฉ‹ เจจเจฟเจฐเจงเจพเจฐเจจ เจตเจฟเฉฑเจš เจจเจนเฉ€เจ‚ เจนเจจ "เจนเฉ‹ เจธเจ•เจฆเจพ เจนเฉˆ" เจจเฉ‚เฉฐ เจ…เจฃเจกเจฟเฉฑเจ  เจ•เฉ€เจคเจพ เจœเจพ เจธเจ•เจฆเจพ เจนเฉˆ (เจฆเฉ‹เจตเฉ‡เจ‚ เจ•เจฐเฉ‹เจฎ เจ…เจคเฉ‡ เจซเจพเจ‡เจฐเจซเจพเจ•เจธ เจฐเจฟเจชเฉ‹เจฐเจŸ เจฆเฉ€เจ†เจ‚ เจคเจฐเฉเฉฑเจŸเฉ€เจ†เจ‚, เจชเจฐ เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจ เจ•เฉฐเจฎ เจ•เจฐเจจเจพ เจœเจพเจฐเฉ€ เจฐเฉฑเจ–เจฆเฉ‡ เจนเจจ)เฅค

เจ…เจคเฉ‡ เจฎเฉˆเจ‚ เจ•เฉเจ เจจเฉเจ•เจคเจฟเจ†เจ‚ เจตเฉฑเจฒ เจงเจฟเจ†เจจ เจ–เจฟเฉฑเจšเจฃเจพ เจšเจพเจนเจพเจ‚เจ—เจพเฅค

  1. เจชเจฟเจ›เฉ‹เจ•เฉœ โ€” เจ‡เฉฑเจ• เจตเจธเจคเฉ‚ เจœเจฟเจธ เจตเจฟเฉฑเจš เจนเฉ‡เจ เจพเจ‚ เจฆเจฟเฉฑเจคเฉ‡ เจ–เฉ‡เจคเจฐ เจธเจผเจพเจฎเจฒ เจนเจจ:
    1. เจธเจ•เฉเจฐเจฟเจชเจŸเจพเจ‚ โ€” เจธเจ•เฉเจฐเจฟเจชเจŸเจพเจ‚ เจฆเจพ เจ‡เฉฑเจ• เจเจฐเฉ‡ เจœเฉ‹ เจฌเฉˆเจ•เจ—เฉเจฐเจพเจ‰เจ‚เจก เจธเฉฐเจฆเจฐเจญ เจตเจฟเฉฑเจš เจšเจฒเจพเจ‡เจ† เจœเจพเจตเฉ‡เจ—เจพ (เจ…เจธเฉ€เจ‚ เจ‡เจธ เจฌเจพเจฐเฉ‡ เจฅเฉ‹เฉœเฉเจนเฉ€ เจฆเฉ‡เจฐ เจฌเจพเจ…เจฆ เจ—เฉฑเจฒ เจ•เจฐเจพเจ‚เจ—เฉ‡);
    2. เจชเฉฐเจจเจพ - เจธเจ•เฉเจฐเจฟเจชเจŸเจพเจ‚ เจฆเฉ€ เจฌเจœเจพเจ เจœเฉ‹ เจ‡เฉฑเจ• เจ–เจพเจฒเฉ€ เจชเฉฐเจจเฉ‡ เจตเจฟเฉฑเจš เจšเจฒเจพเจˆเจ†เจ‚ เจœเจพเจฃเจ—เฉ€เจ†เจ‚, เจคเฉเจธเฉ€เจ‚ เจธเจฎเฉฑเจ—เจฐเฉ€ เจฆเฉ‡ เจจเจพเจฒ html เจจเจฟเจธเจผเจšเจฟเจค เจ•เจฐ เจธเจ•เจฆเฉ‡ เจนเฉ‹เฅค เจ‡เจธ เจธเจฅเจฟเจคเฉ€ เจตเจฟเฉฑเจš, เจธเจ•เฉเจฐเจฟเจชเจŸ เจ–เฉ‡เจคเจฐ เจจเฉ‚เฉฐ เจ…เจฃเจกเจฟเฉฑเจ  เจ•เฉ€เจคเจพ เจœเจพเจตเฉ‡เจ—เจพ, เจ…เจคเฉ‡ เจธเจ•เฉเจฐเจฟเจชเจŸเจพเจ‚ เจจเฉ‚เฉฐ เจธเจฎเฉฑเจ—เจฐเฉ€ เจชเฉฐเจจเฉ‡ เจตเจฟเฉฑเจš เจธเจผเจพเจฎเจฒ เจ•เจฐเจจ เจฆเฉ€ เจฒเฉ‹เฉœ เจนเฉ‹เจตเฉ‡เจ—เฉ€;
    3. เจœเจพเจฐเฉ€ - เจ‡เฉฑเจ• เจฌเจพเจˆเจจเจฐเฉ€ เจซเจฒเฉˆเจ—, เจœเฉ‡เจ•เจฐ เจจเจฟเจฐเจงเจพเจฐเจค เจจเจนเฉ€เจ‚ เจ•เฉ€เจคเจพ เจ—เจฟเจ† เจนเฉˆ, เจคเจพเจ‚ เจฌเฉเจฐเจพเจŠเจœเจผเจฐ เจฌเฉˆเจ•เจ—เฉเจฐเจพเจ‰เจ‚เจก เจชเฉเจฐเจ•เจฟเจฐเจฟเจ† เจจเฉ‚เฉฐ "เจฎเจพเจฐ" เจฆเฉ‡เจตเฉ‡เจ—เจพ เจœเจฆเฉ‹เจ‚ เจ‡เจน เจธเจฎเจเจฆเจพ เจนเฉˆ เจ•เจฟ เจ‡เจน เจ•เฉเจ เจจเจนเฉ€เจ‚ เจ•เจฐ เจฐเจฟเจนเจพ เจนเฉˆ, เจ…เจคเฉ‡ เจœเฉ‡ เจฒเฉ‹เฉœ เจนเฉ‹เจตเฉ‡ เจคเจพเจ‚ เจ‡เจธเจจเฉ‚เฉฐ เจฎเฉเฉœ เจšเจพเจฒเฉ‚ เจ•เจฐ เจฆเฉ‡เจตเฉ‡เจ—เจพเฅค เจจเจนเฉ€เจ‚ เจคเจพเจ‚, เจฌเฉเจฐเจพเจŠเจœเจผเจฐ เจฌเฉฐเจฆ เจนเฉ‹เจฃ 'เจคเฉ‡ เจนเฉ€ เจชเฉฐเจจเจพ เจ…เจจเจฒเฉ‹เจก เจ•เฉ€เจคเจพ เจœเจพเจตเฉ‡เจ—เจพเฅค เจซเจพเจ‡เจฐเจซเจพเจ•เจธ เจตเจฟเฉฑเจš เจธเจฎเจฐเจฅเจฟเจค เจจเจนเฉ€เจ‚ เจนเฉˆเฅค
  2. เจธเจฎเฉฑเจ—เจฐเฉ€_เจธเจ•เฉเจฐเจฟเจชเจŸเจพเจ‚ โ€” เจตเจธเจคเฉ‚เจ†เจ‚ เจฆเฉ€ เจ‡เฉฑเจ• เจฒเฉœเฉ€ เจœเฉ‹ เจคเฉเจนเจพเจจเฉ‚เฉฐ เจตเฉฑเจ–-เจตเฉฑเจ– เจตเฉˆเฉฑเจฌ เจชเฉฐเจจเจฟเจ†เจ‚ 'เจคเฉ‡ เจตเฉฑเจ–-เจตเฉฑเจ– เจธเจ•เฉเจฐเจฟเจชเจŸเจพเจ‚ เจจเฉ‚เฉฐ เจฒเฉ‹เจก เจ•เจฐเจจ เจฆเฉ€ เจ‡เจœเจพเจœเจผเจค เจฆเจฟเฉฐเจฆเฉ€ เจนเฉˆเฅค เจนเจฐเฉ‡เจ• เจตเจธเจคเฉ‚ เจตเจฟเฉฑเจš เจนเฉ‡เจ  เจฒเจฟเจ–เฉ‡ เจฎเจนเฉฑเจคเจตเจชเฉ‚เจฐเจจ เจ–เฉ‡เจคเจฐ เจนเฉเฉฐเจฆเฉ‡ เจนเจจ:
    1. เจฎเฉˆเจš - เจชเฉˆเจŸเจฐเจจ url, เจœเฉ‹ เจ‡เจน เจจเจฟเจฐเจงเจพเจฐเจค เจ•เจฐเจฆเจพ เจนเฉˆ เจ•เจฟ เจ•เฉ€ เจ‡เฉฑเจ• เจ–เจพเจธ เจธเจฎเฉฑเจ—เจฐเฉ€ เจธเจ•เฉเจฐเจฟเจชเจŸ เจธเจผเจพเจฎเจฒ เจ•เฉ€เจคเฉ€ เจœเจพเจตเฉ‡เจ—เฉ€ เจœเจพเจ‚ เจจเจนเฉ€เจ‚เฅค
    2. js โ€” เจธเจ•เฉเจฐเจฟเจชเจŸเจพเจ‚ เจฆเฉ€ เจ‡เฉฑเจ• เจธเฉ‚เจšเฉ€ เจœเฉ‹ เจ‡เจธ เจฎเฉˆเจš เจตเจฟเฉฑเจš เจฒเฉ‹เจก เจ•เฉ€เจคเฉ€เจ†เจ‚ เจœเจพเจฃเจ—เฉ€เจ†เจ‚;
    3. exclude_maches - เจ–เฉ‡เจคเจฐ เจคเฉ‹เจ‚ เจฌเจพเจนเจฐ เจฐเฉฑเจ–เจฟเจ† เจ—เจฟเจ† เจนเฉˆ match URL เจœเฉ‹ เจ‡เจธ เจ–เฉ‡เจคเจฐ เจจเจพเจฒ เจฎเฉ‡เจฒ เจ–เจพเจ‚เจฆเฉ‡ เจนเจจเฅค
  3. เจชเฉฐเจจเจพ_เจ•เจพเจฐเจตเจพเจˆ - เจ…เจธเจฒ เจตเจฟเฉฑเจš เจ‡เฉฑเจ• เจตเจธเจคเฉ‚ เจนเฉˆ เจœเฉ‹ เจ†เจˆเจ•เจจ เจฒเจˆ เจœเจผเจฟเฉฐเจฎเฉ‡เจตเจพเจฐ เจนเฉˆ เจœเฉ‹ เจฌเฉเจฐเจพเจŠเจœเจผเจฐ เจตเจฟเฉฑเจš เจเจกเจฐเฉˆเฉฑเจธ เจฌเจพเจฐ เจฆเฉ‡ เจ…เฉฑเจ—เฉ‡ เจชเฉเจฐเจฆเจฐเจธเจผเจฟเจค เจนเฉเฉฐเจฆเจพ เจนเฉˆ เจ…เจคเฉ‡ เจ‡เจธเจฆเฉ‡ เจจเจพเจฒ เจชเจฐเจธเจชเจฐ เจชเฉเจฐเจญเจพเจต เจนเฉเฉฐเจฆเจพ เจนเฉˆเฅค เจ‡เจน เจคเฉเจนเจพเจจเฉ‚เฉฐ เจ‡เฉฑเจ• เจชเฉŒเจชเจ…เฉฑเจช เจตเจฟเฉฐเจกเฉ‹ เจชเฉเจฐเจฆเจฐเจธเจผเจฟเจค เจ•เจฐเจจ เจฆเฉ€ เจตเฉ€ เจ‡เจœเจพเจœเจผเจค เจฆเจฟเฉฐเจฆเจพ เจนเฉˆ, เจœเฉ‹ เจคเฉเจนเจพเจกเฉ‡ เจ†เจชเจฃเฉ‡ HTML, CSS เจ…เจคเฉ‡ JS เจฆเฉ€ เจตเจฐเจคเฉ‹เจ‚ เจ•เจฐเจ•เฉ‡ เจชเจฐเจฟเจญเจพเจธเจผเจฟเจค เจ•เฉ€เจคเจพ เจ—เจฟเจ† เจนเฉˆเฅค
    1. default_popup - เจชเฉŒเจชเจ…เฉฑเจช เจ‡เฉฐเจŸเจฐเจซเฉ‡เจธ เจจเจพเจฒ HTML เจซเจพเจˆเจฒ เจฆเจพ เจฎเจพเจฐเจ—, CSS เจ…เจคเฉ‡ JS เจนเฉ‹ เจธเจ•เจฆเจพ เจนเฉˆเฅค
  4. เจ…เจงเจฟเจ•เจพเจฐ โ€” เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจ เจ…เจงเจฟเจ•เจพเจฐเจพเจ‚ เจฆเฉ‡ เจชเฉเจฐเจฌเฉฐเจงเจจ เจฒเจˆ เจ‡เฉฑเจ• เจเจฐเฉ‡เฅค เจ…เจงเจฟเจ•เจพเจฐเจพเจ‚ เจฆเฉ€เจ†เจ‚ 3 เจ•เจฟเจธเจฎเจพเจ‚ เจนเจจ, เจœเจฟเจจเฉเจนเจพเจ‚ เจฆเจพ เจตเจฟเจธเจฅเจพเจฐ เจตเจฟเฉฑเจš เจตเจฐเจฃเจจ เจ•เฉ€เจคเจพ เจ—เจฟเจ† เจนเฉˆ เจ‡เฉฑเจฅเฉ‡
  5. เจตเฉˆเฉฑเจฌ_เจชเจนเฉเฉฐเจšเจฏเฉ‹เจ—_เจธเจฐเฉ‹เจค โ€” เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจ เจธเจฐเฉ‹เจค เจœเฉ‹ เจ‡เฉฑเจ• เจตเฉˆเฉฑเจฌ เจชเฉฐเจจเจพ เจฌเฉ‡เจจเจคเฉ€ เจ•เจฐ เจธเจ•เจฆเจพ เจนเฉˆ, เจ‰เจฆเจพเจนเจฐเจจ เจฒเจˆ, เจšเจฟเฉฑเจคเจฐ, JS, CSS, HTML เจซเจพเจˆเจฒเจพเจ‚เฅค
  6. externally_connectable โ€” เจ‡เฉฑเจฅเฉ‡ เจคเฉเจธเฉ€เจ‚ เจนเฉ‹เจฐ เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจเจพเจ‚ เจ…เจคเฉ‡ เจตเฉˆเจฌ เจชเฉ‡เจœเจพเจ‚ เจฆเฉ‡ เจกเฉ‹เจฎเฉ‡เจจเจพเจ‚ เจฆเฉ€ 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 เจœเฉ‹เฉœเจฆเฉ‡ เจนเจพเจ‚ - เจ…เจคเฉ‡ เจธเจพเจกเฉ€ เจเจชเจฒเฉ€เจ•เฉ‡เจธเจผเจจ เจชเจนเจฟเจฒเจพเจ‚ เจนเฉ€ เจ—เฉ‚เจ—เจฒ เจ•เจฐเฉ‹เจฎ เจตเจฟเฉฑเจš เจฒเฉ‹เจก เจ•เฉ€เจคเฉ€ เจœเจพ เจธเจ•เจฆเฉ€ เจนเฉˆ เจ…เจคเฉ‡ เจ‡เจน เจฏเจ•เฉ€เจจเฉ€ เจฌเจฃเจพเจ‰เจ‚เจฆเฉ€ เจนเฉˆ เจ•เจฟ เจ‡เจน เจ•เฉฐเจฎ เจ•เจฐเจฆเจพ เจนเฉˆเฅค

เจ‡เจธเจฆเฉ€ เจชเฉเจธเจผเจŸเฉ€ เจ•เจฐเจจ เจฒเจˆ, เจคเฉเจธเฉ€เจ‚ เจ•เฉ‹เจก เจฒเฉˆ เจธเจ•เจฆเฉ‡ เจนเฉ‹ เจ‡เฉฑเจฅเฉ‹เจ‚. เจ…เจธเฉ€เจ‚ เจœเฉ‹ เจ•เฉ€เจคเจพ เจ‰เจธ เจคเฉ‹เจ‚ เจ‡เจฒเจพเจตเจพ, เจฒเจฟเฉฐเจ• เจจเฉ‡ เจตเฉˆเจฌเจชเฉˆเจ• เจฆเฉ€ เจตเจฐเจคเฉ‹เจ‚ เจ•เจฐเจ•เฉ‡ เจชเฉเจฐเฉ‹เจœเฉˆเจ•เจŸ เจฆเฉ€ เจ…เจธเฉˆเจ‚เจฌเจฒเฉ€ เจจเฉ‚เฉฐ เจ•เฉŒเจ‚เจซเจฟเจ—เจฐ เจ•เฉ€เจคเจพเฅค เจฌเฉเจฐเจพเจ‰เจœเจผเจฐ เจตเจฟเฉฑเจš เจ‡เฉฑเจ• เจเจชเจฒเฉ€เจ•เฉ‡เจธเจผเจจ เจœเฉ‹เฉœเจจ เจฒเจˆ, chrome://extensions เจตเจฟเฉฑเจš เจคเฉเจนเจพเจจเฉ‚เฉฐ เจฒเฉ‹เจก เจ…เจจเจชเฉˆเจ•เจก เจ…เจคเฉ‡ เจธเฉฐเจฌเฉฐเจงเจฟเจค เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจ เจตเจพเจฒเจพ เจซเฉ‹เจฒเจกเจฐ เจšเฉเจฃเจจ เจฆเฉ€ เจฒเฉ‹เฉœ เจนเฉˆ - เจธเจพเจกเฉ‡ เจ•เฉ‡เจธ เจตเจฟเฉฑเจš เจœเจฟเจฒเจพ.

เจ‡เฉฑเจ• เจธเฉเจฐเฉฑเจ–เจฟเจ…เจค เจฌเจฐเจพเจŠเจœเจผเจฐ เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจ เจฒเจฟเจ–เจฃเจพ

เจนเฉเจฃ เจธเจพเจกเจพ เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจ เจธเจฅเจพเจชเจฟเจค เจ…เจคเฉ‡ เจ•เฉฐเจฎ เจ•เจฐ เจฐเจฟเจนเจพ เจนเฉˆเฅค เจคเฉเจธเฉ€เจ‚ เจนเฉ‡เจ เจพเจ‚ เจฆเจฟเฉฑเจคเฉ‡ เจ…เจจเฉเจธเจพเจฐ เจตเฉฑเจ–-เจตเฉฑเจ– เจธเฉฐเจฆเจฐเจญเจพเจ‚ เจฒเจˆ เจกเจฟเจตเฉˆเจฒเจชเจฐ เจŸเฉ‚เจฒ เจšเจฒเจพ เจธเจ•เจฆเฉ‡ เจนเฉ‹:

เจชเฉŒเจชเจ…เฉฑเจช ->

เจ‡เฉฑเจ• เจธเฉเจฐเฉฑเจ–เจฟเจ…เจค เจฌเจฐเจพเจŠเจœเจผเจฐ เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจ เจฒเจฟเจ–เจฃเจพ

เจธเจฎเฉฑเจ—เจฐเฉ€ เจธเจ•เฉเจฐเจฟเจชเจŸ เจ•เฉฐเจธเฉ‹เจฒ เจคเฉฑเจ• เจชเจนเฉเฉฐเจš เจ‰เจธ เจชเฉฐเจจเฉ‡ เจฆเฉ‡ เจ•เฉฐเจธเฉ‹เจฒ เจฆเฉเจ†เจฐเจพ เจ•เฉ€เจคเฉ€ เจœเจพเจ‚เจฆเฉ€ เจนเฉˆ เจœเจฟเจธ 'เจคเฉ‡ เจ‡เจน เจฒเจพเจ‚เจš เจ•เฉ€เจคเจพ เจ—เจฟเจ† เจนเฉˆเฅคเจ‡เฉฑเจ• เจธเฉเจฐเฉฑเจ–เจฟเจ…เจค เจฌเจฐเจพเจŠเจœเจผเจฐ เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจ เจฒเจฟเจ–เจฃเจพ

เจธเฉเจจเฉ‡เจนเฉ‡ เจฆเจพ เจ†เจฆเจพเจจ เจชเฉเจฐเจฆเจพเจจ

เจ‡เจธ เจฒเจˆ, เจธเจพเจจเฉ‚เฉฐ เจฆเฉ‹ เจธเฉฐเจšเจพเจฐ เจšเฉˆเจจเจฒ เจธเจฅเจพเจชเจค เจ•เจฐเจจ เจฆเฉ€ เจฒเฉ‹เฉœ เจนเฉˆ: inpage <-> เจฌเฉˆเจ•เจ—เจฐเจพเจŠเจ‚เจก เจ…เจคเฉ‡ เจชเฉŒเจชเจ…เฉฑเจช <-> เจฌเฉˆเจ•เจ—เจฐเจพเจŠเจ‚เจกเฅค เจคเฉเจธเฉ€เจ‚, เจฌเฉ‡เจธเจผเฉฑเจ•, เจธเจฟเจฐเจซเจผ เจชเฉ‹เจฐเจŸ เจจเฉ‚เฉฐ เจธเฉเจจเฉ‡เจนเฉ‡ เจญเฉ‡เจœ เจธเจ•เจฆเฉ‡ เจนเฉ‹ เจ…เจคเฉ‡ เจ†เจชเจฃเฉ‡ เจ–เฉเจฆ เจฆเฉ‡ เจชเฉเจฐเฉ‹เจŸเฉ‹เจ•เฉ‹เจฒ เจฆเฉ€ เจ–เฉ‹เจœ เจ•เจฐ เจธเจ•เจฆเฉ‡ เจนเฉ‹, เจชเจฐ เจฎเฉˆเจ‚ เจ‰เจธ เจชเจนเฉเฉฐเจš เจจเฉ‚เฉฐ เจคเจฐเจœเฉ€เจน เจฆเจฟเฉฐเจฆเจพ เจนเจพเจ‚ เจœเฉ‹ เจฎเฉˆเจ‚ เจฎเฉˆเจŸเจพเจฎเจพเจธเจ• เจ“เจชเจจ เจธเฉ‹เจฐเจธ เจชเฉเจฐเฉ‹เจœเฉˆเจ•เจŸ เจตเจฟเฉฑเจš เจฆเฉ‡เจ–เจฟเจ† เจธเฉ€เฅค

เจ‡เจน 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 เจ†เจฌเจœเฉˆเจ•เจŸ เจฌเจฃเจพเจเจ—เจพ, เจ…เจคเฉ‡ เจ‰เจนเจจเจพเจ‚ เจฒเจˆ เจ‡เฉฑเจ• เจกเฉ€เจจเฉ‹เจก เจฌเจฃเจพเจเจ—เจพ:

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 เจตเจฟเฉฑเจš เจ•เจพเจฒเจฌเฉˆเจ• เจซเฉฐเจ•เจธเจผเจจเจพเจ‚ เจจเจพเจฒ เจ•เฉฐเจฎ เจ•เจฐเจจเจพ เจฎเจพเฉœเจพ เจตเจฟเจตเจนเจพเจฐ เจนเฉˆ, เจ‡เจธเจฒเจˆ เจ†เจ“ เจ‡เฉฑเจ• เจกเฉ€เจจเฉ‹เจก เจฌเจฃเจพเจ‰เจฃ เจฒเจˆ เจ‡เฉฑเจ• เจ›เฉ‹เจŸเจพ เจธเจนเจพเจ‡เจ• เจฒเจฟเจ–เฉ€เจ เจœเฉ‹ เจคเฉเจนเจพเจจเฉ‚เฉฐ เจ‰เจชเจฏเฉ‹เจ—เจคเจพเจตเจพเจ‚ เจตเจฟเฉฑเจš เจ‡เฉฑเจ• 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 เจฌเจฃเจพ เจธเจ•เจฆเฉ‡ เจนเจพเจ‚เฅค เจธเจฟเจงเจพเจ‚เจค เจตเจฟเฉฑเจš, เจกเจจเฉ‹เจก เจจเฉ‚เฉฐ เจ•เจฟเจคเฉ‡ เจตเฉ€ เจตเจฐเจคเจฟเจ† เจœเจพ เจธเจ•เจฆเจพ เจนเฉˆ, เจฎเฉเฉฑเจ– เจ—เฉฑเจฒ เจ‡เจน เจนเฉˆ เจ•เจฟ เจจเฉ‹เจกเจœเจผ เจธเจŸเฉเจฐเฉ€เจฎ เจฆเฉ‡ เจฐเฉ‚เจช เจตเจฟเฉฑเจš เจŸเฉเจฐเจพเจ‚เจธเจชเฉ‹เจฐเจŸ เจจเฉ‚เฉฐ เจธเจฎเฉ‡เจŸเจฃเจพ.

เจ‡เฉฑเจ• เจตเจฟเจ•เจฒเจช 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. เจ‡เจจเจซเฉ‹เจฐเจธ เจเจ•เจธเจผเจจ เจซเจฒเฉˆเจ— เจฆเฉ‡ เจจเจพเจฒ เจธเจ–เจค เจฎเฉ‹เจก เจตเจฟเฉฑเจš, 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. เจ‡เฉฑเจ• เจนเฉˆเจ‚เจกเจฒเจฐ เจœเจฟเจธเจจเฉ‚เฉฐ เจนเจฐ เจตเจพเจฐ เจ‡เจธ เจฆเฉ‡ เจฌเจฆเจฒเจฃ 'เจคเฉ‡ เจ‡เจธ เจกเฉ‡เจŸเจพ เจจเจพเจฒ เจฌเฉเจฒเจพเจ‡เจ† เจœเจพเจตเฉ‡เจ—เจพเฅค

redux เจฆเฉ‡ เจ‰เจฒเจŸ, เจœเจฟเฉฑเจฅเฉ‡ เจ…เจธเฉ€เจ‚ เจธเจชเฉฑเจธเจผเจŸ เจคเฉŒเจฐ 'เจคเฉ‡ เจ‡เฉฑเจ• เจฆเจฒเฉ€เจฒ เจฆเฉ‡ เจคเฉŒเจฐ 'เจคเฉ‡ เจธเจฅเจฟเจคเฉ€ เจจเฉ‚เฉฐ เจชเฉเจฐเจพเจชเจค เจ•เจฐเจฆเฉ‡ เจนเจพเจ‚, 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 เจ•เฉ‹เจฒ เจนเฉเจฃ เจธเจŸเฉ‹เจฐเฉ‡เจœเจผ เจธเจผเฉเจฐเฉ‚ เจ•เจฐเจจ เจฒเจˆ เจ‡เฉฑเจ• เจขเฉฐเจ— เจนเฉˆเฅค

เจเจจเจ•เฉเจฐเจฟเจชเจธเจผเจจ เจฒเจˆ เจฒเจฟเจ–เจฟเจ† เจ—เจฟเจ† crypto-js เจฆเฉ€ เจตเจฐเจคเฉ‹เจ‚ เจ•เจฐเจฆเฉ‡ เจนเฉ‹เจ เจ‰เจชเจฏเฉ‹เจ—เจคเจพเจตเจพเจ‚:

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 เจตเจฟเฉฑเจš เจจเจตเจพเจ‚ เจธเฉเจจเฉ‡เจนเจพ:

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 เจธเจŸเฉ‡เจŸ เจ…เจคเฉ‡ API เจตเจฟเฉฑเจš เจ‡เฉฑเจ• เจซเฉฐเจ•เจธเจผเจจ เจœเฉ‹เฉœเฉ‹ เจœเฉ‹ เจ‡เจธ เจธเจฅเจฟเจคเฉ€ เจจเฉ‚เฉฐ เจฌเจฆเจฒ เจฆเฉ‡เจตเฉ‡เจ—เจพเฅค เจ†เจ“ เจœเฉ‹เฉœเฉ€เจ 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-เจชเฉเจฐเจคเฉ€เจ•เจฐเจฎ เจ•เฉฐเจชเฉ‹เจจเฉˆเจ‚เจŸ 'เจคเฉ‡, เจ…เจคเฉ‡ เจฐเฉˆเจ‚เจกเจฐ เจจเฉ‚เฉฐ เจ†เจŸเฉ‹เจฎเฉˆเจŸเจฟเจ• เจนเฉ€ เจ•เจพเจฒ เจ•เฉ€เจคเจพ เจœเจพเจตเฉ‡เจ—เจพ เจœเจฆเฉ‹เจ‚ เจ•เฉฐเจชเฉ‹เจจเฉˆเจ‚เจŸ เจฌเจฆเจฒเจพเจ… เจฆเฉเจ†เจฐเจพ เจนเจตเจพเจฒเจพ เจฆเจฟเฉฑเจคเจพ เจ—เจฟเจ† เจ•เฉ‹เจˆ เจตเฉ€ เจจเจฟเจฐเฉ€เจ–เจฃเจฏเฉ‹เจ—. เจคเฉเจนเจพเจจเฉ‚เฉฐ เจ•เจฟเจธเฉ‡ เจตเฉ€ เจฎเฉˆเจชเจธเจŸเฉ‡เจŸ เจŸเฉ‚เจชเฉเจฐเฉŒเจชเจธ เจœเจพเจ‚ 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}
    );

...
}

เจ‡เจธ เจฒเจˆ, เจเจชเจฒเฉ€เจ•เฉ‡เจธเจผเจจ เจคเจฟเจ†เจฐ เจนเฉˆ. เจตเฉˆเฉฑเจฌ เจชเฉฐเจจเฉ‡ เจฒเฉˆเจฃ-เจฆเฉ‡เจฃ เจฒเจˆ เจฆเจธเจคเจ–เจค เจฆเฉ€ เจฌเฉ‡เจจเจคเฉ€ เจ•เจฐ เจธเจ•เจฆเฉ‡ เจนเจจ:

เจ‡เฉฑเจ• เจธเฉเจฐเฉฑเจ–เจฟเจ…เจค เจฌเจฐเจพเจŠเจœเจผเจฐ เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจ เจฒเจฟเจ–เจฃเจพ

เจ‡เฉฑเจ• เจธเฉเจฐเฉฑเจ–เจฟเจ…เจค เจฌเจฐเจพเจŠเจœเจผเจฐ เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจ เจฒเจฟเจ–เจฃเจพ

เจ•เฉ‹เจก เจ‡เฉฑเจฅเฉ‡ เจ‰เจชเจฒเจฌเจง เจนเฉˆ เจฒเจฟเฉฐเจ• เจจเฉ‚เฉฐ.

เจธเจฟเฉฑเจŸเจพ

เจœเฉ‡เจ•เจฐ เจคเฉเจธเฉ€เจ‚ เจฒเฉ‡เจ– เจจเฉ‚เฉฐ เจ…เฉฐเจค เจคเฉฑเจ• เจชเฉœเฉเจน เจฒเจฟเจ† เจนเฉˆ, เจชเจฐ เจซเจฟเจฐ เจตเฉ€ เจธเจตเจพเจฒ เจนเจจ, เจคเจพเจ‚ เจคเฉเจธเฉ€เจ‚ เจ‰เจนเจจเจพเจ‚ เจจเฉ‚เฉฐ เจ‡เฉฑเจฅเฉ‡ เจชเฉเฉฑเจ› เจธเจ•เจฆเฉ‡ เจนเฉ‹ เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจ เจฆเฉ‡ เจจเจพเจฒ เจฐเจฟเจชเฉ‹เจœเจผเจŸเจฐเฉ€เจ†เจ‚. เจ‰เฉฑเจฅเฉ‡ เจคเฉเจนเจพเจจเฉ‚เฉฐ เจนเจฐเฉ‡เจ• เจฎเจจเฉ‹เจจเฉ€เจค เจ•เจฆเจฎ เจฒเจˆ เจ•เจฎเจฟเจŸ เจตเฉ€ เจฎเจฟเจฒเจฃเจ—เฉ‡เฅค

เจ…เจคเฉ‡ เจœเฉ‡เจ•เจฐ เจคเฉเจธเฉ€เจ‚ เจ…เจธเจฒ เจเจ•เจธเจŸเฉˆเจ‚เจธเจผเจจ เจฒเจˆ เจ•เฉ‹เจก เจจเฉ‚เฉฐ เจฆเฉ‡เจ–เจฃ เจตเจฟเฉฑเจš เจฆเจฟเจฒเจšเจธเจชเฉ€ เจฐเฉฑเจ–เจฆเฉ‡ เจนเฉ‹, เจคเจพเจ‚ เจคเฉเจธเฉ€เจ‚ เจ‡เจธเจจเฉ‚เฉฐ เจฒเฉฑเจญ เจธเจ•เจฆเฉ‡ เจนเฉ‹ เจ‡เฉฑเจฅเฉ‡.

เจคเฉ‹เจ‚ เจ•เฉ‹เจก, เจฐเจฟเจชเฉ‹เจœเจผเจŸเจฐเฉ€ เจ…เจคเฉ‡ เจจเฉŒเจ•เจฐเฉ€ เจฆเจพ เจตเฉ‡เจฐเจตเจพ siemarell

เจธเจฐเฉ‹เจค: www.habr.com

เจ‡เฉฑเจ• เจŸเจฟเฉฑเจชเจฃเฉ€ เจœเฉ‹เฉœเฉ‹