เด’เดฐเต เดธเตเดฐเด•เตเดทเดฟเดค เดฌเตเดฐเต—เดธเตผ เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเด‚ เดŽเดดเตเดคเตเดจเตเดจเต

เด’เดฐเต เดธเตเดฐเด•เตเดทเดฟเดค เดฌเตเดฐเต—เดธเตผ เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเด‚ เดŽเดดเตเดคเตเดจเตเดจเต

เดธเดพเดงเดพเดฐเดฃ "เด•เตเดฒเดฏเดจเตเดฑเต-เดธเต†เตผเดตเตผ" เด†เตผเด•เตเด•เดฟเดŸเต†เด•เตเดšเดฑเดฟเตฝ เดจเดฟเดจเตเดจเต เดตเตเดฏเดคเตเดฏเดธเตเดคเดฎเดพเดฏเดฟ, เดตเดฟเด•เต‡เดจเตเดฆเตเดฐเต€เด•เตƒเดค เด†เดชเตเดฒเดฟเด•เตเด•เต‡เดทเดจเตเด•เตพ เด‡เดตเดฏเดพเดฃเต:

  • เด‰เดชเดฏเต‹เด•เตเดคเตƒ เดฒเต‹เด—เดฟเดจเตเด•เดณเตเด‚ เดชเดพเดธเตโ€Œเดตเต‡เดกเตเด•เดณเตเด‚ เด‰เดณเตเดณ เด’เดฐเต เดกเดพเดฑเตเดฑเดพเดฌเต‡เดธเต เดธเด‚เดญเดฐเดฟเด•เตเด•เต‡เดฃเตเดŸ เด†เดตเดถเตเดฏเดฎเดฟเดฒเตเดฒ. เด†เด•เตโ€Œเดธเดธเตเดธเต เดตเดฟเดตเดฐเด™เตเด™เตพ เด‰เดชเดฏเต‹เด•เตเดคเดพเด•เตเด•เตพ เดคเดจเตเดจเต† เดชเตเดฐเดคเตเดฏเต‡เด•เดฎเดพเดฏเดฟ เดธเด‚เดญเดฐเดฟเด•เตเด•เตเดจเตเดจเต, เด•เต‚เดŸเดพเดคเต† เด…เดตเดฐเตเดŸเต† เด†เดงเดฟเด•เดพเดฐเดฟเด•เดคเดฏเตเดŸเต† เดธเตเดฅเดฟเดฐเต€เด•เดฐเดฃเด‚ เดชเตเดฐเต‹เดŸเตเดŸเต‹เด•เตเด•เต‹เตพ เดคเดฒเดคเตเดคเดฟเตฝ เดธเด‚เดญเดตเดฟเด•เตเด•เตเดจเตเดจเต.
  • เด’เดฐเต เดธเต†เตผเดตเตผ เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เต‡เดฃเตเดŸเดคเดฟเดฒเตเดฒ. เด†เดชเตเดฒเดฟเด•เตเด•เต‡เดทเตป เดฒเต‹เดœเดฟเด•เต เด’เดฐเต เดฌเตเดฒเต‹เด•เตเด•เตเดšเต†เดฏเดฟเตป เดจเต†เดฑเตเดฑเตโ€Œเดตเตผเด•เตเด•เดฟเตฝ เดŽเด•เตเดธเดฟเด•เตเดฏเต‚เดŸเตเดŸเต เดšเต†เดฏเตเดฏเดพเตป เด•เดดเดฟเดฏเตเด‚, เด…เดตเดฟเดŸเต† เด†เดตเดถเตเดฏเดฎเดพเดฏ เดกเดพเดฑเตเดฑ เดธเด‚เดญเดฐเดฟเด•เตเด•เดพเตป เด•เดดเดฟเดฏเตเด‚.

เด‰เดชเดฏเต‹เด•เตเดคเตƒ เด•เต€เด•เตพเด•เตเด•เดพเดฏเดฟ เดคเดพเดฐเดคเดฎเตเดฏเต‡เดจ เดธเตเดฐเด•เตเดทเดฟเดคเดฎเดพเดฏ 2 เดธเตเดฑเตเดฑเต‹เดฑเต‡เดœเตเด•เดณเตเดฃเตเดŸเต - เดนเดพเตผเดกเตโ€Œเดตเต†เดฏเตผ เดตเดพเดฒเดฑเตเดฑเตเด•เดณเตเด‚ เดฌเตเดฐเต—เดธเตผ เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเด™เตเด™เดณเตเด‚. เดนเดพเตผเดกเตโ€Œเดตเต†เดฏเตผ เดตเดพเดฒเดฑเตเดฑเตเด•เตพ เดเดฑเต†เด•เตเด•เตเดฑเต† เดธเตเดฐเด•เตเดทเดฟเดคเดฎเดพเดฃเต, เดŽเดจเตเดจเดพเตฝ เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เดพเตป เดชเตเดฐเดฏเดพเดธเดฎเตเดณเตเดณเดคเตเด‚ เดธเต—เดœเดจเตเดฏเดฎเดฒเตเดฒ, เดŽเดจเตเดจเดพเตฝ เดฌเตเดฐเต—เดธเตผ เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเด™เตเด™เตพ เดธเตเดฐเด•เตเดทเดฟเดคเดคเตเดตเดคเตเดคเดฟเดจเตเดฑเต†เดฏเตเด‚ เด‰เดชเดฏเต‹เด— เดŽเดณเตเดชเตเดชเดคเตเดคเดฟเดจเตเดฑเต†เดฏเตเด‚ เดธเดฎเตเดชเต‚เตผเดฃเตเดฃ เดธเด‚เดฏเต‹เดœเดจเดฎเดพเดฃเต, เดฎเดพเดคเตเดฐเดฎเดฒเตเดฒ เด…เดจเตเดคเดฟเดฎ เด‰เดชเดฏเต‹เด•เตเดคเดพเด•เตเด•เตพเด•เตเด•เต เดชเต‚เตผเดฃเตเดฃเดฎเดพเดฏเตเด‚ เดธเต—เดœเดจเตเดฏเดตเตเดฎเดพเด•เดพเด‚.

เด‡เดคเต†เดฒเตเดฒเดพเด‚ เด•เดฃเด•เตเด•เดฟเดฒเต†เดŸเตเดคเตเดคเต, เด‡เดŸเดชเดพเดŸเตเด•เดณเตเด‚ เด’เดชเตเดชเตเด•เดณเตเด‚ เด‰เดชเดฏเต‹เด—เดฟเดšเตเดšเต เดชเตเดฐเดตเตผเดคเตเดคเดฟเด•เตเด•เตเดจเตเดจเดคเดฟเดจเต เดฒเดณเดฟเดคเดฎเดพเดฏ API เดจเตฝเด•เดฟเด•เตเด•เตŠเดฃเตเดŸเต เดตเดฟเด•เต‡เดจเตเดฆเตเดฐเต€เด•เตƒเดค เด†เดชเตเดฒเดฟเด•เตเด•เต‡เดทเดจเตเด•เดณเตเดŸเต† เดตเดฟเด•เดธเดจเด‚ เดฒเดณเดฟเดคเดฎเดพเด•เตเด•เตเดจเตเดจ เดเดฑเตเดฑเดตเตเด‚ เดธเตเดฐเด•เตเดทเดฟเดคเดฎเดพเดฏ เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเด‚ เด‰เดฃเตเดŸเดพเด•เตเด•เดพเตป เดžเด™เตเด™เตพ เด†เด—เตเดฐเดนเดฟเด•เตเด•เตเดจเตเดจเต.
เดˆ เด…เดจเตเดญเดตเดคเตเดคเต†เด•เตเด•เตเดฑเดฟเดšเตเดšเต เดžเด™เตเด™เตพ เดšเตเดตเดŸเต† เดจเดฟเด™เตเด™เดณเต‹เดŸเต เดชเดฑเดฏเตเด‚.

เด•เต‹เดกเต เด‰เดฆเดพเดนเดฐเดฃเด™เตเด™เดณเตเด‚ เดธเตโ€Œเด•เตเดฐเต€เตปเดทเต‹เดŸเตเดŸเตเด•เดณเตเด‚ เด‰เดชเดฏเต‹เด—เดฟเดšเตเดšเต เดฌเตเดฐเต—เดธเตผ เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเด‚ เดŽเด™เตเด™เดจเต† เดŽเดดเตเดคเดพเด‚ เดŽเดจเตเดจเดคเดฟเดจเต†เด•เตเด•เตเดฑเดฟเดšเตเดšเตเดณเตเดณ เด˜เดŸเตเดŸเด‚ เด˜เดŸเตเดŸเดฎเดพเดฏเตเดณเตเดณ เดจเดฟเตผเดฆเตเดฆเต‡เดถเด™เตเด™เตพ เดฒเต‡เด–เดจเดคเตเดคเดฟเตฝ เด…เดŸเด™เตเด™เดฟเดฏเดฟเดฐเดฟเด•เตเด•เตเด‚. เดจเดฟเด™เตเด™เตพเด•เตเด•เต เดŽเดฒเตเดฒเดพ เด•เต‹เดกเตเด‚ เด•เดฃเตเดŸเต†เดคเตเดคเดพเดจเดพเด•เตเด‚ เดถเต‡เด–เดฐเด™เตเด™เตพ. เด“เดฐเต‹ เด•เดฎเตเดฎเดฟเดฑเตเดฑเตเด‚ เดˆ เดฒเต‡เด–เดจเดคเตเดคเดฟเดจเตเดฑเต† เด’เดฐเต เดตเดฟเดญเดพเด—เดตเตเดฎเดพเดฏเดฟ เดฏเตเด•เตเดคเดฟเดธเดนเดฎเดพเดฏเดฟ เดฏเต‹เดœเดฟเด•เตเด•เตเดจเตเดจเต.

เดฌเตเดฐเต—เดธเตผ เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเด™เตเด™เดณเตเดŸเต† เด’เดฐเต เดนเตเดฐเดธเตเดต เดšเดฐเดฟเดคเตเดฐเด‚

เดฌเตเดฐเต—เดธเตผ เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเด™เตเด™เตพ เดตเดณเดฐเต†เด•เตเด•เดพเดฒเดฎเดพเดฏเดฟ เดจเดฟเดฒเดตเดฟเดฒเตเดฃเตเดŸเต. 1999-เตฝ เด‡เดจเตเดฑเตผเดจเต†เดฑเตเดฑเต เดŽเด•เตเดธเตเดชเตเดฒเต‹เดฑเดฑเดฟเตฝ, 2004-เตฝ เดซเดฏเตผเดซเต‹เด•เตเดธเดฟเตฝ เด…เดตเตผ เดชเตเดฐเดคเตเดฏเด•เตเดทเดชเตเดชเต†เดŸเตเดŸเต. เดŽเดจเตเดจเดฟเดฐเตเดจเตเดจเดพเดฒเตเด‚, เดตเดณเดฐเต†เด•เตเด•เดพเดฒเดฎเดพเดฏเดฟ เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเดคเตเดคเดฟเดจเต เด’เดฐเตŠเดฑเตเดฑ เดฎเดพเดจเดฆเดฃเตเดกเดฎเดฟเดฒเตเดฒ.

เด—เต‚เด—เดฟเตพ เด•เตเดฐเต‹เดฎเดฟเดจเตเดฑเต† เดจเดพเดฒเดพเดฎเดคเตเดคเต† เดชเดคเดฟเดชเตเดชเดฟเดฒเต† เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเด™เตเด™เตพเด•เตเด•เตŠเดชเตเดชเด‚ เด‡เดคเต เดชเตเดฐเดคเตเดฏเด•เตเดทเดชเตเดชเต†เดŸเตเดŸเตเดตเต†เดจเตเดจเต เดจเดฎเตเด•เตเด•เต เดชเดฑเดฏเดพเด‚. เดคเต€เตผเดšเตเดšเดฏเดพเดฏเตเด‚, เด…เดจเตเดจเต เด’เดฐเต เดธเตเดชเต†เดธเดฟเดซเดฟเด•เตเด•เต‡เดทเดจเตเด‚ เด‰เดฃเตเดŸเดพเดฏเดฟเดฐเตเดจเตเดจเดฟเดฒเตเดฒ, เดชเด•เตเดทเต‡ Chrome API เด†เดฏเดฟเดฐเตเดจเตเดจเต เด…เดคเดฟเดจเตเดฑเต† เด…เดŸเดฟเดธเตเดฅเดพเดจเด‚: เดฌเตเดฐเต—เดธเตผ เดฎเดพเตผเด•เตเด•เดฑเตเดฑเดฟเดจเตเดฑเต† เดญเต‚เดฐเดฟเดญเดพเด—เดตเตเด‚ เด•เต€เดดเดŸเด•เตเด•เตเด•เดฏเตเด‚ เด’เดฐเต เดฌเดฟเตฝเดฑเตเดฑเต-เด‡เตป เด†เดชเตเดฒเดฟเด•เตเด•เต‡เดทเตป เดธเตเดฑเตเดฑเต‹เตผ เด‰เดณเตเดณเดคเดฟเดจเดพเตฝ, Chrome เดฏเดฅเดพเตผเดคเตเดฅเดคเตเดคเดฟเตฝ เดฌเตเดฐเต—เดธเตผ เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเด™เตเด™เตพเด•เตเด•เตเดณเตเดณ เดฎเดพเดจเดฆเดฃเตเดกเด‚ เดธเดœเตเดœเดฎเดพเด•เตเด•เดฟ.

เดฎเต‹เดธเดฟเดฒเตเดฒเดฏเตเด•เตเด•เต เด…เดคเดฟเดจเตเดฑเต‡เดคเดพเดฏ เดธเตเดฑเตเดฑเดพเตปเดกเต‡เตผเดกเต เด‰เดฃเตเดŸเดพเดฏเดฟเดฐเตเดจเตเดจเต, เดŽเดจเตเดจเดพเตฝ Chrome เดŽเด•เตเดธเตเดฑเตเดฑเตปเดทเดจเตเด•เดณเตเดŸเต† เดœเดจเดชเตเดฐเต€เดคเดฟ เด•เดฃเตเดŸเดชเตเดชเต‹เตพ, เด…เดจเตเดฏเต‹เดœเตเดฏเดฎเดพเดฏ API เดจเดฟเตผเดฎเตเดฎเดฟเด•เตเด•เดพเตป เด•เดฎเตเดชเดจเดฟ เดคเต€เดฐเตเดฎเดพเดจเดฟเดšเตเดšเต. 2015-เตฝ, เดฎเต‹เดธเดฟเดฒเตเดฒเดฏเตเดŸเต† เดฎเตเตปเด•เตˆเดฏเดฟเตฝ, เด•เตเดฐเต‹เดธเต-เดฌเตเดฐเต—เดธเตผ เดŽเด•เตเดธเตเดฑเตเดฑเตปเดทเตป เดธเตเดชเต†เดธเดฟเดซเดฟเด•เตเด•เต‡เดทเดจเตเด•เดณเดฟเตฝ เดชเตเดฐเดตเตผเดคเตเดคเดฟเด•เตเด•เดพเตป เดตเต‡เตพเดกเต เดตเตˆเดกเต เดตเต†เดฌเต เด•เตบเดธเต‹เตผเดทเตเดฏเดคเตเดคเดฟเตฝ (W3C) เด’เดฐเต เดชเตเดฐเดคเตเดฏเต‡เด• เด—เตเดฐเต‚เดชเตเดชเต เดธเตƒเดทเตเดŸเดฟเดšเตเดšเต.

Chrome-เดจเตเดณเตเดณ เดจเดฟเดฒเดตเดฟเดฒเตเดณเตเดณ API เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเด™เตเด™เตพ เด…เดŸเดฟเดธเตเดฅเดพเดจเดฎเดพเดฏเดฟ เดŽเดŸเตเดคเตเดคเต. เดฎเตˆเด•เตเดฐเต‹เดธเต‹เดซเตเดฑเตเดฑเดฟเดจเตเดฑเต† เดชเดฟเดจเตเดคเตเดฃเดฏเต‹เดŸเต†เดฏเดพเดฃเต เดชเตเดฐเดตเตผเดคเตเดคเดจเด‚ เดจเดŸเดคเตเดคเดฟเดฏเดคเต (เดธเตเดฑเตเดฑเดพเตปเดกเต‡เตผเดกเดฟเดจเตเดฑเต† เดตเดฟเด•เดธเดจเดคเตเดคเดฟเตฝ เดชเด™เตเด•เต†เดŸเตเด•เตเด•เดพเตป เด—เต‚เด—เดฟเตพ เดตเดฟเดธเดฎเตเดฎเดคเดฟเดšเตเดšเต), เด…เดคเดฟเดจเตเดฑเต† เดซเดฒเดฎเดพเดฏเดฟ เด’เดฐเต เดกเตเดฐเดพเดซเตเดฑเตเดฑเต เดชเตเดฐเดคเตเดฏเด•เตเดทเดชเตเดชเต†เดŸเตเดŸเต. เดธเดตเดฟเดถเต‡เดทเดคเด•เตพ.

เด”เดชเดšเดพเดฐเดฟเด•เดฎเดพเดฏเดฟ, เดธเตเดชเต†เดธเดฟเดซเดฟเด•เตเด•เต‡เดทเตป เดŽเดกเตเดœเต, เดซเดฏเตผเดซเต‹เด•เตเดธเต, เด“เดชเตเดชเดฑ เดŽเดจเตเดจเดฟเดต เดชเดฟเดจเตเดคเตเดฃเดฏเตเด•เตเด•เตเดจเตเดจเต (Chrome เดˆ เดฒเดฟเดธเตเดฑเตเดฑเดฟเตฝ เด‡เดฒเตเดฒ เดŽเดจเตเดจเดคเต เดถเตเดฐเดฆเตเดงเดฟเด•เตเด•เตเด•). เดŽเดจเตเดจเดพเตฝ เดตเดพเดธเตเดคเดตเดคเตเดคเดฟเตฝ, เดธเตเดฑเตเดฑเดพเตปเดกเต‡เตผเดกเต Chrome-เดฎเดพเดฏเดฟ เดเดฑเต†เด•เตเด•เตเดฑเต† เด…เดจเตเดฏเต‹เดœเตเดฏเดฎเดพเดฃเต, เด•เดพเดฐเดฃเด‚ เด‡เดคเต เดฏเดฅเดพเตผเดคเตเดฅเดคเตเดคเดฟเตฝ เด…เดคเดฟเดจเตเดฑเต† เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเด™เตเด™เดณเต† เด…เดŸเดฟเดธเตเดฅเดพเดจเดฎเดพเด•เตเด•เดฟเดฏเดพเดฃเต เดŽเดดเตเดคเดฟเดฏเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจเดคเต. WebExtensions API-เดฏเต† เด•เตเดฑเดฟเดšเตเดšเต เดจเดฟเด™เตเด™เตพเด•เตเด•เต เด•เต‚เดŸเตเดคเตฝ เดตเดพเดฏเดฟเด•เตเด•เดพเด‚ เด‡เดตเดฟเดŸเต†.

เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃ เด˜เดŸเดจ

เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเดคเตเดคเดฟเดจเต เด†เดตเดถเตเดฏเดฎเดพเดฏ เด’เดฐเต‡เดฏเตŠเดฐเต เดซเดฏเตฝ เดฎเดพเดจเดฟเดซเต†เดธเตเดฑเตเดฑเต (manifest.json) เด†เดฃเต. เด‡เดคเต เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเดคเตเดคเดฟเดฒเต‡เด•เตเด•เตเดณเตเดณ "เดชเตเดฐเดตเต‡เดถเดจ เดชเต‹เดฏเดฟเดจเตเดฑเต" เด•เต‚เดŸเดฟเดฏเดพเดฃเต.

เดฎเดพเดจเดฟเดซเต†เดธเตเดฑเตเดฑเต‹

เดธเตเดชเต†เดธเดฟเดซเดฟเด•เตเด•เต‡เดทเตป เด…เดจเตเดธเดฐเดฟเดšเตเดšเต, เดฎเดพเดจเดฟเดซเต†เดธเตเดฑเตเดฑเต เดซเดฏเตฝ เด’เดฐเต เดธเดพเดงเตเดตเดพเดฏ JSON เดซเดฏเดฒเดพเดฃเต. เดเดคเต เดฌเตเดฐเต—เดธเดฑเดฟเตฝ เดเดคเต เด•เต€เด•เตพ เดชเดฟเดจเตเดคเตเดฃเดฏเตเด•เตเด•เตเดจเตเดจเต เดŽเดจเตเดจเดคเดฟเดจเต†เด•เตเด•เตเดฑเดฟเดšเตเดšเตเดณเตเดณ เดตเดฟเดตเดฐเด™เตเด™เดณเตเดณเตเดณ เดฎเดพเดจเดฟเดซเต†เดธเตเดฑเตเดฑเต เด•เต€เด•เดณเตเดŸเต† เดชเต‚เตผเดฃเตเดฃเดฎเดพเดฏ เดตเดฟเดตเดฐเดฃเด‚ เด•เดพเดฃเดพเตป เด•เดดเดฟเดฏเตเด‚ เด‡เดตเดฟเดŸเต†.

เดธเตโ€Œเดชเต†เดธเดฟเดซเดฟเด•เตเด•เต‡เดทเดจเดฟเตฝ เด‡เดฒเตเดฒเดพเดคเตเดค เด•เต€เด•เตพ เด…เดตเด—เดฃเดฟเด•เตเด•เดชเตเดชเต†เดŸเดพเด‚ (Chrome-เด‰เด‚ Firefox-เด‰เด‚ เดชเดฟเดถเด•เตเด•เตพ เดฑเดฟเดชเตเดชเต‹เตผเดŸเตเดŸเต เดšเต†เดฏเตเดฏเตเดจเตเดจเต, เดชเด•เตเดทเต‡ เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเด™เตเด™เตพ เดชเตเดฐเดตเตผเดคเตเดคเดฟเด•เตเด•เตเดจเตเดจเดคเต เดคเตเดŸเดฐเตเดจเตเดจเต).

เด•เต‚เดŸเดพเดคเต† เดšเดฟเดฒ เดชเต‹เดฏเดฟเดจเตเดฑเตเด•เดณเดฟเดฒเต‡เด•เตเด•เต เดถเตเดฐเดฆเตเดง เด†เด•เตผเดทเดฟเด•เตเด•เดพเตป เดžเดพเตป เด†เด—เตเดฐเดนเดฟเด•เตเด•เตเดจเตเดจเต.

  1. เดชเดถเตเดšเดพเดคเตเดคเดฒเด‚ - เด‡เดจเดฟเดชเตเดชเดฑเดฏเตเดจเตเดจ เดซเต€เตฝเดกเตเด•เตพ เด‰เตพเดชเตเดชเต†เดŸเตเดจเตเดจ เด’เดฐเต เดตเดธเตเดคเต:
    1. เดธเตเด•เตเดฐเดฟเดชเตเดฑเตเดฑเตเด•เตพ - เดชเดถเตเดšเดพเดคเตเดคเดฒ เดธเดจเตเดฆเตผเดญเดคเตเดคเดฟเตฝ เดŽเด•เตเดธเดฟเด•เตเดฏเต‚เดŸเตเดŸเต เดšเต†เดฏเตเดฏเตเดจเตเดจ เดธเตเด•เตเดฐเดฟเดชเตเดฑเตเดฑเตเด•เดณเตเดŸเต† เด’เดฐเต เดจเดฟเดฐ (เด‡เดคเดฟเดจเต†เด•เตเด•เตเดฑเดฟเดšเตเดšเต เดžเด™เตเด™เตพ เด•เตเดฑเดšเตเดšเต เด•เดดเดฟเดžเตเดžเต เดธเด‚เดธเดพเดฐเดฟเด•เตเด•เตเด‚);
    2. เดชเต‡เดœเต - เดถเต‚เดจเตเดฏเดฎเดพเดฏ เดชเต‡เดœเดฟเตฝ เดŽเด•เตเดธเดฟเด•เตเดฏเต‚เดŸเตเดŸเต เดšเต†เดฏเตเดฏเตเดจเตเดจ เดธเตเด•เตเดฐเดฟเดชเตเดฑเตเดฑเตเด•เตพเด•เตเด•เต เดชเด•เดฐเด‚, เดจเดฟเด™เตเด™เตพเด•เตเด•เต เด‰เดณเตเดณเดŸเด•เตเด•เดฎเตเดณเตเดณ html เดตเตเดฏเด•เตเดคเดฎเดพเด•เตเด•เดพเตป เด•เดดเดฟเดฏเตเด‚. เดˆ เดธเดพเดนเดšเดฐเตเดฏเดคเตเดคเดฟเตฝ, เดธเตเด•เตเดฐเดฟเดชเตเดฑเตเดฑเต เดซเต€เตฝเดกเต เด…เดตเด—เดฃเดฟเด•เตเด•เดชเตเดชเต†เดŸเตเด‚, เด•เต‚เดŸเดพเดคเต† เด‰เดณเตเดณเดŸเด•เตเด• เดชเต‡เดœเดฟเดฒเต‡เด•เตเด•เต เดธเตเด•เตเดฐเดฟเดชเตเดฑเตเดฑเตเด•เตพ เดšเต‡เตผเด•เตเด•เต‡เดฃเตเดŸเดคเตเดฃเตเดŸเต;
    3. เดจเดฟเดฐเตเดฌเดจเตเดงเด‚เดชเดฟเดŸเดฟเด•เตเด•เตเด• โ€” เด’เดฐเต เดฌเตˆเดจเดฑเดฟ เดซเตเดฒเดพเด—เต, เดตเตเดฏเด•เตเดคเดฎเดพเด•เตเด•เดฟเดฏเดฟเดŸเตเดŸเดฟเดฒเตเดฒเต†เด™เตเด•เดฟเตฝ, เดฌเตเดฐเต—เดธเตผ เด…เดคเต เด’เดจเตเดจเตเด‚ เดšเต†เดฏเตเดฏเตเดจเตเดจเดฟเดฒเตเดฒเต†เดจเตเดจเต เด•เดฃเด•เตเด•เดพเด•เตเด•เตเดฎเตเดชเต‹เตพ เดชเดถเตเดšเดพเดคเตเดคเดฒ เดชเตเดฐเด•เตเดฐเดฟเดฏเดฏเต† "เด•เตŠเดฒเตเดฒเตเด‚", เด†เดตเดถเตเดฏเดฎเต†เด™เตเด•เดฟเตฝ เด…เดคเต เดชเตเดจเดฐเดพเดฐเด‚เดญเดฟเด•เตเด•เตเด‚. เด…เดฒเตเดฒเต†เด™เตเด•เดฟเตฝ, เดฌเตเดฐเต—เดธเตผ เด…เดŸเดฏเตเด•เตเด•เตเดฎเตเดชเต‹เตพ เดฎเดพเดคเตเดฐเดฎเต‡ เดชเต‡เดœเต เด…เตบเดฒเต‹เดกเต เดšเต†เดฏเตเดฏเตเด•เดฏเตเดณเตเดณเต‚. Firefox-เตฝ เดชเดฟเดจเตเดคเตเดฃเดฏเตเด•เตเด•เตเดจเตเดจเดฟเดฒเตเดฒ.
  2. เด‰เดณเตเดณเดŸเด•เตเด•_เดธเตเด•เตเดฐเดฟเดชเตเดฑเตเดฑเตเด•เตพ - เดตเตเดฏเดคเตเดฏเดธเตเดค เดตเต†เดฌเต เดชเต‡เดœเตเด•เดณเดฟเดฒเต‡เด•เตเด•เต เดตเตเดฏเดคเตเดฏเดธเตเดค เดธเตเด•เตเดฐเดฟเดชเตเดฑเตเดฑเตเด•เตพ เดฒเต‹เดกเต เดšเต†เดฏเตเดฏเดพเตป เดจเดฟเด™เตเด™เดณเต† เด…เดจเตเดตเดฆเดฟเด•เตเด•เตเดจเตเดจ เด’เดฌเตเดœเด•เตเดฑเตเดฑเตเด•เดณเตเดŸเต† เด’เดฐเต เดจเดฟเดฐ. เด“เดฐเต‹ เด’เดฌเตเดœเด•เตเดฑเตเดฑเดฟเดฒเตเด‚ เด‡เดจเดฟเดชเตเดชเดฑเดฏเตเดจเตเดจ เดชเตเดฐเดงเดพเดจเดชเตเดชเต†เดŸเตเดŸ เดซเต€เตฝเดกเตเด•เตพ เด…เดŸเด™เตเด™เดฟเดฏเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจเต:
    1. เดฎเดคเตเดธเดฐเด™เตเด™เตพ - เดชเดพเดฑเตเดฑเต‡เตบ url, เด’เดฐเต เดชเตเดฐเดคเตเดฏเต‡เด• เด‰เดณเตเดณเดŸเด•เตเด• เดธเตเด•เตเดฐเดฟเดชเตเดฑเตเดฑเต เด‰เตพเดชเตเดชเต†เดŸเตเดคเตเดคเดฃเต‹ เดตเต‡เดฃเตเดŸเดฏเต‹ เดŽเดจเตเดจเต เด‡เดคเต เดจเดฟเตผเดฃเตเดฃเดฏเดฟเด•เตเด•เตเดจเตเดจเต.
    2. js - เดˆ เดฎเดคเตเดธเดฐเดคเตเดคเดฟเตฝ เดฒเต‹เดกเต เดšเต†เดฏเตเดฏเตเดจเตเดจ เดธเตเด•เตเดฐเดฟเดชเตเดฑเตเดฑเตเด•เดณเตเดŸเต† เด’เดฐเต เดฒเดฟเดธเตเดฑเตเดฑเต;
    3. เด’เดดเดฟเดตเดพเด•เตเด•_เดชเตŠเดฐเตเดคเตเดคเด™เตเด™เตพ - เดซเต€เตฝเดกเดฟเตฝ เดจเดฟเดจเตเดจเต เด’เดดเดฟเดตเดพเด•เตเด•เตเดจเตเดจเต match เดˆ เดซเต€เตฝเดกเตเดฎเดพเดฏเดฟ เดชเตŠเดฐเตเดคเตเดคเดชเตเดชเต†เดŸเตเดจเตเดจ URL-เด•เตพ.
  3. เดชเต‡เดœเต_เด†เด•เตเดทเตป - เดฏเดฅเดพเตผเดคเตเดฅเดคเตเดคเดฟเตฝ เดฌเตเดฐเต—เดธเดฑเดฟเดฒเต† เด…เดกเตเดฐเดธเต เดฌเดพเดฑเดฟเดจเต เด…เดŸเตเดคเตเดคเดพเดฏเดฟ เดชเตเดฐเดฆเตผเดถเดฟเดชเตเดชเดฟเดšเตเดšเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจ เดเด•เตเด•เดฃเดฟเดจเตเด‚ เด…เดคเตเดฎเดพเดฏเดฟ เด‡เดŸเดชเดดเด•เตเดจเตเดจเดคเดฟเดจเตเด‚ เด‰เดคเตเดคเดฐเดตเดพเดฆเดฟเดฏเดพเดฏ เด’เดฐเต เดตเดธเตเดคเตเดตเดพเดฃเต. เดจเดฟเด™เตเด™เดณเตเดŸเต† เดธเตเดตเดจเตเดคเด‚ HTML, CSS, JS เดŽเดจเตเดจเดฟเดต เด‰เดชเดฏเต‹เด—เดฟเดšเตเดšเต เดจเดฟเตผเดตเดšเดฟเดšเตเดšเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจ เด’เดฐเต เดชเต‹เดชเตเดชเตเด…เดชเตเดชเต เดตเดฟเตปเดกเต‹ เดชเตเดฐเดฆเตผเดถเดฟเดชเตเดชเดฟเด•เตเด•เดพเดจเตเด‚ เด‡เดคเต เดจเดฟเด™เตเด™เดณเต† เด…เดจเตเดตเดฆเดฟเด•เตเด•เตเดจเตเดจเต.
    1. default_popup โ€” เดชเต‹เดชเตเดชเตเด…เดชเตเดชเต เด‡เดจเตเดฑเตผเดซเต‡เดธเตเดณเตเดณ HTML เดซเดฏเดฒเดฟเดฒเต‡เด•เตเด•เตเดณเตเดณ เดชเดพเดคเดฏเดฟเตฝ CSS, JS เดŽเดจเตเดจเดฟเดต เด…เดŸเด™เตเด™เดฟเดฏเดฟเดฐเดฟเด•เตเด•เดพเด‚.
  4. เด…เดจเตเดฎเดคเดฟเด•เตพ - เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃ เด…เดตเด•เดพเดถเด™เตเด™เตพ เด•เตˆเด•เดพเดฐเตเดฏเด‚ เดšเต†เดฏเตเดฏเตเดจเตเดจเดคเดฟเดจเตเดณเตเดณ เด’เดฐเต เดถเตเดฐเต‡เดฃเดฟ. 3 เดคเดฐเดคเตเดคเดฟเดฒเตเดณเตเดณ เด…เดตเด•เดพเดถเด™เตเด™เดณเตเดฃเตเดŸเต, เด…เดต เดตเดฟเดถเดฆเดฎเดพเดฏเดฟ เดตเดฟเดตเดฐเดฟเดšเตเดšเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจเต เด‡เดตเดฟเดŸเต†
  5. web_accessible_resources โ€” เด’เดฐเต เดตเต†เดฌเต เดชเต‡เดœเดฟเดจเต เด…เดญเตเดฏเตผเดคเตเดฅเดฟเด•เตเด•เดพเตป เด•เดดเดฟเดฏเตเดจเตเดจ เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃ เด‰เดฑเดตเดฟเดŸเด™เตเด™เตพ, เด‰เดฆเดพเดนเดฐเดฃเดคเตเดคเดฟเดจเต, เด‡เดฎเต‡เดœเตเด•เตพ, JS, CSS, HTML เดซเดฏเดฒเตเด•เตพ.
  6. เดฌเดพเดนเตเดฏเดฎเดพเดฏเดฟ_เด•เดฃเด•เตเดŸเดฌเดฟเตพ โ€” เด‡เดตเดฟเดŸเต† เดจเดฟเด™เตเด™เตพเด•เตเด•เต เดฎเดฑเตเดฑเต เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเด™เตเด™เดณเตเดŸเต† เดเดกเดฟเด•เดณเตเด‚ เดจเดฟเด™เตเด™เตพเด•เตเด•เต เดฌเดจเตเดงเดฟเดชเตเดชเดฟเด•เตเด•เดพเตป เด•เดดเดฟเดฏเตเดจเตเดจ เดตเต†เดฌเต เดชเต‡เดœเตเด•เดณเตเดŸเต† เดกเตŠเดฎเต†เดฏเตโ€Œเดจเตเด•เดณเตเด‚ เดตเตเดฏเด•เตเดคเดฎเดพเดฏเดฟ เดตเตเดฏเด•เตเดคเดฎเดพเด•เตเด•เดพเตป เด•เดดเดฟเดฏเตเด‚. เด’เดฐเต เดกเตŠเดฎเต†เดฏเตเตป เดฐเดฃเตเดŸเดพเด‚ เดจเดฟเดฒเดฏเต‹ เด‰เดฏเตผเดจเตเดจเดคเต‹ เด†เด•เดพเด‚. เดซเดฏเตผเดซเต‹เด•เตเดธเดฟเตฝ เดชเตเดฐเดตเตผเดคเตเดคเดฟเด•เตเด•เตเดจเตเดจเดฟเดฒเตเดฒ.

เดจเดฟเตผเดตเตเดตเดนเดฃ เดธเดจเตเดฆเตผเดญเด‚

เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเดคเตเดคเดฟเดจเต เดฎเต‚เดจเตเดจเต เด•เต‹เดกเต เดจเดฟเตผเดตเตเดตเดนเดฃ เดธเดจเตเดฆเตผเดญเด™เตเด™เดณเตเดฃเตเดŸเต, เด…เดคเดพเดฏเดคเต, เดฌเตเดฐเต—เดธเตผ 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 เดจเตฝเด•เตเด•เดฏเตเด‚ เดšเต†เดฏเตเดฏเตเด‚.

เดคเตเดŸเด•เตเด•เด‚

เดŽเดฒเตเดฒเดพ เดฌเตเดฐเต—เดธเตผ เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃ เด•เต‹เดกเตเด‚ เด‡เดตเดฟเดŸเต† เดฒเดญเตเดฏเดฎเดพเดฃเต เดธเดพเดฎเต‚เดนเดฟเด•เด‚. เดตเดฟเดตเดฐเดฃเดคเตเดคเดฟเดจเดฟเดŸเดฏเดฟเตฝ เด•เดฎเตเดฎเดฟเดฑเตเดฑเตเด•เดณเดฟเดฒเต‡เด•เตเด•เตเดณเตเดณ เดฒเดฟเด™เตเด•เตเด•เตพ เด‰เดฃเตเดŸเดพเด•เตเด‚.

เดจเดฎเตเด•เตเด•เต เดฎเดพเดจเดฟเดซเต†เดธเตเดฑเตเดฑเต‹เดฏเดฟเตฝ เดจเดฟเดจเตเดจเต เด†เดฐเด‚เดญเดฟเด•เตเด•เดพเด‚:

{
  // ะ˜ะผั ะธ ะพะฟะธัะฐะฝะธะต, ะฒะตั€ัะธั. ะ’ัะต ัั‚ะพ ะฑัƒะดะตั‚ ะฒะธะดะฝะพ ะฒ ะฑั€ะฐัƒะทะตั€ะต ะฒ 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-เตฝ เดจเดฟเด™เตเด™เตพ เดฒเต‹เดกเต เด…เตบเดชเดพเด•เตเด•เต เดšเต†เดฏเตเดคเดคเตเด‚ เด…เดจเตเดฌเดจเตเดง เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเดฎเตเดณเตเดณ เดซเต‹เตพเดกเดฑเตเด‚ เดคเดฟเดฐเดžเตเดžเต†เดŸเตเด•เตเด•เต‡เดฃเตเดŸเดคเตเดฃเตเดŸเต - เดžเด™เตเด™เดณเตเดŸเต† เด•เดพเดฐเตเดฏเดคเตเดคเดฟเตฝ เดกเดฟเดธเตเดฑเตเดฑเต.

เด’เดฐเต เดธเตเดฐเด•เตเดทเดฟเดค เดฌเตเดฐเต—เดธเตผ เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเด‚ เดŽเดดเตเดคเตเดจเตเดจเต

เด‡เดชเตเดชเต‹เตพ เดžเด™เตเด™เดณเตเดŸเต† เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเด‚ เด‡เตปเดธเตเดฑเตเดฑเดพเตพ เดšเต†เดฏเตเดฏเตเด•เดฏเตเด‚ เดชเตเดฐเดตเตผเดคเตเดคเดฟเด•เตเด•เตเด•เดฏเตเด‚ เดšเต†เดฏเตเดฏเตเดจเตเดจเต. เดตเตเดฏเดคเตเดฏเดธเตเดค เดธเดจเตเดฆเตผเดญเด™เตเด™เตพเด•เตเด•เดพเดฏเดฟ เดจเดฟเด™เตเด™เตพเด•เตเด•เต เด‡เดจเดฟเดชเตเดชเดฑเดฏเตเดจเตเดจ เดฐเต€เดคเดฟเดฏเดฟเตฝ เดกเดตเดฒเดชเตเดชเตผ เดŸเต‚เดณเตเด•เตพ เดชเตเดฐเดตเตผเดคเตเดคเดฟเดชเตเดชเดฟเด•เตเด•เดพเตป เด•เดดเดฟเดฏเตเด‚:

เดชเต‹เดชเตเดชเตเด…เดชเตเดชเต ->

เด’เดฐเต เดธเตเดฐเด•เตเดทเดฟเดค เดฌเตเดฐเต—เดธเตผ เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเด‚ เดŽเดดเตเดคเตเดจเตเดจเต

เด‰เดณเตเดณเดŸเด•เตเด• เดธเตโ€Œเด•เตเดฐเดฟเดชเตเดฑเตเดฑเต เด•เตบเดธเต‹เดณเดฟเดฒเต‡เด•เตเด•เตเดณเตเดณ เด†เด•เตโ€Œเดธเดธเต เด…เดคเต เดธเดฎเดพเดฐเด‚เดญเดฟเดšเตเดš เดชเต‡เดœเดฟเดจเตเดฑเต† เด•เตบเดธเต‹เตพ เดตเดดเดฟเดฏเดพเดฃเต เดจเดŸเดชเตเดชเดฟเดฒเดพเด•เตเด•เตเดจเตเดจเดคเต.เด’เดฐเต เดธเตเดฐเด•เตเดทเดฟเดค เดฌเตเดฐเต—เดธเตผ เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเด‚ เดŽเดดเตเดคเตเดจเตเดจเต

เดธเดจเตเดฆเต‡เดถ เด•เตˆเดฎเดพเดฑเตเดฑเด‚

เด…เดคเดฟเดจเดพเตฝ, เดžเด™เตเด™เตพ เดฐเดฃเตเดŸเต เด†เดถเดฏเดตเดฟเดจเดฟเดฎเดฏ เดšเดพเดจเดฒเตเด•เตพ เดธเตเดฅเดพเดชเดฟเด•เตเด•เต‡เดฃเตเดŸเดคเตเดฃเตเดŸเต: เด‡เตปเดชเต‡เดœเต เดชเดถเตเดšเดพเดคเตเดคเดฒเดตเตเด‚ เดชเต‹เดชเตเดชเตเด…เดชเตเดชเต เดชเดถเตเดšเดพเดคเตเดคเดฒเดตเตเด‚. เดจเดฟเด™เตเด™เตพเด•เตเด•เต เดคเต€เตผเดšเตเดšเดฏเดพเดฏเตเด‚ เดชเต‹เตผเดŸเตเดŸเดฟเดฒเต‡เด•เตเด•เต เดธเดจเตเดฆเต‡เดถเด™เตเด™เตพ เด…เดฏเดฏเตโ€Œเด•เตเด•เดพเดจเตเด‚ เดจเดฟเด™เตเด™เดณเตเดŸเต† เดธเตเดตเดจเตเดคเด‚ เดชเตเดฐเต‹เดŸเตเดŸเต‹เด•เตเด•เต‹เตพ เด•เดฃเตเดŸเตเดชเดฟเดŸเดฟเด•เตเด•เดพเดจเตเด‚ เด•เดดเดฟเดฏเตเด‚, เดŽเดจเตเดจเดพเตฝ เดฎเต†เดฑเตเดฑเดพเดฎเดพเดธเตเด•เต เด“เดชเตเดชเตบ เดธเต‹เดดเตโ€Œเดธเต เดชเตเดฐเต‹เดœเด•เตเดฑเตเดฑเดฟเตฝ เดžเดพเตป เด•เดฃเตเดŸ เดธเดฎเต€เดชเดจเดฎเดพเดฃเต เดžเดพเตป เด‡เดทเตเดŸเดชเตเดชเต†เดŸเตเดจเตเดจเดคเต.

Ethereum เดจเต†เดฑเตเดฑเตโ€Œเดตเตผเด•เตเด•เดฟเตฝ เดชเตเดฐเดตเตผเดคเตเดคเดฟเด•เตเด•เตเดจเตเดจเดคเดฟเดจเตเดณเตเดณ เด’เดฐเต เดฌเตเดฐเต—เดธเตผ เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเดฎเดพเดฃเดฟเดคเต. เด…เดคเดฟเตฝ, เด†เดชเตเดฒเดฟเด•เตเด•เต‡เดทเดจเตเดฑเต† เดตเดฟเดตเดฟเดง เดญเดพเด—เด™เตเด™เตพ dnode เดฒเตˆเดฌเตเดฐเดฑเดฟ เด‰เดชเดฏเต‹เด—เดฟเดšเตเดšเต RPC เดตเดดเดฟ เด†เดถเดฏเดตเดฟเดจเดฟเดฎเดฏเด‚ เดจเดŸเดคเตเดคเตเดจเตเดจเต. เดจเดฟเด™เตเด™เตพ เด’เดฐเต เดŸเตเดฐเดพเตปเดธเตโ€Œเดชเต‹เตผเดŸเตเดŸเต เด†เดฏเดฟ เด’เดฐเต nodejs เดธเตเดŸเตเดฐเต€เด‚ เดจเตฝเด•เตเด•เดฏเดพเดฃเต†เด™เตเด•เดฟเตฝ (เด…เดคเดพเดฏเดคเต เด’เดฐเต‡ เด‡เดจเตเดฑเตผเดซเต‡เดธเต เดจเดŸเดชเตเดชเดฟเดฒเดพเด•เตเด•เตเดจเตเดจ เด’เดฐเต เด’เดฌเตโ€Œเดœเด•เตเดฑเตเดฑเต) เด’เดฐเต เดŽเด•เตเดธเตเดšเต‡เดžเตเดšเต เดตเดณเดฐเต† เดตเต‡เด—เดคเตเดคเดฟเดฒเตเด‚ เดธเต—เด•เดฐเตเดฏเดชเตเดฐเดฆเดฎเดพเดฏเตเด‚ เดธเด‚เด˜เดŸเดฟเดชเตเดชเดฟเด•เตเด•เดพเตป เด‡เดคเต เดจเดฟเด™เตเด™เดณเต† เด…เดจเตเดตเดฆเดฟเด•เตเด•เตเดจเตเดจเต:

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)
        })
    }
}

เด‡เดตเดฟเดŸเต†เดฏเตเด‚ เดคเดพเดดเต†เดฏเตเด‚, เด†เด—เต‹เดณ Chrome เด’เดฌเตโ€Œเดœเด•เตเดฑเตเดฑเดฟเดจเต เดชเด•เดฐเด‚, เดžเด™เตเด™เตพ extensionApi เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเดจเตเดจเต, เด…เดคเต 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 เดธเตเดŸเตเดฐเต€เดฎเตเด•เดณเดฟเตฝ เดชเตเดฐเดตเตผเดคเตเดคเดฟเด•เตเด•เตเด•เดฏเตเด‚ เดžเด™เตเด™เตพเด•เตเด•เต เด’เดฐเต เดชเต‹เตผเดŸเตเดŸเต เดฒเดญเดฟเด•เตเด•เตเด•เดฏเตเด‚ เดšเต†เดฏเตเดฏเตเดจเตเดจเดคเดฟเดจเดพเตฝ, เด’เดฐเต เด…เดกเดพเดชเตเดฑเตเดฑเตผ เด•เตเดฒเดพเดธเต เด†เดตเดถเตเดฏเดฎเดพเดฃเต. เดฌเตเดฐเต—เดธเดฑเดฟเตฝ nodejs เดธเตเดŸเตเดฐเต€เดฎเตเด•เตพ เดจเดŸเดชเตเดชเดฟเดฒเดพเด•เตเด•เตเดจเตเดจ เดฑเต€เดกเดฌเดฟเตพ-เดธเตเดŸเตเดฐเต€เด‚ เดฒเตˆเดฌเตเดฐเดฑเดฟ เด‰เดชเดฏเต‹เด—เดฟเดšเตเดšเดพเดฃเต เด‡เดคเต เดจเดฟเตผเดฎเตเดฎเดฟเดšเตเดšเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจเดคเต:

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()
    }
}

เด‡เดจเดฟ เดจเดฎเตเด•เตเด•เต เดฏเตเดเดฏเดฟเตฝ เด’เดฐเต เด•เดฃเด•เตเดทเตป เด‰เดฃเตเดŸเดพเด•เตเด•เดพเด‚:

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;
}

เดžเด™เตเด™เตพ เดคเดฏเตเดฏเดพเดฑเดพเดฃเต เดชเต‡เดœเดฟเดจเตเด‚ เดฏเตเดเด•เตเด•เตเดฎเดพเดฏเดฟ เดชเตเดฐเดคเตเดฏเต‡เด• API เด‰เดณเตเดณ เดตเดฟเดฆเต‚เดฐ เดจเดŸเดชเดŸเดฟเด•เตเดฐเดฎ เด•เต‹เตพ (RPC).. เด’เดฐเต เดชเตเดคเดฟเดฏ เดชเต‡เดœเต เดชเดถเตเดšเดพเดคเตเดคเดฒเดคเตเดคเดฟเดฒเต‡เด•เตเด•เต เดฌเดจเตเดงเดฟเดชเตเดชเดฟเด•เตเด•เตเดฎเตเดชเต‹เตพ เดจเดฎเตเด•เตเด•เต เด‡เดคเต เด•เดพเดฃเดพเตป เด•เดดเดฟเดฏเตเด‚:

เด’เดฐเต เดธเตเดฐเด•เตเดทเดฟเดค เดฌเตเดฐเต—เดธเตผ เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเด‚ เดŽเดดเตเดคเตเดจเตเดจเต

เดถเต‚เดจเตเดฏเดฎเดพเดฏ API, เด‰เดคเตเดญเดตเด‚. เดชเต‡เดœเดฟเดจเตเดฑเต† เดญเดพเด—เดคเตเดคเต, เดจเดฎเตเด•เตเด•เต เดนเดฒเต‹ เดซเด‚เด—เตโ€Œเดทเดจเต† เด‡เดคเตเดชเต‹เดฒเต† เดตเดฟเดณเดฟเด•เตเด•เดพเด‚:

เด’เดฐเต เดธเตเดฐเด•เตเดทเดฟเดค เดฌเตเดฐเต—เดธเตผ เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเด‚ เดŽเดดเตเดคเตเดจเตเดจเต

เด†เดงเตเดจเดฟเด• JS-เตฝ เด•เต‹เตพเดฌเดพเด•เตเด•เต เดซเด‚เด—เตโ€Œเดทเดจเตเด•เตพ เด‰เดชเดฏเต‹เด—เดฟเดšเตเดšเต เดชเตเดฐเดตเตผเดคเตเดคเดฟเด•เตเด•เตเดจเตเดจเดคเต เดฎเต‹เดถเด‚ เดชเต†เดฐเตเดฎเดพเดฑเตเดฑเดฎเดพเดฃเต, เด…เดคเดฟเดจเดพเตฝ เด’เดฐเต API เด’เดฌเตโ€Œเดœเด•เตเดฑเตเดฑเต เดฏเต‚เดŸเตเดŸเดฟเดฒเตเด•เดณเดฟเดฒเต‡เด•เตเด•เต เด•เตˆเดฎเดพเดฑเดพเตป เดจเดฟเด™เตเด™เดณเต† เด…เดจเตเดตเดฆเดฟเด•เตเด•เตเดจเตเดจ เด’เดฐเต dnode เดธเตƒเดทเตโ€ŒเดŸเดฟเด•เตเด•เดพเตป เดจเดฎเตเด•เตเด•เต เด’เดฐเต เดšเต†เดฑเดฟเดฏ เดธเดนเดพเดฏเดฟ เดŽเดดเตเดคเดพเด‚.

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))
    })
});

เด•เต‹เตพ เดซเด‚เด—เตโ€Œเดทเดจเตเด•เตพ เด’เดฐเต เดตเดพเด—เตเดฆเดพเดจเด‚ เดจเตฝเด•เตเดจเตเดจเต:

เด’เดฐเต เดธเตเดฐเด•เตเดทเดฟเดค เดฌเตเดฐเต—เดธเตผ เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเด‚ เดŽเดดเตเดคเตเดจเตเดจเต

เด…เดธเดฟเตปเด•เตเดฐเดฃเดธเต เดซเด‚เด—เตโ€Œเดทเดจเตเด•เดณเตเดณเตเดณ เดชเดคเดฟเดชเตเดชเต เดฒเดญเตเดฏเดฎเดพเดฃเต เด‡เดตเดฟเดŸเต†.

เดฎเตŠเดคเตเดคเดคเตเดคเดฟเตฝ, เด†เตผโ€Œเดชเดฟโ€Œเดธเดฟเดฏเตเด‚ เดธเตโ€ŒเดŸเตเดฐเต€เด‚ เดธเดฎเต€เดชเดจเดตเตเด‚ เดคเดฟเด•เดšเตเดšเตเด‚ เด…เดฏเดตเตเดณเตเดณเดคเดพเดฏเดฟ เดคเต‹เดจเตเดจเตเดจเตเดจเต: เดจเดฎเตเด•เตเด•เต เดธเตเดฑเตเดฑเต€เด‚ เดฎเตพเดŸเตเดŸเดฟเดชเตเดฒเด•เตโ€Œเดธเดฟเด‚เด—เต เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เดพเดจเตเด‚ เดตเตเดฏเดคเตเดฏเดธเตเดค เดœเต‹เดฒเดฟเด•เตพเด•เตเด•เดพเดฏเดฟ เดจเดฟเดฐเดตเดงเดฟ เดตเตเดฏเดคเตเดฏเดธเตเดค เดŽเดชเดฟเดเด•เตพ เดธเตƒเดทเตโ€ŒเดŸเดฟเด•เตเด•เดพเดจเตเด‚ เด•เดดเดฟเดฏเตเด‚. เดคเดคเตเดตเดคเตเดคเดฟเตฝ, 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)
        }
    }
}

เดฏเตเด เด•เตบเดธเต‹เดณเดฟเตฝ เดจเดฟเดจเตเดจเต เด•เตเดฑเดšเตเดšเต เด•เต€เด•เตพ เดšเต‡เตผเดคเตเดคเต เดธเตเดฑเตเดฑเต‡เดฑเตเดฑเดฟเตฝ เดŽเดจเตเดคเดพเดฃเต เดธเด‚เดญเดตเดฟเด•เตเด•เตเดจเตเดจเดคเต†เดจเตเดจเต เดจเต‹เด•เตเด•เดพเด‚:

เด’เดฐเต เดธเตเดฐเด•เตเดทเดฟเดค เดฌเตเดฐเต—เดธเตผ เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเด‚ เดŽเดดเตเดคเตเดจเตเดจเต

เดชเตเดจเดฐเดพเดฐเด‚เดญเดฟเด•เตเด•เตเดฎเตเดชเต‹เตพ เด•เต€เด•เตพ เดจเดทเตโ€ŒเดŸเดชเตเดชเต†เดŸเดพเดคเดฟเดฐเดฟเด•เตเด•เดพเตป เดธเด‚เดธเตเดฅเดพเดจเด‚ เดธเตเดฅเดฟเดฐเดค เดชเตเดฒเตผเดคเตเดคเต‡เดฃเตเดŸเดคเตเดฃเตเดŸเต.

เดžเด™เตเด™เตพ เด‡เดคเต เดฒเต‹เด•เตเด•เตฝ เดธเตเดฑเตเดฑเต‹เดฑเต‡เดœเดฟเตฝ เดธเด‚เดญเดฐเดฟเด•เตเด•เตเด‚, เด“เดฐเต‹ เดฎเดพเดฑเตเดฑเดคเตเดคเดฟเดฒเตเด‚ เด…เดคเต เดคเดฟเดฐเตเดคเตเดคเดฟเดฏเต†เดดเตเดคเตเด‚. เดคเตเดŸเตผเดจเตเดจเต, เด…เดคเดฟเดฒเต‡เด•เตเด•เตเดณเตเดณ เด†เด•เตโ€Œเดธเดธเต เดฏเตเดเดฏเตโ€Œเด•เตเด•เตเด‚ เด†เดตเดถเตเดฏเดฎเดพเดฏเดฟ เดตเดฐเตเด‚, เด•เต‚เดŸเดพเดคเต† เดฎเดพเดฑเตเดฑเด™เตเด™เตพ เดธเดฌเตโ€Œเดธเตโ€Œเด•เตเดฐเตˆเดฌเต เดšเต†เดฏเตเดฏเดพเดจเตเด‚ เดžเดพเตป เด†เด—เตเดฐเดนเดฟเด•เตเด•เตเดจเตเดจเต. เด‡เดคเดฟเดจเต† เด…เดŸเดฟเดธเตเดฅเดพเดจเดฎเดพเด•เตเด•เดฟ, เดจเดฟเดฐเต€เด•เตเดทเดฟเด•เตเด•เดพเดตเตเดจเตเดจ เด’เดฐเต เดธเด‚เดญเดฐเดฃเด‚ เดธเตƒเดทเตเดŸเดฟเด•เตเด•เตเดจเตเดจเดคเดฟเดจเตเด‚ เด…เดคเดฟเดจเตเดฑเต† เดฎเดพเดฑเตเดฑเด™เตเด™เตพ เดธเดฌเตโ€Œเดธเตโ€Œเด•เตเดฐเตˆเดฌเตเดšเต†เดฏเตเดฏเตเดจเตเดจเดคเดฟเดจเตเด‚ เด‡เดคเต เดธเต—เด•เดฐเตเดฏเดชเตเดฐเดฆเดฎเดพเดฏเดฟเดฐเดฟเด•เตเด•เตเด‚.

เดžเด™เตเด™เตพ 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')
        }
    }
}

เด‡เดชเตเดชเต‹เตพ เดžเด™เตเด™เตพ เดŽเตปเด•เตเดฐเดฟเดชเตเดฑเตเดฑเต เดšเต†เดฏเตเดค เด•เต€เด•เดณเตเด‚ เดชเดพเดธเตโ€Œเดตเต‡เดกเตเด‚ เดฎเดพเดคเตเดฐเด‚ เดธเด‚เดญเดฐเดฟเด•เตเด•เตเดจเตเดจเต. เดฌเดพเด•เตเด•เดฟ เดŽเดฒเตเดฒเดพเด‚ เด•เดฃเด•เตเด•เตเด•เต‚เดŸเตเดŸเดฟ. เดธเด‚เดธเตเดฅเดพเดจเดคเตเดคเต เดจเดฟเดจเตเดจเต เดชเดพเดธเตโ€Œเดตเต‡เดกเต เดจเต€เด•เตเด•เด‚ เดšเต†เดฏเตเดคเตเด•เตŠเดฃเตเดŸเต เดžเด™เตเด™เตพ เดฒเต‹เด•เตเด•เต เดšเต†เดฏเตเดค เด…เดตเดธเตเดฅเดฏเดฟเดฒเต‡เด•เตเด•เต เด•เตˆเดฎเดพเดฑเตเดฑเด‚ เดšเต†เดฏเตเดฏเตเดจเตเดจเต. เดชเดฌเตเดฒเดฟเด•เต เดŽเดชเดฟเดเดฏเตเด•เตเด•เต เด‡เดชเตเดชเต‹เตพ เดธเตเดฑเตเดฑเต‹เดฑเต‡เดœเต เด†เดฐเด‚เดญเดฟเด•เตเด•เตเดจเตเดจเดคเดฟเดจเตเดณเตเดณ เด’เดฐเต เดฐเต€เดคเดฟเดฏเตเดฃเตเดŸเต.

เดŽเตปเด•เตเดฐเดฟเดชเตเดทเตป เดตเต‡เดฃเตเดŸเดฟ เดŽเดดเตเดคเดฟเดฏเดคเต 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-เดฏเดฟเตฝ 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 เดˆ เด…เดตเดธเตเดฅเดฏเต† เดฎเดพเดฑเตเดฑเตเดจเตเดจ 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-react เด˜เดŸเด•เดคเตเดคเดฟเตฝ, เด˜เดŸเด•เดคเตเดคเดฟเตฝ เดชเดฐเดพเดฎเตผเดถเดฟเด•เตเด•เดชเตเดชเต†เดŸเตเดจเตเดจ เดเดคเต†เด™เตเด•เดฟเดฒเตเด‚ เดจเดฟเดฐเต€เด•เตเดทเดฃเด™เตเด™เตพ เดฎเดพเดฑเตเดฎเตเดชเต‹เตพ เดฑเต†เตปเดกเตผ เดธเตเดตเดฏเดฎเต‡เดต เดตเดฟเดณเดฟเด•เตเด•เดชเตเดชเต†เดŸเตเด‚. เดจเดฟเด™เตเด™เตพเด•เตเด•เต 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 เดซเต‹เตพเดกเดฑเดฟเตฝ.

เด‡เดชเตเดชเต‹เตพ เด†เดชเตเดฒเดฟเด•เตเด•เต‡เดทเตป เด•เตเดฒเดพเดธเดฟเตฝ เดจเดฟเด™เตเด™เตพ เดฏเตเดเดฏเตโ€Œเด•เตเด•เดพเดฏเดฟ เด’เดฐเต เดธเตเดฑเตเดฑเต‡เดฑเตเดฑเต เดธเต†เดฒเด•เตเดŸเตผ เด‰เดฃเตเดŸเดพเด•เตเด•เตเด•เดฏเตเด‚ เด…เดคเต เดฎเดพเดฑเตเดฎเตเดชเต‹เตพ เดฏเตเดเดฏเต† เด…เดฑเดฟเดฏเดฟเด•เตเด•เตเด•เดฏเตเด‚ เดตเต‡เดฃเด‚. เด‡เดคเต เดšเต†เดฏเตเดฏเตเดจเตเดจเดคเดฟเดจเต, เดจเดฎเตเด•เตเด•เต เด’เดฐเต เดฐเต€เดคเดฟ เดšเต‡เตผเด•เตเด•เดพเด‚ 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

เด’เดฐเต เด…เดญเดฟเดชเตเดฐเดพเดฏเด‚ เดšเต‡เตผเด•เตเด•เตเด•